Как определить, какой порт «Ne» используется на принтере Adobe PDF? - PullRequest
4 голосов
/ 24 марта 2011

Как определить, какой порт (Ne01 :, Ne02 :, Ne99: и т. Д.) Включен принтер?

На компьютерах (WinXP) в BigCorp установлен Adobe Acrobat (версия 7.0 Pro), который даетвиртуальный принтер с именем «Adobe PDF».Если вы печатаете книгу Excel (2003) в формате PDF во время записи макроса, полное имя принтера будет «Adobe PDF на Nexx:», где xx - это двузначная цифра .... и отличается в зависимости от того, какой компьютерВы пытаетесь.

Я написал консольное приложение на C #, используя Excel.Interop (я настоятельно не рекомендую никому другому начинать этот путь в ад), который открывает серию электронных таблиц.Он запускает макрос в каждом из них, сохраняет, печатает в формате PDF, а затем перемещает PDF в папку отчетов на общем диске.

Проблема, с которой я сталкиваюсь, заключается в том, что каждая установка Acrobat, кажется, выбирает случайныйномер порта для принтера PDF ... и я не могу понять, как его получить.

До сих пор я пытался использовать класс Win32_Printer , например,

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», но я не могу понять, как получить port info.

Если япередать только «Adobe PDF» методу Excel interop PrintOut (), он иногда работает, а иногда не работает с «документ не удалось распечатать» ... Я не могу понять, почему.

Если я передаю жестко закодированный Adobe PDFв Ne0x: «с соответствующим значением x он работает каждый раз .

Если я пытаюсь использовать все возможные варианты, Excel помогает печатать на принтере по умолчанию.У меня нет возможности изменить принтер по умолчанию (ограничение политики безопасности)

Может кто-нибудь указать мне код, который правильно перетягивает порт принтера?

Ответы [ 3 ]

5 голосов
/ 28 апреля 2011

Вот что я в итоге сделал

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 голос
/ 24 марта 2011

В прошлый раз, когда я использовал Acrobat, он всегда использовался для установки на LPT1, что позволило избежать проблемы. Но я думаю, что вы должны валяться в реестре, у HKCU\Software\Microsoft\Windows NT\CurrentVersion\Devices есть они.

0 голосов
/ 11 января 2013

Как вы обнаружили, что вам нужно запросить реестр, я использовал [в VBA] , который я получил с Чип Пирсона с отличного сайта Excel :

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 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 в эту строку.

И если вам действительно нужен порт, вы можете снять его с конца строки.

...