如何确保通过另一个可执行文件打开一个可执行文件?
本文关键字:可执行文件 一个 何确保 确保 另一个 | 更新日期: 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",即不通过"打开器",我想确保进程立即退出。
提示?
- 向
actualProgram.exe
传递一个命令行参数,让它知道它是由启动器启动的。(oleksii在OP的评论中也建议) - 在启动器中设置一个可以被子进程继承的环境变量
- 使用记录的方法之一来获取父进程id,并使用它来获取有关启动进程的信息。(当然,如果父进程终止,Windows可以自由地将PID重新分配给新进程。)
- 创建一个内存映射文件/命名管道等。在启动器中可以用来传递信息给子进程。 手动加载和卸载子库中的库引用。如果它们是。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消息的定时,您可以更改您的目标程序以启动,但在它收到自定义消息之前不实际开始做任何事情。