| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 9352 人关注过本帖, 1 人收藏
标题:c#如何得到指定打印机的端口号...
只看楼主 加入收藏
star_520
Rank: 1
等 级:新手上路
帖 子:37
专家分:0
注 册:2008-10-11
收藏(1)
 问题点数:0 回复次数:5 
c#如何得到指定打印机的端口号...
c#如何得到指定打印机的端口号...ip地址...之类的相关信息...困扰中...谢谢...
搜索更多相关主题的帖子: 打印机 端口 
2008-10-16 12:45
skyzoneskyzone
Rank: 1
等 级:新手上路
威 望:1
帖 子:137
专家分:0
注 册:2008-10-6
收藏
得分:0 
2006-07-09 01:30:45
 
大中小
引言
前段时间为客户开发一套打印机配套的软件,对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.

 

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

解决方案二 使用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#中对非托管函数的调用,以及相互之间的数据封装还是一个比较难的地方,有空还需要整理一下。


文章来源:http://spaces.

补充:在2.0中,fixed关键字可以用于定义一个固定大小的数组缓存,而不是像1.x中那样还需要定义一个数字大小。但这种方式只能用于结构(struct)而不能用于类(class)的定义。

读万卷书莫如行万里路,行路在问题答题之中。
2008-10-16 16:55
skyzoneskyzone
Rank: 1
等 级:新手上路
威 望:1
帖 子:137
专家分:0
注 册:2008-10-6
收藏
得分:0 
要下班了。先放上去,自己找方法。

读万卷书莫如行万里路,行路在问题答题之中。
2008-10-16 16:55
skyzoneskyzone
Rank: 1
等 级:新手上路
威 望:1
帖 子:137
专家分:0
注 册:2008-10-6
收藏
得分:0 
看了一下你的问题又,你说的获取打印机端口是不是说获取打印机的信息啊?因为打印机除了打印机专用端口,就是usb端口,而它的端口是自动获取的(就是不固定的,所以你无法获取这样的信息),比如说你把打印机放在usb1它就在usb1上,而你立马放到usb2上也能用(有的打印机可以同时接两台电脑两个端口,你怎么获得?).
获取打印机信息我有方法:
string searchQuery = "SELECT * FROM Win32_Printer";
            ManagementObjectSearcher searchPrinters =
             new ManagementObjectSearcher(searchQuery);
            ManagementObjectCollection printerCollection = searchPrinters.Get();

            foreach (ManagementObject printer in printerCollection)
            {
               MessageBox.Show(printer.Path.ToString());
            }
            searchPrinters.Dispose();
            printerCollection.Dispose();

绝对原创哦(当然,是总结别人的东西精减掉许多东西)。

读万卷书莫如行万里路,行路在问题答题之中。
2008-10-17 14:11
skyzoneskyzone
Rank: 1
等 级:新手上路
威 望:1
帖 子:137
专家分:0
注 册:2008-10-6
收藏
得分:0 
如何纯粹是打印机标准名称:
using System.Drawing.Printing;
foreach (string so in PrinterSettings.InstalledPrinters)
            {
                MessageBox.Show(so);
            }
========================================================================
上楼那个需要用到:using System.Management;

读万卷书莫如行万里路,行路在问题答题之中。
2008-10-17 14:15
star_520
Rank: 1
等 级:新手上路
帖 子:37
专家分:0
注 册:2008-10-11
收藏
得分:0 
谢谢大哥的指点...

人,一定要靠自己...
2008-10-17 16:26
快速回复:c#如何得到指定打印机的端口号...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017177 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved