C# 使用WIN32API獲取印表機
主要使用到winspool.drv中的EnumPrinters函式,程式碼如下:
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumPrinters ([MarshalAs(UnmanagedType.U4)] PRINTER_ENUM flags,
[MarshalAs(UnmanagedType.LPStr)] string sName,
uint iLevel,
IntPtr pPrinterDesc,
uint iSize,
[MarshalAs(UnmanagedType.U4)] ref uint iNeeded,
[MarshalAs(UnmanagedType.U4)] ref uint iReturned
);
說明:Marshal屬性提供了對託管程式碼與非託管程式碼見資料封送。
EnumPrinters 的 WIN32 API的定義如下:
BOOL EnumPrinters(
DWORD Flags, // printer object types
LPTSTR Name, // name of printer object
DWORD Level, // information level
LPBYTE pPrinterEnum, // printer information buffer
DWORD cbBuf, // size of printer information buffer
LPDWORD pcbNeeded, // bytes received or required
LPDWORD pcReturned // number of printers enumerated
);
問題又來啦,EnumPrinters通過Level來獲取PRINTER_INFO,而能獲得印表機驅動的是PRINTER_INFO_2,而C#中又沒有PRINTER_INFO_2結構,偶又開始暈了。。。。。
查了半天資料,網上基本上都是PRINTER_INFO_1的定義,而PRINTER_INFO_2不同與PRINTER_INFO_1,其中還包括DEVMODE結構,非託管的結構套結構,偶開始飄了~~~~
最後發現與其在C#中定義結構來對應非託管的結構,還不如直接用類來替代。所以定義了兩個類
PRINTER_INFO_2以及DEVMODE(注:由於PRINTER_INFO_2中只用到了DEVMODE結構來接收印表機
在PRINTER_INFO_2中,對於所有的DWORD型別資料,全部對應到Int32型別上面,而對於所有LPTSTR、LPDEVMODE以及PSECURITY_DESCRIPTOR一律對應到IntPtr指標型別。
為了獲取非託管中的資料,使用了一下函式獲取印表機資訊
.
PRINTER_INFO_2 pi = new PRINTER_INFO_2();
//把資料從非託管記憶體傳送到到託管記憶體
for(int i = 0; i < numPrinters; i++)
{
Marshal.PtrToStructure( prInfo, pi ); //prInfo是由上面EnumPrinters獲得的印表機
string driver = Marshal.PtrToStringAuto( pi.pDriverName );
if ( printerdriver == "" driver.ToLower().IndexOf( printerdriver ) != -1)
{
// 做相關處理
}
prInfo = new IntPtr(prInfo.ToInt32() + Marshal.SizeOf(typeof(PRINTER_INFO_2))); // 獲取下一個印表機資訊段開始
}
.
問題至此基本解決。但C#中對非託管函式的呼叫,以及相互之間的資料封裝還是一個比較難的地方,有空還需要整理一下。
文章來源:http://spaces.msn.com/sharkoo/Blog/cns!D8E832CE4545AF!158.entry
補充:在2.0中,fixed關鍵字可以用於定義一個固定大小的陣列快取,而不是像1.x中那樣還需要定義一個數字大小。但這種方式只能用於結構(struct)而不能用於類(class)的定義