using System; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Drawing; using System.Collections.Generic; using System.Linq; using System.Web.Script.Serialization; public class AutomationTool { #region Win32 API [DllImport("user32.dll")] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll")] private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); [DllImport("user32.dll")] private static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); [DllImport("user32.dll")] private static extern bool SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); [DllImport("user32.dll")] private static extern bool SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam); [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] private static extern IntPtr GetFocus(); [DllImport("user32.dll")] private static extern int EnumChildWindows(IntPtr hWnd, EnumWindowProc lpEnumFunc, IntPtr lParam); [DllImport("user32.dll")] private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll")] private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); [DllImport("user32.dll")] private static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); [DllImport("user32.dll")] private static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); [DllImport("user32.dll")] private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect); private const uint WM_KEYDOWN = 0x0100; private const uint WM_KEYUP = 0x0101; private const uint WM_KEYPRESS = 0x0102; private const uint WM_CHAR = 0x0102; private const uint WM_SETTEXT = 0x000C; private const uint WM_LBUTTONDOWN = 0x0201; private const uint WM_LBUTTONUP = 0x0202; private const uint WM_RBUTTONDOWN = 0x0204; private const uint WM_RBUTTONUP = 0x0205; private const uint WM_LBUTTONDBLCLK = 0x0203; private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam); private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); [StructLayout(LayoutKind.Sequential)] private struct RECT { public int Left; public int Top; public int Right; public int Bottom; } [StructLayout(LayoutKind.Sequential)] private struct POINT { public int X; public int Y; } [DllImport("user32.dll")] private static extern IntPtr GetParent(IntPtr hWnd); [DllImport("user32.dll")] private static extern IntPtr GetAncestor(IntPtr hwnd, int flags); private const int GA_ROOT = 2; // 添加工具栏相关的常量和结构体 private const uint TB_BUTTONCOUNT = 0x0418; private const uint TB_GETBUTTON = 0x0417; private const uint TB_GETBUTTONTEXT = 0x042D; private const uint TB_GETITEMRECT = 0x041D; [StructLayout(LayoutKind.Sequential)] private struct TBBUTTON { public int iBitmap; public int idCommand; public byte fsState; public byte fsStyle; public byte bReserved1; public byte bReserved2; public IntPtr dwData; public IntPtr iString; } // 添加 SendMessage 重载 [DllImport("user32.dll")] private static extern bool SendMessage(IntPtr hWnd, uint Msg, int wParam, ref TBBUTTON lParam); [DllImport("user32.dll")] private static extern bool SendMessage(IntPtr hWnd, uint Msg, int wParam, ref RECT lParam); [DllImport("user32.dll")] private static extern uint MapVirtualKey(uint uCode, uint uMapType); [DllImport("user32.dll")] private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); #endregion public static void Main(string[] args) { if (args.Length == 0 || args[0] == "-h" || args[0] == "--help") { ShowHelp(); return; } try { List targetWindows = FindTargetWindows(args); if (targetWindows.Count == 0) { throw new Exception("未找到目标窗口"); } string type = GetArgumentValue(args, "-type"); IntPtr targetHandle = targetWindows[0]; // 总是使用第一个窗口 Dictionary operatedWindow = null; switch (type.ToLower()) { case "inspect": // inspect 操作只获取第一个匹配窗口的控件树 string filter = GetArgumentValue(args, "-filter"); bool background = bool.Parse(GetArgumentValue(args, "-background") ?? "false"); // 只在非后台操作时激活窗口 if (!background) { SetForegroundWindow(targetHandle); Thread.Sleep(50); } string treeJson = GetControlsTree(targetHandle, filter); if (!string.IsNullOrEmpty(treeJson)) { Console.WriteLine("[" + treeJson + "]"); } return; // 直接返回,不输出窗口信息 case "keyboard": operatedWindow = HandleKeyboardOperation(targetHandle, args); break; case "mouse": operatedWindow = HandleMouseOperation(targetHandle, args); break; default: throw new Exception("不支持的操作类型"); } // 输出操作的窗口信息 if (operatedWindow != null) { var serializer = new JavaScriptSerializer(); Console.WriteLine(serializer.Serialize(operatedWindow)); } } catch (Exception ex) { Console.Error.WriteLine(string.Format("Error: {0}", ex.Message)); } } private static List FindTargetWindows(string[] args) { List targetWindows = new List(); string method = GetArgumentValue(args, "-method") ?? "title"; string value = GetArgumentValue(args, "-window") ?? ""; // 如果是active方法,直接返回当前活动窗口 if (method.ToLower() == "active") { targetWindows.Add(GetForegroundWindow()); return targetWindows; } // 如果是handle方法,直接返回指定句柄 if (method.ToLower() == "handle") { targetWindows.Add(new IntPtr(long.Parse(value))); return targetWindows; } // 如果没有指定窗口值,返回空列表 if (string.IsNullOrEmpty(value)) { return targetWindows; } switch (method.ToLower()) { case "process": // 通过进程名查找 var processes = System.Diagnostics.Process.GetProcessesByName(value); foreach (var process in processes) { if (process.MainWindowHandle != IntPtr.Zero) { targetWindows.Add(process.MainWindowHandle); } } break; case "class": // 通过窗口类名查找 EnumWindows((hwnd, param) => { if (!IsWindowVisible(hwnd)) { return true; } StringBuilder className = new StringBuilder(256); GetClassName(hwnd, className, className.Capacity); string windowClassName = className.ToString(); if (windowClassName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { targetWindows.Add(hwnd); } return true; }, IntPtr.Zero); break; case "title": default: // 通过窗口标题查找(支持模糊匹配) EnumWindows((hwnd, param) => { StringBuilder title = new StringBuilder(256); GetWindowText(hwnd, title, title.Capacity); string windowTitle = title.ToString(); if (!string.IsNullOrEmpty(windowTitle) && windowTitle.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { targetWindows.Add(hwnd); } return true; }, IntPtr.Zero); break; } if (targetWindows.Count == 0) { Console.WriteLine(string.Format("Error: 未找到匹配的窗口 (method={0}, value={1})", method, value)); } return targetWindows; } private static Dictionary HandleKeyboardOperation(IntPtr targetHandle, string[] args) { string control = GetArgumentValue(args, "-control"); string action = GetArgumentValue(args, "-action"); string value = GetArgumentValue(args, "-value"); bool background = bool.Parse(GetArgumentValue(args, "-background") ?? "false"); // 如果指定了控件,递归查找控件句柄 IntPtr controlHandle = IntPtr.Zero; if (!string.IsNullOrEmpty(control)) { StringBuilder windowTitle = new StringBuilder(256); GetWindowText(targetHandle, windowTitle, windowTitle.Capacity); controlHandle = FindControl(targetHandle, control); if (controlHandle == IntPtr.Zero) { throw new Exception(string.Format("在窗口中未找到指定控件 (窗口句柄={0}, 标题=\"{1}\", 控件类名=\"{2}\")", targetHandle.ToInt64(), windowTitle.ToString(), control)); } targetHandle = controlHandle; } // 只在非后台操作时激活窗口 if (!background) { SetForegroundWindow(targetHandle); Thread.Sleep(50); } switch (action.ToLower()) { case "keys": if (string.IsNullOrEmpty(value)) { throw new Exception("发送按键需要指定 -value 参数"); } SendKeys(targetHandle, value); break; case "text": if (string.IsNullOrEmpty(value)) { throw new Exception("发送文本需要指定 -value 参数"); } SendText(targetHandle, value); break; default: throw new Exception("不支持的keyboard操作类型"); } // 返回操作结果 return GetBasicWindowInfo(targetHandle, controlHandle); } private static Dictionary HandleMouseOperation(IntPtr targetHandle, string[] args) { string control = GetArgumentValue(args, "-control"); string controlText = GetArgumentValue(args, "-text"); string action = GetArgumentValue(args, "-action"); string position = GetArgumentValue(args, "-pos"); bool background = bool.Parse(GetArgumentValue(args, "-background") ?? "false"); if (string.IsNullOrEmpty(action)) { throw new Exception("mouse操作需要指定 -action 参数"); } // 如果指定了控件类名和文本,查找匹配的控件 IntPtr controlHandle = IntPtr.Zero; if (!string.IsNullOrEmpty(control) || !string.IsNullOrEmpty(controlText)) { StringBuilder windowTitle = new StringBuilder(256); GetWindowText(targetHandle, windowTitle, windowTitle.Capacity); controlHandle = FindControlByTextAndClass(targetHandle, controlText, control); if (controlHandle == IntPtr.Zero) { throw new Exception(string.Format("在窗口中未找到指定控件 (窗口句柄={0}, 标题=\"{1}\", 控件类名=\"{2}\", 控件文本=\"{3}\")", targetHandle.ToInt64(), windowTitle.ToString(), control ?? "", controlText ?? "")); } targetHandle = controlHandle; } // 只在非后台操作时激活窗口 if (!background) { SetForegroundWindow(targetHandle); Thread.Sleep(50); } // 获取点击坐标 int x = 0, y = 0; if (!string.IsNullOrEmpty(position)) { // 使用指定坐标 string[] pos = position.Split(','); if (pos.Length == 2) { x = int.Parse(pos[0]); y = int.Parse(pos[1]); } } else { // 如果没有指定坐标,点击控件中心 RECT rect; if (GetWindowRect(targetHandle, out rect)) { x = (rect.Right - rect.Left) / 2; y = (rect.Bottom - rect.Top) / 2; } } int lParam = (y << 16) | (x & 0xFFFF); switch (action.ToLower()) { case "click": SendMessage(targetHandle, WM_LBUTTONDOWN, 0, lParam); SendMessage(targetHandle, WM_LBUTTONUP, 0, lParam); break; case "rightclick": SendMessage(targetHandle, WM_RBUTTONDOWN, 0, lParam); SendMessage(targetHandle, WM_RBUTTONUP, 0, lParam); break; case "doubleclick": SendMessage(targetHandle, WM_LBUTTONDOWN, 0, lParam); SendMessage(targetHandle, WM_LBUTTONUP, 0, lParam); SendMessage(targetHandle, WM_LBUTTONDBLCLK, 0, lParam); SendMessage(targetHandle, WM_LBUTTONUP, 0, lParam); break; default: Console.WriteLine("Error: 不支持的mouse操作类型"); break; } // 返回操作结果 return GetBasicWindowInfo(targetHandle, controlHandle); } private static void SendKeys(IntPtr hWnd, string keys) { // 解析按键组合 string[] keyArray = keys.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string keyCombo in keyArray) { string[] modifiers = keyCombo.Trim().Split('+'); List modifierKeys = new List(); byte mainKey = 0; // 处理每个按键 for (int i = 0; i < modifiers.Length; i++) { byte vKey = GetVirtualKeyCode(modifiers[i].Trim()); if (i < modifiers.Length - 1) { modifierKeys.Add(vKey); } else { mainKey = vKey; } } // 按下修饰键 foreach (byte modifier in modifierKeys) { PostMessage(hWnd, WM_KEYDOWN, modifier, 0); } // 发送主键字符 if (mainKey > 0) { PostMessage(hWnd, WM_CHAR, mainKey, 0); } // 释放修饰键 for (int i = modifierKeys.Count - 1; i >= 0; i--) { byte modifier = modifierKeys[i]; PostMessage(hWnd, WM_KEYUP, modifier, 0); } // 如果有多个按键组合,等待一下 if (keyArray.Length > 1) { Thread.Sleep(50); } } } private static bool IsSpecialKey(byte vKey) { switch (vKey) { // 修饰键 case 0xA0: // VK_LSHIFT case 0xA2: // VK_LCONTROL case 0xA4: // VK_LMENU case 0x5B: // VK_LWIN // 控制键 case 0x08: // VK_BACK case 0x09: // VK_TAB case 0x0D: // VK_RETURN case 0x1B: // VK_ESCAPE case 0x20: // VK_SPACE case 0x2E: // VK_DELETE // 方向键 case 0x25: // VK_LEFT case 0x26: // VK_UP case 0x27: // VK_RIGHT case 0x28: // VK_DOWN // 导航键 case 0x24: // VK_HOME case 0x23: // VK_END case 0x21: // VK_PRIOR (PageUp) case 0x22: // VK_NEXT (PageDown) case 0x2D: // VK_INSERT // 功能键 case 0x70: // VK_F1 case 0x71: // VK_F2 case 0x72: // VK_F3 case 0x73: // VK_F4 case 0x74: // VK_F5 case 0x75: // VK_F6 case 0x76: // VK_F7 case 0x77: // VK_F8 case 0x78: // VK_F9 case 0x79: // VK_F10 case 0x7A: // VK_F11 case 0x7B: // VK_F12 // 其他常用键 case 0x14: // VK_CAPITAL case 0x90: // VK_NUMLOCK case 0x91: // VK_SCROLL case 0x2C: // VK_SNAPSHOT case 0x13: // VK_PAUSE return true; default: return false; } } private static void SendText(IntPtr hWnd, string text) { StringBuilder sb = new StringBuilder(text); SendMessage(hWnd, WM_SETTEXT, 0, sb); } private static string GetArgumentValue(string[] args, string key) { for (int i = 0; i < args.Length - 1; i++) { if (args[i].Equals(key, StringComparison.OrdinalIgnoreCase)) { return args[i + 1]; } } return null; } private static bool HasArgument(string[] args, string key) { return Array.Exists(args, arg => arg.Equals(key, StringComparison.OrdinalIgnoreCase)); } private static byte GetVirtualKeyCode(string key) { switch (key.ToLower()) { case "ctrl": case "^": return 0xA2; // VK_LCONTROL case "alt": return 0xA4; // VK_LMENU case "shift": return 0xA0; // VK_LSHIFT case "win": return 0x5B; // VK_LWIN case "enter": return 0x0D; case "tab": return 0x09; case "esc": return 0x1B; case "space": return 0x20; case "backspace": return 0x08; case "delete": return 0x2E; // 方向键 case "left": return 0x25; // VK_LEFT case "up": return 0x26; // VK_UP case "right": return 0x27; // VK_RIGHT case "down": return 0x28; // VK_DOWN // 导航键 case "home": return 0x24; // VK_HOME case "end": return 0x23; // VK_END case "pageup": return 0x21; // VK_PRIOR case "pagedown": return 0x22; // VK_NEXT case "insert": return 0x2D; // VK_INSERT // 功能键 case "f1": return 0x70; // VK_F1 case "f2": return 0x71; case "f3": return 0x72; case "f4": return 0x73; case "f5": return 0x74; case "f6": return 0x75; case "f7": return 0x76; case "f8": return 0x77; case "f9": return 0x78; case "f10": return 0x79; case "f11": return 0x7A; case "f12": return 0x7B; // 其他常用键 case "capslock": return 0x14; // VK_CAPITAL case "numlock": return 0x90; // VK_NUMLOCK case "scrolllock": return 0x91; // VK_SCROLL case "printscreen": return 0x2C; // VK_SNAPSHOT case "pause": return 0x13; // VK_PAUSE default: if (key.Length == 1) { return (byte)key.ToUpper()[0]; } throw new ArgumentException(string.Format("不支持的按键: {0}", key)); } } private static IntPtr FindControlRecursive(IntPtr parentHandle, string targetClassName) { if (string.IsNullOrEmpty(targetClassName)) return IntPtr.Zero; IntPtr foundHandle = IntPtr.Zero; List childHandles = new List(); // 枚举所有子窗口 EnumWindowProc childProc = new EnumWindowProc((handle, param) => { // 获取类名 StringBuilder classNameBuffer = new StringBuilder(256); GetClassName(handle, classNameBuffer, classNameBuffer.Capacity); // 检查是否匹配 if (classNameBuffer.ToString().Equals(targetClassName, StringComparison.OrdinalIgnoreCase)) { foundHandle = handle; return false; // 找到后停止枚举 } childHandles.Add(handle); return true; }); EnumChildWindows(parentHandle, childProc, IntPtr.Zero); // 如果在当前层级没找到,递归查找子窗口 if (foundHandle == IntPtr.Zero) { foreach (IntPtr childHandle in childHandles) { foundHandle = FindControlRecursive(childHandle, targetClassName); if (foundHandle != IntPtr.Zero) break; } } return foundHandle; } // 修改 HandleKeyboardOperation 和 HandleMouseOperation 中查找控件的部分 private static IntPtr FindControl(IntPtr parentHandle, string controlClass) { // 先尝试直接查找 IntPtr hControl = FindWindowEx(parentHandle, IntPtr.Zero, controlClass, null); if (hControl != IntPtr.Zero) return hControl; // 如果直接查找失败,进行递归查找 return FindControlRecursive(parentHandle, controlClass); } private static IntPtr FindControlByTextAndClass(IntPtr parentHandle, string controlText, string className) { if (string.IsNullOrEmpty(controlText) && string.IsNullOrEmpty(className)) return IntPtr.Zero; List matchedControls = new List(); Queue searchQueue = new Queue(); searchQueue.Enqueue(parentHandle); while (searchQueue.Count > 0) { IntPtr currentHandle = searchQueue.Dequeue(); List children = new List(); // 枚举当前层级的子窗口 EnumWindowProc childProc = new EnumWindowProc((handle, param) => { bool match = true; // 检查类名(如果指定) if (!string.IsNullOrEmpty(className)) { StringBuilder classNameBuffer = new StringBuilder(256); GetClassName(handle, classNameBuffer, classNameBuffer.Capacity); if (!className.Equals(classNameBuffer.ToString(), StringComparison.OrdinalIgnoreCase)) { match = false; } } // 检查控件文本(如果指定) if (match && !string.IsNullOrEmpty(controlText)) { StringBuilder textBuffer = new StringBuilder(256); GetWindowText(handle, textBuffer, textBuffer.Capacity); string windowText = textBuffer.ToString(); if (!windowText.Contains(controlText)) { match = false; } } // 检查控件是否可见 if (match && !IsWindowVisible(handle)) { match = false; } if (match) { matchedControls.Add(handle); } // 将子窗口加入搜索队列 children.Add(handle); return true; }); EnumChildWindows(currentHandle, childProc, IntPtr.Zero); // 将所有子窗口加入搜索队列 foreach (IntPtr child in children) { searchQueue.Enqueue(child); } } if (matchedControls.Count == 0) { return IntPtr.Zero; } else if (matchedControls.Count > 1) { Console.WriteLine("Warning: 找到多个匹配控件:"); foreach (IntPtr handle in matchedControls) { StringBuilder text = new StringBuilder(256); GetWindowText(handle, text, text.Capacity); StringBuilder classBuffer = new StringBuilder(256); GetClassName(handle, classBuffer, classBuffer.Capacity); Console.WriteLine(string.Format("0x{0:X} - Class: {1}, Text: {2}", handle.ToInt64(), classBuffer, text)); } } return matchedControls[0]; } private static void HandleInspectOperation(string[] args) { string filter = GetArgumentValue(args, "-filter"); bool background = bool.Parse(GetArgumentValue(args, "-background") ?? "false"); var targetWindows = FindTargetWindows(args); if (targetWindows.Count == 0) { return; } // 创建一个列表存储所有窗口的控件树数组 List allWindowTrees = new List(); foreach (IntPtr hWnd in targetWindows) { // 只在非后台操作时激活窗口 if (!background) { SetForegroundWindow(hWnd); Thread.Sleep(50); } // 获取当前窗口的控件树并添加到列表 // 注意:每个控件树已经是一个数组 string treeJson = GetControlsTree(hWnd, filter); if (!string.IsNullOrEmpty(treeJson) && treeJson != "{}") { // 将每个控件树作为一个数组元素添加 allWindowTrees.Add("[" + treeJson + "]"); } } // 将所有窗口的控件树数组合并成一个大数组 Console.WriteLine("[" + string.Join(",", allWindowTrees) + "]"); } private static string GetControlsTree(IntPtr parentHandle, string filter, int depth = 0) { if (parentHandle == IntPtr.Zero) return "{}"; StringBuilder json = new StringBuilder(); json.Append("{"); // 获取窗口信息 StringBuilder title = new StringBuilder(256); StringBuilder className = new StringBuilder(256); GetWindowText(parentHandle, title, title.Capacity); GetClassName(parentHandle, className, className.Capacity); // 获取窗口位置和大小 RECT windowRect; GetWindowRect(parentHandle, out windowRect); bool isVisible = IsWindowVisible(parentHandle); // 检查当前节点是否匹配过滤条件 bool matchFilter = true; if (!string.IsNullOrEmpty(filter)) { matchFilter = title.ToString().IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0 || className.ToString().IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0; } // 添加节点信息 - 将句柄改为十进制格式 json.AppendFormat( "\"handle\":\"{0}\",\"class\":\"{1}\",\"text\":\"{2}\",\"visible\":{3},\"location\":{{\"x\":{4},\"y\":{5},\"width\":{6},\"height\":{7}}},\"matched\":{8},\"children\":[", parentHandle.ToInt64(), // 直接使用十进制格式 className.ToString().Replace("\"", "\\\""), title.ToString().Replace("\"", "\\\""), isVisible.ToString().ToLower(), windowRect.Left, windowRect.Top, windowRect.Right - windowRect.Left, windowRect.Bottom - windowRect.Top, matchFilter.ToString().ToLower() ); // 递归获取子控件树 List childJsons = new List(); EnumChildWindows(parentHandle, (hwnd, param) => { string childJson = GetControlsTree(hwnd, filter, depth + 1); if (!string.IsNullOrEmpty(childJson) && childJson != "{}") { childJsons.Add(childJson); } return true; }, IntPtr.Zero); // 添加子节点JSON if (childJsons.Count > 0) { json.Append(string.Join(",", childJsons)); } json.Append("]}"); return json.ToString(); } private static void ShowHelp() { string help = @" Windows 界面自动化工具使用说明 ========================== 基本语法: sendmessage.exe -type <操作类型> [参数...] 操作类型: -------- 1. keyboard - 键盘操作 2. mouse - 鼠标操作 3. inspect - 获取控件树 通用参数: -------- -method 窗口查找方式(可选,默认title) 可选值: - title 窗口标题(支持模糊匹配) - handle 窗口句柄 - active 当前活动窗口 - process 进程名 - class 窗口类名(支持模糊匹配) -window 要查找的窗口值(根据method解释) -control 控件类名 -background 后台操作,不激活窗口,默认激活 键盘操作参数: ----------- -action 操作类型:keys(按键)或text(文本) -value 要发送的按键或文本内容 鼠标操作参数: ----------- -action 操作类型:click(单击)、doubleclick(双击)、rightclick(右键) -text 控件文本 -pos 点击坐标(x,y) 控件树参数: --------- -filter 过滤条件(控件类名或文本) 使用示例: -------- 1. 发送按键到指定窗口: sendmessage.exe -type keyboard -action keys -window ""记事本"" -value ""ctrl+a"" 2. 发送文本到指定控件: sendmessage.exe -type keyboard -action text -window ""记事本"" -control ""Edit"" -value ""Hello World"" 3. 点击指定控件: sendmessage.exe -type mouse -action click -window ""记事本"" -control ""Button"" -text ""确定"" 4. 后台发送文本: sendmessage.exe -type keyboard -action text -window ""记事本"" -value ""Hello"" -background 5. 获取窗口控件树: sendmessage.exe -type inspect -window ""记事本"" -filter ""button"" 6. 使用句柄查找窗口: sendmessage.exe -type keyboard -method handle -window ""0x12345"" -value ""Hello"" 7. 操作当前活动窗口: sendmessage.exe -type keyboard -method active -value ""ctrl+s"" 8. 通过进程名查找窗口: sendmessage.exe -type keyboard -method process -window ""notepad"" -value ""Hello"" 9. 通过窗口类名查找: sendmessage.exe -type keyboard -method class -window ""Chrome"" -value ""Hello"" # 会匹配 Chrome_WidgetWin_1 sendmessage.exe -type keyboard -method class -window ""Chrome_WidgetWin_1"" -value ""Hello"" # 精确匹配 返回值: ------ 1. 均为JSON格式 2. inspect操作返回控件树信息 3. 其他操作返回操作的控件信息及其所在窗口信息 4. 失败均抛出异常 注意事项: -------- 1. 窗口标题、类名支持模糊匹配,active方式可不提供window参数 2. 所有操作都只会处理第一个匹配的窗口 "; Console.WriteLine(help); } private static Dictionary GetBasicWindowInfo(IntPtr hwnd, IntPtr controlHandle = default(IntPtr)) { var info = new Dictionary(); // 获取窗口信息 StringBuilder title = new StringBuilder(256); StringBuilder className = new StringBuilder(256); GetWindowText(hwnd, title, title.Capacity); GetClassName(hwnd, className, className.Capacity); int processId = 0; GetWindowThreadProcessId(hwnd, out processId); string processName = ""; try { var process = System.Diagnostics.Process.GetProcessById(processId); processName = process.ProcessName; } catch { } // 窗口信息放在 window 键下 info["window"] = new Dictionary { { "handle", hwnd.ToInt64() }, { "title", title.ToString() }, { "class", className.ToString() }, { "process", processName } }; // 如果有控件信息,添加到顶层 if (controlHandle != IntPtr.Zero) { StringBuilder controlTitle = new StringBuilder(256); StringBuilder controlClassName = new StringBuilder(256); GetWindowText(controlHandle, controlTitle, controlTitle.Capacity); GetClassName(controlHandle, controlClassName, controlClassName.Capacity); info["handle"] = controlHandle.ToInt64(); info["title"] = controlTitle.ToString(); info["class"] = controlClassName.ToString(); } else { // 如果没有控件,设置为 null info["handle"] = null; info["title"] = null; info["class"] = null; } return info; } }