• ベストアンサー

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での引き渡し方法が分かりません。 よろしくお願い致します。

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

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

>__declspec(dllexport) int testAP(BSTR* cp_KeyData){ > >→char*からBSTR*に変更しました。 だめです。そんな強引なことをしないでください。 char *でかまいません。 BSTR*にするとメモリ破壊が起きます。 __stdcallはどうしたんですか? (ごめんなさい、アンダースコア2つですね) >只、VCのデバックを行うと実行時エラー'49' >DLLが正しく呼び出せません。が出力される。 >(DLL関数を呼んで処理が終了してVBに戻る所で出力されます。 VBのDeclareステートメントと、Cの処理があっていません。メモリを破壊しているのでしょう。 EXEにして動くのはたまたまでしょう。

akira_akira
質問者

補足

ご指導ありがとうございます。 __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はパス通りの場所には置いてあります。 なにか誤りがありましたらご指導お願い致します。

その他の回答 (9)

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.10

モジュール定義ファイルはDLL作成時に作ってますか? (ファイル名:test.def) LIBRARY DLL名 EXPORTS 関数名1 関数名2 関数名3 こんな感じのファイルです。

参考URL:
http://lion.zero.ad.jp/~zar70041/zarchis/archive/tips_vb_use_dll/
akira_akira
質問者

補足

モジュール定義ファイルを作成したところ正常に動作しました。 皆様のご指導の結果、現状 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)
回答No.8

>エントリtestAPがDLLファイル内に見つかりませんと言うメッセージが出力されます。 #7の方の参考urlに書いてある、defファイルを作成してDLLのプロジェクトに追加してビルドしなおしてください。

akira_akira
質問者

補足

皆さんの意見を参考に下記の方法(但し、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)にして実行すると正しく処理が行われるます。 どうしてなのでしょう?

回答No.7

参考までに↓(既に出ている回答以上の情報はありませんが)

参考URL:
http://kamakura.cool.ne.jp/oppama/misc/dll.html
  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.6

>__declspec(dllexport) int FAR testAP(char* a) > >呼び出しは出来るのですが、aのアドレスがNULLです。 かも知れませんね。 呼び出しが出来るかどうかは関数がエクスポートされているかどうかだけです。 で、呼び出し規約は引数の渡し方の定義です。 ちなみに、FARはWin32では意味がありません。 >→ int _stdcall testAP(char* a)に修正した方が >いいのでしょうか? __declspec(dllexport) int _stdcall testAP(char* a) こうしてください。

akira_akira
質問者

補足

度々すみません。 __declspec(dllexport) int _stdcall testAP(char* a)に変更したのですが、エントリtestAPがDLLファイル内に見つかりませんと言うメッセージが出力されます。 ご指摘がありましたらお願い致します。

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

よくよく見ると >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の呼び出しってしたこと無いですか?

akira_akira
質問者

補足

すみません、C側は以下の記述を行ってDLLを作成してます。 __declspec(dllexport) int FAR testAP(char* a) 呼び出しは出来るのですが、aのアドレスがNULLです。 → int _stdcall testAP(char* a)に修正した方が いいのでしょうか? ご指摘がありましたら、お願い致します。

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.4

StringはByValで渡してください。 またStrPtrが不要です。 lngRc = testAP(keydata) VB6では内部文字コードはUNICODEで保持しています。 一方CはSJISです。 StringをByValで渡すのは特別な意味があります。 暗黙的に一度SJISに変換してDLLに渡しています。 ByValといっても実際は参照渡しのようなもので dll側で書き換えた文字列は keydataに反映されます。

akira_akira
質問者

補足

ありがとうございます。 StrPtrを省略してデバックで検証したのですが、 DLL関数の受け側のポインタがNULLで設定されるため、 渡すことができません。。。 ご指摘通りにStringはByValにして、StrPtrを省略したのですが。。。まだ漏れている点がございましたらご指摘ください。

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

>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を使うことになります。

akira_akira
質問者

補足

ありがとうございます。 ご指摘通りポインタを指す領域に文字列も返します。 #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))

回答No.2

#1の方と同じですが、 VB6ならstrPtrが使えますが、.Netでは確認していません。 ret = testAP(strPtr(keydata)) で keydata をみてみてください。

  • momoturbo
  • ベストアンサー率55% (49/88)
回答No.1

まったく自信ありません。(^ ^; 1)strPtrを使用する(文字列のポインタを返します) lngRc = testAP(strPtr(keydata)) ただし、strPtrは非公式関数みたいです。 .Netではなくなった? 2)Cのdefファイルの設定ミス インタープリンター場で動かすと、アプリケーション エラーで落ちますが、VBをexeにしたら落ちなかった ことがあります。 何をどうすればと、きかれてもわかりません。 Cはよくわからないもので・・ 参考になれば幸いです

関連するQ&A

  • 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からCで作成されたDLLへの引数の渡し方

    VBからCで作成されたAPI関数への引数の渡し方がわかりません。 C側の引数のデータ型はchar型でポインタ渡しではありません。 ------------------------------------------------ C側 int KANSU(char Mode) VB側 Public Declare Function KANSU Lib "USERAPI.dll" ( ByVal CHAR As Byte) As Long ------------------------------------------------ C側がポインタ渡しの場合は、VB側はSTRING型で別に悩むことはなかったのですが、文字列渡しの場合は、VB側はBYTE型で渡す必要があり、その方法がわかりません。 どなたか、分かる方よろしくお願いします。 ちなみに、VB6.0です。

  • dllを使用しVB側に文字列を返す2

    No.280310の質問の続きになってしまいますが 「VCで作ったdllを使用し VBに文字列を返すことはできますか」 でVCで作ったdllをVBを呼び出す事ができるようになりました。 Declare宣言で疑問に思ったのですが Declare Function TxtCnt Lib "hoge.dll" (ByVal a As String) As Long aはなぜ値渡しなのでしょうか? 変数が書き換えられて戻ってくるので、byrefで指定していました。 それが問題が起こしていた原因一つでした。 ちなみにint型の数値をポインタで渡した場合はbyrefでうまくいきます。 ご教授願います。

  • 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()」の定義が違うのではないか・・・?と思っているのですが、 どの様に宣言したらよい物なのでしょうか? もしくは、そもそも全然違う箇所を間違っているのでしょうか? 宜しくお願いします。 ※ 説明の足りない箇所があれば、仰ってください。

  • 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

  • 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の変換処理を行う必要があるのでしょうか? よろしくお願いします。

  • VB.NET DLL 参照型String読込み

    VCで作成されたDLLの参照型Stringの読込みに困っております。 ご存じの方、お教え下さい。 VB6では次のような定義で、問題なく実行できます。 Private Declare Function VcToVb _ Lib "xxxxxxx.dll" Alias "VcToVb" _ (ByVal Input_DATA As String, ByVal Input_DATA_Cnt As Long, _ ByRef strData As String, ByRef Err_Cnt As Long, ByRef Err_DATA As String) As Long ------------------------------------ Out_Str , Err_Str の領域を確保 iRent = Check_VcToVb1(Input_STR, Input_Cnt, Out_STR, Err_Cnt, Err_STR) これを VB.NETで実施 Private Declare Ansi Function VcToVb _  Lib "xxxxxxx.dll" Alias "VcToVb" _ (ByVal Input_DATA As String, ByVal Input_DATA_Cnt As Int32, _ <MarshalAs(UnmanagedType.LPStr)> ByRef strData As StringBuilder, _ ByRef err_cnt As Int32, ByRef Err_DATA As StringBuilder) As Int32 (テストのため、strDataのみ) -------------------------------------- Out_Str , Err_Str の領域を確保 iRent = Check_VcToVb1(Input_STR, Input_Cnt, Out_STR, Err_Cnt, Err_STR) ******************************************* 調べた結果、VB.NETでは参照型は簡単にはいかないみたいで、StringBuilderを使用するとか、色々な方法を試しました。 結果は戻ってくるのですが、問題は DLLが文字列を返すときに、文字列内の項目区切文字として chr(0)を設定します。 このため、結果は Chr(0)の前までしか設定されません。 (VB.NETが Chr(0)を文字列の最後と判断する?) これを解決する方法はありますでしょうか。 現在は VB6で呼出す DLLを作成し、VB.NETはこれを使用していますが、 C#.Netならできるのでしょうか。 よろしくお願い申し上げます。

  • 関数の引数

    こんにちわ。 ご存知の方、ご教授してもらえないでしょうか? VB.net2005を使っているのですが 関数の引数に変数をセットして、別関数で 引数に対してデータをセットすることは可能でしょうか? C言語でいうところのポインタを引数に渡し ポインタアドレスに書き込むような処理はVB.netでは 可能なんでしょうか? 下記のような事は試したのですが、うまく出来ませんでした(。。; public sub test1() dim mojiretu as string test2( mojiretu ) msgbox(mojiretu) end sub public sub test2( str as string) str = "文字列" end sub

  • ポインターのポインターについて教えてください。

    vb6.0のstring型の配列をvc6.0で作ったdllに渡したいのですが どうすればいいのでしょうか? VB側の宣言で Private Declare Function test Lib "strr.dll" (ByRef a() As String, ByVal b As String) As Long Byrefで渡すとそのアドレスが入ってるらしいですが C側でうけとるときこの場合 char ***aという形でうけとるのでしょうか? 実際***aでうけとると、最初の1文字目はdll側で受け取れます。 ただその場合どのようにしてポインタを動かせばいいのかわかりません。 普通に1文字ずらすのは(**a)++というのでは駄目なのでしょうか? (*a)++でもa++でも コンパイルはできるのですが、実行するとフリーズします。 (***a)++だと当然のごとくアスキーコードの値が1増えるだけでした。 例えば vbのa(0)="abcd",a(1)="efgh"をvcで作ったdllを使ってb="abcdefgh"にする場合どのようにすればいいのでしょうか?

  • VB6からVCで作成したDLLへのvoidポインタの受け渡し

    VB6でVCで作成されたDLLの関数から戻り値としてvoidポインタを受け取り、 それをDLLの別の関数を呼び出す際に引数として渡すプログラムを作成しようとして 詰まっています。以下サンプルです。 ===VB側 Public Type Param   sStr As String   lNum As Long End Type Declare Function Create Lib "test.dll" (ByRef tParam As Param) As Long Declare Function Free Lib "test.dll" (ByVal pSt As Any) As Long Dim pSt As Long Dim lRet As Long Dim tParam As Param With tParam   .sStr = "test" & Chr(0)   .lNum = 10 End With pSt = Conn(tParam) lRet = Free(pSt) ===VC側 typedef struct stParaA {   char * aaa;   char * bbb; } PARAM_A; typedef struct stParaB {   char * ccc;   int iNum; } PARAM_B; extern "C" void * __stdcall Create(PARAM_B* stParaB) {   PARAM_A stParaA;   //stParaAの各メンバ領域をMallocで確保   return((void*)stParaA); } extern "C" int __stdcall Free(void* stParaA) {   //stParaAの各メンバ領域をfree   return 0; //正常終了の場合 } VC側でデバッグしてみたところ、stParaBの各メンバの値はVC側で取得できているので、 DLLの呼び出し自体には問題はないようですが、Create()でreturnする時と、Free()に 入ってきたときではstParaAのアドレスが変わってしまい、異常終了します。 VC側はソースはあるのでデバッグは可能なのですが、DLLの修正自体は不可となって いるため、VB側を直すしかないのですが、どのようにすればアドレスの受け渡しが できるのでしょうか。