블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2731)
Unity3D (814)
Programming (474)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (57)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (51)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
03-29 07:22
DLL을 사용한다면 참고하시라고 몇자 적어봅니다.

 아미 몇번 DLL을 써 보셧다면 다 아시는 내용일겁니다.

 1.  한 프로그램에 쓰인 클래스를 다른 프로그램에서도 같이 써야 할 일이 생겨서, 그냥 소스만 복사해넣고 좀 고쳐서 놓고 쓰니 불편하더군요.. 그래서 DLL 형태로 공유하는 엔진을 만들어서 Static 링크를 시도했읍니다.

  이때 DLL 만들때 제일 먼저할 것은 DLL 생성한 후에  프리컴파일 디파인 에 _AFXEXT 와 _NOWCOMPILE 을 넣어주는 것입니다.  _NOWCOMPLIE 이란 항목은 나중에 컴파일을 위한 옵션입니다.
 
     Project -> Setting ->  C/C++  에서  추가해 줌..

  다음 클래스 이름을 외부에서 호출할 수 있도록

 class AFX_EXT_CLASS  myClass { ...}  로만 선언하고

 헤더파일에 

#if !defined(_NOWCOMPILE)
#if defined(_DEBUG)
    #pragma comment(lib, "..\\myDLL\\debug\\myDLL.lib")
#else
    #pragma comment(lib, "..\\myDLL\\release\\myDLLD.lib")
#endif
#endif

 
 _NOWCOMPLE 옵션은  헤더파일 포함시 LIB가 같이 포함되도록 하는 용도의 플래그 입니다.
 DLL 컴파일시에만 포함되지 않도록 하기 위해서 DLL 프로젝트에만 _NOWCOMPILE를 추가하는 것이죠.

 
 2. 릴리즈 와 디버그 DLL 버전 관리..
 릴리즈와 디버그 버전을 관리하고자 한다면,   제일 먼저 할 일은  .def 파일을 두개로 만들어서 그중 하나에서 디버그용 이름으로 변경해 놓는 것입니다.  제 경우 D를 추가해 놓죠.
 
    Project -> Setting ->  Link  에서 def  이름 지정된 것을 변경해 줍니다.
 
 이 작업이 빠지면, 디버그 와 릴리즈 버전 이름이 같아서 혼동이 생기게 됩니다.


 3. 버전에 따른 리소스를 다르게?

  버전에 따라서 리소스의 버전을 다르게 만들고 싶어질 경우가 있읍니다.
  좀 귀찮아서 써 봤는데.. 
  이경우    Project -> Setting ->  Resource 에서  프리컴파일 디파인을 지정해 줄 수 있읍니다.
  그러면 RC 파일을 편집해서  조건을 지정할 수 있지만, 여기에 가장 큰 문제는
  리소스 에디터에서 변경을 하게되면 조건 걸린 부분이 날라갑니다.
 결국 별도 파일로 만들어서 #include 시켜서 써야 했죠.
 제경우 bmp 이미지를 몇개를 버전에 따라서 다르게 보이도록 하기 위해서 설정한 것입니다.


 4.  다이나믹 DLL  사용

 먼저 DLL을 만들고, DLL에서 사용하는 함수를 호출 할 수 있도록 선언합니다.
 
extern "C" __declspec( dllexport ) void  InitPage(CString arg1,CString arg2)
{
   CMyDlg dlg;
   dlg.DoModal();
}

  CMyDlg dlg 라는 것이 DLL 내부에 만들어진 다이알로그 입니다.
 

 DLL 의 InitPage 를 호출하는 부분

void CallDll()
{
HINSTANCE hInst,oInst;
#ifdef _DEBUG
    hInst=AfxLoadLibrary("myDLLD.dll"); // 디버그 버전
#else
    hInst=AfxLoadLibrary("myDLL.dll"); //릴리즈 버전
#endif
    if (!hInst)
    {
        AfxMessageBox("DLL Load 에러!");
        return;
    }
    typedef void ( * INITPAGE)(CString,CString);
    INITPAGE func;
        func=(INITPAGE)GetProcAddress(hInst,"InitPage");
    if (func)
    {
        oInst=AfxGetResourceHandle();
        AfxSetResourceHandle(hInst);
        func("테스트","테스트1");
        AfxSetResourceHandle(oInst);
    }
    AfxFreeLibrary(hInst);
 
}

 이렇게 사용하면 됩니다.
 여기서 리소스 핸드를 바꿔주고 복구하는 것이죠
 여기서 중요한 포인트는     typedef void ( * INITPAGE)(CString,CString); 입니다.
 DLL 과 함수 선언이 동일해야 합니다. 저의 실수는 처음에 만들때     typedef bool  ( * INITPAGE)(CString,CString); 로 해 놓고 컴파일하니 이상없이 동작 잘 하더군요,  DEBUG 버전에서 릴리즈 버전으로 바꾸어서 테스트 하니  스택에 오류가 생기더군요.. 무엇이 원인인가.. DLL 함수 선언이 문제인가 하고 이것 저것 고민하면서 테스트 했는데,  결론은 DLL 의 평션에서는  void 였는데,  콜할때 선언은 BOOL 로 해서 ,   릴리즈 버전에서 스택에서 리턴값을 클리어하느라 에러가 났던 것입니다.
  반듯이  DLL 과 사용하는 함수의 선언은 리턴값까지 일치 시켜야 합니다.  파라미터에 신경쓰다가 실수한 부분입니다.

 
 5. 다이나믹 DLL 의 해제 시점..

  DLL의 함수에서 메모리 할당을 받았다면,  DLL 의 해제 시점(AfxFreeLibrary 호출 시점)은   메모리 해제한 이후에 해야 합니다.
  무슨 소리냐면, DLL 함수에 구조체를 보내서, DLL에서  구조체의 데이타를 Free 시키고, 새로 할당해서 데이타를 채워서 리턴시키는데,  이것을 Free 하는 시점에서 계속  힙이 깨졌다는 오류가 나오더군요.
 원인 파악을 하기 위해서 6시간정도 고생을 했는데, 결국 DLL 해제 시점을 옮김으로서 해결되더군요.
 만약 DLL 에서 뭔가를 가져왔다면,  반납하기 전에는 DLL을 해제하지 마세요..
 시스템 크래시와 부딪힐 수 있읍니다.


 

 이상입니다.
 과연 몇분에게나 도움이 될런지.....

ps:
 쓰레드간 통신에서  SendMessage 를 가지고 동기화를 하게 되는 경우,  데드락 걸릴 수 있는 여지가 있읍니다.
 그걸 해결하는 방법은 SendMessageTimeout 이란 평션을 사용하면 어느정도 해결됩니다.
 단 메세지 전송되는 핸들이 서로다른 쓰레드일 경우에만 효과가 있다고 하더군요.
 여기 Q/A 에 있는 정보 입니다.


출처 : 
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=4722&ref=1602
반응형
Posted by blueasa
, |