本文介绍一点关于DLL的基础知识,如果你是系统编程的高手就不要看了。
先介绍些DLL的基础知识。DLL(Dynamic Link Library:动态链接库)其实这个东西就是把一些经常要用的代码块编译完后放在磁盘上,当有应用程序需要其中的功能时,就把DLL文件映射到自己的进程空间中然后根据DLL中的输出符号来加载其中的功能代码,完成一定的功能。这就有点像C标准函数库。
这样做的好处可用有以下几点。
1.节省了系统资源。
2.一次编译,多个进程可用多次调用。
3.就是一个应用程序你可以用C++实现,但C++实现的程序却可用调用其他语言写的DLL文件。
下面介绍一下具体的DLL的编写和调用。
1.DLL的编写其实很我们正常的应用的程序的编写基本上是差不多的。
比如有一个功能函数是
我们可用把它写入正常的应用程序,也可用把它直接的写如DLL文件中。
2.DLL的调用,调用DLL文件有两种方法一种是显式的加载和隐式的加载。
下面先来看看隐示的加载DLL。
(需要两个文件一个DLL.DLL,另一个是install.exe)
我们先来建立一个名为mydll的DLL工程,我用的是VC 6.0。
新件工程->WIN32 Dynamic Link Library。不要选择MFC的DLL工程。
然后选择AN EMPTY DLL PROJECT,接下来一路OK。
这样我们就建立了一个空的DLL工程了。
接下在其中建立mydll.dll和mydll.h文件。
写下如下代码:
编译这个工程,就可用得到DLL.DLL文件了。
然后建立一个明为“install”的控制台工程,在其中建立install.cpp和install.h两个文件。
写入如下代码:
然后把mydll.dll和install.exe放在一起就可以,运行install.exe就可以看到调用DLL的函数的效果。
顺便说一下隐式加载DLL的默认路径
1) 包含可执行映像文件的目录。
2) 进程的当前目录。
3) Wi n d o w s系统目录。
4) Wi n d o w s目录。
5) PAT H环境变量中列出的各个目录。
下面先来看看显式的加载DLL。
(需要如下两个文件in.exe和dl.dll)
建立一个名为dl的DLL工程,然后新建dl.cpp文件代码如下:
新建一个名为“in”控制台工程,然后建立一个 in.cpp
编译后得到in.exe文件
然后把得到的in.exe和dl.dll文件放在同一目录下。运行in.exe就可用看到显式加载DLL的效果。
本问只涉及到了DLL编程的基础部分,一些深入的概念都没有具体的讲解. 如有错误还请通过E-MAIL告诉我。
以后会讲些DLL编程的高级部分。
先介绍些DLL的基础知识。DLL(Dynamic Link Library:动态链接库)其实这个东西就是把一些经常要用的代码块编译完后放在磁盘上,当有应用程序需要其中的功能时,就把DLL文件映射到自己的进程空间中然后根据DLL中的输出符号来加载其中的功能代码,完成一定的功能。这就有点像C标准函数库。
这样做的好处可用有以下几点。
1.节省了系统资源。
2.一次编译,多个进程可用多次调用。
3.就是一个应用程序你可以用C++实现,但C++实现的程序却可用调用其他语言写的DLL文件。
下面介绍一下具体的DLL的编写和调用。
1.DLL的编写其实很我们正常的应用的程序的编写基本上是差不多的。
比如有一个功能函数是
int Add(
int nLeft ,
int nRight)
{
g_nResult = nLeft + nRight;
return g_nResult;
}
{
g_nResult = nLeft + nRight;
return g_nResult;
}
我们可用把它写入正常的应用程序,也可用把它直接的写如DLL文件中。
2.DLL的调用,调用DLL文件有两种方法一种是显式的加载和隐式的加载。
下面先来看看隐示的加载DLL。
(需要两个文件一个DLL.DLL,另一个是install.exe)
我们先来建立一个名为mydll的DLL工程,我用的是VC 6.0。
新件工程->WIN32 Dynamic Link Library。不要选择MFC的DLL工程。
然后选择AN EMPTY DLL PROJECT,接下来一路OK。
这样我们就建立了一个空的DLL工程了。
接下在其中建立mydll.dll和mydll.h文件。
写下如下代码:
//
// mydll.h
// 首先必须创建一个头文件,它包含你想要从DLL输出的函数原型、结构和符号。
//
// DLL的所有源代码模块均包含该头文件,以帮助创建DLL。
#ifdef MYLIBAPI
#else
#define MYLIBAPI extern"C" __declspec(dllimport)
// 这个地方是为了,不改变DLL在被进行C++编译时改变各种符号
#endif
// 变量和函数的声明
MYLIBAPI int g_nResult;
MYLIBAPI int Add( int nLeft, int nRight);
// ---------------------------the end-------------------------
//
// mydll.cpp
//
#include <windows.h>
#include "mydll.h"
#define MYLIBAPI extern "C" __declspec(dllexport)
// 函数和变量的具体定义
int g_nResult;
int Add( int nLeft , int nRight)
{
g_nResult = nLeft + nRight;
return g_nResult;
}
// -----------------------the end---------------------------------
// mydll.h
// 首先必须创建一个头文件,它包含你想要从DLL输出的函数原型、结构和符号。
//
// DLL的所有源代码模块均包含该头文件,以帮助创建DLL。
#ifdef MYLIBAPI
#else
#define MYLIBAPI extern"C" __declspec(dllimport)
// 这个地方是为了,不改变DLL在被进行C++编译时改变各种符号
#endif
// 变量和函数的声明
MYLIBAPI int g_nResult;
MYLIBAPI int Add( int nLeft, int nRight);
// ---------------------------the end-------------------------
//
// mydll.cpp
//
#include <windows.h>
#include "mydll.h"
#define MYLIBAPI extern "C" __declspec(dllexport)
// 函数和变量的具体定义
int g_nResult;
int Add( int nLeft , int nRight)
{
g_nResult = nLeft + nRight;
return g_nResult;
}
// -----------------------the end---------------------------------
编译这个工程,就可用得到DLL.DLL文件了。
然后建立一个明为“install”的控制台工程,在其中建立install.cpp和install.h两个文件。
写入如下代码:
//
// install.h
//
// 其实这个文件和前面的DLL工程里面的mydll.h文件的是一样的
#ifdef MYLIBAPI
#else
#define MYLIBAPI extern"C" __declspec(dllimport)
// 这个地方是为了,不改变DLL在被进行C++编译时改变各种符号
#endif
// 变量和函数的声明
MYLIBAPI int g_nResult;
MYLIBAPI int Add( int nLeft, int nRight);
// ---------------------------the end-------------------------
// install.h
//
// 其实这个文件和前面的DLL工程里面的mydll.h文件的是一样的
#ifdef MYLIBAPI
#else
#define MYLIBAPI extern"C" __declspec(dllimport)
// 这个地方是为了,不改变DLL在被进行C++编译时改变各种符号
#endif
// 变量和函数的声明
MYLIBAPI int g_nResult;
MYLIBAPI int Add( int nLeft, int nRight);
// ---------------------------the end-------------------------
//
// install.cpp
//
// 这个文件是调用DLL内提供的函数的,应用程序。
//
// 这个调用方式是一中“隐式的调用”,这种方是从系统默认的几个路径去找,DLL文件。
// 缺少了程序的灵活性
//
#include <windows.h>
#include "install.h"
#pragma comment(lib,"mydll.lib")
// 这个LIB文件是编译DLL时产生的,在DLL工程的DEBUG文件夹里可用找到。
// mydll.lib里面是DLL文件对外输出的接口符号
int main()
{
int nLeft =10,nRight = 25;
TCHAR sz[100];
wsprintf(sz,TEXT("%d + %d = %d"),nLeft, nRight,Add(nLeft,nRight));
MessageBox (NULL,sz, TEXT("Last Result"),MB_OK);
wsprintf(sz,TEXT("GXTER:%d"), g_nResult);
MessageBox(NULL,sz,TEXT("GXTER"),MB_OK);
return 0;
}
// ------------------------the end--------------------
编译后就可用得到install.exe文件了。
// install.cpp
//
// 这个文件是调用DLL内提供的函数的,应用程序。
//
// 这个调用方式是一中“隐式的调用”,这种方是从系统默认的几个路径去找,DLL文件。
// 缺少了程序的灵活性
//
#include <windows.h>
#include "install.h"
#pragma comment(lib,"mydll.lib")
// 这个LIB文件是编译DLL时产生的,在DLL工程的DEBUG文件夹里可用找到。
// mydll.lib里面是DLL文件对外输出的接口符号
int main()
{
int nLeft =10,nRight = 25;
TCHAR sz[100];
wsprintf(sz,TEXT("%d + %d = %d"),nLeft, nRight,Add(nLeft,nRight));
MessageBox (NULL,sz, TEXT("Last Result"),MB_OK);
wsprintf(sz,TEXT("GXTER:%d"), g_nResult);
MessageBox(NULL,sz,TEXT("GXTER"),MB_OK);
return 0;
}
// ------------------------the end--------------------
然后把mydll.dll和install.exe放在一起就可以,运行install.exe就可以看到调用DLL的函数的效果。
顺便说一下隐式加载DLL的默认路径
1) 包含可执行映像文件的目录。
2) 进程的当前目录。
3) Wi n d o w s系统目录。
4) Wi n d o w s目录。
5) PAT H环境变量中列出的各个目录。
下面先来看看显式的加载DLL。
(需要如下两个文件in.exe和dl.dll)
建立一个名为dl的DLL工程,然后新建dl.cpp文件代码如下:
//
// dl.cpp
//
#include <windows.h>
#include <stdio.h>
int my_fun();
BOOL WINAPI DllMain(HINSTANCE histdll, //
DWORD fdw, // 系统调用/卸载时传递的消息
PVOID fim) // 传进DLLMAIN内的参数
{
switch(fdw)
{
case DLL_PROCESS_ATTACH: //当系统加载一个这个DLL文件时就会给出这消息
my_fun(); //然后会执行my_fun()函数
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return 1; //发现的一个问题就,这个返回值一定要为1,不能为0。
//不然就会出现一个问题,DLL被加载,但LoadLibrary(dll_path);
//这个函数会返回NULL。错误代码为1114(系统加载DLL文件失败)。
}
int my_fun()
{
printf("这里填加功能函数代码!");
return 0;
}
// ------------------------the end------------------------------
编译得到dl.dll文件
// dl.cpp
//
#include <windows.h>
#include <stdio.h>
int my_fun();
BOOL WINAPI DllMain(HINSTANCE histdll, //
DWORD fdw, // 系统调用/卸载时传递的消息
PVOID fim) // 传进DLLMAIN内的参数
{
switch(fdw)
{
case DLL_PROCESS_ATTACH: //当系统加载一个这个DLL文件时就会给出这消息
my_fun(); //然后会执行my_fun()函数
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return 1; //发现的一个问题就,这个返回值一定要为1,不能为0。
//不然就会出现一个问题,DLL被加载,但LoadLibrary(dll_path);
//这个函数会返回NULL。错误代码为1114(系统加载DLL文件失败)。
}
int my_fun()
{
printf("这里填加功能函数代码!");
return 0;
}
// ------------------------the end------------------------------
新建一个名为“in”控制台工程,然后建立一个 in.cpp
//
// in.cpp
//
#include <windows.h>
#include <stdio.h>
int main()
{
int error;
char exe_path[512] ="\0";
HINSTANCE hdll_lib;
char * dll_path ="dl.dll"; //dll文件的路径
//加载一个DLL
hdll_lib = LoadLibrary(dll_path);
if(hdll_lib == NULL)
{
error = GetLastError();
printf("error = %d",error);
}
//获得正在运行的程序的路径 + 文件名,前提是获得了这个程序的句柄
GetModuleFileName(hdll_lib,exe_path,sizeof(exe_path));
printf("\n%s\n",exe_path);
//显式的加载一个DLL的输出符号。
//GetProcAddress(hdll_lib , "my_fun");
//判断是否加载了某个DLL
hdll_lib = GetModuleHandle(dll_path);
if(hdll_lib == NULL)
{
printf("lksjdflkjsf");
hdll_lib = LoadLibrary(dll_path);
}
//卸载一个DLL
FreeLibrary(hdll_lib);
getchar();
return 0;
}
// --------------------------the end-------------------------
// in.cpp
//
#include <windows.h>
#include <stdio.h>
int main()
{
int error;
char exe_path[512] ="\0";
HINSTANCE hdll_lib;
char * dll_path ="dl.dll"; //dll文件的路径
//加载一个DLL
hdll_lib = LoadLibrary(dll_path);
if(hdll_lib == NULL)
{
error = GetLastError();
printf("error = %d",error);
}
//获得正在运行的程序的路径 + 文件名,前提是获得了这个程序的句柄
GetModuleFileName(hdll_lib,exe_path,sizeof(exe_path));
printf("\n%s\n",exe_path);
//显式的加载一个DLL的输出符号。
//GetProcAddress(hdll_lib , "my_fun");
//判断是否加载了某个DLL
hdll_lib = GetModuleHandle(dll_path);
if(hdll_lib == NULL)
{
printf("lksjdflkjsf");
hdll_lib = LoadLibrary(dll_path);
}
//卸载一个DLL
FreeLibrary(hdll_lib);
getchar();
return 0;
}
// --------------------------the end-------------------------
编译后得到in.exe文件
然后把得到的in.exe和dl.dll文件放在同一目录下。运行in.exe就可用看到显式加载DLL的效果。
本问只涉及到了DLL编程的基础部分,一些深入的概念都没有具体的讲解. 如有错误还请通过E-MAIL告诉我。
以后会讲些DLL编程的高级部分。