- - PR -
DLLから文字列を取得する方法
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2006-07-18 09:56
なら、BSTR でやり取りするのが簡単かもしれませんね。 「非 COM で BSTR は…」という抵抗感も無いでしょうし。 | ||||||||||||
|
投稿日時: 2006-07-18 09:59
これはどのようにして調べられたのですか? これ(SysAllocStringやCoTaskAlloc)がNGな場合、それらをつかっているDLLはすべてNGということですよね? (VB6以前の場合、MSのサンプルでSysAllocStringを使っていたので、それ以降も同様のやりかただと思っていた。) # rallocやmalloc,C++のnewは確か(VB6以前のとき)うまくVB側に渡せなかったので実験していません。 | ||||||||||||
|
投稿日時: 2006-07-18 12:46
調べるまでも無く、想像に難くないと思いますが? 「ポインタのポインタ」で渡された文字列の領域を、何故、どのように解放しなければならないかという知識が、マーシャラにはありません。 コレに対して、BSTR では、BSTR の領域確保・解放の手段が明確であり、受け渡しに伴う解放の責任が渡す側と受ける側のどちらにあるかも明確なので、1つ前の投稿で勧めてみました。 [ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2006-07-18 13:59 ] | ||||||||||||
|
投稿日時: 2006-07-18 13:11
あ〜やっと理解できました。 BSTRの場合は、ポインタのポインタではなかったですね。 ということは、BSTR* で受け、SysAllocString等で領域を設定するのはなんら問題はないけれど、 LPWSTR* で受け、CoTaskAlloc等で領域を設定するのは、マーシャラがどう解放するのかわからない ので、自前で解放関数を作って対応するしかないのですね。 | ||||||||||||
|
投稿日時: 2006-07-18 13:14
# ごく簡単にマーシャラの仕組みを書いてみました。
# 詳しくは,英文のヘルプを見てください。
最初の例の BSTR* と SysAllocString と [UnmanagedType.BStr]ref string の組み合わせはOKです。 マーシャラがちゃんとオートメーションでの プロセスヒープ(デフォルトヒープ)でのやり取りの決まり Memory Management Rules (Out-parameter と In-out parameter のところ) を適用して, どっちが確保して,どっちが開放するかを認識しているからです。 基本的には,マーシャラは, COMの仕様にしたがっています。 デフォルトのルールは,簡単に書くと,「いつでも開放」するです。 また, COM仕様では,メモリのやり取りを CoTaskMem... 等の プロセスヒープ(デフォルトヒープ)でのやり取りを想定しています。 なので, CoTaskMemAlloc 以外の mallocやHeapAlloc等の別の方法で, 確保のするような場合は, マーシャラがCoTaskMemFreeで自動開放してしまうのを防ぐために, 文字列でも,IntPtrでの扱いが必要になります。 データ型をIntPtrにすると デフォルトの開放のルールが適用されないからです。 で,それだけだと死ぬほど面倒なので, データ型をIntPtrにするのでなく, 属性を使った文字列の受け渡しの仕組みにも仕込んであります。 (追記: 修正しました) それらを対処するのが,[UnmanagedType.LPWStr] 等の時で, マーシャラは,呼び出し側が無条件に開放しないのを想定します。 で,マーシャラは,それら文字列の受け取りは,ヘルプ Marshaling Strings にあるように, LPTSTR, LPWSTR, LPTSTR と StringBuilder と capacity の組み合わせを 想定しています。 追記: リンクがうまく行っていなかったのを三度修正 [ メッセージ編集済み 編集者: 稍丼 編集日時 2006-07-18 13:17 ] [ メッセージ編集済み 編集者: 稍丼 編集日時 2006-07-18 14:44 ] [ メッセージ編集済み 編集者: 稍丼 編集日時 2006-07-18 14:46 ] [ メッセージ編集済み 編集者: 稍丼 編集日時 2006-07-18 14:49 ] [ メッセージ編集済み 編集者: 稍丼 編集日時 2006-07-19 06:08 ] | ||||||||||||
|
投稿日時: 2006-07-18 13:41
BSTR* は,ポインタのポインタなんだけど,
BSTR は,COMの中心人物で, 文字列のメモリ上での仕様やそのポイントの仕方が決まっていて, 開放の仕方はハッキリしている(SysFreeString)ので マーシャラは,勘違いしないようです。 追記: BSTRがPInvokeのヘルプの文字列受け渡しの例に出てこないのは, COM Interop での方の扱いを想定しているからです。 [ メッセージ編集済み 編集者: 稍丼 編集日時 2006-07-18 13:49 ] | ||||||||||||
|
投稿日時: 2006-07-18 14:10
いいえ違います。 (てか、多分用語の用法が曖昧なだけなんでしょうが、↑のように書くと誤解を招きます) BSTR を使うとしても、「文字列を受け取る」のならば BSTR* で、「ポインタのポインタ」を使うことになります。 SDK ヘッダを見れば分かりますが、BSTR 自体が SysAllocString() API によって確保されたメモリ領域を指すポインタです。
はい。扱うブツが BSTR である以上、不要になった文字列の解放を SysFreeString() で行うのは明確です。
その通りです。 渡されるのは「文字列のポインタ」でしかないので、そこには malloc() したのか、new したのか、CoTaskMemAlloc() したのか、GlobalAlloc() したのか、等の情報がありません。 結果、「領域をどのように解放するか」はプログラマの責任になります。 _________________ // 渋木宏明 (Hiroaki SHIBUKI) // http://hidori.jp/ // Microsoft MVP for Visual C# // // @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/ | ||||||||||||
|
投稿日時: 2006-07-18 14:26
そうですね。 (OLE2ANSIでない場合)BSTRは unsigned short* のtypedefであることは、かなり以前から知っていましたが、 このスレッドに回答しているとき(Blue 投稿日時: 2006-07-13 16:23) あ〜文字列長も入っているのね。これは単なるポインタじゃねぇなぁ(LPWSTRと同等に扱ってはいけないんだ)と思ったため、 ポインタのポインタじゃないって言い方になってしまいました。 |