1 VS2005创建DLL
使用VS2005创建自己的动态链接库,这样就不用看到DLL文件有抵触情感了。
一、打开VS2005软件,创建DLL工程。起名ceshi1.
1)
2) 点击下一步,应用程序类型为DLL,空工程。
3) 完成,一个新的DLL工程设置完毕,接下来编辑源码
添加头文件,命名为ceshi1.h,编辑内容:
#ifndef CESHI1_H
#define CESHI1_H //防止重复定义
#include
//头文件引用
#if defined DLL_EXPORT //源文件需引用下一函数
#define DECLDIR __declspec(dllexport)//就是这个
#else
#define DECLDIR __declspec(dllimport)
#endif
extern "C"
{
DECLDIR int add(int a, int b); //函数声明
DECLDIR void function(void);
}
#endif
解释:VC中有两种方式导出DLL文件中的函数
1) 使用 __declspec关键字。
2) 创建模板定义文件(Module_Definithion File)即.def文件。
在此使用第一种方法:
__declspec(dllexport)作用是导出函数符号到DLL的一个存储类中。在头文件中定义#define DECLDIR __declspec(dllexport)宏来运行这个函数。
使用条件编译,在源文件中宏定义 #define DLL_EXPORT 来运行这个函数。
//******************************************************************************
创建源文件 ceshi1.cpp
#include
#define DLL_EXPORT
#include "ceshi1.h"
extern "C"
{
//定义Dll中的所有函数
DECLDIR int add(int a, int b)
{
return a+b;
}
DECLDIR void function(void)
{
std::cout<<"DLL called"<
int main()
{
function();
std::cout<
#include
typedef int (*AddFunc)(int, int);
typedef void (*FunctionFunc)(void);//函数指针
int main()
{
AddFunc _AddFunc;
FunctionFunc _FunctionFunc;
//HINSTANCE实例句柄(即一个历程的入口地址)
HINSTANCE hInstLibrary = LoadLibraryA("ceshi1.dll");
//注意,此时的LoadLibraryA()窄字符集和LoadLibraryW()宽字符集的区别,后有介绍。
if(hInstLibrary == NULL)
{
FreeLibrary(hInstLibrary);//释放DLL获得的内存,若句柄无效
}
//获得函数的入口地址,还需类型转换
_AddFunc = (AddFunc)GetProcAddress(hInstLibrary,"add");
_FunctionFunc = (FunctionFunc)GetProcAddress(hInstLibrary,"function");
if(_AddFunc==NULL || _FunctionFunc ==NULL)//确定是否成功。
{
FreeLibrary(hInstLibrary);
}
std::cout<<_AddFunc(25,25)<
#include
#include
DLLIMPORT void HelloWorld(void)
{
MessageBox(0,TEXT("Hello World from DLL!\n"),TEXT("Hi"),MB_ICONINFORMATION);
}
BOOL APIENTRY DllMain(HINSTANCE hInst,DWORD reason,LPVOID reserved)
{
switch(reason){
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return true;
}
__declspec(dllexport)标志着后面这个函数将成为对外的接口,使用包含在DLL中的函数,必须将其导入,导入操作通过dllimport来完成,dllexport和dllimport都是VC和BC所支持的关键字,但不能被自身格式所使用,通用格式为__declspec(dllexport)和__declspec(dllimport),为了简化,用宏名代替,若程序被编译成C++程序,同时希望C程序亦可使用,需要增加”C”的链接说明,
#define DLLEXPORT extern “C” __declspec(dllexport),就避免了
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
C++命名损坏。、、有错。
BOOL APIENTRY DllMain()说明:
1、每个DLL必须有一个入口点,DllMain()是入口函数,负责初始化(initialization)和结束(termination)工作,每当一个新的进程或该进程的新的线程访问DLL时,或者不再使用DLL时,或结束时,都将调用DllMain。但是使用terminate Process或terminate Thread结束进程和线程,不会调用DllMain。
DllMain()函数的原型:
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_resong_for_call, LPVOID lpreserved)
{
switch(ul_reason_for_call){
case DLL_PROCESS_ATTACH:
…
case DLL_THREAD_ATTACH:
…
case DLL_PROCESS_DETTACH:
…
case DLL_THREAD_DETTACH:
…
}
return true;
}
参数:
hMoudle:是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);HINSTANCE
ul_reason_for_call:是一个说明动态库被调原因的标志。当进程或线程装入或卸载动态连接库的时候,操作系统调用入口函数,并说明动态连接库被调用的原因。它所有的可能值为:
DLL_PROCESS_ATTACH: 进程被调用;
DLL_THREAD_ATTACH: 线程被调用;
DLL_PROCESS_DETACH: 进程被停止;
DLL_THREAD_DETACH: 线程被停止;
lpReserved:是一个被系统所保留的参数。
//问题:如何使用上面的DLL库文件?
资料:
动态链接库调用有两种函数:导出函数(export function)和内部函数(internal function)。导出函数可被其他模块调用,内部函数只在定义的DLL中内部使用。
其他模块使用导出函数的用法:
1) 传统方法
在模块定义文件的EXPORT部分指定需要的函数或变量,语法格式如下:
entryname[=internalname] [@ordinal[NONAME]] [DATE] [PRIVATE]
其中:entryname是导出函数或数据被引用的名称。
internalname 同entryname.
@ordinal
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
示在输出表中的顺序号
NONAME仅仅在按顺序号输出时被使用,(不使用entryname)
DATA表示输出的是数据项,使用DLL输出数据的程序必须声明该数据项为__declspec(dllimport).
以上各项中,只有entryname是必须的,其他可以省略。
对于“C”函数来说,entryname可以等同于函数名;但是对“C++”函数(成员函数、非成员函数)来说,entryname是修饰名。可以从.map映像文件中得到要输出函数的修饰名,或者使用DUMPBIN /SYMBOLS得到,然后把它们写在.def文件的输出模块。DUMPBIN是VC提供的一个工具。
如果要输出一个“C++”类,则把要输出的数据和成员的修饰名都写入.def模块定义文件。
2) 命令行输出
对链接程序LINK指定/EXPORT命令行参数。
3) 使用MFC提供的修饰符号 __declspec(dllexport)
在要导出的函数、类、数据的声明前加上 __declspec(dllexport) 修饰符,表示导出。
extern “C”使在C++中使用C编译方式,在C++中定义C函数,需加extern “C”关键字,用extern “C”来指明该函数使用C编译方式,导出的C函数可在C代码中调用。
例如:在一个C++文件中,有如下函数
extern “C” {void __declspec(dllexport) __cdecl Test(int var);}
其输出函数名为 Test (非C++方式)
MFC提供了一些宏,就有这样的作用。省略 #define
AFX_CLASS_IMPORT:__declspec(dllexport)
AFX_API_IMPORT:__declspec(dllexport)
AFX_DATA_IMPORT:__declspec(dllexport)
AFX_CLASS_EXPORT:__declspec(dllexport)
AFX_API_EXPORT:__declspec(dllexport)
AFX_DATA_EXPORT:__declspec(dllexport)
AFX_EXT_CLASS: #ifdef _AFX_EXT
AFX_CLASS_EXPORT
#else
AFX_CLASS_IMPORT
AFX_EXT_API:#ifdef _AFX_EXT
AFX_API_EXPORT
#else
AFX_API_IMPORT
AFX_EXT_DATA:#ifdef _AFX_EXT
AFX_DATA_EXPORT
#else
AFX_DATA_IMPORT
像AFX_EXT_CLASS这样的宏,如果用于DLL应用程序的实现中,则表示输出(因为_AFX_EXT被定义,通常是在编译器的标识参数中指定该选项/D_AFX_EXT);如果用于使用DLL的应用程序中,则表示输入(_AFX_EXT没有定义)。
要输出整个的类,对类使用_declspec(_dllexpot);要输出类的成员函数,则对该函数使用_declspec(_dllexport)。如:
class AFX_EXT_CLASS CTextDoc : public CDocument
{
…
}
extern "C" AFX_EXT_API void WINAPI InitMYDLL();
这几种方法中,最好采用第三种,方便好用;其次是第一种,如果按顺序号输出,调用效率会高些;最次是第二种。
3 动态链接库的实现
一、创建DLL文件
1) 使用VS2005创建DLL空工程。
2) 新建头文件 builder1.h,程序:
//*************************************************************************
#ifndef BUILDER1_H
#define BUILDER1_H
#ifdef BUILDER1_DLL
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
//注意#endif的位置
extern "C"{ //原样编译
//__stdcall 使非C/C++语言能够调用API
DLL_API int __stdcall Max(int a, int b);
}
#endif
//******************************************************************************
3) 新建源文件 builder1.cpp
//******************************************************************************
#define BUILDER1_DLL
#include "builder1.h"
DLL_API int __stdcall Max(int a,int b)
{
return a>b ? a:b;
}
//*****************************************************************************
4) 用.def文件创建动态链接库 build1.dll
a、删除build1工程中的builder1.h文件
b、在builder1.cpp中删除#include ”builder1.h”语句。内容:
int __stdcall Max(int a,int b)
{
return a>b ? a:b;
}
c、向该工程中加入一个文本文件,命名为builder1.def,内容:错误
LIBRARY build1 //标准格式 LIBRARY “build1”
EXPORTS
Max @ 1 //注意:一定要有空格,语法的格式
d、编译生出dll文件
二、调用动态链接库DLL
1、隐式调用:
1) 创建控制台工程build2
2) 将build1.dll, build1.lib, builder1.h拷贝到工程所在目录,(主程序cpp所在的文件夹下)
三个文件必须全要。
3) 新建源文件 build2.cpp
//***********************************************************************
#include "builder1.h"
#pragma comment(lib,"build1.lib")
#include
int main()
{
int value;
value = Max(100,250);
std::cout << "Value="<
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
extern "C" __declspec(dllimport) int __stdcall test(void); //接口声明
int main(int argc, char* argv[])
{
std::cout <
#include
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
typedef int (__stdcall *TEST)(void);
int main(int argc, char* argv[])
{
HINSTANCE hDll;
hDll = LoadLibrary("Project2.dll");
TEST ddd;
ddd = GetProcAddress(hDll,"test");
std::cout<<"ddd()="<
#include "staticLib.h"
staticLibTest::staticLibTest()
{
m_value = 8;
}
void staticLibTest::SetVal(int para)
{
m_value = para;
}
int staticLibTest::GetVal()
{
return m_value;
}
void staticLibTest::Display()
{
std::cout <<"output value is: "<
#include "wrap.h"
#pragma comment(lib,"wrap.lib")
int main()
{
ExtcSetVal(250);
ExtcDisplay();
return 0;
}
//******************************************************************************
将之前生成的两个静态库staticLib.lib和wrap.lib还有头文件wrap.h拷到当前目录下,
编译运行即可
2 MFC 动态链接库
1.制作的步骤:
(1)新建MFC AppWizard(dll)工程,工程名为MFCDll,选择空工程 类型。
(2)在生成的MFCDll.cpp文件后面增加下面函数代码:
int sum(int a, int b)
{
return a+b;
}
(3)在生成的MFCDll.def文件后面增加如下:
sum @1 ;表示第一个函数是sum
(4)编译后会产生两个文件MFCDll.lib,MFCDll.dll
2、调用
(1)隐式调用法: 将MFCDll.lib拷贝到需要应用该DLL的工程的目录下,将MyDll.dll拷贝到产生的应用程序的目录下,并在需要应用该DLL中的函数的CPP文件中添加如下几行:
//注意这里没有在MFCDll.h中声明函数,所以不能直接包含MFCDll.h来声明函数。
以下是引用片段:
#pragma comment(lib,"MFCDll");
int sum(int a, int b);
//当然如果你的DLL中有很多函数,那可以另外写个MFCDll.h,包含所有的函数声明,然后直接将头文件包含进去
(2)显示调用法:与Win32的调用方法一样,不需要#pragma comment(lib,"MFCDll");,但是需要在Project->Setting->Link->Object/library modules的框中增加MFCDll.lib这个库。(研究中)
**************************************************************************
DLL(Dynamic Linkable Library)可以看成一些可以直接拿来用的变量、函数或类的集合。在库的发展史上经历了“无库-静态链接库-动态链接库”的时代。
静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。
对动态链接库,我们还需建立如下概念:
(1)DLL 的编制与具体的编程语言及编译器无关
只要遵循约定的DLL接口
规范
编程规范下载gsp规范下载钢格栅规范下载警徽规范下载建设厅规范下载
和调用方式,用各种语言编写的DLL都可以相互调用。譬如Windows提供的系统DLL(其中包括了Windows的API),在任何开发环境中都能被调用,不在乎其是Visual Basic、Visual C++还是Delphi。
(2)动态链接库随处可见
我们在Windows目录下的system32文件夹中会看到kernel32.dll、user32.dll和gdi32.dll,windows的大多数API都包含在这些DLL中。kernel32.dll中的函数主要处理内存管理和进程调度;user32.dll中的函数主要控制用户界面;gdi32.dll中的函数则负责图形方面的操作。
一般的程序员都用过类似MessageBox的函数,其实它就包含在user32.dll这个动态链接库中。由此可见DLL对我们来说其实并不陌生。
(3)VC动态链接库的分类
Visual C++支持三种DLL,它们分别是Non-MFC DLL(非MFC动态库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。
非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;MFC规则DLL 包含一个继承自CWinApp的类,但其无消息循环;MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。
隐式调用的方法比较方便,但DLL改变后,应用程序须从新编译。并且,所有所调用的DLL在应用程序加载的同时被加载到内存中,当应用程序调用的DLL比较多时,装入的过程十分慢。显式调用则比较灵活,但比较麻烦.
静态链接MFC DLL和共享MFC DLL的区别:静态链接把程序中要用的在MFC DLL里的东西全部编译到创建的DLL中,体积会大一点,但可以在没有装MFC的机器上运行;通过共享创建的DLL体积小,但在没有安装MFC的机器上有可能不能运行,因为没有相应的库。