VB6 的開(kāi)發(fā)環(huán)境在現代操作系統上難以直接安裝運行,網(wǎng)上有一些解決方案可以嘗試一下,如果不行可以下載那種精簡(jiǎn)版本 VB6 —— 這個(gè)至少能跑起基本功能,或者可以安裝一個(gè) XP的虛擬機來(lái)運行 VB6。
但 VB6 編寫(xiě)的程序兼容性還是能接受的,VB6 運行時(shí)至今仍然是各版本 Windows 系統自帶的系統組件,所以 VB6 可以生成體積極小的執行文件。而且 VB6 可能是寫(xiě) ActiveX 控件操作最簡(jiǎn)單的開(kāi)發(fā)工具。
今天我們一起來(lái)玩一下 VB6,先用 VB6 寫(xiě)一個(gè)控件,步驟如下:
1、打開(kāi)VB6,選擇新建 ActiveX 控件。
2、在工具條里拖一個(gè) Image 控件到默認的用戶(hù)控件 UserControl1 上面。
3、雙擊 UserControl1 切換到代碼,添加代碼如下:
'聲明一個(gè)普通變量Dim TestPropertyValue As Integer
'聲明一個(gè)事件,在 aardio 中可以響應這個(gè)事件,'注意參數加了ByRef表示傳址,在 aardio 中就可以修改這這個(gè)參數的值Public Event OnImageClick(ByRef TestPropertyValue As Integer)
'這是VB6里點(diǎn)了Image圖像控件觸發(fā)的事件Private Sub Image1_Click() '觸發(fā) COM 控件的事件( 換句話(huà)說(shuō)就是調用 aardio 中的函數 ) RaiseEvent OnImageClick(TestPropertyValue)End Sub
'窗口調整大小觸發(fā)這個(gè)函數,注意 aardio 控件都是非適應縮放的Private Sub UserControl_Resize() Image1.Width = UserControl.Width Image1.Height = UserControl.HeightEnd Sub
'定義讀屬性 TestProperty 的函數,這是帶參數的屬性Public Property Get TestProperty(Param As Integer) As Integer TestProperty = TestPropertyValue + ParamEnd Property
'定義寫(xiě)屬性 TestProperty 的函數,帶參數屬性(參數要跟上面一致)Public Property Let TestProperty(Param As Integer, ByVal v As Integer) TestPropertyValue = v - ParamEnd Property
'定義寫(xiě)屬性 Picture 的函數,參數是一個(gè) IDispatch 接口的 COM 對象Public Property Let Picture(ByVal pic As Variant) Image1.Picture = picEnd Property
'定義一個(gè)名為 Picture 的函數Public Function Add(ByVal a As Integer, ByVal b As Integer) Add = a + bEnd Function
然后在 VB 里點(diǎn)擊 IDE 主菜單“文件->生成 *.ocx ” 就可以了。
整體看起來(lái)還是非常簡(jiǎn)單對吧。不過(guò)我在 aardio 自帶的這個(gè)范例里沒(méi)寫(xiě)注釋?zhuān)驗?VB 使用 ANSI 編碼(杠VB正宗Unicode解決不了問(wèn)題),而現在 ANSI 編碼的文件里用中文的話(huà),很多編輯器打開(kāi)都是亂碼,所以我把注釋刪掉了。
VB的亂碼問(wèn)題是一個(gè)大坑,例如把 ocx 放在簡(jiǎn)體中文目錄下,或者ocx 本身包含簡(jiǎn)體中文名,然后在繁體中文系統下打開(kāi)直接就會(huì )崩潰。如果包含任何其他 Unicode 字符結果是一樣,這也是為什么 ANSI 基本已被這個(gè)世界淘汰的主要原因。
不過(guò)沒(méi)有關(guān)系,在 aardio 里我們可以輕松解決這個(gè)問(wèn)題。在 aardio 里加下面的代碼加載 VB 控件:
var dll = com.lite.appData('aardio\vb6\Vb6Control.ocx',$'\.vb6\Vb6Control.ocx')請注意第@2個(gè)參數的路徑前有一個(gè)$字符,這會(huì )將 ocx 的二進(jìn)制數據編譯到代碼里,發(fā)布后就不需要再帶一個(gè) ocx 了,VB的 ocx 并不支持內存加載,所以我們用 com.lite.appData() 函數將其自動(dòng)復制到 %CommonAppData% 目錄下,這個(gè)路徑是全英文的,自動(dòng)就解決了 VB6 控件遇到 Unicode 路徑崩潰的大難題。
另外,其他需要訪(fǎng)問(wèn)文件路徑的地方我們用 aardio 來(lái)實(shí)現,不用 VB6 干這事,這樣就可以避免 VB6 踩到這個(gè)坑。
我們再看看我們在 aardio 中怎么創(chuàng )建這個(gè)控件:
import com.lite; var dll = com.lite.appData('aardio\vb6\Vb6Control.ocx',$'\.vb6\Vb6Control.ocx')var vbUserControl = dll.createEmbedEx(winform.static);非常簡(jiǎn)單,VB里怎么使用這個(gè)控件,在 aardio 里我們就怎么使用。其實(shí)我們可以在 dll.createEmbedEx() 的第@2個(gè)參數里指定 COM控件的 CLSID,但 VB 這個(gè) CLSID 不好找,很多人是先注冊控件再去注冊表里查,問(wèn)題是 VB6現在注冊控件會(huì )報錯失敗 —— 不過(guò)好在 aardio 可以免注冊調用 VB 控件,并且在 aardio 中可以省略 CLSID,aardio 會(huì )自己幫你找到正確的 CLSID 。這么貼心 —— 有沒(méi)有被感動(dòng)呢?!
上面參數指定的 winform.static 是COM控件宿主窗口(也是COM控件的父窗口),vbUserControl 并不是COM對象,而是 COM對象的容器,vbUserControl._object 才是 COM 對象。
調用 COM 對象的時(shí)候需要寫(xiě) vbUserControl._object.xxxx () 是不是很吃力呢?!其實(shí)我們在 aardio 中通常不會(huì )這么寫(xiě),vbUserControl 通常會(huì )添加大量的封裝函數,通過(guò)這些函數再去訪(fǎng)問(wèn) vbUserControl._object ,這樣 vbUserControl 就成為了一個(gè)代理對象,這種好處是非常多的,一個(gè)最典型的例子就是標準庫的 web.form 或者 com.flash。
但如果我們不想去過(guò)多的封裝,只想直接使用 COM 對象呢?!一個(gè)非常簡(jiǎn)單的方法是這樣寫(xiě):
var comObject = vbUserControl._object然后使用這個(gè) comObject 就行了,不過(guò)能不能不寫(xiě)這句代碼呢?!其實(shí)也是可以的,這就是我使用 dll.createEmbedEx() 而非 dll.createEmbed() 的原因了,這兩個(gè)函數作用相同,但帶 Ex 后綴的 dll.createEmbedEx() 多了一個(gè)功能,他返回的控件容器對象已經(jīng)自動(dòng)實(shí)現了一個(gè)簡(jiǎn)單的 COM 控件代理 —— 例如上面訪(fǎng)問(wèn) vbUserControl 對象的成員就會(huì )自動(dòng)轉為調用 vbUserControl._object 的成員,等于將COM控件容器與 COM對象合二為一了。
控件容器對象還有一個(gè)作用是作為默認的事件監聽(tīng)器,記得我們前面的VB代碼中用 RaiseEvent OnImageClick(TestPropertyValue) 觸發(fā)事件嗎?在 aardio 代碼中我們可以如下響應這個(gè)事件:
//控件容器也是默認的 COM 事件監聽(tīng)器,如下直接指定響應 COM 事件的函數vbUserControl.OnImageClick = function(value){ winform.edit.print('VB控件里點(diǎn)擊了圖像,事件參數:'+value) //VB里這個(gè)事件的參數聲明為 ByRef,所以添加返回值可以修改參數 return 100}是否還記得 VB6 里這個(gè)事件的參數指定為 ByRef 傳址,也就是說(shuō)參數 value 是一個(gè)引用參數,在 aardio 中可以修改他的值,aardio 基于純函數原則不會(huì )直接修改外部參數的值,而是通過(guò)增加返回值修改引用參數的值。這個(gè)事件函數沒(méi)有返回值,也只有一個(gè)需要輸出值的引用參數,所以增加一個(gè)返回值就可以了。
這個(gè)示例是用 VB 顯示圖像,我們就不要用 VB 來(lái)加載圖像了,如果圖像路徑有中文或 Unicode 字符又不太好,但 aardio 是 UTF8 內核,沒(méi)有這些問(wèn)題,所以我們用 com.picture.loadObject( '~\codes\范例程序\D) 圖形圖像\.gdip.jpg' ) 加載圖像再傳給 VB, com.pictrue 的函數創(chuàng )建的都是 IPicture 對象,這是與 VB 兼容的,但我們通過(guò) COM 接口不能傳原生的 IPicture 過(guò)去,我們要用 com.picture.loadObject() 函數,右鍵點(diǎn)這個(gè)函數跳轉到定義,看一下源代碼你就明白了:
namespace com.picture{loadObject = function(path){return ..com.QueryObject( load(path) );}}
其實(shí)就是調用 com.pictrue.load() 加載圖像,再用 com.QueryObject() 轉換為 COM 對象( IDispatch 接口 ) ,然后就可以傳給 VB了:
//修改VB控件的屬性vbUserControl.Picture = com.picture.loadObject( '~\codes\范例程序\D) 圖形圖像\.gdip.jpg' )反正我在繁體系統下測試 VB控件直接加載上面的圖像會(huì )出問(wèn)題,但用上面的方法 —— 用 aardio 加載圖像再傳給 VB6 就完美解決。
至于調用 VB 函數這個(gè)很簡(jiǎn)單:
//調用 VB 函數var c = vbUserControl.Add(2,3);
VB有一個(gè)比較有特色的參數化屬性,例如看到這種寫(xiě)法是不是蒙了:
vbUserControl.TestProperty(2) = 123千萬(wàn)別以為是給函數的返回值賦值,我們把上面的參數化屬性賦值轉換為 等價(jià)的 aardio 代碼如下:
//修改VB控件的參數化屬性,加上 set 前綴以函數形式調用vbUserControl.setTestProperty(2,123)
在 aardio 里給屬性加上 set 前綴就可以變成一個(gè)寫(xiě)屬性的函數,當然也就支持多個(gè)參數了。同理,加上 get 前綴可以變成一個(gè)讀屬性函數,如下:
/*帶多個(gè)參數的屬性加上get前綴并以函數形式調用,例如:*/var testProperty = vbUserControl.getTestProperty(2);好吧下面我們看這個(gè)范例的完整 aardio 源碼,直接復制就可以運行,直接復制就是一個(gè)獨立的、完整的程序:
import win.ui;/*DSG{{*/var winform = win.form(text='免注冊嵌入 VB 控件';right=706;bottom=274)winform.add(edit={cls='edit';left=356;top=20;right=665;bottom=243;db=1;dl=1;dr=1;dt=1;edge=1;hscroll=1;multiline=1;vscroll=1;z=2};static={cls='static';text='Static';left=21;top=20;right=330;bottom=243;dl=1;dt=1;transparent=1;z=1})/*}}*/import com.lite;var dll = com.lite.appData('aardio\vb6\Vb6Control.ocx',$'~\codes\范例程序\2) 調用其他語(yǔ)言\F) VB\.vb6\Vb6Control.ocx');var vbUserControl = dll.createEmbedEx(winform.static);//控件容器也是默認的 COM 事件監聽(tīng)器vbUserControl.OnImageClick = function(value){winform.edit.print('VB控件里點(diǎn)擊了圖像,事件參數:'+value);return 100;}//修改VB控件的屬性vbUserControl.Picture = com.picture.loadObject( '~\codes\范例程序\D) 圖形圖像\.gdip.jpg' )//修改VB控件的參數化屬性,加上 set 前綴以函數形式調用vbUserControl.setTestProperty(2,123)//帶多個(gè)參數的屬性加上get前綴并以函數形式調用,例如:var testProperty = vbUserControl.getTestProperty(2);winform.edit.print('VB 控件 TestProperty(2) 屬性:',testProperty);//調用 VB 函數var c = vbUserControl.Add(2,3);winform.edit.print('調用 VB 控件函數返回值:',c);winform.edit.print('請點(diǎn)擊圖像試試');winform.show();win.loopMessage();
最后不得不佩服一下,這個(gè) VB 控件的體積是:24KB,對比一下現在用 Electron 什么的沒(méi)寫(xiě)幾個(gè)功能就幾百MB是什么概念,這幾百MB里有多少是你真正需要的東西?!不是說(shuō)這些東西沒(méi)有用,就像豪華大房車(chē)一定是有用的,但你明明騎個(gè)自行車(chē)能解決的問(wèn)題,非要每次都開(kāi)豪華大房車(chē)嗎?!想想這個(gè)道理,就會(huì )明白 VB6 的好處在哪里。
圖還是要補上的:
聯(lián)系客服