国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

關于C#中枚舉打印機

2019-11-18 17:56:25
字體:
來源:轉載
供稿:網友

引言
前段時間為客戶開發一套打印機配套的軟件,對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獲得的打印機

      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)的定義。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 南京市| 镇康县| 襄城县| 阿图什市| 土默特左旗| 正镶白旗| 余庆县| 阿拉善左旗| 岢岚县| 濮阳市| 南城县| 绥宁县| 黑水县| 栾城县| 遵义市| 红安县| 新邵县| 太湖县| 牡丹江市| 上蔡县| 霍邱县| 淳安县| 大安市| 岢岚县| 莒南县| 汾西县| 永新县| 视频| 华容县| 平山县| 河间市| 四川省| 彩票| 宁海县| 满洲里市| 宁国市| 长沙市| 沂水县| 乌鲁木齐县| 曲麻莱县| 巫山县|