在 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????????????????
此代码完全错误。您能够编译它的唯一原因是因为 HWND
和 HDC
在托管环境中都被键入为指针 (IntPtr
)。如果您使用 C 或 C++ 编写,则会出现编译错误,使问题更容易被发现。
您已挂接的 DrawText
函数的第一个参数是要在其上绘制文本的设备上下文 (HDC
) 的句柄。
您正在调用的 GetAncestor
函数的第一个参数是 window (HWND
) 的句柄。 HDC
和 HWND
是不兼容的类型;它们不能互换。
设备上下文 (HDC
s) 没有 "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
。你的钩子程序没有做任何有用的事情。此外,您还错过了应用程序调用 DrawTextEx
、ExtTextOut
或 TextOut
来绘制文本的情况,并且假设它甚至使用 GDI 来绘制文本。如果它使用 GDI+、DirectDraw 或其他绘图 API,您的挂钩将永远不会被调用。挂钩对 DrawText
的调用的唯一原因是您想要更改其行为。您实际上并没有更改挂钩过程中的行为,并且根据 window 更改其行为既不可能也不明智。它是一个只处理设备上下文的绘图函数。
我正在使用 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????????????????
此代码完全错误。您能够编译它的唯一原因是因为 HWND
和 HDC
在托管环境中都被键入为指针 (IntPtr
)。如果您使用 C 或 C++ 编写,则会出现编译错误,使问题更容易被发现。
您已挂接的 DrawText
函数的第一个参数是要在其上绘制文本的设备上下文 (HDC
) 的句柄。
您正在调用的 GetAncestor
函数的第一个参数是 window (HWND
) 的句柄。 HDC
和 HWND
是不兼容的类型;它们不能互换。
设备上下文 (HDC
s) 没有 "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
。你的钩子程序没有做任何有用的事情。此外,您还错过了应用程序调用 DrawTextEx
、ExtTextOut
或 TextOut
来绘制文本的情况,并且假设它甚至使用 GDI 来绘制文本。如果它使用 GDI+、DirectDraw 或其他绘图 API,您的挂钩将永远不会被调用。挂钩对 DrawText
的调用的唯一原因是您想要更改其行为。您实际上并没有更改挂钩过程中的行为,并且根据 window 更改其行为既不可能也不明智。它是一个只处理设备上下文的绘图函数。