关于win7的文件关联问题

Windows的文件关联一直是个让人极为头疼的大问题。尤其是如果你是程序作者,如果你想完成诸如把某某文件类型的默认打开方式设置为自己的程序或者给某某文件类型添加一个右键菜单之类的功能,就得不得不面对这一问题。

之前我写Fixcue时,曾经大致地对这一方面进行了一定的了解,最终根据XP和Win7的不同,分别作出了不同的注册表写入方法,当时测试没有什么问题。结果这我自己装了win7之后,第一次运行就报错了。检查了一下程序的逻辑判断,没觉得有什么奇怪之处,结果一打开注册表傻眼了:在HKEY_CLASSES_ROOT下根本没有.cue这一项!我当时也懒得折腾,手动创建了一个改了下键值了事;今天折腾.txt又碰到类似的问题,于是决定彻底搞明白这玩意。

Win7注册表里,存储文件关联主要在这两个地方,一个自然就是HKEY_CLASSES_ROOT下,另一个是HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\。其实这么说可能不太恰当,因为准确地说,前者才是真正定义的地方,而后者则是从前者定义的各种类中选择一个。另外需要注意的是,后者既然在Current User下,那么自然是一个和当前登录用户有关的项。而前者,根据MSDN上关于HKEY_CLASSES_ROOT的介绍,我们可以得知,这个项的存在,主要是出于向下兼容的目的,其本质上是HKEY_LOCAL_MACHINE\Software\Classes和HKEY_CURRENT_USER\Software\Classes的集合(所以也就包含了全局的类和用户特有的类)。但是介于无论修改哪个,对应的项都会跟着变化,而HKEY_CLASSES_ROOT访问起来毕竟路径比较短比较好点,所以一般从这里下手比较多啦。

这里定义打开方式的形式是:在对应的后缀名下建立shell项,里面再建立open项,里面再建立command项,也就是形如:

HKEY_CLASSES_ROOT\.cue\shell\open\command

这样,然后command的键值里写入譬如c:\windows\notepad.exe %1的打开方式。

而后者的结构很清晰,还拿cue(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.CUE)为例,里面有三个子项,分别为:

1. OpenWithList 打开方式里候选的程序;
2. OpenWithProgids 候选的Progid(程序标识符,一般来说就是一个类);
3. UserChoice 设定用户现在选择的打开方式。形式为里面含有Progid键,键值为对应的Progid名。(注意:这里的Progid名,绝大部分时候就是类名,其实就是HKEY_CLASSES_ROOT下的某个子项的名字)

如果没有UserChoice,那么则会选择对应的后缀名的ROOT里的shell\open\command里定义的打开方式。

如果问题只是这么简单就好了,但是实际上有个非常重要的设定——ROOT中类的“重定向”功能。在HKEY_CLASSES_ROOT之中,任意后缀名其本身的默认键值,其本来的目的(我猜)应该是对该类进行描述(比如txtfile的默认键值是Text Document),但事实上,更多的时候被用来进行“重定向”。其方法也很简单,就是将键值设置为另外一个类的名字,那么碰到此类后缀,就会自动把其当成后者。

一个例子就是HKEY_CLASSES_ROOT\.txt里的键值是txtfile,那么自然会对应到HKEY_CLASSES_ROOT\txtfile类。而txtfile里有设定shell\open\command的话,就会用这种方法打开;但是注意前提是HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.txt不能有设定UserChoice的Progid,否则它拥有更高的优先级;而HKEY_CLASSES_ROOT\.txt如果本身也设置有shell\open\command的话,优先级最低。即据优先级排:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.txt\UserChoice中的Progid键值>
HKEY_CLASSES_ROOT\txtfile\Shell\open\command的键值>
HKEY_CLASSES_ROOT\.txt\Shell\open\command的键值
前提:HKEY_CURRENT_USER\.txt的键值为txtfile。

另外更多的例子有如果你装了winrar,那么.rar将被重定向到WinRAR类、.zip将被重定向到WinRAR.zip类、如果你用TTplayer那么.cue将被重定向到Audio.CUE等等。

另外请注意,这个优先级,在XP下似乎有不同。又或者,XP下根本没有什么UserChoice的设定。总之,如果我没记错,在XP下用重定向类的方式来改变文件的打开方式抑或是添加右键菜单,屡试不爽。

其实,win7这种强制UserChoice最高优先级的作法,才是正确的。但是很遗憾的是,很多程序,甚至可以说绝大部分程序,还在使用重定向类的方式来关联程序。而这种方法在win7下,如果用户曾通过右键菜单手动指定过某文件类型的打开方式,那么是无效的(不过,如果用户从未进行过这类操作,那么UserChoice项根本不存在,倒是不会出现什么问题),双击打开该文件仍会采用UserChoice的设定。不得不提Foobar2000的作者的高明,早早地就采用了win7自带的文件关联方式,可以完美地处理文件关联问题。

更为蛋疼的是,如果UserChoice的Progid和重定向的不一致,那么对于某些依赖于某些文件类型的默认类的程序来说,是极为蛋疼的。这么说可能有点绕,拿我写的Fixcue来说吧:我现在需要实现在cue文件类型右键菜单添加一条“用Fixcue修复”的命令,那么我首先需要知道,.cue对应的到底是哪个类。如果在XP年代,我只需要查找一下ROOT\.cue的键值就知道了;而在win7里,你需要知道的是HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.cue\UserChoice里的Progid的键值。同样地,很多程序员依然没有注意到这一现象,仍然采用从ROOT\.cue找键值的方法,于是程序就会在意外的地方报错了。

注:本文中,Progid和类(Class)大部分时候同义。但是Progid似乎不限于类,具体我也搞不清,所以采取了可能会产生混淆的说法,请见谅,欢迎留言纠正。

Advertisements

3 thoughts on “关于win7的文件关联问题

  1. HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.txt\UserChoice中的Progid键值>
    HKEY_CURRENT_USER\txtfile\Shell\open\command的键值>
    HKEY_CURRENT_USER\.txt\Shell\open\command的键值
    前提:HKEY_CURRENT_USER\.txt的键值为txtfile。

    X

    HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.txt\UserChoice中的Progid键值>
    HKEY_CLASSES_ROOT\txtfile\Shell\open\command的键值>
    HKEY_CLASSES_ROOT\.txt\Shell\open\command的键值
    前提:HKEY_CURRENT_USER\.txt的键值为txtfile。

    O

    啧啧,原来这么简单

    另外在FileEx下发现了“.v6太不给力了……”,“.2-RELOADED”等类……囧

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s