[Ruby] pr-win32ole その2
期待してよいのはポインタの4バイトだけと artonさんからコメントをいただいた。
ということは、私は完璧にずっと勘違いしていたということになります。 で、「困ったときのPerl」の格言(←嘘)に従い、Perlはどうしているんだろうなと思って OLE.xs を調べたら、 pVarResult に対しては全く何もしてなかった。
ということは、私が勝手に勘違いして、勝手にpVarResultの処理を独自に追加したんだろうな。きっと。 pVarResult は、[out] なので、Win32OLE 側(呼び出し先)でメモリーを確保して返してあげればいいのか。 メモリーの解放は、OLEサーバ側(呼び出し元)でやってくれるので、気にすることはないのか。
念のため、pVarResultに値を設定しないことにしたら動きがどうなるか質問してみた(ruby-talk:345711)ら、 エラーは消えたけど、エラーメッセージも何も表示せずにクラッシュするようになったらしい(ruby-talk:345759)。
ということは、OLE.xs みたいに何もしないという訳にもいかんのか。
OLEサーバは、pVarResultにNULL以外を指定してWin32OLEを呼び出していて、 呼び出した後、OLEサーバは、何か値が設定されているだろうと期待して、pVarResultを参照したところクラッシュしたということか。
結局、どんなイベントを起こすとそうなるか知りたかったので、もう少しイベントの情報を教えてくれとお願いしてみた。
pr-win32ole はこんな感じにすれば動くのかな。
if pvarResult
v = 0.chr * 16
VariantInit(v)
WIN32OLE.ole_val2variant(result,v)
return VariantCopyInd(pvarResult, v)
end
| 固定リンク
この記事へのコメントは終了しました。
コメント
すみません。前の書き込みは[out, retval]BSTR* ppResultのようなものを想定していました。
[out, retval]VARIANT* pResult であれば、呼ばれた側は、if (pResult) { VariantInit(pResult); pResult->vt = VT_xxx... ; } が正しいです。
VariantCopyIndについては、「This function frees existing content of the destination variant (MSDN)」なので、outなVariantには直接、利用できません。最初にVariantInitでVT_EMPTYに設定する必要があります。
投稿: arton | 2009年9月 5日 (土) 16時33分
正直なところ、VariantInit以外のVariantが付くWin32 APIは、メモリーの扱いが不統一で危険なので、常にMSDNでメモリ操作について調べて利用するか、さもなければ直接vtやbstrValのようなメンバを操作するほうが良いと思います。
上の例では、VariantCopyIndの第2引数に与えているvにBSTRやIDispatchのようなメモリアロケーションが必要なオブジェクトが格納されていると、そのポインタをコピーするのか、再アロケート(あるいは再QIで参照カウンタを進める)かAPIドキュメントからは見えません(おそらくVB用にディープコピーすると思いますが記述されていないので想像でしかない)。したがってリークの可能性もあれば、逆に解放済みオブジェクトを参照する可能性もあります。
投稿: arton | 2009年9月 5日 (土) 16時40分
いやぁ、それにしてもVariantCopy一族は難しいですね。
VariantCopyであれば、結構、詳細までメモリルールを書いてあるんですが、VariantCopyIndは、CE版のAPI説明にデスティネーションのメモリ解放までは書いてありますが、ソースの扱いについては書いていないし。デリファレンスした結果でVariantCopyを内部的に呼ぶのであればディープコピー、そうでなければVariantCopyルールに従って、デリファレンスした場合はシャロウコピーで直接ポインタの場合はディープコピーということになりそうです。
投稿: arton | 2009年9月 5日 (土) 16時58分
いろいろありがとうございます。
とりあえず、私の認識は間違ってはいなかったということですね。
安心しました。
投稿: suke | 2009年9月 5日 (土) 17時22分