1 // Windows/CommonDialog.cpp
2
3 #include "StdAfx.h"
4
5 #include "../Common/MyBuffer.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 // #include "FileDir.h"
18
19 #ifndef _UNICODE
20 extern bool g_IsNT;
21 #endif
22
23 namespace NWindows {
24
25 /*
26 GetSaveFileName()
27 GetOpenFileName()
28 OPENFILENAME
29
30 (lpstrInitialDir) : the initial directory.
31 DOCs: the algorithm for selecting the initial directory varies on different platforms:
32 {
33 Win2000/XP/Vista:
34 1. If lpstrFile contains a path, that path is the initial directory.
35 2. Otherwise, lpstrInitialDir specifies the initial directory.
36
37 Win7:
38 If lpstrInitialDir has the same value as was passed the first time
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.
41 }
42
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
50
51 WinXP-64 and Win10: if no filters, the system shows all files.
52 but DOCs say: If all three members are zero or NULL,
53 the system does not use any filters and does not
54 show any files in the file list control of the dialog box.
55
56 in Win7+: GetOpenFileName() and GetSaveFileName()
57 do not support pstrCustomFilter feature anymore
58 */
59
60 #ifdef UNDER_CE
61 #define MY_OFN_PROJECT 0x00400000
62 #define MY_OFN_SHOW_ALL 0x01000000
63 #endif
64
65
66 /*
67 structures
68 OPENFILENAMEW
69 OPENFILENAMEA
70 contain additional members:
71 #if (_WIN32_WINNT >= 0x0500)
72 void *pvReserved;
73 DWORD dwReserved;
74 DWORD FlagsEx;
75 #endif
76
77 If we compile the source code with (_WIN32_WINNT >= 0x0500), some functions
78 will not work at NT 4.0, if we use sizeof(OPENFILENAME).
79 We try to use reduced structure OPENFILENAME_NT4.
80 */
81
82 // #if defined(_WIN64) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500)
83 #if defined(__GNUC__) && (__GNUC__ <= 9) || defined(Z7_OLD_WIN_SDK)
84 #ifndef _UNICODE
85 #define my_compatib_OPENFILENAMEA OPENFILENAMEA
86 #endif
87 #define my_compatib_OPENFILENAMEW OPENFILENAMEW
88
89 // MinGW doesn't support some required macros. So we define them here:
90 #ifndef CDSIZEOF_STRUCT
91 #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
92 #endif
93 #ifndef _UNICODE
94 #ifndef OPENFILENAME_SIZE_VERSION_400A
95 #define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName)
96 #endif
97 #endif
98 #ifndef OPENFILENAME_SIZE_VERSION_400W
99 #define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName)
100 #endif
101
102 #ifndef _UNICODE
103 #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A
104 #endif
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
125 #endif
126 */
127
128 #ifndef _UNICODE
129 #define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; }
130 #endif
131
CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir,const UStringVector & filters)132 bool CCommonDialogInfo::CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters)
133 {
134 /* GetSaveFileName() and GetOpenFileName() could change current dir,
135 if OFN_NOCHANGEDIR is not used.
136 We can restore current dir manually, if it's required.
137 22.02: we use OFN_NOCHANGEDIR. So we don't need to restore current dir manually. */
138 // NFile::NDir::CCurrentDirRestorer curDirRestorer;
139
140 #ifndef _UNICODE
141 if (!g_IsNT)
142 {
143 AString tempPath;
144 AStringVector f;
145 unsigned i;
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;
164 memset(&p, 0, sizeof(p));
165 p.lStructSize = my_compatib_OPENFILENAMEA_size;
166 p.hwndOwner = hwndOwner;
167 if (size > 1)
168 {
169 p.lpstrFilter = filterBuf;
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;
197 }
198 }
199 else
200 #endif
201 {
202 UString tempPath;
203 unsigned size = filters.Size() + 1;
204 unsigned i;
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;
221 memset(&p, 0, sizeof(p));
222 p.lStructSize = my_compatib_OPENFILENAMEW_size;
223 p.hwndOwner = hwndOwner;
224 if (size > 1)
225 {
226 p.lpstrFilter = filterBuf;
227 p.nFilterIndex = (DWORD)(FilterIndex + 1);
228 }
229 unsigned bufSize = MAX_PATH * 8 + FilePath.Len();
230 if (lpstrInitialDir)
231 {
232 p.lpstrInitialDir = lpstrInitialDir;
233 bufSize += MyStringLen(lpstrInitialDir);
234 }
235 p.nMaxFile = bufSize;
236 p.lpstrFile = tempPath.GetBuf(bufSize);
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
248 ;
249 const BOOL b = SaveMode ?
250 ::GetSaveFileNameW((LPOPENFILENAMEW)(void *)&p) :
251 ::GetOpenFileNameW((LPOPENFILENAMEW)(void *)&p);
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 }
266 }
267 }
268
269 }
270