C++、COM 和传递字符串
我正在调试其他程序员的 Windows Media Player 插件源代码。这个插件有时会导致 WMP 崩溃,有时需要很长时间才能打开插件设置窗口。仅当在播放音乐时打开设置窗口时才会出现此问题。如果播放器停止,它可以正常打开。
在查看代码和调试时,我发现了这似乎是问题原因的代码行。
属性页有如下成员变量:
CComPtr<IDsp_plugin> m_pDsp_plugin;
初始化时属性页调用COM对象的get_text方法:
unsigned char * txt = NULL;
//m_pDsp_plugin is a valid pointer to IDsp_plugin
HRESULT res = m_pDsp_plugin->get_text(&txt);
此时hrs为“0x80010105:服务器抛出异常”。 Visual Studio 调试输出显示“wmplayer.exe 中 0x764efbae 处的第一次机会异常:0x80010105:
get_text 方法定义如下:
Dsp_plugin.idl 中
interface IDsp_plugin : IUnknown
{
HRESULT get_text([out] unsigned char* *pVal);
...
在Dsp_plugin.h 中的
class ATL_NO_VTABLE CDsp_plugin :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CDsp_plugin, &CLSID_Dsp_plugin>,
public IDsp_plugin,
public IMediaObject,
public IWMPPluginEnable,
public ISpecifyPropertyPages
{
STDMETHOD(get_text)(unsigned char* *txt);
...
,最后是引发此异常的方法本身: Dsp_plugin.cpp
STDMETHODIMP CDsp_plugin::get_text (unsigned char* *txt)
{
... // some code for copying a valid string from somewhere to char* y
// 11 bytes of memory for y was allocated using malloc(10+1);
// y contains a valid C string here, tested with debugger and passing to OutputDebugStringA
*txt = (unsigned char*)(y); // This line executes normally, but at the end the caller gets "The server threw an exception." and WMP starts behaving weirdly.
// If I comment it out, the caller gets S_OK and there are no any issues with WMP.
return S_OK;
}
COM DLL 是使用“使用 Unicode 字符集”设置进行编译的。
我不是经验丰富的 COM 程序员,但将字符串作为 unsigned char** 传递对我来说似乎很不寻常,在处理 COM 时我看到的大多是 BSTR 或 VARIANT。
也许一些 COM 专家可以解释为什么会发生这种异常,并且可以通过将方法转换为使用 BSTR* 和 SysAllocString/SysfreeString 而不是 unsigned char**/malloc/free 来修复它吗?
I am debugging some other programmer's source code of a Windows Media Player plugin. This plugin causes WMP to crash sometimes, and sometimes it takes really long time to open plugin settings window. The problem occurs only when opening settings window while music is being played back. It opens without issues if the player is stopped.
While looking through the code and debugging, I have came to the line of code which seems to be the cause of the problems.
The property page has the following member variable:
CComPtr<IDsp_plugin> m_pDsp_plugin;
and the property page at initialization calls get_text method of the COM object:
unsigned char * txt = NULL;
//m_pDsp_plugin is a valid pointer to IDsp_plugin
HRESULT res = m_pDsp_plugin->get_text(&txt);
At this moment hres is "0x80010105: The server threw an exception." and Visual Studio Debug output shows "First-chance exception at 0x764efbae in wmplayer.exe: 0x80010105:
get_text method is defined as follows:
in Dsp_plugin.idl
interface IDsp_plugin : IUnknown
{
HRESULT get_text([out] unsigned char* *pVal);
...
in Dsp_plugin.h
class ATL_NO_VTABLE CDsp_plugin :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CDsp_plugin, &CLSID_Dsp_plugin>,
public IDsp_plugin,
public IMediaObject,
public IWMPPluginEnable,
public ISpecifyPropertyPages
{
STDMETHOD(get_text)(unsigned char* *txt);
...
and finally the method itself which throws this exception:
Dsp_plugin.cpp
STDMETHODIMP CDsp_plugin::get_text (unsigned char* *txt)
{
... // some code for copying a valid string from somewhere to char* y
// 11 bytes of memory for y was allocated using malloc(10+1);
// y contains a valid C string here, tested with debugger and passing to OutputDebugStringA
*txt = (unsigned char*)(y); // This line executes normally, but at the end the caller gets "The server threw an exception." and WMP starts behaving weirdly.
// If I comment it out, the caller gets S_OK and there are no any issues with WMP.
return S_OK;
}
The COM DLL is compiled with setting "Use Unicode Character Set".
I am not experienced COM programmer, but passing strings as unsigned char** seems unusual to me, I have seen mostly BSTR or VARIANT when dealing with COM.
Maybe some COM guru can explain, why this exception happens and can it be possibly fixed just by converting methods to using BSTR* and SysAllocString/SysfreeString instead of unsigned char**/malloc/free ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
简而言之,COM 不知道如何传递
unsigned char *
类型的指针。应用默认编组规则(因为接口定义不不指定任何参数属性),并且,如果我正确解释这一点,COM 会正确封送外部指针本身txt
,但将*txt
视为指向一个单个无符号字符
,而不是字符串。如果呼叫者和被呼叫者碰巧在同一间公寓,这可能仍然有效;从声音来看,他们不是。
最简单的解决方案就是将参数设为
BSTR *
。 COM 对BSTR
有特殊处理,这将确保它正确传递。Put simply, COM doesn't know how to pass around pointers of type
unsigned char *
. The default marshalling rules are applied (since the interface definition doesn't specify any parameter attributes), and, if I'm interpreting this correctly, COM marshals the outer pointer itselftxt
properly, but treats*txt
as a pointer to a singleunsigned char
, not a string.This may still work if the caller and callee happen to be in the same apartment; from the sounds of it, they're not.
The easiest solution is simply to make the parameter a
BSTR *
. COM has special handling forBSTR
which will ensure it's passed correctly.