句柄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);            
    }
}

原文地址:https://www.cnblogs.com/hssbsw/p/1963949.html