友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
C语言实例教程(PDF格式)-第77部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
输入库文件中的名字,而是DLL的文件名。如果文件的扩展名
为。DLL,则可以省略。
这个程序的运行结果同使用隐含链接的前一个程序一样,但它的内部
实现是很不相同的。使用显式链接的应用程序加载时,所调用的DLL
并不加载,只有当应用程序调用LoadLibray()时系统才加载相应的
DLL,并在应用程序调用FreeLibrary()时卸载该DLL。使用隐含链接
的应用程序调用DLL中的导出函数时,方法同调用一般的函数一样,
而使用显式链接的应用程序必须使用指针来调用。由于使用了指针,
因此在编译时不能验证参数的合法性,通过指针使用不合法的参数来
调用DLL中的导出函数将会导致不可预料的后果。
很明显,使用隐含链接的方式调用DLL中的导出函数要比使用显式链
接方便得多。但在某些情况下我们必须使用显式链接。事实上,使用
显式链接调用DLL提供了更大的灵活性。尤其在没有与DLL相对应的
LIB文件时,我们只能使用显式链接来调用DLL中的导出函数,并且,
只要我们使用函数名作参数来调用GetProcAddress(),在更新DLL
时,就没有必要重新链接应用程序。另外,使用隐含链接的方式的应
用程序加载DLL时如果发生错误 (如DLL文件未找到或是DLL中的
DllMain()函数初始化失败)时,应用程序将被终止,而使用显式链
接的应用程序则可以使用如上面的例子中所给出的方法来避免出现这
种情况 (可以使用所创建的两个不同版本的tester程序来验证这一
点)。
…………………………………………………………Page 675……………………………………………………………
由于应用程序调用LoadLibrary()函数时才加载DLL,因此使用显式链
接的应用程序的加载速度要比使用隐含链接的应用程序快。使用显式
链接的另一个好处是,应用程序可以在运行时决定所加载的DLL。
但是要记住,由于使用了指针来传递应用程序的参数,因此编译器在
编译时无法确认应用程序所传递的参数类型是否合法。传递不合法的
参数给DLL中的导出函数的一件危险的事。在程序调试的过程中我们
一定需要注意这一点。
第三节 使用动态链接连库扩展MFC
我们还可以使用DLL来实现从MFC派生的一些可重用类,这种动态链接
库一般称作MFC扩展动态链接库 (MFC Extension DLL)。正如这个名称
所暗示的那样,通过这种方式我们可以扩展MFC所包括的内容,使得
使用MFC编程更加的方便。此外,如果需要在应用程序和DLL之间传递
MFC或者由MFC派生的对象的指针的话,我们也必须使用MFC扩展DLL。
在本节中,我们使用MFC扩展DLL来创建一个输入通用对话框,如图
13。3所示。该对话框很象Visual Basic中的InputBox函数所产生的对
话框,使用过Visual Basic的程序员都有印象,函数InputBox非常之
好用,这里,我们来使用动态链接库在Visual C++ 的MFC中也创建这
么一个好用的类。
图13。 3 输入通用对话框
输入通用对话框由类CInputDlg封装,类CInputDlg提供了一个公有成
员函数GetInput,该成员函数的原型如下:
CString GetInput(CString Title; CString Prompt)
第一个参数Title表示输入对话框的标题,在图13。3中为 “输入”;
第二个参数Prompt代表在输入对话框中显示的简短提示文本,在图
13。3中为 “请输入对话框的标题:”。函数的返回值为用户在对话框
的文本框中输入的字符串。如果用户没有输入任何字符串或者单击了
“取消”按钮,返回值为空串〃〃。
下面我们来介绍该对话框的创建和使用。首先讲述DLL工程
ExtDllDemo的创建。该工程实现了类CInputDlg的导出。
…………………………………………………………Page 676……………………………………………………………
1。 使用AppWizard创建一个MFC扩展DLL工程,将工程取名为
ExtDllDemo。
2。 向工程中添加一个对话框资源IDD_INPUT,按图13。3绘制对话框中
的各控件。这些控件的资源ID如表所示。
表13。 1 对话框资源IDD_INPUT中的控件属性
控件 资源ID
提示文本 IDC_PROMPT
标签
输入文本 IDC_EDIT
框
3。 使用ClassWizard为对话框资源IDD_INPUT创建新的对话框类
CInputDlg,该类直接派生于CDialog。按下面的代码修改类
CInputDlg的头文件和实现文件。
#if !defined(AFX_INPUTDLG_H__02DB98CF_1F76_11D2_971A_0000B4810A31__INCLUDED_)
#define AFX_INPUTDLG_H__02DB98CF_1F76_11D2_971A_0000B4810A31__INCLUDED_
#if _MSC_VER 》= 1000
#pragma once
#endif // _MSC_VER 》= 1000
// InputDlg。h : 头文件
//
// 以下对话框 ID 常量需要手动添加
#define IDC_EDIT 1000
#define IDC_PROMPT 1001
#define IDD_INPUT 129
/////////////////////////////////////////////////////////////////////////////
// CInputDlg 对话框
class __declspec(dllexport) CInputDlg : public CDialog
{
…………………………………………………………Page 677……………………………………………………………
// 构造
public:
CString GetInput(CString Title; CString Prompt);
CInputDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
//{{AFX_DATA(CInputDlg)
enum { IDD = IDD_INPUT };
CString m_strTitle;
CString m_strPrompt;
CString m_strInput;
//}}AFX_DATA
// 重载
// 由 ClassWizard 生成的虚函数重载
//{{AFX_VIRTUAL(CInputDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
//}}AFX_VIRTUAL
// 实现
protected:
// 生成的消息映射函数
//{{AFX_MSG(CInputDlg)
virtual BOOL OnInitDialog();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
…………………………………………………………Page 678……………………………………………………………
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio 将在紧贴上一行之前的位置添加附加的声明
#endif // !defined
(AFX_INPUTDLG_H__02DB98CF_1F76_11D2_971A_0000B4810A31__INCLUDED_)
// InputDlg。cpp : 实现文件
//
#include 〃stdafx。h〃
#include 〃InputDlg。h〃
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE'' = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CInputDlg dialog
CInputDlg::CInputDlg(CWnd* pParent /*=NULL*/)
: CDialog(CInputDlg::IDD; pParent)
{
//{{AFX_DATA_INIT(CInputDlg)
m_strInput = _T(〃〃);
//}}AFX_DATA_INIT
}
void CInputDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
…………………………………………………………Page 679……………………………………………………………
//{{AFX_DATA_MAP(CInputDlg)
DDX_Text(pDX; IDC_EDIT; m_strInput);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CInputDlg; CDialog)
//{{AFX_MSG_MAP(CInputDlg)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CInputDlg message handlers
CString CInputDlg::GetInput(CString Title; CString Prompt)
{
CString str(〃〃); // 注意:这里对 CString 对象 str 的初始化是必要,否则
// 在后面的过程将会出错
// 对标题条和提示文本的实际的更新将在消息处理函数 OnInitDialog 中进行
m_strTitle=Title;
m_strPrompt=Prompt;
if (DoModal()==IDOK)
{
// 如果用户单击了确定,则返回所输入的字符串
str=m_strInput;
}
return str;
}
BOOL CInputDlg::OnInitDialog()
…………………………………………………………Page 680……………………………………………………………
{
CDialog::OnInitDialog();
// 使用用户指定的标题字符串
SetWindowText(m_strTitle);
// 设置提示文本
GetDlgItem(IDC_PROMPT)…》SetWindowText(m_strPrompt);
// 将输入焦点设置为 IDC_EDIT 控件
GetDlgItem(IDC_EDIT)…》SetFocus();
// 由于将输入焦点设置为 IDC_EDIT 控件,因此 OnInitDialog 成员函数应该返回假值
return FALSE;
}
在示例程序中,我们使用了__declspec(dllexport)来导出类
CInputDlg,最主要的原因是因为这种方法相对比较简单一些。
编译DLL工程ExtDllDemo,在Debug 目录下生成了动态链接库
ExtDllDemo。dll的导入库ExtDllDemo。lib 。
下面我们创建动态链接库ExtDllDemo。dll的测试工程ExtDllTest。
1。 使用AppWizard创建基于对话框的EXE工程ExtDllTest,工程
ExtDllTest使用了动态MFC链接 (这是必须的)。将在前一步中生成的
ExtDllDemo。lib拷贝到工程ExtDllTest所在的目录下。完成这一步之
后,从Project菜单下选择Settings命令,在工程的设置对话框中选
择Link选项卡,在Object/Library Modules框中输入
ExtDllDemo。lib。
2。 在实现文件ExtDllDemoDlg。cpp的最前面输入下面的代码:
/////////////////////////////////////////////////////////////////////////////
// CInputDlg dialog
class __declspec(dllimport) CInputDlg : public CDialog
{
public:
…………………………………………………………Page 681……………………………………………………………
CString GetInput(CString Title; CString Prompt);
CInputDlg(CWnd* pParent = NULL);
};
上面的代码在工程中定义了类CInputDlg,以便于在以后的代码中使
用该类。这里需要注意的是,我们只需给出对我们有意义的那些成员
的声明即可,而没有必须在上面的定义中给出完全的成员声明。
在OnInitDialog成员函数的// TODO注释下输入下面的代码。该代码
在应用程序的主对话框弹出之前询问主对话框的标题文本。
CInputDlg dlg;
CString str=dlg。GetInput(〃输入〃; 〃请输入对话框的标题:〃);
SetWindowText(str);
l 注意:
l 如果在CInputDlg::GetInput成员函数中没有对对象变量str进行
正确的初始化(如直接使用return m_strInput等),那么上面的代
码的Debug版本在运行时将会 出现Assertion失败。这种现象的根
源在于CString内部所使用的 内存分配方式。由于CString所使用
的内存分配方式相当的复杂,因此,我们不在这里深入的讨论这
一现象,仅仅指出存在这种问题而已。
编译并生成应用程序ExtDllTest,然后将动态链接库ExtDllDemo。dll
拷贝到应用程序ExtDllTest的目录或系统 目录中,再运行
ExtDllTest,已检验动态链接库ExtDllTest的工作是否正确。
关于DLL还有很多课题可以研究,但是由于篇幅所限,我们在这里仅
给出一些最基本的概念和方法,更详细的参考资料可以查阅MFC的联
机文档。
…………………………………………………………Page 682……………………………………………………………
附表1 MFC类库层次表
…………………………………………………………Page 683……………………………………………………………
…………………………………………………………Page 684……………………………………………………………
…………………………………………………………Page 685……………………………………………………………
…………………………………………………………Page 686……………………………………………………………
…………………………………………………………Page 687……………………………………………………………
附表2 ASCII码表 (0~127)
…………………………………………………………Page 688……………………………………………………………
附录3 虚拟键码
十六进制
符号常量 指定的鼠标或键盘按键
值
VK_LBUTTON 01 鼠标左键
VK_RBUTTON 02 鼠标右键
VK_CANCEL 03 Control…break 过程
VK_MBUTTON 04 鼠标中键
05 07 未定义
? ?
VK_BACK 08 BACKSPACE 键
VK_TAB 09 TAB 键
? 0A?0B 未定义
VK_CLEAR 0C CLEAR 键
VK_RETURN 0D ENTER 键
? 0E?0F 未定义
VK_SHIFT 10 SHIFT 键
…………………………………………………………Page 689……………………………………………………………
VK_CONTROL 11 CTRL 键
VK_MENU 12 ALT 键
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!