정리

DllMain에서 하지 말아야 할 것들

저장소/VC++

야호~~~

FreeLibrary를 할 때 리턴이 안 되는 문제가 있었다.

아오! 대체 왜 그러는지 찾는데 몇시간이 걸린건가 @_@

원인은 CoUninitialize 호출 후 반환되지 않는 문제로 인한 것이었다.


MSDN에 CoUninitialize를 살펴보면 아래와 같은 내용이 있다.

Because there is no way to control the order in which in-process servers are loaded or unloaded, do not call CoInitializeCoInitializeEx, or CoUninitialize from the DllMainfunction.


CoInitialize 처리는 DllMain에서 하지 않았지만 CoUninitalize는 DllMain의 DLL_PROCESS_DETATCH 에서 처리했던게 문제였다.

사실 중간에 CoInitialize/CoUninitialize를 사용했다는 것을 몰랐던 내 문제지만 ㅋㅋ

객체 해제 과정을 따로 처리한 다음에 DllMain에서는 아무 것도 처리하지 않게 만들면 쉽게 해결 가능할 것 같은데

안 해봐서 모르니 일단 패스.


원인을 찾다보니 DLL지옥 관련된 여러 내용들이 있는 것 같다.

정리를 잘 해주신 분들이 있으니까 참고하도록 하자.


참고 1 : http://ancdesign.tistory.com/43

참고 2 : 신영진님의 옛날 블로그 (http://www.jiniya.net/tt/788)


다음 내용은 신영진님의 블로그에서 낼름 복사한 것이다. (혹시 없어질까봐 ^^;)

경고!!! 
DllMain에서 다음 작업들은 절대로 하지 말 것.

  1. LoadLibrary, LoadLibraryEx 호출. 데드락이나 크래시를 유발한다.
  2. 다른 스레드와 동기화. 데드락을 유발한다.
  3. 로더 락을 획득하려는 코드가 가지고 있는 동기화 오브젝트를 획득하려는 시도. 데드락을 유발한다.
  4. CoInitializeEx를 사용한 COM 스레드 초기화. 특정 조건이 충족될 경우 이 함수는 LoadLibraryEx를 호출한다.
  5. 레지스트리 함수들. 이 함수들은 advapi32.dll에 구현되어 있다. advapi32.dll이 초기화 되지 않았다면 크래시가 발생할 수 있다.
  6. CreateProcess 호출. 프로세스 생성은 다른 DLL을 로드할 수 있다.
  7. ExitThread 호출. DLL 디태치(detach) 과정 중에 스레드를 종료하면 로더 락을 다시 획득하도록 만들 수 있다. 이는 데드락이나 크래시가 유발된다.
  8. CreateThread 호출. 동기화만 하지 않는다면 스레드 생성은 괜찮을 수 있다. 하지만 위험하다.
  9. 네임드 파이프나 네임드 오브젝트 생성 (2000만 해당한다). 윈도우 2000에서 네임드 오브젝트 생성은 터미널 서비스 DLL에서 구현되어 있다. 해당 DLL이 초기화되어 있지 않다면 크래시.
  10. CRT에 포함된 메모리 관리 함수들. CRT DLL이 초기화되어 있지 않다면 크래시.
  11. user32.dll이나 gdi32.dll에 포함된 함수 호출. 일부 함수들은 다른 DLL을 로드하고, 이 사실은 크래시가 발생할 수 있다는 것을 의미한다.
  12. 관리된 코드 사용.

* 가장 아름다운 DllMain은 존재하지 않는 것이다 (비어 있는 함수 바디).
** 그래도 먼가 하고 싶다면 kernel32.dll에 포함된 함수 중에 위에서 언급되지 않은 것들만 쓰도록 한다. kernel32.dll이 초기화는 운영체제가 보장해 준다. 
*** 글로벌 오브젝트에 대한 초기화 코드 또한 DllMain 과정에 포함된다. 따라서 글로벌 오브젝트의 생성자 내지는 초기화 함수 부분에 위에서 언급한 내용이 있어서는 안된다.
**** 초기화를 하지 말란 소린가? 아니다. 지연시키라는 말이다.