1370b324cSopenharmony_ci// Windows/CommonDialog.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#include "../Common/MyBuffer.h"
6370b324cSopenharmony_ci
7370b324cSopenharmony_ci#ifdef UNDER_CE
8370b324cSopenharmony_ci#include <commdlg.h>
9370b324cSopenharmony_ci#endif
10370b324cSopenharmony_ci
11370b324cSopenharmony_ci#ifndef _UNICODE
12370b324cSopenharmony_ci#include "../Common/StringConvert.h"
13370b324cSopenharmony_ci#endif
14370b324cSopenharmony_ci
15370b324cSopenharmony_ci#include "CommonDialog.h"
16370b324cSopenharmony_ci#include "Defs.h"
17370b324cSopenharmony_ci// #include "FileDir.h"
18370b324cSopenharmony_ci
19370b324cSopenharmony_ci#ifndef _UNICODE
20370b324cSopenharmony_ciextern bool g_IsNT;
21370b324cSopenharmony_ci#endif
22370b324cSopenharmony_ci
23370b324cSopenharmony_cinamespace NWindows {
24370b324cSopenharmony_ci
25370b324cSopenharmony_ci/*
26370b324cSopenharmony_ci  GetSaveFileName()
27370b324cSopenharmony_ci  GetOpenFileName()
28370b324cSopenharmony_ci  OPENFILENAME
29370b324cSopenharmony_ci
30370b324cSopenharmony_ci(lpstrInitialDir) : the initial directory.
31370b324cSopenharmony_ciDOCs: the algorithm for selecting the initial directory varies on different platforms:
32370b324cSopenharmony_ci{
33370b324cSopenharmony_ci  Win2000/XP/Vista:
34370b324cSopenharmony_ci    1. If lpstrFile contains a path, that path is the initial directory.
35370b324cSopenharmony_ci    2. Otherwise, lpstrInitialDir specifies the initial directory.
36370b324cSopenharmony_ci
37370b324cSopenharmony_ci  Win7:
38370b324cSopenharmony_ci    If lpstrInitialDir has the same value as was passed the first time
39370b324cSopenharmony_ci    the application used an Open or Save As dialog box, the path
40370b324cSopenharmony_ci    most recently selected by the user is used as the initial directory.
41370b324cSopenharmony_ci}
42370b324cSopenharmony_ci
43370b324cSopenharmony_ciWin10:
44370b324cSopenharmony_ci in:
45370b324cSopenharmony_ci  function supports (lpstrInitialDir) path with super prefix "\\\\?\\"
46370b324cSopenharmony_ci  function supports (lpstrInitialDir) path with long path
47370b324cSopenharmony_ci  function doesn't support absolute (lpstrFile) path with super prefix "\\\\?\\"
48370b324cSopenharmony_ci  function doesn't support absolute (lpstrFile) path with long path
49370b324cSopenharmony_ci out: the path with super prefix "\\\\?\\" will be returned, if selected path is long
50370b324cSopenharmony_ci
51370b324cSopenharmony_ciWinXP-64 and Win10: if no filters, the system shows all files.
52370b324cSopenharmony_ci    but DOCs say: If all three members are zero or NULL,
53370b324cSopenharmony_ci        the system does not use any filters and does not
54370b324cSopenharmony_ci        show any files in the file list control of the dialog box.
55370b324cSopenharmony_ci
56370b324cSopenharmony_ciin Win7+: GetOpenFileName() and GetSaveFileName()
57370b324cSopenharmony_ci    do not support pstrCustomFilter feature anymore
58370b324cSopenharmony_ci*/
59370b324cSopenharmony_ci
60370b324cSopenharmony_ci#ifdef UNDER_CE
61370b324cSopenharmony_ci#define MY_OFN_PROJECT  0x00400000
62370b324cSopenharmony_ci#define MY_OFN_SHOW_ALL 0x01000000
63370b324cSopenharmony_ci#endif
64370b324cSopenharmony_ci
65370b324cSopenharmony_ci
66370b324cSopenharmony_ci/*
67370b324cSopenharmony_cistructures
68370b324cSopenharmony_ci  OPENFILENAMEW
69370b324cSopenharmony_ci  OPENFILENAMEA
70370b324cSopenharmony_cicontain additional members:
71370b324cSopenharmony_ci#if (_WIN32_WINNT >= 0x0500)
72370b324cSopenharmony_ci  void *pvReserved;
73370b324cSopenharmony_ci  DWORD dwReserved;
74370b324cSopenharmony_ci  DWORD FlagsEx;
75370b324cSopenharmony_ci#endif
76370b324cSopenharmony_ci
77370b324cSopenharmony_ciIf we compile the source code with (_WIN32_WINNT >= 0x0500), some functions
78370b324cSopenharmony_ciwill not work at NT 4.0, if we use sizeof(OPENFILENAME).
79370b324cSopenharmony_ciWe try to use reduced structure OPENFILENAME_NT4.
80370b324cSopenharmony_ci*/
81370b324cSopenharmony_ci
82370b324cSopenharmony_ci// #if defined(_WIN64) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500)
83370b324cSopenharmony_ci#if defined(__GNUC__) && (__GNUC__ <= 9) || defined(Z7_OLD_WIN_SDK)
84370b324cSopenharmony_ci  #ifndef _UNICODE
85370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEA       OPENFILENAMEA
86370b324cSopenharmony_ci  #endif
87370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEW       OPENFILENAMEW
88370b324cSopenharmony_ci
89370b324cSopenharmony_ci  // MinGW doesn't support some required macros. So we define them here:
90370b324cSopenharmony_ci  #ifndef CDSIZEOF_STRUCT
91370b324cSopenharmony_ci  #define CDSIZEOF_STRUCT(structname, member)  (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
92370b324cSopenharmony_ci  #endif
93370b324cSopenharmony_ci  #ifndef _UNICODE
94370b324cSopenharmony_ci  #ifndef OPENFILENAME_SIZE_VERSION_400A
95370b324cSopenharmony_ci  #define OPENFILENAME_SIZE_VERSION_400A  CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName)
96370b324cSopenharmony_ci  #endif
97370b324cSopenharmony_ci  #endif
98370b324cSopenharmony_ci  #ifndef OPENFILENAME_SIZE_VERSION_400W
99370b324cSopenharmony_ci  #define OPENFILENAME_SIZE_VERSION_400W  CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName)
100370b324cSopenharmony_ci  #endif
101370b324cSopenharmony_ci
102370b324cSopenharmony_ci  #ifndef _UNICODE
103370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A
104370b324cSopenharmony_ci  #endif
105370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W
106370b324cSopenharmony_ci#else
107370b324cSopenharmony_ci  #ifndef _UNICODE
108370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEA       OPENFILENAME_NT4A
109370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEA_size  sizeof(my_compatib_OPENFILENAMEA)
110370b324cSopenharmony_ci  #endif
111370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEW       OPENFILENAME_NT4W
112370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEW_size  sizeof(my_compatib_OPENFILENAMEW)
113370b324cSopenharmony_ci#endif
114370b324cSopenharmony_ci/*
115370b324cSopenharmony_ci#elif defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500)
116370b324cSopenharmony_ci// || !defined(WINVER)
117370b324cSopenharmony_ci  #ifndef _UNICODE
118370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEA       OPENFILENAMEA
119370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA)
120370b324cSopenharmony_ci  #endif
121370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEW       OPENFILENAMEW
122370b324cSopenharmony_ci  #define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW)
123370b324cSopenharmony_ci#else
124370b324cSopenharmony_ci
125370b324cSopenharmony_ci#endif
126370b324cSopenharmony_ci*/
127370b324cSopenharmony_ci
128370b324cSopenharmony_ci#ifndef _UNICODE
129370b324cSopenharmony_ci#define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; }
130370b324cSopenharmony_ci#endif
131370b324cSopenharmony_ci
132370b324cSopenharmony_cibool CCommonDialogInfo::CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters)
133370b324cSopenharmony_ci{
134370b324cSopenharmony_ci  /* GetSaveFileName() and GetOpenFileName() could change current dir,
135370b324cSopenharmony_ci     if OFN_NOCHANGEDIR is not used.
136370b324cSopenharmony_ci     We can restore current dir manually, if it's required.
137370b324cSopenharmony_ci     22.02: we use OFN_NOCHANGEDIR. So we don't need to restore current dir manually. */
138370b324cSopenharmony_ci  // NFile::NDir::CCurrentDirRestorer curDirRestorer;
139370b324cSopenharmony_ci
140370b324cSopenharmony_ci#ifndef _UNICODE
141370b324cSopenharmony_ci  if (!g_IsNT)
142370b324cSopenharmony_ci  {
143370b324cSopenharmony_ci    AString tempPath;
144370b324cSopenharmony_ci    AStringVector f;
145370b324cSopenharmony_ci    unsigned i;
146370b324cSopenharmony_ci    for (i = 0; i < filters.Size(); i++)
147370b324cSopenharmony_ci      f.Add(GetSystemString(filters[i]));
148370b324cSopenharmony_ci    unsigned size = f.Size() + 1;
149370b324cSopenharmony_ci    for (i = 0; i < f.Size(); i++)
150370b324cSopenharmony_ci      size += f[i].Len();
151370b324cSopenharmony_ci    CObjArray<char> filterBuf(size);
152370b324cSopenharmony_ci    // memset(filterBuf, 0, size * sizeof(char));
153370b324cSopenharmony_ci    {
154370b324cSopenharmony_ci      char *dest = filterBuf;
155370b324cSopenharmony_ci      for (i = 0; i < f.Size(); i++)
156370b324cSopenharmony_ci      {
157370b324cSopenharmony_ci        const AString &s = f[i];
158370b324cSopenharmony_ci        MyStringCopy(dest, s);
159370b324cSopenharmony_ci        dest += s.Len() + 1;
160370b324cSopenharmony_ci      }
161370b324cSopenharmony_ci      *dest = 0;
162370b324cSopenharmony_ci    }
163370b324cSopenharmony_ci    my_compatib_OPENFILENAMEA p;
164370b324cSopenharmony_ci    memset(&p, 0, sizeof(p));
165370b324cSopenharmony_ci    p.lStructSize = my_compatib_OPENFILENAMEA_size;
166370b324cSopenharmony_ci    p.hwndOwner = hwndOwner;
167370b324cSopenharmony_ci    if (size > 1)
168370b324cSopenharmony_ci    {
169370b324cSopenharmony_ci      p.lpstrFilter = filterBuf;
170370b324cSopenharmony_ci      p.nFilterIndex = (DWORD)(FilterIndex + 1);
171370b324cSopenharmony_ci    }
172370b324cSopenharmony_ci
173370b324cSopenharmony_ci    CONV_U_To_A(p.lpstrInitialDir, lpstrInitialDir, initialDir_a)
174370b324cSopenharmony_ci    CONV_U_To_A(p.lpstrTitle, lpstrTitle, title_a)
175370b324cSopenharmony_ci
176370b324cSopenharmony_ci    const AString filePath_a = GetSystemString(FilePath);
177370b324cSopenharmony_ci    const unsigned bufSize = MAX_PATH * 8
178370b324cSopenharmony_ci        + filePath_a.Len()
179370b324cSopenharmony_ci        + initialDir_a.Len();
180370b324cSopenharmony_ci    p.nMaxFile = bufSize;
181370b324cSopenharmony_ci    p.lpstrFile = tempPath.GetBuf(bufSize);
182370b324cSopenharmony_ci    MyStringCopy(p.lpstrFile, filePath_a);
183370b324cSopenharmony_ci    p.Flags =
184370b324cSopenharmony_ci          OFN_EXPLORER
185370b324cSopenharmony_ci        | OFN_HIDEREADONLY
186370b324cSopenharmony_ci        | OFN_NOCHANGEDIR;
187370b324cSopenharmony_ci    const BOOL b = SaveMode ?
188370b324cSopenharmony_ci        ::GetSaveFileNameA((LPOPENFILENAMEA)(void *)&p) :
189370b324cSopenharmony_ci        ::GetOpenFileNameA((LPOPENFILENAMEA)(void *)&p);
190370b324cSopenharmony_ci    if (!b)
191370b324cSopenharmony_ci      return false;
192370b324cSopenharmony_ci    {
193370b324cSopenharmony_ci      tempPath.ReleaseBuf_CalcLen(bufSize);
194370b324cSopenharmony_ci      FilePath = GetUnicodeString(tempPath);
195370b324cSopenharmony_ci      FilterIndex = (int)p.nFilterIndex - 1;
196370b324cSopenharmony_ci      return true;
197370b324cSopenharmony_ci    }
198370b324cSopenharmony_ci  }
199370b324cSopenharmony_ci  else
200370b324cSopenharmony_ci#endif
201370b324cSopenharmony_ci  {
202370b324cSopenharmony_ci    UString tempPath;
203370b324cSopenharmony_ci    unsigned size = filters.Size() + 1;
204370b324cSopenharmony_ci    unsigned i;
205370b324cSopenharmony_ci    for (i = 0; i < filters.Size(); i++)
206370b324cSopenharmony_ci      size += filters[i].Len();
207370b324cSopenharmony_ci    CObjArray<wchar_t> filterBuf(size);
208370b324cSopenharmony_ci    // memset(filterBuf, 0, size * sizeof(wchar_t));
209370b324cSopenharmony_ci    {
210370b324cSopenharmony_ci      wchar_t *dest = filterBuf;
211370b324cSopenharmony_ci      for (i = 0; i < filters.Size(); i++)
212370b324cSopenharmony_ci      {
213370b324cSopenharmony_ci        const UString &s = filters[i];
214370b324cSopenharmony_ci        MyStringCopy(dest, s);
215370b324cSopenharmony_ci        dest += s.Len() + 1;
216370b324cSopenharmony_ci      }
217370b324cSopenharmony_ci      *dest = 0;
218370b324cSopenharmony_ci      // if ((unsigned)(dest + 1 - filterBuf) != size) return false;
219370b324cSopenharmony_ci    }
220370b324cSopenharmony_ci    my_compatib_OPENFILENAMEW p;
221370b324cSopenharmony_ci    memset(&p, 0, sizeof(p));
222370b324cSopenharmony_ci    p.lStructSize = my_compatib_OPENFILENAMEW_size;
223370b324cSopenharmony_ci    p.hwndOwner = hwndOwner;
224370b324cSopenharmony_ci    if (size > 1)
225370b324cSopenharmony_ci    {
226370b324cSopenharmony_ci      p.lpstrFilter = filterBuf;
227370b324cSopenharmony_ci      p.nFilterIndex = (DWORD)(FilterIndex + 1);
228370b324cSopenharmony_ci    }
229370b324cSopenharmony_ci    unsigned bufSize = MAX_PATH * 8 + FilePath.Len();
230370b324cSopenharmony_ci    if (lpstrInitialDir)
231370b324cSopenharmony_ci    {
232370b324cSopenharmony_ci      p.lpstrInitialDir = lpstrInitialDir;
233370b324cSopenharmony_ci      bufSize += MyStringLen(lpstrInitialDir);
234370b324cSopenharmony_ci    }
235370b324cSopenharmony_ci    p.nMaxFile = bufSize;
236370b324cSopenharmony_ci    p.lpstrFile = tempPath.GetBuf(bufSize);
237370b324cSopenharmony_ci    MyStringCopy(p.lpstrFile, FilePath);
238370b324cSopenharmony_ci    p.lpstrTitle = lpstrTitle;
239370b324cSopenharmony_ci    p.Flags =
240370b324cSopenharmony_ci          OFN_EXPLORER
241370b324cSopenharmony_ci        | OFN_HIDEREADONLY
242370b324cSopenharmony_ci        | OFN_NOCHANGEDIR
243370b324cSopenharmony_ci        // | OFN_FORCESHOWHIDDEN // Win10 shows hidden items even without this flag
244370b324cSopenharmony_ci        // | OFN_PATHMUSTEXIST
245370b324cSopenharmony_ci      #ifdef UNDER_CE
246370b324cSopenharmony_ci        | (OpenFolderMode ? (MY_OFN_PROJECT | MY_OFN_SHOW_ALL) : 0)
247370b324cSopenharmony_ci      #endif
248370b324cSopenharmony_ci        ;
249370b324cSopenharmony_ci    const BOOL b = SaveMode ?
250370b324cSopenharmony_ci        ::GetSaveFileNameW((LPOPENFILENAMEW)(void *)&p) :
251370b324cSopenharmony_ci        ::GetOpenFileNameW((LPOPENFILENAMEW)(void *)&p);
252370b324cSopenharmony_ci    /* DOCs: lpstrFile :
253370b324cSopenharmony_ci        if the buffer is too small, then:
254370b324cSopenharmony_ci        - the function returns FALSE
255370b324cSopenharmony_ci        - the CommDlgExtendedError() returns FNERR_BUFFERTOOSMALL
256370b324cSopenharmony_ci        - the first two bytes of the lpstrFile buffer contain the
257370b324cSopenharmony_ci          required size, in bytes or characters. */
258370b324cSopenharmony_ci    if (!b)
259370b324cSopenharmony_ci      return false;
260370b324cSopenharmony_ci    {
261370b324cSopenharmony_ci      tempPath.ReleaseBuf_CalcLen(bufSize);
262370b324cSopenharmony_ci      FilePath = tempPath;
263370b324cSopenharmony_ci      FilterIndex = (int)p.nFilterIndex - 1;
264370b324cSopenharmony_ci      return true;
265370b324cSopenharmony_ci    }
266370b324cSopenharmony_ci  }
267370b324cSopenharmony_ci}
268370b324cSopenharmony_ci
269370b324cSopenharmony_ci}
270