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

时间:2016-09-05 21:24:23

标签: c# winapi easyhook

我正在使用Easy Hook lib。如何获得所有者窗口?

    [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等也不起作用 如何获取父窗口?

1 个答案:

答案 0 :(得分:0)

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 function,传入HDC以检索关联的HWND。同样,我必须强调,这不会解决你的实际问题。 不保证设备上下文与窗口关联。设备上下文可能与屏幕关联,或者可能是内存DC,或者它可能是设备DC(与物理相关联)监视器,打印机或其他输出设备)。在所有这些情况下,WindowFromDC将返回NULL(空指针或值IntPtr.Zero)。

如果你从逻辑上考虑这个问题,你会发现你所要求的地方分崩离析。考虑应用程序创建内存DC并调用DrawText以将文本绘制到其中的简单情况。你想要检索什么“窗口”?也许这个过程的“主要”窗口?首先,没有办法确定任意过程。其次,该过程可能甚至没有拥有任何窗口!我可以创建一个无窗口进程,创建并将文本绘制到内存DC中。如果我这样做,最好不要让你的钩子崩溃!

您在评论中拒绝了几个请求,以解释此代码的目的是什么。目前还不清楚为什么要首先挂钩DrawText。你的钩子程序没有做任何有用的事情。此外,您错过了应用程序调用{​​{1}},DrawTextExExtTextOut来绘制文本的情况,并且假设它甚至使用GDI绘制文本。如果它使用GDI +,DirectDraw或其他一些绘图API,则永远不会调用您的钩子。将调用挂接到TextOut的唯一原因是,如果要更改其行为。实际上,您并没有更改钩子过程中的行为,并且基于窗口更改其行为既不可能也不明智。它是一个只处理设备上下文的绘图函数。