VB6 和 VBA 調用子程序時如何傳遞 MSForms.ReturnInteger 型參數
VB6 和 VBA 調用子程序時如何傳遞 MSForms.ReturnInteger 型參數
由於想偷個懶,直接調用一下文本框的按鍵事件處理程序,沒想到懶沒偷成,反而浪費了幾十倍的時間。原因是出現了參數怎麼弄都傳不進去的狀況,讓人很惱火,整天想着這個事情,不弄明白不舒服。
本來嘛,直接調用文本框的按鍵事件處理程序很簡單的,
Call TextBox1_KeyDown(Nothing, 0)
就搞定了,可這不是咱們的風格,萬一以後其他人士修改代碼,使用了 KeyCode 這個參數,我這個調用就會造成空引用的異常。可不能爲了一時的方便留下隱患,好歹要弄個有效的參數傳過去才行。然後問題就出來了,直接傳值不行,傳遞其它類型的變量也不行。
來看代碼:
Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
MsgBox KeyCode
KeyCode = 99
End Sub
那個 MSForms.ReturnInteger 肯定就是個類,那麼按規矩就得這樣調用:
Private Sub CommandButton0_Click()
Dim c As MSForms.ReturnInteger
Set c = New MSForms.ReturnInteger '可是執行到這裏一定出錯,說是創建對象失敗
c = 7
Call TextBox1_KeyDown(c, 0)
MsgBox c
End Sub
這就讓人鬱悶了,與經驗不符啊!
上網找,沒找到任何有用的東西,有一個相關度最高的解決方案是申明一個全局變量,然後設法隨便進入一個事件處理程序,把系統傳遞過來的 KeyCode 對象保存下來,以後就一直使用這個變量交換數據。這個方法實用但是搞笑,並沒有回答我們的疑問,而且我並非一定得解決這個問題,所以不會採用他的方法。
但是不搞清楚原因就不舒服的習慣讓我不斷回顧這個問題。終於,我把 KeyCode 添加到監視裏跟蹤觀察時發現了端倪,我看到了這個變量的類型是
ReturnInteger/IReturnInteger
這一下就明白了,原來 MSForms.ReturnInteger 並非是一個類,而是一個接口。想 New 一個接口當然大錯特錯,我們必須來實現這個接口。
創建一個新類,命名爲:
MyReturnInteger
輸入以下代碼:
Implements MSForms.ReturnInteger
Private v As Long
Private Property Let ReturnInteger_Value(ByVal val As Long)
v = val
End Property
Private Property Get ReturnInteger_Value() As Long
ReturnInteger_Value = v
End Property
Public Property Let Value(ByVal val As Long)
v = val
End Property
Public Property Get Value() As Long
Value = v
End Property
就實現了這個接口。ReturnInteger_Value 那個屬性是接口規定的,必須那樣寫。 Value 那個屬性是爲了方便自己使用,可寫可不寫。
然後事情就簡單了:
Private Sub CommandButton1_Click()
Dim c As New MyReturnInteger
c.Value = 8
Call TextBox1_KeyDown(c, 0)
MsgBox c.Value
End Sub
正常運行。
還有一個問題,就是在事件處理程序裏直接用 x = KeyCode;KeyCode = y 這種風格來書寫,可是在我的調用程序裏必須用 x = c.Value;c.Value = y 這種風格來書寫。這當然不是什麼原則性的問題,但如果我強迫別人在同一個程序中用不同的風格書寫代碼那就是我的不對。解決這個問題的方法是設置自定義類的缺省屬性。
VBA 的 IDE 沒有提供設置缺省屬性的功能,得學 VB6 的方法,將類導出成
MyReturnInteger.cls
文件,然後用記事本打開這個文件,在
Public Property Get Value() As Long
語句之後添加如下語句:
Attribute Value.VB_UserMemId = 0
存盤後再導入 VBA,這個類就有了缺省屬性。
然後下面的代碼就能完美工作:
Private Sub CommandButton2_Click()
Dim c As New MyReturnInteger
c = 9
Call TextBox1_KeyDown(c, 0)
MsgBox c
End Sub
大功告成。這裏的方法對 VB6 同樣適用。