放出测试代码DLL中的代码
unit MyMsgHook;interface
uses
  Windows,SysUtils,Messages,Dialogs;
function MsgHookProc(icode:Integer;awParam:WPARAM;alParam:LPARAM):LongInt;stdcall;
function SetupHook:Boolean;stdcall
function EndHook:Boolean;stdcallvar
  IsHooked:Boolean=False;
  gHook:HHOOK;implementation
//------------------------------------------------------------------------------function MsgHookProc(icode:Integer;awParam:WPARAM;alParam:LPARAM):LongInt;stdcall;
begin
  Result:=0;
  if icode<0 then
    Result:=CallNextHookEx(gHook,icode,awParam,alParam);  if icode=HCBT_ACTIVATE then
    ShowMessage('11111111');end;//------------------------------------------------------------------------------
function SetupHook:Boolean;stdcall
begin
  if IsHooked=False then
  begin
    gHook:=SetWindowsHookEx(WH_CBT,@MsgHookProc,HInstance,0);
    IsHooked:=True;
    Result:=True;
  end
  else
    Result:=False;
end;
//------------------------------------------------------------------------------
function EndHook:Boolean;stdcall
begin
  if IsHooked=True then
  begin
    Result:=UnhookWindowsHookEx(gHook);
    IsHooked:=False;
  end;
end;
end.导出函数如下
library MsgHook;{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }uses
  SysUtils,
  Classes,
  MyMsgHook in 'MyMsgHook.pas';exports
  SetupHook,
  EndHook;
begin
end.MAIN程序中的测试代码
unit mwssage;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;type
  TForm1 = class(TForm)
    btn1: TButton;
    btn2: TButton;
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;function SetupHook:Boolean;stdcall;external 'MsgHook.dll';
function EndHook:Boolean;stdcall;external 'MsgHook.dll';implementation{$R *.dfm}procedure TForm1.btn1Click(Sender: TObject);
begin
  if SetupHook then
    ShowMessage('成功加入');
end;procedure TForm1.btn2Click(Sender: TObject);
begin
  if EndHook then
    ShowMessage('成功解除');
end;end.
编译没错,运行后为什么会出错?请高手根据此代码解之,感谢

解决方案 »

  1.   

    看了delphi中的帮助,发现CBTProc中有很多功能:
      HCBT_ACTIVATE
      HCBT_CREATEWND
      HCBT_DESTROYWND
      HCBT_MINMAX
      HCBT_MOVESIZE
      HCBT_SETFOCUS
      HCBT_SYSCOMMAND library HookPrj;  uses
      SysUtils,
      Classes,
      QQTitleHook in ’QQTitleHook.pas’;  exports
      EnableWheelHook, DisableWheelHook;  begin
      hkQQChat:= 0;
      end.
      ==========================================================
      unit QQTitleHook;  interface  uses
      Windows, Messages, SysUtils, Dialogs, CommCtrl, StrUtils;  var
      hkQQChat: HHOOK;
      //聊天窗口的句柄
      hwQQChat: HWnd ;
      //聊天窗口的标题
      tlQQChat: string;
      //窗口类名
      clsName: string;
      buf: array [0..1024] of char;  const
      //QQ聊天窗口的类名
      csQQ = ’#32770’;  function TitleHookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
      function EnumWindowsTitleFunc(Handle: THandle; lParam: LPARAM): boolean ; stdcall;
      function EnableWheelHook : Boolean; stdcall; export;
      function DisableWheelHook: Boolean; stdcall; export;  implementation  //钩子的处理函数
      function TitleHookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
      begin
      Result:= 0;
      if Code<0 then
      begin
      Result:= CallNextHookEx(hkQQChat, Code, wParam, lParam);
      Exit;
      end
      else
      if Code = HCBT_ACTIVATE then
      begin
      //获取激活窗口的句柄,以及窗口类名,然后判断此窗口类名是否为#32770。
      hwQQChat:= HWND(wParam);
      GetClassName(hwQQChat, buf, 1024);
      clsName:= string(buf);
      if clsName = csQQ then
      begin
      //如果窗口类名是#32770,则遍枚举所有窗口,并将窗口句柄传入
      //【这里仅仅做演示用,因为Windows中很多窗口的类名均为#32770,所以这样判断效率会很底,】
      //【有兴趣的朋友可以根据QQ聊天窗口的特性来增加判断条件,从而提高效率。】
      EnumWindows(@EnumWindowsTitleFunc, hwQQChat);
      end;
      end;
      end;  function EnumWindowsTitleFunc(Handle: THandle; lParam: LPARAM): boolean ; stdcall;
      begin
      if (Handle = lParam) and boolean(GetWindowText(Handle, buf, 256)) then
      begin
      //根据窗口句柄获得窗口标题
      tlQQChat:= string(buf);
      //然后判断标题中是否包含“与...聊天”等相关字符,如果包括则此窗口为QQ聊天窗口
      if ((pos(’与’, tlQQChat)>0) and (pos(’聊天中’, tlQQChat)>0)) then
      begin
      //确定为聊天窗口后遍修改窗口标题。
      tlQQChat := AnsiReplaceStr(tlQQChat, ’与’ , ’我的文档’);
      tlQQChat := AnsiReplaceStr(tlQQChat, ’聊天中’, ’’ );
      SetWindowText(Handle, pchar(tlQQChat));
      end;
      //【同上,这个地方大家可以自由控制,不仅仅局限在QQ、MSN等聊天窗口。】
      //【而且想要将标题改成什么也可以自由控制,如果能根据修改后的窗口图标来确定标题】
      //【比如通过修改将窗口图标替换成Delphi的图标,然后标题修改为Delphi7,谁还能看出破绽呢?哈哈】
      if ((pos(’群 -’, tlQQChat)>0) or (pos(’高级群 -’, tlQQChat)>0)) then
      begin
      tlQQChat := AnsiReplaceStr(tlQQChat, ’群 -’, ’我的文档’);
      tlQQChat := AnsiReplaceStr(tlQQChat, ’高级’ , ’’ );
      SetWindowText(Handle, pchar(tlQQChat));
      end;
      //MSN
      if pos(’ - 对话’, tlQQChat)>0 then
      begin
      tlQQChat := AnsiReplaceStr(tlQQChat, ’ - 对话’ , ’我的文档’);
      SetWindowText(Handle, pchar(tlQQChat));
      end;
      end;
      Result :=True;
      end;  //启动钩子
      function EnableWheelHook: Boolean; stdcall; export;
      begin
      if hkQQChat=0 then
      begin
      hkQQChat := SetWindowsHookEx(WH_CBT, @TitleHookProc, Hinstance, 0);
      Result := True;
      end
      else
      Result := False;
      end;  //卸载钩子
      function DisableWheelHook: Boolean; stdcall; export;
      begin
      if hkQQChat<>0 then
      begin
      UnHookWindowsHookEx(hkQQChat);
      hkQQChat := 0;
      Result := True;
      end
      else
      Result := False;
      end;  end.先看看这个例子看看自己能不能搞定
      

  2.   


    unit   HKProc;  
       
      interface  
       
      uses  
      Windows,   Messages,Dialogs,iniFiles,SysUtils;  
       
      var  
      hNextHookProc:   HHook;  
      procSaveExit:   Pointer;  
       
      function   CBTProc(iCode:   Integer;   wParam:   WPARAM;   lParam:   LPARAM):   LRESULT;   stdcall;  
      function   EnableHotKeyHook:   BOOL;   export;  
      function   DisableHotKeyHook:   BOOL;   export;  
       
      implementation  
       
      function   CBTProc(iCode:   Integer;   wParam:   WPARAM;   lParam:   LPARAM):   LRESULT;   stdcall;  
      var  
          p:   PCBTActivateStruct;  
      begin  
          result:=   0;  
          If   iCode<0   Then  
          begin  
              Result   :=   CallNextHookEx(hNextHookProc,   iCode,   wParam,   lParam);  
              Exit;  
          end  
          else  
          begin  
              If   iCode   =   HCBT_ACTIVATE   then  
              begin  
                  p:=   PCBTActivateStruct(lParam);  
                  if   (p.hWndActive   =   findwindow('#32770',nil))   then   showmessage('lkjl');  
              end;  
          end;  
      end;  
       
       
      function   EnableHotKeyHook:   BOOL;   export;  
      begin  
          Result   :=   False;  
          if   hNextHookProc   <>   0   then   Exit;  
          hNextHookProc   :=   SetWindowsHookEx(WH_CBT,CBTProc,HInstance,0);  
          Result   :=   hNextHookProc   <>   0;  
      end;  
       
      function   DisableHotKeyHook:   BOOL;   export;  
      begin  
          if   hNextHookProc   <>   0   then  
          begin  
              UnhookWindowshookEx(hNextHookProc);    
              hNextHookProc   :=   0;  
          end;  
          Result   :=   hNextHookProc   =   0;  
      end;  
       
      end. __________________________________________  
    If   iCode   =   HCBT_ACTIVATE   then  
      begin  
          p:=   PCBTActivateStruct(lParam);  
          p.hWndActive//就是激活窗口的句柄。findwindow('#32770',nil)返回的是QQ聊天窗口的句柄                                  
      end;
      

  3.   

    问题出在这句上,屏掉它即可 // ShowMessage('11111111');
    function MsgHookProc(icode:Integer;awParam:WPARAM;alParam:LPARAM):LongInt;stdcall;
    begin
      Result:=0;
      if icode<0 then
      begin
        Result:=CallNextHookEx(gHook,icode,awParam,alParam);
      exit;
      end
      else  if icode=HCBT_ACTIVATE then
      begin
       // ShowMessage('11111111');
       end;end;
    改成这样试试,我测试没问题
    function MsgHookProc(icode:Integer;awParam:WPARAM;alParam:LPARAM):LongInt;stdcall;
    var
    a:textfile;
    begin
      Result:=0;
      if icode<0 then
      begin
        Result:=CallNextHookEx(gHook,icode,awParam,alParam);
      exit;
      end
      else  if icode=HCBT_ACTIVATE then
      begin
       assignfile(a,'c:\1.txt');//开始写入//rewrite(a);
    if FileExists('c:\1.txt') then
    begin
      append(a);
      end
      else
      rewrite(a);//rewrite(a);//写入操作
    writeln(a,'有窗口激活了');//写入
    closefile(a);//关闭文件
    end;end;
      

  4.   

    为什么有了ShowMessage('11111111');会报错?
      

  5.   

    If   iCode   =   HCBT_ACTIVATE   then  
      begin  
          p:=   PCBTActivateStruct(lParam);  
          p.hWndActive//就是激活窗口的句柄。findwindow('#32770',nil)返回的是QQ聊天窗口的句柄                                  
      end;
    参考
    要有条件的,不能随便弹出!