【问题标题】:How to get CEdit (or CWnd) text in debug time如何在调试时获取 CEdit(或 CWnd)文本
【发布时间】:2013-07-25 09:28:35
【问题描述】:

当我调试我的项目时,CEdit 对象的文本已更改,我想查看新值。但监视窗口不显示文本成员。
文本存储在哪里?

编辑:我忘了写我使用 Visual C++ 6.0('98 版)

监视窗口中的 CEdit 树如下所示:

m_editBox
|  
+ [CWnd]  
  |  
  + CCmdTarget  
  + classCWnd
  + m_hWnd  
  + wndTop
  + wndBottom
  + wndTopMost
  + wndNoTopMost
  + m_hWndOwner
  - m_nFlags
  - m_pfnSuper
  - m_nMsgDragList
  - m_nModalResult
  + m_pDropTarget
  + m_pCtrlCont
  + m_pCtrlSite
  + _messageEntries
  + messageMap
+ CWnd
  |
  + CCmdTarget
  + m_hWnd
  + m_hWndOwner
  - m_nFlags
  - m_pfnSuper
  - m_nModalResult
  + m_pDropTarget
  - m_pCtrlCont
  - m_pCtrlSite

【问题讨论】:

    标签: c++ oop debugging visual-c++ mfc


    【解决方案1】:

    回答您预先存储窗口文本的问题:我真的不知道,任何给定的窗口也不知道。要获取该信息,您必须改为询问窗口管理器。

    与窗口有关的所有信息都存储在由窗口管理器维护的内部结构中。窗口管理器由 Win32k.sys 实现,因此这些内部结构驻留在内核内存中。 HWND 用作窗口管理器控制的表的索引。即使表条目以只读方式映射到用户空间内存,获取所需信息也相当繁琐。

    到目前为止,很糟糕。然而,还没有全部丢失。您仍然可以获得所需的信息。

    最简单的选择是使用 Spy++ (Spyxx.exe)。它作为 Visual Studio 的一部分提供,有助于检索窗口特定信息,除其他方面外,它将显示窗口的文本。鉴于您的要求,您将转到 Spy -> Find Window... (或按 [Ctrl]+F) 并输入窗口的句柄(以十六进制表示,不带 0x 前缀)。但是,信息不会自动刷新。您需要手动点击刷新按钮。

    如果您想在 Visual Studio 的调试器中获得实时信息,您必须编写一个调试器表达式评估插件。 Microsoft 不正式支持表达式求值器。因此没有官方文档。 How to write a custom native visualizer DLL for Visual Studio 2012 debugger? 提供有用的信息,如果你想走这条路。显示窗口文本条目的表达式求值器如下所示:

    HwndEEAddin.h:

    // HwndEEAddin.h : main header file for the NatvisAddIn DLL
    //
    
    #if !defined( INC_HWNDEEADDIN_H_ )
    #define INC_HWNDEEADDIN_H_
    
    #pragma once
    
    #define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
    #include <windows.h>
    
    
    #define ADDIN_API extern "C" __declspec(dllexport)
    
    /* DebugHelper structure used from within the */
    typedef struct tagDEBUGHELPER
    {
      DWORD dwVersion;
      BOOL (WINAPI *ReadDebuggeeMemory)( struct tagDEBUGHELPER *pThis, DWORD dwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot );
      // from here only when dwVersion >= 0x20000
      unsigned __int64 (WINAPI *GetRealAddress)( struct tagDEBUGHELPER *pThis );
      BOOL (WINAPI *ReadDebuggeeMemoryEx)( struct tagDEBUGHELPER *pThis, unsigned __int64 qwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot );
      int (WINAPI *GetProcessorType)( struct tagDEBUGHELPER *pThis );
    } DEBUGHELPER;
    
    /* Exported Functions */
    ADDIN_API HRESULT WINAPI AddIn_HWND( DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t maxResult, DWORD reserved );
    
    #endif  // !defined( INC_HWNDEEADDIN_H_ )
    

    HwndEEAddin.cpp:

    #include "HwndEEAddin.h"
    
    #include <strsafe.h>
    
    
    ADDIN_API HRESULT WINAPI AddIn_HWND( DWORD dwAddress, DEBUGHELPER* pHelper, int /*nBase*/, BOOL bUniStrings, char *pResult, size_t maxResult, DWORD /*reserved*/ )
    {
      HRESULT hr = E_FAIL;
    
      HWND hWnd = reinterpret_cast< HWND >( dwAddress );
      if ( hWnd != NULL )
      {
        bool bGotWindowText = false;
    
        CHAR asciiWindowText[ 128 ] = { 8 };
        if ( IsWindowUnicode( hWnd ) )
        {
          WCHAR buffer[ 128 ] = { 0 };
          if ( GetWindowTextW( hWnd, buffer, ARRAYSIZE( buffer ) ) )
          {
            if ( WideCharToMultiByte( CP_THREAD_ACP, 0x0, buffer, -1, asciiWindowText, ARRAYSIZE( asciiWindowText ), NULL, NULL ) > 0 )
            {
              bGotWindowText = true;
            }
          }
        }
        else
        {
          if ( GetWindowTextA( hWnd, asciiWindowText, ARRAYSIZE( asciiWindowText ) ) )
          {
            bGotWindowText = true;
          }
        }
    
        if ( bGotWindowText )
        {
          hr = StringCbPrintfA( pResult, maxResult, "{pText=\"%s\"}", asciiWindowText );
        }
      }
    
      return hr;
    }
    

    要在 Visual Studio 2010 及更高版本中注册插件,您必须将 .dll 与以下文件一起复制到 %USERPROFILE%\Documents\Visual Studio 2012\Visualizers。

    HwndEEAddin.natvis:

    <?xml version="1.0" encoding="utf-8"?>
    <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
    
      <!-- Place this file and the AddIn-DLL to this folder: %USERPROFILE%\My Documents\Visual Studio 2012\Visualizers\ -->
    
      <Type Name="HWND__">
        <DisplayString LegacyAddin="HwndEEAddin.dll" Export="_AddIn_HWND@28"></DisplayString>
      </Type>
    
    </AutoVisualizer>
    

    在 2010 之前的 Visual Studio 版本中,您必须通过将以下条目添加到 [AutoExpand] 部分来编辑 autoexp.dat:

    HWND__ = $ADDIN(HwndEEAddin.dll,_AddIn_HWND@28)
    

    .dll 必须位于 devenv.exe 目录或 PATH 中。否则,您将不得不使用完全限定的路径名​​。有关 VS 2010 之前的 Visual Studio 表达式评估器的更多信息,请访问Customizing the Visual Studio Debugger Display of Your Data

    【讨论】:

    • 谢谢!你能解释一下为什么隐藏如此简单的信息如此重要吗?为什么MFC 对象不携带它?
    • @Aharon CWnd 派生类是 HWND 的薄包装,用于识别窗口的本机句柄。底层结构 (WND) 的信息和布局不会暴露给客户端代码以实现抽象层。它允许 Microsoft 随时更改内部 WND 结构,而不会破坏访问公共 API(在本例中为 GetWindowText)的客户端代码。抽象是隐藏复杂性的过程,从系统架构师的角度来看,这是一件好事,但对于想要查看这些细节的开发人员来说,这可能看起来很不幸。
    【解决方案2】:

    实际文本保存在控件的关联内存中,您无法直接访问该内存。您只有将控件的句柄 HWND 包装到 CEdit 类中。为了从那里获取文本,您需要提前将代码 CEdit::GetWindowText 导入本地内存,然后使用调试器对其进行检查。

    【讨论】:

    • 调试时我没有调用GetWindowText,所以我无法执行它。另外,我使用memory窗口没有问题,但我必须知道我应该在哪里观看。
    • 关键是Watch窗口不会显示它。它向您显示从类指针到 m_hWnd 成员的数据,并且文本还在“后面”。
    • 我明白了。但是我不知道在m_hWnd 的哪个位置可以找到它,因为监视窗口只显示带有int 值的unused。如果我在memory 中观看,我想知道我应该使用m_hWnd 指向的地址的偏移量。
    • 文本由 EDIT 控件而非CEdit 实例管理。 CEdit 实例是 Windows EDIT 控件的包装器。我不知道 Roman 还需要告诉你多少次,但 CEdit 控件不保存文本。它必须按需获取。任何体面的调试器都会在监视窗口或评估对话框中为您调用一个方法。
    • 唯一知道存储位置的是 Win32 库中实现EDIT 控件的代码。没有 MFC 对象知道字符串的存储位置。
    【解决方案3】:

    如果要查看新值,则必须使用变量并从窗口中检索文本。

    CString text;
    GetDlgItemText(ID, text);
    

    【讨论】:

    • 这不是我问的。我现在在调试时间,想通过debug windows找到文本值。如果我在手表中找不到它,请告诉我在哪里可以找到。
    • 你不能!这才是重点。文本存储在窗口中,而不是包装编辑控件的 CEdit 类型的 MFC 对象中。您可以使用 Spy 来观察窗口。它将向您显示文本。
    • 使用 GetDlgItemText 有什么问题?您负责,您正在调试,您可以在调试时将 GetDlgItemText 放入您的程序中。
    【解决方案4】:

    CEdit 的“GetWindowText”方法从字面上发送一个 Windows 消息来获取文本,而不是使用简单的访问器方法对文本进行函数调用。m_hWnd 是 O/ 深层内部的某些数据结构的“句柄” S 其中只有窗口的 O/S 代码知道如何检索文本。

    我希望它更简单,但 MFC 只是 Win32 API 的包装器。您可以尝试使用 C#,它在将 UI 呈现为对象方面做得更好(与间接访问的 C/Pascal/程序集结构的包装器相比)

    【讨论】:

    • CEdit 的GetWindowText 调用::GetWindowText。这可能会或可能不会发送消息。如果它不发送消息,它将 - 从技术上讲 - 调用文本的简单访问器。
    猜你喜欢
    • 2013-01-12
    • 2017-11-07
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2012-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多