Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enumerate COM object (IDispatch) methods using ATL?

Tags:

c++

com

atl

Using ATL (VS2008) how can I enumerate the available methods available on a given IDispatch interface (IDispatch*)? I need to search for a method with a specific name and, once I have the DISPID, invoke the method (I know the parameters the method takes.) Ideally I would like to do this using smart COM pointers (CComPtr<>).

Is this possible?

like image 448
Rob Avatar asked Jan 21 '10 19:01

Rob


2 Answers

You can enumerate the methods an IDispatch exposes through the type info. There are two ways to get the type info:

  • through the type library (if any) for the dispinterface.
  • through calling IDispatch::GetTypeInfo.

Unfortunately, an IDispatch implementation is not obligated to provide type info about the methods and properties it implements.

If it does, however, the basic enumerating involves calling ITypeInfo::GetTypeAttr to get the TYPEATTR for the interface and looking at the number of implemented methods (cFuncs) and variables (cVars) and looping over these and calling ITypeInfo::GetFuncDesc() or ITypeInfo::GetVarDesc(). Of course, there are lot more details you will have to deal with as I can list here, but this should be a good starting point for your exploration.

Here's a nice article explaining the process in more details with code in VB.Net.

like image 142
Franci Penov Avatar answered Sep 18 '22 06:09

Franci Penov


Here's some code that does the enumeration (it inserts the [Dispatch ID]-[Method Name] pairs in a map, but that's easy to change).

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

}
like image 20
Yiannis Spyridakis Avatar answered Sep 18 '22 06:09

Yiannis Spyridakis