Ripsaw Library Implementation

In this installment of the Ripsaw article series we’ll start putting some actual code into an implementation of the COM interfaces that we specified in the last article. For those of you who just joined the series, Ripsaw is a log viewer for Windows, similar to the Unix tail utility. This series of articles details my rewrite of the application from the ground up.

So far, we have a test script implemented in JavaScript (or JScript, if you want to be really picky) that is intended to exercise our COM interfaces. There is a base interface that represents a generic log that a client might wish to follow, a more specific interface representing a file, and a dispinterface declaring the events that a Ripsaw library object can fire. In this article we’ll start implementing these interfaces, with the goal of providing just enough functionality to allow us to execute the test script.

I’m implementing this project with Visual Studio 2010, which is still in beta as of this writing. You may download the solution, projects, and source code if you’d like to follow along, but if you haven’t downloaded and installed the 2010 beta yet, you’ll need to adapt the code to your IDE and C++ compiler of choice if you wish to build it (I recommend Visual Studio 2008).

Implementing the COM Interfaces

To briefly recap the design, there will be a Ripsaw COM library that exports objects representing sources of updates, and a Ripsaw client (such as a log viewer or a script) will create objects that fire events whenever the source changes its status. Now that we’ve specified the interfaces, it’s time to implement them just enough to run the test script that we created in the last installment. I like to use ATL to implement the low-level, boilerplate code that’s necessary for IUnknown and IDispatch, though once the wizard is done I usually take over and move all the generated code around. I’ve never liked round-trip development with code generators.

There are three interfaces (for now) that need to be implemented: IRipsawObject, IRipsawFile, and _IRipsawEvents. The first interface is the base interface for not only IRipsawFile but other potential interfaces that might be added later on as the library is developed. That means I want to create the implementation in such a way that I can easily extend it to other sources of data that Ripsaw might use. Unfortunately, if I took the code that the ATL wizard spat out, I’d have a really difficult time reusing it. I need to split the ATL code into a generic interface implementation and a concrete object implementation.

In ATL, when implementing an object derived from IDispatch, you usually get a class definition that looks like this:

That works fine, until it doesn’t. If you ever want to derive a class from RipsawFile, you’re going to run into problems. What I usually do is replace IDispatchImpl with my own template class that derives from IDispatchImpl and implements the interface that my object is going to expose. In this case, I want my object to expose both IRipsawFile and IRipsawObject, so I’ll start by creating a generic template implementation of the base IRipsawObject interface. The template will be defined in a header file named IRipsawObjectImpl.h.

There is quite a bit going on in this template, so let’s go over its various parts.

The Root Type

If you look back at the example class definition for RipsawFile, you’ll see that it derived from CComObjectRootEx<CComMultiThreadModel>. This is because, when the wizard generated the code, the user selected the option to generate an object that was free-threaded. This is an implementation detail of the object, not of the interface, so that’s the first thing we need to abstract away from our generic implementation of the IRipsawObject interface. The problem, however, is that CComObjectRootEx provides a lot of useful types that we should take advantage of, such as methods for guarding blocks of code that need to be serialized when accessed from multiple threads. What I decided to do was make Root a template parameter and derive the implementation from that type. The concrete implementation may provide any type for this parameter as long as it implements the definitions expected from that type, such as ObjectLock.

The IDispatchImpl Type

This is a class that is provided by ATL to implement the ugly details of IDispatch. While the average COM developer can (usually) implement a workable IUnknown rather easily, implementing IDispatch is a good deal more complicated. We know, based on our IDL, that IRipsawObject is derived from IDispatch, so this is an implementation detail that’s appropriate for our generic implementation. Classes that derive from IRipsawObject will also pick up the IDispatch implementation. All of the template parameters to IRipsawObjectImpl after Root are passed along to IDispatchImpl.

Notify_Open, Notify_Close, and Notify_Update

All objects that implement the IRipsawObject interface are expected to fire events to notify clients about open, close, and update events. How these events are generated is an implementation detail best left to the concrete object implementation, but I may need to fire events from the generic implementation. I decided to create stub methods that will be overridden in the concrete implementation.

The Rest of the Code

The remainder of the header is devoted to minimal implementations of the methods and properties defined in the IRipsawObject interface. Most of these will be overridden in IRipsawFile and other derived interfaces. Note that the implementations use InterlockedExchange and ObjectLock to serialize access to internal data. This is because we want to allow the generic implementation to work for free-threaded object implementations, which may be called by more than one thread at a time. The ObjectLock type is expected to be provided by the Root template parameter.

I Could Use Some More Cowbell

This still isn’t enough code to create a usable IRipsawFile implementation, but since that’s the default interface that we need to expose from our COM object we’ll have to derive another generic implementation from IRipsawObject that will let us finally execute our test script. We’ll tackle that template class in the next installment in the series. If you want to cheat and peek ahead, look at the file IRipsawFileImpl.h in the source code.


Leave a Reply

Your email address will not be published.