Search code examples
c#unmanagedsendmessage

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


I was trying to get text from each control in hierarchy. The following code runs fine if I use the unsafe method. However, using the unmanaged version seems to break hWnd, which in result hWnd = GetAncestor(hWnd, GetAncestorFlags.GA_PARENT) complains:

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

I have checked hWnd was not changed after returning from GetWindowTextRaw function, and if I comment out the second SendMessage in this function will not cause the issue (although it will clearly not get the window text).

(PS: I'm using PInvoke.User32 in NuGet)

// 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);
    }
}

Solution

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

    Wrong size, you need buff.Length * sizeof(char). Twice as much as it allocates now. As written, the code corrupts the same heap that the OS uses, anything can happen next. An AVE is a normal and happy outcome, but not guaranteed.