TraceHook

Keith's Browns most excellent Universal Delegator provides a mechanism for inserting arbitrary code between a client and an object. The TraceHook is a UD Hook that traces method calls by object name, interface name and member function name (if the interface is described in a typelib) and dumps the result to the debug output. In addition, if the interface is described in a typelib, all automation-compliant arguments are dumped.

TraceHook's home is http://www.sellsbrothers.com/tools/index.htm#tracehook.

Usage

To use, register the the redist\delegate.dll and the redist\udtracehooksvr.dll COM servers using regsvr32. Copy the itfs.bin to c:\winnt\system32 (or equivalent) A batch file \redist\install.bat can be used to perform the above 3 actions. In the client, include redist\tracehookcli.h and wrap each interface to trace in the TRACKHOOK macro, e.g.

// Get a COM object to wrap
CComPtr<ICalc>  spCalc;
spCalc.CoCreateInstance(CLSID_Calc);

// Wrap it (when _DEBUG is defined only)
TRACEHOOK(OLESTR("MyCalc"), &spCalc.p);

// Use it
spCalc->put_Sum(0);
spCalc->Add(2);
spCalc->Add(2);
long nSum;
spCalc->get_Sum(&nSum);

At runtime, this will result in the following debug output:

MyCalc, ICalc::put_Sum(0)
MyCalc, ICalc::Add(2)
MyCalc, ICalc::Add(2)
MyCalc, ICalc::put_Sum()

alternatively to have the TraceHook automatically wrapped during object creation, you can use the DECLARE_CLASSFACTORY_DEBUGTRACER macro in the object header file (again this is only active for debug builds), e.g.

class ATL_NO_VTABLE CCalc : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CCalc, &CLSID_Calc>,
	public IDispatchImpl<ICalc, &IID_ICalc, &LIBID_CALCSVRLib>
{
public:
	CCalc()
	{
	}

DECLARE_CLASSFACTORY_DEBUGTRACER(CCalc, "calc")
DECLARE_REGISTRY_RESOURCEID(IDR_CALC)
DECLARE_NOT_AGGREGATABLE(CCalc)
DECLARE_PROTECT_FINAL_CONSTRUCT()

// rest of definition

Script Usage

If you're created COM objects from a scripting environment and you'd like to trace those calls as well, you can use TraceHook's implementation of ITraceHookFactory:

interface ITraceHookFactory : IDispatch
{
    [id(1)] HRESULT ComTrace([in] BSTR bstrObjectName, [in,out] VARIANT * pVarObject);
};

For example, using the Windows Scripting Host, a sample VBS file would look like this:

' Create the implementation of ITraceHookFactory
set th = CreateObject("UDTraceHookSvr.TraceHook")

' Create an object (an <object> tag in HTML would be fine, too)
set calc = CreateObject("CalcSvr.Calc")

' Trace all further calls on calc
th.ComTrace "MyCalc", calc

calc.sum = 0
calc.add 2
calc.add 2
msgbox "2+2= " & calc.sum

The resulting debug output would look like this:

MyCalc, IDispatch::(Invoke) sum(0)
MyCalc, IDispatch::(Invoke) add(2)
MyCalc, IDispatch::(Invoke) add(2)
MyCalc, IDispatch::(Invoke) sum() returned 4

Method Names for non typelib based interfaces

The TraceHook can display the method names for interfaces that are not defined in a type library, if they are defined in the file itfs.bin. This file is a structured storage file that contains the method names per interface. The supplied file contains all the standard interface definitions from VC6. New interfaces can be added if you have the MIDL generated header (note you do not actually need the IDL file), using the suplied scripts. The two scripts are

import.bat

This takes a single MIDL generated header, parses it and adds all the contained interface / method names from the header to the itfs.bin file.

files.pl

This takes a directory, and runs import.bat for each file that is a MIDL generated header file.
After running either script remember to copy the itfs.bin file from the scripts directory to winnt\system32.

Script Installation

The scripts rely on both the file AddToDefs.exe (source is in \src\addtodefs), and Perl. before running either of the scripts, Perl for Win32 must be installed and working. (These scripts were developed and tested with Perl v5 Build 110). Perl for Win32 can be downloaded from www.activestate.com

What's Missing

If you've added these features, or any bug fixes, to TraceHook, please send them to me so that I may integrate the changes into the source. Thanks.

Source

The UDTraceHookSrv project contains the source for the CTraceHook class, which is what the TRACEHOOK macro creates, and the CTraceMethodHook class, which is what does the actual method tracing. CTraceHook implements ITraceHook (an interface custom to the TraceHook ) and IDelegatorHookQI (required by the UD). The CTraceMethodHook class implements ITraceMethodHook (an interface custom to the TraceHook) and IDelegatorMethodHookMethods2 (also required by the UD).

The CTraceMethodHook::DelegatorPreprocess method is where all the action is. It maps the vtbl index provided by the UD to a specific method on an interface and prints the debug output. This would be where there would be special tables for standard interfaces for dumping their methods.

The test project is a client for testing the TraceHook. The CalcSvr project is a COM server for use in testing the TraceHook (as well as high precision math).

Copyright

TraceHook is copyright (c) 1999 by Chris Sells and Simon Fell
All rights reserved.
Use at your own risk.

All copyrights for Keith Brown's Universal Delegator belongs to him.