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

What's wrong with this unmanaged code in C#?

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

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

我检查过 hWnd 在从 GetWindowTextRaw 函数返回后没有改变,如果我注释掉这个函数中的第二个 SendMessage 将不会导致问题(尽管它会显然没有得到 window 文本)。

(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('[=10=]');
}

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);
    }
}
IntPtr iptr = Marshal.AllocHGlobal(buff.Length);

尺码错误,您需要 buff.Length * sizeof(char)。是现在分配的两倍。正如所写,代码破坏了 OS 使用的同一个堆,接下来任何事情都可能发生。 AVE 是一个正常而快乐的结果,但不能保证。