C#中这个非托管代码有什么问题?

时间:2017-05-03 12:08:50

标签: c# unmanaged sendmessage

我试图从层次结构中的每个控件获取文本。如果我使用unsafe方法,以下代码运行正常。但是,使用非托管版本似乎会中断hWnd,结果hWnd = GetAncestor(hWnd, GetAncestorFlags.GA_PARENT)会抱怨:

System.AccessViolationException:'尝试读取或写入受保护的内存。这通常表明其他内存已损坏。'

我已经检查hWndGetWindowTextRaw函数返回后没有更改,如果我注释掉此函数中的第二个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);
    }
}

1 个答案:

答案 0 :(得分:3)

IntPtr iptr = Marshal.AllocHGlobal(buff.Length);

尺码错误,您需要buff.Length * sizeof(char)。现在分配的数量是它的两倍。如上所述,代码破坏了操作系统使用的相同堆,接下来就会发生任何事情。 AVE是一种正常且快乐的结果,但不能保证。