jmarin
asked on
Hook a Shell
I'm using SetWindowsHookEx API function with parameter WH_SHELL in a DLL.
When my application call the DLL and active the hook, the taskbar not update when launch and close programs.
Urgent, please send code.
When my application call the DLL and active the hook, the taskbar not update when launch and close programs.
Urgent, please send code.
ASKER
Edited text of question.
Mmmh, let's see if I got this. I guess you mean that when you activate your hook the shell does not work any longer as before, right?
If this is the case then I assume you don't call the next hook correctly. A common mistake in this regard is to store the handle of the hook in a global variable in the unit where the hook is implemented. But since the hook code is called in the various process contexts this variable is only valid for the process which set the hook. In order to make it available to all process contexts you'd need additional work. One approach has proven to be reliable: memory mapped files.
But before I continue I wanna know if this is what your problem is...
Ciao, Mike
If this is the case then I assume you don't call the next hook correctly. A common mistake in this regard is to store the handle of the hook in a global variable in the unit where the hook is implemented. But since the hook code is called in the various process contexts this variable is only valid for the process which set the hook. In order to make it available to all process contexts you'd need additional work. One approach has proven to be reliable: memory mapped files.
But before I continue I wanna know if this is what your problem is...
Ciao, Mike
ASKER
Thanks Mike for your comment.
You have code of a Hook Shell?
You have code of a Hook Shell?
jmarin,
I have code for a mouse hook which is basically the same as a shell hook, but you haven't answered my question. Is it so that the shell does not work properly after you have set the hook, yes or no? I need to know this to take the right steps for your problem!
Ciao, Mike
I have code for a mouse hook which is basically the same as a shell hook, but you haven't answered my question. Is it so that the shell does not work properly after you have set the hook, yes or no? I need to know this to take the right steps for your problem!
Ciao, Mike
ASKER
The Hook not work properly after of installed. The taskbar not work properly and deactive the Win95 System Key. I proof Mouse Hook and work very well, but not Shell Hook.
Mmmh, if a mouse hook works fine but not the shell hook then the problem becomes really difficult. Please post your code of the call back functions here (stripped down if it is too much).
I'm here tomorrow again...
Ciao, Mike
I'm here tomorrow again...
Ciao, Mike
ASKER
This Unit is used in the creation of DLL
In dll, export two function: one for set hook active and other for set hook inactive.
unit ShellHook;
interface
Uses Windows,SysUtils,Classes,C ontrols;
Type
THookMsg = Packed record
Code : integer;
WParam : WPARAM;
LParam : LPARAM;
Result : LResult
end;
Type
THook = Class;
THookMethod = procedure (var HookMsg: THookMsg) of object;
THookNotify = procedure (Hook : THook; var Hookmsg: THookMsg) of object;
THook = Class
Private
FHook : hHook;
FHookProc : Pointer;
FOnPreExecute : THookNotify;
FOnPostExecute : THookNotify;
FActive : Boolean;
FLoadedActive : Boolean;
FThreadID : Integer;
Procedure SetActive(NewState : Boolean);
Procedure SetThreadID(NewID : INteger);
Procedure HookProc(Var HookMsg : THookMsg);
Protected
Procedure PreExecute(Var HookMsg : THookMsg; Var Handled : Boolean); Virtual;
Procedure PostExecute(Var HookMsg : THookMsg); Virtual;
Function AllocateHook : hHook; Virtual; Abstract;
Public
Constructor Create;
Destructor Destroy; Override;
Property ThreadID : Integer Read fThreadID Write SetThreadID Stored False;
Property Active : Boolean Read fActive Write SetActive;
Property OnPreExecute : THookNotify Read fOnPreExecute Write fOnPreExecute;
Property OnPostExecute : THookNotify Read fOnPostExecute Write fOnPostExecute;
Published
End;
Type
TShellHook = Class(THook)
Private
Protected
Public
Function AllocateHook : hHook; Override;
Published
Property Active;
Property OnPreExecute;
Property OnPostExecute;
End;
function MakeHookInstance (Method: THookMethod): pointer;
procedure FreeHookInstance (ObjectInstance: pointer);
implementation
const
InstanceCount = 313;
type
PObjectInstance = ^TObjectInstance;
TObjectInstance = packed record
Code: Byte;
Offset: Integer;
case Integer of
0: (Next: PObjectInstance);
1: (Method: THookMethod);
end;
Type
PInstanceBlock = ^TInstanceBlock;
TInstanceBlock = packed record
Next: PInstanceBlock;
Code: array[1..2] of Byte;
WndProcPtr: Pointer;
Instances: array[0..InstanceCount] of TObjectInstance;
end;
var
InstBlockList : PInstanceBlock = nil;
InstFreeList : PObjectInstance = nil;
function StdHookProc (Code, WParam: WPARAM; LParam: LPARAM): LResult; stdcall; assembler;
asm
XOR EAX,EAX
PUSH EAX
PUSH LParam
PUSH WParam
PUSH Code
MOV EDX,ESP
MOV EAX,[ECX].Longint[4]
CALL [ECX].Pointer
ADD ESP,12
POP EAX
end;
function CalcJmpOffset(Src, Dest: Pointer): Longint;
begin
Result := Longint(Dest) - (Longint(Src) + 5);
end;
function MakeHookInstance(Method: THookMethod): Pointer;
const
BlockCode: array [1..2] of Byte = ($59, $E9);
PageSize = 4096;
var
Block: PInstanceBlock;
Instance: PObjectInstance;
begin
if InstFreeList = nil then
begin
Block := VirtualAlloc (nil, PageSize, MEM_COMMIT,PAGE_EXECUTE_RE ADWRITE);
Block^.Next := InstBlockList;
Move(BlockCode, Block^.Code, SizeOf(BlockCode));
Block^.WndProcPtr := Pointer(CalcJmpOffset(@Blo ck^.Code[2 ],@StdHook Proc));
Instance := @Block^.Instances;
repeat
Instance^.Code := $E8;
Instance^.Offset := CalcJmpOffset(Instance, @Block^.Code);
Instance^.Next := InstFreeList;
InstFreeList := Instance;
Inc(Longint(Instance), SizeOf(TObjectInstance));
until Longint(Instance) - Longint(Block) >= SizeOf(TInstanceBlock);
InstBlockList := Block
end;
Result := InstFreeList;
Instance := InstFreeList;
InstFreeList := Instance^.Next;
Instance^.Method := Method
end;
{ Free a hook method instance }
procedure FreeHookInstance (ObjectInstance: Pointer);
Begin
if ObjectInstance <> nil then
Begin
PObjectInstance(ObjectInst ance)^.Nex t := InstFreeList;
InstFreeList := ObjectInstance
End
End;
Constructor THook.Create;
Begin
fHookProc := MakeHookInstance(HookProc) ;
fActive := false;
fLoadedActive := False;
fHook := 0;
ThreadID := GetCurrentThreadID;
End;
Destructor THook.Destroy;
Begin
Active := False;
FreeHookInstance(fHookProc );
Inherited;
End;
Procedure THook.SetActive(NewState : Boolean);
Begin
If (fActive<>NewState) Then
Begin
fActive := NewState;
Case fActive Of
True : Begin
fHook := AllocateHook;
If (fHook=0) Then
Begin
fActive := False;
Raise Exception.Create(Classname +' CREATION FAILED!');
End;
End;
False : Begin
If (FHook<>0) Then UnhookWindowsHookEx(fHook) ;
fHook := 0;
End;
End;
End;
End;
Procedure THook.SetThreadID(NewID : INteger);
Var
IsActive : Boolean;
Begin
IsActive := fActive;
Active := False;
fThreadID := NewID;
Active := IsActive;
End;
Procedure THook.HookProc(Var HookMsg : THookMsg);
Var
Handled : Boolean;
Begin
Handled := False;
PreExecute(HookMsg,Handled );
If Not Handled Then
Begin
with HookMsg do Result := CallNextHookEx (fHook, Code, wParam, lParam);
PostExecute(HookMsg);
End;
End;
Procedure THook.PreExecute(Var HookMsg : THookMsg; Var Handled : Boolean);
Begin
If Assigned(fOnPreExecute) then
Begin
fOnPreExecute(Self,HookMsg );
End;
End;
Procedure THook.PostExecute(Var HookMsg : THookMsg);
Begin
If Assigned(fOnPostExecute) then
Begin
fOnPostExecute(Self,HookMs g);
End;
End;
Function TShellHook.AllocateHook: hHook;
Begin
Result :=SetWindowsHookEx(WH_SHEL L,fHookPro c,hInstanc e,ThreadID );
End;
end.
In dll, export two function: one for set hook active and other for set hook inactive.
unit ShellHook;
interface
Uses Windows,SysUtils,Classes,C
Type
THookMsg = Packed record
Code : integer;
WParam : WPARAM;
LParam : LPARAM;
Result : LResult
end;
Type
THook = Class;
THookMethod = procedure (var HookMsg: THookMsg) of object;
THookNotify = procedure (Hook : THook; var Hookmsg: THookMsg) of object;
THook = Class
Private
FHook : hHook;
FHookProc : Pointer;
FOnPreExecute : THookNotify;
FOnPostExecute : THookNotify;
FActive : Boolean;
FLoadedActive : Boolean;
FThreadID : Integer;
Procedure SetActive(NewState : Boolean);
Procedure SetThreadID(NewID : INteger);
Procedure HookProc(Var HookMsg : THookMsg);
Protected
Procedure PreExecute(Var HookMsg : THookMsg; Var Handled : Boolean); Virtual;
Procedure PostExecute(Var HookMsg : THookMsg); Virtual;
Function AllocateHook : hHook; Virtual; Abstract;
Public
Constructor Create;
Destructor Destroy; Override;
Property ThreadID : Integer Read fThreadID Write SetThreadID Stored False;
Property Active : Boolean Read fActive Write SetActive;
Property OnPreExecute : THookNotify Read fOnPreExecute Write fOnPreExecute;
Property OnPostExecute : THookNotify Read fOnPostExecute Write fOnPostExecute;
Published
End;
Type
TShellHook = Class(THook)
Private
Protected
Public
Function AllocateHook : hHook; Override;
Published
Property Active;
Property OnPreExecute;
Property OnPostExecute;
End;
function MakeHookInstance (Method: THookMethod): pointer;
procedure FreeHookInstance (ObjectInstance: pointer);
implementation
const
InstanceCount = 313;
type
PObjectInstance = ^TObjectInstance;
TObjectInstance = packed record
Code: Byte;
Offset: Integer;
case Integer of
0: (Next: PObjectInstance);
1: (Method: THookMethod);
end;
Type
PInstanceBlock = ^TInstanceBlock;
TInstanceBlock = packed record
Next: PInstanceBlock;
Code: array[1..2] of Byte;
WndProcPtr: Pointer;
Instances: array[0..InstanceCount] of TObjectInstance;
end;
var
InstBlockList : PInstanceBlock = nil;
InstFreeList : PObjectInstance = nil;
function StdHookProc (Code, WParam: WPARAM; LParam: LPARAM): LResult; stdcall; assembler;
asm
XOR EAX,EAX
PUSH EAX
PUSH LParam
PUSH WParam
PUSH Code
MOV EDX,ESP
MOV EAX,[ECX].Longint[4]
CALL [ECX].Pointer
ADD ESP,12
POP EAX
end;
function CalcJmpOffset(Src, Dest: Pointer): Longint;
begin
Result := Longint(Dest) - (Longint(Src) + 5);
end;
function MakeHookInstance(Method: THookMethod): Pointer;
const
BlockCode: array [1..2] of Byte = ($59, $E9);
PageSize = 4096;
var
Block: PInstanceBlock;
Instance: PObjectInstance;
begin
if InstFreeList = nil then
begin
Block := VirtualAlloc (nil, PageSize, MEM_COMMIT,PAGE_EXECUTE_RE
Block^.Next := InstBlockList;
Move(BlockCode, Block^.Code, SizeOf(BlockCode));
Block^.WndProcPtr := Pointer(CalcJmpOffset(@Blo
Instance := @Block^.Instances;
repeat
Instance^.Code := $E8;
Instance^.Offset := CalcJmpOffset(Instance, @Block^.Code);
Instance^.Next := InstFreeList;
InstFreeList := Instance;
Inc(Longint(Instance), SizeOf(TObjectInstance));
until Longint(Instance) - Longint(Block) >= SizeOf(TInstanceBlock);
InstBlockList := Block
end;
Result := InstFreeList;
Instance := InstFreeList;
InstFreeList := Instance^.Next;
Instance^.Method := Method
end;
{ Free a hook method instance }
procedure FreeHookInstance (ObjectInstance: Pointer);
Begin
if ObjectInstance <> nil then
Begin
PObjectInstance(ObjectInst
InstFreeList := ObjectInstance
End
End;
Constructor THook.Create;
Begin
fHookProc := MakeHookInstance(HookProc)
fActive := false;
fLoadedActive := False;
fHook := 0;
ThreadID := GetCurrentThreadID;
End;
Destructor THook.Destroy;
Begin
Active := False;
FreeHookInstance(fHookProc
Inherited;
End;
Procedure THook.SetActive(NewState : Boolean);
Begin
If (fActive<>NewState) Then
Begin
fActive := NewState;
Case fActive Of
True : Begin
fHook := AllocateHook;
If (fHook=0) Then
Begin
fActive := False;
Raise Exception.Create(Classname
End;
End;
False : Begin
If (FHook<>0) Then UnhookWindowsHookEx(fHook)
fHook := 0;
End;
End;
End;
End;
Procedure THook.SetThreadID(NewID : INteger);
Var
IsActive : Boolean;
Begin
IsActive := fActive;
Active := False;
fThreadID := NewID;
Active := IsActive;
End;
Procedure THook.HookProc(Var HookMsg : THookMsg);
Var
Handled : Boolean;
Begin
Handled := False;
PreExecute(HookMsg,Handled
If Not Handled Then
Begin
with HookMsg do Result := CallNextHookEx (fHook, Code, wParam, lParam);
PostExecute(HookMsg);
End;
End;
Procedure THook.PreExecute(Var HookMsg : THookMsg; Var Handled : Boolean);
Begin
If Assigned(fOnPreExecute) then
Begin
fOnPreExecute(Self,HookMsg
End;
End;
Procedure THook.PostExecute(Var HookMsg : THookMsg);
Begin
If Assigned(fOnPostExecute) then
Begin
fOnPostExecute(Self,HookMs
End;
End;
Function TShellHook.AllocateHook: hHook;
Begin
Result :=SetWindowsHookEx(WH_SHEL
End;
end.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Oops little text corrections (my two years old son is playing around me ... :-):
"While the message frequncy might be quite high it is very likely that the process where the window with the mouse over it belongs too. So what you need is not only a generic, but also a quick solution. "
should read:
"While the message frequency might be quite high, it is very likely that the process where the window with the mouse over it belongs too changes over and over again. So what you need is not only a generic, but also a quick solution. "
"While the message frequncy might be quite high it is very likely that the process where the window with the mouse over it belongs too. So what you need is not only a generic, but also a quick solution. "
should read:
"While the message frequency might be quite high, it is very likely that the process where the window with the mouse over it belongs too changes over and over again. So what you need is not only a generic, but also a quick solution. "
ASKER
Lischke, thanks you.
Win the points
Win the points
Thanks jmarin, but a C grade for my little tutorial is a bit unfair, don't you think? Anyway, better than never getting a grade (as it happens so often here at E-E).
Ciao, Mike
Ciao, Mike
ASKER
I'm sorry but select grade C and forbide select grade A. Anyway, the answer is excellent.
Thanks you
Julian
Thanks you
Julian
ASKER
I'm sorry but select grade C and forbide select grade A. Anyway, the answer is excellent.
Thanks you
Julian
Thanks you
Julian
sorry, but I can't understand what you need. Please reword your question then I can probably help...
Ciao, Mike