Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Dump full interfaces information of an object

0.00/5 (No votes)
16 May 2004 1  
How to understand more about certain objects' implementation details

Introduction

When you get an interface pointer, you may want to know a little more about it. Then you can make full use of it. The following class will dump all other interfaces sit in the same object instance.

Using the code

You just need to declare an instance of the IFDump class in your control class or any other place where you can get an interface pointer. This class will get and cache all registered interfaces into a list in its ctor. Soon after, you can call DumpIF to dump all interfaces for you.

If you think an unregistered typelib which may involve with this interface, you can use GetEntriesFromRegistry to add it, then IFDump class will dump it with a known name, or it will be invisible in the output report.

typedef struct IFPoint
{
    CComBSTR    key;
    ULONG**    addr;
    int    ikind;
    CSimpleArray<MEMORY_BASIC_INFORMATION> mia;
} *pIFPoint;

class IFDump
{
public:
    IFDump()
    {
        GetSystemInfo(&sysinfo);
        limit = sysinfo.lpMinimumApplicationAddress;
        GetEntriesFromRegistry();
    }

    ~IFDump()
    {
        Reset();
        ikeys.RemoveAll();
    }
    CAtlMap<IID,CComBSTR> ikeys;

private:
    CAtlList<IFPoint*>    lstIF;
    SYSTEM_INFO sysinfo;
    LPVOID limit;

    BOOL GetEntriesFromRegistry()
    {
        BOOL Result= FALSE;
        HKEY        hKey1, hKey2;

        ULONG        index1 = 0;
        DWORD        cbName = MAX_PATH;
        TCHAR        tszClsid[MAX_PATH];
        TCHAR        tszSrcName[MAX_PATH];
        DWORD        cbValue = MAX_PATH;

        if (RegOpenKeyEx(HKEY_CLASSES_ROOT, _T("Interface"), 
              0, KEY_READ, &hKey1) == ERROR_SUCCESS)
        {
            while(RegEnumKeyEx(hKey1, index1++, tszClsid, &cbName, 
                      NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
            {
                cbName=MAX_PATH;
                if (RegOpenKeyEx(hKey1, tszClsid, 0, 
                    KEY_READ, &hKey2) == ERROR_SUCCESS)
                {
                    tszSrcName[0] = _T('\0');
                    RegQueryValueEx(hKey2,_T(""),NULL,NULL,
                                  (LPBYTE)tszSrcName,&cbValue);
                    IID iid;
                    CComBSTR bstrInterface(tszClsid);
                    IIDFromString(bstrInterface,&iid);
                    CComBSTR bstrkey(tszSrcName);
                    ikeys.SetAt(iid,bstrkey);
                    cbValue = MAX_PATH;
                    RegCloseKey(hKey2);
                }
                else
                    Result = FALSE;
            }

            RegCloseKey(hKey1);
        }

        return FALSE;
    }

    void QueryMem(ULONG* start,CSimpleArray<MEMORY_BASIC_INFORMATION>& array)
    {
        MEMORY_BASIC_INFORMATION buf;
        SIZE_T result;
        ULONG* p;
        LPVOID q;

        p = (ULONG*)((ULONG)start & ~(sysinfo.dwPageSize - 1));
        for (;;) {
            q = (LPVOID)(p - sysinfo.dwPageSize);
            if ((ULONG*)q > (ULONG*)p || q < limit) 
                break;
            result = VirtualQuery(q, &buf, sizeof(buf));

            if (result != sizeof(buf) || buf.AllocationBase == 0) 
                break;

            array.Add(buf);
            p = (ULONG*)(buf.AllocationBase);
        }
    }

public:
    BOOL Reset()
    {
        POSITION pos1 = lstIF.GetTailPosition();
        while(pos1!=NULL)
        {
            IFPoint* itmIF = lstIF.GetAt(pos1);
            delete itmIF;
            lstIF.GetPrev(pos1);
        }
        lstIF.RemoveAll();
        return TRUE;
    }

    BOOL OutPutResult()
    {
        TCHAR sz[0x1000];
        CComBSTR output;

        POSITION pos1 = lstIF.GetTailPosition();
        ULONG paddr0 = 0;
        while(pos1!=NULL)
        {
            IFPoint* itmIF = lstIF.GetAt(pos1);
            ULONG paddr = (ULONG)itmIF->addr;

            MEMORY_BASIC_INFORMATION buf;
            int icount = itmIF->mia.GetSize();
            if(icount>0)
            {
                buf = itmIF->mia[0];

                ATLTRACE("%08x %08x ",buf.BaseAddress,
                  (ULONG)buf.BaseAddress+(ULONG)buf.RegionSize);
            }
            ATLTRACE("\t");

            wsprintf(sz,_T("%d\t%08x\t%08x\t%s\r\n"),itmIF->ikind,
              itmIF->addr,*itmIF->addr,itmIF->key);
            OutputDebugString(sz);
            lstIF.GetPrev(pos1);
            paddr0 = paddr;
        }
        return TRUE;
    }

    BOOL AddEntriesFromTypeLib(LPOLESTR szFile)
    {
        HRESULT hr = S_FALSE;
        CComPtr<ITypeLib>  ptlib;
        hr = LoadTypeLibEx(szFile, REGKIND_NONE, &ptlib);
        if(FAILED(hr))    return FALSE;

        UINT uicount = ptlib->GetTypeInfoCount();
        for(UINT i=0;i<uicount;i++)
        {
            CComPtr<ITypeInfo> pti;
            hr = ptlib->GetTypeInfo(i,&pti);
            if(FAILED(hr))    break;    
        
            TYPEATTR* pTypeAttr;
            hr = pti->GetTypeAttr(&pTypeAttr);
            if(FAILED(hr))    break;    

            if(pTypeAttr->typekind==TKIND_INTERFACE||
                    pTypeAttr->typekind==TKIND_DISPATCH)
            {
                CComBSTR bstrName;
                hr = pti->GetDocumentation(-1, &bstrName, NULL, NULL, NULL);
                if(SUCCEEDED(hr))    
                    ikeys.SetAt(pTypeAttr->guid,bstrName);
            }

            pti->ReleaseTypeAttr(pTypeAttr);
        }
        return TRUE;
    }

    HRESULT DumpIF(CComPtr<IUnknown> spunk,int kind=0)
    {
        if(!spunk) return S_FALSE;
        HRESULT hr = S_FALSE;

        POSITION pos = ikeys.GetStartPosition();
        while(pos!=NULL)
        {
            CComPtr<IUnknown> xxx;
            hr =spunk->QueryInterface(ikeys.GetKeyAt(pos),(void**)&xxx);
            if(hr==S_OK)
            {
                IFPoint* itmIF    = new IFPoint;
                itmIF->addr        = (ULONG**)((INT_PTR)xxx.p);
                itmIF->ikind    = kind;
                itmIF->key        = ikeys.GetValueAt(pos);
                QueryMem((ULONG*)(xxx.p),itmIF->mia);

                POSITION pos1 = lstIF.GetTailPosition();
                if(pos1==NULL)
                    lstIF.AddTail(itmIF);
                else
                {
                    bool badded = false;
                    while(pos1!=NULL)
                    {
                        IFPoint* curIF = lstIF.GetAt(pos1);

                        if((ULONG)(itmIF->addr)<(ULONG)(curIF->addr))
                        {
                            lstIF.InsertAfter(pos1,itmIF);
                            badded = true;
                            break;
                        }
                        if((ULONG)(itmIF->addr)==(ULONG)(curIF->addr))
                        {
                            curIF->key += _T(" ");
                            curIF->key += ikeys.GetValueAt(pos);
                            lstIF.SetAt(pos1,curIF);
                            badded = true;
                            break;
                        }
                        lstIF.GetPrev(pos1);
                    }
                    if(!badded)
                        lstIF.AddHead(itmIF);
                }
            }
            if(xxx)
            {
                xxx.Release();
                xxx = NULL;
            }
            ikeys.GetNext(pos);
        }
        return hr;
    }
};

The last step is, call DumpIF like the following:

    IFDump ifd;

    HRESULT InPlaceActivate(LONG iVerb, const RECT* /*prcPosRect*/)
    {
        HRESULT hr = CComControl<CProber>::InPlaceActivate(iVerb);

        ifd.Reset();
        ifd.DumpIF(GetUnknown(),0);
        ifd.DumpIF(m_spClientSite.p,1);
        ifd.OutPutResult();
        return S_OK;
    }

History

If you have any other requirements about this class, and you don't want to do it yourself, please drop me a line, I will do my best. Or if you find out any masterpiece which was done by Don Box, Keith Brown or Chris sells, just do the same thing, please let me know. Thanks for your time!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here