我正在调试其他程序员的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);
此时,hres是“0x80010105:服务器抛出异常。”和Visual Studio Debug输出显示“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;
}
使用设置“使用Unicode字符集”编译COM DLL。
我不是经验丰富的COM程序员,但是将字符串作为unsigned char **传递给我似乎不寻常,我在处理COM时看到的主要是BSTR或VARIANT。
也许有些COM大师可以解释一下,为什么会发生这种异常并且可能只是通过将方法转换为使用BSTR *和SysAllocString / SysfreeString而不是unsigned char ** / malloc / free来解决?
答案 0 :(得分:5)
简单地说,COM不知道如何传递unsigned char *
类型的指针。应用了default marshalling rules(因为接口定义没有指定任何参数属性),并且,如果我正确地解释了这一点,COM正确地封送了外部指针本身txt
,但是对待{{1} }}作为指向单 *txt
的指针,而不是字符串。
如果来电者和被叫者碰巧在同一个公寓,这可能仍然有效;从它的声音来看,它们不是。
最简单的解决方案就是将参数设为unsigned char
。 COM对BSTR *
进行了特殊处理,这将确保它正确传递。