C#-使用Win32_API的SendMessage實現指定窗口的模擬點擊操作


這些天因為需求原因,要實現指定窗口的點擊操作。因為是萌新,所以我只能在度娘的幫助下,一步步實現這個簡單的功能。(使用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);    
View Code

 

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);//點擊第二次
        }
}
View Code

 

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)));
}
View Code

 

雖然過程非常的坎坷,但是最終還是實現了我想要的效果。非常開心與大家分享此次模擬點擊的經驗,希望學C#大家能在這篇隨筆的幫助下,不像我一樣,少走一些彎路,感謝您觀賞!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM