Initial Problems with TraceSrv

[Previous] [Next]

The first problem occurred after I got TraceSrv up and running and had connected to it from multiple client processes. My design requirements state that all clients will use the same instance of TraceSrv. When I was testing, each process that was connecting was getting its own copy of the ITrace interface, so there was no way that a trace viewer would ever see the output from multiple processes.

This problem had me stumped because I didn't think it would be that hard to make a single-instance interface. After fumbling around for a day, I was ready to override IClassFactory::CreateInstance and force it always to return a single ITrace interface. Although this modification would've changed the expected behavior of CreateInstance, at least it would've allowed only one instance. Fortunately, while poking through the ATL code, I ran across the CComClassFactorySingleton class, which the documentation says is used to create a single instance—exactly what I needed. This class is handled by the DECLARE_CLASSFACTORY_SINGLETON (CTrace) macro in TRACE.H. This bug was caused by my ignorance of ATL.

Once I started using TraceSrv, I noticed that CComBSTR was doing all those allocations and deallocations on almost every method call. After developing the CFastBSTR class, I thought I was ready for smooth testing. As I started testing various scenarios, I was getting an assertion at the end of CTrace::ProcessTrace, which you can see in Listing 11-2. In TraceSrv, I'm using the assertion macros that I introduced in Chapter 3, and because TraceSrv is designed to be a service, I called SetDiagAssertOptions and turned off the message box display.

I was getting the assertion when I was running TraceSrv with no viewers attached. I walked through Fire_TraceEvent code, which was generated by the Implement Connection Point command in the integrated development environment (IDE), and noticed something very interesting. The code for the original Fire_TraceEvent is shown in Listing 11-3. Take a careful look at the code and see whether you can spot the bug.

Listing 11-3 Fire_TraceEvent with a bug

 HRESULT Fire_TraceEvent( BSTR bstrText ) { CComVariant varResult; T* pT = static_cast<T*>( this ); int nConnectionIndex; CComVariant* pvars = new CComVariant[1]; int nConnections = m_vec.GetSize( ); for ( nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++ ) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt( nConnectionIndex ); pT->Unlock( ); IDispatch* pDispatch = reinterpret_cast<IDispatch*>( sp.p ); if (pDispatch != NULL) { VariantClear( &varResult ); pvars[0] = bstrText; DISPPARAMS disp = { pvars, NULL, 1, 0 }; pDispatch->Invoke( 0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL ); } } delete[] pvars; return varResult.scode; }

Keep in mind that my assertion triggered only when I didn't have any viewers attached to TraceSrv. As you look carefully at Fire_TraceEvent, you'll see that the for loop never executes when a viewer isn't attached. However, the generated code returns varResult.scode, which is initialized only inside the for loop. Consequently, the function returns an uninitialized value when no viewers are attached. In debug builds, Fire_TraceEvent was returning 0xCCCCCCCC, the fill pattern the /GZ compiler switch puts into local variables.

The workaround to the uninitialized variable problem was rather simple. I renamed the file that Implement Connection Point generated, TRACESRVCP.H, to CORRECTEDTRACESRVCP.H, and after the declaration of varResult, I set varResult.scode equal to S_OK. Although using uninitialized variables isn't a recommended programming practice, at least the Visual C++ developers are now returning the results of IDispatch::Invoke calls. In previous versions of Visual C++, they didn't. Once I fixed this small problem, TraceSrv was up and running fairly well.

Before I can wrap up this chapter, I need to cover TraceView, Win32 security, and calling TraceSrv from your code.



Debugging Applications
Debugging Applications for MicrosoftВ® .NET and Microsoft WindowsВ® (Pro-Developer)
ISBN: 0735615365
EAN: 2147483647
Year: 2000
Pages: 122
Authors: John Robbins

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net