aboutsummaryrefslogtreecommitdiff
path: root/CPP/Windows
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/Windows')
-rw-r--r--CPP/Windows/FileDir.cpp138
-rw-r--r--CPP/Windows/FileDir.h23
-rw-r--r--CPP/Windows/FileName.cpp8
-rw-r--r--CPP/Windows/Registry.cpp295
-rw-r--r--CPP/Windows/Registry.h48
-rw-r--r--CPP/Windows/System.cpp41
-rw-r--r--CPP/Windows/System.h2
-rw-r--r--CPP/Windows/SystemInfo.cpp125
-rw-r--r--CPP/Windows/SystemInfo.h2
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
225bool MyMoveFile(CFSTR oldFile, CFSTR newFile) 228bool 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
257static 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
275bool 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
881bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) 937bool 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
944static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile) 1000static 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
971bool MyMoveFile(CFSTR oldFile, CFSTR newFile) 1051bool 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
1074bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
1075{
1076 return MyMoveFile_with_Progress(oldFile, newFile, NULL);
1077}
1078
993 1079
994bool CreateDir(CFSTR path) 1080bool 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);
41bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib); 41bool 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
50Z7_PURE_INTERFACES_BEGIN
51DECLARE_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};
57Z7_PURE_INTERFACES_END
58
44bool MyMoveFile(CFSTR existFileName, CFSTR newFileName); 59bool MyMoveFile(CFSTR existFileName, CFSTR newFileName);
60// (progress == NULL) is allowed
61bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile,
62 ICopyFileProgress *progress);
63
45 64
46#ifndef UNDER_CE 65#ifndef UNDER_CE
47bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName); 66bool 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()
278int FindAltStreamColon(CFSTR path) throw() 278int 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
83LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw() 83LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
84{ 84{
@@ -88,22 +88,36 @@ LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
88 88
89LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw() 89LONG 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
146LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw() 162LONG 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
208LONG 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
219LONG CKey::QueryValue(LPCTSTR name, bool &value) throw() 227LONG 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
227LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value) throw() 243LONG 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
236LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw() 258LONG 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
245LONG 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
253LONG CKey::QueryValue(LPCTSTR name, CSysString &value) 269LONG 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
272LONG 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
280LONG CKey::QueryValue(LPCWSTR name, UString &value) 316LONG 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
309LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count) throw() 365LONG 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
318LONG 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
329LONG CKey::EnumKeys(CSysStringVector &keyNames) 402LONG 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
350LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings) 424LONG 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)
14class CKey 14class 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
17public: 24public:
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
145bool GetRamSize(UInt64 &size) 145bool 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
190bool GetRamSize(UInt64 &size) 202bool 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
123UInt32 GetNumberOfProcessors(); 123UInt32 GetNumberOfProcessors();
124 124
125bool GetRamSize(UInt64 &size); // returns false, if unknown ram size 125bool GetRamSize(size_t &size); // returns false, if unknown ram size
126 126
127unsigned long Get_File_OPEN_MAX(); 127unsigned long Get_File_OPEN_MAX();
128unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks(); 128unsigned 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
544void CCpuName::Fill() 596void 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/*
659mapping arm64 registers to Windows registry:
660CP 4000: MIDR_EL1
661CP 4020: ID_AA64PFR0_EL1
662CP 4021: ID_AA64PFR1_EL1
663CP 4028: ID_AA64DFR0_EL1
664CP 4029: ID_AA64DFR1_EL1
665CP 402C: ID_AA64AFR0_EL1
666CP 402D: ID_AA64AFR1_EL1
667CP 4030: ID_AA64ISAR0_EL1
668CP 4031: ID_AA64ISAR1_EL1
669CP 4038: ID_AA64MMFR0_EL1
670CP 4039: ID_AA64MMFR1_EL1
671CP 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
935void GetCpuName_MultiLine(AString &s); 1012void GetCpuName_MultiLine(AString &s, AString &registers);
936void GetCpuName_MultiLine(AString &s) 1013void GetCpuName_MultiLine(AString &s, AString &registers)
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
9void GetCpuName_MultiLine(AString &s); 9void GetCpuName_MultiLine(AString &s, AString &registers);
10 10
11void GetOsInfoText(AString &sRes); 11void GetOsInfoText(AString &sRes);
12void GetSystemInfoText(AString &s); 12void GetSystemInfoText(AString &s);