Out-Of-Proc-COM-Server:BSTR 未正确编组
我使用 Visual Studio 2010 用 C++ 开发了一个 Out-Of-Proc-COM-Server,以避免 Shellextensions 中的 64 位与 32 位问题 (http://blog.mattmags.com/2007/06/30/accessing-32-bit-dlls-from-64-bit-code/)。
我在这里描述了接口(http:// msdn.microsoft.com/en-us/library/ms686605%28v=VS.85%29.aspx) 在 IDL 文件中:
import "unknwn.idl";
[
object,
uuid("xx"),
helpstring("IShellServerx86-Interface")
]
interface IShellServerx86 : IUnknown
{
HRESULT ShowFileInfo([in]BSTR file, [out]BSTR* htmlFile, [in]BSTR pathChar);
};
该文件生成了一个 Proxy/Stub-DLL,我还注册了它以使用标准编组器方法。 如果我现在调用,
IShellServerx86* pShellServer = NULL;
CoCreateInstance(__uuidof(CShellServerx86), NULL, CLSCTX_LOCAL_SERVER,
__uuidof(IShellServerx86), (void**)&pShellServer);
服务器已创建,我可以
HRESULT CShellServerx86::ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathChar)
使用创建的参数调用该方法(客户端):
BSTR filebstr = ::SysAllocString(A2OLE(file));
BSTR pathBstr = ::SysAllocString(A2OLE(pathChar));
BSTR htmlFileBstr = ::SysAllocString(A2OLE(""));
在客户端中,BSTR 已正确生成,但当调用 COM 方法时(他找到了它!)并且我进行调试进入dllhost.exe,参数无效,如选择了错误的编码。我尝试为整个项目设置“Unicode”,但没有任何变化。
我是否忘记了任何设置,或者我应该尝试其他数据类型进行编组?
提前感谢您的帮助。
编辑:
客户端的实现是:
int CShellWrapperx64Module::ShowFileInfo(IN const char* file,
OUT VARIANT &htmlFile,
IN const char* pathChar)
{...
::CoInitialize(NULL);
IShellServerx86* pShellServer = NULL
hr = ::CoCreateInstance(__uuidof(CShellServerx86), NULL,
CLSCTX_LOCAL_SERVER, __uuidof(IShellServerx86),
(void**)&pShellServer);
BSTR filebstr = ::SysAllocString(A2OLE(file));
BSTR pathBstr = ::SysAllocString(A2OLE(pathChar));
BSTR htmlFileBstr = ::SysAllocString(A2OLE(""));
//Call method of Server
hr = pShellServer->ShowFileInfo(filebstr, &htmlFileBstr, pathBstr);
::CoUninitialize();
VariantInit(&htmlFile);
htmlFile.vt = VT_BSTR;
htmlFile.bstrVal = htmlFileBstr;
}
服务器方法声明如下:
HRESULT CShellServerx86::ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathBSTR)
{...
//TODO
}
在服务器和客户端方法中,调试器将 BSTR 字符串识别为 wchar_t* 数组。但是,例如服务器方法中字符串“file”的内容类似于:0x02546e80“㤈榧”。
所有项目(客户端/服务器)的编码均设置为多字节编码 (Visual Studio)。
EDIT2:
服务器声明如下:
class IShellServerx86 : public IUnknown {
public:
virtual HRESULT ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathChar) = 0;
};
接口的实现:
//CoClass from Interface (Implementation)
class CShellServerx86 : public IShellServerx86 {
public:
CShellServerx86();
virtual ~CShellServerx86();
//inherited from IUnknown
ULONG STDMETHODCALLTYPE AddRef(void);
ULONG STDMETHODCALLTYPE Release(void);
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv);
HRESULT ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathChar);
protected:
ULONG m_uRefCount;
};
...和类工厂 类 CShellServerx86ClassFactory :公共 IClassFactory { 民众: CShellServerx86ClassFactory(); ~CShellServerx86ClassFactory();
//inherited methods from IUnknown
ULONG STDMETHODCALLTYPE AddRef(void);
ULONG STDMETHODCALLTYPE Release(void);
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv);
//inherited methods from IClassFactory
HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter,
REFIID riid, void** ppv);
HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock);
受保护: ULONG m_uRefCount; };
从 DLL 获取类方法:
STDAPI DllGetClassObject ( REFCLSID rclsid, REFIID riid, void** ppv ) {
if (!::InlineIsEqualGUID(rclsid, __uuidof(CShellServerx86)) ) {
return CLASS_E_CLASSNOTAVAILABLE;
}
*ppv = NULL;
CShellServerx86ClassFactory* pShellServerFac;
pShellServerFac = new CShellServerx86ClassFactory;
if (pShellServerFac == NULL) {
return E_OUTOFMEMORY;
}
pShellServerFac->AddRef();
HRESULT hr = pShellServerFac->QueryInterface(riid, ppv);
pShellServerFac->Release();
return hr;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,您必须检查
A2OLE
在您的情况下生成的内容以及它是否适合SysAllocString()
的输入。然后您必须实现
//TODO
- 被调用者有责任正确构建输出参数的值。您必须执行以下操作:此外,您还会在调用者中泄漏
BSTR
:将丢失自新的
BSTR 以来作为第二个参数传递的
将由被调用者创建。相反,只需将其初始化为空指针:BSTR
无论如何,您都会泄漏所有
BSTR
,因为完成后您不会调用SysFreeString()
。要么对您拥有的每个BSTR
调用SysFreeString()
,要么最好使用ATL::CComBSTR
或_bstr_t
等包装类>。First you have to inspect what
A2OLE
produces in your case and whether that's suitable input forSysAllocString()
.Then you have to implement that
//TODO
- it's the callee responsibility to properly build values of out parameters. You'll have to do something like this:Also you're leaking a
BSTR
in the caller:will lose the
BSTR
passed as second parameter since a newBSTR
will be created by the callee. Instead just initialize it to a null pointer:Also you leak all
BSTR
s anyway since you don't callSysFreeString()
when done. Either callSysFreeString()
on eachBSTR
you own or better use a wrapper class likeATL::CComBSTR
or_bstr_t
.