xref: /aosp_15_r20/external/lzma/CPP/Windows/CommonDialog.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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