home *** CD-ROM | disk | FTP | other *** search
- { }
- { This is the core of the system and task hook. Some notes: }
- { }
- { 1) You will definitely want to give the file a more descriptive name }
- { to avoid possible collisions with other DLL names. }
- { 2) Edit the MouseHookCallBack function to do what you need when a }
- { mouse message is received. If you are hooking something other }
- { mouse messages, see the SetWindowsHookEx topic in the help for the }
- { proper WH_xxxx constant, and any notes about the particular type }
- { of hook. }
- { 3) If an application that uses the DLL crashes while the hook is }
- { installed, all manner of wierd things can happen, depending on the }
- { sort of thing you are doing in the callback. The best suggestion }
- { is to use a utility that displays loaded DLLs and forcibly unload }
- { the DLL. You could also write a simple app that checks to see if }
- { the DLL is loaded, and if so, call FreeModule until it returns 0. }
- { 4) If you make changes to the DLL but the changes don't seem to be }
- { working, you may have the DLL already loaded in memory. Remember, }
- { loading a DLL that is already in memory just increments a usage }
- { count in Windows and uses the already loaded copy. }
- { 5) Remember when you are hooking in at the *system* level, your }
- { callback function is being called for everything in the OS. Try }
- { to keep the processing in the callback as tight and fast as you }
- { possibly can. }
- { 6) Be careful of the uses clause. If you include stuff like Dialogs, }
- { you will end up linking in a lot of the VCL, and have a DLL that }
- { comes out compiled to around 250k. You would probably be better }
- { served using WM_USER messages to communicate with the application. }
- { 7) I have successfully hooked mouse messages without the use of a }
- { DLL, but many of the hooks say they require the callback to be in }
- { a DLL, so I am hesitant to include this method. It certainly }
- { makes the build/test cycle *much* easier, but since it is not }
- { "sanctioned" by MS, I would stay away from it and discourage it. }
- { }
-
- library HookDLL;
-
- uses WinTypes, WinProcs, Messages;
-
-
- var
- HookCount: integer;
- HookHandle: HHook;
-
-
- { This is where you do your special processing. }
- {$IFDEF WIN32}
- function MouseHookCallBack(Code: integer; Msg: WPARAM; MouseHook: LPARAM): LRESULT; stdcall;
- {$ELSE}
- function MouseHookCallBack(Code: integer; Msg: word; MouseHook: longint): longint; export;
- {$ENDIF}
- begin
- { If the value of Code is less than 0, we are not allowed to do anything except pass }
- { it on to the next hook procedure immediately. }
- if Code >= 0 then begin
- { This example does nothing except beep when the right mouse button is pressed. }
- if Msg = WM_RBUTTONDOWN then
- MessageBeep(1);
- { This is probably closer to what you would want to do...
- case Msg of:
- WM_LBUTTONDOWN:
- begin
- end;
- WM_LBUTTONUP:
- begin
- end;
- WM_LBUTTONDBLCLK:
- begin
- end;
- WM_RBUTTONDOWN:
- begin
- end;
- WM_RBUTTONUP:
- begin
- end;
- WM_RBUTTONDBLCLK:
- begin
- end;
- WM_MBUTTONDOWN:
- begin
- end;
- WM_MBUTTONUP:
- begin
- end;
- WM_MBUTTONDBLCLK:
- begin
- end;
- WM_MOUSEMOVE:
- begin
- end;
- end;}
-
- { If you handled the situation, and don't want Windows to process the }
- { message, do *NOT* execute the next line. Be very sure this is what }
- { want, though. If you don't pass on stuff like WM_MOUSEMOVE, you }
- { will NOT like the results you get. }
- Result := CallNextHookEx(HookHandle, Code, Msg, MouseHook);
- end else
- Result := CallNextHookEx(HookHandle, Code, Msg, MouseHook);
- end;
-
- { Call InstallHook to set the hook. }
- function InstallHook(SystemHook: boolean; TaskHandle: THandle) : boolean; export;
- { This is really silly, but that's the way it goes. The only way to get the }
- { module handle, *not* instance, is from the filename. The Microsoft example }
- { just hard-codes the DLL filename. I think this is a little bit better. }
- function GetModuleHandleFromInstance: THandle;
- var
- s: array[0..512] of char;
- begin
- { Find the DLL filename from the instance value. }
- GetModuleFileName(hInstance, s, sizeof(s)-1);
- { Find the handle from the filename. }
- Result := GetModuleHandle(s);
- end;
- begin
- { Technically, this procedure could do nothing but call SetWindowsHookEx(), }
- { but it is probably better to be sure about things, and not set the hook }
- { more than once. You definitely don't want your callback being called more }
- { than once per message, do you? }
- Result := TRUE;
- if HookCount = 0 then begin
- if SystemHook then
- HookHandle := SetWindowsHookEx(WH_MOUSE, MouseHookCallBack, HInstance, 0)
- else
- { See the Microsoft KnowledgeBase, PSS ID Number: Q92659, for a discussion of }
- { the Windows bug that requires GetModuleHandle() to be used. }
- HookHandle := SetWindowsHookEx(WH_MOUSE, MouseHookCallBack,
- GetModuleHandleFromInstance, TaskHandle);
- if HookHandle <> 0 then
- inc(HookCount)
- else
- Result := FALSE;
- end else
- inc(HookCount);
- end;
-
- { Call RemoveHook to remove the system hook. }
- function RemoveHook: boolean; export;
- begin
- { See if our reference count is down to 0, and if so then unhook. }
- Result := FALSE;
- if HookCount < 1 then exit;
- Result := TRUE;
- dec(HookCount);
- if HookCount = 0 then
- Result := UnhookWindowsHookEx(HookHandle);
- end;
-
- { Have we hooked into the system? }
- function IsHookSet: boolean; export;
- begin
- Result := (HookCount > 0) and (HookHandle <> 0);
- end;
-
- exports
- InstallHook,
- RemoveHook,
- IsHookSet,
- MouseHookCallBack;
-
- { Initialize DLL data. }
- begin
- HookCount := 0;
- HookHandle := 0;
- end.
-
-