diff options
author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2024-11-29 00:00:00 +0000 |
---|---|---|
committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2024-11-30 15:27:15 +0500 |
commit | e5431fa6f5505e385c6f9367260717e9c47dc2ee (patch) | |
tree | 4cd2c2c3b225b48c8e7053432c41d7b6b6a3d5f8 /CPP/Windows | |
parent | e008ce3976c087bfd21344af8f00a23cf69d4174 (diff) | |
download | 7zip-main.tar.gz 7zip-main.tar.bz2 7zip-main.zip |
Diffstat (limited to 'CPP/Windows')
-rw-r--r-- | CPP/Windows/FileDir.cpp | 138 | ||||
-rw-r--r-- | CPP/Windows/FileDir.h | 23 | ||||
-rw-r--r-- | CPP/Windows/FileName.cpp | 8 | ||||
-rw-r--r-- | CPP/Windows/Registry.cpp | 295 | ||||
-rw-r--r-- | CPP/Windows/Registry.h | 48 | ||||
-rw-r--r-- | CPP/Windows/System.cpp | 41 | ||||
-rw-r--r-- | CPP/Windows/System.h | 2 | ||||
-rw-r--r-- | CPP/Windows/SystemInfo.cpp | 125 | ||||
-rw-r--r-- | CPP/Windows/SystemInfo.h | 2 |
9 files changed, 484 insertions, 198 deletions
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp index dfeed82..2cb83b2 100644 --- a/CPP/Windows/FileDir.cpp +++ b/CPP/Windows/FileDir.cpp | |||
@@ -15,8 +15,9 @@ | |||
15 | #include <sys/stat.h> | 15 | #include <sys/stat.h> |
16 | #include <sys/types.h> | 16 | #include <sys/types.h> |
17 | 17 | ||
18 | #include "../Common/StringConvert.h" | ||
19 | #include "../Common/C_FileIO.h" | 18 | #include "../Common/C_FileIO.h" |
19 | #include "../Common/MyBuffer2.h" | ||
20 | #include "../Common/StringConvert.h" | ||
20 | #endif | 21 | #endif |
21 | 22 | ||
22 | #include "FileDir.h" | 23 | #include "FileDir.h" |
@@ -222,6 +223,8 @@ bool RemoveDir(CFSTR path) | |||
222 | } | 223 | } |
223 | 224 | ||
224 | 225 | ||
226 | // When moving a directory, oldFile and newFile must be on the same drive. | ||
227 | |||
225 | bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | 228 | bool MyMoveFile(CFSTR oldFile, CFSTR newFile) |
226 | { | 229 | { |
227 | #ifndef _UNICODE | 230 | #ifndef _UNICODE |
@@ -250,6 +253,59 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | |||
250 | return false; | 253 | return false; |
251 | } | 254 | } |
252 | 255 | ||
256 | #if defined(Z7_WIN32_WINNT_MIN) && Z7_WIN32_WINNT_MIN >= 0x0500 | ||
257 | static DWORD WINAPI CopyProgressRoutine_to_ICopyFileProgress( | ||
258 | LARGE_INTEGER TotalFileSize, // file size | ||
259 | LARGE_INTEGER TotalBytesTransferred, // bytes transferred | ||
260 | LARGE_INTEGER /* StreamSize */, // bytes in stream | ||
261 | LARGE_INTEGER /* StreamBytesTransferred */, // bytes transferred for stream | ||
262 | DWORD /* dwStreamNumber */, // current stream | ||
263 | DWORD /* dwCallbackReason */, // callback reason | ||
264 | HANDLE /* hSourceFile */, // handle to source file | ||
265 | HANDLE /* hDestinationFile */, // handle to destination file | ||
266 | LPVOID lpData // from CopyFileEx | ||
267 | ) | ||
268 | { | ||
269 | return ((ICopyFileProgress *)lpData)->CopyFileProgress( | ||
270 | (UInt64)TotalFileSize.QuadPart, | ||
271 | (UInt64)TotalBytesTransferred.QuadPart); | ||
272 | } | ||
273 | #endif | ||
274 | |||
275 | bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile, | ||
276 | ICopyFileProgress *progress) | ||
277 | { | ||
278 | #if defined(Z7_WIN32_WINNT_MIN) && Z7_WIN32_WINNT_MIN >= 0x0500 | ||
279 | #ifndef _UNICODE | ||
280 | if (g_IsNT) | ||
281 | #endif | ||
282 | if (progress) | ||
283 | { | ||
284 | IF_USE_MAIN_PATH_2(oldFile, newFile) | ||
285 | { | ||
286 | if (::MoveFileWithProgressW(fs2us(oldFile), fs2us(newFile), | ||
287 | CopyProgressRoutine_to_ICopyFileProgress, progress, MOVEFILE_COPY_ALLOWED)) | ||
288 | return true; | ||
289 | if (::GetLastError() == ERROR_REQUEST_ABORTED) | ||
290 | return false; | ||
291 | } | ||
292 | #ifdef Z7_LONG_PATH | ||
293 | if (USE_SUPER_PATH_2) | ||
294 | { | ||
295 | UString d1, d2; | ||
296 | if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2)) | ||
297 | return BOOLToBool(::MoveFileWithProgressW(d1, d2, | ||
298 | CopyProgressRoutine_to_ICopyFileProgress, progress, MOVEFILE_COPY_ALLOWED)); | ||
299 | } | ||
300 | #endif | ||
301 | return false; | ||
302 | } | ||
303 | #else | ||
304 | UNUSED_VAR(progress) | ||
305 | #endif | ||
306 | return MyMoveFile(oldFile, newFile); | ||
307 | } | ||
308 | |||
253 | #ifndef UNDER_CE | 309 | #ifndef UNDER_CE |
254 | #if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // Win2000 | 310 | #if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // Win2000 |
255 | #define Z7_USE_DYN_CreateHardLink | 311 | #define Z7_USE_DYN_CreateHardLink |
@@ -878,9 +934,9 @@ bool CTempFile::Remove() | |||
878 | return !_mustBeDeleted; | 934 | return !_mustBeDeleted; |
879 | } | 935 | } |
880 | 936 | ||
881 | bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) | 937 | bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore, |
938 | ICopyFileProgress *progress) | ||
882 | { | 939 | { |
883 | // DWORD attrib = 0; | ||
884 | if (deleteDestBefore) | 940 | if (deleteDestBefore) |
885 | { | 941 | { |
886 | if (NFind::DoesFileExist_Raw(name)) | 942 | if (NFind::DoesFileExist_Raw(name)) |
@@ -891,8 +947,8 @@ bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) | |||
891 | } | 947 | } |
892 | } | 948 | } |
893 | DisableDeleting(); | 949 | DisableDeleting(); |
894 | return MyMoveFile(_path, name); | 950 | // if (!progress) return MyMoveFile(_path, name); |
895 | 951 | return MyMoveFile_with_Progress(_path, name, progress); | |
896 | /* | 952 | /* |
897 | if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) | 953 | if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) |
898 | { | 954 | { |
@@ -941,34 +997,59 @@ bool RemoveDir(CFSTR path) | |||
941 | } | 997 | } |
942 | 998 | ||
943 | 999 | ||
944 | static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile) | 1000 | static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile, ICopyFileProgress *progress) |
945 | { | 1001 | { |
946 | NWindows::NFile::NIO::COutFile outFile; | ||
947 | if (!outFile.Create_NEW(newFile)) | ||
948 | return FALSE; | ||
949 | |||
950 | NWindows::NFile::NIO::CInFile inFile; | ||
951 | if (!inFile.Open(oldFile)) | ||
952 | return FALSE; | ||
953 | |||
954 | char buf[1 << 14]; | ||
955 | |||
956 | for (;;) | ||
957 | { | 1002 | { |
958 | const ssize_t num = inFile.read_part(buf, sizeof(buf)); | 1003 | NIO::COutFile outFile; |
959 | if (num == 0) | 1004 | if (!outFile.Create_NEW(newFile)) |
960 | return TRUE; | ||
961 | if (num < 0) | ||
962 | return FALSE; | 1005 | return FALSE; |
963 | size_t processed; | 1006 | NIO::CInFile inFile; |
964 | const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed); | 1007 | if (!inFile.Open(oldFile)) |
965 | if (num2 != num || processed != (size_t)num) | ||
966 | return FALSE; | 1008 | return FALSE; |
1009 | |||
1010 | const size_t k_BufSize = 1 << 16; | ||
1011 | CAlignedBuffer1 buf(k_BufSize); | ||
1012 | |||
1013 | UInt64 length = 0; | ||
1014 | if (progress && !inFile.GetLength(length)) | ||
1015 | length = 0; | ||
1016 | UInt64 prev = 0; | ||
1017 | UInt64 cur = 0; | ||
1018 | for (;;) | ||
1019 | { | ||
1020 | const ssize_t num = inFile.read_part(buf, k_BufSize); | ||
1021 | if (num == 0) | ||
1022 | return TRUE; | ||
1023 | if (num < 0) | ||
1024 | break; | ||
1025 | size_t processed; | ||
1026 | const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed); | ||
1027 | if (num2 != num || processed != (size_t)num) | ||
1028 | break; | ||
1029 | cur += (size_t)num2; | ||
1030 | if (progress && cur - prev >= (1u << 20)) | ||
1031 | { | ||
1032 | prev = cur; | ||
1033 | if (progress->CopyFileProgress(length, cur) != PROGRESS_CONTINUE) | ||
1034 | { | ||
1035 | errno = EINTR; // instead of WIN32::ERROR_REQUEST_ABORTED | ||
1036 | break; | ||
1037 | } | ||
1038 | } | ||
1039 | } | ||
967 | } | 1040 | } |
1041 | // There is file IO error or process was interrupted by user. | ||
1042 | // We close output file and delete it. | ||
1043 | // DeleteFileAlways doesn't change errno (if successed), but we restore errno. | ||
1044 | const int errno_save = errno; | ||
1045 | DeleteFileAlways(newFile); | ||
1046 | errno = errno_save; | ||
1047 | return FALSE; | ||
968 | } | 1048 | } |
969 | 1049 | ||
970 | 1050 | ||
971 | bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | 1051 | bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile, |
1052 | ICopyFileProgress *progress) | ||
972 | { | 1053 | { |
973 | int res = rename(oldFile, newFile); | 1054 | int res = rename(oldFile, newFile); |
974 | if (res == 0) | 1055 | if (res == 0) |
@@ -976,7 +1057,7 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | |||
976 | if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem) | 1057 | if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem) |
977 | return false; | 1058 | return false; |
978 | 1059 | ||
979 | if (My_CopyFile(oldFile, newFile) == FALSE) | 1060 | if (My_CopyFile(oldFile, newFile, progress) == FALSE) |
980 | return false; | 1061 | return false; |
981 | 1062 | ||
982 | struct stat info_file; | 1063 | struct stat info_file; |
@@ -990,6 +1071,11 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | |||
990 | return (unlink(oldFile) == 0); | 1071 | return (unlink(oldFile) == 0); |
991 | } | 1072 | } |
992 | 1073 | ||
1074 | bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | ||
1075 | { | ||
1076 | return MyMoveFile_with_Progress(oldFile, newFile, NULL); | ||
1077 | } | ||
1078 | |||
993 | 1079 | ||
994 | bool CreateDir(CFSTR path) | 1080 | bool CreateDir(CFSTR path) |
995 | { | 1081 | { |
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h index 573ffa2..74675ee 100644 --- a/CPP/Windows/FileDir.h +++ b/CPP/Windows/FileDir.h | |||
@@ -41,7 +41,26 @@ int my_chown(CFSTR path, uid_t owner, gid_t group); | |||
41 | bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib); | 41 | bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib); |
42 | 42 | ||
43 | 43 | ||
44 | #ifndef _WIN32 | ||
45 | #define PROGRESS_CONTINUE 0 | ||
46 | #define PROGRESS_CANCEL 1 | ||
47 | // #define PROGRESS_STOP 2 | ||
48 | // #define PROGRESS_QUIET 3 | ||
49 | #endif | ||
50 | Z7_PURE_INTERFACES_BEGIN | ||
51 | DECLARE_INTERFACE(ICopyFileProgress) | ||
52 | { | ||
53 | // in: total, current: include all/processed alt streams. | ||
54 | // it returns PROGRESS_CONTINUE or PROGRESS_CANCEL. | ||
55 | virtual DWORD CopyFileProgress(UInt64 total, UInt64 current) = 0; | ||
56 | }; | ||
57 | Z7_PURE_INTERFACES_END | ||
58 | |||
44 | bool MyMoveFile(CFSTR existFileName, CFSTR newFileName); | 59 | bool MyMoveFile(CFSTR existFileName, CFSTR newFileName); |
60 | // (progress == NULL) is allowed | ||
61 | bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile, | ||
62 | ICopyFileProgress *progress); | ||
63 | |||
45 | 64 | ||
46 | #ifndef UNDER_CE | 65 | #ifndef UNDER_CE |
47 | bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName); | 66 | bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName); |
@@ -87,7 +106,9 @@ public: | |||
87 | bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix | 106 | bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix |
88 | bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile); | 107 | bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile); |
89 | bool Remove(); | 108 | bool Remove(); |
90 | bool MoveTo(CFSTR name, bool deleteDestBefore); | 109 | // bool MoveTo(CFSTR name, bool deleteDestBefore); |
110 | bool MoveTo(CFSTR name, bool deleteDestBefore, | ||
111 | ICopyFileProgress *progress); | ||
91 | }; | 112 | }; |
92 | 113 | ||
93 | 114 | ||
diff --git a/CPP/Windows/FileName.cpp b/CPP/Windows/FileName.cpp index c16b3d4..1f4a6da 100644 --- a/CPP/Windows/FileName.cpp +++ b/CPP/Windows/FileName.cpp | |||
@@ -278,12 +278,14 @@ bool IsAbsolutePath(const wchar_t *s) throw() | |||
278 | int FindAltStreamColon(CFSTR path) throw() | 278 | int FindAltStreamColon(CFSTR path) throw() |
279 | { | 279 | { |
280 | unsigned i = 0; | 280 | unsigned i = 0; |
281 | if (IsDrivePath2(path)) | 281 | if (IsSuperPath(path)) |
282 | i = 2; | 282 | i = kSuperPathPrefixSize; |
283 | if (IsDrivePath2(path + i)) | ||
284 | i += 2; | ||
283 | int colonPos = -1; | 285 | int colonPos = -1; |
284 | for (;; i++) | 286 | for (;; i++) |
285 | { | 287 | { |
286 | FChar c = path[i]; | 288 | const FChar c = path[i]; |
287 | if (c == 0) | 289 | if (c == 0) |
288 | return colonPos; | 290 | return colonPos; |
289 | if (c == ':') | 291 | if (c == ':') |
diff --git a/CPP/Windows/Registry.cpp b/CPP/Windows/Registry.cpp index c8b1709..a94a50f 100644 --- a/CPP/Windows/Registry.cpp +++ b/CPP/Windows/Registry.cpp | |||
@@ -78,7 +78,7 @@ LONG CKey::Close() throw() | |||
78 | return res; | 78 | return res; |
79 | } | 79 | } |
80 | 80 | ||
81 | // win95, win98: deletes sunkey and all its subkeys | 81 | // win95, win98: deletes subkey and all its subkeys |
82 | // winNT to be deleted must not have subkeys | 82 | // winNT to be deleted must not have subkeys |
83 | LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw() | 83 | LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw() |
84 | { | 84 | { |
@@ -88,22 +88,36 @@ LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw() | |||
88 | 88 | ||
89 | LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw() | 89 | LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw() |
90 | { | 90 | { |
91 | CKey key; | ||
92 | LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE); | ||
93 | if (res != ERROR_SUCCESS) | ||
94 | return res; | ||
95 | FILETIME fileTime; | ||
96 | const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL | ||
97 | DWORD size = kBufSize; | ||
98 | TCHAR buffer[kBufSize]; | ||
99 | while (RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime) == ERROR_SUCCESS) | ||
100 | { | 91 | { |
101 | res = key.RecurseDeleteKey(buffer); | 92 | CKey key; |
93 | LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE); | ||
102 | if (res != ERROR_SUCCESS) | 94 | if (res != ERROR_SUCCESS) |
103 | return res; | 95 | return res; |
104 | size = kBufSize; | 96 | FILETIME fileTime; |
97 | const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL | ||
98 | TCHAR buffer[kBufSize]; | ||
99 | // we use loop limit here for some unexpected code failure | ||
100 | for (unsigned loop_cnt = 0; loop_cnt < (1u << 26); loop_cnt++) | ||
101 | { | ||
102 | DWORD size = kBufSize; | ||
103 | // we always request starting item (index==0) in each iteration, | ||
104 | // because we remove starting item (index==0) in each loop iteration. | ||
105 | res = RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime); | ||
106 | if (res != ERROR_SUCCESS) | ||
107 | { | ||
108 | // possible return codes: | ||
109 | // ERROR_NO_MORE_ITEMS : are no more subkeys available | ||
110 | // ERROR_MORE_DATA : name buffer is too small | ||
111 | // we can try to remove (subKeyName), even if there is non ERROR_NO_MORE_ITEMS error. | ||
112 | // if (res != ERROR_NO_MORE_ITEMS) return res; | ||
113 | break; | ||
114 | } | ||
115 | res = key.RecurseDeleteKey(buffer); | ||
116 | if (res != ERROR_SUCCESS) | ||
117 | return res; | ||
118 | } | ||
119 | // key.Close(); | ||
105 | } | 120 | } |
106 | key.Close(); | ||
107 | return DeleteSubKey(subKeyName); | 121 | return DeleteSubKey(subKeyName); |
108 | } | 122 | } |
109 | 123 | ||
@@ -127,7 +141,7 @@ LONG CKey::DeleteValue(LPCWSTR name) | |||
127 | MY_ASSUME(_object != NULL); | 141 | MY_ASSUME(_object != NULL); |
128 | if (g_IsNT) | 142 | if (g_IsNT) |
129 | return ::RegDeleteValueW(_object, name); | 143 | return ::RegDeleteValueW(_object, name); |
130 | return DeleteValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name)); | 144 | return DeleteValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name)); |
131 | } | 145 | } |
132 | #endif | 146 | #endif |
133 | 147 | ||
@@ -143,12 +157,15 @@ LONG CKey::SetValue(LPCTSTR name, bool value) throw() | |||
143 | return SetValue(name, BoolToUINT32(value)); | 157 | return SetValue(name, BoolToUINT32(value)); |
144 | } | 158 | } |
145 | 159 | ||
160 | |||
161 | // value must be string that is NULL terminated | ||
146 | LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw() | 162 | LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw() |
147 | { | 163 | { |
148 | MYASSERT(value != NULL); | 164 | MYASSERT(value != NULL); |
149 | MY_ASSUME(_object != NULL); | 165 | MY_ASSUME(_object != NULL); |
166 | // note: RegSetValueEx supports (value == NULL), if (cbData == 0) | ||
150 | return RegSetValueEx(_object, name, 0, REG_SZ, | 167 | return RegSetValueEx(_object, name, 0, REG_SZ, |
151 | (const BYTE *)value, ((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)); | 168 | (const BYTE *)value, (DWORD)(((DWORD)lstrlen(value) + 1) * sizeof(TCHAR))); |
152 | } | 169 | } |
153 | 170 | ||
154 | /* | 171 | /* |
@@ -156,7 +173,7 @@ LONG CKey::SetValue(LPCTSTR name, const CSysString &value) | |||
156 | { | 173 | { |
157 | MYASSERT(value != NULL); | 174 | MYASSERT(value != NULL); |
158 | MY_ASSUME(_object != NULL); | 175 | MY_ASSUME(_object != NULL); |
159 | return RegSetValueEx(_object, name, NULL, REG_SZ, | 176 | return RegSetValueEx(_object, name, 0, REG_SZ, |
160 | (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR)); | 177 | (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR)); |
161 | } | 178 | } |
162 | */ | 179 | */ |
@@ -169,9 +186,10 @@ LONG CKey::SetValue(LPCWSTR name, LPCWSTR value) | |||
169 | MY_ASSUME(_object != NULL); | 186 | MY_ASSUME(_object != NULL); |
170 | if (g_IsNT) | 187 | if (g_IsNT) |
171 | return RegSetValueExW(_object, name, 0, REG_SZ, | 188 | return RegSetValueExW(_object, name, 0, REG_SZ, |
172 | (const BYTE * )value, (DWORD)((wcslen(value) + 1) * sizeof(wchar_t))); | 189 | (const BYTE *)value, (DWORD)(((DWORD)wcslen(value) + 1) * sizeof(wchar_t))); |
173 | return SetValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), | 190 | return SetValue(name == NULL ? NULL : |
174 | value == 0 ? 0 : (LPCSTR)GetSystemString(value)); | 191 | (LPCSTR)GetSystemString(name), |
192 | (LPCSTR)GetSystemString(value)); | ||
175 | } | 193 | } |
176 | 194 | ||
177 | #endif | 195 | #endif |
@@ -205,99 +223,137 @@ LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw( | |||
205 | return res; | 223 | return res; |
206 | } | 224 | } |
207 | 225 | ||
208 | LONG CKey::QueryValue(LPCTSTR name, UInt32 &value) throw() | ||
209 | { | ||
210 | DWORD type = 0; | ||
211 | DWORD count = sizeof(DWORD); | ||
212 | LONG res = RegQueryValueEx(_object, name, NULL, &type, | ||
213 | (LPBYTE)&value, &count); | ||
214 | MYASSERT((res != ERROR_SUCCESS) || (type == REG_DWORD)); | ||
215 | MYASSERT((res != ERROR_SUCCESS) || (count == sizeof(UInt32))); | ||
216 | return res; | ||
217 | } | ||
218 | 226 | ||
219 | LONG CKey::QueryValue(LPCTSTR name, bool &value) throw() | 227 | LONG CKey::GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw() |
220 | { | 228 | { |
221 | UInt32 uintValue = BoolToUINT32(value); | 229 | DWORD type = 0; |
222 | LONG res = QueryValue(name, uintValue); | 230 | DWORD count = sizeof(value); |
223 | value = UINT32ToBool(uintValue); | 231 | UInt32 value2; // = value; |
232 | const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count); | ||
233 | if (res == ERROR_SUCCESS) | ||
234 | { | ||
235 | // ERROR_UNSUPPORTED_TYPE | ||
236 | if (count != sizeof(value) || type != REG_DWORD) | ||
237 | return ERROR_UNSUPPORTED_TYPE; // ERROR_INVALID_DATA; | ||
238 | value = value2; | ||
239 | } | ||
224 | return res; | 240 | return res; |
225 | } | 241 | } |
226 | 242 | ||
227 | LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value) throw() | 243 | LONG CKey::GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw() |
228 | { | 244 | { |
229 | UInt32 newVal; | 245 | DWORD type = 0; |
230 | LONG res = QueryValue(name, newVal); | 246 | DWORD count = sizeof(value); |
247 | UInt64 value2; // = value; | ||
248 | const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count); | ||
231 | if (res == ERROR_SUCCESS) | 249 | if (res == ERROR_SUCCESS) |
232 | value = newVal; | 250 | { |
251 | if (count != sizeof(value) || type != REG_QWORD) | ||
252 | return ERROR_UNSUPPORTED_TYPE; | ||
253 | value = value2; | ||
254 | } | ||
233 | return res; | 255 | return res; |
234 | } | 256 | } |
235 | 257 | ||
236 | LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw() | 258 | LONG CKey::GetValue_bool_IfOk(LPCTSTR name, bool &value) throw() |
237 | { | 259 | { |
238 | bool newVal = false; | 260 | UInt32 uintValue; |
239 | LONG res = QueryValue(name, newVal); | 261 | const LONG res = GetValue_UInt32_IfOk(name, uintValue); |
240 | if (res == ERROR_SUCCESS) | 262 | if (res == ERROR_SUCCESS) |
241 | value = newVal; | 263 | value = UINT32ToBool(uintValue); |
242 | return res; | 264 | return res; |
243 | } | 265 | } |
244 | 266 | ||
245 | LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count) throw() | 267 | |
246 | { | ||
247 | DWORD type = 0; | ||
248 | LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); | ||
249 | MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); | ||
250 | return res; | ||
251 | } | ||
252 | 268 | ||
253 | LONG CKey::QueryValue(LPCTSTR name, CSysString &value) | 269 | LONG CKey::QueryValue(LPCTSTR name, CSysString &value) |
254 | { | 270 | { |
255 | value.Empty(); | 271 | value.Empty(); |
256 | DWORD type = 0; | 272 | LONG res = ERROR_SUCCESS; |
257 | DWORD curSize = 0; | 273 | { |
258 | LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, &curSize); | 274 | // if we don't want multiple calls here, |
259 | if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) | 275 | // we can use big value (264) here. |
260 | return res; | 276 | // 3 is default available length in new string. |
261 | UInt32 curSize2 = curSize; | 277 | DWORD size_prev = 3 * sizeof(TCHAR); |
262 | res = QueryValue(name, value.GetBuf(curSize), curSize2); | 278 | // at least 2 attempts are required. But we use more attempts for cases, |
263 | if (curSize > curSize2) | 279 | // where string can be changed by anothner process |
264 | curSize = curSize2; | 280 | for (unsigned i = 0; i < 2 + 2; i++) |
265 | value.ReleaseBuf_CalcLen(curSize / sizeof(TCHAR)); | 281 | { |
282 | DWORD type = 0; | ||
283 | DWORD size = size_prev; | ||
284 | { | ||
285 | LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(TCHAR)); | ||
286 | res = QueryValueEx(name, &type, size == 0 ? NULL : buf, &size); | ||
287 | // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size. | ||
288 | } | ||
289 | if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) | ||
290 | { | ||
291 | if (type != REG_SZ && type != REG_EXPAND_SZ) | ||
292 | { | ||
293 | res = ERROR_UNSUPPORTED_TYPE; | ||
294 | size = 0; | ||
295 | } | ||
296 | } | ||
297 | else | ||
298 | size = 0; | ||
299 | if (size > size_prev) | ||
300 | { | ||
301 | size_prev = size; | ||
302 | size = 0; | ||
303 | res = ERROR_MORE_DATA; | ||
304 | } | ||
305 | value.ReleaseBuf_CalcLen(size / sizeof(TCHAR)); | ||
306 | if (res != ERROR_MORE_DATA) | ||
307 | return res; | ||
308 | } | ||
309 | } | ||
266 | return res; | 310 | return res; |
267 | } | 311 | } |
268 | 312 | ||
269 | 313 | ||
270 | #ifndef _UNICODE | 314 | #ifndef _UNICODE |
271 | 315 | ||
272 | LONG CKey::QueryValue(LPCWSTR name, LPWSTR value, UInt32 &count) | ||
273 | { | ||
274 | DWORD type = 0; | ||
275 | LONG res = RegQueryValueExW(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); | ||
276 | MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); | ||
277 | return res; | ||
278 | } | ||
279 | |||
280 | LONG CKey::QueryValue(LPCWSTR name, UString &value) | 316 | LONG CKey::QueryValue(LPCWSTR name, UString &value) |
281 | { | 317 | { |
282 | value.Empty(); | 318 | value.Empty(); |
283 | DWORD type = 0; | 319 | LONG res = ERROR_SUCCESS; |
284 | DWORD curSize = 0; | ||
285 | LONG res; | ||
286 | if (g_IsNT) | 320 | if (g_IsNT) |
287 | { | 321 | { |
288 | res = RegQueryValueExW(_object, name, NULL, &type, NULL, &curSize); | 322 | DWORD size_prev = 3 * sizeof(wchar_t); |
289 | if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) | 323 | for (unsigned i = 0; i < 2 + 2; i++) |
290 | return res; | 324 | { |
291 | UInt32 curSize2 = curSize; | 325 | DWORD type = 0; |
292 | res = QueryValue(name, value.GetBuf(curSize), curSize2); | 326 | DWORD size = size_prev; |
293 | if (curSize > curSize2) | 327 | { |
294 | curSize = curSize2; | 328 | LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(wchar_t)); |
295 | value.ReleaseBuf_CalcLen(curSize / sizeof(wchar_t)); | 329 | res = RegQueryValueExW(_object, name, NULL, &type, |
330 | size == 0 ? NULL : buf, &size); | ||
331 | } | ||
332 | if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) | ||
333 | { | ||
334 | if (type != REG_SZ && type != REG_EXPAND_SZ) | ||
335 | { | ||
336 | res = ERROR_UNSUPPORTED_TYPE; | ||
337 | size = 0; | ||
338 | } | ||
339 | } | ||
340 | else | ||
341 | size = 0; | ||
342 | if (size > size_prev) | ||
343 | { | ||
344 | size_prev = size; | ||
345 | size = 0; | ||
346 | res = ERROR_MORE_DATA; | ||
347 | } | ||
348 | value.ReleaseBuf_CalcLen(size / sizeof(wchar_t)); | ||
349 | if (res != ERROR_MORE_DATA) | ||
350 | return res; | ||
351 | } | ||
296 | } | 352 | } |
297 | else | 353 | else |
298 | { | 354 | { |
299 | AString vTemp; | 355 | AString vTemp; |
300 | res = QueryValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), vTemp); | 356 | res = QueryValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name), vTemp); |
301 | value = GetUnicodeString(vTemp); | 357 | value = GetUnicodeString(vTemp); |
302 | } | 358 | } |
303 | return res; | 359 | return res; |
@@ -306,26 +362,43 @@ LONG CKey::QueryValue(LPCWSTR name, UString &value) | |||
306 | #endif | 362 | #endif |
307 | 363 | ||
308 | 364 | ||
309 | LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count) throw() | 365 | LONG CKey::QueryValue_Binary(LPCTSTR name, CByteBuffer &value) |
310 | { | 366 | { |
311 | DWORD type = 0; | 367 | // value.Free(); |
312 | LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); | 368 | DWORD size_prev = 0; |
313 | MYASSERT((res != ERROR_SUCCESS) || (type == REG_BINARY)); | 369 | LONG res = ERROR_SUCCESS; |
370 | for (unsigned i = 0; i < 2 + 2; i++) | ||
371 | { | ||
372 | DWORD type = 0; | ||
373 | DWORD size = size_prev; | ||
374 | value.Alloc(size_prev); | ||
375 | res = QueryValueEx(name, &type, value.NonConstData(), &size); | ||
376 | // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size. | ||
377 | if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) | ||
378 | { | ||
379 | if (type != REG_BINARY) | ||
380 | { | ||
381 | res = ERROR_UNSUPPORTED_TYPE; | ||
382 | size = 0; | ||
383 | } | ||
384 | } | ||
385 | else | ||
386 | size = 0; | ||
387 | if (size > size_prev) | ||
388 | { | ||
389 | size_prev = size; | ||
390 | size = 0; | ||
391 | res = ERROR_MORE_DATA; | ||
392 | } | ||
393 | if (size < value.Size()) | ||
394 | value.ChangeSize_KeepData(size, size); | ||
395 | if (res != ERROR_MORE_DATA) | ||
396 | return res; | ||
397 | } | ||
314 | return res; | 398 | return res; |
315 | } | 399 | } |
316 | 400 | ||
317 | 401 | ||
318 | LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize) | ||
319 | { | ||
320 | DWORD type = 0; | ||
321 | dataSize = 0; | ||
322 | LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&dataSize); | ||
323 | if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) | ||
324 | return res; | ||
325 | value.Alloc(dataSize); | ||
326 | return QueryValue(name, (BYTE *)value, dataSize); | ||
327 | } | ||
328 | |||
329 | LONG CKey::EnumKeys(CSysStringVector &keyNames) | 402 | LONG CKey::EnumKeys(CSysStringVector &keyNames) |
330 | { | 403 | { |
331 | keyNames.Clear(); | 404 | keyNames.Clear(); |
@@ -334,23 +407,23 @@ LONG CKey::EnumKeys(CSysStringVector &keyNames) | |||
334 | { | 407 | { |
335 | const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL | 408 | const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL |
336 | FILETIME lastWriteTime; | 409 | FILETIME lastWriteTime; |
337 | UInt32 nameSize = kBufSize; | 410 | DWORD nameSize = kBufSize; |
338 | LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuf(kBufSize), | 411 | const LONG res = ::RegEnumKeyEx(_object, index, |
339 | (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime); | 412 | keyName.GetBuf(kBufSize), &nameSize, |
413 | NULL, NULL, NULL, &lastWriteTime); | ||
340 | keyName.ReleaseBuf_CalcLen(kBufSize); | 414 | keyName.ReleaseBuf_CalcLen(kBufSize); |
341 | if (result == ERROR_NO_MORE_ITEMS) | 415 | if (res == ERROR_NO_MORE_ITEMS) |
342 | break; | 416 | return ERROR_SUCCESS; |
343 | if (result != ERROR_SUCCESS) | 417 | if (res != ERROR_SUCCESS) |
344 | return result; | 418 | return res; |
345 | keyNames.Add(keyName); | 419 | keyNames.Add(keyName); |
346 | } | 420 | } |
347 | return ERROR_SUCCESS; | ||
348 | } | 421 | } |
349 | 422 | ||
423 | |||
350 | LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings) | 424 | LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings) |
351 | { | 425 | { |
352 | size_t numChars = 0; | 426 | size_t numChars = 0; |
353 | |||
354 | unsigned i; | 427 | unsigned i; |
355 | 428 | ||
356 | for (i = 0; i < strings.Size(); i++) | 429 | for (i = 0; i < strings.Size(); i++) |
@@ -362,10 +435,11 @@ LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings) | |||
362 | for (i = 0; i < strings.Size(); i++) | 435 | for (i = 0; i < strings.Size(); i++) |
363 | { | 436 | { |
364 | const UString &s = strings[i]; | 437 | const UString &s = strings[i]; |
365 | size_t size = s.Len() + 1; | 438 | const size_t size = s.Len() + 1; |
366 | wmemcpy(buffer + pos, s, size); | 439 | wmemcpy(buffer + pos, s, size); |
367 | pos += size; | 440 | pos += size; |
368 | } | 441 | } |
442 | // if (pos != numChars) return E_FAIL; | ||
369 | return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t)); | 443 | return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t)); |
370 | } | 444 | } |
371 | 445 | ||
@@ -373,20 +447,18 @@ LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings) | |||
373 | { | 447 | { |
374 | strings.Clear(); | 448 | strings.Clear(); |
375 | CByteBuffer buffer; | 449 | CByteBuffer buffer; |
376 | UInt32 dataSize = 0; | 450 | const LONG res = QueryValue_Binary(valueName, buffer); |
377 | const LONG res = QueryValue(valueName, buffer, dataSize); | ||
378 | if (res != ERROR_SUCCESS) | 451 | if (res != ERROR_SUCCESS) |
379 | return res; | 452 | return res; |
380 | if (dataSize > buffer.Size()) | 453 | const size_t dataSize = buffer.Size(); |
381 | return E_FAIL; | 454 | if (dataSize % sizeof(wchar_t)) |
382 | if (dataSize % sizeof(wchar_t) != 0) | 455 | return ERROR_INVALID_DATA; |
383 | return E_FAIL; | ||
384 | |||
385 | const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer; | 456 | const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer; |
386 | const size_t numChars = dataSize / sizeof(wchar_t); | 457 | const size_t numChars = dataSize / sizeof(wchar_t); |
458 | // we can check that all names are finished | ||
459 | // if (numChars != 0 && data[numChars - 1] != 0) return ERROR_INVALID_DATA; | ||
387 | size_t prev = 0; | 460 | size_t prev = 0; |
388 | UString s; | 461 | UString s; |
389 | |||
390 | for (size_t i = 0; i < numChars; i++) | 462 | for (size_t i = 0; i < numChars; i++) |
391 | { | 463 | { |
392 | if (data[i] == 0) | 464 | if (data[i] == 0) |
@@ -396,7 +468,6 @@ LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings) | |||
396 | prev = i + 1; | 468 | prev = i + 1; |
397 | } | 469 | } |
398 | } | 470 | } |
399 | |||
400 | return res; | 471 | return res; |
401 | } | 472 | } |
402 | 473 | ||
diff --git a/CPP/Windows/Registry.h b/CPP/Windows/Registry.h index 0d3b4fc..74ee919 100644 --- a/CPP/Windows/Registry.h +++ b/CPP/Windows/Registry.h | |||
@@ -14,6 +14,13 @@ LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) | |||
14 | class CKey | 14 | class CKey |
15 | { | 15 | { |
16 | HKEY _object; | 16 | HKEY _object; |
17 | |||
18 | LONG QueryValueEx(LPCTSTR lpValueName, LPDWORD lpType, | ||
19 | LPBYTE lpData, LPDWORD lpcbData) | ||
20 | { | ||
21 | return RegQueryValueEx(_object, lpValueName, NULL, lpType, lpData, lpcbData); | ||
22 | } | ||
23 | |||
17 | public: | 24 | public: |
18 | CKey(): _object(NULL) {} | 25 | CKey(): _object(NULL) {} |
19 | ~CKey() { Close(); } | 26 | ~CKey() { Close(); } |
@@ -22,13 +29,14 @@ public: | |||
22 | void Attach(HKEY key) { _object = key; } | 29 | void Attach(HKEY key) { _object = key; } |
23 | HKEY Detach() | 30 | HKEY Detach() |
24 | { | 31 | { |
25 | HKEY key = _object; | 32 | const HKEY key = _object; |
26 | _object = NULL; | 33 | _object = NULL; |
27 | return key; | 34 | return key; |
28 | } | 35 | } |
29 | 36 | ||
30 | LONG Create(HKEY parentKey, LPCTSTR keyName, | 37 | LONG Create(HKEY parentKey, LPCTSTR keyName, |
31 | LPTSTR keyClass = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE, | 38 | LPTSTR keyClass = REG_NONE, |
39 | DWORD options = REG_OPTION_NON_VOLATILE, | ||
32 | REGSAM accessMask = KEY_ALL_ACCESS, | 40 | REGSAM accessMask = KEY_ALL_ACCESS, |
33 | LPSECURITY_ATTRIBUTES securityAttributes = NULL, | 41 | LPSECURITY_ATTRIBUTES securityAttributes = NULL, |
34 | LPDWORD disposition = NULL) throw(); | 42 | LPDWORD disposition = NULL) throw(); |
@@ -40,18 +48,18 @@ public: | |||
40 | LONG RecurseDeleteKey(LPCTSTR subKeyName) throw(); | 48 | LONG RecurseDeleteKey(LPCTSTR subKeyName) throw(); |
41 | 49 | ||
42 | LONG DeleteValue(LPCTSTR name) throw(); | 50 | LONG DeleteValue(LPCTSTR name) throw(); |
43 | #ifndef _UNICODE | 51 | #ifndef _UNICODE |
44 | LONG DeleteValue(LPCWSTR name); | 52 | LONG DeleteValue(LPCWSTR name); |
45 | #endif | 53 | #endif |
46 | 54 | ||
47 | LONG SetValue(LPCTSTR valueName, UInt32 value) throw(); | 55 | LONG SetValue(LPCTSTR valueName, UInt32 value) throw(); |
48 | LONG SetValue(LPCTSTR valueName, bool value) throw(); | 56 | LONG SetValue(LPCTSTR valueName, bool value) throw(); |
49 | LONG SetValue(LPCTSTR valueName, LPCTSTR value) throw(); | 57 | LONG SetValue(LPCTSTR valueName, LPCTSTR value) throw(); |
50 | // LONG SetValue(LPCTSTR valueName, const CSysString &value); | 58 | // LONG SetValue(LPCTSTR valueName, const CSysString &value); |
51 | #ifndef _UNICODE | 59 | #ifndef _UNICODE |
52 | LONG SetValue(LPCWSTR name, LPCWSTR value); | 60 | LONG SetValue(LPCWSTR name, LPCWSTR value); |
53 | // LONG SetValue(LPCWSTR name, const UString &value); | 61 | // LONG SetValue(LPCWSTR name, const UString &value); |
54 | #endif | 62 | #endif |
55 | 63 | ||
56 | LONG SetValue(LPCTSTR name, const void *value, UInt32 size) throw(); | 64 | LONG SetValue(LPCTSTR name, const void *value, UInt32 size) throw(); |
57 | 65 | ||
@@ -60,21 +68,25 @@ public: | |||
60 | 68 | ||
61 | LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw(); | 69 | LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw(); |
62 | 70 | ||
63 | LONG QueryValue(LPCTSTR name, UInt32 &value) throw(); | 71 | // GetValue_[type]_IfOk(): |
64 | LONG QueryValue(LPCTSTR name, bool &value) throw(); | 72 | // if (return_result == ERROR_SUCCESS), (value) variable was read from registry |
65 | LONG QueryValue(LPCTSTR name, LPTSTR value, UInt32 &dataSize) throw(); | 73 | // if (return_result != ERROR_SUCCESS), (value) variable was not changed |
66 | LONG QueryValue(LPCTSTR name, CSysString &value); | 74 | LONG GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw(); |
67 | 75 | LONG GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw(); | |
68 | LONG GetValue_IfOk(LPCTSTR name, UInt32 &value) throw(); | 76 | LONG GetValue_bool_IfOk(LPCTSTR name, bool &value) throw(); |
69 | LONG GetValue_IfOk(LPCTSTR name, bool &value) throw(); | ||
70 | 77 | ||
71 | #ifndef _UNICODE | 78 | // QueryValue(): |
72 | LONG QueryValue(LPCWSTR name, LPWSTR value, UInt32 &dataSize); | 79 | // if (return_result == ERROR_SUCCESS), (value) string was read from registry |
80 | // if (return_result != ERROR_SUCCESS), (value) string was cleared | ||
81 | LONG QueryValue(LPCTSTR name, CSysString &value); | ||
82 | #ifndef _UNICODE | ||
73 | LONG QueryValue(LPCWSTR name, UString &value); | 83 | LONG QueryValue(LPCWSTR name, UString &value); |
74 | #endif | 84 | #endif |
75 | 85 | ||
76 | LONG QueryValue(LPCTSTR name, void *value, UInt32 &dataSize) throw(); | 86 | // QueryValue_Binary(): |
77 | LONG QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize); | 87 | // if (return_result == ERROR_SUCCESS), (value) buffer was read from registry (BINARY data) |
88 | // if (return_result != ERROR_SUCCESS), (value) buffer was cleared | ||
89 | LONG QueryValue_Binary(LPCTSTR name, CByteBuffer &value); | ||
78 | 90 | ||
79 | LONG EnumKeys(CSysStringVector &keyNames); | 91 | LONG EnumKeys(CSysStringVector &keyNames); |
80 | }; | 92 | }; |
diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp index 03c8988..5fa87f3 100644 --- a/CPP/Windows/System.cpp +++ b/CPP/Windows/System.cpp | |||
@@ -142,9 +142,9 @@ typedef BOOL (WINAPI *Func_GlobalMemoryStatusEx)(MY_LPMEMORYSTATUSEX lpBuffer); | |||
142 | #endif // !UNDER_CE | 142 | #endif // !UNDER_CE |
143 | 143 | ||
144 | 144 | ||
145 | bool GetRamSize(UInt64 &size) | 145 | bool GetRamSize(size_t &size) |
146 | { | 146 | { |
147 | size = (UInt64)(sizeof(size_t)) << 29; | 147 | size = (size_t)sizeof(size_t) << 29; |
148 | 148 | ||
149 | #ifndef UNDER_CE | 149 | #ifndef UNDER_CE |
150 | MY_MEMORYSTATUSEX stat; | 150 | MY_MEMORYSTATUSEX stat; |
@@ -167,11 +167,23 @@ bool GetRamSize(UInt64 &size) | |||
167 | "GlobalMemoryStatusEx"); | 167 | "GlobalMemoryStatusEx"); |
168 | if (fn && fn(&stat)) | 168 | if (fn && fn(&stat)) |
169 | { | 169 | { |
170 | size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); | 170 | // (MY_MEMORYSTATUSEX::ullTotalVirtual) < 4 GiB in 32-bit mode |
171 | size_t size2 = (size_t)0 - 1; | ||
172 | if (size2 > stat.ullTotalPhys) | ||
173 | size2 = (size_t)stat.ullTotalPhys; | ||
174 | if (size2 > stat.ullTotalVirtual) | ||
175 | size2 = (size_t)stat.ullTotalVirtual; | ||
176 | size = size2; | ||
171 | return true; | 177 | return true; |
172 | } | 178 | } |
173 | #endif | 179 | #endif |
174 | 180 | ||
181 | // On computers with more than 4 GB of memory: | ||
182 | // new docs : GlobalMemoryStatus can report (-1) value to indicate an overflow. | ||
183 | // some old docs : GlobalMemoryStatus can report (modulo 4 GiB) value. | ||
184 | // (for example, if 5 GB total memory, it could report 1 GB). | ||
185 | // We don't want to get (modulo 4 GiB) value. | ||
186 | // So we use GlobalMemoryStatusEx() instead. | ||
175 | { | 187 | { |
176 | MEMORYSTATUS stat2; | 188 | MEMORYSTATUS stat2; |
177 | stat2.dwLength = sizeof(stat2); | 189 | stat2.dwLength = sizeof(stat2); |
@@ -187,9 +199,11 @@ bool GetRamSize(UInt64 &size) | |||
187 | // POSIX | 199 | // POSIX |
188 | // #include <stdio.h> | 200 | // #include <stdio.h> |
189 | 201 | ||
190 | bool GetRamSize(UInt64 &size) | 202 | bool GetRamSize(size_t &size) |
191 | { | 203 | { |
192 | size = (UInt64)(sizeof(size_t)) << 29; | 204 | UInt64 size64; |
205 | size = (size_t)sizeof(size_t) << 29; | ||
206 | size64 = size; | ||
193 | 207 | ||
194 | #if defined(__APPLE__) || defined(__DragonFly__) || \ | 208 | #if defined(__APPLE__) || defined(__DragonFly__) || \ |
195 | defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) | 209 | defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) |
@@ -215,7 +229,7 @@ bool GetRamSize(UInt64 &size) | |||
215 | // we use strict check (size_sys == sizeof(val)) for returned value | 229 | // we use strict check (size_sys == sizeof(val)) for returned value |
216 | // because big-endian encoding is possible: | 230 | // because big-endian encoding is possible: |
217 | if (res == 0 && size_sys == sizeof(val) && val) | 231 | if (res == 0 && size_sys == sizeof(val) && val) |
218 | size = val; | 232 | size64 = val; |
219 | else | 233 | else |
220 | { | 234 | { |
221 | uint32_t val32 = 0; | 235 | uint32_t val32 = 0; |
@@ -223,12 +237,12 @@ bool GetRamSize(UInt64 &size) | |||
223 | res = sysctl(mib, 2, &val32, &size_sys, NULL, 0); | 237 | res = sysctl(mib, 2, &val32, &size_sys, NULL, 0); |
224 | // printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val32, (int)size_sys, errno); | 238 | // printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val32, (int)size_sys, errno); |
225 | if (res == 0 && size_sys == sizeof(val32) && val32) | 239 | if (res == 0 && size_sys == sizeof(val32) && val32) |
226 | size = val32; | 240 | size64 = val32; |
227 | } | 241 | } |
228 | 242 | ||
229 | #elif defined(_AIX) | 243 | #elif defined(_AIX) |
230 | #if defined(_SC_AIX_REALMEM) // AIX | 244 | #if defined(_SC_AIX_REALMEM) // AIX |
231 | size = (UInt64)sysconf(_SC_AIX_REALMEM) * 1024; | 245 | size64 = (UInt64)sysconf(_SC_AIX_REALMEM) * 1024; |
232 | #endif | 246 | #endif |
233 | #elif 0 || defined(__sun) | 247 | #elif 0 || defined(__sun) |
234 | #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) | 248 | #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) |
@@ -240,7 +254,7 @@ bool GetRamSize(UInt64 &size) | |||
240 | // printf("\n_SC_PHYS_PAGES (hex) = %lx", (unsigned long)phys_pages); | 254 | // printf("\n_SC_PHYS_PAGES (hex) = %lx", (unsigned long)phys_pages); |
241 | // printf("\n_SC_PAGESIZE = %lu\n", (unsigned long)page_size); | 255 | // printf("\n_SC_PAGESIZE = %lu\n", (unsigned long)page_size); |
242 | if (phys_pages != -1 && page_size != -1) | 256 | if (phys_pages != -1 && page_size != -1) |
243 | size = (UInt64)(Int64)phys_pages * (UInt64)(Int64)page_size; | 257 | size64 = (UInt64)(Int64)phys_pages * (UInt64)(Int64)page_size; |
244 | } | 258 | } |
245 | #endif | 259 | #endif |
246 | #elif defined(__gnu_hurd__) | 260 | #elif defined(__gnu_hurd__) |
@@ -253,7 +267,7 @@ bool GetRamSize(UInt64 &size) | |||
253 | struct sysinfo info; | 267 | struct sysinfo info; |
254 | if (::sysinfo(&info) != 0) | 268 | if (::sysinfo(&info) != 0) |
255 | return false; | 269 | return false; |
256 | size = (UInt64)info.mem_unit * info.totalram; | 270 | size64 = (UInt64)info.mem_unit * info.totalram; |
257 | /* | 271 | /* |
258 | printf("\n mem_unit = %lld", (UInt64)info.mem_unit); | 272 | printf("\n mem_unit = %lld", (UInt64)info.mem_unit); |
259 | printf("\n totalram = %lld", (UInt64)info.totalram); | 273 | printf("\n totalram = %lld", (UInt64)info.totalram); |
@@ -262,10 +276,9 @@ bool GetRamSize(UInt64 &size) | |||
262 | 276 | ||
263 | #endif | 277 | #endif |
264 | 278 | ||
265 | const UInt64 kLimit = (UInt64)1 << (sizeof(size_t) * 8 - 1); | 279 | size = (size_t)1 << (sizeof(size_t) * 8 - 1); |
266 | if (size > kLimit) | 280 | if (size > size64) |
267 | size = kLimit; | 281 | size = (size_t)size64; |
268 | |||
269 | return true; | 282 | return true; |
270 | } | 283 | } |
271 | 284 | ||
diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h index b17111c..9951b8b 100644 --- a/CPP/Windows/System.h +++ b/CPP/Windows/System.h | |||
@@ -122,7 +122,7 @@ struct CProcessAffinity | |||
122 | 122 | ||
123 | UInt32 GetNumberOfProcessors(); | 123 | UInt32 GetNumberOfProcessors(); |
124 | 124 | ||
125 | bool GetRamSize(UInt64 &size); // returns false, if unknown ram size | 125 | bool GetRamSize(size_t &size); // returns false, if unknown ram size |
126 | 126 | ||
127 | unsigned long Get_File_OPEN_MAX(); | 127 | unsigned long Get_File_OPEN_MAX(); |
128 | unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks(); | 128 | unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks(); |
diff --git a/CPP/Windows/SystemInfo.cpp b/CPP/Windows/SystemInfo.cpp index cfc6a90..35846e0 100644 --- a/CPP/Windows/SystemInfo.cpp +++ b/CPP/Windows/SystemInfo.cpp | |||
@@ -530,6 +530,28 @@ struct CCpuName | |||
530 | AString Microcode; | 530 | AString Microcode; |
531 | AString LargePages; | 531 | AString LargePages; |
532 | 532 | ||
533 | #ifdef _WIN32 | ||
534 | UInt32 MHz; | ||
535 | |||
536 | #ifdef MY_CPU_ARM64 | ||
537 | #define Z7_SYS_INFO_SHOW_ARM64_REGS | ||
538 | #endif | ||
539 | #ifdef Z7_SYS_INFO_SHOW_ARM64_REGS | ||
540 | bool Arm64_ISAR0_EL1_Defined; | ||
541 | UInt64 Arm64_ISAR0_EL1; | ||
542 | #endif | ||
543 | #endif | ||
544 | |||
545 | #ifdef _WIN32 | ||
546 | CCpuName(): | ||
547 | MHz(0) | ||
548 | #ifdef Z7_SYS_INFO_SHOW_ARM64_REGS | ||
549 | , Arm64_ISAR0_EL1_Defined(false) | ||
550 | , Arm64_ISAR0_EL1(0) | ||
551 | #endif | ||
552 | {} | ||
553 | #endif | ||
554 | |||
533 | void Fill(); | 555 | void Fill(); |
534 | 556 | ||
535 | void Get_Revision_Microcode_LargePages(AString &s) | 557 | void Get_Revision_Microcode_LargePages(AString &s) |
@@ -537,16 +559,46 @@ struct CCpuName | |||
537 | s.Empty(); | 559 | s.Empty(); |
538 | AddBracedString(s, Revision); | 560 | AddBracedString(s, Revision); |
539 | AddBracedString(s, Microcode); | 561 | AddBracedString(s, Microcode); |
540 | s.Add_OptSpaced(LargePages); | 562 | #ifdef _WIN32 |
563 | if (MHz != 0) | ||
564 | { | ||
565 | s.Add_Space_if_NotEmpty(); | ||
566 | s.Add_UInt32(MHz); | ||
567 | s += " MHz"; | ||
568 | } | ||
569 | #endif | ||
570 | if (!LargePages.IsEmpty()) | ||
571 | s.Add_OptSpaced(LargePages); | ||
572 | } | ||
573 | |||
574 | #ifdef Z7_SYS_INFO_SHOW_ARM64_REGS | ||
575 | void Get_Registers(AString &s) | ||
576 | { | ||
577 | if (Arm64_ISAR0_EL1_Defined) | ||
578 | { | ||
579 | // ID_AA64ISAR0_EL1 | ||
580 | s.Add_OptSpaced("cp4030:"); | ||
581 | PrintHex(s, Arm64_ISAR0_EL1); | ||
582 | { | ||
583 | const unsigned sha2 = ((unsigned)(Arm64_ISAR0_EL1 >> 12) & 0xf) - 1; | ||
584 | if (sha2 < 2) | ||
585 | { | ||
586 | s += ":SHA256"; | ||
587 | if (sha2) | ||
588 | s += ":SHA512"; | ||
589 | } | ||
590 | } | ||
591 | } | ||
541 | } | 592 | } |
593 | #endif | ||
542 | }; | 594 | }; |
543 | 595 | ||
544 | void CCpuName::Fill() | 596 | void CCpuName::Fill() |
545 | { | 597 | { |
546 | CpuName.Empty(); | 598 | // CpuName.Empty(); |
547 | Revision.Empty(); | 599 | // Revision.Empty(); |
548 | Microcode.Empty(); | 600 | // Microcode.Empty(); |
549 | LargePages.Empty(); | 601 | // LargePages.Empty(); |
550 | 602 | ||
551 | AString &s = CpuName; | 603 | AString &s = CpuName; |
552 | 604 | ||
@@ -600,21 +652,32 @@ void CCpuName::Fill() | |||
600 | Revision += GetAnsiString(name); | 652 | Revision += GetAnsiString(name); |
601 | } | 653 | } |
602 | } | 654 | } |
655 | #ifdef _WIN32 | ||
656 | key.GetValue_UInt32_IfOk(TEXT("~MHz"), MHz); | ||
657 | #ifdef Z7_SYS_INFO_SHOW_ARM64_REGS | ||
658 | /* | ||
659 | mapping arm64 registers to Windows registry: | ||
660 | CP 4000: MIDR_EL1 | ||
661 | CP 4020: ID_AA64PFR0_EL1 | ||
662 | CP 4021: ID_AA64PFR1_EL1 | ||
663 | CP 4028: ID_AA64DFR0_EL1 | ||
664 | CP 4029: ID_AA64DFR1_EL1 | ||
665 | CP 402C: ID_AA64AFR0_EL1 | ||
666 | CP 402D: ID_AA64AFR1_EL1 | ||
667 | CP 4030: ID_AA64ISAR0_EL1 | ||
668 | CP 4031: ID_AA64ISAR1_EL1 | ||
669 | CP 4038: ID_AA64MMFR0_EL1 | ||
670 | CP 4039: ID_AA64MMFR1_EL1 | ||
671 | CP 403A: ID_AA64MMFR2_EL1 | ||
672 | */ | ||
673 | if (key.GetValue_UInt64_IfOk(TEXT("CP 4030"), Arm64_ISAR0_EL1) == ERROR_SUCCESS) | ||
674 | Arm64_ISAR0_EL1_Defined = true; | ||
675 | #endif | ||
676 | #endif | ||
603 | LONG res[2]; | 677 | LONG res[2]; |
604 | CByteBuffer bufs[2]; | 678 | CByteBuffer bufs[2]; |
605 | { | 679 | res[0] = key.QueryValue_Binary(TEXT("Previous Update Revision"), bufs[0]); |
606 | for (unsigned i = 0; i < 2; i++) | 680 | res[1] = key.QueryValue_Binary(TEXT("Update Revision"), bufs[1]); |
607 | { | ||
608 | UInt32 size = 0; | ||
609 | res[i] = key.QueryValue(i == 0 ? | ||
610 | TEXT("Previous Update Revision") : | ||
611 | TEXT("Update Revision"), | ||
612 | bufs[i], size); | ||
613 | if (res[i] == ERROR_SUCCESS) | ||
614 | if (size != bufs[i].Size()) | ||
615 | res[i] = ERROR_SUCCESS + 1; | ||
616 | } | ||
617 | } | ||
618 | if (res[0] == ERROR_SUCCESS || res[1] == ERROR_SUCCESS) | 681 | if (res[0] == ERROR_SUCCESS || res[1] == ERROR_SUCCESS) |
619 | { | 682 | { |
620 | for (unsigned i = 0; i < 2; i++) | 683 | for (unsigned i = 0; i < 2; i++) |
@@ -747,9 +810,18 @@ void AddCpuFeatures(AString &s) | |||
747 | unsigned long h = MY_getauxval(AT_HWCAP); | 810 | unsigned long h = MY_getauxval(AT_HWCAP); |
748 | PrintHex(s, h); | 811 | PrintHex(s, h); |
749 | #ifdef MY_CPU_ARM64 | 812 | #ifdef MY_CPU_ARM64 |
813 | #ifndef HWCAP_SHA3 | ||
814 | #define HWCAP_SHA3 (1 << 17) | ||
815 | #endif | ||
816 | #ifndef HWCAP_SHA512 | ||
817 | #define HWCAP_SHA512 (1 << 21) | ||
818 | // #pragma message("=== HWCAP_SHA512 define === ") | ||
819 | #endif | ||
750 | if (h & HWCAP_CRC32) s += ":CRC32"; | 820 | if (h & HWCAP_CRC32) s += ":CRC32"; |
751 | if (h & HWCAP_SHA1) s += ":SHA1"; | 821 | if (h & HWCAP_SHA1) s += ":SHA1"; |
752 | if (h & HWCAP_SHA2) s += ":SHA2"; | 822 | if (h & HWCAP_SHA2) s += ":SHA2"; |
823 | if (h & HWCAP_SHA3) s += ":SHA3"; | ||
824 | if (h & HWCAP_SHA512) s += ":SHA512"; | ||
753 | if (h & HWCAP_AES) s += ":AES"; | 825 | if (h & HWCAP_AES) s += ":AES"; |
754 | if (h & HWCAP_ASIMD) s += ":ASIMD"; | 826 | if (h & HWCAP_ASIMD) s += ":ASIMD"; |
755 | #elif defined(MY_CPU_ARM) | 827 | #elif defined(MY_CPU_ARM) |
@@ -908,13 +980,18 @@ void GetSystemInfoText(AString &sRes) | |||
908 | } | 980 | } |
909 | } | 981 | } |
910 | { | 982 | { |
911 | AString s; | 983 | AString s, registers; |
912 | GetCpuName_MultiLine(s); | 984 | GetCpuName_MultiLine(s, registers); |
913 | if (!s.IsEmpty()) | 985 | if (!s.IsEmpty()) |
914 | { | 986 | { |
915 | sRes += s; | 987 | sRes += s; |
916 | sRes.Add_LF(); | 988 | sRes.Add_LF(); |
917 | } | 989 | } |
990 | if (!registers.IsEmpty()) | ||
991 | { | ||
992 | sRes += registers; | ||
993 | sRes.Add_LF(); | ||
994 | } | ||
918 | } | 995 | } |
919 | /* | 996 | /* |
920 | #ifdef MY_CPU_X86_OR_AMD64 | 997 | #ifdef MY_CPU_X86_OR_AMD64 |
@@ -932,8 +1009,8 @@ void GetSystemInfoText(AString &sRes) | |||
932 | } | 1009 | } |
933 | 1010 | ||
934 | 1011 | ||
935 | void GetCpuName_MultiLine(AString &s); | 1012 | void GetCpuName_MultiLine(AString &s, AString ®isters); |
936 | void GetCpuName_MultiLine(AString &s) | 1013 | void GetCpuName_MultiLine(AString &s, AString ®isters) |
937 | { | 1014 | { |
938 | CCpuName cpuName; | 1015 | CCpuName cpuName; |
939 | cpuName.Fill(); | 1016 | cpuName.Fill(); |
@@ -945,6 +1022,10 @@ void GetCpuName_MultiLine(AString &s) | |||
945 | s.Add_LF(); | 1022 | s.Add_LF(); |
946 | s += s2; | 1023 | s += s2; |
947 | } | 1024 | } |
1025 | registers.Empty(); | ||
1026 | #ifdef Z7_SYS_INFO_SHOW_ARM64_REGS | ||
1027 | cpuName.Get_Registers(registers); | ||
1028 | #endif | ||
948 | } | 1029 | } |
949 | 1030 | ||
950 | 1031 | ||
diff --git a/CPP/Windows/SystemInfo.h b/CPP/Windows/SystemInfo.h index c2e2e3b..4601685 100644 --- a/CPP/Windows/SystemInfo.h +++ b/CPP/Windows/SystemInfo.h | |||
@@ -6,7 +6,7 @@ | |||
6 | #include "../Common/MyString.h" | 6 | #include "../Common/MyString.h" |
7 | 7 | ||
8 | 8 | ||
9 | void GetCpuName_MultiLine(AString &s); | 9 | void GetCpuName_MultiLine(AString &s, AString ®isters); |
10 | 10 | ||
11 | void GetOsInfoText(AString &sRes); | 11 | void GetOsInfoText(AString &sRes); |
12 | void GetSystemInfoText(AString &s); | 12 | void GetSystemInfoText(AString &s); |