SolidWorks二次开发模板:.NET Framework 4.8最小可运行Add-in骨架
简介:本资源是一套开箱即用的SolidWorks二次开发C#模板工程,面向机械设计工程师、CAD自动化开发者及高校相关专业学习者,解决从零搭建SDK插件环境、快速实现功能扩展的入门与实践难题。压缩包共99个文件,含18个核心C#源码(.cs)、2个Visual Studio项目文件(.csproj)、1个解决方案(.sln)、34个运行依赖DLL及5个资源文件(.resx/.bmp),完整覆盖插件初始化、事件响应、界面集成、命令注册等关键模块;包体大小10.24MB,结构清晰,便于理解SolidWorks COM Add-in生命周期与WPF/WinForms界面嵌入逻辑。目前已有729人学习下载,读者可直接导入VS编译调试,获得包含SwAddin.cs主入口、XtraForm1自定义窗体、PMPHandler属性页管理、Solidworks操作封装类等在内的完整工程骨架,并复用Toolbar图标、事件处理链、错误日志框架等实用组件,显著降低二次开发启动门槛。
1. SolidWorks二次开发模板:一个能直接编译、加载、跑通的“最小可运行骨架”
你有没有试过在SolidWorks里点开「工具 → 宏 → 编辑」,粘贴一段C#代码,结果双击运行时弹出“无法加载程序集”或“找不到SolidWorks.Interop.sldworks.dll”?不是代码写错了,是缺了最关键的三样东西:正确的引用路径、匹配的.NET Framework版本、以及——最常被忽略的——注册表项与COM互操作配置。这个SolidWorks二次开发模板,就是为解决这类“明明代码逻辑正确却死活不启动”的问题而生。它不是一个教学Demo,也不是一堆零散的.cs文件集合,而是一个开箱即用的Visual Studio 2022(.NET Framework 4.8)项目,包含完整解决方案结构、预配置的引用、自动注册脚本、调试启动配置,甚至内置了一个带UI按钮的CommandManagerTab示例。适合刚接触API但已能写基础C#的工程师,也适合老手快速搭新功能原型——比如你要加一个“一键导出BOM到Excel”的按钮,把业务逻辑塞进OnCommand方法里,F5就能在SolidWorks里看到效果。它不教你怎么建模,只确保你的代码能稳稳地跑在SolidWorks进程里。
2. 项目结构与技术栈:为什么选.NET Framework 4.8 + COM Interop而不是.NET Core
SolidWorks官方API目前(2024年主流版本SOLIDWORKS 2023–2024)仍基于COM组件模型,所有核心接口(ISldWorks,IModelDoc2,IAssemblyDoc等)都通过SolidWorks.Interop.sldworks.dll暴露。这个DLL本质是COM类型库(.tlb)的.NET互操作包装器(interop assembly),它必须在.NET Framework下运行,且对运行时版本敏感。.NET Core/.NET 5+虽支持COM调用,但需手动处理类型映射、线程套间(STA)、对象生命周期等底层细节,极易引发InvalidCastException或COMException: 0x80070005权限错误。本模板采用.NET Framework 4.8,正是因为它与SolidWorks主进程(单线程套间STA)天然兼容,且VS2022对其支持成熟稳定。
2.1 解决方案目录结构:每个文件都有明确职责
项目采用标准VS解决方案结构,共4个核心文件夹:
SolidWorksAddInTemplate/ ├── AddIn/ # 主Add-in项目(启动入口) │ ├── AddIn.cs # 实现ISwAddin接口:ConnectToSW, DisconnectFromSW, OnCommand │ ├── SwAddIn.csproj # 项目文件,含关键属性配置 │ └── Resources/ # 图标、字符串资源 ├── Common/ # 跨模块复用工具类(非必须,但强烈建议) │ ├── SwHelper.cs # 封装常用操作:获取当前文档、检查装配体、安全释放COM对象 │ └── Logger.cs # 简易日志写入(输出到SolidWorks状态栏+文本文件) ├── UI/ # 用户界面相关(CommandManager、TaskPane、PropertyManagerPage) │ ├── CommandManagerTab.cs # 注册自定义选项卡和按钮 │ └── TaskPaneControl.cs # WinForms用户控件,嵌入SolidWorks任务窗格 └── packages.config # NuGet包管理(仅用于历史兼容,实际引用均手动添加)提示:
AddIn.cs是整个插件的“心脏”。它必须实现SolidWorks.Interop.swpublished.ISwAddin接口,其中ConnectToSW()在SolidWorks启动时被调用,OnCommand()在用户点击按钮时触发。任何初始化逻辑(如加载UI、注册事件)都应放在这里,而非构造函数中——因为Add-in实例由SolidWorks COM容器创建,构造函数执行时机不可控。
2.2 关键引用配置:为什么必须手动添加,不能靠NuGet
SolidWorks API引用不能通过NuGet安装。官方未发布SolidWorks.Interop.*的NuGet包,所有interop DLL均来自SolidWorks安装目录。模板中已预设以下4个必需引用(路径按典型安装位置配置):
| 引用名称 | 物理路径(示例) | 作用 | 是否嵌入互操作类型 |
|---|---|---|---|
SolidWorks.Interop.sldworks | C:\Program Files\SOLIDWORKS Corp\SOLIDWORKS\api\redist\SolidWorks.Interop.sldworks.dll | 主API入口,提供ISldWorks等核心接口 | ✅ 是(Embed Interop Types = True) |
SolidWorks.Interop.swconst | 同上目录 | 枚举常量(如swDocumentTypes_e.swDocPART) | ✅ 是 |
SolidWorks.Interop.swpublished | 同上目录 | Add-in生命周期接口(ISwAddin) | ✅ 是 |
System.Windows.Forms | .NET Framework内置 | UI控件支持(TaskPane、对话框) | ❌ 否 |
注意:
Embed Interop Types = True是关键设置。它将interop类型定义直接编译进你的DLL,避免部署时需额外分发interop DLL。若设为False,用户机器上必须存在完全同版本的interop DLL,极易因版本错配崩溃。
2.3 项目属性配置:三个决定成败的设置项
在SwAddIn.csproj中,以下三项配置直接影响能否加载:
<PropertyGroup> <!-- 1. 必须设为x64(SolidWorks 2018+默认64位) --> <PlatformTarget>x64</PlatformTarget> <!-- 2. 启用COM可见性,让SolidWorks能通过CLSID找到你的类 --> <RegisterForComInterop>true</RegisterForComInterop> <!-- 3. 输出路径必须为绝对路径,且与注册脚本一致 --> <OutputPath>C:\SWAddIns\MyAddIn\</OutputPath> </PropertyGroup>PlatformTarget=x64:SolidWorks 2018及以后版本均为64位进程,若编译为AnyCPU或x86,加载时会报BadImageFormatException。RegisterForComInterop=true:VS在生成时自动调用regasm.exe注册你的程序集,生成注册表项(HKEY_CLASSES_ROOT\CLSID\{...}),这是SolidWorks发现并实例化Add-in的前提。OutputPath:必须为绝对路径。SolidWorks通过注册表中的InprocServer32键值读取DLL路径,若路径错误,会静默失败(无报错,但Add-in不显示)。
3. 核心模块拆解:从注册到响应按钮的完整链路
一个SolidWorks Add-in的生命周期始于注册表,终于OnCommand方法。本节逐层拆解CommandManagerTab如何从代码变成SolidWorks界面上的一个按钮,并触发业务逻辑。
3.1 注册表与CLSID:SolidWorks如何“发现”你的插件
当RegisterForComInterop=true时,VS执行:
regasm.exe "C:\SWAddIns\MyAddIn\SwAddIn.dll" /tlb /codebase该命令在注册表中创建以下关键项(以HKEY_CURRENT_USER为例,避免管理员权限):
HKEY_CURRENT_USER\Software\SOLIDWORKS\Addins\ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890} ← 你的Add-in CLSID (Default) = 1 ← 启用状态(1=启用,0=禁用) LoadAtStartup = 1 ← 启动时加载 Title = "My SolidWorks Add-in" ← 显示名称 Description = "BOM Export Tool" ← 描述提示:CLSID由
Guid特性生成。在AddIn.cs顶部必须声明:[Guid("A1B2C3D4-E5F6-7890-ABCD-EF1234567890")] [ComVisible(true)] public class SwAddIn : ISwAddin { ... }若修改代码后重新生成GUID,旧注册表项失效,需手动清理或重注册。
3.2 CommandManagerTab:在SolidWorks菜单栏添加自定义选项卡
UI/CommandManagerTab.cs负责创建选项卡和按钮。核心逻辑分三步:
获取CommandManager对象(在
ConnectToSW中):// 在AddIn.cs的ConnectToSW方法内 _swApp = (SldWorks)sw; _cmdMgr = _swApp.GetCommandManager((int)swDocumentTypes_e.swDocNONE);创建选项卡与组(在
OnConnect中):// 创建选项卡(ID唯一,建议用数字避免冲突) int tabId = 1001; _cmdMgr.CreateCommandTab(tabId, "My Tools", 0); // 第3参数为图标索引 // 创建按钮组(放在选项卡内) int groupId = 1002; _cmdMgr.CreateCommandGroup(groupId, "Export", "Export BOM", "", -1, false, ref cmdGroup);绑定按钮点击事件(关键!):
// cmdGroup是ICommandGroup对象,其AddCommandItem2方法添加按钮 cmdGroup.AddCommandItem2( "Export BOM", // 按钮文本 -1, // 图标ID(-1=无图标) "Export BOM to Excel", // 工具提示 101, // 命令ID(必须全局唯一,用于OnCommand识别) (int)swCommands_e.swCommands_Custom, // 命令类型 null, // 位图(null=默认) 0, // 位图索引 0 // 附加数据(可传入自定义对象) );
注意:
AddCommandItem2的第4个参数CommandID(此处为101)是OnCommand方法的commandID入参。SolidWorks点击按钮时,会回调OnCommand(commandID, ...), 你只需switch(commandID)即可分发逻辑。
3.3 OnCommand方法:业务逻辑的唯一入口
AddIn.cs中的OnCommand是所有用户交互的终点:
public void OnCommand(int commandID, int option) { try { switch (commandID) { case 101: // Export BOM按钮 ExportBomToExcel(); break; case 102: // Another button... break; default: _swApp.SendMsgToUser($"Unknown command ID: {commandID}"); break; } } catch (Exception ex) { // 必须捕获所有异常!否则SolidWorks可能崩溃 _swApp.SendMsgToUser($"Error: {ex.Message}"); Logger.LogError(ex); } } private void ExportBomToExcel() { var model = _swApp.IActiveDoc2 as IModelDoc2; if (model == null) { _swApp.SendMsgToUser("No active document!"); return; } // 此处写你的BOM导出逻辑... // 例如:遍历FeatureManager,提取零部件,写入Excel }血泪经验:
OnCommand中绝不能有阻塞操作(如长时间IO、网络请求)。SolidWorks主线程被占用会导致界面冻结。若需耗时操作,务必用Task.Run+BeginInvoke回UI线程更新状态,或改用后台线程+进度条(见第5章)。
4. 运行与调试:从编译到SolidWorks内实时调试的全流程
跑通是第一步,调试才是日常。本节给出一套经过验证的、无需反复重启SolidWorks的调试方案。
4.1 一键编译+注册+加载:批处理脚本实操
模板附带build_and_register.bat,内容如下:
@echo off setlocal REM 1. 清理并编译 cd /d "%~dp0" msbuild "SwAddIn.csproj" /p:Configuration=Debug /p:Platform=x64 REM 2. 复制DLL到目标目录(与项目OutputPath一致) xcopy /y "bin\Debug\SwAddIn.dll" "C:\SWAddIns\MyAddIn\" REM 3. 重新注册(关键!每次编译后必须执行) "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe" "C:\SWAddIns\MyAddIn\SwAddIn.dll" /tlb /codebase REM 4. 强制刷新SolidWorks Add-ins列表(无需重启) echo Add-in registered. Now restart SolidWorks or use 'Tools > Add-ins' to reload. pause提示:
regasm.exe路径需根据你的.NET Framework版本调整。v4.0.30319对应.NET 4.0–4.8。若使用.NET 4.8,路径正确;若系统未安装该版本,需先安装.NET Framework 4.8 Developer Pack。
4.2 Visual Studio内联调试:断点直达OnCommand
VS调试的关键在于让SolidWorks进程成为调试目标:
设置启动项目:右键
SwAddIn项目 →Properties→Debug→Start Action→ 选择Start external program,路径填:C:\Program Files\SOLIDWORKS Corp\SOLIDWORKS\sldworks.exe附加到进程(更推荐):
- 先启动SolidWorks(确保Add-in已启用)
- VS中
Debug → Attach to Process... - 找到
sldworks.exe(注意:有多个,选CPU占用高的那个) - 确保
Attach to:为Managed (.NET 4.x) code - 点击
Attach
在
OnCommand方法第一行设断点,然后在SolidWorks中点击你的按钮——VS会立即停住。
避坑:若断点显示“未命中”,检查是否:
- 断点所在DLL与SolidWorks加载的DLL是同一份(对比文件时间戳)
regasm注册的是Debug版DLL,而非Release版- VS调试器附加的是正确的
sldworks.exe(64位进程)
4.3 常见问题排查:5条高频翻车现场与解法
现象1:SolidWorks启动后,Add-in不显示在「工具 → Add-ins」列表中
原因:注册表项缺失或CLSID不匹配;OutputPath与注册路径不一致;RegisterForComInterop=false未开启。
解决:运行regedit,检查HKEY_CURRENT_USER\Software\SOLIDWORKS\Addins\{YourCLSID}是否存在;确认SwAddIn.csproj中RegisterForComInterop为true;核对OutputPath与regasm命令中的DLL路径。
现象2:Add-in在「Add-ins」列表中勾选了,但点击按钮无反应,也无报错
原因:OnCommand方法未被调用,通常因CommandID不匹配或AddCommandItem2调用时机错误(如在DisconnectFromSW中调用)。
解决:在OnCommand开头加_swApp.SendMsgToUser("OnCommand called");验证是否进入;检查AddCommandItem2是否在ConnectToSW或OnConnect中调用(不能在OnDisconnect)。
现象3:点击按钮后SolidWorks崩溃或弹出“应用程序遇到问题”
原因:OnCommand中抛出未捕获异常;COM对象未释放(如IModelDoc2未调用Marshal.ReleaseComObject);跨线程访问UI。
解决:OnCommand必须用try-catch包裹;所有COM对象使用后立即释放(SwHelper.SafeRelease(obj));避免在OnCommand中直接操作WinForms控件,改用Control.Invoke。
现象4:TaskPane控件显示为空白,或报System.Runtime.InteropServices.COMException: 0x80040154
原因:TaskPane控件未正确注册为COM可见;UserControl类缺少[ComVisible(true)];或未在OnConnect中调用_swApp.CreateTaskpaneView2。
解决:确保TaskPaneControl.cs顶部有[ComVisible(true)]和[Guid("...")];在OnConnect中:
_taskPaneView = _swApp.CreateTaskpaneView2( "SwAddIn.UI.TaskPaneControl", // 程序集.类名 "My Task Pane", ref taskPaneHandle );现象5:调试时VS提示“无法加载符号”或断点为空心圆
原因:PDB文件未生成或路径不匹配;SolidWorks加载的是GAC中的旧版本DLL。
解决:检查bin\Debug\下是否有SwAddIn.pdb;在VSDebug → Options → Symbols中添加PDB路径;运行gacutil -lu SwAddIn确认未误装入GAC。
5. 二次开发改造指南:从模板到生产级插件的5个关键升级点
拿到模板只是起点。真正落地时,你会面临日志追踪、多线程、配置持久化、错误恢复等现实问题。以下是我在多个工业客户项目中沉淀的5个必改项,每一条都配可直接复制的代码。
5.1 配置文件管理:用XML替代硬编码路径
硬编码Excel模板路径、服务器地址会让部署变成噩梦。模板中Common/ConfigManager.cs提供轻量XML配置:
public static class ConfigManager { private static readonly string ConfigPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MySwAddIn", "config.xml"); public static string ExcelTemplatePath { get; set; } = @"C:\Templates\bom_template.xlsx"; public static string ServerUrl { get; set; } = "http://localhost:5000/api"; public static void Load() { if (!File.Exists(ConfigPath)) return; var doc = XDocument.Load(ConfigPath); ExcelTemplatePath = doc.Root?.Element("ExcelTemplatePath")?.Value ?? ExcelTemplatePath; ServerUrl = doc.Root?.Element("ServerUrl")?.Value ?? ServerUrl; } public static void Save() { Directory.CreateDirectory(Path.GetDirectoryName(ConfigPath)); var doc = new XDocument( new XElement("Config", new XElement("ExcelTemplatePath", ExcelTemplatePath), new XElement("ServerUrl", ServerUrl) ) ); doc.Save(ConfigPath); } }改造步骤:在
AddIn.cs的ConnectToSW末尾调用ConfigManager.Load();在UI中提供“设置”按钮,点击后调用ConfigManager.Save()。配置文件存于%APPDATA%\MySwAddIn\,用户可手动编辑,也可通过UI修改。
5.2 安全的COM对象释放:避免内存泄漏的SwHelper.SafeRelease
SolidWorks API对象是COM对象,.NET GC无法自动回收。必须显式释放。Common/SwHelper.cs提供健壮释放方法:
public static void SafeRelease(object comObj) { if (comObj == null) return; try { if (Marshal.IsComObject(comObj)) { Marshal.ReleaseComObject(comObj); } } catch (COMException ex) when (ex.ErrorCode == unchecked((int)0x80010108)) // RPC_E_DISCONNECTED { // 对象已被释放,忽略 } catch (InvalidComObjectException) { // 对象已无效,忽略 } finally { comObj = null; // 帮助GC } }使用场景:在
OnCommand末尾、DisconnectFromSW中,对所有IModelDoc2,IFeature,IComponent2等对象调用SafeRelease。例如:var model = _swApp.IActiveDoc2 as IModelDoc2; try { /* do work */ } finally { SwHelper.SafeRelease(model); }
5.3 后台线程与进度反馈:不让SolidWorks卡死的Task.Run模式
导出BOM可能耗时10秒以上。直接在OnCommand中执行会冻结SolidWorks界面。正确做法是:
private async void ExportBomToExcelAsync() { // 1. 显示进度条(通过SolidWorks状态栏) _swApp.SetStatusText("Exporting BOM... Please wait."); // 2. 启动后台任务 await Task.Run(() => { // 所有耗时操作在此执行(注意:不能访问_swApp等COM对象!) var bomData = GenerateBomData(); // 纯计算,不碰COM ExportToExcel(bomData); // 文件IO }); // 3. 回UI线程更新(通过Invoke) _swApp.SetStatusText("BOM exported successfully!"); } private List<BomItem> GenerateBomData() { // 示例:遍历装配体,提取信息 var model = _swApp.IActiveDoc2 as IAssemblyDoc; if (model == null) return new List<BomItem>(); var components = model.GetComponents(false); var list = new List<BomItem>(); foreach (IComponent2 comp in components) { list.Add(new BomItem { Name = comp.Name2, PartNumber = GetCustomProperty(comp, "PartNo"), Quantity = comp.GetSuppressed() ? 0 : 1 }); } return list; }关键点:
Task.Run内禁止访问任何SolidWorks COM对象(如_swApp,model),因为它们绑定到STA线程。所有COM操作必须在await前完成,或通过Invoke委托回主线程。
5.4 错误日志与用户反馈:比SendMsgToUser更可靠的诊断方式
_swApp.SendMsgToUser只能显示简短消息。生产环境需要详细日志:
public static class Logger { private static readonly string LogPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MySwAddIn", "logs"); public static void LogInfo(string message) { WriteLog("INFO", message); } public static void LogError(Exception ex) { var msg = $"{ex.GetType().Name}: {ex.Message}\n{ex.StackTrace}"; WriteLog("ERROR", msg); } private static void WriteLog(string level, string message) { Directory.CreateDirectory(LogPath); var file = Path.Combine(LogPath, $"log_{DateTime.Now:yyyy-MM-dd}.txt"); var line = $"[{DateTime.Now:HH:mm:ss}] [{level}] {message}"; File.AppendAllText(file, line + Environment.NewLine); } }改造:在
OnCommand的catch块中调用Logger.LogError(ex);在ConnectToSW中调用Logger.LogInfo("Add-in loaded")。日志存于%LOCALAPPDATA%\MySwAddIn\logs\,方便用户提交问题时附带。
5.5 安装包制作:Inno Setup脚本一键部署
交付给客户不能只给DLL。模板附带installer.iss(Inno Setup脚本),生成.exe安装包:
[Setup] AppName=My SolidWorks Add-in AppVersion=1.0.0 DefaultDirName={autopf}\MySwAddIn OutputBaseFilename=my-sw-addin-setup [Files] Source: "bin\Debug\SwAddIn.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "bin\Debug\SwAddIn.tlb"; DestDir: "{app}"; Flags: ignoreversion [Run] Filename: "{sys}\regasm.exe"; Parameters: """{app}\SwAddIn.dll"" /tlb /codebase"; Flags: runhidden [Registry] Root: HKA; Subkey: "Software\SOLIDWORKS\Addins\{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"; ValueType: none; ValueName: ""; ValueData: "1"使用:安装Inno Setup Compiler,用
iscc installer.iss生成安装包。双击安装即可完成注册、拷贝、启用全流程。
从那以后我每次新建SolidWorks插件项目,都强制走一遍这个模板的build_and_register.bat,再立刻在SolidWorks里点一次按钮验证。哪怕只是改一行注释,也要确保注册表、DLL、调试器三者同步。这看似多花30秒,却省去了后续2小时排查“为什么没反应”的玄学时间。希望帮到你。
本文还有配套的精品资源,点击获取