Click here to Skip to main content
Click here to Skip to main content
Go to top

Using COM in Gadgets without Installation

, 5 Jun 2007
Rate this:
Please Sign up or sign in to vote.
This article shows how to create gadgets that use COM, without requiring installation or administrator permission.
Screenshot - Workometer.jpg

Introduction

This article shows how any COM component can be used in a Vista Sidebar gadget and be packaged into the gadget ZIP-file so it can be deployed using the usual "one click" deployment without requiring any special MSI installation or administrator permission.

To install the gadget, download the Workometer.zip file, rename the file extension to ".gadget" and double click it.

Background

For the Swiss gadget competition 2007 I wanted to write a special gadget. I had in mind a kind of gauge that displays how fast you can type and some statistics about how many keys you press during a typical workday. For that I needed to use a system wide keyboard & mouse hook, using the Windows API function SetWindowsHookEx.

I knew I'd have to write a COM component that takes care of the statistics, but how could I publish the gadget in the Windows Live gallery if a COM component is required to be installed and registered, before the gadget works? And what about uninstalling?

It took me a while to get it working, but if you know how, it's quite easy. I though I'd share this with you, because people here at codeproject helped me get there.

Using the COM component in JavaScript

I had the choice to write a COM component in C++/ATL or C#/.NET. Both are pretty straight forward so I won't explain that in this article. There are other great articles for that. Anyway SetWindowsHookEx is not available in .NET so I'd have to use Interop. I decided to write the component in plain and simple C++/ATL. The entire source is downloadable from the link above.

The component exposes an Interface called IGauge with a few methods like StartMeasure, StopMeasure, keySpeed, keyCount, etc. The JavaScript code used to access the component looks like this:

var workGauge = new ActiveXObject("Workometer.Gauge"); 
workGauge.StartMeasure();

If you have registered the COM component on your machine that's all you need. However we don't want to have to register it. Read on.

Temporarily register the component using JavaScript and WScript

The trick is to write the registry entries which COM components usually write into the registry when you call regsvr32 or regasm before you instantiate the component. Here are the required registry entries for Workometer.

[HKEY_CURRENT_USER\SOFTWARE\Classes\Workometer.Gauge]
@="Workometer Gauge"

[HKEY_CURRENT_USER\SOFTWARE\Classes\Workometer.Gauge\CLSID]
@="{205BC886-A9AA-4C96-B93C-564CCBA8BD83}"

[HKEY_CURRENT_USER\Software\Classes\CLSID\
{205BC886-A9AA-4C96-B93C-564CCBA8BD83}]
@="Workometer.Gauge"

[HKEY_CURRENT_USER\Software\Classes\CLSID\
{205BC886-A9AA-4C96-B93C-564CCBA8BD83}\InprocServer32]
@="C:\Users\...\Workometer.dll"
ThreadingModel="apartment"

Notice that the entries are not in the HKEY_CLASSES_ROOT section of the registry. To write entries there you would need to run in administrator mode. It surprised me that HKEY_CURRENT_USER could be used, but it works.

To write the entries into the registry using JavaScript use the WScript.Shell object. The WScript object exists on all Vista machines and contains the functions RegWrite and RegDelete which you can use for that purpose. Here's how you call it:

var wshShell = new ActiveXObject("WScript.Shell"); 
wshShell.RegWrite ("HKCU\\SOFTWARE\\Classes\\Workometer.Gauge\\", 
    "Workometer Gauge");

There's one more small thing. The full path name of the DLL must be in the registry. To get the path of the DLL, we use the function System.Gadget.path which is automatically available to all gadgets.

Let's wrap it up

Below you'll find the entire code required to load the Workometer COM component. Basically when the gadget gets loaded I write the required entries into the registry, create the object with ActiveXObject, then immediately delete the registry entries again, so nothing is left behind. That's the whole story.

var workGauge;

loadWorkGauge();

function loadWorkGauge()
{
    // dynamic register (write the registry entries into current user
    var wshShell = new ActiveXObject("WScript.Shell"); 
    var rootCls = "HKCU\\Software\\Classes\\CLSID\\
        {205BC886-A9AA-4C96-B93C-564CCBA8BD83}\\";
    var rootPid = "HKCU\\SOFTWARE\\Classes\\Workometer.Gauge\\";
    wshShell.RegWrite (rootPid, "Workometer Gauge");
    wshShell.RegWrite (rootPid+"CLSID\\", "
        {205BC886-A9AA-4C96-B93C-564CCBA8BD83}");
    wshShell.RegWrite (rootCls, "Workometer.Gauge");
    wshShell.RegWrite (rootCls+"InprocServer32\\", 
        System.Gadget.path+"\\Workometer.dll");
    wshShell.RegWrite (rootCls+"InprocServer32\\ThreadingModel", "apartment");

    // create the COM object and store it in global variable
    workGauge = new ActiveXObject("Workometer.Gauge"); 

    // delete all the entries again
    wshShell.RegDelete (rootCls+"InprocServer32\\");
    wshShell.RegDelete (rootCls);
    wshShell.RegDelete (rootPid+"CLSID\\");
    wshShell.RegDelete (rootPid);
}

When you pack your gadget files into a ZIP file (.gadget) for deployment, the code above assumes the DLL is in the root of the ZIP file, the same place where the gadget.xml file is.

Loading C#/.NET components

Although I haven't tried it, I'm certain you can also load .NET assemblies that expose COM objects in the same way. For assemblies two or three more lines are required to be written into the registry. To find out which lines are required, create the .NET assembly and register it with regasm then have a look at the entries in the registry.

History

  • 6th June 2007: Original posting

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

msbsoftware
Web Developer
Switzerland Switzerland
Markus Bosshard is an ancient software developer who started programming with punch cards before he graduated with a BSc (Computer Science) at Wits University Johannesburg. He now lives in Switzerland and does software consulting and development as an independent software developer. If he has the choice he develops using C#.

Comments and Discussions

 
QuestionExcellent, can you make it save key count history ? PinmemberAybe1-Nov-09 4:55 
QuestionWill this method work for creating services? Pinmembertdw111-Aug-07 10:40 
QuestionErrors trying to install Pinmemberc56759112-Jun-07 6:42 
AnswerRe: Errors trying to install Pinmembermsbsoftware12-Jun-07 9:17 
GeneralRe: Errors trying to install Pinmemberemancero22-Jul-07 14:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 5 Jun 2007
Article Copyright 2007 by msbsoftware
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid