使用ManagementClass将打印机添加到本地计算机
本文关键字:计算机 添加 ManagementClass 打印机 使用 | 更新日期: 2023-09-27 18:09:41
我看到参考资料和提示,可以通过编程方式使用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基本上可以处理所有这些,但情况似乎并非如此。
谢谢!
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;
}
}
}
}
我几乎花了一个星期的时间在这个问题上!我的目标有点复杂,我想把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上运行。在我的测试中是否安装/卸载了很多驱动程序
为了做到这一点,我最终不得不做一个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();
}
这似乎工作…不是理想的方法,但对于那些不在打印服务器上的打印机,它似乎可以完成工作。
我想补充一个答案,因为有另一种方法,微软建议现在使用Microsoft. management . infrastructure而不是System.Management.
这是微软文档的链接:https://msdn.microsoft.com/en-us/library/microsoft.management.infrastructure.aspx
请注意,你必须在c#项目中添加引用到Microsoft.Management.Infrastructure dll:其中Microsoft.Management.Infrastructure
您可能还需要在机器上配置winrmhttps://learn.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();
}
}
}