非托管代码中 System.Diagnostics.Debugger.Launch() 的等价物是啥?
Posted
技术标签:
【中文标题】非托管代码中 System.Diagnostics.Debugger.Launch() 的等价物是啥?【英文标题】:What is the equivalent of System.Diagnostics.Debugger.Launch() in unmanaged code?非托管代码中 System.Diagnostics.Debugger.Launch() 的等价物是什么? 【发布时间】:2013-12-02 21:08:44 【问题描述】:当满足某些条件时,我需要从我的本机 C++ 程序启动调试器。在 C# 中,我只调用 System.Diagnostics.Debugger.Launch()。我认为 Win32 DebugBreak() 调用会做我想做的事,但如果没有调试器,它只会终止应用程序。
如何从本机代码启动调试器的新实例(著名的“可能的调试器”对话框)?甚至可能吗?我可以尝试使用 COM 来创建一个新的 Visual Studio 实例,但它有点复杂,而且还会将我锁定到特定版本的 VS。
【问题讨论】:
我也遇到了同样的问题,也没有找到解决办法。我终于解决了我的问题,方法是将 System.Diagnostics.Debugger.Launch 调用放在混合模式 DLL 中,将该函数导出为非托管函数,然后使用 LoadLibrary 从我的非托管应用程序中显式加载库。 这很酷,但当您的应用程序托管 CLR 时就不行了。加载托管库有点搞砸了整个托管的事情 【参考方案1】:我发现可以直接用当前进程的PID调用vsjitdebugger.exe。确保在 Visual Studio 中的 Tools->Options->Debugging->Just-in-Time 中选择了“Native”。
这是启动调试器的 C++ 代码。它使用各种 Win32 API 的 UNICODE 版本。我得到系统目录,因为 CreateProcess() 不使用 PATH。
bool launchDebugger()
// Get System directory, typically c:\windows\system32
std::wstring systemDir(MAX_PATH+1, '\0');
UINT nChars = GetSystemDirectoryW(&systemDir[0], systemDir.length());
if (nChars == 0) return false; // failed to get system directory
systemDir.resize(nChars);
// Get process ID and create the command line
DWORD pid = GetCurrentProcessId();
std::wostringstream s;
s << systemDir << L"\\vsjitdebugger.exe -p " << pid;
std::wstring cmdLine = s.str();
// Start debugger process
STARTUPINFOW si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcessW(NULL, &cmdLine[0], NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return false;
// Close debugger process handles to eliminate resource leak
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
// Wait for the debugger to attach
while (!IsDebuggerPresent()) Sleep(100);
// Stop execution so the debugger can take over
DebugBreak();
return true;
【讨论】:
太棒了!这正是我调试进程外 COM 服务器所需要的。 我目前正在尝试在托管应用程序中托管 CoreCLR,我发现这是让混合调试正常工作的唯一方法。从 VS 混合调试开始会导致调试器崩溃,仅调用 DebugBreak 会导致死锁,System.Diagnostics.Debugger.Launch
也是如此。
经过长时间的挣扎,这救了我。我还必须在调试器设置中设置“Native”,并将工作目录和输出设置到创建进程的应用程序(通过 QProcess)。
不错!我想当用户在 vsjitdebugger 对话框上单击“取消”时,没有什么好办法不永远等待吗?无需为要附加的调试器引入竞争。我想我们能做的最好的事情就是等待进程退出,然后在调试器附加自身时稍等片刻(例如超时 1 分钟)?
回答我的最后一条评论:您可以等待进程以 exit-code 0 退出,然后等待调试器附加。我找不到任何文档,但是当用户单击取消或 X 关闭对话框时,测试退出代码为 262320。【参考方案2】:
DebugBreak() 很好,__debugbreak() 内在函数也很好。他们都做同样的事情,他们用 STATUS_BREAKPOINT 异常使程序崩溃。然后触发 Windows 错误报告对话框,它会滚动一段时间,然后提供调试按钮。然后启动调试器。
您可能犯的唯一真正错误是等待 WER 对话框的时间不够长,并且太快按下取消。或者禁用 WER。如果根本没有可用的调试器,是的,你不能选择一个。
重要的注册表项是 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\Debugger。通常设置为 vsjitdebugger.exe,即显示“可能的调试器”对话框的那个。
【讨论】:
不。 DebugBreak() 导致错误对话框“foobar.exe 停止工作,Windows 正在检查问题的解决方案”。在任何时候,我都无法选择调试器。至少这是在 Windows 7 上发生的情况。 这就是我提到的 WER 对话框。点击你的脚,不要点击取消。并检查该注册表项。 确实,如果您等待一段时间然后单击“调试”,您就可以选择一个调试器。应该更有耐心。但是,System.Diagnostics.Debugger.Launch() 会立即进入调试器选择对话框,无需等待 45 秒。另一个复杂因素是我的应用程序没有被用户直接调用。如果是这样,我不需要技巧来附加调试器。如果我使用 DebugBreak(),父应用程序似乎认为子进程刚刚死掉并放弃了我,但我还没有深入调查。 叹息,你为什么在你的问题中忽略了这些重要的细节?使用this approach instead。 谢谢。我知道这个。另一个重要的细节 :) 是启动了多个同名进程。我不想调试所有这些,只有在满足某些条件时才需要启动调试器。我听说过一种解决方法,它建议创建一个设置了图像文件执行选项的 DLL,并在需要启动调试器时加载它。说了这么多,仅启动调试器选择对话框的能力将非常有帮助。毕竟,.NET 以某种方式做到了,所以它一定是可能的。【参考方案3】:从您的 Visual C++ 代码中调用_CrtDbgBreak()
,重新编译,运行您的程序,然后从对话框中选择调试程序。
【讨论】:
以上是关于非托管代码中 System.Diagnostics.Debugger.Launch() 的等价物是啥?的主要内容,如果未能解决你的问题,请参考以下文章
等效于 System.Diagnostics.StackTrace 的 C# 可移植类库
如何将 System.Diagnostics.Trace 和 System.Diagnostics.Debug 消息记录到 NLog 文件?