• ベストアンサー

VCのDLL内でmallocした構造体をVBで使用

題名通りですが、 VC側のDLLにてmallocで構造体の領域を確保しています。 この領域をVB側で使用したいのですが、やり方がわかりません。 イメージは Public Declare Function GetData Lib "xxx.dll" (ByRef datas As KOUZOUTAI, ByRef dataCnt As Long) As Boolean みたいな形で、datasに構造体のデータ、及び dataCntに領域確保したデータ数を取得出来ればなと思っております。 VB側では、これもイメージですが、 dim datas() as KOUZOUTAI dim dataCnt as long GetData(datas, dataCnt) for cnt=0 to dataCnt - 1 msgbox datas(cnt).a msgbox datas(cnt).b msgbox datas(cnt).c next みたいな感じで処理をしたいと思っております。 お聞きしたい事は 1)そもそも可能なのか? 2)declare宣言のdatasのところが???です。 3)dim datas() as KOUZOUTAIのところも宣言が???です。 4)datas(cnt).a等としているところも配列?として処理出来るのかが???です。 以上、よろしくお願いします。

  • Vargas
  • お礼率85% (174/204)

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

  • ベストアンサー
  • nda23
  • ベストアンサー率54% (777/1415)
回答No.3

>1)そもそも可能なのか? VC側でVB配列を扱える人が作ったDLLなんでしょうか? できるようならmallocは使わずSafeArray系APIを使うと思います。 最低でもVB側で解放できるようにGlobalAllocを使うはずです。 無理すれば可能だとは思いますが、一時的に成功してもガベージ コレクションが起きた後で動作が不安定になるでしょう。 >2)declare宣言のdatasのところが???です。 VC側で SAFEARRAY **datas となっていれば datas() As KOUZOUTAIと なります。そうすると、mallocではなく、SafeArrayCreateで確保 された領域のポインタが入らなくてはなりません。 VC側が struct xxx *p となっているならdatas As KOUZOUTAIです。 >3)dim datas() as KOUZOUTAIのところも宣言が???です。 Declarationの所では配列要素数を省略した定義は可能です。 後でReDim文で配列領域を確保します。配列要素数を定義すると 固定配列になるので、VC側でメモリを削除したり、確保したり できません。 >4)datas(cnt).a等としているところも配列?として処理出来るのかが???です。 構造体の配列は使用可能です。書式も合っています。 どうしてもVC側で作ったものを使いたいならGlobalAllocでメモリを 確保し、これを戻り値(Long型)とします。VB側では必要な領域を 確保した後、RtlMoveMemoryで内容をコピーして使えば良いでしょう。 尚、VBの変数のポインタはVarPtr関数で求められます。

Vargas
質問者

補足

詳細な回答ありがとうございます。 3)がちょっと気になります。 dim datas() as KOUZOUTAI という宣言がOKなのはわかるのですが、 このあと、redimをしなければならないというところが引っ掛かります。 VC側でHeapAllocでメモリ確保しているのですが、その先頭ポインタ(この考えはVBには無いとは思いますが。)をVB側で受け取っているのに、更に、redimしなければならないのでしょうか? もしかしたら、VB側ではRtlMoveMemoryで上記redimした領域にコピーを行った上で使用しなければならないという意味でしょうか? であれば納得です。 以上、再度、ご回答頂けると幸いです。

その他の回答 (3)

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.4

VBの配列は複雑な管理になっており、先頭ポインタに構造体サイズを 加えれば次の要素のポインタになると言うものではありません。 先ず、管理情報として定義済み(Eraseされていない)フラグが あります。ReDimしていないとこれがFalseですし、LBound、Uboundの 定義も未設定になっています。当然、データ用の領域もありません。 VC側のHeapAllocで取得した領域に上記のような管理情報とデータを 仕込み、更にVB側のメモリ管理に登録する方法をご存知ならば、 何も申し上げることはございません。ReDimするしないも自由です。

Vargas
質問者

お礼

3度にわたるご回答、大変感謝しております。 VB6はそれなりにやってきたつもりでしたが、 今回は全く知らなかった事ばかりで知識が増えました。 ありがとうございました。

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.2

VBはVB6.0(VBA含む)とVB.NET以降では全く別物です。 どちらのバージョンを使用するのか記載しないと適切なアドバイスは 受けられません。使用する環境を記載してください。

Vargas
質問者

補足

すいません。ソースイメージを記述したので、自ずとVB.NETではないと捉えてくれるかなと思いました。VB6.0です。よろしくお願いします。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

その構造体の内容(メンバー)を提示しましょう たとえば struct tagData{   int a;   short b;   byte c; }; といった構造体なら VB6以前であれば Type tagData   dim a as Long   dim b as Integer   dim c as Byte End type といった具合になります 構造体の配列となると SafeArrayタイプでC++側でデータを構築しないとうまくわたらなかったりしますよ VC付属のMSDNで Visual Basic 5.0 から呼び出し可能な DLL の作成例 取った題目のサポート技術を参照してみましょう

参考URL:
http://support.microsoft.com/kb/410837/ja
Vargas
質問者

お礼

この記事は大変助かりました。ありがとうございました。

Vargas
質問者

補足

このURL大変参考になりました。ありがとうございます。 ところで、当方の環境はVB6なのですが、VB6用のこの様な記事が見当たりません。VB5と同じと考えていいんですよね。

関連するQ&A

  • 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ならできるのでしょうか。 よろしくお願い申し上げます。

  • 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でうまくいきます。 ご教授願います。

  • 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

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

  • VB2005 から DLL を呼び出す

    VB 初心者です。 今、VB の練習ということで VB 2005 Express Edition を使って、個人用ブラウザをつくっています。Web ページの表示は Webbrowser コンポーネントを使っています。 その仕様で、閲覧先によって HTTP Proxy を変更するようになっています。(自分で決めたんですが) いろいろ調べてみると、urlmon.dll の UrlMkSetSessionOption() を呼べば自分のアプリケーション限定で Proxy を変更できるようだ、ということがわかりました。 古い VB など(VB 6 とか?)では、 Private Declare Sub UrlMkSetSessionOption Lib "urlmon.dll" _ (ByVal dwOption As Long, ByVal pBuffer As Any, _ ByVal dwBufferLength As Long, _ ByVal dwReserved As Long) このような感じで宣言するとかあったんですが、VB2005 では Any がダメだとか、 Type INTERNET_PROXY_INFO Dim dwAccessType As Long Dim lpszProxy As String Dim lpszProxyBypass As String End Type で Type はダメだとか、呼び出し側で、LenB を使おうとしたら使えないだとか、INTERNET_OPTION_PROXY の値がわからないなど、問題が山積みです。 上記 DLL を VB 2005 で使ったことがある人がいたら(またはわかる人)、使い方を教えてもらえないでしょうか?

  • 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) どうぞ宜しくお願い致します。

  • VCのDLLを呼ぶ場合の宣言方法

    VB.NetからVC++で作成したDLLを使用する場合の宣言方法について教えてください。 VC++のDLLの関数で引数に構造体のポインタを渡すようになっているのですがマーシャリング属性の指定方法がわからなく困っています。 VB6.0では使用できたのでDLL側は問題ないと思うので(DLL側は修正ししないでVB側の修正で対応したいです)VB.Net側の問題だと思うのですがどこを直したらいいのかご教授願えないでしょうか。 以下にVC++のDLLの宣言部、VB6.0のときのソース、VB.Netのソースの必要と思われる部分を載せておきます。 ただしVB.NetのソースはVB6.0からUpGradeしたものをWeb等で調べて修正したものです。 当方VBに関してはまだ触り始めて1ヶ月も経っていないのですが仕事で急ぎで対応しなくてはならないため勉強する時間がなくどうすればいいか困っています。 よろしくお願いします。 ### VC++側ソース(概略) void __stdcall GetData( STESTDATA* pData ) struct STESTDATA { float fData1[6]; float fData2[32][6]; }; ### VB6.0の時のソース Private Type testdata Data1(5) As Single Data2(5, 31) As Single End Type Private Declare Sub GetData Lib "TestLib.dll" (ByRef pData As testdata) Private Sub TimerGetData_Timer() Dim data As testdata GetData data End sub ### VB.Net(2008)の時のソース <StructLayout(LayoutKind.Sequential)> _ Private Structure testdata <MarshalAs(UnmanagedType.ByValArray)> Dim Data1() As Single <MarshalAs(UnmanagedType.ByValArray)> Dim Data2(,) As Single Public Sub Initialize() ReDim Data1(5) ReDim Data2(5, 31) End Sub End Structure <System.Runtime.InteropServices.DllImport("TestLib")> _ Private Shared Sub GetData(ByVal pData As testdata) End Sub Private Sub TimerGetData_Tick(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles TimerGetData.Tick Dim data As testdata data.data1 = New Single(5) {} data.data2 = New Single(5, 31) {} data.Initialize() GetData(data) End Sub ※因みにVB.Netのソースを実行すると本来ならdata構造体のdata1とdata2に値にDLL内で値が設定されるのですが、現状では全て0が設定されてしまっています。

  • 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

  • 構造体配列を引数とするDLL作成し、VBで呼ぶには?

    はじめまして。 VisualC++6.0でDLLを作り、VisualBasic6.0にて VisualC++の関数をコールし、構造体配列の値を 渡そうとしていますがうまくいきません。 どなたかよい知恵をお貸しください。 宜しくお願い致します。 下記に、VisualC++6.0とVisualBasic6.0のやりとり を記します。 *====Visual C++ 6.0側===== typedef struct _DLP_MSGDATA { int flg; char msg[504]; int tmp; } DLP_MSGDATA; _declspec(dllexport) int _stdcall SampSub(int data, DLP_MSGDATA *mdata) { return( 0 ); } *====Visual Basic 5.0側===== Declare Function SampSub Lib "test.dll" Alias "_SampSub@8" _ ( _ ByVal tlp_id As Long, _ ByRef mdata() As DLP_TLP_MSGDATA _ ) As Long Type DLP_TLP_MSGDATA flg As Long msg As String * 504 tmp As Long End Type Private Sub test() Dim mdata(0 To 130) As DLP_TLP_MSGDATA Dim aa As Long Call SampSub( aa, mdata ) End sub

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

専門家に質問してみよう