【问题标题】:(How) can a dll call a function that is implemented in its loading program?(如何)dll 可以调用在其加载程序中实现的函数吗?
【发布时间】:2021-03-13 14:24:00
【问题描述】:

通常我们在windows上加载一个dll并调用它的函数,标记为__declspec(dllexport),但是我可以从dll调用一个在加载的程序中实现的函数吗?

首先说这可以在 Linux 上完成,查看我之前问过的question

我写了一个测试程序来测试这个: CMakeList.txt(对不起,我是 Windows 编程新手,不知道如何使用 Visual Studio):

cmake_minimum_required(VERSION 3.16)
project(untitled4)

set(CMAKE_CXX_STANDARD 17)

add_library(lib1 SHARED lib1.cpp)

add_executable(untitled4 main.cpp)

main.cpp

#include "iostream"
#include "windows.h"
extern "C" {
  // this is the function I want to get called from dll
__declspec(dllexport)
float get_e() {
  return 2.71;
}
}
int main() {
  auto *handler = LoadLibrary("lib1.dll");
  if (!handler) {
    std::cerr << ERROR_DELAY_LOAD_FAILED << std::endl;
    exit(1);
  }
  auto p = (float (*)()) GetProcAddress(handler, "get_pi");
  std::cout << p() << std::endl;
}

lib1.cpp:

#include "iostream"
extern "C" {
  // implemented in main.cpp
__declspec(dllimport)
float get_e();

__declspec(dllexport)
float get_pi() {
  std::cout << get_e() << std::endl; // comment this line will compile, just like the normal case
  return 3.14;
}
}

编译lib1时编译会失败:

NMAKE : fatal error U1077: '"C:\Program Files\JetBrains\CLion 2020.1.1\bin\cmake\win\bin\cmake.exe"' : return code '0xffffffff'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.27.29110\bin\HostX86\x64\nmake.exe"' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.27.29110\bin\HostX86\x64\nmake.exe"' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.27.29110\bin\HostX86\x64\nmake.exe"' : return code '0x2'
LINK Pass 1: command "C:\PROGRA~2\MICROS~2\2019\BUILDT~1\VC\Tools\MSVC\1427~1.291\bin\Hostx86\x64\link.exe /nologo @CMakeFiles\lib1.dir\objects1.rsp /out:lib1.dll /implib:lib1.lib /pdb:C:\Users\derwe\CLionProjects\untitled\cmake-build-debug\lib1.pdb /dll /version:0.0 /machine:x64 /debug /INCREMENTAL kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:CMakeFiles\lib1.dir/intermediate.manifest CMakeFiles\lib1.dir/manifest.res" failed (exit code 1120) with the following output:
   Creating library lib1.lib and object lib1.exp
lib1.cpp.obj : error LNK2019: unresolved external symbol __imp_get_e referenced in function get_pi
lib1.dll : fatal error LNK1120: 1 unresolved externals
Stop.

那么我可以在 Windows 上执行此操作吗?那就是从一个dll中调用main中的一个函数?

附:在 dll 中添加注册表函数并通过它传递 get_e 的想法是感谢,但在我的实际情况下无法考虑。

【问题讨论】:

    标签: c++ windows dll dllimport


    【解决方案1】:

    由于您对 .dll 使用后期绑定,因此您可以对可执行文件中定义的函数执行相同的操作。只需使用此进程句柄以相同的方式调用GetProcAddress(因为它已经在地址空间中)。这是一些(伪)代码:

    auto proc = GetModuleHandle(nullptr);
    auto get_e = reinterpret_cast<float (*) ()>(GetProcAddress(proc, "get_e"));
    

    【讨论】:

    • 感谢您的帮助,它有效。你可以考虑换成auto get_e = reinterpret_cast &lt;float(*)()&gt;(GetProcAddress(proc, "get_e"));,它就不再是伪代码了……
    • 更好和更安全的设计是让调用程序在加载 DLL 后将指向 get_e() 的指针传递给 DLL。 IOW,让 DLL 导出一个程序可以调用的函数,以传递指向允许 DLL 在需要时调用的函数的指针。 DLL 不应在调用程序中四处寻找get_e() 或任何其他函数。
    • @RemyLebeau 这与 asker 的陈述明显相矛盾(“在 dll 中添加注册表函数并通过它传递 get_e 的想法是谢谢,但在我的实际情况中不能考虑。”)我也没有找到我的解决方案“不安全”。这比将指针传递给函数更麻烦(在我看来),但 OP 可能有其原因。
    猜你喜欢
    • 2013-06-09
    • 1970-01-01
    • 2012-02-06
    • 1970-01-01
    • 1970-01-01
    • 2014-10-12
    • 2017-06-07
    • 1970-01-01
    • 2011-05-22
    相关资源
    最近更新 更多