文件关联(C#和Inno脚本实现)

  最近在做一个APK安装器,需要:可双击打开,或者右键点打开可自动开启所做的APK安装器。其实文件关联就是一些注册表的添加,修改和删除,以前没做过太多注册表操作,在网上搜了很多,结果发现都有一些问题,最后从乔尔(新浪技术博客)那里看到一些操作,然后稍作修改,实现文件关联,图标关联。

  因为我之前是关联的.APK文件,就一关联.APK文件说事儿了。

  文件关联操作主要的几个地方:

1.删除操作:删除根目录CurrentUser下面的Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.apk下面的所有子节点,这一点很重要,也很霸道,最初我没操作这一步,结果无论我怎么关联,都是不成功的,双击.apk文件的时候,它启动的始终不是自己做的apk安装器。霸道是因为:之前电脑里面.apk可能已经和某个EXE关联,我们删掉这里,就断了他们的直接关联,这是让apk文件和我们的安装器直接关联的第一步。

2.添加操作:在根目录ClassesRoot下添加一个节点,如CN.APKInstaller,第二步:添加子节点defaultIcon,这个是默认的图标,然后指定本地一个ico文件路径,这样凡是电脑上面的apk文件都会变成你指定那张图片;第三步:在CN.APKInstaller下添加子节点shell,然后再在shell下添加两个子节点open和play,open节点值设为"打开APK",play节点设为"用APKInstaller打开"。这样你在一个apk文件上点击右键就会看到你设置的东西了。

 3.继续添加操作:上一步操作,分别在open和play节点下添加同样的command节点,然后设定command值是你本地APKInstaller的执行文件路径加上一个   " %1”,如"C:\Program Files\APKInstaller.exe" "%1",后面的"%1"是为了实现双击时可以打开EXE。

4.修改操作:修改在根目录ClassesRoot下面的.apk节点的值,设置为CN.APKInstaller,完成。

主要代码如下:

  首先是一个系统API,可以使你的修改不用重启电脑就可以生效:

int SHCNE_ASSOCCHANGED = 0x08000000;
int SHCNF_IDLIST = 0x0000;        

[DllImport("shell32.dll")]
static extern void SHChangeNotify(HChangeNotifyEventID wEventId,
                                           HChangeNotifyFlags uFlags,
                                           IntPtr dwItem1,
                                           IntPtr dwItem2);

 

接下来是一个封装好的方法,直接调用就可以了:
View Code
 public void SetValue(string exeName, string nodeName, string iconPath)
{
            RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts", true);
            if (key.OpenSubKey(".apk") != null)
            {
                key.DeleteSubKeyTree(".apk");
                key.CreateSubKey(".apk");
            }
            if (Registry.ClassesRoot.OpenSubKey(nodeName) != null)
            {
                Registry.ClassesRoot.DeleteSubKeyTree(nodeName);
            }
            if (Registry.ClassesRoot.OpenSubKey(nodeName) == null)
            {
                RegistryKey progId = Registry.ClassesRoot.CreateSubKey(nodeName);
                progId.SetValue("", "APK Instarller");
                RegistryKey defaultIcon = progId.CreateSubKey("DefaultIcon");
                defaultIcon.SetValue("", iconPath);

                RegistryKey shell = progId.CreateSubKey("shell");

                RegistryKey open = shell.CreateSubKey("open");
                open.SetValue("", "安装APK");
                RegistryKey command = open.CreateSubKey("command");
                command.SetValue("", "\"" + exeName + "\" \"%1\"");

                RegistryKey play = shell.CreateSubKey("play");
                play.SetValue("", "用APKInstaller打开");
                command = play.CreateSubKey("command");
                command.SetValue("", "\"" + exeName + "\" \"%1\"", RegistryValueKind.String);
            }
            //修改对应文件类型的默认的关联程序
            RegistryKey apk = Registry.ClassesRoot.OpenSubKey(".apk", true);
            if (apk != null)
            {
                apk.SetValue("", nodeName);
            }
            //通知系统,文件关联已经是作用,不然可能要等到系统重启才看到效果
            SHChangeNotify(HChangeNotifyEventID.SHCNE_ASSOCCHANGED, HChangeNotifyFlags.SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero);
}

例如,调用:string str = @"F:\WorkFile\PC\Setup\apk.ico";
            SetValue(@"F:\WorkFile\PC\Bin\Debug\APKInstaller.exe", "CN.APKInstaller",str);

 

  用Inno脚本的实现原理和上面时一样的,只是需要知道一些脚本的语法而已,脚本如下(其实我也不是很懂):

const
  SHCNE_ASSOCCHANGED = $08000000;
  SHCNF_IDLIST = $0000; { LPITEMIDLIST }

function SHChangeNotifyEx(wEnentID: Integer; uFlag: Cardinal; dwItem1: Integer; dwItem2: Integer): Integer;external 'SHChangeNotify@shell32.dll ';

procedure LinkFileIcon;
var
  FullPath: string;
  IconFilePath:string;
  success:Boolean;
begin
  success := RegDeleteValue(HKEY_CURRENT_USER, 'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.apk', 'Application');
  success := RegDeleteKeyIncludingSubkeys(HKEY_CURRENT_USER, 'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.apk');
  success := RegWriteStringValue(HKEY_CLASSES_ROOT, '.apk', '', ExpandConstant('{#FileExAPP}'));
  FullPath := ExpandConstant('{app}') + '\' + ExpandConstant('{#ProductShortName}') +'.exe';
  success := RegWriteStringValue(HKEY_CLASSES_ROOT, ExpandConstant('{#FileExAPP}') + '\shell\open\command', '', '"' + FullPath+ '"' + ' "%1"');
  //IconFilePath := ExpandConstant('{app}') + '\' + ExpandConstant('{#ProjectFileIcon}');
  IconFilePath := ExpandConstant('{app}\APKInstaller.exe,0');
  success := RegWriteStringValue(HKEY_CLASSES_ROOT, ExpandConstant('{#FileExAPP}') + '\DefaultIcon', '', IconFilePath);
  SHChangeNotifyEx(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
end;
///接触工程文件与应用程序的关联
procedure UnLinkFileIcon;
begin
  RegDeleteKeyIncludingSubkeys(HKEY_CLASSES_ROOT, ExpandConstant('{#FileExAPP}'));
  SHChangeNotifyEx(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
end;  

 

调用:

procedure CurStepChanged(CurStep: TSetupStep);
begin
    LinkFileIcon();
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
    UnLinkFileIcon;
end;

 

稍后将会写一篇有关 文件拖拽到图标或者界面可以直接打开一个新的界面的 文章。排版太烂了,先自喷一个!
posted @ 2012-07-20 11:48  菜鸟_飞飞  阅读(1166)  评论(0编辑  收藏  举报