【向重複工作說不】c#之模擬滑鼠操作
一.寫在前面
作為一個人力資源工作者,會經常遇到填表、報表的事務,其實有時候就是重複再重複的點選滑鼠工作,特別是遇到一些複雜的客戶端程式、網頁程式,諸如用友客戶端、社保管理系統等等,就尤其讓人頭疼。正好這段時間做了很多這方面的工作,搜尋了不少的資料,為了轉化學習效果,記錄於此,溫故知新。
二.引用Windows API
c#模擬滑鼠操作,就必須和WindowsAPI打交道,通過引用它內部的幾個函式,從而實現在螢幕的指定位置單擊、雙擊,或者對指定的窗體(能夠獲得控制程式碼的)、控制元件進行相關控制操作。相關函式如下:
SetCursorPos
(設定滑鼠位置)mouse_event
(控制滑鼠動作)
FindWindow
(獲得視窗的控制程式碼)FindWindowEx
(獲得子視窗或控制元件的控制程式碼)
SetCursorPos設定滑鼠位置
//設定滑鼠位置
[DllImport("user32.dll")] //DllImpor針對非託管的。非託管指的是不利用.net 生成的DLL
//宣告一個外部實現方法SetCursorPos()
public static extern bool SetCursorPos(int X, int Y);
這裡定義宣告動態連結庫
user32.dll
作為靜態入口點。SetCursorPos
是這個動態連結庫裡面的內部方法,所以這裡不要試圖改變大小寫什麼的。這裡定義的方法使用extern
修飾符意味著該方法在 C# 程式碼外部實現。extern
修飾符的常見用法是在使用 Interop 服務調入非託管程式碼時與DllImport 特性一起使用。在這種情況下,還必須將方法宣告為static
。
mouse_event控制滑鼠動作
//控制滑鼠動作
[DllImport("user32.dll")]
public static extern void mouse_event(MouseEventFlag flags, int dx, int dy, uint data, UIntPtr extraInfo);
MouseEventFlag
繼承uint
(uint型為無符號32位整數,佔4個位元組,取值範圍在0~4,294,967,295之間。)的列舉,指代一組滑鼠動作標誌位集;
dx
指滑鼠沿x軸絕對位置或上次滑鼠事件位置產生以來移動的畫素數量;dy
指沿y軸的絕對位置或從上次滑鼠事件以來移動的畫素數量;
data
變數是指,如果flags
為MOUSE_WHEEL,則該變數指定滑鼠輪移動的數量。正值表明滑鼠輪向前轉動,即遠離使用者的方向;負值表明滑鼠輪向後轉動,即朝向使用者。一個輪擊定義為WHEEL_DELTA,即120。如果flags
不是MOUSE_WHEEL,則data
應為零;
extraInfo
指定與滑鼠事件相關的附加32位值,應用程式呼叫函式GetMessageExtraInfo來獲得此附加資訊。一般的情況下賦值IntPtr.Zero
(UIntPtr
用於表示指標或控制程式碼的特定型別(A platform-specific type that is used to represent a pointer or a handle.)它被設計成整數,其大小適用於特定平臺。它們主要用於本機資源,如視窗控制程式碼)
FindWindow獲得視窗的控制程式碼
//在視窗列表中尋找與指定條件相符的第一個視窗,並返回控制程式碼值。這個函式不能查詢子視窗。
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
lpClassName
是視窗的類名,lpWindowName
是視窗的標題。這兩個變數可以用Spy++軟體來獲得。
在搜尋的時候不一定兩者都知道,但至少要知道其中的一個(不知道的可以賦值null
)。有的視窗的標題是比較容易得到的,如"計算器",所以搜尋時應使用標題進行搜尋。但有的軟體的標題不是固定的,如"記事本",如果開啟的檔案不同,視窗標題也不同,這時使用視窗類搜尋就比較方便。如果找到了滿足條件的視窗,這個函式返回該視窗的控制程式碼,否則返回0。如果查詢子視窗需要用FindWindowEx
FindWindowEx獲得視窗或者控制元件的控制程式碼
//該函式獲得一個視窗的控制程式碼,該視窗的類名和視窗名與給定的字串相匹配。這個函式查詢子視窗,從排在給定的子視窗後面的下一個子視窗開始。在查詢時不區分大小寫。
[DllImport("user32.dll", EntryPoint = "FindWindowEx", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
hwndParent
,父視窗控制程式碼,如果hwndParent
為 0 ,則函式以桌面視窗為父視窗,查詢桌面視窗的所有子視窗。
hwndChildAfter
,子視窗控制程式碼,查詢從在Z序
中的下一個子視窗開始。子視窗必須為hwndParent
視窗的直接子視窗而非後代視窗。如果HwndChildAfter為NULL,查詢從hwndParent的第一個子視窗開始。如果hwndParent 和 hwndChildAfter同時為NULL,則函式查詢所有的頂層視窗及訊息視窗。
lpszClass
,視窗或控制元件類名;lpszWindow
,視窗或控制元件標題。如果該引數為 NULL,則為所有視窗全匹配。
三.應用
1 首先新建一個類-類名WindowApi
using System;
using System.Runtime.InteropServices;//需要引用,從而使相應的類或者方法來支援託管/非託管模組間的互相呼叫
namespace 模擬輸入
{
public static class WindowApi
{
#region 滑鼠操作
//首先定義一個列舉,其繼承uint。這樣可以直觀的體現滑鼠的各類動作。
//[Flags]位標誌屬性,從而使該列舉型別的例項可以儲存列舉列表中定義值的任意組合。可以用 與(&)、或(|)、異或(^)進行相應的運算。
[Flags]
public enum MouseEventFlag : uint //設定滑鼠動作的鍵值
{
Move = 0x0001, //發生移動
LeftDown = 0x0002, //滑鼠按下左鍵
LeftUp = 0x0004, //滑鼠鬆開左鍵
RightDown = 0x0008, //滑鼠按下右鍵
RightUp = 0x0010, //滑鼠鬆開右鍵
MiddleDown = 0x0020, //滑鼠按下中鍵
MiddleUp = 0x0040, //滑鼠鬆開中鍵
XDown = 0x0080,
XUp = 0x0100,
Wheel = 0x0800, //滑鼠輪被移動
VirtualDesk = 0x4000, //虛擬桌面
Absolute = 0x8000
}
//設定滑鼠位置
[DllImport("user32.dll")]
public static extern bool SetCursorPos(int X, int Y);
//設定滑鼠按鍵和動作
[DllImport("user32.dll")]
public static extern void mouse_event(MouseEventFlag flags, int dx, int dy, uint data, UIntPtr extraInfo);
//方法:滑鼠左鍵單擊操作:滑鼠左鍵按下和鬆開兩個事件的組合即一次單擊
public static void MouseLeftClickEvent(int dx, int dy, uint data)
{
SetCursorPos(dx, dy);
System.Threading.Thread.Sleep(2 * 1000);
mouse_event(MouseEventFlag.LeftDown|MouseEventFlag.LeftUp, dx, dy, data, UIntPtr.Zero);
}
//方法:滑鼠右鍵單擊操作:滑鼠右鍵鍵按下和鬆開兩個事件的組合即一次單擊
public static void MouseRightClickEvent(int dx, int dy, uint data)
{
SetCursorPos(dx, dy);
System.Threading.Thread.Sleep(2 * 1000);
mouse_event(MouseEventFlag.RightDown|MouseEventFlag.RigthtUp, dx, dy, data, UIntPtr.Zero);
}
#endregion
#region 控制程式碼函式
//獲得視窗的控制程式碼
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
//獲得子視窗、子控制元件的控制程式碼;需要提前知道父窗體的控制程式碼,以及視窗的類名或者標題名。
[DllImport("user32.dll", EntryPoint = "FindWindowEx", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
//該函式返回指定視窗的邊框矩形的尺寸。該尺寸以相對於螢幕座標左上角的螢幕座標給出
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hwnd, out NativeRECT rect);
#endregion
}
}
2 在WinForm中使用剛才新建的WindowApi
假如:有這麼一個程式,我們要進行這樣的操作“ 點選滑鼠到查詢文字框,輸入查詢關鍵字,點選查詢按鈕,獲得查詢的內容,然後在點選窗體上的列印按鈕,調出win系統的列印對話方塊(輸出PDF),輸入PDF的檔名,最後列印輸出。這樣的動作迴圈若干次。 ”因為無法獲得這個程式裡面
查詢文字框
控制元件的控制程式碼,我們就必須模擬滑鼠的操作,點中這個查詢框,然後用SendKeys.SendWait("待查詢關鍵字")
,傳送給定的內容,然後再用滑鼠點選這個查詢按鈕。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void BtnOutPut_Click(object sender, EventArgs e)
{
string str="查詢關鍵字";
Thread.Sleep(1000);
for (int i = 0; i < 10; i++)
{
str += i;
Clipboard.SetText(str);
WindowApi.MouseLeftClickEvent(800, 160, 0);//將滑鼠定位到文字框,假設文字框的中間位置的座標是800,160
//由於SendKeys.SendWait不能傳送中文字元,所以只能用複製貼上的方式折中。
SendKeys.SendWait("^A");//全選
SendKeys.SendWait("^V");//將剪貼簿的內容貼上。
Thread.Sleep(1000);
WindowApi.MouseLeftClickEvent(950, 160, 0);//將滑鼠點選查詢按鈕
WindowApi.MouseLeftClickEvent(1000, 300, 0);//將滑鼠點選列印按鈕
//根據控制程式碼找到列印窗體
IntPtr ptrTaskbar = WindowApi.FindWindow(null, "列印設定");
if (ptrTaskbar != IntPtr.Zero)
{
IntPtr ptrOKBtn = WindowApi.FindWindowEx(ptrTaskbar, IntPtr.Zero, "TButton", "確認");//找到列印窗體中的確定按鈕併傳送確認資訊。
WindowApi.GetWindowRect(ptrOKBtn, out WindowApi.NativeRECT rect);
this.textControlPos.Text = rect.bottom.ToString() + "--" + rect.left.ToString();
WindowApi.SetCursorPos(rect.left + 40, rect.bottom - 15);//將滑鼠定位到列印按鈕
//Thread.Sleep(1000);//delay 5m
WindowApi.mouse_event(WindowApi.MouseEventFlag.LeftDown, 0, 0, 0, UIntPtr.Zero);//單擊滑鼠左鍵
WindowApi.mouse_event(WindowApi.MouseEventFlag.LeftUp, 0, 0, 0, UIntPtr.Zero);//單擊滑鼠左鍵
Thread.Sleep(5000);
//定位列印輸出窗體
IntPtr ptrPrintOutputForm = WindowApi.FindWindow(null, "將列印輸出另存為");
IntPtr ptrPrintOutputForm_Edit = WindowApi.FindWindowEx(ptrPrintOutputForm, "Edit", true);//。
this.textControlPos.Text = ptrPrintOutputForm_Edit.ToString() + "----" + ptrPrintOutputForm.ToString();
WindowApi.SendMessage(ptrPrintOutputForm_Edit, 0x000C, null,str);//輸入另存為的檔名
IntPtr ptrPrintOutputForm_Save = WindowApi.FindWindowEx(ptrPrintOutputForm, IntPtr.Zero, "Button", "儲存(&S)");
WindowApi.SendMessage(ptrPrintOutputForm_Save, 0xF5, 0, 0);//儲存
}
else
{
MessageBox.Show("未能找到列印窗體");
}
str = "查詢關鍵字";
}
}
參考資料
C# 模擬滑鼠移動與點選
C# 系統應用之滑鼠模擬技術及自動操作滑鼠
C#應用WindowsApi實現查詢\列舉(FindWindow、EnumChildWindows)窗體控制元件,併傳送訊息。
c#裡FindWindow的用法
C#模擬滑鼠和鍵盤操作
相關文章
- c# Log 日誌 以及不列印重複LogC#
- 11.22 CW 模擬賽 T3.重複
- 前端模擬使用者的複製操作前端
- Selenium系列教程-07 使用Actions類模擬複雜操作
- 關於 Linux 中模擬滑鼠Linux
- dotnet X11 視窗之間傳送滑鼠訊息 模擬滑鼠輸入
- win10平板虛擬滑鼠怎麼設定_win10平板電腦觸控模擬滑鼠操作方法Win10
- 如何用python模擬點選進行重複話語?Python
- Qt 模擬滑鼠事件-在兩個按鈕之間切換QT事件
- java:模擬棧操作Java
- 12.3 實現模擬滑鼠錄製回放
- Python-模擬滑鼠鍵盤動作Python
- 【XInput】手柄模擬滑鼠運作之 .NET P/Invoke 和 UWP-API 方案XInputAPI
- ADB模擬手機操作
- C# Post 模擬表單提交C#
- C#專案—模擬考試C#
- 2020煤礦採煤機(掘進機)操作模擬考試及煤礦採煤機(掘進機)操作複審模擬考試
- C#模擬HTTP請求Post JSONC#HTTPJSON
- 你能用js模擬出右鍵的複製和貼上功能嗎?如果可以說下是如何操作的?如果不可以請說明下理由JS
- HTML網頁根據座標模擬滑鼠點選HTML網頁
- C# 批次刪除Excel中的重複行C#Excel
- [NOIP 2024 模擬2]陣列操作陣列
- 向HashSet插入自定義物件判斷是否重複物件
- 力扣之存在重複元素力扣
- LeetCode 存在重複元素之JavaScriptLeetCodeJavaScript
- [NOIP 2024 模擬2]矩陣學說矩陣
- 廢土朋克風模擬經營向《多洛可小鎮》創作準備工作分享
- c#刪除有序陣列中的重複項C#陣列
- win10資源管理器已停止工作不斷重複卡死怎麼辦Win10
- golang 模擬瀏覽器登入操作Golang瀏覽器
- win10虛擬機器切換滑鼠怎麼操作_win10虛擬機器內外滑鼠如何切換Win10虛擬機
- Java 中模擬 C# 的擴充套件方法JavaC#套件
- C#窗體--滑鼠事件C#事件
- C#黔驢技巧之去重(Distinct)C#
- noip模擬45[真是啥也不會]
- JavaScript碎片———函式閉包(模擬物件導向)JavaScript函式物件
- python–模組之os操作檔案模組Python
- Java使用程式碼模擬高併發操作Java