home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kolekce / d6 / rxlibsetup.exe / {app} / units / FileUtil.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-02-19  |  36.9 KB  |  1,237 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 2001,2002 SGB Software          }
  6. {         Copyright (c) 1997, 1998 Fedor Koshevnikov,   }
  7. {                        Igor Pavluk and Serge Korolev  }
  8. {         Copyright (c) 1998 Ritting Information Systems}
  9. {                                                       }
  10. {*******************************************************}
  11.  
  12. unit FileUtil;
  13.  
  14. {$I RX.INC}
  15. {$I-,R-}
  16.  
  17. interface
  18.  
  19. uses Windows, RTLConsts, Messages, SysUtils, Classes, Consts, Controls;
  20.  
  21. procedure CopyFile(const FileName, DestName: string;
  22.   ProgressControl: TControl);
  23. procedure CopyFileEx(const FileName, DestName: string;
  24.   OverwriteReadOnly, ShellDialog: Boolean; ProgressControl: TControl);
  25. procedure MoveFile(const FileName, DestName: TFileName);
  26. procedure MoveFileEx(const FileName, DestName: TFileName; ShellDialog: Boolean);
  27. {$IFDEF RX_D4}
  28. function GetFileSize(const FileName: string): Int64;
  29. {$ELSE}
  30. function GetFileSize(const FileName: string): Longint;
  31. {$ENDIF}
  32. function FileDateTime(const FileName: string): TDateTime;
  33. function HasAttr(const FileName: string; Attr: Integer): Boolean;
  34. function DeleteFiles(const FileMask: string): Boolean;
  35. function DeleteFilesEx(const FileMasks: array of string): Boolean;
  36. function ClearDir(const Path: string; Delete: Boolean): Boolean;
  37. function NormalDir(const DirName: string): string;
  38. function RemoveBackSlash(const DirName: string): string;
  39. function ValidFileName(const FileName: string): Boolean;
  40. function DirExists(Name: string): Boolean;
  41. procedure ForceDirectories(Dir: string);
  42.  
  43. function FileLock(Handle: Integer; Offset, LockSize: Longint): Integer;
  44.   {$IFDEF RX_D4} overload; {$ENDIF}
  45. {$IFDEF RX_D4}
  46. function FileLock(Handle: Integer; Offset, LockSize: Int64): Integer; overload;
  47. {$ENDIF}
  48. function FileUnlock(Handle: Integer; Offset, LockSize: Longint): Integer;
  49.   {$IFDEF RX_D4} overload; {$ENDIF}
  50. {$IFDEF RX_D4}
  51. function FileUnlock(Handle: Integer; Offset, LockSize: Int64): Integer; overload;
  52. {$ENDIF}
  53.  
  54. function GetTempDir: string;
  55. function GetWindowsDir: string;
  56. function GetSystemDir: string;
  57.  
  58. function BrowseDirectory(var AFolderName: string; const DlgText: string;
  59.   AHelpContext: THelpContext): Boolean;
  60.  
  61. {$IFDEF WIN32}
  62. function BrowseComputer(var ComputerName: string; const DlgText: string;
  63.   AHelpContext: THelpContext): Boolean;
  64.  
  65. function ShortToLongFileName(const ShortName: string): string;
  66. function ShortToLongPath(const ShortName: string): string;
  67. function LongToShortFileName(const LongName: string): string;
  68. function LongToShortPath(const LongName: string): string;
  69.  
  70. procedure CreateFileLink(const FileName, DisplayName: string; Folder: Integer);
  71. procedure DeleteFileLink(const DisplayName: string; Folder: Integer);
  72. {$ENDIF WIN32}
  73.  
  74. {$IFNDEF RX_D3}
  75. function IsPathDelimiter(const S: string; Index: Integer): Boolean;
  76. {$ENDIF}
  77.  
  78. implementation
  79.  
  80. uses {$IFDEF WIN32} {$IFDEF RX_D3} ActiveX, ComObj, ShlObj, {$ELSE} Ole2,
  81.   OleAuto, {$ENDIF} {$ENDIF} DateUtil, ShellAPI, FileCtrl, Forms, VCLUtils,
  82.   RxPrgrss;
  83.  
  84. {$IFDEF WIN32}
  85.  
  86. {$IFNDEF RX_D3}
  87.  
  88. type
  89.  
  90. { TSHItemID -- Item ID }
  91.  
  92.   PSHItemID = ^TSHItemID;
  93.   TSHItemID = packed record           { mkid }
  94.     cb: Word;                         { Size of the ID (including cb itself) }
  95.     abID: array[0..0] of Byte;        { The item ID (variable length) }
  96.   end;
  97.  
  98. { TItemIDList -- List if item IDs (combined with 0-terminator) }
  99.  
  100.   PItemIDList = ^TItemIDList;
  101.   TItemIDList = packed record         { idl }
  102.      mkid: TSHItemID;
  103.    end;
  104.  
  105.   TFNBFFCallBack = function(Wnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer stdcall;
  106.  
  107.   PBrowseInfo = ^TBrowseInfo;
  108.   TBrowseInfo = packed record
  109.     hwndOwner: HWND;
  110.     pidlRoot: PItemIDList;
  111.     pszDisplayName: LPSTR;  { Return display name of item selected. }
  112.     lpszTitle: LPCSTR;      { text to go in the banner over the tree. }
  113.     ulFlags: UINT;          { Flags that control the return stuff }
  114.     lpfn: TFNBFFCallBack;
  115.     lParam: LPARAM;         { extra info that's passed back in callbacks }
  116.     iImage: Integer;        { output var: where to return the Image index. }
  117.   end;
  118.  
  119. const
  120.  
  121. { Browsing for directory }
  122.  
  123.   BIF_RETURNONLYFSDIRS   = $0001; { For finding a folder to start document searching }
  124.   BIF_DONTGOBELOWDOMAIN  = $0002; { For starting the Find Computer }
  125.   BIF_STATUSTEXT         = $0004;
  126.   BIF_RETURNFSANCESTORS  = $0008;
  127.  
  128.   BIF_BROWSEFORCOMPUTER  = $1000; { Browsing for Computers }
  129.   BIF_BROWSEFORPRINTER   = $2000; { Browsing for Printers }
  130.   BIF_BROWSEINCLUDEFILES = $4000; { Browsing for Everything }
  131.  
  132. { message from browser }
  133.  
  134.   BFFM_INITIALIZED       = 1;
  135.   BFFM_SELCHANGED        = 2;
  136.  
  137. { messages to browser }
  138.  
  139.   BFFM_SETSTATUSTEXT      = (WM_USER + 100);
  140.   BFFM_ENABLEOK           = (WM_USER + 101);
  141.   BFFM_SETSELECTION       = (WM_USER + 102);
  142.  
  143. const
  144.   CSIDL_DRIVES             = $0011;
  145.   CSIDL_NETWORK            = $0012;
  146.  
  147. function SHBrowseForFolder(var lpbi: TBrowseInfo): PItemIDList; stdcall;
  148.   far; external Shell32 name 'SHBrowseForFolder';
  149. function SHGetPathFromIDList(pidl: PItemIDList; pszPath: LPSTR): BOOL; stdcall;
  150.   far; external Shell32 name 'SHGetPathFromIDList';
  151. function SHGetSpecialFolderLocation(hwndOwner: HWND; nFolder: Integer;
  152.   var ppidl: PItemIDList): HResult; stdcall; far; external Shell32
  153.   name 'SHGetSpecialFolderLocation';
  154.  
  155. {$ENDIF RX_D3}
  156.  
  157. { TBrowseFolderDlg }
  158.  
  159. type
  160.   TBrowseKind = (bfFolders, bfComputers);
  161.   TDialogPosition = (dpDefault, dpScreenCenter);
  162.  
  163.   TBrowseFolderDlg = class(TComponent)
  164.   private
  165.     FDefWndProc: Pointer;
  166.     FHelpContext: THelpContext;
  167.     FHandle: HWnd;
  168.     FObjectInstance: Pointer;
  169.     FDesktopRoot: Boolean;
  170.     FBrowseKind: TBrowseKind;
  171.     FPosition: TDialogPosition;
  172.     FText: string;
  173.     FDisplayName: string;
  174.     FSelectedName: string;
  175.     FFolderName: string;
  176.     FImageIndex: Integer;
  177.     FOnInitialized: TNotifyEvent;
  178.     FOnSelChanged: TNotifyEvent;
  179.     procedure SetSelPath(const Path: string);
  180.     procedure SetOkEnable(Value: Boolean);
  181.     procedure DoInitialized;
  182.     procedure DoSelChanged(Param: PItemIDList);
  183.     procedure WMNCDestroy(var Message: TWMNCDestroy); message WM_NCDESTROY;
  184.     procedure WMCommand(var Message: TMessage); message WM_COMMAND;
  185.   protected
  186.     procedure DefaultHandler(var Message); override;
  187.     procedure WndProc(var Message: TMessage); virtual;
  188.     function TaskModalDialog(var Info: TBrowseInfo): PItemIDList;
  189.   public
  190.     constructor Create(AOwner: TComponent); override;
  191.     destructor Destroy; override;
  192.     function Execute: Boolean;
  193.     property Handle: HWnd read FHandle;
  194.     property DisplayName: string read FDisplayName;
  195.     property SelectedName: string read FSelectedName write FSelectedName;
  196.     property ImageIndex: Integer read FImageIndex;
  197.   published
  198.     property BrowseKind: TBrowseKind read FBrowseKind write FBrowseKind default bfFolders;
  199.     property DesktopRoot: Boolean read FDesktopRoot write FDesktopRoot default True;
  200.     property DialogText: string read FText write FText;
  201.     property FolderName: string read FFolderName write FFolderName;
  202.     property HelpContext: THelpContext read FHelpContext write FHelpContext default 0;
  203.     property Position: TDialogPosition read FPosition write FPosition default dpScreenCenter;
  204.     property OnInitialized: TNotifyEvent read FOnInitialized write FOnInitialized;
  205.     property OnSelChanged: TNotifyEvent read FOnSelChanged write FOnSelChanged;
  206.   end;
  207.  
  208. function ExplorerHook(Wnd: HWnd; Msg: UINT; LParam: LPARAM; Data: LPARAM): Integer; stdcall;
  209. begin
  210.   Result := 0;
  211.   if Msg = BFFM_INITIALIZED then begin
  212.     if TBrowseFolderDlg(Data).Position = dpScreenCenter then
  213.       CenterWindow(Wnd);
  214.     TBrowseFolderDlg(Data).FHandle := Wnd;
  215.     TBrowseFolderDlg(Data).FDefWndProc := Pointer(SetWindowLong(Wnd, GWL_WNDPROC,
  216.       Longint(TBrowseFolderDlg(Data).FObjectInstance)));
  217.     TBrowseFolderDlg(Data).DoInitialized;
  218.   end
  219.   else if Msg = BFFM_SELCHANGED then begin
  220.     TBrowseFolderDlg(Data).FHandle := Wnd;
  221.     TBrowseFolderDlg(Data).DoSelChanged(PItemIDList(LParam));
  222.   end;
  223. end;
  224.  
  225. const
  226.   HelpButtonId = $FFFF;
  227.  
  228. constructor TBrowseFolderDlg.Create(AOwner: TComponent);
  229. begin
  230.   inherited Create(AOwner);
  231.   FObjectInstance := Classes.MakeObjectInstance(WndProc);
  232.   FDesktopRoot := True;
  233.   FBrowseKind := bfFolders;
  234.   FPosition := dpScreenCenter;
  235.   SetLength(FDisplayName, MAX_PATH);
  236. end;
  237.  
  238. destructor TBrowseFolderDlg.Destroy;
  239. begin
  240.   if FObjectInstance <> nil then Classes.FreeObjectInstance(FObjectInstance);
  241.   inherited Destroy;
  242. end;
  243.  
  244. procedure TBrowseFolderDlg.DoInitialized;
  245. const
  246.   SBtn = 'BUTTON';
  247. var
  248.   BtnHandle, HelpBtn, BtnFont: THandle;
  249.   BtnSize: TRect;
  250. begin
  251.   if (FBrowseKind = bfComputers) or DirExists(FFolderName) then
  252.     SetSelPath(FFolderName);
  253.   if FHelpContext <> 0 then begin
  254.     BtnHandle := FindWindowEx(FHandle, 0, SBtn, nil);
  255.     if (BtnHandle <> 0) then begin
  256.       GetWindowRect(BtnHandle, BtnSize);
  257.       ScreenToClient(FHandle, BtnSize.TopLeft);
  258.       ScreenToClient(FHandle, BtnSize.BottomRight);
  259.       BtnFont := SendMessage(FHandle, WM_GETFONT, 0, 0);
  260.       HelpBtn := CreateWindow(SBtn, PChar(ResStr(SHelpButton)),
  261.         WS_CHILD or WS_CLIPSIBLINGS or WS_VISIBLE or BS_PUSHBUTTON or WS_TABSTOP,
  262.         12, BtnSize.Top, BtnSize.Right - BtnSize.Left, BtnSize.Bottom - BtnSize.Top,
  263.         FHandle, HelpButtonId, HInstance, nil);
  264.       if BtnFont <> 0 then
  265.         SendMessage(HelpBtn, WM_SETFONT, BtnFont, MakeLParam(1, 0));
  266.       UpdateWindow(FHandle);
  267.     end;
  268.   end;
  269.   if Assigned(FOnInitialized) then FOnInitialized(Self);
  270. end;
  271.  
  272. procedure TBrowseFolderDlg.DoSelChanged(Param: PItemIDList);
  273. var
  274.   Temp: array[0..MAX_PATH] of Char;
  275. begin
  276.   if (FBrowseKind = bfComputers) then begin
  277.     FSelectedName := DisplayName;
  278.   end
  279.   else begin
  280.     if SHGetPathFromIDList(Param, Temp) then begin
  281.       FSelectedName := StrPas(Temp);
  282.       SetOkEnable(DirExists(FSelectedName));
  283.     end
  284.     else begin
  285.       FSelectedName := '';
  286.       SetOkEnable(False);
  287.     end;
  288.   end;
  289.   if Assigned(FOnSelChanged) then FOnSelChanged(Self);
  290. end;
  291.  
  292. procedure TBrowseFolderDlg.SetSelPath(const Path: string);
  293. begin
  294.   if FHandle <> 0 then
  295.     SendMessage(FHandle, BFFM_SETSELECTION, 1, Longint(PChar(Path)));
  296. end;
  297.  
  298. procedure TBrowseFolderDlg.SetOkEnable(Value: Boolean);
  299. begin
  300.   if FHandle <> 0 then SendMessage(FHandle, BFFM_ENABLEOK, 0, Ord(Value));
  301. end;
  302.  
  303. procedure TBrowseFolderDlg.DefaultHandler(var Message);
  304. begin
  305.   if FHandle <> 0 then
  306.     with TMessage(Message) do
  307.       Result := CallWindowProc(FDefWndProc, FHandle, Msg, WParam, LParam)
  308.   else inherited DefaultHandler(Message);
  309. end;
  310.  
  311. procedure TBrowseFolderDlg.WndProc(var Message: TMessage);
  312. begin
  313.   Dispatch(Message);
  314. end;
  315.  
  316. procedure TBrowseFolderDlg.WMCommand(var Message: TMessage);
  317. begin
  318.   if (Message.wParam = HelpButtonId) and (LongRec(Message.lParam).Hi =
  319.     BN_CLICKED) and (FHelpContext <> 0) then
  320.   begin
  321.     Application.HelpContext(FHelpContext);
  322.   end
  323.   else inherited;
  324. end;
  325.  
  326. procedure TBrowseFolderDlg.WMNCDestroy(var Message: TWMNCDestroy);
  327. begin
  328.   inherited;
  329.   FHandle := 0;
  330. end;
  331.  
  332. function TBrowseFolderDlg.Execute: Boolean;
  333. var
  334.   BrowseInfo: TBrowseInfo;
  335.   ItemIDList: PItemIDList;
  336.   Temp: array[0..MAX_PATH] of Char;
  337. begin
  338.   if FDesktopRoot and (FBrowseKind = bfFolders) then
  339.     BrowseInfo.pidlRoot := nil
  340.   else begin
  341.     if FBrowseKind = bfComputers then { root - Network }
  342.       OleCheck(SHGetSpecialFolderLocation(0, CSIDL_NETWORK,
  343.         BrowseInfo.pidlRoot))
  344.     else { root - MyComputer }
  345.       OleCheck(SHGetSpecialFolderLocation(0, CSIDL_DRIVES,
  346.         BrowseInfo.pidlRoot));
  347.   end;
  348.   try
  349.     SetLength(FDisplayName, MAX_PATH);
  350.     with BrowseInfo do begin
  351.       pszDisplayName := PChar(DisplayName);
  352.       if DialogText <> '' then lpszTitle := PChar(DialogText)
  353.       else lpszTitle := nil;
  354.       if FBrowseKind = bfComputers then
  355.         ulFlags := BIF_BROWSEFORCOMPUTER
  356.       else
  357.         ulFlags := BIF_RETURNONLYFSDIRS or BIF_RETURNFSANCESTORS;
  358.       lpfn := ExplorerHook;
  359.       lParam := Longint(Self);
  360.       hWndOwner := Application.Handle;
  361.       iImage := 0;
  362.     end;
  363.     ItemIDList := TaskModalDialog(BrowseInfo);
  364.     Result := ItemIDList <> nil;
  365.     if Result then
  366.     try
  367.       if FBrowseKind = bfFolders then begin
  368.         Win32Check(SHGetPathFromIDList(ItemIDList, Temp));
  369.         FFolderName := RemoveBackSlash(StrPas(Temp));
  370.       end
  371.       else begin
  372.         FFolderName := DisplayName;
  373.       end;
  374.       FSelectedName := FFolderName;
  375.       FImageIndex := BrowseInfo.iImage;
  376.     finally
  377.       CoTaskMemFree(ItemIDList);
  378.     end;
  379.   finally
  380.     if BrowseInfo.pidlRoot <> nil then CoTaskMemFree(BrowseInfo.pidlRoot);
  381.   end;
  382. end;
  383.  
  384. function TBrowseFolderDlg.TaskModalDialog(var Info: TBrowseInfo): PItemIDList;
  385. var
  386.   ActiveWindow: HWnd;
  387.   WindowList: Pointer;
  388. begin
  389.   ActiveWindow := GetActiveWindow;
  390.   WindowList := DisableTaskWindows(0);
  391.   try
  392.     try
  393.       Result := SHBrowseForFolder(Info);
  394.     finally
  395.       FHandle := 0;
  396.       FDefWndProc := nil;
  397.     end;
  398.   finally
  399.     EnableTaskWindows(WindowList);
  400.     SetActiveWindow(ActiveWindow);
  401.   end;
  402. end;
  403.  
  404. function BrowseDirectory(var AFolderName: string; const DlgText: string;
  405.   AHelpContext: THelpContext): Boolean;
  406. begin
  407.   if NewStyleControls then begin
  408.     with TBrowseFolderDlg.Create(Application) do
  409.     try
  410.       DialogText := DlgText;
  411.       FolderName := AFolderName;
  412.       HelpContext := AHelpContext;
  413.       Result := Execute;
  414.       if Result then AFolderName := FolderName;
  415.     finally
  416.       Free;
  417.     end;
  418.   end
  419.   else Result := SelectDirectory(AFolderName, [], AHelpContext);
  420. end;
  421.  
  422. function BrowseComputer(var ComputerName: string; const DlgText: string;
  423.   AHelpContext: THelpContext): Boolean;
  424. begin
  425.   with TBrowseFolderDlg.Create(Application) do
  426.   try
  427.     BrowseKind := bfComputers;
  428.     DialogText := DlgText;
  429.     FolderName := ComputerName;
  430.     HelpContext := AHelpContext;
  431.     Result := Execute;
  432.     if Result then ComputerName := FolderName;
  433.   finally
  434.     Free;
  435.   end;
  436. end;
  437.  
  438. { TRxFileOperator }
  439.  
  440. type
  441.   TFileOperation = (foCopy, foDelete, foMove, foRename);
  442.   TFileOperFlag = (flAllowUndo, flConfirmMouse, flFilesOnly, flMultiDest,
  443.     flNoConfirmation, flNoConfirmMkDir, flRenameOnCollision, flSilent,
  444.     flSimpleProgress, flNoErrorUI);
  445.   TFileOperFlags = set of TFileOperFlag;
  446.  
  447.   TRxFileOperator = class(TComponent)
  448.   private
  449.     FAborted: Boolean;
  450.     FOperation: TFileOperation;
  451.     FOptions: TFileOperFlags;
  452.     FProgressTitle: string;
  453.     FSource: string;
  454.     FDestination: string;
  455.     function TaskModalDialog(DialogFunc: Pointer; var DialogData): Boolean;
  456.   public
  457.     constructor Create(AOwner: TComponent); override;
  458.     function Execute: Boolean; virtual;
  459.     property Aborted: Boolean read FAborted;
  460.   published
  461.     property Destination: string read FDestination write FDestination;
  462.     property Operation: TFileOperation read FOperation write FOperation
  463.       default foCopy;
  464.     property Options: TFileOperFlags read FOptions write FOptions
  465.       default [flAllowUndo, flNoConfirmMkDir];
  466.     property ProgressTitle: string read FProgressTitle write FProgressTitle;
  467.     property Source: string read FSource write FSource;
  468.   end;
  469.  
  470. {$IFNDEF RX_D3}
  471. const
  472.   FOF_NOERRORUI = $0400;
  473. {$ENDIF}
  474.  
  475. constructor TRxFileOperator.Create(AOwner: TComponent);
  476. begin
  477.   inherited Create(AOwner);
  478.   FOptions := [flAllowUndo, flNoConfirmMkDir];
  479. end;
  480.  
  481. function TRxFileOperator.TaskModalDialog(DialogFunc: Pointer; var DialogData): Boolean;
  482. type
  483.   TDialogFunc = function(var DialogData): Integer stdcall;
  484. var
  485.   ActiveWindow: HWnd;
  486.   WindowList: Pointer;
  487. begin
  488.   ActiveWindow := GetActiveWindow;
  489.   WindowList := DisableTaskWindows(0);
  490.   try
  491.     Result := TDialogFunc(DialogFunc)(DialogData) = 0;
  492.   finally
  493.     EnableTaskWindows(WindowList);
  494.     SetActiveWindow(ActiveWindow);
  495.   end;
  496. end;
  497.  
  498. function TRxFileOperator.Execute: Boolean;
  499. const
  500.   OperTypes: array[TFileOperation] of UINT = (
  501.     FO_COPY, FO_DELETE, FO_MOVE, FO_RENAME);
  502.   OperOptions: array[TFileOperFlag] of FILEOP_FLAGS = (
  503.     FOF_ALLOWUNDO, FOF_CONFIRMMOUSE, FOF_FILESONLY, FOF_MULTIDESTFILES,
  504.     FOF_NOCONFIRMATION, FOF_NOCONFIRMMKDIR, FOF_RENAMEONCOLLISION,
  505.     FOF_SILENT, FOF_SIMPLEPROGRESS, FOF_NOERRORUI);
  506. var
  507.   OpStruct: TSHFileOpStruct;
  508.   Flag: TFileOperFlag;
  509.  
  510.   function AllocFileStr(const S: string): PChar;
  511.   var
  512.     P: PChar;
  513.   begin
  514.     Result := nil;
  515.     if S <> '' then begin
  516.       Result := StrCopy(StrAlloc(Length(S) + 2), PChar(S));
  517.       P := Result;
  518.       while P^ <> #0 do begin
  519.         if (P^ = ';') or (P^ = '|') then P^ := #0;
  520.         Inc(P);
  521.       end;
  522.       Inc(P);
  523.       P^ := #0;
  524.     end;
  525.   end;
  526.  
  527. begin
  528.   FAborted := False;
  529.   FillChar(OpStruct, SizeOf(OpStruct), 0);
  530.   with OpStruct do
  531.   try
  532.     if (Application.MainForm <> nil) and
  533.       Application.MainForm.HandleAllocated then
  534.       Wnd := Application.MainForm.Handle
  535.     else Wnd := Application.Handle;
  536.     wFunc := OperTypes[Operation];
  537.     pFrom := AllocFileStr(FSource);
  538.     pTo := AllocFileStr(FDestination);
  539.     fFlags := 0;
  540.     for Flag := Low(Flag) to High(Flag) do
  541.       if Flag in FOptions then fFlags := fFlags or OperOptions[Flag];
  542.     lpszProgressTitle := PChar(FProgressTitle);
  543.     Result := TaskModalDialog(@SHFileOperation, OpStruct);
  544.     FAborted := fAnyOperationsAborted;
  545.   finally
  546.     if pFrom <> nil then StrDispose(pFrom);
  547.     if pTo <> nil then StrDispose(pTo);
  548.   end;
  549. end;
  550.  
  551. {$ELSE}
  552.  
  553. function BrowseDirectory(var AFolderName: string; const DlgText: string;
  554.   AHelpContext: THelpContext): Boolean;
  555. begin
  556.   Result := SelectDirectory(AFolderName, [], AHelpContext);
  557. end;
  558.  
  559. {$ENDIF WIN32}
  560.  
  561. function NormalDir(const DirName: string): string;
  562. begin
  563.   Result := DirName;
  564.   if (Result <> '') and
  565. {$IFDEF RX_D3}
  566.     not (AnsiLastChar(Result)^ in [':', '\']) then
  567. {$ELSE}
  568.     not (Result[Length(Result)] in [':', '\']) then
  569. {$ENDIF}
  570.   begin
  571.     if (Length(Result) = 1) and (UpCase(Result[1]) in ['A'..'Z']) then
  572.       Result := Result + ':\'
  573.     else Result := Result + '\';
  574.   end;
  575. end;
  576.  
  577. function RemoveBackSlash(const DirName: string): string;
  578. begin
  579.   Result := DirName;
  580.   if (Length(Result) > 1) and
  581. {$IFDEF RX_D3}
  582.     (AnsiLastChar(Result)^ = '\') then
  583. {$ELSE}
  584.     (Result[Length(Result)] = '\') then
  585. {$ENDIF}
  586.   begin
  587.     if not ((Length(Result) = 3) and (UpCase(Result[1]) in ['A'..'Z']) and
  588.       (Result[2] = ':')) then
  589.       Delete(Result, Length(Result), 1);
  590.   end;
  591. end;
  592.  
  593. function DirExists(Name: string): Boolean;
  594. {$IFDEF WIN32}
  595. var
  596.   Code: Integer;
  597. begin
  598.   Code := GetFileAttributes(PChar(Name));
  599.   Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
  600. end;
  601. {$ELSE}
  602. var
  603.   SR: TSearchRec;
  604. begin
  605.   if Name[Length(Name)] = '\' then Dec(Name[0]);
  606.   if (Length(Name) = 2) and (Name[2] = ':') then
  607.     Name := Name + '\*.*';
  608.   Result := FindFirst(Name, faDirectory, SR) = 0;
  609.   Result := Result and (SR.Attr and faDirectory <> 0);
  610. end;
  611. {$ENDIF}
  612.  
  613. procedure ForceDirectories(Dir: string);
  614. begin
  615.   if Length(Dir) = 0 then Exit;
  616. {$IFDEF RX_D3}
  617.   if (AnsiLastChar(Dir) <> nil) and (AnsiLastChar(Dir)^ = '\') then
  618. {$ELSE}
  619.   if Dir[Length(Dir)] = '\' then
  620. {$ENDIF}
  621.     Delete(Dir, Length(Dir), 1);
  622.   if (Length(Dir) < 3) or DirectoryExists(Dir) or
  623.     (ExtractFilePath(Dir) = Dir) then Exit;
  624.   ForceDirectories(ExtractFilePath(Dir));
  625. {$IFDEF WIN32}
  626.   CreateDir(Dir);
  627. {$ELSE}
  628.   MkDir(Dir);
  629. {$ENDIF}
  630. end;
  631.  
  632. {$IFDEF WIN32}
  633. procedure CopyMoveFileShell(const FileName, DestName: string; Confirmation,
  634.   AllowUndo, MoveFile: Boolean);
  635. begin
  636.   with TRxFileOperator.Create(nil) do
  637.   try
  638.     Source := FileName;
  639.     Destination := DestName;
  640.     if MoveFile then begin
  641.       if AnsiCompareText(ExtractFilePath(FileName),
  642.         ExtractFilePath(DestName)) = 0 then
  643.         Operation := foRename
  644.       else Operation := foMove;
  645.     end
  646.     else Operation := foCopy;
  647.     if not AllowUndo then
  648.       Options := Options - [flAllowUndo];
  649.     if not Confirmation then
  650.       Options := Options + [flNoConfirmation];
  651.     if not Execute or Aborted then SysUtils.Abort;
  652.   finally
  653.     Free;
  654.   end;
  655. end;
  656. {$ENDIF}
  657.  
  658. procedure CopyFile(const FileName, DestName: string;
  659.   ProgressControl: TControl);
  660. begin
  661.   CopyFileEx(FileName, DestName, False, False, ProgressControl);
  662. end;
  663.  
  664. procedure CopyFileEx(const FileName, DestName: string;
  665.   OverwriteReadOnly, ShellDialog: Boolean; ProgressControl: TControl);
  666. var
  667.   CopyBuffer: Pointer;
  668.   Source, Dest: Integer;
  669.   Destination: TFileName;
  670.   FSize, BytesCopied, TotalCopied: Longint;
  671.   Attr: Integer;
  672. const
  673.   ChunkSize: Longint = 8192;
  674. begin
  675. {$IFDEF WIN32}
  676.   if NewStyleControls and ShellDialog then begin
  677.     CopyMoveFileShell(FileName, DestName, not OverwriteReadOnly,
  678.       False, False);
  679.     Exit;
  680.   end;
  681. {$ENDIF}
  682.   Destination := DestName;
  683.   if HasAttr(Destination, faDirectory) then
  684.     Destination := NormalDir(Destination) + ExtractFileName(FileName);
  685.   GetMem(CopyBuffer, ChunkSize);
  686.   try
  687.     TotalCopied := 0;
  688.     FSize := GetFileSize(FileName);
  689.     Source := FileOpen(FileName, fmShareDenyWrite);
  690.     if Source < 0 then
  691.       raise EFOpenError.CreateFmt(ResStr(SFOpenError), [FileName]);
  692.     try
  693.       if ProgressControl <> nil then begin
  694.         SetProgressMax(ProgressControl, FSize);
  695.         SetProgressMin(ProgressControl, 0);
  696.         SetProgressValue(ProgressControl, 0);
  697.       end;
  698.       ForceDirectories(ExtractFilePath(Destination));
  699.       if OverwriteReadOnly then begin
  700.         Attr := FileGetAttr(Destination);
  701.         if (Attr >= 0) and ((Attr and faReadOnly) <> 0) then
  702.           FileSetAttr(Destination, Attr and not faReadOnly);
  703.       end;
  704.       Dest := FileCreate(Destination);
  705.       if Dest < 0 then
  706.         raise EFCreateError.CreateFmt(ResStr(SFCreateError), [Destination]);
  707.       try
  708.         repeat
  709.           BytesCopied := FileRead(Source, CopyBuffer^, ChunkSize);
  710.           if BytesCopied = -1 then
  711.             raise EReadError.Create(ResStr(SReadError));
  712.           TotalCopied := TotalCopied + BytesCopied;
  713.           if BytesCopied > 0 then begin
  714.             if FileWrite(Dest, CopyBuffer^, BytesCopied) = -1 then
  715.               raise EWriteError.Create(ResStr(SWriteError));
  716.           end;
  717.           if ProgressControl <> nil then
  718.             SetProgressValue(ProgressControl, TotalCopied);
  719.         until BytesCopied < ChunkSize;
  720.         FileSetDate(Dest, FileGetDate(Source));
  721.       finally
  722.         FileClose(Dest);
  723.       end;
  724.     finally
  725.       FileClose(Source);
  726.     end;
  727.   finally
  728.     FreeMem(CopyBuffer, ChunkSize);
  729.     if ProgressControl <> nil then
  730.       SetProgressValue(ProgressControl, 0);
  731.   end;
  732. end;
  733.  
  734. procedure MoveFile(const FileName, DestName: TFileName);
  735. var
  736.   Destination: TFileName;
  737.   Attr: Integer;
  738. begin
  739.   Destination := ExpandFileName(DestName);
  740.   if not RenameFile(FileName, Destination) then begin
  741.     Attr := FileGetAttr(FileName);
  742.     if Attr < 0 then Exit;
  743.     if (Attr and faReadOnly) <> 0 then
  744.       FileSetAttr(FileName, Attr and not faReadOnly);
  745.     CopyFile(FileName, Destination, nil);
  746.     DeleteFile(FileName);
  747.   end;
  748. end;
  749.  
  750. procedure MoveFileEx(const FileName, DestName: TFileName;
  751.   ShellDialog: Boolean);
  752. begin
  753. {$IFDEF WIN32}
  754.   if NewStyleControls and ShellDialog then
  755.     CopyMoveFileShell(FileName, DestName, False, False, True)
  756.   else
  757. {$ENDIF}
  758.     MoveFile(FileName, DestName);
  759. end;
  760.  
  761. {$IFDEF RX_D4}
  762. function GetFileSize(const FileName: string): Int64;
  763. var
  764.   Handle: THandle;
  765.   FindData: TWin32FindData;
  766. begin
  767.   Handle := FindFirstFile(PChar(FileName), FindData);
  768.   if Handle <> INVALID_HANDLE_VALUE then begin
  769.     Windows.FindClose(Handle);
  770.     if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
  771.     begin
  772.       Int64Rec(Result).Lo := FindData.nFileSizeLow;
  773.       Int64Rec(Result).Hi := FindData.nFileSizeHigh;
  774.       Exit;
  775.     end;
  776.   end;
  777.   Result := -1;
  778. end;
  779. {$ELSE}
  780. function GetFileSize(const FileName: string): Longint;
  781. var
  782.   SearchRec: TSearchRec;
  783. begin
  784.   if FindFirst(ExpandFileName(FileName), faAnyFile, SearchRec) = 0 then
  785.     Result := SearchRec.Size
  786.   else Result := -1;
  787.   FindClose(SearchRec);
  788. end;
  789. {$ENDIF RX_D4}
  790.  
  791. function FileDateTime(const FileName: string): System.TDateTime;
  792. var
  793.   Age: Longint;
  794. begin
  795.   Age := FileAge(FileName);
  796.   if Age = -1 then
  797.     Result := NullDate
  798.   else
  799.     Result := FileDateToDateTime(Age);
  800. end;
  801.  
  802. function HasAttr(const FileName: string; Attr: Integer): Boolean;
  803. var
  804.   FileAttr: Integer;
  805. begin
  806.   FileAttr := FileGetAttr(FileName);
  807.   Result := (FileAttr >= 0) and (FileAttr and Attr = Attr);
  808. end;
  809.  
  810. function DeleteFiles(const FileMask: string): Boolean;
  811. var
  812.   SearchRec: TSearchRec;
  813. begin
  814.   Result := FindFirst(ExpandFileName(FileMask), faAnyFile, SearchRec) = 0;
  815.   try
  816.     if Result then
  817.       repeat
  818. //        if (SearchRec.Name[1] <> '.') and
  819. //      !!! BUG !!!
  820.         if (SearchRec.Name <> '.') and
  821.           (SearchRec.Attr and faVolumeID <> faVolumeID) and
  822.           (SearchRec.Attr and faDirectory <> faDirectory) then
  823.         begin
  824.           Result := DeleteFile(ExtractFilePath(FileMask) + SearchRec.Name);
  825.           if not Result then Break;
  826.         end;
  827.       until FindNext(SearchRec) <> 0;
  828.   finally
  829.     FindClose(SearchRec);
  830.   end;
  831. end;
  832.  
  833. function DeleteFilesEx(const FileMasks: array of string): Boolean;
  834. var
  835.   I: Integer;
  836. begin
  837.   Result := True;
  838.   for I := Low(FileMasks) to High(FileMasks) do
  839.     Result := Result and DeleteFiles(FileMasks[I]);
  840. end;
  841.  
  842. function ClearDir(const Path: string; Delete: Boolean): Boolean;
  843. const
  844. {$IFDEF WIN32}
  845.   FileNotFound = 18;
  846. {$ELSE}
  847.   FileNotFound = -18;
  848. {$ENDIF}
  849. var
  850.   FileInfo: TSearchRec;
  851.   DosCode: Integer;
  852. begin
  853.   Result := DirExists(Path);
  854.   if not Result then Exit;
  855.   DosCode := FindFirst(NormalDir(Path) + '*.*', faAnyFile, FileInfo);
  856.   try
  857.     while DosCode = 0 do begin
  858. //      if (FileInfo.Name[1] <> '.') and (FileInfo.Attr <> faVolumeID) then
  859. //      !!! BUG !!!
  860.       if (FileInfo.Name <> '.') and (FileInfo.Name <> '..') and (FileInfo.Attr <> faVolumeID) then
  861.       begin
  862.         if (FileInfo.Attr and faDirectory = faDirectory) then
  863.           Result := ClearDir(NormalDir(Path) + FileInfo.Name, Delete) and Result
  864.         else if (FileInfo.Attr and faVolumeID <> faVolumeID) then begin
  865.           if (FileInfo.Attr and faReadOnly = faReadOnly) then
  866.             FileSetAttr(NormalDir(Path) + FileInfo.Name, faArchive);
  867.           Result := DeleteFile(NormalDir(Path) + FileInfo.Name) and Result;
  868.         end;
  869.       end;
  870.       DosCode := FindNext(FileInfo);
  871.     end;
  872.   finally
  873.     FindClose(FileInfo);
  874.   end;
  875.   if Delete and Result and (DosCode = FileNotFound) and
  876.     not ((Length(Path) = 2) and (Path[2] = ':')) then
  877.   begin
  878.     RmDir(Path);
  879.     Result := (IOResult = 0) and Result;
  880.   end;
  881. end;
  882.  
  883. function GetTempDir: string;
  884. {$IFDEF WIN32}
  885. var
  886.   Buffer: array[0..1023] of Char;
  887. begin
  888.   SetString(Result, Buffer, GetTempPath(SizeOf(Buffer), Buffer));
  889. {$ELSE}
  890. var
  891.   Buffer: array[0..255] of Char;
  892. begin
  893.   GetTempFileName(GetTempDrive(#0), '$', 1, Buffer);
  894.   Result := ExtractFilePath(StrPas(Buffer));
  895. {$ENDIF}
  896. end;
  897.  
  898. function GetWindowsDir: string;
  899. {$IFDEF WIN32}
  900. var
  901.   Buffer: array[0..1023] of Char;
  902. begin
  903.   SetString(Result, Buffer, GetWindowsDirectory(Buffer, SizeOf(Buffer)));
  904. {$ELSE}
  905. begin
  906.   Result[0] := Char(GetWindowsDirectory(@Result[1], 254));
  907. {$ENDIF}
  908. end;
  909.  
  910. function GetSystemDir: string;
  911. {$IFDEF WIN32}
  912. var
  913.   Buffer: array[0..1023] of Char;
  914. begin
  915.   SetString(Result, Buffer, GetSystemDirectory(Buffer, SizeOf(Buffer)));
  916. {$ELSE}
  917. begin
  918.   Result[0] := Char(GetSystemDirectory(@Result[1], 254));
  919. {$ENDIF}
  920. end;
  921.  
  922. {$IFDEF WIN32}
  923.  
  924. function ValidFileName(const FileName: string): Boolean;
  925.   function HasAny(const Str, Substr: string): Boolean;
  926.   var
  927.     I: Integer;
  928.   begin
  929.     Result := False;
  930.     for I := 1 to Length(Substr) do begin
  931.       if Pos(Substr[I], Str) > 0 then begin
  932.         Result := True;
  933.         Break;
  934.       end;
  935.     end;
  936.   end;
  937. begin
  938.   Result := (FileName <> '') and (not HasAny(FileName, '<>"[]|'));
  939.   if Result then Result := Pos('\', ExtractFileName(FileName)) = 0;
  940. end;
  941.  
  942. function FileLock(Handle: Integer; Offset, LockSize: Longint): Integer;
  943. begin
  944.   if LockFile(Handle, Offset, 0, LockSize, 0) then
  945.     Result := 0
  946.   else
  947.     Result := GetLastError;
  948. end;
  949.  
  950. function FileUnlock(Handle: Integer; Offset, LockSize: Longint): Integer;
  951. begin
  952.   if UnlockFile(Handle, Offset, 0, LockSize, 0) then
  953.     Result := 0
  954.   else
  955.     Result := GetLastError;
  956. end;
  957.  
  958. {$IFDEF RX_D4}
  959. function FileLock(Handle: Integer; Offset, LockSize: Int64): Integer;
  960. begin
  961.   if LockFile(Handle, Int64Rec(Offset).Lo, Int64Rec(Offset).Hi,
  962.     Int64Rec(LockSize).Lo, Int64Rec(LockSize).Hi) then Result := 0
  963.   else
  964.     Result := GetLastError;
  965. end;
  966.  
  967. function FileUnlock(Handle: Integer; Offset, LockSize: Int64): Integer;
  968. begin
  969.   if UnlockFile(Handle, Int64Rec(Offset).Lo, Int64Rec(Offset).Hi,
  970.     Int64Rec(LockSize).Lo, Int64Rec(LockSize).Hi) then Result := 0
  971.   else
  972.     Result := GetLastError;
  973. end;
  974. {$ENDIF RX_D4}
  975.  
  976. {$ELSE}
  977.  
  978. function ValidFileName(const FileName: string): Boolean;
  979. const
  980.   MaxNameLen = 12; { file name and extension }
  981.   MaxExtLen  =  4; { extension with point }
  982.   MaxPathLen = 79; { full file path in DOS }
  983. var
  984.   Dir, Name, Ext: TFileName;
  985.  
  986.   function HasAny(Str, SubStr: string): Boolean; near; assembler;
  987.   asm
  988.         PUSH     DS
  989.         CLD
  990.         LDS      SI,Str
  991.         LES      DI,SubStr
  992.         INC      DI
  993.         MOV      DX,DI
  994.         XOR      AH,AH
  995.         LODSB
  996.         MOV      BX,AX
  997.         OR       BX,BX
  998.         JZ       @@2
  999.         MOV      AL,ES:[DI-1]
  1000.         XCHG     AX,CX
  1001.   @@1:  PUSH     CX
  1002.         MOV      DI,DX
  1003.         LODSB
  1004.         REPNE    SCASB
  1005.         POP      CX
  1006.         JE       @@3
  1007.         DEC      BX
  1008.         JNZ      @@1
  1009.   @@2:  XOR      AL,AL
  1010.         JMP      @@4
  1011.   @@3:  MOV      AL,1
  1012.   @@4:  POP      DS
  1013.   end;
  1014.  
  1015. begin
  1016.   Result := True;
  1017.   Dir := Copy(ExtractFilePath(FileName), 1, MaxPathLen);
  1018.   Name := Copy(ExtractFileName(FileName), 1, MaxNameLen);
  1019.   Ext := Copy(ExtractFileExt(FileName), 1, MaxExtLen);
  1020.   if (Dir + Name <> FileName) or HasAny(Name, ';,=+<>|"[] \') or
  1021.     HasAny(Copy(Ext, 2, 255), ';,=+<>|"[] \.') then Result := False;
  1022. end;
  1023.  
  1024. function LockFile(Handle: Integer; StartPos, Length: Longint;
  1025.   Unlock: Boolean): Integer; assembler;
  1026. asm
  1027.       PUSH     DS
  1028.       MOV      AH,5CH
  1029.       MOV      AL,Unlock
  1030.       MOV      BX,Handle
  1031.       MOV      DX,StartPos.Word[0]
  1032.       MOV      CX,StartPos.Word[2]
  1033.       MOV      DI,Length.Word[0]
  1034.       MOV      SI,Length.Word[2]
  1035.       INT      21H
  1036.       JNC      @@1
  1037.       NEG      AX
  1038.       JMP      @@2
  1039. @@1:  MOV      AX,0
  1040. @@2:  POP      DS
  1041. end;
  1042.  
  1043. function FileLock(Handle: Integer; Offset, LockSize: Longint): Integer;
  1044. begin
  1045.   Result := LockFile(Handle, Offset, LockSize, False);
  1046. end;
  1047.  
  1048. function FileUnlock(Handle: Integer; Offset, LockSize: Longint): Integer;
  1049. begin
  1050.   Result := LockFile(Handle, Offset, LockSize, True);
  1051. end;
  1052.  
  1053. {$ENDIF WIN32}
  1054.  
  1055. {$IFDEF WIN32}
  1056.  
  1057. function ShortToLongFileName(const ShortName: string): string;
  1058. var
  1059.   Temp: TWin32FindData;
  1060.   SearchHandle: THandle;
  1061. begin
  1062.   SearchHandle := FindFirstFile(PChar(ShortName), Temp);
  1063.   if SearchHandle <> INVALID_HANDLE_VALUE then begin
  1064.     Result := string(Temp.cFileName);
  1065.     if Result = '' then Result := string(Temp.cAlternateFileName);
  1066.   end
  1067.   else Result := '';
  1068.   Windows.FindClose(SearchHandle);
  1069. end;
  1070.  
  1071. function LongToShortFileName(const LongName: string): string;
  1072. var
  1073.   Temp: TWin32FindData;
  1074.   SearchHandle: THandle;
  1075. begin
  1076.   SearchHandle := FindFirstFile(PChar(LongName), Temp);
  1077.   if SearchHandle <> INVALID_HANDLE_VALUE then begin
  1078.     Result := string(Temp.cAlternateFileName);
  1079.     if Result = '' then Result := string(Temp.cFileName);
  1080.   end
  1081.   else Result := '';
  1082.   Windows.FindClose(SearchHandle);
  1083. end;
  1084.  
  1085. function ShortToLongPath(const ShortName: string): string;
  1086. var
  1087.   LastSlash: PChar;
  1088.   TempPathPtr: PChar;
  1089. begin
  1090.   Result := '';
  1091.   TempPathPtr := PChar(ShortName);
  1092.   LastSlash := StrRScan(TempPathPtr, '\');
  1093.   while LastSlash <> nil do begin
  1094.     Result := '\' + ShortToLongFileName(TempPathPtr) + Result;
  1095.     if LastSlash <> nil then begin
  1096.       LastSlash^ := char(0);
  1097.       LastSlash := StrRScan(TempPathPtr, '\');
  1098.     end;
  1099.   end;
  1100.   Result := TempPathPtr + Result;
  1101. end;
  1102.  
  1103. function LongToShortPath(const LongName: string): string;
  1104. var
  1105.   LastSlash: PChar;
  1106.   TempPathPtr: PChar;
  1107. begin
  1108.   Result := '';
  1109.   TempPathPtr := PChar(LongName);
  1110.   LastSlash := StrRScan(TempPathPtr, '\');
  1111.   while LastSlash <> nil do begin
  1112.     Result := '\' + LongToShortFileName(TempPathPtr) + Result;
  1113.     if LastSlash <> nil then begin
  1114.       LastSlash^ := char(0);
  1115.       LastSlash := StrRScan(TempPathPtr, '\');
  1116.     end;
  1117.   end;
  1118.   Result := TempPathPtr + Result;
  1119. end;
  1120.  
  1121. const
  1122.   IID_IPersistFile: TGUID = (
  1123.     D1:$0000010B;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46));
  1124.  
  1125. {$IFNDEF RX_D3}
  1126. const
  1127.   IID_IShellLinkA: TGUID = (
  1128.     D1:$000214EE; D2:$0000; D3:$0000; D4:($C0,$00,$00,$00,$00,$00,$00,$46));
  1129.   CLSID_ShellLink: TGUID = (
  1130.     D1:$00021401; D2:$0000; D3:$0000; D4:($C0,$00,$00,$00,$00,$00,$00,$46));
  1131.  
  1132. type
  1133.   IShellLink = class(IUnknown) { sl }
  1134.     function GetPath(pszFile: LPSTR; cchMaxPath: Integer;
  1135.       var pfd: TWin32FindData; fFlags: DWORD): HResult; virtual; stdcall; abstract;
  1136.     function GetIDList(var ppidl: PItemIDList): HResult; virtual; stdcall; abstract;
  1137.     function SetIDList(pidl: PItemIDList): HResult; virtual; stdcall; abstract;
  1138.     function GetDescription(pszName: LPSTR; cchMaxName: Integer): HResult; virtual; stdcall; abstract;
  1139.     function SetDescription(pszName: LPSTR): HResult; virtual; stdcall; abstract;
  1140.     function GetWorkingDirectory(pszDir: LPSTR; cchMaxPath: Integer): HResult; virtual; stdcall; abstract;
  1141.     function SetWorkingDirectory(pszDir: LPSTR): HResult; virtual; stdcall; abstract;
  1142.     function GetArguments(pszArgs: LPSTR; cchMaxPath: Integer): HResult; virtual; stdcall; abstract;
  1143.     function SetArguments(pszArgs: LPSTR): HResult; virtual; stdcall; abstract;
  1144.     function GetHotkey(var pwHotkey: Word): HResult; virtual; stdcall; abstract;
  1145.     function SetHotkey(wHotkey: Word): HResult; virtual; stdcall; abstract;
  1146.     function GetShowCmd(var piShowCmd: Integer): HResult; virtual; stdcall; abstract;
  1147.     function SetShowCmd(iShowCmd: Integer): HResult; virtual; stdcall; abstract;
  1148.     function GetIconLocation(pszIconPath: LPSTR; cchIconPath: Integer;
  1149.       var piIcon: Integer): HResult; virtual; stdcall; abstract;
  1150.     function SetIconLocation(pszIconPath: LPSTR; iIcon: Integer): HResult; virtual; stdcall; abstract;
  1151.     function SetRelativePath(pszPathRel: LPSTR; dwReserved: DWORD): HResult; virtual; stdcall; abstract;
  1152.     function Resolve(Wnd: HWND; fFlags: DWORD): HResult; virtual; stdcall; abstract;
  1153.     function SetPath(pszFile: LPSTR): HResult; virtual; stdcall; abstract;
  1154.   end;
  1155. {$ENDIF}
  1156.  
  1157. const
  1158.   LinkExt = '.lnk';
  1159.  
  1160. procedure CreateFileLink(const FileName, DisplayName: string; Folder: Integer);
  1161. var
  1162.   ShellLink: IShellLink;
  1163.   PersistFile: IPersistFile;
  1164.   ItemIDList: PItemIDList;
  1165.   FileDestPath: array[0..MAX_PATH] of Char;
  1166.   FileNameW: array[0..MAX_PATH] of WideChar;
  1167. begin
  1168.   CoInitialize(nil);
  1169.   try
  1170.     OleCheck(CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_SERVER,
  1171.       IID_IShellLinkA, ShellLink));
  1172.     try
  1173.       OleCheck(ShellLink.QueryInterface(IID_IPersistFile, PersistFile));
  1174.       try
  1175.         OleCheck(SHGetSpecialFolderLocation(0, Folder, ItemIDList));
  1176.         SHGetPathFromIDList(ItemIDList, FileDestPath);
  1177.         StrCat(FileDestPath, PChar('\' + DisplayName + LinkExt));
  1178.         ShellLink.SetPath(PChar(FileName));
  1179.         ShellLink.SetIconLocation(PChar(FileName), 0);
  1180.         MultiByteToWideChar(CP_ACP, 0, FileDestPath, -1, FileNameW, MAX_PATH);
  1181.         OleCheck(PersistFile.Save(FileNameW, True));
  1182.       finally
  1183. {$IFDEF RX_D3}
  1184.         PersistFile := nil;
  1185. {$ELSE}
  1186.         PersistFile.Release;
  1187. {$ENDIF}
  1188.       end;
  1189.     finally
  1190. {$IFDEF RX_D3}
  1191.       ShellLink := nil;
  1192. {$ELSE}
  1193.       ShellLink.Release;
  1194. {$ENDIF}
  1195.     end;
  1196.   finally
  1197.     CoUninitialize;
  1198.   end;
  1199. end;
  1200.  
  1201. procedure DeleteFileLink(const DisplayName: string; Folder: Integer);
  1202. var
  1203.   ShellLink: IShellLink;
  1204.   ItemIDList: PItemIDList;
  1205.   FileDestPath: array[0..MAX_PATH] of Char;
  1206. begin
  1207.   CoInitialize(nil);
  1208.   try
  1209.     OleCheck(CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_SERVER,
  1210.       IID_IShellLinkA, ShellLink));
  1211.     try
  1212.       OleCheck(SHGetSpecialFolderLocation(0, Folder, ItemIDList));
  1213.       SHGetPathFromIDList(ItemIDList, FileDestPath);
  1214.       StrCat(FileDestPath, PChar('\' + DisplayName + LinkExt));
  1215.       DeleteFile(FileDestPath);
  1216.     finally
  1217. {$IFDEF RX_D3}
  1218.       ShellLink := nil;
  1219. {$ELSE}
  1220.       ShellLink.Release;
  1221. {$ENDIF}
  1222.     end;
  1223.   finally
  1224.     CoUninitialize;
  1225.   end;
  1226. end;
  1227.  
  1228. {$ENDIF WIN32}
  1229.  
  1230. {$IFNDEF RX_D3}
  1231. function IsPathDelimiter(const S: string; Index: Integer): Boolean;
  1232. begin
  1233.   Result := (Index > 0) and (Index <= Length(S)) and (S[Index] = '\');
  1234. end;
  1235. {$ENDIF}
  1236.  
  1237. end.