Обычно мы загружаем dll в Windows и вызываем ее функции, помеченные как __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? То есть вызвать функцию в main из dll?

P.S. Идеи добавления функции реестра в dll и прохождения через нее get_e - это благодарность, но они не могут рассматриваться в моем реальном случае.

0
psionic12 1 Дек 2020 в 19:17

1 ответ

Лучший ответ

Поскольку вы используете позднее связывание для своей .dll, вы можете сделать то же самое для функции, определенной в исполняемом файле. Просто вызовите GetProcAddress таким же образом, используя этот дескриптор процесса (поскольку он уже находится в адресном пространстве). Вот какой-то (псевдокод):

auto proc = GetModuleHandle(nullptr);
auto get_e = reinterpret_cast<float (*) ()>(GetProcAddress(proc, "get_e"));
2
Remy Lebeau 1 Дек 2020 в 23:24