Copyright © Microsoft Corporation. This document is an archived reproduction of a version originally published by Microsoft. It may have slight formatting modifications for consistency and to improve readability. |
MEMBERID memid SCODE * lprgscode ELEMDESC * lprgelemdescParam INVOKEKIND invkind CALLCONV callconv short cParams short cParamsOpt short oVft short cScodes ELEMDESC elemdescFunc WORD wFuncFlags
Figure 4 COMTypeLibDump
//================================================== // COMTypeLibDump - Matt Pietrek 1999 // Microsoft Systems Journal, March 1999 // FILE: COMTypeLibDump.CPP //================================================== #include <windows.h> #include <ole2.h> #include <tchar.h> //============================================================================ LPCTSTR g_szHelpText = _T( "COMTypeLibDump - Matt Pietrek 1999 for MSJ\n" ) _T( " Syntax: COMTypeLibDump <filename>\n" ); //============================================================================ void DisplayTypeLib( LPCTSTR pszFileName ); void EnumTypeLib( LPTYPELIB pITypeLib ); void DisplayTypeInfo( LPTYPEINFO pITypeInfo ); void EnumTypeInfoMembers( LPTYPEINFO pITypeInfo, LPTYPEATTR pTypeAttr); LPCTSTR GetTypeKindName( TYPEKIND typekind ); LPCTSTR GetInvokeKindName( INVOKEKIND invkind ); //============================================================================ extern "C" int _tmain( int argc, LPCTSTR * argv ) { CoInitialize( 0 ); if ( 2 != argc ) { _tprintf( g_szHelpText ); return 0; } DisplayTypeLib( argv[1] ); CoUninitialize(); return 0; } void DisplayTypeLib( LPCTSTR pszFileName ) { LPTYPELIB pITypeLib; HRESULT hr = LoadTypeLib( pszFileName, &pITypeLib ); if ( S_OK != hr ) { _tprintf( _T("LoadTypeLib failed on file %s\n"), pszFileName ); return; } EnumTypeLib( pITypeLib ); pITypeLib->Release(); } void EnumTypeLib( LPTYPELIB pITypeLib ) { UINT tiCount = pITypeLib->GetTypeInfoCount(); for ( UINT i = 0; i < tiCount; i++ ) { LPTYPEINFO pITypeInfo; HRESULT hr = pITypeLib->GetTypeInfo( i, &pITypeInfo ); if ( S_OK == hr ) { DisplayTypeInfo( pITypeInfo ); pITypeInfo->Release(); } } } void DisplayTypeInfo( LPTYPEINFO pITypeInfo ) { HRESULT hr; BSTR pszTypeInfoName; hr = pITypeInfo->GetDocumentation(MEMBERID_NIL, &pszTypeInfoName, 0, 0, 0); if ( S_OK != hr ) return; TYPEATTR * pTypeAttr; hr = pITypeInfo->GetTypeAttr( &pTypeAttr ); if ( S_OK != hr ) { SysFreeString( pszTypeInfoName ); return; } _tprintf( _T("%ls - %s\n"), pszTypeInfoName, GetTypeKindName(pTypeAttr->typekind) ); EnumTypeInfoMembers( pITypeInfo, pTypeAttr ); _tprintf( _T("\n") ); SysFreeString( pszTypeInfoName ); pITypeInfo->ReleaseTypeAttr( pTypeAttr ); } void EnumTypeInfoMembers( LPTYPEINFO pITypeInfo, LPTYPEATTR pTypeAttr ) { if ( pTypeAttr->cFuncs ) { _tprintf( _T(" Functions:\n") ); for ( unsigned i = 0; i < pTypeAttr->cFuncs; i++ ) { FUNCDESC * pFuncDesc; pITypeInfo->GetFuncDesc( i, &pFuncDesc ); BSTR pszFuncName; pITypeInfo->GetDocumentation(pFuncDesc->memid, &pszFuncName,0,0,0); _tprintf( _T(" %-32ls"), pszFuncName ); _tprintf( _T(" (%ls)\n"), GetInvokeKindName(pFuncDesc->invkind) ); pITypeInfo->ReleaseFuncDesc( pFuncDesc ); SysFreeString( pszFuncName ); } } if ( pTypeAttr->cVars ) { _tprintf( _T(" Variables:\n") ); for ( unsigned i = 0; i < pTypeAttr->cVars; i++ ) { VARDESC * pVarDesc; pITypeInfo->GetVarDesc( i, &pVarDesc ); BSTR pszVarName; pITypeInfo->GetDocumentation(pVarDesc->memid, &pszVarName,0,0,0); _tprintf( _T(" %ls\n"), pszVarName ); pITypeInfo->ReleaseVarDesc( pVarDesc ); SysFreeString( pszVarName ); } } } #define CASE_STRING( x ) case x: s = _T(#x); break; LPCTSTR GetTypeKindName( TYPEKIND typekind ) { LPTSTR s = _T("<unknown>"); switch( typekind ) { CASE_STRING( TKIND_ENUM ) CASE_STRING( TKIND_RECORD ) CASE_STRING( TKIND_MODULE ) CASE_STRING( TKIND_INTERFACE ) CASE_STRING( TKIND_DISPATCH ) CASE_STRING( TKIND_COCLASS ) CASE_STRING( TKIND_ALIAS ) CASE_STRING( TKIND_UNION ) } return s; } LPCTSTR GetInvokeKindName( INVOKEKIND invkind ) { LPTSTR s = _T("<unknown>"); switch( invkind ) { CASE_STRING( INVOKE_FUNC ) CASE_STRING( INVOKE_PROPERTYGET ) CASE_STRING( INVOKE_PROPERTYPUT ) CASE_STRING( INVOKE_PROPERTYPUTREF ) } return s; }
Figure 5 Running COMTypeLibDump
VbVarType - TKIND_ENUM Variables: vbEmpty vbNull vbInteger vbLong vbSingle vbDouble vbCurrency vbDate vbString vbObject vbError vbBoolean vbVariant vbDataObject vbDecimal vbByte vbUserDefinedType vbArray VbMsgBoxStyle - TKIND_ENUM Variables: vbOKOnly vbOKCancel vbAbortRetryIgnore vbYesNoCancel vbYesNo vbRetryCancel vbCritical vbQuestion vbExclamation vbInformation vbDefaultButton1 vbDefaultButton2 vbDefaultButton3 vbDefaultButton4 vbApplicationModal vbSystemModal vbMsgBoxHelpButton vbMsgBoxRight vbMsgBoxRtlReading vbMsgBoxSetForeground FileSystem - TKIND_MODULE Functions: ChDir (INVOKE_FUNC) ChDrive (INVOKE_FUNC) EOF (INVOKE_FUNC) FileAttr (INVOKE_FUNC) FileCopy (INVOKE_FUNC) FileDateTime (INVOKE_FUNC) FileLen (INVOKE_FUNC) GetAttr (INVOKE_FUNC) Kill (INVOKE_FUNC) Loc (INVOKE_FUNC) LOF (INVOKE_FUNC) MkDir (INVOKE_FUNC) Reset (INVOKE_FUNC) RmDir (INVOKE_FUNC) Seek (INVOKE_FUNC) SetAttr (INVOKE_FUNC) _B_str_CurDir (INVOKE_FUNC) _B_var_CurDir (INVOKE_FUNC) FreeFile (INVOKE_FUNC) Dir (INVOKE_FUNC) Interaction - TKIND_MODULE Functions: AppActivate (INVOKE_FUNC) Beep (INVOKE_FUNC) CreateObject (INVOKE_FUNC) DoEvents (INVOKE_FUNC) GetObject (INVOKE_FUNC) InputBox (INVOKE_FUNC) MacScript (INVOKE_FUNC) MsgBox (INVOKE_FUNC) SendKeys (INVOKE_FUNC) Shell (INVOKE_FUNC) Partition (INVOKE_FUNC) Choose (INVOKE_FUNC) _B_var_Environ (INVOKE_FUNC) _B_str_Environ (INVOKE_FUNC) Switch (INVOKE_FUNC) _B_var_Command (INVOKE_FUNC) _B_str_Command (INVOKE_FUNC) IIf (INVOKE_FUNC) GetSetting (INVOKE_FUNC) SaveSetting (INVOKE_FUNC) DeleteSetting (INVOKE_FUNC) GetAllSettings (INVOKE_FUNC) CallByName (INVOKE_FUNC) _ErrObject - TKIND_DISPATCH Functions: QueryInterface (INVOKE_FUNC) AddRef (INVOKE_FUNC) Release (INVOKE_FUNC) GetTypeInfoCount (INVOKE_FUNC) GetTypeInfo (INVOKE_FUNC) GetIDsOfNames (INVOKE_FUNC) Invoke (INVOKE_FUNC) Number (INVOKE_PROPERTYGET) Number (INVOKE_PROPERTYPUT) Source (INVOKE_PROPERTYGET) Source (INVOKE_PROPERTYPUT) Description (INVOKE_PROPERTYGET) Description (INVOKE_PROPERTYPUT) HelpFile (INVOKE_PROPERTYGET) HelpFile (INVOKE_PROPERTYPUT) HelpContext (INVOKE_PROPERTYGET) HelpContext (INVOKE_PROPERTYPUT) Raise (INVOKE_FUNC) Clear (INVOKE_FUNC) LastDllError (INVOKE_PROPERTYGET) ErrObject - TKIND_COCLASS
Figure 6 CoClassSymsCallouts.H
#ifdef __cplusplus extern "C" { #endif BOOL __stdcall CoClassSymsBeginSymbolCallouts( PSTR pszExecutable ); BOOL __stdcall CoClassSymsAddSymbol( unsigned short section, unsigned long offset, PSTR pszSymbolName ); BOOL __stdcall CoClassSymsSymbolsFinished( void ); typedef BOOL (__stdcall * PFNCCSCALLOUTBEGIN)( PSTR pszExecutable ); typedef BOOL (__stdcall * PFNCCSADDSYMBOL)(unsigned short, unsigned long,PSTR); typedef BOOL (__stdcall * PFNCCSFINISHED)(void); #ifdef __cplusplus } #endif
Figure 7 Excerpts from CoClassSyms.CPP
• • • //============================================================================ // Top level handling code for a single ITypeInfo extracted from a typelib //============================================================================ void ProcessTypeInfo( LPTYPEINFO pITypeInfo ) { HRESULT hr; LPTYPEATTR pTypeAttr; hr = pITypeInfo->GetTypeAttr( &pTypeAttr ); if ( S_OK != hr ) return; if ( TKIND_COCLASS == pTypeAttr->typekind ) { for ( unsigned short i = 0; i < pTypeAttr->cImplTypes; i++ ) { HREFTYPE hRefType; hr = pITypeInfo->GetRefTypeOfImplType( i, &hRefType ); if ( S_OK == hr ) ProcessReferencedTypeInfo( pITypeInfo, pTypeAttr, hRefType ); } } pITypeInfo->ReleaseTypeAttr( pTypeAttr ); } //============================================================================ // Given a TKIND_COCLASS ITypeInfo, get the ITypeInfo that describes the // referenced (HREFTYPE) TKIND_DISPATCH or TKIND_INTERFACE. Pass that // ITypeInfo to EnumTypeInfoMembers. //============================================================================ void ProcessReferencedTypeInfo( LPTYPEINFO pITypeInfo_CoClass, LPTYPEATTR pTypeAttr, HREFTYPE hRefType ) { LPTYPEINFO pIRefTypeInfo; HRESULT hr = pITypeInfo_CoClass->GetRefTypeInfo(hRefType, &pIRefTypeInfo); if ( S_OK != hr ) return; LPTYPEATTR pRefTypeAttr; pIRefTypeInfo->GetTypeAttr( &pRefTypeAttr ); LPUNKNOWN pIUnknown = 0; hr = CoCreateInstance( pTypeAttr->guid, 0, // pUnkOuter CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, pRefTypeAttr->guid, (LPVOID *)&pIUnknown ); if ( (S_OK == hr) && pIUnknown ) { EnumTypeInfoMembers( pIRefTypeInfo, pRefTypeAttr, pIUnknown ); pIUnknown->Release(); } pIRefTypeInfo->ReleaseTypeAttr( pRefTypeAttr ); pIRefTypeInfo->Release(); } //============================================================================ // Enumerate through each member of an ITypeInfo. Send the method name and // address to the CoClassSymsAddSymbol function. //============================================================================= void EnumTypeInfoMembers( LPTYPEINFO pITypeInfo, // The ITypeInfo to enum. LPTYPEATTR pTypeAttr, // The associated TYPEATTR. LPUNKNOWN lpUnknown // From CoCreateInstance. ) { // Only call CoClassSymsBeginSymbolCallout once static BOOL fCalledBeginCallout = FALSE; if ( FALSE == fCalledBeginCallout ) { char szFileName[MAX_PATH]; wcstombs( szFileName, g_pszFileName, MAX_PATH ); fCalledBeginCallout = g_pfnCoClassSymsBeginSymbolCallouts(szFileName); } // Make a pointer to the vtable. PBYTE pVTable = (PBYTE)*(PDWORD)(lpUnknown); if ( 0 == pTypeAttr->cFuncs ) // Make sure at least one method! return; // Get the name of the ITypeInfo, to use as the interface name in the // symbol names we'll be constructing. TCHAR pszInterfaceName[256]; GetTypeInfoName( pITypeInfo, pszInterfaceName ); // Enumerate through each method, obtain its name, address, and ship the // info off to CoClassSymsAddSymbol() for ( unsigned i = 0; i < pTypeAttr->cFuncs; i++ ) { FUNCDESC * pFuncDesc; pITypeInfo->GetFuncDesc( i, &pFuncDesc ); TCHAR pszMemberName[256]; GetTypeInfoName( pITypeInfo, pszMemberName, pFuncDesc->memid ); // Index into the vtable to retrieve the method's virtual address DWORD pFunction = *(PDWORD)(pVTable + pFuncDesc->oVft); // Created the basic form of the symbol name in interface::method // form using ANSI characters char pszMungedName[512]; wsprintfA( pszMungedName,"%ls::%ls", pszInterfaceName,pszMemberName ); INVOKEKIND invkind = pFuncDesc->invkind; // If it's a property "get" or "put", append a meaningful ending. // The "put" and "get" will have identical names, so we want to // make them into unique names if ( INVOKE_PROPERTYGET == invkind ) strcat( pszMungedName, "_get" ); else if ( INVOKE_PROPERTYPUT == invkind ) strcat( pszMungedName, "_put" ); else if ( INVOKE_PROPERTYPUTREF == invkind ) strcat( pszMungedName, "_putref" ); // Convert the virtual address to a logical address unsigned short section; unsigned long offset; if ( VAToSectionOffset((PVOID)pFunction, section, offset) ) g_pfnCoClassSymsAddSymbol( section, offset, pszMungedName ); pITypeInfo->ReleaseFuncDesc( pFuncDesc ); } } • • •
Figure 8 Generating .MAP Files
#include <windows.h> #include <imagehlp.h> #include <stdio.h> #include <stdlib.h> //=========================== Global Variables =============================== LOADED_IMAGE g_loadedImage; FILE * g_pMapFile; //============================================================================ BOOL __stdcall CoClassSymsBeginSymbolCallouts( LPCSTR pszExecutable ) { if ( !MapAndLoad( (LPSTR)pszExecutable, 0, &g_loadedImage, FALSE, TRUE ) ) { printf( "Unable to access or load executable\n" ); return 0; } char szExeBaseName[MAX_PATH]; char szMapFileName[MAX_PATH]; _splitpath( pszExecutable, 0, 0, szExeBaseName, 0 ); sprintf( szMapFileName, "%s.MAP", szExeBaseName ); g_pMapFile = fopen( szMapFileName, "wt" ); if ( !g_pMapFile ) return FALSE; fprintf( g_pMapFile, " Start Length Name Class\n" ); PIMAGE_SECTION_HEADER pSectHdr = g_loadedImage.Sections; for ( unsigned i=1; i <= g_loadedImage.NumberOfSections; i++, pSectHdr++ ) { fprintf( g_pMapFile, " %04X:00000000 %08XH %-23.8hs %s\n", i, pSectHdr->Misc.VirtualSize, pSectHdr->Name, pSectHdr->Characteristics & IMAGE_SCN_CNT_CODE ? "CODE" : "DATA" ); } fprintf( g_pMapFile, "\n Address Publics by Value Rva+Base\n\n"); return TRUE; } BOOL __stdcall CoClassSymsAddSymbol( unsigned short section, unsigned long offset, PSTR pszSymbolName ) { if ( !g_pMapFile ) return FALSE; fprintf( g_pMapFile, " %04X:%08X %-32s\n", section, offset, pszSymbolName ); return true; } BOOL __stdcall CoClassSymsSymbolsFinished( void ) { if ( !g_pMapFile ) return FALSE; DWORD entryRVA = g_loadedImage.FileHeader->OptionalHeader.AddressOfEntryPoint; PIMAGE_SECTION_HEADER pSectHdr; pSectHdr = ImageRvaToSection( g_loadedImage.FileHeader, g_loadedImage.MappedAddress, entryRVA ); if ( pSectHdr ) { // Pointer math below!!! WORD section = (WORD)(pSectHdr - g_loadedImage.Sections) +1; DWORD offset = entryRVA - pSectHdr->VirtualAddress; fprintf( g_pMapFile, "\n entry point at %04X:%08X\n", section, offset ); } fclose( g_pMapFile ); UnMapAndLoad( &g_loadedImage ); // Undo the MapAndLoad call return TRUE; }