|
1
|
1 #include "shared.h"
|
|
|
2 #include "filedialogs.h"
|
|
|
3 #include <shlobj.h>
|
|
|
4
|
|
|
5 #define dTEXT(X) pfc::stringcvt::string_os_from_utf8(X)
|
|
|
6
|
|
|
7 static UINT_PTR CALLBACK uGetOpenFileName_Hook(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
|
|
|
8 {
|
|
|
9 switch(msg) {
|
|
|
10 case WM_INITDIALOG:
|
|
|
11 {
|
|
|
12 OPENFILENAME * ofn = reinterpret_cast<OPENFILENAME*>(lp);
|
|
|
13 reinterpret_cast<modal_dialog_scope*>(ofn->lCustData)->initialize(FindOwningPopup(wnd));
|
|
|
14 }
|
|
|
15 return 0;
|
|
|
16 default:
|
|
|
17 return 0;
|
|
|
18 }
|
|
|
19 }
|
|
|
20
|
|
|
21 static void ImportExtMask(pfc::array_t<TCHAR> & out, const char * in) {
|
|
|
22 {
|
|
|
23 pfc::stringcvt::string_os_from_utf8 temp(in);
|
|
|
24 out.set_size(temp.length()+2);
|
|
|
25 out.fill_null();
|
|
|
26 pfc::memcpy_t(out.get_ptr(),temp.get_ptr(),temp.length());
|
|
|
27 }
|
|
|
28
|
|
|
29 for(t_size walk = 0; walk < out.get_size(); ++walk) {
|
|
|
30 if (out[walk] == '|') out[walk] = 0;
|
|
|
31 }
|
|
|
32 }
|
|
|
33
|
|
|
34 BOOL Vista_GetOpenFileName(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::string_base & p_filename,BOOL b_save);
|
|
|
35 BOOL Vista_GetOpenFileNameMulti(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::ptrholder_t<uGetOpenFileNameMultiResult> & out);
|
|
|
36 BOOL Vista_BrowseForFolder(HWND parent, const char * p_title, pfc::string_base & path);
|
|
|
37 puGetOpenFileNameMultiResult Vista_BrowseForFolderEx(HWND parent,const char * title, const char * initPath);
|
|
|
38
|
|
|
39 static bool UseVistaDialogs() {
|
|
|
40 #if FB2K_TARGET_MICROSOFT_STORE || _WIN32_WINNT >= 0x600
|
|
|
41 return true;
|
|
|
42 #else
|
|
|
43 return GetWindowsVersionCode() >= 0x600;
|
|
|
44 #endif
|
|
|
45 }
|
|
|
46
|
|
|
47 BOOL SHARED_EXPORT uGetOpenFileName(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::string_base & p_filename,BOOL b_save) {
|
|
|
48 TRACK_CALL_TEXT("uGetOpenFileName");
|
|
|
49 try {
|
|
|
50 if (UseVistaDialogs()) return Vista_GetOpenFileName(parent, p_ext_mask, def_ext_mask, p_def_ext, p_title, p_directory, p_filename, b_save);
|
|
|
51 } catch(pfc::exception_not_implemented const &) {}
|
|
|
52
|
|
|
53 modal_dialog_scope scope;
|
|
|
54
|
|
|
55 pfc::array_t<TCHAR> ext_mask;
|
|
|
56 ImportExtMask(ext_mask,p_ext_mask);
|
|
|
57
|
|
|
58 TCHAR buffer[4096];
|
|
|
59
|
|
|
60 pfc::stringToBuffer(buffer,pfc::stringcvt::string_os_from_utf8(p_filename));
|
|
|
61
|
|
|
62 pfc::stringcvt::string_os_from_utf8 def_ext(p_def_ext ? p_def_ext : ""),title(p_title ? p_title : ""),
|
|
|
63 directory(p_directory ? p_directory : "");
|
|
|
64
|
|
|
65 OPENFILENAME ofn = {};
|
|
|
66
|
|
|
67 ofn.lStructSize=sizeof(ofn);
|
|
|
68 ofn.hwndOwner = parent;
|
|
|
69 ofn.lpstrFilter = ext_mask.get_ptr();
|
|
|
70 ofn.nFilterIndex = def_ext_mask + 1;
|
|
|
71 ofn.lpstrFile = buffer;
|
|
|
72 ofn.lpstrInitialDir = directory;
|
|
|
73 ofn.nMaxFile = _countof(buffer);
|
|
|
74 ofn.Flags = b_save ? OFN_NOCHANGEDIR|OFN_EXPLORER|OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT|OFN_ENABLEHOOK|OFN_ENABLESIZING : OFN_NOCHANGEDIR|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_ENABLEHOOK|OFN_ENABLESIZING;
|
|
|
75 ofn.lpstrDefExt = *(const TCHAR*)def_ext ? (const TCHAR*)def_ext : 0;
|
|
|
76 ofn.lpstrTitle = *(const TCHAR*)title ? (const TCHAR*)title : 0;
|
|
|
77 ofn.lCustData = reinterpret_cast<LPARAM>(&scope);
|
|
|
78 ofn.lpfnHook = uGetOpenFileName_Hook;
|
|
|
79 if (b_save ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn))
|
|
|
80 {
|
|
|
81 buffer[_countof(buffer)-1]=0;
|
|
|
82
|
|
|
83 {
|
|
|
84 t_size ptr = _tcslen(buffer);
|
|
|
85 while(ptr>0 && buffer[ptr-1]==' ') buffer[--ptr] = 0;
|
|
|
86 }
|
|
|
87
|
|
|
88 p_filename = pfc::stringcvt::string_utf8_from_os(buffer,_countof(buffer));
|
|
|
89 return TRUE;
|
|
|
90 }
|
|
|
91 else return FALSE;
|
|
|
92 }
|
|
|
93
|
|
|
94
|
|
|
95 puGetOpenFileNameMultiResult SHARED_EXPORT uGetOpenFileNameMulti(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory) {
|
|
|
96 TRACK_CALL_TEXT("uGetOpenFileNameMulti");
|
|
|
97 try {
|
|
|
98 if (UseVistaDialogs()) {
|
|
|
99 pfc::ptrholder_t<uGetOpenFileNameMultiResult> result;
|
|
|
100 if (!Vista_GetOpenFileNameMulti(parent,p_ext_mask,def_ext_mask,p_def_ext,p_title,p_directory,result)) return NULL;
|
|
|
101 return result.detach();
|
|
|
102 }
|
|
|
103 } catch(pfc::exception_not_implemented const &) {}
|
|
|
104
|
|
|
105 modal_dialog_scope scope;
|
|
|
106
|
|
|
107 pfc::array_t<TCHAR> ext_mask;
|
|
|
108 ImportExtMask(ext_mask,p_ext_mask);
|
|
|
109
|
|
|
110 TCHAR buffer[0x4000];
|
|
|
111 buffer[0]=0;
|
|
|
112
|
|
|
113 pfc::stringcvt::string_os_from_utf8 def_ext(p_def_ext ? p_def_ext : ""),title(p_title ? p_title : ""),
|
|
|
114 directory(p_directory ? p_directory : "");
|
|
|
115
|
|
|
116 OPENFILENAME ofn = {};
|
|
|
117
|
|
|
118 ofn.lStructSize=sizeof(ofn);
|
|
|
119 ofn.hwndOwner = parent;
|
|
|
120 ofn.lpstrFilter = ext_mask.get_ptr();
|
|
|
121 ofn.nFilterIndex = def_ext_mask + 1;
|
|
|
122 ofn.lpstrFile = buffer;
|
|
|
123 ofn.lpstrInitialDir = directory;
|
|
|
124 ofn.nMaxFile = _countof(buffer);
|
|
|
125 ofn.Flags = OFN_NOCHANGEDIR|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLESIZING;
|
|
|
126 ofn.lpstrDefExt = *(const TCHAR*)def_ext ? (const TCHAR*)def_ext : 0;
|
|
|
127 ofn.lpstrTitle = *(const TCHAR*)title ? (const TCHAR*)title : 0;
|
|
|
128 ofn.lCustData = reinterpret_cast<LPARAM>(&scope);
|
|
|
129 ofn.lpfnHook = uGetOpenFileName_Hook;
|
|
|
130 if (GetOpenFileName(&ofn))
|
|
|
131 {
|
|
|
132 buffer[_countof(buffer)-1]=0;
|
|
|
133 buffer[_countof(buffer)-2]=0;
|
|
|
134
|
|
|
135 pfc::ptrholder_t<uGetOpenFileNameMultiResult_impl> result = new uGetOpenFileNameMultiResult_impl;
|
|
|
136
|
|
|
137 TCHAR * p=buffer;
|
|
|
138 while(*p) p++;
|
|
|
139 p++;
|
|
|
140 if (!*p)
|
|
|
141 {
|
|
|
142 {
|
|
|
143 t_size ptr = _tcslen(buffer);
|
|
|
144 while(ptr>0 && buffer[ptr-1]==' ') buffer[--ptr] = 0;
|
|
|
145 }
|
|
|
146
|
|
|
147 result->AddItem(pfc::stringcvt::string_utf8_from_os(buffer));
|
|
|
148 }
|
|
|
149 else
|
|
|
150 {
|
|
|
151 pfc::string_formatter s = (const char*) pfc::stringcvt::string_utf8_from_os(buffer,_countof(buffer));
|
|
|
152 t_size ofs = s.length();
|
|
|
153 if (ofs>0 && s[ofs-1]!='\\') {s.add_char('\\');ofs++;}
|
|
|
154 while(*p)
|
|
|
155 {
|
|
|
156 s.truncate(ofs);
|
|
|
157 s += pfc::stringcvt::string_utf8_from_os(p);
|
|
|
158 s.skip_trailing_char(' ');
|
|
|
159 result->AddItem(s);
|
|
|
160 while(*p) p++;
|
|
|
161 p++;
|
|
|
162 }
|
|
|
163 }
|
|
|
164 return result.detach();
|
|
|
165 }
|
|
|
166 else return 0;
|
|
|
167 }
|
|
|
168
|
|
|
169
|
|
|
170
|
|
|
171
|
|
|
172
|
|
|
173 struct browse_for_dir_struct
|
|
|
174 {
|
|
|
175 const TCHAR * m_initval;
|
|
|
176 const TCHAR * m_tofind;
|
|
|
177
|
|
|
178 modal_dialog_scope m_scope;
|
|
|
179 };
|
|
|
180
|
|
|
181 static bool file_exists(const TCHAR * p_path)
|
|
|
182 {
|
|
|
183 DWORD val = GetFileAttributes(p_path);
|
|
|
184 if (val == (-1) || (val & FILE_ATTRIBUTE_DIRECTORY)) return false;
|
|
|
185 return true;
|
|
|
186 }
|
|
|
187
|
|
|
188 static void browse_proc_check_okbutton(HWND wnd,const browse_for_dir_struct * p_struct,const TCHAR * p_path)
|
|
|
189 {
|
|
|
190 TCHAR temp[MAX_PATH+1];
|
|
|
191 pfc::stringToBuffer(temp, p_path);
|
|
|
192
|
|
|
193 t_size len = _tcslen(temp);
|
|
|
194 if (len < MAX_PATH && len > 0)
|
|
|
195 {
|
|
|
196 if (temp[len-1] != '\\')
|
|
|
197 temp[len++] = '\\';
|
|
|
198 }
|
|
|
199 t_size idx = 0;
|
|
|
200 while(p_struct->m_tofind[idx] && idx+len < MAX_PATH)
|
|
|
201 {
|
|
|
202 temp[len+idx] = p_struct->m_tofind[idx];
|
|
|
203 idx++;
|
|
|
204 }
|
|
|
205 temp[len+idx] = 0;
|
|
|
206
|
|
|
207 SendMessage(wnd,BFFM_ENABLEOK,0,!!file_exists(temp));
|
|
|
208
|
|
|
209 }
|
|
|
210
|
|
|
211 static int _stdcall browse_proc(HWND wnd,UINT msg,LPARAM lp,LPARAM dat)
|
|
|
212 {
|
|
|
213 browse_for_dir_struct * p_struct = reinterpret_cast<browse_for_dir_struct*>(dat);
|
|
|
214 switch(msg)
|
|
|
215 {
|
|
|
216 case BFFM_INITIALIZED:
|
|
|
217 p_struct->m_scope.initialize(wnd);
|
|
|
218 SendMessage(wnd,BFFM_SETSELECTION,1,(LPARAM)p_struct->m_initval);
|
|
|
219 if (p_struct->m_tofind) browse_proc_check_okbutton(wnd,p_struct,p_struct->m_initval);
|
|
|
220 break;
|
|
|
221 case BFFM_SELCHANGED:
|
|
|
222 if (p_struct->m_tofind)
|
|
|
223 {
|
|
|
224 if (lp != 0)
|
|
|
225 {
|
|
|
226 TCHAR temp[MAX_PATH+1];
|
|
|
227 if (SHGetPathFromIDList(reinterpret_cast<LPCITEMIDLIST>(lp),temp))
|
|
|
228 {
|
|
|
229 temp[MAX_PATH] = 0;
|
|
|
230 browse_proc_check_okbutton(wnd,p_struct,temp);
|
|
|
231 }
|
|
|
232 else
|
|
|
233 SendMessage(wnd,BFFM_ENABLEOK,0,FALSE);
|
|
|
234 }
|
|
|
235 else SendMessage(wnd,BFFM_ENABLEOK,0,FALSE);
|
|
|
236 }
|
|
|
237 break;
|
|
|
238 }
|
|
|
239 return 0;
|
|
|
240 }
|
|
|
241
|
|
|
242 static BOOL BrowseForFolderHelper(HWND p_parent,const TCHAR * p_title,TCHAR (&p_out)[MAX_PATH],const TCHAR * p_file_to_find)
|
|
|
243 {
|
|
|
244 pfc::com_ptr_t<IMalloc> mallocptr;
|
|
|
245
|
|
|
246 if (FAILED(SHGetMalloc(mallocptr.receive_ptr()))) return FALSE;
|
|
|
247 if (mallocptr.is_empty()) return FALSE;
|
|
|
248
|
|
|
249 browse_for_dir_struct data;
|
|
|
250 data.m_initval = p_out;
|
|
|
251 data.m_tofind = p_file_to_find;
|
|
|
252
|
|
|
253
|
|
|
254 BROWSEINFO bi=
|
|
|
255 {
|
|
|
256 p_parent,
|
|
|
257 0,
|
|
|
258 0,
|
|
|
259 p_title,
|
|
|
260 BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX,
|
|
|
261 browse_proc,
|
|
|
262 reinterpret_cast<LPARAM>(&data),
|
|
|
263 0
|
|
|
264 };
|
|
|
265
|
|
|
266 LPITEMIDLIST li = SHBrowseForFolder(&bi);
|
|
|
267 if (li == NULL) return FALSE;
|
|
|
268 BOOL state = SHGetPathFromIDList(li,p_out);
|
|
|
269 mallocptr->Free(li);
|
|
|
270 return state;
|
|
|
271 }
|
|
|
272
|
|
|
273 BOOL SHARED_EXPORT uBrowseForFolder(HWND parent,const char * p_title,pfc::string_base & out) {
|
|
|
274 TRACK_CALL_TEXT("uBrowseForFolder");
|
|
|
275 try {
|
|
|
276 if (UseVistaDialogs()) {
|
|
|
277 return Vista_BrowseForFolder(parent,p_title,out);
|
|
|
278 }
|
|
|
279 } catch(pfc::exception_not_implemented const &) {}
|
|
|
280
|
|
|
281 TCHAR temp[MAX_PATH];
|
|
|
282 pfc::stringToBuffer(temp,dTEXT(out));
|
|
|
283 BOOL rv = BrowseForFolderHelper(parent,dTEXT(p_title),temp,0);
|
|
|
284 if (rv) {
|
|
|
285 out = pfc::stringcvt::string_utf8_from_os(temp,_countof(temp));
|
|
|
286 }
|
|
|
287 return rv;
|
|
|
288 }
|
|
|
289
|
|
|
290 BOOL SHARED_EXPORT uBrowseForFolderWithFile(HWND parent,const char * title,pfc::string_base & out,const char * p_file_to_find)
|
|
|
291 {
|
|
|
292 TRACK_CALL_TEXT("uBrowseForFolderWithFile");
|
|
|
293 TCHAR temp[MAX_PATH];
|
|
|
294 pfc::stringToBuffer(temp,dTEXT(out));
|
|
|
295 BOOL rv = BrowseForFolderHelper(parent,dTEXT(title),temp,dTEXT(p_file_to_find));
|
|
|
296 if (rv) {
|
|
|
297 out = pfc::stringcvt::string_utf8_from_os(temp,_countof(temp));
|
|
|
298 }
|
|
|
299 return rv;
|
|
|
300 }
|
|
|
301
|
|
|
302
|
|
|
303 puGetOpenFileNameMultiResult SHARED_EXPORT uBrowseForFolderEx(HWND parent,const char * title, const char * initPath) {
|
|
|
304 TRACK_CALL_TEXT("uBrowseForFolderEx");
|
|
|
305 try {
|
|
|
306 if (UseVistaDialogs()) {
|
|
|
307 return Vista_BrowseForFolderEx(parent,title, initPath);
|
|
|
308 }
|
|
|
309 } catch(pfc::exception_not_implemented const &) {}
|
|
|
310
|
|
|
311 pfc::string8 temp;
|
|
|
312 if (initPath) temp = initPath;
|
|
|
313 if (!uBrowseForFolder(parent, title, temp)) return NULL;
|
|
|
314 pfc::ptrholder_t<uGetOpenFileNameMultiResult_impl> result = new uGetOpenFileNameMultiResult_impl;
|
|
|
315 result->AddItem(temp);
|
|
|
316 return result.detach();
|
|
|
317 }
|