如何截获分析其它程序窗口的WM_COMMAND消息?就像SPY++一样。
我主要目的是想分析出菜单的ID。
请给出详细的代码,谢谢了。我想这个问题应该难不倒你的!是吗?

解决方案 »

  1.   

    http://hyd8.com/info/3399.htmDelphi中的消息钩子函数和Windows子类处理 入门篇 首先我们先看一下安装HOOK的函数:
    HHOOK SetWindowsHookEx(
        int idHook,       //要安装的HOOK的类型
        HOOKPROC lpfn,    //HOOK的回调函数
        HINSTANCE hMod,   //进程
        DWORD dwThreadId  //程序的线程,如果为0则是全局HOOK
    );熟悉了SetWindowsHookEx函数,我们就能开始我们的工作,挂钩进程。
    首先打开Delphi,创建一个DLL工程(DLL Wizard)。然后创建一个新的单元(Unit1)。
    首先在单元的 interface 下面声明要用到的函数。
    var
        OldHook:HHOOK;
        Histance:HISTANCE;
        OldProc:FARPROC;
    我们的第一个函数是安装HOOK,让我们看一下代码:Function SetHook:Boolean;stdcall;
    begin
      OldHook:=SetWindowsHookEx(WH_KEYBOARD,@HookProc,Histance,0);
      if (OldHook=0) then exit else Result:=True;
    end;这样的话就安装一个全局的键盘HOOK,HOOK的方法还有很多,在此就不一一列举了。下面介绍一下回调函数:
    Function HookProc(nCode,wParam,lParam:Integer);Integer;stdcall;
    begin
      Result:=CallNextHookEx(OldHook,nCode,wParam,lParam);
    end;这样的话就完成了对进程的挂钩。可是挂上钩我们的工作并没结束,相反,我们的工
    作才刚刚开始。钩子的作用是帮我们把DLL注入到别人的进程空间。现在我们的DLL已
    经在别人的进程空间内。所以,我们就可以做我们想做的事。
    下面介绍一下Windows的子类化处理。大家都知道,在windows里不管你做了什么事,都会向windows发送一条消息,然后由
    Windows作出相应的处理后才会返回给传送消息的应用程序。
    那大家会问:“HOOK不是已经拦截了windows消息了吗?”是啊,那也要看是拦截了什么消息,就如上面我们写的WH_KEYBOARD,我们拦截了键盘
    消息,我们可以在按下任何一个按键的时候做出处理。消息的种类有很多。
    可是我们今天要讲的是windows的子类化处理,这又是一门新的技术。
    不废话了,这就开始。^_^相信大家都见过两这个API:GetWindowsLong 和 SetWindowLong;
    可能你们会说,这些不是处理窗口消息的吗?对,这就是我们要用到的API。接下来让我们看一下这些API的参数。
    LONG GetWindowLong(
        HWND hWnd,    //窗体的句柄
        int nIndex    //欲取回的信息,可参照下表
    );
    nIndex的值可以是下列任何一个
    GWL_EXSTYLE 扩展窗口样式 
    GWL_STYLE 窗口样式 
    GWL_WNDPROC 该窗口的窗口函数的地址 
    GWL_HINSTANCE 拥有窗口的实例的句柄 
    GWL_HWNDPARENT 该窗口之父的句柄。不要用SetWindowWord来改变这个值 
    GWL_ID 对话框中一个子窗口的标识符 
    GWL_USERDATA 含义由应用程序规定 
    DWL_DLGPROC 这个窗口的对话框函数地址 
    DWL_MSGRESULT 在对话框函数中处理的一条消息返回的值 
    DWL_USER 含义由应用程序规定 
    也许大家会注意到 GWL_WNDPROC 这个参数。没错,我们子类处理就是要用到这个参数。
    代码如下:
    OldProc:=GetWindowLong(hWnd,GWL_WNDPROC);这样我们的OldProc就指向窗体的窗口函数地址;
    既然得到了窗口函数地址,那么就修改到我们自定义的消息处理地址里吧。
    下面要用到SetWindowLong函数了。
    LONG SetWindowLong(
        HWND hWnd,      //指定窗口句柄
        int nIndex,     //和GetWindowLong的nIndex一样
        LONG dwNewLong  //新的消息处理地址
    );代码如下:
    SetWindowLong(hWnd,GWL_WNDPROC,Longint(@WinProc));这样就把指定窗体的消息转到了我们的函数内执行;回调函数如下:
    Function WinProc(Hwnd,Msg,wParam,lParam:longint):LRESULT; stdcall;
    begin
    Result:=CallWindowProc(OldProc,Hwnd,Msg,wParam,lParam);
    end;
    这里的Msg就是窗口的消息,后面赋上消息表。小节:文章写到这里,相信大家应该明白HOOK和子类是什么回事吧。下面再解释一下
    为什么不在HOOK里处理消息。前面已经提到,HOOK是帮助我们把DLL注入别人的进程。
    而windows子类处理只能在进程内处理消息,所以只有我们到了别人的进程空间内,才
    能做出消息屏蔽的动作。这样说大家都能明白了吧。    好了,就不废话了。下面赋上源代码。希望大家多多支持! ^_^
        (复制就可以用的哦)##########################################################################
    unit Unit1;interface
    uses windows;
    var
        OldHook:HHOOK;        //用来保存HOOK的返回值
        OldProc:FARPROC;      //用来指向窗口消息
        Function SetHook:Boolean;stdcall;
        Function HookProc(nCode,wParam,lParam:Integer):Integer;stdcall;
        Function WinProc(Hwnd,Msg,wParam,lParam:longint):LRESULT; stdcall;
        
    implementation
    {###################################################################################}
    //安装HOOK
    Function SetHook:Boolean;stdcall;
    var
        Histance:Cardinal; 
    begin
      //安装HOOK
      OldHook:=SetWindowsHookEx(WH_KEYBOARD,@HookProc,Histance,0);
      if (OldHook=0) then exit else Result:=True;
    end;{###################################################################################}
    //HOOK回调函数
    Function HookProc(nCode,wParam,lParam:Integer):Integer;stdcall;
    var
    WinStr:HWND;
    begin
      //设置热键
      if (wParam=VK_F12) then
        begin
          WinStr:=FindWindow(nil,'窗口的标题文字');
          OldProc:=FARPROC(GetWindowLong(WinStr,GWL_WNDPROC));
          SetWindowLong(WinStr,GWL_WNDPROC,Longint(@WinProc));
        end;
      //将HOOK传递给Windows处理
      Result:=CallNextHookEx(OldHook,nCode,wParam,lParam);
    end;{###################################################################################}
    //自定义Windows消息处理函数
    Function WinProc(Hwnd,Msg,wParam,lParam:longint):LRESULT; stdcall;
    begin
    {在这做出对消息的处理  case Msg of
        WM_ACTIVATEAPP:exit;
        WM_ACTIVATE:exit;
        WM_KILLFOCUS:exit;
        WM_SETFOCUS:exit;
      end;
    上面这些消息是窗口失去焦点和获得焦点的屏蔽
    }
    //将窗口消息传递给Windows处理
    Result:=CallWindowProc(OldProc,Hwnd,Msg,wParam,lParam);
    end;
    end.
      

  2.   

    http://www.pcbookcn.com/article/1558.htm
    function WindowProc(hWnd,Msg,wParam,lParam:longint):LRESULT; stdcall; 
    var k:integer; 
    begin 
     Result:=DefWindowProc(hWnd,Msg,wParam,lParam); 
     case Msg of 
     wm_destroy: 
       begin 
         for k:=0 to 12 do SetHook(False,k); 
         postmessage(findwindow('WinHook',nil),wm_destroy,0,0); 
         ExitThread(0); 
       end; 
     end; 
     if msg=wmhook then 
     begin 
       if wparam>0 then 
       begin 
         if sethook(true,wparam-1)=true then postmessage(findwindow('WinHook',nil),wmhook,wparam,0); 
       end else 
       begin 
         if sethook(false,-wparam-1)=true then postmessage(findwindow('WinHook',nil),wmhook,wparam,0); 
       end; 
     end; 
    end; procedure run;stdcall; 
    //var k:integer; 
    begin 
     win.wClass.lpfnWndProc:=  @WindowProc; 
     win.wClass.hInstance:=    hInstance; 
     win.wClass.lpszClassName:='WideHook'; 
     RegisterClass(win.wClass); 
     win.hmain:=CreateWindowEx(ws_ex_toolwindow,win.wClass.lpszClassName,'WideHook',WS_CAPTION,0,0,1,1,0,0,hInstance,nil); 
     FillChar(Shared^,SizeOf(TShared),0); 
     shared^.self:=win.hmain; 
     shared^.hinst:=hinstance; 
     InitHookData; 
     wmhook:=registerwindowmessage(pchar('wm_hook')); 
     while(GetMessage(win.Msg,win.hmain,0,0))do 
     begin 
       TranslateMessage(win.Msg); 
       DispatchMessage(win.Msg); 
     end; 
    end; procedure DllEntryPoint(fdwReason:DWORD); 
    begin 
     case fdwReason of 
     DLL_PROCESS_DETACH: 
       Extro; 
     end; 
    end; exports run; begin 
     //建立内存映象文件,用来保存全局变量 
     MemFile:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,SizeOf(TShared),HookMemFileName); 
     Shared:=MapViewOfFile(MemFile,FILE_MAP_WRITE,0,0,0); 
     DLLProc:=@DllEntryPoint; 
    end. ---------这是*.exe主程序--------------------------- Program WinHook; uses windows,messages,sysutils; 
    {$r *.res}  //使用资源文件 
    const 
     HTName:array[1..13] of pchar=( 
     'CALLWNDPROC','CALLWNDPROCRET','CBT','DEBUG','GETMESSAGE','JOURNALPLAYBACK', 
     'JOURNALRECORD','KEYBOARD','MOUSE','MSGFILTER','SHELL','SYSMSGFILTER','FOREGROUNDIDLE' 
     ); 
    type 
     TWin = record 
       Msg:TMsg; 
       wClass:TWndClass; 
       hMain:integer; 
       hbut,hlab:array[1..16] of integer; 
       hLib:integer; 
       HookStat:array[1..16] of bool; 
     end; 
    var 
     Win:TWin;                    //结构变量 
     wmhook:integer; 
     WorkPath:string; 
     hRun:procedure;stdcall; 
    // 
    procedure runhookfun; 
    begin 
     win.hlib:=loadlibrary(pchar(WorkPath+'DemoHook.dll')); 
     if win.hlib=0 then messagebox(win.hmain,'error','',0); 
     hrun:=GetProcAddress(win.hlib,'run'); 
     if @hrun<>nil then hrun; 
    end; procedure runhook; 
    var tid:integer; 
    begin 
     createthread(nil,0,@runhookfun,nil,0,tid); 
    end; function WindowProc(hWnd,Msg,wParam,lParam:longint):LRESULT; stdcall; 
    var k:integer; 
    begin 
     case Msg of 
     WM_SYSCOMMAND: 
       begin 
         case wparam of 
         SC_CLOSE: 
           begin 
             if findwindow('WideHook','WideHook')<>0 then postmessage(findwindow('WideHook','WideHook'),wm_destroy,0,0); 
           end;//showwindow(hwnd,sw_hide); 
         SC_MINIMIZE:;//showwindow(hwnd,sw_hide); 
         SC_MAXIMIZE:; 
         SC_DEFAULT:; 
         SC_MOVE:; 
         SC_SIZE:; 
         //else 
         //Result := DefWindowProc(hwnd, uMsg, wParam, lParam); 
         end; 
         exit; 
       end; 
     wm_command: 
       begin 
     
      

  3.   

    呵呵,那这个问题就难倒你了,是吗?
    http://blog.csdn.net/linzhengqun
    看里面的钩子应用。