2012-10-09 111 views
9

我正在玩一個來自codeproject的項目,它主要監視計算機上的打印活動。然而,它不適用於64位配置。代碼的下面部分是問題。此代碼在打印完成後被調用。如何正確定義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)); 
} 

調試顯示data [i] .field值始終爲0.在32位中,但它工作正常。我認爲PRINTER_NOTIFY_INFO_DATA沒有正確定義。目前我正在使用下面的代碼。任何人都可以解決這個問題,以便在64位上正常工作?

[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; 
} 

我正在使用MS XPS驅動程序測試打印。代碼項目文章是Here

回答

14

由於Data Alignment,它無法正確工作於64位配置。

因此,我建議你改變PRINTER_NOTIFY_INFO如下:

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

然後用Marshal.OffsetOf代替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

你救了我的命,感謝名單上百萬。 –

+0

此外,請確保所涉及的項目已配置爲構建x86可執行文件! –

+0

幾件事情要注意這一點。 1)Marshal.OffsetOf()返回一個IntPtr對象,據我所知不能直接將其轉換爲long。您必須使用IntPtr.ToInt32()方法。 2)如果PRINTER_NOTIFY_INFO.Count爲0,則此代碼可能會使代碼崩潰。這意味着aData []列表中沒有結構。按照所述的方式聲明它,你至少保證了數組中至少有一個對象。如果count爲0,那麼這是潛在的分段錯誤。我將聲明一個IntData作爲一個IntPtr,因爲真的,在非託管代碼中它只是一個指針。 – Ultratrunks