转储对象的完整接口信息





4.00/5 (4投票s)
2004年5月17日
1分钟阅读

30305

422
如何更好地了解某些对象的实现细节。
引言
当你获得一个接口指针时,你可能想了解更多关于它的信息。这样你才能充分利用它。下面的类将会转储同一个对象实例中的所有其他接口。
使用代码
你只需要在你的控件类或者任何可以获得接口指针的地方声明一个 IFDump
类的实例。这个类会在它的 ctor
中获取并缓存所有注册的接口到一个列表中。之后,你可以调用 DumpIF
来转储所有接口。
如果你认为有一个未注册的 typelib
可能与这个接口相关,你可以使用 GetEntriesFromRegistry
来添加它,然后 IFDump
类将会以已知的名称转储它,否则它将在输出报告中不可见。
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; } };
最后一步是,像下面这样调用 DumpIF
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; }
历史
如果你对这个类有任何其他需求,并且不想自己动手实现,请与我联系,我会尽力而为。或者如果你发现了 Don Box、Keith Brown 或 Chris Sells 的任何杰作,请做同样的事情,并告诉我。感谢你的时间!