戻る

Delphiでウインドウの最大化時の大きさをコントロール(マルチモニタ対応)



参考にした情報

この内容はDelphi-ML「[Delphi:90115] ウインドウを最大化したまま最大化サイズを調節する」で付いたレスを参考にしています。 教えてくださる皆様、感謝感謝です。

GetMonitorInfoでモニタに関する情報を取得する

モニタの範囲を知るためにはWindows APIの「GetMonitorInfo」を使う。
このAPIはマルチモニタ対応のAPIで、ディスプレイモニタのハンドルを渡してあげる事によって、そのディスプレイモニタに関する情報を取得する事が出来ます。

情報はMONITORINFO 構造体によって返され、以下のような情報が帰ってきます。

  • モニタ全体の範囲
    MonitorInfo.rcMonitor.Bottom範囲の下側Y座標
    MonitorInfo.rcMonitor.Top範囲の上側Y座標
    MonitorInfo.rcMonitor.Left範囲の左側X座標
    MonitorInfo.rcMonitor.Right範囲の右側X座標

  • モニタ有効面の範囲
    MonitorInfo.rcWork.Bottom範囲の下側Y座標
    MonitorInfo.rcWork.Top範囲の上側Y座標
    MonitorInfo.rcWork.Left範囲の左側X座標
    MonitorInfo.rcWork.Right範囲の右側X座標

    以下の例では赤い四角がモニタの範囲、緑色の範囲がモニタの有効面の範囲になってます。
    タスクバーの分が有効面から除外されていますが、これは
    ウインドウを最大化したときに使える範囲=有効面だからです。
    ※「タスクバーを自動的に隠す」をしていない例です
    他のソフトで、デスクトップを占有するタイプのアプリケーションがある場合はその分も有効面から除外されます
    Monitor1_Bottom.jpg
    Monitor1_Top.jpg

    Monitor1_Left.jpg
    Monitor1_Right.jpg

    取得出来る値は、プライマリモニタの左上を原点として数値が決まります。
    2台目以降のモニタの位置はある程度好きなように置ける様です。
    Monitor2.jpg
    ※ぜんぜん関係ない話ですが、上の図はExcelで作っている物を、セル範囲のコピーってそのままペイント等に画像として貼り付けしてます。
    知らなかったです…なんとなく「出来るかな?」と思ってやって出来てびっくり。

    Delphiのコードだとこんな感じです
    var
      FMonitorInfo: TMonitorInfo;
    begin
      ZeroMemory(@FMonitorInfo, sizeof(FMonitorInfo));
      FMonitorInfo.cbSize := SizeOf(FMonitorInfo);
      GetMonitorInfo(FTargetForm.Monitor.Handle, @FMonitorInfo);

WMGetMinMaxInfoメッセージ

最大化の時に、フォームの大きさと位置の制限をするにはWMGetMinMaxInfoメッセージを使います

procedure WMGetMinMaxInfo(var msg : TWMGetMinMaxInfo); message WM_GETMINMAXINFO;


設定できる値は、以下の通りです。

msg.MinMaxInfo.ptMaxPosition.Xフォームの左上のX座標を指定します
msg.MinMaxInfo.ptMaxPosition.Yフォームの左上のY座標を指定します
msg.MinMaxInfo.ptMaxSize.Xフォームの横幅を指定します
msg.MinMaxInfo.ptMaxSize.Yフォームの縦幅を指定します


「msg.MinMaxInfo.ptMaxPosition.X」「msg.MinMaxInfo.ptMaxPosition.Y」は各種モニタの左上を原点として数値が決まります。

Monitor3.jpg

さらに、フォームのBorderStyleによって、原点位置が変わります

BorderStyle座標の原点
bsDialogモニタ全体の範囲から(0,0)
bsNoneモニタ全体の範囲から(0,0)
bsSingleモニタ有効面の範囲から(0,0)
bsSizeableモニタ有効面の範囲から(0,0)
bsSizeToolWinモニタ全体の範囲から(0,0)
bsToolWindowモニタ全体の範囲から(0,0)

※2009/5/7の時点では「2000・XP」と「Vista・7」では原点位置が変わる様に書いていたのですが、いつの間にか「2000・XP」と同じ動作になる様に「Vista・7」が修正された様です。

作ってみたコード

マルチディスプレイ対応です。
この内容はDelphi-ML「[Delphi:90115] ウインドウを最大化したまま最大化サイズを調節する」で付いたレスを参考にしています。
教えてくださる皆様、感謝感謝です。

2008/1/24修正 ウインドウがbsSizeable・bsSingle以外のモードの場合が動きおかしかったのを修正
2009/5/7修正 WMGetMinMaxInfo2関数で、ちらつきを抑えつつ変更されるように作っていましたが、
色々な場面(OS・フォームBorderStyle・OSテーマ対応)で動作が不安定なので断念…
2010/9/17修正 Vista・7だけ動作が違っていた部分があったが、いつの間にか修正されていた様なので2000・XPと同じ動作をする様に修正する

ダウンロード

80x15.png この作品はクリエイティブ・コモンズ・ライセンスの下でライセンスされています。

{*****************************************************************************}
{                                                                             }
{       MultiMonitorParam                                                     }
{                                                                             }
{       Copyright (c) 2007 Moon Doldo                                         }
{                                                                             }
{この内容はDelphi-ML                                                          }
{[Delphi:90115] ウインドウを最大化したまま最大化サイズを調節する              }
{で付いたレスを参考にしています。                                             }
{                                                                             }
{*****************************************************************************}

unit MultiMonitorParam;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Math, MultiMon, UxTheme;

type
  // TargetFormが指定されていないか存在しないエラー
  ETargetFormIsNotFound = class(Exception);

  // MonitorInfo保持クラス
  TMonitorInfoParam = class(TComponent)
  private
    FMonitorInfo : TMonitorInfo;
    FDisplayMonitorInfo: TMonitorInfo;
    FTargetForm: TForm;

    procedure SetTargetForm(const Value: TForm);
  protected
    // MonitorInfoの取得
    procedure GetMonitorInfoParam;

  public
    //TComponent等 Owner付コンストラクタ定義
    constructor Create(AOwner: TComponent); override;

    // ディスプレイモニタに関する情報を取得
    // プライマリモニタの左上を原点(0,0)として座標値を返す
    function MonitorInfo: TMonitorInfo;
    // ディスプレイモニタに関する情報を取得
    // 各モニタの左上を原点(0,0)として座標値を返す
    function DisplayMonitorInfo: TMonitorInfo;

    // モニタの数を取得
    function MonitorCount: Integer;

    // モニタ番号の取得
    function MonitorNum: Integer;
  published
    // 対象のウインドウを設定
    property TargetForm: TForm read FTargetForm write SetTargetForm;
  end;

  // 最大化の管理クラス
  TMultiMonitorMaxInfoCalc = class(TMonitorInfoParam)
  private
    FMaxSizeY: Integer;
    FMaxSizeX: Integer;
    FMaxPositionY: Integer;
    FMaxPositionX: Integer;
    FMaxAlign: TAlign;

    procedure SetMaxSizeX(const Value: Integer);
    procedure SetMaxSizeY(const Value: Integer);
    procedure SetMaxPositionX(const Value: Integer);
    procedure SetMaxPositionY(const Value: Integer);

    procedure SetMaxAlign(const Value: TAlign);
  protected
    // フォームの大きさと位置の制限(WMGetMinMaxInfo)
    procedure WMNoneGetMinMaxInfo(var msg : TWMGetMinMaxInfo);
    procedure WMClientGetMinMaxInfo(var msg : TWMGetMinMaxInfo);
    procedure WMCustomGetMinMaxInfo(var msg : TWMGetMinMaxInfo);
    procedure WMTopGetMinMaxInfo(var msg : TWMGetMinMaxInfo);
    procedure WMBottomGetMinMaxInfo(var msg : TWMGetMinMaxInfo);
    procedure WMLeftGetMinMaxInfo(var msg : TWMGetMinMaxInfo);
    procedure WMRightGetMinMaxInfo(var msg : TWMGetMinMaxInfo);
  public
    //TComponent等 Owner付コンストラクタ定義
    constructor Create(AOwner: TComponent); override;
    //デストラクタ定義
    destructor Destroy; override;

    // フォームの大きさと位置の制限
    procedure WMGetMinMaxInfo(var msg : TWMGetMinMaxInfo);

    // フォームの大きさと位置の制限(既に最大化している場合)
    procedure WMGetMinMaxInfo2;

    // 通常の状態のフォームを適切な位置へ移動する
    procedure SetFormSafePosition;
  published
    // 設定したいウインドウサイズを指定する
    // alLeft, alRight, alCustomの場合のみ実行される
    property MaxSizeX: Integer read FMaxSizeX write SetMaxSizeX;
    // alTop, alBottom, alCustomの場合のみ実行される
    property MaxSizeY: Integer read FMaxSizeY write SetMaxSizeY;

    // 設定したい位置を指定する(各種モニタの有効面の左上を原点(0,0))
    // alCustomの場合のみ実行される
    property MaxPositionX: Integer read FMaxPositionX write SetMaxPositionX;
    property MaxPositionY: Integer read FMaxPositionY write SetMaxPositionY;

    // 最大化の際に、モニタ内でコントロールを揃える方法を指定します。
    property MaxAlign: TAlign read FMaxAlign write SetMaxAlign;
  end;

// ウインドウハンドルからモニタ番号の取得
function GetHWNDToMonitorNum(hWnd: HWND): Integer;

// Windows XP/Server2003で
// なおかつ「Windows XP スタイル」が設定されているかチェック
function isWindowsXPUseThemes: Boolean;

implementation

function GetHWNDToMonitorNum(hWnd: HWND): Integer;
var
  wHMonitor: HMonitor;
  wHMonitorIndex: Integer;
  wMonitor: TMonitor;
begin
  Result := -1;
  wHMonitor := MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
  for wHMonitorIndex := 0 to Screen.MonitorCount - 1 do
  begin
    if Screen.Monitors[wHMonitorIndex].Handle = wHMonitor then
    begin
      wMonitor := Screen.Monitors[wHMonitorIndex];
      result := wMonitor.MonitorNum;
      Exit;
    end;
  end;
end;

function isWindowsXPUseThemes: Boolean;
var
  WkMajor, WkMinor: LongInt;
  WkInfo: TOSVersionInfo;
begin
  WkInfo.dwOSVersionInfoSize := SizeOf(WkInfo);
  GetVersionEx(WkInfo);
  WkMajor := WkInfo.dwMajorVersion ;
  WkMinor := WkInfo.dwMinorVersion ;
  // dwMajorVersionが5は2000・XP・Server2003
  if WkMajor = 5 then
  begin
    // dwMinorVersionが1はXP
    // dwMinorVersionが2はServer2003
    if (WkMinor = 1) or (WkMinor = 2) then
    begin
      // UxThemeのUseThemesは
      // OSがテーマ対応かクラシックモードかを判別する
      // アプリケーションは関係なし
      result := UseThemes;
    end
    else begin
      result := False;
    end;
  end
  else begin
    result := False;
  end;
end;

{ TMultiMonitorMaxInfoCalc }

constructor TMultiMonitorMaxInfoCalc.Create(AOwner: TComponent);
begin
  inherited;  //上位のクリエイトを呼び出す(Create表記を省略)
  //↓Createを呼出し後に別の処理を書くのが一般的

  FMaxAlign := alCustom;

  FMaxSizeY := 0;
  FMaxSizeX := 0;
  FMaxPositionY := 0;
  FMaxPositionX := 0;
end;

destructor TMultiMonitorMaxInfoCalc.Destroy;
begin
  inherited;
end;

procedure TMultiMonitorMaxInfoCalc.SetFormSafePosition;
var
  WkMonitorInfo : TMonitorInfo;

  WkMonitorInfoWidth, WkMonitorInfoHeight: Integer;
  WkTargetFormRight, WkTargetFormBottom: Integer;

  WkLeft, WkTop: Integer;
begin
  // ウインドウが存在しない場合は例外を発生させる
  if FTargetForm = nil then
  begin
    raise ETargetFormIsNotFound.Create('TargetFormが指定されていません');
  end;
  if IsWindow(FTargetForm.Handle) = False then
  begin
    raise ETargetFormIsNotFound.Create('TargetFormで指定したフォームが存在されていません');
  end;

  if FTargetForm.WindowState = wsNormal then
  begin
    // ディスプレイモニタに関する情報を取得
    WkMonitorInfo := Self.MonitorInfo;

    WkLeft := FTargetForm.Left;
    WkTop := FTargetForm.Top;

    // 左上が有効面からはみ出ていたら直す
    if WkLeft < WkMonitorInfo.rcWork.Left then
    begin
      WkLeft := WkMonitorInfo.rcWork.Left;
    end;
    if WkTop < WkMonitorInfo.rcWork.Top then
    begin
      WkTop := WkMonitorInfo.rcWork.Top;
    end;

    // 右下が有効面からはみ出ていたら直す
    // ただし、有効面のよりフォームが小さい場合のみ行う(左上を優先にするため)
    WkMonitorInfoWidth :=
      WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left;
    if FTargetForm.Width <= WkMonitorInfoWidth then
    begin
      WkTargetFormRight := WkLeft + FTargetForm.Width;
      if WkTargetFormRight > WkMonitorInfo.rcWork.Right then
      begin
        WkLeft := WkMonitorInfo.rcWork.Right - FTargetForm.Width;
      end;
    end;
    WkMonitorInfoHeight :=
      WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top;
    if FTargetForm.Height <= WkMonitorInfoHeight then
    begin
      WkTargetFormBottom := WkTop + FTargetForm.Height;
      if WkTargetFormBottom > WkMonitorInfo.rcWork.Bottom then
      begin
        WkTop := WkMonitorInfo.rcWork.Bottom - FTargetForm.Height;
      end;
    end;

    FTargetForm.Left := WkLeft;
    FTargetForm.Top := WkTop;
  end;
end;

procedure TMultiMonitorMaxInfoCalc.SetMaxAlign(const Value: TAlign);
begin
  FMaxAlign := Value;
  WMGetMinMaxInfo2;
end;

procedure TMultiMonitorMaxInfoCalc.SetMaxPositionX(const Value: Integer);
begin
  FMaxPositionX := Value;
end;

procedure TMultiMonitorMaxInfoCalc.SetMaxPositionY(const Value: Integer);
begin
  FMaxPositionY := Value;
end;

procedure TMultiMonitorMaxInfoCalc.SetMaxSizeX(const Value: Integer);
begin
  FMaxSizeX := Value;
end;

procedure TMultiMonitorMaxInfoCalc.SetMaxSizeY(const Value: Integer);
begin
  FMaxSizeY := Value;
end;

procedure TMultiMonitorMaxInfoCalc.WMBottomGetMinMaxInfo(
  var msg: TWMGetMinMaxInfo);
var
  WkMonitorInfo : TMonitorInfo;

  WkPositionX, WkPositionY: Integer;
  WkBoundaryX, WkBoundaryY: Integer;
begin
  // ディスプレイモニタに関する情報を取得
  // プライマリモニタの左上を原点(0,0)とした値が帰ってくる
  WkMonitorInfo := Self.MonitorInfo;

  // フォームのサイズをmsg.MinMaxInfo.ptMaxSizeに指定
  msg.MinMaxInfo.ptMaxSize.X :=
    WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left;
  msg.MinMaxInfo.ptMaxSize.Y :=
    Min(FMaxSizeY,
    WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top);

  // フォームの位置を保持
  WkPositionX := WkMonitorInfo.rcWork.Left;
  WkPositionY := WkMonitorInfo.rcWork.Bottom - msg.MinMaxInfo.ptMaxSize.Y;

  // フォームの位置をmsg.MinMaxInfo.ptMaxPositionに指定
  // msg.MinMaxInfo.ptMaxPositionは
  // BorderStyleがbsSizeableおよびbsSingleの場合は
  // 各モニタの有効面の左上を原点(0,0)とした座標を指定する。
  // それ以外のBorderStyleでは
  // 各モニタの左上を原点(0,0)として座標値を返す
  if (TargetForm.BorderStyle = bsSizeable) or
    (TargetForm.BorderStyle = bsSingle) then
  begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcWork.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcWork.Top;
  end
  else begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcMonitor.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcMonitor.Top;
  end;

  // WindowsXP・Server2003でOSがテーマ対応の場合
  // BorderStyleがbsDialogが設定されると
  // 境界線が表示されないので、その調整のために境界線の幅だけ調整する
  if (isWindowsXPUseThemes = True) and
    (TargetForm.BorderStyle = bsDialog) then
  begin
    // 立体効果付きのウィンドウの境界線の幅 +
    // 立体効果のないウィンドウの境界の幅 を取得
    WkBoundaryX := GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CXBORDER);
    WkBoundaryY := GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CXBORDER);

    msg.MinMaxInfo.ptMaxSize.X :=
      msg.MinMaxInfo.ptMaxSize.X + (WkBoundaryX * 2);
    msg.MinMaxInfo.ptMaxSize.Y :=
      msg.MinMaxInfo.ptMaxSize.Y + (WkBoundaryY * 2);
    msg.MinMaxInfo.ptMaxPosition.X :=
      msg.MinMaxInfo.ptMaxPosition.X - WkBoundaryX;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      msg.MinMaxInfo.ptMaxPosition.Y - WkBoundaryY;
  end;

  {
  // デバッグ用
  ShowMessage(
    'msg.MinMaxInfo.ptMaxPosition.X:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxPosition.Y:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.Y) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.X:' + IntToStr(msg.MinMaxInfo.ptMaxSize.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.Y:' + IntToStr(msg.MinMaxInfo.ptMaxSize.Y)
    );
  }
end;

procedure TMultiMonitorMaxInfoCalc.WMCustomGetMinMaxInfo(
  var msg: TWMGetMinMaxInfo);
var
  WkMonitorInfo : TMonitorInfo;

  WkPositionX, WkPositionY: Integer;
  WkBoundaryX, WkBoundaryY: Integer;
begin
  // ディスプレイモニタに関する情報を取得
  // プライマリモニタの左上を原点(0,0)とした値が帰ってくる
  WkMonitorInfo := Self.MonitorInfo;

  // フォームの位置を保持
  WkPositionX :=
    FMaxPositionX + WkMonitorInfo.rcWork.Left;
  WkPositionY :=
    FMaxPositionY + WkMonitorInfo.rcWork.Top;

  // 有効面から左上にはみ出ている場合は直す
  if WkPositionX < WkMonitorInfo.rcWork.Left then
  begin
    WkPositionX := WkMonitorInfo.rcWork.Left;
  end;
  if WkPositionY < WkMonitorInfo.rcWork.Top then
  begin
    WkPositionY := WkMonitorInfo.rcWork.Top;
  end;

  // フォームのサイズをmsg.MinMaxInfo.ptMaxSizeに指定
  // 有効面以上の大きさにならないように大きさを修正する
  msg.MinMaxInfo.ptMaxSize.X :=
    Min(FMaxSizeX,
    WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left - FMaxPositionX);
  msg.MinMaxInfo.ptMaxSize.Y :=
    Min(FMaxSizeY,
    WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top - FMaxPositionY);

  // フォームの位置をmsg.MinMaxInfo.ptMaxPositionに指定
  // msg.MinMaxInfo.ptMaxPositionは
  // BorderStyleがbsSizeableおよびbsSingleの場合は
  // 各モニタの有効面の左上を原点(0,0)とした座標を指定する。
  // それ以外のBorderStyleでは
  // 各モニタの左上を原点(0,0)として座標値を返す
  if (TargetForm.BorderStyle = bsSizeable) or
    (TargetForm.BorderStyle = bsSingle) then
  begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcWork.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcWork.Top;
  end
  else begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcMonitor.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcMonitor.Top;
  end;

  // WindowsXP・Server2003でOSがテーマ対応の場合
  // BorderStyleがbsDialogが設定されると
  // 境界線が表示されないので、その調整のために境界線の幅だけ調整する
  if (isWindowsXPUseThemes = True) and
    (TargetForm.BorderStyle = bsDialog) then
  begin
    // 立体効果付きのウィンドウの境界線の幅 +
    // 立体効果のないウィンドウの境界の幅 を取得
    WkBoundaryX := GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CXBORDER);
    WkBoundaryY := GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CXBORDER);

    msg.MinMaxInfo.ptMaxSize.X :=
      msg.MinMaxInfo.ptMaxSize.X + (WkBoundaryX * 2);
    msg.MinMaxInfo.ptMaxSize.Y :=
      msg.MinMaxInfo.ptMaxSize.Y + (WkBoundaryY * 2);
    msg.MinMaxInfo.ptMaxPosition.X :=
      msg.MinMaxInfo.ptMaxPosition.X - WkBoundaryX;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      msg.MinMaxInfo.ptMaxPosition.Y - WkBoundaryY;
  end;

  {
  // デバッグ用
  ShowMessage(
    'msg.MinMaxInfo.ptMaxPosition.X:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxPosition.Y:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.Y) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.X:' + IntToStr(msg.MinMaxInfo.ptMaxSize.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.Y:' + IntToStr(msg.MinMaxInfo.ptMaxSize.Y)
    );
  }
end;

procedure TMultiMonitorMaxInfoCalc.WMGetMinMaxInfo(
  var msg: TWMGetMinMaxInfo);
begin
  // ウインドウが存在しない場合は終了
  if FTargetForm = nil then
  begin
    Exit;
  end;
  if IsWindow(FTargetForm.Handle) = False then
  begin
    Exit;
  end;

  case FMaxAlign of
    alNone:
    begin
      WMNoneGetMinMaxInfo(msg);
    end;
    alClient:
    begin
      WMClientGetMinMaxInfo(msg);
    end;
    alCustom:
    begin
      WMCustomGetMinMaxInfo(msg);
    end;
    alTop:
    begin
      WMTopGetMinMaxInfo(msg);
    end;
    alBottom:
    begin
      WMBottomGetMinMaxInfo(msg);
    end;
    alLeft:
    begin
      WMLeftGetMinMaxInfo(msg);
    end;
    alRight:
    begin
      WMRightGetMinMaxInfo(msg);
    end;
  else
    raise Exception.Create('MaxAlignのエラーです' + #13#10 +
      'プログラミングエラーです、開発者にお問い合わせください');
  end;
end;


procedure TMultiMonitorMaxInfoCalc.WMGetMinMaxInfo2;
begin
  // ウインドウが存在しない場合は終了
  if FTargetForm = nil then
  begin
    Exit;
  end;
  if IsWindow(FTargetForm.Handle) = False then
  begin
    Exit;
  end;

  // 最大化の時のみ実行される
  if IsZoomed(FTargetForm.Handle) then
  begin
    // 最小化して最大化
    ShowWindow(FTargetForm.Handle, SW_NORMAL);
    ShowWindow(FTargetForm.Handle, SW_MAXIMIZE);

    // 以前は、ちらつきを抑えつつ変更されるように作っていましたが、
    // 色々な場面(OS・フォームBorderStyle・OSテーマ対応)
    // で動作が不安定なので断念…
    // Delphi-MLで教えていただいた方申し訳ありません。
  end;
end;

procedure TMultiMonitorMaxInfoCalc.WMLeftGetMinMaxInfo(
  var msg: TWMGetMinMaxInfo);
var
  WkMonitorInfo : TMonitorInfo;

  WkPositionX, WkPositionY: Integer;
  WkBoundaryX, WkBoundaryY: Integer;
begin
  // ディスプレイモニタに関する情報を取得
  // プライマリモニタの左上を原点(0,0)とした値が帰ってくる
  WkMonitorInfo := Self.MonitorInfo;

  // フォームの位置を保持
  WkPositionX := WkMonitorInfo.rcWork.Left;
  WkPositionY := WkMonitorInfo.rcWork.Top;

  // フォームのサイズをmsg.MinMaxInfo.ptMaxSizeに指定
  msg.MinMaxInfo.ptMaxSize.X :=
    Min(FMaxSizeX,
    WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left);
  msg.MinMaxInfo.ptMaxSize.Y :=
    WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top;

  // フォームの位置をmsg.MinMaxInfo.ptMaxPositionに指定
  // msg.MinMaxInfo.ptMaxPositionは
  // BorderStyleがbsSizeableおよびbsSingleの場合は
  // 各モニタの有効面の左上を原点(0,0)とした座標を指定する。
  // それ以外のBorderStyleでは
  // 各モニタの左上を原点(0,0)として座標値を返す
  if (TargetForm.BorderStyle = bsSizeable) or
    (TargetForm.BorderStyle = bsSingle) then
  begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcWork.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcWork.Top;
  end
  else begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcMonitor.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcMonitor.Top;
  end;

  // WindowsXP・Server2003でOSがテーマ対応の場合
  // BorderStyleがbsDialogが設定されると
  // 境界線が表示されないので、その調整のために境界線の幅だけ調整する
  if (isWindowsXPUseThemes = True) and
    (TargetForm.BorderStyle = bsDialog) then
  begin
    // 立体効果付きのウィンドウの境界線の幅 +
    // 立体効果のないウィンドウの境界の幅 を取得
    WkBoundaryX := GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CXBORDER);
    WkBoundaryY := GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CXBORDER);

    msg.MinMaxInfo.ptMaxSize.X :=
      msg.MinMaxInfo.ptMaxSize.X + (WkBoundaryX * 2);
    msg.MinMaxInfo.ptMaxSize.Y :=
      msg.MinMaxInfo.ptMaxSize.Y + (WkBoundaryY * 2);
    msg.MinMaxInfo.ptMaxPosition.X :=
      msg.MinMaxInfo.ptMaxPosition.X - WkBoundaryX;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      msg.MinMaxInfo.ptMaxPosition.Y - WkBoundaryY;
  end;

  {
  // デバッグ用
  ShowMessage(
    'msg.MinMaxInfo.ptMaxPosition.X:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxPosition.Y:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.Y) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.X:' + IntToStr(msg.MinMaxInfo.ptMaxSize.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.Y:' + IntToStr(msg.MinMaxInfo.ptMaxSize.Y)
    );
  }
end;

procedure TMultiMonitorMaxInfoCalc.WMClientGetMinMaxInfo(
  var msg: TWMGetMinMaxInfo);
var
  WkMonitorInfo : TMonitorInfo;

  WkPositionX, WkPositionY: Integer;
  WkBoundaryX, WkBoundaryY: Integer;
begin
  // ディスプレイモニタに関する情報を取得
  // プライマリモニタの左上を原点(0,0)とした値が帰ってくる
  WkMonitorInfo := Self.MonitorInfo;

  // フォームの位置を保持
  WkPositionX := WkMonitorInfo.rcWork.Left;
  WkPositionY := WkMonitorInfo.rcWork.Top;

  // フォームのサイズをmsg.MinMaxInfo.ptMaxSizeに指定
  msg.MinMaxInfo.ptMaxSize.X :=
    WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left;
  msg.MinMaxInfo.ptMaxSize.Y :=
    WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top;

  // フォームの位置をmsg.MinMaxInfo.ptMaxPositionに指定
  // msg.MinMaxInfo.ptMaxPositionは
  // BorderStyleがbsSizeableおよびbsSingleの場合は
  // 各モニタの有効面の左上を原点(0,0)とした座標を指定する。
  // それ以外のBorderStyleでは
  // 各モニタの左上を原点(0,0)として座標値を返す
  if (TargetForm.BorderStyle = bsSizeable) or
    (TargetForm.BorderStyle = bsSingle) then
  begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcWork.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcWork.Top;
  end
  else begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcMonitor.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcMonitor.Top;
  end;

  // WindowsXP・Server2003でOSがテーマ対応の場合
  // BorderStyleがbsDialogが設定されると
  // 境界線が表示されないので、その調整のために境界線の幅だけ調整する
  if (isWindowsXPUseThemes = True) and
    (TargetForm.BorderStyle = bsDialog) then
  begin
    // 立体効果付きのウィンドウの境界線の幅 +
    // 立体効果のないウィンドウの境界の幅 を取得
    WkBoundaryX := GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CXBORDER);
    WkBoundaryY := GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CXBORDER);

    msg.MinMaxInfo.ptMaxSize.X :=
      msg.MinMaxInfo.ptMaxSize.X + (WkBoundaryX * 2);
    msg.MinMaxInfo.ptMaxSize.Y :=
      msg.MinMaxInfo.ptMaxSize.Y + (WkBoundaryY * 2);
    msg.MinMaxInfo.ptMaxPosition.X :=
      msg.MinMaxInfo.ptMaxPosition.X - WkBoundaryX;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      msg.MinMaxInfo.ptMaxPosition.Y - WkBoundaryY;
  end;

  {
  // デバッグ用
  ShowMessage(
    'msg.MinMaxInfo.ptMaxPosition.X:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxPosition.Y:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.Y) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.X:' + IntToStr(msg.MinMaxInfo.ptMaxSize.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.Y:' + IntToStr(msg.MinMaxInfo.ptMaxSize.Y)
    );
  }
end;

procedure TMultiMonitorMaxInfoCalc.WMRightGetMinMaxInfo(
  var msg: TWMGetMinMaxInfo);
var
  WkMonitorInfo : TMonitorInfo;

  WkPositionX, WkPositionY: Integer;
  WkBoundaryX, WkBoundaryY: Integer;
begin
  // ディスプレイモニタに関する情報を取得
  // プライマリモニタの左上を原点(0,0)とした値が帰ってくる
  WkMonitorInfo := Self.MonitorInfo;

  // フォームのサイズをmsg.MinMaxInfo.ptMaxSizeに指定
  msg.MinMaxInfo.ptMaxSize.X :=
    Min(FMaxSizeX,
    WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left);
  msg.MinMaxInfo.ptMaxSize.Y :=
    WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top;

  // フォームの位置を保持
  WkPositionX := WkMonitorInfo.rcWork.Right - msg.MinMaxInfo.ptMaxSize.X;
  WkPositionY := WkMonitorInfo.rcWork.Top;

  // フォームの位置をmsg.MinMaxInfo.ptMaxPositionに指定
  // msg.MinMaxInfo.ptMaxPositionは
  // BorderStyleがbsSizeableおよびbsSingleの場合は
  // 各モニタの有効面の左上を原点(0,0)とした座標を指定する。
  // それ以外のBorderStyleでは
  // 各モニタの左上を原点(0,0)として座標値を返す
  if (TargetForm.BorderStyle = bsSizeable) or
    (TargetForm.BorderStyle = bsSingle) then
  begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcWork.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcWork.Top;
  end
  else begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcMonitor.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcMonitor.Top;
  end;

  // WindowsXP・Server2003でOSがテーマ対応の場合
  // BorderStyleがbsDialogが設定されると
  // 境界線が表示されないので、その調整のために境界線の幅だけ調整する
  if (isWindowsXPUseThemes = True) and
    (TargetForm.BorderStyle = bsDialog) then
  begin
    // 立体効果付きのウィンドウの境界線の幅 +
    // 立体効果のないウィンドウの境界の幅 を取得
    WkBoundaryX := GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CXBORDER);
    WkBoundaryY := GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CXBORDER);

    msg.MinMaxInfo.ptMaxSize.X :=
      msg.MinMaxInfo.ptMaxSize.X + (WkBoundaryX * 2);
    msg.MinMaxInfo.ptMaxSize.Y :=
      msg.MinMaxInfo.ptMaxSize.Y + (WkBoundaryY * 2);
    msg.MinMaxInfo.ptMaxPosition.X :=
      msg.MinMaxInfo.ptMaxPosition.X - WkBoundaryX;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      msg.MinMaxInfo.ptMaxPosition.Y - WkBoundaryY;
  end;

  {
  // デバッグ用
  ShowMessage(
    'msg.MinMaxInfo.ptMaxPosition.X:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxPosition.Y:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.Y) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.X:' + IntToStr(msg.MinMaxInfo.ptMaxSize.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.Y:' + IntToStr(msg.MinMaxInfo.ptMaxSize.Y)
    );
  }
end;

procedure TMultiMonitorMaxInfoCalc.WMTopGetMinMaxInfo(
  var msg: TWMGetMinMaxInfo);
var
  WkMonitorInfo : TMonitorInfo;

  WkPositionX, WkPositionY: Integer;
  WkBoundaryX, WkBoundaryY: Integer;
begin
  // ディスプレイモニタに関する情報を取得
  // プライマリモニタの左上を原点(0,0)とした値が帰ってくる
  WkMonitorInfo := Self.MonitorInfo;

  // フォームの位置を保持
  WkPositionX := WkMonitorInfo.rcWork.Left;
  WkPositionY := WkMonitorInfo.rcWork.Top;

  // フォームのサイズをmsg.MinMaxInfo.ptMaxSizeに指定
  msg.MinMaxInfo.ptMaxSize.X :=
    WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left;
  msg.MinMaxInfo.ptMaxSize.Y :=
    Min(FMaxSizeY,
    WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top);

  // フォームの位置をmsg.MinMaxInfo.ptMaxPositionに指定
  // msg.MinMaxInfo.ptMaxPositionは
  // BorderStyleがbsSizeableおよびbsSingleの場合は
  // 各モニタの有効面の左上を原点(0,0)とした座標を指定する。
  // それ以外のBorderStyleでは
  // 各モニタの左上を原点(0,0)として座標値を返す
  if (TargetForm.BorderStyle = bsSizeable) or
    (TargetForm.BorderStyle = bsSingle) then
  begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcWork.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcWork.Top;
  end
  else begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcMonitor.Left;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcMonitor.Top;
  end;

  // WindowsXP・Server2003でOSがテーマ対応の場合
  // BorderStyleがbsDialogが設定されると
  // 境界線が表示されないので、その調整のために境界線の幅だけ調整する
  if (isWindowsXPUseThemes = True) and
    (TargetForm.BorderStyle = bsDialog) then
  begin
    // 立体効果付きのウィンドウの境界線の幅 +
    // 立体効果のないウィンドウの境界の幅 を取得
    WkBoundaryX := GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CXBORDER);
    WkBoundaryY := GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CXBORDER);

    msg.MinMaxInfo.ptMaxSize.X :=
      msg.MinMaxInfo.ptMaxSize.X + (WkBoundaryX * 2);
    msg.MinMaxInfo.ptMaxSize.Y :=
      msg.MinMaxInfo.ptMaxSize.Y + (WkBoundaryY * 2);
    msg.MinMaxInfo.ptMaxPosition.X :=
      msg.MinMaxInfo.ptMaxPosition.X - WkBoundaryX;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      msg.MinMaxInfo.ptMaxPosition.Y - WkBoundaryY;
  end;

  {
  // デバッグ用
  ShowMessage(
    'msg.MinMaxInfo.ptMaxPosition.X:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxPosition.Y:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.Y) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.X:' + IntToStr(msg.MinMaxInfo.ptMaxSize.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.Y:' + IntToStr(msg.MinMaxInfo.ptMaxSize.Y)
    );
  }
end;

procedure TMultiMonitorMaxInfoCalc.WMNoneGetMinMaxInfo(
  var msg: TWMGetMinMaxInfo);
var
  WkMonitorInfo : TMonitorInfo;

  WkPositionX, WkPositionY: Integer;
  WkBoundaryX, WkBoundaryY: Integer;
begin
  // ディスプレイモニタに関する情報を取得
  // プライマリモニタの左上を原点(0,0)とした値が帰ってくる
  WkMonitorInfo := Self.MonitorInfo;

  // フォームの位置を保持
  if (TargetForm.BorderStyle = bsSizeable) or
    (TargetForm.BorderStyle = bsSingle) then
  begin
    // bsSizeable, bsSingle は
    // 最大化はモニタ有効面の範囲で広がる
    WkPositionX := WkMonitorInfo.rcWork.Left;
    WkPositionY := WkMonitorInfo.rcWork.Top;
  end
  else begin
    // bsDialog, bsNone, bsSizeToolWin, bsToolWindow は
    // 最大化はモニタ全体の範囲で広がる
    WkPositionX := WkMonitorInfo.rcMonitor.Left;
    WkPositionY := WkMonitorInfo.rcMonitor.Top;
  end;

  // 境界線の幅を取得
  case FTargetForm.BorderStyle of
    bsNone:
    begin
      // ウィンドウの境界線が無い
      WkBoundaryX := 0;
      WkBoundaryY := 0;
    end;
    bsDialog, bsSingle, bsToolWindow:
    begin
      // 立体効果付きのウィンドウの境界線の幅 +
      // 立体効果のないウィンドウの境界の幅 を取得
      WkBoundaryX := GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CXBORDER);
      WkBoundaryY := GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CYBORDER);
    end;
  else
    //bsSizeable, bsSizeToolWin
    // サイズ変更可能なウィンドウの周囲を囲む枠の幅 を取得
    WkBoundaryX := GetSystemMetrics(SM_CXFRAME);
    WkBoundaryY := GetSystemMetrics(SM_CYFRAME);
  end;

  // フォームのサイズをmsg.MinMaxInfo.ptMaxSizeに指定
  // 境界線の幅をフォームのサイズに反映させる
  if (TargetForm.BorderStyle = bsSizeable) or
    (TargetForm.BorderStyle = bsSingle) then
  begin
    // bsSizeable, bsSingle は
    // 最大化はモニタ有効面の範囲で広がる
    msg.MinMaxInfo.ptMaxSize.X :=
      WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left +
      (WkBoundaryX * 2);
    msg.MinMaxInfo.ptMaxSize.Y :=
      WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top +
      (WkBoundaryY * 2);
  end
  else begin
    // bsDialog, bsNone, bsSizeToolWin, bsToolWindow は
    // 最大化はモニタ全体の範囲で広がる
    msg.MinMaxInfo.ptMaxSize.X :=
      WkMonitorInfo.rcMonitor.Right - WkMonitorInfo.rcMonitor.Left +
      (WkBoundaryX * 2);
    msg.MinMaxInfo.ptMaxSize.Y :=
      WkMonitorInfo.rcMonitor.Bottom - WkMonitorInfo.rcMonitor.Top +
      (WkBoundaryY * 2);

    // Windows Vista(SP1)では、
    // bsSizeToolWin, bsToolWindowの時に、縦のサイズがおかしく表示される
    // 現象が起こる
    // Windows Vista(無印/SP2)は未確認、他のWindowsではこの現象は起きない
  end;

  // フォームの位置をmsg.MinMaxInfo.ptMaxPositionに指定
  // 境界線の幅をフォームの位置に反映させる
  // msg.MinMaxInfo.ptMaxPositionは
  // BorderStyleがbsSizeableおよびbsSingleの場合は
  // 各モニタの有効面の左上を原点(0,0)とした座標を指定する。
  // それ以外のBorderStyleでは
  // 各モニタの左上を原点(0,0)として座標値を返す
  if (TargetForm.BorderStyle = bsSizeable) or
    (TargetForm.BorderStyle = bsSingle) then
  begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcWork.Left - WkBoundaryX;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcWork.Top - WkBoundaryY;
  end
  else begin
    msg.MinMaxInfo.ptMaxPosition.X :=
      WkPositionX - WkMonitorInfo.rcMonitor.Left - WkBoundaryX;
    msg.MinMaxInfo.ptMaxPosition.Y :=
      WkPositionY - WkMonitorInfo.rcMonitor.Top - WkBoundaryY;
  end;

  {
  // デバッグ用
  ShowMessage(
    'msg.MinMaxInfo.ptMaxPosition.X:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxPosition.Y:' + IntToStr(msg.MinMaxInfo.ptMaxPosition.Y) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.X:' + IntToStr(msg.MinMaxInfo.ptMaxSize.X) + #13#10 +
    'msg.MinMaxInfo.ptMaxSize.Y:' + IntToStr(msg.MinMaxInfo.ptMaxSize.Y)
    );
  }
end;

{ TMonitorInfoParam }

constructor TMonitorInfoParam.Create(AOwner: TComponent);
begin
  inherited;
  if AOwner is TForm then
  begin
    FTargetForm := TForm(AOwner)
  end
  else begin
    FTargetForm := nil;
  end;
end;

function TMonitorInfoParam.DisplayMonitorInfo: TMonitorInfo;
begin
  // ウインドウが存在しない場合は例外を発生させる
  if FTargetForm = nil then
  begin
    raise ETargetFormIsNotFound.Create('TargetFormが指定されていません');
  end;
  if IsWindow(FTargetForm.Handle) = False then
  begin
    raise ETargetFormIsNotFound.Create('TargetFormで指定したフォームが存在されていません');
  end;

  GetMonitorInfoParam;
  result := FDisplayMonitorInfo;
end;


procedure TMonitorInfoParam.GetMonitorInfoParam;
begin
  // ディスプレイモニタに関する情報を取得
  // プライマリモニタの左上を原点として座標値を返す
  ZeroMemory(@FMonitorInfo, sizeof(FMonitorInfo));
  FMonitorInfo.cbSize := SizeOf(FMonitorInfo);
  if GetMonitorInfo(FTargetForm.Monitor.Handle, @FMonitorInfo) = False then
  begin
    // 念のためリトライ(いるのかな・・・?)
    Sleep(100);
    if GetMonitorInfo(FTargetForm.Monitor.Handle, @FMonitorInfo) = False then
    begin
      raise Exception.Create('APIのGetMonitorInfo関数でエラーが発生しました' + #13#10 +
        'プログラミングエラーです、開発者にお問い合わせください');
    end;
  end;

  // ディスプレイモニタに関する情報を取得
  // 各モニタの左上を原点として座標値を返す
  FDisplayMonitorInfo.cbSize := SizeOf(FDisplayMonitorInfo);
  FDisplayMonitorInfo.dwFlags := FMonitorInfo.dwFlags;
  FDisplayMonitorInfo.rcMonitor.Top := 0;
  FDisplayMonitorInfo.rcMonitor.Left := 0;
  FDisplayMonitorInfo.rcMonitor.Bottom :=
    FMonitorInfo.rcMonitor.Bottom - FMonitorInfo.rcMonitor.Top;
  FDisplayMonitorInfo.rcMonitor.Right :=
    FMonitorInfo.rcMonitor.Right - FMonitorInfo.rcMonitor.Left;
  FDisplayMonitorInfo.rcWork.Top :=
    FMonitorInfo.rcWork.Top - FMonitorInfo.rcMonitor.Top;
  FDisplayMonitorInfo.rcWork.Left :=
    FMonitorInfo.rcWork.Left - FMonitorInfo.rcMonitor.Left;
  FDisplayMonitorInfo.rcWork.Bottom :=
    FMonitorInfo.rcWork.Bottom - FMonitorInfo.rcMonitor.Top;
  FDisplayMonitorInfo.rcWork.Right :=
    FMonitorInfo.rcWork.Right - FMonitorInfo.rcMonitor.Left;
end;

function TMonitorInfoParam.MonitorCount: Integer;
begin
  result := Screen.MonitorCount;
end;

function TMonitorInfoParam.MonitorInfo: TMonitorInfo;
begin
  // ウインドウが存在しない場合は例外を発生させる
  if FTargetForm = nil then
  begin
    raise ETargetFormIsNotFound.Create('TargetFormが指定されていません');
  end;
  if IsWindow(FTargetForm.Handle) = False then
  begin
    raise ETargetFormIsNotFound.Create('TargetFormで指定したフォームが存在されていません');
  end;

  GetMonitorInfoParam;
  result := FMonitorInfo;
end;

function TMonitorInfoParam.MonitorNum: Integer;
begin
  result := FTargetForm.Monitor.MonitorNum;
end;

procedure TMonitorInfoParam.SetTargetForm(const Value: TForm);
begin
  FTargetForm := Value;
end;

end.