-2

我正在使用 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);
    }

GetWindowDC、GetDC、GetParent 等都不行,如何获取父窗口?

4

1 回答 1

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

这段代码是完全错误的。您能够编译它的唯一原因是因为两者HWND和在托管环境中都HDC被键入为指针( )。IntPtr如果你用 C 或 C++ 编写,你会得到一个编译错误,使问题更容易被发现。

您已经挂钩的DrawText函数具有作为其第一个参数的设备上下文句柄 ( HDC),文本将在该句柄上绘制。

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

设备上下文(HDCs)没有“祖先”,即使有,该GetAncestor功能也仅适用于 Windows。它不知道如何处理设备上下文,所以它失败了。你给它传递了一个无效的窗口句柄。

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

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

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

于 2016-09-07T10:22:34.877 回答