启动器是一个 Tkinter 窗体程序。隐藏器是一个独立的 PowerShell 进程。启动器负责发现影刀环境、登录账号、提交任务和退出清理。隐藏器负责按固定条件隐藏影刀窗口,并在启动器退出后恢复窗口。一、启动客户端时,启动器设置两个显示开关开发者调用 subprocess.Popen 启动 ShadowBot.exe 时,启动器把 creationflags 设为
详细介绍
启动器是一个 Tkinter 窗体程序。隐藏器是一个独立的 PowerShell 进程。启动器负责发现影刀环境、登录账号、提交任务和退出清理。隐藏器负责按固定条件隐藏影刀窗口,并在启动器退出后恢复窗口。
一、启动客户端时,启动器设置两个显示开关
开发者调用 subprocess.Popen 启动 ShadowBot.exe 时,启动器把 creationflags 设为 CREATE_NO_WINDOW,把 startupinfo.wShowWindow 设为 SW_HIDE。
第一个开关阻止 Windows 创建控制台窗口。第二个开关告诉 Windows 用隐藏状态显示程序主窗口。启动器在 hidden_startupinfo() 里构造这个启动参数,在 ensure_client() 里使用它:
D:\J盘-杂料\业务资料\RPA项目资料\网站RPA应用市场\成品系统\影刀应用解码+打包+脱机运行\yingdao_run_hider\yingdao_launcher.py:261

二、启动器用进程快照判断影刀是否在运行
开发者调用 process_running() 时,启动器用 CreateToolhelp32Snapshot 取得系统进程快照,再逐个比较 szExeFile。
启动器比较的目标名称是 ShadowBot.Shell.exe 和 ShadowBot.exe。启动器先把两个名称转成小写,再做完全匹配。代码没有解析 tasklist 的文本输出。
实现位置:yingdao_launcher.py:332
三、启动器先确认 CLI 能响应,再决定是否启动客户端
client_api_ready() 执行 shadowbot.shell-cli auth current。CLI 返回可解析的 JSON 后,启动器把本地接口视为可调用。
CLI 返回“没有启动”或 not running 时,启动器把接口视为不可调用。wait_for_api() 每 2 秒查询一次,最多等待 120 秒。
实现位置:yingdao_launcher.py:379
四、隐藏器用命名互斥量限制实例数量
隐藏器启动时创建命名互斥量 Local\ShadowBotWindowHiderV2,再调用 WaitOne(0) 抢锁。
第一个隐藏器拿到锁,开始隐藏窗口。第二个隐藏器拿不到锁,直接退出。Local\ 前缀把互斥量限制在当前登录会话内。
实现位置:D:\J盘-杂料\业务资料\RPA项目资料\网站RPA应用市场\成品系统\影刀应用解码+打包+脱机运行\yingdao_run_hider\hide_shadowbot_windows.ps1:2

五、隐藏器监听启动器进程
启动器把自身 PID 写入环境变量 SHADOWBOT_HIDER_PARENT_PID。隐藏器读取这个 PID,每秒执行一次 Process.GetProcessById。
父进程消失后,隐藏器跳出循环,执行窗口恢复,再释放互斥量。启动器被强制结束,隐藏器也会自行退出。
实现位置:hide_shadowbot_windows.ps1:94
六、隐藏器直接调用 Win32 窗口 API
隐藏器用 Add-Type 编译一段 C# 代码,声明 user32.dll 的 EnumWindows、GetWindowText、ShowWindow、IsWindow 等函数。
PowerShell 负责循环,C# 负责枚举顶层窗口和调用 Win32 API。
每轮循环里,隐藏器先跳过不可见窗口,再根据窗口句柄取得 PID,再根据 PID 取得进程名。进程名不在 ShadowBot、ShadowBot.Shell、ShadowBot.Bridge、ShadowBot.Explorer 里时,隐藏器不动这个窗口。
进程名匹配后,隐藏器读取窗口标题,只接受 影刀、影刀登录、RobotRunnerView 三个标题。隐藏器调用 ShowWindow(h, 0) 隐藏窗口,把句柄和标题写进 HiddenWindows 字典,并向日志追加一行记录。
隐藏器用这份白名单排除了应用弹窗。我用带 影刀对话框 的测试应用跑了一遍,日志没有记录这个标题,弹窗一直可见。
实现位置:hide_shadowbot_windows.ps1:24

七、退出时先停止隐藏器,再恢复窗口
启动器退出时,向 %TEMP%\shadowbot_window_hider.stop 写入内容。隐藏器每 50 毫秒检查一次这个文件,看到文件就退出循环。
隐藏器遍历 HiddenWindows。它先用 IsWindow 检查句柄,再核对窗口标题,最后调用 ShowWindow(h, 4) 恢复窗口。状态码 4 是 SW_SHOWNOACTIVATE,窗口显示出来,但不抢当前焦点。
启动器还调用 restore_visible_shadowbot_windows(),枚举标题为 影刀 或 影刀登录 的隐藏窗口,再调用 ShowWindow(h, 4)。这一步覆盖旧版隐藏器没有恢复逻辑的情况。
启动器把 app-run.auto-hide-robot-window 写成 false,启动时也复位一次。启动器不把自动隐藏状态留给下一次运行。
实现位置:yingdao_launcher.py:291、yingdao_launcher.py:1140、yingdao_launcher.py:1162
八、切换账号时,启动器重启影刀进程
ensure_login() 比较当前账号和目标账号。两个账号不同且用户填了密码时,启动器先清空应用列表,再调用 taskkill /F /T /IM ShadowBot.Shell.exe 和 taskkill /F /T /IM ShadowBot.exe。
启动器每 0.5 秒检查一次进程,最多等 20 秒。旧进程退出后,启动器隐藏启动新客户端,登录目标账号,再用 auth current 查一次实际登录用户名。
启动器用重启客户端的方式换会话。taskkill /F /T 会结束进程树,正在运行的任务会一起结束。
实现位置:yingdao_launcher.py:843
九、这个模块容易踩的坑
窗口标题是硬编码字符串。影刀新版本修改标题后,开发者要同步修改
ClientWindowTitles。
启动器用普通权限运行,影刀用管理员权限运行,Windows 会拒绝
taskkill。开发者要让两个进程使用相同权限级别。
隐藏器每隔 1 秒才检查一次父进程。父进程退出后,隐藏器最多再等约 1 秒才退出。
隐藏器只修改窗口显示状态,不结束影刀进程。启动器退出后,影刀后台仍在运行。
隐藏器在恢复前核对窗口标题。开发者在恢复前修改窗口标题,隐藏器会跳过这个句柄。
影刀客户端升级后,开发者要重新确认
ShadowBot.Shell.exe的窗口标题和进程名。
十、我实际试过的部分
我运行了一个带弹窗的应用,观察 14 秒。隐藏器日志记录了 RobotRunnerView 和 影刀,没有记录 影刀对话框。
我启动一个只活 2 秒的临时父进程,再启动隔离的隐藏器实例。父进程退出 2 秒后,隐藏器进程消失。
我执行退出调用链的测试,调用顺序是:停止隐藏器、销毁窗体、把自动隐藏写成 false、等待隐藏器退出、恢复窗口。
我还没在每台机器、每个影刀版本上做肉眼恢复验证。开发者改完这个模块后,先拿一个带弹窗的应用跑一遍,再关闭启动器看主窗口是否回来。
内容版权声明
内容链接:https://www.diezanrpa.com/jinengjiqiao/1410.html
内容标题:影刀RPA实现隐藏窗口执行指定应用与进程控制:给第一次读代码的人
当前文章由平台【超级管理员】原创文案写作,内容版权归当前平台所有,用户转载,请注意来源!
本文最后更新发布于【2026-10-20】,某些文章具有时效性,若有错误或已失效,请联系客服
争议处理:针对本文内容若有异义,亦可直接与【法律顾问:易兴俊,律师联系电话:13825799821】直接联系沟通

