win32day11-windows的库/静态库/动态库
Posted 吴英强
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了win32day11-windows的库/静态库/动态库相关的知识,希望对你有一定的参考价值。
Windows的库
由于项目的复杂程度,或者为了提高代码的
重用率等等,所以才引入了库程序。
库包含两种:
1 静态库:扩展名为LIB的文件,是不能被
加载的程序,可以理解为目标程序的
归档。
2 动态库:扩展名是DLL的文件,是可以被
应用程序加载的程序。
静态库
1 静态库的特点1.1 目标程序的归档
1.2 静态库的代码会被嵌入到程序当中。
1.3 程序执行时不需要静态库存在
2 C语言静态库
2.1 创建静态库
创建Win32静态库项目,使用*.C文件建立项目。
int C_Add( int nAdd1, int nAdd2 )
return ( nAdd1 + nAdd2 );
int C_Sub( int nSub1, int nSub2 )
return ( nSub1 - nSub2 );
2.2 添加静态库函数
2.3 在程序中将静态库导入
2.3.1 项目的Setting里设置, link选项
2.3.2 使用关键字 pragma
#pragma comment(lib, "../lib/winclib.lib")
2.4 使用静态库提供的函数
在C语言程序中,直接使用函数即可。
//导入静态库
#pragma comment(lib, "../lib/winclib.lib")
int main( )
int nAdd = 0;
int nSub = 0;
//使用C静态库的函数
nAdd = C_Add( 100, 100 );
nSub = C_Sub( 100, 100 );
printf( "ADD: %d\\n", nAdd );
printf( "SUB: %d\\n", nSub );
return 0;
3 C++语言的静态库
3.1 创建静态库
创建Win32静态库项目,使用*.CPP文件建立项目。
int CPP_Add( int nAdd1, int nAdd2 )
return ( nAdd1 + nAdd2 );
int CPP_Sub( int nSub1, int nSub2 )
return ( nSub1 - nSub2 );
3.2 添加静态库的函数
3.3 导入静态库
3.3.1 项目的Setting里设置
3.3.2 使用关键字 pragma
#pragma comment(lib, "../lib/wincpplib.lib")
3.4 定义库函数的原形
int CPP_Add( int nAdd1, int nAdd2 );
3.5 使用库函数
3.6 注意:
如果在CPP文件使用C语言静态库,定义的
静态库函数原形,需要增加 extern "C".
例如:
extern "C" int C_Add( int nAdd1, int nAdd2 );
// usecpplib.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
//导入C++的静态库
#pragma comment( lib, "../lib/wincpplib.lib" )
#pragma comment( lib, "../lib/winclib.lib" )
//定义函数原形
int CPP_Add( int nAdd1, int nAdd2 );
int CPP_Sub( int nSub1, int nSub2 );
extern "C"
int C_Add( int nAdd1, int nAdd2 );
int C_Sub( int nSub1, int nSub2 );
int main(int argc, char* argv[])
//使用C++库函数
int nAdd = CPP_Add( 100, 100 );
int nSub = CPP_Sub( 100, 100 );
printf( "ADD: %d\\n", nAdd );
printf( "SUB: %d\\n", nSub );
//使用C库函数
int nAdd2 = C_Add( 100, 100 );
int nSub2 = C_Sub( 100, 100 );
printf( "C_ADD: %d\\n", nAdd );
printf( "C_SUB: %d\\n", nSub );
return 0;
动态库
1 动态库的好处1.1 可以提供模块化的方式,方便协调开发。
1.2 对源代码保护
1.3 减小可执行文件的大小
1.4 提供代码的重用率
2 动态库的基本使用方法
2.1 动态库的创建
2.2 加载动态库
2.3 获取并使用库函数、变量或类
2.4 释放动态库
3 动态库的函数
3.1 创建
3.1.1 创建DLL的项目
使用Win32 DLL项目,创建DLL,添加相应的文件。
3.1.2 增加动态库函数
3.1.3 导出动态库函数
3.1.3.1 使用__declspec(dllexport)方式
在函数前增加这个关键字,例如
__declspec(dllexport) int Dll_Add()
3.1.3.2 增加 extern "C" 方式,即
extern "C" __declspec(dllexport)
以C语言方式导出函数
#include "windows.h"
#include "stdio.h"
BOOL WINAPI DllMain( HINSTANCE hinstDLL,
DWORD fdwReason, LPVOID lpvReserved )
printf( "DLL=%p, Reason=", hinstDLL );
switch( fdwReason )
case DLL_PROCESS_ATTACH:
printf( "DLL_PROCESS_ATTACH\\n" );
break;
case DLL_THREAD_ATTACH:
printf( "DLL_THREAD_ATTACH\\n" );
break;
case DLL_THREAD_DETACH:
printf( "DLL_THREAD_DETACH\\n" );
break;
case DLL_PROCESS_DETACH:
printf( "DLL_PROCESS_DETACH\\n" );
break;
return TRUE;
//C++导出方式
__declspec(dllexport) int Dll_Add( int nAdd1, int nAdd2 )
return ( nAdd1 + nAdd2 );
//C的导出方式
extern "C" __declspec(dllexport) int Dll_Sub( int nSub1, int nSub2 )
return ( nSub1 - nSub2 );
//DEF的导出方式
int Dll_Mul( int nMul1, int nMul2 )
return ( nMul1 * nMul2 );
3.1.3.3 使用DEF文件导出
增加扩展名为DEF的文件到项目中.
在DEF文件中添加导出定义.
LIBRARY dllfunc.dll //导出库
EXPORTS //导出表
Dll_Mul @1 //导出函数
Dll_Div @2
LIBRARY dllfunc.dll
EXPORTS
Dll_Mul @1
3.2 使用
3.2.1 隐式链接
3.2.1.1 导入LIB
项目的Setting或者使用#pragma导入,例如:
#pragma comment( lib, "../lib/dllfunc.lib")
3.2.1.2 定义函数原形
声明一个和导出函数一致的函数定义.
如果DLL采用extern "C"导出函数,
需要定义extern "C"方式函数原形
3.2.1.3 使用函数
直接函数即可
3.2.1.4 应用程序查找DLL的路径
1) 查找当前应用程序的目录.
2) 当前的工作目录
3) 查找Windows System32的目录
4) 查找Windows System的目录
5) 查找Windows目录
6) 查找环境变量PATH指定路径
// CallDllFunc.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
//导入DLL的Lib文件
#pragma comment( lib, "../lib/dllfunc.lib")
//定义函数原形
int Dll_Add( int nAdd1, int nAdd2 );
extern "C" int Dll_Sub( int nSub1, int nSub2 );
int Dll_Mul( int nMul1, int nMul2 );
int main(int argc, char* argv[])
// 使用函数
int nAdd = Dll_Add( 100, 100 );
int nSub = Dll_Sub( 100, 100 );
int nMul = Dll_Mul( 100, 100 );
printf("Dll_Add: %d\\n", nAdd );
printf("Dll_Sub: %d\\n", nSub );
printf("Dll_Mul: %d\\n", nMul );
return 0;
3.2.2 显示链接
3.2.2.1 加载动态库
HINSTANCE LoadLibrary(
LPCTSTR lpLibFileName );//DLL的路径
返回加载好DLL的句柄
3.2.2.2 定义函数原形对应的函数指针
3.2.2.3 获取函数地址
FARPROC GetProcAddress(
HMODULE hModule,//DLL的句柄
LPCSTR lpProcName );//函数的名称
返回对应函数地址
注意:
1 对于__declspec(dllexport)导出的函数,
由于函数名称发生变化,所以无法使用
函数名称获取对应的函数地址,所以
尽量采用隐式链接的方式.
2 extern "C"或DEF方式导出的函数,
可以正常的使用函数名称获取函数地址.
3.2.2.4 使用函数
3.2.2.5 释放动态库
FreeLibrary
// InvokeDllFunc.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
typedef int ( * DLL_ADD )( int nAdd1, int nAdd2 );
typedef int ( * DLL_SUB )( int nSub1, int nSub2 );
typedef int ( * DLL_MUL )( int nMul1, int nMul2 );
void UseDll( )
//加载动态库
HMODULE hDll = (HMODULE)
LoadLibrary( "dllfunc.dll" );
if( hDll == NULL )
printf( "Load Failed\\n");
return;
printf( "DLL Handle: %p\\n", hDll );
//定义函数指针
DLL_ADD Dll_Add = NULL;
DLL_SUB Dll_Sub = NULL;
DLL_MUL Dll_Mul = NULL;
//获取函数地址
Dll_Add = ( DLL_ADD )
GetProcAddress( hDll, "Dll_Add" );
if( NULL == Dll_Add )
printf( "Get Dll_Add Failed\\n");
printf( "Dll_Add: %p\\n", Dll_Add );
Dll_Sub = ( DLL_SUB )
GetProcAddress( hDll, "Dll_Sub" );
if( NULL == Dll_Sub )
printf( "Get Dll_Sub Failed\\n");
printf( "Dll_Sub: %p\\n", Dll_Sub );
Dll_Mul = ( DLL_MUL )
GetProcAddress( hDll, "Dll_Mul" );
if( NULL == Dll_Mul )
printf( "Get Dll_Mul Failed\\n");
printf( "Dll_Mul: %p\\n", Dll_Mul );
//使用函数
int nSub = Dll_Sub( 100, 100 );
int nMul = Dll_Mul( 100, 100 );
printf( "Dll_Sub: %d\\n", nSub );
printf( "Dll_Mul: %d\\n", nMul );
//释放动态库
FreeLibrary( hDll );
int main(int argc, char* argv[])
UseDll( );
return 0;
4 动态库的变量
4.1 定义全局变量
4.2 导出全局变量
4.2.1 __declspec(dllexport)导出
__declspec(dllexport) int g_nValue1 = 100;
4.2.2 DEF文件导出
int g_nValue1 = 100;
在DEF文件的导出列表中增加
g_nValue1 @1 DATA
4.3 导入LIB文件
4.4 定义导入变量
需要使用__declspec(dllimport)定义变量.
extern __declspec(dllimport) int g_nValue1;
4.5 使用变量
// usevalue.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
//导入LIB
#pragma comment( lib, "../lib/dllvalue.lib")
//定义DLL导入变量
extern __declspec(dllimport) int g_nValue1;
extern __declspec(dllimport) int g_nValue2;
int main(int argc, char* argv[])
printf("g_nValue1 = %d\\n", g_nValue1 );
printf("g_nValue2 = %d\\n", g_nValue2 );
return 0;
5 动态库的类
5.1 创建动态库并定义类
5.2 从DLL中导出类
在类名称前增加__declspec(dllexport)定义.
class __declspec(dllexport) CMath
... ;
5.3 使用时导入LIB文件
5.4 导入类
在类名称前增加__declspec(dllimport)定义.
class __declspec(dllimport) CMath
... ;
5.5 使用类
5.6 关于类的导入和导出
1) 定义一个宏,例如:
#ifdef _DLLCLASS_DLL_
#define DLLCLASS_EXT __declspec(dllexport)
#else
#define DLLCLASS_EXT __declspec(dllimport)
#endif //_DLLCLASS_DLL_
2) 根据编译项目,修改_DLLCLASS_DLL_宏声明
对于导出类,需要定义_DLLCLASS_DLL_,
否则不需要定义 _DLLCLASS_DLL_ 宏
3) 类的定义为
class DLLCLASS_EXT CMath
... ;
#ifndef _MATH_H_
#define _MATH_H_
//定义类导入导出宏
#ifdef _DLLCLASS_DLL_
#define DLLCLASS_EXT __declspec(dllexport)
#else
#define DLLCLASS_EXT __declspec(dllimport)
#endif //_DLLCLASS_DLL_
//增加类的导入导出宏
class DLLCLASS_EXT CMath
public:
int Add( int nAdd1, int nAdd2 );
int Sub( int nSub1, int nSub2 );
;
#endif //_MATH_H_
#include "math.h"
int CMath::Add( int nAdd1, int nAdd2 )
return ( nAdd1 + nAdd2 );
int CMath::Sub( int nSub1, int nSub2 )
return ( nSub1 - nSub2 );
// useclass.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
//导入DLL的LIB文件
#pragma comment( lib, "../lib/dllclass.lib")
//需要类的导入方式的声明
#include "../DllClass/math.h"
int main(int argc, char* argv[])
//使用DLL中的类
CMath math;
int nAdd = math.Add( 100, 100 );
int nSub = math.Sub( 100, 100 );
printf("math.Add = %d\\n", nAdd );
printf("math.Sub = %d\\n", nSub );
return 0;
6 DllMain 函数
是DLL文件入口函数.当程序加载或者释放
动态库的时候,会自动调用这个函数.
BOOL WINAPI DllMain(
HINSTANCE hinstDLL,//DLL的句柄
DWORD fdwReason,//DLL被调用的原因
LPVOID lpvReserved ); //保留值
fdwReason -
DLL_PROCESS_ATTACH 进程加载
DLL_THREAD_ATTACH 线程加载
DLL_THREAD_DETACH 线程卸载
DLL_THREAD_DETACH 进程卸载
返回值表示是否加载成功.
以上是关于win32day11-windows的库/静态库/动态库的主要内容,如果未能解决你的问题,请参考以下文章