我写了个简单的测试程序,你看看:
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.

解决方案 »

  1.   

        该例子只是简单的测试了子类化的Api函数,不过我建议你用HookMainWindow(),它比较安全一点。
      

  2.   

    在 95 下有问题吗?
    试试看:
    function InspecterWndProc(Handle:Hwnd;Msg,Wparam:Word;Lparam:LongInt):LongInt; stdcall;
      

  3.   

    To gz_xjf :谢谢答复
     在win9x下,HookMainWindow(),它不能hook其他的进程(窗口)的Window。 
     在win9x下,要监控其他进程的消息也只能用setWindowsHookEx了。在win31下面由于所有进程共享一段内存空间,不存在访问其他进程的内存地址的问题,
    应该用setwindowlong是可以的。但是就不知道错在哪里?苦恼呀。在delphi1.0下面,不支持stdcall调用,这种C的参数入栈方式。
    function NewWndproc(Handle:hWnd;Msg,wParam,lParam:Longint):Longint;stdcall;
      

  4.   

    在Win32下SetWindowLong不能在一个进程内对另一个进程的窗口进行子类化操作,如要实现,需用钩子来实现,源代码在某期的《编程技巧与维护》上有(对不起,我实在记不起了),虽然是VC的源码,但改吧改吧就可以在Delphi中用了.
      

  5.   

    有书上特别强调必须用stdcall作为调用约定。
      

  6.   

    to gz_xjf:
     delphi1.0 不支持stdcall呀。
     在win32下一般来讲setwindowlong是不可以的。但是我的是在16位的win31下呀。
      

  7.   

    我用softice跟踪了一下,发现问题在这里:
     被监控的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错在哪里?哎。高手帮忙呀。。
     
      

  8.   

    function InspecterWndProc(Handle:Hwnd;Msg,Wparam:Word;Lparam:LongInt):LongInt;
    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"
    应该就是这个问题了
      

  9.   

    我昨晚特装Delphi 1.0试了一下,怎样也出错,但如果是自身的应用程序的窗体就正常。我想可能是不能替换别的应用程序的窗口过程。(原因不明)你改用钩子(SetWindowsHookEx)吧。这不是Delphi的问题,是API的问题,可到别的版提问,也许有高手知道原因。
      

  10.   

    还没解决吗?
    试试这样改:
    TargetWindowproc := Pointer(SetWindowLong(TargetHwnd,GWL_WNDPROC,Longint(MakeProcInstance(@InspecterWndProc,Hinstance))));加一个MakeProcInstance吧,16位windows中好象要这样。(太旧不用16位windows了)
    exports记住一定要加
      

  11.   

    高手真多,我想跟你们学Delphi!
      

  12.   

    to guig : 我也试过了,问题依然。
    to agui : 
    setwindowlong 在win31改其他程序的wndproc,要是不允许的话,应该返回零。
    可是我用softice看确实是改掉了。32位的windows就不允许改。它返回零。我已经写了用SetWindowHookVEx的,tmd的也是不行。
    在win9x下是没问题的。
      

  13.   

    to agui:
    你那儿也有delphi1.0 ,要不我把我写的hook程序mail给你?帮忙看看哪里有大bug?
      

  14.   

    to movax
    不会吧???
    加了MakeProcInstance还有问题??
    Option/Project/Compiler/Smart callbacks的钩去掉了没有,有回调函数时这个钩要去掉。
    BTW:要把TMEMO的构件都删除掉,在我这去掉钩后,不删除它们,程序无法运行。
    而且现在程序在win98下也能正常运行了!!!8-DDD
      

  15.   

    to agui(阿贵)
    你的昵称和我的差不多麻。平时也有人叫我agui来着,不过贵字不同。8-P
      

  16.   

    -->movax:
    我不是说不能SetWindowLong,只是Set了以后,Windows调用它有问题。
    hook程序说实话我还没试过,如果你相信我可以mailto: [email protected]>guig:
    好啊,难得有缘!:)
    我试过了MakeProcInstance,是有问题(如果在本应用程序内则可以),你也帮着试一下程序怎么样?
      

  17.   

    to agui
    Option/Project/Compiler/Smart callbacks的钩一定要去掉,否则DELPHI产生的堆栈框架不适合从其他任务来回调。
    去掉钩后,分成两个应用程序已经可以成功运行了(我是在win98上,在win31上应该也可以)。
      

  18.   

    to movax(movax)
    我给你又email了一个例子,是可以成功运行的,你收信看看吧。
      

  19.   

    谢谢。胖胖,不过我没收到哦,请麻烦你邮到[email protected]上。
      

  20.   

    to agui(阿贵): 三个zip文件已发送到你的[email protected] ,看看。。
      

  21.   

    to agui(阿贵): 信收到了?
      

  22.   

    to 胖胖:
     程序已经收到,试验了一下,可以,但是还是有问题的。如果把被监控程序的那段对
     procedure TestMess(var message:TMessage);message wTestMessage;去掉的话,
     监控程序是不会弹出收到消息的对话框的。
     按照程序的意思来讲,点set按钮替换了目标的wndproc,而且里面已经对wTestMessage作
     了处理,如果我向它发送wTestMessage是,理应弹出对话框来。
     如果我要监控第三方程序的话,你这样就实现不了。
      
     
      

  23.   

    to everyone :
    终于弄好了。用setwindowlong的。
    解决办法:重装了wfw3.1,把监视程序的TMemo组件去掉,(但是还是不知道为什么要这样)换用TListBox,去掉delphi1.0的smart callback.原来的程序到没有做很大的改动。
    to 胖胖:
      谢谢你的提示,十分感谢。
      

  24.   

    to movax
    >>如果把被监控程序的那段对
    procedure TestMess(var message:TMessage);message wTestMessage;去掉的话,
    监控程序是不会弹出收到消息的对话框的。不会呀,我试了一下会显示消息对话框呀。
    不知你对监控程序作了什么改动?
      

  25.   

    那是我在win9x下试的。不过在wfw3.1下是可以的。