Tom A
Tom A

Reputation: 1682

Can I detect if a window is partly hidden?

Is it possible to detect if a window for a program outside mine is 1) completely visible, 2) partly hidden, or 3) completely hidden? I want to be able to tell my application not to do anything if a window (based on a retrieved handle) isn't visible. I don't care if the window has focus or not,what the z order is, or anything else, I'm just interested in how much of the window shows. If I need something else to get this, I'm fine, but is it possible? Thanks.

Upvotes: 5

Views: 2874

Answers (2)

Rob Kennedy
Rob Kennedy

Reputation: 163277

Raymond Chen wrote an article about this a few years ago.

The gist of it is that you can use GetClipBox to tell you what kind of clipping region a window's device context has. A null region means the window is totally obscured, and a complex region means it's partially obscured. If it's a simple (rectangular) region, then visibility depends on whether the visible rectangle coincides with the bounds of the window.

A DC can only be used by one thread at a time. Therefore, you should not acquire the DC of a window for an application that isn't yours. Otherwise, you may encounter a situation where the other application — unaware of what you're doing — attempts to use its DC while you're still using it to inspect the clipping region. It should be perfectly safe to use it to make judgments about your own windows, though.

Upvotes: 7

Francesca
Francesca

Reputation: 21640

Here's the solution I used to determine if a form is actually visible (even only partially) to the user. You can easily adapt to your exact use case.

function IsMyFormCovered(const MyForm: TForm): Boolean;
var
   MyRect: TRect;
   MyRgn, TempRgn: HRGN;
   RType: Integer;
   hw: HWND;
begin
  MyRect := MyForm.BoundsRect;            // screen coordinates
  MyRgn := CreateRectRgnIndirect(MyRect); // MyForm not overlapped region
  hw := GetTopWindow(0);                  // currently examined topwindow
  RType := SIMPLEREGION;                  // MyRgn type

// From topmost window downto MyForm, build the not overlapped portion of MyForm
  while (hw<>0) and (hw <> MyForm.handle) and (RType <> NULLREGION) do
  begin
    // nothing to do if hidden window
    if IsWindowVisible(hw) then
    begin
      GetWindowRect(hw, MyRect);
      TempRgn := CreateRectRgnIndirect(MyRect);// currently examined window region
      RType := CombineRgn(MyRgn, MyRgn, TempRgn, RGN_DIFF); // diff intersect
      DeleteObject( TempRgn );
    end; {if}
    if RType <> NULLREGION then // there's a remaining portion
      hw := GetNextWindow(hw, GW_HWNDNEXT);
  end; {while}

  DeleteObject(MyRgn);
  Result := RType = NULLREGION;
end;

function IsMyFormVisible(const MyForm : TForm): Boolean;
begin
  Result:= MyForm.visible and
           isWindowVisible(MyForm.Handle) and
           not IsMyFormCovered(MyForm);
end;

Upvotes: 4

Related Questions