在 Windows 系統上,可以透過操作視窗元件的 Handle ,自動的執行一系列的步驟,且不會像錄製滑鼠 / 鍵盤動作的方式,會受到當時畫面的干擾。
關鍵字
- hWnd:常見的 Handle 變數名稱,h 代表 Handle,Wnd 表示 Window,意思為 Handle of Windows。
參考:Definition of Window Handle
用 C# 操作 Handle
1. 使用 Spy++ 或其它工具,找到特定視窗和元件的 Class 和 Caption。
2. 使用 FindWindow API 找到視窗的 Handle,這些 Handle 其實為視窗元件在記憶體中的指標,因此會以 IntPtr 的方式呈現。FindWindow()
可以用於找視窗的 Handle,FindWindowEx()
則可以根據找到的 Handle 尋找子元件的 Handle。
3. FindWindow()
/ FindWindowEx()
皆可用於找特定 Class 或(和)特定 Caption (Title) 的視窗。
4. 可使用 SendMessage()
輸入內容至編輯器內。如果要輸入按鍵訊號 (如鍵盤快捷鍵,Ctrl+C 等組合鍵) 的話,應使用 PostMessage()。以下程式碼參考自:C# Win32 API FindWindow/ FindWindowEx/SendMessage – Neil(After Work)
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
static extern int SendMessage(IntPtr hWnd, int msg, int wParam, StringBuilder lParam);
const int WM_SETTEXT = 0x000C;
static void Main(string[] args)
{
IntPtr MainWnd = FindWindow("Notepad", null);
IntPtr ChildWnd = FindWindowEx(MainWnd, IntPtr.Zero, "Edit", "");
StringBuilder InsStr = new StringBuilder();
InsStr.Append("ABCDEFGHIJK565465465");
SendMessage(ChildWnd, WM_SETTEXT, 0, InsStr);
}
5. 要送出按鍵訊號,可透過 PostMessage()
,按鍵代碼可參考 Microsoft Docs 提供的特殊按鍵列表 。以下程式碼參考自:handle - SendMessage Return Key and Text to WindowHandle in C# - Stack Overflow
[DllImport("User32.Dll")]
public static extern Int32 PostMessage(IntPtr hWnd, int msg, int wParam, int lParam);
const int WM_KEYDOWN = 0x0100;
const int VK_TAB = 0x09;
PostMessage(process.MainWindowHandle, WM_KEYDOWN, VK_TAB, 1);
6. 特殊按鍵列表:Virtual-Key Codes - Win32 apps - Microsoft Docs
7. 若 Spy++ 的 Class 內容顯示如 “#32770 (Dialog)” 的編號內容,可以直接輸入”#32770”即可。參考自:Findwindow does NOT find “#32770 (Dialog)” class window
8. 同樣使用 PostMessage()
送出滑鼠按鈕的訊號,座標的位置使用位元運算設定:
int x=58;
int y=32;
PostMessage(this.Handle, WM_LBUTTONDOWN, 0, (x & 0xFFFF) + (y & 0xFFFF) * 0x10000);
PostMessage(this.Handle, WM_LBUTTONUP, 0, (x & 0xFFFF) + (y & 0xFFFF) * 0x10000);
PostMessage(this.Handle, WM_LBUTTONDOWN, 0, x + (y<<16));
PostMessage(this.Handle, WM_LBUTTONUP, 0, x+(y<<16));
程式碼參考自:c# 调用win32模拟点击的两种方法 - li-peng - 博客园