前言:
暑假在做一個項目的時候,本來是用C#.NET來寫的一個港口進出閘的流程控制程序,里面涉及一個響應用PLC的采集信息的問題(PLC用串口和工控機相連接),然后思考如何用C#寫串口通訊程序,結果師兄在一旁直接用VC++寫了一個“*.ocx控件”,并在自己的電腦上進行了測試,完工后就把生成的“*.ocx”控件注冊文件復制到了我們的電腦上。我們就在C#.NET程序里面將此控件拖入到主窗口中,然后就能直接利用此控件的事件來捕捉PLC的命令了,感覺好神奇。然后,我對C++的態度有了極大的轉變,以前只知道C++寫窗口程序是多么麻煩啊(遠不如C#.NET來得快和直接),而它的所謂“比較底層,和底層操作系統的關系比C#這些高級語言要密切很多”的好處一直都沒有體會到,現在才知道,正是因為C++比較底層,比較基礎,所以它可以開發出很多和語言無關的公用程序塊,如dll動態鏈接庫和COM組件,原則上,只要你的Windows的系統,用VC++開發出來的這些公用程序塊就能被任何語言調用(如果不用MFC框架,而用ATL框架來編寫,甚至還可以脫離Windwos系統,不僅僅實現跨語言,甚至跨平臺調用,這個筆者就沒有仔細研究了)。
本人大學本科所學本來是電子技術的工業自動化,結果中途做的幾次項目都是“純軟件”,這次暑假的經歷,終于讓我在“硬件”和“軟件”之前找到一個連接交匯點了。
以前做電子產品只是為了實現功能,現在發現這遠遠不夠,按照目前的時代潮流,一個系統除了要功能完備化,還要信息化 ,信息化就涉及到數據采集、存儲、分析和顯示。當然如果你不是做系統的,那么你也不必去用全局的眼光去看待這個問題,但你做了電子產品后,卻不能讓它的功能僅僅局限于在現場完成一些自動控制,而應該開發出和設備相關的上層API,供廣大的非電子專業的上層程序員進行二次開發,在PC上層平臺上對數據信息進行更好的組織和處理。而提供的API最好是具有較好的移植性,以適應不同企業的不同語言的程序員。而COM組件技術很好地解決了這個問題。
說到跨語言的模塊化程序設計,在本文之前發表的一篇《VC++的DLL應用(含Demo演示)》中講了dll的創建方法,用戶可以將一些公用函數放在dll源文件中,然后編譯生成一個dll文件,供程序動態加載連接并調用里面的函數,這個也可以跨語言地進行調用。但dll有自己的局限性,就是沒有事件,而這個時候ActiveX控件就隆重登場了,同樣能夠跨語言使用,ActiveX可以提供方法,屬性甚至是事件(當然對比dll也有缺點,它不是單獨的文件,無法動態加載和卸載)。
因為筆者現在只是學習這個技術并作為一個技術積累,而沒有對這個技術進行原理上的深入研究,所以很多術語可能完全是錯誤的,希望高手看到后,不吝踢教和指正,也能防止本文誤認“子弟”了。本文中,作者是把ActiveX,COM,OCX當作相同的概念來對待的,可能不妥,請見識,如果想細究其具體的區別,請參考文章:
《Activex、OLE、COM、OCX、DLL之間有什么區別?》
其實不管你是否了解它們之前的區別,都無所謂,因為本文只是講解如何從零開始學習并應用這門技術來解決實際問題,大家只需要知道實現步驟就OK了。
好,多的話不說了,下面開始介紹ActiveX這門技術的實現方式。
正文:
ActiveX這門技術是通過生成“*.ocx”文件來實現的。先來了解下OCX文件,在百度百科上面對OCX是這樣解釋的:
“.ocx是ocx控件的擴展名,OCX 是對象類別擴充組件。如果你用過Visual Basic或者Delphi一類的可視化編程工具,那么對控件這個概念一定不會陌生,就是那些工具條上的小按鈕,如EditBox,Grid,,Timer等等。每個控件都有自己的事件、方法和屬性。使用了控件的編程非常容易。首先,在程序的設計階段可以設置一些屬性,如大小,位置,標題(caption)等等;在程序運行階段,可以更改這些屬性,還可以針對不同的事件,調用不同的方法來實現對該控件的控制。控件就好像一塊塊的積木,程序要做的事只是將這些積木搭起來。控件的最大好處是可以重復使用,甚至可以在不同的編程語言之間使用,例如你可以在VB中嵌入用VC開發的控件。”
里面最后一句話比較重要,就是用VC開發的OCX控件,你可以在其它語言里面都能調用,這樣很好的實現了功能化組件的良好循環使用,而且還可以實現跨語言地調用(例如,你完全可以用C#調用C++開發的OCX控件)。
下面開始介紹,如何用VC++一步步生成你想要的“*.ocx”文件。
1.建立最簡單的ocx文件并進行調試
1.1 建立最簡單的ocx文件
VC->新建項目->MFC ActiveX WinZard
一路點擊“確定”,直到點擊“完成”。最后VC++會自動生成一些文件,這些文件就構成了ActiveX的基本模板,文件的主要結構如下:
直接編譯一下,然后在Debug目錄下面就會生成一個名為“ocxDemo.ocx”的控件注冊文件,然后利用“”命令就可以實現本機對此控件的注冊,然后就可以使用本語言或者跨語言編寫程序時引用此控件來實現相應的功能(后面將會講到)。
1.2 ocx調試方法:
VC++自帶有一個調試控件的工具“ActiveX控件測試容器”,通過三種方式可以打開:
1.點擊“調試”按鈕,會出現如下對話框:
然后瀏覽"C:\Program Files\ Visual Studio\Common\Tools\.EXE“
2. 系統的“開始“-》“程序”-》“ Visual C++ 6.0”-》“ Visual C++ 6.0 Tools”-》“Active Control Test ”
3. VC++開發環境中的“工具”-》“ActiveX Control Test ”
通過上面的任意一種方法,都可以調出下面的程序:
右擊空白區域,插入控件,然后會彈出下面的對話框:
選中指定控件,然后點擊確定,控件就被加載到此工具中了,然后可以通過這個工具來看此控件的相關事件響應等等。
2.自VC++生成的模板基礎上自定義功能
所有的自定義功能基本上都來自于“MFC ”類向導對話框。
(“快捷鍵Ctrl+W”或者“查看”->“建立類向導…”)
在“”選項卡中為控件添加方法和屬性。
在“ActiveX Events”選項卡中為控件添加事件。
2.1 添加控件屬性
切換到“”選項卡中,點擊右邊的“Add …”會彈出對話框:
name:外部名稱。指此控件被使用時,外部程序看到的屬性名稱,僅在外部引用時被使用。
Type:屬性類型。除了基本的整形等數據類型外,還有很多復雜的高級數據類型。
name:變量名稱。此屬性在控件源文件中的變量名稱,在編寫控件源碼時使用。
:提醒函數。當此屬性被改變時,會觸發此提醒函數。
:實現方式。指屬性的三種類型:固有型,成員變量型,Get/Set方法型。固有型是指系統賦予的固有屬性,如背景色,標題;成員變量型是用戶自定義的屬性;Get/Set方法型,可能是指只能通過Get/Set方法才能獲取和改變的變量吧(這個沒研究)。
2.2 添加控件方法
在“”選項卡中,點擊右邊的“Add Method…”會彈出對話框:
name:方法外部名稱。
name:方法內部名稱。
Return type:返回值類型。除了基本的整形等數據類型外,還有很多復雜的高級數據類型。
:實現方式。兩種:固有方法,自定義方法。
list:參數列表。參數名稱和參數類型:參數類型包含很多高級數據類型。
2.3 添加控件事件
切換到“ActiveX Events”選項卡中,點擊右邊的“Add Event…”會彈出對話框:
name:事件外部名稱。
name:事件內部名稱。比外部名稱多了個前綴“Fire”。
:實現方式。兩種:固有事件,自定義事件。固有事件一般是鼠標移動,雙擊等等事件,這些事件都由系統消息觸發;自定義事件則是完全由用戶定義的一個函數,但這個函數需要用戶在源文件中調用(在內部調用,對于控件的使用方來說,就相當于在調用的地方此事件被觸發,而內部傳入的參數,則是此事件產生的消息附帶信息)。
list:參數列表。參數名稱和參數類型:參數類型包含很多高級數據類型。
總述:通過“類向導”工具,為控件添加屬性、方法和事件后,VC++會自動在相應的文件里面生成代碼,比如內部方法屬性和外部方法屬性之間的映射,消息的建立,消息的聲明,等等。如果用戶要對引進行深入研究,還需要對程序的結構比較熟悉,知道各部分代碼的作用,知道哪些地方的代碼是系統自動生成的,哪些代碼需要用戶手動加入的。Visual C++開發環境雖然有很多優點,但有個缺點也很明顯,就是代碼結構比較亂,感覺沒有VS2005和后面的Visual Studio系列要好。但是由于VC6.0作為一個比較經典的開發環境,而且網上的有關C++的程序設計基本上都是基于VC6.0的,所以,有必要對其進行學習,便于自己讀懂網上的代碼并進行消化吸收。
2.4 生成ocx文件并調試
直接編譯用戶加入了自定義代碼的項目,然后在項目的Debug目錄下面會生成一個ocx文件,這個就是此控件的注冊文件了。
控件的調試工具仍然是“ActiveX Control Test ”。
假設我們在控件中加入了一個事件:固有事件——“”鼠標移動事件;用戶自定義事件——事件(此事件是通過“”消息來觸發的,返回的是鼠標當前位置的x坐標)。
運行“ActiveX Control Test ”并插入當前控件,當鼠標在上面移動的時候,可以看到產生了事件了。
同時可以通過“Control”-》“Invoke Method”來對控件的方法進行測試,測試的方法就是你輸入參數,它返回計算結果(下面以自定義的方法為例)。
3.控件的使用方法
3.1 注冊控件
ocx控件的安裝方式有很多種,這里介紹最簡單的一種。
步驟:
1.將需要安裝的OCX控件文件復制到某個目錄,例如C盤根目錄下。
2.進入開始,點擊運行。
3.在出現的框中鍵入 C:/xxxx.ocx 。(XXXX為控件名, C:/為目錄)
4.點擊確認后等待出現提醒注冊成功即可。
3.2 ActiveX控件的調用
ActiveX作為一種通用的COM組件,可以被不同語言調用的。
3.2.1 通過VC++調用
利用VC6.0建立一個MFC的基本對話框應用程序
在完成程序向導后。執行下面的步驟:
1. 執行“工程”-》“添加到工程”--》“ and …”。
2. 在彈出的文件瀏覽對話框中,找到 ActiveX 文件目錄下的你剛才注冊的控件,比如“OcxDemo Control”,然后點擊“Insert”按鈕即可將此控件添加到控件工具條集合中。
3. 將控件工具條上新增加的OCX控件拖入到應用程序主窗口中。
完成上面的步驟后,就可以像使用普通控件一樣在VC中使用此控件了(右擊此控件,可以查看此控件的“事件”和“屬性”,就是你在編寫控件源碼時的那些“外部名稱 name”)。
3.2.2 通過C#調用
其實這個才是重點,因為跨語言調用ActiveX技術最被筆者看好的地方。
用Visual Studio 2005新建一個C#.NET的Windows窗口程序,然后在工具箱面板上,右擊“選擇項”,選擇COM組件,找到你注冊的ActiveX控件:
確定后,那個OcxDemo Control控件就加載到工具箱里面了。可以直接拖動這個控件到C#.NET應用程序的主窗口上去了,然后就像使用普通控件那樣使用此控件了。
比如,本文中的ActiveX控件的自定義事件中,是通過鼠標移動來觸發,那么在應用程序中,只要鼠標移動到控件上,那么就會觸發此自定義事件,并獲取當前鼠標位置的橫坐標。
4. 最后一些Tip
1) 在自定義控件時,可在控件源碼的OnDraw()函數中設置控件的外觀(也就是控件被拖入到應用程序中時呈現的樣子,一般默認是一個白色的方框內切橢圓的樣式)。
2) 用C#來使用ActiveX的事件時,事件所產生的數據都包含在Event變量中,只需要用個點運算符就可以取出來了。
5.展望
控件函數的返回值類型那么多,那么復雜,如果要用得好,還需要對那些OLE數據類型進行好好學習,這個等今后需要時再慢慢學習吧。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。