65.9K
CodeProject 正在变化。 阅读更多。
Home

让 DLL 更易于构建和使用

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.63/5 (11投票s)

2004年3月9日

8分钟阅读

viewsIcon

165362

如何快速从现有类构建 DLL 文件以及如何轻松使用它。

引言

对于初学者甚至有经验的程序员来说,要弄清楚如何配置和使用 DLL 可能会很复杂。本文旨在介绍一种简单的构建 DLL 的方法,然后轻松地在项目中将其用于另一个项目,除了需要包含头文件之外,几乎不需要任何其他操作。您只需要一个已设计好并准备好成为 DLL 文件的类。尽管这可能是些新手级别的内容,但据信需要一些使用 MSVS 项目的经验。此外,经验丰富的开发人员可能会从中发现一些有用的细节。

背景

有些人可能很难在互联网上找到非常简单地构建 DLL 的有用方法。本文中的信息实际上是从本网站和其他网站上收集的有关构建 DLL 的信息,所以这并不是什么新鲜事(只是整合了他们的努力)。有几篇文章详细介绍了如何构建 DLL,并强调了 DLL 实际上是什么以及如何使用它的细节。我建议您先阅读这些文章,以找到更广泛的定义。

然而,对于新手“DLL 生成器”来说,似乎缺乏很多(或者说太复杂而难以理解)。您可能听说过有人说构建 DLL 很容易,但弄清楚这一切如何协同工作可能需要付出很多努力。有些文章似乎也没有强调目录位置的重要性。DLL、其库和头文件必须都位于一个可以找到的目录中,该目录可以是 Windows 目录,也可以是编译器可以找到的某个位置。否则,如果找不到一个或全部 DLL 文件,您可能会遇到令人沮丧的编译器问题,这通常会导致无法使用的情况。

使用代码

除了注释部分,没有任何代码附件。通过在您的 MSVS 环境中配合使用,应该很容易理解。您需要做的是:

  1. 准备一个需要成为 DLL 文件的类。
  2. 启动一个新的 DLL 项目
  3. 在您的“StdAfx.h”文件中插入 MACRO 定义。
  4. 在主“foo.h”文件中轻松包含 DLL 库。
  5. 添加一些项目预处理器 MACRO。
  6. 为“Post Builds”(构建后操作)创建批处理文件——将库、头文件和 DLL 文件适当地复制到可找到的目录(s)。

详细说明

  1. 假设您已经创建了类,因此此步骤将被跳过。
  2. 首先是简单部分。启动“Microsoft Visual Studio Visual C++”。选择“文件->新建”,然后会弹出创建对话框。在“项目”选项卡按钮下,选择“MFC 应用程序向导(DLL)”。输入项目名称和要使用的目录,然后单击“确定”。其余选项不是必需的,因此选择您在向导其余部分中想要执行的操作,然后单击“完成”。

    当您启动新项目后,通常会为您创建源代码和头文件。如果您已经拥有要构建的代码,这些文件实际上是不需要的。此步骤只需要项目预设的定义。建议您只删除向导创建的源代码和头文件,然后突出显示并删除。暂时不要编辑“StdAfx”文件,因为这些文件是必需的。

    此步骤的目的是简单地将您的类(“foo”)复制并粘贴到创建的头文件和源文件中。这是一个简单的概念,但如果您持怀疑态度,也可以选择将您的“foo”源文件和头文件添加到项目中,以便构建它。

    接下来您将开始编辑部分。您必须能够使构建正确地编译为 DLL 文件以供使用。DLL 文件使用导出和导入的组合。当这是构建项目时,您需要“导出”。当它被包含在另一个不使用源代码的项目中时,您需要“导入”。这可能是理解 DLL 的难点,因为它不一定为您实现,并且需要一些努力才能理解。顺便说一句,“resource.h”文件仅被包含对话框的 DLL 所需要。在这种情况下,您必须记住,您可能有多个“resource.h”文件,并且必须为每个“resource.h”文件包含完整的路径语句。本文将在以下示例中展示一种可能最好的方法(请记住,如果项目需要此资源文件,则必须手动将其添加到项目中,包括其完整路径)。

  3. 编辑“StdAfx.h”文件,并包含以下 MACROS 和头文件“resource.h”。
    StdAfx.h
    //
    // MSVS included headers, definitions, etc.
    //
    
    // Somewhere near the bottom
    //This is the project macro preprocessor definition 
    //you will be adding shortly.
    #ifdef DLL_EXPORTS
    //This is to be used for the class header file.
    #define DLL_BUILD_MACRO __declspec(dllexport)
    #else
    #define DLL_BUILD_MACRO __declspec(dllimport)
    #endif
    
    #ifndef _DLL_BUILD_ //Why do this? Is it necessary? Yes.
    #define _DLL_BUILD_ DLL_BUILD_MACRO
    #endif
    
    //make sure resources are included here, if desired, 
    //to prevent ambiguous
    //callings to different resource.h files.
    #include “resource.h”
    
    //
    // Rest of file
    //
    
    • 接下来,我们继续编辑 DLL 代码的主头文件。只需添加几行简单的代码即可支持准确的 DLL 构建和使用。
      foo.h
      #ifndef _FOO_H_
      #define _FOO_H_
      
      //
      // Miscellanous here
      //
      
      /*This part automatically includes any libraries when called.
      When this file is built within the DLL project, 
      it will not be called because
      of our preprocessor macro definition “_FOO_DLL_”.
      However, when this file is called from another project, 
      not part of this build,
      it appropriately chooses the correct library and 
      includes them for you.
      WHAT this means is that you will not have to 
      add the library to the project link settings
      for a project that requires this DLL. This helps to 
      avoid the tedious task of
      linking to several custom DLLs.
      
      Note there are two different libraries here and 
      probably not necessary but give
      you an idea of how to separate debug versions 
      from release versions.*/
      
      #ifndef _FOO_DLL_
      #ifdef _DEBUG
      //You will be building a debug program that 
      //uses this file, so in this case we
      //want the debug library.
      #pragma comment( lib, “food.lib” ) 
      #else
      //You will be building a release program that
      //uses this file, so in this case we
      //want the release library.
      #pragma comment( lib, “foo.lib” ) 
      #endif
      #endif
      #ifndef _DLL_BUILD_
      #define _DLL_BUILD_ //Makes sure there are no compiler errors.
      #endif
      
      class _DLL_BUILD_ foo
      private:
      //
      // Your members
      //
      public:
      //
      // Your functions
      //
      };
      
      #endif
    • 继续,编辑“foo.cpp”文件,并确保包含适当的头文件。
      foo.cpp
      
      #include “stdafx.h” //place first
      #include “foo.h”
      
      //
      //Your code
      //
      
    • 下一步要求您实际将 MACROS 添加到项目设置中。在菜单工具栏中,转到“项目->设置…”或按 Alt+F7。单击“C/C++”选项卡。在“预处理器定义:”下,在其他宏定义列表的末尾添加宏定义“_FOO_DLL_”和“DLL_EXPORTS”。确保使用逗号(“,”)分隔每个新 MACRO。务必为发布版本也执行此操作,因为您将不得不为每种构建类型重新执行这些后续步骤。请确保使用任何“调试信息”和/或“浏览信息”进行构建,如果您要构建调试版本并且以后想使用 MSVS 调试器来调试 DLL。
    • 接下来,您将准备最后一步。在同一对话框下转到“构建后步骤”选项卡。在“构建后命令(s):”下,单击一个空白区域并输入“Debug.bat”。对于发布版本,在左侧窗格中,在“设置:”组合框中选择“Win32 Release”。像以前一样在“构建后命令(s)”中输入,但不是“Debug.bat”,而是“Release.bat”。所有项目设置就完成了。
  4. 现在来构建批处理文件。创建一个空白文件。您将添加命令行代码,这些代码会将文件复制到可找到的目录。这里的重点是,如果您可能有很多 DLL,那么将所有必需的组件放在一个目录中会更容易。这比链接到多个目录要方便。以下是本文中使用的建议,您可能需要考虑添加其他选项:
    Debug.bat
    Copy “Debug\foo.lib” “c:\<libraries dir>\food.lib”
    REM copy the dll file to the windows system32 
    REM directory to make the DLL easily
    REM accessible.  Note that you will have to install or include the
    REM dll file in your distribution package for the program that uses it.
    Copy “Debug\foo.dll” “c:\%system dir%\system32”
    Copy “foo.h” “c:\<headers dir>”
    
    Release.bat
    Copy “Release\foo.lib” “c:\<libraries dir>”
    REM copy the dll file to the windows system32 directory 
    REM to make the DLL easily accessible.
    REM Note that you will have to install or include the dll 
    REM file in your distribution package.
    REM Unfortanetly this will overwrite any other DLL files 
    REM such as the Release/Debug version,
    REM so accurate update compilations are needed.  
    REM You will have to note this yourself
    REM before distributing to the public.
    Copy “Release\foo.dll” “c:\%system dir%\system32”
    Copy “foo.h” “c:\<headers dir>”

您已经完全完成了。前提是您已经预先测试了您的类,并考虑了您的库、头文件和 DLL 文件被复制到何处,您应该不会遇到任何问题。您的类应该成为一个 DLL 文件,可以轻松地在未来的项目中大量使用。您只需要知道,您只需要包含头文件,一切就都为您完成了。一切都为您尽可能轻松和简单。

注释

需要提醒的是,DLL 文件必须可访问。本文引用了使用“c:\windows\system32”目录。如果您以后想检索该 DLL 文件,并且必须在可能已经存在的大量 DLL 中找到它,这可能是一个坏主意。如果您以后决定更改项目名称并使用不同的名称构建,这也会很麻烦。在这种情况下,您将不得不找到旧的 DLL 文件并手动删除它,或者就让它在那里。

或者,您可以将 DLL 文件、库文件和头文件复制到将要使用它的项目目录中。但是,如果您决定在另一个项目中使用相同的 DLL,则必须返回并在“Debug.bat”和“Release.bat”文件中添加复制命令行,然后重新构建项目以复制它们。

另外请注意,在 MSVS 中,很容易为新的头文件目录添加自定义目录进行搜索,但遗憾的是不能为 DLL 目录添加。在菜单栏中转到“工具->选项”,然后在“目录”选项卡按钮下。在批处理文件中的“<libraries dir>”应包含在“Show directories for”(显示目录为)组合框中的“Library files”(库文件)下,而“<headers dir>”应包含在“Include files”(包含文件)下。有些 MACROS 在本文中可能看起来是重复的或未使用的。但是,编译器在构建时,需要这种类型的样式,既用于 DLL 项目,也用于使用该 DLL 的项目。如果您发现有些 MACROS 不需要,您可以自己删除。此代码的设计使其存在并且易于访问。测试表明,无论是 DLL 构建还是使用该 DLL 的项目构建,都需要这些类型的 MACRO 设置才能使用。也存在其他可能性和位置。

关注点

研究防火墙、UNIX 以及为什么邮件程序会在 Windows 中自动显示内容。

历史

  • 无需重新格式化。
© . All rights reserved.