通常,当进行AutoCAD二次开发完成后,往往需要编制一个启动程序,以用来启动AutoCAD运行平台及进行一些初始化工作。对于初始化工作,如加载定制菜单、加载定制模块等,AutoCAD已经提供了相应的内置命令(built-in command),但是应用程序如何调用这些命令呢?大家知道,在二次开发中调用AutoCAD内置的命令,通常可以使用ads_command()函数。但是,这样做的前提必须是,该应用程序必须是在AutoCAD平台上运行的,因为ads_command()函数的执行代码包括在AutoCAD运行库文件中。而本文的启动程序是独立于AutoCAD而运行的Windows程序。
对于上述设想,在AutoCAD2000版本中可以通过向AutoCAD主程序发送WM_COPYDATA消息来完成。本文将提供一个例程,该例程的作用是,首先启动AutoCAD2000应用程序,然后加载定制的菜单,而加载定制菜单的命令是通过WM_COPYDATA消息来发送的。本例程采用Visual C++6.0编译通过。
一、准备阶段
本文的例程将要加载的定制菜单如下所示(对于定制AutoCAD菜单的方法,读者可参考各有关参考书或联机帮助)。下面的代码可以采用任何文本编辑器编写,保存格式为文本类型(.txt),但菜单源文件的后缀一般取.mnu。
//Sample.mnu
***MENUGROUP=SAMPLE_MENU
***POP1
**FILE
ID_MENU_FILE [文件(&F)]
ID_FILE_LOCATION [新布置(&N)]
ID_FILE_LAYOUT [打开布置(&O)]
[--]
ID_FILE_SWITCH_ACAD [切换到Auto&CAD\tCtrl+W]^C^Cmenu ACAD
[--]
ID_FILE_EXIT [退出(&E)]^C^C_quit
***POP2
**LAYOUT
ID_MENU_LAYOUT [平面布置(&L)]
保存上述代码,并取文件名为Sample.mnu。在AutoCAD2000的Command提示符下键入“MENU”命令加载该菜单文件。AutoCAD会提示用户是否生成相应的.mnc和.mnr等文件(文件名同,只是后缀不同而已),生成的这些文件自动存放在Sample.mnu文件所在的目录下。在本例程中,将使用已编译过的菜单文件Sample.mnc。。
二、创建工程
启动Visual C++6.0。按照下述步骤创建本例程的工程,该例程为普通的Win32应用程序。
1. 选择“File|New”菜单命令,创建一个“Win32 Application”的工程,工程名称为StartACAD,如图1所示。单击“OK”按钮,进入下一步。
图1 创建一个Win32应用程序工程
2. 在随之弹出的对话框中,选择工程类型为:“A simple Win32 application”,该类型的工程提供一个包含了WinMain()函数的.cpp文件;除此之外,还提供了一个stdafx.h和stdafx.cpp文件,并且设置编译开关以产生一个预编译头文件。单击“Finish”按钮,进入下一步。
3.在随之弹出的对话框中单击OK按钮,确认所列信息即可。
三、编辑源代码
接下来,编辑源代码。该工程已经生成一个带有WinMain()函数的源文件,即StartACAD.cpp。打开该文件并添加如下代码(黑体部分):
// StartACAD.cpp : Defines the entry point for the application.
#include "stdafx.h"
//函数原型声明
void sendCommandToAutoCAD(const HWND hWndApp, const HWND hWndAcad, const LPSTR cmd);
//Windows程序的主函数
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// TODO: Place code here.
//下述代码创建并注册应用程序窗口类
char ClassName[] = "Start AutoCAD";
WNDCLASS WndClass;
HWND hWndACAD = NULL;
if (!hPrevInstance)
{
memset(&WndClass, 0x00, sizeof(WNDCLASS));
WndClass.style = 0;
WndClass.lpfnWndProc = (WNDPROC)NULL; //不需要窗口回调函数
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = NULL;
WndClass.hCursor = NULL;
WndClass.hbrBackground = NULL;
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = ClassName;
RegisterClass(&WndClass);
}
//产生应用程序窗口,并返回句柄
HWND hWndApp = CreateWindow(ClassName, "",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
hWndACAD = FindWindow(NULL, "AutoCAD 2000");
if (hWndACAD)
{
BringWindowToTop(hWndACAD);//将AutoCAD 2000程序窗口置于顶端
ShowWindow(hWndACAD, SW_RESTORE);
}
else
{
//启动AutoCAD 2000并获得其主程序窗口
if( WinExec("C:\\Acad2000\\ACAD.exe", SW_SHOWNORMAL) < 32 )
{
MessageBox(NULL, "AutoCAD 2000启动失败!", "Message", MB_OK);
return FALSE;
}
for(int num = 0; num <= 100; num++)
{
Sleep(500); //暂停,释放控制权
if((hWndACAD = FindWindow(NULL, "AutoCAD 2000")) != NULL)
break;
}
}
char cmdString[133]; //命令字符串变量
//设置系统变量FILEDIA
strcpy(cmdString, "(setq IsChanged 1) (if (= (getvar \"FILEDIA\") 1) (setvar \"FILEDIA\" 0) (setq IsChanged 0))\n");
sendCommandToAutoCAD(hWndApp, hWndACAD, cmdString);
//加载定制菜单
strcpy(cmdString, "MENU\nD:\\StartACAD\\Sample.mnc\n");
sendCommandToAutoCAD(hWndApp, hWndACAD, cmdString);
//恢复系统变量FILEDIA
strcpy(cmdString, "(if (= IsChanged 1) (setvar \"FILEDIA\" 1))\n");
sendCommandToAutoCAD(hWndApp, hWndACAD, cmdString);
DestroyWindow(hWndApp);
return 0;
}
//该函数向AutoCAD 2000主程序发送字符串命令
void sendCommandToAutoCAD(const HWND hWndApp, const HWND hWndAcad, const LPSTR cmd)
{
if( !hWndAcad )
return;
COPYDATASTRUCT cmdMsg;
cmdMsg.dwData = (DWORD)1;
cmdMsg.cbData = (DWORD)strlen(cmd) + 1;
cmdMsg.lpData = cmd;
SendMessageA(hWndAcad, WM_COPYDATA, (WPARAM)hWndApp, (LPARAM)&cmdMsg);
}
上述代码中的WinMain()函数为Win32应用程序的入口函数,类似于C语言DOS程序的main()函数。添加的代码程序流程是:首先检查是否已经存在AutoCAD2000的运行实例,如果已有AutoCAD2000运行,那么获取其主窗口句柄,否则运行AutoCAD2000(假定AutoCAD2000的安装目录为C:\ACAD2000\)。当AutoCAD2000启动以后,向其发送加载菜单的命令字符串。该字符串命令是采用AutoLISP语言(AutoCAD的一种二次开发语言)编写,限于篇幅,此处不再赘述。
注意:此例程假定被加载的菜单文件(Sample.mnc)存放在例程的工程目录上,即C:\StartACAD\。
定义的函数sendCommandToAutoCAD(),用来向AutoCAD2000主程序发送一个字符串命令(注意:AutoCAD12.0(Windows版本)使用定制的WM_ACAD消息)。字符串命令由发送的WM_COPYDATA消息捎带。发送WM_COPYDATA消息只能采用SendMessage()函数或相应的MFC类成员函数。发送WM_COPYDATA消息时,必须构造一个COPYDATASTRUCT结构变量作为消息的第二个参数,即lParam。COPYDATASTRUCT结构如下:
typedef struct tagCOPYDATASTRUCT {
DWORD dwData;
DWORD cbData;
PVOID lpData;
}
COPYDATASTRUCT;
在向AutoCAD2000发送WM_COPYDATA消息时,dwData域必须置为1且为32位(DWORD型);lpData域指向将要发送的以空字符(null)结束的命令字符串,该域值可以为空(NULL);cbData域值指定该命令字符串的长度。如果dwData域值不为1或lpData指向的命令字符串不以空字符结束,那么AutoCAD主程序将不会处理该消息。
保持缺省的参数设置。编译整个工程,生成StartAcad.exe,这是一个Win32应用程序。在Window98平台上运行StartAcad.exe。该程序启动AutoCAD2000并加载定制菜单(即Sample.mnc),如图2所示。
图2 启动AutoCAD2000并加载定制菜单
向AutoCAD2000发送WM_COPYDATA消息的关键是,正确设置WM_COPYDATA消息的各个域值;否则,消息将得不到正确处理。 (上述例程在Windows98,Celron366运行通过)
|