非MFC动态库指的是不用MFC的类库结构,直接用C语言写的DLL,其导出的函数是标准的C接口,能被非MFC或MFC编写的应用程序所调用
在VC++6.0中,File-->New-->Win32 Dynamic-Link Library创建非MFC动态库
(一)一个简单的非MFC动态库
在VC++中new一个Win32 Dynamic-Link Library工程DllTest。注意不要选择MFC AppWizard(dll),因为用MFC AppWizard(dll)建立的将是后面要讲述的MFC 动态链接库。
在建立的工程中添加DllTest.h及DllTest.cpp文件,源代码如下:
//DllTest.h文件
#ifdef DLL_API
#else
#define DLL_API extern "C" _declspec(dllimport) // 需要在每个要导出的函数前面添加标示符 _declspec(dllimport)
//用DLL_API代替_declspec(dllimport)
//一般添加 extern "C"解决名字改编问题
#endif
DLL_API int add(int a,int b);
DLL_API int subtract(int a,int b);
//DllTest.cpp文件
#define DLL_API extern "C" _declspec(dllexport) //这里是_declspec(dllexport)
#include "DllTest.h"
#include <Windows.h>
#include <stdio.h>
int add(int a,int b)
{
return a+b;
}
int subtract(int a,int b)
{
return a-b;
}
直接编译就产生了.lib .dll文件
(二)隐式链接的方式加载DLL
再新建一个工程Test(我们随便建一个win32 console Application),该工程只有一个Test.cpp文件它调用DLL中的函数,代码如下:
#include <stdio.h>
#include "..\DllTest\DllTest.h"
//#pragma comment( lib, "..\\DllTest\\Debug\\DllTest.lib" )
int main(int argc, char *argv[])
{
printf("%d\n",add(5,3));
return 0;
}
如何隐式加载,下面我们一步步的分析,
直接build会出错 Test.obj : error LNK2001: unresolved external symbol __imp__add,,有链接的时候出错,解决:在Test程序中,选择Project-->Settings-->ling-->Object/library modules中输入DllTest.lib(或者在程序中加#pragma comment( lib, "..\\DllTest\\Debug\\DllTest.lib" ) ),然后选择tools-->options-->directories-->library files菜单或选项,填入库文件路径E:\Program Files\Microsoft Visual Studio 6.0\MyProjects\DllTest\Debug(或者直接将产生的DllTest.lib文件拷贝到Test工程下),重新build没有问题了。
运行,出错提示计算机中丢失DllTest.dll,那么我们就需要将产生的DllTest.dll文件拷贝到Test工程目录下,重新运行成功
(三)声明导出函数
在刚才的例子中给出的是在函数声明前面加上_declspec(dllimport),同时在前面加上了extern "C"
注:1.编译器在生成DLL时,会对导出的函数进行名字改编,使用不同的编译器分别生成DLL和访问该DLL的客户端程序的话,后者在访问该DLL的导出函数时就会出现问题,所以一般在定义导出函数时,加上限定符extern "C"
2.使用extern "C"可以解决C++和C语言之间互相调用时函数命令的问题,但是不能用于导出一个类的成员函数,只能用于导出全局函数这种情况
3.如果函数的调用约定发生了改变,即使使用了extern "C",它们的名字仍然会发生改变,那么就有了第二周声明导出函数的方式,使用模块文件(DEF)
接着我们将声明导出函数的另外一种方法,使用模块文件
下面我们重新建Win32 Dynamic-Link Library工程DllTest,添加DllTest.cpp文件,代码如下:
int add(int a,int b)
{
return a+b;
}
int subtract(int a,int b)
{
return a-b;
}
然后添加模块定义文件DllTest.def,我们可以在DllTest工程目录下新建一个空的文本取名DllTest.def,然后在[Project\Add To Project\Files...]-->Insert Files into Project,选择DllTest.def文件将其添加进Test工程,然后添加代码:
LIBRARY DllTest//LIBRARY指定动态链接库的内部名称,这个必须要和生成的动态链接库名称匹配
EXPORTS//指明DLL要导出的函数
add
subtract
build 这个DllTest工程,就产生了.lib .dll文件
自己再编译一个测试工程,代码如下:
#include <stdio.h>
#include <windows.h>
//typedef int(*lpAddFun)(int, int); // 宏定义函数指针类型
int add(int a, int b);
int subtract(int a , int b);
int main(int argc, char *argv[])
{
printf( "%d\n" ,add(5,3));
printf( "%d\n" ,subtract(5,3));
return 0;
}
要像刚才隐式加载一样的去做,才能运行成功
(四)显示加载DLL
上面使用的都是隐式加载DLL的方法,对动态链接库的访问还可以使用显示加载方式:完全由编程者用API函数加载和卸载DLL,程序员可以决定 DLL 文件何时加载或不加载,显式链接在运行时决定加载哪个DLL文件
第一步还是创建DllTest工程,产生.lib .dll文件,
第二步新建工程Test(我们随便建一个win32 console Application),代码如下:
//Test.cpp
#include <stdio.h>
#include <Windows.h>
typedef int (*ADDPROC)(int ,int );//定义函数指针类型
int main(int argc,char *argv[])
{
HINSTANCE hInst;
ADDPROC Add;
hInst=LoadLibrary("..\\DllTest\\Debug\\DllTest.dll"); //动态加载DLL
if(hInst!=NULL)
{
Add=(ADDPROC)GetProcAddress(hInst,"add");//获取DLL的导出函数
if(Add!=NULL)
{
int result=Add(5,3);
printf("%d\n",result);
}
FreeLibrary(hInst);
}
return 0;
}