我看到参考和提示,以编程方式可以使用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);
Run Code Online (Sandbox Code Playgroud)
所有这一切都是创建一个错误"通用失败"
我无法弄清楚我错过了什么.....任何有关这方面的帮助或想法将不胜感激.
我想我需要更好地解释我想要做什么...当打印机需要的打印机没有绑定时,我需要:创建一个tcpip原始端口,通过tcp/ip连接打印机,安装驱动程序,可选默认设置.
我希望WMI能够基本上处理所有这些,但似乎并非如此.
谢谢!
Han*_*ans 13
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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我几乎花了一周的时间在这个问题上!我的目标有点复杂,我想将 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
Run Code Online (Sandbox Code Playgroud)
真正棘手的部分是要知道打印机的名称,它应该与 INF 文件中的字符串匹配!
但是回到 C# 解决方案:我创建了一个类,其中包含 printerName、printerIP 和 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);
}
}
Run Code Online (Sandbox Code Playgroud)
最后安装驱动。如果它在干净的 Windows 上工作,我仍然需要进一步的测试。在我的测试期间是否安装/卸载了许多驱动程序
为了做到这一点,我最终不得不做一个 2 步进器......
首先建立一个命令行来启动:
rundll32.exe printui.dll,PrintUIEntry /if /b "test" /f x2DSPYP.inf /r 10.5.43.32 /m "845 PS"
Run Code Online (Sandbox Code Playgroud)
然后生成它:
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();
}
Run Code Online (Sandbox Code Playgroud)
这似乎有效......不是理想的方法,但对于那些不在打印服务器上的打印机来说,它似乎可以完成这项工作。