简介:面向CATIA CAA二次开发学习者,这份第06讲代码资源包提供完整工程与源文件,适合已掌握CATIA基础、希望深入了解CAA V5或R3插件开发的技术人员。压缩包共含2000个文件,约31.74MB,涵盖C++/CAA开发常见类型:h头文件与cpp源文件构成核心代码,sln、vcproj、vcenv.bat等提供Visual Studio工程配置,catnls、catdlg、bmp用于界面和资源,mkdg、mk、mkb等为编译链接辅助脚本,catpart、catproduct可验证几何操作效果。目前已有501人学习下载,具备一定参考热度。通过研读这些代码,可掌握CAA开发环境搭建、工作台与自定义菜单设计、对象模型访问、事件响应以及模块打包部署等关键流程,还可结合示例学习CAA API中TopoDS_Shape、Handle_TDocStd_Document等常用类用法,为独立开发可靠CATIA插件提供扎实参考。
1. CATIA CAA 二次开发不是装个 SDK 就能跑:这份代码资源帮你绕过环境配置的坑
CATIA CAA 二次开发的第一个拦路虎不是 C++ 语法,而是环境配置。我见过不少同行卡在vcenv.bat报错、SDK 版本对不上、生成的 DLL 加载后 CATIA 直接崩溃这类问题上,一耗就是两三天。这份第 06 讲代码资源包里没有长篇大论的 PPT,而是直接给了能跑的环境脚本和资源文件——vcenv.bat负责把 CAA 开发所需的编译环境和 CATIA 安装环境一次性对齐,几个I_Hdr6.bmp、I_1Normal.bmp则是自定义命令工具条必需的图标资源,省掉你自己去 PS 里画按钮图标的功夫。适合正在做 CATIA 插件、自动化工具、或者想从 VBA 迁移到 CAA 的工程师。下面我会按「环境 → 架构 → 代码 → 排错 → 落地」的顺序,把这套资源里真正值钱的东西拆开讲。
2. 先搭环境再写代码:vcenv.bat、SDK 与 Visual Studio 的三层配置
2.1 vcenv.bat 到底做了什么
CAA 开发环境最大的痛点是环境变量太多。你至少需要配置 CATICPath、CATLibPath、Path 等十几项,而且 CATIA 安装目录、SDK 目录、Visual Studio 版本三者只要有一处对不上,编译出来的模块在加载阶段就会静默失败——不报错、不提示,CATIA 里就是找不到你的命令。
vcenv.bat这个批处理的本质,是把「Visual Studio 的 cl.exe 环境」和「CAA SDK 的编译环境」合并到同一个命令行会话里。常见做法是它内部先调用vcvarsall.bat(Visual Studio 提供的环境初始化脚本),再追加 CAA 相关的 include 和 lib 路径。拿到这套资源后,第一步不是打开 Visual Studio 就写代码,而是先打开一个 CMD 窗口,执行一遍vcenv.bat,确认echo %CATICPath%能输出实际路径。
如果你需要自己维护这份脚本,核心逻辑大致是这样:
@echo off call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 set CATIA_PATH=C:\Program Files\Dassault Systemes\B26 set SDK_PATH=%CATIA_PATH%\CAA set CATICPath=%SDK_PATH%\MSC\CNext\CNext\Includes;%SDK_PATH%\MSC\CNext\CNext\Includes set CATLibPath=%SDK_PATH%\MSC\CNext\CNext\Lib;%SDK_PATH%\MSC\CNext\CNext\Lib\Win64 set Path=%SDK_PATH%\MSC\CNext\CNext\Code\Win64;%CATIA_PATH%\win_b64\code\bin;%Path% echo CAA environment ready.提示:CATICPath 是头文件搜索路径,CATLibPath 是库文件搜索路径,Path 里必须同时包含 CATIA 的
win_b64\code\bin,否则后续编译出的模块运行时找不到 CATIA 的启动器。
逻辑说明:上面这段脚本先给当前 CMD 会话注入 MSVC 的编译器环境,再追加 CATIA 安装路径下的 CAA 头文件和库路径。x64参数对应 64 位架构,如果你用的是 32 位 CATIA,要改成x86。执行完以后,所有编译命令都必须在同一会话里运行,否则环境变量又丢了。
参数说明:B26是 CATIA V5 的版本代号(R26),不同版本对应不同代号,比如 R21 是 V5R21。如果你机器上装的是 R29,这里要改成对应的目录名。win_b64是 64 位编译产物的默认输出目录名,这是达索的固定结构,不要改。
2.2 CAA SDK 选型与版本对应关系
CATIA CAA 的开发方式分 CAA V5 和 CAA R3 两条线。CAA V5 是伴随 CATIA V5 时代的经典路线,只能在 Windows 上用,语言以 C++ 为主,IDE 通常绑 Visual Studio;CAA R3 则是面向 3DEXPERIENCE 平台的现代架构,支持跨平台。这份代码资源走的是 CAA V5 路线,类库前缀是CAT开头,编译产物是.dll加.module文件,这是你判断代码属于哪条线的最快方式。
SDK 版本和 CATIA 版本必须严格对应。R26 的 SDK 不能给 R27 的 CATIA 写插件,这不是接口变了,而是 COM 注册表的 GUID 和类型库版本不匹配。实际工作中,我会在机器上保留两个版本的 CATIA 环境隔离测试,但开发机上只装一个版本,避免vcenv.bat同时指向两条路径时系统傻掉。
2.3 从环境脚本到第一次编译:三步验证
拿到代码资源先别急着看业务逻辑,先复现一遍从环境到编译的完整链路:
- 打开 CMD,执行
vcenv.bat,确认cl命令可用。 - 进入代码资源里的模块目录,执行
mkmk进行增量编译。 - 编译成功后在
win_b64\code\bin目录下找到.dll,在 CATIA 里用Tools -> Command List找到你注册的命令 ID。
如果第一步就失败,检查脚本里的路径是否存在。mkmk是 CAA 的专有构建工具,它读取模块目录下的Imakefile.mk来决定编译哪些源文件,后面第 4 章会专门讲这个文件。第三步如果找不到命令,绝大多数情况不是编译问题,而是命令的CATEAddMenuCommand注册名和资源文件里的CATCmdContainer不一致。
注意:首次编译时
mkmk会连带生成一堆中间代码,耗时 10 到 20 分钟属正常现象。CAA 的框架会先执行 Code Generator 生成接口实现代码,这个过程容易被认为是死机,实际是在跑代码生成器。
3. CAA V5 架构不是黑匣子:工作台、对象模型与命令生命周期
3.1 对象模型的核心:CATBaseUnknown、智能指针与引用计数
CAA 的对象模型和 CATIA 软件本身是同构的。一切的根是CATBaseUnknown,它实现了 COM 风格的引用计数,你用到的CATIProduct、CATIDocument等都继承自它。这里有个关键习惯:所有接口指针的传递和持有都要用CATSmartPtr或者 CAA 推荐的CATI..._var类型,它们负责自动管理引用计数,防止内存泄漏。
我见过很多从 MFC 转过来的同事,习惯性用裸指针存 CAA 接口对象,结果 CATIA 运行一会儿就内存暴涨。这不是 CAA 的问题,是引用计数没人释放。正确做法是这样:
// 获取当前文档的 Product 接口 CATIDocument* pDoc = NULL; CATFrmEditor::GetCurrentEditor()->GetDocument(pDoc); CATIProduct_var spRootProduct = pDoc->GetProduct(); if (NULL_var != spRootProduct) { // 用 spRootProduct 操作根节点 CATUnicodeString strName = spRootProduct->GetName(); }逻辑说明:CATFrmEditor用来取当前激活的编辑器关联的文档,GetDocument返回原始指针,所以只在局部使用不持久化。spRootProduct用_var后缀的智能指针声明,离开作用域自动释放引用,不需要手动Release()。
参数说明:NULL_var是 CAA 提供的智能指针空值检查宏,不要写成NULL或nullptr,因为智能指针重载了比较运算符,NULL_var才是规范写法。取出的名字是CATUnicodeString类型,不能直接当std::string用,需要调用ConvertToChar()转换。
每个 CATIA 文档的根是一个 Product,下面挂 Part、Product 子节点和几何元素。这个树状结构和 Windows 注册表很像:你想操作什么,就先拿到对应接口,再一层层往下查。
3.2 工作台与命令:CmdContainer 到 Accl 的完整链路
用户每次在 CATIA 里点一个按钮,背后走的链路是:工具条图标 → 命令 ID → 命令类 → 实现类。这套机制在 CAA 里叫CATCommand和CATCommandExtension。
创建一条新命令需要三个文件:头文件声明命令类、.cpp实现CreateCommand和命令槽函数、资源文件里写命令容器(CmdContainer)。资源文件里定义如下:
CATCmdContainer pContainer = { "MyCmdContainer", 0, "MyCommand", "MyHeader", 0, 0, 1, 0, 0, 0, 0 }; CATCmdHeader pHeader = { "MyHeader", 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; CATCmdStarter pStarter = { "MyCommand", 0, "MyModuleCommand", "CmdMyModule", 0, 0, 0, 0, 0, 0, 0, 0 };提示:这段看起来像天书的结构体,实际定义在
CATCommandHeader.h里。CATCmdStarter的第一个参数是命令对外暴露的 ID,用CATEAddMenuCommand("MyModule", "MyHeader", "MyCommand", "MyCommandHelp")注册到菜单。
逻辑说明:这组结构体把「命令容器(工具条)→ 头(分组)→ 命令」三级关系在编译期就定了。最常用的是第一个参数,命令 ID 必须和.cpp里调用NewAccess时用的名字完全一致,大小写敏感。
在实际开发中,我更建议直接通过CATEAddMenuCommand在模块初始化函数里注册命令,而不是手写这一堆结构体——前者出错时会有明确的运行时报错,后者写错一个字段,命令直接消失且没有任何提示。
3.3 事件处理:Model Modified 与文档生命周期
CAA 的事件机制基于CATCallback和CATCommand的消息分发。按钮点击、模型修改、文档开关,都会触发对应的事件回调。最常见的需求是「模型被修改后自动更新 BOM 数据」,实现方式是给元素挂一个CATISpecObject的CATModelModified事件回调。
CATCallback cb = 0; CATISpecObject_var spSpec = spRootProduct->GetReference(); cb = spSpec->AddModelModifiedCallback(&MyNotifyClass::ModelModified, this);逻辑说明:AddModelModifiedCallback接收一个回调函数指针和一个上下文对象this。回调函数签名必须是int ModelModified(CATCallbackEvent iEvent, void* iClientData, CATNotification* iNotification),前两个参数固定,第三个是事件携带的通知对象。
参数说明:iClientData就是传进去的this,回调执行时可以把iClientData强转回你的类指针访问成员变量。回调返回 0 表示处理成功,非 0 值会被 CAA 视为异常终止链。事件注册后一定要在模块卸载时移除,否则再次加载模块时回调会重复注册,一个修改触发两次响应。
4. 动手创建 CAA 模块:从 Imakefile 到几何遍历的完整代码
4.1 模块骨架:Imakefile.mk 与 mkmk 的配合
CAA 的每个功能模块是一个独立目录,里面必须有Imakefile.mk文件。它是mkmk的输入,定义了源文件列表、依赖库、输出类型。下面是一个最简模块配置:
# Imakefile.mk BUILD_TYPE = dll MODULE_NAME = MyCAAModule SOURCES = MyModule.cpp \ MyCmd.cpp \ MyImplementation.cpp LIBS = CATProductInterfaces \ CATPartInterfaces \ CATTopologicalInterfaces \ CATVisualizationInterfaces逻辑说明:BUILD_TYPE指定产出物类型,dll表示生成动态库;SOURCES列出所有参与编译的.cpp文件,每行一个文件用反斜杠续行;LIBS列的是依赖的 CAA 库名,这些名字对应 SDK 里的.dll,写错了编译时会在链接阶段报「无法解析的外部符号」或直接提示找不到库文件。
参数说明:MODULE_NAME就是最终生成的.dll和.module文件的基名。模块编译后,CATIA 通过.module文件来识别插件的元数据,这里面记录了模块依赖项,如果缺失会在加载时报CATIA 无法启动应用程序。业务上,LIBS里的库名可以通过 SDK 安装目录下的Instributed文件夹对照查阅,不确定依赖哪个时就全列上——编译慢一点但不会漏。
写完Imakefile.mk后,在模块目录上执行:
mkmk逻辑说明:mkmk会自动解析依赖、调用Code Generator生成接口实现的模板代码、再调用 MSVC 完成编译。首次运行会输出大量日志,末尾出现BUILD SUCCESSFUL就是成功了。
4.2 接口定义与实现分离:CAA 的规范写法
CAA 要求你的「对象服务」必须拆分接口(Interface)和实现(Implementation)。接口用.h声明,实现用.cpp实现,中间由 Code Generator 生成TIE和IMP模板代码。这和你平时写 C++ 类最大的不同是:CAA 的接口类不包含实现,只描述和外部交互的方法签名。
// 接口定义: MyCalculator.h #ifndef MyCalculator_H #define MyCalculator_H #include "CATBaseUnknown.h" #include "CATUnicodeString.h" class MyCalculator : public CATBaseUnknown { CATDeclareInterface; public: virtual double Add(double a, double b) = 0; virtual double Multiply(double a, double b) = 0; }; CATImplementInterface(MyCalculator, CATBaseUnknown); #endif// 实现: MyCalculatorImpl.cpp #include "MyCalculator.h" #include "TIE/MyCalculator.h" class MyCalculatorImpl : public MyCalculator { public: double Add(double a, double b) { return a + b; } double Multiply(double a, double b) { return a * b; } }; TIE_MyCalculator(MyCalculatorImpl);逻辑说明:接口类里CATDeclareInterface声明这是一个 CAA 接口;实现类里TIE_MyCalculator(MyCalculatorImpl)是最关键的一行,它把接口分发的骨架代码生成出来,让你不需要手写 QueryInterface 的分发逻辑。
参数说明:CATImplementInterface宏的第二项是父接口,必须有;TIE_前缀的宏定义在TIE目录下的同名头文件里,由 Code Generator 在编译前自动生成,所以你在 SDK 里直接搜TIE_MyCalculator.h可能搜不到,要先跑一次mkmk才会生成。
4.3 遍历几何体:用 TopoDS_Shape 提取零件的实体信息
CAA 操作三维几何最有代表性的场景,是提取一个 Part 里所有实体的表面积和体积。这依赖的是拓扑数据模型(Topology),核心类型是TopoDS_Shape。操作流程是:从 Product 导航到 Part,再从 Part 拿到CATBody,最后遍历CATBody里的 Faces。
// 遍历 Part 的所有 Body 并计算每个 Face 的面积 #include "CATIProduct.h" #include "CATIPartEditor.h" #include "TopoDS_Shape.hxx" #include "CATTopData.h" #include "CATGeoFactory.h" #include "CATCreateTopOperator.h" #include "CATFrFSurface.h" #include "CATBody.h" CATIPartEditor_var spPart = spRootProduct->AsPartEditor(); if (NULL_var != spPart) { CATBody_var spBody = spPart->GetBody(); TopoDS_Shape shape = spBody->GetShape(); CATTopData topData; CATGeoFactory* pFactory = CATCreateGeoFactory(); // 遍历 Shape 的每个面 CATLISTP(CATCell) faceList; GetCellList(shape.GetContainer(), 2, faceList); for (int i = 1; i <= faceList.Size(); i++) { CATFace* pFace = (CATFace*)faceList[i]; CATSurface* pSurface = pFace->GetSurface(); // 在这里计算曲面积分或提取面的属性 } pFactory->Release(); }逻辑说明:AsPartEditor把 Product 接口转成 Part 编辑接口,这一步只适用于 Part 文档,对 Product(装配体)会返回空指针。GetCellList的第二个参数传入2表示只获取面(Face),这个枚举值的定义是:0 为点、1 为边、2 为面、3 为体。遍历得到的CATFace可以继续调用GetSurface()拿到几何曲面CATSurface。
参数说明:CATCreateGeoFactory()创建的是几何工厂,负责管理几何对象的生命周期,用完必须Release(),否则一帧内容易累积内存。GetCellList拿到的是CATLISTP(CATCell)类型,下标从 1 开始,不是从 0 开始,这和其他 C++ 容器习惯不同,写for循环时注意别越界。
这段代码的价值在于:它是很多自动化功能的地基。BOM 导出、干涉检查、模型分析,本质都是先遍历几何体再做业务计算。实际计算每个面的面积需要用CATFrFAdvancedSurface做参数域积分,代码量比较大,这里不展开;但如果你要做的是「检测模型中是否存在碎面」,上面的遍历代码已经够用了。
5. 避坑指南:CAA 调试、部署与版本兼容的六个常见问题
5.1 模块可以编译但 CATIA 里找不到命令
- 现象:
mkmk编译成功,DLL 也生成在win_b64\code\bin下了,但 CATIA 工具条里就是找不到对应的命令。 - 原因:命令注册名和命令 ID 不一致,或者模块没有被 CATIA 加载。CAA 的模块加载机制是启动时扫描
code\bin目录下的.dll文件,如果 DLL 依赖的另一个模块没加载,整个模块会被静默跳过。 - 解决:先用
depends.exe或dumpbin /dependents检查 DLL 的依赖库是否都在code\bin里;再确认CATEAddMenuCommand的第三个参数和CATCmdStarter里写的命令 ID 字母完全一致(区分大小写)。如果确认无误,删除code\bin下的.module文件清空注册缓存后重启 CATIA。
5.2 vcenv.bat 执行后 cl 命令不可用
- 现象:CMD 窗口执行完
vcenv.bat,输入cl提示不是内部或外部命令。 - 原因:最常见的两种情况:一是脚本里
call vcvarsall.bat没有生效,二是 Windows 的「受控文件夹访问」拦截了脚本写入环境变量。另外,如果你在 PowerShell 里执行.bat文件,环境变量不会保留到 PowerShell 会话。 - 解决:确认脚本是用
call调用 vcvarsall 而不是直接执行(否则控制权不返回);改用 CMD 而不是 PowerShell;如果开启了系统保护,把 CATIA 安装目录加入白名单。
5.3 工具条有图标但点击后 CATIA 崩溃
- 现象:命令图标显示正常,上班时发现 CATIA
闪过一个错误就退出了。 - 原因:命令类里
CreateCommand返回的指针没有正确初始化,或者命令实现类里访问了一个为NULL的接口指针。CAA 对空指针访问没有容错,直接触发访问冲突。 - 解决:给命令类的构造函数里所有成员指针初始化为
NULL,并在CreateCommand里对CATCommand的SetAccess调用点做判空。如果仍崩溃,在 Visual Studio 里开启「本机代码调试」,用F5附加到CATIA.exe进程,崩溃时查看调用堆栈定位行号。
5.4 Debug 版本模块在 Release 版 CATIA 里无法加载
- 现象:本地 VS 调试模式下生成的模块,拷到同事机器上的 CATIA 里没反应。
- 原因:CAA 模块的 Debug 版本依赖 Debug 版 CRT 和 Debug 版 CAA 库,Release 版 CATIA 只会加载 Release 版模块。这是最常见的「在我机器上好好的,到别人那就不行」的原因。
- 解决:对外发布时强制切到 Release 配置重新
mkmk,并确认Imakefile.mk里的编译宏是NDEBUG而不是_DEBUG。调试与部署用两个不同的输出目录,避免混用。
5.5 自定义工具条位置错乱或图标不显示
- 现象:命令加载成功,但图标显示为空白,或者工具条出现在界面左上角,和预期位置不对。
- 原因:CAA 命令的图标文件(
.bmp)需要放在code\bin\resources目录下,文件名要和命令 ID 的 first 参数对应。I_Hdr6.bmp这类资源文件如果没被拷贝到正确目录,CATIA 会用空白图标替代。位置错乱则是因为资源文件里的CATCmdContainer的父级参数指错了工作台。 - 解决:把资源包里的
.bmp文件放到code\bin\resources下,并确认模块资源文件.rcc中被引用。工具条位置建议从既有工作台派生,不要用全局容器,这样默认位置和 CATIA 原生工具条保持一致。
5.6 CAA 模块加载报「类型库未注册」
- 现象:CATIA 启动时报错弹窗,提示模块类型库没有注册。
- 原因:首次编译后没有执行注册操作。CAA 模块不像普通 COM 组件用
regsvr32,而是模块加载时通过.rcc文件自动注册类型库,但.rcc文件没有被识别。 - 解决:检查模块目录里是否生成了
.rcc文件,如果只有 DLL 没有 rcc,检查Imakefile.mk里是否漏掉了RESOURCES字段。可以在开发机上手动执行CATRegTool完成注册,但这只能缓解,正确做法是让 mkmk 在编译时把 rcc 拷到code\bin目录。
6. 落地技巧:用 CAA 从装配体导出 BOM 清单的完整实现
装配体 BOM 导出是 CATIA 二次开发里被问得最多的需求,也是这套代码资源最直接的落地场景。从装配体里遍历所有 Product 节点,提取零件编号、名称、实例路径、数量、材质等信息,输出成 CSV 或 Excel 可读的格式。核心是理解 CATIA 装配树的数据结构:一个装配体是嵌套的 Product 树,每个实例对应一个 Product Reference,多个实例可能引用同一个 Part。
6.1 遍历 Product 树并收集零件属性
CAA 遍历装配树的入口接口是CATIProduct,每个节点都有Children和GetReference,递归遍历即可拿到完整的实例列表。写递归时最关键的是防止重复计数——同一个 Part 被装配两次,BOM 里要按数量累加,而不是输出两行。
// BOM 导出:递归遍历装配树 #include "CATIProduct.h" #include "CATIInstance.h" #include "CATLISTV_CATBaseUnknown.h" #include <fstream> void CollectBOM(CATIProduct_var spProduct, std::map<CATUnicodeString, int>& bomMap) { CATUnicodeString partName = spProduct->GetName(); // 判断是否叶子节点:没有子节点的 Product 是 Part 实例 CATLISTV(CATBaseUnknown_var) children; spProduct->GetChildren(children); if (children.Size() == 0) { // 同一零件多实例时累加数量 bomMap[partName] = bomMap[partName] + 1; return; } // 有子节点就递归遍历 for (int i = 1; i <= children.Size(); i++) { CATIProduct_var spChild(children[i]); if (NULL_var != spChild) { CollectBOM(spChild, bomMap); } } }逻辑说明:GetChildren返回子节点列表,判定叶子节点的条件是子节点数量为零。bomMap用CATUnicodeString做键、int做数量累加,这样同一个 Part 被装配多次时,数量正确累加而不是输出多条重复记录。
参数说明:CATLISTV是 CAA 的动态数组模板,注意它的Size()返回 1 基索引长度。children[i]取出的是CATBaseUnknown_var,转成CATIProduct_var需要做一次接口跳转,这里用的是构造函数式转换,比QueryInterface更简洁。CATUnicodeString作为std::map的键需要重载<,CAA 已经默认实现了,直接用即可。
6.2 输出为 CSV 并用 Excel 打开不乱码
收集完 BOM 数据后,输出文件需要注意两个工程细节:CSV 的编码和字段顺序。CATIA 里的零件名常包含中文,直接输出 UTF-8 编码的 CSV,Excel 打开会乱码。常见做法是输出带 BOM 头的 UTF-8,或者直接用本地代码页(GBK)。
// 输出 BOM 到 CSV,UTF-8 with BOM 确保 Excel 正常显示中文 void WriteCSV(const std::map<CATUnicodeString, int>& bomMap, const char* filePath) { std::ofstream out(filePath, std::ios::binary); // UTF-8 BOM 头 unsigned char bom[] = {0xEF, 0xBB, 0xBF}; out.write((const char*)bom, 3); out << "PartName,Quantity\n"; for (auto& item : bomMap) { CATUnicodeString name = item.first; char* utf8Name = name.ConvertToChar(); out << utf8Name << "," << item.second << "\n"; } out.close(); }逻辑说明:前三字节0xEF 0xBB 0xBF是 UTF-8 的 BOM 标记,Excel 靠它识别编码。ConvertToChar()返回的字符指针在 CAA 内部是char*,调用后不需要手动释放,但如果循环调用注意在一条语句里用完转存,避免指针被内部回收。
参数说明:字段顺序先零件名再数量,这是 BOM 最常见的数据结构。如果后续要加材质、重量、供应商,在这个 CSV 的行字段里追加即可,但要注意字段值里如果包含逗号,需要给字段加双引号转义——治标的方法是导出时统一把所有字段都包上双引号。
6.3 CAA 与 VBA 的取舍:什么时候用 CAA 而不是 VBA
经常有人问,BOM 导出用 VBA 也能做,为什么要用 CAA。我的判断标准很简单:只导出零件号和数量,VBA 够用;但 VBA 的资源占用高而且依赖 CATIA 前台运行,遇到大装配体,VBA 跑一个 5000 零件的装配树会卡得没法看。CAA 的优势是运行在 CATIA 进程内、直接用原生对象模型,遍历效率高一个量级,还能做成无界面的后台命令,放进批处理里无人值守跑。
代价是开发和调试成本。VBA 里一行GetChildren搞定的事,CAA 里要写递归、管引用计数、处理CATUnicodeString和std::string的转换,编译一次也要一两分钟。如果你只是临时导出一次 BOM,用 VBA 没问题;但如果是给整个部门用的工具,或者要集成到 PLM 流程里,CAA 是唯一能满足稳定性的路线。
我第一次做 CAA 模块时,因为没写vcenv.bat的call关键字,环境变量一直没生效,白折腾了一整天;后来又因为命令 ID 里少了一个大写字母,工具条上怎么都找不到自己写的按钮。从那以后,我每次拿到 CAA 代码资源,都强制自己先完整走一遍环境脚本、编译、加载、命令出现这套链路,再深入看业务逻辑——这套顺序能帮你筛掉八成早期翻车点。希望帮到你。
本文还有配套的精品资源,点击获取