• 締切済み

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側を直すしかないのですが、どのようにすればアドレスの受け渡しが できるのでしょうか。

みんなの回答

  • dsuekichi
  • ベストアンサー率64% (171/265)
回答No.1

気になったところを2つほど・・・ (1)「Free 」の宣言で「ByVal pSt As Any」としてますが、 「ByVal pSt As Long」の方が良いのでは? (2)「DLLの修正自体は不可」との事ですが・・・ C側の「PARAM_A stParaA;」って、ローカル変数ですよね・・・ 私の認識では、ローカル関数は関数が終了すると、解放されてしまう・・・ #Mallocした領域は残りますが、Mallocした領域がどこかを記録している、 #stParaAは解放されてしまって、別の用途に使われてしまうかも。 もし正しいアドレスが渡されたとしても、コレでは駄目(でたらめな値になっていて、異常終了する)なのでは?

mamaremon
質問者

補足

>C側の「PARAM_A stParaA;」って、ローカル変数ですよね・・・ >私の認識では、ローカル関数は関数が終了すると、解放されてしまう・・・ えっと、stParaAは変数ですが、(void*)stParaAは変数ではなく、ポインタであるというのは分かりますでしょうか。変数≠ポインタです。変数を渡したいわけではなく、Mallocで確保した領域のアドレスそのもの(ポインタ)を渡そうとしているのが、サンプルコードなのですが、ご理解いただけますでしょうか。ポインタというのはメモリ上のアドレス(位置情報)のことなので、そのメモリの領域が解放されようとも、ポインタそのものがなくなることはありません。 結論からいうと、私の意図した動作はサンプルコードで動くようです。お騒がせしました。異常終了したのはまた別の要因でしたが、割愛させていただきます。

関連するQ&A

  • VC6.0で作成したDLLでVBからの配列を受け取る方法

    VC++でDLLを作成しています。 VBから呼び出しで、配列を渡し、その配列の値を VCで使用したいのです。 通常変数でテストして、うまくいっているのですが、 配列に変更したところ、値がうまく渡りません。 どなたかお分かりになられる方いらっしゃいましたら お力をお貸し願えないでしょうか? 変数で成功しているプログラム VB6.0 標準モジュール Declare Function fncTest Lib "fncTest.dll" (a As Long) As Long フォーム Private Sub Test_Click() dim i as integer i = fncTest(1) End Sub VC++6.0 fncTest.h fncTest_API int _stdcall fncTest(int); fncTest.cpp fncTest_API int _stdcall fncTest(int a) { a = a+1; return a; } fncTest.def     省略 変数aを配列に変更して作ってみたもの(配列bにVBからの配列aの値を入れようとしていますが、 うまくいっていません。) VB6.0 標準モジュール Declare Function fncTest Lib "fncTest.dll" (ByRef a() As Long) As Long フォーム Private Sub Test_Click() Dim i As Integer Dim hairetu(7) As Long Dim values As Variant For i = 0 To 7 hairetu(i) = i Next i values = fncTest(hairetu()) End Sub VC++6.0 fncTest.h fncTest_API int _stdcall fncTest(int*); fncTest.cpp fncTest_API int _stdcall fncTest(int* a) { int b[7]; int i; for (i = 0;i <= 7;i++){ b[i] = a[i]; } return 0; } 以上よろしくお願いします。

  • VC++で作成したDLLをVBから呼ぶと戻り値が化けてしまう

    はじめまして。いつも勉強させていただいております。 VCは今回初めてやっておりますので当たり前の質問 になってしまうかもしれませんがご教授願います。 以下のような仕様でものづくりを行っております。 1.VBよりVC++で作成したDLLを呼び出す。 2.VC++で作成したDLL側ではパラメータより取得した   値を元に足し算をした結果を   戻り値にセットして要求元に返却する。 といった流れで考えています。 2の部分についてはExeを一度作成し実行させた ところDOS窓に値が表示されました。(printfで) しかし、正しくOUTPUTされた値がVB側の戻り値と して返却された時点で参照すると「-6348」 となっています。 なぜこうなってしまうのか原因がわからず投稿 させて頂きました。 ご存知の方、ご教授下さい。 ************************************************* VC++ DLL側のソース ************************************************* #include <windows.h> #define DLL_EXPORT __declspec(dllexport) extern "C" { DLL_EXPORT int add(int a,int b); } int add(int a,int b) { return a+b; } ************************************************* VB  DLL呼び出し元 ************************************************* Option Explicit Private Declare Function add Lib "C:\Program Files\Microsoft Visual Studio\test\Debug\test.dll" Alias "_add@8" (a As Long, b As Long) As Integer Private Sub Command1_Click() Dim ret As Long ret = add(1, 2) MsgBox ret End Sub 環境 OS:WinXP 言語:VC++6.0    VB6.0(SP6)

  • VBからのDLL呼び出しでエラー発生

    お世話になります。 Cで作成したDLLをVB6から呼び出した時にエラーが発生します。エラー内容は「実行時エラー'49'DLLが正しく呼び出せません。」です。 いろいろ試してみると、DLL側にパラメータを指定した場合にエラーが発生しているということが分かったのですが、対処方法は分かりませんでした。 以下にソース内容を記述致しますので、何処が悪いのかをご指摘頂けませんでしょうか。 <DLL側(aaa.dll)> __declspec(dllexport) int MyFunction1() { return 4; } __declspec(dllexport) int MyFunction2(int x) { return x * 2; } <VB側> 共通.bas Public Declare Function MyFunction1 Lib "aaa.dll" () As Long Public Declare Function MyFunction2 Lib "aaa.dll" (ByVal a As Long) As Long 実際の使用箇所 Dim param As Long Dim returnCode As Long MsgBox MyFunction1() param = 3 MsgBox MyFunction2(param) どうぞ宜しくお願い致します。

  • VB2005でVC6.0で作成したDLLから値を取得するには

    VB6からVB2005にコンバートをしたのですがVCで作成したDLLの関数の箇所で下記エラーが出てしまいました。(VCのDLLは他で使用の為変更できず。) エラー内容 「保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。」 いろいろサイト等を調べたのですがうまくいきません。 Marshal.AllocCoTaskMem、Marshal.Copyなどを使用すればできるらしいのですが難しすぎて挫折しました。。 どなたかご教授下さい。 よろしくお願い致します。 VC側ソース(XXX.DLL) GetData( unsigned char far *pRec,   //データ short int *pRecLen,  //サイズ { Char cbBuf[1024]; //バッファ memset(cbBuf, ' ', 1024); //初期化 Call GetBuf(cbBuf); memcpy(pRec, cbBuf, *pRecLen); return(0) ; } VB2005のソース <StructLayout(LayoutKind.Sequential)> Structure St Dim A () As Byte Dim B () As Byte End Structure Declare Function GetData Lib "XXX.DLL" (Byref RecData As St , ByRef Reclen As Short) As Short Sub Dim TmpData As St Dim TmpLen As short =100 Dim X As Byte Dim Y As Byte Redim TmpData.A(49) Redim TmpData.B(49) Call GetData(TmpData, TmpLen) X =TmpData.A(0) Y =TmpData.B(1) ・ ・ End Sub

  • 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"; }

  • 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

  • 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側に渡したいのです。 よろしくお願いします。

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

  • VCで作ったDLL【否 .Net】 配列

    VCでDLLを作り、VBから呼び出しています。 今やりたいのは、Cで言えば void Calc(int a, int b, int x[]) {  x[0] = a + b;  x[1] = a - b;  x[2] = a * b; } int main(int argc, char *argv[]) {  int n[3];  Calc(8,1,n);  printf("%d %d %d\n",n[0],n[1],n[2]);  return 0; } と、いうことです。 関数Calcを__stdcallやdefファイルを使って呼び出せるようにし、VBから呼ぶのですが、うまくいきません(~~メモリが"written"になることは~~)。 VBでは Declare Sub Calc Lib "SimpleDll.dll" (ByVal a As Long, ByVal b As Long, ByRef x() As Long) …略… Dim x(3) As Long Call Calc(6, 4, x) …略… としています。 どうかお力添えを。

  • VB.netでのVC++呼び出し引数の順番

    VC++で作成されたDLLをVB.NetにてそのDLLを呼び出すアプリを作成して います。以下のパターン2では問題なく動作しますが、パターン1では DLL側で見たときにchar変数に正しく値が入りません(NULL)になる。 パターン1とパターン2の違いは引数の順番です。 開発環境:VisualStudio2008 OS:WindowsXP SP2 パターン1(この場合はNG)  VC++側の宣言   extern "C" __declspec(dllexport) void func1(int i,char*s)  VB.Net側の宣言   <System.Runtime.InteropServices.DllImport("func.dll")> _   Public Sub func1(ByVal i As Long, ByVal s As String)   End Sub パターン2(この場合はOK)  VC++側の宣言   extern "C" __declspec(dllexport) void func1(char*s,int i)  VB.Net側の宣言   <System.Runtime.InteropServices.DllImport("func.dll")> _   Public Sub func1(ByVal s As String ,ByVal i As Long)   End Sub VC++側がパターン1で作成さているため、VC++側を修正をしないで 正常に動かすことは可能でしょうか? よろしくお願いします。

専門家に質問してみよう