在 Gadget 中使用 COM 而无需安装






4.75/5 (8投票s)
2007 年 6 月 5 日
4分钟阅读

58312

1515
本文介绍了如何在 Gadgets 中使用 COM 组件,而无需安装或管理员权限。
引言
本文介绍了如何将任何 COM 组件用于 Vista 侧边栏 Gadget,并将其打包到 Gadget 的 ZIP 文件中,以便使用通常的“一键式”部署,而无需任何特殊的 MSI 安装或管理员权限。
要安装 Gadget,请下载 Workometer.zip 文件,将文件扩展名重命名为“.gadget”然后双击它。
背景
为了参加 2007 年瑞士 Gadget 竞赛,我想写一个特殊的 Gadget。我构思了一个类似仪表盘的东西,可以显示你的打字速度以及典型工作日内按键次数的统计信息。为此,我需要使用系统范围的键盘和鼠标挂钩,利用 Windows API 函数 SetWindowsHookEx
。
我知道我必须编写一个负责统计的 COM 组件,但如果 Gadget 需要先安装和注册 COM 组件才能工作,我该如何发布 Gadget 到 Windows Live 图库呢?卸载又该怎么办?
花了点时间才搞定,但如果你知道方法,其实很简单。我想与大家分享这一点,因为 CodeProject 上的许多人帮助我实现了这一点。
在 JavaScript 中使用 COM 组件
我可以选择用 C++/ATL 或 C#/.NET 编写 COM 组件。两者都相当直接,所以在这篇文章中我不会详细解释。有其他很棒的文章可以参考。无论如何,.NET 中没有 SetWindowsHookEx
,所以我需要使用 Interop。我决定用纯粹简单的 C++/ATL 编写组件。全部源代码可从上面的链接下载。
该组件公开了一个名为 IGauge
的接口,其中包含一些方法,如 StartMeasure
、StopMeasure
、keySpeed
、keyCount
等。用于访问该组件的 JavaScript 代码如下所示:
var workGauge = new ActiveXObject("Workometer.Gauge");
workGauge.StartMeasure();
如果您已在计算机上注册了 COM 组件,那么这就足够了。但是,我们不想注册它。请继续阅读。
使用 JavaScript 和 WScript 临时注册组件
诀窍是在实例化组件之前,编写 COM 组件通常在调用 regsvr32
或 regasm
时写入注册表的注册表项。以下是 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"
请注意,这些项不在注册表的 HKEY_CLASSES_ROOT
部分。要在此处写入项,您需要以管理员模式运行。令我惊讶的是,可以使用 HKEY_CURRENT_USER
,但它确实有效。
要使用 JavaScript 将项写入注册表,请使用 WScript.Shell
对象。WScript
对象存在于所有 Vista 计算机上,并包含 RegWrite
和 RegDelete
函数,您可以使用它们来实现此目的。以下是如何调用它的方法:
var wshShell = new ActiveXObject("WScript.Shell");
wshShell.RegWrite ("HKCU\\SOFTWARE\\Classes\\Workometer.Gauge\\",
"Workometer Gauge");
还有一件小事。DLL 的完整路径名必须在注册表中。要获取 DLL 的路径,我们使用函数 System.Gadget.path
,该函数对所有 Gadget 都是自动可用的。
总结
下面是加载 Workometer
COM 组件所需的全部代码。基本上,当 Gadget 加载时,我将所需的项写入注册表,使用 ActiveXObject
创建对象,然后立即删除注册表项,这样就不会留下任何痕迹。这就是全部。
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);
}
当您将 Gadget 文件打包成 ZIP 文件(.gadget)进行部署时,上面的代码假定 DLL 位于 ZIP 文件的根目录下,与 gadget.xml 文件在同一个位置。
加载 C#/.NET 组件
虽然我没有尝试过,但我确信您也可以用同样的方式加载公开 COM 对象的 .NET 程序集。对于程序集,需要在注册表中写入另外两三行。要找出需要哪些行,请创建 .NET 程序集并使用 regasm
注册它,然后在注册表中查看相关项。
历史
- 2007 年 6 月 6 日:初始发布
许可证
本文没有明确的许可证附加,但可能在文章文本或下载文件中包含使用条款。如有疑问,请通过下方的讨论区联系作者。您可以在 此处找到作者可能使用的许可证列表。