我正在编写一个Excel服务器实现,我被困在实现IDispatch的coclass的样板上。我没有访问ATL的权限,但我使用的是ActiveQt,尽管我也对如何在原始C或C++中这样做感兴趣。如何在COM服务器中正确实现IDispatch方法?
和往常一样,这些文档太可怕了。我到目前为止读到的是:
ITypeInfo进行更好的实践。这是正确的吗?ITypeInfo?LoadTypeLib()和家人(然后是ITypeLib::GetTypeInfo())?LoadTypeLib()方法似乎适合COM客户端访问某些库的类型信息,而不是试图内省自身的COM服务器。我说的对吗?
发布于 2013-10-08 22:13:24
如果接口在IDL中正确定义并编译成类型库,则通过类型库的IDispatch实现ITypeInfo是非常可行的,因为它主要是委托。有趣的部分是ITypeInfo::Invoke,它依赖于正确的C++ v-table布局:
public class CComClass: public IDualInterface
{
// ...
// implementing IDualInterface
ITypeInfo* m_pTypeInfo // can be obtained via ITypeLib::GetTypeInfoOfGuid for the GUID of IDualInterface
// IDispatch
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo)
{
*pctinfo = 1;
return S_OK;
}
STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{
if (0 != itinfo)
return E_INVALIDARG;
(*pptinfo = m_pTypeInfo)->AddRef();
return S_OK;
}
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
{
return m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
}
STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
return m_pTypeInfo->Invoke(static_cast<IDualInterface*>(this), dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
}
}我使用了类似的方法来创建MSHTML对象的脚本可调用包装器,以绕过脚本安全限制。
那么你从哪里得到的ITypeInfo呢?从本质上说,你是通过:
ITypeInfo实现知道要调用哪个函数的方式--它不能直接调用类上的C++函数,因为C++没有反射,而且它是语言中立的。因此,它只能将Invoke调用委托给类型库中声明的另一个方法。E_NOTIMPL,然后逐个实现它们)RegisterTypeLib注册。如果它是作为资源嵌入的,则应该从DllRegisterServer实现中调用它。LoadTypeLib加载类型库。这给了你一个ITypeLibGetTypeInfoOfGuid。发布于 2013-10-08 16:46:37
实现IDispatch可能是容易的,也可能是困难的。(假设您不能使用ATL)。
简单的方法是不支持TypeInfo (从GetTypeInfoCount返回0,从GetTypeInfo返回E_NOTIMPL )。没有人应该叫它)。
那么,您所需要支持的就是GetIDsOfNames和Invoke。从本质上说,这只是一个大的查找表。
对于GetIDsOfNames,返回DISP_E_UNKNOWNNAME如果cNames != 1。你不会支持参数名的。然后,您只需在名称到ids的映射中查找rgszNames[0]即可。
最后,实现调用。忽略除了pDispParams和pVarResult之外的所有东西。使用VariantChangeType将参数强制到您期望的类型,并传递给您的实现。设置返回值和返回。好了。
困难的方法是使用ITypeInfo和所有这些。我从来没有这样做过,也不会这样做。ATL使它变得容易,所以只需使用ATL。
如果选择困难的道路,祝你好运。
发布于 2013-10-08 17:19:13
您可以做的是使用类型库。
如果你有,那是一件你不需要做的事。如果没有,则可以使用MIDL编译器创建一个。这是平台SDK附带的免费工具。当然,在这种情况下,这将意味着您必须编写一个IDL文件(这可能是很多工作,但您只需要定义您想要的)。根据您所针对的COM对象的类型,在SDK中可能已经有一个IDL文件。一旦您准备好了IDL,就可以编译它和取回一个TLB文件。
一旦您有了这个TLB文件,就可以使用LoadTypeLib函数加载它。一旦有了ITypeLib引用,就可以加载所需的ITypeInfo (可能不止一次),并基本上路由IDispatch调用(GetIDsOfNames等)。转换为ITypeInfo实现调用,因为它们非常相似。
https://stackoverflow.com/questions/19253471
复制相似问题