1부. MFC 확장 DLL을 만들어보자

1. 필요한 MFC, C++ 클래스를 지정하여 새로만들기에서

프로젝트 만들기에서 MFC App Wizard(dll) DLL 을 선택한다.

다음은 MFC Extension DLL(using shared MFC DLL)을 선택한다.

2. MFC를 지원하지 않는 프로그래밍 언어에서는 사용할수 없지만

비교적 간단히 만들고 코딩이 쉽다

익스포트할 클래스에 대해서 AFX_EXT_CLASS 매크로만 붙여주면 된다

이렇게...

class AFX_EXT_CLASS Cpsd
{
public:

};

즉, 이 클래스를 다른 비주얼 C++ 애플리케이션에서 사용될 수 있도록 익스포트 하겠다는 뜻이다

이 클래스를 가지고 있는 DLL에 링크될 애플리케이션에 의해 사용되는 헤더 파일에 이 매크로를

반드시 포함시켜야 클래스를 제대로 임포트할 수 있다.

DLL의 링크

호출하는 방법은 implicit 과 explicit 방법이 있는데

우선 여기선 조금쉬운 방법인 implicit방법을 먼저 하자

위에서 DLL을 만들때 같이 만들어 지는 lib를 이용한다.

여기서 lib에 대해 언급하면...

링크될때 링커는 이 lib파일을 표준 라이브러리 처럼 다루어 처리하지만, dll을 끌어오는

lib파일은 dll이 익스포트한 함수 각각에 대한 stub(함수 호출에 쓰이는 정보를 일컬음)만을 포함

함수 스텁은 사실 진짜 함수와 동일한 이름과 인수 리스트를 가진 pseudo 함수로서,

내부를 살펴보면 스텁에 필요한 모든 인수를 넘겨서 DLL에 들어있는 진짜 함수를 호출하는

짤막한 코드가 들어있다.

이렇게하면 DLL의 함수를 분리된 파일이 아니라, 애플리케이션 코드의 일부인 것처럼

다루게 된다

LIB 파일을 임포트 라이브러리라고 부른다.

<2>DLL의 링크

DLL를 링크하는 방법은 Implicit 링킹과 Explicit 링킹 두가지 방법이 있습니다.

(1)Implict 링킹

“DLL이 있어서 DLL이 바로 동적 링크되는데 LIB 파일이 왜 필요한가?”

이렇게 물어보는 사람도 있을 것입니다. 이유는 메인프로그램을 컴파일하고 링크할 때 DLL 안에 있는 함수들은 메인프로그램에는 어느 것과도 링크되어 있지 않아 실행 파일로 만들 때 에러가 나오기 때문입니다. 예를 들어, PaintImage(LPSTR  filename);이라는 함수를 DLL로 만들어 놓고 메인프로그램에서 헤더에 extern "C"__declspec(dllimport)void PaintImage(LPSTR filename);이라고 정의하면 컴파일은 하지만 링크할 때 PaintImage 함수를 찾을 수 없다고 하며 에러를 리턴하고 실행 파일을 만들 수 없게 됩니다. 따라서, PaintImage라는 함수를 가상으로 만들어 그것을 0으로 설정해 주는 하나의 함수가 있어야 합니다.

void PaintImage(LPSTR  fileanem)=0;

이렇게 만들어진 함수가 컴파일되어 LIB로 만들어집니다. 따라서, 메인프로그램에서는 실행 내용이 아무것도 들어 있지 않은 LIB를 프로젝트에 삽입하고 컴파일하는 것이죠. 그런 후 프로그램이 실행되면 LIB에 설정된 파일명에 따라 DLL을 로드하고 프로그램 메모리 안에 DLL에서 로드시킨 PaintImage 모듈을 삽입시키게 됩니다. 결국 우리는 DLL을 만들고 난 후 3가지의 파일을 이용해서 메인프로그램을 제작하게 되는 것입니다. 이 3가지 파일은 다음과 같습니다.

① 실질적으로 프로그램이 실행될 때 로드되는 DLL 파일(*.DLL)

② 컴파일할 때 설정해 주는 함수명이 들어 있는 헤더 파일(*.H)

③ 링크할 때 메인프로그램에 빈 함수를 설정하는 LIB 파일(*.LIB)

(2)Explicit 링킹

Explicit 링킹 방법이란 Implict 링킹 처럼 3가지의 파일이 필요가 없이 단순하게 DLL를 이용하여 로드할수 있는 방법을 의미합니다. 이방법으로 DLL를 로드할경우 3개의 함수를 이용합니다.

제일 먼저 라이브러리를 로드하는 LoadLibrary함수입니다. 이함수의 형은 다음과 같습니다.

HINSTANCE LoadLibrary(

LPCTSTR lpLibFileName // DLL파일 명

);

예를 들어서 ExRegularDll.dll이라는 함수를 로드하고자 한다면  다음과 같이 할수 있습니다.

HINSTANCE hDll;

hDll=LoadLibrary("ExRegularDll.dll");

LodadLibrary함수를 이용하로 로드하면 인스턴스 핸들을 리턴합니다. 이 인스턴스 핸들을 이용하여 필요한 함수의 포인터를 찾습니다. 예를 들어 ExRegularDll.dll이라는 함수에 현재 윈도우의 화면 크기를 가지고 있는 함수가 Factory라고 한다면 다음과 같이 할수 있습니다.

typedef int (*FactoryFunc)(int num);

FactoryFunc lpFactoryFunc;

lpFactoryFunc=(FactoryFunc)GetProcAddress(hDll,"Factory");

GetProcAddress함수는 다음과 같은 형태입니다.

FARPROC GetProcAddress(

HMODULE hModule, // DLL인스턴스

LPCSTR lpProcName //함수 이름

);

GetProcAddress함수의 첫번째 인자는 로드한 DLL의 인스턴스 핸들이며 두번째 인자는 이 DLL안에 있는 함수이름입니다. GetProcAddress(hDll,"Factory"); 라고 하였을경우 “ExRegularDll.dll"함수안에서 Factory 함수를 찾아서 이 메모리 위치를 리턴하며 위의 예에서는 이 위치를 lpFactoryFunc 가 받는 것입니다. 이렇게 리턴된 lpFactoryFunc 함수를 실행하고자 한다면 다음과 같이 하면 됩니다.

lpFactoryFunc(num)

lpFactoryFunc();라고 실행하였을경우 DLL의 Factory 의 함수를 실행한것과 같습니다. 만일 Factory 함수의 안에 인자로 (int num)이 있기 때문에 위와 같이 int num의 인자를 설정한것입니다.

이와 같이 라이브러리에서 함수를 실행한후 DLL의 사용이 종료 되면 FreeLibrary함수를 이용하여 해제 하면됩니다.

FreeLibrary(hDll);

이렇게 하였을경우 현재 DLL를 사용하는 프로그램이 전형 없다고 할경우 그 DLL은 메모리에서 해제되나 만일 다른 프로그래에서 사용하고 있다면 이 DLL 은 메모리에 그대로 있습니다. 메모리에서 DLL를 해제하지 않고 싶을경우 한개의 프로그램이 로드하면서 그DLL를 로드하고 아무것도 이용하지 않은채 해제를 하지 않으면 됩니다. 이렇게 되면 다른 프로그램에서는 언제나 메모리에 상주되어 있는 DLL 를 항상 이용할수 있습니다.

시험용 어플리케이션이 MFC 확장 DLL을 사용할 수 있도록 해보자

1. LIb 파일을 인클루드 한다

DLL에 해당하는 lib를 임포트 할때는 두가지 방법이 있다

a. project ->setting -> link -> library modules

b. project -> Add to Project -> Files...

2.  DLL 을 추가했다면 소스코드 파일에서 클래스를 include한 부분을 고쳐서

해당  DLL의 프로젝트 디렉토리를 가리키게 해야된다

이렇게 되어있던 부분을

#include "psd.h"

이렇게 고친다.

#include "..\PSD_EXT_DLL\psd.h"

컴파일해서 사용하면된다.

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

2부. MFC Static Library( LIB)를 만들어 보자

기본적으로 1부에서 만들었던 DLL과 크게 다를 바가 없다

1. Win32 Static Library 를 선택한다.

2. MFC support 및 Pre-Compiled Header를 선택한다.

pre-compiled header지원은 사실 필요하지 않지만 모듈을 만들때 컴파일 속도를 증가시킬수 있다

3. 클래스를 추가할 때는 이미 만들어져 있는 클래스를 불러와서 컴파일 해도되고

새로이 클래스를 추가해서 정의하여 만들어도 된다.

여기선 이미 만들어져 있는것을 불러오도록 하겠다.

psd.cpp와 psd.h 를  포함시켰으며 hanningwindow.h도 나의 프로그램에 필요한 헤더이므로

포함시켰다.

4. Library 인클루드 시키는 것은 1부의 DLL부분을 참고

5. 컴파일하면 Lib파일이 만들어진다.

시험용 어플리케이션이 MFC Static Lib를 사용할 수 있도록 해보자

1. LIb 을 추가했다면 소스코드 파일에서 클래스를 include한 부분을 고쳐서

해당  DLL의 프로젝트 디렉토리를 가리키게 해야된다

이렇게 되어있던 부분을

#include "psd.h"

이렇게 고친다.

#include "..\PSD_STATIC_LIB\psd.h"

2. 컴파일해서 사용한다.

3부. 확장 DLL 과 Static Lib를 사용했을때의 차이점

1. 실행 파일 사이즈 차이

--> 동일한 프로젝트를 컴파일 했을때  static lib를 사용하는

실행파일의 사이즈가 DLL을 사용하는 실행파일보다 20Kb정도 더 크다

참고로 dll자체 사이즈와 lib는 거의 비슷했다

2. F11(Step Into)로 Trace했을때 static lib는 원소스쪽으로 수행이 옮겨가서 볼수 있다

하지만 DLL은 F11 (Step Into)를 했음에도 불구하고 그냥 skip된다