13

Is there a straightforward way to enumerate all visible network printers in .NET? Currently, I'm showing the PrintDialog to allow the user to select a printer. The problem with that is, local printers are displayed as well (along with XPS Document Writer and the like). If I can enumerate network printers myself, I can show a custom dialog with just those printers.

Thanks!!

Mark Carpenter
  • 17,445
  • 22
  • 96
  • 149
  • AvailablePrinterInfo is in which namespace?getting as Error The type or namespace name 'AvailablePrinterInfo' could not be found (are you missing a using directive or an assembly reference –  Nov 03 '11 at 07:42

6 Answers6

16
  • Get the default printer from LocalPrintServer.DefaultPrintQueue
  • Get the installed printers (from user's perspective) from PrinterSettings.InstalledPrinters
  • Enumerate through the list:
  • Any printer beginning with \\ is a network printer - so get the queue with new PrintServer("\\UNCPATH").GetPrintQueue("QueueName")
  • Any printer not beginning with \\ is a local printer so get it with LocalPrintServer.GetQueue("Name")
  • You can see which is default by comparing FullName property.

Note: a network printer can be the default printer from LocalPrintServer.DefaultPrintQueue, but not appear in 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_Weaver
  • 140,023
  • 84
  • 646
  • 689
15

using the new 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);
     }
 }
Simon
  • 33,714
  • 21
  • 133
  • 202
9

found this code here

 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]);
                    }
                }
            }

        }

Update:

"This API function can enumerate all network resources, including servers, workstations, printers, shares, remote directories etc."

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

Andrija
  • 14,037
  • 18
  • 60
  • 87
  • +1 Thanks! I can enumerate just the names of installed network printers with a few small adjustments to this code. Now, do you know if one can enumerate all VISIBLE network printers (not just the installed ones) using a similar technique. – Mark Carpenter Jun 19 '09 at 14:59
  • try this article : http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=741&lngWId=10 "This API function can enumerate all network resources, including servers, workstations, printers, shares, remote directories etc." I hope it helps, cheers – Andrija Jun 19 '09 at 15:13
  • null exception in the last statement. – Lei Yang Nov 20 '13 at 07:50
  • Just wish to add that from what I can tell this no longer works. It doesn't look like ObjectQuery exists any more. – Philip Vaughn Apr 26 '19 at 15:16
2

PrinterSettiings.InstalledPrinters should give you the collection you want

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
Robert
  • 2,964
  • 1
  • 18
  • 16
  • 1
    PrinterSettings.InstalledPrinters still shows non-network printers, as well as document printers (PDF Writer, XPS Document Writer, etc). – Mark Carpenter Jun 19 '09 at 14:57
2

In another post(https://stackoverflow.com/a/30758129/6513653) relationed to this one, Scott Chamberlain said "I do not believe there is anything in .NET that can do this, you will need to make a native call". After to try all the possible .NET resource, I think he is right. So, I started to investigate how ADD PRINTER dialog does its search. Using Wireshark, I found out that ADD PRINTER send at least two types of packages to all hosts in local network: two http/xml request to 3911 port and three SNMP requests. enter image description here The first SNMP request is a get-next 1.3.6.1.2.1.43, which is Printer-MIB. The second one, is a get 1.3.6.1.4.1.2699.1.2.1.2.1.1.3 which is pmPrinterIEEE1284DeviceId of PRINTER-PORT-MONITOR-MIB. This is the most interesting because is where ADD PRINTER takes printer name. The third is a get 1.3.6.1.2.1.1.1.0, which is sysDescr of SNMP MIB-2 System. I do believe that the second SNMP request is enough to find most of network printers in local network, so I did this code. It works for Windows Form Application and it depends on SnmpSharpNet.

Edit: I'm using ARP Ping instead normal Ping to search active hosts in network. Link for an example project: ListNetworks C# Project

ViniCoder
  • 648
  • 9
  • 15
0

Note that if you're working over RDP it seems to complicate this because it looks like it just exports everything on the host as a local printer.

Which is then a problem if you're expecting it to work the same way when not on RDP.

Underground
  • 127
  • 5