我有一个实现了IDispatch接口的类(JSObject)。 该类暴露于运行在我的托pipe的Web浏览器控件(IWebBrowser2)中的JavaScript。
在这里看到更多关于这是如何工作的: 调用Web浏览器控件中运行的JavaScript脚本的C ++函数
我可以从我的JavaScript代码中调用JSObject,并且可以接收返回的整数/多个。 但是当函数返回一个string(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()
返回的string,但是你不能添加它。 alert(returnedString + "foo");
只会显示“返回的string”。 “foo”部分不会添加到string中。 这个string的结尾似乎有些问题。 任何想法的人?
另外,我在这里泄漏内存,因为我没有调用SysFreeString()
?
编辑:
我暂时包含atlbase.h,所以我可以使用CComBSTR
。 上面的代码现在看起来像这样:
pVarResult->vt = VT_BSTR; pVarResult->bstrVal = CComBSTR("test string");
单步执行代码,肯定会显示pVarResult是“testingstring”,直到函数返回。 但是,当我在我的JavaScript代码中alert()返回的string时,我得到“扩展”。 alert(returnedString + "foo")
是“expandedfoo”。 所以这是一个正确的方向,你可以添加到返回的string的一小步。 但这也是一个错误的方向的一步,因为返回的string不是我真正返回的…
*pVarResult = CComVariant("test string");
该代码给出了与以前列表中的代码(使用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);
正如在注释中提到的那样,字符串将被调用者释放 – 内存管理规则规定out-parameters属于调用者。
调试下面几个有趣的事情的代码变得明显。
int lenW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, "testing testing", -1, NULL, 0); BSTR bstrRet = SysAllocStringLen(0, lenW); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, "testing testing", -1, bstrRet, lenW); BSTR bstrRet2 = SysAllocString(L"testing testing"); int len1 = SysStringByteLen(bstrRet); int len2 = SysStringByteLen(bstrRet2);
len1
是32. len2
只是30. SysAllocString
与我的JavaScript代码一起工作,另一种方法不。
看看bstrRet分配的内存,我可以看到它以0x00 0x00 0x00 0x00结尾,而bstrRet2只有0x00 0x00。 所以我的猜测是,当使用bstrRet将其抛出时,会向JavaScript代码发送额外的空终止符。 这就是为什么你不能附加任何东西。 bstrRet2没有额外的空终止符。
知道问题中的原始代码可以如下修改:
int lenW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, "Returned string", -1, NULL, 0) - 1; BSTR bstrRet = SysAllocStringLen(0, lenW); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, "Returned string", lenW*2, bstrRet, lenW); pVarResult->vt = VT_BSTR; pVarResult->bstrVal = bstrRet;
我不确定lenW*2
是否安全,但是在我进行的有限测试中,这个代码似乎工作得很好。