C++二进制程序如何替换自己
How can a C++ binary replace itself?
我以前在更通用的设计上下文中问过这个问题。现在,我想谈谈具体情况。
想象一下,我正在运行app.exe
。它将update.exe
下载到同一文件夹中。app.exe
将如何在app.exe
的内容上复制update.exe
?我是在C++环境中特别提出这个问题的。我需要某种第三调解员应用程序吗?我需要担心文件锁定吗?二进制更新本身最稳健的方法是什么(除非讨厌的IT人员拥有极端的文件权限)?理想情况下,我希望看到可移植的解决方案(Linux+OSX),但Windows是主要目标。
- 将正在运行的
app.exe
移动/重命名为app_old.exe
- 将下载的
update.exe
移动/重命名为app.exe
- 下次启动应用程序时,将使用更新
在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文件被重新加载,但应用程序保持运行)。
像许多其他应用程序一样使用更新程序第三可执行文件。
- 下载新版本
- 安排更新程序以使用新版本替换应用程序
- 关闭主应用程序
- 更新程序运行并完成工作
- 更新程序运行你的应用程序的新版本
- 更新程序退出
- 模板参数替换失败,并且未完成隐式转换
- 没有为自己的结构调用列表推回方法
- 如何用转义符替换字符串中的所有特殊字符
- 我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
- 为什么除非添加括号,否则构造函数上的模板替换会失败?
- 在他自己的方法中,有可能将一个对象取消引用到另一个对象吗
- 在一个读写器队列中,我可以用volatile替换原子吗
- 用符号版本替换对函数的所有调用
- 在c++中为我自己的基于指针的数组分配内存的正确方法
- 如何通过替换顺序代码的while循环来添加OpenMP for循环
- 替换基于地图的所有引用
- 按平均值替换数组中的元素
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?
- 如何将字节数组元素替换为修改的十六进制 ASCII 符号?
- C++从对象自己的类中删除对象
- 如何编写自己的代码来替换`sTD :: min_element`以在向量中找到最小的值
- 正确地将 cv::Mat 替换为自己的投资回报率 (opencv)
- 将 std::async 替换为自己的版本,但 std::p romise 应该在哪里生活
- C++二进制程序如何替换自己
- 对象替换自己是否合法?