程序如何在运行期间自我更新?这可能听起来像是一个复杂的任务,但实际上,windows 操作系统提供了一种方法,使得应用程序在运行时可以修改自己的名称,甚至移动到另一个文件夹中。利用这一特性,我们可以轻松实现程序的 ota(over-the-air)自动更新。
本文将通过示例程序展示如何在运行期间改名,并解释其背后的原理。
首先,让我们编写一个简单的程序,并尝试在运行时手动改名。
运行此程序后,你会发现无法删除它。
然而,你可以轻松地在资源管理器中对它进行改名,甚至将它从一个文件夹移动到另一个文件夹中。
需要注意的是,你不能跨驱动器移动此文件。
不仅是 exe 文件,dll 文件也可以在运行期间改名。实际上,在 exe 程序运行期间,即便使用了某些 dll 文件,这些 dll 文件也是可以改名的。
当然,exe 的运行不一定在启动期间就加载了所有 dll。如果在 exe 启动后但某个 dll 加载前改了 dll 的名称,可能会导致程序无法找到 dll,从而崩溃。
那么,为什么 windows 上的可执行程序可以在运行期间改名呢?这是因为 Windows 的文件系统由两个主要结构组成:一个是目录信息,保存文件的元数据(如文件名、大小、属性和时间戳);另一个是文件的数据链。
当运行程序加载一个程序集时,会为此程序集创建一个内存映射文件。为了优化性能,通常只有实际用到的部分才会被加入到内存映射文件中。当需要使用程序集文件中的某块数据时,Windows 操作系统会将需要的部分加载到内存中。但是,内存映射文件只会锁定文件的数据部分,以保证文件的数据不会被其他进程修改。
这里的关键是,内存映射文件只会锁定文件的数据部分,而不会锁住文件的元数据信息。这意味着你可以随意修改这些元数据信息,而不会影响程序的正常运行。这就包括你可以修改文件名,或者将程序从一个文件夹移动到另一个文件夹。
然而,跨驱动器移动文件会影响到文件的数据部分,所以此操作是不被允许的。
接下来,让我们编写一个程序,展示如何在运行期间自动改名。一般来说,需要 OTA 更新的程序是客户端程序,因此以下代码使用 .NET Core 3.0 编写了一个自我改名的 wpf 程序。
using System.Diagnostics; using System.IO; using System.Windows; <p>namespace Walterlv.Windows.Updater { public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); var fileName = Process.GetCurrentProcess().MainModule.FileName; var newFileName = Path.Combine(Path.GetDirectoryName(fileName), "OldUpdater.exe"); File.Move(fileName, newFileName); // 省略的代码:将新下载的程序改名成 fileName。 } } }
这样,程序在运行后会自动改名。
顺便提一下,以上代码仅适用于 .NET Framework 的桌面应用程序或 .NET Core 3.0 的桌面应用程序。如果是 .NET Core 2.x,则在获取进程名称时可能会是 dotnet.exe(已发布的 .NET Core 程序除外)。
参考资料:
- c# – Why does rename a loaded .net assembly work? – Stack Overflow
- windows 7 – Why can I rename a running executable, but not delete it? – Super User
- deployment – How can we overwrite EXE files while users are running them? – Stack Overflow
本文会经常更新,请阅读原文:https://www.php.cn/link/1745680a5a547dc1fb4b69f85054c299,以避免陈旧错误知识的误导,同时有更好的阅读体验。