inno setup读取注册表遇到的一个坑
一、背景
目前,公司针对PR开发的一个插件需要发布到64位系统上。该插件包括一个prm格式的文件和若干个DLL文件。其中,prm文件需要复制到PR公共插件目录下,DLL需要复制到Windows系统目录中去,这样插件才能正常的工作。公司现在要求发布插件时制作一个安装包,让用户点击安装包后自动将插件相关文件拷贝到相应目录去。本来用inno setup来做一个安装包,顶多就是一个多目录安装的问题。但是,公司发布的插件只能应用在Win64位平台,而且要求通过读取注册表来确定具体的安装目录。这是背景,也正是本文要说坑。
二、分析过程
本来拿到需求一想还挺简单的,本来就详细看过Inno setup的文档,读取注册表只需要调用RegQueryStringValue()即可读取注册表中指定项目。代码就这么写:
function GetInstallString(): String;
var
sInstallPath: String;
begin
sInstallPath := '';
if RegValueExists(HKLM, 'SOFTWARE\Adobe\Premiere Pro\CurrentVersion', 'Plug-InsDir') then
begin
RegQueryStringValue(HKLM, 'SOFTWARE\Adobe\Premiere Pro\CurrentVersion', 'Plug-InsDir', sInstallPath)
end
Result := sInstallPath;
end;
逻辑很简单:先判断这个键是否存在,存在就继续读取键值。编译成功生成安装包。可是一运行问题来了,根本就没有获取到键值。注册表打开着对着写的,路径也反复看了好几遍是错不了的。但是为什么就读取不到具体的键值呢?网上资料不多,大多使用的例子也是如上并无二般。那是为什么呢?那么其他的键值能否读到呢?还是说只是读取不到这个键值?于是变换着,换到一个其他的ROOT下,如HKEY_USERS或者HKEY_CLASSES_ROOT:
function GetInstallString(): String;
var
sInstallPath: String;
begin
sInstallPath := '';
if RegValueExists(HKEY_CURRENT_USER, 'Software\Adobe\Premiere Pro\9.0\PluginCache.64\zh_CN\PSIParser.dll\Com Module', 'ComFullPath') then
begin
RegQueryStringValue(HKEY_CURRENT_USER, 'Software\Adobe\Premiere Pro\9.0\PluginCache.64\zh_CN\PSIParser.dll\Com Module', 'ComFullPath', sInstallPath)
end
Result := sInstallPath;
end;
编译运行正常获得注册表中的键值。再换成HKEY_USERS下的其他键值同样获取成功。那么HKEY_LOCAL_MACHINE下的其他键值是否能获取得到呢?随便找了个键值项,发现也无法获得到键值。那么问题就来了:其他ROOT下的键值都可以获得成功,唯独HKEY_LOCAL_MACHINE下的键值获取不到,这是为什么呢?在网上搜了搜,看到了一个有用的帖子:http://stackoverflow.com/questions/4033976/inno-setup-doesnt-allow-access-to-all-registry-keys-why。通篇读下来,发现了一种解决方法,只要在ROOT名称后跟上64即可解决问题:
function GetInstallString(): String;
var
sInstallPath: String;
begin
sInstallPath := 'C:\Program Files\Adobe\Common\Plug-ins\7.0\MediaCore';
if RegValueExists(HKLM64, 'SOFTWARE\Adobe\Premiere Pro\CurrentVersion', 'Plug-InsDir') then
begin
RegQueryStringValue(HKLM64, 'SOFTWARE\Adobe\Premiere Pro\CurrentVersion', 'Plug-InsDir', sInstallPath)
end
Result := sInstallPath;
end;
那么,问题的原因是什么呢?实际上问题就出在Win64上。Windows 32bit和64bit版本的注册表稍微有不同。我们知道64bit系统上照样可以跑32bit的程序,因此在注册表上也有区分,特意为32bit程序作了兼容处理。32bit程序对注册表HKEY_LOCAL_MACHINE根下的项目操作都进行了重定向:读取HKEY_LOCAL_MACHINE\SOFTWARE下的键值都会重定向到HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\<company>\<product>。那么这就很好解释了,Premiere Pro目前只能运行在64Bit系统上,因此在Wow6432Node下是不会存在记录的,读取相应键值自然会失败。
通过HKLM32和HKLM64明确指出读取的具体位置,就可以避免上述这种问题了。事实上,在inno setup的说明文档中还有另外一种方法可以尝试,也可以避免64bit系统产生的问题。具体代码:
var
OldState: Boolean;
ResultCode: Integer;
begin
// First verify that the user is running a supported -bit version
// of Windows, because calling EnableFsRedirection(False) will
// raise an exception otherwise.
if IsWin64 then
begin
// Turn off redirection, so that cmd.exe from the -bit System
// directory is launched.
OldState := EnableFsRedirection(False);
try
Exec(ExpandConstant('{cmd}'), '', '', SW_SHOW,
ewWaitUntilTerminated, ResultCode);
finally
// Restore the previous redirection state.
EnableFsRedirection(OldState);
end;
end;
end;
关键就是通过调用EnableFsRedirection()函数来禁用注册表操作转发行为。在调用之前先判断当前安装程序是否是运行在64位系统上。
Update 2016-3-7:
在64Bit系统上,将动态库文件拷贝到C:\WINDOWS\System32目录下时,会自动重定向到SysWOW64目录下,导致程序运行异常。这事可以通过设置在[Files]段设置Flags:64即可禁用目录重定向(参考链接)。
三、参考链接
1、http://www.jrsoftware.org/ishelp/index.php?topic=isxfunc_regquerystringvalue
2、http://www.jrsoftware.org/ishelp/index.php?topic=consts
3、http://stackoverflow.com/questions/4033976/inno-setup-doesnt-allow-access-to-all-registry-keys-why
4、http://www.jrsoftware.org/ishelp/index.php?topic=64bitlimitations
5、http://www.jrsoftware.org/ishelp/index.php?topic=isxfunc_enablefsredirection
inno setup读取注册表遇到的一个坑的更多相关文章
- [Inno Setup]写入注册表时32位系统和64位系统的路由
昨天下午组内一位同事跟说,他想在Inno Setup的安装包中写入一个注册表.目标位置是HKLM:\Software\下面创建自己的注册表项.然后说尝试了好几次都不行, 但是往HKCU下面写入却是OK ...
- Inno setup 操作注册表操作参数详解
原文地址:http://www.dayanzai.me/inno-setup-tut.html [Registry] 段这个可选段用来定义一些你想用安装程序在用户系统中创建.修改或删除的注册表键/值. ...
- WinCE下读取注册表获得SD路径
WinCE下读取注册表获得SD路径 [要点]WinCE注册表中[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SDMemory\] 下键Folde ...
- C#读取注册表信息
注册表是视窗系统的一个核心的数据库,在这个数据库中存放中与系统相关的各种参数,这些参数直接控制中系统的启动.硬件的驱动程序安装信息以及在视窗系统上运行的各种应用程序的注册信息等.这就意味着,如果注册表 ...
- 用javascript技术读取注册表中软件安装位置并启动本地软件
1.首先读取注册表中本地软件安装的位置,如果未安装则无就跳转到下载页面. 2.启动软件,关闭页面. 3.如报错提示. <SCRIPT language=javascript> <! ...
- Advanced Installer读取注册表时将Program Files读取为Program Files (x86)的解决办法
原文:Advanced Installer读取注册表时将Program Files读取为Program Files (x86)的解决办法 今天同事在做安装包的时候,有一个读取注册表路径的需求,需要根据 ...
- 读取注册表获取Windows系统XP/7/8/10类型(使用wcscmp比较wchar[]内容)
很多方案是采用GetVersion.GetVersionEx这两个API来查询操作系统的版本号来判断当前的操作系统是Windows系列中的哪个,在Win10没有出现前,这种方法是行的通的,但是Win1 ...
- c++读取注册表的实例
// CRegisterTest.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> #in ...
- Java Windows下读取注册表的工具类
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...
随机推荐
- ASP.net之策略模式
设计思路: 用ASP.net设计,调用策略模式.在第一个数和第二个数的文本框中输入数值,单击录题按钮,数值保存在n1,n2文档中,把要做的题都保存完后,单击开始按钮,开始做题,做完单击判断按钮,进行判 ...
- 输出 n=6 的三角数字阵(JAVA基础回顾)
package itcast.feng; import java.util.Scanner; //需求:输出 n=6 的三角数字阵 //1 //2 3 //4 5 6 //7 8 9 10 //11 ...
- Lesson 5 No wrong numbers
Text Mr.James Scott has a garage in Silbury and now he has just bought another garage in Pinhurst. P ...
- Backbone源码分析(二)
在传统MVC框架模式中,Model承担业务逻辑的任务.Backbone作为一个mvc框架,主要的业务逻辑交由Model与Collection来实现.Model代表领域对象,今天主要学一下Model源码 ...
- Hadoop学习笔记—14.ZooKeeper环境搭建
从字面上来看,ZooKeeper表示动物园管理员,这是一个十分奇妙的名字,我们又想起了Hadoop生态系统中,许多项目的Logo都采用了动物,比如Hadoop采用了大象的形象,所以我们可以猜测ZooK ...
- java中文乱码解决之道(二)-----字符编码详解:基础知识 + ASCII + GB**
在上篇博文(java中文乱码解决之道(一)-----认识字符集)中,LZ简单介绍了主流的字符编码,对各种编码都是点到为止,以下LZ将详细阐述字符集.字符编码等基础知识和ASCII.GB的详情. 一.基 ...
- twobin博客样式—“蓝白之风”
自暑假以来,囫囵吞枣一般蒙头栽入前端自学中,且不说是否窥探其道,却不自觉中提高了对网页版面设计的要求,乃至挑剔.一个设计清爽美观的网页能让读者心旷神怡,甚至没有了阅读疲劳:而一个设计粗劣嘈杂的网页实在 ...
- 说说SQL Server 网络配置
打开Sql Server Configuration Manager,里面显示了SQL Server的网络配置,这些到底表示什么含义呢? 图一:MSSQLSERVER的协议 这些配置选项,其实就是为了 ...
- EF:split your EDMX file into multiple diagrams
我们可以把一个EDMX文件划分为多个类图: 1.在VS中打开EDMX设计器: 2.切换到“模型浏览器”属性设置窗口: 3.在diagrams上右键菜单中选择“添加新的关系图”: 4.在原来的关系图上可 ...
- [ASP.NET MVC] 利用自定义的AuthenticationFilter实现Basic认证
很多情况下目标Action方法都要求在一个安全上下文中被执行,这里所谓的安全上下文主要指的是当前请求者是一个经过授权的用户.授权的本质就是让用户在他许可的权限范围内做他能够做的事情,授权的前提是请求者 ...