1

困扰了我很长时间的事情我终于决定在stackoverflow上问:

为什么在 DEBUG 模式下执行 Windows 窗体项目时,当我单击暂停按钮时,它总是会在Application.Run上停止?

 Application.Run(new FormGuiV2()); // pressing pause stops here

这对我来说似乎是一个缺陷。为什么它不在正在执行的实际代码行上暂停?在调试时停在栈顶是没有帮助的。我想我一定是错误地使用了调试器?

为了解决这个问题,我必须知道正在执行哪些代码行并放置一个调试点,这很容易出错,而且有时跟踪我想要放置调试点的位置很耗时。

我想知道单击暂停按钮并让它实际停止在执行代码行的正确方法。

谢谢

4

3 回答 3

6

它不会,它会在您发出 Debug + Break 命令时停止在任何活动的代码处。您可以在调试器的调用堆栈窗口中看到。然而,你会中断任何你自己正在执行的代码的可能性非常小,你的程序花费 99% 的时间等待 Windows 告诉它发生了一些有趣的事情。这使得调用堆栈通常看起来像:

    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData) + 0x444 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) + 0x155 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x4a bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) + 0x31 bytes  
>   WindowsFormsApplication1.exe!WindowsFormsApplication1.Program.Main() Line 16 + 0x1d bytes   C#
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x6b bytes    
    Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x27 bytes  
    mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x6f bytes   
    mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0xa7 bytes  
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x16 bytes  
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x41 bytes    
    mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes   
    [Native to Managed Transition]  

请注意 FPushMessageLoop() 方法如何位于堆栈跟踪之上。这是 Windows GUI 应用程序中著名的消息循环,即接收 Windows 通知的应用程序。如果您还启用了非托管调试,那么您会看到更多,核心 GetMessage() winapi 函数是消息循环的重要组成部分。

请注意>堆栈跟踪中的标记。这就是您正在谈论的代码行。您看到它的原因是因为它上面的代码是 .NET 框架的一部分。如果你没有安装参考源,你就没有它的源代码。

所以调试器只是沿着堆栈向下走,寻找任何相关的源代码来显示。并且不可避免地会出现在 Program.cs 中的 Main() 方法中,即 Application.Run() 调用。

在 GUI 应用程序中获得有用的中断需要设置断点。

于 2013-07-12T21:57:54.117 回答
2

启动应用程序的主线程将位于Application.Run,否则应用程序将关闭。旋转Application.RunUI 线程和可能的其他线程,这是您预期的位置。

应用程序的主线程是调试器总是跳转到的地方。那是应该始终存在的一个线程,因为否则该进程将关闭。

当您打开 Debug->Windows->Threads 窗口时,您可以切换到其他线程,您会看到其中一个线程实际上已暂停在您可能期望的位置。

请参阅:http: //msdn.microsoft.com/en-us/library/w15yf86f.aspx

于 2013-07-12T21:53:54.487 回答
2

这很可能正在执行的实际代码行。

嗯,实际上,方法内部的代码Application.Run正在执行,但该代码是 .NET Framework 库的一部分,并且您没有打开 .NET 源单步执行。如果您这样做了,它会将您转储到 WinForms 库代码迷宫中的某个地方,您可能也不会觉得这很有帮助。

这个谜团背后的秘密在于,Windows 应用程序大部分时间都在循环等待,根据用户输入和其他事件等待来自操作系统的消息。这称为消息循环。.NET Framework(和其他框架)为您抽象了这一切,在内部处理这些消息并以其他方式(例如通过引发事件)向您公开重要内容。但这一切仍在幕后进行。

您必须恰到好处地计时才能随机点击“暂停”按钮并在某处进入用户代码。大多数情况下,当您中断执行时,代码处于“空闲”点,等待用户输入或其他操作。因此,断点通常是一种更好、更易于管理的方法。

于 2013-07-12T21:55:04.860 回答