在DrawText钩子中从child获取Parent Hwd

本文关键字:child 获取 Parent Hwd DrawText | 更新日期: 2023-09-27 18:05:41

我使用Easy Hook库。如何获得所有者窗口句柄?

    [StructLayout(LayoutKind.Sequential)]
    public struct Rect
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
        public override string ToString()
        {
            return $"[Left: {Left}, Top: {Top}, Right: {Right}, Bottom: {Bottom}]";
        }
    }
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern int DrawText(IntPtr hDc, string lpString, int nCount, ref Rect lpRect, uint uFormat);
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
    public delegate int DDrawText(IntPtr hDc, string lpString, int nCount, ref Rect lpRect, uint uFormat);

    private int DrawText_Hooked(IntPtr hDc, string lpString, int nCount, ref Rect lpRect, uint uFormat)
    {
        var This = (Main) HookRuntimeInfo.Callback;
        lock (This._queue)
        {
            var parent = GetAncestor(hDc, GetAncestorFlags.GetParent); // always return 0! why????????????????                                  
            This._queue.Push($"parent [{parent}]");
        }
        return DrawText(hDc, lpString, nCount, ref lpRect, uFormat);
    }

gettwindowdc, GetDC, GetParent和其他也不起作用如何获取父窗口

在DrawText钩子中从child获取Parent Hwd

var parent = GetAncestor(hDc, GetAncestorFlags.GetParent); // always return 0! why????????????????

这段代码完全是错误。您能够编译它的唯一原因是因为HWNDHDC在托管环境中都被键入为指针(IntPtr)。如果使用C或c++编写,则会出现编译错误,从而使问题更容易看到。

您已经钩住的DrawText函数,其第一个参数是要绘制文本的设备上下文(HDC)的句柄。

你正在调用的GetAncestor函数的第一个参数是一个窗口(HWND)的句柄。HDCHWND是不兼容的类型;

设备上下文(HDC s)没有"祖先",即使它们有,GetAncestor函数也仅为windows设计。它不知道如何处理设备上下文,所以它失败了。您传递给它一个无效的窗口句柄。

就你的实际问题而言,如何获得与DC对应的"父窗口",这个问题没有任何意义。设备上下文没有"父"窗口,甚至只有一些设备上下文与一个窗口相关联。如果一个设备上下文与一个窗口相关联,你可以调用WindowFromDC函数,传入HDC来检索相关的HWND。我必须再次强调,这并不能解决你的实际问题。设备上下文不能保证与窗口相关联。设备上下文可能与屏幕相关联,也可能是内存DC,也可能是设备DC(与物理监视器、打印机或其他输出设备相关联)。在所有这些情况下,WindowFromDC将返回NULL(一个空指针,或者值IntPtr.Zero)。

如果你从逻辑上思考这个问题,你就会发现你的问题在哪里出错了。考虑这样一个简单的情况:应用程序创建一个内存DC,并调用DrawText向其中绘制文本。您想要检索哪个"窗口"?也许是流程的"主"窗口?首先,对于任意的过程,没有办法确定这一点。第二,进程甚至可能没有任何窗口!我可以创建一个无窗口进程来创建文本并将其绘制到内存dc中。如果我这样做,它最好不要撞坏你的钩子!

您在评论中多次拒绝解释这段代码的目的是什么。现在还不清楚为什么要钩住DrawText。钩子子程没有做任何有用的事情。此外,您还忽略了应用程序调用DrawTextExExtTextOutTextOut来绘制文本的情况,这是假设它甚至使用GDI来绘制文本。如果它使用GDI+、DirectDraw或其他绘图API,你的钩子将永远不会被调用。钩子调用DrawText的唯一原因是如果你想改变它的行为。你实际上并没有改变钩子子程的行为,基于一个窗口改变钩子子程的行为既不可能也不明智。它是一个绘图函数,只处理设备上下文。