home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 1999 February / DPPCPRO0299.ISO / February / Delphi / Install / DATA.Z / DIALOGS.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-06-09  |  43.2 KB  |  1,489 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Delphi Visual Component Library                 }
  5. {                                                       }
  6. {       Copyright (c) 1995,96 Borland International     }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit Dialogs;
  11.  
  12. {$R-}
  13.  
  14. interface
  15.  
  16. uses Windows, Messages, SysUtils, CommDlg, Classes, Graphics, Controls,
  17.   Forms;
  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.     FHelpContext: THelpContext;
  33.   protected
  34.     function Message(var Msg: TMessage): Boolean; virtual;
  35.     function TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool; virtual;
  36.   public
  37.     constructor Create(AOwner: TComponent); override;
  38.   published
  39.     property Ctl3D: Boolean read FCtl3D write FCtl3D default True;
  40.     property HelpContext: THelpContext read FHelpContext write FHelpContext default 0;
  41.   end;
  42.  
  43. { TOpenDialog }
  44.  
  45.   TOpenOption = (ofReadOnly, ofOverwritePrompt, ofHideReadOnly,
  46.     ofNoChangeDir, ofShowHelp, ofNoValidate, ofAllowMultiSelect,
  47.     ofExtensionDifferent, ofPathMustExist, ofFileMustExist, ofCreatePrompt,
  48.     ofShareAware, ofNoReadOnlyReturn, ofNoTestFileCreate, ofNoNetworkButton,
  49.     ofNoLongNames, ofOldStyleDialog, ofNoDereferenceLinks);
  50.   TOpenOptions = set of TOpenOption;
  51.  
  52.   TFileEditStyle = (fsEdit, fsComboBox);
  53.  
  54.   TOpenDialog = class(TCommonDialog)
  55.   private
  56.     FHistoryList: TStrings;
  57.     FOptions: TOpenOptions;
  58.     FFilter: string;
  59.     FFilterIndex: Integer;
  60.     FInitialDir: string;
  61.     FTitle: string;
  62.     FDefaultExt: string;
  63.     FFileName: TFileName;
  64.     FFiles: TStrings;
  65.     FFileEditStyle: TFileEditStyle;
  66.     procedure SetHistoryList(Value: TStrings);
  67.     procedure SetInitialDir(const Value: string);
  68.     function DoExecute(Func: Pointer): Bool;
  69.   public
  70.     constructor Create(AOwner: TComponent); override;
  71.     destructor Destroy; override;
  72.     function Execute: Boolean; virtual;
  73.     property Files: TStrings read FFiles;
  74.   published
  75.     property DefaultExt: string read FDefaultExt write FDefaultExt;
  76.     property FileEditStyle: TFileEditStyle read FFileEditStyle write FFileEditStyle;
  77.     property FileName: TFileName read FFileName write FFileName;
  78.     property Filter: string read FFilter write FFilter;
  79.     property FilterIndex: Integer read FFilterIndex write FFilterIndex default 1;
  80.     property HistoryList: TStrings read FHistoryList write SetHistoryList;
  81.     property InitialDir: string read FInitialDir write SetInitialDir;
  82.     property Options: TOpenOptions read FOptions write FOptions default [];
  83.     property Title: string read FTitle write FTitle;
  84.   end;
  85.  
  86. { TSaveDialog }
  87.  
  88.   TSaveDialog = class(TOpenDialog)
  89.     function Execute: Boolean; override;
  90.   end;
  91.  
  92. { TColorDialog }
  93.  
  94.   TColorDialogOption = (cdFullOpen, cdPreventFullOpen, cdShowHelp,
  95.     cdSolidColor, cdAnyColor);
  96.   TColorDialogOptions = set of TColorDialogOption;
  97.  
  98.   TCustomColors = array[0..MaxCustomColors - 1] of Longint;
  99.  
  100.   TColorDialog = class(TCommonDialog)
  101.   private
  102.     FColor: TColor;
  103.     FOptions: TColorDialogOptions;
  104.     FCustomColors: TStrings;
  105.     procedure SetCustomColors(Value: TStrings);
  106.   public
  107.     constructor Create(AOwner: TComponent); override;
  108.     destructor Destroy; override;
  109.     function Execute: Boolean;
  110.   published
  111.     property Color: TColor read FColor write FColor default clBlack;
  112.     property Ctl3D default False;
  113.     property CustomColors: TStrings read FCustomColors write SetCustomColors;
  114.     property Options: TColorDialogOptions read FOptions write FOptions default [];
  115.   end;
  116.  
  117. { TFontDialog }
  118.  
  119.   TFontDialogOption = (fdAnsiOnly, fdTrueTypeOnly, fdEffects,
  120.     fdFixedPitchOnly, fdForceFontExist, fdNoFaceSel, fdNoOEMFonts,
  121.     fdNoSimulations, fdNoSizeSel, fdNoStyleSel,  fdNoVectorFonts,
  122.     fdShowHelp, fdWysiwyg, fdLimitSize, fdScalableOnly, fdApplyButton);
  123.   TFontDialogOptions = set of TFontDialogOption;
  124.  
  125.   TFontDialogDevice = (fdScreen, fdPrinter, fdBoth);
  126.  
  127.   TFDApplyEvent = procedure(Sender: TObject; Wnd: HWND) of object;
  128.  
  129.   TFontDialog = class(TCommonDialog)
  130.   private
  131.     FFont: TFont;
  132.     FDevice: TFontDialogDevice;
  133.     FOptions: TFontDialogOptions;
  134.     FOnApply: TFDApplyEvent;
  135.     FMinFontSize: Integer;
  136.     FMaxFontSize: Integer;
  137.     procedure DoApply(Wnd: HWND);
  138.     procedure SetFont(Value: TFont);
  139.     procedure UpdateFromLogFont(const LogFont: TLogFont);
  140.   protected
  141.     procedure Apply(Wnd: HWND); dynamic;
  142.   public
  143.     constructor Create(AOwner: TComponent); override;
  144.     destructor Destroy; override;
  145.     function Execute: Boolean;
  146.   published
  147.     property Font: TFont read FFont write SetFont;
  148.     property Device: TFontDialogDevice read FDevice write FDevice default fdScreen;
  149.     property MinFontSize: Integer read FMinFontSize write FMinFontSize;
  150.     property MaxFontSize: Integer read FMaxFontSize write FMaxFontSize;
  151.     property Options: TFontDialogOptions read FOptions write FOptions default [fdEffects];
  152.     property OnApply: TFDApplyEvent read FOnApply write FOnApply;
  153.   end;
  154.  
  155. { TPrinterSetupDialog }
  156.  
  157.   TPrinterSetupDialog = class(TCommonDialog)
  158.   public
  159.     procedure Execute;
  160.   end;
  161.  
  162. { TPrintDialog }
  163.  
  164.   TPrintRange = (prAllPages, prSelection, prPageNums);
  165.   TPrintDialogOption = (poPrintToFile, poPageNums, poSelection, poWarning,
  166.     poHelp, poDisablePrintToFile);
  167.   TPrintDialogOptions = set of TPrintDialogOption;
  168.  
  169.   TPrintDialog = class(TCommonDialog)
  170.   private
  171.     FFromPage: Integer;
  172.     FToPage: Integer;
  173.     FCollate: Boolean;
  174.     FOptions: TPrintDialogOptions;
  175.     FPrintToFile: Boolean;
  176.     FPrintRange: TPrintRange;
  177.     FMinPage: Integer;
  178.     FMaxPage: Integer;
  179.     FCopies: Integer;
  180.     procedure SetNumCopies(Value: Integer);
  181.   public
  182.     function Execute: Boolean;
  183.   published
  184.     property Collate: Boolean read FCollate write FCollate default False;
  185.     property Copies: Integer read FCopies write SetNumCopies default 0;
  186.     property FromPage: Integer read FFromPage write FFromPage default 0;
  187.     property MinPage: Integer read FMinPage write FMinPage default 0;
  188.     property MaxPage: Integer read FMaxPage write FMaxPage default 0;
  189.     property Options: TPrintDialogOptions read FOptions write FOptions default [];
  190.     property PrintToFile: Boolean read FPrintToFile write FPrintToFile default False;
  191.     property PrintRange: TPrintRange read FPrintRange write FPrintRange default prAllPages;
  192.     property ToPage: Integer read FToPage write FToPage default 0;
  193.   end;
  194.  
  195. { TFindDialog }
  196.  
  197.   TFindOption = (frDown, frFindNext, frHideMatchCase, frHideWholeWord,
  198.     frHideUpDown, frMatchCase, frDisableMatchCase, frDisableUpDown,
  199.     frDisableWholeWord, frReplace, frReplaceAll, frWholeWord, frShowHelp);
  200.   TFindOptions = set of TFindOption;
  201.  
  202.   TFindReplaceFunc = function(var FindReplace: TFindReplace): HWnd stdcall;
  203.  
  204.   TFindDialog = class(TCommonDialog)
  205.   private
  206.     FOptions: TFindOptions;
  207.     FPosition: TPoint;
  208.     FHandle: HWnd;
  209.     FFindReplaceFunc: TFindReplaceFunc;
  210.     FRedirector: TWinControl;
  211.     FOnFind: TNotifyEvent;
  212.     FOnReplace: TNotifyEvent;
  213.     FFindReplace: TFindReplace;
  214.     FFindText: array[0..255] of Char;
  215.     FReplaceText: array[0..255] of Char;
  216.     function GetFindText: string;
  217.     function GetLeft: Integer;
  218.     function GetPosition: TPoint;
  219.     function GetReplaceText: string;
  220.     function GetTop: Integer;
  221.     procedure SetFindText(const Value: string);
  222.     procedure SetLeft(Value: Integer);
  223.     procedure SetPosition(const Value: TPoint);
  224.     procedure SetReplaceText(const Value: string);
  225.     procedure SetTop(Value: Integer);
  226.   protected
  227.     function Message(var Msg: TMessage): Boolean; override;
  228.     procedure Find; dynamic;
  229.     procedure Replace; dynamic;
  230.   public
  231.     constructor Create(AOwner: TComponent); override;
  232.     destructor Destroy; override;
  233.     procedure CloseDialog;
  234.     function Execute: Boolean;
  235.     property Handle: HWnd read FHandle;
  236.     property Left: Integer read GetLeft write SetLeft;
  237.     property Position: TPoint read GetPosition write SetPosition;
  238.     property Top: Integer read GetTop write SetTop;
  239.   published
  240.     property FindText: string read GetFindText write SetFindText;
  241.     property Options: TFindOptions read FOptions write FOptions default [frDown];
  242.     property OnFind: TNotifyEvent read FOnFind write FOnFind;
  243.   end;
  244.  
  245. { TReplaceDialog }
  246.  
  247.   TReplaceDialog = class(TFindDialog)
  248.   public
  249.     constructor Create(AOwner: TComponent); override;
  250.   published
  251.     property ReplaceText: string read GetReplaceText write SetReplaceText;
  252.     property OnReplace: TNotifyEvent read FOnReplace write FOnReplace;
  253.   end;
  254.  
  255. { Message dialog }
  256.  
  257. type
  258.   TMsgDlgType = (mtWarning, mtError, mtInformation, mtConfirmation, mtCustom);
  259.   TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore,
  260.     mbAll, mbHelp);
  261.   TMsgDlgButtons = set of TMsgDlgBtn;
  262.  
  263. const
  264.   mbYesNoCancel = [mbYes, mbNo, mbCancel];
  265.   mbOKCancel = [mbOK, mbCancel];
  266.   mbAbortRetryIgnore = [mbAbort, mbRetry, mbIgnore];
  267.  
  268. function CreateMessageDialog(const Msg: string; DlgType: TMsgDlgType;
  269.   Buttons: TMsgDlgButtons): TForm;
  270.  
  271. function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
  272.   Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
  273. function MessageDlgPos(const Msg: string; DlgType: TMsgDlgType;
  274.   Buttons: TMsgDlgButtons; HelpCtx: Longint; X, Y: Integer): Integer;
  275.  
  276. procedure ShowMessage(const Msg: string);
  277. procedure ShowMessagePos(const Msg: string; X, Y: Integer);
  278.  
  279. { Input dialog }
  280.  
  281. function InputBox(const ACaption, APrompt, ADefault: string): string;
  282. function InputQuery(const ACaption, APrompt: string;
  283.   var Value: string): Boolean;
  284.  
  285. implementation
  286.  
  287. uses StdCtrls, ExtCtrls, Consts, Printers;
  288.  
  289. { Private globals }
  290.  
  291. var
  292.   HelpMsg: Integer;
  293.   FindMsg: Integer;
  294.   WndProcPtrAtom: TAtom = 0;
  295.   HookCtl3D: Boolean;
  296.  
  297. { Center the given window on the screen }
  298.  
  299. procedure CenterWindow(Wnd: HWnd);
  300. var
  301.   Rect: TRect;
  302. begin
  303.   GetWindowRect(Wnd, Rect);
  304.   SetWindowPos(Wnd, 0,
  305.     (GetSystemMetrics(SM_CXSCREEN) - Rect.Right + Rect.Left) div 2,
  306.     (GetSystemMetrics(SM_CYSCREEN) - Rect.Bottom + Rect.Top) div 3,
  307.     0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);
  308. end;
  309.  
  310. { Generic dialog hook. Centers the dialog on the screen in response to
  311.   the WM_INITDIALOG message }
  312.  
  313. function DialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  314. begin
  315.   Result := 0;
  316.   case Msg of
  317.     WM_INITDIALOG:
  318.       begin
  319.         if HookCtl3D then
  320.         begin
  321.           Subclass3DDlg(Wnd, CTL3D_ALL);
  322.           SetAutoSubClass(True);
  323.         end;
  324.         CenterWindow(Wnd);
  325.         Result := 1;
  326.       end;
  327.     WM_DESTROY:
  328.       if HookCtl3D then SetAutoSubClass(False);
  329.   end;
  330. end;
  331.  
  332. { TCommonDialog }
  333.  
  334. constructor TCommonDialog.Create(AOwner: TComponent);
  335. begin
  336.   inherited Create(AOwner);
  337.   FCtl3D := True;
  338. end;
  339.  
  340. function TCommonDialog.Message(var Msg: TMessage): Boolean;
  341. begin
  342.   Result := False;
  343.   if (Msg.Msg = HelpMsg) and (FHelpContext <> 0) then
  344.   begin
  345.     Application.HelpContext(FHelpContext);
  346.     Result := True;
  347.   end;
  348. end;
  349.  
  350. function TCommonDialog.TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
  351. type
  352.   TDialogFunc = function(var DialogData): Bool stdcall;
  353. var
  354.   ActiveWindow: HWnd;
  355.   WindowList: Pointer;
  356. begin
  357.   ActiveWindow := GetActiveWindow;
  358.   WindowList := DisableTaskWindows(0);
  359.   try
  360.     Application.HookMainWindow(Message);
  361.     try
  362.       Result := TDialogFunc(DialogFunc)(DialogData);
  363.     finally
  364.       Application.UnhookMainWindow(Message);
  365.     end;
  366.   finally
  367.     EnableTaskWindows(WindowList);
  368.     SetActiveWindow(ActiveWindow);
  369.   end;
  370. end;
  371.  
  372. { Open and Save dialog routines }
  373.  
  374. function ExplorerHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  375. begin
  376.   Result := 0;
  377.   if (Msg = WM_NOTIFY) and (POFNotify(LParam)^.hdr.code = CDN_INITDONE) then
  378.     CenterWindow(GetWindowLong(Wnd, GWL_HWNDPARENT));
  379. end;
  380.  
  381. { TOpenDialog }
  382.  
  383. constructor TOpenDialog.Create(AOwner: TComponent);
  384. begin
  385.   inherited Create(AOwner);
  386.   FHistoryList := TStringList.Create;
  387.   FFiles := TStringList.Create;
  388.   FFilterIndex := 1;
  389.   FFileEditStyle := fsEdit;
  390. end;
  391.  
  392. destructor TOpenDialog.Destroy;
  393. begin
  394.   FFiles.Free;
  395.   FHistoryList.Free;
  396.   inherited Destroy;
  397. end;
  398.  
  399. function TOpenDialog.DoExecute(Func: Pointer): Bool;
  400. const
  401.   MultiSelectBufferSize = 8192;
  402.   OpenOptions: array [TOpenOption] of Longint = (
  403.     OFN_READONLY, OFN_OVERWRITEPROMPT, OFN_HIDEREADONLY,
  404.     OFN_NOCHANGEDIR, OFN_SHOWHELP, OFN_NOVALIDATE, OFN_ALLOWMULTISELECT,
  405.     OFN_EXTENSIONDIFFERENT, OFN_PATHMUSTEXIST, OFN_FILEMUSTEXIST,
  406.     OFN_CREATEPROMPT, OFN_SHAREAWARE, OFN_NOREADONLYRETURN,
  407.     OFN_NOTESTFILECREATE, OFN_NONETWORKBUTTON, OFN_NOLONGNAMES,
  408.     OFN_EXPLORER, OFN_NODEREFERENCELINKS);
  409. var
  410.   Option: TOpenOption;
  411.   P: PChar;
  412.   CDefaultExt: array[0..3] of Char;
  413.   OpenFilename: TOpenFilename;
  414.  
  415.   function AllocFilterStr(const S: string): PChar;
  416.   var
  417.     P: PChar;
  418.   begin
  419.     Result := nil;
  420.     if S <> '' then
  421.     begin
  422.       Result := StrCopy(StrAlloc(Length(S) + 2), PChar(S));
  423.       P := Result;
  424.       while P^ <> #0 do
  425.       begin
  426.         if P^ = '|' then P^ := #0;
  427.         Inc(P);
  428.       end;
  429.       Inc(P);
  430.       P^ := #0;
  431.     end;
  432.   end;
  433.  
  434.   function FindExtension(P: PChar): PChar;
  435.   begin
  436.     Result := '';
  437.     while P^ <> #0 do
  438.     begin
  439.       if P^ = '.' then Result := P + 1 else
  440.         if P^ = '\' then Result := '';
  441.       Inc(P);
  442.     end;
  443.   end;
  444.  
  445.   function ExtractFileName(P: PChar; var S: string): PChar;
  446.   var
  447.     Separator: Char;
  448.   begin
  449.     Separator := #0;
  450.     if (ofAllowMultiSelect in FOptions) and
  451.       ((ofOldStyleDialog in FOptions) or not NewStyleControls) then
  452.       Separator := ' ';
  453.     Result := P;
  454.     while (Result[0] <> #0) and (Result[0] <> Separator) do Inc(Result);
  455.     SetString(S, P, Result - P);
  456.     if Result[0] = Separator then Inc(Result);
  457.   end;
  458.  
  459.   procedure ExtractFileNames(P: PChar);
  460.   var
  461.     DirName, FileName: string;
  462.   begin
  463.     P := ExtractFileName(P, DirName);
  464.     P := ExtractFileName(P, FileName);
  465.     if FileName = '' then
  466.       FFiles.Add(DirName)
  467.     else
  468.     begin
  469.       if DirName[Length(DirName)] <> '\' then
  470.         DirName := DirName + '\';
  471.       repeat
  472.         if (FileName[1] <> '\') and ((Length(FileName) <= 3) or
  473.           (FileName[2] <> ':') or (FileName[3] <> '\')) then
  474.           FileName := DirName + FileName;
  475.         FFiles.Add(FileName);
  476.         P := ExtractFileName(P, FileName);
  477.       until FileName = '';
  478.     end;
  479.   end;
  480.  
  481. begin
  482.   FFiles.Clear;
  483.   FillChar(OpenFileName, SizeOf(OpenFileName), 0);
  484.   with OpenFilename do
  485.   try
  486.     lStructSize := SizeOf(TOpenFilename);
  487.     hInstance := System.HInstance;
  488.     lpstrFilter := AllocFilterStr(FFilter);
  489.     nFilterIndex := FFilterIndex;
  490.     if ofAllowMultiSelect in FOptions then
  491.       nMaxFile := MultiSelectBufferSize else
  492.       nMaxFile := MAX_PATH;
  493.     GetMem(lpstrFile, nMaxFile + 2);
  494.     FillChar(lpstrFile^, nMaxFile + 2, 0);
  495.     StrLCopy(lpstrFile, PChar(FFileName), nMaxFile);
  496.     lpstrInitialDir := PChar(FInitialDir);
  497.     lpstrTitle := PChar(FTitle);
  498.     HookCtl3D := FCtl3D;
  499.     Flags := OFN_ENABLEHOOK;
  500.     for Option := Low(Option) to High(Option) do
  501.       if Option in FOptions then
  502.         Flags := Flags or OpenOptions[Option];
  503.     if NewStyleControls then
  504.       Flags := Flags xor OFN_EXPLORER
  505.     else
  506.       Flags := Flags and not OFN_EXPLORER;
  507.     if FDefaultExt <> '' then
  508.     begin
  509.       P := PChar(FDefaultExt);
  510.       if (P^ = #0) and (Flags and OFN_EXPLORER = 0) then
  511.         P := FindExtension(PChar(FFileName));
  512.       lpstrDefExt := StrLCopy(CDefaultExt, P, 3)
  513.     end;
  514.     if (ofOldStyleDialog in Options) or not NewStyleControls then
  515.       lpfnHook := DialogHook
  516.     else
  517.       lpfnHook := ExplorerHook;
  518.     hWndOwner := Application.Handle;
  519.     Result := TaskModalDialog(Func, OpenFileName);
  520.     if Result then
  521.     begin
  522.       if ofAllowMultiSelect in FOptions then
  523.       begin
  524.         ExtractFileNames(lpstrFile);
  525.         FFileName := FFiles[0];
  526.       end else
  527.       begin
  528.         ExtractFileName(lpstrFile, FFileName);
  529.         FFiles.Add(FFileName);
  530.       end;
  531.       if (Flags and OFN_EXTENSIONDIFFERENT) <> 0 then
  532.         Include(FOptions, ofExtensionDifferent) else
  533.         Exclude(FOptions, ofExtensionDifferent);
  534.       if (Flags and OFN_READONLY) <> 0 then
  535.         Include(FOptions, ofReadOnly) else
  536.         Exclude(FOptions, ofReadOnly);
  537.       FFilterIndex := nFilterIndex;
  538.     end;
  539.   finally
  540.     if lpstrFile <> nil then FreeMem(lpstrFile, nMaxFile + 2);
  541.     if lpstrFilter <> nil then StrDispose(lpstrFilter);
  542.   end;
  543. end;
  544.  
  545. procedure TOpenDialog.SetHistoryList(Value: TStrings);
  546. begin
  547.   FHistoryList.Assign(Value);
  548. end;
  549.  
  550. procedure TOpenDialog.SetInitialDir(const Value: string);
  551. var
  552.   L: Integer;
  553. begin
  554.   L := Length(Value);
  555.   if (L > 1) and (Value[L] = '\') and (Value[L - 1] <> ':') then Dec(L);
  556.   FInitialDir := Copy(Value, 1, L);
  557. end;
  558.  
  559. function TOpenDialog.Execute: Boolean;
  560. begin
  561.   Result := DoExecute(@GetOpenFileName);
  562. end;
  563.  
  564. { TSaveDialog }
  565.  
  566. function TSaveDialog.Execute: Boolean;
  567. begin
  568.   Result := DoExecute(@GetSaveFileName);
  569. end;
  570.  
  571. { TColorDialog }
  572.  
  573. constructor TColorDialog.Create(AOwner: TComponent);
  574. begin
  575.   inherited Create(AOwner);
  576.   FCustomColors := TStringList.Create;
  577. end;
  578.  
  579. destructor TColorDialog.Destroy;
  580. begin
  581.   FCustomColors.Free;
  582.   inherited Destroy;
  583. end;
  584.  
  585. function TColorDialog.Execute: Boolean;
  586. const
  587.   DialogOptions: array[TColorDialogOption] of LongInt = (
  588.     CC_FULLOPEN, CC_PREVENTFULLOPEN, CC_SHOWHELP, CC_SOLIDCOLOR,
  589.     CC_ANYCOLOR);
  590. var
  591.   ChooseColorRec: TChooseColor;
  592.   Option: TColorDialogOption;
  593.   CustomColorsArray: TCustomColors;
  594.   ColorPrefix, ColorTags: string;
  595.  
  596.   procedure GetCustomColorsArray;
  597.   var
  598.     I: Integer;
  599.   begin
  600.     for I := 0 to MaxCustomColors - 1 do
  601.       FCustomColors.Values[ColorPrefix + ColorTags[I + 1]] :=
  602.         Format('%.6x', [CustomColorsArray[I]]);
  603.   end;
  604.  
  605.   procedure SetCustomColorsArray;
  606.   var
  607.     Value: string;
  608.     I: Integer;
  609.   begin
  610.     for I := 0 to MaxCustomColors - 1 do
  611.     begin
  612.       Value := FCustomColors.Values[ColorPrefix + ColorTags[I + 1]];
  613.       if Value <> '' then
  614.         CustomColorsArray[I] := StrToInt('$' + Value) else
  615.         CustomColorsArray[I] := -1;
  616.     end;
  617.   end;
  618.  
  619. begin
  620.   ColorPrefix := LoadStr(SColorPrefix);
  621.   ColorTags := LoadStr(SColorTags);
  622.   with ChooseColorRec do
  623.   begin
  624.     SetCustomColorsArray;
  625.     lStructSize := SizeOf(ChooseColorRec);
  626.     rgbResult := ColorToRGB(FColor);
  627.     lpCustColors := @CustomColorsArray;
  628.     Flags := CC_RGBINIT or CC_ENABLEHOOK;
  629.     for Option := Low(Option) to High(Option) do
  630.       if Option in FOptions then
  631.         Flags := Flags or DialogOptions[Option];
  632.     HookCtl3D := FCtl3D;
  633.     lpfnHook := DialogHook;
  634.     hWndOwner := Application.Handle;
  635.     Result := TaskModalDialog(@ChooseColor, ChooseColorRec);
  636.     if Result then
  637.     begin
  638.       FColor := rgbResult;
  639.       GetCustomColorsArray;
  640.     end;
  641.   end;
  642. end;
  643.  
  644. procedure TColorDialog.SetCustomColors(Value: TStrings);
  645. begin
  646.   FCustomColors.Assign(Value);
  647. end;
  648.  
  649. { TFontDialog }
  650.  
  651. const
  652.   IDAPPLYBTN = $402;
  653.  
  654. var
  655.   FontDialog: TFontDialog;
  656.  
  657. function FontDialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  658. begin
  659.   if (Msg = WM_COMMAND) and (LongRec(WParam).Lo = IDAPPLYBTN) and
  660.     (LongRec(WParam).Hi = BN_CLICKED) then
  661.   begin
  662.     FontDialog.DoApply(Wnd);
  663.     Result := 1;
  664.   end else
  665.     Result := DialogHook(Wnd, Msg, wParam, lParam);
  666. end;
  667.  
  668. constructor TFontDialog.Create(AOwner: TComponent);
  669. begin
  670.   inherited Create(AOwner);
  671.   FFont := TFont.Create;
  672.   FOptions := [fdEffects];
  673. end;
  674.  
  675. destructor TFontDialog.Destroy;
  676. begin
  677.   FFont.Free;
  678.   inherited Destroy;
  679. end;
  680.  
  681. procedure TFontDialog.Apply(Wnd: HWND);
  682. begin
  683.   if Assigned(FOnApply) then FOnApply(Self, Wnd);
  684. end;
  685.  
  686. procedure TFontDialog.DoApply(Wnd: HWND);
  687. const
  688.   IDCOLORCMB = $473;
  689. var
  690.   I: Integer;
  691.   LogFont: TLogFont;
  692. begin
  693.   SendMessage(Wnd, WM_CHOOSEFONT_GETLOGFONT, 0, LongInt(@LogFont));
  694.   UpdateFromLogFont(LogFont);
  695.   I := SendDlgItemMessage(Wnd, IDCOLORCMB, CB_GETCURSEL, 0, 0);
  696.   if I <> CB_ERR then
  697.     Font.Color := SendDlgItemMessage(Wnd, IDCOLORCMB, CB_GETITEMDATA, I, 0);
  698.   try
  699.     Apply(Wnd);
  700.   except
  701.     Application.HandleException(Self);
  702.   end;
  703. end;
  704.  
  705. function TFontDialog.Execute: Boolean;
  706. const
  707.   FontOptions: array[TFontDialogOption] of Longint = (
  708.     CF_ANSIONLY, CF_TTONLY, CF_EFFECTS, CF_FIXEDPITCHONLY, CF_FORCEFONTEXIST,
  709.     CF_NOFACESEL, CF_NOOEMFONTS, CF_NOSIMULATIONS, CF_NOSIZESEL,
  710.     CF_NOSTYLESEL, CF_NOVECTORFONTS, CF_SHOWHELP, CF_WYSIWYG, CF_LIMITSIZE,
  711.     CF_SCALABLEONLY, CF_APPLY);
  712.   Devices: array[TFontDialogDevice] of Longint = (
  713.     CF_SCREENFONTS, CF_PRINTERFONTS, CF_BOTH);
  714. var
  715.   ChooseFontRec: TChooseFont;
  716.   LogFont: TLogFont;
  717.   Option: TFontDialogOption;
  718.   SaveFontDialog: TFontDialog;
  719. begin
  720.   with ChooseFontRec do
  721.   begin
  722.     lStructSize := SizeOf(ChooseFontRec);
  723.     hDC := 0;
  724.     lpLogFont := @LogFont;
  725.     GetObject(Font.Handle, SizeOf(LogFont), @LogFont);
  726.     Flags := Devices[FDevice] or (CF_INITTOLOGFONTSTRUCT or CF_ENABLEHOOK);
  727.     for Option := Low(Option) to High(Option) do
  728.       if Option in FOptions then
  729.         Flags := Flags or FontOptions[Option];
  730.     if Assigned(FOnApply) then Flags := Flags or CF_APPLY;
  731.     rgbColors := Font.Color;
  732.     lCustData := 0;
  733.     HookCtl3D := Ctl3D;
  734.     lpfnHook := FontDialogHook;
  735.     nSizeMin := FMinFontSize;
  736.     nSizeMax := FMaxFontSize;
  737.     if nSizeMin > nSizeMax then Flags := Flags and (not CF_LIMITSIZE);
  738.     hWndOwner := Application.Handle;
  739.     SaveFontDialog := FontDialog;
  740.     FontDialog := Self;
  741.     Result := TaskModalDialog(@ChooseFont, ChooseFontRec);
  742.     FontDialog := SaveFontDialog;
  743.     if Result then
  744.     begin
  745.       UpdateFromLogFont(LogFont);
  746.       Font.Color := rgbColors;
  747.     end;
  748.   end;
  749. end;
  750.  
  751. procedure TFontDialog.SetFont(Value: TFont);
  752. begin
  753.   FFont.Assign(Value);
  754. end;
  755.  
  756. procedure TFontDialog.UpdateFromLogFont(const LogFont: TLogFont);
  757. var
  758.   Style: TFontStyles;
  759. begin
  760.   with LogFont do
  761.   begin
  762.     Font.Name := LogFont.lfFaceName;
  763.     Font.Height := LogFont.lfHeight;
  764.     Style := [];
  765.     with LogFont do
  766.     begin
  767.       if lfWeight > FW_REGULAR then Include(Style, fsBold);
  768.       if lfItalic <> 0 then Include(Style, fsItalic);
  769.       if lfUnderline <> 0 then Include(Style, fsUnderline);
  770.       if lfStrikeOut <> 0 then Include(Style, fsStrikeOut);
  771.     end;
  772.     Font.Style := Style;
  773.   end;
  774. end;
  775.  
  776. { Printer dialog routines }
  777.  
  778. procedure GetPrinter(var DeviceMode, DeviceNames: THandle);
  779. var
  780.   Device, Driver, Port: array[0..79] of char;
  781.   DevNames: PDevNames;
  782.   Offset: PChar;
  783. begin
  784.   Printer.GetPrinter(Device, Driver, Port, DeviceMode);
  785.   if DeviceMode <> 0 then
  786.   begin
  787.     DeviceNames := GlobalAlloc(GHND, SizeOf(TDevNames) +
  788.      StrLen(Device) + StrLen(Driver) + StrLen(Port) + 3);
  789.     DevNames := PDevNames(GlobalLock(DeviceNames));
  790.     try
  791.       Offset := PChar(DevNames) + SizeOf(TDevnames);
  792.       with DevNames^ do
  793.       begin
  794.         wDriverOffset := Longint(Offset) - Longint(DevNames);
  795.         Offset := StrECopy(Offset, Driver) + 1;
  796.         wDeviceOffset := Longint(Offset) - Longint(DevNames);
  797.         Offset := StrECopy(Offset, Device) + 1;
  798.         wOutputOffset := Longint(Offset) - Longint(DevNames);;
  799.         StrCopy(Offset, Port);
  800.       end;
  801.     finally
  802.       GlobalUnlock(DeviceNames);
  803.     end;
  804.   end;
  805. end;
  806.  
  807. procedure SetPrinter(DeviceMode, DeviceNames: THandle);
  808. var
  809.   DevNames: PDevNames;
  810. begin
  811.   DevNames := PDevNames(GlobalLock(DeviceNames));
  812.   try
  813.     with DevNames^ do
  814.       Printer.SetPrinter(PChar(DevNames) + wDeviceOffset,
  815.         PChar(DevNames) + wDriverOffset,
  816.         PChar(DevNames) + wOutputOffset, DeviceMode);
  817.   finally
  818.     GlobalUnlock(DeviceNames);
  819.     GlobalFree(DeviceNames);
  820.   end;
  821. end;
  822.  
  823. function CopyData(Handle: THandle): THandle;
  824. var
  825.   Src, Dest: PChar;
  826.   Size: Integer;
  827. begin
  828.   if Handle <> 0 then
  829.   begin
  830.     Size := GlobalSize(Handle);
  831.     Result := GlobalAlloc(GHND, Size);
  832.     if Result <> 0 then
  833.       try
  834.         Src := GlobalLock(Handle);
  835.         Dest := GlobalLock(Result);
  836.         if (Src <> nil) and (Dest <> nil) then Move(Src^, Dest^, Size);
  837.       finally
  838.         GlobalUnlock(Handle);
  839.         GlobalUnlock(Result);
  840.       end
  841.   end
  842.   else Result := 0;
  843. end;
  844.  
  845. { TPrinterSetupDialog }
  846.  
  847. procedure TPrinterSetupDialog.Execute;
  848. var
  849.   PrintDlgRec: TPrintDlg;
  850.   DevHandle: THandle;
  851. begin
  852.   FillChar(PrintDlgRec, SizeOf(PrintDlgRec), 0);
  853.   with PrintDlgRec do
  854.   begin
  855.     lStructSize := SizeOf(PrintDlgRec);
  856.     hInstance := System.HInstance;
  857.     GetPrinter(DevHandle, hDevNames);
  858.     hDevMode := CopyData(DevHandle);
  859.     Flags := PD_ENABLESETUPHOOK or PD_PRINTSETUP;
  860.     HookCtl3D := Ctl3D;
  861.     lpfnSetupHook := DialogHook;
  862.     hWndOwner := Application.Handle;
  863.     if TaskModalDialog(@PrintDlg, PrintDlgRec) then
  864.       SetPrinter(hDevMode, hDevNames)
  865.     else begin
  866.       if hDevMode <> 0 then GlobalFree(hDevMode);
  867.       if hDevNames <> 0 then GlobalFree(hDevNames);
  868.     end;
  869.   end;
  870. end;
  871.  
  872. { TPrintDialog }
  873.  
  874. procedure TPrintDialog.SetNumCopies(Value: Integer);
  875. begin
  876.   FCopies := Value;
  877.   Printer.Copies := Value;
  878. end;
  879.  
  880. function TPrintDialog.Execute: Boolean;
  881. const
  882.   PrintRanges: array[TPrintRange] of Integer =
  883.     (PD_ALLPAGES, PD_SELECTION, PD_PAGENUMS);
  884. var
  885.   PrintDlgRec: TPrintDlg;
  886.   DevHandle: THandle;
  887. begin
  888.   FillChar(PrintDlgRec, SizeOf(PrintDlgRec), 0);
  889.   with PrintDlgRec do
  890.   begin
  891.     lStructSize := SizeOf(PrintDlgRec);
  892.     hInstance := System.HInstance;
  893.     GetPrinter(DevHandle, hDevNames);
  894.     hDevMode := CopyData(DevHandle);
  895.     Flags := PrintRanges[FPrintRange] or (PD_ENABLEPRINTHOOK or
  896.       PD_ENABLESETUPHOOK);
  897.     if FCollate then Inc(Flags, PD_COLLATE);
  898.     if not (poPrintToFile in FOptions) then Inc(Flags, PD_HIDEPRINTTOFILE);
  899.     if not (poPageNums in FOptions) then Inc(Flags, PD_NOPAGENUMS);
  900.     if not (poSelection in FOptions) then Inc(Flags, PD_NOSELECTION);
  901.     if poDisablePrintToFile in FOptions then Inc(Flags, PD_DISABLEPRINTTOFILE);
  902.     if FPrintToFile then Inc(Flags, PD_PRINTTOFILE);
  903.     if poHelp in FOptions then Inc(Flags, PD_SHOWHELP);
  904.     if not (poWarning in FOptions) then Inc(Flags, PD_NOWARNING);
  905.     nFromPage := FFromPage;
  906.     nToPage := FToPage;
  907.     nMinPage := FMinPage;
  908.     nMaxPage := FMaxPage;
  909.     HookCtl3D := Ctl3D;
  910.     lpfnPrintHook := DialogHook;
  911.     lpfnSetupHook := DialogHook;
  912.     hWndOwner := Application.Handle;
  913.     Result := TaskModalDialog(@PrintDlg, PrintDlgRec);
  914.     if Result then
  915.     begin
  916.       SetPrinter(hDevMode, hDevNames);
  917.       FCollate := Flags and PD_COLLATE <> 0;
  918.       FPrintToFile := Flags and PD_PRINTTOFILE <> 0;
  919.       if Flags and PD_SELECTION <> 0 then FPrintRange := prSelection else
  920.         if Flags and PD_PAGENUMS <> 0 then FPrintRange := prPageNums else
  921.           FPrintRange := prAllPages;
  922.       FFromPage := nFromPage;
  923.       FToPage := nToPage;
  924.       if nCopies = 1 then
  925.         Copies := Printer.Copies else
  926.         Copies := nCopies;
  927.     end
  928.     else begin
  929.       if hDevMode <> 0 then GlobalFree(hDevMode);
  930.       if hDevNames <> 0 then GlobalFree(hDevNames);
  931.     end;
  932.   end;
  933. end;
  934.  
  935. { TRedirectorWindow }
  936. { A redirector window is used to put the find/replace dialog into the
  937.   ownership chain of a form, but intercept messages that CommDlg.dll sends
  938.   exclusively to the find/replace dialog's owner.  TRedirectorWindow
  939.   creates its hidden window handle as owned by the target form, and the
  940.   find/replace dialog handle is created as owned by the redirector.  The
  941.   redirector wndproc forwards all messages to the find/replace component.
  942. }
  943.  
  944. type
  945.   TRedirectorWindow = class(TWinControl)
  946.   private
  947.     FFindReplaceDialog: TFindDialog;
  948.     FFormHandle: THandle;
  949.     procedure CMRelease(var Message); message CM_Release;
  950.   protected
  951.     procedure CreateParams(var Params: TCreateParams); override;
  952.     procedure WndProc(var Message: TMessage); override;
  953.   end;
  954.  
  955. procedure TRedirectorWindow.CreateParams(var Params: TCreateParams);
  956. begin
  957.   inherited CreateParams(Params);
  958.   with Params do
  959.   begin
  960.     Style := WS_VISIBLE or WS_POPUP;
  961.     WndParent := FFormHandle;
  962.   end;
  963. end;
  964.  
  965. procedure TRedirectorWindow.WndProc(var Message: TMessage);
  966. begin
  967.   inherited WndProc(Message);
  968.   if (Message.Result = 0) and Assigned(FFindReplaceDialog) then
  969.     Message.Result := Integer(FFindReplaceDialog.Message(Message));
  970. end;
  971.  
  972. procedure TRedirectorWindow.CMRelease(var Message);
  973. begin
  974.   Free;
  975. end;
  976.  
  977. { Find and Replace dialog routines }
  978.  
  979. function FindReplaceWndProc(Wnd: HWND; Msg, WParam, LParam: Longint): Longint; stdcall;
  980.  
  981.   function CallDefWndProc: Longint;
  982.   begin
  983.     Result := CallWindowProc(Pointer(GetProp(Wnd,
  984.       MakeIntAtom(WndProcPtrAtom))), Wnd, Msg, WParam, LParam);
  985.   end;
  986.  
  987. begin
  988.   case Msg of
  989.     WM_DESTROY:
  990.       if Application.DialogHandle = Wnd then Application.DialogHandle := 0;
  991.     WM_NCACTIVATE:
  992.       if WParam <> 0 then
  993.       begin
  994.         if Application.DialogHandle = 0 then Application.DialogHandle := Wnd;
  995.       end else
  996.       begin
  997.         if Application.DialogHandle = Wnd then Application.DialogHandle := 0;
  998.       end;
  999.     WM_NCDESTROY:
  1000.       begin
  1001.         Result := CallDefWndProc;
  1002.         RemoveProp(Wnd, MakeIntAtom(WndProcPtrAtom));
  1003.         Exit;
  1004.       end;
  1005.    end;
  1006.    Result := CallDefWndProc;
  1007. end;
  1008.  
  1009. function FindReplaceDialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  1010. begin
  1011.   Result := DialogHook(Wnd, Msg, wParam, lParam);
  1012.   if Msg = WM_INITDIALOG then
  1013.   begin
  1014.     with TFindDialog(PFindReplace(LParam)^.lCustData) do
  1015.       if (Left <> -1) or (Top <> -1) then
  1016.         SetWindowPos(Wnd, 0, Left, Top, 0, 0, SWP_NOACTIVATE or
  1017.           SWP_NOSIZE or SWP_NOZORDER);
  1018.     SetProp(Wnd, MakeIntAtom(WndProcPtrAtom), GetWindowLong(Wnd, GWL_WNDPROC));
  1019.     SetWindowLong(Wnd, GWL_WNDPROC, Longint(@FindReplaceWndProc));
  1020.     Result := 1;
  1021.   end;
  1022. end;
  1023.  
  1024. const
  1025.   FindOptions: array[TFindOption] of Longint = (
  1026.     FR_DOWN, FR_FINDNEXT, FR_HIDEMATCHCASE, FR_HIDEWHOLEWORD,
  1027.     FR_HIDEUPDOWN, FR_MATCHCASE, FR_NOMATCHCASE, FR_NOUPDOWN, FR_NOWHOLEWORD,
  1028.     FR_REPLACE, FR_REPLACEALL, FR_WHOLEWORD, FR_SHOWHELP);
  1029.  
  1030. { TFindDialog }
  1031.  
  1032. constructor TFindDialog.Create(AOwner: TComponent);
  1033. begin
  1034.   inherited Create(AOwner);
  1035.   FOptions := [frDown];
  1036.   FPosition.X := -1;
  1037.   FPosition.Y := -1;
  1038.   with FFindReplace do
  1039.   begin
  1040.     lStructSize := SizeOf(TFindReplace);
  1041.     hWndOwner := Application.Handle;
  1042.     hInstance := System.HInstance;
  1043.     lpstrFindWhat := FFindText;
  1044.     wFindWhatLen := SizeOf(FFindText);
  1045.     lpstrReplaceWith := FReplaceText;
  1046.     wReplaceWithLen := SizeOf(FReplaceText);
  1047.     lCustData := Longint(Self);
  1048.     lpfnHook := FindReplaceDialogHook;
  1049.   end;
  1050.   FFindReplaceFunc := @CommDlg.FindText;
  1051. end;
  1052.  
  1053. destructor TFindDialog.Destroy;
  1054. begin
  1055.   if FHandle <> 0 then SendMessage(FHandle, WM_CLOSE, 0, 0);
  1056.   FRedirector.Free;
  1057.   inherited Destroy;
  1058. end;
  1059.  
  1060. procedure TFindDialog.CloseDialog;
  1061. begin
  1062.   if FHandle <> 0 then PostMessage(FHandle, WM_CLOSE, 0, 0);
  1063. end;
  1064.  
  1065. function GetTopWindow(Wnd: THandle; var ReturnVar: THandle):Bool; stdcall;
  1066. var
  1067.   Test: TWinControl;
  1068. begin
  1069.   Test := FindControl(Wnd);
  1070.   Result := True;
  1071.   if Assigned(Test) and (Test is TForm) then
  1072.   begin
  1073.     ReturnVar := Wnd;
  1074.     Result := False;
  1075.    end;
  1076. end;
  1077.  
  1078. function TFindDialog.Execute: Boolean;
  1079. var
  1080.   Option: TFindOption;
  1081. begin
  1082.   if FHandle <> 0 then
  1083.   begin
  1084.     BringWindowToTop(FHandle);
  1085.     Result := True;
  1086.   end else
  1087.   begin
  1088.     HookCtl3D := Ctl3D;
  1089.     FFindReplace.Flags := FR_ENABLEHOOK;
  1090.     FFindReplace.lpfnHook := FindReplaceDialogHook;
  1091.     FRedirector := TRedirectorWindow.Create(nil);
  1092.     with TRedirectorWindow(FRedirector) do
  1093.     begin
  1094.       FFindReplaceDialog := Self;
  1095.       EnumThreadWindows(GetCurrentThreadID, @GetTopWindow, LPARAM(@FFormHandle));
  1096.     end;
  1097.     FFindReplace.hWndOwner := FRedirector.Handle;
  1098.     for Option := Low(Option) to High(Option) do
  1099.       if Option in FOptions then
  1100.         FFindReplace.Flags := FFindReplace.Flags or FindOptions[Option];
  1101.     FHandle := FFindReplaceFunc(FFindReplace);
  1102.     Result := FHandle <> 0;
  1103.   end;
  1104. end;
  1105.  
  1106. procedure TFindDialog.Find;
  1107. begin
  1108.   if Assigned(FOnFind) then FOnFind(Self);
  1109. end;
  1110.  
  1111. function TFindDialog.GetFindText: string;
  1112. begin
  1113.   Result := FFindText;
  1114. end;
  1115.  
  1116. function TFindDialog.GetLeft: Integer;
  1117. begin
  1118.   Result := Position.X;
  1119. end;
  1120.  
  1121. function TFindDialog.GetPosition: TPoint;
  1122. var
  1123.   Rect: TRect;
  1124. begin
  1125.   Result := FPosition;
  1126.   if FHandle <> 0 then
  1127.   begin
  1128.     GetWindowRect(FHandle, Rect);
  1129.     Result := Rect.TopLeft;
  1130.   end;
  1131. end;
  1132.  
  1133. function TFindDialog.GetReplaceText: string;
  1134. begin
  1135.   Result := FReplaceText;
  1136. end;
  1137.  
  1138. function TFindDialog.GetTop: Integer;
  1139. begin
  1140.   Result := Position.Y;
  1141. end;
  1142.  
  1143. function TFindDialog.Message(var Msg: TMessage): Boolean;
  1144. var
  1145.   Option: TFindOption;
  1146.   Rect: TRect;
  1147. begin
  1148.   Result := inherited Message(Msg);
  1149.   if not Result then
  1150.     if (Msg.Msg = FindMsg) and (Pointer(Msg.LParam) = @FFindReplace) then
  1151.     begin
  1152.       FOptions := [];
  1153.       for Option := Low(Option) to High(Option) do
  1154.         if (FFindReplace.Flags and FindOptions[Option]) <> 0 then
  1155.           Include(FOptions, Option);
  1156.       if (FFindReplace.Flags and FR_FINDNEXT) <> 0 then
  1157.         Find
  1158.       else
  1159.       if (FFindReplace.Flags and (FR_REPLACE or FR_REPLACEALL)) <> 0 then
  1160.         Replace
  1161.       else
  1162.       if (FFindReplace.Flags and FR_DIALOGTERM) <> 0 then
  1163.       begin
  1164.         GetWindowRect(FHandle, Rect);
  1165.         FPosition := Rect.TopLeft;
  1166.         FHandle := 0;
  1167.         PostMessage(FRedirector.Handle,CM_RELEASE,0,0); // free redirector later
  1168.         FRedirector := nil;
  1169.       end;
  1170.       Result := True;
  1171.     end;
  1172. end;
  1173.  
  1174. procedure TFindDialog.Replace;
  1175. begin
  1176.   if Assigned(FOnReplace) then FOnReplace(Self);
  1177. end;
  1178.  
  1179. procedure TFindDialog.SetFindText(const Value: string);
  1180. begin
  1181.   StrLCopy(FFindText, PChar(Value), SizeOf(FFindText) - 1);
  1182. end;
  1183.  
  1184. procedure TFindDialog.SetLeft(Value: Integer);
  1185. begin
  1186.   SetPosition(Point(Value, Top));
  1187. end;
  1188.  
  1189. procedure TFindDialog.SetPosition(const Value: TPoint);
  1190. begin
  1191.   if (FPosition.X <> Value.X) or (FPosition.Y <> Value.Y) then
  1192.   begin
  1193.     FPosition := Value;
  1194.     if FHandle <> 0 then
  1195.       SetWindowPos(FHandle, 0, Value.X, Value.Y, 0, 0,
  1196.         SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);
  1197.   end;
  1198. end;
  1199.  
  1200. procedure TFindDialog.SetReplaceText(const Value: string);
  1201. begin
  1202.   StrLCopy(FReplaceText, PChar(Value), SizeOf(FReplaceText) - 1);
  1203. end;
  1204.  
  1205. procedure TFindDialog.SetTop(Value: Integer);
  1206. begin
  1207.   SetPosition(Point(Left, Value));
  1208. end;
  1209.  
  1210. { TReplaceDialog }
  1211.  
  1212. constructor TReplaceDialog.Create(AOwner: TComponent);
  1213. begin
  1214.   inherited Create(AOwner);
  1215.   FFindReplaceFunc := CommDlg.ReplaceText;
  1216. end;
  1217.  
  1218. { Message dialog }
  1219.  
  1220. function Max(I, J: Integer): Integer;
  1221. begin
  1222.   if I > J then Result := I else Result := J;
  1223. end;
  1224.  
  1225. function GetAveCharSize(Canvas: TCanvas): TPoint;
  1226. var
  1227.   I: Integer;
  1228.   Buffer: array[0..51] of Char;
  1229. begin
  1230.   for I := 0 to 25 do Buffer[I] := Chr(I + Ord('A'));
  1231.   for I := 0 to 25 do Buffer[I + 26] := Chr(I + Ord('a'));
  1232.   GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result));
  1233.   Result.X := Result.X div 52;
  1234. end;
  1235.  
  1236.  
  1237. type
  1238.   TMessageForm = class(TForm)
  1239.   private
  1240.     procedure HelpButtonClick(Sender: TObject);
  1241.   end;
  1242.  
  1243. procedure TMessageForm.HelpButtonClick(Sender: TObject);
  1244. begin
  1245.   Application.HelpContext(HelpContext);
  1246. end;
  1247.  
  1248.  
  1249. function CreateMessageDialog(const Msg: string; DlgType: TMsgDlgType;
  1250.   Buttons: TMsgDlgButtons): TForm;
  1251. const
  1252.   mcHorzMargin = 8;
  1253.   mcVertMargin = 8;
  1254.   mcHorzSpacing = 10;
  1255.   mcVertSpacing = 10;
  1256.   mcButtonWidth = 50;
  1257.   mcButtonHeight = 14;
  1258.   mcButtonSpacing = 4;
  1259. const
  1260.   Captions: array[TMsgDlgType] of Word = (SMsgDlgWarning, SMsgDlgError,
  1261.     SMsgDlgInformation, SMsgDlgConfirm, 0);
  1262.   IconIDs: array[TMsgDlgType] of PChar = (IDI_EXCLAMATION, IDI_HAND,
  1263.     IDI_ASTERISK, IDI_QUESTION, nil);
  1264.   ButtonNames: array[TMsgDlgBtn] of string = (
  1265.     'Yes', 'No', 'OK', 'Cancel', 'Abort', 'Retry', 'Ignore', 'All', 'Help');
  1266.   ButtonCaptions: array[TMsgDlgBtn] of Word = (
  1267.     SMsgDlgYes, SMsgDlgNo, SMsgDlgOK, SMsgDlgCancel, SMsgDlgAbort,
  1268.     SMsgDlgRetry, SMsgDlgIgnore, SMsgDlgAll, SMsgDlgHelp);
  1269.   ModalResults: array[TMsgDlgBtn] of Integer = (
  1270.     mrYes, mrNo, mrOk, mrCancel, mrAbort, mrRetry, mrIgnore, mrAll, 0);
  1271. var
  1272.   DialogUnits: TPoint;
  1273.   HorzMargin, VertMargin, HorzSpacing, VertSpacing, ButtonWidth,
  1274.   ButtonHeight, ButtonSpacing, ButtonCount, ButtonGroupWidth,
  1275.   IconTextWidth, IconTextHeight, X: Integer;
  1276.   B, DefaultButton, CancelButton: TMsgDlgBtn;
  1277.   IconID: PChar;
  1278.   TextRect: TRect;
  1279. begin
  1280.   Result := TMessageForm.CreateNew(Application);
  1281.   with Result do
  1282.   begin
  1283.     BorderStyle := bsDialog;
  1284.     Canvas.Font := Font;
  1285.     DialogUnits := GetAveCharSize(Canvas);
  1286.     HorzMargin := MulDiv(mcHorzMargin, DialogUnits.X, 4);
  1287.     VertMargin := MulDiv(mcVertMargin, DialogUnits.Y, 8);
  1288.     HorzSpacing := MulDiv(mcHorzSpacing, DialogUnits.X, 4);
  1289.     VertSpacing := MulDiv(mcVertSpacing, DialogUnits.Y, 8);
  1290.     ButtonWidth := MulDiv(mcButtonWidth, DialogUnits.X, 4);
  1291.     ButtonHeight := MulDiv(mcButtonHeight, DialogUnits.Y, 8);
  1292.     ButtonSpacing := MulDiv(mcButtonSpacing, DialogUnits.X, 4);
  1293.     SetRect(TextRect, 0, 0, Screen.Width div 2, 0);
  1294.     DrawText(Canvas.Handle, PChar(Msg), -1, TextRect,
  1295.       DT_CALCRECT or DT_WORDBREAK);
  1296.     IconID := IconIDs[DlgType];
  1297.     IconTextWidth := TextRect.Right;
  1298.     IconTextHeight := TextRect.Bottom;
  1299.     if IconID <> nil then
  1300.     begin
  1301.       Inc(IconTextWidth, 32 + HorzSpacing);
  1302.       if IconTextHeight < 32 then IconTextHeight := 32;
  1303.     end;
  1304.     ButtonCount := 0;
  1305.     for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
  1306.       if B in Buttons then Inc(ButtonCount);
  1307.     ButtonGroupWidth := 0;
  1308.     if ButtonCount <> 0 then
  1309.       ButtonGroupWidth := ButtonWidth * ButtonCount +
  1310.         ButtonSpacing * (ButtonCount - 1);
  1311.     ClientWidth := Max(IconTextWidth, ButtonGroupWidth) + HorzMargin * 2;
  1312.     ClientHeight := IconTextHeight + ButtonHeight + VertSpacing +
  1313.       VertMargin * 2;
  1314.     Left := (Screen.Width div 2) - (Width div 2);
  1315.     Top := (Screen.Height div 2) - (Height div 2);
  1316.     if DlgType <> mtCustom then
  1317.       Caption := LoadStr(Captions[DlgType]) else
  1318.       Caption := Application.Title;
  1319.     if IconID <> nil then
  1320.       with TImage.Create(Result) do
  1321.       begin
  1322.         Name := 'Image';
  1323.         Parent := Result;
  1324.         Picture.Icon.Handle := LoadIcon(0, IconID);
  1325.         SetBounds(HorzMargin, VertMargin, 32, 32);
  1326.       end;
  1327.     with TLabel.Create(Result) do
  1328.     begin
  1329.       Name := 'Message';
  1330.       Parent := Result;
  1331.       WordWrap := True;
  1332.       Caption := Msg;
  1333.       BoundsRect := TextRect;
  1334.       SetBounds(IconTextWidth - TextRect.Right + HorzMargin, VertMargin,
  1335.         TextRect.Right, TextRect.Bottom);
  1336.     end;
  1337.     if mbOk in Buttons then DefaultButton := mbOk else
  1338.       if mbYes in Buttons then DefaultButton := mbYes else
  1339.         DefaultButton := mbRetry;
  1340.     if mbCancel in Buttons then CancelButton := mbCancel else
  1341.       if mbNo in Buttons then CancelButton := mbNo else
  1342.         CancelButton := mbOk;
  1343.     X := (ClientWidth - ButtonGroupWidth) div 2;
  1344.     for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
  1345.       if B in Buttons then
  1346.         with TButton.Create(Result) do
  1347.         begin
  1348.           Name := ButtonNames[B];
  1349.           Parent := Result;
  1350.           Caption := LoadStr(ButtonCaptions[B]);
  1351.           ModalResult := ModalResults[B];
  1352.           if B = DefaultButton then Default := True;
  1353.           if B = CancelButton then Cancel := True;
  1354.           SetBounds(X, IconTextHeight + VertMargin + VertSpacing,
  1355.             ButtonWidth, ButtonHeight);
  1356.           Inc(X, ButtonWidth + ButtonSpacing);
  1357.           if B = mbHelp then
  1358.             OnClick := TMessageForm(Result).HelpButtonClick;
  1359.         end;
  1360.   end;
  1361. end;
  1362.  
  1363. function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
  1364.   Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
  1365. begin
  1366.   Result := MessageDlgPos(Msg, DlgType, Buttons, HelpCtx, -1, -1);
  1367. end;
  1368.  
  1369. function MessageDlgPos(const Msg: string; DlgType: TMsgDlgType;
  1370.   Buttons: TMsgDlgButtons; HelpCtx: Longint; X, Y: Integer): Integer;
  1371. begin
  1372.   with CreateMessageDialog(Msg, DlgType, Buttons) do
  1373.     try
  1374.       HelpContext := HelpCtx;
  1375.       if X >= 0 then Left := X;
  1376.       if Y >= 0 then Top := Y;
  1377.       Result := ShowModal;
  1378.     finally
  1379.       Free;
  1380.     end;
  1381. end;
  1382.  
  1383. procedure ShowMessage(const Msg: string);
  1384. begin
  1385.   ShowMessagePos(Msg, -1, -1);
  1386. end;
  1387.  
  1388. procedure ShowMessagePos(const Msg: string; X, Y: Integer);
  1389. begin
  1390.   MessageDlgPos(Msg, mtCustom, [mbOK], 0, X, Y);
  1391. end;
  1392.  
  1393. { Input dialog }
  1394.  
  1395. function InputQuery(const ACaption, APrompt: string;
  1396.   var Value: string): Boolean;
  1397. var
  1398.   Form: TForm;
  1399.   Prompt: TLabel;
  1400.   Edit: TEdit;
  1401.   DialogUnits: TPoint;
  1402.   ButtonTop, ButtonWidth, ButtonHeight: Integer;
  1403. begin
  1404.   Result := False;
  1405.   Form := TForm.Create(Application);
  1406.   with Form do
  1407.     try
  1408.       Canvas.Font := Font;
  1409.       DialogUnits := GetAveCharSize(Canvas);
  1410.       BorderStyle := bsDialog;
  1411.       Caption := ACaption;
  1412.       ClientWidth := MulDiv(180, DialogUnits.X, 4);
  1413.       ClientHeight := MulDiv(63, DialogUnits.Y, 8);
  1414.       Position := poScreenCenter;
  1415.       Prompt := TLabel.Create(Form);
  1416.       with Prompt do
  1417.       begin
  1418.         Parent := Form;
  1419.         AutoSize := True;
  1420.         Left := MulDiv(8, DialogUnits.X, 4);
  1421.         Top := MulDiv(8, DialogUnits.Y, 8);
  1422.         Caption := APrompt;
  1423.       end;
  1424.       Edit := TEdit.Create(Form);
  1425.       with Edit do
  1426.       begin
  1427.         Parent := Form;
  1428.         Left := Prompt.Left;
  1429.         Top := MulDiv(19, DialogUnits.Y, 8);
  1430.         Width := MulDiv(164, DialogUnits.X, 4);
  1431.         MaxLength := 255;
  1432.         Text := Value;
  1433.         SelectAll;
  1434.       end;
  1435.       ButtonTop := MulDiv(41, DialogUnits.Y, 8);
  1436.       ButtonWidth := MulDiv(50, DialogUnits.X, 4);
  1437.       ButtonHeight := MulDiv(14, DialogUnits.Y, 8);
  1438.       with TButton.Create(Form) do
  1439.       begin
  1440.         Parent := Form;
  1441.         Caption := LoadStr(SMsgDlgOK);
  1442.         ModalResult := mrOk;
  1443.         Default := True;
  1444.         SetBounds(MulDiv(38, DialogUnits.X, 4), ButtonTop, ButtonWidth,
  1445.           ButtonHeight);
  1446.       end;
  1447.       with TButton.Create(Form) do
  1448.       begin
  1449.         Parent := Form;
  1450.         Caption := LoadStr(SMsgDlgCancel);
  1451.         ModalResult := mrCancel;
  1452.         Cancel := True;
  1453.         SetBounds(MulDiv(92, DialogUnits.X, 4), ButtonTop, ButtonWidth,
  1454.           ButtonHeight);
  1455.       end;
  1456.       if ShowModal = mrOk then
  1457.       begin
  1458.         Value := Edit.Text;
  1459.         Result := True;
  1460.       end;
  1461.     finally
  1462.       Form.Free;
  1463.     end;
  1464. end;
  1465.  
  1466. function InputBox(const ACaption, APrompt, ADefault: string): string;
  1467. begin
  1468.   Result := ADefault;
  1469.   InputQuery(ACaption, APrompt, Result);
  1470. end;
  1471.  
  1472. { Initialization and cleanup }
  1473.  
  1474. procedure InitGlobals;
  1475. var
  1476.   AtomText: array[0..31] of Char;
  1477. begin
  1478.   HelpMsg := RegisterWindowMessage(HelpMsgString);
  1479.   FindMsg := RegisterWindowMessage(FindMsgString);
  1480.   WndProcPtrAtom := GlobalAddAtom(StrFmt(AtomText,
  1481.     'WndProcPtr%.8X%.8X', [HInstance, GetCurrentThreadID]));
  1482. end;
  1483.  
  1484. initialization
  1485.   InitGlobals;
  1486. finalization
  1487.   if WndProcPtrAtom <> 0 then GlobalDeleteAtom(WndProcPtrAtom);
  1488. end.
  1489.