我试图从层次结构中的每个控件获取文本。如果我使用unsafe
方法,以下代码运行正常。但是,使用非托管版本似乎会中断hWnd
,结果hWnd = GetAncestor(hWnd, GetAncestorFlags.GA_PARENT)
会抱怨:
System.AccessViolationException:'尝试读取或写入受保护的内存。这通常表明其他内存已损坏。'
我已经检查hWnd
从GetWindowTextRaw
函数返回后没有更改,如果我注释掉此函数中的第二个SendMessage
将不会导致问题(尽管它显然不会得到窗口文本)。
(PS:我在NuGet中使用PInvoke.User32)
// using static PInvoke.User32;
public static string GetWindowTextRaw(IntPtr hWnd) {
// Allocate correct string length first
int length = (int)SendMessage(hWnd, WindowMessage.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
char[] buff = new char[length + 1];
IntPtr iptr = Marshal.AllocHGlobal(buff.Length);
SendMessage(hWnd, WindowMessage.WM_GETTEXT, (IntPtr)(length + 1), iptr);
Marshal.Copy(iptr, buff, 0, length + 1);
Marshal.FreeHGlobal(iptr);
//unsafe
//{
// fixed (char* p = buff)
// SendMessage(hWnd, WindowMessage.WM_GETTEXT, (IntPtr)(length + 1), (IntPtr)p);
//}
return new string(buff).TrimEnd('\0');
}
private void button1_Click(object sender, EventArgs {
POINT p;
IntPtr hWnd;
//while (true)
if (GetCursorPos(out p)) {
hWnd = WindowFromPoint(p); ;
Debug.Print($"{p.x} {p.y} 0x{(int)hWnd:x8}");
while (hWnd != IntPtr.Zero) {
Debug.Print($"{GetWindowTextRaw(hWnd)}");
hWnd = GetAncestor(hWnd, GetAncestorFlags.GA_PARENT);
}
Thread.Sleep(500);
}
}
答案 0 :(得分:3)
IntPtr iptr = Marshal.AllocHGlobal(buff.Length);
尺码错误,您需要buff.Length * sizeof(char)
。现在分配的数量是它的两倍。如上所述,代码破坏了操作系统使用的相同堆,接下来就会发生任何事情。 AVE是一种正常且快乐的结果,但不能保证。