svMCP——Tekla Structures MCP服务器
MCP(Model Context Protocol) Tekla结构2021和2025 通过Claude Desktop和其他MCP客户端。
要求
- Windows 10/11
- .NET 8 SDK
- .NET Framework 4.8(适用于Windows 10+)
- Tekla结构 2021 或 2025 (安装和运行)
安装和配置
1.装配
dotnet build src/TeklaMcpServer/TeklaMcpServer.csproj -c Release自动收集 TeklaMcpServer (净值8.0)+ TeklaBridge (net48)并将teklabridge.exe复制到 bin/Release/net8.0-windows/bridge/.
2.安装Claude Desktop
%APPDATA%\Claude\claude_desktop_config.json:
{
"mcpServers": {
"tekla": {
"command": "D:\\repos\\svMCP\\src\\TeklaMcpServer\\bin\\Release\\net8.0-windows\\TeklaMcpServer.exe"
}
}
}3.修改后的下部
# 1. Закрыть Claude Desktop
# 2. Собрать
dotnet build src/TeklaMcpServer/TeklaMcpServer.csproj -c Release
# 3. Открыть Claude Desktop重要的是: Teklamcpserver.exe在Claude桌面打开时被阻止。 如果只更改了Teklabridge,则可以在不关闭Claude Desktop的情况下重置它, 结果复制到bridge/自动通过目标BuildAndCopyTeklaBridge.
《Tekla Structures 2025》
Teklabridge应该从Tekla扩展文件夹运行,而不是从标准文件夹运行。 bridge/ 目录。 这是必要的,因为Tekla生成 exe.config с ` 记录 指定安装了正确版本的DLL(FileVersion) 2025.0.52577.0而不是NuGet 2025.0.0.0`).
扩展文件夹: C:\TeklaStructures\2025.0\Environments\common\extensions\svMCP\
ДеплойTekla BridgeдляTS2025:
# Сборка TeklaBridge (без закрытия Claude Desktop)
dotnet build src/TeklaBridge/TeklaBridge.csproj -c Release
# Скопировать TeklaBridge.exe и TeklaMcpServer.Api.dll в папку расширений
$src = "src\TeklaBridge\bin\Release\net48"
$dst = "C:\TeklaStructures\2025.0\Environments\common\extensions\svMCP"
New-Item -ItemType Directory -Force $dst
Copy-Item "$src\TeklaBridge.exe" $dst
Copy-Item "$src\TeklaMcpServer.Api.dll" $dst
# Также скопировать сторонние зависимости (System.Text.Json, Newtonsoft.Json и т.д.)exe.config: 手动创建一次,存储在扩展文件夹中。 包含 ` + 对于所有Tekla DLL,指向 C:\TeklaStructures\2025.0\bin\. 源生成器: C:\temp\GenConfig2.ps1`.
TeklamcPServer自动检测TS2025的存在,并从扩展文件夹启动桥。 如果文件存在(ResolveBridgePath() 在 ModelTools.Shared.cs).
建筑
Claude Desktop
│ stdio (JSON-RPC / MCP)
▼
TeklaMcpServer.exe (net8.0-windows)
│ Process.Start → stdout pipe
▼
TeklaBridge.exe (net48)
│ .NET Remoting IPC (TS2021) / Trimble.Remoting MMF (TS2025)
▼
Tekla Structures 2021 / 2025为什么有两个过程?
Tekla Structures Open API需要 net48. MCP SDK要求 net8+在一个过程中不可能兼容不同的Rantimes,不同的CLR。
【版本】【IPC机制】【启动功能】 |---|---|---| | TS2021 | .net remoting,named pipes#reflection-通道名称后缀 -Console:) | | TS2025 | Trimble.Remoting,Memory Mapped Files–从Extensions文件夹启动 exe.config + `` |
Teklabridge是一个细长的Net48包装:使用第一个参数接收命令,执行Tekla API,将JSON返回stdout。
项目结构
src/
├── TeklaMcpServer.Api/ # Весь Tekla API код (net48) — интерфейсы, DTO, реализации
│ ├── Selection/ # IModelSelectionApi, ModelObjectInfo, TeklaModelSelectionApi
│ │ # ISelectionCacheManager, SelectionCacheManager
│ │ # SelectionResult, ToolInputSelectionHandler
│ ├── Drawing/ # Общий drawing-layer: DrawingContext, DrawingViewContext,
│ │ # MarksViewContext, API/DTO/builder-ы по views/marks/dimensions
│ │ # DrawingViewInfo, DrawingViewsResult, DrawingMarkInfo, …
│ ├── Algorithms/
│ │ ├── Packing/ # MaxRectsBinPacker
│ │ └── Marks/ # MarkLayoutEngine, candidate generation, scoring, overlap resolver
│ └── Filtering/
│ ├── Common/ # FilterExpressionParser, FilterTokenizer, FilterAstBuilder, FilterHelper…
│ ├── Drawing/ # DrawingObjectsFilterHelper
│ └── Model/ # IModelFilteringApi, DTOs, TeklaModelFilteringApi
├── TeklaMcpServer/ # MCP сервер (net8.0-windows)
│ ├── Program.cs # Точка входа, конфигурация MCP host
│ └── Tools/ # Тонкие MCP-обёртки
│ ├── Shared/ # RunBridge(), общий код
│ ├── Connection/ # check_connection
│ ├── Model/ # Model tools
│ └── Drawing/ # Drawing tools
├── TeklaBridge/ # Bridge процесс (net48) — только диспетчер команд
│ ├── Program.cs # Точка входа + IPC fix + Console capture
│ └── Commands/
│ ├── ModelCommandHandler.cs
│ └── DrawingCommandHandler.cs
└── svMCP/ # Заглушка (не используется)分担责任
一个项目,一个角色。 |---|---|---| |MCP工具| TeklaMcpServer/Tools/ | 只有薄薄的包装 -挑战 RunBridge(),解析JSON,返回字符串› |桥梁调度员| TeklaBridge/Commands/ 管理课堂命令 TeklaMcpServer.Api系列化结果 全部Tekla代码 TeklaMcpServer.Api/ –接口,DTO和所有Tekla API实现→
TeklaMcpServer.Api -一个独立的NET48项目(不与NET8服务器共享),它的价值在于Bridge过程中合同的清晰边界:可见性、通过MOCK进行测试的能力以及对多个Tekla版本的支持。
可用工具
连接
工具描述 |---|---| | check_connection 检查与Tekla Structures的连接;返回模型的名称和路径
模型
工具描述 |---|---| | get_selected_elements_properties –所选元素的属性:part、boltgroup、weld、rebargroup–所有类型› | get_selected_elements_total_weight 所选元素的总重量(kg) | select_elements_by_class –选择Tekla等级的元素→ | filter_model_objects_by_type –按类型(beam,plate,bolt,assembly…)查找并选择模型对象。
图纸
Tekla Structures需要开放的Drawing Editor
工具描述 |---|---| | list_drawings 查看所有模型图纸 | find_drawings –按名称和/或品牌搜索(Contains,不区分大小写)→ | find_drawings_by_properties 搜索多个属性(JSON筛选器) | open_drawing 打开GUID图纸。 | close_drawing 关闭活动图纸 | export_drawings_to_pdf –通过GUID将图纸导出为PDF→ | create_general_arrangement_drawing –Legacy Workaround:通过宏从保存的模型视图创建GA绘图› | create_single_part_drawing –使用Tekla Open API创建Single Part Drawing→ | create_assembly_drawing 使用Tekla Open API创建Assembly Drawing→ | get_drawing_context –活动图纸和专用对象。 | get_drawing_layout_context |粗糙 DrawingContext:图纸/图纸/视图/预留布局| | get_drawing_view_context |详细 DrawingViewContext 一个物种。 | get_sheet_objects_debug Ðdev/debug:表中的所有对象、它们的BBox和候选区域› | select_drawing_objects –根据模型对象ID选择绘图对象› | filter_drawing_objects –按类型(Mark、Part、DimensionBase…)筛选绘图对象→ | set_mark_content –更改邮票的内容和字体。 | get_drawing_views –所有类型的活动绘图:位置、比例尺、尺寸、板材尺寸› | get_drawing_reserved_areas ≫保留区域列表:表、边缘和总块区› | get_drawing_section_sides 部分物种相对基本物种 | move_view –将视图移到工作表上(绝对或偏移)。 | set_view_scale 改变一个或多个物种的大小。 | fit_views_to_sheet –自动绘制物种的主要方式:标准比例尺选择、无重叠正交布局和投影链接上的后对齐› | get_drawing_marks 要阅读品牌:位置,BBOX/OBB, resolvedGeometry,楼板,leader lines,propertyelement内容;按外观过滤。 | create_part_marks –用指定的内容和风格创建详细的品牌→ | delete_all_marks –删除活动图纸上的所有品牌→ | get_drawing_parts ≫图纸中的所有模型对象:partu pos、assemblyu pos、profile、material、name› | get_drawing_dimensions 全部 StraightDimensionSet 活动图纸:ID, dimensionType距离, viewId/viewType方向, direction, topDirection, referenceLine、bbox集/段, dimensionLine, leadLineMain/Second, textBounds | | get_dimension_contexts ≫Internal/Context Read Path的外观大小≫ | arrange_dimensions ≫通过确定滑动平行堆栈尺寸 Distance | | combine_dimensions #Controlled Combine Path for兼容尺寸集 | move_dimension ≫将尺寸线移到Delta(更改) StraightDimensionSet.Distance) | | create_dimension ◎创建 StraightDimensionSet 点的集合。 | delete_dimension 要删除 StraightDimensionSet 通过ID。 | place_control_diagonals ≫根据视图可见部件的实际固体几何学检查对角线尺寸;过滤 MATERIAL_TYPE (默认为钢/混凝土/木材,无保温层);方向总是自下而上的。 | get_part_geometry_in_view –在视图的本地SK中获取零件几何(BBox、start/end、轴)→ | get_all_parts_geometry_in_view –在一个调用中批量获取视图所有细节的几何结构。 | get_grid_axes –以给定的图纸形式获取网格轴。 | resolve_mark_overlaps –自动允许在每个视图中覆盖标记文本块-最小的本地移动› | arrange_marks –在Anchor Point周围的每个视图中完全自动放置邮票› | arrange_marks_no_collisions 组合通道: arrange_marks +重复 resolve_mark_overlaps 直到稳定。 | draw_debug_overlay Ðdev/debug:在图纸中绘制临时覆盖(行/多边形/文本/交叉)→ | clear_debug_overlay Ðdev/debug:清除整个层或按组› | draw_selected_mark_part_axis_geometry Ðdev/debug:显示选定品牌的详细信息轴和几何结构›
现在,邮票的布局是这样的:
- 处理单位:1
View不是全部Drawing Sheet - 事实上的邮票层现在被设计成
MarksViewContext+MarksViewContextBuilder get_drawing_marks已经在上下文层上构建,但保留了以前的外部DTODrawingMarkInfo- 所有Layout引擎的计算都在本地视图坐标系统中进行
- Tekla层只收集中性层
MarkLayoutItem转换视图坐标和表坐标之间的位移 resolve_mark_overlaps只使用本地MarkOverlapResolver对于物种内部的最小变化arrange_marks使用MarkLayoutEngine:候选生成,评分,贪婪放置изатемлокальный重叠解析器- 对于Leader Line Marks,锚来自
LeaderLinePlacing.StartPoint在物种坐标中;StartPoint不会改变,只会移动。InsertionPoint - 标签几何结构集中在
MarkGeometryHelper取决于PlacingType:
- LeaderLinePlacing -object-aligned geometry标签本身 - BaseLinePlacing / AlongLinePlacing -以当前形式从相关零件方向 - Fallback Path-Raw Tekla Geometry,但它不被认为是Collision/Layout Reasoning的典范
绘图层的上下文现在是这样安排的:
DrawingContext--粗板级上下文для布局видов,预留区域иbefore/after公文包DrawingViewContext--详细的每个视图几何体上下文MarksViewContextfactual mark context一种- dimensions在同一方向
get_dimension_contexts
现在的物种分布是这样的:
- 遗产
PlaceViews()从MCP/Bridge层中删除,不再支持工具 - 物种自动旋转的主要途径
fit_views_to_sheet - Sheet-Level Reasoning现在基于
DrawingContext(get_drawing_layout_context) - 后处理投影通信在内部进行
DrawingProjectionAlignmentService - 保留区域:
DrawingReservedAreaReader.ReadLayoutTableGeometries()使用TableLayout.GetCurrentTables()→PresentationConnection.GetObjectPresentation()Canvas Markers(Segment.Primitives[0/2]准确的BBOX表COverlapVithViews=true通过。 - 工作表缩进:
TableLayout.GetMarginsAndSpaces()返回真实的Margins(通常为5-10毫米),用于sheetMargin在答复中 - 布局表边界的典型来源是canvas标记
Segment.Primitives[0/2];原语的整体累积仅允许为fallback
目前尺寸如下:
get_drawing_dimensions返回Line-based Read Model:dimensionType,viewId/viewType,orientation,direction,topDirection,referenceLine,bbox集/段иdimensionLine/leadLineMain/leadLineSecondget_dimension_contexts在同一绘图/视图层上提供单独的上下文路径arrange_dimensions它已经工作了,但它不是一个完整的布局引擎,而是一个用于并行堆栈的Conservative deterministic spacing pathcombine_dimensions已作为Controlled Combine Path工作,不等同于常规分组TextBounds尚存null,直到Tekla侧文本几何得到运行时Spike的验证- 块
Drawing/Dimensions目前正在重新设计D:\repos\svMCP\dim - 公共
arrange_dimensions和get_dimension_arrangement_debug在Line based redesign完成之前暂时隐藏
诊断
文件内容 |---|---| | C:\temp\teklabridge_log.txt 最后一个错误(JSON) | C:\temp\tekla_channel.txt IPC Channel Names(修复了多少频道) | %TEMP%\svmcp-perf.log →分层剖面 mcp/transport/bridge/api |
分析:
SVMCP_PERF=1-启用计时器记录- `SVMCP_PERF_LOG=
-日志文件路径(默认) %TEMP%\svmcp-perf.log`)
直接调用Teklabridge没有Claude
Teklabridge支持模式 --loop:从stdin读取JSON查询,将JSON返回stdout。这允许您直接从PowerShell测试命令:
$bridge = "C:\TeklaStructures\2025.0\Environments\common\extensions\svMCP\TeklaBridge.exe"
'{"id":1,"cmd":"fit_views_to_sheet","args":[]}' | & $bridge --loop请求格式: {"id":,"cmd":"","args":[,,...]}. 团队列表见 TeklaBridge/Commands/DrawingCommandHandler.cs 和 ModelCommandHandler.cs.
______________________________________________________________________
调试历史:它是如何工作的
开发过程的文档-发生了什么以及如何找到解决方案。
第1阶段原始体系结构
该项目最初是作为一个单一的MCP服务器,直接调用Tekla API。 很快发现: 这是不可能的。.
- MCP-SDK(
ModelContextProtocol)要求。NET 8+ - Tekla Structures 2021 Open API仅提供给 .NET Framework 4.8
- 一个过程中的两个兰特不兼容
决定分为两个过程。 TeklaMcpServer.exe (NET8)启动 TeklaBridge.exe (NET48)通过 Process.Start从stdout获取JSON。
______________________________________________________________________
第二阶段第一个关键错误-IPC在MCP下不起作用
在写了Teklabridge之后,第一个测试显示了一个奇怪的模式:
TeklaBridge.exe check_connection从终端→{"status":"connected"}✅- 通过MCP服务器运行的相同二进制→
RemotingException: Failed to connect to an IPC Port❌
表面检查没有任何结果:进程是在同一用户下运行的,在同一会话中,具有相同的权限(integrity level没有不同)。
什么是IPC端口?
Tekla Structures使用 .NET远程处理 基于命名管道的过时进程间通信机制。客户端连接到视图的命名通道:
\\.\pipe\Tekla.Structures.Model-Console:2021.0.0.0因此,如果名称与服务器创建的名称(Tekla结构本身)不匹配,则无法连接。
通过Reflection进行诊断
为了了解客户端计算的频道名称,添加了诊断-通过反射读取静态字段 ChannelName 内部装配:
var remoterType = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => { try { return a.GetTypes(); } catch { return Array.Empty(); } })
.FirstOrDefault(t => t.Name == "Remoter" && t.Namespace?.Contains("ModelInternal") == true);
var channelField = remoterType?.GetField("ChannelName",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
var channelName = channelField?.GetValue(null)?.ToString();
// Результат из-под MCP: "Tekla.Structures.Model-:2021.0.0.0"
// Должно быть: "Tekla.Structures.Model-Console:2021.0.0.0"查找:词 Console 频道名称丢失。服务器正在听 ...-Console:...客户端尝试连接到 ...-:....
原因
通过搜索Tekla的源代码(通过Dotpeek/Ilspy),我们发现了计算名称的逻辑:
// Упрощённо — внутри Tekla.Structures.ModelInternal
static Remoter() {
var stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); // WinAPI
var handleType = GetFileType(stdoutHandle);
// FILE_TYPE_CHAR (0x0002) = консоль
// FILE_TYPE_PIPE (0x0003) = pipe
var suffix = (handleType == FILE_TYPE_CHAR) ? "Console" : "";
ChannelName = $"Tekla.Structures.Model-{suffix}:{version}";
}即Tekla 故意 根据stdout进程查看的位置更改频道名称。当stdout重定向到pipe时(MCP服务器捕获JSON输出时),后缀 -Console 不添加。但是 Tekla Structures服务器创建一个后缀通道 -Console 总是,因为它有stdout=console。
结果:客户端正在寻找不存在的管道,连接失败。
尝试绕过:直接创建文件
检查: CreateFile 的 \\.\pipe\Tekla.Structures.Model-Console:2021.0.0.0 -两种上下文(终端和MCP)的成功。也就是说,管道存在且可用。问题完全在于客户端库计算的名称不正确。
第一个选择是替换一个字段
// Загружаем ModelInternal вручную (он не грузится автоматически)
var modelInternalPath = Path.Combine(bridgeDir, "Tekla.Structures.ModelInternal.dll");
Assembly.LoadFrom(modelInternalPath);
// Находим класс Remoter и правим ChannelName
var remoter = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => { try { return a.GetTypes(); } catch { return Array.Empty(); } })
.First(t => t.Name == "Remoter" && t.Namespace?.Contains("ModelInternal") == true);
var field = remoter.GetField("ChannelName", BindingFlags.Static | BindingFlags.NonPublic);
field.SetValue(null, "Tekla.Structures.Model-Console:2021.0.0.0");结果: Model连接. check_connection 我做的。 🎉
______________________________________________________________________
第3阶段图纸不起作用-Drawing IPC也坏了
在Model成功之后,添加了Drawing API工具。测试显示:
check_connection,get_selected_elements_properties-工作✅list_drawings→RemotingException: Failed to connect to an IPC Port❌
原因:Control-Tekla图纸API- 独立IPC频道 在一个单独的内部组装。
三个子系统的通道:
ModelInternal.dll→Tekla.Structures.Model-Console:2021.0.0.0DrawingInternal.dll→Tekla.Structures.Drawing-Console:2021.0.0.0TeklaStructuresInternal.dll→Tekla.Structures.TeklaStructures-Console:2021.0.0.0
第一个修正符只修正符 ModelInternal调用Drawing API时加载 DrawingInternal.dll 你的管道断了。
尝试:显式下载drawinginternal
Assembly.LoadFrom(Path.Combine(dir, "Tekla.Structures.DrawingInternal.dll"));
// + повторить поиск-и-замену для Drawing Remoter为Drawing工作。PDF导出(export_drawings_to_pdf还是跌倒了 TeklaStructuresInternal.
______________________________________________________________________
第4阶段最终固定扫描所有内部集合的值模式
每一个明显的例子。 *Internal.dll 做了一个通用的算法:
- 力载荷 全体
Tekla.Structures.*Internal*.dll从Teklabridge目录 - 扫描 一切 静态字符串 全体 下载的Tekla版本
- 任意值
Tekla.Structures.*-:*(即有-:空后缀)→替换-:的-Console:
// 1. Touch public assemblies чтобы они загрузились
_ = typeof(Tekla.Structures.Model.Model);
_ = typeof(Tekla.Structures.Drawing.DrawingHandler);
// 2. Force-load Internal сборки — они не грузятся автоматически
var dir = Path.GetDirectoryName(typeof(DrawingHandler).Assembly.Location) ?? "";
foreach (var dll in Directory.GetFiles(dir, "Tekla.Structures.*Internal*.dll"))
try { Assembly.LoadFrom(dll); } catch { }
// 3. Сканировать все поля, исправить по значению
var bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
if (!asm.GetName().Name.StartsWith("Tekla.Structures")) continue;
Type[] types; try { types = asm.GetTypes(); } catch { continue; }
foreach (var t in types)
foreach (var f in t.GetFields(bindingFlags)) {
if (f.FieldType != typeof(string)) continue;
try {
var val = f.GetValue(null)?.ToString() ?? "";
if (val.StartsWith("Tekla.Structures.") && val.Contains("-:"))
f.SetValue(null, val.Replace("-:", "-Console:"));
} catch { }
}
}关键细微差别:
- 检查 在意义上,而不是类/字段名称-内部类名称可以在Tekla版本之间更改
GetTypes()在try/catch中翻转-某些构建包含不依赖于解析器的类型- B.其他事项NET Framework 4.8可以通过Reflection重写READONLY STATIC字段(由于RVA字段,在.NET 8中不再工作)
- Fix必须执行 到 创建
new Model()或new DrawingHandler()-静态类构造函数在第一次调用时运行一次
结果 C:\temp\tekla_channel.txt 在最后的固定:
Fixed 3 channel(s):
FIXED Tekla.Structures.ModelInternal.Remoter.ChannelName: Tekla.Structures.Model-:2021.0.0.0 -> Tekla.Structures.Model-Console:2021.0.0.0
FIXED Tekla.Structures.DrawingInternal.Remoter.ChannelName: Tekla.Structures.Drawing-:2021.0.0.0 -> Tekla.Structures.Drawing-Console:2021.0.0.0
FIXED Tekla.Structures.TeklaStructuresInternal.Remoter.ChannelName: Tekla.Structures.TeklaStructures-:2021.0.0.0 -> Tekla.Structures.TeklaStructures-Console:2021.0.0.0______________________________________________________________________
第5阶段另一个问题是Tekla在控制台上写。Out
在第一次测试中,Teklabridge JSON输出被Tekla内部诊断“污染”:
[TeklaDebug] Connecting to IPC...
[TeklaDebug] Channel resolved: ...
{"status":"connected","modelName":"..."}MCP服务器无法解压缩响应,JSON不是第一行。
决定:在第一次访问Tekla API之前 Console.Out:
var realOut = Console.Out;
var teklaLog = new StringWriter();
Console.SetOut(teklaLog); // Tekla пишет сюда
// ... работаем с Tekla API ...
// Весь наш вывод — только через realOut
realOut.WriteLine(JsonSerializer.Serialize(result));
// Диагностика Tekla доступна при ошибках
var diag = teklaLog.ToString().Trim();______________________________________________________________________
第6阶段Deploy的问题
EXE已锁定Claude Desktop
Claude Desktop支持 TeklaMcpServer.exe 开放所有的工作时间。当你试图转换:
error MSB3021: Unable to copy file ... Access to the path is denied.决定:总是关闭Claude Desktop之前 dotnet build如果只更换了Teklabridge,它可以被热回收,因为 bridge/TeklaBridge.exe 没有锁定。
NuGet还原послеgit回滚
之后 git checkout 以前的报告出现错误:
NETSDK1004: Assets file 'project.assets.json' not found.
Run a NuGet restore to generate this file.原因: obj/ 已添加到 .gitignore 从Git中删除。checkout之后 project.assets.json 无。
决定:
dotnet restore src/TeklaBridge/TeklaBridge.csproj
dotnet build ...重构后的文件冲突
从单元格转换为单元格 ModelTools.cs 对于子目录中的partial类,旧文件保留在磁盘上(未通过Git删除)。编译器抱怨类重复。
决定:明确删除 rm src/TeklaMcpServer/ModelTools.cs Git Restore之后
______________________________________________________________________
第7阶段遗产:通过宏创建GA绘图
create_general_arrangement_drawing 仅作为临时遗产工作区保存。为了进一步开发绘图块,我们使用开放API,而不是宏。
历史上,GA采用了宏方法,因为它重复了Saved Model View的常规UI工作流。这不是进一步开发的推荐路径:它取决于UI、本地化和对话框元素的内部名称。
算法 :
- 了解
XS_MACRO_DIRECTORY通过TeklaStructuresSettings.GetAdvancedOption - 记下临时的
.cs宏文件到子目录modeling/ - 引起
Operation.RunMacro(macroName)等待完成IsMacroRunning() - 删除临时文件
细微差别:
- 文件名必须没有路径-仅
macroname.cs目录自动定义 - 宏
modeling/仅在模拟模式下可用,在drawings/-在绘图编辑器中 RunMacro异步, 需要通过投票IsMacroRunning()超时
______________________________________________________________________
第9阶段Tekla Structures 2025支持
在切换到TS2025后,Teklabridge停止了连接,出现了一个新的错误:
RemotingIOException: Cannot connect to remoting service
'Tekla.Structures.Model-TeklaStructures-Console:2025.0.0.0' because it does not existTS2025中的车辆更换
Ts2025取代 .NET Remoting (命名管道)на Trimble.Remoting 楼上 内存映射文件 (MMF)。 MMF对象的名称不包括汇编版本,而是 文件版本 安装了DLL。
| TS2021 | TS2025 | |
|---|---|---|
交通。 System.Runtime.Remoting,命名管道 | Trimble.Remoting,MMF | |
频道名称 Tekla.Structures.Model-Console:2021.0.0.0 | Tekla.Structures.Model-TeklaStructures-Console:2025.0.52577.0 | |
Nuget版本 2021.0.0.0 =文件版本 | 2025.0.0.0 ≠文件版本 2025.0.52577.0 |
尝试1:通过Reflection运行时补丁
从安装的DLL读取FileVersion FileVersionInfo.GetVersionInfo() 更新 静态场 ChannelName 在下载的Nuget版本中。 没用 -静态 Nuget DLL构造函数在补丁时尚未运行。 Remoter.ChannelName 曾是 null.
解决方案:从exe.config的extensions文件夹运行
正确的方法-下载 规定 Tekla DLL(带有正确的FileVersion)而不是Nuget副本。
- Teklabridge.exe 复制到:
C:\TeklaStructures\2025.0\Environments\common\extensions\svMCP\
- 并列
TeklaBridge.exe.configс `` 所有Tekla/Trimble DLL版本:
- 当Teklabridge从这个文件夹运行时,CLR会抓取
exe.config下载
DLL从 C:\TeklaStructures\2025.0\bin\ -有fileversion 2025.0.52577.0频道工作。
- TeklaMcpServer 如果存在:
private static string ResolveBridgePath() {
// Newest TS >= 2025 with TeklaBridge.exe in extensions folder takes priority
var extensionsBridge = Directory.GetDirectories(@"C:\TeklaStructures")
.Where(d => Version.TryParse(...) && v.Major >= 2025)
.OrderByDescending(...)
.Select(d => Path.Combine(d, "Environments", "common", "extensions", "svMCP", "TeklaBridge.exe"))
.FirstOrDefault(File.Exists);
return extensionsBridge ?? localBridgePath;
}其他更改(Teklabridge/Program.cs)
- API版本定义:
typeof(Model).Assembly.GetName().Version?.Major = 2025→ApplyTs2025ChannelVersionFix()(读取FileVersion,如果字段初始化,则补丁)- BIN路径定义:TS2021-
nt/bin/,TS2025--bin/直接 XS_DIRTs2025=根文件夹(C:\TeklaStructures\2025.0) 无nt/子目录
结果
问题,原因,解决。 |---|---|---| ÐÐÐÐÐÐÐÐÐÐÐÐÐ 2025.0.0.0, а не 2025.0.52577.0 ≫从扩展文件夹启动,DLL通过下载 ` из安装目录| ≫构建找不到TS2025路径 nt/bin/ 添加检查 bin/ 直接 。 | XS_SYSTEM 指向TS2021 DetectTeklaRootForMajor` 返回空›修复了目录检查›
______________________________________________________________________
结果(所有版本)
问题,原因,解决。 |---|---|---| ÐIPC从管道(TS2021)不起作用›Tekla根据stdout类型计算频道名称 *Internal 频道前 new Model() | Drawing API无法连接 DrawingInternal.dll 不自动加载 *Internal*.dll | PDF出口下降 TeklaStructuresInternal 也坏了 -: | ≫JSON输出中的垃圾≫Tekla在控制台中写道。Out→截取控制台。Out to API调用› Ðexe锁定¸Claude Desktop保持文件打开¸在重新编译前关闭Claude Desktop¸ git之后的netsdk1004 obj/ 在Gitignore。 dotnet restore 在build之前 | filter_model_objects 一直都是0。 is Beam 不适用于IPC代理+ "count" 对比 "Count" | GetType().Name 两种形式的钥匙 ÐÐÐÐÐÐÐÐÐÐÐÐÐ 2025.0.0.0 ≠已安装 2025.0.52577.0 ≫扩展-文件夹+exe.config `` на已安装DLL|
______________________________________________________________________
第8阶段filter_model_objects_by_type:两个隐藏的bug
过滤完成后,工具返回 count: 0 对于任何类型,尽管模型中有对象。
第一组: is Beam 不适用于。net remoting代理
GetAllObjects() 通过IPC返回对象 透明代理运营商 is 验证本地构建的类型身份-对于代理,这总是 false,即使 GetType().Name == "Beam".
// Было (всегда false для IPC-объектов):
modelObject is Beam
// Стало:
modelObject.GetType().Name.Equals("Beam", StringComparison.OrdinalIgnoreCase)诊断显示: GetType().Name 返回 "Beam" 正确的,所以类型是正确的-但是运算符 is 他不承认。这是一个特殊的。Net Remoting:代理对象不是本地代理对象的实例 Beam尽管他表现得像他。
第二组: "count" 对比 "Count" JSON属性寄存器
System.Text.Json 属性序列化 名为C#字段AS-IS (帕斯卡案例→ "Count").
// FilteredModelObjectsResult сериализуется как:
{ "Count": 59, "ObjectIds": [...] }
// Обёртка искала (camelCase):
doc.RootElement.TryGetProperty("count", ...) // всегда false → count = 0
// Исправлено:
doc.RootElement.TryGetProperty("Count", ...) || doc.RootElement.TryGetProperty("count", ...)为什么以前没注意到: select_by_class 和 get_selected_weight 使用匿名C#对象(new { count })它们的字段以小写字母序列化,并与预期键匹配。 FilteredModelObjectsResult 所谓的班级,不。
标签:Autofetch和Foreach
GetObjectsByFilter 返回 ModelObjectEnumerator,实现 IEnumerable但是 foreach B.其他事项Net Remoting上下文不可靠。改为明确 MoveNext().还添加了 ModelObjectEnumerator.AutoFetch = false -如果没有它,在外部过程的上下文中,对象的后台交换可能会中断。
