如何在局域网中获取打印机连接的计算机名称和IP地址

3

在局域网中,通常打印机是共享的,我们可以通过Windows的“添加远程打印机”将这些共享计算机添加到我们的计算机中。我想通过C#获取已添加打印机的列表,以及它们的在线状态和打印机设置。可以通过以下方式获取已添加打印机的列表:

System.Drawing.Printing.PrinterSettings.InstalledPrinters

通过这段代码,我可以将添加的打印机列表获取到一个组合框中。问题在于如何通过C#代码获取每个打印机的在线状态和其他可能的设置。请帮忙。


你已经得到了Jonathan、Fletcher和P.Campbell提供的非常好而详细的答案(有些甚至在半小时内)。我相信你只是忘记在要求更多之前给他们的努力点赞了...一旦我看到你自己的投票,我也会点赞的。 - Kurt Pfeifle
3个回答

3

使用WMI是此类任务的常见选项...

    ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Printer");

                foreach (ManagementObject printer in searcher.Get())
                {
                    string printerName = printer["Name"].ToString().ToLower();
                    Console.WriteLine("Printer :" + printerName);
                    PrintProps(printer, "Status");
                    PrintProps(printer, "PrinterState");
                    PrintProps(printer, "PrinterStatus");


                }

}

static void PrintProps(ManagementObject o, string prop)     
{         
        try { Console.WriteLine(prop + "|" + o[prop]); 
        }         
        catch (Exception e) 
        { 
            Console.Write(e.ToString()); 
        }     
}   

非常感谢您的回答。这种方法成功了,但是有时它并不给出最准确的状态,因为它是通过打印作业信息确定的。MSDN 是这样说的.. 但我想知道 Windows 7 如何非常精确地找到打印机的状态,无论它是在线还是离线,并且是否有一种方式可以通过 C# 代码获得 Windows 显示的状态? - Zerone

3

在线状态

考虑这篇CodeProject文章,题为"如何检查打印机是否已连接"。该示例代码使用WMI和System.Management命名空间。

复制/粘贴:

   ManagementScope scope = new ManagementScope(@"\root\cimv2");
   scope.Connect();

   // Select Printers from WMI Object Collections

   ManagementObjectSearcher searcher = new 
    ManagementObjectSearcher("SELECT * FROM Win32_Printer");

   string printerName = "";
   foreach (ManagementObject printer in searcher.Get()) 
   {
    printerName = printer["Name"].ToString().ToLower();
    if (printerName.Equals(@"hp deskjet 930c"))
    {
     Console.WriteLine("Printer = " + printer["Name"]); 
     if (printer["WorkOffline"].ToString().ToLower().Equals("true"))
     {
      // printer is offline by user

      Console.WriteLine("Your Plug-N-Play printer is not connected.");
     }
     else
     {
      // printer is not offline

       Console.WriteLine("Your Plug-N-Play printer is connected.");
     }
    }
   }
  }

非常感谢您的回答。这种方法也成功地运行,但有时它不能给出最准确的状态,因为它所确定的状态是由打印作业信息决定的。MSDN 是这么说的...但我想知道 Windows 7 如何非常准确地查找打印机的状态,无论它是在线还是离线,并且是否有一种我们可以通过 C# 代码获取 Windows 显示的状态的方法? - Zerone
@Zerone:即使您还有一些问题没有解决,我认为这个答案也值得点赞。 - Kurt Pfeifle

2
作为 WMI 的替代方案,您可以使用打印池 API来收集有关打印机的详细信息。大多数API的P / Invoke签名都可在http://www.pinvoke.net上找到。
打开打印机句柄: http://www.pinvoke.net/default.aspx/winspool.OpenPrinter 收集打印机信息: http://www.pinvoke.net/default.aspx/winspool.GetPrinterData 编辑:
根据要求,这里快速提供一个从 PrintSpoolerApi 收集的示例。
PrintSpoolerAPIExample:
创建新的控制台项目,并将 Program.cs 中的所有代码替换为以下内容(由于类型推断,.NET 3.5及以上版本),每台计算机上可用的每个打印机的打印机详细信息(本地或网络)将打印到控制台。状态值是您感兴趣的内容。 "准备就绪" 的状态代码为0,尝试禁用打印机和禁用与网络打印机的连接以查看状态更改。
using System;
using System.Collections;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;

namespace PrintSpoolerAPIExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var printers = System.Drawing.Printing.PrinterSettings.InstalledPrinters as IEnumerable;

            foreach (string printer in printers)
            {
                var printerInfo = PrintSpoolerApi.GetPrinterProperty(printer);
                StringBuilder sb = new StringBuilder();
                sb.AppendLine(string.Format("ServerName:{0}", printerInfo.ServerName));
                sb.AppendLine(string.Format("PrinterName:{0}", printerInfo.PrinterName));
                sb.AppendLine(string.Format("ShareName:{0}", printerInfo.ShareName));
                sb.AppendLine(string.Format("PortName:{0}", printerInfo.PortName));
                sb.AppendLine(string.Format("DriverName:{0}", printerInfo.DriverName));
                sb.AppendLine(string.Format("Comment:{0}", printerInfo.Comment));
                sb.AppendLine(string.Format("Location:{0}", printerInfo.Location));
                sb.AppendLine(string.Format("DevMode:{0}", printerInfo.DevMode));
                sb.AppendLine(string.Format("SepFile:{0}", printerInfo.SepFile));
                sb.AppendLine(string.Format("PrintProcessor:{0}", printerInfo.PrintProcessor));
                sb.AppendLine(string.Format("Datatype:{0}", printerInfo.Datatype));
                sb.AppendLine(string.Format("Parameters:{0}", printerInfo.Parameters));
                sb.AppendLine(string.Format("Attributes:{0}", printerInfo.Attributes));
                sb.AppendLine(string.Format("Priority:{0}", printerInfo.Priority));
                sb.AppendLine(string.Format("DefaultPriority:{0}", printerInfo.DefaultPriority));
                sb.AppendLine(string.Format("StartTime:{0}", printerInfo.StartTime));
                sb.AppendLine(string.Format("UntilTime:{0}", printerInfo.UntilTime));
                sb.AppendLine(string.Format("Status:{0}", printerInfo.Status));
                sb.AppendLine(string.Format("Jobs:{0}", printerInfo.Jobs));
                sb.AppendLine(string.Format("AveragePpm:{0}", printerInfo.AveragePpm));
                Console.WriteLine(sb.ToString());
            }

            Console.ReadLine();
        }
    }

    class PrintSpoolerApi
    {
        [DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool OpenPrinter(
            [MarshalAs(UnmanagedType.LPTStr)]
            string printerName,
            out IntPtr printerHandle,
            PrinterDefaults printerDefaults);

        [DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool GetPrinter(
            IntPtr printerHandle,
            int level,
            IntPtr printerData,
            int bufferSize,
            ref int printerDataSize);

        [DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool ClosePrinter(
            IntPtr printerHandle);

        [StructLayout(LayoutKind.Sequential)]
        public struct PrinterDefaults
        {
            public IntPtr pDatatype;
            public IntPtr pDevMode;
            public int DesiredAccess;
        }

        public enum PrinterProperty
        {
            ServerName,
            PrinterName,
            ShareName,
            PortName,
            DriverName,
            Comment,
            Location,
            PrintProcessor,
            Datatype,
            Parameters,
            Attributes,
            Priority,
            DefaultPriority,
            StartTime,
            UntilTime,
            Status,
            Jobs,
            AveragePpm
        };

        public struct PrinterInfo2
        {
            [MarshalAs(UnmanagedType.LPTStr)]
            public string ServerName;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string PrinterName;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string ShareName;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string PortName;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string DriverName;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string Comment;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string Location;
            public IntPtr DevMode;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string SepFile;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string PrintProcessor;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string Datatype;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string Parameters;
            public IntPtr SecurityDescriptor;
            public uint Attributes;
            public uint Priority;
            public uint DefaultPriority;
            public uint StartTime;
            public uint UntilTime;
            public uint Status;
            public uint Jobs;
            public uint AveragePpm;
        }

        public static PrinterInfo2 GetPrinterProperty(string printerUncName)
        {
            var printerInfo2 = new PrinterInfo2();

            var pHandle = new IntPtr();
            var defaults = new PrinterDefaults();
            try
            {
                //Open a handle to the printer
                bool ok = OpenPrinter(printerUncName, out pHandle, defaults);

                if (!ok)
                {
                    //OpenPrinter failed, get the last known error and thrown it
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                //Here we determine the size of the data we to be returned
                //Passing in 0 for the size will force the function to return the size of the data requested
                int actualDataSize = 0;
                GetPrinter(pHandle, 2, IntPtr.Zero, 0, ref actualDataSize);

                int err = Marshal.GetLastWin32Error();

                if (err == 122)
                {
                    if (actualDataSize > 0)
                    {
                        //Allocate memory to the size of the data requested
                        IntPtr printerData = Marshal.AllocHGlobal(actualDataSize);
                        //Retrieve the actual information this time
                        GetPrinter(pHandle, 2, printerData, actualDataSize, ref actualDataSize);

                        //Marshal to our structure
                        printerInfo2 = (PrinterInfo2)Marshal.PtrToStructure(printerData, typeof(PrinterInfo2));
                        //We've made the conversion, now free up that memory
                        Marshal.FreeHGlobal(printerData);
                    }
                }
                else
                {
                    throw new Win32Exception(err);
                }

                return printerInfo2;
            }
            finally
            {
                //Always close the handle to the printer
                ClosePrinter(pHandle);
            }
        }
    }
}

如果需要,您可以从API中检索更多详细信息。


我使用了上述的2种查询 WMI 的方法,但有时它不能提供准确的信息。MSDN 表示,由于打印作业状态决定了打印机的状态,直到尝试打印后才能显示最准确的信息。但我只需要找出打印机是在线还是离线,并且我看到 Windows 在“设备和打印机”下非常准确地显示其添加的本地或远程打印机的状态。是否有办法通过 C# 代码访问该 Windows 状态?此外,我仍在学习,我不理解打印池 API,您是否有更多的资源可以提供? - Zerone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接