ARTICLE DETAIL

资讯详情

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

SolidWorks API二次开发:C#实现装配体与虚拟零件自动化

SolidWorks API二次开发:C#实现装配体与虚拟零件自动化 做设计自动化和参数化建模这一块SolidWorks 的 API 二次开发迟早会绕不开。你可能会遇到这样的场景产品系列几百个型号总不能一个个手动装配BOM 要按规则自动生成装配关系每次手工调整稍微复杂一点就出错或者要做概念阶段的快速布局零件还没定型但结构验证已经等不起了。这些需求堆在一起最终都会指向同一个方向用代码直接驱动 SolidWorks在程序里构建装配体、生成虚拟零件、添加配合关系。这篇内容就是围绕这个目标把从零搭建 C# .NET API 开发环境、理解 SolidWorks 装配体对象模型、写出第一个能够自动构建装配体和虚拟零件的实用程序的全过程拆开揉碎了讲清楚。适合刚接触 SolidWorks 二次开发的机械工程师也适合需要给企业搭设计自动化工具的软件工程师参考里面涉及到的东西都是实际项目里真正用得到的。1. 项目背景与整体设计思路1.1 为什么选择 SolidWorks API 做装配体自动化在制造业数字化转型的语境下CAD 二次开发的价值不在于炫技而在于解决重复劳动。以我接触过的几个项目为例最常见的痛点是标准化产品变型设计比如一台设备的框架由型材、钣金件、标准件组成用户只改几个主参数整套装配结构、每个零件的尺寸、各零部件之间的配合关系都要同步变化。如果全手工操作一个型号至少耗掉半天时间而且改错一个尺寸可能导致连锁报错。SolidWorks API 正好能在这个环节发力。它允许开发者从外部程序创建装配体文档、插入零件、添加配合、驱动尺寸、导出工程图或中立格式把建模过程变成参数输入 程序执行的模式。尤其对于装配体这一层API 的覆盖非常完整从 AssemblyDoc 到 Component2从 Mate 到配合组几乎所有你在界面里能做的操作都有对应的接口可以调用。选择 C# 和 .NET 作为开发语言主要考虑三点一是 C# 对 COM 互操作的支持非常成熟SolidWorks 的 API 本质是 COM 组件C# 里加引用后基本上就是强类型调用编译期就能发现很多参数错误二是 C# 的语法和工程化生态更适合做完整工具日志、配置、界面、数据库访问这些周边能力都很顺手三是团队协作时C# 代码的可维护性远比 VBA 宏好得多结构清晰版本管理也能做起来。对于有一定 .NET 基础的工程师来说这套组合的学习曲线其实是最平滑的。1.2 整体架构设计Add-in 还是独立 EXE 程序拿到需求后第一个要做的决定是用 SolidWorks 插件Add-in还是独立的 EXE 程序。这个选择直接影响后面的实现方式和工作量。对比项Add-in 插件独立 EXE 程序启动方式SolidWorks 启动时加载随 SolidWorks 生命周期运行单独启动按需连接 SolidWorks调试体验需要附加到 SolidWorks 进程调试过程偶尔会假死可直接运行调试连接逻辑简单界面集成可以挂菜单、任务窗格深度集成到 SolidWorks 环境通常用 WinForms/WPF 做独立界面部署复杂度需要生成注册表、tlb 文件签名和杀毒软件拦截问题多只需要安装 .NET 运行时和 SolidWorks 环境适用场景给设计师日常使用的工具要求交互体验流畅批处理、参数化生成、数据转换、无人值守任务我的经验是如果是做车间或设计部门内部使用的参数化建模工具Add-in 体验更好但如果是搭建批量生成、数据转换、自动出图这类流程性程序独立 EXE 更稳。原因很简单独立程序的运行环境更干净没有 SolidWorks 界面状态影响出问题时能快速重启进程。这篇内容分享的核心示例采用独立 EXE 方案方便初学者测试和理解你真正做产品时可以把里面的逻辑原封不动搬进 Add-in。1.3 核心技术点拆解SolidWorks API 的对象层级是理解整个开发过程的基础。我习惯把它想成俄罗斯套娃最外层是 SldWorks 对象代表 SolidWorks 应用程序本身往下一层是 ModelDoc2代表当前打开的文档可能是零件、装配体或工程图再往下是 AssemblyDoc装配体文档专用接口、FeatureManager特征管理器、SketchManager草图管理器等。构建装配体主要涉及这样几个核心对象SldWorks连接 SolidWorks、创建文档、读取全局设置。ModelDoc2 / ModelDocExtension通用文档操作比如保存、重建、选择对象。AssemblyDoc装配体特有的操作插入组件、添加配合、爆炸视图等。Component2装配体里的一个具体组件可以是外部零件、子装配体或虚拟零件。Mate2配合对象定义组件之间的几何约束。FeatureManager创建和管理特征。SketchManager创建和编辑草图。理解这套对象模型后整个开发思路就清晰了连接 SldWorks 应用创建装配体文档用 AssemblyDoc 插入或创建组件用 FeatureManager 和 SketchManager 给虚拟零件添加实体特征最后用 Mate2 和配合组来约束组件位置。下面每一节都会围绕这条主线展开。2. 开发环境搭建与Hello Assembly2.1 开发环境准备开发 SolidWorks 二次开发前先把环境配齐。我的建议配置如下Windows 10/11 64 位系统。SolidWorks 2020 或更新版本以下代码基于 2022 编写版本差异我会在问题排查部分说明。Visual Studio 2022 或 2019安装时勾选.NET 桌面开发工作负载。.NET Framework 4.7.2 或更高版本SolidWorks 的 PIA 是基于 .NET Framework 的不要用 .NET Core/.NET 5 创建此类项目否则 COM 互操作会出现很多奇怪问题。SolidWorks API SDK一般随 SolidWorks 安装包一起安装确认安装目录下有 api 文件夹和 SolidWorks Interop 库。检查 SDK 是否完整的简单方法在本机搜索一下有没有C:\Program Files\Common Files\SolidWorks Shared\目录下的sldworks.dll和swconst.dll。这两个 DLL 就是后续要引用的主互操作程序集几乎所有的二次开发都离不开它们。2.2 创建项目并添加 SolidWorks 引用打开 Visual Studio新建一个 Windows 窗体应用.NET Framework项目名称可以叫 SolidWorksAssemblyBuilder。项目创建完成后在解决方案资源管理器里右键引用选择添加引用切到浏览选项卡找到刚才提到的两个 DLL 并添加C:\Program Files\Common Files\SolidWorks Shared\sldworks.dll C:\Program Files\Common Files\SolidWorks Shared\swconst.dll添加引用后在代码文件顶部加上 using 指令using SolidWorks.Interop.sldworks; using SolidWorks.Interop.swconst; using System.Runtime.InteropServices;这里解释一下为什么需要这两个引用sldworks.dll是 SolidWorks API 的主体包含 SldWorks、ModelDoc2、AssemblyDoc、Component2 等类型定义swconst.dll是常量库定义了所有枚举和开关选项比如文档类型常量、配合类型常量等。少了一个都会导致编译失败。还有一点需要注意这两个 DLL 的版本必须和运行的 SolidWorks 版本对应。如果你本机 SolidWorks 是 2022就引用 2022 的 DLL。引用错误版本的 DLL 在调用某些接口时会遇到找不到方法或方法签名不匹配的问题。同一台机器装多个 SolidWorks 版本时务必确认 Visual Studio 里引用的路径正确。2.3 连接 SolidWorks COM 会话写第一行业务代码之前先解决程序怎么找到 SolidWorks 并跟它对话的问题。最常用的方式是通过 COM 的 ProgID程序先尝试获取正在运行的 SolidWorks 实例如果获取不到就启动一个新的 SolidWorks 进程。static SldWorks ConnectToSolidWorks() { SldWorks swApp null; // 第一步尝试获取已经打开的 SolidWorks 实例 try { swApp Marshal.GetActiveObject(SldWorks.Application) as SldWorks; } catch (COMException) { // 没有运行中的实例进入启动流程 } // 第二步启动新的 SolidWorks 实例 if (swApp null) { Type swType Type.GetTypeFromProgID(SldWorks.Application); if (swType null) { throw new Exception(未检测到 SolidWorks 的注册信息请确认已正确安装 SolidWorks。); } swApp (SldWorks)Activator.CreateInstance(swType); swApp.Visible true; // 显示 SolidWorks 窗口 } if (swApp null) { throw new Exception(连接 SolidWorks 失败。); } return swApp; }这段代码背后的原理是Marshal.GetActiveObject是 COM 标准方法用于从 ROTRunning Object Table中检索已经注册为正在运行的 COM 对象。SolidWorks 启动时会把它的 Application 对象注册到 ROT 中所以外部程序可以找到它。Activator.CreateInstance则相当于在系统里执行了new SldWorks.Application触发 SolidWorks 的 COM 服务器注册逻辑从而启动新进程。调用这个函数后可以顺手打印一下版本信息验证连接是否成功SldWorks swApp ConnectToSolidWorks(); string version swApp.RevisionNumber(); Console.WriteLine($SolidWorks 已连接版本: {version});我第一次跑这段代码时就踩过坑程序启动后一直报未将对象引用设置到对象的实例后来发现是 Visual Studio 没有用管理员权限运行导致 COM 激活失败。如果你的程序需要真正操作 SolidWorks 并保存文件建议开发期间就直接以管理员身份运行 Visual Studio。3. 核心细节解析装配体与虚拟零件的实现原理3.1 SolidWorks 装配体模型的数据结构在写创建装配体的代码之前先把 SolidWorks 内存中的数据结构搞清楚否则后面调用 API 很容易一头雾水。装配体文档在 SolidWorks 内部是一个树形结构根节点是装配体文档自身AssemblyDoc下一层是各个组件Component2。组件可以是外部零件引用也可以是子装配体还可以是本节重点说的虚拟零件。每个组件都包含位置信息变换矩阵、名称、所属配置、特征列表等数据。组件下面还有面Face2、边Edge、顶点Vertex、特征Feature、草图Sketch等几何和拓扑信息。这个树形结构反映到 API 上就是很典型的从根往下找的访问模式。你拿到一个装配体文档后遍历第一个层级的组件object[] components (object[])((AssemblyDoc)swDoc).GetComponents(false); foreach (object compObj in components) { Component2 comp (Component2)compObj; string name comp.Name2; string path comp.GetPathName(); Console.WriteLine($组件名称: {name}, 路径: {path}); }理解这个结构的意义在于程序化创建装配体时你要时刻清楚当前操作的对象处于树的哪一层以及这个对象是否已经被 SolidWorks 加载到内存中。比如一个外部零件的组件如果处于轻化状态某些 API 调用可能返回空引用这时需要先调用comp.Unload或修改配置选项把组件设为还原状态。3.2 虚拟零件是什么为什么有用虚拟零件是 SolidWorks 2015 以后重点强化的一个功能。简单说它是存在装配体内部的零件没有独立的 .sldprt 文件路径零件数据以轻量方式存储在装配体文档内部。从用户界面看它的图标带一个特殊的叠加标记命名通常是零件名^装配体名。为什么要用虚拟零件三个原因非常实际概念设计阶段需要快速搭建方案零件尺寸还没定、系列化不确定如果每建一个零件都生成独立文件目录里很快就是一堆垃圾文件。虚拟零件可以避免这种文件污染。虚拟零件的性能开销更小特别适合大批量标准件、辅助结构件的临时建模。在装配体环境下直接建模时虚拟零件可以让自顶向下设计变得顺畅先在装配体里画一个粗结构边验证边细化最后再决定哪些零件要保存成独立文件。当然虚拟零件也有坑。最大的风险是保存管理如果在保存装配体时不特意处理虚拟零件它可能不会被正确保存为外部文件换台电脑打开装配体就发现零件丢了。所以在程序化创建虚拟零件时我会非常强调后面第 4.4 节的保存时机。3.3 配合关系的程序化构建原理装配体自动化的另外一个核心问题是如何把组件放到正确的位置。在 SolidWorks 界面里我们通过添加配合来约束组件比如两个面重合、两个轴同轴、边和面平行等。程序里的做法也是调用配合接口但需要对配合类型、对齐方向、配合对象有一个清晰理解。配合Mate的本质是一个几何约束关系。API 里通过AssemblyDoc.AddMate5方法创建配合核心参数包括配合类型重合、平行、垂直、同轴、距离等、对齐方向同向/反向、距离或角度值距离配合和角度配合需要、以及需要约束的两个几何实体面、轴、边等。在程序里选择几何实体时我强烈建议不要依赖界面选择而是用代码精确获取。SolidWorks API 提供了两种方式一种是通过名称选择比如SelectByID2(面名, FACE, ...)缺点是面名称在不同语言环境下可能不同另一种是直接遍历组件的GetBodies、GetFaces按几何特征判断目标面这种方式更可靠。比如你要让虚拟零件的顶面与装配体前视基准面重合可以先拿到虚拟零件的 body 和 face再拿装配体的基准面然后调用 AddMate5。4. 实操过程从零构建装配体与虚拟零件4.1 创建装配体文档连接 SolidWorks、设计好思路之后开始真正的构建流程。第一步先创建装配体文档。SolidWorks 创建新文档依赖模板文件.asmdot通常安装时会在 SolidWorks 安装目录下生成默认模板。稳妥的做法是从 SolidWorks 的首选项里读取默认模板路径而不是硬编码路径。// 获取默认装配体模板 string assemblyTemplate swApp.GetUserPreferenceStringValue( (int)swUserPreferenceStringValue_e.swDefaultTemplateAssembly); if (string.IsNullOrEmpty(assemblyTemplate)) { // 手动指定常见路径注意版本目录 assemblyTemplate C:\ProgramData\SolidWorks\SOLIDWORKS 2022\templates\Assembly.asmdot; } if (!File.Exists(assemblyTemplate)) { throw new Exception($装配体模板不存在: {assemblyTemplate}); }拿到模板路径后创建装配体文档int errorCode 0; ModelDoc2 swDoc (ModelDoc2)swApp.NewDocument(assemblyTemplate, 0, 0, 0); if (swDoc null) { throw new Exception(创建装配体文档失败错误码: errorCode); } AssemblyDoc swAsm (AssemblyDoc)swDoc; swDoc.SetTitle2(DemoAssembly);这里有个细节NewDocument的后三个参数在早期版本里表示纸张大小和宽高在创建装配体时通常传 0 即可。但不同的 SolidWorks 版本对这个方法的签名处理略有差异如果遇到重载冲突可以先看下智能提示里的方法定义。创建文档后建议立即设置一个自定义标题方便后续识别。也可以顺手关掉装配体的自动重建提示避免批量操作时性能受影响。4.2 创建并插入虚拟零件装配体文档创建完成后就可以往里面插入虚拟零件了。这里用InsertNewVirtualPart方法它会在当前装配体内部创建一个新的零件文档并作为组件插入。调用时传入虚拟零件的初始名称。string virtualPartName MotorMount_01; Component2 swComp null; try { swComp (Component2)swAsm.InsertNewVirtualPart(virtualPartName); } catch (Exception ex) { Console.WriteLine(创建虚拟零件失败: ex.Message); return; } if (swComp null) { throw new Exception(InsertNewVirtualPart 返回空组件请确认当前文档是装配体且版本支持虚拟零件。); } // 获取虚拟零件对应的零件文档 ModelDoc2 vPartDoc (ModelDoc2)swComp.GetModelDoc2();执行完这段代码后SolidWorks 界面左侧的 FeatureManager 树里就能看到装配体下面出现了一个零件节点命名类似MotorMount_01^DemoAssembly。这个组件在磁盘上没有独立的 .sldprt 文件它的几何数据全部存放在装配体文档内部。这里必须提醒一个很常见的坑InsertNewVirtualPart只有在当前文档类型是装配体时才有效如果当前文档是零件或工程图这个方法会直接返回 null 或抛出异常。所以代码里一定要先判断文档类型。判断方式在后面的问题排查部分会给出。创建完虚拟零件后紧接着的一个操作是进入该零件的编辑状态。在 SolidWorks 界面里编辑虚拟零件相当于双击零件节点在 API 里需要激活该组件对应的文档视图。最简单的方式是通过swComp.GetModelDoc2()拿到零件文档后再调用swDoc.ShowNamedView2(*Front, 6)或是直接对文档实例做特征操作。SolidWorks 的文档对象模型允许直接操作未激活的文档但有些特征命令必须在激活状态下才能正常工作。我通常在创建完虚拟零件后调用一次((ModelDoc2)swApp.ActiveDoc)?.ForceRebuild3(...)这样的重建逻辑确保状态一致。4.3 在虚拟零件内部添加实体特征虚拟零件只是一个空的零件文档没有几何实体。要让装配体里有实际的零件形状需要在虚拟零件内部创建草图并拉伸。这也是整个流程中最繁琐、最容易出错的部分。我以最常见的拉伸一个长方体底座为例展示完整的 API 调用链。首先要确保当前焦点在虚拟零件文档上然后通过 FeatureManager 和 SketchManager 创建矩形草图并拉伸。FeatureManager featMgr vPartDoc.FeatureManager; SketchManager skMgr vPartDoc.SketchManager; // 在前视基准面上新建草图 bool sketchEdit skMgr.InsertSketch(true); if (!sketchEdit) { throw new Exception(进入草图编辑失败。); } // 绘制一个中心在原点、宽100mm、高60mm的矩形 // SolidWorks 默认单位是米所以这里传入 0.05 表示 50mm bool rectCreated skMgr.CreateCornerRectangle(-0.05, 0.03, 0, 0.05, -0.03, 0); if (!rectCreated) { throw new Exception(创建矩形草图失败。); } // 退出草图 skMgr.InsertSketch(true);草图完成后调用拉伸特征。FeatureExtrusion3 是创建拉伸凸台的常用接口参数非常多我这里列出实际常用的几个Feature feat featMgr.FeatureExtrusion3( true, // 单向拉伸 false, // 是否双向拉伸 false, // 是否对称拉伸 0, // 双向拉伸时的距离2 0, // 拔模角度 0.02, // 拉伸深度单位米即20mm 0, // 薄壁特征的厚度 false, // 是否薄壁特征 false, // 是否加厚 false, // 是否生成曲面 false, // 是否从草图偏移 false, // 是否反转方向 0, // 偏移距离 0, // 拔模起始点 false, // 是否在终点拔模 false, // 是否在起点拔模 false, // 是否创建圆角 true, // 是否合并结果 true, // 是否使用默认草图 true, // 是否自动选择轮廓 0, // 轮廓选择选项 0, // 特征范围选项 false // 是否生成切除 ); if (feat null) { throw new Exception(拉伸特征创建失败。); } // 强制重建零件 vPartDoc.EditRebuild3(out int rebuildErr, out int rebuildWarn); Console.WriteLine(虚拟零件生成完成重建结果: 错误码 rebuildErr 警告码 rebuildWarn);这段代码里最值得解释的是单位问题。SolidWorks API 里的长度单位默认是米但很多中国设计师习惯用毫米。如果你的项目想统一用毫米建议在程序启动时设置单位偏好swApp.SetUserPreferenceToggle((int)swUserPreferenceToggle_e.swInputDimValOnCreate, false); swApp.SetUserPreferenceDoubleValue((int)swUserPreferenceDoubleValue_e.swUnitLinear, 0); // 0表示米2表示毫米不过坦白讲我在实际项目中很少改全局单位而是在代码里做一个毫米转米的辅助函数所有传入 API 的数据都经过这个函数转换这样代码语义更清楚static double MM(double mm) mm / 1000.0; static double ToMM(double meters) meters * 1000.0;4.4 添加配合关系与约束虚拟零件创建完、几何特征也有了接下来要把零件和装配体或其外部参考关联起来。最典型的场景是让虚拟零件的一个面和装配体的前视基准面重合或者让虚拟零件的一条边与某个外部零件的轴同轴。这里我演示一个面重合配合目标是把虚拟零件的顶面与前视基准面约束为重合。bool sel1 false; bool sel2 false; // 选择虚拟零件的顶面遍历组件实体找到法向为Z轴正方向的那个面 Body2 vBody (Body2)swComp.GetBody(); object[] faces (object[])vBody.GetFaces(); Face2 targetFace null; foreach (object fObj in faces) { Face2 face (Face2)fObj; double[] normal new double[3]; face.GetNormal(out double x, out double y, out double z); // 实际接口为 GetNormal(out double, out double, out double) // 判断是否为顶面法向接近Y轴正方向具体坐标系根据实际方位调整 if (z 0.9) { targetFace face; break; } } if (targetFace ! null) { sel1 targetFace.Select4(false, null, false, 0); } // 选择装配体的前视基准面 sel2 swDoc.Extension.SelectByID2(Front Plane, PLANE, 0, 0, 0, false, 0, null, 0); if (sel1 sel2) { // 添加重合配合 bool mateOk swAsm.AddMate5( (int)swMateType_e.swMateCOINCIDENT, (int)swMateAlign_e.swAlignPOSITIVE, false, // flip 0.0, // 距离/角度值 0.0, // 角度 0.0, // 齿轮比 false, // 锁定旋转 null, // 配合参考1已通过选择指定 null, // 配合参考2 false); // 是否生成配合文件夹外 if (mateOk) { Console.WriteLine(配合添加成功。); } else { Console.WriteLine(配合添加失败。); } }实际开发中识别哪个面是顶面远比这个示例复杂因为面的位置和方向会随着零件的姿态变化。更通用的做法是用面的重心坐标加法向量综合判断或者根据零件上已有的参考几何比如基准面、草图点来定位。这里的重点是理解Select4和AddMate5的关系SolidWorks API 的很多配合方法不是直接把两个面对象传进去而是要求先把它们选中再基于当前选择集创建配合。这是 COM 接口时代的设计惯性新手很容易在这里绕晕。4.5 重建、保存与导出装配体构建完毕后进入收尾阶段重建模型、保存虚拟零件、另存为中立格式如 STEP、STL。重建的代码很简单bool rebuildResult swDoc.ForceRebuild3(out int rebuildErr, out int rebuildWarn); Console.WriteLine($重建状态: {rebuildResult}错误码: {rebuildErr}警告码: {rebuildWarn});重建是必须的。如果不重建SolidWorks 内部的特征数据可能是脏的后续导出的模型可能缺少最新的几何体。我在实际项目中甚至见过不重建直接导出导致零件变空白的案例。虚拟零件的保存是很多人忽略的点。前面提到虚拟零件默认只存在于装配体内部如果你希望它以后能被其他装配体复用就应该把它另存为外部零件文件。SldWorks 提供了一个保存虚拟零件的方法bool saveOk swAsm.SaveVirtualComponents( true, // 已更改的虚拟零件 true, // 未更改的虚拟零件 true, // 是否应用到子装配体 out object errObject);调用这个方法后SolidWorks 会弹出保存对话框如果swAsm有对应的交互设置。如果想完全静默处理可以设置 SolidWorks 的提示模式为不弹框但这种做法有风险一旦路径设置错误虚拟零件可能直接被保存到意想不到的位置。更稳妥的做法是先把虚拟零件另存为明确的路径string externalPartPath D:\Project\Parts\MotorMount_01.sldprt; bool extOk swComp.SaveAsComponent(externalPartPath, 0, 0); // 参数为路径、保留参考、内部错误码不过SaveAsComponent在不同版本的 API 里行为有差异有些版本只支持通过 SaveAs 对话框交互。所以我的建议是在开发阶段先弹一次对话框确认路径正确后再改成静默模式。最后如果需要导出 STEP、STL 等交换格式使用 ModelDoc2 的SaveAs方法string stepPath D:\Project\Output\DemoAssembly.step; int error 0; int warning 0; bool exportOk swDoc.SaveAs(stepPath, 0, 0, null, ref error, ref warning);注意 STEP 导出需要 SolidWorks 安装对应的 translators 组件某些精简安装版本没有这些组件导出时会报错。5. 常见问题与排查技巧实录5.1 COM 连接失败明明装了 SolidWorks 却找不到实例这个现象在刚入门时很常见程序抛出COMException或者Marshal.GetActiveObject一直返回 null。通常有三个原因。权限问题SolidWorks 以管理员身份运行而开发程序以普通用户运行COM 激活会失败。反过来也一样。建议开发期间两边都以管理员身份运行。进程被杀SolidWorks 进程崩溃后ROT 中的对象可能残留但已经无法访问。重启 SolidWorks 就好。引用版本不匹配如果代码里引用了 2022 的 sldworks.dll但本机运行的是 2020COM 激活时方法签名对不上表现为某些方法抛MissingMethodException或返回 null。排查的时候建议在ConnectToSolidWorks函数里加入详细的日志输出记录异常类型和消息方便定位。5.2 NewDocument 返回 null 或模板报错创建装配体文档失败90% 的原因是模板路径不对。很多机器上 SolidWorks 的默认模板路径是没有写入注册表的GetUserPreferenceStringValue返回空字符串。建议做成三级回退读取用户的默认模板设置。读取 SolidWorks 安装目录下的模板路径用swApp.GetExecutablePath()拼接。手动指定一个绝对路径并在代码启动时验证File.Exists。另外注意.asmdot 是装配体模板.prtdot 是零件模板不要混用。5.3 InsertNewVirtualPart 返回空组件InsertNewVirtualPart返回空组件最常见的原因有四个当前文档不是装配体。可以先判断文档类型int docType swDoc.GetType(); // 2 表示装配体1 表示零件3 表示工程图 if (docType ! (int)swDocumentTypes_e.swDocASSEMBLY) { throw new Exception(当前文档不是装配体无法创建虚拟零件。); }装配体处于已保存并关闭的只读状态无法编辑。SolidWorks 版本太低不支持虚拟零件。虚拟零件功能从 2015 版本开始完整支持低于这个版本请考虑用空零件文件代替。当前正在草图编辑状态或配合编辑状态SolidWorks 不允许同时插入组件。先退出所有编辑状态再调用。5.4 拉伸特征失败FeatureExtrusion3 返回 nullFeatureExtrusion3是参数最多的 API 之一也是新手最容易踩坑的地方。我的经验是先跑通最简单的拉伸再逐步增加复杂参数。如果返回 null优先检查三件事当前是否在零件文档环境中。虚拟零件的文档类型是零件不是装配体。如果还在装配体文档上调用FeatureExtrusion3结果是不可预料的。当前是否有可用的草图。拉伸必须基于一个已经存在的草图并且草图必须处于未编辑状态。是否在草图中选择了轮廓。代码里我传了true给自动选择轮廓但如果草图里有多个闭环SolidWorks 可能无法判断拉伸哪个轮廓。这时需要明确指定轮廓或者改为更小的草图区域。5.5 保存后虚拟零件不翼而飞这个问题几乎每个用过虚拟零件的人都会遇到。原因是虚拟零件的数据默认只存在于装配体内部如果你只保存了装配体文件而没有执行保存虚拟零件那么关闭 SolidWorks 后虚拟零件的几何数据可能丢失。SolidWorks 界面在关闭装配体时会弹窗提醒是否保存虚拟零件但程序化操作时很容易忽略这一步。解决方法是形成固定的保存流程在程序结束前先保存所有虚拟零件到指定目录再保存装配体本身。代码顺序不能反因为装配体保存时会记录外部虚拟零件的路径引用。5.6 尺寸单位混乱看起来是 1mm实际却是 1mSolidWorks API 的单位默认是米但很多模具、非标设备工程师的习惯是毫米。我发现一个比较稳妥的做法是程序开头做一个单位检查并定义一个全局单位转换器保证所有进出 API 的数据都经过转换。class LengthConverter { private double _factor 1.0; public LengthConverter(bool useMillimeter) { if (useMillimeter) _factor 1000.0; } public double ToMeters(double value) value / 1000.0; public double FromMeters(double value) value * 1000.0; }在代码里凡是写入 API 的尺寸统一走ToMeters读出来的数据统一走FromMeters。不要在图省事的地方偷懒混用单位导致的模型尺寸错误往往要花几小时才能发现。5.7 性能优化大批量装配时的卡顿问题如果你需要在一个装配体里插入几十甚至上百个虚拟零件逐个调用InsertNewVirtualPart和FeatureExtrusion3会非常卡因为每个特征默认都会触发界面刷新和重建。我实际测过插入 50 个零件、每个零件 2 到 3 个特征默认配置下可能要跑十几分钟。性能优化有几个关键开关关闭屏幕刷新swApp.GetUserPreferenceToggle设置刷新模式或者在文档级别调用swDoc.SetAddToDB(true)让特征加入数据库时不立刻重建。抑制草图自动标注swApp.SetUserPreferenceToggle((int)swUserPreferenceToggle_e.swInputDimValOnCreate, false)避免每次画完草图都弹出尺寸输入框。最后统一重建所有特征创建完以后再调用一次ForceRebuild3而不是每加一个特征就重建一次。还有一个不那么明显但很实用的技巧尽量使用FeatureManager.SetAddToDB(true)配合SetAddToDB2等方法让特征只进入模型数据库而不立即执行几何计算。大批量建模时这个开关能把耗时从分钟级降到秒级。6. 从代码到工程化一些想特别强调的事如果你只是自己研究着玩看到上一节就可以动手了。但如果是给公司搭工具我建议再往下看两点经验。第一日志怎么做。SolidWorks 二次开发的调试体验非常差很多 API 调用不抛异常只是返回 null 或者 false。你在代码里必须做详细的日志记录进入哪个方法、传入了什么参数、返回值是什么、模型当前处于什么状态。日志既能帮你排查问题也能在使用者报告程序跑失败了但不知为啥的时候快速定位。我通常用一个简单的LogHelper类把日志同时输出到控制台和文件文件命名带上时间戳。第二如何设计参数化入口。程序化创建装配体这个能力本身只是基础真正的价值在于把它封装成输入参数、输出模型的工具。比如把装配体的长度、宽度、高度、孔位、零件数量做成一个 XML 或 JSON 配置程序读取配置后自动生成装配体。这样即使不写代码的工程师也能通过改配置文件来驱动建模整个工具的使用面就宽了。我在实际项目中经常遇到一个现象明明 API 调用都成功了但生成的模型在 SolidWorks 里打开时某些配合状态显示为过定义或错误。这通常是配合添加顺序或参考对象选择不当导致的。建议在程序里每添加一个配合就检查一下配合的状态如果有错误立刻停止并输出这条配合的名称和参考对象不要等所有配合加完了再回头找问题。通过遍历FeatureManager.GetFeatures找到类型为配合的特征检查其GetErrorCode2方法可以在早期发现配合冲突。最后再分享一个我个人的习惯无论在哪个项目里我都保留一个手工基准案例。也就是说先用鼠标在 SolidWorks 界面里把整个装配体流程从头到尾操作一遍记录每一步涉及到的操作菜单和选项值然后才去写代码。这个习惯帮我绕开了大量 API 文档描述不清晰的坑因为 SolidWorks 的界面选项往往比 API 枚举值更直观对照着写代码出错的概率会小很多。虚拟零件和装配体自动化这一块功能玩熟了以后可以扩展的方向非常多批量出 BOM、自动装配标准件、参数化生成整机模型、对接 PLM 系统等等。核心还是先把程序化构建装配体 虚拟零件这条链路跑通后面的路就容易走了。
返回列表