1. 程式人生 > >C# 使用WIN32API獲取印表機

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)的定義