[リストへもどる]   [VBレスキュー(花ちゃん)]
一括表示

投稿時間:2006/02/24(Fri) 18:20
投稿者名:gt
URL :
タイトル:
構造体配列転送
お世話になっています、dtです。

VB上で構造体配列をCのDLLへ転送しようと思っていますが、
やり方がわかりません。
VB側:
Public Type SysData_PolygonDfm
        Laye As Integer           ' PolygLaye
        Bcode As Integer          ' PolygBcode
        Type As Integer           ' PolygType
        Name As String            ' PolygName
  End Type
Public SDPolyDfm() As SysData_PolygonDfm

bytC3 = Use_SetDFM_PolyDLL(PolygonDfmAllID, SDPolyDfm(0))

DLL側:
BYTE _stdcall Use_SetDFM_PolyDLL( int PolygonDfmAllID, SysData_PolygonDfm* SDPolyDfm)
{
    for(int j=0; j<PolygonDfmAllID; j++){
        int dd=SDPolyDfm[j].Bcode;
    }

    return (0);
}

コンバイルしてエラーが出ました。

どう対処すればいいでしょうか。
よろしくお願いします.

投稿時間:2006/02/24(Fri) 20:18
投稿者名:neptune
Eメール:
URL :
タイトル:
Re: 構造体配列転送
DLL側のエラーですよね?

VB6ならお手持ちのMSDNで
「[VB5] Visual Basic 5.0 から呼び出し可能な DLL の作成例」
で検索かけてみてください。(MSのサイトのMSDNではヒットしなかった)

そうすると////////以下引用////////
ユーザ定義型 (構造体) の配列の引き渡しの サンプル
Variant 型 および SafeArray を用いて構造体配列の引き渡しを実現します。
///////////////引用終わり////////////
とサンプルが書かれています。
宣言部だけ書くと
__declspec(dllexport) int __stdcall foo(LPSAFEARRAY *ppsa);
です。これでわかると思いますがいかがでしょう?

投稿時間:2006/02/25(Sat) 14:10
投稿者名:gt
URL :
タイトル:
Re^2: 構造体配列転送
neptuneさん:
ご返事ありがとう。

> ユーザ定義型 (構造体) の配列の引き渡しの サンプル
> Variant 型 および SafeArray を用いて構造体配列の引き渡しを実現します。
サンプルを見てうまくできました。
(構造体配列のメンバーを変えて、VBへ戻すということですね。)

一応、DLLに
構造体のメンバー(employee.Name)を確認したいのですが、
以下のように
 wsprintf(bufa, "iemployee.Name:%s", employee.Name);
 MessageBox( hWnd, bufa, "fpAddNumbers3", MB_OK | MB_ICONINFORMATION );
しました。
MessageBoxに表示した文字列が化けています。
どうすればいいでしょうか。

よろしくお願いします。

投稿時間:2006/02/25(Sat) 15:17
投稿者名:Blue
Eメール:
URL :
タイトル:
Re^3: 構造体配列転送
まず、ユーザ定義型の中にString型メンバ変数を使うと、その方はCのほうでは BSTR型(wchar_t*型)に
なります。
通常のchar*ではないので、BSTR型文字列→char*型文字列の変換をしないといけません。

VCであれば、wcstombsで変換できます。
VC以外であれば、WideCharToMultiByte関数を使います。
また C++ でもよければ、 _bstr_tクラスのoperatoer const char* を使うと楽チンです。

投稿時間:2006/02/25(Sat) 17:53
投稿者名:gt
URL :
タイトル:
Re^4: 構造体配列転送
Blueさん
ご返事ありがとう。

> VCであれば、wcstombsで変換できます。
DLL側:
typedef struct {
    short ID;
    BSTR  Name;  
    short flag ;
  }SysData_LAY;

SysData_LAY employee;
i = wcstombs( bufa, employee.Name, MB_CUR_MAX );
 wsprintf(bufa, "iee.Name:%s", employee.Name);  //employee.NameはBSTR  型文字列
ですね?
 MessageBox( hWnd, bufa, "fpAddNumbers3", MB_OK | MB_ICONINFORMATION );
変換の結果は
文字列が化けていないですが、
実際、”iee.Name:iee.Name:”になった。

VB側:
SDLay(j).Nameの初期値は"DRT"です。
SDLay(0).Name="DRT"

どこ間違っているのでしょうか

よろしくお願いします。

投稿時間:2006/02/25(Sat) 18:38
投稿者名:Blue
Eメール:
URL :
タイトル:
Re^5: 構造体配列転送
> i = wcstombs( bufa, employee.Name, MB_CUR_MAX );
> wsprintf(bufa, "iee.Name:%s", employee.Name);  //employee.NameはBSTR 型文字列
おかしくないでしょうか?
bufaを上書きしていますよ。というか、意味ないような。。。

char temp[ 128 ];
char buff[ 128 ];

// 日本語ロケーションを設定
setlocale( LC_ALL, "Japanese" );
// employee.Name は BSTR型文字列なのでchar*型文字列に変換
wcstombs( temp, employee.Name, sizeof( temp ) );
// 変換した文字列を sprintf 関数で格納
sprintf( buff, "iee.Name:%s", temp );
// 表示
MessageBox( hWnd, buff, "fpAddNumbers3", MB_OK | MB_ICONINFORMATION );

それと、
> typedef struct {
>     short ID;
>     BSTR Name;  
>     short flag ;
> }SysData_LAY;
アライメントを考慮しないと、VBの構造体との位置がずれてしまいますよ。
VB側では 4バイト ずつだと思ったので、
typedef struct
{
     short ID;
     short flag;
     BSTR  Name;
} SysData_LAY;
のようにしないといけないような。
# というか、VBでshort型どうやって設定するんだっけ?

色々めんどくさいので、Cとの連携を考えるときは、VBではLong型、Cではint型で扱ったほうが無難です。
(どちらも4バイト)

投稿時間:2006/02/25(Sat) 20:21
投稿者名:neptune
Eメール:
URL :
タイトル:
Re^6: 構造体配列転送
Blueさんが出てきてくれてよかった。私もよく理解できないまま使っているので^ ^;;
前にADO使うのに一度使っただけで忘れてしまってました。

>アライメントを考慮しないと、VBの構造体との位置がずれてしまいますよ。
それは知らなかったです。
> 色々めんどくさいので、Cとの連携を考えるときは、VBではLong型、Cではint型で扱ったほうが無難です。
> (どちらも4バイト)
私はそうしてます。

>// 日本語ロケーションを設定
こういうのもした方が確実なんですね。

投稿時間:2006/02/26(Sun) 10:09
投稿者名:gt
URL :
タイトル:
Re^6: 構造体配列転送
Blueさん
ご回答ありがとう。


> // 日本語ロケーションを設定
> setlocale( LC_ALL, "Japanese" );
setlocale( LC_ALL, "Japanese" );という関数が知らなかった、
これを入れるとうまく表示できました。(他には、参照しながらやっていました)

> アライメントを考慮しないと、VBの構造体との位置がずれてしまいますよ。
> VB側では 4バイト ずつだと思ったので、
> typedef struct
> {
>      short ID;
>      short flag;
>      BSTR  Name;
> } SysData_LAY;
> のようにしないといけないような。
これが知らなかったのですが、
でも、一つ疑問があります、
VB側、文字列のナンバーが複数の場合、(固定長、不定長がある場合)
どう並べるのでしょうか。
この例だと
BSTR  Name;
BSTR  Name2[10];
BSTR  Name3;
BSTR  Name4;
で、
BSTR  Name2[10];
BSTR  Name;
BSTR  BSTR  Name3;
BSTR  Name4;
にするのでしょうか。

> # というか、VBでshort型どうやって設定するんだっけ?
>
VBでshort型   => C側 short型
VBでInteger型 =>  C側 short型
VBでLong型    => C側 Long型
VBでSingle型  => C側 float型
VBでDouble型  => C側 Double型

そうやっていますが、やっぱりいけないですね、バイト数が考えていないです。


> 色々めんどくさいので、Cとの連携を考えるときは、VBではLong型、Cではint型で扱ったほうが無
難で
す。
> (どちらも4バイト)

はい、これからlong型にします。ありがとう。

よろしくお願いします。

投稿時間:2006/02/26(Sun) 13:19
投稿者名:Blue
Eメール:
URL :
タイトル:
Re^7: 構造体配列転送
> VB側、文字列のナンバーが複数の場合、(固定長、不定長がある場合)
固定長メンバがある時のやり方はわかりません。というか普通はやらないような。。。

ちなみに sizeof( BSTR ) は 4 ですから、配列にしても 4 の倍数にしかなりません。
# BSTR a[10]; で sizeof( a ) は 40

> VBでshort型 => C側 short型
本当に Short 型ありますか?私のVB6では As のあとの候補に出てきませんけど。

投稿時間:2006/02/26(Sun) 14:07
投稿者名:gt
URL :
タイトル:
解決
Blueさん
ご返事ありがとう。

> ちなみに sizeof( BSTR ) は 4 ですから、配列にしても 4 の倍数にしかなりません。
> # BSTR a[10]; で sizeof( a ) は 40
>
わかりました。

> > VBでshort型 => C側 short型
> 本当に Short 型ありますか?私のVB6では As のあとの候補に出てきませんけど。
>  
すみませんでした、間違っています。

いろいろ教えていただいて、ほんとにありがとうございました。
neptuneさんもありがとうございました。

投稿時間:2006/02/26(Sun) 14:35
投稿者名:Blue
Eメール:
URL :
タイトル:
Re^8: 構造体配列転送
固定長文字列メンバをC側に渡せるか興味があったので色々と試してみました。
配列で渡す時には Unicode→ANSI文字列 の変換が内部で起こらないので意外と簡単に処理できそうで
す。
# 配列でないものを渡す時は面倒かと。。。(Unicode→ANSI文字列 の変換が内部でおこり文字数とバイ
ト数が違うから)

' VB側
Private Type Product
    Code  As String * 4
    Name  As String
    Stock As Long
End Type

Private Declare Sub Sample16 Lib "vbdll.dll" (ByRef p() As Product)

Private Sub Command16_Click()
    Dim p(3) As Product
    
    With p(0)
        .Code = "A−11"
        .Name = "製品その1"
        .Stock = 20
    End With
    
    With p(1)
        .Code = "B-00"
        .Name = "製品その2"
        .Stock = 100
    End With
    
    With p(2)
        .Code = "C−11"
        .Name = "製品その3"
        .Stock = 10
    End With

    With p(3)
        .Code = "D51"
        .Name = "製品その4"
        .Stock = 0
    End With
    
    Call Sample16(p)
End Sub

// C側
typedef struct tagProduct
{
    wchar_t Code[ 4 ];
    BSTR    Name;
    int     Stock;
} Product;

void WINAPI Sample16( LPSAFEARRAY* args )
{
    wchar_t buff[ 128 ];

    SAFEARRAY* psa = *args;
    long idx, lb, ub;

    Product p;

    SafeArrayLock( psa );
    SafeArrayGetLBound( psa, 1, &lb );
    SafeArrayGetUBound( psa, 1, &ub );

    for ( idx = lb; idx <= ub; idx++ )
    {
        SafeArrayGetElement( psa, &idx, &p );
        /* Unicodeで表示する %.4s がミソ */
        swprintf( buff, L"%.4s,%s,%d", p.Code, p.Name, p.Stock );
        MessageBoxW( NULL, buff, L"Sample16", MB_OK );
    }
    SafeArrayUnlock( psa );
}

投稿時間:2006/02/28(Tue) 09:03
投稿者名:gt
URL :
タイトル:
Re^9: 構造体配列転送
Blueさん
サンプルありがとう。

やってみました。

> ' VB側
> Private Type Product
>     Code  As String * 4
>     Name  As String
>     Stock As Long
> End Type

> // C側
> typedef struct tagProduct
> {
>     wchar_t Code[ 4 ];
>     BSTR    Name;
>     int     Stock;
> } Product;

Code  As String * 4 =>wchar_t Code[ 4 ];で対応していますね、
そういうことが知らなかったのです、勉強になりました。

サンプルをいただいて、ありがとうございました。