콜백함수의 구현





1 CallBack 함수
2 구현방법
3 구현예
4 Comment


1 CallBack 함수 #

음… 윈도우에서는 사용자가 정의 하고 운영체제에 의해서 호출되는 함수를 CallBack 함수라고 한다. 예를 들어 타이머를 설정할때 넣는 함수등등

2 구현방법 #

자체적인 CallBack 함수는 함수포인터를 이용해서 구현된다.(윈도우 CallBack함수가 뭘로 구현됐는지는 모르겠지만 아마도 함수포인터일듯) 일반적으로 라이브러리에서는 함수포인터 변수를 가지고 있고 사용자가 함수를 정의해서 함수포인터에 넣어주면 라이브러리나 운영체제 등에서 필요한 시기에 그 함수를 호출하는 것이다.


3 구현예 #

dll의 정보를 exe에서 출력을 하는것을 구현하는 방법은

  1. exe쪽에서 객체를 넘겨서 DLL에서 출력루틴을 호출
  2. 윈도우 메세지를 이용해서 DLL에서 exe의 윈도우쪽에 메세지를 보내 exe에서 출력루틴을 호출
  3. dll에서 exe쪽에 변수포인터를 넘기고 이 변수를 통해 진행상황을 공유. (이 경우는 exe쪽에서 일정시간마다 변수의 변화값을 체크)
일단 생각나는건 이 세가지이다.
1번의 단점은 객체 출력루틴이나 객체가 변경된다면 DLL을 수정해줘야 하는 어이없는 상황이 생긴다. 장점은 DLL쪽에서 호출하게 되니깐 exe쪽에서는 출력에 관한 사항을 신경쓸 필요가 없다는것.
2번 단점은 윈도우객체에서 처리해야 한다는것.
3번의 단점은 exe에서 귀찮은 코드가 많이 들어간다는것. 장점은 dll에서는 신경쓸 필요가 없다는것.

3가지다 그다지 좋은 코드가 아니라고 생각이든다. 이것을 CallBack 형식으로 구현하는 것이다.

DLL단에서는 함수포인터 변수를 가지고 있고 이걸 exe에서 변경할수 있게 익스포트 해놓는다. 이 함수포인터는 직접 호출되지 않고 DLL에서 내부 함수로 한번 랩핑을 해서 관련정보를 구조체에 집어넣고 이 구조체를 함수포인터의 매개변수로 넣고 함수포인터를 호출하는것 으로 구현을 한다.

exe 단에서는 해당 함수포인터의 형대로 함수를 구현해 놓고 이 함수가 호출될때 마다 넘어오는 매개변수를 이용해서 정보를 출력해주는 것이다.

DLL 단에서의 구현예
아래는 함수포인터를 깔끔하게 선언하기 위한 typedef 문과 함수포인터가 매개변수로 사용하는 구조체선언이다.
// 메세지콜백함수 원형
typedef void (*MSG_FUNC)(void*);

// BINWAFER SSA 콜백함수 구조체 원형
struct AFX_EXT_CLASS BINSSA_MSG_INFO
{
int nNowIdx;
int nMaxIdx;
};


클래스 내부에 함수포인터인 m_FuncMsg를 가지고 있고 이 변수를 변경시킬수 있는 SetMessageFunction( MSG_FUNC func ) 함수를 구현한다. 이 함수에 의해서 exe에서 사용자가 연결한 함수를 함수포인터에 연결하게 된다.
class AFX_EXT_CLASS CSample : public vector<int>
{
private:
// 외부에 진행상황을 알리 위한 메세지함수포인터
MSG_FUNC m_FuncMsg;

public:
CSample ();
virtual ~CSample ();

void Run();
void SetMessageFunction( MSG_FUNC func ) { m_FuncMsg = func; }
};


뭔가를 열심히 실행하는 함수는 중간중간에 exe에 결과를 보내주기 위해서 m_FuncMsg를 호출하게 된다.(만약 exe에서 m_FuncMsg에 함수를 연결해 두지 않았을 경우에는 런타임에러가 발생하게 되니 if문으로 처리하던지 아무것도하지 않는 함수를 정의해놓고 생성자에서 생성될때 그함수에 연결해 놓도록 한다.)
void CSample::Run()
{
int nCnt= (int)size();
for( int i=0; i < nCnt; i++ )
{
// 백터의 각 엘레멘트를 어떻게 저떻게 사용한다.

// 엘레멘트 한개 만큼 뭔가가 처리됐다.
// 처리된 상태를 콜백함수를 통해 exe쪽에 보낸다.
BINSSA_MSG_INFO msgInfo;
msgInfo.nNowIdx = i;
msgInfo.nMaxIdx = nCnt;
m_FuncMsg( &msgInfo );
}
}


exe에서의 구현예
dll에 정의된 콜백함수에 맞추어 해당함수를 사용자가 정의한다.
// BIN SSA 메세지 함수
void BIN_SSA_MSG( void* lpInfo )
{
BINSSA_MSG_INFO* pMsgInfo = (BINSSA_MSG_INFO*)lpInfo;

CString strTmp;
strTmp.Format(“진행:%d/%d, pMsgInfo->nNowIdx+1, pMsgInfo->nMaxIdx );
theApp.Message(strTmp);
}

이 함수를 dll의 객체에 연결해 준다.
void ExeSampleWnd::OnLButtonDown()
{
CSample object;
object.SetMessageFunction( BIN_SSA_MSG);
object.Run();
}

자 이렇게 해두면 ExeSampleWnd 클래스의 객체에서 OnLButtonDown 함수가 실행될때 DLL에서 정의된 CSample의 object라는 객체를 만들고 그 객체의 Run 이라는 함수가 수행될때 수행상태가 변할때마다 BIN_SSA_MSG 라는 exe에 정의된 함수가 호출되서 진행 : 3/30 같은 메세지를 출력하게 된다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다