2011-03-24 796 views
4

如何检测打印机打开的端口(Ne01:,Ne02:,Ne99:等)?如何确定Adobe PDF打印机的“Ne”端口?

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()方法,它有时会起作用,有时会导致“Document failed to print”失败......我找不到原因。

如果我通过一个硬编码的“Adobe PDF在Ne0x:”与一个适当的x值它工作每次

如果我尝试每种可能的变化,Excel将帮助打印到默认打印机。我没有选择更改默认打印机(安全策略限制)

任何人都可以指向正确拉取打印机端口的代码吗?

回答

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

上次我使用Acrobat时,它总是用来在LPT1上自行安装:从而避免了这个问题。但我认为你不得不在注册表中徘徊,HKCU\Software\Microsoft\Windows NT\CurrentVersion\Devices有他们。

0

当你发现你要查询注册表,是我用[在VBA],这是我从Chip Pearson's great Excel site拿到方式:

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 
' modListPrinters 
' By Chip Pearson, [email protected] 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, [email protected]pearson.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设置为该字符串。

如果你真的只是需要端口,你可以把它从字符串的末尾拉出来。