C++のDLLからVBで値を受け取るには?

解決


シープラ  2006-10-03 14:18:19  No: 63157  IP: 192.*.*.*

動作環境
Visual C++ (Visual Studio 2005)
VB6.0 SP5
WinXp

C++でCOMを作成しました。
それをVBから呼び出し文字列もしくは数値を受け取りたいのですが
どうしても文字列が空で参照できません。

C++側
-------------------------------------------------------------------------------------------------
宣言部分
[id(5), helpstring("メソッド get_test")] HRESULT get_test([in] BSTR str, [out] BSTR* strout);

処理部分
STDMETHODIMP Caaa::get_test(BSTR str, BSTR* strout)
{
  CComBSTR testBstr("あいうえお");
  BSTR bstr = testBstr; // bstrにはあいうえおが格納されている

  CAtlString  aaa;

  aaa = (WCHAR*)str;

  MessageBox(NULL,spBstr,aaa,0);  // あいうえおが表示される
  MessageBox(NULL,bstr,aaa,0);  // あいうえおが表示される

  strout = &bstr;  // out引数に"あいうえお"のアドレス格納
      // これがVB側で参照できればいい。
  return S_OK;
}

vb側
-------------------------------------------------------------------------------------------------

Private Sub Command3_Click()
On Error GoTo Err_Command3_Click
    Dim fff As aaa
    
    Dim str1 As String
    Dim str2 As String

    str1 = "わたった"  ' この文字がC++に渡っているのは確認済
    
    Set fff = CreateObject("ttt.aaa.1")
    fff.get_test str1, str2  'C++メソッド実行
    
    MsgBox (str2)     ' str2が空になっており参照できない
    
    
    Set fff = Nothing
    Exit Sub

End Sub


この方法でVB側に"あいうえお"の文字が渡ってこないのはなぜでしょうか?
色々と試しているのですが、str2は参照渡しで渡ってこないのでしょうか?
それとも根本的に何か間違っているのか、よくわからない状態になってしまいました。

助言いただけたら幸いです。
宜しくお願いします。

編集 削除
Blue  2006-10-03 14:38:07  No: 63158  IP: 192.*.*.*

とりあえず、C++での基本中の基本なところが出来てないような。
>strout = &bstr; 
*strout = bstr;

int test(int a){ a = 10; }
int main()
{
    int a;
    test(a);
}
でaに10が設定されないのと同じ理由。

編集 削除
シープラ  2006-10-03 14:57:29  No: 63159  IP: 192.*.*.*

返信ありがとうございました。
strout = &bstr; 
の後*stroutを参照すると"あいうえお"が入っているので同じことだとは思っていたのですが。。。

ご指摘どおりのロジックにしたところ、
もちろん*stroutには値がはいるのですが、vbに返ってきたところで"あいうえお"を見ることが出来ないのです。

値の返し方がまずいのか何なのかもはやわからなくなってしまいました。。

編集 削除
Blue  2006-10-03 15:02:09  No: 63160  IP: 192.*.*.*

となると

おそらく
>CComBSTR 
を使っているからです。
CComBSTRは内部で SysAllocString,SysFreeStringを呼んでいますので、
>fff.get_test str1, str2 'C++メソッド実行
get_testを抜けると自動的にSysFreeStringがよばれ、設定した文字列が解放されてしまうのではないでしょうか。

ですので、
>*strout = bstr;
というようにCComBSTRの値を使わないで、SysAllocStringした値を渡しましょう。

*strout = SysAllocString( bstr );
# *strout = bstr.Copy(); でもいけるかもしれないけど。

編集 削除
Blue  2006-10-03 15:03:27  No: 63161  IP: 192.*.*.*

訂正)
># *strout = bstr.Copy(); でもいけるかもしれないけど。
# *strout = testBstr.Copy(); でもいけるかもしれないけど。

編集 削除
Blue  2006-10-03 15:14:03  No: 63162  IP: 192.*.*.*

追記)
stroutにもともとある文字列をSysFreeStringしないとまずい気がします。

SysFreeString( *strout );


DLLの例ですが、過去ログも参考にしてください。
http://madia.world.coocan.jp/cgi-bin/Vcbbs/wwwlng.cgi?print+200606/06060060.txt
の Sample03W

編集 削除
Blue  2006-10-03 15:26:05  No: 63163  IP: 192.*.*.*

何度もすみません。
>VB6.0 SP5
だと、SysAllocStringじゃまずい気がしてきました。
SysAllocStringByteLenでBSTR型のマルチバイト文字の領域を渡さないと。

つまり Sample03A のような記述の仕方でないとダメなような。
(入力は、char*ですので注意してください)

編集 削除
シープラ  2006-10-03 15:35:13  No: 63164  IP: 192.*.*.*

*strout = SysAllocString(testBstr);
で値がVBで見れました!!

ほんとうに助かりました!!

もっと勉強せねばならないと改めて思いました。
ありがとうございました。

編集 削除
Blue  2006-10-03 15:37:31  No: 63165  IP: 192.*.*.*

>*strout = SysAllocString(testBstr);
あら。COMならそれでいけるんですな。
変な文字列になっていなければ大丈夫だと思います。

忘れ物
つ[解決チェック]

編集 削除
シープラ  2006-10-03 15:49:13  No: 63166  IP: 192.*.*.*

何から何まですみません。。。
今回初めて利用しましたがとても勉強になりました。

編集 削除