1. Introduction
MSN 메신저가 설치되어 있다면 메신저를 한번 열어보자.
아마 등록된 친구들의 목록이 나오는 윈도우가 화면에 나타날 것이다. 이번에는 그 윈도우의 우측 상단에 있는 닫기 버튼을 눌러서
메신저 윈도우를 닫아 보자. 그럼 아마도 윈도우가 사라지면서 우측 하단의 트레이로 캡션바가 사라지는 애니메이션이 표시될 것이다.
무슨 말인지 잘 모르겠다면 메신저 화면을 띄우고 최소화 시켜 보자. 그럼 작업 영역으로 내려가는 애니메이션이 표시될 것이다.
다시 활성화 시켜서 닫아 보자. 그럼 금방 그 둘의 차이를 알 수 있을 것이다.
트레이로 내려가는 애니메이션. 아주 사소한 것이다. 하지만 사용자 입장에서는 이 사소한 하나가 프로그램의 완성도를 살피는
중요한 척도가 된다. 자, 그럼 이제 트레이로 내려가는 애니메이션을 출력하는 방법에 대해서 알아보도록 하자.
2. DrawAnimatedRects
구현의 핵심은 DrawAnimatedRects
API 다. 벌써 이름에서 냄새를 풍기고 있다. 애니메이션 사각형을 그리는 함수겠거니 짐작했다면 정답이다. 함수 원형과 함께
사용법을 알아보도록 하자. view plaincopy to clipboardprint?
BOOL DrawAnimatedRects(
HWND hwnd, // handle to clipping window
int idAni, // type of animation
CONST RECT *lprcFrom, // rectangle coordinates (minimized)
CONST RECT *lprcTo // rectangle coordinates (restored)
);
BOOL DrawAnimatedRects(
HWND hwnd, // handle to clipping window
int idAni, // type of animation
CONST RECT *lprcFrom, // rectangle coordinates (minimized)
CONST RECT *lprcTo // rectangle coordinates (restored)
);
MSDN에서 발췌한 함수의 원형이다. 파라미터는 다음과 같은 의미를 가진다.
hwnd - 윈도우 핸들이다. 애니메이션을 출력할 윈도우의 핸들을 넣어주시면 된다.
idAni - 애니메이션 종류 번호다. 지금까지 출시된 윈도우에서 지원하는 타입은 IDANI_CAPTION 밖에 없다. 따라서 무조건 저 값을 넣으면 된다.
lprcFrom, lprcTo - 사각형 구조체 포인터를 넘긴다. lprcFrom에서 lprcTo로 움직이는 애니메이션이 출력된다.
리
턴 값은 당연히 성공하면 0이 아닌 값을, 실패 시에 0을 리턴 한다. 이제 이 함수에 대해서 대충 감이 잡히셨다면 샘플 코드를
한번 보도록 하자. 여기서 꼭 한번 직접 타이핑해서 결과를 확인해 보도록 하자. 백문이불여일견 이라는 옛말이 있듯이, 백 번
보는 것보다 직접 타이핑해서 결과를 확인하는 것이 더욱 기억에 오래 남는다는 것을 명심하자. CRect rc;
CRect rc2;
GetWindowRect(rc);
rc2 = rc;
rc2.OffsetRect(100, 100);
DrawAnimatedRects(m_hWnd, IDANI_CAPTION, rc, rc2);
CRect rc;
CRect rc2;
GetWindowRect(rc);
rc2 = rc;
rc2.OffsetRect(100, 100);
DrawAnimatedRects(m_hWnd, IDANI_CAPTION, rc, rc2);
쉽다. 윈도우 영역을 구해서 100, 100만큼 오른쪽 아래 있는 사각형으로 이동하는 애니메이션을 출력하는 것이다. 실행해 봤다면 아! 하고 느꼈을 것이다.
3. 트레이는 어디에?
2장까지 읽고는 이제 게임 끝... 하고 덮으시려는 분들이 있을
것 같다. 하지만 한가지 문제가 더 남아 있다. 어디서 어디로 가는 애니메이션을 출력하는가? 라는 문제다. 출발 지점은 당연히
윈도우의 영역이 될 것이고, 종료 지점은 트레이 영역이 될 것이다. 이제 트레이 영역을 구하는 방법만 알면 진짜 게임이 끝나는
거다.
트레이 영역을 찾기 위해서 윈도우 구조를 조금 조사할 필요가 있다. 이럴 때 강력한 힘을 발휘할 수 있는 SPY++을
실행해보자. 그리고 직접 한번 트레이를 찾아 보자. 아직 SPY++의 사용법을 모른다면 지금 당장 배울 필요가 있다. 윈도우
개발을 함에 있어 VC++에 포함된 Depends와 SPY++은 아주 유용한 도구다. 시간이 날 때 꼭 사용법을 익혀 놓도록
하자.
발견한 트레이 윈도우 구조는 왼쪽과 같다. 전체를 둘러싸고 있는 큰 파란 사각형의 윈도우 클래스 명은
"Shell_TrayWnd"다. 그 안을 둘러싸고 있는 빨간 사각형 윈도우의 클래스 명은 "TrayNotifyWnd"다. 끝으로
그 안에 들어있는 보라색 윈도우의 클래스 명은 "ToolbarWindow32"다. 모두 윈도우 명은 없다. 그러나 끝에 찾은
보라색 윈도우의 경우 9x 계열에서는 없다. 2000이상의 버전부터 툴 바 윈도우가 생겼다. XP부터는 Pager란 놈까지
생겼다. 하여튼 여기서 중요한 점은 Shell_TrayWnd와 TrayNotifyWnd는 운영체제에 상관없이 공통된 속성이라는
점이다.
그럼 이제 윈도우만 찾으면 된다~ 윈도우를 찾는 건 너무나 쉽다. 훌륭한 FindWindow API를 사용하면 된다. TrayNotifyWnd를 찾는 FindWindow 코드는 아래와 같다.
- HWND hTrayP = FindWindow("Shell_TrayWnd", NULL);
- HWND hTrayC = FindWindowEx(hTrayP, NULL, "TrayNotifyWnd", NULL);
간단하게 설명하면 첫째 줄에서 Shell_TrayWnd를 찾고, 그 다음 줄에서 ShellTrayWnd의 자식 중에 TrayNotifyWnd를 찾는 코드다.
4. 모두 합쳐봐~
이제 드디어 2,3장에 걸쳐서 배웠던 지식을 활용해서 트레이로 가는 애니메이션을 출력하는 함수를 작성해 보도록 하자. 아래에 샘플로 작성해둔 함수가 있다.
- VOID SendTrayAnimation(HWND hwnd, BOOL bTo)
- {
- RECT rcFrom, rcTo;
-
- HWND hTrayP = FindWindow("Shell_TrayWnd", NULL);
- HWND hTrayC = FindWindowEx(hTrayP, NULL, "TrayNotifyWnd", NULL);
-
- if(hTrayC)
- {
- GetWindowRect(hTrayC, &rcTo);
- }
- else
- {
- SystemParametersInfo(SPI_GETWORKAREA, 0, &rcTo, 0);
-
- rcTo.left = rcTo.right - 118;
- rcTo.top = rcTo.bottom - 30;
- }
-
- GetWindowRect(hwnd, &rcFrom);
-
- if(bTo == TRUE)
- DrawAnimatedRects(hwnd, IDANI_CAPTION, &rcFrom, &rcTo);
- else
- DrawAnimatedRects(hwnd, IDANI_CAPTION, &rcTo, &rcFrom);
- }
첫 번째 인자는 윈도우 핸들을, 두 번째 인자는 TRUE를 넣을 경우 트레이로 내려가는 애니메이션을, FALSE를 넣을 경우 트레이에서 본래 윈도우로 돌아오는 애니메이션을 출력한다.