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 20extern bool g_IsNT; 21#endif 22 23namespace NWindows { 24 25/* 26 GetSaveFileName() 27 GetOpenFileName() 28 OPENFILENAME 29 30(lpstrInitialDir) : the initial directory. 31DOCs: 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 43Win10: 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 51WinXP-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 56in 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/* 67structures 68 OPENFILENAMEW 69 OPENFILENAMEA 70contain additional members: 71#if (_WIN32_WINNT >= 0x0500) 72 void *pvReserved; 73 DWORD dwReserved; 74 DWORD FlagsEx; 75#endif 76 77If we compile the source code with (_WIN32_WINNT >= 0x0500), some functions 78will not work at NT 4.0, if we use sizeof(OPENFILENAME). 79We 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 132bool 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