• 句柄3


    题:请教:如何模拟点击一个窗口的任意一个位置?这个窗口是外部程序的一个弹出对话框。 ( 积分:10, 回复:4, 阅读:72 )
    分类:Windows API ( 版主:amo, cAkk )

    来自:lkdbdlkq, 时间:2007-4-18 14:25:00, ID3702107

    [显示:小字体 | 大字体]

    这个窗口的句柄可以获得,只是窗口在整个屏幕的位置可能因为不同的显示器及而有所不同,我想模拟点击它上面的某一点(X,Y),如何入手呢?非常感谢。 

     

    来自:Mclkings, 时间:2007-5-4 15:24:59, ID3710358

    PostMessaeg 发送就可以了。 

     

    来自:dennyshao001, 时间:2007-5-4 15:31:21, ID3710362

    用消息,WM_MOVING  

     

    来自:wyxriver, 时间:2007-6-17 20:57:47, ID3799606

    模拟鼠标点击事件movent_event  

     

    来自:lkdbdlkq, 时间:2007-6-18 19:59:35, ID3800019

    接受答案了.  

     

     

    /////////////////////////////////////////////////////////////////

    //先找程序外的某个标题的窗体:
    function EnumWinProc(Wnd : HWND; form1 : TForm1) : Boolean; Export; {$IFDEF Win32}StdCall;{$ENDIF}
    var
    WinText : Array[0..255] of Char;
    begin
    GetWindowText(Wnd, WinText, 255);
    Result := True;
    if (StrPas(WinText) <> '') and (Pos('XXX ',WinText)>1) then
    Form1.ListBox1.Items.Add(StrPas(WinText));
    end;

    //
    找到这个窗体,放在列表框中:
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    listbox1.Clear;
    EnumWindows(@EnumWinProc, LongInt(Self));
    end;

    //
    模拟点击:
    procedure TForm1.Button2Click(Sender: TObject);
    var
    Nhwnd:HWND;
    begin
    Nhwnd:=findwindow(NIL,pchar(listbox1.Items[listbox1.ItemIndex]));    
    //PostMessage(Nhwnd,BM_Click,100,100);
    //ShowWindow(Nhwnd,sw_show);
      SetForegroundWindow(Nhwnd);  //
    这一句成功执行了
      SendMessage(Nhwnd,WM_LBUTTONDOWN,400,300);
      SendMessage(Nhwnd,WM_LBUTTONUP,400,300);
      SetForegroundWindow(Nhwnd);
    end;

    end.


    为了试验,我做了个标题为“XXX”的窗体程序,窗体和屏幕一样大,并投置了点击事件:
    procedure TForm1.FormClick(Sender: TObject);
    begin
    showMessage('Clicked OK');
    end;
    结果发现,可以发现这个窗体的句柄,也能SetForegroundWindow,但是这个窗体并没有showMessage('Clicked OK');

    哪里不对了? 

     

    来自:[xiaopei], 时间:2008-5-30 17:36:25, ID3897798

    //试试这样。
      SendMessage(Nhwnd,WM_LBUTTONDOWN,0,(400 shl 16) or 300);
      SendMessage(Nhwnd,WM_LBUTTONUP,0,(400 shl 16) or 300);  

     

    来自:ynduanlian, 时间:2008-5-30 17:54:34, ID3897801

    楼上的这个方法对了,可否再请讲讲如何把点击发到屏幕上的某一点,比如说像素为800*600的那一点? 

     

     

    //////////////////////////////////////////////////////////////////////////////////////////

    程序如下,请大富翁们指教如何改正。
       Handle := FindWindow('Tmainform', 'test');  
      if Handle <> 0 then
          begin
             
    。。。。查找别一程序的窗体句柄
             BtnHandle := Handle;//
    已取得按钮句柄
             //SendMessage(FButtonHandle, WM_LBUTTONDOWN, 0, 0);
             //SendMessage(FButtonHandle, WM_LBUTTONUP, 0, 0);
             PostMessage(FButtonHandle, WM_LBUTTONDOWN, 0, 0);
             PostMessage(FButtonHandle, WM_LBUTTONUP, 0, 0);
             //
    注:改成PostMessage可以跳过
          //
    模拟点击另一程序,结果为别一程序弹出对话框,本程序就在此句停住,
             //
    不能执行下一句模拟点击另一程序对话框的程序。
            Handle := FindWindow('Tform1', 'test');  //
    对话框窗口查找不到正确的句柄,重点
              if Handle <> 0 then
               
    。。。。。。。。。。。。。
    end;  

     

    ]/////////////////////////////////////////////////////////////

    应该可以,我编了一个程序定时激活一个后台应用程序的窗口,然后点击该窗口的特定区域。下面仅是部分源程序,若觉有用,我可将全部文件打包发到你的信箱里!
    unit Unit1;

    interface

    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      ExtCtrls, StdCtrls;

    type
      TGetDot = class(TForm)
        Timer1: TTimer;
        Label1: TLabel;
        procedure Timer1Timer(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;

    var
      GetDot: TGetDot;

    implementation

    {$R *.DFM}

    procedure TGetDot.Timer1Timer(Sender: TObject);
    var
       hCurWindow,CurActiveWindow: HWnd;  //
    窗口句柄
       WinText: array [0..255] of char;
       WinCount:Integer;
    begin
         WinCount:=0;
         CurActiveWindow:=GetActiveWindow();
         hCurWindow := GetWindow(Handle, GW_HWNDFIRST);
         //
    获取第一个窗口的句柄
     while hCurWindow <> 0 do
       begin
           //
    获取窗口的名称
       if GetWindowText(hCurWindow, @WinText, 255)>0 then
          if ( WinText='
    民主湖聊天室 - Microsoft Internet Explorer') then
              begin
                    //
    激活该应用程序窗口,使其在屏幕最前面
                   SendMessage(hCurWindow,WM_SYSCOMMAND,SC_MINIMIZE,0);
                   SendMessage(hCurWindow,WM_SYSCOMMAND,SC_RESTORE,0);
                   //
    将鼠标控制权转到该程序上
                   SetCapture(hCurWindow);
                   //
    鼠标定位到指定座标
                   SetCursorPos(720,475);
                   //
    产生鼠标按键事件
                   mouse_event(MOUSEEVENTF_LEFTDOWN+MOUSEEVENTF_LEFTUP,
                               720,475,0,GetMessageExtraInfo());
                   //
    给其他应用程序以事件反应时间
                   sleep(5000);
              //
    获取下一窗口
              hCurWindow:=GetWindow(hCurWindow, GW_HWNDNEXT);
         end;
    end;
      

     

    来自:lycwg, 时间:2000-6-16 12:06:00, ID266205

    忘了你要不影响当前程序运行,可在处理完成后用下列方法,激活自已的窗体即可!
    SendMessage(GetDot.Handle,WM_SYSCOMMAND,SC_MINIMIZE,0);
    SendMessage(GetDot.Handle,WM_SYSCOMMAND,SC_RESTORE,0);

    其中GetDot为自己应用程序的窗口名 

     

     

     

    /////////////////////////////////////////////////////

    问题已经解决,在此,谢谢各位的帮助
    我现在将代码贴出,以作参考
    function EnumWindowsProc(AHWnd: HWnd;  LPARAM: lParam): boolean; stdcall;
    var
      WndCaption: array[0..254] of char;
      WndClassName: array[0..254] of char;
      rtscreen: trect;
      WinXY:TRect;
      xy:TPoint;
    begin
      GetWindowText(AHWnd, @WndCaption, 254);
      GetClassName(AHWnd, @WndClassName, 254);
      if (pos('CashSurfers.com',wndcaption)<>0) then //
    用你已知的窗口标题替换这里, 找到此窗口
        begin
          ahwnd:=findwindowEX(ahwnd,0,pchar('TButton'),pchar('Cool!'));  //
    找到窗口上的按钮
          GetWindowRect(AHWnd,WinXY);                                    //
    得到按钮的坐标范围
          xy:=WinXY.TopLeft;                                             //
    取得按钮左上角的坐标
          xy.x:=xy.x+10;
          xy.y:=xy.y+10;
          SetCursorPos(xy.x,xy.y);                                       //
    Mouse定位到按钮上
          Mouse_Event(MOUSEEVENTF_LEFTDown,xy.x,xy.y,0,0);               //
    按下左键
          Mouse_Event(MOUSEEVENTF_LEFTUP,  xy.x,xy.y,0,0);               //
    按下右键
        end;
      Result := True ;
    end;

     

     

    ///////////////////////////////////////////////////////////////

    一个很简单的办法:
    建立一form, setwindowrgn(form.handle, createrectrgn(-1,-1,0,0), true);
    setcapture(form.handle),
    然后就可以用form.onmousemove, onmousedown, onmouseup等事件了, 而且窗口在屏幕上不可见(却是actived).

    ////////

    SetForeGroundWindow(hIE); hie为句柄

     

    不在最前面可以先SetForegroundWindow

     

    根本问题是用sendmessage怎么模拟出toolbar上的按钮的click事件,而不是模拟鼠标的单击。谢谢。

    另外的方法就是通过ToolBar的句柄获得类TToolBar的实例obj:=   FindControl(h);,然后可以直接TToolBar(obj).Buttons[0].Click;来模拟,但是FindControl必须在目标进程内调用才能够返回正确的实例地址,所以必须写一个Hookdll,然后注入到目标进程后再FindControl获得实例后模拟Click实现。

    至于你说非要sendmessage来模拟,我是不知道应该发什么消息,等高手解答吧!

     

     

     

    ////////

    方法一 Sending a Message

    1.     btnevent.Perform(WM_LBUTTONDOWN, 0, 0);

    2.     btnevent.Perform(WM_LBUTTONUP, 0, 0);

    复制代码

    方法二 用按钮的事件方法

    1.     btnevent.Click;

    复制代码

    方法三 With a pressed effect:

    1.     {The BM_SETSTATE message is sent by an application

    2.     to change the highlight state of a button.

    3.     }

    4.      

    5.     SendMessage(btnevent.Handle, BM_SETSTATE, 1, 0);

    6.     btnevent.Click;

    7.     Sleep(100); // Some delay

    8.     PostMessage(btnevent.Handle, BM_SETSTATE, 0, 0);

    复制代码

     

     

     

     

    /////////////////////////////////////////////////////////

    如果是想要在整个windows环境下面的热键
    可以参看下面:
    RegisterHotKey
    函数原型及说明:
    BOOL RegisterHotKey(
    HWND hWnd, // window to receive hot-key notification
    int id, // identifier of hot key
    UINT fsModifiers, // key-modifier flags
    UINT vk // virtual-key code);
    参数 id为你自己定义的一个ID值,对一个线程来讲其值必需在0x0000 - 0xBFFF范围之内,对DLL来讲其值必需在0xC000 - 0xFFFF 范围之内,在同一进程内该值必须唯一
    参数 fsModifiers指明与热键联合使用按键,可取值为:MOD_ALT MOD_CONTROL MOD_WIN MOD_SHIFT
    参数 vk指明热键的虚拟键码


    首先(举个例子):
    RegisterHotKey(handle,globaladdatom('hot key'),MOD_ALT,vk_f12);
    然后在form中声明一个函数(过程):
    procedure hotkey(var msg:tmessage);message wm_hotkey;
    过程如下:
    procedure TForm1.hotkey(var msg:tmessage);
    begin
    if (msg.LParamHi=VK_F12) and (msg.LParamLo=MOD_ALT) then
    begin
    form1.show;
    SetForegroundWindow(handle);
    end;
    end;
    这样,不管你在什么地方,窗口就会显示出来。
    当然,你要GlobalDeleteAtom;

     

     

     

     

    //////////////////////////////////////////////////////////////

     

    如何用SendMessage模拟某一按钮的点击事件

    2010-12-14 11:06

    转载自 liu494021458

    最终编辑 liu494021458

    今天在写程序的时候,用到了进程间的通信,上网查了些相关的资料,一般都是通过消息、共享内存、 socket,管道(Pipe),信箱(Mailslot),等等。因为我进程间通信的时候数据量不太大,所以就先测试了一下消息。

    一般情况下,用消息来实现进程通信相对比较简单,自定义消息、手动添加消息映射、编写响应函数,发送端先FindWindow(),然后就向目标进程SendMessage()。自定义消息的测试没有什么问题,但在向目标进程发送系统消息时遇到了些问题,发送WM_CLOSE消息也可以,但是在我尝试发送按钮消息时,遇到了些麻烦,在查资料,并多次测试后终于搞定,看到网上一些资料都没有明确的答案,就把我的一些体会发在这里,有朋友遇到这个问题时也就少走点弯路。当然,我个人水平也很菜,高手就不要看了!

    自定义消息和消息映射就不多说了,获取窗口进程:
    CWnd *pWnd=CWnd::FindWindow(NULL,str);

    模拟其中窗口上的按钮点击事件可以采用以下的方法:

    1、pWnd->SendMessage(WM_COMMAND,IDC_BUTTON1,0);

    2、pWnd->SendMessage(WM_COMMAND,((WPARAM)BN_CLICKED)<<8|(WPARAM)IDC_BUTTON1,0L);

    3、pWnd->SendDlgItemMessage(IDC_BUTTON1,BM_CLICK,0,0);

    4、::SendMessage(pWnd->GetSafeHwnd(),WM_COMMAND,IDC_BUTTON1,NULL);

    5、::SendMessage(pWnd->GetDlgItem(IDC_BUTTON1)->GetSafeHwnd(),WM_LBUTTONDOWN,IDC_BUTTON1,0);
    ::SendMessage(pWnd->GetDlgItem(IDC_BUTTON1)->GetSafeHwnd(),WM_LBUTTONUP,IDC_BUTTON1,0);

    6、pWnd->GetDlgItem(IDC_BUTTON1)->SendMessage(WM_LBUTTONDOWN);
    pWnd->GetDlgItem(IDC_BUTTON1)->SendMessage(WM_LBUTTONUP);

    注意:
    1、如果模拟自己进程内的按钮,前面的方法都可以使用,将其中pWnd替换为this或直接为空即可。

    2、如果是向另外一个进程发送消息,并模拟另外进程中的按钮的点击事件,那么有一点要注意,就是其中的按钮ID号,不能使用比如IDC_BUTTON1这样的宏,因为在本程序里也有定义,并且这个值可能和你想要模拟的按钮的ID在它所在的进程中的ID不同,它会被默认
    替换为本进程内的值。
    举个例子,现在你编写了两个对话框程序A和B,在程序A中,定义了两个按钮,分别为IDC_BUTTON1和IDC_BUTTON2,打开Resource.h查看一下它们的ID值:
    #define IDC_BUTTON1 1000
    #define IDC_BUTTON2 1001
    在程序B中,定义了一个按钮,名字为IDC_BUTTON1,打开Resource.h查看一下该按钮的ID值:
    #define IDC_BUTTON1 1001
    从两个头文件中可以看出,程序A中的IDC_BUTTON2和ID值和程序B中的IDC_BUTTON1的ID值相同,而两个程序的IDC_BUTTON1的值并不相同。
    注意,问题就出在这这儿。如果我们想模拟程序B中按钮IDC_BUTTON1的点击事件,按照前面的方法是行不通的,不信可以试试。
    但如果我们在使用前面的那些方法时,改变一下传递的参数,将其中的IDC_BUTTON1改为IDC_BUTTON2,试一下,进程B中的按钮成功的模拟出来了,竟然达到了我们的目标。那么奇怪,明明B程序中按钮的ID是IDC_BUTTON1啊!现在改为IDC_BUTTON2反而成功了呢?为什么会这样呢?
    其实这主要是因为两个程序的不同引起的,因为我们在A程序中调用前面的方法来模拟程序B的按钮时,程序B中的IDC_BUTTON1按钮的实际的ID值是非曲直1001,而程序A中却把IDC_BUTTON1的值设为了1000,所以无论你怎么发送消息都没用,程序B里面1000的ID值并不是IDC_BUTTON1对应的值,它实际的值应该是1001。不信的话,可以用1001代替IDC_BUTTON1,然后用前面的那些方法试试。

    ////////////////////////////////////////////////////////////////////////////////

    应用程序模拟按钮点击

    2010-12-13 11:32

    编一个程序模拟按下计算器程序中0那个按键

    以下代码获得 计算器 的各个按件的 ID 的 Caption(或Text),并放在 ListBox1 中
    HWND hWnd = FindWindow(NULL, "计算器");
    if( hWnd == NULL )
    return;
    HWND hChildWnd = NULL;
    int id = -1;
    char caption[255];
    for(int i=0;i<10000;i++) {
    hChildWnd = GetDlgItem(hWnd,i);//EditID->Text.ToIntDef(0));
    id = -1;
    if( hChildWnd != NULL ) {
    id = GetDlgCtrlID(hChildWnd);
    if( 0 != GetDlgItemText(
    hWnd,
    id,
    caption,
    255
    ) ) {
    ListBox1->Items->Add(AnsiString(caption)+"="+IntToStr(id));
    }
    }
    }  

    按下某个按钮。

            HWND hWin, hChild;
    hWin = FindWindow("SciCalc", "计算器");
    if(hWin)
    {
    hChild = FindWindowEx(hWin, 0, "Button", "1");
    if(hChild)
    {
    SendMessage(hChild,WM_LBUTTONDOWN,0,0);//按下
    SendMessage(hChild,WM_LBUTTONUP,0,0);//抬起
    }
    }   

     

    //////////////////////////////////////////////////////////

    c++模拟鼠标点击程序的实现方法

    2010-12-15 10:40

     模拟点击,模拟按键等功能一般都是特殊情况下的程序需求,在需要实现模拟的目标程序无源代码,不方便实现自动化的情况下,需要此类功能。比如我原来办公用到的一个管理系统,每天需要逐条审核50多条数据,每审核一条数据总会弹出一个确定对话框,这时候数据已经通过了审核,还需要什么确定,完全是画蛇添足,所以相当烦恼,这与原程序设计考虑不合理有关,此时我就通过模拟点击那个确定对话框,让必须手工点一下确定对话框由后台代码来实现。以下代码模拟点击系统自带计算器中的"7","1","9"按钮,点击后你会看到跟你用手工点击的效果一模一样。当然扩展以下代码能实现其它许多复杂的自动化功能。

    HWND hWndId,hWndB1;
    hWndId = ::FindWindow(NULL,"计算器");
    if (hWndId!=0)
    {
        hWndB1=::FindWindowEx(hWndId,0,"Button","7");
        if (hWndB1!=0 )
        {
            ::PostMessage(hWndB1,WM_LBUTTONDOWN,0,0);
            ::PostMessage(hWndB1,WM_LBUTTONUP,0,0);            
        }
        hWndB1=::FindWindowEx(hWndId,0,"Button","1");
        if (hWndB1!=0 )
        {
            ::PostMessage(hWndB1,WM_LBUTTONDOWN,0,0);
            ::PostMessage(hWndB1,WM_LBUTTONUP,0,0);            
        }
        hWndB1=::FindWindowEx(hWndId,0,"Button","9");
        if (hWndB1!=0 )
        {
            ::PostMessage(hWndB1,WM_LBUTTONDOWN,0,0);
            ::PostMessage(hWndB1,WM_LBUTTONUP,0,0);            
        }
    }

  • 相关阅读:
    排序算法(I)冒泡排序
    C#常用类string
    HashMap----工作原理
    Java计算字符串中字母出现的次数
    数据库优化
    线程和进程的区别(详细)
    SpringMVC工作原理
    jsp运行原理及运行过程
    一个公告
    SR
  • 原文地址:https://www.cnblogs.com/hssbsw/p/1963949.html
Copyright © 2020-2023  润新知