'Callback'에 해당되는 글 1건

  1. 2008.12.01 [API] 콜백함수를 클래스에 포함하기 (간단정리)
Programming/Win32 API2008. 12. 1. 15:29
Win32 Api 프로그래밍을 하다보면 C++ 스타일로 프로그램을 작성하는 것은 매우 유용하다는것을
알수 있다. 그중에 하나가 클래스를 쓰면 소스 코드가 깔끔해지고 더욱 가독성이 좋아진다.
근데 우리가 부딪치는 문제. 콜백함수를 클래스에 포함하려면 컴파일 에러가 난다.
나도 이 문제에 부딪쳤다가 인터넷에서 그 해법을 알아 냈는데 너무 장황하게 설명해놔서
간단히 요약한다
------------------------------------------------------------------------------------------
 
 
1. 예를 들어 이렇게 쓰고 싶은것이다.
 
LRESULT CALLBACK CMyClass::WinProc(HWND hwnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
      switch(uMsg)                                                  

    {

        case WM_INITDIALOG:

        return OnInitDialog( hwnd );

    }

    return FALSE;

 }
 
 
2. 콜백함수를 클래스 안에 포함하고 컴파일을 하면 다음과 같은 에러가난다.
 
: error C2440: 'type cast' : cannot convert from '' to 'int (__stdcall *)(struct HWND__

*,unsigned int,unsigned int,long)'

        None of the functions with this name in scope match the target type



3. 멤버함수는 클래스의 인스턴스가 존재 해야지만 호출할수 있지만 인스턴스가 존재 하지 않아도

쓸수 있는 방법이 바로 static 맴버함수이다.


static LRESULT CALLBACK CMyClass::WinProc(HWND hwnd,UINT iMessage,
                                                      WPARAM wParam,LPARAM lParam)
{
    switch(uMsg)                                                  

    {

        case WM_INITDIALOG:

        return OnInitDialog( hwnd ); // ->error (non-static fuction)

    }

    return FALSE;

}

 
4. 하지만 여기서 문제가 되는게 static 함수에서 non-static 함수를 호출할수 없다는 에러 메세
   지가 또 나타난다. 그래서 클래스에 포함된 모든 함수를 static 으로 선언 하면 해결은 되는
   데 무지 번거롭고 모양세도 이상하다. (필자는 실제로 그런 코드를 본적이 있다. ㅡㅡ;)
   나는 예쁜 코드를 지향 하기 때문에 다른 방법을 생각했다.
   <1> static 함수내에서 static 함수를 호출하는것은 적법하다.

   <2> static 함수내에서 객체의 인스턴스를 통한 멤버함수 호출은 적법하다.


PCMyClass g_pMyClass; // 1)


int WINAPI CMyClass::DlgMain(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

   PCMyClass myClass = new CMyClass; // 2)

   g_pMyClass = myClass;

   ...

   // 콜백함수 호출.

   ...

   return 0;

}


LRESULT CALLBACK CMyClass::WinProc(HWND hwnd,UINT iMessage,
                                                      WPARAM wParam,LPARAM lParam)
 {
    PCMyClass pMyClass = g_pMyClass;  // 3)
 
    switch(uMsg)                                                  

    {

        case WM_INITDIALOG:

        return pMyClass->OnInitDialog( hwnd ); // 4)

    }

    return FALSE;

}

 
내가 참고한 글에서는 lParam 값에 클래스 인스턴스를 넘겨받아서 처리하고 있지만 나는,
1) 전역변수에 클래스 포인터를 선언하고
2) WinMain 함수에 인스턴스를 생성해서 전역변수에 복사한다음
3) 콜백함수안에서 전역변수를 지역 변수에 복사하여
4) 그 인스턴스를 통해 맴버함수를 호출하는 방법을 썼다.
 
결론 : 잘된다.
Posted by skensita