2004. október 15., péntek
How to trap mouse clicks on the Desktop when using a system wide mouse hook
Problem/Question/Abstract:
Does anyone know how to tell (in Delphi code) if I have clicked on the Desktop (not an icon). I have written a system wide mouse hook program but the window handle and the icon handle are the same. How can I tell the difference?
Answer:
I did this by creating a DLL (you can only hook into the desktop via a DLL). The DLL then posts messages to the main application. You need to load the DLL, call Initialize supplying the applications handle (note: StdCall). You then need to assign a custom message handler (application.OnMessage) to listen for the messages posted from the DLL.
Here is the application message handler:
const
WM_DESKTOPMOUSEMESSAGE = WM_USER + 1;
procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
case Msg of
WM_DESKTOPMOUSEMESSAGE:
case Msg.WParam of
WM_LBUTTONUP: ShowMessage('You clicked on the desktop');
end;
end;
procedure TForm1.OnCreate(Sender: TObject);
begin
Application.OnMessage := AppMessage;
end;
Here is the hook code:
Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL - even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters.
library test;
uses
SysUtils, Messages, Windows;
{$R *.RES}
const
WM_DESKTOPMOUSEMESSAGE = WM_USER + 1;
var
HookHandle: HHook;
DesktopHandle: HWnd;
AppHandle: HWnd;
procedure log(logstr: string);
var
F1: Textfile;
begin
AssignFile(F1, 'c:\temp.log');
if FileExists('c:\temp.log') then
Append(F1)
else
Rewrite(F1);
writeln(F1, logstr);
CloseFile(F1);
end;
function MouseHook(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
var
WinDir: array[0..MAX_PATH] of Char;
f: file of HWnd;
begin
{This only happens once, we use the file just to get the variable across to the systems memory}
if AppHandle = 0 then
begin
GetWindowsDirectory(Windir, MAX_PATH);
AssignFile(f, WinDir + '\ah.dat');
Reset(f);
Read(f, AppHandle);
CloseFile(f);
end;
PostMessage(AppHandle, WM_DESKTOPMOUSEMESSAGE, wParam, lParam);
Result := CallNextHookEx(HookHandle, Code, WParam, LParam);
end;
procedure Initialize(ApplicationHandle: HWnd); stdcall;
var
res, pid: DWORD;
f: file of HWnd;
WinDir: array[0..MAX_PATH] of Char;
begin
{Write the application handle to a file so that it can be read first time round
by the hook (the hook has its own memory space)}
Fillchar(windir, sizeOf(WinDir), 0);
GetWindowsDirectory(Windir, MAX_PATH);
AssignFile(f, WinDir + '\ah.dat');
Rewrite(f);
Write(f, ApplicationHandle);
CloseFile(f);
DesktopHandle := FindWindow(nil, 'Program Manager');
if DesktopHandle = 0 then
HookHandle := 0
else
begin
AppHandle := ApplicationHandle;
res := GetWindowThreadProcessID(DesktopHandle, @pid);
HookHandle := SetWindowsHookEx(WH_MOUSE, @MouseHook, hInstance, res);
end;
end;
procedure DeInitialize; stdcall;
begin
if HookHandle <> 0 then
UnHookWindowsHookEx(HookHandle);
end;
exports
Initialize,
DeInitialize;
begin
end.
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése