Subversion Repositories recyclebinunit

Rev

Rev 88 | Rev 90 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 88 Rev 89
Line 159... Line 159...
159
  end;
159
  end;
160
 
160
 
161
  // TODO: Wie sieht es aus mit Laufwerken, die nur als Mount-Point eingebunden sind?
161
  // TODO: Wie sieht es aus mit Laufwerken, die nur als Mount-Point eingebunden sind?
162
  TRbDrive = class(TObject)
162
  TRbDrive = class(TObject)
163
  strict private
163
  strict private
164
    FDriveLetter: Char;
164
    FDriveLetter: AnsiChar;
165
 
165
 
166
    function OldCapacityPercent(var res: integer): boolean; // in % (0-100)
166
    function OldCapacityPercent(var res: integer): boolean; // in % (0-100)
167
    function NewCapacityAbsolute(var res: integer): boolean; // in MB
167
    function NewCapacityAbsolute(var res: integer): boolean; // in MB
168
 
168
 
169
    function DiskSize: integer; // in MB
169
    function DiskSize: integer; // in MB
Line 176... Line 176...
176
    function GetVolumeGUID: TGUID;
176
    function GetVolumeGUID: TGUID;
177
    function GetVolumeGUIDAvailable: boolean;
177
    function GetVolumeGUIDAvailable: boolean;
178
 
178
 
179
    // TODO: get drive serial
179
    // TODO: get drive serial
180
  public
180
  public
181
    constructor Create(ADriveLetter: Char);
181
    constructor Create(ADriveLetter: AnsiChar);
182
 
182
 
183
    // Wenn UserSID='', dann werden alle Recycler gefunden
183
    // Wenn UserSID='', dann werden alle Recycler gefunden
184
    procedure ListRecycleBins(list: TObjectList{TRbRecycleBin}; UserSID: string='');
184
    procedure ListRecycleBins(list: TObjectList{TRbRecycleBin}; UserSID: string='');
185
 
185
 
186
    property DriveLetter: Char read FDriveLetter;
186
    property DriveLetter: AnsiChar read FDriveLetter;
187
    property VolumeGUID: TGUID read GetVolumeGUID;
187
    property VolumeGUID: TGUID read GetVolumeGUID;
188
    property VolumeGUIDAvailable: boolean read GetVolumeGUIDAvailable;
188
    property VolumeGUIDAvailable: boolean read GetVolumeGUIDAvailable;
189
    function GetAPIInfo: TSHQueryRBInfo;
189
    function GetAPIInfo: TSHQueryRBInfo;
190
    function GetSize: int64;
190
    function GetSize: int64;
191
    function GetNumItems: int64;
191
    function GetNumItems: int64;
Line 199... Line 199...
199
  GPOLICYBOOL = (gpUndefined, gpEnabled, gpDisabled);
199
  GPOLICYBOOL = (gpUndefined, gpEnabled, gpDisabled);
200
 
200
 
201
  TRecycleBinManager = class(TObject)
201
  TRecycleBinManager = class(TObject)
202
  public
202
  public
203
    class procedure ListDrives(list: TObjectList{TRbDrive}); static;
203
    class procedure ListDrives(list: TObjectList{TRbDrive}); static;
204
    class function RecycleBinPossible(Drive: Char): boolean; static;
204
    class function RecycleBinPossible(Drive: AnsiChar): boolean; static;
205
 
205
 
206
    class function OwnRecyclersSize: int64; static;
206
    class function OwnRecyclersSize: int64; static;
207
    class function OwnRecyclersNumItems: int64; static;
207
    class function OwnRecyclersNumItems: int64; static;
208
    class function OwnRecyclersEmpty: boolean; static;
208
    class function OwnRecyclersEmpty: boolean; static;
209
 
209
 
Line 362... Line 362...
362
  C_SHGetSettings = 'SHGetSettings';
362
  C_SHGetSettings = 'SHGetSettings';
363
  C_SHGetSetSettings = 'SHGetSetSettings';
363
  C_SHGetSetSettings = 'SHGetSetSettings';
364
 
364
 
365
type
365
type
366
  TSHQueryRecycleBin = function(pszRootPath: LPCTSTR; var pSHQueryRBInfo: TSHQueryRBInfo): HRESULT; stdcall;
366
  TSHQueryRecycleBin = function(pszRootPath: LPCTSTR; var pSHQueryRBInfo: TSHQueryRBInfo): HRESULT; stdcall;
367
  TGetVolumeNameForVolumeMountPoint = function(lpszVolumeMountPoint: LPCTSTR; lpszVolumeName: LPTSTR; cchBufferLength: DWORD): BOOL; stdcall;
367
  TGetVolumeNameForVolumeMountPointA = function(lpszVolumeMountPoint: LPCSTR; lpszVolumeName: LPSTR; cchBufferLength: DWORD): BOOL; stdcall;
368
  TSHEmptyRecycleBin = function(Wnd: HWND; pszRootPath: PChar; dwFlags: DWORD): HRESULT; stdcall;
368
  TSHEmptyRecycleBin = function(Wnd: HWND; pszRootPath: PChar; dwFlags: DWORD): HRESULT; stdcall;
369
  TSHGetSettings = procedure(var lpss: SHELLSTATE; dwMask: DWORD); stdcall;
369
  TSHGetSettings = procedure(var lpss: SHELLSTATE; dwMask: DWORD); stdcall;
370
  TSHGetSetSettings = procedure(var lpss: SHELLSTATE; dwMask: DWORD; bSet: BOOL); stdcall;
370
  TSHGetSetSettings = procedure(var lpss: SHELLSTATE; dwMask: DWORD; bSet: BOOL); stdcall;
371
 
371
 
372
procedure AnsiRemoveNulChars(var s: AnsiString);
372
procedure AnsiRemoveNulChars(var s: AnsiString);
Line 379... Line 379...
379
begin
379
begin
380
  while (Length(s) > 0) and (s[Length(s)] = #0) do
380
  while (Length(s) > 0) and (s[Length(s)] = #0) do
381
    s := Copy(s, 1, Length(s)-1);
381
    s := Copy(s, 1, Length(s)-1);
382
end;
382
end;
383
 
383
 
384
function GetDriveGUID(driveLetter: Char; var guid: TGUID): DWORD;
384
function GetDriveGUID(driveLetter: AnsiChar; var guid: TGUID): DWORD;
385
var
385
var
386
  Buffer: array[0..50] of AnsiChar;
386
  Buffer: array[0..50] of AnsiChar;
387
  x: string;
387
  x: string;
388
  PGetVolumeNameForVolumeMountPoint: TGetVolumeNameForVolumeMountPoint;
388
  PGetVolumeNameForVolumeMountPointA: TGetVolumeNameForVolumeMountPointA;
389
  RBHandle: THandle;
389
  RBHandle: THandle;
390
begin
390
begin
391
  RBHandle := LoadLibrary(kernel32);
391
  RBHandle := LoadLibrary(kernel32);
392
  try
392
  try
393
    if RBHandle <> 0 then
393
    if RBHandle <> 0 then
394
    begin
394
    begin
395
      PGetVolumeNameForVolumeMountPoint := GetProcAddress(RBHandle, C_GetVolumeNameForVolumeMountPoint);
395
      PGetVolumeNameForVolumeMountPointA := GetProcAddress(RBHandle, C_GetVolumeNameForVolumeMountPoint);
396
      if not Assigned(@PGetVolumeNameForVolumeMountPoint) then
396
      if not Assigned(@PGetVolumeNameForVolumeMountPointA) then
397
      begin
397
      begin
398
        result := GetLastError;
398
        result := GetLastError;
399
        FreeLibrary(RBHandle);
399
        FreeLibrary(RBHandle);
400
        RBHandle := 0;
400
        RBHandle := 0;
401
      end
401
      end
402
      else
402
      else
403
      begin
403
      begin
404
        if PGetVolumeNameForVolumeMountPoint(PAnsiChar(driveLetter+':\'), Buffer, SizeOf(Buffer)) then
404
        if PGetVolumeNameForVolumeMountPointA(PAnsiChar(AnsiString(driveLetter+':\')), Buffer, SizeOf(Buffer)) then
405
        begin
405
        begin
406
          x := buffer;
406
          x := string(buffer);
407
          x := copy(x, 11, 38);
407
          x := copy(x, 11, 38);
408
          guid := StringToGUID(x);
408
          guid := StringToGUID(x);
409
          result := ERROR_SUCCESS;
409
          result := ERROR_SUCCESS;
410
        end
410
        end
411
        else
411
        else
Line 478... Line 478...
478
    end;
478
    end;
479
    if not RemoveDir(Name) then result := false;
479
    if not RemoveDir(Name) then result := false;
480
  end;
480
  end;
481
end;
481
end;
482
 
482
 
483
function DriveLetterToDriveNumber(driveLetter: Char): integer;
483
function DriveLetterToDriveNumber(driveLetter: AnsiChar): integer;
484
var
484
var
485
  tmp: string;
485
  tmp: string;
486
begin
486
begin
487
  tmp := LowerCase(driveLetter);
487
  tmp := LowerCase(string(driveLetter));
488
  result := Ord(tmp[1])-Ord('a');
488
  result := Ord(tmp[1])-Ord('a');
489
end;
489
end;
490
 
490
 
491
function GetStringFromDLL(filename: string; num: integer): string;
491
function GetStringFromDLL(filename: string; num: integer): string;
492
const
492
const
Line 946... Line 946...
946
begin
946
begin
947
  // Does the drive exist?
947
  // Does the drive exist?
948
  // see http://www.delphipraxis.net/post2933.html
948
  // see http://www.delphipraxis.net/post2933.html
949
  if not GetLogicalDrives and (1 shl DriveNumber) <> 0 then
949
  if not GetLogicalDrives and (1 shl DriveNumber) <> 0 then
950
  begin
950
  begin
951
    raise EInvalidDrive.CreateFmt(LNG_DRIVE_NOT_EXISTING, [UpperCase(FDriveLetter)+':']);
951
    raise EInvalidDrive.CreateFmt(LNG_DRIVE_NOT_EXISTING, [UpperCase(string(FDriveLetter))+':']);
952
  end;
952
  end;
953
end;
953
end;
954
 
954
 
955
constructor TRbDrive.Create(ADriveLetter: Char);
955
constructor TRbDrive.Create(ADriveLetter: AnsiChar);
956
begin
956
begin
957
  inherited Create;
957
  inherited Create;
958
 
958
 
959
  FDriveLetter := ADriveLetter;
959
  FDriveLetter := ADriveLetter;
960
  CheckDriveExisting;
960
  CheckDriveExisting;
Line 1093... Line 1093...
1093
 
1093
 
1094
    // Im Auslieferungszustand von Windows 95 ist dieser Schlüssel nicht vorhanden.
1094
    // Im Auslieferungszustand von Windows 95 ist dieser Schlüssel nicht vorhanden.
1095
    // Er wird bei der ersten Änderung der Papierkorb-Einstellungen erstellt.
1095
    // Er wird bei der ersten Änderung der Papierkorb-Einstellungen erstellt.
1096
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
1096
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
1097
    begin
1097
    begin
1098
      if reg.OpenKeyReadOnly(FDriveLetter) then
1098
      if reg.OpenKeyReadOnly(string(FDriveLetter)) then
1099
      begin
1099
      begin
1100
        if reg.ValueExists('Percent') then
1100
        if reg.ValueExists('Percent') then
1101
        begin
1101
        begin
1102
          // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
1102
          // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
1103
 
1103
 
Line 1191... Line 1191...
1191
 
1191
 
1192
        // Im Auslieferungszustand von Windows 95 ist dieser Schlüssel nicht vorhanden.
1192
        // Im Auslieferungszustand von Windows 95 ist dieser Schlüssel nicht vorhanden.
1193
        // Er wird bei der ersten Änderung der Papierkorb-Einstellungen erstellt.
1193
        // Er wird bei der ersten Änderung der Papierkorb-Einstellungen erstellt.
1194
        if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
1194
        if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
1195
        begin
1195
        begin
1196
          if reg.OpenKeyReadOnly(FDriveLetter) then
1196
          if reg.OpenKeyReadOnly(string(FDriveLetter)) then
1197
          begin
1197
          begin
1198
            if reg.ValueExists('NukeOnDelete') then
1198
            if reg.ValueExists('NukeOnDelete') then
1199
            begin
1199
            begin
1200
              // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
1200
              // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
1201
 
1201
 
Line 1374... Line 1374...
1374
  // Wir lesen den Eintrag trotzdem, da unsere Software ja auch zu forensischen
1374
  // Wir lesen den Eintrag trotzdem, da unsere Software ja auch zu forensischen
1375
  // Zwecken eingesetzt werden soll.
1375
  // Zwecken eingesetzt werden soll.
1376
  if r.sourceAnsi[0] = #0 then
1376
  if r.sourceAnsi[0] = #0 then
1377
  begin
1377
  begin
1378
    FRemovedEntry := true;
1378
    FRemovedEntry := true;
1379
    r.sourceAnsi[0] := FSourceDrive;
1379
    r.sourceAnsi[0] := AnsiChar(FSourceDrive);
1380
  end;
1380
  end;
1381
 
1381
 
1382
  FSourceAnsi := r.sourceAnsi;
1382
  FSourceAnsi := r.sourceAnsi;
1383
  FSourceUnicode := r.sourceAnsi; // Unicode does not exist in INFO(1) structure
1383
  FSourceUnicode := WideString(r.sourceAnsi); // Unicode does not exist in INFO(1) structure
1384
  FID := IntToStr(r.recordNumber);
1384
  FID := IntToStr(r.recordNumber);
1385
  FDeletionTime := FileTimeToDateTime(r.deletionTime);
1385
  FDeletionTime := FileTimeToDateTime(r.deletionTime);
1386
  FOriginalSize := r.originalSize;
1386
  FOriginalSize := r.originalSize;
1387
 
1387
 
1388
  // Remove #0 at the end. There are some bugs where #0 is added to ANSI/Unicode read paths?! (probably in the ReadVista stuff)
1388
  // Remove #0 at the end. There are some bugs where #0 is added to ANSI/Unicode read paths?! (probably in the ReadVista stuff)
Line 1412... Line 1412...
1412
    Exit;
1412
    Exit;
1413
  end;
1413
  end;
1414
 
1414
 
1415
  // e.g. C:\...\DC0.doc
1415
  // e.g. C:\...\DC0.doc
1416
  result := IncludeTrailingPathDelimiter(ExtractFilePath(IndexFile)) +
1416
  result := IncludeTrailingPathDelimiter(ExtractFilePath(IndexFile)) +
1417
            'D' + (* SourceDrive *) SourceAnsi[1] + ID + ExtractFileExt(SourceAnsi);
1417
            'D' + (* SourceDrive *) Source[1] + ID + ExtractFileExt(Source);
1418
end;
1418
end;
1419
 
1419
 
1420
constructor TRbInfoAItem.Create(fs: TStream; AIndexFile: string);
1420
constructor TRbInfoAItem.Create(fs: TStream; AIndexFile: string);
1421
begin
1421
begin
1422
  inherited Create;
1422
  inherited Create;
Line 1527... Line 1527...
1527
    stream.Seek(0, soBeginning);
1527
    stream.Seek(0, soBeginning);
1528
    stream.ReadBuffer(r1, SizeOf(r1));
1528
    stream.ReadBuffer(r1, SizeOf(r1));
1529
    FSourceAnsi := AnsiString(r1.sourceUnicode); // Invalid chars are automatically converted into '?'
1529
    FSourceAnsi := AnsiString(r1.sourceUnicode); // Invalid chars are automatically converted into '?'
1530
    FSourceUnicode := WideString(r1.sourceUnicode);
1530
    FSourceUnicode := WideString(r1.sourceUnicode);
1531
    FID := ''; // will be added manually (at the constructor)
1531
    FID := ''; // will be added manually (at the constructor)
1532
    FSourceDrive := AnsiChar(r1.sourceUnicode[1]);
1532
    FSourceDrive := r1.sourceUnicode[1];
1533
    FDeletionTime := FileTimeToDateTime(r1.deletionTime);
1533
    FDeletionTime := FileTimeToDateTime(r1.deletionTime);
1534
    FOriginalSize := r1.originalSize;
1534
    FOriginalSize := r1.originalSize;
1535
  end
1535
  end
1536
  else if version = 2 then
1536
  else if version = 2 then
1537
  begin
1537
  begin
Line 1542... Line 1542...
1542
    stream.Read(r2SourceUnicode[0], 2*(r2.sourceCountChars-1));
1542
    stream.Read(r2SourceUnicode[0], 2*(r2.sourceCountChars-1));
1543
 
1543
 
1544
    FSourceAnsi := AnsiString(WideString(r2sourceUnicode)); // Invalid chars are automatically converted into '?'
1544
    FSourceAnsi := AnsiString(WideString(r2sourceUnicode)); // Invalid chars are automatically converted into '?'
1545
    FSourceUnicode := WideString(r2sourceUnicode);
1545
    FSourceUnicode := WideString(r2sourceUnicode);
1546
    FID := ''; // will be added manually (at the constructor)
1546
    FID := ''; // will be added manually (at the constructor)
1547
    FSourceDrive := AnsiChar(r2sourceUnicode[1]);
1547
    FSourceDrive := r2sourceUnicode[1];
1548
    FDeletionTime := FileTimeToDateTime(r2.deletionTime);
1548
    FDeletionTime := FileTimeToDateTime(r2.deletionTime);
1549
    FOriginalSize := r2.originalSize;
1549
    FOriginalSize := r2.originalSize;
1550
  end
1550
  end
1551
  else
1551
  else
1552
  begin
1552
  begin
Line 1779... Line 1779...
1779
  end;
1779
  end;
1780
end;
1780
end;
1781
 
1781
 
1782
class procedure TRecycleBinManager.ListDrives(list: TObjectList{TRbDrive});
1782
class procedure TRecycleBinManager.ListDrives(list: TObjectList{TRbDrive});
1783
var
1783
var
1784
  drive: Char;
1784
  drive: AnsiChar;
1785
begin
1785
begin
1786
  for drive := 'A' to 'Z' do
1786
  for drive := 'A' to 'Z' do
1787
    if RecycleBinPossible(drive) then
1787
    if RecycleBinPossible(drive) then
1788
      list.Add(TRbDrive.Create(drive));
1788
      list.Add(TRbDrive.Create(drive));
1789
end;
1789
end;
Line 1844... Line 1844...
1844
  finally
1844
  finally
1845
    drives.Free;
1845
    drives.Free;
1846
  end;
1846
  end;
1847
end;
1847
end;
1848
 
1848
 
1849
class function TRecycleBinManager.RecycleBinPossible(Drive: Char): boolean;
1849
class function TRecycleBinManager.RecycleBinPossible(Drive: AnsiChar): boolean;
1850
var
1850
var
1851
  typ: Integer;
1851
  typ: Integer;
1852
begin
1852
begin
1853
  // Does the drive exist?
1853
  // Does the drive exist?
1854
  // see http://www.delphipraxis.net/post2933.html
1854
  // see http://www.delphipraxis.net/post2933.html
Line 2325... Line 2325...
2325
  RBHandle: THandle;
2325
  RBHandle: THandle;
2326
 
2326
 
2327
  reg: TRegistry;
2327
  reg: TRegistry;
2328
  rbuf: array[0..255] of byte;
2328
  rbuf: array[0..255] of byte;
2329
 
2329
 
2330
  dwResult: DWORD;
2330
  //dwResult: DWORD;
-
 
2331
  lpdwResult: PDWORD_PTR;
2331
begin
2332
begin
2332
  PSHGetSetSettings := nil;
2333
  PSHGetSetSettings := nil;
-
 
2334
  lpdwResult := nil;
2333
 
2335
 
2334
  RBHandle := LoadLibrary(shell32);
2336
  RBHandle := LoadLibrary(shell32);
2335
  try
2337
  try
2336
    if RBHandle <> 0 then
2338
    if RBHandle <> 0 then
2337
    begin
2339
    begin
Line 2358... Line 2360...
2358
      PSHGetSetSettings(lpss, SSF_NOCONFIRMRECYCLE, true); // Set
2360
      PSHGetSetSettings(lpss, SSF_NOCONFIRMRECYCLE, true); // Set
2359
 
2361
 
2360
      SendMessageTimeout (
2362
      SendMessageTimeout (
2361
        HWND_BROADCAST, WM_SETTINGCHANGE,
2363
        HWND_BROADCAST, WM_SETTINGCHANGE,
2362
        0, lParam (pChar ('ShellState')),
2364
        0, lParam (pChar ('ShellState')),
2363
        SMTO_ABORTIFHUNG, 5000, dwResult
2365
        SMTO_ABORTIFHUNG, 5000, lpdwResult(*dwResult*)
2364
      );
2366
      );
2365
    end
2367
    end
2366
    else
2368
    else
2367
    begin
2369
    begin
2368
      reg := TRegistry.Create;
2370
      reg := TRegistry.Create;
Line 2388... Line 2390...
2388
          reg.WriteBinaryData('ShellState', rbuf, SizeOf(rbuf)); // Set
2390
          reg.WriteBinaryData('ShellState', rbuf, SizeOf(rbuf)); // Set
2389
 
2391
 
2390
          SendMessageTimeout (
2392
          SendMessageTimeout (
2391
            HWND_BROADCAST, WM_SETTINGCHANGE,
2393
            HWND_BROADCAST, WM_SETTINGCHANGE,
2392
            0, lParam (pChar ('ShellState')),
2394
            0, lParam (pChar ('ShellState')),
2393
            SMTO_ABORTIFHUNG, 5000, dwResult
2395
            SMTO_ABORTIFHUNG, 5000, lpdwResult(*dwResult*)
2394
          );
2396
          );
2395
 
2397
 
2396
          reg.CloseKey;
2398
          reg.CloseKey;
2397
        end
2399
        end
2398
        else
2400
        else