본문 바로가기

API

Win API Timer

728x90
반응형

회사 일이 엄청 바쁜이유에서 공부를 제대로 못하다가 주말이 되서야 좀 할 수 있게 되었네요. 그것도 야근의 여파로 제대로 못했지만 ㅜ_ㅜ

뭐 암튼 오늘은 열심히 Timer란 녀석에 대해서 공부해 보았습니다. 그럼 이 타이머는 무엇일까요? 타이머는 이름에서 풍겨오는 이미지와 같이 일정시간 간격을 두고 연속적으로 WM_TIMER 메시지를 발생시킵니다. 주기적으로 해야되는 작업이나 여러 번 나누어서 해야되는 작업이 있다면 이 타이머를 사용해서 하면 되는 것이죠 ^^

우선 타이머 메시지를 통해서 간단한 시간 출력 프로그램을 만들어 보도록하죠


#include
<windows.h>

 

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

HINSTANCE g_hInst;

LPCTSTR  lpszClass = TEXT("TimerTest");

 

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)

{

  HWND hWnd;

  MSG Message;

  WNDCLASS WndClass;

  g_hInst = hInstance;

 

  WndClass.cbClsExtra = 0;

  WndClass.cbWndExtra = 0;

  WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

  WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);

  WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

  WndClass.hInstance = hInstance;

  WndClass.lpfnWndProc = WndProc;

  WndClass.lpszClassName = lpszClass;

  WndClass.lpszMenuName = NULL;

  WndClass.style = CS_HREDRAW | CS_VREDRAW;

  RegisterClass(&WndClass);

 

  hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 250, 150, NULL, (HMENU)NULL, hInstance, NULL);

  ShowWindow(hWnd, nCmdShow);

 

  while(GetMessage(&Message, NULL, 0, 0))

  {

    TranslateMessage(&Message);

    DispatchMessage(&Message);

  }

  return (int)Message.wParam;

}

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

  HDC hdc;

  PAINTSTRUCT ps;

  SYSTEMTIME st;

  static RECT rt={50, 50, 200, 100};

  static TCHAR sTime[128];

 

  switch(iMessage)

  {

  case WM_CREATE:

    SetTimer(hWnd, 1, 1000, NULL);

    SendMessage(hWnd, WM_TIMER, 1, 0);

    return 0;

  case WM_TIMER:

    GetLocalTime(&st);

    wsprintf(sTime, TEXT("%d-%d-%d %d:%d:%d"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);

    InvalidateRect(hWnd, &rt, TRUE);

    return 0;

  case WM_PAINT:

    hdc=BeginPaint(hWnd, &ps);

    TextOut(hdc, 50, 50, sTime, lstrlen(sTime));

    EndPaint(hWnd, &ps);

    return 0;

  case WM_DESTROY:

    KillTimer(hWnd, 1);

    PostQuitMessage(0);

    return 0;

  }

  return(DefWindowProc(hWnd, iMessage, wParam, lParam));

}

메인은 평소와 변함 없이 항상 같은 모습을 가지고 있고요 WndProc함수를 봐보도록 하겠습니다. SYSTEMTIME 구조체는 시스템에서 사용되는 날짜, 시간에 대한 내용을 받아오는 구조체 입니다.(영어를 잘 못해서 해석이 잘못되었을 수도 있습니다 ㅜㅜ)  그리고 RECT 구조체를 사용한 이유는 윈도우를 다시 그려줄때 전체를 다시 그리지 않고 일정부분만 다시 그릴수 있도록 영역을 잡아준 것이고요. sTime은 날짜, 시간 정보를 입력 받기 위한 저장소입니다. WM_CREATE메시지에 SetTimer()함수로 타이머를 생성을 합니다. 첫번째인수는 해당 윈도우를 넘겨주면 되고, 두번째인수는 해당 타이머의 아이디를 지정합니다. 이 아이디를 사용해서 여러게의 타이머를 생성할 수 있는 거죠. 세번째인수는 타이머의 주기를 뜻합니다. 1/1000초를 말하는 것이기 때문에 1000 이라 하면 1초를 뜻하게 되는 것이죠. 네번째 인수는 타이머 메시지 발생시 호출할 함수를 넣는 곳인데 함수가 없다면 NULL를 넣어주시면 되고 이때는 WM_TIMER 메시지가 전달 되게 됩니다.
그리고 WM_TIMER 메시지는 wParam으로 타이머 아이디를 받고, lParam으로는 타이머 메시지 발생시 호출될 함수 번지가 전달이 됩니다. 현재 소스라면 둘다 의미가 없긴 하겠죠 ^^; SendMessage함수를 쓴 이유는 처음 윈도우가 생성되고 타이머가 작동하기 전까지 1초라는 시간이 걸려 1초전까지는 아무것도 출력이 되지 않습니다. 보고 싶다면 SendMessage에 주석을 걸고 한번 샐행을 해보시기 바랍니다 ^^
WM_TIMER로 메시지가 호출되면 GetLocalTime() 함수가 실제 시간을 조사를 하게 됩니다. 그리고 sTime 변수에 그 시간값을 저장하게 되고 WM_PAINT를 호출하게 되는 것이죠. 그럼 그것을 출력하게 될것이고요.
이 프로그램은 이게 전부입니다. 그렇게 많은 내용은 없지요. 한번출력을 해보도록 하세요. 그럼 시간이 바로바로 바뀌며 출력되는것을 볼수가 있을것입니다. 아래와 같이요 ^^


여기서 또한가지 집고넣어갈것이 있습니다. 바로 CALLBACK 함수라는 녀석이죠. 지금도 쉬지 않고 콜백함수를 쓰고 있는데요. 그럼 이 콜백함수는 무엇일까요. 일반적으로 API 함수들은 윈도우가 제공하고 프로그램에서는 이 함수들을 호출해서 운영체제의 서비스를 받는 것들입니다. 하지만 콜백함수는 응용프로그램이 제공하고 운영체제가 필요할 때 호출하는 함수인것이죠. 일반 함수와는 다른 호출 방식인것입니다. 대표적으로 WndProc 함수가 있죠. 메시지가 발생하면 운영체제는 저 WndProc 함수를 호출해서 처리를 합니다. 이 콜백함수는 응용프로그램에서는 호출하지 않고 오직 운영체제에서만 호출 하도록 되어 있는거죠.
갑자기 왜 콜백함수를 알아보내고요?? 다 이유가 있어서 이죠ㅎ... 무엇이냐 하니...SetTimer함수에서 네번째 인수 기억하시죠?? NULL로 선언된 녀석...이녀석이 콜백함수를 호출을 하게 됩니다. 타임관련 함수이기 때문에 보통 TimeProc라는 이름을 주고 있습니다. 다른 이름도 되긴하지만 유저들간의 통합을 위해서 그대로 가는것이 좋을 것입니다~ SetTimer에서 지정한 시간 마다 WM_TIMER 메시지 대신 TimeProc함수를 호출하게 되는것이죠. 위 코드를 살짝 바꿔서 TimeProc함수를 사용해보도록 하겠습니다.


static
TCHAR g_sTime[128];


void CALLBACK TimeProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)

{

  SYSTEMTIME st;

  static RECT rt={50, 50, 200, 100};

  GetLocalTime(&st);

  wsprintf(g_sTime, TEXT("%d-%d-%d %d:%d:%d"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);

  InvalidateRect(hWnd, &rt, TRUE);

}

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

  HDC hdc;

  PAINTSTRUCT ps;

  static RECT rt={50, 50, 200, 100};

 

  switch(iMessage)

  {

  case WM_CREATE:

    SetTimer(hWnd, 1, 1000, TimeProc);

    return 0;

  case WM_PAINT:

    hdc=BeginPaint(hWnd, &ps);

    TextOut(hdc, 50, 50, g_sTime, lstrlen(g_sTime));

    EndPaint(hWnd, &ps);

    return 0;

  case WM_DESTROY:

    KillTimer(hWnd, 1);

    PostQuitMessage(0);

    return 0;

  }

  return(DefWindowProc(hWnd, iMessage, wParam, lParam));

}


g_sTime변수를 우선 전역변수로 설정해났구요..SetTimer에서 1초에 한번씩 TimeProc를 호출하게 되는 것입니다. 뭐 WM_TIMER 메시지에 있던 녀석들을 그대로 가져다 쓰면 되는 것이죠. 그러면 위에서 처리했던 것과 같이 실행되는것을 볼수 있습니다. 단, 1초 동안은 대기가 걸리긴합니다. 저는 어떻게 처리해야될지 모르겠더군요 ㅜ_ㅜ

타이머메시지는 참 여러가지로 재미 있는것들을 할 수 있습니다. 우선 위에서 살펴본 일정시간동안 계속적인 호출이나 작업을 할수 있고, 또 여러개의 타이머를 설정해서 여러가지를 계속적으로 처리할 수 있습니다. 하지만 너무 많은 타이머 설정은 시스템에 영햐을 미칠수 있음을 인지하시고요 ^^ 그리고 일회용 타이머라고 일회적인 대기처리, 즉 어떤 메시지가 생성되었다가 없어진다거나(메뉴나 팝업 메뉴에 마우스를 가져가면 문구가 떴다가 사라지는) 디렉토리를 펼치는 작업이나 기타 등등 너무나 많은 활용을 해볼 수 있죠. 어떤것에서 쓸 수 있는지 한번 연구해 보시는것은 어떨까요??

Timer에 대해서는 이상 마무리 해보도록 하죠. 너무나 어설프고 횡설수설 했지만 귀엽게 봐주시고요 ^^
앞으로 더 발전해나가도록 하겠습니다. 감사합니다~~

출처 : Win api 정복 - 많은 도움 받았습니다~~

728x90
반응형

'API' 카테고리의 다른 글

1초에 한번씩 캡쳐 화면 파일로 저장하기  (0) 2010.03.27
디렉토리 생성  (0) 2010.03.27
캡쳐 화면 BMP로 저장하기  (0) 2010.03.14
메뉴의 단축키, 액셀러레이터 생성  (0) 2010.03.12
메뉴 만들기  (1) 2010.03.11
포커스가 있는 윈도우 캡쳐  (0) 2010.03.10
API로 구현한 전체화면 캡쳐 소스  (0) 2010.03.09
DC 구조체에 관해....  (1) 2010.03.09
버튼 생성  (0) 2010.03.06
API의 첫 시작  (0) 2010.03.05