Noldor130884
Noldor130884

Reputation: 994

Remove chr(0) from (c++ BSTR) string in VBA

I've written a c++ function in a DLL which exports a string to a VBA program:

BSTR _stdcall myFunc()
{
    CRegKey Key;
    CString sValue;
    BSTR Str;

    LONG nA = Key.Open(HKEY_LOCAL_MACHINE, _T("[group path goes here]"), KEY_READ);
    ULONG nValueLength = 0;
    LONG nB = Key.QueryStringValue(_T("[key I want to read goes here]"), NULL, &nValueLength);

    if (nValueLength > 0)
    {
        LONG nC = Key.QueryStringValue(_T("[key I want to read goes here]"), sValue.GetBufferSetLength(nValueLength - 1), &nValueLength);
    }

    Str = _bstr_t(sValue.AllocSysString(), false);

    return Str;

Now Str is something like a version number: let's say "4.10.122".
If I call the function from VBA, I receive instead "4 . 1 0 . 1 2 2", where the "spaces" between each characters are NULL (in VBA they are Chr(0)).

I don't like the idea of having to use the Replace function in my VBA code, so is there any way I can include that step in my c++ code?

EDIT: below the code I'm using to call the function in VBA:

Private Declare Function myFunc Lib "[Path of my DLL here]" () As String

Sub Return_string()

Dim a As String

a = myFunc()

End Sub

Upvotes: 0

Views: 872

Answers (2)

Aurora
Aurora

Reputation: 1354

The problem stems from the Declare statement. When interacting with such functions and strings in particular, VBA will always perform an implicit ANSI to Unicode conversion in both directions. In your case, VBA expects an ANSI string as the return value, which it can then expand into a Unicode equivalent.

To deal with this, you'll have to return an ANSI string and resort to SysAllocStringByteLen:

CStringA sValueA(sValue);
Str = SysAllocStringByteLen(sValueA.GetBuffer(), sValueA.GetLength());

As an alternative, you may also embed a type library inside your DLL. This would omit the automatic string conversion.

Upvotes: 1

rfb
rfb

Reputation: 1167

Far from being able to help you with this specific need but curious about the subject, if i were to come up with a solution i would start from this answer https://stackoverflow.com/a/43423527/781933

Update

According to the above mentioned @SimonMourier detailed answer, and further readings, you should consider string content encodings. The context of the DLL - VBA marshalling is to be considered and depends also on VBA function declaration (stated by @HansPassant).

From this MSDN documentation:

  • When a VBA user-defined function is declared as taking a String argument, Excel converts the supplied string to a byte-string in a locale-specific way.
  • If you want your function to be passed a Unicode string, your VBA user-defined function should accept a Variant instead of a String argument.

So if you use:

Private Declare Function myFunc Lib "[Path of my DLL here]" () As String

conversion from UNICODE to ANSI is needed via StrConv

Dim str As String

str = StrConv(myFunc(), vbFromUnicode)

Otherwise you should get rid of StrConv but using DLL exported BSTR with this declaration:

Private Declare Function myFunc Lib "[Path of my DLL here]" () As Variant

Upvotes: 1

Related Questions