2011-02-01 15 views
5

Tengo un código C# (VS2010; fx2) que se usa para llevar a cabo las funciones de la impresora. Este código funciona bien en el entorno de Windows XP. Cambiando a Windows 7, ya no funciona correctamente.Cambios usando Winspool.drv en Windows 7 64 bit desde Windows XP 32 bit

El primer comportamiento diferente es que el método GetPrinterNames() ahora solo devuelve impresoras locales. Como puede ver, los indicadores están configurados para incluir también impresoras de RED. Probé banderas diferentes, pero sin éxito.

¿Hay una biblioteca diferente a la que debería hacer referencia en la versión de Windows 7/64 bit?

clase de ayuda de la impresora con código se muestra a continuación:

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: Código editado para reducir el tamaño (zonas de menor interés eliminados).

+2

Qué cree que podría reducir esa bajar un poco? Es un gran código que quiere que veamos. –

+0

Hola John. He eliminado lo que creo que son porciones irrelevantes del código. El método de interés es GetPrinterNames() - que se basa en enumPrinters(). Otras funciones tampoco funcionan, pero sospecho que todas serán la misma causa. Gracias por adelantado. – Jayden

Respuesta

1

Según las notas de MSDN para EnumPrinters, su código sólo funciona si el tercero es parámetro de 1

de EnumPrinters ....

PRINTER_ENUM_NETWORK La función enumera las impresoras de red en el dominio del equipo. Este valor solo es válido si Level es 1.

+0

Cambiar este valor a 1 solo parece ahora elevar excepciones. Ejecutar este código (con 2 como parámetro) en Windows XP ya que funciona completamente bien, como se esperaba. Solo cuando se ejecuta en Windows 7 64 bit se produce este problema. – Jayden

+0

¿Qué excepción plantea? –

+0

cómo establecer el nivel 1 válido? – SwR

1

En la máquina de Windows de 64 bits es una excepción OverflowException (operación aritmética que derivó en un desbordamiento.) Causa al convertir un puntero en un entero de 32 bits en lugar de un entero de 64 bits.

int offset = pAddr.ToInt32(); 

fijarlo con

long offset = pAddr.ToInt64(); 

El código completo de trabajo, comprueba en Windows 10 x 64

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

Guau, gracias por el seguimiento de una pregunta de 5 años. Lamentablemente, ya no tengo acceso al proyecto o sistema operativo apropiado para las pruebas. – Jayden

Cuestiones relacionadas