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, (This->options & FOS_PICKFOLDERS) ? SIGDN_FILESYSPATH : SIGDN_PARENTRELATIVEPARSING, &names[valid_count]); 430 if(SUCCEEDED(hr)) 431 { 432 len_total += lstrlenW(names[valid_count]) + 3; 433 valid_count++; 434 } 435 IShellItem_Release(psi); 436 } 437 } 438 439 if(valid_count == 1) 440 { 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, ARRAY_SIZE(buf)); 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 (fos & ~(FOS_OVERWRITEPROMPT | FOS_STRICTFILETYPES | FOS_NOCHANGEDIR | FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM 2511 | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_ALLOWMULTISELECT | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST 2512 | FOS_CREATEPROMPT | FOS_SHAREAWARE | FOS_NOREADONLYRETURN | FOS_NOTESTFILECREATE | FOS_HIDEMRUPLACES 2513 | FOS_HIDEPINNEDPLACES | FOS_NODEREFERENCELINKS | FOS_DONTADDTORECENT | FOS_FORCESHOWHIDDEN 2514 | FOS_DEFAULTNOMINIMODE | FOS_FORCEPREVIEWPANEON | FOS_SUPPORTSTREAMABLEITEMS)) 2515 { 2516 WARN("Invalid option %#x\n", fos); 2517 return E_INVALIDARG; 2518 } 2519 2520 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) ) 2521 { 2522 WCHAR buf[30]; 2523 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, ARRAY_SIZE(buf)); 2524 IFileDialog2_SetTitle(iface, buf); 2525 } 2526 2527 This->options = fos; 2528 2529 return S_OK; 2530 } 2531 2532 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos) 2533 { 2534 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2535 TRACE("%p (%p)\n", This, pfos); 2536 2537 if(!pfos) 2538 return E_INVALIDARG; 2539 2540 *pfos = This->options; 2541 2542 return S_OK; 2543 } 2544 2545 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi) 2546 { 2547 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2548 TRACE("%p (%p)\n", This, psi); 2549 if(This->psi_defaultfolder) 2550 IShellItem_Release(This->psi_defaultfolder); 2551 2552 This->psi_defaultfolder = psi; 2553 2554 if(This->psi_defaultfolder) 2555 IShellItem_AddRef(This->psi_defaultfolder); 2556 2557 return S_OK; 2558 } 2559 2560 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi) 2561 { 2562 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2563 TRACE("%p (%p)\n", This, psi); 2564 if(This->psi_setfolder) 2565 IShellItem_Release(This->psi_setfolder); 2566 2567 This->psi_setfolder = psi; 2568 2569 if(This->psi_setfolder) 2570 IShellItem_AddRef(This->psi_setfolder); 2571 2572 return S_OK; 2573 } 2574 2575 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi) 2576 { 2577 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2578 TRACE("%p (%p)\n", This, ppsi); 2579 if(!ppsi) 2580 return E_INVALIDARG; 2581 2582 /* FIXME: 2583 If the dialog is shown, return the current(ly selected) folder. */ 2584 2585 *ppsi = NULL; 2586 if(This->psi_folder) 2587 *ppsi = This->psi_folder; 2588 else if(This->psi_setfolder) 2589 *ppsi = This->psi_setfolder; 2590 else if(This->psi_defaultfolder) 2591 *ppsi = This->psi_defaultfolder; 2592 2593 if(*ppsi) 2594 { 2595 IShellItem_AddRef(*ppsi); 2596 return S_OK; 2597 } 2598 2599 return E_FAIL; 2600 } 2601 2602 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi) 2603 { 2604 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2605 HRESULT hr; 2606 TRACE("%p (%p)\n", This, ppsi); 2607 2608 if(!ppsi) 2609 return E_INVALIDARG; 2610 2611 if(This->psia_selection) 2612 { 2613 /* FIXME: Check filename edit box */ 2614 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi); 2615 return hr; 2616 } 2617 2618 return E_FAIL; 2619 } 2620 2621 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName) 2622 { 2623 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2624 TRACE("%p (%s)\n", iface, debugstr_w(pszName)); 2625 2626 set_file_name(This, pszName); 2627 2628 return S_OK; 2629 } 2630 2631 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName) 2632 { 2633 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2634 TRACE("%p (%p)\n", iface, pszName); 2635 2636 if(!pszName) 2637 return E_INVALIDARG; 2638 2639 *pszName = NULL; 2640 get_file_name(This, pszName); 2641 return *pszName ? S_OK : E_FAIL; 2642 } 2643 2644 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle) 2645 { 2646 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2647 TRACE("%p (%s)\n", This, debugstr_w(pszTitle)); 2648 2649 LocalFree(This->custom_title); 2650 This->custom_title = StrDupW(pszTitle); 2651 update_control_text(This); 2652 2653 return S_OK; 2654 } 2655 2656 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText) 2657 { 2658 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2659 TRACE("%p (%s)\n", This, debugstr_w(pszText)); 2660 2661 LocalFree(This->custom_okbutton); 2662 This->custom_okbutton = StrDupW(pszText); 2663 update_control_text(This); 2664 update_layout(This); 2665 2666 return S_OK; 2667 } 2668 2669 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel) 2670 { 2671 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2672 TRACE("%p (%s)\n", This, debugstr_w(pszLabel)); 2673 2674 LocalFree(This->custom_filenamelabel); 2675 This->custom_filenamelabel = StrDupW(pszLabel); 2676 update_control_text(This); 2677 update_layout(This); 2678 2679 return S_OK; 2680 } 2681 2682 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi) 2683 { 2684 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2685 HRESULT hr; 2686 TRACE("%p (%p)\n", This, ppsi); 2687 2688 if(!ppsi) 2689 return E_INVALIDARG; 2690 2691 if(This->psia_results) 2692 { 2693 UINT item_count; 2694 hr = IShellItemArray_GetCount(This->psia_results, &item_count); 2695 if(SUCCEEDED(hr)) 2696 { 2697 if(item_count != 1) 2698 return E_FAIL; 2699 2700 /* Adds a reference. */ 2701 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi); 2702 } 2703 2704 return hr; 2705 } 2706 2707 return E_UNEXPECTED; 2708 } 2709 2710 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap) 2711 { 2712 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2713 FIXME("stub - %p (%p, %d)\n", This, psi, fdap); 2714 return S_OK; 2715 } 2716 2717 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension) 2718 { 2719 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2720 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension)); 2721 2722 LocalFree(This->default_ext); 2723 This->default_ext = StrDupW(pszDefaultExtension); 2724 2725 return S_OK; 2726 } 2727 2728 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr) 2729 { 2730 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2731 TRACE("%p (0x%08x)\n", This, hr); 2732 2733 if(This->dlg_hwnd) 2734 EndDialog(This->dlg_hwnd, hr); 2735 2736 return S_OK; 2737 } 2738 2739 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid) 2740 { 2741 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2742 TRACE("%p (%s)\n", This, debugstr_guid(guid)); 2743 This->client_guid = *guid; 2744 return S_OK; 2745 } 2746 2747 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface) 2748 { 2749 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2750 FIXME("stub - %p\n", This); 2751 return E_NOTIMPL; 2752 } 2753 2754 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter) 2755 { 2756 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2757 FIXME("stub - %p (%p)\n", This, pFilter); 2758 return E_NOTIMPL; 2759 } 2760 2761 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel) 2762 { 2763 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2764 TRACE("%p (%s)\n", This, debugstr_w(pszLabel)); 2765 2766 LocalFree(This->custom_cancelbutton); 2767 This->custom_cancelbutton = StrDupW(pszLabel); 2768 update_control_text(This); 2769 update_layout(This); 2770 2771 return S_OK; 2772 } 2773 2774 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi) 2775 { 2776 FileDialogImpl *This = impl_from_IFileDialog2(iface); 2777 FIXME("stub - %p (%p)\n", This, psi); 2778 return E_NOTIMPL; 2779 } 2780 2781 static const IFileDialog2Vtbl vt_IFileDialog2 = { 2782 IFileDialog2_fnQueryInterface, 2783 IFileDialog2_fnAddRef, 2784 IFileDialog2_fnRelease, 2785 IFileDialog2_fnShow, 2786 IFileDialog2_fnSetFileTypes, 2787 IFileDialog2_fnSetFileTypeIndex, 2788 IFileDialog2_fnGetFileTypeIndex, 2789 IFileDialog2_fnAdvise, 2790 IFileDialog2_fnUnadvise, 2791 IFileDialog2_fnSetOptions, 2792 IFileDialog2_fnGetOptions, 2793 IFileDialog2_fnSetDefaultFolder, 2794 IFileDialog2_fnSetFolder, 2795 IFileDialog2_fnGetFolder, 2796 IFileDialog2_fnGetCurrentSelection, 2797 IFileDialog2_fnSetFileName, 2798 IFileDialog2_fnGetFileName, 2799 IFileDialog2_fnSetTitle, 2800 IFileDialog2_fnSetOkButtonLabel, 2801 IFileDialog2_fnSetFileNameLabel, 2802 IFileDialog2_fnGetResult, 2803 IFileDialog2_fnAddPlace, 2804 IFileDialog2_fnSetDefaultExtension, 2805 IFileDialog2_fnClose, 2806 IFileDialog2_fnSetClientGuid, 2807 IFileDialog2_fnClearClientData, 2808 IFileDialog2_fnSetFilter, 2809 IFileDialog2_fnSetCancelButtonLabel, 2810 IFileDialog2_fnSetNavigationRoot 2811 }; 2812 2813 /************************************************************************** 2814 * IFileOpenDialog 2815 */ 2816 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface) 2817 { 2818 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface); 2819 } 2820 2821 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface, 2822 REFIID riid, void **ppvObject) 2823 { 2824 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2825 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 2826 } 2827 2828 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface) 2829 { 2830 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2831 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 2832 } 2833 2834 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface) 2835 { 2836 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2837 return IFileDialog2_Release(&This->IFileDialog2_iface); 2838 } 2839 2840 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner) 2841 { 2842 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2843 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner); 2844 } 2845 2846 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes, 2847 const COMDLG_FILTERSPEC *rgFilterSpec) 2848 { 2849 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2850 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec); 2851 } 2852 2853 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType) 2854 { 2855 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2856 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType); 2857 } 2858 2859 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType) 2860 { 2861 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2862 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType); 2863 } 2864 2865 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde, 2866 DWORD *pdwCookie) 2867 { 2868 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2869 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie); 2870 } 2871 2872 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie) 2873 { 2874 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2875 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie); 2876 } 2877 2878 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos) 2879 { 2880 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2881 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos); 2882 } 2883 2884 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos) 2885 { 2886 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2887 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos); 2888 } 2889 2890 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi) 2891 { 2892 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2893 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi); 2894 } 2895 2896 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi) 2897 { 2898 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2899 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi); 2900 } 2901 2902 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi) 2903 { 2904 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2905 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi); 2906 } 2907 2908 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi) 2909 { 2910 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2911 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi); 2912 } 2913 2914 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName) 2915 { 2916 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2917 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName); 2918 } 2919 2920 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName) 2921 { 2922 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2923 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName); 2924 } 2925 2926 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle) 2927 { 2928 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2929 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle); 2930 } 2931 2932 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText) 2933 { 2934 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2935 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText); 2936 } 2937 2938 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel) 2939 { 2940 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2941 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel); 2942 } 2943 2944 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi) 2945 { 2946 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2947 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi); 2948 } 2949 2950 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap) 2951 { 2952 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2953 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap); 2954 } 2955 2956 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface, 2957 LPCWSTR pszDefaultExtension) 2958 { 2959 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2960 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension); 2961 } 2962 2963 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr) 2964 { 2965 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2966 return IFileDialog2_Close(&This->IFileDialog2_iface, hr); 2967 } 2968 2969 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid) 2970 { 2971 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2972 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid); 2973 } 2974 2975 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface) 2976 { 2977 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2978 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface); 2979 } 2980 2981 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter) 2982 { 2983 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2984 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter); 2985 } 2986 2987 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum) 2988 { 2989 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 2990 TRACE("%p (%p)\n", This, ppenum); 2991 2992 *ppenum = This->psia_results; 2993 2994 if(*ppenum) 2995 { 2996 IShellItemArray_AddRef(*ppenum); 2997 return S_OK; 2998 } 2999 3000 return E_FAIL; 3001 } 3002 3003 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai) 3004 { 3005 FileDialogImpl *This = impl_from_IFileOpenDialog(iface); 3006 TRACE("%p (%p)\n", This, ppsai); 3007 3008 if(This->psia_selection) 3009 { 3010 *ppsai = This->psia_selection; 3011 IShellItemArray_AddRef(*ppsai); 3012 return S_OK; 3013 } 3014 3015 return E_FAIL; 3016 } 3017 3018 static const IFileOpenDialogVtbl vt_IFileOpenDialog = { 3019 IFileOpenDialog_fnQueryInterface, 3020 IFileOpenDialog_fnAddRef, 3021 IFileOpenDialog_fnRelease, 3022 IFileOpenDialog_fnShow, 3023 IFileOpenDialog_fnSetFileTypes, 3024 IFileOpenDialog_fnSetFileTypeIndex, 3025 IFileOpenDialog_fnGetFileTypeIndex, 3026 IFileOpenDialog_fnAdvise, 3027 IFileOpenDialog_fnUnadvise, 3028 IFileOpenDialog_fnSetOptions, 3029 IFileOpenDialog_fnGetOptions, 3030 IFileOpenDialog_fnSetDefaultFolder, 3031 IFileOpenDialog_fnSetFolder, 3032 IFileOpenDialog_fnGetFolder, 3033 IFileOpenDialog_fnGetCurrentSelection, 3034 IFileOpenDialog_fnSetFileName, 3035 IFileOpenDialog_fnGetFileName, 3036 IFileOpenDialog_fnSetTitle, 3037 IFileOpenDialog_fnSetOkButtonLabel, 3038 IFileOpenDialog_fnSetFileNameLabel, 3039 IFileOpenDialog_fnGetResult, 3040 IFileOpenDialog_fnAddPlace, 3041 IFileOpenDialog_fnSetDefaultExtension, 3042 IFileOpenDialog_fnClose, 3043 IFileOpenDialog_fnSetClientGuid, 3044 IFileOpenDialog_fnClearClientData, 3045 IFileOpenDialog_fnSetFilter, 3046 IFileOpenDialog_fnGetResults, 3047 IFileOpenDialog_fnGetSelectedItems 3048 }; 3049 3050 /************************************************************************** 3051 * IFileSaveDialog 3052 */ 3053 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface) 3054 { 3055 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface); 3056 } 3057 3058 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface, 3059 REFIID riid, 3060 void **ppvObject) 3061 { 3062 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3063 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3064 } 3065 3066 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface) 3067 { 3068 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3069 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3070 } 3071 3072 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface) 3073 { 3074 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3075 return IFileDialog2_Release(&This->IFileDialog2_iface); 3076 } 3077 3078 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner) 3079 { 3080 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3081 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner); 3082 } 3083 3084 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes, 3085 const COMDLG_FILTERSPEC *rgFilterSpec) 3086 { 3087 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3088 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec); 3089 } 3090 3091 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType) 3092 { 3093 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3094 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType); 3095 } 3096 3097 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType) 3098 { 3099 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3100 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType); 3101 } 3102 3103 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde, 3104 DWORD *pdwCookie) 3105 { 3106 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3107 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie); 3108 } 3109 3110 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie) 3111 { 3112 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3113 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie); 3114 } 3115 3116 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos) 3117 { 3118 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3119 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos); 3120 } 3121 3122 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos) 3123 { 3124 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3125 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos); 3126 } 3127 3128 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi) 3129 { 3130 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3131 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi); 3132 } 3133 3134 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi) 3135 { 3136 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3137 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi); 3138 } 3139 3140 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi) 3141 { 3142 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3143 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi); 3144 } 3145 3146 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi) 3147 { 3148 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3149 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi); 3150 } 3151 3152 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName) 3153 { 3154 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3155 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName); 3156 } 3157 3158 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName) 3159 { 3160 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3161 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName); 3162 } 3163 3164 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle) 3165 { 3166 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3167 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle); 3168 } 3169 3170 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText) 3171 { 3172 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3173 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText); 3174 } 3175 3176 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel) 3177 { 3178 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3179 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel); 3180 } 3181 3182 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi) 3183 { 3184 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3185 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi); 3186 } 3187 3188 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap) 3189 { 3190 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3191 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap); 3192 } 3193 3194 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface, 3195 LPCWSTR pszDefaultExtension) 3196 { 3197 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3198 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension); 3199 } 3200 3201 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr) 3202 { 3203 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3204 return IFileDialog2_Close(&This->IFileDialog2_iface, hr); 3205 } 3206 3207 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid) 3208 { 3209 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3210 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid); 3211 } 3212 3213 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface) 3214 { 3215 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3216 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface); 3217 } 3218 3219 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter) 3220 { 3221 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3222 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter); 3223 } 3224 3225 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi) 3226 { 3227 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3228 FIXME("stub - %p (%p)\n", This, psi); 3229 return E_NOTIMPL; 3230 } 3231 3232 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore) 3233 { 3234 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3235 FIXME("stub - %p (%p)\n", This, pStore); 3236 return E_NOTIMPL; 3237 } 3238 3239 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface, 3240 IPropertyDescriptionList *pList, 3241 BOOL fAppendDefault) 3242 { 3243 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3244 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault); 3245 return E_NOTIMPL; 3246 } 3247 3248 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore) 3249 { 3250 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3251 FIXME("stub - %p (%p)\n", This, ppStore); 3252 return E_NOTIMPL; 3253 } 3254 3255 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface, 3256 IShellItem *psi, 3257 IPropertyStore *pStore, 3258 HWND hwnd, 3259 IFileOperationProgressSink *pSink) 3260 { 3261 FileDialogImpl *This = impl_from_IFileSaveDialog(iface); 3262 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink); 3263 return E_NOTIMPL; 3264 } 3265 3266 static const IFileSaveDialogVtbl vt_IFileSaveDialog = { 3267 IFileSaveDialog_fnQueryInterface, 3268 IFileSaveDialog_fnAddRef, 3269 IFileSaveDialog_fnRelease, 3270 IFileSaveDialog_fnShow, 3271 IFileSaveDialog_fnSetFileTypes, 3272 IFileSaveDialog_fnSetFileTypeIndex, 3273 IFileSaveDialog_fnGetFileTypeIndex, 3274 IFileSaveDialog_fnAdvise, 3275 IFileSaveDialog_fnUnadvise, 3276 IFileSaveDialog_fnSetOptions, 3277 IFileSaveDialog_fnGetOptions, 3278 IFileSaveDialog_fnSetDefaultFolder, 3279 IFileSaveDialog_fnSetFolder, 3280 IFileSaveDialog_fnGetFolder, 3281 IFileSaveDialog_fnGetCurrentSelection, 3282 IFileSaveDialog_fnSetFileName, 3283 IFileSaveDialog_fnGetFileName, 3284 IFileSaveDialog_fnSetTitle, 3285 IFileSaveDialog_fnSetOkButtonLabel, 3286 IFileSaveDialog_fnSetFileNameLabel, 3287 IFileSaveDialog_fnGetResult, 3288 IFileSaveDialog_fnAddPlace, 3289 IFileSaveDialog_fnSetDefaultExtension, 3290 IFileSaveDialog_fnClose, 3291 IFileSaveDialog_fnSetClientGuid, 3292 IFileSaveDialog_fnClearClientData, 3293 IFileSaveDialog_fnSetFilter, 3294 IFileSaveDialog_fnSetSaveAsItem, 3295 IFileSaveDialog_fnSetProperties, 3296 IFileSaveDialog_fnSetCollectedProperties, 3297 IFileSaveDialog_fnGetProperties, 3298 IFileSaveDialog_fnApplyProperties 3299 }; 3300 3301 /************************************************************************** 3302 * IExplorerBrowserEvents implementation 3303 */ 3304 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface) 3305 { 3306 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface); 3307 } 3308 3309 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface, 3310 REFIID riid, void **ppvObject) 3311 { 3312 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3313 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject); 3314 3315 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3316 } 3317 3318 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface) 3319 { 3320 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3321 TRACE("%p\n", This); 3322 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3323 } 3324 3325 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface) 3326 { 3327 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3328 TRACE("%p\n", This); 3329 return IFileDialog2_Release(&This->IFileDialog2_iface); 3330 } 3331 3332 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface, 3333 PCIDLIST_ABSOLUTE pidlFolder) 3334 { 3335 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3336 IShellItem *psi; 3337 HRESULT hr; 3338 TRACE("%p (%p)\n", This, pidlFolder); 3339 3340 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi); 3341 if(SUCCEEDED(hr)) 3342 { 3343 hr = events_OnFolderChanging(This, psi); 3344 IShellItem_Release(psi); 3345 3346 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */ 3347 if(hr == S_FALSE) 3348 hr = E_FAIL; 3349 3350 return hr; 3351 } 3352 else 3353 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder); 3354 3355 return S_OK; 3356 } 3357 3358 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface, 3359 IShellView *psv) 3360 { 3361 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3362 TRACE("%p (%p)\n", This, psv); 3363 return S_OK; 3364 } 3365 3366 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface, 3367 PCIDLIST_ABSOLUTE pidlFolder) 3368 { 3369 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3370 HRESULT hr; 3371 TRACE("%p (%p)\n", This, pidlFolder); 3372 3373 if(This->psi_folder) 3374 IShellItem_Release(This->psi_folder); 3375 3376 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder); 3377 if(FAILED(hr)) 3378 { 3379 ERR("Failed to get the current folder.\n"); 3380 This->psi_folder = NULL; 3381 } 3382 3383 events_OnFolderChange(This); 3384 3385 return S_OK; 3386 } 3387 3388 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface, 3389 PCIDLIST_ABSOLUTE pidlFolder) 3390 { 3391 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); 3392 TRACE("%p (%p)\n", This, pidlFolder); 3393 return S_OK; 3394 } 3395 3396 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = { 3397 IExplorerBrowserEvents_fnQueryInterface, 3398 IExplorerBrowserEvents_fnAddRef, 3399 IExplorerBrowserEvents_fnRelease, 3400 IExplorerBrowserEvents_fnOnNavigationPending, 3401 IExplorerBrowserEvents_fnOnViewCreated, 3402 IExplorerBrowserEvents_fnOnNavigationComplete, 3403 IExplorerBrowserEvents_fnOnNavigationFailed 3404 }; 3405 3406 /************************************************************************** 3407 * IServiceProvider implementation 3408 */ 3409 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface) 3410 { 3411 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface); 3412 } 3413 3414 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface, 3415 REFIID riid, void **ppvObject) 3416 { 3417 FileDialogImpl *This = impl_from_IServiceProvider(iface); 3418 TRACE("%p\n", This); 3419 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3420 } 3421 3422 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface) 3423 { 3424 FileDialogImpl *This = impl_from_IServiceProvider(iface); 3425 TRACE("%p\n", This); 3426 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3427 } 3428 3429 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface) 3430 { 3431 FileDialogImpl *This = impl_from_IServiceProvider(iface); 3432 TRACE("%p\n", This); 3433 return IFileDialog2_Release(&This->IFileDialog2_iface); 3434 } 3435 3436 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface, 3437 REFGUID guidService, 3438 REFIID riid, void **ppv) 3439 { 3440 FileDialogImpl *This = impl_from_IServiceProvider(iface); 3441 HRESULT hr = E_NOTIMPL; 3442 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); 3443 3444 *ppv = NULL; 3445 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb) 3446 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv); 3447 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame)) 3448 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv); 3449 else 3450 FIXME("Interface %s requested from unknown service %s\n", 3451 debugstr_guid(riid), debugstr_guid(guidService)); 3452 3453 return hr; 3454 } 3455 3456 static const IServiceProviderVtbl vt_IServiceProvider = { 3457 IServiceProvider_fnQueryInterface, 3458 IServiceProvider_fnAddRef, 3459 IServiceProvider_fnRelease, 3460 IServiceProvider_fnQueryService 3461 }; 3462 3463 /************************************************************************** 3464 * ICommDlgBrowser3 implementation 3465 */ 3466 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface) 3467 { 3468 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface); 3469 } 3470 3471 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface, 3472 REFIID riid, void **ppvObject) 3473 { 3474 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3475 TRACE("%p\n", This); 3476 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3477 } 3478 3479 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface) 3480 { 3481 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3482 TRACE("%p\n", This); 3483 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3484 } 3485 3486 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface) 3487 { 3488 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3489 TRACE("%p\n", This); 3490 return IFileDialog2_Release(&This->IFileDialog2_iface); 3491 } 3492 3493 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface, 3494 IShellView *shv) 3495 { 3496 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3497 HRESULT hr; 3498 TRACE("%p (%p)\n", This, shv); 3499 3500 hr = on_default_action(This); 3501 3502 if(SUCCEEDED(hr)) 3503 EndDialog(This->dlg_hwnd, S_OK); 3504 3505 return S_OK; 3506 } 3507 3508 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface, 3509 IShellView *shv, ULONG uChange ) 3510 { 3511 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3512 IDataObject *new_selection; 3513 HRESULT hr; 3514 TRACE("%p (%p, %x)\n", This, shv, uChange); 3515 3516 switch(uChange) 3517 { 3518 case CDBOSC_SELCHANGE: 3519 if(This->psia_selection) 3520 { 3521 IShellItemArray_Release(This->psia_selection); 3522 This->psia_selection = NULL; 3523 } 3524 3525 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection); 3526 if(SUCCEEDED(hr)) 3527 { 3528 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray, 3529 (void**)&This->psia_selection); 3530 if(SUCCEEDED(hr)) 3531 { 3532 fill_filename_from_selection(This); 3533 events_OnSelectionChange(This); 3534 } 3535 3536 IDataObject_Release(new_selection); 3537 } 3538 break; 3539 default: 3540 TRACE("Unhandled state change\n"); 3541 } 3542 return S_OK; 3543 } 3544 3545 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface, 3546 IShellView *shv, LPCITEMIDLIST pidl) 3547 { 3548 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3549 IShellItem *psi; 3550 LPWSTR filename; 3551 LPITEMIDLIST parent_pidl; 3552 HRESULT hr; 3553 ULONG attr; 3554 TRACE("%p (%p, %p)\n", This, shv, pidl); 3555 3556 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS)) 3557 return S_OK; 3558 3559 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl); 3560 if(SUCCEEDED(hr)) 3561 { 3562 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl); 3563 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi); 3564 ILFree(parent_pidl); 3565 ILFree(full_pidl); 3566 } 3567 if(FAILED(hr)) 3568 { 3569 ERR("Failed to get shellitem (%08x).\n", hr); 3570 return S_OK; 3571 } 3572 3573 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr); 3574 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK))) 3575 { 3576 IShellItem_Release(psi); 3577 return S_OK; 3578 } 3579 3580 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK))) 3581 { 3582 IShellItem_Release(psi); 3583 return S_FALSE; 3584 } 3585 3586 hr = S_OK; 3587 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename))) 3588 { 3589 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec)) 3590 hr = S_FALSE; 3591 CoTaskMemFree(filename); 3592 } 3593 3594 IShellItem_Release(psi); 3595 return hr; 3596 } 3597 3598 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface, 3599 IShellView *ppshv, DWORD dwNotifyType) 3600 { 3601 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3602 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType); 3603 return E_NOTIMPL; 3604 } 3605 3606 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface, 3607 IShellView *pshv, 3608 LPWSTR pszText, int cchMax) 3609 { 3610 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3611 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax); 3612 return E_NOTIMPL; 3613 } 3614 3615 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags) 3616 { 3617 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3618 FIXME("Stub: %p (%p)\n", This, pdwFlags); 3619 return E_NOTIMPL; 3620 } 3621 3622 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface, 3623 IShellView *pshv, int iColumn) 3624 { 3625 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3626 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn); 3627 return E_NOTIMPL; 3628 } 3629 3630 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface, 3631 LPWSTR pszFileSpec, int cchFileSpec) 3632 { 3633 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3634 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec); 3635 return E_NOTIMPL; 3636 } 3637 3638 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface, 3639 IShellView *pshv) 3640 { 3641 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); 3642 FIXME("Stub: %p (%p)\n", This, pshv); 3643 return E_NOTIMPL; 3644 } 3645 3646 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = { 3647 ICommDlgBrowser3_fnQueryInterface, 3648 ICommDlgBrowser3_fnAddRef, 3649 ICommDlgBrowser3_fnRelease, 3650 ICommDlgBrowser3_fnOnDefaultCommand, 3651 ICommDlgBrowser3_fnOnStateChange, 3652 ICommDlgBrowser3_fnIncludeObject, 3653 ICommDlgBrowser3_fnNotify, 3654 ICommDlgBrowser3_fnGetDefaultMenuText, 3655 ICommDlgBrowser3_fnGetViewFlags, 3656 ICommDlgBrowser3_fnOnColumnClicked, 3657 ICommDlgBrowser3_fnGetCurrentFilter, 3658 ICommDlgBrowser3_fnOnPreviewCreated 3659 }; 3660 3661 /************************************************************************** 3662 * IOleWindow implementation 3663 */ 3664 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface) 3665 { 3666 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface); 3667 } 3668 3669 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject) 3670 { 3671 FileDialogImpl *This = impl_from_IOleWindow(iface); 3672 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3673 } 3674 3675 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface) 3676 { 3677 FileDialogImpl *This = impl_from_IOleWindow(iface); 3678 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3679 } 3680 3681 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface) 3682 { 3683 FileDialogImpl *This = impl_from_IOleWindow(iface); 3684 return IFileDialog2_Release(&This->IFileDialog2_iface); 3685 } 3686 3687 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde) 3688 { 3689 FileDialogImpl *This = impl_from_IOleWindow(iface); 3690 FIXME("Stub: %p (%d)\n", This, fEnterMOde); 3691 return E_NOTIMPL; 3692 } 3693 3694 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd) 3695 { 3696 FileDialogImpl *This = impl_from_IOleWindow(iface); 3697 TRACE("%p (%p)\n", This, phwnd); 3698 *phwnd = This->dlg_hwnd; 3699 return S_OK; 3700 } 3701 3702 static const IOleWindowVtbl vt_IOleWindow = { 3703 IOleWindow_fnQueryInterface, 3704 IOleWindow_fnAddRef, 3705 IOleWindow_fnRelease, 3706 IOleWindow_fnGetWindow, 3707 IOleWindow_fnContextSensitiveHelp 3708 }; 3709 3710 /************************************************************************** 3711 * IFileDialogCustomize implementation 3712 */ 3713 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface) 3714 { 3715 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface); 3716 } 3717 3718 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface, 3719 REFIID riid, void **ppvObject) 3720 { 3721 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3722 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); 3723 } 3724 3725 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface) 3726 { 3727 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3728 return IFileDialog2_AddRef(&This->IFileDialog2_iface); 3729 } 3730 3731 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface) 3732 { 3733 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3734 return IFileDialog2_Release(&This->IFileDialog2_iface); 3735 } 3736 3737 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface, 3738 DWORD dwIDCtl) 3739 { 3740 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3741 MENUINFO mi; 3742 TRACE("%p (%d)\n", This, dwIDCtl); 3743 3744 if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl)) 3745 return E_UNEXPECTED; 3746 3747 This->hmenu_opendropdown = CreatePopupMenu(); 3748 3749 if (!This->hmenu_opendropdown) 3750 return E_OUTOFMEMORY; 3751 3752 mi.cbSize = sizeof(mi); 3753 mi.fMask = MIM_STYLE; 3754 mi.dwStyle = MNS_NOTIFYBYPOS; 3755 SetMenuInfo(This->hmenu_opendropdown, &mi); 3756 3757 This->cctrl_opendropdown.hwnd = NULL; 3758 This->cctrl_opendropdown.wrapper_hwnd = NULL; 3759 This->cctrl_opendropdown.id = dwIDCtl; 3760 This->cctrl_opendropdown.dlgid = 0; 3761 This->cctrl_opendropdown.type = IDLG_CCTRL_OPENDROPDOWN; 3762 This->cctrl_opendropdown.cdcstate = CDCS_ENABLED | CDCS_VISIBLE; 3763 list_init(&This->cctrl_opendropdown.sub_cctrls); 3764 list_init(&This->cctrl_opendropdown.sub_items); 3765 3766 return S_OK; 3767 } 3768 3769 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface, 3770 DWORD dwIDCtl, 3771 LPCWSTR pszLabel) 3772 { 3773 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3774 customctrl *ctrl; 3775 TBBUTTON tbb; 3776 HRESULT hr; 3777 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel); 3778 3779 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW, 3780 TBSTYLE_FLAT | CCS_NODIVIDER, 0, 3781 This->cctrl_def_height, &ctrl); 3782 if(SUCCEEDED(hr)) 3783 { 3784 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0); 3785 ctrl->type = IDLG_CCTRL_MENU; 3786 3787 /* Add the actual button with a popup menu. */ 3788 tbb.iBitmap = I_IMAGENONE; 3789 tbb.dwData = (DWORD_PTR)CreatePopupMenu(); 3790 tbb.iString = (DWORD_PTR)pszLabel; 3791 tbb.fsState = TBSTATE_ENABLED; 3792 tbb.fsStyle = BTNS_WHOLEDROPDOWN; 3793 tbb.idCommand = 1; 3794 3795 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb); 3796 } 3797 3798 return hr; 3799 } 3800 3801 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface, 3802 DWORD dwIDCtl, 3803 LPCWSTR pszLabel) 3804 { 3805 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3806 customctrl *ctrl; 3807 HRESULT hr; 3808 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel); 3809 3810 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0, 3811 This->cctrl_def_height, &ctrl); 3812 if(SUCCEEDED(hr)) 3813 ctrl->type = IDLG_CCTRL_PUSHBUTTON; 3814 3815 return hr; 3816 } 3817 3818 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface, 3819 DWORD dwIDCtl) 3820 { 3821 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3822 customctrl *ctrl; 3823 HRESULT hr; 3824 TRACE("%p (%d)\n", This, dwIDCtl); 3825 3826 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0, 3827 This->cctrl_def_height, &ctrl); 3828 if(SUCCEEDED(hr)) 3829 ctrl->type = IDLG_CCTRL_COMBOBOX; 3830 3831 return hr; 3832 } 3833 3834 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface, 3835 DWORD dwIDCtl) 3836 { 3837 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3838 customctrl *ctrl; 3839 HRESULT hr; 3840 TRACE("%p (%d)\n", This, dwIDCtl); 3841 3842 hr = cctrl_create_new(This, dwIDCtl, NULL, radiobuttonlistW, 0, 0, 0, &ctrl); 3843 if(SUCCEEDED(hr)) 3844 { 3845 ctrl->type = IDLG_CCTRL_RADIOBUTTONLIST; 3846 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)This); 3847 } 3848 3849 return hr; 3850 } 3851 3852 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface, 3853 DWORD dwIDCtl, 3854 LPCWSTR pszLabel, 3855 BOOL bChecked) 3856 { 3857 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3858 customctrl *ctrl; 3859 HRESULT hr; 3860 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked); 3861 3862 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0, 3863 This->cctrl_def_height, &ctrl); 3864 if(SUCCEEDED(hr)) 3865 { 3866 ctrl->type = IDLG_CCTRL_CHECKBUTTON; 3867 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0); 3868 } 3869 3870 return hr; 3871 } 3872 3873 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface, 3874 DWORD dwIDCtl, 3875 LPCWSTR pszText) 3876 { 3877 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3878 customctrl *ctrl; 3879 HRESULT hr; 3880 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText); 3881 3882 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE, 3883 This->cctrl_def_height, &ctrl); 3884 if(SUCCEEDED(hr)) 3885 ctrl->type = IDLG_CCTRL_EDITBOX; 3886 3887 return hr; 3888 } 3889 3890 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface, 3891 DWORD dwIDCtl) 3892 { 3893 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3894 customctrl *ctrl; 3895 HRESULT hr; 3896 TRACE("%p (%d)\n", This, dwIDCtl); 3897 3898 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0, 3899 GetSystemMetrics(SM_CYEDGE), &ctrl); 3900 if(SUCCEEDED(hr)) 3901 ctrl->type = IDLG_CCTRL_SEPARATOR; 3902 3903 return hr; 3904 } 3905 3906 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface, 3907 DWORD dwIDCtl, 3908 LPCWSTR pszText) 3909 { 3910 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3911 customctrl *ctrl; 3912 HRESULT hr; 3913 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText); 3914 3915 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0, 3916 This->cctrl_def_height, &ctrl); 3917 if(SUCCEEDED(hr)) 3918 ctrl->type = IDLG_CCTRL_TEXT; 3919 3920 return hr; 3921 } 3922 3923 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface, 3924 DWORD dwIDCtl, 3925 LPCWSTR pszLabel) 3926 { 3927 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3928 customctrl *ctrl = get_cctrl(This, dwIDCtl); 3929 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel); 3930 3931 if(!ctrl) return E_INVALIDARG; 3932 3933 switch(ctrl->type) 3934 { 3935 case IDLG_CCTRL_MENU: 3936 case IDLG_CCTRL_PUSHBUTTON: 3937 case IDLG_CCTRL_CHECKBUTTON: 3938 case IDLG_CCTRL_TEXT: 3939 case IDLG_CCTRL_VISUALGROUP: 3940 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel); 3941 break; 3942 case IDLG_CCTRL_OPENDROPDOWN: 3943 return E_NOTIMPL; 3944 default: 3945 break; 3946 } 3947 3948 return S_OK; 3949 } 3950 3951 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface, 3952 DWORD dwIDCtl, 3953 CDCONTROLSTATEF *pdwState) 3954 { 3955 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3956 customctrl *ctrl = get_cctrl(This, dwIDCtl); 3957 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState); 3958 3959 if(!ctrl || ctrl->type == IDLG_CCTRL_OPENDROPDOWN) return E_NOTIMPL; 3960 3961 *pdwState = ctrl->cdcstate; 3962 return S_OK; 3963 } 3964 3965 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface, 3966 DWORD dwIDCtl, 3967 CDCONTROLSTATEF dwState) 3968 { 3969 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 3970 customctrl *ctrl = get_cctrl(This,dwIDCtl); 3971 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState); 3972 3973 if(ctrl && ctrl->hwnd) 3974 { 3975 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE); 3976 3977 if(dwState & CDCS_ENABLED) 3978 wndstyle &= ~(WS_DISABLED); 3979 else 3980 wndstyle |= WS_DISABLED; 3981 3982 if(dwState & CDCS_VISIBLE) 3983 wndstyle |= WS_VISIBLE; 3984 else 3985 wndstyle &= ~(WS_VISIBLE); 3986 3987 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle); 3988 3989 /* We save the state separately since at least one application 3990 * relies on being able to hide a control. */ 3991 ctrl->cdcstate = dwState; 3992 } 3993 3994 return S_OK; 3995 } 3996 3997 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface, 3998 DWORD dwIDCtl, 3999 WCHAR **ppszText) 4000 { 4001 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4002 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4003 WCHAR len, *text; 4004 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText); 4005 4006 if(!ctrl || !ctrl->hwnd || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0))) 4007 return E_FAIL; 4008 4009 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1)); 4010 if(!text) return E_FAIL; 4011 4012 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text); 4013 *ppszText = text; 4014 return S_OK; 4015 } 4016 4017 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface, 4018 DWORD dwIDCtl, 4019 LPCWSTR pszText) 4020 { 4021 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4022 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4023 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText)); 4024 4025 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX) 4026 return E_FAIL; 4027 4028 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText); 4029 return S_OK; 4030 } 4031 4032 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface, 4033 DWORD dwIDCtl, 4034 BOOL *pbChecked) 4035 { 4036 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4037 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4038 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked); 4039 4040 if(ctrl && ctrl->hwnd) 4041 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED); 4042 4043 return S_OK; 4044 } 4045 4046 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface, 4047 DWORD dwIDCtl, 4048 BOOL bChecked) 4049 { 4050 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4051 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4052 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked); 4053 4054 if(ctrl && ctrl->hwnd) 4055 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0); 4056 4057 return S_OK; 4058 } 4059 4060 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem) 4061 { 4062 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0); 4063 UINT i; 4064 if(!count || (count == CB_ERR)) 4065 return -1; 4066 4067 for(i = 0; i < count; i++) 4068 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem) 4069 return i; 4070 4071 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count); 4072 return -1; 4073 } 4074 4075 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface, 4076 DWORD dwIDCtl, 4077 DWORD dwIDItem, 4078 LPCWSTR pszLabel) 4079 { 4080 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4081 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4082 HRESULT hr; 4083 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel)); 4084 4085 if(!ctrl) return E_FAIL; 4086 4087 switch(ctrl->type) 4088 { 4089 case IDLG_CCTRL_COMBOBOX: 4090 { 4091 UINT index; 4092 cctrl_item* item; 4093 4094 hr = add_item(ctrl, dwIDItem, pszLabel, &item); 4095 4096 if (FAILED(hr)) return hr; 4097 4098 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel); 4099 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem); 4100 4101 return S_OK; 4102 } 4103 case IDLG_CCTRL_MENU: 4104 case IDLG_CCTRL_OPENDROPDOWN: 4105 { 4106 cctrl_item* item; 4107 HMENU hmenu; 4108 4109 hr = add_item(ctrl, dwIDItem, pszLabel, &item); 4110 4111 if (FAILED(hr)) return hr; 4112 4113 if (ctrl->type == IDLG_CCTRL_MENU) 4114 { 4115 TBBUTTON tbb; 4116 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb); 4117 hmenu = (HMENU)tbb.dwData; 4118 } 4119 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */ 4120 hmenu = This->hmenu_opendropdown; 4121 4122 AppendMenuW(hmenu, MF_STRING, dwIDItem, pszLabel); 4123 return S_OK; 4124 } 4125 case IDLG_CCTRL_RADIOBUTTONLIST: 4126 { 4127 cctrl_item* item; 4128 4129 hr = add_item(ctrl, dwIDItem, pszLabel, &item); 4130 4131 if (SUCCEEDED(hr)) 4132 { 4133 item->hwnd = CreateWindowExW(0, WC_BUTTONW, pszLabel, 4134 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|BS_RADIOBUTTON|BS_MULTILINE, 4135 0, 0, 0, 0, ctrl->hwnd, ULongToHandle(dwIDItem), COMDLG32_hInstance, 0); 4136 4137 if (!item->hwnd) 4138 { 4139 ERR("Failed to create radio button\n"); 4140 list_remove(&item->entry); 4141 item_free(item); 4142 return E_FAIL; 4143 } 4144 } 4145 4146 return hr; 4147 } 4148 default: 4149 break; 4150 } 4151 4152 return E_NOINTERFACE; /* win7 */ 4153 } 4154 4155 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface, 4156 DWORD dwIDCtl, 4157 DWORD dwIDItem) 4158 { 4159 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4160 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4161 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem); 4162 4163 if(!ctrl) return E_FAIL; 4164 4165 switch(ctrl->type) 4166 { 4167 case IDLG_CCTRL_COMBOBOX: 4168 { 4169 cctrl_item* item; 4170 DWORD position; 4171 4172 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position); 4173 4174 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED)) 4175 { 4176 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0) == CB_ERR) 4177 return E_FAIL; 4178 } 4179 4180 list_remove(&item->entry); 4181 item_free(item); 4182 4183 return S_OK; 4184 } 4185 case IDLG_CCTRL_MENU: 4186 case IDLG_CCTRL_OPENDROPDOWN: 4187 { 4188 HMENU hmenu; 4189 cctrl_item* item; 4190 4191 item = get_item(ctrl, dwIDItem, 0, NULL); 4192 4193 if (!item) 4194 return E_UNEXPECTED; 4195 4196 if (item->cdcstate & CDCS_VISIBLE) 4197 { 4198 if (ctrl->type == IDLG_CCTRL_MENU) 4199 { 4200 TBBUTTON tbb; 4201 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb); 4202 hmenu = (HMENU)tbb.dwData; 4203 } 4204 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */ 4205 hmenu = This->hmenu_opendropdown; 4206 4207 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND)) 4208 return E_UNEXPECTED; 4209 } 4210 4211 list_remove(&item->entry); 4212 item_free(item); 4213 4214 return S_OK; 4215 } 4216 case IDLG_CCTRL_RADIOBUTTONLIST: 4217 { 4218 cctrl_item* item; 4219 4220 item = get_item(ctrl, dwIDItem, 0, NULL); 4221 4222 if (!item) 4223 return E_UNEXPECTED; 4224 4225 list_remove(&item->entry); 4226 item_free(item); 4227 4228 return S_OK; 4229 } 4230 default: 4231 break; 4232 } 4233 4234 return E_FAIL; 4235 } 4236 4237 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface, 4238 DWORD dwIDCtl) 4239 { 4240 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4241 TRACE("%p (%d)\n", This, dwIDCtl); 4242 4243 /* Not implemented by native */ 4244 return E_NOTIMPL; 4245 } 4246 4247 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface, 4248 DWORD dwIDCtl, 4249 DWORD dwIDItem, 4250 CDCONTROLSTATEF *pdwState) 4251 { 4252 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4253 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4254 TRACE("%p (%d, %d, %p)\n", This, dwIDCtl, dwIDItem, pdwState); 4255 4256 if(!ctrl) return E_FAIL; 4257 4258 switch(ctrl->type) 4259 { 4260 case IDLG_CCTRL_COMBOBOX: 4261 case IDLG_CCTRL_MENU: 4262 case IDLG_CCTRL_OPENDROPDOWN: 4263 case IDLG_CCTRL_RADIOBUTTONLIST: 4264 { 4265 cctrl_item* item; 4266 4267 item = get_item(ctrl, dwIDItem, 0, NULL); 4268 4269 if (!item) 4270 return E_UNEXPECTED; 4271 4272 *pdwState = item->cdcstate; 4273 4274 return S_OK; 4275 } 4276 default: 4277 break; 4278 } 4279 4280 return E_FAIL; 4281 } 4282 4283 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface, 4284 DWORD dwIDCtl, 4285 DWORD dwIDItem, 4286 CDCONTROLSTATEF dwState) 4287 { 4288 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4289 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4290 TRACE("%p (%d, %d, %x)\n", This, dwIDCtl, dwIDItem, dwState); 4291 4292 if(!ctrl) return E_FAIL; 4293 4294 switch(ctrl->type) 4295 { 4296 case IDLG_CCTRL_COMBOBOX: 4297 { 4298 cctrl_item* item; 4299 BOOL visible, was_visible; 4300 DWORD position; 4301 4302 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position); 4303 4304 if (!item) 4305 return E_UNEXPECTED; 4306 4307 visible = ((dwState & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED)); 4308 was_visible = ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED)); 4309 4310 if (visible && !was_visible) 4311 { 4312 SendMessageW(ctrl->hwnd, CB_INSERTSTRING, position, (LPARAM)item->label); 4313 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, position, dwIDItem); 4314 } 4315 else if (!visible && was_visible) 4316 { 4317 SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0); 4318 } 4319 4320 item->cdcstate = dwState; 4321 4322 return S_OK; 4323 } 4324 case IDLG_CCTRL_MENU: 4325 case IDLG_CCTRL_OPENDROPDOWN: 4326 { 4327 HMENU hmenu; 4328 cctrl_item* item; 4329 CDCONTROLSTATEF prev_state; 4330 DWORD position; 4331 4332 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, &position); 4333 4334 if (!item) 4335 return E_UNEXPECTED; 4336 4337 prev_state = item->cdcstate; 4338 4339 if (ctrl->type == IDLG_CCTRL_MENU) 4340 { 4341 TBBUTTON tbb; 4342 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb); 4343 hmenu = (HMENU)tbb.dwData; 4344 } 4345 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */ 4346 hmenu = This->hmenu_opendropdown; 4347 4348 if (dwState & CDCS_VISIBLE) 4349 { 4350 if (prev_state & CDCS_VISIBLE) 4351 { 4352 /* change state */ 4353 EnableMenuItem(hmenu, dwIDItem, 4354 MF_BYCOMMAND|((dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED)); 4355 } 4356 else 4357 { 4358 /* show item */ 4359 MENUITEMINFOW mii; 4360 4361 mii.cbSize = sizeof(mii); 4362 mii.fMask = MIIM_ID|MIIM_STATE|MIIM_STRING; 4363 mii.fState = (dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED; 4364 mii.wID = dwIDItem; 4365 mii.dwTypeData = item->label; 4366 4367 InsertMenuItemW(hmenu, position, TRUE, &mii); 4368 } 4369 } 4370 else if (prev_state & CDCS_VISIBLE) 4371 { 4372 /* hide item */ 4373 DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND); 4374 } 4375 4376 item->cdcstate = dwState; 4377 4378 if (ctrl->type == IDLG_CCTRL_OPENDROPDOWN) 4379 { 4380 update_control_text(This); 4381 update_layout(This); 4382 } 4383 4384 return S_OK; 4385 } 4386 case IDLG_CCTRL_RADIOBUTTONLIST: 4387 { 4388 cctrl_item* item; 4389 4390 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, NULL); 4391 4392 if (!item) 4393 return E_UNEXPECTED; 4394 4395 /* Oddly, native allows setting this but doesn't seem to do anything with it. */ 4396 item->cdcstate = dwState; 4397 4398 return S_OK; 4399 } 4400 default: 4401 break; 4402 } 4403 4404 return E_FAIL; 4405 } 4406 4407 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface, 4408 DWORD dwIDCtl, 4409 DWORD *pdwIDItem) 4410 { 4411 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4412 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4413 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem); 4414 4415 if(!ctrl) return E_FAIL; 4416 4417 switch(ctrl->type) 4418 { 4419 case IDLG_CCTRL_COMBOBOX: 4420 { 4421 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0); 4422 if(index == CB_ERR) 4423 return E_FAIL; 4424 4425 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0); 4426 return S_OK; 4427 } 4428 case IDLG_CCTRL_OPENDROPDOWN: 4429 if (This->opendropdown_has_selection) 4430 { 4431 *pdwIDItem = This->opendropdown_selection; 4432 return S_OK; 4433 } 4434 else 4435 { 4436 /* Return first enabled item. */ 4437 cctrl_item* item = get_first_item(ctrl); 4438 4439 if (item) 4440 { 4441 *pdwIDItem = item->id; 4442 return S_OK; 4443 } 4444 4445 WARN("no enabled items in open dropdown\n"); 4446 return E_FAIL; 4447 } 4448 case IDLG_CCTRL_RADIOBUTTONLIST: 4449 { 4450 cctrl_item* item; 4451 4452 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry) 4453 { 4454 if (SendMessageW(item->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) 4455 { 4456 *pdwIDItem = item->id; 4457 return S_OK; 4458 } 4459 } 4460 4461 WARN("no checked items in radio button list\n"); 4462 return E_FAIL; 4463 } 4464 default: 4465 FIXME("Unsupported control type %d\n", ctrl->type); 4466 } 4467 4468 return E_NOTIMPL; 4469 } 4470 4471 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface, 4472 DWORD dwIDCtl, 4473 DWORD dwIDItem) 4474 { 4475 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4476 customctrl *ctrl = get_cctrl(This, dwIDCtl); 4477 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem); 4478 4479 if(!ctrl) return E_INVALIDARG; 4480 4481 switch(ctrl->type) 4482 { 4483 case IDLG_CCTRL_COMBOBOX: 4484 { 4485 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem); 4486 4487 if(index == -1) 4488 return E_INVALIDARG; 4489 4490 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR) 4491 return E_FAIL; 4492 4493 return S_OK; 4494 } 4495 case IDLG_CCTRL_RADIOBUTTONLIST: 4496 { 4497 cctrl_item* item; 4498 4499 item = get_item(ctrl, dwIDItem, 0, NULL); 4500 4501 if (item) 4502 { 4503 radiobuttonlist_set_selected_item(This, ctrl, item); 4504 return S_OK; 4505 } 4506 4507 return E_INVALIDARG; 4508 } 4509 default: 4510 FIXME("Unsupported control type %d\n", ctrl->type); 4511 } 4512 4513 return E_INVALIDARG; 4514 } 4515 4516 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface, 4517 DWORD dwIDCtl, 4518 LPCWSTR pszLabel) 4519 { 4520 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4521 customctrl *vg; 4522 HRESULT hr; 4523 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel)); 4524 4525 if(This->cctrl_active_vg) 4526 return E_UNEXPECTED; 4527 4528 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0, 4529 This->cctrl_def_height, &vg); 4530 if(SUCCEEDED(hr)) 4531 { 4532 vg->type = IDLG_CCTRL_VISUALGROUP; 4533 This->cctrl_active_vg = vg; 4534 } 4535 4536 return hr; 4537 } 4538 4539 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface) 4540 { 4541 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4542 TRACE("%p\n", This); 4543 4544 This->cctrl_active_vg = NULL; 4545 4546 return S_OK; 4547 } 4548 4549 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface, 4550 DWORD dwIDCtl) 4551 { 4552 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4553 FIXME("stub - %p (%d)\n", This, dwIDCtl); 4554 return S_OK; 4555 } 4556 4557 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface, 4558 DWORD dwIDCtl, 4559 DWORD dwIDItem, 4560 LPCWSTR pszLabel) 4561 { 4562 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); 4563 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel)); 4564 return E_NOTIMPL; 4565 } 4566 4567 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = { 4568 IFileDialogCustomize_fnQueryInterface, 4569 IFileDialogCustomize_fnAddRef, 4570 IFileDialogCustomize_fnRelease, 4571 IFileDialogCustomize_fnEnableOpenDropDown, 4572 IFileDialogCustomize_fnAddMenu, 4573 IFileDialogCustomize_fnAddPushButton, 4574 IFileDialogCustomize_fnAddComboBox, 4575 IFileDialogCustomize_fnAddRadioButtonList, 4576 IFileDialogCustomize_fnAddCheckButton, 4577 IFileDialogCustomize_fnAddEditBox, 4578 IFileDialogCustomize_fnAddSeparator, 4579 IFileDialogCustomize_fnAddText, 4580 IFileDialogCustomize_fnSetControlLabel, 4581 IFileDialogCustomize_fnGetControlState, 4582 IFileDialogCustomize_fnSetControlState, 4583 IFileDialogCustomize_fnGetEditBoxText, 4584 IFileDialogCustomize_fnSetEditBoxText, 4585 IFileDialogCustomize_fnGetCheckButtonState, 4586 IFileDialogCustomize_fnSetCheckButtonState, 4587 IFileDialogCustomize_fnAddControlItem, 4588 IFileDialogCustomize_fnRemoveControlItem, 4589 IFileDialogCustomize_fnRemoveAllControlItems, 4590 IFileDialogCustomize_fnGetControlItemState, 4591 IFileDialogCustomize_fnSetControlItemState, 4592 IFileDialogCustomize_fnGetSelectedControlItem, 4593 IFileDialogCustomize_fnSetSelectedControlItem, 4594 IFileDialogCustomize_fnStartVisualGroup, 4595 IFileDialogCustomize_fnEndVisualGroup, 4596 IFileDialogCustomize_fnMakeProminent, 4597 IFileDialogCustomize_fnSetControlItemText 4598 }; 4599 4600 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type) 4601 { 4602 FileDialogImpl *fdimpl; 4603 HRESULT hr; 4604 IShellFolder *psf; 4605 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv); 4606 4607 if(!ppv) 4608 return E_POINTER; 4609 if(pUnkOuter) 4610 return CLASS_E_NOAGGREGATION; 4611 4612 fdimpl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FileDialogImpl)); 4613 if(!fdimpl) 4614 return E_OUTOFMEMORY; 4615 4616 fdimpl->ref = 1; 4617 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2; 4618 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents; 4619 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider; 4620 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3; 4621 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow; 4622 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize; 4623 4624 if(type == ITEMDLG_TYPE_OPEN) 4625 { 4626 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN; 4627 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog; 4628 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR; 4629 fdimpl->custom_title = fdimpl->custom_okbutton = NULL; 4630 } 4631 else 4632 { 4633 WCHAR buf[16]; 4634 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE; 4635 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog; 4636 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR; 4637 4638 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, ARRAY_SIZE(buf)); 4639 fdimpl->custom_title = StrDupW(buf); 4640 fdimpl->custom_okbutton = StrDupW(buf); 4641 } 4642 4643 list_init(&fdimpl->events_clients); 4644 4645 /* FIXME: The default folder setting should be restored for the 4646 * application if it was previously set. */ 4647 SHGetDesktopFolder(&psf); 4648 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder); 4649 IShellFolder_Release(psf); 4650 4651 hr = init_custom_controls(fdimpl); 4652 if(FAILED(hr)) 4653 { 4654 ERR("Failed to initialize custom controls (0x%08x).\n", hr); 4655 IFileDialog2_Release(&fdimpl->IFileDialog2_iface); 4656 return E_FAIL; 4657 } 4658 4659 hr = IFileDialog2_QueryInterface(&fdimpl->IFileDialog2_iface, riid, ppv); 4660 IFileDialog2_Release(&fdimpl->IFileDialog2_iface); 4661 return hr; 4662 } 4663 4664 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) 4665 { 4666 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN); 4667 } 4668 4669 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) 4670 { 4671 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE); 4672 } 4673 4674 #endif /* Win 7 */ 4675