主要使用到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)的定義
新聞熱點
疑難解答