U E D R , A S I H C RSS

MFC Study_2001/MM Timer

No older revisions available

No older revisions available




1. MultiMedia Timer

멀티미디어 타이머에 대한 설명을 적게 되었습니다.

저는 ZP 01 이선호 입니다.

저는 ZP 01 강인수 입니다.


2. 기본 개념

  • OnTimerSetTimer의 조합으로 구현되는 가장 일반적인 타이머는 정확하지 않습니다.
    이게 메시지 방식으로 구동되기 때문에 메시지 큐에 다른 메시지가 쌓이면 그 만큼
    조금씩 늦어지게 된다고 합니다. 실제로도 공이 움직이는 동안에 막대기를 막 움직이
    면 공이 미세하게 느려지는 것을 볼 수 있습니다.(나만 그런가?--;)

  • 이것을 해결하기 위해 MultiMedia Timer를 쓰게 됩니다. Devpia에서 본 바에 의하면
    MultiMedia Timer는 자체적으로 스레드를 만든다네요. 그래서 메시지가 쌓이든 말든
    자기 혼자 할 짓을 다 한대네요.

2.1. 기본 사용법

멀티미디어 타이머에 관련된 함수는 여러가지이나, 타이머를 구현하는데 필요한 함수는 세개입니다.

! 그러나 그전에 추가시켜줘야할 게 있습니다.

첫째는 WINMM.LIB를 추가시켜줘야 하고

둘째는 MMSYSTEM.H 를 인클루드 시켜줘야 합니다.

  • 추가하는법 :
    소스에 #include <mmsystem.h> 를 넣고

    Project(P) - Setting(S, ALT+F7)을 눌러 Link탭의 Object/Library modules:란에 winmm.lib를 적어줍니다.

2.1.1. timeSetEvent

타이머를 발동시키는 함수입니다.

~cpp 
MMRESULT timeSetEvent(UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent);

  • MMRESULT에는 타이머의 번호가 리턴됩니다. NULL일 경우에는 실패한 경우입니다.
  • uDelay : 타이머가 호출될 간격을 넣습니다. 단위는 ms입니다.
  • uResolution : 대개 0을 넣습니다만... 정확도 같다고 합니다.
  • lpTimeProc : CALLBACK함수의 이름을 넣습니다.
  • dwUser : CALLBACK함수에 전달할 인자를 넣습니다.
  • fuEvent : 타이머가 호출되는 방법을 넣습니다.
    • TIME_ONESHOT : CALLBACK함수가 딱 한번만 실행됩니다.
    • TIME_PERIODIC : uDelay시간이 지날 때마다 CALLBACK함수가 실행됩니다.

2.1.2. TimeProc

타이머로 불러내어 직접 실행되는 함수부분입니다

~cpp 
void CALLBACK TimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)

  • uID : 타이머의 번호가 넘어옵니다
  • dwUser : timeSetEvent 함수의 dwUser값이 넘어옵니다.
  • 나머지 두 변수는 쓰지 않습니다.
  • 이것은 콜백 함수라서 전역 변수로 해야된다네요. 굳이 클래스 안에 넣고 싶다면 static으로 선언해야 합니다.

2.1.3. timeKillEvent

사용이 끝난 타이머를 죽이는 부분입니다.

~cpp 
MMRESULT timeKillEvent(UINT uTimerID);

  • uTimerID 에는 타이머의 번호를 넣습니다.

이상이 기본 사용법이었습니다.

2.2. 예제

CALLBACK 함수를 전역으로 선언한 경우

~cpp 
m_TimerID=timeSetEvent(20,1,&TimerProc,(DWORD)this,TIME_PERIODIC);
  • 타이머를 시작하는 부분입니다.
  • m_TimerID는 UINT형 입니다.

~cpp 
void CALLBACK TimerProc(UINT uiID,UINT uiMsg,DWORD dwUser,DWORD dw1,DWORD dw2)
      {
             CAlcaDlg *pDlg=(CAlcaDlg*)AfxGetMainWnd();

	    pDlg->SendMessage(WM_MYMSG,0,0);
      }
  • 콜백 함수를 정의한것입니다. 콜백 함수내에서는 복잡한 일은 하지 않는게 정신건강에 좋다고 합니다.

    그래서 메시지로 날려 봤습니다. 그런데 전 별루 차이점을 못느끼겠더군요..--;

    고칠것 있으면 고쳐 주시길...

~cpp 
CAlcaDlg *pDlg = (CAlcaDlg*)AfxGetMainWnd();
        // 메인 윈도우의 포인터를 얻어와서
timeKillEvent(pDlg->m_TimerID);
        // 타이머 종료

CALLBACK 함수를 클래스 함수로 선언한 경우

클래스 선언시 timeproc함수는 static 으로 선언해야 합니다.

  • CALLBACK 함수는 클래스 내에서 선언 될 경우에는 static으로 선언 되어야합니다.

~cpp 
m_nTimerID = timeSetEvent(5, 0, (LPTIMECALLBACK)timeproc, (DWORD)this, TIME_PERIODIC);
  • m_nTimerID는 UINT형 입니다. 성공할 경우에는 타이머의 번호가 넘어옵니다.
  • 5는 타이머가 호출될 간격입니다. 역시 단위는 ms(1/1000초)입니다.
  • this는 이 클래스 인스턴스의 값을 넘겨줍니다. 클래스 내부 함수로 선언했을 경우네는 중요한 인자값입니다.

~cpp 
void CALLBACK CMyDlg::timeproc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2){
 CMyDlg *pDlg = (CMyDlg *)dwUser;
 pDlg->......
dwUser는 timeSetEvent의 this값을 인자로 받아 pDlg에 현재 인스턴스의 주소를 넣습니다.
pDlg를 통해서 원래 클래스의 모든 메소드와 변수를 사용할 수 있습니다.

~cpp 
timeKillEvnet(m_nTimerID);
setTimerEvent때 얻은 타이머의 번호를 집어넣어 타이머를 죽입니다.

2.3. 주의점

  • CALLBACK 함수를 사용할때의 주의점. (in MSDN)

    - Applications should not call any system-defined functions from inside a callback function, except for PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugString.

    - 어플리케이션은 콜백 함수 내부로부터 다음 함수를 제외하고는 시스템 정의 함수를 부를 수가 없다. : PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugString.

    왠만한 함수들은 Callback함수 내에서 부르면 안됩니다.
  • KB문서 Q130866번을 참고했습니다.
    CALLBACK함수 내부에서 화면을 갱신할 때에는 Invalidte()함수나 user 메세지를 만들어서 날려주면 됩니다.


~cpp 
void CALLBACK EXPORT CTmrprocView::TimerProc(HWND hwnd, UINT msg, UINT idTimer, DWORD dwTime)
{
    CTmrprocView * pThis;
    
    if (m_thisList.Lookup(idTimer, (LPVOID &) pThis))
    {
        ASSERT(pThis->GetSafeHwnd());
        
        CDC* pDC = pThis->GetDC();
        
        wsprintf((LPSTR) pThis->m_strOutput, "CTmrprocView::TimerProc() Called. Count = %ld", ++pThis->m_cCount);
        pThis->Invalidate(TRUE);
    }
}


Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:23:41
Processing time 0.0295 sec