先週の続きで、もう1つの違い、This引数の扱いです。
t.Proc1()という呼出は、擬似コード的に書くとこうなります。thisの位置は前回の記事を見てください。
Dim func = t->vtbl[0]
Dim realThis = t->this
func(realThis)
t->thisで得られる真のthisポインタはインタフェースを実装しているクラス型のオブジェクトとしてのポインタです。仮にクラスCがITestを実装していれば、(アドレス値が同じと言う点で)t As C = t->thisです。なお、この先も、インタフェースを実装しているクラス型のオブジェクトとして通用するアドレス値を保持するthisポインタを「真のthisポインタ」と呼びます。
しかし、COMではこのように1番目の引数は小細工なしにインタフェースへのポインタそのものを渡さなければなりません。
Dim func = t->vtbl[0]
func(t)
このThisの扱いで、またCOMとの違いが生じてしまっているのです。
これはABから呼び出すだけでなく、逆にCOMサーバを作って、クライアントへインタフェースを公開するときにも問題になります。つまり、呼び出された側が真のthisポインタを取り出さなければなりません。例えばこんな感じです。
Class Foo
Implements ITest
Public
Sub Proc1()
End Sub
'Proc2, Proc3も同様に実装
End Class
こんなクラス定義があったら、このようにインタフェースから呼ばれるためのサンク関数を用意し、インタフェースのvtblはInterfalce_関数群を指すようにしておきます。
Class Foo
Implements ITest
Public
Sub Proc1()
End Sub
'Proc2, Proc3も同様に実装
Private
Static Sub Interface_Proc1(pi As インタフェース)
Dim realThis = pi->this As C
realThis.Proc1()
End Sub
End Class
現在のthisを取り出す方式では、仮にProc1が複数のインタフェースのメソッドを同時に実装する場合でも、全インタフェースでサンク処理は同じコードになるはずなので、Interface_Proc1の引数piの型はITestにしていません(つまり真のthisを取り出す方式によってはインタフェース毎にサンクが必要なこともあります)。
COMインタフェースを別枠対応するという字面を最初に見たときから、ABインタフェースとCOMインタフェースで別々の取り扱いをするのはかえって非効率で、一緒くたに扱えたほうが全体的には楽なのではないだろうかと思っていました。横から見ているだけの私には、(サンク以外)たったこれだけの修正で済むのだからABインタフェースをCOMに合わせるのはそう大変なことに思えないのです。
とはいえ、結局のところは、COMがきちんと扱えれば、基本的にはどういう実装をされようと(つまりCOMインタフェースを特別扱いしても)構わないのですけどね。
スポンサード リンク |