如何在C#中从内存启动程序? [英] How can I launch a program from memory in C#?

查看:112
本文介绍了如何在C#中从内存启动程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些UI应用程序驻留在用C#编写的用户任务栏中.该工具的EXE已在使用该工具的许多项目中签入我们的源代码控制系统,因此我们能够通过签入更新的EXE来更新其运行的版本.

I have some UI application that lives in the user's task bar that is written in C#. The EXE for the tool is checked in to our source control system on a number of projects that use it so we are able to update the version they run with by checking in updated EXE.

问题是,当用户获得exe的最新版本时,该程序通常正在运行,并且同步在其计算机上失败.我想对其进行修复,以使该程序在运行时不会锁定exe和任何相关的DLL,以便它们可以同步而不必关闭程序.

The problem is that when the users get the latest revision of the exe, the program is often running, and the sync fails on their machine. I want to fix it so the program doesn't lock the exe and any dependent DLL's when it runs so they can sync without having to shut down the program.

当前,我有一个程序,它将可执行文件作为参数,并将通过提前将程序集内容读入内存从内存中启动它.不幸的是,当涉及程序所需的DLL时,这完全失败了.

Currently, I have a program that takes an executable as a parameter and will launch it from memory by reading the assembly contents into memory ahead of time. Unfortunetly, this totally fails when it comes to the DLL's that the program requires.

我现在拥有的代码如下所示:

The code I have right now looks something like this:

public class ExecuteFromMemory
{
    public static void Main(string[] args)
    {
        //Figure out the name of the EXE to launch and the arguments to forward to it
        string fileName = args[0];
        string[] realArgs = new string[args.Length - 1];
        Array.Copy(args, 1, realArgs, 0, args.Length - 1);

        //Read the assembly from the disk
        byte[] binary = File.ReadAllBytes(fileName);

        //Execute the loaded assembly using reflection
        Assembly memoryAssembly = null;
        try
        {
            memoryAssembly = Assembly.Load(binary);
        }
        catch (Exception ex)
        {
            //Print error message and exit
        }

        MethodInfo method = memoryAssembly.EntryPoint;
        if (method != null && method.IsStatic)
        {
            try
            {
                method.Invoke(null, new object[] { realArgs });
            }
            catch(Exception ex)
            {
                //Print error message and exit
            }
        }
        else
        {
            //Print error message and exit
        }
    }
}

我的问题是,我在做些完全愚蠢的事情吗?有没有更好的方法来解决这个问题?如果没有,我该怎么做以支持处理外部依赖关系?

My question is, am I doing something totally stupid? Is there a better way to handle this? If not, what should I do to support handling external dependencies?

例如,如果您尝试运行使用'Bar.dll'中的功能的'Foo.exe',则上面的代码无法加载任何依赖文件,'Foo.exe'将被覆盖,但是'Bar.dll '仍处于锁定状态,无法覆盖.

For example, the above code fails to load any dependent files if you try to run 'Foo.exe' that uses functions from 'Bar.dll', the 'Foo.exe' will be overwriteable, but 'Bar.dll' is still locked and can't be overwritten.

我尝试从已加载的组件上的"GetReferencedAssemblies()"方法获取引用程序集的列表,但这似乎没有任何迹象表明应从何处加载程序集...我是否需要搜索他们自己?如果是这样,最好的方法是什么?

I tried getting the list of referenced assemblies from the 'GetReferencedAssemblies()' method on the loaded assmebly, but that doesn't seem to give any indication where the assemblies should be loaded from... Do I need to search for them myself? If so, what's the best way to do this?

似乎其他人以前可能也遇到过这种情况,而我不想重新发明轮子.

It seems like other people might have come across this before, and I don't want to re-invent the wheel.

- 更新: 签入EXE是因为这就是我们将内部工具分发给使用它们的团队的方式.对于此用例而言,它不是最佳选择,但我没有机会更改该策略.

- Update: The EXE is checked in because thats how we distribute our in-house tools to the teams that use them. Its not optimal for this use-case, but I don't have the opportunity to change that policy.

推荐答案

免责声明:尽管我熟悉Windows的锁定方式,但我并不使用Windows.

Disclaimer: I don't use Windows, though I am familiar with its strange way of locking things.

为了在运行时更新应用程序,您可能需要有两个过程:可执行文件本身,以及将完成更新过程的更新帮助程序"应用程序.假设您的应用程序是ProcessA.exe,更新助手是Updater.exe.您的主程序将下载可执行文件的新副本,并以随机名称保存.然后,您运行更新程序,该程序监视您当前进程的终止.当您的进程终止时,它将显示一个快速窗口,其中显示更新的状态,将新的可执行文件移到旧的可执行文件所在的位置,然后重新启动该程序.

In order to update your application while it is running, you'll likely need to have two processes: The executable itself, and an update "helper" application that will finish the update process. Let's say that your application is ProcessA.exe and your update helper is Updater.exe. Your main program will download a new copy of the executable, saving it with a random name. Then you run your updater program, which watches for the termination of your current process. When your process terminates, it displays a quick window showing the status of the update, moving the new executable into the place of the old one, and then restarting that program.

能够模拟POSIX文件系统语义并能够删除当前正在运行的进程磁盘映像并将其替换为新文件会更加优雅,但是我不知道在Windows上是否还可以.在POSIX系统上,您可以删除一个正在使用的文件,直到关闭所有剩余的文件句柄后,它才真正被删除,尽管您随后可以重新使用文件名.

It'd be more elegant to be able to emulate POSIX filesystem semantics and be able to delete the currently-running process disk image and replace it with a new file, but I don't know if that is even possible on Windows. On a POSIX system, you can delete an in-use file and it won't actually be deleted until any remaining file handles are closed, though you can then reuse the filename.

您可能想要查看写在 CodeProject 上的文章,其中后续文章.

You might want to check out an article written at CodeProject that talks about this. It also has a follow-up article.

祝你好运!

这篇关于如何在C#中从内存启动程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆