실행파일에서 DLL의 함수를 호출하는 방법에는 다음 두가지가 존재한다.

암시적연결

함수가 어느 DLL에 있는지 밝히지 않고 그냥 사용함. 프로젝트에 임포트 라이브러리를 포함해야 하며 윈도우즈는 임포트 라이브러리의 정보를 참조하여 알아서 DLL을 로드하고 함수를 찾는다. 클라이언트 프로그램이 로드 될 떄 LL이 같이 로드되거나 이미 DLL이 로드되어 있으면 사용 카운트를 1증가시킨다. 클라이언트 프로그램이 실행될 떄 DLL이 로드되므로 실행시 연결이라고 함.


명시적 연결


어느 DLL에 있는 함수인지를 밝히고 사용하는 방법이다. 클라이언트 프로그램이 실행될 때 DLL이 로드되는 것이 아니라 로드하라는 명령이 있을 때 로드된다. 필요할 때 선택적으로 DLL을 로드하므로 상황에 따라 리소스 교체가 가능하며 함수가 속해있는 DLL의 이름을 명시적으로 지정하여 호출하므로 임포트 라이브러리는 불필요하다. 클라이언트 프로그램 실행중에 DLL이 메모리로 읽혀지므로 실행중 연결이라고 한다.


--출처 : 윈도우즈 API 정복


위 방법 중에 암시적연결을 한번 해보자.


전에 포스팅 했던 대로 DLL 프로젝트를 하나 연다음에(DLL Project & complie)


사진과 같이 써주고 컴파일을 하면


위와 같이 DLL파일과 lib파일이 만들어 진것을 볼수 있다.

DLL에서는 제공하고자 하는 함수의 정보를 밖으로 공개해 놓아야 하며 이를 export라 하고 클라이언트에서 이 함수를 사용하는 것을 import라고 한다.

즉 함수를 제공하는 측은 선언을 해야 하는데 __declspec함수가 이 기능을 한다.


__declspec(extended-attribute) declarator 

__declspec함수는 괄호안에 4가지의 인수를 가질 수 있고 그 인수는 다음과 같다.


thread : TLS(Thread Local Storage)데이터로 지정한다. 이 지정자가 붙은 변수는 해당 스레드에서만 사용가능


naked : prolog,epilog,를 생성하지 않고, 어셈블리 언어를 사용하여 직접 prolog ,epilog를 달고자 할 때 사용한다.


dllimport : DLL에 있는 데이터, 오브젝트 함수를 임포트한다. DLL에 있는 이렇게 생긴 함수를 앞으로 사용하겠다는 선언이다.


dllexport : DLL에 있는 데이터, 오브젝트,함수를 엑스포트한다. DLL을 사용하는 클라이언트에게 DLL의 정보를 명시적으로 제공하는 역할을 한다.

이제 새로운 cpp 프로젝트를 하나 만들고


#include<Windows.h>


extern "C" __declspec(dllimport) int add(int a, int b);


LRESULT FAR PASCAL WndProc(HWND, UINT, UINT , LONG);


int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)

{

static char szAppName[]="Hello Win";

MSG msg;

HWND hwnd;

WNDCLASS wndclass;


if(!hPrevInstance)

{

wndclass.style = CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc=WndProc;

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = hInstance;

wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION);

wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);

wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName = szAppName;

wndclass.lpszClassName = szAppName;


RegisterClass(&wndclass);

}

hwnd = CreateWindow(szAppName,"Hello Win Demo",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);

ShowWindow(hwnd,nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg,NULL,0,0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}


LRESULT FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)

{

HDC hdc;

PAINTSTRUCT ps;

RECT rect;

char str[128];

static HINSTANCE hinstDll;

static HHOOK hKeyHook;

static int count =0;


switch(message)

{

case WM_PAINT:

hdc = BeginPaint(hwnd,&ps);

GetClientRect(hwnd,&rect);

DrawText(hdc,"hello,Windows!",-1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);

EndPaint(hwnd,&ps);

return 0;

case WM_LBUTTONDOWN:

wsprintf(str,"1+2 = %d",add(1,2));

MessageBox(NULL,str,"result",MB_OK);

return 0;

case WM_DESTROY:

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hwnd,message,wParam,lParam);

}


위 소스를 입력해주고 컴파일 하면 완료!인 줄 알았지만 ㅠㅠ

아무런 설정도 안해줬기 때문에 우리의 DLL을 찾을수가 없다.따라서



솔루션 탐색기에서 프로젝트에서 우클릭하고 속성에서 


링커 밑에 Input에 첫번째에 다음과 같이 아까만들었던 lib파일 이름을 적어준다.

그리고 만들어졌던 dll파일과 lib파일을 우리가만들고 있는 프로젝트 소스파일과 같이 놔주면 된다. 



컴파일한후에 실행하면....



윈도우 창이 뜬다

WndProc에 설정했던 LBUTTONDOWN을 실행시키면(마우스 좌클릭)



dll에 있는 add함수를 실행하여 3이란 결과값을 가져온후에 실행파일에 있는대로 MessageBox를 띄운다.! ㅠㅠ 



명시적 연결


#include<Windows.h>

#pragma comment(lib,"dll.dll")


LRESULT FAR PASCAL WndProc(HWND, UINT, UINT , LONG);


int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)

{

static char szAppName[]="Hello Win";

MSG msg;

HWND hwnd;

WNDCLASS wndclass;


if(!hPrevInstance)

{

wndclass.style = CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc=WndProc;

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = hInstance;

wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION);

wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);

wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName = szAppName;

wndclass.lpszClassName = szAppName;


RegisterClass(&wndclass);

}

hwnd = CreateWindow(szAppName,"Hello Win Demo",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);

ShowWindow(hwnd,nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg,NULL,0,0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}


LRESULT FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)

{

HDC hdc;

PAINTSTRUCT ps;

RECT rect;

char str[128];

static HINSTANCE hdll;

static HHOOK hKeyHook;

static int count =0;

int (*pFunc)(int,int);

switch(message)

{

case WM_PAINT:

hdc = BeginPaint(hwnd,&ps);

GetClientRect(hwnd,&rect);

DrawText(hdc,"hello,Windows!",-1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);

EndPaint(hwnd,&ps);

return 0;

case WM_LBUTTONDOWN:

hdll=LoadLibrary("dll.dll");

pFunc=(int (*)(int,int))GetProcAddress(hdll,"add");

wsprintf(str,"1+2 = %d",(*pFunc)(1,2));

MessageBox(NULL,str,"result",MB_OK);

    FreeLibrary(hdll);

return 0;

case WM_DESTROY:

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hwnd,message,wParam,lParam);

}


위 암시적 연결과 기능은 똑같지만 명시적으로 연결하는 소스이다.


#pragma comment(lib."dll.lib");


이 지시자는 컴파일러의 라이브러리 관리 모듈에게 dll.lib를 검색해 보도록 하는 명령이다. 소스에서 곧바로 임포트 라이브러리를 지정할 수 있어 편리함.


HINSTANCE LoadLibrary(LPCTSTR lpLibFileName);


이 함수는 지정한 DLL을 메모리로 읽어와 현재 프로세스의 주소 공간에 맵핑시켜 사용할 수 있도록 하되 DLL이 이미 메모리에 올라와 있는 상태라면 사용 카운트만 1증가시킨다. 

DLL을 읽어오는데 성공하면 DLL의 모듈 핸들을 리턴하며 이 핸들은 GetProcAddress함수에서 사용된다. 에러 발생시 NULL 리턴.


FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName);


DLL에서 엑스포트한 함수의 번지를 찾아 그 함수의 함수 포인터를 리턴한다. 첫 번째 인수hModule은 함수가 포함된 DLL의 모듈핸들이고 LoadLibrary 함수가 리턴한 값이다.두번째 lpProcName은 찾고자 하는 함수의 일므을 지정함.


BOOL FreeLibrary(HMODULE hLibModule);


DLL 카운터를 1감소시키며 사용 카운트가 0이 되었을 경우 메모리에서 DLL을 삭제한다. 

'System > Windows' 카테고리의 다른 글

MSG Struct  (0) 2012.09.18
PE struct  (0) 2012.08.30
DLL  (0) 2012.08.21
visual studio DLL complie  (0) 2012.08.21
Message HOOK - Window  (0) 2012.08.20

+ Recent posts