【问题标题】:Remove chr(0) from (c++ BSTR) string in VBA从 VBA 中的 (c++ BSTR) 字符串中删除 chr(0)
【发布时间】:2017-05-08 06:36:00
【问题描述】:

我在 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”,其中每个字符之间的“空格”是 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

【问题讨论】:

  • 这对于 utf-16 编码的字符串是正常的,因为 BSTR 应该是。似乎您没有在 VBA 代码中正确声明该函数。当心这个错误,_bstr_t 包装器在函数返回之前调用 SysFreeString()。完全摆脱它,SysAllocString就足够了。
  • 感谢您指出错误。我刚刚写了如何从 VBA 调用该函数,但即使您对 _bstr_t 进行了更正,它也会返回包含 Chr(0)s 的相同字符串。
  • 我不知道 VBA 需要什么样的咒语来确保它期望 BSTR 函数返回,我只看到参数类型的文档。声明函数 Unicode 可能会有所帮助,但是通过调用它来测试它无数次,这样你就知道没有内存泄漏。
  • 基本上还有其他方法可以将CString 导出到VBA 吗?这是我发现的唯一可行的...

标签: c++ string vba char bstr


【解决方案1】:

远不能帮助你解决这个特定的需求,但对这个主题很好奇,如果我想出一个解决方案,我会从这个答案开始https://stackoverflow.com/a/43423527/781933

更新

根据上面提到的@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

【讨论】:

  • 我在创建函数时读过这个问题,但我仍然没有找到一种简单的方法来简化我的字符串导出...
  • 这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方留下评论。 - From Review
  • 我正在研究更详细的答案。继续“寻找答案”的方法,我认为这可能是调查问题和寻找答案的好方法。
  • @mkl 希望我的回答可以接受并取消投票。
  • @rfb 对不起,否决票不是我投的,我也看不出是谁投的。但是您的编辑明显改善了答案,因此如果反对者再次看到您的答案,他很可能会将其删除。
【解决方案2】:

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

要解决这个问题,您必须返回一个 ANSI 字符串并使用SysAllocStringByteLen

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-04
    • 2022-01-09
    • 2011-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多