ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

HTRI二次开发教程(05):Automation Server 探测(上)——本机注册表与类型库枚举

HTRI二次开发教程(05):Automation Server 探测(上)——本机注册表与类型库枚举 HTRI二次开发教程05Automation Server 探测上——本机注册表与类型库枚举版本与事实声明版本锚点当前Xchanger Suite 9.4Automation Server 是随软件安装的 OLE 自动化服务器无独立版本号。本系列不编造任何 ProgID/类名/方法名。官方对象模型文档位于会员门户https://www.htri.net/software-documentation对未登录访客返回权限墙公开渠道检索不到 ProgID 字符串因此本文只教如何在本机探测示例代码中的 ProgID 一律用...占位必须先探测再替换。文中所有数值均为示例性建模不代表任何标准规定。一句话结论HTRI Automation Server 的 ProgID、CLSID 与类型库Type Library信息没有公开文档唯一合法来源是本机探测——用注册表HKCR子串枚举找到候选 ProgID用 OLE/COM Object Viewer 确认其类型库再用 pywin32 的gencache.EnsureDispatch/makepy生成可自省的包装三步走完才允许写第一行业务调用。〇、本篇要解决的认知问题Q1为什么探测是 HTRI 自动化的第一步而不是找一份 API 文档Q2OLE 自动化服务器COM 组件在 Windows 注册表里留下了哪些痕迹Q3怎么用关键字枚举方法把可能属于 HTRI 的 ProgID 全找出来Q4OLE/COM Object Viewerobjcv和 pywin32 MakePy 各解决什么问题Q5探测结果怎么沉淀成探测清单成为后续所有代码里占位符的唯一替换来源一、机制解析1.1 为什么必须探测官方明确 Automation Server 是an application programming interface (API)“且easily accessed by external applications”并在 2014 年的 TechTip 里用 Visual Studio 2013 C# 演示了五动作打开案例、改输入、运行、取输出、保存。也就是说能力是官方背书的、形态是 OLE 的、但对外的名字不是公开的。这与流程模拟软件领域的经验一致有些产品如 Aspen Plus 的Apwn.Document、HYSYS 的HYSYS.Application的 ProgID 在公开渠道可查而 HTRI 的对象模型文档在会员门户内公开检索零命中。两个产品自动化开放度不同这不是缺陷是商业模式的选择。于是我们的方法学只有一条路探测。用三个标准 Windows 工程工具注册表、objcv、pywin32本机枚举类型库探测结果即合法标识符唯一来源。为什么这对你重要一旦你把抄来的 ProgID写进代码你得到的是一个**能运行但可能绑定了同族其它产品或某个旧版本**的隐患。探测虽慢一步却把风险降到零。1.2 OLE 注册的痕迹一个 OLE 自动化服务器要在 Windows 上可被外部程序创建至少在注册表里登记三类键位于HKEY_CLASSES_ROOT简称 HKCRProgID 键HKCR\ProgID人类可读的程序名通常形如Vendor.Product.ClassCLSID 映射HKCR\ProgID\CLSID→ 指向HKCR\CLSID\{GUID}类型库Type LibraryHKCR\TypeLib\{GUID}定义接口、方法、属性的元数据。因此探测策略是按供应商关键词子串枚举 ProgIDHTRI / Xchanger / Xist / Xace…→ 得到候选 ProgID顺着HKCR\ProgID\CLSID找到{GUID}→ 得到 CLSID在 objcv 里打开该类型库→ 看到方法/属性用 pywin32 MakePy 生成 Python 包装→ 得到可dir()自省的对象。1.3 三个工具的分工工具解决什么输出注册表reg / winreg发现存在哪些以 HTRI 命名的 COM 组件候选 ProgID、CLSID、TypeLib GUID 列表OLE/COM Object Viewerobjcv查看类型库的人类可读接口定义接口名、方法、属性、参数类型pywin32EnsureDispatch / MakePy生成 Python 侧包装供运行期dir()自省与调用win32com.gen_py下的包装模块最佳实践三者顺序使用——注册表撒网、objcv 定名、MakePy 落码。跳过任何一步都会让你在猜名字和报错重试之间反复横跳。1.4 探测清单占位符的唯一替换来源本系列所有涉及 Automation Server 的示例代码都写作ProgID本机枚举所得这类占位符。这些占位符只允许从探测清单里取真实值替换。清单至少含四列ProgID、CLSID、TypeLib GUID、候选产品/模块、探测时间。带时间戳很重要HTRI 升级如从 9.0 到 9.4可能改变注册项清单过期会导致以前能跑现在报错。1.5 探测的三个常见误区误区一把类型库与注册表当成一回事。注册表告诉你这个组件存在、它叫什么、它的 CLSID 是多少类型库文件告诉你这个组件的方法、属性、参数长什么样。前者是门牌号后者是户型图。只查注册表就写代码等于只看门牌号就搬家。误区二以为装了软件就一定有 Automation Server。官方确认 Automation Server 随 Xchanger Suite 安装但装了哪些模块、授权了哪些模块是两回事第 02 篇若本机只装了教育版仅 Xace/Xist/Xphe或根本没装探测自然无命中。无命中不是脚本 bug先确认安装与授权状态。误区三用后期绑定Dispatch做探测。后期绑定创建的对象只暴露动态派发接口dir()信息极少探测价值低。官方演示用 .NET强类型、早期绑定思路我们在 Python 侧对应的是gencache.EnsureDispatch——它会从类型库生成包装让你看到真实成员。一条纪律探测过程中不改注册表、不装/卸组件、不动系统设置。探测是只读侦察任何写操作都应由你明确决定并单独执行——本系列所有探测脚本都以KEY_READ打开、只写自己的输出文件。1.6 探测脚本工程化的四个要点要点一探测也分环境。探测脚本会在两类机器上跑开发机有 HTRI期待命中与CI/交付机可能没有 HTRI期待干净地未命中。因此探测脚本必须在无 HTRI 时优雅退出并给出解释而不是抛栈——本系列所有探测脚本都遵循这条。要点二显式记录探到了什么与没探到什么。一份有用的探测报告既列命中的 ProgID也列用哪些关键词扫过、还剩哪些未确认。只报喜不报忧的探测报告会让你在以为探测完了的错觉里继续猜。要点三探测产物要能带机迁移。probe_registry.json与object_tree.json是机器相关的不同安装、不同版本结果不同。因此它们不能盲目拷贝到另一台机器当结论——迁移的正确姿势是在新机重跑探测而不是复制旧清单。这一点在第 20 篇的平台入口守卫里被强制无清单则停止。要点四给探测结果加置信度。命中的每一条都该标明它是注册表确认 类型库确认高“还是仅关键词命中待甄别低”。低置信度的条目在编码前必须升级为高置信度否则和道听途说没有区别。二、完整代码与逐行剖析代码 5-1注册表子串枚举Python winreg可直接运行# -*- coding: utf-8 -*- probe_registry.py —— 用关键词子串枚举本机可能的 HTRI OLE 组件 用法python probe_registry.py 只读注册表不写任何键、不修改系统。 importwinregimportjsonimportdatetime# 供应/产品关键词子串匹配不区分大小写KEYWORDS[htri,xchanger,xist,xace,xphe,xace,xvib]defenum_hkcr_progids():列出 HKCR 下所有顶层键名即候选 ProgID 空间。names[]withwinreg.OpenKey(winreg.HKEY_CLASSES_ROOT,,0,winreg.KEY_READ)asroot:i0whileTrue:try:subwinreg.EnumKey(root,i)exceptOSError:breaknames.append(sub)i1returnnamesdefmatch_progids(all_names):hits[]fornameinall_names:lowname.lower()ifany(kinlowforkinKEYWORDS):hits.append(name)returnhitsdefget_clsid(progid):读取 HKCR\\ProgID\\CLSID 的值若存在。try:withwinreg.OpenKey(winreg.HKEY_CLASSES_ROOT,f{progid}\\CLSID,0,winreg.KEY_READ)ask:val,_winreg.QueryValueEx(k,)returnvalexceptOSError:returnNonedefmain():all_namesenum_hkcr_progids()hitssorted(set(match_progids(all_names)))print(fHKCR 顶层键总数{len(all_names)}关键词命中{len(hits)})rows[]forprogidinhits:clsidget_clsid(progid)kindProgIDifclsidelse其它可能只是类型/接口名print(f [{kind}]{progid}CLSID{clsid})ifclsid:rows.append({progid:progid,clsid:clsid,typelib_guid:,# objcv 中补齐candidate:,# 人工判断所属产品/模块probed_at:datetime.datetime.now().isoformat(timespecseconds),})ifrows:withopen(probe_registry.json,w,encodingutf-8)asf:json.dump(rows,f,ensure_asciiFalse,indent2)print(f\n已写出 probe_registry.json{len(rows)}条候选 ProgID)print(下一步用 OLE/COM Object Viewer 打开对应类型库补全 typelib_guid。)else:print(\n未命中。可能本机未装 Xchanger Suite、只装了客户端、或命名不含上述关键词。)print(请扩充 KEYWORDS 后重跑切勿凭记忆写入任何 ProgID。)if__name____main__:main()逐行剖析KEYWORDS故意含多个模块名xist/xace/xphe/xvib因为 Automation Server 可能按模块暴露多个 ProgID——多关键词撒网是提高命中率的关键。遍历方式用EnumKey 索引循环 OSError终止而不是先取子键数HKCR 巨大且动态变化枚举途中键数可能变化用异常终止法更稳。get_clsid包在 try 里并非每个含关键词的顶层键都有\CLSID子键有的是接口名、有的是无关词返回None时标记为其它而不是当候选 ProgID。只读打开KEY_READ探测脚本永不写注册表这是安全底线也符合不改系统的工程纪律。输出probe_registry.json时typelib_guid与candidate留空这两列由 objcv 与人工补齐——“机器做机器能做的人做人能做的”。无命中时不猜而是提示扩充关键词或确认是否安装——铁律 1 的直接体现。代码 5-2pywin32 MakePy 生成包装并自省占位 ProgID# -*- coding: utf-8 -*- makepy_probe.py —— 用 pywin32 生成 Automation Server 的 Python 包装并自省 用法python makepy_probe.py 【重要】PROGID 必须换成你代码 5-1 objcv 探测到的真实值此处为占位符。 importwin32com.clientaswc# 占位符必须替换为本机枚举所得的真实 ProgID PROGIDHTRIAutomationServer.ProgID本机枚举所得defmain():ifPROGID.startswith():print([停止] PROGID 仍是占位符。请先运行 probe_registry.py 并用 objcv 确认后替换。)print( 本系列不提供、也不允许使用任何未经探测的 ProgID 字符串。)return# EnsureDispatch优先使用 gencache 中的早期绑定包装没有则自动生成appwc.gencache.EnsureDispatch(PROGID)print(f已创建{PROGID})print(顶层成员前 80 个)fornameinsorted(dir(app))[:80]:print( name)# 早期绑定对象通常带有 _oleobj_/_comobj_ 等内部属性dir() 会一并列出# 业务代码只关心看起来像 API的成员不以 _ 开头。public[nfornindir(app)ifnotn.startswith(_)]print(f\n公开成员数{len(public)})print(提示把公开成员清单写入 probe_members.txt供第 06 篇测绘使用。)withopen(probe_members.txt,w,encodingutf-8)asf:f.write(\n.join(sorted(public)))print(已写出 probe_members.txt)if__name____main__:main()逐行剖析占位符守卫脚本开头先判断PROGID.startswith()是占位符就直接停止并打印纪律说明——把禁止用抄来的 ProgID做成可执行的护栏而不是一句注释。EnsureDispatch优先用gencache早期绑定而非Dispatch后期绑定早期绑定能让dir()看到类型库定义的方法/属性正是我们探测想要的后期绑定只能看到动态派发对象信息少。dir(app)过滤_前缀OLE 对象会带_oleobj_、_comobj_、_ApplyTypes_等内部成员混在输出里会干扰阅读——但不要删第 06 篇会解释它们是 pywin32 的运行期脚手架。写probe_members.txt落盘探测产物必须文件化才能进入版本管理与审计呼应第 10 篇的落盘纪律。全脚本不出现任何具体 ProgID 字符串铁律 1 在代码层的又一次落地。三、常见报错与排查报错 3-1pywintypes.com_error: (-2147221005, 无效的类字符串, ...)。现象EnsureDispatch(PROGID)报invalid class string。根因ProgID 字符串不存在——要么是占位符没换要么是抄来的名字在本机没有注册。解法确认已运行代码 5-1 且命中项非空用 objcv 的 “View TypeLib” 核对 ProgID 拼写绝不靠试错猜名字。报错 3-2EnsureDispatch成功但dir()几乎为空。现象对象建出来了却没几个成员。根因该 ProgID 走的是后期绑定无类型库信息或类型库未在gencache中生成。解法改用EnsureDispatch后再调用win32com.client.gencache.EnsureModule(typelib_guid, ...)或在 objcv 里确认类型库 GUID 后手动清理%TEMP%\gen_py缓存重试。注意清理 gen_py 缓存是常见修复手段但会丢失既有包装——先备份。报错 3-3注册表枚举命中一堆无关的键。现象xist这类关键词命中了非 HTRI 的组件。根因子串匹配天然会误伤。解法用CLSID子键是否存在 objcv 里类型库的作者/描述信息二次甄别把误报在candidate列标注非 HTRI并从候选集剔除。报错 3-4ImportError: No module named winreg极少数环境。现象Python 找不到 winreg。根因winreg 是 Windows 专属标准库在非 Windows 或裁剪的 Python 环境里不存在。解法确认运行环境是 Windows 上的 CPythonHTRI 是 Windows 桌面软件本系列全部在 Windows 上运行。报错 3-5探测清单过期升级后旧 ProgID 失效。现象以前能跑的脚本升级 Xchanger Suite 后报无效的类字符串。根因HTRI 升级可能改动注册项。解法把probed_at时间戳当契约的一部分每次升级后重跑代码 5-1更新清单与datadict.csv的real_identifier列。报错 3-6用Dispatch探测导致成员清单几乎为空。现象换了个创建方式dir()只剩几个内部成员。根因后期绑定不加载类型库。解法改用win32com.client.gencache.EnsureDispatch若仍为空按报错 3-2 处理 gen_py 缓存清理前先备份。四、动手练习练习 1撒网在装有 HTRI 的机器上运行代码 5-1。判定要么生成probe_registry.json且含 ≥1 条候选 ProgID要么明确说明未命中并列出你接下来扩充的关键词两种结果都算通过关键是没有编造。练习 2类型库确认用 OLE/COM Object Viewer 打开命中的组件补全probe_registry.json的typelib_guid列。判定至少 1 条记录的typelib_guid非空且格式为{XXXXXXXX-XXXX-...}。练习 3生成包装把探测到的真实 ProgID 换进代码 5-2 并运行。判定打印出公开成员清单并写出probe_members.txt若把 ProgID 换回占位符脚本应打印[停止]并退出——两态都要验证。练习 4红线自检全文搜索你的探测产物确认没有任何凭记忆写下的 ProgID。判定probe_registry.json每条记录都来自脚本枚举candidate列有依据objcv 类型库信息或官方文档。五、小结与下一篇预告本篇确立了 HTRI 自动化的方法学基石探测优先。我们讲清了 OLE 注册的三类痕迹ProgID / CLSID / TypeLib并用两段代码把注册表撒网与MakePy 自省落成操作产出probe_registry.json与probe_members.txt两份可审计的探测产物。请牢记铁律 1任何具体 ProgID/方法名的唯一合法来源就是本机探测结果。第 06 篇《Automation Server 探测下》我们要把一份成员清单升级为一棵完整的对象树——用 pywin32 包装递归遍历 case→panel→field 的层级导出 JSON 测绘报告并把这些测绘结果填进第 04 篇datadict.csv的real_identifier列。本篇认知问题回显FAQQ1为什么 HTRI 自动化第一步是探测而不是找 API 文档A因为 HTRI Automation Server 是官方背书的 OLE 自动化服务器官方 TechTip 用 Visual Studio 2013 C# 演示打开案例、改输入、运行、取输出、保存五动作但其 ProgID 与对象模型文档位于会员门户内https://www.htri.net/software-documentation对未登录访客返回权限墙公开渠道检索不到 ProgID。唯一可信来源是本机类型库探测猜出来的字符串照抄即报错。Q2OLE 自动化服务器在注册表里留下哪些痕迹A至少三类位于 HKCR一是 ProgID 键HKCR\ProgID人类可读程序名二是 CLSID 映射HKCR\ProgID\CLSID指向HKCR\CLSID\{GUID}三是类型库HKCR\TypeLib\{GUID}保存接口、方法与属性的元数据。探测即顺着这三类键走枚举 ProgID → 取 CLSID → 在 objcv 里读类型库。Q3怎么用关键字枚举找出可能属于 HTRI 的 ProgIDA遍历 HKCR 顶层键名对小写化后的键名做子串匹配关键词取 htri、xchanger、xist、xace、xphe、xvib 等多个命中项再检查是否存在\CLSID子键以区分真 ProgID与接口名/无关词。遍历用 EnumKey 索引循环 OSError 终止读注册表只用 KEY_READ全程不写系统。Q4objcv 与 pywin32 MakePy 各解决什么问题AOLE/COM Object Viewer 解决人类可读地查看类型库——看接口名、方法、属性与参数类型并给出类型库 GUIDpywin32gencache.EnsureDispatch或 makepy解决生成 Python 侧包装——得到可dir()自省的早期绑定对象并把成员清单落盘供后续测绘。三者分工注册表撒网、objcv 定名、MakePy 落码。Q5探测清单怎么成为占位符的唯一替换来源A探测清单至少含 ProgID、CLSID、TypeLib GUID、候选产品/模块、探测时间五列落成 JSON/CSV 纳入版本管理。本系列所有 Automation Server 示例的 ProgID 一律写作ProgID本机枚举所得占位符只允许用清单里的真实值替换清单带probed_at时间戳升级后可重跑探测更新避免过期标识符导致以前能跑现在报错。
返回列表