@tanskong/office-assistant 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,57 +1,91 @@
1
- # Office Assistant
1
+ # Office Assistant - 智能办公助手
2
2
 
3
- AI-powered Office automation via MCP protocol.
3
+ 基于 MCP 协议的 AI 驱动 Office 自动化工具。
4
4
 
5
- ## Features
5
+ ## 功能特性
6
6
 
7
- - **RunPython**: Execute Python code to control Office applications freely
8
- - **Smart Workspace**: Desktop folder for safe file processing
9
- - **Full Office Suite**: Excel, Word, PowerPoint, Outlook, Visio, WPS, and more
10
- - **License Protection**: Machine-bound license activation
7
+ - **RunPython 主力工具**:自由执行 Python 代码控制 Office 应用程序
8
+ - **智能工作区**:桌面文件夹安全处理文件
9
+ - **全 Office 套件支持**:ExcelWordPowerPointOutlookVisioWPS
10
+ - **UI 自动化引擎**:基于 Windows UI Automation 框架的精准截图与控件操作
11
+ - **许可证保护**:机器绑定的许可证激活机制
11
12
 
12
- ## Installation
13
+ ## 安装
13
14
 
14
15
  ```bash
15
- npx @yourname/office-assistant
16
+ npx @tanskong/office-assistant
16
17
  ```
17
18
 
18
- ## Activation
19
+ ## 激活
19
20
 
20
- 1. Set environment variable:
21
+ 1. 设置环境变量:
21
22
  ```bash
22
23
  set OFFICE_ASSISTANT_LICENSE=OFFICE-ASSISTANT-XXXX-XXXX-XXXX-XXXX
23
24
  ```
24
25
 
25
- 2. Run activation:
26
+ 2. 运行激活:
26
27
  ```bash
27
- npx @yourname/office-assistant activate
28
+ npx @tanskong/office-assistant activate
28
29
  ```
29
30
 
30
- 3. Start the server:
31
+ 3. 启动服务:
31
32
  ```bash
32
- npx @yourname/office-assistant
33
+ npx @tanskong/office-assistant
33
34
  ```
34
35
 
35
- ## Disclaimer
36
+ ## 免责声明
36
37
 
37
- Please place files in `Desktop/智能办公区/数据` before processing.
38
- We are not responsible for data loss when operating on original file locations.
38
+ 请将需要处理的文件复制到 `桌面/智能办公区/数据` 文件夹后再进行操作。
39
+ 直接在原文件位置操作导致的数据丢失,本软件概不负责。
39
40
 
40
- ## Tools
41
+ ## 工具列表
41
42
 
42
- | Tool | Description |
43
- |------|-------------|
44
- | `run_python` | Execute Python code (PRIMARY TOOL) |
45
- | `available_apps` | List installed Office applications |
46
- | `launch_app` | Launch an Office application |
47
- | `quit_app` | Quit an Office application |
48
- | `open_file` | Open an Office file |
49
- | `save_file` | Save current document |
50
- | `screenshot` | Capture screenshot |
51
- | `download` | Download file from URL |
52
- | `speak` | Text-to-speech |
53
- | `demonstrate` | Run demonstration |
43
+ ### Office 控制工具
54
44
 
55
- ## License
45
+ | 工具 | 说明 |
46
+ |------|------|
47
+ | `run_python` | 执行 Python 代码(主力工具) |
48
+ | `available_apps` | 列出已安装的 Office 应用程序 |
49
+ | `launch_app` | 启动 Office 应用程序 |
50
+ | `quit_app` | 退出 Office 应用程序 |
51
+ | `open_file` | 打开 Office 文件 |
52
+ | `save_file` | 保存当前文档 |
56
53
 
57
- Commercial license required. See activation instructions above.
54
+ ### UIA 自动化工具
55
+
56
+ | 工具 | 说明 |
57
+ |------|------|
58
+ | `screenshot` | 精准截图(全屏/活动窗口/指定窗口) |
59
+ | `screenshot_element` | 截取指定 UI 元素的截图 |
60
+ | `find_ui_element` | 查找 UI 元素并返回属性信息 |
61
+ | `get_ui_tree` | 获取窗口的 UI 树结构 |
62
+ | `click_ui_element` | 点击指定 UI 元素 |
63
+ | `get_window_list` | 列出所有顶层窗口 |
64
+ | `activate_window` | 激活指定窗口 |
65
+
66
+ ### 系统工具
67
+
68
+ | 工具 | 说明 |
69
+ |------|------|
70
+ | `download` | 从 URL 下载文件 |
71
+ | `demonstrate` | 运行功能演示 |
72
+
73
+ ## 截图功能示例
74
+
75
+ ```python
76
+ # 截取全屏
77
+ screenshot()
78
+
79
+ # 截取活动窗口
80
+ screenshot('active')
81
+
82
+ # 截取指定窗口
83
+ screenshot('Excel')
84
+
85
+ # 截取 UI 元素
86
+ screenshot_element('Calculate', 'Button', 'Calculator')
87
+ ```
88
+
89
+ ## 许可证
90
+
91
+ 需要商业许可证。请参阅上方的激活说明。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanskong/office-assistant",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Office Assistant - AI-powered Office automation via MCP protocol with license protection",
5
5
  "main": "bin/office-assistant.js",
6
6
  "bin": {
package/requirements.txt CHANGED
@@ -2,3 +2,4 @@ fastmcp>=2.3.3
2
2
  pywin32>=310
3
3
  Pillow>=10.0.0
4
4
  psutil>=5.9.0
5
+ uiautomation>=2.0.29
package/src/officer.py CHANGED
@@ -6,6 +6,8 @@ import win32com.client
6
6
  import pythoncom
7
7
  from pathlib import Path
8
8
 
9
+ from uia_tools import UIATools
10
+
9
11
 
10
12
  class TheOfficer:
11
13
  def __init__(self):
@@ -31,6 +33,7 @@ class TheOfficer:
31
33
  self.ComObjects = {}
32
34
  self._printable = False
33
35
  self.Data = OfficerData()
36
+ self.UIA = UIATools()
34
37
 
35
38
  self.MicrosoftApplications = [
36
39
  'Word', 'Excel', 'PowerPoint',
@@ -265,7 +268,26 @@ class TheOfficer:
265
268
  os.makedirs(folder, exist_ok=True)
266
269
  return os.path.join(folder, file_name)
267
270
 
268
- def ScreenShot(self, save_path: str = None) -> str:
271
+ def ScreenShot(self, save_path: str = None, target: str = None) -> str:
272
+ """
273
+ 截取屏幕截图。
274
+
275
+ Args:
276
+ save_path: 保存路径,None 则自动生成
277
+ target: 截图目标,None=全屏, 'active'=活动窗口, 其他=指定窗口名称
278
+
279
+ Returns:
280
+ 截图文件路径
281
+ """
282
+ if self.UIA.available:
283
+ if target is None:
284
+ return self.UIA.screenshot_desktop(save_path)
285
+ elif target == 'active':
286
+ return self.UIA.screenshot_window(None, save_path)
287
+ else:
288
+ return self.UIA.screenshot_window(target, save_path)
289
+
290
+ # 降级到原有 GDI 截图(当 UIA 不可用时)
269
291
  import win32gui
270
292
  import win32ui
271
293
  import win32con
package/src/server.py CHANGED
@@ -11,6 +11,7 @@ We are not responsible for data loss when operating on original file locations.
11
11
 
12
12
  import sys
13
13
  import os
14
+ from io import StringIO
14
15
 
15
16
  from license_manager import verify_license
16
17
  verify_license()
@@ -184,27 +185,157 @@ def run_python(code: str, app_name: str = "Excel") -> dict:
184
185
  doc = _get_active_doc(app, app_name)
185
186
  globals_dict = _build_globals(app, doc, app_name)
186
187
 
188
+ # Capture stdout to return print output
189
+ old_stdout = sys.stdout
190
+ sys.stdout = buffer = StringIO()
191
+
187
192
  try:
188
193
  exec(code, globals_dict)
189
- return {"success": True}
194
+ output = buffer.getvalue()
195
+ sys.stdout = old_stdout
196
+ return {"success": True, "output": output or "(无输出)"}
190
197
  except Exception as e:
198
+ sys.stdout = old_stdout
191
199
  return {"success": False, "error": str(e)}
192
200
 
193
201
 
194
- # ========== System Tools ==========
202
+ # ========== UIA Tools ==========
195
203
 
196
204
  @mcp.tool()
197
- def screenshot(save_name: str = None) -> dict:
198
- """Capture a screenshot and save to the export folder."""
205
+ def screenshot(target: str = None, save_name: str = None) -> dict:
206
+ """
207
+ Capture a screenshot with UIA precision.
208
+
209
+ Args:
210
+ target: Screenshot target. None=full desktop, 'active'=active window, other=window name
211
+ save_name: Filename to save (auto-generated if None)
212
+
213
+ Examples:
214
+ screenshot() # Full desktop
215
+ screenshot('active') # Current active window
216
+ screenshot('Excel') # Window with name containing 'Excel'
217
+ """
218
+ try:
219
+ path = Officer.ScreenShot(save_name, target)
220
+ return {"success": True, "path": path}
221
+ except Exception as e:
222
+ return {"success": False, "error": str(e)}
223
+
224
+
225
+ @mcp.tool()
226
+ def screenshot_element(element_name: str, control_type: str = None,
227
+ parent_name: str = None, save_name: str = None) -> dict:
228
+ """
229
+ Capture screenshot of a specific UI element.
230
+
231
+ Args:
232
+ element_name: Name of the UI element
233
+ control_type: Control type, e.g., 'Button', 'Edit', 'Document'
234
+ parent_name: Parent window name to limit search scope
235
+ save_name: Filename to save
236
+
237
+ Examples:
238
+ screenshot_element('Calculate', 'Button', 'Calculator')
239
+ screenshot_element('Sheet1', 'TabItem', 'Excel')
240
+ """
199
241
  try:
200
- path = Officer.ScreenShot(save_name)
242
+ path = Officer.UIA.screenshot_element(element_name, control_type, parent_name, save_name)
201
243
  return {"success": True, "path": path}
202
- except ImportError as e:
203
- return {"success": False, "error": "缺少 Pillow 模块,请运行: pip install Pillow", "detail": str(e)}
204
244
  except Exception as e:
205
245
  return {"success": False, "error": str(e)}
206
246
 
207
247
 
248
+ @mcp.tool()
249
+ def find_ui_element(name: str, control_type: str = None,
250
+ parent_name: str = None) -> dict:
251
+ """
252
+ Find a UI element and return its properties.
253
+
254
+ Args:
255
+ name: Element name
256
+ control_type: Control type filter
257
+ parent_name: Parent window name
258
+
259
+ Returns:
260
+ Element properties including name, type, rect, automation_id
261
+ """
262
+ try:
263
+ element = Officer.UIA.find_element(name, control_type, parent_name)
264
+ if element is None:
265
+ return {"success": False, "error": f"Element not found: {name}"}
266
+ return {
267
+ "success": True,
268
+ "name": element.Name,
269
+ "type": element.ControlTypeName,
270
+ "automation_id": element.AutomationId,
271
+ "class_name": element.ClassName,
272
+ "rect": element.BoundingRectangle,
273
+ "enabled": element.IsEnabled,
274
+ "visible": not element.IsOffscreen
275
+ }
276
+ except Exception as e:
277
+ return {"success": False, "error": str(e)}
278
+
279
+
280
+ @mcp.tool()
281
+ def get_ui_tree(window_name: str = None, max_depth: int = 3) -> dict:
282
+ """
283
+ Get the UI automation tree of a window.
284
+
285
+ Args:
286
+ window_name: Window name, None for active window
287
+ max_depth: Maximum traversal depth
288
+
289
+ Returns:
290
+ Hierarchical tree structure of UI elements
291
+ """
292
+ try:
293
+ tree = Officer.UIA.get_element_tree(window_name, max_depth)
294
+ return {"success": True, "tree": tree}
295
+ except Exception as e:
296
+ return {"success": False, "error": str(e)}
297
+
298
+
299
+ @mcp.tool()
300
+ def click_ui_element(name: str, control_type: str = None,
301
+ parent_name: str = None) -> dict:
302
+ """
303
+ Click a UI element.
304
+
305
+ Args:
306
+ name: Element name
307
+ control_type: Control type
308
+ parent_name: Parent window name
309
+ """
310
+ try:
311
+ result = Officer.UIA.click_element(name, control_type, parent_name)
312
+ return {"success": result}
313
+ except Exception as e:
314
+ return {"success": False, "error": str(e)}
315
+
316
+
317
+ @mcp.tool()
318
+ def get_window_list() -> dict:
319
+ """List all top-level windows."""
320
+ try:
321
+ windows = Officer.UIA.get_window_list()
322
+ return {"success": True, "windows": windows}
323
+ except Exception as e:
324
+ return {"success": False, "error": str(e)}
325
+
326
+
327
+ @mcp.tool()
328
+ def activate_window(window_name: str) -> dict:
329
+ """Activate a window by name."""
330
+ try:
331
+ result = Officer.UIA.activate_window(window_name)
332
+ return {"success": result}
333
+ except Exception as e:
334
+ return {"success": False, "error": str(e)}
335
+
336
+
337
+ # ========== System Tools ==========
338
+
208
339
  @mcp.tool()
209
340
  def download(url: str, save_name: str = None) -> str:
210
341
  """Download a file from URL to the download folder."""
@@ -0,0 +1,366 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ UI Automation Tools for Office Assistant
4
+ ========================================
5
+ 基于 Windows UI Automation (UIA) 框架的自动化工具模块。
6
+ 提供精准截图、UI 元素探测、控件操作等功能。
7
+
8
+ 依赖: uiautomation >= 2.0
9
+ """
10
+
11
+ import os
12
+ import datetime
13
+ from typing import Optional, List, Dict, Any
14
+ from pathlib import Path
15
+
16
+ try:
17
+ import uiautomation as auto
18
+ except ImportError:
19
+ auto = None
20
+
21
+
22
+ class UIATools:
23
+ """UI Automation 工具封装类"""
24
+
25
+ def __init__(self):
26
+ self._uia_available = auto is not None
27
+
28
+ @property
29
+ def available(self) -> bool:
30
+ """检查 UIA 是否可用"""
31
+ return self._uia_available
32
+
33
+ def _ensure_available(self):
34
+ if not self._uia_available:
35
+ raise ImportError("uiautomation 模块未安装,请运行: pip install uiautomation")
36
+
37
+ def _get_save_path(self, file_name: str = None, subfolder: str = "导出") -> str:
38
+ """获取保存路径"""
39
+ workspace = Path.home() / "Desktop" / "智能办公区"
40
+ if not workspace.exists():
41
+ workspace = Path.home() / "OfficeMCP_Data"
42
+ folder = workspace / subfolder
43
+ folder.mkdir(parents=True, exist_ok=True)
44
+ if file_name is None:
45
+ now = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
46
+ file_name = f"screenshot_{now}.png"
47
+ return str(folder / file_name)
48
+
49
+ # ========== 截图功能 ==========
50
+
51
+ def screenshot_window(self, window_name: str = None, save_path: str = None) -> str:
52
+ """
53
+ 截取指定窗口的截图。
54
+
55
+ Args:
56
+ window_name: 窗口标题或名称,None 则截取活动窗口
57
+ save_path: 保存路径,None 则自动生成
58
+
59
+ Returns:
60
+ 截图文件的完整路径
61
+ """
62
+ self._ensure_available()
63
+
64
+ if window_name:
65
+ window = auto.WindowControl(searchDepth=1, Name=window_name)
66
+ if not window.Exists():
67
+ raise ValueError(f"未找到窗口: {window_name}")
68
+ else:
69
+ window = auto.GetForegroundControl()
70
+
71
+ if save_path is None:
72
+ save_path = self._get_save_path()
73
+ else:
74
+ save_path = self._get_save_path(save_path)
75
+
76
+ window.CaptureToImage(save_path)
77
+ return save_path
78
+
79
+ def screenshot_element(self, element_name: str, control_type: str = None,
80
+ parent_name: str = None, save_path: str = None) -> str:
81
+ """
82
+ 截取指定 UI 元素的截图。
83
+
84
+ Args:
85
+ element_name: 元素名称 (Name 属性)
86
+ control_type: 控件类型,如 'Button', 'Edit', 'Document' 等
87
+ parent_name: 父窗口名称,用于限定搜索范围
88
+ save_path: 保存路径
89
+
90
+ Returns:
91
+ 截图文件的完整路径
92
+ """
93
+ self._ensure_available()
94
+
95
+ element = self.find_element(element_name, control_type, parent_name)
96
+ if element is None:
97
+ raise ValueError(f"未找到元素: {element_name}")
98
+
99
+ if save_path is None:
100
+ save_path = self._get_save_path()
101
+ else:
102
+ save_path = self._get_save_path(save_path)
103
+
104
+ element.CaptureToImage(save_path)
105
+ return save_path
106
+
107
+ def screenshot_desktop(self, save_path: str = None) -> str:
108
+ """
109
+ 截取全屏截图(替代原有的 GDI 截图)。
110
+
111
+ Args:
112
+ save_path: 保存路径
113
+
114
+ Returns:
115
+ 截图文件的完整路径
116
+ """
117
+ self._ensure_available()
118
+
119
+ if save_path is None:
120
+ save_path = self._get_save_path()
121
+ else:
122
+ save_path = self._get_save_path(save_path)
123
+
124
+ desktop = auto.GetRootControl()
125
+ desktop.CaptureToImage(save_path)
126
+ return save_path
127
+
128
+ # ========== 元素查找功能 ==========
129
+
130
+ def find_element(self, name: str, control_type: str = None,
131
+ parent_name: str = None, timeout: int = 3):
132
+ """
133
+ 查找 UI 元素。
134
+
135
+ Args:
136
+ name: 元素名称
137
+ control_type: 控件类型
138
+ parent_name: 父窗口名称
139
+ timeout: 超时时间(秒)
140
+
141
+ Returns:
142
+ 找到的元素对象,未找到返回 None
143
+ """
144
+ self._ensure_available()
145
+
146
+ if parent_name:
147
+ parent = auto.WindowControl(searchDepth=1, Name=parent_name)
148
+ if not parent.Exists(timeout):
149
+ return None
150
+ scope = parent
151
+ else:
152
+ scope = auto.GetRootControl()
153
+
154
+ kwargs = {"Name": name, "searchDepth": 10}
155
+ if control_type:
156
+ kwargs["ControlType"] = getattr(auto.ControlType, control_type, 0)
157
+
158
+ element = scope.FindFirst(**kwargs)
159
+ return element
160
+
161
+ def find_elements(self, name: str = None, control_type: str = None,
162
+ parent_name: str = None, timeout: int = 3) -> List[Any]:
163
+ """
164
+ 查找多个匹配的 UI 元素。
165
+
166
+ Args:
167
+ name: 元素名称(支持部分匹配)
168
+ control_type: 控件类型
169
+ parent_name: 父窗口名称
170
+ timeout: 超时时间
171
+
172
+ Returns:
173
+ 元素列表
174
+ """
175
+ self._ensure_available()
176
+
177
+ if parent_name:
178
+ parent = auto.WindowControl(searchDepth=1, Name=parent_name)
179
+ if not parent.Exists(timeout):
180
+ return []
181
+ scope = parent
182
+ else:
183
+ scope = auto.GetRootControl()
184
+
185
+ kwargs = {"searchDepth": 10}
186
+ if name:
187
+ kwargs["Name"] = name
188
+ if control_type:
189
+ kwargs["ControlType"] = getattr(auto.ControlType, control_type, 0)
190
+
191
+ return scope.FindAll(**kwargs)
192
+
193
+ def get_element_tree(self, window_name: str = None, max_depth: int = 3) -> Dict:
194
+ """
195
+ 获取 UI 元素树结构。
196
+
197
+ Args:
198
+ window_name: 窗口名称,None 则获取当前活动窗口
199
+ max_depth: 最大遍历深度
200
+
201
+ Returns:
202
+ 树结构的字典表示
203
+ """
204
+ self._ensure_available()
205
+
206
+ if window_name:
207
+ root = auto.WindowControl(searchDepth=1, Name=window_name)
208
+ else:
209
+ root = auto.GetForegroundControl()
210
+
211
+ if not root.Exists():
212
+ return {}
213
+
214
+ def build_tree(control, depth: int) -> Dict:
215
+ if depth > max_depth:
216
+ return {"name": control.Name, "type": control.ControlTypeName, "truncated": True}
217
+
218
+ children = []
219
+ for child in control.GetChildren():
220
+ children.append(build_tree(child, depth + 1))
221
+
222
+ return {
223
+ "name": control.Name,
224
+ "type": control.ControlTypeName,
225
+ "automation_id": control.AutomationId,
226
+ "class_name": control.ClassName,
227
+ "rect": control.BoundingRectangle,
228
+ "children": children
229
+ }
230
+
231
+ return build_tree(root, 1)
232
+
233
+ # ========== 元素操作功能 ==========
234
+
235
+ def click_element(self, name: str, control_type: str = None,
236
+ parent_name: str = None) -> bool:
237
+ """
238
+ 点击指定元素。
239
+
240
+ Args:
241
+ name: 元素名称
242
+ control_type: 控件类型
243
+ parent_name: 父窗口名称
244
+
245
+ Returns:
246
+ 是否成功
247
+ """
248
+ self._ensure_available()
249
+
250
+ element = self.find_element(name, control_type, parent_name)
251
+ if element is None:
252
+ return False
253
+
254
+ element.Click()
255
+ return True
256
+
257
+ def send_keys_to_element(self, name: str, text: str,
258
+ control_type: str = "Edit",
259
+ parent_name: str = None) -> bool:
260
+ """
261
+ 向输入框发送文本。
262
+
263
+ Args:
264
+ name: 元素名称
265
+ text: 要发送的文本
266
+ control_type: 控件类型,默认 Edit
267
+ parent_name: 父窗口名称
268
+
269
+ Returns:
270
+ 是否成功
271
+ """
272
+ self._ensure_available()
273
+
274
+ element = self.find_element(name, control_type, parent_name)
275
+ if element is None:
276
+ return False
277
+
278
+ element.SendKeys(text)
279
+ return True
280
+
281
+ def get_element_text(self, name: str, control_type: str = None,
282
+ parent_name: str = None) -> str:
283
+ """
284
+ 获取元素的文本内容。
285
+
286
+ Args:
287
+ name: 元素名称
288
+ control_type: 控件类型
289
+ parent_name: 父窗口名称
290
+
291
+ Returns:
292
+ 文本内容
293
+ """
294
+ self._ensure_available()
295
+
296
+ element = self.find_element(name, control_type, parent_name)
297
+ if element is None:
298
+ return ""
299
+
300
+ return element.Name or ""
301
+
302
+ def wait_for_element(self, name: str, control_type: str = None,
303
+ parent_name: str = None, timeout: int = 10) -> bool:
304
+ """
305
+ 等待元素出现。
306
+
307
+ Args:
308
+ name: 元素名称
309
+ control_type: 控件类型
310
+ parent_name: 父窗口名称
311
+ timeout: 超时时间(秒)
312
+
313
+ Returns:
314
+ 是否找到
315
+ """
316
+ self._ensure_available()
317
+
318
+ element = self.find_element(name, control_type, parent_name)
319
+ if element is None:
320
+ return False
321
+ return element.Exists(timeout)
322
+
323
+ # ========== 窗口操作 ==========
324
+
325
+ def get_window_list(self) -> List[Dict[str, str]]:
326
+ """
327
+ 获取所有顶层窗口列表。
328
+
329
+ Returns:
330
+ 窗口信息列表
331
+ """
332
+ self._ensure_available()
333
+
334
+ windows = []
335
+ root = auto.GetRootControl()
336
+ for window in root.GetChildren():
337
+ if window.ControlType == auto.ControlType.WindowControl:
338
+ windows.append({
339
+ "name": window.Name,
340
+ "class": window.ClassName,
341
+ "handle": window.NativeWindowHandle,
342
+ "rect": window.BoundingRectangle
343
+ })
344
+ return windows
345
+
346
+ def activate_window(self, window_name: str) -> bool:
347
+ """
348
+ 激活指定窗口。
349
+
350
+ Args:
351
+ window_name: 窗口名称
352
+
353
+ Returns:
354
+ 是否成功
355
+ """
356
+ self._ensure_available()
357
+
358
+ window = auto.WindowControl(searchDepth=1, Name=window_name)
359
+ if window.Exists():
360
+ window.SwitchToThisWindow()
361
+ return True
362
+ return False
363
+
364
+
365
+ # 全局实例
366
+ UIA = UIATools()