3

I'm trying to figure out how to pass a user defined structure from a VB6 application to a C++ DLL.

Here's a sample of my VB6 code :

Private Type ObjetVB  
    Rank As Integer
    Id As String
End Type  

Private Declare Sub testLObj Lib "D:\TestDLL.dll" (Tab_Obj() As ObjetVB)
Private Declare Sub testObj Lib "D:\TestDLL.dll" (ByRef Obj As ObjetVB)

Private Sub Command1_Click()
    Dim elements(1 To 4) As ObjetVB, i As Long

    For i = 1 To 4
        elements(i).Rank = i
        elements(i).Id = "Pouet"
    Next

    testLObj elements()
End Sub

Private Sub Command2_Click()
    Dim ObjCrash As ObjetVB

    ObjCrash.Rank = 1
    ObjCrash.Id = "Pouet"

    testObj ObjCrash

End Sub

And a sample of my C++ code :

struct ObjetVB
{
    short Rank;
    char* Id;
};

void videFichier()
{
    ofstream fichier("../../../log.txt", ios::out | ios::trunc);
    if(fichier)
    {    
        fichier.close();
    }
}    

int Log(ObjetVB ObjInput)  
{
    ofstream fichier("../../../log.txt", ios::out | ios::app);
    if(fichier)
    {
        fichier << ObjInput.Rank << endl << "Id : " << ObjInput.Id << endl << endl;
        fichier.close();
    }
    return 0;
}

void __stdcall testObj (ObjetVB* ObjInput)  
{
    videFichier();
    log(*ObjInput);
}

void __stdcall testLObj (SAFEARRAY **Tab_Obj)
{
    ObjetVB *elt;
    HRESULT ret;
    unsigned long i;
    videFichier();

    if ((ret = SafeArrayAccessData(*Tab_Obj,(void **) &elt))==S_OK)
    {
        for (i = 0; i < (*Tab_Obj)->rgsabound->cElements; i++)
        {
            Log(elt[i]);
        } 
        SafeArrayUnaccessData(*Tab_Obj);
    }
}

My Issue is, when I click "Command2", my log file looks like this :

1  
Id : Pouet  

Whereas, when I click "Command1", it looks like this :

1
Id : P

2
Id : P

3
Id : P

4
Id : P

Why does my C++ DLL recognize "char* Id" as a chain of characters when I pass a single item whereas when I use an array of items it looks like it recognizes it as a pointer to the first character?

And, most notably, how could I fix it? I tried using LBSTR instead of char* in my c++ struct, it didn't fix it, I also tried to add "elements(i).Id = String (255, vbNullChar)" berfore initializing the VB6 strings, but it didn't prove to be helpful either.

As usual, I'd like to thank all of you for the time you put into reading and trying to help.

On a side note : English is a foreign langage to me, so I hope I'm almost understandable and, of course, I apologize if it's not the case.

Edit :

I don't know if it could help, but after trying what Mark Bertenshaw suggested, I also tried this : in VB6 :

Id As String * 10  

in C++ :

char Id[10];  

Which gave this weird result :

Objet : 
32
Id : P

Objet : 
1
Id :  

Objet : 
32
Id : P

Objet : 
2
Id :  
4

2 回答 2

2

这里发生的事情是 VB 正在“提供帮助”,并自动为您将 ID 中的 2 字节 Unicode 字符串 (BSTR) 转换为 1 字节 ANSI 字符串 (char*)。但是,当您将 VB 类型放入数组时,我不完全确定它对字符串做了什么。

一种可能性是 ObjetVB 结构的打包给您带来了问题。尝试像这样定义它:

Private Type ObjetVB
   Id As String        ' 4 bytes
   Rank As Integer     ' 2 bytes
End Type   

struct ObjetVB
{
    char* Id;          // 4 bytes
    short Rank;        // 2 bytes
}
于 2012-06-28T15:23:41.957 回答
2

VB6 返回一个 BSTR 而不是 char 数组。一个 BSTR 将充满宽字符,例如。对于标准罗马字母,我相信 2 字节编码与 ASCII 相同,但第二个字节为 0,因此您的字符串的长度似乎为零。

您可以使用 wchar_t* 而不是 char*,您会发现一切似乎都正常。这不是最好的方法,因为您不能保证 wchar_t 和 BSTR 的大小相同。

最好的办法是使用ConvertBSTRToString函数。

于 2012-06-28T14:13:47.343 回答