Hatena::Groupmoz-addon

Ci.nsIZIGOROu

2008-01-03あけますたおめでたう

Getter/Setterの公開、JScriptの関数呼び出し

| 02:55 |  Getter/Setterの公開、JScriptの関数呼び出し - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  Getter/Setterの公開、JScriptの関数呼び出し - Ci.nsIZIGOROu

あけましておめでとうございます新年の初エントリはいきなりニッチネタです><

とりあえず前提はすっ飛ばす。私的なメモです。

Getter/Setter

Private foo As Object

Public Sub Set_Foo(ByRef aFoo As Object)
    foo = aFoo
End Sub

Public Function Get_Foo() As Object
    Return foo
End Function

とかでもまぁ別にいいんだけども、Get_, Set_とかダサいよねって事で、色々調べてたら、

Private fooObj As Object

Public Property Foo() As Object
    Get
        Return fooObj
    End Get
    Set(ByVal value As Object)
        fooObj = value
    End Set
End Property

こういう書き方が出来る。(参考: Property ステートメント - Visual Basic 言語リファレンス)

これはCOMにした場合、idl的には、

[id(0x00000001), propget]
VARIANT Foo();
[id(0x00000001), propputref]
void Foo([in] VARIANT rhs);

のようになる。

JScriptのFunctionオブジェクト

jscriptで自作COMからイベントを発生させたいにおける、Microsoft MVP for Visual C++社本さん*1のフォローですが、

あと、JScript独自のIDispatchExとか。

なお、関数オブジェクトは、DISPIDが0(DISPID_VALUE)で、名前が"anonymous"というメソッドを持ったCOMオブジェクトのようです。 MSDN内でもまとまった記述はなく、色々と苦労して調査しましたよ。。

jscriptで自作COMからイベントを発生させたい

と仰ってますので、IDispatch経由の遅延バインディングJScriptのFunctionオブジェクトの呼び出しが出来るはず。これってVisual Basic 2005でも出来るのかなと色々やってたら出来ました。

Public Function Do_Callback() As Object
    Return callbackValue.GetType.InvokeMember("[DispID=0]", Reflection.BindingFlags.InvokeMethod, Nothing, Callback, Nothing, Nothing, Nothing, Nothing)
End Function

Object.GetType.InvokeMember()で出来る。

今の所は引数なしの関数オブジェクトを呼び出してるけど、InvokeMemberで引数リストを渡す事が出来るから、型変換さえ正しく出来れば問題なく任意の関数を呼び出せる。

サンプルコード

一応書いてみたコード

<ComClass(JScriptFunction.ClassId, JScriptFunction.InterfaceId, JScriptFunction.EventsId)> _
Public Class JScriptFunction
#Region "COM GUIDs"
    ' These  GUIDs provide the COM identity for this class 
    ' and its COM interfaces. If you change them, existing 
    ' clients will no longer be able to access the class.
    Public Const ClassId As String = "e1df88cf-648b-48ec-bf30-5b92576364c2"
    Public Const InterfaceId As String = "3b8b64f8-c707-4f94-945d-447c23df7da1"
    Public Const EventsId As String = "a1299ef6-d8ea-4a6c-9b75-3cf9c6d11402"
#End Region

    ' A creatable COM class must have a Public Sub New() 
    ' with no parameters, otherwise, the class will not be 
    ' registered in the COM registry and cannot be created 
    ' via CreateObject.
    Public Sub New()
        MyBase.New()
    End Sub

    Private callbackValue As Object

    Public Property Callback() As Object
        Get
            Return callbackValue
        End Get
        Set(ByVal value As Object)
            callbackValue = value
        End Set
    End Property

    Public Function Do_Callback() As Object
        Return callbackValue.GetType.InvokeMember("[DispID=0]", Reflection.BindingFlags.InvokeMethod, Nothing, Callback, Nothing, Nothing, Nothing, Nothing)
    End Function
End Class

で動作確認はWSHだったら、

var jsfunc = new ActiveXObject("VBComTest.JSFunction");
jsfunc.Callback = function() { WScript.Echo("hogehoge"); }
jsfunc.Do_Callback();

僕の環境ではプロジェクト名がVBComTestになっているのでProgIDにもprefixとして適用されてる。

*1:「しゃもと」と読むらしい。珍しい苗字ですね。