Windows API 教程(六) 动态链接库

简介

  动态链接库(DLL,全称Dynamic Link Library)进程之间共享使用的函数库。动态链接库提供了一种方法,是进程可以调用不属于其自身可执行代码的函数。函数的可执行代码位于一个DLL中,当调用DLL中的方法时,进程由原本自身的代码执行到DLL中。DLL有助于程序模块化,减少重复开发。
  在这之前已经提到的多次的 kernel32.dll ,也即 windows 的核心DLL,我们进行 windows 编程开发中很多函数都是从其中导出。

编写 DLL

1) 新建项目

【文件】->【新建】->【项目】->选择【win32 项目】->【下一步】->【DLL 空项目】

新建项目的目录要记一下,等会会用到。

2)开始编写 DLL

dll.h


#ifdef MYDLL_EXPORTS
	#define MYDLL_API _declspec(dllexport)
#else
	#define MYDLL_API _declspec(dllimport)
#endif

// 声明自定义导出函数
MYDLL_API void helloDLL(void);

dll.c


#include <windows.h>// for MessageBox
#include "dll.h"	// 引用导出定义

// DLL入口函数
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved)
{
	switch(dwReason)
	{
		// 动态链接库映射到某个进程的地址空间
		case DLL_PROCESS_ATTACH:
			/**
			 * 当DLL刚被加载时触发(LoadLibrary),此处专门用来做初始化工作,
			 * 如果初始化失败可以返回 false 这样DLL就不会被继续加载了
			 **/
		break;

		// 应用程序创建新的线程
		case DLL_THREAD_ATTACH:
			
		break;

		// 应用程序某个线程正常终止
		case DLL_THREAD_DETACH:

		break;
		
		// 动态链接库将被卸载
		case DLL_PROCESS_DETACH:
			/**
			 * 当DLL将要被卸载时触发(FreeLibrary),此处专门用来做清理工作
			 * 如关闭文件,释放内存空间等
			 **/
		break;
	}
	return 1;
}

void helloDLL(void)
{
	MessageBox(NULL, TEXT("Hello DLL~"), TEXT("Title"), MB_OK);
}

编写好之后 F7 生成(visual studio 2008以上),到项目的 Debug 目录下找到生成的 DLL 一般是 【项目名.DLL】

调用 DLL

再新建一个普通的【空项目】就可以了


#include <stdio.h> 
#include <windows.h> 

// 指向函数的指针类型
typedef void (*fun_pointer)(void);

// main
VOID main(VOID) 
{ 
	HINSTANCE hDLL; 
	BOOL flagGetFun = FALSE; 
	fun_pointer p;

	// 加载 Dll
	hDLL = LoadLibrary(TEXT("DLLTEST.dll")); 

	// 判断是否加载成功
	if (hDLL != NULL) 
	{ 
		printf("模块加载成功n");

		// 获得指定导出函数的地址
		p = (fun_pointer) GetProcAddress(hDLL, "helloDLL"); 

		// 判断是否成功
		if (NULL != p) 
		{
			printf("函数获取成功,准备调用函数n");
			p(); // 成功则调用DLL中的函数
		}else
		{
			printf("函数获取失败!n");
			printf("error: %un", GetLastError()); 
		}
		// 释放DLL 
		if (!FreeLibrary(hDLL))
		{
			printf("DLL释放失败n");
			printf("error: %un", GetLastError()); 
		}		
	}else
	{
		printf("模块加载失败!n");
		printf("error: %un", GetLastError()); 
	}		

	system("pause");
}

编写好之后,点击生成,将开始的 DLL 文件拷贝到该项目的 Debug 目录(与exe同一个目录),接着双击执行即可。

调用DLL中的函数

源码下载

上一讲: Windows API 教程(五) 线程编程

下一讲: Windows API 教程(七) hook 监听

4 thoughts on “Windows API 教程(六) 动态链接库

  1. 博主快讲讲 #ifdef MYDLL_EXPORTS的意思是如果定义了MYDLL_EXPORTS就执行下面的#define MYDLL_API _declspec(dllexport),否则执行#define MYDLL_API _declspec(dllexport),但是前面没有定义MYDLL_EXPORTS,难道最终执行的是#define MYDLL_API _declspec(dllexport吗

  2. 博主你好,我编译dll.h的时候有个警报: warning C4273: “helloDll”: dll 链接不一致
    google了下找到解决方法了,
    加上
    #define MYDLL_EXPORTS
    这句就ok了,非常感谢博主写适合新手的文章!

    #define MYDLL_EXPORTS
    #ifdef MYDLL_EXPORTS
    #define MYDLL_API _declspec(dllexport)
    #else
    #define MYDLL_API _declspec(dllimport)
    #endif

    另外还有一个问题就是创建第二个空项目的时候容易搞错,应该指明是windo控制台程序【新手路过……】

  3. 建议在头文件中MYDLL_API void helloDLL(void);的前面加上extern “C”,即是extern “C” MYDLL_API void helloDLL(void);否则在vc++6.0中会导致 p=(fun_pointer) GetProcAddress(hDLL,”helloDLL”);返回值为空,也就是说在DLL中找不到helloDLL函数,因为不加 extern “C”的话,vc++6.0会按照c++语言进行编译,会把helloDLL的函数名改变掉,自然就找不到了

留下评论