有没有更好的方法在 C 中加载 dll?

新手上路,请多包涵

现在我做这样的事情,如果我最终有很多我想在我的 DLL 中引用的函数,这似乎很混乱。是否有更好、更简洁的方法来访问函数,而无需为每个函数定义创建 typedef,以便正确编译和加载函数。我的意思是函数定义已经在 .h 文件中,我不应该在加载函数后重新声明它们(或者我是吗?)有没有比使用 LoadLibary 更好的解决方案?如果有一种方法可以在 Visual Studio 2005 项目设置中执行相同的操作,我不一定需要该功能。


BHannan_Test_Class.h

 #include "stdafx.h"
#include <windows.h>

#ifndef BHANNAN_TEST_CLASS_H_
#define BHANNAN_TEST_CLASS_H_

extern "C" {

    // Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
    int __declspec (dllexport) Factorial(int n);

    // Returns true iff n is a prime number.
    bool __declspec (dllexport) IsPrime(int n);

}

#endif  // BHANNAN_TEST_CLASS_H_


BHannan_Test_Class.cpp

 #include "stdafx.h"
#include "BHannan_Test_Class.h"

// Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
int Factorial(int n) {
  int result = 1;
  for (int i = 1; i <= n; i++) {
    result *= i;
  }

  return result;
}

// Returns true iff n is a prime number.
bool IsPrime(int n) {
  // Trivial case 1: small numbers
  if (n <= 1) return false;

  // Trivial case 2: even numbers
  if (n % 2 == 0) return n == 2;

  // Now, we have that n is odd and n >= 3.

  // Try to divide n by every odd number i, starting from 3
  for (int i = 3; ; i += 2) {
    // We only have to try i up to the squre root of n
    if (i > n/i) break;

    // Now, we have i <= n/i < n.
    // If n is divisible by i, n is not prime.
    if (n % i == 0) return false;
  }

  // n has no integer factor in the range (1, n), and thus is prime.
  return true;
}


dll_test.cpp

 #include <BHannan_Test_Class.h>

typedef int (*FactorialPtr) (int);
FactorialPtr myFactorial=NULL;

// Tests factorial of negative numbers.
TEST(FactorialTest, Negative) {

    HMODULE myDLL = LoadLibrary("BHannan_Sample_DLL.dll");

    if(myDLL) {
        myFactorial = (FactorialPtr) GetProcAddress(myDLL,"Factorial");

        if(myFactorial)
        {
            EXPECT_EQ(1, myFactorial(-5));
            EXPECT_EQ(1, myFactorial(-1));
            EXPECT_TRUE(myFactorial(-10) > 0);
        }

        FreeLibrary(myDLL);
    }

}

原文由 Brian T Hannan 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 663
2 个回答

构建您的 .dll 后,获取附近的 .lib 文件并将您的测试应用程序与其链接。使用在 .h 中声明的函数

您需要在头文件中进行一些小的更改:

 #ifdef EXPORTS_API
  #define MY_API_EXPORT __declspec (dllexport)
#else
  #define MY_API_EXPORT __declspec (dllimport)
#endif

extern "C" {
    int MY_API_EXPORT Factorial(int n);

    // do the same for other functions
}

这样,在构建您的 dll 时,您在项目设置和功能中定义 EXPORTS_API 被导出,在客户端应用程序中,无需定义任何内容。

原文由 Dmitry 发布,翻译遵循 CC BY-SA 2.5 许可协议

在 Windows 世界中,(至少)有 4 种使用 DLL 的方法:

  1. 运行时动态链接(你现在在做什么)
  2. 加载时动态链接(使用 DLL 的“典型”方式)
  3. 延迟加载动态链接
  4. DLL 转发

我不必解释 _运行时动态链接_,因为您已经在这样做了。我现在选择不解释 _延迟负载动态链接_,而不仅仅是笼统地描述它是什么。延迟加载本质上与加载时动态链接相同,只是它是即时完成的,而不是在应用程序加载时完成的。这并不像您想象的那么有用或有益,它很难使用并且难以编写代码。所以我们不要去那里,至少现在是这样。 DLL 转发 比延迟加载更奇特——如此奇特,直到@mox 在评论中提到它,我才听说过它。我会让您阅读上面的链接以了解它,但只要说 DLL 转发就是当您调用一个 DLL 中的导出函数但该请求实际上被 转发 到不同 DLL 中的另一个函数时。

加载时动态链接

这就是我认为的 Vanilla DLL Linking

这就是大多数人在提到在他们的应用程序中使用 DLL 时所指的内容。您只需 #include DLL 的头文件并链接到 LIB 文件。无需 GetProcAddress() 或创建函数指针 typedef。简而言之,它的工作原理如下:

  1. 您通常会获得 3 个文件:一个带有运行时代码的 DLL、一个 LIB 文件和一个头文件。头文件只是一个头文件——它描述了 DLL 中您可以使用的所有工具。

  2. 您编写应用程序, #include 从 DLL 获取头文件并调用这些函数,就像在任何头文件中使用任何函数一样。编译器知道您使用的函数和对象的名称,因为它们位于 DLL 的头文件中。但它还不知道它们在内存中的位置。这就是LIB文件的来源……

  3. 您转到项目的链接器设置并添加“附加库依赖项”,指定 LIB 文件。 LIB 文件告诉链接器您从 H 文件中使用的函数和对象驻留在内存中的位置(显然是相对术语,而不是绝对术语)。

  4. 编译您的应用程序。如果您已正确设置所有内容,它应该可以编译、链接和运行。当您收到“未解决的外部引用”链接器错误时,通常是由于设置不正确。您可能没有指定 LIB 文件的正确路径,或者您需要包含更多 LIB 文件。

原文由 John Dibling 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题