简介这套ObjectARX与AutoCAD云平台点云处理开发包面向从事CAD二次开发及三维点云数据技术的工程人员可用于AutoCAD功能扩展与云端点云应用的原型验证。资源聚焦于ObjectARX与AutoCAD云平台的结合讲解如何实现大规模点云的加载、渲染、过滤、测量以及多用户协同为BIM建模、地理信息分析、文物遗址保护等领域提供开发参考。RAR压缩包内文件总数510个大小约2.21MB代码部分以142个h头文件、100个cpp源文件与72个hpp头文件为主体构成完整C工程结构配套6个sln与5个vcxproj工程文件便于直接编译5个exe程序为编译产物82个bmp与45个png为界面图标、工具栏和启动画面等视觉资源。已有108人下载学习。通过这套工程源码、界面资源及文本说明可快速了解ObjectARX项目目录组织方式、点云数据读入流程、渲染显示管线与云平台协同接口有助于搭建具备点云加载、降采样、特征提取、空间量测等功能的原型工具并可直接复用于城市测绘、建筑规划、地形灾害评估、文物数字化等实际场景。1. ObjectARX 往云端搬之前aNeva 到底是个什么工程接手过 ObjectARX 项目的人应该都有类似经历插件在本地 AutoCAD 里跑得欢老板一句“要上云、浏览器里也能看能改”看着满屏的 acrxEntryPoint 和 ads_ 前缀函数就开始头痛。aNeva_ObjectARXautocad_cloud_ 这类工程名拆开看就是三件事aNeva 是公共封装层的代号ObjectARX 是 AutoCAD 的 C 二次开发 APIcloud 是你要接的远端服务。整篇文章想讲清楚的是这套方向从环境搭建、命令改造到云化落地每一步具体怎么做、参数怎么配、坑在哪里。适合正在做 CAD 插件开发、或者打算把存量 ARX 工具搬上云端的一线开发者。结论先放在前面真正的难点不在 API 本身在 AutoCAD 的进程模型以及你打算让哪一层去碰网络。2. 先让 ObjectARX 工程在本地跑通版本搭配与最小命令很多人在这一步就开始翻车但翻的往往不是代码是环境。ObjectARX 对版本的要求苛刻到近乎强迫症AutoCAD 2024 只能用 VS2022 17.x 编译出来的 ARX2023 对应 VS20222020 对应 VS2019。版本错一位加载时报错能把人看懵。别指望“向下兼容”ARX 是二进制插件SDK 版本和 AutoCAD 主程序版本必须严丝合缝。2.1 版本搭配表SDK、编译器与 AutoCAD 的对应关系我自己维护项目时会做一张表贴在工位上避免每次换电脑都重试一遍。AutoCAD 版本Visual Studio 版本ObjectARX SDK 版本平台AutoCAD 2024VS2022 17.xObjectARX 2024 SDKx64AutoCAD 2023VS2022 17.xObjectARX 2023 SDKx64AutoCAD 2020VS2019 16.xObjectARX 2020 SDKx64AutoCAD 2018VS2017 15.xObjectARX 2018 SDKx64这里有几个隐藏约束网上很多帖子不会说。第一SDK 需要到 Autodesk 开发者门户注册后下载第三方下载站拿到的东西经常缺头文件。第二编译目标平台必须选 x64AutoCAD 2020 之后的主程序是 64 位你编一个 Win32 的 ARX 进去它连加载都不会尝试。第三机器上装了多个 VS 版本时要用对应版本的“开发人员命令提示符”来编译不要直接用 IDE 默认配置。这些前置搞不定后面所有代码都是空谈。2.2 用 ArxWiz 向导生成最小 ARX 工程常见做法是先装 ArxWiz 的 VSIX 向导插件在 VS 里新建项目时选 ObjectARX 模板生成一个能跑的最小工程。生成过程中有几个选项影响后续调试体验DLL 类型选常规 DLL不勾 MFC预编译头建议打开ObjectARX 的头文件数量会让每次全量编译慢到怀疑人生字符集选 UnicodeAutoCAD 内部字符串就是宽字符。生成后把入口文件替换成下面这个最小实现先确认命令通道是通的// aNevaARX.cpp : ObjectARX 最小入口与命令注册 #include StdAfx.h #include acedCmdNF.h #include rxregsvc.h // 业务函数打印一行文本并统计当前选择集里的对象数量 void aNevaSayHello() { acutPrintf(_T(\n[aNeva] hello from ObjectARX 2024)); ads_name sset; // 第一个参数传 NULL 表示在命令行交互式选择 if (acedSSGet(NULL, nullptr, nullptr, nullptr, sset) RTNORM) { long len 0; acedSSLength(sset, len); acutPrintf(_T(\n[aNeva] you picked %ld object(s)), len); acedSSFree(sset); } } // 通过静态函数包一层避免命令回调签名在不同 SDK 上不一致 static void aNeva_Hello() { aNevaSayHello(); } // ARX 统一入口动态库加载 / 卸载时由 AutoCAD 调进来 extern C AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt) { switch (msg) { case AcRx::kInitAppMsg: // 解锁应用程序并声明支持多文档环境 acrxDynamicLinker-unlockApplication(pkt); acrxDynamicLinker-registerAppMDIAware(pkt); acedRegCmds-addCommand( _T(ANEVA_CMDS), // 命令组名卸载时按组移除 _T(ANEVA_HELLO), // 全局命令名命令行输入这个 _T(ANEVA_HELLO), // 本地命令名中文版可换成中文别名 ACRX_CMD_MODAL, // 模态命令不接受透明调用 aNeva_Hello); // 实际执行函数 break; case AcRx::kUnloadAppMsg: acedRegCmds-removeGroup(_T(ANEVA_CMDS)); break; } return AcRx::kRetOK; }这段代码的逻辑按 AutoCAD 的加载链路拆开看acrxEntryPoint 是整个 ARX 的命门工程里所有初始化都在 kInitAppMsg 分支做所有清理都在 kUnloadAppMsg 分支做。addCommand 的参数里有三个地方值得注意第一个是命令组名卸载时按组删除避免逐个命令清理第二个和第三个分别是全局命令名和本地命令名我习惯让它们保持一致第四个参数 ACRX_CMD_MODAL 表示这个命令在文档打开状态下执行如果是查询类命令可以改成 ACRX_CMD_TRANSPARENT允许在其他命令执行中穿插调用。有个坑必须提中文版 AutoCAD 的命令行对英文全局命令名支持没问题但如果你分发给国内用户最好把本地命令名改成中文别名例如 _T(你好云)否则用户在命令行敲 ANEVA_HELLO 总感觉别扭。全局命令名和本地命令名指向同一个函数不冲突。2.3 编译、加载、调试三步走工程配置好之后按 F5 之前先把调试器指向 acad.exe项目属性里 Debugging 选项卡Command 填 AutoCAD 安装目录下的 acad.exeWorking Directory 填到支持文件搜索路径。这样 F5 会直接拉起 AutoCADARX 会被当作启动项加载断点可以直接命中。第一次尝试时不建议这样我一般手动加载步骤是以管理员身份启动 AutoCAD命令行输入 ARX 回车选择编译出来的 .arx 文件再输入 ANEVA_HELLO看到屏幕打印就算命令通道打通。别用 APPLOAD 加载 ARX那是给 LISP 和 .NET 程序用的ARX 一定要通过 ARX 命令或者 acrxLoadModule。调试符号这块是最容易被忽略的。编译要同时生成 .pdb 文件并把 .pdb 和 .arx 放在同一目录否则断点进来全是汇编。加载失败时先看 ARX 命令的回显信息最常见的两类报错一是“无法找到入口”说明 acrxEntryPoint 没有被正确导出检查工程的 .def 文件或者 extern C 声明二是“版本不匹配”说明 SDK 和当前 AutoCAD 版本对不上。代码逻辑先放一边把加载问题解决再谈云化这是血泪经验。3. aNeva 封装层怎么设计ARX 命令访问 cloud 的三条主干路aNeva 在工程里不是某个公开的开源库我更愿意把它理解为你给公共封装层起的代号关键在职责边界。经验是业务命令里不要直接出现 AcDb、AcEd 的调用更不要直接出现 HTTP 客户端代码。命令只做两件事——从 AutoCAD 拿数据、把结果交给服务层。这样本地跑和云端跑的差别只体现在服务层业务逻辑不用改。3.1 为什么需要一层封装命令、服务、传输三层分离很多 ARX 插件写着写着就变成一坨命令函数里直接读数据库、直接弹对话框、直接发网络请求最后想加一个“批量处理”入口时发现核心逻辑没法复用只能复制粘贴。aNeva 这层封装的作用就是把命令注册、业务处理、网络传输拆开。命令层只负责和 AutoCAD 交互比如 acedSSGet 选对象、遍历块表服务层定义业务接口比如“上传图纸信息”“查询任务状态”传输层负责真正往云端发请求。这样做还有一个实际好处本地调试时可以用假数据传输层不依赖网络和云端环境。很多功能在没有外网的环境里也能联调 UI 和数据库逻辑等网络通了再切真实现。这就和 QTools 那一类工具插件不同它们功能丰富但往往把命令注册和业务逻辑揉在一起用户改一个快捷键设置都可能触发连锁问题。封装层从第一天就留好后面上云会省掉一次大重构。3.2 在 ARX 命令里发 HTTP 请求一个最小可用的 POST 客户端ARX 是 C 环境发 HTTP 请求的常见选择是 C REST SDKcpprest通过 vcpkg 安装即可。画重点绝对不要在命令函数里用 wait() 阻塞等待响应AutoCAD UI 线程一旦卡住用户拖动窗口就会无响应然后整个 CAD 被标记为“未响应”。正确做法是把网络请求丢到后台线程用 then 链式回调处理结果。下面是封装后的传输层代码// CloudTransport.cpp : aNeva 传输层最小实现 #include cpprest/http_client.h #include cpprest/json.h #include acedCmdNF.h using namespace web; using namespace web::http; using namespace web::http::client; // 将 JSON 字符串 POST 到云端网关 void aNevaPostJson(const std::wstring url, const std::wstring jsonBody) { // 拆出 host 和 path避免每次拼错 http_client client(url); http_request request(methods::POST); request.headers().add(U(Content-Type), U(application/json)); request.set_body(jsonBody); // 超时给 15 秒云端网关慢的时候别让命令卡死 client.request(request).then([](http_response resp) { if (resp.status_code() status_codes::OK) { acutPrintf(_T(\n[aNeva] upload ok)); } else { acutPrintf(_T(\n[aNeva] upload failed, http %d), resp.status_code()); } }).wait(); // 仅用于最小示例真实命令不要这样写 }这段代码逻辑不复杂构造 client、构造 request、设置 Content-Type 和 JSON 体、发送、处理响应。但注意代码最后一行我写的是“仅用于最小示例”真实命令千万不要用 wait()。我在生产代码里的做法是把 aNevaPostJson 放到 std::thread 里执行在网络回调里用 AcApDocManager 把结果切回文档线程再刷新界面。这一步是 ARX 云化里最容易出玄学问题的地方不切线程直接访问文档轻则界面不刷新重则直接触发“将关闭 AutoCAD”。参数上有几个地方要按实际环境调url 参数建议只传网关地址加路径不要每次都拼完整字符串方便后续换 Spring Cloud Gateway 之类的统一入口jsonBody 用 wstring因为 cpprest 默认走 UTF-16超时时间 15 秒是折中值局域网内可以缩到 5 秒走公网则建议 20 秒以上还要在网关侧配好响应超时否则客户端等不到响应会误判失败。3.3 DWG 数据“抽壳”上云把图框属性读成 JSON很多场景不需要把整个 DWG 传上云图纸可能几百 MB传输慢、版本复杂、还有敏感信息。常见做法是只提取业务数据比如图框里的图号、图名、版本、比例生成 JSON 后上传。这一步是 ObjectARX 拿手好戏核心是遍历块表和属性。下面这段代码读取模型空间里所有块引用提取块名和插入点// DwgExtract.cpp : 提取块引用与插入点 #include dbapserv.h #include dbblock.h #include dbents.h void aNevaExtractBlockRefs(AcDbDatabase* pDb) { // 拿到模型空间块表记录 AcDbBlockTable* pBlockTable nullptr; pDb-getBlockTable(pBlockTable, AcDb::kForRead); AcDbBlockTableRecord* pModel nullptr; pBlockTable-getAt(ACDB_MODEL_SPACE, pModel, AcDb::kForRead); pBlockTable-close(); // 遍历模型空间里所有实体 AcDbBlockTableRecordIterator* pIter nullptr; pModel-newIterator(pIter); for (; !pIter-done(); pIter-step()) { AcDbEntity* pEnt nullptr; pIter-getEntity(pEnt, AcDb::kForRead); // 只处理块引用其他实体跳过 if (pEnt-isKindOf(AcDbBlockReference::desc())) { AcDbBlockReference* pRef AcDbBlockReference::cast(pEnt); AcDbObjectId blockId pRef-blockTableRecord(); AcDbBlockTableRecord* pBlkRec nullptr; acdbOpenObject(pBlkRec, blockId, AcDb::kForRead); const ACHAR* blkName pBlkRec-getName(); AcGePoint3d pt pRef-position(); acutPrintf(_T(\n[aNeva] block %ls at (%lf, %lf)), blkName, pt.x, pt.y); pBlkRec-close(); } pEnt-close(); } delete pIter; pModel-close(); }这段代码的注意点集中在对象生命周期上。getEntity 返回的实体对象默认以 kForRead 打开用完必须 close否则该实体一直被锁住用户后来想编辑时会卡住。isKindOf 判断实体类型是 ARX 的标准姿势不要用 dynamic_castAcDb 对象不是标准 C 对象。块引用的 blockTableRecord() 返回的是 ObjectId需要再次打开才能拿到块名打开后同样要 close。最后 delete pIter遍历器是 new 出来的不释放会造成内存泄漏而 AutoCAD 对这种泄漏非常敏感跑一晚上内存占用能翻几倍。抽壳得到 JSON 之后往云端传哪一条路取决于你的业务规模。给三张路线图供判断方案改造量延迟适用场景关键技术Autodesk Platform Services原 Forge中秒到分钟级浏览器看图、测量、模型轻量化APS Model Derivative自建 DWG 解析 / 批处理服务大毫秒到秒级服务器批量处理无 AutoCAD 环境RealDWG / ODA云桌面 现有 ARX小取决于网络保留存量插件快速实现“云端可用”云主机初始化脚本很多团队刚上云的时候选了第三条先保住现有 ARX 功能再逐步往第一条迁移。这个过渡期里云桌面的初始化脚本是关键新主机开起来要自动装 AutoCAD、装 ARX、配置许可服务不然每扩容一台机器就得手工折腾一遍。等模式稳定了再评估自建解析服务的成本和授权边界。RealDWG 和 ODA 都涉及商业授权具体以你与对应厂商的协议为准法务确认前别先上线。提示往云端传 DWG 源文件的行为需要确认企业内部的数据合规要求。只传提取后的 JSON能规避一大部分审计问题。4. ObjectARX 云化避坑安装 1603、许可管理器与“将关闭 AutoCAD”这一章写的每一条都是我见过或踩过真坑的地方。按“现象 → 原因 → 解决”来写方便你出问题时直接对号入座。4.1 现象一AutoCAD 2020 安装失败提示错误代码 1603有段时间项目组换新电脑装 AutoCAD 2020 频繁看到“错误代码 1603”安装程序走到一半回滚。第一反应是安装包坏了但换了几台机器都一样后来定位到是 Microsoft Visual C Redistributable 版本冲突。机器上已经装了 2022 版运行库AutoCAD 2020 的安装程序坚持要装自己捆绑的那一版Windows Installer 不允许降级于是直接报 1603 回滚。解决方法是先到“控制面板 → 程序和功能”把所有 Microsoft Visual C 2015-2022 Redistributable 卸载干净重新运行 AutoCAD 安装程序让它按自己的顺序装好运行库。如果还不行去 %TEMP% 目录找 Autodesk 的安装日志文件名通常带 Setup 关键词搜 1603 附近的上下文能看到具体卡在哪个组件。杀毒软件在安装期间建议暂时退出WD 和第三方杀软对注册表写入干扰是 1603 的另一个常见来源。4.2 现象二许可管理器不起作用或未正确安装AutoCAD 启动正常但一加载 ARX 就弹出“许可管理器不起作用或未正确安装”命令按钮全是灰的。很多开发者的第一反应是去检查 addCommand 注册代码但代码往往没有任何问题。真实原因是本机的 Autodesk Desktop Licensing ServiceAdSSO没有正常运行或者防火墙把许可服务端口挡了。处理路径是WinR 输入 services.msc找到 Autodesk Desktop Licensing Service确认状态是“正在运行”且启动类型为“自动”它依赖的 FlexNet 相关服务也要一并查。如果服务都在但问题依旧到“C:\Program Files (x86)\Common Files\Autodesk Shared\AdskLicensing”目录下找 AdskLicensingInstHelper按官方说明执行 reset 操作。这个问题在云桌面环境出现的频率更高因为虚拟机的 Windows 服务经常被镜像精简过。AdSSO 这个服务和 Adobe Creative Cloud 桌面版通信报错的机制很像——不是主程序坏了是它背后那个常驻服务挂了。4.3 现象三执行命令后弹出“现在将关闭 AutoCAD”这是最吓人的一种报错自定义 ARX 命令一执行AutoCAD 弹“致命错误现在将关闭 AutoCAD”图纸还没保存。发生原因几乎都是 ARX 代码里的异常没有兜住或者对象生命周期管理出了岔子。典型场景是 C 里解引用了空指针、AcDbObject 已经 close 之后又去访问、在 AcDb 反应器回调里调用 acedCommand。解决思路分两层。第一层所有命令入口用统一的宏包起来例如 ANEVA_SAFE_CALL内部 try/catch 拦截 std::exceptioncatch 到就打印错误而不是让异常穿透到 AutoCAD 消息循环。第二层批量操作时检查每个 open/close 是否成对尤其在遍历数据库时一段循环里提前 return 会导致后续实体没被关闭。崩溃之后别慌AutoCAD 自动保存的 .sv$ 文件是后悔药但恢复需要手工改扩展名治标不治本。调试时务必用 Debug 版 ARX 和 PDB 符号Release 版崩溃时堆栈基本没法看。4.4 现象四大批量修改实体时卡死像“关闭了自动重绘”也没用用户反馈一个命令循环修改 8000 个实体的颜色和图层AutoCAD 界面像幻灯片一样鼠标一直在转圈。网上有人建议“关闭 autocad 自动重绘”但这对 ARX 编程基本没用因为卡顿的根源不在重绘开关而在每次实体修改都触发了数据库通知和图形刷新。正确的优化方向是抑制撤销记录和延迟刷新图形。循环前调用 pDb-disableUndoRecording(true)结束后改回 false可以在数据库层面减少大量撤销栈维护开销批量修改实体时用 AcDbTransaction 包裹整个循环避免逐条提交事务修改完一次性调用 REGEN而不是让每个实体修改都触发一次局部刷新。这一步做完同样的 8000 个实体从“像死机”变成“等两三秒”体感完全不同。如果你看到命令执行完视图还在慢慢刷新多半是图形缓存没有显式失效遍历实体时对每个实体调用 setGraphicsModified 强制标记最后统一刷新。4.5 现象五云环境下登录态过期ARX 命令一半就中断插件上了云桌面之后新问题冒出来了命令执行到一半云端 API 返回 401 未授权。原因是 AutoCAD 的登录态和云端业务系统的 token 是两套独立体系ARX 命令用的 access_token 过期了代码里没处理这个分支直接在遍历图纸的中途崩了或者静默失败。解决方法是把 token 校验提前到命令入口并区分“token 不存在”和“token 过期”两种情况。不存在就提示用户先登录过期就尝试刷新刷新失败则把当前任务写入本地队列等下次 CAD 启动后再补传。业务数据处理和网络传输彻底分开才是云化 ARX 的稳定形态。5. 上线 aNeva 前的端到端验证从 token 缓存到任务队列云化 ARX 和纯本地插件最大的区别是你不仅要验证“命令在 AutoCAD 里不崩”还要验证“数据真的到了云端、别的端能拿到、断网时行为可控”。我的习惯是上线前过一张端到端清单。检查项验证方法通过标准命令基础功能手动执行 ANEVA_HELLO输错参数正常回显不崩溃断网表现拔网线后执行上传命令提示网络不可用不卡界面token 过期篡改本地 token 后执行明确提示重新登录数据一致性上传后到云端控制台查记录JSON 字段与图纸一致多用户并发两个 CAD 客户端同时上传同一图纸服务端不产生脏数据云桌面环境新机器初始化后直接加载 ARX免手工配置即用接下来一个进阶技巧把 token 和任务状态缓存到注册表。ARX 常驻在 AutoCAD 进程里进程退出后内存全部释放token 和未完成任务必须落到持久层。注册表是轻量选择避免引入配置文件路径的权限问题。// TokenCache.cpp : 将 access_token 缓存到 HKCU\\Software\\ANeva #include windows.h void aNevaSaveToken(const std::wstring token) { HKEY hKey nullptr; if (RegCreateKeyEx(HKEY_CURRENT_USER, _T(Software\\ANeva), 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, hKey, nullptr) ! ERROR_SUCCESS) { return; } const BYTE* buf reinterpret_castconst BYTE*(token.c_str()); DWORD bytes static_castDWORD((token.size() 1) * sizeof(wchar_t)); RegSetValueEx(hKey, _T(AccessToken), 0, REG_SZ, buf, bytes); RegCloseKey(hKey); }这段代码逻辑直接创建 HKCU 下的 aNeva 键把宽字符串 token 按 REG_SZ 类型写入。参数上注意 bytes 要包含结尾的 L\0否则下次读取时会多吃一个字符键路径放在 HKCU 而不是 HKLM因为 HKLM 需要管理员权限而 HKCU 是当前用户级。安全性上注册表是明文存储商业环境建议用 DPAPI 加密后再写至少别把 token 硬编码进代码或者命令行。配合本地队列的用法是上传失败时把 JSON 写到一个 SQLite 或本地文件CAD 下一次启动时自动重放这样弱网环境下用户还能继续画图不丢数据。我自己最早做这套方案时犯的错就是一上来就设计了一个宏大的封装框架结果连 hello 命令都加载失败后来学乖了先在纯 CAD 环境把命令跑稳再碰网络再上云。每一步验证没跑透之前不急着写下一个模块。希望这次整理的思路能帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?