SolidWorks二次开发实战:从零构建solidworkstools.dll插件
简介基于 VB.NET 的 SolidWorks 二次开发示例包面向机械设计自动化开发人员与制造业信息化工程师演示如何调用 solidworkstools.dll 完成模型操作、装配管理、参数驱动与自定义用户界面等典型场景。压缩包共 40 个文件约 732KB主体为 Visual Studio 解决方案与 VB 源码6 个 .vb、工程配置 .vbproj、解决方案 .sln同时附带编译生成的 exe/dll、PDB 调试符号、XML 注释及少量资源文件可结合源码与可运行程序对照学习。已有 1878 人学习下载适合刚接触 SolidWorks API 的开发者快速上手。通过该 Demo 可掌握 VB.NET 调用二次开发接口的基本流程、常见对象的调用方式以及从代码编写到生成可执行插件的完整项目结构为后续开发企业级智能设计工具打下基础。1. 从 SolidWorks API 到 solidworkstools.dll我先把这条链讲清楚很多人拿到solidworkstools.dll这个名字下意识以为它是一个官方提供的“二次开发工具箱”装上就能调出各种现成功能。实际不是。在 SolidWorks 二次开发里绝大多数情况下这个 DLL 是别人或者你自己通过 SolidWorks API 编译出来的自定义插件或类库文件名只是项目里顺手起的一个名称。真正决定它能干什么的是里面的代码是否调用了SolidWorks.Interop.sldworks和SolidWorks.Interop.swconst这两个程序集。你需要的不是“找这个 DLL 的教程”而是搞清楚一个 Demo 从新建项目、引用 API、编写插件类到注册调用的完整链路。这篇就按我平时从零搭一个solidworks二次开发Demo 的路径来讲先说清模型和选型再给最小可运行代码再讲参数、调试和分发时最容易踩的坑。适合用 C# 做过桌面程序、但对 SolidWorks API 的 COM 互操作还不太熟的工程师。2. 开发环境与 API 引用顺序这部分错一个后面全白费2.1 先分清两种二次开发方式插件Add-in与独立程序StandaloneSolidWorks 二次开发常见两种形态一种是加载到 SolidWorks 进程里的 Add-inCOM 注册后出现在插件菜单另一种是独立的.exe程序通过Rotate或CreateObject连接 SolidWorks 实例。solidworkstools.dll如果做成 Add-in本质上也是一个被 COM 注册的 .NET 程序集如果是 Standalone 程序的类库则只是被普通引用。这个区别决定了后续的注册方式。在 Demo 阶段我建议先做 Add-in。原因有两点一是它可以直接挂钩菜单事件适合演示“选择模型→读取属性→修改配置”的交互流程二是官方开发模板默认输出 Add-in参考资料最多。Standalone 模式适合做批量处理工具比如批转格式、批量改名但调试时需要先启动 SolidWorks 再连进程稍麻烦。2.2 引用哪些 Interop 程序集版本怎么选新建一个 C# 类库项目后要手动添加以下引用。不要在 GAC 里乱找直接到 SolidWorks 安装目录下的api\redist文件夹找ItemGroup Reference IncludeSolidWorks.Interop.sldworks HintPathC:\Program Files\SOLIDWORKS Corp\SOLIDWORKS\api\redist\SolidWorks.Interop.sldworks.dll/HintPath EmbedInteropTypesFalse/EmbedInteropTypes /Reference Reference IncludeSolidWorks.Interop.swconst HintPathC:\Program Files\SOLIDWORKS Corp\SOLIDWORKS\api\redist\SolidWorks.Interop.swconst.dll/HintPath EmbedInteropTypesFalse/EmbedInteropTypes /Reference /ItemGroup注意这里EmbedInteropTypes必须设为False。如果设为 True运行时会出现“无法将类型‘XXX’转换为‘XXX’”的 Interop 类型嵌入错误。我在第一次写 Demo 时就被这个坑卡了半天。另外SolidWorks 2020 以上版本默认安装的是 .NET Framework 4.6.2 的 Interop 程序集你的项目目标框架最好也选 4.6.2 或 4.7.2别一上来就选 .NET 6/8。2.3 注册表权限与管理员运行Add-in 的 COM 注册需要向注册表写入HKEY_CURRENT_USER\Software\SolidWorks\Addins普通权限即可。但如果你按网上某些老教程用regasm注册到HKCUSolidWorks 有时读不到此时改为注册到HKLM需要管理员权限。建议在开发机上直接以管理员身份运行 Visual Studio并启用“生成后事件”自动注册。regasm $(TargetPath) /codebase /tlb这行命令的作用是将编译好的 DLL 注册为 COM 组件/codebase告诉系统从当前路径加载程序集不装进 GAC/tlb生成类型库。注册成功后注册表里会出现对应 GUID 的键值。3. 最小可运行 Demo菜单、宏录制与模型参数读取3.1 新建插件项目重写ConnectToSW与DisconnectFromSW我一般用 SolidWorks 自带的“SolidWorks Add-in”模板创建项目如果没有模板手动建类库也可以。核心是要实现ISwAddin接口。以下是一个能弹出菜单并读取当前零件名称的最小代码using System; using System.Runtime.InteropServices; using SolidWorks.Interop.sldworks; using SolidWorks.Interop.swconst; namespace SwToolsDemo { [ComVisible(true)] [Guid(A1B2C3D4-1234-4567-89AB-CDEF01234567)] public class Addin : ISwAddin { private SldWorks _swApp; private int _addinId; public bool ConnectToSW(object ThisSW, int Cookie) { _swApp (SldWorks)ThisSW; _addinId Cookie; return true; } public bool DisconnectFromSW() { Marshal.ReleaseComObject(_swApp); _swApp null; return true; } } }这段代码里ConnectToSW的ThisSW就是 SolidWorks 的 Application 对象Cookie是插件实例的唯一标识。只有返回trueSolidWorks 才会认为插件加载成功。Marshal.ReleaseComObject用于释放 COM 引用避免进程退出时 SolidWorks 卡住。3.2 添加菜单命令并关联回调菜单命令的注册稍显啰嗦但必须做。下面代码在“工具”菜单下添加一个名为“读取零件属性”的按钮private const int SWCMD_READ_PROPERTY 1; private void RegisterMenu() { string menuName SwToolsDemo.菜单; bool ret _swApp.AddMenuPopupItem( (int)swMenu_e.swMenuToolbar, menuName, SWCMD_READ_PROPERTY, 读取零件属性, 读取当前零件的自定义属性, _addinId, null); }AddMenuPopupItem的参数里swMenu_e.swMenuToolbar表示工具菜单menuName是菜单项的文字SWCMD_READ_PROPERTY是命令 ID需要在类里定义常量保持一致。回调函数用DllExport特性导出这里不再展开但记住一个原则命令 ID 必须唯一且回调方法的签名必须是void Callback(int commandId)。3.3 读取当前模型名称与自定义属性菜单点击后我们要拿到当前激活的文档。下面是读取文档名称和自定义属性Material的示例private void OnReadProperty() { ModelDoc2 model (ModelDoc2)_swApp.ActiveDoc; if (model null) { _swApp.SendMsgToUser(没有打开任何模型); return; } string name model.GetTitle(); string material ; // 读取自定义属性 CustomPropertyManager propMgr model.Extension.CustomPropertyManager[]; bool found propMgr.Get5(Material, false, out material, out _, out _); _swApp.SendMsgToUser($模型名称: {name}\n材料: {(found ? material : 未设置)}); }这里有两个容易出错的地方。一是CustomPropertyManager[]的空字符串表示“配置特定属性”中的默认配置如果要读取特定配置的属性需要把配置名称填进去。二是Get5是较新版本的 API旧版本用Get2或Get3参数数量不一样。如果编译报错检查一下你引用的 Interop 版本是否支持Get5。3.4 调试时机附加到 SolidWorks 进程写好代码后按 F5 调试Visual Studio 会启动 SolidWorks 并加载插件。如果没反应手动打开“工具→插件”勾选你的插件名称。之后在代码里打断点操作菜单即可进入调试。首次调试建议在ConnectToSW和回调函数入口各设一个断点能快速判断是注册失败还是调用失败。4. 深入 SolidWorks API遍历特征树与修改配置这里才是二次开发的核心价值4.1 遍历特征树的层级逻辑读取零件名称只是开胃菜。真正的批量自动化需求大多围绕“遍历所有特征找到某个指定特征并改参数”展开。SolidWorks API 里特征树是一个树形结构通过IFeatureManager和IFeature的GetFirstFeature/GetNextFeature遍历。private void TraverseFeatures(ModelDoc2 model) { FeatureManager featMgr model.FeatureManager; Feature root featMgr.GetFirstFeature(); while (root ! null) { // 只输出特征名和类型 string featName root.Name; int featType root.GetTypeName2(); Console.WriteLine($#{featName}, 类型: {featType}); // 进入子特征 Feature sub root.GetFirstSubFeature(); while (sub ! null) { Console.WriteLine($ └─ #{sub.Name}); sub sub.GetNextSubFeature(); } root root.GetNextFeature(); } }这里的GetTypeName2()返回的是特征类型字符串比如BossExtrusion、CutExtrusion、Fillet用它可以过滤特征。特征树结构里“子特征”指的是同一个特征下的草图、参考平面等不是装配体里的子装配关系。装配体遍历要用GetDependencies或GetComponents别混用。4.2 修改尺寸参数找到尺寸对象并赋值多数参数化设计需求是“改驱动尺寸重建模型”。实现思路是先通过特征名找到特征再通过特征找到尺寸。下面代码展示了如何修改拉伸特征的深度尺寸private void SetDimensionValue(Feature feature, string dimName, double newValue) { // 遍历该特征下的所有尺寸 object[] dims (object[])feature.GetDimensions(); if (dims null) return; foreach (DisplayDimension dim in dims) { if (dim.FullName dimName) { dim.Set2(newValue, 0, 0, true); break; } } }参数说明Set2(value, offsetX, offsetY, rebuild)的最后一个参数rebuild设为true表示设置后立即重建模型。如果尺寸名带前缀比如D1草图1零件1.SLDPRT需要完整匹配。建议在调用前先打印所有尺寸名确认格式再写匹配逻辑。4.3 配置切换与自定义属性写入处理多配置模型时常需要遍历所有配置并修改配置特定属性。下面代码使用ConfigurationManagerConfigurationManager cfgMgr model.ConfigurationManager; string[] configNames (string[])cfgMgr.GetConfigurationNames(); foreach (string cfgName in configNames) { // 激活目标配置 Configuration cfg cfgMgr.ActivateConfiguration(cfgName, false, false); if (cfg null) continue; // 修改该配置的自定义属性 CustomPropertyManager propMgr model.Extension.CustomPropertyManager[cfgName]; propMgr.Add3(批量标记, swCustomInfoType_e.swCustomInfoText, 已处理, 0); }注意ActivateConfiguration的第二个参数bool OnlyIfSuppressed设置为false表示即使有压缩特征也要激活第三个参数bool ResetDefaults设为false避免激活时重置到默认状态。另外批量修改配置属性时每次激活配置都会触发模型重建若模型复杂耗时会很长这是正常的。5. 打包与分发solidworkstools.dll真正要处理的三个边界问题5.1 目标机器没有安装 SolidWorks SDK 怎么办分发时目标机器通常只装了 SolidWorks没有 SDK 或用的是精简版。此时你的 DLL 依赖的SolidWorks.Interop.sldworks.dll不一定存在。稳妥做法是将 Interop DLL 复制到输出目录并设置“复制本地”为 True随插件一起分发。Reference IncludeSolidWorks.Interop.sldworks HintPath.../HintPath PrivateTrue/Private /ReferencePrivate属性对应“复制本地”。另外不要尝试用 NuGet 上的第三方 SolidWorks API 包代替官方 Interop版本不一致会导致运行时无法加载类型。5.2 保存文档时的名称冲突做过批处理的人会遇到一个问题SolidWorks API 打开文件后直接SaveAs3保存若目标文件名已存在会静默失败或覆盖。正确做法是保存前先检查文件是否存在using System.IO; string targetPath D:\output\ newName .SLDPRT; if (File.Exists(targetPath)) { File.Delete(targetPath); } int error 0; int warning 0; model.SaveAs3(targetPath, 0, 0, ref error, ref warning);参数说明SaveAs3的第一个参数是完整保存路径及文件名第二个Options传 0 采用默认项第三个ExportData传 0 表示不导出附加数据。error和warning是输出参数保存完成后要检查它们error非零说明失败warning非零说明保存时发生了警告比如单位换算。5.3 插件卸载时进程残留COM 互操作最典型的问题是 SolidWorks 进程退出后SldWorks对象未被释放导致进程挂在后台。严谨的卸载流程要两步public bool DisconnectFromSW() { // 1. 移除菜单命令 _swApp.RemoveMenuPopupItem(_addinId, SWCMD_READ_PROPERTY); // 2. 释放 COM 引用 while (Marshal.ReleaseComObject(_swApp) 0) { } _swApp null; GC.Collect(); GC.WaitForPendingFinalizers(); return true; }while (Marshal.ReleaseComObject(_swApp) 0)是保险写法因为 RCW运行时可调用包装计数可能大于 1。GC.Collect()强制回收不可达的 COM 对象但注意不能过度使用否则影响性能。这些动作做完后SolidWorks 能够干净卸载插件不再出现“退出后进程还在任务管理器”的现象。5.4 版本兼容表参考SolidWorks 版本Interop DLL 位置目标框架建议2018-2019api\redist.NET Framework 4.6.12020-2021api\redist.NET Framework 4.6.22022-2023api\redist.NET Framework 4.7.22024api\redist.NET Framework 4.8这里列的是常见组合具体还是要看安装目录实际文件的版本号。若目标机器有多个年份版本插件引用的 Interop 版本需与目标版本一致或者尝试后期绑定方式用Type.GetTypeFromProgID但那会让代码复杂许多Demo 阶段不推荐。6. 用宏录制反推 API 调用这是写出可靠二次开发代码的捷径6.1 录制宏的三种姿势如果你不确定某个操作对应哪个 API最快方法是宏录制。SolidWorks 的宏录制在“工具→宏→录制”里操作完停止后会生成.swpVBA 文件。把 VBA 代码翻译成 C# 时注意以下差异VBA 里Set swApp Application.SldWorks对应 C# 的(SldWorks)Activator.CreateInstance(Type.GetTypeFromProgID(SldWorks.Application))。VBA 里方法参数按位置传入C# 中参数名会出现在智能提示里但需要用Type.Missing占位。VBA 的Long对应 C# 的intDouble对应doubleString对应string。翻译时不要逐行照抄重点看操作序列和对象层级。比如录制一次“修改草图尺寸”流程是建立选择集、获取草图、获取尺寸、设置值。C# 里面对应的是GetDimensions和Set2比 VBA 直白得多。6.2 从 VBA 抓取默认参数值录制的宏里常会看到大量默认参数比如CreateCircle方法的圆心坐标和半径。这些参数在 Demo 里调试时很好用可以先写死跑通后再改成变量。我习惯在宏代码的每个方法调用前加一句Debug.Print把传入参数打印出来这样跑一次就能拿到准确的参数模板。6.3 常见的宏录制陷阱宏录制不会录下“视角旋转”“选中特征树节点”这类界面操作只会录下底层 API 调用。因此如果你录的是“右键删除特征”宏里不一定有Feature.Delete而可能是EditDelete。遇到这种情况按 F1 查 API 帮助里的IFeature方法列表确认Delete或Delete2是否可用。同理录制“隐藏零件”时宏里出现的是SetEntityVisibility不是Visible False。6.4 把宏结果固化到 Demo 代码的模板录制完、翻译完代码后我建议把代码段整理成一个带参数的模板函数。比如“批量把 STL 文件转成 SLDPRT”和“修改所有配置的密度”都能用模板固化。模板函数要独立成类放到solidworkstools.dll里供合作方二次引用。最终项目里的类名可以叫BatchOperationHelper内部包含TraverseFeatures、SetDimensionValue、SaveAllDocuments等方法外层 Add-in 只负责菜单注册与事件调度。这样的结构把界面逻辑和 API 操作分开后续要抽成命令行工具或写成服务都只用换壳不动核心。本文还有配套的精品资源点击获取