Kris_R
Kris_R

Reputation: 2838

C++ dll for VBA - problem with reading/encoding strings

I need to read entries from old-fashioned INI-file with a DLL and after some manipulation export them to VBA code.

The c++ code for the function looks like this:

BSTR __stdcall GetSectionEntry(LPCSTR  sSection, LPCSTR  sEntry)
{
    LPCTSTR gszINIfilename = "C:\\test\\test.ini";
    TCHAR localStr[64];
    
    GetFileAttributes(gszINIfilename);
    if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(gszINIfilename) && GetLastError() == ERROR_FILE_NOT_FOUND) {
        bstr_t bstrt = "";
        return bstrt;
    } else {
        GetPrivateProfileStringA(sSection, sEntry, "", localStr, sizeof(localStr), gszINIfilename);
        //_bstr_t bstrt(localStr);
        CComBSTR bstrt(localStr);
        return bstrt;
    }
}

The VBA (Word 2016):

Declare PtrSafe Function GetSectionEntry Lib "test.dll" (ByVal sSection As String, ByVal sEntry As String) As String

For i = 0 To 5
    Debug.Print ("Name = " & StrConv(GetSectionEntry("Name", CStr(i)), vbFromUnicode))
Next i

End finally the INI-file:

[Name]
0=123456789012345678901234567
1=1234567890123456789012345678
2=1234567890123456789012345678901234567890123456789012345678901
3=12345678901234567890123456789012345678901234567890123456789012

I compiled the DLL using VS2019 with either "Character Set" set to "Not Set" or to "Use Multi-Byte Character Set".

Debugging in VS shows that the strings are properly formatted (for example for 1 it's L"1234567890123456789012345678"). I tested it with different sizes of localStr (64..1024). I tried bstr_t and CComBSTR and a few more. In all cases print.debug in VBA shows following result:

Name = 123456789012345678901234567
Name = ??????????????  ????????????
Name = ??????????????????????????????1 ?? ??????????????yu ?  rg|A ?
Name = 12345678901234567890123456789012345678901234567890123456789012

Any string that is longer than 27 and shorter than 62 characters is not properly encoded. When I checked them without StrConv(string, vbFromUnicode) they were missing all even null-characters. For that reason they are then encoded as some Asian characters:

enter image description here

The same happens for string that are 13--14 character long:

enter image description here

I'm very sure that I'm doing something trivial and stupid but I never had to write any C/C++ for windows. I would be grateful if anyone could point my mistake and correct me.

Upvotes: 0

Views: 176

Answers (1)

    CComBSTR bstrt(localStr);
    return bstrt;

This return statement converts the CComBSTR to a BSTR, and returns that, and then destroys the CComBSTR since it's no longer in scope. When the CComBSTR object is destroyed the string is freed.

Try return bstrt.Detach(); which detaches the string from the CComBSTR object so it won't be freed by the destructor.

After you return it, the string "belongs" to VBA and it's VBA's job to free it, which I assume it does automatically.

Upvotes: 1

Related Questions