ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Aspen HYSYS 二次开发系列教程(2):COM 对象模型逐层拆解——两个 ProgID 入口不可混用

Aspen HYSYS 二次开发系列教程(2):COM 对象模型逐层拆解——两个 ProgID 入口不可混用

Aspen HYSYS 二次开发系列教程(2):COM 对象模型逐层拆解——两个 ProgID 入口不可混用

版本声明块

  • 软件:aspenONE V15(基线,同第 1 篇);文档现实:公开手册为 Customization Guide V7.3(2011-03),V8–V15 无公开更新版
  • 语言/环境:Python(pywin32) + VBA;未证实属性名一律标注"未证实"并给本机 dir() 自查步骤
  • 本文目标:把对象四层链从概念变成可导航的结构,说清两个 ProgID 的语义差异(铁律 2)

一句话结论:HYSYS COM 对象链是 Application → SimulationCase(一个 case 文档,经ActiveDocument或 ProgIDHYSYS.SimulationCase进入)→ Flowsheet → Operations/Streams 容器;两个 ProgID 语义不同——HYSYS.Application面向应用与文档生命周期,HYSYS.SimulationCase直接面向 case——混用会在多窗口/多 case 场景产生"操作对象挂错文档"的事故。

〇、本篇要解决的认知问题

  1. ActiveDocument和 ProgIDHYSYS.SimulationCase直连的区别是什么?
  2. Operations 与 Streams 两个容器的索引语义(Item(“Feed”))在什么情况下会拿不到对象?
  3. 多 case/多窗口场景下"当前文档"的判定规则是什么——脚本为什么会操作错文件?
  4. 对象生命周期:关闭 case 后引用还在吗?释放顺序有什么要求?
  5. 属性访问失败(Object doesn’t support this property)的排查路径是什么?

一、机制解析

1.1 四层链与两个入口(价值锚点:多窗口事故都源于把"当前活动"当"目标文档")

Application (ProgID: HYSYS.Application) ← 应用层:文档生命周期、可见性 │ ├─ ActiveDocument → SimulationCase ← 入口A:当前活动 case(受 GUI 焦点影响) │ └─ ProgID: HYSYS.SimulationCase ← 入口B:直接面向一个 case 实例 │ Flowsheet(稳态流程容器) ├─ Operations.Item("Feed") ← 单元操作集合(按名索引) └─ MaterialStreamFlowsheetStreams ← 流股集合(按名索引)

两个入口的语义差异:入口 A 的"ActiveDocument"是应用当前活动文档——GUI 里切换窗口会改变它;脚本若假设 ActiveDocument 就是目标 case,在多窗口场景会读写错对象。入口 B 直接绑定一个 case,不依赖 GUI 焦点——自动化服务必须用 B(或显式遍历 Application.Documents 找目标)。

1.2 Item() 索引失败的三种情形

现象根因
Item(“Feed”) 返回空/报错名称与 GUI 定义不一致(大小写、后缀)——以本机为准(铁律 7)
稳态脚本在动态 case 上取不到单元两模式可用单元不同(第 12 篇)
属性不存在该对象类不支持此属性——"未证实"属性名不可照搬旧文档

1.3 生命周期与释放顺序

经验法则:先取数据、后关 case;引用在 case 关闭后失效。脚本收尾顺序:读结果 → 保存(如需)→ Close/Exit。跨版本时 ProgID 不带版本号解析到"当前安装版本"——这既是便利也是风险(铁律 1:报告里写实际运行版本)。

二、完整代码与逐行剖析

2.1 显式绑定目标 case(避免 ActiveDocument 陷阱),可运行

importwin32com.client app=win32com.client.Dispatch("HYSYS.Application")# 应用层入口(铁律 3:位数一致)# ——多窗口安全写法:遍历文档找目标 case,不依赖 GUI 焦点——target=Nonefordocinapp.Documents:# Documents 集合(以本机为准)if"mycase"instr(getattr(doc,"FileName","")):target=doc;breakiftargetisNone:raiseSystemExit("target case not open — ActiveDocument fallback NOT safe here")stream=target.Flowsheet.MaterialStreamFlowsheetStreams.Item("Feed")# 名称以本机为准(铁律 7)print("T:",stream.Temperature.Value,"P:",stream.Pressure.Value)

逐行要点:Documents遍历与FileName匹配是"服务形态"的最小守卫;直接ActiveDocument只适合单窗口手动场景。

2.2 VBA 对照(官方一手路线的显式文档引用)

Sub BindCase() Dim app As Object, doc As Object Set app = GetObject(, "HYSYS.Application") ' 连接已运行实例;不存在则 CreateObject For Each doc In app.Documents ' 以本机集合名为准(未证实处自查) If InStr(doc.FileName, "mycase") > 0 Then Set target = doc: Exit For End If Next Debug.Print target.Flowsheet.MaterialStreamFlowsheetStreams.Item("Feed").Temperature.Value End Sub

2.3 属性自查方法(铁律 7 的可执行形态)

Python:print([a for a in dir(stream)]);VBA:用对象浏览器或CallByName试探。判定标准(练习用):对 “Feed” 流股列出 ≥10 个属性并确认 Temperature/Pressure 在列——凡不在列的属性名不得写进脚本。

三、常见报错与排查

  1. “Object doesn’t support this property or method”—— 根因:照搬旧文档属性名(V7.3 手册时代的名称在新版本可能不存在)或对象类不匹配(铁律 7)。解法:本机 dir() 自查;未证实处标注"以本机实测为准"。
  2. 多窗口读写错 case—— 现象:结果与 GUI 显示不一致。根因:ActiveDocument 随焦点变化(1.1)。解法:显式遍历 Documents 绑定目标;服务场景禁用 ActiveDocument。
  3. Item(“Feed”) 拿不到对象—— 根因:名称大小写或流股在另一 case。解法:先列容器成员再索引——把名字当契约管理(第 19 篇命名约定)。
  4. case 关闭后引用报错—— 现象:脚本后半段崩溃。根因:生命周期顺序错误(1.3)。解法:读结果→保存→Close;不要在 Close 后取值。

四、动手练习

  1. 显式绑定复现:开两个 case,用 2.1 脚本绑定目标。判定标准:输出与 GUI 一致且切换焦点后仍正确——这就是"服务形态"的最小验证。
  2. 属性清单自查:对 Feed 流股输出 dir() 全清单存档。判定标准:≥10 属性;凡本文示例用过的属性(Temperature、Pressure)在清单内;不在清单内的旧文档属性名全部标注"未证实"。
  3. 思考题(无标准答案):为什么 ProgID 不带版本号是双刃剑?验证要点清单:① 写出晚期绑定解析机制;② 说明报告版本与运行版本可能不一致的场景;③ 给出多版本共存时锁定版本的办法(对照 Aspen Plus 系列铁律 1)。

五、小结与下一篇预告

本篇确立两个 ProgID 入口的语义差异与显式绑定纪律,把"ActiveDocument 陷阱"钉死为多窗口事故根因。下一篇进入 VBA 环境启用与第一个宏——包括那个最容易被误认为 bug 的默认禁用状态(铁律 4)。


本篇认知问题回显(FAQ)

Q1:HYSYS COM 对象链的四层结构是什么?

A:Application(应用与文档生命周期)→ SimulationCase(一个 case 文档,经 ActiveDocument 或 ProgID HYSYS.SimulationCase 进入)→ Flowsheet → Operations/Streams 两个按名索引的容器。

Q2:HYSYS.Application 和 HYSYS.SimulationCase 两个 ProgID 的区别是什么?

A:HYSYS.Application 面向应用与文档生命周期(ActiveDocument 受 GUI 焦点影响),HYSYS.SimulationCase 直接绑定一个 case 实例——多窗口自动化必须用后者或显式遍历 Documents,混用会读写错文档(铁律 2)。

Q3:脚本为什么会在多窗口场景操作错文件?

A:ActiveDocument 是"当前活动文档",随 GUI 焦点变化;服务形态应显式遍历 Application.Documents 按 FileName 绑定目标 case,不依赖焦点。

Q4:Item(“Feed”) 拿不到对象的常见原因是什么?

A:名称与 GUI 定义不一致(大小写或后缀)、流股属于另一 case、或稳态脚本在动态 case 上取单元(两模式可用对象集不同)——先列容器成员再索引,把名称当契约管理。

Q5:HYSYS COM 对象的属性访问失败如何排查?

A:用本机 dir()(Python)或对象浏览器(VBA)枚举该对象支持的属性——凡不在清单内的旧文档属性名一律标注"未证实";V7.3 手册时代的属性名在 aspenONE V15 可能不存在。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进