C++ 使用ATL枚举COM对象(IDispatch)方法?
使用ATL(VS2008)如何枚举给定IDispatch接口(C++ 使用ATL枚举COM对象(IDispatch)方法?,c++,com,atl,C++,Com,Atl,使用ATL(VS2008)如何枚举给定IDispatch接口(IDispatch*)上可用的方法?我需要搜索一个具有特定名称的方法,一旦我有了DISPID,调用该方法(我知道该方法采用的参数)。理想情况下,我希望使用智能COM指针(CComPtr)来完成这项工作 这可能吗 除非对象实现IDispatchEx,否则无法枚举所有可用的方法 但是,如果知道要调用的方法的名称,可以使用GetIDsOfNames将名称映射到适当的DISPID HRESULT hr; CComPtr<IDispatc
IDispatch*
)上可用的方法?我需要搜索一个具有特定名称的方法,一旦我有了DISPID
,调用该方法(我知道该方法采用的参数)。理想情况下,我希望使用智能COM指针(CComPtr
)来完成这项工作
这可能吗 除非对象实现IDispatchEx,否则无法枚举所有可用的方法 但是,如果知道要调用的方法的名称,可以使用GetIDsOfNames将名称映射到适当的DISPID
HRESULT hr;
CComPtr<IDispatch> dispatch;
DISPID dispid;
WCHAR *member = "YOUR-FUNCTION-NAME-HERE";
DISPPARAMS* dispparams;
// Get your pointer to the IDispatch interface on the object here. Also setup your params in dispparams.
hr = dispatch->GetIDsOfNames(IID_NULL, &member, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (SUCCEEDED(hr)) {
hr = dispatch->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, dispparams, &varResult, NULL, NULL);
}
HRESULT-hr;
买方派遣;
DISPID DISPID;
WCHAR*member=“YOUR-FUNCTION-NAME-HERE”;
DISPPARAMS*DISPPARAMS;
//在此处获取指向对象上IDispatch接口的指针。还可以在dispparams中设置参数。
hr=dispatch->GetIDsOfNames(IID\u NULL,&member,1,LOCALE\u SYSTEM\u DEFAULT,&dispid);
如果(成功(hr)){
hr=dispatch->Invoke(1,IID\u NULL,LOCALE\u USER\u默认值,dispatch\u方法,dispparams,&varResult,NULL,NULL);
}
编辑:为了完整性,我怀疑有一种方法可以查询从IDispatch::GetTypeInfo获取的方法列表的ITypeInfo2接口(假设对象有一个类型库),但我没有这样做。查看另一个答案。您可以枚举
IDispatch通过类型信息公开的方法。有两种方法可以获取类型信息:
- 通过dispinterface的类型库(如果有)
- 通过电话
不幸的是,IDispatch
实现没有义务提供有关其实现的方法和属性的类型信息
但是,如果是这样,则基本枚举包括调用以获取接口的,并查看实现的方法(cFuncs
)和变量(cVars
)的数量,然后循环这些方法并调用or。当然,我可以在这里列出更多的细节,但这应该是你探索的一个很好的起点
这里有一个很好的VB.Net中的with代码。这里有一些执行枚举的代码(它在映射中插入[Dispatch ID]-[Method Name]对,但这很容易更改)
///
///\brief为传入的IDispatch对象返回[DispId,Method Name]的映射
///
HRESULT COMTools::GetIDispatchMethods(u In_uidispatch*pDisp,
_输出标准::映射和方法映射)
{
HRESULT hr=S_正常;
CComPtr spDisp(pDisp);
如果(!spDisp)
返回E_INVALIDARG;
CComPtr spTypeInfo;
hr=spDisp->GetTypeInfo(0、0和spTypeInfo);
if(成功(hr)和spTypeInfo)
{
TYPEATTR*pTatt=nullptr;
hr=spTypeInfo->GetTypeAttr(&pTatt);
if(成功(hr)和pTatt)
{
FUNCDESC*fd=nullptr;
对于(int i=0;icFuncs;++i)
{
hr=spTypeInfo->GetFuncDesc(i和fd);
如果(成功(hr)和fd)
{
CComBSTR-funcName;
spTypeInfo->GetDocumentation(fd->memid,&funcName,nullptr,nullptr,nullptr);
如果(funcName.Length()>0)
{
methodsMap[fd->memid]=funcName;
}
spTypeInfo->releasefundesc(fd);
}
}
spTypeInfo->ReleaseTypeAttr(pTatt);
}
}
返回人力资源;
}
太棒了!正是我需要的。非常感谢。我相信我已经表达了你刚才在我的回答中评论的每一点。请仔细再读一遍。此外,海报只是希望能够调用一个他已经知道名称的方法。因此,我的回答为他真正想做的事情提供了解决方案,而不一定是他问的问题。我怀疑这就是为什么它被标记为正确答案的原因。最后,请冷静下来。只有1和0。好东西。感谢您添加此内容。@Franci,当属性是数组时,返回的VARDESC有一个varkind=IDispatch。如何判断属性是否是数组,如果是数组-如何访问其成员?调用Invoke获取数组时,结果是IDispatch。此IDispatch不支持“Item”或“Length”或任何类似属性。@Uri-请注意,属性不是字段,应通过GetFuncDesc()
进行检查,该属性提供了一个FUNCDESC
,您必须从中转到elemdescFunc
(用于返回)或lprgelemdescParam
(用于参数)。数组通常作为out参数返回,因此您应该检查后者。在任何情况下,这两个函数都给出了ELEMDESC
,您应该在这里检查tdesk
,它返回给您一个TYPEDESC
,它基于VARTYPE vt
可能实际上是一个ARRAYDESC
。如果是这种情况,您有一个SAFEARRAY
@Uri-如果它不是SAFEARRAY
,则该属性很可能返回一个IDispatch
指针,指向一个对象,该对象作为集合实现类似数组的功能。您应该向IDispatch
询问其类型信息,并检查该类型信息,以找出访问集合成员的正确方法。@Uri-如果您的数组来自JScript,则它不是SAFEARRAY,而是JScript数组对象的IDispatch。这里描述了VBScript数组(即SAFEARRAYS)和JScript数组之间的区别。请参阅此工具(源代码):和此:我查找了其他示例,还发现了
///
/// \brief Returns a map of [DispId, Method Name] for the passed-in IDispatch object
///
HRESULT COMTools::GetIDispatchMethods(_In_ IDispatch * pDisp,
_Out_ std::map<long, std::wstring> & methodsMap)
{
HRESULT hr = S_OK;
CComPtr<IDispatch> spDisp(pDisp);
if(!spDisp)
return E_INVALIDARG;
CComPtr<ITypeInfo> spTypeInfo;
hr = spDisp->GetTypeInfo(0, 0, &spTypeInfo);
if(SUCCEEDED(hr) && spTypeInfo)
{
TYPEATTR *pTatt = nullptr;
hr = spTypeInfo->GetTypeAttr(&pTatt);
if(SUCCEEDED(hr) && pTatt)
{
FUNCDESC * fd = nullptr;
for(int i = 0; i < pTatt->cFuncs; ++i)
{
hr = spTypeInfo->GetFuncDesc(i, &fd);
if(SUCCEEDED(hr) && fd)
{
CComBSTR funcName;
spTypeInfo->GetDocumentation(fd->memid, &funcName, nullptr, nullptr, nullptr);
if(funcName.Length()>0)
{
methodsMap[fd->memid] = funcName;
}
spTypeInfo->ReleaseFuncDesc(fd);
}
}
spTypeInfo->ReleaseTypeAttr(pTatt);
}
}
return hr;
}