(okwary) 小叹的学习园地

与天斗?不够高~ 与地斗?不够阔 与人斗? 脸皮不够厚

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

 

{-----MouseHook.pas-------------------------------------------}

 

{

 MouseHook DLL Load & TMouseHook Class Unit
 
 2004-09-08
 
 Copyright ? Thomas Yao

}

unit MouseHook;

interface

uses
  Windows, Messages, Classes;

const
  DEFDLLNAME = 'mousehook.dll';
  MappingFileName = '57D6A971_MouseHookDLL_442C0DB1';
  MSGMOUSEMOVE: PChar = 'MSGMOUSEMOVE57D6A971-049B-45AF-A8CD-37E0B706E036';
  MSGMOUSECLICK: PChar = 'MSGMOUSECLICK442C0DB1-3198-4C2B-A718-143F6E2D1760';

type
  // 全局映像文件, 如果没有TMappingMem, hook就只对本进程起作用
  TMappingMem = record
    Handle: DWORD;
    MsgID: DWORD;
    MouseStruct: TMOUSEHOOKSTRUCT;
  end;
  PMappingMem = ^TMappingMem;

  // 函数原型
  TEnableMouseHook = function(hWindow: HWND; Blocked: BOOL): BOOL; stdcall;

  TDisableMouseHook = function: BOOL; stdcall;

  // 事件对象
  TMouseMoveNotify = procedure(const Handle: HWND; const X, Y: Integer) of object;

  TMouseClickNotify = procedure(const Handle: HWND; const X, Y: Integer) of object;

  // 基类
  TMouseHookBase = class
  private
    FDLLName: string;
    FDLLLoaded: BOOL;
    FListenerHandle: HWND;
    FActive: BOOL;
    hMappingFile: THandle;
    pMapMem: PMappingMem;
    FBlocked: BOOL;
    procedure WndProc(var Message: TMessage);
    procedure SetDLLName(const Value: string);
    procedure SetBlocked(const Value: BOOL);
  protected
    MSG_MOUSEMOVE: UINT;
    MSG_MOUSECLICK: UINT;
    // 消息到事件
    procedure ProcessMessage(var Message: TMessage); virtual; abstract;
  public
    constructor Create; virtual;
    destructor Destroy; override;
    function Start: BOOL; virtual;
    procedure Stop; virtual;
    property DLLLoaded: BOOL read FDLLLoaded;
    property Active: BOOL read FActive;
  published
    property DLLName: string read FDLLName write SetDLLName;
    property Blocked: BOOL read FBlocked write SetBlocked;
  end;

  // 子类TMouseHook, 只提供事件接口实现
  TMouseHook = class(TMouseHookBase)
  private
    FOnMouseMove: TMouseMoveNotify;
    FOnMouseClick: TMouseClickNotify;
    procedure DoMouseMove(const Handle: HWND; const X, Y: Integer);
    procedure DoMouseClick(const Handle: HWND; const X, Y: Integer);
  protected
    procedure ProcessMessage(var Message: TMessage); override;
  public

  published
    property DLLName;
    property OnMouseMove: TMouseMoveNotify read FOnMouseMove write FOnMouseMove;
    property OnMouseClick: TMouseClickNotify read FOnMouseClick write FOnMouseClick;
  end;

var
  // 全局变量
  DLLLoaded: BOOL = False;

  StartMouseHook: TEnableMouseHook;
  StopMouseHook: TDisableMouseHook;

implementation

var
  DLLHandle: HMODULE;

procedure UnloadDLL;                    // 卸载dll
begin
  DLLLoaded := False;

  if DLLHandle <> 0 then
  begin
    FreeLibrary(DLLHandle);
    DLLHandle := 0;
    // 释放函数指针
    @StartMouseHook := nil;
    @StopMouseHook := nil;
  end;
end;

function LoadDLL(const FileName: string): Integer; // 加载dll
begin
  Result := 0;

  if DLLLoaded then
    Exit;

  DLLHandle := LoadLibraryEx(PChar(FileName), 0, 0);
  if DLLHandle <> 0 then
  begin
    DLLLoaded := True;

    // 传递函数指针
    @StartMouseHook := GetProcAddress(DLLHandle, 'EnableMouseHook');
    @StopMouseHook := GetProcAddress(DLLHandle, 'DisableMouseHook');

    if (@StartMouseHook = nil) or (@StopMouseHook = nil) then
    begin
      Result := 0;
      UnloadDLL;
      Exit;
    end;

    Result := 1;
  end
  else
    MessageBox(0, PChar(DEFDLLNAME + ' library could not be loaded !'),
      'Error', MB_ICONERROR);
end;

{ TInputHook }

constructor TMouseHookBase.Create;
begin
  pMapMem := nil;
  hMappingFile := 0;
  FDLLName := DEFDLLNAME;
  FBlocked := True;
  // 产生独一无二的消息id
  MSG_MOUSEMOVE := RegisterWindowMessage(MSGMOUSEMOVE);
  MSG_MOUSECLICK := RegisterWindowMessage(MSGMOUSECLICK);
end;

destructor TMouseHookBase.Destroy;
begin
  Stop;
  inherited;
end;

procedure TMouseHookBase.WndProc(var Message: TMessage);
begin
  if pMapMem = nil then
  begin
    hMappingFile := OpenFileMapping(FILE_MAP_WRITE, False, MappingFileName);
    if hMappingFile = 0 then
      MessageBox(0, 'cannot create share memory!', 'Error', MB_OK or MB_ICONERROR);
    pMapMem := MapViewOfFile(hMappingFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
    if pMapMem = nil then
    begin
      CloseHandle(hMappingFile);
      MessageBox(0, 'cannot map share memory!', 'Error', MB_OK or MB_ICONERROR);
    end;
  end;
  if pMapMem = nil then
    Exit;

  // 消息过滤
  if (Message.Msg = MSG_MOUSEMOVE) or (Message.Msg = MSG_MOUSECLICK) then
  begin
    Message.WParam := pMapMem.MouseStruct.hwnd;
    Message.LParam := (pMapMem.MouseStruct.pt.X and $FFFF) or
      (pMapMem.MouseStruct.pt.Y shl 16);
    ProcessMessage(Message);
  end
  else
    // 不需要处理的消息交给OS默认处理函数
    Message.Result := DefWindowProc(FListenerHandle, Message.Msg, Message.wParam,
      Message.lParam);
end;

function TMouseHookBase.Start: BOOL;
var
  hookRes: Integer;
begin
  Result := False;
  if (not FActive) and (not FDLLLoaded) then
  begin
    if FDLLName = '' then
    begin
      Result := False;
      Exit;
    end
    else
    begin
      hookRes := LoadDLL(FDLLName);
      if hookRes = 0 then
      begin
        Result := False;
        Exit;
      end
      else
      begin
        // 这是关键所在, 通过AllocateHWnd创建一个不可见的窗体, 来实现所有消息的中转
        // 通过TMouseHookBase的WndProc来实现对消息的响应
        FListenerHandle := AllocateHWnd(WndProc);
        if FListenerHandle = 0 then
        begin
          Result := False;
          Exit;
        end
        else
        begin
          if StartMouseHook(FListenerHandle, FBlocked) then
          begin
            Result := True;
            FDLLLoaded := True;
            FActive := True;
          end
          else
          begin
            Result := False;
            Exit;
          end;
        end;
      end;
    end;
  end;
end;

procedure TMouseHookBase.Stop;
begin
  if FActive then
  begin
    if FListenerHandle <> 0 then
    begin
      pMapMem := nil;
      if hMappingFile <> 0 then
      begin
        CloseHandle(hMappingFile);
        hMappingFile := 0;
      end;
      DeallocateHWnd(FListenerHandle);
      StopMouseHook;
      FListenerHandle := 0;
    end;
    UnloadDLL;
    FActive := False;
    FDLLLoaded := False;
  end;
end;

procedure TMouseHookBase.SetDLLName(const Value: string);
begin
  if FActive then
    MessageBox(0, 'Cannot activate hook because DLL name is not set.',
      'Info', MB_OK + MB_ICONERROR)
  else
    FDLLName := Value;
end;

procedure TMouseHookBase.SetBlocked(const Value: BOOL);
begin
  if FActive then
    MessageBox(0, 'Cannot set block property of hook because hook is active!',
      'Info', MB_OK + MB_ICONERROR)
  else
    FBlocked := Value;
end;

{ TMouseHook }

procedure TMouseHook.DoMouseClick(const Handle: HWND; const X, Y: Integer);
begin
  if Assigned(FOnMouseClick) then
    FOnMouseClick(Handle, X, Y);
end;

procedure TMouseHook.DoMouseMove(const Handle: HWND; const X, Y: Integer);
begin
  if Assigned(FOnMouseMove) then
    FOnMouseMove(Handle, X, Y);
end;

procedure TMouseHook.ProcessMessage(var Message: TMessage);
begin
  if Message.Msg = MSG_MOUSEMOVE then
  begin
    DoMouseMove(Message.WParam, Message.LParamLo, Message.LParamHi);
  end
  else if Message.Msg = MSG_MOUSECLICK then
  begin
    DoMouseClick(Message.WParam, Message.LParamLo, Message.LParamHi);
  end;
end;

end.


//==========================================

library MouseHook;

//============================================

 

library MouseHook;

uses
  Windows, Messages;

const
  MappingFileName = '57D6A971_MouseHookDLL_442C0DB1';
  MSGMOUSEMOVE: PChar = 'MSGMOUSEMOVE57D6A971-049B-45AF-A8CD-37E0B706E036';
  MSGMOUSECLICK: PChar = 'MSGMOUSECLICK442C0DB1-3198-4C2B-A718-143F6E2D1760';

type
  TMappingMem = record
    Handle: DWORD;
    MsgID: DWORD;
    MouseStruct: TMOUSEHOOKSTRUCT;
  end;
  PMappingMem = ^TMappingMem;

var
  MSG_MOUSEMOVE: UINT;
  MSG_MOUSECLICK: UINT;
  hMappingFile: THandle;
  pMapMem: PMappingMem;
  mhook: HHook;
  fblocked: BOOL = True;
  //CriticalSection: TRTLCriticalSection;

function MouseHookProc(iCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall
begin
  if fblocked then
    Result := 1
  else
    Result := 0;

  if iCode < 0 then
    CallNextHookEx(mhook, iCode, wParam, lParam);

  case wParam of
    WM_MOUSEMOVE, WM_NCMouseMove:
      begin
        pMapMem^.MsgID := MSG_MOUSEMOVE;
        pMapMem^.MouseStruct := pMOUSEHOOKSTRUCT(lparam)^;
        SendMessage(pMapMem^.Handle, pMapMem^.MsgID, 0, 0);
      end;
    WM_LBUTTONDOWN, WM_NCLBUTTONDOWN:
      begin
        pMapMem^.MsgID := MSG_MOUSECLICK;
        pMapMem^.MouseStruct := pMOUSEHOOKSTRUCT(lparam)^;
        SendMessage(pMapMem^.Handle, pMapMem^.MsgID, 0, 0);
      end;
    WM_LBUTTONUP:
      begin
      end;
    WM_LBUTTONDBLCLK:
      begin
      end;
    WM_RBUTTONDOWN:
      begin
      end;
    WM_RBUTTONUP:
      begin
      end;
    WM_RBUTTONDBLCLK:
      begin
      end;
    WM_MBUTTONDOWN:
      begin
      end;
    WM_MBUTTONUP:
      begin
      end;
    WM_MBUTTONDBLCLK:
      begin
      end;
  end;
end;

function EnableMouseHook(hWindow: HWND; Blocked: BOOL): BOOL; stdcall;
begin
  Result := False;
  if mhook <> 0 then
    Exit;
  pMapMem^.Handle := hWindow;
  fblocked := Blocked;
  mhook := SetWindowsHookEx(WH_MOUSE, MouseHookProc, HInstance, 0);
  Result := mhook <> 0;
end;

function DisableMouseHook: BOOL; stdcall;
begin
  if mhook <> 0 then
  begin
    UnhookWindowshookEx(mhook);
    mhook := 0;
  end;
  Result := mhook = 0;
end;

procedure DllMain(dwReason: DWORD);
begin
  case dwReason of
    DLL_PROCESS_ATTACH:
      begin
        //InitializeCriticalSection(CriticalSection);
        hMappingFile := OpenFileMapping(FILE_MAP_WRITE, False, MappingFileName);
        if hMappingFile = 0 then
        begin
          hMappingFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE,
            0, SizeOf(TMappingMem), MappingFileName);
        end;
        if hMappingFile = 0 then
          MessageBox(0, 'cannot create share memory!', 'Error', MB_OK or MB_ICONERROR);

        pMapMem := MapViewOfFile(hMappingFile, FILE_MAP_WRITE or FILE_MAP_READ,
          0, 0, 0);
        if pMapMem = nil then
        begin
          CloseHandle(hMappingFile);
          MessageBox(0, 'cannot map share memory!', 'Error', MB_OK or MB_ICONERROR);
        end;
        mhook := 0;
        MSG_MOUSEMOVE := RegisterWindowMessage(MSGMOUSEMOVE);
        MSG_MOUSECLICK := RegisterWindowMessage(MSGMOUSECLICK);
      end;
    DLL_PROCESS_DETACH:
      begin
        UnMapViewOfFile(pMapMem);
        CloseHandle(hMappingFile);
        if mhook <> 0 then
          DisableMouseHook;
        //DeleteCriticalSection(CriticalSection);
      end;
    DLL_THREAD_ATTACH:
      begin
      end;
    DLL_THREAD_DETACH:
      begin
      end;
  end;
end;

exports
  EnableMouseHook,
  DisableMouseHook;

begin
  DisableThreadLibraryCalls(HInstance);
  DLLProc := @DLLMain;
  DLLMain(DLL_PROCESS_ATTACH);
end.

 

posted on 2008-12-26 22:46  okwary  阅读(640)  评论(0编辑  收藏  举报
ggg