小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

C#實現(xiàn)對外部程序的調(diào)用操作

 dinghj 2017-04-10

關(guān)于C#如何調(diào)用外部應用程序、如何操作外部程序(如點擊按鈕、輸入文本等),這篇文章介紹的非常詳盡,建議閱讀。

本文代碼下載(VS2010開發(fā)):http://download.csdn.net/source/2796362

本文摘要:

1:一個簡單的例子   

  1.1:EnumChildWindows介紹

  1.2:主要源碼

2:難點:如何獲取指定的控件句柄

  2.1:使用SPY++

  2.2:獲取控件位置

  2.3:獲取控件ID

1:一個簡單的例子 

    在日常編碼過程中,我們常常會進行自動化測試。這里的自動化測試不是指單元測試,而是模擬人工輸入來進行快速的、高并發(fā)的測試??梢允褂玫淖詣踊ぞ哂蠰OADRUNNER,以及目前在VS2010中的功能很強大的測試工作平臺(錄制操作步驟,自動生成代碼)。但是,這些工具的熟練掌握也有一定的時間成本,并且,最主要的,對于一個程序員來說,那不夠靈活。所以,比較高效的一個做法是,調(diào)用WINDOWS API,自己動手寫編碼來實現(xiàn)。

    下面做一個簡單的演示。為了簡便起見,假設存在這樣一個應用程序:

1:提供一個WINFORM窗體,上面存在一個TextBox,以及一個Button;

2:點擊Button,會彈出提示框,提示框內(nèi)容為TextBox的值;

    現(xiàn)在,測試要求如下:

1:在300臺機器上運行上面的程序;

2:到這300臺機器上去點擊這個Button,看看上文中的功能2有沒有實現(xiàn);

    很顯然,實際情況中沒有這么簡單的程序,實際的情況有可能是點擊Button,統(tǒng)一下載一個文件,而測試的要求可能就變?yōu)榭己?a href="http://www./bkhtml/c68" target="_blank" title="服務器教程">服務器的負載?,F(xiàn)在,測試部顯然也沒有300個人坐在客戶機上驗證測試的結(jié)果,這個時候,就需要我們提供一個自動化的測試工具,來完成必要的測試任務。

    測試工具,首先也是一個C#的程序,它的主要目的是:

1:獲取上文應用程序的窗口句柄,繼而獲取TextBox句柄及Button句柄;

2:為TextBox隨機填入一些字符;

3:模擬點擊Button;

1.1:EnumChildWindows介紹

  在這里需要介紹下EnumChildWindows,

EnumChildWindows可是個好東西,可以枚舉一個父窗口的所有子窗口:

BOOL EnumChildWindows( 
  HWND hWndParent,        // handle to parent window // 父窗口句柄 
  WNDENUMPROC lpEnumFunc,  // callback function // 回調(diào)函數(shù)的地址 
  LPARAM lParam            // application-defined value // 你自已定義的參數(shù) 
);

    就這么簡單,讓我們再定義一個回調(diào)函數(shù),像下面這樣:

BOOL CALLBACK EnumChildProc( 
  HWND hwnd,      // handle to child window 
  LPARAM lParam  // application-defined value 
);

    在調(diào)用EnumChildWindows 這個函數(shù)時,直到調(diào)用到最個一個子窗口被枚舉或回調(diào)函數(shù)返回一個false,否則將一直枚舉下去。

1.2:簡單例子的主要源碼

    測試工具的主要代碼如下:

        private void button1_Click(object sender, EventArgs e)
        {
            //獲取測試程序的窗體句柄
            IntPtr mainWnd = FindWindow(null, "FormLogin");
            List<IntPtr> listWnd = new List<IntPtr>();
            //獲取窗體上OK按鈕的句柄 
            IntPtr hwnd_button = FindWindowEx(mainWnd, new IntPtr(0), null, "OK");
            //獲取窗體上所有控件的句柄
            EnumChildWindows(mainWnd, new CallBack(delegate(IntPtr hwnd, int lParam)
            {
                listWnd.Add(hwnd);
                return true;
            }), 0);
            foreach (IntPtr item in listWnd)
            {
                if (item != hwnd_button)
                {
                    char[] UserChar = "luminji".ToCharArray();
                    foreach (char ch in UserChar)
                    {
                        SendChar(item, ch, 100);
                    }
                }
            }
            SendMessage(hwnd_button, WM_CLICK, mainWnd, "0");
        }

        public void SendChar(IntPtr hand, char ch, int SleepTime)
        {
            PostMessage(hand, WM_CHAR, ch, 0);
            System.Threading.Thread.Sleep(SleepTime);
        }

        public static int WM_CHAR = 0x102;
        public static int WM_CLICK = 0x00F5;

        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);  

        [DllImport("user32.dll")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,
            string lpszClass, string lpszWindow);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll")]
        public static extern int AnyPopup();

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        [DllImport("user32.dll")]
        public static extern int EnumThreadWindows(IntPtr dwThreadId, CallBack lpfn, int lParam);

        [DllImport("user32.dll")]
        public static extern int EnumChildWindows(IntPtr hWndParent, CallBack lpfn, int lParam);

        [DllImport("user32.dll", CharSet = CharSet.Ansi)]
        public static extern IntPtr PostMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);

        [DllImport("user32.dll", CharSet = CharSet.Ansi)]
        public static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
       
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr SendMessageA(IntPtr hwnd, int wMsg, int wParam, int lParam);
       
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
       
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int GetWindowTextLength(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern IntPtr GetParent(IntPtr hWnd);
      
        public delegate bool CallBack(IntPtr hwnd, int lParam);

運行效果:

2:難點:如何獲取指定的控件句柄

  細心的人可能已經(jīng)發(fā)現(xiàn),上文中,給文本框賦值的地方,使用了如下代碼:

            foreach (IntPtr item in listWnd)
            {
                if (item != hwnd_button)
                {
                    char[] UserChar = "luminji".ToCharArray();
                    foreach (char ch in UserChar)
                    {
                        SendChar(item, ch, 100);
                    }
                }
            }

  假設我們的窗體上有多個文本框,那么事實上,這段代碼會給所有的文本框輸入"luminji”字樣。這在多數(shù)應用程序中都是不允許的,我們需要精確定位需要控制的控件。

  我們在得到OK按鈕的句柄的時候,使用了函數(shù):

IntPtr hwnd_button = FindWindowEx(mainWnd, new IntPtr(0), null, "OK");

  而想要獲取文本框句柄的時候,這個函數(shù)卻不能使用,因為,所有文本框都是沒有標題的,也就是類似"OK"這個值。有人說,那就使用控件ID吧。且看:

2.1:獲取控件ID

  非.NET程序,一旦程序被生成,控件ID就是固定的,所以這一招,用在非.NET程序中,那是再好也不過了。

   

  根據(jù)ID來得到控件句柄的函數(shù)聲明如下:

        [DllImport("user32.dll ", EntryPoint = "GetDlgItem")]
        public static extern IntPtr GetDlgItem( IntPtr hParent, int nIDParentItem); 

  其中,第一個參數(shù)就是窗體的句柄,第二個參數(shù)就是控件ID。

  但是,顯然,這種方法不適用于我們的.NET程序,因為我們會發(fā)現(xiàn),我們的.NET程序沒運行一次,這個ID是變化的。

2.2:獲取控件位置

  所以,最終的一個方案是:根據(jù)控件位置,人工比對后得到我們想要的控件句柄。該函數(shù)的聲明如下:

   好了,現(xiàn)在的關(guān)鍵就是怎么取得這個控件的位置。我們在VS中查看,某個控件有X坐標和Y坐標,以上面程序的這個TextBox來說,其在VS中顯示的位置是“70,83”,但是而VS中顯示的,是不包含標題和邊框的坐標值。但是這個坐標值可以作為我們?nèi)斯け葘Φ膮⒖肌?nbsp;

   更精確的坐標值,我們寫代碼來實現(xiàn),如下:

            EnumChildWindows(mainWnd, new CallBack(delegate(IntPtr hwnd, int lParam)
            {
                listWnd.Add(hwnd);
                StringBuilder className = new StringBuilder(126);
                StringBuilder title = new StringBuilder(200);
                GetWindowText(hwnd, title, 200);
                RECT clientRect;
                GetClientRect(hwnd, out clientRect);
                int controlWidth = clientRect.Width;
                int controlHeight = clientRect.Height;
                int x = 0, y = 0;
                IntPtr parerntHandle = GetParent(hwnd);
                if (parerntHandle != IntPtr.Zero)
                {
                    GetWindowRect(hwnd, out clientRect);
                    RECT rect;
                    GetWindowRect(parerntHandle, out rect);
                    x = clientRect.X - rect.X;
                    y = clientRect.Y - rect.Y;
                    Debug.Print(x.ToString());
                    Debug.Print(y.ToString());
                }
                return true;
            }), 0);
    注意,上面代碼中的X和Y就是某個控件的精確的X和Y值,記錄下來,比對一下,我們就能得到精確的坐標值了。在上文的例子中,我們的文本框的坐標最終得到為“78,113”。
    有了這個坐標值,我們便知道這個控件的句柄,也就是hwnd是屬于哪個控件的了。

2.3:根據(jù)EnumChildWindows枚舉次序得到句柄

    如果你不想這么麻煩,還有一種簡單的方案,那就是利用EnumChildWindows的枚舉順序。要知道,在不同的機器上,EnumChildWindows枚舉一個窗體上子控件的順序是相同的,也就是說,如果有兩個文本框,它們在這臺機器上被枚舉的順序一個是2,一個是3,那么,它們在其它機器上被枚舉的順序,也是這個固定次序。通過比對,我們也能得到它們各自的句柄。當然,如果我們有了這些句柄,還有什么是不能做到的呢?

2.4:使用SPY++

    SPY++是微軟的一個工具,用戶獲取窗體上的ID或者類型或者句柄等信息。因為在我們的這個例子里,ID和句柄在每臺機器上都是不變的,所以這個工具對于我們來說,沒有多大的用處。但是,當你HACK別人的程序的時候,它會發(fā)揮一定作用。

   

參考:

1:http://book./info/vb/api/4076.html

2:http://dev./course/3_program/cshapo/csharpjs/20100714/441439.html

關(guān)鍵詞:操作  程序  調(diào)用  外部  

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多