티스토리 뷰

190705-4 - _DLLPRE extern "C" __declspec(dllexport), __declspec(dllexport) void Print(int a, int b)
 
교육을 받으면서 노트필기 했던 내용을 날것 그대로 업로드합니다. 

 
라이브러리
  • 다이나믹 링크 라이브러리(DLL) : 실행시간에 결정
  • 스테틱 링크 라이브러리(LIB) : 
 
빌드  
  •               A.c     B.c (텍스트 레벨)
  • 컴파일 작업 : A.obj , B.obj (바이너리 레벨)
  • 링크 작업
  • EXE 생성. (.lib 가 포함) -> 동일한 라이브러리를 포함해서 사용하는 문제가 있을 수 있다.
 
DLL 이라는 개념을 만들어낸다. 
 
우선은 static lib 부터 해보자.
 
라이브러리 : 컴파일완료된 바이너리 데이터 (함수 등의 집합이다.)
 
라이브러리 제공자 = 서버
라이브러리 사용자 = 클라이언트
 
  • 라이브러리
  • .h
  • 도움말
위 세가지를 같이 넘기게 된다.
 
#ifndef/#define/#endif : include 가드 (#pragma once : 사용자정의 전처리기 컴파일러마다 다르게 받아들인다.)
 
라이브러리 만들기
 
라이브러리 사용하기
라이브러리 추가
 
오브젝트 추가하기
obj가 있는 디렉터리 추가
 
lib, obj 무게는 똑같다.
 
이후 빌드하면 exe에 알아서 포함된디. (static 라이브러리는 exe에 포함되는 형태로 보관된다.)
 

 
이제 dll 해보자
 
주의 : dll은 실행시간에 메모리를 생성하고 메모리에 생성한 함수를 매핑하는 작업을 해야한다.
 
dll 가져다 쓰는 방법 : import
 
클라이언트 에서는 import
dll 에서는 export
 
explicit (명시적) 가져다 쓰는 것을 알고 가져다 쓴다. : 직접 가져다 써야되니까 dll을 메모리에 띄우는 LoadLibrary를 써야한다. 다 쓰고 난 후에는 라이브러리를 메모리 상에서 제거하는 FreeLibrary를 사용한다. 로드했으면 메모리상에 dll함수를 매핑시키는 getProcAddress 함수를 사용해야한다. 나머지는 에러처리다. 장점: dll라이브러리만 있으면 다른건 필요없다. 도움말만 있으면 라이브러리만 있으면 가져다 쓸 수 있다는 장점이 있다.
 
implicit (암묵적) 가져다 쓰는 것을 모르고 가져다 쓴다. : dll을 전달해야한다. dll은 실제 내용물을 가지고는있지만 메모리상에 업로드시키거나 매핑시키거나 하는 작업을 해야한다. 그래서 그런 기능을 자동적으로 해주는 것을 stub code(?) 라고 부르는 껍데기 코드정도가 .lib로 만들어진다. .lib가 해주는 역할은 자동적으로 로드,언로드,매핑 시켜주는 역할을 한다. .lib는 exe에 같이 묶이니까 lib가 자동적으로 로드,언로드,매핑 하는 작업을 해준다. 함수 헤더가 필요하다. (.h)  도움말(선택) 필요하다. 
 
.lib는 링크할 때 필요하고 -> exe 생성후 -> 실행시간에 dll이 필요하다.
dll 사용해보자
#include <stdio.h>
extern "C" __declspec(dllexport) void Print(int a, int b)
{
    printf("%d, %d\n", a, b);
}
 
c와 cpp 컴파일 방법이 다르다. 그래서 extern 에 명시한다.
 
설정 이후 F6
 
우선 암묵적인 import를 써보자
#ifndef PRINT_SWAP_HHH
#define PRINT_SWAP_HHH
 
#ifdef _DLLSERVER
#define _DLLPRE extern "C" __declspec(dllexport) // dll에서 사용 서버에서 export 할때
#else
#define _DLLPRE extern "C" __declspec(dllimport) // 사용자가 필요 클라이언트가 사용하고 싶을 때
#endif
 
_DLLPRE void Print(int a, int b);
_DLLPRE void Swap(int* pa, int* pb);
 
#endif
정의 되면 export를 하게되는 것이다.
 
이제 클라이언트 부분이다.
3개를 가져온다.
여기 까지 하고 실행하면 완료가 된다. 여기 까지가 암묵적인 실행 방법이었습니다.
 
이후 exe만 가지고 나가서 실행하면 위 오류가 뜬다. dll이 있어야 되는 곳에 있어야된다. 보통 윈도우즈/시스템 디렉토리다 
 
또는
옮기면 정상실행이된다.
 

 
명시적 dll 가져다 쓰기
dll 하나만 있으면된다 (도움말(선택))
#include <Windows.h>
#include <stdio.h>
int main() {
    HMODULE hDll = NULL;
    int a = 10, b = 20;
 
    hDll = LoadLibrary("DllLibraryEx");//.dll 생략가능
    if (hDll == NULL){
        printf("Dll 로드 실패");
        return -1;
    }
    
    void (*print)(int, int);
    print = (void (*)(int, int))GetProcAddress(hDll, "Print"); // 매핑된 함수의 시작주소를 반환 -> 함수포인터 필요
 
    void (*swap)(int*, int*);
    swap = (void (*)(int*, int*))GetProcAddress(hDll, "Swap"); // 매핑된 함수의 시작주소를 반환 -> 함수포인터 필요
 
    if (NULL != print && NULL != swap) {
        int a = 100;
        int b = 500;
 
        print(a, b);
        swap(&a, &b);
        print(a, b);
    }
    FreeLibrary(hDll);
}

지금 까지는 함수를 가져다 썼다. 이제 클래스를 가져와서 써보도록 하자. 클래스는 타입이다 보니 명시적으로 가져다 쓸 수 있는 방법은 없다. java 등은 exe나 dll에 메타정보라고 해서 타입의 정보를 넣어논다. (리플렉션 기능)
 
dll에 클래스의 매소드의 정의를 넣어놓고 클라이언트에서 불러서 사용을 해봅시다.(암묵적 방법 밖에 없다.)
 
.net 도 dll과 exe다. 외형적으로 구분이 불가능하다. 네이티브dll과 .net의 dll은 전혀다르다. .net은 버츄얼머신에서 돌아가는코드다.
 
클래스의 정의는 헤더에, 메소드의 정의는 cpp
 
타입(클래스) : 시작이 대문자
 
리펙토링의 가장 기초는 명명이다.
 
우리는 서버역할로 먼저
빌드
생성됨.
DllClass.lib 추가
오류. (.exe에 같이 놓던가 path를 설정한다.)
같은 공간에 둔다
실행이 되는 것을 확인할 수 있다.
댓글
댓글쓰기 폼
네이버 이웃추가
«   2019/10   »
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
글 보관함