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. */ 49 DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F); 50 51 WINE_DEFAULT_DEBUG_CHANNEL(commdlg); 52 53 static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0}; 54 static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0}; 55 static const WCHAR radiobuttonlistW[] = {'R','a','d','i','o','B','u','t','t','o','n','L','i','s','t',0}; 56 57 enum ITEMDLG_TYPE { 58 ITEMDLG_TYPE_OPEN, 59 ITEMDLG_TYPE_SAVE 60 }; 61 62 enum ITEMDLG_CCTRL_TYPE { 63 IDLG_CCTRL_MENU, 64 IDLG_CCTRL_PUSHBUTTON, 65 IDLG_CCTRL_COMBOBOX, 66 IDLG_CCTRL_RADIOBUTTONLIST, 67 IDLG_CCTRL_CHECKBUTTON, 68 IDLG_CCTRL_EDITBOX, 69 IDLG_CCTRL_SEPARATOR, 70 IDLG_CCTRL_TEXT, 71 IDLG_CCTRL_OPENDROPDOWN, 72 IDLG_CCTRL_VISUALGROUP 73 }; 74 75 typedef struct cctrl_item { 76 DWORD id, parent_id; 77 LPWSTR label; 78 CDCONTROLSTATEF cdcstate; 79 HWND hwnd; 80 struct list entry; 81 } cctrl_item; 82 83 typedef struct { 84 HWND hwnd, wrapper_hwnd; 85 UINT id, dlgid; 86 enum ITEMDLG_CCTRL_TYPE type; 87 CDCONTROLSTATEF cdcstate; 88 struct list entry; 89 90 struct list sub_cctrls; 91 struct list sub_cctrls_entry; 92 struct list sub_items; 93 } customctrl; 94 95 typedef struct { 96 struct list entry; 97 IFileDialogEvents *pfde; 98 DWORD cookie; 99 } events_client; 100 101 typedef struct FileDialogImpl { 102 IFileDialog2 IFileDialog2_iface; 103 union { 104 IFileOpenDialog IFileOpenDialog_iface; 105 IFileSaveDialog IFileSaveDialog_iface; 106 } u; 107 enum ITEMDLG_TYPE dlg_type; 108 IExplorerBrowserEvents IExplorerBrowserEvents_iface; 109 IServiceProvider IServiceProvider_iface; 110 ICommDlgBrowser3 ICommDlgBrowser3_iface; 111 IOleWindow IOleWindow_iface; 112 IFileDialogCustomize IFileDialogCustomize_iface; 113 LONG ref; 114 115 FILEOPENDIALOGOPTIONS options; 116 COMDLG_FILTERSPEC *filterspecs; 117 UINT filterspec_count; 118 UINT filetypeindex; 119 120 struct list events_clients; 121 DWORD events_next_cookie; 122 123 IShellItemArray *psia_selection; 124 IShellItemArray *psia_results; 125 IShellItem *psi_defaultfolder; 126 IShellItem *psi_setfolder; 127 IShellItem *psi_folder; 128 129 HWND dlg_hwnd; 130 IExplorerBrowser *peb; 131 DWORD ebevents_cookie; 132 133 LPWSTR set_filename; 134 LPWSTR default_ext; 135 LPWSTR custom_title; 136 LPWSTR custom_okbutton; 137 LPWSTR custom_cancelbutton; 138 LPWSTR custom_filenamelabel; 139 140 UINT cctrl_width, cctrl_def_height, cctrls_cols; 141 UINT cctrl_indent, dpi_x, dpi_y; 142 HWND cctrls_hwnd; 143 struct list cctrls; 144 UINT_PTR cctrl_next_dlgid; 145 customctrl *cctrl_active_vg; 146 147 HMENU hmenu_opendropdown; 148 customctrl cctrl_opendropdown; 149 HFONT hfont_opendropdown; 150 BOOL opendropdown_has_selection; 151 DWORD opendropdown_selection; 152 153 GUID client_guid; 154 } FileDialogImpl; 155 156 /************************************************************************** 157 * Event wrappers. 158 */ 159 static HRESULT events_OnFileOk(FileDialogImpl *This) 160 { 161 events_client *cursor; 162 HRESULT hr = S_OK; 163 TRACE("%p\n", This); 164 165 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) 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 179 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder) 180 { 181 events_client *cursor; 182 HRESULT hr = S_OK; 183 TRACE("%p (%p)\n", This, folder); 184 185 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) 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 199 static void events_OnFolderChange(FileDialogImpl *This) 200 { 201 events_client *cursor; 202 TRACE("%p\n", This); 203 204 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) 205 { 206 TRACE("Notifying %p\n", cursor); 207 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface); 208 } 209 } 210 211 static void events_OnSelectionChange(FileDialogImpl *This) 212 { 213 events_client *cursor; 214 TRACE("%p\n", This); 215 216 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) 217 { 218 TRACE("Notifying %p\n", cursor); 219 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface); 220 } 221 } 222 223 static void events_OnTypeChange(FileDialogImpl *This) 224 { 225 events_client *cursor; 226 TRACE("%p\n", This); 227 228 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) 229 { 230 TRACE("Notifying %p\n", cursor); 231 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface); 232 } 233 } 234 235 static HRESULT events_OnOverwrite(FileDialogImpl *This, IShellItem *shellitem) 236 { 237 events_client *cursor; 238 HRESULT hr = S_OK; 239 FDE_OVERWRITE_RESPONSE response = FDEOR_DEFAULT; 240 TRACE("%p %p\n", This, shellitem); 241 242 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) 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 261 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, buf, 100); 262 answer = MessageBoxW(This->dlg_hwnd, buf, This->custom_title, 263 MB_YESNO | MB_ICONEXCLAMATION); 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 276 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce) 277 { 278 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce); 279 } 280 281 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id) 282 { 283 events_client *cursor; 284 TRACE("%p\n", This); 285 286 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) 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 300 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id) 301 { 302 events_client *cursor; 303 TRACE("%p %i %i\n", This, ctl_id, item_id); 304 305 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) 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 319 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked) 320 { 321 events_client *cursor; 322 TRACE("%p\n", This); 323 324 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) 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 338 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This, 339 DWORD ctl_id) 340 { 341 events_client *cursor; 342 TRACE("%p\n", This); 343 344 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) 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 */ 361 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str) 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 387 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str) 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 397 static void fill_filename_from_selection(FileDialogImpl *This) 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, 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 { 441 set_file_name(This, names[0]); 442 CoTaskMemFree(names[0]); 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++ = ' '; 457 CoTaskMemFree(file); 458 } 459 *(cur_point-1) = '\0'; 460 461 set_file_name(This, string); 462 HeapFree(GetProcessHeap(), 0, string); 463 } 464 465 HeapFree(GetProcessHeap(), 0, names); 466 return; 467 } 468 469 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec) 470 { 471 WCHAR *endpos, *ext; 472 473 lstrcpyW(buf, spec); 474 if( (endpos = StrChrW(buf, ';')) ) 475 *endpos = '\0'; 476 477 ext = PathFindExtensionW(buf); 478 if(StrChrW(ext, '*')) 479 return NULL; 480 481 return ext; 482 } 483 484 static BOOL shell_item_exists(IShellItem* shellitem) 485 { 486 LPWSTR filename; 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. */ 494 result = (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES); 495 CoTaskMemFree(filename); 496 } 497 else 498 { 499 SFGAOF attributes; 500 result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes)); 501 } 502 503 return result; 504 } 505 506 static HRESULT on_default_action(FileDialogImpl *This) 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, ¤t_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 { 596 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING); 597 open_action = ONOPEN_BROWSE; 598 } 599 } 600 else 601 { 602 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING); 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]; 662 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, sizeof(buf)/sizeof(WCHAR)); 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 692 if(events_OnFileOk(This) == S_OK) 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 711 static void show_opendropdown(FileDialogImpl *This) 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 733 if(SUCCEEDED(on_default_action(This))) 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 744 static void item_free(cctrl_item *item) 745 { 746 DestroyWindow(item->hwnd); 747 HeapFree(GetProcessHeap(), 0, item->label); 748 HeapFree(GetProcessHeap(), 0, item); 749 } 750 751 static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position) 752 { 753 DWORD dummy; 754 cctrl_item* item; 755 756 if (!position) position = &dummy; 757 758 *position = 0; 759 760 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry) 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 772 static cctrl_item* get_first_item(customctrl* parent) 773 { 774 cctrl_item* item; 775 776 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry) 777 { 778 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED)) 779 return item; 780 } 781 782 return NULL; 783 } 784 785 static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result) 786 { 787 cctrl_item* item; 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 { 798 HeapFree(GetProcessHeap(), 0, item); 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 */ 819 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid) 820 { 821 customctrl *ctrl, *sub_ctrl; 822 823 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) 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 837 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid) 838 { 839 customctrl *ctrl, *sub_ctrl; 840 841 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) 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 858 static 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; 874 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text); 875 876 hdc = GetDC(hctrl); 877 font = (HFONT)SendMessageW(hctrl, WM_GETFONT, 0, 0); 878 font = SelectObject(hdc, font); 879 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size); 880 SelectObject(hdc, font); 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, 899 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); 900 901 HeapFree(GetProcessHeap(), 0, text); 902 } 903 904 static UINT ctrl_get_height(customctrl *ctrl) { 905 RECT rc; 906 GetWindowRect(ctrl->wrapper_hwnd, &rc); 907 return rc.bottom - rc.top; 908 } 909 910 static void ctrl_free(customctrl *ctrl) 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); 920 DestroyMenu((HMENU)tbb.dwData); 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); 936 HeapFree(GetProcessHeap(), 0, ctrl); 937 } 938 939 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl) 940 { 941 RECT rc; 942 UINT total_height; 943 UINT max_width, size; 944 customctrl *sub_ctrl; 945 946 switch(ctrl->type) 947 { 948 case IDLG_CCTRL_PUSHBUTTON: 949 case IDLG_CCTRL_COMBOBOX: 950 case IDLG_CCTRL_CHECKBUTTON: 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, 956 SWP_NOZORDER|SWP_NOMOVE); 957 break; 958 case IDLG_CCTRL_VISUALGROUP: 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, 966 SWP_NOZORDER|SWP_NOSIZE); 967 968 total_height += ctrl_get_height(sub_ctrl); 969 } 970 971 /* The label should be right adjusted */ 972 { 973 UINT width, height; 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, 984 SWP_NOZORDER|SWP_NOMOVE); 985 break; 986 case IDLG_CCTRL_RADIOBUTTONLIST: 987 { 988 cctrl_item* item; 989 990 total_height = 0; 991 max_width = 0; 992 993 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry) 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, 998 SWP_NOZORDER|SWP_NOSIZE); 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, 1007 SWP_NOZORDER|SWP_NOMOVE); 1008 1009 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, max_width, total_height, 1010 SWP_NOZORDER|SWP_NOMOVE); 1011 1012 break; 1013 } 1014 case IDLG_CCTRL_EDITBOX: 1015 case IDLG_CCTRL_SEPARATOR: 1016 case IDLG_CCTRL_MENU: 1017 case IDLG_CCTRL_OPENDROPDOWN: 1018 /* Nothing */ 1019 break; 1020 } 1021 } 1022 1023 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs) 1024 { 1025 FileDialogImpl *This = crs->lpCreateParams; 1026 TRACE("%p\n", This); 1027 1028 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This); 1029 return TRUE; 1030 } 1031 1032 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam) 1033 { 1034 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam)); 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); 1043 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked); 1044 } 1045 else 1046 cctrl_event_OnButtonClicked(This, ctrl->id); 1047 } 1048 1049 return TRUE; 1050 } 1051 1052 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam) 1053 { 1054 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam)); 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 1062 cctrl_event_OnItemSelected(This, ctrl->id, selid); 1063 } 1064 return TRUE; 1065 } 1066 1067 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam) 1068 { 1069 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam; 1070 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom)); 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 { 1079 cctrl_event_OnControlActivating(This,ctrl->id); 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) 1085 cctrl_event_OnItemSelected(This, ctrl->id, idcmd); 1086 } 1087 1088 return TBDDRET_DEFAULT; 1089 } 1090 1091 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam) 1092 { 1093 switch(HIWORD(wparam)) 1094 { 1095 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam); 1096 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam); 1097 } 1098 1099 return FALSE; 1100 } 1101 1102 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam) 1103 { 1104 NMHDR *nmhdr = (NMHDR*)lparam; 1105 1106 switch(nmhdr->code) 1107 { 1108 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam); 1109 } 1110 1111 return FALSE; 1112 } 1113 1114 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 1115 { 1116 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA); 1117 customctrl *ctrl; 1118 HWND hwnd_child; 1119 RECT rc; 1120 1121 switch(message) 1122 { 1123 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam); 1124 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam); 1125 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam); 1126 case WM_SIZE: 1127 hwnd_child = GetPropW(hwnd, notifysink_childW); 1128 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA); 1129 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP) 1130 { 1131 GetClientRect(hwnd, &rc); 1132 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER); 1133 } 1134 return TRUE; 1135 } 1136 1137 return DefWindowProcW(hwnd, message, wparam, lparam); 1138 } 1139 1140 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id, 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; 1145 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS; 1146 customctrl *ctrl; 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 1174 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl)); 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 1191 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl); 1192 1193 if(ppctrl) *ppctrl = ctrl; 1194 1195 This->cctrl_next_dlgid++; 1196 return S_OK; 1197 } 1198 1199 /************************************************************************** 1200 * Container functions. 1201 */ 1202 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width) 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; 1209 customctrl *ctrl; 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; 1238 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) 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; 1263 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) 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; 1290 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) 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, 1312 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); 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 1325 static void ctrl_set_font(customctrl *ctrl, HFONT font) 1326 { 1327 customctrl *sub_ctrl; 1328 cctrl_item* item; 1329 1330 SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE); 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 { 1339 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry) 1340 { 1341 SendMessageW(item->hwnd, WM_SETFONT, (WPARAM)font, TRUE); 1342 } 1343 } 1344 } 1345 1346 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent) 1347 { 1348 LONG wndstyle; 1349 1350 if(parent) 1351 { 1352 customctrl *ctrl; 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. */ 1364 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0); 1365 if(!font) 1366 ERR("Failed to get font handle from dialog.\n"); 1367 1368 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) 1369 { 1370 if(font) ctrl_set_font(ctrl, font); 1371 customctrl_resize(This, ctrl); 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 1387 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs) 1388 { 1389 FileDialogImpl *This = crs->lpCreateParams; 1390 TRACE("%p\n", This); 1391 1392 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This); 1393 return TRUE; 1394 } 1395 1396 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This) 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 1410 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam) 1411 { 1412 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA); 1413 1414 switch(umessage) 1415 { 1416 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam); 1417 case WM_DESTROY: return ctrl_container_on_wm_destroy(This); 1418 default: return DefWindowProcW(hwnd, umessage, wparam, lparam); 1419 } 1420 1421 return FALSE; 1422 } 1423 1424 static void radiobuttonlist_set_selected_item(FileDialogImpl *This, customctrl *ctrl, cctrl_item *item) 1425 { 1426 cctrl_item *cursor; 1427 1428 LIST_FOR_EACH_ENTRY(cursor, &ctrl->sub_items, cctrl_item, entry) 1429 { 1430 SendMessageW(cursor->hwnd, BM_SETCHECK, (cursor == item) ? BST_CHECKED : BST_UNCHECKED, 0); 1431 } 1432 } 1433 1434 static LRESULT radiobuttonlist_on_bn_clicked(FileDialogImpl *This, HWND hwnd, HWND child) 1435 { 1436 DWORD ctrl_id = (DWORD)GetWindowLongPtrW(hwnd, GWLP_ID); 1437 customctrl *ctrl; 1438 cctrl_item *item; 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 1449 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry) 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 1464 radiobuttonlist_set_selected_item(This, ctrl, item); 1465 1466 cctrl_event_OnItemSelected(This, ctrl->id, item->id); 1467 1468 return 0; 1469 } 1470 1471 static LRESULT radiobuttonlist_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam) 1472 { 1473 switch(HIWORD(wparam)) 1474 { 1475 case BN_CLICKED: return radiobuttonlist_on_bn_clicked(This, hwnd, (HWND)lparam); 1476 } 1477 1478 return FALSE; 1479 } 1480 1481 static LRESULT CALLBACK radiobuttonlist_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 1482 { 1483 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA); 1484 1485 switch(message) 1486 { 1487 case WM_COMMAND: return radiobuttonlist_on_wm_command(This, hwnd, wparam, lparam); 1488 } 1489 1490 return DefWindowProcW(hwnd, message, wparam, lparam); 1491 } 1492 1493 static HRESULT init_custom_controls(FileDialogImpl *This) 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 1500 InitCommonControlsEx(NULL); 1501 1502 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) ) 1503 { 1504 wc.style = CS_HREDRAW | CS_VREDRAW; 1505 wc.lpfnWndProc = ctrl_container_wndproc; 1506 wc.cbClsExtra = 0; 1507 wc.cbWndExtra = 0; 1508 wc.hInstance = COMDLG32_hInstance; 1509 wc.hIcon = 0; 1510 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); 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, 1519 WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 1520 0, 0, 0, 0, NULL, 0, 1521 COMDLG32_hInstance, This); 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 */ 1542 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) || 1543 wc.hInstance != COMDLG32_hInstance) 1544 { 1545 wc.style = CS_HREDRAW | CS_VREDRAW; 1546 wc.lpfnWndProc = notifysink_proc; 1547 wc.cbClsExtra = 0; 1548 wc.cbWndExtra = 0; 1549 wc.hInstance = COMDLG32_hInstance; 1550 wc.hIcon = 0; 1551 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); 1552 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 1553 wc.lpszMenuName = NULL; 1554 wc.lpszClassName = floatnotifysinkW; 1555 1556 if (!RegisterClassW(&wc)) 1557 ERR("Failed to register FloatNotifySink window class.\n"); 1558 } 1559 1560 if( !GetClassInfoW(COMDLG32_hInstance, radiobuttonlistW, &wc) || 1561 wc.hInstance != COMDLG32_hInstance) 1562 { 1563 wc.style = CS_HREDRAW | CS_VREDRAW; 1564 wc.lpfnWndProc = radiobuttonlist_proc; 1565 wc.cbClsExtra = 0; 1566 wc.cbWndExtra = 0; 1567 wc.hInstance = COMDLG32_hInstance; 1568 wc.hIcon = 0; 1569 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); 1570 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 1571 wc.lpszMenuName = NULL; 1572 wc.lpszClassName = radiobuttonlistW; 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 */ 1584 static BOOL update_open_dropdown(FileDialogImpl *This) 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; 1593 cctrl_item* item; 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 1642 static void update_layout(FileDialogImpl *This) 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, 1810 SWP_NOZORDER | SWP_NOACTIVATE); 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, 1815 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); 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, 1820 SWP_NOZORDER | SWP_NOACTIVATE); 1821 1822 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) ) 1823 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0, 1824 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); 1825 1826 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) ) 1827 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0, 1828 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); 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, 1832 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); 1833 1834 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) ) 1835 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0, 1836 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); 1837 1838 if(hdwp) 1839 EndDeferWindowPos(hdwp); 1840 else 1841 ERR("Failed to position dialog controls.\n"); 1842 1843 return; 1844 } 1845 1846 static HRESULT init_explorerbrowser(FileDialogImpl *This) 1847 { 1848 IShellItem *psi_folder; 1849 IObjectWithSite *client; 1850 FOLDERSETTINGS fos; 1851 RECT rc = {0}; 1852 HRESULT hr; 1853 1854 /* Create ExplorerBrowser instance */ 1855 OleInitialize(NULL); 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 1902 static void init_toolbar(FileDialogImpl *This, HWND hwnd) 1903 { 1904 HWND htoolbar; 1905 TBADDBITMAP tbab; 1906 TBBUTTON button[2]; 1907 1908 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE, 1909 0, 0, 0, 0, 1910 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL); 1911 1912 tbab.hInst = HINST_COMMCTRL; 1913 tbab.nID = IDB_HIST_LARGE_COLOR; 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 1935 static void update_control_text(FileDialogImpl *This) 1936 { 1937 HWND hitem; 1938 LPCWSTR custom_okbutton; 1939 cctrl_item* item; 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 1973 static LRESULT CALLBACK dropdown_subclass_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam) 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 1982 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0); 1983 show_opendropdown(This); 1984 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0); 1985 1986 return 0; 1987 } 1988 1989 return CallWindowProcW((WNDPROC)GetPropW(hwnd, prop_oldwndproc), hwnd, umessage, wparam, lparam); 1990 } 1991 1992 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam) 1993 { 1994 FileDialogImpl *This = (FileDialogImpl*)lParam; 1995 HWND hitem; 1996 1997 TRACE("(%p, %p)\n", This, hwnd); 1998 1999 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This); 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); 2019 SelectObject(hdc, font); 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, 2075 (HANDLE)SetWindowLongPtrW(dropdown_hwnd, GWLP_WNDPROC, (LONG_PTR)dropdown_subclass_proc)); 2076 } 2077 2078 ctrl_container_reparent(This, This->dlg_hwnd); 2079 init_explorerbrowser(This); 2080 init_toolbar(This, hwnd); 2081 update_control_text(This); 2082 update_layout(This); 2083 2084 if(This->filterspec_count) 2085 events_OnTypeChange(This); 2086 2087 if ((hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME))) 2088 SetFocus(hitem); 2089 2090 return FALSE; 2091 } 2092 2093 static LRESULT on_wm_size(FileDialogImpl *This) 2094 { 2095 update_layout(This); 2096 return FALSE; 2097 } 2098 2099 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam) 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 2111 static LRESULT on_wm_destroy(FileDialogImpl *This) 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 2122 ctrl_container_reparent(This, NULL); 2123 This->dlg_hwnd = NULL; 2124 2125 DeleteObject(This->hfont_opendropdown); 2126 This->hfont_opendropdown = NULL; 2127 2128 return TRUE; 2129 } 2130 2131 static LRESULT on_idok(FileDialogImpl *This) 2132 { 2133 TRACE("%p\n", This); 2134 2135 if(SUCCEEDED(on_default_action(This))) 2136 EndDialog(This->dlg_hwnd, S_OK); 2137 2138 return FALSE; 2139 } 2140 2141 static LRESULT on_idcancel(FileDialogImpl *This) 2142 { 2143 TRACE("%p\n", This); 2144 2145 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED)); 2146 2147 return FALSE; 2148 } 2149 2150 static LRESULT on_command_opendropdown(FileDialogImpl *This, WPARAM wparam, LPARAM lparam) 2151 { 2152 if(HIWORD(wparam) == BN_CLICKED) 2153 { 2154 HWND hwnd = (HWND)lparam; 2155 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0); 2156 show_opendropdown(This); 2157 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0); 2158 } 2159 2160 return FALSE; 2161 } 2162 2163 static LRESULT on_browse_back(FileDialogImpl *This) 2164 { 2165 TRACE("%p\n", This); 2166 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK); 2167 return FALSE; 2168 } 2169 2170 static LRESULT on_browse_forward(FileDialogImpl *This) 2171 { 2172 TRACE("%p\n", This); 2173 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD); 2174 return FALSE; 2175 } 2176 2177 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam) 2178 { 2179 if(HIWORD(wparam) == CBN_SELCHANGE) 2180 { 2181 IShellView *psv; 2182 HRESULT hr; 2183 LPWSTR filename; 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 { 2206 lstrcpyW(buf, filename); 2207 2208 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec)) 2209 PathRemoveExtensionW(buf); 2210 2211 lstrcatW(buf, ext); 2212 set_file_name(This, buf); 2213 } 2214 CoTaskMemFree(filename); 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. */ 2220 events_OnTypeChange(This); 2221 } 2222 2223 return FALSE; 2224 } 2225 2226 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam) 2227 { 2228 switch(LOWORD(wparam)) 2229 { 2230 case IDOK: return on_idok(This); 2231 case IDCANCEL: return on_idcancel(This); 2232 case psh1: return on_command_opendropdown(This, wparam, lparam); 2233 case IDC_NAVBACK: return on_browse_back(This); 2234 case IDC_NAVFORWARD: return on_browse_forward(This); 2235 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam); 2236 default: TRACE("Unknown command.\n"); 2237 } 2238 return FALSE; 2239 } 2240 2241 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam) 2242 { 2243 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA); 2244 2245 switch(umessage) 2246 { 2247 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam); 2248 case WM_COMMAND: return on_wm_command(This, wparam, lparam); 2249 case WM_SIZE: return on_wm_size(This); 2250 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam); 2251 case WM_DESTROY: return on_wm_destroy(This); 2252 } 2253 2254 return FALSE; 2255 } 2256 2257 static HRESULT create_dialog(FileDialogImpl *This, HWND parent) 2258 { 2259 INT_PTR res; 2260 2261 SetLastError(0); 2262 res = DialogBoxParamW(COMDLG32_hInstance, 2263 MAKEINTRESOURCEW(NEWFILEOPENV3ORD), 2264 parent, itemdlg_dlgproc, (LPARAM)This); 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 */ 2279 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface) 2280 { 2281 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface); 2282 } 2283 2284 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface, 2285 REFIID riid, 2286 void **ppvObject) 2287 { 2288 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2289 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject); 2290 2291 *ppvObject = NULL; 2292 if(IsEqualGUID(riid, &IID_IUnknown) || 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 2341 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface) 2342 { 2343 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2344 LONG ref = InterlockedIncrement(&This->ref); 2345 TRACE("%p - ref %d\n", This, ref); 2346 2347 return ref; 2348 } 2349 2350 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface) 2351 { 2352 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2353 LONG ref = InterlockedDecrement(&This->ref); 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 2384 HeapFree(GetProcessHeap(), 0, This); 2385 } 2386 2387 return ref; 2388 } 2389 2390 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner) 2391 { 2392 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2393 TRACE("%p (%p)\n", iface, hwndOwner); 2394 2395 This->opendropdown_has_selection = FALSE; 2396 2397 return create_dialog(This, hwndOwner); 2398 } 2399 2400 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes, 2401 const COMDLG_FILTERSPEC *rgFilterSpec) 2402 { 2403 FileDialogImpl *This = impl_from_IFileDialog2(iface); 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 2427 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType) 2428 { 2429 FileDialogImpl *This = impl_from_IFileDialog2(iface); 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 2442 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType) 2443 { 2444 FileDialogImpl *This = impl_from_IFileDialog2(iface); 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 2458 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie) 2459 { 2460 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2461 events_client *client; 2462 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie); 2463 2464 if(!pfde || !pdwCookie) 2465 return E_INVALIDARG; 2466 2467 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client)); 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 2479 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie) 2480 { 2481 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2482 events_client *client, *found = NULL; 2483 TRACE("%p (%d)\n", This, dwCookie); 2484 2485 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry) 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 2505 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos) 2506 { 2507 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2508 TRACE("%p (0x%x)\n", This, fos); 2509 2510 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) ) 2511 { 2512 WCHAR buf[30]; 2513 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, sizeof(buf)/sizeof(WCHAR)); 2514 IFileDialog2_SetTitle(iface, buf); 2515 } 2516 2517 This->options = fos; 2518 2519 return S_OK; 2520 } 2521 2522 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos) 2523 { 2524 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2525 TRACE("%p (%p)\n", This, pfos); 2526 2527 if(!pfos) 2528 return E_INVALIDARG; 2529 2530 *pfos = This->options; 2531 2532 return S_OK; 2533 } 2534 2535 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi) 2536 { 2537 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2538 TRACE("%p (%p)\n", This, psi); 2539 if(This->psi_defaultfolder) 2540 IShellItem_Release(This->psi_defaultfolder); 2541 2542 This->psi_defaultfolder = psi; 2543 2544 if(This->psi_defaultfolder) 2545 IShellItem_AddRef(This->psi_defaultfolder); 2546 2547 return S_OK; 2548 } 2549 2550 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi) 2551 { 2552 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2553 TRACE("%p (%p)\n", This, psi); 2554 if(This->psi_setfolder) 2555 IShellItem_Release(This->psi_setfolder); 2556 2557 This->psi_setfolder = psi; 2558 2559 if(This->psi_setfolder) 2560 IShellItem_AddRef(This->psi_setfolder); 2561 2562 return S_OK; 2563 } 2564 2565 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi) 2566 { 2567 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2568 TRACE("%p (%p)\n", This, ppsi); 2569 if(!ppsi) 2570 return E_INVALIDARG; 2571 2572 /* FIXME: 2573 If the dialog is shown, return the current(ly selected) folder. */ 2574 2575 *ppsi = NULL; 2576 if(This->psi_folder) 2577 *ppsi = This->psi_folder; 2578 else if(This->psi_setfolder) 2579 *ppsi = This->psi_setfolder; 2580 else if(This->psi_defaultfolder) 2581 *ppsi = This->psi_defaultfolder; 2582 2583 if(*ppsi) 2584 { 2585 IShellItem_AddRef(*ppsi); 2586 return S_OK; 2587 } 2588 2589 return E_FAIL; 2590 } 2591 2592 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi) 2593 { 2594 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2595 HRESULT hr; 2596 TRACE("%p (%p)\n", This, ppsi); 2597 2598 if(!ppsi) 2599 return E_INVALIDARG; 2600 2601 if(This->psia_selection) 2602 { 2603 /* FIXME: Check filename edit box */ 2604 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi); 2605 return hr; 2606 } 2607 2608 return E_FAIL; 2609 } 2610 2611 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName) 2612 { 2613 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2614 TRACE("%p (%s)\n", iface, debugstr_w(pszName)); 2615 2616 set_file_name(This, pszName); 2617 2618 return S_OK; 2619 } 2620 2621 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName) 2622 { 2623 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2624 TRACE("%p (%p)\n", iface, pszName); 2625 2626 if(!pszName) 2627 return E_INVALIDARG; 2628 2629 *pszName = NULL; 2630 get_file_name(This, pszName); 2631 return *pszName ? S_OK : E_FAIL; 2632 } 2633 2634 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle) 2635 { 2636 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2637 TRACE("%p (%s)\n", This, debugstr_w(pszTitle)); 2638 2639 LocalFree(This->custom_title); 2640 This->custom_title = StrDupW(pszTitle); 2641 update_control_text(This); 2642 2643 return S_OK; 2644 } 2645 2646 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText) 2647 { 2648 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2649 TRACE("%p (%s)\n", This, debugstr_w(pszText)); 2650 2651 LocalFree(This->custom_okbutton); 2652 This->custom_okbutton = StrDupW(pszText); 2653 update_control_text(This); 2654 update_layout(This); 2655 2656 return S_OK; 2657 } 2658 2659 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel) 2660 { 2661 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2662 TRACE("%p (%s)\n", This, debugstr_w(pszLabel)); 2663 2664 LocalFree(This->custom_filenamelabel); 2665 This->custom_filenamelabel = StrDupW(pszLabel); 2666 update_control_text(This); 2667 update_layout(This); 2668 2669 return S_OK; 2670 } 2671 2672 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi) 2673 { 2674 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2675 HRESULT hr; 2676 TRACE("%p (%p)\n", This, ppsi); 2677 2678 if(!ppsi) 2679 return E_INVALIDARG; 2680 2681 if(This->psia_results) 2682 { 2683 UINT item_count; 2684 hr = IShellItemArray_GetCount(This->psia_results, &item_count); 2685 if(SUCCEEDED(hr)) 2686 { 2687 if(item_count != 1) 2688 return E_FAIL; 2689 2690 /* Adds a reference. */ 2691 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi); 2692 } 2693 2694 return hr; 2695 } 2696 2697 return E_UNEXPECTED; 2698 } 2699 2700 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap) 2701 { 2702 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2703 FIXME("stub - %p (%p, %d)\n", This, psi, fdap); 2704 return S_OK; 2705 } 2706 2707 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension) 2708 { 2709 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2710 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension)); 2711 2712 LocalFree(This->default_ext); 2713 This->default_ext = StrDupW(pszDefaultExtension); 2714 2715 return S_OK; 2716 } 2717 2718 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr) 2719 { 2720 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2721 TRACE("%p (0x%08x)\n", This, hr); 2722 2723 if(This->dlg_hwnd) 2724 EndDialog(This->dlg_hwnd, hr); 2725 2726 return S_OK; 2727 } 2728 2729 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid) 2730 { 2731 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2732 TRACE("%p (%s)\n", This, debugstr_guid(guid)); 2733 This->client_guid = *guid; 2734 return S_OK; 2735 } 2736 2737 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface) 2738 { 2739 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2740 FIXME("stub - %p\n", This); 2741 return E_NOTIMPL; 2742 } 2743 2744 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter) 2745 { 2746 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2747 FIXME("stub - %p (%p)\n", This, pFilter); 2748 return E_NOTIMPL; 2749 } 2750 2751 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel) 2752 { 2753 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2754 TRACE("%p (%s)\n", This, debugstr_w(pszLabel)); 2755 2756 LocalFree(This->custom_cancelbutton); 2757 This->custom_cancelbutton = StrDupW(pszLabel); 2758 update_control_text(This); 2759 update_layout(This); 2760 2761 return S_OK; 2762 } 2763 2764 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi) 2765 { 2766 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2767 FIXME("stub - %p (%p)\n", This, psi); 2768 return E_NOTIMPL; 2769 } 2770 2771 static const IFileDialog2Vtbl vt_IFileDialog2 = { 2772 IFileDialog2_fnQueryInterface, 2773 IFileDialog2_fnAddRef, 2774 IFileDialog2_fnRelease, 2775 IFileDialog2_fnShow, 2776 IFileDialog2_fnSetFileTypes, 2777 IFileDialog2_fnSetFileTypeIndex, 2778 IFileDialog2_fnGetFileTypeIndex, 2779 IFileDialog2_fnAdvise, 2780 IFileDialog2_fnUnadvise, 2781 IFileDialog2_fnSetOptions, 2782 IFileDialog2_fnGetOptions, 2783 IFileDialog2_fnSetDefaultFolder, 2784 IFileDialog2_fnSetFolder, 2785 IFileDialog2_fnGetFolder, 2786 IFileDialog2_fnGetCurrentSelection, 2787 IFileDialog2_fnSetFileName, 2788 IFileDialog2_fnGetFileName, 2789 IFileDialog2_fnSetTitle, 2790 IFileDialog2_fnSetOkButtonLabel, 2791 IFileDialog2_fnSetFileNameLabel, 2792 IFileDialog2_fnGetResult, 2793 IFileDialog2_fnAddPlace, 2794 IFileDialog2_fnSetDefaultExtension, 2795 IFileDialog2_fnClose, 2796 IFileDialog2_fnSetClientGuid, 2797 IFileDialog2_fnClearClientData, 2798 IFileDialog2_fnSetFilter, 2799 IFileDialog2_fnSetCancelButtonLabel, 2800 IFileDialog2_fnSetNavigationRoot 2801 }; 2802 2803 /************************************************************************** 2804 * IFileOpenDialog 2805 */ 2806 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface) 2807 { 2808 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface); 2809 } 2810 2811 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface, 2812 REFIID riid, void **ppvObject) 2813 { 2814 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2815 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 2816 } 2817 2818 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface) 2819 { 2820 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2821 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 2822 } 2823 2824 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface) 2825 { 2826 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2827 return IFileDialog2_Release(&This->IFileDialog2_iface); 2828 } 2829 2830 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner) 2831 { 2832 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2833 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner); 2834 } 2835 2836 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes, 2837 const COMDLG_FILTERSPEC *rgFilterSpec) 2838 { 2839 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2840 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec); 2841 } 2842 2843 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType) 2844 { 2845 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2846 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType); 2847 } 2848 2849 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType) 2850 { 2851 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2852 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType); 2853 } 2854 2855 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde, 2856 DWORD *pdwCookie) 2857 { 2858 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2859 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie); 2860 } 2861 2862 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie) 2863 { 2864 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2865 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie); 2866 } 2867 2868 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos) 2869 { 2870 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2871 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos); 2872 } 2873 2874 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos) 2875 { 2876 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2877 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos); 2878 } 2879 2880 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi) 2881 { 2882 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2883 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi); 2884 } 2885 2886 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi) 2887 { 2888 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2889 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi); 2890 } 2891 2892 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi) 2893 { 2894 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2895 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi); 2896 } 2897 2898 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi) 2899 { 2900 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2901 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi); 2902 } 2903 2904 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName) 2905 { 2906 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2907 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName); 2908 } 2909 2910 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName) 2911 { 2912 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2913 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName); 2914 } 2915 2916 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle) 2917 { 2918 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2919 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle); 2920 } 2921 2922 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText) 2923 { 2924 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2925 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText); 2926 } 2927 2928 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel) 2929 { 2930 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2931 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel); 2932 } 2933 2934 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi) 2935 { 2936 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2937 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi); 2938 } 2939 2940 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap) 2941 { 2942 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2943 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap); 2944 } 2945 2946 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface, 2947 LPCWSTR pszDefaultExtension) 2948 { 2949 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2950 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension); 2951 } 2952 2953 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr) 2954 { 2955 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2956 return IFileDialog2_Close(&This->IFileDialog2_iface, hr); 2957 } 2958 2959 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid) 2960 { 2961 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2962 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid); 2963 } 2964 2965 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface) 2966 { 2967 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2968 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface); 2969 } 2970 2971 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter) 2972 { 2973 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2974 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter); 2975 } 2976 2977 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum) 2978 { 2979 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2980 TRACE("%p (%p)\n", This, ppenum); 2981 2982 *ppenum = This->psia_results; 2983 2984 if(*ppenum) 2985 { 2986 IShellItemArray_AddRef(*ppenum); 2987 return S_OK; 2988 } 2989 2990 return E_FAIL; 2991 } 2992 2993 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai) 2994 { 2995 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2996 TRACE("%p (%p)\n", This, ppsai); 2997 2998 if(This->psia_selection) 2999 { 3000 *ppsai = This->psia_selection; 3001 IShellItemArray_AddRef(*ppsai); 3002 return S_OK; 3003 } 3004 3005 return E_FAIL; 3006 } 3007 3008 static const IFileOpenDialogVtbl vt_IFileOpenDialog = { 3009 IFileOpenDialog_fnQueryInterface, 3010 IFileOpenDialog_fnAddRef, 3011 IFileOpenDialog_fnRelease, 3012 IFileOpenDialog_fnShow, 3013 IFileOpenDialog_fnSetFileTypes, 3014 IFileOpenDialog_fnSetFileTypeIndex, 3015 IFileOpenDialog_fnGetFileTypeIndex, 3016 IFileOpenDialog_fnAdvise, 3017 IFileOpenDialog_fnUnadvise, 3018 IFileOpenDialog_fnSetOptions, 3019 IFileOpenDialog_fnGetOptions, 3020 IFileOpenDialog_fnSetDefaultFolder, 3021 IFileOpenDialog_fnSetFolder, 3022 IFileOpenDialog_fnGetFolder, 3023 IFileOpenDialog_fnGetCurrentSelection, 3024 IFileOpenDialog_fnSetFileName, 3025 IFileOpenDialog_fnGetFileName, 3026 IFileOpenDialog_fnSetTitle, 3027 IFileOpenDialog_fnSetOkButtonLabel, 3028 IFileOpenDialog_fnSetFileNameLabel, 3029 IFileOpenDialog_fnGetResult, 3030 IFileOpenDialog_fnAddPlace, 3031 IFileOpenDialog_fnSetDefaultExtension, 3032 IFileOpenDialog_fnClose, 3033 IFileOpenDialog_fnSetClientGuid, 3034 IFileOpenDialog_fnClearClientData, 3035 IFileOpenDialog_fnSetFilter, 3036 IFileOpenDialog_fnGetResults, 3037 IFileOpenDialog_fnGetSelectedItems 3038 }; 3039 3040 /************************************************************************** 3041 * IFileSaveDialog 3042 */ 3043 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface) 3044 { 3045 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface); 3046 } 3047 3048 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface, 3049 REFIID riid, 3050 void **ppvObject) 3051 { 3052 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3053 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3054 } 3055 3056 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface) 3057 { 3058 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3059 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3060 } 3061 3062 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface) 3063 { 3064 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3065 return IFileDialog2_Release(&This->IFileDialog2_iface); 3066 } 3067 3068 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner) 3069 { 3070 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3071 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner); 3072 } 3073 3074 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes, 3075 const COMDLG_FILTERSPEC *rgFilterSpec) 3076 { 3077 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3078 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec); 3079 } 3080 3081 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType) 3082 { 3083 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3084 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType); 3085 } 3086 3087 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType) 3088 { 3089 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3090 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType); 3091 } 3092 3093 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde, 3094 DWORD *pdwCookie) 3095 { 3096 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3097 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie); 3098 } 3099 3100 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie) 3101 { 3102 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3103 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie); 3104 } 3105 3106 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos) 3107 { 3108 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3109 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos); 3110 } 3111 3112 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos) 3113 { 3114 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3115 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos); 3116 } 3117 3118 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi) 3119 { 3120 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3121 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi); 3122 } 3123 3124 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi) 3125 { 3126 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3127 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi); 3128 } 3129 3130 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi) 3131 { 3132 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3133 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi); 3134 } 3135 3136 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi) 3137 { 3138 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3139 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi); 3140 } 3141 3142 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName) 3143 { 3144 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3145 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName); 3146 } 3147 3148 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName) 3149 { 3150 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3151 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName); 3152 } 3153 3154 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle) 3155 { 3156 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3157 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle); 3158 } 3159 3160 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText) 3161 { 3162 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3163 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText); 3164 } 3165 3166 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel) 3167 { 3168 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3169 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel); 3170 } 3171 3172 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi) 3173 { 3174 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3175 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi); 3176 } 3177 3178 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap) 3179 { 3180 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3181 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap); 3182 } 3183 3184 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface, 3185 LPCWSTR pszDefaultExtension) 3186 { 3187 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3188 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension); 3189 } 3190 3191 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr) 3192 { 3193 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3194 return IFileDialog2_Close(&This->IFileDialog2_iface, hr); 3195 } 3196 3197 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid) 3198 { 3199 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3200 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid); 3201 } 3202 3203 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface) 3204 { 3205 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3206 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface); 3207 } 3208 3209 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter) 3210 { 3211 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3212 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter); 3213 } 3214 3215 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi) 3216 { 3217 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3218 FIXME("stub - %p (%p)\n", This, psi); 3219 return E_NOTIMPL; 3220 } 3221 3222 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore) 3223 { 3224 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3225 FIXME("stub - %p (%p)\n", This, pStore); 3226 return E_NOTIMPL; 3227 } 3228 3229 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface, 3230 IPropertyDescriptionList *pList, 3231 BOOL fAppendDefault) 3232 { 3233 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3234 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault); 3235 return E_NOTIMPL; 3236 } 3237 3238 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore) 3239 { 3240 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3241 FIXME("stub - %p (%p)\n", This, ppStore); 3242 return E_NOTIMPL; 3243 } 3244 3245 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface, 3246 IShellItem *psi, 3247 IPropertyStore *pStore, 3248 HWND hwnd, 3249 IFileOperationProgressSink *pSink) 3250 { 3251 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3252 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink); 3253 return E_NOTIMPL; 3254 } 3255 3256 static const IFileSaveDialogVtbl vt_IFileSaveDialog = { 3257 IFileSaveDialog_fnQueryInterface, 3258 IFileSaveDialog_fnAddRef, 3259 IFileSaveDialog_fnRelease, 3260 IFileSaveDialog_fnShow, 3261 IFileSaveDialog_fnSetFileTypes, 3262 IFileSaveDialog_fnSetFileTypeIndex, 3263 IFileSaveDialog_fnGetFileTypeIndex, 3264 IFileSaveDialog_fnAdvise, 3265 IFileSaveDialog_fnUnadvise, 3266 IFileSaveDialog_fnSetOptions, 3267 IFileSaveDialog_fnGetOptions, 3268 IFileSaveDialog_fnSetDefaultFolder, 3269 IFileSaveDialog_fnSetFolder, 3270 IFileSaveDialog_fnGetFolder, 3271 IFileSaveDialog_fnGetCurrentSelection, 3272 IFileSaveDialog_fnSetFileName, 3273 IFileSaveDialog_fnGetFileName, 3274 IFileSaveDialog_fnSetTitle, 3275 IFileSaveDialog_fnSetOkButtonLabel, 3276 IFileSaveDialog_fnSetFileNameLabel, 3277 IFileSaveDialog_fnGetResult, 3278 IFileSaveDialog_fnAddPlace, 3279 IFileSaveDialog_fnSetDefaultExtension, 3280 IFileSaveDialog_fnClose, 3281 IFileSaveDialog_fnSetClientGuid, 3282 IFileSaveDialog_fnClearClientData, 3283 IFileSaveDialog_fnSetFilter, 3284 IFileSaveDialog_fnSetSaveAsItem, 3285 IFileSaveDialog_fnSetProperties, 3286 IFileSaveDialog_fnSetCollectedProperties, 3287 IFileSaveDialog_fnGetProperties, 3288 IFileSaveDialog_fnApplyProperties 3289 }; 3290 3291 /************************************************************************** 3292 * IExplorerBrowserEvents implementation 3293 */ 3294 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface) 3295 { 3296 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface); 3297 } 3298 3299 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface, 3300 REFIID riid, void **ppvObject) 3301 { 3302 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3303 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject); 3304 3305 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3306 } 3307 3308 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface) 3309 { 3310 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3311 TRACE("%p\n", This); 3312 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3313 } 3314 3315 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface) 3316 { 3317 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3318 TRACE("%p\n", This); 3319 return IFileDialog2_Release(&This->IFileDialog2_iface); 3320 } 3321 3322 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface, 3323 PCIDLIST_ABSOLUTE pidlFolder) 3324 { 3325 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3326 IShellItem *psi; 3327 HRESULT hr; 3328 TRACE("%p (%p)\n", This, pidlFolder); 3329 3330 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi); 3331 if(SUCCEEDED(hr)) 3332 { 3333 hr = events_OnFolderChanging(This, psi); 3334 IShellItem_Release(psi); 3335 3336 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */ 3337 if(hr == S_FALSE) 3338 hr = E_FAIL; 3339 3340 return hr; 3341 } 3342 else 3343 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder); 3344 3345 return S_OK; 3346 } 3347 3348 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface, 3349 IShellView *psv) 3350 { 3351 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3352 TRACE("%p (%p)\n", This, psv); 3353 return S_OK; 3354 } 3355 3356 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface, 3357 PCIDLIST_ABSOLUTE pidlFolder) 3358 { 3359 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3360 HRESULT hr; 3361 TRACE("%p (%p)\n", This, pidlFolder); 3362 3363 if(This->psi_folder) 3364 IShellItem_Release(This->psi_folder); 3365 3366 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder); 3367 if(FAILED(hr)) 3368 { 3369 ERR("Failed to get the current folder.\n"); 3370 This->psi_folder = NULL; 3371 } 3372 3373 events_OnFolderChange(This); 3374 3375 return S_OK; 3376 } 3377 3378 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface, 3379 PCIDLIST_ABSOLUTE pidlFolder) 3380 { 3381 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3382 TRACE("%p (%p)\n", This, pidlFolder); 3383 return S_OK; 3384 } 3385 3386 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = { 3387 IExplorerBrowserEvents_fnQueryInterface, 3388 IExplorerBrowserEvents_fnAddRef, 3389 IExplorerBrowserEvents_fnRelease, 3390 IExplorerBrowserEvents_fnOnNavigationPending, 3391 IExplorerBrowserEvents_fnOnViewCreated, 3392 IExplorerBrowserEvents_fnOnNavigationComplete, 3393 IExplorerBrowserEvents_fnOnNavigationFailed 3394 }; 3395 3396 /************************************************************************** 3397 * IServiceProvider implementation 3398 */ 3399 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface) 3400 { 3401 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface); 3402 } 3403 3404 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface, 3405 REFIID riid, void **ppvObject) 3406 { 3407 FileDialogImpl *This = impl_from_IServiceProvider(iface); 3408 TRACE("%p\n", This); 3409 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3410 } 3411 3412 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface) 3413 { 3414 FileDialogImpl *This = impl_from_IServiceProvider(iface); 3415 TRACE("%p\n", This); 3416 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3417 } 3418 3419 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface) 3420 { 3421 FileDialogImpl *This = impl_from_IServiceProvider(iface); 3422 TRACE("%p\n", This); 3423 return IFileDialog2_Release(&This->IFileDialog2_iface); 3424 } 3425 3426 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface, 3427 REFGUID guidService, 3428 REFIID riid, void **ppv) 3429 { 3430 FileDialogImpl *This = impl_from_IServiceProvider(iface); 3431 HRESULT hr = E_NOTIMPL; 3432 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); 3433 3434 *ppv = NULL; 3435 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb) 3436 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv); 3437 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame)) 3438 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv); 3439 else 3440 FIXME("Interface %s requested from unknown service %s\n", 3441 debugstr_guid(riid), debugstr_guid(guidService)); 3442 3443 return hr; 3444 } 3445 3446 static const IServiceProviderVtbl vt_IServiceProvider = { 3447 IServiceProvider_fnQueryInterface, 3448 IServiceProvider_fnAddRef, 3449 IServiceProvider_fnRelease, 3450 IServiceProvider_fnQueryService 3451 }; 3452 3453 /************************************************************************** 3454 * ICommDlgBrowser3 implementation 3455 */ 3456 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface) 3457 { 3458 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface); 3459 } 3460 3461 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface, 3462 REFIID riid, void **ppvObject) 3463 { 3464 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3465 TRACE("%p\n", This); 3466 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3467 } 3468 3469 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface) 3470 { 3471 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3472 TRACE("%p\n", This); 3473 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3474 } 3475 3476 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface) 3477 { 3478 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3479 TRACE("%p\n", This); 3480 return IFileDialog2_Release(&This->IFileDialog2_iface); 3481 } 3482 3483 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface, 3484 IShellView *shv) 3485 { 3486 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3487 HRESULT hr; 3488 TRACE("%p (%p)\n", This, shv); 3489 3490 hr = on_default_action(This); 3491 3492 if(SUCCEEDED(hr)) 3493 EndDialog(This->dlg_hwnd, S_OK); 3494 3495 return S_OK; 3496 } 3497 3498 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface, 3499 IShellView *shv, ULONG uChange ) 3500 { 3501 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3502 IDataObject *new_selection; 3503 HRESULT hr; 3504 TRACE("%p (%p, %x)\n", This, shv, uChange); 3505 3506 switch(uChange) 3507 { 3508 case CDBOSC_SELCHANGE: 3509 if(This->psia_selection) 3510 { 3511 IShellItemArray_Release(This->psia_selection); 3512 This->psia_selection = NULL; 3513 } 3514 3515 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection); 3516 if(SUCCEEDED(hr)) 3517 { 3518 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray, 3519 (void**)&This->psia_selection); 3520 if(SUCCEEDED(hr)) 3521 { 3522 fill_filename_from_selection(This); 3523 events_OnSelectionChange(This); 3524 } 3525 3526 IDataObject_Release(new_selection); 3527 } 3528 break; 3529 default: 3530 TRACE("Unhandled state change\n"); 3531 } 3532 return S_OK; 3533 } 3534 3535 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface, 3536 IShellView *shv, LPCITEMIDLIST pidl) 3537 { 3538 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3539 IShellItem *psi; 3540 LPWSTR filename; 3541 LPITEMIDLIST parent_pidl; 3542 HRESULT hr; 3543 ULONG attr; 3544 TRACE("%p (%p, %p)\n", This, shv, pidl); 3545 3546 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS)) 3547 return S_OK; 3548 3549 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl); 3550 if(SUCCEEDED(hr)) 3551 { 3552 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl); 3553 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi); 3554 ILFree(parent_pidl); 3555 ILFree(full_pidl); 3556 } 3557 if(FAILED(hr)) 3558 { 3559 ERR("Failed to get shellitem (%08x).\n", hr); 3560 return S_OK; 3561 } 3562 3563 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr); 3564 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK))) 3565 { 3566 IShellItem_Release(psi); 3567 return S_OK; 3568 } 3569 3570 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK))) 3571 { 3572 IShellItem_Release(psi); 3573 return S_FALSE; 3574 } 3575 3576 hr = S_OK; 3577 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename))) 3578 { 3579 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec)) 3580 hr = S_FALSE; 3581 CoTaskMemFree(filename); 3582 } 3583 3584 IShellItem_Release(psi); 3585 return hr; 3586 } 3587 3588 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface, 3589 IShellView *ppshv, DWORD dwNotifyType) 3590 { 3591 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3592 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType); 3593 return E_NOTIMPL; 3594 } 3595 3596 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface, 3597 IShellView *pshv, 3598 LPWSTR pszText, int cchMax) 3599 { 3600 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3601 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax); 3602 return E_NOTIMPL; 3603 } 3604 3605 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags) 3606 { 3607 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3608 FIXME("Stub: %p (%p)\n", This, pdwFlags); 3609 return E_NOTIMPL; 3610 } 3611 3612 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface, 3613 IShellView *pshv, int iColumn) 3614 { 3615 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3616 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn); 3617 return E_NOTIMPL; 3618 } 3619 3620 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface, 3621 LPWSTR pszFileSpec, int cchFileSpec) 3622 { 3623 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3624 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec); 3625 return E_NOTIMPL; 3626 } 3627 3628 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface, 3629 IShellView *pshv) 3630 { 3631 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3632 FIXME("Stub: %p (%p)\n", This, pshv); 3633 return E_NOTIMPL; 3634 } 3635 3636 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = { 3637 ICommDlgBrowser3_fnQueryInterface, 3638 ICommDlgBrowser3_fnAddRef, 3639 ICommDlgBrowser3_fnRelease, 3640 ICommDlgBrowser3_fnOnDefaultCommand, 3641 ICommDlgBrowser3_fnOnStateChange, 3642 ICommDlgBrowser3_fnIncludeObject, 3643 ICommDlgBrowser3_fnNotify, 3644 ICommDlgBrowser3_fnGetDefaultMenuText, 3645 ICommDlgBrowser3_fnGetViewFlags, 3646 ICommDlgBrowser3_fnOnColumnClicked, 3647 ICommDlgBrowser3_fnGetCurrentFilter, 3648 ICommDlgBrowser3_fnOnPreviewCreated 3649 }; 3650 3651 /************************************************************************** 3652 * IOleWindow implementation 3653 */ 3654 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface) 3655 { 3656 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface); 3657 } 3658 3659 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject) 3660 { 3661 FileDialogImpl *This = impl_from_IOleWindow(iface); 3662 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3663 } 3664 3665 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface) 3666 { 3667 FileDialogImpl *This = impl_from_IOleWindow(iface); 3668 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3669 } 3670 3671 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface) 3672 { 3673 FileDialogImpl *This = impl_from_IOleWindow(iface); 3674 return IFileDialog2_Release(&This->IFileDialog2_iface); 3675 } 3676 3677 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde) 3678 { 3679 FileDialogImpl *This = impl_from_IOleWindow(iface); 3680 FIXME("Stub: %p (%d)\n", This, fEnterMOde); 3681 return E_NOTIMPL; 3682 } 3683 3684 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd) 3685 { 3686 FileDialogImpl *This = impl_from_IOleWindow(iface); 3687 TRACE("%p (%p)\n", This, phwnd); 3688 *phwnd = This->dlg_hwnd; 3689 return S_OK; 3690 } 3691 3692 static const IOleWindowVtbl vt_IOleWindow = { 3693 IOleWindow_fnQueryInterface, 3694 IOleWindow_fnAddRef, 3695 IOleWindow_fnRelease, 3696 IOleWindow_fnGetWindow, 3697 IOleWindow_fnContextSensitiveHelp 3698 }; 3699 3700 /************************************************************************** 3701 * IFileDialogCustomize implementation 3702 */ 3703 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface) 3704 { 3705 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface); 3706 } 3707 3708 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface, 3709 REFIID riid, void **ppvObject) 3710 { 3711 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3712 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3713 } 3714 3715 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface) 3716 { 3717 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3718 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3719 } 3720 3721 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface) 3722 { 3723 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3724 return IFileDialog2_Release(&This->IFileDialog2_iface); 3725 } 3726 3727 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface, 3728 DWORD dwIDCtl) 3729 { 3730 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3731 MENUINFO mi; 3732 TRACE("%p (%d)\n", This, dwIDCtl); 3733 3734 if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl)) 3735 return E_UNEXPECTED; 3736 3737 This->hmenu_opendropdown = CreatePopupMenu(); 3738 3739 if (!This->hmenu_opendropdown) 3740 return E_OUTOFMEMORY; 3741 3742 mi.cbSize = sizeof(mi); 3743 mi.fMask = MIM_STYLE; 3744 mi.dwStyle = MNS_NOTIFYBYPOS; 3745 SetMenuInfo(This->hmenu_opendropdown, &mi); 3746 3747 This->cctrl_opendropdown.hwnd = NULL; 3748 This->cctrl_opendropdown.wrapper_hwnd = NULL; 3749 This->cctrl_opendropdown.id = dwIDCtl; 3750 This->cctrl_opendropdown.dlgid = 0; 3751 This->cctrl_opendropdown.type = IDLG_CCTRL_OPENDROPDOWN; 3752 This->cctrl_opendropdown.cdcstate = CDCS_ENABLED | CDCS_VISIBLE; 3753 list_init(&This->cctrl_opendropdown.sub_cctrls); 3754 list_init(&This->cctrl_opendropdown.sub_items); 3755 3756 return S_OK; 3757 } 3758 3759 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface, 3760 DWORD dwIDCtl, 3761 LPCWSTR pszLabel) 3762 { 3763 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3764 customctrl *ctrl; 3765 TBBUTTON tbb; 3766 HRESULT hr; 3767 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel); 3768 3769 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW, 3770 TBSTYLE_FLAT | CCS_NODIVIDER, 0, 3771 This->cctrl_def_height, &ctrl); 3772 if(SUCCEEDED(hr)) 3773 { 3774 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0); 3775 ctrl->type = IDLG_CCTRL_MENU; 3776 3777 /* Add the actual button with a popup menu. */ 3778 tbb.iBitmap = I_IMAGENONE; 3779 tbb.dwData = (DWORD_PTR)CreatePopupMenu(); 3780 tbb.iString = (DWORD_PTR)pszLabel; 3781 tbb.fsState = TBSTATE_ENABLED; 3782 tbb.fsStyle = BTNS_WHOLEDROPDOWN; 3783 tbb.idCommand = 1; 3784 3785 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb); 3786 } 3787 3788 return hr; 3789 } 3790 3791 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface, 3792 DWORD dwIDCtl, 3793 LPCWSTR pszLabel) 3794 { 3795 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3796 customctrl *ctrl; 3797 HRESULT hr; 3798 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel); 3799 3800 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0, 3801 This->cctrl_def_height, &ctrl); 3802 if(SUCCEEDED(hr)) 3803 ctrl->type = IDLG_CCTRL_PUSHBUTTON; 3804 3805 return hr; 3806 } 3807 3808 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface, 3809 DWORD dwIDCtl) 3810 { 3811 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3812 customctrl *ctrl; 3813 HRESULT hr; 3814 TRACE("%p (%d)\n", This, dwIDCtl); 3815 3816 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0, 3817 This->cctrl_def_height, &ctrl); 3818 if(SUCCEEDED(hr)) 3819 ctrl->type = IDLG_CCTRL_COMBOBOX; 3820 3821 return hr; 3822 } 3823 3824 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface, 3825 DWORD dwIDCtl) 3826 { 3827 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3828 customctrl *ctrl; 3829 HRESULT hr; 3830 TRACE("%p (%d)\n", This, dwIDCtl); 3831 3832 hr = cctrl_create_new(This, dwIDCtl, NULL, radiobuttonlistW, 0, 0, 0, &ctrl); 3833 if(SUCCEEDED(hr)) 3834 { 3835 ctrl->type = IDLG_CCTRL_RADIOBUTTONLIST; 3836 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)This); 3837 } 3838 3839 return hr; 3840 } 3841 3842 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface, 3843 DWORD dwIDCtl, 3844 LPCWSTR pszLabel, 3845 BOOL bChecked) 3846 { 3847 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3848 customctrl *ctrl; 3849 HRESULT hr; 3850 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked); 3851 3852 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0, 3853 This->cctrl_def_height, &ctrl); 3854 if(SUCCEEDED(hr)) 3855 { 3856 ctrl->type = IDLG_CCTRL_CHECKBUTTON; 3857 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0); 3858 } 3859 3860 return hr; 3861 } 3862 3863 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface, 3864 DWORD dwIDCtl, 3865 LPCWSTR pszText) 3866 { 3867 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3868 customctrl *ctrl; 3869 HRESULT hr; 3870 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText); 3871 3872 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE, 3873 This->cctrl_def_height, &ctrl); 3874 if(SUCCEEDED(hr)) 3875 ctrl->type = IDLG_CCTRL_EDITBOX; 3876 3877 return hr; 3878 } 3879 3880 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface, 3881 DWORD dwIDCtl) 3882 { 3883 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3884 customctrl *ctrl; 3885 HRESULT hr; 3886 TRACE("%p (%d)\n", This, dwIDCtl); 3887 3888 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0, 3889 GetSystemMetrics(SM_CYEDGE), &ctrl); 3890 if(SUCCEEDED(hr)) 3891 ctrl->type = IDLG_CCTRL_SEPARATOR; 3892 3893 return hr; 3894 } 3895 3896 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface, 3897 DWORD dwIDCtl, 3898 LPCWSTR pszText) 3899 { 3900 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3901 customctrl *ctrl; 3902 HRESULT hr; 3903 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText); 3904 3905 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0, 3906 This->cctrl_def_height, &ctrl); 3907 if(SUCCEEDED(hr)) 3908 ctrl->type = IDLG_CCTRL_TEXT; 3909 3910 return hr; 3911 } 3912 3913 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface, 3914 DWORD dwIDCtl, 3915 LPCWSTR pszLabel) 3916 { 3917 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3918 customctrl *ctrl = get_cctrl(This, dwIDCtl); 3919 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel); 3920 3921 if(!ctrl) return E_INVALIDARG; 3922 3923 switch(ctrl->type) 3924 { 3925 case IDLG_CCTRL_MENU: 3926 case IDLG_CCTRL_PUSHBUTTON: 3927 case IDLG_CCTRL_CHECKBUTTON: 3928 case IDLG_CCTRL_TEXT: 3929 case IDLG_CCTRL_VISUALGROUP: 3930 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel); 3931 break; 3932 case IDLG_CCTRL_OPENDROPDOWN: 3933 return E_NOTIMPL; 3934 default: 3935 break; 3936 } 3937 3938 return S_OK; 3939 } 3940 3941 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface, 3942 DWORD dwIDCtl, 3943 CDCONTROLSTATEF *pdwState) 3944 { 3945 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3946 customctrl *ctrl = get_cctrl(This, dwIDCtl); 3947 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState); 3948 3949 if(!ctrl || ctrl->type == IDLG_CCTRL_OPENDROPDOWN) return E_NOTIMPL; 3950 3951 *pdwState = ctrl->cdcstate; 3952 return S_OK; 3953 } 3954 3955 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface, 3956 DWORD dwIDCtl, 3957 CDCONTROLSTATEF dwState) 3958 { 3959 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3960 customctrl *ctrl = get_cctrl(This,dwIDCtl); 3961 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState); 3962 3963 if(ctrl && ctrl->hwnd) 3964 { 3965 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE); 3966 3967 if(dwState & CDCS_ENABLED) 3968 wndstyle &= ~(WS_DISABLED); 3969 else 3970 wndstyle |= WS_DISABLED; 3971 3972 if(dwState & CDCS_VISIBLE) 3973 wndstyle |= WS_VISIBLE; 3974 else 3975 wndstyle &= ~(WS_VISIBLE); 3976 3977 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle); 3978 3979 /* We save the state separately since at least one application 3980 * relies on being able to hide a control. */ 3981 ctrl->cdcstate = dwState; 3982 } 3983 3984 return S_OK; 3985 } 3986 3987 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface, 3988 DWORD dwIDCtl, 3989 WCHAR **ppszText) 3990 { 3991 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3992 customctrl *ctrl = get_cctrl(This, dwIDCtl); 3993 WCHAR len, *text; 3994 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText); 3995 3996 if(!ctrl || !ctrl->hwnd || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0))) 3997 return E_FAIL; 3998 3999 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1)); 4000 if(!text) return E_FAIL; 4001 4002 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text); 4003 *ppszText = text; 4004 return S_OK; 4005 } 4006 4007 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface, 4008 DWORD dwIDCtl, 4009 LPCWSTR pszText) 4010 { 4011 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4012 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4013 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText)); 4014 4015 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX) 4016 return E_FAIL; 4017 4018 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText); 4019 return S_OK; 4020 } 4021 4022 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface, 4023 DWORD dwIDCtl, 4024 BOOL *pbChecked) 4025 { 4026 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4027 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4028 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked); 4029 4030 if(ctrl && ctrl->hwnd) 4031 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED); 4032 4033 return S_OK; 4034 } 4035 4036 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface, 4037 DWORD dwIDCtl, 4038 BOOL bChecked) 4039 { 4040 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4041 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4042 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked); 4043 4044 if(ctrl && ctrl->hwnd) 4045 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0); 4046 4047 return S_OK; 4048 } 4049 4050 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem) 4051 { 4052 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0); 4053 UINT i; 4054 if(!count || (count == CB_ERR)) 4055 return -1; 4056 4057 for(i = 0; i < count; i++) 4058 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem) 4059 return i; 4060 4061 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count); 4062 return -1; 4063 } 4064 4065 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface, 4066 DWORD dwIDCtl, 4067 DWORD dwIDItem, 4068 LPCWSTR pszLabel) 4069 { 4070 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4071 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4072 HRESULT hr; 4073 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel)); 4074 4075 if(!ctrl) return E_FAIL; 4076 4077 switch(ctrl->type) 4078 { 4079 case IDLG_CCTRL_COMBOBOX: 4080 { 4081 UINT index; 4082 cctrl_item* item; 4083 4084 hr = add_item(ctrl, dwIDItem, pszLabel, &item); 4085 4086 if (FAILED(hr)) return hr; 4087 4088 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel); 4089 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem); 4090 4091 return S_OK; 4092 } 4093 case IDLG_CCTRL_MENU: 4094 case IDLG_CCTRL_OPENDROPDOWN: 4095 { 4096 cctrl_item* item; 4097 HMENU hmenu; 4098 4099 hr = add_item(ctrl, dwIDItem, pszLabel, &item); 4100 4101 if (FAILED(hr)) return hr; 4102 4103 if (ctrl->type == IDLG_CCTRL_MENU) 4104 { 4105 TBBUTTON tbb; 4106 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb); 4107 hmenu = (HMENU)tbb.dwData; 4108 } 4109 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */ 4110 hmenu = This->hmenu_opendropdown; 4111 4112 AppendMenuW(hmenu, MF_STRING, dwIDItem, pszLabel); 4113 return S_OK; 4114 } 4115 case IDLG_CCTRL_RADIOBUTTONLIST: 4116 { 4117 cctrl_item* item; 4118 4119 hr = add_item(ctrl, dwIDItem, pszLabel, &item); 4120 4121 if (SUCCEEDED(hr)) 4122 { 4123 item->hwnd = CreateWindowExW(0, WC_BUTTONW, pszLabel, 4124 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|BS_RADIOBUTTON|BS_MULTILINE, 4125 0, 0, 0, 0, ctrl->hwnd, ULongToHandle(dwIDItem), COMDLG32_hInstance, 0); 4126 4127 if (!item->hwnd) 4128 { 4129 ERR("Failed to create radio button\n"); 4130 list_remove(&item->entry); 4131 item_free(item); 4132 return E_FAIL; 4133 } 4134 } 4135 4136 return hr; 4137 } 4138 default: 4139 break; 4140 } 4141 4142 return E_NOINTERFACE; /* win7 */ 4143 } 4144 4145 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface, 4146 DWORD dwIDCtl, 4147 DWORD dwIDItem) 4148 { 4149 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4150 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4151 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem); 4152 4153 if(!ctrl) return E_FAIL; 4154 4155 switch(ctrl->type) 4156 { 4157 case IDLG_CCTRL_COMBOBOX: 4158 { 4159 cctrl_item* item; 4160 DWORD position; 4161 4162 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position); 4163 4164 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED)) 4165 { 4166 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0) == CB_ERR) 4167 return E_FAIL; 4168 } 4169 4170 list_remove(&item->entry); 4171 item_free(item); 4172 4173 return S_OK; 4174 } 4175 case IDLG_CCTRL_MENU: 4176 case IDLG_CCTRL_OPENDROPDOWN: 4177 { 4178 HMENU hmenu; 4179 cctrl_item* item; 4180 4181 item = get_item(ctrl, dwIDItem, 0, NULL); 4182 4183 if (!item) 4184 return E_UNEXPECTED; 4185 4186 if (item->cdcstate & CDCS_VISIBLE) 4187 { 4188 if (ctrl->type == IDLG_CCTRL_MENU) 4189 { 4190 TBBUTTON tbb; 4191 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb); 4192 hmenu = (HMENU)tbb.dwData; 4193 } 4194 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */ 4195 hmenu = This->hmenu_opendropdown; 4196 4197 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND)) 4198 return E_UNEXPECTED; 4199 } 4200 4201 list_remove(&item->entry); 4202 item_free(item); 4203 4204 return S_OK; 4205 } 4206 case IDLG_CCTRL_RADIOBUTTONLIST: 4207 { 4208 cctrl_item* item; 4209 4210 item = get_item(ctrl, dwIDItem, 0, NULL); 4211 4212 if (!item) 4213 return E_UNEXPECTED; 4214 4215 list_remove(&item->entry); 4216 item_free(item); 4217 4218 return S_OK; 4219 } 4220 default: 4221 break; 4222 } 4223 4224 return E_FAIL; 4225 } 4226 4227 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface, 4228 DWORD dwIDCtl) 4229 { 4230 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4231 TRACE("%p (%d)\n", This, dwIDCtl); 4232 4233 /* Not implemented by native */ 4234 return E_NOTIMPL; 4235 } 4236 4237 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface, 4238 DWORD dwIDCtl, 4239 DWORD dwIDItem, 4240 CDCONTROLSTATEF *pdwState) 4241 { 4242 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4243 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4244 TRACE("%p (%d, %d, %p)\n", This, dwIDCtl, dwIDItem, pdwState); 4245 4246 if(!ctrl) return E_FAIL; 4247 4248 switch(ctrl->type) 4249 { 4250 case IDLG_CCTRL_COMBOBOX: 4251 case IDLG_CCTRL_MENU: 4252 case IDLG_CCTRL_OPENDROPDOWN: 4253 case IDLG_CCTRL_RADIOBUTTONLIST: 4254 { 4255 cctrl_item* item; 4256 4257 item = get_item(ctrl, dwIDItem, 0, NULL); 4258 4259 if (!item) 4260 return E_UNEXPECTED; 4261 4262 *pdwState = item->cdcstate; 4263 4264 return S_OK; 4265 } 4266 default: 4267 break; 4268 } 4269 4270 return E_FAIL; 4271 } 4272 4273 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface, 4274 DWORD dwIDCtl, 4275 DWORD dwIDItem, 4276 CDCONTROLSTATEF dwState) 4277 { 4278 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4279 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4280 TRACE("%p (%d, %d, %x)\n", This, dwIDCtl, dwIDItem, dwState); 4281 4282 if(!ctrl) return E_FAIL; 4283 4284 switch(ctrl->type) 4285 { 4286 case IDLG_CCTRL_COMBOBOX: 4287 { 4288 cctrl_item* item; 4289 BOOL visible, was_visible; 4290 DWORD position; 4291 4292 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position); 4293 4294 if (!item) 4295 return E_UNEXPECTED; 4296 4297 visible = ((dwState & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED)); 4298 was_visible = ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED)); 4299 4300 if (visible && !was_visible) 4301 { 4302 SendMessageW(ctrl->hwnd, CB_INSERTSTRING, position, (LPARAM)item->label); 4303 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, position, dwIDItem); 4304 } 4305 else if (!visible && was_visible) 4306 { 4307 SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0); 4308 } 4309 4310 item->cdcstate = dwState; 4311 4312 return S_OK; 4313 } 4314 case IDLG_CCTRL_MENU: 4315 case IDLG_CCTRL_OPENDROPDOWN: 4316 { 4317 HMENU hmenu; 4318 cctrl_item* item; 4319 CDCONTROLSTATEF prev_state; 4320 DWORD position; 4321 4322 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, &position); 4323 4324 if (!item) 4325 return E_UNEXPECTED; 4326 4327 prev_state = item->cdcstate; 4328 4329 if (ctrl->type == IDLG_CCTRL_MENU) 4330 { 4331 TBBUTTON tbb; 4332 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb); 4333 hmenu = (HMENU)tbb.dwData; 4334 } 4335 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */ 4336 hmenu = This->hmenu_opendropdown; 4337 4338 if (dwState & CDCS_VISIBLE) 4339 { 4340 if (prev_state & CDCS_VISIBLE) 4341 { 4342 /* change state */ 4343 EnableMenuItem(hmenu, dwIDItem, 4344 MF_BYCOMMAND|((dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED)); 4345 } 4346 else 4347 { 4348 /* show item */ 4349 MENUITEMINFOW mii; 4350 4351 mii.cbSize = sizeof(mii); 4352 mii.fMask = MIIM_ID|MIIM_STATE|MIIM_STRING; 4353 mii.fState = (dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED; 4354 mii.wID = dwIDItem; 4355 mii.dwTypeData = item->label; 4356 4357 InsertMenuItemW(hmenu, position, TRUE, &mii); 4358 } 4359 } 4360 else if (prev_state & CDCS_VISIBLE) 4361 { 4362 /* hide item */ 4363 DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND); 4364 } 4365 4366 item->cdcstate = dwState; 4367 4368 if (ctrl->type == IDLG_CCTRL_OPENDROPDOWN) 4369 { 4370 update_control_text(This); 4371 update_layout(This); 4372 } 4373 4374 return S_OK; 4375 } 4376 case IDLG_CCTRL_RADIOBUTTONLIST: 4377 { 4378 cctrl_item* item; 4379 4380 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, NULL); 4381 4382 if (!item) 4383 return E_UNEXPECTED; 4384 4385 /* Oddly, native allows setting this but doesn't seem to do anything with it. */ 4386 item->cdcstate = dwState; 4387 4388 return S_OK; 4389 } 4390 default: 4391 break; 4392 } 4393 4394 return E_FAIL; 4395 } 4396 4397 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface, 4398 DWORD dwIDCtl, 4399 DWORD *pdwIDItem) 4400 { 4401 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4402 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4403 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem); 4404 4405 if(!ctrl) return E_FAIL; 4406 4407 switch(ctrl->type) 4408 { 4409 case IDLG_CCTRL_COMBOBOX: 4410 { 4411 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0); 4412 if(index == CB_ERR) 4413 return E_FAIL; 4414 4415 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0); 4416 return S_OK; 4417 } 4418 case IDLG_CCTRL_OPENDROPDOWN: 4419 if (This->opendropdown_has_selection) 4420 { 4421 *pdwIDItem = This->opendropdown_selection; 4422 return S_OK; 4423 } 4424 else 4425 { 4426 /* Return first enabled item. */ 4427 cctrl_item* item = get_first_item(ctrl); 4428 4429 if (item) 4430 { 4431 *pdwIDItem = item->id; 4432 return S_OK; 4433 } 4434 4435 WARN("no enabled items in open dropdown\n"); 4436 return E_FAIL; 4437 } 4438 case IDLG_CCTRL_RADIOBUTTONLIST: 4439 { 4440 cctrl_item* item; 4441 4442 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry) 4443 { 4444 if (SendMessageW(item->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) 4445 { 4446 *pdwIDItem = item->id; 4447 return S_OK; 4448 } 4449 } 4450 4451 WARN("no checked items in radio button list\n"); 4452 return E_FAIL; 4453 } 4454 default: 4455 FIXME("Unsupported control type %d\n", ctrl->type); 4456 } 4457 4458 return E_NOTIMPL; 4459 } 4460 4461 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface, 4462 DWORD dwIDCtl, 4463 DWORD dwIDItem) 4464 { 4465 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4466 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4467 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem); 4468 4469 if(!ctrl) return E_INVALIDARG; 4470 4471 switch(ctrl->type) 4472 { 4473 case IDLG_CCTRL_COMBOBOX: 4474 { 4475 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem); 4476 4477 if(index == -1) 4478 return E_INVALIDARG; 4479 4480 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR) 4481 return E_FAIL; 4482 4483 return S_OK; 4484 } 4485 case IDLG_CCTRL_RADIOBUTTONLIST: 4486 { 4487 cctrl_item* item; 4488 4489 item = get_item(ctrl, dwIDItem, 0, NULL); 4490 4491 if (item) 4492 { 4493 radiobuttonlist_set_selected_item(This, ctrl, item); 4494 return S_OK; 4495 } 4496 4497 return E_INVALIDARG; 4498 } 4499 default: 4500 FIXME("Unsupported control type %d\n", ctrl->type); 4501 } 4502 4503 return E_INVALIDARG; 4504 } 4505 4506 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface, 4507 DWORD dwIDCtl, 4508 LPCWSTR pszLabel) 4509 { 4510 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4511 customctrl *vg; 4512 HRESULT hr; 4513 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel)); 4514 4515 if(This->cctrl_active_vg) 4516 return E_UNEXPECTED; 4517 4518 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0, 4519 This->cctrl_def_height, &vg); 4520 if(SUCCEEDED(hr)) 4521 { 4522 vg->type = IDLG_CCTRL_VISUALGROUP; 4523 This->cctrl_active_vg = vg; 4524 } 4525 4526 return hr; 4527 } 4528 4529 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface) 4530 { 4531 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4532 TRACE("%p\n", This); 4533 4534 This->cctrl_active_vg = NULL; 4535 4536 return S_OK; 4537 } 4538 4539 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface, 4540 DWORD dwIDCtl) 4541 { 4542 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4543 FIXME("stub - %p (%d)\n", This, dwIDCtl); 4544 return S_OK; 4545 } 4546 4547 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface, 4548 DWORD dwIDCtl, 4549 DWORD dwIDItem, 4550 LPCWSTR pszLabel) 4551 { 4552 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4553 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel)); 4554 return E_NOTIMPL; 4555 } 4556 4557 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = { 4558 IFileDialogCustomize_fnQueryInterface, 4559 IFileDialogCustomize_fnAddRef, 4560 IFileDialogCustomize_fnRelease, 4561 IFileDialogCustomize_fnEnableOpenDropDown, 4562 IFileDialogCustomize_fnAddMenu, 4563 IFileDialogCustomize_fnAddPushButton, 4564 IFileDialogCustomize_fnAddComboBox, 4565 IFileDialogCustomize_fnAddRadioButtonList, 4566 IFileDialogCustomize_fnAddCheckButton, 4567 IFileDialogCustomize_fnAddEditBox, 4568 IFileDialogCustomize_fnAddSeparator, 4569 IFileDialogCustomize_fnAddText, 4570 IFileDialogCustomize_fnSetControlLabel, 4571 IFileDialogCustomize_fnGetControlState, 4572 IFileDialogCustomize_fnSetControlState, 4573 IFileDialogCustomize_fnGetEditBoxText, 4574 IFileDialogCustomize_fnSetEditBoxText, 4575 IFileDialogCustomize_fnGetCheckButtonState, 4576 IFileDialogCustomize_fnSetCheckButtonState, 4577 IFileDialogCustomize_fnAddControlItem, 4578 IFileDialogCustomize_fnRemoveControlItem, 4579 IFileDialogCustomize_fnRemoveAllControlItems, 4580 IFileDialogCustomize_fnGetControlItemState, 4581 IFileDialogCustomize_fnSetControlItemState, 4582 IFileDialogCustomize_fnGetSelectedControlItem, 4583 IFileDialogCustomize_fnSetSelectedControlItem, 4584 IFileDialogCustomize_fnStartVisualGroup, 4585 IFileDialogCustomize_fnEndVisualGroup, 4586 IFileDialogCustomize_fnMakeProminent, 4587 IFileDialogCustomize_fnSetControlItemText 4588 }; 4589 4590 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type) 4591 { 4592 FileDialogImpl *fdimpl; 4593 HRESULT hr; 4594 IShellFolder *psf; 4595 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv); 4596 4597 if(!ppv) 4598 return E_POINTER; 4599 if(pUnkOuter) 4600 return CLASS_E_NOAGGREGATION; 4601 4602 fdimpl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FileDialogImpl)); 4603 if(!fdimpl) 4604 return E_OUTOFMEMORY; 4605 4606 fdimpl->ref = 1; 4607 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2; 4608 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents; 4609 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider; 4610 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3; 4611 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow; 4612 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize; 4613 4614 if(type == ITEMDLG_TYPE_OPEN) 4615 { 4616 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN; 4617 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog; 4618 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR; 4619 fdimpl->custom_title = fdimpl->custom_okbutton = NULL; 4620 } 4621 else 4622 { 4623 WCHAR buf[16]; 4624 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE; 4625 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog; 4626 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR; 4627 4628 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR)); 4629 fdimpl->custom_title = StrDupW(buf); 4630 fdimpl->custom_okbutton = StrDupW(buf); 4631 } 4632 4633 list_init(&fdimpl->events_clients); 4634 4635 /* FIXME: The default folder setting should be restored for the 4636 * application if it was previously set. */ 4637 SHGetDesktopFolder(&psf); 4638 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder); 4639 IShellFolder_Release(psf); 4640 4641 hr = init_custom_controls(fdimpl); 4642 if(FAILED(hr)) 4643 { 4644 ERR("Failed to initialize custom controls (0x%08x).\n", hr); 4645 IFileDialog2_Release(&fdimpl->IFileDialog2_iface); 4646 return E_FAIL; 4647 } 4648 4649 hr = IFileDialog2_QueryInterface(&fdimpl->IFileDialog2_iface, riid, ppv); 4650 IFileDialog2_Release(&fdimpl->IFileDialog2_iface); 4651 return hr; 4652 } 4653 4654 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) 4655 { 4656 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN); 4657 } 4658 4659 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) 4660 { 4661 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE); 4662 } 4663 4664 #endif /* Win 7 */ 4665