[Windows翻译]动态链接库 - DLL(动态链接库)第3部分:方案实例

92 阅读5分钟

原文地址:www.tenouk.com/ModuleCC1.h…

原文作者:www.tenouk.com/

发布时间:约2004年前后

本模块有哪些内容?

  1. 创建一个简单的动态链接库程序
  2. 使用加载时动态链接
  3. 使用运行时动态链接

我的训练时间: aa小时。在你开始之前,请阅读这里的一些说明。DLL的Windows MFC编程(GUI编程)可以在MFC GUI编程步骤教程中找到。

Win32编程技能。

  • 能够理解、构建和运行动态链接库程序。
  • 能够区分静态链接和动态链接。
  • 能够识别不同类型的动态链接库。
  • 能够创建DLL的导出和导入函数。

创建一个简单的动态链接库程序

下面快照演示如何创建和使用DLL。首先我们来看看如何创建DLL项目的步骤。

选择Win32控制台项目,把项目名称。

选择DLL单选按钮并勾选 "空项目"。

然后照常添加C++源文件。

复制并粘贴下面的源代码。构建即可,不要运行。稍后,我们要创建一个应用程序,在我们的DLL程序中使用mydll()函数。接下来我们就可以构建我们的DLL程序了。在这个例子中,我们构建的是Release版本。

下面的例子mysrcdll.cpp是创建一个简单的DLL程序mydllpro.dll所需要的源代码。文件mysrcdll.cpp包含一个简单的字符串打印函数,叫做mydll()。mydllpro.dll并没有定义一个入口点函数,因为它是与C运行时库链接在一起的,没有自己的初始化或清理功能要执行。

// Project name: mydllpro, File name: mysrcdll.cpp, generating mydllpro.dll, mydllpro.lib...
// The mydll function writes a null-terminated string to
// the standard output device...
// The export mechanism used here is the __declspec(export)
// method supported by Microsoft Visual Studio, but any

// other export method supported by your development
// environment may be substituted.
// For WinXp, don't forget to add
// Advapi32.lib library if needed...
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define EOF (-1)
#ifdef __cplusplus    // If used by C++ code,
extern "C" {          // we need to export the C interface
#endif

__declspec(dllexport) int mydll(LPTSTR lpszMsg)
{
    DWORD cchWritten;
    HANDLE hStdout;
    BOOL fRet;

       printf("-This is mydll.dll file lol!-\n");
       // Get a handle to the standard output device.
       hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
       if (INVALID_HANDLE_VALUE == hStdout)
       {
              // failed to get the handle, give some message, get error code, just exit...
              printf("GetStdHandle(), invalid handle, error: GetLastError().\n");
              return EOF;
       }
       else
              printf("GetStdHandle(), standard handle is OK.\n");
    // Write a null-terminated string to the standard output device.
    while (*lpszMsg != '\0')
    {
        fRet = WriteFile(hStdout, lpszMsg, 1, &cchWritten, NULL);
        if ((fRet == FALSE) || (cchWritten != 1))
            // If something wrong just exit or provide meaningful message/error code...
            return EOF;
            // else, write more...
           lpszMsg++;
    }
       printf("\n");
    return 1;
}
#ifdef __cplusplus
}
#endif

设置发布版本。

或者使用配置管理器...

好了,最后让建立程序。然后,验证一下准备使用的DLL文件(mydllpro.dll)的创建。注意,mydllpro.lib文件将用于隐式链接(加载)。

使用加载时动态链接

创建了一个DLL之后,就可以在应用程序中使用它了。下面的文件mydllloadtime.cpp是一个空的Win32控制台应用程序的源代码,它使用从mydll.dll导出的mydll()函数。请注意,我们之前创建的DLL程序中没有任何用户定义的头文件。

// File: mydllloadtime.cpp
// A simple program that uses mydll() from mydllpro.dll.
// For WinXp, don't forget to add
#define _WIN32_WINNT 0x0501
#include <windows.h>

// call to a function in the mydllpro.dll
__declspec(dllimport) int mydll(LPTSTR);
// Another form: int mydll(LPTSTR);

int main()
{
    int Ret = 1;
    Ret = mydll("This message was printed using the DLL function");
    return Ret;
}

因为mydllloadtime.cpp隐式调用DLL函数,所以应用程序的模块必须与导入的librarymydllpro.lib链接。在本例中,mydllpro.lib和mydllpro.dll被复制到项目目录下。

不幸的是,尽管已经遵循了所有必要的步骤,但当调用mydll()时,这个程序失败了。错误如下所示。

        ...
        ...
        Loaded kernel32.lib(KERNEL32.dll)
      Found __NULL_IMPORT_DESCRIPTOR
        Referenced in kernel32.lib(KERNEL32.dll)
        Loaded kernel32.lib(KERNEL32.dll)
      Found KERNEL32_NULL_THUNK_DATA
        Referenced in kernel32.lib(KERNEL32.dll)
...
...
testdll.obj : error LNK2019: unresolved external symbol "int __cdecl mydll(char *)" (?mydll@@YAHPAD@Z) referenced in function _main
Release/mydlltest.exe : fatal error LNK1120: 1 unresolved externals

从构建输出来看,库文件已经被搜索,但没有被加载/处理。Tenouk没有在Visual C++编译器上尝试这个例子。让我们尝试使用同样的代码来实现Run-Time Dynamic Linking。

使用Run-Time Dynamic Linking

你可以在加载时和运行时动态链接中使用同一个DLL。下面的源代码产生了与上一节中加载时示例相同的输出。程序使用LoadLibrary()函数来获取mydll.dll的句柄。如果LoadLibrary()成功,程序在GetProcAddress()函数中使用返回的句柄来获取DLL的mydll()函数的地址。

调用DLL函数后,程序调用FreeLibrary()函数来卸载DLL。下面的例子说明了运行时和加载时动态链接之间的重要区别。如果themydll.dll文件不可用,使用加载时动态链接的应用程序就会简单地终止。然而,运行时动态链接的例子可以对错误做出响应。

这个项目是一个空的控制台模式的应用程序。将mydllpro.dll复制到项目目录或系统目录或前面提到的任何其他目录序列中。在本例中,mydllpro.dll已被复制到项目目录下。

// File:  testmydllruntime.cpp
// Using Run-Time Dynamic Linking
// A simple program that uses LoadLibrary() and
// GetProcAddress() to access mydll() in mydllpro.dll.
// For WinXp, don't forget to add
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <windows.h>

typedefvoid (*MYPROC)(LPTSTR);

int main()
{
    HINSTANCE hinstLib;
    MYPROC ProcAdd;
    BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
   // Get a handle to our DLL module created in the previous example.
    hinstLib = LoadLibrary("mydllpro");
   // If the handle is valid, try to get the function address.
   if (hinstLib != NULL)
    {
        printf("The dll handle is valid...\n");
        ProzAdd = (MYPROC) GetProcAddress(hinstLib, "mydll");
       // If the function address is valid, call the function.
       if (ProcAdd != NULL)
        {
printf("The function address is valid...\n\n");
fRunTimeLinkSuccess = TRUE;
// Pass some text, mydll() will display it on the standard output...
(ProcAdd) ("\nThis message is via DLL function...\n");
        }
      else
              printf("\nThe function address is NOT valid, error: %d.\n", GetLastError());
// Free the DLL module.
fFreeResult = FreeLibrary(hinstLib);
       if (fFreeResult != 0)
               printf("FreeLibrary() is OK.\n");
       else
               printf("FreeLibrary() is not OK, error: %d.\n", GetLastError());
    }
   else
       printf("The dll handle is not valid, error: %d.\n", GetLastError());
   // If unable to call the DLL function, use an alternative.
   if (!fRunTimeLinkSuccess)
        printf("This message via alternative method...\n");
   return 0;
}

一个示例输出。

好了,它工作了! 该程序使用运行时动态链接;在创建该程序时,你不应该像我们的Load-Time动态链接示例那样与导入库链接。让我们继续看更多的故事。

进一步的阅读和挖掘

  1. Microsoft Visual C++,在线MSDN。

  2. 结构、枚举、联合和typedef故事可以参考C/C++结构、枚举、联合和typedef

  3. 多字节、Unicode字符和本地化请参考Locale、宽字符和Unicode(Story)和Windows用户与组编程教程(Implementation)。

  4. Windows数据类型是Windows数据类型

  5. 查看Amazon.com上最畅销的C / C++和Windows书籍


通过www.DeepL.com/Translator(免费版)翻译