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.
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.
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;