写点什么

InnoSetup 制作补丁包替换文件操作

  • 2022 年 9 月 10 日
    河北
  • 本文字数:2792 字

    阅读完需:约 9 分钟

InnoSetup制作补丁包替换文件操作

在程序即将给用户的时候,通常都会制作一个 exe 的安装包,因为我们面对的客户不知道计算机操作能力如何,最好的方式就是“下一步”、“下一步”....“安装完成”!


在这里讲述一下如何用 InnoSetup 制作一个简单的补丁包。


当前补丁包的功能是:替换安装程序的资源文件,也就是文件夹的替换。


这个操作要是让用户操作起来,可真是难喽,用户只是一顿点击操作,完全不知道运行程序中有什么,所以,在制作补丁包的时候也要做成简单易操作。


接下来讲解下是如何实现的吧!

功能实现

开发环境:win32 控制台应用程序

脚本工具:InnoSetup

那么,该如何实现这个补丁包操作呢?

使用过 InnoSetup 脚本的都知道,可以使用下一步,下一步的方式一建生成简单的打包程序,这里就不讲解是如何配置基本属性了。


想要用脚本实现文件替换的功能,说实话,对于我这个不常用脚本的人来说,还是有一点困难的。索性就使用控制台程序,在 Innosetup 中运行 win32 控制台程序,使用 C++指令完成替换操作。

[Run]Filename: "{app}\server_packWin32.exe";Description: "运行应用程序"
复制代码

以上是 InnoSetup 中的核心调用部分,调用名字叫做:server_packWin32 的程序就可以实现文件替换啦!

win32 程序实现文件替换功能

涉及到的主要功能

1:注册表读取功能

2:读取文件夹内容并覆盖

操作流程

第一步:获取注册表中安装的应用程序的路径

第二步:筛选出旧文件夹路径

第三步:文件替换

根据操作流程就可以实现简单的文件替换功能了。

获取注册表中应用程序路径

1:打开注册表

对于我们 C++来说,获取注册表路径下 key 值信息应该是小菜一碟了吧!

使用RegOpenKeyEx打开指定的键值。该函数一共有五个参数。

参数一:指向以空结尾的字符串指针,一般就是填入我们在注册表中的键值

需要注意的是:如果参数设置成 nullptr 或者是一个指向空字符串的指针时,此时函数将打开一个新的句柄,在这种情况下,函数不会关闭之前打开的句柄的,这里需要大家进行注意哦~

参数二:传入注册表中需要查找的路径。

参数三:默认设置成 0。

参数四:一般在读注册表的时候,设置成 KEY_READ 。这个参数是一个访问掩码,指定对密钥的期望访问权限。

参数五:指向变量的指针,该指针接收打开的键的句柄

注意:只有当键值打开成功之后,才可以做后续操作

HKEY hOpen;//访问注册表,hKEY则保存此函数所打开的键的句柄if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_READ, &hOpen)){   //注册表打开成功,做有效处理}
复制代码

2:读取注册表数据

在读取注册表数据时,一般采用RegQueryValueEx函数进行操作。根据成打开的句柄,查找对应 key 值下的 value 数据

也就是图上红线标注的位置数据。

参数一:是打开注册表键值的句柄,默认传入 hOpen。

参数二:需要查询的 key 值

参数三:默认传入 nullptr

参数四:默认传入 nuppltr

参数五:返回的查询到的数据

参数六:目前没有实际应用,可以不做考虑

TCHAR tcPath[MAX_PATH] = {0};DWORD chData ;printf("Path information is being read...\n");if(RegQueryValueEx(hOpen, key, nullptr, nullptr, (BYTE*)tcPath, &chData) == ERROR_SUCCESS){    //获取到了有效的数据值,记录并返回    std::string spath = Tchar2String(tcPath);    RegCloseKey(hOpen);    return spath;}
复制代码

注意:无论是否查询到有效内容,最后都必须要关闭指定的注册表项的句柄。

在这使用了一个转换函数,有 TCHAR 类型转成了 string 类型。在这里我也贴出来了,如果有需要的,可以拿去了。

std::string Tchar2String(TCHAR* tchar){	int iLen = WideCharToMultiByte(CP_ACP, 0, tchar, -1, NULL, 0, NULL, NULL);	char* chRtn = new char[iLen*sizeof(char)];	WideCharToMultiByte(CP_ACP, 0, tchar, -1, chRtn, iLen, NULL, NULL);	std::string str(chRtn);	delete chRtn;	return str;}
复制代码

筛选出旧文件夹路径

应用程序的整体路径已经拿出来了,对于那些资源文件路径的截取也就简单了。

在这里,就需要根据你需要替换的那些文件对 exe 应用程序来说是哪些层级就可以筛选到了。

文件替换

在文件替换的功能中,首先需要查询新文件夹中存在的所有子文件,并替换成旧文件。

这也是整个替换文件中的重点。

因为程序不知道传入的文件是属于子文件还是嵌套文件,所以,在查询过程中,采用了递归方式,逐层级查询。

查询到匹配文件后,复制替换

第一步

判断传入的需要替换的新文件路径是否存在?

if (_access(spath.c_str(), 0) == -1){	//当前文件夹路径不存在	return;}
复制代码

文件不存在时直接不进行后续处理。在使用_access 函数时,记得要添加头文件#include <io.h>

第二步

获取路径下对应的文件句柄是否有效

在这里需要注意:并不是文件夹存在就代表了文件句柄是有效的。

intptr_t hFile = 0;std::string p, starget;hFile = _findfirst(p.assign(spath).append("\\*").c_str(), &fileinfo);if(!hFile){    return;}
复制代码

第三步

循环遍历查找有效数据

使用 do{}while();的方式根据文件句柄,查找数据是否成功,成功返回 0,失败返回-1

以下格式判断:

do{    //有效数据处理}while(_findnext(hFile, &fileinfo) == 0);
复制代码

第四步

文件判断

如果该文件有子文件夹存在,递归该路径,并查找该子文件夹下的子文件内容,直到没有子文件夹为止。

如果该文件下没有子文件夹直接进行复制替换

if ((fileinfo.attrib & _A_SUBDIR)){    if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)    {		        CopyFolder(p.assign(spath).append("\\").append(fileinfo.name), starget.assign(sTargetpath).append("\\").append(fileinfo.name), enumFlag);    }}else{    std::string  sinfo = p.assign(spath).append("\\").append(fileinfo.name);    std::string sNewTargetPath = starget.assign(sTargetpath).append("\\").append(fileinfo.name);    //文件复制    std::string sLog = "path = ";    sLog += fileinfo.name;    BOOL bSuccess = ::CopyFileA(sinfo.c_str(), sNewTargetPath.c_str(), false);     if (bSuccess == TRUE)    {	sLog += "cpoy successful!\n";	    }    else    {	//复制失败时,判断目标路径是否存在?不存在说明没有安装,存在说明被占用	LoadFilesFailedTips(sNewTargetPath, enumFlag);	sLog += "cpoy failed!\n";    }    printf(sLog.c_str());}
复制代码

这是我们查询的核心部分,也是最最容易出错的地方。

大部分新手都不是很会用递归函数,但是只要你用了就会一直爱上它,真的是太太方便了。

在上述代码中还涉及到了一个重点,就是文件复制。采用了:CopyFileA 函数。

这些函数都是可以在 win32 程序中直接运行的。

总结

根据上述介绍,就可以应用 win32 控制台程序实现文件替换的功能了,将程序编译成 exe 后,直接使用 InnoSetup 脚本程序运行。

用户使用起来非常方便,仅仅需要下一步等几项点击操作就可以实现更新资源的功能啦~


我是中国好公民 st,一名 C++程序媛~

发布于: 刚刚阅读数: 3
用户头像

书山有路勤为径,学海无涯苦作舟 2022.07.01 加入

擅长语言:C++ 涉及语言:Python

评论

发布
暂无评论
InnoSetup制作补丁包替换文件操作_9月月更_中国好公民st_InfoQ写作社区