文档章节

Windows 文件关联机制剖析

東條・スペンサー・咲
 東條・スペンサー・咲
发布于 2017/08/20 10:40
字数 2279
阅读 28
收藏 0

最近要在Windows下实现文件关联,搜集了很多资料,但是质量太乱了。这里将其汇总一下。

Windows中的文件关联

Windows文件关联是以文件类型为分组,以后缀名为标志的。每种文件类型可以有一个类型描述,Windows中一般称为ProgId(Programmatic Identifiers)。ProgId指示了该类型文件在资源管理器中显示的图标,以及对应打开的程序路径。相同ProId的文件类型可以视为同一组,具有相关的显示图标和相同的打开方式。后缀名与软件的对应是通过ProgId(Programmatic Identifiers)进行的,一个后缀名只能对应一个ProgId,而对应同一个ProgId的后缀名可视为一组。或者说,一个后缀名只能对应一个软件,一个软件可以对应多个后缀。

Windows的文件关联由几部分组成,优先级从最高向下依次是:

  • 打开方式设置:用户通过右键菜单中的打开方式对话框指定的设置,
  • 用户设置:仅适用于一特定用户的设置,可由程序提供,
  • 本机设置(所有用户设置):适用于本机所有用户的设置。

文件关联的实现

Windows通过注册表项来关联特殊后缀的文件以及启动他们的程序。有几个地方会有关联信息:
1、HKEY_LOCAL_MACHINE\Software\Classes:该注册表项包括适用所有用户的默认文件关联设置
2、HKEY_CURRENT_USER\Software\Classes:该注册表项包含只适用当前用户的文件关联设置(它会覆盖HKEY_LOCAL_MACHINE项中的设置)
3、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下的注册表项

对于开启UAC的Windows Vista及其后面的版本来讲,还有一个区别是更改本机设置需要管理员权限,而更改当前用户的设置只需要普通权限。

以当前用户设置为例(HKEY_CURRENT_USER),本机设置(HKEY_LOCAL_MACHINE)与用户设置的结构完全一致:

HKEY_CURRENT_USER\Software\Classes
.ext
	(Default) = $YourProgID //任意字符串
	Content Type = $ContentType //可选,HTTP Content Type
	PerceivedType = $PreceivedType //可选,感知类型
	OpenWithProgIds
		(Default) = 空
		$YourProgID = 空
	PersistentHandler //可选
		(Default) = {xxx} //CLSID
$YourProgID //与上面的值对应
	(Default) = $Description //可选,对该文件类型的描述
	DefaultIcon
		(Default) = yourAppPath.exe,1 //可选,文件应当显示的图标
	shell
		open
			command
				(Default) = yourAppPath.exe %1 //打开该文件的命令行参数
		edit
			command
				(Default) = yourAppPath.exe %1 //编辑该文件的命令行参数
		preview
			command
				(Default) = yourAppPath.exe %1 //预览该文件的命令行参数
		printto
			command
				(Default) = yourAppPath.exe %1 //打印该文件的命令行参数

下面将对其中的几个键值进行说明

HTTP Content Type

这个在HTTP请求头里面非常常见,例如文本文件为text/plain,可以在OSC的在线工具查询(在此感谢OSC提供的速查列表,帮大忙了)。

感知类型(PerceivedType)

感知类型是能够让Windows识别的一组文件格式,例如图像类、音频类、文档类。这个键值允许Windows根据其感知类型进行不同的操作,例如一个文件夹的图标,当它是空的时候和当它含有文件的时候,预览的图标可以用两种形式进行显示。这个操作是通过感知类型键值来进行识别并且处理的。

默认的感知类型有以下几种:

  • Folder(文件夹)
  • Text(文本文件)
  • Image(图像文件)
  • Audio(音频文件)
  • Video(视频文件)
  • Compressed(压缩文件)
  • Document(文档文件)
  • System(系统文件)
  • Application(应用程序文件)
  • Gamemedia(游戏、媒体文件)
  • Contacts(联系人文件)

永久句柄(PersistentHandler)

这个键值我没有进行深入的研究,大部分软件用的非常少。在我这里的话,Visual Studio注册的部分使用了这个键值。按照官网的解释,应该是为过滤器准备的。但是在没有明确的功能描述。

如果有人愿意去研究一下的话,这里提供两个链接:一个是Persistent Handlers (Windows)、另一个是Registering Filter Handlers (Windows)

打开、编辑、预览、打印(Open、Edit、Preview、Printto)

打开,顾名思义,就是指当用户在资源管理器中双击、按下回车、或者右键打开时触发的选项。也就是我们通常意义上的文件关联。

编辑,这个选项也很常见。例如随意右键一个ini文件,一般情况下都能看到编辑按钮。这个选项可以让Windows具有使用浏览器和编辑器打开同一种文件的能力。比如对于音频文件来说,我希望使用播放器去播放,然而使用Audition去编辑它(播放器一般来说是不能编辑音频文件的,或者说,不应当由播放器去编辑),那么就需要把这里的默认键值设置为Audition在命令行打开音频文件时的命令。

预览,这个选项很少见到(或者说很少有人会去用吧)。Photoshop会设置此键值。设置后,右键菜单中的预览命令就是这个选项的关联项。

打印,右键菜单中的打印命令的关联项。

打开方式对话框设置

在Windows资源管理器中,用户可以通过右键选择“打开方式”改变默认的关联程序,这个设置的优先级在默认的后缀与ProgId关联的方式之上,保存位置则在HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\下。此位置下同样有许多后缀名,如.ext。在XP下,.ext项下面有Progid或Application子项,Windows 7下则是UserChoice或Application子项,子项的值就是关联的ProgId或者应用程序名称(不包括目录,如yourAppPath.exe)。

该设置注册表下的结构(以Windows 7为例):

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts
.ext
	(Default) = 空
	OpenWithList
		(Default) = 空
		a = xxx.exe //自定义的应用程序1
		b = xxx.exe //自定义的应用程序1
		...
		MRUList = ab //所有自定义程序的列表
	OpenWithProgids
		(Default) = 空
		xxxx.xxx (REG_NONE) //长度为0的二进制值
	UserChoice
		(Default) = 空
		Progid = $xxx //用户选择的应用程序,Application/xxx.exe或者一个Progid

需要注意的是,这个键不建议通过程序进行设置。而且有该键不被允许访问的报告出现。所以在写代码的时候,这部分键值的处理需要慎重考虑。

至此Windows文件关联机制就很清楚了。首先根据后缀名查找HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\,找不到时查找HKEY_CURRENT_USER\Software\Classes,最后才是HKEY_LOCAL_MACHINE\Software\Classes。因此检查一个文件是否与某个程序关联可以按照这个顺序检查。

清除文件关联

Windows 7下清除后缀名与某个程序的关联时要注意,程序只能删除自己拥有的HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ext\UserChoice,因此要清除用户设置的默认打开方式,需要设置一下权限。(这也就是为什么Foobar2000之类的软件会单独带一个设置文件关联的exe了)

在取消文件关联的时候,不需要保存之前的Progid。只需要交给系统处理即可。

杂项

在更改了文件关联以后,最好通知一下Windows设置已经改变,否则要下次登录才能看到变化。方法是使用SHChangeNotify函数并指定SHCNE_ASSOCCHANGED事件。

对于默认程序的设置,需要参照MSDN上的Default Programs这篇文章。

官方建议:总是在文件路径两侧使用双引号;避免硬编码的路径(比如Windows 2000下,没有C:\Windows只有C:\WINNT。官方建议是使用环境变量,例如上例应当是%SYSTEMROOT%);。

官方不建议:从现有的文件关联键复制再进行编辑;使用短的文件拓展名(然而QBasic里面只支持三个字母啊,笑)。

所有有关文件关联相关的文章,可以在MSDN的文件类型和文件关联部分找到。

参考文章

MSDN 的 Files Types:https://msdn.microsoft.com/en-us/library/windows/desktop/cc144148(v=vs.85).aspx
MSDN 的 Best Practices for File Associations:https://msdn.microsoft.com/en-us/library/windows/desktop/cc144156(v=vs.85).aspx
erikaIT 的 windows注册表文件关联机制:http://blog.csdn.net/erikaIT/article/details/71637167
三生石 的 学习笔记:Windows文件关联及有关注册表项:http://yuezhaoblog.blogspot.com.au/2012/07/windows.html

版权声明

本文基于WTFPL发布。

© 著作权归作者所有

共有 人打赏支持
東條・スペンサー・咲

東條・スペンサー・咲

粉丝 34
博文 4
码字总数 5026
作品 1
其他
程序员
ConcurrencyMode.Multiple 模式下的WCF服务就一定是并发执行的吗:探讨同步上下文对并发的影响[下篇]

在《上篇》中,我通过一个具体的实例演示了WCF服务宿主的同步上下文对并发的影响,并简单地介绍了同步上下文是什么东东,以及同步上下文在多线程中的应用。那么,同步上下文在WCF并发体系的内...

长平狐
2012/09/04
426
0
libevent源码深度剖析

作者:http://blog.csdn.net/sparkliang/article/category/660506 libevent源码深度剖析十三——libevent信号处理注意点 2010-02-11 20:00阅读(1669)评论(6) libevent源码深度剖析PDF 2010-...

晨曦之光
2012/03/09
2.4K
0
WCF技术剖析之八:ClientBase<T>中对ChannelFactory<T>的缓存机制

和传统的分布式远程调用一样,WCF的服务调用借助于服务代理(Service Proxy)。而ChannelFactory则是服务代理的创建者。WCF采用基于终结点(Endpoint)服务消费方式:WCF服务通过一个或者多个...

长平狐
2012/09/04
218
0
JDK不同操作系统的FileSystem(Windows&Unix-like)

前言 我们知道不同的操作系统有各自的文件系统,这些文件系统又存在很多差异,而Java 因为是跨平台的,所以它必须要统一处理这些不同平台文件系统之间的差异,才能往上提供统一的入口。 关于...

超人汪小建
2017/12/12
0
0
文件和目录的访问控制(1) 访问控制列表

文件和目录的访问控制(1) 访问控制列表 权限的概念相信你已经不陌生了,那么如何设置一个文件的访问权限呢?编程可不可以实现动态的控制文件权限信息呢?答案是肯定的,.NET可以做到这些。 ...

zting科技
2017/01/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

70.shell的函数 数组 告警系统需求分析

20.16/20.17 shell中的函数 20.18 shell中的数组 20.19 告警系统需求分析 20.16/20.17 shell中的函数: ~1. 函数就是把一段代码整理到了一个小单元中,并给这个小单元起一个名字,当用到这段...

王鑫linux
今天
0
0
分布式框架spring-session实现session一致性使用问题

前言:项目中使用到spring-session来缓存用户信息,保证服务之间session一致性,但是获取session信息为什么不能再服务层获取? 一、spring-session实现session一致性方式 用户每一次请求都会...

WALK_MAN
今天
5
0
C++ yield()与sleep_for()

C++11 标准库提供了yield()和sleep_for()两个方法。 (1)std::this_thread::yield(): 线程调用该方法时,主动让出CPU,并且不参与CPU的本次调度,从而让其他线程有机会运行。在后续的调度周...

yepanl
今天
4
0
Java并发编程实战(chapter_3)(线程池ThreadPoolExecutor源码分析)

这个系列一直没再写,很多原因,中间经历了换工作,熟悉项目,熟悉新团队等等一系列的事情。并发课题对于Java来说是一个又重要又难的一大块,除非气定神闲、精力满满,否则我本身是不敢随便写...

心中的理想乡
今天
31
0
shell学习之获取用户的输入命令read

在运行脚本的时候,命令行参数是可以传入参数,还有就是在脚本运行过程中需要用户输入参数,比如你想要在脚本运行时问个问题,并等待运行脚本的人来回答。bash shell为此提 供了read命令。 ...

woshixin
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部