Solved

Mouse click/key press logging

Posted on 2004-09-01
10
653 Views
Last Modified: 2012-05-05
I'm trying to write a simple DLL to monitor systemwide mouse clicks and keyboard presses. I found some code in the Borland Community pages which has got me off to a start but it is quite a lot more complicated than I had hoped. All I want is to have a running count of mouse clicks (maybe breaking them up by which button was pressed) and key presses (likewise which key was pressed).

This is the semicomplete code (for just keystrokes) I have so far:

library Keyhook;

uses
  SysUtils,
  Classes,
  Windows,
  Messages,
  dialogs,
  Shared in 'Shared.pas';

{$R *.RES}

var

  FKeyHook : HHOOK;
  count:integer;


{keyboard hook function}
function  KeyboardProc(Code : Integer;WP : WPARAM;LP : LPARAM) : LRESULT;stdcall;
begin
  if (Code < 0) then
  begin
    Result := CallNextHookEx(fkeyhook,code,WP,LP);
    Exit;
  end;

  count := count + 1;
  Result := CallNextHookEx(FKeyHook,Code,WP,LP);
end;

procedure DLLEntryPoint(dwReason : DWORD);
begin
  case dwReason of
  DLL_PROCESS_ATTACH:
    begin
      FKeyHook := SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,hInstance,0);
      DisableThreadLibraryCalls(hInstance);
    end;
  DLL_PROCESS_DETACH:
    begin
      UnhookWindowsHookEx(FKeyHook);
    end;
  end;
end;

// this function returns the number of keystrokes as a string
// for use by the host application
function GetKeyStrokes(id:integer):PChar;stdcall;
begin
    result := PChar(inttostr(count));
end;


exports GetKeyStrokes name 'GetKeyStrokes';
exports KeyboardProc name 'KeyboardProc';

begin
  //Intialized := false;
  count := 0;
  DllProc := @DLLEntryPoint;
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.


It seems to be having problems removing the hook; every time I run the host app and press a key, the count increment is 1 more than it was last time?

Any advice/help welcome, I've never worked with Hooks before so this is a bit new to me :)
0
Comment
Question by:nem2k4
  • 5
  • 3
  • 2
10 Comments
 
LVL 11

Expert Comment

by:robert_marquardt
ID: 11961463
The problem with global hooks is that the HHOOK variable (and the Count variable) have to live in a shared segment.
The DLL is loaded into *all* applications and gets its own data segment for each application making it effectively a copy of the DLL.
So the HHOOK variable is only initialized in one of the DLLs.

There are several ways to share the variables. A memory mapped file is one way.
Search Borland Community for "Petr Vones Shared Segment" and you should find an alternative.
There the DLL is manipulated to contain a shared segment.
0
 
LVL 11

Expert Comment

by:robert_marquardt
ID: 11961480
Your GetKeyStrokes function is buggy.
In fact you return a PChar to a string which is already deallocated at that time.
It is also clumsy. Return an Integer and let the calling application do the formatting.
0
 
LVL 33

Expert Comment

by:Slick812
ID: 11965554
hello  nem2k4, , I do not think it is correct to call the SetWindowsHook  in the  DLL_PROCESS_ATTACH, because this DLL_PROCESS_ATTACH  will be called for each Application that is running, as a HOOK dll gets loaded into every process that is in the system message hadeling, , , here is some code that may help you at this EE question - -


http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20587437.html

ask questions if you need more information
0
 

Author Comment

by:nem2k4
ID: 11968907
In case you were wondering, this DLL is being made as a plugin for an application, that's why I had that GetKeyStrokes function returning a PChar (that's how the app's SDK works). This is how I want it to work:

* The host app can call LoadLibrary multiple times, once for each time the plugin is used.
* The first time the plugin is loaded, the hooks should be set up. Any subsequent calls to loadlibrary should not set up any more hooks obviously :)
* The host app needs to retrieve the number of mouse clicks/key presses/etc. from the plugin
0
 

Author Comment

by:nem2k4
ID: 11969993
This is what I have now. Trouble is, the count seems to increase by 3 each time the mouse is clicked, and it starts off at a high number (over 300).



library MouseHook;

uses
  Windows, Messages, SysUtils{,dialogs};

{$R *.RES}

type
  PHookRec = ^THookRec;
  THookRec = Record
    AppHnd,
    HookHnd,
    hWnd: Integer;
    end;

var
Hooked: Boolean;
hKeyHook, hApp, hMemFile: HWND;
PHookRec1: PHookRec;
Count:integer;

function MakeInt(HiI, LoI: SmallInt): Cardinal;
begin
Result := Word(HiI) shl 16 or Word(LoI);
end;

function HookProc(Code, wParam: Integer; var MouseStrut: TMOUSEHOOKSTRUCT): Integer; stdcall;
begin
Result := CallNextHookEx( PHookRec1^.HookHnd, Code, wParam, Integer(@MouseStrut));
if Code = HC_ACTION then
  begin
  count := count+1;
  if (wParam = WM_MOUSEMOVE) or (wParam = WM_RBUTTONUP) or
  (wParam = WM_LBUTTONUP) or (wParam = WM_MBUTTONUP) then
    begin
    if hApp > 0 then
    {PostMessage(hApp, WM_USER + 814, MakeInt(SmallInt(MouseStrut.pt.x),
    SmallInt(MouseStrut.pt.y)), MakeInt(Word(MouseStrut.hwnd),
    SmallInt(MouseStrut.wHitTestCode)));}
    {or
    PostMessage(hApp, WM_USER + 814,wParam, Integer(@MouseStrut));}
    end;
  end;
end;

function GetModuleHandleFromInstance: THandle;
var
Name: array[0..1023] of char;
begin
GetModuleFileName(hInstance, Name, 1023);
Result := GetModuleHandle(Name);
end;


function StartHook(AppHnd: HWND) : Integer; export;
begin
{Result of Zero indicates success}
Result := 0;
if Hooked then
  begin
  Result := 1;
  Exit;
  end;
{if not IsWindow(AppHnd) then
  begin
  Result := 2;
  Exit;
  end;}
hApp := AppHnd;
hKeyHook := SetWindowsHookEx(WH_MOUSE, @HookProc, GetModuleHandleFromInstance, 0);
if hKeyHook > 0 then
  begin
  hMemFile := CreateFileMapping($FFFFFFFF, nil,PAGE_READWRITE,0,
              SizeOf(THookRec), 'Global2a5p');
  PHookRec1 := MapViewOfFile(hMemFile, FILE_MAP_WRITE, 0, 0, 0);
  PHookRec1^.AppHnd := AppHnd;
  PHookRec1.hWnd := 0;
  PHookRec1^.HookHnd := hKeyHook;
  Hooked := True;
  end else
  Result := 3;
end;


function StopHook: Boolean; export;
begin
if PHookRec1 <> nil then
  begin
  UnmapViewOfFile(PHookRec1);
  CloseHandle(hMemFile);
  PHookRec1 := nil;
  end;
if Hooked then
Result := UnhookWindowsHookEx(hKeyHook) else
Result := True;
Hooked := False;
hKeyHook := 0;
end;

procedure EntryProc(dwReason : DWORD);
begin
if (dwReason = Dll_Process_Attach) then
  begin
  hMemFile := OpenFileMapping(FILE_MAP_WRITE, False, 'Global2a5p');
  if HMemFile > 0 then
  PHookRec1 := MapViewOfFile(hMemFile, FILE_MAP_WRITE, 0, 0, 0);
  if PHookRec1 <> nil then
    hApp := PHookRec1.AppHnd;
  //showmessage(inttostr(starthook(0)));
  starthook(0);
  end;

if (dwReason = Dll_Process_Detach) then
  begin
  if Hooked then
  StopHook;
  if PHookRec1 <> nil then
    begin
    UnmapViewOfFile(PHookRec1);
    CloseHandle(hMemFile);
    end;
  end;
end;



function init():PChar;stdcall;
begin
    Result:= 'GetKeyStrokes';
end;

function dlltype(): Integer;
begin
    result := 1;
end;

Function getparam(func: PChar):PChar;stdcall;
begin
    Result := '';
end;


function GetKeyStrokes(id:integer):PChar;stdcall;
begin
    result := PChar(inttostr(count));
end;



exports
  StartHook,
  StopHook;
exports GetKeyStrokes name 'GetKeyStrokes';
exports Init name 'init';
exports DLLType name 'dlltype';
exports getparam name 'getparam';

begin
Hooked := False;
hKeyHook := 0;
hApp := 0;
count := 0;
PHookRec1 := nil;
DLLProc := @EntryProc;
EntryProc(Dll_Process_Attach);
end.
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

Author Comment

by:nem2k4
ID: 11970005
Once my app has quit, the plugin still appears to be loaded or something; I can't delete the DLL file because it is still "in use". Perhaps the hook is not being removed or something?
0
 
LVL 33

Expert Comment

by:Slick812
ID: 11976939
I must  ask?  Why did you include the  starthook(0);  in the  Dll_Process_Attach  , , that is Bad Coding. and may prevent the DLL from ever being "Not Used" (can not delete it)
You do not seem to realize that this  DLL will be loaded in to Many different processes, so this DLL will have many different instances running at the same time, since for a "HOOK"  the system will load the DLL into every running process (in the message system). So to have a "Data" element like a Click or key count you will need to have this in your memory Mapped file, NOT in a variable in your DLL. So your function -

function GetKeyStrokes(id:integer):PChar;stdcall;
begin
    result := PChar(inttostr(count));
end;

can Not give you the correct number, and why do you use the   "stdcall" ? ? and You should return an Integer, NOT a PChar for this type of function. . .
( you also have the WM_MOUSEMOVE in your code which will really mess up your results!)


Here is some Code for a DLL library to count all of the key presses and Mouse Clicks



library KeyMoseHook;

uses
  Messages, Windows;

{$R *.RES}

type
  PHookRec = ^THookRec;
  THookRec = packed Record
    hSend, KeyCount, MouseCount: Cardinal;
  {you do not seem to get that this DLL will be loaded in to EVERY running
  program on your computer, and within those programs messages, it will send
  all of the mouse and keboard messages to this DLL. But because there may
   be a 100 of your DLLs working at any time, They will need to have a
   "Data" storage out side of that process, in a Memory Mapped File.
   So you will nedd a KeyCount  and  MouseCount  in the Mem Mapped file}
    end;

var
Hooked: Boolean = False;
hKeyHook, hMouseHook, hMemFile: HWND;
DTime: Cardinal;
PHookRec1: PHookRec = nil;


function MouseHookFunc(Code, wParam, MouseStrut: Integer): Integer; stdcall;
begin
{this is the Mouse Hook function, I call the CallNextHookEx first because
you do not need to block the Mouse events}
Result := CallNextHookEx(hMouseHook, Code, wParam, MouseStrut);
if Code < 0 then Exit;

if (Code = HC_ACTION)then
  begin
  {to make sure I get a Click and not a drag, I will get the Ticks in DTime}
  if (wParam = WM_RBUTTONDOWN) or (wParam = WM_LBUTTONDOWN) or (wParam = WM_MBUTTONDOWN) then
    DTime := GetTickCount;

  if (wParam = WM_RBUTTONUP) or (wParam = WM_LBUTTONUP) or (wParam = WM_MBUTTONUP) then
    if (GetTickCount - DTime < 400) and not IsBadCodePtr(PHookRec1) then
    begin
    {I use  IsBadCodePtr(PHookRec1)  because it is posible NOT to have the system
    Memory Mapped File Created}

    if PHookRec1.MouseCount < MAXDWORD then  // do not go over range
      Inc(PHookRec1.MouseCount);  {you must use data in the mem mapped file
                                  to keep count of something in all od the DLLs}
    PostMessage(PHookRec1.hSend, WM_USER+648, 11, Integer(PHookRec1.MouseCount));
    {send a message to your Appliction to tell it the numbers have changed}
    Exit;
    end;
  end;
end;


function KeyHookFunc(Code, VirtualKey, KeyStroke: Integer): Integer; stdcall;
begin
{this is the Key Hook Function}
Result := 0;
if Code = HC_NOREMOVE then Exit;
Result := CallNextHookEx(hKeyHook, Code, VirtualKey, KeyStroke);

if Code = HC_ACTION then
  begin
  if ((KeyStroke and (1 shl 30)) = 0) and not IsBadCodePtr(PHookRec1) then
    begin
    if PHookRec1.KeyCount < MAXDWORD then  // do not go over range
      Inc(PHookRec1.KeyCount);
    PostMessage(PHookRec1.hSend, WM_USER+648, 22, Integer(PHookRec1.KeyCount));
    end;
  end;

end;

function StartHook(SendHandle: HWND): Integer; export;
begin
Result := 0;
if Hooked then
  begin
  Result := 1;
  Exit;
  end;
if not IsWindow(SendHandle) then
  begin
  Result := 4;
  Exit;
  end;

hKeyHook := SetWindowsHookEx(WH_KEYBOARD, KeyHookFunc, hInstance, 0);
if hKeyHook <> 0 then
  begin
  {create your mem mapped file}
  hMemFile := CreateFileMapping($FFFFFFFF, // $FFFFFFFF gets a page memory file
                nil,                // no security attributes
                PAGE_READWRITE,      // read/write access
                0,                   // size: high 32-bits
                SizeOf(THookRec),           // size: low 32-bits
                //SizeOf(Integer),
                'v7g27v9khf1');    // name of map object
  PHookRec1 := MapViewOfFile(hMemFile, FILE_MAP_WRITE, 0, 0, 0);
  if PHookRec1 = nil then
    begin
    {there may be system errors that prevent mem mapp creation}
    CloseHandle(hMemFile);
    UnhookWindowsHookEx(hKeyHook);
    Result := 3;
    Exit;
    end;

  PHookRec1.hSend := SendHandle;
  PHookRec1.KeyCount := 0; // be sure to Initalize your Data
  PHookRec1.MouseCount := 0;
  Hooked := True;
  hMouseHook := SetWindowsHookEx(WH_MOUSE, @MouseHookFunc, hInstance, 0);
  end else
  Result := 2;
end;

function StopHook: Boolean; export;
begin
if Hooked then
  begin
  UnhookWindowsHookEx(hMouseHook);
  Result := UnhookWindowsHookEx(hKeyHook);
  end else
  Result := True;
if PHookRec1 <> nil then
  begin
  UnmapViewOfFile(PHookRec1);
  CloseHandle(hMemFile);
  PHookRec1 := nil;
  end;
Hooked := False;
end;

procedure EntryProc(dwReason: Cardinal);
begin
if (dwReason = Dll_Process_Attach) then
  begin
  hMemFile := OpenFileMapping(FILE_MAP_WRITE, False, 'v7g27v9khf1');
  if hMemFile <> 0 then
    PHookRec1 := MapViewOfFile(hMemFile, FILE_MAP_WRITE, 0, 0, 0);
  {system errors may prevent mem mapp creation, a rare thing}
  end else
  if (dwReason = Dll_Process_Detach) then
  begin
  UnhookWindowsHookEx(hMouseHook);
  UnhookWindowsHookEx(hKeyHook);
  if PHookRec1 <> nil then
    begin
    UnmapViewOfFile(PHookRec1);
    CloseHandle(hMemFile);
    end;
  end;
end;

exports
  StartHook,
  StopHook;

begin
hKeyHook := 0;
hMouseHook := 0;
hMemFile := 0;
DLLProc := @EntryProc;
EntryProc(Dll_Process_Attach);
end.



 - = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =\

here is some code for the Program to Call this DLL functions


  TForm1 = class(TForm)

  private
    { Private declarations }
    hLibKM: Integer;
    procedure DLLMess(var Msg : TMessage); message WM_USER+648;



procedure TForm1.FormCreate(Sender: TObject);
begin
hLibKM := 0;
end;


procedure TForm1.DLLMess(var Msg : TMessage);
begin
if Msg.wParam = 22 then
  Label6.Caption := 'Key press count = '+IntToStr(Cardinal(Msg.lParam));

if Msg.wParam = 11 then
  Label7.Caption := 'Mouse Click count = '+IntToStr(Cardinal(Msg.lParam));
end;



procedure TForm1.sbut_StartKeyMosHookClick(Sender: TObject);
var
SHresult: Integer;
StartHook1: function(SendHandle: HWND): Integer;

begin
if hLibKM <> 0 then Exit;
hLibKM := LoadLibrary('KeyMoseHook.dll');
if hLibKM = 0 then
  begin
  ShowMessage('Did not load the DLL');
  Exit;
  end;
@StartHook1 := GetProcAddress(hLibKM, 'StartHook');
if @StartHook1 <> nil then
  begin
  SHresult := StartHook1(Handle);
  if SHresult <> 0 then
    ShowMessage('ERROR - Did Not Start the Hook');
  end else
  Showmessage('ERROR - Did not get StartHook address');

end;


procedure TForm1.sbut_StopKeyMosHookClick(Sender: TObject);
var
StopHook1: function: Boolean;
begin
if hLibKM <> 0 then
  begin
  @StopHook1 := GetProcAddress(hLibKM, 'StopHook');
  if @StopHook1 <> nil then
  begin
  if not StopHook1 then
    ShowMessage('ERROR - Did Not Stop the Hook');
  end else
  Showmessage('ERROR - Did not get StartHook address');
  FreeLibrary(hLibKM);
  FreeLibrary(hLibKM);
  hLibKM := 0;
  end
end;


 - - - - - - - -  - - - - - - - - - - - - - - - - - - -  - - - -

hope this is helpful
0
 

Author Comment

by:nem2k4
ID: 11979139
I need the StarkHook() to be called once by the DLL - if you seee my previous comment, you will see that this library is being loaded by an application with a standard SDK - I can't call StartHook/StopHook from within my application, I need it all to be handled within the library. Also it is why the function returns a PChar and it has the stdcall directive on it - the application needs these to be there in order to talk to the DLL.

Is there some way to place the StartHook/StopHook calls in the library itself so that they are called only once, when the library is first loaded/last unloaded by any process?
0
 
LVL 33

Accepted Solution

by:
Slick812 earned 125 total points
ID: 11981362
OK, another library, this one will start the hook when ever the library is loaded, I have included the   init, DllType and GetKeyStrocks functions




library KeyMoseHook;

uses
  Messages, Windows, SysUtils;

{$R *.RES}

type
  PHookRec = ^THookRec;
  THookRec = packed Record
    KeyCount, LeftBCount, RightBCount, MiddleBCount: Cardinal;
  {you do not seem to get that this DLL will be loaded in to EVERY running
  program on your computer, and within those programs messages, it will send
  all of the mouse and keboard messages to this DLL. But because there may
   be a 100 of your DLLs working at any time, They will need to have a
   "Data" storage out side of that process, in a Memory Mapped File.
   So you will nedd a KeyCount  and  MouseCount  in the Mem Mapped file}
    end;

var
Hooked: Boolean = False;
hKeyHook, hMouseHook, hMemFile: HWND;
DTime: Cardinal;
PHookRec1: PHookRec = nil;


function MouseHookFunc(Code, wParam, MouseStrut: Integer): Integer; stdcall;
begin
{this is the Mouse Hook function, I call the CallNextHookEx first because
you do not need to block the Mouse events}
Result := CallNextHookEx(0, Code, wParam, MouseStrut);
if Code < 0 then Exit;

if (Code = HC_ACTION)then
  begin
  {to make sure I get a Click and not a drag, I will get the Ticks in DTime}
  if (wParam = WM_RBUTTONDOWN) or (wParam = WM_LBUTTONDOWN) or (wParam = WM_MBUTTONDOWN) then
    DTime := GetTickCount;

  if (wParam = WM_LBUTTONUP) and (GetTickCount - DTime < 400) and
    not IsBadCodePtr(PHookRec1) then
    if PHookRec1.LeftBCount < MAXDWORD then  // do not go over range
        Inc(PHookRec1.LeftBCount);

  if (wParam = WM_RBUTTONUP) and (GetTickCount - DTime < 400) and
    not IsBadCodePtr(PHookRec1) then
    if PHookRec1.RightBCount < MAXDWORD then  // do not go over range
        Inc(PHookRec1.RightBCount);

  if (wParam = WM_MBUTTONUP) and (GetTickCount - DTime < 400) and
    not IsBadCodePtr(PHookRec1) then
    if PHookRec1.MiddleBCount < MAXDWORD then  // do not go over range
        Inc(PHookRec1.MiddleBCount);

 // if (wParam = WM_RBUTTONUP) or  or (wParam = WM_MBUTTONUP) then
 //   if (GetTickCount - DTime < 400) and not IsBadCodePtr(PHookRec1) then
 //   begin
    {I use  IsBadCodePtr(PHookRec1)  because it is posible NOT to have the system
    Memory Mapped File Created}

//    if PHookRec1.MouseCount < MAXDWORD then  // do not go over range
//     Inc(PHookRec1.MouseCount);  {you must use data in the mem mapped file
 //                                 to keep count of something in all od the DLLs}
 //   PostMessage(PHookRec1.hSend, WM_USER+648, 11, Integer(PHookRec1.MouseCount));
    {send a message to your Appliction to tell it the numbers have changed}
 //   Exit;
 //   end;
  end;
end;


function KeyHookFunc(Code, VirtualKey, KeyStroke: Integer): Integer; stdcall;
begin
{this is the Key Hook Function}
Result := 0;
if Code = HC_NOREMOVE then Exit;
Result := CallNextHookEx(0, Code, VirtualKey, KeyStroke);

if Code = HC_ACTION then
  begin
  if ((KeyStroke and (1 shl 30)) = 0) and not IsBadCodePtr(PHookRec1) then
    begin
    if PHookRec1.KeyCount < MAXDWORD then  // do not go over range
      Inc(PHookRec1.KeyCount);
    end;
  end;

end;

procedure StartHook;
begin
if Hooked then Exit;

hKeyHook := SetWindowsHookEx(WH_KEYBOARD, KeyHookFunc, hInstance, 0);
if hKeyHook <> 0 then
  begin
  {create your mem mapped file}
  hMemFile := CreateFileMapping($FFFFFFFF, // $FFFFFFFF gets a page memory file
                nil,                // no security attributes
                PAGE_READWRITE,      // read/write access
                0,                   // size: high 32-bits
                SizeOf(THookRec),           // size: low 32-bits
                //SizeOf(Integer),
                'v7g27v9khf1');    // name of map object
  PHookRec1 := MapViewOfFile(hMemFile, FILE_MAP_WRITE, 0, 0, 0);
  if PHookRec1 = nil then
    begin
    {there may be system errors that prevent mem mapp creation}
    CloseHandle(hMemFile);
    UnhookWindowsHookEx(hKeyHook);
    Exit;
    end;
  //PHookRec1.hHook := hKeyHook;
  PHookRec1.KeyCount := 0; // be sure to Initalize your Data
  PHookRec1.LeftBCount := 0;
  PHookRec1.RightBCount := 0;
  PHookRec1.MiddleBCount := 0;
  Hooked := True;
  hMouseHook := SetWindowsHookEx(WH_MOUSE, @MouseHookFunc, hInstance, 0);
  end;
end;

{function StopHook: Boolean; export;
begin
if Hooked then
  begin
  UnhookWindowsHookEx(hMouseHook);
  Result := UnhookWindowsHookEx(hKeyHook);
  end else
  Result := True;
if PHookRec1 <> nil then
  begin
  UnmapViewOfFile(PHookRec1);
  CloseHandle(hMemFile);
  PHookRec1 := nil;
  end;
Hooked := False;
end; }


function init: PChar; stdcall; export;
begin
Result:= 'GetKeyStrokes';
end;

function dlltype: Integer; stdcall; export;
begin
result := 1;
end;

function getparam(func: PChar): PChar; stdcall; export;
begin
Result := nil;
end;

function GetKeyStrokes(id: Integer): PChar; stdcall; export;
begin
Result := nil;
if IsBadCodePtr(PHookRec1) then Exit;
Case id of
  0: result := PChar(inttostr(PHookRec1.KeyCount));
  1: result := PChar(inttostr(PHookRec1.LeftBCount));
  2: result := PChar(inttostr(PHookRec1.RightBCount));
  3: result := PChar(inttostr(PHookRec1.MiddleBCount));
  end;
end;

procedure EntryProc(dwReason: Cardinal);
begin
if (dwReason = Dll_Process_Attach) then
  begin
  hMemFile := OpenFileMapping(FILE_MAP_WRITE, False, 'v7g27v9khf1');
  if hMemFile = 0 then
    StartHook
    else
    PHookRec1 := MapViewOfFile(hMemFile, FILE_MAP_WRITE, 0, 0, 0);
  end else
  if (dwReason = Dll_Process_Detach) then
  begin
  UnhookWindowsHookEx(hMouseHook);
  UnhookWindowsHookEx(hKeyHook);
  if PHookRec1 <> nil then
    begin
    UnmapViewOfFile(PHookRec1);
    CloseHandle(hMemFile);
    end;
  end;
end;

exports
  init, dlltype, getparam, GetKeyStrokes;

begin
hKeyHook := 0;
hMouseHook := 0;
hMemFile := 0;
DLLProc := @EntryProc;
EntryProc(Dll_Process_Attach);
end.


= = = = = = = = = = = = = = = = = = =  = = = = = = = = = = = = = =

button clicks in the Loading Program

procedure TForm1.sbut_StartKeyMosHookClick(Sender: TObject);
begin
hLibKM := LoadLibrary('KeyMoseHook.dll');
if hLibKM = 0 then
  begin
  ShowMessage('Did not load the DLL');
  Exit;
  end;
end;

procedure TForm1.sbut_GetKeyMosInfoClick(Sender: TObject);
var
GetKeyStrokes1: function(id: Integer): PChar; stdcall;
begin
if hLibKM = 0 then Exit;
@GetKeyStrokes1 := GetProcAddress(hLibKM, 'GetKeyStrokes');
if @GetKeyStrokes1 <> nil then
  begin
  Label6.Caption := 'Key Presses is '+GetKeyStrokes1(0);
  Label7.Caption := 'Left Clicks is '+GetKeyStrokes1(1);
  end else
  Showmessage('ERROR - Did not get GetKeyStrokes1 address');
end;

= = = = = = = = = = = = = = = = = = = =  = = = = = = = = = = = = = = = = = = =

I can not see any thing when you say =
"The host app can call LoadLibrary multiple times, once for each time the plugin is used."

OK if a Library is "Loaded" it will just get the handle of the library already loaded on the next call to "LoadLibrary( )" so I do not follow this statement, however, if you mean that the program will load this library and then "Free" this library before it Loads it again, then I do not know of a way to keep the hooks running if a library is not loaded in a program. . .

you may need to study up on your API methods inorder to have a better idea of how to modify this code to do what you want it to do
0
 

Author Comment

by:nem2k4
ID: 11982309
Perfect, just what I wanted! Thanks a lot :)
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now