728x90

안녕하세요. 공유민입니다.
오늘은 MFC 상태 정보 관리 및 모듈, 리소스 핸들에 대해 공부했던 것을 정리하려고 합니다.
여기서 모듈이라는 단어를 정리하자면 하나의 소스 파일일 수도 있고, 실행 파일 단위일 수도 있습니다.


MFC는 자체적으로 구현한 TLS(Thread Local Stroage), 즉 MFC TLS를 사용하여 MFC의 상태 정보를 관리한다.

MFC가 관리하는 상태 정보는 3가지가 있다.
- 스레드 정보 : _AFX_THREAD_STATE
- 모듈 정보 : AFX_MODULE_STATE
- 모듈 스레드 정보 : AFX_MODULE_THREAD_STATE

_AFX_THREAD_STATE, AFX_MODULE_STATE, AFX_MODULE_THREAD_STATE는 MFC 상태 정보 관리를 위해 사용되는 클래스이다.

[_AFX_THREAD_STATE]
    • 스레드 단위로 정보를 관리하기 위한 클래스
    • 스레드마다 생성(스레드 단위의 전역 변수(TLS))
    • 애플리케이션은 _AFX_THREAD_STATE를 이용하여 내부적으로 관리하는 스레드 정보에 접근할 수 있다.
       내부적으로 관리하는 스레드 정보
        - 현재 스레드의 마지막 메시지, 마우스 좌표, 훅 함수 등...
        - 보다 자세한 내용은 afxstat_.h의 _AFX_THREAD_STATE 클래스 정의 부분을 참고.
    • _AFX_THREAD_STAT의 주목적은 AFX_MODULE_STATE 클래스를 포함하기 위한 것이다.

[AFX_MODULE_STATE]
   • 실행 모듈 정보를 관리하기 위한 클래스
   • 실행 모듈 단위의 전역 변수
   • 내부적으로 관리하는 정보
     - 애플리케이션 객체 포인터
     - 인스턴스 핸들
     - 리소스 인스턴스 핸들
     - 윈도우 프로시저 주소
     - 런타임 클래스(CRuntimeClass) 리스트
     등... 보다 자세한 내용은 afxstat_.h의 AFX_MODULE_STATE 클래스 정의 부분을 참고.

[AFX_MODULE_THREAD_STATE]
   • 특정 모듈에서 특정 스레드가 생성하거나 설정한 정보를 관리하기 위한 클래스
   • 스레드마다 생성(스레드 단위의 전역 변수(TLS))
   • 내부적으로 관리하는 정보
     - 핸들맵 등...
     보다 자세한 내용은 afxstat_.h의 AFX_MODULE_THREAD_STATE 클래스 정의 부분을 참고.






 [그림 1]

 [그림 1]



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 소스 1
 
    // Exe 모듈 상태
    AFX_MODULE_STATE* GAMS = AfxGetAppModuleState();
    AFX_MODULE_STATE* SMS  = AfxGetStaticModuleState();
    AFX_MODULE_STATE* MS = AfxGetModuleState();
    
    // MOUULE_STATE를 DLL 모듈 상태로 변환 후 
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
 
    GAMS = AfxGetAppModuleState();
    SMS  = AfxGetStaticModuleState();
    MS = AfxGetModuleState();
 
/*
디버깅으로 확인한 변수 값 (Exe = 100, Dll = 200)
 GAMS = 100, SMS = 200, MS = 100
// MOUULE_STATE를 DLL로 변환 후 
 GAMS = 100, SMS = 200, MS = 200
*/
cs


  ◆ AFX_MANAGE_STATE
AFX_MANAGE_STATE(AFX_MODULE_STATE* pModuleState);
어떤 함수 안에서 현재 스레드의 AFX_MODULE_STATE 전환을 위해서 AfxSetModuleState 함수를 직접 호출하는 것보다는
AFX_MANAGE_STATE 매크로를 사용하는 것이 편리하다. 

AfxSetModuleState() : 직접 모듈 상태를 바꿈.

  • AfxGetAppModuleState()
MFC는 전체 모듈(실행을 위해 로드 되어 있는 .EXE와 모든 DLL)들을 논리적인 하나의 모듈로 보고, 이것을 위해 AFX_MODULE_STATE를 할당한다. 이렇게 할당된 AFX_MODULE_STATE 객체를 반환한다. 
제일 최상위 모듈 상태를 반환한다고 생각하면 된다. 그림 1에서는 계속 모듈 100을 반환할 것이다.

  • AfxGetModuleState()
현재 실행 흐름(스레드)을 기준으로 AFX_MODULE_STATE 객체를 반환한다.

현재 스레드의 모듈 핸들에 저장된 값을 기준으로 모듈 상태를 반환한다. 그림 1에서는 모듈 100을 반환할 것이다. 그러나 이 값은 소스 1에서 했던 것처럼 AFX_MANAGE_STATE(AfxGetStaticModuleState())와 같이 변경해준다면 값이 바뀐다.

  • AfxGetStaticModuleState()
항상 호출 시점의 모듈에 선언된 AFX_MODULE_STATE 객체를 반환한다.

현재 호출된 모듈의 모듈 상태를 반환한다. 예를 들어 그림 1에서 Exe 모듈을 실행 중이라면 100을 반환, Dll 모듈을 실행 중이라면 200을 반환한다.


위와 같이 모듈 상태를 변경했던 이유는 Dll에 포함된 리소스(그림 1에서 500)를 사용하기 위해서였다. 모듈 상태를 변경하지 않으면 이미 Dll을 호출했음에도 Exe에 있는 리소스(그림 1에서 1000)를 접근하려 할 것이고 이는 오류를 야기한다.

만약 MFC를 사용하지 않는 win32 프로젝트라면 위의 AFX_MANAGE_STATE를 사용할 수 없다. 하지만 리소스(그림 1에서 500)를 사용하기 위해 모듈을 바꿔줘야 한다면 어떡해야 할까? 이럴 때에는 WINAPI에서 제공하는 GetModuleHandle()를 사용하여 해결할 수 있다.



1
2
3
4
// 소스 2
// 현재 Exe 모듈 핸들을 가리키고 있으니 Dll 모듈 핸들로 바꿔준다.
    HINSTANCE hinst;
    hinst = GetModuleHandle("DllFileName.dll");    // dll 핸들을 얻어 옴
cs

소스 2와 같이 핸들을 받아오면 해당 리소스(그림 1에서 500)에 접근할 수 있다.



+ Recent posts