ARTICLE DETAIL

资讯详情

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

PDMS二次开发教程:从PML脚本到.NET管道工具实战

PDMS二次开发教程:从PML脚本到.NET管道工具实战 简介面向工厂设计工程师与开发者的PDMS二次开发教程系统讲解如何用PML扩展PDMS的设计、报告、界面及流程自动化能力适合已掌握基础建模、希望提升定制化效率的初中级用户。压缩包共59个文件、237KB以doc教程、cpp/cs源码、h头文件、pmlfrm窗体、pmlfnc函数及exe演示程序为主覆盖PML语法、PDMS12 dotNet接口、dars_MFC窗口、CsvFixer等示例并附UE语法高亮配置与培训PPT便于对照学习。已有2739人浏览学习。通过源码与文档可掌握变量、控制结构、对象属性访问、事件驱动等PML核心语法结合自动化布管、定制报表、扩展菜单、数据校验等实例快速建立PDMS二次开发的项目级落地思路。1. pdms二次开发教程从这条管道曲线说起拿到一个 pdms 二次开发教程先要搞清楚它到底能解决什么。你在 PDMS 里花三天建完的管道模型业主突然要一个带保温厚度的材料表或者设计院要求所有 2 寸以下管线必须用承插焊连接你不想一条条去点属性框核对。这些事靠鼠标点击做不完靠 PDMS 自带命令也做不干净唯一的出路就是把 PDMS 里面的数据「接」出来按你的规则跑一遍再写回去。这就是 pdms 二次开发的正事不是改软件界面而是让 PDMS 替我干活——批量改属性、批量出图、批量校验模型。这个方向适合三类人设计工程师想省掉重复劳动IT 人员要在 PDMS 和 ERP、材料系统之间打通数据还有做模板工具的人想把团队里的建模规范做成一键成品。本教程用一套完整链路来讲——先跑通最小的 PML 脚本再上 .NET 做独立工具最后给一套数据提取和管道工具的落地方案以及我用这几年踩出来的几十个坑。看完你就知道PDMS 二次开发没有你想的那么神秘但也不是网上那种「复制粘贴就跑」的段子。2. PML 脚本是 PDMS 二次开发的地基先跑通第一个工具2.1 为什么选 PML 而不是一上来就碰 .NETPDMS 二次开发主要有两条路PMLProgrammable Macro Language和 .NET API。你打开 PDMS 的命令行窗口输入show !!pml能直接看到语法对象树这套内嵌语言就是 PML。它和 PDMS 是同一个进程能直接操作当前打开的模型数据库适合写「寄生在 PDMS 里」的小工具。而 .NET API 是 PDMS 12.0 之后主推的接口需要编译成 dll 再注册调用适合写独立运行的批处理工具。我的经验是凡是设计人员自己用、需要在模型界面里交互的工具用 PML凡是数据量大、要定时跑、要对接外部系统的用 .NET。新手尤其不要跳过 PML 直接啃 .NET——PDMS 二次开发的核心是理解它的数据库对象模型Design 层、Element 层、属性 DB 的分布PML 让你能在界面上肉眼验证每一步操作的后果这个反馈回路比什么都重要。2.2 最小可运行脚本读出一个管道的等级和直径先写一个能当场看到效果的 PML 脚本。新建一个文本文件后缀改成.pml放进任意目录在 PDMS 命令窗口输入-- getpipeinfo.pml !pipe $!PIPEQSE !name !pipe.Name !spec !pipe.Spec !dia !pipe.Diameter !!pml $? !name | !spec | tostring(!dia)这段代码先说逻辑$!PIPEQSE是 PDMS 内置的查询命令运行后光标变成拾取状态你在模型里点一条管道!pipe就拿到了这条管道的对象引用。.Name取管道名.Spec取等级.Diameter取公称直径。最后一行!!pml $?是把结果写到 PDMS 命令行加tostring()是因为直径在 PML 里是实数型直接拼字符串会报类型不匹配。参数说明里有个关键点.Diameter返回的是模型的物理内径不是公称直径。如果设计用的是 2 寸 SCH40 管线模型里存的可能是 49.25mm 这种实际值你要显示 DN50 就得查等级库的 SKEY 再映射。很多新手第一次看到输出数字和自己预期不符直接在微信群里问为什么数据错了其实只是没搞清楚这个对象属性是物理值还是工程值。判断的方法很简单在 PDMS 里点开管道属性看「General」页显示的数值单位是 mm 还是英寸如果带单位说明底层是物理存储输出前要做单位转换。2.3 把脚本接上命令栏和自定义菜单脚本写好了不能每次都在命令窗口敲路径。PDMS 二次开发的标准做法是把工具挂到菜单。在 PDMS 安装目录的App文件夹下找pml子目录不同版本路径略有差异比如C:\AVEVA\PDMS\12.0\App\pml里面有一个pml.sys初始化文件追加一行do file !mypml/getpipeinfo.pml注意这里!mypml是 PML 的环境变量路径不一定指向你的脚本目录。我的做法是先用!!sys查看当前环境变量再把自己的脚本目录加进去!!mydir C:\pdms_dev\scripts $? newlayer !mydir do file !mydir/getpipeinfo.pml这段代码的逻辑是newlayer命令把!mydir登记到 PDMS 的文件搜索路径之后do file就能用环境变量名引用脚本。如果用绝对路径也行但项目之间迁移容易断路径用环境变量管理是血泪经验换来的规范。菜单挂载选择在pml.sys里、还要写menus子文件不同版本的挂法不太一样。PDMS 12.0 常见的是在pml.sys里加入自定义菜单初始化然后重开模块。如果你用的是较老的 11.6 或较新的 E3D初始化文件位置和菜单注册方式会有差别但do file和newlayer这两条命令逻辑是通用的。跑完脚本后去命令窗口敲getpipeinfo看能不能直接弹出提示。2.4 遍历模型对当前区域的所有管道统一改名每次点选一条管道效率太低真正干活的时候你得遍历。下面这段脚本展示了 PDMS 二次开发里最常用的模型遍历方法——从当前位置往下找所有 Pipe 元素逐个改名-- renamepipes.pml !sels $1 !ele !!new from !sels !pipe !ele.First( Pipe ) while !pipe !null do !oldname !pipe.Name !newname NEW_ !oldname !pipe.Name !newname !pipe !pipe.Next( Pipe ) endwhile这里$1是当前选中元素集合!!new from创建一个对象指针.First(Pipe)找第一个 Pipe 子元素.Next(Pipe)继续找下一个。循环里直接给.Name赋值就是最简单的批量改属性。注意这个循环只遍历指定类型不会碰下面的设备、支架分支。写法上 PML 的集合遍历不能像 C# 那样安全地边改边删所以要在循环里避开删除操作删元素必须另开一轮——这是 PML 对象模型的边界。3. .NET 接口开发把 PDMS 工具变成独立程序3.1 PML 的尽头是 .NET什么时候必须迁移PML 再强大也有绕不过去的墙处理 10 万级元素时脚本慢得让人想砸电脑没有正常的异常处理机制一个报错弹窗出来你都没法定位是哪一行想调用 Windows 的 WebService、读数据库、生成 Excel 报表PML 写起来像在泥地里骑自行车。这些场景就是 PDMS 二次开发里 .NET 接口的舞台。PDMS 从 12.0 开始提供了完整的 .NET API 程序集你可以在 Visual Studio 里引用来访问模型数据。我自己判断迁移的时机就三条数据量超过几万条、要做后台批处理、要和外部系统交换数据满足任何一条就果断转 .NET。另外 .NET 接口通过 COM 互操作访问 PDMS 的对象模型所以核心概念和 PML 一致——都是 Element、DB、Attribute 这套体系。学会了 PML 的遍历逻辑转到 .NET 只是换一层语法壳。3.2 用 C# 读取 Design 元素列表的完整示例新建一个 C# 控制台项目添加Aveva.Pdms.Database、Aveva.Pdms.Utilities、Aveva.ApplicationFramework等引用版本不同命名空间略有区别从 12.0 到 E3D 都有。下面是从当前 Design 模块的指定位置读取所有 Pipe 名称和规格的代码using System; using System.Collections.Generic; using Aveva.Pdms.Database; using Aveva.Pdms.Utilities; namespace PdmsDev { class Program { static void Main(string[] args) { DbElement current DbElement.CurrentElement; DbElement[] pipes current.GetElements(new DbType[] { DbType.Pipe }); Liststring output new Liststring(); foreach (DbElement pipe in pipes) { string name pipe.GetString(DbAttributeInstance.NAME); string spec pipe.GetString(DbAttributeInstance.ASPEC); output.Add(${name}|{spec}); } System.IO.File.WriteAllLines(C:\pdms_dev\output.txt, output); Console.WriteLine(Done: output.Count); } } }代码逻辑说清楚DbElement.CurrentElement拿当前模块的位置对象GetElements(DbType.Pipe)一次性取到该位置下属性的所有 Pipe 元素注意GetElements 是深层遍历会把子级所有层级的管道都带上来。GetString(DbAttributeInstance.NAME)按属性名取字符串值。管道等级属性在 PDMS 内部叫ASPEC不是SPEC——这是坑后面避坑章节还会专门讲。参数说明括号里的new DbType\[\]是类型过滤器只返回 Pipe如果不加返回的是全部子元素数据量大时内存吃紧。这个程序不依赖 PDMS 界面在命令行跑就行但要先启动 PDMS 并打开一个 Design 模块因为 .NET API 要连上数据库进程。3.3 搭建一个不依赖用户交互的批处理框架如果要写一个每周五晚上自动跑的材料统计工具.NET 最实用的架构是命令行入参 配置文件 日志输出。我不写入参而是推荐配置文件因为设计人员不熟悉命令行。下面是一个最小框架的示意// Program.cs 入口逻辑 static void Main(string[] args) { string configPath args.Length 0 ? args[0] : C:\pdms_dev\config.ini; var cfg LoadConfig(configPath); string modelPath cfg[ModelPath]; string outputFile cfg[OutputFile]; string[] pipeTypes cfg[PipeTypes].Split(|); try { var session PdmsSession.Connect(modelPath); var report GenerateReport(session, pipeTypes); System.IO.File.WriteAllText(outputFile, report); WriteLog($OK|{DateTime.Now}|{outputFile}); } catch (Exception ex) { WriteLog($FAIL|{DateTime.Now}|{ex.Message}); throw; } }这个框架的价值在于PDMS 二次开发里最容易翻车的就是「今天能用、明天不能跑」因为模块的打开状态、用户的登录权限、数据库连接对象没释放都可能导致随机失败。配置文件把连接路径、类型列表、输出位置和日志等级全抽出来排错的时候看一眼日志就知道卡在哪一步。异常处理里WriteLog写的是结构化文本——时间戳、状态、位置三字段这是我自己常用的平替日志方案不用额外引 NLog 之类的库。PdmsSession.Connect之类的方法名是示意性的不同版本 API 的启动方法不一样PDMS 12.0 通常要引Aveva.ApplicationFramework先启动框架服务再连数据库。不要在程序里直接 new 一个Database要通过框架的IDatabase服务来连——这是 .NET 接口稳定性的关键。3.4 对外提供的接口选择COM 与 .NET API 的取舍还有一个经常被问到的点「我家 PDMS 是 11.6 的老系统可以用 .NET 吗」答案是11.6 没有完整的 .NET API只能走 COM 接口把 PDMS 当 COM 服务器用C# 里通过Marshal.GetActiveObject(PDMS.Application)拿到进程对象再反射调用方法。这种写法功能上能做但速度慢、不稳定而且微软已经逐步收紧GetActiveObject的权限。我的建议很直接老系统优先用 PML 做界面内的工具真要做外部程序花点钱升级到 12.0 SP6 以上或者直接用 E3D省下后面排错的成本比什么都值。4. PDMS 二次开发避坑指南九个血泪经验4.1 属性名弄错SPEC 还是 ASPEC现象用 C# 的pipe.GetString(DbAttributeInstance.SPEC)去取等级运行不报错但返回的值一直是空字符串。原因PDMS 的数据库里管道等级有两个相关属性。SPEC是逻辑名不是所有元素都有很多时候你需要的实际存储属性叫ASPECA 开头是 Attribute 的缩写两者的取值逻辑不完全一样。用错属性名是 PDMS 二次开发里最低级也最浪费时间的错。解决调出 PDMS 的 Command Line 工具选中元素用Q ASPEC和Q SPEC各查一次看哪个返回了你想要的值再去代码里改属性名。任何时候不确定属性先用这个命令验证不要对着文档猜。4.2 遍历里的类型判断为什么把设备也算进去了现象用!ele.First(Pipe)遍历发现有些设备箱体也被改名了逻辑明明只处理了 Pipe 类型。原因PDMS 的Pipe类型是Equipment、Structure之外的管路元素但分支箱体在数据库中可能是PipeBranch而PipeBranch继承自Pipe的部分语义导致部分类型判断为真。PML 脚本里的First(Pipe)不会精确匹配它对类型是「兼容即算」的。解决遍历时加双重判断。!ele.TypeName PIPE这种用DbAttributeInstance.TYPE或者.TypeName比较不要只依赖First(Pipe)。在 .NET 里就直接用DbType.Pipe做显式过滤不写模糊匹配。4.3 属性改完不生效别忘记$P刷新现象脚本循环跑完屏幕上的模型属性没有任何变化但脚本再跑一遍读到的值又是新值。原因PDMS 的图形界面和数据库之间有缓存脚本直接改属性不一定立刻触发图形刷新尤其当改动涉及管道路径、等级这类参与计算的性质时刷新滞后是很隐蔽的。解决在批量操作结束后调用一次$P或者!!pml $P强制刷新当前视窗。要注意的是$P刷的是整个模块的视图数据量大的时候会很慢所以不要每个循环都调放在循环结束之后调一次。这个「改完不刷新」的坑在材料统计工具里最常见因为你看不到模型变化就以为代码写错了其实只是没触发刷新。4.4 脚本运行到一半弹窗卡死消息框阻塞现象脚本在循环里调用了一个弹窗函数然后 PDMS 界面失去响应连取消按钮都点不动。原因PML 的!!弹窗或者 .NET 里的MessageBox.Show在 PDMS 主线程上运行而循环还在执行界面消息泵被阻塞。PDMS 二次开发里有个约定——不要在遍历模型时弹窗。这是新手最容易犯的错因为调试的时候你想看每一步的值就把弹窗塞进了循环。解决调试时把输出写到文件而不是弹窗。在 .NET 里写一个DebugLog方法往文本追加在 PML 里用write命令写日志文件。等确认逻辑正确再删除日志不影响性能。如果一定要手动交互把信息收集到列表里循环结束后最后统一弹窗。4.5 开发环境中文路径的玄学问题现象代码放到D:\管道工具\材料统计\目录下一运行到读取模型文件就报文件不存在。原因PDMS 底层很多组件用的是旧编码体系对中文路径的兼容性就那样报错时可能不会明确说路径问题而是说数据库连接失败之类。很多翻车都是从这个细节开始的。解决整个开发工作根目录全部用英文不要有空格和中文。模型文件名如果是设计院发来的中文名先复制一份出来改名再操作。这个话题我不想多展开但这条我写进了团队规范救了很多次场。4.6 模型大、遍历慢要区分深层和浅层现象一个只有 50 根管道的区域遍历竟然跑了十几秒。原因GetElements没有加深度限制当当前元素是 Zone 时深层遍历会把它下面的分支、管嘴、支架、附件全部提出来体量瞬间膨胀。PDMS 的层级结构很深Zone → Pipe → Branch → Hanger 一层套一层浅层遍历能解决问题就别深层拉。解决.GetElements(DbType.Pipe)已经带了类型过滤但如果还慢可以先拿到子元素列表用.Subtype(DbType.Pipe)浅层拿一次再逐层往下。判断数据量级的方法很简单先.Count看看有多少条数量在一万以内直接拉超过一万就要按层拆。5. 数据提取与管道工具实战从模型里抓出你要的每一根管线5.1 核心建模理念PDMS 二次开发的数据本质是 DB做 PDMS 二次开发最容易被忽略的认知是PDMS 不是三维软件是一个带三维界面的数据库。你在屏幕上看到的每一条管道在数据库里是一个 Element 记录它的等级、保温厚度、连接方式全部是记录上的属性字段。所以一切工具的底层都是——定位元素、读属性、写属性这三个动作。PDMS 的元素定位方式有两种一种从界面选择进去拿对象如前面写的$!PIPEQSE另一种用 DBKEY 直接定位元素——cvxrootid(rootname, idroot, type)就是. NET 里从根 ID 拿元素的方式idroot是根节点标识type用来判断这是什么类型的对象。这个函数在材料统计、跨模块查找时非常有价值因为 DBKEY 是元素最稳定的身份证名字可以改DBKEY 不会变。5.2 最小可用的数据导出脚本把管道清单写成 CSV下面这段 PML 脚本解决的问题很实际把当前区域所有管道的名称、等级、公称直径、保温厚度导出一个 CSV给材料工程师用。-- export_pipe_list.pml !sels $1 !ele !!new from !sels !pipe !ele.First( Pipe ) !!file C:\pdms_dev\pipelist.csv !!writefile newfile !!file !!writefile.WriteLine( Name,Spec,DN,Insulation ) while !pipe !null do !spec !pipe.Spec !dia !pipe.Diameter !insu !pipe.GetProp( INSULATION ) !!writefile.WriteLine( !pipe.Name , !spec , tostring(!dia) , tostring(!insu) ) !pipe !pipe.Next( Pipe ) endwhile !!writefile.Close()逻辑说明newfile是 PML 里创建文件对象的命令WriteLine逐行写入。管道等级从.Spec取直径需要转成字符串保温厚度用GetProp(INSULATION)而不是.Insulation原因是 PML 没有预定义的 Insulation 属性对象必须用属性名去查这点和 .NET 的GetString是同一个套路。循环结束后务必Close()释放文件句柄。参数说明这个脚本里我故意没做单位转换。输出的直径是模型内径毫米值材料工程师拿这个数据做表格时会再处理。如果你想直接输出英制或公称直径就得自己写单位换算函数PDMS 的Convert命令可以做单位转换但要注意Convert会改变当前环境设置用完要恢复不然影响后续会话。5.3 管道工具的应用案例按连接方式批量修改支管等级网上热词里经常看到「pdms二次开发应用案例 pipelinetool」这类工具做的核心功能我拆开看就是「按规则批量改模型」。举一个最常见的设计规范要求所有承插焊连接的支管等级必须从 SCH40 降到 SCH10S。手工改几百个分支头会改到怀疑人生PML 脚本用管道对象模型能直接解决-- change_branch_spec.pml !branch !pipe.GetChildren( PipeBranch ) while !branch !null do !joint !branch.GetProp( JOINT ) if !joint SW then !branch.Spec SCH10S endif !branch !branch.Next( PipeBranch ) endwhile这段代码的关键是JOINT属性存的是连接方式编码——SW代表 Socket Weld承插焊不同项目设置的编码可能不同需要先查项目标准。改属性后同样记得$P刷新前端同事常吐槽后端把模型改了但界面没变化就是这个原因。这个工具的价值不在于代码长短而在于它展示了 PDMS 二次开发里最常见的一类模式——不是从零建模而是对既有模型做规则化修补。设计规范永远在变每次变更都靠人肉去点属性框不仅慢而且漏。写成脚本后一个「规范变更」从一周变成半小时这就是为什么设计院愿意投入二次开发的根本原因。6. 验证开发成果与进阶方向怎样确认你的工具是可靠的工具写完之后要经过一套验证流程才能交付。我自己的做法是三步第一步用已知模型做基准对比——打开一个已经统计过的区域跑你的脚本把输出和之前人工做的表格逐行比对完全一致才算过第一关第二步是边界测试——故意创建一个只有一根管道、空模型、或者包含非法等级数据的模型看程序会不会崩溃、会不会输出脏数据第三步是把工具放到真实项目里和一个资深的管道工程师一起「背靠背」他手工统计你机器跑批对比两边的差异。敏感场景里最常用的验证方法是「故意造一个坏数据」。PDMS 模型里经常有建立了一半的管道等级字段是空的直径是零跑循环的时候不会报错但结果很差。我一般在提取数据前先加一层合法性判断-- 过滤无效管道 if !pipe.IsValid() and !pipe.Diameter 0 then -- 进入正式处理流程 endifIsValid()检查元素对象是否还有效——PDMS 里删除的元素在后来的遍历里可能还会被引用这是 .NET 接口和 PML 都有的一个坑不加判断就会出现NullReferenceException的玄学崩溃。加了这层守卫之后工具交付后问题少了八成。进阶方向上我建议你从三个点继续深挖一是把数据提取做成定时任务对接材料管理系统让 PDMS 模型自动生成采购清单二是做模型规则校验在建模阶段实时拦截错误比如支管焊了不该焊的等级三是做 PML 和 .NET 的混合架构——界面交互用 PML重型计算走 .NET兼顾开发效率和运行速度。这些方向都有现成的第三方库可以借鉴但 PDMS 的版本差异太大没有一套代码通吃所有版本升级前一定要先跑回归测试。最后说一个我自己的习惯每次开发完一个工具我会把「它解决了什么问题、坑在哪里、给后来者的备注」写成一页纸的说明放在脚本同一目录下。这个习惯让我在半年后接到维护需求时不用重新考古自己的代码。PDMS 二次开发的技术边界其实很清晰但项目里的坑只有自己踩过才记得牢——希望我的这些经验能帮你在做管道工具和材料统计的这条路上少走一段弯路。本文还有配套的精品资源点击获取
返回列表