DllMain이 언제, 왜 호출되는지에 대하여 알아보자.

DllMain의 정의는 아래와 같다.

-------------------------- DllMain의 원형 -------------------------------

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);

----------------------------------------------------------------------

1. HINSTANCE hinstDll
   - DLL이 가상주소에 매핑되었을 때의 핸들이다. WinMain의 hInstance 와 동일한 셩격을 갖고있다.
   - IMAGE_OPTIONAL_HEADER 의 ImageBase 필드에 지정된 값이다.  보통 디폴트로 0x10000000 번지에 로드된다.

2. DWORD fdwReason
   - DllMain 이 호출한 이유를 나타낸다.
   - fdwReason 의 값으로는
     -> DLL_PROCESS_ATTACH : DLL이 프로세스의 주소 공간에 최초로 매핑됬을때

     -> DLL_PROCESS_DETACH : DLL이 프로세스의 주소 공간으로 부터 해제될 때

     -> DLL_THREAD_ATTACH : 어떤 프로세스 내에서 스레드가 생성될 때 해당 프로세스 주소공간에 매핑되어 있는 모든 DLL의 파일이미지검사하여 DLL_THREAD_ATTACH 로 호출

     -> DLL_THREAD_DETACH : 스레드 엔트리 포인트 함수로부터 리턴될때 시스템은 ExitThread를 호출한다 이때 스레드를 바로 없애지 않고 매핑되어 있는 모든 DLL의 DllMain에 DLL_THREAD_DETACH를 호출

-----------------------------------------------------------------------------------------------------------------------------------------

DllMain을 정의할 때 주의할 점이 있는데 DllMain을 호출할때 동기화를 맞추어야 한다.

예를 들어 스레드가 생성될 때 DLL_THREAD_ATTACH 를 매개 변수로 하여 DllMain이 호출된다. 이때 다른 스레드가 종료되는 상황이라면

DllMain이 동시에 두 개의 스레드에 대하여 호출되는 상황이 발생할 것앋. 이 경우 동기화 문제를 고려할 필요가 없도록 시스템이 알아서

앞에 호출된 DllMain의 실행이 끝날 때까지 DllMain의 실행을 대기시키게 된다. 이런 상황 때문에 DllMain 내에서 대기 함수(WaitForXXX 함수군들)를 호출할 때 신중을 기해야 한다.

아니 이런 상황이 발생하지 않도록 코딩해야 한다.  제프리 책 Programming Applications for Microsoft Windows 2000에 이런 상황이 발생할 수 있는 문제점에 대한 예제가 나오는데

확인해보자

------------------------------------- 데드락이 발생하는 DllMain의 예) ----------------------------------------

BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, PVOID lpvReserved)
{
 HWND hThread;
 DWOIRD dwThreadld;

 switch(fdwReason)
 {
 case DLL_PROCESS_ATTACH:
 hThred = CreateThread(NULL,0,SomeFunction,NULL,0,&dwThreadld); // 스레드하나 생성
 
  WaitForSingleObject(hThread, INFINITE);  // 스레드가 끝날때 까지 DllMain 실행을 대기 시킨다.

  CloseHandle(hThread);
 break;

 case DLL_PROCESS_DETACH:
 break;

 case DLL_THREAD_ATTACH:
 break;

 case DLL_THREAD_DETACH:
 break;

 }

}

----------------------------------------------------------------------------------------------------

위 코드를 보면 Dll 로드시에 호출되는 DllMain에서 스레드를 하나 생성하였다.

이 스레드가 종료할때까지 메인 스레드를 대기하는 코드다

이 프로그램은 데드락 상태에 빠지게 되는데  메인스레드는 SomeFuction을 실행하는 스레드를 생성키기고

WaitForSingleObject 를 통해 SomeFuction 의 실행이 종료될 때까지 대기한다.

하지만 여기서 문제가 되는것은 스레드 생성시에도 DLL_THREAD_ATTACHG를 매개변수로 하여 DllMain이 호출된다는 것이다.

그리고 앞서 언급한 것처럼 이미 DLL_PROCESS_ATTACH를 매개 변수로 하여 메인 스레드에 의해 DllMain이 호출 중이기 때문에

시스템은 메인 스레드가 실행 중인 DllMain 실행이 끝날때까지 SomFunction을 실행하는 스레드를 위한

DllMain 실행을 대기시킨다. 이 상황, 즉 메인 스레드에 의한 DllMain 실행은 SomeFunction 을 실행하는 스레드가 종료되기를 기다리고 있으며

SomeFuction 을 실행할 스레드는 SomeFunction을 실행하기 전에 DllMain을 호출하기 위하여 메인 스레드에 의한 DllMain의 호출이 끝나기를 기다리고 있다.

서로가 서로를 끝나기만 기다리고 있는 것이다. 이런 실수를 범하지 않도록 DllMain정의 시에 신중을 기해야 한다.

 


블로그 이미지

란마12

,