え? 何のことかって? 要するにアレよ。例えば非ビジュアルコンポーネントでMessageBox APIを使いたくなったと思いねェ。ところがどっこい、ウィンドウハンドルはTWinColtrolクラスを継承していないと使えないんで、困ったりするんですな。
いろいろ調べたですよ……尽きるところTWinControlクラスでやってることをそのままやれば良いんですが、結構煩雑でして。
それはそれとして、多分このような目的のためにあるかのようなシンプルな回答とするなら、実にFormsユニットのAllocateHWnd()メソッドを使うだけでOKだったんです……。
あちこちの非ビジュアルコンポーネントで呼ばれておりますですよ。
ちなみに作ったハンドルは当然、自分で開放しましょう。DeallocateHWndメソッドを呼びます。
TMyClass.WndProc( var Msg:TMessage );
begin
if Msg.Msg = WM_XXX then
try
if Assigned(FOnEvening) then FOnEvening(Self);
except
Application.HandleException(Self);
end
else
Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.wParam, Msg.lParam);
end;
WM_XXXがメッセージ名です。WM_TIMERやWM_HOTKEYなど、いろいろあります。Win32 SDKのヘルプを見ればいろいろありますんで面白げに読んでみましょう
じゃあ不可能かと言うと、そこはそれ、蛇の道は蛇。「やらぬなら・やらせて見せようプロシージャ」とばかり、先のウィンドウプロシージャをドロップを受け付けてくれるコントロールに強引に押し付けて、イベントを処理させちゃうわけですな。こう言うのをサブクラス化と言うらしいですが。
具体的には、プロシージャをオブジェクトとして確保しておいて、APIを使って相手側のプロシージャ参照ポインタに上書きしちゃうわけ。VCLのイベントハンドラを実行時に切り替えるみたいなもん……ですが、最後にちゃんと書き戻してあげないと大変なことになるかも まぁ、一つのアプリ内(プロセス内)ならほぼ同時に消えるってんで大丈夫かと存じますが、やっぱし作った順に消すとか、使った順に返すとか、そう言う美しさは大事だと思いますよ。えぇ今日日でも。
こいつはフォームにコンポーネントを貼り付けるだけでダブルクリックに反応します…… EnabledプロパティをON/OFFする仕組みを搭載して、フォームをダブルクリックしてみましょう。 |
unit vclMouseHook; interface uses classes, windows, messages, controls, shellapi, forms, sysutils; type TMouseHook = class(TComponent) private FOldWndProc: Pointer; FNewWndProc: Pointer; FWndHandle : HWND; FEnabled : Boolean; procedure WndProc( var Msg:TMessage ); virtual; public constructor Create(AOwner:TComponent); override; destructor Destroy; override; procedure DoubleClick( KeyFlag:Integer; X,Y:LongInt); published property Enabled:Boolean read FEnabled write FEnabled default True; end; procedure Register; implementation procedure Register; begin RegisterComponents('魔僧神仙',[TMouseHook]); end; { TMouseHook } constructor TMouseHook.Create(AOwner: TComponent); begin inherited; FEnabled := True; FWndHandle := TWinControl(AOwner).Handle; FNewWndProc := MakeObjectInstance(WndProc); FOldWndProc := Pointer(SetWindowLong(FWndHandle,GWL_WNDPROC,LongInt(FNewWndProc))); end; destructor TMouseHook.Destroy; begin SetWindowLong(FWndHandle,GWL_WNDPROC,LongInt(FOldWndProc)); inherited; end; procedure TMouseHook.DoubleClick(KeyFlag: Integer; X,Y:LongInt); var Str: String; begin Str := '('+IntToStr(X)+','+IntToStr(Y)+')'; Application.MessageBox(PChar(Str),'',MB_ICONINFORMATION); end; procedure TMouseHook.WndProc( var Msg:TMessage ); begin with Msg do begin if (Msg=WM_LBUTTONDBLCLK)and(Enabled) then begin try DoubleClick(wParam,Loword(lParam),HiWord(lParam)); except Application.HandleException(Self); end; end else Result := CallWindowProc(FOldWndProc,FWndHandle,Msg,wParam,lParam); end; end; end. |