又用到dll这个东东了,之前学的一知半解,参考了众多资料终于知道了一点皮毛,赶紧记下,以后都别忘了!
先介绍一下dll创建的方法,我目前知道的在vs2005 c++环境下有两种(不知道意外情况下是否存在第三种),
(1)利用 __declspec(export)
为了编写方面先预定义一下
#ifndef DLLTEST2_EXPORTS
#define DLLTEST2_EXPORTS
#endif
#ifdef DLLTEST2_EXPORTS
#define DLLTEST2_API __declspec(dllexport)
#else
#define DLLTEST2_API __declspec(dllimport)
#endif
然后在头文件中声明库函数,格式如下
DLLTEST2_API int MaxFun(int x,int y);
DLLTEST2_API int AddFun(int x,int y);
DLLTEST2_API void PrintFun(void);
嘻嘻,又是这三个函数,浅显易懂啊! 另外说明一下,类似以下的内容自动生成的代码是给你做例子看的,直接注释掉,咱自己写就行
// 此类是从 dlltest2.dll 导出的
//class DLLTEST2_API Cdlltest2 {
//public:
// Cdlltest2(void);
// // TODO: 在此添加您的方法。
//};
//extern DLLTEST2_API int ndlltest2;
//DLLTEST2_API int fndlltest2(void);
//
然后编辑源文件,对声明的库函数进行定义
#include "stdafx.h"
#include "dlltest2.h"
#include <iostream>
#ifdef _MANAGED
#pragma managed(push, off)
#endif
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
这是导出变量的一个示例
//DLLTEST2_API int ndlltest2=0;
//
这是导出函数的一个示例。
//DLLTEST2_API int fndlltest2(void)
//{
// return 42;
//}
// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 dlltest2.h
//Cdlltest2::Cdlltest2()
//{
// return;
//}
DLLTEST2_API int MaxFun(int x,int y)
{
return ((x>y)?(x):(y));
}
DLLTEST2_API int AddFun(int x,int y)
{
return (x+y);
}
DLLTEST2_API void PrintFun(void)
{
std::cout<<"调用动态库函数"<<std::endl;
}
点击编译就生成了我们想要的dll库了,看这里
下面说第二种方法:
(2)利用def文件
声明函数、定义函数按照我们通常的做法写就可,如下所示:
int MaxFun(int x,int y);
int AddFun(int x,int y);
void PrintFun(void);
int MaxFun(int x,int y)
{
return ((x>y)?(x):(y));
}
int AddFun(int x,int y)
{
return (x+y);
}
void PrintFun(void)
{
std::cout<<"调用动态库函数"<<std::endl;
}
创建编写def文件,
LIBRARY "dlltest2"
EXPORTS
AddFun @1
MaxFun @2
PrintFun @3
;
dlltest2为动态库的库名,AddFun、MaxFun及PrintFun为导出的函数名,这个一看大家就知道怎么写了,需要说明的是,函数名和@之间的空格不能少,少了可就错了哦,我开始就犯了这样的错误,最后的分号,你当然也不能忽略。同样编译,我们的dll也出来了。
创建过程就完了,有的说第一种方法导出时函数名会被改变,如果编译器不同导入时经常会出错,不知道真假,那我就建议大家用第二种方法咯
下面我也唠叨下使用方法:
1)隐式链接
把我们之前生成的dll、lib和头文件放到要调用的项目目录下,在我们调用的头文件前加上#pragma comment(lib,"dlltest2.lib"),就可以把那些库函数当项目中的函数一样自如调用了,有一个困惑也要注释一下,既然在dll项目中,dll和lib文件是在debug文件下,那我把dll和lib也放到调用项目的dubug文件夹下,应该没问题吧,头文件我放到与debug并行的dlltest2文件夹下,不知道问什么,找不到lib文件,看清楚哦,是debug不是Debug哦,后来我把lib文件与头文件放到一起,就ok了,不知道是和我的路径设置有问题,还是别的原因,暂时也记下了。
2)显示调用
这个说来就麻烦点,要利用LoadLibrary先加载动态库,再利用GetProcAdddress获取各函数的地址,使用完之后再用FreeLibrary释放,哎,不知道有没有说清楚,上代码吧
#include "dlltest2.h"
#include <iostream>
#include <windows.h>
typedef int (*pAddFunc)(int,int);
typedef int (*pMaxFunc)(int ,int);
typedef void (*pPrintFun)(void);
int main(void)
{
pAddFunc _AddFunc;
pMaxFunc _MaxFunc;
pPrintFun _PrintFun;
HINSTANCE hInstance=LoadLibraryA("dlltest2.dll");
if(hInstance==NULL)
{
FreeLibrary(hInstance);
}
_AddFunc=(pAddFunc)GetProcAddress(hInstance,"AddFun");
_MaxFunc=(pMaxFunc)GetProcAddress(hInstance,"MaxFun");
_PrintFun=(pPrintFun)GetProcAddress(hInstance,"PrintFun");
if(_AddFunc==NULL||_MaxFunc==NULL||_PrintFun==NULL)
{
FreeLibrary(hInstance);//释放空间
}
_PrintFun();
std::cout<<"输入20 25"<<std::endl;
std::cout<<"AddFun"<<_AddFunc(20,25)<<std::endl;
std::cout<<"MaxFun"<<_MaxFunc(20,25)<<std::endl;
FreeLibrary(hInstance);
return 0;
}
就知道这么多了,先到这里