- PR -

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

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

戻り値として文字列を返す場合、マーシャラの開放はどうなるんでしょうか?



s/開放/解放/g

サンプルが正しいとして、out と同じ動きになるんでしょうね。
この動作は、先に挙げたヘルプの記載とも符合します。

コード:

p = static_cast< BSTR >( ::CoTaskMemAlloc( ( len + 1 ) * sizeof( wchar_t ) ) );



結果的に帳尻があって警告は出ないかもしれませんが、↑は

コード:

p = static_cast<LPWSTR>( ::CoTaskMemAlloc( ( len + 1 ) * sizeof( wchar_t ) ) );



であるべきかと。


[ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2006-07-19 13:53 ]
yayadon
常連さん
会議室デビュー日: 2003/07/23
投稿数: 41
投稿日時: 2006-07-19 17:23
引用:

Blueさんの書き込み (2006-07-19 12:11) より:
質問です。
戻り値として文字列を返す場合、マーシャラの解放はどうなるんでしょうか?


マーシャラは,基本的には常に解放で,
今まで問題にしてきた引数での場合でも,
LPTSTR / LPWSTR / LPSTR の場合は,
デフォルトの動作(常に解放)に従って解放されます。
in 時は in string と宣言で,
ref の時は,ref string と宣言するのでなく StringBuilder と宣言する。

どっちか微妙なのでは?というのは,LPTSTR* という話の流れだったと思います。

ヘルプによると,戻り値を解放したくない時は,
 LPTSTR GetCommandLine();
の使用例で,
IntPtr型で宣言して戻り値を受ける例がわざわざ載っているので,
そういうことでしょう。

# アドレスを引数から返して見たけど,毎回同じアドレスが返ってくるので,
# DLL側が同じ場所を(CoTaskMemAllocで)確保できているのと,
# 後から Marshal.PtrToStringUniで正確に取り出せないので
# 解放しているんでしょう。

// 開放 -> 解放 に修正

[ メッセージ編集済み 編集者: 稍丼 編集日時 2006-07-20 10:24 ]
Blue
大ベテラン
会議室デビュー日: 2005/09/12
投稿数: 230
お住まい・勤務地: 知っている人は知っている
投稿日時: 2006-07-20 00:19
引用:

渋木宏明(ひどり)さんの書き込み (2006-07-19 13:51) より:
s/開放/解放/g


間違えて変換していたようです。ご指摘ありがとうございます。

引用:

結果的に帳尻があって警告は出ないかもしれませんが、↑は

コード:
p = static_cast<LPWSTR>( ::CoTaskMemAlloc( ( len + 1 ) * sizeof( wchar_t ) ) );



であるべきかと。


そうですね。wchar_t*で宣言した変数である以上、BSTRにキャストすべきではないですね。

稍丼さん、渋木宏明(ひどり)さん、いろはさん
おかげさまで、文字列の領域確保に関してはカナリ勉強になりました。
いろいろ、ご指導ありがとうございました。
yayadon
常連さん
会議室デビュー日: 2003/07/23
投稿数: 41
投稿日時: 2006-07-20 10:01
一応,念のため...ということで。

LPWSTR は,wchar_t* です。
BSTR は,OLECHAR* ですが,
現在,OLECHAR は,WCHAR (wchar_t) なので,
結局,
BSTR も wchar_t* になります。

そうすると,各ポインタが指す先の状態が

コード:
□ や ■ は,1バイトとする ( + ■■ は,NULL終端文字)

    □□■■□□■■□□■■□□ + ■■
    ↑
    LPWSTR

    □□■■□□■■□□■■□□ + ■■
    ↑
    BSTR


のように考える人がいるかもしれません。
でも,真の意味は,

コード:

    □□■■□□■■□□■■□□ + ■■
    ↑
    LPWSTR

■■■■□□■■□□■■□□■■□□ + ■■
    ↑
    BSTR


という状態を想定しています。
-4バイト分のオフセット位置から4バイト長で,文字列長が入っていることを想定しています。

上で,

 BSTRの確保と解放は,原則,SysAllocString & SysFreeString を使う

というのは,そのためです。
CoTaskMemAlloc で確保したポイント先に,
memcpy された後の(LPWSTR のポイント先の)文字列の前には何もない
ということです。

このスレの最初の方で,[MarshalAs(UnmanagedType.BStr)] の時に,
SysAllocStringの確保だと成功して,
CoTaskMemAllocだと失敗していたのはそのためです。

で,いろはさんが SysAllocStringを使うべきと結論になったというのと,
ひどりさんが それが大原則です という話の流れになったわけです。


あと,SysAllocString は,
どこのヒープに確保しているんだ?と思う人もいるかもしれませんが,
SysAllocString や SysFreeString が,
使用するヒープへのハンドルの指定が要らないのは,
COM仕様でプロセスヒープ(デフォルトヒープ)上でやりとりすると決められているため
プロセスヒープ上に常に確保するから,そういう指定は必要ないからです。


# 私もマーシャラの動きの勉強になりました。

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