ReactOS 0.4.16-dev-252-g9ccafe8
itemdlg.c
Go to the documentation of this file.
1/*
2 * Common Item Dialog
3 *
4 * Copyright 2010,2011 David Hedberg
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#ifndef __REACTOS__ /* Win 7 */
22
23#include <stdarg.h>
24
25#define COBJMACROS
26#define NONAMELESSUNION
27
28#include "windef.h"
29#include "winbase.h"
30#include "winuser.h"
31#include "wingdi.h"
32#include "winreg.h"
33#include "shlwapi.h"
34
35#include "commdlg.h"
36#include "cdlg.h"
37#include "filedlgbrowser.h"
38
39#include "wine/debug.h"
40#include "wine/list.h"
41
42#define IDC_NAV_TOOLBAR 200
43#define IDC_NAVBACK 201
44#define IDC_NAVFORWARD 202
45
46#include <initguid.h>
47/* This seems to be another version of IID_IFileDialogCustomize. If
48 * there is any difference I have yet to find it. */
49DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F);
50
52
53static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0};
54static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0};
55static const WCHAR radiobuttonlistW[] = {'R','a','d','i','o','B','u','t','t','o','n','L','i','s','t',0};
56
60};
61
73};
74
75typedef struct cctrl_item {
78 CDCONTROLSTATEF cdcstate;
80 struct list entry;
82
83typedef struct {
84 HWND hwnd, wrapper_hwnd;
87 CDCONTROLSTATEF cdcstate;
88 struct list entry;
89
90 struct list sub_cctrls;
91 struct list sub_cctrls_entry;
92 struct list sub_items;
94
95typedef struct {
96 struct list entry;
100
101typedef struct FileDialogImpl {
103 union {
104 IFileOpenDialog IFileOpenDialog_iface;
106 } u;
108 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
112 IFileDialogCustomize IFileDialogCustomize_iface;
114
115 FILEOPENDIALOGOPTIONS options;
119
122
123 IShellItemArray *psia_selection;
124 IShellItemArray *psia_results;
128
132
139
143 struct list cctrls;
146
152
155
156/**************************************************************************
157 * Event wrappers.
158 */
160{
162 HRESULT hr = S_OK;
163 TRACE("%p\n", This);
164
166 {
167 TRACE("Notifying %p\n", cursor);
168 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
169 if(FAILED(hr) && hr != E_NOTIMPL)
170 break;
171 }
172
173 if(hr == E_NOTIMPL)
174 hr = S_OK;
175
176 return hr;
177}
178
180{
182 HRESULT hr = S_OK;
183 TRACE("%p (%p)\n", This, folder);
184
186 {
187 TRACE("Notifying %p\n", cursor);
188 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
189 if(FAILED(hr) && hr != E_NOTIMPL)
190 break;
191 }
192
193 if(hr == E_NOTIMPL)
194 hr = S_OK;
195
196 return hr;
197}
198
200{
202 TRACE("%p\n", This);
203
205 {
206 TRACE("Notifying %p\n", cursor);
207 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
208 }
209}
210
212{
214 TRACE("%p\n", This);
215
217 {
218 TRACE("Notifying %p\n", cursor);
219 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
220 }
221}
222
224{
226 TRACE("%p\n", This);
227
229 {
230 TRACE("Notifying %p\n", cursor);
231 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
232 }
233}
234
236{
238 HRESULT hr = S_OK;
240 TRACE("%p %p\n", This, shellitem);
241
243 {
244 TRACE("Notifying %p\n", cursor);
245 hr = IFileDialogEvents_OnOverwrite(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, shellitem, &response);
246 TRACE("<-- hr=%x response=%u\n", hr, response);
247 if(FAILED(hr) && hr != E_NOTIMPL)
248 break;
249 }
250
251 if(hr == E_NOTIMPL)
252 hr = S_OK;
253
254 if(SUCCEEDED(hr))
255 {
256 if (response == FDEOR_DEFAULT)
257 {
258 WCHAR buf[100];
259 int answer;
260
262 answer = MessageBoxW(This->dlg_hwnd, buf, This->custom_title,
264 if (answer == IDNO || answer == IDCANCEL)
265 {
266 hr = E_FAIL;
267 }
268 }
269 else if (response == FDEOR_REFUSE)
270 hr = E_FAIL;
271 }
272
273 return hr;
274}
275
276static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
277{
278 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
279}
280
282{
284 TRACE("%p\n", This);
285
287 {
288 IFileDialogControlEvents *pfdce;
289 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
290 {
291 TRACE("Notifying %p\n", cursor);
292 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
293 IFileDialogControlEvents_Release(pfdce);
294 }
295 }
296
297 return S_OK;
298}
299
301{
303 TRACE("%p %i %i\n", This, ctl_id, item_id);
304
306 {
307 IFileDialogControlEvents *pfdce;
308 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
309 {
310 TRACE("Notifying %p\n", cursor);
311 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
312 IFileDialogControlEvents_Release(pfdce);
313 }
314 }
315
316 return S_OK;
317}
318
320{
322 TRACE("%p\n", This);
323
325 {
326 IFileDialogControlEvents *pfdce;
327 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
328 {
329 TRACE("Notifying %p\n", cursor);
330 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
331 IFileDialogControlEvents_Release(pfdce);
332 }
333 }
334
335 return S_OK;
336}
337
339 DWORD ctl_id)
340{
342 TRACE("%p\n", This);
343
345 {
346 IFileDialogControlEvents *pfdce;
347 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
348 {
349 TRACE("Notifying %p\n", cursor);
350 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
351 IFileDialogControlEvents_Release(pfdce);
352 }
353 }
354
355 return S_OK;
356}
357
358/**************************************************************************
359 * Helper functions.
360 */
362{
363 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
364 UINT len;
365
366 if(!hwnd_edit)
367 {
368 if(This->set_filename)
369 {
370 len = lstrlenW(This->set_filename);
371 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
372 lstrcpyW(*str, This->set_filename);
373 return len;
374 }
375 return 0;
376 }
377
378 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
379 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
380 if(!*str)
381 return 0;
382
383 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
384 return len;
385}
386
388{
389 if(This->set_filename)
390 LocalFree(This->set_filename);
391
392 This->set_filename = str ? StrDupW(str) : NULL;
393
394 return SetDlgItemTextW(This->dlg_hwnd, IDC_FILENAME, This->set_filename);
395}
396
398{
399 IShellItem *psi;
400 LPWSTR *names;
401 HRESULT hr;
402 UINT item_count, valid_count;
403 UINT len_total, i;
404
405 if(!This->psia_selection)
406 return;
407
408 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
409 if(FAILED(hr) || !item_count)
410 return;
411
412 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
413
414 /* Get names of the selected items */
415 valid_count = 0; len_total = 0;
416 for(i = 0; i < item_count; i++)
417 {
418 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
419 if(SUCCEEDED(hr))
420 {
421 UINT attr;
422
423 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
424 if(SUCCEEDED(hr) &&
425 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
426 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
427 continue;
428
429 hr = IShellItem_GetDisplayName(psi, (This->options & FOS_PICKFOLDERS) ? SIGDN_FILESYSPATH : SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
430 if(SUCCEEDED(hr))
431 {
432 len_total += lstrlenW(names[valid_count]) + 3;
433 valid_count++;
434 }
435 IShellItem_Release(psi);
436 }
437 }
438
439 if(valid_count == 1)
440 {
443 }
444 else if(valid_count > 1)
445 {
446 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
447 LPWSTR cur_point = string;
448
449 for(i = 0; i < valid_count; i++)
450 {
451 LPWSTR file = names[i];
452 *cur_point++ = '\"';
453 lstrcpyW(cur_point, file);
454 cur_point += lstrlenW(file);
455 *cur_point++ = '\"';
456 *cur_point++ = ' ';
458 }
459 *(cur_point-1) = '\0';
460
461 set_file_name(This, string);
462 HeapFree(GetProcessHeap(), 0, string);
463 }
464
466 return;
467}
468
470{
471 WCHAR *endpos, *ext;
472
473 lstrcpyW(buf, spec);
474 if( (endpos = StrChrW(buf, ';')) )
475 *endpos = '\0';
476
478 if(StrChrW(ext, '*'))
479 return NULL;
480
481 return ext;
482}
483
485{
487 HRESULT hr;
488 BOOL result;
489
490 hr = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &filename);
491 if (SUCCEEDED(hr))
492 {
493 /* FIXME: Implement SFGAO_VALIDATE in Wine and use it instead. */
496 }
497 else
498 {
499 SFGAOF attributes;
500 result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes));
501 }
502
503 return result;
504}
505
507{
508 IShellFolder *psf_parent, *psf_desktop;
509 LPITEMIDLIST *pidla;
510 LPITEMIDLIST current_folder;
511 LPWSTR fn_iter, files = NULL, tmp_files;
512 UINT file_count = 0, len, i;
513 int open_action;
514 HRESULT hr, ret = E_FAIL;
515
516 len = get_file_name(This, &tmp_files);
517 if(len)
518 {
519 UINT size_used;
520 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
521 CoTaskMemFree(tmp_files);
522 }
523 if(!file_count) return E_FAIL;
524
525 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
526 if(FAILED(hr))
527 {
528 ERR("Failed to get pidl for current directory.\n");
529 HeapFree(GetProcessHeap(), 0, files);
530 return hr;
531 }
532
533 TRACE("Acting on %d file(s).\n", file_count);
534
535 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
536 open_action = ONOPEN_OPEN;
537 fn_iter = files;
538
539 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
540 {
541 WCHAR canon_filename[MAX_PATH];
542 psf_parent = NULL;
543
544 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
545
546 if( (This->options & FOS_NOVALIDATE) &&
547 !(This->options & FOS_FILEMUSTEXIST) )
548 open_action = ONOPEN_OPEN;
549 else
550 open_action = ONOPEN_BROWSE;
551
552 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
553 This->options & ~FOS_FILEMUSTEXIST,
554 (This->dlg_type == ITEMDLG_TYPE_SAVE),
555 open_action);
556
557 /* Add the proper extension */
558 if(open_action == ONOPEN_OPEN)
559 {
560 static const WCHAR dotW[] = {'.',0};
561
562 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
563 {
564 WCHAR extbuf[MAX_PATH], *newext = NULL;
565
566 if(This->filterspec_count)
567 {
568 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
569 }
570 else if(This->default_ext)
571 {
572 lstrcpyW(extbuf, dotW);
573 lstrcatW(extbuf, This->default_ext);
574 newext = extbuf;
575 }
576
577 if(newext)
578 {
579 WCHAR *ext = PathFindExtensionW(canon_filename);
580 if(lstrcmpW(ext, newext))
581 lstrcatW(canon_filename, newext);
582 }
583 }
584 else
585 {
586 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
587 !PathFileExistsW(canon_filename))
588 {
589 if(This->default_ext)
590 {
591 lstrcatW(canon_filename, dotW);
592 lstrcatW(canon_filename, This->default_ext);
593
594 if(!PathFileExistsW(canon_filename))
595 {
597 open_action = ONOPEN_BROWSE;
598 }
599 }
600 else
601 {
603 open_action = ONOPEN_BROWSE;
604 }
605 }
606 }
607 }
608
609 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
610
611 if(psf_parent && !(open_action == ONOPEN_BROWSE))
612 IShellFolder_Release(psf_parent);
613
614 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
615 }
616
617 HeapFree(GetProcessHeap(), 0, files);
618 ILFree(current_folder);
619
620 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
621 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
622
623 switch(open_action)
624 {
625 case ONOPEN_SEARCH:
626 FIXME("Filtering not implemented.\n");
627 break;
628
629 case ONOPEN_BROWSE:
630 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
631 if(FAILED(hr))
632 ERR("Failed to browse to directory: %08x\n", hr);
633
634 IShellFolder_Release(psf_parent);
635 break;
636
637 case ONOPEN_OPEN:
638 hr = SHGetDesktopFolder(&psf_desktop);
639 if(SUCCEEDED(hr))
640 {
641 if(This->psia_results)
642 {
643 IShellItemArray_Release(This->psia_results);
644 This->psia_results = NULL;
645 }
646
647 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
648 &This->psia_results);
649
650 IShellFolder_Release(psf_desktop);
651
652 if(FAILED(hr))
653 break;
654
655 if(This->options & FOS_PICKFOLDERS)
656 {
657 SFGAOF attributes;
658 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
659 if(hr != S_OK)
660 {
661 WCHAR buf[64];
663
664 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
665
666 IShellItemArray_Release(This->psia_results);
667 This->psia_results = NULL;
668 break;
669 }
670 }
671
672 if((This->options & FOS_OVERWRITEPROMPT) && This->dlg_type == ITEMDLG_TYPE_SAVE)
673 {
674 IShellItem *shellitem;
675
676 for (i=0; SUCCEEDED(hr) && i<file_count; i++)
677 {
678 hr = IShellItemArray_GetItemAt(This->psia_results, i, &shellitem);
679 if (SUCCEEDED(hr))
680 {
681 if (shell_item_exists(shellitem))
682 hr = events_OnOverwrite(This, shellitem);
683
684 IShellItem_Release(shellitem);
685 }
686 }
687
688 if (FAILED(hr))
689 break;
690 }
691
693 ret = S_OK;
694 }
695 break;
696
697 default:
698 ERR("Failed.\n");
699 break;
700 }
701
702 /* Clean up */
703 for(i = 0; i < file_count; i++)
704 ILFree(pidla[i]);
705 HeapFree(GetProcessHeap(), 0, pidla);
706
707 /* Success closes the dialog */
708 return ret;
709}
710
712{
713 HWND open_hwnd;
714 RECT open_rc;
715 MSG msg;
716
717 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
718
719 GetWindowRect(open_hwnd, &open_rc);
720
721 if (TrackPopupMenu(This->hmenu_opendropdown, 0, open_rc.left, open_rc.bottom, 0, This->dlg_hwnd, NULL) &&
722 PeekMessageW(&msg, This->dlg_hwnd, WM_MENUCOMMAND, WM_MENUCOMMAND, PM_REMOVE))
723 {
724 MENUITEMINFOW mii;
725
726 This->opendropdown_has_selection = TRUE;
727
728 mii.cbSize = sizeof(mii);
729 mii.fMask = MIIM_ID;
730 GetMenuItemInfoW((HMENU)msg.lParam, msg.wParam, TRUE, &mii);
731 This->opendropdown_selection = mii.wID;
732
734 EndDialog(This->dlg_hwnd, S_OK);
735 else
736 This->opendropdown_has_selection = FALSE;
737 }
738}
739
740/**************************************************************************
741 * Control item functions.
742 */
743
745{
746 DestroyWindow(item->hwnd);
747 HeapFree(GetProcessHeap(), 0, item->label);
749}
750
751static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position)
752{
753 DWORD dummy;
755
756 if (!position) position = &dummy;
757
758 *position = 0;
759
761 {
762 if (item->id == itemid)
763 return item;
764
765 if ((item->cdcstate & visible_flags) == visible_flags)
766 (*position)++;
767 }
768
769 return NULL;
770}
771
773{
775
777 {
778 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
779 return item;
780 }
781
782 return NULL;
783}
784
786{
788 LPWSTR label_copy;
789
790 if (get_item(parent, itemid, 0, NULL))
791 return E_INVALIDARG;
792
793 item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item));
794 label_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(label)+1)*sizeof(WCHAR));
795
796 if (!item || !label_copy)
797 {
799 HeapFree(GetProcessHeap(), 0, label_copy);
800 return E_OUTOFMEMORY;
801 }
802
803 item->id = itemid;
804 item->parent_id = parent->id;
805 lstrcpyW(label_copy, label);
806 item->label = label_copy;
807 item->cdcstate = CDCS_VISIBLE|CDCS_ENABLED;
808 item->hwnd = NULL;
809 list_add_tail(&parent->sub_items, &item->entry);
810
811 *result = item;
812
813 return S_OK;
814}
815
816/**************************************************************************
817 * Control functions.
818 */
820{
821 customctrl *ctrl, *sub_ctrl;
822
824 {
825 if(ctrl->dlgid == dlgid)
826 return ctrl;
827
828 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
829 if(sub_ctrl->dlgid == dlgid)
830 return sub_ctrl;
831 }
832
833 ERR("Failed to find control with dialog id %d\n", dlgid);
834 return NULL;
835}
836
838{
839 customctrl *ctrl, *sub_ctrl;
840
842 {
843 if(ctrl->id == ctlid)
844 return ctrl;
845
846 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
847 if(sub_ctrl->id == ctlid)
848 return sub_ctrl;
849 }
850
851 if (This->hmenu_opendropdown && This->cctrl_opendropdown.id == ctlid)
852 return &This->cctrl_opendropdown;
853
854 TRACE("No existing control with control id %d\n", ctlid);
855 return NULL;
856}
857
858static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
859{
860 LPWSTR text;
861 UINT len, final_width;
862 UINT lines, final_height;
863 SIZE size;
864 RECT rc;
865 HDC hdc;
866 WCHAR *c;
867 HFONT font;
868
869 TRACE("\n");
870
871 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
872 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
873 if(!text) return;
875
876 hdc = GetDC(hctrl);
877 font = (HFONT)SendMessageW(hctrl, WM_GETFONT, 0, 0);
881 ReleaseDC(hctrl, hdc);
882
883 if(len && multiline)
884 {
885 /* FIXME: line-wrap */
886 for(lines = 1, c = text; *c != '\0'; c++)
887 if(*c == '\n') lines++;
888
889 final_height = size.cy*lines + 2*4;
890 }
891 else
892 {
893 GetWindowRect(hctrl, &rc);
894 final_height = rc.bottom - rc.top;
895 }
896
897 final_width = min(max(size.cx, min_width) + 4, max_width);
898 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
900
902}
903
905 RECT rc;
906 GetWindowRect(ctrl->wrapper_hwnd, &rc);
907 return rc.bottom - rc.top;
908}
909
911{
912 customctrl *sub_cur1, *sub_cur2;
913 cctrl_item *item_cur1, *item_cur2;
914
915 TRACE("Freeing control %p\n", ctrl);
916 if(ctrl->type == IDLG_CCTRL_MENU)
917 {
918 TBBUTTON tbb;
919 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
921 }
922
923 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
924 {
925 list_remove(&sub_cur1->sub_cctrls_entry);
926 ctrl_free(sub_cur1);
927 }
928
929 LIST_FOR_EACH_ENTRY_SAFE(item_cur1, item_cur2, &ctrl->sub_items, cctrl_item, entry)
930 {
931 list_remove(&item_cur1->entry);
932 item_free(item_cur1);
933 }
934
935 DestroyWindow(ctrl->hwnd);
937}
938
940{
941 RECT rc;
942 UINT total_height;
943 UINT max_width, size;
944 customctrl *sub_ctrl;
945
946 switch(ctrl->type)
947 {
951 case IDLG_CCTRL_TEXT:
952 size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
953 ctrl_resize(ctrl->hwnd, size, size, TRUE);
954 GetWindowRect(ctrl->hwnd, &rc);
955 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
957 break;
959 total_height = 0;
960 ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
961
962 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
963 {
964 customctrl_resize(This, sub_ctrl);
965 SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
967
968 total_height += ctrl_get_height(sub_ctrl);
969 }
970
971 /* The label should be right adjusted */
972 {
974
975 GetWindowRect(ctrl->hwnd, &rc);
976 width = rc.right - rc.left;
977 height = rc.bottom - rc.top;
978
979 SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
980 }
981
982 /* Resize the wrapper window to fit all the sub controls */
983 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
985 break;
987 {
989
990 total_height = 0;
991 max_width = 0;
992
994 {
995 size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
996 ctrl_resize(item->hwnd, size, size, TRUE);
997 SetWindowPos(item->hwnd, NULL, 0, total_height, 0, 0,
999
1000 GetWindowRect(item->hwnd, &rc);
1001
1002 total_height += rc.bottom - rc.top;
1003 max_width = max(rc.right - rc.left, max_width);
1004 }
1005
1006 SetWindowPos(ctrl->hwnd, NULL, 0, 0, max_width, total_height,
1008
1009 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, max_width, total_height,
1011
1012 break;
1013 }
1014 case IDLG_CCTRL_EDITBOX:
1016 case IDLG_CCTRL_MENU:
1018 /* Nothing */
1019 break;
1020 }
1021}
1022
1024{
1025 FileDialogImpl *This = crs->lpCreateParams;
1026 TRACE("%p\n", This);
1027
1029 return TRUE;
1030}
1031
1033{
1035
1036 TRACE("%p, %lx\n", This, wparam);
1037
1038 if(ctrl)
1039 {
1040 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
1041 {
1042 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
1044 }
1045 else
1047 }
1048
1049 return TRUE;
1050}
1051
1053{
1055 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
1056
1057 if(ctrl)
1058 {
1059 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
1060 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
1061
1063 }
1064 return TRUE;
1065}
1066
1068{
1069 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
1071 POINT pt = { 0, nmtb->rcButton.bottom };
1072 TBBUTTON tbb;
1073 UINT idcmd;
1074
1075 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
1076
1077 if(ctrl)
1078 {
1080
1081 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1082 ClientToScreen(ctrl->hwnd, &pt);
1083 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
1084 if(idcmd)
1086 }
1087
1088 return TBDDRET_DEFAULT;
1089}
1090
1092{
1093 switch(HIWORD(wparam))
1094 {
1097 }
1098
1099 return FALSE;
1100}
1101
1103{
1104 NMHDR *nmhdr = (NMHDR*)lparam;
1105
1106 switch(nmhdr->code)
1107 {
1109 }
1110
1111 return FALSE;
1112}
1113
1115{
1118 HWND hwnd_child;
1119 RECT rc;
1120
1121 switch(message)
1122 {
1126 case WM_SIZE:
1127 hwnd_child = GetPropW(hwnd, notifysink_childW);
1129 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
1130 {
1131 GetClientRect(hwnd, &rc);
1133 }
1134 return TRUE;
1135 }
1136
1138}
1139
1141 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
1142 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
1143{
1144 HWND ns_hwnd, control_hwnd, parent_hwnd;
1147
1148 if(get_cctrl(This, id))
1149 return E_UNEXPECTED; /* Duplicate id */
1150
1151 if(This->cctrl_active_vg)
1152 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
1153 else
1154 parent_hwnd = This->cctrls_hwnd;
1155
1156 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
1157 0, 0, This->cctrl_width, height, parent_hwnd,
1158 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
1159 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
1160 0, 0, This->cctrl_width, height, ns_hwnd,
1161 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
1162
1163 if(!ns_hwnd || !control_hwnd)
1164 {
1165 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
1166 DestroyWindow(ns_hwnd);
1167 DestroyWindow(control_hwnd);
1168
1169 return E_FAIL;
1170 }
1171
1172 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
1173
1175 if(!ctrl)
1176 return E_OUTOFMEMORY;
1177
1178 ctrl->hwnd = control_hwnd;
1179 ctrl->wrapper_hwnd = ns_hwnd;
1180 ctrl->id = id;
1181 ctrl->dlgid = This->cctrl_next_dlgid;
1182 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
1183 list_init(&ctrl->sub_cctrls);
1184 list_init(&ctrl->sub_items);
1185
1186 if(This->cctrl_active_vg)
1187 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
1188 else
1189 list_add_tail(&This->cctrls, &ctrl->entry);
1190
1192
1193 if(ppctrl) *ppctrl = ctrl;
1194
1195 This->cctrl_next_dlgid++;
1196 return S_OK;
1197}
1198
1199/**************************************************************************
1200 * Container functions.
1201 */
1203{
1204 UINT container_height;
1205 UINT column_width;
1206 UINT nr_of_cols;
1207 UINT max_control_height, total_height = 0;
1208 UINT cur_col_pos, cur_row_pos;
1210 BOOL fits_height;
1211 UINT cspacing = MulDiv(90, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Columns are spaced with 90px */
1212 UINT rspacing = MulDiv(4, This->dpi_y, USER_DEFAULT_SCREEN_DPI); /* Rows are spaced with 4 px. */
1213
1214 /* Given the new width of the container, this function determines the
1215 * needed height of the container and places the controls according to
1216 * the new layout. Returns the new height.
1217 */
1218
1219 TRACE("%p\n", This);
1220
1221 column_width = This->cctrl_width + cspacing;
1222 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
1223
1224 /* We don't need to do anything unless the number of visible columns has changed. */
1225 if(nr_of_cols == This->cctrls_cols)
1226 {
1227 RECT rc;
1228 GetWindowRect(This->cctrls_hwnd, &rc);
1229 return rc.bottom - rc.top;
1230 }
1231
1232 This->cctrls_cols = nr_of_cols;
1233
1234 /* Get the size of the tallest control, and the total size of
1235 * all the controls to figure out the number of slots we need.
1236 */
1237 max_control_height = 0;
1239 {
1240 if(ctrl->cdcstate & CDCS_VISIBLE)
1241 {
1242 UINT control_height = ctrl_get_height(ctrl);
1243 max_control_height = max(max_control_height, control_height);
1244
1245 total_height += control_height + rspacing;
1246 }
1247 }
1248
1249 if(!total_height)
1250 return 0;
1251
1252 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1253 TRACE("Guess: container_height: %d\n",container_height);
1254
1255 /* Incrementally increase container_height until all the controls
1256 * fit.
1257 */
1258 do {
1259 UINT columns_needed = 1;
1260 cur_row_pos = 0;
1261
1262 fits_height = TRUE;
1264 {
1265 if(ctrl->cdcstate & CDCS_VISIBLE)
1266 {
1267 UINT control_height = ctrl_get_height(ctrl);
1268
1269 if(cur_row_pos + control_height > container_height)
1270 {
1271 if(++columns_needed > nr_of_cols)
1272 {
1273 container_height += 1;
1274 fits_height = FALSE;
1275 break;
1276 }
1277 cur_row_pos = 0;
1278 }
1279
1280 cur_row_pos += control_height + rspacing;
1281 }
1282 }
1283 } while(!fits_height);
1284
1285 TRACE("Final container height: %d\n", container_height);
1286
1287 /* Move the controls to their final destination
1288 */
1289 cur_col_pos = 0; cur_row_pos = 0;
1291 {
1292 if(ctrl->cdcstate & CDCS_VISIBLE)
1293 {
1294 RECT rc;
1295 UINT control_height, control_indent;
1296 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1297 control_height = rc.bottom - rc.top;
1298
1299 if(cur_row_pos + control_height > container_height)
1300 {
1301 cur_row_pos = 0;
1302 cur_col_pos += This->cctrl_width + cspacing;
1303 }
1304
1305
1306 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1307 control_indent = 0;
1308 else
1309 control_indent = This->cctrl_indent;
1310
1311 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1313
1314 cur_row_pos += control_height + rspacing;
1315 }
1316 }
1317
1318 /* Sanity check */
1319 if(cur_row_pos + This->cctrl_width > container_width)
1320 ERR("-- Failed to place controls properly.\n");
1321
1322 return container_height;
1323}
1324
1326{
1327 customctrl *sub_ctrl;
1329
1331
1332 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1333 {
1334 ctrl_set_font(sub_ctrl, font);
1335 }
1336
1337 if (ctrl->type == IDLG_CCTRL_RADIOBUTTONLIST)
1338 {
1340 {
1342 }
1343 }
1344}
1345
1347{
1348 LONG wndstyle;
1349
1350 if(parent)
1351 {
1353 HFONT font;
1354
1355 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1356 wndstyle &= ~(WS_POPUP);
1357 wndstyle |= WS_CHILD;
1358 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1359
1360 SetParent(This->cctrls_hwnd, parent);
1361 ShowWindow(This->cctrls_hwnd, TRUE);
1362
1363 /* Set the fonts to match the dialog font. */
1365 if(!font)
1366 ERR("Failed to get font handle from dialog.\n");
1367
1369 {
1372 }
1373 }
1374 else
1375 {
1376 ShowWindow(This->cctrls_hwnd, FALSE);
1377
1378 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1379 wndstyle &= ~(WS_CHILD);
1380 wndstyle |= WS_POPUP;
1381 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1382
1383 SetParent(This->cctrls_hwnd, NULL);
1384 }
1385}
1386
1388{
1389 FileDialogImpl *This = crs->lpCreateParams;
1390 TRACE("%p\n", This);
1391
1393 return TRUE;
1394}
1395
1397{
1398 customctrl *cur1, *cur2;
1399 TRACE("%p\n", This);
1400
1401 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1402 {
1403 list_remove(&cur1->entry);
1404 ctrl_free(cur1);
1405 }
1406
1407 return TRUE;
1408}
1409
1411{
1413
1414 switch(umessage)
1415 {
1418 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1419 }
1420
1421 return FALSE;
1422}
1423
1425{
1427
1429 {
1431 }
1432}
1433
1435{
1439 BOOL found_item=FALSE;
1440
1441 ctrl = get_cctrl_from_dlgid(This, ctrl_id);
1442
1443 if (!ctrl)
1444 {
1445 ERR("Can't find this control\n");
1446 return 0;
1447 }
1448
1450 {
1451 if (item->hwnd == child)
1452 {
1453 found_item = TRUE;
1454 break;
1455 }
1456 }
1457
1458 if (!found_item)
1459 {
1460 ERR("Can't find control item\n");
1461 return 0;
1462 }
1463
1465
1467
1468 return 0;
1469}
1470
1472{
1473 switch(HIWORD(wparam))
1474 {
1476 }
1477
1478 return FALSE;
1479}
1480
1482{
1484
1485 switch(message)
1486 {
1488 }
1489
1491}
1492
1494{
1495 WNDCLASSW wc;
1496 HDC hdc;
1497 static const WCHAR ctrl_container_classname[] =
1498 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1499
1501
1502 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1503 {
1506 wc.cbClsExtra = 0;
1507 wc.cbWndExtra = 0;
1509 wc.hIcon = 0;
1511 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1512 wc.lpszMenuName = NULL;
1513 wc.lpszClassName = ctrl_container_classname;
1514
1515 if(!RegisterClassW(&wc)) return E_FAIL;
1516 }
1517
1518 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1520 0, 0, 0, 0, NULL, 0,
1522 if(!This->cctrls_hwnd)
1523 return E_FAIL;
1524
1525 hdc = GetDC(This->cctrls_hwnd);
1526 This->dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
1527 This->dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
1528 ReleaseDC(This->cctrls_hwnd, hdc);
1529
1530 This->cctrl_width = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Controls have a fixed width */
1531 This->cctrl_indent = MulDiv(100, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1532 This->cctrl_def_height = MulDiv(23, This->dpi_y, USER_DEFAULT_SCREEN_DPI);
1533 This->cctrls_cols = 0;
1534
1535 This->cctrl_next_dlgid = 0x2000;
1536 list_init(&This->cctrls);
1537 This->cctrl_active_vg = NULL;
1538
1539 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1540
1541 /* Register class for */
1544 {
1547 wc.cbClsExtra = 0;
1548 wc.cbWndExtra = 0;
1550 wc.hIcon = 0;
1552 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1553 wc.lpszMenuName = NULL;
1555
1556 if (!RegisterClassW(&wc))
1557 ERR("Failed to register FloatNotifySink window class.\n");
1558 }
1559
1562 {
1565 wc.cbClsExtra = 0;
1566 wc.cbWndExtra = 0;
1568 wc.hIcon = 0;
1570 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1571 wc.lpszMenuName = NULL;
1573
1574 if (!RegisterClassW(&wc))
1575 ERR("Failed to register RadioButtonList window class.\n");
1576 }
1577
1578 return S_OK;
1579}
1580
1581/**************************************************************************
1582 * Window related functions.
1583 */
1585{
1586 /* Show or hide the open dropdown button as appropriate */
1587 BOOL show=FALSE, showing;
1588 HWND open_hwnd, dropdown_hwnd;
1589
1590 if (This->hmenu_opendropdown)
1591 {
1592 INT num_visible_items=0;
1594
1595 LIST_FOR_EACH_ENTRY(item, &This->cctrl_opendropdown.sub_items, cctrl_item, entry)
1596 {
1597 if (item->cdcstate & CDCS_VISIBLE)
1598 {
1599 num_visible_items++;
1600 if (num_visible_items >= 2)
1601 {
1602 show = TRUE;
1603 break;
1604 }
1605 }
1606 }
1607 }
1608
1609 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1610 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1611
1612 showing = (GetWindowLongPtrW(dropdown_hwnd, GWL_STYLE) & WS_VISIBLE) != 0;
1613
1614 if (showing != show)
1615 {
1616 RECT open_rc, dropdown_rc;
1617
1618 GetWindowRect(open_hwnd, &open_rc);
1619 GetWindowRect(dropdown_hwnd, &dropdown_rc);
1620
1621 if (show)
1622 {
1623 ShowWindow(dropdown_hwnd, SW_SHOW);
1624
1625 SetWindowPos(open_hwnd, NULL, 0, 0,
1626 (open_rc.right - open_rc.left) - (dropdown_rc.right - dropdown_rc.left),
1627 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1628 }
1629 else
1630 {
1631 ShowWindow(dropdown_hwnd, SW_HIDE);
1632
1633 SetWindowPos(open_hwnd, NULL, 0, 0,
1634 (open_rc.right - open_rc.left) + (dropdown_rc.right - dropdown_rc.left),
1635 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1636 }
1637 }
1638
1639 return show;
1640}
1641
1643{
1644 HDWP hdwp;
1645 HWND hwnd;
1646 RECT dialog_rc;
1647 RECT cancel_rc, dropdown_rc, open_rc;
1648 RECT filetype_rc, filename_rc, filenamelabel_rc;
1649 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1650 static const UINT vspacing = 4, hspacing = 4;
1651 static const UINT min_width = 320, min_height = 200;
1652 BOOL show_dropdown;
1653
1654 if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
1655 {
1656 TRACE("Invalid dialog window, not updating layout\n");
1657 return;
1658 }
1659
1660 if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
1661 {
1662 TRACE("Dialog size (%d, %d) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
1663 return;
1664 }
1665
1666 /****
1667 * Calculate the size of the dialog and all the parts.
1668 */
1669
1670 /* Cancel button */
1671 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1672 if(hwnd)
1673 {
1674 int cancel_width, cancel_height;
1675 GetWindowRect(hwnd, &cancel_rc);
1676 cancel_width = cancel_rc.right - cancel_rc.left;
1677 cancel_height = cancel_rc.bottom - cancel_rc.top;
1678
1679 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1680 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1681 cancel_rc.right = cancel_rc.left + cancel_width;
1682 cancel_rc.bottom = cancel_rc.top + cancel_height;
1683 }
1684
1685 /* Open/Save dropdown */
1686 show_dropdown = update_open_dropdown(This);
1687
1688 if(show_dropdown)
1689 {
1690 int dropdown_width, dropdown_height;
1691 hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1692
1693 GetWindowRect(hwnd, &dropdown_rc);
1694 dropdown_width = dropdown_rc.right - dropdown_rc.left;
1695 dropdown_height = dropdown_rc.bottom - dropdown_rc.top;
1696
1697 dropdown_rc.left = cancel_rc.left - dropdown_width - hspacing;
1698 dropdown_rc.top = cancel_rc.top;
1699 dropdown_rc.right = dropdown_rc.left + dropdown_width;
1700 dropdown_rc.bottom = dropdown_rc.top + dropdown_height;
1701 }
1702 else
1703 {
1704 dropdown_rc.left = dropdown_rc.right = cancel_rc.left - hspacing;
1705 dropdown_rc.top = cancel_rc.top;
1706 dropdown_rc.bottom = cancel_rc.bottom;
1707 }
1708
1709 /* Open/Save button */
1710 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1711 if(hwnd)
1712 {
1713 int open_width, open_height;
1714 GetWindowRect(hwnd, &open_rc);
1715 open_width = open_rc.right - open_rc.left;
1716 open_height = open_rc.bottom - open_rc.top;
1717
1718 open_rc.left = dropdown_rc.left - open_width;
1719 open_rc.top = dropdown_rc.top;
1720 open_rc.right = open_rc.left + open_width;
1721 open_rc.bottom = open_rc.top + open_height;
1722 }
1723
1724 /* The filetype combobox. */
1725 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1726 if(hwnd)
1727 {
1728 int filetype_width, filetype_height;
1729 GetWindowRect(hwnd, &filetype_rc);
1730
1731 filetype_width = filetype_rc.right - filetype_rc.left;
1732 filetype_height = filetype_rc.bottom - filetype_rc.top;
1733
1734 filetype_rc.right = cancel_rc.right;
1735
1736 filetype_rc.left = filetype_rc.right - filetype_width;
1737 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1738 filetype_rc.bottom = filetype_rc.top + filetype_height;
1739
1740 if(!This->filterspec_count)
1741 filetype_rc.left = filetype_rc.right;
1742 }
1743
1744 /* Filename label. */
1745 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1746 if(hwnd)
1747 {
1748 int filetypelabel_width, filetypelabel_height;
1749 GetWindowRect(hwnd, &filenamelabel_rc);
1750
1751 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1752 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1753
1754 filenamelabel_rc.left = 160; /* FIXME */
1755 filenamelabel_rc.top = filetype_rc.top;
1756 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1757 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1758 }
1759
1760 /* Filename edit box. */
1761 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1762 if(hwnd)
1763 {
1764 int filename_width, filename_height;
1765 GetWindowRect(hwnd, &filename_rc);
1766
1767 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1768 filename_height = filename_rc.bottom - filename_rc.top;
1769
1770 filename_rc.left = filenamelabel_rc.right + hspacing;
1771 filename_rc.top = filetype_rc.top;
1772 filename_rc.right = filename_rc.left + filename_width;
1773 filename_rc.bottom = filename_rc.top + filename_height;
1774 }
1775
1776 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1777 if(hwnd)
1778 {
1779 GetWindowRect(hwnd, &toolbar_rc);
1780 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1781 }
1782
1783 /* The custom controls */
1784 customctrls_rc.left = dialog_rc.left + hspacing;
1785 customctrls_rc.right = dialog_rc.right - hspacing;
1786 customctrls_rc.bottom = filename_rc.top - vspacing;
1787 customctrls_rc.top = customctrls_rc.bottom -
1788 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1789
1790 /* The ExplorerBrowser control. */
1791 ebrowser_rc.left = dialog_rc.left + hspacing;
1792 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1793 ebrowser_rc.right = dialog_rc.right - hspacing;
1794 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1795
1796 /****
1797 * Move everything to the right place.
1798 */
1799
1800 /* FIXME: The Save Dialog uses a slightly different layout. */
1801 hdwp = BeginDeferWindowPos(7);
1802
1803 if(hdwp && This->peb)
1804 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1805
1806 if(hdwp && This->cctrls_hwnd)
1807 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1808 customctrls_rc.left, customctrls_rc.top,
1809 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1811
1812 /* The default controls */
1813 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1814 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1816
1817 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1818 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1819 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1821
1822 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1823 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1825
1826 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1827 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1829
1830 if(hdwp && This->hmenu_opendropdown && (hwnd = GetDlgItem(This->dlg_hwnd, psh1)))
1831 DeferWindowPos(hdwp, hwnd, NULL, dropdown_rc.left, dropdown_rc.top, 0, 0,
1833
1834 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1835 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1837
1838 if(hdwp)
1839 EndDeferWindowPos(hdwp);
1840 else
1841 ERR("Failed to position dialog controls.\n");
1842
1843 return;
1844}
1845
1847{
1848 IShellItem *psi_folder;
1850 FOLDERSETTINGS fos;
1851 RECT rc = {0};
1852 HRESULT hr;
1853
1854 /* Create ExplorerBrowser instance */
1856
1857 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1858 &IID_IExplorerBrowser, (void**)&This->peb);
1859 if(FAILED(hr))
1860 {
1861 ERR("Failed to instantiate ExplorerBrowser control.\n");
1862 return hr;
1863 }
1864
1865 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES | EBO_NOBORDER);
1866
1867 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1868 if(FAILED(hr))
1869 {
1870 ERR("Failed to initialize the ExplorerBrowser control.\n");
1871 IExplorerBrowser_Release(This->peb);
1872 This->peb = NULL;
1873 return hr;
1874 }
1875 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1876 if(FAILED(hr))
1877 ERR("Advise (ExplorerBrowser) failed.\n");
1878
1879 /* Get previous options? */
1880 fos.ViewMode = fos.fFlags = 0;
1881 if(!(This->options & FOS_ALLOWMULTISELECT))
1882 fos.fFlags |= FWF_SINGLESEL;
1883
1884 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1885
1886 hr = IExplorerBrowser_QueryInterface(This->peb, &IID_IObjectWithSite, (void**)&client);
1887 if (hr == S_OK)
1888 {
1889 hr = IObjectWithSite_SetSite(client, (IUnknown*)&This->IFileDialog2_iface);
1890 IObjectWithSite_Release(client);
1891 if(FAILED(hr))
1892 ERR("SetSite failed, 0x%08x\n", hr);
1893 }
1894
1895 /* Browse somewhere */
1896 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1897 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1898
1899 return S_OK;
1900}
1901
1903{
1904 HWND htoolbar;
1905 TBADDBITMAP tbab;
1906 TBBUTTON button[2];
1907
1909 0, 0, 0, 0,
1911
1912 tbab.hInst = HINST_COMMCTRL;
1914 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1915
1916 button[0].iBitmap = HIST_BACK;
1917 button[0].idCommand = IDC_NAVBACK;
1918 button[0].fsState = TBSTATE_ENABLED;
1919 button[0].fsStyle = BTNS_BUTTON;
1920 button[0].dwData = 0;
1921 button[0].iString = 0;
1922
1923 button[1].iBitmap = HIST_FORWARD;
1924 button[1].idCommand = IDC_NAVFORWARD;
1925 button[1].fsState = TBSTATE_ENABLED;
1926 button[1].fsStyle = BTNS_BUTTON;
1927 button[1].dwData = 0;
1928 button[1].iString = 0;
1929
1930 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1931 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1932 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1933}
1934
1936{
1937 HWND hitem;
1938 LPCWSTR custom_okbutton;
1940 UINT min_width = MulDiv(50, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1941 UINT max_width = MulDiv(250, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1942
1943 if(This->custom_title)
1944 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1945
1946 if(This->hmenu_opendropdown && (item = get_first_item(&This->cctrl_opendropdown)))
1947 custom_okbutton = item->label;
1948 else
1949 custom_okbutton = This->custom_okbutton;
1950
1951 if(custom_okbutton &&
1952 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1953 {
1954 SetWindowTextW(hitem, custom_okbutton);
1955 ctrl_resize(hitem, min_width, max_width, FALSE);
1956 }
1957
1958 if(This->custom_cancelbutton &&
1959 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1960 {
1961 SetWindowTextW(hitem, This->custom_cancelbutton);
1962 ctrl_resize(hitem, min_width, max_width, FALSE);
1963 }
1964
1965 if(This->custom_filenamelabel &&
1966 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1967 {
1968 SetWindowTextW(hitem, This->custom_filenamelabel);
1969 ctrl_resize(hitem, min_width, max_width, FALSE);
1970 }
1971}
1972
1974{
1975 static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
1976 static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
1977
1978 if (umessage == WM_LBUTTONDOWN)
1979 {
1980 FileDialogImpl *This = GetPropW(hwnd, prop_this);
1981
1985
1986 return 0;
1987 }
1988
1989 return CallWindowProcW((WNDPROC)GetPropW(hwnd, prop_oldwndproc), hwnd, umessage, wparam, lparam);
1990}
1991
1993{
1995 HWND hitem;
1996
1997 TRACE("(%p, %p)\n", This, hwnd);
1998
2000 This->dlg_hwnd = hwnd;
2001
2002 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
2003 if(hitem) ShowWindow(hitem, SW_HIDE);
2004
2005 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
2006 if(hitem) ShowWindow(hitem, SW_HIDE);
2007
2008 /* Fill filetypes combobox, or hide it. */
2009 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
2010 if(This->filterspec_count)
2011 {
2012 HDC hdc;
2013 HFONT font;
2014 SIZE size;
2015 UINT i, maxwidth = 0;
2016
2017 hdc = GetDC(hitem);
2018 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
2020
2021 for(i = 0; i < This->filterspec_count; i++)
2022 {
2023 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
2024
2025 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
2026 maxwidth = max(maxwidth, size.cx);
2027 }
2028 ReleaseDC(hitem, hdc);
2029
2030 if(maxwidth > 0)
2031 {
2032 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
2033 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
2034 }
2035 else
2036 ERR("Failed to calculate width of filetype dropdown\n");
2037
2038 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
2039 }
2040 else
2041 ShowWindow(hitem, SW_HIDE);
2042
2043 if(This->set_filename &&
2044 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
2045 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
2046
2047 if(This->hmenu_opendropdown)
2048 {
2049 HWND dropdown_hwnd;
2050 LOGFONTW lfw, lfw_marlett;
2051 HFONT dialog_font;
2052 static const WCHAR marlett[] = {'M','a','r','l','e','t','t',0};
2053 static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
2054 static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
2055
2056 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
2057
2058 /* Change dropdown button font to Marlett */
2059 dialog_font = (HFONT)SendMessageW(dropdown_hwnd, WM_GETFONT, 0, 0);
2060
2061 GetObjectW(dialog_font, sizeof(lfw), &lfw);
2062
2063 memset(&lfw_marlett, 0, sizeof(lfw_marlett));
2064 lstrcpyW(lfw_marlett.lfFaceName, marlett);
2065 lfw_marlett.lfHeight = lfw.lfHeight;
2066 lfw_marlett.lfCharSet = SYMBOL_CHARSET;
2067
2068 This->hfont_opendropdown = CreateFontIndirectW(&lfw_marlett);
2069
2070 SendMessageW(dropdown_hwnd, WM_SETFONT, (LPARAM)This->hfont_opendropdown, 0);
2071
2072 /* Subclass button so we can handle LBUTTONDOWN */
2073 SetPropW(dropdown_hwnd, prop_this, This);
2074 SetPropW(dropdown_hwnd, prop_oldwndproc,
2076 }
2077
2078 ctrl_container_reparent(This, This->dlg_hwnd);
2083
2084 if(This->filterspec_count)
2086
2087 if ((hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)))
2088 SetFocus(hitem);
2089
2090 return FALSE;
2091}
2092
2094{
2096 return FALSE;
2097}
2098
2100{
2101 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
2102 TRACE("%p (%p)\n", This, mmi);
2103
2104 /* FIXME */
2105 mmi->ptMinTrackSize.x = 640;
2106 mmi->ptMinTrackSize.y = 480;
2107
2108 return FALSE;
2109}
2110
2112{
2113 TRACE("%p\n", This);
2114
2115 if(This->peb)
2116 {
2117 IExplorerBrowser_Destroy(This->peb);
2118 IExplorerBrowser_Release(This->peb);
2119 This->peb = NULL;
2120 }
2121
2123 This->dlg_hwnd = NULL;
2124
2125 DeleteObject(This->hfont_opendropdown);
2126 This->hfont_opendropdown = NULL;
2127
2128 return TRUE;
2129}
2130
2132{
2133 TRACE("%p\n", This);
2134
2136 EndDialog(This->dlg_hwnd, S_OK);
2137
2138 return FALSE;
2139}
2140
2142{
2143 TRACE("%p\n", This);
2144
2146
2147 return FALSE;
2148}
2149
2151{
2152 if(HIWORD(wparam) == BN_CLICKED)
2153 {
2154 HWND hwnd = (HWND)lparam;
2158 }
2159
2160 return FALSE;
2161}
2162
2164{
2165 TRACE("%p\n", This);
2166 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
2167 return FALSE;
2168}
2169
2171{
2172 TRACE("%p\n", This);
2173 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
2174 return FALSE;
2175}
2176
2178{
2180 {
2181 IShellView *psv;
2182 HRESULT hr;
2184 UINT prev_index = This->filetypeindex;
2185
2186 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
2187 TRACE("File type selection changed to %d.\n", This->filetypeindex);
2188
2189 if(prev_index == This->filetypeindex)
2190 return FALSE;
2191
2192 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
2193 if(SUCCEEDED(hr))
2194 {
2195 IShellView_Refresh(psv);
2196 IShellView_Release(psv);
2197 }
2198
2199 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
2200 {
2201 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
2202
2203 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
2204 if(ext)
2205 {
2207
2208 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
2210
2211 lstrcatW(buf, ext);
2213 }
2215 }
2216
2217 /* The documentation claims that OnTypeChange is called only
2218 * when the dialog is opened, but this is obviously not the
2219 * case. */
2221 }
2222
2223 return FALSE;
2224}
2225
2227{
2228 switch(LOWORD(wparam))
2229 {
2230 case IDOK: return on_idok(This);
2231 case IDCANCEL: return on_idcancel(This);
2233 case IDC_NAVBACK: return on_browse_back(This);
2236 default: TRACE("Unknown command.\n");
2237 }
2238 return FALSE;
2239}
2240
2242{
2244
2245 switch(umessage)
2246 {
2248 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
2249 case WM_SIZE: return on_wm_size(This);
2251 case WM_DESTROY: return on_wm_destroy(This);
2252 }
2253
2254 return FALSE;
2255}
2256
2258{
2259 INT_PTR res;
2260
2261 SetLastError(0);
2263 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
2265 This->dlg_hwnd = NULL;
2266 if(res == -1)
2267 {
2268 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
2269 return E_FAIL;
2270 }
2271
2272 TRACE("Returning 0x%08x\n", (HRESULT)res);
2273 return (HRESULT)res;
2274}
2275
2276/**************************************************************************
2277 * IFileDialog implementation
2278 */
2280{
2281 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
2282}
2283
2285 REFIID riid,
2286 void **ppvObject)
2287{
2289 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2290
2291 *ppvObject = NULL;
2293 IsEqualGUID(riid, &IID_IFileDialog) ||
2294 IsEqualGUID(riid, &IID_IFileDialog2))
2295 {
2296 *ppvObject = iface;
2297 }
2298 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
2299 {
2300 *ppvObject = &This->u.IFileOpenDialog_iface;
2301 }
2302 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
2303 {
2304 *ppvObject = &This->u.IFileSaveDialog_iface;
2305 }
2306 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
2307 {
2308 *ppvObject = &This->IExplorerBrowserEvents_iface;
2309 }
2310 else if(IsEqualGUID(riid, &IID_IServiceProvider))
2311 {
2312 *ppvObject = &This->IServiceProvider_iface;
2313 }
2314 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
2315 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
2316 IsEqualGUID(&IID_ICommDlgBrowser, riid))
2317 {
2318 *ppvObject = &This->ICommDlgBrowser3_iface;
2319 }
2320 else if(IsEqualGUID(&IID_IOleWindow, riid))
2321 {
2322 *ppvObject = &This->IOleWindow_iface;
2323 }
2324 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
2325 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
2326 {
2327 *ppvObject = &This->IFileDialogCustomize_iface;
2328 }
2329 else
2330 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
2331
2332 if(*ppvObject)
2333 {
2334 IUnknown_AddRef((IUnknown*)*ppvObject);
2335 return S_OK;
2336 }
2337
2338 return E_NOINTERFACE;
2339}
2340
2342{
2345 TRACE("%p - ref %d\n", This, ref);
2346
2347 return ref;
2348}
2349
2351{
2354 TRACE("%p - ref %d\n", This, ref);
2355
2356 if(!ref)
2357 {
2358 UINT i;
2359 for(i = 0; i < This->filterspec_count; i++)
2360 {
2361 LocalFree((void*)This->filterspecs[i].pszName);
2362 LocalFree((void*)This->filterspecs[i].pszSpec);
2363 }
2364 HeapFree(GetProcessHeap(), 0, This->filterspecs);
2365
2366 DestroyWindow(This->cctrls_hwnd);
2367
2368 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
2369 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
2370 if(This->psi_folder) IShellItem_Release(This->psi_folder);
2371 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
2372 if(This->psia_results) IShellItemArray_Release(This->psia_results);
2373
2374 LocalFree(This->set_filename);
2375 LocalFree(This->default_ext);
2376 LocalFree(This->custom_title);
2377 LocalFree(This->custom_okbutton);
2378 LocalFree(This->custom_cancelbutton);
2379 LocalFree(This->custom_filenamelabel);
2380
2381 DestroyMenu(This->hmenu_opendropdown);
2382 DeleteObject(This->hfont_opendropdown);
2383
2385 }
2386
2387 return ref;
2388}
2389
2391{
2393 TRACE("%p (%p)\n", iface, hwndOwner);
2394
2395 This->opendropdown_has_selection = FALSE;
2396
2397 return create_dialog(This, hwndOwner);
2398}
2399
2401 const COMDLG_FILTERSPEC *rgFilterSpec)
2402{
2404 UINT i;
2405 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
2406
2407 if(This->filterspecs)
2408 return E_UNEXPECTED;
2409
2410 if(!rgFilterSpec)
2411 return E_INVALIDARG;
2412
2413 if(!cFileTypes)
2414 return S_OK;
2415
2416 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
2417 for(i = 0; i < cFileTypes; i++)
2418 {
2419 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
2420 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
2421 }
2422 This->filterspec_count = cFileTypes;
2423
2424 return S_OK;
2425}
2426
2428{
2430 TRACE("%p (%d)\n", This, iFileType);
2431
2432 if(!This->filterspecs)
2433 return E_FAIL;
2434
2435 iFileType = max(iFileType, 1);
2436 iFileType = min(iFileType, This->filterspec_count);
2437 This->filetypeindex = iFileType-1;
2438
2439 return S_OK;
2440}
2441
2443{
2445 TRACE("%p (%p)\n", This, piFileType);
2446
2447 if(!piFileType)
2448 return E_INVALIDARG;
2449
2450 if(This->filterspec_count == 0)
2451 *piFileType = 0;
2452 else
2453 *piFileType = This->filetypeindex + 1;
2454
2455 return S_OK;
2456}
2457
2459{
2462 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
2463
2464 if(!pfde || !pdwCookie)
2465 return E_INVALIDARG;
2466
2468 client->pfde = pfde;
2469 client->cookie = ++This->events_next_cookie;
2470
2471 IFileDialogEvents_AddRef(pfde);
2472 *pdwCookie = client->cookie;
2473
2474 list_add_tail(&This->events_clients, &client->entry);
2475
2476 return S_OK;
2477}
2478
2480{
2482 events_client *client, *found = NULL;
2483 TRACE("%p (%d)\n", This, dwCookie);
2484
2486 {
2487 if(client->cookie == dwCookie)
2488 {
2489 found = client;
2490 break;
2491 }
2492 }
2493
2494 if(found)
2495 {
2496 list_remove(&found->entry);
2497 IFileDialogEvents_Release(found->pfde);
2498 HeapFree(GetProcessHeap(), 0, found);
2499 return S_OK;
2500 }
2501
2502 return E_INVALIDARG;
2503}
2504
2505static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
2506{
2508 TRACE("%p (0x%x)\n", This, fos);
2509
2510 if (fos & ~(FOS_OVERWRITEPROMPT | FOS_STRICTFILETYPES | FOS_NOCHANGEDIR | FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM
2511 | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_ALLOWMULTISELECT | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST
2512 | FOS_CREATEPROMPT | FOS_SHAREAWARE | FOS_NOREADONLYRETURN | FOS_NOTESTFILECREATE | FOS_HIDEMRUPLACES
2513 | FOS_HIDEPINNEDPLACES | FOS_NODEREFERENCELINKS | FOS_DONTADDTORECENT | FOS_FORCESHOWHIDDEN
2514 | FOS_DEFAULTNOMINIMODE | FOS_FORCEPREVIEWPANEON | FOS_SUPPORTSTREAMABLEITEMS))
2515 {
2516 WARN("Invalid option %#x\n", fos);
2517 return E_INVALIDARG;
2518 }
2519
2520 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
2521 {
2522 WCHAR buf[30];
2524 IFileDialog2_SetTitle(iface, buf);
2525 }
2526
2527 This->options = fos;
2528
2529 return S_OK;
2530}
2531
2532static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
2533{
2535 TRACE("%p (%p)\n", This, pfos);
2536
2537 if(!pfos)
2538 return E_INVALIDARG;
2539
2540 *pfos = This->options;
2541
2542 return S_OK;
2543}
2544
2546{
2548 TRACE("%p (%p)\n", This, psi);
2549 if(This->psi_defaultfolder)
2550 IShellItem_Release(This->psi_defaultfolder);
2551
2552 This->psi_defaultfolder = psi;
2553
2554 if(This->psi_defaultfolder)
2555 IShellItem_AddRef(This->psi_defaultfolder);
2556
2557 return S_OK;
2558}
2559
2561{
2563 TRACE("%p (%p)\n", This, psi);
2564 if(This->psi_setfolder)
2565 IShellItem_Release(This->psi_setfolder);
2566
2567 This->psi_setfolder = psi;
2568
2569 if(This->psi_setfolder)
2570 IShellItem_AddRef(This->psi_setfolder);
2571
2572 return S_OK;
2573}
2574
2576{
2578 TRACE("%p (%p)\n", This, ppsi);
2579 if(!ppsi)
2580 return E_INVALIDARG;
2581
2582 /* FIXME:
2583 If the dialog is shown, return the current(ly selected) folder. */
2584
2585 *ppsi = NULL;
2586 if(This->psi_folder)
2587 *ppsi = This->psi_folder;
2588 else if(This->psi_setfolder)
2589 *ppsi = This->psi_setfolder;
2590 else if(This->psi_defaultfolder)
2591 *ppsi = This->psi_defaultfolder;
2592
2593 if(*ppsi)
2594 {
2595 IShellItem_AddRef(*ppsi);
2596 return S_OK;
2597 }
2598
2599 return E_FAIL;
2600}
2601
2603{
2605 HRESULT hr;
2606 TRACE("%p (%p)\n", This, ppsi);
2607
2608 if(!ppsi)
2609 return E_INVALIDARG;
2610
2611 if(This->psia_selection)
2612 {
2613 /* FIXME: Check filename edit box */
2614 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2615 return hr;
2616 }
2617
2618 return E_FAIL;
2619}
2620
2622{
2624 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2625
2626 set_file_name(This, pszName);
2627
2628 return S_OK;
2629}
2630
2632{
2634 TRACE("%p (%p)\n", iface, pszName);
2635
2636 if(!pszName)
2637 return E_INVALIDARG;
2638
2639 *pszName = NULL;
2640 get_file_name(This, pszName);
2641 return *pszName ? S_OK : E_FAIL;
2642}
2643
2645{
2647 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2648
2649 LocalFree(This->custom_title);
2650 This->custom_title = StrDupW(pszTitle);
2652
2653 return S_OK;
2654}
2655
2657{
2659 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2660
2661 LocalFree(This->custom_okbutton);
2662 This->custom_okbutton = StrDupW(pszText);
2665
2666 return S_OK;
2667}
2668
2670{
2672 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2673
2674 LocalFree(This->custom_filenamelabel);
2675 This->custom_filenamelabel = StrDupW(pszLabel);
2678
2679 return S_OK;
2680}
2681
2683{
2685 HRESULT hr;
2686 TRACE("%p (%p)\n", This, ppsi);
2687
2688 if(!ppsi)
2689 return E_INVALIDARG;
2690
2691 if(This->psia_results)
2692 {
2693 UINT item_count;
2694 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2695 if(SUCCEEDED(hr))
2696 {
2697 if(item_count != 1)
2698 return E_FAIL;
2699
2700 /* Adds a reference. */
2701 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2702 }
2703
2704 return hr;
2705 }
2706
2707 return E_UNEXPECTED;
2708}
2709
2711{
2713 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2714 return S_OK;
2715}
2716
2718{
2720 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2721
2722 LocalFree(This->default_ext);
2723 This->default_ext = StrDupW(pszDefaultExtension);
2724
2725 return S_OK;
2726}
2727
2729{
2731 TRACE("%p (0x%08x)\n", This, hr);
2732
2733 if(This->dlg_hwnd)
2734 EndDialog(This->dlg_hwnd, hr);
2735
2736 return S_OK;
2737}
2738
2740{
2742 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2743 This->client_guid = *guid;
2744 return S_OK;
2745}
2746
2748{
2750 FIXME("stub - %p\n", This);
2751 return E_NOTIMPL;
2752}
2753
2755{
2757 FIXME("stub - %p (%p)\n", This, pFilter);
2758 return E_NOTIMPL;
2759}
2760
2762{
2764 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2765
2766 LocalFree(This->custom_cancelbutton);
2767 This->custom_cancelbutton = StrDupW(pszLabel);
2770
2771 return S_OK;
2772}
2773
2775{
2777 FIXME("stub - %p (%p)\n", This, psi);
2778 return E_NOTIMPL;
2779}
2780
2781static const IFileDialog2Vtbl vt_IFileDialog2 = {
2811};
2812
2813/**************************************************************************
2814 * IFileOpenDialog
2815 */
2816static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2817{
2818 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2819}
2820
2822 REFIID riid, void **ppvObject)
2823{
2825 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2826}
2827
2828static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2829{
2831 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2832}
2833
2834static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2835{
2837 return IFileDialog2_Release(&This->IFileDialog2_iface);
2838}
2839
2840static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2841{
2843 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2844}
2845
2846static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2847 const COMDLG_FILTERSPEC *rgFilterSpec)
2848{
2850 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2851}
2852
2853static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2854{
2856 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2857}
2858
2859static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2860{
2862 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2863}
2864
2865static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2866 DWORD *pdwCookie)
2867{
2869 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2870}
2871
2872static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2873{
2875 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2876}
2877
2878static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2879{
2881 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2882}
2883
2884static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2885{
2887 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2888}
2889
2891{
2893 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2894}
2895
2896static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2897{
2899 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2900}
2901
2902static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2903{
2905 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2906}
2907
2909{
2911 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2912}
2913
2914static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2915{
2917 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2918}
2919
2920static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2921{
2923 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2924}
2925
2926static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2927{
2929 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2930}
2931
2932static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2933{
2935 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2936}
2937
2938static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2939{
2941 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2942}
2943
2944static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2945{
2947 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2948}
2949
2950static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2951{
2953 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2954}
2955
2957 LPCWSTR pszDefaultExtension)
2958{
2960 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2961}
2962
2963static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2964{
2966 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2967}
2968
2970{
2972 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2973}
2974
2976{
2978 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2979}
2980
2981static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2982{
2984 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2985}
2986
2987static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2988{
2990 TRACE("%p (%p)\n", This, ppenum);
2991
2992 *ppenum = This->psia_results;
2993
2994 if(*ppenum)
2995 {
2996 IShellItemArray_AddRef(*ppenum);
2997 return S_OK;
2998 }
2999
3000 return E_FAIL;
3001}
3002
3003static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
3004{
3006 TRACE("%p (%p)\n", This, ppsai);
3007
3008 if(This->psia_selection)
3009 {
3010 *ppsai = This->psia_selection;
3011 IShellItemArray_AddRef(*ppsai);
3012 return S_OK;
3013 }
3014
3015 return E_FAIL;
3016}
3017
3018static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
3048};
3049
3050/**************************************************************************
3051 * IFileSaveDialog
3052 */
3054{
3055 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
3056}
3057
3059 REFIID riid,
3060 void **ppvObject)
3061{
3063 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3064}
3065
3067{
3069 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3070}
3071
3073{
3075 return IFileDialog2_Release(&This->IFileDialog2_iface);
3076}
3077
3079{
3081 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
3082}
3083
3085 const COMDLG_FILTERSPEC *rgFilterSpec)
3086{
3088 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
3089}
3090
3092{
3094 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
3095}
3096
3098{
3100 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
3101}
3102
3104 DWORD *pdwCookie)
3105{
3107 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
3108}
3109
3111{
3113 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
3114}
3115
3116static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
3117{
3119 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
3120}
3121
3122static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
3123{
3125 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
3126}
3127
3129{
3131 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
3132}
3133
3135{
3137 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
3138}
3139
3141{
3143 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
3144}
3145
3147{
3149 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
3150}
3151
3153{
3155 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
3156}
3157
3159{
3161 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
3162}
3163
3165{
3167 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
3168}
3169
3171{
3173 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
3174}
3175
3177{
3179 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
3180}
3181
3183{
3185 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
3186}
3187
3189{
3191 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
3192}
3193
3195 LPCWSTR pszDefaultExtension)
3196{
3198 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
3199}
3200
3202{
3204 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
3205}
3206
3208{
3210 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
3211}
3212
3214{
3216 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
3217}
3218
3220{
3222 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
3223}
3224
3226{
3228 FIXME("stub - %p (%p)\n", This, psi);
3229 return E_NOTIMPL;
3230}
3231
3233{
3235 FIXME("stub - %p (%p)\n", This, pStore);
3236 return E_NOTIMPL;
3237}
3238
3241 BOOL fAppendDefault)
3242{
3244 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
3245 return E_NOTIMPL;
3246}
3247
3249{
3251 FIXME("stub - %p (%p)\n", This, ppStore);
3252 return E_NOTIMPL;
3253}
3254
3256 IShellItem *psi,
3257 IPropertyStore *pStore,
3258 HWND hwnd,
3260{
3262 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
3263 return E_NOTIMPL;
3264}
3265
3266static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
3299};
3300
3301/**************************************************************************
3302 * IExplorerBrowserEvents implementation
3303 */
3304static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
3305{
3306 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
3307}
3308
3309static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
3310 REFIID riid, void **ppvObject)
3311{
3313 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
3314
3315 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3316}
3317
3318static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
3319{
3321 TRACE("%p\n", This);
3322 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3323}
3324
3325static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
3326{
3328 TRACE("%p\n", This);
3329 return IFileDialog2_Release(&This->IFileDialog2_iface);
3330}
3331
3333 PCIDLIST_ABSOLUTE pidlFolder)
3334{
3336 IShellItem *psi;
3337 HRESULT hr;
3338 TRACE("%p (%p)\n", This, pidlFolder);
3339
3340 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
3341 if(SUCCEEDED(hr))
3342 {
3344 IShellItem_Release(psi);
3345
3346 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
3347 if(hr == S_FALSE)
3348 hr = E_FAIL;
3349
3350 return hr;
3351 }
3352 else
3353 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
3354
3355 return S_OK;
3356}
3357
3358static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
3359 IShellView *psv)
3360{
3362 TRACE("%p (%p)\n", This, psv);
3363 return S_OK;
3364}
3365
3367 PCIDLIST_ABSOLUTE pidlFolder)
3368{
3370 HRESULT hr;
3371 TRACE("%p (%p)\n", This, pidlFolder);
3372
3373 if(This->psi_folder)
3374 IShellItem_Release(This->psi_folder);
3375
3376 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
3377 if(FAILED(hr))
3378 {
3379 ERR("Failed to get the current folder.\n");
3380 This->psi_folder = NULL;
3381 }
3382
3384
3385 return S_OK;
3386}
3387
3389 PCIDLIST_ABSOLUTE pidlFolder)
3390{
3392 TRACE("%p (%p)\n", This, pidlFolder);
3393 return S_OK;
3394}
3395
3396static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
3404};
3405
3406/**************************************************************************
3407 * IServiceProvider implementation
3408 */
3410{
3411 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
3412}
3413
3415 REFIID riid, void **ppvObject)
3416{
3418 TRACE("%p\n", This);
3419 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3420}
3421
3423{
3425 TRACE("%p\n", This);
3426 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3427}
3428
3430{
3432 TRACE("%p\n", This);
3433 return IFileDialog2_Release(&This->IFileDialog2_iface);
3434}
3435
3437 REFGUID guidService,
3438 REFIID riid, void **ppv)
3439{
3442 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
3443
3444 *ppv = NULL;
3445 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
3446 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
3447 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
3448 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
3449 else
3450 FIXME("Interface %s requested from unknown service %s\n",
3451 debugstr_guid(riid), debugstr_guid(guidService));
3452
3453 return hr;
3454}
3455
3456static const IServiceProviderVtbl vt_IServiceProvider = {
3461};
3462
3463/**************************************************************************
3464 * ICommDlgBrowser3 implementation
3465 */
3467{
3468 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
3469}
3470
3472 REFIID riid, void **ppvObject)
3473{
3475 TRACE("%p\n", This);
3476 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3477}
3478
3480{
3482 TRACE("%p\n", This);
3483 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3484}
3485
3487{
3489 TRACE("%p\n", This);
3490 return IFileDialog2_Release(&This->IFileDialog2_iface);
3491}
3492
3494 IShellView *shv)
3495{
3497 HRESULT hr;
3498 TRACE("%p (%p)\n", This, shv);
3499
3501
3502 if(SUCCEEDED(hr))
3503 EndDialog(This->dlg_hwnd, S_OK);
3504
3505 return S_OK;
3506}
3507
3509 IShellView *shv, ULONG uChange )
3510{
3512 IDataObject *new_selection;
3513 HRESULT hr;
3514 TRACE("%p (%p, %x)\n", This, shv, uChange);
3515
3516 switch(uChange)
3517 {
3518 case CDBOSC_SELCHANGE:
3519 if(This->psia_selection)
3520 {
3521 IShellItemArray_Release(This->psia_selection);
3522 This->psia_selection = NULL;
3523 }
3524
3525 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
3526 if(SUCCEEDED(hr))
3527 {
3528 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
3529 (void**)&This->psia_selection);
3530 if(SUCCEEDED(hr))
3531 {
3534 }
3535
3536 IDataObject_Release(new_selection);
3537 }
3538 break;
3539 default:
3540 TRACE("Unhandled state change\n");
3541 }
3542 return S_OK;
3543}
3544
3546 IShellView *shv, LPCITEMIDLIST pidl)
3547{
3549 IShellItem *psi;
3551 LPITEMIDLIST parent_pidl;
3552 HRESULT hr;
3553 ULONG attr;
3554 TRACE("%p (%p, %p)\n", This, shv, pidl);
3555
3556 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3557 return S_OK;
3558
3559 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3560 if(SUCCEEDED(hr))
3561 {
3562 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3563 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3564 ILFree(parent_pidl);
3565 ILFree(full_pidl);
3566 }
3567 if(FAILED(hr))
3568 {
3569 ERR("Failed to get shellitem (%08x).\n", hr);
3570 return S_OK;
3571 }
3572
3573 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3574 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3575 {
3576 IShellItem_Release(psi);
3577 return S_OK;
3578 }
3579
3580 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3581 {
3582 IShellItem_Release(psi);
3583 return S_FALSE;
3584 }
3585
3586 hr = S_OK;
3587 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3588 {
3589 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3590 hr = S_FALSE;
3592 }
3593
3594 IShellItem_Release(psi);
3595 return hr;
3596}
3597
3599 IShellView *ppshv, DWORD dwNotifyType)
3600{
3602 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
3603 return E_NOTIMPL;
3604}
3605
3607 IShellView *pshv,
3608 LPWSTR pszText, int cchMax)
3609{
3611 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3612 return E_NOTIMPL;
3613}
3614
3616{
3618 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3619 return E_NOTIMPL;
3620}
3621
3623 IShellView *pshv, int iColumn)
3624{
3626 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3627 return E_NOTIMPL;
3628}
3629
3631 LPWSTR pszFileSpec, int cchFileSpec)
3632{
3634 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3635 return E_NOTIMPL;
3636}
3637
3639 IShellView *pshv)
3640{
3642 FIXME("Stub: %p (%p)\n", This, pshv);
3643 return E_NOTIMPL;
3644}
3645
3646static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3659};
3660
3661/**************************************************************************
3662 * IOleWindow implementation
3663 */
3665{
3666 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3667}
3668
3670{
3672 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3673}
3674
3676{
3678 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3679}
3680
3682{
3684 return IFileDialog2_Release(&This->IFileDialog2_iface);
3685}
3686
3688{
3690 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3691 return E_NOTIMPL;
3692}
3693
3695{
3697 TRACE("%p (%p)\n", This, phwnd);
3698 *phwnd = This->dlg_hwnd;
3699 return S_OK;
3700}
3701
3702static const IOleWindowVtbl vt_IOleWindow = {
3708};
3709
3710/**************************************************************************
3711 * IFileDialogCustomize implementation
3712 */
3713static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3714{
3715 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3716}
3717
3718static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3719 REFIID riid, void **ppvObject)
3720{
3722 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3723}
3724
3725static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3726{
3728 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3729}
3730
3731static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3732{
3734 return IFileDialog2_Release(&This->IFileDialog2_iface);
3735}
3736
3738 DWORD dwIDCtl)
3739{
3741 MENUINFO mi;
3742 TRACE("%p (%d)\n", This, dwIDCtl);
3743
3744 if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl))
3745 return E_UNEXPECTED;
3746
3747 This->hmenu_opendropdown = CreatePopupMenu();
3748
3749 if (!This->hmenu_opendropdown)
3750 return E_OUTOFMEMORY;
3751
3752 mi.cbSize = sizeof(mi);
3753 mi.fMask = MIM_STYLE;
3754 mi.dwStyle = MNS_NOTIFYBYPOS;
3755 SetMenuInfo(This->hmenu_opendropdown, &mi);
3756
3757 This->cctrl_opendropdown.hwnd = NULL;
3758 This->cctrl_opendropdown.wrapper_hwnd = NULL;
3759 This->cctrl_opendropdown.id = dwIDCtl;
3760 This->cctrl_opendropdown.dlgid = 0;
3761 This->cctrl_opendropdown.type = IDLG_CCTRL_OPENDROPDOWN;
3762 This->cctrl_opendropdown.cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
3763 list_init(&This->cctrl_opendropdown.sub_cctrls);
3764 list_init(&This->cctrl_opendropdown.sub_items);
3765
3766 return S_OK;
3767}
3768
3769static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3770 DWORD dwIDCtl,
3771 LPCWSTR pszLabel)
3772{
3775 TBBUTTON tbb;
3776 HRESULT hr;
3777 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3778
3781 This->cctrl_def_height, &ctrl);
3782 if(SUCCEEDED(hr))
3783 {
3784 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3785 ctrl->type = IDLG_CCTRL_MENU;
3786
3787 /* Add the actual button with a popup menu. */
3788 tbb.iBitmap = I_IMAGENONE;
3790 tbb.iString = (DWORD_PTR)pszLabel;
3793 tbb.idCommand = 1;
3794
3795 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3796 }
3797
3798 return hr;
3799}
3800
3801static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3802 DWORD dwIDCtl,
3803 LPCWSTR pszLabel)
3804{
3807 HRESULT hr;
3808 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3809
3810 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3811 This->cctrl_def_height, &ctrl);
3812 if(SUCCEEDED(hr))
3814
3815 return hr;
3816}
3817
3818static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3819 DWORD dwIDCtl)
3820{
3823 HRESULT hr;
3824 TRACE("%p (%d)\n", This, dwIDCtl);
3825
3827 This->cctrl_def_height, &ctrl);
3828 if(SUCCEEDED(hr))
3829 ctrl->type = IDLG_CCTRL_COMBOBOX;
3830
3831 return hr;
3832}
3833
3835 DWORD dwIDCtl)
3836{
3839 HRESULT hr;
3840 TRACE("%p (%d)\n", This, dwIDCtl);
3841
3842 hr = cctrl_create_new(This, dwIDCtl,