Finding the screen position of a system tray icon

hi gurus,

i have a system tray icon and would like to display a window at or around it. Is there any way i can get the location or dimensions of my tray icon?

thanks,
Gavin
mrpinkoAsked:
Who is Participating?
 
Meir RivkinFull stack Software EngineerCommented:
static VOID GetTrayWndRect(LPRECT lpTrayRect)
{
  // First, we'll use a quick hack method. We know that the taskbar is a window
  // of class Shell_TrayWnd, and the status tray is a child of this of class
  // TrayNotifyWnd. This provides us a window rect to minimize to. Note, however,
  // that this is not guaranteed to work on future versions of the shell. If we
  // use this method, make sure we have a backup!
  HWND hShellTrayWnd=FindWindowEx(NULL,NULL,TEXT("Shell_TrayWnd"),NULL);
  if(hShellTrayWnd)
  {
    HWND hTrayNotifyWnd=FindWindowEx(hShellTrayWnd,NULL,TEXT("TrayNotifyWnd"),NULL);
    if(hTrayNotifyWnd)
    {
      GetWindowRect(hTrayNotifyWnd,lpTrayRect);
      return;
    }
  }

  // OK, we failed to get the rect from the quick hack. Either explorer isn't
  // running or it's a new version of the shell with the window class names
  // changed (how dare Microsoft change these undocumented class names!) So, we
  // try to find out what side of the screen the taskbar is connected to. We
  // know that the system tray is either on the right or the bottom of the
  // taskbar, so we can make a good guess at where to minimize to
  APPBARDATA appBarData;
  appBarData.cbSize=sizeof(appBarData);
  if(SHAppBarMessage(ABM_GETTASKBARPOS,&appBarData))
  {
    // We know the edge the taskbar is connected to, so guess the rect of the
    // system tray. Use various fudge factor to make it look good
    switch(appBarData.uEdge)
    {
      case ABE_LEFT:
      case ABE_RIGHT:
     // We want to minimize to the bottom of the taskbar
     lpTrayRect->top=appBarData.rc.bottom-100;
     lpTrayRect->bottom=appBarData.rc.bottom-16;
     lpTrayRect->left=appBarData.rc.left;
     lpTrayRect->right=appBarData.rc.right;
     break;

      case ABE_TOP:
      case ABE_BOTTOM:
     // We want to minimize to the right of the taskbar
     lpTrayRect->top=appBarData.rc.top;
     lpTrayRect->bottom=appBarData.rc.bottom;
     lpTrayRect->left=appBarData.rc.right-100;
     lpTrayRect->right=appBarData.rc.right-16;
     break;
    }

    return;
  }

  // Blimey, we really aren't in luck. It's possible that a third party shell
  // is running instead of explorer. This shell might provide support for the
  // system tray, by providing a Shell_TrayWnd window (which receives the
  // messages for the icons) So, look for a Shell_TrayWnd window and work out
  // the rect from that. Remember that explorer's taskbar is the Shell_TrayWnd,
  // and stretches either the width or the height of the screen. We can't rely
  // on the 3rd party shell's Shell_TrayWnd doing the same, in fact, we can't
  // rely on it being any size. The best we can do is just blindly use the
  // window rect, perhaps limiting the width and height to, say 150 square.
  // Note that if the 3rd party shell supports the same configuraion as
  // explorer (the icons hosted in NotifyTrayWnd, which is a child window of
  // Shell_TrayWnd), we would already have caught it above
  hShellTrayWnd=FindWindowEx(NULL,NULL,TEXT("Shell_TrayWnd"),NULL);
  if(hShellTrayWnd)
  {
    GetWindowRect(hShellTrayWnd,lpTrayRect);
    if(lpTrayRect->right-lpTrayRect->left>DEFAULT_RECT_WIDTH)
      lpTrayRect->left=lpTrayRect->right-DEFAULT_RECT_WIDTH;
    if(lpTrayRect->bottom-lpTrayRect->top>DEFAULT_RECT_HEIGHT)
      lpTrayRect->top=lpTrayRect->bottom-DEFAULT_RECT_HEIGHT;

    return;
  }

  // OK. Haven't found a thing. Provide a default rect based on the current work
  // area
  SystemParametersInfo(SPI_GETWORKAREA,0,lpTrayRect,0);
  lpTrayRect->left=lpTrayRect->right-DEFAULT_RECT_WIDTH;
  lpTrayRect->top=lpTrayRect->bottom-DEFAULT_RECT_HEIGHT;
}

good luck
0
 
vbk_bgmCommented:
Hi,
The sys tray is a child window of the task bar. Hence you can obtain the rect in the foll way.
HWND hWndTask = FindWindow(_T("Shell_TrayWnd"), _T(""));
HWND hWndTray = NULL;
RECT rect;
for(HWND hWnd = GetWindow(hWndTask,GW_CHILD); hWnd != NULL; hWnd = GetWindow(hWnd,GW_HWNDNEXT))
    {
         TCHAR ClassName[MAX_PATH];
         if (GetClassName(hWnd,ClassName,MAX_PATH))
         {
              if (0 == lstrcmp(_T  ("TrayNotifyWnd"),ClassName))
              {
                   hWndTray = hWnd;
                   break;
              }
         }
    }
   
//get the rect in screen coordinates    
GetWindowRect(hWndTray,&rect);
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.