How do I determine if the user can see my window?

The answer to this one depends upon whether you wish to determine if the user can see your whole window, part of your window, or a specific point on your window.

A Single Point

to determine if the user can see a specific point, you can find the screen coordinates of that point, call WindowFromPoint, and check to see if the handle returned from WindowFromPoint is the same as yours. If so, you'd think the user can see that point (though of course it could be one pixel peeping out from behind the multiple windows covering it up). This simple function should test if the user can see the middle of your window :

BOOL IsWindowCentreVisibleToUser (HWND hWnd)
{
   BOOL bRetVal = FALSE;
   RECT rcWnd;
   POINT pt;

   if (IsWindow (hWnd))
   {
      GetWindowRect (hWnd, &rcWnd);
      pt.x = rcWnd.left + (rcWnd.right - rcWnd.left)/2;
      pt.y = rcWnd.top  + (rcWnd.bottom - rcWnd.top)/2;

      bRetVal = (WindowFromPoint (pt) == hWnd);
   }
   return bRetVal;
}

BUT - the down side of this simplistic solution is that WindowFromPoint doesn't return handles for disabled windows. Ack... so we need something better. Read on...

The Window, Whole or Part

Things get a little more complicated when we're talking about all or part of a window. Basically, the trick is to make Windows do the work for you by using the clipping system. Take a look at the code below:

#define IWVTU_FULL    1
#define IWVTU_PARTIAL 2
#define IWVTU_HIDDEN  3
#define IWVTU_ERROR   4

UINT IsWindowVisibleToUser (HWND hWnd)
{
   UINT uRetVal = IWVTU_ERROR;
   int  iClipRes;
   HDC hdcWnd;
   RECT rcWndClient;
   RECT rcWndClip;

   if (IsWindow (hWnd))
   {
      // This uses the clipping system to determine if the user
      // can see all or part of the window. The only problem
      // comes when the region returned is a rectangle, i.e. the
      // return code from GetClipBox is SIMPLEREGION. In that
      // case we check against the client area rectangle, on the
      // basis that what we _really_ care about is the contents
      // of the window, not the caption bar.

      hdcWnd = GetDC (hWnd);
      GetClientRect (hWnd, &rcWndClient);
      iClipRes = GetClipBox (hdcWnd, &rcWndClip);
      ReleaseDC (hWnd, hdcWnd);

      switch (iClipRes)
      {
         case NULLREGION:
            uRetVal = IWVTU_HIDDEN;
            break;
         case SIMPLEREGION:
            if (EqualRect (&rcWndClip, &rcWndClient))
               uRetVal = IWVTU_FULL;
            else
               uRetVal = IWVTU_PARTIAL;
            break;
         case COMPLEXREGION:
            uRetVal = IWVTU_PARTIAL;
            break;
         default:
            uRetVal = IWVTU_ERROR;
            break;
      }
   }
   return uRetVal;
}

This latter sample is based upon an idea originally posted by Russ Freeman.

Download