如何在调试时获取CEdit(或CWnd)文本

How to get CEdit (or CWnd) text in debug time

本文关键字:CWnd 文本 CEdit 获取 调试      更新时间:2023-10-16

当我调试项目时,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

要回答您的问题,窗口的文本存储在哪里:我真的不知道,任何给定的窗口也不知道。要获得这些信息,您必须询问窗口管理器。

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

到目前为止,太糟糕了。然而,并不是所有的东西都失去了。你仍然可以获得你需要的信息。

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

如果希望在VisualStudio的调试器中获得实时信息,则必须编写调试器表达式评估加载项。Microsoft不正式支持表达式评估器。因此,没有正式文件。如何为Visual Studio 2012调试器编写自定义的本机可视化工具DLL?如果你想走这条路,可以提供有用的信息。显示窗口文本项的表达式计算器如下所示:

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 DocumentsVisual Studio 2012Visualizers -->
  <Type Name="HWND__">
    <DisplayString LegacyAddin="HwndEEAddin.dll" Export="_AddIn_HWND@28"></DisplayString>
  </Type>
</AutoVisualizer>

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

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

.dll必须位于devenv.exe目录或PATH上。否则,您将不得不使用完全限定的路径名。有关VS 2010之前的Visual Studio表达式计算器的其他信息,请参阅自定义数据的Visual Studio调试器显示。

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

如果您想查看新值,那么您必须使用一个变量并从窗口中检索文本。

CString text;
GetDlgItemText(ID, text);

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

我希望它更简单,但MFC只是Win32 API的包装器。您可以尝试使用C#,它可以更好地将UI呈现为对象(相对于间接访问的C/Pascal/汇编结构的包装器)