简介:SolidWorks二次开发全教程系列面向需要借助API与VBA实现建模自动化的工程师,以及刚接触SolidWorks宏开发的初学者,帮助读者掌握从录制宏到编辑、调试宏的完整流程。教程先从“录制一个宏”讲起,说明录制后代码通常不能直接使用,需要依据经验做调整;随后给出编辑或调试宏的操作路径,并提醒处理.swp与.swb文件时会出现自动转换。针对新宏,还具体列出三类需要删除的冗余代码:未用到的变量声明、切换视图的代码、以及紧邻ClearSelection2的无效选择调用。更进一步,教程结合代码示例讲解SelectByID2和GetSelectedObject5两个API,演示如何按特征名称选择对象并通过索引获取选中特征。整份内容为1个doc文档,压缩后仅276KB,篇幅精炼但关键点覆盖到位。目前已有6199人学习下载,适合作为SolidWorks二次开发入门和避坑参考。
1. SolidWorks二次开发全教程系列(靠谱)在解决什么:从录宏到插件的实际路线
网上能找到的 SolidWorks 二次开发资料并不少,但大多数是“给你一段能跑的宏,跑完就没了”:没有版本说明,没有对象模型讲解,也没告诉你怎么处理打开失败、批量卡死、换机器加载不出来的问题。真正靠谱的路线,是先理解 SolidWorks 对外暴露的 COM 接口,再从宏录制拿到第一段可回放代码,最后把它扩展成带日志、带回归测试、能交给同事用的工具。这篇就是按这条路线写的,面向机械结构工程师、工艺工程师和 CAD/PLM 集成开发,目标是让读者读完能动手做批量属性、参数化改尺寸、自动导出,并对常见翻车点有心理准备。
2. SolidWorks二次开发的API底层:为什么所有语言都绕不开COM对象模型
2.1 SolidWorks进程外COM服务器:拿到Application之后一切才开始
SolidWorks 本身不是一个独立 SDK,而是一个 COM 自动化服务器。你用 C#、VB.NET、Python、C++ 写二次开发,本质都是连到同一个 SldWorks 实例上调用接口。这就是为什么时间长了你会发现,不同语言写的代码长得完全不一样,但接口名、枚举值、调用顺序几乎一致。
典型调用顺序是:
- 创建或连接
SldWorks.Application - 用
OpenDoc6或ActiveDoc拿到当前模型 - 顺藤摸瓜,从
ModelDoc2往下找到ModelDocExtension、Feature、Dimension - 操作完成后保存并关闭文档
用 Python 做最小连接,常见写法是:
import win32com.client swApp = win32com.client.Dispatch("SldWorks.Application") swApp.Visible = True这里的Dispatch会启动或连接正在运行的 SolidWorks 实例。Visible = True表示把 SolidWorks 主窗口显示出来;在批量脚本里,我一般会让它显示,因为窗口隐藏时如果 API 弹出对话框,进程会一直等到超时,看起来就像假死。
需要特别留意:SolidWorks 是单进程应用,不要用CoCreateInstance的方式反复创建新实例,更不要指望“多开 SolidWorks 就能并行跑脚本”。我见过有人为了提升批量处理速度,循环里每次都用CreateObject去拿新实例,结果拿到的还是同一个进程,反而把命令行搞出一堆僵尸窗口。
2.2 开发语言怎么选:VBA、C#、Python和C++各自的硬边界
不用一上来就纠结“到底学哪种语言”,先看你的使用场景。我的经验如下:
| 写法 | 启动成本 | 适合场景 | 主要风险 |
|---|---|---|---|
| VBA 宏 | 最低 | 个人提效、原型验证、录宏改参数 | 难发布、难做日志和错误恢复 |
| Python | 低 | 批量文件处理、后台服务、测试脚本 | 需要装 pywin32,位数要匹配 |
| C# Add-in | 中 | 企业级插件、菜单、事件回调、日常驻留 | 版本绑定、COM 注册和清理 |
| C++ | 高 | 性能极敏感、深度内核集成 | 开发成本高,绝大多数项目用不上 |
如果只是给自己写小工具,Python 是划算的选择。pywin32可以直接调 SolidWorks 的 COM 接口,代码量比 C# 少,遇到问题也容易在命令行里试。pip install pywin32就能装。
如果要做成公司里所有人都能用的插件,我会选 C# Add-in。它能把功能挂到 SolidWorks 菜单栏,能订阅文档打开、保存、重建事件,也能把日志写到 Windows 事件日志或文件里。C# 的代价是“部署时踩坑”:DLL 的位数、SolidWorks 版本、.addin 文件路径,只要其中一个不对,插件就加载不出来。这个后面会具体讲。
VBA 宏也不是没用。新手第一次接触 API 时,最好的入口就是宏录制:录制一段操作,看它生成了什么代码,再反查每个接口在对象模型里的位置。这个习惯比多看十遍教程都管用。
2.3 先背下这张对象关系图:Application→ModelDoc→Feature→Dimension
SolidWorks 二次开发的对象模型,本质上是一棵树:
SldWorks:应用入口。负责打开文档、获取当前文档、设置系统选项。ModelDoc2:所有零件、装配体、工程图文档的基类。你拿到ActiveDoc后,首先会得到一个ModelDoc2。ModelDocExtension:从ModelDoc2.Extension拿到。属性写入、配置操作、参考引用等高级功能都挂在这里。PartDoc、AssemblyDoc、DrawingDoc:分别对应三种文档类型的接口,很多操作需要把ModelDoc2转换成具体类型再做。ConfigurationManager:管理配置,读取配置名称、激活配置。Feature:特征树里的节点。通过FirstFeature()和GetNextFeature()可以遍历所有特征。Dimension:尺寸对象。改参数化尺寸时,最常用的是ModelDoc2.Parameter("D1@Sketch1")。CustomPropertyManager:自定义属性,也就是标题栏、BOM、ERP 集成里写入的那些字段。
很多人从录宏开始学,录完以后不知道哪里改,就是因为没把这棵树记到心里。比如录制“在零件里添加自定义属性”,录出来的代码里会出现ModelDoc2、Extension、AddCustomProperty3;如果你知道Extension是高级操作的挂载点,就知道以后查找“属性、配置、附加数据”都要往这里找。
反过来,如果你录了一段“拉伸凸台”,录出来的代码会是一大串SketchManager和FeatureManager调用,这两者对应的是草图绘制和特征创建,和属性写入完全是两个分支。所以遇到问题先问自己:我现在是在操作文档对象、特征对象,还是尺寸对象?这一步想清楚,照着对象模型图去查 API 就没那么难。
3. 用宏录制进入SolidWorks二次开发:从录制到批量属性写入
3.1 最简单的SolidWorks API跑通:宏录制一段“写自定义属性”
第一次接触 SolidWorks 二次开发,不建议直接建工程、引 DLL、写类。先打开 SolidWorks,点“工具 → 宏 → 录制”,然后手动完成一次操作:在自定义属性里写一个值。操作结束后停止录制,SolidWorks 会生成一段 VBA 宏,这段代码就是你第一份可运行的 API 程序。
录出来的代码核心逻辑通常长这样:
Dim swApp As SldWorks.SldWorks Set swApp = Application.SldWorks Dim swModel As SldWorks.ModelDoc2 Set swModel = swApp.ActiveDoc Dim ok As Boolean ok = swModel.Extension.AddCustomProperty3("材料", 0, "", "Q235")逻辑说明:Application.SldWorks拿到当前 SolidWorks 应用对象;swApp.ActiveDoc拿到当前激活的模型文档;然后调Extension.AddCustomProperty3写入名为“材料”的自定义属性。
参数说明:
"材料"是属性名称,会出现在文件的自定义属性列表里。0表示写到所有配置。SolidWorks 的swCustomPropertyConfigurationOptions_e枚举里,0 代表所有配置,1 代表仅当前配置,2 代表其他配置。如果装配体的 BOM 要按配置区分材料,这个参数就要重新考虑。""是配置名。传空字符串表示不限定单一配置,和前面的 0 配合使用。"Q235"是属性值。ok是返回值,写入成功返回 True。别忽略它,很多诡异问题都是因为写入失败但代码继续跑,最后保存了一个没有属性的文件。
顺带说明:如果AddCustomProperty3在你手头的老版本 SolidWorks 里报“方法不存在”,可以换成老接口AddCustomInfo2。两者用途一样,但新版接口对多配置的支持更好,返回值也更明确。
3.2 批量工具落地:Python遍历目录处理零件和装配体
宏录制解决了“会不会”的问题,但实际工作里很少只改一个文件。常见的需求是这样的:一个外购件目录下有一百多个零件,要根据文件名规则写入“图号”“检查人”“日期”等属性,然后统一另存为 STEP 给下游。
这种批量任务用 Python 写更顺手。下面是能直接跑的目录遍历版本:
import os import win32com.client swApp = win32com.client.Dispatch("SldWorks.Application") swApp.Visible = True type_map = { ".sldprt": 1, ".sldasm": 2, } folder = r"D:\part_library\standard_parts" for root, _, files in os.walk(folder): for name in files: ext = os.path.splitext(name)[1].lower() if ext not in type_map: continue path = os.path.join(root, name) # 文件已经打开时,OpenDoc6 不会返回新对象,先查重 opened = swApp.GetDocumentByName(name) if opened: continue model = swApp.OpenDoc6(path, type_map[ext], 0, "", 0, 0) if model is None: print("打开失败:", path) continue try: ok = model.Extension.AddCustomProperty3( "检查人", 0, "", "张三" ) if ok: model.Save() finally: swApp.CloseDoc(model.GetTitle())逻辑说明:代码先遍历目录下所有.sldprt和.sldasm文件,用OpenDoc6逐个打开,写入“检查人”属性后保存,最后关闭文档。try/finally保证不管写入是否成功,文档都会被关闭,避免 SolidWorks 里的打开文档越积越多。
参数说明:
OpenDoc6的第二个参数是文档类型:.sldprt传 1,.sldasm传 2,工程图是 3。- 第三个参数是打开选项,
0表示默认方式,1表示静默打开。我一般先不用1,因为静默打开会把错误弹窗也屏蔽掉,出问题更难定位。 - 最后两个
0, 0在 C# 里必须用ref传错误和警告变量,在 Python 里如果只关心结果,可以传占位值。
这里有一个比较容易被忽略的问题:如果目标文件已经在 SolidWorks 中打开,OpenDoc6再调用一次并不会真的“重新打开”,也不会返回你想要的ModelDoc2。所以我在打开前先用GetDocumentByName做了检查,名字匹配就直接跳过。这样能防止脚本把用户在用的重要模型关掉。
3.3 新老属性接口的取舍:AddCustomProperty3与AddCustomInfo2
写自定义属性是一个非常高频的操作,但网上很多老帖子里用的是AddCustomInfo2。这个接口在旧版 SolidWorks 没有问题,只是对“配置”的支持不够直观。新版里我更推荐AddCustomProperty3,因为它把配置选项作为一个明确参数,写成("材料", 0, "", "Q235")一眼能看懂。
如果你维护的是老项目,代码里大量用了AddCustomInfo2,也不必全部重写。只要确认写入后的属性能在“配置特定”标签下正确显示,就可以继续用。但新代码、新插件建议统一用AddCustomProperty3,避免未来 SolidWorks 升级时接口行为变化带来的批量返工。
另外要注意:自定义属性不是写进去就万事大吉。SolidWorks 的“文件属性”和“配置特定属性”是两套体系,BOM 取哪个字段取决于你的材料明细表模板里绑定了哪个属性名。二次开发写入的内容如果和工程图模板里的属性名不一致,就算值写对了,标题栏照样是空的。所以做批量写入之前,先打开一个模板文件,确认它读取的属性名到底叫“材料”还是“Material”,这个动作比写代码还重要。
4. SolidWorks二次开发的四个高频场景:参数化、装配、导出与事件回调
4.1 参数化改尺寸:D1@Sketch1与EditRebuild3的配合
机械设计里最常听到的需求是“根据输入的参数自动改模型”。这类需求本质不是画图,而是把已有模型的尺寸参数暴露给外部程序。SolidWorks 里每个标注尺寸都有一个完整名称,比如D1@Sketch1,其中D1是尺寸编号,Sketch1是尺寸所属草图或特征。
获取和修改尺寸的典型代码是:
def set_primary_dimension(model, dim_name, new_value): try: param = model.Parameter(dim_name) param.SystemValue = float(new_value) model.EditRebuild3() return True except Exception as e: print("改尺寸失败:", dim_name, e) return False逻辑说明:model.Parameter用来按完整名称获取尺寸参数;SystemValue是尺寸的系统值,单位是米,不是毫米。所以如果你输入的是 25 毫米,你要给它0.025,或者传入之前先做单位换算。EditRebuild3是重建模型,让新尺寸真正生效。
这里有个很折磨人的坑:尺寸完整名称会随建模语言变化。中文版 SolidWorks 里,D1@Sketch1往往显示成D1@草图1;如果使用者改过尺寸名称,还可能出现长度@草图1这样的自定义名称。所以硬编码D1@Sketch1的代码换台电脑可能直接失效。我的做法是先录一段宏,在模型里手动改一次目标尺寸,然后从宏代码里复制完整的尺寸名,而不是靠猜。
EditRebuild3也不是每次都必须调用。如果只是改一个参考尺寸且不关心模型实时更新,可以攒到最后一起重建。批量参数化时,最好先关掉“自动重建”,等全部尺寸都写完再统一EditRebuild3,否则改十个尺寸会重建十次,时间全部花在等待上。
4.2 自动装配与配合:用组件添加API时需要留意什么
自动装配是看起来很美、实际坑最多的方向。从 API 层面看,核心是两步:往装配体里插入零件,然后加配合。插入零件对应AssemblyDoc.AddComponent5或它的历史版本AddComponent4,加配合对应AddMate5这一族接口。问题是这两个接口的参数都非常长,而且配合方向、对齐方式、配置选择稍微传错,SolidWorks 就会生成完全不同的约束。
我给新手的建议是:不要一开始就手写装配代码。先录制一段“插入零件 → 添加重合配合 → 添加同心配合”的宏,把录到的代码原样搬进你的工程,再逐步把路径和名称参数替换成变量。这样至少能保证调用参数格式是对的,你只需要理解每个参数是干什么的。
自动装配真正要处理的不是“加配合”,而是“重复插入”和“配合失败”。装配体里已经有同一个零件时,AddComponent5会再一次插入新实例,不会自动帮你按名称去重。所以插入前要遍历GetComponents,或者用Component2.GetName2做名称比对。加配合失败时,AddMate5通常不会直接抛异常,而是返回失败状态,配合关系不产生,但零件已经放进来了,这时候装配体就会处于一种“多了一个零件、却少一组约束”的中间状态。我一般会先把配合放到最后一起加,加之前记录当前组件数量,如果失败就撤销整批操作。
4.3 文件导出:PDF、STEP、STL/OBJ给Unity前处理
导出这批需求,最常见的入口是SaveAs3。扩展名决定输出格式,路径给全,SolidWorks 会按扩展名走转换逻辑:
export_path = r"D:\export\part1.STEP" model.SaveAs3(export_path, 0, 0, 0, 0, 0)参数说明:第一个参数是完整导出路径;第二个是版本,0表示当前 SolidWorks 版本,一般不建议改;第三个是选项,0用默认导出设置;第四个是导出数据对象,传0表示不附加额外配置;最后两个是错误和警告占位。
如果导出 PDF,想控制线宽、颜色、图纸大小,需要构造ExportPdfData对象后再传给SaveAs3。导出 STEP 时,如果下游是 Siemens NX 或 Creo,最好先问一句对方要 AP203 还是 AP214,这会影响面曲面和颜色的保留方式。
被问得越来越多的需求是把 SolidWorks 模型给 Unity 用。Unity 不认.sldprt,也不擅长直接解析庞大的 STEP 文件。稳妥路线是:先用SaveAs3导出 STL 或 OBJ,再通过 Blender 或 3D Max 转成 FBX,顺便做减面和材质拆分。不要在 SolidWorks 里死磕贴图级别的东西,那不是它的强项。如果你的模型只是用来做外观展示,把单位统一成米再导出,能省掉 Unity 里缩放一百倍的麻烦。
4.4 事件回调:Add-in长期驻留的必需品
脚本型工具一般是“打开 SolidWorks → 跑一次 → 退出”,它天然不需要关心事件。但企业级插件往往要求“用户在 SolidWorks 里打开模型时,插件自动记录日志;保存时,插件自动把属性写入数据库”。这时候就要做事件回调。
C# Add-in 的常见做法是实现ISwAddin接口,在连接方法里订阅 SolidWorks 的文档事件。SolidWorks 暴露的事件接口里比较常用的是文档打开、文档保存、文档重建这几个。订阅成功后,用户每次打开零件,插件都能拿到ModelDoc2,然后走你写好的属性检查逻辑。
这块我要给一句实际忠告:事件回调里不要做重操作。用户打开文件只想赶紧编辑,如果你的事件回调在文档打开之后马上遍历几百个特征、写几十个属性,SolidWorks 界面会被卡住,体验非常差。正确做法是事件回调里只记录“发生了什么、在哪发生的”,然后把真正的批量操作放到后台线程或者等文档空闲时再执行。这也解释了为什么很多 Add-in 做到后期,核心问题不再是调用 API,而是任务调度和异常隔离。
5. SolidWorks二次开发避坑排查:四个最常翻车的运行现场
5.1 OpenDoc6返回None但目录里明明有文件
现象:路径没错,文件也在硬盘上,但OpenDoc6返回None,代码直接跳过继续处理下一个文件,最后发现一批文件都没被写入。
原因:多数情况是文档类型枚举传错了。.sldprt传 1,.sldasm传 2,.sldrw传 3,这里传错会让 SolidWorks 找不到对应的打开器。另一个常见原因是文件已经在 SolidWorks 里打开了,OpenDoc6不会重复返回新对象。还有可能是 SolidWorks 正在显示一个模态对话框,比如“是否重建”“是否保存”,这时外部调用会一直得不到结果。
解决:先用GetDocumentByName检查文件是否已经打开;再按后缀名正确映射类型;打开后立刻判断返回值,不要盲目往后走。如果仍然失败,把OpenDoc6的 options 参数从 0 改成 0 加上静默标记,并把错误参数打印出来看具体错误码。错误码比None本身有价值得多。
5.2 尺寸被改到别的特征上:FullName和自定义名称的坑
现象:用Parameter("D1@Sketch1")修改尺寸,结果模型重建后,改的值出现在了一个完全无关的特征上,或者是模型弹出“无法找到该尺寸”的提示。
原因:SolidWorks 的尺寸编号不是永久不变的。当你删掉草图里的某个约束,或者在另一个特征前插入新的草图,D1这个名字可能会被重新编号。中文版和英文版的名称差异更是让硬编码方案雪上加霜。
解决:不要在代码里硬编码尺寸名称。可以用宏录制先确认当前模型里的真实尺寸名称;或者通过Feature遍历拿到尺寸对象,再判断它的几何意义。如果只是做固定模板的参数化,建议给系列模型里每个关键尺寸先手动改成可读名称,比如“长度@主要草图”,这样代码可读性和稳定性都会高很多。
5.3 批量跑太久SolidWorks假死或崩溃:把视图效果和模型重建分开
现象:脚本开始的前两分钟正常,五分钟后 SolidWorks 窗口无响应,cpu 占用居高不下,严重时直接闪退,弹窗都来不及保存。
原因:批量打开模型后,SolidWorks 默认会在图形区做阴影、反射、边线渲染,每一个模型都触发一次完整刷新;再加上循环里频繁EditRebuild3,画面边改边刷新,资源很快就顶不住了。这也常被误认为是 API 不稳定,其实是绘图线程被拖垮。
解决:处理大批量文件前,先在 SolidWorks 的系统选项里关闭阴影和反射,显示效果从“上色带阴影”改成普通“上色”;脚本运行时把图形区最小化或缩到托盘,能不重建就不重建。需要批量改属性的文件,完全不需要进入重建流程;需要改尺寸的,只对最后结果来一次EditRebuild3。另外,每个文档处理完都及时CloseDoc,不要让几十个模型同时开在后台。
5.4 换一台机器Add-in加载失败:Interop和安装路径问题
现象:插件在开发机上一切正常,拷到同事电脑上后,SolidWorks 插件列表里看不到,或者显示加载错误,甚至 SolidWorks 启动时弹出和 CEF、运行时组件相关的报错。
原因:C# Add-in 编译出来的是一个带 Interop 引用的托管 DLL,它和 SolidWorks 版本、目标平台、COM 注册状态都强相关。常见具体原因有三个:一是 DLL 或 .addin 文件路径不对,二是 C# 项目的目标平台和 SolidWorks 位数不一致,三是开发机上安装过 SolidWorks SDK 而目标机器没有对应运行时。
解决:发布时把插件 DLL 放到固定目录,.addin文件指向的路径和实际路径保持一致;目标平台改成 x64,和现在主流 SolidWorks 保持一致;在目标机器上用 “以管理员身份运行” 的命令行执行注册命令,确认 DLL 被正确登记。遇到启动时 CEF 报错的机器,先修复或重装对应版本的 SolidWorks 基础组件,再检查插件问题,顺序别搞反。
5.5 批量处理后的文件再次打开属性丢失
现象:脚本跑完,用 SolidWorks 打开文件,属性确实能看到;但把文件发给客户或者导入 PDM 后,属性字段变空了。
原因:常见原因不是写入失败,而是保存时机不对。AddCustomProperty3执行后,如果不调用保存相关接口,文件只是内存中被修改;另外,有些批量工具把文件以只读方式打开,保存动作无效。还有一种情况是写到了配置特定属性,而对方读取的是“文件属性”标签下对应的字段,两边不在一处。
解决:写入后先判断返回值,再调用ModelDoc2.Save或Save3,确保磁盘文件被刷新。如果是配置特定属性,要确认 BOM 和工程图读取的是同一层级的属性。保存成功后,重新打开文件,手工去自定义属性里看一眼,这一步最好加到脚本结尾作为验证。
6. 从能跑到可靠:给SolidWorks二次开发加日志、回归与“后悔药”
6.1 每个COM调用都记录返回值
写 SolidWorks 二次开发,最忌讳的是“代码执行完没有报错,但结果不对”。几乎每个 API 都有返回值或错误参数,但很多人懒得管。我现在的习惯是:凡是写入、保存、重建、导出这一类有副作用的方法,返回值全部记录下来,至少记录到内存日志里。
拿属性写入举例,我会这样记录:
ok = model.Extension.AddCustomProperty3("检查人", 0, "", code) logger.info("%s | 检查人=%s | result=%s", model.GetTitle(), code, ok)运行结束后,用日志过滤result=False的行,而不是靠眼睛一个个打开模型看属性。这对几百个文件的批量任务尤其重要,否则最后你根本不知道哪些成功、哪些失败。
6.2 复制件回归测试
在大量修改自己的二次开发工具之前,我会先复制一份零件和装配体副本,在副本上跑新逻辑。原因很简单:SolidWorks 的 API 行为会随版本和模型状态变化,你觉得“肯定没问题”的代码,换一个新版本可能就有问题。回归测试可以很简单:跑完脚本后,用CustomInfo2把属性读出来,和目标清单比对,输出不一致的记录。
我会把这一步固化到脚本里,不能省。特别是改尺寸和自动装配这类不可逆操作,副本方案的保底价值极大,相当于给自己留了一颗后悔药。
6.3 只做“完成时”写入的操作习惯
还有一个我踩过多次的坑:不要让代码“边做边写”。比如批量改属性时,每改一个文件就立刻保存,如果中途 SolidWorks 崩溃,前面已经保存的文件已经污染完毕,还没跑到的文件保持原样,最后两边状态不一致。现在我的做法是:先只读地打开所有需要处理的文件,把操作全部在内存里准备好,最后统一保存。凡是不能保证中途失败的,就不急着落盘。
我年少轻狂时写过一次自动装配的脚本,直接在原装配体上边插入零件边保存。跑到一半遇到一个坏参考文件,SolidWorks 直接崩掉,原装配体结构损坏,靠备份才救回来。从那以后,所有不安全的批量改动都在副本上做,代码里加日志,保存前先备份。希望帮到你。
本文还有配套的精品资源,点击获取