创建Win32 DLL的步骤和使用

152 篇文章 1 订阅
3 篇文章 0 订阅

说明 这里的DLL只针对 Win32 DLL (非MFC)

一. 创建DLL步骤


1. 创建Win32 DLL


next, next,...


2. 修改一下DLL 的主函数


BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		break;
	case DLL_PROCESS_DETACH:
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
	}
	return TRUE;
}


3. 以下面的形式添加你想要导出的函数


// *.h
#pragma once
#ifdef __cplusplus
extern "C"{
#endif
/

int __stdcall TestDll(int nA, int nB);

/
#ifdef __cplusplus
}
#endif 


//*.cpp
#ifdef __cplusplus
extern "C"{
#endif
/

int __stdcall TestDll(int nA, int nB)
{
	return nA + nB;
}

/
#ifdef __cplusplus
}
#endif

4. 添加一个def文件


LIBRARY "MyDLL"
EXPORTS
	TestDll @ 1

在vs2010中使用.def文件导出函数时, 要在工程属性|链接器|输入|模块定义文件中, 加入自定义的.def文件名.
编译好dll后, 可用vs的命令提示查看导出函数  dumpbin -exports dllnames


5. 编译


你可以按照默认的, 也可以按照自己喜欢的(例如debug版的dll是*d.dll)



二. 使用DLL步骤


1. 创建一个测试工程, 把上面步骤的dll,lib和.h文件放到对应的位置


2. 包含对应的.h文件, 添加语句 #pragma comment(lib, "*.lib") 
// 这里的*.lib是对应DLL的lib名称或详细路径 (这方法叫做静态加载),
// 静态加载时, 可以在 项目|***属性|链接器|输入|附加依赖项中写入对应的 *.lib 来
// 代替写 #pragma comment(lib, "*.lib")

// *.lib文件的路径是基于工程的工作目录而定的, 而不是该cpp文件的.
// 看个人习惯吧, 各有各的好处.
//


3. 编译即可.


4. 你也可以使用LoadLibrary, GetProcAddress等API来调用DLL(这叫做动态加载).
静态加载需要lib和头文件, 而动态加载不需要lib, 但要知道导出函数的名称和参数, 也就是要知道函数的声明.
    
5. 动态加载的步骤:


typedef int (__stdcall *LPFUNCTestDll)(int, int);

HMODULE hSdt = LoadLibrary(_T("*.dll"));;
if(0 == hSdt)	// 加载失败
{
	return;
}

LPFUNCTestDll TestDll = (LPFUNCTestDll)GetProcAddress(hSdt,"TestDll");

TestDll(1, 2);// 调用

FreeLibrary(hSdt);

   
三. 其他说明


1. extern "C"的作用 (C一定要大写)
       默认c++编译器会对名字作修饰,有诸如@YAH,主要包括参数的类型和参数大小的信息。其中一个重要的原因就是重载函数,如果两个重载函数都需要导出,那么就要用修饰名来区分了。 
关于具体原因参照<<核心编程>>, 网上关于修饰名的介绍也很多.

      不使用extern "C"的话, 在出现重载函数时, 非C++开发的程序有可能找不到DLL中的导出函数, 如果你dll中没有重载函数的话, 我觉得不使用也行, 个人认为加入比较好.

      如果你的客户端,就是倒入dll的应用程序不用c++方式调用的话,那么就找不到这个函数了你能保证你的客户一定是用c++编译吗  如果它是vb的应用程序呢??   所以在dll里面,加上extern"C" 
   
      extern "C"的作用是,使编译器按照c的方式生成函数名, c的方式实际的函数名和你写的一样. 如果没有这个, 则按照c++的方式生成函数名, 这样实际的函数名(LoadLibrary方式GetProcAddress传入的函数名)和你写得函数名不一样, 这样你用LoadLibrary, GetProcAddress这种方式调用dll就不成功. 但是用引入库的方式调用, 则编译器自动转换函数名, 所以总是没有问题.


2. 除了使用.def文件导出函数外, 可以使用__declspec(dllexport)和__declspec(dllimport)
步骤如下:


a. *.h
// *.h
#pragma once
#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C"{
#endif
/

DECLDIR int __stdcall TestDll(int nA, int nB);

/
#ifdef __cplusplus
}
#endif


b. *.cpp
/
#define DLL_EXPORT

#include "*.h"
#ifdef __cplusplus
extern "C"{
#endif
/

DECLDIR int __stdcall TestDll(int nA, int nB)
{
	return nA + nB;
}
/
#ifdef __cplusplus
}
#endif

3. 该方法我不是很常用, 但我记得有一次我写了一个DLL给其他开发语言调用使用def文件的就调用成功, 而使用__declspec(dllexport)和__declspec(dllimport)却不行, 具体原因也不太清楚了, 现在还是比较多使用.def文件导出函数.



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值