关于.Net中Process的使用方法和各种用途汇总(二):用Process启动cmd.exe完成将cs编译成dll
上一章博客我为大家介绍了Process类的所有基本使用方法,这一章博客我来为大家做一个小扩展,来熟悉一下Process类的实际使用,废话不多说我们开始演示。
先看看我们的软件要设计成的布局吧。
首先我们需要给定会使用到的dll,记得vs中的引用那一项吗?我们虽然不需要将这里面的引用全部导入进来,但是我们需要将我们使用过的dll全部导入进来,不然编译时会提示找不到类方法之类的。
可能有些同学不知道怎么查看一个类或者方法所在的dll,其实只用对着那个方法或者类按下f12就能在打开的文档的正上方看到所在的dll了,包括dll所在的路径都写的非常清楚。
我后续更新是想完成导入工程,读取出来工程内的cs文件和资源,选择需要编译的cs文件和资源,然后点击编译,完成编译,不过功能比较多,我会慢慢的更新,没更新一个版本会在本博客的下方附上地址。
介绍就先到此为止,我们开始讲解代码的实现过程,由于整个工程的代码大部分和我们需要讲解的内容无关,所以我只挑出核心功能在这里介绍一下,其他的内容请自行下载工程查看。先贴上代码,我感觉代码中的注释已经写的非常明白的,不过我还是找些注释解释的不是很明白的地方详细讲解下。
/// <summary>
/// 异步执行编译
/// </summary>
private async void Compiled()
{
//注意:我们下面这几个变量提前拿出来是因为ui都式不能跨线程访问,异步操作也会被认为是多线程。 //dll的输出路径
string working = path_textBox.Text;
//dll的名字
string name = name_textBox.Text;
//vs的路径,这里我们使用的是vs的一个批处理文件进行dll的编译,它会自动帮我们配置好环境,虽然我们直接使用.net的csc.exe也能编译,但是你看我的代码里用的c#6.0的各种新语法都是需要编译器支持的,仅仅使用.net的csc.exe是无法完成编译的
string vs_Path = vs_Path_textBox.Text + "\\Common7\\Tools\\VsMSBuildCmd.bat"; //这个也不算新语法了,这个和上面的async是一对,你给一个方法标记上async表示这个方法是异步的,但是注意await等待的代码以外的代码是同步执行的,也就是说是主线程执行的,必须将需要执行的代码放在Task.Run()中,才会异步执行,我一开始就是有这个误区一直疑惑异步为啥还会卡。
await Task.Run(() =>
{
//创建一个ProcessStartInfo,设置初始信息
System.Diagnostics.ProcessStartInfo start = new System.Diagnostics.ProcessStartInfo("cmd.exe");
//让应用可以接受输入,这里我们用于向控制台输入命令
start.RedirectStandardInput = true;
//让应用可以输出数据,这里我们是打算读取在编译完毕后读取控制台的输出数据判断是否编译成功的,但是暂时无法完成此功能
start.RedirectStandardOutput = true;
//这个属性设置成true可以让打开的控制台无窗口,以达到我们想要的效果
start.CreateNoWindow = true;
//这个属性也不知道干什么用的,但是你想对控制台进行控制,这个属性必须设置为false,不然会抛出异常告诉你,必须要将此属性设置为false
start.UseShellExecute = false; //终于开始正题了,就像上一章博客介绍的那样,我们通过ProcessStartInfo初始化一个Process对象
System.Diagnostics.Process process = System.Diagnostics.Process.Start(start); //以下就是像控制台输入命令的过程了,想从控制台读取数据,就直接调用StandardOutput.ReadLine();就能读取一行了,不过要注意了,你调用了此方法后,控制台会一直等待一个输入,所以很容易就一直卡在那里不执行下面的代码 //GetLetter方法是我自己定义个获取路径中的盘符加上:用的,用此方法获取到vs所在的盘,之后直接将命令输给cmd,就能进入vs所在的磁盘分区了,不明白的自己去补控制台命令
process.StandardInput.WriteLine(GetLetter(vs_Path));
//用cd命令进入VsMSBuildCmd.bat批处理文件所在的路径
process.StandardInput.WriteLine("cd " + System.IO.Path.GetDirectoryName(vs_Path));
//获取VsMSBuildCmd.bat文件的名字,并输入给cmd,执行这个批处理文件的命令
process.StandardInput.WriteLine(System.IO.Path.GetFileName(vs_Path)); //批处理文件执行完毕后,我们的控制台环境就被搭建好了,我们将路径再转向dll的输出目录
process.StandardInput.WriteLine(GetLetter(working));
process.StandardInput.WriteLine("cd " + working); //将会使用到的dll以","为分割符拼接起来。这里我说明一下会使用到的dll什么意思,假设我们的类调用第三方dll之类的时候,当然你调用了如System.Windows.MessageBox();之类的方法也需要引用对应的dll。
//不知道用的方法或者类是在哪个dll?对着你的方法或者类按下f12在代开的文档的最上方写着呢。
//StringBuilder是个高效的字符串拼接类,但是相应的功能没有string多,在拼接完所有字符串后,直接ToString就能得到字符串
StringBuilder dll = new StringBuilder();
foreach (string item in DllPath)
{
dll.Append(item);
dll.Append(",");
} //将需要编译的cs文件以空格为分隔符拼接起来,这里用空格,dll那里用,这是语法,别问我为什么。
StringBuilder cs = new StringBuilder();
foreach (string item in CsPath)
{
cs.Append(item);
cs.Append(" ");
} //如果没有使用其他dll的情况下
if (dll.ToString() == "")
{
//由于没有使用dll的情况。
//我一一解释这些命令都是干嘛用的,csc是用来编译我们cs文件的应用程序,/t:library代表我们要将cs文件编译成dll,当然也能编译成exe之类的,之后跟上空格再加上所有需要编译的cs文件。再之后用/out:指定输出的名字
process.StandardInput.WriteLine($"csc /t:library {cs.ToString()} /out:{name}");
}
else
{
//使用了其他dll的情况下,其他的都跟上面相同。主要式添加了/r:,/r:后面跟上所有的dll,用","分割
process.StandardInput.WriteLine($"csc /r:{dll.ToString()} /t:library {cs.ToString()} /out:{name}");
} //所有命令都执行完毕了,接下来久给一个exit的命令退出控制台吧
process.StandardInput.WriteLine("exit");
//等待控制台关闭
process.WaitForExit();
//释放Process对象的所有资源
process.Close(); //执行事件,这里有个新语法,?.表示CompiledEndEvent不为null的情况下就出发CompiledEndEvent事件
CompiledEndEvent?.Invoke();
});
}
string vs_Path = vs_Path_textBox.Text + "\\Common7\\Tools\\VsMSBuildCmd.bat";
我们先说明一下VsMSBuildCmd.bat这个批处理文件吧,vs2013和vs2015我均已证实VsMSBuildCmd.bat所在路径是vs安装路径下的一指定路径下的,因此我这里久干脆拼接了一下字符串。如果低版本vs路径有所不同各位可以看着修改。VsMSBuildCmd.bat文件帮我们做了一些编译操作,不执行这个文件,而是直接执行.net目录下的csc.exe的话,我们是无法编译c#的一些新语法的。有一点各位要明白,c#版本和.net版本几乎没有太大关系,也不能说完全没关系,c#新版本的语法其实是编译器维护的,所以我们仅仅用csc.exe是无法识别那些新语法的。
再简单介绍一些async和await,这个是c#5.0增加的两个关键字,他让我们编写异步方法变得异常方法,通过上面的代码你也可以看到这个方法是可以混合异步和同步操作的,我们可以在方法中使用await等待一个费时的操作,在这个操作执行完毕后才会继续执行下面的方法,且不堵塞线程。仅仅只有Task.Run();中的方法是异步执行的,这样极大的方便了我们很多的操作。用法我已经告诉大家了,怎么去利用各自看着用吧。对了,别在Unity中使用,Unity中用的是c#4.0的语法和.Net2.0的版本,无法支持这两个关键字。
其他的没啥好讲的了,注释写的已经非常清楚了。我就给各位讲讲本代码中使用到的c#6.0的新语法吧。
首先是"$"运算符,这个运算符是为了简化string.Format();方法而被设计出来的,我给个$运算符和string.Format的例子一对比,你就会简单明了的明吧$干什么用的,怎么用了。
string a = "我", b = "是", c = "谁", d = "?";
string s = $"{a}到底{b}{c}呀{d}";
string s2 = string.Format("{0]到底{1}{2}呀{3}", a, b, c, d);
看着上面的例子,两种拼接字符串的方式,用$运算符可以降低我们不少工作量,而且阅读性也增加了。他们的输出结果自然也是相同的。
然后式?.运算符,中文名叫什么来着忘记了,不过也不用在意这种事。这个运算符依然是简化我们的工作用的,看下面的代码,这样很容易就能明白。
LL kk = null; //我们以前的写法
if (kk != null)
kk.S();
//而用?.运算符,这个运算符意思就是如果kk不为null的话就执行kk.S();跟上面那两行代码一个功能
kk?.S();
说到?.运算符了,就不得不提提??运算符,?.运算符表示不为null时执行,??运算符则表示为null时执行。看段代码:
LL kk = null; //我们以前的写法
if (kk == null)
kk = new LL();
//而用?.运算符
kk = kk ?? new LL();
好了,感谢阅读本篇博客,希望各位也能有所收获。Process类和ProcessStartInfo类还有很多功能,大家可以自己去多多研究研究,有机会的话我会在后续章节中为各位继续分享。
附上整个工程源码,工程是vs2015写成的WPF程序,使用了大量c#6.0的新语法,低版本的打开会提示大量的错误,vs2013貌似能正常编译,没试过,再低版本的都无法使用。不过只用将工程中的几个不兼容的小错误修改一下就能正常编译了。
如果你只是想要运行程序的话,直接在工程目录中的bin\Release目录下找到DLL编译器.exe即可拷贝走使用。
工程还有很多问题,比如无法获取编译结果,不会储存最近一次的操作信息登,这些问题我都会后续修复,并在此页面更新,每修改一版我都会写上版本。
1.0 beta版:http://files.cnblogs.com/files/menghuijinxi/DLL%E7%BC%96%E8%AF%91%E5%99%A8.zip
文章原创,欢迎转载,请标明出处。
关于.Net中Process的使用方法和各种用途汇总(二):用Process启动cmd.exe完成将cs编译成dll的更多相关文章
- 关于.Net中Process的使用方法和各种用途汇总(一):Process用法简介
简介: .Net中Process类功能十分强大.它可以接受程序路径启动程序,接受文件路径使用默认程序打开文件,接受超链接自动使用默认浏览器打开链接,或者打开指定文件夹等等功能. 想要使用Process ...
- Golang调用windows下的dll动态库中的函数 Golang 编译成 DLL 文件
Golang调用windows下的dll动态库中的函数 package main import ( "fmt" "syscall" "time&quo ...
- OC-私有方法,构造方法,类的本质及启动过程
总结 标号 主题 内容 一 OC的私有方法 私有变量/私有方法 二 @property 概念/基本使用/寻找方法的过程/查找顺序 三 @synthesize @synthesize概念/基本使用/注意 ...
- C#中WinForm程序退出方法技巧总结(转)
本文实例总结了C#中WinForm程序退出方法技巧.分享给大家供大家参考.具体分析如下: 在c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit ...
- asp.net中导出Excel的方法
一.asp.net中导出Excel的方法: 本文转载 在asp.net中导出Excel有两种方法,一种是将导出的文件存放在服务器某个文件夹下面,然后将文件地址输出在浏览器上:一种是将文件直接将文件输出 ...
- asp.net中导出Execl的方法
一.asp.net中导出Execl的方法: 在 asp.net中导出Execl有两种方法,一种是将导出的文件存放在服务器某个文件夹下面,然后将文件地址 输出在浏览器上:一种是将文件直接将文件输出流写给 ...
- 并发编程 process 模块的方法及运用 僵尸与孤儿
进程创建的两种方法 Process() 继承Process 重写run方法,传参数的时候要写init,但是注意要在init方法中运行父类的init方法 Windows下写代码开启子进程时,必须写上if ...
- 将NX模型导入Process Designer的方法
如何把一个有焊点的零件从nx中输入到process designer 中? 用户在NX中做了一个prt文件, 想把它输入到process designer中, 并且包括焊点信息, 该如何做? 解决 ...
- 我的Android进阶之旅------>android中service的onStartCommand()方法中intent为null的问题
今天在维护公司的一个APP的时候,突然爆了空指针异常, Caused by: java.lang.NullPointerException: Attempt to invoke virtual met ...
随机推荐
- unique函数(STL)
unique()函数是一个去重函数,STL中unique的函数 unique的功能是去除相邻的重复元素(只保留一个),还有一个容易忽视的特性是它并不真正把重复的元素删除.他是c++中的函数,所以头文件 ...
- axis2开发webservice之编写Axis2模块(Module)
axis2中的模块化开发.能够让开发者自由的加入自己所需的模块.提高开发效率,减少开发的难度. Axis2能够通过模块(Module)进行扩展. Axis2模块至少须要有两个类,这两个类分别实现了Mo ...
- 项目期复习总结1:背景图合并,hack,浏览器内核前缀,伪类after before
文件夹: 1.背景图合并和CSS Spirit 2.PS基本快捷键 3.hack技术基本书写,为什么不用? 4.内核前缀 5.伪类afterbefore 1.背景图合并和CSS Spirit 背景图合 ...
- [IT学习]跟阿铭学linux(第3版)
1.安装Linux在虚拟化平台上 Windows Vmware Workstation,需要在本机上打开CPU对虚拟化的支持.Virtualization Cent OS7 已成功安装. 2.http ...
- 授权QQ登录的qq端前端页面变迁
ac_type = 'qq' if ac_type == 'qq': myid, mypwd = qq_key xp = '/html/body/div/div/div[2]/div/div/div/ ...
- 如何快速定位JVM中消耗CPU最多的线程? Java 性能调优
https://mp.weixin.qq.com/s/ZqlhPC06_KW6a9OSgEuIVw 上面的线程栈我们注意到 nid 的值其实就是线程 ID,它是十六进制的,我们将消耗 CPU 最高的线 ...
- hashable
Glossary — Python 3.6.5 documentation https://docs.python.org/3/glossary.html?highlight=equal hashab ...
- kernel: audit: printk limit exceeded
问题: 小长假的第一天早上8:18一个数据,被定时任务中的脚本漏处理: 查定时任务的日志,发现调度异常 查var messages-20171231 日志信息,排查问题. http://man7.or ...
- apply current folder view to all folders
https://www.tenforums.com/tutorials/35093-apply-folder-view-all-folders-same-type-windows-10-a.html ...
- bzoj1566 [NOI2009]管道取珠——DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1566 一眼看上去很懵... 但是答案可以转化成有两个人在同时取珠子,他们取出来一样的方案数: ...