這些天因為需求原因,要實現指定窗口的點擊操作。因為是萌新,所以我只能在度娘的幫助下,一步步實現這個簡單的功能。(使用API方法需引入System.Runtime.InteropServices命名空間)
(注1:該情景我已獲取了我需要操作窗口的句柄,如要自行獲取請使用Win32API下的FindWindow方法與FindWindowEx方法)
(注2:如果不想看我的試錯過程可以直接看3)
1.過程中繞了許多彎路
最開始是想通過Win32API下的mouse_event來實現鼠標的模擬點擊的操作,但用此方法需要先用SetForegroudWindow方法將窗口置頂,然后再使用mouse_event方法來進行點擊;這種操作並不是我理想中的效果。
這種方式是通過模擬前台鼠標點擊,先將所需操作的窗口置前,然后通過鼠標事件模擬點擊操作進行點擊。很遺憾,我使用這種方法並沒有執行成功,后來我了解到這種方法需要配合幾個其他的API方法使用。
using System.Runtime.InteropServices; private static int MOUSEEVENTF_MOVE = 0x0001; //移動鼠標 private static int MOUSEEVENTF_LEFTDOWN = 0x0002; //模擬鼠標左鍵按下 private static int MOUSEEVENTF_LEFTUP = 0x0004; //模擬鼠標左鍵抬起 private static int MOUSEEVENTF_RIGHTDOWN = 0x0008; //模擬鼠標右鍵按下 private static int MOUSEEVENTF_RIGHTUP = 0x0010; //模擬鼠標右鍵抬起 private static int MOUSEEVENTF_MIDDLEDOWN = 0x0020; //模擬鼠標中鍵按下 private static int MOUSEEVENTF_MIDDLEUP = 0x0040; //模擬鼠標中鍵抬起 private static int MOUSEEVENTF_ABSOLUTE = 0x8000; //標示是否采用絕對坐標 [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);//指定句柄窗口置前 [System.Runtime.InteropServices.DllImport("user32")] public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);//https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event 有參數詳解 SetForegroundWindow(new IntPtr(窗口句柄)); mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, x, y, 0, 0);
2.然后我便又接觸到SetCursorPos這個API方法、並在大佬博客知識海領悟出了MoveMouseToPoint、SetMouseRectangle、SetMouseAtCenterScreen等方法,繼而再次挑戰我的目標。
原理是先通過SetCursorPos設置鼠標光標的位置,然后通過MoveMouseToPoint移動鼠標到指定位置,再通過mouse_event進行點擊
其實這個點擊方式與第一種方法大同小異,無非是多了一個設置鼠標位置的過程,雖然這此完成了我所要的點擊效果,卻沒有達到我的真正的目的。
using System.Runtime.InteropServices; public class MouseClick { /// <summary> /// 引用user32.dll動態鏈接庫(windows api), /// 使用庫中定義 API:SetCursorPos /// </summary> [DllImport("user32.dll")] private static extern int SetCursorPos(int x, int y); /// <summary> /// 移動鼠標到指定的坐標點 /// </summary> /// <param name="p">移動的點位</param> public void MoveMouseToPoint(Point p) { SetCursorPos(p.X, p.Y); } /// <summary> /// 設置鼠標的移動范圍 /// </summary> /// <param name="rectangle">移動范圍的矩陣</param> public void SetMouseRectangle(Rectangle rectangle) { System.Windows.Forms.Cursor.Clip = rectangle; } /// <summary> /// 中心坐標x或y /// </summary> public static int loginx, loginy; /// <summary> /// 設置鼠標位於屏幕中心 /// </summary> public void SetMouseAtCenterScreen() { //當前屏幕的寬高 int winHeight = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height; int winWidth = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width; //設置鼠標的x,y位置 loginx = winWidth / 3 * 2; loginy = winHeight / 4 + 5; Point centerP = new Point(loginx, loginy); //移動鼠標 MoveMouseToPoint(centerP); } public const int MOUSEEVENTF_LEFTDOWN = 0x2;//左鍵按下 public const int MOUSEEVENTF_LEFTUP = 0x4;//左鍵彈起 public enum MouseEventFlags { Move = 0x0001, //移動鼠標 LeftDown = 0x0002,//模擬鼠標左鍵按下 LeftUp = 0x0004,//模擬鼠標左鍵抬起 RightDown = 0x0008,//鼠標右鍵按下 RightUp = 0x0010,//鼠標右鍵抬起 MiddleDown = 0x0020,//鼠標中鍵按下 MiddleUp = 0x0040,//中鍵抬起 Wheel = 0x0800, Absolute = 0x8000//標示是否采用絕對坐標 } /// <summary> /// 鼠標事件 /// </summary> /// <param name="dwFlags">鼠標操作指令</param> /// <param name="dx">操作點x</param> /// <param name="dy">操作點y</param> /// <param name="cButtons">參數1</param> /// <param name="dwExtraInfo">參數2</param> [DllImport("User32")] public extern static void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo); /// <summary> /// 鼠標左鍵點擊屏幕中心 /// </summary> public void MouseClick_CenterScree() { SetMouseAtCenterScreen(); mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, loginx, loginy, 0, 0); //mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, loginx, loginy, 0, 0);//點擊第二次 } }
3.經過這兩此的資料撈取代碼實驗,我發現mouse_event是不能達到我想要的效果的,於是我便把目光投向了一個新的API方法,那便是SendMessage(windows系統信息交互方法)。
SendMessage的執行原理是:將執行的操作消息發送到一個或多個窗口,函數方法調用指定窗口的窗口過程,執行窗口過程處理完成該操作消息,最后執行返回。
該函數方法原型是↓
LRESULT SendMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
屬於User32.dll中的函數方法。具體參數詳解請參照:SendMessage參數詳解
剛接觸這個函數方法,也沒有立刻解決指定模擬點擊的問題;因為SendMessage用法有許多,光是參數Msg就包含了許多種。SendMessage發送消息類型(Msg)
最后在不斷的度娘幫助下,完成了我想要的效果
(注:因為在此消息類型中,坐標y的值屬於高位,所以要左移16位變為高位數)
using System.Runtime.InteropServices public class Mouer_Click { [DllImport("user32.dll", EntryPoint = "SendMessageA")] public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); SendMessage(new IntPtr(窗口句柄), 0x201, IntPtr.Zero, new IntPtr(x + (y << 16))); SendMessage(new IntPtr(窗口句柄), 0x202, IntPtr.Zero, new IntPtr(x + (y << 16))); }
雖然過程非常的坎坷,但是最終還是實現了我想要的效果。非常開心與大家分享此次模擬點擊的經驗,希望學C#大家能在這篇隨筆的幫助下,不像我一樣,少走一些彎路,感謝您觀賞!
