Subversion Repositories recyclebinunit

Rev

Rev 80 | Rev 92 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 80 Rev 91
1
 
1
 
2
// ********************************************************************************
2
// ********************************************************************************
3
// **** ATTENTION! This unit is not developed anymore.                        *****
3
// **** ATTENTION! This unit is not developed anymore.                        *****
4
// **** Please use the new version RecBinUnit2.pas , which is Object-oriented *****
4
// **** Please use the new version RecBinUnit2.pas , which is Object-oriented *****
5
// ********************************************************************************
5
// ********************************************************************************
6
 
6
 
7
////////////////////////////////////////////////////////////////////////////////////
7
////////////////////////////////////////////////////////////////////////////////////
8
// RECYCLE-BIN-FUNCTIONS BY DANIEL MARSCHALL                                      //
8
// RECYCLE-BIN-FUNCTIONS BY DANIEL MARSCHALL                                      //
9
// E-MAIL: info@daniel-marschall.de                                               //
9
// E-MAIL: info@daniel-marschall.de                                               //
10
// WEB:    www.daniel-marschall.de                                                //
10
// WEB:    www.daniel-marschall.de                                                //
11
////////////////////////////////////////////////////////////////////////////////////
11
////////////////////////////////////////////////////////////////////////////////////
12
// Revision: 01 NOV 2016                                                          //
12
// Revision: 01 NOV 2016                                                          //
13
// This unit is freeware, but please link to my website if you are using it!      //
13
// This unit is freeware, but please link to my website if you are using it!      //
14
////////////////////////////////////////////////////////////////////////////////////
14
////////////////////////////////////////////////////////////////////////////////////
15
// Successfully tested with:                                                      //
15
// Successfully tested with:                                                      //
16
// Windows 95b (without IE4 Shell Extensions)                                     //
16
// Windows 95b (without IE4 Shell Extensions)                                     //
17
// Windows 95b (with IE4 Shell Extensions)                                        //
17
// Windows 95b (with IE4 Shell Extensions)                                        //
18
// Windows 98-SE                                                                  //
18
// Windows 98-SE                                                                  //
19
// Windows NT4 SP6                                                                //
19
// Windows NT4 SP6                                                                //
20
// Windows XP-SP3                                                                 //
20
// Windows XP-SP3                                                                 //
21
// Windows 2000-SP4                                                               //
21
// Windows 2000-SP4                                                               //
22
// Windows 2003 Server EE SP1                                                     //
22
// Windows 2003 Server EE SP1                                                     //
23
// Windows Vista                                                                  //
23
// Windows Vista                                                                  //
24
// Windows 7                                                                      //
24
// Windows 7                                                                      //
-
 
25
////////////////////////////////////////////////////////////////////////////////////
-
 
26
// DOES **NOT** WORK WITH "VERSION 2" INDEX FILES USED IN LATER VERSIONS OF WIN10 //
25
// Windows 10                                                                     //
27
// USE RECYCLE BIN UNIT V2 INSTEAD!                                               //
26
////////////////////////////////////////////////////////////////////////////////////
28
////////////////////////////////////////////////////////////////////////////////////
27
//                                                                                //
29
//                                                                                //
28
//  Needs Delphi 4 or higher. If you are using Delphi 4 or 5, you can not use the //
30
//  Needs Delphi 4 or higher. If you are using Delphi 4 or 5, you can not use the //
29
//  RecyclerGetDateTime() functions, because the unit "DateUtils" is missing.     //
31
//  RecyclerGetDateTime() functions, because the unit "DateUtils" is missing.     //
30
//  Warning! This is a platform unit.                                             //
32
//  Warning! This is a platform unit.                                             //
31
//                                                                                //
33
//                                                                                //
32
//  To do! Can you help?                                                          //
34
//  To do! Can you help?                                                          //
33
//    - Win7 : Drive GUIDs                                                        //
35
//    - Win7 : Drive GUIDs                                                        //
34
//    - Win7 : Absolute vs. Relative size limitations                             //
36
//    - Win7 : Absolute vs. Relative size limitations                             //
35
//    - WideString-Support (input/output)                                         //
37
//    - WideString-Support (input/output)                                         //
36
//    - Always do EOF before reading anything?                                    //
38
//    - Always do EOF before reading anything?                                    //
37
//    - Is it possible to identify a Vista-file that is not named $Ixxxxxx.ext?   //
39
//    - Is it possible to identify a Vista-file that is not named $Ixxxxxx.ext?   //
38
//    - RecyclerGetInfofiles() check additionally for removable device?           //
40
//    - RecyclerGetInfofiles() check additionally for removable device?           //
39
//      RecyclerIsValid() is false.                                               //
41
//      RecyclerIsValid() is false.                                               //
40
//    - Make it possible to empty the recycle bin of one specific drive!          //
42
//    - Make it possible to empty the recycle bin of one specific drive!          //
41
//                                                                                //
43
//                                                                                //
42
//  Unknown! Do you know the answer?                                              //
44
//  Unknown! Do you know the answer?                                              //
43
//    - How does Windows 9x/NT manage the daylight saving time (if it does)?      //
45
//    - How does Windows 9x/NT manage the daylight saving time (if it does)?      //
44
//    - How does Windows Vista react to a RECYCLER\ folder on a NTFS device?      //
46
//    - How does Windows Vista react to a RECYCLER\ folder on a NTFS device?      //
45
//    - How does Windows Vista react to a RECYCLED\ folder on a FAT device?       //
47
//    - How does Windows Vista react to a RECYCLED\ folder on a FAT device?       //
46
//                                                                                //
48
//                                                                                //
47
//  Thanks to all these who have helped me solving coding problems.               //
49
//  Thanks to all these who have helped me solving coding problems.               //
48
//  Thanks to SEBA for sending in the Windows Vista trash structure files.        //
50
//  Thanks to SEBA for sending in the Windows Vista trash structure files.        //
49
//  Thanks to OMATA for testing the unit with Delphi 4.                           //
51
//  Thanks to OMATA for testing the unit with Delphi 4.                           //
50
//  Thanks to DEITYSOU for making a bugfix of DriveExists()                       //
52
//  Thanks to DEITYSOU for making a bugfix of DriveExists()                       //
51
//                                                                                //
53
//                                                                                //
52
////////////////////////////////////////////////////////////////////////////////////
54
////////////////////////////////////////////////////////////////////////////////////
53
 
55
 
54
(*
56
(*
55
 
57
 
56
== TODO LISTE ==
58
== TODO LISTE ==
57
 
59
 
58
- Wichtig! Windows XP: InfoTip, IntroText und LocalizedString sind Resourcenangaben und müssen ausgelesen werden!
60
- Wichtig! Windows XP: InfoTip, IntroText und LocalizedString sind Resourcenangaben und müssen ausgelesen werden!
59
- Testen: Wie reagiert Windows, wenn Bitbucket\C existiert, aber kein Wert 'Percent' hat? Mit der Standardeinstellung?
61
- Testen: Wie reagiert Windows, wenn Bitbucket\C existiert, aber kein Wert 'Percent' hat? Mit der Standardeinstellung?
60
- Bug: Windows 2000 bei bestehenden Windows 95 Partition: Recycler Filename ist dann Recycled und nicht Recycler!
62
- Bug: Windows 2000 bei bestehenden Windows 95 Partition: Recycler Filename ist dann Recycled und nicht Recycler!
61
- bug? w95 recycled file hat immer selben löschzeitpunkt und größe? war die nicht verschieden?
63
- bug? w95 recycled file hat immer selben löschzeitpunkt und größe? war die nicht verschieden?
62
- beachtet? bei leerem papierkorb auf fat ist weder info noch info2 vorhanden?
64
- beachtet? bei leerem papierkorb auf fat ist weder info noch info2 vorhanden?
63
- testen: auch möglich, einen vista papierkorb offline öffnen?
65
- testen: auch möglich, einen vista papierkorb offline öffnen?
64
- Problem: bei win95(ohne ie4) und win2000 gleichzeitiger installation: es existiert info UND info2!!!
66
- Problem: bei win95(ohne ie4) und win2000 gleichzeitiger installation: es existiert info UND info2!!!
65
- Implement SETTER functions to every kind of configuration thing. (percentage etc)
67
- Implement SETTER functions to every kind of configuration thing. (percentage etc)
66
- Registry CURRENT_USER: Funktionen auch für fremde Benutzer zur Verfügung stellen?
68
- Registry CURRENT_USER: Funktionen auch für fremde Benutzer zur Verfügung stellen?
67
- Es sollte möglich sein, dass ein Laufwerk mehr als 1 Recycler beinhaltet -- behandeln
69
- Es sollte möglich sein, dass ein Laufwerk mehr als 1 Recycler beinhaltet -- behandeln
68
 
70
 
69
=== Future Ideas ===
71
=== Future Ideas ===
70
 
72
 
71
- Demoapplikation: Dateien statt Text als Explorer-Like (TListView)?
73
- Demoapplikation: Dateien statt Text als Explorer-Like (TListView)?
72
- Einzelne Elemente oder alle wiederherstellen oder löschen
74
- Einzelne Elemente oder alle wiederherstellen oder löschen
73
- Konfiguration für Laufwerke ändern etc
75
- Konfiguration für Laufwerke ändern etc
74
- IconString -> TIcon Convertion functions
76
- IconString -> TIcon Convertion functions
75
- platzreservierung in mb-angabe berechnen
77
- platzreservierung in mb-angabe berechnen
76
- I don't know if there exists any API function which checks the state at any internal way.
78
- I don't know if there exists any API function which checks the state at any internal way.
77
- copy/move files from recyclebin
79
- copy/move files from recyclebin
78
 
80
 
79
*)
81
*)
80
 
82
 
81
// TODO: Also include BC++ Versions
83
// TODO: Also include BC++ Versions
82
{$IFNDEF BCB}
84
{$IFNDEF BCB}
83
{$DEFINE DEL1UP}
85
{$DEFINE DEL1UP}
84
{$IFNDEF VER80}
86
{$IFNDEF VER80}
85
{$DEFINE DEL2UP}
87
{$DEFINE DEL2UP}
86
{$IFNDEF VER90}
88
{$IFNDEF VER90}
87
{$DEFINE DEL3UP}
89
{$DEFINE DEL3UP}
88
{$IFNDEF VER100}
90
{$IFNDEF VER100}
89
{$DEFINE DEL4UP}
91
{$DEFINE DEL4UP}
90
{$IFNDEF VER120}
92
{$IFNDEF VER120}
91
{$DEFINE DEL5UP}
93
{$DEFINE DEL5UP}
92
{$IFNDEF VER130}
94
{$IFNDEF VER130}
93
{$DEFINE DEL6UP}
95
{$DEFINE DEL6UP}
94
{$IFNDEF VER140}
96
{$IFNDEF VER140}
95
{$DEFINE DEL7UP}
97
{$DEFINE DEL7UP}
96
{$ENDIF}
98
{$ENDIF}
97
{$ENDIF}
99
{$ENDIF}
98
{$ENDIF}
100
{$ENDIF}
99
{$ENDIF}
101
{$ENDIF}
100
{$ENDIF}
102
{$ENDIF}
101
{$ENDIF}
103
{$ENDIF}
102
{$ENDIF}
104
{$ENDIF}
103
 
105
 
104
{$IFDEF DEL7UP}
106
{$IFDEF DEL7UP}
105
{$WARN UNSAFE_TYPE OFF}
107
{$WARN UNSAFE_TYPE OFF}
106
{$WARN UNSAFE_CODE OFF}
108
{$WARN UNSAFE_CODE OFF}
107
{$WARN UNSAFE_CAST OFF}
109
{$WARN UNSAFE_CAST OFF}
108
{$ENDIF}
110
{$ENDIF}
109
 
111
 
110
{$IFDEF DEL6UP}
112
{$IFDEF DEL6UP}
111
unit RecyclerFunctions platform;
113
unit RecyclerFunctions platform;
112
{$ELSE}
114
{$ELSE}
113
unit RecyclerFunctions;
115
unit RecyclerFunctions;
114
{$ENDIF}
116
{$ENDIF}
115
 
117
 
116
// Configuration
118
// Configuration
117
 
119
 
118
// If enabled, all functions with parameter "InfofileOrRecycleFolder" will
120
// If enabled, all functions with parameter "InfofileOrRecycleFolder" will
119
// also accept files which are not the indexfile (then, a INFO2 or INFO file
121
// also accept files which are not the indexfile (then, a INFO2 or INFO file
120
// will be searched in this directory).
122
// will be searched in this directory).
121
{.$DEFINE allow_all_filenames}
123
{.$DEFINE allow_all_filenames}
122
 
124
 
123
interface
125
interface
124
 
126
 
125
uses
127
uses
126
  Windows, SysUtils, Classes, {$IFDEF DEL6UP}DateUtils,{$ENDIF}
128
  Windows, SysUtils, Classes, {$IFDEF DEL6UP}DateUtils,{$ENDIF}
127
  ShellApi{$IFNDEF DEL6UP}, FileCtrl{$ENDIF}, Registry,
129
  ShellApi{$IFNDEF DEL6UP}, FileCtrl{$ENDIF}, Registry,
128
  Messages, BitOps;
130
  Messages, BitOps;
129
 
131
 
130
type
132
type
131
  EUnknownState = class(Exception);
133
  EUnknownState = class(Exception);
132
  EEventCategoryNotDefined = class(Exception);
134
  EEventCategoryNotDefined = class(Exception);
133
  EAPICallError = class(Exception);
135
  EAPICallError = class(Exception);
134
 
136
 
135
  PSHQueryRBInfo = ^TSHQueryRBInfo;
137
  PSHQueryRBInfo = ^TSHQueryRBInfo;
136
  TSHQueryRBInfo = packed record
138
  TSHQueryRBInfo = packed record
137
    cbSize      : dword;
139
    cbSize      : dword;
138
    i64Size     : int64;
140
    i64Size     : int64;
139
    i64NumItems : int64;
141
    i64NumItems : int64;
140
  end;
142
  end;
141
 
143
 
142
  GPOLICYBOOL = (gpUndefined, gpEnabled, gpDisabled);
144
  GPOLICYBOOL = (gpUndefined, gpEnabled, gpDisabled);
143
 
145
 
144
const
146
const
145
  RECYCLER_CLSID = '{645FF040-5081-101B-9F08-00AA002F954E}';
147
  RECYCLER_CLSID = '{645FF040-5081-101B-9F08-00AA002F954E}';
146
 
148
 
147
{$IFDEF DEL6UP}
149
{$IFDEF DEL6UP}
148
function RecyclerGetDateTime(drive: char; fileid: string): tdatetime; overload;
150
function RecyclerGetDateTime(drive: char; fileid: string): tdatetime; overload;
149
function RecyclerGetDateTime(drive: char; UserSID: string; fileid: string): tdatetime; overload;
151
function RecyclerGetDateTime(drive: char; UserSID: string; fileid: string): tdatetime; overload;
150
function RecyclerGetDateTime(InfofileOrRecycleFolder: string): tdatetime; overload;
152
function RecyclerGetDateTime(InfofileOrRecycleFolder: string): tdatetime; overload;
151
function RecyclerGetDateTime(InfofileOrRecycleFolder: string; id: string): tdatetime; overload;
153
function RecyclerGetDateTime(InfofileOrRecycleFolder: string; id: string): tdatetime; overload;
152
{$ENDIF}
154
{$ENDIF}
153
 
155
 
154
function RecyclerGetSourceUnicode(drive: char; fileid: string): WideString; overload;
156
function RecyclerGetSourceUnicode(drive: char; fileid: string): WideString; overload;
155
function RecyclerGetSourceUnicode(drive: char; UserSID: string; fileid: string): WideString; overload;
157
function RecyclerGetSourceUnicode(drive: char; UserSID: string; fileid: string): WideString; overload;
156
function RecyclerGetSourceUnicode(InfofileOrRecycleFolder: string): WideString; overload;
158
function RecyclerGetSourceUnicode(InfofileOrRecycleFolder: string): WideString; overload;
157
function RecyclerGetSourceUnicode(InfofileOrRecycleFolder: string; id: string): WideString; overload;
159
function RecyclerGetSourceUnicode(InfofileOrRecycleFolder: string; id: string): WideString; overload;
158
 
160
 
159
function RecyclerGetSource(drive: char; fileid: string): string; overload;
161
function RecyclerGetSource(drive: char; fileid: string): string; overload;
160
function RecyclerGetSource(drive: char; UserSID: string; fileid: string): string; overload;
162
function RecyclerGetSource(drive: char; UserSID: string; fileid: string): string; overload;
161
function RecyclerGetSource(InfofileOrRecycleFolder: string): string; overload;
163
function RecyclerGetSource(InfofileOrRecycleFolder: string): string; overload;
162
function RecyclerGetSource(InfofileOrRecycleFolder: string; id: string): string; overload;
164
function RecyclerGetSource(InfofileOrRecycleFolder: string; id: string): string; overload;
163
 
165
 
164
procedure RecyclerListIndexes(drive: char; result: TStringList); overload;
166
procedure RecyclerListIndexes(drive: char; result: TStringList); overload;
165
procedure RecyclerListIndexes(drive: char; UserSID: string; result: TStringList); overload;
167
procedure RecyclerListIndexes(drive: char; UserSID: string; result: TStringList); overload;
166
procedure RecyclerListIndexes(InfofileOrRecycleFolder: string; result: TStringList); overload;
168
procedure RecyclerListIndexes(InfofileOrRecycleFolder: string; result: TStringList); overload;
167
 
169
 
168
function RecyclerGetSourceDrive(drive: char; fileid: string): char; overload;
170
function RecyclerGetSourceDrive(drive: char; fileid: string): char; overload;
169
function RecyclerGetSourceDrive(drive: char; UserSID: string; fileid: string): char; overload;
171
function RecyclerGetSourceDrive(drive: char; UserSID: string; fileid: string): char; overload;
170
function RecyclerGetSourceDrive(InfofileOrRecycleFolder: string): char; overload;
172
function RecyclerGetSourceDrive(InfofileOrRecycleFolder: string): char; overload;
171
function RecyclerGetSourceDrive(InfofileOrRecycleFolder: string; id: string): char; overload;
173
function RecyclerGetSourceDrive(InfofileOrRecycleFolder: string; id: string): char; overload;
172
 
174
 
173
function RecyclerOriginalSize(drive: char; fileid: string): integer; overload;
175
function RecyclerOriginalSize(drive: char; fileid: string): integer; overload;
174
function RecyclerOriginalSize(drive: char; UserSID: string; fileid: string): integer; overload;
176
function RecyclerOriginalSize(drive: char; UserSID: string; fileid: string): integer; overload;
175
function RecyclerOriginalSize(InfofileOrRecycleFolder: string): integer; overload;
177
function RecyclerOriginalSize(InfofileOrRecycleFolder: string): integer; overload;
176
function RecyclerOriginalSize(InfofileOrRecycleFolder: string; id: string): integer; overload;
178
function RecyclerOriginalSize(InfofileOrRecycleFolder: string; id: string): integer; overload;
177
 
179
 
178
function RecyclerIsValid(drive: char): boolean; overload;
180
function RecyclerIsValid(drive: char): boolean; overload;
179
function RecyclerIsValid(drive: char; UserSID: string): boolean; overload;
181
function RecyclerIsValid(drive: char; UserSID: string): boolean; overload;
180
function RecyclerIsValid(InfofileOrRecycleFolder: string): boolean; overload;
182
function RecyclerIsValid(InfofileOrRecycleFolder: string): boolean; overload;
181
 
183
 
182
function RecyclerCurrentFilename(drive: char; fileid: string): string; overload;
184
function RecyclerCurrentFilename(drive: char; fileid: string): string; overload;
183
function RecyclerCurrentFilename(drive: char; UserSID: string; fileid: string): string; overload;
185
function RecyclerCurrentFilename(drive: char; UserSID: string; fileid: string): string; overload;
184
function RecyclerCurrentFilename(InfofileOrRecycleFolder: string): string; overload;
186
function RecyclerCurrentFilename(InfofileOrRecycleFolder: string): string; overload;
185
function RecyclerCurrentFilename(InfofileOrRecycleFolder: string; id: string): string; overload;
187
function RecyclerCurrentFilename(InfofileOrRecycleFolder: string; id: string): string; overload;
186
 
188
 
187
function RecyclerGetPath(drive: char; UserSID: string; IncludeInfofile: boolean; fileid: string): string; overload;
189
function RecyclerGetPath(drive: char; UserSID: string; IncludeInfofile: boolean; fileid: string): string; overload;
188
function RecyclerGetPath(drive: char; UserSID: string; IncludeInfofile: boolean): string; overload;
190
function RecyclerGetPath(drive: char; UserSID: string; IncludeInfofile: boolean): string; overload;
189
function RecyclerGetPath(drive: char; IncludeInfofile: boolean): string; overload;
191
function RecyclerGetPath(drive: char; IncludeInfofile: boolean): string; overload;
190
function RecyclerGetPath(drive: char; UserSID: string): string; overload;
192
function RecyclerGetPath(drive: char; UserSID: string): string; overload;
191
function RecyclerGetPath(drive: char): string; overload;
193
function RecyclerGetPath(drive: char): string; overload;
192
 
194
 
193
procedure RecyclerGetInfofiles(drive: char; UserSID: string; IncludeInfofile: boolean; fileid: string; result: TStringList); overload;
195
procedure RecyclerGetInfofiles(drive: char; UserSID: string; IncludeInfofile: boolean; fileid: string; result: TStringList); overload;
194
procedure RecyclerGetInfofiles(drive: char; UserSID: string; IncludeInfofile: boolean; result: TStringList); overload;
196
procedure RecyclerGetInfofiles(drive: char; UserSID: string; IncludeInfofile: boolean; result: TStringList); overload;
195
procedure RecyclerGetInfofiles(drive: char; IncludeInfofile: boolean; result: TStringList); overload;
197
procedure RecyclerGetInfofiles(drive: char; IncludeInfofile: boolean; result: TStringList); overload;
196
procedure RecyclerGetInfofiles(drive: char; UserSID: string; result: TStringList); overload;
198
procedure RecyclerGetInfofiles(drive: char; UserSID: string; result: TStringList); overload;
197
procedure RecyclerGetInfofiles(drive: char; result: TStringList); overload;
199
procedure RecyclerGetInfofiles(drive: char; result: TStringList); overload;
198
 
200
 
199
function RecyclerCurrentFilenameAndPath(drive: char; UserSID: string; fileid: string): string; overload;
201
function RecyclerCurrentFilenameAndPath(drive: char; UserSID: string; fileid: string): string; overload;
200
function RecyclerCurrentFilenameAndPath(drive: char; fileid: string): string; overload;
202
function RecyclerCurrentFilenameAndPath(drive: char; fileid: string): string; overload;
201
function RecyclerCurrentFilenameAndPath(InfofileOrRecycleFolder: string; id: string): string; overload;
203
function RecyclerCurrentFilenameAndPath(InfofileOrRecycleFolder: string; id: string): string; overload;
202
 
204
 
203
function RecyclerRemoveItem(drive: char; UserSID: string; fileid: string): boolean; overload;
205
function RecyclerRemoveItem(drive: char; UserSID: string; fileid: string): boolean; overload;
204
function RecyclerRemoveItem(drive: char; fileid: string): boolean; overload;
206
function RecyclerRemoveItem(drive: char; fileid: string): boolean; overload;
205
function RecyclerRemoveItem(InfofileOrRecycleFolder: string; id: string): boolean; overload;
207
function RecyclerRemoveItem(InfofileOrRecycleFolder: string; id: string): boolean; overload;
206
 
208
 
207
procedure RecyclerGetAllRecyclerDrives(result: TStringList);
209
procedure RecyclerGetAllRecyclerDrives(result: TStringList);
208
 
210
 
209
function RecyclerEmptyRecycleBin(flags: cardinal): boolean; overload;
211
function RecyclerEmptyRecycleBin(flags: cardinal): boolean; overload;
210
function RecyclerEmptyRecycleBin(sound, progress, confirmation: boolean): boolean; overload;
212
function RecyclerEmptyRecycleBin(sound, progress, confirmation: boolean): boolean; overload;
211
 
213
 
212
function RecyclerAddFileOrFolder(FileOrFolder: string; confirmation: boolean): boolean; overload;
214
function RecyclerAddFileOrFolder(FileOrFolder: string; confirmation: boolean): boolean; overload;
213
function RecyclerAddFileOrFolder(FileOrFolder: string): boolean; overload;
215
function RecyclerAddFileOrFolder(FileOrFolder: string): boolean; overload;
214
 
216
 
215
function RecyclerConfirmationDialogEnabled: boolean;
217
function RecyclerConfirmationDialogEnabled: boolean;
216
function RecyclerShellStateConfirmationDialogEnabled: boolean;
218
function RecyclerShellStateConfirmationDialogEnabled: boolean;
217
procedure RecyclerConfirmationDialogSetEnabled(NewSetting: boolean);
219
procedure RecyclerConfirmationDialogSetEnabled(NewSetting: boolean);
218
 
220
 
219
function RecyclerGetCurrentIconString: string;
221
function RecyclerGetCurrentIconString: string;
220
function RecyclerGetDefaultIconString: string;
222
function RecyclerGetDefaultIconString: string;
221
function RecyclerGetEmptyIconString: string;
223
function RecyclerGetEmptyIconString: string;
222
function RecyclerGetFullIconString: string;
224
function RecyclerGetFullIconString: string;
223
 
225
 
224
function RecyclerGetName: string;
226
function RecyclerGetName: string;
225
function RecyclerGetInfoTip: string;
227
function RecyclerGetInfoTip: string;
226
function RecyclerGetIntroText: string;
228
function RecyclerGetIntroText: string;
227
 
229
 
228
function RecyclerEmptyEventGetName: string;
230
function RecyclerEmptyEventGetName: string;
229
function RecyclerEmptyEventGetCurrentSound: string;
231
function RecyclerEmptyEventGetCurrentSound: string;
230
function RecyclerEmptyEventGetDefaultSound: string;
232
function RecyclerEmptyEventGetDefaultSound: string;
231
procedure RecyclerEmptyEventGetSoundCategories(AStringList: TStringList);
233
procedure RecyclerEmptyEventGetSoundCategories(AStringList: TStringList);
232
function RecyclerEmptyEventGetSound(ACategory: string): string;
234
function RecyclerEmptyEventGetSound(ACategory: string): string;
233
 
235
 
234
function RecyclerGlobalGetPercentUsage: integer;
236
function RecyclerGlobalGetPercentUsage: integer;
235
function RecyclerSpecificGetPercentUsage(Drive: Char): integer;
237
function RecyclerSpecificGetPercentUsage(Drive: Char): integer;
236
function RecyclerGetPercentUsageAutoDeterminate(Drive: Char): integer;
238
function RecyclerGetPercentUsageAutoDeterminate(Drive: Char): integer;
237
 
239
 
238
function RecyclerGlobalIsNukeOnDelete: boolean;
240
function RecyclerGlobalIsNukeOnDelete: boolean;
239
function RecyclerSpecificIsNukeOnDelete(Drive: Char): boolean;
241
function RecyclerSpecificIsNukeOnDelete(Drive: Char): boolean;
240
function RecyclerIsNukeOnDeleteAutoDeterminate(Drive: Char): boolean;
242
function RecyclerIsNukeOnDeleteAutoDeterminate(Drive: Char): boolean;
241
 
243
 
242
function RecyclerHasGlobalSettings: boolean;
244
function RecyclerHasGlobalSettings: boolean;
243
 
245
 
244
function RecyclerIsEmpty: boolean; overload;
246
function RecyclerIsEmpty: boolean; overload;
245
function RecyclerIsEmpty(Drive: Char): boolean; overload;
247
function RecyclerIsEmpty(Drive: Char): boolean; overload;
246
 
248
 
247
function RecyclerGetNumItems: int64; overload;
249
function RecyclerGetNumItems: int64; overload;
248
function RecyclerGetNumItems(Drive: Char): int64; overload;
250
function RecyclerGetNumItems(Drive: Char): int64; overload;
249
 
251
 
250
function RecyclerGetSize: int64; overload;
252
function RecyclerGetSize: int64; overload;
251
function RecyclerGetSize(Drive: Char): int64; overload;
253
function RecyclerGetSize(Drive: Char): int64; overload;
252
 
254
 
253
function RecyclerGetAPIInfo(Drive: Char): TSHQueryRBInfo; overload;
255
function RecyclerGetAPIInfo(Drive: Char): TSHQueryRBInfo; overload;
254
function RecyclerGetAPIInfo(Path: String): TSHQueryRBInfo; overload;
256
function RecyclerGetAPIInfo(Path: String): TSHQueryRBInfo; overload;
255
 
257
 
256
function RecyclerGetCLSID: string;
258
function RecyclerGetCLSID: string;
257
 
259
 
258
// Diese Funktion ist false, wenn sie z.B. unter Windows 95 ohne Internet Explorer
260
// Diese Funktion ist false, wenn sie z.B. unter Windows 95 ohne Internet Explorer
259
// 4.0 Shell Extension ausgeführt wird. Wenn abwärtskompatibler Code geschrieben
261
// 4.0 Shell Extension ausgeführt wird. Wenn abwärtskompatibler Code geschrieben
260
// werden soll, sollte RecyclerQueryFunctionAvailable() verwendet werden, da
262
// werden soll, sollte RecyclerQueryFunctionAvailable() verwendet werden, da
261
// unter Windows 95 folgende Funktionalitäten NICHT vorhanden sind:
263
// unter Windows 95 folgende Funktionalitäten NICHT vorhanden sind:
262
// - RecyclerIsEmpty
264
// - RecyclerIsEmpty
263
// - RecyclerGetNumItems
265
// - RecyclerGetNumItems
264
// - RecyclerGetSize
266
// - RecyclerGetSize
265
// - RecyclerGetAPIInfo
267
// - RecyclerGetAPIInfo
266
function RecyclerQueryFunctionAvailable: boolean;
268
function RecyclerQueryFunctionAvailable: boolean;
267
 
269
 
268
function RecyclerGroupPolicyNoRecycleFiles: GPOLICYBOOL;
270
function RecyclerGroupPolicyNoRecycleFiles: GPOLICYBOOL;
269
function RecyclerGroupPolicyConfirmFileDelete: GPOLICYBOOL;
271
function RecyclerGroupPolicyConfirmFileDelete: GPOLICYBOOL;
270
function RecyclerGroupPolicyRecycleBinSize: integer;
272
function RecyclerGroupPolicyRecycleBinSize: integer;
271
 
273
 
272
function GPBoolToString(value: GPOLICYBOOL): String;
274
function GPBoolToString(value: GPOLICYBOOL): String;
273
 
275
 
274
function RecyclerIsPossible(Drive: Char): boolean;
276
function RecyclerIsPossible(Drive: Char): boolean;
275
 
277
 
276
function RecyclerLibraryVersion: string;
278
function RecyclerLibraryVersion: string;
277
 
279
 
278
implementation
280
implementation
279
 
281
 
280
type
282
type
281
  SHELLSTATE = record
283
  SHELLSTATE = record
282
    Flags1: DWORD;
284
    Flags1: DWORD;
283
(*
285
(*
284
    BOOL fShowAllObjects : 1;
286
    BOOL fShowAllObjects : 1;
285
    BOOL fShowExtensions : 1;
287
    BOOL fShowExtensions : 1;
286
    BOOL fNoConfirmRecycle : 1;
288
    BOOL fNoConfirmRecycle : 1;
287
 
289
 
288
    BOOL fShowSysFiles : 1;
290
    BOOL fShowSysFiles : 1;
289
    BOOL fShowCompColor : 1;
291
    BOOL fShowCompColor : 1;
290
    BOOL fDoubleClickInWebView : 1;
292
    BOOL fDoubleClickInWebView : 1;
291
    BOOL fDesktopHTML : 1;
293
    BOOL fDesktopHTML : 1;
292
    BOOL fWin95Classic : 1;
294
    BOOL fWin95Classic : 1;
293
    BOOL fDontPrettyPath : 1;
295
    BOOL fDontPrettyPath : 1;
294
    BOOL fShowAttribCol : 1; // No longer used, dead bit
296
    BOOL fShowAttribCol : 1; // No longer used, dead bit
295
    BOOL fMapNetDrvBtn : 1;
297
    BOOL fMapNetDrvBtn : 1;
296
    BOOL fShowInfoTip : 1;
298
    BOOL fShowInfoTip : 1;
297
    BOOL fHideIcons : 1;
299
    BOOL fHideIcons : 1;
298
    BOOL fWebView : 1;
300
    BOOL fWebView : 1;
299
    BOOL fFilter : 1;
301
    BOOL fFilter : 1;
300
    BOOL fShowSuperHidden : 1;
302
    BOOL fShowSuperHidden : 1;
301
    BOOL fNoNetCrawling : 1;
303
    BOOL fNoNetCrawling : 1;
302
*)
304
*)
303
    dwWin95Unused: DWORD; // Win95 only - no longer supported pszHiddenFileExts
305
    dwWin95Unused: DWORD; // Win95 only - no longer supported pszHiddenFileExts
304
    uWin95Unused: UINT; // Win95 only - no longer supported cbHiddenFileExts
306
    uWin95Unused: UINT; // Win95 only - no longer supported cbHiddenFileExts
305
 
307
 
306
    // Note: Not a typo!  This is a persisted structure so we cannot use LPARAM
308
    // Note: Not a typo!  This is a persisted structure so we cannot use LPARAM
307
    lParamSort: Integer;
309
    lParamSort: Integer;
308
    iSortDirection: Integer;
310
    iSortDirection: Integer;
309
 
311
 
310
    version: UINT;
312
    version: UINT;
311
 
313
 
312
    // new for win2k. need notUsed var to calc the right size of ie4 struct
314
    // new for win2k. need notUsed var to calc the right size of ie4 struct
313
    // FIELD_OFFSET does not work on bit fields
315
    // FIELD_OFFSET does not work on bit fields
314
    uNotUsed: UINT; // feel free to rename and use
316
    uNotUsed: UINT; // feel free to rename and use
315
    Flags2: DWORD;
317
    Flags2: DWORD;
316
(*
318
(*
317
    BOOL fSepProcess: 1;
319
    BOOL fSepProcess: 1;
318
    // new for Whistler.
320
    // new for Whistler.
319
    BOOL fStartPanelOn: 1;       //Indicates if the Whistler StartPanel mode is ON or OFF.
321
    BOOL fStartPanelOn: 1;       //Indicates if the Whistler StartPanel mode is ON or OFF.
320
    BOOL fShowStartPage: 1;      //Indicates if the Whistler StartPage on desktop is ON or OFF.
322
    BOOL fShowStartPage: 1;      //Indicates if the Whistler StartPage on desktop is ON or OFF.
321
    UINT fSpareFlags : 13;
323
    UINT fSpareFlags : 13;
322
*)
324
*)
323
  end;
325
  end;
324
  LPSHELLSTATE = ^SHELLSTATE;
326
  LPSHELLSTATE = ^SHELLSTATE;
325
 
327
 
326
const
328
const
327
  {$IFDEF MSWINDOWS}
329
  {$IFDEF MSWINDOWS}
328
    shell32  = 'shell32.dll';
330
    shell32  = 'shell32.dll';
329
    advapi32 = 'advapi32.dll';
331
    advapi32 = 'advapi32.dll';
330
  {$ENDIF}
332
  {$ENDIF}
331
  {$IFDEF LINUX}
333
  {$IFDEF LINUX}
332
    shell32  = 'libshell32.borland.so';
334
    shell32  = 'libshell32.borland.so';
333
    advapi32 = 'libwine.borland.so';
335
    advapi32 = 'libwine.borland.so';
334
  {$ENDIF}
336
  {$ENDIF}
335
 
337
 
336
  // Masks for the shellstate
338
  // Masks for the shellstate
337
   SSF_SHOWALLOBJECTS  = $00000001;
339
   SSF_SHOWALLOBJECTS  = $00000001;
338
  SSF_SHOWEXTENSIONS  = $00000002;
340
  SSF_SHOWEXTENSIONS  = $00000002;
339
  SSF_HIDDENFILEEXTS  = $00000004;
341
  SSF_HIDDENFILEEXTS  = $00000004;
340
  SSF_SERVERADMINUI   = $00000004;
342
  SSF_SERVERADMINUI   = $00000004;
341
  SSF_SHOWCOMPCOLOR   = $00000008;
343
  SSF_SHOWCOMPCOLOR   = $00000008;
342
  SSF_SORTCOLUMNS     = $00000010;
344
  SSF_SORTCOLUMNS     = $00000010;
343
  SSF_SHOWSYSFILES    = $00000020;
345
  SSF_SHOWSYSFILES    = $00000020;
344
  SSF_DOUBLECLICKINWEBVIEW = $00000080;
346
  SSF_DOUBLECLICKINWEBVIEW = $00000080;
345
  SSF_SHOWATTRIBCOL   = $00000100;
347
  SSF_SHOWATTRIBCOL   = $00000100;
346
  SSF_DESKTOPHTML     = $00000200;
348
  SSF_DESKTOPHTML     = $00000200;
347
  SSF_WIN95CLASSIC    = $00000400;
349
  SSF_WIN95CLASSIC    = $00000400;
348
  SSF_DONTPRETTYPATH  = $00000800;
350
  SSF_DONTPRETTYPATH  = $00000800;
349
  SSF_SHOWINFOTIP     = $00002000;
351
  SSF_SHOWINFOTIP     = $00002000;
350
  SSF_MAPNETDRVBUTTON = $00001000;
352
  SSF_MAPNETDRVBUTTON = $00001000;
351
  SSF_NOCONFIRMRECYCLE = $00008000;
353
  SSF_NOCONFIRMRECYCLE = $00008000;
352
  SSF_HIDEICONS       = $00004000;
354
  SSF_HIDEICONS       = $00004000;
353
  SSF_FILTER          = $00010000;
355
  SSF_FILTER          = $00010000;
354
  SSF_WEBVIEW         = $00020000;
356
  SSF_WEBVIEW         = $00020000;
355
  SSF_SHOWSUPERHIDDEN = $00040000;
357
  SSF_SHOWSUPERHIDDEN = $00040000;
356
  SSF_SEPPROCESS      = $00080000;
358
  SSF_SEPPROCESS      = $00080000;
357
  SSF_NONETCRAWLING   = $00100000;
359
  SSF_NONETCRAWLING   = $00100000;
358
  SSF_STARTPANELON    = $00200000;
360
  SSF_STARTPANELON    = $00200000;
359
  SSF_SHOWSTARTPAGE   = $00400000;
361
  SSF_SHOWSTARTPAGE   = $00400000;
360
 
362
 
361
// **********************************************************
363
// **********************************************************
362
// COMPATIBILITY FUNCTIONS
364
// COMPATIBILITY FUNCTIONS
363
// **********************************************************
365
// **********************************************************
364
 
366
 
365
{$IFNDEF DEL5UP}
367
{$IFNDEF DEL5UP}
366
function IncludeTrailingBackslash(str: string): string;
368
function IncludeTrailingBackslash(str: string): string;
367
begin
369
begin
368
  if Copy(str, length(str), 1) = '\' then    // TODO? Gibt es PathDelim in Delphi 4?
370
  if Copy(str, length(str), 1) = '\' then    // TODO? Gibt es PathDelim in Delphi 4?
369
    Result := str
371
    Result := str
370
  else
372
  else
371
    Result := str + '\';
373
    Result := str + '\';
372
end;
374
end;
373
{$ENDIF}
375
{$ENDIF}
374
 
376
 
375
// **********************************************************
377
// **********************************************************
376
// INTERNALLY USED FUNCTIONS
378
// INTERNALLY USED FUNCTIONS
377
// **********************************************************
379
// **********************************************************
378
 
380
 
379
resourcestring
381
resourcestring
380
  LNG_UNEXPECTED_STATE = 'Cannot determinate state of "%s" because of an unknown value in the configuration of your operation system. Please contact the developer of the Recycler Bin Unit and help improving the determination methods!';
382
  LNG_UNEXPECTED_STATE = 'Cannot determinate state of "%s" because of an unknown value in the configuration of your operation system. Please contact the developer of the Recycler Bin Unit and help improving the determination methods!';
381
  LNG_API_CALL_ERROR = 'Error while calling the API. Additional information: "%s".';
383
  LNG_API_CALL_ERROR = 'Error while calling the API. Additional information: "%s".';
382
  LNG_NOT_CALLABLE = '%s not callable';
384
  LNG_NOT_CALLABLE = '%s not callable';
383
  LNG_ERROR_CODE = '%s (Arguments: %s) returns error code %s';
385
  LNG_ERROR_CODE = '%s (Arguments: %s) returns error code %s';
384
 
386
 
385
function _DeleteDirectory(const Name: string): boolean;
387
function _DeleteDirectory(const Name: string): boolean;
386
var
388
var
387
  F: TSearchRec;
389
  F: TSearchRec;
388
begin
390
begin
389
  result := true;
391
  result := true;
390
  if FindFirst(IncludeTrailingPathDelimiter(Name) + '*', faAnyFile, F) = 0 then
392
  if FindFirst(IncludeTrailingPathDelimiter(Name) + '*', faAnyFile, F) = 0 then
391
  begin
393
  begin
392
    try
394
    try
393
      repeat
395
      repeat
394
        if (F.Attr and faDirectory <> 0) then
396
        if (F.Attr and faDirectory <> 0) then
395
        begin
397
        begin
396
          if (F.Name <> '.') and (F.Name <> '..') then
398
          if (F.Name <> '.') and (F.Name <> '..') then
397
          begin
399
          begin
398
            result := result and _DeleteDirectory(IncludeTrailingPathDelimiter(Name) + F.Name);
400
            result := result and _DeleteDirectory(IncludeTrailingPathDelimiter(Name) + F.Name);
399
          end;
401
          end;
400
        end
402
        end
401
        else
403
        else
402
        begin
404
        begin
403
          if not DeleteFile(IncludeTrailingPathDelimiter(Name) + F.Name) then result := false;
405
          if not DeleteFile(IncludeTrailingPathDelimiter(Name) + F.Name) then result := false;
404
        end;
406
        end;
405
      until FindNext(F) <> 0;
407
      until FindNext(F) <> 0;
406
    finally
408
    finally
407
      FindClose(F);
409
      FindClose(F);
408
    end;
410
    end;
409
    if not RemoveDir(Name) then result := false;
411
    if not RemoveDir(Name) then result := false;
410
  end;
412
  end;
411
end;
413
end;
412
 
414
 
413
function _FileSize(FileName: string): int64;
415
function _FileSize(FileName: string): int64;
414
var
416
var
415
  fs: TFileStream;
417
  fs: TFileStream;
416
begin
418
begin
417
  fs := TFileStream.Create(FileName, fmOpenRead);
419
  fs := TFileStream.Create(FileName, fmOpenRead);
418
  try
420
  try
419
    result := fs.size;
421
    result := fs.size;
420
  finally
422
  finally
421
    fs.free;
423
    fs.free;
422
  end;
424
  end;
423
end;
425
end;
424
 
426
 
425
function _DriveNum(Drive: Char): Byte;
427
function _DriveNum(Drive: Char): Byte;
426
// a->0, ..., z->25
428
// a->0, ..., z->25
427
var
429
var
428
  tmp: string;
430
  tmp: string;
429
begin
431
begin
430
  tmp := LowerCase(Drive);
432
  tmp := LowerCase(Drive);
431
  result := Ord(tmp[1])-Ord('a');
433
  result := Ord(tmp[1])-Ord('a');
432
end;
434
end;
433
 
435
 
434
function _registryReadDump(AReg: TRegistry; AName: string): string;
436
function _registryReadDump(AReg: TRegistry; AName: string): string;
435
const
437
const
436
  // Win2000 RegEdit has set the max input length of a REG_BINARY to $3FFF.
438
  // Win2000 RegEdit has set the max input length of a REG_BINARY to $3FFF.
437
  // Probably its the longest possible binary string and not just a GUI limit.
439
  // Probably its the longest possible binary string and not just a GUI limit.
438
  BufMax = $3FFF;
440
  BufMax = $3FFF;
439
var
441
var
440
  buf: array[0..BufMax] of byte;
442
  buf: array[0..BufMax] of byte;
441
  i: integer;
443
  i: integer;
442
  realsize: integer;
444
  realsize: integer;
443
begin
445
begin
444
  realsize := AReg.ReadBinaryData(AName, buf, SizeOf(buf));
446
  realsize := AReg.ReadBinaryData(AName, buf, SizeOf(buf));
445
 
447
 
446
  for i := 0 to realsize-1 do
448
  for i := 0 to realsize-1 do
447
  begin
449
  begin
448
    result := result + chr(buf[i]);
450
    result := result + chr(buf[i]);
449
  end;
451
  end;
450
end;
452
end;
451
 
453
 
452
function _GetStringFromDLL(filename: string; num: integer): string;
454
function _GetStringFromDLL(filename: string; num: integer): string;
453
const
455
const
454
  // http://www.eggheadcafe.com/forumarchives/vcmfc/sep2005/post23917443.asp
456
  // http://www.eggheadcafe.com/forumarchives/vcmfc/sep2005/post23917443.asp
455
  MAX_BUF = 4097; // OK?
457
  MAX_BUF = 4097; // OK?
456
var
458
var
457
  hLib: THandle;
459
  hLib: THandle;
458
  buf: array[0..MAX_BUF] of char;
460
  buf: array[0..MAX_BUF] of char;
459
begin
461
begin
460
  hLib := LoadLibrary(PChar(filename));
462
  hLib := LoadLibrary(PChar(filename));
461
  try
463
  try
462
    LoadString(hLib, num, buf, sizeof(buf));
464
    LoadString(hLib, num, buf, sizeof(buf));
463
    result := buf;
465
    result := buf;
464
  finally
466
  finally
465
    FreeLibrary(hLib);
467
    FreeLibrary(hLib);
466
  end;
468
  end;
467
end;
469
end;
468
 
470
 
469
// http://www.delphi-library.de/topic_Umgebungsvariable+in+einem+String+aufloesen_20516,0.html
471
// http://www.delphi-library.de/topic_Umgebungsvariable+in+einem+String+aufloesen_20516,0.html
470
function _ExpandEnvStr(const szInput: string): string;
472
function _ExpandEnvStr(const szInput: string): string;
471
const
473
const
472
  MAXSIZE = 32768; // laut PSDK sind 32k das Maximum
474
  MAXSIZE = 32768; // laut PSDK sind 32k das Maximum
473
begin
475
begin
474
  SetLength(Result,MAXSIZE);
476
  SetLength(Result,MAXSIZE);
475
  SetLength(Result,ExpandEnvironmentStrings(pchar(szInput),
477
  SetLength(Result,ExpandEnvironmentStrings(pchar(szInput),
476
    @Result[1],length(Result))-1); //-1 um abschließendes #0 zu verwerfen
478
    @Result[1],length(Result))-1); //-1 um abschließendes #0 zu verwerfen
477
end;
479
end;
478
 
480
 
479
// Beispiele
481
// Beispiele
480
// Papierkorb                                                 -- Windows 95
482
// Papierkorb                                                 -- Windows 95
481
// @C:\WINNT\system32\shell32.dll,-8964@1031,Papierkorb       -- Windows 2000
483
// @C:\WINNT\system32\shell32.dll,-8964@1031,Papierkorb       -- Windows 2000
482
 
484
 
483
function _DecodeReferenceString(s: string): string;
485
function _DecodeReferenceString(s: string): string;
484
var
486
var
485
  dll, id, lang, cache: string;
487
  dll, id, lang, cache: string;
486
  sl, sl2: tstringlist;
488
  sl, sl2: tstringlist;
487
begin
489
begin
488
  if Copy(s, 1, 1) = '@' then
490
  if Copy(s, 1, 1) = '@' then
489
  begin
491
  begin
490
    // Referenz auf eine DLL
492
    // Referenz auf eine DLL
491
    // @<dll>,-<id>[@<lang>][,<cache>]
493
    // @<dll>,-<id>[@<lang>][,<cache>]
492
 
494
 
493
    sl := TStringList.Create;
495
    sl := TStringList.Create;
494
    try
496
    try
495
      // '@' am Anfang entfernen
497
      // '@' am Anfang entfernen
496
      s := Copy(s, 2, length(s)-1);
498
      s := Copy(s, 2, length(s)-1);
497
 
499
 
498
      // Nach ',' auftrennen
500
      // Nach ',' auftrennen
499
      // sl[0] --> dll
501
      // sl[0] --> dll
500
      // sl[1] --> -id@lang
502
      // sl[1] --> -id@lang
501
      // sl[2] --> cache
503
      // sl[2] --> cache
502
      sl.CommaText := s;
504
      sl.CommaText := s;
503
 
505
 
504
      if sl.Count > 2 then
506
      if sl.Count > 2 then
505
      begin
507
      begin
506
        // Das Ergebnis ist bereits im Klartext vorhanden und muss nicht extrahiert werden
508
        // Das Ergebnis ist bereits im Klartext vorhanden und muss nicht extrahiert werden
507
        // Ist bei Windows 2000 der Fall
509
        // Ist bei Windows 2000 der Fall
508
        cache := sl[2];
510
        cache := sl[2];
509
        result := cache;
511
        result := cache;
510
        exit;
512
        exit;
511
      end;
513
      end;
512
 
514
 
513
      if sl.Count > 1 then
515
      if sl.Count > 1 then
514
      begin
516
      begin
515
        dll := sl[0];
517
        dll := sl[0];
516
 
518
 
517
        sl2 := TStringList.Create;
519
        sl2 := TStringList.Create;
518
        try
520
        try
519
          // Nach '@' auftrennen
521
          // Nach '@' auftrennen
520
          // sl2[0] --> id
522
          // sl2[0] --> id
521
          // sl2[1] --> lang
523
          // sl2[1] --> lang
522
          sl2.CommaText := StringReplace(sl[1], '@', ',', [rfReplaceAll]);
524
          sl2.CommaText := StringReplace(sl[1], '@', ',', [rfReplaceAll]);
523
 
525
 
524
          id := sl2[0];
526
          id := sl2[0];
525
 
527
 
526
          if sl2.Count > 1 then
528
          if sl2.Count > 1 then
527
          begin
529
          begin
528
            // ToDo: In Zukunft beachten, sofern möglich
530
            // ToDo: In Zukunft beachten, sofern möglich
529
            lang := sl2[1];
531
            lang := sl2[1];
530
          end;
532
          end;
531
 
533
 
532
          // Umgebungsvariablen erkennen und Minuszeichen entfernen
534
          // Umgebungsvariablen erkennen und Minuszeichen entfernen
533
          result := _GetStringFromDLL(_ExpandEnvStr(dll), -StrToInt(id));
535
          result := _GetStringFromDLL(_ExpandEnvStr(dll), -StrToInt(id));
534
        finally
536
        finally
535
          sl2.Free;
537
          sl2.Free;
536
        end;
538
        end;
537
      end
539
      end
538
      else
540
      else
539
      begin
541
      begin
540
        // Zu wenige Informationen!
542
        // Zu wenige Informationen!
541
 
543
 
542
        result := '';
544
        result := '';
543
      end;
545
      end;
544
    finally
546
    finally
545
      sl.Free;
547
      sl.Free;
546
    end;
548
    end;
547
  end
549
  end
548
  else
550
  else
549
  begin
551
  begin
550
    // Kein Hinweis auf eine Referenz
552
    // Kein Hinweis auf eine Referenz
551
    result := s;
553
    result := s;
552
  end;
554
  end;
553
end;
555
end;
554
 
556
 
555
function _readInt8(const Stream: TStream): byte;
557
function _readInt8(const Stream: TStream): byte;
556
var
558
var
557
  I: integer;
559
  I: integer;
558
begin
560
begin
559
  i := 0;
561
  i := 0;
560
  Stream.ReadBuffer(i, 1);
562
  Stream.ReadBuffer(i, 1);
561
  Result := i;
563
  Result := i;
562
end;
564
end;
563
 
565
 
564
function _readInt32(const Stream: TStream): Longword;
566
function _readInt32(const Stream: TStream): Longword;
565
var
567
var
566
  I: integer;
568
  I: integer;
567
begin
569
begin
568
  i := 0;
570
  i := 0;
569
  Stream.ReadBuffer(i, 4);
571
  Stream.ReadBuffer(i, 4);
570
  Result := i;
572
  Result := i;
571
end;
573
end;
572
 
574
 
573
function _readInt64(const Stream: TStream): int64;
575
function _readInt64(const Stream: TStream): int64;
574
var
576
var
575
  I: int64;
577
  I: int64;
576
begin
578
begin
577
  i := 0;
579
  i := 0;
578
  Stream.ReadBuffer(i, 8);
580
  Stream.ReadBuffer(i, 8);
579
  Result := i;
581
  Result := i;
580
end;
582
end;
581
 
583
 
582
function _readChar(const Stream: TStream): char;
584
function _readChar(const Stream: TStream): char;
583
var
585
var
584
  C: Char;
586
  C: Char;
585
begin
587
begin
586
  C := #0;
588
  C := #0;
587
  Stream.ReadBuffer(C, 1);
589
  Stream.ReadBuffer(C, 1);
588
  Result := C;
590
  Result := C;
589
end;
591
end;
590
 
592
 
591
function _readNullTerminatedString(const Stream: TStream): String;
593
function _readNullTerminatedString(const Stream: TStream): String;
592
var
594
var
593
  S: String;
595
  S: String;
594
  C: Char;
596
  C: Char;
595
begin
597
begin
596
  S := '';
598
  S := '';
597
  repeat
599
  repeat
598
    Stream.ReadBuffer(C, 1);
600
    Stream.ReadBuffer(C, 1);
599
    if (C <> #0) then
601
    if (C <> #0) then
600
      S := S + C;
602
      S := S + C;
601
  until C = #0;
603
  until C = #0;
602
  Result := S;
604
  Result := S;
603
end;
605
end;
604
 
606
 
605
// http://www.delphipraxis.net/post761928.html#761928
607
// http://www.delphipraxis.net/post761928.html#761928
606
function _readNullTerminatedWideString(const Stream: TStream): WideString;
608
function _readNullTerminatedWideString(const Stream: TStream): WideString;
607
var
609
var
608
  S: WideString;
610
  S: WideString;
609
  WC: WideChar;
611
  WC: WideChar;
610
begin
612
begin
611
  S := '';
613
  S := '';
612
  repeat
614
  repeat
613
    Stream.ReadBuffer(WC, 2);
615
    Stream.ReadBuffer(WC, 2);
614
    if (WC <> #0) then
616
    if (WC <> #0) then
615
      S := S + WC;
617
      S := S + WC;
616
  until WC = #0;
618
  until WC = #0;
617
  Result := S;
619
  Result := S;
618
end;
620
end;
619
 
621
 
620
// http://www.delphipraxis.net/post340194.html#340194
622
// http://www.delphipraxis.net/post340194.html#340194
621
function _nowUTC: TDateTime;
623
function _nowUTC: TDateTime;
622
var
624
var
623
  SystemTime: TSystemTime;
625
  SystemTime: TSystemTime;
624
begin
626
begin
625
  GetSystemTime(SystemTime);
627
  GetSystemTime(SystemTime);
626
  with SystemTime do
628
  with SystemTime do
627
  begin
629
  begin
628
    Result := EncodeDate(wYear, wMonth, wDay) +
630
    Result := EncodeDate(wYear, wMonth, wDay) +
629
              EncodeTime(wHour, wMinute, wSecond, wMilliseconds);
631
              EncodeTime(wHour, wMinute, wSecond, wMilliseconds);
630
  end;
632
  end;
631
end;
633
end;
632
 
634
 
633
{$IFDEF DEL6UP}
635
{$IFDEF DEL6UP}
634
function _getGMTDifference(): extended;
636
function _getGMTDifference(): extended;
635
begin
637
begin
636
  result := - (datetimetounix(_nowUTC())-datetimetounix(Now())) / 3600;
638
  result := - (datetimetounix(_nowUTC())-datetimetounix(Now())) / 3600;
637
end;
639
end;
638
 
640
 
639
function _fileTimeToDateTime(FileTime: int64): TDateTime;
641
function _fileTimeToDateTime(FileTime: int64): TDateTime;
640
begin
642
begin
641
  // http://www.e-fense.com/helix/Docs/Recycler_Bin_Record_Reconstruction.pdf
643
  // http://www.e-fense.com/helix/Docs/Recycler_Bin_Record_Reconstruction.pdf
642
  // UnixTime = 0.0000001 * NTTime + 11644473600
644
  // UnixTime = 0.0000001 * NTTime + 11644473600
643
  // This is wrong! The correct formula is:
645
  // This is wrong! The correct formula is:
644
  // UnixTime = 0.0000001 * NTTime - 11644473600 + c * 3600
646
  // UnixTime = 0.0000001 * NTTime - 11644473600 + c * 3600
645
  // c = GMT-Difference (MEZ = 1) inclusive daylight saving time (+3600 seconds)
647
  // c = GMT-Difference (MEZ = 1) inclusive daylight saving time (+3600 seconds)
646
  result := unixtodatetime(FileTime div 10000000 - 11644473600 + round(_getGMTDifference() * 3600));
648
  result := unixtodatetime(FileTime div 10000000 - 11644473600 + round(_getGMTDifference() * 3600));
647
end;
649
end;
648
{$ENDIF}
650
{$ENDIF}
649
 
651
 
650
// http://www.delphipraxis.net/post471470.html
652
// http://www.delphipraxis.net/post471470.html
651
function _getAccountSid(const Server, User: WideString; var Sid: PSID): DWORD;
653
function _getAccountSid(const Server, User: WideString; var Sid: PSID): DWORD;
652
var
654
var
653
  dwDomainSize, dwSidSize: DWord;
655
  dwDomainSize, dwSidSize: DWord;
654
  R: LongBool;
656
  R: LongBool;
655
  wDomain: WideString;
657
  wDomain: WideString;
656
  Use: DWord;
658
  Use: DWord;
657
begin
659
begin
658
  Result := 0;
660
  Result := 0;
659
  SetLastError(0);
661
  SetLastError(0);
660
  dwSidSize := 0;
662
  dwSidSize := 0;
661
  dwDomainSize := 0;
663
  dwDomainSize := 0;
662
  R := LookupAccountNameW(PWideChar(Server), PWideChar(User), nil, dwSidSize,
664
  R := LookupAccountNameW(PWideChar(Server), PWideChar(User), nil, dwSidSize,
663
       nil, dwDomainSize, Use);
665
       nil, dwDomainSize, Use);
664
  if (not R) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
666
  if (not R) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
665
  begin
667
  begin
666
    SetLength(wDomain, dwDomainSize);
668
    SetLength(wDomain, dwDomainSize);
667
    Sid := GetMemory(dwSidSize);
669
    Sid := GetMemory(dwSidSize);
668
    R := LookupAccountNameW(PWideChar(Server), PWideChar(User), Sid,
670
    R := LookupAccountNameW(PWideChar(Server), PWideChar(User), Sid,
669
         dwSidSize, PWideChar(wDomain), dwDomainSize, Use);
671
         dwSidSize, PWideChar(wDomain), dwDomainSize, Use);
670
    if not R then
672
    if not R then
671
    begin
673
    begin
672
      FreeMemory(Sid);
674
      FreeMemory(Sid);
673
      Sid := nil;
675
      Sid := nil;
674
    end;
676
    end;
675
  end
677
  end
676
  else
678
  else
677
    Result := GetLastError;
679
    Result := GetLastError;
678
end;
680
end;
679
 
681
 
680
const
682
const
681
  UNLEN = 256; // lmcons.h
683
  UNLEN = 256; // lmcons.h
682
 
684
 
683
// Template:
685
// Template:
684
// http://www.latiumsoftware.com/en/pascal/0014.php
686
// http://www.latiumsoftware.com/en/pascal/0014.php
685
function _getLoginNameW: widestring;
687
function _getLoginNameW: widestring;
686
var
688
var
687
  Buffer: array[0..UNLEN] of widechar;
689
  Buffer: array[0..UNLEN] of widechar;
688
  Size: DWORD;
690
  Size: DWORD;
689
begin
691
begin
690
  Size := SizeOf(Buffer);
692
  Size := SizeOf(Buffer);
691
  if GetUserNameW(Buffer, Size) then
693
  if GetUserNameW(Buffer, Size) then
692
    Result := Buffer
694
    Result := Buffer
693
  else
695
  else
694
    Result := 'User';
696
    Result := 'User';
695
end;
697
end;
696
 
698
 
697
function _ConvertSidToStringSidA(SID: PSID; var strSID: LPSTR): boolean;
699
function _ConvertSidToStringSidA(SID: PSID; var strSID: LPSTR): boolean;
698
type
700
type
699
  DllReg = function(SID: PSID; var StringSid: LPSTR): Boolean; stdcall;
701
  DllReg = function(SID: PSID; var StringSid: LPSTR): Boolean; stdcall;
700
var
702
var
701
  hDll: THandle;
703
  hDll: THandle;
702
  dr: DllReg;
704
  dr: DllReg;
703
begin
705
begin
704
  result := false;
706
  result := false;
705
  hDll := LoadLibrary(advapi32);
707
  hDll := LoadLibrary(advapi32);
706
  if hDll <> 0 then
708
  if hDll <> 0 then
707
  begin
709
  begin
708
    @dr := GetProcAddress(hDll, 'ConvertSidToStringSidA');
710
    @dr := GetProcAddress(hDll, 'ConvertSidToStringSidA');
709
 
711
 
710
    if assigned(dr) then
712
    if assigned(dr) then
711
    begin
713
    begin
712
      result := dr(SID, strSID);
714
      result := dr(SID, strSID);
713
    end;
715
    end;
714
  end;
716
  end;
715
end;
717
end;
716
 
718
 
717
const
719
const
718
  winternl_lib = 'Ntdll.dll';
720
  winternl_lib = 'Ntdll.dll';
719
 
721
 
720
type
722
type
721
  USHORT = Word;
723
  USHORT = Word;
722
  PWSTR = PWidechar;
724
  PWSTR = PWidechar;
723
  PCWSTR = PWideChar;
725
  PCWSTR = PWideChar;
724
 
726
 
725
   NTSTATUS = Longword;
727
   NTSTATUS = Longword;
726
 
728
 
727
  _UNICODE_STRING = record
729
  _UNICODE_STRING = record
728
    Length: USHORT;
730
    Length: USHORT;
729
    MaximumLength: USHORT;
731
    MaximumLength: USHORT;
730
    Buffer: PWSTR;
732
    Buffer: PWSTR;
731
  end;
733
  end;
732
  UNICODE_STRING = _UNICODE_STRING;
734
  UNICODE_STRING = _UNICODE_STRING;
733
  PUNICODE_STRING = ^UNICODE_STRING;
735
  PUNICODE_STRING = ^UNICODE_STRING;
734
 
736
 
735
function _RtlConvertSidToUnicodeString(
737
function _RtlConvertSidToUnicodeString(
736
  UnicodeString: PUNICODE_STRING;
738
  UnicodeString: PUNICODE_STRING;
737
  Sid: PSID;
739
  Sid: PSID;
738
  AllocateDestinationString: BOOLEAN): NTSTATUS; stdcall;
740
  AllocateDestinationString: BOOLEAN): NTSTATUS; stdcall;
739
type
741
type
740
  DllReg = function(UnicodeString: PUNICODE_STRING;
742
  DllReg = function(UnicodeString: PUNICODE_STRING;
741
  Sid: PSID;
743
  Sid: PSID;
742
  AllocateDestinationString: BOOLEAN): NTSTATUS; stdcall;
744
  AllocateDestinationString: BOOLEAN): NTSTATUS; stdcall;
743
var
745
var
744
  hDll: THandle;
746
  hDll: THandle;
745
  dr: DllReg;
747
  dr: DllReg;
746
begin
748
begin
747
  result := $FFFFFFFF;
749
  result := $FFFFFFFF;
748
  hDll := LoadLibrary(winternl_lib);
750
  hDll := LoadLibrary(winternl_lib);
749
  if hDll = 0 then Exit;
751
  if hDll = 0 then Exit;
750
  try
752
  try
751
    @dr := GetProcAddress(hDll, 'RtlConvertSidToUnicodeString');
753
    @dr := GetProcAddress(hDll, 'RtlConvertSidToUnicodeString');
752
    if not Assigned(dr) then Exit;
754
    if not Assigned(dr) then Exit;
753
    result := dr(UnicodeString, Sid, AllocateDestinationString);
755
    result := dr(UnicodeString, Sid, AllocateDestinationString);
754
  finally
756
  finally
755
    FreeLibrary(hDll);
757
    FreeLibrary(hDll);
756
  end;
758
  end;
757
end;
759
end;
758
 
760
 
759
procedure _RtlFreeUnicodeString(UnicodeString: PUNICODE_STRING); stdcall;
761
procedure _RtlFreeUnicodeString(UnicodeString: PUNICODE_STRING); stdcall;
760
type
762
type
761
  DllReg = procedure(UnicodeString: PUNICODE_STRING); stdcall;
763
  DllReg = procedure(UnicodeString: PUNICODE_STRING); stdcall;
762
var
764
var
763
  hDll: THandle;
765
  hDll: THandle;
764
  dr: DllReg;
766
  dr: DllReg;
765
begin
767
begin
766
  hDll := LoadLibrary(winternl_lib);
768
  hDll := LoadLibrary(winternl_lib);
767
  if hDll = 0 then Exit;
769
  if hDll = 0 then Exit;
768
  try
770
  try
769
    @dr := GetProcAddress(hDll, 'RtlFreeUnicodeString');
771
    @dr := GetProcAddress(hDll, 'RtlFreeUnicodeString');
770
    if not Assigned(dr) then Exit;
772
    if not Assigned(dr) then Exit;
771
    dr(UnicodeString);
773
    dr(UnicodeString);
772
  finally
774
  finally
773
    FreeLibrary(hDll);
775
    FreeLibrary(hDll);
774
  end;
776
  end;
775
end;
777
end;
776
 
778
 
777
function _NT_SidToString(SID: PSID; var strSID: string): boolean;
779
function _NT_SidToString(SID: PSID; var strSID: string): boolean;
778
var
780
var
779
  pus: PUNICODE_STRING;
781
  pus: PUNICODE_STRING;
780
  us: UNICODE_STRING;
782
  us: UNICODE_STRING;
781
begin
783
begin
782
  pus := @us;
784
  pus := @us;
783
  result := _RtlConvertSidToUnicodeString(pus, SID, true) = 0;
785
  result := _RtlConvertSidToUnicodeString(pus, SID, true) = 0;
784
  if not result then Exit;
786
  if not result then Exit;
785
  strSID := pus^.Buffer;
787
  strSID := pus^.Buffer;
786
  UniqueString(strSID);
788
  UniqueString(strSID);
787
  _RtlFreeUnicodeString(pus);
789
  _RtlFreeUnicodeString(pus);
788
  result := true;
790
  result := true;
789
end;
791
end;
790
 
792
 
791
// Source: http://www.delphipraxis.net/post471470.html
793
// Source: http://www.delphipraxis.net/post471470.html
792
// Modified
794
// Modified
793
function _getMySID(): string;
795
function _getMySID(): string;
794
var
796
var
795
  SID: PSID;
797
  SID: PSID;
796
  strSID: PAnsiChar;
798
  strSID: PAnsiChar;
797
  err: DWORD;
799
  err: DWORD;
798
begin
800
begin
799
  SID := nil;
801
  SID := nil;
800
 
802
 
801
  err := _getAccountSid('', _getLoginNameW(), SID);
803
  err := _getAccountSid('', _getLoginNameW(), SID);
802
  try
804
  try
803
    if err > 0 then
805
    if err > 0 then
804
    begin
806
    begin
805
      EAPICallError.Create('_getAccountSid:' + SysErrorMessage(err));
807
      EAPICallError.Create('_getAccountSid:' + SysErrorMessage(err));
806
      Exit;
808
      Exit;
807
    end;
809
    end;
808
 
810
 
809
    if _ConvertSidToStringSidA(SID, strSID) then
811
    if _ConvertSidToStringSidA(SID, strSID) then
810
    begin
812
    begin
811
      result := string(strSID);
813
      result := string(strSID);
812
      Exit;
814
      Exit;
813
    end;
815
    end;
814
 
816
 
815
    if _NT_SidToString(SID, result) then Exit;
817
    if _NT_SidToString(SID, result) then Exit;
816
 
818
 
817
    EAPICallError.Create('_getMySID:' + SysErrorMessage(err));
819
    EAPICallError.Create('_getMySID:' + SysErrorMessage(err));
818
  finally
820
  finally
819
    if Assigned(SID) then FreeMemory(SID);
821
    if Assigned(SID) then FreeMemory(SID);
820
  end;
822
  end;
821
end;
823
end;
822
 
824
 
823
// Originalcode aus http://www.delphipraxis.net/post2933.html
825
// Originalcode aus http://www.delphipraxis.net/post2933.html
824
function _DriveExists(DriveByte: Byte): Boolean; overload;
826
function _DriveExists(DriveByte: Byte): Boolean; overload;
825
begin
827
begin
826
  Result := GetLogicalDrives and (1 shl DriveByte) <> 0;
828
  Result := GetLogicalDrives and (1 shl DriveByte) <> 0;
827
end;
829
end;
828
 
830
 
829
function _driveExists(Drive: Char): Boolean; overload;
831
function _driveExists(Drive: Char): Boolean; overload;
830
var
832
var
831
  DriveByte: Byte;
833
  DriveByte: Byte;
832
  tmp: string;
834
  tmp: string;
833
begin
835
begin
834
  // Make drive letter upper case (for older Delphi versions)
836
  // Make drive letter upper case (for older Delphi versions)
835
  tmp := UpperCase(Drive);
837
  tmp := UpperCase(Drive);
836
  Drive := tmp[1];
838
  Drive := tmp[1];
837
 
839
 
838
  DriveByte := Ord(Drive) - Ord('A');
840
  DriveByte := Ord(Drive) - Ord('A');
839
  Result := _DriveExists(DriveByte);
841
  Result := _DriveExists(DriveByte);
840
end;
842
end;
841
 
843
 
842
function _isFAT(drive: char): boolean;
844
function _isFAT(drive: char): boolean;
843
var
845
var
844
  Dummy2: DWORD;
846
  Dummy2: DWORD;
845
  Dummy3: DWORD;
847
  Dummy3: DWORD;
846
  FileSystem: array[0..MAX_PATH] of char;
848
  FileSystem: array[0..MAX_PATH] of char;
847
  VolumeName: array[0..MAX_PATH] of char;
849
  VolumeName: array[0..MAX_PATH] of char;
848
  s: string;
850
  s: string;
849
begin
851
begin
850
  result := false;
852
  result := false;
851
  if _driveExists(drive) then
853
  if _driveExists(drive) then
852
  begin
854
  begin
853
    s := drive + DriveDelim + PathDelim; // ohne die Auslagerung in einen String kommt es zu einer AV in ntdll
855
    s := drive + DriveDelim + PathDelim; // ohne die Auslagerung in einen String kommt es zu einer AV in ntdll
854
    GetVolumeInformation(PChar(s), VolumeName,
856
    GetVolumeInformation(PChar(s), VolumeName,
855
      SizeOf(VolumeName), nil, Dummy2, Dummy3, FileSystem, SizeOf(FileSystem));
857
      SizeOf(VolumeName), nil, Dummy2, Dummy3, FileSystem, SizeOf(FileSystem));
856
    result := uppercase(copy(FileSystem, 0, 3)) = 'FAT';
858
    result := uppercase(copy(FileSystem, 0, 3)) = 'FAT';
857
  end;
859
  end;
858
end;
860
end;
859
 
861
 
860
// **********************************************************
862
// **********************************************************
861
// VISTA AND WINDOWS 7 FUNCTIONS, INTERNAL USED
863
// VISTA AND WINDOWS 7 FUNCTIONS, INTERNAL USED
862
// **********************************************************
864
// **********************************************************
863
 
865
 
864
const
866
const
865
  vista_valid_index_size = $220; // 544
867
  vista_valid_index_size = $220; // 544
866
 
868
 
867
function _isFileVistaRealfile(filename: string): boolean;
869
function _isFileVistaRealfile(filename: string): boolean;
868
begin
870
begin
869
  result := uppercase(copy(extractfilename(filename), 0, 2)) = '$R';
871
  result := uppercase(copy(extractfilename(filename), 0, 2)) = '$R';
870
end;
872
end;
871
 
873
 
872
function _isFileVistaIndexfile(filename: string): boolean;
874
function _isFileVistaIndexfile(filename: string): boolean;
873
begin
875
begin
874
  result := uppercase(copy(extractfilename(filename), 0, 2)) = '$I';
876
  result := uppercase(copy(extractfilename(filename), 0, 2)) = '$I';
875
end;
877
end;
876
 
878
 
877
function _isFileVistaNamed(filename: string): boolean;
879
function _isFileVistaNamed(filename: string): boolean;
878
begin
880
begin
879
  result := _isFileVistaIndexfile(filename) or
881
  result := _isFileVistaIndexfile(filename) or
880
            _isFileVistaRealfile(filename);
882
            _isFileVistaRealfile(filename);
881
end;
883
end;
882
 
884
 
883
function _VistaChangeRealfileToIndexfile(realfile: string): string;
885
function _VistaChangeRealfileToIndexfile(realfile: string): string;
884
begin
886
begin
885
  if _isFileVistaRealfile(realfile) then
887
  if _isFileVistaRealfile(realfile) then
886
  begin
888
  begin
887
    result := extractfilepath(realfile)+'$I'+
889
    result := extractfilepath(realfile)+'$I'+
888
      copy(extractfilename(realfile), 3, length(extractfilename(realfile))-2);
890
      copy(extractfilename(realfile), 3, length(extractfilename(realfile))-2);
889
  end
891
  end
890
  else
892
  else
891
    result := realfile; // ignore, even if it is not a vista recycle-file
893
    result := realfile; // ignore, even if it is not a vista recycle-file
892
end;
894
end;
893
 
895
 
894
function _VistaChangeIndexfileToRealfile(indexfile: string): string;
896
function _VistaChangeIndexfileToRealfile(indexfile: string): string;
895
begin
897
begin
896
  if _isFileVistaIndexfile(indexfile) then
898
  if _isFileVistaIndexfile(indexfile) then
897
  begin
899
  begin
898
    result := extractfilepath(indexfile)+'$R'+
900
    result := extractfilepath(indexfile)+'$R'+
899
      copy(extractfilename(indexfile), 3, length(extractfilename(indexfile))-2);
901
      copy(extractfilename(indexfile), 3, length(extractfilename(indexfile))-2);
900
  end
902
  end
901
  else
903
  else
902
    result := indexfile; // ignore, even if it is not a vista recycle-file
904
    result := indexfile; // ignore, even if it is not a vista recycle-file
903
end;
905
end;
904
 
906
 
905
procedure _VistaListIndexes(recyclerpath: string; result: TStringList);
907
procedure _VistaListIndexes(recyclerpath: string; result: TStringList);
906
var
908
var
907
  sr: TSearchRec;
909
  sr: TSearchRec;
908
  r: Integer;
910
  r: Integer;
909
  tmp: string;
911
  tmp: string;
910
begin
912
begin
911
  tmp := recyclerpath;
913
  tmp := recyclerpath;
912
  tmp := IncludeTrailingBackslash(tmp);
914
  tmp := IncludeTrailingBackslash(tmp);
913
 
915
 
914
  if not directoryexists(tmp) then exit;
916
  if not directoryexists(tmp) then exit;
915
 
917
 
916
  r := FindFirst(tmp+PathDelim + '$I*', faAnyFile, sr);
918
  r := FindFirst(tmp+PathDelim + '$I*', faAnyFile, sr);
917
  while r = 0 do
919
  while r = 0 do
918
  begin
920
  begin
919
    if (sr.Name <> '.') and (sr.Name <> '..') then
921
    if (sr.Name <> '.') and (sr.Name <> '..') then
920
    begin
922
    begin
921
      if sr.Size = vista_valid_index_size then
923
      if sr.Size = vista_valid_index_size then
922
      begin
924
      begin
923
        result.Add(copy(sr.name, 3, length(sr.name)-2));
925
        result.Add(copy(sr.name, 3, length(sr.name)-2));
924
      end;
926
      end;
925
    end;
927
    end;
926
    r := FindNext(sr);
928
    r := FindNext(sr);
927
  end;
929
  end;
928
 
930
 
929
  FindClose(sr);
931
  FindClose(sr);
930
end;
932
end;
931
 
933
 
932
function _VistaCurrentFilename(infofilename: string): string;
934
function _VistaCurrentFilename(infofilename: string): string;
933
begin
935
begin
934
  result := extractfilename(infofilename);
936
  result := extractfilename(infofilename);
935
 
937
 
936
  if _isFileVistaRealfile(result) then
938
  if _isFileVistaRealfile(result) then
937
  begin
939
  begin
938
    exit;
940
    exit;
939
  end;
941
  end;
940
 
942
 
941
  if _isFileVistaIndexfile(result) then
943
  if _isFileVistaIndexfile(result) then
942
  begin
944
  begin
943
    result := _VistaChangeIndexfileToRealfile(result);
945
    result := _VistaChangeIndexfileToRealfile(result);
944
    exit;
946
    exit;
945
  end;
947
  end;
946
 
948
 
947
  result := copy(result, 3, length(result)-2);
949
  result := copy(result, 3, length(result)-2);
948
  result := '$R'+result;
950
  result := '$R'+result;
949
end;
951
end;
950
 
952
 
951
function _VistaGetSourceDrive(infofile: string): char;
953
function _VistaGetSourceDrive(infofile: string): char;
952
var
954
var
953
  fs: TFileStream;
955
  fs: TFileStream;
954
  tmp: string;
956
  tmp: string;
955
const
957
const
956
  drive_vista_position = $18;
958
  drive_vista_position = $18;
957
begin
959
begin
958
  result := #0;
960
  result := #0;
959
 
961
 
960
  tmp := infofile;
962
  tmp := infofile;
961
  tmp := _VistaChangeRealfileToIndexfile(tmp);
963
  tmp := _VistaChangeRealfileToIndexfile(tmp);
962
  if not fileexists(tmp) then exit;
964
  if not fileexists(tmp) then exit;
963
 
965
 
964
  fs := TFileStream.Create(tmp, fmOpenRead);
966
  fs := TFileStream.Create(tmp, fmOpenRead);
965
  try
967
  try
966
    fs.seek(drive_vista_position, soFromBeginning);
968
    fs.seek(drive_vista_position, soFromBeginning);
967
    result := _readChar(fs);
969
    result := _readChar(fs);
968
  finally
970
  finally
969
    fs.free;
971
    fs.free;
970
  end;
972
  end;
971
end;
973
end;
972
 
974
 
973
{$IFDEF DEL6UP}
975
{$IFDEF DEL6UP}
974
function _VistaGetDateTime(infofile: string): TDateTime;
976
function _VistaGetDateTime(infofile: string): TDateTime;
975
var
977
var
976
  fs: TFileStream;
978
  fs: TFileStream;
977
  tmp: string;
979
  tmp: string;
978
const
980
const
979
  timestamp_vista_position = $10;
981
  timestamp_vista_position = $10;
980
begin
982
begin
981
  result := EncodeDateTime(1601, 1, 1, 0, 0, 0, 0);
983
  result := EncodeDateTime(1601, 1, 1, 0, 0, 0, 0);
982
 
984
 
983
  tmp := infofile;
985
  tmp := infofile;
984
  tmp := _VistaChangeRealfileToIndexfile(tmp);
986
  tmp := _VistaChangeRealfileToIndexfile(tmp);
985
  if not fileexists(tmp) then exit;
987
  if not fileexists(tmp) then exit;
986
 
988
 
987
  fs := TFileStream.Create(tmp, fmOpenRead);
989
  fs := TFileStream.Create(tmp, fmOpenRead);
988
  try
990
  try
989
    fs.seek(timestamp_vista_position, soFromBeginning);
991
    fs.seek(timestamp_vista_position, soFromBeginning);
990
    result := _fileTimeToDateTime(_readInt64(fs));
992
    result := _fileTimeToDateTime(_readInt64(fs));
991
  finally
993
  finally
992
    fs.free;
994
    fs.free;
993
  end;
995
  end;
994
end;
996
end;
995
{$ENDIF}
997
{$ENDIF}
996
 
998
 
997
function _VistaGetSourceUnicode(infofile: string): string;
999
function _VistaGetSourceUnicode(infofile: string): string;
998
var
1000
var
999
  fs: TFileStream;
1001
  fs: TFileStream;
1000
  tmp: string;
1002
  tmp: string;
1001
const
1003
const
1002
  unicode_vista_position = $18;
1004
  unicode_vista_position = $18;
1003
begin
1005
begin
1004
  result := '';
1006
  result := '';
1005
 
1007
 
1006
  tmp := infofile;
1008
  tmp := infofile;
1007
  tmp := _VistaChangeRealfileToIndexfile(tmp);
1009
  tmp := _VistaChangeRealfileToIndexfile(tmp);
1008
  if not fileexists(tmp) then exit;
1010
  if not fileexists(tmp) then exit;
1009
 
1011
 
1010
  fs := TFileStream.Create(tmp, fmOpenRead);
1012
  fs := TFileStream.Create(tmp, fmOpenRead);
1011
  try
1013
  try
1012
    fs.seek(unicode_vista_position, soFromBeginning);
1014
    fs.seek(unicode_vista_position, soFromBeginning);
1013
    result := _readNullTerminatedWideString(fs);
1015
    result := _readNullTerminatedWideString(fs);
1014
  finally
1016
  finally
1015
    fs.free;
1017
    fs.free;
1016
  end;
1018
  end;
1017
end;
1019
end;
1018
 
1020
 
1019
function _VistaOriginalSize(infofile: string): integer;
1021
function _VistaOriginalSize(infofile: string): integer;
1020
var
1022
var
1021
  fs: TFileStream;
1023
  fs: TFileStream;
1022
  tmp: string;
1024
  tmp: string;
1023
const
1025
const
1024
  size_vista_position = $8;
1026
  size_vista_position = $8;
1025
begin
1027
begin
1026
  result := -1;
1028
  result := -1;
1027
 
1029
 
1028
  tmp := infofile;
1030
  tmp := infofile;
1029
  tmp := _VistaChangeRealfileToIndexfile(tmp);
1031
  tmp := _VistaChangeRealfileToIndexfile(tmp);
1030
  if not fileexists(tmp) then exit;
1032
  if not fileexists(tmp) then exit;
1031
 
1033
 
1032
  fs := TFileStream.Create(tmp, fmOpenRead);
1034
  fs := TFileStream.Create(tmp, fmOpenRead);
1033
  try
1035
  try
1034
    fs.seek(size_vista_position, soFromBeginning);
1036
    fs.seek(size_vista_position, soFromBeginning);
1035
    result := _readInt32(fs);
1037
    result := _readInt32(fs);
1036
  finally
1038
  finally
1037
    fs.free;
1039
    fs.free;
1038
  end;
1040
  end;
1039
end;
1041
end;
1040
 
1042
 
1041
function _checkInfo1or2File(filename: string): boolean;
1043
function _checkInfo1or2File(filename: string): boolean;
1042
var
1044
var
1043
  fs: TStream;
1045
  fs: TStream;
1044
  record_length: integer;
1046
  record_length: integer;
1045
const
1047
const
1046
  length_position = $C;
1048
  length_position = $C;
1047
  empty_size = 20;
1049
  empty_size = 20;
1048
begin
1050
begin
1049
  fs := TFileStream.Create(filename, fmOpenRead);
1051
  fs := TFileStream.Create(filename, fmOpenRead);
1050
  try
1052
  try
1051
    fs.seek(length_position, soFromBeginning);
1053
    fs.seek(length_position, soFromBeginning);
1052
    record_length := _readInt32(fs);
1054
    record_length := _readInt32(fs);
1053
 
1055
 
1054
    // Check the file length
1056
    // Check the file length
1055
    if record_length = 0 then
1057
    if record_length = 0 then
1056
      result := false
1058
      result := false
1057
    else
1059
    else
1058
      result := (fs.size - empty_size) mod record_length = 0;
1060
      result := (fs.size - empty_size) mod record_length = 0;
1059
  finally
1061
  finally
1060
    fs.free;
1062
    fs.free;
1061
  end;
1063
  end;
1062
end;
1064
end;
1063
 
1065
 
1064
function _VistaIsValid(infofile: string): boolean;
1066
function _VistaIsValid(infofile: string): boolean;
1065
var
1067
var
1066
  tmp: string;
1068
  tmp: string;
1067
begin
1069
begin
1068
  result := false;
1070
  result := false;
1069
 
1071
 
1070
  tmp := infofile;
1072
  tmp := infofile;
1071
  tmp := _VistaChangeRealfileToIndexfile(tmp);
1073
  tmp := _VistaChangeRealfileToIndexfile(tmp);
1072
  if not fileexists(tmp) then exit;
1074
  if not fileexists(tmp) then exit;
1073
 
1075
 
1074
  // Check the file length
1076
  // Check the file length
1075
  result := _FileSize(tmp) = vista_valid_index_size;
1077
  result := _FileSize(tmp) = vista_valid_index_size;
1076
end;
1078
end;
1077
 
1079
 
1078
// **********************************************************
1080
// **********************************************************
1079
// PUBLIC FUNCTIONS
1081
// PUBLIC FUNCTIONS
1080
// **********************************************************
1082
// **********************************************************
1081
 
1083
 
1082
{$IFDEF DEL6UP}
1084
{$IFDEF DEL6UP}
1083
 
1085
 
1084
function RecyclerGetDateTime(InfofileOrRecycleFolder: string): tdatetime; overload;
1086
function RecyclerGetDateTime(InfofileOrRecycleFolder: string): tdatetime; overload;
1085
begin
1087
begin
1086
  result := RecyclerGetDateTime(InfofileOrRecycleFolder, '');
1088
  result := RecyclerGetDateTime(InfofileOrRecycleFolder, '');
1087
end;
1089
end;
1088
 
1090
 
1089
function RecyclerGetDateTime(drive: char; fileid: string): tdatetime; overload;
1091
function RecyclerGetDateTime(drive: char; fileid: string): tdatetime; overload;
1090
begin
1092
begin
1091
  result := RecyclerGetDateTime(drive, '', fileid);
1093
  result := RecyclerGetDateTime(drive, '', fileid);
1092
end;
1094
end;
1093
 
1095
 
1094
function RecyclerGetDateTime(drive: char; UserSID: string; fileid: string): tdatetime; overload;
1096
function RecyclerGetDateTime(drive: char; UserSID: string; fileid: string): tdatetime; overload;
1095
var
1097
var
1096
  infofile: string;
1098
  infofile: string;
1097
begin
1099
begin
1098
  infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1100
  infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1099
  result := RecyclerGetDateTime(infofile, fileid);
1101
  result := RecyclerGetDateTime(infofile, fileid);
1100
end;
1102
end;
1101
 
1103
 
1102
function RecyclerGetDateTime(InfofileOrRecycleFolder: string; id: string): tdatetime; overload;
1104
function RecyclerGetDateTime(InfofileOrRecycleFolder: string; id: string): tdatetime; overload;
1103
var
1105
var
1104
  fs: TFileStream;
1106
  fs: TFileStream;
1105
  i, record_length: integer;
1107
  i, record_length: integer;
1106
  tmp: string;
1108
  tmp: string;
1107
const
1109
const
1108
  length_position = $C;
1110
  length_position = $C;
1109
  unique_index_position = $118;
1111
  unique_index_position = $118;
1110
  timestamp_position = $120;
1112
  timestamp_position = $120;
1111
begin
1113
begin
1112
  // FILETIME does start at 01.01.1601 00:00:00 (GMT)
1114
  // FILETIME does start at 01.01.1601 00:00:00 (GMT)
1113
  result := EncodeDateTime(1601, 1, 1, 0, 0, 0, 0);
1115
  result := EncodeDateTime(1601, 1, 1, 0, 0, 0, 0);
1114
 
1116
 
1115
  tmp := InfofileOrRecycleFolder;
1117
  tmp := InfofileOrRecycleFolder;
1116
 
1118
 
1117
  if _isFileVistaNamed(tmp) then
1119
  if _isFileVistaNamed(tmp) then
1118
  begin
1120
  begin
1119
    result := _VistaGetDateTime(tmp);
1121
    result := _VistaGetDateTime(tmp);
1120
    exit;
1122
    exit;
1121
  end;
1123
  end;
1122
 
1124
 
1123
  {$IFDEF allow_all_filenames}
1125
  {$IFDEF allow_all_filenames}
1124
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1126
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1125
  begin
1127
  begin
1126
    if fileexists(extractfilepath(tmp)+'INFO2') then
1128
    if fileexists(extractfilepath(tmp)+'INFO2') then
1127
      tmp := extractfilepath(tmp)+'INFO2'
1129
      tmp := extractfilepath(tmp)+'INFO2'
1128
    else if fileexists(extractfilepath(tmp)+'INFO') then
1130
    else if fileexists(extractfilepath(tmp)+'INFO') then
1129
      tmp := extractfilepath(tmp)+'INFO';
1131
      tmp := extractfilepath(tmp)+'INFO';
1130
  end;
1132
  end;
1131
  {$ENDIF}
1133
  {$ENDIF}
1132
 
1134
 
1133
  if directoryexists(tmp) then
1135
  if directoryexists(tmp) then
1134
  begin
1136
  begin
1135
    tmp := IncludeTrailingBackslash(tmp);
1137
    tmp := IncludeTrailingBackslash(tmp);
1136
 
1138
 
1137
    if fileexists(tmp+'$I'+id) then
1139
    if fileexists(tmp+'$I'+id) then
1138
    begin
1140
    begin
1139
      result := _VistaGetDateTime(tmp+'$I'+id);
1141
      result := _VistaGetDateTime(tmp+'$I'+id);
1140
      exit;
1142
      exit;
1141
    end
1143
    end
1142
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1144
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1143
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1145
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1144
  end;
1146
  end;
1145
 
1147
 
1146
  if not fileexists(tmp) then exit;
1148
  if not fileexists(tmp) then exit;
1147
  if not RecyclerIsValid(tmp) then exit;
1149
  if not RecyclerIsValid(tmp) then exit;
1148
 
1150
 
1149
  fs := TFileStream.Create(tmp, fmOpenRead);
1151
  fs := TFileStream.Create(tmp, fmOpenRead);
1150
  try
1152
  try
1151
    fs.seek(length_position, soFromBeginning);
1153
    fs.seek(length_position, soFromBeginning);
1152
    record_length := _readInt32(fs);
1154
    record_length := _readInt32(fs);
1153
 
1155
 
1154
    i := -1;
1156
    i := -1;
1155
    repeat
1157
    repeat
1156
      inc(i);
1158
      inc(i);
1157
      if unique_index_position+i*record_length > fs.size then break;
1159
      if unique_index_position+i*record_length > fs.size then break;
1158
      fs.seek(unique_index_position+i*record_length, soFromBeginning);
1160
      fs.seek(unique_index_position+i*record_length, soFromBeginning);
1159
      if inttostr(_readInt32(fs)) = id then
1161
      if inttostr(_readInt32(fs)) = id then
1160
      begin
1162
      begin
1161
        fs.seek(timestamp_position+i*record_length, soFromBeginning);
1163
        fs.seek(timestamp_position+i*record_length, soFromBeginning);
1162
        result := _fileTimeToDateTime(_readInt64(fs));
1164
        result := _fileTimeToDateTime(_readInt64(fs));
1163
        break;
1165
        break;
1164
      end;
1166
      end;
1165
      until false;
1167
      until false;
1166
  finally
1168
  finally
1167
    fs.free;
1169
    fs.free;
1168
  end;
1170
  end;
1169
end;
1171
end;
1170
 
1172
 
1171
{$ENDIF}
1173
{$ENDIF}
1172
 
1174
 
1173
////////////////////////////////////////////////////////////////////////////////
1175
////////////////////////////////////////////////////////////////////////////////
1174
 
1176
 
1175
function RecyclerGetSourceUnicode(InfofileOrRecycleFolder: string): WideString; overload;
1177
function RecyclerGetSourceUnicode(InfofileOrRecycleFolder: string): WideString; overload;
1176
begin
1178
begin
1177
  result := RecyclerGetSourceUnicode(InfofileOrRecycleFolder, '');
1179
  result := RecyclerGetSourceUnicode(InfofileOrRecycleFolder, '');
1178
end;
1180
end;
1179
 
1181
 
1180
function RecyclerGetSourceUnicode(drive: char; fileid: string): WideString; overload;
1182
function RecyclerGetSourceUnicode(drive: char; fileid: string): WideString; overload;
1181
begin
1183
begin
1182
  result := RecyclerGetSourceUnicode(drive, '', fileid);
1184
  result := RecyclerGetSourceUnicode(drive, '', fileid);
1183
end;
1185
end;
1184
 
1186
 
1185
function RecyclerGetSourceUnicode(drive: char; UserSID: string; fileid: string): WideString; overload;
1187
function RecyclerGetSourceUnicode(drive: char; UserSID: string; fileid: string): WideString; overload;
1186
var
1188
var
1187
  infofile: string;
1189
  infofile: string;
1188
begin
1190
begin
1189
  if Win32Platform = VER_PLATFORM_WIN32_NT then
1191
  if Win32Platform = VER_PLATFORM_WIN32_NT then
1190
  begin
1192
  begin
1191
    infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1193
    infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1192
    result := RecyclerGetSourceUnicode(infofile, fileid);
1194
    result := RecyclerGetSourceUnicode(infofile, fileid);
1193
  end
1195
  end
1194
  else
1196
  else
1195
  begin
1197
  begin
1196
    // Windows 9x does not support unicode
1198
    // Windows 9x does not support unicode
1197
    result := RecyclerGetSource(drive, UserSID, fileid);
1199
    result := RecyclerGetSource(drive, UserSID, fileid);
1198
  end;
1200
  end;
1199
end;
1201
end;
1200
 
1202
 
1201
function RecyclerGetSourceUnicode(InfofileOrRecycleFolder: string; id: string): WideString; overload;
1203
function RecyclerGetSourceUnicode(InfofileOrRecycleFolder: string; id: string): WideString; overload;
1202
var
1204
var
1203
  fs: TFileStream;
1205
  fs: TFileStream;
1204
  i, record_length: integer;
1206
  i, record_length: integer;
1205
  tmp: string;
1207
  tmp: string;
1206
const
1208
const
1207
  length_position = $C;
1209
  length_position = $C;
1208
  unique_index_position = $118;
1210
  unique_index_position = $118;
1209
  unicode_source_position = $12C;
1211
  unicode_source_position = $12C;
1210
begin
1212
begin
1211
  result := '';
1213
  result := '';
1212
 
1214
 
1213
  tmp := InfofileOrRecycleFolder;
1215
  tmp := InfofileOrRecycleFolder;
1214
 
1216
 
1215
  if _isFileVistaNamed(tmp) then
1217
  if _isFileVistaNamed(tmp) then
1216
  begin
1218
  begin
1217
    // Vista only gives unicode names
1219
    // Vista only gives unicode names
1218
    result := _VistaGetSourceUnicode(tmp);
1220
    result := _VistaGetSourceUnicode(tmp);
1219
    exit;
1221
    exit;
1220
  end;
1222
  end;
1221
 
1223
 
1222
  {$IFDEF allow_all_filenames}
1224
  {$IFDEF allow_all_filenames}
1223
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1225
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1224
  begin
1226
  begin
1225
    if fileexists(extractfilepath(tmp)+'INFO2') then
1227
    if fileexists(extractfilepath(tmp)+'INFO2') then
1226
      tmp := extractfilepath(tmp)+'INFO2'
1228
      tmp := extractfilepath(tmp)+'INFO2'
1227
    else if fileexists(extractfilepath(tmp)+'INFO') then
1229
    else if fileexists(extractfilepath(tmp)+'INFO') then
1228
      tmp := extractfilepath(tmp)+'INFO';
1230
      tmp := extractfilepath(tmp)+'INFO';
1229
  end;
1231
  end;
1230
  {$ENDIF}
1232
  {$ENDIF}
1231
 
1233
 
1232
  if directoryexists(tmp) then
1234
  if directoryexists(tmp) then
1233
  begin
1235
  begin
1234
    tmp := IncludeTrailingBackslash(tmp);
1236
    tmp := IncludeTrailingBackslash(tmp);
1235
 
1237
 
1236
    if fileexists(tmp+'$I'+id) then
1238
    if fileexists(tmp+'$I'+id) then
1237
    begin
1239
    begin
1238
      // Vista only gives unicode names
1240
      // Vista only gives unicode names
1239
      result := _VistaGetSourceUnicode(tmp+'$I'+id);
1241
      result := _VistaGetSourceUnicode(tmp+'$I'+id);
1240
      exit;
1242
      exit;
1241
    end
1243
    end
1242
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1244
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1243
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1245
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1244
  end;
1246
  end;
1245
 
1247
 
1246
  if not fileexists(tmp) then exit;
1248
  if not fileexists(tmp) then exit;
1247
  if not RecyclerIsValid(tmp) then exit;
1249
  if not RecyclerIsValid(tmp) then exit;
1248
 
1250
 
1249
  fs := TFileStream.Create(tmp, fmOpenRead);
1251
  fs := TFileStream.Create(tmp, fmOpenRead);
1250
  try
1252
  try
1251
    fs.seek(length_position, soFromBeginning);
1253
    fs.seek(length_position, soFromBeginning);
1252
    record_length := _readInt32(fs);
1254
    record_length := _readInt32(fs);
1253
 
1255
 
1254
    if record_length <> $118 then
1256
    if record_length <> $118 then
1255
    begin
1257
    begin
1256
      // Windows NT
1258
      // Windows NT
1257
      i := -1;
1259
      i := -1;
1258
      repeat
1260
      repeat
1259
        inc(i);
1261
        inc(i);
1260
        if unique_index_position+i*record_length > fs.size then break;
1262
        if unique_index_position+i*record_length > fs.size then break;
1261
        fs.seek(unique_index_position+i*record_length, soFromBeginning);
1263
        fs.seek(unique_index_position+i*record_length, soFromBeginning);
1262
        if inttostr(_readInt32(fs)) = id then
1264
        if inttostr(_readInt32(fs)) = id then
1263
        begin
1265
        begin
1264
          fs.seek(unicode_source_position+i*record_length, soFromBeginning);
1266
          fs.seek(unicode_source_position+i*record_length, soFromBeginning);
1265
          result := _readNullTerminatedWideString(fs);
1267
          result := _readNullTerminatedWideString(fs);
1266
          break;
1268
          break;
1267
        end;
1269
        end;
1268
      until false;
1270
      until false;
1269
    end;
1271
    end;
1270
  finally
1272
  finally
1271
    fs.free;
1273
    fs.free;
1272
  end;
1274
  end;
1273
 
1275
 
1274
  if record_length = $118 then
1276
  if record_length = $118 then
1275
  begin
1277
  begin
1276
    // Windows 9x has no unicode support
1278
    // Windows 9x has no unicode support
1277
    result := RecyclerGetSource(tmp, id);
1279
    result := RecyclerGetSource(tmp, id);
1278
  end;
1280
  end;
1279
end;
1281
end;
1280
 
1282
 
1281
////////////////////////////////////////////////////////////////////////////////
1283
////////////////////////////////////////////////////////////////////////////////
1282
 
1284
 
1283
function RecyclerGetSource(InfofileOrRecycleFolder: string): string; overload;
1285
function RecyclerGetSource(InfofileOrRecycleFolder: string): string; overload;
1284
begin
1286
begin
1285
  result := RecyclerGetSource(InfofileOrRecycleFolder, '');
1287
  result := RecyclerGetSource(InfofileOrRecycleFolder, '');
1286
end;
1288
end;
1287
 
1289
 
1288
function RecyclerGetSource(drive: char; fileid: string): string; overload;
1290
function RecyclerGetSource(drive: char; fileid: string): string; overload;
1289
begin
1291
begin
1290
  result := RecyclerGetSource(drive, '', fileid);
1292
  result := RecyclerGetSource(drive, '', fileid);
1291
end;
1293
end;
1292
 
1294
 
1293
function RecyclerGetSource(drive: char; UserSID: string; fileid: string): string; overload;
1295
function RecyclerGetSource(drive: char; UserSID: string; fileid: string): string; overload;
1294
var
1296
var
1295
  infofile: string;
1297
  infofile: string;
1296
begin
1298
begin
1297
  infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1299
  infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1298
  result := RecyclerGetSource(infofile, fileid);
1300
  result := RecyclerGetSource(infofile, fileid);
1299
end;
1301
end;
1300
 
1302
 
1301
function RecyclerGetSource(InfofileOrRecycleFolder: string; id: string): string; overload;
1303
function RecyclerGetSource(InfofileOrRecycleFolder: string; id: string): string; overload;
1302
var
1304
var
1303
  fs: TFileStream;
1305
  fs: TFileStream;
1304
  i, record_length: integer;
1306
  i, record_length: integer;
1305
  tmp: string;
1307
  tmp: string;
1306
  alternativ: string;
1308
  alternativ: string;
1307
const
1309
const
1308
  length_position = $C;
1310
  length_position = $C;
1309
  unique_index_position = $118;
1311
  unique_index_position = $118;
1310
  source_position = $14;
1312
  source_position = $14;
1311
begin
1313
begin
1312
  result := '';
1314
  result := '';
1313
 
1315
 
1314
  tmp := InfofileOrRecycleFolder;
1316
  tmp := InfofileOrRecycleFolder;
1315
 
1317
 
1316
  if _isFileVistaNamed(tmp) then
1318
  if _isFileVistaNamed(tmp) then
1317
  begin
1319
  begin
1318
    // Vista only gives unicode names
1320
    // Vista only gives unicode names
1319
    result := _VistaGetSourceUnicode(tmp);
1321
    result := _VistaGetSourceUnicode(tmp);
1320
    exit;
1322
    exit;
1321
  end;
1323
  end;
1322
 
1324
 
1323
  {$IFDEF allow_all_filenames}
1325
  {$IFDEF allow_all_filenames}
1324
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1326
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1325
  begin
1327
  begin
1326
    if fileexists(extractfilepath(tmp)+'INFO2') then
1328
    if fileexists(extractfilepath(tmp)+'INFO2') then
1327
      tmp := extractfilepath(tmp)+'INFO2'
1329
      tmp := extractfilepath(tmp)+'INFO2'
1328
    else if fileexists(extractfilepath(tmp)+'INFO') then
1330
    else if fileexists(extractfilepath(tmp)+'INFO') then
1329
      tmp := extractfilepath(tmp)+'INFO';
1331
      tmp := extractfilepath(tmp)+'INFO';
1330
  end;
1332
  end;
1331
  {$ENDIF}
1333
  {$ENDIF}
1332
 
1334
 
1333
  if directoryexists(tmp) then
1335
  if directoryexists(tmp) then
1334
  begin
1336
  begin
1335
    tmp := IncludeTrailingBackslash(tmp);
1337
    tmp := IncludeTrailingBackslash(tmp);
1336
 
1338
 
1337
    if fileexists(tmp+'$I'+id) then
1339
    if fileexists(tmp+'$I'+id) then
1338
    begin
1340
    begin
1339
      // Vista only gives unicode names
1341
      // Vista only gives unicode names
1340
      result := _VistaGetSourceUnicode(tmp+'$I'+id);
1342
      result := _VistaGetSourceUnicode(tmp+'$I'+id);
1341
      exit;
1343
      exit;
1342
    end
1344
    end
1343
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1345
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1344
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1346
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1345
  end;
1347
  end;
1346
 
1348
 
1347
  if not fileexists(tmp) then exit;
1349
  if not fileexists(tmp) then exit;
1348
  if not RecyclerIsValid(tmp) then exit;
1350
  if not RecyclerIsValid(tmp) then exit;
1349
 
1351
 
1350
  fs := TFileStream.Create(tmp, fmOpenRead);
1352
  fs := TFileStream.Create(tmp, fmOpenRead);
1351
  try
1353
  try
1352
    fs.seek(length_position, soFromBeginning);
1354
    fs.seek(length_position, soFromBeginning);
1353
    record_length := _readInt32(fs);
1355
    record_length := _readInt32(fs);
1354
 
1356
 
1355
    i := -1;
1357
    i := -1;
1356
    repeat
1358
    repeat
1357
      inc(i);
1359
      inc(i);
1358
      if unique_index_position+i*record_length > fs.size then break;
1360
      if unique_index_position+i*record_length > fs.size then break;
1359
      fs.seek(unique_index_position+i*record_length, soFromBeginning);
1361
      fs.seek(unique_index_position+i*record_length, soFromBeginning);
1360
      if inttostr(_readInt32(fs)) = id then
1362
      if inttostr(_readInt32(fs)) = id then
1361
      begin
1363
      begin
1362
        fs.seek(source_position+i*record_length, soFromBeginning);
1364
        fs.seek(source_position+i*record_length, soFromBeginning);
1363
        alternativ := _readChar(fs);
1365
        alternativ := _readChar(fs);
1364
 
1366
 
1365
        if alternativ = #0 then
1367
        if alternativ = #0 then
1366
        begin
1368
        begin
1367
          fs.seek(source_position+i*record_length+1, soFromBeginning);
1369
          fs.seek(source_position+i*record_length+1, soFromBeginning);
1368
          result := _readNullTerminatedString(fs);
1370
          result := _readNullTerminatedString(fs);
1369
        end
1371
        end
1370
        else
1372
        else
1371
        begin
1373
        begin
1372
          fs.seek(source_position+i*record_length, soFromBeginning);
1374
          fs.seek(source_position+i*record_length, soFromBeginning);
1373
          result := _readNullTerminatedString(fs);
1375
          result := _readNullTerminatedString(fs);
1374
        end;
1376
        end;
1375
 
1377
 
1376
        break;
1378
        break;
1377
      end;
1379
      end;
1378
    until false;
1380
    until false;
1379
  finally
1381
  finally
1380
    fs.free;
1382
    fs.free;
1381
  end;
1383
  end;
1382
 
1384
 
1383
  // In some cases the ansi-source-name is [Null]:\...\
1385
  // In some cases the ansi-source-name is [Null]:\...\
1384
  if alternativ = #0 then
1386
  if alternativ = #0 then
1385
  begin
1387
  begin
1386
    result := RecyclerGetSourceDrive(InfofileOrRecycleFolder, id) + result;
1388
    result := RecyclerGetSourceDrive(InfofileOrRecycleFolder, id) + result;
1387
  end;
1389
  end;
1388
end;
1390
end;
1389
 
1391
 
1390
////////////////////////////////////////////////////////////////////////////////
1392
////////////////////////////////////////////////////////////////////////////////
1391
 
1393
 
1392
procedure RecyclerListIndexes(drive: char; result: TStringList); overload;
1394
procedure RecyclerListIndexes(drive: char; result: TStringList); overload;
1393
begin
1395
begin
1394
  RecyclerListIndexes(drive, '', result);
1396
  RecyclerListIndexes(drive, '', result);
1395
end;
1397
end;
1396
 
1398
 
1397
procedure RecyclerListIndexes(drive: char; UserSID: string; result: TStringList); overload;
1399
procedure RecyclerListIndexes(drive: char; UserSID: string; result: TStringList); overload;
1398
var
1400
var
1399
  infofile: string;
1401
  infofile: string;
1400
begin
1402
begin
1401
  infofile := RecyclerGetPath(drive, UserSID, false);
1403
  infofile := RecyclerGetPath(drive, UserSID, false);
1402
  RecyclerListIndexes(infofile, result);
1404
  RecyclerListIndexes(infofile, result);
1403
end;
1405
end;
1404
 
1406
 
1405
procedure RecyclerListIndexes(InfofileOrRecycleFolder: string; result: TStringList); overload;
1407
procedure RecyclerListIndexes(InfofileOrRecycleFolder: string; result: TStringList); overload;
1406
var
1408
var
1407
  fs: TFileStream;
1409
  fs: TFileStream;
1408
  i, record_length: integer;
1410
  i, record_length: integer;
1409
  tmp: string;
1411
  tmp: string;
1410
const
1412
const
1411
  length_position = $C;
1413
  length_position = $C;
1412
  unique_index_position = $118;
1414
  unique_index_position = $118;
1413
begin
1415
begin
1414
  tmp := InfofileOrRecycleFolder;
1416
  tmp := InfofileOrRecycleFolder;
1415
 
1417
 
1416
  if _isFileVistaNamed(tmp) then
1418
  if _isFileVistaNamed(tmp) then
1417
  begin
1419
  begin
1418
    _VistaListIndexes(extractfilepath(tmp), result);
1420
    _VistaListIndexes(extractfilepath(tmp), result);
1419
    exit;
1421
    exit;
1420
  end;
1422
  end;
1421
 
1423
 
1422
  {$IFDEF allow_all_filenames}
1424
  {$IFDEF allow_all_filenames}
1423
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1425
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1424
  begin
1426
  begin
1425
    if fileexists(extractfilepath(tmp)+'INFO2') then
1427
    if fileexists(extractfilepath(tmp)+'INFO2') then
1426
      tmp := extractfilepath(tmp)+'INFO2'
1428
      tmp := extractfilepath(tmp)+'INFO2'
1427
    else if fileexists(extractfilepath(tmp)+'INFO') then
1429
    else if fileexists(extractfilepath(tmp)+'INFO') then
1428
      tmp := extractfilepath(tmp)+'INFO';
1430
      tmp := extractfilepath(tmp)+'INFO';
1429
  end;
1431
  end;
1430
  {$ENDIF}
1432
  {$ENDIF}
1431
 
1433
 
1432
  if directoryexists(tmp) then
1434
  if directoryexists(tmp) then
1433
  begin
1435
  begin
1434
    tmp := IncludeTrailingBackslash(tmp);
1436
    tmp := IncludeTrailingBackslash(tmp);
1435
 
1437
 
1436
    if fileexists(tmp+'INFO2') then     tmp := tmp+'INFO2'
1438
    if fileexists(tmp+'INFO2') then     tmp := tmp+'INFO2'
1437
    else if fileexists(tmp+'INFO') then tmp := tmp+'INFO'
1439
    else if fileexists(tmp+'INFO') then tmp := tmp+'INFO'
1438
    else
1440
    else
1439
    begin
1441
    begin
1440
      // Last try: is it a vista-directory?
1442
      // Last try: is it a vista-directory?
1441
      _VistaListIndexes(tmp, result);
1443
      _VistaListIndexes(tmp, result);
1442
      exit;
1444
      exit;
1443
    end;
1445
    end;
1444
  end;
1446
  end;
1445
 
1447
 
1446
  if not fileexists(tmp) then exit;
1448
  if not fileexists(tmp) then exit;
1447
  if not RecyclerIsValid(tmp) then exit;
1449
  if not RecyclerIsValid(tmp) then exit;
1448
 
1450
 
1449
  fs := TFileStream.Create(tmp, fmOpenRead);
1451
  fs := TFileStream.Create(tmp, fmOpenRead);
1450
  try
1452
  try
1451
    fs.seek(length_position, soFromBeginning);
1453
    fs.seek(length_position, soFromBeginning);
1452
    record_length := _readInt32(fs);
1454
    record_length := _readInt32(fs);
1453
 
1455
 
1454
    i := -1;
1456
    i := -1;
1455
    repeat
1457
    repeat
1456
      inc(i);
1458
      inc(i);
1457
      if unique_index_position+i*record_length > fs.size then break;
1459
      if unique_index_position+i*record_length > fs.size then break;
1458
      fs.seek(unique_index_position+i*record_length, soFromBeginning);
1460
      fs.seek(unique_index_position+i*record_length, soFromBeginning);
1459
 
1461
 
1460
      result.Add(inttostr(_readInt32(fs)));
1462
      result.Add(inttostr(_readInt32(fs)));
1461
    until false;
1463
    until false;
1462
  finally
1464
  finally
1463
    fs.free;
1465
    fs.free;
1464
  end;
1466
  end;
1465
end;
1467
end;
1466
 
1468
 
1467
////////////////////////////////////////////////////////////////////////////////
1469
////////////////////////////////////////////////////////////////////////////////
1468
 
1470
 
1469
function RecyclerGetSourceDrive(InfofileOrRecycleFolder: string): char; overload;
1471
function RecyclerGetSourceDrive(InfofileOrRecycleFolder: string): char; overload;
1470
begin
1472
begin
1471
  result := RecyclerGetSourceDrive(InfofileOrRecycleFolder, '');
1473
  result := RecyclerGetSourceDrive(InfofileOrRecycleFolder, '');
1472
end;
1474
end;
1473
 
1475
 
1474
function RecyclerGetSourceDrive(drive: char; fileid: string): char; overload;
1476
function RecyclerGetSourceDrive(drive: char; fileid: string): char; overload;
1475
begin
1477
begin
1476
  result := RecyclerGetSourceDrive(drive, '', fileid);
1478
  result := RecyclerGetSourceDrive(drive, '', fileid);
1477
end;
1479
end;
1478
 
1480
 
1479
function RecyclerGetSourceDrive(drive: char; UserSID: string; fileid: string): char; overload;
1481
function RecyclerGetSourceDrive(drive: char; UserSID: string; fileid: string): char; overload;
1480
var
1482
var
1481
  infofile: string;
1483
  infofile: string;
1482
begin
1484
begin
1483
  infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1485
  infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1484
  result := RecyclerGetSourceDrive(infofile, fileid);
1486
  result := RecyclerGetSourceDrive(infofile, fileid);
1485
end;
1487
end;
1486
 
1488
 
1487
function RecyclerGetSourceDrive(InfofileOrRecycleFolder: string; id: string): char; overload;
1489
function RecyclerGetSourceDrive(InfofileOrRecycleFolder: string; id: string): char; overload;
1488
var
1490
var
1489
  fs: TFileStream;
1491
  fs: TFileStream;
1490
  i, record_length: integer;
1492
  i, record_length: integer;
1491
  tmp: string;
1493
  tmp: string;
1492
const
1494
const
1493
  length_position = $C;
1495
  length_position = $C;
1494
  unique_index_position = $118;
1496
  unique_index_position = $118;
1495
  source_drive_position = $11C;
1497
  source_drive_position = $11C;
1496
begin
1498
begin
1497
  result := #0;
1499
  result := #0;
1498
 
1500
 
1499
  tmp := InfofileOrRecycleFolder;
1501
  tmp := InfofileOrRecycleFolder;
1500
 
1502
 
1501
  if _isFileVistaNamed(tmp) then
1503
  if _isFileVistaNamed(tmp) then
1502
  begin
1504
  begin
1503
    result := _VistaGetSourceDrive(tmp);
1505
    result := _VistaGetSourceDrive(tmp);
1504
    exit;
1506
    exit;
1505
  end;
1507
  end;
1506
 
1508
 
1507
  {$IFDEF allow_all_filenames}
1509
  {$IFDEF allow_all_filenames}
1508
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1510
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1509
  begin
1511
  begin
1510
    if fileexists(extractfilepath(tmp)+'INFO2') then
1512
    if fileexists(extractfilepath(tmp)+'INFO2') then
1511
      tmp := extractfilepath(tmp)+'INFO2'
1513
      tmp := extractfilepath(tmp)+'INFO2'
1512
    else if fileexists(extractfilepath(tmp)+'INFO') then
1514
    else if fileexists(extractfilepath(tmp)+'INFO') then
1513
      tmp := extractfilepath(tmp)+'INFO';
1515
      tmp := extractfilepath(tmp)+'INFO';
1514
  end;
1516
  end;
1515
  {$ENDIF}
1517
  {$ENDIF}
1516
 
1518
 
1517
  if directoryexists(tmp) then
1519
  if directoryexists(tmp) then
1518
  begin
1520
  begin
1519
    tmp := IncludeTrailingBackslash(tmp);
1521
    tmp := IncludeTrailingBackslash(tmp);
1520
 
1522
 
1521
    if fileexists(tmp+'$I'+id) then
1523
    if fileexists(tmp+'$I'+id) then
1522
    begin
1524
    begin
1523
      result := _VistaGetSourceDrive(tmp+'$I'+id);
1525
      result := _VistaGetSourceDrive(tmp+'$I'+id);
1524
      exit;
1526
      exit;
1525
    end
1527
    end
1526
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1528
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1527
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1529
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1528
  end;
1530
  end;
1529
 
1531
 
1530
  if not fileexists(tmp) then exit;
1532
  if not fileexists(tmp) then exit;
1531
  if not RecyclerIsValid(tmp) then exit;
1533
  if not RecyclerIsValid(tmp) then exit;
1532
 
1534
 
1533
  fs := TFileStream.Create(tmp, fmOpenRead);
1535
  fs := TFileStream.Create(tmp, fmOpenRead);
1534
  try
1536
  try
1535
    fs.seek(length_position, soFromBeginning);
1537
    fs.seek(length_position, soFromBeginning);
1536
    record_length := _readInt32(fs);
1538
    record_length := _readInt32(fs);
1537
 
1539
 
1538
    i := -1;
1540
    i := -1;
1539
    repeat
1541
    repeat
1540
      inc(i);
1542
      inc(i);
1541
      if unique_index_position+i*record_length > fs.size then break;
1543
      if unique_index_position+i*record_length > fs.size then break;
1542
      fs.seek(unique_index_position+i*record_length, soFromBeginning);
1544
      fs.seek(unique_index_position+i*record_length, soFromBeginning);
1543
      if inttostr(_readInt32(fs)) = id then
1545
      if inttostr(_readInt32(fs)) = id then
1544
      begin
1546
      begin
1545
        fs.seek(source_drive_position+i*record_length, soFromBeginning);
1547
        fs.seek(source_drive_position+i*record_length, soFromBeginning);
1546
        result := chr(ord('A') + _readInt8(fs));
1548
        result := chr(ord('A') + _readInt8(fs));
1547
        break;
1549
        break;
1548
      end;
1550
      end;
1549
    until false;
1551
    until false;
1550
  finally
1552
  finally
1551
    fs.free;
1553
    fs.free;
1552
  end;
1554
  end;
1553
end;
1555
end;
1554
 
1556
 
1555
////////////////////////////////////////////////////////////////////////////////
1557
////////////////////////////////////////////////////////////////////////////////
1556
 
1558
 
1557
function RecyclerOriginalSize(InfofileOrRecycleFolder: string): integer; overload;
1559
function RecyclerOriginalSize(InfofileOrRecycleFolder: string): integer; overload;
1558
begin
1560
begin
1559
  result := RecyclerOriginalSize(InfofileOrRecycleFolder, '');
1561
  result := RecyclerOriginalSize(InfofileOrRecycleFolder, '');
1560
end;
1562
end;
1561
 
1563
 
1562
function RecyclerOriginalSize(drive: char; fileid: string): integer; overload;
1564
function RecyclerOriginalSize(drive: char; fileid: string): integer; overload;
1563
begin
1565
begin
1564
  result := RecyclerOriginalSize(drive, '', fileid);
1566
  result := RecyclerOriginalSize(drive, '', fileid);
1565
end;
1567
end;
1566
 
1568
 
1567
function RecyclerOriginalSize(drive: char; UserSID: string; fileid: string): integer; overload;
1569
function RecyclerOriginalSize(drive: char; UserSID: string; fileid: string): integer; overload;
1568
var
1570
var
1569
  infofile: string;
1571
  infofile: string;
1570
begin
1572
begin
1571
  infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1573
  infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1572
  result := RecyclerOriginalSize(infofile, fileid);
1574
  result := RecyclerOriginalSize(infofile, fileid);
1573
end;
1575
end;
1574
 
1576
 
1575
function RecyclerOriginalSize(InfofileOrRecycleFolder: string; id: string): integer; overload;
1577
function RecyclerOriginalSize(InfofileOrRecycleFolder: string; id: string): integer; overload;
1576
var
1578
var
1577
  fs: TFileStream;
1579
  fs: TFileStream;
1578
  i, record_length: integer;
1580
  i, record_length: integer;
1579
  tmp: string;
1581
  tmp: string;
1580
const
1582
const
1581
  length_position = $C;
1583
  length_position = $C;
1582
  unique_index_position = $118;
1584
  unique_index_position = $118;
1583
  original_size_position = $128;
1585
  original_size_position = $128;
1584
begin
1586
begin
1585
  result := -1;
1587
  result := -1;
1586
 
1588
 
1587
  tmp := InfofileOrRecycleFolder;
1589
  tmp := InfofileOrRecycleFolder;
1588
 
1590
 
1589
  if _isFileVistaNamed(tmp) then
1591
  if _isFileVistaNamed(tmp) then
1590
  begin
1592
  begin
1591
    result := _VistaOriginalSize(tmp);
1593
    result := _VistaOriginalSize(tmp);
1592
    exit;
1594
    exit;
1593
  end;
1595
  end;
1594
 
1596
 
1595
  {$IFDEF allow_all_filenames}
1597
  {$IFDEF allow_all_filenames}
1596
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1598
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1597
  begin
1599
  begin
1598
    if fileexists(extractfilepath(tmp)+'INFO2') then
1600
    if fileexists(extractfilepath(tmp)+'INFO2') then
1599
      tmp := extractfilepath(tmp)+'INFO2'
1601
      tmp := extractfilepath(tmp)+'INFO2'
1600
    else if fileexists(extractfilepath(tmp)+'INFO') then
1602
    else if fileexists(extractfilepath(tmp)+'INFO') then
1601
      tmp := extractfilepath(tmp)+'INFO';
1603
      tmp := extractfilepath(tmp)+'INFO';
1602
  end;
1604
  end;
1603
  {$ENDIF}
1605
  {$ENDIF}
1604
 
1606
 
1605
  if directoryexists(tmp) then
1607
  if directoryexists(tmp) then
1606
  begin
1608
  begin
1607
    tmp := IncludeTrailingBackslash(tmp);
1609
    tmp := IncludeTrailingBackslash(tmp);
1608
 
1610
 
1609
    if fileexists(tmp+'$I'+id) then
1611
    if fileexists(tmp+'$I'+id) then
1610
    begin
1612
    begin
1611
      result := _VistaOriginalSize(tmp+'$I'+id);
1613
      result := _VistaOriginalSize(tmp+'$I'+id);
1612
      exit;
1614
      exit;
1613
    end
1615
    end
1614
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1616
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1615
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1617
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1616
  end;
1618
  end;
1617
 
1619
 
1618
  if not fileexists(tmp) then exit;
1620
  if not fileexists(tmp) then exit;
1619
  if not RecyclerIsValid(tmp) then exit;
1621
  if not RecyclerIsValid(tmp) then exit;
1620
 
1622
 
1621
  fs := TFileStream.Create(tmp, fmOpenRead);
1623
  fs := TFileStream.Create(tmp, fmOpenRead);
1622
  try
1624
  try
1623
    fs.seek(length_position, soFromBeginning);
1625
    fs.seek(length_position, soFromBeginning);
1624
    record_length := _readInt32(fs);
1626
    record_length := _readInt32(fs);
1625
 
1627
 
1626
    i := -1;
1628
    i := -1;
1627
    repeat
1629
    repeat
1628
      inc(i);
1630
      inc(i);
1629
      if unique_index_position+i*record_length > fs.size then break;
1631
      if unique_index_position+i*record_length > fs.size then break;
1630
      fs.seek(unique_index_position+i*record_length, soFromBeginning);
1632
      fs.seek(unique_index_position+i*record_length, soFromBeginning);
1631
      if inttostr(_readInt32(fs)) = id then
1633
      if inttostr(_readInt32(fs)) = id then
1632
      begin
1634
      begin
1633
        fs.seek(original_size_position+i*record_length, soFromBeginning);
1635
        fs.seek(original_size_position+i*record_length, soFromBeginning);
1634
        result := _readInt32(fs);
1636
        result := _readInt32(fs);
1635
        break;
1637
        break;
1636
      end;
1638
      end;
1637
    until false;
1639
    until false;
1638
  finally
1640
  finally
1639
    fs.free;
1641
    fs.free;
1640
  end;
1642
  end;
1641
end;
1643
end;
1642
 
1644
 
1643
////////////////////////////////////////////////////////////////////////////////
1645
////////////////////////////////////////////////////////////////////////////////
1644
 
1646
 
1645
function RecyclerIsValid(drive: char): boolean; overload;
1647
function RecyclerIsValid(drive: char): boolean; overload;
1646
begin
1648
begin
1647
  // Bei Vista und Win2003 (VM) erhalte ich bei LW A: die Meldung
1649
  // Bei Vista und Win2003 (VM) erhalte ich bei LW A: die Meldung
1648
  // "c0000013 Kein Datenträger". Exception Abfangen geht nicht.
1650
  // "c0000013 Kein Datenträger". Exception Abfangen geht nicht.
1649
  // Daher erstmal überprüfen, ob Laufwerk existiert.
1651
  // Daher erstmal überprüfen, ob Laufwerk existiert.
1650
  result := false;
1652
  result := false;
1651
  if not RecyclerIsPossible(drive) then exit;
1653
  if not RecyclerIsPossible(drive) then exit;
1652
 
1654
 
1653
  result := RecyclerIsValid(drive, '');
1655
  result := RecyclerIsValid(drive, '');
1654
end;
1656
end;
1655
 
1657
 
1656
function RecyclerIsValid(drive: char; UserSID: string): boolean; overload;
1658
function RecyclerIsValid(drive: char; UserSID: string): boolean; overload;
1657
var
1659
var
1658
  infofile: string;
1660
  infofile: string;
1659
begin
1661
begin
1660
  // Anmerkung siehe oben.
1662
  // Anmerkung siehe oben.
1661
  result := false;
1663
  result := false;
1662
  if not RecyclerIsPossible(drive) then exit;
1664
  if not RecyclerIsPossible(drive) then exit;
1663
 
1665
 
1664
  infofile := RecyclerGetPath(drive, UserSID, false);
1666
  infofile := RecyclerGetPath(drive, UserSID, false);
1665
  result := RecyclerIsValid(infofile);
1667
  result := RecyclerIsValid(infofile);
1666
end;
1668
end;
1667
 
1669
 
1668
function RecyclerIsValid(InfofileOrRecycleFolder: string): boolean; overload;
1670
function RecyclerIsValid(InfofileOrRecycleFolder: string): boolean; overload;
1669
var
1671
var
1670
  tmp: string;
1672
  tmp: string;
1671
  x: TStringList;
1673
  x: TStringList;
1672
  i: integer;
1674
  i: integer;
1673
  eine_fehlerhaft: boolean;
1675
  eine_fehlerhaft: boolean;
1674
begin
1676
begin
1675
  result := false;
1677
  result := false;
1676
 
1678
 
1677
  tmp := InfofileOrRecycleFolder;
1679
  tmp := InfofileOrRecycleFolder;
1678
 
1680
 
1679
  if _isFileVistaNamed(tmp) then
1681
  if _isFileVistaNamed(tmp) then
1680
  begin
1682
  begin
1681
    result := _VistaIsValid(tmp);
1683
    result := _VistaIsValid(tmp);
1682
    exit;
1684
    exit;
1683
  end;
1685
  end;
1684
 
1686
 
1685
  {$IFDEF allow_all_filenames}
1687
  {$IFDEF allow_all_filenames}
1686
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1688
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1687
  begin
1689
  begin
1688
    if fileexists(extractfilepath(tmp)+'INFO2') then
1690
    if fileexists(extractfilepath(tmp)+'INFO2') then
1689
      tmp := extractfilepath(tmp)+'INFO2'
1691
      tmp := extractfilepath(tmp)+'INFO2'
1690
    else if fileexists(extractfilepath(tmp)+'INFO') then
1692
    else if fileexists(extractfilepath(tmp)+'INFO') then
1691
      tmp := extractfilepath(tmp)+'INFO';
1693
      tmp := extractfilepath(tmp)+'INFO';
1692
  end;
1694
  end;
1693
  {$ENDIF}
1695
  {$ENDIF}
1694
 
1696
 
1695
  if directoryexists(tmp) then
1697
  if directoryexists(tmp) then
1696
  begin
1698
  begin
1697
    tmp := IncludeTrailingBackslash(tmp);
1699
    tmp := IncludeTrailingBackslash(tmp);
1698
 
1700
 
1699
    if fileexists(tmp+'INFO2') then
1701
    if fileexists(tmp+'INFO2') then
1700
    begin
1702
    begin
1701
      result := _checkInfo1or2File(tmp+'INFO2');
1703
      result := _checkInfo1or2File(tmp+'INFO2');
1702
    end;
1704
    end;
1703
 
1705
 
1704
    if not result and fileexists(tmp+'INFO') then
1706
    if not result and fileexists(tmp+'INFO') then
1705
    begin
1707
    begin
1706
      result := _checkInfo1or2File(tmp+'INFO');
1708
      result := _checkInfo1or2File(tmp+'INFO');
1707
    end;
1709
    end;
1708
 
1710
 
1709
    if not result then
1711
    if not result then
1710
    begin
1712
    begin
1711
      // Complete vista-directory declared?
1713
      // Complete vista-directory declared?
1712
      eine_fehlerhaft := false;
1714
      eine_fehlerhaft := false;
1713
      x := TStringList.Create;
1715
      x := TStringList.Create;
1714
      try
1716
      try
1715
        _VistaListIndexes(tmp, x);
1717
        _VistaListIndexes(tmp, x);
1716
        for i := 0 to x.Count - 1 do
1718
        for i := 0 to x.Count - 1 do
1717
        begin
1719
        begin
1718
          if not _VistaIsValid(tmp+'$I'+x.Strings[i]) then
1720
          if not _VistaIsValid(tmp+'$I'+x.Strings[i]) then
1719
          begin
1721
          begin
1720
            eine_fehlerhaft := true;
1722
            eine_fehlerhaft := true;
1721
          end;
1723
          end;
1722
        end;
1724
        end;
1723
      finally
1725
      finally
1724
        x.Free;
1726
        x.Free;
1725
      end;
1727
      end;
1726
      result := not eine_fehlerhaft;
1728
      result := not eine_fehlerhaft;
1727
    end;
1729
    end;
1728
  end;
1730
  end;
1729
 
1731
 
1730
  if not fileexists(tmp) then exit;
1732
  if not fileexists(tmp) then exit;
1731
 
1733
 
1732
  result := _checkInfo1or2File(tmp);
1734
  result := _checkInfo1or2File(tmp);
1733
end;
1735
end;
1734
 
1736
 
1735
////////////////////////////////////////////////////////////////////////////////
1737
////////////////////////////////////////////////////////////////////////////////
1736
 
1738
 
1737
function RecyclerCurrentFilename(InfofileOrRecycleFolder: string): string; overload;
1739
function RecyclerCurrentFilename(InfofileOrRecycleFolder: string): string; overload;
1738
begin
1740
begin
1739
  result := RecyclerCurrentFilename(InfofileOrRecycleFolder, '');
1741
  result := RecyclerCurrentFilename(InfofileOrRecycleFolder, '');
1740
end;
1742
end;
1741
 
1743
 
1742
function RecyclerCurrentFilename(drive: char; fileid: string): string; overload;
1744
function RecyclerCurrentFilename(drive: char; fileid: string): string; overload;
1743
begin
1745
begin
1744
  result := RecyclerCurrentFilename(drive, '', fileid);
1746
  result := RecyclerCurrentFilename(drive, '', fileid);
1745
end;
1747
end;
1746
 
1748
 
1747
function RecyclerCurrentFilename(drive: char; UserSID: string; fileid: string): string; overload;
1749
function RecyclerCurrentFilename(drive: char; UserSID: string; fileid: string): string; overload;
1748
var
1750
var
1749
  infofile: string;
1751
  infofile: string;
1750
begin
1752
begin
1751
  infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1753
  infofile := RecyclerGetPath(drive, UserSID, true, fileid);
1752
  result := RecyclerCurrentFilename(infofile, fileid);
1754
  result := RecyclerCurrentFilename(infofile, fileid);
1753
end;
1755
end;
1754
 
1756
 
1755
function RecyclerCurrentFilename(InfofileOrRecycleFolder: string; id: string): string; overload;
1757
function RecyclerCurrentFilename(InfofileOrRecycleFolder: string; id: string): string; overload;
1756
var
1758
var
1757
  a, c: string;
1759
  a, c: string;
1758
  tmp: string;
1760
  tmp: string;
1759
begin
1761
begin
1760
  result := '';
1762
  result := '';
1761
 
1763
 
1762
  tmp := InfofileOrRecycleFolder;
1764
  tmp := InfofileOrRecycleFolder;
1763
 
1765
 
1764
  if _isFileVistaNamed(tmp) then
1766
  if _isFileVistaNamed(tmp) then
1765
  begin
1767
  begin
1766
    result := _VistaCurrentFilename(tmp);
1768
    result := _VistaCurrentFilename(tmp);
1767
    exit;
1769
    exit;
1768
  end;
1770
  end;
1769
 
1771
 
1770
  {$IFDEF allow_all_filenames}
1772
  {$IFDEF allow_all_filenames}
1771
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1773
  if not RecyclerIsValid(tmp) and fileexists(tmp) then
1772
  begin
1774
  begin
1773
    if fileexists(extractfilepath(tmp)+'INFO2') then
1775
    if fileexists(extractfilepath(tmp)+'INFO2') then
1774
      tmp := extractfilepath(tmp)+'INFO2'
1776
      tmp := extractfilepath(tmp)+'INFO2'
1775
    else if fileexists(extractfilepath(tmp)+'INFO') then
1777
    else if fileexists(extractfilepath(tmp)+'INFO') then
1776
      tmp := extractfilepath(tmp)+'INFO';
1778
      tmp := extractfilepath(tmp)+'INFO';
1777
  end;
1779
  end;
1778
  {$ENDIF}
1780
  {$ENDIF}
1779
 
1781
 
1780
  if directoryexists(tmp) then
1782
  if directoryexists(tmp) then
1781
  begin
1783
  begin
1782
    tmp := IncludeTrailingBackslash(tmp);
1784
    tmp := IncludeTrailingBackslash(tmp);
1783
 
1785
 
1784
    if fileexists(tmp+'$I'+id) then
1786
    if fileexists(tmp+'$I'+id) then
1785
    begin
1787
    begin
1786
      result := _VistaCurrentFilename(tmp+'$I'+id);
1788
      result := _VistaCurrentFilename(tmp+'$I'+id);
1787
      exit;
1789
      exit;
1788
    end
1790
    end
1789
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1791
    else if fileexists(tmp+'INFO2') then tmp := tmp+'INFO2'
1790
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1792
    else if fileexists(tmp+'INFO') then  tmp := tmp+'INFO';
1791
  end;
1793
  end;
1792
 
1794
 
1793
  a := RecyclerGetSourceDrive(tmp, id);
1795
  a := RecyclerGetSourceDrive(tmp, id);
1794
  c := extractfileext(RecyclerGetSourceUnicode(tmp, id));
1796
  c := extractfileext(RecyclerGetSourceUnicode(tmp, id));
1795
  if (a <> '') then
1797
  if (a <> '') then
1796
  begin
1798
  begin
1797
    result := 'D' + a + id + c;
1799
    result := 'D' + a + id + c;
1798
  end;
1800
  end;
1799
end;
1801
end;
1800
 
1802
 
1801
////////////////////////////////////////////////////////////////////////////////
1803
////////////////////////////////////////////////////////////////////////////////
1802
 
1804
 
1803
function RecyclerGetPath(drive: char; UserSID: string; IncludeInfofile: boolean; fileid: string): string; overload;
1805
function RecyclerGetPath(drive: char; UserSID: string; IncludeInfofile: boolean; fileid: string): string; overload;
1804
var
1806
var
1805
  sl: TStringList;
1807
  sl: TStringList;
1806
begin
1808
begin
1807
  sl := TStringList.Create;
1809
  sl := TStringList.Create;
1808
  try
1810
  try
1809
    RecyclerGetInfofiles(drive, UserSID, IncludeInfofile, fileid, sl);
1811
    RecyclerGetInfofiles(drive, UserSID, IncludeInfofile, fileid, sl);
1810
    if sl.Count > 0 then
1812
    if sl.Count > 0 then
1811
      result := ExtractFilePath(sl.Strings[0])
1813
      result := ExtractFilePath(sl.Strings[0])
1812
    else
1814
    else
1813
      result := '';
1815
      result := '';
1814
  finally
1816
  finally
1815
    sl.free;
1817
    sl.free;
1816
  end;
1818
  end;
1817
end;
1819
end;
1818
 
1820
 
1819
function RecyclerGetPath(drive: char; UserSID: string; IncludeInfofile: boolean): string; overload;
1821
function RecyclerGetPath(drive: char; UserSID: string; IncludeInfofile: boolean): string; overload;
1820
var
1822
var
1821
  sl: TStringList;
1823
  sl: TStringList;
1822
begin
1824
begin
1823
  sl := TStringList.Create;
1825
  sl := TStringList.Create;
1824
  try
1826
  try
1825
    RecyclerGetInfofiles(drive, UserSID, IncludeInfofile, sl);
1827
    RecyclerGetInfofiles(drive, UserSID, IncludeInfofile, sl);
1826
    if sl.Count > 0 then
1828
    if sl.Count > 0 then
1827
      result := ExtractFilePath(sl.Strings[0])
1829
      result := ExtractFilePath(sl.Strings[0])
1828
    else
1830
    else
1829
      result := '';
1831
      result := '';
1830
  finally
1832
  finally
1831
    sl.free;
1833
    sl.free;
1832
  end;
1834
  end;
1833
end;
1835
end;
1834
 
1836
 
1835
function RecyclerGetPath(drive: char; IncludeInfofile: boolean): string; overload;
1837
function RecyclerGetPath(drive: char; IncludeInfofile: boolean): string; overload;
1836
var
1838
var
1837
  sl: TStringList;
1839
  sl: TStringList;
1838
begin
1840
begin
1839
  sl := TStringList.Create;
1841
  sl := TStringList.Create;
1840
  try
1842
  try
1841
    RecyclerGetInfofiles(drive, IncludeInfofile, sl);
1843
    RecyclerGetInfofiles(drive, IncludeInfofile, sl);
1842
    if sl.Count > 0 then
1844
    if sl.Count > 0 then
1843
      result := ExtractFilePath(sl.Strings[0])
1845
      result := ExtractFilePath(sl.Strings[0])
1844
    else
1846
    else
1845
      result := '';
1847
      result := '';
1846
  finally
1848
  finally
1847
    sl.free;
1849
    sl.free;
1848
  end;
1850
  end;
1849
end;
1851
end;
1850
 
1852
 
1851
function RecyclerGetPath(drive: char; UserSID: string): string; overload;
1853
function RecyclerGetPath(drive: char; UserSID: string): string; overload;
1852
var
1854
var
1853
  sl: TStringList;
1855
  sl: TStringList;
1854
begin
1856
begin
1855
  sl := TStringList.Create;
1857
  sl := TStringList.Create;
1856
  try
1858
  try
1857
    RecyclerGetInfofiles(drive, UserSID, sl);
1859
    RecyclerGetInfofiles(drive, UserSID, sl);
1858
    if sl.Count > 0 then
1860
    if sl.Count > 0 then
1859
      result := ExtractFilePath(sl.Strings[0])
1861
      result := ExtractFilePath(sl.Strings[0])
1860
    else
1862
    else
1861
      result := '';
1863
      result := '';
1862
  finally
1864
  finally
1863
    sl.free;
1865
    sl.free;
1864
  end;
1866
  end;
1865
end;
1867
end;
1866
 
1868
 
1867
function RecyclerGetPath(drive: char): string; overload;
1869
function RecyclerGetPath(drive: char): string; overload;
1868
var
1870
var
1869
  sl: TStringList;
1871
  sl: TStringList;
1870
begin
1872
begin
1871
  sl := TStringList.Create;
1873
  sl := TStringList.Create;
1872
  try
1874
  try
1873
    RecyclerGetInfofiles(drive, sl);
1875
    RecyclerGetInfofiles(drive, sl);
1874
    if sl.Count > 0 then
1876
    if sl.Count > 0 then
1875
      result := ExtractFilePath(sl.Strings[0])
1877
      result := ExtractFilePath(sl.Strings[0])
1876
    else
1878
    else
1877
      result := '';
1879
      result := '';
1878
  finally
1880
  finally
1879
    sl.free;
1881
    sl.free;
1880
  end;
1882
  end;
1881
end;
1883
end;
1882
 
1884
 
1883
////////////////////////////////////////////////////////////////////////////////
1885
////////////////////////////////////////////////////////////////////////////////
1884
 
1886
 
1885
procedure RecyclerGetInfofiles(drive: char; UserSID: string; IncludeInfofile: boolean; fileid: string; result: TStringList); overload;
1887
procedure RecyclerGetInfofiles(drive: char; UserSID: string; IncludeInfofile: boolean; fileid: string; result: TStringList); overload;
1886
var
1888
var
1887
  dir: string;
1889
  dir: string;
1888
begin
1890
begin
1889
  // Find recyclers from Windows Vista or higher
1891
  // Find recyclers from Windows Vista or higher
1890
 
1892
 
1891
  if _isFAT(drive) then
1893
  if _isFAT(drive) then
1892
  begin
1894
  begin
1893
    dir := drive + DriveDelim + PathDelim + '$recycle.bin' + PathDelim;
1895
    dir := drive + DriveDelim + PathDelim + '$recycle.bin' + PathDelim;
1894
    if IncludeInfofile and (fileid <> '') then
1896
    if IncludeInfofile and (fileid <> '') then
1895
    begin
1897
    begin
1896
      if fileExists(dir + '$I'+fileid) then
1898
      if fileExists(dir + '$I'+fileid) then
1897
      begin
1899
      begin
1898
        result.Add(dir + '$I'+fileid);
1900
        result.Add(dir + '$I'+fileid);
1899
      end;
1901
      end;
1900
    end
1902
    end
1901
    else
1903
    else
1902
    begin
1904
    begin
1903
      if directoryExists(dir) then
1905
      if directoryExists(dir) then
1904
      begin
1906
      begin
1905
        result.Add(dir);
1907
        result.Add(dir);
1906
      end;
1908
      end;
1907
    end;
1909
    end;
1908
  end
1910
  end
1909
  else
1911
  else
1910
  begin
1912
  begin
1911
    if UserSID <> '' then
1913
    if UserSID <> '' then
1912
    begin
1914
    begin
1913
      dir := drive + DriveDelim + PathDelim + '$recycle.bin'+PathDelim+UserSID+PathDelim;
1915
      dir := drive + DriveDelim + PathDelim + '$recycle.bin'+PathDelim+UserSID+PathDelim;
1914
      if IncludeInfofile and (fileid <> '') then
1916
      if IncludeInfofile and (fileid <> '') then
1915
      begin
1917
      begin
1916
        if fileExists(dir + '$I'+fileid) then
1918
        if fileExists(dir + '$I'+fileid) then
1917
        begin
1919
        begin
1918
          result.Add(dir + '$I'+fileid);
1920
          result.Add(dir + '$I'+fileid);
1919
        end;
1921
        end;
1920
      end
1922
      end
1921
      else
1923
      else
1922
      begin
1924
      begin
1923
        if directoryExists(dir) then
1925
        if directoryExists(dir) then
1924
        begin
1926
        begin
1925
          result.Add(dir);
1927
          result.Add(dir);
1926
        end;
1928
        end;
1927
      end;
1929
      end;
1928
    end
1930
    end
1929
    else
1931
    else
1930
    begin
1932
    begin
1931
      // TODO: aber vielleicht möchte man die Papierkörbe aller Benutzer (also aller SIDs) finden!!!
1933
      // TODO: aber vielleicht möchte man die Papierkörbe aller Benutzer (also aller SIDs) finden!!!
1932
      dir := drive + DriveDelim + PathDelim + '$recycle.bin'+PathDelim+_getMySID()+PathDelim;
1934
      dir := drive + DriveDelim + PathDelim + '$recycle.bin'+PathDelim+_getMySID()+PathDelim;
1933
      if IncludeInfofile and (fileid <> '') then
1935
      if IncludeInfofile and (fileid <> '') then
1934
      begin
1936
      begin
1935
        if fileExists(dir + '$I'+fileid) then
1937
        if fileExists(dir + '$I'+fileid) then
1936
        begin
1938
        begin
1937
          result.Add(dir + '$I'+fileid);
1939
          result.Add(dir + '$I'+fileid);
1938
        end;
1940
        end;
1939
      end
1941
      end
1940
      else
1942
      else
1941
      begin
1943
      begin
1942
        if directoryExists(dir) then
1944
        if directoryExists(dir) then
1943
        begin
1945
        begin
1944
          result.Add(dir);
1946
          result.Add(dir);
1945
        end;
1947
        end;
1946
      end;
1948
      end;
1947
    end;
1949
    end;
1948
  end;
1950
  end;
1949
 
1951
 
1950
  // Find recyclers from Windows before Vista
1952
  // Find recyclers from Windows before Vista
1951
 
1953
 
1952
  if _isFAT(drive) then
1954
  if _isFAT(drive) then
1953
  begin
1955
  begin
1954
    dir := drive + DriveDelim + PathDelim + 'Recycled' + PathDelim;
1956
    dir := drive + DriveDelim + PathDelim + 'Recycled' + PathDelim;
1955
    if IncludeInfofile then
1957
    if IncludeInfofile then
1956
    begin
1958
    begin
1957
      // Both "recycle bins" are possible if you have multiboot (but do overwrite themselfes if you empty them)
1959
      // Both "recycle bins" are possible if you have multiboot (but do overwrite themselfes if you empty them)
1958
      if fileExists(dir + 'INFO2') then
1960
      if fileExists(dir + 'INFO2') then
1959
        result.Add(dir + 'INFO2'); // Windows 95 with Internet Explorer 4 Extension or higher Windows versions
1961
        result.Add(dir + 'INFO2'); // Windows 95 with Internet Explorer 4 Extension or higher Windows versions
1960
      if fileExists(dir + 'INFO') then
1962
      if fileExists(dir + 'INFO') then
1961
        result.Add(dir + 'INFO'); // Windows 95 native
1963
        result.Add(dir + 'INFO'); // Windows 95 native
1962
    end
1964
    end
1963
    else
1965
    else
1964
    begin
1966
    begin
1965
      if directoryExists(dir) then
1967
      if directoryExists(dir) then
1966
        result.Add(dir);
1968
        result.Add(dir);
1967
    end;
1969
    end;
1968
  end
1970
  end
1969
  else
1971
  else
1970
  begin
1972
  begin
1971
    if UserSID <> '' then
1973
    if UserSID <> '' then
1972
    begin
1974
    begin
1973
      dir := drive + DriveDelim + PathDelim + 'Recycler'+PathDelim+UserSID+PathDelim;
1975
      dir := drive + DriveDelim + PathDelim + 'Recycler'+PathDelim+UserSID+PathDelim;
1974
      if IncludeInfofile then
1976
      if IncludeInfofile then
1975
      begin
1977
      begin
1976
        if fileExists(dir + 'INFO2') then
1978
        if fileExists(dir + 'INFO2') then
1977
          result.Add(dir + 'INFO2');
1979
          result.Add(dir + 'INFO2');
1978
        if fileExists(dir + 'INFO') then
1980
        if fileExists(dir + 'INFO') then
1979
          result.Add(dir + 'INFO'); // Windows NT 4
1981
          result.Add(dir + 'INFO'); // Windows NT 4
1980
      end
1982
      end
1981
      else
1983
      else
1982
      begin
1984
      begin
1983
        if directoryExists(dir) then
1985
        if directoryExists(dir) then
1984
          result.Add(dir);
1986
          result.Add(dir);
1985
      end;
1987
      end;
1986
    end
1988
    end
1987
    else
1989
    else
1988
    begin
1990
    begin
1989
      dir := drive + DriveDelim + PathDelim + 'Recycler'+PathDelim+_getMySID()+PathDelim;
1991
      dir := drive + DriveDelim + PathDelim + 'Recycler'+PathDelim+_getMySID()+PathDelim;
1990
      if IncludeInfofile then
1992
      if IncludeInfofile then
1991
      begin
1993
      begin
1992
        if fileExists(dir + 'INFO2') then
1994
        if fileExists(dir + 'INFO2') then
1993
          result.Add(dir + 'INFO2');
1995
          result.Add(dir + 'INFO2');
1994
        if fileExists(dir + 'INFO') then
1996
        if fileExists(dir + 'INFO') then
1995
          result.Add(dir + 'INFO'); // Windows NT 4
1997
          result.Add(dir + 'INFO'); // Windows NT 4
1996
      end
1998
      end
1997
      else
1999
      else
1998
      begin
2000
      begin
1999
        if directoryExists(dir) then
2001
        if directoryExists(dir) then
2000
          result.Add(dir);
2002
          result.Add(dir);
2001
      end;
2003
      end;
2002
    end;
2004
    end;
2003
  end;
2005
  end;
2004
end;
2006
end;
2005
 
2007
 
2006
procedure RecyclerGetInfofiles(drive: char; UserSID: string; IncludeInfofile: boolean; result: TStringList); overload;
2008
procedure RecyclerGetInfofiles(drive: char; UserSID: string; IncludeInfofile: boolean; result: TStringList); overload;
2007
begin
2009
begin
2008
  RecyclerGetInfofiles(drive, UserSID, IncludeInfofile, '', result);
2010
  RecyclerGetInfofiles(drive, UserSID, IncludeInfofile, '', result);
2009
end;
2011
end;
2010
 
2012
 
2011
procedure RecyclerGetInfofiles(drive: char; IncludeInfofile: boolean; result: TStringList); overload;
2013
procedure RecyclerGetInfofiles(drive: char; IncludeInfofile: boolean; result: TStringList); overload;
2012
begin
2014
begin
2013
  RecyclerGetInfofiles(drive, '', IncludeInfofile, '', result);
2015
  RecyclerGetInfofiles(drive, '', IncludeInfofile, '', result);
2014
end;
2016
end;
2015
 
2017
 
2016
procedure RecyclerGetInfofiles(drive: char; UserSID: string; result: TStringList); overload;
2018
procedure RecyclerGetInfofiles(drive: char; UserSID: string; result: TStringList); overload;
2017
begin
2019
begin
2018
  RecyclerGetInfofiles(drive, UserSID, false, '', result);
2020
  RecyclerGetInfofiles(drive, UserSID, false, '', result);
2019
end;
2021
end;
2020
 
2022
 
2021
procedure RecyclerGetInfofiles(drive: char; result: TStringList); overload;
2023
procedure RecyclerGetInfofiles(drive: char; result: TStringList); overload;
2022
begin
2024
begin
2023
  RecyclerGetInfofiles(drive, '', false, '', result);
2025
  RecyclerGetInfofiles(drive, '', false, '', result);
2024
end;
2026
end;
2025
 
2027
 
2026
////////////////////////////////////////////////////////////////////////////////
2028
////////////////////////////////////////////////////////////////////////////////
2027
 
2029
 
2028
function RecyclerCurrentFilenameAndPath(drive: char; UserSID: string; fileid: string): string; overload;
2030
function RecyclerCurrentFilenameAndPath(drive: char; UserSID: string; fileid: string): string; overload;
2029
begin
2031
begin
2030
  result := RecyclerGetPath(drive, UserSID, false, fileid) +
2032
  result := RecyclerGetPath(drive, UserSID, false, fileid) +
2031
    RecyclerCurrentFilename(drive, UserSID, fileid);
2033
    RecyclerCurrentFilename(drive, UserSID, fileid);
2032
end;
2034
end;
2033
 
2035
 
2034
function RecyclerCurrentFilenameAndPath(drive: char; fileid: string): string; overload;
2036
function RecyclerCurrentFilenameAndPath(drive: char; fileid: string): string; overload;
2035
begin
2037
begin
2036
  result := RecyclerCurrentFilenameAndPath(drive, '', fileid);
2038
  result := RecyclerCurrentFilenameAndPath(drive, '', fileid);
2037
end;
2039
end;
2038
 
2040
 
2039
function RecyclerCurrentFilenameAndPath(InfofileOrRecycleFolder: string; id: string): string; overload;
2041
function RecyclerCurrentFilenameAndPath(InfofileOrRecycleFolder: string; id: string): string; overload;
2040
begin
2042
begin
2041
  if RecyclerIsValid(InfofileOrRecycleFolder) then
2043
  if RecyclerIsValid(InfofileOrRecycleFolder) then
2042
  begin
2044
  begin
2043
    result := extractfilepath(InfofileOrRecycleFolder) +
2045
    result := extractfilepath(InfofileOrRecycleFolder) +
2044
      RecyclerCurrentFilename(InfofileOrRecycleFolder, id);
2046
      RecyclerCurrentFilename(InfofileOrRecycleFolder, id);
2045
  end
2047
  end
2046
  else
2048
  else
2047
    result := '';
2049
    result := '';
2048
end;
2050
end;
2049
 
2051
 
2050
////////////////////////////////////////////////////////////////////////////////
2052
////////////////////////////////////////////////////////////////////////////////
2051
 
2053
 
2052
function RecyclerRemoveItem(drive: char; UserSID: string; fileid: string): boolean; overload;
2054
function RecyclerRemoveItem(drive: char; UserSID: string; fileid: string): boolean; overload;
2053
var
2055
var
2054
  tmp: string;
2056
  tmp: string;
2055
begin
2057
begin
2056
  tmp := RecyclerCurrentFilenameAndPath(drive, UserSID, fileid);
2058
  tmp := RecyclerCurrentFilenameAndPath(drive, UserSID, fileid);
2057
  if fileexists(tmp) then
2059
  if fileexists(tmp) then
2058
  begin
2060
  begin
2059
    deletefile(tmp);
2061
    deletefile(tmp);
2060
    result := fileexists(tmp);
2062
    result := fileexists(tmp);
2061
  end
2063
  end
2062
  else
2064
  else
2063
  begin
2065
  begin
2064
    directoryexists(tmp);
2066
    directoryexists(tmp);
2065
    result := directoryexists(tmp);
2067
    result := directoryexists(tmp);
2066
  end;
2068
  end;
2067
end;
2069
end;
2068
 
2070
 
2069
function RecyclerRemoveItem(drive: char; fileid: string): boolean; overload;
2071
function RecyclerRemoveItem(drive: char; fileid: string): boolean; overload;
2070
begin
2072
begin
2071
  result := RecyclerRemoveItem(drive, '', fileid);
2073
  result := RecyclerRemoveItem(drive, '', fileid);
2072
end;
2074
end;
2073
 
2075
 
2074
function RecyclerRemoveItem(InfofileOrRecycleFolder: string; id: string): boolean; overload;
2076
function RecyclerRemoveItem(InfofileOrRecycleFolder: string; id: string): boolean; overload;
2075
var
2077
var
2076
  tmp: string;
2078
  tmp: string;
2077
begin
2079
begin
2078
  tmp := RecyclerCurrentFilenameAndPath(InfofileOrRecycleFolder, id);
2080
  tmp := RecyclerCurrentFilenameAndPath(InfofileOrRecycleFolder, id);
2079
  if fileexists(tmp) then
2081
  if fileexists(tmp) then
2080
  begin
2082
  begin
2081
    deletefile(tmp);
2083
    deletefile(tmp);
2082
    result := fileexists(tmp);
2084
    result := fileexists(tmp);
2083
  end
2085
  end
2084
  else
2086
  else
2085
  begin
2087
  begin
2086
    _DeleteDirectory(tmp);
2088
    _DeleteDirectory(tmp);
2087
    result := directoryexists(tmp);
2089
    result := directoryexists(tmp);
2088
  end;
2090
  end;
2089
end;
2091
end;
2090
 
2092
 
2091
procedure RecyclerGetAllRecyclerDrives(result: TStringList);
2093
procedure RecyclerGetAllRecyclerDrives(result: TStringList);
2092
var
2094
var
2093
  Drive: char;
2095
  Drive: char;
2094
begin
2096
begin
2095
  for Drive := 'A' to 'Z' do
2097
  for Drive := 'A' to 'Z' do
2096
  begin
2098
  begin
2097
    if RecyclerIsPossible(Drive) and RecyclerIsValid(Drive) then
2099
    if RecyclerIsPossible(Drive) and RecyclerIsValid(Drive) then
2098
    begin
2100
    begin
2099
      result.Add(Drive);
2101
      result.Add(Drive);
2100
    end;
2102
    end;
2101
  end;
2103
  end;
2102
end;
2104
end;
2103
 
2105
 
2104
////////////////////////////////////////////////////////////////////////////////
2106
////////////////////////////////////////////////////////////////////////////////
2105
 
2107
 
2106
// http://www.dsdt.info/tipps/?id=176
2108
// http://www.dsdt.info/tipps/?id=176
2107
function RecyclerEmptyRecycleBin(flags: cardinal): boolean; overload;
2109
function RecyclerEmptyRecycleBin(flags: cardinal): boolean; overload;
2108
type
2110
type
2109
  TSHEmptyRecycleBin = function (Wnd: HWND;
2111
  TSHEmptyRecycleBin = function (Wnd: HWND;
2110
                                 pszRootPath: PChar;
2112
                                 pszRootPath: PChar;
2111
                                 dwFlags: DWORD):
2113
                                 dwFlags: DWORD):
2112
                                 HRESULT; stdcall;
2114
                                 HRESULT; stdcall;
2113
var
2115
var
2114
  PSHEmptyRecycleBin: TSHEmptyRecycleBin;
2116
  PSHEmptyRecycleBin: TSHEmptyRecycleBin;
2115
  LibHandle: THandle;
2117
  LibHandle: THandle;
2116
const
2118
const
2117
  C_SHEmptyRecycleBinA = 'SHEmptyRecycleBinA';
2119
  C_SHEmptyRecycleBinA = 'SHEmptyRecycleBinA';
2118
begin
2120
begin
2119
  result := true;
2121
  result := true;
2120
  LibHandle := LoadLibrary(shell32) ;
2122
  LibHandle := LoadLibrary(shell32) ;
2121
  try
2123
  try
2122
    if LibHandle <> 0 then
2124
    if LibHandle <> 0 then
2123
    begin
2125
    begin
2124
      @PSHEmptyRecycleBin:= GetProcAddress(LibHandle, C_SHEmptyRecycleBinA);
2126
      @PSHEmptyRecycleBin:= GetProcAddress(LibHandle, C_SHEmptyRecycleBinA);
2125
      if @PSHEmptyRecycleBin <> nil then
2127
      if @PSHEmptyRecycleBin <> nil then
2126
      begin
2128
      begin
2127
        PSHEmptyRecycleBin(hInstance, nil, flags);
2129
        PSHEmptyRecycleBin(hInstance, nil, flags);
2128
      end
2130
      end
2129
      else
2131
      else
2130
        result := false;
2132
        result := false;
2131
    end
2133
    end
2132
    else
2134
    else
2133
      result := false;
2135
      result := false;
2134
  finally
2136
  finally
2135
    @PSHEmptyRecycleBin := nil;
2137
    @PSHEmptyRecycleBin := nil;
2136
    FreeLibrary(LibHandle);
2138
    FreeLibrary(LibHandle);
2137
  end;
2139
  end;
2138
end;
2140
end;
2139
 
2141
 
2140
function RecyclerEmptyRecycleBin(sound, progress, confirmation: boolean): boolean; overload;
2142
function RecyclerEmptyRecycleBin(sound, progress, confirmation: boolean): boolean; overload;
2141
const
2143
const
2142
  SHERB_NOCONFIRMATION = $00000001;
2144
  SHERB_NOCONFIRMATION = $00000001;
2143
  SHERB_NOPROGRESSUI   = $00000002;
2145
  SHERB_NOPROGRESSUI   = $00000002;
2144
  SHERB_NOSOUND        = $00000004;
2146
  SHERB_NOSOUND        = $00000004;
2145
var
2147
var
2146
  flags: cardinal;
2148
  flags: cardinal;
2147
begin
2149
begin
2148
  flags := 0;
2150
  flags := 0;
2149
 
2151
 
2150
  if not progress then
2152
  if not progress then
2151
    flags := flags or SHERB_NOPROGRESSUI;
2153
    flags := flags or SHERB_NOPROGRESSUI;
2152
  if not confirmation then
2154
  if not confirmation then
2153
    flags := flags or SHERB_NOCONFIRMATION;
2155
    flags := flags or SHERB_NOCONFIRMATION;
2154
  if not sound then
2156
  if not sound then
2155
    flags := flags or SHERB_NOSOUND;
2157
    flags := flags or SHERB_NOSOUND;
2156
 
2158
 
2157
  result := RecyclerEmptyRecycleBin(flags);
2159
  result := RecyclerEmptyRecycleBin(flags);
2158
end;
2160
end;
2159
 
2161
 
2160
////////////////////////////////////////////////////////////////////////////////
2162
////////////////////////////////////////////////////////////////////////////////
2161
 
2163
 
2162
// Template
2164
// Template
2163
// http://www.dsdt.info/tipps/?id=116
2165
// http://www.dsdt.info/tipps/?id=116
2164
function RecyclerAddFileOrFolder(FileOrFolder: string; confirmation: boolean): boolean; overload;
2166
function RecyclerAddFileOrFolder(FileOrFolder: string; confirmation: boolean): boolean; overload;
2165
var
2167
var
2166
  Operation: TSHFileOpStruct;
2168
  Operation: TSHFileOpStruct;
2167
begin
2169
begin
2168
  with Operation do
2170
  with Operation do
2169
  begin
2171
  begin
2170
    Wnd := hInstance; // OK?
2172
    Wnd := hInstance; // OK?
2171
    wFunc := FO_DELETE;
2173
    wFunc := FO_DELETE;
2172
    pFrom := PChar(FileOrFolder + #0);
2174
    pFrom := PChar(FileOrFolder + #0);
2173
    pTo := nil;
2175
    pTo := nil;
2174
    fFlags := FOF_ALLOWUNDO;
2176
    fFlags := FOF_ALLOWUNDO;
2175
    if not confirmation then fFlags := fFlags or FOF_NOCONFIRMATION;
2177
    if not confirmation then fFlags := fFlags or FOF_NOCONFIRMATION;
2176
  end;
2178
  end;
2177
  Result := SHFileOperation(Operation) = 0;
2179
  Result := SHFileOperation(Operation) = 0;
2178
end;
2180
end;
2179
 
2181
 
2180
function RecyclerAddFileOrFolder(FileOrFolder: string): boolean; overload;
2182
function RecyclerAddFileOrFolder(FileOrFolder: string): boolean; overload;
2181
begin
2183
begin
2182
  result := RecyclerAddFileOrFolder(FileOrFolder, false);
2184
  result := RecyclerAddFileOrFolder(FileOrFolder, false);
2183
end;
2185
end;
2184
 
2186
 
2185
function RecyclerConfirmationDialogEnabled: boolean;
2187
function RecyclerConfirmationDialogEnabled: boolean;
2186
var
2188
var
2187
  gp: GPOLICYBOOL;
2189
  gp: GPOLICYBOOL;
2188
begin
2190
begin
2189
  gp := RecyclerGroupPolicyConfirmFileDelete;
2191
  gp := RecyclerGroupPolicyConfirmFileDelete;
2190
  if gp <> gpUndefined then
2192
  if gp <> gpUndefined then
2191
  begin
2193
  begin
2192
    result := gp = gpEnabled;
2194
    result := gp = gpEnabled;
2193
  end
2195
  end
2194
  else
2196
  else
2195
  begin
2197
  begin
2196
    result := RecyclerShellStateConfirmationDialogEnabled;
2198
    result := RecyclerShellStateConfirmationDialogEnabled;
2197
  end;
2199
  end;
2198
end;
2200
end;
2199
 
2201
 
2200
function RecyclerShellStateConfirmationDialogEnabled: boolean;
2202
function RecyclerShellStateConfirmationDialogEnabled: boolean;
2201
type
2203
type
2202
  TSHGetSettings = procedure (var lpss: SHELLSTATE; dwMask: DWORD) stdcall;
2204
  TSHGetSettings = procedure (var lpss: SHELLSTATE; dwMask: DWORD) stdcall;
2203
const
2205
const
2204
  C_SHGetSettings = 'SHGetSettings';
2206
  C_SHGetSettings = 'SHGetSettings';
2205
var
2207
var
2206
  lpss: SHELLSTATE;
2208
  lpss: SHELLSTATE;
2207
  bNoConfirmRecycle: boolean;
2209
  bNoConfirmRecycle: boolean;
2208
 
2210
 
2209
  PSHGetSettings: TSHGetSettings;
2211
  PSHGetSettings: TSHGetSettings;
2210
  RBHandle: THandle;
2212
  RBHandle: THandle;
2211
 
2213
 
2212
  reg: TRegistry;
2214
  reg: TRegistry;
2213
  rbuf: array[0..255] of byte;
2215
  rbuf: array[0..255] of byte;
2214
begin
2216
begin
2215
  PSHGetSettings := nil;
2217
  PSHGetSettings := nil;
2216
  result := false; // Avoid warning message
2218
  result := false; // Avoid warning message
2217
 
2219
 
2218
  RBHandle := LoadLibrary(shell32);
2220
  RBHandle := LoadLibrary(shell32);
2219
  if(RBHandle <> 0) then
2221
  if(RBHandle <> 0) then
2220
  begin
2222
  begin
2221
    PSHGetSettings := GetProcAddress(RBHandle, C_SHGetSettings);
2223
    PSHGetSettings := GetProcAddress(RBHandle, C_SHGetSettings);
2222
    if (@PSHGetSettings = nil) then
2224
    if (@PSHGetSettings = nil) then
2223
    begin
2225
    begin
2224
      FreeLibrary(RBHandle);
2226
      FreeLibrary(RBHandle);
2225
      RBHandle := 0;
2227
      RBHandle := 0;
2226
    end;
2228
    end;
2227
  end;
2229
  end;
2228
 
2230
 
2229
  if (RBHandle <> 0) and (Assigned(PSHGetSettings)) then
2231
  if (RBHandle <> 0) and (Assigned(PSHGetSettings)) then
2230
  begin
2232
  begin
2231
    ZeroMemory(@lpss, SizeOf(lpss));
2233
    ZeroMemory(@lpss, SizeOf(lpss));
2232
    PSHGetSettings(lpss, SSF_NOCONFIRMRECYCLE);
2234
    PSHGetSettings(lpss, SSF_NOCONFIRMRECYCLE);
2233
    // bNoConfirmRecycle := (lpss.Flags1 and 4) = 4; // fNoConfirmRecycle
2235
    // bNoConfirmRecycle := (lpss.Flags1 and 4) = 4; // fNoConfirmRecycle
2234
    bNoConfirmRecycle := GetByteBit(lpss.Flags1, 2);
2236
    bNoConfirmRecycle := GetByteBit(lpss.Flags1, 2);
2235
 
2237
 
2236
    result := not bNoConfirmRecycle;
2238
    result := not bNoConfirmRecycle;
2237
  end
2239
  end
2238
  else
2240
  else
2239
  begin
2241
  begin
2240
    reg := TRegistry.Create;
2242
    reg := TRegistry.Create;
2241
    try
2243
    try
2242
      // API function call failed. Probably because Windows is too old.
2244
      // API function call failed. Probably because Windows is too old.
2243
      // Try to read out from registry.
2245
      // Try to read out from registry.
2244
      // The 3rd bit of the 5th byte of "ShellState" is the value
2246
      // The 3rd bit of the 5th byte of "ShellState" is the value
2245
      // of "fNoConfirmRecycle".
2247
      // of "fNoConfirmRecycle".
2246
 
2248
 
2247
      reg.RootKey := HKEY_CURRENT_USER;
2249
      reg.RootKey := HKEY_CURRENT_USER;
2248
      if (reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Explorer')) then
2250
      if (reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Explorer')) then
2249
      begin
2251
      begin
2250
        ZeroMemory(@rbuf, SizeOf(rbuf));
2252
        ZeroMemory(@rbuf, SizeOf(rbuf));
2251
        reg.ReadBinaryData('ShellState', rbuf, SizeOf(rbuf));
2253
        reg.ReadBinaryData('ShellState', rbuf, SizeOf(rbuf));
2252
 
2254
 
2253
        // Lese 3tes Bit vom 5ten Byte
2255
        // Lese 3tes Bit vom 5ten Byte
2254
        // bNoConfirmRecycle := ((rbuf[4] and 4) = 4);
2256
        // bNoConfirmRecycle := ((rbuf[4] and 4) = 4);
2255
        bNoConfirmRecycle := GetByteBit(rbuf[4], 2);
2257
        bNoConfirmRecycle := GetByteBit(rbuf[4], 2);
2256
        result := not bNoConfirmRecycle;
2258
        result := not bNoConfirmRecycle;
2257
 
2259
 
2258
        reg.CloseKey;
2260
        reg.CloseKey;
2259
      end
2261
      end
2260
      else
2262
      else
2261
      begin
2263
      begin
2262
        raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_NOT_CALLABLE, [C_SHGetSettings])]);
2264
        raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_NOT_CALLABLE, [C_SHGetSettings])]);
2263
      end;
2265
      end;
2264
    finally
2266
    finally
2265
      reg.Free;
2267
      reg.Free;
2266
    end;
2268
    end;
2267
  end;
2269
  end;
2268
 
2270
 
2269
  if (RBHandle <> 0) then FreeLibrary(RBHandle);
2271
  if (RBHandle <> 0) then FreeLibrary(RBHandle);
2270
end;
2272
end;
2271
 
2273
 
2272
procedure RecyclerConfirmationDialogSetEnabled(NewSetting: boolean);
2274
procedure RecyclerConfirmationDialogSetEnabled(NewSetting: boolean);
2273
type
2275
type
2274
  TSHGetSetSettings = procedure (var lpss: SHELLSTATE; dwMask: DWORD; bSet: BOOL) stdcall;
2276
  TSHGetSetSettings = procedure (var lpss: SHELLSTATE; dwMask: DWORD; bSet: BOOL) stdcall;
2275
const
2277
const
2276
  C_SHGetSetSettings = 'SHGetSetSettings';
2278
  C_SHGetSetSettings = 'SHGetSetSettings';
2277
var
2279
var
2278
  lpss: SHELLSTATE;
2280
  lpss: SHELLSTATE;
2279
 
2281
 
2280
  PSHGetSetSettings: TSHGetSetSettings;
2282
  PSHGetSetSettings: TSHGetSetSettings;
2281
  RBHandle: THandle;
2283
  RBHandle: THandle;
2282
 
2284
 
2283
  reg: TRegistry;
2285
  reg: TRegistry;
2284
  rbuf: array[0..255] of byte;
2286
  rbuf: array[0..255] of byte;
2285
 
2287
 
2286
  dwResult: DWORD;
2288
  //dwResult: DWORD;
-
 
2289
  lpdwResult: PDWORD_PTR;
2287
begin
2290
begin
2288
  PSHGetSetSettings := nil;
2291
  PSHGetSetSettings := nil;
-
 
2292
  lpdwResult := nil;
2289
 
2293
 
2290
  RBHandle := LoadLibrary(shell32);
2294
  RBHandle := LoadLibrary(shell32);
2291
  if(RBHandle <> 0) then
2295
  if(RBHandle <> 0) then
2292
  begin
2296
  begin
2293
    PSHGetSetSettings := GetProcAddress(RBHandle, C_SHGetSetSettings);
2297
    PSHGetSetSettings := GetProcAddress(RBHandle, C_SHGetSetSettings);
2294
    if (@PSHGetSetSettings = nil) then
2298
    if (@PSHGetSetSettings = nil) then
2295
    begin
2299
    begin
2296
      FreeLibrary(RBHandle);
2300
      FreeLibrary(RBHandle);
2297
      RBHandle := 0;
2301
      RBHandle := 0;
2298
    end;
2302
    end;
2299
  end;
2303
  end;
2300
 
2304
 
2301
  if (RBHandle <> 0) and (Assigned(PSHGetSetSettings)) then
2305
  if (RBHandle <> 0) and (Assigned(PSHGetSetSettings)) then
2302
  begin
2306
  begin
2303
    ZeroMemory(@lpss, SizeOf(lpss));
2307
    ZeroMemory(@lpss, SizeOf(lpss));
2304
    PSHGetSetSettings(lpss, SSF_NOCONFIRMRECYCLE, false); // Get
2308
    PSHGetSetSettings(lpss, SSF_NOCONFIRMRECYCLE, false); // Get
2305
    lpss.Flags1 := SetByteBit(lpss.Flags1, 2, NewSetting);
2309
    lpss.Flags1 := SetByteBit(lpss.Flags1, 2, NewSetting);
2306
    PSHGetSetSettings(lpss, SSF_NOCONFIRMRECYCLE, true); // Set
2310
    PSHGetSetSettings(lpss, SSF_NOCONFIRMRECYCLE, true); // Set
2307
 
2311
 
2308
    SendMessageTimeout (
2312
    SendMessageTimeout (
2309
      HWND_BROADCAST, WM_SETTINGCHANGE,
2313
      HWND_BROADCAST, WM_SETTINGCHANGE,
2310
      0, lParam (pChar ('ShellState')),
2314
      0, lParam (pChar ('ShellState')),
2311
      SMTO_ABORTIFHUNG, 5000, dwResult
2315
      SMTO_ABORTIFHUNG, 5000, lpdwResult(*dwResult*)
2312
    );
2316
    );
2313
  end
2317
  end
2314
  else
2318
  else
2315
  begin
2319
  begin
2316
    reg := TRegistry.Create;
2320
    reg := TRegistry.Create;
2317
    try
2321
    try
2318
      // API function call failed. Probably because Windows is too old.
2322
      // API function call failed. Probably because Windows is too old.
2319
      // Try to read out from registry.
2323
      // Try to read out from registry.
2320
      // The 3rd bit of the 5th byte of "ShellState" is the value
2324
      // The 3rd bit of the 5th byte of "ShellState" is the value
2321
      // of "fNoConfirmRecycle".
2325
      // of "fNoConfirmRecycle".
2322
 
2326
 
2323
      reg.RootKey := HKEY_CURRENT_USER;
2327
      reg.RootKey := HKEY_CURRENT_USER;
2324
      if (reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Explorer', false)) then
2328
      if (reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Explorer', false)) then
2325
      begin
2329
      begin
2326
        ZeroMemory(@rbuf, SizeOf(rbuf));
2330
        ZeroMemory(@rbuf, SizeOf(rbuf));
2327
        reg.ReadBinaryData('ShellState', rbuf, SizeOf(rbuf)); // Get
2331
        reg.ReadBinaryData('ShellState', rbuf, SizeOf(rbuf)); // Get
2328
        rbuf[4] := SetByteBit(rbuf[4], 2, NewSetting);
2332
        rbuf[4] := SetByteBit(rbuf[4], 2, NewSetting);
2329
        reg.WriteBinaryData('ShellState', rbuf, SizeOf(rbuf)); // Set
2333
        reg.WriteBinaryData('ShellState', rbuf, SizeOf(rbuf)); // Set
2330
 
2334
 
2331
        SendMessageTimeout (
2335
        SendMessageTimeout (
2332
          HWND_BROADCAST, WM_SETTINGCHANGE,
2336
          HWND_BROADCAST, WM_SETTINGCHANGE,
2333
          0, lParam (pChar ('ShellState')),
2337
          0, lParam (pChar ('ShellState')),
2334
          SMTO_ABORTIFHUNG, 5000, dwResult
2338
          SMTO_ABORTIFHUNG, 5000, lpdwResult(*dwResult*)
2335
        );
2339
        );
2336
 
2340
 
2337
        reg.CloseKey;
2341
        reg.CloseKey;
2338
      end
2342
      end
2339
      else
2343
      else
2340
      begin
2344
      begin
2341
        raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_NOT_CALLABLE, [C_SHGetSetSettings])]);
2345
        raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_NOT_CALLABLE, [C_SHGetSetSettings])]);
2342
      end;
2346
      end;
2343
    finally
2347
    finally
2344
      reg.Free;
2348
      reg.Free;
2345
    end;
2349
    end;
2346
  end;
2350
  end;
2347
 
2351
 
2348
  if (RBHandle <> 0) then FreeLibrary(RBHandle);
2352
  if (RBHandle <> 0) then FreeLibrary(RBHandle);
2349
end;
2353
end;
2350
 
2354
 
2351
function RecyclerGetCurrentIconString: string;
2355
function RecyclerGetCurrentIconString: string;
2352
begin
2356
begin
2353
  if RecyclerIsEmpty then
2357
  if RecyclerIsEmpty then
2354
    result := RecyclerGetEmptyIconString
2358
    result := RecyclerGetEmptyIconString
2355
  else
2359
  else
2356
    result := RecyclerGetFullIconString;
2360
    result := RecyclerGetFullIconString;
2357
end;
2361
end;
2358
 
2362
 
2359
function RecyclerGetDefaultIconString: string;
2363
function RecyclerGetDefaultIconString: string;
2360
var
2364
var
2361
  reg: TRegistry;
2365
  reg: TRegistry;
2362
begin
2366
begin
2363
  // Please note: The "default" icon is not always the icon of the
2367
  // Please note: The "default" icon is not always the icon of the
2364
  // current recycle bin in its current state (full, empty)
2368
  // current recycle bin in its current state (full, empty)
2365
  // At Windows 95b, the registry value actually did change every time the
2369
  // At Windows 95b, the registry value actually did change every time the
2366
  // recycle bin state did change, but at Windows 2000 I could not see any
2370
  // recycle bin state did change, but at Windows 2000 I could not see any
2367
  // update, even after reboot. So, the registry value is possible fixed as
2371
  // update, even after reboot. So, the registry value is possible fixed as
2368
  // default = empty on newer OS versions.
2372
  // default = empty on newer OS versions.
2369
 
2373
 
2370
  reg := TRegistry.Create;
2374
  reg := TRegistry.Create;
2371
  try
2375
  try
2372
    reg.RootKey := HKEY_CLASSES_ROOT;
2376
    reg.RootKey := HKEY_CLASSES_ROOT;
2373
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID+'\DefaultIcon') then
2377
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID+'\DefaultIcon') then
2374
    begin
2378
    begin
2375
      result := reg.ReadString('');
2379
      result := reg.ReadString('');
2376
      reg.CloseKey;
2380
      reg.CloseKey;
2377
    end;
2381
    end;
2378
  finally
2382
  finally
2379
    reg.Free;
2383
    reg.Free;
2380
  end;
2384
  end;
2381
end;
2385
end;
2382
 
2386
 
2383
function RecyclerGetEmptyIconString: string;
2387
function RecyclerGetEmptyIconString: string;
2384
var
2388
var
2385
  reg: TRegistry;
2389
  reg: TRegistry;
2386
begin
2390
begin
2387
  reg := TRegistry.Create;
2391
  reg := TRegistry.Create;
2388
  try
2392
  try
2389
    reg.RootKey := HKEY_CLASSES_ROOT;
2393
    reg.RootKey := HKEY_CLASSES_ROOT;
2390
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID+'\DefaultIcon') then
2394
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID+'\DefaultIcon') then
2391
    begin
2395
    begin
2392
      result := reg.ReadString('Empty');
2396
      result := reg.ReadString('Empty');
2393
      reg.CloseKey;
2397
      reg.CloseKey;
2394
    end;
2398
    end;
2395
  finally
2399
  finally
2396
    reg.Free;
2400
    reg.Free;
2397
  end;
2401
  end;
2398
end;
2402
end;
2399
 
2403
 
2400
function RecyclerGetFullIconString: string;
2404
function RecyclerGetFullIconString: string;
2401
var
2405
var
2402
  reg: TRegistry;
2406
  reg: TRegistry;
2403
begin
2407
begin
2404
  reg := TRegistry.Create;
2408
  reg := TRegistry.Create;
2405
  try
2409
  try
2406
    reg.RootKey := HKEY_CLASSES_ROOT;
2410
    reg.RootKey := HKEY_CLASSES_ROOT;
2407
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID+'\DefaultIcon') then
2411
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID+'\DefaultIcon') then
2408
    begin
2412
    begin
2409
      result := reg.ReadString('Full');
2413
      result := reg.ReadString('Full');
2410
      reg.CloseKey;
2414
      reg.CloseKey;
2411
    end;
2415
    end;
2412
  finally
2416
  finally
2413
    reg.Free;
2417
    reg.Free;
2414
  end;
2418
  end;
2415
end;
2419
end;
2416
 
2420
 
2417
function RecyclerGetName: string;
2421
function RecyclerGetName: string;
2418
var
2422
var
2419
  reg: TRegistry;
2423
  reg: TRegistry;
2420
begin
2424
begin
2421
  // Windows 95b:
2425
  // Windows 95b:
2422
  // Change of CLSID\{645FF040-5081-101B-9F08-00AA002F954E} will change the desktop name of the recycle bin.
2426
  // Change of CLSID\{645FF040-5081-101B-9F08-00AA002F954E} will change the desktop name of the recycle bin.
2423
 
2427
 
2424
  // Windows 2000: If LocalizedString is available, the 3rd argument will be parsed
2428
  // Windows 2000: If LocalizedString is available, the 3rd argument will be parsed
2425
  // (if the third argument will removed, it will be read out from the DLL resource string automatically)
2429
  // (if the third argument will removed, it will be read out from the DLL resource string automatically)
2426
 
2430
 
2427
  reg := TRegistry.Create;
2431
  reg := TRegistry.Create;
2428
  try
2432
  try
2429
    reg.RootKey := HKEY_CLASSES_ROOT;
2433
    reg.RootKey := HKEY_CLASSES_ROOT;
2430
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID) then
2434
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID) then
2431
    begin
2435
    begin
2432
      if reg.ValueExists('LocalizedString') then
2436
      if reg.ValueExists('LocalizedString') then
2433
      begin
2437
      begin
2434
        result := reg.ReadString('LocalizedString');
2438
        result := reg.ReadString('LocalizedString');
2435
        result := _DecodeReferenceString(result);
2439
        result := _DecodeReferenceString(result);
2436
      end
2440
      end
2437
      else
2441
      else
2438
      begin
2442
      begin
2439
        result := reg.ReadString('');
2443
        result := reg.ReadString('');
2440
      end;
2444
      end;
2441
 
2445
 
2442
      reg.CloseKey;
2446
      reg.CloseKey;
2443
    end;
2447
    end;
2444
  finally
2448
  finally
2445
    reg.Free;
2449
    reg.Free;
2446
  end;
2450
  end;
2447
end;
2451
end;
2448
 
2452
 
2449
function RecyclerGetInfoTip: string;
2453
function RecyclerGetInfoTip: string;
2450
var
2454
var
2451
  reg: TRegistry;
2455
  reg: TRegistry;
2452
begin
2456
begin
2453
  // Not available in some older versions of Windows
2457
  // Not available in some older versions of Windows
2454
 
2458
 
2455
  reg := TRegistry.Create;
2459
  reg := TRegistry.Create;
2456
  try
2460
  try
2457
    reg.RootKey := HKEY_CLASSES_ROOT;
2461
    reg.RootKey := HKEY_CLASSES_ROOT;
2458
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID) then
2462
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID) then
2459
    begin
2463
    begin
2460
      result := reg.ReadString('InfoTip');
2464
      result := reg.ReadString('InfoTip');
2461
      result := _DecodeReferenceString(result);
2465
      result := _DecodeReferenceString(result);
2462
 
2466
 
2463
      reg.CloseKey;
2467
      reg.CloseKey;
2464
    end;
2468
    end;
2465
  finally
2469
  finally
2466
    reg.Free;
2470
    reg.Free;
2467
  end;
2471
  end;
2468
end;
2472
end;
2469
 
2473
 
2470
function RecyclerGetIntroText: string;
2474
function RecyclerGetIntroText: string;
2471
var
2475
var
2472
  reg: TRegistry;
2476
  reg: TRegistry;
2473
begin
2477
begin
2474
  // Not available in some older versions of Windows
2478
  // Not available in some older versions of Windows
2475
 
2479
 
2476
  reg := TRegistry.Create;
2480
  reg := TRegistry.Create;
2477
  try
2481
  try
2478
    reg.RootKey := HKEY_CLASSES_ROOT;
2482
    reg.RootKey := HKEY_CLASSES_ROOT;
2479
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID) then
2483
    if reg.OpenKeyReadOnly('CLSID\'+RECYCLER_CLSID) then
2480
    begin
2484
    begin
2481
      result := reg.ReadString('IntroText');
2485
      result := reg.ReadString('IntroText');
2482
      result := _DecodeReferenceString(result);
2486
      result := _DecodeReferenceString(result);
2483
 
2487
 
2484
      reg.CloseKey;
2488
      reg.CloseKey;
2485
    end;
2489
    end;
2486
  finally
2490
  finally
2487
    reg.Free;
2491
    reg.Free;
2488
  end;
2492
  end;
2489
end;
2493
end;
2490
 
2494
 
2491
function RecyclerEmptyEventGetName: string;
2495
function RecyclerEmptyEventGetName: string;
2492
var
2496
var
2493
  reg: TRegistry;
2497
  reg: TRegistry;
2494
begin
2498
begin
2495
  reg := TRegistry.Create;
2499
  reg := TRegistry.Create;
2496
  try
2500
  try
2497
    reg.RootKey := HKEY_CURRENT_USER;
2501
    reg.RootKey := HKEY_CURRENT_USER;
2498
    if reg.OpenKeyReadOnly('AppEvents\EventLabels\EmptyRecycleBin') then
2502
    if reg.OpenKeyReadOnly('AppEvents\EventLabels\EmptyRecycleBin') then
2499
    begin
2503
    begin
2500
      result := reg.ReadString('');
2504
      result := reg.ReadString('');
2501
      reg.CloseKey;
2505
      reg.CloseKey;
2502
    end;
2506
    end;
2503
  finally
2507
  finally
2504
    reg.Free;
2508
    reg.Free;
2505
  end;
2509
  end;
2506
end;
2510
end;
2507
 
2511
 
2508
function RecyclerEmptyEventGetCurrentSound: string;
2512
function RecyclerEmptyEventGetCurrentSound: string;
2509
begin
2513
begin
2510
  result := RecyclerEmptyEventGetSound('.Current');
2514
  result := RecyclerEmptyEventGetSound('.Current');
2511
end;
2515
end;
2512
 
2516
 
2513
function RecyclerEmptyEventGetDefaultSound: string;
2517
function RecyclerEmptyEventGetDefaultSound: string;
2514
begin
2518
begin
2515
  result := RecyclerEmptyEventGetSound('.Default');
2519
  result := RecyclerEmptyEventGetSound('.Default');
2516
end;
2520
end;
2517
 
2521
 
2518
procedure RecyclerEmptyEventGetSoundCategories(AStringList: TStringList);
2522
procedure RecyclerEmptyEventGetSoundCategories(AStringList: TStringList);
2519
var
2523
var
2520
  reg: TRegistry;
2524
  reg: TRegistry;
2521
begin
2525
begin
2522
  reg := TRegistry.Create;
2526
  reg := TRegistry.Create;
2523
  try
2527
  try
2524
    reg.RootKey := HKEY_CURRENT_USER;
2528
    reg.RootKey := HKEY_CURRENT_USER;
2525
    if reg.OpenKeyReadOnly('AppEvents\Schemes\Apps\Explorer\EmptyRecycleBin') then
2529
    if reg.OpenKeyReadOnly('AppEvents\Schemes\Apps\Explorer\EmptyRecycleBin') then
2526
    begin
2530
    begin
2527
      reg.GetKeyNames(AStringList);
2531
      reg.GetKeyNames(AStringList);
2528
      reg.CloseKey;
2532
      reg.CloseKey;
2529
    end;
2533
    end;
2530
  finally
2534
  finally
2531
    reg.Free;
2535
    reg.Free;
2532
  end;
2536
  end;
2533
end;
2537
end;
2534
 
2538
 
2535
function RecyclerEmptyEventGetSound(ACategory: string): string;
2539
function RecyclerEmptyEventGetSound(ACategory: string): string;
2536
var
2540
var
2537
  reg: TRegistry;
2541
  reg: TRegistry;
2538
resourcestring
2542
resourcestring
2539
  LNG_SND_EVENT_CAT_ERROR = 'The category "%s" is not available for the notification event "%s".';
2543
  LNG_SND_EVENT_CAT_ERROR = 'The category "%s" is not available for the notification event "%s".';
2540
begin
2544
begin
2541
  // Outputs an filename or empty string for no sound defined.
2545
  // Outputs an filename or empty string for no sound defined.
2542
 
2546
 
2543
  reg := TRegistry.Create;
2547
  reg := TRegistry.Create;
2544
  try
2548
  try
2545
    reg.RootKey := HKEY_CURRENT_USER;
2549
    reg.RootKey := HKEY_CURRENT_USER;
2546
    if reg.OpenKeyReadOnly('AppEvents\Schemes\Apps\Explorer\EmptyRecycleBin') then
2550
    if reg.OpenKeyReadOnly('AppEvents\Schemes\Apps\Explorer\EmptyRecycleBin') then
2547
    begin
2551
    begin
2548
      if reg.OpenKeyReadOnly(ACategory) then
2552
      if reg.OpenKeyReadOnly(ACategory) then
2549
      begin
2553
      begin
2550
        result := reg.ReadString('');
2554
        result := reg.ReadString('');
2551
        reg.CloseKey;
2555
        reg.CloseKey;
2552
      end
2556
      end
2553
      else
2557
      else
2554
        raise EEventCategoryNotDefined.CreateFmt(LNG_SND_EVENT_CAT_ERROR, [ACategory, 'EmptyRecycleBin']);
2558
        raise EEventCategoryNotDefined.CreateFmt(LNG_SND_EVENT_CAT_ERROR, [ACategory, 'EmptyRecycleBin']);
2555
      reg.CloseKey;
2559
      reg.CloseKey;
2556
    end;
2560
    end;
2557
  finally
2561
  finally
2558
    reg.Free;
2562
    reg.Free;
2559
  end;
2563
  end;
2560
end;
2564
end;
2561
 
2565
 
2562
function RecyclerGlobalGetPercentUsage: integer;
2566
function RecyclerGlobalGetPercentUsage: integer;
2563
var
2567
var
2564
  reg: TRegistry;
2568
  reg: TRegistry;
2565
  dump: string;
2569
  dump: string;
2566
const
2570
const
2567
  RES_DEFAULT = 10;
2571
  RES_DEFAULT = 10;
2568
begin
2572
begin
2569
  result := -1;
2573
  result := -1;
2570
 
2574
 
2571
  reg := TRegistry.Create;
2575
  reg := TRegistry.Create;
2572
  try
2576
  try
2573
    reg.RootKey := HKEY_LOCAL_MACHINE;
2577
    reg.RootKey := HKEY_LOCAL_MACHINE;
2574
 
2578
 
2575
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
2579
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
2576
    begin
2580
    begin
2577
      if reg.ValueExists('Percent') then
2581
      if reg.ValueExists('Percent') then
2578
      begin
2582
      begin
2579
        // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
2583
        // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
2580
 
2584
 
2581
        result := reg.ReadInteger('Percent');
2585
        result := reg.ReadInteger('Percent');
2582
      end
2586
      end
2583
      else if reg.ValueExists('PurgeInfo') then
2587
      else if reg.ValueExists('PurgeInfo') then
2584
      begin
2588
      begin
2585
        // Windows 95 - Verschlüsselte Informationen liegen in PurgeInfo
2589
        // Windows 95 - Verschlüsselte Informationen liegen in PurgeInfo
2586
 
2590
 
2587
        dump := _registryReadDump(reg, 'PurgeInfo');
2591
        dump := _registryReadDump(reg, 'PurgeInfo');
2588
        result := Ord(dump[63]);
2592
        result := Ord(dump[63]);
2589
      end
2593
      end
2590
      else
2594
      else
2591
      begin
2595
      begin
2592
        // Windows 95 - Standardwerte sind gegeben, deswegen existiert kein PurgeInfo
2596
        // Windows 95 - Standardwerte sind gegeben, deswegen existiert kein PurgeInfo
2593
 
2597
 
2594
        result := RES_DEFAULT; // Standardeinstellung bei Windows
2598
        result := RES_DEFAULT; // Standardeinstellung bei Windows
2595
      end;
2599
      end;
2596
 
2600
 
2597
      reg.CloseKey;
2601
      reg.CloseKey;
2598
    end;
2602
    end;
2599
  finally
2603
  finally
2600
    reg.Free;
2604
    reg.Free;
2601
  end;
2605
  end;
2602
end;
2606
end;
2603
 
2607
 
2604
function RecyclerSpecificGetPercentUsage(Drive: Char): integer;
2608
function RecyclerSpecificGetPercentUsage(Drive: Char): integer;
2605
var
2609
var
2606
  reg: TRegistry;
2610
  reg: TRegistry;
2607
  dump: string;
2611
  dump: string;
2608
const
2612
const
2609
  RES_DEFAULT = 10;
2613
  RES_DEFAULT = 10;
2610
begin
2614
begin
2611
  result := -1;
2615
  result := -1;
2612
 
2616
 
2613
  reg := TRegistry.Create;
2617
  reg := TRegistry.Create;
2614
  try
2618
  try
2615
    reg.RootKey := HKEY_LOCAL_MACHINE;
2619
    reg.RootKey := HKEY_LOCAL_MACHINE;
2616
 
2620
 
2617
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
2621
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
2618
    begin
2622
    begin
2619
      if reg.OpenKeyReadOnly(Drive) then
2623
      if reg.OpenKeyReadOnly(Drive) then
2620
      begin
2624
      begin
2621
        if reg.ValueExists('Percent') then
2625
        if reg.ValueExists('Percent') then
2622
        begin
2626
        begin
2623
          // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
2627
          // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
2624
 
2628
 
2625
          result := reg.ReadInteger('Percent');
2629
          result := reg.ReadInteger('Percent');
2626
        end
2630
        end
2627
        else
2631
        else
2628
        begin
2632
        begin
2629
          result := RES_DEFAULT;
2633
          result := RES_DEFAULT;
2630
        end;
2634
        end;
2631
        reg.CloseKey;
2635
        reg.CloseKey;
2632
      end
2636
      end
2633
      else
2637
      else
2634
      begin
2638
      begin
2635
        if reg.ValueExists('PurgeInfo') then
2639
        if reg.ValueExists('PurgeInfo') then
2636
        begin
2640
        begin
2637
          // Windows 95 - Verschlüsselte Informationen liegen in PurgeInfo
2641
          // Windows 95 - Verschlüsselte Informationen liegen in PurgeInfo
2638
 
2642
 
2639
          dump := _registryReadDump(reg, 'PurgeInfo');
2643
          dump := _registryReadDump(reg, 'PurgeInfo');
2640
 
2644
 
2641
          // NOT tested, only theoretical! My idea about the possible structure is:
2645
          // NOT tested, only theoretical! My idea about the possible structure is:
2642
          // 0x08 = Drive A
2646
          // 0x08 = Drive A
2643
          // 0x0a = Drive B
2647
          // 0x0a = Drive B
2644
          // 0x0c = Drive C (validated)
2648
          // 0x0c = Drive C (validated)
2645
          // 0x0e = Drive D
2649
          // 0x0e = Drive D
2646
          // ...
2650
          // ...
2647
 
2651
 
2648
          result := Ord(dump[9+_DriveNum(Drive)*2]);
2652
          result := Ord(dump[9+_DriveNum(Drive)*2]);
2649
        end
2653
        end
2650
        else
2654
        else
2651
        begin
2655
        begin
2652
          // Windows 95 - Standardwerte sind gegeben, deswegen existiert kein PurgeInfo
2656
          // Windows 95 - Standardwerte sind gegeben, deswegen existiert kein PurgeInfo
2653
 
2657
 
2654
          result := RES_DEFAULT; // Standardeinstellung bei Windows
2658
          result := RES_DEFAULT; // Standardeinstellung bei Windows
2655
        end;
2659
        end;
2656
      end;
2660
      end;
2657
 
2661
 
2658
      reg.CloseKey;
2662
      reg.CloseKey;
2659
    end;
2663
    end;
2660
  finally
2664
  finally
2661
    reg.Free;
2665
    reg.Free;
2662
  end;
2666
  end;
2663
end;
2667
end;
2664
 
2668
 
2665
function RecyclerGetPercentUsageAutoDeterminate(Drive: Char): integer;
2669
function RecyclerGetPercentUsageAutoDeterminate(Drive: Char): integer;
2666
var
2670
var
2667
  gpSetting: integer;
2671
  gpSetting: integer;
2668
begin
2672
begin
2669
  gpSetting := RecyclerGroupPolicyRecycleBinSize;
2673
  gpSetting := RecyclerGroupPolicyRecycleBinSize;
2670
  if gpSetting <> -1 then
2674
  if gpSetting <> -1 then
2671
    result := gpSetting
2675
    result := gpSetting
2672
  else if RecyclerHasGlobalSettings then
2676
  else if RecyclerHasGlobalSettings then
2673
    result := RecyclerGlobalGetPercentUsage
2677
    result := RecyclerGlobalGetPercentUsage
2674
  else
2678
  else
2675
    result := RecyclerSpecificGetPercentUsage(Drive);
2679
    result := RecyclerSpecificGetPercentUsage(Drive);
2676
end;
2680
end;
2677
 
2681
 
2678
function RecyclerGlobalIsNukeOnDelete: boolean;
2682
function RecyclerGlobalIsNukeOnDelete: boolean;
2679
var
2683
var
2680
  reg: TRegistry;
2684
  reg: TRegistry;
2681
  dump: string;
2685
  dump: AnsiString;
2682
const
2686
const
2683
  RES_DEFAULT = false;
2687
  RES_DEFAULT = false;
2684
begin
2688
begin
2685
  result := false;
2689
  result := false;
2686
 
2690
 
2687
  reg := TRegistry.Create;
2691
  reg := TRegistry.Create;
2688
  try
2692
  try
2689
    reg.RootKey := HKEY_LOCAL_MACHINE;
2693
    reg.RootKey := HKEY_LOCAL_MACHINE;
2690
 
2694
 
2691
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
2695
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
2692
    begin
2696
    begin
2693
      if reg.ValueExists('NukeOnDelete') then
2697
      if reg.ValueExists('NukeOnDelete') then
2694
      begin
2698
      begin
2695
        // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
2699
        // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
2696
 
2700
 
2697
        result := reg.ReadBool('NukeOnDelete');
2701
        result := reg.ReadBool('NukeOnDelete');
2698
      end
2702
      end
2699
      else if reg.ValueExists('PurgeInfo') then
2703
      else if reg.ValueExists('PurgeInfo') then
2700
      begin
2704
      begin
2701
        // Windows 95 - Verschlüsselte Informationen liegen in PurgeInfo
2705
        // Windows 95 - Verschlüsselte Informationen liegen in PurgeInfo
2702
 
2706
 
2703
        // See comment at RecyclerSpecificIsNukeOnDelete()
2707
        // See comment at RecyclerSpecificIsNukeOnDelete()
2704
 
2708
 
2705
        dump := _registryReadDump(reg, 'PurgeInfo');
2709
        dump := AnsiString(_registryReadDump(reg, 'PurgeInfo'));
2706
        result := GetAnsiCharBit(dump[68], 3);
2710
        result := GetAnsiCharBit(dump[68], 3);
2707
      end
2711
      end
2708
      else
2712
      else
2709
      begin
2713
      begin
2710
        // Windows 95 - Standardwerte sind gegeben, deswegen existiert kein PurgeInfo
2714
        // Windows 95 - Standardwerte sind gegeben, deswegen existiert kein PurgeInfo
2711
 
2715
 
2712
        result := RES_DEFAULT; // Standardeinstellung bei Windows
2716
        result := RES_DEFAULT; // Standardeinstellung bei Windows
2713
      end;
2717
      end;
2714
 
2718
 
2715
      reg.CloseKey;
2719
      reg.CloseKey;
2716
    end;
2720
    end;
2717
  finally
2721
  finally
2718
    reg.Free;
2722
    reg.Free;
2719
  end;
2723
  end;
2720
end;
2724
end;
2721
 
2725
 
2722
function RecyclerSpecificIsNukeOnDelete(Drive: Char): boolean;
2726
function RecyclerSpecificIsNukeOnDelete(Drive: Char): boolean;
2723
var
2727
var
2724
  reg: TRegistry;
2728
  reg: TRegistry;
2725
  dump: string;
2729
  dump: AnsiString;
2726
  d: Byte;
2730
  d: Byte;
2727
const
2731
const
2728
  RES_DEFAULT = false;
2732
  RES_DEFAULT = false;
2729
begin
2733
begin
2730
  result := false;
2734
  result := false;
2731
 
2735
 
2732
  reg := TRegistry.Create;
2736
  reg := TRegistry.Create;
2733
  try
2737
  try
2734
    reg.RootKey := HKEY_LOCAL_MACHINE;
2738
    reg.RootKey := HKEY_LOCAL_MACHINE;
2735
 
2739
 
2736
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
2740
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
2737
    begin
2741
    begin
2738
      if reg.OpenKeyReadOnly(Drive) then
2742
      if reg.OpenKeyReadOnly(Drive) then
2739
      begin
2743
      begin
2740
        if reg.ValueExists('NukeOnDelete') then
2744
        if reg.ValueExists('NukeOnDelete') then
2741
        begin
2745
        begin
2742
          // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
2746
          // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
2743
 
2747
 
2744
          result := reg.ReadBool('NukeOnDelete');
2748
          result := reg.ReadBool('NukeOnDelete');
2745
        end;
2749
        end;
2746
        reg.CloseKey;
2750
        reg.CloseKey;
2747
      end
2751
      end
2748
      else
2752
      else
2749
      begin
2753
      begin
2750
        if reg.ValueExists('PurgeInfo') then
2754
        if reg.ValueExists('PurgeInfo') then
2751
        begin
2755
        begin
2752
          // Windows 95 - Verschlüsselte Informationen liegen in PurgeInfo
2756
          // Windows 95 - Verschlüsselte Informationen liegen in PurgeInfo
2753
 
2757
 
2754
          dump := _registryReadDump(reg, 'PurgeInfo');
2758
          dump := AnsiString(_registryReadDump(reg, 'PurgeInfo'));
2755
 
2759
 
2756
          // NOT tested, only theoretical! My idea about the possible structure is:
2760
          // NOT tested, only theoretical! My idea about the possible structure is:
2757
          //
2761
          //
2758
          // Byte      0x40       0x41       0x42       0x43
2762
          // Byte      0x40       0x41       0x42       0x43
2759
          // Bit       76543210   76543210   76543210   76543210
2763
          // Bit       76543210   76543210   76543210   76543210
2760
          //           --------   --------   --------   --------
2764
          //           --------   --------   --------   --------
2761
          // Meaning   hgfedcba   ponmlkji   xwvutsrq   ????G?zy
2765
          // Meaning   hgfedcba   ponmlkji   xwvutsrq   ????G?zy
2762
          //
2766
          //
2763
          // a..z = Drives
2767
          // a..z = Drives
2764
          // G    = global settings
2768
          // G    = global settings
2765
          //
2769
          //
2766
          // Already validated:
2770
          // Already validated:
2767
          // 0x64 = 04 (00000100)
2771
          // 0x64 = 04 (00000100)
2768
          // 0x67 = 08 (00001000)
2772
          // 0x67 = 08 (00001000)
2769
 
2773
 
2770
          d := _DriveNum(Drive);
2774
          d := _DriveNum(Drive);
2771
          result := GetAnsiCharBit(dump[65+(d div 7)], d mod 7);
2775
          result := GetAnsiCharBit(dump[65+(d div 7)], d mod 7);
2772
        end
2776
        end
2773
        else
2777
        else
2774
        begin
2778
        begin
2775
          // Windows 95 - Standardwerte sind gegeben, deswegen existiert kein PurgeInfo
2779
          // Windows 95 - Standardwerte sind gegeben, deswegen existiert kein PurgeInfo
2776
 
2780
 
2777
          result := RES_DEFAULT; // Standardeinstellung bei Windows
2781
          result := RES_DEFAULT; // Standardeinstellung bei Windows
2778
        end;
2782
        end;
2779
      end;
2783
      end;
2780
 
2784
 
2781
      reg.CloseKey;
2785
      reg.CloseKey;
2782
    end;
2786
    end;
2783
  finally
2787
  finally
2784
    reg.Free;
2788
    reg.Free;
2785
  end;
2789
  end;
2786
end;
2790
end;
2787
 
2791
 
2788
function RecyclerIsNukeOnDeleteAutoDeterminate(Drive: Char): boolean;
2792
function RecyclerIsNukeOnDeleteAutoDeterminate(Drive: Char): boolean;
2789
begin
2793
begin
2790
  if RecyclerGroupPolicyNoRecycleFiles = gpEnabled then
2794
  if RecyclerGroupPolicyNoRecycleFiles = gpEnabled then
2791
    result := true
2795
    result := true
2792
  else if RecyclerHasGlobalSettings then
2796
  else if RecyclerHasGlobalSettings then
2793
    result := RecyclerGlobalIsNukeOnDelete
2797
    result := RecyclerGlobalIsNukeOnDelete
2794
  else
2798
  else
2795
    result := RecyclerSpecificIsNukeOnDelete(Drive);
2799
    result := RecyclerSpecificIsNukeOnDelete(Drive);
2796
end;
2800
end;
2797
 
2801
 
2798
function RecyclerHasGlobalSettings: boolean;
2802
function RecyclerHasGlobalSettings: boolean;
2799
var
2803
var
2800
  reg: TRegistry;
2804
  reg: TRegistry;
2801
  dump: string;
2805
  dump: string;
2802
begin
2806
begin
2803
  result := false;
2807
  result := false;
2804
 
2808
 
2805
  reg := TRegistry.Create;
2809
  reg := TRegistry.Create;
2806
  try
2810
  try
2807
    reg.RootKey := HKEY_LOCAL_MACHINE;
2811
    reg.RootKey := HKEY_LOCAL_MACHINE;
2808
 
2812
 
2809
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
2813
    if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\BitBucket') then
2810
    begin
2814
    begin
2811
      if reg.ValueExists('UseGlobalSettings') then
2815
      if reg.ValueExists('UseGlobalSettings') then
2812
      begin
2816
      begin
2813
        // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
2817
        // Windows 2000 - Informationen liegen aufgeschlüsselt in der Registry
2814
 
2818
 
2815
        result := reg.ReadBool('UseGlobalSettings');
2819
        result := reg.ReadBool('UseGlobalSettings');
2816
      end
2820
      end
2817
      else if reg.ValueExists('PurgeInfo') then
2821
      else if reg.ValueExists('PurgeInfo') then
2818
      begin
2822
      begin
2819
        // Windows 95 - Verschlüsselte Informationen liegen in PurgeInfo
2823
        // Windows 95 - Verschlüsselte Informationen liegen in PurgeInfo
2820
        // TODO: Gibt es ein offizielles Dokument oder ein API, indem PurgeInfo
2824
        // TODO: Gibt es ein offizielles Dokument oder ein API, indem PurgeInfo
2821
        // offiziell entschlüsselbar ist?
2825
        // offiziell entschlüsselbar ist?
2822
 
2826
 
2823
        dump := _registryReadDump(reg, 'PurgeInfo');
2827
        dump := _registryReadDump(reg, 'PurgeInfo');
2824
        if dump[5] = #$01 then
2828
        if dump[5] = #$01 then
2825
          result := true
2829
          result := true
2826
        else if dump[5] = #$00 then
2830
        else if dump[5] = #$00 then
2827
          result := false
2831
          result := false
2828
        else
2832
        else
2829
          raise EUnknownState.Create(Format(LNG_UNEXPECTED_STATE, ['PurgeInfo']));
2833
          raise EUnknownState.Create(Format(LNG_UNEXPECTED_STATE, ['PurgeInfo']));
2830
      end
2834
      end
2831
      else
2835
      else
2832
      begin
2836
      begin
2833
        // Windows 95 - Standardwerte sind gegeben, deswegen existiert kein PurgeInfo
2837
        // Windows 95 - Standardwerte sind gegeben, deswegen existiert kein PurgeInfo
2834
 
2838
 
2835
        result := true; // Standardeinstellung bei Windows
2839
        result := true; // Standardeinstellung bei Windows
2836
      end;
2840
      end;
2837
 
2841
 
2838
      reg.CloseKey;
2842
      reg.CloseKey;
2839
    end;
2843
    end;
2840
  finally
2844
  finally
2841
    reg.Free;
2845
    reg.Free;
2842
  end;
2846
  end;
2843
end;
2847
end;
2844
 
2848
 
2845
function RecyclerIsEmpty: boolean;
2849
function RecyclerIsEmpty: boolean;
2846
var
2850
var
2847
  Drive: Char;
2851
  Drive: Char;
2848
begin
2852
begin
2849
  result := true;
2853
  result := true;
2850
  for Drive := 'A' to 'Z' do
2854
  for Drive := 'A' to 'Z' do
2851
  begin
2855
  begin
2852
    if RecyclerIsPossible(Drive) and not RecyclerIsEmpty(Drive) then
2856
    if RecyclerIsPossible(Drive) and not RecyclerIsEmpty(Drive) then
2853
    begin
2857
    begin
2854
      result := false;
2858
      result := false;
2855
      exit;
2859
      exit;
2856
    end;
2860
    end;
2857
  end;
2861
  end;
2858
end;
2862
end;
2859
 
2863
 
2860
function RecyclerIsEmpty(Drive: Char): boolean;
2864
function RecyclerIsEmpty(Drive: Char): boolean;
2861
begin
2865
begin
2862
  result := RecyclerGetAPIInfo(Drive).i64NumItems = 0;
2866
  result := RecyclerGetAPIInfo(Drive).i64NumItems = 0;
2863
end;
2867
end;
2864
 
2868
 
2865
function RecyclerGetNumItems: int64;
2869
function RecyclerGetNumItems: int64;
2866
var
2870
var
2867
  Drive: Char;
2871
  Drive: Char;
2868
begin
2872
begin
2869
  result := 0;
2873
  result := 0;
2870
  for Drive := 'A' to 'Z' do
2874
  for Drive := 'A' to 'Z' do
2871
  begin
2875
  begin
2872
    if RecyclerIsPossible(Drive) then
2876
    if RecyclerIsPossible(Drive) then
2873
    begin
2877
    begin
2874
      result := result + RecyclerGetNumItems(Drive);
2878
      result := result + RecyclerGetNumItems(Drive);
2875
    end;
2879
    end;
2876
  end;
2880
  end;
2877
end;
2881
end;
2878
 
2882
 
2879
function RecyclerGetNumItems(Drive: Char): int64;
2883
function RecyclerGetNumItems(Drive: Char): int64;
2880
begin
2884
begin
2881
  result := RecyclerGetAPIInfo(Drive).i64NumItems;
2885
  result := RecyclerGetAPIInfo(Drive).i64NumItems;
2882
end;
2886
end;
2883
 
2887
 
2884
function RecyclerGetSize: int64;
2888
function RecyclerGetSize: int64;
2885
var
2889
var
2886
  Drive: Char;
2890
  Drive: Char;
2887
begin
2891
begin
2888
  result := 0;
2892
  result := 0;
2889
  for Drive := 'A' to 'Z' do
2893
  for Drive := 'A' to 'Z' do
2890
  begin
2894
  begin
2891
    if RecyclerIsPossible(Drive) then
2895
    if RecyclerIsPossible(Drive) then
2892
    begin
2896
    begin
2893
      result := result + RecyclerGetSize(Drive);
2897
      result := result + RecyclerGetSize(Drive);
2894
    end;
2898
    end;
2895
  end;
2899
  end;
2896
end;
2900
end;
2897
 
2901
 
2898
function RecyclerGetSize(Drive: Char): int64;
2902
function RecyclerGetSize(Drive: Char): int64;
2899
begin
2903
begin
2900
  result := RecyclerGetAPIInfo(Drive).i64Size;
2904
  result := RecyclerGetAPIInfo(Drive).i64Size;
2901
end;
2905
end;
2902
 
2906
 
2903
function RecyclerGetAPIInfo(Drive: Char): TSHQueryRBInfo;
2907
function RecyclerGetAPIInfo(Drive: Char): TSHQueryRBInfo;
2904
begin
2908
begin
2905
  result := RecyclerGetAPIInfo(Drive + ':\');
2909
  result := RecyclerGetAPIInfo(Drive + ':\');
2906
end;
2910
end;
2907
 
2911
 
2908
const
2912
const
2909
  C_SHQueryRecycleBin = 'SHQueryRecycleBinA';
2913
  C_SHQueryRecycleBin = 'SHQueryRecycleBinA';
2910
 
2914
 
2911
type
2915
type
2912
  TSHQueryRecycleBin = function(pszRootPath: LPCTSTR;
2916
  TSHQueryRecycleBin = function(pszRootPath: LPCTSTR;
2913
    var pSHQueryRBInfo: TSHQueryRBInfo): HRESULT; stdcall;
2917
    var pSHQueryRBInfo: TSHQueryRBInfo): HRESULT; stdcall;
2914
 
2918
 
2915
function RecyclerGetAPIInfo(Path: String): TSHQueryRBInfo;
2919
function RecyclerGetAPIInfo(Path: String): TSHQueryRBInfo;
2916
var
2920
var
2917
  PSHQueryRecycleBin: TSHQueryRecycleBin;
2921
  PSHQueryRecycleBin: TSHQueryRecycleBin;
2918
  RBHandle: THandle;
2922
  RBHandle: THandle;
2919
  res: HRESULT;
2923
  res: HRESULT;
2920
begin
2924
begin
2921
  PSHQueryRecycleBin := nil;
2925
  PSHQueryRecycleBin := nil;
2922
 
2926
 
2923
  // Ref: http://www.delphipraxis.net/post1291.html
2927
  // Ref: http://www.delphipraxis.net/post1291.html
2924
 
2928
 
2925
  RBHandle := LoadLibrary(shell32);
2929
  RBHandle := LoadLibrary(shell32);
2926
  if(RBHandle <> 0) then
2930
  if(RBHandle <> 0) then
2927
  begin
2931
  begin
2928
    PSHQueryRecycleBin := GetProcAddress(RBHandle, C_SHQueryRecycleBin);
2932
    PSHQueryRecycleBin := GetProcAddress(RBHandle, C_SHQueryRecycleBin);
2929
    if(@PSHQueryRecycleBin = nil) then
2933
    if(@PSHQueryRecycleBin = nil) then
2930
    begin
2934
    begin
2931
      FreeLibrary(RBHandle);
2935
      FreeLibrary(RBHandle);
2932
      RBHandle := 0;
2936
      RBHandle := 0;
2933
    end;
2937
    end;
2934
  end;
2938
  end;
2935
 
2939
 
2936
  fillchar(result, SizeOf(TSHQueryRBInfo),0);
2940
  fillchar(result, SizeOf(TSHQueryRBInfo),0);
2937
  result.cbSize := SizeOf(TSHQueryRBInfo);
2941
  result.cbSize := SizeOf(TSHQueryRBInfo);
2938
 
2942
 
2939
  if (RBHandle <> 0) and (Assigned(PSHQueryRecycleBin)) then
2943
  if (RBHandle <> 0) and (Assigned(PSHQueryRecycleBin)) then
2940
  begin
2944
  begin
2941
    res := PSHQueryRecycleBin(PChar(Path), result);
2945
    res := PSHQueryRecycleBin(PChar(Path), result);
2942
    // if Succeeded(res) then
2946
    // if Succeeded(res) then
2943
    if res = S_OK then
2947
    if res = S_OK then
2944
    begin
2948
    begin
2945
      // Alles OK, unser result hat nun die gewünschten Daten.
2949
      // Alles OK, unser result hat nun die gewünschten Daten.
2946
    end
2950
    end
2947
    else
2951
    else
2948
    begin
2952
    begin
2949
      // Since Windows Vista, SHQueryRecycleBin will fail with E_FAIL (80004005)
2953
      // Since Windows Vista, SHQueryRecycleBin will fail with E_FAIL (80004005)
2950
      // if Path is a floppy or CD drive...
2954
      // if Path is a floppy or CD drive...
-
 
2955
      // Windows 10: Error 0x8007003 for Path 'C:\'
2951
      raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_ERROR_CODE, [C_SHQueryRecycleBin, Path, '0x'+IntToHex(res, 2*SizeOf(HRESULT))])]);
2956
      raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_ERROR_CODE, [C_SHQueryRecycleBin, Path, '0x'+IntToHex(res, 2*SizeOf(HRESULT))])]);
2952
    end;
2957
    end;
2953
  end
2958
  end
2954
  else
2959
  else
2955
    raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_NOT_CALLABLE, [C_SHQueryRecycleBin])]);
2960
    raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_NOT_CALLABLE, [C_SHQueryRecycleBin])]);
2956
 
2961
 
2957
  if (RBHandle <> 0) then FreeLibrary(RBHandle);
2962
  if (RBHandle <> 0) then FreeLibrary(RBHandle);
2958
end;
2963
end;
2959
 
2964
 
2960
function RecyclerGetCLSID: string;
2965
function RecyclerGetCLSID: string;
2961
begin
2966
begin
2962
  result := RECYCLER_CLSID;
2967
  result := RECYCLER_CLSID;
2963
end;
2968
end;
2964
 
2969
 
2965
// Windows 95 without Internet Explorer 4 has no SHQueryRecycleBinA.
2970
// Windows 95 without Internet Explorer 4 has no SHQueryRecycleBinA.
2966
function RecyclerQueryFunctionAvailable: boolean;
2971
function RecyclerQueryFunctionAvailable: boolean;
2967
var
2972
var
2968
  RBHandle: THandle;
2973
  RBHandle: THandle;
2969
  SHQueryRecycleBin: TSHQueryRecycleBin;
2974
  SHQueryRecycleBin: TSHQueryRecycleBin;
2970
begin
2975
begin
2971
  RBHandle := LoadLibrary(shell32);
2976
  RBHandle := LoadLibrary(shell32);
2972
  if(RBHandle <> 0) then
2977
  if(RBHandle <> 0) then
2973
  begin
2978
  begin
2974
    SHQueryRecycleBin := GetProcAddress(RBHandle, C_SHQueryRecycleBin);
2979
    SHQueryRecycleBin := GetProcAddress(RBHandle, C_SHQueryRecycleBin);
2975
    if(@SHQueryRecycleBin = nil) then
2980
    if(@SHQueryRecycleBin = nil) then
2976
    begin
2981
    begin
2977
      FreeLibrary(RBHandle);
2982
      FreeLibrary(RBHandle);
2978
      RBHandle := 0;
2983
      RBHandle := 0;
2979
    end;
2984
    end;
2980
  end;
2985
  end;
2981
 
2986
 
2982
  result := RBHandle <> 0;
2987
  result := RBHandle <> 0;
2983
end;
2988
end;
2984
 
2989
 
2985
const
2990
const
2986
  GroupPolicyAcceptHKLMTrick = true;
2991
  GroupPolicyAcceptHKLMTrick = true;
2987
 
2992
 
2988
// TODO: In future also detect for other users
2993
// TODO: In future also detect for other users
2989
// TODO: Also make a setter (inkl. Message to Windows Explorer?)
2994
// TODO: Also make a setter (inkl. Message to Windows Explorer?)
2990
function RecyclerGroupPolicyNoRecycleFiles: GPOLICYBOOL;
2995
function RecyclerGroupPolicyNoRecycleFiles: GPOLICYBOOL;
2991
var
2996
var
2992
  reg: TRegistry;
2997
  reg: TRegistry;
2993
begin
2998
begin
2994
  result := gpUndefined;
2999
  result := gpUndefined;
2995
 
3000
 
2996
  reg := TRegistry.Create;
3001
  reg := TRegistry.Create;
2997
  try
3002
  try
2998
    // If a value is set in HKEY_LOCAL_MACHINE, it will be prefered,
3003
    // If a value is set in HKEY_LOCAL_MACHINE, it will be prefered,
2999
    // even if gpedit.msc shows "Not configured"!
3004
    // even if gpedit.msc shows "Not configured"!
3000
    if GroupPolicyAcceptHKLMTrick then
3005
    if GroupPolicyAcceptHKLMTrick then
3001
    begin
3006
    begin
3002
      reg.RootKey := HKEY_LOCAL_MACHINE;
3007
      reg.RootKey := HKEY_LOCAL_MACHINE;
3003
      if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3008
      if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3004
      begin
3009
      begin
3005
        if reg.ValueExists('NoRecycleFiles') then
3010
        if reg.ValueExists('NoRecycleFiles') then
3006
        begin
3011
        begin
3007
          if reg.ReadBool('NoRecycleFiles') then
3012
          if reg.ReadBool('NoRecycleFiles') then
3008
            result := gpEnabled
3013
            result := gpEnabled
3009
          else
3014
          else
3010
            result := gpDisabled;
3015
            result := gpDisabled;
3011
          Exit;
3016
          Exit;
3012
        end;
3017
        end;
3013
        reg.CloseKey;
3018
        reg.CloseKey;
3014
      end;
3019
      end;
3015
    end;
3020
    end;
3016
 
3021
 
3017
    reg.RootKey := HKEY_CURRENT_USER;
3022
    reg.RootKey := HKEY_CURRENT_USER;
3018
    if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3023
    if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3019
    begin
3024
    begin
3020
      if reg.ValueExists('NoRecycleFiles') then
3025
      if reg.ValueExists('NoRecycleFiles') then
3021
      begin
3026
      begin
3022
        if reg.ReadBool('NoRecycleFiles') then
3027
        if reg.ReadBool('NoRecycleFiles') then
3023
          result := gpEnabled
3028
          result := gpEnabled
3024
        else
3029
        else
3025
          result := gpDisabled;
3030
          result := gpDisabled;
3026
      end;
3031
      end;
3027
      reg.CloseKey;
3032
      reg.CloseKey;
3028
    end;
3033
    end;
3029
  finally
3034
  finally
3030
    reg.Free;
3035
    reg.Free;
3031
  end;
3036
  end;
3032
end;
3037
end;
3033
 
3038
 
3034
// TODO: In future also detect for other users
3039
// TODO: In future also detect for other users
3035
// TODO: Also make a setter (inkl. Message to Windows Explorer?)
3040
// TODO: Also make a setter (inkl. Message to Windows Explorer?)
3036
function RecyclerGroupPolicyConfirmFileDelete: GPOLICYBOOL;
3041
function RecyclerGroupPolicyConfirmFileDelete: GPOLICYBOOL;
3037
var
3042
var
3038
  reg: TRegistry;
3043
  reg: TRegistry;
3039
begin
3044
begin
3040
  result := gpUndefined;
3045
  result := gpUndefined;
3041
  reg := TRegistry.Create;
3046
  reg := TRegistry.Create;
3042
  try
3047
  try
3043
    // If a value is set in HKEY_LOCAL_MACHINE, it will be prefered,
3048
    // If a value is set in HKEY_LOCAL_MACHINE, it will be prefered,
3044
    // even if gpedit.msc shows "Not configured"!
3049
    // even if gpedit.msc shows "Not configured"!
3045
    if GroupPolicyAcceptHKLMTrick then
3050
    if GroupPolicyAcceptHKLMTrick then
3046
    begin
3051
    begin
3047
      reg.RootKey := HKEY_LOCAL_MACHINE;
3052
      reg.RootKey := HKEY_LOCAL_MACHINE;
3048
      if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3053
      if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3049
      begin
3054
      begin
3050
        if reg.ValueExists('ConfirmFileDelete') then
3055
        if reg.ValueExists('ConfirmFileDelete') then
3051
        begin
3056
        begin
3052
          if reg.ReadBool('ConfirmFileDelete') then
3057
          if reg.ReadBool('ConfirmFileDelete') then
3053
            result := gpEnabled
3058
            result := gpEnabled
3054
          else
3059
          else
3055
            result := gpDisabled;
3060
            result := gpDisabled;
3056
          Exit;
3061
          Exit;
3057
        end;
3062
        end;
3058
        reg.CloseKey;
3063
        reg.CloseKey;
3059
      end;
3064
      end;
3060
    end;
3065
    end;
3061
 
3066
 
3062
    reg.RootKey := HKEY_CURRENT_USER;
3067
    reg.RootKey := HKEY_CURRENT_USER;
3063
    if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3068
    if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3064
    begin
3069
    begin
3065
      if reg.ValueExists('ConfirmFileDelete') then
3070
      if reg.ValueExists('ConfirmFileDelete') then
3066
      begin
3071
      begin
3067
        if reg.ReadBool('ConfirmFileDelete') then
3072
        if reg.ReadBool('ConfirmFileDelete') then
3068
          result := gpEnabled
3073
          result := gpEnabled
3069
        else
3074
        else
3070
          result := gpDisabled;
3075
          result := gpDisabled;
3071
      end;
3076
      end;
3072
      reg.CloseKey;
3077
      reg.CloseKey;
3073
    end;
3078
    end;
3074
  finally
3079
  finally
3075
    reg.Free;
3080
    reg.Free;
3076
  end;
3081
  end;
3077
end;
3082
end;
3078
 
3083
 
3079
 
3084
 
3080
// TODO: In future also detect for other users
3085
// TODO: In future also detect for other users
3081
// TODO: Also make a setter (inkl. Message to Windows Explorer?)
3086
// TODO: Also make a setter (inkl. Message to Windows Explorer?)
3082
function RecyclerGroupPolicyRecycleBinSize: integer;
3087
function RecyclerGroupPolicyRecycleBinSize: integer;
3083
var
3088
var
3084
  reg: TRegistry;
3089
  reg: TRegistry;
3085
begin
3090
begin
3086
  result := -1;
3091
  result := -1;
3087
  reg := TRegistry.Create;
3092
  reg := TRegistry.Create;
3088
  try
3093
  try
3089
    // If a value is set in HKEY_LOCAL_MACHINE, it will be prefered,
3094
    // If a value is set in HKEY_LOCAL_MACHINE, it will be prefered,
3090
    // even if gpedit.msc shows "Not configured"!
3095
    // even if gpedit.msc shows "Not configured"!
3091
    if GroupPolicyAcceptHKLMTrick then
3096
    if GroupPolicyAcceptHKLMTrick then
3092
    begin
3097
    begin
3093
      reg.RootKey := HKEY_LOCAL_MACHINE;
3098
      reg.RootKey := HKEY_LOCAL_MACHINE;
3094
      if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3099
      if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3095
      begin
3100
      begin
3096
        if reg.ValueExists('RecycleBinSize') then
3101
        if reg.ValueExists('RecycleBinSize') then
3097
        begin
3102
        begin
3098
          result := reg.ReadInteger('RecycleBinSize');
3103
          result := reg.ReadInteger('RecycleBinSize');
3099
          Exit;
3104
          Exit;
3100
        end;
3105
        end;
3101
        reg.CloseKey;
3106
        reg.CloseKey;
3102
      end;
3107
      end;
3103
    end;
3108
    end;
3104
 
3109
 
3105
    reg.RootKey := HKEY_CURRENT_USER;
3110
    reg.RootKey := HKEY_CURRENT_USER;
3106
    if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3111
    if reg.OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer') then
3107
    begin
3112
    begin
3108
      if reg.ValueExists('RecycleBinSize') then
3113
      if reg.ValueExists('RecycleBinSize') then
3109
      begin
3114
      begin
3110
        result := reg.ReadInteger('RecycleBinSize');
3115
        result := reg.ReadInteger('RecycleBinSize');
3111
      end;
3116
      end;
3112
      reg.CloseKey;
3117
      reg.CloseKey;
3113
    end;
3118
    end;
3114
  finally
3119
  finally
3115
    reg.Free;
3120
    reg.Free;
3116
  end;
3121
  end;
3117
end;
3122
end;
3118
 
3123
 
3119
function GPBoolToString(value: GPOLICYBOOL): String;
3124
function GPBoolToString(value: GPOLICYBOOL): String;
3120
begin
3125
begin
3121
  case value of
3126
  case value of
3122
    gpUndefined: result := 'Not configured';
3127
    gpUndefined: result := 'Not configured';
3123
    gpEnabled: result := 'Enabled';
3128
    gpEnabled: result := 'Enabled';
3124
    gpDisabled: result := 'Disabled';
3129
    gpDisabled: result := 'Disabled';
3125
  end;
3130
  end;
3126
end;
3131
end;
3127
 
3132
 
3128
function RecyclerIsPossible(Drive: Char): boolean;
3133
function RecyclerIsPossible(Drive: Char): boolean;
3129
var
3134
var
3130
  typ: Integer;
3135
  typ: Integer;
3131
begin
3136
begin
3132
  typ := GetDriveType(PChar(Drive + ':\'));
3137
  typ := GetDriveType(PChar(Drive + ':\'));
3133
  result := typ = DRIVE_FIXED;
3138
  result := typ = DRIVE_FIXED;
3134
end;
3139
end;
3135
 
3140
 
3136
function RecyclerLibraryVersion: string;
3141
function RecyclerLibraryVersion: string;
3137
begin
3142
begin
3138
  result := 'ViaThinkSoft Recycle Bin Unit [01 JUL 2016]';
3143
  result := 'ViaThinkSoft Recycle Bin Unit [01 JUL 2016]';
3139
end;
3144
end;
3140
 
3145
 
3141
end.
3146
end.
3142
 
3147