Monthly Archives: November 2006

COM aggregation and ref counting woes

Why are we talking about Component Object Model (COM), isn't that old dead technology? Well… no. There are still so many COM objects in use today, in many projects, that you will run into them sooner or later. As a software engineer you might even have to resolve bugs in these components. Today I want to draw attention to ref counting bugs that can creep in when using aggregation within these objects.

COM objects use reference counting to control their lifetime. This is achieved through the implementation of an IUnknown interface by each and every object. This interface contains (quick – what are the first three v-table entries?) IUnknown::QueryInterface, IUnknown::AddRef and IUnknown::Release. So after you add a reference to an object with AddRef, you are expected to call Release when you are finished. Reference counting bugs can crop up in object clients when someone forgets this rule and are usually a real pain to find. This difficulty can be compounded even further if the object itself messes up its implementation of AddRef.

The implementation of AddRef is typically simple (just increment an internal counter), however when the object aggregates other objects in its internal implementation (another form of object reuse as opposed to using containment) it becomes more complex. In these cases you have to ensure that AddRef and Release calls operate on the correct object.

Lets take the example of a hypothetical AIRPLANE object. An AIRPLANE is implemented by aggregating WING, and ENGINE objects. WING implements IWing and IUnknown, ENGINE implements IEngine and IUnknown. Now clients of the AIRPLANE object would expect that IWing::AddRef, and IEngine::AddRef both control the lifetime of the outer object (the component/object doing the reusing – in this case AIRPLANE). This is fair and reasonable, however the only way this can happen is if the inner objects (WING and ENGINE) are aware of the outer object. So when WING and ENGINE are created, AIRPLANE passes a pointer to its IUnknown implementation (called the controlling unknown) down to the inner objects. If they support aggregation then they will use this pointer to handle any IUnknown calls that come in through IWing and IEngine. If they do not support aggregation they will return CLASS_E_NOAGGREGATION and fail creation. However ENGINE and WING must not delegate to the controlling unknown for any AddRef and Release calls that come in through IUnknown itself, as this is what the outer object will use to control their lifetime.

These are just the basic rules of aggregation that when applied ensure that object lifetime is still managed correctly. Common problems arise when the inner objects forget to delegate the AddRef and Release calls to the controlling unknown, or do so in the wrong case (i.e. when called through IUnknown::AddRef). In this case the client of AIRPLANE may see what appears to be a ref counting bug on their side, but is actually an internal issue with the aggregation.

… no wonder people like managed code and .NET. Ref counting bugs can get tricky.

 

Seattle to New York City

November 4th, 2006 – I was driving across Montana before I actually realized what I was getting into… a seriously long drive. Seattle, the city of Starbucks coffee, is located in the northwest of America, roughly 2800 miles (4500 km) drive from New York City. Wouldn’t it be great to drive all the way across the U.S of A? Coast to coast? Well.. that’s what I was thinking, and I had five days to get across.

I have been working as a Software Engineer in Seattle for five years now. After having finished a particularly long project I decided it was time for a small vacation, and driving across the country was always on the list. So after a little packing and staring at maps, a couple of friends and I started the drive. Our goal was to make it to New York City in five days (when I had a return flight booked… no way I was driving back).

The drive took us through thirteen states – Washington, Idaho, Montana, Wyoming, South Dakota, Minnesota, Wisconsin, Illinois, Indiana, Ohio, Pennsylvania, New Jersey and New York.

 

OLYMPUS DIGITAL CAMERA

 

OLYMPUS DIGITAL CAMERA

Washington was fairly familiar. Idaho was very short with only one mountain pass that was rather scary at night and with rain. Montana was the longest stretch of road ever, luckily it was broken up by a detour into Wyoming to see Yellowstone National Park. Yellowstone was awesome, however I think it would have been more awesome if we were there during summer. We happened to arrive on the very last day they allowed people in, and most of the park was covered in snow as it is situated from 5000 to 8000 ft. The most interesting things were the hot springs and two buffalo we found grazing on a field (I was told that there were many more buffalo, but I guess they were all hiding from the crazy cold weather… probably near the hot springs).

OLYMPUS DIGITAL CAMERA

 

OLYMPUS DIGITAL CAMERA

 

yellowstone4

Next it was onto South Dakota where the driving started to get scary. Middle of the night, driving on the highway, fog, low visibility and what else happens? Deer start jumping all around the highway. After narrowly missing one we started noticing all the carcasses on the side of the road and decided it was best to stick to daytime driving. The next days driving started at sunrise – 6am.

The next few states passed quickly as we were into the routine of driving. Chicago went by, Indiana, Ohio, and before we knew it we were on the east coast and I-90 had turned into a tollway. Our next big stop was Philadelphia, home of the Liberty Bell and cheese steaks. The Bell was interesting, the cheese steak was yummy.

libertybell

 

newyorkmet

And finally after four days we arrived in New York City. Overall the journey was great fun and in hindsight not as difficult as I had imagined.

Windows PowerShell

Power users love shells. Not the seafood kind, but the command line interface, computer command scripting kind. Even MacOS which was traditionally GUI driven, now has a shell (albeit somewhat hidden), due to its makeover in OS X. With a shell the user can input text commands to manipulate the computer. The most obvious use of which is the ability to script common operations, or perform functions faster than perhaps the user-interface driven counterpart operation.

MS Windows based operating systems have been using cmd.exe as their shell for quite some time, until PowerShell came along. Windows PowerShell currently has an RC2 release available for download. Whats so special about Windows PowerShell?.. where do I start? 🙂

The biggest change is in the object pipeline. No longer do commands output text, now its all objects. So when you do something like:

Get-Process | Format-Wide

The output of Get-Process is piped, as objects, to the next command. In this case Format-Wide takes the objects and formats them in a particular way. You could have used Format-List, or a multitude of other variations. Passing objects allows much richer communication between functions in the command pipeline as well as other shell operations. So you can imagine what something like this may do:

Get-Process m* | dir

Yes you guessed it, it actually lists the folder location of all currently running processes that start with the letter m.

Windows PowerShell also has a whole new syntax. Commands have verb-noun type names which provides for clear, consistent, and easily discoverable functionality (and if you are ever lost, just type "help", or append "-?" to a command). To help people transition from other shells there are aliased commands, so commands such as "cd", "dir", "more" are aliased to their corresponding commands and work just fine.

I could go on for pages and pages about all the cool new things, but lets just cover two more items, PowerShell drives, and COM object scripting (that I thought was very cool). Have you ever wanted to query the registry and manipulate it right from a script instead of messing with regedit and .reg files? Well try this out:

cd HKLM:\Software

and now you have navigated to HKEY_LOCAL_MACHINE\Software. Well what else can you do? Just try "Get-PSDrive" to see a list of all the other mapped PowerShell drives you can navigate.

So what if you have a COM Automation object that you want to work with? Lets say you need to boot Excel, do a few calculations and retrieve the result? Prior to Windows PowerShell this was not trivial but now all you need is a few lines similar to this:


$xl = New-Object -ComObject Excel.Application
$xl.Workbooks.Add()
$xl.Range("A1").Value2 = 5
$xl.Range("A2").Value2 = 6
$xl.Range("A3").Value2 = "=Sum(A1, A2)"
$output = $xl.Range("A3")
$xl.Quit()

It looks very C# ish, but being able to run this straight from a command line script is just great.