views:

103

answers:

1

I have a Delphi 2006 app with a CHM help file. It all works OK except that I cannot get any help to connect to the "Help" button on the TOpenDialog and TSaveDialog.

A simple program demonstrating this is shown below. Clicking button 2 opens the help file and displays the correct page. Clicking button 1 opens the dialog, but clicking on the help button in the dialog has no effect.

unit Unit22;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,
  HTMLHelpViewer ;

type
  TForm22 = class(TForm)
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form22: TForm22;

implementation

{$R *.dfm}

procedure TForm22.Button1Click(Sender: TObject);
begin
OpenDialog1.HelpContext := 10410 ;
OpenDialog1.Execute ;
end;

procedure TForm22.Button2Click(Sender: TObject);
begin
Application.HelpContext  (10410) ;
end;

procedure TForm22.FormCreate(Sender: TObject);
begin
Application.HelpFile := 'c:\help.chm' ;
end;

end.
+10  A: 

With default settings TOpenDialog's help message handling doesn't work (you should submit it to Quality Central).

The specific reason is because Windows sends the help message to the dialog's parent, rather than the dialog itself, so unless your form is set up to process it it just gets ignored.

The fix is to set Application.ModalPopupMode to pmAuto instead of the default of pmNone. You can do that once during your normal startup code, or just before you show the dialog. When that's set Delphi creates an intermediate window (Dialogs.pas::TRedirectorWindow) which handles the message correctly.

If for some reason you can't change the ModalPopupMode then, as I said, you need to handle the message on your form:

TForm22 = class(TForm)
...
  procedure WndProc(var Message: TMessage); override;
end;

initialization

var
  HelpMsg: Cardinal;

procedure TForm22.WndProc(var Message: TMessage);
begin
  inherited;
  if (Message.Msg = HelpMsg) and (OpenDialog1.Handle <> 0) then
    Application.HelpContext(OpenDialog1.HelpContext);
end;

initialization
  HelpMsg := RegisterWindowMessage(HelpMsgString);
end.
Craig Peterson
Thanks for that. The simpler fix worked (Application.ModalPopupMode := pmAuto, called in an overriden CreateWnd() method) - I don't know what other possible side effects that may have in my app. Presumably I don't need to do anything on exit, as the TApplication instance will be gone anyway.
@user89691: It will have the side effect that every form opened will be "parented" to the form from which it was opened. And that means that it will be closed when the "parent" form is closed. If you need more control, use pmExplicit as the PopupMode and set each forms PopupParent..., well, explicitely... "Parentend" (between parenthesis) because the form's actual parent is _not_ affected, only its PopupParent.
Marjan Venema
OK, I'm still a bit confused here. The CreateWnd override is working, so is it safe to leave it that way? Alternatively My TOpenDialog and TSaveDialog's are auto-created (i.e. the components have been dropped onto the form at design-time). So could I: 1) Just before the call to Execute, save the current value of Application.ModalPopup. 2) then, set Application.ModalPopup = pmAuto. 3) after the call to Execute, restore Application.ModalPopup to it's saved value. This seems to work, and has the advantage that I'm less likely to break it elsewhere as everything has remained as it was.
It should be safe to leave it that way. Using `pmAuto` is closer to how other, non-Delphi applications behave.
Craig Peterson