11

我看到参考和提示,可以使用 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 基本上可以解决所有这些问题,但似乎并非如此。

谢谢!

4

4 回答 4

14

WMIWin32_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;
      }
    }
  }
}
于 2013-04-16T18:52:08.090 回答
5

我花了将近一周的时间来解决这个问题!我的目标有点复杂,我想将 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 作为属性的类。和驱动程序名称 = 打印机名称

    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 上工作,我仍然需要进一步测试。在我的测试期间是否安装/卸载了许多驱动程序

于 2016-07-15T16:30:19.237 回答
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();
    }

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

于 2013-04-29T12:47:58.873 回答
0

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

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

请注意,您必须在 c# 项目中添加对 Microsoft.Management.Infrastructure dll 的引用: 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();
    }
}

}

于 2018-08-01T15:24:52.810 回答