2011-12-28 6 views
2

Мне нужна помощь в доступе к глобальным функциям в DLL/основной программе. У меня есть базовый классиспользовать переменную статическую переменную/функцию через dlls

Base.h

#ifdef MAIN_DLL 
#define DECLSPEC __declspec(dllexport) 
#else 
#define DECLSPEC __declspec(dllimport) 
#endif 


class Base { 
private: 
    DECLSPEC static Filesystem * filesystem; 
    DECLSPEC static Logger * logger; 
    DECLSPEC static System * system; 

public: 

    static void setFilesystem(Filesystem * filesystem_); 
    static void setApplication(Application * application_); 
    static void setLogger(Logger * logger_); 
    static void setSystem(System * system_); 

    static Filesystem * fs() { return filesystem; } 
    static Logger * log() { return logger; } 
    static System * sys() { return system; } 

}; 

main.cpp (основное применение) (MAIN_DLL предопределен здесь)

Filesystem * Base::filesystem = 0; 
Logger * Base::logger = 0; 
System * Base::system = 0; 

Когда доступ из библиотеки DLL:

System * system = Base::sys(); 
if(system == 0) std::cout << "Error"; 

Thanks, Gasim

+1

Это может быть интересно для вас: http://stackoverflow.com/questions/4911994/sharing-a-global-static-variable-between-a-process-and-dll – marcinj

ответ

4

Это зависит от системы, но вы должны убедиться, что символы в DLL, содержащие определения функций-членов и статические данные элемента, правильно экспортируют символы и что их библиотека правильно импортирует их. В Linux это означает использование опции -E при связывании исполняемого файла (если символы определены в исполняемом файле); в Windows вы обычно должны использовать условно скомпилированные расширения компилятора, см. __declspec; Компиляторы Microsoft не поддерживают DLL в стандартном C++.

EDIT:

Вот пример, который работает на моей системе (VC 2010):

В Ач:

#ifndef A_h_20111228AYCcNClDUzvxOX7ua19Fb9y5 
#define A_h_20111228AYCcNClDUzvxOX7ua19Fb9y5 

#include <ostream> 

#ifdef DLL_A 
#define A_EXPORT __declspec(dllexport) 
#else 
#define A_EXPORT __declspec(dllimport) 
#endif 

class A_EXPORT InA 
{ 
    static std::ostream* ourDest; 
public: 
    static void setDest(std::ostream& dest); 
    static std::ostream* getStream() { return ourDest; } 
}; 
#endif 

В a.cpp:

#include "A.h" 

std::ostream* InA::ourDest = NULL; 

void 
InA::setDest(std::ostream& dest) 
{ 
    ourDest = &dest; 
} 

В main.cpp:

#include <iostream> 
#include "A.h" 

int 
main() 
{ 
    InA::setDest(std::cout); 
    std::cout << InA::getStream() << std::endl; 
    return 0; 
} 

Составитель и связан с:

cl /EHs /LDd /DDLL_A A.cpp 
cl /EHs /MDd main.cpp A.lib 

Как я понимаю (я больше Unix человек), все .cpp, которые становятся частью библиотеки DLL должна иметь/DDLL_A в командной строке который вызывает компилятор; никто из других не должен. В Visual Studios это обычно достигается за счет использования отдельных проектов для каждой dll и каждого исполняемого файла. В свойствах проекта есть запись ConfigurationProperties → C/C++ → Препроцессор → Препроцессор Определения; просто добавьте DLL_A (но только в одном проекте, который генерирует A.ddl).

+0

Я был пытаясь исправить код, чтобы получить то, что вы говорили. Я заработал! Спасибо вам за помощь! – Gasim

+0

Я исправил проблему, но я получаю LNK4049. Я не знаю, что я делаю неправильно. – Gasim

+0

@ Гасим без дополнительной информации, а также я. Что вы делаете именно так? (Обычным решением является определение 'DLLNAME_EXPORT'' '__declspec (dllexport)' при компиляции кода в DLL 'DLLNAME' и' __declspec (dllimport) 'в другом месте. Похоже, что вы определили его по-разному в двух источники, которые являются частью одной и той же DLL.) –

2

Проблема в том, что ваш заголовочный файл, предназначенный для компиляции в DLL, содержит код! Поэтому «main.exe» выдает локальную копию встроенных функций (таких как Base :: sys), но фактическая реализация «Base :: setSystem» скомпилирована в DLL. Поэтому, когда main вызывает вызов setSystem, он вызывает базовую :: setSystem, связанную с DLL. Но когда он компилирует Base :: sys, он видит, что встроенная реализация существует и использует это.

Другими словами, у вас есть две копии «Базы», ​​плавающие вокруг. Один, который живет в EXE, и другой, который живет в DLL. И встроенные функции путают компилятор и компоновщик в отношении того, какую версию вызывать.

Не помещайте встроенные функции (или код в этом случае) в файл заголовка, где реализация предназначена для работы в DLL.

Легко исправить:

// base.h (gets included by main) 
class Base { 
private: 
static Filesystem * filesystem; 
    static Logger * logger; 
    static System * system; 

public: 

    static void setFilesystem(Filesystem * filesystem_); 
    static void setApplication(Application * application_); 
    static void setLogger(Logger * logger_); 
    static void setSystem(System * system_); 
    static Filesystem * fs(); 
    static Logger * log(); 
    static System * sys(); 
}; 

// base.cpp (gets compiled only within the DLL 
System* Base::sys() 
{ 
    return system; 
} 

// repeat "get" function for "log" and "fs" as well 

правой фикс:

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

Лучшим подходом является экспорт чистой библиотеки «C» из библиотеки DLL. И не подвергайте внутренние элементы заголовкам. ИЛИ, если вы хотите экспортировать классы C++, сделайте это с помощью COM-интерфейсов. Тогда все, что вы делаете, - это вставить объявление заголовка в ваш файл заголовка.

+0

Я изменил все, как вы сказали, а также создал статическую библиотеку, потому что он не будет компилировать (ошибки ссылок) без помещая эти файлы в оба проекта. Но это все еще не работает. Моя проблема в том, что я пытаюсь иметь статические переменные в DLL. Основное приложение устанавливает статические переменные, используя сеттеры, и все DLL должны иметь «глобальные» переменные, доступные через геттеры. Является ли это возможным? – Gasim

+0

Это конечно возможно. Какая ошибка ссылки - возможно, это указывает на реальную проблему. Вы правильно экспортируете эти функции из библиотеки DLL? Либо с атрибутом __dllexport, либо с файлом .DEF. – selbie

+0

Хорошо. У меня есть статическая библиотека «Base.lib», которая хранит символы базового класса. «Engine.exe» должен инициализировать переменные базового класса с помощью установщиков. И DLL использует эти переменные, используя геттеры. Getters и seters не нужно экспортировать, но статические переменные действительно должны. Итак, я добавил '#pragma data_seg (". Base_seg ")' (я изменил исходный код, чтобы вы легко его увидели). Однако это не работает. – Gasim

Смежные вопросы