我需要帮助访问DLL /主程序的全局函数。我有一个班级基地
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";
谢谢, 卡西姆
答案 0 :(得分:4)
这是系统相关的,但您必须确保包含成员函数和静态成员数据定义的DLL中的符号正确导出符号,并且使用它们的DLL正确导入它们。在Linux下,这意味着在链接可执行文件时使用-E
选项(如果符号在可执行文件中定义);在Windows下,您通常必须使用有条件编译的编译器扩展,请参阅__declspec
; Microsoft编译器不支持标准C ++中的DLL。
编辑:
这是一个适用于我的系统的示例(VC 2010):
在A.h:
#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
生成{{1}})。
答案 1 :(得分:2)
问题是你的头文件意味着编译成DLL包含代码!因此“main.exe”执行内联函数的本地副本(例如Base :: sys),但“Base :: setSystem”的实际实现被编译到DLL中。因此,当main调用“setSystem”调用时,它调用链接到DLL的Base :: setSystem。但是当它编译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
正确修复:
你真的,真的,真的不应该尝试从DLL导出C ++类。它是允许的,但是当您开始在头文件中插入代码并更改DLL的不同版本中的接口时,它会变得非常复杂。
更好的方法是从DLL导出纯“C”库。并且不要在头文件中公开内部。或者,如果您确实要导出C ++类,请使用COM接口。然后您要做的就是在头文件中添加一个接口声明。