VS2005创建自己的DLL库

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#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 中的函数,必 须将其导入,导入操作通过 dllimport 来完成,dllexport 和 dllimport 都是 VC 和 BC 所支持的 关键字,但不能被自身格式所使用,通用格式为__declspec(dllexport)和__declspec(dllimport), 为了简化,用宏名代替,若程序被编译成 C++程序,同时希望 C 程序亦可使用,需要增加”C” 的链接说明, #define DLLEXPORT extern “C” __declspec(dllexport),就避免了标准 C++命名损坏。、、有错。
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) {
switch(reason){ case DLL_PROCESS_ATTACH: break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break;
}
return true; }
Windows 的执行文件可以划分为两种形式:程序和动态连接库(DLLs)。一般程序运行是 用.EXE 文件,但应用程序有时需要调用存储在 DLL 中的函数。
当我们调用 Windows 中的 API 函数的时候,实际上就是调用存储在 DLL 中的函数。 在如下几种情况下,调用 DLL 是合理的:
1) 不同的程序使用相同的 DLL ,这样只需要将 DLL 在内存中装载一次,节省了内存 的开销。
} returnຫໍສະໝຸດ Baidutrue;
}
参数: hMoudle:是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP 段 的一个选择符);HINSTANCE ul_reason_for_call:是一个说明动态库被调原因的标志。当进程或线程装入或卸载动态连接 库的时候,操作系统调用入口函数,并说明动态连接库被调用的原因。它所有的可能值为:
__declspec(dllexport)作用是导出函数符号到 DLL 的一个存储类中。在头文
件中定义#define DECLDIR __declspec(dllexport)宏来运行这个函数。
使用条件编译,在源文件中宏定义 #define DLL_EXPORT 来运行这个函数。
//****************************************************************************** 创建源文件 ceshi1.cpp #include <iostream>
DLL_PROCESS_ATTACH: 进程被调用; DLL_THREAD_ATTACH: 线程被调用; DLL_PROCESS_DETACH: 进程被停止; DLL_THREAD_DETACH: 线程被停止; lpReserved:是一个被系统所保留的参数。 //问题:如何使用上面的 DLL 库文件?
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)<<std::endl; _FunctionFunc(); getchar();
FreeLibrary(hInstLibrary); return 0; } //******************************************************************************
1 VS2005 创建 DLL
使用 VS2005 创建自己的动态链接库,这样就不用看到 DLL 文件有抵触情感了。 一、打开 VS2005 软件,创建 DLL 工程。起名 ceshi1.
1)
2) 点击下一步,应用程序类型为 DLL,空工程。
3) 完成,一个新的 DLL 工程设置完毕,接下来编辑源码 添加头文件,命名为 ceshi1.h,编辑内容: #ifndef CESHI1_H
function(); std::cout<<add(25,25)<<std::endl;
getchar(); return 0; } //****************************************************************************** 2) 显式链接 只加载.dll 文件,但需用到函数指针和 Windows 函数,不需要.lib 文件和.h 头文件。 #include <iostream> #include <windows.h>
#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"<<std::endl; } } 编译工程,生成 ceshi1.dll 文件和 ceshi1.lib 文件(注:找到工程目录,这两个文件在外 面的 debug 文件夹下)。 二、使用创建好的 DLL 库文件 创建一个控制台应用程序
BOOL APIENTRY DllMain()说明: 1、每个 DLL 必须有一个入口点,DllMain()是入口函数,负责初始化(initialization)和结
束(termination)工作,每当一个新的进程或该进程的新的线程访问 DLL 时,或者不再使用 DLL 时,或结束时,都将调用 DllMain。但是使用 terminate Process 或 terminate Thread 结束 进程和线程,不会调用 DllMain。
#define CESHI1_H //防止重复定义
#include <iostream> //头文件引用
#if defined DLL_EXPORT //源文件需引用下一函数 #define DECLDIR __declspec(dllexport)//就是这个
#else #define DECLDIR __declspec(dllimport)
2 C 语言创建 DLL
只是要在公开的接口函数声明前面加上几个特定的修饰符。 //**********example1.h***********************************************************
#ifndef EXAMPLE1_H #define EXAMPLE1_H
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: …
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) {
1) 隐式链接: 连接到.lib 文件,首先将 ceshi1.h 头文件,ceshi1.dll 动态库文件,ceshi1.lib 静态库文件放在控制台应用程序工程的目录中,即源文件所在的文件夹里。 添加源文件 ceshi2.cpp,编码:
#pragma comment(lib,"ceshi1.lib")//链接.lib文件 #include "ceshi1.h" //包含dll的头文件 #include <iostream> int main() {
#define DLLIMPORT __declspec(dllexport)
DLLIMPORT void HelloWorld(void);
#endif
//******example1.c*************************************************************** #include "example1.h" #include <windows.h> #include <stdio.h> #include <stdlib.h>
资料:
动态链接库调用有两种函数:导出函数(export function)和内部函数(internal function)。 导出函数可被其他模块调用,内部函数只在定义的 DLL 中内部使用。
其他模块使用导出函数的用法: 1) 传统方法 在模块定义文件的 EXPORT 部分指定需要的函数或变量,语法格式如下: entryname[=internalname] [@ordinal[NONAME]] [DATE] [PRIVATE] 其中:entryname 是导出函数或数据被引用的名称。 internalname 同 entryname. @ordinal 表示在输出表中的顺序号 NONAME 仅仅在按顺序号输出时被使用,(不使用 entryname) DATA 表 示 输 出 的 是 数 据 项 , 使 用 DLL 输 出 数 据 的 程 序 必 须 声 明 该 数 据 项 为 __declspec(dllimport). 以上各项中,只有 entryname 是必须的,其他可以省略。 对于“C”函数来说,entryname 可以等同于函数名;但是对“C++”函数(成员函数、 非成员函数)来说,entryname 是修饰名。可以从.map 映像文件中得到要输出函数的修 饰名,或者使用 DUMPBIN /SYMBOLS 得到,然后把它们写在.def 文件的输出模块。 DUMPBIN 是 VC 提供的一个工具。
2) 当某些内容需要升级的时候,如果使用 DLL 只需要改变 DLL 就可以了,而不需要 把整个程序都进行变动。
3) 由于 DLL 是独立于语言的,所以,当不同语言习惯的人共同开发一个大型项目的 时候,使用 DLL 便于程序系统的交流,当然,Delphi 开发的 DLL 也可以在诸如 Visual BASIC, C++ 等系统中使用。
相关文档
最新文档