2012. 1. 16. 16:40 윈도우/스터디

출처 : http://sol9501.blog.me/70102942944
출처 : http://psmon.x-y.net/xy_bb/board.php?id=PgSkill&board_sec=0&page=2&mode=view&total=46&no=25

기본적인것이 잘 정리된것 같아서.. 퍼왔습니다.

DLL (Dynamic Link Library)이란,

어플리케이션에서 동적으로 링크하여 사용할 수 있는 라이브러리를 말하며,
확장자로는 .dll, .fon, .drv, .exe 등이 사용된다.

장점으로는,
일단, 여러 어플리케이션이 사용한다면 메모리 낭비를 줄일 수 있겠고,
업그레이드및 모듈별관리가 용이한점을 들 수 있겠다.

구조는,
간단히 코드부분과 데이터로 구성되어있으며, 스택이 없다는 것이 특징이다.
//스택은 어플이케이션의 것을 사용한다
스택이 없으므로 독립적인 프로세스가 될 수 없으며
운영체제로 부터의 메세지를 받을 수 없다
내부에 Exported Function Table을 가지고 있으며,
서수 + 기호이름 + 실제함수를 가리키는 포인터로 구성되어 있다.

(MSDN-TechnicalArticles-VisualTools-VisualC++-Visual C++4.0- DLLs for Beginners 참조)

종류는,
- Regular DLL (Statically linked MFC DLL) : 배포시 자신의 DLL만 제공가능
- Regular DLL (using Shared MFC DLL) : 배포시 자신의 DLL과 MFC공유DLL을 같이 제공
-> 어플리케이션이 MFC이외의 경우에도 사용가능
C언어 기반의 인터페이스제공 필요.
- MFC Extension DLL (using Shared MFC DLL) : MFC로 작성된 어플리케이션에서만 사용가능

링킹방법으로는,
- Implicit Linking (암시적링킹)
- DLL + Lib + header file 필요.
- 어플리케이션 로딩때 같이 로딩.
- Explicit Linking (명시적링킹)
- 로딩타임 마음대로 결정가능 ( 예: 영문리소스/한글리소스 동적으로 결정 )
- 주요함수
- LoadLibrary : DLL모듈 로딩
- GetProcAddress : 함수의 포인터를 얻어옴
- FreeLibrary : DLL 종료 (reference counter를 1감소시킨다)

컴파일러 커맨드
- _WINDLL : 현재 프로젝트가 DLL임을 의미
- _USRDLL : Regular DLL임을 의미
- _AFXDLL : using Shared MFC DLL 임을 의미
- _AFXEXT : MFC Extension DLL임을 의미

일반적인 익스포트함수 예제

extern "C" declspec(dllexport) void WINAPI function(void);
// extern "C" : 컴파일때 decoration name을 생성하지 않도록 하기위해 (C-Style)
// declspec(dllexport/dllimport) : Export/Import된 함수임을 의미
// WINAPI
- "windef.h"의 119 line 에 _stdcall 로 정의되어 있음
- PASCAL calling convension을 의미 : push는 거꾸로(오른쪽에서 왼쪽), pop은 Callee가 담당.
- 참고로, C++은 디폴트로 _cdecl을 사용 : push는 거꾸로(오른쪽에서 왼쪽), pop은 Caller가 담당.

DLL 찾기 순서
1 어플리케이션(EXE)을 포함한 폴더
2 프로세스의 현재 폴더
3 시스템 폴더
4 윈도우즈 폴더
5 Path에 지정되어 있는 폴더들...


TIPs

1. DLL에 공유데이터를 포함시키기 위한 방법

- memory-mapped file을 사용하는 방법. (요건 나중에...)

- named data section을 사용하는 방법.

#pragma data_seg ("Shared")
int iShared = 0;
#pragma data_seg ()


2. DLL내에 있는 Resource 참조 방법

- 가장 일반적인 MFC 어플리케이션 + MFC Extension DLL 의 경우 리소스를 찾는 순서

1. 어플리케이션(EXE)의 리소스 검색
2. DLL의 리소스 검색
3. MFC공유DLL의 리소스 검색
-> 중복되는 리소스이름이 있는 경우는 먼저 찾아진 리소스를 사용하게 된다.
임의로 찾기 순서를 바꾸기 위해서
AfxSetResourceHandle(원하는 모듈의 리소스핸들)을 사용할 수 있다.
예) 다음의 코드는 DLL내에 있는 리소스를 먼저 찾기 위한 코드이다.
// DLL의 코드
Handle hInstOld = AfxGetResourceHandle(); // 어플리케이션의 리소스핸들을 보관.
AfxSetResourceHandle(DLL의 DllMain에서 얻은 DLL의 리소스핸들);
// ...
AfxSetResourceHandle(hInstOld); // 원래대로 복귀

- MFC 어플리케이션(or 델파이/비베...) + Regular DLL 의 경우.

- Regular DLL을 사용하는 경우에는 위와같이 DLL내의 리소스를 참조할 수 없다.
따라서 DLL내의 리소스(다이얼로그와같은)를 참조하기 위해서는,
다음과 같이 임의로 Module State를 전환시켜주는 함수가 필요하다.
- AFX_MANAGE_STATE(AfxGetStaticModuleState());
일반적으로 프로세스(EXE)의 인스턴스핸들은 거의 항상 0x00400000이고,
DLL은 0x10000000 이다.
DLL내에서 위의 함수를 사용한 후에는 인스턴스핸들이 DLL의 인스턴스핸들(0x10000000)로
바뀐 것을 확인해 볼 수 있을것이다.

- (어플리케이션 + ) Regular DLL + MFC Extension DLL

- Regular DLL에서 MFC Extension DLL내에 있는 리소스를 참조하려 할때 역시
그냥 되지는 않는다. 이때는 두가지 방법이 있는데,

첫번째는,

잠시 리소스를 참조하기 위해 사용되는 인스턴스핸들을 MFC Extension DLL의 것으로
바꿨다가 복구해주는 방법이다.

HINSTANCE hInstOld = AfxGetResourceHandle();
AfxSetResourceHandle(g_hModule);
m_menu.LoadMenu(IDR_LISTOUTPUT)
AfxSetResourceHandle(hInstOld); // restore the old resource chain

이 방법은 위의 리소스찾기 순서를 바꾸기 위해 사용했던 방법과 같다.
g_hModule은 DLLMain에 있던 hInstance를 전역변수로 보관한 것이다.

두번째는,

아래 소스는 MFC Extension DLL을 만들었을 때 만들어지는 소스의 일부이다.
잘 보고 가장 긴 주석문에서 시키는 대로 하면된다.

new CDynLinkLibrary(Implicit_MFCExt_dllDLL); 를 주석처리하고,
따로 함수를 만들어 익스포트 시킨다.
그리고, 그 함수를 Regular DLL의 InitInstance와 같은 함수에서
첨에 한번 초기화를 시키도록 해 주면 된다.
그러면 Regular DLL의 리소스체인에 attach된다.

extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);

if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("IMPLICIT_MFCEXT_DLL.DLL Initializing!\n");

// Extension DLL one-time initialization
if (!AfxInitExtensionModule(Implicit_MFCExt_dllDLL, hInstance))
return 0;

// Insert this DLL into the resource chain
// NOTE: If this Extension DLL is being implicitly linked to by
// an MFC Regular DLL (such as an ActiveX Control)
// instead of an MFC application, then you will want to
// remove this line from DllMain and put it in a separate
// function exported from this Extension DLL. The Regular DLL
// that uses this Extension DLL should then explicitly call that
// function to initialize this Extension DLL. Otherwise,
// the CDynLinkLibrary object will not be attached to the
// Regular DLL's resource chain, and serious problems will
// result.

//new CDynLinkLibrary(Implicit_MFCExt_dllDLL);

g_hModuleInstance = hInstance;
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("IMPLICIT_MFCEXT_DLL.DLL Terminating!\n");
// Terminate the library before destructors are called
AfxTermExtensionModule(Implicit_MFCExt_dllDLL);
}
return 1; // ok
}

extern "C" AFX_EXT_API void WINAPI InitMFCExtDLL()
{
// create a new CDynLinkLibrary for this app
new CDynLinkLibrary(Implicit_MFCExt_dllDLL);
}


'윈도우 > 스터디' 카테고리의 다른 글

Media Transfer Protocol (MTP)  (0) 2011.12.15
PostThreadMessage로 SendThreadMessage 구현하기  (0) 2011.11.28
_stprintf_s  (0) 2011.11.28
Visual Studio C++ 메모리 릭  (2) 2011.11.24
posted by townone