【问题标题】:Debugging into MFC header code does not work with Visual Studio 2019调试 MFC 标头代码不适用于 Visual Studio 2019
【发布时间】:2022-01-07 22:40:19
【问题描述】:

TL;DR:调试 MFC (CString) 标头代码在我的机器上和两台 上都不起作用,就我而言可以看出这是由于这些头文件的特殊编译方式。

通过反汇编输入时单步执行 MFC 标头代码有效,但设置 brealpoints 无效。

我正在寻找解决方法或至少确认我的分析。


系统:

  • Visual Studio 2019 专业版 16.9.6
  • Windows 10 / 1809 企业版 LTSC

设置:(我很抱歉这太长了。)

  • 创建 Visual Studio 2019 示例 MFC 应用程序项目(SDI 应用程序)

  • 确保Enable Just My Code在选项 -> 调试 -> 常规下关闭

  • 将构建配置设置为 Debug/x64(没有区别,但让我们都留在同一页面上)

  • 导航到MFCApplication1.cpp -> CMFCApplication1App::InitInstance()

  • 像这样插入一个 CString 初始化:

      ...
      InitCommonControlsEx(&InitCtrls);
    
      CWinAppEx::InitInstance(); // please put breakpoint 1 here
    
      // Add this line and set breakpoints
      CString this_is_text(L"Debugging into CString Header does not work!"); // breakpoint 2 here
    

现在,你可以在调试器下启动程序了,你应该在第一个断点处停止:

现在,确保所有符号都已加载,最简单的方法是通过调用堆栈完成:

只需选择调用堆栈窗口中的所有行,然后在上下文菜单中点击加载符号。之后调用堆栈大致如下所示:

     >  MFCApplication1.exe!CMFCApplication1App::InitInstance() Line 75 C++
        mfc140ud.dll!AfxWinMain(HINSTANCE__ * hInstance=0x00007ff7b5070000, ...) Line 37    C++
        MFCApplication1.exe!wWinMain(HINSTANCE__ * hInstance=0x00007ff7b5070000, ...) Line 26   C++
        MFCApplication1.exe!invoke_main() Line 123  C++
        MFCApplication1.exe!__scrt_common_main_seh() Line 288   C++
        MFCApplication1.exe!__scrt_common_main() Line 331   C++
        MFCApplication1.exe!wWinMainCRTStartup(void * __formal=0x000000c2b7084000) Line 17  C++
        kernel32.dll!BaseThreadInitThunk()  Unknown
        ntdll.dll!RtlUserThreadStart()  Unknown

现在,您可以尝试 stepping-into(可能是 F11)CWinAppEx::InitInstance() 功能,它应该工作没有问题,让您登陆mfc140ud.dll!CWinApp::InitInstance() Line 394 - 这个没问题。

再次退出,然后尝试进入CString ctor:

这在我的机器上不起作用!

我可以做的是(从上面的观点)切换到反汇编视图,进入calls 并以这种方式进入标题代码:

然后我可以成功地单步执行(但永远不会进入)MFC 标头代码。尝试设置断点会报错:

当前不会命中断点。没有调试器代码类型的可执行代码与此行相关联。 可能的原因包括...

C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29910\atlmfc\include\cstringt.h

这就是我所在的地方。

分析

我们可以从 MFC 代码中看到,我们可以进入“常规”cpp 代码,但只要我们尝试进入(或设置断点)此 @ 内的代码987654342@它坏了。

这里很奇怪:这是模板header代码,但执行的代码(如反汇编所示)仍然不在用户模块中,而是在mfc###.dll!我认为他们对预处理器做了一些聪明的技巧(参见defined(_MFC_DLL_BLD) 和一些类似的东西),这使得头文件的这种多用途成为可能,也许这也是破坏调试器的原因。

问题

  • 这是一个已知问题吗?所有 VS2019 安装都会出现这种情况吗?我的设置有什么特殊之处吗?
  • 也许在较新的 VS 版本中已修复?
  • 如果这确实被破坏了,除了在进入 MFC 标头时不断切换到反汇编视图之外,还有什么可用的解决方法。

这里最有趣的答案实际上是关于为什么会中断 - 调试器在哪里感到困惑?这是调试库代码时 re-define-ing 代码的普遍问题吗?

【问题讨论】:

  • Martin,您在使用 Visual Assist 吗?如果是,则任何解决方案都不起作用。即使您不使用 Visual Assist,其中一些也无法工作。
  • @JohnCz - 是的,我们使用 VSAssist。不确定该工具将如何获得报酬。但是调试器中的断点。你的评论有太多的负面影响。我没有解析所有的...不是;-P

标签: c++ visual-studio debugging mfc pdb


【解决方案1】:

分析在某些时候偏离了方向,但我们终于在这里找到了问题的一部分:

Require source files to exactly match the original version 选项:

是问题所在,但以一种非常奇特的方式:

当您不需要匹配源文件时(即禁用此默认选项),则会出现 OP 的错误行为:调试器无法再将符号与 cstringt.h 文件匹配。

不幸的是,我在两台机器上都禁用了此功能。拉入第三台机器表明我们可以设置断点(尽管 F11 仍然不起作用),通过比较 VS 设置的 xml 导出我们发现这是不同的。

所以,长话短说:对我们来说,能够在(未修改的!)MFC 标头中设置断点,需要我们启用Require source files to exactly match .. 选项。

如果该选项被禁用,这意味着调试器的行为更为宽松,则它不再起作用。

而且,是的,我们仔细检查了它在C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29910\atlmfc\include\cstringt.h 处始终是同一个源文件

step-into/F11 的谜团仍然存在,但我想这最好单独提出一个问题。

【讨论】:

    【解决方案2】:

    MSVC 附带的源不匹配。

    我认为会发生这种情况,因为 DLL 已使用 Windows Update 或新的 vcredist 进行了更新,但 Visual Studio 包含的内容未更新。如果使用/MT/MTd 构建并静态链接MFC,则问题不会持续存在。

    如果你在乎的话,也许可以向http://developercommunity.visualstudio.com报告。

    解决方法 1

    执行@selbie 描述的步骤:

    1. 在我要单步执行的代码行上设置断点。
    2. 何时 到达断点,在编辑器窗口中右键单击并选择 “去拆卸”。
    3. 在反汇编模式下,跨步直到到达 call 声明。 [...] 你 可以通过再次右键单击并选择退出反汇编模式 “转到源代码”。

    (略过与本题无关的部分)

    然后手动拾取header的位置,调试器会告诉它不匹配。虽然差异似乎微不足道,所以标题是可用的。

    解决方法 2

    静态链接 MFC,使用 /MT/MTd 编译

    解决方法 3

    ATL 有一个类似的CString 不会出现此问题:

    #include <atlbase.h>
    #include <atlstr.h>
    
    int main() {
        ATL::CString this_is_text("Debugging into CString header works");
    }
    

    【讨论】:

    • 如果 MFC 的支持库使用 Windows Update 进行更新,我会感到惊讶。您是否已证实是这种情况?由于预处理器宏和类模板的混合,我倾向于 MFC 的 CString 实现混淆 Visual Studio 的调试器。
    • @IInspectable,可能不适用于 Windows 更新,但肯定适用于 Visual Studio Redistributables。我不认为调试器会被模板混淆,因为静态链接解决了这个问题,并且与一些标准库部分(如std::function/std::bind)相比,CString 并不是最做作的部分。 (调试器本身不解析任何东西,它依赖于 .pdb 文件和其中的行号/标识符名称)
    • 我认为您总是需要/MTd 来调试进入 MFC 的步骤。这是否特定于某些 VS 版本和/或某些类?
    • @BarmakShemirani,显然是的,一些组合适用于/MDd / /MD。当然/MT 就像/MTd 一样工作。
    【解决方案3】:

    在工具->选项->调试中取消选中启用我的代码选项

    我知道这适用于 c++ std:: library 代码调试。当我忘记取消选中此选项时,我执行的另一种技术类似于您上面描述的。

    1. 在我要单步执行的代码行上设置断点。
    2. 到达断点后,右键单击编辑器窗口并选择“Go To Disassemly”。
    3. 在反汇编模式下,单步执行直到出现call 语句。这通常是标准库。最终,您将导航到汇编和系统代码源的混合。您可以通过再次右键单击并选择“转到源代码”来退出反汇编模式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-09
      • 2019-07-30
      • 2021-09-19
      • 1970-01-01
      • 2020-11-25
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      相关资源
      最近更新 更多