@egtraイグトランスの頭の中(のかけら)ActiveBasicを中心にプログラミングの話をぼちぼちと。Qiitaの21日目の記事です。ネタは尽きていないのに、日数の残りが少なくて、少し戸惑っています。今回は、OBJREFモニカーの寿命について調べてみました。すると結局、タイトルにあるようにスタブオブジェクトの寿命であることに気付いたという話です。サンプルコードは前回からの改変で話を進めますが、そんなわけで、OBJREFモニカーだけでなく、特に後半はアパートメントをまたぐ場合すべてに当てはまる話です。OBJREFモニカーの寿命OBJREFモニカーおよびその文字列が有効な期間は、OBJREFが参照するスタブオブジェクトの寿命と同じです。他アパートメントの側でReleaseして参照カウントが0になったら終わってしまう、というのがデフォルトの挙動です。その挙動を確かめてみます。前回のサンプルコードのVBScript側を以下のように2回GetObjectするように変えます。途中でNothingを代入して参照を消しているのがミソです。hoge()すると実行結果はこうなります。Nothingの行で、スタブオブジェクトが用済みとなったため捨てられてしまい、OBJREFも無効になります。そのため、2回目のGetObjectは失敗に終わります。大本のオブジェクト自体の参照カウントがたとえまだ0でなかったとしても、結果は同じです。Nothingの行を無くすと、以下のように2回目のGetObjectも成功することが分かります。objref:TUVPVwEAAAA(中略)//AAAOAP//AAAAAA==:--------Hoge::Invoke--------Hoge::Invokeスタブを生かし続ける上記の挙動では困る、すなわち1度ならず何度でもOBJREFモニカーを使えるようにしたい場合もあります。その方法は2つあります。1つはIExternalConnectionを実装する方法、もう1つはCoLockObjectExternal関数を利用する方法です。今回はCoLockObjectExternal関数を使ってみます。前回のC++側コードを少し変更し、CreateObjrefMoniker関数呼び出しの付近にCoLockObjectExternal関数を追加します。CreateObjrefMonikerとの順番はどちらが先でも構いません。Nothingの行を元に戻して実行した結果です。以下のように2回目のGetObjectも成功します。先ほど「スタブオブジェクトが捨てられる」と書きました。それを確認してみます。1度OBJREFモニカーを作り、それが別の文字列になっていることでもって確かめられます。前回のコードのmain関数部分を以下のコードに置き換えます。OBJREFモニカーの文字列を作る処理を別の関数に切り出しました。}OBJREFモニカーを作る→VBScript側でGetObjectしてスタブを破棄→OBJREFモニカーを作る、という順で実行されます。最後に2つのOBJREFモニカーの文字列を比較した結果を出力させています。実行すると次のようになります。monikerStr2)がfalseとなっています。(CreateObjrefMoniker)関数呼び出しの前後にCoLockObjectExternal関数呼び出しを追加した場合を試します。objref:TUVPVwEAAAA(中略)//AAAOAP//AAAAAA==:true見事、trueになります。同じオブジェクトに対するスタブが存在するため、2度目のCreateObjrefMonikerでも同じOBJREFが使用されます。そのため、GetDisplayNameでも同じ文字列が得られました。おまけ:IExternalConnection今回IExternalConnectionは取り上げませんでした。そのため、IExternalConnectionを扱っている日本語ウェブページのリンクを並べておきます。私も、幾度となく参照しました。アウトプロセスサーバ(2)取り上げなかった理由を強いて挙げるとすれば、私のIExternalConnectionを使う理由が外部からの切断(最終Release)の検知であることが多いからかなと思います。ロックしたオブジェクトの寿命を考えるCoLockObjectExternalやIExternalConnectionでロックすると、他アパートメントからいくらReleaseしてもスタブオブジェクトから大元のオブジェクトへの参照を保持し続けます。オブジェクトの参照カウントはいったいいつ0になって、いつ削除されるのでしょう。答えは、「自ら決める」です。GUIアプリケーションで主たるウィンドウが閉じられたり、Windowsサービスアプリケーションで終了が要求されたりしたらオブジェクトも利用不可能にする方式が考えられます。他アパートメントの利用状況とは一切関係なく、自らの都合で切断するのです具体的には、CoUninitialize()でアパートメントごと終了させたり、CoDisconnectObject関数で個々のオブジェクトごとに切断を言い渡したりできます。CoLockObjectExternal関数の2番目の引数にFALSEを渡すことで、ロックを解除する(スタブは必要に応じて生き残るかもしれない)方法もあります。まとめOBJREFモニカーはOBJREFに連動して、プロキシオブジェクト(他アパートメント)からの参照次第で寿命が決まります。それが困るならCoLockObjectExternalまたはIExternalConnectionでスタブオブジェクトをロックできます。自オブジェクトあるいは自アプリの都合で寿命を決めたい場合にロックは有用です。マーシャリングのことなのでプロセス間・プロセス内関係なく当てはまる話ですが、プロセス間でないと遭遇しにくい問題という印象があります。Tableを使っている限り、スタブの寿命を気にする事態に直面することはなかなかありません。コメントをキャンセルメールアドレスが公開されることはありません。WPThemes.Info。