unit my_monitor; //{$DEFINE _DEBUG} //{$DEFINE tttDEBUG} interface uses Windows, Messages, SysUtils, Classes, Controls, ExtCtrls, MultiMon, Forms; type //モニター座標 TMyMonitorPos = record MonitorNum: Integer; Position: TPoint; end; TMyScreenSize = class(TObject) private FrcDesktopRect : TRect; //デスクトップ全体のRect FrgDesktopRegion : HRGN; //各モニターのリージョンを足したもの FrcMonitorsRect : array of TRect; //各モニターのRect FhMonitorsHandle : array of HMONITOR; //各モニターのハンドル function FGetMonitorCount : Integer; function FGetMonitorsRect(iIndex: Integer) : TRect; function FGetScreenLeft : Integer; function FGetScreenTop : Integer; function FGetScreenWidth : Integer; function FGetScreenHeight : Integer; public constructor Create; destructor Destroy; override; procedure Reflesh; procedure SetBounds(AForm: TForm); function GetMonitorRect(AForm: TForm): TRect; function MonitorNum(hHandle: HMONITOR): Integer; overload; function MonitorNum(AForm: TForm): Integer; overload; //2015-07-23 function RectInDesktopRect(ARect: TRect): Boolean; property MonitorCount : Integer read FGetMonitorCount; property DesktopRegion : HRGN read FrgDesktopRegion; property DesktopRect : TRect read FrcDesktopRect; property ScreenLeft : Integer read FGetScreenLeft; property ScreenTop : Integer read FGetScreenTop; property ScreenWidth : Integer read FGetScreenWidth; property ScreenHeight : Integer read FGetScreenHeight; property MonitorsRect[iIndex: Integer]: TRect read FGetMonitorsRect; end; var MyScreenSize : TMyScreenSize; // MyCashDesktop : TMyScreenSize; function gfnrcMonitorRectGet(AScreenSize: TMyScreenSize; ptPos: TPoint): TRect; overload; function gfnrcMonitorRectGet(ptPos: TPoint) : TRect; overload; function gfnrScreenToMonitor(AScreenSize: TMyScreenSize; ptPos: TPoint): TMyMonitorPos; overload; function gfnrScreenToMonitor(ptPos: TPoint) : TMyMonitorPos; overload; //============================================================================== implementation uses {$IFDEF _DEBUG} myDebug, {$ENDIF} general; function gfnhMonitorFromRect(rcRect: TRect): HMONITOR; {2008-12-05: rcRectの領域があるモニターのモニターハンドルを返す。 } begin Result := MultiMon.MonitorFromRect(@rcRect, MONITOR_DEFAULTTONEAREST); end; function gfnrScreenToMonitor(AScreenSize: TMyScreenSize; ptPos: TPoint): TMyMonitorPos; {2008-07-08: スクリーン座標をモニター座標に変換して返す } var i: Integer; begin Result.MonitorNum := 0; Result.Position := Point(0, 0); for i := 0 to AScreenSize.MonitorCount -1 do begin if (PtInRect(AScreenSize.MonitorsRect[i], ptPos)) then begin Result.Position.X := ptPos.X - AScreenSize.MonitorsRect[i].Left; Result.Position.Y := ptPos.Y - AScreenSize.MonitorsRect[i].Top; Result.MonitorNum := i +1; //モニター番号なので+1; Break; end; end; end; function gfnrScreenToMonitor(ptPos: TPoint): TMyMonitorPos; begin Result := gfnrScreenToMonitor(MyScreenSize, ptPos); end; //------------------------------------------------------------------------------ { TMyScreenSize } constructor TMyScreenSize.Create; begin inherited; Reflesh; end; destructor TMyScreenSize.Destroy; begin DeleteObject(FrgDesktopRegion); inherited; end; procedure TMyScreenSize.Reflesh; //デスクトップの大きさ(各モニターの領域の総和)とリージョンをセット。 function _EnumMonitorsProc(hHandle: HMONITOR; dc: HDC; r: PRect; AScreenSize: TMyScreenSize): BOOL; stdcall; var li_Len, li_High : Integer; begin li_Len := Length(AScreenSize.FrcMonitorsRect) +1; SetLength(AScreenSize.FrcMonitorsRect, li_Len); li_High := High(AScreenSize.FrcMonitorsRect); AScreenSize.FrcMonitorsRect[li_High] := r^; SetLength(AScreenSize.FhMonitorsHandle, li_Len); AScreenSize.FhMonitorsHandle[li_High] := hHandle; Result := True; end; var i : Integer; lrc_Rect : TRect; lrg_Rgn : HRGN; begin FrcDesktopRect := Rect(0, 0, 0, 0); FrcMonitorsRect := nil; FhMonitorsHandle := nil; DeleteObject(FrgDesktopRegion); FrgDesktopRegion := CreateRectRgnIndirect(Rect(0, 0, 0, 0)); EnumDisplayMonitors(0, nil, @_EnumMonitorsProc, LPARAM(Self)); for i := 0 to High(FrcMonitorsRect) do begin {$IFDEF tttDEBUG} // AScreenSize.FrcMonitorsRect[li_High] := r^; myDebug.gpcDebug(IntToStr(i), FrcMonitorsRect[i]); if (i = 1) then FrcMonitorsRect[i] := Rect(0, 0, 3840, 2160); {$ENDIF} lrc_Rect := FrcMonitorsRect[i]; FrcDesktopRect.Left := gfniMin([FrcDesktopRect.Left, lrc_Rect.Left]); FrcDesktopRect.Top := gfniMin([FrcDesktopRect.Top, lrc_Rect.Top]); FrcDesktopRect.Right := gfniMax([FrcDesktopRect.Right, lrc_Rect.Right]); FrcDesktopRect.Bottom := gfniMax([FrcDesktopRect.Bottom, lrc_Rect.Bottom]); lrg_Rgn := CreateRectRgnIndirect(lrc_Rect); try {li_Ret :=} CombineRgn(FrgDesktopRegion, FrgDesktopRegion, lrg_Rgn, RGN_OR); //myDebug.gpcDebug(['CombineRgn', li_Ret]); finally DeleteObject(lrg_Rgn); end; end; {li_Ret :=} OffsetRgn(FrgDesktopRegion, -FrcDesktopRect.Left, -FrcDesktopRect.Top); //myDebug.gpcDebug(['OffsetRgn', li_Ret]); //li_Ret := GetRgnBox(FrgDesktopRegion, lrc_Test); //myDebug.gpcDebug(['GetRgnBox', gfnsRectString(lrc_Test)]); end; procedure TMyScreenSize.SetBounds(AForm : TForm); begin if not(RectInRegion(FrgDesktopRegion, gfnrcRectShift(AForm.BoundsRect, Point(-FrcDesktopRect.Left, -FrcDesktopRect.Top)))) then begin SetWindowPos(AForm.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOZORDER or SWP_NOACTIVATE); end; end; function TMyScreenSize.GetMonitorRect(AForm : TForm) : TRect; var lh_Handle : HMONITOR; i : Integer; begin lh_Handle := gfnhMonitorFromRect(AForm.BoundsRect); for i := 0 to FGetMonitorCount -1 do begin if (FhMonitorsHandle[i] = lh_Handle) then begin Result := FrcMonitorsRect[i]; Exit; end; end; Result := Rect(0, 0, 0, 0); end; function TMyScreenSize.MonitorNum(hHandle : HMONITOR) : Integer; var i : Integer; begin for i := 0 to FGetMonitorCount -1 do begin if (FhMonitorsHandle[i] = hHandle) then begin Result := i +1; //モニター番号なので+1 Exit; end; end; Result := -1; end; function TMyScreenSize.MonitorNum(AForm: TForm): Integer; {2015-07-23: AFormのあるモニター番号を返す。 } begin Result := MonitorNum(gfnhMonitorFromRect(AForm.BoundsRect)); end; function TMyScreenSize.FGetMonitorCount : Integer; begin Result := Length(FrcMonitorsRect); end; function TMyScreenSize.FGetMonitorsRect(iIndex : Integer) : TRect; //iIndexは0ベース。 //1ベースのモニター番号ではないことに注意。 begin Result := Rect(0, 0, 0, 0); if (iIndex < 0) or (iIndex >= FGetMonitorCount) then begin Exit; end; Result := FrcMonitorsRect[iIndex]; end; function TMyScreenSize.RectInDesktopRect(ARect: TRect): Boolean; var i : Integer; begin for i := 0 to FGetMonitorCount -1 do begin if (gfnbRectInRect(ARect, FGetMonitorsRect(i))) then begin Result := True; Exit; end; end; Result := False; end; function TMyScreenSize.FGetScreenLeft : Integer; begin Result := FrcDesktopRect.Left; end; function TMyScreenSize.FGetScreenTop : Integer; begin Result := FrcDesktopRect.Top; end; function TMyScreenSize.FGetScreenWidth : Integer; begin Result := gfniRectWidth(FrcDesktopRect); end; function TMyScreenSize.FGetScreenHeight : Integer; begin Result := gfniRectHeight(FrcDesktopRect); end; //------------------------------------------------------------------------------ function gfnrcMonitorRectGet(AScreenSize : TMyScreenSize; ptPos: TPoint): TRect; //モニター var i : Integer; lrc_Rect : TRect; begin for i := 0 to AScreenSize.MonitorCount -1 do begin lrc_Rect := AScreenSize.MonitorsRect[i]; if (PtInRect(lrc_Rect, ptPos)) then begin Result := lrc_Rect; Exit; end; end; Result := Rect(0, 0, 0, 0); //範囲外だった end; function gfnrcMonitorRectGet(ptPos: TPoint): TRect; begin Result := gfnrcMonitorRectGet(MyScreenSize, ptPos); end; //------------------------------------------------------------------------------ initialization MyScreenSize := TMyScreenSize.Create; // MyCashDesktop := TMyScreenSize.Create; finalization MyScreenSize.Free; MyScreenSize := nil; // MyCashDesktop.Free; // MyCashDesktop := nil; end.