Winform动态编译并打包

24 篇文章 2 订阅
3 篇文章 0 订阅

        C#文章第四篇之动态编译并生成exe程序,本文主要介绍C#动态编译然后生成exe可执行文件。

        接第三篇附件在打上水印之后与源码一起动态编译进exe程序。程序在.NET Framework 4,VistualStudio 2017上测试通过。

        动态编译主要利用CSharpCodeProvider类,CSharpCodeProvider提供对 C# 代码生成器和代码编译器的实例的访问权限。通过输入源码文件编译为可执行文件,并将错误返回。

CompilerResults compilerResults = new CSharpCodeProvider().CompileAssemblyFromSource(compilerParameters, new string[]
{
    sourceCode
});

        编译之前需要将C#代码包含的命名空间、类、方法,以及需要引用的命名空间处理出来,对于引用的控件DLL也需要加载进来一起编译。

第一步、加载需要编译的文件

        此部分可以定义一个变量或者放在文件中,项目中为了方便特意将引用部分提取到变量中,而源码部分保存为文件,在打包文件的时候动态加载。

public static string code = @"using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Data.SqlClient;
using O2S.Components.PDFRender4NET;
";

 打包的exe执行的时候部分代码需要admin权限,因此在Main()方法中需要设置相关的权限:

//已管理员权限运行,同时关闭当前程序
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(); 
startInfo.FileName = System.Windows.Forms.Application.ExecutablePath;
startInfo.Verb = "runas";
System.Diagnostics.Process.Start(startInfo);
System.Diagnostics.Process.GetCurrentProcess().Kill();
return;

加载dll

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string resourceName = new AssemblyName(args.Name).Name + ".dll";
    using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) { Byte[] assemblyData = new Byte[stream.Length]; stream.Read(assemblyData, 0, assemblyData.Length); return Assembly.Load(assemblyData); }
}

第二步、编译源码

        通过CompilerParameters设置相关参数:GenerateExecutable设置为true,表示生成可执行文件,OutputAssembly设置输出程序集的名称,CompilerOptions设置编译器编译时的参数,例如运行平台、程序图标等参数,EmbeddedResources是一个集合是打包后的程序包含的资源文件,可以设置程序运行需要的dll文件、相关图像、图标等文件,同时打包的附件(word、excel、pdf)等也包含在EmbeddedResources中。

compilerParameters.EmbeddedResources.Add("O2S.Components.PDFView4NET.dll");
...
compilerParameters.EmbeddedResources.Add("11.jpg");
compilerParameters.EmbeddedResources.Add(Environment.GetEnvironmentVariable("TEMP") + "\\" + current + ".pdf");

        在项目中因需要打包的dll较多,为了减少体积,因此将相关dll打包为压缩文件

compilerParameters.EmbeddedResources.Add("dll.zip");

        调用CSharpCodeProvider类的CompileAssemblyFromSource方法完成编译

CompilerResults compilerResults = new CSharpCodeProvider().CompileAssemblyFromSource(compilerParameters, new string[]
{
    sourceCode
});

CompileAssemblyFromSource方法有两个参数第一个是CompilerParameters用于设置编译器的相关参数和对象,第二个string[]为要编译的源代码字符串的数组。如果编译失败则返回响应的错误通过compilerResults.Errors.HasErrors可以获取到相应内容。

        最后,以zip形式打包的dll需要在新程序运行的时候解压出来

string temp = System.Environment.GetEnvironmentVariable("TEMP") + "\\";
//加载程序集中的dll文件,并保存在临时文件夹中
Stream stream = asm.GetManifestResourceStream("FileView.dll.zip");
byte[] srcBuf = new Byte[stream.Length];
stream.Read(srcBuf, 0, srcBuf.Length);
using (FileStream fs = new FileStream(temp + "dll.zip", FileMode.Create, FileAccess.Write))
{
    fs.Write(srcBuf, 0, srcBuf.Length);
    fs.Close();
}
//zip解压
UnZip(temp + "dll.zip", temp, "");

        文件加密项目到此为止,后续整理源码后再发出来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苜蓿花乐园

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值