New TypeLib.CoClass は何を実行する?

この問題は、Visual Basic の魔法に騙された気分になれました。
フォームにボタンをおいて次のようなコードを書きます。

Private Dim AppleWithPoison as New Fruit.Apple
Private Dim AnApple as Fruit.Apple

Private Sub Command1_Click()
  Set AnApple = AppleWithPoison
End Sub

Private Sub Command2_Click()
  Set AnApple = New Fruit.Apple
End Sub

Private Sub Command3_Click()
  Call AnApple.Eat()
End Sub

実際に Visual Basic を手元で動かしながら日記を書いているわけではないので、多少のコードのミスは目をつぶってください。

私は、このコードは次のように動作すると思っていました。

このフォームがロードされると、Private な変数 AppleWithPoison と AnApple が作られる。
その状態で、AnApple は何も参照しておらず*1、AppleWithPoison はインスタンス化された Fruits.Apple を参照している。

ボタン1を押すと、毒リンゴを手に取ることができる。これは、AppleWithPoison の参照しているリンゴの参照カウンタを1増加させる

ボタン2を押すと、リンゴを手に取ることができる。これは、新しい Fruit.Appleインスタンスが作成され、AnApple によって参照される

ボタン3を押すと、手に取ったリンゴを食べることができる。これは、AnApple が参照するリンゴの Eat メソッドを呼ぶだけ

私は、リンゴを手に取らずに食べるようなことを行ってはならず、まずはボタン1を選択していないことを指差し確認し、ボタン2を押してからボタン3を押す必要がある

しかし、これはいくつかは間違いだった。

このフォームがロードされ、画面に表示されたときは、まだ Fruit.dll はメモリ上にロードすらされていない。Fruit.dll の DllMain() 関数にデバッグ用のメッセージなどを仕込んでみればすぐにわかるだろう。

  • ならば、AppleWithPoison は何を参照しているのか?
  • ならば、DLL はいつメモリ上にロードされるのか?
  • ならば、Fruits.Appleインスタンスはいつ作成されるのか?

最初の疑問は難しいが、Fruit.dll は DllMain() を含めた様々な処理内容を詳細に出力するデバッグ用のライブラリなので、残りの問題はすぐに解決した。

VB の変数で、coclass を指定してNew を伴ったものを宣言した場合、そのインスタンスは該当の変数が始めて操作される直前に実体化される。
インスタンス化に必要なDLLは、このときに初めてプロセスにロードされる。

また、AppleWithPoison や AnApple のように、変数の型に coclass を指定した場合、それはその coclass の実装する default interface を指定したことになる。Fruit.Apple の default interface が IApple ならば、AppleWithPoison と AnApple は、Fruit.IApple の参照を保持することが可能な変数となる。

*1:Nothing を参照しているとも言える