diff options
author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2023-06-21 00:00:00 +0000 |
---|---|---|
committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2023-12-17 14:59:19 +0500 |
commit | 5b39dc76f1bc82f941d5c800ab9f34407a06b53a (patch) | |
tree | fe5e17420300b715021a76328444088d32047963 /CPP/Windows/CommonDialog.cpp | |
parent | 93be7d4abfd4233228f58ee1fbbcd76d91be66a4 (diff) | |
download | 7zip-23.01.tar.gz 7zip-23.01.tar.bz2 7zip-23.01.zip |
23.0123.01
Diffstat (limited to '')
-rw-r--r-- | CPP/Windows/CommonDialog.cpp | 291 |
1 files changed, 176 insertions, 115 deletions
diff --git a/CPP/Windows/CommonDialog.cpp b/CPP/Windows/CommonDialog.cpp index eaaecad..7a92d5f 100644 --- a/CPP/Windows/CommonDialog.cpp +++ b/CPP/Windows/CommonDialog.cpp | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | #include "StdAfx.h" | 3 | #include "StdAfx.h" |
4 | 4 | ||
5 | #include "../Common/MyWindows.h" | 5 | #include "../Common/MyBuffer.h" |
6 | 6 | ||
7 | #ifdef UNDER_CE | 7 | #ifdef UNDER_CE |
8 | #include <commdlg.h> | 8 | #include <commdlg.h> |
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | #include "CommonDialog.h" | 15 | #include "CommonDialog.h" |
16 | #include "Defs.h" | 16 | #include "Defs.h" |
17 | // #include "FileDir.h" | ||
17 | 18 | ||
18 | #ifndef _UNICODE | 19 | #ifndef _UNICODE |
19 | extern bool g_IsNT; | 20 | extern bool g_IsNT; |
@@ -21,61 +22,46 @@ extern bool g_IsNT; | |||
21 | 22 | ||
22 | namespace NWindows { | 23 | namespace NWindows { |
23 | 24 | ||
24 | #ifndef _UNICODE | 25 | /* |
26 | GetSaveFileName() | ||
27 | GetOpenFileName() | ||
28 | OPENFILENAME | ||
25 | 29 | ||
26 | class CDoubleZeroStringListA | 30 | (lpstrInitialDir) : the initial directory. |
27 | { | 31 | DOCs: the algorithm for selecting the initial directory varies on different platforms: |
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 | { | 32 | { |
38 | unsigned len = MyStringLen(s) + 1; | 33 | Win2000/XP/Vista: |
39 | if (len >= Size) | 34 | 1. If lpstrFile contains a path, that path is the initial directory. |
40 | return false; | 35 | 2. Otherwise, lpstrInitialDir specifies the initial directory. |
41 | MyStringCopy(Buf, s); | 36 | |
42 | Buf += len; | 37 | Win7: |
43 | Size -= len; | 38 | If lpstrInitialDir has the same value as was passed the first time |
44 | return true; | 39 | the application used an Open or Save As dialog box, the path |
40 | most recently selected by the user is used as the initial directory. | ||
45 | } | 41 | } |
46 | 42 | ||
47 | #endif | 43 | Win10: |
44 | in: | ||
45 | function supports (lpstrInitialDir) path with super prefix "\\\\?\\" | ||
46 | function supports (lpstrInitialDir) path with long path | ||
47 | function doesn't support absolute (lpstrFile) path with super prefix "\\\\?\\" | ||
48 | function doesn't support absolute (lpstrFile) path with long path | ||
49 | out: the path with super prefix "\\\\?\\" will be returned, if selected path is long | ||
48 | 50 | ||
49 | class CDoubleZeroStringListW | 51 | WinXP-64 and Win10: if no filters, the system shows all files. |
50 | { | 52 | but DOCs say: If all three members are zero or NULL, |
51 | LPWSTR Buf; | 53 | the system does not use any filters and does not |
52 | unsigned Size; | 54 | show any files in the file list control of the dialog box. |
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 | 55 | ||
56 | in Win7+: GetOpenFileName() and GetSaveFileName() | ||
57 | do not support pstrCustomFilter feature anymore | ||
58 | */ | ||
70 | 59 | ||
71 | #ifdef UNDER_CE | 60 | #ifdef UNDER_CE |
72 | #define MY__OFN_PROJECT 0x00400000 | 61 | #define MY_OFN_PROJECT 0x00400000 |
73 | #define MY__OFN_SHOW_ALL 0x01000000 | 62 | #define MY_OFN_SHOW_ALL 0x01000000 |
74 | #endif | 63 | #endif |
75 | 64 | ||
76 | /* if (lpstrFilter == NULL && nFilterIndex == 0) | ||
77 | MSDN : "the system doesn't show any files", | ||
78 | but WinXP-64 shows all files. Why ??? */ | ||
79 | 65 | ||
80 | /* | 66 | /* |
81 | structures | 67 | structures |
@@ -89,16 +75,16 @@ contain additional members: | |||
89 | #endif | 75 | #endif |
90 | 76 | ||
91 | If we compile the source code with (_WIN32_WINNT >= 0x0500), some functions | 77 | 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*). | 78 | will not work at NT 4.0, if we use sizeof(OPENFILENAME). |
93 | So we use size of old version of structure. */ | 79 | We try to use reduced structure OPENFILENAME_NT4. |
80 | */ | ||
94 | 81 | ||
95 | #if defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500) | 82 | // #if defined(_WIN64) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500) |
96 | // || !defined(WINVER) | 83 | #if defined(__GNUC__) && (__GNUC__ <= 9) || defined(Z7_OLD_WIN_SDK) |
97 | #ifndef _UNICODE | 84 | #ifndef _UNICODE |
98 | #define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA) | 85 | #define my_compatib_OPENFILENAMEA OPENFILENAMEA |
99 | #endif | 86 | #endif |
100 | #define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW) | 87 | #define my_compatib_OPENFILENAMEW OPENFILENAMEW |
101 | #else | ||
102 | 88 | ||
103 | // MinGW doesn't support some required macros. So we define them here: | 89 | // MinGW doesn't support some required macros. So we define them here: |
104 | #ifndef CDSIZEOF_STRUCT | 90 | #ifndef CDSIZEOF_STRUCT |
@@ -117,91 +103,166 @@ So we use size of old version of structure. */ | |||
117 | #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A | 103 | #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A |
118 | #endif | 104 | #endif |
119 | #define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W | 105 | #define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W |
106 | #else | ||
107 | #ifndef _UNICODE | ||
108 | #define my_compatib_OPENFILENAMEA OPENFILENAME_NT4A | ||
109 | #define my_compatib_OPENFILENAMEA_size sizeof(my_compatib_OPENFILENAMEA) | ||
110 | #endif | ||
111 | #define my_compatib_OPENFILENAMEW OPENFILENAME_NT4W | ||
112 | #define my_compatib_OPENFILENAMEW_size sizeof(my_compatib_OPENFILENAMEW) | ||
113 | #endif | ||
114 | /* | ||
115 | #elif defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500) | ||
116 | // || !defined(WINVER) | ||
117 | #ifndef _UNICODE | ||
118 | #define my_compatib_OPENFILENAMEA OPENFILENAMEA | ||
119 | #define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA) | ||
120 | #endif | ||
121 | #define my_compatib_OPENFILENAMEW OPENFILENAMEW | ||
122 | #define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW) | ||
123 | #else | ||
124 | |||
120 | #endif | 125 | #endif |
126 | */ | ||
121 | 127 | ||
122 | #ifndef _UNICODE | 128 | #ifndef _UNICODE |
123 | #define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; } | 129 | #define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; } |
124 | #endif | 130 | #endif |
125 | 131 | ||
126 | bool MyGetOpenFileName(HWND hwnd, LPCWSTR title, | 132 | bool CCommonDialogInfo::CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters) |
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 | { | 133 | { |
137 | const unsigned kBufSize = MAX_PATH * 2; | 134 | /* GetSaveFileName() and GetOpenFileName() could change current dir, |
138 | const unsigned kFilterBufSize = MAX_PATH; | 135 | if OFN_NOCHANGEDIR is not used. |
139 | if (!filter) | 136 | We can restore current dir manually, if it's required. |
140 | filter = L"*.*"; | 137 | 22.02: we use OFN_NOCHANGEDIR. So we don't need to restore current dir manually. */ |
141 | #ifndef _UNICODE | 138 | // NFile::NDir::CCurrentDirRestorer curDirRestorer; |
139 | |||
140 | #ifndef _UNICODE | ||
142 | if (!g_IsNT) | 141 | if (!g_IsNT) |
143 | { | 142 | { |
144 | CHAR buf[kBufSize]; | 143 | AString tempPath; |
145 | MyStringCopy(buf, (const char *)GetSystemString(filePath)); | 144 | AStringVector f; |
146 | // OPENFILENAME_NT4A | 145 | unsigned i; |
147 | OPENFILENAMEA p; | 146 | for (i = 0; i < filters.Size(); i++) |
147 | f.Add(GetSystemString(filters[i])); | ||
148 | unsigned size = f.Size() + 1; | ||
149 | for (i = 0; i < f.Size(); i++) | ||
150 | size += f[i].Len(); | ||
151 | CObjArray<char> filterBuf(size); | ||
152 | // memset(filterBuf, 0, size * sizeof(char)); | ||
153 | { | ||
154 | char *dest = filterBuf; | ||
155 | for (i = 0; i < f.Size(); i++) | ||
156 | { | ||
157 | const AString &s = f[i]; | ||
158 | MyStringCopy(dest, s); | ||
159 | dest += s.Len() + 1; | ||
160 | } | ||
161 | *dest = 0; | ||
162 | } | ||
163 | my_compatib_OPENFILENAMEA p; | ||
148 | memset(&p, 0, sizeof(p)); | 164 | memset(&p, 0, sizeof(p)); |
149 | p.lStructSize = my_compatib_OPENFILENAMEA_size; | 165 | p.lStructSize = my_compatib_OPENFILENAMEA_size; |
150 | p.hwndOwner = hwnd; | 166 | p.hwndOwner = hwndOwner; |
151 | CHAR filterBuf[kFilterBufSize]; | 167 | if (size > 1) |
152 | { | 168 | { |
153 | CDoubleZeroStringListA dz(filterBuf, kFilterBufSize); | ||
154 | dz.Add(GetSystemString(filterDescription ? filterDescription : filter)); | ||
155 | dz.Add(GetSystemString(filter)); | ||
156 | dz.Finish(); | ||
157 | p.lpstrFilter = filterBuf; | 169 | p.lpstrFilter = filterBuf; |
158 | p.nFilterIndex = 1; | 170 | p.nFilterIndex = (DWORD)(FilterIndex + 1); |
171 | } | ||
172 | |||
173 | CONV_U_To_A(p.lpstrInitialDir, lpstrInitialDir, initialDir_a) | ||
174 | CONV_U_To_A(p.lpstrTitle, lpstrTitle, title_a) | ||
175 | |||
176 | const AString filePath_a = GetSystemString(FilePath); | ||
177 | const unsigned bufSize = MAX_PATH * 8 | ||
178 | + filePath_a.Len() | ||
179 | + initialDir_a.Len(); | ||
180 | p.nMaxFile = bufSize; | ||
181 | p.lpstrFile = tempPath.GetBuf(bufSize); | ||
182 | MyStringCopy(p.lpstrFile, filePath_a); | ||
183 | p.Flags = | ||
184 | OFN_EXPLORER | ||
185 | | OFN_HIDEREADONLY | ||
186 | | OFN_NOCHANGEDIR; | ||
187 | const BOOL b = SaveMode ? | ||
188 | ::GetSaveFileNameA((LPOPENFILENAMEA)(void *)&p) : | ||
189 | ::GetOpenFileNameA((LPOPENFILENAMEA)(void *)&p); | ||
190 | if (!b) | ||
191 | return false; | ||
192 | { | ||
193 | tempPath.ReleaseBuf_CalcLen(bufSize); | ||
194 | FilePath = GetUnicodeString(tempPath); | ||
195 | FilterIndex = (int)p.nFilterIndex - 1; | ||
196 | return true; | ||
159 | } | 197 | } |
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 | } | 198 | } |
171 | else | 199 | else |
172 | #endif | 200 | #endif |
173 | { | 201 | { |
174 | WCHAR buf[kBufSize]; | 202 | UString tempPath; |
175 | MyStringCopy(buf, filePath); | 203 | unsigned size = filters.Size() + 1; |
176 | // OPENFILENAME_NT4W | 204 | unsigned i; |
177 | OPENFILENAMEW p; | 205 | for (i = 0; i < filters.Size(); i++) |
206 | size += filters[i].Len(); | ||
207 | CObjArray<wchar_t> filterBuf(size); | ||
208 | // memset(filterBuf, 0, size * sizeof(wchar_t)); | ||
209 | { | ||
210 | wchar_t *dest = filterBuf; | ||
211 | for (i = 0; i < filters.Size(); i++) | ||
212 | { | ||
213 | const UString &s = filters[i]; | ||
214 | MyStringCopy(dest, s); | ||
215 | dest += s.Len() + 1; | ||
216 | } | ||
217 | *dest = 0; | ||
218 | // if ((unsigned)(dest + 1 - filterBuf) != size) return false; | ||
219 | } | ||
220 | my_compatib_OPENFILENAMEW p; | ||
178 | memset(&p, 0, sizeof(p)); | 221 | memset(&p, 0, sizeof(p)); |
179 | p.lStructSize = my_compatib_OPENFILENAMEW_size; | 222 | p.lStructSize = my_compatib_OPENFILENAMEW_size; |
180 | p.hwndOwner = hwnd; | 223 | p.hwndOwner = hwndOwner; |
181 | 224 | if (size > 1) | |
182 | WCHAR filterBuf[kFilterBufSize]; | ||
183 | { | 225 | { |
184 | CDoubleZeroStringListW dz(filterBuf, kFilterBufSize); | ||
185 | dz.Add(filterDescription ? filterDescription : filter); | ||
186 | dz.Add(filter); | ||
187 | dz.Finish(); | ||
188 | p.lpstrFilter = filterBuf; | 226 | p.lpstrFilter = filterBuf; |
189 | p.nFilterIndex = 1; | 227 | p.nFilterIndex = (DWORD)(FilterIndex + 1); |
190 | } | 228 | } |
191 | 229 | unsigned bufSize = MAX_PATH * 8 + FilePath.Len(); | |
192 | p.lpstrFile = buf; | 230 | if (lpstrInitialDir) |
193 | p.nMaxFile = kBufSize; | 231 | { |
194 | p.lpstrInitialDir = initialDir; | 232 | p.lpstrInitialDir = lpstrInitialDir; |
195 | p.lpstrTitle = title; | 233 | bufSize += MyStringLen(lpstrInitialDir); |
196 | p.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | 234 | } |
197 | #ifdef UNDER_CE | 235 | p.nMaxFile = bufSize; |
198 | | (openFolder ? (MY__OFN_PROJECT | MY__OFN_SHOW_ALL) : 0) | 236 | p.lpstrFile = tempPath.GetBuf(bufSize); |
199 | #endif | 237 | MyStringCopy(p.lpstrFile, FilePath); |
238 | p.lpstrTitle = lpstrTitle; | ||
239 | p.Flags = | ||
240 | OFN_EXPLORER | ||
241 | | OFN_HIDEREADONLY | ||
242 | | OFN_NOCHANGEDIR | ||
243 | // | OFN_FORCESHOWHIDDEN // Win10 shows hidden items even without this flag | ||
244 | // | OFN_PATHMUSTEXIST | ||
245 | #ifdef UNDER_CE | ||
246 | | (OpenFolderMode ? (MY_OFN_PROJECT | MY_OFN_SHOW_ALL) : 0) | ||
247 | #endif | ||
200 | ; | 248 | ; |
201 | 249 | const BOOL b = SaveMode ? | |
202 | bool res = BOOLToBool(::GetOpenFileNameW(&p)); | 250 | ::GetSaveFileNameW((LPOPENFILENAMEW)(void *)&p) : |
203 | resPath = buf; | 251 | ::GetOpenFileNameW((LPOPENFILENAMEW)(void *)&p); |
204 | return res; | 252 | /* DOCs: lpstrFile : |
253 | if the buffer is too small, then: | ||
254 | - the function returns FALSE | ||
255 | - the CommDlgExtendedError() returns FNERR_BUFFERTOOSMALL | ||
256 | - the first two bytes of the lpstrFile buffer contain the | ||
257 | required size, in bytes or characters. */ | ||
258 | if (!b) | ||
259 | return false; | ||
260 | { | ||
261 | tempPath.ReleaseBuf_CalcLen(bufSize); | ||
262 | FilePath = tempPath; | ||
263 | FilterIndex = (int)p.nFilterIndex - 1; | ||
264 | return true; | ||
265 | } | ||
205 | } | 266 | } |
206 | } | 267 | } |
207 | 268 | ||