home *** CD-ROM | disk | FTP | other *** search
/ Delphi Anthology / aDELPHI.iso / Runimage / Delphi50 / Source / Vcl / dialogs.pas < prev    next >
Pascal/Delphi Source File  |  1999-08-11  |  56KB  |  1,853 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {                                                       }
  6. {       Copyright (c) 1995,99 Inprise Corporation       }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit Dialogs;
  11.  
  12. {$R-,T-,H+,X+}
  13.  
  14. interface
  15.  
  16. uses Windows, Messages, SysUtils, CommDlg, Classes, Graphics, Controls,
  17.   Forms, StdCtrls;
  18.  
  19. const
  20.  
  21. { Maximum number of custom colors in color dialog }
  22.  
  23.   MaxCustomColors = 16;
  24.  
  25. type
  26.  
  27. { TCommonDialog }
  28.  
  29.   TCommonDialog = class(TComponent)
  30.   private
  31.     FCtl3D: Boolean;
  32.     FDefWndProc: Pointer;
  33.     FHelpContext: THelpContext;
  34.     FHandle: HWnd;
  35.     FObjectInstance: Pointer;
  36.     FTemplate: PChar;
  37.     FOnClose: TNotifyEvent;
  38.     FOnShow: TNotifyEvent;
  39.     procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY;
  40.     procedure WMInitDialog(var Message: TWMInitDialog); message WM_INITDIALOG;
  41.     procedure WMNCDestroy(var Message: TWMNCDestroy); message WM_NCDESTROY;
  42.     procedure MainWndProc(var Message: TMessage);
  43.   protected
  44.     procedure DoClose; dynamic;
  45.     procedure DoShow; dynamic;
  46.     procedure WndProc(var Message: TMessage); virtual;
  47.     function MessageHook(var Msg: TMessage): Boolean; virtual;
  48.     function TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool; virtual;
  49.     function Execute: Boolean; virtual; abstract;
  50.     property Template: PChar read FTemplate write FTemplate;
  51.   public
  52.     constructor Create(AOwner: TComponent); override;
  53.     destructor Destroy; override;
  54.     procedure DefaultHandler(var Message); override;
  55.     property Handle: HWnd read FHandle;
  56.   published
  57.     property Ctl3D: Boolean read FCtl3D write FCtl3D default True;
  58.     property HelpContext: THelpContext read FHelpContext write FHelpContext default 0;
  59.     property OnClose: TNotifyEvent read FOnClose write FOnClose;
  60.     property OnShow: TNotifyEvent read FOnShow write FOnShow;
  61.   end;
  62.  
  63. { TOpenDialog }
  64.  
  65.   TOpenOption = (ofReadOnly, ofOverwritePrompt, ofHideReadOnly,
  66.     ofNoChangeDir, ofShowHelp, ofNoValidate, ofAllowMultiSelect,
  67.     ofExtensionDifferent, ofPathMustExist, ofFileMustExist, ofCreatePrompt,
  68.     ofShareAware, ofNoReadOnlyReturn, ofNoTestFileCreate, ofNoNetworkButton,
  69.     ofNoLongNames, ofOldStyleDialog, ofNoDereferenceLinks, ofEnableIncludeNotify,
  70.     ofEnableSizing);
  71.   TOpenOptions = set of TOpenOption;
  72.  
  73.   TFileEditStyle = (fsEdit, fsComboBox);
  74.   TOFNotifyEx = type CommDlg.TOFNotifyEx;
  75.   {$NODEFINE TOFNotifyEx}
  76.   TIncludeItemEvent = procedure (const OFN: TOFNotifyEx; var Include: Boolean) of object;
  77.  
  78.   TOpenDialog = class(TCommonDialog)
  79.   private
  80.     FHistoryList: TStrings;
  81.     FOptions: TOpenOptions;
  82.     FFilter: string;
  83.     FFilterIndex: Integer;
  84.     FCurrentFilterIndex: Integer;
  85.     FInitialDir: string;
  86.     FTitle: string;
  87.     FDefaultExt: string;
  88.     FFileName: TFileName;
  89.     FFiles: TStrings;
  90.     FFileEditStyle: TFileEditStyle;
  91.     FOnSelectionChange: TNotifyEvent;
  92.     FOnFolderChange: TNotifyEvent;
  93.     FOnTypeChange: TNotifyEvent;
  94.     FOnCanClose: TCloseQueryEvent;
  95.     FOnIncludeItem: TIncludeItemEvent;
  96.     function GetFileName: TFileName;
  97.     function GetFilterIndex: Integer;
  98.     procedure ReadFileEditStyle(Reader: TReader);
  99.     procedure SetHistoryList(Value: TStrings);
  100.     procedure SetInitialDir(const Value: string);
  101.   protected
  102.     function CanClose(var OpenFileName: TOpenFileName): Boolean;
  103.     function DoCanClose: Boolean; dynamic;
  104.     function DoExecute(Func: Pointer): Bool;
  105.     procedure DoSelectionChange; dynamic;
  106.     procedure DoFolderChange; dynamic;
  107.     procedure DoTypeChange; dynamic;
  108.     procedure DoIncludeItem(const OFN: TOFNotifyEx; var Include: Boolean); dynamic;
  109.     procedure DefineProperties(Filer: TFiler); override;
  110.     procedure GetFileNames(var OpenFileName: TOpenFileName);
  111.     function GetStaticRect: TRect; virtual;
  112.     procedure WndProc(var Message: TMessage); override;
  113.   public
  114.     constructor Create(AOwner: TComponent); override;
  115.     destructor Destroy; override;
  116.     function Execute: Boolean; override;
  117.     property FileEditStyle: TFileEditStyle read FFileEditStyle write FFileEditStyle;
  118.     property Files: TStrings read FFiles;
  119.     property HistoryList: TStrings read FHistoryList write SetHistoryList;
  120.   published
  121.     property DefaultExt: string read FDefaultExt write FDefaultExt;
  122.     property FileName: TFileName read GetFileName write FFileName;
  123.     property Filter: string read FFilter write FFilter;
  124.     property FilterIndex: Integer read GetFilterIndex write FFilterIndex default 1;
  125.     property InitialDir: string read FInitialDir write SetInitialDir;
  126.     property Options: TOpenOptions read FOptions write FOptions default [ofHideReadOnly, ofEnableSizing];
  127.     property Title: string read FTitle write FTitle;
  128.     property OnCanClose: TCloseQueryEvent read FOnCanClose write FOnCanClose;
  129.     property OnFolderChange: TNotifyEvent read FOnFolderChange write FOnFolderChange;
  130.     property OnSelectionChange: TNotifyEvent read FOnSelectionChange write FOnSelectionChange;
  131.     property OnTypeChange: TNotifyEvent read FOnTypeChange write FOnTypeChange;
  132.     property OnIncludeItem: TIncludeItemEvent read FOnIncludeItem write FOnIncludeItem;
  133.   end;
  134.  
  135. { TSaveDialog }
  136.  
  137.   TSaveDialog = class(TOpenDialog)
  138.     function Execute: Boolean; override;
  139.   end;
  140.  
  141. { TColorDialog }
  142.  
  143.   TColorDialogOption = (cdFullOpen, cdPreventFullOpen, cdShowHelp,
  144.     cdSolidColor, cdAnyColor);
  145.   TColorDialogOptions = set of TColorDialogOption;
  146.  
  147.   TCustomColors = array[0..MaxCustomColors - 1] of Longint;
  148.  
  149.   TColorDialog = class(TCommonDialog)
  150.   private
  151.     FColor: TColor;
  152.     FOptions: TColorDialogOptions;
  153.     FCustomColors: TStrings;
  154.     procedure SetCustomColors(Value: TStrings);
  155.   public
  156.     constructor Create(AOwner: TComponent); override;
  157.     destructor Destroy; override;
  158.     function Execute: Boolean; override;
  159.   published
  160.     property Color: TColor read FColor write FColor default clBlack;
  161.     property Ctl3D default False;
  162.     property CustomColors: TStrings read FCustomColors write SetCustomColors;
  163.     property Options: TColorDialogOptions read FOptions write FOptions default [];
  164.   end;
  165.  
  166. { TFontDialog }
  167.  
  168.   TFontDialogOption = (fdAnsiOnly, fdTrueTypeOnly, fdEffects,
  169.     fdFixedPitchOnly, fdForceFontExist, fdNoFaceSel, fdNoOEMFonts,
  170.     fdNoSimulations, fdNoSizeSel, fdNoStyleSel,  fdNoVectorFonts,
  171.     fdShowHelp, fdWysiwyg, fdLimitSize, fdScalableOnly, fdApplyButton);
  172.   TFontDialogOptions = set of TFontDialogOption;
  173.  
  174.   TFontDialogDevice = (fdScreen, fdPrinter, fdBoth);
  175.  
  176.   TFDApplyEvent = procedure(Sender: TObject; Wnd: HWND) of object;
  177.  
  178.   TFontDialog = class(TCommonDialog)
  179.   private
  180.     FFont: TFont;
  181.     FDevice: TFontDialogDevice;
  182.     FOptions: TFontDialogOptions;
  183.     FOnApply: TFDApplyEvent;
  184.     FMinFontSize: Integer;
  185.     FMaxFontSize: Integer;
  186.     FFontCharsetModified: Boolean;
  187.     FFontColorModified: Boolean;
  188.     procedure DoApply(Wnd: HWND);
  189.     procedure SetFont(Value: TFont);
  190.     procedure UpdateFromLogFont(const LogFont: TLogFont);
  191.   protected
  192.     procedure Apply(Wnd: HWND); dynamic;
  193.     procedure WndProc(var Message: TMessage); override;
  194.   public
  195.     constructor Create(AOwner: TComponent); override;
  196.     destructor Destroy; override;
  197.     function Execute: Boolean; override;
  198.   published
  199.     property Font: TFont read FFont write SetFont;
  200.     property Device: TFontDialogDevice read FDevice write FDevice default fdScreen;
  201.     property MinFontSize: Integer read FMinFontSize write FMinFontSize;
  202.     property MaxFontSize: Integer read FMaxFontSize write FMaxFontSize;
  203.     property Options: TFontDialogOptions read FOptions write FOptions default [fdEffects];
  204.     property OnApply: TFDApplyEvent read FOnApply write FOnApply;
  205.   end;
  206.  
  207. { TPrinterSetupDialog }
  208.  
  209.   TPrinterSetupDialog = class(TCommonDialog)
  210.   public
  211.     function Execute: Boolean; override;
  212.   end;
  213.  
  214. { TPrintDialog }
  215.  
  216.   TPrintRange = (prAllPages, prSelection, prPageNums);
  217.   TPrintDialogOption = (poPrintToFile, poPageNums, poSelection, poWarning,
  218.     poHelp, poDisablePrintToFile);
  219.   TPrintDialogOptions = set of TPrintDialogOption;
  220.  
  221.   TPrintDialog = class(TCommonDialog)
  222.   private
  223.     FFromPage: Integer;
  224.     FToPage: Integer;
  225.     FCollate: Boolean;
  226.     FOptions: TPrintDialogOptions;
  227.     FPrintToFile: Boolean;
  228.     FPrintRange: TPrintRange;
  229.     FMinPage: Integer;
  230.     FMaxPage: Integer;
  231.     FCopies: Integer;
  232.     procedure SetNumCopies(Value: Integer);
  233.   public
  234.     function Execute: Boolean; override;
  235.   published
  236.     property Collate: Boolean read FCollate write FCollate default False;
  237.     property Copies: Integer read FCopies write SetNumCopies default 0;
  238.     property FromPage: Integer read FFromPage write FFromPage default 0;
  239.     property MinPage: Integer read FMinPage write FMinPage default 0;
  240.     property MaxPage: Integer read FMaxPage write FMaxPage default 0;
  241.     property Options: TPrintDialogOptions read FOptions write FOptions default [];
  242.     property PrintToFile: Boolean read FPrintToFile write FPrintToFile default False;
  243.     property PrintRange: TPrintRange read FPrintRange write FPrintRange default prAllPages;
  244.     property ToPage: Integer read FToPage write FToPage default 0;
  245.   end;
  246.  
  247. { TFindDialog }
  248.  
  249.   TFindOption = (frDown, frFindNext, frHideMatchCase, frHideWholeWord,
  250.     frHideUpDown, frMatchCase, frDisableMatchCase, frDisableUpDown,
  251.     frDisableWholeWord, frReplace, frReplaceAll, frWholeWord, frShowHelp);
  252.   TFindOptions = set of TFindOption;
  253.  
  254.   TFindReplaceFunc = function(var FindReplace: TFindReplace): HWnd stdcall;
  255.  
  256.   TFindDialog = class(TCommonDialog)
  257.   private
  258.     FOptions: TFindOptions;
  259.     FPosition: TPoint;
  260.     FFindReplaceFunc: TFindReplaceFunc;
  261.     FRedirector: TWinControl;
  262.     FOnFind: TNotifyEvent;
  263.     FOnReplace: TNotifyEvent;
  264.     FFindHandle: HWnd;
  265.     FFindReplace: TFindReplace;
  266.     FFindText: array[0..255] of Char;
  267.     FReplaceText: array[0..255] of Char;
  268.     function GetFindText: string;
  269.     function GetLeft: Integer;
  270.     function GetPosition: TPoint;
  271.     function GetReplaceText: string;
  272.     function GetTop: Integer;
  273.     procedure SetFindText(const Value: string);
  274.     procedure SetLeft(Value: Integer);
  275.     procedure SetPosition(const Value: TPoint);
  276.     procedure SetReplaceText(const Value: string);
  277.     procedure SetTop(Value: Integer);
  278.     property ReplaceText: string read GetReplaceText write SetReplaceText;
  279.     property OnReplace: TNotifyEvent read FOnReplace write FOnReplace;
  280.   protected
  281.     function MessageHook(var Msg: TMessage): Boolean; override;
  282.     procedure Find; dynamic;
  283.     procedure Replace; dynamic;
  284.   public
  285.     constructor Create(AOwner: TComponent); override;
  286.     destructor Destroy; override;
  287.     procedure CloseDialog;
  288.     function Execute: Boolean; override;
  289.     property Left: Integer read GetLeft write SetLeft;
  290.     property Position: TPoint read GetPosition write SetPosition;
  291.     property Top: Integer read GetTop write SetTop;
  292.   published
  293.     property FindText: string read GetFindText write SetFindText;
  294.     property Options: TFindOptions read FOptions write FOptions default [frDown];
  295.     property OnFind: TNotifyEvent read FOnFind write FOnFind;
  296.   end;
  297.  
  298. { TReplaceDialog }
  299.  
  300.   TReplaceDialog = class(TFindDialog)
  301.   public
  302.     constructor Create(AOwner: TComponent); override;
  303.   published
  304.     property ReplaceText;
  305.     property OnReplace;
  306.   end;
  307.  
  308. { Message dialog }
  309.  
  310. type
  311.   TMsgDlgType = (mtWarning, mtError, mtInformation, mtConfirmation, mtCustom);
  312.   TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore,
  313.     mbAll, mbNoToAll, mbYesToAll, mbHelp);
  314.   TMsgDlgButtons = set of TMsgDlgBtn;
  315.  
  316. const
  317.   mbYesNoCancel = [mbYes, mbNo, mbCancel];
  318.   mbOKCancel = [mbOK, mbCancel];
  319.   mbAbortRetryIgnore = [mbAbort, mbRetry, mbIgnore];
  320.  
  321. function CreateMessageDialog(const Msg: string; DlgType: TMsgDlgType;
  322.   Buttons: TMsgDlgButtons): TForm;
  323.  
  324. function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
  325.   Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
  326. function MessageDlgPos(const Msg: string; DlgType: TMsgDlgType;
  327.   Buttons: TMsgDlgButtons; HelpCtx: Longint; X, Y: Integer): Integer;
  328. function MessageDlgPosHelp(const Msg: string; DlgType: TMsgDlgType;
  329.   Buttons: TMsgDlgButtons; HelpCtx: Longint; X, Y: Integer;
  330.   const HelpFileName: string): Integer;
  331.  
  332. procedure ShowMessage(const Msg: string);
  333. procedure ShowMessageFmt(const Msg: string; Params: array of const);
  334. procedure ShowMessagePos(const Msg: string; X, Y: Integer);
  335.  
  336. { Input dialog }
  337.  
  338. function InputBox(const ACaption, APrompt, ADefault: string): string;
  339. function InputQuery(const ACaption, APrompt: string;
  340.   var Value: string): Boolean;
  341.  
  342. { Win98 and Win2k will default to the "My Documents" folder if the InitialDir
  343.   property is empty and no files of the filtered type are contained in the
  344.   current directory. Set this flag to True to force TOpenDialog and descendents
  345.   to always open in the current directory when InitialDir is empty. (Same
  346.   behavior as setting InitialDir to '.') }
  347. var
  348.   ForceCurrentDirectory: Boolean = False;
  349.  
  350. implementation
  351.  
  352. uses ExtCtrls, Consts, Printers, Dlgs;
  353.  
  354. { Private globals }
  355.  
  356. var
  357.   CreationControl: TCommonDialog = nil;
  358.   HelpMsg: Cardinal;
  359.   FindMsg: Cardinal;
  360.   WndProcPtrAtom: TAtom = 0;
  361.  
  362. { Center the given window on the screen }
  363.  
  364. procedure CenterWindow(Wnd: HWnd);
  365. var
  366.   Rect: TRect;
  367.   Monitor: TMonitor;
  368. begin
  369.   GetWindowRect(Wnd, Rect);
  370.   if Application.MainForm <> nil then
  371.     Monitor := Application.MainForm.Monitor
  372.   else
  373.     Monitor := Screen.Monitors[0];
  374.   SetWindowPos(Wnd, 0,
  375.     Monitor.Left + ((Monitor.Width - Rect.Right + Rect.Left) div 2),
  376.     Monitor.Top + ((Monitor.Height - Rect.Bottom + Rect.Top) div 3),
  377.     0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);
  378. end;
  379.  
  380. { Generic dialog hook. Centers the dialog on the screen in response to
  381.   the WM_INITDIALOG message }
  382.  
  383. function DialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  384. begin
  385.   Result := 0;
  386.   if Msg = WM_INITDIALOG then
  387.   begin
  388.     CenterWindow(Wnd);
  389.     CreationControl.FHandle := Wnd;
  390.     CreationControl.FDefWndProc := Pointer(SetWindowLong(Wnd, GWL_WNDPROC,
  391.       Longint(CreationControl.FObjectInstance)));
  392.     CallWindowProc(CreationControl.FObjectInstance, Wnd, Msg, WParam, LParam);
  393.     CreationControl := nil;
  394.   end;
  395. end;
  396.  
  397. { TCommonDialog }
  398.  
  399. constructor TCommonDialog.Create(AOwner: TComponent);
  400. begin
  401.   inherited Create(AOwner);
  402.   FCtl3D := True;
  403.   FObjectInstance := MakeObjectInstance(MainWndProc);
  404. end;
  405.  
  406. destructor TCommonDialog.Destroy;
  407. begin
  408.   if FObjectInstance <> nil then FreeObjectInstance(FObjectInstance);
  409.   inherited Destroy;
  410. end;
  411.  
  412. function TCommonDialog.MessageHook(var Msg: TMessage): Boolean;
  413. begin
  414.   Result := False;
  415.   if (Msg.Msg = HelpMsg) and (FHelpContext <> 0) then
  416.   begin
  417.     Application.HelpContext(FHelpContext);
  418.     Result := True;
  419.   end;
  420. end;
  421.  
  422. procedure TCommonDialog.DefaultHandler(var Message);
  423. begin
  424.   if FHandle <> 0 then
  425.     with TMessage(Message) do
  426.       Result := CallWindowProc(FDefWndProc, FHandle, Msg, WParam, LParam)
  427.   else inherited DefaultHandler(Message);
  428. end;
  429.  
  430. procedure TCommonDialog.MainWndProc(var Message: TMessage);
  431. begin
  432.   try
  433.     WndProc(Message);
  434.   except
  435.     Application.HandleException(Self);
  436.   end;
  437. end;
  438.  
  439. procedure TCommonDialog.WndProc(var Message: TMessage);
  440. begin
  441.   Dispatch(Message);
  442. end;
  443.  
  444. procedure TCommonDialog.WMDestroy(var Message: TWMDestroy);
  445. begin
  446.   inherited;
  447.   DoClose;
  448. end;
  449.  
  450. procedure TCommonDialog.WMInitDialog(var Message: TWMInitDialog);
  451. begin
  452.   { Called only by non-explorer style dialogs }
  453.   DoShow;
  454.   { Prevent any further processing }
  455.   Message.Result := 0;
  456. end;
  457.  
  458. procedure TCommonDialog.WMNCDestroy(var Message: TWMNCDestroy);
  459. begin
  460.   inherited;
  461.   FHandle := 0;
  462. end;
  463.  
  464. function TCommonDialog.TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
  465. type
  466.   TDialogFunc = function(var DialogData): Bool stdcall;
  467. var
  468.   ActiveWindow: HWnd;
  469.   WindowList: Pointer;
  470.   FPUControlWord: Word;
  471. begin
  472.   ActiveWindow := GetActiveWindow;
  473.   WindowList := DisableTaskWindows(0);
  474.   try
  475.     Application.HookMainWindow(MessageHook);
  476.     asm
  477.       // Avoid FPU control word change in NETRAP.dll, NETAPI32.dll, etc
  478.       FNSTCW  FPUControlWord
  479.     end;
  480.     try
  481.       CreationControl := Self;
  482.       Result := TDialogFunc(DialogFunc)(DialogData);
  483.     finally
  484.       asm
  485.         FNCLEX
  486.         FLDCW FPUControlWord
  487.       end;
  488.       Application.UnhookMainWindow(MessageHook);
  489.     end;
  490.   finally
  491.     EnableTaskWindows(WindowList);
  492.     SetActiveWindow(ActiveWindow);
  493.   end;
  494. end;
  495.  
  496. procedure TCommonDialog.DoClose;
  497. begin
  498.   if Assigned(FOnClose) then FOnClose(Self);
  499. end;
  500.  
  501. procedure TCommonDialog.DoShow;
  502. begin
  503.   if Assigned(FOnShow) then FOnShow(Self);
  504. end;
  505.  
  506. { Open and Save dialog routines }
  507.  
  508. function ExplorerHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  509. begin
  510.   Result := 0;
  511.   if Msg = WM_INITDIALOG then
  512.   begin
  513.     CreationControl.FHandle := Wnd;
  514.     CreationControl.FDefWndProc := Pointer(SetWindowLong(Wnd, GWL_WNDPROC,
  515.       Longint(CreationControl.FObjectInstance)));
  516.     CallWindowProc(CreationControl.FObjectInstance, Wnd, Msg, WParam, LParam);
  517.     CreationControl := nil;
  518.   end
  519.   else if (Msg = WM_NOTIFY) and (POFNotify(LParam)^.hdr.code = CDN_INITDONE) then
  520.     CenterWindow(GetWindowLong(Wnd, GWL_HWNDPARENT));
  521. end;
  522.  
  523. { TOpenDialog }
  524.  
  525. constructor TOpenDialog.Create(AOwner: TComponent);
  526. begin
  527.   inherited Create(AOwner);
  528.   FHistoryList := TStringList.Create;
  529.   FOptions := [ofHideReadOnly, ofEnableSizing];
  530.   FFiles := TStringList.Create;
  531.   FFilterIndex := 1;
  532.   FFileEditStyle := fsEdit;
  533. end;
  534.  
  535. destructor TOpenDialog.Destroy;
  536. begin
  537.   FFiles.Free;
  538.   FHistoryList.Free;
  539.   inherited Destroy;
  540. end;
  541.  
  542. function TOpenDialog.CanClose(var OpenFileName: TOpenFileName): Boolean;
  543. begin
  544.   GetFileNames(OpenFileName);
  545.   Result := DoCanClose;
  546.   FFiles.Clear;
  547. end;
  548.  
  549. procedure TOpenDialog.WndProc(var Message: TMessage);
  550. var
  551.   Index: Integer;
  552.   Include: Boolean;
  553. begin
  554.   Message.Result := 0;
  555.   { If not ofOldStyleDialog then DoShow on CDN_INITDONE, not WM_INITDIALOG }
  556.   if (Message.Msg = WM_INITDIALOG) and not (ofOldStyleDialog in Options) then Exit
  557.   else if (Message.Msg = WM_NOTIFY) then
  558.     case (POFNotify(Message.LParam)^.hdr.code) of
  559.       CDN_FILEOK:
  560.         if not CanClose(POFNotify(Message.LParam)^.lpOFN^) then
  561.         begin
  562.           Message.Result := 1;
  563.           SetWindowLong(Handle, DWL_MSGRESULT, Message.Result);
  564.           Exit;
  565.         end;
  566.       CDN_INITDONE: DoShow;
  567.       CDN_SELCHANGE: DoSelectionChange;
  568.       CDN_FOLDERCHANGE: DoFolderChange;
  569.       CDN_TYPECHANGE:
  570.         begin
  571.           Index := POFNotify(Message.LParam)^.lpOFN^.nFilterIndex;
  572.           if Index <> FCurrentFilterIndex then
  573.           begin
  574.             FCurrentFilterIndex := Index;
  575.             DoTypeChange;
  576.           end;
  577.         end;
  578.       CDN_INCLUDEITEM:
  579.         if Message.LParam <> 0 then
  580.         begin
  581.           Include := True;
  582.           DoIncludeItem(TOFNotifyEx(POFNotifyEx(Message.LParam)^), Include);
  583.           Message.Result := Byte(Include);
  584.         end;
  585.     end;
  586.   inherited WndProc(Message);
  587. end;
  588.  
  589. function TOpenDialog.DoCanClose: Boolean;
  590. begin
  591.   Result := True;
  592.   if Assigned(FOnCanClose) then FOnCanClose(Self, Result);
  593. end;
  594.  
  595. procedure TOpenDialog.DoSelectionChange;
  596. begin
  597.   if Assigned(FOnSelectionChange) then FOnSelectionChange(Self);
  598. end;
  599.  
  600. procedure TOpenDialog.DoFolderChange;
  601. begin
  602.   if Assigned(FOnFolderChange) then FOnFolderChange(Self);
  603. end;
  604.  
  605. procedure TOpenDialog.DoTypeChange;
  606. begin
  607.   if Assigned(FOnTypeChange) then FOnTypeChange(Self);
  608. end;
  609.  
  610. procedure TOpenDialog.ReadFileEditStyle(Reader: TReader);
  611. begin
  612.   { Ignore FileEditStyle }
  613.   Reader.ReadIdent;
  614. end;
  615.  
  616. procedure TOpenDialog.DefineProperties(Filer: TFiler);
  617. begin
  618.   inherited DefineProperties(Filer);
  619.   Filer.DefineProperty('FileEditStyle', ReadFileEditStyle, nil, False);
  620. end;
  621.  
  622. function TOpenDialog.DoExecute(Func: Pointer): Bool;
  623. const
  624.   MultiSelectBufferSize = High(Word) - 16;
  625.   OpenOptions: array [TOpenOption] of DWORD = (
  626.     OFN_READONLY, OFN_OVERWRITEPROMPT, OFN_HIDEREADONLY,
  627.     OFN_NOCHANGEDIR, OFN_SHOWHELP, OFN_NOVALIDATE, OFN_ALLOWMULTISELECT,
  628.     OFN_EXTENSIONDIFFERENT, OFN_PATHMUSTEXIST, OFN_FILEMUSTEXIST,
  629.     OFN_CREATEPROMPT, OFN_SHAREAWARE, OFN_NOREADONLYRETURN,
  630.     OFN_NOTESTFILECREATE, OFN_NONETWORKBUTTON, OFN_NOLONGNAMES,
  631.     OFN_EXPLORER, OFN_NODEREFERENCELINKS, OFN_ENABLEINCLUDENOTIFY,
  632.     OFN_ENABLESIZING);
  633. var
  634.   Option: TOpenOption;
  635.   OpenFilename: TOpenFilename;
  636.  
  637.   function AllocFilterStr(const S: string): string;
  638.   var
  639.     P: PChar;
  640.   begin
  641.     Result := '';
  642.     if S <> '' then
  643.     begin
  644.       Result := S + #0;  // double null terminators
  645.       P := AnsiStrScan(PChar(Result), '|');
  646.       while P <> nil do
  647.       begin
  648.         P^ := #0;
  649.         Inc(P);
  650.         P := AnsiStrScan(P, '|');
  651.       end;
  652.     end;
  653.   end;
  654.  
  655. var
  656.   TempFilter, TempFilename, TempExt: string;
  657. begin
  658.   FFiles.Clear;
  659.   FillChar(OpenFileName, SizeOf(OpenFileName), 0);
  660.   with OpenFilename do
  661.   begin
  662.     lStructSize := SizeOf(TOpenFilename);
  663.     hInstance := SysInit.HInstance;
  664.     TempFilter := AllocFilterStr(FFilter);
  665.     lpstrFilter := PChar(TempFilter);
  666.     nFilterIndex := FFilterIndex;
  667.     FCurrentFilterIndex := FFilterIndex;
  668.     if ofAllowMultiSelect in FOptions then
  669.       nMaxFile := MultiSelectBufferSize else
  670.       nMaxFile := MAX_PATH;
  671.     SetLength(TempFilename, nMaxFile + 2);
  672.     lpstrFile := PChar(TempFilename);
  673.     FillChar(lpstrFile^, nMaxFile + 2, 0);
  674.     StrLCopy(lpstrFile, PChar(FFileName), nMaxFile);
  675.     if (FInitialDir = '') and ForceCurrentDirectory then
  676.       lpstrInitialDir := '.'
  677.     else
  678.       lpstrInitialDir := PChar(FInitialDir);
  679.     lpstrTitle := PChar(FTitle);
  680.     Flags := OFN_ENABLEHOOK;
  681.     for Option := Low(Option) to High(Option) do
  682.       if Option in FOptions then
  683.         Flags := Flags or OpenOptions[Option];
  684.     if NewStyleControls then
  685.       Flags := Flags xor OFN_EXPLORER
  686.     else
  687.       Flags := Flags and not OFN_EXPLORER;
  688.     TempExt := FDefaultExt;
  689.     if (TempExt = '') and (Flags and OFN_EXPLORER = 0) then
  690.     begin
  691.       TempExt := ExtractFileExt(FFilename);
  692.       Delete(TempExt, 1, 1);
  693.     end;
  694.     if TempExt <> '' then lpstrDefExt := PChar(TempExt);
  695.     if (ofOldStyleDialog in Options) or not NewStyleControls then
  696.       lpfnHook := DialogHook
  697.     else
  698.     begin
  699.       lpfnHook := ExplorerHook;
  700.     end;
  701.       if Template <> nil then
  702.       begin
  703.         Flags := Flags or OFN_ENABLETEMPLATE;
  704.         lpTemplateName := Template;
  705.       end;
  706.     hWndOwner := Application.Handle;
  707.     Result := TaskModalDialog(Func, OpenFileName);
  708.     if Result then
  709.     begin
  710.       GetFileNames(OpenFilename);
  711.       if (Flags and OFN_EXTENSIONDIFFERENT) <> 0 then
  712.         Include(FOptions, ofExtensionDifferent) else
  713.         Exclude(FOptions, ofExtensionDifferent);
  714.       if (Flags and OFN_READONLY) <> 0 then
  715.         Include(FOptions, ofReadOnly) else
  716.         Exclude(FOptions, ofReadOnly);
  717.       FFilterIndex := nFilterIndex;
  718.     end;
  719.   end;
  720. end;
  721.  
  722. procedure TOpenDialog.GetFileNames(var OpenFileName: TOpenFileName);
  723. var
  724.   Separator: Char;
  725.  
  726.   function ExtractFileName(P: PChar; var S: TFilename): PChar;
  727.   begin
  728.     Result := AnsiStrScan(P, Separator);
  729.     if Result = nil then
  730.     begin
  731.       S := P;
  732.       Result := StrEnd(P);
  733.     end
  734.     else
  735.     begin
  736.       SetString(S, P, Result - P);
  737.       Inc(Result);
  738.     end;
  739.   end;
  740.  
  741.   procedure ExtractFileNames(P: PChar);
  742.   var
  743.     DirName, FileName: TFilename;
  744.   begin
  745.     P := ExtractFileName(P, DirName);
  746.     P := ExtractFileName(P, FileName);
  747.     if FileName = '' then
  748.       FFiles.Add(DirName)
  749.     else
  750.     begin
  751.       if AnsiLastChar(DirName)^ <> '\' then
  752.         DirName := DirName + '\';
  753.       repeat
  754.         if (FileName[1] <> '\') and ((Length(FileName) <= 3) or
  755.           (FileName[2] <> ':') or (FileName[3] <> '\')) then
  756.           FileName := DirName + FileName;
  757.         FFiles.Add(FileName);
  758.         P := ExtractFileName(P, FileName);
  759.       until FileName = '';
  760.     end;
  761.   end;
  762.  
  763. begin
  764.   Separator := #0;
  765.   if (ofAllowMultiSelect in FOptions) and
  766.     ((ofOldStyleDialog in FOptions) or not NewStyleControls) then
  767.     Separator := ' ';
  768.   with OpenFileName do
  769.   begin
  770.     if ofAllowMultiSelect in FOptions then
  771.     begin
  772.       ExtractFileNames(lpstrFile);
  773.       FFileName := FFiles[0];
  774.     end else
  775.     begin
  776.       ExtractFileName(lpstrFile, FFileName);
  777.       FFiles.Add(FFileName);
  778.     end;
  779.   end;
  780. end;
  781.  
  782. function TOpenDialog.GetStaticRect: TRect;
  783. begin
  784.   if FHandle <> 0 then
  785.   begin
  786.     if not (ofOldStyleDialog in Options) then
  787.     begin
  788.       GetWindowRect(GetDlgItem(FHandle, stc32), Result);
  789.       MapWindowPoints(0, FHandle, Result, 2);
  790.     end
  791.     else GetClientRect(FHandle, Result)
  792.   end
  793.   else Result := Rect(0,0,0,0);
  794. end;
  795.  
  796. function TOpenDialog.GetFileName: TFileName;
  797. var
  798.   Path: array[0..MAX_PATH] of Char;
  799. begin
  800.   if NewStyleControls and (FHandle <> 0) then
  801.   begin
  802.     SendMessage(GetParent(FHandle), CDM_GETFILEPATH, SizeOf(Path), Integer(@Path));
  803.     Result := StrPas(Path);
  804.   end
  805.   else Result := FFileName;
  806. end;
  807.  
  808. function TOpenDialog.GetFilterIndex: Integer;
  809. begin
  810.   if FHandle <> 0 then
  811.     Result := FCurrentFilterIndex
  812.   else
  813.     Result := FFilterIndex;
  814. end;
  815.  
  816. procedure TOpenDialog.SetHistoryList(Value: TStrings);
  817. begin
  818.   FHistoryList.Assign(Value);
  819. end;
  820.  
  821. procedure TOpenDialog.SetInitialDir(const Value: string);
  822. var
  823.   L: Integer;
  824. begin
  825.   L := Length(Value);
  826.   if (L > 1) and IsPathDelimiter(Value, L)
  827.     and not IsDelimiter(':', Value, L - 1) then Dec(L);
  828.   FInitialDir := Copy(Value, 1, L);
  829. end;
  830.  
  831. function TOpenDialog.Execute: Boolean;
  832. begin
  833.   Result := DoExecute(@GetOpenFileName);
  834. end;
  835.  
  836. procedure TOpenDialog.DoIncludeItem(const OFN: TOFNotifyEx; var Include: Boolean);
  837. begin
  838.   if Assigned(FOnIncludeItem) then FOnIncludeItem(OFN, Include);
  839. end;
  840.  
  841. { TSaveDialog }
  842.  
  843. function TSaveDialog.Execute: Boolean;
  844. begin
  845.   Result := DoExecute(@GetSaveFileName);
  846. end;
  847.  
  848. { TColorDialog }
  849.  
  850. constructor TColorDialog.Create(AOwner: TComponent);
  851. begin
  852.   inherited Create(AOwner);
  853.   FCustomColors := TStringList.Create;
  854. end;
  855.  
  856. destructor TColorDialog.Destroy;
  857. begin
  858.   FCustomColors.Free;
  859.   inherited Destroy;
  860. end;
  861.  
  862. function TColorDialog.Execute: Boolean;
  863. const
  864.   DialogOptions: array[TColorDialogOption] of DWORD = (
  865.     CC_FULLOPEN, CC_PREVENTFULLOPEN, CC_SHOWHELP, CC_SOLIDCOLOR,
  866.     CC_ANYCOLOR);
  867. var
  868.   ChooseColorRec: TChooseColor;
  869.   Option: TColorDialogOption;
  870.   CustomColorsArray: TCustomColors;
  871.  
  872. const
  873.   ColorPrefix = 'Color';
  874.  
  875.   procedure GetCustomColorsArray;
  876.   var
  877.     I: Integer;
  878.   begin
  879.     for I := 0 to MaxCustomColors - 1 do
  880.       FCustomColors.Values[ColorPrefix + Char(Ord('A') + I)] :=
  881.         Format('%.6x', [CustomColorsArray[I]]);
  882.   end;
  883.  
  884.   procedure SetCustomColorsArray;
  885.   var
  886.     Value: string;
  887.     I: Integer;
  888.   begin
  889.     for I := 0 to MaxCustomColors - 1 do
  890.     begin
  891.       Value := FCustomColors.Values[ColorPrefix + Char(Ord('A') + I)];
  892.       if Value <> '' then
  893.         CustomColorsArray[I] := StrToInt('$' + Value) else
  894.         CustomColorsArray[I] := -1;
  895.     end;
  896.   end;
  897.  
  898. begin
  899.   with ChooseColorRec do
  900.   begin
  901.     SetCustomColorsArray;
  902.     lStructSize := SizeOf(ChooseColorRec);
  903.     hInstance := SysInit.HInstance;
  904.     rgbResult := ColorToRGB(FColor);
  905.     lpCustColors := @CustomColorsArray;
  906.     Flags := CC_RGBINIT or CC_ENABLEHOOK;
  907.     for Option := Low(Option) to High(Option) do
  908.       if Option in FOptions then
  909.         Flags := Flags or DialogOptions[Option];
  910.     if Template <> nil then
  911.     begin
  912.       Flags := Flags or CC_ENABLETEMPLATE;
  913.       lpTemplateName := Template;
  914.     end;
  915.     lpfnHook := DialogHook;
  916.     hWndOwner := Application.Handle;
  917.     Result := TaskModalDialog(@ChooseColor, ChooseColorRec);
  918.     if Result then
  919.     begin
  920.       FColor := rgbResult;
  921.       GetCustomColorsArray;
  922.     end;
  923.   end;
  924. end;
  925.  
  926. procedure TColorDialog.SetCustomColors(Value: TStrings);
  927. begin
  928.   FCustomColors.Assign(Value);
  929. end;
  930.  
  931. { TFontDialog }
  932.  
  933. const
  934.   IDAPPLYBTN = $402;
  935.  
  936. var
  937.   FontDialog: TFontDialog;
  938.  
  939. function FontDialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  940. begin
  941.   if (Msg = WM_COMMAND) and (LongRec(WParam).Lo = IDAPPLYBTN) and
  942.     (LongRec(WParam).Hi = BN_CLICKED) then
  943.   begin
  944.     FontDialog.DoApply(Wnd);
  945.     Result := 1;
  946.   end else
  947.     Result := DialogHook(Wnd, Msg, wParam, lParam);
  948. end;
  949.  
  950. constructor TFontDialog.Create(AOwner: TComponent);
  951. begin
  952.   inherited Create(AOwner);
  953.   FFont := TFont.Create;
  954.   FOptions := [fdEffects];
  955. end;
  956.  
  957. destructor TFontDialog.Destroy;
  958. begin
  959.   FFont.Free;
  960.   inherited Destroy;
  961. end;
  962.  
  963. procedure TFontDialog.WndProc(var Message: TMessage);
  964. begin
  965.   { Make sure we only take values from the color combobox and script combobox
  966.     if they have been changed. }
  967.   if (Message.Msg = WM_COMMAND) and (Message.WParamHi = CBN_SELENDOK) then
  968.     if (Message.WParamLo = cmb4) then FFontColorModified := True
  969.     else if (Message.WParamLo = cmb5) then FFontCharsetModified := True;
  970.   inherited WndProc(Message);
  971. end;
  972.  
  973. procedure TFontDialog.Apply(Wnd: HWND);
  974. begin
  975.   if Assigned(FOnApply) then FOnApply(Self, Wnd);
  976. end;
  977.  
  978. procedure TFontDialog.DoApply(Wnd: HWND);
  979. const
  980.   IDCOLORCMB = $473;
  981. var
  982.   I: Integer;
  983.   LogFont: TLogFont;
  984. begin
  985.   SendMessage(Wnd, WM_CHOOSEFONT_GETLOGFONT, 0, LongInt(@LogFont));
  986.   UpdateFromLogFont(LogFont);
  987.   I := SendDlgItemMessage(Wnd, IDCOLORCMB, CB_GETCURSEL, 0, 0);
  988.   if I <> CB_ERR then
  989.     Font.Color := SendDlgItemMessage(Wnd, IDCOLORCMB, CB_GETITEMDATA, I, 0);
  990.   try
  991.     Apply(Wnd);
  992.   except
  993.     Application.HandleException(Self);
  994.   end;
  995. end;
  996.  
  997. function TFontDialog.Execute: Boolean;
  998. const
  999.   FontOptions: array[TFontDialogOption] of DWORD = (
  1000.     CF_ANSIONLY, CF_TTONLY, CF_EFFECTS, CF_FIXEDPITCHONLY, CF_FORCEFONTEXIST,
  1001.     CF_NOFACESEL, CF_NOOEMFONTS, CF_NOSIMULATIONS, CF_NOSIZESEL,
  1002.     CF_NOSTYLESEL, CF_NOVECTORFONTS, CF_SHOWHELP,
  1003.     CF_WYSIWYG or CF_BOTH or CF_SCALABLEONLY, CF_LIMITSIZE,
  1004.     CF_SCALABLEONLY, CF_APPLY);
  1005.   Devices: array[TFontDialogDevice] of DWORD = (
  1006.     CF_SCREENFONTS, CF_PRINTERFONTS, CF_BOTH);
  1007. var
  1008.   ChooseFontRec: TChooseFont;
  1009.   LogFont: TLogFont;
  1010.   Option: TFontDialogOption;
  1011.   SaveFontDialog: TFontDialog;
  1012.   OriginalFaceName: string;
  1013. begin
  1014.   with ChooseFontRec do
  1015.   begin
  1016.     lStructSize := SizeOf(ChooseFontRec);
  1017.     hDC := 0;
  1018.     if FDevice <> fdScreen then hDC := Printer.Handle;
  1019.     lpLogFont := @LogFont;
  1020.     GetObject(Font.Handle, SizeOf(LogFont), @LogFont);
  1021.     OriginalFaceName := LogFont.lfFaceName;
  1022.     Flags := Devices[FDevice] or (CF_INITTOLOGFONTSTRUCT or CF_ENABLEHOOK);
  1023.     for Option := Low(Option) to High(Option) do
  1024.       if Option in FOptions then
  1025.         Flags := Flags or FontOptions[Option];
  1026.     if Assigned(FOnApply) then Flags := Flags or CF_APPLY;
  1027.     if Template <> nil then
  1028.     begin
  1029.       Flags := Flags or CF_ENABLETEMPLATE;
  1030.       lpTemplateName := Template;
  1031.     end;
  1032.     rgbColors := Font.Color;
  1033.     lCustData := 0;
  1034.     lpfnHook := FontDialogHook;
  1035.     nSizeMin := FMinFontSize;
  1036.     nSizeMax := FMaxFontSize;
  1037.     if nSizeMin > nSizeMax then Flags := Flags and (not CF_LIMITSIZE);
  1038.     hWndOwner := Application.Handle;
  1039.     SaveFontDialog := FontDialog;
  1040.     FontDialog := Self;
  1041.     FFontColorModified := False;
  1042.     FFontCharsetModified := False;
  1043.     Result := TaskModalDialog(@ChooseFont, ChooseFontRec);
  1044.     FontDialog := SaveFontDialog;
  1045.     if Result then
  1046.     begin
  1047.       if AnsiCompareText(OriginalFaceName, LogFont.lfFaceName) <> 0 then
  1048.         FFontCharsetModified := True;
  1049.       UpdateFromLogFont(LogFont);
  1050.       if FFontColorModified then Font.Color := rgbColors;
  1051.     end;
  1052.   end;
  1053. end;
  1054.  
  1055. procedure TFontDialog.SetFont(Value: TFont);
  1056. begin
  1057.   FFont.Assign(Value);
  1058. end;
  1059.  
  1060. procedure TFontDialog.UpdateFromLogFont(const LogFont: TLogFont);
  1061. var
  1062.   Style: TFontStyles;
  1063. begin
  1064.   with LogFont do
  1065.   begin
  1066.     Font.Name := LogFont.lfFaceName;
  1067.     Font.Height := LogFont.lfHeight;
  1068.     if FFontCharsetModified then
  1069.       Font.Charset := TFontCharset(LogFont.lfCharSet);
  1070.     Style := [];
  1071.     with LogFont do
  1072.     begin
  1073.       if lfWeight > FW_REGULAR then Include(Style, fsBold);
  1074.       if lfItalic <> 0 then Include(Style, fsItalic);
  1075.       if lfUnderline <> 0 then Include(Style, fsUnderline);
  1076.       if lfStrikeOut <> 0 then Include(Style, fsStrikeOut);
  1077.     end;
  1078.     Font.Style := Style;
  1079.   end;
  1080. end;
  1081.  
  1082. { Printer dialog routines }
  1083.  
  1084. procedure GetPrinter(var DeviceMode, DeviceNames: THandle);
  1085. var
  1086.   Device, Driver, Port: array[0..79] of char;
  1087.   DevNames: PDevNames;
  1088.   Offset: PChar;
  1089. begin
  1090.   Printer.GetPrinter(Device, Driver, Port, DeviceMode);
  1091.   if DeviceMode <> 0 then
  1092.   begin
  1093.     DeviceNames := GlobalAlloc(GHND, SizeOf(TDevNames) +
  1094.      StrLen(Device) + StrLen(Driver) + StrLen(Port) + 3);
  1095.     DevNames := PDevNames(GlobalLock(DeviceNames));
  1096.     try
  1097.       Offset := PChar(DevNames) + SizeOf(TDevnames);
  1098.       with DevNames^ do
  1099.       begin
  1100.         wDriverOffset := Longint(Offset) - Longint(DevNames);
  1101.         Offset := StrECopy(Offset, Driver) + 1;
  1102.         wDeviceOffset := Longint(Offset) - Longint(DevNames);
  1103.         Offset := StrECopy(Offset, Device) + 1;
  1104.         wOutputOffset := Longint(Offset) - Longint(DevNames);;
  1105.         StrCopy(Offset, Port);
  1106.       end;
  1107.     finally
  1108.       GlobalUnlock(DeviceNames);
  1109.     end;
  1110.   end;
  1111. end;
  1112.  
  1113. procedure SetPrinter(DeviceMode, DeviceNames: THandle);
  1114. var
  1115.   DevNames: PDevNames;
  1116. begin
  1117.   DevNames := PDevNames(GlobalLock(DeviceNames));
  1118.   try
  1119.     with DevNames^ do
  1120.       Printer.SetPrinter(PChar(DevNames) + wDeviceOffset,
  1121.         PChar(DevNames) + wDriverOffset,
  1122.         PChar(DevNames) + wOutputOffset, DeviceMode);
  1123.   finally
  1124.     GlobalUnlock(DeviceNames);
  1125.     GlobalFree(DeviceNames);
  1126.   end;
  1127. end;
  1128.  
  1129. function CopyData(Handle: THandle): THandle;
  1130. var
  1131.   Src, Dest: PChar;
  1132.   Size: Integer;
  1133. begin
  1134.   if Handle <> 0 then
  1135.   begin
  1136.     Size := GlobalSize(Handle);
  1137.     Result := GlobalAlloc(GHND, Size);
  1138.     if Result <> 0 then
  1139.       try
  1140.         Src := GlobalLock(Handle);
  1141.         Dest := GlobalLock(Result);
  1142.         if (Src <> nil) and (Dest <> nil) then Move(Src^, Dest^, Size);
  1143.       finally
  1144.         GlobalUnlock(Handle);
  1145.         GlobalUnlock(Result);
  1146.       end
  1147.   end
  1148.   else Result := 0;
  1149. end;
  1150.  
  1151. { TPrinterSetupDialog }
  1152.  
  1153. function TPrinterSetupDialog.Execute: Boolean;
  1154. var
  1155.   PrintDlgRec: TPrintDlg;
  1156.   DevHandle: THandle;
  1157. begin
  1158.   FillChar(PrintDlgRec, SizeOf(PrintDlgRec), 0);
  1159.   with PrintDlgRec do
  1160.   begin
  1161.     lStructSize := SizeOf(PrintDlgRec);
  1162.     hInstance := SysInit.HInstance;
  1163.     GetPrinter(DevHandle, hDevNames);
  1164.     hDevMode := CopyData(DevHandle);
  1165.     Flags := PD_ENABLESETUPHOOK or PD_PRINTSETUP;
  1166.     lpfnSetupHook := DialogHook;
  1167.     hWndOwner := Application.Handle;
  1168.     Result := TaskModalDialog(@PrintDlg, PrintDlgRec);
  1169.     if Result then
  1170.       SetPrinter(hDevMode, hDevNames)
  1171.     else begin
  1172.       if hDevMode <> 0 then GlobalFree(hDevMode);
  1173.       if hDevNames <> 0 then GlobalFree(hDevNames);
  1174.     end;
  1175.   end;
  1176. end;
  1177.  
  1178. { TPrintDialog }
  1179.  
  1180. procedure TPrintDialog.SetNumCopies(Value: Integer);
  1181. begin
  1182.   FCopies := Value;
  1183.   Printer.Copies := Value;
  1184. end;
  1185.  
  1186. function TPrintDialog.Execute: Boolean;
  1187. const
  1188.   PrintRanges: array[TPrintRange] of Integer =
  1189.     (PD_ALLPAGES, PD_SELECTION, PD_PAGENUMS);
  1190. var
  1191.   PrintDlgRec: TPrintDlg;
  1192.   DevHandle: THandle;
  1193. begin
  1194.   FillChar(PrintDlgRec, SizeOf(PrintDlgRec), 0);
  1195.   with PrintDlgRec do
  1196.   begin
  1197.     lStructSize := SizeOf(PrintDlgRec);
  1198.     hInstance := SysInit.HInstance;
  1199.     GetPrinter(DevHandle, hDevNames);
  1200.     hDevMode := CopyData(DevHandle);
  1201.     Flags := PrintRanges[FPrintRange] or (PD_ENABLEPRINTHOOK or
  1202.       PD_ENABLESETUPHOOK);
  1203.     if FCollate then Inc(Flags, PD_COLLATE);
  1204.     if not (poPrintToFile in FOptions) then Inc(Flags, PD_HIDEPRINTTOFILE);
  1205.     if not (poPageNums in FOptions) then Inc(Flags, PD_NOPAGENUMS);
  1206.     if not (poSelection in FOptions) then Inc(Flags, PD_NOSELECTION);
  1207.     if poDisablePrintToFile in FOptions then Inc(Flags, PD_DISABLEPRINTTOFILE);
  1208.     if FPrintToFile then Inc(Flags, PD_PRINTTOFILE);
  1209.     if poHelp in FOptions then Inc(Flags, PD_SHOWHELP);
  1210.     if not (poWarning in FOptions) then Inc(Flags, PD_NOWARNING);
  1211.     nFromPage := FFromPage;
  1212.     nToPage := FToPage;
  1213.     nMinPage := FMinPage;
  1214.     nMaxPage := FMaxPage;
  1215.     lpfnPrintHook := DialogHook;
  1216.     lpfnSetupHook := DialogHook;
  1217.     hWndOwner := Application.Handle;
  1218.     Result := TaskModalDialog(@PrintDlg, PrintDlgRec);
  1219.     if Result then
  1220.     begin
  1221.       SetPrinter(hDevMode, hDevNames);
  1222.       FCollate := Flags and PD_COLLATE <> 0;
  1223.       FPrintToFile := Flags and PD_PRINTTOFILE <> 0;
  1224.       if Flags and PD_SELECTION <> 0 then FPrintRange := prSelection else
  1225.         if Flags and PD_PAGENUMS <> 0 then FPrintRange := prPageNums else
  1226.           FPrintRange := prAllPages;
  1227.       FFromPage := nFromPage;
  1228.       FToPage := nToPage;
  1229.       if nCopies = 1 then
  1230.         Copies := Printer.Copies else
  1231.         Copies := nCopies;
  1232.     end
  1233.     else begin
  1234.       if hDevMode <> 0 then GlobalFree(hDevMode);
  1235.       if hDevNames <> 0 then GlobalFree(hDevNames);
  1236.     end;
  1237.   end;
  1238. end;
  1239.  
  1240. { TRedirectorWindow }
  1241. { A redirector window is used to put the find/replace dialog into the
  1242.   ownership chain of a form, but intercept messages that CommDlg.dll sends
  1243.   exclusively to the find/replace dialog's owner.  TRedirectorWindow
  1244.   creates its hidden window handle as owned by the target form, and the
  1245.   find/replace dialog handle is created as owned by the redirector.  The
  1246.   redirector wndproc forwards all messages to the find/replace component.
  1247. }
  1248.  
  1249. type
  1250.   TRedirectorWindow = class(TWinControl)
  1251.   private
  1252.     FFindReplaceDialog: TFindDialog;
  1253.     FFormHandle: THandle;
  1254.     procedure CMRelease(var Message); message CM_Release;
  1255.   protected
  1256.     procedure CreateParams(var Params: TCreateParams); override;
  1257.     procedure WndProc(var Message: TMessage); override;
  1258.   end;
  1259.  
  1260. procedure TRedirectorWindow.CreateParams(var Params: TCreateParams);
  1261. begin
  1262.   inherited CreateParams(Params);
  1263.   with Params do
  1264.   begin
  1265.     Style := WS_VISIBLE or WS_POPUP;
  1266.     WndParent := FFormHandle;
  1267.   end;
  1268. end;
  1269.  
  1270. procedure TRedirectorWindow.WndProc(var Message: TMessage);
  1271. begin
  1272.   inherited WndProc(Message);
  1273.   if (Message.Result = 0) and Assigned(FFindReplaceDialog) then
  1274.     Message.Result := Integer(FFindReplaceDialog.MessageHook(Message));
  1275. end;
  1276.  
  1277. procedure TRedirectorWindow.CMRelease(var Message);
  1278. begin
  1279.   Free;
  1280. end;
  1281.  
  1282. { Find and Replace dialog routines }
  1283.  
  1284. function FindReplaceWndProc(Wnd: HWND; Msg, WParam, LParam: Longint): Longint; stdcall;
  1285.  
  1286.   function CallDefWndProc: Longint;
  1287.   begin
  1288.     Result := CallWindowProc(Pointer(GetProp(Wnd,
  1289.       MakeIntAtom(WndProcPtrAtom))), Wnd, Msg, WParam, LParam);
  1290.   end;
  1291.  
  1292. begin
  1293.   case Msg of
  1294.     WM_DESTROY:
  1295.       if Application.DialogHandle = Wnd then Application.DialogHandle := 0;
  1296.     WM_NCACTIVATE:
  1297.       if WParam <> 0 then
  1298.       begin
  1299.         if Application.DialogHandle = 0 then Application.DialogHandle := Wnd;
  1300.       end else
  1301.       begin
  1302.         if Application.DialogHandle = Wnd then Application.DialogHandle := 0;
  1303.       end;
  1304.     WM_NCDESTROY:
  1305.       begin
  1306.         Result := CallDefWndProc;
  1307.         RemoveProp(Wnd, MakeIntAtom(WndProcPtrAtom));
  1308.         Exit;
  1309.       end;
  1310.    end;
  1311.    Result := CallDefWndProc;
  1312. end;
  1313.  
  1314. function FindReplaceDialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  1315. begin
  1316.   Result := DialogHook(Wnd, Msg, wParam, lParam);
  1317.   if Msg = WM_INITDIALOG then
  1318.   begin
  1319.     with TFindDialog(PFindReplace(LParam)^.lCustData) do
  1320.       if (Left <> -1) or (Top <> -1) then
  1321.         SetWindowPos(Wnd, 0, Left, Top, 0, 0, SWP_NOACTIVATE or
  1322.           SWP_NOSIZE or SWP_NOZORDER);
  1323.     SetProp(Wnd, MakeIntAtom(WndProcPtrAtom), GetWindowLong(Wnd, GWL_WNDPROC));
  1324.     SetWindowLong(Wnd, GWL_WNDPROC, Longint(@FindReplaceWndProc));
  1325.     Result := 1;
  1326.   end;
  1327. end;
  1328.  
  1329. const
  1330.   FindOptions: array[TFindOption] of DWORD = (
  1331.     FR_DOWN, FR_FINDNEXT, FR_HIDEMATCHCASE, FR_HIDEWHOLEWORD,
  1332.     FR_HIDEUPDOWN, FR_MATCHCASE, FR_NOMATCHCASE, FR_NOUPDOWN, FR_NOWHOLEWORD,
  1333.     FR_REPLACE, FR_REPLACEALL, FR_WHOLEWORD, FR_SHOWHELP);
  1334.  
  1335. { TFindDialog }
  1336.  
  1337. constructor TFindDialog.Create(AOwner: TComponent);
  1338. begin
  1339.   inherited Create(AOwner);
  1340.   FOptions := [frDown];
  1341.   FPosition.X := -1;
  1342.   FPosition.Y := -1;
  1343.   with FFindReplace do
  1344.   begin
  1345.     lStructSize := SizeOf(TFindReplace);
  1346.     hWndOwner := Application.Handle;
  1347.     hInstance := SysInit.HInstance;
  1348.     lpstrFindWhat := FFindText;
  1349.     wFindWhatLen := SizeOf(FFindText);
  1350.     lpstrReplaceWith := FReplaceText;
  1351.     wReplaceWithLen := SizeOf(FReplaceText);
  1352.     lCustData := Longint(Self);
  1353.     lpfnHook := FindReplaceDialogHook;
  1354.   end;
  1355.   FFindReplaceFunc := @CommDlg.FindText;
  1356. end;
  1357.  
  1358. destructor TFindDialog.Destroy;
  1359. begin
  1360.   if FFindHandle <> 0 then SendMessage(FFindHandle, WM_CLOSE, 0, 0);
  1361.   FRedirector.Free;
  1362.   inherited Destroy;
  1363. end;
  1364.  
  1365. procedure TFindDialog.CloseDialog;
  1366. begin
  1367.   if FFindHandle <> 0 then PostMessage(FFindHandle, WM_CLOSE, 0, 0);
  1368. end;
  1369.  
  1370. function GetTopWindow(Wnd: THandle; var ReturnVar: THandle):Bool; stdcall;
  1371. var
  1372.   Test: TWinControl;
  1373. begin
  1374.   Test := FindControl(Wnd);
  1375.   Result := True;
  1376.   if Assigned(Test) and (Test is TForm) then
  1377.   begin
  1378.     ReturnVar := Wnd;
  1379.     Result := False;
  1380.    end;
  1381. end;
  1382.  
  1383. function TFindDialog.Execute: Boolean;
  1384. var
  1385.   Option: TFindOption;
  1386. begin
  1387.   if FFindHandle <> 0 then
  1388.   begin
  1389.     BringWindowToTop(FFindHandle);
  1390.     Result := True;
  1391.   end else
  1392.   begin
  1393.     FFindReplace.Flags := FR_ENABLEHOOK;
  1394.     FFindReplace.lpfnHook := FindReplaceDialogHook;
  1395.     FRedirector := TRedirectorWindow.Create(nil);
  1396.     with TRedirectorWindow(FRedirector) do
  1397.     begin
  1398.       FFindReplaceDialog := Self;
  1399.       EnumThreadWindows(GetCurrentThreadID, @GetTopWindow, LPARAM(@FFormHandle));
  1400.     end;
  1401.     FFindReplace.hWndOwner := FRedirector.Handle;
  1402.     for Option := Low(Option) to High(Option) do
  1403.       if Option in FOptions then
  1404.         FFindReplace.Flags := FFindReplace.Flags or FindOptions[Option];
  1405.     if Template <> nil then
  1406.     begin
  1407.       FFindReplace.Flags := FFindReplace.Flags or FR_ENABLETEMPLATE;
  1408.       FFindReplace.lpTemplateName := Template;
  1409.     end;
  1410.     CreationControl := Self;
  1411.     FFindHandle := FFindReplaceFunc(FFindReplace);
  1412.     Result := FFindHandle <> 0;
  1413.   end;
  1414. end;
  1415.  
  1416. procedure TFindDialog.Find;
  1417. begin
  1418.   if Assigned(FOnFind) then FOnFind(Self);
  1419. end;
  1420.  
  1421. function TFindDialog.GetFindText: string;
  1422. begin
  1423.   Result := FFindText;
  1424. end;
  1425.  
  1426. function TFindDialog.GetLeft: Integer;
  1427. begin
  1428.   Result := Position.X;
  1429. end;
  1430.  
  1431. function TFindDialog.GetPosition: TPoint;
  1432. var
  1433.   Rect: TRect;
  1434. begin
  1435.   Result := FPosition;
  1436.   if FFindHandle <> 0 then
  1437.   begin
  1438.     GetWindowRect(FFindHandle, Rect);
  1439.     Result := Rect.TopLeft;
  1440.   end;
  1441. end;
  1442.  
  1443. function TFindDialog.GetReplaceText: string;
  1444. begin
  1445.   Result := FReplaceText;
  1446. end;
  1447.  
  1448. function TFindDialog.GetTop: Integer;
  1449. begin
  1450.   Result := Position.Y;
  1451. end;
  1452.  
  1453. function TFindDialog.MessageHook(var Msg: TMessage): Boolean;
  1454. var
  1455.   Option: TFindOption;
  1456.   Rect: TRect;
  1457. begin
  1458.   Result := inherited MessageHook(Msg);
  1459.   if not Result then
  1460.     if (Msg.Msg = FindMsg) and (Pointer(Msg.LParam) = @FFindReplace) then
  1461.     begin
  1462.       FOptions := [];
  1463.       for Option := Low(Option) to High(Option) do
  1464.         if (FFindReplace.Flags and FindOptions[Option]) <> 0 then
  1465.           Include(FOptions, Option);
  1466.       if (FFindReplace.Flags and FR_FINDNEXT) <> 0 then
  1467.         Find
  1468.       else
  1469.       if (FFindReplace.Flags and (FR_REPLACE or FR_REPLACEALL)) <> 0 then
  1470.         Replace
  1471.       else
  1472.       if (FFindReplace.Flags and FR_DIALOGTERM) <> 0 then
  1473.       begin
  1474.         GetWindowRect(FFindHandle, Rect);
  1475.         FPosition := Rect.TopLeft;
  1476.         FFindHandle := 0;
  1477.         PostMessage(FRedirector.Handle,CM_RELEASE,0,0); // free redirector later
  1478.         FRedirector := nil;
  1479.       end;
  1480.       Result := True;
  1481.     end;
  1482. end;
  1483.  
  1484. procedure TFindDialog.Replace;
  1485. begin
  1486.   if Assigned(FOnReplace) then FOnReplace(Self);
  1487. end;
  1488.  
  1489. procedure TFindDialog.SetFindText(const Value: string);
  1490. begin
  1491.   StrLCopy(FFindText, PChar(Value), SizeOf(FFindText) - 1);
  1492. end;
  1493.  
  1494. procedure TFindDialog.SetLeft(Value: Integer);
  1495. begin
  1496.   SetPosition(Point(Value, Top));
  1497. end;
  1498.  
  1499. procedure TFindDialog.SetPosition(const Value: TPoint);
  1500. begin
  1501.   if (FPosition.X <> Value.X) or (FPosition.Y <> Value.Y) then
  1502.   begin
  1503.     FPosition := Value;
  1504.     if FFindHandle <> 0 then
  1505.       SetWindowPos(FFindHandle, 0, Value.X, Value.Y, 0, 0,
  1506.         SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);
  1507.   end;
  1508. end;
  1509.  
  1510. procedure TFindDialog.SetReplaceText(const Value: string);
  1511. begin
  1512.   StrLCopy(FReplaceText, PChar(Value), SizeOf(FReplaceText) - 1);
  1513. end;
  1514.  
  1515. procedure TFindDialog.SetTop(Value: Integer);
  1516. begin
  1517.   SetPosition(Point(Left, Value));
  1518. end;
  1519.  
  1520. { TReplaceDialog }
  1521.  
  1522. constructor TReplaceDialog.Create(AOwner: TComponent);
  1523. begin
  1524.   inherited Create(AOwner);
  1525.   FFindReplaceFunc := CommDlg.ReplaceText;
  1526. end;
  1527.  
  1528. { Message dialog }
  1529.  
  1530. function Max(I, J: Integer): Integer;
  1531. begin
  1532.   if I > J then Result := I else Result := J;
  1533. end;
  1534.  
  1535. function GetAveCharSize(Canvas: TCanvas): TPoint;
  1536. var
  1537.   I: Integer;
  1538.   Buffer: array[0..51] of Char;
  1539. begin
  1540.   for I := 0 to 25 do Buffer[I] := Chr(I + Ord('A'));
  1541.   for I := 0 to 25 do Buffer[I + 26] := Chr(I + Ord('a'));
  1542.   GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result));
  1543.   Result.X := Result.X div 52;
  1544. end;
  1545.  
  1546.  
  1547. type
  1548.   TMessageForm = class(TForm)
  1549.   private
  1550.     procedure HelpButtonClick(Sender: TObject);
  1551.   public
  1552.     constructor CreateNew(AOwner: TComponent); reintroduce;
  1553.   end;
  1554.  
  1555. constructor TMessageForm.CreateNew(AOwner: TComponent);
  1556. var
  1557.   NonClientMetrics: TNonClientMetrics;
  1558. begin
  1559.   inherited CreateNew(AOwner);
  1560.   NonClientMetrics.cbSize := sizeof(NonClientMetrics);
  1561.   if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
  1562.     Font.Handle := CreateFontIndirect(NonClientMetrics.lfMessageFont);
  1563. end;
  1564.  
  1565. procedure TMessageForm.HelpButtonClick(Sender: TObject);
  1566. begin
  1567.   Application.HelpContext(HelpContext);
  1568. end;
  1569.  
  1570. var
  1571.   Captions: array[TMsgDlgType] of Pointer = (@SMsgDlgWarning, @SMsgDlgError,
  1572.     @SMsgDlgInformation, @SMsgDlgConfirm, nil);
  1573.   IconIDs: array[TMsgDlgType] of PChar = (IDI_EXCLAMATION, IDI_HAND,
  1574.     IDI_ASTERISK, IDI_QUESTION, nil);
  1575.   ButtonNames: array[TMsgDlgBtn] of string = (
  1576.     'Yes', 'No', 'OK', 'Cancel', 'Abort', 'Retry', 'Ignore', 'All', 'NoToAll',
  1577.     'YesToAll', 'Help');
  1578.   ButtonCaptions: array[TMsgDlgBtn] of Pointer = (
  1579.     @SMsgDlgYes, @SMsgDlgNo, @SMsgDlgOK, @SMsgDlgCancel, @SMsgDlgAbort,
  1580.     @SMsgDlgRetry, @SMsgDlgIgnore, @SMsgDlgAll, @SMsgDlgNoToAll, @SMsgDlgYesToAll,
  1581.     @SMsgDlgHelp);
  1582.   ModalResults: array[TMsgDlgBtn] of Integer = (
  1583.     mrYes, mrNo, mrOk, mrCancel, mrAbort, mrRetry, mrIgnore, mrAll, mrNoToAll,
  1584.     mrYesToAll, 0);
  1585. var
  1586.   ButtonWidths : array[TMsgDlgBtn] of integer;  // initialized to zero
  1587.  
  1588. function CreateMessageDialog(const Msg: string; DlgType: TMsgDlgType;
  1589.   Buttons: TMsgDlgButtons): TForm;
  1590. const
  1591.   mcHorzMargin = 8;
  1592.   mcVertMargin = 8;
  1593.   mcHorzSpacing = 10;
  1594.   mcVertSpacing = 10;
  1595.   mcButtonWidth = 50;
  1596.   mcButtonHeight = 14;
  1597.   mcButtonSpacing = 4;
  1598. var
  1599.   DialogUnits: TPoint;
  1600.   HorzMargin, VertMargin, HorzSpacing, VertSpacing, ButtonWidth,
  1601.   ButtonHeight, ButtonSpacing, ButtonCount, ButtonGroupWidth,
  1602.   IconTextWidth, IconTextHeight, X, ALeft: Integer;
  1603.   B, DefaultButton, CancelButton: TMsgDlgBtn;
  1604.   IconID: PChar;
  1605.   TextRect: TRect;
  1606. begin
  1607.   Result := TMessageForm.CreateNew(Application);
  1608.   with Result do
  1609.   begin
  1610.     BiDiMode := Application.BiDiMode;
  1611.     BorderStyle := bsDialog;
  1612.     Canvas.Font := Font;
  1613.     DialogUnits := GetAveCharSize(Canvas);
  1614.     HorzMargin := MulDiv(mcHorzMargin, DialogUnits.X, 4);
  1615.     VertMargin := MulDiv(mcVertMargin, DialogUnits.Y, 8);
  1616.     HorzSpacing := MulDiv(mcHorzSpacing, DialogUnits.X, 4);
  1617.     VertSpacing := MulDiv(mcVertSpacing, DialogUnits.Y, 8);
  1618.     ButtonWidth := MulDiv(mcButtonWidth, DialogUnits.X, 4);
  1619.     for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
  1620.     begin
  1621.       if B in Buttons then
  1622.       begin
  1623.         if ButtonWidths[B] = 0 then
  1624.         begin
  1625.           TextRect := Rect(0,0,0,0);
  1626.           Windows.DrawText( canvas.handle,
  1627.             PChar(LoadResString(ButtonCaptions[B])), -1,
  1628.             TextRect, DT_CALCRECT or DT_LEFT or DT_SINGLELINE or
  1629.             DrawTextBiDiModeFlagsReadingOnly);
  1630.           with TextRect do ButtonWidths[B] := Right - Left + 8;
  1631.         end;
  1632.         if ButtonWidths[B] > ButtonWidth then
  1633.           ButtonWidth := ButtonWidths[B];
  1634.       end;
  1635.     end;
  1636.     ButtonHeight := MulDiv(mcButtonHeight, DialogUnits.Y, 8);
  1637.     ButtonSpacing := MulDiv(mcButtonSpacing, DialogUnits.X, 4);
  1638.     SetRect(TextRect, 0, 0, Screen.Width div 2, 0);
  1639.     DrawText(Canvas.Handle, PChar(Msg), Length(Msg)+1, TextRect,
  1640.       DT_EXPANDTABS or DT_CALCRECT or DT_WORDBREAK or
  1641.       DrawTextBiDiModeFlagsReadingOnly);
  1642.     IconID := IconIDs[DlgType];
  1643.     IconTextWidth := TextRect.Right;
  1644.     IconTextHeight := TextRect.Bottom;
  1645.     if IconID <> nil then
  1646.     begin
  1647.       Inc(IconTextWidth, 32 + HorzSpacing);
  1648.       if IconTextHeight < 32 then IconTextHeight := 32;
  1649.     end;
  1650.     ButtonCount := 0;
  1651.     for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
  1652.       if B in Buttons then Inc(ButtonCount);
  1653.     ButtonGroupWidth := 0;
  1654.     if ButtonCount <> 0 then
  1655.       ButtonGroupWidth := ButtonWidth * ButtonCount +
  1656.         ButtonSpacing * (ButtonCount - 1);
  1657.     ClientWidth := Max(IconTextWidth, ButtonGroupWidth) + HorzMargin * 2;
  1658.     ClientHeight := IconTextHeight + ButtonHeight + VertSpacing +
  1659.       VertMargin * 2;
  1660.     Left := (Screen.Width div 2) - (Width div 2);
  1661.     Top := (Screen.Height div 2) - (Height div 2);
  1662.     if DlgType <> mtCustom then
  1663.       Caption := LoadResString(Captions[DlgType]) else
  1664.       Caption := Application.Title;
  1665.     if IconID <> nil then
  1666.       with TImage.Create(Result) do
  1667.       begin
  1668.         Name := 'Image';
  1669.         Parent := Result;
  1670.         Picture.Icon.Handle := LoadIcon(0, IconID);
  1671.         SetBounds(HorzMargin, VertMargin, 32, 32);
  1672.       end;
  1673.     with TLabel.Create(Result) do
  1674.     begin
  1675.       Name := 'Message';
  1676.       Parent := Result;
  1677.       WordWrap := True;
  1678.       Caption := Msg;
  1679.       BoundsRect := TextRect;
  1680.       BiDiMode := Result.BiDiMode;
  1681.       ALeft := IconTextWidth - TextRect.Right + HorzMargin;
  1682.       if UseRightToLeftAlignment then
  1683.         ALeft := Result.ClientWidth - ALeft - Width;
  1684.       SetBounds(ALeft, VertMargin,
  1685.         TextRect.Right, TextRect.Bottom);
  1686.     end;
  1687.     if mbOk in Buttons then DefaultButton := mbOk else
  1688.       if mbYes in Buttons then DefaultButton := mbYes else
  1689.         DefaultButton := mbRetry;
  1690.     if mbCancel in Buttons then CancelButton := mbCancel else
  1691.       if mbNo in Buttons then CancelButton := mbNo else
  1692.         CancelButton := mbOk;
  1693.     X := (ClientWidth - ButtonGroupWidth) div 2;
  1694.     for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
  1695.       if B in Buttons then
  1696.         with TButton.Create(Result) do
  1697.         begin
  1698.           Name := ButtonNames[B];
  1699.           Parent := Result;
  1700.           Caption := LoadResString(ButtonCaptions[B]);
  1701.           ModalResult := ModalResults[B];
  1702.           if B = DefaultButton then Default := True;
  1703.           if B = CancelButton then Cancel := True;
  1704.           SetBounds(X, IconTextHeight + VertMargin + VertSpacing,
  1705.             ButtonWidth, ButtonHeight);
  1706.           Inc(X, ButtonWidth + ButtonSpacing);
  1707.           if B = mbHelp then
  1708.             OnClick := TMessageForm(Result).HelpButtonClick;
  1709.         end;
  1710.   end;
  1711. end;
  1712.  
  1713. function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
  1714.   Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
  1715. begin
  1716.   Result := MessageDlgPosHelp(Msg, DlgType, Buttons, HelpCtx, -1, -1, '');
  1717. end;
  1718.  
  1719. function MessageDlgPos(const Msg: string; DlgType: TMsgDlgType;
  1720.   Buttons: TMsgDlgButtons; HelpCtx: Longint; X, Y: Integer): Integer;
  1721. begin
  1722.   Result := MessageDlgPosHelp(Msg, DlgType, Buttons, HelpCtx, X, Y, '');
  1723. end;
  1724.  
  1725. function MessageDlgPosHelp(const Msg: string; DlgType: TMsgDlgType;
  1726.   Buttons: TMsgDlgButtons; HelpCtx: Longint; X, Y: Integer;
  1727.   const HelpFileName: string): Integer;
  1728. begin
  1729.   with CreateMessageDialog(Msg, DlgType, Buttons) do
  1730.     try
  1731.       HelpContext := HelpCtx;
  1732.       HelpFile := HelpFileName;
  1733.       if X >= 0 then Left := X;
  1734.       if Y >= 0 then Top := Y;
  1735.       if (Y < 0) and (X < 0) then Position := poScreenCenter;
  1736.       Result := ShowModal;
  1737.     finally
  1738.       Free;
  1739.     end;
  1740. end;
  1741.  
  1742. procedure ShowMessage(const Msg: string);
  1743. begin
  1744.   ShowMessagePos(Msg, -1, -1);
  1745. end;
  1746.  
  1747. procedure ShowMessageFmt(const Msg: string; Params: array of const);
  1748. begin
  1749.   ShowMessage(Format(Msg, Params));
  1750. end;
  1751.  
  1752. procedure ShowMessagePos(const Msg: string; X, Y: Integer);
  1753. begin
  1754.   MessageDlgPos(Msg, mtCustom, [mbOK], 0, X, Y);
  1755. end;
  1756.  
  1757. { Input dialog }
  1758.  
  1759. function InputQuery(const ACaption, APrompt: string;
  1760.   var Value: string): Boolean;
  1761. var
  1762.   Form: TForm;
  1763.   Prompt: TLabel;
  1764.   Edit: TEdit;
  1765.   DialogUnits: TPoint;
  1766.   ButtonTop, ButtonWidth, ButtonHeight: Integer;
  1767. begin
  1768.   Result := False;
  1769.   Form := TForm.Create(Application);
  1770.   with Form do
  1771.     try
  1772.       Canvas.Font := Font;
  1773.       DialogUnits := GetAveCharSize(Canvas);
  1774.       BorderStyle := bsDialog;
  1775.       Caption := ACaption;
  1776.       ClientWidth := MulDiv(180, DialogUnits.X, 4);
  1777.       ClientHeight := MulDiv(63, DialogUnits.Y, 8);
  1778.       Position := poScreenCenter;
  1779.       Prompt := TLabel.Create(Form);
  1780.       with Prompt do
  1781.       begin
  1782.         Parent := Form;
  1783.         AutoSize := True;
  1784.         Left := MulDiv(8, DialogUnits.X, 4);
  1785.         Top := MulDiv(8, DialogUnits.Y, 8);
  1786.         Caption := APrompt;
  1787.       end;
  1788.       Edit := TEdit.Create(Form);
  1789.       with Edit do
  1790.       begin
  1791.         Parent := Form;
  1792.         Left := Prompt.Left;
  1793.         Top := MulDiv(19, DialogUnits.Y, 8);
  1794.         Width := MulDiv(164, DialogUnits.X, 4);
  1795.         MaxLength := 255;
  1796.         Text := Value;
  1797.         SelectAll;
  1798.       end;
  1799.       ButtonTop := MulDiv(41, DialogUnits.Y, 8);
  1800.       ButtonWidth := MulDiv(50, DialogUnits.X, 4);
  1801.       ButtonHeight := MulDiv(14, DialogUnits.Y, 8);
  1802.       with TButton.Create(Form) do
  1803.       begin
  1804.         Parent := Form;
  1805.         Caption := SMsgDlgOK;
  1806.         ModalResult := mrOk;
  1807.         Default := True;
  1808.         SetBounds(MulDiv(38, DialogUnits.X, 4), ButtonTop, ButtonWidth,
  1809.           ButtonHeight);
  1810.       end;
  1811.       with TButton.Create(Form) do
  1812.       begin
  1813.         Parent := Form;
  1814.         Caption := SMsgDlgCancel;
  1815.         ModalResult := mrCancel;
  1816.         Cancel := True;
  1817.         SetBounds(MulDiv(92, DialogUnits.X, 4), ButtonTop, ButtonWidth,
  1818.           ButtonHeight);
  1819.       end;
  1820.       if ShowModal = mrOk then
  1821.       begin
  1822.         Value := Edit.Text;
  1823.         Result := True;
  1824.       end;
  1825.     finally
  1826.       Form.Free;
  1827.     end;
  1828. end;
  1829.  
  1830. function InputBox(const ACaption, APrompt, ADefault: string): string;
  1831. begin
  1832.   Result := ADefault;
  1833.   InputQuery(ACaption, APrompt, Result);
  1834. end;
  1835.  
  1836. { Initialization and cleanup }
  1837.  
  1838. procedure InitGlobals;
  1839. var
  1840.   AtomText: array[0..31] of Char;
  1841. begin
  1842.   HelpMsg := RegisterWindowMessage(HelpMsgString);
  1843.   FindMsg := RegisterWindowMessage(FindMsgString);
  1844.   WndProcPtrAtom := GlobalAddAtom(StrFmt(AtomText,
  1845.     'WndProcPtr%.8X%.8X', [HInstance, GetCurrentThreadID]));
  1846. end;
  1847.  
  1848. initialization
  1849.   InitGlobals;
  1850. finalization
  1851.   if WndProcPtrAtom <> 0 then GlobalDeleteAtom(WndProcPtrAtom);
  1852. end.
  1853.