public void DetachFromProcess_WhenProcessIsNull_Throws() { var debuggerSetup = new DebuggerSetup(); var logger = MockRepository.GenerateStub<ILogger>(); var debugger = new VisualStudioDebugger(debuggerSetup, logger, null); Assert.Throws<ArgumentNullException>(() => debugger.DetachFromProcess(null)); }
public void Start(string workingDirectory, Process debuggerProcess, LoggerResult logger) { var gameHostAssembly = typeof(GameDebuggerTarget).Assembly.Location; using (var debugger = debuggerProcess != null ? VisualStudioDebugger.GetByProcess(debuggerProcess.Id) : null) { var address = "Stride/Debugger/" + Guid.NewGuid(); var arguments = $"--host=\"{address}\""; // Child process should wait for a debugger to be attached if (debugger != null) { arguments += " --wait-debugger-attach"; } var startInfo = new ProcessStartInfo { FileName = gameHostAssembly, Arguments = arguments, WorkingDirectory = workingDirectory, CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, }; // Start ServiceWire pipe var gameDebuggerHost = new GameDebuggerHost(logger); ServiceHost = new NpHost(address, null, null); ServiceHost.AddService <IGameDebuggerHost>(gameDebuggerHost); ServiceHost.Open(); var process = new Process { StartInfo = startInfo }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); // Make sure proces will be killed if our process is finished unexpectedly attachedChildProcessJob = new AttachedChildProcessJob(process); // Attach debugger debugger?.AttachToProcess(process.Id); GameHost = gameDebuggerHost; } }
public int Run(string currentDirectory, Dictionary <string, string> environmentVariables, string[] args, bool shadowCache, int?debuggerProcessId, string callbackAddress) { bool lockTaken = false; try { Monitor.TryEnter(runLock, ref lockTaken); if (!lockTaken) { // Busy, exit right away return(BusyReturnCode); } // Do your stuff... Console.WriteLine("Run Received {0}", string.Join(" ", args)); upTime.Restart(); if (debuggerProcessId.HasValue && !Debugger.IsAttached) { using (var debugger = VisualStudioDebugger.GetByProcess(debuggerProcessId.Value)) { debugger?.Attach(); } } using (var callbackChannel = new NpClient <IServerLogger>(new NpEndPoint(callbackAddress))) { var result = shadowManager.Run(currentDirectory, environmentVariables, args, shadowCache, callbackChannel); return(result); } } finally { if (lockTaken) { Monitor.Exit(runLock); } } }
public async Task <ResultStatus> TryExecuteRemote(Command command, BuilderContext builderContext, IExecuteContext executeContext, LocalCommandContext commandContext) { while (!CanSpawnParallelProcess()) { await Task.Delay(1, command.CancellationToken); } var address = "net.pipe://localhost/" + Guid.NewGuid(); var arguments = $"--slave=\"{address}\" --build-path=\"{builderOptions.BuildDirectory}\""; using (var debugger = VisualStudioDebugger.GetAttached()) { if (debugger != null) { arguments += $" --reattach-debugger={debugger.ProcessId}"; } } // Start WCF pipe for communication with process var processBuilderRemote = new ProcessBuilderRemote(assemblyContainer, commandContext, command); var host = new ServiceHost(processBuilderRemote); host.AddServiceEndpoint(typeof(IProcessBuilderRemote), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None) { MaxReceivedMessageSize = int.MaxValue }, address); var startInfo = new ProcessStartInfo { // Note: try to get exec server if it exists, otherwise use CompilerApp.exe FileName = (string)AppDomain.CurrentDomain.GetData("RealEntryAssemblyFile") ?? typeof(PackageBuilder).Assembly.Location, Arguments = arguments, WorkingDirectory = Environment.CurrentDirectory, CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, }; host.Open(); var output = new List <string>(); var process = new Process { StartInfo = startInfo }; process.Start(); process.OutputDataReceived += (_, args) => LockProcessAndAddDataToList(process, output, args); process.ErrorDataReceived += (_, args) => LockProcessAndAddDataToList(process, output, args); process.BeginOutputReadLine(); process.BeginErrorReadLine(); // Note: we don't want the thread to schedule another job since the CPU core will be in use by the process, so we do a blocking WaitForExit. process.WaitForExit(); host.Close(); NotifyParallelProcessEnded(); if (process.ExitCode != 0) { executeContext.Logger.Error($"Remote command crashed with output:{Environment.NewLine}{string.Join(Environment.NewLine, output)}"); } if (processBuilderRemote.Result != null) { // Register results back locally foreach (var outputObject in processBuilderRemote.Result.OutputObjects) { commandContext.RegisterOutput(outputObject.Key, outputObject.Value); } // Register log messages foreach (var logMessage in processBuilderRemote.Result.LogMessages) { commandContext.Logger.Log(logMessage); } // Register tags foreach (var tag in processBuilderRemote.Result.TagSymbols) { commandContext.AddTag(tag.Key, tag.Value); } } return(command.CancellationToken.IsCancellationRequested ? ResultStatus.Cancelled : (process.ExitCode == 0 ? ResultStatus.Successful : ResultStatus.Failed)); }
public int Run(string[] args) { // This is used by ExecServer to retrieve the logs directly without using the console redirect (which is not working well // in a multi-domain scenario) var redirectLogToAppDomainAction = AppDomain.CurrentDomain.GetData("AppDomainLogToAction") as Action <string, ConsoleColor>; clock = Stopwatch.StartNew(); // TODO this is hardcoded. Check how to make this dynamic instead. RuntimeHelpers.RunModuleConstructor(typeof(IProceduralModel).Module.ModuleHandle); RuntimeHelpers.RunModuleConstructor(typeof(MaterialKeys).Module.ModuleHandle); RuntimeHelpers.RunModuleConstructor(typeof(SpriteFontAsset).Module.ModuleHandle); RuntimeHelpers.RunModuleConstructor(typeof(ModelAsset).Module.ModuleHandle); RuntimeHelpers.RunModuleConstructor(typeof(SpriteStudioAnimationAsset).Module.ModuleHandle); RuntimeHelpers.RunModuleConstructor(typeof(ParticleSystem).Module.ModuleHandle); //var project = new Package(); //project.Save("test.sdpkg"); //Thread.Sleep(10000); //var spriteFontAsset = StaticFontAsset.New(); //Content.Save("test.sdfnt", spriteFontAsset); //project.Refresh(); //args = new string[] { "test.sdpkg", "-o:app_data", "-b:tmp", "-t:1" }; var exeName = Path.GetFileName(Assembly.GetExecutingAssembly().Location); var showHelp = false; var packMode = false; var buildEngineLogger = GlobalLogger.GetLogger("BuildEngine"); var options = new PackageBuilderOptions(new ForwardingLoggerResult(buildEngineLogger)); var p = new OptionSet { "Copyright (c) Stride contributors (https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) All Rights Reserved", "Stride Build Tool - Version: " + String.Format( "{0}.{1}.{2}", typeof(Program).Assembly.GetName().Version.Major, typeof(Program).Assembly.GetName().Version.Minor, typeof(Program).Assembly.GetName().Version.Build) + string.Empty, string.Format("Usage: {0} inputPackageFile [options]* -b buildPath", exeName), string.Empty, "=== Options ===", string.Empty, { "h|help", "Show this message and exit", v => showHelp = v != null }, { "v|verbose", "Show more verbose progress logs", v => options.Verbose = v != null }, { "d|debug", "Show debug logs (imply verbose)", v => options.Debug = v != null }, { "log", "Enable file logging", v => options.EnableFileLogging = v != null }, { "disable-auto-compile", "Disable auto-compile of projects", v => options.DisableAutoCompileProjects = v != null }, { "project-configuration=", "Project configuration", v => options.ProjectConfiguration = v }, { "platform=", "Platform name", v => options.Platform = (PlatformType)Enum.Parse(typeof(PlatformType), v) }, { "solution-file=", "Solution File Name", v => options.SolutionFile = v }, { "package-id=", "Package Id from the solution file", v => options.PackageId = Guid.Parse(v) }, { "package-file=", "Input Package File Name", v => options.PackageFile = v }, { "o|output-path=", "Output path", v => options.OutputDirectory = v }, { "b|build-path=", "Build path", v => options.BuildDirectory = v }, { "log-file=", "Log build in a custom file.", v => { options.EnableFileLogging = v != null; options.CustomLogFileName = v; } }, { "log-pipe=", "Log pipe.", v => { if (!string.IsNullOrEmpty(v)) { options.LogPipeNames.Add(v); } } }, { "monitor-pipe=", "Monitor pipe.", v => { if (!string.IsNullOrEmpty(v)) { options.MonitorPipeNames.Add(v); } } }, { "slave=", "Slave pipe", v => options.SlavePipe = v }, // Benlitz: I don't think this should be documented { "server=", "This Compiler is launched as a server", v => { } }, { "pack", "Special mode to copy assets and resources in a folder for NuGet packaging", v => packMode = true }, { "t|threads=", "Number of threads to create. Default value is the number of hardware threads available.", v => options.ThreadCount = int.Parse(v) }, { "test=", "Run a test session.", v => options.TestName = v }, { "property:", "Properties. Format is name1=value1;name2=value2", v => { if (!string.IsNullOrEmpty(v)) { foreach (var nameValue in v.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { var equalIndex = nameValue.IndexOf('='); if (equalIndex == -1) { throw new OptionException("Expect name1=value1;name2=value2 format.", "property"); } options.Properties.Add(nameValue.Substring(0, equalIndex), nameValue.Substring(equalIndex + 1)); } } } }, { "compile-property:", "Compile properties. Format is name1=value1;name2=value2", v => { if (!string.IsNullOrEmpty(v)) { if (options.ExtraCompileProperties == null) { options.ExtraCompileProperties = new Dictionary <string, string>(); } foreach (var nameValue in v.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { var equalIndex = nameValue.IndexOf('='); if (equalIndex == -1) { throw new OptionException("Expect name1=value1;name2=value2 format.", "property"); } options.ExtraCompileProperties.Add(nameValue.Substring(0, equalIndex), nameValue.Substring(equalIndex + 1)); } } } }, { "reattach-debugger=", "Reattach to a Visual Studio debugger", v => { int debuggerProcessId; if (!string.IsNullOrEmpty(v) && int.TryParse(v, out debuggerProcessId)) { if (!Debugger.IsAttached) { using (var debugger = VisualStudioDebugger.GetByProcess(debuggerProcessId)) { debugger?.Attach(); } } } } }, }; TextWriterLogListener fileLogListener = null; BuildResultCode exitCode; RemoteLogForwarder assetLogger = null; try { var unexpectedArgs = p.Parse(args); // Set remote logger assetLogger = new RemoteLogForwarder(options.Logger, options.LogPipeNames); GlobalLogger.GlobalMessageLogged += assetLogger; // Activate proper log level buildEngineLogger.ActivateLog(options.LoggerType); // Output logs to the console with colored messages if (options.SlavePipe == null && !options.LogPipeNames.Any()) { if (redirectLogToAppDomainAction != null) { globalLoggerOnGlobalMessageLogged = new LogListenerRedirectToAction(redirectLogToAppDomainAction); } else { globalLoggerOnGlobalMessageLogged = new ConsoleLogListener { LogMode = ConsoleLogMode.Always }; } globalLoggerOnGlobalMessageLogged.TextFormatter = FormatLog; GlobalLogger.GlobalMessageLogged += globalLoggerOnGlobalMessageLogged; } if (unexpectedArgs.Any()) { throw new OptionException("Unexpected arguments [{0}]".ToFormat(string.Join(", ", unexpectedArgs)), "args"); } try { options.ValidateOptions(); } catch (ArgumentException ex) { throw new OptionException(ex.Message, ex.ParamName); } if (showHelp) { p.WriteOptionDescriptions(Console.Out); return((int)BuildResultCode.Successful); } else if (packMode) { PackageSessionPublicHelper.FindAndSetMSBuildVersion(); var csprojFile = options.PackageFile; var intermediatePackagePath = options.BuildDirectory; var generatedItems = new List <(string SourcePath, string PackagePath)>(); var logger = new LoggerResult(); if (!PackAssetsHelper.Run(logger, csprojFile, intermediatePackagePath, generatedItems)) { foreach (var message in logger.Messages) { Console.WriteLine(message); } return((int)BuildResultCode.BuildError); } foreach (var generatedItem in generatedItems) { Console.WriteLine($"{generatedItem.SourcePath}|{generatedItem.PackagePath}"); } return((int)BuildResultCode.Successful); } // Also write logs from master process into a file if (options.SlavePipe == null) { if (options.EnableFileLogging) { string logFileName = options.CustomLogFileName; if (string.IsNullOrEmpty(logFileName)) { string inputName = Path.GetFileNameWithoutExtension(options.PackageFile); logFileName = "Logs/Build-" + inputName + "-" + DateTime.Now.ToString("yy-MM-dd-HH-mm") + ".txt"; } string dirName = Path.GetDirectoryName(logFileName); if (dirName != null) { Directory.CreateDirectory(dirName); } fileLogListener = new TextWriterLogListener(new FileStream(logFileName, FileMode.Create)) { TextFormatter = FormatLog }; GlobalLogger.GlobalMessageLogged += fileLogListener; } options.Logger.Info("BuildEngine arguments: " + string.Join(" ", args)); options.Logger.Info("Starting builder."); } else { IsSlave = true; } if (!string.IsNullOrEmpty(options.TestName)) { var test = new TestSession(); test.RunTest(options.TestName, options.Logger); exitCode = BuildResultCode.Successful; } else { builder = new PackageBuilder(options); if (!IsSlave && redirectLogToAppDomainAction == null) { Console.CancelKeyPress += OnConsoleOnCancelKeyPress; } exitCode = builder.Build(); } } catch (OptionException e) { options.Logger.Error($"Command option '{e.OptionName}': {e.Message}"); exitCode = BuildResultCode.CommandLineError; } catch (Exception e) { options.Logger.Error($"Unhandled exception", e); exitCode = BuildResultCode.BuildError; } finally { // Flush and close remote logger if (assetLogger != null) { GlobalLogger.GlobalMessageLogged -= assetLogger; assetLogger.Dispose(); } if (fileLogListener != null) { GlobalLogger.GlobalMessageLogged -= fileLogListener; fileLogListener.LogWriter.Close(); } // Output logs to the console with colored messages if (globalLoggerOnGlobalMessageLogged != null) { GlobalLogger.GlobalMessageLogged -= globalLoggerOnGlobalMessageLogged; } if (builder != null && !IsSlave && redirectLogToAppDomainAction == null) { Console.CancelKeyPress -= OnConsoleOnCancelKeyPress; } // Reset cache hold by YamlSerializer YamlSerializer.Default.ResetCache(); } return((int)exitCode); }
private async Task <ResultStatus> StartCommand(IExecuteContext executeContext, ListStore <CommandResultEntry> commandResultEntries, BuilderContext builderContext) { var logger = executeContext.Logger; //await Scheduler.Yield(); ResultStatus status; using (commandResultEntries) { logger.Debug($"Starting command {Command}..."); // Creating the CommandResult object var commandContext = new LocalCommandContext(executeContext, this, builderContext); // Actually processing the command if (Command.ShouldSpawnNewProcess() && builderContext.MaxParallelProcesses > 0 && builderContext.SlaveBuilderPath != null) { while (!builderContext.CanSpawnParallelProcess()) { await Task.Delay(1, Command.CancellationToken); } var address = "net.pipe://localhost/" + Guid.NewGuid(); var arguments = string.Format("--slave=\"{0}\" --build-path=\"{1}\" --profile=\"{2}\"", address, builderContext.BuildPath, builderContext.BuildProfile); using (var debugger = VisualStudioDebugger.GetAttached()) { if (debugger != null) { arguments += $" --reattach-debugger={debugger.ProcessId}"; } } var startInfo = new ProcessStartInfo { FileName = builderContext.SlaveBuilderPath, Arguments = arguments, WorkingDirectory = Environment.CurrentDirectory, CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, }; // Start WCF pipe for communication with process var processBuilderRemote = new ProcessBuilderRemote(commandContext, Command, builderContext.Parameters); var host = new ServiceHost(processBuilderRemote); host.AddServiceEndpoint(typeof(IProcessBuilderRemote), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None) { MaxReceivedMessageSize = int.MaxValue }, address); host.Open(); var output = new List <string>(); var process = new Process { StartInfo = startInfo }; process.Start(); process.OutputDataReceived += (_, args) => LockProcessAndAddDataToList(process, output, args); process.ErrorDataReceived += (_, args) => LockProcessAndAddDataToList(process, output, args); process.BeginOutputReadLine(); process.BeginErrorReadLine(); // Attach debugger to newly created process // Add a reference to EnvDTE80 in the csproj and uncomment this (and also the Thread.Sleep in BuildEngineCmmands), then start the master process without debugger to attach to a slave. //var dte = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.11.0"); //foreach (EnvDTE.Process dteProcess in dte.Debugger.LocalProcesses) //{ // if (dteProcess.ProcessID == process.Id) // { // dteProcess.Attach(); // dte.Debugger.CurrentProcess = dteProcess; // } //} Task[] tasksToWait = null; while (!process.HasExited) { Thread.Sleep(1); lock (spawnedCommandsToWait) { if (spawnedCommandsToWait.Count > 0) { tasksToWait = spawnedCommandsToWait.ToArray(); spawnedCommandsToWait.Clear(); } } if (tasksToWait != null) { await Task.WhenAll(tasksToWait); tasksToWait = null; } } host.Close(); builderContext.NotifyParallelProcessEnded(); if (process.ExitCode != 0) { logger.Debug($"Remote command crashed with output:{Environment.NewLine}{string.Join(Environment.NewLine, output)}"); } if (processBuilderRemote.Result != null) { // Register results back locally foreach (var outputObject in processBuilderRemote.Result.OutputObjects) { commandContext.RegisterOutput(outputObject.Key, outputObject.Value); } // Register log messages foreach (var logMessage in processBuilderRemote.Result.LogMessages) { commandContext.Logger.Log(logMessage); } // Register tags foreach (var tag in processBuilderRemote.Result.TagSymbols) { TagSymbol tagSymbol; // Resolve tag locally if (!Command.TagSymbols.TryGetValue(tag.Value, out tagSymbol)) { // Should we ignore silently? (with warning) throw new InvalidOperationException("Could not find tag symbol."); } commandContext.AddTag(tag.Key, tagSymbol); } } status = Command.CancellationToken.IsCancellationRequested ? ResultStatus.Cancelled : (process.ExitCode == 0 ? ResultStatus.Successful : ResultStatus.Failed); } else { Command.PreCommand(commandContext); if (!Command.BasePreCommandCalled) { throw new InvalidOperationException("base.PreCommand not called in command " + Command); } try { // Merge results from prerequisites // TODO: This will prevent us from overwriting this asset with different content as it will result in a write conflict // At some point we _might_ want to get rid of WaitBuildStep/ListBuildStep system and write a fully stateless input/output-based system; probably need further discussions var fileProvider = ContentManager.FileProvider; if (fileProvider != null) { var assetIndexMap = fileProvider.ContentIndexMap; foreach (var prerequisiteStep in PrerequisiteSteps) { foreach (var output in prerequisiteStep.OutputObjectIds) { assetIndexMap[output.Key.Path] = output.Value; } } } status = await Command.DoCommand(commandContext); } catch (Exception ex) { executeContext.Logger.Error("Exception in command " + this + ": " + ex); status = ResultStatus.Failed; } Command.PostCommand(commandContext, status); if (!Command.BasePostCommandCalled) { throw new InvalidOperationException("base.PostCommand not called in command " + Command); } } // Ensure the command set at least the result status if (status == ResultStatus.NotProcessed) { throw new InvalidDataException("The command " + Command + " returned ResultStatus.NotProcessed after completion."); } // Registering the result to the build cache RegisterCommandResult(commandResultEntries, commandContext.ResultEntry, status); } return(status); }
private const int RetryWait = 1000; // in ms /// <summary> /// Runs the specified arguments copy. /// </summary> /// <param name="argsCopy">The arguments copy.</param> /// <returns>System.Int32.</returns> public int Run(string[] argsCopy) { if (argsCopy.Length == 0) { Console.WriteLine("Usage ExecServer.exe [/direct executablePath|/server entryAssemblyPath executablePath CPUindex] /shadow [executableArguments]"); return(0); } var args = new List <string>(argsCopy); if (args[0] == "/direct") { args.RemoveAt(0); var executablePath = ExtractPath(args, "executable"); var execServerApp = new ExecServerRemote(executablePath, executablePath, false, false, true); int result = execServerApp.Run(Environment.CurrentDirectory, new Dictionary <string, string>(), args.ToArray(), false, null); return(result); } if (args[0] == "/server") { args.RemoveAt(0); var entryAssemblyPath = ExtractPath(args, "entryAssembly"); var executablePath = ExtractPath(args, "executable"); var cpu = int.Parse(args[0]); args.RemoveAt(0); int result = 0; try { result = RunServer(entryAssemblyPath, executablePath, cpu); } catch (Exception ex) { try { var pid = Process.GetCurrentProcess().Id; var logPath = GetExecServerErrorLogFilePath(executablePath, pid); File.AppendAllText(logPath, $"Unexpected error while trying to run ExecServerApp [{executablePath}]. Exception: {ex}"); } catch (Exception) { // Don't try to log an error } result = 1; } return(result); } else { bool useShadowCache = false; if (args[0] == "/shadow") { args.RemoveAt(0); useShadowCache = true; } var executablePath = ExtractPath(args, "executable"); var workingDirectory = ExtractPath(args, "working directory"); // Collect environment variables var environmentVariables = new Dictionary <string, string>(); foreach (DictionaryEntry environmentVariable in Environment.GetEnvironmentVariables()) { environmentVariables.Add((string)environmentVariable.Key, (string)environmentVariable.Value); } int?debuggerProcessId = null; using (var debugger = VisualStudioDebugger.GetAttached()) { if (debugger != null) { debuggerProcessId = debugger.ProcessId; } } var result = RunClient(executablePath, workingDirectory, environmentVariables, args, useShadowCache, debuggerProcessId); return(result); } }
public static void Main() { AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; EditorPath.EditorTitle = XenkoGameStudio.EditorName; if (IntPtr.Size == 4) { MessageBox.Show("Xenko GameStudio requires a 64bit OS to run.", "Xenko", MessageBoxButton.OK, MessageBoxImage.Error); Environment.Exit(1); } PrivacyPolicyHelper.RestartApplication = RestartApplication; PrivacyPolicyHelper.EnsurePrivacyPolicyXenko30(); // Set the XenkoDir environment variable var installDir = DirectoryHelper.GetInstallationDirectory("Xenko"); Environment.SetEnvironmentVariable("XenkoDir", installDir); // We use MRU of the current version only when we're trying to reload last session. var mru = new MostRecentlyUsedFileCollection(InternalSettings.LoadProfileCopy, InternalSettings.MostRecentlyUsedSessions, InternalSettings.WriteFile, XenkoGameStudio.EditorVersionMajor, false); mru.LoadFromSettings(); EditorSettings.Initialize(); Thread.CurrentThread.Name = "Main thread"; // Install Metrics for the editor using (XenkoGameStudio.MetricsClient = new MetricsClient(CommonApps.XenkoEditorAppId)) { try { // Environment.GetCommandLineArgs correctly process arguments regarding the presence of '\' and '"' var args = Environment.GetCommandLineArgs().Skip(1).ToList(); var startupSessionPath = XenkoEditorSettings.StartupSession.GetValue(); var lastSessionPath = EditorSettings.ReloadLastSession.GetValue() ? mru.MostRecentlyUsedFiles.FirstOrDefault() : null; var initialSessionPath = !UPath.IsNullOrEmpty(startupSessionPath) ? startupSessionPath : lastSessionPath?.FilePath; // Handle arguments for (var i = 0; i < args.Count; i++) { if (args[i] == "/LauncherWindowHandle") { windowHandle = new IntPtr(long.Parse(args[++i])); } else if (args[i] == "/NewProject") { initialSessionPath = null; } else if (args[i] == "/DebugEditorGraphics") { EmbeddedGame.DebugMode = true; } else if (args[i] == "/RenderDoc") { // TODO: RenderDoc is not working here (when not in debug) GameStudioPreviewService.DisablePreview = true; renderDocManager = new RenderDocManager(); } else if (args[i] == "/Reattach") { var debuggerProcessId = int.Parse(args[++i]); if (!System.Diagnostics.Debugger.IsAttached) { using (var debugger = VisualStudioDebugger.GetByProcess(debuggerProcessId)) { debugger?.Attach(); } } } else if (args[i] == "/RecordEffects") { GameStudioBuilderService.GlobalEffectLogPath = args[++i]; } else { initialSessionPath = args[i]; } } RuntimeHelpers.RunModuleConstructor(typeof(Asset).Module.ModuleHandle); //listen to logger for crash report GlobalLogger.GlobalMessageLogged += GlobalLoggerOnGlobalMessageLogged; mainDispatcher = Dispatcher.CurrentDispatcher; mainDispatcher.InvokeAsync(() => Startup(initialSessionPath)); using (new WindowManager(mainDispatcher)) { app = new App { ShutdownMode = ShutdownMode.OnExplicitShutdown }; app.Activated += (sender, eventArgs) => { XenkoGameStudio.MetricsClient?.SetActiveState(true); }; app.Deactivated += (sender, eventArgs) => { XenkoGameStudio.MetricsClient?.SetActiveState(false); }; app.InitializeComponent(); app.Run(); } renderDocManager?.Shutdown(); } catch (Exception e) { HandleException(e, 0); } } }
public void CanAttachToProcessWithDebugger() { var debuggerSetup = new DebuggerSetup(); var logger = new MarkupStreamLogger(TestLog.Default); var debugger = new VisualStudioDebugger(debuggerSetup, logger, null); ProcessStartInfo processStartInfo = CreateProcessStartInfoForDummyProcess(); Process process = Process.Start(processStartInfo); try { Assert.IsFalse(debugger.IsAttachedToProcess(process), "Initially the debugger is not attached."); Assert.AreEqual(AttachDebuggerResult.Attached, debugger.AttachToProcess(process), "Should attach to process."); Assert.IsTrue(debugger.IsAttachedToProcess(process), "Should report that it has attached to process."); Assert.AreEqual(AttachDebuggerResult.AlreadyAttached, debugger.AttachToProcess(process), "Should report that it was already attached to process."); /* This fails because Visual Studio returns "The requested operation is not supported." * It seems to be related to having the Native debugger engine attached. Assert.AreEqual(DetachDebuggerResult.Detached, debugger.DetachFromProcess(process), "Should detach from process."); Assert.IsFalse(debugger.IsAttachedToProcess(process), "Finally the debugger is not attached."); Assert.AreEqual(DetachDebuggerResult.AlreadyDetached, debugger.DetachFromProcess(process), "Should report that it was already detached from process."); */ } finally { process.Kill(); } }
public static void Main() { // wait, are we already running? int waitToClose = 16; while (Process.GetProcessesByName("Focus.GameStudio").Length > 1) { if (waitToClose-- <= 0) { MessageBox.Show("Focus GameStudio is already running! Only one instance is possible at a time.", "Focus", MessageBoxButton.OK, MessageBoxImage.Error); Environment.Exit(1); } Thread.Sleep(250); } AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; EditorPath.EditorTitle = XenkoGameStudio.EditorName; if (IntPtr.Size == 4) { MessageBox.Show(EngineName + " " + GameStudioName + " requires a 64bit OS to run.", "Focus", MessageBoxButton.OK, MessageBoxImage.Error); Environment.Exit(1); } PrivacyPolicyHelper.RestartApplication = RestartApplication; PrivacyPolicyHelper.EnsurePrivacyPolicyXenko30(); // We use MRU of the current version only when we're trying to reload last session. var mru = new MostRecentlyUsedFileCollection(InternalSettings.LoadProfileCopy, InternalSettings.MostRecentlyUsedSessions, InternalSettings.WriteFile); mru.LoadFromSettings(); EditorSettings.Initialize(); Thread.CurrentThread.Name = "EditorGameThread (GameStudio)"; EntityManager.EnforceThreads = false; try { // Environment.GetCommandLineArgs correctly process arguments regarding the presence of '\' and '"' var args = Environment.GetCommandLineArgs().Skip(1).ToList(); var startupSessionPath = XenkoEditorSettings.StartupSession.GetValue(); var lastSessionPath = EditorSettings.ReloadLastSession.GetValue() ? mru.MostRecentlyUsedFiles.FirstOrDefault() : null; var initialSessionPath = !UPath.IsNullOrEmpty(startupSessionPath) ? startupSessionPath : lastSessionPath?.FilePath; // Handle arguments for (var i = 0; i < args.Count; i++) { if (args[i] == "/LauncherWindowHandle") { windowHandle = new IntPtr(long.Parse(args[++i])); } else if (args[i] == "/NewProject") { initialSessionPath = null; } else if (args[i] == "/DebugEditorGraphics") { EmbeddedGame.DebugMode = true; } else if (args[i] == "/RenderDoc") { // TODO: RenderDoc is not working here (when not in debug) GameStudioPreviewService.DisablePreview = true; renderDocManager = new RenderDocManager(); } else if (args[i] == "/Reattach") { var debuggerProcessId = int.Parse(args[++i]); if (!System.Diagnostics.Debugger.IsAttached) { using (var debugger = VisualStudioDebugger.GetByProcess(debuggerProcessId)) { debugger?.Attach(); } } } else if (args[i] == "/RecordEffects") { GameStudioBuilderService.GlobalEffectLogPath = args[++i]; } else { initialSessionPath = args[i]; } } RuntimeHelpers.RunModuleConstructor(typeof(Asset).Module.ModuleHandle); //listen to logger for crash report GlobalLogger.GlobalMessageLogged += GlobalLoggerOnGlobalMessageLogged; mainDispatcher = Dispatcher.CurrentDispatcher; mainDispatcher.InvokeAsync(() => Startup(initialSessionPath)); using (new WindowManager(mainDispatcher)) { app = new App { ShutdownMode = ShutdownMode.OnExplicitShutdown }; app.InitializeComponent(); app.Run(); } renderDocManager?.Shutdown(); } catch (Exception e) { HandleException(e, 0); } }