C ++: явная загрузка DLL: исключение первого шанса для функций, не являющихся «внешними C» - PullRequest
0 голосов
/ 31 мая 2010

У меня проблемы с импортом моих функций C ++. Если я объявлю их как функции C, я могу успешно импортировать их. При явной загрузке, если в какой-либо функции отсутствует внешний символ C, я получаю следующее исключение:

First-chance exception at 0x00000000 in cpp.exe: 0xC0000005: Access violation.

DLL.h:

extern "C" __declspec(dllimport) int addC(int a, int b);
__declspec(dllimport) int addCpp(int a, int b);

DLL.cpp:

#include "DLL.h"
int addC(int a, int b) {
    return a + b;
}
int addCpp(int a, int b) {
    return a + b;
}

main.cpp:

#include "..DLL/DLL.h"
#include <stdio.h>
#include <windows.h>

int main() {
    int a = 2;
    int b = 1;
    typedef int (*PFNaddC)(int,int);
    typedef int (*PFNaddCpp)(int,int);

    HMODULE hDLL = LoadLibrary(TEXT("../Debug/DLL.dll"));

    if (hDLL != NULL)
    {
        PFNaddC pfnAddC = (PFNaddC)GetProcAddress(hDLL, "addC");
        PFNaddCpp pfnAddCpp = (PFNaddCpp)GetProcAddress(hDLL, "addCpp");
        printf("a=%d, b=%d\n", a,b);
        printf("pfnAddC: %d\n", pfnAddC(a,b));
        printf("pfnAddCpp: %d\n", pfnAddCpp(a,b)); //EXCEPTION ON THIS LINE

    }
    getchar();
    return 0;
}

Как импортировать функции с ++ для динамической загрузки? Я обнаружил, что следующий код работает с неявной загрузкой, ссылаясь на * .lib, но я хотел бы узнать о динамической загрузке.

Спасибо всем заранее.

Обновление: bindump / export

1 00011109 ?addCpp@@YAHHH@Z = @ILT+260(?addCpp@@YAHHH@Z)
2 00011136 addC = @ILT+305(_addC)

Решение

  1. Создать структуру преобразования как найдено здесь
  2. Посмотрите на экспортировать и явно копировать Соглашение по присвоению имен в c ++.

    PFNaddCpp pfnAddCpp = (PFNaddCpp) GetProcAddress (hDLL, "? AddCpp @@ YAHHH @ Z");

Ответы [ 2 ]

1 голос
/ 31 мая 2010

Неизбежно, нарушение доступа к нулевому указателю связано с тем, что GetProcAddress() возвращает ноль при ошибке.

Проблема в том, что имена C ++ искажены компилятором, чтобы приспособиться к различным возможностям C ++ (пространства имен, классы и перегрузки, среди прочего). Итак, ваша функция addCpp() на самом деле не называется addCpp() в результирующей библиотеке. Когда вы объявляете функцию с extern "C", вы отказываетесь от перегрузки и возможности помещать функцию в пространство имен, но взамен вы получаете функцию, имя которой не искажено, и которую вы можете вызвать из кода C (который не ' ничего не знаю о калечащем имени.)

Один из способов обойти это - экспортировать функции, используя .def файл для переименования экспортируемых функций. Есть статья Явная ссылка на классы в DLL , в которой описывается, что для этого необходимо.

0 голосов
/ 31 мая 2010

Можно просто обернуть весь заголовочный файл в extern "C" следующим образом. Тогда вам не нужно беспокоиться о том, чтобы забыть extern "C" в одном из ваших объявлений.

#ifdef __cplusplus
extern "C" {
#endif

__declspec(dllimport) int addC(int a, int b);
__declspec(dllimport) int addCpp(int a, int b);

#ifdef __cplusplus
} /* extern "C" */
#endif

Вы по-прежнему можете использовать все функции C ++, к которым вы привыкли, в теле функций - эти функции по-прежнему являются функциями C ++ - у них просто есть ограничения на прототипы, чтобы сделать их совместимыми с кодом C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...