我使用Visual Studio 2010在C ++中开发了一个Out-Of-Proc-COM-Server,以避免Shellextensions(http://blog.mattmags.com/2007/06/30/accessing-32-bit-dlls-from-64-bit-code/)中的64位与32位问题。
我在IDL文件中描述了这里的接口(http://msdn.microsoft.com/en-us/library/ms686605%28v=VS.85%29.aspx):
import "unknwn.idl";
[
object,
uuid("xx"),
helpstring("IShellServerx86-Interface")
]
interface IShellServerx86 : IUnknown
{
HRESULT ShowFileInfo([in]BSTR file, [out]BSTR* htmlFile, [in]BSTR pathChar);
};
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,我也注册使用标准Marshaller方法。 如果我现在打电话
创建了服务器,我可以调用方法
IShellServerx86* pShellServer = NULL;
CoCreateInstance(__uuidof(CShellServerx86), NULL, CLSCTX_LOCAL_SERVER,
__uuidof(IShellServerx86), (void**)&pShellServer);
并使用创建的参数(客户端):
HRESULT CShellServerx86::ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathChar)
在客户端中BSTR是正确生成的,但是当调用COM方法时(他找到它!)并且我调试到dllhost.exe,参数无效,就像选择了错误的编码一样。我尝试整个项目设置“Unicode”,但没有任何变化。
我是否忘记了任何设置,还是应该尝试其他数据类型进行编组?
提前感谢您的帮助。
编辑:
客户的实施是:
BSTR filebstr = ::SysAllocString(A2OLE(file));
BSTR pathBstr = ::SysAllocString(A2OLE(pathChar));
BSTR htmlFileBstr = ::SysAllocString(A2OLE(""));
服务器方法声明如下:
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;
}
在服务器和客户端方法中,调试器将BSTR字符串识别为wchar_t * -arrays。但是,例如服务器方法中字符串“file”的内容类似于:0x02546e80“㤈榧”。
编码适用于设置为Multibyte-Encoding(Visual Studio)的所有项目(客户端/服务器)。
EDIT2:
服务器声明为follwed:
HRESULT CShellServerx86::ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathBSTR)
{...
//TODO
}
接口的实现:
class IShellServerx86 : public IUnknown {
public:
virtual HRESULT ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathChar) = 0;
};
......和班级工厂 class CShellServerx86ClassFactory:public IClassFactory { 上市: CShellServerx86ClassFactory(); 〜CShellServerx86ClassFactory();
//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;
};
保护: ULONG m_uRefCount; };
DLL中的GetClass-Method:
//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);
}
答案 0 :(得分:1)
首先,您必须检查A2OLE
在您的案例中产生的内容以及这是SysAllocString()
的合适输入。
然后你必须实现//TODO
- 正确构建out参数值的被调用者责任。你必须做这样的事情:
HRESULT CShellServerx86::ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathBSTR)
{
if( htmlFile == 0 ) {
return E_POINTER;
}
// do useful stuff, generate the string for the htmlFile, then
*htmlFile = SysAllocString( TheStringForHtmlFileParameter );
return S_OK;
}
此外,您在调用方中泄露BSTR
:
BSTR htmlFileBstr = ::SysAllocString(A2OLE(""));
//Call method of Server
hr = pShellServer->ShowFileInfo(filebstr, &htmlFileBstr, pathBstr);
将丢失作为第二个参数传递的BSTR
,因为被调用者将创建一个新的BSTR
。而只是将其初始化为空指针:
BSTR htmlFileBstr = 0;
//Call method of Server
hr = pShellServer->ShowFileInfo(filebstr, &htmlFileBstr, pathBstr);
此外,您仍然会泄漏所有BSTR
,因为完成后您没有拨打SysFreeString()
。在您拥有的每个SysFreeString()
上调用BSTR
,或者更好地使用ATL::CComBSTR
或_bstr_t
等包装类。