Windows系统很早就加入了文件关联的功能,它大大增加了日常使用操作系统的便利性。所谓的文件关联就是指系统把指定扩展名的文件自动关联到相应的应用程序,比如.doc文件默认情况下就自动和Microsoft Word关联。当用户双击.doc文件的时候,系统会自动用Microsoft Word打开它。这篇文章将介绍怎样在Windows系统下面手动设置或者用程序自动设置文件关联。
如何手动设置文件关联
Windows系统(包括Windows XP、Windows Vista和Windows 7)都可以手动设置文件关联,下面以Windows 7为例解释怎样设置。
- 打开控制面板->程序->默认程序->关联文件类型或者协议与应用程序:
在上面的屏幕截屏上,我们可以看到.doc文件类型为"Microsoft Word 97 - 2003 Document",其默认关联的应用程序是Microsoft Word。用户可以双击上面列表中的任何一条关联记录来设置自己的关联。比如把TXT文件关联从默认的写字板应用程序改成Microsoft Word。首先双击TXT文件关联记录,弹出下面对话框。然后在其中选择Microsoft Word应用程序默认打开TXT文件,确定之后即可。
如何编程添加文件关联
除了上面介绍的手动设置文件关联,我们还经常需要程序自动设置文件关联。比如,程序有默认的文件格式,我们常常希望自动把该文件格式和程序自动关联起来。现在很多安装包制作软件(比如Install Shield) 都提供了类似的功能,它可以帮助我们在安装过程中设置文件关联。具体的设置方式大家参考相软件使用手册吧。这里我想介绍如何自己写程序来实现文件关联(该技术的经典用例就是希望在程序运行时首先检查文件关联设置并在需要时添加指定文件关联设置)。
- 背景知识
-
Windows用注册表来保存当前系统的所有文件关联设置。它们一般存在下面的几个注册表项中:
- HKEY_LOCAL_MACHINE/Software/Classes:该注册表项包括适用所有用户的默认文件关联设置,如下图所示:
- HKEY_CURRENT_USER/Software/Classes:该注册表项包含只适用当前用户的文件关联设置(它会覆盖HKEY_LOCAL_MACHINE项中的设置)。如下图所示:
除上面两个注册表项和文件关联相关外,还有另外一个非常重要的注册表项:HKEY_CLASSES_ROOT
该注册表项目里面的设置是保证Windows浏览器能够选择正确的应用程序打开相应文件的关键所在。在Windows 2000之后,该注册表项目中的文件关联设置分别存在上面所说的两个注册表项中去了。而HKEY_CLASS_ROOT 注册表项则成为融合(注意,对于相关的文件类型,HKEY_CURRENT_USER下面的设置会覆盖HKEY_LOCAL_MACHINE下面的设置)上面两个注册表项内容的一个镜像。为了更新文件关联设置,你必须更新"HKEY_CURRENT_USER/Software/Classess"或者"HKEY_LOCAL_MACHINE/Software/Classess"下的注册表项,而不是直接更新HKEY_CLASS_ROOT下的注册表项。
- 程序实例
典型的设置文件关联的程序逻辑如下:
检查当前文件类型是否已经关联到某个应用程序(检查HKEY_CLASS_ROOT注册表项,因为它包含了来自HKEY_LOCAL_MACHINE和HKEY_CURRENT_USER设置)。如果没有该文件类型的设置,则进入下一步。如果已经设置了相关的文件关联,则由你的业务逻辑确定需不需要覆盖该文件关联。若需要,则也进入下一步。 添加相应的文件关联到注册表项中去(如果希望该设置只对当前用户有效,则添加到HKEY_CURRENT_USER中,如果希望该设置对机器上的所有用户有效,则添加HKEY_LOCAL_MACHINE中。 刷新更新后的注册表让它生效。具体代码如下:
bool setFileAssociation(const wstring& ext,
const wstring& applicationName,
const wstring& progId,
const wstring& defaultIcon,
const wstring& description)
{
bool bRet = false;
HKEY hExtKey;//检查是否已经为该文件类型设置文件关联
if(RegOpenKey(HKEY_CLASSES_ROOT, ext.c_str(), &hExtKey) == ERROR_SUCCESS)
{
HKEY hKey;
wstring HKCUPrefix = _T("Software//Classes//");
//设置文件关联(注意:需要设置一组值,包括文件类型扩展名、描述、ProgId、默认图标和Windows Shell启动命令格式)
wstring fullExt = HKCUPrefix + ext;
if(ERROR_SUCCESS != RegCreateKey(HKEY_CURRENT_USER, fullExt.c_str(), &hKey)
|| ERROR_SUCCESS != RegSetValue(hKey, _T(""), REG_SZ, progId.c_str(), progId.length() * sizeof(wchar_t) + 1)
|| ERROR_SUCCESS != RegCloseKey(hKey))
{
throw exception(ext.c_str());
}wstring fullProgId = HKCUPrefix + progId;
if(ERROR_SUCCESS != RegCreateKey(HKEY_CURRENT_USER, fullProgId.c_str(), &hKey)
|| ERROR_SUCCESS != RegSetValue(hKey, _T(""), REG_SZ, description.c_str(), description.length() * sizeof(wchar_t) + 1)
|| ERROR_SUCCESS != RegCloseKey(hKey))
{
throw exception(ext.c_str());
}wstring strIconKey = fullProgId + _T(" //DefaultIcon ");
if(ERROR_SUCCESS != RegCreateKey(HKEY_CURRENT_USER, strIconKey.c_str(), &hKey)
|| ERROR_SUCCESS != RegSetValue(hKey, _T(""), REG_SZ, defaultIcon.c_str(), defaultIcon.length() * sizeof(wchar_t) + 1)
|| ERROR_SUCCESS != RegCloseKey(hKey))
{
throw exception(ext.c_str());
}wstring strShellKey = fullProgId + _T(" //Shell ");
if(ERROR_SUCCESS != RegCreateKey(HKEY_CURRENT_USER, strShellKey.c_str(), &hKey)
|| ERROR_SUCCESS != RegSetValue(hKey, _T(""), REG_SZ, _T("Open"), 4 * sizeof(wchar_t) + 1)
|| ERROR_SUCCESS != RegCloseKey(hKey))
{
throw exception(ext.c_str());
}
wstring strCommandKey = fullProgId + _T(" //Shell//Open//Command ");
wstring strCommand = applicationName + _T(" /"%1/"");
if(ERROR_SUCCESS != RegCreateKey(HKEY_CURRENT_USER, strCommandKey.c_str(), &hKey)
|| ERROR_SUCCESS != RegSetValue(hKey, _T(""), REG_SZ, strCommand.c_str(), strCommand.length() * sizeof(wchar_t) + 1)
|| ERROR_SUCCESS != RegCloseKey(hKey))
{
throw exception(ext.c_str());
}//通知系统让上面设置生效
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
bRet = true;
}
return bRet;
}