使用WIN32API获取打印机 转来转去,又回到WIN32API上来了,无奈啊。。。。。。怪不得C++依然这么吃香 啊。。。。。
.Net给我们提供了DllImport来操作非托管的DLL(发现C#如此的强啊~~~~暗自偷笑)。
主要使用到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#中对非托管函数的调用,以及相互之间的数据封装还是一个比较难的地方,有空还需要整理一下。