ARTICLE DETAIL

资讯详情

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

SolidWorks二次开发模板:C# Add-in插件从零搭建与避坑指南

SolidWorks二次开发模板:C# Add-in插件从零搭建与避坑指南 简介面向机械设计与CAD二次开发工程师的SolidWorks SDK入门模板以C#语言为例展示如何通过COM接口与.NET类库扩展SolidWorks功能适合需要自动化建模、定制工具栏与命令的开发者快速建立项目骨架。压缩包共99个文件核心为34个dll动态库、18个cs源码文件以及exe可执行程序、resx/resources资源文件、xml配置和bmp图标等整体大小10.24MB包含完整的Visual Studio解决方案与插件注册相关信息。内容覆盖SDK基础调用、ISldWorks实例获取、Add-in插件实现、Windows Forms界面定制、命令与事件处理、PMP页面及工具栏图标设计等模块可作为从零搭建二次开发项目的参考模板。已有726人学习下载适合希望系统了解SolidWorks二次开发流程、快速上手C#插件编程的初学者或中级开发者。1. SolidWorks二次开发模板别让“录好的宏”变成“搬不完的坑”做非标自动化那会儿我最烦的活是给几十个零件批量写“图号、材料、表面处理”这三个自定义属性。SolidWorks自带宏录制能解决一半问题——录一遍、循环跑确实省事。可一旦想让车间同事也用上就得把宏搬进Add-in插件加个菜单按钮再装到他们机器上。这一步我折腾了整整三天COM对象莫名失效、注册后菜单加载不出来、换台电脑就崩。后来我把整套工程结构抽成了模板把二次开发里最容易翻车的“工程脚手架”一次性补齐正确的引用方式、x64注册、属性管理页生命周期、日志输出。这份模板适合三类人写参数化插件却总在环境问题上卡壳的工程师、想把宏升级成正式插件的工艺人员、以及刚被安排“用SolidWorks API搞批量出图”的倒霉蛋。2. 模板结构与选型为什么C# Add-in 属性管理页是二次开发的起点2.1 模板里到底放了什么两层脚手架而不是一堆示例很多网上的“二次开发模板”其实是一堆示例代码堆在一起从零件绘制到装配体遍历都有但你复制过来根本连编译都过不了。我拆过多次后发现真正有用的模板应当是“两层”结构第一层解决工程生命周期第二层才是业务API示例。这份模板按下面这个目录组织SwExtensionTemplate/ ├─ SwExtensionTemplate.csproj ├─ SwExtensionTemplate.cs ├─ Properties/ │ └─ AssemblyInfo.cs ├─ Addin/ │ ├─ SwAddin.cs // Add-in入口与菜单命令注册 │ ├─ SwAddinRegistration.cs // 注册表写入与卸载清理 │ └─ SwAddinAttributes.cs // 版本、描述、当前文档类型限定 ├─ UI/ │ ├─ PropertyManagerPage.cs // 属性管理页生命周期 │ └─ PropertyManagerPageControl.cs ├─ Api/ │ ├─ DocumentUtils.cs // 文档类型判断、路径、自定义属性 │ ├─ FeatureWalker.cs // 特征树遍历 │ ├─ AssemblyMateReader.cs // 装配体配合读取 │ └─ Log.cs // 文件日志输出 └─ Resources/ └─ CommandButton.bmp // 菜单按钮图标SwAddin.cs负责实现ISwAddin接口这是SolidWorks识别插件的入口。SwAddinRegistration.cs里写了注册表项的写入逻辑而不是让你手动去改注册表。UI目录下的PropertyManagerPage相关文件处理右侧属性管理页的创建与销毁这是多数二次开发界面最容易被忽略的部分——很多人只做菜单不做属性页最后用户输参数还得靠Excel驱动。2.2 选型理由宏、VSTA与Add-in的边界选型不是越复杂越好得看用途。VBA宏适合自用、一次性脚本VSTA适合需要和SolidWorks一起打包、低分发给少量内部用户的场景C# Add-in则是交付给多台机器、需要强健生命周期管理的选择。它支持事件钩子、属性管理页、右键菜单、自定义选项卡还能建独立的安装包。我一般建议项目里至少有“宏→Add-in”的迁移路径因为录制的宏能快速验证API调用方式而Add-in才能承载按钮、面板、批量处理这些正式功能。这份模板选的是Add-in方案依赖.NET Framework 4.8和SolidWorks Interop库。它不依赖具体版本号编译时会自动引本机安装的SolidWorks.Interop.sldworks.dll和SolidWorks.Interop.swconst.dll这样在2018到2024各版本上都能编译。2.3 SolidWorks API的核心调用路径从文档对象到特征树SolidWorks的API是典型的两段式调用先拿到ISldWorks应用对象再由它获取当前活动文档IModelDoc2之后才能深入零件、装配体和工程图。模板里的DocumentUtils.cs把这个过程固化成一个方法public IModelDoc2 GetActiveDocument() { ISldWorks swApp (ISldWorks)GetSwAppInstance(); if (swApp null) return null; ModelDoc2 doc swApp.ActiveDoc as ModelDoc2; if (doc null) { Log.Warn(没有打开的文档请在SolidWorks中先打开一个零件或装配体。); return null; } return doc; }GetSwAppInstance()用的是Marshal.GetActiveObject(SldWorks.Application)或进程内接口注入模板里两者都封装好了。注意ModelDoc2是早期版本遗留的类型现在仍然可用配合IModelDoc2接口使用不会有兼容问题。调用路径理顺后后续三个常用模块——自定义属性、特征遍历、装配体配合读取——都挂在同一条线上。这个模板的价值在于它预设了注册、菜单、属性页这些“环境代码”你下载后只需要改命名空间和UI文案直接往Api目录里加业务逻辑。相比自己从零搭一个Add-in工程能省掉至少一整天的查文档时间。3. 把模板跑起来从零到生成第一个工具面板3.1 解压、改名、编译、注册的完整步骤下载这份模板后不要直接双击.sln编译先确认本机SolidWorks版本和.NET环境。假设你用的是SolidWorks 2022 Visual Studio 2022按下面步骤操作mkdir D:\Dev\MySwExtension # 将模板内容解压到该目录 # 修改文件名和命名空间将 SwExtensionTemplate.csproj 改为 MySwExtension.csproj # 用VS打开工程后Find Replace 将 SwExtensionTemplate 替为 MySwExtension msbuild MySwExtension.csproj /p:ConfigurationRelease /p:Platformx64编译前在项目属性里确认目标平台为x64并关闭“首选32位”选项。SolidWorks 2020之后是纯64位进程混用AnyCPU会在运行时踩到类型加载或接口调用崩溃。编译通过后注册插件前先关闭SolidWorks然后用管理员权限执行C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe /codebase D:\Dev\MySwExtension\bin\x64\Release\MySwExtension.dllRegAsm会在HKEY_CURRENT_USER\Software\SOLIDWORKS\AddIns下写入插件注册表项。模板里的SwAddinRegistration.cs已经把/codebase所需的AssemblyInfo属性ComVisible、Guid配好了不会出现“注册后找不到程序集”的问题。3.2 注册Add-in时如何处理CEF启动错误与管理员权限这步是新手最容易翻车的地方。SolidWorks 2020以后内置了CEF组件用于UI渲染装过旧版本时经常报error 1714. The older version of CEF for SOLIDWORKS applications cannot be removed。这个报错出现时Add-in注册其实已经写进注册表了但SolidWorks启动时会因CEF组件状态异常而中断加载或直接闪退。处理方式先做注册表清理再重装CEF运行时。用WinR输入regedit定位到HKEY_LOCAL_MACHINE\SOFTWARE\SolidWorks\Addins和HKEY_CURRENT_USER\Software\SolidWorks\AddIns删除目标插件对应的GUID项然后从控制面板修复或卸载CEF for SOLIDWORKS组件再重新安装对应版本。这是环境问题不是代码问题但如果不提前处理后续每次调试都会浪费十分钟。3.3 第一次运行在SolidWorks界面里找到你的命令按钮启动SolidWorks后菜单栏会出现“工具”→“插件”选项在插件列表里勾选“MySwExtension”。如果此时右侧没有出现属性管理页而是只有菜单命令说明模板的菜单注册逻辑生效了。点击菜单命令后模板会在当前文档右侧弹出属性管理页public int RunCommand() { PropertyManagerPage pmp new PropertyManagerPage(); pmp.Show(swext, 批量属性写入, MySwExtension); return 0; }第一次运行时我建议用调试器直接F5。Visual Studio中设置“启动外部程序”为C:\Program Files\SOLIDWORKS Corp\SOLIDWORKS\SLDWORKS.exe命中断点后逐行走能看到SwAddin.cs里ConnectToSW方法触发过程。日志文件默认输出到%TEMP%\MySwExtension.log注册成功与否、菜单是否挂上都能在日志里看到线索。4. 常用模块代码拆解自定义属性、特征遍历与装配体4.1 自定义属性写入这是BOM提取与工程图映射的基础自定义属性是SolidWorks二次开发里最刚需的功能。模板的DocumentUtils.cs里实现了一个按配置名写入属性的方法它兼容“配置特定”和“整个文件”两种场景public bool SetCustomProperty(IModelDoc2 doc, string configName, string propName, string value) { ICustomPropertyManager cpm null; if (string.IsNullOrEmpty(configName)) // 空配置名 写入到“整个文件”层级 cpm doc.Extension.CustomPropertyManager[]; else cpm doc.Extension.CustomPropertyManager[configName]; if (cpm null) return false; bool wasExisting cpm.Get(propName).valueSet; cpm.Set(propName, value); // Set第二个参数为“按照线框显示”的文本值 Log.Info($属性 {propName} 在配置 {configName} 中已更新原值存在{wasExisting}); return true; }ICustomPropertyManager后跟的索引器参数不是配置名数组下标而是配置的“友好名称”——空串代表文件级实际配置名如Default或Part_Config_01代表特定配置。cpm.Get(propName).valueSet用于区分“属性存在但值为空”和“属性不存在”两种情况批量写入时这个判断很重要比如材料属性可能需要覆盖图号属性可能要保持原样。写完后调用doc.ForceRebuild3(true)触发一次重建保证属性变化传播到工程图的自定义表格。这条在模板里放在RefreshDocument方法里必要时批量操作会多次调用。4.2 特征树遍历识别“库特征”与“阵列”并标记非标零件里经常混入大量库特征与阵列遍历特征树时如果全量处理性能会拖垮插件。模板的FeatureWalker.cs用递归方式遍历全部特征但允许传入特征类型筛选器public void Walk(IModelDoc2 doc, int[] featureTypes) { Feature root (Feature)doc.FirstFeature(); RecursiveVisit(root, featureTypes, 0); } private void RecursiveVisit(Feature feat, int[] featureTypes, int depth) { while (feat ! null) { string featType feat.GetTypeName2 null ? : feat.GetTypeName2; if (featureTypes null || featureTypes.Contains(feat.GetTypeName2.GetHashCode())) { Log.Info(${new string( , depth * 2)}{feat.Name} [{featType}]); } Feature subFeat feat.GetFirstSubFeature(); if (subFeat ! null) RecursiveVisit(subFeat, featureTypes, depth 1); feat feat.GetNextFeature(); } }GetTypeName2返回的是特征类型字符串而不是类型ID比如“Fillet”“Pattern”“CutListFolder”等所以判断时要和模板里featureNameMap做映射不能直接转int。模板里预置了常用类型Fillet、Chamfer、LinearPattern、CircularPattern、MirrorPattern。遍历时用深度参数控制缩进方便日志里看出父子层级。注意GetFirstSubFeature只对部分特征有效比如阵列特征、多实体焊件普通拉伸特征直接返回null。4.3 装配体配合遍历读取配合名称与配合类型自定义属性管BOM装配体配合读取管的是装配工艺文档自动生成。模板的AssemblyMateReader.cs遍历活动装配体中所有配合对象public void DumpMates(IAssemblyDoc asmDoc, bool includeHidden) { Feature feat asmDoc.FeatureByPositionReverse(0) as Feature; while (feat ! null) { if (feat.GetTypeName2 MateGroup) { Feature mate feat.GetFirstSubFeature(); while (mate ! null) { if (includeHidden || mate.IsSuppressed() false) { Log.Info($配合名称: {mate.Name}); // 配合类型在 mate.GetSpecificFeature2() 中 IMateFeatureMateData mateData mate.GetSpecificFeature2() as IMateFeatureMateData; if (mateData ! null) Log.Info($ 类型: {mateData.Type}, 关联面数: {mateData.EntityCount}); } mate mate.GetNextFeature(); } } feat feat.GetNextFeature(); } }配合对象全部挂在“配合”根节点下遍历时先找MateGroup特征再进入子特征循环。GetSpecificFeature2返回的具体特征类型因SolidWorks版本不同有差异模板里以IMateFeatureMateData为例它包含配合类型枚举重合0、同轴1、距离2和关联实体数这些数据足够生成装配流程图。如果只要配合名称不用调用GetSpecificFeature2那个接口在部分旧版本上会抛异常建议用try/catch包住。5. 避坑与常见问题崩溃、注册表和COM对象的临终之争5.1 日志先行用模板自带的Log先别问“为什么崩”二次开发遇到的崩溃有一半是“环境玄学”——插件在开发机正常装机就崩。模板里带的Log.cs把所有关键调用点写成文本日志这是排查崩溃的第一工具。日志级别分Info/Warn/Error默认写到%TEMP%下打开后能看到Add-in的完整生命周期加载、菜单注册、属性页创建、属性写入、销毁。常见的崩溃场景是用户报“插件一打开就闪退”实际上日志里已经写明了“属性页创建失败”或“文档类型不匹配”。我建议所有内部迭代都用日志驱动而不是靠MessageBox一步步弹窗因为弹窗本身打断API调用链某些情况下会掩盖时序崩溃。5.2 三个高频崩溃AnyCPU、GC回收与属性页事件泄漏第一个高频问题是编译目标选了AnyCPU导致类型加载失败。现象是插件在VS调试时正常部署到客户机器后SolidWorks启动时提示“Cannot load assembly”。原因是SolidWorks是64位进程AnyCPU在运行时可能被JIT成32位加载64位Interop时抛出异常。解决方式是固定x64平台并保证发布的是bin\x64\Release下的产物。第二个高频问题是被垃圾回收的COM对象。现象是宏转译的代码在循环里跑了几个零件后突然抛COMException而且报错位置不固定。原因是C#局部变量持有的COM对象在函数结束后被GC释放但SolidWorks内部仍引用。解决方式是在模板的GlobalVariables.cs里用静态字段保存ISldWorks实例且不要显式调用Marshal.ReleaseComObject——这个调用以讹传讹了很久实际在SolidWorks Interop场景下反而会提前释放底层COM对象。让GC自然管理配合GC.KeepAlive。第三个高频问题是属性管理页二次打开时崩溃。现象是第一次点击菜单打开属性页正常关闭后再打开SolidWorks直接卡死或无响应。原因是属性页时事件没有解绑比如OnClosing和OnDestroyHandler里没有移除控件事件导致第二次打开时事件重复挂接。模板在PropertyManagerPage.cs的DestroyHandler里做了完整的解绑不要为了省事把这个方法掏空。5.3 卸载残留与CEF错误注册表清理的边界我遇到过最烦的坑是插件卸载后SolidWorks“插件”列表里仍然能勾选该插件勾选后加载失败。现象是Add-in已经卸载但注册表项还在。原因是卸载时没执行RegAsm /unregister或安装包没有删除注册表项。模板的SwAddinRegistration.cs里通过AssemblyInfo声明的[ComRegisterFunction]和[ComUnregisterFunction]方法负责写入和清理手动安装时记得在卸载前执行regasm /unregister。顺带说另一个常见的错误码error 1714。它虽然发生在安装阶段却会被误判为插件问题。现象是安装SolidWorks或安装插件时提示“The older version of CEF for SOLIDWORKS applications cannot be removed”然后安装中止。原因是CEF组件在卸载旧版本时注册表残留了DisplayName和UninstallString指向不存在的目录。解决方式是先用Windows Installer修复SolidWorks主程序不行就手动删掉HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall下所有CEF相关键值再重新装。这个过程有个边界只删CEF键值绝对不要碰SolidWorks主程序的注册表否则会引发“无法连接到服务器”或版本验证失败。另外如果你卸过PSTool这类第三方工具它的残留可能占用了SolidWorks插件GUID再次勾选时会跳到PSTool的加载逻辑。这种冲突表现是插件列表里有两个同名项只能靠检查注册表GUID来区分。模板里为每个插件生成了独立GUID不要复制使用否则两台机器上会互相覆盖。6. 进阶用法把模板扩展成参数化零件生成器6.1 用尺寸参数集驱动模型模板里预设的SetDimension方法是把参数化模板从“读取设计表”变成“直接改尺寸”的关键。在SolidWorks中每个被标记为“从动”或“驱动”的尺寸都有对应的名称例如D1草图1通过Parameter对象可以完成重命名、赋值与重建。public bool SetDimension(IModelDoc2 doc, string dimName, double newValue) { Dimension dim doc.Parameter(dimName) as Dimension; if (dim null) { Log.Warn($尺寸 {dimName} 未找到请检查尺寸名称是否为 D1草图1 形式); return false; } dim.SetSystemValue3(newValue, (int)swSetValueChange_e.swSetValueInThisConfiguration, null); doc.EditRebuild3(); return true; }用dim.SetSystemValue3而不是dim.SystemValue newValue是因为SetSystemValue3能指定写入哪个配置并支持单位换算。参数传入的newValue必须是米制单位SI不是用户当前显示的毫米值。比如界面显示50mm传入0.05。这是参数化驱动最容易踩的单位坑模板的UnitConvert.cs里做了mmToM与mToMm的封装批量驱动时强制统一用米作为内部变量。6.2 验证与习惯每次改配置都跑一遍“重建更新属性”参数化模板的最后一环是验证否则尺寸改了、工程图没更新交付时才发现就晚了。我的习惯是每次改动尺寸集合后强制调用一次ForceRebuild3(true)然后重新读取所有自定义属性并与输入值比对。这个方法在模板里叫ValidateResult它会遍历当前配置下的体积、质量、自定义属性如果和预设偏差超过0.5%日志输出Error级别提示。从那以后我每次接手SolidWorks二次开发项目都会强制先把模板的日志打开、GUID改掉、目标平台锁定x64然后再动业务代码。这套流程救了我好几回至少把“玄学崩溃”变成“日志说话”。希望帮到你。本文还有配套的精品资源点击获取
返回列表