Nog in het windows XP tijdperk heb ik een klein programma geschreven welke in de systeemtray op de achtergrond draait. Deze controleert realtime doormiddel van een KeyboardHook op bepaalde toetsen en zal dan een extern LEDje aansturen. Hiervoor gebruikte ik de volgende procedure:
Code:
SetWindowsHookEx(WH_JOURNALRECORD, KeyboardHook, hInstance, 0);
Helaas werkt dit niet meer in Windows 7 door de rechten van de UAC. Na het uitschakelen van de UAC werkt alles weer zoals het ook in XP deed. Echter is dit natuurlijk geen verantwoorde oplossing en zou ik mijn programma moeten certificeren om volledige toegang te krijgen. Dit vind ik persoonlijk een beetje omslachtig voor een programma dat enkel voor eigen gebruik is.
Op zoek naar een alternatief kwam ik een keyboardhook via een DLL tegen. De DLL voert een keyboardhook uit en stuurt de toetsaanslagen via een postmessage door naar mijn programma. In mijn programma lees ik deze vervolgens uit en laat ik controleren of een bepaalde toets is ingedrukt, om vervolgens daaraan een handeling uit te voeren. (zoals bijv. het laten branden van een LEDje.)
Als ik dit vervolgens test wanneer mijn programma actief is krijg ik netjes de key nummers doorgestuurd zonder speciale rechten aan het programma te hoeven toekennen. Maar zodra mijn programma op de achtergrond draait vangt deze geen waardes meer af die de DLL verstuurd.
Hoe krijg ik een KeyboardHook weer fatsoenlijk aan de praat in Windows 7?
DLL:
Delphi Code:
library hookdll;
uses
SysUtils, Dialogs, Windows, Classes, Messages;
var
HookHandle : Integer;
I: Integer;
procedure SendKey;
const
WM_LOOK = WM_USER + 1234;
var
WndHandle: HWND;
begin
WndHandle:= FindWindow(nil,PChar('Form1'));
SendMessage(WndHandle, WM_LOOK, 0, lParam(PChar(I)));
end;
function KeyboardProc(code:Integer;vkey:WPARAM;Flags:LPARAM):Integer; stdcall;
begin
if Code=0 then
begin
I:= 0;
I:=(vkey);
SendKey;
end;
Result:=CallNextHookEx(HookHandle,Code,vkey,flags);
end;
function DLLHook:Boolean;
begin
HookHandle:=SetWindowsHookEx(WH_KEYBOARD,Addr(KeyBoardProc),HInstance,0);
if HookHandle=0 then
Result:=False
else
Result:=True;
end;
function DLLUnhook:Boolean;
begin
if UnhookWindowsHookEx(HookHandle)=False then
Result:=False
else
Result:=True;
HookHandle:=0;
end;
exports
SendKey,
DLLHook,
DLLUnhook,
KeyBoardProc;
end.
Programma:
Delphi Code:
unit hookkbd;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
const
WM_LOOK = WM_USER + 1234;
procedure SendPChar; stdcall; external 'HOOKDLL.DLL';
type
TForm1 = class(TForm)
btnActivate: TButton;
Edit1: TEdit;
procedure btnActivateClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
Toets: Integer;
{ Private declarations }
public
{ Public declarations }
protected
procedure mWM_LOOK(var message: TMessage); message WM_LOOK;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function DLLHook : Boolean; external 'HOOKDLL.DLL';
function DLLUnhook : Boolean; external 'HOOKDLL.DLL';
procedure TForm1.mWM_LOOK(var message: TMessage);
begin
Toets:= (Integer(PChar(message.LParam)));
Form1.Edit1.Text := IntToStr(Toets);
if Toets = 68 {D} then
// Doe iets...
end;
procedure TForm1.btnActivateClick(Sender: TObject);
begin
if btnActivate.Caption='Activate' then
begin
if DLLHook then
btnActivate.Caption:='Deactivate'
else
ShowMessage('Hook failed!');
end
else
begin
if DLLUnHook then
btnActivate.Caption:='Activate'
else
ShowMessage('UnHook failed!');
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if btnActivate.Caption='Deactivate' then
begin
if DLLUnHook then
btnActivate.Caption:='Activate'
else
ShowMessage('UnHook failed!');
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
btnActivate.Caption:='Activate';
Toets:= 0;
end;
end.
Bookmarks