您好,TC。您知道,我们当中的一个脚本专家有这样一位朋友,他在当地面包店找到了一个烤馅饼的暑期工作。不可否认,这听起来绝对是一个完美的工作,并且的确是这样,只不过有一件事除外:这位朋友实际上从未品尝过这些馅饼;因为这些馅饼全部被卖光,他甚至都没有机会为自己切下哪怕一片馅饼。事实证明,这可能是最糟糕的一项工作:周围永远弥漫着刚出炉馅饼的诱人香味,但却不能吃上一口。
我们脚本专家对这位可怜的烤馅饼朋友深感同情。毕竟,每天我们都编写新的脚本,然而,我们自己却很少使用这些脚本。我们已编写了用来管理 Active Directory 的脚本,然而,不知什么在作怪,他们不让我们管理 Microsoft Active Directory。(自己去想吧。)我们已编写了用来管理 DNS 服务器的脚本,却不允许我们构建自己的 DNS 服务器。我们已编写了用来在 Excel 中创建图表的脚本,但他们不让我们在 Excel 中创建图表。
哦,不错,他们会让我们那样做;只是我们没有必要去创建图表。
但是这个任务却不同。我们一直都在使用 HTA,并且我们总是右键单击 HTA 然后单击 Edit;接着,会在 Microsoft Word(或 Microsoft FrontPage,这取决于该特定计算机上所安装的工具)中打开 HTA,但这不是用于 HTA 的首选编辑器。与您一样,我们情愿使用记事本,也就是说,如果编写了向 HTA 文件添加 Edit 命令的脚本,那么脚本专家也会从中受益。您知道,类似下面这个脚本:
Const HKEY_CLASSES_ROOT = &H80000000
strComputer = "."
Set objRegistry = GetObject("winmgmts://" & strComputer & "/root/default:StdRegProv")
strKeyPath = "htafile/Shell/Edit/Command"
objRegistry.CreateKey HKEY_CLASSES_ROOT,strKeyPath
strValue = "%SystemRoot%/system32/NOTEPAD.EXE %1"
objRegistry.SetExpandedStringValue HKEY_CLASSES_ROOT,strKeyPath,vbNullString,strValue
如果要向 HTA 文件的上下文菜单中添加一个命令(您当然是要这样做),首先需要将一个新项添加到注册表中;特别是,需要转到 HKEY_CLASSES_ROOT,然后添加 htafile/Shell/Edit/Command 项。这就是我们在前半部分脚本中所要做的事情。我们定义一个名为 HKEY_CLASSES_ROOT 的常量,并将其值设为 &H80000000;这会将要使用的注册表配置单元指示给脚本。然后,我们连接到本地计算机上的 WMI 服务(尽管此脚本也可以在远程计算机上运行),从而绑定到 root/default 命名空间中的 StdRegProv 类。
到目前为止相当容易,对吧?然后,我们使用下行代码将新注册表项的路径(在 HKEY_CLASSES_ROOT 内)分配给一个名为 strKeyPath 的变量:
strKeyPath = "htafile/Shell/Edit/Command"
完成后,我们便可以使用 CreateKey 方法来创建新项。要执行此操作,我们只需调用 CreateKey,并向其传递两个变量:常量 HKEY_CLASSES_ROOT 和变量 strKeyPath。或者,更准确的是:
objRegistry.CreateKey HKEY_CLASSES_ROOT,strKeyPath
那是什么?如果您已经有了名为 htafile/Shell/Edit/Command 的注册表项,那该怎么办?嗨,不要紧。如果该项已经存在,不会发生什么坏事情;脚本只是跳过 CreateKey 方法,转到下一行代码。如果注册表项已经存在,不会发生任何错误。
这确实很不错,不是吗?
现在,我们必须做的就是将要执行的实际命令(即,“在记事本中打开此文件”)分配给 Command 项的默认值。这并不特别难,但它确实有点棘手。因此我们应该向您解释它是如何奏效的。
正如您所知道的,我们想让 HTA 文件有一个与 VBScript 文件类似的上下文菜单:我们希望能够右键单击 HTA 文件,单击 Edit,然后让 HTA 在记事本中打开。坦白地说,我们不能百分之百确定实现此操作的方法,因此我们简单地浏览一下 VBSFile/Shell/Edit/Command 项的默认值。它看起来与以下类似:
%SystemRoot%/system32/NOTEPAD.EXE %1
那么它对 HTA 文件同样奏效吗?嗨,如果不亲自试一试,就永远不会知道,对吗?考虑到这一点,我们将该字符串分配给一个名为 strValue 的变量:
strValue = "%SystemRoot%/system32/NOTEPAD.EXE %1"
现在,我们只需将此变量的值分配给 htafile/Shell/Edit/Command 的默认值。在此之前,我们需要记住两件事。第一,您可能已经注意到,环境变量 %SystemRoot% 已嵌入到了命令中。这很好:这意味着我们可以输入记事本的路径,而不必知道 Windows 目录是 C:/Windows 还是 D:/Winnt,或者完全是其他内容。然而,这也意味着我们必须使用 REG_EXPAND_SZ 数据类型来配置默认值。此数据类型的注册表值会自动用实际物理路径来“扩展”环境变量;换句话说,它会将 %SystemRoot%/system32/NOTEPAD.EXE 更改为类似于 C:/Windows/system32/NOTEPAD.EXE 的路径。
为默认值赋予 REG_EXPAND_SZ 数据类型会很难吗?继续往下看:如果它很难,您真的以为脚本专家只是在试试?我们必须做的所有事情就是确信,因此当我们赋值时,我们使用 SetExpandedStringValue 方法。
非常正确。有人可能会感到奇怪,为什么我们一直使用通用词组“默认值”,而不使用我们需要修改的注册表值的名称。这样做实际上有一个充分的理由:注册表项的默认值没有名称。(虽然它在 RegEdit 中以 (Default) 形式出现,但它只是一个占位符值,不是它的名称。)那么,我们如何才能访问没有名称的注册表值呢?所幸这也是非常简单的:在调用 SetExpandedStringValue 方法时,只要不指定名称就行。看看我们用来调用 SetExpandedStringValue 的这行代码:
objRegistry.SetExpandedStringValue HKEY_CLASSES_ROOT,strKeyPath,vbNullString,strValue
注意以下四个参数:常量 HKEY_CLASSES_ROOT、变量 strKeyPath、VBScript 常量 vbNullString 以及变量 strValue。使用注册表项默认值的秘密在于使用 vbNullString(其只代表空值),而不使用值名称。当指定 vbNullString 代替值名称时,您将自动连接到默认值。
WMI 不是很神奇吗?
实际上,WMI 确实很神奇,但我们今天真的没有时间聊天。因为,我们一直渴望有一大块黑莓馅饼。
最好是两大块黑莓馅饼。另外还有一片巧克力奶油馅饼作为餐后甜点。