Jul 12 2007

[C/C++]함수 포인터를 이용한 DLL과 사용 프로그램 간의 양방향 호출

분류: Lang.C_CPP 태그: ,, , Heart @ 1:35 오전

Trackback : http://dev.heartsavior.net/archives/93/trackback/

DLL을 사용한 프로그램을 구현하다 보면 단방향 호출이 상당히 불편할 때가 많다.
DLL은 dllimport/dllexport를 통해 함수 (혹은 AFX_EXT_CLASS 등으로 클래스) 를 노출시킴으로써 DLL을 사용하는 측에서 호출할 수 있지만, 역으로 DLL을 사용하는 측의 함수를 DLL에서 사용해야 할 일이 생긴다면?

이럴 때 ‘함수 포인터’를 이용하면 간단히 해결할 수 있다.

상황을 하나 설정해 보자.

DLL 내부의 동작 로직상 고유의 ID를 얻어야 하는데, 이 ID 값은 외부 프로그램에서 제공한다.
그리고 그 ID 값은 필요할 때마다 새로 생성할 수 있어야 한다.(즉, 로직 내에서 ID가 몇개 필요할지는 예측할 수 없다)

이럴 경우 ID 갯수 예측을 할 수 없기 때문에 DLL 배포함수에 전달인자로 ID 리스트를 넘기는 방법을 사용할 수가 없고, 외부 프로그램에서 ID를 생성하는 함수를 DLL 배포함수를 통해 함수 주소를 넘겨주고, DLL에서는 ID 생성이 필요할 때 마다 함수 포인터를 사용하여 외부 함수를 사용하는 방법으로 문제를 해결해야 한다.

소스 코드로 설명하자면,

// DLL 배포 함수를 모은 헤더 파트(외부 배포 및 내부 사용 겸용)

// 프로젝트에서 DLL에는 _MYDLL_을 predefine 에 꼭 넣어줄 것
#ifdef _MYDLL_
#define MY_DLL_DIST    __declspec(dllexport)
#else
#define MY_DLL_DIST    __declspec(dllimport)
#endif _MYDLL_

// ID를 얻어오는 함수를 외부 프로그램으로부터 등록받는 배포함수
void MY_DLL_DIST RegisterIDRetriveFunc( BOOL (*fpGetID)(char *pszIDBuf, int nBufLength) );

// RegisterIDRetriveFunc의 구현부

// ID를 얻어오는 함수의 포인터를 전역 변수로 저장할 것임
// 등록이 되지 않은 상태는 NULL로 표시
BOOL (*fpGetNewID)(char *pszID, int nBufLength) = NULL;

void MY_DLL_DIST RegisterIDRetriveFunc( BOOL (*fpGetID)(char *pszIDBuf, int nBufLength) )
{
// 전역 함수 포인터에 외부 함수를 등록
fpGetNewID = fpGetID;
}

// 이후에 사용할 때의 예제
// BOOL bSuccess =  (*fpGetNewID)(pszBuf, nBufLen);

// 외부 프로그램의 소스
BOOL GetID(char *pszIDBuf, int nBufLength)
{

}

// DLL 에 함수를 등록
RegisterIDRetriveFunc(&GetID);

외부 프로그램에서는 ID를 얻을 수 있는 함수의 주소를 전달인자로 하여 RegisterIDRetriveFunc()를 호출하고, DLL에서는 RegisterIDRetriveFunc의 전달인자로 넘겨받은 함수 주소를 가지고 DLL 내부에서 보관하고 있다가 필요할 때 함수 포인터 형식으로 호출하면 된다.