主要使用到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)的定义
新闻热点
疑难解答