ARTICLE DETAIL

资讯详情

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

EPLAN API二次开发实战:从脚本到插件的电气图纸批处理指南

EPLAN API二次开发实战:从脚本到插件的电气图纸批处理指南 简介面向电气自动化设计及 EPLAN 二次开发人员这份 zip 压缩包8.72MB共 137 个文件是一套基于 EPLAN API 的插件工程实例。72 个 dll 为运行依赖与扩展组件22 个 cs 构成 C# 源码核心配合 xml、resx、resources、sln、csproj 等工程文件与项目文件可完整还原名为 EPLAN.EplAddin.JMC 的插件项目。工程覆盖电气项目建立与管理、窗体界面设计、绘图对象属性调整、自定义缩放逻辑等典型场景并涉及自动生成报告、批量修改项目、集成外部数据库等 EPLAN API 常用能力适合需要掌握插件开发流程或实现定制化工作流的工程师。image 与 bmp 资源用于界面图标suo、cache、pdb 记录了 Visual Studio 工程状态和调试配置项目还附带窗体设计器、图标等界面资源便于理清插件交互与工程组织的完整脉络。已有 370 人学习下载从源码结构到资源组织再到调试信息均能提供完整参考便于快速上手 EPLAN API 插件开发。1. EPLAN API 不是玄学电气图纸批处理这条路为什么不直接用鼠标当手里的EPLAN工程超过20页你一定经历过年底统查部件缺漏、给所有页面改标题栏、把设备清单导成Excel一套流程下来要点几百下鼠标。EPLAN API 就是把这套操作从“点鼠标”变成“跑代码”的出口开发者通过C#调用EPLAN暴露的接口能直接读取项目结构、页面、设备与部件数据也能反写属性和生成图纸。你下载到的很多压缩包资源——比如文件名带 eplanapi、eplan项目插件、EPLAN API.zip 的材料——本质都是别人封装好的这类能力真正动手时你会发现它并不要求你懂EPLAN内部实现只要会基础C#就能在几小时内做出一个批量改图工具。这篇文章按脚本、外部程序、插件三条路线展开给你一套能直接复现的最小实现和排错清单看完你就能决定自己的项目该走哪条路。2. 先分清三种EPLAN API开发方式脚本、外部程序、Add-In插件怎么选2.1 三个核心程序集DataModel、HEServices、ApplicationServer各管什么EPLAN从2.7开始把二次开发接口稳定在.NET平台上安装目录Bin文件夹里那一堆以Eplan开头的DLL就是API本体。第一次打开Bin文件夹的人通常会懵Eplan.EplApi.DataModel.dll、Eplan.EplApi.HEServices.dll、Eplan.EplApi.ApplicationServer.dll、Eplan.EplApi.Base.dll……到底引哪个我的判断标准是先看一句话分工表程序集运行位置核心类实际管什么Eplan.EplApi.DataModel进程内/外部进程均可Project、Page、Device、Function项目、页面、设备、功能的数据模型读写图纸数据的主入口Eplan.EplApi.HEServicesEPLAN进程内SelectionSet、CommandInterpreter、Command用户交互、当前选中对象、执行EPLAN内置命令Eplan.EplApi.ApplicationServer独立外部进程EplanApplication从外部启动或连接EPLAN独立EXE方案专用Eplan.EplApi.Base两边都用ScriptMethod、Properties、LockingService基础特性、属性对象、并发锁、枚举定义这里有个常见误解很多教程说“HEServices能做外部开发”其实不然。HEServices里的SelectionSet要依赖已经运行的EPLAN进程上下文你从一个独立的EXE里new SelectionSet()十有八九拿到的是空对象或直接抛COM异常。真正的外部开发入口是ApplicationServer它负责把EPLAN拉起来或者挂到已运行的EPLAN实例上然后DataModel才能正常工作。我一般这样选型只想给当前项目临时跑一遍逻辑用脚本要做定时任务或批量处理一堆项目且不想开着EPLAN图形界面用外部EXE要给团队做成常态化菜单工具才考虑Add-In插件。这三者的代码量是脚本小于EXE小于插件但可控性和分发便利性正好反过来提前想清楚能少走很多弯路。2.2 版本和.NET框架装的是EPLAN 2.9还是2022API怎么跟着变EPLAN API的程序集编译目标跟着主版本走。以常见部署环境为例EPLAN Electric P8 2.9时代Bin下的DLL基本面向.NET Framework 4.7.2/4.8用Visual Studio建.NET Framework类库就能引用到了2022、2023、2024这些版本部分新接口开始向.NET 6/8迁移官方会提供对应的SDK或NuGet包。但如果你拿不到官方SDK最稳妥的办法不是到处搜“EPLAN API.zip”而是直接在你已经安装的EPLAN目录里找C:\Program Files\EPLAN\Platform\版本号\Bin\Eplan.EplApi.*.dll直接引用本地DLLAPI版本和运行版本永远一致这是最不容易翻车的组合。指导思想一句话开发机、目标机、引用DLL三者版本保持同一主版本。你用2.9的DLL去连2022的EPLANConnect方法多半直接抛异常而且异常信息经常是含糊的“系统找不到指定的文件”排查起来相当痛苦。另外EPLAN的API程序集大多标记为强命名除了版本号还要注意公钥令牌。有的同事从某个下载包里拿了一套DLL放进去后发现和本机安装版本的强名称冲突最终还是要回归到“引用本机Bin目录”这条路。这也是为什么我强烈建议无论压缩包来源多靠谱第一件事是打开Bin目录核对DLL版本而不是先双击README。2.3 最小环境搭建从Bin目录引用DLL目标平台锁x64假设你用的是Visual Studio我建议的最小工程配置如下建一个.NET Framework控制台应用目标框架选net48如果你的EPLAN是2024之后的版本再按实际支持的框架调整然后添加引用浏览到EPLAN Bin目录选取DataModel、HEServices、Base三个DLL。生成配置里把平台目标明确设为x64不要用AnyCPU。EPLAN是纯64位进程AnyCPU在旧版.NET Framework下遇到非托管组件时会以x86优先级加载一运行就是BadImageFormatException。一个可以抄的csproj片段PropertyGroup OutputTypeExe/OutputType TargetFrameworknet48/TargetFramework PlatformTargetx64/PlatformTarget GenerateAssemblyInfofalse/GenerateAssemblyInfo /PropertyGroup ItemGroup Reference IncludeEplan.EplApi.Base HintPathC:\Program Files\EPLAN\Platform\2022.1.0\Bin\Eplan.EplApi.Base.dll/HintPath Privatefalse/Private /Reference Reference IncludeEplan.EplApi.DataModel HintPathC:\Program Files\EPLAN\Platform\2022.1.0\Bin\Eplan.EplApi.DataModel.dll/HintPath Privatefalse/Private /Reference /ItemGroup这里有两个关键点。第一HintPath里的版本号路径要改成你机器实际安装的目录不要照抄第二Private设为false也就是不把这几个DLL复制到输出目录。EPLAN的API程序集在加载时会走它自己的探测路径如果你把DLL复制到exe旁边反而容易出现两个副本打架的问题。调试时要么把EPLAN设为启动外部程序要么在EPLAN里打开项目后用Visual Studio的“附加到进程”直接调试脚本后者体验更好能直接看到异常断点落在哪一行。3. 30分钟跑通第一个EPLAN API脚本列出项目全部页面3.1 建脚本文件把EPLAN API当普通C#库引用EPLAN内置了脚本运行器菜单路径一般是“脚本”-“浏览”可以直接运行一个.cs文件。这种内部脚本的好处是省去进程管理代码在EPLAN进程内执行天然拥有当前项目上下文。EFLAN脚本的入口就是一个标了[ScriptMethod]特性的方法EPLAN会把方法名当作可执行入口列出来。我习惯把脚本存到固定目录比如D:\EPLAN_Scripts文件名用英文避免编码和路径问题。脚本文件顶部引用程序集时不需要Copy LocalEPLAN脚本引擎会自动到Bin目录解析。这里有个小技巧脚本里不要依赖外部NuGet包EPLAN脚本运行器对自定义依赖的支持很弱想用复杂库就老老实实转外部EXE。3.2 读取当前项目和页面最小可运行代码下面这段是完整可运行的最小脚本作用是列出当前EPLAN打开项目的所有页面并弹出页面总数using System; using Eplan.EplApi.DataModel; using Eplan.EplApi.HEServices; using Eplan.EplApi.Base; namespace EplanApiScript { public class ListPages { [ScriptMethod] public void Execute() { Project project new SelectionSet().GetCurrentProject(false); if (project null) { System.Windows.Forms.MessageBox.Show(请先打开一个EPLAN项目); return; } int count 0; foreach (Page page in project.Pages) { string info page.PageName | page.PageType | page.Description; Console.WriteLine(info); count; } System.Windows.Forms.MessageBox.Show(页面总数: count); } } }逻辑说明new SelectionSet().GetCurrentProject(false)是获取当前活动项目最常用的写法参数传false表示“如果没有打开的项目就直接返回null不弹出打开对话框”如果传trueEPLAN会弹窗要求你手动选项目适合交互式运行。拿到project对象后project.Pages返回项目里所有页面的集合包括多层级结构下的所有页。page.PageName是页的完整路径名page.PageType是页面类型枚举page.Description是页面描述。Console.WriteLine在EPLAN脚本里不一定有控制台可看所以最后用MessageBox兜底显示结果。参数说明如果想只处理某层或某个类型的页面可以在循环里加过滤比如if (!page.PageName.StartsWith(G/2)) continue;G/2是EPLAN里第2个高层代号按实际项目结构调整即可。这条过滤习惯能让你在页面很多的工程里少跑很多冤枉路。3.3 从脚本到插件按钮把功能挂进菜单的过渡做法脚本虽然能跑但每次都要打开“脚本”菜单再浏览文件对最终用户不友好。EPLAN并没有一个可视化“导入插件”按钮常见做法是把脚本方法注册为自定义命令再通过“用户自定义命令”设置窗口分配给一个快捷键或工具条按钮。具体路径在EPLAN的设置里搜索“命令”找到“脚本”分类把你写好的脚本方法关联进去。更深一层如果你希望功能表现为一个真正常驻的菜单项比如点击“导出设备清单”直接执行那就要走Add-In插件路线。EPLAN的Add-In本质上是一个被EPLAN进程加载的.NET程序集它通常在初始化阶段用CommandInterpreter注册自定义Action然后在菜单配置里引用这个Action。这里给一个用CommandInterpreter执行内置命令的示例说明插件层是怎么和EPLAN命令系统打交道的using Eplan.EplApi.HEServices; public class ActionRunner { [ScriptMethod] public void ExecuteExport() { CommandInterpreter ci new CommandInterpreter(); ci.Execute(XPAExport); } }逻辑说明CommandInterpreter是EPLAN动作系统的客户端Execute(XPAExport)表示触发EPLAN内置的导出Excel对话框命令。Add-In插件的核心就是把你自己写的业务方法包装成一个Action然后用同样的方式挂到菜单上。参数说明XPAExport在不同版本依然保留但如果你要调用的内置命令名称在目标版本已经改名Execute会静默失败所以插件里最好先写日志确认Action真的被调用到了。我的建议是团队内部用脚本加快捷键就够要跨部门分发再花时间做插件否则维护成本容易超过收益。4. 把API用到生产环境批量导出设备清单和更新页属性的可复现代码4.1 批量导出设备清单到CSV一张核心表格的写法电气设计里最常被追问的就是“这张图纸里到底用了哪些设备”。用鼠标一个个看部件选型表很慢用API遍历整个项目一次就能拿到所有设备。下面这段脚本遍历当前项目所有设备把核心字段写成CSVusing System; using System.IO; using System.Text; using Eplan.EplApi.DataModel; using Eplan.EplApi.HEServices; public class ExportDevicesCsv { [ScriptMethod] public void Execute() { Project project new SelectionSet().GetCurrentProject(false); if (project null) { throw new InvalidOperationException(没有打开的项目); } StringBuilder sb new StringBuilder(); sb.AppendLine(DT,名称,功能文本); foreach (Device device in project.GetDevices()) { // 设备标识符DT是设备在项目中的唯一代号 string dt device.DT; // 主功能的可见名称可能为空空值统一写成空格避免Excel错位 string name device.Function ! null ? device.Function.VisibleName : ; // 功能文本常用于描述这设备在电路里干什么 string text device.Function ! null ? device.Function.FunctionText : ; sb.Append(dt).Append(,) .Append(name).Append(,) .Append(text).AppendLine(); } string output Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), devices.csv); File.WriteAllText(output, sb.ToString(), Encoding.UTF8); System.Windows.Forms.MessageBox.Show(已导出: output); } }逻辑说明project.GetDevices()返回项目下所有设备对象这里没传过滤参数就是全量导出。device.DT是设备标识符也就是图纸上看到的那个DT编号跨页保持唯一device.Function拿到的是该设备的主功能VisibleName是显示名FunctionText是功能文本。只有Function不为空时才读取否则直接填空字符串这是批量导出里最常见的空引用坑。参数说明CSV用逗号分隔如果项目里有描述文本本身包含逗号导出后会被Excel拆成多列。处理办法很简单把文本字段里的逗号替换成全角逗号或者用制表符替换逗号作为分隔符。我倾向于制表符因为设备描述里很少出现Tab。另外Encoding.UTF8要显式声明否则Windows下默认的ANSI编码导出的CSV用Excel打开中文容易乱码。4.2 批量更新页属性先查属性ID再写死批量改属性是EPLAN API最常见的需求比如给所有结构为G/2的页面统一改描述。EPLAN的每个属性都有一个数字ID属性ID在不同主版本之间有变动所以我不建议你直接抄网上的数字。正确顺序是在EPLAN里打开目标页右键查看属性用属性选择器把“页描述”或“功能文本”的属性编号查出来再把这个编号写进脚本。下面是可替换的骨架代码using Eplan.EplApi.DataModel; using Eplan.EplApi.HEServices; public class UpdatePageDescriptions { [ScriptMethod] public void Execute() { Project project new SelectionSet().GetCurrentProject(false); if (project null) return; int pageDescPropertyId 1111; // 请用属性选择器查本机版本的页描述ID foreach (Page page in project.Pages) { if (!page.PageName.StartsWith(G/2)) continue; // Properties集合用ID索引Set写入新值 page.Properties[pageDescPropertyId].Set(2025版 第3次修改); } } }逻辑说明page.Properties是该页的属性集合用方括号传入属性ID返回一个属性值对象调用Set写入。写入后EPLAN会标记页面为已修改和手工编辑属性一样。这里我只处理G/2层级的页面避免把项目里的封面和目录也一并改了。参数说明属性ID是本机的换一个EPLAN版本必须重新查不要用属性显示名去索引本地化语言一变脚本就失效用ID才是稳定的做法。4.3 验证批量结果差分对比和抽样检查的现场经验批量脚本跑完不能直接宣称完成验证环节我一般分三步。第一步导出处理前的设备清单CSV再导出处理后的CSV用文本对比工具做差分重点看新增、删除和修改的字段这一步能挡住大部分逻辑错误。第二步抽3到5个典型页面人工复核特别是那些系统提示“写入失败”的页面在EPLAN的消息面板里会记录失败原因常见原因包括页面被锁定或属性只读需要解锁后再跑。第三步用EPLAN自身的“项目检查”功能跑一遍错误检查确认批量写入没有把结构改坏。差分验证的效果比肉眼扫图纸靠谱得多这也是我每次都优先做CSV导出的原因——只有数据可比较脚本的改动才可审计。5. EPLAN API开发避坑记录5个让新手当场翻车的典型问题5.1 现象外部EXE退出后EPLAN进程仍然卡在后台项目文件被锁死原因用了ApplicationServer但没有正确释放。EplanApplication和project对象持有EPLAN进程的引用直接退出main方法不会自动清理COM引用挂在那里导致下次打开项目时提示“项目正在使用中”。解决在finally块里成对关闭project.Close()释放项目文件eplan.Close()释放应用进程。另外调试外部EXE时如果代码中途抛异常进程可能已经残留打开任务管理器把EPLAN进程结束再重跑这是最直接的后悔药。5.2 现象一运行就抛BadImageFormatException错误信息指向程序集加载原因这几乎是x86/x64不匹配的专属症状。EPLAN进程是64位你的C#工程如果没有把平台目标设为x64而是AnyCPU或x86运行时JIT会按32位加载程序集EPLAN的DLL是64位强命名程序集就直接拒绝加载。解决打开工程属性生成选项卡里把平台目标改成x64同时确认Debug和Release都改只改一个配置会在换模式后再次翻车。5.3 现象从某处拿到的“EPLAN API.zip”里DLL引入后运行时提示找不到方法或方法签名不匹配原因压缩包里的DLL和本机EPLAN主版本不是同一代。EPLAN API的方法签名和类型在主版本之间是演进的2.9上编译的调用代码放到2022上经常出现“找不到方法”的运行时异常。解决不依赖外来的DLL包直接引用本机安装目录Bin下的DLL重新编译如果你确实只有那个zip包至少先看里面DLL的文件版本和你本机是否一致再看包内有没有附带对应的EPLAN版本说明。版本不一致时代码能编译通过也没有用运行时黑匣子一样报错。5.4 现象批量处理多个项目时内存占用持续上涨最后EPLAN假死原因循环里每处理一个项目就new一个Project并Open用完没有Close。EPLAN的项目对象持有大量数据模型不释放就会累积在进程内存里几百个页面之后基本卡死。解决所有Open必须成对出现无论是否成功都要Close如果担心中途异常把每个项目处理逻辑包在try/finally里finally负责Close。另一个容易被忽略的点是脚本里的MessageBox批处理时弹窗阻塞会让EPLAN看起来像“卡死”改成写日志文件跑完再看结果。5.5 现象在2.9上写好的属性ID到2022版里运行时写入完全不生效原因EPLAN的属性ID体系在不同版本之间存在调整同一个“页描述”属性不同版本的数字ID可能不同还可能被拆分成了不同用途的属性。解决每个版本第一次写脚本时先手工查属性选择器确认目标属性的数字ID存成一个常量配置文件不要散落在代码里同时写一个读取验证的方法写入后立刻读出来比对不一致就说明ID不对提前暴露而不是等到批量跑完才发现。6. 把API脚本做成长期工具日志、异常恢复和验证开关脚本从“自己跑着玩”变成“团队天天用”至少要加三样东西日志、异常恢复和验证开关。日志不是只在出错时写而是每条关键步骤都写这样别人用的时候说“这里不对”你能直接看时间线定位是哪一步不对。异常恢复的核心是备份我在每次批量写入前都会用EPLAN的打包功能先做一次项目归档或者让脚本把将要修改的页面清单先导出来改挂了还能手动回退。验证开关是一个bool参数叫dryRun为true时脚本只统计和打印将要做什么不实际写入任何属性确认输出符合预期后再关掉开关真正执行。这三样加起来脚本才具备交付给别人用的基本素养。下面是一个通用安全运行模板可以套在任何脚本方法上using System; using System.IO; using Eplan.EplApi.DataModel; using Eplan.EplApi.HEServices; public class SafeRunner { private static readonly string LogFile D:\EPLAN_Scripts\api_log.txt; private bool dryRun true; // 上线前保持true确认无误后改为false [ScriptMethod] public void Execute() { DateTime start DateTime.Now; Log(开始执行dryRun dryRun); Project project new SelectionSet().GetCurrentProject(false); if (project null) { Log(没有打开的项目终止); return; } try { int touched 0; foreach (Page page in project.Pages) { if (!page.PageName.StartsWith(G/2)) continue; Log(准备处理: page.PageName); if (!dryRun) { // 这里放真正的写入逻辑 } touched; } Log(扫描完成命中页面数 touched 耗时 (DateTime.Now - start)); } catch (Exception ex) { Log(出错: ex.Message 堆栈: ex.StackTrace); } } private void Log(string message) { File.AppendAllText(LogFile, [ DateTime.Now.ToString(yyyy-MM-dd HH:mm:ss) ] message Environment.NewLine); } }逻辑说明日志文件写固定路径每条记录带时间戳出错时把异常堆栈一起写入dryRun模式下只扫描和记录不做实际写入。这样团队同事拿到脚本后可以先跑一遍dryRun看命中多少页面确认范围没问题再执行心理门槛低很多。参数说明LogFile路径要根据实际环境改建议放在一个非系统盘目录下避免用户权限写不进去。我自己的教训是最早做API脚本一上来就想着写成完整插件结果被版本兼容和COM释放问题耗了一周后来老老实实改成“脚本落地、日志兜底、CSV验证”三步走一个下午就能交付一个稳定批处理工具。代码不一定要多先进能确认跑没跑对、坏了能退回去才是长期能维护的方案。希望帮到你。本文还有配套的精品资源点击获取
返回列表