在 DrawText Hook 中从子节点获取父 Hwd

Get Parent Hwd from child in DrawText Hook

我正在使用 Easy Hook 库。如何让所有者 window 处理?

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

GetWindowDC、GetDC、GetParent 和其他的也不起作用 如何获取父 window ?

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

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

您已挂接的 DrawText 函数的第一个参数是要在其上绘制文本的设备上下文 (HDC) 的句柄。

您正在调用的 GetAncestor 函数的第一个参数是 window (HWND) 的句柄。 HDCHWND 是不兼容的类型;它们不能互换。

设备上下文 (HDCs) 没有 "ancestors",即使有,GetAncestor 函数也仅为 windows 设计。它不知道如何处理设备上下文,所以它失败了。您向它传递了一个无效的 window 句柄。

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

如果您从逻辑上考虑这个问题,您就会发现您所问的问题在哪里。考虑应用程序创建内存 DC 并调用 DrawText 将文本绘制到其中的简单情况。 "window" 您想检索什么?也许 "main" window 用于进程?首先,没有办法为任意进程确定这一点。其次,进程可能甚至 没有 任何 windows!我可以创建一个 windowless 进程来创建文本并将其绘制到内存 DC 中。如果我这样做,最好不要让你的钩子挂掉!

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