2011-02-01 67 views
5

Tôi có một số mã C# (VS2010; fx2) được sử dụng để thực hiện các chức năng của máy in. Mã này hoạt động tốt trong môi trường Windows XP. Thay đổi sang Windows 7, nó không còn hoạt động chính xác nữa.Thay đổi sử dụng Winspool.drv trong Windows 7 64 bit từ Windows XP 32 bit

Hành vi khác nhau đầu tiên là phương thức GetPrinterNames() hiện chỉ trả về máy in cục bộ. Như bạn có thể thấy, các cờ được thiết lập để bao gồm cả máy in NETWORK. Tôi đã thử các cờ khác nhau, nhưng không thành công.

Có thư viện nào khác mà tôi nên tham khảo trong phiên bản Windows 7/64 bit không?

Printer lớp helper với mã hiển thị dưới đây:

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: Mã sửa để giảm kích thước (lĩnh vực quan tâm ít bị loại bỏ).

+2

Bạn nghĩ bạn có thể thu hẹp lại một chút? Đó là rất nhiều mã bạn muốn chúng tôi xem xét. –

+0

Xin chào John. Tôi đã xóa những gì tôi nghĩ là các phần không liên quan của mã. Phương thức quan tâm là GetPrinterNames() - dựa trên enumPrinters(). Các chức năng khác cũng không hoạt động - nhưng tôi nghi ngờ nó sẽ là nguyên nhân tương tự. Cảm ơn trước. – Jayden

Trả lời

1

Theo ghi chú MSDN cho EnumPrinters, mã của bạn chỉ hoạt động nếu paramater thứ 3 là 1

từ EnumPrinters ....

PRINTER_ENUM_NETWORK Chức năng liệt kê các máy in mạng trong phạm vi của máy tính. Giá trị này chỉ hợp lệ nếu Cấp là 1.

+0

Thay đổi giá trị này thành 1 chỉ dường như hiện đang tăng ngoại lệ. Chạy mã này (với 2 là tham số) trong Windows XP vì nó hoạt động hoàn toàn tốt, như mong đợi. Chỉ khi chạy trên Windows 7 64 bit thì vấn đề này mới xảy ra. – Jayden

+0

Trường hợp ngoại lệ gì? –

+0

cách đặt cấp hợp lệ 1? – SwR

1

Trên máy tính 64 bit là ngoại lệ OverflowException (Số học hoạt động dẫn đến tràn.) Gây ra bằng cách chuyển đổi con trỏ trong số nguyên 32 bit thay vì số nguyên 64 bit.

int offset = pAddr.ToInt32(); 

Khắc phục sự cố với

long offset = pAddr.ToInt64(); 

Mã làm việc hoàn chỉnh, kiểm tra trên 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, cảm ơn vì đã theo dõi một quesiton 5 tuổi. Thật không may, tôi không còn quyền truy cập vào dự án hoặc hệ điều hành thích hợp để thử nghiệm. – Jayden

Các vấn đề liên quan