2012年7月7日星期六

学习笔记:Windows文件关联及有关注册表项


      不得不说Windows的注册表是世界上最混乱的地方之一,各个软件各自为政,没有统一的接口保证,不同版本的Windows具体实现也不一样。为了实现文件关联功能,花了几天时间,找了不少资料,在这里做个总结。
       Windows文件关联是以文件类型为分组,以后缀名为标志的。每种文件类型可以有一个类型描述,Windows中一般称为ProgId(Programmatic Identifiers)。ProgId指示了该类型文件在资源管理器中显示的图标,以及对应打开的程序路径。相同ProId的文件类型可以视为同一组,具有相关的显示图标和相同的打开方式。后缀名与软件的对应是通过ProgId(Programmatic Identifiers)进行的,一个后缀名只能对应一个ProgId,而对应同一个ProgId的后缀名可视为一组。或者说,一个后缀名只能对应一个软件,一个软件可以对应多个后缀。
        在Windows中,这些关联信息保存在注册表中以下两个位置:
        HKEY_CURRENT_USER\Software\Classes
        HKEY_LOCAL_MACHINE\Software\Classes
        其中HKEY_LOCAL_MACHINE\Software\Classes保存的是本机上所有用户的设置,HKEY_CURRENT_USER\Software\Classes保存的是当前用户的设置,而当前用户的设置优先级比较高。对于开启UAC的Windows7来讲,还有一个区别是更改本机设置需要管理员权限,而更改当前用户的设置只需要普通权限。为了方便读取,Windows下还有个HKEY_CLASS_ROOT根键,里面的内容是上面两个位置下的键值合并后的视图。由于是视图,因此最好只用于读取,若要更改则可以更改HKEY_CURRENT_USER\Software\Classes下的内容。
        以HKEY_CURRENT_USER\Software\Classes为例,要关联一个后缀名例如.ext,则需要在上面所说几个位置下有 .ext 这个项,该项的默认值即为对应的ProgId,假设是 YourProgID。在 .ext的相同层级下还应该有一个名为 YourProgID 的项,里面包含了DefaultIconshell\open\command这两个子项。DefaultIcon子项的值为显示的图标,shell\open\command的值为关联的程序。如下:

       HKEY_LOCAL_MACHINE\Software\Classes
       .ext
             (Default) = YourProgID//可以是任何字符串
       YourProgID //与上面的值对应
             DefaultIcon
                    (Default) = iconToShow, 0
             shell
                   open
                          command
                                  (Default) = yourAppPath.exe %1



       这样,当在资源管理器里点击具有.ext后缀名的文件时,Windows会先在HKCR\Software\Classes和HKLM\Software\Classes下寻找 .ext这一项,找到后读取其默认ProgId,再同样寻找此ProgId,找到其shell\open\command的值后就调用该程序。这个过程是一个映射
       在Windows资源管理器中,用户可以通过右键选择“打开方式”改变默认的关联程序,这个设置的优先级在默认的后缀与ProgId关联的方式之上,保存位置则在HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\下。此位置下同样有许多后缀名,如.ext。在XP下,.ext项下面有ProgidApplication子项,Win7下则是UserChoiceApplication子项,子项的值就是关联的ProgId或者应用程序名称(不包括目录,如yourAppPath.exe)。
       至此Windows文件关联机制就很清楚了。首先根据后缀名查找HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\,找不到时查找HKEY_CURRENT_USER\Software\Classes,最后才是HKEY_LOCAL_MACHINE\Software\Classes。因此检查一个文件是否与某个程序关联可以按照这个顺序检查。
       设置一个后缀名与某个程序的关联则有些不一样,主要的原则是先清除原有的关联,再设置新的关联方式。清除关联包括清除用户自己设置的“打开方式”。设置新的关联方式时,最好只在HKEY_CURRENT_USER\Software\Classes下设置。首先设置后缀名的默认ProgId为自己程序的ProgId,再建立一个ProgId指定显示图标和程序路径。
        Win7下清除后缀名与某个程序的关联时要注意,程序只能删除自己拥有的HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ext\UserChoice,因此要清除用户设置的默认打开方式,需要设置一下权限。这可以通过regini.exe这个自带程序来实现。
        还有一点需要注意的是,在更改了文件关联以后,最好通知一下Windows设置已经改变,否则要下次登录才能看到变化。方法是使用SHChangeNotify函数并指定SHCNE_ASSOCCHANGED事件。
       此外在查找资料的过程中,发现很多人更改文件关联时都是将原先对应的ProgId保存起来,要取消关联时则恢复原先的ProgId对应。但根据MSDN上的文章,最好不要取消后.ext对应的值,由系统自己处理更好。
       具体的编程实现可以参考Editor源码中的fileassoc.h和fileassoc.cpp,使用Qt4完成。

      
参考资料:

1 条评论: