OpenDialog, SaveDialogをメインフォームの中央に表示する

下記のサイトのコードを一部変更したものです。
Delphi User's Forum
"コモンダイアログの表示位置を変更"
"RE:コモンダイアログの表示位置を変更"

変更箇所
1) 64bit Windows対策(Windows API 引数のキャスト LongInt を Int64 に変更)。
2) ダイアログがスクリーンをはみ出さないように制限。
3) Application.MainFormOnTaskbar := False; モードへの対策
    pWinPos の設定を2回実行するようにした(FOpenDialog1MoveFlag と FSaveDialog1MoveFlag を Byteに変更してカウンタに使用)。
      追記)3回実行しないとダメな場合があるようです。

メインフォームの名称 FormMain を適切にリネームしてご利用ください。

注1)下記のイベント設定が必要です。
OpenDialog1のイベント
  onClose: OpenDialog1Close
  onShow: OpenDialog1Show
SaveDialog1のイベント
  onClose: SaveDialog1Close
  onShow: SaveDialog1Show

注2)InitialDirを有効にするには、呼び出し前にFilenameを空にする必要があります。
  Opendialog1.Filename := '';
  Opendialog1.InitialDir := EditFolder.Text;
  if Opendialog1.Execute then


--- ソースコード ---

uses
  , MultiMon;

type
  TFormMain = class(TForm)

    procedure OpenDialog1Show(Sender: TObject);
    procedure OpenDialog1Close(Sender: TObject);
    procedure SaveDialog1Show(Sender: TObject);
    procedure SaveDialog1Close(Sender: TObject);
  private
    { Private 宣言 }

    FOpenDialog1hWnd: HWND;
    FNewOpenDialog1WndProc, FOldOpenDialog1WndProc: TFarProc;
    FOpenDialog1MoveFlag: Byte;
    FSaveDialog1hWnd: HWND;
    FNewSaveDialog1WndProc, FOldSaveDialog1WndProc: TFarProc;
    FSaveDialog1MoveFlag: Byte;
    procedure OpenDialog1WndProc(var Message: TMessage);
    procedure SaveDialog1WndProc(var Message: TMessage);
  public
    { Public 宣言 }
  end;

var
  FormMain: TFormMain;

implementation

{$R *.dfm}

  // フォームTargetを表示しているモニタの座標とサイズを返す(Uses に MultiMon が必要)
  {
    TMonitorInfoEx = Record
      cbSize : Cardinal;  // レコードのサイズ
      rcMonitor : TRect;  // モニタの矩形
      rcWork : TRect;     // ワークエリアの矩形
      dwFlags : Cardinal; // プライマリモニタなら<>0
      szDevice : array[0..31] of Char; // デバイス名(NULL終端)
    end;
  }
  Function GetMonitorRect(Target : TForm = Nil) : TRect;
  Var LMonitorInfoEx : TMonitorInfoEx;
  begin
    if Target=Nil then Target := Application.MainForm;
    FillChar(LMonitorInfoEx, SizeOf(TMonitorInfoEx), #0);
    LMonitorInfoEx.cbSize := SizeOf(LMonitorInfoEx);
    GetMonitorInfo(Target.Monitor.Handle, @LMonitorInfoEx);
    Result := LMonitorInfoEx.rcWork;     // 有効エリアを返す
  end;


  //------ for FormMain.OpenDialog1 ------

  // OpenDialog1 OnShowイベント
  procedure TFormMain.OpenDialog1Show(Sender: TObject);
  begin
    if ofOldStyleDialog in (Sender as TOpenDialog).Options then
      FOpenDialog1hWnd := (Sender as TOpenDialog).Handle
    else
      FOpenDialog1hWnd := GetParent((Sender as TOpenDialog).Handle);
    // 動的サブクラス化
    FOpenDialog1MoveFlag := 2; // 位置調整していない
    FNewOpenDialog1WndProc := MakeObjectInstance(OpenDialog1WndProc);
    FOldOpenDialog1WndProc := Pointer(GetWindowLong(FOpenDialog1hWnd, GWL_WNDPROC));
    SetWindowLong(FOpenDialog1hWnd, GWL_WNDPROC, Int64(FNewOpenDialog1WndProc));
  end;

  // OpenDialog1 OnCloseイベント
  procedure TFormMain.OpenDialog1Close(Sender: TObject);
  begin
    // 動的サブクラス化を解除する
    SetWindowLong(FOpenDialog1hWnd, GWL_WNDPROC, INT64(FOldOpenDialog1WndProc));
    FreeObjectInstance(FNewOpenDialog1WndProc);
    FOpenDialog1hWnd       := HWND(nil);
    FNewOpenDialog1WndProc := nil;
    FOldOpenDialog1WndProc := nil;
  end;

  // OpenDialog1の新しいウィンドウプロシージャ
  procedure TFormMain.OpenDialog1WndProc(var Message: TMessage);
  var
    pWinPos: PWindowPos;
    ScreenRect, mc, rc: TRect;
  begin
    if (Message.Msg = WM_WINDOWPOSCHANGING) and (FOpenDialog1MoveFlag > 0) then begin
      Dec(FOpenDialog1MoveFlag);
      pWinPos := PWindowPos(Message.LParam);
      pWinPos^.flags := pWinPos^.flags and not(SWP_NOMOVE);
      // 表示位置をスクリーン座標で設定する
      ScreenRect := GetMonitorRect(FormMain);
      GetWindowRect(FormMain.Handle, mc);
      GetWindowRect(FOpenDialog1hWnd, rc);
      pWinPos^.x := mc.left + (mc.Width  - rc.Width)  div 2;
      pWinPos^.y := mc.Top  + (mc.Height - rc.Height) div 2;
      // スクリーンからはみ出さないように制限する
      if pWinPos^.y<ScreenRect.Top then pWinPos^.y := ScreenRect.Top;
      if pWinPos^.y>(ScreenRect.Bottom-rc.Height) then pWinPos^.y := ScreenRect.Bottom-rc.Height;
      if pWinPos^.x<ScreenRect.Left then pWinPos^.x := ScreenRect.Left;
      if pWinPos^.x>(ScreenRect.Right-rc.Width) then pWinPos^.x := ScreenRect.Right-rc.Width;
    end;
    Message.Result := CallWindowProc(FOldOpenDialog1WndProc, FOpenDialog1hWnd, Message.Msg, Message.WParam, Message.LParam);
  end;

  //------ for FormMain.SaveDialog1 ------

  //SaveDialog1 OnShowイベント
  procedure TFormMain.SaveDialog1Show(Sender: TObject);
  begin
    if ofOldStyleDialog in (Sender as TSaveDialog).Options then
      FSaveDialog1hWnd := (Sender as TSaveDialog).Handle
    else
      FSaveDialog1hWnd := GetParent((Sender as TSaveDialog).Handle);
    // 動的サブクラス化
    FSaveDialog1MoveFlag := 2; // 位置調整していない
    FNewSaveDialog1WndProc := MakeObjectInstance(SaveDialog1WndProc);
    FOldSaveDialog1WndProc := Pointer(GetWindowLong(FSaveDialog1hWnd, GWL_WNDPROC));
    SetWindowLong(FSaveDialog1hWnd, GWL_WNDPROC, Int64(FNewSaveDialog1WndProc));
  end;

  // SaveDialog1 OnCloseイベント
  procedure TFormMain.SaveDialog1Close(Sender: TObject);
  begin
    //動的サブクラス化を解除する
    SetWindowLong(FSaveDialog1hWnd, GWL_WNDPROC, Int64(FOldSaveDialog1WndProc));
    FreeObjectInstance(FNewSaveDialog1WndProc);
    FSaveDialog1hWnd       := HWND(nil);
    FNewSaveDialog1WndProc := nil;
    FOldSaveDialog1WndProc := nil;
  end;

  // SaveDialog1の新しいウィンドウプロシージャ
  procedure TFormMain.SaveDialog1WndProc(var Message: TMessage);
  var
    pWinPos: PWindowPos;
    ScreenRect, mc, rc: TRect;
  begin
    if (Message.Msg = WM_WINDOWPOSCHANGING) and (FSaveDialog1MoveFlag > 0) then begin
      Dec(FSaveDialog1MoveFlag);
      pWinPos := PWindowPos(Message.LParam);
      pWinPos^.flags := pWinPos^.flags and not(SWP_NOMOVE);
      // 表示位置をスクリーン座標で設定する
      ScreenRect := GetMonitorRect(FormMain);
      GetWindowRect(FormMain.Handle, mc);
      GetWindowRect(FSaveDialog1hWnd, rc);
      pWinPos^.x := mc.left + (mc.Width  - rc.Width)  div 2;
      pWinPos^.y := mc.Top  + (mc.Height - rc.Height) div 2;
      // スクリーンからはみ出さないように制限する
      if pWinPos^.y<ScreenRect.Top then pWinPos^.y := ScreenRect.Top;
      if pWinPos^.y>(ScreenRect.Bottom-rc.Height) then pWinPos^.y := ScreenRect.Bottom-rc.Height;
      if pWinPos^.x<ScreenRect.Left then pWinPos^.x := ScreenRect.Left;
      if pWinPos^.x>(ScreenRect.Right-rc.Width) then pWinPos^.x := ScreenRect.Right-rc.Width;
    end;
    Message.Result := CallWindowProc(FOldSaveDialog1WndProc, FSaveDialog1hWnd, Message.Msg, Message.WParam, Message.LParam);
  end;

  //------ end ------

参考)実行時に基準にするフォームを変更したい場合。

1. 変数 Form_Main を追加する。
  Var
    Form_Main : TForm = Nil;

2. GetMonitorRect(FormMain) と GetWindowRect(FormMain.Handle, mc) の引数 FormMain を Form_Main に変更する。
  ScreenRect := GetMonitorRect(Form_Main);
  GetWindowRect(Form_Main.Handle, mc);

3. 基準にするフォームを指定してから呼び出す
  Form_Main := Form2;
  if OpenDialog1.Execute then // Form2の中央に表示する
  ...
  Form_Main := Form3;
  if OpenDialog1.Execute then // Form3の中央に表示する
  ...
  if OpenDialog1.Execute then // Form3の中央に表示する

4. 念のため GetMonitorRect 関数の先頭行を下記に変更すると安心かも。
  if Target=Nil then begin Target := Application.MainForm; Form_Main := Target; end;

Home