- ベストアンサー
Cで作成したDLL関数をVBから呼び 引数渡し方法
/**** Cプログラム *****/ int testAP( char* a) aのポインタにアドレスを返します。 /**** VB プログラム****/ Public Declare Function testAP Lib "test.dll" (ByRef a As String) As Integer Dim keydata As String * 128 lngRc = testAP(keydata) 上記VBのAPを実行するとアプリケーションエラーになります。 Cプログラムのデバックをすると入口ではaのポインタにはアドレスがセットされていて 、値を設定出来、最後まで正常動作して、VBとのインタフェースで落ちています。 VB6.exeでアプリケーションエラーになっています。 恐らく、VBにはポインタという概念が無いと聞いていてCのAPとの受け渡しに失敗して そうなのですが、VBでの引き渡し方法が分かりません。 よろしくお願い致します。
- みんなの回答 (10)
- 専門家の回答
質問者が選んだベストアンサー
>__declspec(dllexport) int testAP(BSTR* cp_KeyData){ > >→char*からBSTR*に変更しました。 だめです。そんな強引なことをしないでください。 char *でかまいません。 BSTR*にするとメモリ破壊が起きます。 __stdcallはどうしたんですか? (ごめんなさい、アンダースコア2つですね) >只、VCのデバックを行うと実行時エラー'49' >DLLが正しく呼び出せません。が出力される。 >(DLL関数を呼んで処理が終了してVBに戻る所で出力されます。 VBのDeclareステートメントと、Cの処理があっていません。メモリを破壊しているのでしょう。 EXEにして動くのはたまたまでしょう。
その他の回答 (9)
- sha-girl
- ベストアンサー率52% (430/816)
モジュール定義ファイルはDLL作成時に作ってますか? (ファイル名:test.def) LIBRARY DLL名 EXPORTS 関数名1 関数名2 関数名3 こんな感じのファイルです。
補足
モジュール定義ファイルを作成したところ正常に動作しました。 皆様のご指導の結果、現状 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に値を設定する } モジュール定義 --- test.defファイル ---- LIBRARY test EXPORTS testAP 上記設定及びコンパイルで実行した結果 VB側でDLLのtestAPを呼び、正常に戻り、keydata変数には C側で設定した値が返却されました。 VBからCのDLLを呼ぶ際は、モジュール定義ファイルも必要なのですね。 momoturboさん、hayahayahayaさん、taka_tetsuさん、sha-girlさん、FlossenEngelさん ありがとうございました。皆様のおかげですごく助かりました。 また特にtaka_tetsuさん、sha-girlさんには大変時間をさいてもらって感謝しています。ありがとうございました。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>エントリtestAPがDLLファイル内に見つかりませんと言うメッセージが出力されます。 #7の方の参考urlに書いてある、defファイルを作成してDLLのプロジェクトに追加してビルドしなおしてください。
補足
皆さんの意見を参考に下記の方法(但し、VBをコンパイル(EXE)にして)で 正しく処理が出来ました。!! でも、下記の方法で大丈夫なのか不安です。 何かご指摘がありましたら、教えてください。 また、デバック時のエラーについて、知っている方がいれば教えてください。 /* ---- C側のプログラム ------*/ __declspec(dllexport) int testAP(BSTR* cp_KeyData){ →char*からBSTR*に変更しました。 char c_DATA[5]="1234" LPSTR lp_DATA; lp_DATA=(LPSTR)cp_KeyData; →LPSTRにアドレスをかぶせる strcpy(lp_DATA,c_DATA); return(OK); } /* ---- VB側のプログラム ------*/ Public Declare Function testAP Lib "test.dll" (ByVal lpKeyData As String) As Long Dim lngRc As Integer Dim keydata As String * 128 →128Byte確保、確保しないとエラーとなってしまう? lngRc = testAP(keydata) →keydataには"1234"が返されました。 /*****************************************************************************/ 只、VCのデバックを行うと実行時エラー'49' DLLが正しく呼び出せません。が出力される。 (DLL関数を呼んで処理が終了してVBに戻る所で出力されます。 VBをコンパイル(EXE)にして実行すると正しく処理が行われるます。 どうしてなのでしょう?
- FlossenEngel
- ベストアンサー率77% (132/170)
参考までに↓(既に出ている回答以上の情報はありませんが)
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>__declspec(dllexport) int FAR testAP(char* a) > >呼び出しは出来るのですが、aのアドレスがNULLです。 かも知れませんね。 呼び出しが出来るかどうかは関数がエクスポートされているかどうかだけです。 で、呼び出し規約は引数の渡し方の定義です。 ちなみに、FARはWin32では意味がありません。 >→ int _stdcall testAP(char* a)に修正した方が >いいのでしょうか? __declspec(dllexport) int _stdcall testAP(char* a) こうしてください。
補足
度々すみません。 __declspec(dllexport) int _stdcall testAP(char* a)に変更したのですが、エントリtestAPがDLLファイル内に見つかりませんと言うメッセージが出力されます。 ご指摘がありましたらお願い致します。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
よくよく見ると >int testAP( char* a) 呼び出し規約が無いですが平気ですか?。 VBから呼び出す場合は_stdcall規約です。 int _stdcall testAP( char* a) とか int WINAPI testAP( char* a) になるはずです。 >Public Declare Function testAP Lib "test.dll" (ByVal keydata As String) As Integer 戻り値の型がIntegerになってます。 C側ではintなので、32bitですからLongにする必要があります。 で、あとは#4の方の指摘どおり、StrPtrが不要です。 #WindowsAPIの呼び出しってしたこと無いですか?
補足
すみません、C側は以下の記述を行ってDLLを作成してます。 __declspec(dllexport) int FAR testAP(char* a) 呼び出しは出来るのですが、aのアドレスがNULLです。 → int _stdcall testAP(char* a)に修正した方が いいのでしょうか? ご指摘がありましたら、お願い致します。
- sha-girl
- ベストアンサー率52% (430/816)
StringはByValで渡してください。 またStrPtrが不要です。 lngRc = testAP(keydata) VB6では内部文字コードはUNICODEで保持しています。 一方CはSJISです。 StringをByValで渡すのは特別な意味があります。 暗黙的に一度SJISに変換してDLLに渡しています。 ByValといっても実際は参照渡しのようなもので dll側で書き換えた文字列は keydataに反映されます。
補足
ありがとうございます。 StrPtrを省略してデバックで検証したのですが、 DLL関数の受け側のポインタがNULLで設定されるため、 渡すことができません。。。 ご指摘通りにStringはByValにして、StrPtrを省略したのですが。。。まだ漏れている点がございましたらご指摘ください。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>Public Declare Function testAP Lib "test.dll" (ByRef a As String) As Integer 正しくはByValです。 http://homepage2.nifty.com/newton/vbe/not_teach/hvbe_06.html >/**** Cプログラム *****/ >int testAP( char* a) >aのポインタにアドレスを返します。 ちなみにこれではポインタは返せませんよ。 ポインタの指す領域に文字列は返せますが。 本当にアドレスの値を返したいのであれば、 Win32であればポインタは32ビットなのでLongを使うことになります。
補足
ありがとうございます。 ご指摘通りポインタを指す領域に文字列も返します。 #1,2,3の方がのご指摘通りに、修正して行ったのですが、 今度は実行時エラー49 DLLが呼び出せませんと出力されすます。 このメッセージはVBからDLL関数を呼んで、関数を抜けて VBに戻るときに出力されます。 VBの修正は以下の通りなのですが、誤りとあったらご指導お願い致します。 Public Declare Function testAP Lib "test.dll" (ByVal keydata As String) As Integer Dim keydata As String * 128 lngRc = testAP(StrPtr(keydata))
- hayahayahaya
- ベストアンサー率36% (41/113)
#1の方と同じですが、 VB6ならstrPtrが使えますが、.Netでは確認していません。 ret = testAP(strPtr(keydata)) で keydata をみてみてください。
- momoturbo
- ベストアンサー率55% (49/88)
まったく自信ありません。(^ ^; 1)strPtrを使用する(文字列のポインタを返します) lngRc = testAP(strPtr(keydata)) ただし、strPtrは非公式関数みたいです。 .Netではなくなった? 2)Cのdefファイルの設定ミス インタープリンター場で動かすと、アプリケーション エラーで落ちますが、VBをexeにしたら落ちなかった ことがあります。 何をどうすればと、きかれてもわかりません。 Cはよくわからないもので・・ 参考になれば幸いです
補足
ご指導ありがとうございます。 __stdcallを試してみたのですが、実行時に 実行時エラー'453' TestAPがDLLファイル C:\bin\test.dll内に見つかりません。 というエラーになってしまいます。 C側は __declspec(dllexport) long __stdcall testAP(char*) VB側は Public Declare Function testAP Lib "c:\bin\test.dll" (ByVal lpKeyData As String)As Long です。 test.dllはパス通りの場所には置いてあります。 なにか誤りがありましたらご指導お願い致します。