我有一个实现 IDispatch 接口(interface)的类 (JSObject)。该类暴露给在我托管的 Web 浏览器控件 (IWebBrowser2) 中运行的 JavaScript。
在此处查看有关其工作原理的更多信息:Calling C++ function from JavaScript script running in a web browser control
我可以从我的 JavaScript 代码中调用 JSObject,并且我可以接收返回的整数/长整数。但是当函数返回字符串 (BSTR) 时出现问题。
这是 IDispatch::Invoke()
代码的一部分:
int lenW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, "Returned string", -1,
NULL, 0);
BSTR bstrRet = SysAllocStringLen(0, lenW);
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, "Returned string", -1, bstrRet,
lenW);
pVarResult->vt = VT_BSTR;
pVarResult->bstrVal = bstrRet;
// Who calls SysFreeString(bstrRet);?
使用上面的代码,您可以alert()
返回的字符串,但您不能向它添加。 alert(returnedString + "foo");
只会显示“返回的字符串”。 “foo”部分未添加到字符串中。不知何故,字符串的结尾似乎有问题。有什么想法吗?
此外,由于我没有调用 SysFreeString()
,我是否在此处泄漏内存?
编辑:
我暂时包含了 atlbase.h,这样我就可以使用 CComBSTR
。上面的代码现在看起来像这样:
pVarResult->vt = VT_BSTR;
pVarResult->bstrVal = CComBSTR("test string");
单步执行该代码明确表明 pVarResult 一直是“测试字符串”,直到函数返回。但是当我在我的 JavaScript 代码中 alert() 返回的字符串时,我得到了“扩展”。 alert(returnedString + "foo")
是“expandedfoo”。所以这是朝着正确方向迈出的一小步,因为您可以将其添加到返回的字符串中。但这也是朝着错误方向迈出的一步,因为返回的字符串并不是我真正返回的……
*pVarResult = CComVariant("test string");
该代码给出的结果与前面 list 中的代码相同(使用 CComBSTR)。
最佳答案
第一个 MultiByteToWideChar()
调用返回存储字符串所需的字符数,包括空终止符。然后 SysAllocStringLen()
为 lenW+1
个字符(比需要的多一个)分配一个缓冲区,并且已经以 null 终止它。
由于 MultiByteToWideChar()
还写入一个空终止符,因此您最终会在字符串末尾得到两个。对于 BSTR
来说,嵌入的空字符是可能的,因为它们有长度前缀,因此 JScript 实现可能会在不删除附加字符的情况下连接......因此你最终会得到一个带有嵌入空字符的字符串中间部分只会打印一部分。
长话短说,固定长度:
lenW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, NULL, 0);
bstrRet = SysAllocStringLen(0, lenW-1);
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, bstrRet, lenW-1);
如评论中所述,字符串将由调用者释放 - memory management rules规定输出参数归调用者所有。
关于javascript - 从 C++ 函数返回字符串到 JavaScript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3754268/