использовать переменную / функцию статического класса в dll - PullRequest
2 голосов
/ 28 декабря 2011

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

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";

Спасибо, Gasim

Ответы [ 2 ]

4 голосов
/ 28 декабря 2011

Это зависит от системы, но вам нужно убедиться, что символы в DLL, содержащие определения функций-членов и статические данные-члены, правильно экспортируют символы и что 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).

2 голосов
/ 28 декабря 2011

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

Другими словами, у вас есть две копии "Base", плавающие вокруг.Один, который живет в 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.Затем все, что вы делаете, это помещаете объявление интерфейса в ваш заголовочный файл.

...