diff options
author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2021-12-27 00:00:00 +0000 |
---|---|---|
committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2022-03-18 15:35:13 +0500 |
commit | f19f813537c7aea1c20749c914e756b54a9c3cf5 (patch) | |
tree | 816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /CPP/Windows | |
parent | 98e06a519b63b81986abe76d28887f6984a7732b (diff) | |
download | 7zip-21.07.tar.gz 7zip-21.07.tar.bz2 7zip-21.07.zip |
'21.07'21.07
Diffstat (limited to 'CPP/Windows')
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 | ||