zoukankan      html  css  js  c++  java
  • C# 动态创建EXE

     动态创建EXE功能目的:

    比如我们写了设计软件,可以界面设计一些东西。现在我们需要将我们设计好的东西保存成一个exe,用户打开就直接可以看到设计好的东西。也就是需要把数据保存到exe里面。

    这个时候呢,我们可以动态生成一个新的程序,这个程序调用我们原先的设计软件,区别是,我们运行这个软件的时候,可以把原先设计好的数据全部写死写入到新的软件里面,

    然后参数传入到设计软件。这样就可以实现双击运行软件,打开就是原先设计好的数据了。

     废话讲完了,也不知道有没有讲清楚、、、、

    1.创建项目SaveExe或者修改代码中SaveExe名字为自己的项目

    2.添加按钮调用CreateCodeEXE,即可实现编译生成一个新的exe即 复制了自身的exe生成一个新的exe(目的就是新生的exe,我们可以增加预设参数属性之类)。

    public static void CreateCodeEXE()
            {
                CSharpCodeProvider provider = new CSharpCodeProvider();
                CompilerParameters parameters = new CompilerParameters();
                parameters.GenerateExecutable = true;
                parameters.CompilerOptions = "/target:winexe /optimize /win32icon:ImageView.ico";
                parameters.GenerateInMemory = false;
                string path = "test.exe";
                parameters.OutputAssembly = path;
                
                parameters.ReferencedAssemblies.Add("SaveExe.exe");//此处是自身的exe
                parameters.ReferencedAssemblies.Add("System.dll");
                parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
                parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
                parameters.ReferencedAssemblies.Add("System.Core.dll");
                parameters.ReferencedAssemblies.Add("System.Data.dll");
                parameters.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
                parameters.ReferencedAssemblies.Add("System.Deployment.dll");
                parameters.ReferencedAssemblies.Add("System.Drawing.dll");
                parameters.ReferencedAssemblies.Add("System.Net.Http.dll");
                parameters.ReferencedAssemblies.Add("System.Xml.dll"); 
                parameters.ReferencedAssemblies.Add("System.Xml.Linq.dll");
                
                string sourceFile = @"
                using System;
                using System.Collections.Generic;
                using System.Linq;
                using System.Threading.Tasks;
                using System.Windows.Forms;
    
                namespace SaveExe
                {
                    static class Program
                    {
                        /// <summary>
                        /// 应用程序的主入口点。
                        /// </summary>
                        [STAThread]
                        static void Main()
                        {
                            Application.EnableVisualStyles();
                            Application.SetCompatibleTextRenderingDefault(false);
                            Application.Run(new Form1());
                        }
                    }
                }
            ";
                CompilerResults cr = provider.CompileAssemblyFromSource(parameters, sourceFile);
                if (cr.Errors.Count > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (var er in cr.Errors)
                        sb.AppendLine(er.ToString());
                    MessageBox.Show(sb.ToString());
                }
                else
                {
                    MessageBox.Show("编译成功");
                }
            }

     以上方法有一个限制就是必须在自身的exe所在的路径下有效,即生成的exe和原本的exe要在同一个目录下。

    解决方案,就是嵌入资源,将原本的exe嵌入到新生成的exe。然后使用动态加载。

    例子:

    程序GraphicPlay.EXE,里面有个Form1,实现生成新的程序,直接弹出Form1

    public class SaveEXE
        {
            public static void CreateCode(string filename, string source)
            {
                CSharpCodeProvider provider = new CSharpCodeProvider();
                CompilerParameters parameters = new CompilerParameters();
                parameters.GenerateExecutable = true;
                parameters.CompilerOptions = "/target:winexe /optimize /win32icon:Image.ico";//这里增加了图标,没有对应图标的可以删除
                parameters.GenerateInMemory = false;
                string path = filename;
                parameters.OutputAssembly = path;
    
                parameters.ReferencedAssemblies.Add("System.dll");
                parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
                parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
                parameters.ReferencedAssemblies.Add("System.Core.dll");
                parameters.ReferencedAssemblies.Add("System.Data.dll");
                parameters.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
                parameters.ReferencedAssemblies.Add("System.Deployment.dll");
                parameters.ReferencedAssemblies.Add("System.Drawing.dll");
                parameters.ReferencedAssemblies.Add("System.Net.Http.dll");
                parameters.ReferencedAssemblies.Add("System.Xml.dll");
                parameters.ReferencedAssemblies.Add("System.Xml.Linq.dll");
                parameters.EmbeddedResources.Add(Application.ExecutablePath);//这里添加嵌入资源
                
                CompilerResults cr = provider.CompileAssemblyFromSource(parameters, source);
                if (cr.Errors.Count > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (var er in cr.Errors)
                        sb.AppendLine(er.ToString());
                    throw new Exception(sb.ToString());
                }
            }
        }
    SaveEXE.CreateCode(save.FileName,(@"
                        using System;
                        using System.Collections.Generic;
                        using System.Linq;
                        using System.Threading.Tasks;
                        using System.Windows.Forms; 
                        using System.Reflection; 
                        using System.IO; 
    
                        namespace GraphicPlay
                        {
                            static class Program
                            {
                                /// <summary>
                                /// 应用程序的主入口点。
                                /// </summary>
                                [STAThread]
                                static void Main()
                                {
                                    Application.EnableVisualStyles();
                                    Application.SetCompatibleTextRenderingDefault(false);
                                    try
                                    {
                                        Assembly assembly = Assembly.GetExecutingAssembly();
                                        Stream stream = assembly.GetManifestResourceStream(""GraphicPlay.EXE"");
                                        if(stream==null)
                                            throw new Exception(""加载资源失败"");
                                        byte[] buffer = new byte[(int)stream.Length];
                                        stream.Read(buffer, 0, buffer.Length);
                                        stream.Close();
                                        Assembly asm = Assembly.Load(buffer);
                                        if(stream==null)
                                            throw new Exception(""加载程序集失败"");
                                        Type t = asm.GetType(""GraphicPlay.Form1"");
                                        var form = asm.CreateInstance(t.FullName) as Form;
                                        Application.Run(form);
                                    }
                                    catch(Exception ex)
                                    {
                                        MessageBox.Show(ex.ToString());
                                    }
                                }
                            }
                        }"));

     有时需要动态引用DLL,可以参考以下方法:(需要先将DLL添加到资源文件中,然后加载资源文件)

    System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
            {
                string dllName = args.Name.Contains(",") ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", "");
                dllName = dllName.Replace(".", "_");
                if (dllName.EndsWith("_resources")) return null;
                System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
                byte[] bytes = (byte[])rm.GetObject(dllName);
                return System.Reflection.Assembly.Load(bytes);
            }
    
            public Form1()//看清楚这是窗体本来的初始化函数
            {
                //在InitializeComponent()之前调用
    
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
                InitializeComponent();
            }

    参考文章:https://www.iteye.com/problems/72159

                      https://blog.csdn.net/lin381825673/article/details/39122257?tdsourcetag=s_pcqq_aiomsg

                      https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/target-compiler-option

  • 相关阅读:
    vs.net2003里添加邮件发件人身份验证
    Linux下用PYTHON查找同名进程
    修改机器名后要修改IIS匿名访问用户
    [C#]使用MYSQL数据库
    JIRA OutOfMemoryErrors
    获取linux下当机堆栈
    python调用pipe
    [探讨]一次性工具软件
    GGSN
    三层交换机的作用
  • 原文地址:https://www.cnblogs.com/mqxs/p/11028165.html
Copyright © 2011-2022 走看看