BarTender是一款優秀的條碼列印軟體,可以支援很多種類型的條碼設計和列印,具體大家可參考他的官網(http://www.seagullscientific.com/aspx/products.aspx),這裡不多介紹。
在剛開始接觸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應該看協助文檔沒什麼問題,裡面對各個類以及他們的方法和屬性都做了詳細的解釋。下面給出一段代碼,裡面代表了最簡單的典型使用:
首先添加引用,在.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就可以很好明白了。寫出他的隊列管理詳細僅供大家探討~~大家看這一部分源碼的時候,要先看一下線程的相關知識。
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調用本地的印表機讀取列印檔案進行列印。這個要求伺服器和用戶端都裝有同一個印表機驅動,而且用戶端真正列印時使用的印表機驅動,要跟伺服器上用來產生列印檔案的印表機驅動一致。這裡也有對這種方式的一些資料,僅供參考:
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)。
二、ActiveX COM
在我嘔心瀝血看了好久的SDK,把他的源碼反編譯出來慢慢研究了幾個星期後,老大說要在用戶端進行列印~~頓時內牛滿面~~我跟老大說起上面的那種先產生列印檔案,再發送到用戶端的列印方式,老大說不行,最好少跟伺服器進行通訊,因為他們的網路環境不怎樣~~鬱悶了~~在Senior的提醒下,開始對ActiveX進行研究~~主要的思路是想通過做出一個ActiveX外掛程式,然後進入頁面的時候在用戶端進行安裝,然後對用戶端機器上的BarTender進行控制~~既然是用ActiveX,那就使用BarTender提供的最簡單的COM就行了~
COM裡面主要的就那麼幾個類,下面一一詳細說明:
1) Application類:實際上代表一個BarTender的進程,當你建立一個此類的對象的時候,就會出現一個新的BarTender進程。
2) Format類:實際上代表一個格式標籤(BTW檔案),使用Application. Formats.Open()方法可以開啟並返回一個Format對象。這個類裡麵包含了列印設定,標籤的參數設定等一系列的設定,很重要的一個類。
3) NamedSubString類:管理標籤檔案裡所有SubString的類。
4) DataBase類:管理標籤檔案裡設定的所有資料庫連結的類。
5) QueryPromts類:管理標籤檔案裡面資料庫查詢參數的類。
鑒於Format類是比較重要的類,這裡再對他的相關屬性和方法也做一下說明:
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屬性:標示是馬上用印表機列印出實物,還是產生一個列印檔案。
通過上面方法的解釋,大家已經看到裡面已經有幾種動態控制列印內容的方式了,我在項目中使用了上面兩種,一種是直接通過SetNamedSubStringValue方法去設定某些變數的值,然後進行列印,這個適合小量的列印,因為每次都要調用Application和Format對象來處理,所以列印100份就要調用一百次,效率低,但是可以靈活設定每次的列印內容;另外一種是使用序列化列印,這個的效率就高了,因為他是只調用一次把資料扔給BarTender,之後的都是BarTender根據序列化規則去產生列印內容,不過這個方式就欠缺靈活性,只適用於標籤的內容是有一定的規律進行變化的大批量列印。
上面還提到了DataBase和QueryPromts類,這兩個類是用在串連資料庫的列印中的,這個是我用到的第三種動態控制列印內容的方法。主要思路是,在標籤裡設定好各項內容,這些內容都是對應資料庫的某些欄位,然後設定好查詢條件,暴露一個或多個查詢參數,然後在程式裡通過QueryPromts類來設定這些查詢參數來查詢出不同的資料庫內容,達到動態改變列印內容的目的。Format.Databases.QueryPrompts.GetQueryPrompt()可以特定的查詢條件,然後通過設定Value屬性來設定他的值,最後設定完所有查詢條件後進行列印。
關於這幾種動態控制列印內容的方法,都是要設計標籤檔案和程式相互配合的,比較不靈活,其實可以做成更好的動態配置方式的,不過老大說沒必要,就放棄了。至於要是有朋友不瞭解標籤檔案的設計,我有時間會寫一個文章來專門說標籤檔案的設計的。
三、整合
有了上面的介紹後,大家對BarTender提供的整合資訊有了一定的瞭解了。我是採用了ActiveX COM的方式,而且我的是用戶端列印,於是我也做了個偽ActiveX外掛程式,為什麼叫“偽”呢?因為他不是傳統意義上的ActiveX,而是用C#編寫的(悔恨當年沒學C++),所以叫“偽”。關於製作偽ActiveX,網上有很好的教程,我這裡就給個連結算了(http://www.cnblogs.com/homer/archive/2005/01/04/86473.html)。
在做好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來驗證一下想法,認真調試一下追蹤問題。不動手是沒辦法可以很好的理解一樣東西的。