关于c#中枚举打印机_c#应用

2008-02-23 05:44:49来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

引言
前段时间为客户研发一套打印机配套的软件,对C#中调用打印机做了些研究。

---------------------------------------------

问题
.Net Framework 1.1给我们提供了一个PrinterSettings类,以提供指定有关文档打印方式的信息,其中包括打印文档的打印机。其中的静态属性InstalledPrinters能够使我们获取安装在电脑上任何打印机的名称。
但是可惜的是,该属性仅仅能够提供已安装的打印机的名称。对于获取该打印机的相关信息(如打印机类型等)却无能为力。问题就产生了,由于客户无法提供打印机的SDK,所以对打印机的筛选(处于商业目的,客户需要软件只能在使用他们的打印机时才能输出)只能通过打印机驱动的辨认来实现。

----------------------------------------------


解决方案一 使用WMI获取打印机信息

WMI,全称Windows Management Instrumentation。是可伸缩的系统管理结构,他采用一个统一的、基于标准的、可扩展的面向对象接口。WMI 为您提供和系统管理信息和基础 WMI API 交互的标准方法。WMI 主要由系统管理应用程式研发人员和管理员用来访问和操作系统管理信息。

.Net Framework中System.Management类提供了对WMI的支持,其中ManagementObjectSearcher用于根据指定的查询或枚举检索 ManagementObject 或 ManagementClass 对象的集合。

/**//// <summary>
/// Code 1:WMI搜索示例
/// <summary>
/// <param name="strDrivername">驱动名称</param>
/// <returns>返回找到的打印机列表</returns>
/// <remarks>strDrivername支持”%“连同”_“通配符查询,类似于SQL语句中的查询<remarks>
public StringCollection GetPrintsWithDrivername( string strDrivername )
{
StringCollection scPrinters = new StringCollection();
string strcheck = "";
if( strDrivername !="" && strDrivername != "*" )
strcheck = " where DriverName like \" strDrivername "\";
string searchQuery = "SELECT Name FROM Win32_Printer" strcheck;
ManagementObjectSearcher searchPrinters =
new ManagementObjectSearcher(searchQuery);
ManagementObjectCollection printerCollection = searchPrinters.Get();

foreach(ManagementObject printer in printerCollection)
{
string printname = printer.Properties["Name"].Value.ToString();
scPrinters.Add(printname);
}
searchPrinters.Dispose();
printerCollection.Dispose();

return scPrinters;
}


问题看上去基本解决了,运行程式的确是获得了正确的打印机列表。可是用户用了一段时间后发现,有的时候打印机无法正确获得,看来DOTNET调用WMI稳定性的确有点问题啊。。。。。。

WMI本身功能还是相当强大的,通过VBS基本能够涵盖WINDOWS最基本的操作。周详能够参加MSDN的文档。

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/wmi_start_page.asp

-------------------------------------------

解决方案二 使用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获得的打印机

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: 怎样在您的应用程式中集成google搜索?_c#应用

下一篇: php实现简单线性回归之数据研究工具_php技巧