C# - Enumerating network printers on remote machin

2019-07-29 23:00发布

问题:

I am writing an application to check if a network printer from a print server is connected to a remote machine, but having trouble with the remote part... I'm using System.Printing and passing in the remote hostname/IP address through the 'compID' variable. The problem I'm having is that the code always returns the networked printers on my LOCAL machine rather than the remote machine:

EnumeratedPrintQueueTypes[] compEnumerationFlags = { EnumeratedPrintQueueTypes.Connections };

PrintServer compPrinters = new PrintServer("\\\\" + compID);
PrintQueueCollection printQueuesOnComputer = compPrinters.GetPrintQueues(compEnumerationFlags);

List<string> compPrinterList = new List<string>();

foreach (PrintQueue printer in printQueuesOnComputer)
    {
        compPrinterList.Add(printer.Name);
    }

string csv = string.Join("\n", compPrinterList.ToArray());
Microsoft.VisualBasic.Interaction.MsgBox(csv);

Forgive the messy bit at the end there, but it's just a quick and dirty way for me to see what the results are for the moment.

The strange thing is that if I change the 'compID' variable to our actual print server and change the flags from "Connections' to 'Shared', then the code successfully returns all the shared printers from our print server.

All this is running as an admin on our domain, so that should hopefully not be an issue here. Is there something simple I'm overlooking or is there some sort of restriction on the types of machines I can connect to with PrintServer?

回答1:

So I have a workaround which seems to do the job well enough after a bit of testing. The printers would have been connected to the machine at somepoint using rundll32 printui.dll,PrintUIEntry /ga /c\\%computername% /n\\%printserver%\%printername%

In the application I've imported printui.dll:

[DllImport("printui.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        private static extern void PrintUIEntryW(IntPtr hwnd, IntPtr hinst, string lpszCmdLine, int nCmdShow);

Then later I use the /ge flag on the remote machine to list all per-machine connections, output that to a temp text file, then check to see if the printer name is contained in the text file:

PrintUIEntryW(IntPtr.Zero, IntPtr.Zero, "/c \\\\" + compID + " /ge /q /f c:\\temp\\printers.txt", 0);

string file = File.ReadAllText("c:\\temp\\printers.txt");
if (file.Contains(printerID))
{
    exist = true;
}
File.Delete("c:\\temp\\printers.txt");

I'm aware this probably isn't the best way to go about it, but it seems to work in the environment I operate in, so I'm providing this as an answer.