Author: Jonas Bilinkevicius
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:
1 const
2 WM_DESKTOPMOUSEMESSAGE = WM_USER + 1;
3
4 procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
5 begin
6 case Msg of
7 WM_DESKTOPMOUSEMESSAGE:
8 case Msg.WParam of
9 WM_LBUTTONUP: ShowMessage('You clicked on the desktop');
10 end;
11 end;
12
13 procedure TForm1.OnCreate(Sender: TObject);
14 begin
15 Application.OnMessage := AppMessage;
16 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.
17 library test;
18
19 uses
20 SysUtils, Messages, Windows;
21
22 {$R *.RES}
23
24 const
25 WM_DESKTOPMOUSEMESSAGE = WM_USER + 1;
26
27 var
28 HookHandle: HHook;
29 DesktopHandle: HWnd;
30 AppHandle: HWnd;
31
32 procedure log(logstr: string);
33 var
34 F1: Textfile;
35 begin
36 AssignFile(F1, 'c:\temp.log');
37 if FileExists('c:\temp.log') then
38 Append(F1)
39 else
40 Rewrite(F1);
41 writeln(F1, logstr);
42 CloseFile(F1);
43 end;
44
45 function MouseHook(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
46 var
47 WinDir: array[0..MAX_PATH] of Char;
48 f: file of HWnd;
49 begin
50 {This only happens once, we use the file just to get the variable across to the
51 systems memory}
52 if AppHandle = 0 then
53 begin
54 GetWindowsDirectory(Windir, MAX_PATH);
55 AssignFile(f, WinDir + '\ah.dat');
56 Reset(f);
57 read(f, AppHandle);
58 CloseFile(f);
59 end;
60 PostMessage(AppHandle, WM_DESKTOPMOUSEMESSAGE, wParam, lParam);
61 Result := CallNextHookEx(HookHandle, Code, WParam, LParam);
62 end;
63
64 procedure Initialize(ApplicationHandle: HWnd); stdcall;
65 var
66 res, pid: DWORD;
67 f: file of HWnd;
68 WinDir: array[0..MAX_PATH] of Char;
69 begin
70 {Write the application handle to a file so that it can be read first time round
71 by the hook (the hook has its own memory space)}
72 Fillchar(windir, sizeOf(WinDir), 0);
73 GetWindowsDirectory(Windir, MAX_PATH);
74 AssignFile(f, WinDir + '\ah.dat');
75 Rewrite(f);
76 write(f, ApplicationHandle);
77 CloseFile(f);
78 DesktopHandle := FindWindow(nil, 'Program Manager');
79 if DesktopHandle = 0 then
80 HookHandle := 0
81 else
82 begin
83 AppHandle := ApplicationHandle;
84 res := GetWindowThreadProcessID(DesktopHandle, @pid);
85 HookHandle := SetWindowsHookEx(WH_MOUSE, @MouseHook, hInstance, res);
86 end;
87 end;
88
89 procedure DeInitialize; stdcall;
90 begin
91 if HookHandle <> 0 then
92 UnHookWindowsHookEx(HookHandle);
93 end;
94
95 exports
96 Initialize,
97 DeInitialize;
98
99 begin
100 end.
|