//------------------------------------------------------------------
{ DLL单元 }
library Project1;uses
ShareMem, //因为用到了string类型
SysUtils,
Classes,
Unit1 in 'Unit1.pas';{$R *.res}
exports
StartSpyMessage,
StopSpyMessage;begin
end.
//------------------------------------------------------------------
{ DLL单元引用的Unit1单元 }
//------------------------------------------------------------------
unit Unit1;
{ }
interfaceuses
Messages, Windows, Classes, SysUtils;{ 开始监视 hSpyWnd为调用者窗体上Edit控件的句柄 dwThreadId为要监视的线程的ID }
function StartSpyMessage(hSpyWnd: THandle; dwThreadId: DWORD): Boolean; stdcall;{ 结束监视 }
procedure StopSpyMessage; stdcall;implementationvar
HWndProc: THandle; //WH_CALLWNDPROC钩子的句柄 { 保存StartSpyMessage在被调用时传进来的要监视的线程的ID }
ghSpyWnd: HWND; { WH_CALLWNDPROC的钩子过程 }
function CallWndProc(code: Integer; wP: WPARAM; lP: LPARAM): LRESULT; stdcall;
var
s: string;
begin
if code = HC_ACTION then
if PCWPSTRUCT(lp)^.message = WM_COMMAND then //只想捕获菜单操作和快捷键操作
begin
{ 设置DLL调用程序上的Edit控件的内容为 受控程序的菜单ID或快捷键ID }
s := IntToStr(LOWORD(PCWPSTRUCT(lp)^.wParam));
MessageBox(0, '截获到了', '', MB_OK);
SendMessage(ghSpyWnd, WM_SETTEXT, Length(s), Longint(s)); { ghSpyWnd为DLL调用程序上的Edit控件的句柄 }
end;
Result := CallNextHookEx(HWndProc, code, wP, lP);
end;function StartSpyMessage(hSpyWnd: THandle; dwThreadId: DWORD): Boolean;
begin
Result := False;
ghSpyWnd := hSpyWnd;
if HWndProc <> 0 then
Exit; { 因为只想监视指定程序,不想将DLL注入所有进程空间来挂WH_CALLWNDPROC钩子,所以使用了ThreadId 主要是想节省资源 }
HWndProc := SetWindowsHookEx(WH_CALLWNDPROC, @CallWndProc, HInstance, dwThreadId);
if HWndProc = 0 then
begin
StopSpyMessage;
Exit;
end;
Result := True;
end;procedure StopSpyMessage;
begin
UnhookWindowsHookEx(HWndProc);
HWndProc := 0;
end;end.
//------------------------------------------------------------------
//------------------------------------------------------------------
{ DLL的调用程序 窗体上放两个Edit,两个Button }
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Button2: TButton;
Edit2: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}
function StartSpyMessage(hSpyWnd: THandle; dwThreadId: DWORD): Boolean; stdcall; external 'Project1.dll';
procedure StopSpyMessage; stdcall; external 'Project1.dll';
procedure TForm1.Button1Click(Sender: TObject);
begin
{ Edit2上的内容为16进制的线程ID(创建最外层窗体的线程的ID),可以用Spy++查得 }
StartSpyMessage(Edit1.Handle, strtoint('$' + Edit2.Text)); //开始监视
end;procedure TForm1.Button2Click(Sender: TObject);
begin
StopSpyMessage; //停止监视
end;procedure TForm1.FormDestroy(Sender: TObject);
begin
StopSpyMessage;
end;end.
//------------------------------------------------------------------
现在的问题是:
在开始监视后用进程管理器可以看到Project1.dll和borlandmm.dll已经进入了受控程序的进程中。比如RealPlayer。
可是不论我操作其菜单还是使用快捷键,我的监控程序都监视不到!怎么回事?
另外在停止监视时受控程序会弹出出错对话框,报告“0X00000000指令引用的0X00000000内存。该内存不能为read”怎么回事?差哪呢?为什么就不能捕获WM_COMMAND消息呢?为什么?????
{ DLL单元 }
library Project1;uses
ShareMem, //因为用到了string类型
SysUtils,
Classes,
Unit1 in 'Unit1.pas';{$R *.res}
exports
StartSpyMessage,
StopSpyMessage;begin
end.
//------------------------------------------------------------------
{ DLL单元引用的Unit1单元 }
//------------------------------------------------------------------
unit Unit1;
{ }
interfaceuses
Messages, Windows, Classes, SysUtils;{ 开始监视 hSpyWnd为调用者窗体上Edit控件的句柄 dwThreadId为要监视的线程的ID }
function StartSpyMessage(hSpyWnd: THandle; dwThreadId: DWORD): Boolean; stdcall;{ 结束监视 }
procedure StopSpyMessage; stdcall;implementationvar
HWndProc: THandle; //WH_CALLWNDPROC钩子的句柄 { 保存StartSpyMessage在被调用时传进来的要监视的线程的ID }
ghSpyWnd: HWND; { WH_CALLWNDPROC的钩子过程 }
function CallWndProc(code: Integer; wP: WPARAM; lP: LPARAM): LRESULT; stdcall;
var
s: string;
begin
if code = HC_ACTION then
if PCWPSTRUCT(lp)^.message = WM_COMMAND then //只想捕获菜单操作和快捷键操作
begin
{ 设置DLL调用程序上的Edit控件的内容为 受控程序的菜单ID或快捷键ID }
s := IntToStr(LOWORD(PCWPSTRUCT(lp)^.wParam));
MessageBox(0, '截获到了', '', MB_OK);
SendMessage(ghSpyWnd, WM_SETTEXT, Length(s), Longint(s)); { ghSpyWnd为DLL调用程序上的Edit控件的句柄 }
end;
Result := CallNextHookEx(HWndProc, code, wP, lP);
end;function StartSpyMessage(hSpyWnd: THandle; dwThreadId: DWORD): Boolean;
begin
Result := False;
ghSpyWnd := hSpyWnd;
if HWndProc <> 0 then
Exit; { 因为只想监视指定程序,不想将DLL注入所有进程空间来挂WH_CALLWNDPROC钩子,所以使用了ThreadId 主要是想节省资源 }
HWndProc := SetWindowsHookEx(WH_CALLWNDPROC, @CallWndProc, HInstance, dwThreadId);
if HWndProc = 0 then
begin
StopSpyMessage;
Exit;
end;
Result := True;
end;procedure StopSpyMessage;
begin
UnhookWindowsHookEx(HWndProc);
HWndProc := 0;
end;end.
//------------------------------------------------------------------
//------------------------------------------------------------------
{ DLL的调用程序 窗体上放两个Edit,两个Button }
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Button2: TButton;
Edit2: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}
function StartSpyMessage(hSpyWnd: THandle; dwThreadId: DWORD): Boolean; stdcall; external 'Project1.dll';
procedure StopSpyMessage; stdcall; external 'Project1.dll';
procedure TForm1.Button1Click(Sender: TObject);
begin
{ Edit2上的内容为16进制的线程ID(创建最外层窗体的线程的ID),可以用Spy++查得 }
StartSpyMessage(Edit1.Handle, strtoint('$' + Edit2.Text)); //开始监视
end;procedure TForm1.Button2Click(Sender: TObject);
begin
StopSpyMessage; //停止监视
end;procedure TForm1.FormDestroy(Sender: TObject);
begin
StopSpyMessage;
end;end.
//------------------------------------------------------------------
现在的问题是:
在开始监视后用进程管理器可以看到Project1.dll和borlandmm.dll已经进入了受控程序的进程中。比如RealPlayer。
可是不论我操作其菜单还是使用快捷键,我的监控程序都监视不到!怎么回事?
另外在停止监视时受控程序会弹出出错对话框,报告“0X00000000指令引用的0X00000000内存。该内存不能为read”怎么回事?差哪呢?为什么就不能捕获WM_COMMAND消息呢?为什么?????
http://blog.csdn.net/linzhengqun
找钩子的文章
http://blog.csdn.net/linzhengqun/archive/2005/10/06/496082.aspx
我上网的时间有限。太多资料我也看不过来。to:suncheng_hong(亮)
我问完问题后就下线回家了。我也不知道回复情况如何!当时上网的时间到了。所以很着急,希望大家能尽快的回复我的帖子因此给大家发了短消息。不好意思,骚扰大家了。说说我是怎么解决的:
写这段程序的时候我抱着侥幸的心理,不想使用映射共享内存的方法来进行主进程与DLL间的通信。认为在调用DLL时初始化DLL中的全局变量然后再将DLL注入其它进程的空间那么这个全局变量的值也会被复制过去。然而回家后经过试验发现当DLL被注入其它进程的地址空间的时候实际上是被重新初始化了。所以这个小聪明看来是不行的。还是乖乖的用影射共享内存的方法解决了。
◆◆◆不知道我上面的说法对不对?就是“发现当DLL被注入其它进程的地址空间的时候实际上是被重新初始化了”这句对不对?
刚才到大富翁上看了一下。确实没人解决。怎么回事呢?大富翁怎么了?刚才忘了说了。不使用string类型了,也不引用ShareMem单元了。退出出错的问题没有了。
在DLL中还是尽量不用这个内存管理器好。还是自己管理内存吧。麻烦就麻烦点吧。
不过在Delphi就只能用内存映射了。
DLL进入每一个进程实际就是完全不同的两份拷贝,所以你需要一种全局共享的内存供这些DLL使用。