|
楼主 |
发表于 2018-6-18 13:48:18
|
显示全部楼层
本帖最后由 cnxh 于 2018-6-18 13:52 编辑
谁能改一下下面说的那个Runner类,public void Run(string assemblyPath)这个函数,复制过来有错误
在Windows上从内存中启动.net程序(C#程序从内存中启动)
2018年02月27日 22:58:42
阅读数:244
通常,我们的程序是保存在计算机的硬盘上的,程序的启动是通过操作系统将硬盘上的文件加载到内存中并进行执行的。然而,操作系统打开磁盘上的可执行文件后,该可执行文件就会处于被打开状态。这样会产生一个问题:你无法对这个可执行文件进行修改和删除等操作。另外,C#程序本身具有一定的开源性,因为当你拿到.net的exe或dll文件后,可以很轻松的通过一些软件对其反编译,得到源代码。而且反编译得到的源代码与编写该程序的源代码几乎一模一样(这是题外话)。如果我们启动了程序后不会锁定磁盘上的文件又该如何操作呢?
基本思路:1.先将可执行文件读取放在正在执行的程序中的一个数据块中,比如读入一个字节型数组中。
2.再将这个数组的数据当成程序来执行。
针对Windows上的.net程序类型分别有不同的解决方案。
注意:被启动的程序需要的dll(无论是C#编写的还是C++编写的),存放的位置应该相对第一个程序的位置放置。
控制台和Winform程序
首先我们在需要启动程序的地方执行以下代码。
var bin = File.ReadAllBytes(@"被启动程序的绝对路径")
Assembly asm = Assembly.Load(bin);
method = asm.EntryPoint;
System.Threading.Thread thd;
System.Threading.ThreadStart ts;
ts = new System.Threading.ThreadStart(RunNewApp);
thd = new System.Threading.Thread(ts);
thd.Start();
其中method是一个私有字段,其定义为
private MethodInfo method;
其中RunNewApp方法的定义为
private void RunNewApp()
{
if (method != null)
method.Invoke(null, null);
}
应用举例:
1.在一个Winform中启动另一个Winform程序。比如我们在第一个winform程序中添加一个按钮,按钮的事件就是上面的代码。
2.在一个控制台中启动另一个控制台程序。
WPF程序
如果使用上面的代码用一个WPF程序启动从内存中启动另一个WPF程序,是会出错的,我们可以采用如下方法。
这里提供了一个Runner类,其代码如下:
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
namespace 你的程序的名称空间
{
public class Runner : MarshalByRefObject
{
public static AppDomain RunInOtherDomain(string assemblyPath)
{
var ownType = typeof(Runner);
string ownAssemblyName = ownType.Assembly.FullName;
var childDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString());
childDomain.Load(ownAssemblyName);
var runner = (Runner)childDomain.CreateInstanceAndUnwrap(ownAssemblyName, ownType.FullName);
runner.Run(assemblyPath);
return childDomain;
}
public void Run(string assemblyPath)
{
var otherAssemblyBytes = File.ReadAllBytes(assemblyPath);
var assembly = AppDomain.CurrentDomain.Load(otherAssemblyBytes);
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
throw new NotImplementedException("Probably need to do some work here if you depend on other assemblies.");
};
Application.ResourceAssembly = assembly;
var app = assembly.GetExportedTypes().Single(t => typeof(Application).IsAssignableFrom(t));
MethodInfo main = app.GetMethod("Main", BindingFlags.Static | BindingFlags.Public);
main.Invoke(null, null);
}
}
}
当你需要启动你的第二个程序时,只需要使用如下代码:
Runner.RunInOtherDomain(@"被启动程序的绝对路径");
总结
这样做有一些好处:开发人员没有必要去把真正需要执行可执行文件保存在硬盘上,可以将其保存在服务器上(或者加密后保存程序),让硬盘上的一个小程序来下载(解密)真正的可执行文件,放在内存中,并进行执行;当需要更新(修复)程序时,就可以在不关闭源程序的基础上进行程序更新;保护自己的程序不受源码级泄露的威胁。
当然,这样做也可能会带来一些安全隐患,对于用户而言:下载的程序的安全性是无法考量的,因为用户是在不知情的情况下直接下载并执行了未知程序。
|
|