1.2  示例

本节给出了多个应用实例。1.2.1节介绍了如何在一个工作空间中包含多个工程;1.2.2节演示了如何增加消息映射;1.2.3节介绍了如何利用类向导关联成员变量;1.2.4节演示了一些调试技巧;1.2.5节演示了利用分隔窗口实现单文档多视图;1.2.6节演示了如何实现多文档。

1.2.1  新建工作空间

本实例介绍了如何在一个工作空间中包含多个工程。

1.实例说明

一个大的商业软件有几十个甚至几百个模块,划分这么多模块的优点至少有以下几个。

1)便于维护。修改错误或新增功能只需要修改少量模块。

2)复用性强。大的软件一般包含一个主程序和若干个工具,工具可以独立运行,是主程序的补充或简化。它们的内核是相同的,模块化使得他们可以共用内核。

3)便于移植。由于与环境交互的部分都封装在对应模块中,环境变了,只需要修改对应的模块。举个例子,某软件以前只支持Access数据库,现在要支持Oracle,只需要修改与数据库交互的那个模块。

4)便于分工协作。如果模块划分得不好,一个程序员无意中犯的错误,可能会导致其他程序员无法工作。

一般而言,一个模块对应一个工程,在新建工程时,会自动生成一个工作空间。如果想一个工作空间包含几个工程,可以用下面的方法。

2.实现

下面的这个例子,演示如何让一个工作空间包含两个工程。具体步骤如下:

1)建立一个文件夹存放代码,如G:\VCBook

2)启动VC 6.0,选择菜单“FileNew”命令打开“New”对话框,选择“Workspace”属性卡。在“Locatin”编辑框中输入Ex010201,在“Workspaces name”编辑框中输入Ex010201,如图1-38所示。单击“OK”按钮,完成新建工作空间。

1-38  新建工作空间

3)在Workspace窗口的工作空间(Workspace)名上单击鼠标右键(如图1-39所示),在弹出的快捷菜单上选择“Add New Project to Workspace”命令。

1-39 增加工程

4)在弹出的对话框的“Porject name”编辑框中输入Ex010201Exe,双击工程类型中的“MFC AppWizardexe)”,在弹出的“MFC AppWizardStep 1”对话框中选择“Dialog based”,直接单击“Finish”按钮完成新建工程。

5)单击“File View”标签页,进入File View(文件视图)。重复步骤(2),在弹出对话框的“Project name”中输入Ex010201Dll,双击工程类型中的“MFC AppWizarddll)”,在弹出的“MFC AppWizard - Step 1”对话框中选择“MFC Extension DLLusing shared MFC DLL)”,如图1-40所示,直接单击“Finish”按钮完成创建新工程。

1-40  新建扩展动态库

6)目前为止,已经新建了一个工作空间,包含两个工程。为了让Exe工程能够使用Dll中的内容,必须把它的输出路径调成一致。选择菜单“ProjectSettings”命令(或使用快捷键Alt + F7),会弹出“Project Settings”对话框。选中Ex010201Dll工程,单击Link标签,将“Output file name”编辑框中的内容改成“../_Debug/Ex010201Dll.dll”,如图1-41所示。用同样的方法将“Ex010201Exe”的Output file name改成“../Debug/Ex010201Exe.exe”,单击“OK”按钮关闭“Project Setting”对话框。

1-41  设置输出路径

7)进入File View视图,在“Ex010201Dll files”上单击鼠标右键,在弹出的快捷菜单中选择“Set as Active Project”命令,将Ex010201Dll工程设为当前工程,如图1-42所示。从“Build”菜单中选择Build Ex010201Dll.dll命令。将Ex010201Exe设置成当前工程,从“Build”菜单中选择Execute命令创建并运行Ex010201Exe.exe。这时会在G:\VCBook\Ex010201\_Debug文件夹产生Ex010201Exe.exeEx010201Dll.dll

1-42 设置当前活动工程

8)确保Ex010201Dll是当前工程,从“Insert”菜单中选择“New class”命令,会弹出“New class”对话框,如图1-43所示,在“Class type”下拉列表框中选择Generic Class,名称(Name)为CStudent,单击“OK”按钮。

1-43 增加新类

9)为CStudent类名前加__declspec(dllexport)以便于Ex010201Exe使用这个类。为CStudent类加一个私有成员m_iAge,公有函数SetAge

Student.h的关键代码如下:

class __declspec(dllexport) CStudent 

{

public:

         bool SetAge(int iAge);

         CStudent();

         virtual ~CStudent();

private:

         int              m_iAge ;

};

Student.cpp的关键代码如下:

CStudent::CStudent()

{

}

 

CStudent::~CStudent()

{

}

 

bool CStudent::SetAge(int iAge)

{

         m_iAge = iAge ;

         return true ;

}

10Ex010201Exe中重新声明CStudent类,与Ex010201Dll中的声明略有不同,并在CEx010201ExeDlg::OnInitDialog()使用CStudent

class __declspec(dllimport) CStudent 

{

public:

         bool SetAge(int iAge);

         CStudent();

         virtual ~CStudent();

 

private:

         int              m_iAge ;

 

};

 

BOOL CEx010201ExeDlg::OnInitDialog()

{

         CDialog::OnInitDialog();

 

         CStudent stu ;

         if(!stu.SetAge(100))

                   AfxMessageBox("设置学生年龄失败");

//…

}

11)把Ex010201Exe设为当前工程,从“Project”菜单中选择“Dependencies”,在弹出的“Project Dependencies”对话框中把唯一的一个复选框选上,如图1-44所示。设置成功后,Ex010201Dll会依赖于Ex010201Exe,编译Ex010201Exe时会自动编译Ex010201Dll

1-44 设置依赖关系

12)创建并运行Ex010201Exe.exe,查看效果。

13SetAge这个函数写得极端不合理,因为学生的年龄是有一个范围的,不可以是0也不可能是100。这里不研究实际范围,假定最小年龄是5,最大年龄是50。那么SetAge函数应该这样写:

bool CStudent::SetAge(int iAge)

{

         if(iAge < 5 || iAge > 50 )

                   return false ;//设置失败

 

         m_iAge = iAge ;

         return true ;

}

只编译Ex010201.dll,运行Ex010201Exe.exe,查看效果,效果如图1-45所示。

1-45 Ex010201Exe.exe运行效果

这个示例体现了模块化的优点,修改了一个模块,不影响其他模块。

注意:

1)如是一个模块变化较大,声明部分发生了变化,使用此模块的其他模块也必须重新编译。

2)将多个工程放进一个工作空间只是便于编写代码,当工程比较多时只需要将几个常用工程放进工作空间。


回目录