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* )
{
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!