Delphi 我能检测出窗户是否部分隐藏吗?

Delphi 我能检测出窗户是否部分隐藏吗?,delphi,visibility,Delphi,Visibility,有没有可能检测到矿井外的程序窗口1)完全可见,2)部分隐藏,还是3)完全隐藏?如果窗口(基于检索到的句柄)不可见,我希望能够告诉我的应用程序不要做任何事情。我不关心窗口是否有焦点,z顺序是什么,或者其他什么,我只关心窗口显示了多少。如果我需要别的东西来得到这个,我很好,但是有可能吗?谢谢。陈雷蒙几年前写道 它的要点是,您可以使用它来告诉您窗口的设备上下文具有什么样的剪辑区域。空区域表示窗口完全被遮挡,复杂区域表示窗口部分被遮挡。如果是简单(矩形)区域,则可见性取决于可见矩形是否与窗口边界重合 D

有没有可能检测到矿井外的程序窗口1)完全可见,2)部分隐藏,还是3)完全隐藏?如果窗口(基于检索到的句柄)不可见,我希望能够告诉我的应用程序不要做任何事情。我不关心窗口是否有焦点,z顺序是什么,或者其他什么,我只关心窗口显示了多少。如果我需要别的东西来得到这个,我很好,但是有可能吗?谢谢。

陈雷蒙几年前写道

它的要点是,您可以使用它来告诉您窗口的设备上下文具有什么样的剪辑区域。空区域表示窗口完全被遮挡,复杂区域表示窗口部分被遮挡。如果是简单(矩形)区域,则可见性取决于可见矩形是否与窗口边界重合


DC一次只能由一个线程使用。因此,您不应该为非您的应用程序获取窗口的DC。否则,您可能会遇到另一个应用程序(不知道您在做什么)在您仍在使用其DC检查剪裁区域时尝试使用其DC的情况。不过,使用它来判断您自己的窗口应该是非常安全的。

以下是我用来确定表单是否对用户实际可见(甚至只是部分可见)的解决方案。您可以轻松地适应您的确切用例

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;
函数IsMyFormCovered(const MyForm:TForm):布尔;
变量
MyRect:TRect;
MyRgn,TempRgn:HRGN;
RType:整数;
hw:HWND;
开始
MyRect:=MyForm.BoundsRect;//屏幕坐标
MyRgn:=CreateRectRgnIndirect(MyRect);//MyForm不重叠区域
hw:=GetTopWindow(0);//当前检查的topwindow
RType:=SIMPLEREGION;//MyRgn型
//从最上面的窗口向下到MyForm,构建MyForm的不重叠部分
而(hw0)和(hw MyForm.handle)和(RType NULLREGION)则
开始
//如果隐藏窗口,则无需执行任何操作
如果IsWindowVisible(hw),则
开始
GetWindowRect(hw,MyRect);
TempRgn:=CreateRectRgnIndirect(MyRect);//当前检查的窗口区域
RType:=组合器(MyRgn,MyRgn,TempRgn,RGN_DIFF);//差交
删除对象(TempRgn);
结束;{if}
如果RType NULLREGION,那么//还有一部分
hw:=GetNextWindow(hw,GW\u HWNDNEXT);
结束;{while}
删除对象(MyRgn);
结果:=RType=NULLREGION;
结束;
函数IsMyFormVisible(const MyForm:TForm):布尔;
开始
结果:=MyForm.visible和
isWindowVisible(MyForm.Handle)和
不是我的形式;
结束;

只是好奇:关于DC和线程的注意事项和警告,您的来源是什么?我在MSDN上找不到与此相关的任何信息,事实上GetDC()有一个合作伙伴ReleaseDC()[MSDN确实说必须由调用GetDC()的同一线程调用该线程]表明线程同步是(或者可以/应该)在GDI本身中处理的。。。i、 如果线程A试图获取DC(hWnd),而线程B已经拥有它,那么线程A将等待线程B释放它。这没有文档记录,但直觉上是我所期望的。我应该补充一点,我还没有测试过这个理论。[继续]:不是我所说的“确认”,但专家交换上的这个问题至少似乎支持我的理论:[进一步继续:]GetDC()可以返回NULL,表示无法获得DC,因此在我的理论线程a/B场景中,线程a也可能获得NULL DC,而不是被迫等待线程B(取决于GDI在该区域的实际行为)。我想知道有多少调用GetDC()的代码测试过结果?VCL[in]在TWinControl.GetDeviceContext()中测试结果是出了名的,但由于任何失败的原因,它都没有测试,只是盲目地(在我实际遇到的一次错误的情况下)报告了一个OutofResources。谢谢Rob,你链接的文章正好提供了我所需要的。这确实有效。忘记任何依赖GetClipBox()的答案吧-它根本不起作用(至少在现代情况下/Windows 10是如此)。这个解决方案(我不得不将代码转换成C++)确实可以告诉您窗口是否完全被窗口覆盖而隐藏。好东西。