我在几年前的新闻组中写了这篇文章。翻阅一下,我发现这并不是我写过最清晰的文章,但是它相当完整。值得一提的是,下面是我重新印刷的内容:
首先,您需要在HKEY_CLASSES_ROOT
下创建一个子键,用于保存启动应用程序的命令。 您应该给此键命名为半描述性名称。您的文件扩展名将映射到此键。例如,默认情况下,TXT文件被映射到名为txtfile
的键。使用此设置的好处是,如果您的应用程序可以处理多个扩展名,则可以将它们全部映射到此键。例如,许多图像编辑应用程序会创建一个名为“imagefile”的子键,并将.bmp、.jpg、.gif等文件映射到该键。我们将称您的键为“JoeBlowFile”。接下来,您需要为新的JoeBlowFile键设置“默认”值,以描述用户拥有的文件类型的文本字符串。这是在Windows Explorer下“类型”下显示的内容。再次以TXT文件示例说明,此处的好字符串可能是“文本文件”或“文本文档”(默认值为后者)。您的字符串可能是“Joe Blow数据”。
现在,在您的新密钥下,您可以创建另一个子密钥,称为“DefaultIcon”。正如其名称所示,它设置了与此类型文件一起使用的图标。您应该创建一个自定义图标,以图像方式表示您的程序处理的文档。您可以将此图标保存为ICO文件在您的应用程序目录中,但更好的是,您可以将其包含为EXE或DLL中的资源。无论哪种方式,然后您都需要将子键的默认值设置为表示ICO、EXE或DLL的完整路径和文件名的字符串。如果文件中有多个图标(特别是如果您将其作为资源包含在EXE或DLL中),则还需要添加逗号,并使用基于零的正索引号来表示要使用的图标,或者使用负资源ID,使用您在资源脚本中分配给图标的任何ID的负数。因此,您的可能是“C:\Program Files\JoeBlow\JoeBlow.exe, 2”。
C#开发者注意事项。不幸的是,C#项目无法拥有资源脚本。通过将资源添加到项目并将其指定为“嵌入式资源”,以便将其包含在.NET应用程序中,会以一种与之前方法不兼容的新的.NET特定格式进行包含。在使用VS.NET上的C#时,您唯一能够正确嵌入到应用程序中的图标是应用程序图标,可以从项目属性中访问。如果您需要其他图标(例如,表示由您的应用程序处理的文档文件而不是表示应用程序本身的图标),则需要将ICO文件本身包含在项目中,使用C++编译带有嵌入图标的DLL,或者创建和编译资源脚本,并将其从项目属性中包含在项目中。
无论您选择使用DefaultIcon
键与否,现在您需要在JoeBlowFile
键下创建一个名为“shell”的子键。在shell
键下,您将为您希望用户能够从上下文菜单(右键菜单)执行的每个命令创建单独的键。这些项目称为“动词”。为了保持一致性,其中之一应该是“打开” - 如果存在此键,则默认情况下将执行此键(即当用户双击您类型的文件时,将执行打开命令)。或者,您可以将“shell”键的默认值设置为您想要默认执行的动词。您可以选择将每个动词键的默认值设置为您希望在用户右键单击您类型的文件时出现在上下文菜单中的文本。在此文本中,可以使用“&”符号来指定下一个字符将被加下划线,这意味着用户可以按下对应于该字符的键来从上下文菜单中选择该命令。例如,对于“打开”键,您可以将“使用&Joe Blow的应用程序打开”作为默认值。然后,该文本将显示在该类型文件的上下文菜单中,并且用户可以按字母J启动Joe Blow的应用程序。
你唯一需要做的事情,就是在“open”(和随后的)键下创建另一个名为“command”的子键。命令键的默认值必须设置为表示执行该操作所需命令的字符串。例如,在“open”键下的命令键中,默认字符串可能是“C:\Program Files\JoeBlow\JoeBlow.exe”“%1”。请注意,路径\文件名周围的引号只有在路径或文件名中包含任何空格时才是必需的,但对于32位应用程序,它们绝对需要在
%1
周围。
%1
就像旧的MS-DOS批处理(.bat)文件中的
%1
一样。在这种情况下,
%1
将被替换为命令行上的第一个参数,这在本例中成为您的应用程序应打开的文件的文件名。因为您无法预先知道包含您应该打开的文件的路径或文件名是否包含空格,所以必须在
%1
周围放置引号。
您的应用程序还应包含其他必需的参数。例如,在“print”键下,“command”键的默认值可能是“C:\Program Files\JoeBlow\JoeBlow.exe”“%1”/print”,或者是“C:\Program Files\JoeBlow\JoeBlow.exe”/print“%1”。您可以自行决定如何处理应用程序中的命令行参数。
关于可替换的参数,如上所述的“%1”。显然,“%1”参数/可能/被替换为要打开的
短文件名。这并非总是如此,我还没有弄清楚Windows用来确定传递哪个参数的标准——短或长。可能是如果注册表中列出的可执行路径是长文件名,则Windows将使用长文件名替换%1以启动,但如果可执行路径是短文件名或可以解释为短文件名,则Windows将使用短文件名替换
%1
。如果您想确保始终获取
长文件名,请改用“%L”。您可以使用大写L(如我所做)或小写字母,但我更喜欢使用大写字母,因为小写字母“l”看起来太像数字“1”。
此外,如果您的程序知道如何处理Shell项ID,则可以使用“%i”参数而不是长文件名来获取
该参数。同样,大写或小写的“i”都很合适,但我发现大写字母“I”更难与小写字母“l”和数字“1”区分开来。如果您不知道Shell项ID是什么,那没关系。您可能永远不需要使用它们。
你终于完成了
JoeBlowFile
键。其余部分相对简单。您只需在HKEY_CLASSES_ROOT下创建另一个子键(如果尚不存在),并将其命名为文档类型的扩展名相同。以txtfile示例为例,名称将是“.txt”(带点号,但不带引号)。你的(Joe Blow的)可能是“.jbf”(用于Joe Blow文件)。此键的默认值现在必须设置为您创建的第一个键的名称,在我们使用的示例中为“JoeBlowFile”。
就是这样。您已经在注册表中完成了操作。请记住,您必须确保您的应用程序以与您在“shell”键下设置的命令一致的方式处理命令行。当您的应用程序启动时,Windows不会自动为您打开该文件...您必须自己打开它。
图形上看起来像这样:
HKEY_CLASSES_ROOT
| +--.jbf = JoeBlowFile
|
+--JoeBlowFile = Joe Blow Data
|
+--DefaultIcon = C:\Program Files\JoeBlow\JoeBlow.exe, 2
|
+--Shell
|
+--open = 使用Joe Blow的应用程序打开(&J)
| |
| +--command = "C:\Program Files\JoeBlow\JoeBlow.exe" "%1"
|
+--print
|
+--command = "C:\Program Files\JoeBlow\JoeBlow.exe" "%1" /print
如果您还不知道如何修改注册表,请在MSDN中查找以“Reg”开头的所有函数,包括RegOpenKeyEx、RegCreateKeyEx和RegSetValueEx。您也可以通过创建“.reg”文件并使用ShellExecuteEx()来调用“regedit.exe /s”来进行弱化方式的操作。(使用/s
可以防止Regedit弹出一个消息框询问“您确定要将[name of file.reg]中的信息添加到注册表吗?”) REG文件的格式简单明了。以下是一个示例REG文件,用于添加上面提到的“JoeBlow”示例:
REGEDIT4
[HKEY_CLASSES_ROOT\.jbf]
@="JoeBlowFile"
[HKEY_CLASSES_ROOT\JoeBlowFile]
@="Joe Blow Data"
[HKEY_CLASSES_ROOT\JoeBlowFile\DefaultIcon]
@="C:\\Program Files\\JoeBlow\\JoeBlow.exe, 2"
[HKEY_CLASSES_ROOT\JoeBlowFile\Shell]
[HKEY_CLASSES_ROOT\JoeBlowFile\Shell\open]
@="使用 Joe Blow 的应用程序打开(&J)"
[HKEY_CLASSES_ROOT\JoeBlowFile\Shell\open\command]
@="\"C:\\Program Files\\JoeBlow\\JoeBlow.exe\" \"%1\""
[HKEY_CLASSES_ROOT\JoeBlowFile\Shell\print]
@="打印(&P)"
[HKEY_CLASSES_ROOT\JoeBlowFile\Shell\print\command]
@="\"C:\\Program Files\\JoeBlow\\JoeBlow.exe \"%1\" /print"
确保在文件的第一行包含"REGEDIT4",否则它将无法工作。同时,确保在最后一行按下回车键,否则该行将不会被读取。总体而言,以这种方式将程序添加到注册表并不像听起来那么方便,因为如果您的应用程序安装在C:\Program Files\JoeBlow之外的任何位置,您将不得不修改您的REG文件。
上述说明针对使用C或C++直接编程Win32 API的用户。对于.NET上的C#来说,要简单得多。请参考Registry类,或者您甚至可以使用VS.NET中的部署项目以图形化方式完成大部分操作。
要向.NET程序集添加本地可访问资源,您需要一个资源脚本。资源脚本是一个纯文本文件,就像代码文件一样。实际上,它就是代码;声明性代码,由资源编译器rc.exe编译。以下是一个示例资源脚本:
#include <windows.h>
#define IDI_APP 100
#define IDI_FILE 200
#define ID_VERSION 1
IDI_APP ICON "Resources\\Application.ico"
IDI_FILE ICON "Resources\\JowBlowFile.ico"
ID_VERSION VERSIONINFO
FILEVERSION 1, 0, 19, 186
PRODUCTVERSION 1, 0, 19, 186
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP {
BLOCK "StringFileInfo" {
BLOCK "040904B0" {
VALUE "CompanyName", "Joe Blow, Inc.\0"
VALUE "FileDescription", "Joe Blow's App\0"
VALUE "FileVersion", "1.0.19.186\0"
VALUE "InternalName", "JoeBlow\0"
VALUE "LegalCopyright", "Copyright © 2008-2009 Joe Blow Incorporated\0"
VALUE "OriginalFilename", "JoeBlow.exe\0"
VALUE "ProductName", "Joe Blow\0"
VALUE "ProductVersion", "1.0.19.189\0"
}
}
BLOCK "VarFileInfo" {
VALUE "Translation", 0x409 , 1200
}
}
这样做的最大缺点是,您必须手动将版本信息添加到资源脚本中(除非您想完全放弃版本信息)。在我的应用程序中,我添加了一个自定义构建步骤,运行我编写的程序直接更新可执行文件中的版本信息,以便我不必手动更新资源脚本中的版本号,但该程序不适合公开发布,而且超出了本文的范围。
现在,您需要调用资源编译器将此资源脚本构建为二进制资源文件。将此脚本保存为JoeBlow.rc,然后启动Visual Studio命令提示符。它在Visual Studio开始菜单文件夹的工具下。如果您没有安装Visual Studio,我相信您可以在SDK的一部分中获得rc.exe。Microsoft似乎也在
这里提供最新版本。
一旦在VS cmd提示符下(或者在您的路径中有rc.exe),只需键入:
rc JoeBlow.rc
就是这么简单。假设我所包含的图标存在,上面的资源脚本应该可以在没有错误的情况下编译。这将在同一目录中创建一个名为JoeBlow.res的新文件。现在,假设您使用的是Visual Studio,您需要编辑项目属性以包括此资源文件。
这些说明适用于Visual Studio 2005或2008。我不记得如何在旧版本中执行此操作,甚至不确定是否可以,在2010年之前我也没有尝试过,但它可能相似。在解决方案资源管理器中右键单击项目,然后选择属性(或从主菜单栏中的“项目”菜单中选择属性)。在应用程序选项卡上,这是您应该看到的第一个选项卡,在底部是一个资源组框。在这里,您有两个选项:“图标和清单”或“资源文件”。选择后者选项。这将启用文本框,您可以输入(或浏览)您的新资源文件,JoeBlow.res。
最后,只需要构建您的项目,就可以在本机PE格式中嵌入图标,当浏览与您的应用程序关联的文件时,可通过shell访问。现在,如果您将
HKEY_CLASSES_ROOT\JoeBlowFile\DefaultIcon
的值设置为
C:\Program Files\JoeBlow\JoeBlow.exe,1
(使用基于0的索引号)或
C:\Program Files\JoeBlow\JoeBlow.exe,-200
(使用资源标识符的负数,如上所定义的
IDI_FILE
),则您的图标将显示在Explorer中的.jbf文件中。
要立即在安装后显示新图标,您可能需要刷新shell的图标缓存。我发现如何做到这一点的说明
here。基本思路是将shell图标大小(位于
HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics
)从当前值更改为其他值,然后再改回来,在每次更改后广播
WM_SETTINGCHANGE
消息。
祝你好运。如果您需要其他任何帮助,请告诉我。