Не удается получить доступ к переменной в C++ DLL из приложения C
Я застрял на исправление в устаревшем приложении Visual C++ 6. В исходный код C++ DLL я положил
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
что приводит к тому, что MyNewVariable отображается (приятно недекорированный) в таблице экспорта (как показано в dumpbin /exports blah.dll). Однако я не могу понять, как объявить переменную, чтобы я мог получить к ней доступ в исходном файле на языке C. Я пробовал разные вещи, в том числе
_declspec(dllimport) char* MyNewVariable;
но это просто дает мне ошибку компоновщика:
неразрешенный внешний символ "__declspec(dllimport) char * MyNewVariable" (__imp_?MyNewVariable@@3PADA)
extern "C" _declspec(dllimport) char* MyNewVariable;
как подсказал Тони (и, как я уже пытался раньше), приводит к другому ожидаемому украшению, но все еще не удалил его:
неразрешенный внешний символ __imp__MyNewVariable
Как мне написать объявление, чтобы переменная C++ DLL была доступна из приложения C?
Ответ
Как определено botismarius и другими (большое спасибо всем), мне нужно было связаться с DLL-библиотекой.lib. Чтобы предотвратить искажение имени, мне нужно было объявить его (в исходном коде C) без декораторов, а это значит, что мне нужно было использовать файл.lib.
7 ответов
Вы должны ссылаться на библиотеку, сгенерированную после компиляции DLL. В настройках компоновщика проекта необходимо добавить .lib
файл. И да, вы должны также объявить переменную как:
extern "C" { declspec(dllimport) char MyNewVariable; }
extern "C" - это то, как вы удаляете украшение - оно должно работать так:
extern "C" declspec (dllimport) char MyNewVariable;
или если вы хотите заголовок, который может использоваться C++ или C (с ключом /TC)
#ifdef __cplusplus
extern "C" {
#endif
declspec(dllimport) char MyNewVariable;
#ifdef __cplusplus
}
#endif
И, конечно, связь с библиотекой импорта, сгенерированной dll, выполняющей экспорт.
Я не уверен, кто снизил botismarius, потому что он прав. Причина в том, что.lib генерирует библиотеку импорта, которая позволяет просто объявить внешнюю переменную / функцию с помощью __declspec(dllimport)
и просто используй это. Библиотека импорта просто автоматизирует необходимые LoadLibrary()
а также GetProcAddress()
звонки. Без этого вам нужно вызвать их вручную.
@Graeme: Ты тоже в этом прав. Я думаю, что компилятор "C", который использует OP, не поддерживает стандарт C99, а компилирует как C++, таким образом искажая имена. Настоящий компилятор C не понимает часть "C" extern "C"
ключевое слово.
Они оба правы. Тот факт, что сообщение об ошибке описывает __imp_?MyNewVariable@@3PADA
означает, что он ищет декорированное имя, поэтому необходим внешний символ "C". Однако связывание с библиотекой импорта также необходимо, иначе вы просто получите другую ошибку ссылки.
В исходном коде dll у вас должна быть эта реализация, чтобы файл.lib экспортировал символ:
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
Клиент c должен использовать заголовок с этим объявлением, чтобы код клиента импортировал символ:
extern "C" _declspec(dllimport) char* MyNewVariable;
Этот заголовок вызовет ошибку компиляции, если # include-ed в исходном коде dll, поэтому он обычно помещается в заголовок экспорта, который используется только для экспортируемых функций и только клиентами.
Если вам нужно, вы также можете создать "универсальный" заголовок, который можно включить в любом месте, которое выглядит следующим образом:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef dll_source_file
#define EXPORTED declspec(dllexport)
#else
#define EXPORTED declspec(dllimport)
#endif dll_source_file
#ifdef __cplusplus
}
#endif
EXPORTED char* MyNewVariable;
Тогда исходный код DLL выглядит так:
#define dll_source_code
#include "universal_header.h"
EXPORTED char* MyNewVariable = 0;
И клиент выглядит так:
#include "universal_header.h"
...
MyNewVariable = "Hello, world";
Если вы делаете это много, монстр #ifdef наверху может перейти в export_magic.h, а universal_header.h становится:
#include "export_magic.h"
EXPORTED char *MyNewVariable;
Я никогда не использовал _declspec(dllimport), когда программировал в Windows. Вы должны быть в состоянии просто объявить
extern "C" char* MyNewVariable;
и ссылка на.libb, созданный при компиляции DLL.