이쿠의 슬기로운 개발생활

함께 성장하기 위한 보안 개발자 EverNote 내용 공유

코딩/C and C++

동적라이브러리 (DLL) 코딩 및 적용

이쿠우우 2020. 11. 30. 21:26
반응형

 

 

동적라이브러리 (DLL) 만들기

 

1. 프로젝트 생성

Visual Studio → New Project → Win32 Project → Project, Solution name : DLibrary → OK

 

 

2. Header 파일

#pragma once
#ifdef MAKE_DLL_TEST_EXPORTS //파일명(프로젝트명)_EXPORT
#define DLLTEST_API __declspec(dllexport) // 파일명_API __declspec(dllexport)
#else
#define DLLTEST_API __declspec(dllimport) // 파일명_API __declspec(dllexport)
#endif
extern "C" DLLTEST_API int dll_test_sum(int , int );
extern "C" DLLTEST_API int dll_test_sub(int , int );

 

2.1. 코드 분석

[ #ifdef 문 ]

MAKE_DLL_TEST_EXPORTS가 정의되어 있으면

DLLTEST 가  __declspec(dllexport) 가 되고

그렇지 않으면

DLLTEST 가  __declspec(dllimport) 가 된다.

즉 dll을 만들때는 dll 프로젝트 명과 동일하여 export 되고

dll 을 적용할 때는 import 가 된다.

 

[ __declspec(dllexport) 란? ]

__declspec은 함수의 특성을 지정하는 구문

dllexport용 함수라는 특성을 선언한다는 뜻

 

 

3. 소스 파일

#include <iostream>

#include "make_dll_test.h"

extern "C" DLLTEST_API int dll_test_sum(int a, int b) {

       return a + b;

}

extern "C" DLLTEST_API int dll_test_sub(int a, int b) {

       return a - b;

}

 

4. 빌드하면 정적라이브러리 (lib), 동적라이브러리 (dll) 생성됨

 


dll 과 lib 

 

[dll 이란?]

dll = 동적 라이브러리

실행 파일에서 해당 라이브러리의 기능을 사용 시에만, 

라이브러리 파일을 참조하여(혹은 다운로드받아) 기능을 호출함.

즉 프로그램이 실행 되었을 때 메모리에 적재 되어서
언제든지 이 라이브러리가 제공하는 함수에 대해 접근하고 사용할 수 있게 됨.

 

[lib란?]

lib = 정적 라이브러리

일반적으로 실행 파일을 만들 때는 소스 코드를 컴파일하고 만들어진 obj 파일을

링커가 하나로 묶어 exe 파일을 만듬

여기서 lib을 사용하면 링크 단계에서 링커가 이 lib파일도 같이 묶어서 하나의 exe 파일을 만듬

즉 빌드하여 만들어지는 exe 파일에 lib 내용이 모두 들어감

 

 

외부코드를 사용하기 위한 library로

dll = Runtime 중에 

lib = Complie 할때 필요함

 

 


묵시적 (암시적 Implicit) 연결 방법

 

1. (lib 파일 인식) 프로젝트 우클릭 속성 -> 구성 속성 -> 링커 -> 일반 -> 추가라이브러리 디렉터리

 

생성한 lib 파일의 위치를 추가

 

 

 

 

2. (lib 파일 인식) 프로젝트 우클릭 속성 -> 구성 속성 -> 링커 -> 입력 -> 추가 종속성

생성한 lib 파일의 이름을 추가

 

 

 

 

3. (header 파일 인식) 프로젝트 우클릭 속성 -> 구성 속성 -> C/C++ -> 일반 -> 추가 포함 디렉터리

dll 만들때 사용했던 header 파일의 경로를 넣어줌

 

 

 

4. (dll 파일 인식)프로젝트 우클릭 속성 -> 구성 속성 -> 디버깅 -> 환경

dll파일이 있는 폴더 경로를 환경변수로 넣어줌

예 : PATH=%PATH%;D:\동적라이브러리_Test\dll_lib_header

참고 : 간단한 방법으로는 dll 을 프로젝트가 있는 폴더에 넣어주면 자동으로 인식함

 

5. dll 적용 예제 코드

#include <iostream>
#include "make_dll_test.h"

void main() {
       int a = 5;
       int b = 3;
       int c, d;
       c = dll_test_sum(a,b);
       d = dll_test_sub(a, b);
       printf("a + b = %d\n", c);
       printf("a - b = %d\n", d);
}

 

6. 코드 추가 설명

위 코드는 Header 파일에 

extern "C" DLLTEST_API int dll_test_sum(int , int );

extern "C" DLLTEST_API int dll_test_sub(int , int );

가 명시되어 있어서 cpp 파일에 명시를 안했지만

header 에 명시하지 않은 경우 

cpp 파일에

extern "C" DLLTEST_API int dll_test_sum(int , int );

extern "C" DLLTEST_API int dll_test_sub(int , int );

를 명시하면 사용할 수 있음

 


 

명시적 연결 방법

 

명시적 연결을 사용하면 필요할 때 dll 에서 함수를 로드하여

특정 함수 포인터에 사용하려는 함수를 

맵핑시켜서 사용할 수 있음

 

 

1. (dll 파일 인식)프로젝트 우클릭 속성 -> 구성 속성 -> 디버깅 -> 환경

명시적 연결 방법은 DLL 만 환경변수로 바라보면 가능함

dll파일이 있는 폴더 경로를 환경변수로 넣어줌

예 : PATH=%PATH%;D:\동적라이브러리_Test\dll_lib_header

참고 : 간단한 방법으로는 dll 을 프로젝트가 있는 폴더에 넣어주면 자동으로 인식함

 

 

2. 예제 코드

#include <iostream>

#include <windows.h>

typedef int(*pDLLFunction)(int, int);

pDLLFunction pFunction = NULL;

 

int main() {

       int a = 5;

       int b = 3;

       int c, d;

       HMODULE hMod = NULL;

       hMod = LoadLibraryA("make_dll_test.dll");

       if (hMod == NULL)

       {

              printf("DLL Load Failed.\n");

              return 0;

       }

       pFunction = (pDLLFunction)GetProcAddress(hMod, "dll_test_sum");

       c =  pFunction(a, b);

       pFunction = (pDLLFunction)GetProcAddress(hMod, "dll_test_sub");

       d = pFunction(a, b);

       printf("a + b = %d\n", c);

       printf("a - b = %d\n", d);

       return 0;

}

 

 

3. 코드 설명

[ 1 ]

typedef int(*pDLLFunction)(int, int);
pDLLFunction pFunction = NULL;

pDLLFunction이라는 함수 포인터 자료형을 선언하고,

pFunction이라는 함수 포인터를 만들고, 이를 NULL로 초기화.

이 pFunction이라는 함수 포인터에 외부 DLL의 함수를 맵핑

 

 

[ 2 ]

HMODULE hMod = NULL;
hMod = LoadLibraryA("make_dll_test.dll");
if (hMod == NULL)
{
      printf("DLL Load Failed.\n");
      return 0;
}

[ HMODULE 설명 ]

dll를 담아둘 수 있는 자료형

hMod 를선언하고 정의한 뒤에

상위에서 만들어두었던 make_dll_test.dll을 불러들임

이 때 사용되는 함수가 LoadLibraryA()라는 함수임.

이 함수는 dll파일을 불러들이지 못하는 경우 NULL을 리턴하며,

이 경우에 대한 예외처리를 해주어야함

dll파일이 불러들여졌다면

해당 dll파일에서 우리가 호출하고자 하는 함수를 불러들여야함

상위 DLL 만들기 프로젝트에서 만들어 두었던dll_test_sub dll_test_sum함수를 불러와야함

 

[ HMODULE 관련 오류 정리 ]

DLL 관련 오류

  • 해당 DLL 라이브러리가 물고있는 DLL도 있어야 정상적으로 인식함

193 error

  • 1) 라이브러리는 봤지만 해당 라이브러리 Bits 가 맞지 않음,
  • 2) 해당 라이브러리와 연동되어있는 다른 dll 을 인식하지 못해서 오류발행
  • 해결책 = 프로그램이 실행되는 경로에 dll 을 모두 같이 넣어줘야함

126 erro

  • 라이브러리 경로 자체를 찾기 못한상황
  • 해결책 = 라이브러리 경로를 다시 확인

 

[ 3 ]

pFunction = (pDLLFunction)GetProcAddress(hMod, "dll_test_sum");
c =  pFunction(a, b);

pFunction에 pDLLFunction타입의 함수인 dll_test_sum 이름의 함수를 hMod라는 dll로부터 불러들인다는 뜻

함수명은 GetProcAddress 를 통해 매칭시킴

pFunction 함수에 dll_test_sum이 함수를 통해 a, b를 넘겨 리턴되는 값을 받음

 

 


 

 

 

 

반응형

'코딩 > C and C++' 카테고리의 다른 글

C++ windows 로컬 그룹 정책 확인  (1) 2021.12.22
C++ Windows console 결과 영어로 출력  (0) 2021.12.22
네임드 파이프 (Named-Pipe)  (0) 2020.10.04
C++에서 JSON 사용  (4) 2020.09.13
JSON  (0) 2020.09.13