BaseUtils.pas 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. unit BaseUtils;
  2. {==================================================================
  3. Basic file handling utilities / Version 1.2 / 11.1999
  4. ========================================================
  5. Description:
  6. ============
  7. Basic utilities useful for handling files or directories.
  8. Used by the components TDriveView and TDirView.
  9. Author:
  10. =======
  11. (c) Ingo Eckel 5/1998
  12. Sodener Weg 38
  13. 65812 Bad Soden
  14. Germany
  15. Modifications (for WinSCP):
  16. ===========================
  17. (c) Martin Prikryl 2001, 2002
  18. {==================================================================}
  19. interface
  20. uses
  21. SysUtils, Windows, Forms, ShlObj, PIDL, Classes, Controls;
  22. type
  23. TDateTimePrecision = (tpNone, tpDay, tpMinute, tpSecond, tpMillisecond);
  24. function CheckFileExists(FileName: string): Boolean;
  25. function DirExists(Dir: string): Boolean; overload;
  26. function DirExists(Dir: string; var Attrs: Integer): Boolean; overload;
  27. function DiskSize(Drive: Byte): Int64;
  28. function ExtractFileNameOnly(Name: string): string;
  29. function FileOrDirExists(FileName: string): Boolean;
  30. function FormatSize(Size: Integer): string; overload;
  31. function FormatSize(Size: Cardinal): string; overload;
  32. function FormatSize(Size: Int64): string; overload;
  33. procedure FreePIDL(var PIDL: PItemIDList);
  34. function StrContains(Str1, Str2: string): Boolean;
  35. procedure StrTranslate(var Str: string; Code: string);
  36. function IsUncPath(Path: string): Boolean;
  37. function AnyValidPath: string;
  38. procedure ReduceDateTimePrecision(var DateTime: TDateTime;
  39. Precision: TDateTimePrecision);
  40. function SpecialFolderLocation(Folder: Integer; var Path: string;
  41. var PIDL: PItemIDList): Boolean; overload;
  42. function SpecialFolderLocation(Folder: Integer; var Path: string): Boolean; overload;
  43. function ShellImageList(Owner: TComponent; Flags: UINT): TImageList;
  44. function FormatLastOSError(Message: string): string;
  45. resourcestring
  46. SNoValidPath = 'Can''t find any valid path.';
  47. SUcpPathsNotSupported = 'UNC paths are not supported.';
  48. implementation
  49. uses
  50. IEDriveInfo, DateUtils, ShellApi, SysConst;
  51. var
  52. GetDiskFreeSpaceEx: function (Directory: PChar;
  53. var FreeAvailable, TotalSpace: TLargeInteger; TotalFree: PLargeInteger): Bool stdcall = nil;
  54. function AnyValidPath: string;
  55. var
  56. Drive: TDrive;
  57. begin
  58. for Drive := 'C' to 'Z' do
  59. if (DriveInfo[Drive].DriveType = DRIVE_FIXED) and
  60. DirectoryExists(Drive + ':\') then
  61. begin
  62. Result := Drive + ':\';
  63. Exit;
  64. end;
  65. for Drive := 'C' to 'Z' do
  66. if (DriveInfo[Drive].DriveType = DRIVE_REMOTE) and
  67. DirectoryExists(Drive + ':\') then
  68. begin
  69. Result := Drive + ':\';
  70. Exit;
  71. end;
  72. raise Exception.Create(SNoValidPath);
  73. end;
  74. function IsUncPath(Path: string): Boolean;
  75. begin
  76. Result := (Copy(Path, 1, 2) = '\\') or (Copy(Path, 1, 2) = '//');
  77. end;
  78. procedure StrTranslate(var Str: string; Code: string);
  79. var
  80. Index: Integer;
  81. begin
  82. if (Length(Code) > 0) and (Length(Code) mod 2 = 0) then
  83. for Index := 1 to Length(Code) div 2 do
  84. while Pos(Code[Index*2-1], Str) <> 0 do
  85. Str[Pos(Code[Index*2-1], Str)] := Code[Index*2];
  86. end; {StrTranslate}
  87. function StrContains(Str1, Str2: string): Boolean;
  88. var
  89. Index: Integer;
  90. begin
  91. for Index := 1 to Length(Str1) do
  92. if Pos(Str1[Index], Str2) <> 0 then
  93. begin
  94. Result := True;
  95. Exit;
  96. end;
  97. Result := False;
  98. end; {StringCountains}
  99. function FileOrDirExists(FileName: string): Boolean;
  100. var
  101. SRec : TSearchRec;
  102. begin
  103. if Length(FileName) = 0 then Result := False
  104. else
  105. begin
  106. Result := (FindFirst(FileName, faAnyFile, SRec) = 0);
  107. SysUtils.FindCLose(SRec);
  108. end;
  109. end; {FileOrDirExists}
  110. function CheckFileExists(FileName: string): Boolean;
  111. var
  112. SaveFileMode : Integer;
  113. F: file;
  114. begin
  115. SaveFileMode := System.FileMode;
  116. System.FileMode := 0;
  117. try
  118. AssignFile(F, FileName);
  119. Reset(F, 1);
  120. Result := IOResult = 0;
  121. if Result then
  122. CloseFile(F);
  123. finally
  124. System.FileMode := SaveFileMode;
  125. end;
  126. end; {CheckFileExists}
  127. function DirExists(Dir: string; var Attrs: Integer): Boolean;
  128. var
  129. SRec: TSearchRec;
  130. begin
  131. Result := ((Length(Dir) <= 3) and (Length(Dir) >= 2)) and (Dir[2] = ':');
  132. if Result then Attrs := 0
  133. else
  134. begin
  135. if FindFirst(Dir, faAnyFile, SRec) = 0 then
  136. begin
  137. Result := (SRec.Attr and faDirectory <> 0);
  138. Attrs := SRec.Attr;
  139. end;
  140. SysUtils.FindClose(SRec);
  141. end;
  142. end; {DirExists}
  143. function DirExists(Dir: string): Boolean;
  144. var
  145. Dummy: Integer;
  146. begin
  147. Result := DirExists(Dir, Dummy);
  148. end; {DirExists}
  149. function ExtractFileNameOnly(Name: string): string;
  150. var
  151. Ext: string;
  152. begin
  153. Result := ExtractFileName(Name);
  154. Ext := ExtractFileExt(Name);
  155. if Ext <> '' then
  156. Delete(Result, Length(Result)-Length(Ext)+1, Length(Ext));
  157. end; {ExtractFileNameOnly}
  158. function FormatSize(Size: Integer): string;
  159. begin
  160. Result := FormatSize(Cardinal(Abs(Size)));
  161. end; {FormatSize}
  162. function FormatSize(Size: Cardinal): string;
  163. var
  164. i: Integer;
  165. p: Integer;
  166. begin
  167. p := 0;
  168. i := 3;
  169. Result := IntToStr(Size);
  170. while i + p < Length(Result) do
  171. begin
  172. Insert(ThousandSeparator, Result, Length(Result) - (i + p)+ 1);
  173. Inc(p);
  174. INC(i, 3);
  175. end;
  176. end; {FormatSize}
  177. function FormatSize(Size: Int64): String;
  178. var
  179. i: Integer;
  180. p: Integer;
  181. begin
  182. p := 0;
  183. i := 3;
  184. Result := IntToStr(Size);
  185. while i + p < Length(Result) do
  186. begin
  187. Insert(ThousandSeparator, Result, Length(Result) - (i + p)+ 1);
  188. Inc(p);
  189. Inc(i, 3);
  190. end;
  191. end; {FormatSize}
  192. procedure FreePIDL(var PIDL: PItemIDList);
  193. begin
  194. if PIDL <> nil then
  195. begin
  196. try
  197. ShellMalloc.Free(PIDL);
  198. PIDL := NIL;
  199. except
  200. PIDL := NIL;
  201. end;
  202. end;
  203. end; {FreePIDL}
  204. function InternalGetDiskSpace(Drive: Byte;
  205. var TotalSpace, FreeSpaceAvailable: Int64): Bool;
  206. var
  207. RootPath: array[0..4] of Char;
  208. RootPtr: PChar;
  209. begin
  210. RootPtr := nil;
  211. if Drive > 0 then
  212. begin
  213. RootPath[0] := Char(Drive + $40);
  214. RootPath[1] := ':';
  215. RootPath[2] := '\';
  216. RootPath[3] := #0;
  217. RootPtr := RootPath;
  218. end;
  219. Result := GetDiskFreeSpaceEx(RootPtr, FreeSpaceAvailable, TotalSpace, nil);
  220. end;
  221. // This function is used if the OS doesn't support GetDiskFreeSpaceEx
  222. function BackfillGetDiskFreeSpaceEx(Directory: PChar; var FreeAvailable,
  223. TotalSpace: TLargeInteger; TotalFree: PLargeInteger): Bool; stdcall;
  224. var
  225. SectorsPerCluster, BytesPerSector, FreeClusters, TotalClusters: LongWord;
  226. Temp: Int64;
  227. Dir: PChar;
  228. begin
  229. if Directory <> nil then
  230. Dir := Directory
  231. else
  232. Dir := nil;
  233. Result := GetDiskFreeSpaceA(Dir, SectorsPerCluster, BytesPerSector,
  234. FreeClusters, TotalClusters);
  235. Temp := SectorsPerCluster * BytesPerSector;
  236. FreeAvailable := Temp * FreeClusters;
  237. TotalSpace := Temp * TotalClusters;
  238. end;
  239. function DiskSize(Drive: Byte): Int64;
  240. var
  241. FreeSpace: Int64;
  242. begin
  243. if not InternalGetDiskSpace(Drive, Result, FreeSpace) then
  244. Result := -1;
  245. end;
  246. procedure InitDriveSpacePtr;
  247. var
  248. Kernel: THandle;
  249. begin
  250. Kernel := GetModuleHandle(Windows.Kernel32);
  251. if Kernel <> 0 then
  252. @GetDiskFreeSpaceEx := GetProcAddress(Kernel, 'GetDiskFreeSpaceExA');
  253. if not Assigned(GetDiskFreeSpaceEx) then
  254. GetDiskFreeSpaceEx := @BackfillGetDiskFreeSpaceEx;
  255. end;
  256. // duplicated in RemoteFiles.cpp
  257. procedure ReduceDateTimePrecision(var DateTime: TDateTime;
  258. Precision: TDateTimePrecision);
  259. var
  260. Y, M, D, H, N, S, MS: Word;
  261. begin
  262. if Precision = tpNone then DateTime := 0
  263. else
  264. if Precision <> tpMillisecond then
  265. begin
  266. DecodeDateTime(DateTime, Y, M, D, H, N, S, MS);
  267. case Precision of
  268. tpDay:
  269. begin
  270. H := 0;
  271. N := 0;
  272. S := 0;
  273. MS := 0;
  274. end;
  275. tpMinute:
  276. begin
  277. S := 0;
  278. MS := 0;
  279. end;
  280. tpSecond:
  281. begin
  282. MS := 0;
  283. end;
  284. end;
  285. DateTime := EncodeDate(Y, M, D) + EncodeTime(H, N, S, MS);
  286. end;
  287. end;
  288. function SpecialFolderLocation(Folder: Integer; var Path: string;
  289. var PIDL: PItemIDList): Boolean;
  290. begin
  291. SetLength(Path, MAX_PATH);
  292. Result :=
  293. (not Failed(SHGetSpecialFolderLocation(Application.Handle, Folder, PIDL))) and
  294. SHGetPathFromIDList(PIDL, PChar(Path));
  295. if Result then SetLength(Path, StrLen(PChar(Path)));
  296. end;
  297. function SpecialFolderLocation(Folder: Integer; var Path: string): Boolean;
  298. var
  299. PIDL: PItemIDList;
  300. begin
  301. Result := SpecialFolderLocation(Folder, Path, PIDL);
  302. end;
  303. function ShellImageList(Owner: TComponent; Flags: UINT): TImageList;
  304. var
  305. FileInfo: TShFileInfo;
  306. begin
  307. Result := TImageList.Create(Owner);
  308. Result.Handle := SHGetFileInfo('', 0, FileInfo, SizeOf(FileInfo),
  309. SHGFI_SYSICONINDEX or Flags);
  310. Result.ShareImages := True;
  311. end;
  312. function FormatLastOSError(Message: string): string;
  313. var
  314. LastError: Integer;
  315. begin
  316. Result := Message;
  317. LastError := GetLastError;
  318. if LastError <> 0 then
  319. Result := Result + #13#10 + #13#10 + Format(SOSError, [LastError, SysErrorMessage(LastError)]);
  320. end;
  321. initialization
  322. InitDriveSpacePtr;
  323. end.