[MFC] Extension DLL (확장 DLL) 만들기

오늘은 Extension DLL을 만드는 법에 대해 알아보겠습니다.

보통 실무에서 DLL이라 하면 쓰임새가

  1. 같은 작업을 처리하는 함수를 한곳에 만들을 때
  2. 공유 메모리로 쓸 때
  3. 라이브러리를 제공할 때(함수 내부를 안보이게 하기 위해)

사용합니다.(다른 용도로 사용할 수도 있지만 보통 이렇게 사용하죠.)

간단히 설명하자면,
A프로젝트에 더하기 기능이 필요하여 더하기 함수를 만들었습니다.
그런데 개발을 하다보니 프로젝트양이 커져서 B프로젝트도 생겼는데 이 B프로젝트에도 더하기 함수가 필요해졌습니다.
그럼 A프로젝트, B프로젝트에 더하기 함수가 두개여야 할까요?
그럴 필요 없이 DLL로 만들어서 A프로젝트와 B프로젝트가 DLL에 있는 더하기 함수를 참조하면 된다는 겁니다.
바로 만드는 법을 해보겠습니다.

만드는 것이 어렵진 않으나, 기존 개발과 다르니 많이 헷갈릴 수도 있습니다. 계속 반복해서 만들어 해보세요. 저도 가끔 까먹습니다.

1. 같은 작업을 처리하는 함수를 한곳에 만들을 때

대화상자 프로젝트를 만들고 리소스 뷰에서 확인 버튼을 더블 클릭 하여 확인 버튼 이벤트 처리 함수를 생성해 줍니다.
그리고 아래와 같이 SumXnY함수를 만들어줍니다.

void CMFCApplication1Dlg::OnBnClickedOk()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	int iSum = SumXnY( 1, 2 );
	CString sMsg;
	sMsg.Format( _T("%d"), iSum );
	AfxMessageBox( sMsg );
}

DLL 프로젝트를 생성하여 SumXnY를 만들어야 합니다.
솔루션 우클릭 -> 추가 -> 새프로젝트를 선택해줍니다.

그리고 MFC -> MFC -> DLL을 선택 해주시고, 이름에 MathFunction을 입력하고 확인을 눌러줍니다.

다음 화면이 나올 때 MFC Extension DLL(MFC 확장 DLL)을 선택하신 후 마침을 선택합니다.

솔루션 탐색기 보시면 아래와 같이 DLL 프로젝트가 생겼습니다.

여기서 MathFunction 프로젝트 우클릭 -> 추가 -> 새 항목을 선택하여 헤더 파일 -> MathFunctionAPI.h 입력 -> 추가 버튼을 선택합니다.

자, 이 헤더파일에 아래와 같이 입력합니다.

#pragma once

#ifdef _DLL_MATH_
#define DLL_MATH _declspec(dllexport)
#else
#define DLL_MATH __declspec(dllimport)
#endif

DLL_MATH int SumXnY( int iX, int iY );

그리고 dllmain.cpp 맨 아래 아래와 같이 입력합니다.(하이라이트와 같은 위치에 입력하세요)

// dllmain.cpp
		// 소멸자가 호출되기 전에 라이브러리를 종료합니다.
		AfxTermExtensionModule(MathFunctionDLL);
	}
	return 1;   // 확인
}

#ifndef _DLL_MATH_
#define _DLL_MATH_
#endif

#include "MathFunctionAPI.h"

DLL_MATH int SumXnY( int iX, int iY )
{
	return iX + iY;
}

이제 대화상자 cpp로 가서 MathFunctionAPI.h를 include 합니다.(하이라이트와 같은 위치에 입력하세요)

// MFCApplication1Dlg.cpp : 구현 파일
//

#include "stdafx.h"
#include "MFCApplication1.h"
#include "MFCApplication1Dlg.h"
#include "afxdialogex.h"

// DLL API 함수 Include
#include "../MathFunction/MathFunctionAPI.h"
#pragma comment( lib, "MathFunction.lib" )

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

이 상태로 빌드(F7)해도 빌드가 되지 않습니다.
대화상자 프로젝트 우클릭 -> 속성에서 구성 속성 -> 링커 -> 일반에 있는 추가 라이브러리 디렉터리에다가 아래와 같이 입력합니다.

이 상태에서 빌드(F7)하고 대화상자를 실행해 보면 확인 버튼을 눌렀을때 아래와 같이 나타납니다.
코드 안에 있는 1 + 2가 제대로 작동한 모습이죠.

여기서 대화상자 프로젝트를 하나 더 만들어 줍니다.

대화상자2(MFCApplication2)에도 똑같이 확인 버튼을 더블 클릭해서 이벤트 처리 함수를 만들어 줍니다.

void CMFCApplication2Dlg::OnBnClickedOk()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	int iSum = SumXnY( 3, 4 );
	CString sMsg;
	sMsg.Format( _T( "%d" ), iSum );
	AfxMessageBox( sMsg );
}

이번엔 3 더하기 4입니다.

위에 했던 것처럼 대화상자2.cpp 위에 MathFunctionAPI.h를 include 합니다.(하이라이트와 같은 위치에 입력하세요)

// MFCApplication2Dlg.cpp : 구현 파일
//

#include "stdafx.h"
#include "MFCApplication2.h"
#include "MFCApplication2Dlg.h"
#include "afxdialogex.h"

// DLL API 함수 Include
#include "../MathFunction/MathFunctionAPI.h"
#pragma comment( lib, "MathFunction.lib" )

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

이 상태로 빌드(F7)해도 빌드가 되지 않습니다.
위에서 했던 것처럼 대화상자 프로젝트 우클릭 -> 속성에서 구성 속성 -> 링커 -> 일반에 있는 추가 라이브러리 디렉터리에다가 아래와 같이 입력합니다.

이 상태에서 빌드(F7)하고 대화상자2에서도 정상 작동하나 확인해 봅니다. ( 3 더하기 4 )

보시는 것처럼 DLL에 함수 하나만 만들어 2개의 프로젝트에서 참고 하실 수 있습니다.

2. 공유 메모리로 쓸 때

공유메모리로 쓰기위해 아래와 같이 DLL 프로젝트에 ShareMemory.h파일을 하나 만들어 줍니다.

ShareMemory.h에 아래와 같이 입력합니다.

#pragma once

#ifdef _SHARE_MEMORY_
#define SHARE_MEMORY _declspec(dllexport)
#else
#define SHARE_MEMORY __declspec(dllimport)
#endif

SHARE_MEMORY void SetValue( int iSet );
SHARE_MEMORY int GetValue( );

그리고 dllmain.cpp 맨 아래에 아래와 같이 입력합니다.

// 공유 메모리 
#pragma data_seg("SHARE_MEMORY")		// data_seg(섹션이름)
int iMemory( 0 );				// 공유할 메모리 선언(초기화)
#pragma data_seg()				// data_seg()

#pragma comment(linker, "/section:SHARE_MEMORY,RWS")	// 섹션의 메모리를 공유


#ifndef _SHARE_MEMORY_
#define _SHARE_MEMORY_
#endif

#include "ShareMemory.h"

SHARE_MEMORY void SetValue( int iSet )
{
	iMemory = iSet;
}
SHARE_MEMORY int GetValue()
{
	return iMemory;
}

그리고 대화상자 1, 2의 .cpp 파일에 아래와 같이 입력합니다.(하이라이트와 같은 위치에 입력하세요)

// DLL API 함수 Include
#include "../MathFunction/MathFunctionAPI.h"
#pragma comment( lib, "MathFunction.lib" )

// Share Memory Include
#include "../MathFunction/ShareMemory.h"
#pragma comment( lib, "MathFunction.lib" )

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

대화상자 1은 Memory Set 버튼을, 대화상자 2는 Memory Get 버튼을 만들어 주고 더블 클릭 하여 이벤트 처리기 함수를 추가합니다.

그리고 추가한 버튼의 이벤트 처리기 함수에 아래와 같이 입력합니다.

void CMFCApplication1Dlg::OnBnClickedButton1()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	SetValue( 10 );
}
void CMFCApplication2Dlg::OnBnClickedButton1()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	int iGet = GetValue();
	CString sGet;
	sGet.Format( _T( "%d" ), iGet );
	AfxMessageBox( sGet );
}

아래 움짤처럼 대화상자 1에서 Set을 하면 해당 값이 대화 상자 2에서 표시가 됩니다.

3. 라이브러리를 제공할 때(함수 내부를 안보이게 하기 위해)

이게 무슨 소린지 예를들어 설명하겠습니다. MathFunction에 있는 함수는 여러분이 다니는 회사에서 만든 함수라고 합시다. 타 업체에서 MathFunction DLL을 만들어 다른 업체에 납품 합니다. 그런데 함수를 다 줘야 할까요?? 그러면 회사 기밀 유출되겠죠.
DLL은 함수를 은닉 시켜 줍니다. 새로운 프로젝트를 만들어줍니다.(OtherCompany)

아래 그림과 같이 솔루션 폴더에 MathFunction 폴더를 생성합니다.

이 폴더에 아까 만들어준 파일 중 MathFunctionAPI.h, ShareMemory.h, MathFunction.lib 파일을 복사합니다.

OtherCompany 대화상자 .cpp 파일에 아래와 같이 입력합니다.(하이라이트와 같은 위치에 입력하세요)

// OtherCompanyDlg.cpp : 구현 파일
//

#include "stdafx.h"
#include "OtherCompany.h"
#include "OtherCompanyDlg.h"
#include "afxdialogex.h"

// DLL API 함수 Include
#include "../MathFunction/MathFunctionAPI.h"

// Share Memory Include
#include "../MathFunction/ShareMemory.h"

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

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

그리고 확인 버튼을 더블 클릭하여 이벤트 처리 함수에 아래와 같이 입력 합니다.

void COtherCompanyDlg::OnBnClickedOk()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	int iSum = SumXnY( 3, 4 );

	SetValue( iSum );

	int iGet = GetValue();

	CString sMsg;
	sMsg.Format( _T( "iGet : %d" ), iGet );
	AfxMessageBox( sMsg );
}

프로젝트 우클릭 -> 속성에서 구성 속성 -> 링커 -> 일반 -> 추가 라이브러리 디렉터리에 아래와 같이  $(solutiondir)MathFunction\를 입력합니다.

그리고 빌드(F7)하여 .exe 파일 위치에 MathFunction.dll을 위치시킵니다.

맨 위에 설명 드린

  1. 같은 작업을 처리하는 함수를 한곳에 만들을 때
  2. 공유 메모리로 쓸 때
  3. 라이브러리를 제공할 때(함수 내부를 안보이게 하기 위해)

를 모두 설명 드렸습니다.

하다 보니 너무 길어 졌는데 MFC 확장 DLL을 사용하신 다면 이정도는 숙지 하셔야 합니다.
계속 반복하다 보면 잘 만드실 수 있을 겁니다.