2011-02-01 11 views
5

Mam trochę kodu C# (VS2010; fx2), który jest używany do wykonywania funkcji drukarki. Ten kod działa poprawnie w środowisku Windows XP. Przechodząc na Windows 7, nie działa już poprawnie.Zmiany za pomocą Winspool.drv w systemie Windows 7 64-bitowe z Windows XP 32 bit

Pierwsze inne zachowanie polega na tym, że metoda GetPrinterNames() zwraca teraz tylko drukarki lokalne. Jak widać, flagi są ustawione tak, aby zawierały również drukarki sieciowe. Próbowałem różnych flag, ale bez powodzenia.

Czy istnieje inna biblioteka, do której powinienem się odwoływać w wersji Windows 7/64 bit?

drukarki klasy pomocnika z kodem poniżej:

internal class Printers 
{ 

    ... 

    [DllImport("winspool.drv", SetLastError = true)] 
    static extern bool EnumPrintersW(Int32 flags, [MarshalAs(UnmanagedType.LPTStr)] string printerName, 
     Int32 level, IntPtr buffer, Int32 bufferSize, out Int32 requiredBufferSize, 
     out Int32 numPrintersReturned); 

    [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern bool EnumPrinters(PrinterEnumFlags Flags, string Name, uint Level, IntPtr pPrinterEnum, uint cbBuf, ref uint pcbNeeded, ref uint pcReturned); 

    ... 

    ... 

    public static string[] GetPrinterNames() 
    { 
     List<string> returnVal = new List<string>(); 
     foreach(PRINTER_INFO_2 info in enumPrinters(PrinterEnumFlags.PRINTER_ENUM_LOCAL | PrinterEnumFlags.PRINTER_ENUM_NETWORK)) 
     { 
      returnVal.Add(info.pPrinterName); 
     } 
     return returnVal.ToArray(); 
    } 

... 

    private static PRINTER_INFO_2[] enumPrinters(PrinterEnumFlags Flags) 
    { 
     uint cbNeeded = 0; 
     uint cReturned = 0; 
     if (EnumPrinters(Flags, null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned)) 
     { 
      return null; 
     } 
     int lastWin32Error = Marshal.GetLastWin32Error(); 
     if (lastWin32Error == ERROR_INSUFFICIENT_BUFFER) 
     { 
      IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded); 
      if (EnumPrinters(Flags, null, 2, pAddr, cbNeeded, ref cbNeeded, ref cReturned)) 
      { 
       PRINTER_INFO_2[] printerInfo2 = new PRINTER_INFO_2[cReturned]; 
       int offset = pAddr.ToInt32(); 
       Type type = typeof(PRINTER_INFO_2); 
       int increment = Marshal.SizeOf(type); 
       for (int i = 0; i < cReturned; i++) 
       { 
        printerInfo2[i] = (PRINTER_INFO_2)Marshal.PtrToStructure(new IntPtr(offset), type); 
        offset += increment; 
       } 
       Marshal.FreeHGlobal(pAddr); 
       return printerInfo2; 
      } 
      lastWin32Error = Marshal.GetLastWin32Error(); 
     } 
     throw new System.ComponentModel.Win32Exception(lastWin32Error); 
    } 

    ... 

    [FlagsAttribute] 
    enum PrinterEnumFlags 
    { 
     PRINTER_ENUM_DEFAULT = 0x00000001, 
     PRINTER_ENUM_LOCAL = 0x00000002, 
     PRINTER_ENUM_CONNECTIONS = 0x00000004, 
     PRINTER_ENUM_FAVORITE = 0x00000004, 
     PRINTER_ENUM_NAME = 0x00000008, 
     PRINTER_ENUM_REMOTE = 0x00000010, 
     PRINTER_ENUM_SHARED = 0x00000020, 
     PRINTER_ENUM_NETWORK = 0x00000040, 
     PRINTER_ENUM_EXPAND = 0x00004000, 
     PRINTER_ENUM_CONTAINER = 0x00008000, 
     PRINTER_ENUM_ICONMASK = 0x00ff0000, 
     PRINTER_ENUM_ICON1 = 0x00010000, 
     PRINTER_ENUM_ICON2 = 0x00020000, 
     PRINTER_ENUM_ICON3 = 0x00040000, 
     PRINTER_ENUM_ICON4 = 0x00080000, 
     PRINTER_ENUM_ICON5 = 0x00100000, 
     PRINTER_ENUM_ICON6 = 0x00200000, 
     PRINTER_ENUM_ICON7 = 0x00400000, 
     PRINTER_ENUM_ICON8 = 0x00800000, 
     PRINTER_ENUM_HIDE = 0x01000000 
    } 

EDIT: Kod edytowane w celu zmniejszenia wielkości (obszary mniej interesujące usuwane).

+2

sądzisz można zawęzić, że nieco w dół? To dużo kodu, na który mamy zwrócić uwagę. –

+0

Cześć John. Usunąłem to, co uważam za nieistotne części kodu. Interesującą metodą jest GetPrinterNames() - która opiera się na enumPrinters(). Inne funkcje również nie działają - ale podejrzewam, że wszystkie będą tą samą przyczyną. Z góry dziękuję. – Jayden

Odpowiedz

1

Według notatek MSDN EnumPrinters Twój kod działa tylko wtedy, 3rd paramater jest 1

z EnumPrinters ....

PRINTER_ENUM_NETWORK Funkcja wylicza drukarki sieciowe w domenie komputera. Ta wartość jest poprawna tylko wtedy, gdy Poziom wynosi 1.

+0

Zmiana tej wartości na 1 wydaje się teraz powodować wyjątki. Uruchomienie tego kodu (z 2 jako parametr) w systemie Windows XP, ponieważ działa zupełnie dobrze, zgodnie z oczekiwaniami. Dopiero wtedy, gdy działa na Windows 7 64 bit, ten problem występuje wtedy. – Jayden

+0

Co to za wyjątek? –

+0

jak ustawić prawidłowy poziom 1? – SwR

1

Na 64-bitowym komputerze z systemem Windows jest wyjątkiem OverflowException (Operacja arytmetyczna spowodowała przepełnienie). Powodowana przez konwersję wskaźnika w 32-bitową liczbę całkowitą zamiast 64-bitowej liczby całkowitej.

int offset = pAddr.ToInt32(); 

Fix go

long offset = pAddr.ToInt64(); 

Kompletny kod roboczych, sprawdzone na systemie Windows 10 x64

public static string[] GetPrinterNames() 
{ 
    var results = new List<string>(); 
    foreach (PRINTER_INFO_2 info in enumPrinters(PrinterEnumFlags.PRINTER_ENUM_LOCAL | PrinterEnumFlags.PRINTER_ENUM_NETWORK)) 
     results.Add(info.pPrinterName); 
    return results.ToArray(); 
} 

private static PRINTER_INFO_2[] enumPrinters(PrinterEnumFlags Flags) 
{ 
    uint cbNeeded = 0; 
    uint cReturned = 0; 
    if (EnumPrinters(Flags, null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned)) 
    { 
     return null; 
    } 
    int lastWin32Error = Marshal.GetLastWin32Error(); 
    if (lastWin32Error == ERROR_INSUFFICIENT_BUFFER) 
    { 
     IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded); 
     if (EnumPrinters(Flags, null, 2, pAddr, cbNeeded, ref cbNeeded, ref cReturned)) 
     { 
      PRINTER_INFO_2[] printerInfo2 = new PRINTER_INFO_2[cReturned]; 
      long offset = pAddr.ToInt64(); 
      Type type = typeof(PRINTER_INFO_2); 
      int increment = Marshal.SizeOf(type); 
      for (int i = 0; i < cReturned; i++) 
      { 
       printerInfo2[i] = (PRINTER_INFO_2)Marshal.PtrToStructure(new IntPtr(offset), type); 
       offset += increment; 
      } 
      Marshal.FreeHGlobal(pAddr); 
      return printerInfo2; 
     } 
     lastWin32Error = Marshal.GetLastWin32Error(); 
    } 
    throw new System.ComponentModel.Win32Exception(lastWin32Error); 
} 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
internal struct PRINTER_INFO_2 
{ 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pServerName; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pPrinterName; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pShareName; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pPortName; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pDriverName; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pComment; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pLocation; 
    public IntPtr pDevMode; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pSepFile; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pPrintProcessor; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pDatatype; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public string pParameters; 
    public IntPtr pSecurityDescriptor; 
    public uint Attributes; 
    public uint Priority; 
    public uint DefaultPriority; 
    public uint StartTime; 
    public uint UntilTime; 
    public uint Status; 
    public uint cJobs; 
    public uint AveragePPM; 
} 

const int ERROR_INSUFFICIENT_BUFFER = 122; 

[FlagsAttribute] 
enum PrinterEnumFlags 
{ 
    PRINTER_ENUM_DEFAULT = 0x00000001, 
    PRINTER_ENUM_LOCAL = 0x00000002, 
    PRINTER_ENUM_CONNECTIONS = 0x00000004, 
    PRINTER_ENUM_FAVORITE = 0x00000004, 
    PRINTER_ENUM_NAME = 0x00000008, 
    PRINTER_ENUM_REMOTE = 0x00000010, 
    PRINTER_ENUM_SHARED = 0x00000020, 
    PRINTER_ENUM_NETWORK = 0x00000040, 
    PRINTER_ENUM_EXPAND = 0x00004000, 
    PRINTER_ENUM_CONTAINER = 0x00008000, 
    PRINTER_ENUM_ICONMASK = 0x00ff0000, 
    PRINTER_ENUM_ICON1 = 0x00010000, 
    PRINTER_ENUM_ICON2 = 0x00020000, 
    PRINTER_ENUM_ICON3 = 0x00040000, 
    PRINTER_ENUM_ICON4 = 0x00080000, 
    PRINTER_ENUM_ICON5 = 0x00100000, 
    PRINTER_ENUM_ICON6 = 0x00200000, 
    PRINTER_ENUM_ICON7 = 0x00400000, 
    PRINTER_ENUM_ICON8 = 0x00800000, 
    PRINTER_ENUM_HIDE = 0x01000000 
} 

[DllImport("winspool.drv", SetLastError = true)] 
static extern bool EnumPrintersW(Int32 flags, [MarshalAs(UnmanagedType.LPTStr)] string printerName, 
       Int32 level, IntPtr buffer, Int32 bufferSize, out Int32 requiredBufferSize, 
       out Int32 numPrintersReturned); 

[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] 
private static extern bool EnumPrinters(PrinterEnumFlags Flags, string Name, uint Level, IntPtr pPrinterEnum, uint cbBuf, ref uint pcbNeeded, ref uint pcReturned); 
+0

Wow, dziękuję za kontynuację 5-letniego quesitonu. Niestety, nie mam już dostępu do projektu lub systemu operacyjnego odpowiedniego do testowania. – Jayden

Powiązane problemy