Thunderclap, the Newsletter of Rolling Thunder Computing

Volume 2, Number 1 Fall 1999

In this issue:
About Thunderclap
Subscription Information
Feature Article: The Compensating Resource Manager in COM+
New Book on COM+ by David Platt, published by Microsoft Press
Blatant Self Promotion
Contest with Prizes: Computer Oxymorons
Results of Last Contest: Country-Western Song Titles

About Thunderclap

Welcome to the second year of my (more or less) quarterly newsletters. Each brings you a technical article on COM or COM+ development, which I hope you will find useful. Each will also bring you a contest, allowing you to show off your intelligence and creativity to win prizes, which I hope you will find funny (although some readers have reported the reverse.) In between you will find my own blatant self promotional material, telling you about the latest ways I've come up with to separate you from your money. (I could have said "carefully selected products and services that we feel might interest you", or other mealy-mouthed horsepuckey. You want the truth or you want me to waste my time and yours dressing it up?)

This newsletter may be freely redistributed, provided that it is sent in its entirety. If you enjoyed it, why not forward it to a friend who might also enjoy it? The subscription roll has grown from nothing a year ago to over 1200 for this issue. I'd like to hear what you think about this newsletter and what types of articles you'd like to see in the future. 

Subscription Information

Thunderclap is free, and is distributed via e-mail only. We never rent, sell or give away our mailing list. Subscription and unsubscription are handled by a human operator reading e-mail messages. To subscribe or unsubscribe, jump to the Rolling Thunder Web site and fill in the subscription form.

Feature Article: The Compensating Resource Manager in COM+

(This article assumes a conceptual familiarity with transactioning in COM)

It’s very easy for an object to participate in a transaction as a client of a Resource Manager (RM), but writing an RM has historically been hellishly difficult. If you study the complex dance that an RM has to do with the  DTC in the two-phase commit process, and the failure recovery requirements, and perhaps look at the sample RM in the MTS SDK, you will see just what a colossal pain in the ass it is, which is why there are so few today (major commercial databases and MSMQ, that’s about it).  The physics major I once was finds this philosophically satisfying; it means that the amount of crap in the universe is conserved. Making things easier for the client makes them harder for the server, and vice versa. But practically speaking, this doesn’t help you write an RM.

Why would you want to do this? It makes sense when coordinating any irreversible action in a distributed environment. For example, suppose you wanted to delete a file, or save changes to an edited file, but only if everyone else agreed. That would be a great place to write a transactional file deleter. There’s an even simpler reason you might want to do this. Objects participating in transactions don’t currently find out whether the transaction committed or aborted; only the enlisted RMs know that. An object might want to find out whether the transaction it was working on committed or aborted so that it could cache resources for later use, instead of having to dump them to maintain transactional correctness. Unfortunately, until now, writing an RM to obtain this information was far too difficult and expensive to be useful for mere mortal middle-tier programmers.

That has now changed with the appearance of Compensating Resource Manager (CRM) support in COM+. Microsoft realized that many of the things an RM had to do were generic, that is, they are common to all RMs. For example, every RM has to recognize the presence of a transaction in its client's context and negotiate with the DTC to enlist in that transaction.  Every RM has to write a durable log file to keep track of what was doing in case it crashes. And every RM has to do the two-phase commit dance with the DTC. So as is the case throughout COM+, Microsoft said, “Well, if these things are common to most implementations, then why don’t we provide a prefabricated version that the wise people who buy our operating system can just inherit?”

The prefabricated functionality is the CRM Clerk.  This is an object, provided by the operating system, that handles the negotiations with the DTC, recognizing, enlisting in, and receiving notifications for transactions.  It provides a durable log file that components can use, instead of having to write their own. And it also handles failure recovery from this durable log file in the event of a crash during a transaction. Using the CRM Clerk makes it much, MUCH easier for you to write your own RMs, thereby allowing you to provide whatever functionality you care to in a transactional manner. RMs that use the CRM Clerk are known as Compensating Resource Managers, or CRMs.

The name "Compensating Resource Manager" makes you think of a compensating transaction, which is an equal-but-opposite transaction that undoes the effect of a previous transaction. The credit that you see on your Visa bill when you return something to a store is a compensating transaction. Unfortunately, this has nothing whatsoever to do with the CRM. Microsoft is bad at nomenclature; so bad that I coined a term in my latest column in Byte.Com to describe their miscues. The term is MINFU, which in polite company stands for Microsoft Nomenclature Foul-Up. Using the 'C' word to describe RMs of this type is a MINFU. The term "Visual Editing" (to distinguish it from tactile editing, I imagine, or perhaps olfactory editing) is a MINFU. Renaming COM to OLE (1994), then back to COM (1995), then ActiveX (1996), was and is one giant MINFU. 

A sample CRM comes with the Platform SDK, but it’s several versions old and doesn’t work with the current releases of Windows 2000 (I’m running RC2).  So I’ve written a sample CRM for you to play with, which you can download by clicking here. (You know you’re a geek if you consider a CRM something to play with.) It doesn’t do much, just pops up message boxes in each function call, so you can see who is doing what to whom. The sample code is written in C++, but there's no reason you couldn't write a CRM in VB or any other COM-aware language.

I've provided an export file called "RtCrmDemo.msi", which you will find in the "\Deploy" subdirectory. If you simply run this file, it will make all the installation settings for the proper operation of the sample code (at least it should, famous last words). I did this with the "Export..." feature of the COM+ catalog, which may be the subject of another newsletter article some day. If for some reason this doesn't work, or if you don't want to trust it, create a new application  using the Component Services Snap-In (or whatever they’re calling it this week, watch for another MINFU).  On the “Advanced” tab,  check the “Enable Compensating Resource Managers” box. This sets up administrative entries, among other things, creating the durable log file, which you can find in the \system32\dtclog directory. It will have the app id as its name and the extension “.crmlog”.  Then add the two components. Mark the worker as requiring a transaction. Mark the compensator as transaction = disabled, synch = disabled, JIT activation = no.

A CRM consists of  two COM+ components that have intimate knowledge of each other. The first is called the CRM Worker. This is the object that a client app creates and calls methods on. The worker exposes your own custom VTBL or IDispatch interface, providing whatever business logic you think your customers want to buy. What makes it a CRM Worker instead of  just a plain old middleware object is that it does its work in such a way that the second component, the CRM Compensator, is able to undo it if necessary when the transaction closes. For example, suppose you were to write a CRM that provided transactional deletion of files (which the SDK sample does). The worker would rename the file, the compensator would actually delete the file if the transaction later committed, or restore its original name if the transaction aborted.

For its part of the dance, the worker first creates the CRM Clerk, obtaining a pointer to the ICrmLogControl interface. The worker then calls the method ICrmLogControl::RegisterCompensator( ), thereby telling the clerk which compensator to launch when it is time to commit or abort the transactions. Thus:

HRESULT CMyOwnCrmWorker::Activate()
      HRESULT hr = GetObjectContext(&m_spObjectContext);

      CLSID clsid ;
      CLSIDFromProgID (L"CrmClerk.CrmClerk.1", &clsid) ;

Create the CRM Clerk object, provided by the operating system.

      hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER, 
            (void **)&m_pLogControl);

Tell the clerk which compensator to launch when this transaction commits or aborts.

hr = m_pLogControl->RegisterCompensator(
          L"WorkerAndCompensator.MyOwnCrmCompensator", // compensator progid
          L"description goes here",                 // description
          COMSVCSLib::CRMREGFLAG_ALLPHASES);        // flags

     return hr;

The worker then performs its business logic in whatever manner you think it should. As it does its thing, the worker uses the clerk to write records to the application's durable log file. These records are later passed by the CRM Clerk to the compensator when the transaction closes. The sample program does nothing but write this log, via the method ICrmLogControl::WriteLogRecord( ), which takes all of its data in the form of blobs. Thus:

STDMETHODIMP CMyOwnCrmWorker::DoSomethingInTransaction(
    BSTR TextDescription)

    HRESULT hr = S_OK;
Assemble data to write log record.

      COMSVCSLib::BLOB blobs [1]  ;
      blobs[0].pBlobData = (unsigned char *) ((char*) desc) ;
      blobs[0].cbSize = desc.length( ) * 2 ;

Write record to the durable log saying what we've done.

      hr = m_pLogControl->WriteLogRecord (blobs, 1) ;  

      return S_OK;

The CRM Compensator is a COM+ component that you write that implements the ICrmCompensator interface. Its methods are:


Delivers an ICrmLogControl Interface to the CRM Compensator so that it can write further log records during transaction completion.


Notifies the CRM Compensator of the prepare phase of the transaction completion and that records are about to be delivered.


Delivers a log record in forward order during the prepare phase.


Notifies the CRM Compensator that it has had all the log records available during the prepare phase.


Notifies the CRM Compensator of the commit phase of the transaction completion and that records are about to be delivered.


Delivers a log record in forward order during the commit phase. 


Notifies the CRM Compensator that it has delivered all the log records available during the commit phase.


Notifies the CRM Compensator of the abort phase of the transaction completion, and that records are about to be delivered.


Delivers a log record to the CRM Compensator during the abort phase.


Notifies the CRM Compensator that it has received all the log records available during the abort phase.

The CRM clerk will create the compensator when the transaction closes. It knows which compensator to create because the worker passed the compensator's ProgID in the call to ICrmLogControl::RegisterCompensator( ) shown earlier. The clerk will call the compensator's  methods, passing it the durable log file records that the CRM worker wrote earlier. It is up to the compensator to do the right thing either to commit the transaction by confirming the the work done by the worker, or to abort it by undoing that work. 

If the transaction commits, the clerk will call your compensator’s BeginPrepare, PrepareRecord, and EndPrepare methods. The first two in the sample code simply pop up informational message boxes. The last method contains a parameter that the compensator uses to signal the clerk, and thence the DTC, whether or not it has been successful at preparing to commit the transaction. My sample pops up a message box to ask you. Thus: 

HRESULT CMyOwnCrmCompensator::EndPrepare(BOOL *pfOkToPrepare)

Get choice from user. Signal successful or unsuccessful prepare based on user's choice.

  if (MessageBox (NULL, "OK to Commit?", 
    "RtCrmDemo ICrmCompensator::EndPrepare", 
     MB_YESNO) == IDYES)
        *pfOkToPrepare = TRUE;
      *pfOkToPrepare = FALSE ;

    return S_OK;

If the transaction commits, then the clerk will call the compensator's BeginCommit, CommitRecord, and EndCommit methods. If the transaction aborts, then the clerk will not ask the compensator to prepare. It will simply call the BeginAbort, AbortRecord, and EndAbort methods. Again, you will see all of these with message boxes.

So run the client app; it looks like this:


Click create, wait for it to happen. Then click “DoSomething”  as many times as you want, varying the log text as you like. Then click commit or abort. You will see message boxes informing you of the progress of the two-phase commit process through the worker and compensator. 

It looks easy, and it is in fact several orders of magnitude easier than the other way. There are still lots of things to think about. A CRM provides durability (through the log file) and atomicity, by enlisting in the DTC to participate in the transaction with other components.  It doesn’t provide isolation; you have to write that yourself in whatever way makes sense for your worker's business logic. Also, you have to think about the order in which things are done. For example, the worker needs to make sure that it writes to the log before it actually does its work; otherwise it might crash after it did the work but before it logged the work for possible later undoing by the compensator. This in turn means that you have to write the compensator to properly attain a consistent state if it can't find the work that the log file says it should.  For another example, suppose the compensator crashes during a recovery, the same log file record could be processed more than once. This means that you have to make the log file information idempotent, which means that it produces the same result no matter how many times it runs. Adding $100 to an account balance is not an idempotent operation, whereas setting an account balance to $500 is idempotent. 

Enjoy playing with the CRM. Give me a call if I can help you out. And as Red Green  would say, until next time, "Keep your stick on the ice."

New Book: Understanding COM+

by David S. Platt, President of Rolling Thunder Computing

Published by Microsoft Press

ucompluscvr.jpg (8012 bytes)

It's been a long haul, but I finally finished my book on COM+. It's entitled Understanding COM+, published by Microsoft Press,  ISBN 0-73560-666-8. It's a different approach than my other books, more of a conceptual overview than a wealth of cut-and-paste code. I'm using the same format that David Chappell did in his very successful Understanding ActiveX and OLE, published by Microsoft Press in 1996. It has been or is being translated into Japanese, German, Italian, Korean, and two flavors of Chinese. 

The first review of this book on said:

"A reader from Tucson, Arizona , July 25, 1999 [5 stars] great little book! 
This book presents the new features of COM+ in an extremely intelligent and sometimes very humorous way. Its focus is definitely not on the mechanics of the new components, but rather on their high-level purpose along with design and architectural issues. This allows the reader to gain perspective rapidly as the messy details are left to the Windows 2000 documentation.

Bits of brilliant philosophical insight are included. Read the epilogue and you can justify your comfy six-figure salary."

Blatant Self Promotion

New In-House Training Class on COM+

Rolling Thunder Computing is pleased to announce its new in-house training class on COM+. This three or four day training class will cover all the portions of COM+, including that catalog, security, synchronization and threading, transactions, queued components, and loosely coupled events. You can read all about it on Rolling Thunder Computing's web site,

Queued Components in Connecticut in October

I'll be giving a talk on Queued Components at the Connecticut COM SIG on Wednesday, October 13. Doors open for networking and pizza at 5:30, announcements at 6:00, main presentation at 6:15. Full information and directions are at

Keynote at Eastern Canada PDC

I'll be giving a keynote talk at Microsoft's Eastern Canada Developers' Conference in Ottawa. The conference is at the Palais de Congres in Hull, Quebec, 5 minutes from downtown Ottawa, from Nov 8-10. My talk is an Overview of COM+, from 9:00 - 10:30 on Tuesday Nov 9. Full  information is at

COM+ in Iceland in November

Iceland is fast becoming per-capita the most  COM-aware country in the world. I taught 19 students in a class there last January, out of a total population of 275,000 souls in the entire country. In per-capita terms, that's like Billy Joel selling out Madison Square Garden in the US (well, sort of). I'm now coming back to teach a 3-day advanced COM+ class on November 15-17. There were still three seats available at the time of this writing. The class will be taught in English, at the University of Iceland in Reykjavik on . For information, see Select the link "námskeið" and then "hugbúnaður" and it is course number 196.

OLE for Life Insurance in Miami in January

I'll be teaching the next public class on OLE for Life Insurance in Miami in January, sponsored by FDP Corp. The exact dates are January 12-14 (Wed-Fri) and January 17-19 (Mon-Wed), 2000.  For more information on this class or OLifE in general, see

Advance notice – Harvard in the spring.

I'll be teaching my class CSCI-E218, Programming COM+, COM, ActiveX, and OLE, at Harvard Extension in the Spring 2000 term, provided of course that civilization doesn't collapse as a result of the Y2K bug. The class is designed for practicing programmers and is open to the public. It meets Thursday nights at 7:35 PM, beginning on February 3 in Lecture Hall E (downstairs) at the Harvard Science Center. The class grants 4 units of graduate credit and costs $1250. I don't have the 2000 syllabus written yet, but it will be substantially similar to last year's, which you can find at

New Contest with Prizes: Computer Oxymorons

I've always been fascinated by oxymorons, which are self-contradictory phrases, for example, "jumbo shrimp", or "Clinton ethics." Although the phrase seems to make sense at first glance, upon further reflection, you realize that the words contradict each other; that there just ain't no such thing. Those of us who travel frequently would probably agree that "airline schedule" is an oxymoron, and so is "airline food". The word comes from the Greek roots "oxus", meaning "sharp", and "moros", meaning "dull."   For this contest, you are to submit one or more computer-related oxymorons. For example:

Enough RAM

Microsoft Tech Support

VB Programmer

I find that generating oxymorons is an activity that yields well to communal brainstorming while drinking lots of beer. Your entries must be computer-related and original. This isn't a family newsletter, so they don't have to be clean or politically correct. Submitting more than one increases your chances of winning. First prize is $100, second prize $50. Winners will be announced in the next issue of Thunderclap, and the judge's decision (mine) is final. In the event of duplicate or similar entries, the earliest wins. All entries become property of Rolling Thunder Computing.  All authors will be identified by first and last names, but not by company. Authors names will be withheld if you so request. Submit your entries via e-mail to

Results of Last Contest: Geeky Country-Western Song Titles

Here are the results of the last contest, in which you were asked to provide geeky country-western song titles:

First prize, $100 to Al Mele, who can use it to buy a cure:

I Stuck My Disk In the Drive With No Write Protection, Now I'm Holding A Floppy With a Viral Infection

Second prize to Lloyd Chumbley, continuing the proud tradition of VB bashing in this newsletter:

"Momma, Don't Let PC's Compile Visual Basic"

And honorable mention to all:

It Don't Mean a Thin' if You Cain't Make It Spin - C.D. Rom
If Bugs Don't Bite Then Why the Hell Does My ASSERT?
If You Were Smart Enough to Program You Wouldn't Be Testing

     -- Al Mele

"It's Been Lonely on the Airplane, Since my Battery Died"

    -- Lloyd Chumbley

If I said you had a beautiful laptop, would you hold it against me?, by Mike Dell and the del Fuegos

    -- David Hostler

You may have GPS on your PDA but you won't find me till ICQ. -- by the TLAs. 
My dog died (but I still have my mouse) 
I got the achy breaky hard drive blues 

    --  Dr. Ian Chai

"Stand by your RAM"
"Upload me Jesus through the COM port of life"
"A woman is only a woman but MS Access is a joke"

    -- Ed Lowe

Legal Notices

Thunderclap does not accept advertising; nor do we sell, rent, or give away our subscriber list. We will make every effort to keep the names of subscribers private; however, if served with a court order, we will sing like a whole flock of canaries. If this bothers you, don't subscribe.

Source code and binaries supplied via this newsletter are provided "as-is", with no warranty of functionality, reliability or suitability for any purpose.

This newsletter is Copyright © 1999 by Rolling Thunder Computing, Inc., Ipswich MA. It may be freely redistributed provided that it is redistributed in its entirety, and that absolutely no changes are made in any way, including the removal of these legal notices.

Thunderclap is a registered trademark ® of Rolling Thunder Computing, Inc., Ipswich MA. All other trademarks are owned by their respective companies.