在调试时,有时您需要附加已经运行的进程,而不是仅在调试器中启动应用程序.
我自己常常放入Sleep()或MessageBox调用,以便更容易连接调试器.我担心其中一些可能最终会被提交给源代码控制.
在延迟足够时间的同时避免这种情况的最佳方法是什么,以便可以将调试器连接到正在运行的进程?
用#ifdef _DEBUG
一种方式保护睡眠或消息框,但我想知道是否有更好的方法.
睡眠时,您还有一个问题,即您可能无法及时附着.使用MessageBox,您可能遇到远程调试或调试没有可见GUI的进程的问题(示例在Vista上作为服务运行)
你可以使用DebugBreak,检查这些链接:
http://www.epsilon-delta.net/articles/vc6_debug.html#breaking-with-debugbreak
http://blogs.msdn.com/calvin_hsia/archive/2006/08/25/724572.aspx
要在特定点附加调试器,您有以下几种选择:
最简单的只是调用DebugBreak
,它几乎相当于__asm int 3
,但也适用于其他架构(如果我没记错的话,MSVC for x64不允许内联汇编).这将打开即时调试器窗口,您将能够从已注册的调试器(即Visual Studio)中进行选择以附加到该进程.
或者,您可以引入一个调用Sleep
,让您有机会附加调试器.您应该使用#ifdef _DEBUG
此方法,以确保您实际上并未附带此代码.
一个问题:为什么不能从IDE运行代码?它是一个服务或IIS加载的DLL或类似的?
在这种情况下,您可以签出ImageFileExecutionOptions
注册表项,该注册表项允许您在进程启动时附加调试器.
如果为此使用cdb,则可以将其配置为WinDbg实例的服务器或客户端,并以此方式进行调试.我以前使用WinDbg作为内核调试器,并使用ImageFileExecutionOptions从ntsd -d
命名进程开始,这样做了.这会导致WinDbg进入用户模式.这有时是一种有用的技术.
另一种变体,我有时会使用它
while( !::IsDebuggerPresent() ) ::Sleep( 100 ); // to avoid 100% CPU load
它应该静静等待,直到您将调试器附加到进程.
Freddy和Reoa有正确的解决方案.但我想添加一个不使用MessageBox的原因.
仅显示MessageBox会部分停止您的应用程序.因为您正在显示UI,所以程序中至少有一个线程仍在运行消息泵.因此,如果您的代码执行以下任何操作.
通过Windows消息进行通信
有非平凡的用户界面
是多线程的
实际上,您将在一个状态下请求调试器,但在完全不同的状态下附加到您的程序.这可能会导致令人困惑的情况和错误.
我们最近对我们的代码库进行了更改,以便永远不会显示MessageBox,以便为此提供便利.它会为非平凡的应用程序产生非常糟糕的行为.