- PR -

DLLから文字列を取得する方法

投稿者投稿内容
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2006-07-18 09:56
引用:

そもそもの発想が『CoTaskMemAllocを使えば良いんだ』っと言うところでしたので。



なら、BSTR でやり取りするのが簡単かもしれませんね。
「非 COM で BSTR は…」という抵抗感も無いでしょうし。
Blue
大ベテラン
会議室デビュー日: 2005/09/12
投稿数: 230
お住まい・勤務地: 知っている人は知っている
投稿日時: 2006-07-18 09:59
引用:

稍丼さんの書き込み (2006-07-17 13:04) より:
ただ,ポインタのポインタにした場合,
DLL側が確保した領域にある文字列を
マーシャラが開放していないようです。


これはどのようにして調べられたのですか?
これ(SysAllocStringやCoTaskAlloc)がNGな場合、それらをつかっているDLLはすべてNGということですよね?
(VB6以前の場合、MSのサンプルでSysAllocStringを使っていたので、それ以降も同様のやりかただと思っていた。)

# rallocやmalloc,C++のnewは確か(VB6以前のとき)うまくVB側に渡せなかったので実験していません。
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2006-07-18 12:46
引用:

引用:

ただ,ポインタのポインタにした場合,
DLL側が確保した領域にある文字列を
マーシャラが開放していないようです。


これはどのようにして調べられたのですか?



調べるまでも無く、想像に難くないと思いますが?

「ポインタのポインタ」で渡された文字列の領域を、何故、どのように解放しなければならないかという知識が、マーシャラにはありません。

コレに対して、BSTR では、BSTR の領域確保・解放の手段が明確であり、受け渡しに伴う解放の責任が渡す側と受ける側のどちらにあるかも明確なので、1つ前の投稿で勧めてみました。

[ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2006-07-18 13:59 ]
Blue
大ベテラン
会議室デビュー日: 2005/09/12
投稿数: 230
お住まい・勤務地: 知っている人は知っている
投稿日時: 2006-07-18 13:11
引用:

渋木宏明(ひどり)さんの書き込み (2006-07-18 12:46) より:
「ポインタのポインタ」で渡された文字列の領域を、何故、どのように解放しなければならないかという知識が、マーシャラにはありません。

コレに対して、BSTR では、BSTR の領域確保・解放の手段が明確であり、受け渡しに伴う解放の責任が渡す側と受ける側のどちらにあるかも明確なので、1つ前の投稿で勧めてみました。


あ〜やっと理解できました。
BSTRの場合は、ポインタのポインタではなかったですね。

ということは、BSTR* で受け、SysAllocString等で領域を設定するのはなんら問題はないけれど、
LPWSTR* で受け、CoTaskAlloc等で領域を設定するのは、マーシャラがどう解放するのかわからない
ので、自前で解放関数を作って対応するしかないのですね。
yayadon
常連さん
会議室デビュー日: 2003/07/23
投稿数: 41
投稿日時: 2006-07-18 13:14
# ごく簡単にマーシャラの仕組みを書いてみました。
# 詳しくは,英文のヘルプを見てください。

引用:

Blueさんの書き込み (2006-07-18 09:59) より:
これ(SysAllocStringやCoTaskAlloc)がNGな場合、
それらをつかっているDLLはすべてNGということですよね?



最初の例の 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 ]
yayadon
常連さん
会議室デビュー日: 2003/07/23
投稿数: 41
投稿日時: 2006-07-18 13:41
BSTR* は,ポインタのポインタなんだけど,
BSTR は,COMの中心人物で,
文字列のメモリ上での仕様やそのポイントの仕方が決まっていて,
開放の仕方はハッキリしている(SysFreeString)ので
マーシャラは,勘違いしないようです。

追記:
BSTRがPInvokeのヘルプの文字列受け渡しの例に出てこないのは,
COM Interop での方の扱いを想定しているからです。

[ メッセージ編集済み 編集者: 稍丼 編集日時 2006-07-18 13:49 ]
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2006-07-18 14:10
引用:

BSTRの場合は、ポインタのポインタではなかったですね。



いいえ違います。
(てか、多分用語の用法が曖昧なだけなんでしょうが、↑のように書くと誤解を招きます)

BSTR を使うとしても、「文字列を受け取る」のならば BSTR* で、「ポインタのポインタ」を使うことになります。
SDK ヘッダを見れば分かりますが、BSTR 自体が SysAllocString() API によって確保されたメモリ領域を指すポインタです。

引用:

ということは、BSTR* で受け、SysAllocString等で領域を設定するのはなんら問題はないけれど、



はい。扱うブツが BSTR である以上、不要になった文字列の解放を SysFreeString() で行うのは明確です。

引用:

LPWSTR* で受け、CoTaskAlloc等で領域を設定するのは、マーシャラがどう解放するのかわからない
ので、自前で解放関数を作って対応するしかないのですね。



その通りです。

渡されるのは「文字列のポインタ」でしかないので、そこには malloc() したのか、new したのか、CoTaskMemAlloc() したのか、GlobalAlloc() したのか、等の情報がありません。

結果、「領域をどのように解放するか」はプログラマの責任になります。

_________________
// 渋木宏明 (Hiroaki SHIBUKI)
// http://hidori.jp/
// Microsoft MVP for Visual C#
//
// @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/
Blue
大ベテラン
会議室デビュー日: 2005/09/12
投稿数: 230
お住まい・勤務地: 知っている人は知っている
投稿日時: 2006-07-18 14:26
引用:

渋木宏明(ひどり)さんの書き込み (2006-07-18 14:10) より:
引用:

BSTRの場合は、ポインタのポインタではなかったですね。



いいえ違います。
(てか、多分用語の用法が曖昧なだけなんでしょうが、↑のように書くと誤解を招きます)


そうですね。
(OLE2ANSIでない場合)BSTRは unsigned short* のtypedefであることは、かなり以前から知っていましたが、
このスレッドに回答しているとき(Blue 投稿日時: 2006-07-13 16:23)
あ〜文字列長も入っているのね。これは単なるポインタじゃねぇなぁ(LPWSTRと同等に扱ってはいけないんだ)と思ったため、
ポインタのポインタじゃないって言い方になってしまいました。

スキルアップ/キャリアアップ(JOB@IT)