WinDBG:来自 WinForms 应用程序的内存转储 - 如何获取文本框的值

Posted

技术标签:

【中文标题】WinDBG:来自 WinForms 应用程序的内存转储 - 如何获取文本框的值【英文标题】:WinDBG: memory dump from WinForms application - how to get a value of text box 【发布时间】:2021-10-18 00:32:59 【问题描述】:

我有一个来自 GUI 应用程序(.NET、WinForms)的内存转储,我正在尝试获取文本框的值(即在文本框中输入的值)。

我可以访问底层文本框对象,但 text 字段为空:

0:009> !DumpObj /d 000002afab5bc530
Name:        System.Windows.Forms.TextBox
MethodTable: 00007ff87c847038
EEClass:     00007ff87c8ffe30
Size:        248(0xf8) bytes
File:        C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ff88c655dd8  40005ba        8        System.Object  0 instance 0000000000000000 __identity
00007ff88ba275a0  400293e       10 ...ponentModel.ISite  0 instance 0000000000000000 site
00007ff88ba1dbd0  400293f       18 ....EventHandlerList  0 instance 000002afab5bd4b8 events
00007ff88c655dd8  400293d     11d0        System.Object  0   static 0000000000000000 EventDisposed
00007ff87c84a188  400081b       20 ...ntrolNativeWindow  0 instance 000002afab5bc660 window
00007ff87c8487e8  400081c       28 ...ows.Forms.Control  0 instance 000002afab558398 parent
00007ff87c8487e8  400081d       30 ...ows.Forms.Control  0 instance 000002afab558398 reflectParent
00007ff87c84aab0  400081e       38 ...orms.CreateParams  0 instance 000002afab5bd3d8 createParams
00007ff88c6585a0  400081f       70         System.Int32  1 instance               34 x
00007ff88c6585a0  4000820       74         System.Int32  1 instance               63 y
00007ff88c6585a0  4000821       78         System.Int32  1 instance              229 width
00007ff88c6585a0  4000822       7c         System.Int32  1 instance               20 height
00007ff88c6585a0  4000823       80         System.Int32  1 instance              225 clientWidth
00007ff88c6585a0  4000824       84         System.Int32  1 instance               16 clientHeight
00007ff88c6585a0  4000825       88         System.Int32  1 instance         16908815 state
00007ff88c6585a0  4000826       8c         System.Int32  1 instance             2120 state2
00007ff87d6d2da0  4000827       90         System.Int32  1 instance             8768 controlStyle
00007ff88c6585a0  4000828       94         System.Int32  1 instance                2 tabIndex
00007ff88c6559c0  4000829       40        System.String  0 instance 0000000000000000 text  <<<<<< this one

(但文本框肯定已填充,因为我可以在屏幕上看到值)。

有没有办法获取文本框text字段/属性的值?

【问题讨论】:

.NET 属性是一对函数,一个 getter 和一个 setter。 WinForms 文本框中的文本是本机 Windows 文本框控件中的文本(通过将 WM_SETTEXT 和 WM_GETTEXT 消息发送到控件/窗口来设置。抱歉,我目前知识不足,希望对您有所帮助。您可以在 MSFT 调试博客上找到一些帮助。请记住,这不是特定于 WinForms,您使用的是原生 Windows 控件 看起来Control 使用StringBuilder 将文本存储在getter internal virtual string WindowText StringBuilder sb = new StringBuilder(textLen + 1); 所以只要StringBuilder 对象没有被垃圾收集,那么你应该能够找到它。您可能想尝试使用 sourceforge 上的免费工具 ClrDbg 【参考方案1】:

WinForms 文本框并不总是在您每次按下某个键时创建一个新的字符串对象,除非您有强制执行此操作的代码。如果您将 32767 字符 CounterString 粘贴到 TextBox 中,您会期望在 .NET 堆上的某处有两倍长的字符串,但实际上没有:

0:012> !dumpheap -mt 689024e4 -min 0n65000
 Address       MT     Size

Statistics:
      MT    Count    TotalSize Class Name
Total 0 objects

因此您不能简单地通过!dumpheap!do 访问它。

ReferenceSource给我们

public override string Text 
    get 
        return base.Text;
    
    set 
        base.Text = value;
        selectionSet = false;
    

因此委托给 TextBoxBase,TextBoxBase 再次委托给 Control。

public virtual string Text 
    get 
        if (CacheTextInternal) 
            return(text == null) ? "" : text;
        
        else 
            return WindowText;
        
    

我们看到您识别出的text 属性用于缓存或使用WindowText

int textLen = SafeNativeMethods.GetWindowTextLength(new HandleRef(window, Handle));

// Check to see if the system supports DBCS character
// if so, double the length of the buffer.
if (SystemInformation.DbcsEnabled) 
    textLen = (textLen * 2) + 1;

StringBuilder sb = new StringBuilder(textLen + 1);
UnsafeNativeMethods.GetWindowText(new HandleRef(window, Handle), sb, sb.Capacity);
return sb.ToString();

使用 Spy++ 可以确认 WM_GETTEXTLENGTH (GetWindowTextLength) 和 WM_GETTEXT (GetWindowText) 用于从本机控件获取文本:

因此,只要您的 .NET 代码不访问 TextBox 的 Text 属性,您就需要查看控件的本机端。

【讨论】:

以上是关于WinDBG:来自 WinForms 应用程序的内存转储 - 如何获取文本框的值的主要内容,如果未能解决你的问题,请参考以下文章

来自 AForge FFMPEG 的图片框为空 - C#/WinForms

Richtexbox 如何在 Winforms 上附加来自事件侦听器的异步文本?

如何使用来自客户端 C# Winforms 的 asmx 服务 (BL) 的类函数

《Windows核心编程》第3章——深入理解handle

《Windows核心编程》第3章——深入理解handle

WinDBG__独立安装文件