也许一个愚蠢的问题,但...如何从WndProc中获取窗口句柄?
我正在写一个class
应采取保持一个窗口的护理(FGuestHWnd
,从现在起)视觉锚定到“主机窗口”(FHostHWnd
)。
FGuestHWnd
和HostHWnd
没有父母/所有者/子女关系。FGuestHWnd
属于另一个过程 - 不关心。FHostHWnd
是VCLTWinControl
的窗口句柄,所以这是我的过程中的一个子窗口。它可以坐在父/子树内的任何级别。例如,假设这是一个TPanel
。
现在我必须“钩”FHostHWnd
的移动/调整大小,并在我的自定义计算后调用SetWindowPos(FGuestHWnd...
。调整大小非常简单:我可以使用SetWindowLong(FHostHWnd, GWL_WNDPROC, ...)
将FHostHWnd
的WndProc“重定向到”我的自定义WindowPorcedure和陷阱WM_WINDOWPOSCHANGING
。由于FHostHWnd
是客户端对齐的,因此此消息会自动发送到FHostHWnd
,因为其中一个祖先的大小已调整。
感动,如果我不缺少的东西,是有点麻烦,因为如果我移动的主要形式FHostHWnd
是不是真的很感动。它保持与其父母相同的位置。所以它不会以任何方式通知祖先的移动。
我的解决办法是有父的WndProc“重定向”到自定义窗口过程和陷阱WM_WINDOWPOSCHANGING为“移动”唯一消息。 在这种情况下,我可以用自定义消息通知FHostHWnd
。 我班内的一些字段将跟踪Win Handles,原WndProc addesses和新WndProc地址链。
下面是一些代码来解释我的结构:
TMyWindowHandler = class(TObject)
private
FHostAncestorHWndList: TList;
FHostHWnd: HWND;
FGuestHWnd: HWND;
FOldHostAncestorWndProcList: TList;
FNewHostAncestorWndProcList: TList;
//...
procedure HookHostAncestorWindows;
procedure UnhookHostAncestorWindows;
procedure HostAncestorWndProc(var Msg: TMessage);
end;
procedure TMyWindowHandler.HookHostAncestorWindows;
var
ParentHWnd: HWND;
begin
ParentHWnd := GetParent(FHostHWnd);
while (ParentHWnd > 0) do
begin
FHostAncestorHWndList.Insert(0, Pointer(ParentHWnd));
FOldHostAncestorWndProcList.Insert(0, TFarProc(GetWindowLong(ParentHWnd, GWL_WNDPROC)));
FNewHostAncestorWndProcList.Insert(0, MakeObjectInstance(HostAncestorWndProc));
Assert(FOldHostAncestorWndProcList.Count = FHostAncestorHWndList.Count);
Assert(FNewHostAncestorWndProcList.Count = FHostAncestorHWndList.Count);
if (SetWindowLong(ParentHWnd, GWL_WNDPROC, LongInt(FNewHostAncestorWndProcList[0])) = 0) then
RaiseLastOSError;
ParentHWnd := GetParent(FHostHWnd);
end;
end;
这里是处理程序:
procedure TMyWindowHandler.HostAncestorWndProc(var Msg: TMessage);
var
pNew: PWindowPos;
begin
case Msg.Msg of
WM_DESTROY: begin
UnHookHostAncestorWindows;
end;
WM_WINDOWPOSCHANGING: begin
pNew := PWindowPos(Msg.LParam);
// Only if the window moved!
if ((pNew.flags and SWP_NOMOVE) = 0) then
begin
//
// Do whatever
//
end;
end;
end;
Msg.Result := CallWindowProc(???, ???, Msg.Msg, Msg.WParam, Msg.LParam);
end;
我的问题是:
我怎样才能得到的窗口句柄从我的WindowProcedure里面,当我最终调用CallWindowProc
? (如果我有窗口句柄,我也可以在FOldHostAncestorWndProcList
中找到它,然后在FHostAncestorHWndList
中查找右边的Old-WndProc-pointer) 或者,作为替代,如何获取CURRENT方法指针,以便我可以在其中找到它FNewHostAncestorWndProcList
并在FHostAncestorHWndList
中查找HWND。
或者你提出其他解决办法?
请注意,我想保留一切HWND为导向,而不是VCL/TWinControl感知。
换句话说,我的应用程序应该只实例TMyWindowHandler传递给它两个HWND
S(主机和客户)。
谢谢大卫。但是'MakeObjectInstance'不是专门为解决这个问题而存在的吗?看起来VCL本身绑定了一个'TWinControl'的'WndProc'。 – yankee
我已经扩大了。 'MakeObjectInstance'是你的问题。 'AllocateHwnd'和'TWinControl.Create'使用它来形成窗口和实例之间的一对一关系。您的问题具有多对一的实例关系。所以'MakeObjectInstance'根本不好。 –
好点大卫。谢谢。 – yankee