PageRenderTime 64ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/FileGuard/MainUnit.pas

http://github.com/rofl0r/KOL
Pascal | 1586 lines | 1436 code | 66 blank | 84 comment | 79 complexity | bc7ff66d053fa47f9f9a7475a22e1640 MD5 | raw file
  1. { KOL MCK } // Do not remove this line!
  2. {$DEFINE KOL_MCK}
  3. unit MainUnit;
  4. interface
  5. {$IFDEF KOL_MCK}
  6. uses Windows, Messages, ShellAPI, KOL, KOLMHXP {$IFNDEF KOL_MCK}, MCKMHXP, mirror, Classes, Controls, mckControls, mckObjs, Graphics, mckCtrls {$ENDIF}, MultiDirsChange, FileVersionUnit, err;
  7. {$ELSE}
  8. {$I uses.inc}
  9. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  10. Dialogs;
  11. {$ENDIF}
  12. //const Registry = 'Software\Bonanzas\FileGuard\';
  13. const
  14. WM_USER_HIDE = WM_USER + 111;
  15. type
  16. {$IFDEF KOL_MCK}
  17. {$I MCKfakeClasses.inc}
  18. {$IFDEF KOLCLASSES} TfmMainGuard = class; PfmMainGuard = TfmMainGuard; {$ELSE OBJECTS} PfmMainGuard = ^TfmMainGuard; {$ENDIF CLASSES/OBJECTS}
  19. {$IFDEF KOLCLASSES}{$I TfmMainGuard.inc}{$ELSE} TfmMainGuard = object(TObj) {$ENDIF}
  20. Form: PControl;
  21. {$ELSE not_KOL_MCK}
  22. TfmMainGuard = class(TForm)
  23. {$ENDIF KOL_MCK}
  24. KOLProject1: TKOLProject;
  25. TrayIcon1: TKOLTrayIcon;
  26. Panel1: TKOLPanel;
  27. lStatus: TKOLLabel;
  28. bExit: TKOLButton;
  29. KOLApplet1: TKOLApplet;
  30. pm1: TKOLPopupMenu;
  31. tc1: TKOLTabControl;
  32. TabControl1_Tab0: TKOLPanel;
  33. TabControl1_Tab1: TKOLPanel;
  34. TabControl1_Tab2: TKOLPanel;
  35. Memo1: TKOLMemo;
  36. Panel2: TKOLPanel;
  37. eStoragePath: TKOLEditBox;
  38. bBrowseStorage: TKOLButton;
  39. dSelStorage: TKOLOpenDirDialog;
  40. Panel3: TKOLPanel;
  41. Toolbar1: TKOLToolbar;
  42. ImageList1: TKOLImageList;
  43. lv1: TKOLListView;
  44. tc1_Tab3: TKOLPanel;
  45. lLink: TKOLLabel;
  46. Panel4: TKOLPanel;
  47. ImageShow1: TKOLImageShow;
  48. ImageList2: TKOLImageList;
  49. Panel5: TKOLPanel;
  50. LabelEffect1: TKOLLabelEffect;
  51. LabelEffect2: TKOLLabelEffect;
  52. Panel6: TKOLPanel;
  53. lDescription_About: TKOLLabel;
  54. Panel7: TKOLPanel;
  55. lStorageStatus: TKOLLabel;
  56. tvDirs: TKOLTreeView;
  57. lvFiles: TKOLListView;
  58. Splitter1: TKOLSplitter;
  59. ImageList3: TKOLImageList;
  60. pm2: TKOLPopupMenu;
  61. pm3: TKOLPopupMenu;
  62. KOLForm1: TKOLForm;
  63. TimerHide: TKOLTimer;
  64. pnLogInfo: TKOLPanel;
  65. cDetailed: TKOLCheckBox;
  66. lQueued: TKOLLabel;
  67. MHXP1: TKOLMHXP;
  68. TimerCheckConnect: TKOLTimer;
  69. ThreadRescanStorageTree: TKOLThread;
  70. procedure TrayIcon1Mouse(Sender: PObj; Message: Word);
  71. procedure pm1pmStateMenu(Sender: PMenu; Item: Integer);
  72. procedure KOLForm1Close(Sender: PObj; var Accept: Boolean);
  73. procedure bExitClick(Sender: PObj);
  74. procedure pm1pmExitMenu(Sender: PMenu; Item: Integer);
  75. procedure bBrowseStorageClick(Sender: PObj);
  76. procedure KOLForm1Destroy(Sender: PObj);
  77. procedure KOLForm1Show(Sender: PObj);
  78. procedure KOLForm1FormCreate(Sender: PObj);
  79. procedure eStoragePathChange(Sender: PObj);
  80. procedure lv1LVData(Sender: PControl; Idx, SubItem: Integer;
  81. var Txt: String; var ImgIdx: Integer; var State: Cardinal;
  82. var Store: Boolean);
  83. procedure Toolbar1TBAddClick(Sender: PControl; BtnID: Integer);
  84. procedure lv1LVStateChange(Sender: PControl; IdxFrom, IdxTo: Integer;
  85. OldState, NewState: Cardinal);
  86. procedure Toolbar1TBEditClick(Sender: PControl; BtnID: Integer);
  87. procedure Toolbar1TBDelClick(Sender: PControl; BtnID: Integer);
  88. procedure Toolbar1TBUpClick(Sender: PControl; BtnID: Integer);
  89. procedure Toolbar1TBDnClick(Sender: PControl; BtnID: Integer);
  90. procedure lv1MouseDblClk(Sender: PControl; var Mouse: TMouseEventData);
  91. procedure lv1KeyDown(Sender: PControl; var Key: Integer;
  92. Shift: Cardinal);
  93. procedure lLinkMouseEnter(Sender: PObj);
  94. procedure lLinkMouseLeave(Sender: PObj);
  95. procedure lLinkClick(Sender: PObj);
  96. procedure lvFilesLVData(Sender: PControl; Idx, SubItem: Integer;
  97. var Txt: String; var ImgIdx: Integer; var State: Cardinal;
  98. var Store: Boolean);
  99. procedure tvDirsSelChange(Sender: PObj);
  100. procedure pm2pmHistoryMenu(Sender: PMenu; Item: Integer);
  101. procedure pm2pmRestoreMenu(Sender: PMenu; Item: Integer);
  102. procedure pm3pmDirRestoreMenu(Sender: PMenu; Item: Integer);
  103. procedure KOLForm1Minimize(Sender: PObj);
  104. procedure TimerHideTimer(Sender: PObj);
  105. procedure lvFilesLVStateChange(Sender: PControl; IdxFrom,
  106. IdxTo: Integer; OldState, NewState: Cardinal);
  107. procedure pm3pmDirOpenMenu(Sender: PMenu; Item: Integer);
  108. procedure lvFilesMouseDblClk(Sender: PControl;
  109. var Mouse: TMouseEventData);
  110. procedure lvFilesKeyDown(Sender: PControl; var Key: Integer;
  111. Shift: Cardinal);
  112. procedure TimerCheckConnectTimer(Sender: PObj);
  113. function ThreadRescanStorageTreeExecute(Sender: PThread): Integer;
  114. private
  115. { Private declarations }
  116. LastChanged: String;
  117. procedure DirChanged( Sender: PObj; const Path: string; CheckFirstTime: Boolean = FALSE ); overload;
  118. procedure DirChanged( Sender: PObj; const Path: string ); overload;
  119. procedure AddToTree( Tree: PTree; const Path: String; WithSubdirs: Boolean );
  120. public
  121. { Public declarations }
  122. WantClose: Boolean;
  123. AdminMessage: Boolean;
  124. Restricted: Boolean;
  125. StorageOK: Boolean;
  126. MonitorList: PStrListEx;
  127. FiltersList: PStrListEx;
  128. AnyDirsChange: PAnyDirsChange;
  129. TreeDirs: PTree;
  130. LastUCLProgress: DWORD;
  131. procedure DoExit;
  132. procedure ShowStatus;
  133. procedure SaveSettings;
  134. procedure EnableCommands;
  135. procedure PrepareTree;
  136. procedure UCLOnProgress( const Sender: PObj; const InBytes, OutBytes: Cardinal );
  137. procedure AcceptDirItem( Sender: PObj; var FindData: TWin32FindData;
  138. var Action: TDirItemAction );
  139. public
  140. DirChangesQueue: PStrListEx;
  141. procedure IdleEvent( Sender: PObj );
  142. procedure HandleDirChanges( const Path: String; FirstHandling: Boolean );
  143. procedure HandleFileChange( const FilePath: String; Action: Integer );
  144. public
  145. StorageChanged, StorageTreeChanged: Boolean;
  146. Directory: PStrListEx;
  147. Directory_Path, Directory_Root, Directory_Prefix: String;
  148. procedure RebuildStorageTree;
  149. procedure AddPathToTVDirs( DirPath: String; Obj: Integer );
  150. procedure ClearDirectory;
  151. procedure CollectAllVersionsInfo( FileStream: PStream; const FI: TFileVersionInfo;
  152. SecType: Byte; SecLen: DWORD; var Cont: Boolean );
  153. procedure RestoreFiles( FileList: PStrList );
  154. procedure AddFilesFromSubdirs( SL: PStrList; Node: THandle;
  155. SubdirsRecursively: Boolean );
  156. public
  157. VerDate: TDateTime;
  158. VersionFile: PStream;
  159. VerIdx: Integer;
  160. VerFileName: String;
  161. procedure RestoreForDate( FileStream: PStream; const FI: TFileVersionInfo;
  162. SecType: Byte; SecLen: DWORD; var Cont: Boolean );
  163. procedure RestoreSubdirs( Sender: PObj );
  164. procedure RestoreSelected( Sender: PObj );
  165. procedure ViewFile;
  166. procedure ShowQueued;
  167. end;
  168. var
  169. fmMainGuard {$IFDEF KOL_MCK} : PfmMainGuard {$ELSE} : TfmMainGuard {$ENDIF} ;
  170. {$IFDEF KOL_MCK}
  171. procedure NewfmMainGuard( var Result: PfmMainGuard; AParent: PControl );
  172. {$ENDIF}
  173. procedure Log( const S: String );
  174. function DoApplyUpdates( Strm1, Strm2, Strm3: PStream ): Boolean;
  175. implementation
  176. uses EditFilterUnit, StorageUnit, HistoryUnit, RestoreUnit, DIUCLStreams,
  177. UpdatesUnit;
  178. function DoApplyUpdates( Strm1, Strm2, Strm3: PStream ): Boolean;
  179. begin
  180. Result := TRUE;
  181. TRY
  182. ApplyUpdates( Strm1, Strm2, Strm3, Storage.ProgressHandler );
  183. EXCEPT
  184. Result := FALSE;
  185. END;
  186. end;
  187. type
  188. PDirData = ^TDirData;
  189. TDirData = packed record
  190. FT: TFileTime;
  191. Sz: DWORD;
  192. TotalSz: DWORD;
  193. end;
  194. procedure Log(const S: String);
  195. var L: Integer;
  196. SL: PStrList;
  197. I: Integer;
  198. T: String;
  199. begin
  200. T := DateTime2StrShort( Now ) + ' ';
  201. if not StrIsStartingFrom( PChar( S ), '-' ) then
  202. LogFileOutput( GetStartDir + 'fileguard.log', T + S );
  203. if StrIsStartingFrom( PChar( S ), '-' ) and not fmMainGuard.cDetailed.Checked then Exit;
  204. L := fmMainGuard.Memo1.TextSize;
  205. if L > 16384 then
  206. begin
  207. SL := NewStrList;
  208. SL.Text := fmMainGuard.Memo1.Text;
  209. I := SL.Count div 2;
  210. for I := 1 to I do
  211. SL.Delete( 0 );
  212. fmMainGuard.Memo1.Text := SL.Text;
  213. SL.Free;
  214. L := fmMainGuard.Memo1.TextSize;
  215. end;
  216. fmMainGuard.Memo1.Add( T + S + #13#10 );
  217. fmMainGuard.Memo1.SelStart := L;
  218. fmMainGuard.Memo1.Perform( EM_SCROLLCARET, 0, 0 );
  219. end;
  220. {$IFNDEF KOL_MCK} {$R *.DFM} {$ENDIF}
  221. {$IFDEF KOL_MCK}
  222. {$I MainUnit_1.inc}
  223. {$ENDIF}
  224. procedure TfmMainGuard.TrayIcon1Mouse(Sender: PObj; Message: Word);
  225. var P: TPoint;
  226. begin
  227. CASE Message OF
  228. WM_LBUTTONDOWN:
  229. begin
  230. Applet.Show;
  231. if Applet.WindowState = wsMinimized then
  232. AppletRestore;
  233. Form.Show;
  234. end;
  235. WM_RBUTTONUP:
  236. begin
  237. GetCursorPos( P );
  238. pm1.PopupEx( P.X, P.Y );
  239. end;
  240. END;
  241. end;
  242. procedure TfmMainGuard.pm1pmStateMenu(Sender: PMenu; Item: Integer);
  243. begin
  244. Applet.Show;
  245. if Applet.WindowState = wsMinimized then
  246. AppletRestore;
  247. Form.Show;
  248. end;
  249. procedure TfmMainGuard.KOLForm1Close(Sender: PObj; var Accept: Boolean);
  250. begin
  251. Accept := FALSE;
  252. Applet.Visible := FALSE;
  253. Form.Hide;
  254. end;
  255. procedure TfmMainGuard.bExitClick(Sender: PObj);
  256. begin
  257. WantClose := TRUE;
  258. DoExit;
  259. end;
  260. procedure TfmMainGuard.DoExit;
  261. begin
  262. PostQuitMessage( 0 );
  263. end;
  264. procedure TfmMainGuard.pm1pmExitMenu(Sender: PMenu; Item: Integer);
  265. begin
  266. DoExit;
  267. end;
  268. procedure TfmMainGuard.bBrowseStorageClick(Sender: PObj);
  269. var S: String;
  270. begin
  271. if dSelStorage.Execute then
  272. begin
  273. S := dSelStorage.Path;
  274. eStoragePath.Text := S;
  275. end;
  276. end;
  277. procedure TfmMainGuard.KOLForm1Destroy(Sender: PObj);
  278. begin
  279. SaveSettings;
  280. AnyDirsChange.Clear;
  281. Sleep( 200 );
  282. MonitorList.Free;
  283. FiltersList.Free;
  284. DirChangesQueue.Free;
  285. ClearDirectory;
  286. LastChanged := '';
  287. if ThreadRescanStorageTree.Suspended then
  288. ThreadRescanStorageTree.Resume;
  289. ThreadRescanStorageTree.WaitFor;
  290. end;
  291. procedure TfmMainGuard.KOLForm1Show(Sender: PObj);
  292. var R: TRect;
  293. begin
  294. Toolbar1.Perform( TB_SETROWS, 1 shl 16, Integer( @ R ) );
  295. //
  296. //Applet.Font.FontName := 'Arial';
  297. //Applet.Font.FontHeight := 16;
  298. end;
  299. {var R: THandle;
  300. begin
  301. R := RegKeyOpenCreate( HKEY_LOCAL_MACHINE, Registry );
  302. if R = 0 then
  303. begin
  304. if not AdminMessage then
  305. begin
  306. AdminMessage := TRUE;
  307. ShowMessage( 'You must have administrator rights to change settings!' );
  308. end;
  309. Restricted := TRUE;
  310. Exit;
  311. end;
  312. RegKeyClose( R );
  313. end;}
  314. procedure TfmMainGuard.KOLForm1FormCreate(Sender: PObj);
  315. var //R: THandle;
  316. I: Integer;
  317. S: String;
  318. C: Char;
  319. Ini: PIniFile;
  320. begin
  321. SetPriorityClass( GetCurrentProcess, IDLE_PRIORITY_CLASS );
  322. tc1.CurIndex := 0;
  323. lDescription_About.Caption := 'Automatic Backup Files System. ' +
  324. 'Monitors changes in specified directories and for files satisfying to ' +
  325. 'specified filters performs specified action. It is possible to provide ' +
  326. 'saving last modified version only or save entire history of changes for ' +
  327. 'certain kinds of files. Either a directory on another HDD, or network ' +
  328. 'shared folder can be used as a storage for saved files.';
  329. Directory := NewStrListEx;
  330. new( Storage, Create );
  331. DirChangesQueue := NewStrListEx;
  332. AnyDirsChange := NewAnyDirsChange( DirChanged, FILE_NOTIFY_CHANGE_FILE_NAME or
  333. FILE_NOTIFY_CHANGE_DIR_NAME or
  334. FILE_NOTIFY_CHANGE_SIZE or
  335. FILE_NOTIFY_CHANGE_LAST_WRITE );
  336. MonitorList := NewStrListEx;
  337. FiltersList := NewStrListEx;
  338. TreeDirs := NewTree( nil, '' );
  339. for C := 'A' to 'Z' do
  340. NewTree( TreeDirs, C + ':' );
  341. Ini := OpenIniFile( GetStartDir + 'fileguard.ini' );
  342. TRY
  343. Ini.Section := 'Main';
  344. I := Ini.ValueInteger( 'DirCount', 0 );
  345. for I := 1 to I do
  346. begin
  347. S := Ini.ValueString( 'Dir' + Int2Str( I ), '' );
  348. if S = '' then continue;
  349. S := IncludeTrailingPathDelimiter( S );
  350. MonitorList.AddObject( S, Ini.ValueInteger( 'Action' + Int2Str( I ), 0 ) );
  351. S := Ini.ValueString( 'Filter' + Int2Str( I ), '*.*' );
  352. FiltersList.AddObject( S, Ini.ValueInteger( 'Time' + Int2Str( I ), 0 ) );
  353. end;
  354. lv1.LVCount := MonitorList.Count;
  355. eStoragePath.Text := Ini.ValueString( 'Storage', '' );
  356. Storage.Path := eStoragePath.Text;
  357. ShowStatus;
  358. PrepareTree;
  359. FINALLY
  360. Ini.Free;
  361. END;
  362. {R := RegKeyOpenRead( HKEY_LOCAL_MACHINE, Registry );
  363. TRY
  364. I := RegKeyGetDw( R, 'DirCount' );
  365. for I := 1 to I do
  366. begin
  367. S := RegKeyGetStr( R, 'Dir' + Int2Str( I ) );
  368. S := IncludeTrailingPathDelimiter( S );
  369. MonitorList.AddObject( S, RegKeyGetDw( R, 'Action' + Int2Str( I ) ) );
  370. S := RegKeyGetStr( R, 'Filter' + Int2Str( I ) );
  371. FiltersList.AddObject( S, RegKeyGetDw( R, 'Time' + Int2Str( I ) ) );
  372. end;
  373. lv1.LVCount := MonitorList.Count;
  374. eStoragePath.Text := RegKeyGetStr( R, 'Storage' );
  375. Storage.Path := eStoragePath.Text;
  376. ShowStatus;
  377. PrepareTree;
  378. FINALLY
  379. RegKeyClose( R );
  380. END;}
  381. RegisterIdleHandler( IdleEvent );
  382. end;
  383. procedure TfmMainGuard.eStoragePathChange(Sender: PObj);
  384. var S: String;
  385. OK: Boolean;
  386. F: HFile;
  387. Buffer: array[ 0..1023 ] of Char;
  388. E: Boolean;
  389. begin
  390. OK := TRUE;
  391. lStorageStatus.Caption := '';
  392. S := eStoragePath.Text;
  393. E := DirectoryExists( S );
  394. if E or
  395. (pos( ':', S ) > 0) and (Length( S ) <= 3) and (S <> '') and
  396. (S[ 1 ] in [ 'a'..'z', 'A'..'Z' ]) and (S[ 3 ] = '\') then
  397. begin
  398. if StrIsStartingFrom( PChar( S ), '\\' ) then
  399. begin
  400. // сетевая директория - проверить, что запись туда возможна...
  401. F := FileCreate( S + 'test.file', ofOpenWrite or ofOpenAlways );
  402. if F = INVALID_HANDLE_VALUE then OK := FALSE
  403. else
  404. TRY
  405. FillChar( Buffer, Sizeof( Buffer ), 255 );
  406. if FileWrite( F, Buffer, Sizeof( Buffer ) ) <> Sizeof( Buffer ) then
  407. OK := FALSE;
  408. FINALLY
  409. FileClose( F );
  410. END;
  411. if not OK then
  412. begin
  413. if E then
  414. lStorageStatus.Caption := 'Access denied'
  415. else
  416. lStorageStatus.Caption := 'Disconnected';
  417. TimerCheckConnect.Enabled := TRUE;
  418. end;
  419. end
  420. else
  421. if pos( ':', S ) = 2 then
  422. begin
  423. CASE GetDriveType( PChar( Copy( S, 1, 2 ) + '\' ) ) OF
  424. DRIVE_UNKNOWN: ShowMessage( 'Drive ' + S[ 1 ] + ' unknown. Saving will be ' +
  425. 'performed as to the another HDD or to shared network folder.' );
  426. DRIVE_REMOVABLE, DRIVE_FIXED, DRIVE_REMOTE:
  427. begin
  428. //todo: проверить, что это не тот же самый диск, который мониторируется
  429. end;
  430. DRIVE_CDROM:
  431. begin
  432. lStorageStatus.Caption := 'Storing on CD-ROM not supported!';
  433. OK := FALSE;
  434. end;
  435. DRIVE_RAMDISK:
  436. begin
  437. lStorageStatus.Caption := 'Storing on RAM-disk has no sense!';
  438. OK := FALSE;
  439. end;
  440. else
  441. begin
  442. lStorageStatus.Caption := 'This kind of storage can not be used!';
  443. OK := FALSE;
  444. end;
  445. END;
  446. end;
  447. end
  448. else
  449. begin
  450. if StrIsStartingFrom( PChar( S ), '\\' ) then
  451. begin
  452. lStorageStatus.Caption := 'Disconnected';
  453. TimerCheckConnect.Enabled := TRUE;
  454. end;
  455. OK := FALSE;
  456. end;
  457. StorageOK := OK;
  458. if OK then
  459. begin
  460. lStorageStatus.Caption := 'Storage OK.';
  461. StorageChanged := TRUE;
  462. StorageTreeChanged := TRUE;
  463. ShowStatus;
  464. SaveSettings;
  465. Storage.Path := eStoragePath.Text;
  466. PrepareTree;
  467. end;
  468. ShowStatus;
  469. end;
  470. procedure TfmMainGuard.ShowStatus;
  471. var S: String;
  472. begin
  473. if StorageOK then
  474. S := eStoragePath.Text
  475. else
  476. S := '<not set>';
  477. lStatus.Caption := 'Monitored: ' + Int2Str( MonitorList.Count ) + ' dirs ' +
  478. 'Storage: ' + S;
  479. end;
  480. procedure TfmMainGuard.lv1LVData(Sender: PControl; Idx, SubItem: Integer;
  481. var Txt: String; var ImgIdx: Integer; var State: Cardinal;
  482. var Store: Boolean);
  483. begin
  484. CASE SubItem OF
  485. 0: Txt := MonitorList.Items[ Idx ];
  486. 1: Txt := FiltersList.Items[ Idx ];
  487. 2: Txt := Int2Str( FiltersList.Objects[ Idx ] );
  488. END;
  489. ImgIdx := MonitorList.Objects[ Idx ] and 3;
  490. if MonitorList.Objects[ Idx ] and 4 <> 0 then
  491. State := (3+1) shl 12;
  492. Store := FALSE;
  493. end;
  494. procedure TfmMainGuard.Toolbar1TBAddClick(Sender: PControl;
  495. BtnID: Integer);
  496. begin
  497. if fmEditFilter = nil then
  498. NewfmEditFilter( fmEditFilter, Applet );
  499. fmEditFilter.Operation := -1;
  500. fmEditFilter.Form.Show;
  501. //fmEditFilter.Form.Hide;
  502. end;
  503. procedure TfmMainGuard.SaveSettings;
  504. var //R: THandle;
  505. I: Integer;
  506. Ini: PIniFile;
  507. begin
  508. Ini := OpenIniFile( GetStartDir + 'fileguard.ini' );
  509. TRY
  510. Ini.Section := 'Main';
  511. Ini.Mode := ifmWrite;
  512. Ini.ValueString( 'Storage', eStoragePath.Text );
  513. Ini.ValueInteger( 'DirCount', MonitorList.Count );
  514. for I := 0 to MonitorList.Count-1 do
  515. begin
  516. Ini.ValueString( 'Dir' + Int2Str( I+1 ), MonitorList.Items[ I ] );
  517. Ini.ValueString( 'Filter' + Int2Str( I+1 ), FiltersList.Items[ I ] );
  518. Ini.ValueInteger( 'Action' + Int2Str( I+1 ), MonitorList.Objects[ I ] );
  519. Ini.ValueInteger( 'Time' + Int2Str( I+1 ), FiltersList.Objects[ I ] );
  520. end;
  521. FINALLY
  522. Ini.Free;
  523. END;
  524. {R := RegKeyOpenCreate( HKEY_LOCAL_MACHINE, Registry );
  525. if R = 0 then Exit;
  526. TRY
  527. RegKeySetStr( R, 'Storage', eStoragePath.Text );
  528. RegKeySetDw( R, 'DirCount', MonitorList.Count );
  529. for I := 0 to MonitorList.Count-1 do
  530. begin
  531. RegKeySetStr( R, 'Dir' + Int2Str( I+1 ), MonitorList.Items[ I ] );
  532. RegKeySetStr( R, 'Filter' + Int2Str( I+1 ), FiltersList.Items[ I ] );
  533. RegKeySetDw( R, 'Action' + Int2Str( I+1 ), MonitorList.Objects[ I ] );
  534. RegKeySetDw( R, 'Time' + Int2Str( I+1 ), FiltersList.Objects[ I ] );
  535. end;
  536. FINALLY
  537. RegKeyClose( R );
  538. END;}
  539. end;
  540. procedure TfmMainGuard.EnableCommands;
  541. begin
  542. //Toolbar1.TBButtonEnabled[ TBAdd ] := TRUE;
  543. Toolbar1.TBButtonEnabled[ TBEdit ] := lv1.LVCurItem >= 0;
  544. Toolbar1.TBButtonEnabled[ TBDel ] := lv1.LVCurItem >= 0;
  545. Toolbar1.TBButtonEnabled[ TBUp ] := lv1.LVCurItem > 0;
  546. Toolbar1.TBButtonEnabled[ TBDn ] := (lv1.LVCurItem >= 0)
  547. and (lv1.LVCurItem < lv1.LVCount - 1);
  548. end;
  549. procedure TfmMainGuard.lv1LVStateChange(Sender: PControl; IdxFrom,
  550. IdxTo: Integer; OldState, NewState: Cardinal);
  551. begin
  552. EnableCommands;
  553. end;
  554. procedure TfmMainGuard.Toolbar1TBEditClick(Sender: PControl;
  555. BtnID: Integer);
  556. var Idx: Integer;
  557. begin
  558. Idx := lv1.LVCurItem;
  559. if Idx < 0 then Exit;
  560. if fmEditFilter = nil then
  561. NewfmEditFilter( fmEditFilter, Applet );
  562. fmEditFilter.eDir.Text := MonitorList.Items[ Idx ];
  563. fmEditFilter.eFilter.Text := FiltersList.Items[ Idx ];
  564. fmEditFilter.eAction.CurIndex := MonitorList.Objects[ Idx ] and 3;
  565. fmEditFilter.eActionChange( nil );
  566. fmEditFilter.eTime.Text := Int2Str( FiltersList.Objects[ Idx ] );
  567. fmEditFilter.Operation := Idx;
  568. fmEditFilter.cSubdirectories.Checked := MonitorList.Objects[ Idx ] and 4 <> 0;
  569. fmEditFilter.cSubdirectoriesClick( nil );
  570. fmEditFilter.Form.Show;
  571. end;
  572. procedure TfmMainGuard.Toolbar1TBDelClick(Sender: PControl;
  573. BtnID: Integer);
  574. var Idx: Integer;
  575. begin
  576. Idx := lv1.LVCurItem;
  577. if Idx < 0 then Exit;
  578. MonitorList.Delete( Idx );
  579. FiltersList.Delete( Idx );
  580. lv1.LVCount := MonitorList.Count;
  581. SaveSettings;
  582. EnableCommands;
  583. ShowStatus;
  584. end;
  585. procedure TfmMainGuard.Toolbar1TBUpClick(Sender: PControl; BtnID: Integer);
  586. var Idx: Integer;
  587. begin
  588. Idx := lv1.LVCurItem;
  589. MonitorList.Swap( Idx - 1, Idx );
  590. lv1.Invalidate;
  591. lv1.LVCurItem := lv1.LVCurItem-1;
  592. EnableCommands;
  593. SaveSettings;
  594. end;
  595. procedure TfmMainGuard.Toolbar1TBDnClick(Sender: PControl; BtnID: Integer);
  596. var Idx: Integer;
  597. begin
  598. Idx := lv1.LVCurItem;
  599. MonitorList.Swap( Idx + 1, Idx );
  600. lv1.Invalidate;
  601. lv1.LVCurItem := lv1.LVCurItem+1;
  602. EnableCommands;
  603. SaveSettings;
  604. end;
  605. procedure TfmMainGuard.DirChanged(Sender: PObj; const Path: string; CheckFirstTime: Boolean = FALSE);
  606. var I: Integer;
  607. begin
  608. I := DirChangesQueue.IndexOf( Path );
  609. if I < 0 then
  610. begin
  611. if CheckFirstTime then
  612. DirChangesQueue.AddObject( Path, 1 )
  613. else
  614. DirChangesQueue.AddObject( Path, 0 );
  615. ShowQueued;
  616. if not CheckFirstTime and (LastChanged <> Path) then
  617. begin
  618. LastChanged := Path;
  619. Log( 'Changed: ' + Path );
  620. end;
  621. end
  622. else
  623. if not CheckFirstTime then
  624. begin
  625. DirChangesQueue.Objects[ I ] := 0;
  626. end;
  627. end;
  628. procedure TfmMainGuard.lv1MouseDblClk(Sender: PControl;
  629. var Mouse: TMouseEventData);
  630. begin
  631. if Toolbar1.TBButtonEnabled[ TBEdit ] then
  632. Toolbar1TBEditClick( nil, 0 );
  633. end;
  634. procedure TfmMainGuard.lv1KeyDown(Sender: PControl; var Key: Integer;
  635. Shift: Cardinal);
  636. begin
  637. if Key = VK_RETURN then
  638. if Toolbar1.TBButtonEnabled[ TBEdit ] then
  639. Toolbar1TBEditClick( nil, 0 );
  640. end;
  641. procedure TfmMainGuard.PrepareTree;
  642. var I: Integer;
  643. S: String;
  644. begin
  645. for I := 0 to MonitorList.Count-1 do
  646. begin
  647. S := MonitorList.Items[ I ];
  648. AddToTree( TreeDirs, S, MonitorList.Objects[ I ] and 4 <> 0 );
  649. end;
  650. end;
  651. procedure TfmMainGuard.AddToTree(Tree: PTree; const Path: String; WithSubdirs: Boolean);
  652. var Node, Child: PTree;
  653. I, J: Integer;
  654. DName: String;
  655. DL: PDirList;
  656. PC: DWORD;
  657. SrcPath: String;
  658. begin
  659. Applet.ProcessMessages;
  660. SrcPath := Path;
  661. //SetThreadPriority( GetCurrentThread, )
  662. if not( (Path <> '') and (Path[ 1 ] in [ 'A'..'Z', 'a'..'z' ]) and
  663. (Path[ 2 ] = ':') ) then Exit;
  664. if not DirectoryExists( Path ) then Exit;
  665. //DL := NewDirList( SrcPath, '*.*', FILE_ATTRIBUTE_DIRECTORY );
  666. DL := NewDirList( '', '', 0 );
  667. DL.OnItem := AcceptDirItem;
  668. DL.ScanDirectory( SrcPath, '*.*', FILE_ATTRIBUTE_DIRECTORY );
  669. PC := GetPriorityClass( GetCurrentProcess );
  670. SetPriorityClass( GetCurrentProcess, IDLE_PRIORITY_CLASS );
  671. if not AnsiEq( IncludeTrailingPathDelimiter( Path ), GetStartDir ) then
  672. AnyDirsChange.Add( SrcPath );
  673. TRY
  674. Node := nil;
  675. DName := '';
  676. for I := 0 to Tree.Count-1 do
  677. begin
  678. Node := Tree.Items[ I ];
  679. if StrEq( Node.Name[ 1 ], SrcPath[ 1 ] ) then
  680. begin
  681. DName := Parse( SrcPath, '\' );
  682. while Path <> '' do
  683. begin
  684. DName := Parse( SrcPath, '\' );
  685. Child := nil;
  686. for J := 0 to Node.Count-1 do
  687. begin
  688. Child := Node.Items[ J ];
  689. if AnsiEq( DName, Child.Name ) then
  690. begin
  691. Node := Child;
  692. break;
  693. end
  694. else Child := nil;
  695. end;
  696. if Child = nil then break;
  697. end;
  698. break;
  699. end
  700. else
  701. Node := nil;
  702. end;
  703. if Node = nil then Exit;
  704. if DName = '' then
  705. DName := Parse( SrcPath, '\' );
  706. while (DName <> '') or (SrcPath <> '') do
  707. begin
  708. Child := NewTree( Node, DName );
  709. DName := Parse( SrcPath, '\' );
  710. Node := Child;
  711. end;
  712. DirChanged( nil, DL.Path, TRUE );
  713. //Log( 'Added: ' + DL.Path );
  714. if WithSubdirs then
  715. for I := 0 to DL.Count-1 do
  716. begin
  717. if DL.IsDirectory[ I ] then
  718. AddToTree( TreeDirs, DL.Path + DL.Names[ I ], TRUE );
  719. end;
  720. FINALLY
  721. DL.Free;
  722. SetPriorityClass( GetCurrentProcess, PC );
  723. END;
  724. end;
  725. procedure TfmMainGuard.IdleEvent(Sender: PObj);
  726. var Path: String;
  727. I: Integer;
  728. IsFirst: Boolean;
  729. begin
  730. if DirChangesQueue.Count > 0 then
  731. begin
  732. for I := 1 to DirChangesQueue.Count do
  733. begin
  734. Applet.ProcessMessages;
  735. if WantClose then Exit;
  736. if DirChangesQueue.Count = 0 then
  737. break;
  738. Path := DirChangesQueue.Items[ 0 ];
  739. IsFirst := DirChangesQueue.Objects[ 0 ] <> 0;
  740. DirChangesQueue.Delete( 0 );
  741. ShowQueued;
  742. HandleDirChanges( Path, IsFirst );
  743. if StorageTreeChanged then
  744. begin
  745. Log( '-Started: rescanning Storage and building tree' );
  746. //RebuildStorageTree;
  747. if ThreadRescanStorageTree.Suspended then
  748. ThreadRescanStorageTree.Resume;
  749. //StorageTreeChanged := TRUE;
  750. Log( '-Finished: rescanning Storage and building tree' );
  751. end;
  752. end;
  753. end;
  754. if StorageTreeChanged then
  755. begin
  756. Log( '-Started: rescanning Storage and building tree' );
  757. RebuildStorageTree;
  758. Log( '-Finished: rescanning Storage and building tree' );
  759. end;
  760. end;
  761. procedure TfmMainGuard.HandleDirChanges(const Path: String; FirstHandling: Boolean);
  762. var DL: PDirList;
  763. I, J: Integer;
  764. S, S1: String;
  765. Satisfied: Boolean;
  766. AllHandled: Boolean;
  767. FT: TFileTime;
  768. ST: TSystemTime;
  769. ChangeTime, TimeElapsed: TDateTime;
  770. Time2Wait: Integer;
  771. begin
  772. Log( '-Handling directory (scan for changes): ' + Path );
  773. Applet.ProcessMessages;
  774. //DL := NewDirList( Path, '*.*', 0 );
  775. DL := NewDirList( '', '', 0 );
  776. DL.OnItem := AcceptDirItem;
  777. DL.ScanDirectory( Path, '*.*', 0 );
  778. AllHandled := TRUE;
  779. TRY
  780. for I := 0 to DL.Count-1 do
  781. begin
  782. Applet.ProcessMessages;
  783. if not DL.IsDirectory[ I ] then
  784. begin
  785. for J := 0 to MonitorList.Count-1 do
  786. begin
  787. if WantClose then Exit;
  788. S := MonitorList.Items[ J ];
  789. if AnsiEq( Copy( Path, 1, Length( S ) ), S ) and
  790. ( (MonitorList.Objects[ J ] and 4 <> 0) OR
  791. (pos( '\', CopyEnd( Path, Length( S )+1 )) <= 0)
  792. ) then
  793. begin
  794. S := FiltersList.Items[ J ];
  795. if S = '' then Satisfied := TRUE
  796. else
  797. begin
  798. Satisfied := FALSE;
  799. while S <> '' do
  800. begin
  801. S1 := Parse( S, ';' );
  802. if StrSatisfy( DL.Names[ I ], S1 ) then
  803. begin
  804. Satisfied := TRUE; break;
  805. end;
  806. end;
  807. end;
  808. if Satisfied then
  809. begin
  810. if not FirstHandling then
  811. begin
  812. if MonitorList.Objects[ J ] and 3 = 2 then break; // Action = not handle
  813. FT := DL.Items[ I ].ftLastWriteTime;
  814. FileTimeToSystemTime( FT, ST );
  815. SystemTime2DateTime( ST, ChangeTime );
  816. ChangeTime := DateTime_System2Local( ChangeTime );
  817. TimeElapsed := Now - ChangeTime;
  818. Time2Wait := FiltersList.Objects[ J ];
  819. if TimeElapsed * 24 * 3600 < Time2Wait then
  820. begin
  821. AllHandled := FALSE;
  822. break; // Время ожидания еще не вышло
  823. end;
  824. end;
  825. HandleFileChange( DL.Path + DL.Names[ I ], MonitorList.Objects[ J ] and 3 );
  826. end;
  827. end;
  828. end;
  829. end;
  830. end;
  831. if not AllHandled then
  832. begin
  833. I := DirChangesQueue.IndexOf( Path );
  834. if I < 0 then
  835. begin
  836. DirChangesQueue.Add( Path );
  837. ShowQueued;
  838. end;
  839. end;
  840. FINALLY
  841. DL.Free;
  842. END;
  843. end;
  844. procedure TfmMainGuard.HandleFileChange(const FilePath: String;
  845. Action: Integer);
  846. var ChkSum: DWORD;
  847. begin
  848. Applet.ProcessMessages;
  849. if not Storage.OK then Exit;
  850. if not Storage.CheckFile( FilePath, ChkSum ) then
  851. Storage.UpdateFile( FilePath, ChkSum, Action );
  852. //Log( 'File: ' + FilePath );
  853. end;
  854. procedure TfmMainGuard.lLinkMouseEnter(Sender: PObj);
  855. begin
  856. lLink.Font.FontStyle := [ fsItalic, fsUnderline ];
  857. end;
  858. procedure TfmMainGuard.lLinkMouseLeave(Sender: PObj);
  859. begin
  860. lLink.Font.FontStyle := [ fsUnderline ];
  861. end;
  862. procedure TfmMainGuard.lLinkClick(Sender: PObj);
  863. begin
  864. ShellExecute( 0, nil, 'http://bonanzas.rinet.ru', nil, nil, SW_SHOW );
  865. end;
  866. procedure TfmMainGuard.DirChanged(Sender: PObj; const Path: string);
  867. begin
  868. DirChanged( Sender, Path, FALSE );
  869. end;
  870. procedure TfmMainGuard.RebuildStorageTree;
  871. var DL, DL1: PDirList;
  872. I, J, P: Integer;
  873. L: PStrListEx;
  874. FS: PStream;
  875. S: String;
  876. begin
  877. StorageTreeChanged := FALSE;
  878. if not Storage.OK then
  879. begin
  880. tvDirs.Clear;
  881. Exit;
  882. end;
  883. //DL := NewDirList( eStoragePath.Text, '*.*', FILE_ATTRIBUTE_DIRECTORY );
  884. DL := NewDirList( '', '', 0 );
  885. DL.OnItem := AcceptDirItem;
  886. DL.ScanDirectory( eStoragePath.Text, '*.*', FILE_ATTRIBUTE_DIRECTORY );
  887. TRY
  888. for I := 0 to DL.Count-1 do
  889. begin
  890. //Applet.ProcessMessages;
  891. if DL.IsDirectory[ I ] and FileExists( DL.Path + DL.Names[ I ] + '\FileGuard.dir' ) then
  892. begin
  893. if tvDirs.TVRoot = 0 then
  894. tvDirs.TVInsert( 0, 0, 'ROOT' );
  895. AddPathToTVDirs( DL.Names[ I ], -1 );
  896. //DL1 := NewDirList( DL.Path + DL.Names[ I ] + '\', '*.*', FILE_ATTRIBUTE_NORMAL );
  897. DL1 := NewDirList( '', '', 0 );
  898. DL1.OnItem := AcceptDirItem;
  899. DL1.ScanDirectory( DL.Path + DL.Names[ I ] + '\', '*.*', FILE_ATTRIBUTE_NORMAL );
  900. L := NewStrListEx;
  901. TRY
  902. for J := 0 to DL1.Count-1 do
  903. begin
  904. //Applet.ProcessMessages;
  905. if not DL1.IsDirectory[ J ] then
  906. begin
  907. P := Str2Int( DL1.Names[ J ] );
  908. if (P > 0) and (L.IndexOfObj( Pointer( P ) ) < 0) then
  909. begin
  910. FS := NewReadFileStream( DL1.Path + DL1.Names[ J ] );
  911. TRY
  912. if FS.Handle <> INVALID_HANDLE_VALUE then
  913. begin
  914. S := FS.ReadStrZ;
  915. L.AddObject( S, P );
  916. AddPathToTVDirs( DL.Names[ I ] + '\' + S, P );
  917. end;
  918. FINALLY
  919. FS.Free;
  920. END;
  921. end;
  922. end;
  923. end;
  924. FINALLY
  925. DL1.Free;
  926. L.Free;
  927. END;
  928. end;
  929. end;
  930. FINALLY
  931. DL.Free;
  932. END;
  933. end;
  934. procedure TfmMainGuard.AddPathToTVDirs(DirPath: String; Obj: Integer);
  935. var Node, Child: THandle;
  936. DName, SrcPath: String;
  937. I: Integer;
  938. begin
  939. Applet.ProcessMessages;
  940. SrcPath := DirPath;
  941. I := pos( ':', SrcPath );
  942. if I > 0 then
  943. SrcPath := CopyEnd( SrcPath, I-1 );
  944. Node := tvDirs.TVRoot;
  945. while TRUE do
  946. begin
  947. DName := Parse( DirPath, '\' );
  948. if DName = '' then
  949. begin
  950. if Obj > 0 then
  951. tvDirs.TVItemData[ Node ] := Pointer( Obj );
  952. Exit;
  953. end;
  954. Child := tvDirs.TVItemChild[ Node ];
  955. while Child <> 0 do
  956. begin
  957. Applet.ProcessMessages;
  958. if AnsiEq( tvDirs.TVItemText[ Child ], DName ) then
  959. begin
  960. Node := Child;
  961. DName := Parse( DirPath, '\' );
  962. if DName = '' then
  963. begin
  964. if Obj > 0 then
  965. tvDirs.TVItemData[ Child ] := Pointer( Obj );
  966. Exit;
  967. end;
  968. Child := tvDirs.TVItemChild[ Node ];
  969. continue;
  970. end;
  971. Child := tvDirs.TVItemNext[ Child ];
  972. end;
  973. Child := tvDirs.TVInsert( Node, 0, DName );
  974. if DirPath = '' then
  975. tvDirs.TVItemData[ Child ] := Pointer( Obj );
  976. if (DirPath = '') and (Obj = -1) then
  977. begin
  978. tvDirs.TVItemImage[ Child ] := FileIconSystemIdx( ParamStr( 0 ) );
  979. end
  980. else
  981. if pos( ':', DName ) > 0 then
  982. tvDirs.TVItemImage[ Child ] := FileIconSysIdxOffline( 'C:\' )
  983. else
  984. tvDirs.TVItemImage[ Child ] := FileIconSystemIdx( GetStartDir );
  985. tvDirs.TVItemSelImg[ Child ] := tvDirs.TVItemImage[ Child ];
  986. tvDirs.TVSort( Node );
  987. if DirPath = '' then Exit;
  988. Node := Child;
  989. end;
  990. end;
  991. procedure TfmMainGuard.lvFilesLVData(Sender: PControl; Idx,
  992. SubItem: Integer; var Txt: String; var ImgIdx: Integer;
  993. var State: Cardinal; var Store: Boolean);
  994. var DirData: PDirData;
  995. ST: TSystemTime;
  996. DT: TDateTime;
  997. begin
  998. DirData := Pointer( Directory.Objects[ Idx ] );
  999. CASE SubItem OF
  1000. ColName: Txt := Directory.Items[ Idx ];
  1001. ColDate: begin
  1002. FileTimeToSystemTime( DirData.FT, ST );
  1003. SystemTime2DateTime( ST, DT );
  1004. DT := DateTime_System2Local( DT );
  1005. Txt := DateTime2StrShort( DT );
  1006. end;
  1007. ColSize: begin
  1008. Txt := Num2Bytes( DirData.Sz );
  1009. end;
  1010. ColUsed: begin
  1011. Txt := Num2Bytes( DirData.TotalSz );
  1012. end;
  1013. END;
  1014. ImgIdx := FileIconSysIdxOffline( Directory_Path + Directory.Items[ Idx ] );
  1015. end;
  1016. procedure TfmMainGuard.ClearDirectory;
  1017. var I: Integer;
  1018. DirData: PDirData;
  1019. begin
  1020. lvFiles.LVCount := 0;
  1021. for I := 0 to Directory.Count-1 do
  1022. begin
  1023. DirData := Pointer( Directory.Objects[ I ] );
  1024. if DirData <> nil then
  1025. FreeMem( DirData );
  1026. end;
  1027. Directory.Clear;
  1028. Directory_Path := '';
  1029. Directory_Root := '';
  1030. Directory_Prefix := '';
  1031. end;
  1032. procedure TfmMainGuard.tvDirsSelChange(Sender: PObj);
  1033. var Node, Node0: THandle;
  1034. DL: PDirList;
  1035. I, P: Integer;
  1036. DirData: PDirData;
  1037. FN: String;
  1038. FS: PStream;
  1039. begin
  1040. Node := tvDirs.TVSelected;
  1041. Node0 := Node;
  1042. ClearDirectory;
  1043. if Node <> 0 then
  1044. begin
  1045. Directory_Path := '';
  1046. while (Node <> 0) and (pos( ':', Directory_Path ) <= 0) do
  1047. begin
  1048. Directory_Path := tvDirs.TVItemText[ Node ] + '\' + Directory_Path;
  1049. Node := tvDirs.TVItemParent[ Node ];
  1050. end;
  1051. if Node = 0 then Exit;
  1052. Directory_Prefix := '';
  1053. if Integer( tvDirs.TVItemData[ Node0 ] ) > 0 then
  1054. Directory_Prefix := Format( '%.08d+',
  1055. [ Integer( tvDirs.TVItemData[ Node0 ] ) ] );
  1056. Directory_Root := tvDirs.TVItemText[ Node ] + '\';
  1057. Directory_Path := Directory_Root + Directory_Path;
  1058. P := Integer( tvDirs.TVItemData[ Node0 ] );
  1059. if P <= 0 then Exit;
  1060. //DL := NewDirList( IncludeTrailingPathDelimiter( eStoragePath.Text ) +
  1061. // tvDirs.TVItemText[ Node ] + '\',
  1062. // Format( '%.08d', [ P ] ) + '+*.*', FILE_ATTRIBUTE_NORMAL );
  1063. DL := NewDirList( '','', 0 );
  1064. DL.OnItem := AcceptDirItem;
  1065. DL.ScanDirectory( IncludeTrailingPathDelimiter( eStoragePath.Text ) +
  1066. tvDirs.TVItemText[ Node ] + '\',
  1067. Format( '%.08d', [ P ] ) + '+*.*', FILE_ATTRIBUTE_NORMAL );
  1068. TRY
  1069. for I := 0 to DL.Count-1 do
  1070. begin
  1071. if not DL.IsDirectory[ I ] then
  1072. begin
  1073. FN := CopyEnd( DL.Names[ I ], 10 );
  1074. DirData := AllocMem( Sizeof( TDirData ) );
  1075. FS := NewReadFileStream( DL.Path + DL.Names[ I ] );
  1076. TRY
  1077. Storage.EnumSections( FS, Storage.LookForLastVersionInfo );
  1078. FINALLY
  1079. FS.Free;
  1080. END;
  1081. DirData.FT := Storage.LastInfo.FT;
  1082. DirData.Sz := Storage.LastInfo.Sz;
  1083. DirData.TotalSz := DL.Items[ I ].nFileSizeLow;
  1084. Directory.AddObject( FN, DWORD( DirData ) );
  1085. end;
  1086. end;
  1087. Directory.Sort( FALSE );
  1088. lvFiles.LVCount := Directory.Count;
  1089. FINALLY
  1090. DL.Free;
  1091. END;
  1092. end;
  1093. end;
  1094. procedure TfmMainGuard.pm2pmHistoryMenu(Sender: PMenu; Item: Integer);
  1095. var FS: PStream;
  1096. LI: Integer;
  1097. begin
  1098. LI := lvFiles.LVCurItem;
  1099. if LI < 0 then Exit;
  1100. if fmHistory = nil then
  1101. NewfmHistory( fmHistory, Applet );
  1102. FS := NewReadFileStream( IncludeTrailingPathDelimiter( eStoragePath.Text )
  1103. + Directory_Root + Directory_Prefix + Directory.Items[ LI ] );
  1104. TRY
  1105. fmHistory.CurFile := LI;
  1106. fmHistory.HL.Clear;
  1107. Storage.EnumSections( FS, CollectAllVersionsInfo );
  1108. fmHistory.lvHistory.LVCount := fmHistory.HL.Count;
  1109. if (fmHistory.lvHistory.LVCount > 0) and (fmHistory.lvHistory.LVCurItem < 0) then
  1110. fmHistory.lvHistory.LVCurItem := 0;
  1111. FINALLY //
  1112. FS.Free;
  1113. END;
  1114. fmHistory.Form.Caption := 'History of version: ' + Directory.Items[ LI ];
  1115. fmHistory.CurFile := LI;
  1116. if not fmHistory.Form.Visible then
  1117. fmHistory.Form.Show;
  1118. //fmHistory.Form.Hide;
  1119. end;
  1120. procedure TfmMainGuard.CollectAllVersionsInfo(FileStream: PStream;
  1121. const FI: TFileVersionInfo; SecType: Byte; SecLen: DWORD;
  1122. var Cont: Boolean);
  1123. var ST: TSystemTime;
  1124. DT: TDateTime;
  1125. L: DWORD;
  1126. begin
  1127. FileTimeToSystemTime( FI.FT, ST );
  1128. SystemTime2DateTime( ST, DT );
  1129. DT := DateTime_System2Local( DT );
  1130. FileStream.Position := FileStream.Position - 4;
  1131. FileStream.Read( L, 4 );
  1132. fmHistory.HL.Add( DateTime2StrShort( DT )+#9+Num2Bytes( FI.Sz )+#9+Int2Str( L ) );
  1133. end;
  1134. procedure TfmMainGuard.pm2pmRestoreMenu(Sender: PMenu; Item: Integer);
  1135. begin
  1136. if fmRestore = nil then
  1137. begin
  1138. NewfmRestore( fmRestore, Applet );
  1139. fmRestore.eDate.DateTime := Trunc( Now );
  1140. fmRestore.eTime.DateTime := Frac( Now );
  1141. end;
  1142. fmRestore.lFilescount.Caption := Int2Str( lvFiles.LVSelCount );
  1143. fmRestore.cSubdirsRecursively.Visible := FALSE;
  1144. fmRestore.OnRestore := RestoreSelected;
  1145. fmRestore.Form.Show;
  1146. end;
  1147. procedure TfmMainGuard.pm3pmDirRestoreMenu(Sender: PMenu; Item: Integer);
  1148. var S: String;
  1149. N: Integer;
  1150. begin
  1151. if fmRestore = nil then
  1152. begin
  1153. NewfmRestore( fmRestore, Applet );
  1154. fmRestore.eDate.DateTime := Trunc( Now );
  1155. fmRestore.eTime.DateTime := Frac( Now );
  1156. end;
  1157. S := Int2Str( Directory.Count ) + ' files';
  1158. N := tvDirs.TVItemChildCount[ tvDirs.TVSelected ];
  1159. if N > 0 then
  1160. S := S + ' and ' + Int2Str( N ) + ' dirs';
  1161. fmRestore.lFilescount.Caption := S;
  1162. fmRestore.cSubdirsRecursively.Visible := TRUE;
  1163. fmRestore.OnRestore := RestoreSubdirs;
  1164. fmRestore.Form.Show;
  1165. //fmRestore.Form.Hide;
  1166. end;
  1167. procedure TfmMainGuard.AddFilesFromSubdirs(SL: PStrList; Node: THandle;
  1168. SubdirsRecursively: Boolean);
  1169. var Child: THandle;
  1170. P: Integer;
  1171. DL: PDirList;
  1172. I: Integer;
  1173. begin
  1174. Child := tvDirs.TVItemChild[ Node ];
  1175. while Child <> 0 do
  1176. begin
  1177. P := Integer( tvDirs.TVItemData[ Child ] );
  1178. if P > 0 then
  1179. begin
  1180. //DL := NewDirList( IncludeTrailingPathDelimiter( eStoragePath.Text ) +
  1181. // Directory_Root, Format( '%.08d+', [ P ] ) + '*.*', FILE_ATTRIBUTE_NORMAL );
  1182. DL := NewDirList( '', '', 0 );
  1183. DL.OnItem := AcceptDirItem;
  1184. DL.ScanDirectory( IncludeTrailingPathDelimiter( eStoragePath.Text ) +
  1185. Directory_Root, Format( '%.08d+', [ P ] ) + '*.*', FILE_ATTRIBUTE_NORMAL );
  1186. TRY
  1187. for I := 0 to DL.Count-1 do
  1188. if not DL.IsDirectory[ I ] then
  1189. begin
  1190. SL.Add( Directory_Root + DL.Names[ I ] );
  1191. end;
  1192. FINALLY
  1193. DL.Free;
  1194. END;
  1195. end;
  1196. if SubdirsRecursively then
  1197. AddFilesFromSubdirs( SL, Child, TRUE );
  1198. Child := tvDirs.TVItemNext[ Child ];
  1199. end;
  1200. end;
  1201. procedure TfmMainGuard.RestoreFiles(FileList: PStrList);
  1202. var I: Integer;
  1203. FS, VS, DS: PStream;
  1204. S, FN: String;
  1205. Yes_All: Boolean;
  1206. Q: Integer;
  1207. begin
  1208. Yes_All := FALSE;
  1209. for I := 0 to FileList.Count-1 do
  1210. begin
  1211. Log( 'Restore: ' + FileList.Items[ I ] );
  1212. FN := CopyEnd( ExtractFileName( FileList.Items[ I ] ), 10 );
  1213. FS := nil;
  1214. while TRUE do
  1215. begin
  1216. Applet.ProcessMessages;
  1217. FS := NewReadFileStream( IncludeTrailingPathDelimiter( eStoragePath.Text ) +
  1218. FileList.Items[ I ] );
  1219. if FS.Handle = INVALID_HANDLE_VALUE then
  1220. begin
  1221. Log( 'Can not open ' + IncludeTrailingPathDelimiter( eStoragePath.Text ) +
  1222. FileList.Items[ I ] );
  1223. CASE MessageBox( Form.Handle, PChar( 'Can not open file ' +
  1224. IncludeTrailingPathDelimiter( eStoragePath.Text ) +
  1225. FileList.Items[ I ] ), Pchar( Applet.Caption ),
  1226. MB_RETRYCANCEL ) OF
  1227. ID_CANCEL: Exit;
  1228. ID_RETRY: continue;
  1229. END;
  1230. end;
  1231. break;
  1232. end;
  1233. TRY
  1234. VS := NewMemoryStream;
  1235. TRY
  1236. VerFileName := FileList.Items[ I ];
  1237. VerDate := fmRestore.eDate.Date + fmRestore.eTime.Time;
  1238. VersionFile := VS;
  1239. VerIdx := 0;
  1240. Storage.EnumSections( FS, RestoreForDate );
  1241. if VS.Size = 0 then
  1242. begin
  1243. Log( 'File not restored - 0 bytes read' );
  1244. end
  1245. else
  1246. begin
  1247. FS.Position := 0;
  1248. S := FS.ReadStrZ;
  1249. if not DirectoryExists( S ) then
  1250. begin
  1251. if Yes_All then Q := 0
  1252. else
  1253. Q := ShowQuestion( 'Directory ' + S + ' not exists. Create it?',
  1254. 'Yes/Yes All/No, cancel' );
  1255. if Q = 1 then Yes_All := TRUE;
  1256. CASE Q OF
  1257. 0, 1:
  1258. begin
  1259. MkDir( S );
  1260. if not DirectoryExists( S ) then
  1261. begin
  1262. ShowMessage( 'Could not create directory ' + S + '. ' +
  1263. 'Operation aborted.' ); Exit;
  1264. end;
  1265. PrepareTree;
  1266. end;
  1267. 2: Exit;
  1268. END;
  1269. end;
  1270. if FileExists( S + FN ) then
  1271. DeleteFile2Recycle( S + FN );
  1272. DS := NewWriteFileStream( S + FN );
  1273. TRY
  1274. if DS.Handle = INVALID_HANDLE_VALUE then
  1275. begin
  1276. ShowMessage( 'Can not write file ' + S + FN + '. Operation is ' +
  1277. 'aborting. If the existing file already deleted, you can restore ' +
  1278. 'it from Recycle.' ); Exit;
  1279. end;
  1280. VS.Position := 0;
  1281. Stream2Stream( DS, VS, VS.Size );
  1282. Log( 'Restored: ' + S + FN );
  1283. FINALLY
  1284. DS.Free;
  1285. END;
  1286. end;
  1287. FINALLY
  1288. VS.Free;
  1289. END;
  1290. FINALLY
  1291. FS.Free;
  1292. END;
  1293. end;
  1294. end;
  1295. procedure TfmMainGuard.RestoreForDate(FileStream: PStream;
  1296. const FI: TFileVersionInfo; SecType: Byte; SecLen: DWORD;
  1297. var Cont: Boolean);
  1298. var L: DWORD;
  1299. US: PStream;
  1300. OldVersion, CmdStream: PStream;
  1301. ST: TSystemTime;
  1302. DT: TDateTime;
  1303. begin
  1304. Inc( VerIdx );
  1305. FileTimeToSystemTime( FI.FT, ST );
  1306. SystemTime2DateTime( ST, DT );
  1307. DT := DateTime_Local2System( DT );
  1308. if (VersionFile.Size > 0) and (DT > VerDate) then
  1309. begin
  1310. Cont := FALSE; // восстановлено за предшествующую дату, дажльше не надо
  1311. Exit;
  1312. end;
  1313. if SecType and 1 = 0 then
  1314. begin // полная версия здесь
  1315. VersionFile.Position := 0;
  1316. if SecType and 2 = 0 then
  1317. Stream2Stream( VersionFile, FileStream, SecLen )
  1318. else
  1319. begin // сжатая полная версия
  1320. FileStream.Read( L, 4 );
  1321. US := DIUCLStreams.NewUclDStream( $80000, FileStream, UCLOnProgress );
  1322. TRY
  1323. Stream2Stream( VersionFile, US, L );
  1324. FINALLY
  1325. US.Free;
  1326. END;
  1327. end;
  1328. end
  1329. else
  1330. begin // обновление от предыдущей версии здесь
  1331. OldVersion := NewMemoryStream;
  1332. CmdStream := NewMemoryStream;
  1333. TRY
  1334. if SecType and 2 = 0 then
  1335. Stream2Stream( CmdStream, FileStream, SecLen )
  1336. else
  1337. begin // командный поток сжат
  1338. FileStream.Read( L, 4 );
  1339. US := DIUCLStreams.NewUclDStream( $80000, FileStream, UCLOnProgress );
  1340. TRY
  1341. Stream2Stream( CmdStream, FileStream, L );
  1342. FINALLY
  1343. US.Free;
  1344. END;
  1345. end;
  1346. // теперь распаковка новой версии
  1347. if CmdStream.Size > 0 then
  1348. begin
  1349. VersionFile.Position := 0;
  1350. Stream2Stream( OldVersion, VersionFile, VersionFile.Size );
  1351. OldVersion.Position := 0;
  1352. VersionFile.Position := 0;
  1353. CmdStream.Position := 0;
  1354. if not DoApplyUpdates( VersionFile, OldVersion, CmdStream ) then
  1355. begin
  1356. Log( 'Can not unpack version #' + Int2Str( VerIdx ) + ' of ' + VerFileName );
  1357. VersionFile.Position := 0;
  1358. OldVersion.Position := 0;
  1359. Stream2Stream( VersionFile, OldVersion, OldVersion.Size );
  1360. Cont := FALSE;
  1361. end;
  1362. end
  1363. else
  1364. VersionFile.Position := VersionFile.Size;
  1365. FINALLY
  1366. OldVersion.Free;
  1367. CmdStream.Free;
  1368. END;
  1369. end;
  1370. VersionFile.Size := VersionFile.Position;
  1371. VersionFile.Position := 0;
  1372. end;
  1373. procedure TfmMainGuard.KOLForm1Minimize(Sender: PObj);
  1374. begin
  1375. Form.Hide;
  1376. TimerHide.Enabled := TRUE;
  1377. end;
  1378. procedure TfmMainGuard.TimerHideTimer(Sender: PObj);
  1379. begin
  1380. TimerHide.Enabled := FALSE;
  1381. if not Form.Visible and Applet.Visible then
  1382. Applet.Hide;
  1383. end;
  1384. procedure TfmMainGuard.RestoreSubdirs(Sender: PObj);
  1385. var SL: PStrList;
  1386. LI: Integer;
  1387. begin
  1388. SL := NewStrList;
  1389. TRY
  1390. for LI := 0 to Directory.Count-1 do
  1391. SL.Add( Directory_Root + Directory_Prefix + Directory.Items[ LI ] );
  1392. if fmRestore.cSubdirsRecursively.Checked then
  1393. AddFilesFromSubdirs( SL, tvDirs.TVSelected, TRUE );
  1394. RestoreFiles( SL );
  1395. FINALLY
  1396. SL.Free;
  1397. END;
  1398. end;
  1399. procedure TfmMainGuard.RestoreSelected(Sender: PObj);
  1400. var SL: PStrList;
  1401. LI: Integer;
  1402. begin
  1403. SL := NewStrList;
  1404. TRY
  1405. LI := lvFiles.LVCurItem;
  1406. while LI >= 0 do
  1407. begin
  1408. SL.Add( Directory_Prefix + Directory.Items[ LI ] );
  1409. LI := lvFiles.LVNextSelected( LI );
  1410. end;
  1411. RestoreFiles( SL );
  1412. FINALLY
  1413. SL.Free;
  1414. END;
  1415. end;
  1416. procedure TfmMainGuard.UCLOnProgress(const Sender: PObj; const InBytes, OutBytes: Cardinal );
  1417. begin
  1418. if Abs( Integer( GetTickCount - LastUCLProgress ) ) > 100 then
  1419. begin
  1420. LastUCLProgress := GetTickCount;
  1421. Applet.ProcessMessages;
  1422. end;
  1423. end;
  1424. procedure TfmMainGuard.lvFilesLVStateChange(Sender: PControl; IdxFrom,
  1425. IdxTo: Integer; OldState, NewState: Cardinal);
  1426. begin
  1427. if fmHistory <> nil then
  1428. if fmHistory.Form.Visible then
  1429. if lvFiles.LVCurItem >= 0 then
  1430. begin
  1431. pm2pmHistoryMenu( nil, 0 );
  1432. end;
  1433. end;
  1434. procedure TfmMainGuard.pm3pmDirOpenMenu(Sender: PMenu; Item: Integer);
  1435. var S: String;
  1436. begin
  1437. if tvDirs.TVSelected = 0 then Exit;
  1438. S := tvDirs.TVItemPath( tvDirs.TVSelected, '\' );
  1439. Parse( S, '\' ); // ROOT\...
  1440. Parse( S, '\' ); // machinename\...
  1441. if not DirectoryExists( S ) then
  1442. ShowMessage( 'Directory does not exists: ' + S )
  1443. else
  1444. ShellExecute( 0, nil, PChar( IncludeTrailingPathDelimiter( S ) ),
  1445. nil, nil, SW_SHOW );
  1446. end;
  1447. procedure TfmMainGuard.lvFilesMouseDblClk(Sender: PControl;
  1448. var Mouse: TMouseEventData);
  1449. begin
  1450. ViewFile;
  1451. end;
  1452. procedure TfmMainGuard.ViewFile;
  1453. begin
  1454. if fmHistory = nil then
  1455. NewfmHistory( fmHistory, Applet );
  1456. fmHistory.VerIdx := MaxInt;
  1457. fmHistory.CurFile := lvFiles.LVCurItem;
  1458. if fmHistory.CurFile >= 0 then
  1459. fmHistory.ViewHistory;
  1460. end;
  1461. procedure TfmMainGuard.lvFilesKeyDown(Sender: PControl; var Key: Integer;
  1462. Shift: Cardinal);
  1463. begin
  1464. if Key = VK_RETURN then
  1465. ViewFile;
  1466. end;
  1467. procedure TfmMainGuard.TimerCheckConnectTimer(Sender: PObj);
  1468. begin
  1469. TimerCheckConnect.Enabled := FALSE;
  1470. eStoragePathChange( nil );
  1471. end;
  1472. function TfmMainGuard.ThreadRescanStorageTreeExecute(
  1473. Sender: PThread): Integer;
  1474. begin
  1475. while not AppletTerminated do
  1476. begin
  1477. RebuildStorageTree;
  1478. Sender.Suspend;
  1479. end;
  1480. Result := 0;
  1481. end;
  1482. procedure TfmMainGuard.AcceptDirItem(Sender: PObj;
  1483. var FindData: TWin32FindData; var Action: TDirItemAction);
  1484. begin
  1485. if AppletTerminated then
  1486. Action := diCancel
  1487. else
  1488. Applet.ProcessMessages;
  1489. end;
  1490. procedure TfmMainGuard.ShowQueued;
  1491. begin
  1492. if DirChangesQueue.Count > 0 then
  1493. lQueued.Caption := 'Queued: ' + Int2Str( DirChangesQueue.Count ) + ' dirs'
  1494. else
  1495. lQueued.Caption := '';
  1496. Global_Align( pnLogInfo );
  1497. end;
  1498. end.