生成的工程中所包含的文件结构如,StdAfx.h、StdAfx.cpp和stddll.cpp文件均为标准扩展型动态连接库相关文件,其中StdAfx.h、StdAfx.cpp的作用是生成动态连接库的预编译头,stddll.cpp中包含了标准动态连接库的初始化和终止操作代码,对于这三个文件用户一般可不作修改;first.rc为动态连接库的资源文件,该文件中列出了所有在应用程序中用到的Windows资源,如图标、位图、菜单、字串、对 话框、快捷键等等,用户可通过VC++提供的资源编辑器添加、修改和删除自己的资源;first.def为动态连接库的模块定义文件,在文件中定义了动态连接库的输出信息,如果用户在二次开发的应用程序中提供了一些函数以供其它二次开发的应用程序使用,则应在此文件中输出这些函数;在ReadMe.txt文件中,简要介绍了应用程序开发模板所生成的每个文件;FuncDef.h为函数声明头文件,用于声明用户自定义的消息响应函数;Userapp.cpp为最主要的文件,在文件中可实现应用程序的初始化和终止处理,以及其它用户编制的消息响应函数,文件的内容如下:
#include "StdAfx.h"
#include "eb_api.h" // CAXA EB API 函数
#include "funcdef.h" // 包含用户消息响应函数声明的头文件
#include "resource.h"
FUNTABLE ft[] = {
// TODO: 添加消息响应函数与对应ID值的对应组并删除下面的NULL
NULL
};
CMDDTABLE pCmd[] = {
// TODO: 添加执行消息响应函数的命令名与对应ID值的对应组并删除下面的NULL
NULL
};
void STARTUP()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
AfxGetApp()->m_pMainWnd=new CFrameWnd;
AfxGetApp()->m_pMainWnd->m_hWnd=ebGetMainFrame()->m_hWnd;
for(int i=0; i<ELEMENTS(ft); i++)
ebRegistFunc(&ft[i]);
for(i=0; i<ELEMENTS(pCmd); i++)
ebRegistCmd(&pCmd[i]);
// TODO: 定制用户界面,例如加载用户自定义的菜单等
// TODO: 添加其他初始化信息
}
void FINISH()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
for(int i=0; i<ELEMENTS(ft); i++)
ebDelFunc(&ft[i]);
for(i=0; i<ELEMENTS(pCmd); i++)
ebDelCmd(&pCmd[i]);
// TODO: 添加应用程序终止时的处理,如删除掉在STARTUP()
// 函数中加载的用户自定义菜单
ASSERT(AfxGetMainWnd()!=NULL);
AfxGetMainWnd()->m_hWnd=NULL;
delete AfxGetMainWnd();}
// 注册构件库
struct CONITEM // 构件描述结构
{
int m_iCmdID; // 命令ID
int m_iNameID; // 名字字符串资源ID
int m_iBmpID; // 位图资源ID
int m_iFuncID; // 功能说明字符串资源ID
};
CONITEM pCon[]= {
// TODO: 添加构件库描述数组并删除下面的NULL
NULL
};
LPCTSTR WINAPI REGCON(CONITEM** pConArray,int* iConNum)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
*pConArray=pCon;
*iConNum=ELEMENTS(pCon);
// TODO: 设置构件库的描述
return _T("First");
}
对这段程序作以下几点说明:
1. eb_api.h为包含所有电子图板二次开发所用到的常量、公共变量、结构、类的定义以所有API函数的声明,因此凡是用到这些定义和声明的文件中均要包含该头文件。
2. ft为FUNTABLE结构定义的数组,在数组中定义了执行每个消息响应函数所对应发出消息的ID值,这里的ID值可以自己设定(范围在34001~37000),但最好采用在Resource.h中声明的ID值。初始时数组中只有一个元素NULL,如果用户要添加自定义的对应组,则应将NULL删除掉。同理,pCmd为CMDDTABLE结构定义的数组,在数组中定义了执行每个消息响应函数所对应发出消息的ID值和执行该函数的命令名(字符串,比如画线的命令为line),初始时数组中只有一个元素NULL,如果用户要添加自定义的对应组,则应将NULL删除掉。FUNTABLE和CMDDTABLE结构的定义可参考第节中的内容。
3. 在应用程序被装载时,应用程序管理器首先调用STARTUP()函数,因此在STARTUP()函数中放置初始化代码,比如声明消息响应、注册执行消息响应函数的命令名、加载用户自定义菜单及按钮等等,用户还可以将一些需要在应用程序一加载就执行的代码放在STARTUP()函数体内。
4. 在应用程序被卸载前,应用程序管理器调用FINISH()函数,因此FINISH()函数中放置终止操作代码,比如撤销消息响应函数所占用的ID号、注销执行消息响应函数的命令名、删除用户自定义菜单及按钮等等,用户还可以将一些需要在应用程序卸载前执行的代码放在FINISH()函数体内。卸载工作的作用非常重要,如果卸载工作做的不彻底,不仅有可能与后来加载的应用程序产生冲突,还可能影响电子图板其他功能的正常使用,因此用户在编程时一定注意要与加载相对应,在卸载时将属于本应用程序的东西清理干净。
5. 文件最后的CONITEM结构和REGCON函数是为构件库设计的,在一般的二次开发应用程序中可以不做任何处理,有关构件库的使用和开发在后面章节中会详细介绍。