Excuter.exe 动态编译执行器,可执行任意逻辑,实现源码与工具的分离。
    源码:

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Windows.Forms;
    4. using System.Threading.Tasks;
    5. using System.IO;
    6. using System.Reflection;
    7. using System.Text;
    8. using System.CodeDom.Compiler;
    9. using Microsoft.CSharp;
    10. namespace Excuter
    11. {
    12. static class Program
    13. {
    14. public static bool isDebug = false;
    15. public static int delayMillionSecond = 0;
    16. public static string sourceCode = "";
    17. public static object[] sourceArgs = null;
    18. public static bool autoDelet = false;
    19. /// <summary>
    20. /// 应用程序的主入口点。可直接传入源码、或源码文件路径。DEBUG标识是否输出运行信息。DELAY标识延时毫秒时间值。AUTODELET是否自删除。
    21. /// </summary>
    22. [STAThread]
    23. static void Main(string[] args)
    24. {
    25. Application.EnableVisualStyles();
    26. Application.SetCompatibleTextRenderingDefault(false);
    27. //Application.Run(new Form1());
    28. //if (args == null || args.Length == 0) args = new string[] { @"F:\sc\桌面快捷存储\tmp\Test.cs" };
    29. //string source = @"D:\sci\Visual Studio 2008\Projects\ClearDir\ClearDir\Resources\ClearTool.txt";
    30. //string source = @"D:\sci\Visual Studio 2008\Projects\ClearDir\ClearDir\bin\Debug\Code.txt";
    31. //if (args == null || args.Length == 0) args = new string[] { source, @"F:\sc\桌面快捷存储\tmp\新建文本文档.txt" };
    32. if (args !=null && args.Length > 0)
    33. {
    34. // 判断参数中是否含有DEBUG
    35. List<string> arglist = new List<string>();
    36. foreach (string arg in args)
    37. {
    38. if (arg.Equals("DEBUG")) isDebug = true;
    39. else if (arg.Equals("AUTODELET")) autoDelet = true;
    40. else if (arg.StartsWith("DELAY")) delayMillionSecond = int.Parse(arg.Substring("DELAY".Length));
    41. else arglist.Add(arg);
    42. }
    43. args = arglist.ToArray();
    44. // 其他参数作为执行参数
    45. string[] Arg = null;
    46. if (args.Length > 1)
    47. {
    48. Arg = new string[args.Length - 1];
    49. for (int i = 1; i < args.Length; i++)
    50. {
    51. Arg[i - 1] = args[i];
    52. }
    53. }
    54. sourceCode = args[0];
    55. sourceArgs = new object[] { Arg };
    56. ExcuteProcess(); // 执行逻辑
    57. Application.Run(); // 在当前线程上运行应用程序消息循环
    58. }
    59. else if (autoDelet) AutoDelet.deletItself();
    60. }
    61. /// <summary>
    62. /// 根据param中的参数控制截屏
    63. /// </summary>
    64. public static void ExcuteProcess()
    65. {
    66. if (delayMillionSecond > 0)
    67. {
    68. Timer timer = new Timer();
    69. timer.Interval = delayMillionSecond;
    70. timer.Tick += Timer_Tick;
    71. delayMillionSecond = 0;
    72. timer.Enabled = true;
    73. }
    74. else
    75. {
    76. // 第一个参数作为源码或源码文件
    77. object result = "";
    78. if (File.Exists(sourceCode)) result = Excute.RunFileFirst(sourceCode, sourceArgs);
    79. else result = Excute.RunSourceCodeFirst(sourceCode, sourceArgs);
    80. if (isDebug && result != null) MessageBox.Show(sourceCode + "\r\n" + result.ToString());
    81. if (autoDelet) AutoDelet.deletItself();
    82. exit();
    83. }
    84. }
    85. /// <summary>
    86. /// 延时截屏处理逻辑
    87. /// </summary>
    88. private static void Timer_Tick(object sender, EventArgs e)
    89. {
    90. ((Timer)sender).Stop(); // 停止计时
    91. ExcuteProcess(); // 执行逻辑
    92. }
    93. /// <summary>
    94. /// 调用系统退出
    95. /// </summary>
    96. public static void exit()
    97. {
    98. //Application.Exit();
    99. //Application.ExitThread();
    100. System.Environment.Exit(0);
    101. }
    102. }
    103. /// <summary>
    104. /// 动态编译执行
    105. /// </summary>
    106. public class Excute
    107. {
    108. # region 动态编译源码并执行
    109. /// <summary>
    110. /// 解析并编译执行源码文件sourceFile,第一个类的首个公用或静态方法
    111. /// </summary>
    112. public static object RunFileFirst(string sourceFile, object[] args = null)
    113. {
    114. try
    115. {
    116. string sourceCode = fileToString(sourceFile); // 读取文件内容
    117. return RunSourceCodeFirst(sourceCode, args); // 执行
    118. }
    119. catch (Exception ex)
    120. {
    121. return ex.ToString();
    122. }
    123. }
    124. /// <summary>
    125. /// 解析并编译执行sourceCode,第一个类的首个公用或静态方法
    126. /// </summary>
    127. public static object RunSourceCodeFirst(string sourceCode, object[] args = null)
    128. {
    129. try
    130. {
    131. sourceCode = Encoder.Decode(sourceCode); // 解析源码
    132. string[] assemblies = getUsing(sourceCode).ToArray(); // 获取引用程序集
    133. string methodName = getFirstPublicMethod(sourceCode); // 获取方法名
    134. bool isStatic = isPublicStaticMethod(sourceCode, methodName); // 判断是否为静态方法
    135. return Run(sourceCode, "", methodName, args, isStatic, assemblies); // 执行
    136. }
    137. catch (Exception ex)
    138. {
    139. return ex.ToString();
    140. }
    141. }
    142. /// <summary>
    143. /// 动态编译执行
    144. /// </summary>
    145. /// <param name="sourceCode">源码</param>
    146. /// <param name="classFullName">命名空间.类</param>
    147. /// <param name="methodName">方法名</param>
    148. /// <param name="args">方法参数</param>
    149. /// <param name="assemblies">引用程序集</param>
    150. /// <param name="isStaticMethod">是否为静态方法</param>
    151. static object Run(string sourceCode, string classFullName, string methodName, object[] args = null, bool isStaticMethod = false, string[] assemblies = null)
    152. {
    153. try
    154. {
    155. // 设置编译参数 System.Xml.dll
    156. CompilerParameters param = new CompilerParameters();
    157. param.GenerateExecutable = false;
    158. param.GenerateInMemory = true;
    159. // 添加常用的默认程序集
    160. param.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
    161. param.ReferencedAssemblies.Add("mscorlib.dll");
    162. param.ReferencedAssemblies.Add("System.dll");
    163. param.ReferencedAssemblies.Add("System.Core.dll");
    164. param.ReferencedAssemblies.Add("System.Data.dll");
    165. param.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
    166. param.ReferencedAssemblies.Add("System.Drawing.dll");
    167. param.ReferencedAssemblies.Add("System.Windows.Forms.dll");
    168. param.ReferencedAssemblies.Add("System.Xml.dll");
    169. param.ReferencedAssemblies.Add("System.Xml.Linq.dll");
    170. if (assemblies != null)
    171. {
    172. foreach (string name in assemblies)
    173. {
    174. string assembly = name + ".dll";
    175. if (!param.ReferencedAssemblies.Contains(assembly))
    176. {
    177. param.ReferencedAssemblies.Add(assembly);
    178. }
    179. }
    180. }
    181. // 动态编译字符串代码
    182. CompilerResults result = new CSharpCodeProvider().CompileAssemblyFromSource(param, sourceCode);
    183. if (result.Errors.HasErrors)
    184. {
    185. // 编译出错:
    186. StringBuilder str = new StringBuilder();
    187. foreach (CompilerError err in result.Errors)
    188. {
    189. str.AppendLine(err.ErrorText);
    190. }
    191. return str.ToString();
    192. }
    193. else
    194. {
    195. // 编译通过:
    196. Assembly assembly = result.CompiledAssembly; // 获取已编译通过的程序集
    197. if (classFullName == null || classFullName.Equals("")) // 若未指定,则获取程序集第一个类路径名
    198. {
    199. classFullName = assembly.GetTypes()[0].FullName;
    200. }
    201. if (isStaticMethod)
    202. {
    203. // 调用程序集的静态方法: Type.InvokeMember
    204. Type type = assembly.GetType(classFullName, true, true);
    205. //object[] arg = new object[] { "参数1", "参数2" };
    206. object tmp = type.InvokeMember(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, args);
    207. return tmp;
    208. }
    209. else
    210. {
    211. // 调用程序集类实例方法: method.Invoke
    212. object obj = assembly.CreateInstance(classFullName); // 创建一个类实例对象
    213. MethodInfo method = obj.GetType().GetMethod(methodName);// 获取对象的对应方法
    214. object tmp = method.Invoke(obj, args); // 调用对象的方法
    215. return tmp;
    216. }
    217. }
    218. }
    219. catch (Exception ex)
    220. {
    221. return ex.ToString();
    222. }
    223. }
    224. # endregion
    225. # region 相关功能函数
    226. /// <summary>
    227. /// 获取文件中的数据,自动判定编码格式
    228. /// </summary>
    229. private static string fileToString(String filePath)
    230. {
    231. string str = "";
    232. //获取文件内容
    233. if (File.Exists(filePath))
    234. {
    235. StreamReader file1;
    236. file1 = new StreamReader(filePath, Encoding.UTF8); // 读取文件中的数据
    237. str = file1.ReadToEnd(); // 读取文件中的全部数据
    238. file1.Close();
    239. file1.Dispose();
    240. }
    241. return str;
    242. }
    243. /// <summary>
    244. /// 获取第一个公用方法
    245. /// </summary>
    246. /// <param name="sourceCode"></param>
    247. /// <returns></returns>
    248. private static string getFirstPublicMethod(string sourceCode)
    249. {
    250. string methodName = "";
    251. String[] lines = sourceCode.Replace("\r\n", "\n").Split('\n');
    252. foreach (string iteam in lines)
    253. {
    254. string line = iteam.Trim();
    255. if (line.StartsWith("public ") && line.Contains("(") && line.Contains(")"))
    256. {
    257. methodName = line.Substring(0, line.IndexOf("("));
    258. methodName = methodName.Substring(methodName.LastIndexOf(" ") + 1);
    259. break;
    260. }
    261. }
    262. return methodName;
    263. }
    264. /// <summary>
    265. /// 判断指定的方法是否为静态方法
    266. /// </summary>
    267. /// <returns></returns>
    268. private static bool isPublicStaticMethod(string sourceCode, string methodName)
    269. {
    270. bool isStatic = false;
    271. String[] lines = sourceCode.Replace("\r\n", "\n").Split('\n');
    272. foreach (string iteam in lines)
    273. {
    274. string line = iteam.Trim();
    275. if (line.StartsWith("public ") && line.Contains(" " + methodName) && line.Contains("(") && line.Contains(")") && line.Contains("static"))
    276. {
    277. isStatic = true;
    278. }
    279. }
    280. return isStatic;
    281. }
    282. /// <summary>
    283. /// 获取应用的程序集信息
    284. /// </summary>
    285. private static List<string> getUsing(string sourceCode)
    286. {
    287. String[] lines = sourceCode.Replace("\r\n", "\n").Split('\n');
    288. List<string> usings = new List<string>();
    289. foreach (string iteam in lines)
    290. {
    291. string line = iteam.Trim();
    292. if (line.StartsWith("using ") && line.EndsWith(";"))
    293. {
    294. string usingAssembley = line.TrimEnd(';').Substring("using ".Length);
    295. CheckAddAssembly(usings, usingAssembley);
    296. }
    297. }
    298. return usings;
    299. }
    300. /// <summary>
    301. /// 检测添加较短长度的Assembly名称
    302. /// </summary>
    303. private static void CheckAddAssembly(List<string> usings, string usingAssembley)
    304. {
    305. if (usings.Contains(usingAssembley)) return;
    306. for (int i = 0; i < usings.Count; i++)
    307. {
    308. string name = usings[i];
    309. if (usingAssembley.StartsWith(name + ".")) return;
    310. else if (name.StartsWith(usingAssembley + "."))
    311. {
    312. usings[i] = usingAssembley;
    313. }
    314. }
    315. usings.Add(usingAssembley);
    316. }
    317. # endregion
    318. }
    319. public class Encoder
    320. {
    321. public static void example()
    322. {
    323. String data = "test encode";
    324. string encode = Encode(data);
    325. string decode = Decode(encode);
    326. bool b = data.Equals(decode);
    327. bool b2 = b;
    328. }
    329. /// <summary>
    330. /// 转码data为全字母串,并添加前缀
    331. /// </summary>
    332. public static string Encode(string data)
    333. {
    334. string str = data;
    335. if (!data.StartsWith("ALPHABETCODE@"))
    336. {
    337. str = "ALPHABETCODE@" + EncodeAlphabet(data);
    338. }
    339. return str;
    340. }
    341. /// <summary>
    342. /// 解析字母串为原有串
    343. /// </summary>
    344. public static string Decode(string data)
    345. {
    346. string str = data;
    347. if (data.StartsWith("ALPHABETCODE@"))
    348. {
    349. str = DecodeAlphabet(data.Substring("ALPHABETCODE@".Length));
    350. }
    351. return str;
    352. }
    353. # region 字符串字母编码逻辑
    354. /// <summary>
    355. /// 转化为字母字符串
    356. /// </summary>
    357. public static string EncodeAlphabet(string data)
    358. {
    359. byte[] B = Encoding.UTF8.GetBytes(data);
    360. return ToStr(B);
    361. }
    362. /// <summary>
    363. /// 每个字节转化为两个字母
    364. /// </summary>
    365. private static string ToStr(byte[] B)
    366. {
    367. StringBuilder Str = new StringBuilder();
    368. foreach (byte b in B)
    369. {
    370. Str.Append(ToStr(b));
    371. }
    372. return Str.ToString();
    373. }
    374. private static string ToStr(byte b)
    375. {
    376. return "" + ToChar(b / 16) + ToChar(b % 16);
    377. }
    378. private static char ToChar(int n)
    379. {
    380. return (char)('a' + n);
    381. }
    382. /// <summary>
    383. /// 解析字母字符串
    384. /// </summary>
    385. public static string DecodeAlphabet(string data)
    386. {
    387. byte[] B = new byte[data.Length / 2];
    388. char[] C = data.ToCharArray();
    389. for (int i = 0; i < C.Length; i += 2)
    390. {
    391. byte b = ToByte(C[i], C[i + 1]);
    392. B[i / 2] = b;
    393. }
    394. return Encoding.UTF8.GetString(B);
    395. }
    396. /// <summary>
    397. /// 每两个字母还原为一个字节
    398. /// </summary>
    399. private static byte ToByte(char a1, char a2)
    400. {
    401. return (byte)((a1 - 'a') * 16 + (a2 - 'a'));
    402. }
    403. # endregion
    404. }
    405. public class AutoDelet
    406. {
    407. /// <summary>
    408. /// 应用自删除
    409. /// </summary>
    410. public static void deletItself()
    411. {
    412. try
    413. {
    414. string curExe = System.Windows.Forms.Application.ExecutablePath;
    415. string tmpName = AppDomain.CurrentDomain.BaseDirectory + "$";
    416. string name1 = "$";
    417. while (File.Exists(tmpName))
    418. {
    419. tmpName = tmpName + "$";
    420. name1 = name1 + "$";
    421. }
    422. File.Move(curExe, tmpName); // 重命名当前文件
    423. string vbsName = AppDomain.CurrentDomain.BaseDirectory + "$";
    424. string name2 = "$";
    425. while (File.Exists(vbsName + ".vbs"))
    426. {
    427. vbsName = vbsName + "$";
    428. name2 = name2 + "$";
    429. }
    430. //Set ws = CreateObject("Wscript.Shell")
    431. //WScript.sleep 5000
    432. //ws.run "cmd /c ?> $",vbhide
    433. //ws.run "cmd /c del $",vbhide
    434. //ws.run "cmd /c ?> $.vbs",vbhide
    435. //ws.run "cmd /c del $.vbs",vbhide
    436. StringBuilder Str = new StringBuilder();
    437. Str.AppendLine("Set ws = CreateObject(\"Wscript.Shell\")");
    438. Str.AppendLine("WScript.sleep 4000");
    439. Str.AppendLine("ws.run \"cmd /c ?> " + name1 + "\",vbhide");
    440. Str.AppendLine("ws.run \"cmd /c del " + name1 + "\",vbhide");
    441. Str.AppendLine("ws.run \"cmd /c ?> " + name2 + ".vbs\",vbhide");
    442. Str.AppendLine("ws.run \"cmd /c del " + name2 + ".vbs\",vbhide");
    443. string data = Str.ToString();
    444. SaveFile(data, vbsName + ".vbs");
    445. System.Diagnostics.Process.Start(vbsName + ".vbs");
    446. System.Environment.Exit(0); //退出
    447. }
    448. catch (Exception) { }
    449. }
    450. /// <summary>
    451. /// 保存数据data到文件处理过程,返回值为保存的文件名
    452. /// </summary>
    453. private static String SaveFile(String data, String filePath)
    454. {
    455. System.IO.StreamWriter file1 = new System.IO.StreamWriter(filePath, false, Encoding.Default); //文件已覆盖方式添加内容
    456. file1.Write(data); //保存数据到文件
    457. file1.Close(); //关闭文件
    458. file1.Dispose(); //释放对象
    459. return filePath;
    460. }
    461. }
    462. }

    ————————————————
    版权声明:本文为CSDN博主「scimence」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/scimence/article/details/76981225