정적 라이브러리는 #include<stdio.h> 와 같이 인클루드 시키는 printf,scanf 와 같은 함수들이 있는 라이브러리

=> 컴파일시에 해당 라이브러리 코드가 실행 파일과 합쳐진다.

printf문을 쓰는 5개의 프로그램이 있다면


| 프로그램 1  (printf코드) |
| 프로그램 2  (printf코드) |
| 프로그램 3  (printf코드) |
| 프로그램 4  (printf코드) |
| 프로그램 5  (printf코드) |

와 같이 각각의 프로그램마다 printf 코드가 들어간다.. 왜냐 하면 컴파일시에

정적으로 해당 라이브러리 가 합체되어 컴파일 되기 때문이다.

그래서 똑같은 코드가 프로그램마다 합쳐저서 용량이 늘어나는 단점이 있다..



DLL = 동적 링크 라이브러리 Dynamic link Library

하지만  동적링크라이브러리는 다르다...

해당 라이브러리는 일단 메모리에 한번 올리고..

프로그램들이 그 라이브러리를 필요할때 메모리에 올라와 있는걸 가져다 쓰기만 하면된다.

만약 printf 코드를 동적라이브러리로 만들었다고 가정하고

그 동적라이브러리를 쓰는 5개의 프로그램이 있다면


-----------  메모리 ---------------
|  메모리에 printf 라이브러리 코드 딱 한번 로드 (주소 0x10001050) |
-----------  메모리 ---------------


| 프로그램 1 (0x10001050) 호출) |
| 프로그램 2 (0x10001050) 호출) |
| 프로그램 3 (0x10001050) 호출) |
| 프로그램 4 (0x10001050) 호출) |
| 프로그램 5 (0x10001050) 호출) |


해당 프로그램들은 덩치큰 라이브러리 코드들은 포함하고 있는게 아니고

그냥 해당 코드가 있는 메모리 주소를 불러오는 간단한 하고 조그만한 코드가 있으므로

프로그램 용량이 줄어들것이다..

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





글엄 간단한 DLL파일을 만들어 보자..

비주얼 c++ 6.0 에서 프로젝트 만들때  Win32 Dynamic-Link Library  라는 옵션을 주어서

만들면 된다. 아래에서 아주 간단한 함수 하나를 만들어보고  이 함수를 export 시켜서

일반 실행파일에서 쓰는 예제를 만들어 보자

------------------- test.cpp ----------------------

int Sum(int a, int b)

{

 return a+b;

}

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

다.. 만들었다... 죠낸 간다하다 -_-ㅋ 그렇다.

그냥 두 수를 인자로 받고 더 해서 결과를 리턴해주는 아주 죠낸 초 간단 함수이다.

이 함수를 dll파일로 만들었으니.. 이 함수는 동적링크 라이브러리 되시겠다... 

WinMain 필요없다.. main 도 필요없다.

그냥 우리가 필요한 함수만 딱 써놨다.. 그래도 된다.. -_-ㅋ


컴파일하면 test.dll 파일이 생성될것이다.



그렇다면 이 dll파일을 사용하는 일반 실행파일을 만들어보자..

일단 이 dll파일을  실행하려는 실행파일에 같은 폴더에 넣는다..

그리고 해당 실행파일이 이 dll을 불러오고.. 그리고 또  dll 않에 있는 함수를

사용하는 예제는 아래와 같다.




------------------ usedll.cpp ------------------

#include <windows.h>

#define DLL_NAME "test.dll" // 불러 오려는 dll 이름이다.
#define DLL_FUNC "Sum" // 불러 오려는 함수 이름이다.


void Error(LPCTSTR str);
void Printf(LPCTSTR str);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
 HMODULE hModule;
 LPVOID lpFunc = NULL;
 TCHAR buf[512];

 hModule = LoadLibrary(DLL_NAME);

 if(!hModule)
 {
  Error("LoadLibrary Error");
 }
 else
 {
  wsprintf(buf,"hModule = 0x%8x\n",hModule);
  Printf(buf);
 }

 lpFunc = GetProcAddress(hModule,DLL_FUNC);

 if(!lpFunc)
 {
  Error("GetProceAddress Error");
 }
 else
 {
  wsprintf(buf,"lpFunc = 0x%8x\n",lpFunc);
  Printf(buf);
 }

 return 0;
}

void Error(LPCTSTR str)
{
 MessageBox(HWND_DESKTOP,str,"ERROR",MB_OK);
 ExitProcess(1);
}

void Printf(LPCTSTR str)
{
 MessageBox(HWND_DESKTOP,str,"OK",MB_OK);
}

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




우의 코드는 실제로 함수를 사용하지 않고 그냥 dll을 로드하고 그 함수 주소를 얻어오는 코드인데

일단 함수 주소만 알면 언제든지 불러올수 있으므로 함수 주소를 얻는 코드까지만 작성했다.

이상이 없다면 모듈주소와 함수주소가 출력될것이다.

하지만 안타깝게도 위의 실행파일을 실행하면 DLL 파일은 찾을수 있지만

함수 주소는 찾을 수 없다는 에러를 발생시킨다......

그 이유는 .... 그 이유는... 그 이유는.....

dll 않에서 만든 함수는 외부로 수출???(export) 되야 하는 것이다.. 이것들은 특별하기 때문에

컴파일시에 이 함수는 외부로 링크될 함수야!!!!!! 라고 알려줘야 한ㄷ고 한다.......... 우리는 그 작업을 안한 것이다. -_-;;;


콘솔창으로 들어가서 해당 dll 파일이 있는 위치로 이동후

dumpbin /EXPORTS test.dll      <-- 라고 쳐보자... 이 명령어는 해당 dll 파일에서 export (수출하는 함수?) 리스트를 보여달라고 하는것이다.

결과 화면을 보면 수출하는 함수가 없다고 뜰 것이다...


그러면 export를 수출 하는 두가지 방법이 있다고 하는데.. 그 방법을 살펴보자

첫번째 방법 : 모듈 정의 파일 사용 (.def 파일사용)

두번째 방법 : __declspec(dllexport) 지시자 사용




[첫번째 방법 : 모듈 정의 파일 사용 (.def 파일사용)]


비주얼 컴파일에 프로젝트에서 소스파일 추가 하여 확장자를 .def 라고 하고 cpp 파일과 동일한 파일명으로 하나 만든다.

그리고 그 .def 파일에 다음과 같이 써보자


----------------------- dll.def --------------------------------------------

LIBRARY  
EXPORTS
 Sum   @1

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

LIBRARY  DLL      <-- 라이브러리 이름이다..

EXPORTS                                   <-- export (수출) 할 함수들 리스트 들

 Sum <-- 함수명  @1    <-- 서수지정..

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


대략 설명은 이렇다... 이렇게 def 파일을 정의하고 다시 컴파일 한 후!!!

생성되는 dll 파일을 다시 dll을 이용하는 실행파일에 넣고 하면!!

아무런 에러 없이 함수 주소를 가져올 것이다.

그리고.. dumpbin /exports test.dll 이라고 하면 전에 없던 export 라는 부분에서 수출하려는 함수 목록으로 Sum이라는 함수가 나타날 것이다...

 

 




반응형

+ Recent posts