C++Builderで作成したDLLからVBアプリのコールバック(引数に構造体の配列を含む)を呼ぶには


ああ  2005-09-09 01:23:59  No: 125039

C++Builderで作成したDLLからVBアプリのコールバック関数を呼びます。
その際、VBアプリのコールバック関数の引数にDLLと同じ構造体の配列の
ポインタを渡しているのですが、VBアプリで値が取得できません。

どのようにすれば値が取得できるのか教えてください。

[開発環境]
VB6
[標準モジュール]
Public Declare Function AAA Lib "AAA.dll" (ByVal Callback As Any) As Long

[コールバック関数]
Sub Callback(ByRef b() As TAMESI)

    Dim a As TAMESI
    Dim i As Integer
    
    For i = 0 To 1
        a.kekka = b(i).kekka
        a.waruatai = b(i).waruatai
        Main.List1.AddItem ("KEKKA = " + CStr(a.kekka))
        Main.List1.AddItem ("WARUATAI = " + CStr(a.waruatai))
    Next
End Sub

[コールバック関数設定]
 Private Sub OKButton_Click()
     Dim ReturnValue As Long
     ReturnValue = AAA(AddressOf Callback)
End Sub

[Cでの構造体宣言]
typedef struct TAMESI {
      long kekka;
      long waruatai;
}TAMESI;

[VBでの構造体宣言]
Public Type TAMESI
      kekka As Long
      waruatai As Long
End Type


K.J.K.  2005-09-09 03:47:15  No: 125040

C++Builderにおける、関数及びコールバックの定義は
どうなっているのでしょうか?
# というか、これらを隠して情報が得られるはずはないでしょう。


Blue  2005-09-09 09:34:40  No: 125041

> Sub Callback(ByRef b() As TAMESI)
となっているので、DLL内で TAMESI の配列をつくっているのでしょうか?

おそらく、DLL内の記述に問題があると思われます。
# SAFEARRAYとして扱い、SafeArrayCreate関数等を使わないとまともに動かないかと。


Blue  2005-09-09 10:33:29  No: 125042

いろいろ調べてみましたが、
SafeArrayCreate関数では、自前のstructを設定できないらしいです。
http://search.acty-net.ne.jp/mfc_search/archive/2004-1/msg00901.html
VARTYPEに設定できる型の配列は可能。(文字列、数値等)

# ここまでくると完全にCの話です罠。

> Sub Callback(ByRef b() As TAMESI)
だったら、配列渡すんじゃなくて、DLL側で配列分ループまわせばいいと思うのですが。


Blue  2005-09-09 10:51:30  No: 125043

リンク先がずれていました。
ここ↓がスレの先頭。
http://search.acty-net.ne.jp/mfc_search/archive/2004-1/msg00900.html


ああ  2005-09-10 05:19:40  No: 125044

そうですか、難しいのですね。
それでは、

[Cでの構造体宣言]
typedef struct TAMESI {
      long kekka;
      long waruatai;
}TAMESI;

typedef struct PPP {
      TAMESI tamesi[5];
}PPP;

として、C側は
void (CALLBACK *lpCallback)(PPP*);
とすれば、

[VBでの構造体宣言]
type TAMESI {
      kekka as long;
      waruatai as long;
}TAMESI;

typedef struct PPP {
      tamesi(6) as TAMESI;
}PPP;

[VBコールバック関数]
Sub Callback(ByRef b() As PPP)

    Dim a As TAMESI
    Dim i As Integer
    
    For i = 0 To 6
        a.kekka = b(i).kekka
        a.waruatai = b(i).waruatai
        Main.List1.AddItem ("KEKKA = " + CStr(a.kekka))
        Main.List1.AddItem ("WARUATAI = " + CStr(a.waruatai))
    Next
End Sub

のように、構造体の配列を持った構造体というやり方はVBでは
ゆるされているのでしょうか。


Blue  2005-09-10 06:51:42  No: 125045

先にも書いたと思いますが、
C側でVBが扱える構造体の配列をつくることが出来ないらしいので、
> Sub Callback(ByRef b() As PPP)
というのはムリです。

あらかじめ、VB側で領域を確保した構造体を渡して、C側で設定するのは可能です。

Private Sub OKButton_Click()
     Dim ReturnValue As Long
     Dim p           As PPP
     ReturnValue = AAA(AddressOf(Callback),p)
End Sub

みたいに。

それと、これは基本的にVB側の問題ではないので
VBのコードばかり書かれても、解決しません。

Cで書かれたDLLの関数の定義を書いてくださいね。


Blue  2005-09-10 06:56:07  No: 125046

というか Cの知識が乏しいようですが。

>typedef struct PPP {
>      TAMESI tamesi[5];
>}PPP;
typedef の構造体名と別名が同じなのは出来ないはずですが。(PPPが同じ)
>For i = 0 To 6
tamesi[ 5 ]と配列を宣言したら 0〜4までの配列になります。(要素数が5)

> void (CALLBACK *lpCallback)(PPP*);
DLLでexprotできるように書いてくださいね。
(この宣言の仕方ではどこからも使えないはず。)


Blue  2005-09-10 07:59:18  No: 125047

> typedef の構造体名と別名が同じなのは出来ないはずですが。(PPPが同じ)
ごめんなさい、出来ました。でも普通はこのような書き方はしないはずですが。
# 書くならば無名構造体にするのかな。


Blue  2005-09-10 11:33:36  No: 125048

> 先にも書いたと思いますが、
> C側でVBが扱える構造体の配列をつくることが出来ないらしいので、
> > Sub Callback(ByRef b() As PPP)
> というのはムリです。
前言撤回させてください。

調べ方が悪かったらしく、SafeArrayCreate関数ではなく、
SafeArrayAllocDescriptor,SafeArrayAllocDataを使えば設定できました。

以下サンプルソース
/* C側ソース(VC6で作成) */
#include <windows.h>

extern "C"
{
#endif

typedef struct
{
    long int kekka;
    long int waruatai;
} TAMESI;

__declspec( dllexport ) HRESULT WINAPI AttachEventProc( void ( CALLBACK *lpCallback )( LPSAFEARRAY* ) )
{
    TAMESI     tElement;
    SAFEARRAY* psaRelation;
    long int   index;

    static const int  size = 5;
    
    if ( FAILED( SafeArrayAllocDescriptor( 1, &psaRelation ) ) )
    {
        return E_UNEXPECTED;
    }

    /* 要素のサイズを設定 */
    psaRelation->cbElements = sizeof( TAMESI );
    psaRelation->fFeatures  = FADF_STATIC;
    /* 配列のサイズを設定 */
    psaRelation->rgsabound[ 0 ].cElements = size;
    psaRelation->rgsabound[ 0 ].lLbound   = 0;

    if ( FAILED( SafeArrayAllocData( psaRelation ) ) )
    {
        SafeArrayDestroyDescriptor( psaRelation );
        return E_UNEXPECTED;
    }

    /* 配列に設定 */
    SafeArrayLock( psaRelation );   
    for ( index = 0; index < size; ++index )
    {
        tElement.waruatai = index + 1;
        tElement.kekka    = 100 / ( index + 1 );

        SafeArrayPutElement( psaRelation, &index, &tElement );
    }
    SafeArrayUnlock( psaRelation );

    /* コールバック関数の呼び出し */
    ( *lpCallback )( &psaRelation );

    /* 配列の削除 */
    SafeArrayDestroyData( psaRelation );
    SafeArrayDestroyDescriptor( psaRelation );

    return S_OK;
}

#ifdef __cplusplus
}
#endif

' VB側Declare宣言文
Public Declare Function AttachEventProc Lib "test.dll" (ByVal func As Any) As Long


※返信する前に利用規約をご確認ください。




  


  このエントリーをはてなブックマークに追加