从 DLL 动态加载函数

2021-12-17 00:00:00 dll winapi c++

我正在查看 .dll 文件,我了解它们的用法并且我正在尝试了解如何使用它们.

I'm having a little look at .dll files, I understand their usage and I'm trying to understand how to use them.

我创建了一个 .dll 文件,其中包含一个函数,该函数返回一个名为 funci() 的整数

I have created a .dll file that contains a function that returns an integer named funci()

使用此代码,我(认为)已将 .dll 文件导入到项目中(没有抱怨):

using this code, I (think) I've imported the .dll file into the project(there's no complaints):

#include <windows.h>
#include <iostream>

int main() {
  HINSTANCE hGetProcIDDLL = LoadLibrary("C:\Documents and Settings\User\Desktop  \fgfdg\dgdg\test.dll");

  if (hGetProcIDDLL == NULL) {
    std::cout << "cannot locate the .dll file" << std::endl;
  } else {
    std::cout << "it has been called" << std::endl;
    return -1;
  }

  int a = funci();

  return a;
}

# funci function 

int funci() {
  return 40;
}

但是,当我尝试编译这个我认为已导入 .dll 的 .cpp 文件时,出现以下错误:

However when I try to compile this .cpp file that I think has imported the .dll I have the following error:

C:Documents and SettingsUserDesktopfgfdgonemore.cpp||In function 'int main()':|
C:Documents and SettingsUserDesktopfgfdgonemore.cpp|16|error: 'funci' was not     declared in this scope|
||=== Build finished: 1 errors, 0 warnings ===|

我知道 .dll 与头文件不同,所以我知道我不能导入这样的函数,但这是我能想出的最好的方法来证明我已经尝试过了.

I know a .dll is different from a header file so I know I can't import a function like this but it's the best I could come up with to show that I've tried.

我的问题是,如何使用 hGetProcIDDLL 指针访问 .dll 中的函数.

My question is, how can I use the hGetProcIDDLL pointer to access the function within the .dll.

我希望这个问题是有道理的,而且我不会再挑错树了.

I hope this question makes sense and I'm not barking up some wrong tree yet again.

推荐答案

LoadLibrary 没有按照您的想法执行.它将 DLL 加载到当前进程的内存中,但它不会神奇地导入其中定义的函数!这是不可能的,因为函数调用是在编译时由链接器解析的,而 LoadLibrary 在运行时被调用(请记住,C++ 是一个 静态类型 语言).

LoadLibrary does not do what you think it does. It loads the DLL into the memory of the current process, but it does not magically import functions defined in it! This wouldn't be possible, as function calls are resolved by the linker at compile time while LoadLibrary is called at runtime (remember that C++ is a statically typed language).

您需要一个单独的 WinAPI 函数来获取动态加载函数的地址:GetProcAddress.

You need a separate WinAPI function to get the address of dynamically loaded functions: GetProcAddress.

示例

#include <windows.h>
#include <iostream>

/* Define a function pointer for our imported
 * function.
 * This reads as "introduce the new type f_funci as the type: 
 *                pointer to a function returning an int and 
 *                taking no arguments.
 *
 * Make sure to use matching calling convention (__cdecl, __stdcall, ...)
 * with the exported function. __stdcall is the convention used by the WinAPI
 */
typedef int (__stdcall *f_funci)();

int main()
{
  HINSTANCE hGetProcIDDLL = LoadLibrary("C:\Documents and Settings\User\Desktop\test.dll");

  if (!hGetProcIDDLL) {
    std::cout << "could not load the dynamic library" << std::endl;
    return EXIT_FAILURE;
  }

  // resolve function address here
  f_funci funci = (f_funci)GetProcAddress(hGetProcIDDLL, "funci");
  if (!funci) {
    std::cout << "could not locate the function" << std::endl;
    return EXIT_FAILURE;
  }

  std::cout << "funci() returned " << funci() << std::endl;

  return EXIT_SUCCESS;
}

此外,您应该导出DLL 中的函数正确.可以这样做:

Also, you should export your function from the DLL correctly. This can be done like this:

int __declspec(dllexport) __stdcall funci() {
   // ...
}

正如 Lundin 指出的那样,释放库的句柄 如果您不再需要它们.如果没有其他进程仍然持有同一个 DLL 的句柄,这将导致它被卸载.

As Lundin notes, it's good practice to free the handle to the library if you don't need them it longer. This will cause it to get unloaded if no other process still holds a handle to the same DLL.

相关文章