在程序即将给用户的时候,通常都会制作一个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脚本程序运行。

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

我是糯诺诺米团,一名C++开发程序媛~

InnoSetup制作补丁包替换文件操作相关推荐

  1. ubuntu系统使用quilt制作补丁包

    简介 本文采用quilt命令制作deb包的补丁具体操作如下 解压源码包 首先应从相关源地址下载所需打补丁的源码包 [root@localhost /]# ls initramfs-tools_0.13 ...

  2. u852日期限制解决补丁_用友U8hotfix和补丁包替换原则及注意事项

    摘要: 本文提供在用友U8V8.52erp软件平台管理的系统管理模块中打了8月20日的补丁,并打了8-20日的U852HOTFIX,进去企业门户后,点击存货核算节点,U8就退出了,不知何因? 另外想问 ...

  3. 不解压war包替换文件

    打成war包,不压缩 jar -cvfM0 nerdaye.war nerdaye 解压war包到当前目录 jar -xvf nerdaye.war PACKAGEPATH=/apps/update/ ...

  4. ubuntu系统使用quilt命令自定义配置制作补丁包解析

    简介 patch的制作需要借quilt工具完成补丁,quilt 命令提供了记录修改的一个基本方式.对 Debian 打包来说,该工具需要进行自定义,从而在 debian/patches/ 目录内记录修 ...

  5. linux bash 的文件查找替换 文件操作

    文章目录 1. sed命令 1.1 简介 1.1.1 删除:d命令 1.1.1 替换:s命令 2. 典型用法 2.1 sed 查找某行,关键字,并且替换一行 2.2 sed 查找某行,关键字,并且替换 ...

  6. Linux下补丁包(.patch文件)制作及使用[u-boot示例]

    需求 移植 u-boot 时需要修改通用的 u-boot 源码,为了避免每次都去重复修改,直接使用 patch 包的形式. 制作补丁包 # 1.完成功能调试之后,在当前目录下执行 make distc ...

  7. 自学Python第九天- 模块、包、编码、文件操作、OS 模块、打包

    自学Python第九天- 模块.包.编码.文件操作.OS 模块.打包 模块 导入模块 程序入口 包 编码 文件操作 打开或创建文件 常用的文件打开模式 边读边写 文件对象的常用方法 读写 CSV Ex ...

  8. Java 文件操作 逐行替换文件内容,加快翻译效率

    昨天想看部奥斯卡老片,结果发现居然没有中文版. 为了更方便理解电影内容,下载了罗马尼亚语srt字幕. 但是,碍于水平有限,只能用谷歌翻译快速翻译完.在压制视频时,却发现时间戳由于谷歌翻译的影响.变得不 ...

  9. 【Go语言】集合与文件操作

    本文目录 1.数据集合的主要操作 1_1.字典的声明 1_2.字典的初始化和创建 1_3.字典的访问和操作 1_4.其他类型的数据集 2.文件操作 2_1.文件操作概述os包和path包 2_2.文件 ...

最新文章

  1. Python 之 pip拒绝访问
  2. 现任明教教主共享胖AP与WLC安全配置录像.上半部分
  3. 【Fibonacci-PEG,LDPC】基于Fibonacci-PEG算法的LDPC码校验矩阵的构造
  4. linux系列服务总结之四:SAMBA共享设置完整介绍
  5. oracle数据库安装自动化,自动化Oracle数据库静默安装
  6. LeetCode677. 键值映射(Trie树)
  7. Java前端技术学习
  8. rabbitmq实现秒杀中订单流量削峰
  9. js 访问android 路径,Android与JS进行交互传文件路径
  10. 基于XMPP协议的Android即时通信系
  11. 服务端端口状态和客户端端口状态解释-LISTENING-ESTABLISHED-TIME_WAIT
  12. 【三维路径规划】基于matlab狼群算法无人机三维路径规划【含Matlab源码 167期】
  13. 通过图标来识别网站用户指纹
  14. 【黄啊码】微信小程序+php实现即时通讯聊天功能
  15. 阿里云服务器安装MySql8.0.26
  16. 短线起爆点(移动均线15种战法)
  17. Git报错:Git failed with a fatal error. Git failed with a fatal error. Need to specify how to reconcile
  18. linux系统无线网卡驱动安装,在linux上怎么安装无线网卡驱动?
  19. Linux下一种 ELF 文件的代码签名验证机制
  20. 《登黄山偶感》艺术品赏

热门文章

  1. 一文教你学会使用 th:block
  2. Java解决上台阶问题
  3. 十、PyQtgraph使用QtDesigner提升3D图形界面
  4. 使用MathType为公式自动编号
  5. 【矩阵论】5. 线性空间与线性变换——生成子空间
  6. 怎么一键拼图?快速拼图这样做
  7. Unity License 出错
  8. mbedtls 库基础及其应用
  9. 【C++学习笔记2】构造函数、析构函数、函数多态、抽象类、函数模板
  10. 互联网公司的中台实践:网易杭研的中台往事