본문 바로가기
C & C++/MFC 컨트롤

[Tip] 트레이 아이콘 조작

by izen8 2011. 3. 29.
반응형

Visual C++로 제작된 프로그램에서 시스템 트레이를 조작하는데는 다음과 같은 함수를 사용한다.

BOOL WINAPI Shell_NotifyIcon(DWORD dwMessage, PNOTIFYICONDATA pnid) ;


  dwMessage는 다음과 같은 값들이 들어간다.
  - NIM_ADD : 시스템 트레이에 새로운 아이콘 추가
  - NIM_DELETE : 아이콘 제거
  - NIM_MODIFY : 아이콘 수정

  그리고 PNOTIFYICONDATA는 다음과 같은 구조체이다.

typedef struct _NOTIFYICONDATA {
  DWORD    cbSize;
  HWND      hWnd;
  UINT        uID;
  UINT        uFlags;
  UINT        uCallbackMessage;
  HICON      hIcon;
  char         szTip[64];
} NOTIFYICONDATA, *PNOTIFYICONDATA;


  - cbSize : 구조체의 크기
  - hWnd : 윈도우 핸들
  - uID : 아이콘 식별자. 호출한 애플리케이션의 아이콘을 다른것과 구별해서 식별할 수 있게 해주는 사용자 정의값
  - uFlags
      NIF_MESSAGE : uCallbackMessage 사용
      NIF_ICON : hIcon 사용
      NIF_TIP : szTip 사용
  - uCallbackMessage : 아이콘이 hWnd 윈도우와 통신하기 위해 사용할 메시지 ID. 메시지는 WM_APP의 오프셋으로 선언되는 사용자 정의 메시지이다.
  - hIcon : 화면에 그려질 아이콘의 핸들
  - szTip : 아이콘의 툴팁을 위한 텍스트

  대충 함수와 구조체를 보면 그 사용법을 알 수 있을 것이다. 적절한 값으로 구조체를 만들고, 함수를 호출 해주면 된다. MFC에서의 간단한 예를 보도록 하자.

1. 시스템 트레이에 아이콘 추가

#define WM_TRAY_NOTIFY  WM_APP+1

NOTIFYICONDATA      nid;

// 구조체 설정
::ZeroMemory(&nid, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
nid.hWnd = this->m_hWnd;
nid.uID = IDR_MAINFRAME;
nid.uFlags = NIF_TIP | NIF_ICON | NIF_MESSAGE;
nid.uCallbackMessage = WM_TRAY_NOTIFY;
strcpy(nid.szTip, "test");

// 트레이에 추가
::Shell_NotifyIcon(NIM_ADD, &nid);


2. 제거
  제거시에는 hWnd와 uID만 셋팅해주면 된다.

NOTIFYICONDATA  nid;
::ZeroMemory(&nid, sizoef(nid));
nid.cbSize = sizeof(nid);
nid.hWnd = this->m_hWnd;
nid.uID = IDR_MAINFRAME;
::Shell_NotifyIcon(NIM_DELETE, &nid);


3. Context 메뉴 handle
  일반적으로 시스템 트레이 아이콘을 우클릭 했을 때는 context 메뉴가 팝업된다. 그부분을 핸들링하는 코드의 예제이다.

POINT    pt;
GetCursorPos(&pt);
SetForegroundWindow(hWnd);
TrackPopupMenu(menu, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL);
PostMessage(hWnd, WM_NULL, 0, 0);


  여기서 한가지 중요한 것은 TrackPopupMenu 함수를 호출하기 전에 SetForegroundWindow 함수를 호출하고, 이후에는 WM_NULL 메시지를 포스트 해주어야 한다는 것이다. 그렇지 않으면 팝업메뉴가 사라지지 않는 버그가 발생한다.

4. 메시지 수신
  시스템 트레이로부터 수신하게되는 메시지는 마우스 메시지 뿐이므로, 그것만을 처리해주면 된다. 위의 코드를 참고한 예제코드는 다음과 같다.

ON_MESSAGE(WM_TRAY_NOTIFY, OnTrayNotify);

LONG TestDlg::OnTrayNotify(WPARAM wParam, LPARAM lParam) {
  CMenu     menu;
  CMenu*   pTrayMenu;
  CPoint      pt;

  if (wParam == IDR_MAINFRAM) {
    switch(lParam) {
    case WM_RBUTTONUP :
      menu.LoadMenu(IDR_TRAYMENU);
      pTrayMenu = menu.getSubMenu(0);
      ::GetCursorPos(&pt);
      SetForegroundWindow();
      pTrayMenu->TrackPopupMenu(TPM_LEFTALIGN, pt.x, pt.y, this, NULL);
      SetForegroundWindow();

      pTrayMenu->DestroyMenu();
      menu.DestroyMenu();
      break;

    case WM_LBUTTONDBLCLK :
      if (!IsWindowVisible())
       ShowWindow(SW_SHOW);
      SetForegroundWindow();
      break;
    }
  }

  return 0;
}


반응형

댓글