EnumPrinters (winspool)
Last changed: Nick Lowe-62.3.225.7

.
Summary
Used to enumerate printer-information. See PrinterEnumFlags for the flags. See PRINTER_INFO_2 for the structure for level 2 info.

C# Signature:

    [DllImport("winspool.drv", CharSet=CharSet.Auto, SetLastError=true)]
    private static extern bool EnumPrinters(PrinterEnumFlags Flags, string Name, uint Level,
    IntPtr pPrinterEnum, uint cbBuf,
    ref uint pcbNeeded, ref uint pcReturned);

VB Signature:

Declare Function EnumPrinters Lib "winspool.dll" (TODO) As TODO

User-Defined Types:

PRINTER_INFO_2

PrinterEnumFlags

Notes:

None.

Tips & Tricks:

Please add some!

Sample Code:

    unsafe public static PRINTER_INFO_2 [] EnumPrinters(PrinterEnumFlags Flags)
    {
        PRINTER_INFO_2 [] Info2;

        uint cbNeeded = 0;
        uint cReturned = 0;
        bool ret = Winspool.EnumPrinters(Flags,
            null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned);

        byte [] bPrinterEnum = new byte [cbNeeded];
        fixed (byte *pAddr = bPrinterEnum)
        {

            ret = Winspool.EnumPrinters(Flags,
                null, 2, (IntPtr)pAddr, (uint)bPrinterEnum.Length, ref cbNeeded, ref cReturned);

            if (ret)
            {
                Info2 = new PRINTER_INFO_2[cReturned];

                byte *pCurrent = pAddr;
                for (int i = 0; i < cReturned; i++)
                {
                    Info2[i].pServerName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pPrinterName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pShareName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pPortName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pDriverName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pComment = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pLocation = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pDevMode = Marshal.ReadIntPtr((IntPtr)pCurrent);
                    pCurrent += 4;
                    Info2[i].pSepFile = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pPrintProcessor = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pDatatype = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pParameters = Marshal.PtrToStringAuto(Marshal.ReadIntPtr((IntPtr)pCurrent));
                    pCurrent += 4;
                    Info2[i].pSecurityDescriptor = Marshal.ReadIntPtr((IntPtr)pCurrent);
                    pCurrent += 4;
                    Info2[i].Attributes = (uint)Marshal.ReadInt32((IntPtr)pCurrent);
                    pCurrent += 4;
                    Info2[i].Priority = (uint)Marshal.ReadInt32((IntPtr)pCurrent);
                    pCurrent += 4;
                    Info2[i].DefaultPriority = (uint)Marshal.ReadInt32((IntPtr)pCurrent);
                    pCurrent += 4;
                    Info2[i].StartTime = (uint)Marshal.ReadInt32((IntPtr)pCurrent);
                    pCurrent += 4;
                    Info2[i].UntilTime = (uint)Marshal.ReadInt32((IntPtr)pCurrent);
                    pCurrent += 4;
                    Info2[i].Status = (uint)Marshal.ReadInt32((IntPtr)pCurrent);
                    pCurrent += 4;
                    Info2[i].cJobs = (uint)Marshal.ReadInt32((IntPtr)pCurrent);
                    pCurrent += 4;
                    Info2[i].AveragePPM = (uint)Marshal.ReadInt32((IntPtr)pCurrent);
                    pCurrent += 4;
                }
            }
            else
            {
                Info2 = new PRINTER_INFO_2[0];
            }

        }
        return Info2;
    }

You can avoid using unsafe code blocks if you so wish like so:

            uint cbNeeded = 0;
            uint cReturned = 0;
            bool ret = EnumPrinters(PRINTER_ENUM_LOCAL, null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned);

            IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded);
            ret = EnumPrinters(PRINTER_ENUM_LOCAL, null, 2, pAddr, cbNeeded, ref cbNeeded, ref cReturned);

            if (ret)
            {
                PRINTER_INFO_2 [] Info2 = new PRINTER_INFO_2[cReturned];
                int offset = pAddr.ToInt32();

                for (int i = 0; i < cReturned; i++)
                {
                    Info2[i] = (PRINTER_INFO_2) Marshal.PtrToStructure(new IntPtr(offset), typeof(PRINTER_INFO_2));
                    offset += Marshal.SizeOf(typeof(PRINTER_INFO_2));
                }

                Marshal.FreeHGlobal(pAddr);

Alternative Managed API:

PrinterSettings.InstalledPrinters, but this only gives the name of the printers.

Documentation