2

我正在创建一个自我更新的应用程序,其中大部分代码都在一个单独的 DLL 中。它是命令行,最终将在 Mono 上运行。我只是想让这段代码在命令行的 Windows 上的 C# 中工作。

如何创建 ac# 应用程序,以便在运行时删除支持的 dll?

AppDomain domain = AppDomain.CreateDomain("MyDomain");
ObjectHandle instance = domain.CreateInstance( "VersionUpdater.Core", "VersionUpdater.Core.VersionInfo");
object unwrap = instance.Unwrap();
Console.WriteLine(((ICommand)unwrap).Run());
AppDomain.Unload(domain);
Console.ReadLine();

在 ReadLine,VersionUpdater.Core.dll 仍被锁定,无法删除

ICommand 接口位于 VersionUpdater.Common.dll 中,命令行应用程序和 VersionUpdater.Core.dll 都引用了该接口

4

4 回答 4

6

我曾经管理过类似事情的唯一方法是将 DLL 放在一个单独的 AppDomain 中,以尝试删除它。我卸载了另一个 AppDomain,然后从磁盘中删除了 DLL。

如果您正在寻找一种执行更新的方法,那么我会想到一个生成真正 AppDomain 的存根 exe。然后,当该存根 exe 检测到要应用更新时,它会退出另一个 AppDomain,然后执行更新魔法。

编辑:更新程序不能与它正在更新的东西共享 DLL,否则它将锁定这些 DLL,从而防止它们被删除。我怀疑这就是为什么您仍然会遇到异常的原因。更新程序必须是独立的,并且不依赖于其他 AppDomain 使用的任何内容,反之亦然。

于 2008-10-07T17:15:33.120 回答
1

Unwrap 会将对象类型的程序集加载到调用它的 appdomain 中。解决此问题的一种方法是在您的“基础”程序集中创建一个调用 command.run 的类型,然后将其加载到您的新 appdomain 中。这样,您就不必从不同程序集中的类型调用对象的 unwrap,并且可以删除磁盘上的程序集。

于 2008-10-07T17:28:07.710 回答
1

当我构建一个自我更新的应用程序时,我使用了存根的想法,但存根就是应用程序本身。

该应用程序将启动,寻找更新。如果它找到更新,它会将新应用程序的副本下载到临时存储,然后使用显示“您正在更新”的命令行选项启动它 (System.Diagnostics.Process.Start())。然后原始的exe退出。

生成的 exe 启动,看到它是一个更新,并将自身复制到原始应用程序目录。然后它从该新位置启动应用程序。然后生成的 exe 结束。

从原始应用程序安装位置新启动的 exe 启动 - 看到临时文件并将其删除。然后恢复正常执行。

于 2009-03-08T03:42:30.373 回答
1

您始终可以MOVEFILE_DELAY_UNTIL_REBOOT在重新启动时使用删除。这很可能是做这类事情的最简单的方式,通过 hackey 我通常会看到类似的东西;加载新的 DLL 或注入 explorer.exe 甚至修补系统 dll 以加载到另一个进程等...

来自 MSDN的 MoveFileEx

lpNewFileName [in, optional ] 本地计算机上文件或目录的新名称。

移动文件时,目标可以位于不同的文件系统或卷上。如果目标在另一个驱动器上,则必须 MOVEFILE_COPY_ALLOWED在 dwFlags 中设置标志。

移动目录时,目标必须位于同一驱动器上。

如果 dwFlags 指定 MOVEFILE_DELAY_UNTIL_REBOOT并且 lpNewFileName 为NULL,则MoveFileEx 注册 lpExistingFileName 文件以在系统重新启动时删除。如果 lpExistingFileName 引用一个目录,则系统仅在目录为空时才会在重新启动时删除该目录。

于 2009-05-29T06:48:41.040 回答