本文介绍的是程序内嵌,如果需要实现窗体内嵌(捕捉程序外部窗体到自己控件上显示),可参考本人发表的文章:https://blog.csdn.net/lzl_li/article/details/117120335
本文介绍如何在程序中内嵌其它exe程序文件并调取运行,修正了网上写的代码。
(主要修正了资源文件的读取、EXE文件中Main(string [])函数参数传递代码)
1.先建立一个测试项目test,编译输出test.exe
2.再建立一个加壳项目AppPacker
3.在项目AppPacker中找到 “properties\resources.resx”,双击Resources.resx打开,在里面添加test.exe文件为本项目的资源:
4.打开Program.cs文件,主函数Main中添加如下代码:
static void Main(string []args)
{
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());//因调用的是带窗体程序,如果此处调用窗体将导致方法1报错。
string[] str;
if (args != null && args.Length > 0)
str = args;
else
str = new string[] { "没有获得参数,程序中定义的字符串。" };
byte[] fileBytes = Properties.Resources.test;//资源中获取数据(“test”是作为文件资源提前加入到了本工程的资源文件“properties\resources.resx”)
/*上面的方法获取资源文件简单有效,下面是网上使用的方法,过于复杂而且容易出错,本人测试不通过,不知道哪里的问题
String projectName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name.ToString();
System.IO.Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(projectName + ".test.exe");
byte[] fileBytes = new byte[stream.Length];
stream.Read(fileBytes, 0, (int)stream.Length);
*/
//【方法1】进程内部调用代码执行:同一进程只能打开一个主窗体,否则会报错。【如果本进程已经开了主窗体,调用的代码中也有主窗体会报错】
System.Reflection.Assembly asm = System.Reflection.Assembly.Load(fileBytes);//对加载的APP有要求,C#类型程序一般可以(.NET平台编译的托管代码应该也可以),其它编译的程序测试了很多都不可以
System.Reflection.MethodInfo info = asm.EntryPoint;
System.Reflection.ParameterInfo[] parameters = info.GetParameters();
if ((parameters != null) && (parameters.Length > 0))
//info.Invoke(null,(object[])str); //网上错误的参数传递(错误在于参数列表变成一个个字符串,而非main函数要求的字符串数组),下面是修正后的调用
info.Invoke(null, new object[] { str });//参数1是方法的对象,因为主主函数为静态函数没有对象所以为null;参数2是方法的参数对象列表,主函数一般是只有1个string[]参数对象
else
info.Invoke(null, null);
//【方法2】进程外部启动新进程(将资源文件存储到磁盘并启动新进程),不受编译平台限制,所有类型APP文件都可以
string fileName = System.IO.Path.GetTempPath();
if (fileName.EndsWith("\\"))
fileName = fileName + "test.exe";
else
fileName = fileName + "\\test.exe";
System.IO.BinaryWriter bw = new System.IO.BinaryWriter(new System.IO.FileStream(fileName, System.IO.FileMode.Create));
bw.Write(fileBytes);
bw.Flush();
bw.Dispose();
System.Diagnostics.Process myPro = System.Diagnostics.Process.Start(fileName, str[0]);
//上面2种方式,都可以在资源文件数据进行加密操作,先将文件加密再加入资源当中,读取时再进行解密,然后执行后续操作。
}
本文中的代码参考了以下文章,并对其中的2个关键点进行了修正:
https://www.cnblogs.com/huangcong/archive/2010/03/23/1693293.html
https://www.cnblogs.com/xlw1219/archive/2012/11/29/2795069.html