Maybe a stupid question, but ...
I am writing class, which should take care that the Window Window ( FGuestHWnd, henceforth) is visually bound to the "Host Window" ( FHostHWnd).
FGuestHWndand HostHWndhave no parent / owner / child relationship.FGuestHWnd belongs to another process - don't care.FHostHWndis a VCL window handle TWinControl, so this is a child window inside my process. It can sit at any level inside the parent / child tree. For example, let's say this TPanel.
Now I need to “intercept” the FHostHWndmove / resize and call SetWindowPos(FGuestHWnd...after my user calculation.
Resizing is simple: I can use WndProc SetWindowLong(FHostHWnd, GWL_WNDPROC, ...)to “redirect” FHostHWndto my custom WindowPorcedure and trap WM_WINDOWPOSCHANGING. This message is automatically sent to FHostHWndwhen one of its ancestors receives a size because it is FHostHWndaligned by click.
MOVEMENT, if I don’t miss something, is a little more complicated, because if I move the main form, FHostHWndit doesn’t actually move. He maintains the same position with respect to his parent. Therefore, he is in no way notified of the movement of the ancestors.
, "" ANY ANCESTOR WndProc Window WM_WINDOWPOSCHANGING "".
FHostHWnd .
Win Handles, Original 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;
:
Window Handle WindowProcedure, CallWindowProc?
( Window Handle, FOldHostAncestorWndProcList, Old-WndProc FHostAncestorHWndList)
, , CURRENT, FNewHostAncestorWndProcList HWND FHostAncestorHWndList.
?
, HWND-, VCL/TWinControl-aware.
, TMyWindowHandler, HWND ( ).