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;
}