- - PR -
DLLから文字列を取得する方法
1|2|3|4|5
次のページへ»
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2006-07-13 11:24
いろはです。
C#で作っているEXEからVCで作っているDLLを呼び出して文字列を取得する方法を 教えてください。(VS2003) DLL内でメモリを確保し、メッセージを作成してC#側で扱いたいと思っています。 MSDNのサンプルをチェックして、メモリ確保はCoTaskMemAllocを使用すると 言うことは確認しましたが、いまいち上手く行っておりません。 以下、DLL側のサンプルソースです。 int GetMessage( char** msg ) { if( *msg ) CoTaskMemFree(*msg); // 解放が必要? char message[] = "message!"; size_t len = strlen( message ); *msg = (char*)CoTaskMemAlloc( sizeof(char)*(len+1) ); return 0; } C#では以下の様に書いています。 [DllImport("XXXX.dll")] public extern static int GetMessage( ref System.Text.StringBuilder msg ); System.Text.StringBuilder msg = new System.Text.StringBuilder(); msg.Append( (char)0 ); GetMessage( ref msg ); 上記のソースだとCoTaskMemFreeで例外が発生します。 呼び出し側をStringBuilderからStringに変えてみたり、refをとってみたりしました が、やっぱり上手く行きません。 MSDNのサンプルには戻り値として返す方法も出ていましたが、戻り値は 他の用途で使いたい為、引数として何とか文字列が取れないかと思っています。 以上、よろしくお願いします。 | ||||
|
投稿日時: 2006-07-13 11:46
String変数を生成したいのであればSysAllocString関数を使ってみるのはどうでしょうか?
VC DLL側サンプル
C#側で、きちんとMarshalAs属性を指定すればうまくいくと思います。 (Stringで受け取る) ※関数は2つ書きましたが(〜A、〜W)、MarshalAsを適切に設定すればどちらも同じ動きになります。 C#のデフォルト(MarshalAsを指定しない場合)がどちらか確かでないため2つ書いてみました。 [ メッセージ編集済み 編集者: Blue 編集日時 2006-07-13 11:51 ] | ||||
|
投稿日時: 2006-07-13 13:13
Blueさん 回答ありがとうございます。
あげていただいたサンプルを元にC#の呼び出し元を以下の様に書き換えることで、 欲しい処理が実現できました。 [DllImport("XXXX.dll")] public extern static int GetMessage( [MarshalAs(UnmanagedType.BStr)] ref String msg ); ところで今回はBlueさんに教えて頂いた方法でまったく構わないのですが、 私が最初にチャレンジした方法では上手くいかないんでしょうか? MarshalAsとかも試してみたんですが、やっぱりダメでしたし。。 やっぱりこの辺の話は難しいです。 | ||||
|
投稿日時: 2006-07-13 14:09
一応
で動いているようには見える。 最初のやつでは、文字列を確保した領域に入れていないのでアウトですね。 [ メッセージ編集済み 編集者: Blue 編集日時 2006-07-13 14:33 ] | ||||
|
投稿日時: 2006-07-13 15:38
再び出していただいたCoTaskMemAllocを使用する方を試してみました。
仕様上CoTaskMemAllocを使えとなっているようですので、出来ればこちらでと思うので。 しかし、やはりCoTaskMemFreeの部分で例外が出てしまいます。 現状のソースをもう一度載せます。何処がBlueさんと違うのでしょうか? ちなみに今回はDLL内はUnicodeを使用しています。 (毎回2パターン書いてもらって申し訳ありませんでした) C# 呼び出し側 [DllImport("ConvertImage.dll")] public extern static int GetMessage( [MarshalAs(UnmanagedType.BStr)] ref String msg ); string msg = ""; GetMessage( ref msg ); VC DLL側 int GetMessage( BSTR* msg ) { ::CoTaskMemFree( *msg ); // ここで早速例外が出てしまいます -以下省略- } せっかく答えていただいているのに、長くなり申し訳ありません。 出来ればちゃんと理解しておきたいと思いますので。 よろしくお願いします。 | ||||
|
投稿日時: 2006-07-13 15:47
渡すのは BSTR型ではなく、BSTR*型です。(NULL文字終端) ですから UnmanagedType.BStrではなくUnmanagedType.LPWStrでやってみてください。 (でも、SysAllocStringを使っているほうもダメだと思うんだけど何でだろ?) [ メッセージ編集済み 編集者: Blue 編集日時 2006-07-13 16:03 ] | ||||
|
投稿日時: 2006-07-13 16:23
どうも、SysAllocString関数を間違えて認識していたようです。
UnmanagedType.BStr は 「長さを示すプリフィックスを付けた 2 バイトの Unicode 文字列。」 で、 UnmanagedType.LPWStr は 「終端が null の 2 バイトの Unicode 文字列。」 でした。 MSDN - UnmanagedType 列挙体 で、SysAllocStringの場合、UnmanagedType.BStrでもUnmanagedType.LPWStrでもうまくいくのは どういう仕組みなんだろ。。。 ↓↓↓ Dr. GUI と COM オートメーション、第 3 部:続 COM のすばらしきデータ型 に解説がありました。 ということは、SysAllocStringを使う場合「LPWStr」で受けるのは大丈夫なのかな? これがまずいと、SysAllocStringByteLen+LPStrもまずくなるような。。。 # いろいろ編集してすいません。 [ メッセージ編集済み 編集者: Blue 編集日時 2006-07-13 16:42 ] | ||||
|
投稿日時: 2006-07-13 16:40
なんだかBlueさんまで悩ませてしまっているようです。。。
申し訳ありません。 現在の状況を報告します。 とりあえずUnmanagedTypeはLPWStrと修正しました。 がやはりCoTaskMemFreeで例外が発生します。 今まで進行中のプロジェクトの一部でテストをしていたので、今回の問題と切り分けるために、新規のプロジェクトを起こしてテストをしてみました。 すると、、、 なんか動きが変? C#側をスタートプロジェクトとしてデバッガ起動するとCoTaskMemFreeで例外が発生します。 しかしVC側をスタートプロジェクトとして起動すると、何の問題も無くCoTaskMemFreeが成功します。。汗 とりえず、これから”Dr.GUIとCOM…”を読んでみます。 |
1|2|3|4|5
次のページへ»