如何检测打印机所在的端口(Ne01:,Ne02:,Ne99:等)?
BigCorp的计算机(WinXP)安装了Adobe Acrobat(版本7.0 Pro),它提供了一个名为“Adobe PDF”的虚拟打印机。如果在录制宏的同时将Excel(2003)工作簿打印为pdf,则打印机的全名为“Nexx上的Adobe PDF:”,其中xx是两位数......并且不同取决于具体内容你试试的电脑。
我已经使用Excel.Interop编写了一个C#控制台应用程序(我强烈反对其他任何人开始这条路走向地狱),这会打开一系列电子表格。它在每个中运行一个宏,保存,打印为pdf,然后将pdf移动到共享驱动器上的报告文件夹。
我面临的问题是,每次安装Acrobat似乎都会为PDF打印机选择一个随机端口号...我无法弄清楚如何获取它。
到目前为止,我已尝试使用Win32_Printer class,因此
var searcher = new ManagementObjectSearcher( @"SELECT * FROM Win32_Printer" );
foreach ( ManagementObject printer in searcher.Get() )
{
if ( Regex.IsMatch( printer["Name"].ToString(), @"(adobe|pdf)", RegexOptions.IgnoreCase ) )
{
//printer["Name"]; => "Adobe PDF"
//printer["PortName"] => "my documents/*.pdf"
foreach ( PropertyData pd in printer.Properties )
{
Console.WriteLine(string.Format("{0}, {1}", pd.Name, pd.Value));
}
break;
}
}
我也在System.Drawing.Printing类中探讨过。 PrinterSettings.InstalledPrinters将为您提供打印机“Adobe PDF”的名称,但我无法弄清楚如何获取端口信息。
如果我只将“Adobe PDF”传递给excel interop PrintOut()方法,它有时会起作用,有时会因“文档无法打印”而失败......我无法弄清楚原因。
如果我使用适当的x值传递硬编码的“Nexx上的Adobe PDF:”,则每次都 。
如果我尝试所有可能的变化,Excel会帮助打印到默认打印机。我没有选择更改默认打印机(安全策略限制)
有人能指出我正确拉动打印机端口的代码吗?
答案 0 :(得分:5)
这就是我最终做的事情
using Microsoft.Win32;
...
var devices = Registry.CurrentUser.OpenSubKey( @"Software\Microsoft\Windows NT\CurrentVersion\Devices" ); //Read-accessible even when using a locked-down account
string printerName = "Adobe PDF";
try
{
foreach ( string name in devices.GetValueNames() )
{
if ( Regex.IsMatch( name, printerName, RegexOptions.IgnoreCase ) )
{
var value = (String)devices.GetValue( name );
var port = Regex.Match( value, @"(Ne\d+:)", RegexOptions.IgnoreCase ).Value;
return printerName + " on " + port;
}
}
}
catch
{
throw;
}
答案 1 :(得分:1)
上次我使用Acrobat时,它总是习惯于在LPT1上安装自己:从而避免了这个问题。但我认为你必须在注册表中徘徊,HKCU\Software\Microsoft\Windows NT\CurrentVersion\Devices
拥有它们。
答案 2 :(得分:0)
正如您发现必须查询注册表一样,这是我使用 [在VBA中] 的方式,这是我从Chip Pearson's great Excel site获得的:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' modListPrinters
' By Chip Pearson, chip@cpearson.com www.cpearson.com
' Created 22-Sept-2012
' This provides a function named GetPrinterFullNames that
' returns a String array, each element of which is the name
' of a printer installed on the machine.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const HKEY_CURRENT_USER As Long = &H80000001
Private Const HKCU = HKEY_CURRENT_USER
Private Const KEY_QUERY_VALUE = &H1&
Private Const ERROR_NO_MORE_ITEMS = 259&
Private Const ERROR_MORE_DATA = 234
Private Const REG_SZ = 1
Private Declare Function RegOpenKeyEx Lib "advapi32" _
Alias "RegOpenKeyExA" ( _
ByVal hKey As Long, _
ByVal lpSubKey As String, _
ByVal ulOptions As Long, _
ByVal samDesired As Long, _
phkResult As Long) As Long
Private Declare Function RegEnumValue Lib "ADVAPI32.DLL" _
Alias "RegEnumValueA" ( _
ByVal hKey As Long, _
ByVal dwIndex As Long, _
ByVal lpValueName As String, _
lpcbValueName As Long, _
ByVal lpReserved As Long, _
lpType As Long, _
lpData As Byte, _
lpcbData As Long) As Long
Private Declare Function RegCloseKey Lib "ADVAPI32.DLL" ( _
ByVal hKey As Long) As Long
Public Function GetPrinterFullNames() As String()
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GetPrinterFullNames
' By Chip Pearson, chip@cpearson.com, www.cpearson.com
' Returns an array of printer names, where each printer name
' is the device name followed by the port name. The value can
' be used to assign a printer to the ActivePrinter property of
' the Application object. Note that setting the ActivePrinter
' changes the default printer for Excel but does not change
' the Windows default printer.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim Printers() As String ' array of names to be returned
Dim PNdx As Long ' index into Printers()
Dim hKey As Long ' registry key handle
Dim Res As Long ' result of API calls
Dim Ndx As Long ' index for RegEnumValue
Dim ValueName As String ' name of each value in the printer key
Dim ValueNameLen As Long ' length of ValueName
Dim DataType As Long ' registry value data type
Dim ValueValue() As Byte ' byte array of registry value value
Dim ValueValueS As String ' ValueValue converted to String
Dim CommaPos As Long ' position of comma character in ValueValue
Dim ColonPos As Long ' position of colon character in ValueValue
Dim M As Long ' string index
' registry key in HCKU listing printers
Const PRINTER_KEY = "Software\Microsoft\Windows NT\CurrentVersion\Devices"
PNdx = 0
Ndx = 0
' assume printer name is less than 256 characters
ValueName = String$(256, Chr(0))
ValueNameLen = 255
' assume the port name is less than 1000 characters
ReDim ValueValue(0 To 999)
' assume there are less than 1000 printers installed
ReDim Printers(1 To 1000)
' open the key whose values enumerate installed printers
Res = RegOpenKeyEx(HKCU, PRINTER_KEY, 0&, _
KEY_QUERY_VALUE, hKey)
' start enumeration loop of printers
Res = RegEnumValue(hKey, Ndx, ValueName, _
ValueNameLen, 0&, DataType, ValueValue(0), 1000)
' loop until all values have been enumerated
Do Until Res = ERROR_NO_MORE_ITEMS
M = InStr(1, ValueName, Chr(0))
If M > 1 Then
' clean up the ValueName
ValueName = Left(ValueName, M - 1)
End If
' find position of a comma and colon in the port name
CommaPos = InStr(1, ValueValue, ",")
ColonPos = InStr(1, ValueValue, ":")
' ValueValue byte array to ValueValueS string
On Error Resume Next
ValueValueS = Mid(ValueValue, CommaPos + 1, ColonPos - CommaPos)
On Error GoTo 0
' next slot in Printers
PNdx = PNdx + 1
Printers(PNdx) = ValueName & " on " & ValueValueS
' reset some variables
ValueName = String(255, Chr(0))
ValueNameLen = 255
ReDim ValueValue(0 To 999)
ValueValueS = vbNullString
' tell RegEnumValue to get the next registry value
Ndx = Ndx + 1
' get the next printer
Res = RegEnumValue(hKey, Ndx, ValueName, ValueNameLen, _
0&, DataType, ValueValue(0), 1000)
' test for error
If (Res <> 0) And (Res <> ERROR_MORE_DATA) Then
Exit Do
End If
Loop
' shrink Printers down to used size
ReDim Preserve Printers(1 To PNdx)
Res = RegCloseKey(hKey)
' Return the result array
GetPrinterFullNames = Printers
End Function
然后我使用此功能获取PDF打印机名称:
Public Function FindPDFPrinter() As String
'this function finds the exact printer name for the Adobe PDF printer
Dim Printers() As String
Dim N As Integer
FindPDFPrinter = ""
Printers = GetPrinterFullNames()
For N = LBound(Printers) To UBound(Printers)
If InStr(1, Printers(N), "PDF") Then
FindPDFPrinter = Printers(N)
End If
Next N
End Function
然后将Application.ActivePrinter设置为该String。
如果你真的需要这个端口,你可以把它拉出字符串的末尾。