/// <summary> /// Reads a material for the given surface and its associated images /// </summary> public static WavefrontOBJ.Material ReadMaterial(ProcessReader reader, long address) { // Read Material var material = reader.ReadStruct <Material>(address); // Create new OBJ Image var objMaterial = new WavefrontOBJ.Material(Path.GetFileNameWithoutExtension(reader.ReadNullTerminatedString(reader.ReadInt64(address)).Replace("*", ""))); // Loop over images for (byte i = 0; i < material.ImageCount; i++) { // Read Material Image var materialImage = reader.ReadStruct <MaterialImage64A>(material.ImageTablePointer + i * Marshal.SizeOf <MaterialImage64A>()); // Check for color map for now if (materialImage.SemanticHash == 0xA0AB1041) { objMaterial.DiffuseMap = "_images\\\\" + reader.ReadNullTerminatedString(reader.ReadInt64(materialImage.ImagePointer + 96)) + ".png"; } } // Done return(objMaterial); }
/// <summary> /// Runs a command /// </summary> /// <param name="command">The command to run</param> /// <param name="args">Arguments to the command</param> /// <returns>The output from the command</returns> public string RunCommand(string command, string args) { Process proc = new Process(); proc.StartInfo.FileName = command; proc.StartInfo.Arguments = args; proc.StartInfo.CreateNoWindow = true; proc.StartInfo.RedirectStandardOutput = true; proc.StartInfo.RedirectStandardError = true; proc.StartInfo.UseShellExecute = false; proc.Start(); //Console.WriteLine( proc.MainModule.FileName ); ProcessReader outreader = new ProcessReader(proc.StandardOutput); ProcessReader errreader = new ProcessReader(proc.StandardError); outreader.Start(); errreader.Start(); proc.WaitForExit(); outreader.Wait(); errreader.Wait(); if (proc.ExitCode != 0) { throw new ApplicationException("command exit code was " + proc.ExitCode.ToString() + Environment.NewLine + errreader.Output + Environment.NewLine + "Command was " + proc.StartInfo.FileName + " " + proc.StartInfo.Arguments); } // normalize newlines string[] lines = Regex.Split(outreader.Output, @"\r?\n"); return(String.Join(Environment.NewLine, lines)); }
/// <summary> /// Reads Static Models /// </summary> public unsafe static List <IWMap.Entity> ReadStaticModels(ProcessReader reader, long address, int count) { // Resulting Entities List <IWMap.Entity> entities = new List <IWMap.Entity>(count); // Read buffer var byteBuffer = reader.ReadBytes(address, count * Marshal.SizeOf <GfxStaticModel>()); // Loop number of models we have for (int i = 0; i < count; i++) { // Read Struct var staticModel = ByteUtil.BytesToStruct <GfxStaticModel>(byteBuffer, i * Marshal.SizeOf <GfxStaticModel>()); // Model Name var modelName = reader.ReadNullTerminatedString(reader.ReadInt32(staticModel.ModelPointer)); // New Matrix var matrix = new Rotation.Matrix(); // Copy X Values matrix.Values[0] = staticModel.Matrix[0]; matrix.Values[1] = staticModel.Matrix[1]; matrix.Values[2] = staticModel.Matrix[2]; // Copy Y Values matrix.Values[4] = staticModel.Matrix[3]; matrix.Values[5] = staticModel.Matrix[4]; matrix.Values[6] = staticModel.Matrix[5]; // Copy Z Values matrix.Values[8] = staticModel.Matrix[6]; matrix.Values[9] = staticModel.Matrix[7]; matrix.Values[10] = staticModel.Matrix[8]; // Convert to Euler var euler = matrix.ToEuler(); // Add it entities.Add(IWMap.Entity.CreateMiscModel(modelName, new Vector3(staticModel.X, staticModel.Y, staticModel.Z), Rotation.ToDegrees(euler), staticModel.ModelScale)); } // Done return(entities); }
/// <summary> /// Reads BSP Data /// </summary> public static void ExportBSPData(ProcessReader reader, long assetPoolsAddress, long assetSizesAddress, string gameType, Action <object> printCallback = null) { // Found her printCallback?.Invoke("Found supported game: Call of Duty: Black Ops"); // Get XModel Name var firstXModelName = reader.ReadNullTerminatedString(reader.ReadInt32(reader.ReadInt32(assetPoolsAddress + 0x14) + 4)); // Validate by XModel Name if (firstXModelName == "void" || firstXModelName == "defaultactor" || firstXModelName == "defaultweapon") { // Load BSP Pools (they only have a size of 1 so we have no free header) var gfxMapAsset = reader.ReadStruct <GfxMap>(reader.ReadInt32(assetPoolsAddress + 0x44)); // Name string gfxMapName = reader.ReadNullTerminatedString(gfxMapAsset.NamePointer); string mapName = reader.ReadNullTerminatedString(gfxMapAsset.MapNamePointer); // Verify a BSP is actually loaded (if in base menu, etc, no map is loaded) if (String.IsNullOrWhiteSpace(gfxMapName)) { printCallback?.Invoke("No BSP loaded. Enter Main Menu or a Map to load in the required assets."); } else { // New IW Map var mapFile = new IWMap(); // Print Info printCallback?.Invoke(String.Format("\n--------------------------\n")); printCallback?.Invoke(String.Format("Loaded Gfx Map - {0}", gfxMapName)); printCallback?.Invoke(String.Format("Loaded Map - {0}", mapName)); printCallback?.Invoke(String.Format("Vertex Count - {0}", gfxMapAsset.GfxVertexCount)); printCallback?.Invoke(String.Format("Indices Count - {0}", gfxMapAsset.GfxIndicesCount)); printCallback?.Invoke(String.Format("Surface Count - {0}", gfxMapAsset.SurfaceCount)); printCallback?.Invoke(String.Format("Model Count - {0}", gfxMapAsset.GfxStaticModelsCount)); // Build output Folder string outputName = Path.Combine("exported_maps", "black_ops", gameType, mapName, mapName); Directory.CreateDirectory(Path.GetDirectoryName(outputName)); // Stop watch var stopWatch = Stopwatch.StartNew(); // Read Vertices printCallback?.Invoke("Parsing vertex data...."); var vertices = ReadGfxVertices(reader, gfxMapAsset.GfxVerticesPointer, gfxMapAsset.GfxVertexCount); printCallback?.Invoke(String.Format("Parsed vertex data in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Read Indices printCallback?.Invoke("Parsing surface indices...."); var indices = ReadGfxIndices(reader, gfxMapAsset.GfxIndicesPointer, gfxMapAsset.GfxIndicesCount); printCallback?.Invoke(String.Format("Parsed indices in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Read Indices printCallback?.Invoke("Parsing surfaces...."); var surfaces = ReadGfxSufaces(reader, gfxMapAsset.GfxSurfacesPointer, gfxMapAsset.SurfaceCount); printCallback?.Invoke(String.Format("Parsed surfaces in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Write OBJ printCallback?.Invoke("Generating map files..."); // Create new OBJ var obj = new WavefrontOBJ(); // Append Vertex Data foreach (var vertex in vertices) { obj.Vertices.Add(vertex.Position); obj.Normals.Add(vertex.Normal); obj.UVs.Add(vertex.UV); } // Image Names (for Search String) HashSet <string> imageNames = new HashSet <string>(); // Append Faces foreach (var surface in surfaces) { // Create new Material var material = ReadMaterial(reader, surface.MaterialPointer); // Add to images imageNames.Add(material.DiffuseMap); // Add it obj.AddMaterial(material); // Add points for (ushort i = 0; i < surface.FaceCount; i++) { // Face Indices var faceIndex1 = indices[i * 3 + surface.FaceIndex] + surface.VertexIndex; var faceIndex2 = indices[i * 3 + surface.FaceIndex + 1] + surface.VertexIndex; var faceIndex3 = indices[i * 3 + surface.FaceIndex + 2] + surface.VertexIndex; // Validate unique points, and write to OBJ if (faceIndex1 != faceIndex2 && faceIndex1 != faceIndex3 && faceIndex2 != faceIndex3) { // new Obj Face var objFace = new WavefrontOBJ.Face(material.Name); // Add points objFace.Vertices[0] = new WavefrontOBJ.Face.Vertex(faceIndex1, faceIndex1, faceIndex1); objFace.Vertices[2] = new WavefrontOBJ.Face.Vertex(faceIndex2, faceIndex2, faceIndex2); objFace.Vertices[1] = new WavefrontOBJ.Face.Vertex(faceIndex3, faceIndex3, faceIndex3); // Add to OBJ obj.Faces.Add(objFace); } } } // Save it obj.Save(outputName + ".obj"); // Build search strinmg string searchString = ""; // Loop through images, and append each to the search string (for Wraith/Greyhound) foreach (string imageName in imageNames) { searchString += String.Format("{0},", Path.GetFileNameWithoutExtension(imageName)); } // Create .JSON with XModel Data List <IDictionary> ModelData = CreateXModelDictionary(reader, gfxMapAsset.GfxStaticModelsPointer, (int)gfxMapAsset.GfxStaticModelsCount); string xmodeljson = JToken.FromObject(ModelData).ToString(Formatting.Indented); File.WriteAllText(outputName + "_xmodels.json", xmodeljson); // Loop through xmodels, and append each to the search string (for Wraith/Greyhound) List <string> xmodelList = CreateXModelList(ModelData); // Dump it File.WriteAllText(outputName + "_search_string.txt", searchString); File.WriteAllText(outputName + "_xmodelList.txt", String.Join(",", xmodelList.ToArray())); // Read entities and dump to map mapFile.Entities.AddRange(ReadStaticModels(reader, gfxMapAsset.GfxStaticModelsPointer, (int)gfxMapAsset.GfxStaticModelsCount)); mapFile.DumpToMap(outputName + ".map"); // Done printCallback?.Invoke(String.Format("Generated files in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); } } else { printCallback?.Invoke("Call of Duty: Black Ops is supported, but this EXE is not."); } }
/// <summary> /// Reads BSP Data /// </summary> public static void ExportBSPData(ProcessReader reader, long assetPoolsAddress, long assetSizesAddress, string gameType, Action <object> printCallback = null) { // Found her printCallback?.Invoke("Found supported game: Call of Duty: Modern Warfare Remastered"); // Validate by XModel Name var baseAddr = reader.GetBaseAddress(); var si = reader.ReadInt64(reader.ReadInt64(baseAddr + assetPoolsAddress + 0x38) + 8); var po = reader.ReadNullTerminatedString(si) == "fx"; if (po) { // Load BSP Pools (they only have a size of 1 so we don't care about reading more than 1) var gfxMapAsset = reader.ReadStruct <GfxMap>(reader.ReadInt64(reader.GetBaseAddress() + assetPoolsAddress + 0xF8)); // Name string gfxMapName = reader.ReadNullTerminatedString(gfxMapAsset.NamePointer); string mapName = reader.ReadNullTerminatedString(gfxMapAsset.MapNamePointer); // Verify a BSP is actually loaded (if in base menu, etc, no map is loaded) if (String.IsNullOrWhiteSpace(gfxMapName)) { printCallback?.Invoke("No BSP loaded. Enter Main Menu or a Map to load in the required assets."); } else { // New IW Map var mapFile = new IWMap(); // Print Info printCallback?.Invoke(String.Format("Loaded Gfx Map - {0}", gfxMapName)); printCallback?.Invoke(String.Format("Loaded Map - {0}", mapName)); printCallback?.Invoke(String.Format("Vertex Count - {0}", gfxMapAsset.GfxVertexCount)); printCallback?.Invoke(String.Format("Indices Count - {0}", gfxMapAsset.GfxIndicesCount)); printCallback?.Invoke(String.Format("Surface Count - {0}", gfxMapAsset.SurfaceCount)); printCallback?.Invoke(String.Format("Model Count - {0}", gfxMapAsset.GfxStaticModelsCount)); // Build output Folder string outputName = Path.Combine("exported_maps", "modern_warfare_rm", gameType, mapName, mapName); Directory.CreateDirectory(Path.GetDirectoryName(outputName)); // Stop watch var stopWatch = Stopwatch.StartNew(); // Read Vertices printCallback?.Invoke("Parsing vertex data...."); var vertices = ReadGfxVertices(reader, gfxMapAsset.GfxVerticesPointer, (int)gfxMapAsset.GfxVertexCount); printCallback?.Invoke(String.Format("Parsed vertex data in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Read Indices printCallback?.Invoke("Parsing surface indices...."); var indices = ReadGfxIndices(reader, gfxMapAsset.GfxIndicesPointer, (int)gfxMapAsset.GfxIndicesCount); printCallback?.Invoke(String.Format("Parsed indices in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Read Indices printCallback?.Invoke("Parsing surfaces...."); var surfaces = ReadGfxSufaces(reader, gfxMapAsset.GfxSurfacesPointer, gfxMapAsset.SurfaceCount); printCallback?.Invoke(String.Format("Parsed surfaces in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Write OBJ printCallback?.Invoke("Converting to OBJ...."); // Create new OBJ var obj = new WavefrontOBJ(); // Append Vertex Data foreach (var vertex in vertices) { obj.Vertices.Add(vertex.Position); obj.Normals.Add(vertex.Normal); obj.UVs.Add(vertex.UV); } // Image Names (for Search String) HashSet <string> imageNames = new HashSet <string>(); // Append Faces foreach (var surface in surfaces) { // Create new Material var material = ReadMaterial(reader, surface.MaterialPointer); // Add to images imageNames.Add(material.DiffuseMap); // Add it obj.AddMaterial(material); // Add points for (ushort i = 0; i < surface.FaceCount; i++) { // Face Indices var faceIndex1 = indices[i * 3 + surface.FaceIndex] + surface.VertexIndex; var faceIndex2 = indices[i * 3 + surface.FaceIndex + 1] + surface.VertexIndex; var faceIndex3 = indices[i * 3 + surface.FaceIndex + 2] + surface.VertexIndex; // Validate unique points, and write to OBJ if (faceIndex1 != faceIndex2 && faceIndex1 != faceIndex3 && faceIndex2 != faceIndex3) { // new Obj Face var objFace = new WavefrontOBJ.Face(material.Name); // Add points objFace.Vertices[0] = new WavefrontOBJ.Face.Vertex(faceIndex1, faceIndex1, faceIndex1); objFace.Vertices[2] = new WavefrontOBJ.Face.Vertex(faceIndex2, faceIndex2, faceIndex2); objFace.Vertices[1] = new WavefrontOBJ.Face.Vertex(faceIndex3, faceIndex3, faceIndex3); // Add to OBJ obj.Faces.Add(objFace); } } } // Save it obj.Save(outputName + ".obj"); // Build search strinmg string searchString = ""; // Loop through images, and append each to the search string (for Wraith/Greyhound) foreach (string imageName in imageNames) { searchString += String.Format("{0},", Path.GetFileNameWithoutExtension(imageName)); } // Dump it File.WriteAllText(outputName + "_search_string.txt", searchString); // Read entities and dump to map mapFile.Entities.AddRange(ReadStaticModels(reader, gfxMapAsset.GfxStaticModelsPointer, (int)gfxMapAsset.GfxStaticModelsCount)); mapFile.DumpToMap(outputName + ".map"); // Done printCallback?.Invoke(String.Format("Converted to OBJ in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); } } else { printCallback?.Invoke("Call of Duty: Modern Warfare Remastered is supported, but this EXE is not."); } }
/// <summary> /// StartTestWorker does the actual work of starting a test. It should already be running on it's own thread by the time /// we call here (because StartTest creates the new thread). /// </summary> private void StartTestWorker(object test) { try { // Update the running time for the stress run if (((TimeSpan)DateTime.Now.Subtract(_lastLogTime)).TotalMinutes >= 30) { _logger.RecordTimeStamp(); _lastLogTime = DateTime.Now; } ReliabilityTest daTest = test as ReliabilityTest; if (_detourHelpers != null) { _detourHelpers.SetTestIdName(daTest.Index + 1, daTest.RefOrID); _detourHelpers.SetThreadTestId(daTest.Index + 1); } Debug.Assert(daTest != null); // if we didn't find the test then there's something horribly wrong! daTest.StartTime = DateTime.Now; switch (daTest.TestStartMode) { case TestStartModeEnum.ProcessLoader: #if PROJECTK_BUILD Task.Factory.StartNew(() => { Console.WriteLine("==============================running test: {0}==============================", daTest.Assembly); try { daTest.EntryPointMethod.Invoke(null, new object[] { (daTest.Arguments == null) ? new string[0] : daTest.GetSplitArguments() }); } catch (Exception e) { Console.WriteLine(e); } Interlocked.Increment(ref _testsRanCount); SignalTestFinished(daTest); }); #else try { if (daTest.TestObject is string) { ProcessStartInfo pi = null; Process p = null; try { if (daTest.Debugger != null && daTest.Debugger != String.Empty) { if (daTest.DebuggerOptions == null) { pi = new ProcessStartInfo((string)daTest.Debugger, String.Format("{0} {1} {2}", "-g", (string)daTest.TestObject, daTest.Arguments )); } else { pi = new ProcessStartInfo((string)daTest.Debugger, String.Format("{0} {1} {2}", daTest.DebuggerOptions, (string)daTest.TestObject, daTest.Arguments )); } } else { // works for both exe and batch files // a temporary file for exitcode is not needed here // since it's not running directly under smarty pi = new ProcessStartInfo((string)daTest.TestObject, daTest.Arguments); } if (daTest.BasePath != String.Empty) { pi.WorkingDirectory = daTest.BasePath; } pi.UseShellExecute = false; pi.RedirectStandardOutput = true; pi.RedirectStandardError = true; p = Process.Start(pi); using (ProcessReader pr = new ProcessReader(p, daTest.RefOrID)) // reads & outputs standard error & output { int timeOutCnt = 0; while (!pr.Exited) { if (timeOutCnt > 24 * 15) { pr.TimedOut = true; break; } Thread.Sleep(2500); timeOutCnt++; } int exitCode = 0; if (!pr.TimedOut) { p.WaitForExit(); exitCode = p.ExitCode; if (exitCode != daTest.SuccessCode) { AddFailure(String.Format("Test Result ({0}) != Success ({1})", exitCode, daTest.SuccessCode), daTest, exitCode); } else { AddSuccess("", daTest, exitCode); } } else { // external test timed out.. try { p.Kill(); AddFailure(String.Format("Test Timed out after 15 minutes..."), daTest, exitCode); } catch (Exception e) { AddFailure(String.Format("Test timed out after 15 minutes, failed to kill: {0}", e), daTest, exitCode); } } } } catch (Exception e) { if (null != pi) { // let's see what process info thinks of this... Console.WriteLine("Trying to run {1} {2} from {0}", pi.WorkingDirectory, pi.FileName, pi.Arguments); } Console.WriteLine("Unable to start test: {0} because {1} was thrown ({2})\r\nStack Trace: {3}", daTest.TestObject, e.GetType(), e.Message, e.StackTrace); SignalTestFinished(daTest); AddFailure("Unable to run test: ", daTest, -1); return; } finally { if (null != p) { p.Dispose(); } } Interlocked.Increment(ref testsRanCount); SignalTestFinished(daTest); } else if (daTest.TestObject != null) { SignalTestFinished(daTest); throw new NotSupportedException("ProcessLoader can only load applications, not assemblies!" + daTest.RefOrID + daTest.TestObject.GetType().ToString()); } else { SignalTestFinished(daTest); AddFailure("Test does not exist", daTest, -1); } } catch (Exception e) { AddFailure("Failed to start test in process loader mode" + e.ToString(), daTest, -1); Interlocked.Increment(ref testsRanCount); SignalTestFinished(daTest); Console.WriteLine("STA thread issue encountered, couldn't start in process loader {0}", e); MyDebugBreak(daTest.RefOrID); } #endif break; case TestStartModeEnum.AppDomainLoader: #if PROJECTK_BUILD Console.WriteLine("Appdomain mode is NOT supported for ProjectK"); #else try { if (daTest.TestObject is string) { try { int exitCode; #pragma warning disable 0618 // AppendPrivatePath is obsolute, should move to AppDomainSetup but it's too risky at end of beta 1. daTest.AppDomain.AppendPrivatePath(daTest.BasePath); #pragma warning restore // Execute the test. if (daTest.Assembly.ToLower().IndexOf(".exe") == -1 && daTest.Assembly.ToLower().IndexOf(".dll") == -1) // must be a simple name or fullname... { //exitCode = daTest.AppDomain.ExecuteAssemblyByName(daTest.Assembly, daTest.GetSplitArguments()); exitCode = daTest.AppDomain.ExecuteAssemblyByName(daTest.Assembly, null, daTest.GetSplitArguments()); } else { //exitCode = daTest.AppDomain.ExecuteAssembly(daTest.Assembly, daTest.GetSplitArguments()); exitCode = daTest.AppDomain.ExecuteAssembly(daTest.Assembly, null, daTest.GetSplitArguments()); } // HACKHACK: VSWhidbey bug #113535: Breaking change. Tests that return a value via Environment.ExitCode // will not have their value propagated back properly via AppDomain.ExecuteAssembly. These tests will // typically have a return value of 0 (because they have a void entry point). We will check // Environment.ExitCode and if it's not zero, we'll treat that as our return value (then reset // Env.ExitCode back to 0). if (exitCode == 0 && Environment.ExitCode != 0) { logger.WriteTestRace(daTest); exitCode = Environment.ExitCode; Environment.ExitCode = 0; } if (exitCode != daTest.SuccessCode) { AddFailure(String.Format("Test Result ({0}) != Success ({1})", exitCode, daTest.SuccessCode), daTest, exitCode); } else { AddSuccess("", daTest, exitCode); } logger.WriteToInstrumentationLog(curTestSet, LoggingLevels.Tests, String.Format("Test {0} has exited with result {1}", daTest.RefOrID, exitCode)); } catch (PathTooLongException) { if (curTestSet.DebugBreakOnPathTooLong) { MyDebugBreak("Path too long"); } } catch (AppDomainUnloadedException) { logger.WriteToInstrumentationLog(curTestSet, LoggingLevels.Tests, String.Format("Error in executing test {0}: AppDomainUnloaded", daTest.RefOrID)); AddFailure("Failed to ExecuteAssembly, AD Unloaded (" + daTest.AppDomain.FriendlyName + ")", daTest, -1); } catch (OutOfMemoryException e) { HandleOom(e, "ExecuteAssembly"); } catch (Exception e) { Exception eTemp = e.InnerException; while (eTemp != null) { if (eTemp is OutOfMemoryException) { HandleOom(e, "ExecuteAssembly (inner)"); break; } eTemp = eTemp.InnerException; } if (eTemp == null) { logger.WriteToInstrumentationLog(curTestSet, LoggingLevels.Tests, String.Format("Error in executing test {0}: {1}", daTest.RefOrID, e)); AddFailure("Failed to ExecuteAssembly (" + e.ToString() + ")", daTest, -1); } if ((Thread.CurrentThread.ThreadState & System.Threading.ThreadState.AbortRequested) != 0) { UnexpectedThreadAbortDebugBreak(); logger.WriteToInstrumentationLog(curTestSet, LoggingLevels.Tests, String.Format("Test left thread w/ abort requested set")); AddFailure("Abort Requested Bit Still Set (" + e.ToString() + ")", daTest, -1); Thread.ResetAbort(); } } } else if (daTest.TestObject is ISingleReliabilityTest) { try { if (((ISingleReliabilityTest)daTest.TestObject).Run() != true) { AddFailure("SingleReliabilityTest returned false", daTest, 0); } else { AddSuccess("", daTest, 1); } } catch (Exception e) { Console.WriteLine("Error in executing ISingleReliabilityTest: {0}", e); AddFailure("ISingleReliabilityTest threw exception!", daTest, -1); } } else if (daTest.TestObject is IMultipleReliabilityTest) { try { if (((IMultipleReliabilityTest)daTest.TestObject).Run(0) != true) { AddFailure("MultipleReliabilityTest returned false", daTest, 0); } else { AddSuccess("", daTest, 1); } } catch (Exception ex) { Console.WriteLine("Error in executing IMultipleReliabilityTest: {0}", ex); AddFailure("IMultipleReliabilityTest threw exception!", daTest, -1); } } /* Test is finished executing, we need to clean up now... */ Interlocked.Increment(ref testsRanCount); if (curTestSet.AppDomainLoaderMode == AppDomainLoaderMode.FullIsolation || curTestSet.AppDomainLoaderMode == AppDomainLoaderMode.Lazy) { // we're in full isolation & have test runs left. we need to // recreate the app domain so that we don't die on statics. lock (daTest) { if (daTest.AppDomain != null) { logger.WriteToInstrumentationLog(curTestSet, LoggingLevels.AppDomain, String.Format("Unloading app domain (locked): {0}", daTest.AppDomain.FriendlyName)); AppDomain.Unload(daTest.AppDomain); daTest.AppDomain = null; daTest.MyLoader = null; } if (curTestSet.MaximumLoops != 1 && curTestSet.AppDomainLoaderMode != AppDomainLoaderMode.Lazy) { TestPreLoader(daTest, curTestSet.DiscoveryPaths); // need to reload assembly & appdomain } logger.WriteToInstrumentationLog(curTestSet, LoggingLevels.AppDomain, String.Format("Unloading complete (freeing lock): {0}", daTest.RefOrID)); } } else if ((daTest.RunCount >= (curTestSet.MaximumLoops * daTest.ConcurrentCopies) || ((DateTime.Now.Subtract(startTime).Ticks / TimeSpan.TicksPerMinute > curTestSet.MaximumTime))) && (curTestSet.AppDomainLoaderMode != AppDomainLoaderMode.RoundRobin)) // don't want to unload domains in round robin mode, we don't know how // many tests are left. { lock (daTest) { // make sure no one accesses the app domain at the same time (between here & RunReliabilityTests) if (daTest.RunningCount == 1 && daTest.AppDomain != null) { // only unload when the last test finishes. // unload app domain's async so that we don't block while holding daTest lock. AppDomainUnloadDelegate adu = new AppDomainUnloadDelegate(AppDomain.Unload); adu.BeginInvoke(daTest.AppDomain, null, null); daTest.AppDomain = null; RunCommands(daTest.PostCommands, "post", daTest); } } } } catch (ThreadAbortException) { UnexpectedThreadAbortDebugBreak(); } finally { SignalTestFinished(daTest); } #endif break; } } catch (Exception e) { _logger.WriteToInstrumentationLog(_curTestSet, LoggingLevels.Tests, String.Format("Unexpected exception on StartTestWorker: {0}", e)); } }
public unsafe static List <IDictionary> CreateXModelDictionary(ProcessReader reader, long address, int count, List <IDictionary> MapEntities) { // Force english-US input Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); // Read buffer var byteBuffer = reader.ReadBytes(address, count * Marshal.SizeOf <GfxStaticModel>()); // Loop number of models we have List <IDictionary> MapModels = new List <IDictionary>(count); // Create list with unnessecary strings in model names List <string> badStrings = new List <string>() { "\"ml", "\"mv", }; for (int i = 0; i < count; i++) { Dictionary <string, string> ModelData = new Dictionary <string, string>(); List <double> Position = new List <double>(); List <double> angles = new List <double>(); // Read Struct var staticModel = ByteUtil.BytesToStruct <GfxStaticModel>(byteBuffer, i * Marshal.SizeOf <GfxStaticModel>()); // Model Name var modelName = reader.ReadNullTerminatedString(reader.ReadInt64(staticModel.ModelPointer)); var matrix = new Rotation.Matrix(); // Copy X Values matrix.Values[0] = staticModel.Matrix[0]; matrix.Values[1] = staticModel.Matrix[1]; matrix.Values[2] = staticModel.Matrix[2]; // Copy Y Values matrix.Values[4] = staticModel.Matrix[3]; matrix.Values[5] = staticModel.Matrix[4]; matrix.Values[6] = staticModel.Matrix[5]; // Copy Z Values matrix.Values[8] = staticModel.Matrix[6]; matrix.Values[9] = staticModel.Matrix[7]; matrix.Values[10] = staticModel.Matrix[8]; // Convert to Euler var euler = matrix.ToEuler(); // Add it if (string.IsNullOrEmpty(modelName) == true || modelName.Contains("?") == true || modelName.Contains("'") == true || modelName.Contains("\\") == true || modelName.Contains("fx") == true || modelName.Contains("viewmodel") == true || modelName.Contains("*") == true || staticModel.ModelScale < 0.001 || staticModel.ModelScale > 10) { } else { foreach (string b in badStrings) { if (modelName.Contains(b)) { modelName = modelName.Replace(b, "\""); } } ModelData.Add("Name", CleanInput(modelName)); ModelData.Add("PosX", string.Format("{0:0.0000}", staticModel.X)); ModelData.Add("PosY", string.Format("{0:0.0000}", staticModel.Y)); ModelData.Add("PosZ", string.Format("{0:0.0000}", staticModel.Z)); ModelData.Add("RotX", string.Format("{0:0.0000}", (float)Rotation.ToDegrees(euler).X).ToString(CultureInfo.InvariantCulture)); ModelData.Add("RotY", string.Format("{0:0.0000}", (float)Rotation.ToDegrees(euler).Y).ToString(CultureInfo.InvariantCulture)); ModelData.Add("RotZ", string.Format("{0:0.0000}", (float)Rotation.ToDegrees(euler).Z).ToString(CultureInfo.InvariantCulture)); ModelData.Add("Scale", string.Format("{0:0.0000}", staticModel.ModelScale).ToString(CultureInfo.InvariantCulture)); MapModels.Add(new Dictionary <string, string>(ModelData)); } } foreach (IDictionary entity in MapEntities) { MapModels.Add(entity); } // Done return(MapModels); }
/// <summary> /// Reads BSP Data /// </summary> public static void ExportBSPData(ProcessReader reader, long assetPoolsAddress, long assetSizesAddress, string gameType, Action <object> printCallback = null) { // Found her printCallback?.Invoke("Found supported game: Call of Duty: Black Ops 2"); // Validate by XModel Name if (reader.ReadNullTerminatedString(reader.ReadInt32(reader.ReadInt32(assetPoolsAddress + 0x14) + 4)) == "defaultvehicle") { // Load BSP Pools (they only have a size of 1 so we have no free header) var gfxMapAsset = reader.ReadStruct <GfxMap>(reader.ReadInt32(assetPoolsAddress + 0x44)); // Name string gfxMapName = reader.ReadNullTerminatedString(gfxMapAsset.NamePointer); string mapName = reader.ReadNullTerminatedString(gfxMapAsset.MapNamePointer); // Verify a BSP is actually loaded (if in base menu, etc, no map is loaded) if (String.IsNullOrWhiteSpace(gfxMapName)) { printCallback?.Invoke("No BSP loaded. Enter Main Menu or a Map to load in the required assets."); } else { // New IW Map var mapFile = new IWMap(); // Print Info printCallback?.Invoke(String.Format("Loaded Gfx Map - {0}", gfxMapName)); printCallback?.Invoke(String.Format("Loaded Map - {0}", mapName)); printCallback?.Invoke(String.Format("Vertex Count - {0}", gfxMapAsset.GfxVertexCount)); printCallback?.Invoke(String.Format("Indices Count - {0}", gfxMapAsset.GfxIndicesCount)); printCallback?.Invoke(String.Format("Surface Count - {0}", gfxMapAsset.SurfaceCount)); printCallback?.Invoke(String.Format("Model Count - {0}", gfxMapAsset.GfxStaticModelsCount)); // Build output Folder string outputName = Path.Combine("exported_maps", "black_ops_2", gameType, mapName, mapName); Directory.CreateDirectory(Path.GetDirectoryName(outputName)); // Stop watch var stopWatch = Stopwatch.StartNew(); // Read Vertices printCallback?.Invoke("Parsing vertex data...."); var vertexBuffer = reader.ReadBytes(gfxMapAsset.GfxVerticesPointer, gfxMapAsset.GfxVertexBufferSize); printCallback?.Invoke(String.Format("Parsed vertex data in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Read Indices printCallback?.Invoke("Parsing surface indices...."); var indices = ReadGfxIndices(reader, gfxMapAsset.GfxIndicesPointer, gfxMapAsset.GfxIndicesCount); printCallback?.Invoke(String.Format("Parsed indices in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Read Indices printCallback?.Invoke("Parsing surfaces...."); var surfaces = ReadGfxSufaces(reader, gfxMapAsset.GfxSurfacesPointer, gfxMapAsset.SurfaceCount); printCallback?.Invoke(String.Format("Parsed surfaces in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Write OBJ printCallback?.Invoke("Converting to OBJ...."); // Create new OBJ var obj = new WavefrontOBJ(); // Image Names (for Search String) HashSet <string> imageNames = new HashSet <string>(); // Vertex Index Tracker int vertexIndex = 0; // Append Faces foreach (var surface in surfaces) { // Create new Material var material = ReadMaterial(reader, surface.MaterialPointer); // Add to images imageNames.Add(material.DiffuseMap); // Add it obj.AddMaterial(material); // Add points for (ushort i = 0; i < surface.FaceCount; i++) { // Face Indices var faceIndex1 = indices[i * 3 + surface.FaceIndex]; var faceIndex2 = indices[i * 3 + surface.FaceIndex + 1]; var faceIndex3 = indices[i * 3 + surface.FaceIndex + 2]; // Validate unique points, and write to OBJ if (faceIndex1 != faceIndex2 && faceIndex1 != faceIndex3 && faceIndex2 != faceIndex3) { // new Obj Face var objFace = new WavefrontOBJ.Face(material.Name); // Unpack vertices var vertex1 = UnpackVertex(ByteUtil.BytesToStruct <GfxVertex>(vertexBuffer, surface.VertexBufferOffset + (faceIndex1 * 36))); var vertex2 = UnpackVertex(ByteUtil.BytesToStruct <GfxVertex>(vertexBuffer, surface.VertexBufferOffset + (faceIndex2 * 36))); var vertex3 = UnpackVertex(ByteUtil.BytesToStruct <GfxVertex>(vertexBuffer, surface.VertexBufferOffset + (faceIndex3 * 36))); // Add Offsets obj.Vertices.Add(vertex1.Position); obj.Vertices.Add(vertex2.Position); obj.Vertices.Add(vertex3.Position); // Add Normals obj.Normals.Add(vertex1.Normal); obj.Normals.Add(vertex2.Normal); obj.Normals.Add(vertex3.Normal); // Add UVs obj.UVs.Add(vertex1.UV); obj.UVs.Add(vertex2.UV); obj.UVs.Add(vertex3.UV); // Add points objFace.Vertices[0] = new WavefrontOBJ.Face.Vertex(vertexIndex, vertexIndex, vertexIndex); objFace.Vertices[2] = new WavefrontOBJ.Face.Vertex(vertexIndex + 1, vertexIndex + 1, vertexIndex + 1); objFace.Vertices[1] = new WavefrontOBJ.Face.Vertex(vertexIndex + 2, vertexIndex + 2, vertexIndex + 2); // Add to OBJ obj.Faces.Add(objFace); vertexIndex += 3; } } } // Save it obj.Save(outputName + ".obj"); // Build search strinmg string searchString = ""; // Loop through images, and append each to the search string (for Wraith/Greyhound) foreach (string imageName in imageNames) { searchString += String.Format("{0},", Path.GetFileNameWithoutExtension(imageName)); } // Dump it File.WriteAllText(outputName + "_search_string.txt", searchString); // Read entities and dump to map mapFile.Entities.AddRange(ReadStaticModels(reader, gfxMapAsset.GfxStaticModelsPointer, gfxMapAsset.GfxStaticModelsCount)); mapFile.DumpToMap(outputName + ".map"); // Done printCallback?.Invoke(String.Format("Converted to OBJ in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); } } else { printCallback?.Invoke("Call of Duty: Black Ops 2 is supported, but this EXE is not."); } }
private static void Build(BuildInfo info) { try { ProcessReader process_reader; string log_file = Path.Combine(info.BUILDER_DATA_LOG_DIR, info.command.command + ".log"); DateTime local_starttime = DateTime.Now; DBState result; DBCommand command = info.command; int exitcode = 0; ReportBuildStateResponse response; Logger.Log("{0} Builder started new thread for sequence {1} step {2}", info.number, info.command.sequence, info.command.command); /* Check if step has been aborted already */ info.work.State = WebService.GetWorkStateSafe(info.work); if (info.work.State != DBState.NotDone && info.work.State != DBState.Executing) { /* If we're in an executing state, we're restarting a command for whatever reason (crash, reboot, etc) */ Logger.Log("{0} Builder found that step {1} is not ready to start, it's in a '{2}' state", info.number, info.command.command, info.work.State); return; } result = DBState.Executing; info.work.starttime = DBRecord.DatabaseNow; info.work.State = result; info.work.host_id = info.host.id; info.work = WebService.ReportBuildStateSafe(info.work).Work; using (Job p = ProcessHelper.CreateJob()) { using (FileStream fs = new FileStream(log_file, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) { using (var log = new SynchronizedStreamWriter(new StreamWriter(fs))) { p.StartInfo.FileName = info.command.filename; p.StartInfo.Arguments = string.Format(info.command.arguments, Path.Combine(info.temp_dir, info.command.command), info.temp_dir); if (!string.IsNullOrEmpty(info.command.working_directory)) { p.StartInfo.WorkingDirectory = Path.Combine(info.BUILDER_DATA_SOURCE_DIR, info.command.working_directory); } else { p.StartInfo.WorkingDirectory = info.BUILDER_DATA_SOURCE_DIR; } // set environment variables p.StartInfo.EnvironmentVariables ["BUILD_LANE"] = info.lane.lane; p.StartInfo.EnvironmentVariables ["BUILD_COMMAND"] = info.command.command; p.StartInfo.EnvironmentVariables ["BUILD_REVISION"] = info.revision.revision; p.StartInfo.EnvironmentVariables ["BUILD_INSTALL"] = Configuration.CygwinizePath(info.BUILDER_DATA_INSTALL_DIR); p.StartInfo.EnvironmentVariables ["BUILD_DATA_LANE"] = Configuration.GetDataLane(info.lane.id); p.StartInfo.EnvironmentVariables ["BUILD_DATA_SOURCE"] = info.BUILDER_DATA_SOURCE_DIR; p.StartInfo.EnvironmentVariables ["BUILD_REPOSITORY"] = info.lane.repository; p.StartInfo.EnvironmentVariables ["BUILD_HOST"] = Configuration.Host; p.StartInfo.EnvironmentVariables ["BUILD_WORK_HOST"] = info.host_being_worked_for; p.StartInfo.EnvironmentVariables ["BUILD_LANE_MAX_REVISION"] = info.lane.max_revision; p.StartInfo.EnvironmentVariables ["BUILD_LANE_MIN_REVISION"] = info.lane.min_revision; p.StartInfo.EnvironmentVariables ["BUILD_LANE_COMMIT_FILTER"] = info.lane.commit_filter; int r = 0; foreach (string repo in info.lane.repository.Split(',')) { p.StartInfo.EnvironmentVariables ["BUILD_REPOSITORY_" + r.ToString()] = repo; r++; } p.StartInfo.EnvironmentVariables ["BUILD_REPOSITORY_SPACE"] = info.lane.repository.Replace(',', ' '); p.StartInfo.EnvironmentVariables ["BUILD_SEQUENCE"] = "0"; p.StartInfo.EnvironmentVariables ["BUILD_SCRIPT_DIR"] = info.temp_dir; p.StartInfo.EnvironmentVariables ["LD_LIBRARY_PATH"] = Configuration.CygwinizePath(Configuration.GetLdLibraryPath(info.lane.id, info.revision.revision)); p.StartInfo.EnvironmentVariables ["PKG_CONFIG_PATH"] = Configuration.CygwinizePath(Configuration.GetPkgConfigPath(info.lane.id, info.revision.revision)); p.StartInfo.EnvironmentVariables ["PATH"] = Configuration.CygwinizePath(Configuration.GetPath(info.lane.id, info.revision.revision)); p.StartInfo.EnvironmentVariables ["C_INCLUDE_PATH"] = Configuration.CygwinizePath(Configuration.GetCIncludePath(info.lane.id, info.revision.revision)); p.StartInfo.EnvironmentVariables ["CPLUS_INCLUDE_PATH"] = Configuration.CygwinizePath(Configuration.GetCPlusIncludePath(info.lane.id, info.revision.revision)); // We need to remove all paths from environment variables that were // set for this executable to work so that they don't mess with // whatever we're trying to execute string [] bot_dependencies = new string [] { "PATH", "LD_LIBRARY_PATH", "PKG_CONFIG_PATH", "C_INCLUDE_PATH", "CPLUS_INCLUDE_PATH", "AC_LOCAL_PATH", "MONO_PATH" }; foreach (string bot_dependency in bot_dependencies) { if (!p.StartInfo.EnvironmentVariables.ContainsKey(bot_dependency)) { continue; } List <string> paths = new List <string> (p.StartInfo.EnvironmentVariables [bot_dependency].Split(new char [] { ':' /* XXX: does windows use ';' here? */ }, StringSplitOptions.None)); for (int i = paths.Count - 1; i >= 0; i--) { if (paths [i].Contains("bot-dependencies")) { paths.RemoveAt(i); } } p.StartInfo.EnvironmentVariables [bot_dependency] = string.Join(":", paths.ToArray()); } if (info.environment_variables != null) { // order is important here, we need to loop over the array in the same order get got the variables. for (int e = 0; e < info.environment_variables.Count; e++) { info.environment_variables [e].Evaluate(p.StartInfo.EnvironmentVariables); } } process_reader = new ProcessReader(log); process_reader.Setup(p); p.Start(); process_reader.Start(); while (!p.WaitForExit(60000 /* 1 minute */)) { if (p.HasExited) { break; } // Check if step has been aborted. info.work.State = WebService.GetWorkStateSafe(info.work); if (info.work.State == DBState.Aborted) { result = DBState.Aborted; try { exitcode = 255; Logger.Log("{1} The build step '{0}' has been aborted, terminating it.", info.command.command, info.number); p.Terminate(log); log.WriteLine(string.Format("{1} The build step '{0}' was aborted, terminated it.", info.command.command, info.number)); } catch (Exception ex) { Logger.Log("{1} Exception while killing build step: {0}", ex.ToString(), info.number); } break; } // Check if step has timedout bool timedout = false; string timeoutReason = null; int timeout = 30; if ((DateTime.Now > local_starttime.AddMinutes(info.command.timeout))) { timedout = true; timeoutReason = string.Format("The build step '{0}' didn't finish in {1} minute(s).", info.command.command, info.command.timeout); } else if (log.LastStamp.AddMinutes(timeout) <= DateTime.Now) { timedout = true; timeoutReason = string.Format("The build step '{0}' has had no output for {1} minute(s).", info.command.command, timeout); } if (!timedout) { continue; } try { result = DBState.Timeout; exitcode = 255; Logger.Log("{0} {1}", info.number, timeoutReason); log.WriteLine("\n*** Timed out. Proceeding to get stack traces for all child processes. ***"); p.Terminate(log); log.WriteLine("\n * " + timeoutReason + " * \n"); } catch (Exception ex) { Logger.Log("{1} Exception while terminating build step: {0}", ex.ToString(), info.number); } break; } // Sleep a bit so that the process has enough time to finish System.Threading.Thread.Sleep(1000); process_reader.Join(); if (p.HasExited) { exitcode = p.ExitCode; } else { Logger.Log("{1} Step: {0}: the process didn't exit in time.", command.command, info.number); exitcode = 1; } if (result == DBState.Executing) { if (exitcode == 0) { result = DBState.Success; } else { result = DBState.Failed; } } else if (result == DBState.Aborted) { result = DBState.Failed; } } } } info.work.State = result; using (TextReader reader = new StreamReader(new FileStream(log_file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) info.work.CalculateSummary(reader); info.work.endtime = DBRecord.DatabaseNow; response = WebService.ReportBuildStateSafe(info.work); info.work = response.Work; WebService.UploadFilesSafe(info.work, new string [] { log_file }, new bool [] { false }); // Gather files from logged commands and from the upload_files glob CheckLog(log_file, info); if (!string.IsNullOrEmpty(info.command.upload_files)) { foreach (string glob in info.command.upload_files.Split(',')) { // TODO: handle globs in directory parts // TODO: allow absolute paths? Logger.Log("Uploading files from glob {0}", glob); // TODO: allow hidden files also WebService.UploadFilesSafe(info.work, Directory.GetFiles(Path.Combine(info.BUILDER_DATA_SOURCE_DIR, Path.GetDirectoryName(glob)), Path.GetFileName(glob)), null); } } if (response.RevisionWorkCompleted) { // Cleanup after us. string base_dir = Configuration.GetDataRevisionDir(info.lane.id, info.revision.revision); FileUtilities.TryDeleteDirectoryRecursive(base_dir); } Logger.Log("{4} Revision {0}, executed step '{1}' in {2} s, ExitCode: {3}, State: {4}", info.revision.revision, info.command.command, info.work.duration, exitcode, info.number, info.work.State); } catch (Exception ex) { info.work.State = DBState.Failed; info.work.summary = ex.Message; info.work = WebService.ReportBuildStateSafe(info.work).Work; Logger.Log("{3} Revision {0}, got exception '{1}': \n{2}", info.revision.revision, ex.Message, ex.StackTrace, info.number); throw; } finally { Logger.Log("{0} Builder finished thread for sequence {0}", info.number); if ((info.work.State == DBState.Failed || info.work.State == DBState.Aborted || info.work.State == DBState.Timeout) && !info.command.nonfatal) { failed_hostlanes.Add(info.hostlane); } } }
public HydraStatus LoadGame() { foreach (var gdt in GDTs) { gdt.Value.Assets.Clear(); } Process[] processes = Process.GetProcesses(); var status = HydraStatus.FailedToFindGame; foreach (var process in processes) { foreach (var game in Games) { for (int i = 0; i < game.ProcessNames.Length; i++) { if (process.ProcessName == game.ProcessNames[i]) { Game = (IGame)game.Clone(); Game.ProcessIndex = i; Reader = new ProcessReader(process); if (Game.ValidateAddresses(this)) { Game.AssetPools = GetAssetPools(Game); Assets = new List <GameAsset>(); #if DEBUG // For printing a new support table for the README.md Console.WriteLine("| {0} | {1} |", "Asset Type".PadRight(32), "Settings Group".PadRight(32)); #endif foreach (var assetPool in Game.AssetPools) { if (Settings["Show" + assetPool.SettingGroup, "Yes"] == "Yes") { #if DEBUG Console.WriteLine("| {0} | {1} |", assetPool.Name.PadRight(32), assetPool.SettingGroup.PadRight(32)); #endif Assets.AddRange(assetPool.Load(this)); } #if DEBUG else { Console.WriteLine("Ignoring Pool: {0}", assetPool.Name); } #endif } status = HydraStatus.Success; } else { Clear(); status = HydraStatus.UnsupportedBinary; } break; } } } } return(status); }
public static void ResolveAddresses(ProcessReader reader, string gameType) { }
/// <summary> /// Runs the executable file /// </summary> /// <returns>The result of running the executable file</returns> public ProcessResult Run() { lock (this) { CheckNotRunning(); _running = true; _process = new System.Diagnostics.Process { StartInfo = GetStartInfo() }; WriteStandardInput(); if (_result.Status == ProcessStatus.NotStarted) { _result.Status = ProcessStatus.Started; _endTime = System.DateTime.Now.AddSeconds(Timeout); _process.Start(); } } if (_result.Status == ProcessStatus.Started) { if (Options.StandardInputEncoding != null) { _standardInput = new StreamWriter(_process.StandardInput.BaseStream, Options.StandardInputEncoding); } else { _standardInput = _process.StandardInput; } var inputThread = new Thread(new ThreadStart(() => StandardInput.Flush())); inputThread.Start(); var outputReader = new ProcessReader(this, ProcessReader.OutputType.StandardOutput); var errorReader = new ProcessReader(this, ProcessReader.OutputType.StandardError); lock (this) { AddEvent(new ProcessEventArgs(ProcessEventType.Started, this)); DoEvents(); while (!_process.HasExited) { Monitor.Wait(this, 250); DoEvents(); if ((_timeout > 0) && (System.DateTime.Now > _endTime)) { // Not a very nice way to end a process, // but effective. _process.Kill(); _result.Status = ProcessStatus.TimedOut; } else if (_result.Status == ProcessStatus.Cancelled) { _process.Kill(); } } } _process.WaitForExit(); outputReader.Join(); errorReader.Join(); inputThread.Join(); DoEvents(); _result.ExitCode = _process.ExitCode; } if (_result.Status == ProcessStatus.Started) { _result.Status = ProcessStatus.Finished; } lock (this) { if (Options.StandardInputEncoding != null && _standardInput != null) { _standardInput.Dispose(); } _standardInput = null; _running = false; } return(_result); }