有一个巧妙的小技巧,您可以使用它永远不要让操作系统锁定.dll的/.exe,而.exe需要运行。

假设我们的目录如下所示:

>opener.exe
>actualProgram.exe
>dependency.dll

As a basic example, we could do this:

namespace Opener
{
    class Program
    {
        static void Main(string[] args)
        {

            AppDomain domain = AppDomain.CurrentDomain;
            AppDomain newDomain = AppDomain.CreateDomain(
                domain.FriendlyName,
                domain.Evidence,
                domain.BaseDirectory,
                domain.RelativeSearchPath,
                true,  // "shadow copy" files: copy rather than lock
                domain.SetupInformation.AppDomainInitializer,
                domain.SetupInformation.AppDomainInitializerArguments
            );
            string assembly =
                System.Reflection.Assembly.GetExecutingAssembly().Location
                + "\\..\\actualProgram.exe";
            newDomain.ExecuteAssembly(assembly, args);
        }
    }
}

我们还可以在其中添加更多逻辑,尽管已打开该流程的实例,但仍可以使用它来实际替换/更新actualProgram.exe。尝试一下:通过“打开器”加载时,您将能够删除/修改/替换依赖项和“实际”程序。显然,这样做有其好处,即使更新变得容易得多。

但是,在您的“actual.exe”中,如何确定它是通过另一个可执行文件加载的,又知道它是在不锁定.exe的情况下加载的?如果有人只是要加载“actual.exe”,即不通过“opener”加载,我要确保该过程立即退出。

提示?

最佳答案

  • 将命令行参数传递给actualProgram.exe,让它知道它是由启动器启动的。 (也由oleksii在OP的评论中建议)
  • 在启动程序中设置一个可由子进程继承的环境变量。
  • 使用已记录的方法之一来获取父进程ID,并使用它来获取有关启动进程的信息。 (当然,如果父进程终止,Windows可以自由地将PID重新分配给新进程。)
  • 创建一个内存映射文件/命名管道/etc。在启动器中,可用于将信息传递给 child 。
  • 手动加载和卸载子代中的库引用。如果它们是.Net程序集,则可以使用AssemblyResolve事件,将文件从磁盘加载到字节数组中,并使用Assembly.Load(byte[], byte[])重载。

  • 注意:只要在修改/移动/删除它们之前,手动或在运行时加载所有程序集,就可以了。另外,在加载DLL之后更改DLL可能对正在运行的进程没有影响。我可能在两种情况下都说过,因为通常在运行时不使用这些库是一个好主意,尤其是在您不手动加载它们的情况下。

    也可以看看:
  • Run-Time Dynamic Linking @ MSDN
  • How can a Win32 process get the pid of its parent?
  • Assembly.Load Method (Byte[], Byte[])
  • 关于c# - 如何确保通过另一个可执行文件打开一个可执行文件?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32096544/

    10-11 22:57
    查看更多