欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MFC中DLL的创建

程序员文章站 2022-06-25 19:17:12
...

可创建的MFC DLL有三种:

①  Regular DLLusing shared MFC DLL MFC动态链接常规DLL需要MFC动态链接库。该类型DLL既可以被MFC程序使用也可以被一般的Win32程序使用

②  Regular DLLwith MFC statically linkedMFC静态链接常规DLL。这种DLL将要使用的MFC的类代码直接加入到DLL中,从而使得DLL增大。但这样可以使得程序无需依赖MFC环境,不需要具有MFC动态链接库。该类型DLL既可以被MFC程序使用也可以被一般的Win32程序使用

③  MFCextension DLLMFC扩展DLL。该种类型的DLL要求可以链接到MFC动态链接库。故MFC扩展DLL是在MFC动态链接库基础上创建的。也就是说,要使用该DLL,首先要有MFC动态链接库,并且只能被MFC程序使用

 

第三种MFC DLL工程创建后,会有一个DllMain函数,但前两种DLL工程没有:

DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	……
}
一般来说,不用对该函数做改动。

 

封装自定义代码

常用的封装有两种:纯函数封装类封装

无论是哪一种封装,编译后,都会在Debug或Release文件夹下生成许多文件。其中需要用到的只有.DLL文件与.lib文件,除此之外还有相关的.h文件。

使用自定义DLL需要三个文件:.h.DLL.lib

①  将这三个文件复制到新工程的根目录下。

②  在新工程中将.h文件导入工程并在需要的地方#include。

③  在需要调用DLL中自定义类的地方

#pragma  comment(lib,"MyDll.lib")

然后就可以正常使用DLL中封装的类了。

lib文件是DLL文件的一个代理,记录了DLL中的函数名,但不含实现代码。exe程序会与lib文件进行链接,从而调用DLL中的具体函数。

要将一个纯函数封装到DLL中,则:

1.      纯函数的声明与实现一定要分开。声明在.h文件中,实现在.cpp文件中。

2.      将.h与.cpp正常加入到工程中,然后修改.h中的类声明:

bool  MyFunction();

修改为:

extern "C" _declspec(dllexport) bool  MyFunction();

编译即可。

要将一个自定义类封装到DLL中,则:

1.      将该类的.h与.cpp正常加入到工程中,然后修改.h中的类声明:

class CYuEdit :public CEdit

修改为:

class AFX_EXT_CLASS CYuEdit : public CEdit

AFX_EXT_CLASS关键字用于导出DLL中的函数。只有这样才能使exe程序调用DLL中的函数。

编译即可。

要将一个资源封装到MFC  DLL,则:

1.      若将一个对话框封装在DLL里,首先添加一个对话框资源,然后为该对话框添加类。该类中会绑定该对话框:

 enum { IDD = IDD_DIALOG_TEST};

注意该对话框资源是存在于DLL工程中的,所以在exe中无法识别该资源。可以在DLL中写一个纯函数用于显示对话框,而不要将对话框类的.h直接导入引用工程中。

2.      若需要将.BMP与Icon等资源封装到DLL中,那么直接将相应资源添加进DLL工程,编译即可。比如添加了一个BMP,在DLL的Resource.h该BMP定义为:

#define IDB_BITMAP_TEST     2001

使用资源时,将DLL与lib导入后,新工程依然不能识别上面的BMP的ID。为了可以正确识别,首先要在新工程的Resource.h中定义需要使用的资源,也就是将

#define IDB_BITMAP_TEST     2001

添加到新工程的Resource.h中。

然后就可以引用了。

特别注意两个Resource.h中的BMP资源定义必须相同。

HMODULE等同于HINSTANCE 

HINSTANCE hDllModule;	//DLL句柄
hDllModule = LoadLibrary(_T("DLL_TEST.dll"));
if (hDllModule)
{
	//执行某些操作
	FreeLibrary(hDllModule);
}

上面代码用于获取DLL的句柄以及释放DLL。注意LoadLibrary ()FreeLibrary()是对应的。

根据DLL句柄,可以用两种方法获取DLL中的资源(推荐使用第二种):

①  使用FindResource()LoadResource()配合。该方法可以获取所有类型资源。注意FindResource()要求传入一个HMODULE,而HMODULEHINSTANCE 是相同的,直接传入HINSTANCE 即可。

②  使用各种资源相应的Load函数。如BITMAP的函数为LoadBitmap()。

示例代码:

①  使用FindResource()LoadResource()配合。

HRSRC hRsrc = FindResource(hDllModule, MAKEINTRESOURCE(IDB_BITMAP_TEST), RT_BITMAP);
if (NULL == hRsrc)
{
	return FALSE;
}

//获取资源的大小
DWORD dwSize = SizeofResource(NULL, hRsrc);
if (0 == dwSize)
{
	return FALSE;
}

//加载资源
HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
if (NULL == hGlobal)
{
	return FALSE;
}

//锁定资源
LPVOID pBuffer = LockResource(hGlobal);
if (NULL == pBuffer)
{
	return FALSE;
}

//执行某些操作

//释放资源
FreeResource(hGlobal);

注意LockResource()FreeResource()是对应的。

②  使用各种资源相应的Load函数。

    HBITMAP hBitmap=LoadBitmap(hDllModule,MAKEINTRESOURCE(IDB_BITMAP_TEST));        //从DLL中读取BITMAP资源

 

四.纯资源DLL

若要将所有的资源封装进一个DLL中,然后为所有程序共享,那么就需要编写纯资源DLL。纯资源DLL内部只含纯资源。资源DLL使用的是Win32 DLL。

创建项目时,选择Win32Project,在后续的Application Setting页面的Application Type中选择DLL。

然后直接将相应资源添加进DLL工程。

为了避免编译出现错误“: error LNK2001:unresolved external symbol [email protected],在project右键选则properties,Linker->Input->AdditionalDependencies填入:
Debug:加入 msvcrtd.lib
Release:加入 msvcrt.lib

其中Debug与Release的选择在左上角。也可直接选择All Configurations。

编译即可。

纯资源DLL用法跟上面三中2一样。但纯资源DLL没有lib文件,只有DLL文件。

 

对于上面的三与四来说,要引用DLL中的资源就必须保证DLL中的Resource.h与新工程中的Resource.h有相同的资源定义。

但这样是很不方便的,使用者是无法知道DLL中Resource.h的定义的。所以,一般都使用另一种方法:

①   创建DLL工程并添加一个资源。比如:

#define IDB_BITMAP1    1001

②   找到该资源在Resource.h中的定义,也就是上面的代码。然后为该资源修改一个别名:

#define IDB_BITMAP_TEST     1001

③   新建一个.h文件。该文件用于定义所有共享函数与共享资源。然后将上面的代码复制到该.h文件中。

④   将DLL及lib加入新工程后,也要将.h加入新工程。这样,当需要使用DLL中的资源时,就可以通过.h文件得知资源名称与ID。

但该方法依然需要在新工程的Resource.h中再次定义,或者在新工程使用函数前定义。

相关标签: MFC DLL