A megoldás trükkje a következőben rejlik: adott a WM_NCHITTEST Windows üzenet, mely akkor jön létre, ha a felhasználó mozog az egérrel a Form területén. Ennél az üzenetnél kell eldönteni, hogy az egér melyik részén jár a Form-nak. Az üzenet visszatérési értéke tartalmazza ezt a döntést. Ha ennek értéke htCaption lesz, akkor a Windows azt „hiszi”, hogy az egér a Form fejléce fölött tartózkodik, így ennek megfelelően fogja az egeret kezelni: vagyis a felhasználó képes lesz az adott helyen a Form mozgatására.
Ennek ismeretében már nincs más dolgunk, mint elhitetni a Windows-al, hogy amikor az új TImage komponensünk felett tartózkodik az egér, akkor ezt vegye úgy mintha a Form fejléce lenne.
Ennek megvalósítására kezelnünk kell a WM_NCHITTEST üzenetet. Ezen belül ellenőriznünk kell, hogy az egér aktuálisan a mi komponensünk felett tartózkodik-e vagy sem. Ha igen, akkor a htCaption értéket adjuk visszatérési értékül.
procedure TImageCaption.DoWndProc(var Message: TMessage);
...
case Message.Msg of
WM_NCHITTEST: begin
p:=ScreenToClient(SmallPointToPoint(TWMNCHitTest(Message).Pos));
if PtInRect(ClientRect, p) then begin
Message.Result:=htCaption;
end;
end;
...
Ezzel kész is lehetnénk, csakhogy van még egy megoldandó problémánk. Ez pedig az, hogy az üzeneteket a Form kapja és nem a rajta lévő TImage komponensből származtatott új osztályunk.
Márpedig nekünk arra van szükségünk, hogy a Form üzeneteit a saját komponensünk is figyelni tudja. Ennek megvalósítására a következőt tesszük: a komponensünk létrejöttekor a Form üzenetkezelő eljárását a saját komponensünk üzenetkezelőjére irányítjuk, majd amikor ez elvégezte dolgát, akkor meghívjuk a Form eredeti üzenetkezelőjét, mivel mi csak a WM_NCHITTEST üzenetre vagyunk kíváncsiak.
A komponensünk konstruktorában tehát tároljuk a Form eredeti üzenetkezelőjét az FOldWndProc változóba, majd saját DoWndProc névre hallgató eljárásunkat adjuk értékül. Ekkor ha a Form üzenetet kap, azt a DoWndProc eljárás kezeli le, mely meghívja az eredeti üzenet kezelőt is a Form működőképességének megőrzése érdekében.
constructor TImageCaption.Create(AOwner: TComponent);
begin
inherited;
FDestroying:=false;
FOldWndProc:=(AOwner as TForm).WindowProc;
(Owner as TForm).WindowProc:=DoWndProc;
end;
A komponens megszűnésekor helyre kell állítanunk az eredeti állapotot, hogy a Form a komponensünk nélkül is működőképes maradjon. Ez alól csak az az eset kivétel, ha a Form is éppen megszűnik, és ezért kerül meghívásra a komponensünk destruktora. Ezt onnan fogjuk tudni, hogy az üzenetkezelőben figyeljük a WM_CLOSE, WM_DESTROY üzeneteket is és az FDestroying belső változónkat igazra állítjuk, ha ezek az üzenetek befutnak.
destructor TImageCaption.Destroy;
begin
if not FDestroying then begin
(Owner as TForm).WindowProc:=FOldWndProc;
end;
inherited;
end;