2011-03-24 783 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設置爲該字符串。

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