diff options
Diffstat (limited to '')
89 files changed, 14979 insertions, 0 deletions
diff --git a/CPP/Windows/COM.cpp b/CPP/Windows/COM.cpp new file mode 100644 index 0000000..d0cb321 --- /dev/null +++ b/CPP/Windows/COM.cpp | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | // Windows/COM.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | /* | ||
| 6 | |||
| 7 | #include "COM.h" | ||
| 8 | #include "../Common/StringConvert.h" | ||
| 9 | |||
| 10 | namespace NWindows { | ||
| 11 | namespace NCOM { | ||
| 12 | |||
| 13 | // CoInitialize (NULL); must be called! | ||
| 14 | |||
| 15 | UString GUIDToStringW(REFGUID guid) | ||
| 16 | { | ||
| 17 | UString s; | ||
| 18 | const unsigned kSize = 48; | ||
| 19 | StringFromGUID2(guid, s.GetBuf(kSize), kSize); | ||
| 20 | s.ReleaseBuf_CalcLen(kSize); | ||
| 21 | return s; | ||
| 22 | } | ||
| 23 | |||
| 24 | AString GUIDToStringA(REFGUID guid) | ||
| 25 | { | ||
| 26 | return UnicodeStringToMultiByte(GUIDToStringW(guid)); | ||
| 27 | } | ||
| 28 | |||
| 29 | HRESULT StringToGUIDW(const wchar_t *string, GUID &classID) | ||
| 30 | { | ||
| 31 | return CLSIDFromString((wchar_t *)string, &classID); | ||
| 32 | } | ||
| 33 | |||
| 34 | HRESULT StringToGUIDA(const char *string, GUID &classID) | ||
| 35 | { | ||
| 36 | return StringToGUIDW(MultiByteToUnicodeString(string), classID); | ||
| 37 | } | ||
| 38 | |||
| 39 | }} | ||
| 40 | |||
| 41 | */ | ||
diff --git a/CPP/Windows/COM.h b/CPP/Windows/COM.h new file mode 100644 index 0000000..cee7f70 --- /dev/null +++ b/CPP/Windows/COM.h | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | // Windows/COM.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_COM_H | ||
| 4 | #define __WINDOWS_COM_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NCOM { | ||
| 10 | |||
| 11 | #ifdef _WIN32 | ||
| 12 | |||
| 13 | class CComInitializer | ||
| 14 | { | ||
| 15 | public: | ||
| 16 | CComInitializer() | ||
| 17 | { | ||
| 18 | #ifdef UNDER_CE | ||
| 19 | CoInitializeEx(NULL, COINIT_MULTITHREADED); | ||
| 20 | #else | ||
| 21 | // it's single thread. Do we need multithread? | ||
| 22 | CoInitialize(NULL); | ||
| 23 | #endif | ||
| 24 | }; | ||
| 25 | ~CComInitializer() { CoUninitialize(); } | ||
| 26 | }; | ||
| 27 | |||
| 28 | class CStgMedium | ||
| 29 | { | ||
| 30 | STGMEDIUM _object; | ||
| 31 | public: | ||
| 32 | bool _mustBeReleased; | ||
| 33 | CStgMedium(): _mustBeReleased(false) {} | ||
| 34 | ~CStgMedium() { Free(); } | ||
| 35 | void Free() | ||
| 36 | { | ||
| 37 | if (_mustBeReleased) | ||
| 38 | ReleaseStgMedium(&_object); | ||
| 39 | _mustBeReleased = false; | ||
| 40 | } | ||
| 41 | const STGMEDIUM* operator->() const { return &_object;} | ||
| 42 | STGMEDIUM* operator->() { return &_object;} | ||
| 43 | STGMEDIUM* operator&() { return &_object; } | ||
| 44 | }; | ||
| 45 | |||
| 46 | #endif | ||
| 47 | |||
| 48 | /* | ||
| 49 | ////////////////////////////////// | ||
| 50 | // GUID <--> String Conversions | ||
| 51 | UString GUIDToStringW(REFGUID guid); | ||
| 52 | AString GUIDToStringA(REFGUID guid); | ||
| 53 | #ifdef UNICODE | ||
| 54 | #define GUIDToString GUIDToStringW | ||
| 55 | #else | ||
| 56 | #define GUIDToString GUIDToStringA | ||
| 57 | #endif | ||
| 58 | |||
| 59 | HRESULT StringToGUIDW(const wchar_t *string, GUID &classID); | ||
| 60 | HRESULT StringToGUIDA(const char *string, GUID &classID); | ||
| 61 | #ifdef UNICODE | ||
| 62 | #define StringToGUID StringToGUIDW | ||
| 63 | #else | ||
| 64 | #define StringToGUID StringToGUIDA | ||
| 65 | #endif | ||
| 66 | */ | ||
| 67 | |||
| 68 | }} | ||
| 69 | |||
| 70 | #endif | ||
diff --git a/CPP/Windows/Clipboard.cpp b/CPP/Windows/Clipboard.cpp new file mode 100644 index 0000000..bc7e201 --- /dev/null +++ b/CPP/Windows/Clipboard.cpp | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | // Windows/Clipboard.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifdef UNDER_CE | ||
| 6 | #include <winuserm.h> | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #include "../Common/StringConvert.h" | ||
| 10 | |||
| 11 | #include "Clipboard.h" | ||
| 12 | #include "Defs.h" | ||
| 13 | #include "MemoryGlobal.h" | ||
| 14 | #include "Shell.h" | ||
| 15 | |||
| 16 | namespace NWindows { | ||
| 17 | |||
| 18 | bool CClipboard::Open(HWND wndNewOwner) throw() | ||
| 19 | { | ||
| 20 | m_Open = BOOLToBool(::OpenClipboard(wndNewOwner)); | ||
| 21 | return m_Open; | ||
| 22 | } | ||
| 23 | |||
| 24 | bool CClipboard::Close() throw() | ||
| 25 | { | ||
| 26 | if (!m_Open) | ||
| 27 | return true; | ||
| 28 | m_Open = !BOOLToBool(CloseClipboard()); | ||
| 29 | return !m_Open; | ||
| 30 | } | ||
| 31 | |||
| 32 | bool ClipboardIsFormatAvailableHDROP() | ||
| 33 | { | ||
| 34 | return BOOLToBool(IsClipboardFormatAvailable(CF_HDROP)); | ||
| 35 | } | ||
| 36 | |||
| 37 | /* | ||
| 38 | bool ClipboardGetTextString(AString &s) | ||
| 39 | { | ||
| 40 | s.Empty(); | ||
| 41 | if (!IsClipboardFormatAvailable(CF_TEXT)) | ||
| 42 | return false; | ||
| 43 | CClipboard clipboard; | ||
| 44 | |||
| 45 | if (!clipboard.Open(NULL)) | ||
| 46 | return false; | ||
| 47 | |||
| 48 | HGLOBAL h = ::GetClipboardData(CF_TEXT); | ||
| 49 | if (h != NULL) | ||
| 50 | { | ||
| 51 | NMemory::CGlobalLock globalLock(h); | ||
| 52 | const char *p = (const char *)globalLock.GetPointer(); | ||
| 53 | if (p != NULL) | ||
| 54 | { | ||
| 55 | s = p; | ||
| 56 | return true; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | return false; | ||
| 60 | } | ||
| 61 | */ | ||
| 62 | |||
| 63 | /* | ||
| 64 | bool ClipboardGetFileNames(UStringVector &names) | ||
| 65 | { | ||
| 66 | names.Clear(); | ||
| 67 | if (!IsClipboardFormatAvailable(CF_HDROP)) | ||
| 68 | return false; | ||
| 69 | CClipboard clipboard; | ||
| 70 | |||
| 71 | if (!clipboard.Open(NULL)) | ||
| 72 | return false; | ||
| 73 | |||
| 74 | HGLOBAL h = ::GetClipboardData(CF_HDROP); | ||
| 75 | if (h != NULL) | ||
| 76 | { | ||
| 77 | NMemory::CGlobalLock globalLock(h); | ||
| 78 | void *p = (void *)globalLock.GetPointer(); | ||
| 79 | if (p != NULL) | ||
| 80 | { | ||
| 81 | NShell::CDrop drop(false); | ||
| 82 | drop.Attach((HDROP)p); | ||
| 83 | drop.QueryFileNames(names); | ||
| 84 | return true; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | return false; | ||
| 88 | } | ||
| 89 | */ | ||
| 90 | |||
| 91 | static bool ClipboardSetData(UINT uFormat, const void *data, size_t size) throw() | ||
| 92 | { | ||
| 93 | NMemory::CGlobal global; | ||
| 94 | if (!global.Alloc(GMEM_DDESHARE | GMEM_MOVEABLE, size)) | ||
| 95 | return false; | ||
| 96 | { | ||
| 97 | NMemory::CGlobalLock globalLock(global); | ||
| 98 | LPVOID p = globalLock.GetPointer(); | ||
| 99 | if (!p) | ||
| 100 | return false; | ||
| 101 | memcpy(p, data, size); | ||
| 102 | } | ||
| 103 | if (::SetClipboardData(uFormat, global) == NULL) | ||
| 104 | return false; | ||
| 105 | global.Detach(); | ||
| 106 | return true; | ||
| 107 | } | ||
| 108 | |||
| 109 | bool ClipboardSetText(HWND owner, const UString &s) | ||
| 110 | { | ||
| 111 | CClipboard clipboard; | ||
| 112 | if (!clipboard.Open(owner)) | ||
| 113 | return false; | ||
| 114 | if (!::EmptyClipboard()) | ||
| 115 | return false; | ||
| 116 | |||
| 117 | bool res; | ||
| 118 | res = ClipboardSetData(CF_UNICODETEXT, (const wchar_t *)s, (s.Len() + 1) * sizeof(wchar_t)); | ||
| 119 | #ifndef _UNICODE | ||
| 120 | AString a (UnicodeStringToMultiByte(s, CP_ACP)); | ||
| 121 | if (ClipboardSetData(CF_TEXT, (const char *)a, (a.Len() + 1) * sizeof(char))) | ||
| 122 | res = true; | ||
| 123 | a = UnicodeStringToMultiByte(s, CP_OEMCP); | ||
| 124 | if (ClipboardSetData(CF_OEMTEXT, (const char *)a, (a.Len() + 1) * sizeof(char))) | ||
| 125 | res = true; | ||
| 126 | #endif | ||
| 127 | return res; | ||
| 128 | } | ||
| 129 | |||
| 130 | } | ||
diff --git a/CPP/Windows/Clipboard.h b/CPP/Windows/Clipboard.h new file mode 100644 index 0000000..60fedc1 --- /dev/null +++ b/CPP/Windows/Clipboard.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Windows/Clipboard.h | ||
| 2 | |||
| 3 | #ifndef __CLIPBOARD_H | ||
| 4 | #define __CLIPBOARD_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | |||
| 10 | class CClipboard | ||
| 11 | { | ||
| 12 | bool m_Open; | ||
| 13 | public: | ||
| 14 | CClipboard(): m_Open(false) {}; | ||
| 15 | ~CClipboard() { Close(); } | ||
| 16 | bool Open(HWND wndNewOwner) throw(); | ||
| 17 | bool Close() throw(); | ||
| 18 | }; | ||
| 19 | |||
| 20 | bool ClipboardIsFormatAvailableHDROP(); | ||
| 21 | |||
| 22 | // bool ClipboardGetFileNames(UStringVector &names); | ||
| 23 | // bool ClipboardGetTextString(AString &s); | ||
| 24 | bool ClipboardSetText(HWND owner, const UString &s); | ||
| 25 | |||
| 26 | } | ||
| 27 | |||
| 28 | #endif | ||
diff --git a/CPP/Windows/CommonDialog.cpp b/CPP/Windows/CommonDialog.cpp new file mode 100644 index 0000000..eaaecad --- /dev/null +++ b/CPP/Windows/CommonDialog.cpp | |||
| @@ -0,0 +1,208 @@ | |||
| 1 | // Windows/CommonDialog.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../Common/MyWindows.h" | ||
| 6 | |||
| 7 | #ifdef UNDER_CE | ||
| 8 | #include <commdlg.h> | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #ifndef _UNICODE | ||
| 12 | #include "../Common/StringConvert.h" | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #include "CommonDialog.h" | ||
| 16 | #include "Defs.h" | ||
| 17 | |||
| 18 | #ifndef _UNICODE | ||
| 19 | extern bool g_IsNT; | ||
| 20 | #endif | ||
| 21 | |||
| 22 | namespace NWindows { | ||
| 23 | |||
| 24 | #ifndef _UNICODE | ||
| 25 | |||
| 26 | class CDoubleZeroStringListA | ||
| 27 | { | ||
| 28 | LPTSTR Buf; | ||
| 29 | unsigned Size; | ||
| 30 | public: | ||
| 31 | CDoubleZeroStringListA(LPSTR buf, unsigned size): Buf(buf), Size(size) {} | ||
| 32 | bool Add(LPCSTR s) throw(); | ||
| 33 | void Finish() { *Buf = 0; } | ||
| 34 | }; | ||
| 35 | |||
| 36 | bool CDoubleZeroStringListA::Add(LPCSTR s) throw() | ||
| 37 | { | ||
| 38 | unsigned len = MyStringLen(s) + 1; | ||
| 39 | if (len >= Size) | ||
| 40 | return false; | ||
| 41 | MyStringCopy(Buf, s); | ||
| 42 | Buf += len; | ||
| 43 | Size -= len; | ||
| 44 | return true; | ||
| 45 | } | ||
| 46 | |||
| 47 | #endif | ||
| 48 | |||
| 49 | class CDoubleZeroStringListW | ||
| 50 | { | ||
| 51 | LPWSTR Buf; | ||
| 52 | unsigned Size; | ||
| 53 | public: | ||
| 54 | CDoubleZeroStringListW(LPWSTR buf, unsigned size): Buf(buf), Size(size) {} | ||
| 55 | bool Add(LPCWSTR s) throw(); | ||
| 56 | void Finish() { *Buf = 0; } | ||
| 57 | }; | ||
| 58 | |||
| 59 | bool CDoubleZeroStringListW::Add(LPCWSTR s) throw() | ||
| 60 | { | ||
| 61 | unsigned len = MyStringLen(s) + 1; | ||
| 62 | if (len >= Size) | ||
| 63 | return false; | ||
| 64 | MyStringCopy(Buf, s); | ||
| 65 | Buf += len; | ||
| 66 | Size -= len; | ||
| 67 | return true; | ||
| 68 | } | ||
| 69 | |||
| 70 | |||
| 71 | #ifdef UNDER_CE | ||
| 72 | #define MY__OFN_PROJECT 0x00400000 | ||
| 73 | #define MY__OFN_SHOW_ALL 0x01000000 | ||
| 74 | #endif | ||
| 75 | |||
| 76 | /* if (lpstrFilter == NULL && nFilterIndex == 0) | ||
| 77 | MSDN : "the system doesn't show any files", | ||
| 78 | but WinXP-64 shows all files. Why ??? */ | ||
| 79 | |||
| 80 | /* | ||
| 81 | structures | ||
| 82 | OPENFILENAMEW | ||
| 83 | OPENFILENAMEA | ||
| 84 | contain additional members: | ||
| 85 | #if (_WIN32_WINNT >= 0x0500) | ||
| 86 | void *pvReserved; | ||
| 87 | DWORD dwReserved; | ||
| 88 | DWORD FlagsEx; | ||
| 89 | #endif | ||
| 90 | |||
| 91 | If we compile the source code with (_WIN32_WINNT >= 0x0500), some functions | ||
| 92 | will not work at NT 4.0, if we use sizeof(OPENFILENAME*). | ||
| 93 | So we use size of old version of structure. */ | ||
| 94 | |||
| 95 | #if defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500) | ||
| 96 | // || !defined(WINVER) | ||
| 97 | #ifndef _UNICODE | ||
| 98 | #define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA) | ||
| 99 | #endif | ||
| 100 | #define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW) | ||
| 101 | #else | ||
| 102 | |||
| 103 | // MinGW doesn't support some required macros. So we define them here: | ||
| 104 | #ifndef CDSIZEOF_STRUCT | ||
| 105 | #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) | ||
| 106 | #endif | ||
| 107 | #ifndef _UNICODE | ||
| 108 | #ifndef OPENFILENAME_SIZE_VERSION_400A | ||
| 109 | #define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName) | ||
| 110 | #endif | ||
| 111 | #endif | ||
| 112 | #ifndef OPENFILENAME_SIZE_VERSION_400W | ||
| 113 | #define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName) | ||
| 114 | #endif | ||
| 115 | |||
| 116 | #ifndef _UNICODE | ||
| 117 | #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A | ||
| 118 | #endif | ||
| 119 | #define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W | ||
| 120 | #endif | ||
| 121 | |||
| 122 | #ifndef _UNICODE | ||
| 123 | #define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; } | ||
| 124 | #endif | ||
| 125 | |||
| 126 | bool MyGetOpenFileName(HWND hwnd, LPCWSTR title, | ||
| 127 | LPCWSTR initialDir, | ||
| 128 | LPCWSTR filePath, | ||
| 129 | LPCWSTR filterDescription, | ||
| 130 | LPCWSTR filter, | ||
| 131 | UString &resPath | ||
| 132 | #ifdef UNDER_CE | ||
| 133 | , bool openFolder | ||
| 134 | #endif | ||
| 135 | ) | ||
| 136 | { | ||
| 137 | const unsigned kBufSize = MAX_PATH * 2; | ||
| 138 | const unsigned kFilterBufSize = MAX_PATH; | ||
| 139 | if (!filter) | ||
| 140 | filter = L"*.*"; | ||
| 141 | #ifndef _UNICODE | ||
| 142 | if (!g_IsNT) | ||
| 143 | { | ||
| 144 | CHAR buf[kBufSize]; | ||
| 145 | MyStringCopy(buf, (const char *)GetSystemString(filePath)); | ||
| 146 | // OPENFILENAME_NT4A | ||
| 147 | OPENFILENAMEA p; | ||
| 148 | memset(&p, 0, sizeof(p)); | ||
| 149 | p.lStructSize = my_compatib_OPENFILENAMEA_size; | ||
| 150 | p.hwndOwner = hwnd; | ||
| 151 | CHAR filterBuf[kFilterBufSize]; | ||
| 152 | { | ||
| 153 | CDoubleZeroStringListA dz(filterBuf, kFilterBufSize); | ||
| 154 | dz.Add(GetSystemString(filterDescription ? filterDescription : filter)); | ||
| 155 | dz.Add(GetSystemString(filter)); | ||
| 156 | dz.Finish(); | ||
| 157 | p.lpstrFilter = filterBuf; | ||
| 158 | p.nFilterIndex = 1; | ||
| 159 | } | ||
| 160 | |||
| 161 | p.lpstrFile = buf; | ||
| 162 | p.nMaxFile = kBufSize; | ||
| 163 | CONV_U_To_A(p.lpstrInitialDir, initialDir, initialDirA); | ||
| 164 | CONV_U_To_A(p.lpstrTitle, title, titleA); | ||
| 165 | p.Flags = OFN_EXPLORER | OFN_HIDEREADONLY; | ||
| 166 | |||
| 167 | bool res = BOOLToBool(::GetOpenFileNameA(&p)); | ||
| 168 | resPath = GetUnicodeString(buf); | ||
| 169 | return res; | ||
| 170 | } | ||
| 171 | else | ||
| 172 | #endif | ||
| 173 | { | ||
| 174 | WCHAR buf[kBufSize]; | ||
| 175 | MyStringCopy(buf, filePath); | ||
| 176 | // OPENFILENAME_NT4W | ||
| 177 | OPENFILENAMEW p; | ||
| 178 | memset(&p, 0, sizeof(p)); | ||
| 179 | p.lStructSize = my_compatib_OPENFILENAMEW_size; | ||
| 180 | p.hwndOwner = hwnd; | ||
| 181 | |||
| 182 | WCHAR filterBuf[kFilterBufSize]; | ||
| 183 | { | ||
| 184 | CDoubleZeroStringListW dz(filterBuf, kFilterBufSize); | ||
| 185 | dz.Add(filterDescription ? filterDescription : filter); | ||
| 186 | dz.Add(filter); | ||
| 187 | dz.Finish(); | ||
| 188 | p.lpstrFilter = filterBuf; | ||
| 189 | p.nFilterIndex = 1; | ||
| 190 | } | ||
| 191 | |||
| 192 | p.lpstrFile = buf; | ||
| 193 | p.nMaxFile = kBufSize; | ||
| 194 | p.lpstrInitialDir = initialDir; | ||
| 195 | p.lpstrTitle = title; | ||
| 196 | p.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | ||
| 197 | #ifdef UNDER_CE | ||
| 198 | | (openFolder ? (MY__OFN_PROJECT | MY__OFN_SHOW_ALL) : 0) | ||
| 199 | #endif | ||
| 200 | ; | ||
| 201 | |||
| 202 | bool res = BOOLToBool(::GetOpenFileNameW(&p)); | ||
| 203 | resPath = buf; | ||
| 204 | return res; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | } | ||
diff --git a/CPP/Windows/CommonDialog.h b/CPP/Windows/CommonDialog.h new file mode 100644 index 0000000..aaf17ac --- /dev/null +++ b/CPP/Windows/CommonDialog.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | // Windows/CommonDialog.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_COMMON_DIALOG_H | ||
| 4 | #define __WINDOWS_COMMON_DIALOG_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | |||
| 10 | bool MyGetOpenFileName(HWND hwnd, LPCWSTR title, | ||
| 11 | LPCWSTR initialDir, // can be NULL, so dir prefix in filePath will be used | ||
| 12 | LPCWSTR filePath, // full path | ||
| 13 | LPCWSTR filterDescription, // like "All files (*.*)" | ||
| 14 | LPCWSTR filter, // like "*.exe" | ||
| 15 | UString &resPath | ||
| 16 | #ifdef UNDER_CE | ||
| 17 | , bool openFolder = false | ||
| 18 | #endif | ||
| 19 | ); | ||
| 20 | |||
| 21 | } | ||
| 22 | |||
| 23 | #endif | ||
diff --git a/CPP/Windows/Console.cpp b/CPP/Windows/Console.cpp new file mode 100644 index 0000000..28ba1c4 --- /dev/null +++ b/CPP/Windows/Console.cpp | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | // Windows/Console.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "Console.h" | ||
| 6 | |||
| 7 | namespace NWindows{ | ||
| 8 | namespace NConsole{ | ||
| 9 | |||
| 10 | }} | ||
diff --git a/CPP/Windows/Console.h b/CPP/Windows/Console.h new file mode 100644 index 0000000..43e02fa --- /dev/null +++ b/CPP/Windows/Console.h | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | // Windows/Console.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONSOLE_H | ||
| 4 | #define __WINDOWS_CONSOLE_H | ||
| 5 | |||
| 6 | #include "Defs.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NConsole { | ||
| 10 | |||
| 11 | class CBase | ||
| 12 | { | ||
| 13 | protected: | ||
| 14 | HANDLE m_Object; | ||
| 15 | public: | ||
| 16 | void Attach(HANDLE handle) { m_Object = handle; } | ||
| 17 | bool GetMode(DWORD &mode) | ||
| 18 | { return BOOLToBool(::GetConsoleMode(m_Object, &mode)); } | ||
| 19 | bool SetMode(DWORD mode) | ||
| 20 | { return BOOLToBool(::SetConsoleMode(m_Object, mode)); } | ||
| 21 | }; | ||
| 22 | |||
| 23 | class CIn: public CBase | ||
| 24 | { | ||
| 25 | public: | ||
| 26 | bool PeekEvents(PINPUT_RECORD events, DWORD numEvents, DWORD &numEventsRead) | ||
| 27 | { return BOOLToBool(::PeekConsoleInput(m_Object, events, numEvents, &numEventsRead)); } | ||
| 28 | bool PeekEvent(INPUT_RECORD &event, DWORD &numEventsRead) | ||
| 29 | { return PeekEvents(&event, 1, numEventsRead); } | ||
| 30 | bool ReadEvents(PINPUT_RECORD events, DWORD numEvents, DWORD &numEventsRead) | ||
| 31 | { return BOOLToBool(::ReadConsoleInput(m_Object, events, numEvents, &numEventsRead)); } | ||
| 32 | bool ReadEvent(INPUT_RECORD &event, DWORD &numEventsRead) | ||
| 33 | { return ReadEvents(&event, 1, numEventsRead); } | ||
| 34 | bool GetNumberOfEvents(DWORD &numEvents) | ||
| 35 | { return BOOLToBool(::GetNumberOfConsoleInputEvents(m_Object, &numEvents)); } | ||
| 36 | |||
| 37 | bool WriteEvents(const INPUT_RECORD *events, DWORD numEvents, DWORD &numEventsWritten) | ||
| 38 | { return BOOLToBool(::WriteConsoleInput(m_Object, events, numEvents, &numEventsWritten)); } | ||
| 39 | bool WriteEvent(const INPUT_RECORD &event, DWORD &numEventsWritten) | ||
| 40 | { return WriteEvents(&event, 1, numEventsWritten); } | ||
| 41 | |||
| 42 | bool Read(LPVOID buffer, DWORD numChars, DWORD &numCharsRead) | ||
| 43 | { return BOOLToBool(::ReadConsole(m_Object, buffer, numChars, &numCharsRead, NULL)); } | ||
| 44 | |||
| 45 | bool Flush() | ||
| 46 | { return BOOLToBool(::FlushConsoleInputBuffer(m_Object)); } | ||
| 47 | |||
| 48 | }; | ||
| 49 | |||
| 50 | }} | ||
| 51 | |||
| 52 | #endif | ||
diff --git a/CPP/Windows/Control/ComboBox.cpp b/CPP/Windows/Control/ComboBox.cpp new file mode 100644 index 0000000..f6ed8d3 --- /dev/null +++ b/CPP/Windows/Control/ComboBox.cpp | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | // Windows/Control/ComboBox.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef _UNICODE | ||
| 6 | #include "../../Common/StringConvert.h" | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #include "ComboBox.h" | ||
| 10 | |||
| 11 | #ifndef _UNICODE | ||
| 12 | extern bool g_IsNT; | ||
| 13 | #endif | ||
| 14 | |||
| 15 | namespace NWindows { | ||
| 16 | namespace NControl { | ||
| 17 | |||
| 18 | LRESULT CComboBox::GetLBText(int index, CSysString &s) | ||
| 19 | { | ||
| 20 | s.Empty(); | ||
| 21 | LRESULT len = GetLBTextLen(index); // length, excluding the terminating null character | ||
| 22 | if (len == CB_ERR) | ||
| 23 | return len; | ||
| 24 | LRESULT len2 = GetLBText(index, s.GetBuf((unsigned)len)); | ||
| 25 | if (len2 == CB_ERR) | ||
| 26 | return len; | ||
| 27 | if (len > len2) | ||
| 28 | len = len2; | ||
| 29 | s.ReleaseBuf_CalcLen((unsigned)len); | ||
| 30 | return len; | ||
| 31 | } | ||
| 32 | |||
| 33 | #ifndef _UNICODE | ||
| 34 | LRESULT CComboBox::AddString(LPCWSTR s) | ||
| 35 | { | ||
| 36 | if (g_IsNT) | ||
| 37 | return SendMsgW(CB_ADDSTRING, 0, (LPARAM)s); | ||
| 38 | return AddString(GetSystemString(s)); | ||
| 39 | } | ||
| 40 | |||
| 41 | LRESULT CComboBox::GetLBText(int index, UString &s) | ||
| 42 | { | ||
| 43 | s.Empty(); | ||
| 44 | if (g_IsNT) | ||
| 45 | { | ||
| 46 | LRESULT len = SendMsgW(CB_GETLBTEXTLEN, MY__int_TO_WPARAM(index), 0); | ||
| 47 | if (len == CB_ERR) | ||
| 48 | return len; | ||
| 49 | LRESULT len2 = SendMsgW(CB_GETLBTEXT, MY__int_TO_WPARAM(index), (LPARAM)s.GetBuf((unsigned)len)); | ||
| 50 | if (len2 == CB_ERR) | ||
| 51 | return len; | ||
| 52 | if (len > len2) | ||
| 53 | len = len2; | ||
| 54 | s.ReleaseBuf_CalcLen((unsigned)len); | ||
| 55 | return len; | ||
| 56 | } | ||
| 57 | AString sa; | ||
| 58 | LRESULT len = GetLBText(index, sa); | ||
| 59 | if (len == CB_ERR) | ||
| 60 | return len; | ||
| 61 | s = GetUnicodeString(sa); | ||
| 62 | return s.Len(); | ||
| 63 | } | ||
| 64 | #endif | ||
| 65 | |||
| 66 | }} | ||
diff --git a/CPP/Windows/Control/ComboBox.h b/CPP/Windows/Control/ComboBox.h new file mode 100644 index 0000000..f08b1f7 --- /dev/null +++ b/CPP/Windows/Control/ComboBox.h | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | // Windows/Control/ComboBox.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_COMBOBOX_H | ||
| 4 | #define __WINDOWS_CONTROL_COMBOBOX_H | ||
| 5 | |||
| 6 | #include "../../Common/MyWindows.h" | ||
| 7 | |||
| 8 | #include <CommCtrl.h> | ||
| 9 | |||
| 10 | #include "../Window.h" | ||
| 11 | |||
| 12 | namespace NWindows { | ||
| 13 | namespace NControl { | ||
| 14 | |||
| 15 | #define MY__int_TO_WPARAM(i) ((WPARAM)(INT_PTR)(i)) | ||
| 16 | |||
| 17 | class CComboBox: public CWindow | ||
| 18 | { | ||
| 19 | public: | ||
| 20 | void ResetContent() { SendMsg(CB_RESETCONTENT, 0, 0); } | ||
| 21 | LRESULT AddString(LPCTSTR s) { return SendMsg(CB_ADDSTRING, 0, (LPARAM)s); } | ||
| 22 | #ifndef _UNICODE | ||
| 23 | LRESULT AddString(LPCWSTR s); | ||
| 24 | #endif | ||
| 25 | |||
| 26 | /* If this parameter is -1, any current selection in the list is removed and the edit control is cleared.*/ | ||
| 27 | LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, MY__int_TO_WPARAM(index), 0); } | ||
| 28 | |||
| 29 | /* If no item is selected, it returns CB_ERR (-1) */ | ||
| 30 | int GetCurSel() { return (int)SendMsg(CB_GETCURSEL, 0, 0); } | ||
| 31 | |||
| 32 | /* If an error occurs, it is CB_ERR (-1) */ | ||
| 33 | int GetCount() { return (int)SendMsg(CB_GETCOUNT, 0, 0); } | ||
| 34 | |||
| 35 | LRESULT GetLBTextLen(int index) { return SendMsg(CB_GETLBTEXTLEN, MY__int_TO_WPARAM(index), 0); } | ||
| 36 | LRESULT GetLBText(int index, LPTSTR s) { return SendMsg(CB_GETLBTEXT, MY__int_TO_WPARAM(index), (LPARAM)s); } | ||
| 37 | LRESULT GetLBText(int index, CSysString &s); | ||
| 38 | #ifndef _UNICODE | ||
| 39 | LRESULT GetLBText(int index, UString &s); | ||
| 40 | #endif | ||
| 41 | |||
| 42 | LRESULT SetItemData(int index, LPARAM lParam) { return SendMsg(CB_SETITEMDATA, MY__int_TO_WPARAM(index), lParam); } | ||
| 43 | LRESULT GetItemData(int index) { return SendMsg(CB_GETITEMDATA, MY__int_TO_WPARAM(index), 0); } | ||
| 44 | |||
| 45 | LRESULT GetItemData_of_CurSel() { return GetItemData(GetCurSel()); } | ||
| 46 | |||
| 47 | void ShowDropDown(bool show = true) { SendMsg(CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); } | ||
| 48 | }; | ||
| 49 | |||
| 50 | #ifndef UNDER_CE | ||
| 51 | |||
| 52 | class CComboBoxEx: public CComboBox | ||
| 53 | { | ||
| 54 | public: | ||
| 55 | bool SetUnicodeFormat(bool fUnicode) { return LRESULTToBool(SendMsg(CBEM_SETUNICODEFORMAT, BOOLToBool(fUnicode), 0)); } | ||
| 56 | |||
| 57 | /* Returns: | ||
| 58 | an INT value that represents the number of items remaining in the control. | ||
| 59 | If (index) is invalid, the message returns CB_ERR. */ | ||
| 60 | LRESULT DeleteItem(int index) { return SendMsg(CBEM_DELETEITEM, MY__int_TO_WPARAM(index), 0); } | ||
| 61 | |||
| 62 | LRESULT InsertItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_INSERTITEM, 0, (LPARAM)item); } | ||
| 63 | #ifndef _UNICODE | ||
| 64 | LRESULT InsertItem(COMBOBOXEXITEMW *item) { return SendMsg(CBEM_INSERTITEMW, 0, (LPARAM)item); } | ||
| 65 | #endif | ||
| 66 | |||
| 67 | LRESULT SetItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_SETITEM, 0, (LPARAM)item); } | ||
| 68 | DWORD SetExtendedStyle(DWORD exMask, DWORD exStyle) { return (DWORD)SendMsg(CBEM_SETEXTENDEDSTYLE, exMask, exStyle); } | ||
| 69 | HWND GetEditControl() { return (HWND)SendMsg(CBEM_GETEDITCONTROL, 0, 0); } | ||
| 70 | HIMAGELIST SetImageList(HIMAGELIST imageList) { return (HIMAGELIST)SendMsg(CBEM_SETIMAGELIST, 0, (LPARAM)imageList); } | ||
| 71 | }; | ||
| 72 | |||
| 73 | #endif | ||
| 74 | |||
| 75 | }} | ||
| 76 | |||
| 77 | #endif | ||
diff --git a/CPP/Windows/Control/CommandBar.h b/CPP/Windows/Control/CommandBar.h new file mode 100644 index 0000000..a619744 --- /dev/null +++ b/CPP/Windows/Control/CommandBar.h | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | // Windows/Control/CommandBar.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_COMMANDBAR_H | ||
| 4 | #define __WINDOWS_CONTROL_COMMANDBAR_H | ||
| 5 | |||
| 6 | #ifdef UNDER_CE | ||
| 7 | |||
| 8 | #include "../../Common/MyWindows.h" | ||
| 9 | |||
| 10 | #include <commctrl.h> | ||
| 11 | |||
| 12 | #include "../Window.h" | ||
| 13 | |||
| 14 | namespace NWindows { | ||
| 15 | namespace NControl { | ||
| 16 | |||
| 17 | class CCommandBar: public NWindows::CWindow | ||
| 18 | { | ||
| 19 | public: | ||
| 20 | bool Create(HINSTANCE hInst, HWND hwndParent, int idCmdBar) | ||
| 21 | { | ||
| 22 | _window = ::CommandBar_Create(hInst, hwndParent, idCmdBar); | ||
| 23 | return (_window != NULL); | ||
| 24 | } | ||
| 25 | |||
| 26 | // Macros | ||
| 27 | // void Destroy() { CommandBar_Destroy(_window); } | ||
| 28 | // bool AddButtons(UINT numButtons, LPTBBUTTON buttons) { return BOOLToBool(SendMsg(TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)buttons)); } | ||
| 29 | bool InsertButton(int iButton, LPTBBUTTON button) { return BOOLToBool(SendMsg(TB_INSERTBUTTON, (WPARAM)iButton, (LPARAM)button)); } | ||
| 30 | BOOL AddToolTips(UINT numToolTips, LPTSTR toolTips) { return BOOLToBool(SendMsg(TB_SETTOOLTIPS, (WPARAM)numToolTips, (LPARAM)toolTips)); } | ||
| 31 | void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); } | ||
| 32 | |||
| 33 | bool AddAdornments(DWORD dwFlags) { return BOOLToBool(::CommandBar_AddAdornments(_window, dwFlags, 0)); } | ||
| 34 | int AddBitmap(HINSTANCE hInst, int idBitmap, int iNumImages, int iImageWidth, int iImageHeight) { return ::CommandBar_AddBitmap(_window, hInst, idBitmap, iNumImages, iImageWidth, iImageHeight); } | ||
| 35 | bool DrawMenuBar(WORD iButton) { return BOOLToBool(::CommandBar_DrawMenuBar(_window, iButton)); } | ||
| 36 | HMENU GetMenu(WORD iButton) { return ::CommandBar_GetMenu(_window, iButton); } | ||
| 37 | int Height() { return CommandBar_Height(_window); } | ||
| 38 | HWND InsertComboBox(HINSTANCE hInst, int iWidth, UINT dwStyle, WORD idComboBox, WORD iButton) { return ::CommandBar_InsertComboBox(_window, hInst, iWidth, dwStyle, idComboBox, iButton); } | ||
| 39 | bool InsertMenubar(HINSTANCE hInst, WORD idMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubar(_window, hInst, idMenu, iButton)); } | ||
| 40 | bool InsertMenubarEx(HINSTANCE hInst, LPTSTR pszMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubarEx(_window, hInst, pszMenu, iButton)); } | ||
| 41 | bool Show(bool cmdShow) { return BOOLToBool(::CommandBar_Show(_window, BoolToBOOL(cmdShow))); } | ||
| 42 | |||
| 43 | |||
| 44 | // CE 4.0 | ||
| 45 | void AlignAdornments() { CommandBar_AlignAdornments(_window); } | ||
| 46 | }; | ||
| 47 | |||
| 48 | }} | ||
| 49 | |||
| 50 | #endif | ||
| 51 | |||
| 52 | #endif | ||
diff --git a/CPP/Windows/Control/Dialog.cpp b/CPP/Windows/Control/Dialog.cpp new file mode 100644 index 0000000..9ddd234 --- /dev/null +++ b/CPP/Windows/Control/Dialog.cpp | |||
| @@ -0,0 +1,414 @@ | |||
| 1 | // Windows/Control/Dialog.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | // #include "../../Windows/DLL.h" | ||
| 6 | |||
| 7 | #ifndef _UNICODE | ||
| 8 | #include "../../Common/StringConvert.h" | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #include "Dialog.h" | ||
| 12 | |||
| 13 | extern HINSTANCE g_hInstance; | ||
| 14 | #ifndef _UNICODE | ||
| 15 | extern bool g_IsNT; | ||
| 16 | #endif | ||
| 17 | |||
| 18 | namespace NWindows { | ||
| 19 | namespace NControl { | ||
| 20 | |||
| 21 | static INT_PTR APIENTRY DialogProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam) | ||
| 22 | { | ||
| 23 | CWindow tempDialog(dialogHWND); | ||
| 24 | if (message == WM_INITDIALOG) | ||
| 25 | tempDialog.SetUserDataLongPtr(lParam); | ||
| 26 | CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr()); | ||
| 27 | if (dialog == NULL) | ||
| 28 | return FALSE; | ||
| 29 | if (message == WM_INITDIALOG) | ||
| 30 | dialog->Attach(dialogHWND); | ||
| 31 | |||
| 32 | /* MSDN: The dialog box procedure should return | ||
| 33 | TRUE - if it processed the message | ||
| 34 | FALSE - if it did not process the message | ||
| 35 | If the dialog box procedure returns FALSE, | ||
| 36 | the dialog manager performs the default dialog operation in response to the message. | ||
| 37 | */ | ||
| 38 | |||
| 39 | try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); } | ||
| 40 | catch(...) { return TRUE; } | ||
| 41 | } | ||
| 42 | |||
| 43 | bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) | ||
| 44 | { | ||
| 45 | switch (message) | ||
| 46 | { | ||
| 47 | case WM_INITDIALOG: return OnInit(); | ||
| 48 | case WM_COMMAND: return OnCommand(wParam, lParam); | ||
| 49 | case WM_NOTIFY: return OnNotify((UINT)wParam, (LPNMHDR) lParam); | ||
| 50 | case WM_TIMER: return OnTimer(wParam, lParam); | ||
| 51 | case WM_SIZE: return OnSize(wParam, LOWORD(lParam), HIWORD(lParam)); | ||
| 52 | case WM_DESTROY: return OnDestroy(); | ||
| 53 | case WM_HELP: OnHelp(); return true; | ||
| 54 | /* | ||
| 55 | OnHelp( | ||
| 56 | #ifdef UNDER_CE | ||
| 57 | (void *) | ||
| 58 | #else | ||
| 59 | (LPHELPINFO) | ||
| 60 | #endif | ||
| 61 | lParam); | ||
| 62 | return true; | ||
| 63 | */ | ||
| 64 | default: return false; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | bool CDialog::OnCommand(WPARAM wParam, LPARAM lParam) | ||
| 69 | { | ||
| 70 | return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam); | ||
| 71 | } | ||
| 72 | |||
| 73 | bool CDialog::OnCommand(int code, int itemID, LPARAM lParam) | ||
| 74 | { | ||
| 75 | if (code == BN_CLICKED) | ||
| 76 | return OnButtonClicked(itemID, (HWND)lParam); | ||
| 77 | return false; | ||
| 78 | } | ||
| 79 | |||
| 80 | bool CDialog::OnButtonClicked(int buttonID, HWND /* buttonHWND */) | ||
| 81 | { | ||
| 82 | switch (buttonID) | ||
| 83 | { | ||
| 84 | case IDOK: OnOK(); break; | ||
| 85 | case IDCANCEL: OnCancel(); break; | ||
| 86 | case IDCLOSE: OnClose(); break; | ||
| 87 | case IDHELP: OnHelp(); break; | ||
| 88 | default: return false; | ||
| 89 | } | ||
| 90 | return true; | ||
| 91 | } | ||
| 92 | |||
| 93 | |||
| 94 | static bool GetWorkAreaRect(RECT *rect, HWND hwnd) | ||
| 95 | { | ||
| 96 | if (hwnd) | ||
| 97 | { | ||
| 98 | #ifndef UNDER_CE | ||
| 99 | /* MonitorFromWindow() is supported in Win2000+ | ||
| 100 | MonitorFromWindow() : retrieves a handle to the display monitor that has the | ||
| 101 | largest area of intersection with the bounding rectangle of a specified window. | ||
| 102 | dwFlags: Determines the function's return value if the window does not intersect any display monitor. | ||
| 103 | MONITOR_DEFAULTTONEAREST : Returns display that is nearest to the window. | ||
| 104 | MONITOR_DEFAULTTONULL : Returns NULL. | ||
| 105 | MONITOR_DEFAULTTOPRIMARY : Returns the primary display monitor. | ||
| 106 | */ | ||
| 107 | const HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); | ||
| 108 | if (hmon) | ||
| 109 | { | ||
| 110 | MONITORINFO mi; | ||
| 111 | memset(&mi, 0, sizeof(mi)); | ||
| 112 | mi.cbSize = sizeof(mi); | ||
| 113 | if (GetMonitorInfoA(hmon, &mi)) | ||
| 114 | { | ||
| 115 | *rect = mi.rcWork; | ||
| 116 | return true; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | #endif | ||
| 120 | } | ||
| 121 | |||
| 122 | /* Retrieves the size of the work area on the primary display monitor. | ||
| 123 | The work area is the portion of the screen not obscured | ||
| 124 | by the system taskbar or by application desktop toolbars. | ||
| 125 | Any DPI virtualization mode of the caller has no effect on this output. */ | ||
| 126 | |||
| 127 | return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0)); | ||
| 128 | } | ||
| 129 | |||
| 130 | |||
| 131 | bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd) | ||
| 132 | { | ||
| 133 | // it returns for system font. Real font uses another values | ||
| 134 | const LONG v = GetDialogBaseUnits(); | ||
| 135 | const int x = LOWORD(v); | ||
| 136 | const int y = HIWORD(v); | ||
| 137 | |||
| 138 | RECT rect; | ||
| 139 | GetWorkAreaRect(&rect, hwnd); | ||
| 140 | const int wx = RECT_SIZE_X(rect); | ||
| 141 | const int wy = RECT_SIZE_Y(rect); | ||
| 142 | return | ||
| 143 | xSize / 4 * x <= wx && | ||
| 144 | ySize / 8 * y <= wy; | ||
| 145 | } | ||
| 146 | |||
| 147 | bool CDialog::GetMargins(int margin, int &x, int &y) | ||
| 148 | { | ||
| 149 | x = margin; | ||
| 150 | y = margin; | ||
| 151 | RECT rect; | ||
| 152 | rect.left = 0; | ||
| 153 | rect.top = 0; | ||
| 154 | rect.right = margin; | ||
| 155 | rect.bottom = margin; | ||
| 156 | if (!MapRect(&rect)) | ||
| 157 | return false; | ||
| 158 | x = rect.right - rect.left; | ||
| 159 | y = rect.bottom - rect.top; | ||
| 160 | return true; | ||
| 161 | } | ||
| 162 | |||
| 163 | int CDialog::Units_To_Pixels_X(int units) | ||
| 164 | { | ||
| 165 | RECT rect; | ||
| 166 | rect.left = 0; | ||
| 167 | rect.top = 0; | ||
| 168 | rect.right = units; | ||
| 169 | rect.bottom = units; | ||
| 170 | if (!MapRect(&rect)) | ||
| 171 | return units * 3 / 2; | ||
| 172 | return rect.right - rect.left; | ||
| 173 | } | ||
| 174 | |||
| 175 | bool CDialog::GetItemSizes(int id, int &x, int &y) | ||
| 176 | { | ||
| 177 | RECT rect; | ||
| 178 | if (!::GetWindowRect(GetItem(id), &rect)) | ||
| 179 | return false; | ||
| 180 | x = RECT_SIZE_X(rect); | ||
| 181 | y = RECT_SIZE_Y(rect); | ||
| 182 | return true; | ||
| 183 | } | ||
| 184 | |||
| 185 | void CDialog::GetClientRectOfItem(int id, RECT &rect) | ||
| 186 | { | ||
| 187 | ::GetWindowRect(GetItem(id), &rect); | ||
| 188 | ScreenToClient(&rect); | ||
| 189 | } | ||
| 190 | |||
| 191 | bool CDialog::MoveItem(int id, int x, int y, int width, int height, bool repaint) | ||
| 192 | { | ||
| 193 | return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint))); | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | /* | ||
| 198 | typedef BOOL (WINAPI * Func_DwmGetWindowAttribute)( | ||
| 199 | HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute); | ||
| 200 | |||
| 201 | static bool GetWindowsRect_DWM(HWND hwnd, RECT *rect) | ||
| 202 | { | ||
| 203 | // dll load and free is too slow : 300 calls in second. | ||
| 204 | NDLL::CLibrary dll; | ||
| 205 | if (!dll.Load(FTEXT("dwmapi.dll"))) | ||
| 206 | return false; | ||
| 207 | Func_DwmGetWindowAttribute f = (Func_DwmGetWindowAttribute)dll.GetProc("DwmGetWindowAttribute" ); | ||
| 208 | if (f) | ||
| 209 | { | ||
| 210 | #define MY__DWMWA_EXTENDED_FRAME_BOUNDS 9 | ||
| 211 | // 30000 per second | ||
| 212 | RECT r; | ||
| 213 | if (f(hwnd, MY__DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK) | ||
| 214 | { | ||
| 215 | *rect = r; | ||
| 216 | return true; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | return false; | ||
| 220 | } | ||
| 221 | */ | ||
| 222 | |||
| 223 | |||
| 224 | static bool IsRect_Small_Inside_Big(const RECT &sm, const RECT &big) | ||
| 225 | { | ||
| 226 | return sm.left >= big.left | ||
| 227 | && sm.right <= big.right | ||
| 228 | && sm.top >= big.top | ||
| 229 | && sm.bottom <= big.bottom; | ||
| 230 | } | ||
| 231 | |||
| 232 | |||
| 233 | static bool AreRectsOverlapped(const RECT &r1, const RECT &r2) | ||
| 234 | { | ||
| 235 | return r1.left < r2.right | ||
| 236 | && r1.right > r2.left | ||
| 237 | && r1.top < r2.bottom | ||
| 238 | && r1.bottom > r2.top; | ||
| 239 | } | ||
| 240 | |||
| 241 | |||
| 242 | static bool AreRectsEqual(const RECT &r1, const RECT &r2) | ||
| 243 | { | ||
| 244 | return r1.left == r2.left | ||
| 245 | && r1.right == r2.right | ||
| 246 | && r1.top == r2.top | ||
| 247 | && r1.bottom == r2.bottom; | ||
| 248 | } | ||
| 249 | |||
| 250 | |||
| 251 | void CDialog::NormalizeSize(bool fullNormalize) | ||
| 252 | { | ||
| 253 | RECT workRect; | ||
| 254 | if (!GetWorkAreaRect(&workRect, *this)) | ||
| 255 | return; | ||
| 256 | RECT rect; | ||
| 257 | if (!GetWindowRect(&rect)) | ||
| 258 | return; | ||
| 259 | int xs = RECT_SIZE_X(rect); | ||
| 260 | int ys = RECT_SIZE_Y(rect); | ||
| 261 | |||
| 262 | // we don't want to change size using workRect, if window is outside of WorkArea | ||
| 263 | if (!AreRectsOverlapped(rect, workRect)) | ||
| 264 | return; | ||
| 265 | |||
| 266 | /* here rect and workRect are overlapped, but it can be false | ||
| 267 | overlapping of small shadow when window in another display. */ | ||
| 268 | |||
| 269 | const int xsW = RECT_SIZE_X(workRect); | ||
| 270 | const int ysW = RECT_SIZE_Y(workRect); | ||
| 271 | if (xs <= xsW && ys <= ysW) | ||
| 272 | return; // size of window is OK | ||
| 273 | if (fullNormalize) | ||
| 274 | { | ||
| 275 | Show(SW_SHOWMAXIMIZED); | ||
| 276 | return; | ||
| 277 | } | ||
| 278 | int x = workRect.left; | ||
| 279 | int y = workRect.top; | ||
| 280 | if (xs < xsW) x += (xsW - xs) / 2; else xs = xsW; | ||
| 281 | if (ys < ysW) y += (ysW - ys) / 2; else ys = ysW; | ||
| 282 | Move(x, y, xs, ys, true); | ||
| 283 | } | ||
| 284 | |||
| 285 | |||
| 286 | void CDialog::NormalizePosition() | ||
| 287 | { | ||
| 288 | RECT workRect; | ||
| 289 | if (!GetWorkAreaRect(&workRect, *this)) | ||
| 290 | return; | ||
| 291 | |||
| 292 | RECT rect2 = workRect; | ||
| 293 | bool useWorkArea = true; | ||
| 294 | const HWND parentHWND = GetParent(); | ||
| 295 | |||
| 296 | if (parentHWND) | ||
| 297 | { | ||
| 298 | RECT workRectParent; | ||
| 299 | if (!GetWorkAreaRect(&workRectParent, parentHWND)) | ||
| 300 | return; | ||
| 301 | |||
| 302 | // if windows are in different monitors, we use only workArea of current window | ||
| 303 | |||
| 304 | if (AreRectsEqual(workRectParent, workRect)) | ||
| 305 | { | ||
| 306 | // RECT rect3; if (GetWindowsRect_DWM(parentHWND, &rect3)) {} | ||
| 307 | CWindow wnd(parentHWND); | ||
| 308 | if (wnd.GetWindowRect(&rect2)) | ||
| 309 | { | ||
| 310 | // it's same monitor. So we try to use parentHWND rect. | ||
| 311 | /* we don't want to change position, if parent window is not inside work area. | ||
| 312 | In Win10 : parent window rect is 8 pixels larger for each corner than window size for shadow. | ||
| 313 | In maximize mode : window is outside of workRect. | ||
| 314 | if parent window is inside workRect, we will use parent window instead of workRect */ | ||
| 315 | if (IsRect_Small_Inside_Big(rect2, workRect)) | ||
| 316 | useWorkArea = false; | ||
| 317 | } | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | RECT rect; | ||
| 322 | if (!GetWindowRect(&rect)) | ||
| 323 | return; | ||
| 324 | |||
| 325 | if (useWorkArea) | ||
| 326 | { | ||
| 327 | // we don't want to move window, if it's already inside. | ||
| 328 | if (IsRect_Small_Inside_Big(rect, workRect)) | ||
| 329 | return; | ||
| 330 | // we don't want to move window, if it's outside of workArea | ||
| 331 | if (!AreRectsOverlapped(rect, workRect)) | ||
| 332 | return; | ||
| 333 | rect2 = workRect; | ||
| 334 | } | ||
| 335 | |||
| 336 | { | ||
| 337 | const int xs = RECT_SIZE_X(rect); | ||
| 338 | const int ys = RECT_SIZE_Y(rect); | ||
| 339 | const int xs2 = RECT_SIZE_X(rect2); | ||
| 340 | const int ys2 = RECT_SIZE_Y(rect2); | ||
| 341 | // we don't want to change position if parent is smaller. | ||
| 342 | if (xs <= xs2 && ys <= ys2) | ||
| 343 | { | ||
| 344 | const int x = rect2.left + (xs2 - xs) / 2; | ||
| 345 | const int y = rect2.top + (ys2 - ys) / 2; | ||
| 346 | |||
| 347 | if (x != rect.left || y != rect.top) | ||
| 348 | Move(x, y, xs, ys, true); | ||
| 349 | // SetWindowPos(*this, HWND_TOP, x, y, 0, 0, SWP_NOSIZE); | ||
| 350 | return; | ||
| 351 | } | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | |||
| 356 | |||
| 357 | bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow) | ||
| 358 | { | ||
| 359 | HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); | ||
| 360 | if (aHWND == 0) | ||
| 361 | return false; | ||
| 362 | Attach(aHWND); | ||
| 363 | return true; | ||
| 364 | } | ||
| 365 | |||
| 366 | INT_PTR CModalDialog::Create(LPCTSTR templateName, HWND parentWindow) | ||
| 367 | { | ||
| 368 | return DialogBoxParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); | ||
| 369 | } | ||
| 370 | |||
| 371 | #ifndef _UNICODE | ||
| 372 | |||
| 373 | bool CModelessDialog::Create(LPCWSTR templateName, HWND parentWindow) | ||
| 374 | { | ||
| 375 | HWND aHWND; | ||
| 376 | if (g_IsNT) | ||
| 377 | aHWND = CreateDialogParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); | ||
| 378 | else | ||
| 379 | { | ||
| 380 | AString name; | ||
| 381 | LPCSTR templateNameA; | ||
| 382 | if (IS_INTRESOURCE(templateName)) | ||
| 383 | templateNameA = (LPCSTR)templateName; | ||
| 384 | else | ||
| 385 | { | ||
| 386 | name = GetSystemString(templateName); | ||
| 387 | templateNameA = name; | ||
| 388 | } | ||
| 389 | aHWND = CreateDialogParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this); | ||
| 390 | } | ||
| 391 | if (aHWND == 0) | ||
| 392 | return false; | ||
| 393 | Attach(aHWND); | ||
| 394 | return true; | ||
| 395 | } | ||
| 396 | |||
| 397 | INT_PTR CModalDialog::Create(LPCWSTR templateName, HWND parentWindow) | ||
| 398 | { | ||
| 399 | if (g_IsNT) | ||
| 400 | return DialogBoxParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); | ||
| 401 | AString name; | ||
| 402 | LPCSTR templateNameA; | ||
| 403 | if (IS_INTRESOURCE(templateName)) | ||
| 404 | templateNameA = (LPCSTR)templateName; | ||
| 405 | else | ||
| 406 | { | ||
| 407 | name = GetSystemString(templateName); | ||
| 408 | templateNameA = name; | ||
| 409 | } | ||
| 410 | return DialogBoxParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this); | ||
| 411 | } | ||
| 412 | #endif | ||
| 413 | |||
| 414 | }} | ||
diff --git a/CPP/Windows/Control/Dialog.h b/CPP/Windows/Control/Dialog.h new file mode 100644 index 0000000..8a39e99 --- /dev/null +++ b/CPP/Windows/Control/Dialog.h | |||
| @@ -0,0 +1,190 @@ | |||
| 1 | // Windows/Control/Dialog.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_DIALOG_H | ||
| 4 | #define __WINDOWS_CONTROL_DIALOG_H | ||
| 5 | |||
| 6 | #include "../Window.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NControl { | ||
| 10 | |||
| 11 | class CDialog: public CWindow | ||
| 12 | { | ||
| 13 | public: | ||
| 14 | CDialog(HWND wnd = NULL): CWindow(wnd){}; | ||
| 15 | virtual ~CDialog() {}; | ||
| 16 | |||
| 17 | HWND GetItem(int itemID) const | ||
| 18 | { return GetDlgItem(_window, itemID); } | ||
| 19 | |||
| 20 | bool EnableItem(int itemID, bool enable) const | ||
| 21 | { return BOOLToBool(::EnableWindow(GetItem(itemID), BoolToBOOL(enable))); } | ||
| 22 | |||
| 23 | bool ShowItem(int itemID, int cmdShow) const | ||
| 24 | { return BOOLToBool(::ShowWindow(GetItem(itemID), cmdShow)); } | ||
| 25 | |||
| 26 | bool ShowItem_Bool(int itemID, bool show) const | ||
| 27 | { return ShowItem(itemID, show ? SW_SHOW: SW_HIDE); } | ||
| 28 | |||
| 29 | bool HideItem(int itemID) const { return ShowItem(itemID, SW_HIDE); } | ||
| 30 | |||
| 31 | bool SetItemText(int itemID, LPCTSTR s) | ||
| 32 | { return BOOLToBool(SetDlgItemText(_window, itemID, s)); } | ||
| 33 | |||
| 34 | bool SetItemTextA(int itemID, LPCSTR s) | ||
| 35 | { return BOOLToBool(SetDlgItemTextA(_window, itemID, s)); } | ||
| 36 | |||
| 37 | bool SetItemText_Empty(int itemID) | ||
| 38 | { return SetItemText(itemID, TEXT("")); } | ||
| 39 | |||
| 40 | #ifndef _UNICODE | ||
| 41 | bool SetItemText(int itemID, LPCWSTR s) | ||
| 42 | { | ||
| 43 | CWindow window(GetItem(itemID)); | ||
| 44 | return window.SetText(s); | ||
| 45 | } | ||
| 46 | #endif | ||
| 47 | |||
| 48 | UINT GetItemText(int itemID, LPTSTR string, int maxCount) | ||
| 49 | { return GetDlgItemText(_window, itemID, string, maxCount); } | ||
| 50 | #ifndef _UNICODE | ||
| 51 | /* | ||
| 52 | bool GetItemText(int itemID, LPWSTR string, int maxCount) | ||
| 53 | { | ||
| 54 | CWindow window(GetItem(itemID)); | ||
| 55 | return window.GetText(string, maxCount); | ||
| 56 | } | ||
| 57 | */ | ||
| 58 | #endif | ||
| 59 | |||
| 60 | bool GetItemText(int itemID, UString &s) | ||
| 61 | { | ||
| 62 | CWindow window(GetItem(itemID)); | ||
| 63 | return window.GetText(s); | ||
| 64 | } | ||
| 65 | |||
| 66 | bool SetItemInt(int itemID, UINT value, bool isSigned) | ||
| 67 | { return BOOLToBool(SetDlgItemInt(_window, itemID, value, BoolToBOOL(isSigned))); } | ||
| 68 | bool GetItemInt(int itemID, bool isSigned, UINT &value) | ||
| 69 | { | ||
| 70 | BOOL result; | ||
| 71 | value = GetDlgItemInt(_window, itemID, &result, BoolToBOOL(isSigned)); | ||
| 72 | return BOOLToBool(result); | ||
| 73 | } | ||
| 74 | |||
| 75 | HWND GetNextGroupItem(HWND control, bool previous) | ||
| 76 | { return GetNextDlgGroupItem(_window, control, BoolToBOOL(previous)); } | ||
| 77 | HWND GetNextTabItem(HWND control, bool previous) | ||
| 78 | { return GetNextDlgTabItem(_window, control, BoolToBOOL(previous)); } | ||
| 79 | |||
| 80 | LRESULT SendMsg_NextDlgCtl(WPARAM wParam, LPARAM lParam) | ||
| 81 | { return SendMsg(WM_NEXTDLGCTL, wParam, lParam); } | ||
| 82 | LRESULT SendMsg_NextDlgCtl_HWND(HWND hwnd) { return SendMsg_NextDlgCtl((WPARAM)hwnd, TRUE); } | ||
| 83 | LRESULT SendMsg_NextDlgCtl_CtlId(int id) { return SendMsg_NextDlgCtl_HWND(GetItem(id)); } | ||
| 84 | LRESULT SendMsg_NextDlgCtl_Next() { return SendMsg_NextDlgCtl(0, FALSE); } | ||
| 85 | LRESULT SendMsg_NextDlgCtl_Prev() { return SendMsg_NextDlgCtl(1, FALSE); } | ||
| 86 | |||
| 87 | bool MapRect(LPRECT rect) | ||
| 88 | { return BOOLToBool(MapDialogRect(_window, rect)); } | ||
| 89 | |||
| 90 | bool IsMessage(LPMSG message) | ||
| 91 | { return BOOLToBool(IsDialogMessage(_window, message)); } | ||
| 92 | |||
| 93 | LRESULT SendItemMessage(int itemID, UINT message, WPARAM wParam, LPARAM lParam) | ||
| 94 | { return SendDlgItemMessage(_window, itemID, message, wParam, lParam); } | ||
| 95 | |||
| 96 | bool CheckButton(int buttonID, UINT checkState) | ||
| 97 | { return BOOLToBool(CheckDlgButton(_window, buttonID, checkState)); } | ||
| 98 | bool CheckButton(int buttonID, bool checkState) | ||
| 99 | { return CheckButton(buttonID, UINT(checkState ? BST_CHECKED : BST_UNCHECKED)); } | ||
| 100 | |||
| 101 | UINT IsButtonChecked(int buttonID) const | ||
| 102 | { return IsDlgButtonChecked(_window, buttonID); } | ||
| 103 | bool IsButtonCheckedBool(int buttonID) const | ||
| 104 | { return (IsButtonChecked(buttonID) == BST_CHECKED); } | ||
| 105 | |||
| 106 | bool CheckRadioButton(int firstButtonID, int lastButtonID, int checkButtonID) | ||
| 107 | { return BOOLToBool(::CheckRadioButton(_window, firstButtonID, lastButtonID, checkButtonID)); } | ||
| 108 | |||
| 109 | virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam); | ||
| 110 | virtual bool OnInit() { return true; } | ||
| 111 | virtual bool OnCommand(WPARAM wParam, LPARAM lParam); | ||
| 112 | virtual bool OnCommand(int code, int itemID, LPARAM lParam); | ||
| 113 | virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; } | ||
| 114 | virtual bool OnDestroy() { return false; } | ||
| 115 | |||
| 116 | /* | ||
| 117 | #ifdef UNDER_CE | ||
| 118 | virtual void OnHelp(void *) { OnHelp(); } | ||
| 119 | #else | ||
| 120 | virtual void OnHelp(LPHELPINFO) { OnHelp(); } | ||
| 121 | #endif | ||
| 122 | */ | ||
| 123 | virtual void OnHelp() {}; | ||
| 124 | |||
| 125 | virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); | ||
| 126 | virtual void OnOK() {}; | ||
| 127 | virtual void OnCancel() {}; | ||
| 128 | virtual void OnClose() {} | ||
| 129 | virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */) { return false; } | ||
| 130 | virtual bool OnTimer(WPARAM /* timerID */, LPARAM /* callback */) { return false; } | ||
| 131 | |||
| 132 | LONG_PTR SetMsgResult(LONG_PTR newLongPtr ) | ||
| 133 | { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); } | ||
| 134 | LONG_PTR GetMsgResult() const | ||
| 135 | { return GetLongPtr(DWLP_MSGRESULT); } | ||
| 136 | |||
| 137 | bool GetMargins(int margin, int &x, int &y); | ||
| 138 | int Units_To_Pixels_X(int units); | ||
| 139 | bool GetItemSizes(int id, int &x, int &y); | ||
| 140 | void GetClientRectOfItem(int id, RECT &rect); | ||
| 141 | bool MoveItem(int id, int x, int y, int width, int height, bool repaint = true); | ||
| 142 | |||
| 143 | void NormalizeSize(bool fullNormalize = false); | ||
| 144 | void NormalizePosition(); | ||
| 145 | }; | ||
| 146 | |||
| 147 | class CModelessDialog: public CDialog | ||
| 148 | { | ||
| 149 | public: | ||
| 150 | bool Create(LPCTSTR templateName, HWND parentWindow); | ||
| 151 | bool Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); } | ||
| 152 | #ifndef _UNICODE | ||
| 153 | bool Create(LPCWSTR templateName, HWND parentWindow); | ||
| 154 | #endif | ||
| 155 | virtual void OnOK() { Destroy(); } | ||
| 156 | virtual void OnCancel() { Destroy(); } | ||
| 157 | virtual void OnClose() { Destroy(); } | ||
| 158 | }; | ||
| 159 | |||
| 160 | class CModalDialog: public CDialog | ||
| 161 | { | ||
| 162 | public: | ||
| 163 | INT_PTR Create(LPCTSTR templateName, HWND parentWindow); | ||
| 164 | INT_PTR Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); } | ||
| 165 | #ifndef _UNICODE | ||
| 166 | INT_PTR Create(LPCWSTR templateName, HWND parentWindow); | ||
| 167 | #endif | ||
| 168 | |||
| 169 | bool End(INT_PTR result) { return BOOLToBool(::EndDialog(_window, result)); } | ||
| 170 | virtual void OnOK() { End(IDOK); } | ||
| 171 | virtual void OnCancel() { End(IDCANCEL); } | ||
| 172 | virtual void OnClose() { End(IDCLOSE); } | ||
| 173 | }; | ||
| 174 | |||
| 175 | class CDialogChildControl: public NWindows::CWindow | ||
| 176 | { | ||
| 177 | int m_ID; | ||
| 178 | public: | ||
| 179 | void Init(const NWindows::NControl::CDialog &parentDialog, int id) | ||
| 180 | { | ||
| 181 | m_ID = id; | ||
| 182 | Attach(parentDialog.GetItem(id)); | ||
| 183 | } | ||
| 184 | }; | ||
| 185 | |||
| 186 | bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd = NULL); | ||
| 187 | |||
| 188 | }} | ||
| 189 | |||
| 190 | #endif | ||
diff --git a/CPP/Windows/Control/Edit.h b/CPP/Windows/Control/Edit.h new file mode 100644 index 0000000..51a22c5 --- /dev/null +++ b/CPP/Windows/Control/Edit.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // Windows/Control/Edit.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_EDIT_H | ||
| 4 | #define __WINDOWS_CONTROL_EDIT_H | ||
| 5 | |||
| 6 | #include "../Window.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NControl { | ||
| 10 | |||
| 11 | class CEdit: public CWindow | ||
| 12 | { | ||
| 13 | public: | ||
| 14 | void SetPasswordChar(WPARAM c) { SendMsg(EM_SETPASSWORDCHAR, c); } | ||
| 15 | }; | ||
| 16 | |||
| 17 | }} | ||
| 18 | |||
| 19 | #endif | ||
diff --git a/CPP/Windows/Control/ImageList.cpp b/CPP/Windows/Control/ImageList.cpp new file mode 100644 index 0000000..3e22b95 --- /dev/null +++ b/CPP/Windows/Control/ImageList.cpp | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | // Windows/Control/ImageList.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "ImageList.h" | ||
| 6 | |||
| 7 | namespace NWindows { | ||
| 8 | namespace NControl { | ||
| 9 | |||
| 10 | }} | ||
diff --git a/CPP/Windows/Control/ImageList.h b/CPP/Windows/Control/ImageList.h new file mode 100644 index 0000000..19feb11 --- /dev/null +++ b/CPP/Windows/Control/ImageList.h | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | // Windows/Control/ImageList.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_IMAGE_LIST_H | ||
| 4 | #define __WINDOWS_CONTROL_IMAGE_LIST_H | ||
| 5 | |||
| 6 | #include <CommCtrl.h> | ||
| 7 | |||
| 8 | #include "../Defs.h" | ||
| 9 | |||
| 10 | namespace NWindows { | ||
| 11 | namespace NControl { | ||
| 12 | |||
| 13 | class CImageList | ||
| 14 | { | ||
| 15 | HIMAGELIST m_Object; | ||
| 16 | public: | ||
| 17 | operator HIMAGELIST() const {return m_Object; } | ||
| 18 | CImageList(): m_Object(NULL) {} | ||
| 19 | bool Attach(HIMAGELIST imageList) | ||
| 20 | { | ||
| 21 | if (imageList == NULL) | ||
| 22 | return false; | ||
| 23 | m_Object = imageList; | ||
| 24 | return true; | ||
| 25 | } | ||
| 26 | |||
| 27 | HIMAGELIST Detach() | ||
| 28 | { | ||
| 29 | HIMAGELIST imageList = m_Object; | ||
| 30 | m_Object = NULL; | ||
| 31 | return imageList; | ||
| 32 | } | ||
| 33 | |||
| 34 | bool Create(int width, int height, UINT flags, int initialNumber, int grow) | ||
| 35 | { | ||
| 36 | HIMAGELIST a = ImageList_Create(width, height, flags, | ||
| 37 | initialNumber, grow); | ||
| 38 | if (a == NULL) | ||
| 39 | return false; | ||
| 40 | return Attach(a); | ||
| 41 | } | ||
| 42 | |||
| 43 | bool Destroy() // DeleteImageList() in MFC | ||
| 44 | { | ||
| 45 | if (m_Object == NULL) | ||
| 46 | return false; | ||
| 47 | return BOOLToBool(ImageList_Destroy(Detach())); | ||
| 48 | } | ||
| 49 | |||
| 50 | ~CImageList() | ||
| 51 | { Destroy(); } | ||
| 52 | |||
| 53 | int GetImageCount() const | ||
| 54 | { return ImageList_GetImageCount(m_Object); } | ||
| 55 | |||
| 56 | bool GetImageInfo(int index, IMAGEINFO* imageInfo) const | ||
| 57 | { return BOOLToBool(ImageList_GetImageInfo(m_Object, index, imageInfo)); } | ||
| 58 | |||
| 59 | int Add(HBITMAP hbmImage, HBITMAP hbmMask = 0) | ||
| 60 | { return ImageList_Add(m_Object, hbmImage, hbmMask); } | ||
| 61 | int AddMasked(HBITMAP hbmImage, COLORREF mask) | ||
| 62 | { return ImageList_AddMasked(m_Object, hbmImage, mask); } | ||
| 63 | int AddIcon(HICON icon) | ||
| 64 | { return ImageList_AddIcon(m_Object, icon); } | ||
| 65 | int Replace(int index, HICON icon) | ||
| 66 | { return ImageList_ReplaceIcon(m_Object, index, icon); } | ||
| 67 | |||
| 68 | // If index is -1, the function removes all images. | ||
| 69 | bool Remove(int index) | ||
| 70 | { return BOOLToBool(ImageList_Remove(m_Object, index)); } | ||
| 71 | bool RemoveAll() | ||
| 72 | { return BOOLToBool(ImageList_RemoveAll(m_Object)); } | ||
| 73 | |||
| 74 | HICON ExtractIcon(int index) | ||
| 75 | { return ImageList_ExtractIcon(NULL, m_Object, index); } | ||
| 76 | HICON GetIcon(int index, UINT flags) | ||
| 77 | { return ImageList_GetIcon(m_Object, index, flags); } | ||
| 78 | |||
| 79 | bool GetIconSize(int &width, int &height) const | ||
| 80 | { return BOOLToBool(ImageList_GetIconSize(m_Object, &width, &height)); } | ||
| 81 | bool SetIconSize(int width, int height) | ||
| 82 | { return BOOLToBool(ImageList_SetIconSize(m_Object, width, height)); } | ||
| 83 | }; | ||
| 84 | |||
| 85 | }} | ||
| 86 | |||
| 87 | #endif | ||
diff --git a/CPP/Windows/Control/ListView.cpp b/CPP/Windows/Control/ListView.cpp new file mode 100644 index 0000000..16cfd39 --- /dev/null +++ b/CPP/Windows/Control/ListView.cpp | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | // Windows/Control/ListView.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "ListView.h" | ||
| 6 | |||
| 7 | #ifndef _UNICODE | ||
| 8 | extern bool g_IsNT; | ||
| 9 | #endif | ||
| 10 | |||
| 11 | namespace NWindows { | ||
| 12 | namespace NControl { | ||
| 13 | |||
| 14 | bool CListView::CreateEx(DWORD exStyle, DWORD style, | ||
| 15 | int x, int y, int width, int height, | ||
| 16 | HWND parentWindow, HMENU idOrHMenu, | ||
| 17 | HINSTANCE instance, LPVOID createParam) | ||
| 18 | { | ||
| 19 | return CWindow::CreateEx(exStyle, WC_LISTVIEW, TEXT(""), style, x, y, width, | ||
| 20 | height, parentWindow, idOrHMenu, instance, createParam); | ||
| 21 | } | ||
| 22 | |||
| 23 | bool CListView::GetItemParam(int index, LPARAM ¶m) const | ||
| 24 | { | ||
| 25 | LVITEM item; | ||
| 26 | item.iItem = index; | ||
| 27 | item.iSubItem = 0; | ||
| 28 | item.mask = LVIF_PARAM; | ||
| 29 | bool aResult = GetItem(&item); | ||
| 30 | param = item.lParam; | ||
| 31 | return aResult; | ||
| 32 | } | ||
| 33 | |||
| 34 | int CListView::InsertColumn(int columnIndex, LPCTSTR text, int width) | ||
| 35 | { | ||
| 36 | LVCOLUMN ci; | ||
| 37 | ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; | ||
| 38 | ci.pszText = (LPTSTR)(void *)text; | ||
| 39 | ci.iSubItem = columnIndex; | ||
| 40 | ci.cx = width; | ||
| 41 | return InsertColumn(columnIndex, &ci); | ||
| 42 | } | ||
| 43 | |||
| 44 | int CListView::InsertItem(int index, LPCTSTR text) | ||
| 45 | { | ||
| 46 | LVITEM item; | ||
| 47 | item.mask = LVIF_TEXT | LVIF_PARAM; | ||
| 48 | item.iItem = index; | ||
| 49 | item.lParam = index; | ||
| 50 | item.pszText = (LPTSTR)(void *)text; | ||
| 51 | item.iSubItem = 0; | ||
| 52 | return InsertItem(&item); | ||
| 53 | } | ||
| 54 | |||
| 55 | int CListView::SetSubItem(int index, int subIndex, LPCTSTR text) | ||
| 56 | { | ||
| 57 | LVITEM item; | ||
| 58 | item.mask = LVIF_TEXT; | ||
| 59 | item.iItem = index; | ||
| 60 | item.pszText = (LPTSTR)(void *)text; | ||
| 61 | item.iSubItem = subIndex; | ||
| 62 | return SetItem(&item); | ||
| 63 | } | ||
| 64 | |||
| 65 | #ifndef _UNICODE | ||
| 66 | |||
| 67 | int CListView::InsertColumn(int columnIndex, LPCWSTR text, int width) | ||
| 68 | { | ||
| 69 | LVCOLUMNW ci; | ||
| 70 | ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; | ||
| 71 | ci.pszText = (LPWSTR)(void *)text; | ||
| 72 | ci.iSubItem = columnIndex; | ||
| 73 | ci.cx = width; | ||
| 74 | return InsertColumn(columnIndex, &ci); | ||
| 75 | } | ||
| 76 | |||
| 77 | int CListView::InsertItem(int index, LPCWSTR text) | ||
| 78 | { | ||
| 79 | LVITEMW item; | ||
| 80 | item.mask = LVIF_TEXT | LVIF_PARAM; | ||
| 81 | item.iItem = index; | ||
| 82 | item.lParam = index; | ||
| 83 | item.pszText = (LPWSTR)(void *)text; | ||
| 84 | item.iSubItem = 0; | ||
| 85 | return InsertItem(&item); | ||
| 86 | } | ||
| 87 | |||
| 88 | int CListView::SetSubItem(int index, int subIndex, LPCWSTR text) | ||
| 89 | { | ||
| 90 | LVITEMW item; | ||
| 91 | item.mask = LVIF_TEXT; | ||
| 92 | item.iItem = index; | ||
| 93 | item.pszText = (LPWSTR)(void *)text; | ||
| 94 | item.iSubItem = subIndex; | ||
| 95 | return SetItem(&item); | ||
| 96 | } | ||
| 97 | |||
| 98 | #endif | ||
| 99 | |||
| 100 | static LRESULT APIENTRY ListViewSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | ||
| 101 | { | ||
| 102 | CWindow window(hwnd); | ||
| 103 | CListView2 *w = (CListView2 *)(window.GetUserDataLongPtr()); | ||
| 104 | if (w == NULL) | ||
| 105 | return 0; | ||
| 106 | return w->OnMessage(message, wParam, lParam); | ||
| 107 | } | ||
| 108 | |||
| 109 | LRESULT CListView2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) | ||
| 110 | { | ||
| 111 | #ifndef _UNICODE | ||
| 112 | if (g_IsNT) | ||
| 113 | return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam); | ||
| 114 | else | ||
| 115 | #endif | ||
| 116 | return CallWindowProc(_origWindowProc, *this, message, wParam, lParam); | ||
| 117 | } | ||
| 118 | |||
| 119 | void CListView2::SetWindowProc() | ||
| 120 | { | ||
| 121 | SetUserDataLongPtr((LONG_PTR)this); | ||
| 122 | #ifndef _UNICODE | ||
| 123 | if (g_IsNT) | ||
| 124 | _origWindowProc = (WNDPROC)SetLongPtrW(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc); | ||
| 125 | else | ||
| 126 | #endif | ||
| 127 | _origWindowProc = (WNDPROC)SetLongPtr(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc); | ||
| 128 | } | ||
| 129 | |||
| 130 | /* | ||
| 131 | LRESULT CListView3::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) | ||
| 132 | { | ||
| 133 | LRESULT res = CListView2::OnMessage(message, wParam, lParam); | ||
| 134 | if (message == WM_GETDLGCODE) | ||
| 135 | { | ||
| 136 | // when user presses RETURN, windows sends default (first) button command to parent dialog. | ||
| 137 | // we disable this: | ||
| 138 | MSG *msg = (MSG *)lParam; | ||
| 139 | WPARAM key = wParam; | ||
| 140 | bool change = false; | ||
| 141 | if (msg) | ||
| 142 | { | ||
| 143 | if (msg->message == WM_KEYDOWN && msg->wParam == VK_RETURN) | ||
| 144 | change = true; | ||
| 145 | } | ||
| 146 | else if (wParam == VK_RETURN) | ||
| 147 | change = true; | ||
| 148 | if (change) | ||
| 149 | res |= DLGC_WANTALLKEYS; | ||
| 150 | } | ||
| 151 | return res; | ||
| 152 | } | ||
| 153 | */ | ||
| 154 | |||
| 155 | }} | ||
diff --git a/CPP/Windows/Control/ListView.h b/CPP/Windows/Control/ListView.h new file mode 100644 index 0000000..a13b104 --- /dev/null +++ b/CPP/Windows/Control/ListView.h | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | // Windows/Control/ListView.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_LISTVIEW_H | ||
| 4 | #define __WINDOWS_CONTROL_LISTVIEW_H | ||
| 5 | |||
| 6 | #include "../../Common/MyWindows.h" | ||
| 7 | |||
| 8 | #include <CommCtrl.h> | ||
| 9 | |||
| 10 | #include "../Window.h" | ||
| 11 | |||
| 12 | namespace NWindows { | ||
| 13 | namespace NControl { | ||
| 14 | |||
| 15 | class CListView: public NWindows::CWindow | ||
| 16 | { | ||
| 17 | public: | ||
| 18 | bool CreateEx(DWORD exStyle, DWORD style, | ||
| 19 | int x, int y, int width, int height, | ||
| 20 | HWND parentWindow, HMENU idOrHMenu, | ||
| 21 | HINSTANCE instance, LPVOID createParam); | ||
| 22 | |||
| 23 | void SetUnicodeFormat() | ||
| 24 | { | ||
| 25 | #ifndef UNDER_CE | ||
| 26 | ListView_SetUnicodeFormat(_window, TRUE); | ||
| 27 | #endif | ||
| 28 | } | ||
| 29 | |||
| 30 | bool DeleteAllItems() { return BOOLToBool(ListView_DeleteAllItems(_window)); } | ||
| 31 | bool DeleteColumn(int columnIndex) { return BOOLToBool(ListView_DeleteColumn(_window, columnIndex)); } | ||
| 32 | |||
| 33 | int InsertColumn(int columnIndex, const LVCOLUMN *columnInfo) { return ListView_InsertColumn(_window, columnIndex, columnInfo); } | ||
| 34 | int InsertColumn(int columnIndex, LPCTSTR text, int width); | ||
| 35 | bool SetColumnOrderArray(int count, const int *columns) | ||
| 36 | { return BOOLToBool(ListView_SetColumnOrderArray(_window, count, (int *)(void *)columns)); } | ||
| 37 | |||
| 38 | /* | ||
| 39 | int GetNumColumns() | ||
| 40 | { | ||
| 41 | HWND header = ListView_GetHeader(_window); | ||
| 42 | if (!header) | ||
| 43 | return -1; | ||
| 44 | return Header_GetItemCount(header); | ||
| 45 | } | ||
| 46 | */ | ||
| 47 | |||
| 48 | int InsertItem(const LVITEM* item) { return ListView_InsertItem(_window, item); } | ||
| 49 | int InsertItem(int index, LPCTSTR text); | ||
| 50 | bool SetItem(const LVITEM* item) { return BOOLToBool(ListView_SetItem(_window, item)); } | ||
| 51 | int SetSubItem(int index, int subIndex, LPCTSTR text); | ||
| 52 | |||
| 53 | #ifndef _UNICODE | ||
| 54 | |||
| 55 | int InsertColumn(int columnIndex, const LVCOLUMNW *columnInfo) { return (int)SendMsg(LVM_INSERTCOLUMNW, (WPARAM)columnIndex, (LPARAM)columnInfo); } | ||
| 56 | int InsertColumn(int columnIndex, LPCWSTR text, int width); | ||
| 57 | int InsertItem(const LV_ITEMW* item) { return (int)SendMsg(LVM_INSERTITEMW, 0, (LPARAM)item); } | ||
| 58 | int InsertItem(int index, LPCWSTR text); | ||
| 59 | bool SetItem(const LV_ITEMW* item) { return BOOLToBool((BOOL)SendMsg(LVM_SETITEMW, 0, (LPARAM)item)); } | ||
| 60 | int SetSubItem(int index, int subIndex, LPCWSTR text); | ||
| 61 | |||
| 62 | #endif | ||
| 63 | |||
| 64 | bool DeleteItem(int itemIndex) { return BOOLToBool(ListView_DeleteItem(_window, itemIndex)); } | ||
| 65 | |||
| 66 | UINT GetSelectedCount() const { return ListView_GetSelectedCount(_window); } | ||
| 67 | int GetItemCount() const { return ListView_GetItemCount(_window); } | ||
| 68 | |||
| 69 | INT GetSelectionMark() const { return ListView_GetSelectionMark(_window); } | ||
| 70 | |||
| 71 | void SetItemCount(int numItems) { ListView_SetItemCount(_window, numItems); } | ||
| 72 | void SetItemCountEx(int numItems, DWORD flags) { ListView_SetItemCountEx(_window, numItems, flags); } | ||
| 73 | |||
| 74 | int GetNextItem(int startIndex, UINT flags) const { return ListView_GetNextItem(_window, startIndex, flags); } | ||
| 75 | int GetNextSelectedItem(int startIndex) const { return GetNextItem(startIndex, LVNI_SELECTED); } | ||
| 76 | int GetFocusedItem() const { return GetNextItem(-1, LVNI_FOCUSED); } | ||
| 77 | |||
| 78 | bool GetItem(LVITEM* item) const { return BOOLToBool(ListView_GetItem(_window, item)); } | ||
| 79 | bool GetItemParam(int itemIndex, LPARAM ¶m) const; | ||
| 80 | void GetItemText(int itemIndex, int subItemIndex, LPTSTR text, int textSizeMax) const | ||
| 81 | { ListView_GetItemText(_window, itemIndex, subItemIndex, text, textSizeMax); } | ||
| 82 | bool SortItems(PFNLVCOMPARE compareFunction, LPARAM dataParam) | ||
| 83 | { return BOOLToBool(ListView_SortItems(_window, compareFunction, dataParam)); } | ||
| 84 | |||
| 85 | void SetItemState(int index, UINT state, UINT mask) { ListView_SetItemState(_window, index, state, mask); } | ||
| 86 | void SetItemState_Selected(int index, bool select) { SetItemState(index, select ? LVIS_SELECTED : 0, LVIS_SELECTED); } | ||
| 87 | void SetItemState_Selected(int index) { SetItemState(index, LVIS_SELECTED, LVIS_SELECTED); } | ||
| 88 | void SelectAll() { SetItemState_Selected(-1); } | ||
| 89 | void SetItemState_FocusedSelected(int index) { SetItemState(index, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); } | ||
| 90 | UINT GetItemState(int index, UINT mask) const { return ListView_GetItemState(_window, index, mask); } | ||
| 91 | bool IsItemSelected(int index) const { return GetItemState(index, LVIS_SELECTED) == LVIS_SELECTED; } | ||
| 92 | |||
| 93 | bool GetColumn(int columnIndex, LVCOLUMN* columnInfo) const | ||
| 94 | { return BOOLToBool(ListView_GetColumn(_window, columnIndex, columnInfo)); } | ||
| 95 | |||
| 96 | HIMAGELIST SetImageList(HIMAGELIST imageList, int imageListType) | ||
| 97 | { return ListView_SetImageList(_window, imageList, imageListType); } | ||
| 98 | |||
| 99 | // version 4.70: NT5 | (NT4 + ie3) | w98 | (w95 + ie3) | ||
| 100 | DWORD GetExtendedListViewStyle() { return ListView_GetExtendedListViewStyle(_window); } | ||
| 101 | void SetExtendedListViewStyle(DWORD exStyle) { ListView_SetExtendedListViewStyle(_window, exStyle); } | ||
| 102 | void SetExtendedListViewStyle(DWORD exMask, DWORD exStyle) { ListView_SetExtendedListViewStyleEx(_window, exMask, exStyle); } | ||
| 103 | |||
| 104 | void SetCheckState(UINT index, bool checkState) { ListView_SetCheckState(_window, index, BoolToBOOL(checkState)); } | ||
| 105 | bool GetCheckState(UINT index) { return BOOLToBool(ListView_GetCheckState(_window, index)); } | ||
| 106 | |||
| 107 | bool EnsureVisible(int index, bool partialOK) { return BOOLToBool(ListView_EnsureVisible(_window, index, BoolToBOOL(partialOK))); } | ||
| 108 | |||
| 109 | bool GetItemRect(int index, RECT *rect, int code) { return BOOLToBool(ListView_GetItemRect(_window, index, rect, code)); } | ||
| 110 | |||
| 111 | HWND GetEditControl() { return ListView_GetEditControl(_window) ; } | ||
| 112 | HWND EditLabel(int itemIndex) { return ListView_EditLabel(_window, itemIndex) ; } | ||
| 113 | |||
| 114 | bool RedrawItems(int firstIndex, int lastIndex) { return BOOLToBool(ListView_RedrawItems(_window, firstIndex, lastIndex)); } | ||
| 115 | bool RedrawAllItems() | ||
| 116 | { | ||
| 117 | if (GetItemCount() > 0) | ||
| 118 | return RedrawItems(0, GetItemCount() - 1); | ||
| 119 | return true; | ||
| 120 | } | ||
| 121 | bool RedrawItem(int index) { return RedrawItems(index, index); } | ||
| 122 | |||
| 123 | int HitTest(LPLVHITTESTINFO info) { return ListView_HitTest(_window, info); } | ||
| 124 | COLORREF GetBkColor() { return ListView_GetBkColor(_window); } | ||
| 125 | bool SetColumnWidth(int iCol, int cx) { return BOOLToBool(ListView_SetColumnWidth(_window, iCol, cx)); } | ||
| 126 | bool SetColumnWidthAuto(int iCol) { return SetColumnWidth(iCol, LVSCW_AUTOSIZE); } | ||
| 127 | }; | ||
| 128 | |||
| 129 | class CListView2: public CListView | ||
| 130 | { | ||
| 131 | WNDPROC _origWindowProc; | ||
| 132 | public: | ||
| 133 | void SetWindowProc(); | ||
| 134 | virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); | ||
| 135 | }; | ||
| 136 | |||
| 137 | /* | ||
| 138 | class CListView3: public CListView2 | ||
| 139 | { | ||
| 140 | public: | ||
| 141 | virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); | ||
| 142 | }; | ||
| 143 | */ | ||
| 144 | |||
| 145 | }} | ||
| 146 | |||
| 147 | #endif | ||
diff --git a/CPP/Windows/Control/ProgressBar.h b/CPP/Windows/Control/ProgressBar.h new file mode 100644 index 0000000..0374306 --- /dev/null +++ b/CPP/Windows/Control/ProgressBar.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // Windows/Control/ProgressBar.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_PROGRESSBAR_H | ||
| 4 | #define __WINDOWS_CONTROL_PROGRESSBAR_H | ||
| 5 | |||
| 6 | #include "../../Common/MyWindows.h" | ||
| 7 | |||
| 8 | #include <CommCtrl.h> | ||
| 9 | |||
| 10 | #include "../Window.h" | ||
| 11 | |||
| 12 | namespace NWindows { | ||
| 13 | namespace NControl { | ||
| 14 | |||
| 15 | class CProgressBar: public CWindow | ||
| 16 | { | ||
| 17 | public: | ||
| 18 | LRESULT SetPos(int pos) { return SendMsg(PBM_SETPOS, pos, 0); } | ||
| 19 | LRESULT DeltaPos(int increment) { return SendMsg(PBM_DELTAPOS, increment, 0); } | ||
| 20 | UINT GetPos() { return (UINT)SendMsg(PBM_GETPOS, 0, 0); } | ||
| 21 | LRESULT SetRange(unsigned short minValue, unsigned short maxValue) { return SendMsg(PBM_SETRANGE, 0, MAKELPARAM(minValue, maxValue)); } | ||
| 22 | DWORD SetRange32(int minValue, int maxValue) { return (DWORD)SendMsg(PBM_SETRANGE32, minValue, maxValue); } | ||
| 23 | int SetStep(int step) { return (int)SendMsg(PBM_SETSTEP, step, 0); } | ||
| 24 | LRESULT StepIt() { return SendMsg(PBM_STEPIT, 0, 0); } | ||
| 25 | INT GetRange(bool minValue, PPBRANGE range) { return (INT)SendMsg(PBM_GETRANGE, BoolToBOOL(minValue), (LPARAM)range); } | ||
| 26 | |||
| 27 | #ifndef UNDER_CE | ||
| 28 | COLORREF SetBarColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBARCOLOR, 0, color); } | ||
| 29 | COLORREF SetBackgroundColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBKCOLOR, 0, color); } | ||
| 30 | #endif | ||
| 31 | }; | ||
| 32 | |||
| 33 | }} | ||
| 34 | |||
| 35 | #endif | ||
diff --git a/CPP/Windows/Control/PropertyPage.cpp b/CPP/Windows/Control/PropertyPage.cpp new file mode 100644 index 0000000..ce8696d --- /dev/null +++ b/CPP/Windows/Control/PropertyPage.cpp | |||
| @@ -0,0 +1,143 @@ | |||
| 1 | // Windows/Control/PropertyPage.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef _UNICODE | ||
| 6 | #include "../../Common/StringConvert.h" | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #include "PropertyPage.h" | ||
| 10 | |||
| 11 | extern HINSTANCE g_hInstance; | ||
| 12 | #ifndef _UNICODE | ||
| 13 | extern bool g_IsNT; | ||
| 14 | #endif | ||
| 15 | |||
| 16 | namespace NWindows { | ||
| 17 | namespace NControl { | ||
| 18 | |||
| 19 | static INT_PTR APIENTRY MyProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam) | ||
| 20 | { | ||
| 21 | CWindow tempDialog(dialogHWND); | ||
| 22 | if (message == WM_INITDIALOG) | ||
| 23 | tempDialog.SetUserDataLongPtr(((PROPSHEETPAGE *)lParam)->lParam); | ||
| 24 | CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr()); | ||
| 25 | if (dialog == NULL) | ||
| 26 | return FALSE; | ||
| 27 | if (message == WM_INITDIALOG) | ||
| 28 | dialog->Attach(dialogHWND); | ||
| 29 | try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); } | ||
| 30 | catch(...) { return TRUE; } | ||
| 31 | } | ||
| 32 | |||
| 33 | bool CPropertyPage::OnNotify(UINT /* controlID */, LPNMHDR lParam) | ||
| 34 | { | ||
| 35 | switch (lParam->code) | ||
| 36 | { | ||
| 37 | case PSN_APPLY: SetMsgResult(OnApply(LPPSHNOTIFY(lParam))); break; | ||
| 38 | case PSN_KILLACTIVE: SetMsgResult(BoolToBOOL(OnKillActive(LPPSHNOTIFY(lParam)))); break; | ||
| 39 | case PSN_SETACTIVE: SetMsgResult(OnSetActive(LPPSHNOTIFY(lParam))); break; | ||
| 40 | case PSN_RESET: OnReset(LPPSHNOTIFY(lParam)); break; | ||
| 41 | case PSN_HELP: OnNotifyHelp(LPPSHNOTIFY(lParam)); break; | ||
| 42 | default: return false; | ||
| 43 | } | ||
| 44 | return true; | ||
| 45 | } | ||
| 46 | |||
| 47 | INT_PTR MyPropertySheet(const CObjectVector<CPageInfo> &pagesInfo, HWND hwndParent, const UString &title) | ||
| 48 | { | ||
| 49 | #ifndef _UNICODE | ||
| 50 | AStringVector titles; | ||
| 51 | #endif | ||
| 52 | #ifndef _UNICODE | ||
| 53 | CRecordVector<PROPSHEETPAGEA> pagesA; | ||
| 54 | #endif | ||
| 55 | CRecordVector<PROPSHEETPAGEW> pagesW; | ||
| 56 | |||
| 57 | unsigned i; | ||
| 58 | #ifndef _UNICODE | ||
| 59 | for (i = 0; i < pagesInfo.Size(); i++) | ||
| 60 | titles.Add(GetSystemString(pagesInfo[i].Title)); | ||
| 61 | #endif | ||
| 62 | |||
| 63 | for (i = 0; i < pagesInfo.Size(); i++) | ||
| 64 | { | ||
| 65 | const CPageInfo &pageInfo = pagesInfo[i]; | ||
| 66 | #ifndef _UNICODE | ||
| 67 | { | ||
| 68 | PROPSHEETPAGE page; | ||
| 69 | page.dwSize = sizeof(page); | ||
| 70 | page.dwFlags = PSP_HASHELP; | ||
| 71 | page.hInstance = g_hInstance; | ||
| 72 | page.pszTemplate = MAKEINTRESOURCE(pageInfo.ID); | ||
| 73 | page.pszIcon = NULL; | ||
| 74 | page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure; | ||
| 75 | |||
| 76 | if (titles[i].IsEmpty()) | ||
| 77 | page.pszTitle = NULL; | ||
| 78 | else | ||
| 79 | { | ||
| 80 | page.dwFlags |= PSP_USETITLE; | ||
| 81 | page.pszTitle = titles[i]; | ||
| 82 | } | ||
| 83 | page.lParam = (LPARAM)pageInfo.Page; | ||
| 84 | page.pfnCallback = NULL; | ||
| 85 | pagesA.Add(page); | ||
| 86 | } | ||
| 87 | #endif | ||
| 88 | { | ||
| 89 | PROPSHEETPAGEW page; | ||
| 90 | page.dwSize = sizeof(page); | ||
| 91 | page.dwFlags = PSP_HASHELP; | ||
| 92 | page.hInstance = g_hInstance; | ||
| 93 | page.pszTemplate = MAKEINTRESOURCEW(pageInfo.ID); | ||
| 94 | page.pszIcon = NULL; | ||
| 95 | page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure; | ||
| 96 | |||
| 97 | if (pageInfo.Title.IsEmpty()) | ||
| 98 | page.pszTitle = NULL; | ||
| 99 | else | ||
| 100 | { | ||
| 101 | page.dwFlags |= PSP_USETITLE; | ||
| 102 | page.pszTitle = pageInfo.Title; | ||
| 103 | } | ||
| 104 | page.lParam = (LPARAM)pageInfo.Page; | ||
| 105 | page.pfnCallback = NULL; | ||
| 106 | pagesW.Add(page); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | #ifndef _UNICODE | ||
| 111 | if (!g_IsNT) | ||
| 112 | { | ||
| 113 | PROPSHEETHEADER sheet; | ||
| 114 | sheet.dwSize = sizeof(sheet); | ||
| 115 | sheet.dwFlags = PSH_PROPSHEETPAGE; | ||
| 116 | sheet.hwndParent = hwndParent; | ||
| 117 | sheet.hInstance = g_hInstance; | ||
| 118 | AString titleA (GetSystemString(title)); | ||
| 119 | sheet.pszCaption = titleA; | ||
| 120 | sheet.nPages = pagesInfo.Size(); | ||
| 121 | sheet.nStartPage = 0; | ||
| 122 | sheet.ppsp = &pagesA.Front(); | ||
| 123 | sheet.pfnCallback = NULL; | ||
| 124 | return ::PropertySheetA(&sheet); | ||
| 125 | } | ||
| 126 | else | ||
| 127 | #endif | ||
| 128 | { | ||
| 129 | PROPSHEETHEADERW sheet; | ||
| 130 | sheet.dwSize = sizeof(sheet); | ||
| 131 | sheet.dwFlags = PSH_PROPSHEETPAGE; | ||
| 132 | sheet.hwndParent = hwndParent; | ||
| 133 | sheet.hInstance = g_hInstance; | ||
| 134 | sheet.pszCaption = title; | ||
| 135 | sheet.nPages = pagesInfo.Size(); | ||
| 136 | sheet.nStartPage = 0; | ||
| 137 | sheet.ppsp = &pagesW.Front(); | ||
| 138 | sheet.pfnCallback = NULL; | ||
| 139 | return ::PropertySheetW(&sheet); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | }} | ||
diff --git a/CPP/Windows/Control/PropertyPage.h b/CPP/Windows/Control/PropertyPage.h new file mode 100644 index 0000000..b68fd8f --- /dev/null +++ b/CPP/Windows/Control/PropertyPage.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | // Windows/Control/PropertyPage.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_PROPERTYPAGE_H | ||
| 4 | #define __WINDOWS_CONTROL_PROPERTYPAGE_H | ||
| 5 | |||
| 6 | #include "../../Common/MyWindows.h" | ||
| 7 | |||
| 8 | #include <PrSht.h> | ||
| 9 | |||
| 10 | #include "Dialog.h" | ||
| 11 | |||
| 12 | namespace NWindows { | ||
| 13 | namespace NControl { | ||
| 14 | |||
| 15 | INT_PTR APIENTRY ProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam); | ||
| 16 | |||
| 17 | class CPropertyPage: public CDialog | ||
| 18 | { | ||
| 19 | public: | ||
| 20 | CPropertyPage(HWND window = NULL): CDialog(window){}; | ||
| 21 | |||
| 22 | void Changed() { PropSheet_Changed(GetParent(), (HWND)*this); } | ||
| 23 | void UnChanged() { PropSheet_UnChanged(GetParent(), (HWND)*this); } | ||
| 24 | |||
| 25 | virtual bool OnNotify(UINT controlID, LPNMHDR lParam); | ||
| 26 | |||
| 27 | virtual bool OnKillActive() { return false; } // false = OK | ||
| 28 | virtual bool OnKillActive(const PSHNOTIFY *) { return OnKillActive(); } | ||
| 29 | virtual LONG OnSetActive() { return false; } // false = OK | ||
| 30 | virtual LONG OnSetActive(const PSHNOTIFY *) { return OnSetActive(); } | ||
| 31 | virtual LONG OnApply() { return PSNRET_NOERROR; } | ||
| 32 | virtual LONG OnApply(const PSHNOTIFY *) { return OnApply(); } | ||
| 33 | virtual void OnNotifyHelp() {} | ||
| 34 | virtual void OnNotifyHelp(const PSHNOTIFY *) { OnNotifyHelp(); } | ||
| 35 | virtual void OnReset() {} | ||
| 36 | virtual void OnReset(const PSHNOTIFY *) { OnReset(); } | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct CPageInfo | ||
| 40 | { | ||
| 41 | CPropertyPage *Page; | ||
| 42 | UString Title; | ||
| 43 | UINT ID; | ||
| 44 | }; | ||
| 45 | |||
| 46 | INT_PTR MyPropertySheet(const CObjectVector<CPageInfo> &pagesInfo, HWND hwndParent, const UString &title); | ||
| 47 | |||
| 48 | }} | ||
| 49 | |||
| 50 | #endif | ||
diff --git a/CPP/Windows/Control/ReBar.h b/CPP/Windows/Control/ReBar.h new file mode 100644 index 0000000..c2d58db --- /dev/null +++ b/CPP/Windows/Control/ReBar.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // Windows/Control/ReBar.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_REBAR_H | ||
| 4 | #define __WINDOWS_CONTROL_REBAR_H | ||
| 5 | |||
| 6 | #include "../Window.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NControl { | ||
| 10 | |||
| 11 | class CReBar: public NWindows::CWindow | ||
| 12 | { | ||
| 13 | public: | ||
| 14 | bool SetBarInfo(LPREBARINFO barInfo) | ||
| 15 | { return LRESULTToBool(SendMsg(RB_SETBARINFO, 0, (LPARAM)barInfo)); } | ||
| 16 | bool InsertBand(int index, LPREBARBANDINFO bandInfo) | ||
| 17 | { return LRESULTToBool(SendMsg(RB_INSERTBAND, index, (LPARAM)bandInfo)); } | ||
| 18 | bool SetBandInfo(unsigned index, LPREBARBANDINFO bandInfo) | ||
| 19 | { return LRESULTToBool(SendMsg(RB_SETBANDINFO, index, (LPARAM)bandInfo)); } | ||
| 20 | void MaximizeBand(unsigned index, bool ideal) | ||
| 21 | { SendMsg(RB_MAXIMIZEBAND, index, BoolToBOOL(ideal)); } | ||
| 22 | bool SizeToRect(LPRECT rect) | ||
| 23 | { return LRESULTToBool(SendMsg(RB_SIZETORECT, 0, (LPARAM)rect)); } | ||
| 24 | UINT GetHeight() | ||
| 25 | { return (UINT)SendMsg(RB_GETBARHEIGHT); } | ||
| 26 | UINT GetBandCount() | ||
| 27 | { return (UINT)SendMsg(RB_GETBANDCOUNT); } | ||
| 28 | bool DeleteBand(UINT index) | ||
| 29 | { return LRESULTToBool(SendMsg(RB_DELETEBAND, index)); } | ||
| 30 | }; | ||
| 31 | |||
| 32 | }} | ||
| 33 | |||
| 34 | #endif | ||
diff --git a/CPP/Windows/Control/Static.h b/CPP/Windows/Control/Static.h new file mode 100644 index 0000000..5523b2e --- /dev/null +++ b/CPP/Windows/Control/Static.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Windows/Control/Static.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_STATIC_H | ||
| 4 | #define __WINDOWS_CONTROL_STATIC_H | ||
| 5 | |||
| 6 | #include "../Window.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NControl { | ||
| 10 | |||
| 11 | class CStatic: public CWindow | ||
| 12 | { | ||
| 13 | public: | ||
| 14 | HANDLE SetImage(WPARAM imageType, HANDLE handle) { return (HANDLE)SendMsg(STM_SETIMAGE, imageType, (LPARAM)handle); } | ||
| 15 | HANDLE GetImage(WPARAM imageType) { return (HANDLE)SendMsg(STM_GETIMAGE, imageType, 0); } | ||
| 16 | |||
| 17 | #ifdef UNDER_CE | ||
| 18 | HICON SetIcon(HICON icon) { return (HICON)SetImage(IMAGE_ICON, icon); } | ||
| 19 | HICON GetIcon() { return (HICON)GetImage(IMAGE_ICON); } | ||
| 20 | #else | ||
| 21 | HICON SetIcon(HICON icon) { return (HICON)SendMsg(STM_SETICON, (WPARAM)icon, 0); } | ||
| 22 | HICON GetIcon() { return (HICON)SendMsg(STM_GETICON, 0, 0); } | ||
| 23 | #endif | ||
| 24 | }; | ||
| 25 | |||
| 26 | }} | ||
| 27 | |||
| 28 | #endif | ||
diff --git a/CPP/Windows/Control/StatusBar.h b/CPP/Windows/Control/StatusBar.h new file mode 100644 index 0000000..988b847 --- /dev/null +++ b/CPP/Windows/Control/StatusBar.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | // Windows/Control/StatusBar.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_STATUSBAR_H | ||
| 4 | #define __WINDOWS_CONTROL_STATUSBAR_H | ||
| 5 | |||
| 6 | #include "../Window.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NControl { | ||
| 10 | |||
| 11 | class CStatusBar: public NWindows::CWindow | ||
| 12 | { | ||
| 13 | public: | ||
| 14 | bool Create(LONG style, LPCTSTR text, HWND hwndParent, UINT id) | ||
| 15 | { return (_window = ::CreateStatusWindow(style, text, hwndParent, id)) != 0; } | ||
| 16 | bool SetText(LPCTSTR text) | ||
| 17 | { return CWindow::SetText(text); } | ||
| 18 | bool SetText(unsigned index, LPCTSTR text, UINT type) | ||
| 19 | { return LRESULTToBool(SendMsg(SB_SETTEXT, index | type, (LPARAM)text)); } | ||
| 20 | bool SetText(unsigned index, LPCTSTR text) | ||
| 21 | { return SetText(index, text, 0); } | ||
| 22 | |||
| 23 | #ifndef _UNICODE | ||
| 24 | bool Create(LONG style, LPCWSTR text, HWND hwndParent, UINT id) | ||
| 25 | { return (_window = ::CreateStatusWindowW(style, text, hwndParent, id)) != 0; } | ||
| 26 | bool SetText(LPCWSTR text) | ||
| 27 | { return CWindow::SetText(text); } | ||
| 28 | bool SetText(unsigned index, LPCWSTR text, UINT type) | ||
| 29 | { return LRESULTToBool(SendMsg(SB_SETTEXTW, index | type, (LPARAM)text)); } | ||
| 30 | bool SetText(unsigned index, LPCWSTR text) | ||
| 31 | { return SetText(index, text, 0); } | ||
| 32 | #endif | ||
| 33 | |||
| 34 | bool SetParts(unsigned numParts, const int *edgePostions) | ||
| 35 | { return LRESULTToBool(SendMsg(SB_SETPARTS, numParts, (LPARAM)edgePostions)); } | ||
| 36 | void Simple(bool simple) | ||
| 37 | { SendMsg(SB_SIMPLE, BoolToBOOL(simple), 0); } | ||
| 38 | }; | ||
| 39 | |||
| 40 | }} | ||
| 41 | |||
| 42 | #endif | ||
diff --git a/CPP/Windows/Control/StdAfx.h b/CPP/Windows/Control/StdAfx.h new file mode 100644 index 0000000..1cbd7fe --- /dev/null +++ b/CPP/Windows/Control/StdAfx.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | // StdAfx.h | ||
| 2 | |||
| 3 | #ifndef __STDAFX_H | ||
| 4 | #define __STDAFX_H | ||
| 5 | |||
| 6 | #include "../../Common/Common.h" | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/CPP/Windows/Control/ToolBar.h b/CPP/Windows/Control/ToolBar.h new file mode 100644 index 0000000..7bc93a2 --- /dev/null +++ b/CPP/Windows/Control/ToolBar.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // Windows/Control/ToolBar.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_TOOLBAR_H | ||
| 4 | #define __WINDOWS_CONTROL_TOOLBAR_H | ||
| 5 | |||
| 6 | #include "../Window.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NControl { | ||
| 10 | |||
| 11 | class CToolBar: public NWindows::CWindow | ||
| 12 | { | ||
| 13 | public: | ||
| 14 | void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); } | ||
| 15 | DWORD GetButtonSize() { return (DWORD)SendMsg(TB_GETBUTTONSIZE, 0, 0); } | ||
| 16 | |||
| 17 | bool GetMaxSize(LPSIZE size) | ||
| 18 | #ifdef UNDER_CE | ||
| 19 | { | ||
| 20 | // maybe it must be fixed for more than 1 buttons | ||
| 21 | DWORD val = GetButtonSize(); | ||
| 22 | size->cx = LOWORD(val); | ||
| 23 | size->cy = HIWORD(val); | ||
| 24 | return true; | ||
| 25 | } | ||
| 26 | #else | ||
| 27 | { | ||
| 28 | return LRESULTToBool(SendMsg(TB_GETMAXSIZE, 0, (LPARAM)size)); | ||
| 29 | } | ||
| 30 | #endif | ||
| 31 | |||
| 32 | bool EnableButton(UINT buttonID, bool enable) { return LRESULTToBool(SendMsg(TB_ENABLEBUTTON, buttonID, MAKELONG(BoolToBOOL(enable), 0))); } | ||
| 33 | void ButtonStructSize() { SendMsg(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON)); } | ||
| 34 | HIMAGELIST SetImageList(UINT listIndex, HIMAGELIST imageList) { return HIMAGELIST(SendMsg(TB_SETIMAGELIST, listIndex, (LPARAM)imageList)); } | ||
| 35 | bool AddButton(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONS, numButtons, (LPARAM)buttons)); } | ||
| 36 | #ifndef _UNICODE | ||
| 37 | bool AddButtonW(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONSW, numButtons, (LPARAM)buttons)); } | ||
| 38 | #endif | ||
| 39 | }; | ||
| 40 | |||
| 41 | }} | ||
| 42 | |||
| 43 | #endif | ||
diff --git a/CPP/Windows/Control/Trackbar.h b/CPP/Windows/Control/Trackbar.h new file mode 100644 index 0000000..313e0c8 --- /dev/null +++ b/CPP/Windows/Control/Trackbar.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Windows/Control/Trackbar.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_TRACKBAR_H | ||
| 4 | #define __WINDOWS_CONTROL_TRACKBAR_H | ||
| 5 | |||
| 6 | #include "../Window.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NControl { | ||
| 10 | |||
| 11 | class CTrackbar: public CWindow | ||
| 12 | { | ||
| 13 | public: | ||
| 14 | void SetRange(int minimum, int maximum, bool redraw = true) | ||
| 15 | { SendMsg(TBM_SETRANGE, BoolToBOOL(redraw), MAKELONG(minimum, maximum)); } | ||
| 16 | void SetPos(int pos, bool redraw = true) | ||
| 17 | { SendMsg(TBM_SETPOS, BoolToBOOL(redraw), pos); } | ||
| 18 | void SetTicFreq(int freq) | ||
| 19 | { SendMsg(TBM_SETTICFREQ, freq); } | ||
| 20 | |||
| 21 | int GetPos() | ||
| 22 | { return (int)SendMsg(TBM_GETPOS); } | ||
| 23 | }; | ||
| 24 | |||
| 25 | }} | ||
| 26 | |||
| 27 | #endif | ||
diff --git a/CPP/Windows/Control/Window2.cpp b/CPP/Windows/Control/Window2.cpp new file mode 100644 index 0000000..994d96e --- /dev/null +++ b/CPP/Windows/Control/Window2.cpp | |||
| @@ -0,0 +1,200 @@ | |||
| 1 | // Windows/Control/Window2.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef _UNICODE | ||
| 6 | #include "../../Common/StringConvert.h" | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #include "Window2.h" | ||
| 10 | |||
| 11 | #ifndef _UNICODE | ||
| 12 | extern bool g_IsNT; | ||
| 13 | #endif | ||
| 14 | |||
| 15 | namespace NWindows { | ||
| 16 | |||
| 17 | #ifndef _UNICODE | ||
| 18 | ATOM MyRegisterClass(CONST WNDCLASSW *wndClass); | ||
| 19 | #endif | ||
| 20 | |||
| 21 | namespace NControl { | ||
| 22 | |||
| 23 | #ifdef UNDER_CE | ||
| 24 | #define MY_START_WM_CREATE WM_CREATE | ||
| 25 | #else | ||
| 26 | #define MY_START_WM_CREATE WM_NCCREATE | ||
| 27 | #endif | ||
| 28 | |||
| 29 | static LRESULT CALLBACK WindowProcedure(HWND aHWND, UINT message, WPARAM wParam, LPARAM lParam) | ||
| 30 | { | ||
| 31 | CWindow tempWindow(aHWND); | ||
| 32 | if (message == MY_START_WM_CREATE) | ||
| 33 | tempWindow.SetUserDataLongPtr((LONG_PTR)(((LPCREATESTRUCT)lParam)->lpCreateParams)); | ||
| 34 | CWindow2 *window = (CWindow2 *)(tempWindow.GetUserDataLongPtr()); | ||
| 35 | if (window != NULL && message == MY_START_WM_CREATE) | ||
| 36 | window->Attach(aHWND); | ||
| 37 | if (window == 0) | ||
| 38 | { | ||
| 39 | #ifndef _UNICODE | ||
| 40 | if (g_IsNT) | ||
| 41 | return DefWindowProcW(aHWND, message, wParam, lParam); | ||
| 42 | else | ||
| 43 | #endif | ||
| 44 | return DefWindowProc(aHWND, message, wParam, lParam); | ||
| 45 | } | ||
| 46 | return window->OnMessage(message, wParam, lParam); | ||
| 47 | } | ||
| 48 | |||
| 49 | bool CWindow2::CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName, | ||
| 50 | DWORD style, int x, int y, int width, int height, | ||
| 51 | HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance) | ||
| 52 | { | ||
| 53 | WNDCLASS wc; | ||
| 54 | if (!::GetClassInfo(instance, className, &wc)) | ||
| 55 | { | ||
| 56 | // wc.style = CS_HREDRAW | CS_VREDRAW; | ||
| 57 | wc.style = 0; | ||
| 58 | wc.lpfnWndProc = WindowProcedure; | ||
| 59 | wc.cbClsExtra = 0; | ||
| 60 | wc.cbWndExtra = 0; | ||
| 61 | wc.hInstance = instance; | ||
| 62 | wc.hIcon = NULL; | ||
| 63 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); | ||
| 64 | wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); | ||
| 65 | wc.lpszMenuName = NULL; | ||
| 66 | wc.lpszClassName = className; | ||
| 67 | if (::RegisterClass(&wc) == 0) | ||
| 68 | return false; | ||
| 69 | } | ||
| 70 | return CWindow::CreateEx(exStyle, className, windowName, style, | ||
| 71 | x, y, width, height, parentWindow, idOrHMenu, instance, this); | ||
| 72 | } | ||
| 73 | |||
| 74 | #ifndef _UNICODE | ||
| 75 | |||
| 76 | bool CWindow2::CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName, | ||
| 77 | DWORD style, int x, int y, int width, int height, | ||
| 78 | HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance) | ||
| 79 | { | ||
| 80 | bool needRegister; | ||
| 81 | if (g_IsNT) | ||
| 82 | { | ||
| 83 | WNDCLASSW wc; | ||
| 84 | needRegister = ::GetClassInfoW(instance, className, &wc) == 0; | ||
| 85 | } | ||
| 86 | else | ||
| 87 | { | ||
| 88 | WNDCLASSA windowClassA; | ||
| 89 | AString classNameA; | ||
| 90 | LPCSTR classNameP; | ||
| 91 | if (IS_INTRESOURCE(className)) | ||
| 92 | classNameP = (LPCSTR)className; | ||
| 93 | else | ||
| 94 | { | ||
| 95 | classNameA = GetSystemString(className); | ||
| 96 | classNameP = classNameA; | ||
| 97 | } | ||
| 98 | needRegister = ::GetClassInfoA(instance, classNameP, &windowClassA) == 0; | ||
| 99 | } | ||
| 100 | if (needRegister) | ||
| 101 | { | ||
| 102 | WNDCLASSW wc; | ||
| 103 | // wc.style = CS_HREDRAW | CS_VREDRAW; | ||
| 104 | wc.style = 0; | ||
| 105 | wc.lpfnWndProc = WindowProcedure; | ||
| 106 | wc.cbClsExtra = 0; | ||
| 107 | wc.cbWndExtra = 0; | ||
| 108 | wc.hInstance = instance; | ||
| 109 | wc.hIcon = NULL; | ||
| 110 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); | ||
| 111 | wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); | ||
| 112 | wc.lpszMenuName = NULL; | ||
| 113 | wc.lpszClassName = className; | ||
| 114 | if (MyRegisterClass(&wc) == 0) | ||
| 115 | return false; | ||
| 116 | } | ||
| 117 | return CWindow::CreateEx(exStyle, className, windowName, style, | ||
| 118 | x, y, width, height, parentWindow, idOrHMenu, instance, this); | ||
| 119 | } | ||
| 120 | |||
| 121 | #endif | ||
| 122 | |||
| 123 | LRESULT CWindow2::DefProc(UINT message, WPARAM wParam, LPARAM lParam) | ||
| 124 | { | ||
| 125 | #ifndef _UNICODE | ||
| 126 | if (g_IsNT) | ||
| 127 | return DefWindowProcW(_window, message, wParam, lParam); | ||
| 128 | else | ||
| 129 | #endif | ||
| 130 | return DefWindowProc(_window, message, wParam, lParam); | ||
| 131 | } | ||
| 132 | |||
| 133 | LRESULT CWindow2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) | ||
| 134 | { | ||
| 135 | LRESULT result; | ||
| 136 | switch (message) | ||
| 137 | { | ||
| 138 | case WM_CREATE: | ||
| 139 | if (!OnCreate((CREATESTRUCT *)lParam)) | ||
| 140 | return -1; | ||
| 141 | break; | ||
| 142 | case WM_COMMAND: | ||
| 143 | if (OnCommand(wParam, lParam, result)) | ||
| 144 | return result; | ||
| 145 | break; | ||
| 146 | case WM_NOTIFY: | ||
| 147 | if (OnNotify((UINT)wParam, (LPNMHDR) lParam, result)) | ||
| 148 | return result; | ||
| 149 | break; | ||
| 150 | case WM_DESTROY: | ||
| 151 | OnDestroy(); | ||
| 152 | break; | ||
| 153 | case WM_CLOSE: | ||
| 154 | OnClose(); | ||
| 155 | return 0; | ||
| 156 | case WM_SIZE: | ||
| 157 | if (OnSize(wParam, LOWORD(lParam), HIWORD(lParam))) | ||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | return DefProc(message, wParam, lParam); | ||
| 161 | } | ||
| 162 | |||
| 163 | bool CWindow2::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT &result) | ||
| 164 | { | ||
| 165 | return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result); | ||
| 166 | } | ||
| 167 | |||
| 168 | bool CWindow2::OnCommand(int /* code */, int /* itemID */, LPARAM /* lParam */, LRESULT & /* result */) | ||
| 169 | { | ||
| 170 | return false; | ||
| 171 | // return DefProc(message, wParam, lParam); | ||
| 172 | /* | ||
| 173 | if (code == BN_CLICKED) | ||
| 174 | return OnButtonClicked(itemID, (HWND)lParam); | ||
| 175 | */ | ||
| 176 | } | ||
| 177 | |||
| 178 | /* | ||
| 179 | bool CDialog::OnButtonClicked(int buttonID, HWND buttonHWND) | ||
| 180 | { | ||
| 181 | switch (buttonID) | ||
| 182 | { | ||
| 183 | case IDOK: | ||
| 184 | OnOK(); | ||
| 185 | break; | ||
| 186 | case IDCANCEL: | ||
| 187 | OnCancel(); | ||
| 188 | break; | ||
| 189 | case IDHELP: | ||
| 190 | OnHelp(); | ||
| 191 | break; | ||
| 192 | default: | ||
| 193 | return false; | ||
| 194 | } | ||
| 195 | return true; | ||
| 196 | } | ||
| 197 | |||
| 198 | */ | ||
| 199 | |||
| 200 | }} | ||
diff --git a/CPP/Windows/Control/Window2.h b/CPP/Windows/Control/Window2.h new file mode 100644 index 0000000..7ac580c --- /dev/null +++ b/CPP/Windows/Control/Window2.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | // Windows/Control/Window2.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_CONTROL_WINDOW2_H | ||
| 4 | #define __WINDOWS_CONTROL_WINDOW2_H | ||
| 5 | |||
| 6 | #include "../Window.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NControl { | ||
| 10 | |||
| 11 | class CWindow2: public CWindow | ||
| 12 | { | ||
| 13 | LRESULT DefProc(UINT message, WPARAM wParam, LPARAM lParam); | ||
| 14 | public: | ||
| 15 | CWindow2(HWND newWindow = NULL): CWindow(newWindow){}; | ||
| 16 | virtual ~CWindow2() {}; | ||
| 17 | |||
| 18 | bool CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName, | ||
| 19 | DWORD style, int x, int y, int width, int height, | ||
| 20 | HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance); | ||
| 21 | |||
| 22 | #ifndef _UNICODE | ||
| 23 | bool CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName, | ||
| 24 | DWORD style, int x, int y, int width, int height, | ||
| 25 | HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance); | ||
| 26 | #endif | ||
| 27 | |||
| 28 | virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); | ||
| 29 | virtual bool OnCreate(CREATESTRUCT * /* createStruct */) { return true; } | ||
| 30 | // virtual LRESULT OnCommand(WPARAM wParam, LPARAM lParam); | ||
| 31 | virtual bool OnCommand(WPARAM wParam, LPARAM lParam, LRESULT &result); | ||
| 32 | virtual bool OnCommand(int code, int itemID, LPARAM lParam, LRESULT &result); | ||
| 33 | virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; } | ||
| 34 | virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */, LRESULT & /* result */) { return false; } | ||
| 35 | virtual void OnDestroy() { PostQuitMessage(0); } | ||
| 36 | virtual void OnClose() { Destroy(); } | ||
| 37 | /* | ||
| 38 | virtual LRESULT OnHelp(LPHELPINFO helpInfo) { OnHelp(); } | ||
| 39 | virtual LRESULT OnHelp() {}; | ||
| 40 | virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); | ||
| 41 | virtual void OnOK() {}; | ||
| 42 | virtual void OnCancel() {}; | ||
| 43 | */ | ||
| 44 | |||
| 45 | LONG_PTR SetMsgResult(LONG_PTR newLongPtr) { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); } | ||
| 46 | LONG_PTR GetMsgResult() const { return GetLongPtr(DWLP_MSGRESULT); } | ||
| 47 | }; | ||
| 48 | |||
| 49 | }} | ||
| 50 | |||
| 51 | #endif | ||
diff --git a/CPP/Windows/DLL.cpp b/CPP/Windows/DLL.cpp new file mode 100644 index 0000000..cf5d01a --- /dev/null +++ b/CPP/Windows/DLL.cpp | |||
| @@ -0,0 +1,191 @@ | |||
| 1 | // Windows/DLL.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "DLL.h" | ||
| 6 | |||
| 7 | #ifdef _WIN32 | ||
| 8 | |||
| 9 | #ifndef _UNICODE | ||
| 10 | extern bool g_IsNT; | ||
| 11 | #endif | ||
| 12 | |||
| 13 | extern HINSTANCE g_hInstance; | ||
| 14 | |||
| 15 | namespace NWindows { | ||
| 16 | namespace NDLL { | ||
| 17 | |||
| 18 | bool CLibrary::Free() throw() | ||
| 19 | { | ||
| 20 | if (_module == 0) | ||
| 21 | return true; | ||
| 22 | if (!::FreeLibrary(_module)) | ||
| 23 | return false; | ||
| 24 | _module = 0; | ||
| 25 | return true; | ||
| 26 | } | ||
| 27 | |||
| 28 | bool CLibrary::LoadEx(CFSTR path, DWORD flags) throw() | ||
| 29 | { | ||
| 30 | if (!Free()) | ||
| 31 | return false; | ||
| 32 | #ifndef _UNICODE | ||
| 33 | if (!g_IsNT) | ||
| 34 | { | ||
| 35 | _module = ::LoadLibraryEx(fs2fas(path), NULL, flags); | ||
| 36 | } | ||
| 37 | else | ||
| 38 | #endif | ||
| 39 | { | ||
| 40 | _module = ::LoadLibraryExW(fs2us(path), NULL, flags); | ||
| 41 | } | ||
| 42 | return (_module != NULL); | ||
| 43 | } | ||
| 44 | |||
| 45 | bool CLibrary::Load(CFSTR path) throw() | ||
| 46 | { | ||
| 47 | if (!Free()) | ||
| 48 | return false; | ||
| 49 | #ifndef _UNICODE | ||
| 50 | if (!g_IsNT) | ||
| 51 | { | ||
| 52 | _module = ::LoadLibrary(fs2fas(path)); | ||
| 53 | } | ||
| 54 | else | ||
| 55 | #endif | ||
| 56 | { | ||
| 57 | _module = ::LoadLibraryW(fs2us(path)); | ||
| 58 | } | ||
| 59 | return (_module != NULL); | ||
| 60 | } | ||
| 61 | |||
| 62 | bool MyGetModuleFileName(FString &path) | ||
| 63 | { | ||
| 64 | HMODULE hModule = g_hInstance; | ||
| 65 | path.Empty(); | ||
| 66 | #ifndef _UNICODE | ||
| 67 | if (!g_IsNT) | ||
| 68 | { | ||
| 69 | TCHAR s[MAX_PATH + 2]; | ||
| 70 | s[0] = 0; | ||
| 71 | DWORD size = ::GetModuleFileName(hModule, s, MAX_PATH + 1); | ||
| 72 | if (size <= MAX_PATH && size != 0) | ||
| 73 | { | ||
| 74 | path = fas2fs(s); | ||
| 75 | return true; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | else | ||
| 79 | #endif | ||
| 80 | { | ||
| 81 | WCHAR s[MAX_PATH + 2]; | ||
| 82 | s[0] = 0; | ||
| 83 | DWORD size = ::GetModuleFileNameW(hModule, s, MAX_PATH + 1); | ||
| 84 | if (size <= MAX_PATH && size != 0) | ||
| 85 | { | ||
| 86 | path = us2fs(s); | ||
| 87 | return true; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | return false; | ||
| 91 | } | ||
| 92 | |||
| 93 | #ifndef _SFX | ||
| 94 | |||
| 95 | FString GetModuleDirPrefix() | ||
| 96 | { | ||
| 97 | FString s; | ||
| 98 | if (MyGetModuleFileName(s)) | ||
| 99 | { | ||
| 100 | int pos = s.ReverseFind_PathSepar(); | ||
| 101 | if (pos >= 0) | ||
| 102 | s.DeleteFrom((unsigned)(pos + 1)); | ||
| 103 | } | ||
| 104 | if (s.IsEmpty()) | ||
| 105 | s = "." STRING_PATH_SEPARATOR; | ||
| 106 | return s; | ||
| 107 | } | ||
| 108 | |||
| 109 | #endif | ||
| 110 | |||
| 111 | }} | ||
| 112 | |||
| 113 | #else | ||
| 114 | |||
| 115 | #include <dlfcn.h> | ||
| 116 | #include <stdlib.h> | ||
| 117 | |||
| 118 | namespace NWindows { | ||
| 119 | namespace NDLL { | ||
| 120 | |||
| 121 | bool CLibrary::Free() throw() | ||
| 122 | { | ||
| 123 | if (_module == NULL) | ||
| 124 | return true; | ||
| 125 | int ret = dlclose(_module); | ||
| 126 | if (ret != 0) | ||
| 127 | return false; | ||
| 128 | _module = NULL; | ||
| 129 | return true; | ||
| 130 | } | ||
| 131 | |||
| 132 | static | ||
| 133 | // FARPROC | ||
| 134 | void * | ||
| 135 | local_GetProcAddress(HMODULE module, LPCSTR procName) | ||
| 136 | { | ||
| 137 | void *ptr = NULL; | ||
| 138 | if (module) | ||
| 139 | { | ||
| 140 | ptr = dlsym(module, procName); | ||
| 141 | } | ||
| 142 | return ptr; | ||
| 143 | } | ||
| 144 | |||
| 145 | bool CLibrary::Load(CFSTR path) throw() | ||
| 146 | { | ||
| 147 | if (!Free()) | ||
| 148 | return false; | ||
| 149 | |||
| 150 | int options = 0; | ||
| 151 | |||
| 152 | #ifdef RTLD_LOCAL | ||
| 153 | options |= RTLD_LOCAL; | ||
| 154 | #endif | ||
| 155 | |||
| 156 | #ifdef RTLD_NOW | ||
| 157 | options |= RTLD_NOW; | ||
| 158 | #endif | ||
| 159 | |||
| 160 | #ifdef RTLD_GROUP | ||
| 161 | #if ! (defined(hpux) || defined(__hpux)) | ||
| 162 | options |= RTLD_GROUP; // mainly for solaris but not for HPUX | ||
| 163 | #endif | ||
| 164 | #endif | ||
| 165 | |||
| 166 | void *handler = dlopen(path, options); | ||
| 167 | |||
| 168 | if (handler) | ||
| 169 | { | ||
| 170 | // here we can transfer some settings to DLL | ||
| 171 | } | ||
| 172 | else | ||
| 173 | { | ||
| 174 | } | ||
| 175 | |||
| 176 | _module = handler; | ||
| 177 | |||
| 178 | return (_module != NULL); | ||
| 179 | } | ||
| 180 | |||
| 181 | // FARPROC | ||
| 182 | void * CLibrary::GetProc(LPCSTR procName) const | ||
| 183 | { | ||
| 184 | // return My_GetProcAddress(_module, procName); | ||
| 185 | return local_GetProcAddress(_module, procName); | ||
| 186 | // return NULL; | ||
| 187 | } | ||
| 188 | |||
| 189 | }} | ||
| 190 | |||
| 191 | #endif | ||
diff --git a/CPP/Windows/DLL.h b/CPP/Windows/DLL.h new file mode 100644 index 0000000..0c093ee --- /dev/null +++ b/CPP/Windows/DLL.h | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | // Windows/DLL.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_DLL_H | ||
| 4 | #define __WINDOWS_DLL_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NDLL { | ||
| 10 | |||
| 11 | #ifdef _WIN32 | ||
| 12 | |||
| 13 | #ifdef UNDER_CE | ||
| 14 | #define My_GetProcAddress(module, procName) (void *)::GetProcAddressA(module, procName) | ||
| 15 | #else | ||
| 16 | #define My_GetProcAddress(module, procName) (void *)::GetProcAddress(module, procName) | ||
| 17 | #endif | ||
| 18 | |||
| 19 | /* Win32: Don't call CLibrary::Free() and FreeLibrary() from another | ||
| 20 | FreeLibrary() code: detaching code in DLL entry-point or in | ||
| 21 | destructors of global objects in DLL module. */ | ||
| 22 | |||
| 23 | class CLibrary | ||
| 24 | { | ||
| 25 | HMODULE _module; | ||
| 26 | |||
| 27 | // CLASS_NO_COPY(CLibrary); | ||
| 28 | public: | ||
| 29 | CLibrary(): _module(NULL) {}; | ||
| 30 | ~CLibrary() { Free(); } | ||
| 31 | |||
| 32 | operator HMODULE() const { return _module; } | ||
| 33 | HMODULE* operator&() { return &_module; } | ||
| 34 | bool IsLoaded() const { return (_module != NULL); } | ||
| 35 | |||
| 36 | void Attach(HMODULE m) | ||
| 37 | { | ||
| 38 | Free(); | ||
| 39 | _module = m; | ||
| 40 | } | ||
| 41 | HMODULE Detach() | ||
| 42 | { | ||
| 43 | HMODULE m = _module; | ||
| 44 | _module = NULL; | ||
| 45 | return m; | ||
| 46 | } | ||
| 47 | |||
| 48 | bool Free() throw(); | ||
| 49 | bool LoadEx(CFSTR path, DWORD flags = LOAD_LIBRARY_AS_DATAFILE) throw(); | ||
| 50 | bool Load(CFSTR path) throw(); | ||
| 51 | // FARPROC | ||
| 52 | void *GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); } | ||
| 53 | }; | ||
| 54 | |||
| 55 | #else | ||
| 56 | |||
| 57 | typedef void * HMODULE; | ||
| 58 | // typedef int (*FARPROC)(); | ||
| 59 | // typedef void *FARPROC; | ||
| 60 | |||
| 61 | class CLibrary | ||
| 62 | { | ||
| 63 | HMODULE _module; | ||
| 64 | |||
| 65 | // CLASS_NO_COPY(CLibrary); | ||
| 66 | public: | ||
| 67 | CLibrary(): _module(NULL) {}; | ||
| 68 | ~CLibrary() { Free(); } | ||
| 69 | |||
| 70 | bool Free() throw(); | ||
| 71 | bool Load(CFSTR path) throw(); | ||
| 72 | // FARPROC | ||
| 73 | void *GetProc(LPCSTR procName) const; // { return My_GetProcAddress(_module, procName); } | ||
| 74 | }; | ||
| 75 | |||
| 76 | #endif | ||
| 77 | |||
| 78 | bool MyGetModuleFileName(FString &path); | ||
| 79 | |||
| 80 | FString GetModuleDirPrefix(); | ||
| 81 | |||
| 82 | }} | ||
| 83 | |||
| 84 | #endif | ||
diff --git a/CPP/Windows/Defs.h b/CPP/Windows/Defs.h new file mode 100644 index 0000000..1d96078 --- /dev/null +++ b/CPP/Windows/Defs.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | // Windows/Defs.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_DEFS_H | ||
| 4 | #define __WINDOWS_DEFS_H | ||
| 5 | |||
| 6 | #include "../Common/MyWindows.h" | ||
| 7 | |||
| 8 | #ifdef _WIN32 | ||
| 9 | inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); } | ||
| 10 | inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); } | ||
| 11 | #endif | ||
| 12 | |||
| 13 | inline bool BOOLToBool(BOOL v) { return (v != FALSE); } | ||
| 14 | |||
| 15 | inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); } | ||
| 16 | inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); } | ||
| 17 | |||
| 18 | #endif | ||
diff --git a/CPP/Windows/ErrorMsg.cpp b/CPP/Windows/ErrorMsg.cpp new file mode 100644 index 0000000..f6343a5 --- /dev/null +++ b/CPP/Windows/ErrorMsg.cpp | |||
| @@ -0,0 +1,133 @@ | |||
| 1 | // Windows/ErrorMsg.h | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #if !defined(_UNICODE) || !defined(_WIN32) | ||
| 6 | #include "../Common/StringConvert.h" | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #include "ErrorMsg.h" | ||
| 10 | |||
| 11 | #ifdef _WIN32 | ||
| 12 | #if !defined(_UNICODE) | ||
| 13 | extern bool g_IsNT; | ||
| 14 | #endif | ||
| 15 | #endif | ||
| 16 | |||
| 17 | namespace NWindows { | ||
| 18 | namespace NError { | ||
| 19 | |||
| 20 | static bool MyFormatMessage(DWORD errorCode, UString &message) | ||
| 21 | { | ||
| 22 | #ifndef _SFX | ||
| 23 | if ((HRESULT)errorCode == MY_HRES_ERROR__INTERNAL_ERROR) | ||
| 24 | { | ||
| 25 | message = "Internal Error: The failure in hardware (RAM or CPU), OS or program"; | ||
| 26 | return true; | ||
| 27 | } | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #ifdef _WIN32 | ||
| 31 | |||
| 32 | LPVOID msgBuf; | ||
| 33 | #ifndef _UNICODE | ||
| 34 | if (!g_IsNT) | ||
| 35 | { | ||
| 36 | if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||
| 37 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | ||
| 38 | NULL, errorCode, 0, (LPTSTR) &msgBuf, 0, NULL) == 0) | ||
| 39 | return false; | ||
| 40 | message = GetUnicodeString((LPCTSTR)msgBuf); | ||
| 41 | } | ||
| 42 | else | ||
| 43 | #endif | ||
| 44 | { | ||
| 45 | if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||
| 46 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | ||
| 47 | NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0) | ||
| 48 | return false; | ||
| 49 | message = (LPCWSTR)msgBuf; | ||
| 50 | } | ||
| 51 | ::LocalFree(msgBuf); | ||
| 52 | return true; | ||
| 53 | |||
| 54 | #else // _WIN32 | ||
| 55 | |||
| 56 | AString m; | ||
| 57 | |||
| 58 | const char *s = NULL; | ||
| 59 | |||
| 60 | switch ((Int32)errorCode) | ||
| 61 | { | ||
| 62 | // case ERROR_NO_MORE_FILES : s = "No more files"; break; | ||
| 63 | // case ERROR_DIRECTORY : s = "Error Directory"; break; | ||
| 64 | case E_NOTIMPL : s = "E_NOTIMPL : Not implemented"; break; | ||
| 65 | case E_NOINTERFACE : s = "E_NOINTERFACE : No such interface supported"; break; | ||
| 66 | case E_ABORT : s = "E_ABORT : Operation aborted"; break; | ||
| 67 | case E_FAIL : s = "E_FAIL : Unspecified error"; break; | ||
| 68 | |||
| 69 | case STG_E_INVALIDFUNCTION : s = "STG_E_INVALIDFUNCTION"; break; | ||
| 70 | case CLASS_E_CLASSNOTAVAILABLE : s = "CLASS_E_CLASSNOTAVAILABLE"; break; | ||
| 71 | |||
| 72 | case E_OUTOFMEMORY : s = "E_OUTOFMEMORY : Can't allocate required memory"; break; | ||
| 73 | case E_INVALIDARG : s = "E_INVALIDARG : One or more arguments are invalid"; break; | ||
| 74 | |||
| 75 | // case MY__E_ERROR_NEGATIVE_SEEK : s = "MY__E_ERROR_NEGATIVE_SEEK"; break; | ||
| 76 | default: | ||
| 77 | break; | ||
| 78 | } | ||
| 79 | |||
| 80 | /* strerror() for unknown errors still shows message "Unknown error -12345678") | ||
| 81 | So we must transfer error codes before strerror() */ | ||
| 82 | if (!s) | ||
| 83 | { | ||
| 84 | if ((errorCode & 0xFFFF0000) == (UInt32)((MY__FACILITY__WRes << 16) | 0x80000000)) | ||
| 85 | errorCode &= 0xFFFF; | ||
| 86 | else if ((errorCode & ((UInt32)1 << 31))) | ||
| 87 | return false; // we will show hex error later for that case | ||
| 88 | |||
| 89 | s = strerror((int)errorCode); | ||
| 90 | |||
| 91 | // if (!s) | ||
| 92 | { | ||
| 93 | m += "errno="; | ||
| 94 | m.Add_UInt32(errorCode); | ||
| 95 | if (s) | ||
| 96 | m += " : "; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | if (s) | ||
| 101 | m += s; | ||
| 102 | |||
| 103 | MultiByteToUnicodeString2(message, m); | ||
| 104 | return true; | ||
| 105 | |||
| 106 | #endif | ||
| 107 | } | ||
| 108 | |||
| 109 | |||
| 110 | UString MyFormatMessage(DWORD errorCode) | ||
| 111 | { | ||
| 112 | UString m; | ||
| 113 | if (!MyFormatMessage(errorCode, m) || m.IsEmpty()) | ||
| 114 | { | ||
| 115 | char s[16]; | ||
| 116 | for (int i = 0; i < 8; i++) | ||
| 117 | { | ||
| 118 | unsigned t = errorCode & 0xF; | ||
| 119 | errorCode >>= 4; | ||
| 120 | s[7 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); | ||
| 121 | } | ||
| 122 | s[8] = 0; | ||
| 123 | m += "Error #"; | ||
| 124 | m += s; | ||
| 125 | } | ||
| 126 | else if (m.Len() >= 2 | ||
| 127 | && m[m.Len() - 1] == 0x0A | ||
| 128 | && m[m.Len() - 2] == 0x0D) | ||
| 129 | m.DeleteFrom(m.Len() - 2); | ||
| 130 | return m; | ||
| 131 | } | ||
| 132 | |||
| 133 | }} | ||
diff --git a/CPP/Windows/ErrorMsg.h b/CPP/Windows/ErrorMsg.h new file mode 100644 index 0000000..01204eb --- /dev/null +++ b/CPP/Windows/ErrorMsg.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // Windows/ErrorMsg.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_ERROR_MSG_H | ||
| 4 | #define __WINDOWS_ERROR_MSG_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NError { | ||
| 10 | |||
| 11 | UString MyFormatMessage(DWORD errorCode); | ||
| 12 | inline UString MyFormatMessage(HRESULT errorCode) { return MyFormatMessage((DWORD)errorCode); } | ||
| 13 | |||
| 14 | }} | ||
| 15 | |||
| 16 | #endif | ||
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp new file mode 100644 index 0000000..8a33fc8 --- /dev/null +++ b/CPP/Windows/FileDir.cpp | |||
| @@ -0,0 +1,1129 @@ | |||
| 1 | // Windows/FileDir.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | |||
| 6 | #ifndef _WIN32 | ||
| 7 | #include <stdio.h> | ||
| 8 | #include <stdlib.h> | ||
| 9 | #include <errno.h> | ||
| 10 | #include <limits.h> | ||
| 11 | #include <unistd.h> | ||
| 12 | #include <time.h> | ||
| 13 | #include <utime.h> | ||
| 14 | #include <fcntl.h> | ||
| 15 | #include <sys/stat.h> | ||
| 16 | #include <sys/types.h> | ||
| 17 | |||
| 18 | #include "../Common/StringConvert.h" | ||
| 19 | #include "../Common/C_FileIO.h" | ||
| 20 | #include "TimeUtils.h" | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #include "FileDir.h" | ||
| 24 | #include "FileFind.h" | ||
| 25 | #include "FileName.h" | ||
| 26 | |||
| 27 | #ifndef _UNICODE | ||
| 28 | extern bool g_IsNT; | ||
| 29 | #endif | ||
| 30 | |||
| 31 | using namespace NWindows; | ||
| 32 | using namespace NFile; | ||
| 33 | using namespace NName; | ||
| 34 | |||
| 35 | namespace NWindows { | ||
| 36 | namespace NFile { | ||
| 37 | namespace NDir { | ||
| 38 | |||
| 39 | #ifdef _WIN32 | ||
| 40 | |||
| 41 | #ifndef UNDER_CE | ||
| 42 | |||
| 43 | bool GetWindowsDir(FString &path) | ||
| 44 | { | ||
| 45 | UINT needLength; | ||
| 46 | #ifndef _UNICODE | ||
| 47 | if (!g_IsNT) | ||
| 48 | { | ||
| 49 | TCHAR s[MAX_PATH + 2]; | ||
| 50 | s[0] = 0; | ||
| 51 | needLength = ::GetWindowsDirectory(s, MAX_PATH + 1); | ||
| 52 | path = fas2fs(s); | ||
| 53 | } | ||
| 54 | else | ||
| 55 | #endif | ||
| 56 | { | ||
| 57 | WCHAR s[MAX_PATH + 2]; | ||
| 58 | s[0] = 0; | ||
| 59 | needLength = ::GetWindowsDirectoryW(s, MAX_PATH + 1); | ||
| 60 | path = us2fs(s); | ||
| 61 | } | ||
| 62 | return (needLength > 0 && needLength <= MAX_PATH); | ||
| 63 | } | ||
| 64 | |||
| 65 | bool GetSystemDir(FString &path) | ||
| 66 | { | ||
| 67 | UINT needLength; | ||
| 68 | #ifndef _UNICODE | ||
| 69 | if (!g_IsNT) | ||
| 70 | { | ||
| 71 | TCHAR s[MAX_PATH + 2]; | ||
| 72 | s[0] = 0; | ||
| 73 | needLength = ::GetSystemDirectory(s, MAX_PATH + 1); | ||
| 74 | path = fas2fs(s); | ||
| 75 | } | ||
| 76 | else | ||
| 77 | #endif | ||
| 78 | { | ||
| 79 | WCHAR s[MAX_PATH + 2]; | ||
| 80 | s[0] = 0; | ||
| 81 | needLength = ::GetSystemDirectoryW(s, MAX_PATH + 1); | ||
| 82 | path = us2fs(s); | ||
| 83 | } | ||
| 84 | return (needLength > 0 && needLength <= MAX_PATH); | ||
| 85 | } | ||
| 86 | #endif // UNDER_CE | ||
| 87 | |||
| 88 | |||
| 89 | bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) | ||
| 90 | { | ||
| 91 | #ifndef _UNICODE | ||
| 92 | if (!g_IsNT) | ||
| 93 | { | ||
| 94 | ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | ||
| 95 | return false; | ||
| 96 | } | ||
| 97 | #endif | ||
| 98 | |||
| 99 | HANDLE hDir = INVALID_HANDLE_VALUE; | ||
| 100 | IF_USE_MAIN_PATH | ||
| 101 | hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, | ||
| 102 | NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); | ||
| 103 | #ifdef WIN_LONG_PATH | ||
| 104 | if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) | ||
| 105 | { | ||
| 106 | UString superPath; | ||
| 107 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 108 | hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, | ||
| 109 | NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); | ||
| 110 | } | ||
| 111 | #endif | ||
| 112 | |||
| 113 | bool res = false; | ||
| 114 | if (hDir != INVALID_HANDLE_VALUE) | ||
| 115 | { | ||
| 116 | res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime)); | ||
| 117 | ::CloseHandle(hDir); | ||
| 118 | } | ||
| 119 | return res; | ||
| 120 | } | ||
| 121 | |||
| 122 | |||
| 123 | |||
| 124 | bool SetFileAttrib(CFSTR path, DWORD attrib) | ||
| 125 | { | ||
| 126 | #ifndef _UNICODE | ||
| 127 | if (!g_IsNT) | ||
| 128 | { | ||
| 129 | if (::SetFileAttributes(fs2fas(path), attrib)) | ||
| 130 | return true; | ||
| 131 | } | ||
| 132 | else | ||
| 133 | #endif | ||
| 134 | { | ||
| 135 | IF_USE_MAIN_PATH | ||
| 136 | if (::SetFileAttributesW(fs2us(path), attrib)) | ||
| 137 | return true; | ||
| 138 | #ifdef WIN_LONG_PATH | ||
| 139 | if (USE_SUPER_PATH) | ||
| 140 | { | ||
| 141 | UString superPath; | ||
| 142 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 143 | return BOOLToBool(::SetFileAttributesW(superPath, attrib)); | ||
| 144 | } | ||
| 145 | #endif | ||
| 146 | } | ||
| 147 | return false; | ||
| 148 | } | ||
| 149 | |||
| 150 | |||
| 151 | bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) | ||
| 152 | { | ||
| 153 | #ifdef _WIN32 | ||
| 154 | if ((attrib & 0xF0000000) != 0) | ||
| 155 | attrib &= 0x3FFF; | ||
| 156 | #endif | ||
| 157 | return SetFileAttrib(path, attrib); | ||
| 158 | } | ||
| 159 | |||
| 160 | |||
| 161 | bool RemoveDir(CFSTR path) | ||
| 162 | { | ||
| 163 | #ifndef _UNICODE | ||
| 164 | if (!g_IsNT) | ||
| 165 | { | ||
| 166 | if (::RemoveDirectory(fs2fas(path))) | ||
| 167 | return true; | ||
| 168 | } | ||
| 169 | else | ||
| 170 | #endif | ||
| 171 | { | ||
| 172 | IF_USE_MAIN_PATH | ||
| 173 | if (::RemoveDirectoryW(fs2us(path))) | ||
| 174 | return true; | ||
| 175 | #ifdef WIN_LONG_PATH | ||
| 176 | if (USE_SUPER_PATH) | ||
| 177 | { | ||
| 178 | UString superPath; | ||
| 179 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 180 | return BOOLToBool(::RemoveDirectoryW(superPath)); | ||
| 181 | } | ||
| 182 | #endif | ||
| 183 | } | ||
| 184 | return false; | ||
| 185 | } | ||
| 186 | |||
| 187 | |||
| 188 | bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | ||
| 189 | { | ||
| 190 | #ifndef _UNICODE | ||
| 191 | if (!g_IsNT) | ||
| 192 | { | ||
| 193 | if (::MoveFile(fs2fas(oldFile), fs2fas(newFile))) | ||
| 194 | return true; | ||
| 195 | } | ||
| 196 | else | ||
| 197 | #endif | ||
| 198 | { | ||
| 199 | IF_USE_MAIN_PATH_2(oldFile, newFile) | ||
| 200 | { | ||
| 201 | if (::MoveFileW(fs2us(oldFile), fs2us(newFile))) | ||
| 202 | return true; | ||
| 203 | } | ||
| 204 | #ifdef WIN_LONG_PATH | ||
| 205 | if (USE_SUPER_PATH_2) | ||
| 206 | { | ||
| 207 | UString d1, d2; | ||
| 208 | if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2)) | ||
| 209 | return BOOLToBool(::MoveFileW(d1, d2)); | ||
| 210 | } | ||
| 211 | #endif | ||
| 212 | } | ||
| 213 | return false; | ||
| 214 | } | ||
| 215 | |||
| 216 | #ifndef UNDER_CE | ||
| 217 | EXTERN_C_BEGIN | ||
| 218 | typedef BOOL (WINAPI *Func_CreateHardLinkW)( | ||
| 219 | LPCWSTR lpFileName, | ||
| 220 | LPCWSTR lpExistingFileName, | ||
| 221 | LPSECURITY_ATTRIBUTES lpSecurityAttributes | ||
| 222 | ); | ||
| 223 | EXTERN_C_END | ||
| 224 | #endif // UNDER_CE | ||
| 225 | |||
| 226 | bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) | ||
| 227 | { | ||
| 228 | #ifndef _UNICODE | ||
| 229 | if (!g_IsNT) | ||
| 230 | { | ||
| 231 | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | ||
| 232 | return false; | ||
| 233 | /* | ||
| 234 | if (::CreateHardLink(fs2fas(newFileName), fs2fas(existFileName), NULL)) | ||
| 235 | return true; | ||
| 236 | */ | ||
| 237 | } | ||
| 238 | else | ||
| 239 | #endif | ||
| 240 | { | ||
| 241 | Func_CreateHardLinkW my_CreateHardLinkW = (Func_CreateHardLinkW) | ||
| 242 | (void *)::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"); | ||
| 243 | if (!my_CreateHardLinkW) | ||
| 244 | return false; | ||
| 245 | IF_USE_MAIN_PATH_2(newFileName, existFileName) | ||
| 246 | { | ||
| 247 | if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL)) | ||
| 248 | return true; | ||
| 249 | } | ||
| 250 | #ifdef WIN_LONG_PATH | ||
| 251 | if (USE_SUPER_PATH_2) | ||
| 252 | { | ||
| 253 | UString d1, d2; | ||
| 254 | if (GetSuperPaths(newFileName, existFileName, d1, d2, USE_MAIN_PATH_2)) | ||
| 255 | return BOOLToBool(my_CreateHardLinkW(d1, d2, NULL)); | ||
| 256 | } | ||
| 257 | #endif | ||
| 258 | } | ||
| 259 | return false; | ||
| 260 | } | ||
| 261 | |||
| 262 | |||
| 263 | /* | ||
| 264 | WinXP-64 CreateDir(): | ||
| 265 | "" - ERROR_PATH_NOT_FOUND | ||
| 266 | \ - ERROR_ACCESS_DENIED | ||
| 267 | C:\ - ERROR_ACCESS_DENIED, if there is such drive, | ||
| 268 | |||
| 269 | D:\folder - ERROR_PATH_NOT_FOUND, if there is no such drive, | ||
| 270 | C:\nonExistent\folder - ERROR_PATH_NOT_FOUND | ||
| 271 | |||
| 272 | C:\existFolder - ERROR_ALREADY_EXISTS | ||
| 273 | C:\existFolder\ - ERROR_ALREADY_EXISTS | ||
| 274 | |||
| 275 | C:\folder - OK | ||
| 276 | C:\folder\ - OK | ||
| 277 | |||
| 278 | \\Server\nonExistent - ERROR_BAD_NETPATH | ||
| 279 | \\Server\Share_Readonly - ERROR_ACCESS_DENIED | ||
| 280 | \\Server\Share - ERROR_ALREADY_EXISTS | ||
| 281 | |||
| 282 | \\Server\Share_NTFS_drive - ERROR_ACCESS_DENIED | ||
| 283 | \\Server\Share_FAT_drive - ERROR_ALREADY_EXISTS | ||
| 284 | */ | ||
| 285 | |||
| 286 | bool CreateDir(CFSTR path) | ||
| 287 | { | ||
| 288 | #ifndef _UNICODE | ||
| 289 | if (!g_IsNT) | ||
| 290 | { | ||
| 291 | if (::CreateDirectory(fs2fas(path), NULL)) | ||
| 292 | return true; | ||
| 293 | } | ||
| 294 | else | ||
| 295 | #endif | ||
| 296 | { | ||
| 297 | IF_USE_MAIN_PATH | ||
| 298 | if (::CreateDirectoryW(fs2us(path), NULL)) | ||
| 299 | return true; | ||
| 300 | #ifdef WIN_LONG_PATH | ||
| 301 | if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH) | ||
| 302 | { | ||
| 303 | UString superPath; | ||
| 304 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 305 | return BOOLToBool(::CreateDirectoryW(superPath, NULL)); | ||
| 306 | } | ||
| 307 | #endif | ||
| 308 | } | ||
| 309 | return false; | ||
| 310 | } | ||
| 311 | |||
| 312 | /* | ||
| 313 | CreateDir2 returns true, if directory can contain files after the call (two cases): | ||
| 314 | 1) the directory already exists | ||
| 315 | 2) the directory was created | ||
| 316 | path must be WITHOUT trailing path separator. | ||
| 317 | |||
| 318 | We need CreateDir2, since fileInfo.Find() for reserved names like "com8" | ||
| 319 | returns FILE instead of DIRECTORY. And we need to use SuperPath */ | ||
| 320 | |||
| 321 | static bool CreateDir2(CFSTR path) | ||
| 322 | { | ||
| 323 | #ifndef _UNICODE | ||
| 324 | if (!g_IsNT) | ||
| 325 | { | ||
| 326 | if (::CreateDirectory(fs2fas(path), NULL)) | ||
| 327 | return true; | ||
| 328 | } | ||
| 329 | else | ||
| 330 | #endif | ||
| 331 | { | ||
| 332 | IF_USE_MAIN_PATH | ||
| 333 | if (::CreateDirectoryW(fs2us(path), NULL)) | ||
| 334 | return true; | ||
| 335 | #ifdef WIN_LONG_PATH | ||
| 336 | if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH) | ||
| 337 | { | ||
| 338 | UString superPath; | ||
| 339 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 340 | { | ||
| 341 | if (::CreateDirectoryW(superPath, NULL)) | ||
| 342 | return true; | ||
| 343 | if (::GetLastError() != ERROR_ALREADY_EXISTS) | ||
| 344 | return false; | ||
| 345 | NFind::CFileInfo fi; | ||
| 346 | if (!fi.Find(us2fs(superPath))) | ||
| 347 | return false; | ||
| 348 | return fi.IsDir(); | ||
| 349 | } | ||
| 350 | } | ||
| 351 | #endif | ||
| 352 | } | ||
| 353 | if (::GetLastError() != ERROR_ALREADY_EXISTS) | ||
| 354 | return false; | ||
| 355 | NFind::CFileInfo fi; | ||
| 356 | if (!fi.Find(path)) | ||
| 357 | return false; | ||
| 358 | return fi.IsDir(); | ||
| 359 | } | ||
| 360 | |||
| 361 | #endif // _WIN32 | ||
| 362 | |||
| 363 | static bool CreateDir2(CFSTR path); | ||
| 364 | |||
| 365 | bool CreateComplexDir(CFSTR _path) | ||
| 366 | { | ||
| 367 | #ifdef _WIN32 | ||
| 368 | |||
| 369 | { | ||
| 370 | DWORD attrib = NFind::GetFileAttrib(_path); | ||
| 371 | if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) | ||
| 372 | return true; | ||
| 373 | } | ||
| 374 | |||
| 375 | #ifndef UNDER_CE | ||
| 376 | |||
| 377 | if (IsDriveRootPath_SuperAllowed(_path)) | ||
| 378 | return false; | ||
| 379 | |||
| 380 | const unsigned prefixSize = GetRootPrefixSize(_path); | ||
| 381 | |||
| 382 | #endif // UNDER_CE | ||
| 383 | |||
| 384 | #else // _WIN32 | ||
| 385 | |||
| 386 | // Posix | ||
| 387 | NFind::CFileInfo fi; | ||
| 388 | if (fi.Find(_path)) | ||
| 389 | { | ||
| 390 | if (fi.IsDir()) | ||
| 391 | return true; | ||
| 392 | } | ||
| 393 | |||
| 394 | #endif // _WIN32 | ||
| 395 | |||
| 396 | FString path (_path); | ||
| 397 | |||
| 398 | int pos = path.ReverseFind_PathSepar(); | ||
| 399 | if (pos >= 0 && (unsigned)pos == path.Len() - 1) | ||
| 400 | { | ||
| 401 | if (path.Len() == 1) | ||
| 402 | return true; | ||
| 403 | path.DeleteBack(); | ||
| 404 | } | ||
| 405 | |||
| 406 | const FString path2 (path); | ||
| 407 | pos = (int)path.Len(); | ||
| 408 | |||
| 409 | for (;;) | ||
| 410 | { | ||
| 411 | if (CreateDir2(path)) | ||
| 412 | break; | ||
| 413 | if (::GetLastError() == ERROR_ALREADY_EXISTS) | ||
| 414 | return false; | ||
| 415 | pos = path.ReverseFind_PathSepar(); | ||
| 416 | if (pos < 0 || pos == 0) | ||
| 417 | return false; | ||
| 418 | |||
| 419 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 420 | if (pos == 1 && IS_PATH_SEPAR(path[0])) | ||
| 421 | return false; | ||
| 422 | if (prefixSize >= (unsigned)pos + 1) | ||
| 423 | return false; | ||
| 424 | #endif | ||
| 425 | |||
| 426 | path.DeleteFrom((unsigned)pos); | ||
| 427 | } | ||
| 428 | |||
| 429 | while (pos < (int)path2.Len()) | ||
| 430 | { | ||
| 431 | int pos2 = NName::FindSepar(path2.Ptr((unsigned)pos + 1)); | ||
| 432 | if (pos2 < 0) | ||
| 433 | pos = (int)path2.Len(); | ||
| 434 | else | ||
| 435 | pos += 1 + pos2; | ||
| 436 | path.SetFrom(path2, (unsigned)pos); | ||
| 437 | if (!CreateDir(path)) | ||
| 438 | return false; | ||
| 439 | } | ||
| 440 | |||
| 441 | return true; | ||
| 442 | } | ||
| 443 | |||
| 444 | |||
| 445 | #ifdef _WIN32 | ||
| 446 | |||
| 447 | bool DeleteFileAlways(CFSTR path) | ||
| 448 | { | ||
| 449 | /* If alt stream, we also need to clear READ-ONLY attribute of main file before delete. | ||
| 450 | SetFileAttrib("name:stream", ) changes attributes of main file. */ | ||
| 451 | { | ||
| 452 | DWORD attrib = NFind::GetFileAttrib(path); | ||
| 453 | if (attrib != INVALID_FILE_ATTRIBUTES | ||
| 454 | && (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0 | ||
| 455 | && (attrib & FILE_ATTRIBUTE_READONLY) != 0) | ||
| 456 | { | ||
| 457 | if (!SetFileAttrib(path, attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY)) | ||
| 458 | return false; | ||
| 459 | } | ||
| 460 | } | ||
| 461 | |||
| 462 | #ifndef _UNICODE | ||
| 463 | if (!g_IsNT) | ||
| 464 | { | ||
| 465 | if (::DeleteFile(fs2fas(path))) | ||
| 466 | return true; | ||
| 467 | } | ||
| 468 | else | ||
| 469 | #endif | ||
| 470 | { | ||
| 471 | /* DeleteFile("name::$DATA") deletes all alt streams (same as delete DeleteFile("name")). | ||
| 472 | Maybe it's better to open "name::$DATA" and clear data for unnamed stream? */ | ||
| 473 | IF_USE_MAIN_PATH | ||
| 474 | if (::DeleteFileW(fs2us(path))) | ||
| 475 | return true; | ||
| 476 | #ifdef WIN_LONG_PATH | ||
| 477 | if (USE_SUPER_PATH) | ||
| 478 | { | ||
| 479 | UString superPath; | ||
| 480 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 481 | return BOOLToBool(::DeleteFileW(superPath)); | ||
| 482 | } | ||
| 483 | #endif | ||
| 484 | } | ||
| 485 | return false; | ||
| 486 | } | ||
| 487 | |||
| 488 | |||
| 489 | |||
| 490 | bool RemoveDirWithSubItems(const FString &path) | ||
| 491 | { | ||
| 492 | bool needRemoveSubItems = true; | ||
| 493 | { | ||
| 494 | NFind::CFileInfo fi; | ||
| 495 | if (!fi.Find(path)) | ||
| 496 | return false; | ||
| 497 | if (!fi.IsDir()) | ||
| 498 | { | ||
| 499 | ::SetLastError(ERROR_DIRECTORY); | ||
| 500 | return false; | ||
| 501 | } | ||
| 502 | if (fi.HasReparsePoint()) | ||
| 503 | needRemoveSubItems = false; | ||
| 504 | } | ||
| 505 | |||
| 506 | if (needRemoveSubItems) | ||
| 507 | { | ||
| 508 | FString s (path); | ||
| 509 | s.Add_PathSepar(); | ||
| 510 | const unsigned prefixSize = s.Len(); | ||
| 511 | NFind::CEnumerator enumerator; | ||
| 512 | enumerator.SetDirPrefix(s); | ||
| 513 | NFind::CDirEntry fi; | ||
| 514 | bool isError = false; | ||
| 515 | DWORD lastError = 0; | ||
| 516 | while (enumerator.Next(fi)) | ||
| 517 | { | ||
| 518 | s.DeleteFrom(prefixSize); | ||
| 519 | s += fi.Name; | ||
| 520 | if (fi.IsDir()) | ||
| 521 | { | ||
| 522 | if (!RemoveDirWithSubItems(s)) | ||
| 523 | { | ||
| 524 | lastError = GetLastError(); | ||
| 525 | isError = true; | ||
| 526 | } | ||
| 527 | } | ||
| 528 | else if (!DeleteFileAlways(s)) | ||
| 529 | { | ||
| 530 | lastError = GetLastError(); | ||
| 531 | isError = false; | ||
| 532 | } | ||
| 533 | } | ||
| 534 | if (isError) | ||
| 535 | { | ||
| 536 | SetLastError(lastError); | ||
| 537 | return false; | ||
| 538 | } | ||
| 539 | } | ||
| 540 | |||
| 541 | // we clear read-only attrib to remove read-only dir | ||
| 542 | if (!SetFileAttrib(path, 0)) | ||
| 543 | return false; | ||
| 544 | return RemoveDir(path); | ||
| 545 | } | ||
| 546 | |||
| 547 | #endif // _WIN32 | ||
| 548 | |||
| 549 | #ifdef UNDER_CE | ||
| 550 | |||
| 551 | bool MyGetFullPathName(CFSTR path, FString &resFullPath) | ||
| 552 | { | ||
| 553 | resFullPath = path; | ||
| 554 | return true; | ||
| 555 | } | ||
| 556 | |||
| 557 | #else | ||
| 558 | |||
| 559 | bool MyGetFullPathName(CFSTR path, FString &resFullPath) | ||
| 560 | { | ||
| 561 | return GetFullPath(path, resFullPath); | ||
| 562 | } | ||
| 563 | |||
| 564 | #ifdef _WIN32 | ||
| 565 | |||
| 566 | bool SetCurrentDir(CFSTR path) | ||
| 567 | { | ||
| 568 | // SetCurrentDirectory doesn't support \\?\ prefix | ||
| 569 | #ifndef _UNICODE | ||
| 570 | if (!g_IsNT) | ||
| 571 | { | ||
| 572 | return BOOLToBool(::SetCurrentDirectory(fs2fas(path))); | ||
| 573 | } | ||
| 574 | else | ||
| 575 | #endif | ||
| 576 | { | ||
| 577 | return BOOLToBool(::SetCurrentDirectoryW(fs2us(path))); | ||
| 578 | } | ||
| 579 | } | ||
| 580 | |||
| 581 | |||
| 582 | bool GetCurrentDir(FString &path) | ||
| 583 | { | ||
| 584 | path.Empty(); | ||
| 585 | |||
| 586 | DWORD needLength; | ||
| 587 | #ifndef _UNICODE | ||
| 588 | if (!g_IsNT) | ||
| 589 | { | ||
| 590 | TCHAR s[MAX_PATH + 2]; | ||
| 591 | s[0] = 0; | ||
| 592 | needLength = ::GetCurrentDirectory(MAX_PATH + 1, s); | ||
| 593 | path = fas2fs(s); | ||
| 594 | } | ||
| 595 | else | ||
| 596 | #endif | ||
| 597 | { | ||
| 598 | WCHAR s[MAX_PATH + 2]; | ||
| 599 | s[0] = 0; | ||
| 600 | needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s); | ||
| 601 | path = us2fs(s); | ||
| 602 | } | ||
| 603 | return (needLength > 0 && needLength <= MAX_PATH); | ||
| 604 | } | ||
| 605 | |||
| 606 | #endif // _WIN32 | ||
| 607 | #endif // UNDER_CE | ||
| 608 | |||
| 609 | |||
| 610 | bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName) | ||
| 611 | { | ||
| 612 | bool res = MyGetFullPathName(path, resDirPrefix); | ||
| 613 | if (!res) | ||
| 614 | resDirPrefix = path; | ||
| 615 | int pos = resDirPrefix.ReverseFind_PathSepar(); | ||
| 616 | pos++; | ||
| 617 | resFileName = resDirPrefix.Ptr((unsigned)pos); | ||
| 618 | resDirPrefix.DeleteFrom((unsigned)pos); | ||
| 619 | return res; | ||
| 620 | } | ||
| 621 | |||
| 622 | bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix) | ||
| 623 | { | ||
| 624 | FString resFileName; | ||
| 625 | return GetFullPathAndSplit(path, resDirPrefix, resFileName); | ||
| 626 | } | ||
| 627 | |||
| 628 | bool MyGetTempPath(FString &path) | ||
| 629 | { | ||
| 630 | #ifdef _WIN32 | ||
| 631 | path.Empty(); | ||
| 632 | DWORD needLength; | ||
| 633 | #ifndef _UNICODE | ||
| 634 | if (!g_IsNT) | ||
| 635 | { | ||
| 636 | TCHAR s[MAX_PATH + 2]; | ||
| 637 | s[0] = 0; | ||
| 638 | needLength = ::GetTempPath(MAX_PATH + 1, s); | ||
| 639 | path = fas2fs(s); | ||
| 640 | } | ||
| 641 | else | ||
| 642 | #endif | ||
| 643 | { | ||
| 644 | WCHAR s[MAX_PATH + 2]; | ||
| 645 | s[0] = 0; | ||
| 646 | needLength = ::GetTempPathW(MAX_PATH + 1, s);; | ||
| 647 | path = us2fs(s); | ||
| 648 | } | ||
| 649 | return (needLength > 0 && needLength <= MAX_PATH); | ||
| 650 | |||
| 651 | #else | ||
| 652 | |||
| 653 | // FIXME: improve that code | ||
| 654 | path = "/tmp/"; | ||
| 655 | if (!NFind::DoesDirExist_FollowLink(path)) | ||
| 656 | path = "./"; | ||
| 657 | return true; | ||
| 658 | #endif | ||
| 659 | } | ||
| 660 | |||
| 661 | |||
| 662 | static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COutFile *outFile) | ||
| 663 | { | ||
| 664 | UInt32 d = | ||
| 665 | #ifdef _WIN32 | ||
| 666 | (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); | ||
| 667 | #else | ||
| 668 | (UInt32)(time(NULL) << 12) ^ ((UInt32)getppid() << 14) ^ (UInt32)(getpid()); | ||
| 669 | #endif | ||
| 670 | |||
| 671 | for (unsigned i = 0; i < 100; i++) | ||
| 672 | { | ||
| 673 | path = prefix; | ||
| 674 | if (addRandom) | ||
| 675 | { | ||
| 676 | char s[16]; | ||
| 677 | UInt32 val = d; | ||
| 678 | unsigned k; | ||
| 679 | for (k = 0; k < 8; k++) | ||
| 680 | { | ||
| 681 | unsigned t = val & 0xF; | ||
| 682 | val >>= 4; | ||
| 683 | s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); | ||
| 684 | } | ||
| 685 | s[k] = '\0'; | ||
| 686 | if (outFile) | ||
| 687 | path += '.'; | ||
| 688 | path += s; | ||
| 689 | UInt32 step = GetTickCount() + 2; | ||
| 690 | if (step == 0) | ||
| 691 | step = 1; | ||
| 692 | d += step; | ||
| 693 | } | ||
| 694 | addRandom = true; | ||
| 695 | if (outFile) | ||
| 696 | path += ".tmp"; | ||
| 697 | if (NFind::DoesFileOrDirExist(path)) | ||
| 698 | { | ||
| 699 | SetLastError(ERROR_ALREADY_EXISTS); | ||
| 700 | continue; | ||
| 701 | } | ||
| 702 | if (outFile) | ||
| 703 | { | ||
| 704 | if (outFile->Create(path, false)) | ||
| 705 | return true; | ||
| 706 | } | ||
| 707 | else | ||
| 708 | { | ||
| 709 | if (CreateDir(path)) | ||
| 710 | return true; | ||
| 711 | } | ||
| 712 | DWORD error = GetLastError(); | ||
| 713 | if (error != ERROR_FILE_EXISTS && | ||
| 714 | error != ERROR_ALREADY_EXISTS) | ||
| 715 | break; | ||
| 716 | } | ||
| 717 | path.Empty(); | ||
| 718 | return false; | ||
| 719 | } | ||
| 720 | |||
| 721 | bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile) | ||
| 722 | { | ||
| 723 | if (!Remove()) | ||
| 724 | return false; | ||
| 725 | if (!CreateTempFile(prefix, false, _path, outFile)) | ||
| 726 | return false; | ||
| 727 | _mustBeDeleted = true; | ||
| 728 | return true; | ||
| 729 | } | ||
| 730 | |||
| 731 | bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile) | ||
| 732 | { | ||
| 733 | if (!Remove()) | ||
| 734 | return false; | ||
| 735 | FString tempPath; | ||
| 736 | if (!MyGetTempPath(tempPath)) | ||
| 737 | return false; | ||
| 738 | if (!CreateTempFile(tempPath + namePrefix, true, _path, outFile)) | ||
| 739 | return false; | ||
| 740 | _mustBeDeleted = true; | ||
| 741 | return true; | ||
| 742 | } | ||
| 743 | |||
| 744 | bool CTempFile::Remove() | ||
| 745 | { | ||
| 746 | if (!_mustBeDeleted) | ||
| 747 | return true; | ||
| 748 | _mustBeDeleted = !DeleteFileAlways(_path); | ||
| 749 | return !_mustBeDeleted; | ||
| 750 | } | ||
| 751 | |||
| 752 | bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) | ||
| 753 | { | ||
| 754 | // DWORD attrib = 0; | ||
| 755 | if (deleteDestBefore) | ||
| 756 | { | ||
| 757 | if (NFind::DoesFileExist_Raw(name)) | ||
| 758 | { | ||
| 759 | // attrib = NFind::GetFileAttrib(name); | ||
| 760 | if (!DeleteFileAlways(name)) | ||
| 761 | return false; | ||
| 762 | } | ||
| 763 | } | ||
| 764 | DisableDeleting(); | ||
| 765 | return MyMoveFile(_path, name); | ||
| 766 | |||
| 767 | /* | ||
| 768 | if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) | ||
| 769 | { | ||
| 770 | DWORD attrib2 = NFind::GetFileAttrib(name); | ||
| 771 | if (attrib2 != INVALID_FILE_ATTRIBUTES) | ||
| 772 | SetFileAttrib(name, attrib2 | FILE_ATTRIBUTE_READONLY); | ||
| 773 | } | ||
| 774 | */ | ||
| 775 | } | ||
| 776 | |||
| 777 | #ifdef _WIN32 | ||
| 778 | bool CTempDir::Create(CFSTR prefix) | ||
| 779 | { | ||
| 780 | if (!Remove()) | ||
| 781 | return false; | ||
| 782 | FString tempPath; | ||
| 783 | if (!MyGetTempPath(tempPath)) | ||
| 784 | return false; | ||
| 785 | if (!CreateTempFile(tempPath + prefix, true, _path, NULL)) | ||
| 786 | return false; | ||
| 787 | _mustBeDeleted = true; | ||
| 788 | return true; | ||
| 789 | } | ||
| 790 | |||
| 791 | bool CTempDir::Remove() | ||
| 792 | { | ||
| 793 | if (!_mustBeDeleted) | ||
| 794 | return true; | ||
| 795 | _mustBeDeleted = !RemoveDirWithSubItems(_path); | ||
| 796 | return !_mustBeDeleted; | ||
| 797 | } | ||
| 798 | #endif | ||
| 799 | |||
| 800 | |||
| 801 | |||
| 802 | #ifndef _WIN32 | ||
| 803 | |||
| 804 | bool RemoveDir(CFSTR path) | ||
| 805 | { | ||
| 806 | return (rmdir(path) == 0); | ||
| 807 | } | ||
| 808 | |||
| 809 | |||
| 810 | static BOOL My__CopyFile(CFSTR oldFile, CFSTR newFile) | ||
| 811 | { | ||
| 812 | NWindows::NFile::NIO::COutFile outFile; | ||
| 813 | if (!outFile.Create(newFile, false)) | ||
| 814 | return FALSE; | ||
| 815 | |||
| 816 | NWindows::NFile::NIO::CInFile inFile; | ||
| 817 | if (!inFile.Open(oldFile)) | ||
| 818 | return FALSE; | ||
| 819 | |||
| 820 | char buf[1 << 14]; | ||
| 821 | |||
| 822 | for (;;) | ||
| 823 | { | ||
| 824 | const ssize_t num = inFile.read_part(buf, sizeof(buf)); | ||
| 825 | if (num == 0) | ||
| 826 | return TRUE; | ||
| 827 | if (num < 0) | ||
| 828 | return FALSE; | ||
| 829 | size_t processed; | ||
| 830 | const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed); | ||
| 831 | if (num2 != num || processed != (size_t)num) | ||
| 832 | return FALSE; | ||
| 833 | } | ||
| 834 | } | ||
| 835 | |||
| 836 | |||
| 837 | bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | ||
| 838 | { | ||
| 839 | int res = rename(oldFile, newFile); | ||
| 840 | if (res == 0) | ||
| 841 | return true; | ||
| 842 | if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem) | ||
| 843 | return false; | ||
| 844 | |||
| 845 | if (My__CopyFile(oldFile, newFile) == FALSE) | ||
| 846 | return false; | ||
| 847 | |||
| 848 | struct stat info_file; | ||
| 849 | res = stat(oldFile, &info_file); | ||
| 850 | if (res != 0) | ||
| 851 | return false; | ||
| 852 | |||
| 853 | /* | ||
| 854 | ret = chmod(dst,info_file.st_mode & g_umask.mask); | ||
| 855 | */ | ||
| 856 | return (unlink(oldFile) == 0); | ||
| 857 | } | ||
| 858 | |||
| 859 | |||
| 860 | bool CreateDir(CFSTR path) | ||
| 861 | { | ||
| 862 | return (mkdir(path, 0777) == 0); // change it | ||
| 863 | } | ||
| 864 | |||
| 865 | static bool CreateDir2(CFSTR path) | ||
| 866 | { | ||
| 867 | return (mkdir(path, 0777) == 0); // change it | ||
| 868 | } | ||
| 869 | |||
| 870 | |||
| 871 | bool DeleteFileAlways(CFSTR path) | ||
| 872 | { | ||
| 873 | return (remove(path) == 0); | ||
| 874 | } | ||
| 875 | |||
| 876 | bool SetCurrentDir(CFSTR path) | ||
| 877 | { | ||
| 878 | return (chdir(path) == 0); | ||
| 879 | } | ||
| 880 | |||
| 881 | |||
| 882 | bool GetCurrentDir(FString &path) | ||
| 883 | { | ||
| 884 | path.Empty(); | ||
| 885 | |||
| 886 | #define MY__PATH_MAX PATH_MAX | ||
| 887 | // #define MY__PATH_MAX 1024 | ||
| 888 | |||
| 889 | char s[MY__PATH_MAX + 1]; | ||
| 890 | char *res = getcwd(s, MY__PATH_MAX); | ||
| 891 | if (res) | ||
| 892 | { | ||
| 893 | path = fas2fs(s); | ||
| 894 | return true; | ||
| 895 | } | ||
| 896 | { | ||
| 897 | // if (errno != ERANGE) return false; | ||
| 898 | #if defined(__GLIBC__) || defined(__APPLE__) | ||
| 899 | /* As an extension to the POSIX.1-2001 standard, glibc's getcwd() | ||
| 900 | allocates the buffer dynamically using malloc(3) if buf is NULL. */ | ||
| 901 | res = getcwd(NULL, 0); | ||
| 902 | if (res) | ||
| 903 | { | ||
| 904 | path = fas2fs(res); | ||
| 905 | ::free(res); | ||
| 906 | return true; | ||
| 907 | } | ||
| 908 | #endif | ||
| 909 | return false; | ||
| 910 | } | ||
| 911 | } | ||
| 912 | |||
| 913 | |||
| 914 | |||
| 915 | // #undef UTIME_OMIT // to debug | ||
| 916 | |||
| 917 | #ifndef UTIME_OMIT | ||
| 918 | /* we can define UTIME_OMIT for debian and another systems. | ||
| 919 | Is it OK to define UTIME_OMIT to -2 here, if UTIME_OMIT is not defined? */ | ||
| 920 | // #define UTIME_OMIT -2 | ||
| 921 | #endif | ||
| 922 | |||
| 923 | static bool FILETME_To_timespec(const FILETIME *ft, timespec &ts) | ||
| 924 | { | ||
| 925 | if (ft) | ||
| 926 | { | ||
| 927 | const Int64 sec = NTime::FileTimeToUnixTime64(*ft); | ||
| 928 | // time_t is long | ||
| 929 | const time_t sec2 = (time_t)sec; | ||
| 930 | if (sec2 == sec) | ||
| 931 | { | ||
| 932 | ts.tv_sec = sec2; | ||
| 933 | const UInt64 winTime = (((UInt64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime; | ||
| 934 | ts.tv_nsec = (long)((winTime % 10000000) * 100); | ||
| 935 | return true; | ||
| 936 | } | ||
| 937 | } | ||
| 938 | // else | ||
| 939 | { | ||
| 940 | ts.tv_sec = 0; | ||
| 941 | ts.tv_nsec = | ||
| 942 | #ifdef UTIME_OMIT | ||
| 943 | UTIME_OMIT; // keep old timesptamp | ||
| 944 | #else | ||
| 945 | // UTIME_NOW; // set to the current time | ||
| 946 | 0; | ||
| 947 | #endif | ||
| 948 | return false; | ||
| 949 | } | ||
| 950 | } | ||
| 951 | |||
| 952 | |||
| 953 | |||
| 954 | |||
| 955 | bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) | ||
| 956 | { | ||
| 957 | // need testing | ||
| 958 | /* | ||
| 959 | struct utimbuf buf; | ||
| 960 | struct stat st; | ||
| 961 | UNUSED_VAR(cTime) | ||
| 962 | |||
| 963 | printf("\nstat = %s\n", path); | ||
| 964 | int ret = stat(path, &st); | ||
| 965 | |||
| 966 | if (ret == 0) | ||
| 967 | { | ||
| 968 | buf.actime = st.st_atime; | ||
| 969 | buf.modtime = st.st_mtime; | ||
| 970 | } | ||
| 971 | else | ||
| 972 | { | ||
| 973 | time_t cur_time = time(0); | ||
| 974 | buf.actime = cur_time; | ||
| 975 | buf.modtime = cur_time; | ||
| 976 | } | ||
| 977 | |||
| 978 | if (aTime) | ||
| 979 | { | ||
| 980 | UInt32 ut; | ||
| 981 | if (NTime::FileTimeToUnixTime(*aTime, ut)) | ||
| 982 | buf.actime = ut; | ||
| 983 | } | ||
| 984 | |||
| 985 | if (mTime) | ||
| 986 | { | ||
| 987 | UInt32 ut; | ||
| 988 | if (NTime::FileTimeToUnixTime(*mTime, ut)) | ||
| 989 | buf.modtime = ut; | ||
| 990 | } | ||
| 991 | |||
| 992 | return utime(path, &buf) == 0; | ||
| 993 | */ | ||
| 994 | |||
| 995 | // if (!aTime && !mTime) return true; | ||
| 996 | |||
| 997 | struct timespec times[2]; | ||
| 998 | UNUSED_VAR(cTime) | ||
| 999 | |||
| 1000 | bool needChange; | ||
| 1001 | needChange = FILETME_To_timespec(aTime, times[0]); | ||
| 1002 | needChange |= FILETME_To_timespec(mTime, times[1]); | ||
| 1003 | |||
| 1004 | if (!needChange) | ||
| 1005 | return true; | ||
| 1006 | |||
| 1007 | const int flags = 0; // follow link | ||
| 1008 | // = AT_SYMLINK_NOFOLLOW; // don't follow link | ||
| 1009 | return utimensat(AT_FDCWD, path, times, flags) == 0; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | |||
| 1013 | |||
| 1014 | struct C_umask | ||
| 1015 | { | ||
| 1016 | mode_t mask; | ||
| 1017 | |||
| 1018 | C_umask() | ||
| 1019 | { | ||
| 1020 | /* by security reasons we restrict attributes according | ||
| 1021 | with process's file mode creation mask (umask) */ | ||
| 1022 | const mode_t um = umask(0); // octal :0022 is expected | ||
| 1023 | mask = 0777 & (~um); // octal: 0755 is expected | ||
| 1024 | umask(um); // restore the umask | ||
| 1025 | // printf("\n umask = 0%03o mask = 0%03o\n", um, mask); | ||
| 1026 | |||
| 1027 | // mask = 0777; // debug we can disable the restriction: | ||
| 1028 | } | ||
| 1029 | }; | ||
| 1030 | |||
| 1031 | static C_umask g_umask; | ||
| 1032 | |||
| 1033 | // #define PRF(x) x; | ||
| 1034 | #define PRF(x) | ||
| 1035 | |||
| 1036 | #define TRACE_SetFileAttrib(msg) \ | ||
| 1037 | PRF(printf("\nSetFileAttrib(%s, %x) : %s\n", (const char *)path, attrib, msg)); | ||
| 1038 | |||
| 1039 | #define TRACE_chmod(s, mode) \ | ||
| 1040 | PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode))); | ||
| 1041 | |||
| 1042 | |||
| 1043 | bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) | ||
| 1044 | { | ||
| 1045 | TRACE_SetFileAttrib(""); | ||
| 1046 | |||
| 1047 | struct stat st; | ||
| 1048 | |||
| 1049 | bool use_lstat = true; | ||
| 1050 | if (use_lstat) | ||
| 1051 | { | ||
| 1052 | if (lstat(path, &st) != 0) | ||
| 1053 | { | ||
| 1054 | TRACE_SetFileAttrib("bad lstat()"); | ||
| 1055 | return false; | ||
| 1056 | } | ||
| 1057 | // TRACE_chmod("lstat", st.st_mode); | ||
| 1058 | } | ||
| 1059 | else | ||
| 1060 | { | ||
| 1061 | if (stat(path, &st) != 0) | ||
| 1062 | { | ||
| 1063 | TRACE_SetFileAttrib("bad stat()"); | ||
| 1064 | return false; | ||
| 1065 | } | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) | ||
| 1069 | { | ||
| 1070 | TRACE_SetFileAttrib("attrib & FILE_ATTRIBUTE_UNIX_EXTENSION"); | ||
| 1071 | st.st_mode = attrib >> 16; | ||
| 1072 | if (S_ISDIR(st.st_mode)) | ||
| 1073 | { | ||
| 1074 | // user/7z must be able to create files in this directory | ||
| 1075 | st.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR); | ||
| 1076 | } | ||
| 1077 | else if (!S_ISREG(st.st_mode)) | ||
| 1078 | return true; | ||
| 1079 | } | ||
| 1080 | else if (S_ISLNK(st.st_mode)) | ||
| 1081 | { | ||
| 1082 | /* for most systems: permissions for symlinks are fixed to rwxrwxrwx. | ||
| 1083 | so we don't need chmod() for symlinks. */ | ||
| 1084 | return true; | ||
| 1085 | // SetLastError(ENOSYS); | ||
| 1086 | // return false; | ||
| 1087 | } | ||
| 1088 | else | ||
| 1089 | { | ||
| 1090 | TRACE_SetFileAttrib("Only Windows Attributes"); | ||
| 1091 | // Only Windows Attributes | ||
| 1092 | if (S_ISDIR(st.st_mode) | ||
| 1093 | || (attrib & FILE_ATTRIBUTE_READONLY) == 0) | ||
| 1094 | return true; | ||
| 1095 | st.st_mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | int res; | ||
| 1099 | /* | ||
| 1100 | if (S_ISLNK(st.st_mode)) | ||
| 1101 | { | ||
| 1102 | printf("\nfchmodat()\n"); | ||
| 1103 | TRACE_chmod(path, (st.st_mode) & g_umask.mask); | ||
| 1104 | // AT_SYMLINK_NOFOLLOW is not implemted still in Linux. | ||
| 1105 | res = fchmodat(AT_FDCWD, path, (st.st_mode) & g_umask.mask, | ||
| 1106 | S_ISLNK(st.st_mode) ? AT_SYMLINK_NOFOLLOW : 0); | ||
| 1107 | } | ||
| 1108 | else | ||
| 1109 | */ | ||
| 1110 | { | ||
| 1111 | TRACE_chmod(path, (st.st_mode) & g_umask.mask); | ||
| 1112 | res = chmod(path, (st.st_mode) & g_umask.mask); | ||
| 1113 | } | ||
| 1114 | // TRACE_SetFileAttrib("End") | ||
| 1115 | return (res == 0); | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | |||
| 1119 | bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) | ||
| 1120 | { | ||
| 1121 | PRF(printf("\nhard link() %s -> %s\n", newFileName, existFileName)); | ||
| 1122 | return (link(existFileName, newFileName) == 0); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | #endif // !_WIN32 | ||
| 1126 | |||
| 1127 | // #endif | ||
| 1128 | |||
| 1129 | }}} | ||
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h new file mode 100644 index 0000000..6d6ddea --- /dev/null +++ b/CPP/Windows/FileDir.h | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | // Windows/FileDir.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_FILE_DIR_H | ||
| 4 | #define __WINDOWS_FILE_DIR_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | #include "FileIO.h" | ||
| 9 | |||
| 10 | namespace NWindows { | ||
| 11 | namespace NFile { | ||
| 12 | namespace NDir { | ||
| 13 | |||
| 14 | bool GetWindowsDir(FString &path); | ||
| 15 | bool GetSystemDir(FString &path); | ||
| 16 | |||
| 17 | bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); | ||
| 18 | |||
| 19 | |||
| 20 | #ifdef _WIN32 | ||
| 21 | |||
| 22 | bool SetFileAttrib(CFSTR path, DWORD attrib); | ||
| 23 | |||
| 24 | /* | ||
| 25 | Some programs store posix attributes in high 16 bits of windows attributes field. | ||
| 26 | Also some programs use additional flag markers: 0x8000 or 0x4000. | ||
| 27 | SetFileAttrib_PosixHighDetect() tries to detect posix field, and it extracts only attribute | ||
| 28 | bits that are related to current system only. | ||
| 29 | */ | ||
| 30 | |||
| 31 | #endif | ||
| 32 | |||
| 33 | bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib); | ||
| 34 | |||
| 35 | |||
| 36 | bool MyMoveFile(CFSTR existFileName, CFSTR newFileName); | ||
| 37 | |||
| 38 | #ifndef UNDER_CE | ||
| 39 | bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName); | ||
| 40 | #endif | ||
| 41 | |||
| 42 | bool RemoveDir(CFSTR path); | ||
| 43 | bool CreateDir(CFSTR path); | ||
| 44 | |||
| 45 | /* CreateComplexDir returns true, if directory can contain files after the call (two cases): | ||
| 46 | 1) the directory already exists (network shares and drive paths are supported) | ||
| 47 | 2) the directory was created | ||
| 48 | path can be WITH or WITHOUT trailing path separator. */ | ||
| 49 | |||
| 50 | bool CreateComplexDir(CFSTR path); | ||
| 51 | |||
| 52 | bool DeleteFileAlways(CFSTR name); | ||
| 53 | bool RemoveDirWithSubItems(const FString &path); | ||
| 54 | |||
| 55 | bool MyGetFullPathName(CFSTR path, FString &resFullPath); | ||
| 56 | bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); | ||
| 57 | bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix); | ||
| 58 | |||
| 59 | #ifndef UNDER_CE | ||
| 60 | |||
| 61 | bool SetCurrentDir(CFSTR path); | ||
| 62 | bool GetCurrentDir(FString &resultPath); | ||
| 63 | |||
| 64 | #endif | ||
| 65 | |||
| 66 | bool MyGetTempPath(FString &resultPath); | ||
| 67 | |||
| 68 | class CTempFile MY_UNCOPYABLE | ||
| 69 | { | ||
| 70 | bool _mustBeDeleted; | ||
| 71 | FString _path; | ||
| 72 | void DisableDeleting() { _mustBeDeleted = false; } | ||
| 73 | public: | ||
| 74 | CTempFile(): _mustBeDeleted(false) {} | ||
| 75 | ~CTempFile() { Remove(); } | ||
| 76 | const FString &GetPath() const { return _path; } | ||
| 77 | bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix | ||
| 78 | bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile); | ||
| 79 | bool Remove(); | ||
| 80 | bool MoveTo(CFSTR name, bool deleteDestBefore); | ||
| 81 | }; | ||
| 82 | |||
| 83 | |||
| 84 | #ifdef _WIN32 | ||
| 85 | class CTempDir MY_UNCOPYABLE | ||
| 86 | { | ||
| 87 | bool _mustBeDeleted; | ||
| 88 | FString _path; | ||
| 89 | public: | ||
| 90 | CTempDir(): _mustBeDeleted(false) {} | ||
| 91 | ~CTempDir() { Remove(); } | ||
| 92 | const FString &GetPath() const { return _path; } | ||
| 93 | void DisableDeleting() { _mustBeDeleted = false; } | ||
| 94 | bool Create(CFSTR namePrefix) ; | ||
| 95 | bool Remove(); | ||
| 96 | }; | ||
| 97 | #endif | ||
| 98 | |||
| 99 | |||
| 100 | #if !defined(UNDER_CE) | ||
| 101 | class CCurrentDirRestorer MY_UNCOPYABLE | ||
| 102 | { | ||
| 103 | FString _path; | ||
| 104 | public: | ||
| 105 | bool NeedRestore; | ||
| 106 | |||
| 107 | CCurrentDirRestorer(): NeedRestore(true) | ||
| 108 | { | ||
| 109 | GetCurrentDir(_path); | ||
| 110 | } | ||
| 111 | ~CCurrentDirRestorer() | ||
| 112 | { | ||
| 113 | if (!NeedRestore) | ||
| 114 | return; | ||
| 115 | FString s; | ||
| 116 | if (GetCurrentDir(s)) | ||
| 117 | if (s != _path) | ||
| 118 | SetCurrentDir(_path); | ||
| 119 | } | ||
| 120 | }; | ||
| 121 | #endif | ||
| 122 | |||
| 123 | }}} | ||
| 124 | |||
| 125 | #endif | ||
diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp new file mode 100644 index 0000000..591f8df --- /dev/null +++ b/CPP/Windows/FileFind.cpp | |||
| @@ -0,0 +1,1242 @@ | |||
| 1 | // Windows/FileFind.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | // #include <stdio.h> | ||
| 6 | |||
| 7 | #ifndef _WIN32 | ||
| 8 | #include <fcntl.h> /* Definition of AT_* constants */ | ||
| 9 | #include "TimeUtils.h" | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #include "FileFind.h" | ||
| 13 | #include "FileIO.h" | ||
| 14 | #include "FileName.h" | ||
| 15 | |||
| 16 | #ifndef _UNICODE | ||
| 17 | extern bool g_IsNT; | ||
| 18 | #endif | ||
| 19 | |||
| 20 | using namespace NWindows; | ||
| 21 | using namespace NFile; | ||
| 22 | using namespace NName; | ||
| 23 | |||
| 24 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 25 | |||
| 26 | EXTERN_C_BEGIN | ||
| 27 | |||
| 28 | typedef enum | ||
| 29 | { | ||
| 30 | My_FindStreamInfoStandard, | ||
| 31 | My_FindStreamInfoMaxInfoLevel | ||
| 32 | } MY_STREAM_INFO_LEVELS; | ||
| 33 | |||
| 34 | typedef struct | ||
| 35 | { | ||
| 36 | LARGE_INTEGER StreamSize; | ||
| 37 | WCHAR cStreamName[MAX_PATH + 36]; | ||
| 38 | } MY_WIN32_FIND_STREAM_DATA, *MY_PWIN32_FIND_STREAM_DATA; | ||
| 39 | |||
| 40 | typedef HANDLE (WINAPI *FindFirstStreamW_Ptr)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel, | ||
| 41 | LPVOID findStreamData, DWORD flags); | ||
| 42 | |||
| 43 | typedef BOOL (APIENTRY *FindNextStreamW_Ptr)(HANDLE findStream, LPVOID findStreamData); | ||
| 44 | |||
| 45 | EXTERN_C_END | ||
| 46 | |||
| 47 | #endif // defined(_WIN32) && !defined(UNDER_CE) | ||
| 48 | |||
| 49 | |||
| 50 | namespace NWindows { | ||
| 51 | namespace NFile { | ||
| 52 | |||
| 53 | |||
| 54 | #ifdef _WIN32 | ||
| 55 | #ifdef SUPPORT_DEVICE_FILE | ||
| 56 | namespace NSystem | ||
| 57 | { | ||
| 58 | bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); | ||
| 59 | } | ||
| 60 | #endif | ||
| 61 | #endif | ||
| 62 | |||
| 63 | namespace NFind { | ||
| 64 | |||
| 65 | #define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; | ||
| 66 | |||
| 67 | void CFileInfoBase::ClearBase() throw() | ||
| 68 | { | ||
| 69 | Size = 0; | ||
| 70 | MY_CLEAR_FILETIME(CTime); | ||
| 71 | MY_CLEAR_FILETIME(ATime); | ||
| 72 | MY_CLEAR_FILETIME(MTime); | ||
| 73 | Attrib = 0; | ||
| 74 | // ReparseTag = 0; | ||
| 75 | IsAltStream = false; | ||
| 76 | IsDevice = false; | ||
| 77 | |||
| 78 | #ifndef _WIN32 | ||
| 79 | ino = 0; | ||
| 80 | nlink = 0; | ||
| 81 | mode = 0; | ||
| 82 | #endif | ||
| 83 | } | ||
| 84 | |||
| 85 | bool CFileInfo::IsDots() const throw() | ||
| 86 | { | ||
| 87 | if (!IsDir() || Name.IsEmpty()) | ||
| 88 | return false; | ||
| 89 | if (Name[0] != '.') | ||
| 90 | return false; | ||
| 91 | return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == '.'); | ||
| 92 | } | ||
| 93 | |||
| 94 | |||
| 95 | #ifdef _WIN32 | ||
| 96 | |||
| 97 | |||
| 98 | #define WIN_FD_TO_MY_FI(fi, fd) \ | ||
| 99 | fi.Attrib = fd.dwFileAttributes; \ | ||
| 100 | fi.CTime = fd.ftCreationTime; \ | ||
| 101 | fi.ATime = fd.ftLastAccessTime; \ | ||
| 102 | fi.MTime = fd.ftLastWriteTime; \ | ||
| 103 | fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \ | ||
| 104 | /* fi.ReparseTag = fd.dwReserved0; */ \ | ||
| 105 | fi.IsAltStream = false; \ | ||
| 106 | fi.IsDevice = false; | ||
| 107 | |||
| 108 | /* | ||
| 109 | #ifdef UNDER_CE | ||
| 110 | fi.ObjectID = fd.dwOID; | ||
| 111 | #else | ||
| 112 | fi.ReparseTag = fd.dwReserved0; | ||
| 113 | #endif | ||
| 114 | */ | ||
| 115 | |||
| 116 | static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfo &fi) | ||
| 117 | { | ||
| 118 | WIN_FD_TO_MY_FI(fi, fd); | ||
| 119 | fi.Name = us2fs(fd.cFileName); | ||
| 120 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 121 | // fi.ShortName = us2fs(fd.cAlternateFileName); | ||
| 122 | #endif | ||
| 123 | } | ||
| 124 | |||
| 125 | #ifndef _UNICODE | ||
| 126 | static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) | ||
| 127 | { | ||
| 128 | WIN_FD_TO_MY_FI(fi, fd); | ||
| 129 | fi.Name = fas2fs(fd.cFileName); | ||
| 130 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 131 | // fi.ShortName = fas2fs(fd.cAlternateFileName); | ||
| 132 | #endif | ||
| 133 | } | ||
| 134 | #endif | ||
| 135 | |||
| 136 | //////////////////////////////// | ||
| 137 | // CFindFile | ||
| 138 | |||
| 139 | bool CFindFileBase::Close() throw() | ||
| 140 | { | ||
| 141 | if (_handle == INVALID_HANDLE_VALUE) | ||
| 142 | return true; | ||
| 143 | if (!::FindClose(_handle)) | ||
| 144 | return false; | ||
| 145 | _handle = INVALID_HANDLE_VALUE; | ||
| 146 | return true; | ||
| 147 | } | ||
| 148 | |||
| 149 | /* | ||
| 150 | WinXP-64 FindFirstFile(): | ||
| 151 | "" - ERROR_PATH_NOT_FOUND | ||
| 152 | folder\ - ERROR_FILE_NOT_FOUND | ||
| 153 | \ - ERROR_FILE_NOT_FOUND | ||
| 154 | c:\ - ERROR_FILE_NOT_FOUND | ||
| 155 | c: - ERROR_FILE_NOT_FOUND, if current dir is ROOT ( c:\ ) | ||
| 156 | c: - OK, if current dir is NOT ROOT ( c:\folder ) | ||
| 157 | folder - OK | ||
| 158 | |||
| 159 | \\ - ERROR_INVALID_NAME | ||
| 160 | \\Server - ERROR_INVALID_NAME | ||
| 161 | \\Server\ - ERROR_INVALID_NAME | ||
| 162 | |||
| 163 | \\Server\Share - ERROR_BAD_NETPATH | ||
| 164 | \\Server\Share - ERROR_BAD_NET_NAME (Win7). | ||
| 165 | !!! There is problem : Win7 makes some requests for "\\Server\Shar" (look in Procmon), | ||
| 166 | when we call it for "\\Server\Share" | ||
| 167 | |||
| 168 | \\Server\Share\ - ERROR_FILE_NOT_FOUND | ||
| 169 | |||
| 170 | \\?\UNC\Server\Share - ERROR_INVALID_NAME | ||
| 171 | \\?\UNC\Server\Share - ERROR_BAD_PATHNAME (Win7) | ||
| 172 | \\?\UNC\Server\Share\ - ERROR_FILE_NOT_FOUND | ||
| 173 | |||
| 174 | \\Server\Share_RootDrive - ERROR_INVALID_NAME | ||
| 175 | \\Server\Share_RootDrive\ - ERROR_INVALID_NAME | ||
| 176 | |||
| 177 | e:\* - ERROR_FILE_NOT_FOUND, if there are no items in that root folder | ||
| 178 | w:\* - ERROR_PATH_NOT_FOUND, if there is no such drive w: | ||
| 179 | */ | ||
| 180 | |||
| 181 | bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi) | ||
| 182 | { | ||
| 183 | if (!Close()) | ||
| 184 | return false; | ||
| 185 | #ifndef _UNICODE | ||
| 186 | if (!g_IsNT) | ||
| 187 | { | ||
| 188 | WIN32_FIND_DATAA fd; | ||
| 189 | _handle = ::FindFirstFileA(fs2fas(path), &fd); | ||
| 190 | if (_handle == INVALID_HANDLE_VALUE) | ||
| 191 | return false; | ||
| 192 | Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); | ||
| 193 | } | ||
| 194 | else | ||
| 195 | #endif | ||
| 196 | { | ||
| 197 | WIN32_FIND_DATAW fd; | ||
| 198 | |||
| 199 | IF_USE_MAIN_PATH | ||
| 200 | _handle = ::FindFirstFileW(fs2us(path), &fd); | ||
| 201 | #ifdef WIN_LONG_PATH | ||
| 202 | if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH) | ||
| 203 | { | ||
| 204 | UString superPath; | ||
| 205 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 206 | _handle = ::FindFirstFileW(superPath, &fd); | ||
| 207 | } | ||
| 208 | #endif | ||
| 209 | if (_handle == INVALID_HANDLE_VALUE) | ||
| 210 | return false; | ||
| 211 | Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); | ||
| 212 | } | ||
| 213 | return true; | ||
| 214 | } | ||
| 215 | |||
| 216 | bool CFindFile::FindNext(CFileInfo &fi) | ||
| 217 | { | ||
| 218 | #ifndef _UNICODE | ||
| 219 | if (!g_IsNT) | ||
| 220 | { | ||
| 221 | WIN32_FIND_DATAA fd; | ||
| 222 | if (!::FindNextFileA(_handle, &fd)) | ||
| 223 | return false; | ||
| 224 | Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); | ||
| 225 | } | ||
| 226 | else | ||
| 227 | #endif | ||
| 228 | { | ||
| 229 | WIN32_FIND_DATAW fd; | ||
| 230 | if (!::FindNextFileW(_handle, &fd)) | ||
| 231 | return false; | ||
| 232 | Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); | ||
| 233 | } | ||
| 234 | return true; | ||
| 235 | } | ||
| 236 | |||
| 237 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 238 | |||
| 239 | //////////////////////////////// | ||
| 240 | // AltStreams | ||
| 241 | |||
| 242 | static FindFirstStreamW_Ptr g_FindFirstStreamW; | ||
| 243 | static FindNextStreamW_Ptr g_FindNextStreamW; | ||
| 244 | |||
| 245 | static struct CFindStreamLoader | ||
| 246 | { | ||
| 247 | CFindStreamLoader() | ||
| 248 | { | ||
| 249 | HMODULE hm = ::GetModuleHandleA("kernel32.dll"); | ||
| 250 | g_FindFirstStreamW = (FindFirstStreamW_Ptr)(void *)::GetProcAddress(hm, "FindFirstStreamW"); | ||
| 251 | g_FindNextStreamW = (FindNextStreamW_Ptr)(void *)::GetProcAddress(hm, "FindNextStreamW"); | ||
| 252 | } | ||
| 253 | } g_FindStreamLoader; | ||
| 254 | |||
| 255 | bool CStreamInfo::IsMainStream() const throw() | ||
| 256 | { | ||
| 257 | return StringsAreEqualNoCase_Ascii(Name, "::$DATA"); | ||
| 258 | }; | ||
| 259 | |||
| 260 | UString CStreamInfo::GetReducedName() const | ||
| 261 | { | ||
| 262 | // remove ":$DATA" postfix, but keep postfix, if Name is "::$DATA" | ||
| 263 | UString s (Name); | ||
| 264 | if (s.Len() > 6 + 1 && StringsAreEqualNoCase_Ascii(s.RightPtr(6), ":$DATA")) | ||
| 265 | s.DeleteFrom(s.Len() - 6); | ||
| 266 | return s; | ||
| 267 | } | ||
| 268 | |||
| 269 | /* | ||
| 270 | UString CStreamInfo::GetReducedName2() const | ||
| 271 | { | ||
| 272 | UString s = GetReducedName(); | ||
| 273 | if (!s.IsEmpty() && s[0] == ':') | ||
| 274 | s.Delete(0); | ||
| 275 | return s; | ||
| 276 | } | ||
| 277 | */ | ||
| 278 | |||
| 279 | static void Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(const MY_WIN32_FIND_STREAM_DATA &sd, CStreamInfo &si) | ||
| 280 | { | ||
| 281 | si.Size = (UInt64)sd.StreamSize.QuadPart; | ||
| 282 | si.Name = sd.cStreamName; | ||
| 283 | } | ||
| 284 | |||
| 285 | /* | ||
| 286 | WinXP-64 FindFirstStream(): | ||
| 287 | "" - ERROR_PATH_NOT_FOUND | ||
| 288 | folder\ - OK | ||
| 289 | folder - OK | ||
| 290 | \ - OK | ||
| 291 | c:\ - OK | ||
| 292 | c: - OK, if current dir is ROOT ( c:\ ) | ||
| 293 | c: - OK, if current dir is NOT ROOT ( c:\folder ) | ||
| 294 | \\Server\Share - OK | ||
| 295 | \\Server\Share\ - OK | ||
| 296 | |||
| 297 | \\ - ERROR_INVALID_NAME | ||
| 298 | \\Server - ERROR_INVALID_NAME | ||
| 299 | \\Server\ - ERROR_INVALID_NAME | ||
| 300 | */ | ||
| 301 | |||
| 302 | bool CFindStream::FindFirst(CFSTR path, CStreamInfo &si) | ||
| 303 | { | ||
| 304 | if (!Close()) | ||
| 305 | return false; | ||
| 306 | if (!g_FindFirstStreamW) | ||
| 307 | { | ||
| 308 | ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | ||
| 309 | return false; | ||
| 310 | } | ||
| 311 | { | ||
| 312 | MY_WIN32_FIND_STREAM_DATA sd; | ||
| 313 | SetLastError(0); | ||
| 314 | IF_USE_MAIN_PATH | ||
| 315 | _handle = g_FindFirstStreamW(fs2us(path), My_FindStreamInfoStandard, &sd, 0); | ||
| 316 | if (_handle == INVALID_HANDLE_VALUE) | ||
| 317 | { | ||
| 318 | if (::GetLastError() == ERROR_HANDLE_EOF) | ||
| 319 | return false; | ||
| 320 | // long name can be tricky for path like ".\dirName". | ||
| 321 | #ifdef WIN_LONG_PATH | ||
| 322 | if (USE_SUPER_PATH) | ||
| 323 | { | ||
| 324 | UString superPath; | ||
| 325 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 326 | _handle = g_FindFirstStreamW(superPath, My_FindStreamInfoStandard, &sd, 0); | ||
| 327 | } | ||
| 328 | #endif | ||
| 329 | } | ||
| 330 | if (_handle == INVALID_HANDLE_VALUE) | ||
| 331 | return false; | ||
| 332 | Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si); | ||
| 333 | } | ||
| 334 | return true; | ||
| 335 | } | ||
| 336 | |||
| 337 | bool CFindStream::FindNext(CStreamInfo &si) | ||
| 338 | { | ||
| 339 | if (!g_FindNextStreamW) | ||
| 340 | { | ||
| 341 | ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | ||
| 342 | return false; | ||
| 343 | } | ||
| 344 | { | ||
| 345 | MY_WIN32_FIND_STREAM_DATA sd; | ||
| 346 | if (!g_FindNextStreamW(_handle, &sd)) | ||
| 347 | return false; | ||
| 348 | Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si); | ||
| 349 | } | ||
| 350 | return true; | ||
| 351 | } | ||
| 352 | |||
| 353 | bool CStreamEnumerator::Next(CStreamInfo &si, bool &found) | ||
| 354 | { | ||
| 355 | bool res; | ||
| 356 | if (_find.IsHandleAllocated()) | ||
| 357 | res = _find.FindNext(si); | ||
| 358 | else | ||
| 359 | res = _find.FindFirst(_filePath, si); | ||
| 360 | if (res) | ||
| 361 | { | ||
| 362 | found = true; | ||
| 363 | return true; | ||
| 364 | } | ||
| 365 | found = false; | ||
| 366 | return (::GetLastError() == ERROR_HANDLE_EOF); | ||
| 367 | } | ||
| 368 | |||
| 369 | #endif | ||
| 370 | |||
| 371 | |||
| 372 | /* | ||
| 373 | WinXP-64 GetFileAttributes(): | ||
| 374 | If the function fails, it returns INVALID_FILE_ATTRIBUTES and use GetLastError() to get error code | ||
| 375 | |||
| 376 | \ - OK | ||
| 377 | C:\ - OK, if there is such drive, | ||
| 378 | D:\ - ERROR_PATH_NOT_FOUND, if there is no such drive, | ||
| 379 | |||
| 380 | C:\folder - OK | ||
| 381 | C:\folder\ - OK | ||
| 382 | C:\folderBad - ERROR_FILE_NOT_FOUND | ||
| 383 | |||
| 384 | \\Server\BadShare - ERROR_BAD_NETPATH | ||
| 385 | \\Server\Share - WORKS OK, but MSDN says: | ||
| 386 | GetFileAttributes for a network share, the function fails, and GetLastError | ||
| 387 | returns ERROR_BAD_NETPATH. You must specify a path to a subfolder on that share. | ||
| 388 | */ | ||
| 389 | |||
| 390 | DWORD GetFileAttrib(CFSTR path) | ||
| 391 | { | ||
| 392 | #ifndef _UNICODE | ||
| 393 | if (!g_IsNT) | ||
| 394 | return ::GetFileAttributes(fs2fas(path)); | ||
| 395 | else | ||
| 396 | #endif | ||
| 397 | { | ||
| 398 | IF_USE_MAIN_PATH | ||
| 399 | { | ||
| 400 | DWORD dw = ::GetFileAttributesW(fs2us(path)); | ||
| 401 | if (dw != INVALID_FILE_ATTRIBUTES) | ||
| 402 | return dw; | ||
| 403 | } | ||
| 404 | #ifdef WIN_LONG_PATH | ||
| 405 | if (USE_SUPER_PATH) | ||
| 406 | { | ||
| 407 | UString superPath; | ||
| 408 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 409 | return ::GetFileAttributesW(superPath); | ||
| 410 | } | ||
| 411 | #endif | ||
| 412 | return INVALID_FILE_ATTRIBUTES; | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | /* if path is "c:" or "c::" then CFileInfo::Find() returns name of current folder for that disk | ||
| 417 | so instead of absolute path we have relative path in Name. That is not good in some calls */ | ||
| 418 | |||
| 419 | /* In CFileInfo::Find() we want to support same names for alt streams as in CreateFile(). */ | ||
| 420 | |||
| 421 | /* CFileInfo::Find() | ||
| 422 | We alow the following paths (as FindFirstFile): | ||
| 423 | C:\folder | ||
| 424 | c: - if current dir is NOT ROOT ( c:\folder ) | ||
| 425 | |||
| 426 | also we support paths that are not supported by FindFirstFile: | ||
| 427 | \ | ||
| 428 | \\.\c: | ||
| 429 | c:\ - Name will be without tail slash ( c: ) | ||
| 430 | \\?\c:\ - Name will be without tail slash ( c: ) | ||
| 431 | \\Server\Share | ||
| 432 | \\?\UNC\Server\Share | ||
| 433 | |||
| 434 | c:\folder:stream - Name = folder:stream | ||
| 435 | c:\:stream - Name = :stream | ||
| 436 | c::stream - Name = c::stream | ||
| 437 | */ | ||
| 438 | |||
| 439 | bool CFileInfo::Find(CFSTR path, bool followLink) | ||
| 440 | { | ||
| 441 | #ifdef SUPPORT_DEVICE_FILE | ||
| 442 | if (IsDevicePath(path)) | ||
| 443 | { | ||
| 444 | ClearBase(); | ||
| 445 | Name = path + 4; | ||
| 446 | IsDevice = true; | ||
| 447 | |||
| 448 | if (NName::IsDrivePath2(path + 4) && path[6] == 0) | ||
| 449 | { | ||
| 450 | FChar drive[4] = { path[4], ':', '\\', 0 }; | ||
| 451 | UInt64 clusterSize, totalSize, freeSize; | ||
| 452 | if (NSystem::MyGetDiskFreeSpace(drive, clusterSize, totalSize, freeSize)) | ||
| 453 | { | ||
| 454 | Size = totalSize; | ||
| 455 | return true; | ||
| 456 | } | ||
| 457 | } | ||
| 458 | |||
| 459 | NIO::CInFile inFile; | ||
| 460 | // ::OutputDebugStringW(path); | ||
| 461 | if (!inFile.Open(path)) | ||
| 462 | return false; | ||
| 463 | // ::OutputDebugStringW(L"---"); | ||
| 464 | if (inFile.SizeDefined) | ||
| 465 | Size = inFile.Size; | ||
| 466 | return true; | ||
| 467 | } | ||
| 468 | #endif | ||
| 469 | |||
| 470 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 471 | |||
| 472 | int colonPos = FindAltStreamColon(path); | ||
| 473 | if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0) | ||
| 474 | { | ||
| 475 | UString streamName = fs2us(path + (unsigned)colonPos); | ||
| 476 | FString filePath (path); | ||
| 477 | filePath.DeleteFrom((unsigned)colonPos); | ||
| 478 | /* we allow both cases: | ||
| 479 | name:stream | ||
| 480 | name:stream:$DATA | ||
| 481 | */ | ||
| 482 | const unsigned kPostfixSize = 6; | ||
| 483 | if (streamName.Len() <= kPostfixSize | ||
| 484 | || !StringsAreEqualNoCase_Ascii(streamName.RightPtr(kPostfixSize), ":$DATA")) | ||
| 485 | streamName += ":$DATA"; | ||
| 486 | |||
| 487 | bool isOk = true; | ||
| 488 | |||
| 489 | if (IsDrivePath2(filePath) && | ||
| 490 | (colonPos == 2 || (colonPos == 3 && filePath[2] == '\\'))) | ||
| 491 | { | ||
| 492 | // FindFirstFile doesn't work for "c:\" and for "c:" (if current dir is ROOT) | ||
| 493 | ClearBase(); | ||
| 494 | Name.Empty(); | ||
| 495 | if (colonPos == 2) | ||
| 496 | Name = filePath; | ||
| 497 | } | ||
| 498 | else | ||
| 499 | isOk = Find(filePath, followLink); // check it (followLink) | ||
| 500 | |||
| 501 | if (isOk) | ||
| 502 | { | ||
| 503 | Attrib &= ~(DWORD)(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); | ||
| 504 | Size = 0; | ||
| 505 | CStreamEnumerator enumerator(filePath); | ||
| 506 | for (;;) | ||
| 507 | { | ||
| 508 | CStreamInfo si; | ||
| 509 | bool found; | ||
| 510 | if (!enumerator.Next(si, found)) | ||
| 511 | return false; | ||
| 512 | if (!found) | ||
| 513 | { | ||
| 514 | ::SetLastError(ERROR_FILE_NOT_FOUND); | ||
| 515 | return false; | ||
| 516 | } | ||
| 517 | if (si.Name.IsEqualTo_NoCase(streamName)) | ||
| 518 | { | ||
| 519 | // we delete postfix, if alt stream name is not "::$DATA" | ||
| 520 | if (si.Name.Len() > kPostfixSize + 1) | ||
| 521 | si.Name.DeleteFrom(si.Name.Len() - kPostfixSize); | ||
| 522 | Name += us2fs(si.Name); | ||
| 523 | Size = si.Size; | ||
| 524 | IsAltStream = true; | ||
| 525 | return true; | ||
| 526 | } | ||
| 527 | } | ||
| 528 | } | ||
| 529 | } | ||
| 530 | |||
| 531 | #endif | ||
| 532 | |||
| 533 | CFindFile finder; | ||
| 534 | |||
| 535 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 536 | { | ||
| 537 | /* | ||
| 538 | DWORD lastError = GetLastError(); | ||
| 539 | if (lastError == ERROR_FILE_NOT_FOUND | ||
| 540 | || lastError == ERROR_BAD_NETPATH // XP64: "\\Server\Share" | ||
| 541 | || lastError == ERROR_BAD_NET_NAME // Win7: "\\Server\Share" | ||
| 542 | || lastError == ERROR_INVALID_NAME // XP64: "\\?\UNC\Server\Share" | ||
| 543 | || lastError == ERROR_BAD_PATHNAME // Win7: "\\?\UNC\Server\Share" | ||
| 544 | ) | ||
| 545 | */ | ||
| 546 | |||
| 547 | unsigned rootSize = 0; | ||
| 548 | if (IsSuperPath(path)) | ||
| 549 | rootSize = kSuperPathPrefixSize; | ||
| 550 | |||
| 551 | if (NName::IsDrivePath(path + rootSize) && path[rootSize + 3] == 0) | ||
| 552 | { | ||
| 553 | DWORD attrib = GetFileAttrib(path); | ||
| 554 | if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) | ||
| 555 | { | ||
| 556 | ClearBase(); | ||
| 557 | Attrib = attrib; | ||
| 558 | Name = path + rootSize; | ||
| 559 | Name.DeleteFrom(2); | ||
| 560 | if (!Fill_From_ByHandleFileInfo(path)) | ||
| 561 | { | ||
| 562 | } | ||
| 563 | return true; | ||
| 564 | } | ||
| 565 | } | ||
| 566 | else if (IS_PATH_SEPAR(path[0])) | ||
| 567 | { | ||
| 568 | if (path[1] == 0) | ||
| 569 | { | ||
| 570 | DWORD attrib = GetFileAttrib(path); | ||
| 571 | if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) | ||
| 572 | { | ||
| 573 | ClearBase(); | ||
| 574 | Name.Empty(); | ||
| 575 | Attrib = attrib; | ||
| 576 | return true; | ||
| 577 | } | ||
| 578 | } | ||
| 579 | else | ||
| 580 | { | ||
| 581 | const unsigned prefixSize = GetNetworkServerPrefixSize(path); | ||
| 582 | if (prefixSize > 0 && path[prefixSize] != 0) | ||
| 583 | { | ||
| 584 | if (NName::FindSepar(path + prefixSize) < 0) | ||
| 585 | { | ||
| 586 | if (Fill_From_ByHandleFileInfo(path)) | ||
| 587 | { | ||
| 588 | Name = path + prefixSize; | ||
| 589 | return true; | ||
| 590 | } | ||
| 591 | |||
| 592 | FString s (path); | ||
| 593 | s.Add_PathSepar(); | ||
| 594 | s += '*'; // CHAR_ANY_MASK | ||
| 595 | bool isOK = false; | ||
| 596 | if (finder.FindFirst(s, *this)) | ||
| 597 | { | ||
| 598 | if (Name == FTEXT(".")) | ||
| 599 | { | ||
| 600 | Name = path + prefixSize; | ||
| 601 | return true; | ||
| 602 | } | ||
| 603 | isOK = true; | ||
| 604 | /* if "\\server\share" maps to root folder "d:\", there is no "." item. | ||
| 605 | But it's possible that there are another items */ | ||
| 606 | } | ||
| 607 | { | ||
| 608 | DWORD attrib = GetFileAttrib(path); | ||
| 609 | if (isOK || (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)) | ||
| 610 | { | ||
| 611 | ClearBase(); | ||
| 612 | if (attrib != INVALID_FILE_ATTRIBUTES) | ||
| 613 | Attrib = attrib; | ||
| 614 | else | ||
| 615 | SetAsDir(); | ||
| 616 | Name = path + prefixSize; | ||
| 617 | return true; | ||
| 618 | } | ||
| 619 | } | ||
| 620 | // ::SetLastError(lastError); | ||
| 621 | } | ||
| 622 | } | ||
| 623 | } | ||
| 624 | } | ||
| 625 | } | ||
| 626 | #endif | ||
| 627 | |||
| 628 | bool res = finder.FindFirst(path, *this); | ||
| 629 | if (!followLink | ||
| 630 | || !res | ||
| 631 | || !HasReparsePoint()) | ||
| 632 | return res; | ||
| 633 | |||
| 634 | // return FollowReparse(path, IsDir()); | ||
| 635 | return Fill_From_ByHandleFileInfo(path); | ||
| 636 | } | ||
| 637 | |||
| 638 | bool CFileInfo::Fill_From_ByHandleFileInfo(CFSTR path) | ||
| 639 | { | ||
| 640 | BY_HANDLE_FILE_INFORMATION info; | ||
| 641 | if (!NIO::CFileBase::GetFileInformation(path, &info)) | ||
| 642 | return false; | ||
| 643 | { | ||
| 644 | Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; | ||
| 645 | CTime = info.ftCreationTime; | ||
| 646 | ATime = info.ftLastAccessTime; | ||
| 647 | MTime = info.ftLastWriteTime; | ||
| 648 | Attrib = info.dwFileAttributes; | ||
| 649 | return true; | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | /* | ||
| 654 | bool CFileInfo::FollowReparse(CFSTR path, bool isDir) | ||
| 655 | { | ||
| 656 | if (isDir) | ||
| 657 | { | ||
| 658 | FString prefix = path; | ||
| 659 | prefix.Add_PathSepar(); | ||
| 660 | |||
| 661 | // "folder/." refers to folder itself. So we can't use that path | ||
| 662 | // we must use enumerator and search "." item | ||
| 663 | CEnumerator enumerator; | ||
| 664 | enumerator.SetDirPrefix(prefix); | ||
| 665 | for (;;) | ||
| 666 | { | ||
| 667 | CFileInfo fi; | ||
| 668 | if (!enumerator.NextAny(fi)) | ||
| 669 | break; | ||
| 670 | if (fi.Name.IsEqualTo_Ascii_NoCase(".")) | ||
| 671 | { | ||
| 672 | // we can copy preperies; | ||
| 673 | CTime = fi.CTime; | ||
| 674 | ATime = fi.ATime; | ||
| 675 | MTime = fi.MTime; | ||
| 676 | Attrib = fi.Attrib; | ||
| 677 | Size = fi.Size; | ||
| 678 | return true; | ||
| 679 | } | ||
| 680 | break; | ||
| 681 | } | ||
| 682 | // LastError(lastError); | ||
| 683 | return false; | ||
| 684 | } | ||
| 685 | |||
| 686 | { | ||
| 687 | NIO::CInFile inFile; | ||
| 688 | if (inFile.Open(path)) | ||
| 689 | { | ||
| 690 | BY_HANDLE_FILE_INFORMATION info; | ||
| 691 | if (inFile.GetFileInformation(&info)) | ||
| 692 | { | ||
| 693 | ClearBase(); | ||
| 694 | Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; | ||
| 695 | CTime = info.ftCreationTime; | ||
| 696 | ATime = info.ftLastAccessTime; | ||
| 697 | MTime = info.ftLastWriteTime; | ||
| 698 | Attrib = info.dwFileAttributes; | ||
| 699 | return true; | ||
| 700 | } | ||
| 701 | } | ||
| 702 | return false; | ||
| 703 | } | ||
| 704 | } | ||
| 705 | */ | ||
| 706 | |||
| 707 | bool DoesFileExist_Raw(CFSTR name) | ||
| 708 | { | ||
| 709 | CFileInfo fi; | ||
| 710 | return fi.Find(name) && !fi.IsDir(); | ||
| 711 | } | ||
| 712 | |||
| 713 | bool DoesFileExist_FollowLink(CFSTR name) | ||
| 714 | { | ||
| 715 | CFileInfo fi; | ||
| 716 | return fi.Find_FollowLink(name) && !fi.IsDir(); | ||
| 717 | } | ||
| 718 | |||
| 719 | bool DoesDirExist(CFSTR name, bool followLink) | ||
| 720 | { | ||
| 721 | CFileInfo fi; | ||
| 722 | return fi.Find(name, followLink) && fi.IsDir(); | ||
| 723 | } | ||
| 724 | |||
| 725 | bool DoesFileOrDirExist(CFSTR name) | ||
| 726 | { | ||
| 727 | CFileInfo fi; | ||
| 728 | return fi.Find(name); | ||
| 729 | } | ||
| 730 | |||
| 731 | |||
| 732 | void CEnumerator::SetDirPrefix(const FString &dirPrefix) | ||
| 733 | { | ||
| 734 | _wildcard = dirPrefix; | ||
| 735 | _wildcard += '*'; | ||
| 736 | } | ||
| 737 | |||
| 738 | bool CEnumerator::NextAny(CFileInfo &fi) | ||
| 739 | { | ||
| 740 | if (_findFile.IsHandleAllocated()) | ||
| 741 | return _findFile.FindNext(fi); | ||
| 742 | else | ||
| 743 | return _findFile.FindFirst(_wildcard, fi); | ||
| 744 | } | ||
| 745 | |||
| 746 | bool CEnumerator::Next(CFileInfo &fi) | ||
| 747 | { | ||
| 748 | for (;;) | ||
| 749 | { | ||
| 750 | if (!NextAny(fi)) | ||
| 751 | return false; | ||
| 752 | if (!fi.IsDots()) | ||
| 753 | return true; | ||
| 754 | } | ||
| 755 | } | ||
| 756 | |||
| 757 | bool CEnumerator::Next(CFileInfo &fi, bool &found) | ||
| 758 | { | ||
| 759 | /* | ||
| 760 | for (;;) | ||
| 761 | { | ||
| 762 | if (!NextAny(fi)) | ||
| 763 | break; | ||
| 764 | if (!fi.IsDots()) | ||
| 765 | { | ||
| 766 | found = true; | ||
| 767 | return true; | ||
| 768 | } | ||
| 769 | } | ||
| 770 | */ | ||
| 771 | |||
| 772 | if (Next(fi)) | ||
| 773 | { | ||
| 774 | found = true; | ||
| 775 | return true; | ||
| 776 | } | ||
| 777 | |||
| 778 | found = false; | ||
| 779 | DWORD lastError = ::GetLastError(); | ||
| 780 | if (_findFile.IsHandleAllocated()) | ||
| 781 | return (lastError == ERROR_NO_MORE_FILES); | ||
| 782 | // we support the case for empty root folder: FindFirstFile("c:\\*") returns ERROR_FILE_NOT_FOUND | ||
| 783 | if (lastError == ERROR_FILE_NOT_FOUND) | ||
| 784 | return true; | ||
| 785 | if (lastError == ERROR_ACCESS_DENIED) | ||
| 786 | { | ||
| 787 | // here we show inaccessible root system folder as empty folder to eliminate redundant user warnings | ||
| 788 | const char *s = "System Volume Information" STRING_PATH_SEPARATOR "*"; | ||
| 789 | const int len = (int)strlen(s); | ||
| 790 | const int delta = (int)_wildcard.Len() - len; | ||
| 791 | if (delta == 0 || (delta > 0 && IS_PATH_SEPAR(_wildcard[(unsigned)delta - 1]))) | ||
| 792 | if (StringsAreEqual_Ascii(_wildcard.Ptr((unsigned)delta), s)) | ||
| 793 | return true; | ||
| 794 | } | ||
| 795 | return false; | ||
| 796 | } | ||
| 797 | |||
| 798 | |||
| 799 | //////////////////////////////// | ||
| 800 | // CFindChangeNotification | ||
| 801 | // FindFirstChangeNotification can return 0. MSDN doesn't tell about it. | ||
| 802 | |||
| 803 | bool CFindChangeNotification::Close() throw() | ||
| 804 | { | ||
| 805 | if (!IsHandleAllocated()) | ||
| 806 | return true; | ||
| 807 | if (!::FindCloseChangeNotification(_handle)) | ||
| 808 | return false; | ||
| 809 | _handle = INVALID_HANDLE_VALUE; | ||
| 810 | return true; | ||
| 811 | } | ||
| 812 | |||
| 813 | HANDLE CFindChangeNotification::FindFirst(CFSTR path, bool watchSubtree, DWORD notifyFilter) | ||
| 814 | { | ||
| 815 | #ifndef _UNICODE | ||
| 816 | if (!g_IsNT) | ||
| 817 | _handle = ::FindFirstChangeNotification(fs2fas(path), BoolToBOOL(watchSubtree), notifyFilter); | ||
| 818 | else | ||
| 819 | #endif | ||
| 820 | { | ||
| 821 | IF_USE_MAIN_PATH | ||
| 822 | _handle = ::FindFirstChangeNotificationW(fs2us(path), BoolToBOOL(watchSubtree), notifyFilter); | ||
| 823 | #ifdef WIN_LONG_PATH | ||
| 824 | if (!IsHandleAllocated()) | ||
| 825 | { | ||
| 826 | UString superPath; | ||
| 827 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 828 | _handle = ::FindFirstChangeNotificationW(superPath, BoolToBOOL(watchSubtree), notifyFilter); | ||
| 829 | } | ||
| 830 | #endif | ||
| 831 | } | ||
| 832 | return _handle; | ||
| 833 | } | ||
| 834 | |||
| 835 | #ifndef UNDER_CE | ||
| 836 | |||
| 837 | bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings) | ||
| 838 | { | ||
| 839 | driveStrings.Clear(); | ||
| 840 | #ifndef _UNICODE | ||
| 841 | if (!g_IsNT) | ||
| 842 | { | ||
| 843 | driveStrings.Clear(); | ||
| 844 | UINT32 size = GetLogicalDriveStrings(0, NULL); | ||
| 845 | if (size == 0) | ||
| 846 | return false; | ||
| 847 | CObjArray<char> buf(size); | ||
| 848 | UINT32 newSize = GetLogicalDriveStrings(size, buf); | ||
| 849 | if (newSize == 0 || newSize > size) | ||
| 850 | return false; | ||
| 851 | AString s; | ||
| 852 | UINT32 prev = 0; | ||
| 853 | for (UINT32 i = 0; i < newSize; i++) | ||
| 854 | { | ||
| 855 | if (buf[i] == 0) | ||
| 856 | { | ||
| 857 | s = buf + prev; | ||
| 858 | prev = i + 1; | ||
| 859 | driveStrings.Add(fas2fs(s)); | ||
| 860 | } | ||
| 861 | } | ||
| 862 | return prev == newSize; | ||
| 863 | } | ||
| 864 | else | ||
| 865 | #endif | ||
| 866 | { | ||
| 867 | UINT32 size = GetLogicalDriveStringsW(0, NULL); | ||
| 868 | if (size == 0) | ||
| 869 | return false; | ||
| 870 | CObjArray<wchar_t> buf(size); | ||
| 871 | UINT32 newSize = GetLogicalDriveStringsW(size, buf); | ||
| 872 | if (newSize == 0 || newSize > size) | ||
| 873 | return false; | ||
| 874 | UString s; | ||
| 875 | UINT32 prev = 0; | ||
| 876 | for (UINT32 i = 0; i < newSize; i++) | ||
| 877 | { | ||
| 878 | if (buf[i] == 0) | ||
| 879 | { | ||
| 880 | s = buf + prev; | ||
| 881 | prev = i + 1; | ||
| 882 | driveStrings.Add(us2fs(s)); | ||
| 883 | } | ||
| 884 | } | ||
| 885 | return prev == newSize; | ||
| 886 | } | ||
| 887 | } | ||
| 888 | |||
| 889 | #endif // UNDER_CE | ||
| 890 | |||
| 891 | |||
| 892 | |||
| 893 | #else // _WIN32 | ||
| 894 | |||
| 895 | // ---------- POSIX ---------- | ||
| 896 | |||
| 897 | static int MY__lstat(CFSTR path, struct stat *st, bool followLink) | ||
| 898 | { | ||
| 899 | memset(st, 0, sizeof(*st)); | ||
| 900 | int res; | ||
| 901 | // #ifdef ENV_HAVE_LSTAT | ||
| 902 | if (/* global_use_lstat && */ !followLink) | ||
| 903 | { | ||
| 904 | // printf("\nlstat\n"); | ||
| 905 | res = lstat(path, st); | ||
| 906 | } | ||
| 907 | else | ||
| 908 | // #endif | ||
| 909 | { | ||
| 910 | // printf("\nstat\n"); | ||
| 911 | res = stat(path, st); | ||
| 912 | } | ||
| 913 | /* | ||
| 914 | printf("\nres = %d\n", res); | ||
| 915 | printf("\n st_dev = %lld \n", (long long)(st->st_dev)); | ||
| 916 | printf("\n st_ino = %lld \n", (long long)(st->st_ino)); | ||
| 917 | printf("\n st_mode = %lld \n", (long long)(st->st_mode)); | ||
| 918 | printf("\n st_nlink = %lld \n", (long long)(st->st_nlink)); | ||
| 919 | printf("\n st_uid = %lld \n", (long long)(st->st_uid)); | ||
| 920 | printf("\n st_gid = %lld \n", (long long)(st->st_gid)); | ||
| 921 | printf("\n st_size = %lld \n", (long long)(st->st_size)); | ||
| 922 | printf("\n st_blksize = %lld \n", (long long)(st->st_blksize)); | ||
| 923 | printf("\n st_blocks = %lld \n", (long long)(st->st_blocks)); | ||
| 924 | */ | ||
| 925 | |||
| 926 | return res; | ||
| 927 | } | ||
| 928 | |||
| 929 | |||
| 930 | static const char *Get_Name_from_Path(CFSTR path) throw() | ||
| 931 | { | ||
| 932 | size_t len = strlen(path); | ||
| 933 | if (len == 0) | ||
| 934 | return path; | ||
| 935 | const char *p = path + len - 1; | ||
| 936 | { | ||
| 937 | if (p == path) | ||
| 938 | return path; | ||
| 939 | p--; | ||
| 940 | } | ||
| 941 | for (;;) | ||
| 942 | { | ||
| 943 | char c = *p; | ||
| 944 | if (IS_PATH_SEPAR(c)) | ||
| 945 | return p + 1; | ||
| 946 | if (p == path) | ||
| 947 | return path; | ||
| 948 | p--; | ||
| 949 | } | ||
| 950 | } | ||
| 951 | |||
| 952 | |||
| 953 | void timespec_To_FILETIME(const MY_ST_TIMESPEC &ts, FILETIME &ft) | ||
| 954 | { | ||
| 955 | UInt64 v = NTime::UnixTime64ToFileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); | ||
| 956 | ft.dwLowDateTime = (DWORD)v; | ||
| 957 | ft.dwHighDateTime = (DWORD)(v >> 32); | ||
| 958 | } | ||
| 959 | |||
| 960 | UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode) | ||
| 961 | { | ||
| 962 | UInt32 attrib = S_ISDIR(mode) ? | ||
| 963 | FILE_ATTRIBUTE_DIRECTORY : | ||
| 964 | FILE_ATTRIBUTE_ARCHIVE; | ||
| 965 | if ((mode & 0222) == 0) // S_IWUSR in p7zip | ||
| 966 | attrib |= FILE_ATTRIBUTE_READONLY; | ||
| 967 | return attrib | FILE_ATTRIBUTE_UNIX_EXTENSION | ((mode & 0xFFFF) << 16); | ||
| 968 | } | ||
| 969 | |||
| 970 | /* | ||
| 971 | UInt32 Get_WinAttrib_From_stat(const struct stat &st) | ||
| 972 | { | ||
| 973 | UInt32 attrib = S_ISDIR(st.st_mode) ? | ||
| 974 | FILE_ATTRIBUTE_DIRECTORY : | ||
| 975 | FILE_ATTRIBUTE_ARCHIVE; | ||
| 976 | |||
| 977 | if ((st.st_mode & 0222) == 0) // check it !!! | ||
| 978 | attrib |= FILE_ATTRIBUTE_READONLY; | ||
| 979 | |||
| 980 | attrib |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((st.st_mode & 0xFFFF) << 16); | ||
| 981 | return attrib; | ||
| 982 | } | ||
| 983 | */ | ||
| 984 | |||
| 985 | void CFileInfo::SetFrom_stat(const struct stat &st) | ||
| 986 | { | ||
| 987 | IsDevice = false; | ||
| 988 | |||
| 989 | if (S_ISDIR(st.st_mode)) | ||
| 990 | { | ||
| 991 | Size = 0; | ||
| 992 | } | ||
| 993 | else | ||
| 994 | { | ||
| 995 | Size = (UInt64)st.st_size; // for a symbolic link, size = size of filename | ||
| 996 | } | ||
| 997 | |||
| 998 | Attrib = Get_WinAttribPosix_From_PosixMode(st.st_mode); | ||
| 999 | |||
| 1000 | // NTime::UnixTimeToFileTime(st.st_ctime, CTime); | ||
| 1001 | // NTime::UnixTimeToFileTime(st.st_mtime, MTime); | ||
| 1002 | // NTime::UnixTimeToFileTime(st.st_atime, ATime); | ||
| 1003 | #ifdef __APPLE__ | ||
| 1004 | // #ifdef _DARWIN_FEATURE_64_BIT_INODE | ||
| 1005 | /* | ||
| 1006 | here we can use birthtime instead of st_ctimespec. | ||
| 1007 | but we use st_ctimespec for compatibility with previous versions and p7zip. | ||
| 1008 | st_birthtimespec in OSX | ||
| 1009 | st_birthtim : at FreeBSD, NetBSD | ||
| 1010 | */ | ||
| 1011 | // timespec_To_FILETIME(st.st_birthtimespec, CTime); | ||
| 1012 | // #else | ||
| 1013 | timespec_To_FILETIME(st.st_ctimespec, CTime); | ||
| 1014 | // #endif | ||
| 1015 | timespec_To_FILETIME(st.st_mtimespec, MTime); | ||
| 1016 | timespec_To_FILETIME(st.st_atimespec, ATime); | ||
| 1017 | #else | ||
| 1018 | timespec_To_FILETIME(st.st_ctim, CTime); | ||
| 1019 | timespec_To_FILETIME(st.st_mtim, MTime); | ||
| 1020 | timespec_To_FILETIME(st.st_atim, ATime); | ||
| 1021 | #endif | ||
| 1022 | |||
| 1023 | dev = st.st_dev; | ||
| 1024 | ino = st.st_ino; | ||
| 1025 | nlink = st.st_nlink; | ||
| 1026 | mode = st.st_mode; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | bool CFileInfo::Find_DontFill_Name(CFSTR path, bool followLink) | ||
| 1030 | { | ||
| 1031 | struct stat st; | ||
| 1032 | if (MY__lstat(path, &st, followLink) != 0) | ||
| 1033 | return false; | ||
| 1034 | SetFrom_stat(st); | ||
| 1035 | return true; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | |||
| 1039 | bool CFileInfo::Find(CFSTR path, bool followLink) | ||
| 1040 | { | ||
| 1041 | // printf("\nCEnumerator::Find() name = %s\n", path); | ||
| 1042 | if (!Find_DontFill_Name(path, followLink)) | ||
| 1043 | return false; | ||
| 1044 | |||
| 1045 | // printf("\nOK\n"); | ||
| 1046 | |||
| 1047 | Name = Get_Name_from_Path(path); | ||
| 1048 | if (!Name.IsEmpty()) | ||
| 1049 | { | ||
| 1050 | char c = Name.Back(); | ||
| 1051 | if (IS_PATH_SEPAR(c)) | ||
| 1052 | Name.DeleteBack(); | ||
| 1053 | } | ||
| 1054 | return true; | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | |||
| 1058 | bool DoesFileExist_Raw(CFSTR name) | ||
| 1059 | { | ||
| 1060 | // FIXME for symbolic links. | ||
| 1061 | struct stat st; | ||
| 1062 | if (MY__lstat(name, &st, false) != 0) | ||
| 1063 | return false; | ||
| 1064 | return !S_ISDIR(st.st_mode); | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | bool DoesFileExist_FollowLink(CFSTR name) | ||
| 1068 | { | ||
| 1069 | // FIXME for symbolic links. | ||
| 1070 | struct stat st; | ||
| 1071 | if (MY__lstat(name, &st, true) != 0) | ||
| 1072 | return false; | ||
| 1073 | return !S_ISDIR(st.st_mode); | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | bool DoesDirExist(CFSTR name, bool followLink) | ||
| 1077 | { | ||
| 1078 | struct stat st; | ||
| 1079 | if (MY__lstat(name, &st, followLink) != 0) | ||
| 1080 | return false; | ||
| 1081 | return S_ISDIR(st.st_mode); | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | bool DoesFileOrDirExist(CFSTR name) | ||
| 1085 | { | ||
| 1086 | struct stat st; | ||
| 1087 | if (MY__lstat(name, &st, false) != 0) | ||
| 1088 | return false; | ||
| 1089 | return true; | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | |||
| 1093 | CEnumerator::~CEnumerator() | ||
| 1094 | { | ||
| 1095 | if (_dir) | ||
| 1096 | closedir(_dir); | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | void CEnumerator::SetDirPrefix(const FString &dirPrefix) | ||
| 1100 | { | ||
| 1101 | _wildcard = dirPrefix; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | bool CDirEntry::IsDots() const throw() | ||
| 1105 | { | ||
| 1106 | /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN) | ||
| 1107 | we can call fstatat() for that case, but we use only (Name) check here */ | ||
| 1108 | |||
| 1109 | #if !defined(_AIX) | ||
| 1110 | if (Type != DT_DIR && Type != DT_UNKNOWN) | ||
| 1111 | return false; | ||
| 1112 | #endif | ||
| 1113 | |||
| 1114 | return Name.Len() != 0 | ||
| 1115 | && Name.Len() <= 2 | ||
| 1116 | && Name[0] == '.' | ||
| 1117 | && (Name.Len() == 1 || Name[1] == '.'); | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | |||
| 1121 | bool CEnumerator::NextAny(CDirEntry &fi, bool &found) | ||
| 1122 | { | ||
| 1123 | found = false; | ||
| 1124 | |||
| 1125 | if (!_dir) | ||
| 1126 | { | ||
| 1127 | const char *w = "./"; | ||
| 1128 | if (!_wildcard.IsEmpty()) | ||
| 1129 | w = _wildcard.Ptr(); | ||
| 1130 | _dir = ::opendir((const char *)w); | ||
| 1131 | if (_dir == NULL) | ||
| 1132 | return false; | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | // To distinguish end of stream from an error, we must set errno to zero before readdir() | ||
| 1136 | errno = 0; | ||
| 1137 | |||
| 1138 | struct dirent *de = readdir(_dir); | ||
| 1139 | if (!de) | ||
| 1140 | { | ||
| 1141 | if (errno == 0) | ||
| 1142 | return true; // it's end of stream, and we report it with (found = false) | ||
| 1143 | // it's real error | ||
| 1144 | return false; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | fi.iNode = de->d_ino; | ||
| 1148 | |||
| 1149 | #if !defined(_AIX) | ||
| 1150 | fi.Type = de->d_type; | ||
| 1151 | /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN) | ||
| 1152 | we can set (Type) from fstatat() in that case. | ||
| 1153 | But (Type) is not too important. So we don't set it here with slow fstatat() */ | ||
| 1154 | /* | ||
| 1155 | // fi.Type = DT_UNKNOWN; // for debug | ||
| 1156 | if (fi.Type == DT_UNKNOWN) | ||
| 1157 | { | ||
| 1158 | struct stat st; | ||
| 1159 | if (fstatat(dirfd(_dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) == 0) | ||
| 1160 | if (S_ISDIR(st.st_mode)) | ||
| 1161 | fi.Type = DT_DIR; | ||
| 1162 | } | ||
| 1163 | */ | ||
| 1164 | #endif | ||
| 1165 | |||
| 1166 | /* | ||
| 1167 | if (de->d_type == DT_DIR) | ||
| 1168 | fi.Attrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(S_IFDIR) << 16); | ||
| 1169 | else if (de->d_type < 16) | ||
| 1170 | fi.Attrib = FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(de->d_type) << (16 + 12)); | ||
| 1171 | */ | ||
| 1172 | fi.Name = de->d_name; | ||
| 1173 | |||
| 1174 | /* | ||
| 1175 | printf("\nCEnumerator::NextAny; len = %d %s \n", (int)fi.Name.Len(), fi.Name.Ptr()); | ||
| 1176 | for (unsigned i = 0; i < fi.Name.Len(); i++) | ||
| 1177 | printf (" %02x", (unsigned)(Byte)de->d_name[i]); | ||
| 1178 | printf("\n"); | ||
| 1179 | */ | ||
| 1180 | |||
| 1181 | found = true; | ||
| 1182 | return true; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | |||
| 1186 | bool CEnumerator::Next(CDirEntry &fi, bool &found) | ||
| 1187 | { | ||
| 1188 | // printf("\nCEnumerator::Next()\n"); | ||
| 1189 | // PrintName("Next", ""); | ||
| 1190 | for (;;) | ||
| 1191 | { | ||
| 1192 | if (!NextAny(fi, found)) | ||
| 1193 | return false; | ||
| 1194 | if (!found) | ||
| 1195 | return true; | ||
| 1196 | if (!fi.IsDots()) | ||
| 1197 | { | ||
| 1198 | /* | ||
| 1199 | if (!NeedFullStat) | ||
| 1200 | return true; | ||
| 1201 | // we silently skip error file here - it can be wrong link item | ||
| 1202 | if (fi.Find_DontFill_Name(path)) | ||
| 1203 | return true; | ||
| 1204 | */ | ||
| 1205 | return true; | ||
| 1206 | } | ||
| 1207 | } | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | /* | ||
| 1211 | bool CEnumerator::Next(CDirEntry &fileInfo, bool &found) | ||
| 1212 | { | ||
| 1213 | bool found; | ||
| 1214 | if (!Next(fi, found)) | ||
| 1215 | return false; | ||
| 1216 | return found; | ||
| 1217 | } | ||
| 1218 | */ | ||
| 1219 | |||
| 1220 | bool CEnumerator::Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const | ||
| 1221 | { | ||
| 1222 | // printf("\nCEnumerator::Fill_FileInfo()\n"); | ||
| 1223 | struct stat st; | ||
| 1224 | // probably it's OK to use fstatat() even if it changes file position dirfd(_dir) | ||
| 1225 | int res = fstatat(dirfd(_dir), de.Name, &st, followLink ? 0 : AT_SYMLINK_NOFOLLOW); | ||
| 1226 | // if fstatat() is not supported, we can use stat() / lstat() | ||
| 1227 | |||
| 1228 | /* | ||
| 1229 | const FString path = _wildcard + s; | ||
| 1230 | int res = MY__lstat(path, &st, followLink); | ||
| 1231 | */ | ||
| 1232 | |||
| 1233 | if (res != 0) | ||
| 1234 | return false; | ||
| 1235 | fileInfo.SetFrom_stat(st); | ||
| 1236 | fileInfo.Name = de.Name; | ||
| 1237 | return true; | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | #endif // _WIN32 | ||
| 1241 | |||
| 1242 | }}} | ||
diff --git a/CPP/Windows/FileFind.h b/CPP/Windows/FileFind.h new file mode 100644 index 0000000..8f28ee3 --- /dev/null +++ b/CPP/Windows/FileFind.h | |||
| @@ -0,0 +1,305 @@ | |||
| 1 | // Windows/FileFind.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_FILE_FIND_H | ||
| 4 | #define __WINDOWS_FILE_FIND_H | ||
| 5 | |||
| 6 | #ifndef _WIN32 | ||
| 7 | #include <sys/stat.h> | ||
| 8 | #include <sys/types.h> | ||
| 9 | #include <dirent.h> | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #include "../Common/MyString.h" | ||
| 13 | #include "../Common/MyWindows.h" | ||
| 14 | #include "Defs.h" | ||
| 15 | |||
| 16 | namespace NWindows { | ||
| 17 | namespace NFile { | ||
| 18 | namespace NFind { | ||
| 19 | |||
| 20 | // bool DoesFileExist(CFSTR name, bool followLink); | ||
| 21 | bool DoesFileExist_Raw(CFSTR name); | ||
| 22 | bool DoesFileExist_FollowLink(CFSTR name); | ||
| 23 | bool DoesDirExist(CFSTR name, bool followLink); | ||
| 24 | |||
| 25 | inline bool DoesDirExist(CFSTR name) | ||
| 26 | { return DoesDirExist(name, false); } | ||
| 27 | inline bool DoesDirExist_FollowLink(CFSTR name) | ||
| 28 | { return DoesDirExist(name, true); } | ||
| 29 | |||
| 30 | // it's always _Raw | ||
| 31 | bool DoesFileOrDirExist(CFSTR name); | ||
| 32 | |||
| 33 | DWORD GetFileAttrib(CFSTR path); | ||
| 34 | |||
| 35 | |||
| 36 | namespace NAttributes | ||
| 37 | { | ||
| 38 | inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; } | ||
| 39 | inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; } | ||
| 40 | inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; } | ||
| 41 | inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; } | ||
| 42 | inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; } | ||
| 43 | inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; } | ||
| 44 | inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; } | ||
| 45 | } | ||
| 46 | |||
| 47 | class CFileInfoBase | ||
| 48 | { | ||
| 49 | bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); } | ||
| 50 | public: | ||
| 51 | UInt64 Size; | ||
| 52 | FILETIME CTime; | ||
| 53 | FILETIME ATime; | ||
| 54 | FILETIME MTime; | ||
| 55 | DWORD Attrib; | ||
| 56 | bool IsAltStream; | ||
| 57 | bool IsDevice; | ||
| 58 | |||
| 59 | #ifdef _WIN32 | ||
| 60 | /* | ||
| 61 | #ifdef UNDER_CE | ||
| 62 | DWORD ObjectID; | ||
| 63 | #else | ||
| 64 | UINT32 ReparseTag; | ||
| 65 | #endif | ||
| 66 | */ | ||
| 67 | #else | ||
| 68 | dev_t dev; | ||
| 69 | ino_t ino; | ||
| 70 | nlink_t nlink; | ||
| 71 | mode_t mode; | ||
| 72 | // bool Use_lstat; | ||
| 73 | #endif | ||
| 74 | |||
| 75 | CFileInfoBase() { ClearBase(); } | ||
| 76 | void ClearBase() throw(); | ||
| 77 | |||
| 78 | void SetAsDir() | ||
| 79 | { | ||
| 80 | Attrib = FILE_ATTRIBUTE_DIRECTORY; | ||
| 81 | #ifndef _WIN32 | ||
| 82 | Attrib |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16)); | ||
| 83 | #endif | ||
| 84 | } | ||
| 85 | |||
| 86 | bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } | ||
| 87 | bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } | ||
| 88 | bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); } | ||
| 89 | bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); } | ||
| 90 | bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); } | ||
| 91 | bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); } | ||
| 92 | bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); } | ||
| 93 | bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); } | ||
| 94 | bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); } | ||
| 95 | bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); } | ||
| 96 | bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } | ||
| 97 | bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } | ||
| 98 | |||
| 99 | #ifndef _WIN32 | ||
| 100 | bool IsPosixLink() const | ||
| 101 | { | ||
| 102 | const UInt32 mod = Attrib >> 16; | ||
| 103 | return S_ISLNK(mod); | ||
| 104 | } | ||
| 105 | #endif | ||
| 106 | |||
| 107 | bool IsOsSymLink() const | ||
| 108 | { | ||
| 109 | #ifdef _WIN32 | ||
| 110 | return HasReparsePoint(); | ||
| 111 | #else | ||
| 112 | return IsPosixLink(); | ||
| 113 | #endif | ||
| 114 | } | ||
| 115 | }; | ||
| 116 | |||
| 117 | struct CFileInfo: public CFileInfoBase | ||
| 118 | { | ||
| 119 | FString Name; | ||
| 120 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 121 | // FString ShortName; | ||
| 122 | #endif | ||
| 123 | |||
| 124 | bool IsDots() const throw(); | ||
| 125 | bool Find(CFSTR path, bool followLink = false); | ||
| 126 | bool Find_FollowLink(CFSTR path) { return Find(path, true); } | ||
| 127 | |||
| 128 | #ifdef _WIN32 | ||
| 129 | bool Fill_From_ByHandleFileInfo(CFSTR path); | ||
| 130 | // bool FollowReparse(CFSTR path, bool isDir); | ||
| 131 | #else | ||
| 132 | bool Find_DontFill_Name(CFSTR path, bool followLink = false); | ||
| 133 | void SetFrom_stat(const struct stat &st); | ||
| 134 | #endif | ||
| 135 | }; | ||
| 136 | |||
| 137 | |||
| 138 | #ifdef _WIN32 | ||
| 139 | |||
| 140 | class CFindFileBase MY_UNCOPYABLE | ||
| 141 | { | ||
| 142 | protected: | ||
| 143 | HANDLE _handle; | ||
| 144 | public: | ||
| 145 | bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE; } | ||
| 146 | CFindFileBase(): _handle(INVALID_HANDLE_VALUE) {} | ||
| 147 | ~CFindFileBase() { Close(); } | ||
| 148 | bool Close() throw(); | ||
| 149 | }; | ||
| 150 | |||
| 151 | class CFindFile: public CFindFileBase | ||
| 152 | { | ||
| 153 | public: | ||
| 154 | bool FindFirst(CFSTR wildcard, CFileInfo &fileInfo); | ||
| 155 | bool FindNext(CFileInfo &fileInfo); | ||
| 156 | }; | ||
| 157 | |||
| 158 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 159 | |||
| 160 | struct CStreamInfo | ||
| 161 | { | ||
| 162 | UString Name; | ||
| 163 | UInt64 Size; | ||
| 164 | |||
| 165 | UString GetReducedName() const; // returns ":Name" | ||
| 166 | // UString GetReducedName2() const; // returns "Name" | ||
| 167 | bool IsMainStream() const throw(); | ||
| 168 | }; | ||
| 169 | |||
| 170 | class CFindStream: public CFindFileBase | ||
| 171 | { | ||
| 172 | public: | ||
| 173 | bool FindFirst(CFSTR filePath, CStreamInfo &streamInfo); | ||
| 174 | bool FindNext(CStreamInfo &streamInfo); | ||
| 175 | }; | ||
| 176 | |||
| 177 | class CStreamEnumerator MY_UNCOPYABLE | ||
| 178 | { | ||
| 179 | CFindStream _find; | ||
| 180 | FString _filePath; | ||
| 181 | |||
| 182 | bool NextAny(CFileInfo &fileInfo, bool &found); | ||
| 183 | public: | ||
| 184 | CStreamEnumerator(const FString &filePath): _filePath(filePath) {} | ||
| 185 | bool Next(CStreamInfo &streamInfo, bool &found); | ||
| 186 | }; | ||
| 187 | |||
| 188 | #endif // defined(_WIN32) && !defined(UNDER_CE) | ||
| 189 | |||
| 190 | |||
| 191 | class CEnumerator MY_UNCOPYABLE | ||
| 192 | { | ||
| 193 | CFindFile _findFile; | ||
| 194 | FString _wildcard; | ||
| 195 | |||
| 196 | bool NextAny(CFileInfo &fileInfo); | ||
| 197 | public: | ||
| 198 | void SetDirPrefix(const FString &dirPrefix); | ||
| 199 | bool Next(CFileInfo &fileInfo); | ||
| 200 | bool Next(CFileInfo &fileInfo, bool &found); | ||
| 201 | }; | ||
| 202 | |||
| 203 | |||
| 204 | class CFindChangeNotification MY_UNCOPYABLE | ||
| 205 | { | ||
| 206 | HANDLE _handle; | ||
| 207 | public: | ||
| 208 | operator HANDLE () { return _handle; } | ||
| 209 | bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE && _handle != 0; } | ||
| 210 | CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {} | ||
| 211 | ~CFindChangeNotification() { Close(); } | ||
| 212 | bool Close() throw(); | ||
| 213 | HANDLE FindFirst(CFSTR pathName, bool watchSubtree, DWORD notifyFilter); | ||
| 214 | bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); } | ||
| 215 | }; | ||
| 216 | |||
| 217 | #ifndef UNDER_CE | ||
| 218 | bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings); | ||
| 219 | #endif | ||
| 220 | |||
| 221 | typedef CFileInfo CDirEntry; | ||
| 222 | |||
| 223 | |||
| 224 | #else // WIN32 | ||
| 225 | |||
| 226 | |||
| 227 | struct CDirEntry | ||
| 228 | { | ||
| 229 | ino_t iNode; | ||
| 230 | #if !defined(_AIX) | ||
| 231 | Byte Type; | ||
| 232 | #endif | ||
| 233 | FString Name; | ||
| 234 | |||
| 235 | /* | ||
| 236 | #if !defined(_AIX) | ||
| 237 | bool IsDir() const | ||
| 238 | { | ||
| 239 | // (Type == DT_UNKNOWN) on some systems | ||
| 240 | return Type == DT_DIR; | ||
| 241 | } | ||
| 242 | #endif | ||
| 243 | */ | ||
| 244 | |||
| 245 | bool IsDots() const throw(); | ||
| 246 | }; | ||
| 247 | |||
| 248 | class CEnumerator MY_UNCOPYABLE | ||
| 249 | { | ||
| 250 | DIR *_dir; | ||
| 251 | FString _wildcard; | ||
| 252 | |||
| 253 | bool NextAny(CDirEntry &fileInfo, bool &found); | ||
| 254 | public: | ||
| 255 | CEnumerator(): _dir(NULL) {} | ||
| 256 | ~CEnumerator(); | ||
| 257 | void SetDirPrefix(const FString &dirPrefix); | ||
| 258 | |||
| 259 | bool Next(CDirEntry &fileInfo, bool &found); | ||
| 260 | bool Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const; | ||
| 261 | bool DirEntry_IsDir(const CDirEntry &de, bool followLink) const | ||
| 262 | { | ||
| 263 | #if !defined(_AIX) | ||
| 264 | if (de.Type == DT_DIR) | ||
| 265 | return true; | ||
| 266 | if (de.Type != DT_UNKNOWN) | ||
| 267 | return false; | ||
| 268 | #endif | ||
| 269 | CFileInfo fileInfo; | ||
| 270 | if (Fill_FileInfo(de, fileInfo, followLink)) | ||
| 271 | { | ||
| 272 | return fileInfo.IsDir(); | ||
| 273 | } | ||
| 274 | return false; // change it | ||
| 275 | } | ||
| 276 | }; | ||
| 277 | |||
| 278 | /* | ||
| 279 | inline UInt32 Get_WinAttrib_From_PosixMode(UInt32 mode) | ||
| 280 | { | ||
| 281 | UInt32 attrib = S_ISDIR(mode) ? | ||
| 282 | FILE_ATTRIBUTE_DIRECTORY : | ||
| 283 | FILE_ATTRIBUTE_ARCHIVE; | ||
| 284 | if ((st.st_mode & 0222) == 0) // check it !!! | ||
| 285 | attrib |= FILE_ATTRIBUTE_READONLY; | ||
| 286 | return attrib; | ||
| 287 | } | ||
| 288 | */ | ||
| 289 | |||
| 290 | UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode); | ||
| 291 | |||
| 292 | // UInt32 Get_WinAttrib_From_stat(const struct stat &st); | ||
| 293 | #if defined(_AIX) | ||
| 294 | #define MY_ST_TIMESPEC st_timespec | ||
| 295 | #else | ||
| 296 | #define MY_ST_TIMESPEC timespec | ||
| 297 | #endif | ||
| 298 | |||
| 299 | void timespec_To_FILETIME(const MY_ST_TIMESPEC &ts, FILETIME &ft); | ||
| 300 | |||
| 301 | #endif // WIN32 | ||
| 302 | |||
| 303 | }}} | ||
| 304 | |||
| 305 | #endif | ||
diff --git a/CPP/Windows/FileIO.cpp b/CPP/Windows/FileIO.cpp new file mode 100644 index 0000000..2974b1b --- /dev/null +++ b/CPP/Windows/FileIO.cpp | |||
| @@ -0,0 +1,825 @@ | |||
| 1 | // Windows/FileIO.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifdef SUPPORT_DEVICE_FILE | ||
| 6 | #include "../../C/Alloc.h" | ||
| 7 | #endif | ||
| 8 | |||
| 9 | // #include <stdio.h> | ||
| 10 | |||
| 11 | #include "FileIO.h" | ||
| 12 | #include "FileName.h" | ||
| 13 | |||
| 14 | HRESULT GetLastError_noZero_HRESULT() | ||
| 15 | { | ||
| 16 | DWORD res = ::GetLastError(); | ||
| 17 | if (res == 0) | ||
| 18 | return E_FAIL; | ||
| 19 | return HRESULT_FROM_WIN32(res); | ||
| 20 | } | ||
| 21 | |||
| 22 | #ifdef _WIN32 | ||
| 23 | |||
| 24 | #ifndef _UNICODE | ||
| 25 | extern bool g_IsNT; | ||
| 26 | #endif | ||
| 27 | |||
| 28 | using namespace NWindows; | ||
| 29 | using namespace NFile; | ||
| 30 | using namespace NName; | ||
| 31 | |||
| 32 | namespace NWindows { | ||
| 33 | namespace NFile { | ||
| 34 | |||
| 35 | #ifdef SUPPORT_DEVICE_FILE | ||
| 36 | |||
| 37 | namespace NSystem | ||
| 38 | { | ||
| 39 | bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); | ||
| 40 | } | ||
| 41 | #endif | ||
| 42 | |||
| 43 | namespace NIO { | ||
| 44 | |||
| 45 | /* | ||
| 46 | WinXP-64 CreateFile(): | ||
| 47 | "" - ERROR_PATH_NOT_FOUND | ||
| 48 | :stream - OK | ||
| 49 | .:stream - ERROR_PATH_NOT_FOUND | ||
| 50 | .\:stream - OK | ||
| 51 | |||
| 52 | folder\:stream - ERROR_INVALID_NAME | ||
| 53 | folder:stream - OK | ||
| 54 | |||
| 55 | c:\:stream - OK | ||
| 56 | |||
| 57 | c::stream - ERROR_INVALID_NAME, if current dir is NOT ROOT ( c:\dir1 ) | ||
| 58 | c::stream - OK, if current dir is ROOT ( c:\ ) | ||
| 59 | */ | ||
| 60 | |||
| 61 | bool CFileBase::Create(CFSTR path, DWORD desiredAccess, | ||
| 62 | DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) | ||
| 63 | { | ||
| 64 | if (!Close()) | ||
| 65 | return false; | ||
| 66 | |||
| 67 | #ifdef SUPPORT_DEVICE_FILE | ||
| 68 | IsDeviceFile = false; | ||
| 69 | #endif | ||
| 70 | |||
| 71 | #ifndef _UNICODE | ||
| 72 | if (!g_IsNT) | ||
| 73 | { | ||
| 74 | _handle = ::CreateFile(fs2fas(path), desiredAccess, shareMode, | ||
| 75 | (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); | ||
| 76 | } | ||
| 77 | else | ||
| 78 | #endif | ||
| 79 | { | ||
| 80 | IF_USE_MAIN_PATH | ||
| 81 | _handle = ::CreateFileW(fs2us(path), desiredAccess, shareMode, | ||
| 82 | (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); | ||
| 83 | #ifdef WIN_LONG_PATH | ||
| 84 | if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH) | ||
| 85 | { | ||
| 86 | UString superPath; | ||
| 87 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | ||
| 88 | _handle = ::CreateFileW(superPath, desiredAccess, shareMode, | ||
| 89 | (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); | ||
| 90 | } | ||
| 91 | #endif | ||
| 92 | } | ||
| 93 | |||
| 94 | /* | ||
| 95 | #ifndef UNDER_CE | ||
| 96 | #ifndef _SFX | ||
| 97 | if (_handle == INVALID_HANDLE_VALUE) | ||
| 98 | { | ||
| 99 | // it's debug hack to open symbolic links in Windows XP and WSL links in Windows 10 | ||
| 100 | DWORD lastError = GetLastError(); | ||
| 101 | if (lastError == ERROR_CANT_ACCESS_FILE) | ||
| 102 | { | ||
| 103 | CByteBuffer buf; | ||
| 104 | if (NIO::GetReparseData(path, buf, NULL)) | ||
| 105 | { | ||
| 106 | CReparseAttr attr; | ||
| 107 | if (attr.Parse(buf, buf.Size())) | ||
| 108 | { | ||
| 109 | FString dirPrefix, fileName; | ||
| 110 | if (NDir::GetFullPathAndSplit(path, dirPrefix, fileName)) | ||
| 111 | { | ||
| 112 | FString fullPath; | ||
| 113 | if (GetFullPath(dirPrefix, us2fs(attr.GetPath()), fullPath)) | ||
| 114 | { | ||
| 115 | // FIX IT: recursion levels must be restricted | ||
| 116 | return Create(fullPath, desiredAccess, | ||
| 117 | shareMode, creationDisposition, flagsAndAttributes); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | } | ||
| 122 | SetLastError(lastError); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | #endif | ||
| 126 | #endif | ||
| 127 | */ | ||
| 128 | |||
| 129 | return (_handle != INVALID_HANDLE_VALUE); | ||
| 130 | } | ||
| 131 | |||
| 132 | bool CFileBase::Close() throw() | ||
| 133 | { | ||
| 134 | if (_handle == INVALID_HANDLE_VALUE) | ||
| 135 | return true; | ||
| 136 | if (!::CloseHandle(_handle)) | ||
| 137 | return false; | ||
| 138 | _handle = INVALID_HANDLE_VALUE; | ||
| 139 | return true; | ||
| 140 | } | ||
| 141 | |||
| 142 | bool CFileBase::GetLength(UInt64 &length) const throw() | ||
| 143 | { | ||
| 144 | #ifdef SUPPORT_DEVICE_FILE | ||
| 145 | if (IsDeviceFile && SizeDefined) | ||
| 146 | { | ||
| 147 | length = Size; | ||
| 148 | return true; | ||
| 149 | } | ||
| 150 | #endif | ||
| 151 | |||
| 152 | DWORD high = 0; | ||
| 153 | const DWORD low = ::GetFileSize(_handle, &high); | ||
| 154 | if (low == INVALID_FILE_SIZE) | ||
| 155 | if (::GetLastError() != NO_ERROR) | ||
| 156 | return false; | ||
| 157 | length = (((UInt64)high) << 32) + low; | ||
| 158 | return true; | ||
| 159 | |||
| 160 | /* | ||
| 161 | LARGE_INTEGER fileSize; | ||
| 162 | // GetFileSizeEx() is unsupported in 98/ME/NT, and supported in Win2000+ | ||
| 163 | if (!GetFileSizeEx(_handle, &fileSize)) | ||
| 164 | return false; | ||
| 165 | length = (UInt64)fileSize.QuadPart; | ||
| 166 | return true; | ||
| 167 | */ | ||
| 168 | } | ||
| 169 | |||
| 170 | |||
| 171 | /* Specification for SetFilePointer(): | ||
| 172 | |||
| 173 | If a new file pointer is a negative value, | ||
| 174 | { | ||
| 175 | the function fails, | ||
| 176 | the file pointer is not moved, | ||
| 177 | the code returned by GetLastError() is ERROR_NEGATIVE_SEEK. | ||
| 178 | } | ||
| 179 | |||
| 180 | If the hFile handle is opened with the FILE_FLAG_NO_BUFFERING flag set | ||
| 181 | { | ||
| 182 | an application can move the file pointer only to sector-aligned positions. | ||
| 183 | A sector-aligned position is a position that is a whole number multiple of | ||
| 184 | the volume sector size. | ||
| 185 | An application can obtain a volume sector size by calling the GetDiskFreeSpace. | ||
| 186 | } | ||
| 187 | |||
| 188 | It is not an error to set a file pointer to a position beyond the end of the file. | ||
| 189 | The size of the file does not increase until you call the SetEndOfFile, WriteFile, or WriteFileEx function. | ||
| 190 | |||
| 191 | If the return value is INVALID_SET_FILE_POINTER and if lpDistanceToMoveHigh is non-NULL, | ||
| 192 | an application must call GetLastError to determine whether or not the function has succeeded or failed. | ||
| 193 | */ | ||
| 194 | |||
| 195 | bool CFileBase::GetPosition(UInt64 &position) const throw() | ||
| 196 | { | ||
| 197 | LONG high = 0; | ||
| 198 | const DWORD low = ::SetFilePointer(_handle, 0, &high, FILE_CURRENT); | ||
| 199 | if (low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) | ||
| 200 | { | ||
| 201 | // for error case we can set (position) to (-1) or (0) or leave (position) unchanged. | ||
| 202 | // position = (UInt64)(Int64)-1; // for debug | ||
| 203 | position = 0; | ||
| 204 | return false; | ||
| 205 | } | ||
| 206 | position = (((UInt64)(UInt32)high) << 32) + low; | ||
| 207 | return true; | ||
| 208 | // we don't want recursed GetPosition() | ||
| 209 | // return Seek(0, FILE_CURRENT, position); | ||
| 210 | } | ||
| 211 | |||
| 212 | bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw() | ||
| 213 | { | ||
| 214 | #ifdef SUPPORT_DEVICE_FILE | ||
| 215 | if (IsDeviceFile && SizeDefined && moveMethod == FILE_END) | ||
| 216 | { | ||
| 217 | distanceToMove += Size; | ||
| 218 | moveMethod = FILE_BEGIN; | ||
| 219 | } | ||
| 220 | #endif | ||
| 221 | |||
| 222 | LONG high = (LONG)(distanceToMove >> 32); | ||
| 223 | const DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod); | ||
| 224 | if (low == INVALID_SET_FILE_POINTER) | ||
| 225 | { | ||
| 226 | const DWORD lastError = ::GetLastError(); | ||
| 227 | if (lastError != NO_ERROR) | ||
| 228 | { | ||
| 229 | // 21.07: we set (newPosition) to real position even after error. | ||
| 230 | GetPosition(newPosition); | ||
| 231 | SetLastError(lastError); // restore LastError | ||
| 232 | return false; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | newPosition = (((UInt64)(UInt32)high) << 32) + low; | ||
| 236 | return true; | ||
| 237 | } | ||
| 238 | |||
| 239 | bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw() | ||
| 240 | { | ||
| 241 | return Seek((Int64)position, FILE_BEGIN, newPosition); | ||
| 242 | } | ||
| 243 | |||
| 244 | bool CFileBase::SeekToBegin() const throw() | ||
| 245 | { | ||
| 246 | UInt64 newPosition = 0; | ||
| 247 | return Seek(0, newPosition) && (newPosition == 0); | ||
| 248 | } | ||
| 249 | |||
| 250 | bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw() | ||
| 251 | { | ||
| 252 | return Seek(0, FILE_END, newPosition); | ||
| 253 | } | ||
| 254 | |||
| 255 | // ---------- CInFile --------- | ||
| 256 | |||
| 257 | #ifdef SUPPORT_DEVICE_FILE | ||
| 258 | |||
| 259 | void CInFile::CorrectDeviceSize() | ||
| 260 | { | ||
| 261 | // maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail | ||
| 262 | static const UInt32 kClusterSize = 1 << 14; | ||
| 263 | UInt64 pos = Size & ~(UInt64)(kClusterSize - 1); | ||
| 264 | UInt64 realNewPosition; | ||
| 265 | if (!Seek(pos, realNewPosition)) | ||
| 266 | return; | ||
| 267 | Byte *buf = (Byte *)MidAlloc(kClusterSize); | ||
| 268 | |||
| 269 | bool needbackward = true; | ||
| 270 | |||
| 271 | for (;;) | ||
| 272 | { | ||
| 273 | UInt32 processed = 0; | ||
| 274 | // up test is slow for "PhysicalDrive". | ||
| 275 | // processed size for latest block for "PhysicalDrive0" is 0. | ||
| 276 | if (!Read1(buf, kClusterSize, processed)) | ||
| 277 | break; | ||
| 278 | if (processed == 0) | ||
| 279 | break; | ||
| 280 | needbackward = false; | ||
| 281 | Size = pos + processed; | ||
| 282 | if (processed != kClusterSize) | ||
| 283 | break; | ||
| 284 | pos += kClusterSize; | ||
| 285 | } | ||
| 286 | |||
| 287 | if (needbackward && pos != 0) | ||
| 288 | { | ||
| 289 | pos -= kClusterSize; | ||
| 290 | for (;;) | ||
| 291 | { | ||
| 292 | // break; | ||
| 293 | if (!Seek(pos, realNewPosition)) | ||
| 294 | break; | ||
| 295 | if (!buf) | ||
| 296 | { | ||
| 297 | buf = (Byte *)MidAlloc(kClusterSize); | ||
| 298 | if (!buf) | ||
| 299 | break; | ||
| 300 | } | ||
| 301 | UInt32 processed = 0; | ||
| 302 | // that code doesn't work for "PhysicalDrive0" | ||
| 303 | if (!Read1(buf, kClusterSize, processed)) | ||
| 304 | break; | ||
| 305 | if (processed != 0) | ||
| 306 | { | ||
| 307 | Size = pos + processed; | ||
| 308 | break; | ||
| 309 | } | ||
| 310 | if (pos == 0) | ||
| 311 | break; | ||
| 312 | pos -= kClusterSize; | ||
| 313 | } | ||
| 314 | } | ||
| 315 | MidFree(buf); | ||
| 316 | } | ||
| 317 | |||
| 318 | |||
| 319 | void CInFile::CalcDeviceSize(CFSTR s) | ||
| 320 | { | ||
| 321 | SizeDefined = false; | ||
| 322 | Size = 0; | ||
| 323 | if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile) | ||
| 324 | return; | ||
| 325 | #ifdef UNDER_CE | ||
| 326 | |||
| 327 | SizeDefined = true; | ||
| 328 | Size = 128 << 20; | ||
| 329 | |||
| 330 | #else | ||
| 331 | |||
| 332 | PARTITION_INFORMATION partInfo; | ||
| 333 | bool needCorrectSize = true; | ||
| 334 | |||
| 335 | /* | ||
| 336 | WinXP 64-bit: | ||
| 337 | |||
| 338 | HDD \\.\PhysicalDrive0 (MBR): | ||
| 339 | GetPartitionInfo == GeometryEx : corrrect size? (includes tail) | ||
| 340 | Geometry : smaller than GeometryEx (no tail, maybe correct too?) | ||
| 341 | MyGetDiskFreeSpace : FAIL | ||
| 342 | Size correction is slow and block size (kClusterSize) must be small? | ||
| 343 | |||
| 344 | HDD partition \\.\N: (NTFS): | ||
| 345 | MyGetDiskFreeSpace : Size of NTFS clusters. Same size can be calculated after correction | ||
| 346 | GetPartitionInfo : size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS | ||
| 347 | Geometry / CdRomGeometry / GeometryEx : size of HDD (not that partition) | ||
| 348 | |||
| 349 | CD-ROM drive (ISO): | ||
| 350 | MyGetDiskFreeSpace : correct size. Same size can be calculated after correction | ||
| 351 | Geometry == CdRomGeometry : smaller than corrrect size | ||
| 352 | GetPartitionInfo == GeometryEx : larger than corrrect size | ||
| 353 | |||
| 354 | Floppy \\.\a: (FAT): | ||
| 355 | Geometry : correct size. | ||
| 356 | CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL | ||
| 357 | correction works OK for FAT. | ||
| 358 | correction works OK for non-FAT, if kClusterSize = 512. | ||
| 359 | */ | ||
| 360 | |||
| 361 | if (GetPartitionInfo(&partInfo)) | ||
| 362 | { | ||
| 363 | Size = (UInt64)partInfo.PartitionLength.QuadPart; | ||
| 364 | SizeDefined = true; | ||
| 365 | needCorrectSize = false; | ||
| 366 | if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0) | ||
| 367 | { | ||
| 368 | FChar path[4] = { s[4], ':', '\\', 0 }; | ||
| 369 | UInt64 clusterSize, totalSize, freeSize; | ||
| 370 | if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize)) | ||
| 371 | Size = totalSize; | ||
| 372 | else | ||
| 373 | needCorrectSize = true; | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | if (!SizeDefined) | ||
| 378 | { | ||
| 379 | my_DISK_GEOMETRY_EX geomEx; | ||
| 380 | SizeDefined = GetGeometryEx(&geomEx); | ||
| 381 | if (SizeDefined) | ||
| 382 | Size = (UInt64)geomEx.DiskSize.QuadPart; | ||
| 383 | else | ||
| 384 | { | ||
| 385 | DISK_GEOMETRY geom; | ||
| 386 | SizeDefined = GetGeometry(&geom); | ||
| 387 | if (!SizeDefined) | ||
| 388 | SizeDefined = GetCdRomGeometry(&geom); | ||
| 389 | if (SizeDefined) | ||
| 390 | Size = (UInt64)geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector; | ||
| 391 | } | ||
| 392 | } | ||
| 393 | |||
| 394 | if (needCorrectSize && SizeDefined && Size != 0) | ||
| 395 | { | ||
| 396 | CorrectDeviceSize(); | ||
| 397 | SeekToBegin(); | ||
| 398 | } | ||
| 399 | |||
| 400 | // SeekToBegin(); | ||
| 401 | #endif | ||
| 402 | } | ||
| 403 | |||
| 404 | // ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 && | ||
| 405 | |||
| 406 | #define MY_DEVICE_EXTRA_CODE \ | ||
| 407 | IsDeviceFile = IsDevicePath(fileName); \ | ||
| 408 | CalcDeviceSize(fileName); | ||
| 409 | #else | ||
| 410 | #define MY_DEVICE_EXTRA_CODE | ||
| 411 | #endif | ||
| 412 | |||
| 413 | bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) | ||
| 414 | { | ||
| 415 | DWORD desiredAccess = GENERIC_READ; | ||
| 416 | |||
| 417 | #ifdef _WIN32 | ||
| 418 | if (PreserveATime) | ||
| 419 | desiredAccess |= FILE_WRITE_ATTRIBUTES; | ||
| 420 | #endif | ||
| 421 | |||
| 422 | bool res = Create(fileName, desiredAccess, shareMode, creationDisposition, flagsAndAttributes); | ||
| 423 | |||
| 424 | #ifdef _WIN32 | ||
| 425 | if (res && PreserveATime) | ||
| 426 | { | ||
| 427 | FILETIME ft; | ||
| 428 | ft.dwHighDateTime = ft.dwLowDateTime = 0xFFFFFFFF; | ||
| 429 | ::SetFileTime(_handle, NULL, &ft, NULL); | ||
| 430 | } | ||
| 431 | #endif | ||
| 432 | |||
| 433 | MY_DEVICE_EXTRA_CODE | ||
| 434 | return res; | ||
| 435 | } | ||
| 436 | |||
| 437 | bool CInFile::OpenShared(CFSTR fileName, bool shareForWrite) | ||
| 438 | { return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } | ||
| 439 | |||
| 440 | bool CInFile::Open(CFSTR fileName) | ||
| 441 | { return OpenShared(fileName, false); } | ||
| 442 | |||
| 443 | // ReadFile and WriteFile functions in Windows have BUG: | ||
| 444 | // If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) | ||
| 445 | // from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES | ||
| 446 | // (Insufficient system resources exist to complete the requested service). | ||
| 447 | |||
| 448 | // Probably in some version of Windows there are problems with other sizes: | ||
| 449 | // for 32 MB (maybe also for 16 MB). | ||
| 450 | // And message can be "Network connection was lost" | ||
| 451 | |||
| 452 | static const UInt32 kChunkSizeMax = (1 << 22); | ||
| 453 | |||
| 454 | bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw() | ||
| 455 | { | ||
| 456 | DWORD processedLoc = 0; | ||
| 457 | bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL)); | ||
| 458 | processedSize = (UInt32)processedLoc; | ||
| 459 | return res; | ||
| 460 | } | ||
| 461 | |||
| 462 | bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw() | ||
| 463 | { | ||
| 464 | if (size > kChunkSizeMax) | ||
| 465 | size = kChunkSizeMax; | ||
| 466 | return Read1(data, size, processedSize); | ||
| 467 | } | ||
| 468 | |||
| 469 | bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw() | ||
| 470 | { | ||
| 471 | processedSize = 0; | ||
| 472 | do | ||
| 473 | { | ||
| 474 | UInt32 processedLoc = 0; | ||
| 475 | bool res = ReadPart(data, size, processedLoc); | ||
| 476 | processedSize += processedLoc; | ||
| 477 | if (!res) | ||
| 478 | return false; | ||
| 479 | if (processedLoc == 0) | ||
| 480 | return true; | ||
| 481 | data = (void *)((unsigned char *)data + processedLoc); | ||
| 482 | size -= processedLoc; | ||
| 483 | } | ||
| 484 | while (size > 0); | ||
| 485 | return true; | ||
| 486 | } | ||
| 487 | |||
| 488 | bool CInFile::ReadFull(void *data, size_t size, size_t &processedSize) throw() | ||
| 489 | { | ||
| 490 | processedSize = 0; | ||
| 491 | do | ||
| 492 | { | ||
| 493 | UInt32 processedLoc = 0; | ||
| 494 | const UInt32 sizeLoc = (size > kChunkSizeMax ? (UInt32)kChunkSizeMax : (UInt32)size); | ||
| 495 | const bool res = Read1(data, sizeLoc, processedLoc); | ||
| 496 | processedSize += processedLoc; | ||
| 497 | if (!res) | ||
| 498 | return false; | ||
| 499 | if (processedLoc == 0) | ||
| 500 | return true; | ||
| 501 | data = (void *)((unsigned char *)data + processedLoc); | ||
| 502 | size -= processedLoc; | ||
| 503 | } | ||
| 504 | while (size > 0); | ||
| 505 | return true; | ||
| 506 | } | ||
| 507 | |||
| 508 | // ---------- COutFile --------- | ||
| 509 | |||
| 510 | static inline DWORD GetCreationDisposition(bool createAlways) | ||
| 511 | { return createAlways? CREATE_ALWAYS: CREATE_NEW; } | ||
| 512 | |||
| 513 | bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) | ||
| 514 | { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } | ||
| 515 | |||
| 516 | bool COutFile::Open(CFSTR fileName, DWORD creationDisposition) | ||
| 517 | { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } | ||
| 518 | |||
| 519 | bool COutFile::Create(CFSTR fileName, bool createAlways) | ||
| 520 | { return Open(fileName, GetCreationDisposition(createAlways)); } | ||
| 521 | |||
| 522 | bool COutFile::CreateAlways(CFSTR fileName, DWORD flagsAndAttributes) | ||
| 523 | { return Open(fileName, FILE_SHARE_READ, GetCreationDisposition(true), flagsAndAttributes); } | ||
| 524 | |||
| 525 | bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() | ||
| 526 | { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); } | ||
| 527 | |||
| 528 | bool COutFile::SetMTime(const FILETIME *mTime) throw() { return SetTime(NULL, NULL, mTime); } | ||
| 529 | |||
| 530 | bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw() | ||
| 531 | { | ||
| 532 | if (size > kChunkSizeMax) | ||
| 533 | size = kChunkSizeMax; | ||
| 534 | DWORD processedLoc = 0; | ||
| 535 | bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL)); | ||
| 536 | processedSize = (UInt32)processedLoc; | ||
| 537 | return res; | ||
| 538 | } | ||
| 539 | |||
| 540 | bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw() | ||
| 541 | { | ||
| 542 | processedSize = 0; | ||
| 543 | do | ||
| 544 | { | ||
| 545 | UInt32 processedLoc = 0; | ||
| 546 | bool res = WritePart(data, size, processedLoc); | ||
| 547 | processedSize += processedLoc; | ||
| 548 | if (!res) | ||
| 549 | return false; | ||
| 550 | if (processedLoc == 0) | ||
| 551 | return true; | ||
| 552 | data = (const void *)((const unsigned char *)data + processedLoc); | ||
| 553 | size -= processedLoc; | ||
| 554 | } | ||
| 555 | while (size != 0); | ||
| 556 | return true; | ||
| 557 | } | ||
| 558 | |||
| 559 | bool COutFile::WriteFull(const void *data, size_t size) throw() | ||
| 560 | { | ||
| 561 | do | ||
| 562 | { | ||
| 563 | UInt32 processedLoc = 0; | ||
| 564 | const UInt32 sizeCur = (size > kChunkSizeMax ? kChunkSizeMax : (UInt32)size); | ||
| 565 | if (!WritePart(data, sizeCur, processedLoc)) | ||
| 566 | return false; | ||
| 567 | if (processedLoc == 0) | ||
| 568 | return (size == 0); | ||
| 569 | data = (const void *)((const unsigned char *)data + processedLoc); | ||
| 570 | size -= processedLoc; | ||
| 571 | } | ||
| 572 | while (size != 0); | ||
| 573 | return true; | ||
| 574 | } | ||
| 575 | |||
| 576 | bool COutFile::SetEndOfFile() throw() { return BOOLToBool(::SetEndOfFile(_handle)); } | ||
| 577 | |||
| 578 | bool COutFile::SetLength(UInt64 length) throw() | ||
| 579 | { | ||
| 580 | UInt64 newPosition; | ||
| 581 | if (!Seek(length, newPosition)) | ||
| 582 | return false; | ||
| 583 | if (newPosition != length) | ||
| 584 | return false; | ||
| 585 | return SetEndOfFile(); | ||
| 586 | } | ||
| 587 | |||
| 588 | bool COutFile::SetLength_KeepPosition(UInt64 length) throw() | ||
| 589 | { | ||
| 590 | UInt64 currentPos = 0; | ||
| 591 | if (!GetPosition(currentPos)) | ||
| 592 | return false; | ||
| 593 | DWORD lastError = 0; | ||
| 594 | const bool result = SetLength(length); | ||
| 595 | if (!result) | ||
| 596 | lastError = GetLastError(); | ||
| 597 | UInt64 currentPos2; | ||
| 598 | const bool result2 = Seek(currentPos, currentPos2); | ||
| 599 | if (lastError != 0) | ||
| 600 | SetLastError(lastError); | ||
| 601 | return (result && result2); | ||
| 602 | } | ||
| 603 | |||
| 604 | }}} | ||
| 605 | |||
| 606 | #else // _WIN32 | ||
| 607 | |||
| 608 | |||
| 609 | // POSIX | ||
| 610 | |||
| 611 | #include <fcntl.h> | ||
| 612 | #include <unistd.h> | ||
| 613 | |||
| 614 | namespace NWindows { | ||
| 615 | namespace NFile { | ||
| 616 | |||
| 617 | namespace NDir { | ||
| 618 | bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); | ||
| 619 | } | ||
| 620 | |||
| 621 | namespace NIO { | ||
| 622 | |||
| 623 | bool CFileBase::OpenBinary(const char *name, int flags) | ||
| 624 | { | ||
| 625 | #ifdef O_BINARY | ||
| 626 | flags |= O_BINARY; | ||
| 627 | #endif | ||
| 628 | |||
| 629 | Close(); | ||
| 630 | _handle = ::open(name, flags, 0666); | ||
| 631 | return _handle != -1; | ||
| 632 | } | ||
| 633 | |||
| 634 | bool CFileBase::Close() | ||
| 635 | { | ||
| 636 | if (_handle == -1) | ||
| 637 | return true; | ||
| 638 | if (close(_handle) != 0) | ||
| 639 | return false; | ||
| 640 | _handle = -1; | ||
| 641 | return true; | ||
| 642 | } | ||
| 643 | |||
| 644 | bool CFileBase::GetLength(UInt64 &length) const | ||
| 645 | { | ||
| 646 | length = 0; | ||
| 647 | // length = (UInt64)(Int64)-1; // for debug | ||
| 648 | const off_t curPos = seekToCur(); | ||
| 649 | if (curPos == -1) | ||
| 650 | return false; | ||
| 651 | const off_t lengthTemp = seek(0, SEEK_END); | ||
| 652 | seek(curPos, SEEK_SET); | ||
| 653 | length = (UInt64)lengthTemp; | ||
| 654 | return (lengthTemp != -1); | ||
| 655 | } | ||
| 656 | |||
| 657 | off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const | ||
| 658 | { | ||
| 659 | // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove); | ||
| 660 | // off_t res = ::lseek(_handle, distanceToMove, moveMethod); | ||
| 661 | return ::lseek(_handle, distanceToMove, moveMethod); | ||
| 662 | // printf(" res = %lld", (long long)res); | ||
| 663 | // return res; | ||
| 664 | } | ||
| 665 | |||
| 666 | off_t CFileBase::seekToBegin() const throw() | ||
| 667 | { | ||
| 668 | return seek(0, SEEK_SET); | ||
| 669 | } | ||
| 670 | |||
| 671 | off_t CFileBase::seekToCur() const throw() | ||
| 672 | { | ||
| 673 | return seek(0, SEEK_CUR); | ||
| 674 | } | ||
| 675 | |||
| 676 | /* | ||
| 677 | bool CFileBase::SeekToBegin() const throw() | ||
| 678 | { | ||
| 679 | return (::seek(0, SEEK_SET) != -1); | ||
| 680 | } | ||
| 681 | */ | ||
| 682 | |||
| 683 | |||
| 684 | ///////////////////////// | ||
| 685 | // CInFile | ||
| 686 | |||
| 687 | bool CInFile::Open(const char *name) | ||
| 688 | { | ||
| 689 | return CFileBase::OpenBinary(name, O_RDONLY); | ||
| 690 | } | ||
| 691 | |||
| 692 | bool CInFile::OpenShared(const char *name, bool) | ||
| 693 | { | ||
| 694 | return Open(name); | ||
| 695 | } | ||
| 696 | |||
| 697 | /* | ||
| 698 | On Linux (32-bit and 64-bit): | ||
| 699 | read(), write() (and similar system calls) will transfer at most | ||
| 700 | 0x7ffff000 = (2GiB - 4 KiB) bytes, returning the number of bytes actually transferred. | ||
| 701 | */ | ||
| 702 | |||
| 703 | static const size_t kChunkSizeMax = ((size_t)1 << 22); | ||
| 704 | |||
| 705 | ssize_t CInFile::read_part(void *data, size_t size) throw() | ||
| 706 | { | ||
| 707 | if (size > kChunkSizeMax) | ||
| 708 | size = kChunkSizeMax; | ||
| 709 | return ::read(_handle, data, size); | ||
| 710 | } | ||
| 711 | |||
| 712 | bool CInFile::ReadFull(void *data, size_t size, size_t &processed) throw() | ||
| 713 | { | ||
| 714 | processed = 0; | ||
| 715 | do | ||
| 716 | { | ||
| 717 | const ssize_t res = read_part(data, size); | ||
| 718 | if (res < 0) | ||
| 719 | return false; | ||
| 720 | if (res == 0) | ||
| 721 | break; | ||
| 722 | data = (void *)((unsigned char *)data + (size_t)res); | ||
| 723 | size -= (size_t)res; | ||
| 724 | processed += (size_t)res; | ||
| 725 | } | ||
| 726 | while (size > 0); | ||
| 727 | return true; | ||
| 728 | } | ||
| 729 | |||
| 730 | |||
| 731 | ///////////////////////// | ||
| 732 | // COutFile | ||
| 733 | |||
| 734 | bool COutFile::Create(const char *name, bool createAlways) | ||
| 735 | { | ||
| 736 | Path = name; // change it : set it only if open is success. | ||
| 737 | if (createAlways) | ||
| 738 | { | ||
| 739 | Close(); | ||
| 740 | _handle = ::creat(name, 0666); | ||
| 741 | return _handle != -1; | ||
| 742 | } | ||
| 743 | return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY); | ||
| 744 | } | ||
| 745 | |||
| 746 | bool COutFile::Open(const char *name, DWORD creationDisposition) | ||
| 747 | { | ||
| 748 | UNUSED_VAR(creationDisposition) // FIXME | ||
| 749 | return Create(name, false); | ||
| 750 | } | ||
| 751 | |||
| 752 | ssize_t COutFile::write_part(const void *data, size_t size) throw() | ||
| 753 | { | ||
| 754 | if (size > kChunkSizeMax) | ||
| 755 | size = kChunkSizeMax; | ||
| 756 | return ::write(_handle, data, size); | ||
| 757 | } | ||
| 758 | |||
| 759 | ssize_t COutFile::write_full(const void *data, size_t size, size_t &processed) throw() | ||
| 760 | { | ||
| 761 | processed = 0; | ||
| 762 | do | ||
| 763 | { | ||
| 764 | const ssize_t res = write_part(data, size); | ||
| 765 | if (res < 0) | ||
| 766 | return res; | ||
| 767 | if (res == 0) | ||
| 768 | break; | ||
| 769 | data = (const void *)((const unsigned char *)data + (size_t)res); | ||
| 770 | size -= (size_t)res; | ||
| 771 | processed += (size_t)res; | ||
| 772 | } | ||
| 773 | while (size > 0); | ||
| 774 | return (ssize_t)processed; | ||
| 775 | } | ||
| 776 | |||
| 777 | bool COutFile::SetLength(UInt64 length) throw() | ||
| 778 | { | ||
| 779 | const off_t len2 = (off_t)length; | ||
| 780 | if ((Int64)length != len2) | ||
| 781 | { | ||
| 782 | SetLastError(EFBIG); | ||
| 783 | return false; | ||
| 784 | } | ||
| 785 | // The value of the seek pointer shall not be modified by a call to ftruncate(). | ||
| 786 | int iret = ftruncate(_handle, len2); | ||
| 787 | return (iret == 0); | ||
| 788 | } | ||
| 789 | |||
| 790 | bool COutFile::Close() | ||
| 791 | { | ||
| 792 | bool res = CFileBase::Close(); | ||
| 793 | if (!res) | ||
| 794 | return res; | ||
| 795 | if (CTime_defined || ATime_defined || MTime_defined) | ||
| 796 | { | ||
| 797 | /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path, | ||
| 798 | CTime_defined ? &CTime : NULL, | ||
| 799 | ATime_defined ? &ATime : NULL, | ||
| 800 | MTime_defined ? &MTime : NULL); | ||
| 801 | } | ||
| 802 | return res; | ||
| 803 | } | ||
| 804 | |||
| 805 | bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() | ||
| 806 | { | ||
| 807 | // On some OS (cygwin, MacOSX ...), you must close the file before updating times | ||
| 808 | // return true; | ||
| 809 | |||
| 810 | if (cTime) { CTime = *cTime; CTime_defined = true; } else CTime_defined = false; | ||
| 811 | if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false; | ||
| 812 | if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; | ||
| 813 | return true; | ||
| 814 | } | ||
| 815 | |||
| 816 | bool COutFile::SetMTime(const FILETIME *mTime) throw() | ||
| 817 | { | ||
| 818 | if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; | ||
| 819 | return true; | ||
| 820 | } | ||
| 821 | |||
| 822 | }}} | ||
| 823 | |||
| 824 | |||
| 825 | #endif | ||
diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h new file mode 100644 index 0000000..22998eb --- /dev/null +++ b/CPP/Windows/FileIO.h | |||
| @@ -0,0 +1,347 @@ | |||
| 1 | // Windows/FileIO.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_FILE_IO_H | ||
| 4 | #define __WINDOWS_FILE_IO_H | ||
| 5 | |||
| 6 | #include "../Common/MyWindows.h" | ||
| 7 | |||
| 8 | #define _my_IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) | ||
| 9 | #define _my_IO_REPARSE_TAG_SYMLINK (0xA000000CL) | ||
| 10 | #define _my_IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL) | ||
| 11 | |||
| 12 | #define _my_SYMLINK_FLAG_RELATIVE 1 | ||
| 13 | |||
| 14 | // what the meaning of that FLAG or field (2)? | ||
| 15 | #define _my_LX_SYMLINK_FLAG 2 | ||
| 16 | |||
| 17 | #ifdef _WIN32 | ||
| 18 | |||
| 19 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 20 | #include <WinIoCtl.h> | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #else | ||
| 24 | |||
| 25 | #include <sys/types.h> | ||
| 26 | #include <sys/stat.h> | ||
| 27 | |||
| 28 | #endif | ||
| 29 | |||
| 30 | #include "../Common/MyString.h" | ||
| 31 | #include "../Common/MyBuffer.h" | ||
| 32 | |||
| 33 | #include "Defs.h" | ||
| 34 | |||
| 35 | HRESULT GetLastError_noZero_HRESULT(); | ||
| 36 | |||
| 37 | #define my_FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER | ||
| 38 | #define my_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER | ||
| 39 | #define my_FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER | ||
| 40 | |||
| 41 | namespace NWindows { | ||
| 42 | namespace NFile { | ||
| 43 | |||
| 44 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 45 | bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL); | ||
| 46 | #endif | ||
| 47 | |||
| 48 | struct CReparseShortInfo | ||
| 49 | { | ||
| 50 | unsigned Offset; | ||
| 51 | unsigned Size; | ||
| 52 | |||
| 53 | bool Parse(const Byte *p, size_t size); | ||
| 54 | }; | ||
| 55 | |||
| 56 | struct CReparseAttr | ||
| 57 | { | ||
| 58 | UInt32 Tag; | ||
| 59 | UInt32 Flags; | ||
| 60 | UString SubsName; | ||
| 61 | UString PrintName; | ||
| 62 | |||
| 63 | AString WslName; | ||
| 64 | |||
| 65 | bool HeaderError; | ||
| 66 | bool TagIsUnknown; | ||
| 67 | bool MinorError; | ||
| 68 | DWORD ErrorCode; | ||
| 69 | |||
| 70 | CReparseAttr(): Tag(0), Flags(0) {} | ||
| 71 | |||
| 72 | // Parse() | ||
| 73 | // returns (true) and (ErrorCode = 0), if (it'a correct known link) | ||
| 74 | // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag | ||
| 75 | bool Parse(const Byte *p, size_t size); | ||
| 76 | |||
| 77 | bool IsMountPoint() const { return Tag == _my_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction | ||
| 78 | bool IsSymLink_Win() const { return Tag == _my_IO_REPARSE_TAG_SYMLINK; } | ||
| 79 | bool IsSymLink_WSL() const { return Tag == _my_IO_REPARSE_TAG_LX_SYMLINK; } | ||
| 80 | |||
| 81 | bool IsRelative_Win() const { return Flags == _my_SYMLINK_FLAG_RELATIVE; } | ||
| 82 | |||
| 83 | bool IsRelative_WSL() const | ||
| 84 | { | ||
| 85 | if (WslName.IsEmpty()) | ||
| 86 | return true; | ||
| 87 | char c = WslName[0]; | ||
| 88 | return !IS_PATH_SEPAR(c); | ||
| 89 | } | ||
| 90 | |||
| 91 | // bool IsVolume() const; | ||
| 92 | |||
| 93 | bool IsOkNamePair() const; | ||
| 94 | UString GetPath() const; | ||
| 95 | }; | ||
| 96 | |||
| 97 | |||
| 98 | #ifdef _WIN32 | ||
| 99 | |||
| 100 | namespace NIO { | ||
| 101 | |||
| 102 | bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo = NULL); | ||
| 103 | bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); | ||
| 104 | bool DeleteReparseData(CFSTR path); | ||
| 105 | |||
| 106 | class CFileBase MY_UNCOPYABLE | ||
| 107 | { | ||
| 108 | protected: | ||
| 109 | HANDLE _handle; | ||
| 110 | |||
| 111 | bool Create(CFSTR path, DWORD desiredAccess, | ||
| 112 | DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); | ||
| 113 | |||
| 114 | public: | ||
| 115 | |||
| 116 | bool DeviceIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inSize, | ||
| 117 | LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned, LPOVERLAPPED overlapped = NULL) const | ||
| 118 | { | ||
| 119 | return BOOLToBool(::DeviceIoControl(_handle, controlCode, inBuffer, inSize, | ||
| 120 | outBuffer, outSize, bytesReturned, overlapped)); | ||
| 121 | } | ||
| 122 | |||
| 123 | bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned) const | ||
| 124 | { | ||
| 125 | return DeviceIoControl(controlCode, NULL, 0, outBuffer, outSize, bytesReturned); | ||
| 126 | } | ||
| 127 | |||
| 128 | bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize) const | ||
| 129 | { | ||
| 130 | DWORD bytesReturned; | ||
| 131 | return DeviceIoControlOut(controlCode, outBuffer, outSize, &bytesReturned); | ||
| 132 | } | ||
| 133 | |||
| 134 | public: | ||
| 135 | bool PreserveATime; | ||
| 136 | #ifdef SUPPORT_DEVICE_FILE | ||
| 137 | bool IsDeviceFile; | ||
| 138 | bool SizeDefined; | ||
| 139 | UInt64 Size; // it can be larger than real available size | ||
| 140 | #endif | ||
| 141 | |||
| 142 | CFileBase(): _handle(INVALID_HANDLE_VALUE), PreserveATime(false) {}; | ||
| 143 | ~CFileBase() { Close(); } | ||
| 144 | |||
| 145 | bool Close() throw(); | ||
| 146 | |||
| 147 | bool GetPosition(UInt64 &position) const throw(); | ||
| 148 | bool GetLength(UInt64 &length) const throw(); | ||
| 149 | |||
| 150 | bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw(); | ||
| 151 | bool Seek(UInt64 position, UInt64 &newPosition) const throw(); | ||
| 152 | bool SeekToBegin() const throw(); | ||
| 153 | bool SeekToEnd(UInt64 &newPosition) const throw(); | ||
| 154 | |||
| 155 | bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const | ||
| 156 | { return BOOLToBool(GetFileInformationByHandle(_handle, info)); } | ||
| 157 | |||
| 158 | static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info) | ||
| 159 | { | ||
| 160 | // probably it can work for complex paths: unsupported by another things | ||
| 161 | NIO::CFileBase file; | ||
| 162 | if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS)) | ||
| 163 | return false; | ||
| 164 | return file.GetFileInformation(info); | ||
| 165 | } | ||
| 166 | }; | ||
| 167 | |||
| 168 | #ifndef UNDER_CE | ||
| 169 | #define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM | ||
| 170 | #define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) | ||
| 171 | // #define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) | ||
| 172 | |||
| 173 | // IOCTL_DISK_GET_DRIVE_GEOMETRY_EX works since WinXP | ||
| 174 | #define my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) | ||
| 175 | |||
| 176 | struct my_DISK_GEOMETRY_EX | ||
| 177 | { | ||
| 178 | DISK_GEOMETRY Geometry; | ||
| 179 | LARGE_INTEGER DiskSize; | ||
| 180 | BYTE Data[1]; | ||
| 181 | }; | ||
| 182 | #endif | ||
| 183 | |||
| 184 | class CInFile: public CFileBase | ||
| 185 | { | ||
| 186 | #ifdef SUPPORT_DEVICE_FILE | ||
| 187 | |||
| 188 | #ifndef UNDER_CE | ||
| 189 | |||
| 190 | bool GetGeometry(DISK_GEOMETRY *res) const | ||
| 191 | { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } | ||
| 192 | |||
| 193 | bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const | ||
| 194 | { return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); } | ||
| 195 | |||
| 196 | bool GetCdRomGeometry(DISK_GEOMETRY *res) const | ||
| 197 | { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } | ||
| 198 | |||
| 199 | bool GetPartitionInfo(PARTITION_INFORMATION *res) | ||
| 200 | { return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); } | ||
| 201 | |||
| 202 | #endif | ||
| 203 | |||
| 204 | void CorrectDeviceSize(); | ||
| 205 | void CalcDeviceSize(CFSTR name); | ||
| 206 | |||
| 207 | #endif | ||
| 208 | |||
| 209 | public: | ||
| 210 | bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); | ||
| 211 | bool OpenShared(CFSTR fileName, bool shareForWrite); | ||
| 212 | bool Open(CFSTR fileName); | ||
| 213 | |||
| 214 | #ifndef UNDER_CE | ||
| 215 | |||
| 216 | bool OpenReparse(CFSTR fileName) | ||
| 217 | { | ||
| 218 | // 17.02 fix: to support Windows XP compatibility junctions: | ||
| 219 | // we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ | ||
| 220 | return | ||
| 221 | Create(fileName, 0, | ||
| 222 | // Open(fileName, | ||
| 223 | FILE_SHARE_READ, OPEN_EXISTING, | ||
| 224 | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS); | ||
| 225 | } | ||
| 226 | |||
| 227 | #endif | ||
| 228 | |||
| 229 | bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw(); | ||
| 230 | bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw(); | ||
| 231 | bool Read(void *data, UInt32 size, UInt32 &processedSize) throw(); | ||
| 232 | bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); | ||
| 233 | }; | ||
| 234 | |||
| 235 | class COutFile: public CFileBase | ||
| 236 | { | ||
| 237 | public: | ||
| 238 | bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); | ||
| 239 | bool Open(CFSTR fileName, DWORD creationDisposition); | ||
| 240 | bool Create(CFSTR fileName, bool createAlways); | ||
| 241 | bool CreateAlways(CFSTR fileName, DWORD flagsAndAttributes); | ||
| 242 | |||
| 243 | bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw(); | ||
| 244 | bool SetMTime(const FILETIME *mTime) throw(); | ||
| 245 | bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw(); | ||
| 246 | bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw(); | ||
| 247 | bool WriteFull(const void *data, size_t size) throw(); | ||
| 248 | bool SetEndOfFile() throw(); | ||
| 249 | bool SetLength(UInt64 length) throw(); | ||
| 250 | bool SetLength_KeepPosition(UInt64 length) throw(); | ||
| 251 | }; | ||
| 252 | |||
| 253 | } | ||
| 254 | |||
| 255 | |||
| 256 | #else // _WIN32 | ||
| 257 | |||
| 258 | namespace NIO { | ||
| 259 | |||
| 260 | bool GetReparseData(CFSTR path, CByteBuffer &reparseData); | ||
| 261 | // bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); | ||
| 262 | |||
| 263 | // parameters are in reverse order of symlink() function !!! | ||
| 264 | bool SetSymLink(CFSTR from, CFSTR to); | ||
| 265 | bool SetSymLink_UString(CFSTR from, const UString &to); | ||
| 266 | |||
| 267 | |||
| 268 | class CFileBase | ||
| 269 | { | ||
| 270 | protected: | ||
| 271 | int _handle; | ||
| 272 | |||
| 273 | bool OpenBinary(const char *name, int flags); | ||
| 274 | public: | ||
| 275 | bool PreserveATime; | ||
| 276 | |||
| 277 | CFileBase(): _handle(-1), PreserveATime(false) {}; | ||
| 278 | ~CFileBase() { Close(); } | ||
| 279 | bool Close(); | ||
| 280 | bool GetLength(UInt64 &length) const; | ||
| 281 | off_t seek(off_t distanceToMove, int moveMethod) const; | ||
| 282 | off_t seekToBegin() const throw(); | ||
| 283 | off_t seekToCur() const throw(); | ||
| 284 | // bool SeekToBegin() throw(); | ||
| 285 | int my_fstat(struct stat *st) const { return fstat(_handle, st); } | ||
| 286 | }; | ||
| 287 | |||
| 288 | class CInFile: public CFileBase | ||
| 289 | { | ||
| 290 | public: | ||
| 291 | bool Open(const char *name); | ||
| 292 | bool OpenShared(const char *name, bool shareForWrite); | ||
| 293 | ssize_t read_part(void *data, size_t size) throw(); | ||
| 294 | // ssize_t read_full(void *data, size_t size, size_t &processed); | ||
| 295 | bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); | ||
| 296 | }; | ||
| 297 | |||
| 298 | class COutFile: public CFileBase | ||
| 299 | { | ||
| 300 | bool CTime_defined; | ||
| 301 | bool ATime_defined; | ||
| 302 | bool MTime_defined; | ||
| 303 | |||
| 304 | FILETIME CTime; | ||
| 305 | FILETIME ATime; | ||
| 306 | FILETIME MTime; | ||
| 307 | |||
| 308 | AString Path; | ||
| 309 | ssize_t write_part(const void *data, size_t size) throw(); | ||
| 310 | public: | ||
| 311 | COutFile(): | ||
| 312 | CTime_defined(false), | ||
| 313 | ATime_defined(false), | ||
| 314 | MTime_defined(false) | ||
| 315 | {} | ||
| 316 | |||
| 317 | bool Close(); | ||
| 318 | bool Create(const char *name, bool createAlways); | ||
| 319 | bool Open(const char *name, DWORD creationDisposition); | ||
| 320 | ssize_t write_full(const void *data, size_t size, size_t &processed) throw(); | ||
| 321 | |||
| 322 | bool WriteFull(const void *data, size_t size) throw() | ||
| 323 | { | ||
| 324 | size_t processed; | ||
| 325 | ssize_t res = write_full(data, size, processed); | ||
| 326 | if (res == -1) | ||
| 327 | return false; | ||
| 328 | return processed == size; | ||
| 329 | } | ||
| 330 | |||
| 331 | bool SetLength(UInt64 length) throw(); | ||
| 332 | bool SetLength_KeepPosition(UInt64 length) throw() | ||
| 333 | { | ||
| 334 | return SetLength(length); | ||
| 335 | } | ||
| 336 | bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw(); | ||
| 337 | bool SetMTime(const FILETIME *mTime) throw(); | ||
| 338 | }; | ||
| 339 | |||
| 340 | } | ||
| 341 | |||
| 342 | #endif // _WIN32 | ||
| 343 | |||
| 344 | }} | ||
| 345 | |||
| 346 | |||
| 347 | #endif | ||
diff --git a/CPP/Windows/FileLink.cpp b/CPP/Windows/FileLink.cpp new file mode 100644 index 0000000..8ce634f --- /dev/null +++ b/CPP/Windows/FileLink.cpp | |||
| @@ -0,0 +1,613 @@ | |||
| 1 | // Windows/FileLink.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../../C/CpuArch.h" | ||
| 6 | |||
| 7 | #ifndef _WIN32 | ||
| 8 | #include <unistd.h> | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #ifdef SUPPORT_DEVICE_FILE | ||
| 12 | #include "../../C/Alloc.h" | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #include "../Common/UTFConvert.h" | ||
| 16 | #include "../Common/StringConvert.h" | ||
| 17 | |||
| 18 | #include "FileDir.h" | ||
| 19 | #include "FileFind.h" | ||
| 20 | #include "FileIO.h" | ||
| 21 | #include "FileName.h" | ||
| 22 | |||
| 23 | #ifndef _UNICODE | ||
| 24 | extern bool g_IsNT; | ||
| 25 | #endif | ||
| 26 | |||
| 27 | namespace NWindows { | ||
| 28 | namespace NFile { | ||
| 29 | |||
| 30 | using namespace NName; | ||
| 31 | |||
| 32 | /* | ||
| 33 | Reparse Points (Junctions and Symbolic Links): | ||
| 34 | struct | ||
| 35 | { | ||
| 36 | UInt32 Tag; | ||
| 37 | UInt16 Size; // not including starting 8 bytes | ||
| 38 | UInt16 Reserved; // = 0 | ||
| 39 | |||
| 40 | UInt16 SubstituteOffset; // offset in bytes from start of namesChars | ||
| 41 | UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL | ||
| 42 | UInt16 PrintOffset; // offset in bytes from start of namesChars | ||
| 43 | UInt16 PrintLen; // size in bytes, it doesn't include tailed NUL | ||
| 44 | |||
| 45 | [UInt32] Flags; // for Symbolic Links only. | ||
| 46 | |||
| 47 | UInt16 namesChars[] | ||
| 48 | } | ||
| 49 | |||
| 50 | MOUNT_POINT (Junction point): | ||
| 51 | 1) there is NUL wchar after path | ||
| 52 | 2) Default Order in table: | ||
| 53 | Substitute Path | ||
| 54 | Print Path | ||
| 55 | 3) pathnames can not contain dot directory names | ||
| 56 | |||
| 57 | SYMLINK: | ||
| 58 | 1) there is no NUL wchar after path | ||
| 59 | 2) Default Order in table: | ||
| 60 | Print Path | ||
| 61 | Substitute Path | ||
| 62 | */ | ||
| 63 | |||
| 64 | /* | ||
| 65 | Win10 WSL2: | ||
| 66 | admin rights + sudo: it creates normal windows symbolic link. | ||
| 67 | in another cases : it creates IO_REPARSE_TAG_LX_SYMLINK repare point. | ||
| 68 | */ | ||
| 69 | |||
| 70 | /* | ||
| 71 | static const UInt32 kReparseFlags_Alias = (1 << 29); | ||
| 72 | static const UInt32 kReparseFlags_HighLatency = (1 << 30); | ||
| 73 | static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31); | ||
| 74 | |||
| 75 | #define _my_IO_REPARSE_TAG_HSM (0xC0000004L) | ||
| 76 | #define _my_IO_REPARSE_TAG_HSM2 (0x80000006L) | ||
| 77 | #define _my_IO_REPARSE_TAG_SIS (0x80000007L) | ||
| 78 | #define _my_IO_REPARSE_TAG_WIM (0x80000008L) | ||
| 79 | #define _my_IO_REPARSE_TAG_CSV (0x80000009L) | ||
| 80 | #define _my_IO_REPARSE_TAG_DFS (0x8000000AL) | ||
| 81 | #define _my_IO_REPARSE_TAG_DFSR (0x80000012L) | ||
| 82 | */ | ||
| 83 | |||
| 84 | #define Get16(p) GetUi16(p) | ||
| 85 | #define Get32(p) GetUi32(p) | ||
| 86 | |||
| 87 | static const wchar_t * const k_LinkPrefix = L"\\??\\"; | ||
| 88 | static const unsigned k_LinkPrefix_Size = 4; | ||
| 89 | |||
| 90 | static bool IsLinkPrefix(const wchar_t *s) | ||
| 91 | { | ||
| 92 | return IsString1PrefixedByString2(s, k_LinkPrefix); | ||
| 93 | } | ||
| 94 | |||
| 95 | /* | ||
| 96 | static const wchar_t * const k_VolumePrefix = L"Volume{"; | ||
| 97 | static const bool IsVolumeName(const wchar_t *s) | ||
| 98 | { | ||
| 99 | return IsString1PrefixedByString2(s, k_VolumePrefix); | ||
| 100 | } | ||
| 101 | */ | ||
| 102 | |||
| 103 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 104 | |||
| 105 | #define Set16(p, v) SetUi16(p, v) | ||
| 106 | #define Set32(p, v) SetUi32(p, v) | ||
| 107 | |||
| 108 | static void WriteString(Byte *dest, const wchar_t *path) | ||
| 109 | { | ||
| 110 | for (;;) | ||
| 111 | { | ||
| 112 | wchar_t c = *path++; | ||
| 113 | if (c == 0) | ||
| 114 | return; | ||
| 115 | Set16(dest, (UInt16)c); | ||
| 116 | dest += 2; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL) | ||
| 121 | { | ||
| 122 | bool isAbs = IsAbsolutePath(path); | ||
| 123 | if (!isAbs && !isSymLink) | ||
| 124 | return false; | ||
| 125 | |||
| 126 | if (isWSL) | ||
| 127 | { | ||
| 128 | // unsupported characters probably use Replacement Character UTF-16 0xFFFD | ||
| 129 | AString utf; | ||
| 130 | ConvertUnicodeToUTF8(path, utf); | ||
| 131 | const size_t size = 4 + utf.Len(); | ||
| 132 | if (size != (UInt16)size) | ||
| 133 | return false; | ||
| 134 | dest.Alloc(8 + size); | ||
| 135 | Byte *p = dest; | ||
| 136 | Set32(p, _my_IO_REPARSE_TAG_LX_SYMLINK); | ||
| 137 | Set16(p + 4, (UInt16)(size)); | ||
| 138 | Set16(p + 6, 0); | ||
| 139 | Set32(p + 8, _my_LX_SYMLINK_FLAG); | ||
| 140 | memcpy(p + 12, utf.Ptr(), utf.Len()); | ||
| 141 | return true; | ||
| 142 | } | ||
| 143 | |||
| 144 | // usual symbolic LINK (NOT WSL) | ||
| 145 | |||
| 146 | bool needPrintName = true; | ||
| 147 | |||
| 148 | if (IsSuperPath(path)) | ||
| 149 | { | ||
| 150 | path += kSuperPathPrefixSize; | ||
| 151 | if (!IsDrivePath(path)) | ||
| 152 | needPrintName = false; | ||
| 153 | } | ||
| 154 | |||
| 155 | const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0; | ||
| 156 | |||
| 157 | size_t len2 = (size_t)MyStringLen(path) * 2; | ||
| 158 | const size_t len1 = len2 + add_Prefix_Len * 2; | ||
| 159 | if (!needPrintName) | ||
| 160 | len2 = 0; | ||
| 161 | |||
| 162 | size_t totalNamesSize = (len1 + len2); | ||
| 163 | |||
| 164 | /* some WIM imagex software uses old scheme for symbolic links. | ||
| 165 | so we can old scheme for byte to byte compatibility */ | ||
| 166 | |||
| 167 | bool newOrderScheme = isSymLink; | ||
| 168 | // newOrderScheme = false; | ||
| 169 | |||
| 170 | if (!newOrderScheme) | ||
| 171 | totalNamesSize += 2 * 2; | ||
| 172 | |||
| 173 | const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize; | ||
| 174 | if (size != (UInt16)size) | ||
| 175 | return false; | ||
| 176 | dest.Alloc(size); | ||
| 177 | memset(dest, 0, size); | ||
| 178 | const UInt32 tag = isSymLink ? | ||
| 179 | _my_IO_REPARSE_TAG_SYMLINK : | ||
| 180 | _my_IO_REPARSE_TAG_MOUNT_POINT; | ||
| 181 | Byte *p = dest; | ||
| 182 | Set32(p, tag); | ||
| 183 | Set16(p + 4, (UInt16)(size - 8)); | ||
| 184 | Set16(p + 6, 0); | ||
| 185 | p += 8; | ||
| 186 | |||
| 187 | unsigned subOffs = 0; | ||
| 188 | unsigned printOffs = 0; | ||
| 189 | if (newOrderScheme) | ||
| 190 | subOffs = (unsigned)len2; | ||
| 191 | else | ||
| 192 | printOffs = (unsigned)len1 + 2; | ||
| 193 | |||
| 194 | Set16(p + 0, (UInt16)subOffs); | ||
| 195 | Set16(p + 2, (UInt16)len1); | ||
| 196 | Set16(p + 4, (UInt16)printOffs); | ||
| 197 | Set16(p + 6, (UInt16)len2); | ||
| 198 | |||
| 199 | p += 8; | ||
| 200 | if (isSymLink) | ||
| 201 | { | ||
| 202 | UInt32 flags = isAbs ? 0 : _my_SYMLINK_FLAG_RELATIVE; | ||
| 203 | Set32(p, flags); | ||
| 204 | p += 4; | ||
| 205 | } | ||
| 206 | |||
| 207 | if (add_Prefix_Len != 0) | ||
| 208 | WriteString(p + subOffs, k_LinkPrefix); | ||
| 209 | WriteString(p + subOffs + add_Prefix_Len * 2, path); | ||
| 210 | if (needPrintName) | ||
| 211 | WriteString(p + printOffs, path); | ||
| 212 | return true; | ||
| 213 | } | ||
| 214 | |||
| 215 | #endif // defined(_WIN32) && !defined(UNDER_CE) | ||
| 216 | |||
| 217 | |||
| 218 | static void GetString(const Byte *p, unsigned len, UString &res) | ||
| 219 | { | ||
| 220 | wchar_t *s = res.GetBuf(len); | ||
| 221 | unsigned i; | ||
| 222 | for (i = 0; i < len; i++) | ||
| 223 | { | ||
| 224 | wchar_t c = Get16(p + i * 2); | ||
| 225 | if (c == 0) | ||
| 226 | break; | ||
| 227 | s[i] = c; | ||
| 228 | } | ||
| 229 | s[i] = 0; | ||
| 230 | res.ReleaseBuf_SetLen(i); | ||
| 231 | } | ||
| 232 | |||
| 233 | bool CReparseAttr::Parse(const Byte *p, size_t size) | ||
| 234 | { | ||
| 235 | ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA; | ||
| 236 | HeaderError = true; | ||
| 237 | TagIsUnknown = true; | ||
| 238 | MinorError = false; | ||
| 239 | |||
| 240 | if (size < 8) | ||
| 241 | return false; | ||
| 242 | Tag = Get32(p); | ||
| 243 | UInt32 len = Get16(p + 4); | ||
| 244 | if (len + 8 != size) | ||
| 245 | // if (len + 8 > size) | ||
| 246 | return false; | ||
| 247 | /* | ||
| 248 | if ((type & kReparseFlags_Alias) == 0 || | ||
| 249 | (type & kReparseFlags_Microsoft) == 0 || | ||
| 250 | (type & 0xFFFF) != 3) | ||
| 251 | */ | ||
| 252 | |||
| 253 | if (Get16(p + 6) != 0) // padding | ||
| 254 | return false; | ||
| 255 | |||
| 256 | HeaderError = false; | ||
| 257 | |||
| 258 | if ( Tag != _my_IO_REPARSE_TAG_MOUNT_POINT | ||
| 259 | && Tag != _my_IO_REPARSE_TAG_SYMLINK | ||
| 260 | && Tag != _my_IO_REPARSE_TAG_LX_SYMLINK) | ||
| 261 | { | ||
| 262 | // for unsupported reparse points | ||
| 263 | ErrorCode = (DWORD)ERROR_REPARSE_TAG_INVALID; // ERROR_REPARSE_TAG_MISMATCH | ||
| 264 | // errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID | ||
| 265 | return false; | ||
| 266 | } | ||
| 267 | |||
| 268 | TagIsUnknown = false; | ||
| 269 | |||
| 270 | p += 8; | ||
| 271 | size -= 8; | ||
| 272 | |||
| 273 | if (Tag == _my_IO_REPARSE_TAG_LX_SYMLINK) | ||
| 274 | { | ||
| 275 | if (len < 4) | ||
| 276 | return false; | ||
| 277 | Flags = Get32(p); // maybe it's not Flags | ||
| 278 | if (Flags != _my_LX_SYMLINK_FLAG) | ||
| 279 | return false; | ||
| 280 | len -= 4; | ||
| 281 | p += 4; | ||
| 282 | char *s = WslName.GetBuf(len); | ||
| 283 | unsigned i; | ||
| 284 | for (i = 0; i < len; i++) | ||
| 285 | { | ||
| 286 | char c = (char)p[i]; | ||
| 287 | s[i] = c; | ||
| 288 | if (c == 0) | ||
| 289 | break; | ||
| 290 | } | ||
| 291 | WslName.ReleaseBuf_SetEnd(i); | ||
| 292 | MinorError = (i != len); | ||
| 293 | ErrorCode = 0; | ||
| 294 | return true; | ||
| 295 | } | ||
| 296 | |||
| 297 | if (len < 8) | ||
| 298 | return false; | ||
| 299 | unsigned subOffs = Get16(p); | ||
| 300 | unsigned subLen = Get16(p + 2); | ||
| 301 | unsigned printOffs = Get16(p + 4); | ||
| 302 | unsigned printLen = Get16(p + 6); | ||
| 303 | len -= 8; | ||
| 304 | p += 8; | ||
| 305 | |||
| 306 | Flags = 0; | ||
| 307 | if (Tag == _my_IO_REPARSE_TAG_SYMLINK) | ||
| 308 | { | ||
| 309 | if (len < 4) | ||
| 310 | return false; | ||
| 311 | Flags = Get32(p); | ||
| 312 | len -= 4; | ||
| 313 | p += 4; | ||
| 314 | } | ||
| 315 | |||
| 316 | if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) | ||
| 317 | return false; | ||
| 318 | if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) | ||
| 319 | return false; | ||
| 320 | GetString(p + subOffs, subLen >> 1, SubsName); | ||
| 321 | GetString(p + printOffs, printLen >> 1, PrintName); | ||
| 322 | |||
| 323 | ErrorCode = 0; | ||
| 324 | return true; | ||
| 325 | } | ||
| 326 | |||
| 327 | |||
| 328 | bool CReparseShortInfo::Parse(const Byte *p, size_t size) | ||
| 329 | { | ||
| 330 | const Byte *start = p; | ||
| 331 | Offset= 0; | ||
| 332 | Size = 0; | ||
| 333 | if (size < 8) | ||
| 334 | return false; | ||
| 335 | UInt32 Tag = Get32(p); | ||
| 336 | UInt32 len = Get16(p + 4); | ||
| 337 | if (len + 8 > size) | ||
| 338 | return false; | ||
| 339 | /* | ||
| 340 | if ((type & kReparseFlags_Alias) == 0 || | ||
| 341 | (type & kReparseFlags_Microsoft) == 0 || | ||
| 342 | (type & 0xFFFF) != 3) | ||
| 343 | */ | ||
| 344 | if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT && | ||
| 345 | Tag != _my_IO_REPARSE_TAG_SYMLINK) | ||
| 346 | // return true; | ||
| 347 | return false; | ||
| 348 | |||
| 349 | if (Get16(p + 6) != 0) // padding | ||
| 350 | return false; | ||
| 351 | |||
| 352 | p += 8; | ||
| 353 | size -= 8; | ||
| 354 | |||
| 355 | if (len != size) // do we need that check? | ||
| 356 | return false; | ||
| 357 | |||
| 358 | if (len < 8) | ||
| 359 | return false; | ||
| 360 | unsigned subOffs = Get16(p); | ||
| 361 | unsigned subLen = Get16(p + 2); | ||
| 362 | unsigned printOffs = Get16(p + 4); | ||
| 363 | unsigned printLen = Get16(p + 6); | ||
| 364 | len -= 8; | ||
| 365 | p += 8; | ||
| 366 | |||
| 367 | // UInt32 Flags = 0; | ||
| 368 | if (Tag == _my_IO_REPARSE_TAG_SYMLINK) | ||
| 369 | { | ||
| 370 | if (len < 4) | ||
| 371 | return false; | ||
| 372 | // Flags = Get32(p); | ||
| 373 | len -= 4; | ||
| 374 | p += 4; | ||
| 375 | } | ||
| 376 | |||
| 377 | if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) | ||
| 378 | return false; | ||
| 379 | if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) | ||
| 380 | return false; | ||
| 381 | |||
| 382 | Offset = (unsigned)(p - start) + subOffs; | ||
| 383 | Size = subLen; | ||
| 384 | return true; | ||
| 385 | } | ||
| 386 | |||
| 387 | bool CReparseAttr::IsOkNamePair() const | ||
| 388 | { | ||
| 389 | if (IsLinkPrefix(SubsName)) | ||
| 390 | { | ||
| 391 | if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size))) | ||
| 392 | return PrintName.IsEmpty(); | ||
| 393 | if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0) | ||
| 394 | return true; | ||
| 395 | } | ||
| 396 | return wcscmp(SubsName, PrintName) == 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* | ||
| 400 | bool CReparseAttr::IsVolume() const | ||
| 401 | { | ||
| 402 | if (!IsLinkPrefix(SubsName)) | ||
| 403 | return false; | ||
| 404 | return IsVolumeName(SubsName.Ptr(k_LinkPrefix_Size)); | ||
| 405 | } | ||
| 406 | */ | ||
| 407 | |||
| 408 | UString CReparseAttr::GetPath() const | ||
| 409 | { | ||
| 410 | if (IsSymLink_WSL()) | ||
| 411 | { | ||
| 412 | UString u; | ||
| 413 | // if (CheckUTF8(attr.WslName) | ||
| 414 | if (!ConvertUTF8ToUnicode(WslName, u)) | ||
| 415 | MultiByteToUnicodeString2(u, WslName); | ||
| 416 | return u; | ||
| 417 | } | ||
| 418 | |||
| 419 | UString s (SubsName); | ||
| 420 | if (IsLinkPrefix(s)) | ||
| 421 | { | ||
| 422 | s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\" | ||
| 423 | if (IsDrivePath(s.Ptr(k_LinkPrefix_Size))) | ||
| 424 | s.DeleteFrontal(k_LinkPrefix_Size); | ||
| 425 | } | ||
| 426 | return s; | ||
| 427 | } | ||
| 428 | |||
| 429 | #ifdef SUPPORT_DEVICE_FILE | ||
| 430 | |||
| 431 | namespace NSystem | ||
| 432 | { | ||
| 433 | bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); | ||
| 434 | } | ||
| 435 | #endif // SUPPORT_DEVICE_FILE | ||
| 436 | |||
| 437 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 438 | |||
| 439 | namespace NIO { | ||
| 440 | |||
| 441 | bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo) | ||
| 442 | { | ||
| 443 | reparseData.Free(); | ||
| 444 | CInFile file; | ||
| 445 | if (!file.OpenReparse(path)) | ||
| 446 | return false; | ||
| 447 | |||
| 448 | if (fileInfo) | ||
| 449 | file.GetFileInformation(fileInfo); | ||
| 450 | |||
| 451 | const unsigned kBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; | ||
| 452 | CByteArr buf(kBufSize); | ||
| 453 | DWORD returnedSize; | ||
| 454 | if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize)) | ||
| 455 | return false; | ||
| 456 | reparseData.CopyFrom(buf, returnedSize); | ||
| 457 | return true; | ||
| 458 | } | ||
| 459 | |||
| 460 | static bool CreatePrefixDirOfFile(CFSTR path) | ||
| 461 | { | ||
| 462 | FString path2 (path); | ||
| 463 | int pos = path2.ReverseFind_PathSepar(); | ||
| 464 | if (pos < 0) | ||
| 465 | return true; | ||
| 466 | #ifdef _WIN32 | ||
| 467 | if (pos == 2 && path2[1] == L':') | ||
| 468 | return true; // we don't create Disk folder; | ||
| 469 | #endif | ||
| 470 | path2.DeleteFrom((unsigned)pos); | ||
| 471 | return NDir::CreateComplexDir(path2); | ||
| 472 | } | ||
| 473 | |||
| 474 | |||
| 475 | static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD size) | ||
| 476 | { | ||
| 477 | COutFile file; | ||
| 478 | if (!file.Open(path, | ||
| 479 | FILE_SHARE_WRITE, | ||
| 480 | OPEN_EXISTING, | ||
| 481 | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)) | ||
| 482 | return false; | ||
| 483 | |||
| 484 | DWORD returnedSize; | ||
| 485 | return file.DeviceIoControl(controlCode, data, size, NULL, 0, &returnedSize); | ||
| 486 | } | ||
| 487 | |||
| 488 | |||
| 489 | // If there is Reparse data already, it still writes new Reparse data | ||
| 490 | bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) | ||
| 491 | { | ||
| 492 | NFile::NFind::CFileInfo fi; | ||
| 493 | if (fi.Find(path)) | ||
| 494 | { | ||
| 495 | if (fi.IsDir() != isDir) | ||
| 496 | { | ||
| 497 | ::SetLastError(ERROR_DIRECTORY); | ||
| 498 | return false; | ||
| 499 | } | ||
| 500 | } | ||
| 501 | else | ||
| 502 | { | ||
| 503 | if (isDir) | ||
| 504 | { | ||
| 505 | if (!NDir::CreateComplexDir(path)) | ||
| 506 | return false; | ||
| 507 | } | ||
| 508 | else | ||
| 509 | { | ||
| 510 | CreatePrefixDirOfFile(path); | ||
| 511 | COutFile file; | ||
| 512 | if (!file.Create(path, CREATE_NEW)) | ||
| 513 | return false; | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | return OutIoReparseData(my_FSCTL_SET_REPARSE_POINT, path, (void *)(const Byte *)(data), size); | ||
| 518 | } | ||
| 519 | |||
| 520 | |||
| 521 | bool DeleteReparseData(CFSTR path) | ||
| 522 | { | ||
| 523 | CByteBuffer reparseData; | ||
| 524 | if (!GetReparseData(path, reparseData, NULL)) | ||
| 525 | return false; | ||
| 526 | /* MSDN: The tag specified in the ReparseTag member of this structure | ||
| 527 | must match the tag of the reparse point to be deleted, | ||
| 528 | and the ReparseDataLength member must be zero */ | ||
| 529 | #define my_REPARSE_DATA_BUFFER_HEADER_SIZE 8 | ||
| 530 | if (reparseData.Size() < my_REPARSE_DATA_BUFFER_HEADER_SIZE) | ||
| 531 | { | ||
| 532 | SetLastError(ERROR_INVALID_REPARSE_DATA); | ||
| 533 | return false; | ||
| 534 | } | ||
| 535 | BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE]; | ||
| 536 | memset(buf, 0, sizeof(buf)); | ||
| 537 | memcpy(buf, reparseData, 4); // tag | ||
| 538 | return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf)); | ||
| 539 | } | ||
| 540 | |||
| 541 | } | ||
| 542 | |||
| 543 | #endif // defined(_WIN32) && !defined(UNDER_CE) | ||
| 544 | |||
| 545 | |||
| 546 | #ifndef _WIN32 | ||
| 547 | |||
| 548 | namespace NIO { | ||
| 549 | |||
| 550 | bool GetReparseData(CFSTR path, CByteBuffer &reparseData) | ||
| 551 | { | ||
| 552 | reparseData.Free(); | ||
| 553 | |||
| 554 | #define MAX_PATHNAME_LEN 1024 | ||
| 555 | char buf[MAX_PATHNAME_LEN + 2]; | ||
| 556 | const size_t request = sizeof(buf) - 1; | ||
| 557 | |||
| 558 | // printf("\nreadlink() path = %s \n", path); | ||
| 559 | const ssize_t size = readlink(path, buf, request); | ||
| 560 | // there is no tail zero | ||
| 561 | |||
| 562 | if (size < 0) | ||
| 563 | return false; | ||
| 564 | if ((size_t)size >= request) | ||
| 565 | { | ||
| 566 | SetLastError(EINVAL); // check it: ENAMETOOLONG | ||
| 567 | return false; | ||
| 568 | } | ||
| 569 | |||
| 570 | // printf("\nreadlink() res = %s size = %d \n", buf, (int)size); | ||
| 571 | reparseData.CopyFrom((const Byte *)buf, (size_t)size); | ||
| 572 | return true; | ||
| 573 | } | ||
| 574 | |||
| 575 | |||
| 576 | /* | ||
| 577 | // If there is Reparse data already, it still writes new Reparse data | ||
| 578 | bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) | ||
| 579 | { | ||
| 580 | // AString s; | ||
| 581 | // s.SetFrom_CalcLen(data, size); | ||
| 582 | // return (symlink(s, path) == 0); | ||
| 583 | UNUSED_VAR(path) | ||
| 584 | UNUSED_VAR(isDir) | ||
| 585 | UNUSED_VAR(data) | ||
| 586 | UNUSED_VAR(size) | ||
| 587 | SetLastError(ENOSYS); | ||
| 588 | return false; | ||
| 589 | } | ||
| 590 | */ | ||
| 591 | |||
| 592 | bool SetSymLink(CFSTR from, CFSTR to) | ||
| 593 | { | ||
| 594 | // printf("\nsymlink() %s -> %s\n", from, to); | ||
| 595 | int ir; | ||
| 596 | // ir = unlink(path); | ||
| 597 | // if (ir == 0) | ||
| 598 | ir = symlink(to, from); | ||
| 599 | return (ir == 0); | ||
| 600 | } | ||
| 601 | |||
| 602 | bool SetSymLink_UString(CFSTR from, const UString &to) | ||
| 603 | { | ||
| 604 | AString utf; | ||
| 605 | ConvertUnicodeToUTF8(to, utf); | ||
| 606 | return SetSymLink(from, utf); | ||
| 607 | } | ||
| 608 | |||
| 609 | } | ||
| 610 | |||
| 611 | #endif // !_WIN32 | ||
| 612 | |||
| 613 | }} | ||
diff --git a/CPP/Windows/FileMapping.cpp b/CPP/Windows/FileMapping.cpp new file mode 100644 index 0000000..1933f7c --- /dev/null +++ b/CPP/Windows/FileMapping.cpp | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | // Windows/FileMapping.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "FileMapping.h" | ||
| 6 | |||
| 7 | namespace NWindows { | ||
| 8 | namespace NFile { | ||
| 9 | namespace NMapping { | ||
| 10 | |||
| 11 | |||
| 12 | }}} | ||
diff --git a/CPP/Windows/FileMapping.h b/CPP/Windows/FileMapping.h new file mode 100644 index 0000000..f90c429 --- /dev/null +++ b/CPP/Windows/FileMapping.h | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | // Windows/FileMapping.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_FILEMAPPING_H | ||
| 4 | #define __WINDOWS_FILEMAPPING_H | ||
| 5 | |||
| 6 | #include "../Common/MyTypes.h" | ||
| 7 | |||
| 8 | #include "Handle.h" | ||
| 9 | |||
| 10 | namespace NWindows { | ||
| 11 | |||
| 12 | class CFileMapping: public CHandle | ||
| 13 | { | ||
| 14 | public: | ||
| 15 | WRes Create(DWORD protect, UInt64 maxSize, LPCTSTR name) | ||
| 16 | { | ||
| 17 | _handle = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, protect, (DWORD)(maxSize >> 32), (DWORD)maxSize, name); | ||
| 18 | return ::GetLastError(); | ||
| 19 | } | ||
| 20 | |||
| 21 | WRes Open(DWORD | ||
| 22 | #ifndef UNDER_CE | ||
| 23 | desiredAccess | ||
| 24 | #endif | ||
| 25 | , LPCTSTR name) | ||
| 26 | { | ||
| 27 | #ifdef UNDER_CE | ||
| 28 | WRes res = Create(PAGE_READONLY, 0, name); | ||
| 29 | if (res == ERROR_ALREADY_EXISTS) | ||
| 30 | return 0; | ||
| 31 | Close(); | ||
| 32 | if (res == 0) | ||
| 33 | res = ERROR_FILE_NOT_FOUND; | ||
| 34 | return res; | ||
| 35 | #else | ||
| 36 | _handle = ::OpenFileMapping(desiredAccess, FALSE, name); | ||
| 37 | if (_handle != 0) | ||
| 38 | return 0; | ||
| 39 | return ::GetLastError(); | ||
| 40 | #endif | ||
| 41 | } | ||
| 42 | |||
| 43 | LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap) | ||
| 44 | { | ||
| 45 | return ::MapViewOfFile(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap); | ||
| 46 | } | ||
| 47 | |||
| 48 | #ifndef UNDER_CE | ||
| 49 | LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap, LPVOID baseAddress) | ||
| 50 | { | ||
| 51 | return ::MapViewOfFileEx(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap, baseAddress); | ||
| 52 | } | ||
| 53 | #endif | ||
| 54 | }; | ||
| 55 | |||
| 56 | class CFileUnmapper | ||
| 57 | { | ||
| 58 | const void *_data; | ||
| 59 | public: | ||
| 60 | CFileUnmapper(const void *data) : _data(data) {} | ||
| 61 | ~CFileUnmapper() { ::UnmapViewOfFile(_data); } | ||
| 62 | }; | ||
| 63 | |||
| 64 | } | ||
| 65 | |||
| 66 | #endif | ||
diff --git a/CPP/Windows/FileName.cpp b/CPP/Windows/FileName.cpp new file mode 100644 index 0000000..d61ff7e --- /dev/null +++ b/CPP/Windows/FileName.cpp | |||
| @@ -0,0 +1,893 @@ | |||
| 1 | // Windows/FileName.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef _WIN32 | ||
| 6 | #include <limits.h> | ||
| 7 | #include <unistd.h> | ||
| 8 | #include "../Common/StringConvert.h" | ||
| 9 | #include "FileDir.h" | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #include "FileName.h" | ||
| 13 | |||
| 14 | #ifndef _UNICODE | ||
| 15 | extern bool g_IsNT; | ||
| 16 | #endif | ||
| 17 | |||
| 18 | namespace NWindows { | ||
| 19 | namespace NFile { | ||
| 20 | namespace NName { | ||
| 21 | |||
| 22 | #define IS_SEPAR(c) IS_PATH_SEPAR(c) | ||
| 23 | |||
| 24 | int FindSepar(const wchar_t *s) throw() | ||
| 25 | { | ||
| 26 | for (const wchar_t *p = s;; p++) | ||
| 27 | { | ||
| 28 | const wchar_t c = *p; | ||
| 29 | if (c == 0) | ||
| 30 | return -1; | ||
| 31 | if (IS_SEPAR(c)) | ||
| 32 | return (int)(p - s); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | #ifndef USE_UNICODE_FSTRING | ||
| 37 | int FindSepar(const FChar *s) throw() | ||
| 38 | { | ||
| 39 | for (const FChar *p = s;; p++) | ||
| 40 | { | ||
| 41 | const FChar c = *p; | ||
| 42 | if (c == 0) | ||
| 43 | return -1; | ||
| 44 | if (IS_SEPAR(c)) | ||
| 45 | return (int)(p - s); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | #endif | ||
| 49 | |||
| 50 | #ifndef USE_UNICODE_FSTRING | ||
| 51 | void NormalizeDirPathPrefix(FString &dirPath) | ||
| 52 | { | ||
| 53 | if (dirPath.IsEmpty()) | ||
| 54 | return; | ||
| 55 | if (!IsPathSepar(dirPath.Back())) | ||
| 56 | dirPath.Add_PathSepar(); | ||
| 57 | } | ||
| 58 | #endif | ||
| 59 | |||
| 60 | void NormalizeDirPathPrefix(UString &dirPath) | ||
| 61 | { | ||
| 62 | if (dirPath.IsEmpty()) | ||
| 63 | return; | ||
| 64 | if (!IsPathSepar(dirPath.Back())) | ||
| 65 | dirPath.Add_PathSepar(); | ||
| 66 | } | ||
| 67 | |||
| 68 | #ifdef _WIN32 | ||
| 69 | |||
| 70 | #ifndef USE_UNICODE_FSTRING | ||
| 71 | #ifdef WIN_LONG_PATH | ||
| 72 | static void NormalizeDirSeparators(UString &s) | ||
| 73 | { | ||
| 74 | const unsigned len = s.Len(); | ||
| 75 | for (unsigned i = 0; i < len; i++) | ||
| 76 | if (s[i] == '/') | ||
| 77 | s.ReplaceOneCharAtPos(i, WCHAR_PATH_SEPARATOR); | ||
| 78 | } | ||
| 79 | #endif | ||
| 80 | #endif | ||
| 81 | |||
| 82 | void NormalizeDirSeparators(FString &s) | ||
| 83 | { | ||
| 84 | const unsigned len = s.Len(); | ||
| 85 | for (unsigned i = 0; i < len; i++) | ||
| 86 | if (s[i] == '/') | ||
| 87 | s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR); | ||
| 88 | } | ||
| 89 | |||
| 90 | #endif | ||
| 91 | |||
| 92 | |||
| 93 | #define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) | ||
| 94 | |||
| 95 | bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } | ||
| 96 | |||
| 97 | bool IsAltPathPrefix(CFSTR s) throw() | ||
| 98 | { | ||
| 99 | unsigned len = MyStringLen(s); | ||
| 100 | if (len == 0) | ||
| 101 | return false; | ||
| 102 | if (s[len - 1] != ':') | ||
| 103 | return false; | ||
| 104 | |||
| 105 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 106 | if (IsDevicePath(s)) | ||
| 107 | return false; | ||
| 108 | if (IsSuperPath(s)) | ||
| 109 | { | ||
| 110 | s += kSuperPathPrefixSize; | ||
| 111 | len -= kSuperPathPrefixSize; | ||
| 112 | } | ||
| 113 | if (len == 2 && IsDrivePath2(s)) | ||
| 114 | return false; | ||
| 115 | #endif | ||
| 116 | |||
| 117 | return true; | ||
| 118 | } | ||
| 119 | |||
| 120 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 121 | |||
| 122 | const char * const kSuperPathPrefix = "\\\\?\\"; | ||
| 123 | #ifdef WIN_LONG_PATH | ||
| 124 | static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; | ||
| 125 | #endif | ||
| 126 | |||
| 127 | #define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3])) | ||
| 128 | #define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3])) | ||
| 129 | #define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3])) | ||
| 130 | |||
| 131 | #define IS_UNC_WITH_SLASH(s) ( \ | ||
| 132 | ((s)[0] == 'U' || (s)[0] == 'u') \ | ||
| 133 | && ((s)[1] == 'N' || (s)[1] == 'n') \ | ||
| 134 | && ((s)[2] == 'C' || (s)[2] == 'c') \ | ||
| 135 | && IS_SEPAR((s)[3])) | ||
| 136 | |||
| 137 | bool IsDevicePath(CFSTR s) throw() | ||
| 138 | { | ||
| 139 | #ifdef UNDER_CE | ||
| 140 | |||
| 141 | s = s; | ||
| 142 | return false; | ||
| 143 | /* | ||
| 144 | // actually we don't know the way to open device file in WinCE. | ||
| 145 | unsigned len = MyStringLen(s); | ||
| 146 | if (len < 5 || len > 5 || !IsString1PrefixedByString2(s, "DSK")) | ||
| 147 | return false; | ||
| 148 | if (s[4] != ':') | ||
| 149 | return false; | ||
| 150 | // for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ)); | ||
| 151 | */ | ||
| 152 | |||
| 153 | #else | ||
| 154 | |||
| 155 | if (!IS_DEVICE_PATH(s)) | ||
| 156 | return false; | ||
| 157 | unsigned len = MyStringLen(s); | ||
| 158 | if (len == 6 && s[5] == ':') | ||
| 159 | return true; | ||
| 160 | if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive")) | ||
| 161 | return false; | ||
| 162 | for (unsigned i = 17; i < len; i++) | ||
| 163 | if (s[i] < '0' || s[i] > '9') | ||
| 164 | return false; | ||
| 165 | return true; | ||
| 166 | |||
| 167 | #endif | ||
| 168 | } | ||
| 169 | |||
| 170 | bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } | ||
| 171 | bool IsNetworkPath(CFSTR s) throw() | ||
| 172 | { | ||
| 173 | if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) | ||
| 174 | return false; | ||
| 175 | if (IsSuperUncPath(s)) | ||
| 176 | return true; | ||
| 177 | FChar c = s[2]; | ||
| 178 | return (c != '.' && c != '?'); | ||
| 179 | } | ||
| 180 | |||
| 181 | unsigned GetNetworkServerPrefixSize(CFSTR s) throw() | ||
| 182 | { | ||
| 183 | if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) | ||
| 184 | return 0; | ||
| 185 | unsigned prefixSize = 2; | ||
| 186 | if (IsSuperUncPath(s)) | ||
| 187 | prefixSize = kSuperUncPathPrefixSize; | ||
| 188 | else | ||
| 189 | { | ||
| 190 | FChar c = s[2]; | ||
| 191 | if (c == '.' || c == '?') | ||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | int pos = FindSepar(s + prefixSize); | ||
| 195 | if (pos < 0) | ||
| 196 | return 0; | ||
| 197 | return prefixSize + (unsigned)(pos + 1); | ||
| 198 | } | ||
| 199 | |||
| 200 | bool IsNetworkShareRootPath(CFSTR s) throw() | ||
| 201 | { | ||
| 202 | unsigned prefixSize = GetNetworkServerPrefixSize(s); | ||
| 203 | if (prefixSize == 0) | ||
| 204 | return false; | ||
| 205 | s += prefixSize; | ||
| 206 | int pos = FindSepar(s); | ||
| 207 | if (pos < 0) | ||
| 208 | return true; | ||
| 209 | return s[(unsigned)pos + 1] == 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | static const unsigned kDrivePrefixSize = 3; /* c:\ */ | ||
| 213 | |||
| 214 | bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } | ||
| 215 | // bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } | ||
| 216 | bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); } | ||
| 217 | bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } | ||
| 218 | // bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } | ||
| 219 | |||
| 220 | #ifndef USE_UNICODE_FSTRING | ||
| 221 | bool IsDrivePath2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } | ||
| 222 | // bool IsDriveName2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } | ||
| 223 | bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } | ||
| 224 | bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); } | ||
| 225 | bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } | ||
| 226 | #endif // USE_UNICODE_FSTRING | ||
| 227 | |||
| 228 | bool IsDrivePath_SuperAllowed(CFSTR s) throw() | ||
| 229 | { | ||
| 230 | if (IsSuperPath(s)) | ||
| 231 | s += kSuperPathPrefixSize; | ||
| 232 | return IsDrivePath(s); | ||
| 233 | } | ||
| 234 | |||
| 235 | bool IsDriveRootPath_SuperAllowed(CFSTR s) throw() | ||
| 236 | { | ||
| 237 | if (IsSuperPath(s)) | ||
| 238 | s += kSuperPathPrefixSize; | ||
| 239 | return IsDrivePath(s) && s[kDrivePrefixSize] == 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | bool IsAbsolutePath(const wchar_t *s) throw() | ||
| 243 | { | ||
| 244 | return IS_SEPAR(s[0]) || IsDrivePath2(s); | ||
| 245 | } | ||
| 246 | |||
| 247 | int FindAltStreamColon(CFSTR path) throw() | ||
| 248 | { | ||
| 249 | unsigned i = 0; | ||
| 250 | if (IsDrivePath2(path)) | ||
| 251 | i = 2; | ||
| 252 | int colonPos = -1; | ||
| 253 | for (;; i++) | ||
| 254 | { | ||
| 255 | FChar c = path[i]; | ||
| 256 | if (c == 0) | ||
| 257 | return colonPos; | ||
| 258 | if (c == ':') | ||
| 259 | { | ||
| 260 | if (colonPos < 0) | ||
| 261 | colonPos = (int)i; | ||
| 262 | continue; | ||
| 263 | } | ||
| 264 | if (IS_SEPAR(c)) | ||
| 265 | colonPos = -1; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | #ifndef USE_UNICODE_FSTRING | ||
| 270 | |||
| 271 | static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s) | ||
| 272 | { | ||
| 273 | // Network path: we look "server\path\" as root prefix | ||
| 274 | int pos = FindSepar(s); | ||
| 275 | if (pos < 0) | ||
| 276 | return 0; | ||
| 277 | int pos2 = FindSepar(s + (unsigned)pos + 1); | ||
| 278 | if (pos2 < 0) | ||
| 279 | return 0; | ||
| 280 | return pos + pos2 + 2; | ||
| 281 | } | ||
| 282 | |||
| 283 | static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s) | ||
| 284 | { | ||
| 285 | if (IsDrivePath(s)) | ||
| 286 | return kDrivePrefixSize; | ||
| 287 | if (!IS_SEPAR(s[0])) | ||
| 288 | return 0; | ||
| 289 | if (s[1] == 0 || !IS_SEPAR(s[1])) | ||
| 290 | return 1; | ||
| 291 | unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); | ||
| 292 | return (size == 0) ? 0 : 2 + size; | ||
| 293 | } | ||
| 294 | |||
| 295 | static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s) | ||
| 296 | { | ||
| 297 | if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) | ||
| 298 | { | ||
| 299 | unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); | ||
| 300 | return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; | ||
| 301 | } | ||
| 302 | // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" | ||
| 303 | int pos = FindSepar(s + kSuperPathPrefixSize); | ||
| 304 | if (pos < 0) | ||
| 305 | return 0; | ||
| 306 | return kSuperPathPrefixSize + pos + 1; | ||
| 307 | } | ||
| 308 | |||
| 309 | unsigned GetRootPrefixSize(CFSTR s) throw() | ||
| 310 | { | ||
| 311 | if (IS_DEVICE_PATH(s)) | ||
| 312 | return kDevicePathPrefixSize; | ||
| 313 | if (IsSuperPath(s)) | ||
| 314 | return GetRootPrefixSize_Of_SuperPath(s); | ||
| 315 | return GetRootPrefixSize_Of_SimplePath(s); | ||
| 316 | } | ||
| 317 | |||
| 318 | #endif // USE_UNICODE_FSTRING | ||
| 319 | |||
| 320 | static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() | ||
| 321 | { | ||
| 322 | // Network path: we look "server\path\" as root prefix | ||
| 323 | int pos = FindSepar(s); | ||
| 324 | if (pos < 0) | ||
| 325 | return 0; | ||
| 326 | int pos2 = FindSepar(s + (unsigned)pos + 1); | ||
| 327 | if (pos2 < 0) | ||
| 328 | return 0; | ||
| 329 | return (unsigned)(pos + pos2 + 2); | ||
| 330 | } | ||
| 331 | |||
| 332 | static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw() | ||
| 333 | { | ||
| 334 | if (IsDrivePath(s)) | ||
| 335 | return kDrivePrefixSize; | ||
| 336 | if (!IS_SEPAR(s[0])) | ||
| 337 | return 0; | ||
| 338 | if (s[1] == 0 || !IS_SEPAR(s[1])) | ||
| 339 | return 1; | ||
| 340 | unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); | ||
| 341 | return (size == 0) ? 0 : 2 + size; | ||
| 342 | } | ||
| 343 | |||
| 344 | static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw() | ||
| 345 | { | ||
| 346 | if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) | ||
| 347 | { | ||
| 348 | unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); | ||
| 349 | return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; | ||
| 350 | } | ||
| 351 | // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" | ||
| 352 | int pos = FindSepar(s + kSuperPathPrefixSize); | ||
| 353 | if (pos < 0) | ||
| 354 | return 0; | ||
| 355 | return kSuperPathPrefixSize + (unsigned)(pos + 1); | ||
| 356 | } | ||
| 357 | |||
| 358 | unsigned GetRootPrefixSize(const wchar_t *s) throw() | ||
| 359 | { | ||
| 360 | if (IS_DEVICE_PATH(s)) | ||
| 361 | return kDevicePathPrefixSize; | ||
| 362 | if (IsSuperPath(s)) | ||
| 363 | return GetRootPrefixSize_Of_SuperPath(s); | ||
| 364 | return GetRootPrefixSize_Of_SimplePath(s); | ||
| 365 | } | ||
| 366 | |||
| 367 | #else // _WIN32 | ||
| 368 | |||
| 369 | bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } | ||
| 370 | |||
| 371 | #ifndef USE_UNICODE_FSTRING | ||
| 372 | unsigned GetRootPrefixSize(CFSTR s) throw(); | ||
| 373 | unsigned GetRootPrefixSize(CFSTR s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } | ||
| 374 | #endif | ||
| 375 | unsigned GetRootPrefixSize(const wchar_t *s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } | ||
| 376 | |||
| 377 | #endif // _WIN32 | ||
| 378 | |||
| 379 | |||
| 380 | #ifndef UNDER_CE | ||
| 381 | |||
| 382 | static bool GetCurDir(UString &path) | ||
| 383 | { | ||
| 384 | path.Empty(); | ||
| 385 | |||
| 386 | #ifdef _WIN32 | ||
| 387 | |||
| 388 | DWORD needLength; | ||
| 389 | #ifndef _UNICODE | ||
| 390 | if (!g_IsNT) | ||
| 391 | { | ||
| 392 | TCHAR s[MAX_PATH + 2]; | ||
| 393 | s[0] = 0; | ||
| 394 | needLength = ::GetCurrentDirectory(MAX_PATH + 1, s); | ||
| 395 | path = fs2us(fas2fs(s)); | ||
| 396 | } | ||
| 397 | else | ||
| 398 | #endif | ||
| 399 | { | ||
| 400 | WCHAR s[MAX_PATH + 2]; | ||
| 401 | s[0] = 0; | ||
| 402 | needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s); | ||
| 403 | path = s; | ||
| 404 | } | ||
| 405 | return (needLength > 0 && needLength <= MAX_PATH); | ||
| 406 | |||
| 407 | #else | ||
| 408 | |||
| 409 | FString s; | ||
| 410 | if (!NDir::GetCurrentDir(s)) | ||
| 411 | return false; | ||
| 412 | path = GetUnicodeString(s); | ||
| 413 | return true; | ||
| 414 | |||
| 415 | #endif | ||
| 416 | } | ||
| 417 | |||
| 418 | static bool ResolveDotsFolders(UString &s) | ||
| 419 | { | ||
| 420 | #ifdef _WIN32 | ||
| 421 | // s.Replace(L'/', WCHAR_PATH_SEPARATOR); | ||
| 422 | #endif | ||
| 423 | |||
| 424 | for (unsigned i = 0;;) | ||
| 425 | { | ||
| 426 | const wchar_t c = s[i]; | ||
| 427 | if (c == 0) | ||
| 428 | return true; | ||
| 429 | if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) | ||
| 430 | { | ||
| 431 | const wchar_t c1 = s[i + 1]; | ||
| 432 | if (c1 == '.') | ||
| 433 | { | ||
| 434 | const wchar_t c2 = s[i + 2]; | ||
| 435 | if (IS_SEPAR(c2) || c2 == 0) | ||
| 436 | { | ||
| 437 | if (i == 0) | ||
| 438 | return false; | ||
| 439 | int k = (int)i - 2; | ||
| 440 | i += 2; | ||
| 441 | |||
| 442 | for (;; k--) | ||
| 443 | { | ||
| 444 | if (k < 0) | ||
| 445 | return false; | ||
| 446 | if (!IS_SEPAR(s[(unsigned)k])) | ||
| 447 | break; | ||
| 448 | } | ||
| 449 | |||
| 450 | do | ||
| 451 | k--; | ||
| 452 | while (k >= 0 && !IS_SEPAR(s[(unsigned)k])); | ||
| 453 | |||
| 454 | unsigned num; | ||
| 455 | |||
| 456 | if (k >= 0) | ||
| 457 | { | ||
| 458 | num = i - (unsigned)k; | ||
| 459 | i = (unsigned)k; | ||
| 460 | } | ||
| 461 | else | ||
| 462 | { | ||
| 463 | num = (c2 == 0 ? i : (i + 1)); | ||
| 464 | i = 0; | ||
| 465 | } | ||
| 466 | |||
| 467 | s.Delete(i, num); | ||
| 468 | continue; | ||
| 469 | } | ||
| 470 | } | ||
| 471 | else if (IS_SEPAR(c1) || c1 == 0) | ||
| 472 | { | ||
| 473 | unsigned num = 2; | ||
| 474 | if (i != 0) | ||
| 475 | i--; | ||
| 476 | else if (c1 == 0) | ||
| 477 | num = 1; | ||
| 478 | s.Delete(i, num); | ||
| 479 | continue; | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | i++; | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | #endif // UNDER_CE | ||
| 488 | |||
| 489 | #define LONG_PATH_DOTS_FOLDERS_PARSING | ||
| 490 | |||
| 491 | |||
| 492 | /* | ||
| 493 | Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\ | ||
| 494 | To solve that problem we check such path: | ||
| 495 | - super path contains "." or ".." - we use kSuperPathType_UseOnlySuper | ||
| 496 | - super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain | ||
| 497 | */ | ||
| 498 | #ifdef LONG_PATH_DOTS_FOLDERS_PARSING | ||
| 499 | #ifndef UNDER_CE | ||
| 500 | static bool AreThereDotsFolders(CFSTR s) | ||
| 501 | { | ||
| 502 | for (unsigned i = 0;; i++) | ||
| 503 | { | ||
| 504 | FChar c = s[i]; | ||
| 505 | if (c == 0) | ||
| 506 | return false; | ||
| 507 | if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) | ||
| 508 | { | ||
| 509 | FChar c1 = s[i + 1]; | ||
| 510 | if (c1 == 0 || IS_SEPAR(c1) || | ||
| 511 | (c1 == '.' && (s[i + 2] == 0 || IS_SEPAR(s[i + 2])))) | ||
| 512 | return true; | ||
| 513 | } | ||
| 514 | } | ||
| 515 | } | ||
| 516 | #endif | ||
| 517 | #endif // LONG_PATH_DOTS_FOLDERS_PARSING | ||
| 518 | |||
| 519 | #ifdef WIN_LONG_PATH | ||
| 520 | |||
| 521 | /* | ||
| 522 | Most of Windows versions have problems, if some file or dir name | ||
| 523 | contains '.' or ' ' at the end of name (Bad Path). | ||
| 524 | To solve that problem, we always use Super Path ("\\?\" prefix and full path) | ||
| 525 | in such cases. Note that "." and ".." are not bad names. | ||
| 526 | |||
| 527 | There are 3 cases: | ||
| 528 | 1) If the path is already Super Path, we use that path | ||
| 529 | 2) If the path is not Super Path : | ||
| 530 | 2.1) Bad Path; we use only Super Path. | ||
| 531 | 2.2) Good Path; we use Main Path. If it fails, we use Super Path. | ||
| 532 | |||
| 533 | NeedToUseOriginalPath returns: | ||
| 534 | kSuperPathType_UseOnlyMain : Super already | ||
| 535 | kSuperPathType_UseOnlySuper : not Super, Bad Path | ||
| 536 | kSuperPathType_UseMainAndSuper : not Super, Good Path | ||
| 537 | */ | ||
| 538 | |||
| 539 | int GetUseSuperPathType(CFSTR s) throw() | ||
| 540 | { | ||
| 541 | if (IsSuperOrDevicePath(s)) | ||
| 542 | { | ||
| 543 | #ifdef LONG_PATH_DOTS_FOLDERS_PARSING | ||
| 544 | if ((s)[2] != '.') | ||
| 545 | if (AreThereDotsFolders(s + kSuperPathPrefixSize)) | ||
| 546 | return kSuperPathType_UseOnlySuper; | ||
| 547 | #endif | ||
| 548 | return kSuperPathType_UseOnlyMain; | ||
| 549 | } | ||
| 550 | |||
| 551 | for (unsigned i = 0;; i++) | ||
| 552 | { | ||
| 553 | FChar c = s[i]; | ||
| 554 | if (c == 0) | ||
| 555 | return kSuperPathType_UseMainAndSuper; | ||
| 556 | if (c == '.' || c == ' ') | ||
| 557 | { | ||
| 558 | FChar c2 = s[i + 1]; | ||
| 559 | if (c2 == 0 || IS_SEPAR(c2)) | ||
| 560 | { | ||
| 561 | // if it's "." or "..", it's not bad name. | ||
| 562 | if (c == '.') | ||
| 563 | { | ||
| 564 | if (i == 0 || IS_SEPAR(s[i - 1])) | ||
| 565 | continue; | ||
| 566 | if (s[i - 1] == '.') | ||
| 567 | { | ||
| 568 | if (i - 1 == 0 || IS_SEPAR(s[i - 2])) | ||
| 569 | continue; | ||
| 570 | } | ||
| 571 | } | ||
| 572 | return kSuperPathType_UseOnlySuper; | ||
| 573 | } | ||
| 574 | } | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | |||
| 579 | |||
| 580 | /* | ||
| 581 | returns false in two cases: | ||
| 582 | - if GetCurDir was used, and GetCurDir returned error. | ||
| 583 | - if we can't resolve ".." name. | ||
| 584 | if path is ".", "..", res is empty. | ||
| 585 | if it's Super Path already, res is empty. | ||
| 586 | for \**** , and if GetCurDir is not drive (c:\), res is empty | ||
| 587 | for absolute paths, returns true, res is Super path. | ||
| 588 | */ | ||
| 589 | |||
| 590 | static bool GetSuperPathBase(CFSTR s, UString &res) | ||
| 591 | { | ||
| 592 | res.Empty(); | ||
| 593 | |||
| 594 | FChar c = s[0]; | ||
| 595 | if (c == 0) | ||
| 596 | return true; | ||
| 597 | if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) | ||
| 598 | return true; | ||
| 599 | |||
| 600 | if (IsSuperOrDevicePath(s)) | ||
| 601 | { | ||
| 602 | #ifdef LONG_PATH_DOTS_FOLDERS_PARSING | ||
| 603 | |||
| 604 | if ((s)[2] == '.') | ||
| 605 | return true; | ||
| 606 | |||
| 607 | // we will return true here, so we will try to use these problem paths. | ||
| 608 | |||
| 609 | if (!AreThereDotsFolders(s + kSuperPathPrefixSize)) | ||
| 610 | return true; | ||
| 611 | |||
| 612 | UString temp = fs2us(s); | ||
| 613 | unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp); | ||
| 614 | if (fixedSize == 0) | ||
| 615 | return true; | ||
| 616 | |||
| 617 | UString rem = &temp[fixedSize]; | ||
| 618 | if (!ResolveDotsFolders(rem)) | ||
| 619 | return true; | ||
| 620 | |||
| 621 | temp.DeleteFrom(fixedSize); | ||
| 622 | res += temp; | ||
| 623 | res += rem; | ||
| 624 | |||
| 625 | #endif | ||
| 626 | |||
| 627 | return true; | ||
| 628 | } | ||
| 629 | |||
| 630 | if (IS_SEPAR(c)) | ||
| 631 | { | ||
| 632 | if (IS_SEPAR(s[1])) | ||
| 633 | { | ||
| 634 | UString temp = fs2us(s + 2); | ||
| 635 | unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp); | ||
| 636 | // we ignore that error to allow short network paths server\share? | ||
| 637 | /* | ||
| 638 | if (fixedSize == 0) | ||
| 639 | return false; | ||
| 640 | */ | ||
| 641 | UString rem = &temp[fixedSize]; | ||
| 642 | if (!ResolveDotsFolders(rem)) | ||
| 643 | return false; | ||
| 644 | res += kSuperUncPrefix; | ||
| 645 | temp.DeleteFrom(fixedSize); | ||
| 646 | res += temp; | ||
| 647 | res += rem; | ||
| 648 | return true; | ||
| 649 | } | ||
| 650 | } | ||
| 651 | else | ||
| 652 | { | ||
| 653 | if (IsDrivePath2(s)) | ||
| 654 | { | ||
| 655 | UString temp = fs2us(s); | ||
| 656 | unsigned prefixSize = 2; | ||
| 657 | if (IsDrivePath(s)) | ||
| 658 | prefixSize = kDrivePrefixSize; | ||
| 659 | UString rem = temp.Ptr(prefixSize); | ||
| 660 | if (!ResolveDotsFolders(rem)) | ||
| 661 | return true; | ||
| 662 | res += kSuperPathPrefix; | ||
| 663 | temp.DeleteFrom(prefixSize); | ||
| 664 | res += temp; | ||
| 665 | res += rem; | ||
| 666 | return true; | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 670 | UString curDir; | ||
| 671 | if (!GetCurDir(curDir)) | ||
| 672 | return false; | ||
| 673 | NormalizeDirPathPrefix(curDir); | ||
| 674 | |||
| 675 | unsigned fixedSizeStart = 0; | ||
| 676 | unsigned fixedSize = 0; | ||
| 677 | const char *superMarker = NULL; | ||
| 678 | if (IsSuperPath(curDir)) | ||
| 679 | { | ||
| 680 | fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); | ||
| 681 | if (fixedSize == 0) | ||
| 682 | return false; | ||
| 683 | } | ||
| 684 | else | ||
| 685 | { | ||
| 686 | if (IsDrivePath(curDir)) | ||
| 687 | { | ||
| 688 | superMarker = kSuperPathPrefix; | ||
| 689 | fixedSize = kDrivePrefixSize; | ||
| 690 | } | ||
| 691 | else | ||
| 692 | { | ||
| 693 | if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) | ||
| 694 | return false; | ||
| 695 | fixedSizeStart = 2; | ||
| 696 | fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); | ||
| 697 | if (fixedSize == 0) | ||
| 698 | return false; | ||
| 699 | superMarker = kSuperUncPrefix; | ||
| 700 | } | ||
| 701 | } | ||
| 702 | |||
| 703 | UString temp; | ||
| 704 | if (IS_SEPAR(c)) | ||
| 705 | { | ||
| 706 | temp = fs2us(s + 1); | ||
| 707 | } | ||
| 708 | else | ||
| 709 | { | ||
| 710 | temp += &curDir[fixedSizeStart + fixedSize]; | ||
| 711 | temp += fs2us(s); | ||
| 712 | } | ||
| 713 | if (!ResolveDotsFolders(temp)) | ||
| 714 | return false; | ||
| 715 | if (superMarker) | ||
| 716 | res += superMarker; | ||
| 717 | res += curDir.Mid(fixedSizeStart, fixedSize); | ||
| 718 | res += temp; | ||
| 719 | return true; | ||
| 720 | } | ||
| 721 | |||
| 722 | |||
| 723 | /* | ||
| 724 | In that case if GetSuperPathBase doesn't return new path, we don't need | ||
| 725 | to use same path that was used as main path | ||
| 726 | |||
| 727 | GetSuperPathBase superPath.IsEmpty() onlyIfNew | ||
| 728 | false * * GetCurDir Error | ||
| 729 | true false * use Super path | ||
| 730 | true true true don't use any path, we already used mainPath | ||
| 731 | true true false use main path as Super Path, we don't try mainMath | ||
| 732 | That case is possible now if GetCurDir returns unknown | ||
| 733 | type of path (not drive and not network) | ||
| 734 | |||
| 735 | We can change that code if we want to try mainPath, if GetSuperPathBase returns error, | ||
| 736 | and we didn't try mainPath still. | ||
| 737 | If we want to work that way, we don't need to use GetSuperPathBase return code. | ||
| 738 | */ | ||
| 739 | |||
| 740 | bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew) | ||
| 741 | { | ||
| 742 | if (GetSuperPathBase(path, superPath)) | ||
| 743 | { | ||
| 744 | if (superPath.IsEmpty()) | ||
| 745 | { | ||
| 746 | // actually the only possible when onlyIfNew == true and superPath is empty | ||
| 747 | // is case when | ||
| 748 | |||
| 749 | if (onlyIfNew) | ||
| 750 | return false; | ||
| 751 | superPath = fs2us(path); | ||
| 752 | } | ||
| 753 | |||
| 754 | NormalizeDirSeparators(superPath); | ||
| 755 | return true; | ||
| 756 | } | ||
| 757 | return false; | ||
| 758 | } | ||
| 759 | |||
| 760 | bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew) | ||
| 761 | { | ||
| 762 | if (!GetSuperPathBase(s1, d1) || | ||
| 763 | !GetSuperPathBase(s2, d2)) | ||
| 764 | return false; | ||
| 765 | |||
| 766 | NormalizeDirSeparators(d1); | ||
| 767 | NormalizeDirSeparators(d2); | ||
| 768 | |||
| 769 | if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew) | ||
| 770 | return false; | ||
| 771 | if (d1.IsEmpty()) d1 = fs2us(s1); | ||
| 772 | if (d2.IsEmpty()) d2 = fs2us(s2); | ||
| 773 | return true; | ||
| 774 | } | ||
| 775 | |||
| 776 | |||
| 777 | /* | ||
| 778 | // returns true, if we need additional use with New Super path. | ||
| 779 | bool GetSuperPath(CFSTR path, UString &superPath) | ||
| 780 | { | ||
| 781 | if (GetSuperPathBase(path, superPath)) | ||
| 782 | return !superPath.IsEmpty(); | ||
| 783 | return false; | ||
| 784 | } | ||
| 785 | */ | ||
| 786 | #endif // WIN_LONG_PATH | ||
| 787 | |||
| 788 | bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res) | ||
| 789 | { | ||
| 790 | res = s; | ||
| 791 | |||
| 792 | #ifdef UNDER_CE | ||
| 793 | |||
| 794 | if (!IS_SEPAR(s[0])) | ||
| 795 | { | ||
| 796 | if (!dirPrefix) | ||
| 797 | return false; | ||
| 798 | res = dirPrefix; | ||
| 799 | res += s; | ||
| 800 | } | ||
| 801 | |||
| 802 | #else | ||
| 803 | |||
| 804 | unsigned prefixSize = GetRootPrefixSize(s); | ||
| 805 | if (prefixSize != 0) | ||
| 806 | { | ||
| 807 | if (!AreThereDotsFolders(s + prefixSize)) | ||
| 808 | return true; | ||
| 809 | |||
| 810 | UString rem = fs2us(s + prefixSize); | ||
| 811 | if (!ResolveDotsFolders(rem)) | ||
| 812 | return true; // maybe false; | ||
| 813 | res.DeleteFrom(prefixSize); | ||
| 814 | res += us2fs(rem); | ||
| 815 | return true; | ||
| 816 | } | ||
| 817 | |||
| 818 | /* | ||
| 819 | FChar c = s[0]; | ||
| 820 | if (c == 0) | ||
| 821 | return true; | ||
| 822 | if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) | ||
| 823 | return true; | ||
| 824 | if (IS_SEPAR(c) && IS_SEPAR(s[1])) | ||
| 825 | return true; | ||
| 826 | if (IsDrivePath(s)) | ||
| 827 | return true; | ||
| 828 | */ | ||
| 829 | |||
| 830 | UString curDir; | ||
| 831 | if (dirPrefix) | ||
| 832 | curDir = fs2us(dirPrefix); | ||
| 833 | else | ||
| 834 | { | ||
| 835 | if (!GetCurDir(curDir)) | ||
| 836 | return false; | ||
| 837 | } | ||
| 838 | NormalizeDirPathPrefix(curDir); | ||
| 839 | |||
| 840 | unsigned fixedSize = 0; | ||
| 841 | |||
| 842 | #ifdef _WIN32 | ||
| 843 | |||
| 844 | if (IsSuperPath(curDir)) | ||
| 845 | { | ||
| 846 | fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); | ||
| 847 | if (fixedSize == 0) | ||
| 848 | return false; | ||
| 849 | } | ||
| 850 | else | ||
| 851 | { | ||
| 852 | if (IsDrivePath(curDir)) | ||
| 853 | fixedSize = kDrivePrefixSize; | ||
| 854 | else | ||
| 855 | { | ||
| 856 | if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) | ||
| 857 | return false; | ||
| 858 | fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); | ||
| 859 | if (fixedSize == 0) | ||
| 860 | return false; | ||
| 861 | fixedSize += 2; | ||
| 862 | } | ||
| 863 | } | ||
| 864 | |||
| 865 | #endif // _WIN32 | ||
| 866 | |||
| 867 | UString temp; | ||
| 868 | if (IS_SEPAR(s[0])) | ||
| 869 | { | ||
| 870 | temp = fs2us(s + 1); | ||
| 871 | } | ||
| 872 | else | ||
| 873 | { | ||
| 874 | temp += curDir.Ptr(fixedSize); | ||
| 875 | temp += fs2us(s); | ||
| 876 | } | ||
| 877 | if (!ResolveDotsFolders(temp)) | ||
| 878 | return false; | ||
| 879 | curDir.DeleteFrom(fixedSize); | ||
| 880 | res = us2fs(curDir); | ||
| 881 | res += us2fs(temp); | ||
| 882 | |||
| 883 | #endif // UNDER_CE | ||
| 884 | |||
| 885 | return true; | ||
| 886 | } | ||
| 887 | |||
| 888 | bool GetFullPath(CFSTR path, FString &fullPath) | ||
| 889 | { | ||
| 890 | return GetFullPath(NULL, path, fullPath); | ||
| 891 | } | ||
| 892 | |||
| 893 | }}} | ||
diff --git a/CPP/Windows/FileName.h b/CPP/Windows/FileName.h new file mode 100644 index 0000000..de8bd13 --- /dev/null +++ b/CPP/Windows/FileName.h | |||
| @@ -0,0 +1,119 @@ | |||
| 1 | // Windows/FileName.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_FILE_NAME_H | ||
| 4 | #define __WINDOWS_FILE_NAME_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NFile { | ||
| 10 | namespace NName { | ||
| 11 | |||
| 12 | int FindSepar(const wchar_t *s) throw(); | ||
| 13 | #ifndef USE_UNICODE_FSTRING | ||
| 14 | int FindSepar(const FChar *s) throw(); | ||
| 15 | #endif | ||
| 16 | |||
| 17 | void NormalizeDirPathPrefix(FString &dirPath); // ensures that it ended with '\\', if dirPath is not epmty | ||
| 18 | void NormalizeDirPathPrefix(UString &dirPath); | ||
| 19 | |||
| 20 | #ifdef _WIN32 | ||
| 21 | void NormalizeDirSeparators(FString &s); | ||
| 22 | #endif | ||
| 23 | |||
| 24 | bool IsDrivePath(const wchar_t *s) throw(); // first 3 chars are drive chars like "a:\\" | ||
| 25 | |||
| 26 | bool IsAltPathPrefix(CFSTR s) throw(); /* name: */ | ||
| 27 | |||
| 28 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 29 | |||
| 30 | extern const char * const kSuperPathPrefix; /* \\?\ */ | ||
| 31 | const unsigned kDevicePathPrefixSize = 4; | ||
| 32 | const unsigned kSuperPathPrefixSize = 4; | ||
| 33 | const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4; | ||
| 34 | |||
| 35 | bool IsDevicePath(CFSTR s) throw(); /* \\.\ */ | ||
| 36 | bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */ | ||
| 37 | bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */ | ||
| 38 | |||
| 39 | /* GetNetworkServerPrefixSize() returns size of server prefix: | ||
| 40 | \\?\UNC\SERVER\ | ||
| 41 | \\SERVER\ | ||
| 42 | in another cases it returns 0 | ||
| 43 | */ | ||
| 44 | |||
| 45 | unsigned GetNetworkServerPrefixSize(CFSTR s) throw(); | ||
| 46 | |||
| 47 | bool IsNetworkShareRootPath(CFSTR s) throw(); /* \\?\UNC\SERVER\share or \\SERVER\share or with slash */ | ||
| 48 | |||
| 49 | bool IsDrivePath_SuperAllowed(CFSTR s) throw(); // first chars are drive chars like "a:\" or "\\?\a:\" | ||
| 50 | bool IsDriveRootPath_SuperAllowed(CFSTR s) throw(); // exact drive root path "a:\" or "\\?\a:\" | ||
| 51 | |||
| 52 | bool IsDrivePath2(const wchar_t *s) throw(); // first 2 chars are drive chars like "a:" | ||
| 53 | // bool IsDriveName2(const wchar_t *s) throw(); // is drive name like "a:" | ||
| 54 | bool IsSuperPath(const wchar_t *s) throw(); | ||
| 55 | bool IsSuperOrDevicePath(const wchar_t *s) throw(); | ||
| 56 | |||
| 57 | #ifndef USE_UNICODE_FSTRING | ||
| 58 | bool IsDrivePath2(CFSTR s) throw(); // first 2 chars are drive chars like "a:" | ||
| 59 | // bool IsDriveName2(CFSTR s) throw(); // is drive name like "a:" | ||
| 60 | bool IsDrivePath(CFSTR s) throw(); | ||
| 61 | bool IsSuperPath(CFSTR s) throw(); | ||
| 62 | bool IsSuperOrDevicePath(CFSTR s) throw(); | ||
| 63 | |||
| 64 | /* GetRootPrefixSize() returns size of ROOT PREFIX for cases: | ||
| 65 | \ | ||
| 66 | \\.\ | ||
| 67 | C:\ | ||
| 68 | \\?\C:\ | ||
| 69 | \\?\UNC\SERVER\Shared\ | ||
| 70 | \\SERVER\Shared\ | ||
| 71 | in another cases it returns 0 | ||
| 72 | */ | ||
| 73 | |||
| 74 | unsigned GetRootPrefixSize(CFSTR s) throw(); | ||
| 75 | |||
| 76 | #endif | ||
| 77 | |||
| 78 | int FindAltStreamColon(CFSTR path) throw(); | ||
| 79 | |||
| 80 | #endif // _WIN32 | ||
| 81 | |||
| 82 | bool IsAbsolutePath(const wchar_t *s) throw(); | ||
| 83 | unsigned GetRootPrefixSize(const wchar_t *s) throw(); | ||
| 84 | |||
| 85 | #ifdef WIN_LONG_PATH | ||
| 86 | |||
| 87 | const int kSuperPathType_UseOnlyMain = 0; | ||
| 88 | const int kSuperPathType_UseOnlySuper = 1; | ||
| 89 | const int kSuperPathType_UseMainAndSuper = 2; | ||
| 90 | |||
| 91 | int GetUseSuperPathType(CFSTR s) throw(); | ||
| 92 | bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew); | ||
| 93 | bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew); | ||
| 94 | |||
| 95 | #define USE_MAIN_PATH (__useSuperPathType != kSuperPathType_UseOnlySuper) | ||
| 96 | #define USE_MAIN_PATH_2 (__useSuperPathType1 != kSuperPathType_UseOnlySuper && __useSuperPathType2 != kSuperPathType_UseOnlySuper) | ||
| 97 | |||
| 98 | #define USE_SUPER_PATH (__useSuperPathType != kSuperPathType_UseOnlyMain) | ||
| 99 | #define USE_SUPER_PATH_2 (__useSuperPathType1 != kSuperPathType_UseOnlyMain || __useSuperPathType2 != kSuperPathType_UseOnlyMain) | ||
| 100 | |||
| 101 | #define IF_USE_MAIN_PATH int __useSuperPathType = GetUseSuperPathType(path); if (USE_MAIN_PATH) | ||
| 102 | #define IF_USE_MAIN_PATH_2(x1, x2) \ | ||
| 103 | int __useSuperPathType1 = GetUseSuperPathType(x1); \ | ||
| 104 | int __useSuperPathType2 = GetUseSuperPathType(x2); \ | ||
| 105 | if (USE_MAIN_PATH_2) | ||
| 106 | |||
| 107 | #else | ||
| 108 | |||
| 109 | #define IF_USE_MAIN_PATH | ||
| 110 | #define IF_USE_MAIN_PATH_2(x1, x2) | ||
| 111 | |||
| 112 | #endif // WIN_LONG_PATH | ||
| 113 | |||
| 114 | bool GetFullPath(CFSTR dirPrefix, CFSTR path, FString &fullPath); | ||
| 115 | bool GetFullPath(CFSTR path, FString &fullPath); | ||
| 116 | |||
| 117 | }}} | ||
| 118 | |||
| 119 | #endif | ||
diff --git a/CPP/Windows/FileSystem.cpp b/CPP/Windows/FileSystem.cpp new file mode 100644 index 0000000..6259453 --- /dev/null +++ b/CPP/Windows/FileSystem.cpp | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | // Windows/FileSystem.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef UNDER_CE | ||
| 6 | |||
| 7 | #ifndef _UNICODE | ||
| 8 | #include "../Common/StringConvert.h" | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #include "FileSystem.h" | ||
| 12 | #include "Defs.h" | ||
| 13 | |||
| 14 | #ifndef _UNICODE | ||
| 15 | extern bool g_IsNT; | ||
| 16 | #endif | ||
| 17 | |||
| 18 | namespace NWindows { | ||
| 19 | namespace NFile { | ||
| 20 | namespace NSystem { | ||
| 21 | |||
| 22 | #ifdef _WIN32 | ||
| 23 | |||
| 24 | bool MyGetVolumeInformation( | ||
| 25 | CFSTR rootPath, | ||
| 26 | UString &volumeName, | ||
| 27 | LPDWORD volumeSerialNumber, | ||
| 28 | LPDWORD maximumComponentLength, | ||
| 29 | LPDWORD fileSystemFlags, | ||
| 30 | UString &fileSystemName) | ||
| 31 | { | ||
| 32 | BOOL res; | ||
| 33 | #ifndef _UNICODE | ||
| 34 | if (!g_IsNT) | ||
| 35 | { | ||
| 36 | TCHAR v[MAX_PATH + 2]; v[0] = 0; | ||
| 37 | TCHAR f[MAX_PATH + 2]; f[0] = 0; | ||
| 38 | res = GetVolumeInformation(fs2fas(rootPath), | ||
| 39 | v, MAX_PATH, | ||
| 40 | volumeSerialNumber, maximumComponentLength, fileSystemFlags, | ||
| 41 | f, MAX_PATH); | ||
| 42 | volumeName = MultiByteToUnicodeString(v); | ||
| 43 | fileSystemName = MultiByteToUnicodeString(f); | ||
| 44 | } | ||
| 45 | else | ||
| 46 | #endif | ||
| 47 | { | ||
| 48 | WCHAR v[MAX_PATH + 2]; v[0] = 0; | ||
| 49 | WCHAR f[MAX_PATH + 2]; f[0] = 0; | ||
| 50 | res = GetVolumeInformationW(fs2us(rootPath), | ||
| 51 | v, MAX_PATH, | ||
| 52 | volumeSerialNumber, maximumComponentLength, fileSystemFlags, | ||
| 53 | f, MAX_PATH); | ||
| 54 | volumeName = v; | ||
| 55 | fileSystemName = f; | ||
| 56 | } | ||
| 57 | return BOOLToBool(res); | ||
| 58 | } | ||
| 59 | |||
| 60 | UINT MyGetDriveType(CFSTR pathName) | ||
| 61 | { | ||
| 62 | #ifndef _UNICODE | ||
| 63 | if (!g_IsNT) | ||
| 64 | { | ||
| 65 | return GetDriveType(fs2fas(pathName)); | ||
| 66 | } | ||
| 67 | else | ||
| 68 | #endif | ||
| 69 | { | ||
| 70 | return GetDriveTypeW(fs2us(pathName)); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | typedef BOOL (WINAPI * GetDiskFreeSpaceExA_Pointer)( | ||
| 75 | LPCSTR lpDirectoryName, // directory name | ||
| 76 | PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller | ||
| 77 | PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk | ||
| 78 | PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk | ||
| 79 | ); | ||
| 80 | |||
| 81 | typedef BOOL (WINAPI * GetDiskFreeSpaceExW_Pointer)( | ||
| 82 | LPCWSTR lpDirectoryName, // directory name | ||
| 83 | PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller | ||
| 84 | PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk | ||
| 85 | PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk | ||
| 86 | ); | ||
| 87 | |||
| 88 | bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize) | ||
| 89 | { | ||
| 90 | DWORD numSectorsPerCluster, bytesPerSector, numFreeClusters, numClusters; | ||
| 91 | bool sizeIsDetected = false; | ||
| 92 | #ifndef _UNICODE | ||
| 93 | if (!g_IsNT) | ||
| 94 | { | ||
| 95 | GetDiskFreeSpaceExA_Pointer pGetDiskFreeSpaceEx = (GetDiskFreeSpaceExA_Pointer)(void *)GetProcAddress( | ||
| 96 | GetModuleHandle(TEXT("kernel32.dll")), "GetDiskFreeSpaceExA"); | ||
| 97 | if (pGetDiskFreeSpaceEx) | ||
| 98 | { | ||
| 99 | ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2; | ||
| 100 | sizeIsDetected = BOOLToBool(pGetDiskFreeSpaceEx(fs2fas(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2)); | ||
| 101 | totalSize = totalSize2.QuadPart; | ||
| 102 | freeSize = freeSize2.QuadPart; | ||
| 103 | } | ||
| 104 | if (!::GetDiskFreeSpace(fs2fas(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters)) | ||
| 105 | return false; | ||
| 106 | } | ||
| 107 | else | ||
| 108 | #endif | ||
| 109 | { | ||
| 110 | GetDiskFreeSpaceExW_Pointer pGetDiskFreeSpaceEx = (GetDiskFreeSpaceExW_Pointer)(void *)GetProcAddress( | ||
| 111 | GetModuleHandle(TEXT("kernel32.dll")), "GetDiskFreeSpaceExW"); | ||
| 112 | if (pGetDiskFreeSpaceEx) | ||
| 113 | { | ||
| 114 | ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2; | ||
| 115 | sizeIsDetected = BOOLToBool(pGetDiskFreeSpaceEx(fs2us(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2)); | ||
| 116 | totalSize = totalSize2.QuadPart; | ||
| 117 | freeSize = freeSize2.QuadPart; | ||
| 118 | } | ||
| 119 | if (!::GetDiskFreeSpaceW(fs2us(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters)) | ||
| 120 | return false; | ||
| 121 | } | ||
| 122 | clusterSize = (UInt64)bytesPerSector * (UInt64)numSectorsPerCluster; | ||
| 123 | if (!sizeIsDetected) | ||
| 124 | { | ||
| 125 | totalSize = clusterSize * (UInt64)numClusters; | ||
| 126 | freeSize = clusterSize * (UInt64)numFreeClusters; | ||
| 127 | } | ||
| 128 | return true; | ||
| 129 | } | ||
| 130 | |||
| 131 | #endif | ||
| 132 | |||
| 133 | }}} | ||
| 134 | |||
| 135 | #endif | ||
diff --git a/CPP/Windows/FileSystem.h b/CPP/Windows/FileSystem.h new file mode 100644 index 0000000..9b49a02 --- /dev/null +++ b/CPP/Windows/FileSystem.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // Windows/FileSystem.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_FILE_SYSTEM_H | ||
| 4 | #define __WINDOWS_FILE_SYSTEM_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | #include "../Common/MyTypes.h" | ||
| 8 | |||
| 9 | namespace NWindows { | ||
| 10 | namespace NFile { | ||
| 11 | namespace NSystem { | ||
| 12 | |||
| 13 | #ifdef _WIN32 | ||
| 14 | |||
| 15 | bool MyGetVolumeInformation( | ||
| 16 | CFSTR rootPath , | ||
| 17 | UString &volumeName, | ||
| 18 | LPDWORD volumeSerialNumber, | ||
| 19 | LPDWORD maximumComponentLength, | ||
| 20 | LPDWORD fileSystemFlags, | ||
| 21 | UString &fileSystemName); | ||
| 22 | |||
| 23 | UINT MyGetDriveType(CFSTR pathName); | ||
| 24 | |||
| 25 | bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); | ||
| 26 | |||
| 27 | #endif | ||
| 28 | |||
| 29 | }}} | ||
| 30 | |||
| 31 | #endif | ||
diff --git a/CPP/Windows/Handle.h b/CPP/Windows/Handle.h new file mode 100644 index 0000000..5878c83 --- /dev/null +++ b/CPP/Windows/Handle.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // Windows/Handle.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_HANDLE_H | ||
| 4 | #define __WINDOWS_HANDLE_H | ||
| 5 | |||
| 6 | #include "../Common/MyTypes.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | |||
| 10 | class CHandle MY_UNCOPYABLE | ||
| 11 | { | ||
| 12 | protected: | ||
| 13 | HANDLE _handle; | ||
| 14 | public: | ||
| 15 | operator HANDLE() { return _handle; } | ||
| 16 | CHandle(): _handle(NULL) {} | ||
| 17 | ~CHandle() { Close(); } | ||
| 18 | bool IsCreated() const { return (_handle != NULL); } | ||
| 19 | bool Close() | ||
| 20 | { | ||
| 21 | if (_handle == NULL) | ||
| 22 | return true; | ||
| 23 | if (!::CloseHandle(_handle)) | ||
| 24 | return false; | ||
| 25 | _handle = NULL; | ||
| 26 | return true; | ||
| 27 | } | ||
| 28 | void Attach(HANDLE handle) { _handle = handle; } | ||
| 29 | HANDLE Detach() | ||
| 30 | { | ||
| 31 | HANDLE handle = _handle; | ||
| 32 | _handle = NULL; | ||
| 33 | return handle; | ||
| 34 | } | ||
| 35 | }; | ||
| 36 | |||
| 37 | } | ||
| 38 | |||
| 39 | #endif | ||
diff --git a/CPP/Windows/MemoryGlobal.cpp b/CPP/Windows/MemoryGlobal.cpp new file mode 100644 index 0000000..2a22394 --- /dev/null +++ b/CPP/Windows/MemoryGlobal.cpp | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | // Windows/MemoryGlobal.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "MemoryGlobal.h" | ||
| 6 | |||
| 7 | namespace NWindows { | ||
| 8 | namespace NMemory { | ||
| 9 | |||
| 10 | bool CGlobal::Alloc(UINT flags, SIZE_T size) throw() | ||
| 11 | { | ||
| 12 | HGLOBAL newBlock = ::GlobalAlloc(flags, size); | ||
| 13 | if (newBlock == NULL) | ||
| 14 | return false; | ||
| 15 | _global = newBlock; | ||
| 16 | return true; | ||
| 17 | } | ||
| 18 | |||
| 19 | bool CGlobal::Free() throw() | ||
| 20 | { | ||
| 21 | if (_global == NULL) | ||
| 22 | return true; | ||
| 23 | _global = ::GlobalFree(_global); | ||
| 24 | return (_global == NULL); | ||
| 25 | } | ||
| 26 | |||
| 27 | bool CGlobal::ReAlloc(SIZE_T size) throw() | ||
| 28 | { | ||
| 29 | HGLOBAL newBlock = ::GlobalReAlloc(_global, size, GMEM_MOVEABLE); | ||
| 30 | if (newBlock == NULL) | ||
| 31 | return false; | ||
| 32 | _global = newBlock; | ||
| 33 | return true; | ||
| 34 | } | ||
| 35 | |||
| 36 | }} | ||
diff --git a/CPP/Windows/MemoryGlobal.h b/CPP/Windows/MemoryGlobal.h new file mode 100644 index 0000000..c217510 --- /dev/null +++ b/CPP/Windows/MemoryGlobal.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // Windows/MemoryGlobal.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_MEMORY_GLOBAL_H | ||
| 4 | #define __WINDOWS_MEMORY_GLOBAL_H | ||
| 5 | |||
| 6 | #include "../Common/MyWindows.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NMemory { | ||
| 10 | |||
| 11 | class CGlobal | ||
| 12 | { | ||
| 13 | HGLOBAL _global; | ||
| 14 | public: | ||
| 15 | CGlobal(): _global(NULL){}; | ||
| 16 | ~CGlobal() { Free(); } | ||
| 17 | operator HGLOBAL() const { return _global; } | ||
| 18 | void Attach(HGLOBAL hGlobal) | ||
| 19 | { | ||
| 20 | Free(); | ||
| 21 | _global = hGlobal; | ||
| 22 | } | ||
| 23 | HGLOBAL Detach() | ||
| 24 | { | ||
| 25 | HGLOBAL h = _global; | ||
| 26 | _global = NULL; | ||
| 27 | return h; | ||
| 28 | } | ||
| 29 | bool Alloc(UINT flags, SIZE_T size) throw(); | ||
| 30 | bool Free() throw(); | ||
| 31 | LPVOID Lock() const { return GlobalLock(_global); } | ||
| 32 | void Unlock() const { GlobalUnlock(_global); } | ||
| 33 | bool ReAlloc(SIZE_T size) throw(); | ||
| 34 | }; | ||
| 35 | |||
| 36 | class CGlobalLock | ||
| 37 | { | ||
| 38 | HGLOBAL _global; | ||
| 39 | LPVOID _ptr; | ||
| 40 | public: | ||
| 41 | LPVOID GetPointer() const { return _ptr; } | ||
| 42 | CGlobalLock(HGLOBAL hGlobal): _global(hGlobal) | ||
| 43 | { | ||
| 44 | _ptr = GlobalLock(hGlobal); | ||
| 45 | }; | ||
| 46 | ~CGlobalLock() | ||
| 47 | { | ||
| 48 | if (_ptr != NULL) | ||
| 49 | GlobalUnlock(_global); | ||
| 50 | } | ||
| 51 | }; | ||
| 52 | |||
| 53 | }} | ||
| 54 | |||
| 55 | #endif | ||
diff --git a/CPP/Windows/MemoryLock.cpp b/CPP/Windows/MemoryLock.cpp new file mode 100644 index 0000000..fdfbeb9 --- /dev/null +++ b/CPP/Windows/MemoryLock.cpp | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | // Windows/MemoryLock.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../../C/CpuArch.h" | ||
| 6 | |||
| 7 | #include "MemoryLock.h" | ||
| 8 | |||
| 9 | namespace NWindows { | ||
| 10 | namespace NSecurity { | ||
| 11 | |||
| 12 | #ifndef UNDER_CE | ||
| 13 | |||
| 14 | #ifdef _UNICODE | ||
| 15 | #define MY_FUNC_SELECT(f) :: f | ||
| 16 | #else | ||
| 17 | #define MY_FUNC_SELECT(f) my_ ## f | ||
| 18 | extern "C" { | ||
| 19 | typedef BOOL (WINAPI * Func_OpenProcessToken)(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle); | ||
| 20 | typedef BOOL (WINAPI * Func_LookupPrivilegeValue)(LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid); | ||
| 21 | typedef BOOL (WINAPI * Func_AdjustTokenPrivileges)(HANDLE TokenHandle, BOOL DisableAllPrivileges, | ||
| 22 | PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength); | ||
| 23 | } | ||
| 24 | #define GET_PROC_ADDR(fff, name) Func_ ## fff my_ ## fff = (Func_ ## fff)GetProcAddress(hModule, name) | ||
| 25 | #endif | ||
| 26 | |||
| 27 | bool EnablePrivilege(LPCTSTR privilegeName, bool enable) | ||
| 28 | { | ||
| 29 | bool res = false; | ||
| 30 | |||
| 31 | #ifndef _UNICODE | ||
| 32 | |||
| 33 | HMODULE hModule = ::LoadLibrary(TEXT("Advapi32.dll")); | ||
| 34 | if (hModule == NULL) | ||
| 35 | return false; | ||
| 36 | |||
| 37 | GET_PROC_ADDR(OpenProcessToken, "OpenProcessToken"); | ||
| 38 | GET_PROC_ADDR(LookupPrivilegeValue, "LookupPrivilegeValueA"); | ||
| 39 | GET_PROC_ADDR(AdjustTokenPrivileges, "AdjustTokenPrivileges"); | ||
| 40 | |||
| 41 | if (my_OpenProcessToken && | ||
| 42 | my_AdjustTokenPrivileges && | ||
| 43 | my_LookupPrivilegeValue) | ||
| 44 | |||
| 45 | #endif | ||
| 46 | |||
| 47 | { | ||
| 48 | HANDLE token; | ||
| 49 | if (MY_FUNC_SELECT(OpenProcessToken)(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) | ||
| 50 | { | ||
| 51 | TOKEN_PRIVILEGES tp; | ||
| 52 | if (MY_FUNC_SELECT(LookupPrivilegeValue)(NULL, privilegeName, &(tp.Privileges[0].Luid))) | ||
| 53 | { | ||
| 54 | tp.PrivilegeCount = 1; | ||
| 55 | tp.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0); | ||
| 56 | if (MY_FUNC_SELECT(AdjustTokenPrivileges)(token, FALSE, &tp, 0, NULL, NULL)) | ||
| 57 | res = (GetLastError() == ERROR_SUCCESS); | ||
| 58 | } | ||
| 59 | ::CloseHandle(token); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | #ifndef _UNICODE | ||
| 64 | |||
| 65 | ::FreeLibrary(hModule); | ||
| 66 | |||
| 67 | #endif | ||
| 68 | |||
| 69 | return res; | ||
| 70 | } | ||
| 71 | |||
| 72 | |||
| 73 | |||
| 74 | typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *); | ||
| 75 | |||
| 76 | /* | ||
| 77 | We suppose that Window 10 works incorrectly with "Large Pages" at: | ||
| 78 | - Windows 10 1703 (15063) : incorrect allocating after VirtualFree() | ||
| 79 | - Windows 10 1709 (16299) : incorrect allocating after VirtualFree() | ||
| 80 | - Windows 10 1809 (17763) : the failures for blocks of 1 GiB and larger, | ||
| 81 | if CPU doesn't support 1 GB pages. | ||
| 82 | Windows 10 1903 (18362) probably works correctly. | ||
| 83 | */ | ||
| 84 | |||
| 85 | unsigned Get_LargePages_RiskLevel() | ||
| 86 | { | ||
| 87 | OSVERSIONINFOEXW vi; | ||
| 88 | HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); | ||
| 89 | if (!ntdll) | ||
| 90 | return 0; | ||
| 91 | Func_RtlGetVersion func = (Func_RtlGetVersion)(void *)GetProcAddress(ntdll, "RtlGetVersion"); | ||
| 92 | if (!func) | ||
| 93 | return 0; | ||
| 94 | func(&vi); | ||
| 95 | if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) | ||
| 96 | return 0; | ||
| 97 | if (vi.dwMajorVersion + vi.dwMinorVersion != 10) | ||
| 98 | return 0; | ||
| 99 | if (vi.dwBuildNumber <= 16299) | ||
| 100 | return 1; | ||
| 101 | |||
| 102 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 103 | if (vi.dwBuildNumber < 18362 && !CPU_IsSupported_PageGB()) | ||
| 104 | return 1; | ||
| 105 | #endif | ||
| 106 | |||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | #endif | ||
| 111 | |||
| 112 | }} | ||
diff --git a/CPP/Windows/MemoryLock.h b/CPP/Windows/MemoryLock.h new file mode 100644 index 0000000..dcaf182 --- /dev/null +++ b/CPP/Windows/MemoryLock.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | // Windows/MemoryLock.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_MEMORY_LOCK_H | ||
| 4 | #define __WINDOWS_MEMORY_LOCK_H | ||
| 5 | |||
| 6 | #include "../Common/MyWindows.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NSecurity { | ||
| 10 | |||
| 11 | #ifndef UNDER_CE | ||
| 12 | |||
| 13 | bool EnablePrivilege(LPCTSTR privilegeName, bool enable = true); | ||
| 14 | |||
| 15 | inline bool EnablePrivilege_LockMemory(bool enable = true) | ||
| 16 | { | ||
| 17 | return EnablePrivilege(SE_LOCK_MEMORY_NAME, enable); | ||
| 18 | } | ||
| 19 | |||
| 20 | inline void EnablePrivilege_SymLink() | ||
| 21 | { | ||
| 22 | /* Probably we do not to set any Privilege for junction points. | ||
| 23 | But we need them for Symbolic links */ | ||
| 24 | NSecurity::EnablePrivilege(SE_RESTORE_NAME); | ||
| 25 | |||
| 26 | /* Probably we need only SE_RESTORE_NAME, but there is also | ||
| 27 | SE_CREATE_SYMBOLIC_LINK_NAME. So we set it also. Do we need it? */ | ||
| 28 | |||
| 29 | NSecurity::EnablePrivilege(TEXT("SeCreateSymbolicLinkPrivilege")); // SE_CREATE_SYMBOLIC_LINK_NAME | ||
| 30 | |||
| 31 | // Do we need to set SE_BACKUP_NAME ? | ||
| 32 | } | ||
| 33 | |||
| 34 | unsigned Get_LargePages_RiskLevel(); | ||
| 35 | |||
| 36 | #endif | ||
| 37 | |||
| 38 | }} | ||
| 39 | |||
| 40 | #endif | ||
diff --git a/CPP/Windows/Menu.cpp b/CPP/Windows/Menu.cpp new file mode 100644 index 0000000..3ad6953 --- /dev/null +++ b/CPP/Windows/Menu.cpp | |||
| @@ -0,0 +1,216 @@ | |||
| 1 | // Windows/Menu.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef _UNICODE | ||
| 6 | #include "../Common/StringConvert.h" | ||
| 7 | #endif | ||
| 8 | #include "Menu.h" | ||
| 9 | |||
| 10 | #ifndef _UNICODE | ||
| 11 | extern bool g_IsNT; | ||
| 12 | #endif | ||
| 13 | |||
| 14 | namespace NWindows { | ||
| 15 | |||
| 16 | /* | ||
| 17 | structures | ||
| 18 | MENUITEMINFOA | ||
| 19 | MENUITEMINFOW | ||
| 20 | contain additional member: | ||
| 21 | #if (WINVER >= 0x0500) | ||
| 22 | HBITMAP hbmpItem; | ||
| 23 | #endif | ||
| 24 | If we compile the source code with (WINVER >= 0x0500), some functions | ||
| 25 | will not work at NT 4.0, if cbSize is set as sizeof(MENUITEMINFO*). | ||
| 26 | So we use size of old version of structure. */ | ||
| 27 | |||
| 28 | #if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500) | ||
| 29 | #ifndef _UNICODE | ||
| 30 | #define my_compatib_MENUITEMINFOA_size sizeof(MENUITEMINFOA) | ||
| 31 | #endif | ||
| 32 | #define my_compatib_MENUITEMINFOW_size sizeof(MENUITEMINFOW) | ||
| 33 | #else | ||
| 34 | #define MY_STRUCT_SIZE_BEFORE(structname, member) ((UINT)(UINT_PTR)((LPBYTE)(&((structname*)0)->member) - (LPBYTE)(structname*)0)) | ||
| 35 | #ifndef _UNICODE | ||
| 36 | #define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem) | ||
| 37 | #endif | ||
| 38 | #define my_compatib_MENUITEMINFOW_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOW, hbmpItem) | ||
| 39 | #endif | ||
| 40 | |||
| 41 | static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si) | ||
| 42 | { | ||
| 43 | ZeroMemory(&si, sizeof(si)); | ||
| 44 | si.cbSize = my_compatib_MENUITEMINFOW_size; // sizeof(si); | ||
| 45 | si.fMask = item.fMask; | ||
| 46 | si.fType = item.fType; | ||
| 47 | si.fState = item.fState; | ||
| 48 | si.wID = item.wID; | ||
| 49 | si.hSubMenu = item.hSubMenu; | ||
| 50 | si.hbmpChecked = item.hbmpChecked; | ||
| 51 | si.hbmpUnchecked = item.hbmpUnchecked; | ||
| 52 | si.dwItemData = item.dwItemData; | ||
| 53 | } | ||
| 54 | |||
| 55 | #ifndef _UNICODE | ||
| 56 | static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOA &si) | ||
| 57 | { | ||
| 58 | ZeroMemory(&si, sizeof(si)); | ||
| 59 | si.cbSize = my_compatib_MENUITEMINFOA_size; // sizeof(si); | ||
| 60 | si.fMask = item.fMask; | ||
| 61 | si.fType = item.fType; | ||
| 62 | si.fState = item.fState; | ||
| 63 | si.wID = item.wID; | ||
| 64 | si.hSubMenu = item.hSubMenu; | ||
| 65 | si.hbmpChecked = item.hbmpChecked; | ||
| 66 | si.hbmpUnchecked = item.hbmpUnchecked; | ||
| 67 | si.dwItemData = item.dwItemData; | ||
| 68 | } | ||
| 69 | #endif | ||
| 70 | |||
| 71 | static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item) | ||
| 72 | { | ||
| 73 | item.fMask = si.fMask; | ||
| 74 | item.fType = si.fType; | ||
| 75 | item.fState = si.fState; | ||
| 76 | item.wID = si.wID; | ||
| 77 | item.hSubMenu = si.hSubMenu; | ||
| 78 | item.hbmpChecked = si.hbmpChecked; | ||
| 79 | item.hbmpUnchecked = si.hbmpUnchecked; | ||
| 80 | item.dwItemData = si.dwItemData; | ||
| 81 | } | ||
| 82 | |||
| 83 | #ifndef _UNICODE | ||
| 84 | static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item) | ||
| 85 | { | ||
| 86 | item.fMask = si.fMask; | ||
| 87 | item.fType = si.fType; | ||
| 88 | item.fState = si.fState; | ||
| 89 | item.wID = si.wID; | ||
| 90 | item.hSubMenu = si.hSubMenu; | ||
| 91 | item.hbmpChecked = si.hbmpChecked; | ||
| 92 | item.hbmpUnchecked = si.hbmpUnchecked; | ||
| 93 | item.dwItemData = si.dwItemData; | ||
| 94 | } | ||
| 95 | #endif | ||
| 96 | |||
| 97 | bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) | ||
| 98 | { | ||
| 99 | const UINT kMaxSize = 512; | ||
| 100 | #ifndef _UNICODE | ||
| 101 | if (!g_IsNT) | ||
| 102 | { | ||
| 103 | CHAR s[kMaxSize + 1]; | ||
| 104 | MENUITEMINFOA si; | ||
| 105 | ConvertItemToSysForm(item, si); | ||
| 106 | if (item.IsString()) | ||
| 107 | { | ||
| 108 | si.cch = kMaxSize; | ||
| 109 | si.dwTypeData = s; | ||
| 110 | } | ||
| 111 | if (GetItemInfo(itemIndex, byPosition, &si)) | ||
| 112 | { | ||
| 113 | ConvertItemToMyForm(si, item); | ||
| 114 | if (item.IsString()) | ||
| 115 | item.StringValue = GetUnicodeString(s); | ||
| 116 | return true; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | else | ||
| 120 | #endif | ||
| 121 | { | ||
| 122 | wchar_t s[kMaxSize + 1]; | ||
| 123 | MENUITEMINFOW si; | ||
| 124 | ConvertItemToSysForm(item, si); | ||
| 125 | if (item.IsString()) | ||
| 126 | { | ||
| 127 | si.cch = kMaxSize; | ||
| 128 | si.dwTypeData = s; | ||
| 129 | } | ||
| 130 | if (GetItemInfo(itemIndex, byPosition, &si)) | ||
| 131 | { | ||
| 132 | ConvertItemToMyForm(si, item); | ||
| 133 | if (item.IsString()) | ||
| 134 | item.StringValue = s; | ||
| 135 | return true; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | return false; | ||
| 139 | } | ||
| 140 | |||
| 141 | bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item) | ||
| 142 | { | ||
| 143 | #ifndef _UNICODE | ||
| 144 | if (!g_IsNT) | ||
| 145 | { | ||
| 146 | MENUITEMINFOA si; | ||
| 147 | ConvertItemToSysForm(item, si); | ||
| 148 | AString s; | ||
| 149 | if (item.IsString()) | ||
| 150 | { | ||
| 151 | s = GetSystemString(item.StringValue); | ||
| 152 | si.dwTypeData = s.Ptr_non_const(); | ||
| 153 | } | ||
| 154 | return SetItemInfo(itemIndex, byPosition, &si); | ||
| 155 | } | ||
| 156 | else | ||
| 157 | #endif | ||
| 158 | { | ||
| 159 | MENUITEMINFOW si; | ||
| 160 | ConvertItemToSysForm(item, si); | ||
| 161 | if (item.IsString()) | ||
| 162 | si.dwTypeData = item.StringValue.Ptr_non_const(); | ||
| 163 | return SetItemInfo(itemIndex, byPosition, &si); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item) | ||
| 168 | { | ||
| 169 | #ifndef _UNICODE | ||
| 170 | if (!g_IsNT) | ||
| 171 | { | ||
| 172 | MENUITEMINFOA si; | ||
| 173 | ConvertItemToSysForm(item, si); | ||
| 174 | AString s; | ||
| 175 | if (item.IsString()) | ||
| 176 | { | ||
| 177 | s = GetSystemString(item.StringValue); | ||
| 178 | si.dwTypeData = s.Ptr_non_const(); | ||
| 179 | } | ||
| 180 | return InsertItem(itemIndex, byPosition, &si); | ||
| 181 | } | ||
| 182 | else | ||
| 183 | #endif | ||
| 184 | { | ||
| 185 | MENUITEMINFOW si; | ||
| 186 | ConvertItemToSysForm(item, si); | ||
| 187 | if (item.IsString()) | ||
| 188 | si.dwTypeData = item.StringValue.Ptr_non_const(); | ||
| 189 | #ifdef UNDER_CE | ||
| 190 | UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING; | ||
| 191 | UINT id = item.wID; | ||
| 192 | if ((item.fMask & MIIM_SUBMENU) != 0) | ||
| 193 | { | ||
| 194 | flags |= MF_POPUP; | ||
| 195 | id = (UINT)item.hSubMenu; | ||
| 196 | } | ||
| 197 | if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue)) | ||
| 198 | return false; | ||
| 199 | return SetItemInfo(itemIndex, byPosition, &si); | ||
| 200 | #else | ||
| 201 | return InsertItem(itemIndex, byPosition, &si); | ||
| 202 | #endif | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | #ifndef _UNICODE | ||
| 207 | bool CMenu::AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem) | ||
| 208 | { | ||
| 209 | if (g_IsNT) | ||
| 210 | return BOOLToBool(::AppendMenuW(_menu, flags, newItemID, newItem)); | ||
| 211 | else | ||
| 212 | return AppendItem(flags, newItemID, GetSystemString(newItem)); | ||
| 213 | } | ||
| 214 | #endif | ||
| 215 | |||
| 216 | } | ||
diff --git a/CPP/Windows/Menu.h b/CPP/Windows/Menu.h new file mode 100644 index 0000000..aacdc7c --- /dev/null +++ b/CPP/Windows/Menu.h | |||
| @@ -0,0 +1,158 @@ | |||
| 1 | // Windows/Menu.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_MENU_H | ||
| 4 | #define __WINDOWS_MENU_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | #include "Defs.h" | ||
| 9 | |||
| 10 | namespace NWindows { | ||
| 11 | |||
| 12 | struct CMenuItem | ||
| 13 | { | ||
| 14 | UString StringValue; | ||
| 15 | UINT fMask; | ||
| 16 | UINT fType; | ||
| 17 | UINT fState; | ||
| 18 | UINT wID; | ||
| 19 | HMENU hSubMenu; | ||
| 20 | HBITMAP hbmpChecked; | ||
| 21 | HBITMAP hbmpUnchecked; | ||
| 22 | ULONG_PTR dwItemData; | ||
| 23 | // LPTSTR dwTypeData; | ||
| 24 | // UINT cch; | ||
| 25 | // HBITMAP hbmpItem; | ||
| 26 | bool IsString() const // change it MIIM_STRING | ||
| 27 | { return ((fMask & MIIM_TYPE) != 0 && (fType == MFT_STRING)); } | ||
| 28 | bool IsSeparator() const { return (fType == MFT_SEPARATOR); } | ||
| 29 | CMenuItem(): fMask(0), fType(0), fState(0), wID(0), hSubMenu(0), hbmpChecked(0), | ||
| 30 | hbmpUnchecked(0), dwItemData(0) {} | ||
| 31 | }; | ||
| 32 | |||
| 33 | class CMenu | ||
| 34 | { | ||
| 35 | HMENU _menu; | ||
| 36 | public: | ||
| 37 | CMenu(): _menu(NULL) {}; | ||
| 38 | operator HMENU() const { return _menu; } | ||
| 39 | void Attach(HMENU menu) { _menu = menu; } | ||
| 40 | |||
| 41 | HMENU Detach() | ||
| 42 | { | ||
| 43 | HMENU menu = _menu; | ||
| 44 | _menu = NULL; | ||
| 45 | return menu; | ||
| 46 | } | ||
| 47 | |||
| 48 | bool Create() | ||
| 49 | { | ||
| 50 | _menu = ::CreateMenu(); | ||
| 51 | return (_menu != NULL); | ||
| 52 | } | ||
| 53 | |||
| 54 | bool CreatePopup() | ||
| 55 | { | ||
| 56 | _menu = ::CreatePopupMenu(); | ||
| 57 | return (_menu != NULL); | ||
| 58 | } | ||
| 59 | |||
| 60 | bool Destroy() | ||
| 61 | { | ||
| 62 | if (_menu == NULL) | ||
| 63 | return false; | ||
| 64 | return BOOLToBool(::DestroyMenu(Detach())); | ||
| 65 | } | ||
| 66 | |||
| 67 | int GetItemCount() | ||
| 68 | { | ||
| 69 | #ifdef UNDER_CE | ||
| 70 | for (int i = 0;; i++) | ||
| 71 | { | ||
| 72 | CMenuItem item; | ||
| 73 | item.fMask = MIIM_STATE; | ||
| 74 | if (!GetItem(i, true, item)) | ||
| 75 | return i; | ||
| 76 | } | ||
| 77 | #else | ||
| 78 | return GetMenuItemCount(_menu); | ||
| 79 | #endif | ||
| 80 | } | ||
| 81 | |||
| 82 | HMENU GetSubMenu(int pos) { return ::GetSubMenu(_menu, pos); } | ||
| 83 | #ifndef UNDER_CE | ||
| 84 | /* | ||
| 85 | bool GetItemString(UINT idItem, UINT flag, CSysString &result) | ||
| 86 | { | ||
| 87 | result.Empty(); | ||
| 88 | int len = ::GetMenuString(_menu, idItem, 0, 0, flag); | ||
| 89 | int len2 = ::GetMenuString(_menu, idItem, result.GetBuf(len + 2), len + 1, flag); | ||
| 90 | if (len > len2) | ||
| 91 | len = len2; | ||
| 92 | result.ReleaseBuf_CalcLen(len + 2); | ||
| 93 | return (len != 0); | ||
| 94 | } | ||
| 95 | */ | ||
| 96 | UINT GetItemID(int pos) { return ::GetMenuItemID(_menu, pos); } | ||
| 97 | UINT GetItemState(UINT id, UINT flags) { return ::GetMenuState(_menu, id, flags); } | ||
| 98 | #endif | ||
| 99 | |||
| 100 | bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) | ||
| 101 | { return BOOLToBool(::GetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } | ||
| 102 | bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) | ||
| 103 | { return BOOLToBool(::SetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } | ||
| 104 | |||
| 105 | bool AppendItem(UINT flags, UINT_PTR newItemID, LPCTSTR newItem) | ||
| 106 | { return BOOLToBool(::AppendMenu(_menu, flags, newItemID, newItem)); } | ||
| 107 | |||
| 108 | bool Insert(UINT position, UINT flags, UINT_PTR idNewItem, LPCTSTR newItem) | ||
| 109 | { return BOOLToBool(::InsertMenu(_menu, position, flags, idNewItem, newItem)); } | ||
| 110 | |||
| 111 | #ifndef UNDER_CE | ||
| 112 | bool InsertItem(UINT itemIndex, bool byPosition, LPCMENUITEMINFO itemInfo) | ||
| 113 | { return BOOLToBool(::InsertMenuItem(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } | ||
| 114 | #endif | ||
| 115 | |||
| 116 | bool RemoveItem(UINT item, UINT flags) { return BOOLToBool(::RemoveMenu(_menu, item, flags)); } | ||
| 117 | void RemoveAllItemsFrom(UINT index) { while (RemoveItem(index, MF_BYPOSITION)); } | ||
| 118 | void RemoveAllItems() { RemoveAllItemsFrom(0); } | ||
| 119 | |||
| 120 | #ifndef _UNICODE | ||
| 121 | bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) | ||
| 122 | { return BOOLToBool(::GetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } | ||
| 123 | bool InsertItem(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) | ||
| 124 | { return BOOLToBool(::InsertMenuItemW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } | ||
| 125 | bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) | ||
| 126 | { return BOOLToBool(::SetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } | ||
| 127 | bool AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem); | ||
| 128 | #endif | ||
| 129 | |||
| 130 | bool GetItem(UINT itemIndex, bool byPosition, CMenuItem &item); | ||
| 131 | bool SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item); | ||
| 132 | bool InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item); | ||
| 133 | |||
| 134 | int Track(UINT flags, int x, int y, HWND hWnd) { return ::TrackPopupMenuEx(_menu, flags, x, y, hWnd, NULL); } | ||
| 135 | |||
| 136 | bool CheckRadioItem(UINT idFirst, UINT idLast, UINT idCheck, UINT flags) | ||
| 137 | { return BOOLToBool(::CheckMenuRadioItem(_menu, idFirst, idLast, idCheck, flags)); } | ||
| 138 | |||
| 139 | DWORD CheckItem(UINT id, UINT uCheck) { return ::CheckMenuItem(_menu, id, uCheck); } | ||
| 140 | DWORD CheckItemByID(UINT id, bool check) { return CheckItem(id, MF_BYCOMMAND | (check ? MF_CHECKED : MF_UNCHECKED)); } | ||
| 141 | |||
| 142 | BOOL EnableItem(UINT uIDEnableItem, UINT uEnable) { return EnableMenuItem(_menu, uIDEnableItem, uEnable); } | ||
| 143 | }; | ||
| 144 | |||
| 145 | class CMenuDestroyer | ||
| 146 | { | ||
| 147 | CMenu *_menu; | ||
| 148 | public: | ||
| 149 | CMenuDestroyer(CMenu &menu): _menu(&menu) {} | ||
| 150 | CMenuDestroyer(): _menu(0) {} | ||
| 151 | ~CMenuDestroyer() { if (_menu) _menu->Destroy(); } | ||
| 152 | void Attach(CMenu &menu) { _menu = &menu; } | ||
| 153 | void Disable() { _menu = 0; } | ||
| 154 | }; | ||
| 155 | |||
| 156 | } | ||
| 157 | |||
| 158 | #endif | ||
diff --git a/CPP/Windows/NationalTime.cpp b/CPP/Windows/NationalTime.cpp new file mode 100644 index 0000000..0dcd31e --- /dev/null +++ b/CPP/Windows/NationalTime.cpp | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // Windows/NationalTime.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "NationalTime.h" | ||
| 6 | |||
| 7 | namespace NWindows { | ||
| 8 | namespace NNational { | ||
| 9 | namespace NTime { | ||
| 10 | |||
| 11 | bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, | ||
| 12 | LPCTSTR format, CSysString &resultString) | ||
| 13 | { | ||
| 14 | resultString.Empty(); | ||
| 15 | int numChars = ::GetTimeFormat(locale, flags, time, format, NULL, 0); | ||
| 16 | if (numChars == 0) | ||
| 17 | return false; | ||
| 18 | numChars = ::GetTimeFormat(locale, flags, time, format, | ||
| 19 | resultString.GetBuf(numChars), numChars + 1); | ||
| 20 | resultString.ReleaseBuf_CalcLen(numChars); | ||
| 21 | return (numChars != 0); | ||
| 22 | } | ||
| 23 | |||
| 24 | bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, | ||
| 25 | LPCTSTR format, CSysString &resultString) | ||
| 26 | { | ||
| 27 | resultString.Empty(); | ||
| 28 | int numChars = ::GetDateFormat(locale, flags, time, format, NULL, 0); | ||
| 29 | if (numChars == 0) | ||
| 30 | return false; | ||
| 31 | numChars = ::GetDateFormat(locale, flags, time, format, | ||
| 32 | resultString.GetBuf(numChars), numChars + 1); | ||
| 33 | resultString.ReleaseBuf_CalcLen(numChars); | ||
| 34 | return (numChars != 0); | ||
| 35 | } | ||
| 36 | |||
| 37 | }}} | ||
diff --git a/CPP/Windows/NationalTime.h b/CPP/Windows/NationalTime.h new file mode 100644 index 0000000..49b0e5e --- /dev/null +++ b/CPP/Windows/NationalTime.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | // Windows/NationalTime.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_NATIONAL_TIME_H | ||
| 4 | #define __WINDOWS_NATIONAL_TIME_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NNational { | ||
| 10 | namespace NTime { | ||
| 11 | |||
| 12 | bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, | ||
| 13 | LPCTSTR format, CSysString &resultString); | ||
| 14 | |||
| 15 | bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, | ||
| 16 | LPCTSTR format, CSysString &resultString); | ||
| 17 | |||
| 18 | }}} | ||
| 19 | |||
| 20 | #endif | ||
diff --git a/CPP/Windows/Net.cpp b/CPP/Windows/Net.cpp new file mode 100644 index 0000000..2a3952a --- /dev/null +++ b/CPP/Windows/Net.cpp | |||
| @@ -0,0 +1,370 @@ | |||
| 1 | // Windows/Net.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../Common/MyBuffer.h" | ||
| 6 | |||
| 7 | #ifndef _UNICODE | ||
| 8 | #include "../Common/StringConvert.h" | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #include "Net.h" | ||
| 12 | |||
| 13 | #ifndef _UNICODE | ||
| 14 | extern bool g_IsNT; | ||
| 15 | #endif | ||
| 16 | |||
| 17 | namespace NWindows { | ||
| 18 | namespace NNet { | ||
| 19 | |||
| 20 | DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource) | ||
| 21 | { | ||
| 22 | Close(); | ||
| 23 | DWORD result = ::WNetOpenEnum(scope, type, usage, netResource, &_handle); | ||
| 24 | _handleAllocated = (result == NO_ERROR); | ||
| 25 | return result; | ||
| 26 | } | ||
| 27 | |||
| 28 | #ifndef _UNICODE | ||
| 29 | DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource) | ||
| 30 | { | ||
| 31 | Close(); | ||
| 32 | DWORD result = ::WNetOpenEnumW(scope, type, usage, netResource, &_handle); | ||
| 33 | _handleAllocated = (result == NO_ERROR); | ||
| 34 | return result; | ||
| 35 | } | ||
| 36 | #endif | ||
| 37 | |||
| 38 | static void SetComplexString(bool &defined, CSysString &destString, LPCTSTR srcString) | ||
| 39 | { | ||
| 40 | defined = (srcString != 0); | ||
| 41 | if (defined) | ||
| 42 | destString = srcString; | ||
| 43 | else | ||
| 44 | destString.Empty(); | ||
| 45 | } | ||
| 46 | |||
| 47 | static void ConvertNETRESOURCEToCResource(const NETRESOURCE &netResource, CResource &resource) | ||
| 48 | { | ||
| 49 | resource.Scope = netResource.dwScope; | ||
| 50 | resource.Type = netResource.dwType; | ||
| 51 | resource.DisplayType = netResource.dwDisplayType; | ||
| 52 | resource.Usage = netResource.dwUsage; | ||
| 53 | SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName); | ||
| 54 | SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName); | ||
| 55 | SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment); | ||
| 56 | SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider); | ||
| 57 | } | ||
| 58 | |||
| 59 | static void SetComplexString2(LPTSTR *destString, bool defined, const CSysString &srcString) | ||
| 60 | { | ||
| 61 | if (defined) | ||
| 62 | *destString = srcString.Ptr_non_const(); | ||
| 63 | else | ||
| 64 | *destString = NULL; | ||
| 65 | } | ||
| 66 | |||
| 67 | static void ConvertCResourceToNETRESOURCE(const CResource &resource, NETRESOURCE &netResource) | ||
| 68 | { | ||
| 69 | netResource.dwScope = resource.Scope; | ||
| 70 | netResource.dwType = resource.Type; | ||
| 71 | netResource.dwDisplayType = resource.DisplayType; | ||
| 72 | netResource.dwUsage = resource.Usage; | ||
| 73 | SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName); | ||
| 74 | SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName); | ||
| 75 | SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment); | ||
| 76 | SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider); | ||
| 77 | } | ||
| 78 | |||
| 79 | #ifndef _UNICODE | ||
| 80 | |||
| 81 | static void SetComplexString(bool &defined, UString &destString, LPCWSTR src) | ||
| 82 | { | ||
| 83 | defined = (src != NULL); | ||
| 84 | if (defined) | ||
| 85 | destString = src; | ||
| 86 | else | ||
| 87 | destString.Empty(); | ||
| 88 | } | ||
| 89 | |||
| 90 | static void ConvertNETRESOURCEToCResource(const NETRESOURCEW &netResource, CResourceW &resource) | ||
| 91 | { | ||
| 92 | resource.Scope = netResource.dwScope; | ||
| 93 | resource.Type = netResource.dwType; | ||
| 94 | resource.DisplayType = netResource.dwDisplayType; | ||
| 95 | resource.Usage = netResource.dwUsage; | ||
| 96 | SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName); | ||
| 97 | SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName); | ||
| 98 | SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment); | ||
| 99 | SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider); | ||
| 100 | } | ||
| 101 | |||
| 102 | static void SetComplexString2(LPWSTR *destString, bool defined, const UString &srcString) | ||
| 103 | { | ||
| 104 | if (defined) | ||
| 105 | *destString = srcString.Ptr_non_const(); | ||
| 106 | else | ||
| 107 | *destString = NULL; | ||
| 108 | } | ||
| 109 | |||
| 110 | static void ConvertCResourceToNETRESOURCE(const CResourceW &resource, NETRESOURCEW &netResource) | ||
| 111 | { | ||
| 112 | netResource.dwScope = resource.Scope; | ||
| 113 | netResource.dwType = resource.Type; | ||
| 114 | netResource.dwDisplayType = resource.DisplayType; | ||
| 115 | netResource.dwUsage = resource.Usage; | ||
| 116 | SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName); | ||
| 117 | SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName); | ||
| 118 | SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment); | ||
| 119 | SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider); | ||
| 120 | } | ||
| 121 | |||
| 122 | static void ConvertResourceWToResource(const CResourceW &resourceW, CResource &resource) | ||
| 123 | { | ||
| 124 | *(CResourceBase *)&resource = *(CResourceBase *)&resourceW; | ||
| 125 | resource.LocalName = GetSystemString(resourceW.LocalName); | ||
| 126 | resource.RemoteName = GetSystemString(resourceW.RemoteName); | ||
| 127 | resource.Comment = GetSystemString(resourceW.Comment); | ||
| 128 | resource.Provider = GetSystemString(resourceW.Provider); | ||
| 129 | } | ||
| 130 | |||
| 131 | static void ConvertResourceToResourceW(const CResource &resource, CResourceW &resourceW) | ||
| 132 | { | ||
| 133 | *(CResourceBase *)&resourceW = *(CResourceBase *)&resource; | ||
| 134 | resourceW.LocalName = GetUnicodeString(resource.LocalName); | ||
| 135 | resourceW.RemoteName = GetUnicodeString(resource.RemoteName); | ||
| 136 | resourceW.Comment = GetUnicodeString(resource.Comment); | ||
| 137 | resourceW.Provider = GetUnicodeString(resource.Provider); | ||
| 138 | } | ||
| 139 | #endif | ||
| 140 | |||
| 141 | DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource) | ||
| 142 | { | ||
| 143 | NETRESOURCE netResource; | ||
| 144 | LPNETRESOURCE pointer = NULL; | ||
| 145 | if (resource) | ||
| 146 | { | ||
| 147 | ConvertCResourceToNETRESOURCE(*resource, netResource); | ||
| 148 | pointer = &netResource; | ||
| 149 | } | ||
| 150 | return Open(scope, type, usage, pointer); | ||
| 151 | } | ||
| 152 | |||
| 153 | #ifndef _UNICODE | ||
| 154 | DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource) | ||
| 155 | { | ||
| 156 | if (g_IsNT) | ||
| 157 | { | ||
| 158 | NETRESOURCEW netResource; | ||
| 159 | LPNETRESOURCEW pointer = NULL; | ||
| 160 | if (resource) | ||
| 161 | { | ||
| 162 | ConvertCResourceToNETRESOURCE(*resource, netResource); | ||
| 163 | pointer = &netResource; | ||
| 164 | } | ||
| 165 | return Open(scope, type, usage, pointer); | ||
| 166 | } | ||
| 167 | CResource resourceA; | ||
| 168 | CResource *pointer = NULL; | ||
| 169 | if (resource) | ||
| 170 | { | ||
| 171 | ConvertResourceWToResource(*resource, resourceA); | ||
| 172 | pointer = &resourceA; | ||
| 173 | } | ||
| 174 | return Open(scope, type, usage, pointer); | ||
| 175 | } | ||
| 176 | #endif | ||
| 177 | |||
| 178 | DWORD CEnum::Close() | ||
| 179 | { | ||
| 180 | if (!_handleAllocated) | ||
| 181 | return NO_ERROR; | ||
| 182 | DWORD result = ::WNetCloseEnum(_handle); | ||
| 183 | _handleAllocated = (result != NO_ERROR); | ||
| 184 | return result; | ||
| 185 | } | ||
| 186 | |||
| 187 | DWORD CEnum::Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) | ||
| 188 | { | ||
| 189 | return ::WNetEnumResource(_handle, lpcCount, lpBuffer, lpBufferSize); | ||
| 190 | } | ||
| 191 | |||
| 192 | #ifndef _UNICODE | ||
| 193 | DWORD CEnum::NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) | ||
| 194 | { | ||
| 195 | return ::WNetEnumResourceW(_handle, lpcCount, lpBuffer, lpBufferSize); | ||
| 196 | } | ||
| 197 | #endif | ||
| 198 | |||
| 199 | DWORD CEnum::Next(CResource &resource) | ||
| 200 | { | ||
| 201 | const DWORD kBufferSize = 16384; | ||
| 202 | CByteArr byteBuffer(kBufferSize); | ||
| 203 | LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); | ||
| 204 | ZeroMemory(lpnrLocal, kBufferSize); | ||
| 205 | DWORD bufferSize = kBufferSize; | ||
| 206 | DWORD numEntries = 1; | ||
| 207 | DWORD result = Next(&numEntries, lpnrLocal, &bufferSize); | ||
| 208 | if (result != NO_ERROR) | ||
| 209 | return result; | ||
| 210 | if (numEntries != 1) | ||
| 211 | return (DWORD)E_FAIL; | ||
| 212 | ConvertNETRESOURCEToCResource(lpnrLocal[0], resource); | ||
| 213 | return result; | ||
| 214 | } | ||
| 215 | |||
| 216 | #ifndef _UNICODE | ||
| 217 | DWORD CEnum::Next(CResourceW &resource) | ||
| 218 | { | ||
| 219 | if (g_IsNT) | ||
| 220 | { | ||
| 221 | const DWORD kBufferSize = 16384; | ||
| 222 | CByteArr byteBuffer(kBufferSize); | ||
| 223 | LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); | ||
| 224 | ZeroMemory(lpnrLocal, kBufferSize); | ||
| 225 | DWORD bufferSize = kBufferSize; | ||
| 226 | DWORD numEntries = 1; | ||
| 227 | DWORD result = NextW(&numEntries, lpnrLocal, &bufferSize); | ||
| 228 | if (result != NO_ERROR) | ||
| 229 | return result; | ||
| 230 | if (numEntries != 1) | ||
| 231 | return (DWORD)E_FAIL; | ||
| 232 | ConvertNETRESOURCEToCResource(lpnrLocal[0], resource); | ||
| 233 | return result; | ||
| 234 | } | ||
| 235 | CResource resourceA; | ||
| 236 | DWORD result = Next(resourceA); | ||
| 237 | ConvertResourceToResourceW(resourceA, resource); | ||
| 238 | return result; | ||
| 239 | } | ||
| 240 | #endif | ||
| 241 | |||
| 242 | |||
| 243 | DWORD GetResourceParent(const CResource &resource, CResource &parentResource) | ||
| 244 | { | ||
| 245 | const DWORD kBufferSize = 16384; | ||
| 246 | CByteArr byteBuffer(kBufferSize); | ||
| 247 | LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); | ||
| 248 | ZeroMemory(lpnrLocal, kBufferSize); | ||
| 249 | DWORD bufferSize = kBufferSize; | ||
| 250 | NETRESOURCE netResource; | ||
| 251 | ConvertCResourceToNETRESOURCE(resource, netResource); | ||
| 252 | DWORD result = ::WNetGetResourceParent(&netResource, lpnrLocal, &bufferSize); | ||
| 253 | if (result != NO_ERROR) | ||
| 254 | return result; | ||
| 255 | ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource); | ||
| 256 | return result; | ||
| 257 | } | ||
| 258 | |||
| 259 | #ifndef _UNICODE | ||
| 260 | DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource) | ||
| 261 | { | ||
| 262 | if (g_IsNT) | ||
| 263 | { | ||
| 264 | const DWORD kBufferSize = 16384; | ||
| 265 | CByteArr byteBuffer(kBufferSize); | ||
| 266 | LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); | ||
| 267 | ZeroMemory(lpnrLocal, kBufferSize); | ||
| 268 | DWORD bufferSize = kBufferSize; | ||
| 269 | NETRESOURCEW netResource; | ||
| 270 | ConvertCResourceToNETRESOURCE(resource, netResource); | ||
| 271 | DWORD result = ::WNetGetResourceParentW(&netResource, lpnrLocal, &bufferSize); | ||
| 272 | if (result != NO_ERROR) | ||
| 273 | return result; | ||
| 274 | ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource); | ||
| 275 | return result; | ||
| 276 | } | ||
| 277 | CResource resourceA, parentResourceA; | ||
| 278 | ConvertResourceWToResource(resource, resourceA); | ||
| 279 | DWORD result = GetResourceParent(resourceA, parentResourceA); | ||
| 280 | ConvertResourceToResourceW(parentResourceA, parentResource); | ||
| 281 | return result; | ||
| 282 | } | ||
| 283 | #endif | ||
| 284 | |||
| 285 | DWORD GetResourceInformation(const CResource &resource, | ||
| 286 | CResource &destResource, CSysString &systemPathPart) | ||
| 287 | { | ||
| 288 | const DWORD kBufferSize = 16384; | ||
| 289 | CByteArr byteBuffer(kBufferSize); | ||
| 290 | LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); | ||
| 291 | ZeroMemory(lpnrLocal, kBufferSize); | ||
| 292 | DWORD bufferSize = kBufferSize; | ||
| 293 | NETRESOURCE netResource; | ||
| 294 | ConvertCResourceToNETRESOURCE(resource, netResource); | ||
| 295 | LPTSTR lplpSystem; | ||
| 296 | DWORD result = ::WNetGetResourceInformation(&netResource, | ||
| 297 | lpnrLocal, &bufferSize, &lplpSystem); | ||
| 298 | if (result != NO_ERROR) | ||
| 299 | return result; | ||
| 300 | if (lplpSystem != 0) | ||
| 301 | systemPathPart = lplpSystem; | ||
| 302 | ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource); | ||
| 303 | return result; | ||
| 304 | } | ||
| 305 | |||
| 306 | #ifndef _UNICODE | ||
| 307 | DWORD GetResourceInformation(const CResourceW &resource, | ||
| 308 | CResourceW &destResource, UString &systemPathPart) | ||
| 309 | { | ||
| 310 | if (g_IsNT) | ||
| 311 | { | ||
| 312 | const DWORD kBufferSize = 16384; | ||
| 313 | CByteArr byteBuffer(kBufferSize); | ||
| 314 | LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); | ||
| 315 | ZeroMemory(lpnrLocal, kBufferSize); | ||
| 316 | DWORD bufferSize = kBufferSize; | ||
| 317 | NETRESOURCEW netResource; | ||
| 318 | ConvertCResourceToNETRESOURCE(resource, netResource); | ||
| 319 | LPWSTR lplpSystem; | ||
| 320 | DWORD result = ::WNetGetResourceInformationW(&netResource, | ||
| 321 | lpnrLocal, &bufferSize, &lplpSystem); | ||
| 322 | if (result != NO_ERROR) | ||
| 323 | return result; | ||
| 324 | if (lplpSystem != 0) | ||
| 325 | systemPathPart = lplpSystem; | ||
| 326 | ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource); | ||
| 327 | return result; | ||
| 328 | } | ||
| 329 | CResource resourceA, destResourceA; | ||
| 330 | ConvertResourceWToResource(resource, resourceA); | ||
| 331 | AString systemPathPartA; | ||
| 332 | DWORD result = GetResourceInformation(resourceA, destResourceA, systemPathPartA); | ||
| 333 | ConvertResourceToResourceW(destResourceA, destResource); | ||
| 334 | systemPathPart = GetUnicodeString(systemPathPartA); | ||
| 335 | return result; | ||
| 336 | } | ||
| 337 | #endif | ||
| 338 | |||
| 339 | DWORD AddConnection2(const CResource &resource, | ||
| 340 | LPCTSTR password, LPCTSTR userName, DWORD flags) | ||
| 341 | { | ||
| 342 | NETRESOURCE netResource; | ||
| 343 | ConvertCResourceToNETRESOURCE(resource, netResource); | ||
| 344 | return ::WNetAddConnection2(&netResource, | ||
| 345 | password, userName, flags); | ||
| 346 | } | ||
| 347 | |||
| 348 | DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags); | ||
| 349 | |||
| 350 | #ifndef _UNICODE | ||
| 351 | DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags) | ||
| 352 | { | ||
| 353 | if (g_IsNT) | ||
| 354 | { | ||
| 355 | NETRESOURCEW netResource; | ||
| 356 | ConvertCResourceToNETRESOURCE(resource, netResource); | ||
| 357 | return ::WNetAddConnection2W(&netResource,password, userName, flags); | ||
| 358 | } | ||
| 359 | CResource resourceA; | ||
| 360 | ConvertResourceWToResource(resource, resourceA); | ||
| 361 | const CSysString passwordA (GetSystemString(password)); | ||
| 362 | const CSysString userNameA (GetSystemString(userName)); | ||
| 363 | return AddConnection2(resourceA, | ||
| 364 | password ? (LPCTSTR)passwordA: 0, | ||
| 365 | userName ? (LPCTSTR)userNameA: 0, | ||
| 366 | flags); | ||
| 367 | } | ||
| 368 | #endif | ||
| 369 | |||
| 370 | }} | ||
diff --git a/CPP/Windows/Net.h b/CPP/Windows/Net.h new file mode 100644 index 0000000..7b60b1b --- /dev/null +++ b/CPP/Windows/Net.h | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | // Windows/Net.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_NET_H | ||
| 4 | #define __WINDOWS_NET_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | namespace NNet { | ||
| 10 | |||
| 11 | struct CResourceBase | ||
| 12 | { | ||
| 13 | DWORD Scope; | ||
| 14 | DWORD Type; | ||
| 15 | DWORD DisplayType; | ||
| 16 | DWORD Usage; | ||
| 17 | bool LocalNameIsDefined; | ||
| 18 | bool RemoteNameIsDefined; | ||
| 19 | bool CommentIsDefined; | ||
| 20 | bool ProviderIsDefined; | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct CResource: public CResourceBase | ||
| 24 | { | ||
| 25 | CSysString LocalName; | ||
| 26 | CSysString RemoteName; | ||
| 27 | CSysString Comment; | ||
| 28 | CSysString Provider; | ||
| 29 | }; | ||
| 30 | |||
| 31 | #ifdef _UNICODE | ||
| 32 | typedef CResource CResourceW; | ||
| 33 | #else | ||
| 34 | struct CResourceW: public CResourceBase | ||
| 35 | { | ||
| 36 | UString LocalName; | ||
| 37 | UString RemoteName; | ||
| 38 | UString Comment; | ||
| 39 | UString Provider; | ||
| 40 | }; | ||
| 41 | #endif | ||
| 42 | |||
| 43 | class CEnum | ||
| 44 | { | ||
| 45 | HANDLE _handle; | ||
| 46 | bool _handleAllocated; | ||
| 47 | DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource); | ||
| 48 | DWORD Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); | ||
| 49 | #ifndef _UNICODE | ||
| 50 | DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource); | ||
| 51 | DWORD NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); | ||
| 52 | #endif | ||
| 53 | protected: | ||
| 54 | bool IsHandleAllocated() const { return _handleAllocated; } | ||
| 55 | public: | ||
| 56 | CEnum(): _handleAllocated(false) {} | ||
| 57 | ~CEnum() { Close(); } | ||
| 58 | DWORD Close(); | ||
| 59 | DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource); | ||
| 60 | DWORD Next(CResource &resource); | ||
| 61 | #ifndef _UNICODE | ||
| 62 | DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource); | ||
| 63 | DWORD Next(CResourceW &resource); | ||
| 64 | #endif | ||
| 65 | }; | ||
| 66 | |||
| 67 | DWORD GetResourceParent(const CResource &resource, CResource &parentResource); | ||
| 68 | #ifndef _UNICODE | ||
| 69 | DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource); | ||
| 70 | #endif | ||
| 71 | |||
| 72 | DWORD GetResourceInformation(const CResource &resource, | ||
| 73 | CResource &destResource, CSysString &systemPathPart); | ||
| 74 | #ifndef _UNICODE | ||
| 75 | DWORD GetResourceInformation(const CResourceW &resource, | ||
| 76 | CResourceW &destResource, UString &systemPathPart); | ||
| 77 | #endif | ||
| 78 | |||
| 79 | DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags); | ||
| 80 | #ifndef _UNICODE | ||
| 81 | DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags); | ||
| 82 | #endif | ||
| 83 | |||
| 84 | }} | ||
| 85 | |||
| 86 | #endif | ||
diff --git a/CPP/Windows/NtCheck.h b/CPP/Windows/NtCheck.h new file mode 100644 index 0000000..0af3291 --- /dev/null +++ b/CPP/Windows/NtCheck.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | // Windows/NtCheck.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_NT_CHECK_H | ||
| 4 | #define __WINDOWS_NT_CHECK_H | ||
| 5 | |||
| 6 | #ifdef _WIN32 | ||
| 7 | |||
| 8 | #include "../Common/MyWindows.h" | ||
| 9 | |||
| 10 | #if !defined(_WIN64) && !defined(UNDER_CE) | ||
| 11 | static inline bool IsItWindowsNT() | ||
| 12 | { | ||
| 13 | OSVERSIONINFO vi; | ||
| 14 | vi.dwOSVersionInfoSize = sizeof(vi); | ||
| 15 | return (::GetVersionEx(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_NT); | ||
| 16 | } | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #ifndef _UNICODE | ||
| 20 | extern | ||
| 21 | bool g_IsNT; | ||
| 22 | #if defined(_WIN64) || defined(UNDER_CE) | ||
| 23 | bool g_IsNT = true; | ||
| 24 | #define SET_IS_NT | ||
| 25 | #else | ||
| 26 | bool g_IsNT = false; | ||
| 27 | #define SET_IS_NT g_IsNT = IsItWindowsNT(); | ||
| 28 | #endif | ||
| 29 | #define NT_CHECK_ACTION | ||
| 30 | // #define NT_CHECK_ACTION { NT_CHECK_FAIL_ACTION } | ||
| 31 | #else | ||
| 32 | #if !defined(_WIN64) && !defined(UNDER_CE) | ||
| 33 | #define NT_CHECK_ACTION if (!IsItWindowsNT()) { NT_CHECK_FAIL_ACTION } | ||
| 34 | #else | ||
| 35 | #define NT_CHECK_ACTION | ||
| 36 | #endif | ||
| 37 | #define SET_IS_NT | ||
| 38 | #endif | ||
| 39 | |||
| 40 | #define NT_CHECK NT_CHECK_ACTION SET_IS_NT | ||
| 41 | |||
| 42 | #else | ||
| 43 | |||
| 44 | #define NT_CHECK | ||
| 45 | |||
| 46 | #endif | ||
| 47 | |||
| 48 | #endif | ||
diff --git a/CPP/Windows/ProcessMessages.cpp b/CPP/Windows/ProcessMessages.cpp new file mode 100644 index 0000000..0f48aee --- /dev/null +++ b/CPP/Windows/ProcessMessages.cpp | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // Windows/ProcessMessages.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "ProcessMessages.h" | ||
| 6 | |||
| 7 | namespace NWindows { | ||
| 8 | |||
| 9 | void ProcessMessages(HWND window) | ||
| 10 | { | ||
| 11 | MSG msg; | ||
| 12 | while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) | ||
| 13 | { | ||
| 14 | if (window == (HWND) NULL || !IsDialogMessage(window, &msg)) | ||
| 15 | { | ||
| 16 | TranslateMessage(&msg); | ||
| 17 | DispatchMessage(&msg); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | } | ||
diff --git a/CPP/Windows/ProcessMessages.h b/CPP/Windows/ProcessMessages.h new file mode 100644 index 0000000..b2558a0 --- /dev/null +++ b/CPP/Windows/ProcessMessages.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | // Windows/ProcessMessages.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_PROCESSMESSAGES_H | ||
| 4 | #define __WINDOWS_PROCESSMESSAGES_H | ||
| 5 | |||
| 6 | namespace NWindows { | ||
| 7 | |||
| 8 | void ProcessMessages(HWND window); | ||
| 9 | |||
| 10 | } | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/CPP/Windows/ProcessUtils.cpp b/CPP/Windows/ProcessUtils.cpp new file mode 100644 index 0000000..9bf0538 --- /dev/null +++ b/CPP/Windows/ProcessUtils.cpp | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | // ProcessUtils.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../Common/StringConvert.h" | ||
| 6 | |||
| 7 | #include "ProcessUtils.h" | ||
| 8 | |||
| 9 | #ifndef _UNICODE | ||
| 10 | extern bool g_IsNT; | ||
| 11 | #endif | ||
| 12 | |||
| 13 | namespace NWindows { | ||
| 14 | |||
| 15 | #ifndef UNDER_CE | ||
| 16 | static UString GetQuotedString(const UString &s) | ||
| 17 | { | ||
| 18 | UString s2 ('\"'); | ||
| 19 | s2 += s; | ||
| 20 | s2 += '\"'; | ||
| 21 | return s2; | ||
| 22 | } | ||
| 23 | #endif | ||
| 24 | |||
| 25 | WRes CProcess::Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir) | ||
| 26 | { | ||
| 27 | /* | ||
| 28 | OutputDebugStringW(L"CProcess::Create"); | ||
| 29 | OutputDebugStringW(imageName); | ||
| 30 | if (params) | ||
| 31 | { | ||
| 32 | OutputDebugStringW(L"params:"); | ||
| 33 | OutputDebugStringW(params); | ||
| 34 | } | ||
| 35 | if (curDir) | ||
| 36 | { | ||
| 37 | OutputDebugStringW(L"cur dir:"); | ||
| 38 | OutputDebugStringW(curDir); | ||
| 39 | } | ||
| 40 | */ | ||
| 41 | |||
| 42 | Close(); | ||
| 43 | const UString params2 = | ||
| 44 | #ifndef UNDER_CE | ||
| 45 | GetQuotedString(imageName) + L' ' + | ||
| 46 | #endif | ||
| 47 | params; | ||
| 48 | #ifdef UNDER_CE | ||
| 49 | curDir = 0; | ||
| 50 | #else | ||
| 51 | imageName = 0; | ||
| 52 | #endif | ||
| 53 | PROCESS_INFORMATION pi; | ||
| 54 | BOOL result; | ||
| 55 | #ifndef _UNICODE | ||
| 56 | if (!g_IsNT) | ||
| 57 | { | ||
| 58 | STARTUPINFOA si; | ||
| 59 | si.cb = sizeof(si); | ||
| 60 | si.lpReserved = 0; | ||
| 61 | si.lpDesktop = 0; | ||
| 62 | si.lpTitle = 0; | ||
| 63 | si.dwFlags = 0; | ||
| 64 | si.cbReserved2 = 0; | ||
| 65 | si.lpReserved2 = 0; | ||
| 66 | |||
| 67 | CSysString curDirA; | ||
| 68 | if (curDir != 0) | ||
| 69 | curDirA = GetSystemString(curDir); | ||
| 70 | const AString s = GetSystemString(params2); | ||
| 71 | result = ::CreateProcessA(NULL, s.Ptr_non_const(), | ||
| 72 | NULL, NULL, FALSE, 0, NULL, ((curDir != 0) ? (LPCSTR)curDirA: 0), &si, &pi); | ||
| 73 | } | ||
| 74 | else | ||
| 75 | #endif | ||
| 76 | { | ||
| 77 | STARTUPINFOW si; | ||
| 78 | si.cb = sizeof(si); | ||
| 79 | si.lpReserved = 0; | ||
| 80 | si.lpDesktop = 0; | ||
| 81 | si.lpTitle = 0; | ||
| 82 | si.dwFlags = 0; | ||
| 83 | si.cbReserved2 = 0; | ||
| 84 | si.lpReserved2 = 0; | ||
| 85 | |||
| 86 | result = CreateProcessW(imageName, params2.Ptr_non_const(), | ||
| 87 | NULL, NULL, FALSE, 0, NULL, curDir, &si, &pi); | ||
| 88 | } | ||
| 89 | if (result == 0) | ||
| 90 | return ::GetLastError(); | ||
| 91 | ::CloseHandle(pi.hThread); | ||
| 92 | _handle = pi.hProcess; | ||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms) | ||
| 97 | { | ||
| 98 | CProcess process; | ||
| 99 | return process.Create(imageName, params, 0); | ||
| 100 | } | ||
| 101 | |||
| 102 | } | ||
diff --git a/CPP/Windows/ProcessUtils.h b/CPP/Windows/ProcessUtils.h new file mode 100644 index 0000000..e46f9ab --- /dev/null +++ b/CPP/Windows/ProcessUtils.h | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | // Windows/ProcessUtils.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_PROCESS_UTILS_H | ||
| 4 | #define __WINDOWS_PROCESS_UTILS_H | ||
| 5 | |||
| 6 | #include <Psapi.h> | ||
| 7 | |||
| 8 | #include "../Common/MyString.h" | ||
| 9 | |||
| 10 | #include "Defs.h" | ||
| 11 | #include "Handle.h" | ||
| 12 | |||
| 13 | namespace NWindows { | ||
| 14 | |||
| 15 | class CProcess: public CHandle | ||
| 16 | { | ||
| 17 | public: | ||
| 18 | bool Open(DWORD desiredAccess, bool inheritHandle, DWORD processId) | ||
| 19 | { | ||
| 20 | _handle = ::OpenProcess(desiredAccess, inheritHandle, processId); | ||
| 21 | return (_handle != 0); | ||
| 22 | } | ||
| 23 | |||
| 24 | #ifndef UNDER_CE | ||
| 25 | |||
| 26 | bool GetExitCodeProcess(LPDWORD lpExitCode) { return BOOLToBool(::GetExitCodeProcess(_handle, lpExitCode)); } | ||
| 27 | bool Terminate(UINT exitCode) { return BOOLToBool(::TerminateProcess(_handle, exitCode)); } | ||
| 28 | #if (WINVER >= 0x0500) | ||
| 29 | DWORD GetGuiResources (DWORD uiFlags) { return ::GetGuiResources(_handle, uiFlags); } | ||
| 30 | #endif | ||
| 31 | bool SetPriorityClass(DWORD dwPriorityClass) { return BOOLToBool(::SetPriorityClass(_handle, dwPriorityClass)); } | ||
| 32 | DWORD GetPriorityClass() { return ::GetPriorityClass(_handle); } | ||
| 33 | // bool GetIoCounters(PIO_COUNTERS lpIoCounters ) { return BOOLToBool(::GetProcessIoCounters(_handle, lpIoCounters )); } | ||
| 34 | |||
| 35 | bool GetTimes(LPFILETIME creationTime, LPFILETIME exitTime, LPFILETIME kernelTime, LPFILETIME userTime) | ||
| 36 | { return BOOLToBool(::GetProcessTimes(_handle, creationTime, exitTime, kernelTime, userTime)); } | ||
| 37 | |||
| 38 | DWORD WaitForInputIdle(DWORD milliseconds) { return ::WaitForInputIdle(_handle, milliseconds); } | ||
| 39 | |||
| 40 | // Debug | ||
| 41 | |||
| 42 | bool ReadMemory(LPCVOID baseAddress, LPVOID buffer, SIZE_T size, SIZE_T* numberOfBytesRead) | ||
| 43 | { return BOOLToBool(::ReadProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesRead)); } | ||
| 44 | |||
| 45 | bool WriteMemory(LPVOID baseAddress, LPCVOID buffer, SIZE_T size, SIZE_T* numberOfBytesWritten) | ||
| 46 | { return BOOLToBool(::WriteProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesWritten)); } | ||
| 47 | |||
| 48 | bool FlushInstructionCache(LPCVOID baseAddress = 0, SIZE_T size = 0) | ||
| 49 | { return BOOLToBool(::FlushInstructionCache(_handle, baseAddress, size)); } | ||
| 50 | |||
| 51 | LPVOID VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect) | ||
| 52 | { return VirtualAllocEx(_handle, address, size, allocationType, protect); } | ||
| 53 | |||
| 54 | bool VirtualFree(LPVOID address, SIZE_T size, DWORD freeType) | ||
| 55 | { return BOOLToBool(::VirtualFreeEx(_handle, address, size, freeType)); } | ||
| 56 | |||
| 57 | // Process Status API (PSAPI) | ||
| 58 | |||
| 59 | bool EmptyWorkingSet() | ||
| 60 | { return BOOLToBool(::EmptyWorkingSet(_handle)); } | ||
| 61 | bool EnumModules(HMODULE *hModules, DWORD arraySizeInBytes, LPDWORD receivedBytes) | ||
| 62 | { return BOOLToBool(::EnumProcessModules(_handle, hModules, arraySizeInBytes, receivedBytes)); } | ||
| 63 | |||
| 64 | DWORD MyGetModuleBaseName(HMODULE hModule, LPTSTR baseName, DWORD size) | ||
| 65 | { return ::GetModuleBaseName(_handle, hModule, baseName, size); } | ||
| 66 | bool MyGetModuleBaseName(HMODULE hModule, CSysString &name) | ||
| 67 | { | ||
| 68 | const unsigned len = MAX_PATH + 100; | ||
| 69 | DWORD resultLen = MyGetModuleBaseName(hModule, name.GetBuf(len), len); | ||
| 70 | name.ReleaseBuf_CalcLen(len); | ||
| 71 | return (resultLen != 0); | ||
| 72 | } | ||
| 73 | |||
| 74 | DWORD MyGetModuleFileNameEx(HMODULE hModule, LPTSTR baseName, DWORD size) | ||
| 75 | { return ::GetModuleFileNameEx(_handle, hModule, baseName, size); } | ||
| 76 | bool MyGetModuleFileNameEx(HMODULE hModule, CSysString &name) | ||
| 77 | { | ||
| 78 | const unsigned len = MAX_PATH + 100; | ||
| 79 | DWORD resultLen = MyGetModuleFileNameEx(hModule, name.GetBuf(len), len); | ||
| 80 | name.ReleaseBuf_CalcLen(len); | ||
| 81 | return (resultLen != 0); | ||
| 82 | } | ||
| 83 | |||
| 84 | bool GetModuleInformation(HMODULE hModule, LPMODULEINFO moduleInfo) | ||
| 85 | { return BOOLToBool(::GetModuleInformation(_handle, hModule, moduleInfo, sizeof(MODULEINFO))); } | ||
| 86 | bool GetMemoryInfo(PPROCESS_MEMORY_COUNTERS memCounters) | ||
| 87 | { return BOOLToBool(::GetProcessMemoryInfo(_handle, memCounters, sizeof(PROCESS_MEMORY_COUNTERS))); } | ||
| 88 | |||
| 89 | #endif | ||
| 90 | |||
| 91 | WRes Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir); | ||
| 92 | |||
| 93 | DWORD Wait() { return ::WaitForSingleObject(_handle, INFINITE); } | ||
| 94 | }; | ||
| 95 | |||
| 96 | WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms); | ||
| 97 | |||
| 98 | } | ||
| 99 | |||
| 100 | #endif | ||
diff --git a/CPP/Windows/PropVariant.cpp b/CPP/Windows/PropVariant.cpp new file mode 100644 index 0000000..6e43c7b --- /dev/null +++ b/CPP/Windows/PropVariant.cpp | |||
| @@ -0,0 +1,361 @@ | |||
| 1 | // Windows/PropVariant.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../Common/Defs.h" | ||
| 6 | |||
| 7 | #include "PropVariant.h" | ||
| 8 | |||
| 9 | namespace NWindows { | ||
| 10 | namespace NCOM { | ||
| 11 | |||
| 12 | BSTR AllocBstrFromAscii(const char *s) throw() | ||
| 13 | { | ||
| 14 | if (!s) | ||
| 15 | return NULL; | ||
| 16 | UINT len = (UINT)strlen(s); | ||
| 17 | BSTR p = ::SysAllocStringLen(NULL, len); | ||
| 18 | if (p) | ||
| 19 | { | ||
| 20 | for (UINT i = 0; i <= len; i++) | ||
| 21 | p[i] = (Byte)s[i]; | ||
| 22 | } | ||
| 23 | return p; | ||
| 24 | } | ||
| 25 | |||
| 26 | HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw() | ||
| 27 | { | ||
| 28 | p->bstrVal = ::SysAllocStringLen(NULL, numChars); | ||
| 29 | if (!p->bstrVal) | ||
| 30 | { | ||
| 31 | p->vt = VT_ERROR; | ||
| 32 | p->scode = E_OUTOFMEMORY; | ||
| 33 | return E_OUTOFMEMORY; | ||
| 34 | } | ||
| 35 | p->vt = VT_BSTR; | ||
| 36 | return S_OK; | ||
| 37 | } | ||
| 38 | |||
| 39 | HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw() | ||
| 40 | { | ||
| 41 | p->bstrVal = AllocBstrFromAscii(s); | ||
| 42 | if (p->bstrVal) | ||
| 43 | { | ||
| 44 | p->vt = VT_BSTR; | ||
| 45 | return S_OK; | ||
| 46 | } | ||
| 47 | p->vt = VT_ERROR; | ||
| 48 | p->scode = E_OUTOFMEMORY; | ||
| 49 | return E_OUTOFMEMORY; | ||
| 50 | } | ||
| 51 | |||
| 52 | CPropVariant::CPropVariant(const PROPVARIANT &varSrc) | ||
| 53 | { | ||
| 54 | vt = VT_EMPTY; | ||
| 55 | InternalCopy(&varSrc); | ||
| 56 | } | ||
| 57 | |||
| 58 | CPropVariant::CPropVariant(const CPropVariant &varSrc) | ||
| 59 | { | ||
| 60 | vt = VT_EMPTY; | ||
| 61 | InternalCopy(&varSrc); | ||
| 62 | } | ||
| 63 | |||
| 64 | CPropVariant::CPropVariant(BSTR bstrSrc) | ||
| 65 | { | ||
| 66 | vt = VT_EMPTY; | ||
| 67 | *this = bstrSrc; | ||
| 68 | } | ||
| 69 | |||
| 70 | CPropVariant::CPropVariant(LPCOLESTR lpszSrc) | ||
| 71 | { | ||
| 72 | vt = VT_EMPTY; | ||
| 73 | *this = lpszSrc; | ||
| 74 | } | ||
| 75 | |||
| 76 | CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc) | ||
| 77 | { | ||
| 78 | InternalCopy(&varSrc); | ||
| 79 | return *this; | ||
| 80 | } | ||
| 81 | |||
| 82 | CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc) | ||
| 83 | { | ||
| 84 | InternalCopy(&varSrc); | ||
| 85 | return *this; | ||
| 86 | } | ||
| 87 | |||
| 88 | CPropVariant& CPropVariant::operator=(BSTR bstrSrc) | ||
| 89 | { | ||
| 90 | *this = (LPCOLESTR)bstrSrc; | ||
| 91 | return *this; | ||
| 92 | } | ||
| 93 | |||
| 94 | static const char * const kMemException = "out of memory"; | ||
| 95 | |||
| 96 | CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc) | ||
| 97 | { | ||
| 98 | InternalClear(); | ||
| 99 | vt = VT_BSTR; | ||
| 100 | wReserved1 = 0; | ||
| 101 | bstrVal = ::SysAllocString(lpszSrc); | ||
| 102 | if (!bstrVal && lpszSrc) | ||
| 103 | { | ||
| 104 | throw kMemException; | ||
| 105 | // vt = VT_ERROR; | ||
| 106 | // scode = E_OUTOFMEMORY; | ||
| 107 | } | ||
| 108 | return *this; | ||
| 109 | } | ||
| 110 | |||
| 111 | CPropVariant& CPropVariant::operator=(const UString &s) | ||
| 112 | { | ||
| 113 | InternalClear(); | ||
| 114 | vt = VT_BSTR; | ||
| 115 | wReserved1 = 0; | ||
| 116 | bstrVal = ::SysAllocStringLen(s, s.Len()); | ||
| 117 | if (!bstrVal) | ||
| 118 | throw kMemException; | ||
| 119 | return *this; | ||
| 120 | } | ||
| 121 | |||
| 122 | CPropVariant& CPropVariant::operator=(const UString2 &s) | ||
| 123 | { | ||
| 124 | /* | ||
| 125 | if (s.IsEmpty()) | ||
| 126 | *this = L""; | ||
| 127 | else | ||
| 128 | */ | ||
| 129 | { | ||
| 130 | InternalClear(); | ||
| 131 | vt = VT_BSTR; | ||
| 132 | wReserved1 = 0; | ||
| 133 | bstrVal = ::SysAllocStringLen(s.GetRawPtr(), s.Len()); | ||
| 134 | if (!bstrVal) | ||
| 135 | throw kMemException; | ||
| 136 | /* SysAllocStringLen probably appends a null-terminating character for NULL string. | ||
| 137 | But it doesn't specified in MSDN. | ||
| 138 | But we suppose that it works | ||
| 139 | |||
| 140 | if (!s.GetRawPtr()) | ||
| 141 | { | ||
| 142 | *bstrVal = 0; | ||
| 143 | } | ||
| 144 | */ | ||
| 145 | |||
| 146 | /* MSDN: Windows CE: SysAllocStringLen() : Passing invalid (and under some circumstances NULL) | ||
| 147 | pointers to this function causes an unexpected termination of the application. | ||
| 148 | Is it safe? Maybe we must chamnge the code for that case ? */ | ||
| 149 | } | ||
| 150 | return *this; | ||
| 151 | } | ||
| 152 | |||
| 153 | CPropVariant& CPropVariant::operator=(const char *s) | ||
| 154 | { | ||
| 155 | InternalClear(); | ||
| 156 | vt = VT_BSTR; | ||
| 157 | wReserved1 = 0; | ||
| 158 | bstrVal = AllocBstrFromAscii(s); | ||
| 159 | if (!bstrVal) | ||
| 160 | { | ||
| 161 | throw kMemException; | ||
| 162 | // vt = VT_ERROR; | ||
| 163 | // scode = E_OUTOFMEMORY; | ||
| 164 | } | ||
| 165 | return *this; | ||
| 166 | } | ||
| 167 | |||
| 168 | CPropVariant& CPropVariant::operator=(bool bSrc) throw() | ||
| 169 | { | ||
| 170 | if (vt != VT_BOOL) | ||
| 171 | { | ||
| 172 | InternalClear(); | ||
| 173 | vt = VT_BOOL; | ||
| 174 | } | ||
| 175 | boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; | ||
| 176 | return *this; | ||
| 177 | } | ||
| 178 | |||
| 179 | BSTR CPropVariant::AllocBstr(unsigned numChars) | ||
| 180 | { | ||
| 181 | if (vt != VT_EMPTY) | ||
| 182 | InternalClear(); | ||
| 183 | vt = VT_BSTR; | ||
| 184 | wReserved1 = 0; | ||
| 185 | bstrVal = ::SysAllocStringLen(NULL, numChars); | ||
| 186 | if (!bstrVal) | ||
| 187 | { | ||
| 188 | throw kMemException; | ||
| 189 | // vt = VT_ERROR; | ||
| 190 | // scode = E_OUTOFMEMORY; | ||
| 191 | } | ||
| 192 | return bstrVal; | ||
| 193 | } | ||
| 194 | |||
| 195 | #define SET_PROP_id_dest(id, dest) \ | ||
| 196 | if (vt != id) { InternalClear(); vt = id; } dest = value; | ||
| 197 | |||
| 198 | void CPropVariant::Set_Int32(Int32 value) throw() | ||
| 199 | { | ||
| 200 | SET_PROP_id_dest(VT_I4, lVal); | ||
| 201 | } | ||
| 202 | |||
| 203 | void CPropVariant::Set_Int64(Int64 value) throw() | ||
| 204 | { | ||
| 205 | SET_PROP_id_dest(VT_I8, hVal.QuadPart); | ||
| 206 | } | ||
| 207 | |||
| 208 | #define SET_PROP_FUNC(type, id, dest) \ | ||
| 209 | CPropVariant& CPropVariant::operator=(type value) throw() \ | ||
| 210 | { SET_PROP_id_dest(id, dest); return *this; } | ||
| 211 | |||
| 212 | SET_PROP_FUNC(Byte, VT_UI1, bVal) | ||
| 213 | // SET_PROP_FUNC(Int16, VT_I2, iVal) | ||
| 214 | // SET_PROP_FUNC(Int32, VT_I4, lVal) | ||
| 215 | SET_PROP_FUNC(UInt32, VT_UI4, ulVal) | ||
| 216 | SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart) | ||
| 217 | // SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) | ||
| 218 | SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime) | ||
| 219 | |||
| 220 | HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() | ||
| 221 | { | ||
| 222 | switch (prop->vt) | ||
| 223 | { | ||
| 224 | case VT_EMPTY: | ||
| 225 | case VT_UI1: | ||
| 226 | case VT_I1: | ||
| 227 | case VT_I2: | ||
| 228 | case VT_UI2: | ||
| 229 | case VT_BOOL: | ||
| 230 | case VT_I4: | ||
| 231 | case VT_UI4: | ||
| 232 | case VT_R4: | ||
| 233 | case VT_INT: | ||
| 234 | case VT_UINT: | ||
| 235 | case VT_ERROR: | ||
| 236 | case VT_FILETIME: | ||
| 237 | case VT_UI8: | ||
| 238 | case VT_R8: | ||
| 239 | case VT_CY: | ||
| 240 | case VT_DATE: | ||
| 241 | prop->vt = VT_EMPTY; | ||
| 242 | prop->wReserved1 = 0; | ||
| 243 | prop->wReserved2 = 0; | ||
| 244 | prop->wReserved3 = 0; | ||
| 245 | prop->uhVal.QuadPart = 0; | ||
| 246 | return S_OK; | ||
| 247 | } | ||
| 248 | return ::VariantClear((VARIANTARG *)prop); | ||
| 249 | // return ::PropVariantClear(prop); | ||
| 250 | // PropVariantClear can clear VT_BLOB. | ||
| 251 | } | ||
| 252 | |||
| 253 | HRESULT CPropVariant::Clear() throw() | ||
| 254 | { | ||
| 255 | if (vt == VT_EMPTY) | ||
| 256 | return S_OK; | ||
| 257 | return PropVariant_Clear(this); | ||
| 258 | } | ||
| 259 | |||
| 260 | HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw() | ||
| 261 | { | ||
| 262 | ::VariantClear((tagVARIANT *)this); | ||
| 263 | switch (pSrc->vt) | ||
| 264 | { | ||
| 265 | case VT_UI1: | ||
| 266 | case VT_I1: | ||
| 267 | case VT_I2: | ||
| 268 | case VT_UI2: | ||
| 269 | case VT_BOOL: | ||
| 270 | case VT_I4: | ||
| 271 | case VT_UI4: | ||
| 272 | case VT_R4: | ||
| 273 | case VT_INT: | ||
| 274 | case VT_UINT: | ||
| 275 | case VT_ERROR: | ||
| 276 | case VT_FILETIME: | ||
| 277 | case VT_UI8: | ||
| 278 | case VT_R8: | ||
| 279 | case VT_CY: | ||
| 280 | case VT_DATE: | ||
| 281 | memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); | ||
| 282 | return S_OK; | ||
| 283 | } | ||
| 284 | return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc)); | ||
| 285 | } | ||
| 286 | |||
| 287 | |||
| 288 | HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() | ||
| 289 | { | ||
| 290 | HRESULT hr = Clear(); | ||
| 291 | if (FAILED(hr)) | ||
| 292 | return hr; | ||
| 293 | // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT)); | ||
| 294 | *(PROPVARIANT *)this = *pSrc; | ||
| 295 | pSrc->vt = VT_EMPTY; | ||
| 296 | return S_OK; | ||
| 297 | } | ||
| 298 | |||
| 299 | HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw() | ||
| 300 | { | ||
| 301 | if (pDest->vt != VT_EMPTY) | ||
| 302 | { | ||
| 303 | HRESULT hr = PropVariant_Clear(pDest); | ||
| 304 | if (FAILED(hr)) | ||
| 305 | return hr; | ||
| 306 | } | ||
| 307 | // memcpy(pDest, this, sizeof(PROPVARIANT)); | ||
| 308 | *pDest = *(PROPVARIANT *)this; | ||
| 309 | vt = VT_EMPTY; | ||
| 310 | return S_OK; | ||
| 311 | } | ||
| 312 | |||
| 313 | HRESULT CPropVariant::InternalClear() throw() | ||
| 314 | { | ||
| 315 | if (vt == VT_EMPTY) | ||
| 316 | return S_OK; | ||
| 317 | HRESULT hr = Clear(); | ||
| 318 | if (FAILED(hr)) | ||
| 319 | { | ||
| 320 | vt = VT_ERROR; | ||
| 321 | scode = hr; | ||
| 322 | } | ||
| 323 | return hr; | ||
| 324 | } | ||
| 325 | |||
| 326 | void CPropVariant::InternalCopy(const PROPVARIANT *pSrc) | ||
| 327 | { | ||
| 328 | HRESULT hr = Copy(pSrc); | ||
| 329 | if (FAILED(hr)) | ||
| 330 | { | ||
| 331 | if (hr == E_OUTOFMEMORY) | ||
| 332 | throw kMemException; | ||
| 333 | vt = VT_ERROR; | ||
| 334 | scode = hr; | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | int CPropVariant::Compare(const CPropVariant &a) throw() | ||
| 339 | { | ||
| 340 | if (vt != a.vt) | ||
| 341 | return MyCompare(vt, a.vt); | ||
| 342 | switch (vt) | ||
| 343 | { | ||
| 344 | case VT_EMPTY: return 0; | ||
| 345 | // case VT_I1: return MyCompare(cVal, a.cVal); | ||
| 346 | case VT_UI1: return MyCompare(bVal, a.bVal); | ||
| 347 | case VT_I2: return MyCompare(iVal, a.iVal); | ||
| 348 | case VT_UI2: return MyCompare(uiVal, a.uiVal); | ||
| 349 | case VT_I4: return MyCompare(lVal, a.lVal); | ||
| 350 | case VT_UI4: return MyCompare(ulVal, a.ulVal); | ||
| 351 | // case VT_UINT: return MyCompare(uintVal, a.uintVal); | ||
| 352 | case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart); | ||
| 353 | case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart); | ||
| 354 | case VT_BOOL: return -MyCompare(boolVal, a.boolVal); | ||
| 355 | case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime); | ||
| 356 | case VT_BSTR: return 0; // Not implemented | ||
| 357 | default: return 0; | ||
| 358 | } | ||
| 359 | } | ||
| 360 | |||
| 361 | }} | ||
diff --git a/CPP/Windows/PropVariant.h b/CPP/Windows/PropVariant.h new file mode 100644 index 0000000..108bf6b --- /dev/null +++ b/CPP/Windows/PropVariant.h | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | // Windows/PropVariant.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_PROP_VARIANT_H | ||
| 4 | #define __WINDOWS_PROP_VARIANT_H | ||
| 5 | |||
| 6 | #include "../Common/MyTypes.h" | ||
| 7 | #include "../Common/MyWindows.h" | ||
| 8 | #include "../Common/MyString.h" | ||
| 9 | |||
| 10 | namespace NWindows { | ||
| 11 | namespace NCOM { | ||
| 12 | |||
| 13 | BSTR AllocBstrFromAscii(const char *s) throw(); | ||
| 14 | |||
| 15 | HRESULT PropVariant_Clear(PROPVARIANT *p) throw(); | ||
| 16 | |||
| 17 | HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw(); | ||
| 18 | HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw(); | ||
| 19 | |||
| 20 | inline void PropVarEm_Set_UInt32(PROPVARIANT *p, UInt32 v) throw() | ||
| 21 | { | ||
| 22 | p->vt = VT_UI4; | ||
| 23 | p->ulVal = v; | ||
| 24 | } | ||
| 25 | |||
| 26 | inline void PropVarEm_Set_UInt64(PROPVARIANT *p, UInt64 v) throw() | ||
| 27 | { | ||
| 28 | p->vt = VT_UI8; | ||
| 29 | p->uhVal.QuadPart = v; | ||
| 30 | } | ||
| 31 | |||
| 32 | inline void PropVarEm_Set_FileTime64(PROPVARIANT *p, UInt64 v) throw() | ||
| 33 | { | ||
| 34 | p->vt = VT_FILETIME; | ||
| 35 | p->filetime.dwLowDateTime = (DWORD)v; | ||
| 36 | p->filetime.dwHighDateTime = (DWORD)(v >> 32); | ||
| 37 | } | ||
| 38 | |||
| 39 | inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw() | ||
| 40 | { | ||
| 41 | p->vt = VT_BOOL; | ||
| 42 | p->boolVal = (b ? VARIANT_TRUE : VARIANT_FALSE); | ||
| 43 | } | ||
| 44 | |||
| 45 | |||
| 46 | class CPropVariant : public tagPROPVARIANT | ||
| 47 | { | ||
| 48 | // ---------- forbidden functions ---------- | ||
| 49 | CPropVariant(const char *s); | ||
| 50 | // CPropVariant(const UString &s); | ||
| 51 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
| 52 | CPropVariant(const FString &s); | ||
| 53 | CPropVariant& operator=(const FString &s); | ||
| 54 | #endif | ||
| 55 | |||
| 56 | public: | ||
| 57 | CPropVariant() | ||
| 58 | { | ||
| 59 | vt = VT_EMPTY; | ||
| 60 | wReserved1 = 0; | ||
| 61 | // wReserved2 = 0; | ||
| 62 | // wReserved3 = 0; | ||
| 63 | // uhVal.QuadPart = 0; | ||
| 64 | bstrVal = 0; | ||
| 65 | } | ||
| 66 | ~CPropVariant() throw() { Clear(); } | ||
| 67 | CPropVariant(const PROPVARIANT &varSrc); | ||
| 68 | CPropVariant(const CPropVariant &varSrc); | ||
| 69 | CPropVariant(BSTR bstrSrc); | ||
| 70 | CPropVariant(LPCOLESTR lpszSrc); | ||
| 71 | CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); } | ||
| 72 | CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; } | ||
| 73 | |||
| 74 | private: | ||
| 75 | CPropVariant(UInt16 value); // { vt = VT_UI2; wReserved1 = 0; uiVal = value; } | ||
| 76 | CPropVariant(Int16 value); // { vt = VT_I2; wReserved1 = 0; iVal = value; } | ||
| 77 | CPropVariant(Int32 value); // { vt = VT_I4; wReserved1 = 0; lVal = value; } | ||
| 78 | CPropVariant(Int64 value); // { vt = VT_I8; wReserved1 = 0; hVal.QuadPart = value; } | ||
| 79 | |||
| 80 | public: | ||
| 81 | CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; } | ||
| 82 | CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; } | ||
| 83 | CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; } | ||
| 84 | |||
| 85 | CPropVariant& operator=(const CPropVariant &varSrc); | ||
| 86 | CPropVariant& operator=(const PROPVARIANT &varSrc); | ||
| 87 | CPropVariant& operator=(BSTR bstrSrc); | ||
| 88 | CPropVariant& operator=(LPCOLESTR lpszSrc); | ||
| 89 | CPropVariant& operator=(const UString &s); | ||
| 90 | CPropVariant& operator=(const UString2 &s); | ||
| 91 | CPropVariant& operator=(const char *s); | ||
| 92 | CPropVariant& operator=(const AString &s) | ||
| 93 | { return (*this)=(const char *)s; } | ||
| 94 | |||
| 95 | CPropVariant& operator=(bool bSrc) throw(); | ||
| 96 | CPropVariant& operator=(Byte value) throw(); | ||
| 97 | |||
| 98 | private: | ||
| 99 | CPropVariant& operator=(Int16 value) throw(); | ||
| 100 | CPropVariant& operator=(UInt16 value) throw(); | ||
| 101 | CPropVariant& operator=(Int32 value) throw(); | ||
| 102 | CPropVariant& operator=(Int64 value) throw(); | ||
| 103 | |||
| 104 | public: | ||
| 105 | CPropVariant& operator=(UInt32 value) throw(); | ||
| 106 | CPropVariant& operator=(UInt64 value) throw(); | ||
| 107 | CPropVariant& operator=(const FILETIME &value) throw(); | ||
| 108 | |||
| 109 | void Set_Int32(Int32 value) throw(); | ||
| 110 | void Set_Int64(Int64 value) throw(); | ||
| 111 | |||
| 112 | BSTR AllocBstr(unsigned numChars); | ||
| 113 | |||
| 114 | HRESULT Clear() throw(); | ||
| 115 | HRESULT Copy(const PROPVARIANT *pSrc) throw(); | ||
| 116 | HRESULT Attach(PROPVARIANT *pSrc) throw(); | ||
| 117 | HRESULT Detach(PROPVARIANT *pDest) throw(); | ||
| 118 | |||
| 119 | HRESULT InternalClear() throw(); | ||
| 120 | void InternalCopy(const PROPVARIANT *pSrc); | ||
| 121 | |||
| 122 | int Compare(const CPropVariant &a) throw(); | ||
| 123 | }; | ||
| 124 | |||
| 125 | }} | ||
| 126 | |||
| 127 | #endif | ||
diff --git a/CPP/Windows/PropVariantConv.cpp b/CPP/Windows/PropVariantConv.cpp new file mode 100644 index 0000000..b58d37e --- /dev/null +++ b/CPP/Windows/PropVariantConv.cpp | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | // PropVariantConv.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../Common/IntToString.h" | ||
| 6 | |||
| 7 | #include "Defs.h" | ||
| 8 | #include "PropVariantConv.h" | ||
| 9 | |||
| 10 | #define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; } | ||
| 11 | |||
| 12 | bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw() | ||
| 13 | { | ||
| 14 | *s = 0; | ||
| 15 | FILETIME ft; | ||
| 16 | if (!FileTimeToLocalFileTime(&utc, &ft)) | ||
| 17 | return false; | ||
| 18 | |||
| 19 | SYSTEMTIME st; | ||
| 20 | if (!BOOLToBool(FileTimeToSystemTime(&ft, &st))) | ||
| 21 | return false; | ||
| 22 | |||
| 23 | { | ||
| 24 | unsigned val = st.wYear; | ||
| 25 | if (val >= 10000) | ||
| 26 | { | ||
| 27 | *s++ = (char)('0' + val / 10000); | ||
| 28 | val %= 10000; | ||
| 29 | } | ||
| 30 | s[3] = (char)('0' + val % 10); val /= 10; | ||
| 31 | s[2] = (char)('0' + val % 10); val /= 10; | ||
| 32 | s[1] = (char)('0' + val % 10); | ||
| 33 | s[0] = (char)('0' + val / 10); | ||
| 34 | s += 4; | ||
| 35 | } | ||
| 36 | UINT_TO_STR_2('-', st.wMonth); | ||
| 37 | UINT_TO_STR_2('-', st.wDay); | ||
| 38 | |||
| 39 | if (level > kTimestampPrintLevel_DAY) | ||
| 40 | { | ||
| 41 | UINT_TO_STR_2(' ', st.wHour); | ||
| 42 | UINT_TO_STR_2(':', st.wMinute); | ||
| 43 | |||
| 44 | if (level >= kTimestampPrintLevel_SEC) | ||
| 45 | { | ||
| 46 | UINT_TO_STR_2(':', st.wSecond); | ||
| 47 | |||
| 48 | if (level > kTimestampPrintLevel_SEC) | ||
| 49 | { | ||
| 50 | *s++ = '.'; | ||
| 51 | /* | ||
| 52 | { | ||
| 53 | unsigned val = st.wMilliseconds; | ||
| 54 | s[2] = (char)('0' + val % 10); val /= 10; | ||
| 55 | s[1] = (char)('0' + val % 10); | ||
| 56 | s[0] = (char)('0' + val / 10); | ||
| 57 | s += 3; | ||
| 58 | } | ||
| 59 | *s++ = ' '; | ||
| 60 | */ | ||
| 61 | |||
| 62 | { | ||
| 63 | unsigned numDigits = 7; | ||
| 64 | UInt32 val = (UInt32)((((UInt64)ft.dwHighDateTime << 32) + ft.dwLowDateTime) % 10000000); | ||
| 65 | for (unsigned i = numDigits; i != 0;) | ||
| 66 | { | ||
| 67 | i--; | ||
| 68 | s[i] = (char)('0' + val % 10); val /= 10; | ||
| 69 | } | ||
| 70 | if (numDigits > (unsigned)level) | ||
| 71 | numDigits = (unsigned)level; | ||
| 72 | s += numDigits; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | *s = 0; | ||
| 79 | return true; | ||
| 80 | } | ||
| 81 | |||
| 82 | |||
| 83 | bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) throw() | ||
| 84 | { | ||
| 85 | char s[32]; | ||
| 86 | bool res = ConvertUtcFileTimeToString(ft, s, level); | ||
| 87 | for (unsigned i = 0;; i++) | ||
| 88 | { | ||
| 89 | Byte c = (Byte)s[i]; | ||
| 90 | dest[i] = c; | ||
| 91 | if (c == 0) | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | return res; | ||
| 95 | } | ||
| 96 | |||
| 97 | |||
| 98 | void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw() | ||
| 99 | { | ||
| 100 | *dest = 0; | ||
| 101 | switch (prop.vt) | ||
| 102 | { | ||
| 103 | case VT_EMPTY: return; | ||
| 104 | case VT_BSTR: dest[0] = '?'; dest[1] = 0; return; | ||
| 105 | case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return; | ||
| 106 | case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; | ||
| 107 | case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; | ||
| 108 | case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; | ||
| 109 | case VT_FILETIME: ConvertUtcFileTimeToString(prop.filetime, dest); return; | ||
| 110 | // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; | ||
| 111 | case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; | ||
| 112 | case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; | ||
| 113 | case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return; | ||
| 114 | case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? '+' : '-'; dest[1] = 0; return; | ||
| 115 | default: dest[0] = '?'; dest[1] = ':'; ConvertUInt64ToString(prop.vt, dest + 2); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw() | ||
| 120 | { | ||
| 121 | *dest = 0; | ||
| 122 | switch (prop.vt) | ||
| 123 | { | ||
| 124 | case VT_EMPTY: return; | ||
| 125 | case VT_BSTR: dest[0] = '?'; dest[1] = 0; return; | ||
| 126 | case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return; | ||
| 127 | case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; | ||
| 128 | case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; | ||
| 129 | case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; | ||
| 130 | case VT_FILETIME: ConvertUtcFileTimeToString(prop.filetime, dest); return; | ||
| 131 | // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; | ||
| 132 | case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; | ||
| 133 | case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; | ||
| 134 | case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return; | ||
| 135 | case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? (wchar_t)'+' : (wchar_t)'-'; dest[1] = 0; return; | ||
| 136 | default: dest[0] = '?'; dest[1] = ':'; ConvertUInt32ToString(prop.vt, dest + 2); | ||
| 137 | } | ||
| 138 | } | ||
diff --git a/CPP/Windows/PropVariantConv.h b/CPP/Windows/PropVariantConv.h new file mode 100644 index 0000000..390e0b8 --- /dev/null +++ b/CPP/Windows/PropVariantConv.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // Windows/PropVariantConv.h | ||
| 2 | |||
| 3 | #ifndef __PROP_VARIANT_CONV_H | ||
| 4 | #define __PROP_VARIANT_CONV_H | ||
| 5 | |||
| 6 | #include "../Common/MyTypes.h" | ||
| 7 | |||
| 8 | // provide at least 32 bytes for buffer including zero-end | ||
| 9 | |||
| 10 | #define kTimestampPrintLevel_DAY -3 | ||
| 11 | // #define kTimestampPrintLevel_HOUR -2 | ||
| 12 | #define kTimestampPrintLevel_MIN -1 | ||
| 13 | #define kTimestampPrintLevel_SEC 0 | ||
| 14 | #define kTimestampPrintLevel_NTFS 7 | ||
| 15 | |||
| 16 | bool ConvertUtcFileTimeToString(const FILETIME &ft, char *s, int level = kTimestampPrintLevel_SEC) throw(); | ||
| 17 | bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw(); | ||
| 18 | |||
| 19 | // provide at least 32 bytes for buffer including zero-end | ||
| 20 | // don't send VT_BSTR to these functions | ||
| 21 | void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw(); | ||
| 22 | void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw(); | ||
| 23 | |||
| 24 | inline bool ConvertPropVariantToUInt64(const PROPVARIANT &prop, UInt64 &value) | ||
| 25 | { | ||
| 26 | switch (prop.vt) | ||
| 27 | { | ||
| 28 | case VT_UI8: value = (UInt64)prop.uhVal.QuadPart; return true; | ||
| 29 | case VT_UI4: value = prop.ulVal; return true; | ||
| 30 | case VT_UI2: value = prop.uiVal; return true; | ||
| 31 | case VT_UI1: value = prop.bVal; return true; | ||
| 32 | case VT_EMPTY: return false; | ||
| 33 | default: throw 151199; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | #endif | ||
diff --git a/CPP/Windows/PropVariantUtils.cpp b/CPP/Windows/PropVariantUtils.cpp new file mode 100644 index 0000000..6daee83 --- /dev/null +++ b/CPP/Windows/PropVariantUtils.cpp | |||
| @@ -0,0 +1,161 @@ | |||
| 1 | // PropVariantUtils.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../Common/IntToString.h" | ||
| 6 | |||
| 7 | #include "PropVariantUtils.h" | ||
| 8 | |||
| 9 | using namespace NWindows; | ||
| 10 | |||
| 11 | static void AddHex(AString &s, UInt32 v) | ||
| 12 | { | ||
| 13 | char sz[16]; | ||
| 14 | sz[0] = '0'; | ||
| 15 | sz[1] = 'x'; | ||
| 16 | ConvertUInt32ToHex(v, sz + 2); | ||
| 17 | s += sz; | ||
| 18 | } | ||
| 19 | |||
| 20 | |||
| 21 | AString TypePairToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 value) | ||
| 22 | { | ||
| 23 | char sz[16]; | ||
| 24 | const char *p = NULL; | ||
| 25 | for (unsigned i = 0; i < num; i++) | ||
| 26 | { | ||
| 27 | const CUInt32PCharPair &pair = pairs[i]; | ||
| 28 | if (pair.Value == value) | ||
| 29 | p = pair.Name; | ||
| 30 | } | ||
| 31 | if (!p) | ||
| 32 | { | ||
| 33 | ConvertUInt32ToString(value, sz); | ||
| 34 | p = sz; | ||
| 35 | } | ||
| 36 | return (AString)p; | ||
| 37 | } | ||
| 38 | |||
| 39 | void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NCOM::CPropVariant &prop) | ||
| 40 | { | ||
| 41 | prop = TypePairToString(pairs, num, value); | ||
| 42 | } | ||
| 43 | |||
| 44 | |||
| 45 | AString TypeToString(const char * const table[], unsigned num, UInt32 value) | ||
| 46 | { | ||
| 47 | char sz[16]; | ||
| 48 | const char *p = NULL; | ||
| 49 | if (value < num) | ||
| 50 | p = table[value]; | ||
| 51 | if (!p) | ||
| 52 | { | ||
| 53 | ConvertUInt32ToString(value, sz); | ||
| 54 | p = sz; | ||
| 55 | } | ||
| 56 | return (AString)p; | ||
| 57 | } | ||
| 58 | |||
| 59 | void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop) | ||
| 60 | { | ||
| 61 | char sz[16]; | ||
| 62 | const char *p = NULL; | ||
| 63 | if (value < num) | ||
| 64 | p = table[value]; | ||
| 65 | if (!p) | ||
| 66 | { | ||
| 67 | ConvertUInt32ToString(value, sz); | ||
| 68 | p = sz; | ||
| 69 | } | ||
| 70 | prop = p; | ||
| 71 | } | ||
| 72 | |||
| 73 | |||
| 74 | AString FlagsToString(const char * const *names, unsigned num, UInt32 flags) | ||
| 75 | { | ||
| 76 | AString s; | ||
| 77 | for (unsigned i = 0; i < num; i++) | ||
| 78 | { | ||
| 79 | UInt32 flag = (UInt32)1 << i; | ||
| 80 | if ((flags & flag) != 0) | ||
| 81 | { | ||
| 82 | const char *name = names[i]; | ||
| 83 | if (name && name[0] != 0) | ||
| 84 | { | ||
| 85 | s.Add_OptSpaced(name); | ||
| 86 | flags &= ~flag; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | if (flags != 0) | ||
| 91 | { | ||
| 92 | s.Add_Space_if_NotEmpty(); | ||
| 93 | AddHex(s, flags); | ||
| 94 | } | ||
| 95 | return s; | ||
| 96 | } | ||
| 97 | |||
| 98 | AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags) | ||
| 99 | { | ||
| 100 | AString s; | ||
| 101 | for (unsigned i = 0; i < num; i++) | ||
| 102 | { | ||
| 103 | const CUInt32PCharPair &p = pairs[i]; | ||
| 104 | UInt32 flag = (UInt32)1 << (unsigned)p.Value; | ||
| 105 | if ((flags & flag) != 0) | ||
| 106 | { | ||
| 107 | if (p.Name[0] != 0) | ||
| 108 | s.Add_OptSpaced(p.Name); | ||
| 109 | } | ||
| 110 | flags &= ~flag; | ||
| 111 | } | ||
| 112 | if (flags != 0) | ||
| 113 | { | ||
| 114 | s.Add_Space_if_NotEmpty(); | ||
| 115 | AddHex(s, flags); | ||
| 116 | } | ||
| 117 | return s; | ||
| 118 | } | ||
| 119 | |||
| 120 | void FlagsToProp(const char * const *names, unsigned num, UInt32 flags, NCOM::CPropVariant &prop) | ||
| 121 | { | ||
| 122 | prop = FlagsToString(names, num, flags); | ||
| 123 | } | ||
| 124 | |||
| 125 | void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NCOM::CPropVariant &prop) | ||
| 126 | { | ||
| 127 | prop = FlagsToString(pairs, num, flags); | ||
| 128 | } | ||
| 129 | |||
| 130 | |||
| 131 | static AString Flags64ToString(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags) | ||
| 132 | { | ||
| 133 | AString s; | ||
| 134 | for (unsigned i = 0; i < num; i++) | ||
| 135 | { | ||
| 136 | const CUInt32PCharPair &p = pairs[i]; | ||
| 137 | UInt64 flag = (UInt64)1 << (unsigned)p.Value; | ||
| 138 | if ((flags & flag) != 0) | ||
| 139 | { | ||
| 140 | if (p.Name[0] != 0) | ||
| 141 | s.Add_OptSpaced(p.Name); | ||
| 142 | } | ||
| 143 | flags &= ~flag; | ||
| 144 | } | ||
| 145 | if (flags != 0) | ||
| 146 | { | ||
| 147 | { | ||
| 148 | char sz[32]; | ||
| 149 | sz[0] = '0'; | ||
| 150 | sz[1] = 'x'; | ||
| 151 | ConvertUInt64ToHex(flags, sz + 2); | ||
| 152 | s.Add_OptSpaced(sz); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | return s; | ||
| 156 | } | ||
| 157 | |||
| 158 | void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NCOM::CPropVariant &prop) | ||
| 159 | { | ||
| 160 | prop = Flags64ToString(pairs, num, flags); | ||
| 161 | } | ||
diff --git a/CPP/Windows/PropVariantUtils.h b/CPP/Windows/PropVariantUtils.h new file mode 100644 index 0000000..3dd8295 --- /dev/null +++ b/CPP/Windows/PropVariantUtils.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // Windows/PropVariantUtils.h | ||
| 2 | |||
| 3 | #ifndef __PROP_VARIANT_UTILS_H | ||
| 4 | #define __PROP_VARIANT_UTILS_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | #include "PropVariant.h" | ||
| 9 | |||
| 10 | struct CUInt32PCharPair | ||
| 11 | { | ||
| 12 | UInt32 Value; | ||
| 13 | const char *Name; | ||
| 14 | }; | ||
| 15 | |||
| 16 | AString TypePairToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 value); | ||
| 17 | void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop); | ||
| 18 | |||
| 19 | AString FlagsToString(const char * const *names, unsigned num, UInt32 flags); | ||
| 20 | AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags); | ||
| 21 | void FlagsToProp(const char * const *names, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop); | ||
| 22 | void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop); | ||
| 23 | |||
| 24 | AString TypeToString(const char * const table[], unsigned num, UInt32 value); | ||
| 25 | void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop); | ||
| 26 | |||
| 27 | #define PAIR_TO_PROP(pairs, value, prop) PairToProp(pairs, ARRAY_SIZE(pairs), value, prop) | ||
| 28 | #define FLAGS_TO_PROP(pairs, value, prop) FlagsToProp(pairs, ARRAY_SIZE(pairs), value, prop) | ||
| 29 | #define TYPE_TO_PROP(table, value, prop) TypeToProp(table, ARRAY_SIZE(table), value, prop) | ||
| 30 | |||
| 31 | void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NWindows::NCOM::CPropVariant &prop); | ||
| 32 | #define FLAGS64_TO_PROP(pairs, value, prop) Flags64ToProp(pairs, ARRAY_SIZE(pairs), value, prop) | ||
| 33 | |||
| 34 | #endif | ||
diff --git a/CPP/Windows/Registry.cpp b/CPP/Windows/Registry.cpp new file mode 100644 index 0000000..b20157d --- /dev/null +++ b/CPP/Windows/Registry.cpp | |||
| @@ -0,0 +1,406 @@ | |||
| 1 | // Windows/Registry.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include <wchar.h> | ||
| 6 | // #include <stdio.h> | ||
| 7 | |||
| 8 | #ifndef _UNICODE | ||
| 9 | #include "../Common/StringConvert.h" | ||
| 10 | #endif | ||
| 11 | #include "Registry.h" | ||
| 12 | |||
| 13 | #ifndef _UNICODE | ||
| 14 | extern bool g_IsNT; | ||
| 15 | #endif | ||
| 16 | |||
| 17 | namespace NWindows { | ||
| 18 | namespace NRegistry { | ||
| 19 | |||
| 20 | #define MYASSERT(expr) // _ASSERTE(expr) | ||
| 21 | #define MY_ASSUME(expr) | ||
| 22 | |||
| 23 | /* | ||
| 24 | static void Error() | ||
| 25 | { | ||
| 26 | #ifdef _CONSOLE | ||
| 27 | printf("\nregistry error\n"); | ||
| 28 | #else | ||
| 29 | MessageBoxW(0, L"registry error", L"", 0); | ||
| 30 | // exit(1); | ||
| 31 | #endif | ||
| 32 | } | ||
| 33 | |||
| 34 | #define MY_ASSUME(expr) { if (!(expr)) Error(); } | ||
| 35 | */ | ||
| 36 | |||
| 37 | LONG CKey::Create(HKEY parentKey, LPCTSTR keyName, | ||
| 38 | LPTSTR keyClass, DWORD options, REGSAM accessMask, | ||
| 39 | LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition) throw() | ||
| 40 | { | ||
| 41 | MY_ASSUME(parentKey != NULL); | ||
| 42 | DWORD dispositionReal; | ||
| 43 | HKEY key = NULL; | ||
| 44 | LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass, | ||
| 45 | options, accessMask, securityAttributes, &key, &dispositionReal); | ||
| 46 | if (disposition != NULL) | ||
| 47 | *disposition = dispositionReal; | ||
| 48 | if (res == ERROR_SUCCESS) | ||
| 49 | { | ||
| 50 | res = Close(); | ||
| 51 | _object = key; | ||
| 52 | } | ||
| 53 | return res; | ||
| 54 | } | ||
| 55 | |||
| 56 | LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask) throw() | ||
| 57 | { | ||
| 58 | MY_ASSUME(parentKey != NULL); | ||
| 59 | HKEY key = NULL; | ||
| 60 | LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key); | ||
| 61 | if (res == ERROR_SUCCESS) | ||
| 62 | { | ||
| 63 | res = Close(); | ||
| 64 | MYASSERT(res == ERROR_SUCCESS); | ||
| 65 | _object = key; | ||
| 66 | } | ||
| 67 | return res; | ||
| 68 | } | ||
| 69 | |||
| 70 | LONG CKey::Close() throw() | ||
| 71 | { | ||
| 72 | LONG res = ERROR_SUCCESS; | ||
| 73 | if (_object != NULL) | ||
| 74 | { | ||
| 75 | res = RegCloseKey(_object); | ||
| 76 | _object = NULL; | ||
| 77 | } | ||
| 78 | return res; | ||
| 79 | } | ||
| 80 | |||
| 81 | // win95, win98: deletes sunkey and all its subkeys | ||
| 82 | // winNT to be deleted must not have subkeys | ||
| 83 | LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw() | ||
| 84 | { | ||
| 85 | MY_ASSUME(_object != NULL); | ||
| 86 | return RegDeleteKey(_object, subKeyName); | ||
| 87 | } | ||
| 88 | |||
| 89 | LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw() | ||
| 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 | { | ||
| 101 | res = key.RecurseDeleteKey(buffer); | ||
| 102 | if (res != ERROR_SUCCESS) | ||
| 103 | return res; | ||
| 104 | size = kBufSize; | ||
| 105 | } | ||
| 106 | key.Close(); | ||
| 107 | return DeleteSubKey(subKeyName); | ||
| 108 | } | ||
| 109 | |||
| 110 | |||
| 111 | ///////////////////////// | ||
| 112 | // Value Functions | ||
| 113 | |||
| 114 | static inline UInt32 BoolToUINT32(bool value) { return (value ? 1: 0); } | ||
| 115 | static inline bool UINT32ToBool(UInt32 value) { return (value != 0); } | ||
| 116 | |||
| 117 | |||
| 118 | LONG CKey::DeleteValue(LPCTSTR name) throw() | ||
| 119 | { | ||
| 120 | MY_ASSUME(_object != NULL); | ||
| 121 | return ::RegDeleteValue(_object, name); | ||
| 122 | } | ||
| 123 | |||
| 124 | #ifndef _UNICODE | ||
| 125 | LONG CKey::DeleteValue(LPCWSTR name) | ||
| 126 | { | ||
| 127 | MY_ASSUME(_object != NULL); | ||
| 128 | if (g_IsNT) | ||
| 129 | return ::RegDeleteValueW(_object, name); | ||
| 130 | return DeleteValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name)); | ||
| 131 | } | ||
| 132 | #endif | ||
| 133 | |||
| 134 | LONG CKey::SetValue(LPCTSTR name, UInt32 value) throw() | ||
| 135 | { | ||
| 136 | MY_ASSUME(_object != NULL); | ||
| 137 | return RegSetValueEx(_object, name, 0, REG_DWORD, | ||
| 138 | (const BYTE *)&value, sizeof(UInt32)); | ||
| 139 | } | ||
| 140 | |||
| 141 | LONG CKey::SetValue(LPCTSTR name, bool value) throw() | ||
| 142 | { | ||
| 143 | return SetValue(name, BoolToUINT32(value)); | ||
| 144 | } | ||
| 145 | |||
| 146 | LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw() | ||
| 147 | { | ||
| 148 | MYASSERT(value != NULL); | ||
| 149 | MY_ASSUME(_object != NULL); | ||
| 150 | return RegSetValueEx(_object, name, 0, REG_SZ, | ||
| 151 | (const BYTE *)value, ((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)); | ||
| 152 | } | ||
| 153 | |||
| 154 | /* | ||
| 155 | LONG CKey::SetValue(LPCTSTR name, const CSysString &value) | ||
| 156 | { | ||
| 157 | MYASSERT(value != NULL); | ||
| 158 | MY_ASSUME(_object != NULL); | ||
| 159 | return RegSetValueEx(_object, name, NULL, REG_SZ, | ||
| 160 | (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR)); | ||
| 161 | } | ||
| 162 | */ | ||
| 163 | |||
| 164 | #ifndef _UNICODE | ||
| 165 | |||
| 166 | LONG CKey::SetValue(LPCWSTR name, LPCWSTR value) | ||
| 167 | { | ||
| 168 | MYASSERT(value != NULL); | ||
| 169 | MY_ASSUME(_object != NULL); | ||
| 170 | if (g_IsNT) | ||
| 171 | return RegSetValueExW(_object, name, 0, REG_SZ, | ||
| 172 | (const BYTE * )value, (DWORD)((wcslen(value) + 1) * sizeof(wchar_t))); | ||
| 173 | return SetValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), | ||
| 174 | value == 0 ? 0 : (LPCSTR)GetSystemString(value)); | ||
| 175 | } | ||
| 176 | |||
| 177 | #endif | ||
| 178 | |||
| 179 | |||
| 180 | LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size) throw() | ||
| 181 | { | ||
| 182 | MYASSERT(value != NULL); | ||
| 183 | MY_ASSUME(_object != NULL); | ||
| 184 | return RegSetValueEx(_object, name, 0, REG_BINARY, | ||
| 185 | (const BYTE *)value, size); | ||
| 186 | } | ||
| 187 | |||
| 188 | LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) | ||
| 189 | { | ||
| 190 | MYASSERT(value != NULL); | ||
| 191 | CKey key; | ||
| 192 | LONG res = key.Create(parentKey, keyName); | ||
| 193 | if (res == ERROR_SUCCESS) | ||
| 194 | res = key.SetValue(valueName, value); | ||
| 195 | return res; | ||
| 196 | } | ||
| 197 | |||
| 198 | LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw() | ||
| 199 | { | ||
| 200 | MYASSERT(value != NULL); | ||
| 201 | CKey key; | ||
| 202 | LONG res = key.Create(_object, keyName); | ||
| 203 | if (res == ERROR_SUCCESS) | ||
| 204 | res = key.SetValue(valueName, value); | ||
| 205 | return res; | ||
| 206 | } | ||
| 207 | |||
| 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 | |||
| 219 | LONG CKey::QueryValue(LPCTSTR name, bool &value) throw() | ||
| 220 | { | ||
| 221 | UInt32 uintValue = BoolToUINT32(value); | ||
| 222 | LONG res = QueryValue(name, uintValue); | ||
| 223 | value = UINT32ToBool(uintValue); | ||
| 224 | return res; | ||
| 225 | } | ||
| 226 | |||
| 227 | LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value) throw() | ||
| 228 | { | ||
| 229 | UInt32 newVal; | ||
| 230 | LONG res = QueryValue(name, newVal); | ||
| 231 | if (res == ERROR_SUCCESS) | ||
| 232 | value = newVal; | ||
| 233 | return res; | ||
| 234 | } | ||
| 235 | |||
| 236 | LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw() | ||
| 237 | { | ||
| 238 | bool newVal = false; | ||
| 239 | LONG res = QueryValue(name, newVal); | ||
| 240 | if (res == ERROR_SUCCESS) | ||
| 241 | value = newVal; | ||
| 242 | return res; | ||
| 243 | } | ||
| 244 | |||
| 245 | LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count) throw() | ||
| 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 | |||
| 253 | LONG CKey::QueryValue(LPCTSTR name, CSysString &value) | ||
| 254 | { | ||
| 255 | value.Empty(); | ||
| 256 | DWORD type = 0; | ||
| 257 | UInt32 curSize = 0; | ||
| 258 | LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&curSize); | ||
| 259 | if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) | ||
| 260 | return res; | ||
| 261 | UInt32 curSize2 = curSize; | ||
| 262 | res = QueryValue(name, value.GetBuf(curSize), curSize2); | ||
| 263 | if (curSize > curSize2) | ||
| 264 | curSize = curSize2; | ||
| 265 | value.ReleaseBuf_CalcLen(curSize / sizeof(TCHAR)); | ||
| 266 | return res; | ||
| 267 | } | ||
| 268 | |||
| 269 | |||
| 270 | #ifndef _UNICODE | ||
| 271 | |||
| 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) | ||
| 281 | { | ||
| 282 | value.Empty(); | ||
| 283 | DWORD type = 0; | ||
| 284 | UInt32 curSize = 0; | ||
| 285 | |||
| 286 | LONG res; | ||
| 287 | |||
| 288 | if (g_IsNT) | ||
| 289 | { | ||
| 290 | res = RegQueryValueExW(_object, name, NULL, &type, NULL, (DWORD *)&curSize); | ||
| 291 | if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) | ||
| 292 | return res; | ||
| 293 | UInt32 curSize2 = curSize; | ||
| 294 | res = QueryValue(name, value.GetBuf(curSize), curSize2); | ||
| 295 | if (curSize > curSize2) | ||
| 296 | curSize = curSize2; | ||
| 297 | value.ReleaseBuf_CalcLen(curSize / sizeof(wchar_t)); | ||
| 298 | } | ||
| 299 | else | ||
| 300 | { | ||
| 301 | AString vTemp; | ||
| 302 | res = QueryValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), vTemp); | ||
| 303 | value = GetUnicodeString(vTemp); | ||
| 304 | } | ||
| 305 | |||
| 306 | return res; | ||
| 307 | } | ||
| 308 | |||
| 309 | #endif | ||
| 310 | |||
| 311 | |||
| 312 | LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count) throw() | ||
| 313 | { | ||
| 314 | DWORD type = 0; | ||
| 315 | LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); | ||
| 316 | MYASSERT((res != ERROR_SUCCESS) || (type == REG_BINARY)); | ||
| 317 | return res; | ||
| 318 | } | ||
| 319 | |||
| 320 | |||
| 321 | LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize) | ||
| 322 | { | ||
| 323 | DWORD type = 0; | ||
| 324 | dataSize = 0; | ||
| 325 | LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&dataSize); | ||
| 326 | if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) | ||
| 327 | return res; | ||
| 328 | value.Alloc(dataSize); | ||
| 329 | return QueryValue(name, (BYTE *)value, dataSize); | ||
| 330 | } | ||
| 331 | |||
| 332 | LONG CKey::EnumKeys(CSysStringVector &keyNames) | ||
| 333 | { | ||
| 334 | keyNames.Clear(); | ||
| 335 | CSysString keyName; | ||
| 336 | for (DWORD index = 0; ; index++) | ||
| 337 | { | ||
| 338 | const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL | ||
| 339 | FILETIME lastWriteTime; | ||
| 340 | UInt32 nameSize = kBufSize; | ||
| 341 | LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuf(kBufSize), | ||
| 342 | (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime); | ||
| 343 | keyName.ReleaseBuf_CalcLen(kBufSize); | ||
| 344 | if (result == ERROR_NO_MORE_ITEMS) | ||
| 345 | break; | ||
| 346 | if (result != ERROR_SUCCESS) | ||
| 347 | return result; | ||
| 348 | keyNames.Add(keyName); | ||
| 349 | } | ||
| 350 | return ERROR_SUCCESS; | ||
| 351 | } | ||
| 352 | |||
| 353 | LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings) | ||
| 354 | { | ||
| 355 | size_t numChars = 0; | ||
| 356 | |||
| 357 | unsigned i; | ||
| 358 | |||
| 359 | for (i = 0; i < strings.Size(); i++) | ||
| 360 | numChars += strings[i].Len() + 1; | ||
| 361 | |||
| 362 | CObjArray<wchar_t> buffer(numChars); | ||
| 363 | size_t pos = 0; | ||
| 364 | |||
| 365 | for (i = 0; i < strings.Size(); i++) | ||
| 366 | { | ||
| 367 | const UString &s = strings[i]; | ||
| 368 | size_t size = s.Len() + 1; | ||
| 369 | wmemcpy(buffer + pos, s, size); | ||
| 370 | pos += size; | ||
| 371 | } | ||
| 372 | return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t)); | ||
| 373 | } | ||
| 374 | |||
| 375 | LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings) | ||
| 376 | { | ||
| 377 | strings.Clear(); | ||
| 378 | CByteBuffer buffer; | ||
| 379 | UInt32 dataSize = 0; | ||
| 380 | LONG res = QueryValue(valueName, buffer, dataSize); | ||
| 381 | if (res != ERROR_SUCCESS) | ||
| 382 | return res; | ||
| 383 | if (dataSize > buffer.Size()) | ||
| 384 | return E_FAIL; | ||
| 385 | if (dataSize % sizeof(wchar_t) != 0) | ||
| 386 | return E_FAIL; | ||
| 387 | |||
| 388 | const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer; | ||
| 389 | size_t numChars = dataSize / sizeof(wchar_t); | ||
| 390 | size_t prev = 0; | ||
| 391 | UString s; | ||
| 392 | |||
| 393 | for (size_t i = 0; i < numChars; i++) | ||
| 394 | { | ||
| 395 | if (data[i] == 0) | ||
| 396 | { | ||
| 397 | s = data + prev; | ||
| 398 | strings.Add(s); | ||
| 399 | prev = i + 1; | ||
| 400 | } | ||
| 401 | } | ||
| 402 | |||
| 403 | return res; | ||
| 404 | } | ||
| 405 | |||
| 406 | }} | ||
diff --git a/CPP/Windows/Registry.h b/CPP/Windows/Registry.h new file mode 100644 index 0000000..ca79dfe --- /dev/null +++ b/CPP/Windows/Registry.h | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | // Windows/Registry.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_REGISTRY_H | ||
| 4 | #define __WINDOWS_REGISTRY_H | ||
| 5 | |||
| 6 | #include "../Common/MyBuffer.h" | ||
| 7 | #include "../Common/MyString.h" | ||
| 8 | |||
| 9 | namespace NWindows { | ||
| 10 | namespace NRegistry { | ||
| 11 | |||
| 12 | LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value); | ||
| 13 | |||
| 14 | class CKey | ||
| 15 | { | ||
| 16 | HKEY _object; | ||
| 17 | public: | ||
| 18 | CKey(): _object(NULL) {} | ||
| 19 | ~CKey() { Close(); } | ||
| 20 | |||
| 21 | operator HKEY() const { return _object; } | ||
| 22 | void Attach(HKEY key) { _object = key; } | ||
| 23 | HKEY Detach() | ||
| 24 | { | ||
| 25 | HKEY key = _object; | ||
| 26 | _object = NULL; | ||
| 27 | return key; | ||
| 28 | } | ||
| 29 | |||
| 30 | LONG Create(HKEY parentKey, LPCTSTR keyName, | ||
| 31 | LPTSTR keyClass = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE, | ||
| 32 | REGSAM accessMask = KEY_ALL_ACCESS, | ||
| 33 | LPSECURITY_ATTRIBUTES securityAttributes = NULL, | ||
| 34 | LPDWORD disposition = NULL) throw(); | ||
| 35 | LONG Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask = KEY_ALL_ACCESS) throw(); | ||
| 36 | |||
| 37 | LONG Close() throw(); | ||
| 38 | |||
| 39 | LONG DeleteSubKey(LPCTSTR subKeyName) throw(); | ||
| 40 | LONG RecurseDeleteKey(LPCTSTR subKeyName) throw(); | ||
| 41 | |||
| 42 | LONG DeleteValue(LPCTSTR name) throw(); | ||
| 43 | #ifndef _UNICODE | ||
| 44 | LONG DeleteValue(LPCWSTR name); | ||
| 45 | #endif | ||
| 46 | |||
| 47 | LONG SetValue(LPCTSTR valueName, UInt32 value) throw(); | ||
| 48 | LONG SetValue(LPCTSTR valueName, bool value) throw(); | ||
| 49 | LONG SetValue(LPCTSTR valueName, LPCTSTR value) throw(); | ||
| 50 | // LONG SetValue(LPCTSTR valueName, const CSysString &value); | ||
| 51 | #ifndef _UNICODE | ||
| 52 | LONG SetValue(LPCWSTR name, LPCWSTR value); | ||
| 53 | // LONG SetValue(LPCWSTR name, const UString &value); | ||
| 54 | #endif | ||
| 55 | |||
| 56 | LONG SetValue(LPCTSTR name, const void *value, UInt32 size) throw(); | ||
| 57 | |||
| 58 | LONG SetValue_Strings(LPCTSTR valueName, const UStringVector &strings); | ||
| 59 | LONG GetValue_Strings(LPCTSTR valueName, UStringVector &strings); | ||
| 60 | |||
| 61 | LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw(); | ||
| 62 | |||
| 63 | LONG QueryValue(LPCTSTR name, UInt32 &value) throw(); | ||
| 64 | LONG QueryValue(LPCTSTR name, bool &value) throw(); | ||
| 65 | LONG QueryValue(LPCTSTR name, LPTSTR value, UInt32 &dataSize) throw(); | ||
| 66 | LONG QueryValue(LPCTSTR name, CSysString &value); | ||
| 67 | |||
| 68 | LONG GetValue_IfOk(LPCTSTR name, UInt32 &value) throw(); | ||
| 69 | LONG GetValue_IfOk(LPCTSTR name, bool &value) throw(); | ||
| 70 | |||
| 71 | #ifndef _UNICODE | ||
| 72 | LONG QueryValue(LPCWSTR name, LPWSTR value, UInt32 &dataSize); | ||
| 73 | LONG QueryValue(LPCWSTR name, UString &value); | ||
| 74 | #endif | ||
| 75 | |||
| 76 | LONG QueryValue(LPCTSTR name, void *value, UInt32 &dataSize) throw(); | ||
| 77 | LONG QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize); | ||
| 78 | |||
| 79 | LONG EnumKeys(CSysStringVector &keyNames); | ||
| 80 | }; | ||
| 81 | |||
| 82 | }} | ||
| 83 | |||
| 84 | #endif | ||
diff --git a/CPP/Windows/ResourceString.cpp b/CPP/Windows/ResourceString.cpp new file mode 100644 index 0000000..ae8182e --- /dev/null +++ b/CPP/Windows/ResourceString.cpp | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | // Windows/ResourceString.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef _UNICODE | ||
| 6 | #include "../Common/StringConvert.h" | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #include "ResourceString.h" | ||
| 10 | |||
| 11 | extern HINSTANCE g_hInstance; | ||
| 12 | #ifndef _UNICODE | ||
| 13 | extern bool g_IsNT; | ||
| 14 | #endif | ||
| 15 | |||
| 16 | namespace NWindows { | ||
| 17 | |||
| 18 | #ifndef _UNICODE | ||
| 19 | |||
| 20 | static CSysString MyLoadStringA(HINSTANCE hInstance, UINT resourceID) | ||
| 21 | { | ||
| 22 | CSysString s; | ||
| 23 | int size = 128; | ||
| 24 | int len; | ||
| 25 | do | ||
| 26 | { | ||
| 27 | size <<= 1; | ||
| 28 | len = ::LoadString(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size); | ||
| 29 | } | ||
| 30 | while (size - len <= 1); | ||
| 31 | s.ReleaseBuf_CalcLen((unsigned)len); | ||
| 32 | return s; | ||
| 33 | } | ||
| 34 | |||
| 35 | #endif | ||
| 36 | |||
| 37 | static const int kStartSize = 256; | ||
| 38 | |||
| 39 | static void MyLoadString2(HINSTANCE hInstance, UINT resourceID, UString &s) | ||
| 40 | { | ||
| 41 | int size = kStartSize; | ||
| 42 | int len; | ||
| 43 | do | ||
| 44 | { | ||
| 45 | size <<= 1; | ||
| 46 | len = ::LoadStringW(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size); | ||
| 47 | } | ||
| 48 | while (size - len <= 1); | ||
| 49 | s.ReleaseBuf_CalcLen((unsigned)len); | ||
| 50 | } | ||
| 51 | |||
| 52 | // NT4 doesn't support LoadStringW(,,, 0) to get pointer to resource string. So we don't use it. | ||
| 53 | |||
| 54 | UString MyLoadString(UINT resourceID) | ||
| 55 | { | ||
| 56 | #ifndef _UNICODE | ||
| 57 | if (!g_IsNT) | ||
| 58 | return GetUnicodeString(MyLoadStringA(g_hInstance, resourceID)); | ||
| 59 | else | ||
| 60 | #endif | ||
| 61 | { | ||
| 62 | { | ||
| 63 | wchar_t s[kStartSize]; | ||
| 64 | s[0] = 0; | ||
| 65 | int len = ::LoadStringW(g_hInstance, resourceID, s, kStartSize); | ||
| 66 | if (kStartSize - len > 1) | ||
| 67 | return s; | ||
| 68 | } | ||
| 69 | UString dest; | ||
| 70 | MyLoadString2(g_hInstance, resourceID, dest); | ||
| 71 | return dest; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest) | ||
| 76 | { | ||
| 77 | dest.Empty(); | ||
| 78 | #ifndef _UNICODE | ||
| 79 | if (!g_IsNT) | ||
| 80 | MultiByteToUnicodeString2(dest, MyLoadStringA(hInstance, resourceID)); | ||
| 81 | else | ||
| 82 | #endif | ||
| 83 | { | ||
| 84 | { | ||
| 85 | wchar_t s[kStartSize]; | ||
| 86 | s[0] = 0; | ||
| 87 | int len = ::LoadStringW(hInstance, resourceID, s, kStartSize); | ||
| 88 | if (kStartSize - len > 1) | ||
| 89 | { | ||
| 90 | dest = s; | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | MyLoadString2(hInstance, resourceID, dest); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | void MyLoadString(UINT resourceID, UString &dest) | ||
| 99 | { | ||
| 100 | MyLoadString(g_hInstance, resourceID, dest); | ||
| 101 | } | ||
| 102 | |||
| 103 | } | ||
diff --git a/CPP/Windows/ResourceString.h b/CPP/Windows/ResourceString.h new file mode 100644 index 0000000..f0bdabf --- /dev/null +++ b/CPP/Windows/ResourceString.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // Windows/ResourceString.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_RESOURCE_STRING_H | ||
| 4 | #define __WINDOWS_RESOURCE_STRING_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | namespace NWindows { | ||
| 9 | |||
| 10 | UString MyLoadString(UINT resourceID); | ||
| 11 | void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest); | ||
| 12 | void MyLoadString(UINT resourceID, UString &dest); | ||
| 13 | |||
| 14 | } | ||
| 15 | |||
| 16 | #endif | ||
diff --git a/CPP/Windows/SecurityUtils.cpp b/CPP/Windows/SecurityUtils.cpp new file mode 100644 index 0000000..640c90d --- /dev/null +++ b/CPP/Windows/SecurityUtils.cpp | |||
| @@ -0,0 +1,181 @@ | |||
| 1 | // Windows/SecurityUtils.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../Common/MyString.h" | ||
| 6 | |||
| 7 | #include "SecurityUtils.h" | ||
| 8 | |||
| 9 | namespace NWindows { | ||
| 10 | namespace NSecurity { | ||
| 11 | |||
| 12 | /* | ||
| 13 | bool MyLookupAccountSid(LPCTSTR systemName, PSID sid, | ||
| 14 | CSysString &accountName, CSysString &domainName, PSID_NAME_USE sidNameUse) | ||
| 15 | { | ||
| 16 | DWORD accountNameSize = 0, domainNameSize = 0; | ||
| 17 | |||
| 18 | if (!::LookupAccountSid(systemName, sid, | ||
| 19 | accountName.GetBuf(0), &accountNameSize, | ||
| 20 | domainName.GetBuf(0), &domainNameSize, sidNameUse)) | ||
| 21 | { | ||
| 22 | if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) | ||
| 23 | return false; | ||
| 24 | } | ||
| 25 | DWORD accountNameSize2 = accountNameSize, domainNameSize2 = domainNameSize; | ||
| 26 | bool result = BOOLToBool(::LookupAccountSid(systemName, sid, | ||
| 27 | accountName.GetBuf(accountNameSize), &accountNameSize2, | ||
| 28 | domainName.GetBuf(domainNameSize), &domainNameSize2, sidNameUse)); | ||
| 29 | accountName.ReleaseBuf_CalcLen(accountNameSize); | ||
| 30 | domainName.ReleaseBuf_CalcLen(domainNameSize); | ||
| 31 | return result; | ||
| 32 | } | ||
| 33 | */ | ||
| 34 | |||
| 35 | static void SetLsaString(LPWSTR src, PLSA_UNICODE_STRING dest) | ||
| 36 | { | ||
| 37 | size_t len = (size_t)wcslen(src); | ||
| 38 | dest->Length = (USHORT)(len * sizeof(WCHAR)); | ||
| 39 | dest->MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR)); | ||
| 40 | dest->Buffer = src; | ||
| 41 | } | ||
| 42 | |||
| 43 | /* | ||
| 44 | static void MyLookupSids(CPolicy &policy, PSID ps) | ||
| 45 | { | ||
| 46 | LSA_REFERENCED_DOMAIN_LIST *referencedDomains = NULL; | ||
| 47 | LSA_TRANSLATED_NAME *names = NULL; | ||
| 48 | NTSTATUS nts = policy.LookupSids(1, &ps, &referencedDomains, &names); | ||
| 49 | int res = LsaNtStatusToWinError(nts); | ||
| 50 | LsaFreeMemory(referencedDomains); | ||
| 51 | LsaFreeMemory(names); | ||
| 52 | } | ||
| 53 | */ | ||
| 54 | |||
| 55 | #ifndef _UNICODE | ||
| 56 | typedef BOOL (WINAPI * LookupAccountNameWP)( | ||
| 57 | LPCWSTR lpSystemName, | ||
| 58 | LPCWSTR lpAccountName, | ||
| 59 | PSID Sid, | ||
| 60 | LPDWORD cbSid, | ||
| 61 | LPWSTR ReferencedDomainName, | ||
| 62 | LPDWORD cchReferencedDomainName, | ||
| 63 | PSID_NAME_USE peUse | ||
| 64 | ); | ||
| 65 | #endif | ||
| 66 | |||
| 67 | static PSID GetSid(LPWSTR accountName) | ||
| 68 | { | ||
| 69 | #ifndef _UNICODE | ||
| 70 | HMODULE hModule = GetModuleHandle(TEXT("Advapi32.dll")); | ||
| 71 | if (hModule == NULL) | ||
| 72 | return NULL; | ||
| 73 | LookupAccountNameWP lookupAccountNameW = (LookupAccountNameWP)GetProcAddress(hModule, "LookupAccountNameW"); | ||
| 74 | if (lookupAccountNameW == NULL) | ||
| 75 | return NULL; | ||
| 76 | #endif | ||
| 77 | |||
| 78 | DWORD sidLen = 0, domainLen = 0; | ||
| 79 | SID_NAME_USE sidNameUse; | ||
| 80 | if (! | ||
| 81 | #ifdef _UNICODE | ||
| 82 | ::LookupAccountNameW | ||
| 83 | #else | ||
| 84 | lookupAccountNameW | ||
| 85 | #endif | ||
| 86 | (NULL, accountName, NULL, &sidLen, NULL, &domainLen, &sidNameUse)) | ||
| 87 | { | ||
| 88 | if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) | ||
| 89 | { | ||
| 90 | PSID pSid = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sidLen); | ||
| 91 | LPWSTR domainName = (LPWSTR)::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (domainLen + 1) * sizeof(WCHAR)); | ||
| 92 | BOOL res = | ||
| 93 | #ifdef _UNICODE | ||
| 94 | ::LookupAccountNameW | ||
| 95 | #else | ||
| 96 | lookupAccountNameW | ||
| 97 | #endif | ||
| 98 | (NULL, accountName, pSid, &sidLen, domainName, &domainLen, &sidNameUse); | ||
| 99 | ::HeapFree(GetProcessHeap(), 0, domainName); | ||
| 100 | if (res) | ||
| 101 | return pSid; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | return NULL; | ||
| 105 | } | ||
| 106 | |||
| 107 | #define MY__SE_LOCK_MEMORY_NAME L"SeLockMemoryPrivilege" | ||
| 108 | |||
| 109 | bool AddLockMemoryPrivilege() | ||
| 110 | { | ||
| 111 | CPolicy policy; | ||
| 112 | LSA_OBJECT_ATTRIBUTES attr; | ||
| 113 | attr.Length = sizeof(attr); | ||
| 114 | attr.RootDirectory = NULL; | ||
| 115 | attr.ObjectName = NULL; | ||
| 116 | attr.Attributes = 0; | ||
| 117 | attr.SecurityDescriptor = NULL; | ||
| 118 | attr.SecurityQualityOfService = NULL; | ||
| 119 | if (policy.Open(NULL, &attr, | ||
| 120 | // GENERIC_WRITE) | ||
| 121 | POLICY_ALL_ACCESS) | ||
| 122 | // STANDARD_RIGHTS_REQUIRED, | ||
| 123 | // GENERIC_READ | GENERIC_EXECUTE | POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES) | ||
| 124 | != 0) | ||
| 125 | return false; | ||
| 126 | LSA_UNICODE_STRING userRights; | ||
| 127 | wchar_t s[128] = MY__SE_LOCK_MEMORY_NAME; | ||
| 128 | SetLsaString(s, &userRights); | ||
| 129 | WCHAR userName[256 + 2]; | ||
| 130 | DWORD size = 256; | ||
| 131 | if (!GetUserNameW(userName, &size)) | ||
| 132 | return false; | ||
| 133 | PSID psid = GetSid(userName); | ||
| 134 | if (psid == NULL) | ||
| 135 | return false; | ||
| 136 | bool res = false; | ||
| 137 | |||
| 138 | /* | ||
| 139 | PLSA_UNICODE_STRING userRightsArray; | ||
| 140 | ULONG countOfRights; | ||
| 141 | NTSTATUS status = policy.EnumerateAccountRights(psid, &userRightsArray, &countOfRights); | ||
| 142 | if (status != 0) | ||
| 143 | return false; | ||
| 144 | bool finded = false; | ||
| 145 | for (ULONG i = 0; i < countOfRights; i++) | ||
| 146 | { | ||
| 147 | LSA_UNICODE_STRING &ur = userRightsArray[i]; | ||
| 148 | if (ur.Length != s.Length() * sizeof(WCHAR)) | ||
| 149 | continue; | ||
| 150 | if (wcsncmp(ur.Buffer, s, s.Length()) != 0) | ||
| 151 | continue; | ||
| 152 | finded = true; | ||
| 153 | res = true; | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | if (!finded) | ||
| 157 | */ | ||
| 158 | { | ||
| 159 | /* | ||
| 160 | LSA_ENUMERATION_INFORMATION *enums; | ||
| 161 | ULONG countReturned; | ||
| 162 | NTSTATUS status = policy.EnumerateAccountsWithUserRight(&userRights, &enums, &countReturned); | ||
| 163 | if (status == 0) | ||
| 164 | { | ||
| 165 | for (ULONG i = 0; i < countReturned; i++) | ||
| 166 | MyLookupSids(policy, enums[i].Sid); | ||
| 167 | if (enums) | ||
| 168 | ::LsaFreeMemory(enums); | ||
| 169 | res = true; | ||
| 170 | } | ||
| 171 | */ | ||
| 172 | NTSTATUS status = policy.AddAccountRights(psid, &userRights); | ||
| 173 | if (status == 0) | ||
| 174 | res = true; | ||
| 175 | // ULONG res = LsaNtStatusToWinError(status); | ||
| 176 | } | ||
| 177 | HeapFree(GetProcessHeap(), 0, psid); | ||
| 178 | return res; | ||
| 179 | } | ||
| 180 | |||
| 181 | }} | ||
diff --git a/CPP/Windows/SecurityUtils.h b/CPP/Windows/SecurityUtils.h new file mode 100644 index 0000000..8966dfd --- /dev/null +++ b/CPP/Windows/SecurityUtils.h | |||
| @@ -0,0 +1,167 @@ | |||
| 1 | // Windows/SecurityUtils.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_SECURITY_UTILS_H | ||
| 4 | #define __WINDOWS_SECURITY_UTILS_H | ||
| 5 | |||
| 6 | #include <NTSecAPI.h> | ||
| 7 | |||
| 8 | #include "Defs.h" | ||
| 9 | |||
| 10 | namespace NWindows { | ||
| 11 | namespace NSecurity { | ||
| 12 | |||
| 13 | class CAccessToken | ||
| 14 | { | ||
| 15 | HANDLE _handle; | ||
| 16 | public: | ||
| 17 | CAccessToken(): _handle(NULL) {}; | ||
| 18 | ~CAccessToken() { Close(); } | ||
| 19 | bool Close() | ||
| 20 | { | ||
| 21 | if (_handle == NULL) | ||
| 22 | return true; | ||
| 23 | bool res = BOOLToBool(::CloseHandle(_handle)); | ||
| 24 | if (res) | ||
| 25 | _handle = NULL; | ||
| 26 | return res; | ||
| 27 | } | ||
| 28 | |||
| 29 | bool OpenProcessToken(HANDLE processHandle, DWORD desiredAccess) | ||
| 30 | { | ||
| 31 | Close(); | ||
| 32 | return BOOLToBool(::OpenProcessToken(processHandle, desiredAccess, &_handle)); | ||
| 33 | } | ||
| 34 | |||
| 35 | /* | ||
| 36 | bool OpenThreadToken(HANDLE threadHandle, DWORD desiredAccess, bool openAsSelf) | ||
| 37 | { | ||
| 38 | Close(); | ||
| 39 | return BOOLToBool(::OpenTreadToken(threadHandle, desiredAccess, BoolToBOOL(anOpenAsSelf), &_handle)); | ||
| 40 | } | ||
| 41 | */ | ||
| 42 | |||
| 43 | bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState, | ||
| 44 | DWORD bufferLength, PTOKEN_PRIVILEGES previousState, PDWORD returnLength) | ||
| 45 | { return BOOLToBool(::AdjustTokenPrivileges(_handle, BoolToBOOL(disableAllPrivileges), | ||
| 46 | newState, bufferLength, previousState, returnLength)); } | ||
| 47 | |||
| 48 | bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState) | ||
| 49 | { return AdjustPrivileges(disableAllPrivileges, newState, 0, NULL, NULL); } | ||
| 50 | |||
| 51 | bool AdjustPrivileges(PTOKEN_PRIVILEGES newState) | ||
| 52 | { return AdjustPrivileges(false, newState); } | ||
| 53 | |||
| 54 | }; | ||
| 55 | |||
| 56 | #ifndef _UNICODE | ||
| 57 | typedef NTSTATUS (NTAPI *LsaOpenPolicyP)(PLSA_UNICODE_STRING SystemName, | ||
| 58 | PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle); | ||
| 59 | typedef NTSTATUS (NTAPI *LsaCloseP)(LSA_HANDLE ObjectHandle); | ||
| 60 | typedef NTSTATUS (NTAPI *LsaAddAccountRightsP)(LSA_HANDLE PolicyHandle, | ||
| 61 | PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); | ||
| 62 | #define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) | ||
| 63 | #endif | ||
| 64 | |||
| 65 | struct CPolicy | ||
| 66 | { | ||
| 67 | protected: | ||
| 68 | LSA_HANDLE _handle; | ||
| 69 | #ifndef _UNICODE | ||
| 70 | HMODULE hModule; | ||
| 71 | #endif | ||
| 72 | public: | ||
| 73 | operator LSA_HANDLE() const { return _handle; } | ||
| 74 | CPolicy(): _handle(NULL) | ||
| 75 | { | ||
| 76 | #ifndef _UNICODE | ||
| 77 | hModule = GetModuleHandle(TEXT("Advapi32.dll")); | ||
| 78 | #endif | ||
| 79 | }; | ||
| 80 | ~CPolicy() { Close(); } | ||
| 81 | |||
| 82 | NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes, | ||
| 83 | ACCESS_MASK desiredAccess) | ||
| 84 | { | ||
| 85 | #ifndef _UNICODE | ||
| 86 | if (hModule == NULL) | ||
| 87 | return MY_STATUS_NOT_IMPLEMENTED; | ||
| 88 | LsaOpenPolicyP lsaOpenPolicy = (LsaOpenPolicyP)GetProcAddress(hModule, "LsaOpenPolicy"); | ||
| 89 | if (lsaOpenPolicy == NULL) | ||
| 90 | return MY_STATUS_NOT_IMPLEMENTED; | ||
| 91 | #endif | ||
| 92 | |||
| 93 | Close(); | ||
| 94 | return | ||
| 95 | #ifdef _UNICODE | ||
| 96 | ::LsaOpenPolicy | ||
| 97 | #else | ||
| 98 | lsaOpenPolicy | ||
| 99 | #endif | ||
| 100 | (systemName, objectAttributes, desiredAccess, &_handle); | ||
| 101 | } | ||
| 102 | |||
| 103 | NTSTATUS Close() | ||
| 104 | { | ||
| 105 | if (_handle == NULL) | ||
| 106 | return 0; | ||
| 107 | |||
| 108 | #ifndef _UNICODE | ||
| 109 | if (hModule == NULL) | ||
| 110 | return MY_STATUS_NOT_IMPLEMENTED; | ||
| 111 | LsaCloseP lsaClose = (LsaCloseP)GetProcAddress(hModule, "LsaClose"); | ||
| 112 | if (lsaClose == NULL) | ||
| 113 | return MY_STATUS_NOT_IMPLEMENTED; | ||
| 114 | #endif | ||
| 115 | |||
| 116 | NTSTATUS res = | ||
| 117 | #ifdef _UNICODE | ||
| 118 | ::LsaClose | ||
| 119 | #else | ||
| 120 | lsaClose | ||
| 121 | #endif | ||
| 122 | (_handle); | ||
| 123 | _handle = NULL; | ||
| 124 | return res; | ||
| 125 | } | ||
| 126 | |||
| 127 | NTSTATUS EnumerateAccountsWithUserRight(PLSA_UNICODE_STRING userRights, | ||
| 128 | PLSA_ENUMERATION_INFORMATION *enumerationBuffer, PULONG countReturned) | ||
| 129 | { return LsaEnumerateAccountsWithUserRight(_handle, userRights, (void **)enumerationBuffer, countReturned); } | ||
| 130 | |||
| 131 | NTSTATUS EnumerateAccountRights(PSID sid, PLSA_UNICODE_STRING* userRights, PULONG countOfRights) | ||
| 132 | { return ::LsaEnumerateAccountRights(_handle, sid, userRights, countOfRights); } | ||
| 133 | |||
| 134 | NTSTATUS LookupSids(ULONG count, PSID* sids, | ||
| 135 | PLSA_REFERENCED_DOMAIN_LIST* referencedDomains, PLSA_TRANSLATED_NAME* names) | ||
| 136 | { return LsaLookupSids(_handle, count, sids, referencedDomains, names); } | ||
| 137 | |||
| 138 | NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights) | ||
| 139 | { | ||
| 140 | #ifndef _UNICODE | ||
| 141 | if (hModule == NULL) | ||
| 142 | return MY_STATUS_NOT_IMPLEMENTED; | ||
| 143 | LsaAddAccountRightsP lsaAddAccountRights = (LsaAddAccountRightsP)GetProcAddress(hModule, "LsaAddAccountRights"); | ||
| 144 | if (lsaAddAccountRights == NULL) | ||
| 145 | return MY_STATUS_NOT_IMPLEMENTED; | ||
| 146 | #endif | ||
| 147 | |||
| 148 | return | ||
| 149 | #ifdef _UNICODE | ||
| 150 | ::LsaAddAccountRights | ||
| 151 | #else | ||
| 152 | lsaAddAccountRights | ||
| 153 | #endif | ||
| 154 | (_handle, accountSid, userRights, countOfRights); | ||
| 155 | } | ||
| 156 | NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights) | ||
| 157 | { return AddAccountRights(accountSid, userRights, 1); } | ||
| 158 | |||
| 159 | NTSTATUS RemoveAccountRights(PSID accountSid, bool allRights, PLSA_UNICODE_STRING userRights, ULONG countOfRights) | ||
| 160 | { return LsaRemoveAccountRights(_handle, accountSid, (BOOLEAN)(allRights ? TRUE : FALSE), userRights, countOfRights); } | ||
| 161 | }; | ||
| 162 | |||
| 163 | bool AddLockMemoryPrivilege(); | ||
| 164 | |||
| 165 | }} | ||
| 166 | |||
| 167 | #endif | ||
diff --git a/CPP/Windows/Shell.cpp b/CPP/Windows/Shell.cpp new file mode 100644 index 0000000..d0f9032 --- /dev/null +++ b/CPP/Windows/Shell.cpp | |||
| @@ -0,0 +1,358 @@ | |||
| 1 | // Windows/Shell.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | /* | ||
| 6 | #include <stdio.h> | ||
| 7 | #include <string.h> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include "../Common/MyCom.h" | ||
| 11 | #ifndef _UNICODE | ||
| 12 | #include "../Common/StringConvert.h" | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #include "COM.h" | ||
| 16 | #include "Shell.h" | ||
| 17 | |||
| 18 | #ifndef _UNICODE | ||
| 19 | extern bool g_IsNT; | ||
| 20 | #endif | ||
| 21 | |||
| 22 | namespace NWindows { | ||
| 23 | namespace NShell { | ||
| 24 | |||
| 25 | #ifndef UNDER_CE | ||
| 26 | |||
| 27 | // SHGetMalloc is unsupported in Windows Mobile? | ||
| 28 | |||
| 29 | void CItemIDList::Free() | ||
| 30 | { | ||
| 31 | if (m_Object == NULL) | ||
| 32 | return; | ||
| 33 | CMyComPtr<IMalloc> shellMalloc; | ||
| 34 | if (::SHGetMalloc(&shellMalloc) != NOERROR) | ||
| 35 | throw 41099; | ||
| 36 | shellMalloc->Free(m_Object); | ||
| 37 | m_Object = NULL; | ||
| 38 | } | ||
| 39 | |||
| 40 | /* | ||
| 41 | CItemIDList::(LPCITEMIDLIST itemIDList): m_Object(NULL) | ||
| 42 | { *this = itemIDList; } | ||
| 43 | CItemIDList::(const CItemIDList& itemIDList): m_Object(NULL) | ||
| 44 | { *this = itemIDList; } | ||
| 45 | |||
| 46 | CItemIDList& CItemIDList::operator=(LPCITEMIDLIST object) | ||
| 47 | { | ||
| 48 | Free(); | ||
| 49 | if (object != 0) | ||
| 50 | { | ||
| 51 | UINT32 size = GetSize(object); | ||
| 52 | m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size); | ||
| 53 | if (m_Object != NULL) | ||
| 54 | MoveMemory(m_Object, object, size); | ||
| 55 | } | ||
| 56 | return *this; | ||
| 57 | } | ||
| 58 | |||
| 59 | CItemIDList& CItemIDList::operator=(const CItemIDList &object) | ||
| 60 | { | ||
| 61 | Free(); | ||
| 62 | if (object.m_Object != NULL) | ||
| 63 | { | ||
| 64 | UINT32 size = GetSize(object.m_Object); | ||
| 65 | m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size); | ||
| 66 | if (m_Object != NULL) | ||
| 67 | MoveMemory(m_Object, object.m_Object, size); | ||
| 68 | } | ||
| 69 | return *this; | ||
| 70 | } | ||
| 71 | */ | ||
| 72 | |||
| 73 | ///////////////////////////// | ||
| 74 | // CDrop | ||
| 75 | |||
| 76 | void CDrop::Attach(HDROP object) | ||
| 77 | { | ||
| 78 | Free(); | ||
| 79 | m_Object = object; | ||
| 80 | m_Assigned = true; | ||
| 81 | } | ||
| 82 | |||
| 83 | void CDrop::Free() | ||
| 84 | { | ||
| 85 | if (m_MustBeFinished && m_Assigned) | ||
| 86 | Finish(); | ||
| 87 | m_Assigned = false; | ||
| 88 | } | ||
| 89 | |||
| 90 | UINT CDrop::QueryCountOfFiles() | ||
| 91 | { | ||
| 92 | return QueryFile(0xFFFFFFFF, (LPTSTR)NULL, 0); | ||
| 93 | } | ||
| 94 | |||
| 95 | UString CDrop::QueryFileName(UINT fileIndex) | ||
| 96 | { | ||
| 97 | UString fileName; | ||
| 98 | #ifndef _UNICODE | ||
| 99 | if (!g_IsNT) | ||
| 100 | { | ||
| 101 | AString fileNameA; | ||
| 102 | UINT bufferSize = QueryFile(fileIndex, (LPTSTR)NULL, 0); | ||
| 103 | const unsigned len = bufferSize + 2; | ||
| 104 | QueryFile(fileIndex, fileNameA.GetBuf(len), bufferSize + 1); | ||
| 105 | fileNameA.ReleaseBuf_CalcLen(len); | ||
| 106 | fileName = GetUnicodeString(fileNameA); | ||
| 107 | } | ||
| 108 | else | ||
| 109 | #endif | ||
| 110 | { | ||
| 111 | UINT bufferSize = QueryFile(fileIndex, (LPWSTR)NULL, 0); | ||
| 112 | const unsigned len = bufferSize + 2; | ||
| 113 | QueryFile(fileIndex, fileName.GetBuf(len), bufferSize + 1); | ||
| 114 | fileName.ReleaseBuf_CalcLen(len); | ||
| 115 | } | ||
| 116 | return fileName; | ||
| 117 | } | ||
| 118 | |||
| 119 | void CDrop::QueryFileNames(UStringVector &fileNames) | ||
| 120 | { | ||
| 121 | UINT numFiles = QueryCountOfFiles(); | ||
| 122 | /* | ||
| 123 | char s[100]; | ||
| 124 | sprintf(s, "QueryFileNames: %d files", numFiles); | ||
| 125 | OutputDebugStringA(s); | ||
| 126 | */ | ||
| 127 | fileNames.ClearAndReserve(numFiles); | ||
| 128 | for (UINT i = 0; i < numFiles; i++) | ||
| 129 | { | ||
| 130 | const UString s2 = QueryFileName(i); | ||
| 131 | if (!s2.IsEmpty()) | ||
| 132 | fileNames.AddInReserved(s2); | ||
| 133 | /* | ||
| 134 | OutputDebugStringW(L"file ---"); | ||
| 135 | OutputDebugStringW(s2); | ||
| 136 | */ | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | |||
| 141 | bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path) | ||
| 142 | { | ||
| 143 | const unsigned len = MAX_PATH * 2; | ||
| 144 | bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len))); | ||
| 145 | path.ReleaseBuf_CalcLen(len); | ||
| 146 | return result; | ||
| 147 | } | ||
| 148 | |||
| 149 | #endif | ||
| 150 | |||
| 151 | #ifdef UNDER_CE | ||
| 152 | |||
| 153 | bool BrowseForFolder(LPBROWSEINFO, CSysString) | ||
| 154 | { | ||
| 155 | return false; | ||
| 156 | } | ||
| 157 | |||
| 158 | bool BrowseForFolder(HWND, LPCTSTR, UINT, LPCTSTR, CSysString &) | ||
| 159 | { | ||
| 160 | return false; | ||
| 161 | } | ||
| 162 | |||
| 163 | bool BrowseForFolder(HWND /* owner */, LPCTSTR /* title */, | ||
| 164 | LPCTSTR /* initialFolder */, CSysString & /* resultPath */) | ||
| 165 | { | ||
| 166 | /* | ||
| 167 | // SHBrowseForFolder doesn't work before CE 6.0 ? | ||
| 168 | if (GetProcAddress(LoadLibrary(L"ceshell.dll", L"SHBrowseForFolder") == 0) | ||
| 169 | MessageBoxW(0, L"no", L"", 0); | ||
| 170 | else | ||
| 171 | MessageBoxW(0, L"yes", L"", 0); | ||
| 172 | */ | ||
| 173 | /* | ||
| 174 | UString s = "all files"; | ||
| 175 | s += " (*.*)"; | ||
| 176 | return MyGetOpenFileName(owner, title, initialFolder, s, resultPath, true); | ||
| 177 | */ | ||
| 178 | return false; | ||
| 179 | } | ||
| 180 | |||
| 181 | #else | ||
| 182 | |||
| 183 | bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath) | ||
| 184 | { | ||
| 185 | NWindows::NCOM::CComInitializer comInitializer; | ||
| 186 | LPITEMIDLIST itemIDList = ::SHBrowseForFolder(browseInfo); | ||
| 187 | if (itemIDList == NULL) | ||
| 188 | return false; | ||
| 189 | CItemIDList itemIDListHolder; | ||
| 190 | itemIDListHolder.Attach(itemIDList); | ||
| 191 | return GetPathFromIDList(itemIDList, resultPath); | ||
| 192 | } | ||
| 193 | |||
| 194 | |||
| 195 | static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) | ||
| 196 | { | ||
| 197 | #ifndef UNDER_CE | ||
| 198 | switch (uMsg) | ||
| 199 | { | ||
| 200 | case BFFM_INITIALIZED: | ||
| 201 | { | ||
| 202 | SendMessage(hwnd, BFFM_SETSELECTION, TRUE, data); | ||
| 203 | break; | ||
| 204 | } | ||
| 205 | /* | ||
| 206 | case BFFM_SELCHANGED: | ||
| 207 | { | ||
| 208 | TCHAR dir[MAX_PATH]; | ||
| 209 | if (::SHGetPathFromIDList((LPITEMIDLIST) lp , dir)) | ||
| 210 | SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)dir); | ||
| 211 | else | ||
| 212 | SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)TEXT("")); | ||
| 213 | break; | ||
| 214 | } | ||
| 215 | */ | ||
| 216 | default: | ||
| 217 | break; | ||
| 218 | } | ||
| 219 | #endif | ||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | |||
| 224 | static bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags, | ||
| 225 | LPCTSTR initialFolder, CSysString &resultPath) | ||
| 226 | { | ||
| 227 | CSysString displayName; | ||
| 228 | BROWSEINFO browseInfo; | ||
| 229 | browseInfo.hwndOwner = owner; | ||
| 230 | browseInfo.pidlRoot = NULL; | ||
| 231 | |||
| 232 | // there are Unicode/Astring problems in some WinCE SDK ? | ||
| 233 | /* | ||
| 234 | #ifdef UNDER_CE | ||
| 235 | browseInfo.pszDisplayName = (LPSTR)displayName.GetBuf(MAX_PATH); | ||
| 236 | browseInfo.lpszTitle = (LPCSTR)title; | ||
| 237 | #else | ||
| 238 | */ | ||
| 239 | browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH); | ||
| 240 | browseInfo.lpszTitle = title; | ||
| 241 | // #endif | ||
| 242 | browseInfo.ulFlags = ulFlags; | ||
| 243 | browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc : NULL; | ||
| 244 | browseInfo.lParam = (LPARAM)initialFolder; | ||
| 245 | return BrowseForFolder(&browseInfo, resultPath); | ||
| 246 | } | ||
| 247 | |||
| 248 | bool BrowseForFolder(HWND owner, LPCTSTR title, | ||
| 249 | LPCTSTR initialFolder, CSysString &resultPath) | ||
| 250 | { | ||
| 251 | return BrowseForFolder(owner, title, | ||
| 252 | #ifndef UNDER_CE | ||
| 253 | BIF_NEWDIALOGSTYLE | | ||
| 254 | #endif | ||
| 255 | BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT, initialFolder, resultPath); | ||
| 256 | // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0) | ||
| 257 | } | ||
| 258 | |||
| 259 | #ifndef _UNICODE | ||
| 260 | |||
| 261 | typedef BOOL (WINAPI * SHGetPathFromIDListWP)(LPCITEMIDLIST pidl, LPWSTR pszPath); | ||
| 262 | |||
| 263 | bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path) | ||
| 264 | { | ||
| 265 | path.Empty(); | ||
| 266 | SHGetPathFromIDListWP shGetPathFromIDListW = (SHGetPathFromIDListWP) | ||
| 267 | ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetPathFromIDListW"); | ||
| 268 | if (shGetPathFromIDListW == 0) | ||
| 269 | return false; | ||
| 270 | const unsigned len = MAX_PATH * 2; | ||
| 271 | bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len))); | ||
| 272 | path.ReleaseBuf_CalcLen(len); | ||
| 273 | return result; | ||
| 274 | } | ||
| 275 | |||
| 276 | typedef LPITEMIDLIST (WINAPI * SHBrowseForFolderWP)(LPBROWSEINFOW lpbi); | ||
| 277 | |||
| 278 | static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) | ||
| 279 | { | ||
| 280 | NWindows::NCOM::CComInitializer comInitializer; | ||
| 281 | SHBrowseForFolderWP shBrowseForFolderW = (SHBrowseForFolderWP) | ||
| 282 | ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHBrowseForFolderW"); | ||
| 283 | if (shBrowseForFolderW == 0) | ||
| 284 | return false; | ||
| 285 | LPITEMIDLIST itemIDList = shBrowseForFolderW(browseInfo); | ||
| 286 | if (itemIDList == NULL) | ||
| 287 | return false; | ||
| 288 | CItemIDList itemIDListHolder; | ||
| 289 | itemIDListHolder.Attach(itemIDList); | ||
| 290 | return GetPathFromIDList(itemIDList, resultPath); | ||
| 291 | } | ||
| 292 | |||
| 293 | static | ||
| 294 | int CALLBACK BrowseCallbackProc2(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) | ||
| 295 | { | ||
| 296 | switch (uMsg) | ||
| 297 | { | ||
| 298 | case BFFM_INITIALIZED: | ||
| 299 | { | ||
| 300 | SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, data); | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | /* | ||
| 304 | case BFFM_SELCHANGED: | ||
| 305 | { | ||
| 306 | wchar_t dir[MAX_PATH * 2]; | ||
| 307 | |||
| 308 | if (shGetPathFromIDListW((LPITEMIDLIST)lp , dir)) | ||
| 309 | SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir); | ||
| 310 | else | ||
| 311 | SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)L""); | ||
| 312 | break; | ||
| 313 | } | ||
| 314 | */ | ||
| 315 | default: | ||
| 316 | break; | ||
| 317 | } | ||
| 318 | return 0; | ||
| 319 | } | ||
| 320 | |||
| 321 | |||
| 322 | static bool BrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags, | ||
| 323 | LPCWSTR initialFolder, UString &resultPath) | ||
| 324 | { | ||
| 325 | UString displayName; | ||
| 326 | BROWSEINFOW browseInfo; | ||
| 327 | browseInfo.hwndOwner = owner; | ||
| 328 | browseInfo.pidlRoot = NULL; | ||
| 329 | browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH); | ||
| 330 | browseInfo.lpszTitle = title; | ||
| 331 | browseInfo.ulFlags = ulFlags; | ||
| 332 | browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc2 : NULL; | ||
| 333 | browseInfo.lParam = (LPARAM)initialFolder; | ||
| 334 | return BrowseForFolder(&browseInfo, resultPath); | ||
| 335 | } | ||
| 336 | |||
| 337 | bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath) | ||
| 338 | { | ||
| 339 | if (g_IsNT) | ||
| 340 | return BrowseForFolder(owner, title, | ||
| 341 | BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | ||
| 342 | // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified. | ||
| 343 | , initialFolder, resultPath); | ||
| 344 | // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0) | ||
| 345 | CSysString s; | ||
| 346 | bool res = BrowseForFolder(owner, GetSystemString(title), | ||
| 347 | BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | ||
| 348 | // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified. | ||
| 349 | , GetSystemString(initialFolder), s); | ||
| 350 | resultPath = GetUnicodeString(s); | ||
| 351 | return res; | ||
| 352 | } | ||
| 353 | |||
| 354 | #endif | ||
| 355 | |||
| 356 | #endif | ||
| 357 | |||
| 358 | }} | ||
diff --git a/CPP/Windows/Shell.h b/CPP/Windows/Shell.h new file mode 100644 index 0000000..de91d3f --- /dev/null +++ b/CPP/Windows/Shell.h | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | // Windows/Shell.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_SHELL_H | ||
| 4 | #define __WINDOWS_SHELL_H | ||
| 5 | |||
| 6 | #include "../Common/MyWindows.h" | ||
| 7 | #include <ShlObj.h> | ||
| 8 | |||
| 9 | #include "../Common/MyString.h" | ||
| 10 | |||
| 11 | #include "Defs.h" | ||
| 12 | |||
| 13 | namespace NWindows{ | ||
| 14 | namespace NShell{ | ||
| 15 | |||
| 16 | ///////////////////////// | ||
| 17 | // CItemIDList | ||
| 18 | #ifndef UNDER_CE | ||
| 19 | |||
| 20 | class CItemIDList | ||
| 21 | { | ||
| 22 | LPITEMIDLIST m_Object; | ||
| 23 | public: | ||
| 24 | CItemIDList(): m_Object(NULL) {} | ||
| 25 | // CItemIDList(LPCITEMIDLIST itemIDList); | ||
| 26 | // CItemIDList(const CItemIDList& itemIDList); | ||
| 27 | ~CItemIDList() { Free(); } | ||
| 28 | void Free(); | ||
| 29 | void Attach(LPITEMIDLIST object) | ||
| 30 | { | ||
| 31 | Free(); | ||
| 32 | m_Object = object; | ||
| 33 | } | ||
| 34 | LPITEMIDLIST Detach() | ||
| 35 | { | ||
| 36 | LPITEMIDLIST object = m_Object; | ||
| 37 | m_Object = NULL; | ||
| 38 | return object; | ||
| 39 | } | ||
| 40 | operator LPITEMIDLIST() { return m_Object;} | ||
| 41 | operator LPCITEMIDLIST() const { return m_Object;} | ||
| 42 | LPITEMIDLIST* operator&() { return &m_Object; } | ||
| 43 | LPITEMIDLIST operator->() { return m_Object; } | ||
| 44 | |||
| 45 | // CItemIDList& operator=(LPCITEMIDLIST object); | ||
| 46 | // CItemIDList& operator=(const CItemIDList &object); | ||
| 47 | }; | ||
| 48 | |||
| 49 | ///////////////////////////// | ||
| 50 | // CDrop | ||
| 51 | |||
| 52 | class CDrop | ||
| 53 | { | ||
| 54 | HDROP m_Object; | ||
| 55 | bool m_MustBeFinished; | ||
| 56 | bool m_Assigned; | ||
| 57 | void Free(); | ||
| 58 | public: | ||
| 59 | CDrop(bool mustBeFinished) : m_MustBeFinished(mustBeFinished), m_Assigned(false) {} | ||
| 60 | ~CDrop() { Free(); } | ||
| 61 | |||
| 62 | void Attach(HDROP object); | ||
| 63 | operator HDROP() { return m_Object;} | ||
| 64 | bool QueryPoint(LPPOINT point) | ||
| 65 | { return BOOLToBool(::DragQueryPoint(m_Object, point)); } | ||
| 66 | void Finish() { ::DragFinish(m_Object); } | ||
| 67 | UINT QueryFile(UINT fileIndex, LPTSTR fileName, UINT fileNameSize) | ||
| 68 | { return ::DragQueryFile(m_Object, fileIndex, fileName, fileNameSize); } | ||
| 69 | #ifndef _UNICODE | ||
| 70 | UINT QueryFile(UINT fileIndex, LPWSTR fileName, UINT fileNameSize) | ||
| 71 | { return ::DragQueryFileW(m_Object, fileIndex, fileName, fileNameSize); } | ||
| 72 | #endif | ||
| 73 | UINT QueryCountOfFiles(); | ||
| 74 | UString QueryFileName(UINT fileIndex); | ||
| 75 | void QueryFileNames(UStringVector &fileNames); | ||
| 76 | }; | ||
| 77 | |||
| 78 | #endif | ||
| 79 | |||
| 80 | ///////////////////////////// | ||
| 81 | // Functions | ||
| 82 | |||
| 83 | bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path); | ||
| 84 | bool BrowseForFolder(LPBROWSEINFO lpbi, CSysString &resultPath); | ||
| 85 | bool BrowseForFolder(HWND owner, LPCTSTR title, LPCTSTR initialFolder, CSysString &resultPath); | ||
| 86 | |||
| 87 | #ifndef _UNICODE | ||
| 88 | bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path); | ||
| 89 | bool BrowseForFolder(LPBROWSEINFO lpbi, UString &resultPath); | ||
| 90 | bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath); | ||
| 91 | #endif | ||
| 92 | }} | ||
| 93 | |||
| 94 | #endif | ||
diff --git a/CPP/Windows/StdAfx.h b/CPP/Windows/StdAfx.h new file mode 100644 index 0000000..1766dfa --- /dev/null +++ b/CPP/Windows/StdAfx.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | // StdAfx.h | ||
| 2 | |||
| 3 | #ifndef __STDAFX_H | ||
| 4 | #define __STDAFX_H | ||
| 5 | |||
| 6 | #include "../Common/Common.h" | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/CPP/Windows/Synchronization.cpp b/CPP/Windows/Synchronization.cpp new file mode 100644 index 0000000..fbf919d --- /dev/null +++ b/CPP/Windows/Synchronization.cpp | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | // Windows/Synchronization.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef _WIN32 | ||
| 6 | |||
| 7 | #include "Synchronization.h" | ||
| 8 | |||
| 9 | namespace NWindows { | ||
| 10 | namespace NSynchronization { | ||
| 11 | |||
| 12 | /* | ||
| 13 | #define INFINITE 0xFFFFFFFF | ||
| 14 | #define MAXIMUM_WAIT_OBJECTS 64 | ||
| 15 | #define STATUS_ABANDONED_WAIT_0 ((NTSTATUS)0x00000080L) | ||
| 16 | #define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) | ||
| 17 | #define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) | ||
| 18 | // WINAPI | ||
| 19 | DWORD WaitForMultipleObjects(DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout); | ||
| 20 | */ | ||
| 21 | |||
| 22 | DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles) | ||
| 23 | { | ||
| 24 | if (count < 1) | ||
| 25 | { | ||
| 26 | // abort(); | ||
| 27 | SetLastError(EINVAL); | ||
| 28 | return WAIT_FAILED; | ||
| 29 | } | ||
| 30 | |||
| 31 | CSynchro *synchro = handles[0]->_sync; | ||
| 32 | synchro->Enter(); | ||
| 33 | |||
| 34 | // #ifdef DEBUG_SYNCHRO | ||
| 35 | for (DWORD i = 1; i < count; i++) | ||
| 36 | { | ||
| 37 | if (synchro != handles[i]->_sync) | ||
| 38 | { | ||
| 39 | // abort(); | ||
| 40 | synchro->Leave(); | ||
| 41 | SetLastError(EINVAL); | ||
| 42 | return WAIT_FAILED; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | // #endif | ||
| 46 | |||
| 47 | for (;;) | ||
| 48 | { | ||
| 49 | for (DWORD i = 0; i < count; i++) | ||
| 50 | { | ||
| 51 | if (handles[i]->IsSignaledAndUpdate()) | ||
| 52 | { | ||
| 53 | synchro->Leave(); | ||
| 54 | return WAIT_OBJECT_0 + i; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | synchro->WaitCond(); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | }} | ||
| 62 | |||
| 63 | #endif | ||
diff --git a/CPP/Windows/Synchronization.h b/CPP/Windows/Synchronization.h new file mode 100644 index 0000000..7d2e8d2 --- /dev/null +++ b/CPP/Windows/Synchronization.h | |||
| @@ -0,0 +1,393 @@ | |||
| 1 | // Windows/Synchronization.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_SYNCHRONIZATION_H | ||
| 4 | #define __WINDOWS_SYNCHRONIZATION_H | ||
| 5 | |||
| 6 | #include "../../C/Threads.h" | ||
| 7 | |||
| 8 | #include "../Common/MyTypes.h" | ||
| 9 | |||
| 10 | #include "Defs.h" | ||
| 11 | |||
| 12 | #ifdef _WIN32 | ||
| 13 | #include "Handle.h" | ||
| 14 | #endif | ||
| 15 | |||
| 16 | namespace NWindows { | ||
| 17 | namespace NSynchronization { | ||
| 18 | |||
| 19 | class CBaseEvent MY_UNCOPYABLE | ||
| 20 | { | ||
| 21 | protected: | ||
| 22 | ::CEvent _object; | ||
| 23 | public: | ||
| 24 | bool IsCreated() { return Event_IsCreated(&_object) != 0; } | ||
| 25 | |||
| 26 | CBaseEvent() { Event_Construct(&_object); } | ||
| 27 | ~CBaseEvent() { Close(); } | ||
| 28 | WRes Close() { return Event_Close(&_object); } | ||
| 29 | |||
| 30 | #ifdef _WIN32 | ||
| 31 | operator HANDLE() { return _object; } | ||
| 32 | WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) | ||
| 33 | { | ||
| 34 | _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name); | ||
| 35 | if (name == NULL && _object != 0) | ||
| 36 | return 0; | ||
| 37 | return ::GetLastError(); | ||
| 38 | } | ||
| 39 | WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) | ||
| 40 | { | ||
| 41 | _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name); | ||
| 42 | if (_object != 0) | ||
| 43 | return 0; | ||
| 44 | return ::GetLastError(); | ||
| 45 | } | ||
| 46 | #endif | ||
| 47 | |||
| 48 | WRes Set() { return Event_Set(&_object); } | ||
| 49 | // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); } | ||
| 50 | WRes Reset() { return Event_Reset(&_object); } | ||
| 51 | WRes Lock() { return Event_Wait(&_object); } | ||
| 52 | }; | ||
| 53 | |||
| 54 | class CManualResetEvent: public CBaseEvent | ||
| 55 | { | ||
| 56 | public: | ||
| 57 | WRes Create(bool initiallyOwn = false) | ||
| 58 | { | ||
| 59 | return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0); | ||
| 60 | } | ||
| 61 | WRes CreateIfNotCreated_Reset() | ||
| 62 | { | ||
| 63 | if (IsCreated()) | ||
| 64 | return Reset(); | ||
| 65 | return ManualResetEvent_CreateNotSignaled(&_object); | ||
| 66 | } | ||
| 67 | #ifdef _WIN32 | ||
| 68 | WRes CreateWithName(bool initiallyOwn, LPCTSTR name) | ||
| 69 | { | ||
| 70 | return CBaseEvent::Create(true, initiallyOwn, name); | ||
| 71 | } | ||
| 72 | #endif | ||
| 73 | }; | ||
| 74 | |||
| 75 | class CAutoResetEvent: public CBaseEvent | ||
| 76 | { | ||
| 77 | public: | ||
| 78 | WRes Create() | ||
| 79 | { | ||
| 80 | return AutoResetEvent_CreateNotSignaled(&_object); | ||
| 81 | } | ||
| 82 | WRes CreateIfNotCreated_Reset() | ||
| 83 | { | ||
| 84 | if (IsCreated()) | ||
| 85 | return Reset(); | ||
| 86 | return AutoResetEvent_CreateNotSignaled(&_object); | ||
| 87 | } | ||
| 88 | }; | ||
| 89 | |||
| 90 | |||
| 91 | /* | ||
| 92 | #ifdef _WIN32 | ||
| 93 | |||
| 94 | class CObject: public CHandle | ||
| 95 | { | ||
| 96 | public: | ||
| 97 | WRes Lock(DWORD timeoutInterval = INFINITE) | ||
| 98 | { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); } | ||
| 99 | }; | ||
| 100 | |||
| 101 | class CMutex: public CObject | ||
| 102 | { | ||
| 103 | public: | ||
| 104 | WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) | ||
| 105 | { | ||
| 106 | _handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name); | ||
| 107 | if (name == NULL && _handle != 0) | ||
| 108 | return 0; | ||
| 109 | return ::GetLastError(); | ||
| 110 | } | ||
| 111 | #ifndef UNDER_CE | ||
| 112 | WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) | ||
| 113 | { | ||
| 114 | _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name); | ||
| 115 | if (_handle != 0) | ||
| 116 | return 0; | ||
| 117 | return ::GetLastError(); | ||
| 118 | } | ||
| 119 | #endif | ||
| 120 | WRes Release() | ||
| 121 | { | ||
| 122 | return ::ReleaseMutex(_handle) ? 0 : ::GetLastError(); | ||
| 123 | } | ||
| 124 | }; | ||
| 125 | |||
| 126 | class CMutexLock MY_UNCOPYABLE | ||
| 127 | { | ||
| 128 | CMutex *_object; | ||
| 129 | public: | ||
| 130 | CMutexLock(CMutex &object): _object(&object) { _object->Lock(); } | ||
| 131 | ~CMutexLock() { _object->Release(); } | ||
| 132 | }; | ||
| 133 | |||
| 134 | #endif // _WIN32 | ||
| 135 | */ | ||
| 136 | |||
| 137 | |||
| 138 | class CSemaphore MY_UNCOPYABLE | ||
| 139 | { | ||
| 140 | ::CSemaphore _object; | ||
| 141 | public: | ||
| 142 | CSemaphore() { Semaphore_Construct(&_object); } | ||
| 143 | ~CSemaphore() { Close(); } | ||
| 144 | WRes Close() { return Semaphore_Close(&_object); } | ||
| 145 | |||
| 146 | #ifdef _WIN32 | ||
| 147 | operator HANDLE() { return _object; } | ||
| 148 | #endif | ||
| 149 | |||
| 150 | // bool IsCreated() const { return Semaphore_IsCreated(&_object) != 0; } | ||
| 151 | |||
| 152 | WRes Create(UInt32 initCount, UInt32 maxCount) | ||
| 153 | { | ||
| 154 | return Semaphore_Create(&_object, initCount, maxCount); | ||
| 155 | } | ||
| 156 | WRes OptCreateInit(UInt32 initCount, UInt32 maxCount) | ||
| 157 | { | ||
| 158 | return Semaphore_OptCreateInit(&_object, initCount, maxCount); | ||
| 159 | } | ||
| 160 | WRes Release() { return Semaphore_Release1(&_object); } | ||
| 161 | WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); } | ||
| 162 | WRes Lock() { return Semaphore_Wait(&_object); } | ||
| 163 | }; | ||
| 164 | |||
| 165 | class CCriticalSection MY_UNCOPYABLE | ||
| 166 | { | ||
| 167 | ::CCriticalSection _object; | ||
| 168 | public: | ||
| 169 | CCriticalSection() { CriticalSection_Init(&_object); } | ||
| 170 | ~CCriticalSection() { CriticalSection_Delete(&_object); } | ||
| 171 | void Enter() { CriticalSection_Enter(&_object); } | ||
| 172 | void Leave() { CriticalSection_Leave(&_object); } | ||
| 173 | }; | ||
| 174 | |||
| 175 | class CCriticalSectionLock MY_UNCOPYABLE | ||
| 176 | { | ||
| 177 | CCriticalSection *_object; | ||
| 178 | void Unlock() { _object->Leave(); } | ||
| 179 | public: | ||
| 180 | CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); } | ||
| 181 | ~CCriticalSectionLock() { Unlock(); } | ||
| 182 | }; | ||
| 183 | |||
| 184 | |||
| 185 | #ifdef _WIN32 | ||
| 186 | |||
| 187 | typedef HANDLE CHandle_WFMO; | ||
| 188 | typedef CSemaphore CSemaphore_WFMO; | ||
| 189 | typedef CAutoResetEvent CAutoResetEvent_WFMO; | ||
| 190 | typedef CManualResetEvent CManualResetEvent_WFMO; | ||
| 191 | |||
| 192 | inline DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles) | ||
| 193 | { | ||
| 194 | return ::WaitForMultipleObjects(count, handles, FALSE, INFINITE); | ||
| 195 | } | ||
| 196 | |||
| 197 | #define SYNC_OBJ_DECL(obj) | ||
| 198 | #define SYNC_WFMO(x) | ||
| 199 | #define SYNC_PARAM(x) | ||
| 200 | #define SYNC_PARAM_DECL(x) | ||
| 201 | |||
| 202 | #else // _WIN32 | ||
| 203 | |||
| 204 | // POSIX sync objects for WaitForMultipleObjects | ||
| 205 | |||
| 206 | #define SYNC_WFMO(x) x | ||
| 207 | #define SYNC_PARAM(x) x, | ||
| 208 | #define SYNC_PARAM_DECL(x) NWindows::NSynchronization::CSynchro *x | ||
| 209 | #define SYNC_OBJ_DECL(x) NWindows::NSynchronization::CSynchro x; | ||
| 210 | |||
| 211 | class CSynchro MY_UNCOPYABLE | ||
| 212 | { | ||
| 213 | pthread_mutex_t _mutex; | ||
| 214 | pthread_cond_t _cond; | ||
| 215 | bool _isValid; | ||
| 216 | |||
| 217 | public: | ||
| 218 | CSynchro() { _isValid = false; } | ||
| 219 | ~CSynchro() | ||
| 220 | { | ||
| 221 | if (_isValid) | ||
| 222 | { | ||
| 223 | ::pthread_mutex_destroy(&_mutex); | ||
| 224 | ::pthread_cond_destroy(&_cond); | ||
| 225 | } | ||
| 226 | _isValid = false; | ||
| 227 | } | ||
| 228 | WRes Create() | ||
| 229 | { | ||
| 230 | RINOK(::pthread_mutex_init(&_mutex, 0)); | ||
| 231 | WRes ret = ::pthread_cond_init(&_cond, 0); | ||
| 232 | _isValid = 1; | ||
| 233 | return ret; | ||
| 234 | } | ||
| 235 | WRes Enter() | ||
| 236 | { | ||
| 237 | return ::pthread_mutex_lock(&_mutex); | ||
| 238 | } | ||
| 239 | WRes Leave() | ||
| 240 | { | ||
| 241 | return ::pthread_mutex_unlock(&_mutex); | ||
| 242 | } | ||
| 243 | WRes WaitCond() | ||
| 244 | { | ||
| 245 | return ::pthread_cond_wait(&_cond, &_mutex); | ||
| 246 | } | ||
| 247 | WRes LeaveAndSignal() | ||
| 248 | { | ||
| 249 | WRes res1 = ::pthread_cond_broadcast(&_cond); | ||
| 250 | WRes res2 = ::pthread_mutex_unlock(&_mutex); | ||
| 251 | return (res2 ? res2 : res1); | ||
| 252 | } | ||
| 253 | }; | ||
| 254 | |||
| 255 | |||
| 256 | struct CBaseHandle_WFMO; | ||
| 257 | typedef NWindows::NSynchronization::CBaseHandle_WFMO *CHandle_WFMO; | ||
| 258 | |||
| 259 | // these constants are from Windows | ||
| 260 | #define WAIT_OBJECT_0 0 | ||
| 261 | #define WAIT_FAILED ((DWORD)0xFFFFFFFF) | ||
| 262 | |||
| 263 | DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles); | ||
| 264 | |||
| 265 | |||
| 266 | struct CBaseHandle_WFMO MY_UNCOPYABLE | ||
| 267 | { | ||
| 268 | CSynchro *_sync; | ||
| 269 | |||
| 270 | CBaseHandle_WFMO(): _sync(NULL) {} | ||
| 271 | |||
| 272 | operator CHandle_WFMO() { return this; } | ||
| 273 | virtual bool IsSignaledAndUpdate() = 0; | ||
| 274 | }; | ||
| 275 | |||
| 276 | |||
| 277 | class CBaseEvent_WFMO : public CBaseHandle_WFMO | ||
| 278 | { | ||
| 279 | bool _manual_reset; | ||
| 280 | bool _state; | ||
| 281 | |||
| 282 | public: | ||
| 283 | |||
| 284 | // bool IsCreated() { return (this->_sync != NULL); } | ||
| 285 | // CBaseEvent_WFMO() { ; } | ||
| 286 | ~CBaseEvent_WFMO() { Close(); } | ||
| 287 | |||
| 288 | WRes Close() { this->_sync = NULL; return 0; } | ||
| 289 | |||
| 290 | WRes Create( | ||
| 291 | CSynchro *sync, | ||
| 292 | bool manualReset, bool initiallyOwn) | ||
| 293 | { | ||
| 294 | this->_sync = sync; | ||
| 295 | this->_manual_reset = manualReset; | ||
| 296 | this->_state = initiallyOwn; | ||
| 297 | return 0; | ||
| 298 | } | ||
| 299 | |||
| 300 | WRes Set() | ||
| 301 | { | ||
| 302 | RINOK(this->_sync->Enter()); | ||
| 303 | this->_state = true; | ||
| 304 | return this->_sync->LeaveAndSignal(); | ||
| 305 | } | ||
| 306 | |||
| 307 | WRes Reset() | ||
| 308 | { | ||
| 309 | RINOK(this->_sync->Enter()); | ||
| 310 | this->_state = false; | ||
| 311 | return this->_sync->Leave(); | ||
| 312 | } | ||
| 313 | |||
| 314 | virtual bool IsSignaledAndUpdate() | ||
| 315 | { | ||
| 316 | if (this->_state == false) | ||
| 317 | return false; | ||
| 318 | if (this->_manual_reset == false) | ||
| 319 | this->_state = false; | ||
| 320 | return true; | ||
| 321 | } | ||
| 322 | }; | ||
| 323 | |||
| 324 | |||
| 325 | class CManualResetEvent_WFMO: public CBaseEvent_WFMO | ||
| 326 | { | ||
| 327 | public: | ||
| 328 | WRes Create(CSynchro *sync, bool initiallyOwn = false) { return CBaseEvent_WFMO::Create(sync, true, initiallyOwn); } | ||
| 329 | }; | ||
| 330 | |||
| 331 | |||
| 332 | class CAutoResetEvent_WFMO: public CBaseEvent_WFMO | ||
| 333 | { | ||
| 334 | public: | ||
| 335 | WRes Create(CSynchro *sync) { return CBaseEvent_WFMO::Create(sync, false, false); } | ||
| 336 | WRes CreateIfNotCreated_Reset(CSynchro *sync) | ||
| 337 | { | ||
| 338 | return Create(sync); | ||
| 339 | } | ||
| 340 | }; | ||
| 341 | |||
| 342 | |||
| 343 | class CSemaphore_WFMO : public CBaseHandle_WFMO | ||
| 344 | { | ||
| 345 | UInt32 _count; | ||
| 346 | UInt32 _maxCount; | ||
| 347 | |||
| 348 | public: | ||
| 349 | CSemaphore_WFMO() : _count(0), _maxCount(0) {} | ||
| 350 | |||
| 351 | WRes Close() { this->_sync = NULL; return 0; } | ||
| 352 | |||
| 353 | WRes Create(CSynchro *sync, UInt32 initCount, UInt32 maxCount) | ||
| 354 | { | ||
| 355 | if (initCount > maxCount || maxCount < 1) | ||
| 356 | return EINVAL; | ||
| 357 | this->_sync = sync; | ||
| 358 | this->_count = initCount; | ||
| 359 | this->_maxCount = maxCount; | ||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | |||
| 363 | WRes Release(UInt32 releaseCount = 1) | ||
| 364 | { | ||
| 365 | if (releaseCount < 1) | ||
| 366 | return EINVAL; | ||
| 367 | |||
| 368 | RINOK(this->_sync->Enter()); | ||
| 369 | UInt32 newCount = this->_count + releaseCount; | ||
| 370 | if (newCount > this->_maxCount) | ||
| 371 | { | ||
| 372 | RINOK(this->_sync->Leave()); | ||
| 373 | return ERROR_TOO_MANY_POSTS; // EINVAL | ||
| 374 | } | ||
| 375 | this->_count = newCount; | ||
| 376 | |||
| 377 | return this->_sync->LeaveAndSignal(); | ||
| 378 | } | ||
| 379 | |||
| 380 | virtual bool IsSignaledAndUpdate() | ||
| 381 | { | ||
| 382 | if (this->_count == 0) | ||
| 383 | return false; | ||
| 384 | this->_count--; | ||
| 385 | return true; | ||
| 386 | } | ||
| 387 | }; | ||
| 388 | |||
| 389 | #endif // _WIN32 | ||
| 390 | |||
| 391 | }} | ||
| 392 | |||
| 393 | #endif | ||
diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp new file mode 100644 index 0000000..3a14b77 --- /dev/null +++ b/CPP/Windows/System.cpp | |||
| @@ -0,0 +1,234 @@ | |||
| 1 | // Windows/System.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef _WIN32 | ||
| 6 | #include <unistd.h> | ||
| 7 | #ifdef __APPLE__ | ||
| 8 | #include <sys/sysctl.h> | ||
| 9 | #else | ||
| 10 | #include <sys/sysinfo.h> | ||
| 11 | #endif | ||
| 12 | #endif | ||
| 13 | |||
| 14 | #include "../Common/Defs.h" | ||
| 15 | // #include "../Common/MyWindows.h" | ||
| 16 | |||
| 17 | // #include "../../C/CpuArch.h" | ||
| 18 | |||
| 19 | #include "System.h" | ||
| 20 | |||
| 21 | namespace NWindows { | ||
| 22 | namespace NSystem { | ||
| 23 | |||
| 24 | #ifdef _WIN32 | ||
| 25 | |||
| 26 | UInt32 CountAffinity(DWORD_PTR mask) | ||
| 27 | { | ||
| 28 | UInt32 num = 0; | ||
| 29 | for (unsigned i = 0; i < sizeof(mask) * 8; i++) | ||
| 30 | num += (UInt32)((mask >> i) & 1); | ||
| 31 | return num; | ||
| 32 | } | ||
| 33 | |||
| 34 | BOOL CProcessAffinity::Get() | ||
| 35 | { | ||
| 36 | #ifndef UNDER_CE | ||
| 37 | return GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask); | ||
| 38 | #else | ||
| 39 | return FALSE; | ||
| 40 | #endif | ||
| 41 | } | ||
| 42 | |||
| 43 | |||
| 44 | UInt32 GetNumberOfProcessors() | ||
| 45 | { | ||
| 46 | // We need to know how many threads we can use. | ||
| 47 | // By default the process is assigned to one group. | ||
| 48 | // So we get the number of logical processors (threads) | ||
| 49 | // assigned to current process in the current group. | ||
| 50 | // Group size can be smaller than total number logical processors, for exammple, 2x36 | ||
| 51 | |||
| 52 | CProcessAffinity pa; | ||
| 53 | |||
| 54 | if (pa.Get() && pa.processAffinityMask != 0) | ||
| 55 | return pa.GetNumProcessThreads(); | ||
| 56 | |||
| 57 | SYSTEM_INFO systemInfo; | ||
| 58 | GetSystemInfo(&systemInfo); | ||
| 59 | // the number of logical processors in the current group | ||
| 60 | return (UInt32)systemInfo.dwNumberOfProcessors; | ||
| 61 | } | ||
| 62 | |||
| 63 | #else | ||
| 64 | |||
| 65 | |||
| 66 | BOOL CProcessAffinity::Get() | ||
| 67 | { | ||
| 68 | numSysThreads = GetNumberOfProcessors(); | ||
| 69 | |||
| 70 | /* | ||
| 71 | numSysThreads = 8; | ||
| 72 | for (unsigned i = 0; i < numSysThreads; i++) | ||
| 73 | CpuSet_Set(&cpu_set, i); | ||
| 74 | return TRUE; | ||
| 75 | */ | ||
| 76 | |||
| 77 | #ifdef _7ZIP_AFFINITY_SUPPORTED | ||
| 78 | |||
| 79 | // numSysThreads = sysconf(_SC_NPROCESSORS_ONLN); // The number of processors currently online | ||
| 80 | if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) != 0) | ||
| 81 | return FALSE; | ||
| 82 | return TRUE; | ||
| 83 | |||
| 84 | #else | ||
| 85 | |||
| 86 | // cpu_set = ((CCpuSet)1 << (numSysThreads)) - 1; | ||
| 87 | return TRUE; | ||
| 88 | // errno = ENOSYS; | ||
| 89 | // return FALSE; | ||
| 90 | |||
| 91 | #endif | ||
| 92 | } | ||
| 93 | |||
| 94 | UInt32 GetNumberOfProcessors() | ||
| 95 | { | ||
| 96 | #ifndef _7ZIP_ST | ||
| 97 | long n = sysconf(_SC_NPROCESSORS_CONF); // The number of processors configured | ||
| 98 | if (n < 1) | ||
| 99 | n = 1; | ||
| 100 | return (UInt32)n; | ||
| 101 | #else | ||
| 102 | return 1; | ||
| 103 | #endif | ||
| 104 | } | ||
| 105 | |||
| 106 | #endif | ||
| 107 | |||
| 108 | |||
| 109 | #ifdef _WIN32 | ||
| 110 | |||
| 111 | #ifndef UNDER_CE | ||
| 112 | |||
| 113 | #if !defined(_WIN64) && defined(__GNUC__) | ||
| 114 | |||
| 115 | typedef struct _MY_MEMORYSTATUSEX { | ||
| 116 | DWORD dwLength; | ||
| 117 | DWORD dwMemoryLoad; | ||
| 118 | DWORDLONG ullTotalPhys; | ||
| 119 | DWORDLONG ullAvailPhys; | ||
| 120 | DWORDLONG ullTotalPageFile; | ||
| 121 | DWORDLONG ullAvailPageFile; | ||
| 122 | DWORDLONG ullTotalVirtual; | ||
| 123 | DWORDLONG ullAvailVirtual; | ||
| 124 | DWORDLONG ullAvailExtendedVirtual; | ||
| 125 | } MY_MEMORYSTATUSEX, *MY_LPMEMORYSTATUSEX; | ||
| 126 | |||
| 127 | #else | ||
| 128 | |||
| 129 | #define MY_MEMORYSTATUSEX MEMORYSTATUSEX | ||
| 130 | #define MY_LPMEMORYSTATUSEX LPMEMORYSTATUSEX | ||
| 131 | |||
| 132 | #endif | ||
| 133 | |||
| 134 | typedef BOOL (WINAPI *GlobalMemoryStatusExP)(MY_LPMEMORYSTATUSEX lpBuffer); | ||
| 135 | |||
| 136 | #endif // !UNDER_CE | ||
| 137 | |||
| 138 | |||
| 139 | bool GetRamSize(UInt64 &size) | ||
| 140 | { | ||
| 141 | size = (UInt64)(sizeof(size_t)) << 29; | ||
| 142 | |||
| 143 | #ifndef UNDER_CE | ||
| 144 | MY_MEMORYSTATUSEX stat; | ||
| 145 | stat.dwLength = sizeof(stat); | ||
| 146 | #endif | ||
| 147 | |||
| 148 | #ifdef _WIN64 | ||
| 149 | |||
| 150 | if (!::GlobalMemoryStatusEx(&stat)) | ||
| 151 | return false; | ||
| 152 | size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); | ||
| 153 | return true; | ||
| 154 | |||
| 155 | #else | ||
| 156 | |||
| 157 | #ifndef UNDER_CE | ||
| 158 | GlobalMemoryStatusExP globalMemoryStatusEx = (GlobalMemoryStatusExP) | ||
| 159 | (void *)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "GlobalMemoryStatusEx"); | ||
| 160 | if (globalMemoryStatusEx && globalMemoryStatusEx(&stat)) | ||
| 161 | { | ||
| 162 | size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); | ||
| 163 | return true; | ||
| 164 | } | ||
| 165 | #endif | ||
| 166 | |||
| 167 | { | ||
| 168 | MEMORYSTATUS stat2; | ||
| 169 | stat2.dwLength = sizeof(stat2); | ||
| 170 | ::GlobalMemoryStatus(&stat2); | ||
| 171 | size = MyMin(stat2.dwTotalVirtual, stat2.dwTotalPhys); | ||
| 172 | return true; | ||
| 173 | } | ||
| 174 | #endif | ||
| 175 | } | ||
| 176 | |||
| 177 | #else | ||
| 178 | |||
| 179 | // POSIX | ||
| 180 | // #include <stdio.h> | ||
| 181 | |||
| 182 | bool GetRamSize(UInt64 &size) | ||
| 183 | { | ||
| 184 | size = (UInt64)(sizeof(size_t)) << 29; | ||
| 185 | |||
| 186 | #ifdef __APPLE__ | ||
| 187 | |||
| 188 | #ifdef HW_MEMSIZE | ||
| 189 | uint64_t val = 0; // support 2Gb+ RAM | ||
| 190 | int mib[2] = { CTL_HW, HW_MEMSIZE }; | ||
| 191 | #elif defined(HW_PHYSMEM64) | ||
| 192 | uint64_t val = 0; // support 2Gb+ RAM | ||
| 193 | int mib[2] = { CTL_HW, HW_PHYSMEM64 }; | ||
| 194 | #else | ||
| 195 | unsigned int val = 0; // For old system | ||
| 196 | int mib[2] = { CTL_HW, HW_PHYSMEM }; | ||
| 197 | #endif // HW_MEMSIZE | ||
| 198 | size_t size_sys = sizeof(val); | ||
| 199 | |||
| 200 | sysctl(mib, 2, &val, &size_sys, NULL, 0); | ||
| 201 | if (val) | ||
| 202 | size = val; | ||
| 203 | |||
| 204 | #elif defined(_AIX) | ||
| 205 | // fixme | ||
| 206 | #elif defined(__gnu_hurd__) | ||
| 207 | // fixme | ||
| 208 | #elif defined(__FreeBSD_kernel__) && defined(__GLIBC__) | ||
| 209 | // GNU/kFreeBSD Debian | ||
| 210 | // fixme | ||
| 211 | #else | ||
| 212 | |||
| 213 | struct sysinfo info; | ||
| 214 | if (::sysinfo(&info) != 0) | ||
| 215 | return false; | ||
| 216 | size = (UInt64)info.mem_unit * info.totalram; | ||
| 217 | const UInt64 kLimit = (UInt64)1 << (sizeof(size_t) * 8 - 1); | ||
| 218 | if (size > kLimit) | ||
| 219 | size = kLimit; | ||
| 220 | |||
| 221 | /* | ||
| 222 | printf("\n mem_unit = %lld", (UInt64)info.mem_unit); | ||
| 223 | printf("\n totalram = %lld", (UInt64)info.totalram); | ||
| 224 | printf("\n freeram = %lld", (UInt64)info.freeram); | ||
| 225 | */ | ||
| 226 | |||
| 227 | #endif | ||
| 228 | |||
| 229 | return true; | ||
| 230 | } | ||
| 231 | |||
| 232 | #endif | ||
| 233 | |||
| 234 | }} | ||
diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h new file mode 100644 index 0000000..23cb0da --- /dev/null +++ b/CPP/Windows/System.h | |||
| @@ -0,0 +1,129 @@ | |||
| 1 | // Windows/System.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_SYSTEM_H | ||
| 4 | #define __WINDOWS_SYSTEM_H | ||
| 5 | |||
| 6 | #ifndef _WIN32 | ||
| 7 | // #include <sched.h> | ||
| 8 | #include "../../C/Threads.h" | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #include "../Common/MyTypes.h" | ||
| 12 | |||
| 13 | namespace NWindows { | ||
| 14 | namespace NSystem { | ||
| 15 | |||
| 16 | |||
| 17 | #ifdef _WIN32 | ||
| 18 | |||
| 19 | UInt32 CountAffinity(DWORD_PTR mask); | ||
| 20 | |||
| 21 | struct CProcessAffinity | ||
| 22 | { | ||
| 23 | // UInt32 numProcessThreads; | ||
| 24 | // UInt32 numSysThreads; | ||
| 25 | DWORD_PTR processAffinityMask; | ||
| 26 | DWORD_PTR systemAffinityMask; | ||
| 27 | |||
| 28 | void InitST() | ||
| 29 | { | ||
| 30 | // numProcessThreads = 1; | ||
| 31 | // numSysThreads = 1; | ||
| 32 | processAffinityMask = 1; | ||
| 33 | systemAffinityMask = 1; | ||
| 34 | } | ||
| 35 | |||
| 36 | void CpuZero() | ||
| 37 | { | ||
| 38 | processAffinityMask = 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | void CpuSet(unsigned cpuIndex) | ||
| 42 | { | ||
| 43 | processAffinityMask |= ((DWORD_PTR)1 << cpuIndex); | ||
| 44 | } | ||
| 45 | |||
| 46 | UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); } | ||
| 47 | UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); } | ||
| 48 | |||
| 49 | BOOL Get(); | ||
| 50 | |||
| 51 | BOOL SetProcAffinity() const | ||
| 52 | { | ||
| 53 | return SetProcessAffinityMask(GetCurrentProcess(), processAffinityMask); | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | |||
| 57 | |||
| 58 | #else // WIN32 | ||
| 59 | |||
| 60 | struct CProcessAffinity | ||
| 61 | { | ||
| 62 | UInt32 numSysThreads; | ||
| 63 | |||
| 64 | UInt32 GetNumSystemThreads() const { return (UInt32)numSysThreads; } | ||
| 65 | BOOL Get(); | ||
| 66 | |||
| 67 | #ifdef _7ZIP_AFFINITY_SUPPORTED | ||
| 68 | |||
| 69 | CCpuSet cpu_set; | ||
| 70 | |||
| 71 | void InitST() | ||
| 72 | { | ||
| 73 | numSysThreads = 1; | ||
| 74 | CpuSet_Zero(&cpu_set); | ||
| 75 | CpuSet_Set(&cpu_set, 0); | ||
| 76 | } | ||
| 77 | |||
| 78 | UInt32 GetNumProcessThreads() const { return (UInt32)CPU_COUNT(&cpu_set); } | ||
| 79 | void CpuZero() { CpuSet_Zero(&cpu_set); } | ||
| 80 | void CpuSet(unsigned cpuIndex) { CpuSet_Set(&cpu_set, cpuIndex); } | ||
| 81 | int IsCpuSet(unsigned cpuIndex) const { return CpuSet_IsSet(&cpu_set, cpuIndex); } | ||
| 82 | // void CpuClr(int cpuIndex) { CPU_CLR(cpuIndex, &cpu_set); } | ||
| 83 | |||
| 84 | BOOL SetProcAffinity() const | ||
| 85 | { | ||
| 86 | return sched_setaffinity(0, sizeof(cpu_set), &cpu_set) == 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | #else | ||
| 90 | |||
| 91 | void InitST() | ||
| 92 | { | ||
| 93 | numSysThreads = 1; | ||
| 94 | } | ||
| 95 | |||
| 96 | UInt32 GetNumProcessThreads() const | ||
| 97 | { | ||
| 98 | return numSysThreads; | ||
| 99 | /* | ||
| 100 | UInt32 num = 0; | ||
| 101 | for (unsigned i = 0; i < sizeof(cpu_set) * 8; i++) | ||
| 102 | num += (UInt32)((cpu_set >> i) & 1); | ||
| 103 | return num; | ||
| 104 | */ | ||
| 105 | } | ||
| 106 | |||
| 107 | void CpuZero() { } | ||
| 108 | void CpuSet(unsigned cpuIndex) { UNUSED_VAR(cpuIndex); } | ||
| 109 | int IsCpuSet(unsigned cpuIndex) const { return (cpuIndex < numSysThreads) ? 1 : 0; } | ||
| 110 | |||
| 111 | BOOL SetProcAffinity() const | ||
| 112 | { | ||
| 113 | errno = ENOSYS; | ||
| 114 | return FALSE; | ||
| 115 | } | ||
| 116 | |||
| 117 | #endif | ||
| 118 | }; | ||
| 119 | |||
| 120 | #endif | ||
| 121 | |||
| 122 | |||
| 123 | UInt32 GetNumberOfProcessors(); | ||
| 124 | |||
| 125 | bool GetRamSize(UInt64 &size); // returns false, if unknown ram size | ||
| 126 | |||
| 127 | }} | ||
| 128 | |||
| 129 | #endif | ||
diff --git a/CPP/Windows/SystemInfo.cpp b/CPP/Windows/SystemInfo.cpp new file mode 100644 index 0000000..d882a8e --- /dev/null +++ b/CPP/Windows/SystemInfo.cpp | |||
| @@ -0,0 +1,917 @@ | |||
| 1 | // Windows/SystemInfo.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../../C/CpuArch.h" | ||
| 6 | |||
| 7 | #include "../Common/IntToString.h" | ||
| 8 | |||
| 9 | #ifdef _WIN32 | ||
| 10 | |||
| 11 | #include "Registry.h" | ||
| 12 | |||
| 13 | #else | ||
| 14 | |||
| 15 | #include <unistd.h> | ||
| 16 | #include <sys/utsname.h> | ||
| 17 | #ifdef __APPLE__ | ||
| 18 | #include <sys/sysctl.h> | ||
| 19 | #elif !defined(_AIX) | ||
| 20 | |||
| 21 | #include <sys/auxv.h> | ||
| 22 | |||
| 23 | // #undef AT_HWCAP // to debug | ||
| 24 | // #undef AT_HWCAP2 // to debug | ||
| 25 | |||
| 26 | /* the following patch for some debian systems. | ||
| 27 | Is it OK to define AT_HWCAP and AT_HWCAP2 here with these constant numbers? */ | ||
| 28 | /* | ||
| 29 | #if defined(__FreeBSD_kernel__) && defined(__GLIBC__) | ||
| 30 | #ifndef AT_HWCAP | ||
| 31 | #define AT_HWCAP 16 | ||
| 32 | #endif | ||
| 33 | #ifndef AT_HWCAP2 | ||
| 34 | #define AT_HWCAP2 26 | ||
| 35 | #endif | ||
| 36 | #endif | ||
| 37 | */ | ||
| 38 | |||
| 39 | #ifdef MY_CPU_ARM_OR_ARM64 | ||
| 40 | #include <asm/hwcap.h> | ||
| 41 | #endif | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #ifdef __linux__ | ||
| 45 | #include "../Windows/FileIO.h" | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #endif // WIN32 | ||
| 49 | |||
| 50 | #include "SystemInfo.h" | ||
| 51 | #include "System.h" | ||
| 52 | |||
| 53 | using namespace NWindows; | ||
| 54 | |||
| 55 | #ifdef __linux__ | ||
| 56 | |||
| 57 | static bool ReadFile_to_Buffer(CFSTR fileName, CByteBuffer &buf) | ||
| 58 | { | ||
| 59 | NWindows::NFile::NIO::CInFile file; | ||
| 60 | if (!file.Open(fileName)) | ||
| 61 | return false; | ||
| 62 | /* | ||
| 63 | UInt64 size; | ||
| 64 | if (!file.GetLength(size)) | ||
| 65 | { | ||
| 66 | // GetLength() doesn't work "/proc/cpuinfo" | ||
| 67 | return false; | ||
| 68 | } | ||
| 69 | if (size >= ((UInt32)1 << 29)) | ||
| 70 | return false; | ||
| 71 | */ | ||
| 72 | size_t size = 0; | ||
| 73 | size_t addSize = ((size_t)1 << 12); | ||
| 74 | for (;;) | ||
| 75 | { | ||
| 76 | // printf("\nsize = %d\n", (unsigned)size); | ||
| 77 | buf.ChangeSize_KeepData(size + addSize, size); | ||
| 78 | size_t processed; | ||
| 79 | if (!file.ReadFull(buf + size, addSize, processed)) | ||
| 80 | return false; | ||
| 81 | if (processed == 0) | ||
| 82 | { | ||
| 83 | buf.ChangeSize_KeepData(size, size); | ||
| 84 | return true; | ||
| 85 | } | ||
| 86 | size += processed; | ||
| 87 | addSize *= 2; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | #endif | ||
| 92 | |||
| 93 | |||
| 94 | #if defined(_WIN32) || defined(AT_HWCAP) || defined(AT_HWCAP2) | ||
| 95 | static void PrintHex(AString &s, UInt64 v) | ||
| 96 | { | ||
| 97 | char temp[32]; | ||
| 98 | ConvertUInt64ToHex(v, temp); | ||
| 99 | s += temp; | ||
| 100 | } | ||
| 101 | #endif | ||
| 102 | |||
| 103 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 104 | |||
| 105 | static void PrintCpuChars(AString &s, UInt32 v) | ||
| 106 | { | ||
| 107 | for (int j = 0; j < 4; j++) | ||
| 108 | { | ||
| 109 | Byte b = (Byte)(v & 0xFF); | ||
| 110 | v >>= 8; | ||
| 111 | if (b == 0) | ||
| 112 | break; | ||
| 113 | s += (char)b; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | |||
| 118 | static void x86cpuid_to_String(const Cx86cpuid &c, AString &s, AString &ver) | ||
| 119 | { | ||
| 120 | s.Empty(); | ||
| 121 | |||
| 122 | UInt32 maxFunc2 = 0; | ||
| 123 | UInt32 t[3]; | ||
| 124 | |||
| 125 | MyCPUID(0x80000000, &maxFunc2, &t[0], &t[1], &t[2]); | ||
| 126 | |||
| 127 | bool fullNameIsAvail = (maxFunc2 >= 0x80000004); | ||
| 128 | |||
| 129 | if (fullNameIsAvail) | ||
| 130 | { | ||
| 131 | for (unsigned i = 0; i < 3; i++) | ||
| 132 | { | ||
| 133 | UInt32 d[4] = { 0 }; | ||
| 134 | MyCPUID(0x80000002 + i, &d[0], &d[1], &d[2], &d[3]); | ||
| 135 | for (unsigned j = 0; j < 4; j++) | ||
| 136 | PrintCpuChars(s, d[j]); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | s.Trim(); | ||
| 141 | |||
| 142 | if (s.IsEmpty()) | ||
| 143 | { | ||
| 144 | for (int i = 0; i < 3; i++) | ||
| 145 | PrintCpuChars(s, c.vendor[i]); | ||
| 146 | s.Trim(); | ||
| 147 | } | ||
| 148 | |||
| 149 | { | ||
| 150 | char temp[32]; | ||
| 151 | ConvertUInt32ToHex(c.ver, temp); | ||
| 152 | ver += temp; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | /* | ||
| 157 | static void x86cpuid_all_to_String(AString &s) | ||
| 158 | { | ||
| 159 | Cx86cpuid p; | ||
| 160 | if (!x86cpuid_CheckAndRead(&p)) | ||
| 161 | return; | ||
| 162 | s += "x86cpuid maxFunc = "; | ||
| 163 | s.Add_UInt32(p.maxFunc); | ||
| 164 | for (unsigned j = 0; j <= p.maxFunc; j++) | ||
| 165 | { | ||
| 166 | s.Add_LF(); | ||
| 167 | // s.Add_UInt32(j); // align | ||
| 168 | { | ||
| 169 | char temp[32]; | ||
| 170 | ConvertUInt32ToString(j, temp); | ||
| 171 | unsigned len = (unsigned)strlen(temp); | ||
| 172 | while (len < 8) | ||
| 173 | { | ||
| 174 | len++; | ||
| 175 | s.Add_Space(); | ||
| 176 | } | ||
| 177 | s += temp; | ||
| 178 | } | ||
| 179 | |||
| 180 | s += ":"; | ||
| 181 | UInt32 d[4] = { 0 }; | ||
| 182 | MyCPUID(j, &d[0], &d[1], &d[2], &d[3]); | ||
| 183 | for (unsigned i = 0; i < 4; i++) | ||
| 184 | { | ||
| 185 | char temp[32]; | ||
| 186 | ConvertUInt32ToHex8Digits(d[i], temp); | ||
| 187 | s += " "; | ||
| 188 | s += temp; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | } | ||
| 192 | */ | ||
| 193 | |||
| 194 | #endif | ||
| 195 | |||
| 196 | |||
| 197 | |||
| 198 | #ifdef _WIN32 | ||
| 199 | |||
| 200 | static const char * const k_PROCESSOR_ARCHITECTURE[] = | ||
| 201 | { | ||
| 202 | "x86" // "INTEL" | ||
| 203 | , "MIPS" | ||
| 204 | , "ALPHA" | ||
| 205 | , "PPC" | ||
| 206 | , "SHX" | ||
| 207 | , "ARM" | ||
| 208 | , "IA64" | ||
| 209 | , "ALPHA64" | ||
| 210 | , "MSIL" | ||
| 211 | , "x64" // "AMD64" | ||
| 212 | , "IA32_ON_WIN64" | ||
| 213 | , "NEUTRAL" | ||
| 214 | , "ARM64" | ||
| 215 | , "ARM32_ON_WIN64" | ||
| 216 | }; | ||
| 217 | |||
| 218 | #define MY__PROCESSOR_ARCHITECTURE_INTEL 0 | ||
| 219 | #define MY__PROCESSOR_ARCHITECTURE_AMD64 9 | ||
| 220 | |||
| 221 | |||
| 222 | #define MY__PROCESSOR_INTEL_PENTIUM 586 | ||
| 223 | #define MY__PROCESSOR_AMD_X8664 8664 | ||
| 224 | |||
| 225 | /* | ||
| 226 | static const CUInt32PCharPair k_PROCESSOR[] = | ||
| 227 | { | ||
| 228 | { 2200, "IA64" }, | ||
| 229 | { 8664, "x64" } | ||
| 230 | }; | ||
| 231 | |||
| 232 | #define PROCESSOR_INTEL_386 386 | ||
| 233 | #define PROCESSOR_INTEL_486 486 | ||
| 234 | #define PROCESSOR_INTEL_PENTIUM 586 | ||
| 235 | #define PROCESSOR_INTEL_860 860 | ||
| 236 | #define PROCESSOR_INTEL_IA64 2200 | ||
| 237 | #define PROCESSOR_AMD_X8664 8664 | ||
| 238 | #define PROCESSOR_MIPS_R2000 2000 | ||
| 239 | #define PROCESSOR_MIPS_R3000 3000 | ||
| 240 | #define PROCESSOR_MIPS_R4000 4000 | ||
| 241 | #define PROCESSOR_ALPHA_21064 21064 | ||
| 242 | #define PROCESSOR_PPC_601 601 | ||
| 243 | #define PROCESSOR_PPC_603 603 | ||
| 244 | #define PROCESSOR_PPC_604 604 | ||
| 245 | #define PROCESSOR_PPC_620 620 | ||
| 246 | #define PROCESSOR_HITACHI_SH3 10003 | ||
| 247 | #define PROCESSOR_HITACHI_SH3E 10004 | ||
| 248 | #define PROCESSOR_HITACHI_SH4 10005 | ||
| 249 | #define PROCESSOR_MOTOROLA_821 821 | ||
| 250 | #define PROCESSOR_SHx_SH3 103 | ||
| 251 | #define PROCESSOR_SHx_SH4 104 | ||
| 252 | #define PROCESSOR_STRONGARM 2577 // 0xA11 | ||
| 253 | #define PROCESSOR_ARM720 1824 // 0x720 | ||
| 254 | #define PROCESSOR_ARM820 2080 // 0x820 | ||
| 255 | #define PROCESSOR_ARM920 2336 // 0x920 | ||
| 256 | #define PROCESSOR_ARM_7TDMI 70001 | ||
| 257 | #define PROCESSOR_OPTIL 18767 // 0x494f | ||
| 258 | */ | ||
| 259 | |||
| 260 | |||
| 261 | /* | ||
| 262 | static const char * const k_PF[] = | ||
| 263 | { | ||
| 264 | "FP_ERRATA" | ||
| 265 | , "FP_EMU" | ||
| 266 | , "CMPXCHG" | ||
| 267 | , "MMX" | ||
| 268 | , "PPC_MOVEMEM_64BIT" | ||
| 269 | , "ALPHA_BYTE" | ||
| 270 | , "SSE" | ||
| 271 | , "3DNOW" | ||
| 272 | , "RDTSC" | ||
| 273 | , "PAE" | ||
| 274 | , "SSE2" | ||
| 275 | , "SSE_DAZ" | ||
| 276 | , "NX" | ||
| 277 | , "SSE3" | ||
| 278 | , "CMPXCHG16B" | ||
| 279 | , "CMP8XCHG16" | ||
| 280 | , "CHANNELS" | ||
| 281 | , "XSAVE" | ||
| 282 | , "ARM_VFP_32" | ||
| 283 | , "ARM_NEON" | ||
| 284 | , "L2AT" | ||
| 285 | , "VIRT_FIRMWARE" | ||
| 286 | , "RDWRFSGSBASE" | ||
| 287 | , "FASTFAIL" | ||
| 288 | , "ARM_DIVIDE" | ||
| 289 | , "ARM_64BIT_LOADSTORE_ATOMIC" | ||
| 290 | , "ARM_EXTERNAL_CACHE" | ||
| 291 | , "ARM_FMAC" | ||
| 292 | , "RDRAND" | ||
| 293 | , "ARM_V8" | ||
| 294 | , "ARM_V8_CRYPTO" | ||
| 295 | , "ARM_V8_CRC32" | ||
| 296 | , "RDTSCP" | ||
| 297 | , "RDPID" | ||
| 298 | , "ARM_V81_ATOMIC" | ||
| 299 | , "MONITORX" | ||
| 300 | }; | ||
| 301 | */ | ||
| 302 | |||
| 303 | #endif | ||
| 304 | |||
| 305 | |||
| 306 | #ifdef _WIN32 | ||
| 307 | |||
| 308 | static void PrintPage(AString &s, UInt32 v) | ||
| 309 | { | ||
| 310 | if ((v & 0x3FF) == 0) | ||
| 311 | { | ||
| 312 | s.Add_UInt32(v >> 10); | ||
| 313 | s += "K"; | ||
| 314 | } | ||
| 315 | else | ||
| 316 | s.Add_UInt32(v >> 10); | ||
| 317 | } | ||
| 318 | |||
| 319 | static AString TypeToString2(const char * const table[], unsigned num, UInt32 value) | ||
| 320 | { | ||
| 321 | char sz[16]; | ||
| 322 | const char *p = NULL; | ||
| 323 | if (value < num) | ||
| 324 | p = table[value]; | ||
| 325 | if (!p) | ||
| 326 | { | ||
| 327 | ConvertUInt32ToString(value, sz); | ||
| 328 | p = sz; | ||
| 329 | } | ||
| 330 | return (AString)p; | ||
| 331 | } | ||
| 332 | |||
| 333 | // #if defined(_7ZIP_LARGE_PAGES) || defined(_WIN32) | ||
| 334 | // #ifdef _WIN32 | ||
| 335 | void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v) | ||
| 336 | { | ||
| 337 | char c = 0; | ||
| 338 | if ((v & 0x3FF) == 0) { v >>= 10; c = 'K'; | ||
| 339 | if ((v & 0x3FF) == 0) { v >>= 10; c = 'M'; | ||
| 340 | if ((v & 0x3FF) == 0) { v >>= 10; c = 'G'; | ||
| 341 | if ((v & 0x3FF) == 0) { v >>= 10; c = 'T'; | ||
| 342 | }}}} | ||
| 343 | else | ||
| 344 | { | ||
| 345 | PrintHex(s, v); | ||
| 346 | return; | ||
| 347 | } | ||
| 348 | char temp[32]; | ||
| 349 | ConvertUInt64ToString(v, temp); | ||
| 350 | s += temp; | ||
| 351 | if (c) | ||
| 352 | s += c; | ||
| 353 | } | ||
| 354 | // #endif | ||
| 355 | // #endif | ||
| 356 | |||
| 357 | static void SysInfo_To_String(AString &s, const SYSTEM_INFO &si) | ||
| 358 | { | ||
| 359 | s += TypeToString2(k_PROCESSOR_ARCHITECTURE, ARRAY_SIZE(k_PROCESSOR_ARCHITECTURE), si.wProcessorArchitecture); | ||
| 360 | |||
| 361 | if (!( (si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_INTEL && si.dwProcessorType == MY__PROCESSOR_INTEL_PENTIUM) | ||
| 362 | || (si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_AMD64 && si.dwProcessorType == MY__PROCESSOR_AMD_X8664))) | ||
| 363 | { | ||
| 364 | s += " "; | ||
| 365 | // s += TypePairToString(k_PROCESSOR, ARRAY_SIZE(k_PROCESSOR), si.dwProcessorType); | ||
| 366 | s.Add_UInt32(si.dwProcessorType); | ||
| 367 | } | ||
| 368 | s += " "; | ||
| 369 | PrintHex(s, si.wProcessorLevel); | ||
| 370 | s += "."; | ||
| 371 | PrintHex(s, si.wProcessorRevision); | ||
| 372 | if ((UInt64)si.dwActiveProcessorMask + 1 != ((UInt64)1 << si.dwNumberOfProcessors)) | ||
| 373 | if ((UInt64)si.dwActiveProcessorMask + 1 != 0 || si.dwNumberOfProcessors != sizeof(UInt64) * 8) | ||
| 374 | { | ||
| 375 | s += " act:"; | ||
| 376 | PrintHex(s, si.dwActiveProcessorMask); | ||
| 377 | } | ||
| 378 | s += " cpus:"; | ||
| 379 | s.Add_UInt32(si.dwNumberOfProcessors); | ||
| 380 | if (si.dwPageSize != 1 << 12) | ||
| 381 | { | ||
| 382 | s += " page:"; | ||
| 383 | PrintPage(s, si.dwPageSize); | ||
| 384 | } | ||
| 385 | if (si.dwAllocationGranularity != 1 << 16) | ||
| 386 | { | ||
| 387 | s += " gran:"; | ||
| 388 | PrintPage(s, si.dwAllocationGranularity); | ||
| 389 | } | ||
| 390 | s += " "; | ||
| 391 | |||
| 392 | DWORD_PTR minAdd = (DWORD_PTR)si.lpMinimumApplicationAddress; | ||
| 393 | UInt64 maxSize = (UInt64)(DWORD_PTR)si.lpMaximumApplicationAddress + 1; | ||
| 394 | const UInt32 kReserveSize = ((UInt32)1 << 16); | ||
| 395 | if (minAdd != kReserveSize) | ||
| 396 | { | ||
| 397 | PrintSize_KMGT_Or_Hex(s, minAdd); | ||
| 398 | s += "-"; | ||
| 399 | } | ||
| 400 | else | ||
| 401 | { | ||
| 402 | if ((maxSize & (kReserveSize - 1)) == 0) | ||
| 403 | maxSize += kReserveSize; | ||
| 404 | } | ||
| 405 | PrintSize_KMGT_Or_Hex(s, maxSize); | ||
| 406 | } | ||
| 407 | |||
| 408 | #ifndef _WIN64 | ||
| 409 | EXTERN_C_BEGIN | ||
| 410 | typedef VOID (WINAPI *Func_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo); | ||
| 411 | EXTERN_C_END | ||
| 412 | #endif | ||
| 413 | |||
| 414 | #endif | ||
| 415 | |||
| 416 | #ifdef __APPLE__ | ||
| 417 | #ifndef MY_CPU_X86_OR_AMD64 | ||
| 418 | static void Add_sysctlbyname_to_String(const char *name, AString &s) | ||
| 419 | { | ||
| 420 | size_t bufSize = 256; | ||
| 421 | char buf[256]; | ||
| 422 | if (My_sysctlbyname_Get(name, &buf, &bufSize) == 0) | ||
| 423 | s += buf; | ||
| 424 | } | ||
| 425 | #endif | ||
| 426 | #endif | ||
| 427 | |||
| 428 | void GetSysInfo(AString &s1, AString &s2); | ||
| 429 | void GetSysInfo(AString &s1, AString &s2) | ||
| 430 | { | ||
| 431 | s1.Empty(); | ||
| 432 | s2.Empty(); | ||
| 433 | |||
| 434 | #ifdef _WIN32 | ||
| 435 | SYSTEM_INFO si; | ||
| 436 | GetSystemInfo(&si); | ||
| 437 | { | ||
| 438 | SysInfo_To_String(s1, si); | ||
| 439 | // s += " : "; | ||
| 440 | } | ||
| 441 | |||
| 442 | #if !defined(_WIN64) && !defined(UNDER_CE) | ||
| 443 | Func_GetNativeSystemInfo fn_GetNativeSystemInfo = (Func_GetNativeSystemInfo)(void *)GetProcAddress( | ||
| 444 | GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"); | ||
| 445 | if (fn_GetNativeSystemInfo) | ||
| 446 | { | ||
| 447 | SYSTEM_INFO si2; | ||
| 448 | fn_GetNativeSystemInfo(&si2); | ||
| 449 | // if (memcmp(&si, &si2, sizeof(si)) != 0) | ||
| 450 | { | ||
| 451 | // s += " - "; | ||
| 452 | SysInfo_To_String(s2, si2); | ||
| 453 | } | ||
| 454 | } | ||
| 455 | #endif | ||
| 456 | #endif | ||
| 457 | } | ||
| 458 | |||
| 459 | |||
| 460 | void GetCpuName(AString &s); | ||
| 461 | |||
| 462 | static void AddBracedString(AString &dest, AString &src) | ||
| 463 | { | ||
| 464 | if (!src.IsEmpty()) | ||
| 465 | { | ||
| 466 | AString s; | ||
| 467 | s += '('; | ||
| 468 | s += src; | ||
| 469 | s += ')'; | ||
| 470 | dest.Add_OptSpaced(s); | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | struct CCpuName | ||
| 475 | { | ||
| 476 | AString CpuName; | ||
| 477 | AString Revision; | ||
| 478 | AString Microcode; | ||
| 479 | AString LargePages; | ||
| 480 | |||
| 481 | void Fill(); | ||
| 482 | |||
| 483 | void Get_Revision_Microcode_LargePages(AString &s) | ||
| 484 | { | ||
| 485 | s.Empty(); | ||
| 486 | AddBracedString(s, Revision); | ||
| 487 | AddBracedString(s, Microcode); | ||
| 488 | s.Add_OptSpaced(LargePages); | ||
| 489 | } | ||
| 490 | }; | ||
| 491 | |||
| 492 | void CCpuName::Fill() | ||
| 493 | { | ||
| 494 | CpuName.Empty(); | ||
| 495 | Revision.Empty(); | ||
| 496 | Microcode.Empty(); | ||
| 497 | LargePages.Empty(); | ||
| 498 | |||
| 499 | AString &s = CpuName; | ||
| 500 | |||
| 501 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 502 | { | ||
| 503 | Cx86cpuid cpuid; | ||
| 504 | if (x86cpuid_CheckAndRead(&cpuid)) | ||
| 505 | { | ||
| 506 | x86cpuid_to_String(cpuid, s, Revision); | ||
| 507 | } | ||
| 508 | else | ||
| 509 | { | ||
| 510 | #ifdef MY_CPU_AMD64 | ||
| 511 | s += "x64"; | ||
| 512 | #else | ||
| 513 | s += "x86"; | ||
| 514 | #endif | ||
| 515 | } | ||
| 516 | } | ||
| 517 | #elif defined(__APPLE__) | ||
| 518 | { | ||
| 519 | Add_sysctlbyname_to_String("machdep.cpu.brand_string", s); | ||
| 520 | } | ||
| 521 | #endif | ||
| 522 | |||
| 523 | |||
| 524 | if (s.IsEmpty()) | ||
| 525 | { | ||
| 526 | #ifdef MY_CPU_LE | ||
| 527 | s += "LE"; | ||
| 528 | #elif defined(MY_CPU_BE) | ||
| 529 | s += "BE"; | ||
| 530 | #endif | ||
| 531 | } | ||
| 532 | |||
| 533 | #ifdef __APPLE__ | ||
| 534 | { | ||
| 535 | AString s2; | ||
| 536 | UInt32 v = 0; | ||
| 537 | if (My_sysctlbyname_Get_UInt32("machdep.cpu.core_count", &v) == 0) | ||
| 538 | { | ||
| 539 | s2.Add_UInt32(v); | ||
| 540 | s2 += 'C'; | ||
| 541 | } | ||
| 542 | if (My_sysctlbyname_Get_UInt32("machdep.cpu.thread_count", &v) == 0) | ||
| 543 | { | ||
| 544 | s2.Add_UInt32(v); | ||
| 545 | s2 += 'T'; | ||
| 546 | } | ||
| 547 | if (!s2.IsEmpty()) | ||
| 548 | { | ||
| 549 | s.Add_Space_if_NotEmpty(); | ||
| 550 | s += s2; | ||
| 551 | } | ||
| 552 | } | ||
| 553 | #endif | ||
| 554 | |||
| 555 | |||
| 556 | #ifdef _WIN32 | ||
| 557 | { | ||
| 558 | NRegistry::CKey key; | ||
| 559 | if (key.Open(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS) | ||
| 560 | { | ||
| 561 | LONG res[2]; | ||
| 562 | CByteBuffer bufs[2]; | ||
| 563 | { | ||
| 564 | for (int i = 0; i < 2; i++) | ||
| 565 | { | ||
| 566 | UInt32 size = 0; | ||
| 567 | res[i] = key.QueryValue(i == 0 ? | ||
| 568 | TEXT("Previous Update Revision") : | ||
| 569 | TEXT("Update Revision"), bufs[i], size); | ||
| 570 | if (res[i] == ERROR_SUCCESS) | ||
| 571 | if (size != bufs[i].Size()) | ||
| 572 | res[i] = ERROR_SUCCESS + 1; | ||
| 573 | } | ||
| 574 | } | ||
| 575 | if (res[0] == ERROR_SUCCESS || res[1] == ERROR_SUCCESS) | ||
| 576 | { | ||
| 577 | for (int i = 0; i < 2; i++) | ||
| 578 | { | ||
| 579 | if (i == 1) | ||
| 580 | Microcode += "->"; | ||
| 581 | if (res[i] != ERROR_SUCCESS) | ||
| 582 | continue; | ||
| 583 | const CByteBuffer &buf = bufs[i]; | ||
| 584 | if (buf.Size() == 8) | ||
| 585 | { | ||
| 586 | UInt32 high = GetUi32(buf); | ||
| 587 | if (high != 0) | ||
| 588 | { | ||
| 589 | PrintHex(Microcode, high); | ||
| 590 | Microcode += "."; | ||
| 591 | } | ||
| 592 | PrintHex(Microcode, GetUi32(buf + 4)); | ||
| 593 | } | ||
| 594 | } | ||
| 595 | } | ||
| 596 | } | ||
| 597 | } | ||
| 598 | #endif | ||
| 599 | |||
| 600 | |||
| 601 | #ifdef _7ZIP_LARGE_PAGES | ||
| 602 | Add_LargePages_String(LargePages); | ||
| 603 | #endif | ||
| 604 | } | ||
| 605 | |||
| 606 | void AddCpuFeatures(AString &s); | ||
| 607 | void AddCpuFeatures(AString &s) | ||
| 608 | { | ||
| 609 | #ifdef _WIN32 | ||
| 610 | // const unsigned kNumFeatures_Extra = 32; // we check also for unknown features | ||
| 611 | // const unsigned kNumFeatures = ARRAY_SIZE(k_PF) + kNumFeatures_Extra; | ||
| 612 | const unsigned kNumFeatures = 64; | ||
| 613 | UInt64 flags = 0; | ||
| 614 | for (unsigned i = 0; i < kNumFeatures; i++) | ||
| 615 | { | ||
| 616 | if (IsProcessorFeaturePresent(i)) | ||
| 617 | { | ||
| 618 | flags += (UInt64)1 << i; | ||
| 619 | // s.Add_Space_if_NotEmpty(); | ||
| 620 | // s += TypeToString2(k_PF, ARRAY_SIZE(k_PF), i); | ||
| 621 | } | ||
| 622 | } | ||
| 623 | s.Add_OptSpaced("f:"); | ||
| 624 | PrintHex(s, flags); | ||
| 625 | |||
| 626 | #elif defined(__APPLE__) | ||
| 627 | { | ||
| 628 | UInt32 v = 0; | ||
| 629 | if (My_sysctlbyname_Get_UInt32("hw.pagesize", &v) == 0) | ||
| 630 | { | ||
| 631 | s += "PageSize:"; | ||
| 632 | s.Add_UInt32(v >> 10); | ||
| 633 | s += "KB"; | ||
| 634 | } | ||
| 635 | } | ||
| 636 | |||
| 637 | #else | ||
| 638 | |||
| 639 | const long v = sysconf(_SC_PAGESIZE); | ||
| 640 | if (v != -1) | ||
| 641 | { | ||
| 642 | s.Add_Space_if_NotEmpty(); | ||
| 643 | s += "PageSize:"; | ||
| 644 | s.Add_UInt32((UInt32)(v >> 10)); | ||
| 645 | s += "KB"; | ||
| 646 | } | ||
| 647 | |||
| 648 | #if !defined(_AIX) | ||
| 649 | |||
| 650 | #ifdef __linux__ | ||
| 651 | |||
| 652 | CByteBuffer buf; | ||
| 653 | if (ReadFile_to_Buffer("/sys/kernel/mm/transparent_hugepage/enabled", buf)) | ||
| 654 | // if (ReadFile_to_Buffer("/proc/cpuinfo", buf)) | ||
| 655 | { | ||
| 656 | s.Add_OptSpaced("THP:"); | ||
| 657 | AString s2; | ||
| 658 | s2.SetFrom_CalcLen((const char *)(const void *)(const Byte *)buf, (unsigned)buf.Size()); | ||
| 659 | const int pos = s2.Find('['); | ||
| 660 | if (pos >= 0) | ||
| 661 | { | ||
| 662 | const int pos2 = s2.Find(']', pos + 1); | ||
| 663 | if (pos2 >= 0) | ||
| 664 | { | ||
| 665 | s2.DeleteFrom(pos2); | ||
| 666 | s2.DeleteFrontal(pos + 1); | ||
| 667 | } | ||
| 668 | } | ||
| 669 | s += s2; | ||
| 670 | } | ||
| 671 | // else throw CSystemException(MY_SRes_HRESULT_FROM_WRes(errno)); | ||
| 672 | |||
| 673 | #endif | ||
| 674 | |||
| 675 | |||
| 676 | #ifdef AT_HWCAP | ||
| 677 | s.Add_OptSpaced("hwcap:"); | ||
| 678 | { | ||
| 679 | unsigned long h = getauxval(AT_HWCAP); | ||
| 680 | PrintHex(s, h); | ||
| 681 | #ifdef MY_CPU_ARM64 | ||
| 682 | if (h & HWCAP_CRC32) s += ":CRC32"; | ||
| 683 | if (h & HWCAP_SHA1) s += ":SHA1"; | ||
| 684 | if (h & HWCAP_SHA2) s += ":SHA2"; | ||
| 685 | if (h & HWCAP_AES) s += ":AES"; | ||
| 686 | if (h & HWCAP_ASIMD) s += ":ASIMD"; | ||
| 687 | #elif defined(MY_CPU_ARM) | ||
| 688 | if (h & HWCAP_NEON) s += ":NEON"; | ||
| 689 | #endif | ||
| 690 | } | ||
| 691 | #endif // AT_HWCAP | ||
| 692 | |||
| 693 | #ifdef AT_HWCAP2 | ||
| 694 | { | ||
| 695 | unsigned long h = getauxval(AT_HWCAP2); | ||
| 696 | #ifndef MY_CPU_ARM | ||
| 697 | if (h != 0) | ||
| 698 | #endif | ||
| 699 | { | ||
| 700 | s += " hwcap2:"; | ||
| 701 | PrintHex(s, h); | ||
| 702 | #ifdef MY_CPU_ARM | ||
| 703 | if (h & HWCAP2_CRC32) s += ":CRC32"; | ||
| 704 | if (h & HWCAP2_SHA1) s += ":SHA1"; | ||
| 705 | if (h & HWCAP2_SHA2) s += ":SHA2"; | ||
| 706 | if (h & HWCAP2_AES) s += ":AES"; | ||
| 707 | #endif | ||
| 708 | } | ||
| 709 | } | ||
| 710 | #endif // AT_HWCAP2 | ||
| 711 | #endif // _AIX | ||
| 712 | #endif // _WIN32 | ||
| 713 | } | ||
| 714 | |||
| 715 | |||
| 716 | #ifdef _WIN32 | ||
| 717 | #ifndef UNDER_CE | ||
| 718 | |||
| 719 | EXTERN_C_BEGIN | ||
| 720 | typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *); | ||
| 721 | EXTERN_C_END | ||
| 722 | |||
| 723 | static BOOL My_RtlGetVersion(OSVERSIONINFOEXW *vi) | ||
| 724 | { | ||
| 725 | HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); | ||
| 726 | if (!ntdll) | ||
| 727 | return FALSE; | ||
| 728 | Func_RtlGetVersion func = (Func_RtlGetVersion)(void *)GetProcAddress(ntdll, "RtlGetVersion"); | ||
| 729 | if (!func) | ||
| 730 | return FALSE; | ||
| 731 | func(vi); | ||
| 732 | return TRUE; | ||
| 733 | } | ||
| 734 | |||
| 735 | #endif | ||
| 736 | #endif | ||
| 737 | |||
| 738 | |||
| 739 | void GetOsInfoText(AString &sRes) | ||
| 740 | { | ||
| 741 | sRes.Empty(); | ||
| 742 | AString s; | ||
| 743 | |||
| 744 | #ifdef _WIN32 | ||
| 745 | #ifndef UNDER_CE | ||
| 746 | // OSVERSIONINFO vi; | ||
| 747 | OSVERSIONINFOEXW vi; | ||
| 748 | vi.dwOSVersionInfoSize = sizeof(vi); | ||
| 749 | // if (::GetVersionEx(&vi)) | ||
| 750 | if (My_RtlGetVersion(&vi)) | ||
| 751 | { | ||
| 752 | s += "Windows"; | ||
| 753 | if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) | ||
| 754 | s.Add_UInt32(vi.dwPlatformId); | ||
| 755 | s += " "; s.Add_UInt32(vi.dwMajorVersion); | ||
| 756 | s += "."; s.Add_UInt32(vi.dwMinorVersion); | ||
| 757 | s += " "; s.Add_UInt32(vi.dwBuildNumber); | ||
| 758 | |||
| 759 | if (vi.wServicePackMajor != 0 || vi.wServicePackMinor != 0) | ||
| 760 | { | ||
| 761 | s += " SP:"; s.Add_UInt32(vi.wServicePackMajor); | ||
| 762 | s += "."; s.Add_UInt32(vi.wServicePackMinor); | ||
| 763 | } | ||
| 764 | // s += " Suite:"; PrintHex(s, vi.wSuiteMask); | ||
| 765 | // s += " Type:"; s.Add_UInt32(vi.wProductType); | ||
| 766 | // s += " "; s += GetOemString(vi.szCSDVersion); | ||
| 767 | } | ||
| 768 | /* | ||
| 769 | { | ||
| 770 | s += " OEMCP:"; s.Add_UInt32(GetOEMCP()); | ||
| 771 | s += " ACP:"; s.Add_UInt32(GetACP()); | ||
| 772 | } | ||
| 773 | */ | ||
| 774 | #endif | ||
| 775 | #else // _WIN32 | ||
| 776 | |||
| 777 | if (!s.IsEmpty()) | ||
| 778 | s.Add_LF(); | ||
| 779 | struct utsname un; | ||
| 780 | if (uname(&un) == 0) | ||
| 781 | { | ||
| 782 | s += un.sysname; | ||
| 783 | // s += " : "; s += un.nodename; // we don't want to show name of computer | ||
| 784 | s += " : "; s += un.release; | ||
| 785 | s += " : "; s += un.version; | ||
| 786 | s += " : "; s += un.machine; | ||
| 787 | |||
| 788 | #ifdef __APPLE__ | ||
| 789 | // Add_sysctlbyname_to_String("kern.version", s); | ||
| 790 | // it's same as "utsname.version" | ||
| 791 | #endif | ||
| 792 | } | ||
| 793 | #endif // _WIN32 | ||
| 794 | |||
| 795 | sRes += s; | ||
| 796 | } | ||
| 797 | |||
| 798 | |||
| 799 | |||
| 800 | void GetSystemInfoText(AString &sRes) | ||
| 801 | { | ||
| 802 | GetOsInfoText(sRes); | ||
| 803 | sRes.Add_LF(); | ||
| 804 | |||
| 805 | { | ||
| 806 | AString s, s1, s2; | ||
| 807 | GetSysInfo(s1, s2); | ||
| 808 | if (!s1.IsEmpty() || !s2.IsEmpty()) | ||
| 809 | { | ||
| 810 | s = s1; | ||
| 811 | if (s1 != s2 && !s2.IsEmpty()) | ||
| 812 | { | ||
| 813 | s += " - "; | ||
| 814 | s += s2; | ||
| 815 | } | ||
| 816 | } | ||
| 817 | { | ||
| 818 | AddCpuFeatures(s); | ||
| 819 | if (!s.IsEmpty()) | ||
| 820 | { | ||
| 821 | sRes += s; | ||
| 822 | sRes.Add_LF(); | ||
| 823 | } | ||
| 824 | } | ||
| 825 | } | ||
| 826 | { | ||
| 827 | AString s; | ||
| 828 | GetCpuName(s); | ||
| 829 | if (!s.IsEmpty()) | ||
| 830 | { | ||
| 831 | sRes += s; | ||
| 832 | sRes.Add_LF(); | ||
| 833 | } | ||
| 834 | } | ||
| 835 | /* | ||
| 836 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 837 | { | ||
| 838 | AString s; | ||
| 839 | x86cpuid_all_to_String(s); | ||
| 840 | if (!s.IsEmpty()) | ||
| 841 | { | ||
| 842 | printCallback->Print(s); | ||
| 843 | printCallback->NewLine(); | ||
| 844 | } | ||
| 845 | } | ||
| 846 | #endif | ||
| 847 | */ | ||
| 848 | } | ||
| 849 | |||
| 850 | |||
| 851 | void GetCpuName(AString &s); | ||
| 852 | void GetCpuName(AString &s) | ||
| 853 | { | ||
| 854 | CCpuName cpuName; | ||
| 855 | cpuName.Fill(); | ||
| 856 | s = cpuName.CpuName; | ||
| 857 | AString s2; | ||
| 858 | cpuName.Get_Revision_Microcode_LargePages(s2); | ||
| 859 | s.Add_OptSpaced(s2); | ||
| 860 | } | ||
| 861 | |||
| 862 | |||
| 863 | void GetCpuName_MultiLine(AString &s); | ||
| 864 | void GetCpuName_MultiLine(AString &s) | ||
| 865 | { | ||
| 866 | CCpuName cpuName; | ||
| 867 | cpuName.Fill(); | ||
| 868 | s = cpuName.CpuName; | ||
| 869 | AString s2; | ||
| 870 | cpuName.Get_Revision_Microcode_LargePages(s2); | ||
| 871 | if (!s2.IsEmpty()) | ||
| 872 | { | ||
| 873 | s.Add_LF(); | ||
| 874 | s += s2; | ||
| 875 | } | ||
| 876 | } | ||
| 877 | |||
| 878 | void GetCompiler(AString &s) | ||
| 879 | { | ||
| 880 | #ifdef __VERSION__ | ||
| 881 | s += __VERSION__; | ||
| 882 | #endif | ||
| 883 | |||
| 884 | #ifdef __GNUC__ | ||
| 885 | s += " GCC "; | ||
| 886 | s.Add_UInt32(__GNUC__); | ||
| 887 | s += '.'; | ||
| 888 | s.Add_UInt32(__GNUC_MINOR__); | ||
| 889 | s += '.'; | ||
| 890 | s.Add_UInt32(__GNUC_PATCHLEVEL__); | ||
| 891 | #endif | ||
| 892 | |||
| 893 | #ifdef __clang__ | ||
| 894 | s += " CLANG "; | ||
| 895 | s.Add_UInt32(__clang_major__); | ||
| 896 | s += '.'; | ||
| 897 | s.Add_UInt32(__clang_minor__); | ||
| 898 | #endif | ||
| 899 | |||
| 900 | #ifdef __xlC__ | ||
| 901 | s += " XLC "; | ||
| 902 | s.Add_UInt32(__xlC__ >> 8); | ||
| 903 | s += '.'; | ||
| 904 | s.Add_UInt32(__xlC__ & 0xFF); | ||
| 905 | #ifdef __xlC_ver__ | ||
| 906 | s += '.'; | ||
| 907 | s.Add_UInt32(__xlC_ver__ >> 8); | ||
| 908 | s += '.'; | ||
| 909 | s.Add_UInt32(__xlC_ver__ & 0xFF); | ||
| 910 | #endif | ||
| 911 | #endif | ||
| 912 | |||
| 913 | #ifdef _MSC_VER | ||
| 914 | s += " MSC "; | ||
| 915 | s.Add_UInt32(_MSC_VER); | ||
| 916 | #endif | ||
| 917 | } | ||
diff --git a/CPP/Windows/SystemInfo.h b/CPP/Windows/SystemInfo.h new file mode 100644 index 0000000..e941d0a --- /dev/null +++ b/CPP/Windows/SystemInfo.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | // Windows/SystemInfo.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_SYSTEM_INFO_H | ||
| 4 | #define __WINDOWS_SYSTEM_INFO_H | ||
| 5 | |||
| 6 | #include "../Common/MyString.h" | ||
| 7 | |||
| 8 | |||
| 9 | void GetCpuName_MultiLine(AString &s); | ||
| 10 | |||
| 11 | void GetOsInfoText(AString &sRes); | ||
| 12 | void GetSystemInfoText(AString &s); | ||
| 13 | void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v); | ||
| 14 | void Add_LargePages_String(AString &s); | ||
| 15 | |||
| 16 | void GetCompiler(AString &s); | ||
| 17 | |||
| 18 | #endif | ||
diff --git a/CPP/Windows/Thread.h b/CPP/Windows/Thread.h new file mode 100644 index 0000000..5fca173 --- /dev/null +++ b/CPP/Windows/Thread.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | // Windows/Thread.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_THREAD_H | ||
| 4 | #define __WINDOWS_THREAD_H | ||
| 5 | |||
| 6 | #include "../../C/Threads.h" | ||
| 7 | |||
| 8 | #include "Defs.h" | ||
| 9 | |||
| 10 | namespace NWindows { | ||
| 11 | |||
| 12 | class CThread MY_UNCOPYABLE | ||
| 13 | { | ||
| 14 | ::CThread thread; | ||
| 15 | public: | ||
| 16 | CThread() { Thread_Construct(&thread); } | ||
| 17 | ~CThread() { Close(); } | ||
| 18 | bool IsCreated() { return Thread_WasCreated(&thread) != 0; } | ||
| 19 | WRes Close() { return Thread_Close(&thread); } | ||
| 20 | // WRes Wait() { return Thread_Wait(&thread); } | ||
| 21 | WRes Wait_Close() { return Thread_Wait_Close(&thread); } | ||
| 22 | |||
| 23 | WRes Create(THREAD_FUNC_TYPE startAddress, LPVOID param) | ||
| 24 | { return Thread_Create(&thread, startAddress, param); } | ||
| 25 | WRes Create_With_Affinity(THREAD_FUNC_TYPE startAddress, LPVOID param, CAffinityMask affinity) | ||
| 26 | { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); } | ||
| 27 | WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet) | ||
| 28 | { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); } | ||
| 29 | |||
| 30 | #ifdef _WIN32 | ||
| 31 | operator HANDLE() { return thread; } | ||
| 32 | void Attach(HANDLE handle) { thread = handle; } | ||
| 33 | HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } | ||
| 34 | DWORD Resume() { return ::ResumeThread(thread); } | ||
| 35 | DWORD Suspend() { return ::SuspendThread(thread); } | ||
| 36 | bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } | ||
| 37 | int GetPriority() { return ::GetThreadPriority(thread); } | ||
| 38 | bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } | ||
| 39 | #endif | ||
| 40 | }; | ||
| 41 | |||
| 42 | } | ||
| 43 | |||
| 44 | #endif | ||
diff --git a/CPP/Windows/TimeUtils.cpp b/CPP/Windows/TimeUtils.cpp new file mode 100644 index 0000000..1f1335f --- /dev/null +++ b/CPP/Windows/TimeUtils.cpp | |||
| @@ -0,0 +1,234 @@ | |||
| 1 | // Windows/TimeUtils.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef _WIN32 | ||
| 6 | #include <sys/time.h> | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #include "Defs.h" | ||
| 10 | #include "TimeUtils.h" | ||
| 11 | |||
| 12 | namespace NWindows { | ||
| 13 | namespace NTime { | ||
| 14 | |||
| 15 | static const UInt32 kNumTimeQuantumsInSecond = 10000000; | ||
| 16 | static const UInt32 kFileTimeStartYear = 1601; | ||
| 17 | #if !defined(_WIN32) || defined(UNDER_CE) | ||
| 18 | static const UInt32 kDosTimeStartYear = 1980; | ||
| 19 | #endif | ||
| 20 | static const UInt32 kUnixTimeStartYear = 1970; | ||
| 21 | static const UInt64 kUnixTimeOffset = | ||
| 22 | (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); | ||
| 23 | static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond; | ||
| 24 | |||
| 25 | bool DosTimeToFileTime(UInt32 dosTime, FILETIME &ft) throw() | ||
| 26 | { | ||
| 27 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 28 | return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft)); | ||
| 29 | #else | ||
| 30 | ft.dwLowDateTime = 0; | ||
| 31 | ft.dwHighDateTime = 0; | ||
| 32 | UInt64 res; | ||
| 33 | if (!GetSecondsSince1601(kDosTimeStartYear + (dosTime >> 25), (dosTime >> 21) & 0xF, (dosTime >> 16) & 0x1F, | ||
| 34 | (dosTime >> 11) & 0x1F, (dosTime >> 5) & 0x3F, (dosTime & 0x1F) * 2, res)) | ||
| 35 | return false; | ||
| 36 | res *= kNumTimeQuantumsInSecond; | ||
| 37 | ft.dwLowDateTime = (UInt32)res; | ||
| 38 | ft.dwHighDateTime = (UInt32)(res >> 32); | ||
| 39 | return true; | ||
| 40 | #endif | ||
| 41 | } | ||
| 42 | |||
| 43 | static const UInt32 kHighDosTime = 0xFF9FBF7D; | ||
| 44 | static const UInt32 kLowDosTime = 0x210000; | ||
| 45 | |||
| 46 | bool FileTimeToDosTime(const FILETIME &ft, UInt32 &dosTime) throw() | ||
| 47 | { | ||
| 48 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 49 | |||
| 50 | WORD datePart, timePart; | ||
| 51 | if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart)) | ||
| 52 | { | ||
| 53 | dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime; | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | dosTime = (((UInt32)datePart) << 16) + timePart; | ||
| 57 | |||
| 58 | #else | ||
| 59 | |||
| 60 | #define PERIOD_4 (4 * 365 + 1) | ||
| 61 | #define PERIOD_100 (PERIOD_4 * 25 - 1) | ||
| 62 | #define PERIOD_400 (PERIOD_100 * 4 + 1) | ||
| 63 | |||
| 64 | unsigned year, mon, day, hour, min, sec; | ||
| 65 | UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32); | ||
| 66 | Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | ||
| 67 | unsigned temp; | ||
| 68 | UInt32 v; | ||
| 69 | v64 += (kNumTimeQuantumsInSecond * 2 - 1); | ||
| 70 | v64 /= kNumTimeQuantumsInSecond; | ||
| 71 | sec = (unsigned)(v64 % 60); | ||
| 72 | v64 /= 60; | ||
| 73 | min = (unsigned)(v64 % 60); | ||
| 74 | v64 /= 60; | ||
| 75 | hour = (unsigned)(v64 % 24); | ||
| 76 | v64 /= 24; | ||
| 77 | |||
| 78 | v = (UInt32)v64; | ||
| 79 | |||
| 80 | year = (unsigned)(kFileTimeStartYear + v / PERIOD_400 * 400); | ||
| 81 | v %= PERIOD_400; | ||
| 82 | |||
| 83 | temp = (unsigned)(v / PERIOD_100); | ||
| 84 | if (temp == 4) | ||
| 85 | temp = 3; | ||
| 86 | year += temp * 100; | ||
| 87 | v -= temp * PERIOD_100; | ||
| 88 | |||
| 89 | temp = v / PERIOD_4; | ||
| 90 | if (temp == 25) | ||
| 91 | temp = 24; | ||
| 92 | year += temp * 4; | ||
| 93 | v -= temp * PERIOD_4; | ||
| 94 | |||
| 95 | temp = v / 365; | ||
| 96 | if (temp == 4) | ||
| 97 | temp = 3; | ||
| 98 | year += temp; | ||
| 99 | v -= temp * 365; | ||
| 100 | |||
| 101 | if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) | ||
| 102 | ms[1] = 29; | ||
| 103 | for (mon = 1; mon <= 12; mon++) | ||
| 104 | { | ||
| 105 | unsigned s = ms[mon - 1]; | ||
| 106 | if (v < s) | ||
| 107 | break; | ||
| 108 | v -= s; | ||
| 109 | } | ||
| 110 | day = (unsigned)v + 1; | ||
| 111 | |||
| 112 | dosTime = kLowDosTime; | ||
| 113 | if (year < kDosTimeStartYear) | ||
| 114 | return false; | ||
| 115 | year -= kDosTimeStartYear; | ||
| 116 | dosTime = kHighDosTime; | ||
| 117 | if (year >= 128) | ||
| 118 | return false; | ||
| 119 | dosTime = (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec >> 1); | ||
| 120 | #endif | ||
| 121 | return true; | ||
| 122 | } | ||
| 123 | |||
| 124 | UInt64 UnixTimeToFileTime64(UInt32 unixTime) throw() | ||
| 125 | { | ||
| 126 | return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond; | ||
| 127 | } | ||
| 128 | |||
| 129 | void UnixTimeToFileTime(UInt32 unixTime, FILETIME &ft) throw() | ||
| 130 | { | ||
| 131 | UInt64 v = UnixTimeToFileTime64(unixTime); | ||
| 132 | ft.dwLowDateTime = (DWORD)v; | ||
| 133 | ft.dwHighDateTime = (DWORD)(v >> 32); | ||
| 134 | } | ||
| 135 | |||
| 136 | UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw() | ||
| 137 | { | ||
| 138 | return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond; | ||
| 139 | } | ||
| 140 | |||
| 141 | bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &ft) throw() | ||
| 142 | { | ||
| 143 | if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset)) | ||
| 144 | { | ||
| 145 | ft.dwLowDateTime = ft.dwHighDateTime = (UInt32)(Int32)-1; | ||
| 146 | return false; | ||
| 147 | } | ||
| 148 | Int64 v = (Int64)kUnixTimeOffset + unixTime; | ||
| 149 | if (v < 0) | ||
| 150 | { | ||
| 151 | ft.dwLowDateTime = ft.dwHighDateTime = 0; | ||
| 152 | return false; | ||
| 153 | } | ||
| 154 | UInt64 v2 = (UInt64)v * kNumTimeQuantumsInSecond; | ||
| 155 | ft.dwLowDateTime = (DWORD)v2; | ||
| 156 | ft.dwHighDateTime = (DWORD)(v2 >> 32); | ||
| 157 | return true; | ||
| 158 | } | ||
| 159 | |||
| 160 | Int64 FileTimeToUnixTime64(const FILETIME &ft) throw() | ||
| 161 | { | ||
| 162 | UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; | ||
| 163 | return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; | ||
| 164 | } | ||
| 165 | |||
| 166 | bool FileTimeToUnixTime(const FILETIME &ft, UInt32 &unixTime) throw() | ||
| 167 | { | ||
| 168 | UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; | ||
| 169 | winTime /= kNumTimeQuantumsInSecond; | ||
| 170 | if (winTime < kUnixTimeOffset) | ||
| 171 | { | ||
| 172 | unixTime = 0; | ||
| 173 | return false; | ||
| 174 | } | ||
| 175 | winTime -= kUnixTimeOffset; | ||
| 176 | if (winTime > 0xFFFFFFFF) | ||
| 177 | { | ||
| 178 | unixTime = 0xFFFFFFFF; | ||
| 179 | return false; | ||
| 180 | } | ||
| 181 | unixTime = (UInt32)winTime; | ||
| 182 | return true; | ||
| 183 | } | ||
| 184 | |||
| 185 | bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, | ||
| 186 | unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw() | ||
| 187 | { | ||
| 188 | resSeconds = 0; | ||
| 189 | if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 || | ||
| 190 | day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59) | ||
| 191 | return false; | ||
| 192 | UInt32 numYears = year - kFileTimeStartYear; | ||
| 193 | UInt32 numDays = numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400; | ||
| 194 | Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | ||
| 195 | if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) | ||
| 196 | ms[1] = 29; | ||
| 197 | month--; | ||
| 198 | for (unsigned i = 0; i < month; i++) | ||
| 199 | numDays += ms[i]; | ||
| 200 | numDays += day - 1; | ||
| 201 | resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec; | ||
| 202 | return true; | ||
| 203 | } | ||
| 204 | |||
| 205 | void GetCurUtcFileTime(FILETIME &ft) throw() | ||
| 206 | { | ||
| 207 | // Both variants provide same low resolution on WinXP: about 15 ms. | ||
| 208 | // But GetSystemTimeAsFileTime is much faster. | ||
| 209 | #ifdef _WIN32 | ||
| 210 | |||
| 211 | #ifdef UNDER_CE | ||
| 212 | SYSTEMTIME st; | ||
| 213 | GetSystemTime(&st); | ||
| 214 | SystemTimeToFileTime(&st, &ft); | ||
| 215 | #else | ||
| 216 | GetSystemTimeAsFileTime(&ft); | ||
| 217 | #endif | ||
| 218 | |||
| 219 | #else | ||
| 220 | |||
| 221 | UInt64 v = 0; | ||
| 222 | struct timeval now; | ||
| 223 | if (gettimeofday(&now, 0 ) == 0) | ||
| 224 | { | ||
| 225 | v = ((UInt64)now.tv_sec + kUnixTimeOffset) * | ||
| 226 | kNumTimeQuantumsInSecond + (UInt64)now.tv_usec * 10; | ||
| 227 | } | ||
| 228 | ft.dwLowDateTime = (DWORD)v; | ||
| 229 | ft.dwHighDateTime = (DWORD)(v >> 32); | ||
| 230 | |||
| 231 | #endif | ||
| 232 | } | ||
| 233 | |||
| 234 | }} | ||
diff --git a/CPP/Windows/TimeUtils.h b/CPP/Windows/TimeUtils.h new file mode 100644 index 0000000..d1d8c15 --- /dev/null +++ b/CPP/Windows/TimeUtils.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // Windows/TimeUtils.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_TIME_UTILS_H | ||
| 4 | #define __WINDOWS_TIME_UTILS_H | ||
| 5 | |||
| 6 | #include "../Common/MyTypes.h" | ||
| 7 | #include "../Common/MyWindows.h" | ||
| 8 | |||
| 9 | namespace NWindows { | ||
| 10 | namespace NTime { | ||
| 11 | |||
| 12 | bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime) throw(); | ||
| 13 | bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime) throw(); | ||
| 14 | |||
| 15 | // UInt32 Unix Time : for dates 1970-2106 | ||
| 16 | UInt64 UnixTimeToFileTime64(UInt32 unixTime) throw(); | ||
| 17 | void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime) throw(); | ||
| 18 | |||
| 19 | // Int64 Unix Time : negative values for dates before 1970 | ||
| 20 | UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw(); | ||
| 21 | bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &fileTime) throw(); | ||
| 22 | |||
| 23 | bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw(); | ||
| 24 | Int64 FileTimeToUnixTime64(const FILETIME &ft) throw(); | ||
| 25 | |||
| 26 | bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, | ||
| 27 | unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw(); | ||
| 28 | void GetCurUtcFileTime(FILETIME &ft) throw(); | ||
| 29 | |||
| 30 | }} | ||
| 31 | |||
| 32 | #endif | ||
diff --git a/CPP/Windows/Window.cpp b/CPP/Windows/Window.cpp new file mode 100644 index 0000000..32af4aa --- /dev/null +++ b/CPP/Windows/Window.cpp | |||
| @@ -0,0 +1,179 @@ | |||
| 1 | // Windows/Window.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #ifndef _UNICODE | ||
| 6 | #include "../Common/StringConvert.h" | ||
| 7 | #endif | ||
| 8 | #include "Window.h" | ||
| 9 | |||
| 10 | #ifndef _UNICODE | ||
| 11 | extern bool g_IsNT; | ||
| 12 | #endif | ||
| 13 | |||
| 14 | namespace NWindows { | ||
| 15 | |||
| 16 | #ifndef _UNICODE | ||
| 17 | ATOM MyRegisterClass(CONST WNDCLASSW *wndClass) | ||
| 18 | { | ||
| 19 | if (g_IsNT) | ||
| 20 | return RegisterClassW(wndClass); | ||
| 21 | WNDCLASSA wndClassA; | ||
| 22 | wndClassA.style = wndClass->style; | ||
| 23 | wndClassA.lpfnWndProc = wndClass->lpfnWndProc; | ||
| 24 | wndClassA.cbClsExtra = wndClass->cbClsExtra; | ||
| 25 | wndClassA.cbWndExtra = wndClass->cbWndExtra; | ||
| 26 | wndClassA.hInstance = wndClass->hInstance; | ||
| 27 | wndClassA.hIcon = wndClass->hIcon; | ||
| 28 | wndClassA.hCursor = wndClass->hCursor; | ||
| 29 | wndClassA.hbrBackground = wndClass->hbrBackground; | ||
| 30 | AString menuName; | ||
| 31 | AString className; | ||
| 32 | if (IS_INTRESOURCE(wndClass->lpszMenuName)) | ||
| 33 | wndClassA.lpszMenuName = (LPCSTR)wndClass->lpszMenuName; | ||
| 34 | else | ||
| 35 | { | ||
| 36 | menuName = GetSystemString(wndClass->lpszMenuName); | ||
| 37 | wndClassA.lpszMenuName = menuName; | ||
| 38 | } | ||
| 39 | if (IS_INTRESOURCE(wndClass->lpszClassName)) | ||
| 40 | wndClassA.lpszClassName = (LPCSTR)wndClass->lpszClassName; | ||
| 41 | else | ||
| 42 | { | ||
| 43 | className = GetSystemString(wndClass->lpszClassName); | ||
| 44 | wndClassA.lpszClassName = className; | ||
| 45 | } | ||
| 46 | return RegisterClassA(&wndClassA); | ||
| 47 | } | ||
| 48 | |||
| 49 | bool CWindow::Create(LPCWSTR className, | ||
| 50 | LPCWSTR windowName, DWORD style, | ||
| 51 | int x, int y, int width, int height, | ||
| 52 | HWND parentWindow, HMENU idOrHMenu, | ||
| 53 | HINSTANCE instance, LPVOID createParam) | ||
| 54 | { | ||
| 55 | if (g_IsNT) | ||
| 56 | { | ||
| 57 | _window = ::CreateWindowW(className, windowName, | ||
| 58 | style, x, y, width, height, parentWindow, | ||
| 59 | idOrHMenu, instance, createParam); | ||
| 60 | return (_window != NULL); | ||
| 61 | } | ||
| 62 | return Create(GetSystemString(className), GetSystemString(windowName), | ||
| 63 | style, x, y, width, height, parentWindow, | ||
| 64 | idOrHMenu, instance, createParam); | ||
| 65 | } | ||
| 66 | |||
| 67 | bool CWindow::CreateEx(DWORD exStyle, LPCWSTR className, | ||
| 68 | LPCWSTR windowName, DWORD style, | ||
| 69 | int x, int y, int width, int height, | ||
| 70 | HWND parentWindow, HMENU idOrHMenu, | ||
| 71 | HINSTANCE instance, LPVOID createParam) | ||
| 72 | { | ||
| 73 | if (g_IsNT) | ||
| 74 | { | ||
| 75 | _window = ::CreateWindowExW(exStyle, className, windowName, | ||
| 76 | style, x, y, width, height, parentWindow, | ||
| 77 | idOrHMenu, instance, createParam); | ||
| 78 | return (_window != NULL); | ||
| 79 | } | ||
| 80 | AString classNameA; | ||
| 81 | LPCSTR classNameP; | ||
| 82 | if (IS_INTRESOURCE(className)) | ||
| 83 | classNameP = (LPCSTR)className; | ||
| 84 | else | ||
| 85 | { | ||
| 86 | classNameA = GetSystemString(className); | ||
| 87 | classNameP = classNameA; | ||
| 88 | } | ||
| 89 | AString windowNameA; | ||
| 90 | LPCSTR windowNameP; | ||
| 91 | if (IS_INTRESOURCE(windowName)) | ||
| 92 | windowNameP = (LPCSTR)windowName; | ||
| 93 | else | ||
| 94 | { | ||
| 95 | windowNameA = GetSystemString(windowName); | ||
| 96 | windowNameP = windowNameA; | ||
| 97 | } | ||
| 98 | return CreateEx(exStyle, classNameP, windowNameP, | ||
| 99 | style, x, y, width, height, parentWindow, | ||
| 100 | idOrHMenu, instance, createParam); | ||
| 101 | } | ||
| 102 | |||
| 103 | #endif | ||
| 104 | |||
| 105 | #ifndef _UNICODE | ||
| 106 | bool MySetWindowText(HWND wnd, LPCWSTR s) | ||
| 107 | { | ||
| 108 | if (g_IsNT) | ||
| 109 | return BOOLToBool(::SetWindowTextW(wnd, s)); | ||
| 110 | return BOOLToBool(::SetWindowTextA(wnd, UnicodeStringToMultiByte(s))); | ||
| 111 | } | ||
| 112 | #endif | ||
| 113 | |||
| 114 | bool CWindow::GetText(CSysString &s) | ||
| 115 | { | ||
| 116 | s.Empty(); | ||
| 117 | unsigned len = (unsigned)GetTextLength(); | ||
| 118 | if (len == 0) | ||
| 119 | return (::GetLastError() == ERROR_SUCCESS); | ||
| 120 | TCHAR *p = s.GetBuf(len); | ||
| 121 | { | ||
| 122 | unsigned len2 = (unsigned)GetText(p, (int)(len + 1)); | ||
| 123 | if (len > len2) | ||
| 124 | len = len2; | ||
| 125 | } | ||
| 126 | s.ReleaseBuf_CalcLen(len); | ||
| 127 | if (len == 0) | ||
| 128 | return (::GetLastError() == ERROR_SUCCESS); | ||
| 129 | return true; | ||
| 130 | } | ||
| 131 | |||
| 132 | #ifndef _UNICODE | ||
| 133 | bool CWindow::GetText(UString &s) | ||
| 134 | { | ||
| 135 | if (g_IsNT) | ||
| 136 | { | ||
| 137 | s.Empty(); | ||
| 138 | unsigned len = (unsigned)GetWindowTextLengthW(_window); | ||
| 139 | if (len == 0) | ||
| 140 | return (::GetLastError() == ERROR_SUCCESS); | ||
| 141 | wchar_t *p = s.GetBuf(len); | ||
| 142 | { | ||
| 143 | unsigned len2 = (unsigned)GetWindowTextW(_window, p, (int)(len + 1)); | ||
| 144 | if (len > len2) | ||
| 145 | len = len2; | ||
| 146 | } | ||
| 147 | s.ReleaseBuf_CalcLen(len); | ||
| 148 | if (len == 0) | ||
| 149 | return (::GetLastError() == ERROR_SUCCESS); | ||
| 150 | return true; | ||
| 151 | } | ||
| 152 | CSysString sysString; | ||
| 153 | bool result = GetText(sysString); | ||
| 154 | MultiByteToUnicodeString2(s, sysString); | ||
| 155 | return result; | ||
| 156 | } | ||
| 157 | #endif | ||
| 158 | |||
| 159 | |||
| 160 | /* | ||
| 161 | bool CWindow::ModifyStyleBase(int styleOffset, | ||
| 162 | DWORD remove, DWORD add, UINT flags) | ||
| 163 | { | ||
| 164 | DWORD style = GetWindowLong(styleOffset); | ||
| 165 | DWORD newStyle = (style & ~remove) | add; | ||
| 166 | if (style == newStyle) | ||
| 167 | return false; // it is not good | ||
| 168 | |||
| 169 | SetWindowLong(styleOffset, newStyle); | ||
| 170 | if (flags != 0) | ||
| 171 | { | ||
| 172 | ::SetWindowPos(_window, NULL, 0, 0, 0, 0, | ||
| 173 | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | flags); | ||
| 174 | } | ||
| 175 | return TRUE; | ||
| 176 | } | ||
| 177 | */ | ||
| 178 | |||
| 179 | } | ||
diff --git a/CPP/Windows/Window.h b/CPP/Windows/Window.h new file mode 100644 index 0000000..83726c7 --- /dev/null +++ b/CPP/Windows/Window.h | |||
| @@ -0,0 +1,284 @@ | |||
| 1 | // Windows/Window.h | ||
| 2 | |||
| 3 | #ifndef __WINDOWS_WINDOW_H | ||
| 4 | #define __WINDOWS_WINDOW_H | ||
| 5 | |||
| 6 | #include "../Common/MyWindows.h" | ||
| 7 | #include "../Common/MyString.h" | ||
| 8 | |||
| 9 | #include "Defs.h" | ||
| 10 | |||
| 11 | #ifndef UNDER_CE | ||
| 12 | |||
| 13 | #define MY__WM_CHANGEUISTATE 0x0127 | ||
| 14 | #define MY__WM_UPDATEUISTATE 0x0128 | ||
| 15 | #define MY__WM_QUERYUISTATE 0x0129 | ||
| 16 | |||
| 17 | // LOWORD(wParam) values in WM_*UISTATE | ||
| 18 | #define MY__UIS_SET 1 | ||
| 19 | #define MY__UIS_CLEAR 2 | ||
| 20 | #define MY__UIS_INITIALIZE 3 | ||
| 21 | |||
| 22 | // HIWORD(wParam) values in WM_*UISTATE | ||
| 23 | #define MY__UISF_HIDEFOCUS 0x1 | ||
| 24 | #define MY__UISF_HIDEACCEL 0x2 | ||
| 25 | #define MY__UISF_ACTIVE 0x4 | ||
| 26 | |||
| 27 | #endif | ||
| 28 | |||
| 29 | namespace NWindows { | ||
| 30 | |||
| 31 | inline ATOM MyRegisterClass(CONST WNDCLASS *wndClass) | ||
| 32 | { return ::RegisterClass(wndClass); } | ||
| 33 | |||
| 34 | #ifndef _UNICODE | ||
| 35 | ATOM MyRegisterClass(CONST WNDCLASSW *wndClass); | ||
| 36 | #endif | ||
| 37 | |||
| 38 | #ifdef _UNICODE | ||
| 39 | inline bool MySetWindowText(HWND wnd, LPCWSTR s) { return BOOLToBool(::SetWindowText(wnd, s)); } | ||
| 40 | #else | ||
| 41 | bool MySetWindowText(HWND wnd, LPCWSTR s); | ||
| 42 | #endif | ||
| 43 | |||
| 44 | |||
| 45 | #ifdef UNDER_CE | ||
| 46 | #define GWLP_USERDATA GWL_USERDATA | ||
| 47 | #define GWLP_WNDPROC GWL_WNDPROC | ||
| 48 | #define BTNS_BUTTON TBSTYLE_BUTTON | ||
| 49 | #define WC_COMBOBOXW L"ComboBox" | ||
| 50 | #define DWLP_MSGRESULT DWL_MSGRESULT | ||
| 51 | #endif | ||
| 52 | |||
| 53 | class CWindow | ||
| 54 | { | ||
| 55 | private: | ||
| 56 | // bool ModifyStyleBase(int styleOffset, DWORD remove, DWORD add, UINT flags); | ||
| 57 | protected: | ||
| 58 | HWND _window; | ||
| 59 | public: | ||
| 60 | CWindow(HWND newWindow = NULL): _window(newWindow){}; | ||
| 61 | CWindow& operator=(HWND newWindow) | ||
| 62 | { | ||
| 63 | _window = newWindow; | ||
| 64 | return *this; | ||
| 65 | } | ||
| 66 | operator HWND() const { return _window; } | ||
| 67 | void Attach(HWND newWindow) { _window = newWindow; } | ||
| 68 | HWND Detach() | ||
| 69 | { | ||
| 70 | HWND window = _window; | ||
| 71 | _window = NULL; | ||
| 72 | return window; | ||
| 73 | } | ||
| 74 | |||
| 75 | bool Foreground() { return BOOLToBool(::SetForegroundWindow(_window)); } | ||
| 76 | |||
| 77 | HWND GetParent() const { return ::GetParent(_window); } | ||
| 78 | bool GetWindowRect(LPRECT rect) const { return BOOLToBool(::GetWindowRect(_window,rect)); } | ||
| 79 | #ifndef UNDER_CE | ||
| 80 | bool IsZoomed() const { return BOOLToBool(::IsZoomed(_window)); } | ||
| 81 | #endif | ||
| 82 | bool ClientToScreen(LPPOINT point) const { return BOOLToBool(::ClientToScreen(_window, point)); } | ||
| 83 | bool ScreenToClient(LPPOINT point) const { return BOOLToBool(::ScreenToClient(_window, point)); } | ||
| 84 | |||
| 85 | bool CreateEx(DWORD exStyle, LPCTSTR className, | ||
| 86 | LPCTSTR windowName, DWORD style, | ||
| 87 | int x, int y, int width, int height, | ||
| 88 | HWND parentWindow, HMENU idOrHMenu, | ||
| 89 | HINSTANCE instance, LPVOID createParam) | ||
| 90 | { | ||
| 91 | _window = ::CreateWindowEx(exStyle, className, windowName, | ||
| 92 | style, x, y, width, height, parentWindow, | ||
| 93 | idOrHMenu, instance, createParam); | ||
| 94 | return (_window != NULL); | ||
| 95 | } | ||
| 96 | |||
| 97 | bool Create(LPCTSTR className, | ||
| 98 | LPCTSTR windowName, DWORD style, | ||
| 99 | int x, int y, int width, int height, | ||
| 100 | HWND parentWindow, HMENU idOrHMenu, | ||
| 101 | HINSTANCE instance, LPVOID createParam) | ||
| 102 | { | ||
| 103 | _window = ::CreateWindow(className, windowName, | ||
| 104 | style, x, y, width, height, parentWindow, | ||
| 105 | idOrHMenu, instance, createParam); | ||
| 106 | return (_window != NULL); | ||
| 107 | } | ||
| 108 | |||
| 109 | #ifndef _UNICODE | ||
| 110 | bool Create(LPCWSTR className, | ||
| 111 | LPCWSTR windowName, DWORD style, | ||
| 112 | int x, int y, int width, int height, | ||
| 113 | HWND parentWindow, HMENU idOrHMenu, | ||
| 114 | HINSTANCE instance, LPVOID createParam); | ||
| 115 | bool CreateEx(DWORD exStyle, LPCWSTR className, | ||
| 116 | LPCWSTR windowName, DWORD style, | ||
| 117 | int x, int y, int width, int height, | ||
| 118 | HWND parentWindow, HMENU idOrHMenu, | ||
| 119 | HINSTANCE instance, LPVOID createParam); | ||
| 120 | #endif | ||
| 121 | |||
| 122 | |||
| 123 | bool Destroy() | ||
| 124 | { | ||
| 125 | if (_window == NULL) | ||
| 126 | return true; | ||
| 127 | bool result = BOOLToBool(::DestroyWindow(_window)); | ||
| 128 | if (result) | ||
| 129 | _window = NULL; | ||
| 130 | return result; | ||
| 131 | } | ||
| 132 | bool IsWindow() { return BOOLToBool(::IsWindow(_window)); } | ||
| 133 | bool Move(int x, int y, int width, int height, bool repaint = true) | ||
| 134 | { return BOOLToBool(::MoveWindow(_window, x, y, width, height, BoolToBOOL(repaint))); } | ||
| 135 | |||
| 136 | bool ChangeSubWindowSizeX(HWND hwnd, int xSize) | ||
| 137 | { | ||
| 138 | RECT rect; | ||
| 139 | ::GetWindowRect(hwnd, &rect); | ||
| 140 | POINT p1; | ||
| 141 | p1.x = rect.left; | ||
| 142 | p1.y = rect.top; | ||
| 143 | ScreenToClient(&p1); | ||
| 144 | return BOOLToBool(::MoveWindow(hwnd, p1.x, p1.y, xSize, rect.bottom - rect.top, TRUE)); | ||
| 145 | } | ||
| 146 | |||
| 147 | void ScreenToClient(RECT *rect) | ||
| 148 | { | ||
| 149 | POINT p1, p2; | ||
| 150 | p1.x = rect->left; | ||
| 151 | p1.y = rect->top; | ||
| 152 | p2.x = rect->right; | ||
| 153 | p2.y = rect->bottom; | ||
| 154 | ScreenToClient(&p1); | ||
| 155 | ScreenToClient(&p2); | ||
| 156 | |||
| 157 | rect->left = p1.x; | ||
| 158 | rect->top = p1.y; | ||
| 159 | rect->right = p2.x; | ||
| 160 | rect->bottom = p2.y; | ||
| 161 | } | ||
| 162 | |||
| 163 | bool GetClientRect(LPRECT rect) { return BOOLToBool(::GetClientRect(_window, rect)); } | ||
| 164 | bool Show(int cmdShow) { return BOOLToBool(::ShowWindow(_window, cmdShow)); } | ||
| 165 | bool Show_Bool(bool show) { return Show(show ? SW_SHOW: SW_HIDE); } | ||
| 166 | |||
| 167 | #ifndef UNDER_CE | ||
| 168 | bool SetPlacement(CONST WINDOWPLACEMENT *placement) { return BOOLToBool(::SetWindowPlacement(_window, placement)); } | ||
| 169 | bool GetPlacement(WINDOWPLACEMENT *placement) { return BOOLToBool(::GetWindowPlacement(_window, placement)); } | ||
| 170 | #endif | ||
| 171 | bool Update() { return BOOLToBool(::UpdateWindow(_window)); } | ||
| 172 | bool InvalidateRect(LPCRECT rect, bool backgroundErase = true) | ||
| 173 | { return BOOLToBool(::InvalidateRect(_window, rect, BoolToBOOL(backgroundErase))); } | ||
| 174 | void SetRedraw(bool redraw = true) { SendMsg(WM_SETREDRAW, (WPARAM)BoolToBOOL(redraw), 0); } | ||
| 175 | |||
| 176 | LONG_PTR SetStyle(LONG_PTR style) { return SetLongPtr(GWL_STYLE, style); } | ||
| 177 | LONG_PTR GetStyle() const { return GetLongPtr(GWL_STYLE); } | ||
| 178 | // bool MyIsMaximized() const { return ((GetStyle() & WS_MAXIMIZE) != 0); } | ||
| 179 | |||
| 180 | LONG_PTR SetLong(int index, LONG newLongPtr) { return ::SetWindowLong(_window, index, newLongPtr); } | ||
| 181 | LONG_PTR GetLong(int index) const { return ::GetWindowLong(_window, index); } | ||
| 182 | LONG_PTR SetUserDataLong(LONG newLongPtr) { return SetLong(GWLP_USERDATA, newLongPtr); } | ||
| 183 | LONG_PTR GetUserDataLong() const { return GetLong(GWLP_USERDATA); } | ||
| 184 | |||
| 185 | |||
| 186 | #ifdef UNDER_CE | ||
| 187 | |||
| 188 | LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr) { return SetLong(index, newLongPtr); } | ||
| 189 | LONG_PTR GetLongPtr(int index) const { return GetLong(index); } | ||
| 190 | |||
| 191 | LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetUserDataLong(newLongPtr); } | ||
| 192 | LONG_PTR GetUserDataLongPtr() const { return GetUserDataLong(); } | ||
| 193 | |||
| 194 | #else | ||
| 195 | |||
| 196 | LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr) | ||
| 197 | { return ::SetWindowLongPtr(_window, index, | ||
| 198 | #ifndef _WIN64 | ||
| 199 | (LONG) | ||
| 200 | #endif | ||
| 201 | newLongPtr); } | ||
| 202 | #ifndef _UNICODE | ||
| 203 | LONG_PTR SetLongPtrW(int index, LONG_PTR newLongPtr) | ||
| 204 | { return ::SetWindowLongPtrW(_window, index, | ||
| 205 | #ifndef _WIN64 | ||
| 206 | (LONG) | ||
| 207 | #endif | ||
| 208 | newLongPtr); } | ||
| 209 | #endif | ||
| 210 | |||
| 211 | LONG_PTR GetLongPtr(int index) const { return ::GetWindowLongPtr(_window, index); } | ||
| 212 | LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetLongPtr(GWLP_USERDATA, newLongPtr); } | ||
| 213 | LONG_PTR GetUserDataLongPtr() const { return GetLongPtr(GWLP_USERDATA); } | ||
| 214 | |||
| 215 | #endif | ||
| 216 | |||
| 217 | /* | ||
| 218 | bool ModifyStyle(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0) | ||
| 219 | { return ModifyStyleBase(GWL_STYLE, remove, add, flags); } | ||
| 220 | bool ModifyStyleEx(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0) | ||
| 221 | { return ModifyStyleBase(GWL_EXSTYLE, remove, add, flags); } | ||
| 222 | */ | ||
| 223 | |||
| 224 | HWND SetFocus() { return ::SetFocus(_window); } | ||
| 225 | |||
| 226 | LRESULT SendMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) | ||
| 227 | { return ::SendMessage(_window, message, wParam, lParam); } | ||
| 228 | #ifndef _UNICODE | ||
| 229 | LRESULT SendMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) | ||
| 230 | { return ::SendMessageW(_window, message, wParam, lParam); } | ||
| 231 | #endif | ||
| 232 | |||
| 233 | bool PostMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) | ||
| 234 | { return BOOLToBool(::PostMessage(_window, message, wParam, lParam)); } | ||
| 235 | #ifndef _UNICODE | ||
| 236 | bool PostMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) | ||
| 237 | { return BOOLToBool(::PostMessageW(_window, message, wParam, lParam)); } | ||
| 238 | #endif | ||
| 239 | |||
| 240 | bool SetText(LPCTSTR s) { return BOOLToBool(::SetWindowText(_window, s)); } | ||
| 241 | #ifndef _UNICODE | ||
| 242 | bool SetText(LPCWSTR s) { return MySetWindowText(_window, s); } | ||
| 243 | #endif | ||
| 244 | |||
| 245 | int GetTextLength() const | ||
| 246 | { return GetWindowTextLength(_window); } | ||
| 247 | int GetText(LPTSTR string, int maxCount) const | ||
| 248 | { return GetWindowText(_window, string, maxCount); } | ||
| 249 | bool GetText(CSysString &s); | ||
| 250 | #ifndef _UNICODE | ||
| 251 | /* | ||
| 252 | UINT GetText(LPWSTR string, int maxCount) const | ||
| 253 | { return GetWindowTextW(_window, string, maxCount); } | ||
| 254 | */ | ||
| 255 | bool GetText(UString &s); | ||
| 256 | #endif | ||
| 257 | |||
| 258 | bool Enable(bool enable) | ||
| 259 | { return BOOLToBool(::EnableWindow(_window, BoolToBOOL(enable))); } | ||
| 260 | |||
| 261 | bool IsEnabled() | ||
| 262 | { return BOOLToBool(::IsWindowEnabled(_window)); } | ||
| 263 | |||
| 264 | #ifndef UNDER_CE | ||
| 265 | HMENU GetSystemMenu(bool revert) | ||
| 266 | { return ::GetSystemMenu(_window, BoolToBOOL(revert)); } | ||
| 267 | #endif | ||
| 268 | |||
| 269 | UINT_PTR SetTimer(UINT_PTR idEvent, UINT elapse, TIMERPROC timerFunc = 0) | ||
| 270 | { return ::SetTimer(_window, idEvent, elapse, timerFunc); } | ||
| 271 | bool KillTimer(UINT_PTR idEvent) | ||
| 272 | {return BOOLToBool(::KillTimer(_window, idEvent)); } | ||
| 273 | |||
| 274 | HICON SetIcon(WPARAM sizeType, HICON icon) { return (HICON)SendMsg(WM_SETICON, sizeType, (LPARAM)icon); } | ||
| 275 | }; | ||
| 276 | |||
| 277 | #define RECT_SIZE_X(r) ((r).right - (r).left) | ||
| 278 | #define RECT_SIZE_Y(r) ((r).bottom - (r).top) | ||
| 279 | |||
| 280 | inline bool IsKeyDown(int virtKey) { return (::GetKeyState(virtKey) & 0x8000) != 0; } | ||
| 281 | |||
| 282 | } | ||
| 283 | |||
| 284 | #endif | ||
