从 VBA 中的 (c++ BSTR) 字符串中删除 chr(0)

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

我在 DLL 中编写了一个 C++ 函数,它将字符串导出到 VBA 程序:

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;

现在 Str 类似于版本号:比方说“4.10.122”。
如果我从 VBA 调用该函数,我收到的是“4 . 1 0 . 1 2 2”,其中每个字符之间的 "spaces" 是 NULL(在 VBA 中它们是 Chr(0)).

我不喜欢在我的 VBA 代码中使用 Replace 函数的想法,那么有什么办法可以在我的 C++ 代码中包含该步骤吗?

编辑:在我用来调用 VBA 中的函数的代码下方:

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

Sub Return_string()

Dim a As String

a = myFunc()

End Sub

远远不能帮助您解决这个特定需求,但对这个主题很好奇,如果我想出一个解决方案,我会从这个答案开始

更新

根据上面提到的@SimonMourier 的详细回答和进一步的阅读,你应该考虑字符串内容编码。 DLL 的上下文 - VBA 编组要考虑并且还取决于 VBA 函数声明(由@HansPassant 声明)。

来自this MSDN documentation

  • 当 VBA 用户定义函数被声明为采用字符串参数时,Excel 以特定于语言环境的方式将提供的字符串转换为字节字符串。
  • 如果您希望向您的函数传递 Unicode 字符串,您的 VBA 用户定义函数应该接受 Variant 而不是 String 参数。

所以如果你使用:

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

需要通过 StrConv

从 UNICODE 转换为 ANSI
Dim str As String

str = StrConv(myFunc(), vbFromUnicode)

否则你应该摆脱 StrConv 但使用 DLL 导出 BSTR 与此声明:

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

问题源于Declare语句。特别是与此类函数和字符串交互时,VBA 将始终在两个方向上执行隐式 ANSI 到 Unicode 转换。在您的情况下,VBA 需要一个 ANSI 字符串作为 return 值,然后它可以扩展为 Unicode 等价物。

要解决这个问题,您必须 return 一个 ANSI 字符串并求助于 SysAllocStringByteLen:

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

作为替代方案,您也可以在 DLL 中嵌入类型库。这将省略自动字符串转换。