我写了个简单的测试程序,你看看:
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations } public
{ Public declarations }
end;const
wTestMessage=WM_USER+200;var
Form1: TForm1;
WProc:pointer;
function NewWndproc(Handle:hWnd;Msg,wParam,lParam:Longint):Longint;stdcall;implementation
{$R *.DFM}function NewWndproc(Handle:hWnd;Msg,wParam,lParam:Longint):Longint;stdcall;
begin
Form1.Edit1.text:='我接收到了!';
Result:=CallWindowProc(WProc,Application.Handle,Msg,wParam,lParam);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
WProc:=pointer(SetWindowLong(Application.Handle,GWL_WNDPROC,Integer(@NewWndproc)));
end;end.
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations } public
{ Public declarations }
end;const
wTestMessage=WM_USER+200;var
Form1: TForm1;
WProc:pointer;
function NewWndproc(Handle:hWnd;Msg,wParam,lParam:Longint):Longint;stdcall;implementation
{$R *.DFM}function NewWndproc(Handle:hWnd;Msg,wParam,lParam:Longint):Longint;stdcall;
begin
Form1.Edit1.text:='我接收到了!';
Result:=CallWindowProc(WProc,Application.Handle,Msg,wParam,lParam);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
WProc:=pointer(SetWindowLong(Application.Handle,GWL_WNDPROC,Integer(@NewWndproc)));
end;end.
试试看:
function InspecterWndProc(Handle:Hwnd;Msg,Wparam:Word;Lparam:LongInt):LongInt; stdcall;
在win9x下,HookMainWindow(),它不能hook其他的进程(窗口)的Window。
在win9x下,要监控其他进程的消息也只能用setWindowsHookEx了。在win31下面由于所有进程共享一段内存空间,不存在访问其他进程的内存地址的问题,
应该用setwindowlong是可以的。但是就不知道错在哪里?苦恼呀。在delphi1.0下面,不支持stdcall调用,这种C的参数入栈方式。
function NewWndproc(Handle:hWnd;Msg,wParam,lParam:Longint):Longint;stdcall;
delphi1.0 不支持stdcall呀。
在win32下一般来讲setwindowlong是不可以的。但是我的是在16位的win31下呀。
被监控的control,在没有修改它的wndproc的情况,
Handle Calss wndProc
53C8(2) TMemo 3637:03D4
修改它的wndproc以后的情况,
Handle Calss wndProc
53C8(2) TMemo 18F7:0816
U 18F7:0816 后,这里确实是我为被监控的control定义的新的winproc地址。
在修改它的wndproc后,我让它获得焦点。于是激活了softice我定义的断点,进入18F7:0816,于是我就用了F10命令n次,发现一直在里面打转。
问题就出在这里,
正常:本来新的wndproc在做完处理后,把message传给old wndproc处理,
它再处理完后,控制权交回给win31。
我的错误:新的wndproc在做完处理后,没有把message传给old wndproc处理,但是我在程序里已经用callwndproc(原来的wndproc,xxx,xx,xx)。是不是callwndproc写错了呢?
我看了半天都每看出我写的callwndproc错在哪里?哎。高手帮忙呀。。
begin
{后来,这里我什么都不写,直接把消息传给被监控程序的wndproc,不过还是会报错}
Result := CallWindowproc(TargetWindowProc,TargetHwnd,Msg,Wparam,lparam);
end
改为
function InspecterWndProc(Handle:Hwnd;Msg,Wparam:Word;Lparam:LongInt):LongInt;export;
begin
{后来,这里我什么都不写,直接把消息传给被监控程序的wndproc,不过还是会报错}
Result := CallWindowproc(TargetWindowProc,TargetHwnd,Msg,Wparam,lparam);
end
回调函数声明时要加"export"
应该就是这个问题了
试试这样改:
TargetWindowproc := Pointer(SetWindowLong(TargetHwnd,GWL_WNDPROC,Longint(MakeProcInstance(@InspecterWndProc,Hinstance))));加一个MakeProcInstance吧,16位windows中好象要这样。(太旧不用16位windows了)
exports记住一定要加
to agui :
setwindowlong 在win31改其他程序的wndproc,要是不允许的话,应该返回零。
可是我用softice看确实是改掉了。32位的windows就不允许改。它返回零。我已经写了用SetWindowHookVEx的,tmd的也是不行。
在win9x下是没问题的。
你那儿也有delphi1.0 ,要不我把我写的hook程序mail给你?帮忙看看哪里有大bug?
不会吧???
加了MakeProcInstance还有问题??
Option/Project/Compiler/Smart callbacks的钩去掉了没有,有回调函数时这个钩要去掉。
BTW:要把TMEMO的构件都删除掉,在我这去掉钩后,不删除它们,程序无法运行。
而且现在程序在win98下也能正常运行了!!!8-DDD
你的昵称和我的差不多麻。平时也有人叫我agui来着,不过贵字不同。8-P
我不是说不能SetWindowLong,只是Set了以后,Windows调用它有问题。
hook程序说实话我还没试过,如果你相信我可以mailto: [email protected]>guig:
好啊,难得有缘!:)
我试过了MakeProcInstance,是有问题(如果在本应用程序内则可以),你也帮着试一下程序怎么样?
Option/Project/Compiler/Smart callbacks的钩一定要去掉,否则DELPHI产生的堆栈框架不适合从其他任务来回调。
去掉钩后,分成两个应用程序已经可以成功运行了(我是在win98上,在win31上应该也可以)。
我给你又email了一个例子,是可以成功运行的,你收信看看吧。
程序已经收到,试验了一下,可以,但是还是有问题的。如果把被监控程序的那段对
procedure TestMess(var message:TMessage);message wTestMessage;去掉的话,
监控程序是不会弹出收到消息的对话框的。
按照程序的意思来讲,点set按钮替换了目标的wndproc,而且里面已经对wTestMessage作
了处理,如果我向它发送wTestMessage是,理应弹出对话框来。
如果我要监控第三方程序的话,你这样就实现不了。
终于弄好了。用setwindowlong的。
解决办法:重装了wfw3.1,把监视程序的TMemo组件去掉,(但是还是不知道为什么要这样)换用TListBox,去掉delphi1.0的smart callback.原来的程序到没有做很大的改动。
to 胖胖:
谢谢你的提示,十分感谢。
>>如果把被监控程序的那段对
procedure TestMess(var message:TMessage);message wTestMessage;去掉的话,
监控程序是不会弹出收到消息的对话框的。不会呀,我试了一下会显示消息对话框呀。
不知你对监控程序作了什么改动?