Sunday, February 22, 2004

COM Threading Bites Me Right in the Ass

Professionally speaking, I left COM behind years ago, when I decided to focus on .NET full-time. I've been lucky enough to have that career option. Of course, it doesn't mean that I've forgotten what I know about COM, and sometimes that knowledge comes in handy. Other times, I'm reminded of how confusing that stuff has always been, and I'm even more grateful I could move on.

Take tonight. I was coding along, working on my implementation of FlexWikiPad. I wanted to pop up a dialog box so the user could choose a folder to store the wiki in. “No problem,” I thought, “I'll just use the built-in folder browser dialog.” Imagine my surprise when I ran the code and got a blank dialog. Oh, it had an OK and a Cancel button, but there was nothing but grey background where the folders on my computer should have been shown.

I did what any good debugger would do, and started stripping down the application, looking for the line of code that was causing the problem. But the application kept getting smaller, and soon it was just an empty form with a button on it. Clicking the button did nothing but open the dialog, and it still had the same problem. I was mystified.

I had a suspicion that something might have gone screwy in the project settings somewhere, so I fired up the project wizard, and I created a second project from scratch, with the intention of using WinMerge to diff the two project files. Only, when I was perusing the generated source code, I saw something that gave me pause. After thinking about it for a second, I went back and made a one-line change in my original program, and sure enough, it started working.

The problem in this case springs from the fact that I tend not to rely on the VS.NET wizards. Rather, I either write my source files from scratch, or I generate them with CodeSmith templates. So I had failed to mark my Main method with that little [STAThread] attribute, which, in the type of .NET programs that I usually write, is actually a good idea. But when you're dealing with controls that interop via COM - as is apparently the case with the folder browsing stuff - it just causes things to go kerbluey in odd ways.

Ah, COM.


  1. Ah, apartment threading. One of the worst monstrosities that Microsoft ever foisted on its development community.

  2. It sort of makes sense if you look at it historically. COM was the first commercially successful component model, and when it made it big, the number one use case was for thread-affine GUI controls. It just sort of went from there.

    It was ultimately far too complex, of course. But that also made it a good source of consulting income for a while. Or still, for that matter. :)

  3. Sure, it started as sort of an enforced BeginInvoke. But by never allowing VB developers to write free-threaded objects (perhaps they though Mort couldn't handle it - or that the VBRuntime couldn't), they doomed us to nightmare world of marshaling, message pumps, and reentrancy weirdness (and gave us the worlds longest API function - CoMarshalInterThreadInterfaceInStream). I ran into that wall in a big way writing a web service facade for a VB6 COM API in .NET. The hoops I had to jump through would make PT Barnum proud.

  4. It was the VB runtime that couldn't handle it. But yeah, it sucked. :)

    I'm sure there's a lesson in there somewhere about trying to protect people from themselves too much.