C# 中的这段非托管代码有什么问题? [英] What's wrong with this unmanaged code in C#?

查看:36
本文介绍了C# 中的这段非托管代码有什么问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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: '试图读取或写入受保护的内存.这通常表明其他内存已损坏.'

我已经检查了 hWnd 在从 GetWindowTextRaw 函数返回后没有改变,如果我注释掉这个函数中的第二个 SendMessage 将不会导致问题(虽然它显然不会得到窗口文本).

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:我在 NuGet 中使用 PInvoke.User32)

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

推荐答案

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

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

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.

这篇关于C# 中的这段非托管代码有什么问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆