diff --git a/BeefLibs/corlib/src/Console.bf b/BeefLibs/corlib/src/Console.bf index 3f40cfc6..b34610ff 100644 --- a/BeefLibs/corlib/src/Console.bf +++ b/BeefLibs/corlib/src/Console.bf @@ -90,13 +90,13 @@ namespace System static function void(StringView str) OutString = => OutString_Simple; - [CLink, CallingConvention(.Cdecl)] - static extern void putchar(char8 c); + public static extern void PutChar(char8 c); + public static extern void ReopenHandles(); static void OutString_Simple(StringView str) { for (var c in str.RawChars) - putchar(c); + PutChar(c); } static void OutString_Ex(StringView str) diff --git a/BeefLibs/corlib/src/Windows.bf b/BeefLibs/corlib/src/Windows.bf index 83ac3741..716f3acb 100644 --- a/BeefLibs/corlib/src/Windows.bf +++ b/BeefLibs/corlib/src/Windows.bf @@ -1496,6 +1496,9 @@ namespace System [CLink, CallingConvention(.Stdcall)] public static extern IntBool GetExitCodeThread(Handle process, out int32 exitCode); + [Import("psapi.lib"), CLink, CallingConvention(.Stdcall)] + public static extern int32 GetModuleFileNameExW(Handle process, Handle module, char16* filename, int32 size); + [CLink, CallingConvention(.Stdcall)] public static extern int32 ResumeThread(Handle thread); diff --git a/BeefRT/rt/BfObjects.h b/BeefRT/rt/BfObjects.h index 81522e7e..479d6356 100644 --- a/BeefRT/rt/BfObjects.h +++ b/BeefRT/rt/BfObjects.h @@ -181,6 +181,13 @@ namespace bf Beefy::String GetTypeName(); }; + class Console + { + public: + BFRT_EXPORT static void PutChar(char c); + BFRT_EXPORT static void ReopenHandles(); + }; + class Exception : public Object { diff --git a/BeefRT/rt/Internal.cpp b/BeefRT/rt/Internal.cpp index 87b4c078..c39dd4a6 100644 --- a/BeefRT/rt/Internal.cpp +++ b/BeefRT/rt/Internal.cpp @@ -292,6 +292,26 @@ static void NTAPI TlsFreeFunc(void* ptr) gBfRtCallbacks.Thread_Exiting(); } +void bf::System::Console::PutChar(char c) +{ + putchar(c); +} + +void bf::System::Console::ReopenHandles() +{ + FILE* fDummy; + freopen_s(&fDummy, "CONOUT$", "w", stdout); + freopen_s(&fDummy, "CONOUT$", "w", stderr); + freopen_s(&fDummy, "CONIN$", "r", stdin); +// +// // std::wcout, std::wclog, std::wcerr, std::wcin + HANDLE hConOut = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE hConIn = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + SetStdHandle(STD_OUTPUT_HANDLE, hConOut); + SetStdHandle(STD_ERROR_HANDLE, hConOut); + SetStdHandle(STD_INPUT_HANDLE, hConIn); +} + void bf::System::Runtime::Init(int version, int flags, BfRtCallbacks* callbacks) { BfpSystemInitFlags sysInitFlags = BfpSystemInitFlag_InstallCrashCatcher; diff --git a/BeefTools/BeefCon/src/Program.bf b/BeefTools/BeefCon/src/Program.bf index 3f69de14..683d0f09 100644 --- a/BeefTools/BeefCon/src/Program.bf +++ b/BeefTools/BeefCon/src/Program.bf @@ -12,14 +12,20 @@ class Program BeefConConsoleProvider.Pipe mPipe ~ delete _; WinNativeConsoleProvider mProvider ~ delete _; int32 mPid; + int32 mAttachedPid; + Windows.ProcessHandle mAttachedProcess; + String mAttachedName = new .() ~ delete _; int32 mConid; String mExecStr = new .() ~ delete _; SpawnedProcess mSpawnedProcess ~ delete _; public ~this() { - mSpawnedProcess.Kill(); - mSpawnedProcess.WaitFor(); + if (mSpawnedProcess != null) + { + mSpawnedProcess.Kill(); + mSpawnedProcess.WaitFor(); + } } static mixin GET(var ptr) @@ -105,6 +111,16 @@ class Program case .Update: bool paused = GET!(ptr); mProvider.Update(paused); + case .Attached: + int32 pid = GET!(ptr); + Process process = scope .(); + if (process.GetProcessById(pid) case .Ok) + { + mAttachedPid = pid; + mAttachedName.Set(process.ProcessName); + WinNativeConsoleProvider.SetConsoleTitleW(mAttachedName.ToScopedNativeWChar!()); + mAttachedProcess = Windows.OpenProcess(Windows.PROCESS_ALL_ACCESS, false, mAttachedPid); + } default: } case .Err(let err): @@ -113,22 +129,111 @@ class Program } } + public void ClearConsoleTitle() + { + WinNativeConsoleProvider.SetConsoleTitleW("BeefIDE Debug Console".ToScopedNativeWChar!()); + } + + /*[CLink] + static extern void* freopen (char8 * filename, char8 * mode, void* stream ); + [CLink] + static extern void* stdout;*/ + public void Run() { mPipe = new .(); mPipe.Listen(mPid, mConid); mProvider = new .(); - //mProvider.mHideNativeConsole = false; + mProvider.mHideNativeConsole = !mExecStr.IsEmpty; mProvider.Attach(); + Console.ReopenHandles(); - ProcessStartInfo procInfo = scope ProcessStartInfo(); - procInfo.UseShellExecute = false; - procInfo.SetFileName(mExecStr); + if (!mExecStr.IsEmpty) + { + ProcessStartInfo procInfo = scope ProcessStartInfo(); + procInfo.UseShellExecute = false; + procInfo.SetFileName(mExecStr); - mSpawnedProcess = new SpawnedProcess(); - if (mSpawnedProcess.Start(procInfo) case .Err) - return; + mSpawnedProcess = new SpawnedProcess(); + if (mSpawnedProcess.Start(procInfo) case .Err) + return; + } + else + { + ClearConsoleTitle(); + } + + while (true) + { + // Check BeefIDE process + { + var process = Platform.BfpProcess_GetById(null, mPid, null); + if (process == null) + { + Console.Error.WriteLine("Process closed"); + return; + } + Platform.BfpProcess_Release(process); + } + + MessageLoop(); + + if (mPipe.mFailed) + { + if (mSpawnedProcess == null) + { + DeleteAndNullify!(mPipe); + mPipe = new .(); + mPipe.Listen(mPid, mConid); + } + else + return; + } + + if (!mPipe.mConnected) + Thread.Sleep(20); + + if (mSpawnedProcess != null) + { + if (mSpawnedProcess.WaitFor(0)) + return; + } + + if (mAttachedPid != 0) + { + if ((Windows.GetExitCodeProcess(mAttachedProcess, var exitCode)) && (exitCode != 259)) + { + ClearConsoleTitle(); + + Console.WriteLine(); + Console.WriteLine(scope $"{mAttachedName} (process {mAttachedPid}) exited with code {exitCode}."); + Console.WriteLine("Press any key to close this window..."); + + mAttachedProcess.Close(); + mAttachedProcess = default; + mAttachedPid = 0; + mAttachedName.Clear(); + } + } + + if ((mSpawnedProcess == null) && (mAttachedPid == 0)) + { + if (Console.KeyAvailable) + return; + } + } + } + + /*public void RunHost() + { + mPipe = new .(); + mPipe.Listen(mPid, 0); + + + + WinNativeConsoleProvider.AllocConsole(); + WinNativeConsoleProvider.SetConsoleTitleW("BeefIDE Debug Console".ToScopedNativeWChar!()); while (true) { @@ -146,26 +251,32 @@ class Program if (!mPipe.mConnected) Thread.Sleep(20); - - if (mSpawnedProcess.WaitFor(0)) - return; } - } + }*/ public static int Main(String[] args) { - if (args.Count < 2) + if (args.Count < 1) { - Console.Error.WriteLine("Usage: BeefCon "); + Console.Error.WriteLine("Usage: BeefCon [conid] [exe]"); return 1; } Program pg = scope .(); - pg.mPid = int32.Parse(args[0]); - pg.mConid = int32.Parse(args[1]); - pg.mExecStr.Set(args[2]); - pg.Run(); - + if (args.Count >= 3) + { + pg.mPid = int32.Parse(args[0]); + pg.mConid = int32.Parse(args[1]); + pg.mExecStr.Set(args[2]); + pg.Run(); + } + else + { + pg.mPid = int32.Parse(args[0]); + pg.mConid = -Process.CurrentId; + pg.Run(); + } + return 0; } } \ No newline at end of file diff --git a/BeefySysLib/platform/win/Platform.cpp b/BeefySysLib/platform/win/Platform.cpp index ad9a122d..5a72b9cc 100644 --- a/BeefySysLib/platform/win/Platform.cpp +++ b/BeefySysLib/platform/win/Platform.cpp @@ -1500,7 +1500,7 @@ BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetProcessName(BfpProcess* process, char OUTRESULT(BfpProcessResult_UnknownError); return; } - WCHAR wName[MAX_PATH]; + WCHAR wName[MAX_PATH] = { 0 }; ::GetModuleFileNameExW(hProc, NULL, wName, MAX_PATH); ::CloseHandle(hProc); String name = UTF8Encode(wName); diff --git a/IDE/src/Debugger/DebugManager.bf b/IDE/src/Debugger/DebugManager.bf index 14cf86f3..c0eef4cb 100644 --- a/IDE/src/Debugger/DebugManager.bf +++ b/IDE/src/Debugger/DebugManager.bf @@ -270,7 +270,7 @@ namespace IDE.Debugger static extern char8* Debugger_GetCollectionContinuation(char8* continuationData, int32 callStackIdx, int32 count); [CallingConvention(.Stdcall),CLink] - static extern void Debugger_ForegroundTarget(); + static extern void Debugger_ForegroundTarget(int32 altProcessId); [CallingConvention(.Stdcall),CLink] static extern void CallStack_Update(); @@ -314,6 +314,9 @@ namespace IDE.Debugger [CallingConvention(.Stdcall),CLink] static extern char8* Debugger_GetProcessInfo(); + [CallingConvention(.Stdcall),CLink] + static extern int32 Debugger_GetProcessId(); + [CallingConvention(.Stdcall),CLink] static extern char8* Debugger_GetThreadInfo(); @@ -912,9 +915,9 @@ namespace IDE.Debugger outVal.Append(result); } - public void ForegroundTarget() + public void ForegroundTarget(int32 altProcessId) { - Debugger_ForegroundTarget(); + Debugger_ForegroundTarget(altProcessId); } public void UpdateCallStack() @@ -1079,6 +1082,13 @@ namespace IDE.Debugger outProcessInfo.Append(strPtr); } + public int32 GetProcessId() + { + if (!mIsRunning) + return 0; + return Debugger_GetProcessId(); + } + public void GetThreadInfo(String outThreadInfo) { if (!mIsRunning) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 64c3357a..b39d7d0c 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -426,8 +426,15 @@ namespace IDE public int mSampleRate; } + class OpenDebugConsoleCmd : ExecutionCmd + { + + } + class StartDebugCmd : ExecutionCmd { + public bool mConnectedToConsole; + public int32 mConsoleProcessId; public bool mWasCompiled; public bool mHotCompileEnabled; @@ -9248,6 +9255,73 @@ namespace IDE } } + if (let startDebugCmd = next as StartDebugCmd) + { +#if BF_PLATFORM_WINDOWS + if ((mSettings.mDebugConsoleKind == .Native) && (mSettings.mKeepNativeConsoleOpen)) + { + if (!startDebugCmd.mConnectedToConsole) + { + if (startDebugCmd.mConsoleProcessId == 0) + { + int32 processId = 0; + + List processList = scope .(); + Process.GetProcesses(processList); + defer processList.ClearAndDeleteItems(); + + for (var process in processList) + { + if ((process.ProcessName.Contains("BeefCon.exe")) || (process.ProcessName.Contains("BeefCon_d.exe"))) + { + var title = process.GetMainWindowTitle(.. scope .()); + if (title.EndsWith("Debug Console")) + { + processId = process.Id; + } + } + } + + if (processId == 0) + { + var beefConExe = scope $"{gApp.mInstallDir}/BeefCon.exe"; + + ProcessStartInfo procInfo = scope ProcessStartInfo(); + procInfo.UseShellExecute = false; + procInfo.SetFileName(beefConExe); + procInfo.SetArguments(scope $"{Process.CurrentId}"); + procInfo.ActivateWindow = false; + + var process = scope SpawnedProcess(); + if (process.Start(procInfo) case .Ok) + { + processId = (.)process.ProcessId; + } + } + + startDebugCmd.mConsoleProcessId = processId; + } + + if (startDebugCmd.mConsoleProcessId != 0) + { + if (WinNativeConsoleProvider.AttachConsole(startDebugCmd.mConsoleProcessId)) + { + // Worked + WinNativeConsoleProvider.ClearConsole(); + mConsolePanel.mBeefConAttachState = .Attached(startDebugCmd.mConsoleProcessId); + startDebugCmd.mConnectedToConsole = true; + } + else + { + // Keep trying to attach + return; + } + } + } + } +#endif + } + defer delete next; mExecutionQueue.RemoveAt(0); @@ -9336,6 +9410,19 @@ namespace IDE } else OutputLine("Failed to start debugger"); + +/*#if BF_PLATFORM_WINDOWS + if ((mSettings.mDebugConsoleKind == .Native) && (mSettings.mKeepNativeConsoleOpen)) + { + BeefConConsoleProvider.Pipe pipe = scope .(); + //pipe.Connect(Process.CurrentId, ) + pipe.Connect(123, -startDebugCmd.mConsoleProcessId).IgnoreError(); + + pipe.StartMessage(.Attached); + pipe.Stream.Write((int32)mDebugger.GetProcessId()); + pipe.EndMessage(); + } +#endif*/ } } else if (next is ExecutionQueueCmd) @@ -13781,7 +13868,12 @@ namespace IDE if (mForegroundTargetCountdown > 0) { if ((--mForegroundTargetCountdown == 0) && (mDebugger.mIsRunning)) - mDebugger.ForegroundTarget(); + { + if (mConsolePanel.mBeefConAttachState case .Connected(let processId)) + mDebugger.ForegroundTarget(processId); + else + mDebugger.ForegroundTarget(0); + } } if ((mDebugger != null) && (mExecutionPaused) && (mDebugger.mIsRunning)) @@ -13845,6 +13937,33 @@ namespace IDE DeleteAndNullify!(mLaunchData); mErrorsPanel?.UpdateAlways(); + + if ((mConsolePanel != null) && (mConsolePanel.mBeefConAttachState case .Attached(let consoleProcessId))) + { + if (!mDebugger.mIsRunning) + { + mConsolePanel.Detach(); + } + else + { + int32 debugProcessId = mDebugger.GetProcessId(); + if (debugProcessId != 0) + { + BeefConConsoleProvider.Pipe pipe = scope .(); + pipe.Connect(Process.CurrentId, -consoleProcessId).IgnoreError(); + //pipe.Connect(Process.CurrentId, ) + //pipe.Connect(123, -consoleProcessId).IgnoreError(); + + pipe.StartMessage(.Attached); + pipe.Stream.Write(debugProcessId); + pipe.EndMessage(); + mConsolePanel.Detach(); + + mConsolePanel.mBeefConAttachState = .Connected(consoleProcessId); + mDebugger.ForegroundTarget(consoleProcessId); + } + } + } } public void ShowPassOutput(BfPassInstance bfPassInstance) diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index f487edcb..7fc911c7 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -1122,6 +1122,7 @@ namespace IDE public String mWindowsTerminal = new .("Powershell") ~ delete _; public ConsoleKind mDebugConsoleKind; public bool mAlwaysEnableConsole; + public bool mKeepNativeConsoleOpen; public String mEmscriptenPath = new .() ~ delete _; public bool mEnableDevMode; public TutorialsFinished mTutorialsFinished = .(); @@ -1184,6 +1185,7 @@ namespace IDE sd.Add("WindowsTerminal", mWindowsTerminal); sd.Add("DebugConsole", mDebugConsoleKind); sd.Add("AlwaysEnableConsole", mAlwaysEnableConsole); + sd.Add("KeepNativeConsoleOpen", mKeepNativeConsoleOpen); } using (sd.CreateObject("Wasm")) sd.Add("EmscriptenPath", mEmscriptenPath); @@ -1279,6 +1281,7 @@ namespace IDE sd.Get("WindowsTerminal", mWindowsTerminal); mDebugConsoleKind = sd.GetEnum("DebugConsole", .Native); mAlwaysEnableConsole = sd.GetBool("AlwaysEnableConsole"); + mKeepNativeConsoleOpen = sd.GetBool("KeepNativeConsoleOpen"); } using (sd.Open("Wasm")) sd.Get("EmscriptenPath", mEmscriptenPath); diff --git a/IDE/src/ui/ConsolePanel.bf b/IDE/src/ui/ConsolePanel.bf index 884f1f0d..022179fe 100644 --- a/IDE/src/ui/ConsolePanel.bf +++ b/IDE/src/ui/ConsolePanel.bf @@ -281,6 +281,13 @@ class ConsolePanel : Panel } } + public enum BeefConAttachState + { + case None; + case Attached(int32 processId); + case Connected(int32 processId); + } + public ConsoleProvider mConsoleProvider ~ delete _; public DarkCheckBox mMousePassthroughCB; public DarkCheckBox mPauseCB; @@ -290,6 +297,7 @@ class ConsolePanel : Panel public int32 mCellHeight; public (Position start, Position end)? mSelection; public Position? mClickPos; + public BeefConAttachState mBeefConAttachState; public bool Paused { @@ -781,6 +789,14 @@ class ConsolePanel : Panel public void Detach() { + if (mBeefConAttachState case .Attached) + { +#if BF_PLATFORM_WINDOWS + WinNativeConsoleProvider.FreeConsole(); +#endif + mBeefConAttachState = .None; + } + if (!mConsoleProvider.Attached) return; mConsoleProvider.Detach(); diff --git a/IDE/src/ui/SettingsDialog.bf b/IDE/src/ui/SettingsDialog.bf index 9eae565f..340ed4bb 100644 --- a/IDE/src/ui/SettingsDialog.bf +++ b/IDE/src/ui/SettingsDialog.bf @@ -181,6 +181,7 @@ namespace IDE.ui AddPropertiesItem(category, "Windows Terminal", "mWindowsTerminal"); AddPropertiesItem(category, "Debug Console", "mDebugConsoleKind"); AddPropertiesItem(category, "Always Enable Console", "mAlwaysEnableConsole"); + AddPropertiesItem(category, "Keep Native Console Open", "mKeepNativeConsoleOpen"); category.Open(true, true); } diff --git a/IDE/src/util/ConsoleProvider.bf b/IDE/src/util/ConsoleProvider.bf index 4fa429c1..9e485ab7 100644 --- a/IDE/src/util/ConsoleProvider.bf +++ b/IDE/src/util/ConsoleProvider.bf @@ -250,10 +250,13 @@ class WinNativeConsoleProvider : ConsoleProvider #if BF_PLATFORM_WINDOWS [CLink, CallingConvention(.Stdcall)] - public static extern void AllocConsole(); + public static extern Windows.IntBool AllocConsole(); [CLink, CallingConvention(.Stdcall)] - public static extern void AttachConsole(int processId); + public static extern void SetConsoleTitleW(char16* title); + + [CLink, CallingConvention(.Stdcall)] + public static extern Windows.IntBool AttachConsole(int processId); [CLink, CallingConvention(.Stdcall)] public static extern void FreeConsole(); @@ -290,6 +293,15 @@ class WinNativeConsoleProvider : ConsoleProvider [CLink] public static extern Windows.IntBool ReadConsoleInputW(Windows.Handle handle, INPUT_RECORD* eventsPtr, int32 eventCount, out int32 numEventsRead); + + [CLink] + public static extern Windows.IntBool SetConsoleCursorPosition(Windows.Handle handle, POINT pos); + + [CLink] + public static extern Windows.IntBool FillConsoleOutputCharacterW(Windows.Handle handle, char16 char, int32 length, POINT writeCoord, out int32 numCharsWritten); + + [CLink] + public static extern Windows.IntBool FillConsoleOutputAttribute(Windows.Handle handle, uint16 attribute, int32 length, POINT writeCoord, out int32 numCharsWritten); #endif ScreenInfo mScreenInfo ~ delete _; @@ -789,6 +801,58 @@ class WinNativeConsoleProvider : ConsoleProvider { return (mScreenInfo != null) ? mScreenInfo.mColorTable[i] : 0xFF000000; } + + public static void ClearConsole() + { + var outHandle = Console.[Friend]GetStdHandle(Console.STD_OUTPUT_HANDLE); + + POINT coordScreen = default; // home for the cursor + int32 cCharsWritten; + CONSOLE_SCREEN_BUFFER_INFOEX csbi = default; + csbi.mSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + + // Get the number of character cells in the current buffer. + if (!GetConsoleScreenBufferInfoEx(outHandle, ref csbi)) + { + return; + } + + let dwConSize = (int32)csbi.mWidth * csbi.mHeight; + + // Fill the entire screen with blanks. + if (!FillConsoleOutputCharacterW(outHandle, // Handle to console screen buffer + ' ', // Character to write to the buffer + dwConSize, // Number of cells to write + coordScreen, // Coordinates of first cell + out cCharsWritten)) // Receive number of characters written + { + return; + } + + // Get the current text attribute. + if (!GetConsoleScreenBufferInfoEx(outHandle, ref csbi)) + { + return; + } + + // Set the buffer's attributes accordingly. + if (!FillConsoleOutputAttribute(outHandle, // Handle to console screen buffer + csbi.wAttributes, // Character attributes to use + dwConSize, // Number of cells to set attribute + coordScreen, // Coordinates of first cell + out cCharsWritten)) // Receive number of characters written + { + return; + } + + // Put the cursor at its home coordinates. + SetConsoleCursorPosition(outHandle, coordScreen); + } + + public void Clear() + { + ClearConsole(); + } } class BeefConConsoleProvider : ConsoleProvider @@ -807,7 +871,8 @@ class BeefConConsoleProvider : ConsoleProvider MouseUp, MouseWheel, ScrollTo, - Update + Update, + Attached } public class Pipe diff --git a/IDEHelper/Compiler/CeDebugger.cpp b/IDEHelper/Compiler/CeDebugger.cpp index ea918206..ee674066 100644 --- a/IDEHelper/Compiler/CeDebugger.cpp +++ b/IDEHelper/Compiler/CeDebugger.cpp @@ -409,7 +409,7 @@ void CeDebugger::ContinueDebugEvent() mCeMachine->mDebugEvent.Set(); } -void CeDebugger::ForegroundTarget() +void CeDebugger::ForegroundTarget(int altProcessId) { } @@ -4361,6 +4361,11 @@ String CeDebugger::GetProcessInfo() return String(); } +int CeDebugger::GetProcessId() +{ + return 0; +} + DebugVisualizerEntry* CeDebugger::FindVisualizerForType(BfType* dbgType, Array* wildcardCaptures) { auto ceModule = mCeMachine->mCeModule; diff --git a/IDEHelper/Compiler/CeDebugger.h b/IDEHelper/Compiler/CeDebugger.h index 61f218bb..027921ea 100644 --- a/IDEHelper/Compiler/CeDebugger.h +++ b/IDEHelper/Compiler/CeDebugger.h @@ -324,7 +324,7 @@ public: virtual String GetDbgAllocInfo() override; virtual void Update() override; virtual void ContinueDebugEvent() override; - virtual void ForegroundTarget() override; + virtual void ForegroundTarget(int altProcessId) override; virtual Breakpoint* CreateBreakpoint(const StringImpl& fileName, int lineNum, int wantColumn, int instrOffset) override; virtual Breakpoint* CreateMemoryBreakpoint(intptr addr, int byteCount) override; virtual Breakpoint* CreateSymbolBreakpoint(const StringImpl& symbolName) override; @@ -359,6 +359,7 @@ public: virtual String GetAutoLocals(int callStackIdx, bool showRegs) override; virtual String CompactChildExpression(const StringImpl& expr, const StringImpl& parentExpr, int callStackIdx) override; virtual String GetProcessInfo() override; + virtual int GetProcessId() override; virtual String GetThreadInfo() override; virtual void SetActiveThread(int threadId) override; virtual int GetActiveThread() override; diff --git a/IDEHelper/DebugManager.cpp b/IDEHelper/DebugManager.cpp index 385417a3..aa1709a6 100644 --- a/IDEHelper/DebugManager.cpp +++ b/IDEHelper/DebugManager.cpp @@ -1363,9 +1363,9 @@ BF_EXPORT const char* BF_CALLTYPE Debugger_GetCollectionContinuation(const char* return outString.c_str(); } -BF_EXPORT void BF_CALLTYPE Debugger_ForegroundTarget() +BF_EXPORT void BF_CALLTYPE Debugger_ForegroundTarget(int altProcessId) { - gDebugger->ForegroundTarget(); + gDebugger->ForegroundTarget(altProcessId); //BOOL worked = EnumThreadWindows(gDebugger->mProcessInfo.dwThreadId, WdEnumWindowsProc, 0); //BF_ASSERT(worked); @@ -1378,6 +1378,11 @@ BF_EXPORT const char* BF_CALLTYPE Debugger_GetProcessInfo() return outString.c_str(); } +BF_EXPORT int BF_CALLTYPE Debugger_GetProcessId() +{ + return gDebugger->GetProcessId(); +} + BF_EXPORT const char* BF_CALLTYPE Debugger_GetThreadInfo() { String& outString = *gTLStrReturn.Get(); diff --git a/IDEHelper/Debugger.h b/IDEHelper/Debugger.h index a58701d8..851bd19a 100644 --- a/IDEHelper/Debugger.h +++ b/IDEHelper/Debugger.h @@ -285,7 +285,7 @@ public: virtual String GetDbgAllocInfo() = 0; virtual void Update() = 0; virtual void ContinueDebugEvent() = 0; - virtual void ForegroundTarget() = 0; + virtual void ForegroundTarget(int altProcessId) = 0; virtual Breakpoint* CreateBreakpoint(const StringImpl& fileName, int lineNum, int wantColumn, int instrOffset) = 0; virtual Breakpoint* CreateMemoryBreakpoint(intptr addr, int byteCount) = 0; virtual Breakpoint* CreateSymbolBreakpoint(const StringImpl& symbolName) = 0; @@ -320,6 +320,7 @@ public: virtual String GetAutoLocals(int callStackIdx, bool showRegs) = 0; virtual String CompactChildExpression(const StringImpl& expr, const StringImpl& parentExpr, int callStackIdx) = 0; virtual String GetProcessInfo() = 0; + virtual int GetProcessId() = 0; virtual String GetThreadInfo() = 0; virtual void SetActiveThread(int threadId) = 0; virtual int GetActiveThread() = 0; diff --git a/IDEHelper/WinDebugger.cpp b/IDEHelper/WinDebugger.cpp index 87d1ec05..8c68ba15 100644 --- a/IDEHelper/WinDebugger.cpp +++ b/IDEHelper/WinDebugger.cpp @@ -3055,6 +3055,8 @@ void WinDebugger::ContinueDebugEvent() static BOOL CALLBACK WdEnumWindowsProc(HWND hwnd, LPARAM lParam) { + int wantProcessId = lParam; + HWND owner = GetWindow(hwnd, GW_OWNER); if (!IsWindowVisible(hwnd)) return TRUE; @@ -3062,7 +3064,7 @@ static BOOL CALLBACK WdEnumWindowsProc(HWND hwnd, LPARAM lParam) DWORD processId = 0; DWORD threadId = GetWindowThreadProcessId(hwnd, &processId); - if (processId != ((WinDebugger*)gDebugger)->mProcessInfo.dwProcessId) + if (processId != wantProcessId) return TRUE; while (true) @@ -3080,8 +3082,12 @@ static BOOL CALLBACK WdEnumWindowsProc(HWND hwnd, LPARAM lParam) return TRUE; } -void WinDebugger::ForegroundTarget() +void WinDebugger::ForegroundTarget(int altProcessId) { + int wantProcessId = altProcessId; + if (wantProcessId == 0) + wantProcessId = ((WinDebugger*)gDebugger)->mProcessInfo.dwProcessId; + HWND hwnd = ::GetForegroundWindow(); if (hwnd != INVALID_HANDLE_VALUE) { @@ -3090,8 +3096,8 @@ void WinDebugger::ForegroundTarget() if (processId == ((WinDebugger*)gDebugger)->mProcessInfo.dwProcessId) return; // Already good } - - EnumWindows(WdEnumWindowsProc, 0); + + EnumWindows(WdEnumWindowsProc, wantProcessId); } static int gFindLineDataAt = 0; @@ -10977,6 +10983,14 @@ String WinDebugger::GetProcessInfo() return retStr; } +int WinDebugger::GetProcessId() +{ + AutoCrit autoCrit(mDebugManager->mCritSect); + if (!mThreadList.IsEmpty()) + return mThreadList[0]->mProcessId; + return mDbgProcessId; +} + String WinDebugger::GetThreadInfo() { AutoCrit autoCrit(mDebugManager->mCritSect); diff --git a/IDEHelper/WinDebugger.h b/IDEHelper/WinDebugger.h index 9feb2784..5aab5afc 100644 --- a/IDEHelper/WinDebugger.h +++ b/IDEHelper/WinDebugger.h @@ -598,7 +598,7 @@ public: virtual String GetDbgAllocInfo() override; virtual void Update() override; virtual void ContinueDebugEvent() override; - virtual void ForegroundTarget() override; + virtual void ForegroundTarget(int altProcessId) override; virtual Breakpoint* CreateBreakpoint(const StringImpl& fileName, int lineNum, int wantColumn, int instrOffset) override; virtual Breakpoint* CreateMemoryBreakpoint(intptr addr, int byteCount) override; virtual Breakpoint* CreateSymbolBreakpoint(const StringImpl& symbolName) override; @@ -630,6 +630,7 @@ public: virtual String GetAutoLocals(int callStackIdx, bool showRegs) override; virtual String CompactChildExpression(const StringImpl& expr, const StringImpl& parentExpr, int callStackIdx) override; virtual String GetProcessInfo() override; + virtual int GetProcessId() override; virtual String GetThreadInfo() override; virtual void SetActiveThread(int threadId) override; virtual int GetActiveThread() override;