ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • AfxGetInstanceHandle() 함수가 NULL 을 리턴하는 경우
    개발 2008.05.13 19:19


    며칠 전 별도로 진행되어오던 여러 프로젝트를 통합하던 과정에서 AfxGetInstanceHandle() 이 NULL 을 리턴하는 문제를 발견했습니다.

    실행화일이 이제 겨우 Load 될려는 시점에서 문제가 발생한 터라 특별한 디거빙정보는 없고 디버거는 아래 MFC 라인에서 멈춰있었습니다.

     

    _AFXWIN_INLINE HINSTANCE AFXAPI AfxGetInstanceHandle()

               { ASSERT(afxCurrentInstanceHandle != NULL);

                         return afxCurrentInstanceHandle; }

     

    대략 난감할 때면 언제나 그렇듯 구글링을 통해 여러가지 가능성을 점검하다가 아래 문서를 발견했습니다.

     

    How To Debug MFC Module and Thread State Problems

     

    이전에도 이 문서를 본적이 있었는데 그 때는 제대로 써 먹지 못했지만 이번에는 정말 제대로 써 먹었습니다.

     

    결국 dll 의 인스턴스 핸들이 사라진 이유는 MFC 에서 관리하는 모듈 인스턴스가 어떤 이유에서인지 변경되었다는 것을 의미한다고 위 문서에 적혀 있습니다.

     

    그래서 문서에 나와있는 데로 아래 내용을 여러 DLL 과 실행파일의 stdafx.h 에 추가하고

     

    #ifdef _DEBUG

       #define MODULE_TRACE()  TRACE("%s(%d) : Module State nInst = 0x%X\n", \

             __FILE__, __LINE__, AfxGetModuleState()->m_hCurrentInstanceHandle)

       #define THREAD_TRACE()  TRACE("%s(%d) : Thread State Address = 0x%X\n",\

             __FILE__, __LINE__, AfxGetThreadState())

       #else

       #define MODULE_TRACE()

       #define THREAD_TRACE()

       #endif  //_DEBUG

                                             

    의심이 갈만한 소스에는 다음 두 줄을 추가해서

     

    MODULE_TRACE();

    THREAD_TRACE();

     

    모듈과 Thread 의 상태가 변경되는 곳이 있는 지 찾아 봤습니다.

    결국 한참을 헤매긴 했지만 Application 의 MainFrame 이 생성되기 직전 ATL 관련 COM 객체를 생성하면서 전역 모듈 상태가 변경되는 현상을 발견했습니다.

    이전까지 작동하던 코드여서 정확하게 왜 문제가 생겼는지는 분석해 보진 못했지만, 모듈/쓰레드 추적기 덕분에 제 딴엔 참 어려운 문제를 해결 할 수 있었습니다.

     

    사실 MFC 에서 모듈 상태변경은 참 귀찮은 부분 중에 하나입니다.

    MFC Regular Dll 을 새로 만들면 프로젝트.cpp 소스에 다음과 같은 주석이 달립니다. 가끔씩 빼 먹어도 잘 작동하는 편인데, 이 부분에서 뭔가 심각한 MFC 상태 변경과정을 거치는 모양입니다.

     

    //

    //         참고:

    //

    //                   이 DLL이 MFC DLL에 대해 동적으로 링크되어 있는 경우

    //                   해당 DLL에서 내보내고 MFC로 호출하는 모든 함수의

    //                   시작 부분에

    //                   AFX_MANAGE_STATE 매크로가 들어 있어야 합니다.

    //

    //                   예:

    //

    //                   extern "C" BOOL PASCAL EXPORT ExportedFunction()

    //                   {

    //                              AFX_MANAGE_STATE(AfxGetStaticModuleState());

    //                              // 함수의 나머지 본문은 여기에 옵니다.

    //                   }

    //

    //                   이 매크로는 MFC로 호출하기 전에

    //                   각 함수에 반드시 들어 있어야 합니다.

    //                   즉, 매크로는 함수의 첫 번째 문이어야 하며

    //                   개체 변수의 생성자가 MFC DLL로

    //                   호출할 수 있으므로 개체 변수가 선언되기 전에

    //                   나와야 합니다.

    //

    //                   자세한 내용은

    //                   MFC Technical Note 33 및 58을 참조하십시오.

     

     

    근데 여태까지 MFC Technical Note 33 및 58를 읽어 보지 못해서, 확장 DLL 과 Regular Dll을 경험적으로만 파악하고 있습니다.

    • 확장 dll 은 리소스 아이디가 메인 어플리케이션과 같이 사용되고 Regular Dll 은 따로 놉니다.

    • ATL 은 Regular Dll 에만 추가 가능하네요

    • Regular Dll 에서 생성한 STL 컨테이너 데이터를 확장 DLL로 넘어오면 문제가 생겨서 고생한 적이 있습니다. 결국 MSDN 을 보니 그렇게 쓸 수 없다더군요.

     

     

    그 외에도 문서가 아닌 경험적으로 알고 있는 사항이 좀 더 있을 것 같은데 생각이 나질 않네요.

    역시, 공부가 필요합니다 ^^;

     

     

    댓글 0

Designed by black7375.