MFC dll

来源:互联网 发布:淘宝怎么在线咨询医生 编辑:程序博客网 时间:2024/06/05 03:08

Windows DLL 编程

一、静态链接库

1.创建一个“Win32控制台应用程序”项目。项目名定义为staticdll

2. 在“应用程序设置”中配置为“静态库”,其他默认。

 

 

 

3.向生成的项目中添加一个头文件和一个实现文件,名称分别为staticlib.hstaticlib.cpp。分别向这两个文中添加如下代码:

//staticlib.h

#ifndefLIB_H

#defineLIB_H

 

extern"C" int add(int x,inty);  //声明为C编译、连接方式的外部函数

 

#endif

 

//staticlib.cpp

#include"stdafx.h"

#include"staticlib.h"

 

int add(int x,inty)

{

    returnx + y;

}

 

4.编译链接后会在解决方案的根目录下的debug目录中得到一个staticdll.lib库文件。该文件就是静态库的关键文件。使用该库文件,将其编译链接到用户程序中,就可以调用在静态库中定义的导出函数add

 

5.测试静态库staticdll.lib

1)创建一个“win32控制台应用程序”项目。名称为:staticdlltest

2)配置“应用程序设置”为“控制台应用程序”,其他默认。

3)在主staticdlltest.cpp文件中主要代码如下所示。

// StaticDllTest.cpp :定义控制台应用程序的入口点。

//

#include"stdafx.h"

#include"..\StaticDll\staticLib.h"

 

#pragmacomment(lib, "..\\debug\\staticdll.lib") //指定与静态库一起连接

 

int _tmain(int argc,_TCHAR* argv[])

{

    printf("2 + 3 = %d\n", add( 2, 3 ) );

    return 0;

}

 

 

 

 

二、Win32 动态链接库

1.      创建一个“Win32 控制台应用程序”。名称为NonMfcDll

2.      配置“应用程序设置”为“DLL”。

3.      向生成的项目中添加一个头文件和一个实现文件,名称分别为nonmfclib.hnonmfclib.cpp。分别向这两个文中添加如下代码:

//NonMfcLib.h

#ifndefLIB_H

#defineLIB_H

 

extern"C" __declspec(dllexport)int add(intx, int y);

 

#endif

 

//NonMfcLib.cpp

 

#include"stdafx.h"

#include"NonMfclib.h"

 

int add(int x,int y)

{

    returnx + y;

}

从以上代码中,可以看出我们在本项目中添加了一个导出函数add

 

4.      为了验证类的导出情况,我们再向本项目中添加一个C++类。名称为CmyClass。下面是该类的头文件及实现文件的具体代码。

//CmyClass.h

#pragmaonce

 

extern"C" __declspec(dllexport)void ext_hello();

 

class__declspec(dllexport)CmyClass

{

public:

    CmyClass(void);

    ~CmyClass(void);

    voidHello(void);

};

 

//CmyClass.cpp

#include"StdAfx.h"

#include"CmyClass.h"

#include<iostream>

 

usingnamespace std;

 

voidext_hello()

{

    CmyClassmyCls;

    myCls.Hello();

}

 

CmyClass::CmyClass(void)

{

}

 

CmyClass::~CmyClass(void)

{

}

 

voidCmyClass::Hello(void)

{

    cout <<"大家好!" <<endl

}

CmyClass类中包含了一个成员函数Hello。不过在用户函数中无法直接调用该函数,必须使用另外一个类外部函数进行间接调用类成员函数。因此,添加了一个ext_hello函数用来间接调用一个CmyClass类的对象实例的Hello函数,来达到对类的成员函数的导出使用。

 

5.      编译链接后会在解决方案的根目录下的debug目录中得到一个nonmfcdll.lib库文件和nonmfcdll.dll动态链接文件。Lib库文件用来进行静态导入,而dll用来动态导入。不过请注意这里的lib文件和静态库的lib文件是不一样的。这里的lib文件只包含了导出函数的接口说明,而真正的导出函数的执行体实际在dll文件中。

 

6.      动态导入win32动态链接库。

1)  创建一个“Win32控制台应用程序”项目。名称为NonMfcDlltest

2)  配置“应用程序设置”为“控制台程序”,其他默认。

3)  NonMfcDlltest.cpp文件的代码如下所示:

// NonMfcDllTest.cpp :定义控制台应用程序的入口点。

//

#include"stdafx.h"

#include<Windows.h>

 

typedefint(*lpAddFun)(int,int);

 

int _tmain(int argc,_TCHAR* argv[])

{

    HINSTANCEhDll;

    lpAddFunaddFun;

    lpHelloFunhelloFun;

    hDll =LoadLibrary(_T("..\\Debug\\NonMfcDll.dll"));

    if (hDll !=NULL)

    {

       addFun = (lpAddFun)GetProcAddress(hDll,"add");

       if (addFun !=NULL)

       {

           int result = addFun(2,3);

           printf("%d\n",result);

       }

       FreeLibrary(hDll);

    }

   

    return 0;

}

由上述代码可以总结动态链接库的动态导入的基本步骤大致如下:

l         定义一个需要导入的动态链接库导出函数的函数指针类型;

l         使用LoadLibrary函数动态加载动态链接库;

l         使用GetProcAddress函数获取动态链接库导出函数地址;

l         使用函数;

l         使用FreeLibrary函数释放动态链接库;

4)  采用动态导入方式,只能通过间接使用类外部函数来调用类的成员。不能直接在用户程序中直接使用类的对象来调用成员。

 

7.      静态导入Win32动态链接库

1)       创建一个“Win32控制台应用程序”项目。名称为NonMfcDllStaticCall

2)       配置“应用程序设置”为“控制台程序”,其他默认。

3)       NonMfcDllStaticCall.cpp文件的代码如下所示:

#include"stdafx.h"

#include"CmyClass.h"

#pragmacomment(lib,"..\\debug\\NonMfcDll.lib")

 

extern"C" __declspec(dllimport)int add(intx,int y);

 

int _tmain(int argc,_TCHAR* argv[])

{

    intresult = add(2,3);

    printf("%d\n",result);

   

    CmyClassmyCls;

    myCls.Hello();

    return 0;

}

 

这里需要注意的是,必须将动态链接库中定义的类的头文件拷贝到测试项目的根目录下,并且在项目主CPP文件中将该头文件包含。然后,使用#pragma comment指示编译器静态链接动态链接库到项目中,并将需要导入的函数接口在主CPP文件中进行声明。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

三、MFC 常规动态链接库

1.创建一个“MFC DLL”项目。名称为 StaticMfcRegularDll

2. 配置“应用程序设置”为“带静态链接MFC的规则DLL”。

 

3. MFC规则DLL中导出函数,导出类的方法与前面介绍的Win32 DLL中的方法完全一致,因此,在此就不再进行说明。

 

4. MFC DLL最大的特点就是可以使用MFC类库。因此,我们为项目添加一个IDIDD_DIALOG1的对话框资源,然后为该对话框添加一个派生于CDialog的类:CDllDlg。对话框资源,你可以根据你的需求定义。我们这里就进行最简单的布置为如下图的形式,以便在用户程序中调用时,明确这是来之DLL中的对话框资源。

由于,MFC规则DLL不允许导出整个类,以及类的成员函数,所以,为了保证用户程序能够调用该对话框资源,因此,必须在类外部实现一个外部函数。具体代码如下所示:

//StaticMfcRegularDll.h

extern "C" void __declspec(dllexport)ShowDlg();

 

//StaticMfcRegularDll.cpp

#include "DllDlg.h"

......

voidShowDlg()

{

    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    CDllDlgdlg;

    dlg.DoModal();

}

......

上述代码所作的工作是:

l         声明一个导出显示对话框的函数接口;

l         将对话框的头文件包含如MFC规则DLL的主CPP文件中;

l         定义显示对话框的函数;

注意,建议在任何导出函数的函数体开始的位置加入:

AFX_MANAGE_STATE(AfxGetStaticModuleState());

以保证,不管MFC库是如何链接到本DLL文件中的,都可以保证找到该对话框资源。

 

5. 编译链接后,该项目将生成两个主要输出文件:StaticMfcRegularDll.libStaticMfcRegularDll.dll

 

6. 测试该MFC DLL,采用静态导入。

1)创建一个MFC SDI应用程序项目。

2)为了在测试项目中的任何派生类中都能导入到MFC Dll中的导出函数,我们在CWinApp派生类的头文件中添加以下代码:

#pragmacomment(lib,"..\\debug\\StaticMfcRegularDll.lib")

extern "C" _declspec(dllimport)void ShowDlg();

从以上代码可知,我们在测试项目中采用的是静态导入方式。

3)在测试项目中添加一个菜单资源,IDID_DLLTEST_DLLDLG。并为该菜单添加一个命令处理程序,该处理程序添加给CFrameWnd派生类中。然后,在该处理程序的实现中添加对导入函数ShowDlg的调用,即可。

voidCMainFrame::OnDlltestDlldlg()

{

    // TODO:在此添加命令处理程序代码

    ShowDlg();

}

 

7.       测试该MFC Dll,采用动态导入。

1MFC Dll的动态导入,与前面我们介绍的Win32 Dll的动态导入方式是相同的。下面,就在静态导入测试项目的基础上,来实现对函数ShowDlg的动态导入。

2)我们要做两件的事情,就是定义一个与ShowDlg函数的对应的函数指针类型,然后修改前面的那个菜单资源的命令处理程序的实现。

 

下面这行代码,加入到CWinApp派生类的头文件中。

typedef void(*ShowDlg)(void);

 

下面,是新的菜单命令处理函数

voidCMainFrame::OnDlltestDlldlg()

{

    // TODO:在此添加命令处理程序代码

    HINSTANCEhDll;

    ShowDlgpSDlg;

    hDll =LoadLibrary(_T("..\\debug\\StaticMfcRegularDll.dll"));

    if (hDll !=NULL)

    {

       pSDlg = (ShowDlg)GetProcAddress(hDll,"ShowDlg");

       if (pSDlg !=NULL)

       {

           pSDlg();

       }

       FreeLibrary(hDll);

    }  

}

 

 

 

四、MFC 扩展动态链接库

         MFC 扩展DLLMFC规则DLL的主要区别是,对于有MFC类派生的派生类,MFC扩展DLL可以导出整个类,而MFC规则DLL则不行。

1)  创建一个“MFC DLL”项目。名称为 MfcExtDll;

2)  配置“应用程序设置”为“MFC 扩展DLL;

3)  为项目添加一个对话框资源,ID为:IDD_DIALOG1;

4)  为该对话框资源添加一个派生于CDialogMFC派生类。类名为CMyDllDlg;

5)  修改CMyDllDlg类的头文件中,类的接口声明。

class AFX_EXT_CLASSCMyDllDlg : publicCDialog

Class 向导自动生成的代码基础上,仅是在class关键字和类名之间添加上AFX_EXT_CLASS

6)  由于,导入MFC扩展DLL的对话框类时,要求用户测试程序必须包含类的头文件,又因为对话框的头文件中包含了对话框的资源ID,因此在用户测试文件中还必须包含资源的头文件resource.h。由于,用户测试程序中也会包含资源头文件resource.h,为了避免同一项目文件重名的冲突,因此,这里需要修改DLL项目中的资源头文件名。

按照上图所示,打开MfcExtDll.rc资源文件。会看到如下形式的代码内容:

// Microsoft Visual C++ generated resource script.

//

#include"dllresource.h"

......//此处省略很多代码

1 TEXTINCLUDE

BEGIN

    "dllresource.h\0"

END

......//此处省略很多代码

将原有的resource.h替换为任何你想使用的名字。这里,我将其修改为dllresource.h

然后,在下图所示的地方进行resource.h的文件名重命名。

7)  编译链接后,项目会生成两个主要输出文件MfcExtDll.libMfcExtDll.dll

 

接下来,就是对该MFC扩展Dll进行测试。

1)  创建一个MFC SDI应用程序项目。

 

2)  CWinApp的派生类头文件中添加:

#pragma comment(lib,"..\\debug\\mfcextdll.lib")

进行Dll的静态导入。

 

3)  MyDllDlg.hdllresource.h两个头文件拷贝到该项目的根目录;

 

4)  在项目中的CFrameWnd的派生类的实现文件中包含MyDllDlg.h

 

 

5)  为项目添加一个菜单项资源:ID_DLLTEST_DLLDLG,并为该菜单项添加命令处理程序到CFrameWnd的派生类中。

 

6)  为该菜单命令处理程序写实现代码。

CMyDllDlgdlg;

dlg.DoModal();

 

 

思考:

通过前面的操作之后,应该对于Dll的使用方式有了一个基本认识。是否可以实现一个能通过动态链接库实现的用户界面语言在中英文间切换的对话款。