본문 바로가기

프로그래밍/VC/VC.NET/Cs

DLL(Dynamic Link Libraray)에 대한 이야기

DLL은 프로그램간에 공유가 가능하고 정적링크라이브러리와는 다른 기능을 가진다.

정적 라이브러리와의 차이점

정적 라이브러리는 실행 파일에 필요 라이브러리가 포함된것이며,

DLL의 경우 실행파일에 포함되지않고, 실행파일이 메모리에 로드되어서
실행이 될때, 라이브러리가 메모리로 로드되어 실행파일과 링크된다.

결국 정적라이브러리일 경우 실행파일에 포함되므로, 실행파일자체가 커지지만,
독립적 사용이 가능하고, DLL은 파일의 용량은 상대적으로 적고 공유가 가능하지만,
독립적으로 사용하기는 어려워진다.

정적 라이브러리는 실행파일에 필요 모듈 호출부분에서 호출 모듈의 주소를 알아야 하지만,
동적 라이브러리는 실행파일이 메모리 상주할때나 되어야 라이브러리주소를  알수있다.

DLL을 사용하면, 링크과정에서 포함이 된다고 컴파일러는 인식을 하게 되고,
이때 .DEF 파일에 선언이 되어진 링크대상을 찾아 호출한다.


DLL 사용시의 장점

  • 코드의 공유로 실행 파일을 줄일 수 있다. 
  • 메모리의 효율적 사용이 가능
  • 공유 코드를 모듈화해서 재사용할수 있다. 
  • 프로젝트시 관리가 용이하다. 
  • 함수나 기능 추가를 다시 링크하지 않아도 된다. 

DLL 사용시 단점

  • 실행파일이 작아지지만, 배포파일수가 늘어난다.
  • 프로젝트의 복잡성증가
  • 버전관리문제

DLL 초기화

32비트환경에서 DLL메인함수이름을 지정하는데, 이를 엔트리포인트(Entry point)라하며, 보통 DllMain으로 사용.
엔트리 포인트는 다음과 같은 경우호출된다.

  • 프로세스가 처음으로 DLL호출시
  • DLL연결된 프로세스가 새 스레드 생성시
  • DLL연결된 프로세스가 소유한 스레드 제거시
  • 프로세스가 DLL제거시 

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
BOOL fResult = FLASE;

  switch (dwReason)
  {
    case DLL_PROCESS_ATTACH:
    break;
    case DLL_THEREAD_ATTACH:
    break;
    case DLL_THEREAD_DETACH:
    break;
    case DLL_PROCESS_DETACH:
    break;
  }
  return fResult;
}


*Visual C++에서 엔트리 포인트를 변경하기 위해서는, Build/setting->link->catergory->output->entry-point 의 이름을 바꾸면된다.


 DLL 함수 Export하기

함수를 사용하기위해서는 _declspec(dllexpoort)를 사용한다.
그리고 라이브러리의 def 파일의 exports 에서 아이템이름을 명시한다.

int _declspec(dllexport) Func()

_declspec 인자

인자 의미
 dllexport DLL로부터 EXPORT 될수 있는 함수 선언
 dllimport DLL로부터 IMPORT 할 수 있는 함수 선언
 naked 프롤로그코드나 에필로그코드가 가지면 않되는 함수 선언
 thread  TLS(Thread Local Storage)변수로 해당 변수 선언

DLL 링크하기

DLL링크하는 방법은 Implicit linking과 Explicit linking의 방법이있다.
암시적링크는 프로그램이 dll파일을 실행시 로드한후 종료할때 해제하는 방법이고,
명시적링크는 필요할때마다 로드하고 사용후 해제하는 방법이다.


암시적링크(Implicit linking)

dll이 링크될때 호출 프로세스로 매핑되나, 실제 dll 사용전에는 메모리로 로드되지는않는다.
사용방법.

  • 링크옵션에 사용 dll 파일의 임포트라이브러리(lib)을 추가
  • 사용 dll 파일 임포트 라이브러리(lib)을 프로젝트 디렉토리로 복사
  • 헤더 파일 포함

 extern "C" _declspec(dllimport)
BOOL Validate(LPSTR szID);


명시적링크(Explicit linking)

런타임에 직접 dll을 로드하므로, 임포트라이브러리가 필요없다.
LoadLIbrary로 호출하고, FreeLibrary로 해제할수 있다. 따라서, 효율적 메모리 사용이 가능하다.
먼저 함수타입을 선언해야한다.

tydef BOOL(*PFUNC)(LPSTR);
LoadLibrary API이용, 로드한다.

HINSTANCE  hLibInstance;
hInstance = LoadLibrary("TelnDLL");

dll 사용함수 메모리번지를 알아와서 포인터리턴시킨다. 함수인자와 반환형이 동일해야한다.

PFUNC pFunc = (PFUNC)GetProcAddress(hLibInstance,"CheckID");

사용후 메모리 해제한다.

FreeLibrary(hInstance);

HINSTANCE LoadLibrary(LPCTSTR lpLipFileName); lpLibFileName에서 지정한 dll 모듈을 로드해서, 핸들을 리턴
BOOL FreeLibrary(HINSTANCE hLibModule); hLibModule에 지정핸들이 가르키는 모듈을 해제.불값을 리턴
FASPROC GetProcAddress(HMODULE hModule,LPCTSTR lpProcName); LoadLibrary에서 리턴한 인스턴스핸들이 가르키는 모듈에서, lpProcName에 지정한
함수를 찾아 주소를 리턴한다.

이 글은 스프링노트에서 작성되었습니다.