天天看點

【轉】BarTender與ASP.NET的內建小結(條碼标簽列印程式設計)

話說自從上次發了篇NHibernate的資料後,好久沒有寫東西了,半年來一直在忙一個項目,做完項目後,發現很多東西雖然當時做了,懂了,但是很快就會模糊了,于是又再想起總結的重要性~~沒啥地方好放資料的,放在部落格園也是一個不錯的選擇~~

本人也是新手,寫的不好的地方,請多原諒。如果發現有什麼錯誤,請指出,我會更改的,謝謝!

本文章做探讨交流隻用,歡迎轉載,轉載請注明出處,謝謝!

本來在做SilverLight的東西的,後來項目有需求,說要在系統裡加入條形碼的設計和列印功能,PM提出兩個方案,一個就是自己去開發一個條形碼設計器,這樣的好處就是跟系統的內建使用比較友善,但是開發這個設計器又是一個比較大的Task;另外一個方案就是使用客戶原有的BarTender軟體,把軟體內建到系統中,那麼設計部分還是交由BarTender去完成,我們的系統隻需開發內建的部分就好。經過商量,大家決定了采取內建BarTender的方案,于是就要找人去做技術攻關了,跟原來的Partner商量了一下,他說想繼續深入學習SilverLight,我就想去涉獵更多的東西,于是剛好,分道了~~

在剛開始接觸BarTender的時候,發現網上的資料很少,我是把他們官網上的資料都看了,什麼白皮書啊,向導之類的都看了。我們的系統是ASP.NET做的,通過一段時間的學習,知道了BarTender的幾種內建模式。ActiveX COM內建,Commander的觸發式內建,還有9.0版本後支援的.NET SDK的支援。簡單說說這幾個方式:

1、              ActiveX COM:BarTender在你的機器上安裝好後,會在機器上注冊一個COM,你在程式中可以調用這個COM,使用他提供的方法和屬性,進行BarTender的程式級控制。這個內建方式比較實用,對BarTender的版本要求低,不過因為是基本的COM使用,是以要求你對COM的接口比較熟悉,對整個BarTender的調用流程和細節比較清晰,對于COM接口的描述,大家可以參考Automation.chm這個幫助文檔(在Seagull\BarTender Suite\BarTender目錄下)。

2、              Commander的觸發式內建:簡單來說,這個是通過配置BarTender,讓他監視某個檔案,當程式生成這個檔案的時候,就會觸發喚醒BarTender進行列印工作,這種方式我覺得不大好用,是以了解也不多,歡迎讨論交流。

3、              .NET SDK:這個是9.0版本開始支援的一個适用于.NET架構的SDK,裡面提供了很多類來進行BarTender的控制,由于這個SDK也是用.NET編寫的,是以對于用在.NET下的內建非常友善,不過由于對版本有要求,是以要考慮客戶的成本來使用。

一、.NET SDK

我們的項目開始的時候是使用.NET SDK 的,因為那時都還沒有搞清楚客戶是需要在伺服器列印還是用戶端列印,老大就要求先開始研究了,這個很氣人!做了許久才說客戶要在用戶端列印,把之前做的一切東西都推翻了~~

.NET SDK裡面分開了兩個,一個是标準的,一個是Server版的,标準的隻是簡單的開啟BarTender程序去處理列印任務,是以當有多個任務同時列印的時候,就需要自己去管理任務隊列問題;而Server版的就是裡面有了任務隊列機制,很友善的管理任務隊列和BarTender的程序資源。但是Server版需要安裝BarTender的Enterprise版才支援,ORZ~~什麼都是錢~~

1、              SDK其實底層上也是對COM的調用,隻不過封裝了,讓開發者更好操作,标準的SDK應該看幫助文檔沒什麼問題,裡面對各個類以及他們的方法和屬性都做了詳細的解釋。下面給出一段代碼,裡面代表了最簡單的典型使用:<!--[endif]-->

        首先添加引用,在.NET的TAB裡面可以找到Seagull.BarTender.Print

        然後,在程式裡添加命名空間引用 “using Seagull.BarTender.Print;”

        之後程式的簡單使用如下:

            //new an BarTender engine

          Engine engine = new Engine(true);

          //use the engine to open a format document to return a LabelFormatDocument object

          LabelFormatDocument format = engine.Documents.Open("c:\\test.btw");

          //use the LabelFormatDocument object to print

          format.Print("Select printer", out messages);

           使用完成後記得回收相關資源。

  2、              對于Server版的SDK,我在這裡稍微的描述一下他的隊列管理詳細吧,不過單純使用SDK是不需要知道這些東西的,使用上跟标準的SDK一樣簡單,隻要參考幫助文檔和Samples就可以很好明白了。寫出他的隊列管理詳細僅供大家探讨~~大家看這一部分源碼的時候,要先看一下線程的相關知識。<!--[endif]-->

      1) 程式流程核心是:把任務放進任務隊列裡,任務隊列檢測到有任務在排隊的話,就把任務扔到引擎管理中,選擇一個空閑的引擎來執行任務。

      2) 管理任務隊列主要是使用BtPool類,這個類裡面的Consume函數不斷地檢測隊列是否為空,如果不為空,則開始任務的送出工作,先通過engine.Status != TaskEngineStatus.Busy來檢測空閑的Engine,然後通過engine.SubmitTask(this.m_masterTaskQueue)來送出任務到Engine裡。

    在SubmitTask函數裡面,我們可以看到把扔進來的任務付給目前引擎對應的任務的句子:

      this.m_task = tasks.Dequeue();

    然後我們檢視管理引擎的主要類TaskEngine,可以看到裡面同樣有一個Consume函數,他會不斷檢測目前引擎對應的任務是否為空,不為空則開始執行任務。

    是以,當SubmitTask函數裡通過this.m_task = tasks.Dequeue()把任務賦給了目前引擎的任務後,就會開始任務執行的Task.Run()方法。

    在Task.Run()方法裡,根據多态的特性,調用this.OnRun()的時候,是調用了PrintLabelFormatTask類的OnRun()方法。在PrintLabelFormatTask類的OnRun()方法裡就實作了把任務發送到列印機或者列印成檔案的工作。

      BtPool管理任務隊列和引擎池。TaskEngine對應的是一個引擎。TaskQueue為隊列的相關操作的類。TaskEngines為TaskEngine的相關操作的類。

  3、              大家可能看到網絡浏覽器的列印例子,裡面寫到了用戶端的列印,這個用戶端的列印其實也是在伺服器上做,但伺服器上做的隻是把列印的結果輸出為一個列印檔案,然後把檔案傳送到用戶端,用戶端再通過JaveScript調用本地的列印機讀取列印檔案進行列印。這個要求伺服器和用戶端都裝有同一個列印機驅動,而且用戶端真正列印時使用的列印機驅動,要跟伺服器上用來生成列印檔案的列印機驅動一緻。這裡也有對這種方式的一些資料,僅供參考:<!--[endif]-->

1)WebLabelPrint用戶端列印

 //設定列印到檔案

labelFormat.PrintSetup.PrintToFile = true;

//設定列印機

      labelFormat.PrintSetup.PrinterName = compatibleServerPrinter;

      //設定列印機的License

labelFormat.PrintSetup.PrintToFileLicense = Request.Form.Get(_listPrinters.PrintLicenseUniqueID);

      string tempFullPath = (string)Application["TempFolderFullPath"];

//設定列印檔案的路徑

           labelFormat.PrintSetup.PrintToFileName = System.IO.Path.Combine(tempFullPath,Guid.NewGuid().ToString() + ".prn");

2)設定好以上東西後,就像正常的伺服器列印一樣,把任務發送到任務隊列,當列印完成的時候,調用函數TaskPrint_Succeeded,裡面将printTask.PrintCode讀取出來,然後把列印碼發送到本地的列印機進行列印。

3)ClientPrinting.js: PrintList.aspx頁面裡用到GetClientPrinters函數,完成用戶端列印的主要是BarTenderPrintClient.js和WebLabelPrintSample.js檔案。

4)BarTenderPrintClient.js檔案裡主要包含了一些針對列印機的操作,如獲得列印機清單,比對伺服器和用戶端的列印機,獲得列印機的License,還有就是把列印碼發送到對應的列印機上。

        5)WebLabelPrintSample.js檔案主要包含了将用戶端列印機清單填充到DropDownList裡(PrintListControl.ascx),将用戶端列印機清單填充到Table裡(Printers.aspx)。<!--[endif]-->

二、ActiveX COM

         在我嘔心瀝血看了好久的SDK,把他的源碼反編譯出來慢慢研究了幾個星期後,老大說要在用戶端進行列印~~頓時内牛滿面~~我跟老大說起上面的那種先生成列印檔案,再發送到用戶端的列印方式,老大說不行,最好少跟伺服器進行通信,因為他們的網絡環境不怎樣~~郁悶了~~在Senior的提醒下,開始對ActiveX進行研究~~主要的思路是想通過做出一個ActiveX插件,然後進入頁面的時候在用戶端進行安裝,然後對用戶端機器上的BarTender進行控制~~既然是用ActiveX,那就使用BarTender提供的最簡單的COM就行了~

               COM裡面主要的就那麼幾個類,下面一一詳細說明:<!--[endif]-->

1)           Application類:實際上代表一個BarTender的程序,當你建立一個此類的對象的時候,就會出現一個新的BarTender程序。

2)           Format類:實際上代表一個格式标簽(BTW檔案),使用Application. Formats.Open()方法可以打開并傳回一個Format對象。這個類裡面包含了列印設定,标簽的參數設定等一系列的設定,很重要的一個類。

3)           NamedSubString類:管理标簽檔案裡所有SubString的類。

4)           DataBase類:管理标簽檔案裡設定的所有資料庫連結的類。

    5)      QueryPromts類:管理标簽檔案裡面資料庫查詢參數的類。

         <!--[endif]-->鑒于Format類是比較重要的類,這裡再對他的相關屬性和方法也做一下說明:<!--[endif]-->

1) Print方法:這個就是最常用的列印方法,裡面可設定列印的任務名,是否等待列印完成,等待逾時時間,列印過程輸出的資訊。

2) PrintOut方法:如果你需要在列印時出現列印設定對話框和狀态框,你可以選擇這個方法來實作。

3) Save方法:儲存對Format的更改。

4) SetNamedSubStringValue方法:設定某個特定的SubString的值,這裡就可以作為一個動态改變列印内容的方法。

5) SetPromt方法:跟SetNamedSubStringValue方法類似,不過他設定的是列印提示的值,某些标簽通過設定可以在列印的時候彈出對話框,輸入某些變量的值來改變列印内容,這個方法就是動态設定這些變量的。不過在內建中比較少用。

6) IdenticalCopiesOfLabel屬性:這個是設定列印時要列印多少份相同的标簽的,預設為标簽設定。

7) NumberSerializedLabels屬性:這個是序列化列印時使用的,當你的标簽啟動了序列化後,這個屬性代表的就是列印的份數,譬如你的序列化初始資料是1,增量為1,NumberSerializedLabels設定為5,那麼就會列印出1、2、3、4、5,五個标簽出來。

8) Printer屬性:指定要使用的列印機,預設為系統指定的預設列印機。

9)     PrintToFile屬性:标示是馬上用列印機列印出實物,還是生成一個列印檔案。<!--[endif]-->

通過上面方法的解釋,大家已經看到裡面已經有幾種動态控制列印内容的方式了,我在項目中使用了上面兩種,一種是直接通過SetNamedSubStringValue方法去設定某些變量的值,然後進行列印,這個适合小量的列印,因為每次都要調用Application和Format對象來處理,是以列印100份就要調用一百次,效率低,但是可以靈活設定每次的列印内容;另外一種是使用序列化列印,這個的效率就高了,因為他是隻調用一次把資料扔給BarTender,之後的都是BarTender根據序列化規則去生成列印内容,不過這個方式就欠缺靈活性,隻适用于标簽的内容是有一定的規律進行變化的大批量列印。

上面還提到了DataBase和QueryPromts類,這兩個類是用在連接配接資料庫的列印中的,這個是我用到的第三種動态控制列印内容的方法。主要思路是,在标簽裡設定好各項内容,這些内容都是對應資料庫的某些字段,然後設定好查詢條件,暴露一個或多個查詢參數,然後在程式裡通過QueryPromts類來設定這些查詢參數來查詢出不同的資料庫内容,達到動态改變列印内容的目的。Format.Databases.QueryPrompts.GetQueryPrompt()可以特定的查詢條件,然後通過設定Value屬性來設定他的值,最後設定完所有查詢條件後進行列印。

關于這幾種動态控制列印内容的方法,都是要設計标簽檔案和程式互相配合的,比較不靈活,其實可以做成更好的動态配置方式的,不過老大說沒必要,就放棄了。至于要是有朋友不了解标簽檔案的設計,我有時間會寫一個文章來專門說标簽檔案的設計的。

<!--[endif]-->

三、內建

         在做好ActiveX并确定部署好後,在網頁上調用ActiveX插件就需要用到JavaScript了,大家在部署ActiveX的網頁上,會有下面這樣一句代碼:

        <object id="BTDPrintClient" classid="clsid:{0750A7B0-CF1E-4EAD-8C73-E0C8F6D9E890}" codebase="CAB/BarTender_AX.cab"></object>

       這裡也提醒一下,第二個屬性的名字是classid,然後裡面設定的字元串的開頭那幾個是clsid,是不同的,我當時就在這裡沒注意,部署了好久都不行。

       回到JavaScript的調用上來,在調用時,主要就是下面的代碼:

            printClient = new ActiveXObject("BTDPrintClient.PrintClient");

     這裡應該很好了解,就是建立BTDPrintClient這個object對象裡面的PrintClient對象。完成這一句後,printClient就等于是一個PrintClient的對象了,你可以在JavaScript裡面調用PrintClient的各種方法屬性了,于是就可以控制本地的BarTender了。 

四、小結

         做一個東西的內建,我覺得首先你是必須要去很了解這個要內建的軟體,可以通過上網搜尋資料,官方文檔,最重要的還是軟體自身的一些幫助文檔和API文檔,基本軟體的資訊都在裡面了。而且這次做內建我還聯系上了BarTender的亞太區這邊的技術支援,也給我帶來了不少幫助,雖然他們是要購買産品才能提供支援,但是初步的支援還是可以提供的,你隻要跟他們說在用他們的試用版進行內建測試,看效果如何再決定要不要購買産品,哈哈~~引誘引誘~~

         還有在做一個新的東西的時候,還是建議多動手吧,做些小Demo來驗證一下想法,認真調試一下追蹤問題。不動手是沒辦法可以很好的了解一樣東西的,是以,做IT,累死了~~什麼時候上天砸些錢給我啊?燒香去~~~