void AttachClick(object sender, RoutedEventArgs e) { _taskContext.ThrowIfNotOnMainThread(); // Figure out core file path CoreListEntry?coreListEntry = null; if (TabControl.SelectedContent == GameletGroupBox) { coreListEntry = (CoreListEntry?)CoreList.SelectedItem; if (coreListEntry == null) { _dialogUtil.ShowError(ErrorStrings.NoCoreFileSelected); return; } } string coreFilePath = null; bool deleteAfter = false; if (TabControl.SelectedContent == LocalGroupBox) { coreFilePath = LocalCorePathBox.Text; } else if (TabControl.SelectedContent == GameletGroupBox) { var tempPath = Path.GetTempPath(); try { _cancelableTaskFactory .Create(TaskMessages.DownloadingCoreFile, async task => await _remoteFile.GetAsync(new SshTarget(_instance), "/usr/local/cloudcast/core/" + coreListEntry?.Name, tempPath, task)) .RunAndRecord(_actionRecorder, ActionType.CrashDumpDownload); } catch (ProcessException ex) { Trace.WriteLine($"Failed to download core file.{Environment.NewLine}" + $"{ex}"); _dialogUtil.ShowError(ErrorStrings.FailedToDownloadCore(ex.Message), ex.ToString()); return; } coreFilePath = Path.Combine(tempPath, coreListEntry?.Name); deleteAfter = true; } if (string.IsNullOrEmpty(coreFilePath)) { ShowMessage(ErrorStrings.FailedToRetrieveCoreFilePath); return; } // Check if we have a debugger (should always be the case). var vsDebugger = (IVsDebugger4)ServiceProvider.GlobalProvider.GetService(typeof(IVsDebugger)); if (vsDebugger == null) { ShowMessage(ErrorStrings.FailedToStartDebugger); return; } try { _actionRecorder.RecordToolAction(ActionType.CrashDumpAttach, delegate { _taskContext.ThrowIfNotOnMainThread(); VsDebugTargetInfo4[] debugTargets = new VsDebugTargetInfo4[1]; debugTargets[0].dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess; // LaunchDebugTargets4() throws an exception if |bstrExe| and |bstrCurDir| // are empty. Use core path and temp directory as placeholders. debugTargets[0].bstrExe = coreFilePath; debugTargets[0].bstrCurDir = Path.GetTempPath(); var parameters = _paramsFactory.Create(); parameters.CoreFilePath = coreFilePath; parameters.DebugSessionId = _debugSessionMetrics.DebugSessionId; parameters.DeleteCoreFile = deleteAfter; debugTargets[0].bstrOptions = _paramsFactory.Serialize(parameters); debugTargets[0].guidLaunchDebugEngine = YetiConstants.DebugEngineGuid; VsDebugTargetProcessInfo[] processInfo = new VsDebugTargetProcessInfo[debugTargets.Length]; vsDebugger.LaunchDebugTargets4(1, debugTargets, processInfo); }); } catch (COMException except) { Trace.WriteLine($"Failed to start debugger: {except}"); // Both DebugEngine and Visual Studio already show error dialogs if DebugEngine // has to abort while it's attaching, no need to show another dialog in that case. if (except.ErrorCode != VSConstants.E_ABORT) { _dialogUtil.ShowError(ErrorStrings.FailedToStartDebugger, except.ToString()); } } finally { Close(); } }