使用ATL枚举COM对象(IDispatch)方法?

时间:2010-01-21 19:43:53

标签: c++ com atl

使用ATL(VS2008)如何枚举给定IDispatch接口(IDispatch*)上可用的可用方法?我需要搜索具有特定名称的方法,并且一旦我有DISPID,就调用该方法(我知道方法所采用的参数。)理想情况下,我想使用智能COM指针({{ 1}})。

这可能吗?

3 个答案:

答案 0 :(得分:17)

您可以枚举IDispatch通过类型信息公开的方法。有两种方法可以获取类型信息:

不幸的是,IDispatch实现没有义务提供有关它实现的方法和属性的类型信息。

如果确实如此,基本枚举涉及调用ITypeInfo::GetTypeAttr来获取接口的TYPEATTR并查看已实现的方法(cFuncs)和变量({{的数量1}})并循环遍历这些并调用ITypeInfo::GetFuncDesc()ITypeInfo::GetVarDesc()。当然,你可以在这里列出更多细节,但这应该是你探索的一个很好的起点。

这是一个很好的article explaining the process in more details,代码在VB.Net中。

答案 1 :(得分:11)

这是一些进行枚举的代码(它在地图中插入[Dispatch ID] - [Method Name]对,但这很容易改变)。

///
/// \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;

}

答案 2 :(得分:7)

除非对象实现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);
}

编辑:为了完整性,我怀疑有一种方法来询问ITypeInfo2接口(假设有一个对象的类型库),你可以从IDispatch :: GetTypeInfo获取方法列表,但我还没有完成它。见其他答案。