碎碎念
不得不說autocad二次開發的相關資料真的少,大多數還很舊。圖書館里VBA的一本最近出版時間是2006,AutoLisp的2013(還是個十二五規划教材),ObjectARX的書是2014年出的,結果開發的是autocad2010,還配套VS2008,里面的內容也是......慘不忍睹......
不過女朋友設計院的插件在AutoCAD2017上一用就崩也不是個辦法(說實話用上2017就再也不想回2011了),只好自己找AutoCAD 2017的官方資料開搞。
首先是技術選型問題,就查找到的資料而言二次開發有三個流派,AutoLisp,VBA(ActiveX), Cpp/C#(.Net + ObjectARX)。AutoLisp不了解,目前主要是解決問題(實現那一用就崩的插件里的一個小功能,功能下文再詳細敘述),暫時不打算從頭開始擼Lisp。ActiveX的提供(據說)很少,VBA我也不是很熟,作為次要選擇。那么首先就先試試ObjectARX的水。
正文
AutoCAD 2017 的官方開發文檔地址:
http://help.autodesk.com/view/ACD/2017/CHS/?home=homepage_dev
此外在Develop Center有坑學習資料。網址
http://usa.autodesk.com/adsk/servlet/index?id=1911627&siteID=123112
首先要下載ObjectArx2017的庫。另外ARX集成到VS2015開發環境的Wizard不包含在庫的安裝包中,需要另外單獨下載。
ObjectARX2017庫下載地址(需要Submit個人信息):
http://usa.autodesk.com/adsk/servlet/item?siteID=123112&id=785550
Wizard下載地址:
http://images.autodesk.com/adsk/files/ObjectARXWizards-2017.zip
首先安裝ObjectARX庫,它讓你指定一個解壓路徑,解壓完成后並不會有可執行文件進行進一步安裝。這里面的文件根據32位和64位分別用於提供給VS2015來include和link。
其次安裝Wizard。裝完Wizard之后Visual C++就會出現Autodesk開發的模板。
安裝Wizard這里有個坑: 如果直接雙擊安裝,隨后VS里工程創建時不會成功的。根據我的排查,得到的安裝成功的必要條件為:
1. VS2015必須安裝了MFC組件
2. Wizard必須主動以管理員身份安裝,方法為已Admin身份啟動一個cmd,再由這個cmd去啟動Wizard的MSI安裝包。(我第一次安裝時UAC已設置到最低,msi安裝時應該默認已經給了admin的權限,此處非常奇怪)
如果選擇不安裝Wizard,自己手動創建一個win32 dll項目,也是可以的,主要可以參考”ObjectARX 2017 Trainning”里的CHM文檔,按步驟配置可以走通。
要點如下:
1. 創建的項目是Win32 Dll 項目。
2. 修改項目屬性中的C/C++子項,Additional Include Directories里添加ObjectARX根目錄下的inc/文件夾和inc-win32/(若采用64位編譯則是inc-x64/)文件夾。
3. C/C++子項中的Code Generation項里的Runtime Library改為Multi-threaded Dll
4. C/C++中的Preprocessor中把_DEBUG宏去掉。(其實文檔里這步已經讓我考慮轉VBA)
5. 鏈接器(Linker)中添加附加依賴目錄和附加依賴項。此處文檔有坑: 附加依賴項是
rxapi.lib; acdb21.lib; acge21.lib; acad.lib; ac1st21.lib; accore.lib;
文檔中的文件名是錯誤的(不存在的)。
得到的配置截圖(64位)如下:
至此再敲教程的代碼就可以正常運行了。
我的示例代碼為:
// objectArxHelloWorld.cpp : 定義 DLL 應用程序的導出函數。 // #include "stdafx.h" #include "tchar.h" #include <aced.h> #include <rxregsvc.h> void initApp(); void unloadApp(); void helloWorld(); void initApp() { // register a command with the AutoCAD command mechanism acedRegCmds->addCommand(_T("HELLOWORLD_COMMANDS"), _T("Hello"), _T("Bonjour"), ACRX_CMD_TRANSPARENT, helloWorld); } void unloadApp() { acedRegCmds->removeGroup(_T("HELLOWORLD_COMMANDS")); } void helloWorld() { acutPrintf(_T("\n萌萌噠!")); } extern "C" AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt) { switch (msg) { case AcRx::kInitAppMsg: acrxDynamicLinker->unlockApplication(pkt); acrxRegisterAppMDIAware(pkt); initApp(); break; case AcRx::kUnloadAppMsg: unloadApp(); break; default: break; } return AcRx::kRetOK; }