【问题标题】:add printer to local computer using ManagementClass使用 ManagementClass 将打印机添加到本地计算机
【发布时间】:2013-04-16 14:46:56
【问题描述】:

我看到一些参考和提示,可以使用 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);   

所有这些都会产生一个错误“通用故障”

我无法弄清楚我错过了什么.....任何关于此的帮助或想法将不胜感激。

我认为我需要更好地解释我正在尝试做什么......当所需的打印机未绑定到打印服务器时,我需要: 创建一个 tcpip 原始端口, 通过 tcp/ip 连接打印机, 安装驱动程序, 可选择设置默认值。

我希望 WMI 基本上可以处理所有这些问题,但事实并非如此。

谢谢!

【问题讨论】:

    标签: c# printing


    【解决方案1】:

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

    【讨论】:

    • 有时候我不知道服务器名,只有IP地址...这意味着它还需要有一种方法来安装驱动程序。有点让我难过。
    • @Kevin:您也可以使用 IP 代替服务器名称。只需将服务器名称替换为 IP 地址即可。上面的代码也适用于 IP 地址。
    • 在哪里可以找到错误代码列表?我收到 1722 错误代码。
    • @Kevin:在这里,你会发现错误代码:msdn.microsoft.com/en-us/library/windows/desktop/…
    • 我仍在努力确定... WMI 处理起来非常令人沮丧。我还必须能够加载驱动程序......所以......我在这方面有点膝盖。您的代码不会创建我需要完成的端口。我可以创建端口,但我无法找到加载驱动程序的方法,尽管我正在查看 win32_printerdriver ....
    【解决方案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# 解决方案:我创建了一个以打印机名称、打印机 IP 和 managementScope 作为属性的类。和 driverName = 打印机名

        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】:

      为了做到这一点,我最终不得不做一个 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();
          }
      

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

      【讨论】:

        【解决方案4】:

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

        这里是微软文档的链接: 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# 将打印机从打印服务器添加到本地机器的示例代码

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        using Microsoft.Management.Infrastructure;
        using Microsoft.Management.Infrastructure.Generic;
        using Microsoft.Management.Infrastructure.Options;
        
        
        namespace MMITest
        {
        class Program
        {
            static void Main(string[] args)
            {
                using (var session = CimSession.Create("localhost"))
                {
                    using (var cimMethodParameters = new CimMethodParametersCollection())
                    {
                        cimMethodParameters.Add(CimMethodParameter.Create("Name", @"\\PrintServerName\PrinterName", CimFlags.Parameter));
                        session.InvokeMethod(@"root\cimv2", "Win32_Printer", "AddPrinterConnection", cimMethodParameters);
                    }
                }
        
                Console.ReadLine();
            }
        }
        

        }

        【讨论】:

          猜你喜欢
          • 2015-03-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-12
          • 1970-01-01
          • 1970-01-01
          • 2018-09-02
          • 2011-03-29
          • 1970-01-01
          相关资源
          最近更新 更多