如何确保通过另一个可执行文件打开一个可执行文件?

本文关键字:可执行文件 一个 何确保 确保 另一个 | 更新日期: 2023-09-27 18:08:38

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

假设我们的目录是这样的:

<>之前> opener.exe> actualProgram.exe> dependency.dll之前作为一个基本的例子,我们可以这样做:
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。尝试一下:你将能够删除/修改/替换依赖和"实际"的程序,当它通过"打开器"加载。显然,这有它的好处,即使更新更容易。

但是在你的"实际。exe"中,你怎么能确定它是通过另一个可执行文件加载的,并且知道它是在没有对.exe采取锁的情况下加载的?如果有人只是加载"实际。exe",即不通过"打开器",我想确保进程立即退出。

提示?

如何确保通过另一个可执行文件打开一个可执行文件?

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

注意:只要你所有的程序集都是手动加载的,或者在你修改/移动/删除它们之前由运行时加载,你的可能 ok。此外,在加载DLL后更改它将可能对正在运行的进程没有影响。我说可能在这两种情况下,因为它通常是一个好主意,让库单独在运行时,特别是如果你不手动加载它们。

参见:

  • 运行时动态链接@ MSDN
  • Win32进程如何获得其父进程的pid ?
  • 组装。Load Method (Byte[], Byte[])

如何在应用程序启动后发送自定义消息?启动的代码应该是这样的:

private void LaunchApplication()
{
  ProcessStartInfo start = new ProcessStartInfo();
  //you could pass in arguments here if you wanted
  start.Arguments = string.Empty;
  //your EXE name
  start.FileName = @"c:'your_program.exe";
  start.WindowStyle = ProcessWindowStyle.Normal;
  start.CreateNoWindow = true;
  Process p = Process.Start(start);
  while (0 == (int)p.MainWindowHandle)
  {
    System.Threading.Thread.Sleep(100);
  }
  processHandle = p.MainWindowHandle;
  label1.Text = processHandle.ToString();
  //the launched program will receive this message as a signal that it can continue
  SendNotifyMessage(processHandle, 99999, UIntPtr.Zero, IntPtr.Zero);
}

和您正在运行的应用程序将需要一个简短的自定义windows消息处理程序来监视"stay-alive"信号。

private bool allowedToLive = false;
//how long will we wait for the signal?  should arrive in < 1 second
private int TimeoutSeconds = 1;
private DateTime appStartTime = DateTime.Now;
protected override void WndProc(ref Message m)
{
  base.WndProc(ref m);
  //receiving the special message means we are allowed to live.
  if(!allowedToLive)
  {
    allowedToLive = (m.Msg == 99999);
    if (!allowedToLive && (TimeoutSeconds <= DateTime.Now.Subtract(appStartTime).Seconds))
    {
      //times up.  quit.
      Application.Exit();
    }
  }
}

如果您不想依赖于windows消息的定时,您可以更改您的目标程序以启动,但在它收到自定义消息之前不实际开始做任何事情。