1.怎么拦截 WM_MenuSelect消息???
2.怎么编写“程序级”的勾子,而不是“系统级”的勾子。
3.怎么知道一个弹出菜单是否已经关闭??分数另开帖子给分。(我是新手,最多只能出100分).

解决方案 »

  1.   

    我想你是想做一个程序级鼠标勾子,关于怎么知道一个弹出菜单是否已经关闭你可以用AnyPopup(测试屏幕上是否有弹出菜单),TrackPopupMenu(可以让菜单弹出在屏幕上的任意地方)就可以解决了。
    下面是一个关于Mouse Hook的例子。通过Delphi建立键盘鼠标动作纪录与回放    很多的教学软件或系统监视软件可以自动记录回放用户的输入文字或点击按钮等操作操作,这个功能的实现是使用
    了Windows的Hook函数。
        Windows提供API函数SetwindowsHookEx来建立一个Hook,通过这个函数可以将一个程序添加到Hook链中监视Windows
    消息,函数语法为:
        SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HINST; dwThreadId: DWORD)
        其中参数idHook指定建立的监视函数类型。通过Windows MSDN帮助可以看到,SetwindowsHookEx函数提供15种不同
    的消息监视类型,在这里我们将使用WH_JOURNALRECORD和WH_JOURNALPLAYBACK来监视键盘和鼠标操作。参数lpfn指定消
    息函数,在相应的消息产生后,系统会调用该函数并将消息值传递给该函数供处理。函数的一般形式为:
        Hookproc (code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
        其中code为系统指示标记,wParam和lParam为附加参数,根据不同的消息监视类型而不同。只要在程序中建立这样
    一个函数再通过SetwindowsHookEx函数将它加入到消息监视链中就可以处理消息了。
        在不需要监视系统消息时需要调用提供UnHookWindowsHookEx来解除对消息的监视。
        WH_JOURNALRECORD和WH_JOURNALPLAYBACK类型是两种相反的Hook类型,前者获得鼠标、键盘动作消息,后者回放鼠
    标键盘消息。所以在程序中我们需要建立两个消息函数,一个用于纪录鼠标键盘操作并保存到一个数组中,另一个用于
    将保存的操作返给系统回放。
        下面来建立程序,在Delphi中建立一个工程,在Form1上添加3个按钮用于程序操作。另外再添加一个按钮控件和一
    个Edit控件用于验证操作。
        下面是Form1的全部代码unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        Button3: TButton;
        Edit1: TEdit;
        Button4: TButton;
        procedure FormCreate(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;  EventArr:array[0..1000]of EVENTMSG;
      EventLog:Integer;
      PlayLog:Integer;
      hHook,hPlay:Integer;
      recOK:Integer;
      canPlay:Integer;
      bDelay:Bool;
    implementation{$R *.DFM}
    Function PlayProc(iCode:Integer;wParam:wParam;lParam:lParam):LRESULT;stdcall;
    begin
      canPlay:=1;
      Result:=0;  if iCode < 0 then     //必须将消息传递到消息链的下一个接受单元
        Result := CallNextHookEx(hPlay,iCode,wParam,lParam)
      else if iCode = HC_SYSMODALON then
        canPlay:=0
      else if iCode = HC_SYSMODALOFF then
        canPlay:=1
      else if ((canPlay =1 )and(iCode=HC_GETNEXT)) then begin
        if bDelay then begin
          bDelay:=False;
          Result:=50;
        end;
        pEventMSG(lParam)^:=EventArr[PlayLog];
      end
      else if ((canPlay = 1)and(iCode = HC_SKIP))then begin
        bDelay := True;
        PlayLog:=PlayLog+1;
      end;
      if PlayLog>=EventLog then begin
        UNHookWindowsHookEx(hPlay);
      end;
    end;function HookProc(iCode:Integer;wParam:wParam;lParam:lParam):LRESULT;stdcall;
    begin
      recOK:=1;
      Result:=0;  if iCode < 0 then
        Result := CallNextHookEx(hHook,iCode,wParam,lParam)
      else if iCode = HC_SYSMODALON then
        recOK:=0
      else if iCode = HC_SYSMODALOFF then
        recOK:=1
      else if ((recOK>0) and (iCode = HC_ACTION)) then begin
        EventArr[EventLog]:=pEventMSG(lParam)^;
        EventLog:=EventLog+1;    if EventLog>=1000 then begin
          UnHookWindowsHookEx(hHook);
        end;
      end;
    end;procedure TForm1.FormCreate(Sender: TObject);
    begin
      Button1.Caption:='纪录';
      Button2.Caption:='停止';
      Button3.Caption:='回放';
      Button4.Caption:='范例';
      Button2.Enabled:=False;
      Button3.Enabled:=False;
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      EventLog:=0;
      //建立键盘鼠标操作消息纪录链
      hHook:=SetwindowsHookEx(WH_JOURNALRECORD,HookProc,HInstance,0);
      Button2.Enabled:=True;
      Button1.Enabled:=False;
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
      UnHookWindowsHookEx(hHook);
      hHook:=0;  Button1.Enabled:=True;
      Button2.Enabled:=False;
      Button3.Enabled:=True;
    end;procedure TForm1.Button3Click(Sender: TObject);
    begin
      PlayLog:=0;
      //建立键盘鼠标操作消息纪录回放链
      hPlay:=SetwindowsHookEx(WH_JOURNALPLAYBACK,PlayProc,
        HInstance,0);  Button3.Enabled:=False;
    end;end.    代码添加完毕后,运行程序,点击“纪录”按钮开始纪录操作,这时你可以在文本控件中输入一些文字或者点击
    “范例”按钮,然后点击“停止”按钮停止纪录,再点击“回放”按钮就可以讲先前所做的操作回放。
        在上面的程序中,HookProc是纪录操作的消息函数,每当有鼠标键盘消息发生时,系统都会调用该函数,消息信
    息就保存在地址lParam中,我们可以讲消息保存在一个数组中。PlayProc是消息回放函数,当系统可以执行消息回放
    时调用该函数,程序就将先前纪录的消息值返回到lParam指向的区域中,系统就会执行该消息,从而实现了消息回放。你如果要拦截Wm_MenuSelect消息的话,只要在窗体的Private 声明中写下面这样就可以了:
       procedure WMSelect(var Message : TWM_MenuSelect); Message WM_Select;
    然后实现这个过程就可以了。
    你是不是想选择菜单的时候的在状态栏之类的地方给出提示信息呀,如果是的话,可以不要这样。只要实现应用程序的OnHint过程就可以了。
        在主窗体的CREATE 事件中写下 Application.OnHint := myHint;并在主窗体实现中实现该myHint 过程。
      Procedure TMainfrm.OnHint(Sender : TComponet);
      begin
        StatusBar1.Panels[0].Text := Application.Hint;
      end;
       
    这样就可以了。
      

  2.   

    to AWolfBoy(龍行江湖):
    首先谢谢你帮助,不过里面有一些我在实现时有点不对。
    请你再帮我看看。
    我的程序是这样的:我用timer1判断当鼠标指向屏幕的右上角时,在右
    上角弹出一个菜单并同时把timer1.enabled:=false;这样没有问题。
    可是当把这个菜单关闭了,以后当鼠标再指向屏幕的右上角时,就弹
    不出刚才的菜单了。我用了你说的“AnyPopup”,不行。用 procedure WMSelect(var Message:TWM_MenuSelect);Message  WM_Select;  
    也拦截不住WM_Select消息。你可以试一下。
      

  3.   

    写错了,
    procedure WMSelect(var Message:TWM_MenuSelect);Message  WM_MenuSelect;前面的用TrackPopupMenu.