Не удается получить доступ к переменной в 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.


person Ian Horwill    schedule 11.09.2008    source источник


Ответы (7)


вы должны ссылаться на библиотеку, созданную после компиляции DLL. В параметрах компоновщика проекта необходимо добавить файл .lib. И да, вы также должны объявить переменную как:

extern "C" { declspec(dllimport) char MyNewVariable; }
person botismarius    schedule 11.09.2008

extern "C" - это то, как вы удаляете украшение - он должен работать, чтобы использовать:

extern «C» declspec (dllimport) char MyNewVariable;

или если вам нужен заголовок, который может использоваться C ++ или C (с переключателем / TC)

#ifdef __cplusplus
extern "C" {
#endif
declspec(dllimport) char MyNewVariable;
#ifdef __cplusplus
}
#endif

И, конечно же, ссылка на библиотеку импорта, сгенерированную dll, выполняющую экспорт.

person Tony Lee    schedule 11.09.2008

Я не уверен, кто обманул ботисмариуса, потому что он прав. Причина в том, что сгенерированный .lib - это библиотека импорта, которая позволяет просто объявить внешнюю переменную / функцию с помощью __declspec(dllimport) и просто использовать ее. Библиотека импорта просто автоматизирует необходимые вызовы LoadLibrary() и GetProcAddress(). Без него вам нужно вызывать их вручную.

person spoulson    schedule 11.09.2008

Они оба правы. Тот факт, что в сообщении об ошибке описывается __imp_?MyNewVariable@@3PADA, означает, что он ищет оформленное имя, поэтому необходимо внешнее "C". Однако связь с библиотекой импорта также необходима, иначе вы просто получите другую ошибку связи.

person Graeme Perrow    schedule 11.09.2008

@Graeme: Вы тоже правы. Я думаю, что компилятор "C", который использует OP, не обеспечивает соблюдение стандарта C99, а компилирует его как C ++, таким образом искажая имена. Настоящий компилятор C не поймет "C" часть ключевого слова extern "C".

person spoulson    schedule 11.09.2008
comment
Правда. Вы можете поместить внешнюю часть C в блок #ifdef __CPLUSPLUS, чтобы обойти это. - person Graeme Perrow; 11.09.2008

В исходном коде 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;
person Bart    schedule 11.09.2008

Я никогда не использовал _declspec (dllimport), когда программировал в Windows. Вы должны иметь возможность просто объявить

extern "C" char* MyNewVariable;

и ссылка на .libb, созданный при компиляции DLL.

person Community    schedule 11.09.2008