C++二进制程序如何替换自己

How can a C++ binary replace itself?

本文关键字:替换 自己 何替换 二进制 程序 C++      更新时间:2023-10-16

我以前在更通用的设计上下文中问过这个问题。现在,我想谈谈具体情况。

想象一下,我正在运行app.exe。它将update.exe下载到同一文件夹中。app.exe将如何在app.exe的内容上复制update.exe?我是在C++环境中特别提出这个问题的。我需要某种第三调解员应用程序吗?我需要担心文件锁定吗?二进制更新本身最稳健的方法是什么(除非讨厌的IT人员拥有极端的文件权限)?理想情况下,我希望看到可移植的解决方案(Linux+OSX),但Windows是主要目标。

  1. 将正在运行的app.exe移动/重命名为app_old.exe
  2. 将下载的update.exe移动/重命名为app.exe
  3. 下次启动应用程序时,将使用更新

在windows下,重命名正在运行的即锁定的dll/exe不是问题。

在Linux上,可以删除正在运行的程序的可执行文件,因此:

  • 下载app.exe~
  • 删除正在运行的app.exe
  • app.exe~重命名为app.exe

在Windows上,不可能删除正在运行的程序的可执行文件,但可以重命名它:

  • 下载app.exe~
  • 将运行中的app.exe重命名为app.exe.old
  • app.exe~重命名为app.exe
  • 重新启动时删除app.exe.old

这是一个操作系统功能,而不是C++功能
你使用的是什么操作系统?

在Windows中,请参阅MoveFileEx()函数,在linux上,只需覆盖正在运行的应用程序(替换linux中正在运行的可执行文件)

在Windows上,至少有一个运行的应用程序正在锁定自己的.exe文件和所有静态链接的.dll文件。这可以防止应用程序直接更新自己,如果它希望防止重新启动,则会导致更新(如果重新启动可以,则应用程序可以将MOVEFILE_DELAY_UNTIL_REBOOT标志传递给MoveFileEx,并且可以自由地"覆盖"它自己的.exe,因为无论如何都会延迟)。这就是为什么应用程序通常不在自己的.exe上检查更新,而是启动一个检查更新的填充程序,然后启动"真正的"应用程序。事实上,"填充程序"甚至可以由操作系统本身通过正确配置的清单文件来完成。Visual Studio构建的应用程序将其作为一个预制向导打包工具,请参阅Visual C++应用程序的ClickOnce部署。

典型的Linux应用程序不会自我更新,因为操作系统有很多很多种风格。大多数应用程序都是作为源程序分发的,通过某些版本的auto-hell运行以自我配置和构建自己,然后通过make install安装自己(所有这些都可以在包后面自动进行)。即使是作为特定Linux版本的二进制文件分发的应用程序也不会复制自己,而是并排安装新版本,然后更新symbolic link以"激活"新版本(同样,包管理软件可能会隐藏这一点)。

如果OSX应用程序是Posix风格的,那么它们要么属于Linux,要么现在属于为您处理更新的MacAppStore应用程序。

我希望有一天,滚动自己的自我更新永远不会达到这两种技术(ClickOnce、RPM、AppStore)的复杂程度,并为用户提供与发现、升级和卸载相关的预期行为。我会顺应潮流,在它们各自的平台上使用这些技术。

这只是克服"重启"问题的一个想法。制作一个不需要更新的程序怎么样。只需在插件结构中实现它,所以它只是一个更新主机,它本身加载一个带有程序所需所有功能的.dll文件,并在那里调用主函数。当它检测到一个更新(可能在一个单独的线程中)时,它会告诉dll句柄关闭,替换文件并加载新的文件。这样,您的应用程序在更新自身时保持运行(只有dll文件被重新加载,但应用程序保持运行)。

像许多其他应用程序一样使用更新程序第三可执行文件。

  • 下载新版本
  • 安排更新程序以使用新版本替换应用程序
  • 关闭主应用程序
  • 更新程序运行并完成工作
  • 更新程序运行你的应用程序的新版本
  • 更新程序退出