comparison foosdk/sdk/foobar2000/shared/filedialogs.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
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 }