FileUtil.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:37k
源码类别:

Delphi控件源码

开发平台:

Delphi

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