본문 바로가기
프로그래밍/Windows API

동적 링크 라이브러리(DLL) 사용 / 만들기 #1

by 호군 2010. 11. 16.
반응형
동적 라이브러리를 보기 전에 정적 라이브러리를 먼저 살펴 보겠습니다.


O 정적 라이브러리(.LIB)

  정적 라이브러리(lib)를 만드는 법은 간단합니다. Visual Studio 2008에서 프로젝트 구성 형식을 정적 라이브러리(.lib)로 만들고 실행을 하면 되기 때문입니다. 이용을 하려면 이 라이브러리(.lib)해더 파일(.h)을 이 라이브러리를 이용할 프로젝트에 추가해주면, 이용 또한 쉽습니다.

  - 프로젝트에 추가 방법 [첫번째]
 1. [프로젝트 -  속성] 선택
 2. [링커 - 일반]탭을 선택 후, '추가 라이브러리 디렉터리'에 lib 파일의 경로를 추가.
 3. [링커 - 입력]탭을 선택 후, '추가 종속성' 란에 lib 파일을 입력하고, 확인을 누름.

  - 프로젝트에 추가 방법 [두번째]
 1. main.cpp(App 소스코드를 말함)에서 아래와 같이 입력합니다.
#include "XXX.h" // .h 파일의 경로를 입력한다. 또는 프로젝트에 그 폴더를 포함시킨다.
#pragma comment(lib, "XXX.lib") // lib경로를 입력해야한다. 속성창에서 하는 일과 같다.

void main()
{
   ......
}



O 동적 라이브러리(.DLL)
  동적 라이브러리 또한 정적 라이브러리와 같이 사용이 가능합니다. dll로 프로젝트를 만들고 실행을 하게 되면 dll과 lib 파일이 생성됩니다. 여기서 lib파일에는 dll에 구현된 함수를 찾을 수 있는 정보가 있습니다.(저두 본거라...) 그래서 정적 라이브러리와 같은 방법으로 사용이 가능합니다. 이런 방식을 '암시적 연결'이라고 합니다.
   암시적 연결 방법만 있는 것은 아닙니다. 명시적 방법 또한 있습니다. 이 방법은 dll 파일만 있어도 사용 할 수 있습니다. 하지만 C스타일의 함수여야 하는 듯 합니다. 아래를 보시면 아시겠지만 함수의 이름으로 주소를 얻어오기 때문에 C++에서 사용 할 수 있는 오버로딩이 되지 않습니다. 오버로딩이란 함수의 이름은 같지만 매개변수가 다를 경우 다른 함수로 간주 하는 것을 말합니다.
  한번 코드로 정리 해보겠습니다. 첫번째는 헤더와 lib파일을 이용해서 dll을 사용하는 방법입니다. 

 - DLL 소스코드
//Swap.h
#ifndef __SWAP_H__
#define __SWAP_H__


#ifdef DLL_EXPORT
    #define DLLTYPE __declspec(dllexport)
#else
    #define DLLTYPE __declspec(dllimport)
#endif //DLL_EXPORT

extern "C" DLLTYPE void SwapInt(int* dest, int* src);
extern "C" DLLTYPE void SwapStr(char* dest, char* src, int size);

#endif //__SWAP_H__

//Swap.cpp
#define DLL_EXPORT
#include "Swap.h"
void SwapInt(int* dest, int* src)
{
    int temp = *dest;
    *dest = *src;
    *src = temp;
}
void SwapStr(char* dest, char* src, int size)
{
    char* pcTemp = new char[size];
    for(int i = 0 ; i < size ; i++)
    {
        pcTemp[i] = dest[i];
        dest[i] = src[i];
        src[i] = pcTemp[i];
    }
    delete [] pcTemp;


 - App 소스코드1 (.h + .lib 이용하여 dll 함수 호출)
#include <stdio.h>
#include <windows.h>
#include <tchar.h>

#include "..\SwapDll\Swap.h"
#pragma comment(lib, "..\\Debug\\SwapDll.lib")

int main()
{
    int a = 10, b = 20;

    printf("\t\ta : %d, b : %d\n", a, b);
    SwapInt(&a,&b); 
    printf("swap --> \ta : %d, b : %d\n", a, b);

    return 0;
}


- App 소스코드2 (WinAPI를 이용하여 dll 함수 호출)
#include <stdio.h>
#include <windows.h>
#include <tchar.h>

typedef void (*Func)(int*, int*);
int main()
{
    int a = 10, b = 20;
    
    HINSTANCE hDll = LoadLibrary(_T("SwapDll.dll"));
    if(hDll == NULL)
    {
        printf("dll 로드 실패\n");
        return -1;
    }
    Func pFunc = (Func)GetProcAddress(hDll, "SwapInt");
    Func pFunc1 = (Func)GetProcAddress(hDll, "SwapStr");
    printf("\t\ta : %d, b : %d\n", a, b);
    pFunc(&a,&b); 
    printf("swap --> \ta : %d, b : %d\n", a, b);
 
    FreeLibrary(hDll);
    return 0;
}


  위의 소스코드는 코드 작성 이외의 다른 설정은 하지 않았습니다. dll의 구현은 함수 단위로 되어있습니다.
  dll을 클래스 단위로 구현한다면 어떻게 사용해야 할까요? 코드로 보겠습니다.

- DLL 소스코드(Class)
//SwapClass.h
#ifndef __SWAP_CLASS_H__
#define __SWAP_CLASS_H__

#ifdef DLL_EXPORT_CLASS
    #define DLLTYPE __declspec(dllexport)
#else
    #define DLLTYPE __declspec(dllimport)
#endif //DLL_EXPORT_CLASS

class DLLTYPE CSwapClass
{
public:
 CSwapClass();
 ~CSwapClass();
 void Int(int* dest, int* src);
 void String(char* dest, char* src, int size);
};

#endif //__SWAP_CLASS_H__

//SwapClass.cpp
#define DLL_EXPORT_CLASS
#include "SwapClass.h"

CSwapClass::CSwapClass()
{
}
CSwapClass::~CSwapClass()
{
}
void CSwapClass::Int(int* dest, int* src)

    int temp = *dest;
    *dest = *src;
    *src = temp;
}
void CSwapClass::String(char* dest, char* src, int size)
{
    char* pcTemp = new char[size];
    for(int i = 0 ; i < size ; i++)
    {
         pcTemp[i] = dest[i];
         dest[i] = src[i];
         src[i] = pcTemp[i];
    }
    delete [] pcTemp;
}


- App 소스코드 (Class)
#include <stdio.h>
#include <windows.h>
#include <tchar.h>

#include "..\SwapClassDll\SwapClass.h"
#pragma comment(lib, "..\\Debug\\SwapClassDll.lib")

int main()
{
    int a = 10, b = 20;
    CSwapClass swaper;
 
    printf("\t\ta : %d, b : %d\n", a, b);
    swaper.Int(&a,&b); 
    printf("swap --> \ta : %d, b : %d\n", a, b);
    return 0;
}

  위와 같이 사용한다면 class 또한 사용이 가능합니다. 만약에 암시적으로 사용하고 싶다면, LoadLibrary() 함수와 GetProcAddress () 함수를 사용해야 하야 합니다. 하지만 GetProcAddress() 함수에 들어가는 두번째 매개변수는 함수명 또는 서수가 들어가야 합니다. C++의 함수는 사용 할 수 없기 때문에 [extern "C"] 를 사용해야 합니다. 그래서 그 함수에서는 new CSwapClass()를 반환한다면 사용이 가능합니다.


LibraryExample.zip




※ 암시적 연결을 사용해서 함수 호출을 할려했더니 저는 애러는 나지 않았는데 정확한 주소
  를 못 얻어오더군요.. 좀 더 공부를 해봐야 할 듯  합니다.

지금까지 암시적/명시적 연결로 DLL을 사용하는 방법을 알아봤습니다. 모두 열공하세요.

ps. Error C2491이 발생하신 분은 한번 보시기 바랍니다.(Microsoft 영문)
      링크 : http://support.microsoft.com/kb/815647/en-us/
반응형