2011-12-28 4 views
2

DLL/주 프로그램에서 전역 함수에 액세스하는 데 도움이 필요합니다. 나는 수업 자료 (MAIN_DLL 여기에 미리 정의되어)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 (기본 응용 프로그램)가

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

나는 DLL에서 액세스 :

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

감사합니다. Gasim

+1

이것은 관심의 대상이 될 수 있습니다 : 가 http://stackoverflow.com/questions/4911994/sharing-a-global-static-variable-between-a-process-and-dll – marcinj

답변

4

이것은 시스템에 따라 다르지만 멤버 함수 및 정적 멤버 데이터의 정의가 들어있는 DLL의 심볼이 심볼을 올바르게 내보내고 DLL을 올바르게 사용하여 심볼을 가져 오는지 확인해야합니다. 리눅스에서는 실행 파일을 링크 할 때 -E 옵션을 사용하는 것을 의미합니다 (심볼이 실행 파일에 정의 된 경우). Windows에서는 일반적으로 조건부 컴파일 컴파일러 확장을 사용해야합니다 (__declspec 참조). Microsoft 컴파일러는 표준 C++에서 DLL을 지원하지 않습니다.

는 편집 : 아에서

: A.cpp에서

#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 

:

#include "A.h" 

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

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

여기에

는 (2010 VC) 내 시스템에서 작동하는 예제 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 

, 는 DLL의 일부가되는 통화 당 모든 명령 줄에/DDLL_A을 가져야한다 which 은 컴파일러를 호출합니다. 다른 누구도 따라야하지 않습니다. Visual Studio에서 은 일반적으로 각 dll에 대해 별도의 프로젝트를 사용하고 각 실행 파일에 을 사용하여 수행합니다. 프로젝트의 속성에는 항목이 있습니다. ConfigurationProperties → C/C++ → 전 처리기 → 전 처리기 정의; 단지 DLL_A을 추가하면됩니다 (그러나 이 생성하는 하나의 프로젝트에만 A.ddl이 생성됩니다).

+0

내가왔다 당신이 말한 것을 얻기 위해 코드를 수정하려고합니다. 나는 일할 수있어! 도와 주셔서 감사합니다! – Gasim

+0

문제가 해결되었지만 LNK4049가 표시됩니다. 내가 뭘 잘못하고 있는지 모르겠다. – Gasim

+0

@Gasim 더 자세한 정보가 없거나 나도 마찬가지입니다. 정확히 무엇을하고 있습니까? (보통의 해결책은'DLLNAME_EXPORT'을'DLLNAME' DLL의 코드를 컴파일 할 때'__declspec (dllexport)'에 정의하고'__declspec (dllimport)'를 다른 곳으로 정의하는 것입니다. 소스는 같은 DLL의 일부입니다. –

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에서 인터페이스를 변경할 때 정말 빨리 복잡해집니다.

더 나은 방법은 DLL에서 순수한 "C"라이브러리를 내보내는 것입니다. 내부 파일을 헤더 파일에 노출시키지 마십시오. 또는 C++ 클래스를 내보내려면 COM 인터페이스를 사용하십시오. 그런 다음 헤더 파일에 인터페이스 선언을 넣는 것뿐입니다.

+0

당신이 말한대로 모든것을 변경했고 컴파일하지 않기 때문에 (링크 오류) 정적 라이브러리도 만들었습니다. 이 파일들을 두 프로젝트에 넣었습니다. 하지만 여전히 작동하지 않습니다. 내 문제는, 나는 DLL을 통해 정적 변수를 가지고 노력하고있다. 기본 응용 프로그램은 setter를 사용하여 정적 변수를 설정하고 모든 dll에는 getter를 통해 액세스되는 "전역"변수가 있어야합니다. 가능한가? – Gasim

+0

확실히 가능합니다. 링크 오류 란 무엇입니까? 실제 문제를 나타내는 것일 수 있습니다. 제대로 DLL에서 이러한 함수를 내보내는, 맞습니까? __dllexport 특성 또는 .DEF 파일을 사용하십시오. – selbie

+0

확인. Base 클래스의 심볼을 저장하는 "Base.lib"정적 라이브러리가 있습니다. "engine.exe"는 setter를 사용하여 Base 클래스의 변수를 초기화해야합니다. 그리고 DLL은 getter를 사용하여 이러한 변수를 사용합니다. 게터와 세터는 내보낼 필요가 없지만 정적 변수는 가져야합니다. 그래서,'#pragma data_seg (". base_seg")'를 추가했습니다 (시각적으로 쉽게 볼 수 있도록 소스 코드가 변경되었습니다). 그래도 작동하지 않습니다. – Gasim

관련 문제