zoukankan      html  css  js  c++  java
  • C语言dll文件的说明以及生成、使用方法

      最近在搞一些小项目,由于要涉及到跟其它语言进行交互,动态链接库变成了不二的选择。为此也查阅了很多资料,将动态链接库的相关知识在此做一个整理。

      一、动态链接库概述

      动态链接库(Dynamic Link Library )是一种不可执行的二进制程序文件,它允许多个程序共享执行特殊任务所必需的代码和其他资源。Windows 中,DLL 多数情况下是带有 ".dll" 扩展名的文件,但也可能是 ".ocx"或其他扩展名;Linux系统中常常是 ".so" 的文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 文件中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。使用动态链接库可以更为容易地将更新应用于各个模块,而不会影响该程序的其他部分。是开发大型项目必不可少的部分。

      二、优缺点

      优点:(1)节省内存和代码重用:当多个程序使用同一个函数库时,DLL可以减少在磁盘和物理内存中加载代码的重复量,且有助于代码的重用。

         (2)模块化:DLL有助于促进模块式程序开发。模块化允许仅仅更改几个应用程序共享使用的一个DLL中的代码和数据而不需要更改应用程序自身。适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。这种模块化的基本形式允许如Microsoft Office、Microsoft Visual Studio、甚至windows自身这样大的应用程序使用较为紧凑的补丁和服务包。

           (3)扩展了应用程序的特性,使用dll文件可以使得应用程序能很方便的进行功能的扩展,很多程序的插件机制就是通过dll文件实现的。

         (4)可以用多种语言来编译和调用,由于各种语言都有自己独特的开发优势,在处理某类事务方面具有着独特的优势,所以在多种语言编程的过程中,可以利用dll文件作为桥梁,可以发挥多种语言的优点。

      缺点:DLL Hell:即DLL地狱,指几个应用程序在使用同一个共享的DLL库时发生版本冲突。

      究其原因,八个字:成也共用,败也共用。因为DLL Hell正是由于动态链接库可与其他程序共用函数、资源所导致。

      主要有两种情况

      设想这样一个场景:程序A会使用1.0版本的动态链接库X,则在程序A安装到系统时,会同时安装该1.0版本的动态链接库X。假设另一个程序B也会使用到动态链接库X,那么程序B直接复制到硬盘中即可正常运行,因为动态链接库已经存在于系统中。然而有一天,另一程序C也要使用动态链接库X,但是由于程序C开发的时间较晚,其需要较新版本---2.0版本的动态链接库X。则在程序C被安装到系统时,2.0版本的动态链接库X 也必须随之安装到系统中,此时系统中1.0版本的动态链接库将被2.0版本所取代(替换)。

      情况1:新版本的动态链接库不兼容旧版本。如,A何B需要X所提供的功能,在升级到2.0后,新版本的X竟然把此功能取消了(很难想象吧,呵呵但有时候就是如此....)。则此时虽然C能正常运行,但A和B均无法工作了。

      情况2:新版本的动态链接库兼容旧版本,但是存在一个bug。

      三、入口点

      就跟应用程序的main函数一样,dll文件也有入口函数,叫做DllMain(),它的原型是这样的:

     1 BOOL APIENTRY DllMain(
     2     HANDLE hModule,             // DLL模块的句柄
     3     DWORD ul_reason_for_call,   // 调用本函数的原因
     4     LPVOID lpReserved           // 保留
     5 ) {
     6     switch (ul_reason_for_call)
     7     {
     8         case DLL_PROCESS_ATTACH:
     9             //进程正在加载本DLL
    10         break;
    11         case DLL_THREAD_ATTACH:
    12             //一个线程被创建
    13         break;
    14         case DLL_THREAD_DETACH:
    15             //一个线程正常退出
    16         break;
    17         case DLL_PROCESS_DETACH:
    18             //进程正在卸载本DLL
    19         break;
    20     }
    21     return TRUE;            //返回TRUE,表示成功执行本函数
    22 }

      入口点函数只应执行简单的初始化任务,不应调用任何其他 DLL 加载函数或终止函数。例如,在入口点函数中,不应直接或间接调用 LoadLibrary 函数或LoadLibraryEx 函数。此外,不应在进程终止时调用 FreeLibrary函数。

      四、生成DLL文件

      下面来生成一个DLL文件,为方便起见,只定义一个简单函数。

      生成DLL文件需要用到两个文件,一个头文件,dll_add.h,和一个源文件,dll_add.c

      头文件内容:

    1 #ifndef _DLL_DEMO_H_
    2 #define _DLL_DEMO_H_
    3 #ifdef DLLDEMO_EXPORTS
    4 #define DLL_DEMO _declspec( dllexport )
    5 #else
    6 #define DLL_DEMO _declspec(dllimport)
    7 #endif
    8 extern "C" DLL_DEMO int Add(int a, int b);
    9 #endif

      源文件内容:

    1 #include "dll_demo.h"
    2 
    3 int Add(int a, int b)
    4 {
    5     return (a + b);
    6 }

      这里因为不需要对函数载入与卸载作特殊处理,所以可以不使用入口函数。

      使用的是vs2015,在debug模式或者release模式下调试后会在相应目录下生成dll文件,即可使用。

      五、调用DLL文件

      生成DLL自然是为了调用,调用DLL有两种方式。

      静态调用:使用.h+.lib+.dll

      

     1 #include <windows.h>
     2 #include <iostream>
     3 #include "DLL_DEMO.h"
     4 using namespace std;
     5 #pragma comment(lib, "DLL_DEMO.lib")
     6 
     7 extern "C" _declspec(dllimport) int Add(int a, int b);
     8 int main(int argc, char *argv[])
     9 {
    10     cout << Add(2, 3) << endl;
    11     system("pause");
    12     return 0;
    13 }

      把头文件和lib文件、dll文件都放到跟源文件同一目录下即可使用。当然,路径可以重新设置。

      动态调用:仅使用dll文件

     1 #include <windows.h>
     2 #include <iostream>
     3 using namespace std;
     4 typedef int (*AddFunc)(int a, int b);
     5 int main(int argc, char *argv[])
     6 {
     7       HMODULE hDll = LoadLibrary(L"DLL_DEMO.dll");
     8       if (hDll != NULL)
     9       {
    10             AddFunc add = (AddFunc)GetProcAddress(hDll, "Add");
    11             if (add != NULL)
    12             {
    13                   cout<<add(2, 3)<<endl;
    14             }
    15             FreeLibrary(hDll);
    16       }
    17 }

      在字符串前加一个L作用: unicode字符集是两个字节组成的。L告示编译器使用两个字节的 unicode 字符集。

      也可以使用dll来实现类和变量的共享,还可以实现内存共享,因为研究不多,所以这里暂不介绍。

      

  • 相关阅读:
    链表--判断一个链表是否为回文结构
    矩阵--“之”字形打印矩阵
    二叉树——平衡二叉树,二叉搜索树,完全二叉树
    链表--反转单向和双向链表
    codeforces 490C. Hacking Cypher 解题报告
    codeforces 490B.Queue 解题报告
    BestCoder19 1001.Alexandra and Prime Numbers(hdu 5108) 解题报告
    codeforces 488A. Giga Tower 解题报告
    codeforces 489C.Given Length and Sum of Digits... 解题报告
    codeforces 489B. BerSU Ball 解题报告
  • 原文地址:https://www.cnblogs.com/mfrank/p/6166254.html
Copyright © 2011-2022 走看看