有没有一种.NET方式可以枚举所有可用的网络打印机?

13

有没有一种简单的方法在.NET中列出所有可见的网络打印机?目前,我正在显示PrintDialog以允许用户选择打印机。问题是,本地打印机也会被显示(连同XPS Document Writer等)。如果我可以自己枚举网络打印机,我就可以显示一个仅包含这些打印机的自定义对话框。

谢谢!!


AvailablePrinterInfo在哪个命名空间中?出现错误:找不到类型或命名空间名称“AvailablePrinterInfo”(是否缺少使用指令或程序集引用?)。 - user1027158
6个回答

16
  • LocalPrintServer.DefaultPrintQueue获取默认打印机
  • 从用户角度获取已安装的打印机,使用PrinterSettings.InstalledPrinters
  • 枚举打印机列表:
  • \\ 开头的打印机是网络打印机 - 使用 new PrintServer("\\UNCPATH").GetPrintQueue("QueueName") 获取队列
  • 不以 \\ 开头的打印机是本地打印机,使用LocalPrintServer.GetQueue("Name") 获取
  • 您可以通过比较 FullName 属性来查看哪个是默认打印机。

注意:网络打印机可以是LocalPrintServer.DefaultPrintQueue中的默认打印机,但不会出现在LocalPrintServer.GetPrintQueues()中。

    // get available printers
    LocalPrintServer printServer = new LocalPrintServer();
    PrintQueue defaultPrintQueue = printServer.DefaultPrintQueue;

    // get all printers installed (from the users perspective)he t
    var printerNames = PrinterSettings.InstalledPrinters;
    var availablePrinters = printerNames.Cast<string>().Select(printerName => 
    {
        var match = Regex.Match(printerName, @"(?<machine>\\\\.*?)\\(?<queue>.*)");
        PrintQueue queue;
        if (match.Success)
        {
            queue = new PrintServer(match.Groups["machine"].Value).GetPrintQueue(match.Groups["queue"].Value);
        }
        else
        {
            queue = printServer.GetPrintQueue(printerName);
        }

        var capabilities = queue.GetPrintCapabilities();
        return new AvailablePrinterInfo()
        {
            Name = printerName,
            Default = queue.FullName == defaultPrintQueue.FullName,
            Duplex = capabilities.DuplexingCapability.Contains(Duplexing.TwoSidedLongEdge),
            Color = capabilities.OutputColorCapability.Contains(OutputColor.Color)
        };
    }).ToArray();

    DefaultPrinter = AvailablePrinters.SingleOrDefault(x => x.Default);

谢谢Simon - 非常有用。 - PolicyWatcher
每次我在这个上面得到点赞时,我都会想“真是一团糟!”很高兴它有所帮助——但希望现在有更好的方法! - Simon_Weaver

15

使用新的System.Printing API

using (var printServer = new PrintServer(string.Format(@"\\{0}", PrinterServerName)))
{
    foreach (var queue in printServer.GetPrintQueues())
    {
        if (!queue.IsShared)
        {
            continue;
        }
        Debug.WriteLine(queue.Name);
     }
 }

这应该是被接受的答案。直截了当。 - Keytrap

9

在这里找到了这段代码(链接)

 private void btnGetPrinters_Click(object sender, EventArgs e)
        {
// Use the ObjectQuery to get the list of configured printers
            System.Management.ObjectQuery oquery =
                new System.Management.ObjectQuery("SELECT * FROM Win32_Printer");

            System.Management.ManagementObjectSearcher mosearcher =
                new System.Management.ManagementObjectSearcher(oquery);

            System.Management.ManagementObjectCollection moc = mosearcher.Get();

            foreach (ManagementObject mo in moc)
            {
                System.Management.PropertyDataCollection pdc = mo.Properties;
                foreach (System.Management.PropertyData pd in pdc)
                {
                    if ((bool)mo["Network"])
                    {
                        cmbPrinters.Items.Add(mo[pd.Name]);
                    }
                }
            }

        }

更新:

“此API函数可以枚举所有网络资源,包括服务器、工作站、打印机、共享、远程目录等。”

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=741&lngWId=10


+1 谢谢!我可以通过对这段代码进行一些小调整,仅枚举已安装的网络打印机的名称。现在,您知道是否可以使用类似的技术枚举所有可见的网络打印机(而不仅仅是已安装的)吗? - Mark Carpenter
尝试阅读这篇文章: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=741&lngWId=10“此 API 函数可以枚举所有网络资源,包括服务器、工作站、打印机、共享、远程目录等。” 希望对您有所帮助,祝好! - Andrija
最后一条语句出现了空指针异常。 - Lei Yang
只是想补充一下,据我所知,这种方法已经不再适用了。似乎 ObjectQuery 已经不存在了。 - Philip Vaughn

2

在另一篇与此相关的帖子(https://stackoverflow.com/a/30758129/6513653)中,Scott Chamberlain说:“我不认为.NET中有任何东西可以做到这一点,你需要进行本地调用”。在尝试了所有可能的.NET资源后,我认为他是正确的。 因此,我开始研究ADD PRINTER对话框如何进行搜索。使用Wireshark,我发现ADD PRINTER会向本地网络中的所有主机发送至少两种类型的包:两个针对3911端口的http/xml请求和三个SNMP请求。enter image description here 第一个SNMP请求是get-next 1.3.6.1.2.1.43,它是Printer-MIB。第二个请求是get 1.3.6.1.4.1.2699.1.2.1.2.1.1.3,它是PRINTER-PORT-MONITOR-MIB的pmPrinterIEEE1284DeviceId。这是最有趣的部分,因为它是ADD PRINTER获取打印机名称的地方。第三个请求是get 1.3.6.1.2.1.1.1.0,它是SNMP MIB-2 System的sysDescr。 我确信第二个SNMP请求足以在本地网络中找到大多数网络打印机,因此我编写了这段代码。它适用于Windows窗体应用程序,并依赖于SnmpSharpNet。
编辑:我正在使用ARP Ping而不是普通Ping来搜索网络中的活动主机。以下是一个示例项目的链接:ListNetworks C# Project

2

PrinterSettiings.InstalledPrinters应该会给你想要的集合。


1
PrinterSettings.InstalledPrinters 仍然显示非网络打印机,以及文档打印机(PDF Writer、XPS Document Writer 等)。 - Mark Carpenter

0
请注意,如果您正在通过RDP进行工作,似乎会使这个过程变得复杂,因为它看起来像是将主机上的所有内容都导出为本地打印机。
如果您期望在不使用RDP时以相同的方式工作,那么这将成为一个问题。

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