通常,我们在Windows上加载一个dll并调用标记为的函数__declspec(dllexport)
,但是我可以从dll调用已加载程序中实现的函数吗?
首先,这可以在Linux上完成,请检查我之前提出的问题。
我编写了一个测试程序对此进行测试: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中的函数?
PS在dll中添加注册表功能并 get_e
通过它的想法非常感谢,但在我的实际情况中不能考虑。
由于你正在为.dll使用后期绑定,因此你可能会对可执行文件中定义的功能执行相同的操作。只需GetProcAddress
使用此进程句柄(因为它已经在地址空间中)以相同的方式进行调用即可。这是一些(伪)代码:
auto proc = GetModuleHandle(nullptr);
auto get_e = reinterpret_cast<float (*) ()>(GetProcAddress(proc, "get_e"));
感谢您的帮助,它的工作原理。您可能会考虑更改为
auto get_e = reinterpret_cast <float(*)()>(GetProcAddress(proc, "get_e"));
,它将不再是伪代码...@ psionic12好点。
更好,更安全的设计是使调用程序
get_e()
在加载DLL之后将指针传递给DLL。IOW,让DLL导出一个程序可以调用的函数,以将指针传递给需要时允许DLL调用的函数。DLL不应绕过正在寻找的调用程序get_e()
或任何其他功能。@RemyLebeau这明显与asker的声明相矛盾(“在dll中添加注册表函数并通过它传递get_e的想法很感谢,但在我的实际情况中不能考虑。”)我也没有发现我的解决方案“不安全”。(在我看来)比传递指向该函数的指针更麻烦,但是OP可能有其原因。