Recent

Author Topic: Center OpenDialog To Parent Form Windows XP  (Read 7723 times)

guitarmang

  • New Member
  • *
  • Posts: 31
Center OpenDialog To Parent Form Windows XP
« on: December 05, 2014, 10:08:25 pm »
Hi,
Just wanted to thank everyone that's answered my questions so far about dialogs. This is a great community.

I have one more question. I have some older Delphi code that works well to center dialogs to the parent form. I'm using Lazarus version 1.2.6, and I'm on Windows XP, and trying to center the explorer type opendialog(not the of oldstyle). I've used the Lazarus tool to convert the Delphi project to Lazarus. I'm stuck with trying to fix a couple of functions. Here's some code.
Code: [Select]
function GetTopWindow: HWND;
begin
  Result := GetLastActivePopup(Application.Handle);
  if (Result = Application.Handle) or not IsWindowVisible(Result) then
    Result := Screen.ActiveCustomForm.Handle;
end;

Code: [Select]
function TAwCommonDialog.Execute: Boolean;
begin
  try
    Application.NormalizeAllTopMosts;
    FHookProc := MakeHookInstance(HookProc);
    FWndHook := SetWindowsHookEx(WH_CALLWNDPROCRET, FHookProc, 0,
      GetCurrentThreadID);
    Result := FDialog.Execute;
  finally
    if FWndHook <> 0 then
      UnhookWindowsHookEx(FWndHook);
    if FHookProc <> nil then
      FreeHookInstance(FHookProc);
    Application.RestoreTopMosts;
  end;
end;

Would it be possible to get this code working in Lazarus?

Any help would be greatly appreciated.
Thanks, Wyatt

Here's the Delphi project that I converted. See Attached.



ChrisF

  • Hero Member
  • *****
  • Posts: 542
Re: Center OpenDialog To Parent Form Windows XP
« Reply #1 on: December 05, 2014, 11:26:40 pm »
A first possible correction...

Once Application and MainForm have been created:
Code: [Select]
Application.Handle  -->  Application.MainForm.Handle

And if it's not enough, for a windows program only (this solution is not recommended, and may eventually not work):
Code: [Select]
uses
   ..., Win32Int;

Application.Handle  -->  Win32WidgetSet.AppHandle


** Edit **  For the rest, are NormalizeAllTopMosts/RestoreTopMosts really necessary ?
« Last Edit: December 05, 2014, 11:43:36 pm by ChrisF »

guitarmang

  • New Member
  • *
  • Posts: 31
Re: Center OpenDialog To Parent Form Windows XP
« Reply #2 on: December 06, 2014, 12:29:30 am »
A first possible correction...

Once Application and MainForm have been created:
Code: [Select]
Application.Handle  -->  Application.MainForm.Handle

And if it's not enough, for a windows program only (this solution is not recommended, and may eventually not work):
Code: [Select]
uses
   ..., Win32Int;

Application.Handle  -->  Win32WidgetSet.AppHandle


** Edit **  For the rest, are NormalizeAllTopMosts/RestoreTopMosts really necessary ?

Thanks for the reply.

I tried what you recommended, and it compiles, but the dialog doesn't center to the form.
Thanks for trying.
Wyatt

guitarmang

  • New Member
  • *
  • Posts: 31
Re: Center OpenDialog To Parent Form Windows XP
« Reply #3 on: December 06, 2014, 12:43:22 am »
Here's another attached project for a test.
I commented out the NormalizeAllTopMosts and RestoreTopMosts, and replaced Application.Handle with Application.MainForm.Handle.

Thanks again for trying.




typo

  • Hero Member
  • *****
  • Posts: 3051
Re: Center OpenDialog To Parent Form Windows XP
« Reply #4 on: December 06, 2014, 02:10:04 am »
You could try to make a feature request on BugTracker.
« Last Edit: December 06, 2014, 03:38:05 pm by typo »

ChrisF

  • Hero Member
  • *****
  • Posts: 542
Re: Center OpenDialog To Parent Form Windows XP
« Reply #5 on: December 06, 2014, 05:34:43 pm »
You can't use this code directly for Lazarus/FPC

Your code is tightly bind to the way Delphi processes the Windows Common DialogBoxes; but this is different for Lazarus.

Just as a proof of concept, modifying and simplifying your code gives an acceptable result for very basic programs (i.e. for very simple forms and applications).

In TAwCommonDialog.HookProc, modify as indicated:
Code: [Select]
//      Parent := GetWindowLong(FDialog.Handle, GWL_HWNDPARENT);
//      if ((Data.hwnd = FDialog.Handle) and (Parent = Application.MainForm.Handle)) or
//        ((Data.hwnd = FDialog.Handle) and (FDialog is TFindDialog)) or
//        (Data.hwnd = Parent) then
      Parent := GetWindowLong(Data.hWnd, GWL_HWNDPARENT);
      if (Parent <> 0) and (Parent = FCenterWnd) then

This is only for demonstration purposes and certainly not a definitive solution (several controls have been removed, which makes this code not a general one).

A very simple approach would be to modify the LCL code to comply to your needs (or eventually to make and use your own Dialogs controls by overwriting the current ones).

Apparently, currently DialogBoxes are always centered relatively to the screen with Lazarus, not to the owner form: see "Reposition" function in "win32wsdialogs.pp"


** Edit **   BTW, you don't need to add the "win32int" unit in your "uses" clause if you're not using any windows widegset objects or classes (which is the case or your second sample code).
« Last Edit: December 06, 2014, 07:43:19 pm by ChrisF »

guitarmang

  • New Member
  • *
  • Posts: 31
Re: Center OpenDialog To Parent Form Windows XP
« Reply #6 on: December 07, 2014, 01:40:40 am »
You can't use this code directly for Lazarus/FPC

Your code is tightly bind to the way Delphi processes the Windows Common DialogBoxes; but this is different for Lazarus.

Just as a proof of concept, modifying and simplifying your code gives an acceptable result for very basic programs (i.e. for very simple forms and applications).

In TAwCommonDialog.HookProc, modify as indicated:
Code: [Select]
//      Parent := GetWindowLong(FDialog.Handle, GWL_HWNDPARENT);
//      if ((Data.hwnd = FDialog.Handle) and (Parent = Application.MainForm.Handle)) or
//        ((Data.hwnd = FDialog.Handle) and (FDialog is TFindDialog)) or
//        (Data.hwnd = Parent) then
      Parent := GetWindowLong(Data.hWnd, GWL_HWNDPARENT);
      if (Parent <> 0) and (Parent = FCenterWnd) then

This is only for demonstration purposes and certainly not a definitive solution (several controls have been removed, which makes this code not a general one).

A very simple approach would be to modify the LCL code to comply to your needs (or eventually to make and use your own Dialogs controls by overwriting the current ones).

Apparently, currently DialogBoxes are always centered relatively to the screen with Lazarus, not to the owner form: see "Reposition" function in "win32wsdialogs.pp"


** Edit **   BTW, you don't need to add the "win32int" unit in your "uses" clause if you're not using any windows widegset objects or classes (which is the case or your second sample code).

Chris,
thanks.

For the purpose of just the opendialog it should be ok, right?
It is a Windows form application I'm using it for.
That's all I'll be using it for.

Edit: I'm using the opendialog to select a folder (Windows XP only or Windows 7 with classic theme, themes turned off).
 For Windows Vista and later, I'll be using the new vista style dialog, that automatically centers to the parent form.
Here's a test project (for XP only, for now, or windows 7 users could test it with themes turned off, and classic mode). See attached.

It's working great!
Many Thanks, Wyatt
« Last Edit: December 07, 2014, 01:54:34 am by guitarmang »