Rev 91 | Rev 96 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 91 | Rev 92 | ||
---|---|---|---|
Line 7... | Line 7... | ||
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: 30 Jun 2022 // |
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) // |
Line 20... | Line 20... | ||
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 (version 1 and version 2 format) // |
27 | // USE RECYCLE BIN UNIT V2 INSTEAD! // |
26 | // Windows 11 // |
28 | //////////////////////////////////////////////////////////////////////////////////// |
27 | //////////////////////////////////////////////////////////////////////////////////// |
29 | // // |
28 | // // |
30 | // Needs Delphi 4 or higher. If you are using Delphi 4 or 5, you can not use the // |
29 | // Needs Delphi 4 or higher. If you are using Delphi 4 or 5, you can not use the // |
31 | // RecyclerGetDateTime() functions, because the unit "DateUtils" is missing. // |
30 | // RecyclerGetDateTime() functions, because the unit "DateUtils" is missing. // |
32 | // Warning! This is a platform unit. // |
31 | // Warning! This is a platform unit. // |
Line 133... | Line 132... | ||
133 | EUnknownState = class(Exception); |
132 | EUnknownState = class(Exception); |
134 | EEventCategoryNotDefined = class(Exception); |
133 | EEventCategoryNotDefined = class(Exception); |
135 | EAPICallError = class(Exception); |
134 | EAPICallError = class(Exception); |
136 | 135 | ||
137 | PSHQueryRBInfo = ^TSHQueryRBInfo; |
136 | PSHQueryRBInfo = ^TSHQueryRBInfo; |
- | 137 | {$IFDEF WIN64} |
|
- | 138 | // ATTENTION! MUST NOT BE PACKED! Alignment for 64 bit must be 8 and for 32 bit must be 4 |
|
- | 139 | TSHQueryRBInfo = record |
|
- | 140 | {$ELSE} |
|
138 | TSHQueryRBInfo = packed record |
141 | TSHQueryRBInfo = packed record |
- | 142 | {$ENDIF} |
|
139 | cbSize : dword; |
143 | cbSize : dword; |
140 | i64Size : int64; |
144 | i64Size : int64; |
141 | i64NumItems : int64; |
145 | i64NumItems : int64; |
142 | end; |
146 | end; |
143 | 147 | ||
Line 861... | Line 865... | ||
861 | 865 | ||
862 | // ********************************************************** |
866 | // ********************************************************** |
863 | // VISTA AND WINDOWS 7 FUNCTIONS, INTERNAL USED |
867 | // VISTA AND WINDOWS 7 FUNCTIONS, INTERNAL USED |
864 | // ********************************************************** |
868 | // ********************************************************** |
865 | 869 | ||
866 | const |
- | |
867 | vista_valid_index_size = $220; // 544 |
- | |
868 | - | ||
869 | function _isFileVistaRealfile(filename: string): boolean; |
870 | function _isFileVistaRealfile(filename: string): boolean; |
870 | begin |
871 | begin |
871 | result := uppercase(copy(extractfilename(filename), 0, 2)) = '$R'; |
872 | result := uppercase(copy(extractfilename(filename), 0, 2)) = '$R'; |
872 | end; |
873 | end; |
873 | 874 | ||
Line 918... | Line 919... | ||
918 | r := FindFirst(tmp+PathDelim + '$I*', faAnyFile, sr); |
919 | r := FindFirst(tmp+PathDelim + '$I*', faAnyFile, sr); |
919 | while r = 0 do |
920 | while r = 0 do |
920 | begin |
921 | begin |
921 | if (sr.Name <> '.') and (sr.Name <> '..') then |
922 | if (sr.Name <> '.') and (sr.Name <> '..') then |
922 | begin |
923 | begin |
923 | if sr.Size = vista_valid_index_size then |
- | |
924 | begin |
- | |
925 | result.Add(copy(sr.name, 3, length(sr.name)-2)); |
924 | result.Add(copy(sr.name, 3, length(sr.name)-2)); |
926 | end; |
- | |
927 | end; |
925 | end; |
928 | r := FindNext(sr); |
926 | r := FindNext(sr); |
929 | end; |
927 | end; |
930 | 928 | ||
931 | FindClose(sr); |
929 | FindClose(sr); |
Line 952... | Line 950... | ||
952 | 950 | ||
953 | function _VistaGetSourceDrive(infofile: string): char; |
951 | function _VistaGetSourceDrive(infofile: string): char; |
954 | var |
952 | var |
955 | fs: TFileStream; |
953 | fs: TFileStream; |
956 | tmp: string; |
954 | tmp: string; |
- | 955 | version: DWORD; |
|
957 | const |
956 | const |
958 | drive_vista_position = $18; |
957 | drive_vista_position = $18; |
959 | begin |
958 | begin |
960 | result := #0; |
959 | result := #0; |
961 | 960 | ||
Line 963... | Line 962... | ||
963 | tmp := _VistaChangeRealfileToIndexfile(tmp); |
962 | tmp := _VistaChangeRealfileToIndexfile(tmp); |
964 | if not fileexists(tmp) then exit; |
963 | if not fileexists(tmp) then exit; |
965 | 964 | ||
966 | fs := TFileStream.Create(tmp, fmOpenRead); |
965 | fs := TFileStream.Create(tmp, fmOpenRead); |
967 | try |
966 | try |
- | 967 | fs.ReadBuffer(version, 4); |
|
- | 968 | if version > 2 then |
|
- | 969 | raise Exception.CreateFmt('Unexpeceted version %d of Vista index file', [version]); |
|
968 | fs.seek(drive_vista_position, soFromBeginning); |
970 | fs.seek(drive_vista_position, soFromBeginning); |
969 | result := _readChar(fs); |
971 | result := _readChar(fs); |
970 | finally |
972 | finally |
971 | fs.free; |
973 | fs.free; |
972 | end; |
974 | end; |
Line 975... | Line 977... | ||
975 | {$IFDEF DEL6UP} |
977 | {$IFDEF DEL6UP} |
976 | function _VistaGetDateTime(infofile: string): TDateTime; |
978 | function _VistaGetDateTime(infofile: string): TDateTime; |
977 | var |
979 | var |
978 | fs: TFileStream; |
980 | fs: TFileStream; |
979 | tmp: string; |
981 | tmp: string; |
- | 982 | version: DWORD; |
|
980 | const |
983 | const |
981 | timestamp_vista_position = $10; |
984 | timestamp_vista_position = $10; |
982 | begin |
985 | begin |
983 | result := EncodeDateTime(1601, 1, 1, 0, 0, 0, 0); |
986 | result := EncodeDateTime(1601, 1, 1, 0, 0, 0, 0); |
984 | 987 | ||
Line 986... | Line 989... | ||
986 | tmp := _VistaChangeRealfileToIndexfile(tmp); |
989 | tmp := _VistaChangeRealfileToIndexfile(tmp); |
987 | if not fileexists(tmp) then exit; |
990 | if not fileexists(tmp) then exit; |
988 | 991 | ||
989 | fs := TFileStream.Create(tmp, fmOpenRead); |
992 | fs := TFileStream.Create(tmp, fmOpenRead); |
990 | try |
993 | try |
- | 994 | fs.ReadBuffer(version, 4); |
|
- | 995 | if version > 2 then |
|
- | 996 | raise Exception.CreateFmt('Unexpeceted version %d of Vista index file', [version]); |
|
991 | fs.seek(timestamp_vista_position, soFromBeginning); |
997 | fs.seek(timestamp_vista_position, soFromBeginning); |
992 | result := _fileTimeToDateTime(_readInt64(fs)); |
998 | result := _fileTimeToDateTime(_readInt64(fs)); |
993 | finally |
999 | finally |
994 | fs.free; |
1000 | fs.free; |
995 | end; |
1001 | end; |
Line 998... | Line 1004... | ||
998 | 1004 | ||
999 | function _VistaGetSourceUnicode(infofile: string): string; |
1005 | function _VistaGetSourceUnicode(infofile: string): string; |
1000 | var |
1006 | var |
1001 | fs: TFileStream; |
1007 | fs: TFileStream; |
1002 | tmp: string; |
1008 | tmp: string; |
- | 1009 | version: DWORD; |
|
1003 | const |
1010 | const |
1004 | unicode_vista_position = $18; |
1011 | unicode_vista_position_v1 = $18; |
- | 1012 | unicode_vista_position_v2 = $1C; |
|
1005 | begin |
1013 | begin |
1006 | result := ''; |
1014 | result := ''; |
1007 | 1015 | ||
1008 | tmp := infofile; |
1016 | tmp := infofile; |
1009 | tmp := _VistaChangeRealfileToIndexfile(tmp); |
1017 | tmp := _VistaChangeRealfileToIndexfile(tmp); |
1010 | if not fileexists(tmp) then exit; |
1018 | if not fileexists(tmp) then exit; |
1011 | 1019 | ||
1012 | fs := TFileStream.Create(tmp, fmOpenRead); |
1020 | fs := TFileStream.Create(tmp, fmOpenRead); |
1013 | try |
1021 | try |
- | 1022 | fs.ReadBuffer(version, 4); |
|
- | 1023 | if version = 2 then |
|
- | 1024 | // Note: This is not the official way to read the source. Actually, you should check the size and only read this specified size |
|
1014 | fs.seek(unicode_vista_position, soFromBeginning); |
1025 | fs.seek(unicode_vista_position_v2, soFromBeginning) |
- | 1026 | else if version = 1 then |
|
- | 1027 | fs.seek(unicode_vista_position_v1, soFromBeginning) |
|
- | 1028 | else |
|
- | 1029 | raise Exception.CreateFmt('Unexpeceted version %d of Vista index file', [version]); |
|
1015 | result := _readNullTerminatedWideString(fs); |
1030 | result := _readNullTerminatedWideString(fs); |
1016 | finally |
1031 | finally |
1017 | fs.free; |
1032 | fs.free; |
1018 | end; |
1033 | end; |
1019 | end; |
1034 | end; |
1020 | 1035 | ||
1021 | function _VistaOriginalSize(infofile: string): integer; |
1036 | function _VistaOriginalSize(infofile: string): integer; |
1022 | var |
1037 | var |
1023 | fs: TFileStream; |
1038 | fs: TFileStream; |
1024 | tmp: string; |
1039 | tmp: string; |
- | 1040 | version: DWORD; |
|
1025 | const |
1041 | const |
1026 | size_vista_position = $8; |
1042 | size_vista_position = $8; |
1027 | begin |
1043 | begin |
1028 | result := -1; |
1044 | result := -1; |
1029 | 1045 | ||
Line 1031... | Line 1047... | ||
1031 | tmp := _VistaChangeRealfileToIndexfile(tmp); |
1047 | tmp := _VistaChangeRealfileToIndexfile(tmp); |
1032 | if not fileexists(tmp) then exit; |
1048 | if not fileexists(tmp) then exit; |
1033 | 1049 | ||
1034 | fs := TFileStream.Create(tmp, fmOpenRead); |
1050 | fs := TFileStream.Create(tmp, fmOpenRead); |
1035 | try |
1051 | try |
- | 1052 | fs.ReadBuffer(version, 4); |
|
- | 1053 | if version > 2 then |
|
- | 1054 | raise Exception.CreateFmt('Unexpeceted version %d of Vista index file', [version]); |
|
1036 | fs.seek(size_vista_position, soFromBeginning); |
1055 | fs.seek(size_vista_position, soFromBeginning); |
1037 | result := _readInt32(fs); |
1056 | result := _readInt32(fs); |
1038 | finally |
1057 | finally |
1039 | fs.free; |
1058 | fs.free; |
1040 | end; |
1059 | end; |
Line 1065... | Line 1084... | ||
1065 | 1084 | ||
1066 | function _VistaIsValid(infofile: string): boolean; |
1085 | function _VistaIsValid(infofile: string): boolean; |
1067 | var |
1086 | var |
1068 | tmp: string; |
1087 | tmp: string; |
1069 | begin |
1088 | begin |
1070 | result := false; |
- | |
1071 | - | ||
1072 | tmp := infofile; |
1089 | tmp := infofile; |
1073 | tmp := _VistaChangeRealfileToIndexfile(tmp); |
1090 | tmp := _VistaChangeRealfileToIndexfile(tmp); |
1074 | if not fileexists(tmp) then exit; |
1091 | result := fileexists(tmp); |
1075 | - | ||
1076 | // Check the file length |
- | |
1077 | result := _FileSize(tmp) = vista_valid_index_size; |
- | |
1078 | end; |
1092 | end; |
1079 | 1093 | ||
1080 | // ********************************************************** |
1094 | // ********************************************************** |
1081 | // PUBLIC FUNCTIONS |
1095 | // PUBLIC FUNCTIONS |
1082 | // ********************************************************** |
1096 | // ********************************************************** |
Line 2114... | Line 2128... | ||
2114 | HRESULT; stdcall; |
2128 | HRESULT; stdcall; |
2115 | var |
2129 | var |
2116 | PSHEmptyRecycleBin: TSHEmptyRecycleBin; |
2130 | PSHEmptyRecycleBin: TSHEmptyRecycleBin; |
2117 | LibHandle: THandle; |
2131 | LibHandle: THandle; |
2118 | const |
2132 | const |
- | 2133 | {$IFDEF UNICODE} |
|
- | 2134 | C_SHEmptyRecycleBin = 'SHEmptyRecycleBinW'; |
|
- | 2135 | {$ELSE} |
|
2119 | C_SHEmptyRecycleBinA = 'SHEmptyRecycleBinA'; |
2136 | C_SHEmptyRecycleBin = 'SHEmptyRecycleBinA'; |
- | 2137 | {$ENDIF} |
|
2120 | begin |
2138 | begin |
2121 | result := true; |
2139 | result := true; |
2122 | LibHandle := LoadLibrary(shell32) ; |
2140 | LibHandle := LoadLibrary(shell32) ; |
2123 | try |
2141 | try |
2124 | if LibHandle <> 0 then |
2142 | if LibHandle <> 0 then |
2125 | begin |
2143 | begin |
2126 | @PSHEmptyRecycleBin:= GetProcAddress(LibHandle, C_SHEmptyRecycleBinA); |
2144 | @PSHEmptyRecycleBin:= GetProcAddress(LibHandle, C_SHEmptyRecycleBin); |
2127 | if @PSHEmptyRecycleBin <> nil then |
2145 | if @PSHEmptyRecycleBin <> nil then |
2128 | begin |
2146 | begin |
2129 | PSHEmptyRecycleBin(hInstance, nil, flags); |
2147 | PSHEmptyRecycleBin(hInstance, nil, flags); |
2130 | end |
2148 | end |
2131 | else |
2149 | else |
Line 2908... | Line 2926... | ||
2908 | begin |
2926 | begin |
2909 | result := RecyclerGetAPIInfo(Drive + ':\'); |
2927 | result := RecyclerGetAPIInfo(Drive + ':\'); |
2910 | end; |
2928 | end; |
2911 | 2929 | ||
2912 | const |
2930 | const |
- | 2931 | {$IFDEF UNICODE} |
|
- | 2932 | C_SHQueryRecycleBin = 'SHQueryRecycleBinW'; |
|
- | 2933 | {$ELSE} |
|
2913 | C_SHQueryRecycleBin = 'SHQueryRecycleBinA'; |
2934 | C_SHQueryRecycleBin = 'SHQueryRecycleBinA'; |
- | 2935 | {$ENDIF} |
|
2914 | 2936 | ||
2915 | type |
2937 | type |
2916 | TSHQueryRecycleBin = function(pszRootPath: LPCTSTR; |
2938 | TSHQueryRecycleBin = function(pszRootPath: LPCTSTR; |
2917 | var pSHQueryRBInfo: TSHQueryRBInfo): HRESULT; stdcall; |
2939 | var pSHQueryRBInfo: TSHQueryRBInfo): HRESULT; stdcall; |
2918 | 2940 | ||
Line 2950... | Line 2972... | ||
2950 | end |
2972 | end |
2951 | else |
2973 | else |
2952 | begin |
2974 | begin |
2953 | // Since Windows Vista, SHQueryRecycleBin will fail with E_FAIL (80004005) |
2975 | // Since Windows Vista, SHQueryRecycleBin will fail with E_FAIL (80004005) |
2954 | // if Path is a floppy or CD drive... |
2976 | // if Path is a floppy or CD drive... |
2955 | // Windows 10: Error 0x8007003 for Path 'C:\' |
- | |
2956 | raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_ERROR_CODE, [C_SHQueryRecycleBin, Path, '0x'+IntToHex(res, 2*SizeOf(HRESULT))])]); |
2977 | raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_ERROR_CODE, [C_SHQueryRecycleBin, Path, '0x'+IntToHex(res, 2*SizeOf(HRESULT))])]); |
2957 | end; |
2978 | end; |
2958 | end |
2979 | end |
2959 | else |
2980 | else |
2960 | raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_NOT_CALLABLE, [C_SHQueryRecycleBin])]); |
2981 | raise EAPICallError.CreateFmt(LNG_API_CALL_ERROR, [Format(LNG_NOT_CALLABLE, [C_SHQueryRecycleBin])]); |
Line 3138... | Line 3159... | ||
3138 | result := typ = DRIVE_FIXED; |
3159 | result := typ = DRIVE_FIXED; |
3139 | end; |
3160 | end; |
3140 | 3161 | ||
3141 | function RecyclerLibraryVersion: string; |
3162 | function RecyclerLibraryVersion: string; |
3142 | begin |
3163 | begin |
3143 | result := 'ViaThinkSoft Recycle Bin Unit [01 JUL 2016]'; |
3164 | result := 'ViaThinkSoft Recycle Bin Unit [30 JUN 2022]'; |
3144 | end; |
3165 | end; |
3145 | 3166 | ||
3146 | end. |
3167 | end. |