天天看點

C# - WinFrm應用程式MessageBox自動關閉小實驗

概述

在程式中MessageBox彈出的對話框,用于向使用者展示消息,這是一個模式視窗,可阻止應用程式中的其他操作,直到使用者将其關閉。但是有時候在自動化程式中,如果彈出對話框,程式将會中斷,等待人工的幹預,這是一個非常不好的互動體驗,如果程式能夠自動幫我們點選其中一個按鈕,讓對話框消失,該有多好。

原理

通過對話框的标題查找對話框,擷取對話框的句柄,然後對話框發送指令。

涉及知識點

  • MessageBox   顯示消息視窗(也稱為對話框)向使用者展示消息。這是一個模式視窗,可阻止應用程式中的其他操作,直到使用者将其關閉。System.Windows.Forms.MessageBox可包含通知并訓示使用者的文本、按鈕和符号。
  • Thread 建立和控制線程,設定其優先級并擷取其狀态。本例子主要建立一個線程,查找彈出的視窗。
  • WIN32 API 也就是Microsoft Windows 32位平台的應用程式程式設計接口。每一個服務,就是一個函數,用于和Windows進行互動。
  • MessageBoxButtons 是一個Enum,表示對話框上顯示哪些按鈕。
  • PostMessage 是Windows API(應用程式接口)中的一個常用函數,用于将一條消息放入到消息隊列中。消息隊列裡的消息通過調用GetMessage和PeekMessage取得。

程式運作效果

核心代碼

C# - WinFrm應用程式MessageBox自動關閉小實驗
C# - WinFrm應用程式MessageBox自動關閉小實驗
1 using System;
  2 using System.Collections.Generic;
  3 using System.Drawing;
  4 using System.Linq;
  5 using System.Runtime.InteropServices;
  6 using System.Text;
  7 using System.Threading;
  8 using System.Threading.Tasks;
  9 
 10 namespace MessageBoxTest
 11 {
 12     /// <summary>
 13     /// 作者:Alan.hsiang
 14     /// 日期:2018-04-18
 15     /// 描述:通過WinAPI進行查找視窗,并對視窗進行操作
 16     /// </summary>
 17     public class MessageBoxHelper
 18     {
 19         /// <summary>
 20         /// 查找視窗
 21         /// </summary>
 22         /// <param name="hwnd">視窗句柄</param>
 23         /// <param name="title">視窗标題</param>
 24         /// <returns></returns>
 25         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 26         static extern IntPtr FindWindow(IntPtr hwnd, string title);
 27 
 28         /// <summary>
 29         /// 移動視窗
 30         /// </summary>
 31         /// <param name="hwnd">視窗句柄</param>
 32         /// <param name="x">起始位置X</param>
 33         /// <param name="y">起始位置Y</param>
 34         /// <param name="nWidth">視窗寬度</param>
 35         /// <param name="nHeight">視窗高度</param>
 36         /// <param name="rePaint">是否重繪</param>
 37         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 38         static extern void MoveWindow(IntPtr hwnd, int x, int y, int nWidth, int nHeight, bool rePaint);
 39 
 40         /// <summary>
 41         /// 擷取視窗矩形
 42         /// </summary>
 43         /// <param name="hwnd">視窗句柄</param>
 44         /// <param name="rect"></param>
 45         /// <returns></returns>
 46         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 47         static extern bool GetWindowRect(IntPtr hwnd, out Rectangle rect);
 48 
 49         /// <summary>
 50         /// 向視窗發送資訊
 51         /// </summary>
 52         /// <param name="hwnd">視窗句柄</param>
 53         /// <param name="msg">資訊</param>
 54         /// <param name="wParam">高位元組</param>
 55         /// <param name="lParam">低位元組</param>
 56         /// <returns></returns>
 57         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 58         static extern int PostMessage(IntPtr hwnd, int msg, uint wParam, uint lParam);
 59 
 60         public const int WM_CLOSE = 0x10; //關閉指令
 61 
 62         public const int WM_KEYDOWN = 0x0100;//按下鍵
 63 
 64         public const int WM_KEYUP = 0x0101;//按鍵起來
 65 
 66         public const int VK_RETURN = 0x0D;//Enter鍵
 67 
 68         public static bool IsWorking = false;
 69 
 70         /// <summary>
 71         /// 對話框标題
 72         /// </summary>
 73         public static string[] titles = new string[4] { "請選擇", "提示", "錯誤", "警告" };
 74 
 75         /// <summary>
 76         /// 查找和移動視窗
 77         /// </summary>
 78         /// <param name="title">視窗标題</param>
 79         /// <param name="x">起始位置X</param>
 80         /// <param name="y">起始位置Y</param>
 81         public static void FindAndMoveWindow(string title, int x, int y)
 82         {
 83             Thread t = new Thread(() =>
 84             {
 85                 IntPtr msgBox = IntPtr.Zero;
 86                 while ((msgBox = FindWindow(IntPtr.Zero, title)) == IntPtr.Zero) ;
 87                 Rectangle r = new Rectangle();
 88                 GetWindowRect(msgBox, out r);
 89                 MoveWindow(msgBox, x, y, r.Width - r.X, r.Height - r.Y, true);
 90             });
 91             t.Start();
 92         }
 93 
 94         /// <summary>
 95         /// 查找和關閉視窗
 96         /// </summary>
 97         /// <param name="title">标題</param>
 98         private static void FindAndKillWindow(string title)
 99         {
100             IntPtr ptr = FindWindow(IntPtr.Zero, title);
101             if (ptr != IntPtr.Zero)
102             {
103                 int ret = PostMessage(ptr, WM_CLOSE, 0, 0);
104                 Thread.Sleep(1000);
105                 ptr = FindWindow(IntPtr.Zero, title);
106                 if (ptr != IntPtr.Zero)
107                 {
108                     PostMessage(ptr, WM_KEYDOWN, VK_RETURN, 0);
109                     PostMessage(ptr, WM_KEYUP, VK_RETURN, 0);
110                 }
111             }
112         }
113 
114         /// <summary>
115         /// 查找和關閉視窗
116         /// </summary>
117         public static void FindAndKillWindow()
118         {
119             Thread t = new Thread(() =>
120             {
121                 while (IsWorking)
122                 {
123                     //按标題查找
124                     foreach (string title in titles)
125                     {
126                         FindAndKillWindow(title);
127                     }
128                     Thread.Sleep(3000);
129                 }
130             });
131 
132             t.Start();
133         }
134     }
135 }      

View Code

原部落格位址:

C# - WinFrm應用程式MessageBox自動關閉小實驗