使用ManagementClass将打印机添加到本地计算机

时间:2013-04-16 14:46:56

标签: c# printing

我看到参考和提示,以编程方式可以使用ManagementClass等将网络打印机添加到本地计算机。但是我还没有找到任何关于这样做的实际教程。

有没有人真正使用过ManagementClass来做这件事?

我这样做:

var connectionOption = new ConnectionOption();
var mgmScope = new ManagementScope("root\cimv2",connectionOptions);

var printerClass = new ManagementClass(mgmScope, new ManagementPath("Win32_Printer"),null);
var printerObj = printerClass.CreateInstance();

printerObj["DeviceID"] = prnName;     //
printerObj["DriverName"] = drvName;   // full path to driver
printerObj["PortName"] = "myTestPort:";

var options = new PutOptions {Type = PutType.UpdateOrCreate};
printerObj.Put(options);   

所有这一切都是创建错误“Generic Failure”

我无法弄清楚我错过了什么......对此有任何帮助或想法都会受到赞赏。

我想我需要更好地解释我要做的事情......当所需的打印机不依赖于打印服务器时,我需要: 创建一个tcpip原始端口, 通过tcp / ip连接打印机, 安装驱动, 可选地设置默认值。

我希望WMI能够基本上处理所有这些事情,但事实并非如此。

谢谢!

4 个答案:

答案 0 :(得分:12)

WMI Win32_Printer类提供了一个名为AddPrinterConnection的方法 将网络打印机添加到本地打印机列表中。下面的代码 显示如何使用Win32_Printer类连接网络打印机。

请注意,在某些情况下,AddPrinterConnection会失败 连接远程打印机。在下面的示例中,我列出了最多 常见的错误案例。

using (ManagementClass win32Printer = new ManagementClass("Win32_Printer"))
{
  using (ManagementBaseObject inputParam =
     win32Printer.GetMethodParameters("AddPrinterConnection"))
  {
    // Replace <server_name> and <printer_name> with the actual server and
    // printer names.
    inputParam.SetPropertyValue("Name", "\\\\<server_name>\\<printer_name>");

    using (ManagementBaseObject result = 
        (ManagementBaseObject)win32Printer.InvokeMethod("AddPrinterConnection", inputParam, null))
    {
      uint errorCode = (uint)result.Properties["returnValue"].Value;

      switch (errorCode)
      {
        case 0:
          Console.Out.WriteLine("Successfully connected printer.");
          break;
        case 5:
          Console.Out.WriteLine("Access Denied.");
          break;
        case 123:
          Console.Out.WriteLine("The filename, directory name, or volume label syntax is incorrect.");
          break;
        case 1801:
          Console.Out.WriteLine("Invalid Printer Name.");
          break;
        case 1930:
          Console.Out.WriteLine("Incompatible Printer Driver.");
          break;
        case 3019:
          Console.Out.WriteLine("The specified printer driver was not found on the system and needs to be downloaded.");
          break;
      }
    }
  }
}

答案 1 :(得分:2)

为了做到这一点,我最终不得不做一个2步...

首先建立一个命令行来启动:

rundll32.exe printui.dll,PrintUIEntry /if /b "test" /f x2DSPYP.inf /r 10.5.43.32 /m "845 PS"

然后产生它:

    public static string ShellProcessCommandLine(string cmdLineArgs,string path)
    {
        var sb = new StringBuilder();
        var pSpawn = new Process
        {
            StartInfo =
                {
                    WorkingDirectory = path, 
                    FileName = "cmd.exe", 
                    CreateNoWindow = true,
                    Arguments = cmdLineArgs,
                    RedirectStandardInput = true,
                    RedirectStandardOutput = true,
                    UseShellExecute = false
                }
        };
        pSpawn.OutputDataReceived += (sender, args) => sb.AppendLine(args.Data);
        pSpawn.Start();
        pSpawn.BeginOutputReadLine();
        pSpawn.WaitForExit();

        return sb.ToString();
    }

这似乎有效...不是理想的方法,但对于那些不在打印服务器上的打印机,它似乎可以完成这项工作。

答案 2 :(得分:2)

我在这个问题上花了差不多一周的时间!我的目标有点复杂,我想将C#代码包装在由SharePoint外接程序调用的WCF服务中,并且此WCF服务应远程调用客户端以安装打印机。因此,我努力与WMI。 与此同时,我设法使用rundll32解决方案(首先需要创建端口),并且还做了一个powershell变体,真的是最简单的:

$printerPort = "IP_"+ $printerIP
$printerName = "Xerox WorkCentre 6605DN PCL6"
Add-PrinterPort -Name $printerPort -PrinterHostAddress $printerIP
Add-PrinterDriver -Name $printerName
Add-Printer -Name $printerName -DriverName $printerName -PortName $printerPort

真正棘手的部分是知道打印机的名称,它应该匹配INF文件中的字符串!

但回到C#解决方案:我创建了一个以printerName,printerIP和managementScope作为属性的类。并且driverName = printerName

    private string PrinterPortName
    {
        get {  return "IP_" + printerIP; }
    }

    private void CreateManagementScope(string computerName)
    {
        var wmiConnectionOptions = new ConnectionOptions();
        wmiConnectionOptions.Impersonation = ImpersonationLevel.Impersonate;
        wmiConnectionOptions.Authentication = AuthenticationLevel.Default;
        wmiConnectionOptions.EnablePrivileges = true; // required to load/install the driver.
        // Supposed equivalent to VBScript objWMIService.Security_.Privileges.AddAsString "SeLoadDriverPrivilege", True 

        string path = "\\\\" + computerName + "\\root\\cimv2";
        managementScope = new ManagementScope(path, wmiConnectionOptions);
        managementScope.Connect();
    }

    private bool CheckPrinterPort()
    {
        //Query system for Operating System information
        ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_TCPIPPrinterPort");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(managementScope, query);

        ManagementObjectCollection queryCollection = searcher.Get();
        foreach (ManagementObject m in queryCollection)
        {
            if (m["Name"].ToString() == PrinterPortName)
                return true;
        }
        return false;
    }

    private bool CreatePrinterPort()
    {
        if (CheckPrinterPort())
            return true;

        var printerPortClass = new ManagementClass(managementScope, new ManagementPath("Win32_TCPIPPrinterPort"), new ObjectGetOptions());
        printerPortClass.Get();
        var newPrinterPort = printerPortClass.CreateInstance();
        newPrinterPort.SetPropertyValue("Name", PrinterPortName);
        newPrinterPort.SetPropertyValue("Protocol", 1);
        newPrinterPort.SetPropertyValue("HostAddress", printerIP);
        newPrinterPort.SetPropertyValue("PortNumber", 9100);    // default=9100
        newPrinterPort.SetPropertyValue("SNMPEnabled", false);  // true?
        newPrinterPort.Put();
        return true;
    }

    private bool CreatePrinterDriver(string printerDriverFolderPath)
    {
        var endResult = false;
        // Inspired from https://msdn.microsoft.com/en-us/library/aa384771%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
        // and http://microsoft.public.win32.programmer.wmi.narkive.com/y5GB15iF/adding-printer-driver-using-system-management
        string printerDriverInfPath = IOUtils.FindInfFile(printerDriverFolderPath);
        var printerDriverClass = new ManagementClass(managementScope, new ManagementPath("Win32_PrinterDriver"), new ObjectGetOptions());            
        var printerDriver = printerDriverClass.CreateInstance();
        printerDriver.SetPropertyValue("Name", driverName);
        printerDriver.SetPropertyValue("FilePath", printerDriverFolderPath);
        printerDriver.SetPropertyValue("InfName", printerDriverInfPath);

        // Obtain in-parameters for the method
        using (ManagementBaseObject inParams = printerDriverClass.GetMethodParameters("AddPrinterDriver"))
        {
            inParams["DriverInfo"] = printerDriver;
            // Execute the method and obtain the return values.            

            using (ManagementBaseObject result = printerDriverClass.InvokeMethod("AddPrinterDriver", inParams, null))
            {
                // result["ReturnValue"]
                uint errorCode = (uint)result.Properties["ReturnValue"].Value;  // or directly result["ReturnValue"]
                // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681386(v=vs.85).aspx
                switch (errorCode)
                {
                    case 0:
                        //Trace.TraceInformation("Successfully connected printer.");
                        endResult = true;
                        break;
                    case 5:
                        Trace.TraceError("Access Denied.");
                        break;
                    case 123:
                        Trace.TraceError("The filename, directory name, or volume label syntax is incorrect.");
                        break;
                    case 1801:
                        Trace.TraceError("Invalid Printer Name.");
                        break;
                    case 1930:
                        Trace.TraceError("Incompatible Printer Driver.");
                        break;
                    case 3019:
                        Trace.TraceError("The specified printer driver was not found on the system and needs to be downloaded.");
                        break;
                }
            }
        }
        return endResult;
    }

    private bool CreatePrinter()
    {
        var printerClass = new ManagementClass(managementScope, new ManagementPath("Win32_Printer"), new ObjectGetOptions());
        printerClass.Get();
        var printer = printerClass.CreateInstance();
        printer.SetPropertyValue("DriverName", driverName);
        printer.SetPropertyValue("PortName", PrinterPortName);
        printer.SetPropertyValue("Name", printerName);
        printer.SetPropertyValue("DeviceID", printerName);
        printer.SetPropertyValue("Location", "Front Office");
        printer.SetPropertyValue("Network", true);
        printer.SetPropertyValue("Shared", false);
        printer.Put();
        return true;
    }


    private void InstallPrinterWMI(string printerDriverPath)
    {
        bool printePortCreated = false, printeDriverCreated = false, printeCreated = false;
        try
        {                
            printePortCreated = CreatePrinterPort();
            printeDriverCreated = CreatePrinterDriver(printerDriverPath);
            printeCreated = CreatePrinter();
        }
        catch (ManagementException err)
        {
            if (printePortCreated)
            {
                // RemovePort
            }
            Console.WriteLine("An error occurred while trying to execute the WMI method: " + err.Message);
        }
    }

最后安装驱动程序。如果它在干净的Windows上工作,我还需要进一步测试。我的测试期间有很多安装/卸载驱动程序

答案 3 :(得分:0)

我想添加答案,因为还有另一种方法,Microsoft建议现在通过System.Management使用Microsoft.Management.Infrastructure。

这里是Microsoft文档的链接: https://msdn.microsoft.com/en-us/library/microsoft.management.infrastructure.aspx

请注意,您必须在c#项目中将引用添加到Microsoft.Management.Infrastructure dll: Where the Microsoft.Management.Infrastructure

您可能还需要在计算机上配置winrm https://docs.microsoft.com/en-us/windows/desktop/winrm/installation-and-configuration-for-windows-remote-management

以下是使用c#从打印服务器将打印机添加到本地计算机的示例代码

close()

}