Registration-free COM the old-fashioned way: The car mp3 player

Windows XP introduced Registration-Free COM, permitting you to place your COM object registrations in a manifest rather than in the registry. Very handy when you want to support xcopy deployment or running directly off a thumb drive. And very much in keeping with the principle of not using a global solution for a local problem. (If you need your COM object to be used from other programs, then global registration is not unreasonable, but if the only client is another part of your program, then you have a local problem that should employ a local solution.)

Here are some articles on the subject:

Before manifest-based COM object registration was possible, you had to do things the old-school way. Mind you, old-school registration-free COM is not a very useful skill any more, falling into the same category as knowing how to churn butter or use a typewriter eraser, but since when did that ever stop me from writing about something?

One old-school way is to call Dll­Get­Class­Object directly. This works only if you control both sides of the equation (the client and the server) because it's now your responsibility to ensure that both sides agree on the threading model. You won't have the actual COM libraries sitting in between watching out for scenarios that require marshalling, for example.

For a toy project of mine, I used a different approach. My little project was an mp3 player for my laptop. Now, sure, we already have tons of mp3-playing apps out there, but mine was different: Mine was designed to be used on long driving trips. (This was back in the days when long driving trips were part of my life. I don't drive that much any more.)

Here was the plan: I connected the line-out from the laptop into my car sound system, so that the music came out my car speakers. Meanwhile, all input to the program came from the mouse. Specifically, it came from the mouse buttons and the wheel. The mouse itself never moved. The idea was that I could hook up a mouse to the laptop, put the laptop on the passenger seat, and leave the mouse on the center console. I would then use the mouse buttons and wheel to navigate my music collection. I forget exactly what I ended up doing, but it was something like

  • Left button click = select current item
  • Right button click = go up one level
  • Rotate wheel = scroll through current directory

Now remember, this program was designed to be used while driving, which means both eyes on the road. (This was long before hands-free driving laws came on the scene.) Therefore, the program provided feedback not by displaying items on the screen but by using speech synthesis to read the names of the files and directories out loud. Finding a song to play, therefore, consisted of turning the wheel and listening as the laptop read out the name of the album, then when I found the one I wanted, I would click the left mouse button, and then I would use the wheel to scroll through the songs, and when I heard the title of the one I wanted, I clicked the left mouse button again, and boom, the song started playing.

I added some heuristics to the code so if consecutive tracks began with the same words (which happens often with classical music, think Symphony #5 in c minor, first movement followed by Symphony #5 in c minor, second movement) it spoke only the changes.

While the song was playing, the mouse buttons served as playback controls. I think it went something like this:

  • Left button click = pause / play
  • Right button click = exit and choose another song
  • Rotate wheel = rewind / fast-forward ten seconds
  • Press middle mouse button and rotate wheel = previous/next track

(Exercise: Why didn't I need a volume control?)

The easiest programming language for this was a Web page. I created a host program that simply created a Web browser control. The host program told the Web browser control to navigate to my carplay.html file, and boom, I now had an in-car playback system. I could use things like File­System­Object to navigate the file system and the Windows Media Player control to do the playback. Now, this story takes place so many years ago that Internet Explorer didn't support the mouse wheel yet, so the host program also converted wheel messages into fake keyboard activity (wheel motion was converted into the up and down arrows) so that the Web page could respond to them.

Once nice thing about this whole set-up is that I had the HTML DOM at my disposal. My program spewed diagnostic output to the screen like crazy, but who cares? The end user isn't looking at the screen. Therefore, the entire Web page is free real estate for debugging.

The only thing missing was the speech synthesizer.

There was no ActiveX control for speech synthesis, so I wrote one of my own. I let SAPI do the heavy lifting; my ActiveX control was simply some glue that let a Web page pass a string to be spoken. (Or pass a null string to shut up.) I wanted my program to be xcopy-deployable (USB thumb drives didn't exist back then) so I looked for a registration-free technique. The Dll­Get­Class­Object technique wouldn't work since I didn't control how Internet Explorer created COM objects; it always called Co­Create­Instance.

The technique I used was Co­Register­Class­Object. I created a class factory for my object and explicitly registered it before creating the Web browser control. That way, when the Web page asked for my object, lo and behold, there it was: In memory, not in the registry.

That was a really long-winded story with a punch line that tells you how to do something you don't need to do any more because there are easier ways of doing it nowadays. I wouldn't be surprised if you wanted a refund.

The real punch line: I spent far more time writing the program than I ever did using it.

Comments (29)
  1. Wilhelm Svenselius says:

    You didn't need a volume control because the car's audio system had one. You would want to keep the volume of the laptop as constant as possible.

  2. Dan Bugglin says:

    Had to write a web app recently that would take in XML files and preprocess them with some JS (because XSL sucks) and then run through the XSL and then postprocess in JS (because XSL sucks, and sucks varying degrees depending on which browser you use it on, for example Chrome and IE both hard code DIFFERENT output encodings and don't allow you to change them) and then for IE I could create a FileSystemObject and then write output directly to the filesystem with just an ActiveX warning.  Kinda scary.

  3. You didn't need a volume control because you had loudness normalization (e.g. ReplayGain metadata) enabled.

  4. That's pretty awesome.

    All the good ones are taken, but I suggest that you didn't need a volume control because you could control the apparent loudness of the music by driving faster or slower to raise or lower the noise floor. ;-)

  5. Gabe says:

    You didn't need a volume control because you had a microphone mounted near your head whose input was compared to the output signal, and your program dynamically adjusted the amplifier gain to maintain a constant average S/N ratio.

  6. Skyborne says:

    Agreed with @Wilhelm Svenselius, with the additional note that you said "line out"–presumably this is a separate port from headphones, with an independent volume control.  So your car volume would also not depend on the last time you used headphones with the laptop (both the headphones, and the environment.)

  7. Jason says:

    "but since when did that ever stop me from writing about something?" – But that's precisely why we love this blog! :D

    As for remembering outdated info., I kept tinkering with DOS years after it was a distant memory and my friends used to laugh at me. Guess who they come to now to help them with old skool gaming setups?

  8. Mott555 says:

    (Exercise: Why didn't I need a volume control?)

    The real punch line: I spent far more time writing the program than I ever did using it.

    Because you forgot to implement it and never noticed since you didn't really use the system. :P

  9. R. Bemrose says:

    "There was no ActiveX control for speech synthesis, so I wrote one of my own. "

    Wow, how long ago was this?  I remember that Microsoft Agent was an ActiveX control that supported Speech Synthesis (and animated characters) and was shipped as part of Windows 98.

  10. Anonymous Coward says:

    I spent far more time writing the program than I ever did using it.

    Who cares? It was probably good fun and a nice exercise.

    In any case, I can still see situations where CoRegisterClassObject can be useful. It may be old-fashioned, but it's simple and significantly less finicky than the newfangled approach.

    People still build houses out of brick and mortar, or even wood if that suits them. The existence of steel and concrete doesn't stop the old methods from working, or even from being useful.

  11. Devlin says:

    That is an amazingly cool way to go about doing things, the sort of hack people would've gone nuts over back in the 90s when the idea of playing MP3s in a car was still a grand undertaking.

  12. You didn't need a volume control because the music being played by a web page, and the music that web pages play is always obnoxiously loud anyway (which is the way you like it).

  13. s/Once/One says:

    I spent far more time writing the program than I ever did using it.

    And I thought it's typical. Like spending more time tweaking a game mod than actually playing with it.

  14. Mark S says:

    "The real punch line: I spent far more time writing the program than I ever did using it."

    We've all been least I assume so for the people who'd read this blog

  15. JJJ says:

    They had mice with scroll wheels back then?  That thing must have cost like $500.

  16. voo says:

    @Mark & s/Yes I noticed that too:

    Came here to say the same.. "hmm I could spend half an hour doing this by hand or spend a day writing a program that does the task in any possible combination (which will never come up anyhow)".

    Wasn't that the motto of the boost library? "Why spend three days writing a program, if you spend three years writing a library for it" or something?

  17. mpz says:

    Is this what you would call a shaggy dog story? ;-)

  18. Damien says:

    I guess I don't get "The easiest programming language for this was a Web page" – if you've got to write code anyway – to host the browser control, do the COM registration, translate mousewheel messages – what is the web page adding to the party?

    [The rapid application development framework. -Raymond]
  19. Anton says:

    Now I think I retry to make sense of scary Elevated COM Object.

  20. Mark S says:

    Ha, yeah.  Apropos Raymond's recent bus transfer story, I wrote an app to figure out the optimal routing for my commute, even if it involves, for example, taking an express train PAST my stop and doubling back.  I'd have to commute for about 1000 years for the savings to add up to what I spent writing it.  But it was a fun exercise, I used it to learn WPF, Windows Phone programming, and it was a fun exercise in graph theory.  

    Anyway if you commute near NYC you may as well bear the fruits of my labor:

  21. kinokijuf says:

    You should make your program available for download.

  22. immibis says:

    I'm probably missing the sarcasm in all the other volume control comments.

    You didn't need a volume control because the sound was going through your car's existing stereo system which already has one.

  23. immibis says:

    Somehow I missed the very first comment.

  24. chentiangemalc says:

    that story is way too cool. love it … reminds me of my early computing days, it was so often a lot of work to build a simple tool that i didn't even use…

  25. Daniel Campos says:

    "…but if the only client is another part of your program, then you have a local problem that should employ a local solution"

    I think the MSN dev team never learn this part. They loves to fill the system with unnecessary services that could be part of the MSN messenger application and as far I know they are not used for any other application of the system. Is a waste of resources.

  26. No One says:

    You didn't need a volume control because you would sing along as loud as you wanted and new all the songs by heart.  (And could sing them a cappella.)

  27. DA-NA-NA-NA... says:

    Singing along to Symphony #5 is fun!

  28. Peter Schickele (of PDQ Bach fame) has a sportscast version of that symphony which is worth a listen.

  29. Ian Boyd says:

    i tried the DllGetClassObject route for unregistered COM objects a long time ago. i got worried when i'm now responsible for the lifetime of the COM object. i can call DllCanUnloadNow, but i was terrified about what happens if i want to shutdown my application but DllCanUnloadNow returns S_FALSE?

    As a practical matter, i can't see how there could be extra references to objects inside "my" dll, when i should be the only one using it. But who knows if i might have some stray references that only happen in a strange use-test that testing missed. This is the value in having the magical "COM" big brother handling that for me; i just bow out, and let him worry about unloading the libraries.

    Stricken with panic, i never went through with it – and just registered them. Solving a local problem (fear of crashes) with a global solution.

Comments are closed.

Skip to main content