简介:Tekla OpenAPI 是 Tekla Structures 官方提供的开发接口,这份参考文档适合结构工程二次开发工程师、BIM 集成开发者以及希望实现建模自动化的 Tekla 进阶用户。文档以 API 参考页面为主体,涵盖对象模型、常用接口函数、事件驱动机制、访问权限、错误处理、IFC/DWG 数据交换、调试与性能优化等关键知识点;同时说明基于 .NET 的多种编程语言调用方式,并可在网页中翻译为中文后查阅,便于快速理解接口用法与对象关系。资源为 RAR 压缩包,约 21.72MB;当前解析到的文件总数为 0,未给出具体文件类型明细,实际内容应以解压后的离线页面为准。已有 487 人学习或下载,适合需要系统梳理 Tekla OpenAPI 知识体系、开发自定义插件或与外部系统对接的工程师收藏使用,有助于减少重复建模操作并提升自动化程度。
1. TeklaOpenAPI Reference:为什么多数人下载后第一反应是关掉?
聊到 Tekla OpenAPI 二次开发,很多人第一反应是去翻那份 Reference 文档。但以我做钢结构深化设计插件这几年的观察,真正能把这份文档用起来的人,十个里面不超过三个。多数人的流程是:下载、解压、打开命名空间列表,看到几万个类和成员,然后默默关掉,回到手工建模。这份资源解决的根本不是"Tekla 有没有 API"的问题,而是"API 到底怎么调、参数从哪来、返回结果怎么处理"的落地问题。它适合那些在 Tekla 里做参数化建模、写自动化脚本、或者想摆脱重复劳动的深化设计师和软件工程师。这篇文章我会从引用 DLL 讲到插件骨架,再到参数化建模实战,最后给到避坑经验和进阶技巧,全程按我自己的踩坑记录来写,希望帮你在 OpenAPI 这条路上少走点弯路。
2. 把引用吃透:四个核心 DLL 与第一条通路
2.1 别急着写代码,先搞懂 Reference 里四个核心 DLL
Tekla OpenAPI 的 Reference 文档看起来像个黑匣子,几万个类堆在命名空间里,很容易把人劝退。但其实你日常开发真正会用到的核心程序集就四个,把它们的关系理清楚,Reference 文档里 80% 的内容都能迅速定位。
| DLL 名称 | 核心命名空间 | 主要职责 |
|---|---|---|
| Tekla.Structures.dll | Tekla.Structures | 基础连接、几何点、线、向量定义,所有二次开发的地基 |
| Tekla.Structures.Model.dll | Tekla.Structures.Model | 访问模型数据库,操作零件、构件、螺栓、焊缝等实体 |
| Tekla.Structures.Drawing.dll | Tekla.Structures.Drawing | 图纸自动化,视图、标注、尺寸、构件图处理 |
| Tekla.Structures.CustomProperty.dll | Tekla.Structures.CustomProperty | 自定义属性读写,插件与图纸/模型之间传参的关键 |
我最开始踩的一个坑就是一股脑把四个 DLL 全引用进去,结果项目编译出一堆版本冲突警告。后来学乖了:做模型自动化只引用前两个,做图纸自动化再引入 Drawing,做属性扩展才碰 CustomProperty。Reference 文档里每个类都有个Assembly标注,你照着那个找就行,别贪多。
2.2 最小可复现模型:连接与遍历
不管你后面要做什么功能,第一步永远是建立 API 与当前模型的连接。这个连接如果没建立起来,后面所有代码都会在Model对象上直接抛空引用异常。我一般会写一个最小可复现模型来验证通路,代码量不大,但能排查掉 90% 的环境问题。
using Tekla.Structures; using Tekla.Structures.Model; public class TeklaConnectionTest { public bool ConnectAndReadModel() { // 1. 建立与 Tekla 进程的全局连接 TeklaStructures.Connect(); ConnectionStatus status = TeklaStructures.Connect(); if (status != ConnectionStatus.ConnectionStatusOK) { return false; // 连接失败,检查 Tekla 是否以完整模式启动 } // 2. 实例化 Model 对象,代表当前打开的模型 Model model = new Model(); if (!model.GetConnectionStatus()) { return false; // 连接状态为 false 时,后续操作全部无效 } // 3. 获取模型中的梁对象,验证读取通道 ModelObjectSelector selector = model.GetModelObjectSelector(); var beams = selector.GetAllObjectsWithType<Beam>(); int count = 0; foreach (var obj in beams) { count++; if (obj is Beam beam) { // 这里先不修改,只读属性,确保 API 通路完全打通 string profile = beam.Profile.ProfileString; string material = beam.Material.MaterialString; } } // 4. 断开连接,释放 API 占用的句柄 TeklaStructures.Disconnect(); return count > 0; } }这段代码里有几个参数值得注意。ConnectionStatus.ConnectionStatusOK是唯一能继续往下走的状态,如果你看到的是ConnectionStatusConnectionFailed,多半是 Tekla 软件没开,或者你开了但没进入任意模型。GetAllObjectsWithType<Beam>()是泛型过滤,它等价于你在 Reference 里查到的GetAllObjectsWithType(Type type)的重载版本,用泛型写可以省掉后面的类型判断。beam.Profile.ProfileString返回的是截面名称字符串,比如HN400x200,这是后面批量修改的基础。读属性不需要事务,改属性才需要,这个区别我放在第 4 章细讲。
2.3 从 Reference 中提取参数:不要死记硬背
Tekla OpenAPI 的 Reference 文件(chm 或网页格式)里有完整的类继承关系和属性说明,但直接搜的效率非常低。我一般会先在 Reference 里定位类所在的程序集,然后直接用代码补全来探索属性。你按下Ctrl+Space看智能提示,会看到InsertionPoint、CoordinateSystem、Class、Name这些常见属性,这些都是ModelObject基类里定义好的。真正要查数据库字段对应关系时,Reference 里每个属性下面会有一段Description,里面经常藏着数据库字段名,比如Part.PART_ID。这个 ID 在你后面写跨模块同步功能时特别有用,先记着就好。
提示:如果你用 Visual Studio,把 Tekla 安装目录下的
nt\bin\net加到项目引用路径,里面就是这些 DLL。不要从C:\Windows\Microsoft.NET里乱找,版本完全对不上。
3. 从参考到运行:搭一个能挂进 Tekla 的插件骨架
3.1 为什么是插件(dll)而不是宏(cs)
Tekla 自带宏录制功能,很多初学者会用宏录一段操作,然后导成 C# 代码来改。宏的本质是调用 OpenAPI 把界面操作重放一遍,它的问题是逻辑全在一个Main函数里,没有输入定义,也没有异常隔离。你要做一个给别人用的批量建模工具,宏的代码结构撑不住。插件的优势在于它实现了 Tekla 规定的接口,能拿到用户拾取的点、对象列表、甚至能把自己挂到菜单和工具栏上。从 Reference 的角度看,插件核心就是PluginBase和PluginLoaderBase两个类,后者负责把插件加载到 Tekla 环境,前者负责业务逻辑。
3.2 插件骨架:DefineInput 与 Run 的分工
写插件的第一步是创建类库项目,目标框架选.NET Framework 4.7.2或更高,具体看你用的 Tekla 版本。不要选.NET Core,Tekla 的 API 底层是 .NET Framework,选错了连引用都加不进去。下面是一个最简插件骨架,你可以在任何空项目里跑起来。
using System; using System.Collections.Generic; using Tekla.Structures; using Tekla.Structures.Model; using Tekla.Structures.Model.UI; using Tekla.Structures.Plugin; namespace MyTeklaPlugin { // 告诉 Tekla 这个类的插件名称,会显示在菜单里 [Plugin("MyFirstPlugin")] public class MyFirstPlugin : PluginBase { // DefineInput 负责定义这个插件需要用户提供什么 public override List<InputDefinition> DefineInput() { List<InputDefinition> inputs = new List<InputDefinition>(); // 让用户拾取一个点作为插入点 inputs.Add(new InputDefinition(InputType.PickPoint)); return inputs; } // Run 是插件的主入口,insertionPoint 就是用户拾取的点 public override bool Run(Point insertionPoint) { try { // 在这里写你的核心逻辑 return true; } catch (Exception ex) { // 插件环境里异常不能直接抛给 Tekla,先记录再返回 false return false; } } } }这段代码的骨架作用很关键。DefineInput里可以添加多个InputDefinition,比如先拾取一个点,再拾取一组对象,对应的InputType分别是PickPoint和PickObjects。Run方法里的insertionPoint参数,是PickPoint拾取到的那个点在世界坐标系下的坐标,很多新手以为插件不需要这个参数,结果在Run里自己又去创建点,绕了一圈反而丢了精度。插件编译通过后,把生成的 dll 复制到 Tekla 的C:\Program Files\Tekla Structures\<版本>\nt\bin\plugins目录下,重启 Tekla 就能在应用菜单里看到它。
3.3 选择过滤:PickObjects 的正确打开方式
很多实际场景里,用户不是点一个点,而是框选一批梁或柱来批量处理。这时候InputDefinition要换成PickObjects,并且在Run里用Selection对象来取。我见过不少人在这里翻车:Run里拿不到Selection,是因为 Tekla 的拾取结果不是实时传递到插件的,而是要先从模型里把选中对象捞回来。
public override bool Run(Point insertionPoint) { // 注意:不是直接遍历 UI 里的 Selection,而是通过 ModelObjectSelector Model model = new Model(); ModelObjectSelector selector = model.GetModelObjectSelector(); // 从当前模型中选择被选中的对象 var selected = selector.GetObjectsByType(Beam.BeamType); foreach (var obj in selected) { if (obj is Beam beam) { // 这时才拿到用户选中的梁对象 } } return true; }这里要留意Beam.BeamType这个静态字段,它替代了旧版本里写在ModelObject上的类型枚举。你在 Reference 里查Beam类时会发现它继承自Part,而Part继承自ModelObject,所以Beam天然拥有Name、Class、Material、Profile这些属性。正确的捞对象姿势是直接用GetObjectsByType(Beam.BeamType),而不是先用GetAllObjectsWithType<ModelObject>()再自己做类型判断。后者会把模型里所有的零件、螺栓、焊缝全捞一遍,性能差一截。
4. 参数化建模实战:改截面、加螺栓的 API 路径
4.1 构件层级:Beam、Part 与 ModelObject 的关系
在修改参数之前,先花 30 秒看清 Tekla 的类继承树。Reference 里Beam的继承链是这样的:ModelObject->Part->Beam。ModelObject负责的是 ID、名称、坐标系这些基础数据;Part增加了Profile、Material、Class、Position这些构件属性;Beam则增加了起点、终点和方向向量。这个结构决定了你改截面时能调到什么程度。Profile是Profile类型,它有一个ProfileString属性,直接改这个字符串就能换截面。但很多初学者不知道的是,改完必须调用Modify(),否则 Tekla 的内存模型里还是旧数据。
using Tekla.Structures.Model; public void ChangeBeamProfile(string beamId, string newProfile) { Model model = new Model(); // 通过 ID 直接拿到对象,ID 是字符串类型 ModelObject obj = model.GetModelObjectByID(beamId); if (obj is Beam beam) { // 修改前先记录旧截面,方便回滚 string oldProfile = beam.Profile.ProfileString; beam.Profile.ProfileString = newProfile; // 关键步骤:Modify 把内存里的修改同步到模型数据库 bool success = beam.Modify(); if (!success) { // 修改失败要回滚 beam.Profile.ProfileString = oldProfile; beam.Modify(); } } }参数说明就藏在代码里。GetModelObjectByID(string)里面传的 ID,是你在第 2 章最小可复现模型里拿到的那种字符串 ID,不是数据库自增整数。Modify()的返回值是bool,如果返回false,通常意味着当前线程没有开启事务。我在这地方翻过车:以为Modify()内部会自己处理事务,结果静默失败,模型上什么都没变。后面才意识到,OpenAPI 里所有写操作都必须包在Transaction里。
public bool UpdateBeamWithTransaction(string beamId, string newProfile) { Model model = new Model(); // 开启一个事务,事务名建议写清楚用途 Transaction transaction = new Transaction(model); transaction.Start("Change Profile"); ModelObject obj = model.GetModelObjectByID(beamId); if (obj is Beam beam) { beam.Profile.ProfileString = newProfile; beam.Modify(); // 事务提交,这里才是真正落库 return transaction.Commit(); } // 出错时回滚,不留半截数据 transaction.RollBack(); return false; }事务的作用是让一系列操作要么全部成功要么全部不生效。Start方法里传入的字符串会显示在模型历史记录里,方便你排查是哪个插件改了模型。我看到很多 macaroon 生成的代码里事务名是默认的,但我建议你养成写清楚事务名的习惯,模型出问题时这是第一手线索。
4.2 加螺栓:BoltGroup 参数与正向轴陷阱
螺栓比改截面复杂得多,因为它涉及一个方向问题。BoltGroup是一个附着在零件上的连接对象,它有三个核心参数组:螺栓定义(大小、标准)、孔定义(直径、长圆孔)、位置定义(坐标、方向)。坑就在方向里。
using Tekla.Structures.Geometry3d; using Tekla.Structures.Model; public void AddBoltGroupToBeam(Beam beam, Point position, Vector direction) { // 这个螺栓组要加到 Beam 的一端 BoltGroup boltGroup = new BoltGroup(); boltGroup.BoltSize = 20.0; // M20 螺栓 boltGroup.BoltStandard = "ISO 4014"; // 普通六角头螺栓标准 boltGroup.BoltType = BoltGroup.BoltTypeEnum.BOLT_TYPE_NORMAL; boltGroup.HoleDiameter = 22.0; // 比螺栓大 2mm 的圆孔 // 位置参数:参考点、方向向量、旋转角度 Position positionDef = new Position(); positionDef.Plane = Position.PlaneEnum.MIDDLE; // 螺栓在构件中部 positionDef.Rotation = Position.RotationEnum.BOLT_HOLE_ALIGNED; // 螺栓孔对齐 boltGroup.Position = positionDef; // 正向轴:决定螺栓打进来的方向,这个最容易踩坑 boltGroup.PositiveAxis = direction; // 把螺栓组关联到目标零件 boltGroup.AddToModel(beam); boltGroup.Insert(); }这个代码里最玄学的就是PositiveAxis。它是个Vector,表示螺栓从哪边打进来。如果方向反过来,螺栓就会出现在构件另一侧,在图纸上表现为完全相反。我第一次写的时候直接用了new Vector(0, 0, 1),结果在斜梁上全部打反了。后来才注意到 Reference 里对PositiveAxis的描述是 "螺栓组正方向轴向量",需要根据梁的坐标系计算。更稳妥的做法是从梁的起点、终点算出方向:
Vector GetBeamPositiveAxis(Beam beam) { Point start = beam.StartPoint; Point end = beam.EndPoint; // 从起点指向终点的单位向量 Vector direction = new Vector(end.X - start.X, end.Y - start.Y, end.Z - start.Z); direction.Normalize(); return direction; }用这个方法得到的轴向永远不会跟梁身拧着。这里也引出一个通用教训:凡是 Reference 里带Axis、Plane、Rotation的参数,都是从几何坐标语义出发的,不能拍脑袋给全局坐标。多花两分钟查一下当前构件的坐标系,能省掉后面一小时的返工。
5. 避坑指南:OpenAPI 开发中五个高频翻车现场
5.1 异常:Object reference not set to an instance of an object.
现象:运行插件时,软件直接弹这个错,指向某一行代码,但那一行看起来没问题。原因:最常见的是Model实例没有成功获取到当前模型。比如在宏代码里直接new Model(),但 Tekla 当前只在打开软件、没打开具体模型的状态。第二个常见原因是GetModelObjectByID()返回了null,但你没做判空就调用Profile属性。解决:首先在所有 API 调用前检查Model.GetConnectionStatus(),其次对GetModelObjectByID等返回值为对象的方法,一律判空再继续。这个习惯能避免 90% 的空引用异常。
5.2 事务未提交,模型被锁死
现象:插件跑完,发现模型处于只读状态,所有按钮变灰,必须重启 Tekla 才能动。原因:某个分支里Transaction.Start()了,但因为异常或提前return,没有走到Commit()或RollBack(),事务一直攥在持有它的大旗里。解决:把事务放进try-catch-finally,在finally里判断事务是否还开着,开着就回滚。我通常写一个壳子:
Transaction transaction = new Transaction(model); transaction.Start("safe batch op"); try { // 业务逻辑 transaction.Commit(); } catch { transaction.RollBack(); throw; }这样不管中间发生什么,事务都不会泄漏。
5.3 GetAllObjectsWithType 返回空集合
现象:在某个模型里能正常遍历梁,到另一个模型里返回空。原因:第一种情况是当前模型是空的,但用户一般不会拿空模型来调插件。第二种情况是过滤条件用的类型不匹配,比如模型里的梁实际是ContourPlate,你用Beam去捞自然捞不到。第三种情况是模型数据库状态未更新,Geometry或Analysis视图下 OpenAPI 访问的是不同的数据库分支。解决:先用GetAllObjectsWithType<ModelObject>()确认模型里到底有哪些类型,再换成具体类型;同时确保模型处于完全打开状态,不是只打开了某个子视图。
5.4 DLL 版本与运行中的 Tekla 不匹配
现象:编译时没有报错,运行时报Could not load file or assembly 'Tekla.Structures.Model, Version=...'或者直接BadImageFormatException。原因:你本机装了多个 Tekla 版本,VS 项目里引用的 DLL 是旧版安装路径下的,但当前启动的是新版 Tekla。OpenAPI 的 DLL 是强命名程序集,版本号完全匹配才认账。解决:每次切换 Tekla 版本时,把项目里所有 Tekla 相关引用删掉重新从当前版本的nt\bin\net添加。血泪经验:不要用相对路径引用,直接引用绝对路径,并关掉本地复制选项,跑之前人工核对版本。
5.5 独立工具连不上模型的玄学
现象:写了个 exe 工具,双击打开能正常启动,但调用Connect()时返回失败,或者连接成功后Model对象拿到的是空模型。原因:Tekla 的 OpenAPI 连接要求调用方以管理员身份运行并启用交互桌面。如果你用任务计划程序或者从 CI 工具里启动 exe,运行上下文是 Session 0,几乎没有桌面访问权,API 自然连不上。解决:交互式运行时右键以管理员身份运行;如果确实需要无人值守运行,得把 Tekla 本身提前打开并加载好目标模型,工具只负责连接、不负责拉起软件。
注意:如果你要开发的是 C++ 环境下的 Tekla 扩展,你会遇到一堆
undefined reference to的链接错误,那是编译器在告诉你某个符号没有实现,本质跟 C# 里空引用异常类似,都是没找到该找的东西。先检查库路径,再检查函数签名。
6. 进阶技巧:用反射把 Reference 变成你的内部工具库
到了这个阶段,你应该已经能熟练增删改查模型对象了。但 Reference 那个黑匣子依然让人头大,查一个属性要层层展开。我的做法是用反射直接扫描 DLL,把 Tekla 的类结构拉平成一个自己看得懂的 Markdown 文件,相当于给自己做一份"精简版 Reference"。
using System; using System.Collections.Generic; using System.Reflection; using System.Text; public class ApiRefGenerator { public static void GenerateSummary(string dllPath, string outputPath) { Assembly asm = Assembly.LoadFrom(dllPath); Type[] types = asm.GetTypes(); Array.Sort(types, (t1, t2) => string.Compare(t1.FullName, t2.FullName, StringComparison.Ordinal)); StringBuilder sb = new StringBuilder(); sb.AppendLine("# Tekla API Quick Reference"); sb.AppendLine($"Generated from {dllPath}"); foreach (Type type in types) { // 过滤掉编译器生成的嵌套类 if (type.IsNested && type.IsSealed) continue; sb.AppendLine($"\n## {type.FullName}"); sb.AppendLine($"Base Type: {type.BaseType?.FullName ?? "none"}"); // 重点提取属性和方法名,这就是你日常查的东西 var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in props) { sb.AppendLine($" - Property: {prop.PropertyType.Name} {prop.Name}"); } var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); foreach (var method in methods) { if (method.IsSpecialName) continue; // 跳过 getter/setter 自动生成的方法 sb.AppendLine($" - Method: {method.ReturnType.Name} {method.Name}(...)"); } } System.IO.File.WriteAllText(outputPath, sb.ToString()); } }这个反射工具的参数很直接:dllPath指向你当前 Tekla 版本目录下的Tekla.Structures.Model.dll,outputPath指向你要生成的 Markdown 文件。生成的表格里会包含每个类的基类、属性类型和方法签名,这样你写代码前先翻自己的 Markdown,脑子里就有了整个 API 的地图,而不是在一片混沌里瞎找。我每次升级 Tekla 版本都会重新生成一份,并 diff 两份文档之间新增了哪些类,这样新版本有什么能力变化一目了然。
另外一个值得养成的习惯是:再用反射把枚举值也导出来。Reference 文档里枚举是最难查的,比如Position.RotationEnum具体有哪些成员,反映到代码里就是BOLT_HOLE_ALIGNED、TOP、BELOW这些值。
我记得有一次给现场写批量出图工具,因为没做事务回滚,把一整层钢梁的截面全改错了,老板盯着屏幕看我一行行找回旧参数,那叫一个狼狈。从那以后,我每次写批量修改工具,都会强制走一遍流程:先建事务并备份涉及构件的旧参数,然后在测试模型里跑一次,最后再切到真实模型上执行。顺序永远不要颠倒——备份、测试、执行。这是一个老工程师最笨也最稳的套路。希望这篇文章能帮你在 Tekla OpenAPI 的路上减少几个失眠夜,也让你在遇到 Reference 文档翻车时,知道自己不是一个人。
本文还有配套的精品资源,点击获取