VC++6.0でDLLを作成してVBから呼び出す方法

このQ&Aのポイント
  • VC++6.0のDLLを作成し、VBから呼び出す方法について説明します。
  • VC++6.0で作成したDLLをVBから呼び出す際、一部の文字が正しく表示されない現象が発生する場合があります。
  • 文字化けの原因や対処法についても解説します。
回答を見る
  • ベストアンサー

VBからMFC-DLL呼び出し

VC++6.0でDLLを作成してVBから呼んでいます。 VC++6.0 __declspec(dllexport) BSTR WINAPI FunA() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CString strA = _T("This is the テストです。.愛する</CsvData>"); return strA.AllocSysString(); } VB6.0 Private Declare Function FunA _ Lib "Communication.dll" () As String Dim strRet As String strRet = StrConv(FunA(), vbFromUnicode) これを実行すると 『This is the テストです。.愛す?</CsvData>』 がstrRetに格納されます。 『愛する』→『愛す?』になってしまうんですが、 どうしてでしょうか。

質問者が選んだベストアンサー

  • ベストアンサー
  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.3

>回答していただいたコードを見ますと、VB側で >文字列サイズを決めてDLLに渡しているんですが、 >僕が意図していることも可能でしょうか。 >方法などがご存知でしたら教えてください。 VB、VC++間の受け渡しに限りませんが、 1.VC++側に、文字数を取得する関数を作り、それを事前に 呼び出すことで領域を確保する ・・・DLLでグローバル変数を使用しますが。 2.領域の確保、解放はすべてVC++側で行う ・・・VC++に、領域解放用の関数を作成する。 ただし、すべてアドレス操作になるため、 Longでアドレス値の受け渡しが必要 3.領域の確保はVC++、解放はVB側で行う となるでしょう。 で、簡単に済ますなら1になると思いますが、折角なので今回は3を お勧めします。 で、jaekukさんの作成されたものからの変更は、BSTRを返すのではなく、 VARIANTを返すようにしてください。 これで、正しくVBで扱える文字列を返せるようになり、 VB側では特に意識することなく領域の解放が行われます。 #DLLをCOMにしたり、タイプライブラリを作成すればString型(BSTR)でも 特に問題はなくなります。 VC++6.0 __declspec(dllexport) VARIANT WINAPI FunA() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); //別にこうする必要は無いですよ。API直接でもかまいません COleVariant vntA = L"This is the テストです。.愛する</CsvData>"; return vntA.Detach(); } VB6.0 Private Declare Function FunA _ Lib "Communication.dll" () As Variant Dim strRet As String strRet = FunA() こんなかな?

jaekuk
質問者

補足

ご回答本当に有難うございます。助かっています。 テストしてみましたが大丈夫でした。 これでまず解決できそうです。 >領域の確保はVC++、解放はVB側で行う ここで上のソースコード上は確保と開放のところが見当たらないですが、VB側で何もしなくても開放されるのでしょうか。 そしてもしよろしければ2番目のやり方も具体的に教えて頂けませんか。

その他の回答 (3)

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.4

>>領域の確保はVC++、解放はVB側で行う >ここで上のソースコード上は確保と開放のところが見当た>らないですが、VB側で何もしなくても開放されるのでしょうか。 確保は、COleVariantのコンストラクタで文字列を渡している時点で行われています。 解放は、DLLの関数を呼び出したときの関数が終了した時点、この場合はstrRetが無効になった時点で行われています。 ちなみに、VBの可変長文字列って特に意識しないでも VBが領域の確保、解放ってやってくれてますよね。 今回は、VBが領域の確保、解放を自動的に行うことができる、Variantに格納できる値をDLLから返すことによって VBの内部動作に領域の解放を任せています。 もちろん、VBでは解放の処理を自動的にやってくれますが、このDLLの関数をCやC++から呼んだときは、正しく解放処理を行わないとメモリリークが発生します。 >そしてもしよろしければ2番目のやり方も具体的に教えて頂けませんか。 あくまでも例ですが。 __declspec(dllexport) LONG WINAPI FunA(LPSTR * lplp) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); LPSTR lpStr = new char[42]; lstrcpy(lpStr, "This is the テストです。.愛する</CsvData>"); *lplp = lpStr //結局VB側で長さが必要になっちゃいますけどね return 42; } __declspec(dllexport) LONG WINAPI Free(LPSTR lpStr) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); delete lpstr[]; return 0; } VB6.0 Private Declare Function FunA _ Lib "Communication.dll" (lpStrPtr As Long) As Long Private Declare Function Free _ Lib "Communication.dll" (ByVal lpStrPtr As Long) As Long Private Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As String, ByVal lpString2 As Long) As Long Dim lngLen As Long Dim lngStrPtr As Long lngLen = FunA(lngStrPtr) '取得した内容をString型にするために必要な領域を準備 Dim strString As String strString = Space(lngLen) 'lpStrPtrから文字列を取り出す '第二引数がByVal Longになってるところがミソ Call lstrcpy(strString, lngStrPtr) 'DLLで確保した領域を解放 Call Free(lngStrPtr) こんな感じにすれば一応はできますが。 似たようなことをやってるところを見つけたのでどうぞ。 http://www.bekkoame.ne.jp/~ilgg/VBMain/VB/C/Pointer.html

参考URL:
http://www.bekkoame.ne.jp/~ilgg/VBMain/VB/C/Pointer.html
jaekuk
質問者

お礼

ご回答有難うございます。 おかげさまで解決できました。 今後ともよろしくお願いします。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.2

>テストしてみたんですが,うまく行きません。 >もっと具体的なコードが欲しいですが, BSTRで返す理由も聞いてみたかったですけど(^^;; というわけで、サンプル。 __declspec(dllexport) LONG WINAPI FunA(LPSTR lpString) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); lstrcpy(lpString, "This is the テストです。.愛する</CsvData>"); return(0); } VB6.0 Private Declare Function FunA _ Lib "Communication.dll" (ByVal lpString As String) As Long Dim strRet As String strRet = Space(256) Call FunA(strRet)

jaekuk
質問者

補足

回答有難うございます。 BSTRで返す理由はDLLの中で返す文字列の長さが動的に変わるのでVB側で文字列長さを決めてDLLに参照型パラメータとして渡すのが困難なだめです。 回答していただいたコードを見ますと、VB側で文字列サイズを決めてDLLに渡しているんですが、僕が意図していることも可能でしょうか。 方法などがご存知でしたら教えてください。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1

こんなことをしてるから。 >Dim strRet As String >strRet = StrConv(FunA(), vbFromUnicode) なんでMFC側からBSTRで返すんですか? 簡単に済ますのなら、VBからは普通は戻り値ではなくByValのパラメータでStringをわたし、 VC++側はLPSTRで受け取るのがいいと思うのですが。

jaekuk
質問者

補足

ご回答有難うございます。 テストしてみたんですが,うまく行きません。 もっと具体的なコードが欲しいですが, お願いします。

関連するQ&A

  • MFC-DLL VBからCallしStackError[No.741430の続き]

    #DLLをCOMにしたり、タイプライブラリを作成すればString型(BSTR)でも 特に問題はなくなります。 VC++で文字列を返すDLLを作ってVBで呼んでいます。 DLLの中でのスタック(Stack)サイズの問題みたいですが、 DLLは自分のスタックを持たなくてそれを使うAppのスタックを使うとしていますが、間違っていたら教えてください。そしてどうすればこのエラーを避けることができて、ただしくデータをVB側で受け取ることができるのでしょうか。 しかし返すデータが大きく(たとえば3MBの文字列)なると『実行エラー28 スタック領域が不足しています。』というエラーメッセージが出て終了されます。 VC++6.0 __declspec(dllexport) VARIANT WINAPI FunA() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); COleVariant vntA = <3MB程度の文字列> ; return vntA.Detach(); } VB6.0 Private Declare Function FunA _ Lib "Communication.dll" () As Variant Dim strRet As String strRet = FunA()

  • Cで作成したDLLをVBで呼出

    Cで作成したDLLの関数をVB6.0から呼び出す事ができず、悩んでおります。 ご教授お願いします。 どの様な関数を呼び出そうとしているのかというと、以下の通りです。 <DLL Cで作成(コンパイラVC6)> void WINAPI hoge(BSTR pgname,BSTR fmt,...){ ~処理~ } /* 宣言では頭にDLLExport*/ <呼出側 VB6.0で作成> '宣言 Public Declare Function hoge Lib "hoge" _ (ByRef pgname as String , _ ByRef fmt as String , _ ParamArray args()) '呼出 call hoge("foo","baa","array1",2) この様なコードを書いております。 C側、VB側ともに固定数の引数にしてみたところ、 通ったので「ParamArray args()」の定義が違うのではないか・・・?と思っているのですが、 どの様に宣言したらよい物なのでしょうか? もしくは、そもそも全然違う箇所を間違っているのでしょうか? 宜しくお願いします。 ※ 説明の足りない箇所があれば、仰ってください。

  • Cで作成したDLL関数をVBから呼ぶ(.NET)

    以前の質問に「Cで作成したDLL関数をVBから呼ぶ」(QNo.1703839)がありますが、下記のコードを見るとVB6での内容だと思います。 Dim keydata As String * 128 keydata = String$(128, Chr(0) & Chr(0)) VB.NETでVC++のDLLで変更した文字列を受けたいのですが、 どのようにすればよいのでしょうか? VB.NET2003 <DllImport("DllTest.dll")> Private Shared Function _ Test(ByVal s1 As String) As String End Function Private Sub btnTest_Click(...) ... Dim s1 As String = "abc" Dim s2 As String Dim s3 As String s2 = Test(s1) MessageBox.Show(s2) ' "1"が表示される s3 = StrConv(s2, VbStrConv.None) MessageBox.Show(s3) ' 同じく"1"が表示 end sub VC++のDLL extern "C" __declspec (dllexport) BSTR __stdcall Test(char* s1) { AfxMessageBox(s1); // "abc"が表示される OK strcpy(s1, "123"); CString s2; s2 = "123"; return s2.AllocSysString(); } また、文字列に全角を含めても大丈夫でしょうか? Unicodeの変換処理を行う必要があるのでしょうか? よろしくお願いします。

  • Cで作成したDLL関数をVBから呼ぶ

    以前にあった「Cで作成したDLL関数をVBから呼び 引数渡し方法」を試したのですがVB側でデータが受け取れません。 http://oshiete1.goo.ne.jp/kotaeru.php3?q=711327 C側での値設定がわるいのでしょうか? VB側 Public Declare Function testAP Lib "C:\bin\test.dll" (ByVal lpKeyData As String) As Long --------------------------------------------------------------------------- Dim lngRc As Long Dim keydata As String * 128 keydata = String$(128, Chr(0) & Chr(0)) lngRc = testAP(keydata) VC側 __declspec(dllexport) long __stdcall testAP(char *lpdata){ →C側でlpdataに値を設定する lpdata="ABCDEF"; }

  • VBのDLLの関数をVC++で使う

    VC++でDLLファイル(Test.dll)の関数を使いたいですが、下記の三つの関数を呼び出す場合はどうすればいいですか? 教えてください。 Test.dllの内容は以下のとおりです。 _ExportGCMS : IDispatch { _bstr_t CreateGCMSFile ( _bstr_t pCustomerName, _bstr_t pOutType, _bstr_t pOutDir ); _bstr_t AppendGCMSFile ( SAFEARRAY * * pData, _bstr_t pAppendFileName ); _bstr_t ExportCSV ( _bstr_t pSourceFile, _bstr_t pOutFileName ); } よろしくお願いします。

  • DLL VBとC++

    VBAからVC++2005のDLLを呼び出すプログラムを書いています。 VB側で作成したcpp_proc関数を呼ぶとVBアプリ自体が落ちました。 DLLのreturnの直前に以下のMessageBoxで表示させるとそこまでは表示され、 リターンを押すと、落ちました。 VB側の引数の値 String * 8192が悪いのでしょうか? return直前まで動作していたので、DLLの戻り値に何か原因があるのでしょうか? ついでの質問ですが、DEFの @1は無くても動くのでしょうか? 意味が知りたいです。 // ----- C++ (DLL側) ----- int __stdcall cpp_proc(LPCSTR inp, LPSTR out) { ... 省略 MessageBox(0, "ここまで通過", "debug", MB_OK); return 0; } // ----- DEF ----- LIBRARY "example" DESCRIPTION 'テスト' EXPORTS ; 明示的なエクスポートはここへ記述できます cpp_proc @1 '----- VB側 ----- Public Declare Function cpp_proc Lib "example.dll" _ (ByVal inp As String, ByRef out As String) As Integer Public Sub Test() Dim ret As Integer Dim inp As String Dim out As String * 8192 ret = cpp_proc(inp, out) MsgBox("ret=[" & Cstr(ret) & "]"); End Sub

  • VB6から参照可能なDLLの作成

    VB6から参照可能なDLLの作成を参考書をみながらしましたが、上手くいかない為質問させていただきます。 開発環境VC++ 2005 C++ CTEST.dll #include <windows.h> __declspec (dllexport) int __stdcall test(int i) { i = i + 5; return i; } .defファイル LIBRARY "test" DESCRIPTION EXPORTS A 以上でDLLを作成し、VB6側で Private Declare test Lib "CTEST.dll" (ByVal i as integer) で宣言しても「エラー53 ファイルがみつかりません」と表示されます。「参照の追加」から参照しようとしても「このファイルは参照できません。」をエラーがでてしまいます。 直すべき点はどの部分なのでしょうか? ご教示ねがいます。

  • VCでのDLLからVBへの文字列の引渡し

    ===VB(Ver.6.0 SP5)側=== Public Declare Function GetStrSample Lib "Test.dll" () As String ・・・・・ Label1.Caption = GetStrSample ===VC側(Ver6.0)=== const char *StrSample="ABCDE01234";   ・・・・ _declspec(dllexport) BSTR _stdcall GetStrSample() { CString strResult; strResult = StrSample; return strResult.AllocSysString(); } 上記のようなコードで、VC側をDLLとしてVBから呼び出すと、 Label1には "A" しか表示されず、ブレークを置いてGetStrSample の戻り値を調べてみると、0x41,0x00,0x42,0x00,のように、 0x00が挟まれてしまいました。 ( ?hex(asc(mid(GetStrSample,3,1))) のようにして調べました。)  何故なのでしょうか? 文字コードの違いでしょうか? 正常にABCDE01234が渡せるようにするにはどうすればいいでしょうか? VCは初心者で、本や他人の作ったコードやMSDNを見て作成してみました。 目的は、DLLのバージョン等の情報をVB側に渡したいのです。 よろしくお願いします。

  • VBのString型の配列をVCで受け取るには?

    VBでString型の配列として定義されている変数を VCのプログラムで受け取るにはどうすればよいのでしょうか? 試しにVBでString型の配列を作って DLLのC_TESTというファンクションを呼び出すという 処理を作ってみたのですが、コンパイルエラーになってしまいます。 なにかおかしいところありますか? そもそもVCにはString型ってないんですよね? プログラミング初心者ですので、変な言葉遣いに なってるかもしれませんが宜しくお願いします。 VB Declare Function C_TEST Lib "\test.dll" (ByVal data() As String) As Integer Dim A(1) As String dim rtn as Integer A(0)="あああ" A(1)="いいい" rtn= C_TEST(A) VCのプログラム int _stdcall C_TEST(LPSTR A[2] ){ AfxMessageBox( A[0] ); return(0); }

  • VB6で作成した自作DLLをVB.NETで呼び出し例外発生時に参照渡しの引数に値を設定する方法

    VB6で作成した自作のDLLをVB.NET2005で作成したEXEから呼び出した際に、DLLメソッドの正常・異常終了に関わらず第2引数の戻り値に第1引数の値を設定したいと考えていますが旨くいきません。 何かよい方法はないでしょうか? 以下、簡単なサンプルです。 =========================== VB6 DLL =========================== Public Sub getDataForTest(ByVal strIn As String, ByRef strOut As String) Dim intData As Integer 'strInの値をstrOutに代入 strOut = strIn 'strInの値を1で割り算 intData = CInt(strIn) / 1 End Sub =============================================================== =================== DLL呼び出し正常パターン =================== Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim objCom As New Project1.Class1 Dim strRet As String = "" Try Call objCom.getDataForTest("1", strRet) Catch ex As Exception MsgBox(ex.Message) Finally MsgBox(strRet) ←←← 1が表示される  End Try End Sub =============================================================== =================== DLL呼び出し異常パターン =================== Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim objCom As New Project1.Class1 Dim strRet As String = "" Try Call objCom.getDataForTest("A", strRet) Catch ex As Exception MsgBox(ex.Message) Finally MsgBox(strRet) ←←← この時にAを表示したいがstrRetが空  End Try End Sub ===============================================================

専門家に質問してみよう