如何让VC在编译ARX项目时自动通知AutoCAD卸载ARX程序,并在编译完成后自动加载新编译的ARX程序
在编写ARX程序时,一个比较麻烦的地方在于,每次重新编译ARX项目时,需要先手动的卸载此前加载调试的ARX程序,然后编译,最后再加载新生成的程序,虽然过程不算复杂,但经常这样做会让人感到厌烦。有没有办法使VC在启动编译前,自动通知AutoCAD卸载此插件(即旧版本的ARX程序),然后开始编译,编译完成后,再自动通知AutoCAD加载此新生成的ARX插件呢?
我在查看了QQ群里一些朋友的讨论之后,结合他们给出的一些思路,经过一番摸索,终于找到一种可行的方案。这个方案包括如下几个部分:
1.添加两个自定义命令,分别用于加载和卸载ARX程序
AutoCAD自带几个命令,如APPLOAD, ARX等,可用于ARX程序的加载和卸载,但都是基于GUI的操作,无法完全通过命令行的方式实现ARX的加载和卸载。因此,需要我们自己编写两个命令来分别实现通过命令行加载,卸载ARX程序。这个容易实现:
新建一个叫做ArxLoader的ARX项目,添加两个命令ArxLoad, ArxUnload,分别用于加载和卸载通过路径指定的ARX程序:
static void wdArxLoader_ARXLOAD(void) { ACHAR arxPath[134]; acedGetString(1,NULL,arxPath); AcRxDynamicLinker* pLinker = acrxDynamicLinker; #ifdef NDEBUG // release version pLinker->loadModule(arxPath,false); #else // debug version acedPrompt(arxPath); pLinker->loadModule(arxPath,true); #endif } static void wdArxLoader_ARXUNLOAD(void) { ACHAR arxPath[134]; acedGetString(1,NULL,arxPath); AcRxDynamicLinker* pLinker = acrxDynamicLinker; #ifdef NDEBUG // release version pLinker->unloadModule(arxPath); #else // debug version acedPrompt(arxPath); pLinker->unloadModule(arxPath); #endif }
这个项目会生成一个名为wdArxLoader.arx的插件,其中包含ArxLoad和ArxUnload命令,备用。
2.实现外部程序向AutoCAD主程序发送AutoCAD命令
这一步比较关键,实现方法也比较“古怪”。这里有篇文章讲述如何通过各种方式向AutoCAD发送命令:
Techniques for calling AutoCAD commands programmatically
我采用了这篇文章中所介绍的方式来实现从我们自己的外部程序向AutoCAD发送Ansys命令。
新建一个win32控制台项目,添加如下代码:
#include <string> #include <cassert> BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { COPYDATASTRUCT* pCmdMsg = (COPYDATASTRUCT*)lParam; const int MAX_LEN = 256; TCHAR caption[MAX_LEN]; assert(hwnd!=NULL); ::GetWindowText(hwnd,caption,MAX_LEN); std::wstring captionStr(caption); if (captionStr.substr(0,12)==_T("AutoCAD 2008")) { ::SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)pCmdMsg); } return TRUE; } void SendCmdToAcad(LPCTSTR cmd) { COPYDATASTRUCT cmdMsg; cmdMsg.dwData = (DWORD)1; cmdMsg.cbData = (DWORD)(_tcslen(cmd) + 1) * sizeof(TCHAR); cmdMsg.lpData = (PVOID)cmd; ::EnumDesktopWindows(NULL,EnumWindowsProc,(LPARAM)&cmdMsg); } int _tmain(int argc, TCHAR* argv[]) { if (argc>1) { std::wstring unloadCmd(argv[1]); unloadCmd += _T("\r"); SendCmdToAcad(unloadCmd.c_str()); } return 0; }
这里向AutoCAD主窗口发送消息的代码与参考文献的类似,只是获取AutoCAD主窗口的句柄的方式不一样,原文中adsw_acadMainWnd()函数只能用于从ARX插件内部获取主窗口句柄,而不能用于“外部独立程序”中,因此只能采取其他间接的方法获取,比如我这里使用的枚举所有顶级窗口的方式。
这个项目会生成一个名为SendCmdToAcad.exe的命令行小工具,备用。
3.设置我们自己所要编译的ARX项目
在项目的属性页对话框中,在“All Configuration”配置下,选择”Build Events>>Pre-build Event”,然后在”Command line”中输入:
D:\Cpp\ObjectArx\AcadToAnsys\Release\SendCmdToAcad.exe "arxunload $(TargetPath)"
其中,”D:\Cpp\ObjectArx\AcadToAnsys\Release\SendCmdToAcad.exe”是我们前面第2步准备的命令行小工具的完整路径,”arxunload $(TargetPath) ”是要发送给AutoCAD执行的命令,用于通知AutoCAD卸载我们所要重新编译生成的ARX程序。
选择”Build Events>>Pre-build Event”,然后在”Command line”中输入:
D:\Cpp\ObjectArx\AcadToAnsys\Release\SendCmdToAcad.exe "arxload $(TargetPath)"
其中,”D:\Cpp\ObjectArx\AcadToAnsys\Release\SendCmdToAcad.exe”是我们前面第2步准备的命令行小工具的完整路径,”arxload $(TargetPath) ”是要发送给AutoCAD执行的命令,用于通知AutoCAD加载我们刚重新编译生成的ARX程序。
4.使用方法
在AutoCAD中输入APPLOAD手动加载第1步中准备好的wdArxLoader.arx,此后,就不再需要在重新编译我们的ARX项目时,手动的加载卸载ARX程序了,这一过程会由VC自动通知AutoCAD帮我们完成,我们要做的就是简单重现编译下就可以了,