IEDriveInfo.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. unit IEDriveInfo;
  2. {==================================================================
  3. Component TDriveInfo / Version 2.6 / January 2000
  4. ====================================================
  5. Description:
  6. ============
  7. Central drive management class. Provides information about all
  8. installed drives, for example wether drive is valid, disk is inserted
  9. displayname or volume size.
  10. Author:
  11. =======
  12. (c) Ingo Eckel 1999
  13. Sodener Weg 38
  14. 65812 Bad Soden
  15. Germany
  16. For detailed documentation and history see the documentation in TDriveInfo.htm.
  17. {==================================================================}
  18. {Required compiler options:}
  19. {$A+,B-,X+,H+,P+}
  20. {$WARN SYMBOL_PLATFORM OFF}
  21. interface
  22. uses
  23. Windows, Registry, SysUtils, Classes, ComCtrls, ShellApi, ShlObj, CommCtrl, Forms,
  24. BaseUtils, System.Generics.Collections;
  25. const
  26. {Flags used by TDriveInfo.ReadDriveStatus and TDriveView.RefreshRootNodes:}
  27. dsValid = 0; {checks only whether drive is still valid}
  28. dsImageIndex = 1; {Fetch imageindex, if not allready fetched}
  29. dsSize = 2; {Fetch disk size and serialnumber}
  30. dsDisplayName = 4; {Fetch drives displayname}
  31. dsAll = dsImageIndex or dsSize or dsDisplayName;
  32. FirstDrive = 'A';
  33. SystemDrive = 'C';
  34. LastDrive = 'Z';
  35. FirstSpecialFolder = CSIDL_DESKTOP;
  36. LastSpecialFolder = CSIDL_PRINTHOOD;
  37. type
  38. TDriveInfoRec = class
  39. PIDL : PItemIDList; {Fully qualyfied PIDL}
  40. Init : Boolean; {Drivestatus was updated once}
  41. Valid : Boolean; {Drivestatus is valid}
  42. DriveReady : Boolean; {Drive is ready}
  43. DriveType : Integer; {DRIVE_REMOVABLE, DRIVE_FIXED, DRIVE_CDROM, DRIVE_RAMDISK, DRIVE_REMOTE}
  44. DisplayName : string; {Windows displayname}
  45. PrettyName : string; {Prettyfied displayname}
  46. DriveSerial : DWORD; {Serial number of the drive}
  47. Size : Int64; {Drivesize}
  48. ImageIndex : Integer; {Drive imageIndex}
  49. end;
  50. TRealDrive = char;
  51. TSpecialFolder = FirstSpecialFolder..LastSpecialFolder;
  52. PSpecialFolderRec = ^TSpecialFolderRec;
  53. TSpecialFolderRec = record
  54. Valid: Boolean;
  55. Location: string;
  56. DisplayName: string;
  57. ImageIndex: Integer;
  58. PIDL: PItemIDList;
  59. end;
  60. TDriveInfo = class(TObject)
  61. private
  62. FData: TObjectDictionary<string, TDriveInfoRec>;
  63. FNoDrives: DWORD;
  64. FDesktop: IShellFolder;
  65. FFolders: array[TSpecialFolder] of TSpecialFolderRec;
  66. FHonorDrivePolicy: Boolean;
  67. FUseABDrives: Boolean;
  68. FLoaded: Boolean;
  69. function GetFolder(Folder: TSpecialFolder): PSpecialFolderRec;
  70. procedure ReadDriveBasicStatus(Drive: string);
  71. procedure ResetDrive(Drive: string);
  72. procedure SetHonorDrivePolicy(Value: Boolean);
  73. function GetFirstFixedDrive: Char;
  74. procedure NeedData;
  75. procedure Load;
  76. function AddDrive(Drive: string): TDriveInfoRec;
  77. public
  78. function Get(Drive: string): TDriveInfoRec;
  79. property SpecialFolder[Folder: TSpecialFolder]: PSpecialFolderRec read GetFolder;
  80. function AnyValidPath: string;
  81. function GetDriveKey(Path: string): string;
  82. function GetDriveRoot(Drive: string): string;
  83. function IsRealDrive(Drive: string): Boolean;
  84. function IsFixedDrive(Drive: string): Boolean;
  85. function GetImageIndex(Drive: string): Integer;
  86. function GetSimpleName(Drive: string): string;
  87. function GetDisplayName(Drive: string): string;
  88. function GetPrettyName(Drive: string): string;
  89. function ReadDriveStatus(Drive: string; Flags: Integer): Boolean;
  90. property HonorDrivePolicy: Boolean read FHonorDrivePolicy write SetHonorDrivePolicy;
  91. property FirstFixedDrive: Char read GetFirstFixedDrive;
  92. property UseABDrives: Boolean read FUseABDrives write FUseABDrives;
  93. constructor Create;
  94. destructor Destroy; override;
  95. end;
  96. function GetShellFileName(const Name: string): string; overload;
  97. function GetShellFileName(PIDL: PItemIDList): string; overload;
  98. function GetNetWorkName(Drive: string): string;
  99. function GetNetWorkConnected(Drive: string): Boolean;
  100. function IsRootPath(Path: string): Boolean;
  101. {Central drive information object instance of TDriveInfo}
  102. var
  103. DriveInfo : TDriveInfo;
  104. resourceString
  105. ErrorInvalidDrive = '%s is a invalid drive letter.';
  106. implementation
  107. uses
  108. Math, PIDL, OperationWithTimeout, PasTools, CompThread;
  109. var
  110. ThreadLock: TRTLCriticalSection;
  111. ReadyDrives: string;
  112. type
  113. TDriveInfoThread = class(TCompThread)
  114. public
  115. constructor Create(Drives: string);
  116. protected
  117. procedure Execute; override;
  118. private
  119. FDrives: string;
  120. end;
  121. constructor TDriveInfoThread.Create(Drives: string);
  122. begin
  123. inherited Create(True);
  124. FDrives := Drives;
  125. FreeOnTerminate := True;
  126. Resume;
  127. end;
  128. procedure TDriveInfoThread.Execute;
  129. var
  130. I: Integer;
  131. FreeSpace, Size: Int64;
  132. DriveRoot: string;
  133. Drive: Char;
  134. begin
  135. if Length(FDrives) = 1 then
  136. begin
  137. Drive := FDrives[1];
  138. DriveRoot := DriveInfo.GetDriveRoot(Drive);
  139. if GetDiskFreeSpaceEx(PChar(DriveRoot), FreeSpace, Size, nil) then
  140. begin
  141. EnterCriticalSection(ThreadLock);
  142. ReadyDrives := ReadyDrives + Drive;
  143. LeaveCriticalSection(ThreadLock);
  144. end;
  145. end
  146. else
  147. begin
  148. for I := 1 to Length(FDrives) do
  149. begin
  150. TDriveInfoThread.Create(FDrives[I]);
  151. Sleep(100);
  152. end;
  153. end;
  154. end;
  155. constructor TDriveInfo.Create;
  156. begin
  157. inherited;
  158. FHonorDrivePolicy := True;
  159. FUseABDrives := True;
  160. FLoaded := False;
  161. FData := TObjectDictionary<string, TDriveInfoRec>.Create([doOwnsValues]);
  162. end; {TDriveInfo.Create}
  163. destructor TDriveInfo.Destroy;
  164. begin
  165. FData.Free;
  166. inherited;
  167. end; {TDriveInfo.Destroy}
  168. procedure TDriveInfo.NeedData;
  169. var
  170. I: Integer;
  171. Drive: Char;
  172. begin
  173. if not FLoaded then
  174. begin
  175. Load;
  176. FLoaded := True;
  177. end;
  178. EnterCriticalSection(ThreadLock);
  179. try
  180. for I := 1 to Length(ReadyDrives) do
  181. begin
  182. Drive := ReadyDrives[I];
  183. Assert(FData.ContainsKey(Drive));
  184. FData[Drive].DriveReady := True;
  185. end;
  186. ReadyDrives := '';
  187. finally
  188. LeaveCriticalSection(ThreadLock);
  189. end;
  190. end;
  191. function TDriveInfo.AnyValidPath: string;
  192. var
  193. Drive: TRealDrive;
  194. begin
  195. // Fallback to A:/B: if no other drive is found?
  196. for Drive := SystemDrive to LastDrive do
  197. if Get(Drive).Valid and
  198. (Get(Drive).DriveType = DRIVE_FIXED) and
  199. DirectoryExists(ApiPath(GetDriveRoot(Drive))) then
  200. begin
  201. Result := GetDriveRoot(Drive);
  202. Exit;
  203. end;
  204. for Drive := SystemDrive to LastDrive do
  205. if Get(Drive).Valid and
  206. (Get(Drive).DriveType = DRIVE_REMOTE) and
  207. DirectoryExists(ApiPath(GetDriveRoot(Drive))) then
  208. begin
  209. Result := GetDriveRoot(Drive);
  210. Exit;
  211. end;
  212. raise Exception.Create(SNoValidPath);
  213. end;
  214. function TDriveInfo.IsRealDrive(Drive: string): Boolean;
  215. begin
  216. Result := (Length(Drive) = 1);
  217. Assert((not Result) or ((Drive[1] >= FirstDrive) and (Drive[1] <= LastDrive)));
  218. end;
  219. function TDriveInfo.IsFixedDrive(Drive: string): Boolean;
  220. begin
  221. Result := True;
  222. if IsRealDrive(Drive) and (Drive[1] < FirstFixedDrive) then Result := False;
  223. end;
  224. function TDriveInfo.GetDriveKey(Path: string): string;
  225. begin
  226. Result := ExtractFileDrive(Path);
  227. if (Length(Result) = 2) and (Result[2] = DriveDelim) then
  228. begin
  229. Result := Upcase(Result[1]);
  230. end
  231. else
  232. if IsUncPath(Path) then
  233. begin
  234. Result := LowerCase(Result);
  235. end
  236. else
  237. begin
  238. raise EConvertError.Create(Format(ErrorInvalidDrive, [Path]))
  239. end;
  240. end;
  241. function TDriveInfo.GetDriveRoot(Drive: string): string;
  242. begin
  243. if IsRealDrive(Drive) then
  244. begin
  245. Result := Drive + ':\'
  246. end
  247. else
  248. begin
  249. Assert(IsUncPath(Drive));
  250. Result := IncludeTrailingBackslash(Drive);
  251. end;
  252. end;
  253. function TDriveInfo.GetFolder(Folder: TSpecialFolder): PSpecialFolderRec;
  254. var
  255. FileInfo: TShFileInfo;
  256. Path: PChar;
  257. Flags: Word;
  258. begin
  259. NeedData;
  260. Assert((Folder >= Low(FFolders)) and (Folder <= High(FFolders)));
  261. with FFolders[Folder] do
  262. begin
  263. if not Valid then
  264. begin
  265. SpecialFolderLocation(Folder, Location, PIDL);
  266. if Assigned(PIDL) then
  267. begin
  268. Path := PChar(PIDL);
  269. Flags := SHGFI_PIDL;
  270. end
  271. else
  272. begin
  273. Path := PChar(Location);
  274. Flags := 0;
  275. end;
  276. SHGetFileInfo(Path, 0, FileInfo, SizeOf(FileInfo),
  277. SHGFI_DISPLAYNAME or SHGFI_SYSICONINDEX or SHGFI_SMALLICON or Flags);
  278. ImageIndex := FileInfo.iIcon;
  279. DisplayName := FileInfo.szDisplayName;
  280. Valid := True;
  281. end;
  282. end;
  283. Result := @FFolders[Folder];
  284. end;
  285. procedure TDriveInfo.SetHonorDrivePolicy(Value: Boolean);
  286. var
  287. Drive: TRealDrive;
  288. begin
  289. if HonorDrivePolicy <> Value then
  290. begin
  291. FHonorDrivePolicy := Value;
  292. if FLoaded then
  293. begin
  294. for Drive := FirstDrive to LastDrive do
  295. begin
  296. ReadDriveBasicStatus(Drive);
  297. end;
  298. end;
  299. end;
  300. end;
  301. function TDriveInfo.GetFirstFixedDrive: Char;
  302. begin
  303. if UseABDrives then Result := FirstDrive
  304. else Result := SystemDrive;
  305. end;
  306. procedure TDriveInfo.ReadDriveBasicStatus(Drive: string);
  307. begin
  308. Assert(FData.ContainsKey(Drive));
  309. with FData[Drive] do
  310. begin
  311. DriveType := Windows.GetDriveType(PChar(GetDriveRoot(Drive)));
  312. Valid :=
  313. ((not IsRealDrive(Drive)) or (not FHonorDrivePolicy) or (not Bool((1 shl (Ord(Drive[1]) - 65)) and FNoDrives))) and
  314. (DriveType in [DRIVE_REMOVABLE, DRIVE_FIXED, DRIVE_CDROM, DRIVE_RAMDISK, DRIVE_REMOTE]);
  315. end;
  316. end;
  317. procedure TDriveInfo.ResetDrive(Drive: string);
  318. begin
  319. with FData[Drive] do
  320. begin
  321. DriveReady := False;
  322. DisplayName := '';
  323. PrettyName := '';
  324. DriveSerial := 0;
  325. Size := -1;
  326. ImageIndex := 0;
  327. end;
  328. end;
  329. procedure TDriveInfo.Load;
  330. var
  331. Drive: TRealDrive;
  332. Reg: TRegistry;
  333. Folder: TSpecialFolder;
  334. Drives: string;
  335. begin
  336. FNoDrives := 0;
  337. Reg := TRegistry.Create;
  338. try
  339. if Reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') Then
  340. Reg.ReadBinaryData('NoDrives', FNoDrives, SizeOf(FNoDrives));
  341. except
  342. try
  343. FNoDrives := Reg.ReadInteger('NoDrives');
  344. except
  345. end;
  346. end;
  347. Reg.Free;
  348. FDesktop := nil;
  349. Drives := EmptyStr;
  350. for Drive := FirstDrive to LastDrive do
  351. begin
  352. if AddDrive(Drive).Valid then
  353. Drives := Drives + Drive;
  354. end;
  355. if Length(Drives) > 0 then
  356. TDriveInfoThread.Create(Drives);
  357. for Folder := Low(FFolders) to High(FFolders) do
  358. FFolders[Folder].Valid := False;
  359. end;
  360. function TDriveInfo.AddDrive(Drive: string): TDriveInfoRec;
  361. begin
  362. Result := TDriveInfoRec.Create;
  363. FData.Add(Drive, Result);
  364. ResetDrive(Drive);
  365. ReadDriveBasicStatus(Drive);
  366. end;
  367. function TDriveInfo.GetImageIndex(Drive: string): Integer;
  368. begin
  369. NeedData;
  370. Result := 0;
  371. if Get(Drive).Valid then
  372. begin
  373. if Get(Drive).ImageIndex = 0 then
  374. ReadDriveStatus(Drive, dsImageIndex);
  375. Result := Get(Drive).ImageIndex;
  376. end;
  377. end; {TDriveInfo.GetImageIndex}
  378. function TDriveInfo.GetDisplayName(Drive: string): string;
  379. begin
  380. if Get(Drive).Valid then
  381. begin
  382. if Length(Get(Drive).DisplayName) = 0 then
  383. ReadDriveStatus(Drive, dsDisplayName);
  384. Result := Get(Drive).DisplayName;
  385. end
  386. else
  387. begin
  388. Result := GetSimpleName(Drive);
  389. end;
  390. end; {TDriveInfo.GetDisplayname}
  391. function TDriveInfo.GetPrettyName(Drive: string): string;
  392. begin
  393. if Get(Drive).Valid then
  394. begin
  395. if Length(Get(Drive).PrettyName) = 0 then
  396. ReadDriveStatus(Drive, dsDisplayName);
  397. Result := Get(Drive).PrettyName;
  398. end
  399. else
  400. begin
  401. Result := GetSimpleName(Drive);
  402. end;
  403. end; {TDriveInfo.GetPrettyName}
  404. function TDriveInfo.GetSimpleName(Drive: string): string;
  405. begin
  406. Result := Drive;
  407. if IsRealDrive(Result) then Result := Result + ':';
  408. end;
  409. function TDriveInfo.Get(Drive: string): TDriveInfoRec;
  410. begin
  411. NeedData;
  412. if not FData.TryGetValue(Drive, Result) then
  413. begin
  414. Assert(IsUncPath(Drive));
  415. Result := AddDrive(Drive);
  416. end;
  417. end; {TDriveInfo.GetData}
  418. function TDriveInfo.ReadDriveStatus(Drive: string; Flags: Integer): Boolean;
  419. var
  420. ErrorMode: Word;
  421. FileInfo: TShFileInfo;
  422. DriveRoot: string;
  423. DriveID: string;
  424. CPos: Integer;
  425. Eaten: ULONG;
  426. ShAttr: ULONG;
  427. MaxFileNameLength: DWORD;
  428. FileSystemFlags: DWORD;
  429. FreeSpace: Int64;
  430. SimpleName: string;
  431. DriveInfoRec: TDriveInfoRec;
  432. S: string;
  433. begin
  434. // Among other, this makes sure the pending drive-ready status from the background thread are collected,
  435. // before we overwrite it with fresh status here.
  436. NeedData;
  437. if not Assigned(FDesktop) then
  438. SHGetDesktopFolder(FDesktop);
  439. DriveRoot := GetDriveRoot(Drive);
  440. // When this method is called, the entry always exists already
  441. Assert(FData.ContainsKey(Drive));
  442. DriveInfoRec := FData[Drive];
  443. with DriveInfoRec do
  444. begin
  445. Init := True;
  446. ReadDriveBasicStatus(Drive);
  447. if Valid then
  448. begin
  449. if (not Assigned(PIDL)) and IsFixedDrive(Drive) then
  450. begin
  451. ShAttr := 0;
  452. if DriveType = DRIVE_REMOTE then
  453. begin
  454. ShellFolderParseDisplayNameWithTimeout(
  455. FDesktop, Application.Handle, nil, PChar(DriveRoot), Eaten, PIDL, ShAttr, 2 * MSecsPerSec);
  456. end
  457. else
  458. begin
  459. FDesktop.ParseDisplayName(Application.Handle, nil, PChar(DriveRoot), Eaten, PIDL, ShAttr);
  460. end;
  461. end;
  462. {Read driveStatus:}
  463. if (Flags and dsSize) <> 0 then
  464. begin
  465. { turn off critical errors }
  466. ErrorMode := SetErrorMode(SEM_FailCriticalErrors or SEM_NOOPENFILEERRORBOX);
  467. try
  468. DriveReady := GetDiskFreeSpaceEx(PChar(DriveRoot), FreeSpace, Size, nil);
  469. if DriveReady then
  470. begin
  471. {Access the physical drive:}
  472. if GetVolumeInformation(PChar(DriveRoot), nil, 0,
  473. @DriveSerial, MaxFileNameLength, FileSystemFlags,
  474. nil, 0) then
  475. begin
  476. end
  477. else
  478. begin
  479. DriveSerial := 0;
  480. end;
  481. end
  482. else
  483. begin
  484. DriveSerial := 0;
  485. end;
  486. finally
  487. { restore old error mode }
  488. SetErrorMode(ErrorMode);
  489. end;
  490. end;
  491. {DisplayName:}
  492. if (Flags and dsDisplayName) <> 0 then
  493. begin
  494. {Fetch drives displayname:}
  495. SimpleName := GetSimpleName(Drive);
  496. if Assigned(PIDL) then DisplayName := GetShellFileName(PIDL)
  497. else
  498. begin
  499. // typical reason we do not have PIDL is that it took too long to
  500. // call ParseDisplayName, in what case calling SHGetFileInfo with
  501. // path (instead of PIDL) will take long too, avoiding that and using
  502. // fallback
  503. DisplayName := '(' + SimpleName + ')';
  504. end;
  505. if DriveType <> DRIVE_REMOTE then
  506. begin
  507. PrettyName := SimpleName + ' ' + DisplayName;
  508. S := ' (' + SimpleName + ')';
  509. CPos := Pos(S, PrettyName);
  510. if CPos > 0 then
  511. Delete(PrettyName, CPos, Length(S));
  512. end
  513. else
  514. if IsRealDrive(Drive) then
  515. begin
  516. DriveID := GetNetWorkName(Drive);
  517. PrettyName := Format('%s %s (%s)', [SimpleName, ExtractFileName(DriveID), ExtractFileDir(DriveID)]);
  518. end
  519. else
  520. begin
  521. Assert(IsUncPath(DriveRoot));
  522. PrettyName := SimpleName;
  523. end;
  524. end;
  525. {ImageIndex:}
  526. if (Flags and dsImageIndex) <> 0 then
  527. begin
  528. if Assigned(PIDL) then
  529. begin
  530. SHGetFileInfo(PChar(PIDL), 0, FileInfo, SizeOf(FileInfo), SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_PIDL)
  531. end
  532. else
  533. begin
  534. SHGetFileInfo(PChar(DriveRoot), 0, FileInfo, SizeOf(FileInfo), SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
  535. end;
  536. ImageIndex := FileInfo.iIcon;
  537. end;
  538. end
  539. else
  540. begin
  541. if Assigned(PIDL) then
  542. FreePIDL(PIDL);
  543. ResetDrive(Drive);
  544. end;
  545. Result := Valid and DriveReady;
  546. end;
  547. end; {TDriveInfo.ReadDriveStatus}
  548. function GetShellFileName(const Name: string): string;
  549. var
  550. SFI: TSHFileInfo;
  551. E: Integer;
  552. begin
  553. E := SetErrorMode(SEM_FAILCRITICALERRORS);
  554. try
  555. if SHGetFileInfo(PChar(Name), 0, SFI, SizeOf(TSHFileInfo), SHGFI_DISPLAYNAME) <> 0 then
  556. Result := SFI.szDisplayName;
  557. finally
  558. SetErrorMode(E);
  559. end;
  560. end; {GetShellFileName}
  561. function GetShellFileName(PIDL: PItemIDList): string;
  562. var
  563. SFI: TSHFileInfo;
  564. E: Integer;
  565. begin
  566. E := SetErrorMode(SEM_FAILCRITICALERRORS);
  567. try
  568. if SHGetFileInfo(PChar(PIDL), 0, SFI, SizeOf(TSHFileInfo), SHGFI_PIDL or SHGFI_DISPLAYNAME) <> 0 then
  569. Result := SFI.szDisplayName;
  570. finally
  571. SetErrorMode(E);
  572. end;
  573. end; {GetShellFileName}
  574. function GetNetWorkName(Drive: string): string;
  575. var
  576. Path: string;
  577. P: array[0..MAX_PATH] of Char;
  578. MaxLen : DWORD;
  579. begin
  580. Path := ExcludeTrailingBackslash(DriveInfo.GetDriveRoot(Drive));
  581. MaxLen := MAX_PATH;
  582. if WNetGetConnection(PChar(Path), P, MaxLen) = NO_ERROR then
  583. Result := P
  584. else
  585. Result := '';
  586. end; {GetNetWorkName}
  587. type
  588. LPBYTE = ^BYTE;
  589. LMSTR = LPWSTR;
  590. NET_API_STATUS = DWORD;
  591. _USE_INFO_1 = record
  592. ui1_local: LMSTR;
  593. ui1_remote: LMSTR;
  594. ui1_password: LMSTR;
  595. ui1_status: DWORD;
  596. ui1_asg_type: DWORD;
  597. ui1_refcount: DWORD;
  598. ui1_usecount: DWORD;
  599. end;
  600. USE_INFO_1 = _USE_INFO_1;
  601. PUSE_INFO_1 = ^USE_INFO_1;
  602. LPVOID = Pointer;
  603. const
  604. USE_OK = 0;
  605. USE_PAUSED = 1;
  606. USE_SESSLOST = 2;
  607. USE_DISCONN = 2;
  608. USE_NETERR = 3;
  609. USE_CONN = 4;
  610. USE_RECONN = 5;
  611. function NetUseGetInfo(UncServerName: LMSTR; UseName: LMSTR; Level: DWORD; var BufPtr: LPBYTE): NET_API_STATUS; stdcall; external 'netapi32.dll';
  612. function NetApiBufferFree(Buffer: Pointer): DWORD; stdcall; external 'netapi32.dll';
  613. function GetNetWorkConnected(Drive: string): Boolean;
  614. var
  615. BufPtr: LPBYTE;
  616. NetResult: Integer;
  617. ServerName: string;
  618. PServerName: PChar;
  619. Name: string;
  620. P: Integer;
  621. begin
  622. Name := '';
  623. PServerName := nil;
  624. if DriveInfo.IsRealDrive(Drive) then
  625. begin
  626. Name := Drive + ':';
  627. end
  628. else
  629. if IsUncPath(Drive) then
  630. begin
  631. Name := Copy(Drive, 3, Length(Drive) - 2);
  632. P := Pos('\', Name);
  633. if P > 0 then
  634. begin
  635. ServerName := Copy(Name, P + 1, Length(Name) - P);
  636. PServerName := PChar(ServerName);
  637. SetLength(Name, P - 1);
  638. end
  639. else
  640. begin
  641. Assert(False);
  642. end;
  643. end
  644. else
  645. begin
  646. Assert(False);
  647. end;
  648. if Name = '' then
  649. begin
  650. Result := False;
  651. end
  652. else
  653. begin
  654. NetResult := NetUseGetInfo(PServerName, PChar(Name), 1, BufPtr);
  655. if NetResult = 0 then
  656. begin
  657. Result := (PUSE_INFO_1(BufPtr)^.ui1_status = USE_OK);
  658. NetApiBufferFree(LPVOID(BufPtr));
  659. end
  660. else
  661. begin
  662. // NetUseGetInfo works for DFS shares only, hence when it fails
  663. // we suppose different share type and fallback to "connected"
  664. Result := True;
  665. end;
  666. end;
  667. end;
  668. function IsRootPath(Path: string): Boolean;
  669. begin
  670. Result := SameText(ExcludeTrailingBackslash(ExtractFileDrive(Path)), ExcludeTrailingBackslash(Path));
  671. end;
  672. initialization
  673. InitializeCriticalSection(ThreadLock);
  674. if not Assigned(DriveInfo) then
  675. DriveInfo := TDriveInfo.Create;
  676. finalization
  677. if Assigned(DriveInfo) then
  678. begin
  679. DriveInfo.Free;
  680. DriveInfo := nil;
  681. end;
  682. DeleteCriticalSection(ThreadLock);
  683. end.