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 thought 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()
{
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");
workGauge = new ActiveXObject("Workometer.Gauge");
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: Initial post
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.