天天看點

模拟對另一程序的視窗按鈕的點選

1、

在自動化測試中經常要模拟視窗按鈕的點選。

參考文章:http://blog.csdn.net/blackboyofsnp/article/details/3372719

有時我們需要這麼做, 手動模拟按鈕按下的事件, 讓程式做出與按鈕真的按下時一樣的響應.

   設按鈕ID為ID_BTN_OK, 目前Dialog視窗.    實際上系統并不能區分按鈕是真的按下了(如用滑鼠點選), 還是一個我們自己用代碼模拟出的一種"假象". 它所需要知道的隻是哪個視窗(按鈕也是一種視窗)發生了哪一種事件, 然後在消息循環中處理它. 系統怎麼才 能知道這些呢? 當然靠的是消息(message), 我們 隻需按照Windows或者MFC的标準格式把相應的資訊傳給系統, 系統就會"上當"了.    向系統傳遞消息可以用SendMessage或PostMessage(可能還有其他很多函數哦), 但SendMessage執行後系統 會一直等待, 直到要發送的消息被處理掉. 而PostMessage可不管那麼多, 發送消息後立即傳回程式流程. 當 按鈕按下的響應函數中有很大一個循環時, 用SendMessage會出現許多問題, 尤其是要在程式初始化階段模拟時, 會導緻窗體無法完成初始化. 是以我們用PostMessage(). 它的原型為:

BOOL PostMessage(          HWND hWnd,
    UINT Msg,
    WPARAM wParam,
     LPARAM lParam
);
           

這樣寫;  

PostMessage(WM_COMMAND, MAKEWPARAM(ID_BTN_OK, BN_CLICKED), NULL);
           

這裡, WM_COMMAND是要發送的消息, MAKEWPARAM宏是為了組成一個WPARAM,WM_COMMAND消息的WPARAM的低字為控件ID,高字為識别碼, 最後一個參數LPARAM可為NULL.相關定義可檢視MSDN.

  這樣我們就把必需的資訊格式化好發送給系統了. 當系統在消息循環中收到該消息時, 就知道哦, 你要引發控件ID_BTN_OK 的事件BN_CLICKED, 好的我幫你處理. 于是我們就驚喜地看到按鈕看起來真的按下去了, 并執行了和真正按下去時一樣的代碼.

看評論說不管用,我又試驗了一下。建立一個對話框工程,在對話框上添加一個按鈕,ID為IDC_BTN_TEST,單擊它,為它添加ON_BN_CLICKED消息響應函數:

void CtestDlg::OnBnClickedBtnTest()
{
    AfxMessageBox(_T("OK"));
}
           

然後在對話框的OnInitDialog()函數的return TRUE前加上:

PostMessage(WM_COMMAND, MAKEWPARAM(IDC_BTN_TEST, BN_CLICKED), NULL);
           

好了,再運作程式,會彈出個消息框 “OK”,說明模拟正确。

 2、 C#調用迅雷的時候 自動模拟點選”下載下傳按鈕” 關閉彈出視窗

網上 關于 “不彈出《建立任務》的對話框的方法 在迅雷5.9貌似不适用了” 那麼我改了一下網上的“監聽方式”來進行模拟點選

#region Dll Import 需要導入的api 聲明。
 
        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string lpClassName,
      string lpWindowName);
 
        [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent,
      IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
 
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(IntPtr hWnd,
      int Msg, IntPtr wParam, string lParam);
        const int WM_GETTEXT = 0x000D;
        const int WM_SETTEXT = 0x000C;
        const int WM_CLICK = 0x00F5;
        #endregion
        //關消息的方法
        private void ClosePopWindow(object obj)
        {
            //這些用spy++可以看到
            string lpszParentClass = "#32770"; //整個視窗的類名
            string lpszParentWindow = "建立新的下載下傳任務"; //視窗标題
            string lpszClass_Submit = "Button"; //需要查找的Button的類名
            string lpszName_Submit = "立即下載下傳"; //需要查找的Button的标題          
 
            IntPtr ParenthWnd = new IntPtr(0);
            IntPtr EdithWnd = new IntPtr(0);
            int i = 0;
            while (true)
            {
                //查到窗體,得到整個窗體
                ParenthWnd = FindWindow(lpszParentClass, lpszParentWindow);
                //判斷這個窗體是否有效
                if (!ParenthWnd.Equals(IntPtr.Zero))
                {
 
                    //得到第一級子視窗
                    EdithWnd = FindWindowEx(ParenthWnd,
                        new IntPtr(0), "#32770", "");
                    //Console.WriteLine("第一級-"+EdithWnd.ToString());
                    //得到Button這個子窗體,并觸發它的Click事件
                    EdithWnd = FindWindowEx(EdithWnd,
                        new IntPtr(0), lpszClass_Submit, lpszName_Submit);
                    //Console.WriteLine("第二級-" + EdithWnd.ToString());
                    if (!EdithWnd.Equals(IntPtr.Zero))
                    {
                        SendMessage(EdithWnd, WM_CLICK, (IntPtr)0, "0");
                    }
                    return;
                }
                Thread.Sleep(1000);
                i++;
                //  Console.WriteLine("第"+i.ToString()+"次檢查"); 5秒都沒顯示出來就推出循環
                if (i > 15)
                {
                    //break;
                }
            }
        } 
 
//需要導入如下類庫
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Win32;
 
//在迅雷送出前添加一個方法
ThreadPool.QueueUserWorkItem(new WaitCallback(ClosePopWindow));
           

 3、

#include <iostream>
#include <fstream>
#include <math.h>
#include <cctype>
#include <string>
#include <windows.h>

using namespace std;

int main()
{
    //cout << "Hello world!" << endl;
    HWND hwnd = FindWindow( 0, "檔案視窗"  );


    //HWND hWnd2 =  GetDlgItem( hwnd, 1001);

    char* strs = new char[ 255 ];
    HWND hWnd2 = ::FindWindowEx(hwnd,NULL,"Button",NULL);

    while ( hWnd2 )
    {
        GetWindowText( hWnd2, strs, 255 );


        cout << strs << endl;



       /* if ( strcasecmp( strs, "确定" ) == 0 ) {
            break;
        }*/

        hWnd2 = FindWindowEx( hwnd, hWnd2, "Button", NULL );
    }




    UINT nCtrlID = ::GetDlgCtrlID(hWnd2);
    ::PostMessage(hWnd2, WM_COMMAND, (WPARAM)(BN_CLICKED << 16 | nCtrlID), (LPARAM)hWnd2);
    ::PostMessage(hWnd2,WM_MOUSEMOVE, MK_LBUTTON, MAKELONG(0,0) );
    ::PostMessage(hWnd2,WM_LBUTTONDOWN,MK_LBUTTON,MAKELPARAM(0,0));
    ::PostMessage(hWnd2,WM_LBUTTONUP,MK_LBUTTON,MAKELPARAM(0,0));

    return 0;
}
           

4、往編輯框中寫入檔案(可實作)

SetWindowText