| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
| 2 | |
| 3 | using System; |
| 4 | using System.Collections.Generic; |
| 5 | using System.ComponentModel; |
| 6 | using System.Diagnostics; |
| 7 | using System.IO; |
| 8 | using System.Runtime.InteropServices; |
| 9 | using Microsoft.Win32; |
| 10 | |
| 11 | namespace TestExe |
| 12 | { |
| 13 | public abstract class Task |
| 14 | { |
| 15 | public string data; |
| 16 | |
| 17 | public Task(string Data) |
| 18 | { |
| 19 | this.data = Data; |
| 20 | } |
| 21 | |
| 22 | public abstract void RunTask(); |
| 23 | |
| 24 | } |
| 25 | |
| 26 | public class ExitCodeTask : Task |
| 27 | { |
| 28 | public ExitCodeTask(string Data) : base(Data) { } |
| 29 | |
| 30 | public override void RunTask() |
| 31 | { |
| 32 | // this task does nothing. Just stores data about what exit code to return. |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | public class SleepTask : Task |
| 37 | { |
| 38 | public SleepTask(string Data) : base(Data) { } |
| 39 | |
| 40 | public override void RunTask() |
| 41 | { |
| 42 | int milliseconds = int.Parse(this.data); |
| 43 | Console.WriteLine("Starting to sleep for {0} milliseconds", milliseconds); |
| 44 | System.Threading.Thread.Sleep(milliseconds); |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | public class SleepRandomTask : Task |
| 49 | { |
| 50 | public SleepRandomTask(string Data) : base(Data) { } |
| 51 | |
| 52 | public override void RunTask() |
| 53 | { |
| 54 | int low = int.Parse(this.data.Split(new string[] { ":" }, 2, StringSplitOptions.None)[0]); |
| 55 | int high = int.Parse(this.data.Split(new string[] { ":" }, 2, StringSplitOptions.None)[1]); |
| 56 | |
| 57 | Random r = new Random(); |
| 58 | int milliseconds = r.Next(high - low) + low; |
| 59 | Console.WriteLine("Starting to sleep for {0} milliseconds", milliseconds); |
| 60 | System.Threading.Thread.Sleep(milliseconds); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | public class GenerateFilesTask : Task |
| 65 | { |
| 66 | public GenerateFilesTask(string Data) : base(Data) { } |
| 67 | |
| 68 | public override void RunTask() |
| 69 | { |
| 70 | string[] tokens = this.data.Split(new char[] { '|' }, 2); |
| 71 | string folderPath = System.Environment.ExpandEnvironmentVariables(tokens[0]); |
| 72 | long size = long.Parse(tokens[1]); |
| 73 | Directory.CreateDirectory(folderPath); |
| 74 | var bytes = new byte[0]; |
| 75 | for (long i = 1; i <= size; i++) |
| 76 | { |
| 77 | File.WriteAllBytes(Path.Combine(folderPath, $"{i}.txt"), bytes); |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | public class LargeFileTask : Task |
| 83 | { |
| 84 | public LargeFileTask(string Data) : base(Data) { } |
| 85 | |
| 86 | public override void RunTask() |
| 87 | { |
| 88 | string[] tokens = this.data.Split(new char[] { '|' }, 2); |
| 89 | string filePath = System.Environment.ExpandEnvironmentVariables(tokens[0]); |
| 90 | long size = long.Parse(tokens[1]); |
| 91 | using (var stream = File.Create(filePath)) |
| 92 | { |
| 93 | stream.Seek(size - 1, SeekOrigin.Begin); |
| 94 | stream.WriteByte(1); |
| 95 | } |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | public class LogTask : Task |
| 100 | { |
| 101 | string[] argsUsed; |
| 102 | public LogTask(string Data, string[] args) |
| 103 | : base(Data) |
| 104 | { |
| 105 | this.argsUsed = args; |
| 106 | } |
| 107 | |
| 108 | public override void RunTask() |
| 109 | { |
| 110 | string logFile = ""; |
| 111 | string argsUsedString = ""; |
| 112 | |
| 113 | foreach (string a in this.argsUsed) |
| 114 | { |
| 115 | argsUsedString += a + " "; |
| 116 | } |
| 117 | |
| 118 | try |
| 119 | { |
| 120 | logFile = System.Environment.ExpandEnvironmentVariables(this.data); |
| 121 | Console.WriteLine("creating log file: " + logFile); |
| 122 | StreamWriter textFile = File.CreateText(logFile); |
| 123 | textFile.WriteLine("This is a log file created by TestExe.exe"); |
| 124 | textFile.WriteLine("Args used: " + argsUsedString); |
| 125 | textFile.Close(); |
| 126 | } |
| 127 | catch |
| 128 | { |
| 129 | Console.WriteLine("creating a log file failed for: {0}", logFile); |
| 130 | } |
| 131 | |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | public class FileExistsTask : Task |
| 136 | { |
| 137 | public FileExistsTask(string Data) : base(Data) { } |
| 138 | |
| 139 | public override void RunTask() |
| 140 | { |
| 141 | string fileToExist = System.Environment.ExpandEnvironmentVariables(this.data); |
| 142 | |
| 143 | if (!String.IsNullOrEmpty(fileToExist)) |
| 144 | { |
| 145 | Console.WriteLine("Waiting for this file to exist: \"" + fileToExist + "\""); |
| 146 | while (!System.IO.File.Exists(fileToExist)) |
| 147 | { |
| 148 | System.Threading.Thread.Sleep(250); |
| 149 | } |
| 150 | Console.WriteLine("Found: \"" + fileToExist + "\""); |
| 151 | } |
| 152 | |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | public class DeleteManifestsTask : Task |
| 157 | { |
| 158 | public DeleteManifestsTask(string Data) : base(Data) { } |
| 159 | |
| 160 | public override void RunTask() |
| 161 | { |
| 162 | string filePath = System.Environment.ExpandEnvironmentVariables(this.data); |
| 163 | IntPtr type = new IntPtr(24); //RT_MANIFEST |
| 164 | IntPtr name = new IntPtr(1); //CREATEPROCESS_MANIFEST_RESOURCE_ID |
| 165 | DeleteResource(filePath, type, name, 1033); |
| 166 | } |
| 167 | |
| 168 | private static void DeleteResource(string filePath, IntPtr type, IntPtr name, ushort language, bool throwOnError = false) |
| 169 | { |
| 170 | bool discard = true; |
| 171 | IntPtr handle = BeginUpdateResourceW(filePath, false); |
| 172 | try |
| 173 | { |
| 174 | if (handle == IntPtr.Zero) |
| 175 | { |
| 176 | throw new Win32Exception(); |
| 177 | } |
| 178 | |
| 179 | if (!UpdateResourceW(handle, type, name, language, IntPtr.Zero, 0)) |
| 180 | { |
| 181 | throw new Win32Exception(); |
| 182 | } |
| 183 | |
| 184 | discard = false; |
| 185 | } |
| 186 | catch |
| 187 | { |
| 188 | if (throwOnError) |
| 189 | { |
| 190 | throw; |
| 191 | } |
| 192 | } |
| 193 | finally |
| 194 | { |
| 195 | if (handle != IntPtr.Zero) |
| 196 | { |
| 197 | if (!EndUpdateResourceW(handle, discard) && throwOnError) |
| 198 | { |
| 199 | throw new Win32Exception(); |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] |
| 206 | private extern static IntPtr BeginUpdateResourceW(string fileName, [MarshalAs(UnmanagedType.Bool)] bool deleteExistingResources); |
| 207 | |
| 208 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] |
| 209 | [return: MarshalAs(UnmanagedType.Bool)] |
| 210 | private extern static bool UpdateResourceW(IntPtr hUpdate, IntPtr type, IntPtr name, ushort language, IntPtr pData, uint cb); |
| 211 | |
| 212 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] |
| 213 | [return: MarshalAs(UnmanagedType.Bool)] |
| 214 | private extern static bool EndUpdateResourceW(IntPtr hUpdate, [MarshalAs(UnmanagedType.Bool)] bool discard); |
| 215 | } |
| 216 | |
| 217 | public class TaskParser |
| 218 | { |
| 219 | |
| 220 | public static List<Task> ParseTasks(string[] args) |
| 221 | { |
| 222 | List<Task> tasks = new List<Task>(); |
| 223 | |
| 224 | try |
| 225 | { |
| 226 | // for invalid args. return empty list |
| 227 | if (args.Length % 2 == 0) |
| 228 | { |
| 229 | Task t; |
| 230 | |
| 231 | for (int i = 0; i < args.Length; i += 2) |
| 232 | { |
| 233 | switch (args[i].ToLower()) |
| 234 | { |
| 235 | case "/ec": |
| 236 | t = new ExitCodeTask(args[i + 1]); |
| 237 | tasks.Add(t); |
| 238 | break; |
| 239 | case "/s": |
| 240 | t = new SleepTask(args[i + 1]); |
| 241 | tasks.Add(t); |
| 242 | break; |
| 243 | case "/sr": |
| 244 | t = new SleepRandomTask(args[i + 1]); |
| 245 | tasks.Add(t); |
| 246 | break; |
| 247 | case "/gf": |
| 248 | t = new GenerateFilesTask(args[i + 1]); |
| 249 | tasks.Add(t); |
| 250 | break; |
| 251 | case "/lf": |
| 252 | t = new LargeFileTask(args[i + 1]); |
| 253 | tasks.Add(t); |
| 254 | break; |
| 255 | case "/log": |
| 256 | t = new LogTask(args[i + 1], args); |
| 257 | tasks.Add(t); |
| 258 | break; |
| 259 | case "/fe": |
| 260 | t = new FileExistsTask(args[i + 1]); |
| 261 | tasks.Add(t); |
| 262 | break; |
| 263 | case "/dm": |
| 264 | t = new DeleteManifestsTask(args[i + 1]); |
| 265 | tasks.Add(t); |
| 266 | break; |
| 267 | #if NETFRAMEWORK |
| 268 | case "/pinfo": |
| 269 | t = new ProcessInfoTask(args[i + 1]); |
| 270 | tasks.Add(t); |
| 271 | break; |
| 272 | case "/regw": |
| 273 | t = new RegistryWriterTask(args[i + 1]); |
| 274 | tasks.Add(t); |
| 275 | break; |
| 276 | case "/regd": |
| 277 | t = new RegistryDeleterTask(args[i + 1]); |
| 278 | tasks.Add(t); |
| 279 | break; |
| 280 | #endif |
| 281 | |
| 282 | default: |
| 283 | Console.WriteLine("Error: Invalid switch specified."); |
| 284 | return new List<Task>(); |
| 285 | } |
| 286 | } |
| 287 | } |
| 288 | } |
| 289 | catch |
| 290 | { |
| 291 | Console.WriteLine("Error: Invalid switch data specified. Couldn't parse the data."); |
| 292 | return new List<Task>(); |
| 293 | } |
| 294 | |
| 295 | return tasks; |
| 296 | } |
| 297 | } |
| 298 | } |