原文链接
    动态创建EXE功能目的:
    比如我们写了设计软件,可以界面设计一些东西。现在我们需要将我们设计好的东西保存成一个exe,用户打开就直接可以看到设计好的东西。也就是需要把数据保存到exe里面。
    这个时候呢,我们可以动态生成一个新的程序,这个程序调用我们原先的设计软件,区别是,我们运行这个软件的时候,可以把原先设计好的数据全部写死写入到新的软件里面,
    然后参数传入到设计软件。这样就可以实现双击运行软件,打开就是原先设计好的数据了。
    ★★★C# 动态建立EXE - 图1
    废话讲完了,也不知道有没有讲清楚、、、、
    1.创建项目SaveExe或者修改代码中SaveExe名字为自己的项目
    2.添加按钮调用CreateCodeEXE,即可实现编译生成一个新的exe即 复制了自身的exe生成一个新的exe(目的就是新生的exe,我们可以增加预设参数属性之类)。

    1. public static void CreateCodeEXE()
    2. {
    3. CSharpCodeProvider provider = new CSharpCodeProvider();
    4. CompilerParameters parameters = new CompilerParameters();
    5. parameters.GenerateExecutable = true;
    6. parameters.CompilerOptions = "/target:winexe /optimize /win32icon:ImageView.ico";
    7. parameters.GenerateInMemory = false;
    8. string path = "test.exe";
    9. parameters.OutputAssembly = path;
    10. parameters.ReferencedAssemblies.Add("SaveExe.exe");//此处是自身的exe
    11. parameters.ReferencedAssemblies.Add("System.dll");
    12. parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
    13. parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
    14. parameters.ReferencedAssemblies.Add("System.Core.dll");
    15. parameters.ReferencedAssemblies.Add("System.Data.dll");
    16. parameters.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
    17. parameters.ReferencedAssemblies.Add("System.Deployment.dll");
    18. parameters.ReferencedAssemblies.Add("System.Drawing.dll");
    19. parameters.ReferencedAssemblies.Add("System.Net.Http.dll");
    20. parameters.ReferencedAssemblies.Add("System.Xml.dll");
    21. parameters.ReferencedAssemblies.Add("System.Xml.Linq.dll");
    22. string sourceFile = @"
    23. using System;
    24. using System.Collections.Generic;
    25. using System.Linq;
    26. using System.Threading.Tasks;
    27. using System.Windows.Forms;
    28. namespace SaveExe
    29. {
    30. static class Program
    31. {
    32. /// <summary>
    33. /// 应用程序的主入口点。
    34. /// </summary>
    35. [STAThread]
    36. static void Main()
    37. {
    38. Application.EnableVisualStyles();
    39. Application.SetCompatibleTextRenderingDefault(false);
    40. Application.Run(new Form1());
    41. }
    42. }
    43. }
    44. ";
    45. CompilerResults cr = provider.CompileAssemblyFromSource(parameters, sourceFile);
    46. if (cr.Errors.Count > 0)
    47. {
    48. StringBuilder sb = new StringBuilder();
    49. foreach (var er in cr.Errors)
    50. sb.AppendLine(er.ToString());
    51. MessageBox.Show(sb.ToString());
    52. }
    53. else
    54. {
    55. MessageBox.Show("编译成功");
    56. }
    57. }

    以上方法有一个限制就是必须在自身的exe所在的路径下有效,即生成的exe和原本的exe要在同一个目录下。
    解决方案,就是嵌入资源,将原本的exe嵌入到新生成的exe。然后使用动态加载。
    例子:
    程序GraphicPlay.EXE,里面有个Form1,实现生成新的程序,直接弹出Form1

    1. public class SaveEXE
    2. {
    3. public static void CreateCode(string filename, string source)
    4. {
    5. CSharpCodeProvider provider = new CSharpCodeProvider();
    6. CompilerParameters parameters = new CompilerParameters();
    7. parameters.GenerateExecutable = true;
    8. parameters.CompilerOptions = "/target:winexe /optimize /win32icon:Image.ico";//这里增加了图标,没有对应图标的可以删除
    9. parameters.GenerateInMemory = false;
    10. string path = filename;
    11. parameters.OutputAssembly = path;
    12. parameters.ReferencedAssemblies.Add("System.dll");
    13. parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
    14. parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
    15. parameters.ReferencedAssemblies.Add("System.Core.dll");
    16. parameters.ReferencedAssemblies.Add("System.Data.dll");
    17. parameters.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
    18. parameters.ReferencedAssemblies.Add("System.Deployment.dll");
    19. parameters.ReferencedAssemblies.Add("System.Drawing.dll");
    20. parameters.ReferencedAssemblies.Add("System.Net.Http.dll");
    21. parameters.ReferencedAssemblies.Add("System.Xml.dll");
    22. parameters.ReferencedAssemblies.Add("System.Xml.Linq.dll");
    23. parameters.EmbeddedResources.Add(Application.ExecutablePath);//这里添加嵌入资源
    24. CompilerResults cr = provider.CompileAssemblyFromSource(parameters, source);
    25. if (cr.Errors.Count > 0)
    26. {
    27. StringBuilder sb = new StringBuilder();
    28. foreach (var er in cr.Errors)
    29. sb.AppendLine(er.ToString());
    30. throw new Exception(sb.ToString());
    31. }
    32. }
    33. }
    1. SaveEXE.CreateCode(save.FileName,(@"
    2. using System;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5. using System.Threading.Tasks;
    6. using System.Windows.Forms;
    7. using System.Reflection;
    8. using System.IO;
    9. namespace GraphicPlay
    10. {
    11. static class Program
    12. {
    13. /// <summary>
    14. /// 应用程序的主入口点。
    15. /// </summary>
    16. [STAThread]
    17. static void Main()
    18. {
    19. Application.EnableVisualStyles();
    20. Application.SetCompatibleTextRenderingDefault(false);
    21. try
    22. {
    23. Assembly assembly = Assembly.GetExecutingAssembly();
    24. Stream stream = assembly.GetManifestResourceStream(""GraphicPlay.EXE"");
    25. if(stream==null)
    26. throw new Exception(""加载资源失败"");
    27. byte[] buffer = new byte[(int)stream.Length];
    28. stream.Read(buffer, 0, buffer.Length);
    29. stream.Close();
    30. Assembly asm = Assembly.Load(buffer);
    31. if(stream==null)
    32. throw new Exception(""加载程序集失败"");
    33. Type t = asm.GetType(""GraphicPlay.Form1"");
    34. var form = asm.CreateInstance(t.FullName) as Form;
    35. Application.Run(form);
    36. }
    37. catch(Exception ex)
    38. {
    39. MessageBox.Show(ex.ToString());
    40. }
    41. }
    42. }
    43. }"));

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

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

    参考文章: 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