#author("2022-10-25T12:12:26+09:00","default:ahyahya2","ahyahya2")
[[戻る>DoldoWorkz#delphi]]

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

#hr
#contents
#hr

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

**GetMonitorInfoでモニタに関する情報を取得する [#q67f6944]
-[[MSDN Japan-GetMonitorInfo:http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpgdi/html/_win32_GetMonitorInfo.asp]]~
GetMonitorInfoの情報があります。~

-[[MONITORINFO構造体-WinAPI Database for VB Programmer:http://www.winapi-database.com/Struct/MONITORINFO.html]]~
MONITORINFO 構造体の情報があります。~

モニタの範囲を知るためにはWindows APIの「GetMonitorInfo」を使う。~
このAPIはマルチモニタ対応のAPIで、ディスプレイモニタのハンドルを渡してあげる事によって、そのディスプレイモニタに関する情報を取得する事が出来ます。~
~
情報はMONITORINFO 構造体によって返され、以下のような情報が帰ってきます。~
~
-&color(red){''モニタ全体の範囲''};~
|MonitorInfo.rcMonitor.Bottom|範囲の下側Y座標|
|MonitorInfo.rcMonitor.Top|範囲の上側Y座標|
|MonitorInfo.rcMonitor.Left|範囲の左側X座標|
|MonitorInfo.rcMonitor.Right|範囲の右側X座標|
~
-&color(Green){''モニタ有効面の範囲''};~
|MonitorInfo.rcWork.Bottom|範囲の下側Y座標|
|MonitorInfo.rcWork.Top|範囲の上側Y座標|
|MonitorInfo.rcWork.Left|範囲の左側X座標|
|MonitorInfo.rcWork.Right|範囲の右側X座標|
~
以下の例では赤い四角がモニタの範囲、緑色の範囲がモニタの有効面の範囲になってます。~
タスクバーの分が有効面から除外されていますが、これは~
ウインドウを最大化したときに使える範囲=有効面だからです。~
※「タスクバーを自動的に隠す」をしていない例です~
他のソフトで、デスクトップを占有するタイプのアプリケーションがある場合はその分も有効面から除外されます~
#ref(Monitor1_Bottom.jpg,around)
#ref(Monitor1_Top.jpg)
#img(,clear)
#clear
~
#ref(Monitor1_Left.jpg,around)
#ref(Monitor1_Right.jpg)
#img(,clear)
#clear
~
取得出来る値は、&color(red){''プライマリモニタの左上を原点''};として数値が決まります。~
2台目以降のモニタの位置はある程度好きなように置ける様です。~
#ref(Monitor2.jpg)
※ぜんぜん関係ない話ですが、上の図はExcelで作っている物を、セル範囲のコピーってそのままペイント等に画像として貼り付けしてます。~
知らなかったです…なんとなく「出来るかな?」と思ってやって出来てびっくり。~
~
Delphiのコードだとこんな感じです
 var
   FMonitorInfo: TMonitorInfo;
 begin
   ZeroMemory(@FMonitorInfo, sizeof(FMonitorInfo));
   FMonitorInfo.cbSize := SizeOf(FMonitorInfo);
   GetMonitorInfo(FTargetForm.Monitor.Handle, @FMonitorInfo);
**WMGetMinMaxInfoメッセージ [#dc8f5264]
最大化の時に、フォームの大きさと位置の制限をするには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」は&color(red){''各種モニタの左上を原点''};として数値が決まります。~
#ref(Monitor3.jpg)

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

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

※2009/5/7の時点では「2000・XP」と「Vista・7」では原点位置が変わる様に書いていたのですが、いつの間にか「2000・XP」と同じ動作になる様に「Vista・7」が修正された様です。~
**作ってみたコード [#o031755d]
マルチディスプレイ対応です。~
この内容はDelphi-ML「[Delphi:90115] ウインドウを最大化したまま最大化サイズを調節する」で付いたレスを参考にしています。~
教えてくださる皆様、感謝感謝です。~

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

ダウンロード
#ref(MultiMonitorParam100917.zip)
[[&ref(http://i.creativecommons.org/l/by/2.1/jp/80x15.png);>http://creativecommons.org/licenses/by/2.1/jp/]]
この作品は[[クリエイティブ・コモンズ・ライセンス>http://creativecommons.org/licenses/by/2.1/jp/]]の下でライセンスされています。
 {*****************************************************************************}
 {                                                                             }
 {       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.