和其他语言一样,C#实现文件关联同样需要直接操作注册表,即按规则分别设置文件扩展名,文档类型说明,友好名称,图标,调用方法等键值即可,网上随便查查就可以写出以下的代码。
using Microsoft.Win32;
RegistryKey key = Registry.ClassesRoot.OpenSubKey(".jb");
if (key == null)
{
key = Registry.ClassesRoot.CreateSubKey(".jb");
key.SetValue("", "Jeebook.Reader.jb");
key.SetValue("Content Type", "application/jb");key = Registry.ClassesRoot.CreateSubKey("Jeebook.Reader.jb");
key.SetValue("", "Jeebook Document");RegistryKey keySub = key.CreateSubKey("DefaultIcon");
keySub.SetValue("", System.Windows.Forms.Application.StartupPath + "Jeebook.ico");
keySub = key.CreateSubKey("shell//open//command");
keySub.SetValue("", "/"" + System.Windows.Forms.Application.ExecutablePath + "/" /"%1/"");
}
相对来说,C#实现比较麻烦的是图标路径,一般文件类型注册的都是执行文件的资源,格式如下:
格式:<执行程序exe路径>,<资源ID> // 资源ID为正数,表示资源的索引号,否则为资源ID
在C++中很容易获取资源ID,但C#中还没搞清楚如何取道资源的ID,所以索性在程序执行目录下附带一个图标文件用于注册,这样倒也方便随时修改:)
此外,就是如何验证图标是否设置正确。现在的系统超爱缓存,除非LOG OFF级别的操作,否则手工修改注册表很难马上响应,当然通过程序调用应该刷新系统状态,这个下次有时间再研究吧
如果只是用于XP以下的程序,以上的代码就已经足够了。可惜的是,Vista以后引入了UAC,上面的代码在UAC下会弹出异常,这肯定不是我们希望的。
一种解决方法是通过创建一个Mainifest文件,添加以下脚本:
这样程序图标上会出现一个小盾牌,表示该程序需要在管理员模式下运行,每次运行都会自动弹出UAC的验证窗口。但这个对某些只是需要书写一次注册表的程序来说,每次都弹出提示是无法忍受的,那么如何能够通过代码弹出UAC验证窗口呢?
Google的结果,貌似没有在运行中触发提示并将进程改变为管理员模式的办法,不过只要在执行进程时将Verb设置为runas就可以自动触发UAC验证,使被调用的程序在管理员模式下运行。那么,只要在程序中重新启动自己就可以达到触发UAC验证窗口的目的,代码如下:
System.Diagnostics.ProcessStartInfo start = new System.Diagnostics.ProcessStartInfo();
System.Diagnostics.Process p = new System.Diagnostics.Process();
start.WorkingDirectory = System.Windows.Forms.Application.StartupPath;
start.Verb = "runas";
start.FileName = System.Windows.Forms.Application.ExecutablePath;
System.Diagnostics.Process.Start(start);
当然,如果你将上面的代码直接放入你的FormLoad中,那将是场灾难,因为你的程序会不断的启动自己直到把你的机器资源耗光为止。所以我们还需要有能够判断是否已经进入管理员模式的代码,如下:
WindowsIdentity wi = WindowsIdentity.GetCurrent();
WindowsPrincipal wp = new WindowsPrincipal(wi);if (!wp.IsInRole(WindowsBuiltInRole.Administrator))
wi代表的是当前用户,WindowsBuiltInRole.Administrator是管理员的标识符(比较奇怪的是VB好像有自己特殊的名字空间来实现以上的功能,不知为什么,当然我们用标准的方法判断也没什么不好)
由此将以上所有的代码整合起来,得到以下的结果:
if ( null != Registry.ClassesRoot.OpenSubKey(".jb") )
return;WindowsIdentity wi = WindowsIdentity.GetCurrent();
WindowsPrincipal wp = new WindowsPrincipal(wi);if (!wp.IsInRole(WindowsBuiltInRole.Administrator))
{
System.Diagnostics.ProcessStartInfo start = new
System.Diagnostics.ProcessStartInfo();
System.Diagnostics.Process p = new System.Diagnostics.Process();
start.WorkingDirectory = System.Windows.Forms.Application.StartupPath;
start.Verb = "runas";
start.FileName = System.Windows.Forms.Application.ExecutablePath;
System.Diagnostics.Process.Start(start);
Application.Exit();
return;
}RegistryKey key = Registry.ClassesRoot.OpenSubKey(".jb");
if (key == null)
{
key = Registry.ClassesRoot.CreateSubKey(".jb");
key.SetValue("", "Jeebook.Reader.jb");
key.SetValue("Content Type", "application/jb");key = Registry.ClassesRoot.CreateSubKey("Jeebook.Reader.jb");
key.SetValue("", "Jeebook Document");RegistryKey keySub = key.CreateSubKey("DefaultIcon");
keySub.SetValue("", System.Windows.Forms.Application.StartupPath + "Jeebook.ico");
keySub = key.CreateSubKey("shell//open//command");
keySub.SetValue("", "/"" + System.Windows.Forms.Application.ExecutablePath + "/" /"%1/"");
}
文件关联是个很常用很简单的功能,但真要做的好,还得费点功夫啊:)