2012-10-09 28 views
9

Estaba jugando con un proyecto de codeproject que básicamente supervisa la actividad de impresión en la computadora. Sin embargo, no funciona correctamente para la configuración de 64 bits. La parte inferior del código era el problema. Este código se invoca siempre que se realiza la impresión.¿Cómo se define correctamente PRINT_NOTIFY_INFO_DATA?

PRINTER_NOTIFY_INFO info = (PRINTER_NOTIFY_INFO)Marshal.PtrToStructure(pNotifyInfo, typeof(PRINTER_NOTIFY_INFO));       
int pData = (int)pNotifyInfo + Marshal.SizeOf(typeof(PRINTER_NOTIFY_INFO)); 
PRINTER_NOTIFY_INFO_DATA[] data = new PRINTER_NOTIFY_INFO_DATA[info.Count]; 
for (uint i = 0; i < info.Count; i++) 
{ 
    data[i] = (PRINTER_NOTIFY_INFO_DATA)Marshal.PtrToStructure((IntPtr)pData, typeof(PRINTER_NOTIFY_INFO_DATA)); 
    pData += Marshal.SizeOf(typeof(PRINTER_NOTIFY_INFO_DATA)); 
} 

depuración muestra que los datos [i] .field valor es siempre 0. En 32 bits sin embargo funciona correctamente. Creo que la PRINTER_NOTIFY_INFO_DATA no está definida correctamente. Actualmente estoy usando el siguiente código. ¿Alguien puede arreglar esto para que funcione correctamente en 64 bit también?

[StructLayout(LayoutKind.Sequential)] 
public struct PRINTER_NOTIFY_INFO 
{ 
    public uint Version; 
    public uint Flags; 
    public uint Count; 
} 


[StructLayout(LayoutKind.Sequential)] 
public struct PRINTER_NOTIFY_INFO_DATA_DATA 
{ 
    public uint cbBuf; 
    public IntPtr pBuf; 
} 

[StructLayout(LayoutKind.Explicit)] 
public struct PRINTER_NOTIFY_INFO_DATA_UNION 
{ 
    [FieldOffset(0)] 
    private uint adwData0; 
    [FieldOffset(4)] 
    private uint adwData1; 
    [FieldOffset(0)] 
    public PRINTER_NOTIFY_INFO_DATA_DATA Data; 
    public uint[] adwData 
    { 
     get 
     { 
      return new uint[] { this.adwData0, this.adwData1 }; 
     } 
    } 
} 

// Structure borrowed from http://lifeandtimesofadeveloper.blogspot.com/2007/10/unmanaged-structures-padding-and-c-part_18.html. 
[StructLayout(LayoutKind.Sequential)] 
public struct PRINTER_NOTIFY_INFO_DATA 
{ 
    public ushort Type; 
    public ushort Field; 
    public uint Reserved; 
    public uint Id; 
    public PRINTER_NOTIFY_INFO_DATA_UNION NotifyData; 
} 

Estaba probando la impresión con el controlador MS XPS. El artículo del proyecto de código es Here

Respuesta

14

No funciona correctamente para la configuración de 64 bits debido a Data Alignment.

por lo que sugiero que cambie PRINTER_NOTIFY_INFO de la siguiente manera:

[StructLayout(LayoutKind.Sequential)] 
public struct PRINTER_NOTIFY_INFO 
{ 
    public uint Version; 
    public uint Flags; 
    public uint Count; 
    public PRINTER_NOTIFY_INFO_DATA_UNION aData; 
} 

y luego usar Marshal.OffsetOf en lugar de Marshal.SizeOf:

PRINTER_NOTIFY_INFO info = (PRINTER_NOTIFY_INFO)Marshal.PtrToStructure(pNotifyInfo, typeof(PRINTER_NOTIFY_INFO));       
long pData = (long)pNotifyInfo + (long)Marshal.OffsetOf(typeof(PRINTER_NOTIFY_INFO), "aData"); 
PRINTER_NOTIFY_INFO_DATA[] data = new PRINTER_NOTIFY_INFO_DATA[info.Count]; 
for (uint i = 0; i < info.Count; i++) 
{ 
    data[i] = (PRINTER_NOTIFY_INFO_DATA)Marshal.PtrToStructure((IntPtr)pData, typeof(PRINTER_NOTIFY_INFO_DATA)); 
    pData += (long)Marshal.SizeOf(typeof(PRINTER_NOTIFY_INFO_DATA)); 
} 
+0

has salvado la vida, Gracias un millón. –

+0

Además, asegúrese de que los proyectos involucrados estén configurados para compilar ejecutables x86. –

+0

Un par de cosas para tener en cuenta sobre esto. 1) Marshal.OffsetOf() devuelve un objeto IntPtr, que a mi conocimiento no se puede convertir directamente en un largo. Debe usar el método IntPtr.ToInt32(). 2) Este código puede bloquear su código si PRINTER_NOTIFY_INFO.Count es 0. Significaría que no hay estructuras en la lista aData []. Al declararlo en la forma descrita, usted está garantizando al menos 1 objeto en la matriz. Si count es 0, entonces es posible una falla de segmentación. Yo declararía aData como IntPtr en su lugar, ya que realmente, en código no administrado solo es un puntero. – Ultratrunks