123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Windows.Forms;
- using System.Xml.Linq;
- using Newtonsoft.Json;
- namespace MSBuild
- {
- public partial class FormMain : Form
- {
- #region 变量
- /// <summary>
- /// 配置信息保存路径
- /// </summary>
- private static readonly string Dir = AppDomain.CurrentDomain.BaseDirectory + @"SaveDir\";
- /// <summary>
- /// 需要编译的文件路径
- /// </summary>
- private List<string> _listProject;
- /// <summary>
- /// 替换dll
- /// </summary>
- private string[] _listDll;
- /// <summary>
- /// 获取编译工具路径
- /// </summary>
- private string _versionUrl;
- /// <summary>
- /// 获取编译模式
- /// </summary>
- private string _configure;
- /// <summary>
- /// 指定文件夹
- /// </summary>
- private string _saveUrl;
- /// <summary>
- /// 编译的日志
- /// </summary>
- private string _buildLog;
- /// <summary>
- /// 记录替换过程中发生的信息
- /// </summary>
- private string _replaceText;
- /// <summary>
- /// 替换的线程
- /// </summary>
- private readonly BackgroundWorker _replaceWorker = new BackgroundWorker();
- /// <summary>
- /// 编译的线程
- /// </summary>
- private readonly BackgroundWorker _buildWorker = new BackgroundWorker();
- #endregion
- #region 窗体方法
- public FormMain()
- {
- InitializeComponent();
- }
- /// <summary>
- /// 响应窗体的Load事件
- /// </summary>
- private void FormMain_Load(object sender, EventArgs e)
- {
- projectFileText.ReadOnly = dllFileText.ReadOnly = outputText.ReadOnly = buildText.ReadOnly = true;
- buttonReplace.Enabled = false;
- // 获取编译工具
- BindVersion();
- // 获取编译模式
- BindModel();
- // 设置线程属性
- _replaceWorker.WorkerReportsProgress = _buildWorker.WorkerReportsProgress = true; // 进度更新
- // 设置线程处理的对象
- _replaceWorker.DoWork += _replaceWorker_DoWork;
- _replaceWorker.ProgressChanged += _replaceWorker_ProgressChanged;
- _replaceWorker.RunWorkerCompleted += _replaceWorker_RunWorkerCompleted;
- _buildWorker.DoWork += _buildWorker_DoWork;
- _buildWorker.ProgressChanged += _buildWorker_ProgressChanged;
- _buildWorker.RunWorkerCompleted += _buildWorker_RunWorkerCompleted;
- }
- #endregion
- #region 对象方法
- /// <summary>
- /// 打开文件文件夹
- /// </summary>
- private void buttonOpenProject_Click(object sender, EventArgs e)
- {
- var dialog = new FolderBrowserDialog { Description = @"请选择需要编译的文件路径!" };
- bool? result = dialog.ShowDialog() == DialogResult.OK;
- if (result == true)
- {
- projectFileText.Text = dialog.SelectedPath;
- }
- }
- /// <summary>
- /// 打开替换Dll文件夹
- /// </summary>
- private void buttonOpenDll_Click(object sender, EventArgs e)
- {
- var dialog = new FolderBrowserDialog { Description = @"请选择替换Dll的文件路径!" };
- bool? result = dialog.ShowDialog() == DialogResult.OK;
- if (result == true)
- {
- dllFileText.Text = dialog.SelectedPath;
- }
- }
- /// <summary>
- /// 查找需要替换的文件
- /// </summary>
- private void buttonAnalysis_Click(object sender, EventArgs e)
- {
- /* 清空显示 */
- projectText.Text = "";
- // 判断编译路径是否存在
- if (string.IsNullOrWhiteSpace(projectFileText.Text))
- {
- MessageBox.Show(@"编译文件夹路径不能为空!");
- return;
- }
- // 判断文件夹是否存在
- if (!Directory.Exists(projectFileText.Text))
- {
- MessageBox.Show(@"编译文件夹路径不存在");
- return;
- }
- // 判断替换路径是否存在
- if (string.IsNullOrWhiteSpace(dllFileText.Text))
- {
- MessageBox.Show(@"替换路径不能为空!");
- return;
- }
- // 判断替换文件夹是否存在
- if (!Directory.Exists(dllFileText.Text))
- {
- MessageBox.Show(@"替换文件夹不存在!");
- return;
- }
- // 获取编译路径下的所有.csproj文件
- _listProject = Directory.GetFiles(projectFileText.Text, "*.csproj", SearchOption.AllDirectories).ToList();
- // 若不存在,则提示
- if (_listProject.Count == 0)
- {
- MessageBox.Show(@"不存在需要编译的文件");
- return;
- }
- foreach (var project in _listProject)
- {
- projectText.Text += project + Environment.NewLine;
- }
- // 获取替换dll
- _listDll = Directory.GetFiles(dllFileText.Text, "*.dll", SearchOption.AllDirectories);
- if (_listDll.Length == 0)
- {
- MessageBox.Show(@"替换路径下,没有发现可以替换的DLL!");
- buttonReplace.Enabled = false;
- }
- buttonReplace.Enabled = true;
- }
- /// <summary>
- /// 替换引用
- /// </summary>
- private void buttonReplace_Click(object sender, EventArgs e)
- {
- // 替换路径不能为空
- if (string.IsNullOrWhiteSpace(dllFileText.Text))
- {
- MessageBox.Show(@"替换路径不能为空!");
- return;
- }
- // 判断是否正在异步执行
- if (!_replaceWorker.IsBusy)
- {
- _replaceWorker.RunWorkerAsync();
- }
- }
- /// <summary>
- /// 选择输出文件夹
- /// </summary>
- private void buttonOutputFile_Click(object sender, EventArgs e)
- {
- var dialog = new FolderBrowserDialog { Description = @"请选择输出的文件路径!" };
- bool? result = dialog.ShowDialog() == DialogResult.OK;
- if (result == true)
- {
- outputText.Text = dialog.SelectedPath;
- }
- }
- /// <summary>
- /// 编译
- /// </summary>
- private void buttonBuild_Click(object sender, EventArgs e)
- {
- /* 清空显示 */
- buildText.Text = "";
- // 判断编译源是否为空
- if (_listProject == null || _listProject.Count == 0)
- {
- MessageBox.Show(@"请先查找!");
- return;
- }
- // 判断输出路径是否存在
- if (!Directory.Exists(outputText.Text))
- {
- MessageBox.Show(@"指定输出路径不存在");
- return;
- }
- // 获取编译工具路径
- _versionUrl = ((ItemModel)versionCom.SelectedItem).Value;
- // 获取编译模式
- _configure = ((ItemModel)configureBox.SelectedItem).Value;
- // 指定文件夹
- _saveUrl = outputText.Text;
- // 判断是否正在执行异步操作
- if (!_buildWorker.IsBusy && !_replaceWorker.IsBusy)
- {
- _buildWorker.RunWorkerAsync();
- }
- }
- /// <summary>
- /// 保存配置的事件
- /// </summary>
- private void SaveConfigure_Click(object sender, EventArgs e)
- {
- //获取当前配置
- var config = GetConfigModel();
- //保存路径不存在时,创建
- if (!Directory.Exists(Dir))
- {
- Directory.CreateDirectory(Dir);
- }
- //若文件不存在则创建
- var filePath = Dir + "config.txt";
- var file = new StreamWriter(filePath, false);
- //写入
- file.Write(JsonConvert.SerializeObject(config));
- //关闭
- file.Close();
- file.Dispose();
- //提示
- MessageBox.Show(@"保存成功");
- }
- /// <summary>
- /// 读取配置的事件
- /// </summary>
- private void ReadConfigure_Click(object sender, EventArgs e)
- {
- try
- {
- // 获取文件内容
- if (!File.Exists(Dir + "config.txt"))
- {
- return;
- }
- var file = new StreamReader(Dir + "config.txt");
- var str = file.ReadToEnd();
- file.Close();
- file.Dispose();
- if (string.IsNullOrWhiteSpace(str))
- {
- return;
- }
- // 反序列化
- var config = JsonConvert.DeserializeObject<ConfigureModel>(str);
- if (config == null)
- {
- return;
- }
- // 赋值
- projectFileText.Text = config.Url;
- dllFileText.Text = config.PathUrl;
- outputText.Text = config.OutputUrl;
- versionCom.SelectedValue = config.VersionUlr;
- configureBox.SelectedValue = config.ModelKey;
- }
- catch (Exception exception)
- {
- MessageBox.Show(exception.Message);
- }
- }
- /// <summary>
- /// 响应_replaceWorker的DoWork事件
- /// </summary>
- private void _replaceWorker_DoWork(object sender, DoWorkEventArgs e)
- {
- // 清空文本
- _replaceText = "";
- // 获取替换的dll
- var dllFiles = _listDll
- .Select(file => new DirectoryInfo(file)).Select(path => new AnalysisModel { NewName = path.Name, NewPath = path.FullName })
- .ToList();
- // 循环获取替换
- var log = "";
- var count = _listProject.Count;
- for (var index = count - 1; index >= 0; index--)
- {
- _replaceWorker.ReportProgress(int.Parse(Math.Ceiling((count - index) / count * 100.0).ToString(CultureInfo.CurrentCulture)));
- var project = _listProject[index];
- // 获取项目名称
- var projectName = project.Substring(project.LastIndexOf('\\') + 1);
- var name = projectName.Substring(0, projectName.LastIndexOf('.'));
- //获取.csproj文件中的所有非系统引用
- var doc = XDocument.Load(project);
- var element = (doc.Root.Elements())
- .First(x => x.Name.LocalName == "ItemGroup");
- if (element == null)
- {
- log += name + ":项目中没有引用第三方不需替换。" + Environment.NewLine;
- _replaceText += name + "替换失败" + Environment.NewLine;
- continue;
- }
- var reference = element.Elements()
- .Where(x => x.Name.LocalName == "Reference")
- .ToList();
- var projectLists = reference
- .Select(el => new AnalysisModel() { OldName = el.Attribute("Include").Value, OldPath = el.Value })
- .Where(x => !string.IsNullOrWhiteSpace(x.OldPath))
- .ToList();
- if (projectLists.Count == 0)
- {
- log += name + ":项目中没有引用第三方不需替换。" + Environment.NewLine;
- _replaceText += name + "替换失败" + Environment.NewLine;
- continue;
- }
- //根据获取的引用查找替换文件夹中的引用
- var list = (from projectList in projectLists
- let sp = projectList.OldName.Split(',')
- let y = sp.Length == 0 ? projectList.OldName : sp[0]
- let split = y.Split(new[] { ".v" }, StringSplitOptions.None)
- let x = split.Length == 1 ? y : split[1] == "1" ? y : split[0]
- let z = split.Length < 2 || split[1].IndexOf('.') + 1 == split[1].Length - 1 ? "" : split[1].Substring(split[1].IndexOf('.', split[1].IndexOf('.') + 1))
- let contain = dllFiles.Where(a => a.NewName.Contains(x)).ToList()
- let contains = z == "" ? contain : contain.Where(b => b.NewName.Contains(z)).ToList()
- where contains.Count != 0
- select new AnalysisModel
- {
- OldName = projectList.OldName,
- OldPath = projectList.OldPath,
- NewName = contains[0].NewName,
- NewPath = contains[0].NewPath
- })
- .ToList();
- var listExcept = (from projectList in projectLists
- let sp = projectList.OldName.Split(',')
- let y = sp.Length == 0 ? projectList.OldName : sp[0]
- let split = y.Split(new[] { ".v" }, StringSplitOptions.None)
- let x = split.Length == 0 ? projectList.OldName : split[0]
- let contain = dllFiles.Where(z => z.NewName.Contains(x)).ToList()
- where contain.Count == 0
- select new AnalysisModel
- {
- OldName = y
- })
- .ToList();
- if (list.Count == 0)
- {
- log += name + ":所引用的第三方dll,在引用文件夹中全部不存在" + Environment.NewLine;
- _replaceText += name + "替换失败" + Environment.NewLine;
- _listProject.Remove(project); //不进行编译
- continue;
- }
- if (listExcept.Count != 0)
- {
- var listDll = string.Join(",", listExcept.Select(x => x.OldName));
- log += name + ":所引用的第三方dll" + listDll + ",在引用文件夹中不存在" + Environment.NewLine;
- _replaceText += name + "替换失败" + Environment.NewLine;
- _listProject.Remove(project); //不进行编译
- continue;
- }
- //获取.csproj文件中的所有非系统引用
- var elements = element.Elements().Where(x => !string.IsNullOrWhiteSpace(x.Value)).ToList();
- for (var i = elements.Count - 1; i >= 0; i--)
- {
- var elem = elements[i];
- var old = list.Where(x => x.OldName == elem.Attribute("Include").Value).ToList();
- if (old.Count == 0) continue;
- //添加新节点
- XNamespace nameNamespace = element.Name.NamespaceName;
- var referenceName = new XElement(nameNamespace + "Reference");
- var newName = old[0].NewName.Split(new[] { ".dll" }, StringSplitOptions.None);
- referenceName.SetAttributeValue("Include", newName.Length == 0 ? old[0].NewName : newName[0]);
- referenceName.SetElementValue(nameNamespace + "HintPath", old[0].NewPath);
- element.AddFirst(referenceName);
- //移除当前节点
- elem.Remove();
- }
- doc.Save(project, SaveOptions.OmitDuplicateNamespaces);
- _replaceText += name + "替换成功" + Environment.NewLine;
- }
- //保存路径不存在时,创建
- if (!Directory.Exists(Dir))
- {
- Directory.CreateDirectory(Dir);
- }
- //若文件不存在则创建
- var filePath = Dir + "log.txt";
- var logFile = new StreamWriter(filePath, false);
- //写入
- logFile.Write(log);
- //关闭
- logFile.Close();
- logFile.Dispose();
- //提示
- _replaceText += "如有替换失败,请查看log.txt日志";
- }
- /// <summary>
- /// 响应_replaceWorker的ProgressChanged事件
- /// </summary>
- private void _replaceWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
- {
- replaceProgress.Value = e.ProgressPercentage;
- }
- /// <summary>
- /// 响应_replaceWorker的RunWorkerCompleted事件
- /// </summary>
- private void _replaceWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
- {
- MessageBox.Show(e.Cancelled ? @"进程已被取消:" + replaceProgress.Value + "%" : @"进程执行完成:" + replaceProgress.Value + "%");
- replaceProgress.Value = 0;
- projectText.Text = _replaceText;
- }
- /// <summary>
- /// 响应_buildWorker的DoWork事件
- /// </summary>
- private void _buildWorker_DoWork(object sender, DoWorkEventArgs e)
- {
- //循环编译
- string errLog = "";
- var count = _listProject.Count;
- for (var index = 0; index < _listProject.Count; index++)
- {
- var project = _listProject[index];
- // 获取编译文件路径
- var buildUrl = project;
- // 获取输出路径,不存在则新建,存在则删除文件夹中的文件
- var outputUrl = buildUrl.Substring(0, buildUrl.LastIndexOf('\\')) + "\\bin\\" + _configure;
- if (!Directory.Exists(outputUrl))
- {
- Directory.CreateDirectory(outputUrl);
- }
- else
- {
- DeleteDir(outputUrl);
- }
- // 定义编译脚本
- var cmd = "";
- cmd += "@echo off";
- cmd += "\r\n";
- cmd += "\"" + _versionUrl + "\" " + "\"" + buildUrl + "\" " + "/t:rebuild /p:Configuration=" + _configure + " /p:OutDir=" + "\"" + outputUrl + "\"";
- // 编译
- string output;
- ComHelper.RunCmd(cmd, out output);
- _buildLog = output + Environment.NewLine;
- // 复制文件到指定文件夹
- var file = buildUrl.Substring(buildUrl.LastIndexOf('\\'));
- var fileName = file.Substring(0, file.LastIndexOf('.')) + ".dll";
- if (!File.Exists(outputUrl + '\\' + fileName))
- {
- fileName = file.Substring(0, file.LastIndexOf('.')) + ".exe";
- }
- try
- {
- File.Copy(outputUrl + '\\' + fileName, _saveUrl + '\\' + fileName, true);
- }
- catch
- {
- errLog += output;
- }
- _buildWorker.ReportProgress(int.Parse(Math.Ceiling((index + 1.0) / count * 100).ToString(CultureInfo.CurrentCulture)));
- }
- //保存路径不存在时,创建
- if (!Directory.Exists(Dir))
- {
- Directory.CreateDirectory(Dir);
- }
- //若文件不存在则创建
- var filePath = Dir + "errors.txt";
- var logFile = new StreamWriter(filePath, false);
- //写入
- logFile.Write(errLog);
- //关闭
- logFile.Close();
- logFile.Dispose();
- }
- /// <summary>
- /// 响应_buildWorker的ProgressChanged事件
- /// </summary>
- private void _buildWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
- {
- buildProgress.Value = e.ProgressPercentage;
- buildText.Text += _buildLog;
- }
- /// <summary>
- /// 响应_buildWorker的RunWorkerCompleted事件
- /// </summary>
- private void _buildWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
- {
- MessageBox.Show(e.Cancelled ? @"进程已被取消:" + buildProgress.Value + "%" : @"进程执行完成:" + buildProgress.Value + "%");
- buildProgress.Value = 0;
- }
- #endregion
- #region 内部方法
- /// <summary>
- /// 获取并绑定编译工具
- /// </summary>
- private void BindVersion()
- {
- //获取MSBuild
- var exeName = "MSBuild.exe";
- var msBuilds = Directory.GetFiles(@"C:\Program Files (x86)", exeName, SearchOption.AllDirectories);
- if (msBuilds.Length == 0)
- {
- MessageBox.Show(@"请先安装vs");
- return;
- }
- var listVersion = (from msBuild in msBuilds
- let split = msBuild.Split(new[] { "\\", "/" }, StringSplitOptions.RemoveEmptyEntries)
- where split.Length > 3
- let amd = split[split.Length - 2]
- let version = amd.Contains("64") ? "(x64)" : "(x86)"
- select new ItemModel(split[3] + version, msBuild))
- .ToList();
- versionCom.DisplayMember = "Key";
- versionCom.ValueMember = "Value";
- versionCom.DataSource = listVersion;
- }
- /// <summary>
- /// 绑定编译模式
- /// </summary>
- private void BindModel()
- {
- var dataSource = new List<ItemModel>
- {
- new ItemModel("1", "Debug"),
- new ItemModel("2", "Release")
- };
- //编译模式
- configureBox.DisplayMember = "Value";
- configureBox.ValueMember = "Key";
- configureBox.DataSource = dataSource;
- }
- /// <summary>
- /// 获取当前配置
- /// </summary>
- private ConfigureModel GetConfigModel()
- {
- var config = new ConfigureModel()
- {
- Url = projectFileText.Text,
- PathUrl = dllFileText.Text,
- OutputUrl = outputText.Text
- };
- if (versionCom.SelectedItem is ItemModel)
- {
- ItemModel versionItem = versionCom.SelectedItem as ItemModel;
- config.Version = versionItem.Key;
- config.VersionUlr = versionItem.Value;
- }
- if (configureBox.SelectedItem is ItemModel)
- {
- ItemModel modelItem = configureBox.SelectedItem as ItemModel;
- config.Model = modelItem.Value;
- config.ModelKey = modelItem.Key;
- }
- return config;
- }
- /// <summary>
- /// 删除文件夹下的所有文件
- /// </summary>
- private void DeleteDir(string srcPath)
- {
- try
- {
- DirectoryInfo dir = new DirectoryInfo(srcPath);
- FileSystemInfo[] fileInfo = dir.GetFileSystemInfos();
- foreach (FileSystemInfo file in fileInfo)
- {
- if (file is DirectoryInfo)
- {
- DirectoryInfo subDir = new DirectoryInfo(file.FullName);
- subDir.Delete(true);
- }
- else
- {
- File.Delete(file.FullName);
- }
- }
- }
- catch (Exception)
- {
- throw;
- }
- }
- #endregion
- }
- }
|