1 /* 2 * COMMDLG - File Open Dialogs Win95 look and feel 3 * 4 * Copyright 1999 Francois Boisvert 5 * Copyright 1999, 2000 Juergen Schmied 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 * 21 * FIXME: The whole concept of handling unicode is badly broken. 22 * many hook-messages expect a pointer to a 23 * OPENFILENAMEA or W structure. With the current architecture 24 * we would have to convert the beast at every call to a hook. 25 * we have to find a better solution but it would likely cause 26 * a complete rewrite after which we should handle the 27 * OPENFILENAME structure without any converting (jsch). 28 * 29 * FIXME: any hook gets a OPENFILENAMEA structure 30 * 31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too 32 * 33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING) 34 * 35 * FIXME: algorithm for selecting the initial directory is too simple 36 * 37 * FIXME: add to recent docs 38 * 39 * FIXME: flags not implemented: OFN_DONTADDTORECENT, 40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN, 41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS 42 * 43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG) 44 * 45 * 46 */ 47 48 #include <ctype.h> 49 #include <stdlib.h> 50 #include <stdarg.h> 51 #include <stdio.h> 52 #include <string.h> 53 54 #define COBJMACROS 55 #define NONAMELESSUNION 56 57 #include "windef.h" 58 #include "winbase.h" 59 #include "winternl.h" 60 #include "winnls.h" 61 #include "wingdi.h" 62 #ifdef __REACTOS__ 63 /* RegGetValueW is supported by Win2k3 SP1 but headers need Win Vista */ 64 #undef _WIN32_WINNT 65 #define _WIN32_WINNT 0x0600 66 #endif 67 #include "winreg.h" 68 #include "winuser.h" 69 #include "commdlg.h" 70 #include "dlgs.h" 71 #include "cdlg.h" 72 #include "cderr.h" 73 #include "shellapi.h" 74 #include "shlobj.h" 75 #include "filedlgbrowser.h" 76 #include "shlwapi.h" 77 78 #include "wine/debug.h" 79 #include "wine/heap.h" 80 #ifdef __REACTOS__ 81 #include "wine/unicode.h" 82 #endif 83 84 WINE_DEFAULT_DEBUG_CHANNEL(commdlg); 85 86 #define UNIMPLEMENTED_FLAGS \ 87 (OFN_DONTADDTORECENT |\ 88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\ 89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/) 90 91 /*********************************************************************** 92 * Data structure and global variables 93 */ 94 typedef struct SFolder 95 { 96 int m_iImageIndex; /* Index of picture in image list */ 97 HIMAGELIST hImgList; 98 int m_iIndent; /* Indentation index */ 99 LPITEMIDLIST pidlItem; /* absolute pidl of the item */ 100 101 } SFOLDER,*LPSFOLDER; 102 103 typedef struct tagLookInInfo 104 { 105 int iMaxIndentation; 106 UINT uSelectedItem; 107 } LookInInfos; 108 109 110 /*********************************************************************** 111 * Defines and global variables 112 */ 113 114 /* Draw item constant */ 115 #define XTEXTOFFSET 3 116 117 /* AddItem flags*/ 118 #define LISTEND -1 119 120 /* SearchItem methods */ 121 #define SEARCH_PIDL 1 122 #define SEARCH_EXP 2 123 #define ITEM_NOTFOUND -1 124 125 /* Undefined windows message sent by CreateViewObject*/ 126 #define WM_GETISHELLBROWSER WM_USER+7 127 128 #define TBPLACES_CMDID_PLACE0 0xa064 129 #define TBPLACES_CMDID_PLACE1 0xa065 130 #define TBPLACES_CMDID_PLACE2 0xa066 131 #define TBPLACES_CMDID_PLACE3 0xa067 132 #define TBPLACES_CMDID_PLACE4 0xa068 133 134 /* NOTE 135 * Those macros exist in windowsx.h. However, you can't really use them since 136 * they rely on the UNICODE defines and can't be used inside Wine itself. 137 */ 138 139 /* Combo box macros */ 140 #define CBGetItemDataPtr(hwnd,iItemId) \ 141 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0) 142 143 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */ 144 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */ 145 146 static const WCHAR LastVisitedMRUW[] = 147 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', 148 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 149 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\', 150 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0}; 151 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0}; 152 153 static const WCHAR filedlg_info_propnameW[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0}; 154 155 FileOpenDlgInfos *get_filedlg_infoptr(HWND hwnd) 156 { 157 return GetPropW(hwnd, filedlg_info_propnameW); 158 } 159 160 static BOOL is_dialog_hooked(const FileOpenDlgInfos *info) 161 { 162 return (info->ofnInfos->Flags & OFN_ENABLEHOOK) && info->ofnInfos->lpfnHook; 163 } 164 165 static BOOL filedialog_is_readonly_hidden(const FileOpenDlgInfos *info) 166 { 167 return (info->ofnInfos->Flags & OFN_HIDEREADONLY) || (info->DlgInfos.dwDlgProp & FODPROP_SAVEDLG); 168 } 169 170 /*********************************************************************** 171 * Prototypes 172 */ 173 174 /* Internal functions used by the dialog */ 175 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam); 176 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam); 177 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam); 178 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd); 179 static BOOL FILEDLG95_OnOpen(HWND hwnd); 180 static LRESULT FILEDLG95_InitControls(HWND hwnd); 181 static void FILEDLG95_Clean(HWND hwnd); 182 183 /* Functions used by the shell navigation */ 184 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd); 185 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd); 186 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb); 187 static void FILEDLG95_SHELL_Clean(HWND hwnd); 188 189 /* Functions used by the EDIT box */ 190 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed); 191 192 /* Functions used by the filetype combo box */ 193 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd); 194 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode); 195 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt); 196 static void FILEDLG95_FILETYPE_Clean(HWND hwnd); 197 198 /* Functions used by the Look In combo box */ 199 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo); 200 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct); 201 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode); 202 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId); 203 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod); 204 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl); 205 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd); 206 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl); 207 static void FILEDLG95_LOOKIN_Clean(HWND hwnd); 208 209 /* Functions for dealing with the most-recently-used registry keys */ 210 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path); 211 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret); 212 static void FILEDLG95_MRU_save_filename(LPCWSTR filename); 213 #ifdef __REACTOS__ 214 static void FILEDLG95_MRU_load_ext(LPWSTR stored_path, size_t cchMax, LPCWSTR defext); 215 static void FILEDLG95_MRU_save_ext(LPCWSTR filename); 216 #endif 217 218 /* Miscellaneous tool functions */ 219 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName); 220 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs); 221 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl); 222 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName); 223 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl); 224 static UINT GetNumSelected( IDataObject *doSelected ); 225 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium); 226 227 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 228 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 229 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed); 230 static BOOL BrowseSelectedFolder(HWND hwnd); 231 232 static BOOL get_config_key_as_dword(HKEY hkey, const WCHAR *name, DWORD *value) 233 { 234 DWORD type, data, size; 235 236 size = sizeof(data); 237 if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size)) 238 { 239 *value = data; 240 return TRUE; 241 } 242 243 return FALSE; 244 } 245 246 static BOOL get_config_key_dword(HKEY hkey, const WCHAR *name, DWORD *value) 247 { 248 DWORD type, data, size; 249 250 size = sizeof(data); 251 if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size) && type == REG_DWORD) 252 { 253 *value = data; 254 return TRUE; 255 } 256 257 return FALSE; 258 } 259 260 static BOOL get_config_key_string(HKEY hkey, const WCHAR *name, WCHAR **value) 261 { 262 DWORD type, size; 263 WCHAR *str; 264 265 if (hkey && !RegQueryValueExW(hkey, name, 0, &type, NULL, &size)) 266 { 267 if (type != REG_SZ && type != REG_EXPAND_SZ) 268 return FALSE; 269 } 270 271 str = heap_alloc(size); 272 if (RegQueryValueExW(hkey, name, 0, &type, (BYTE *)str, &size)) 273 { 274 heap_free(str); 275 return FALSE; 276 } 277 278 *value = str; 279 return TRUE; 280 } 281 282 static BOOL is_places_bar_enabled(const FileOpenDlgInfos *fodInfos) 283 { 284 static const WCHAR noplacesbarW[] = {'N','o','P','l','a','c','e','s','B','a','r',0}; 285 DWORD value; 286 HKEY hkey; 287 288 if (fodInfos->ofnInfos->lStructSize != sizeof(*fodInfos->ofnInfos) || 289 (fodInfos->ofnInfos->FlagsEx & OFN_EX_NOPLACESBAR) || 290 !(fodInfos->ofnInfos->Flags & OFN_EXPLORER)) 291 { 292 return FALSE; 293 } 294 295 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32", &hkey)) 296 return TRUE; 297 298 value = 0; 299 get_config_key_as_dword(hkey, noplacesbarW, &value); 300 RegCloseKey(hkey); 301 return value == 0; 302 } 303 304 static void filedlg_collect_places_pidls(FileOpenDlgInfos *fodInfos) 305 { 306 static const int default_places[] = 307 { 308 CSIDL_DESKTOP, 309 CSIDL_MYDOCUMENTS, 310 CSIDL_DRIVES, 311 }; 312 unsigned int i; 313 HKEY hkey; 314 315 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32\\Placesbar", 316 &hkey)) 317 { 318 for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++) 319 { 320 static const WCHAR placeW[] = {'P','l','a','c','e','%','d',0}; 321 WCHAR nameW[8]; 322 DWORD value; 323 HRESULT hr; 324 WCHAR *str; 325 326 swprintf(nameW, placeW, i); 327 if (get_config_key_dword(hkey, nameW, &value)) 328 { 329 hr = SHGetSpecialFolderLocation(NULL, value, &fodInfos->places[i]); 330 if (FAILED(hr)) 331 WARN("Unrecognized special folder %u.\n", value); 332 } 333 else if (get_config_key_string(hkey, nameW, &str)) 334 { 335 hr = SHParseDisplayName(str, NULL, &fodInfos->places[i], 0, NULL); 336 if (FAILED(hr)) 337 WARN("Failed to parse custom places location, %s.\n", debugstr_w(str)); 338 heap_free(str); 339 } 340 } 341 342 /* FIXME: eliminate duplicates. */ 343 344 RegCloseKey(hkey); 345 return; 346 } 347 348 for (i = 0; i < ARRAY_SIZE(default_places); i++) 349 SHGetSpecialFolderLocation(NULL, default_places[i], &fodInfos->places[i]); 350 } 351 352 /*********************************************************************** 353 * GetFileName95 354 * 355 * Creates an Open common dialog box that lets the user select 356 * the drive, directory, and the name of a file or set of files to open. 357 * 358 * IN : The FileOpenDlgInfos structure associated with the dialog 359 * OUT : TRUE on success 360 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 361 */ 362 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos) 363 { 364 LRESULT lRes; 365 void *template; 366 HRSRC hRes; 367 HANDLE hDlgTmpl = 0; 368 WORD templateid; 369 370 /* test for missing functionality */ 371 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS) 372 { 373 FIXME("Flags 0x%08x not yet implemented\n", 374 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS); 375 } 376 377 /* Create the dialog from a template */ 378 379 if (is_places_bar_enabled(fodInfos)) 380 templateid = NEWFILEOPENV2ORD; 381 else 382 templateid = NEWFILEOPENORD; 383 384 if (!(hRes = FindResourceW(COMDLG32_hInstance, MAKEINTRESOURCEW(templateid), (LPCWSTR)RT_DIALOG))) 385 { 386 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); 387 return FALSE; 388 } 389 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) || 390 !(template = LockResource( hDlgTmpl ))) 391 { 392 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); 393 return FALSE; 394 } 395 396 /* msdn: explorer style dialogs permit sizing by default. 397 * The OFN_ENABLESIZING flag is only needed when a hook or 398 * custom template is provided */ 399 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) && 400 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))) 401 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING; 402 403 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING) 404 { 405 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0; 406 fodInfos->initial_size.x = fodInfos->initial_size.y = 0; 407 } 408 409 /* old style hook messages */ 410 if (is_dialog_hooked(fodInfos)) 411 { 412 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW); 413 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW); 414 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW); 415 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW); 416 } 417 418 if (fodInfos->unicode) 419 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance, 420 template, 421 fodInfos->ofnInfos->hwndOwner, 422 FileOpenDlgProc95, 423 (LPARAM) fodInfos); 424 else 425 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance, 426 template, 427 fodInfos->ofnInfos->hwndOwner, 428 FileOpenDlgProc95, 429 (LPARAM) fodInfos); 430 if (fodInfos->ole_initialized) 431 OleUninitialize(); 432 433 /* Unable to create the dialog */ 434 if( lRes == -1) 435 return FALSE; 436 437 return lRes; 438 } 439 440 static WCHAR *heap_strdupAtoW(const char *str) 441 { 442 WCHAR *ret; 443 INT len; 444 445 if (!str) 446 return NULL; 447 448 len = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0); 449 ret = heap_alloc(len * sizeof(WCHAR)); 450 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); 451 452 return ret; 453 } 454 455 static void init_filedlg_infoW(OPENFILENAMEW *ofn, FileOpenDlgInfos *info) 456 { 457 INITCOMMONCONTROLSEX icc; 458 459 /* Initialize ComboBoxEx32 */ 460 icc.dwSize = sizeof(icc); 461 icc.dwICC = ICC_USEREX_CLASSES; 462 InitCommonControlsEx(&icc); 463 464 /* Initialize CommDlgExtendedError() */ 465 COMDLG32_SetCommDlgExtendedError(0); 466 467 memset(info, 0, sizeof(*info)); 468 469 /* Pass in the original ofn */ 470 info->ofnInfos = ofn; 471 472 info->title = ofn->lpstrTitle; 473 info->defext = ofn->lpstrDefExt; 474 info->filter = ofn->lpstrFilter; 475 info->customfilter = ofn->lpstrCustomFilter; 476 477 if (ofn->lpstrFile) 478 { 479 info->filename = heap_alloc(ofn->nMaxFile * sizeof(WCHAR)); 480 lstrcpynW(info->filename, ofn->lpstrFile, ofn->nMaxFile); 481 } 482 483 if (ofn->lpstrInitialDir) 484 { 485 DWORD len = ExpandEnvironmentStringsW(ofn->lpstrInitialDir, NULL, 0); 486 if (len) 487 { 488 info->initdir = heap_alloc(len * sizeof(WCHAR)); 489 ExpandEnvironmentStringsW(ofn->lpstrInitialDir, info->initdir, len); 490 } 491 } 492 493 info->unicode = TRUE; 494 } 495 496 static void init_filedlg_infoA(OPENFILENAMEA *ofn, FileOpenDlgInfos *info) 497 { 498 OPENFILENAMEW ofnW; 499 int len; 500 501 ofnW = *(OPENFILENAMEW *)ofn; 502 503 ofnW.lpstrInitialDir = heap_strdupAtoW(ofn->lpstrInitialDir); 504 ofnW.lpstrDefExt = heap_strdupAtoW(ofn->lpstrDefExt); 505 ofnW.lpstrTitle = heap_strdupAtoW(ofn->lpstrTitle); 506 507 if (ofn->lpstrFile) 508 { 509 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFile, ofn->nMaxFile, NULL, 0); 510 ofnW.lpstrFile = heap_alloc(len * sizeof(WCHAR)); 511 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFile, ofn->nMaxFile, ofnW.lpstrFile, len); 512 ofnW.nMaxFile = len; 513 } 514 515 if (ofn->lpstrFilter) 516 { 517 LPCSTR s; 518 int n; 519 520 /* filter is a list... title\0ext\0......\0\0 */ 521 s = ofn->lpstrFilter; 522 while (*s) s = s+strlen(s)+1; 523 s++; 524 n = s - ofn->lpstrFilter; 525 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0); 526 ofnW.lpstrFilter = heap_alloc(len * sizeof(WCHAR)); 527 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, (WCHAR *)ofnW.lpstrFilter, len); 528 } 529 530 /* convert lpstrCustomFilter */ 531 if (ofn->lpstrCustomFilter) 532 { 533 int n, len; 534 LPCSTR s; 535 536 /* customfilter contains a pair of strings... title\0ext\0 */ 537 s = ofn->lpstrCustomFilter; 538 if (*s) s = s+strlen(s)+1; 539 if (*s) s = s+strlen(s)+1; 540 n = s - ofn->lpstrCustomFilter; 541 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0); 542 ofnW.lpstrCustomFilter = heap_alloc(len * sizeof(WCHAR)); 543 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, ofnW.lpstrCustomFilter, len); 544 } 545 546 init_filedlg_infoW(&ofnW, info); 547 548 /* fixup A-specific fields */ 549 info->ofnInfos = (OPENFILENAMEW *)ofn; 550 info->unicode = FALSE; 551 552 /* free what was duplicated */ 553 heap_free((void *)ofnW.lpstrInitialDir); 554 heap_free(ofnW.lpstrFile); 555 } 556 557 /*********************************************************************** 558 * GetFileDialog95 559 * 560 * Call GetFileName95 with this structure and clean the memory. 561 */ 562 static BOOL GetFileDialog95(FileOpenDlgInfos *info, UINT dlg_type) 563 { 564 WCHAR *current_dir = NULL; 565 unsigned int i; 566 BOOL ret; 567 568 /* save current directory */ 569 if (info->ofnInfos->Flags & OFN_NOCHANGEDIR) 570 { 571 current_dir = heap_alloc(MAX_PATH * sizeof(WCHAR)); 572 GetCurrentDirectoryW(MAX_PATH, current_dir); 573 } 574 575 switch (dlg_type) 576 { 577 case OPEN_DIALOG: 578 ret = GetFileName95(info); 579 break; 580 case SAVE_DIALOG: 581 info->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG; 582 ret = GetFileName95(info); 583 break; 584 default: 585 ret = FALSE; 586 } 587 588 /* set the lpstrFileTitle */ 589 if (ret && info->ofnInfos->lpstrFile && info->ofnInfos->lpstrFileTitle) 590 { 591 if (info->unicode) 592 { 593 LPOPENFILENAMEW ofn = info->ofnInfos; 594 WCHAR *file_title = PathFindFileNameW(ofn->lpstrFile); 595 lstrcpynW(ofn->lpstrFileTitle, file_title, ofn->nMaxFileTitle); 596 } 597 else 598 { 599 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)info->ofnInfos; 600 char *file_title = PathFindFileNameA(ofn->lpstrFile); 601 lstrcpynA(ofn->lpstrFileTitle, file_title, ofn->nMaxFileTitle); 602 } 603 } 604 605 if (current_dir) 606 { 607 SetCurrentDirectoryW(current_dir); 608 heap_free(current_dir); 609 } 610 611 if (!info->unicode) 612 { 613 heap_free((void *)info->defext); 614 heap_free((void *)info->title); 615 heap_free((void *)info->filter); 616 heap_free((void *)info->customfilter); 617 } 618 619 heap_free(info->filename); 620 heap_free(info->initdir); 621 622 for (i = 0; i < ARRAY_SIZE(info->places); i++) 623 ILFree(info->places[i]); 624 625 return ret; 626 } 627 628 /****************************************************************************** 629 * COMDLG32_GetDisplayNameOf [internal] 630 * 631 * Helper function to get the display name for a pidl. 632 */ 633 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) { 634 LPSHELLFOLDER psfDesktop; 635 STRRET strret; 636 637 if (FAILED(SHGetDesktopFolder(&psfDesktop))) 638 return FALSE; 639 640 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) { 641 IShellFolder_Release(psfDesktop); 642 return FALSE; 643 } 644 645 IShellFolder_Release(psfDesktop); 646 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH)); 647 } 648 649 /****************************************************************************** 650 * COMDLG32_GetCanonicalPath [internal] 651 * 652 * Helper function to get the canonical path. 653 */ 654 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent, 655 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile) 656 { 657 WCHAR lpstrTemp[MAX_PATH]; 658 659 /* Get the current directory name */ 660 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile)) 661 { 662 /* last fallback */ 663 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile); 664 } 665 PathAddBackslashW(lpstrPathAndFile); 666 667 TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile), debugstr_w(lpstrFile)); 668 669 /* if the user specified a fully qualified path use it */ 670 if(PathIsRelativeW(lpstrFile)) 671 { 672 lstrcatW(lpstrPathAndFile, lpstrFile); 673 } 674 else 675 { 676 /* does the path have a drive letter? */ 677 if (PathGetDriveNumberW(lpstrFile) == -1) 678 lstrcpyW(lpstrPathAndFile+2, lpstrFile); 679 else 680 lstrcpyW(lpstrPathAndFile, lpstrFile); 681 } 682 683 /* resolve "." and ".." */ 684 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile ); 685 lstrcpyW(lpstrPathAndFile, lpstrTemp); 686 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile)); 687 } 688 689 /*********************************************************************** 690 * COMDLG32_SplitFileNames [internal] 691 * 692 * Creates a delimited list of filenames. 693 */ 694 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed) 695 { 696 UINT nStrCharCount = 0; /* index in src buffer */ 697 UINT nFileIndex = 0; /* index in dest buffer */ 698 UINT nFileCount = 0; /* number of files */ 699 700 /* we might get single filename without any '"', 701 * so we need nStrLen + terminating \0 + end-of-list \0 */ 702 *lpstrFileList = heap_alloc((nStrLen + 2) * sizeof(WCHAR)); 703 *sizeUsed = 0; 704 705 /* build delimited file list from filenames */ 706 while ( nStrCharCount <= nStrLen ) 707 { 708 if ( lpstrEdit[nStrCharCount]=='"' ) 709 { 710 nStrCharCount++; 711 while ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"')) 712 { 713 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount]; 714 nStrCharCount++; 715 } 716 (*lpstrFileList)[nFileIndex++] = 0; 717 nFileCount++; 718 } 719 nStrCharCount++; 720 } 721 722 /* single, unquoted string */ 723 if ((nStrLen > 0) && (nFileIndex == 0) ) 724 { 725 lstrcpyW(*lpstrFileList, lpstrEdit); 726 nFileIndex = lstrlenW(lpstrEdit) + 1; 727 nFileCount = 1; 728 } 729 730 /* trailing \0 */ 731 (*lpstrFileList)[nFileIndex++] = '\0'; 732 733 *sizeUsed = nFileIndex; 734 return nFileCount; 735 } 736 737 /*********************************************************************** 738 * ArrangeCtrlPositions [internal] 739 * 740 * NOTE: Make sure to add testcases for any changes made here. 741 */ 742 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help) 743 { 744 HWND hwndChild, hwndStc32; 745 RECT rectParent, rectChild, rectStc32; 746 INT help_fixup = 0; 747 int chgx, chgy; 748 749 /* Take into account if open as read only checkbox and help button 750 * are hidden 751 */ 752 if (hide_help) 753 { 754 RECT rectHelp, rectCancel; 755 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp); 756 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel); 757 /* subtract the height of the help button plus the space between 758 * the help button and the cancel button to the height of the dialog 759 */ 760 help_fixup = rectHelp.bottom - rectCancel.bottom; 761 } 762 763 /* 764 There are two possibilities to add components to the default file dialog box. 765 766 By default, all the new components are added below the standard dialog box (the else case). 767 768 However, if there is a static text component with the stc32 id, a special case happens. 769 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box 770 in the window and the cx and cy indicate how to size the window. 771 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left 772 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on.... 773 774 */ 775 776 GetClientRect(hwndParentDlg, &rectParent); 777 778 /* when arranging controls we have to use fixed parent size */ 779 rectParent.bottom -= help_fixup; 780 781 hwndStc32 = GetDlgItem(hwndChildDlg, stc32); 782 if (hwndStc32) 783 { 784 GetWindowRect(hwndStc32, &rectStc32); 785 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2); 786 787 /* set the size of the stc32 control according to the size of 788 * client area of the parent dialog 789 */ 790 SetWindowPos(hwndStc32, 0, 791 0, 0, 792 rectParent.right, rectParent.bottom, 793 SWP_NOMOVE | SWP_NOZORDER); 794 } 795 else 796 SetRectEmpty(&rectStc32); 797 798 /* this part moves controls of the child dialog */ 799 hwndChild = GetWindow(hwndChildDlg, GW_CHILD); 800 while (hwndChild) 801 { 802 if (hwndChild != hwndStc32) 803 { 804 GetWindowRect(hwndChild, &rectChild); 805 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2); 806 807 /* move only if stc32 exist */ 808 if (hwndStc32 && rectChild.left > rectStc32.right) 809 { 810 /* move to the right of visible controls of the parent dialog */ 811 rectChild.left += rectParent.right; 812 rectChild.left -= rectStc32.right; 813 } 814 /* move even if stc32 doesn't exist */ 815 if (rectChild.top >= rectStc32.bottom) 816 { 817 /* move below visible controls of the parent dialog */ 818 rectChild.top += rectParent.bottom; 819 rectChild.top -= rectStc32.bottom - rectStc32.top; 820 } 821 822 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top, 823 0, 0, SWP_NOSIZE | SWP_NOZORDER); 824 } 825 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT); 826 } 827 828 /* this part moves controls of the parent dialog */ 829 hwndChild = GetWindow(hwndParentDlg, GW_CHILD); 830 while (hwndChild) 831 { 832 if (hwndChild != hwndChildDlg) 833 { 834 GetWindowRect(hwndChild, &rectChild); 835 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2); 836 837 /* left,top of stc32 marks the position of controls 838 * from the parent dialog 839 */ 840 rectChild.left += rectStc32.left; 841 rectChild.top += rectStc32.top; 842 843 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top, 844 0, 0, SWP_NOSIZE | SWP_NOZORDER); 845 } 846 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT); 847 } 848 849 /* calculate the size of the resulting dialog */ 850 851 /* here we have to use original parent size */ 852 GetClientRect(hwndParentDlg, &rectParent); 853 GetClientRect(hwndChildDlg, &rectChild); 854 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent), 855 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32)); 856 857 if (hwndStc32) 858 { 859 /* width */ 860 if (rectParent.right > rectStc32.right - rectStc32.left) 861 chgx = rectChild.right - ( rectStc32.right - rectStc32.left); 862 else 863 chgx = rectChild.right - rectParent.right; 864 /* height */ 865 if (rectParent.bottom > rectStc32.bottom - rectStc32.top) 866 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup; 867 else 868 /* Unconditionally set new dialog 869 * height to that of the child 870 */ 871 chgy = rectChild.bottom - rectParent.bottom; 872 } 873 else 874 { 875 chgx = 0; 876 chgy = rectChild.bottom - help_fixup; 877 } 878 /* set the size of the parent dialog */ 879 GetWindowRect(hwndParentDlg, &rectParent); 880 SetWindowPos(hwndParentDlg, 0, 881 0, 0, 882 rectParent.right - rectParent.left + chgx, 883 rectParent.bottom - rectParent.top + chgy, 884 SWP_NOMOVE | SWP_NOZORDER); 885 } 886 887 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 888 { 889 switch(uMsg) { 890 case WM_INITDIALOG: 891 return TRUE; 892 } 893 return FALSE; 894 } 895 896 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd) 897 { 898 LPCVOID template; 899 HRSRC hRes; 900 HANDLE hDlgTmpl = 0; 901 HWND hChildDlg = 0; 902 903 TRACE("%p, %p\n", fodInfos, hwnd); 904 905 /* 906 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME 907 * structure's hInstance parameter is not a HINSTANCE, but 908 * instead a pointer to a template resource to use. 909 */ 910 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)) 911 { 912 HINSTANCE hinst; 913 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE) 914 { 915 hinst = COMDLG32_hInstance; 916 if( !(template = LockResource( fodInfos->ofnInfos->hInstance))) 917 { 918 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); 919 return NULL; 920 } 921 } 922 else 923 { 924 hinst = fodInfos->ofnInfos->hInstance; 925 if(fodInfos->unicode) 926 { 927 LPOPENFILENAMEW ofn = fodInfos->ofnInfos; 928 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG); 929 } 930 else 931 { 932 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; 933 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG); 934 } 935 if (!hRes) 936 { 937 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); 938 return NULL; 939 } 940 if (!(hDlgTmpl = LoadResource( hinst, hRes )) || 941 !(template = LockResource( hDlgTmpl ))) 942 { 943 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); 944 return NULL; 945 } 946 } 947 if (fodInfos->unicode) 948 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd, 949 is_dialog_hooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate, 950 (LPARAM)fodInfos->ofnInfos); 951 else 952 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd, 953 is_dialog_hooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate, 954 (LPARAM)fodInfos->ofnInfos); 955 return hChildDlg; 956 } 957 else if (is_dialog_hooked(fodInfos)) 958 { 959 RECT rectHwnd; 960 struct { 961 DLGTEMPLATE tmplate; 962 WORD menu,class,title; 963 } temp; 964 GetClientRect(hwnd,&rectHwnd); 965 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK; 966 temp.tmplate.dwExtendedStyle = 0; 967 temp.tmplate.cdit = 0; 968 temp.tmplate.x = 0; 969 temp.tmplate.y = 0; 970 temp.tmplate.cx = 0; 971 temp.tmplate.cy = 0; 972 temp.menu = temp.class = temp.title = 0; 973 974 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate, 975 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos); 976 977 return hChildDlg; 978 } 979 return NULL; 980 } 981 982 /*********************************************************************** 983 * SendCustomDlgNotificationMessage 984 * 985 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog 986 */ 987 988 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode) 989 { 990 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwndParentDlg); 991 LRESULT hook_result; 992 OFNOTIFYW ofnNotify; 993 994 TRACE("%p %d\n", hwndParentDlg, uCode); 995 996 if (!fodInfos || !fodInfos->DlgInfos.hwndCustomDlg) 997 return 0; 998 999 TRACE("CALL NOTIFY for %d\n", uCode); 1000 1001 ofnNotify.hdr.hwndFrom = hwndParentDlg; 1002 ofnNotify.hdr.idFrom = 0; 1003 ofnNotify.hdr.code = uCode; 1004 ofnNotify.lpOFN = fodInfos->ofnInfos; 1005 ofnNotify.pszFile = NULL; 1006 1007 if (fodInfos->unicode) 1008 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify); 1009 else 1010 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify); 1011 1012 TRACE("RET NOTIFY retval %#lx\n", hook_result); 1013 1014 return hook_result; 1015 } 1016 1017 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result) 1018 { 1019 UINT len, total; 1020 WCHAR *p, *buffer; 1021 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 1022 1023 TRACE("CDM_GETFILEPATH:\n"); 1024 1025 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) ) 1026 return -1; 1027 1028 /* get path and filenames */ 1029 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 ); 1030 buffer = heap_alloc( (len + 2 + MAX_PATH) * sizeof(WCHAR) ); 1031 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer ); 1032 if (len) 1033 { 1034 p = buffer + lstrlenW(buffer); 1035 *p++ = '\\'; 1036 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p ); 1037 } 1038 if (fodInfos->unicode) 1039 { 1040 total = lstrlenW( buffer) + 1; 1041 if (result) lstrcpynW( result, buffer, size ); 1042 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result)); 1043 } 1044 else 1045 { 1046 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL ); 1047 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL ); 1048 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result)); 1049 } 1050 heap_free( buffer ); 1051 return total; 1052 } 1053 1054 /*********************************************************************** 1055 * FILEDLG95_HandleCustomDialogMessages 1056 * 1057 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages 1058 */ 1059 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 1060 { 1061 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 1062 WCHAR lpstrPath[MAX_PATH]; 1063 INT_PTR retval; 1064 1065 if(!fodInfos) return FALSE; 1066 1067 switch(uMsg) 1068 { 1069 case CDM_GETFILEPATH: 1070 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam); 1071 break; 1072 1073 case CDM_GETFOLDERPATH: 1074 TRACE("CDM_GETFOLDERPATH:\n"); 1075 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath); 1076 if (lParam) 1077 { 1078 if (fodInfos->unicode) 1079 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam); 1080 else 1081 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1, 1082 (LPSTR)lParam, (int)wParam, NULL, NULL); 1083 } 1084 retval = lstrlenW(lpstrPath) + 1; 1085 break; 1086 1087 case CDM_GETFOLDERIDLIST: 1088 retval = ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent); 1089 if (retval <= wParam) 1090 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval); 1091 break; 1092 1093 case CDM_GETSPEC: 1094 TRACE("CDM_GETSPEC:\n"); 1095 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1; 1096 if (lParam) 1097 { 1098 if (fodInfos->unicode) 1099 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam); 1100 else 1101 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam); 1102 } 1103 break; 1104 1105 case CDM_SETCONTROLTEXT: 1106 TRACE("CDM_SETCONTROLTEXT:\n"); 1107 if ( lParam ) 1108 { 1109 if( fodInfos->unicode ) 1110 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam ); 1111 else 1112 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam ); 1113 } 1114 retval = TRUE; 1115 break; 1116 1117 case CDM_HIDECONTROL: 1118 /* MSDN states that it should fail for not OFN_EXPLORER case */ 1119 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER) 1120 { 1121 HWND control = GetDlgItem( hwnd, wParam ); 1122 if (control) ShowWindow( control, SW_HIDE ); 1123 retval = TRUE; 1124 } 1125 else retval = FALSE; 1126 break; 1127 1128 default: 1129 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST) 1130 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST); 1131 return FALSE; 1132 } 1133 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval); 1134 return TRUE; 1135 } 1136 1137 /*********************************************************************** 1138 * FILEDLG95_OnWMGetMMI 1139 * 1140 * WM_GETMINMAXINFO message handler for resizable dialogs 1141 */ 1142 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr) 1143 { 1144 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 1145 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE; 1146 if( fodInfos->initial_size.x || fodInfos->initial_size.y) 1147 { 1148 mmiptr->ptMinTrackSize = fodInfos->initial_size; 1149 } 1150 return TRUE; 1151 } 1152 1153 /*********************************************************************** 1154 * FILEDLG95_OnWMSize 1155 * 1156 * WM_SIZE message handler, resize the dialog. Re-arrange controls. 1157 * 1158 * FIXME: this could be made more elaborate. Now use a simple scheme 1159 * where the file view is enlarged and the controls are either moved 1160 * vertically or horizontally to get out of the way. Only the "grip" 1161 * is moved in both directions to stay in the corner. 1162 */ 1163 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam) 1164 { 1165 RECT rc, rcview; 1166 int chgx, chgy; 1167 HWND ctrl; 1168 HDWP hdwp; 1169 FileOpenDlgInfos *fodInfos; 1170 1171 if( wParam != SIZE_RESTORED) return FALSE; 1172 fodInfos = get_filedlg_infoptr(hwnd); 1173 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE; 1174 /* get the new dialog rectangle */ 1175 GetWindowRect( hwnd, &rc); 1176 TRACE("%p, size from %d,%d to %d,%d\n", hwnd, fodInfos->sizedlg.cx, fodInfos->sizedlg.cy, 1177 rc.right -rc.left, rc.bottom -rc.top); 1178 /* not initialized yet */ 1179 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) || 1180 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */ 1181 (fodInfos->sizedlg.cy == rc.bottom -rc.top))) 1182 return FALSE; 1183 chgx = rc.right - rc.left - fodInfos->sizedlg.cx; 1184 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy; 1185 fodInfos->sizedlg.cx = rc.right - rc.left; 1186 fodInfos->sizedlg.cy = rc.bottom - rc.top; 1187 /* change the size of the view window */ 1188 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview); 1189 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2); 1190 hdwp = BeginDeferWindowPos( 10); 1191 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0, 1192 rcview.right - rcview.left + chgx, 1193 rcview.bottom - rcview.top + chgy, 1194 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); 1195 /* change position and sizes of the controls */ 1196 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT)) 1197 { 1198 int ctrlid = GetDlgCtrlID( ctrl); 1199 GetWindowRect( ctrl, &rc); 1200 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2); 1201 if( ctrl == fodInfos->DlgInfos.hwndGrip) 1202 { 1203 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy, 1204 0, 0, 1205 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); 1206 } 1207 else if( rc.top > rcview.bottom) 1208 { 1209 /* if it was below the shell view 1210 * move to bottom */ 1211 switch( ctrlid) 1212 { 1213 /* file name (edit or comboboxex) and file types combo change also width */ 1214 case edt1: 1215 case cmb13: 1216 case cmb1: 1217 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy, 1218 rc.right - rc.left + chgx, rc.bottom - rc.top, 1219 SWP_NOACTIVATE | SWP_NOZORDER); 1220 break; 1221 /* then these buttons must move out of the way */ 1222 case IDOK: 1223 case IDCANCEL: 1224 case pshHelp: 1225 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy, 1226 0, 0, 1227 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); 1228 break; 1229 default: 1230 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy, 1231 0, 0, 1232 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); 1233 } 1234 } 1235 else if( rc.left > rcview.right) 1236 { 1237 /* if it was to the right of the shell view 1238 * move to right */ 1239 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top, 1240 0, 0, 1241 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); 1242 } 1243 else 1244 /* special cases */ 1245 { 1246 switch( ctrlid) 1247 { 1248 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */ 1249 case IDC_LOOKIN: 1250 DeferWindowPos( hdwp, ctrl, NULL, 0, 0, 1251 rc.right - rc.left + chgx, rc.bottom - rc.top, 1252 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); 1253 break; 1254 case IDC_TOOLBARSTATIC: 1255 case IDC_TOOLBAR: 1256 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top, 1257 0, 0, 1258 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); 1259 break; 1260 #endif 1261 /* not resized in windows. Since wine uses this invisible control 1262 * to size the browser view it needs to be resized */ 1263 case IDC_SHELLSTATIC: 1264 DeferWindowPos( hdwp, ctrl, NULL, 0, 0, 1265 rc.right - rc.left + chgx, 1266 rc.bottom - rc.top + chgy, 1267 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); 1268 break; 1269 case IDC_TOOLBARPLACES: 1270 DeferWindowPos( hdwp, ctrl, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + chgy, 1271 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); 1272 break; 1273 } 1274 } 1275 } 1276 if(fodInfos->DlgInfos.hwndCustomDlg && 1277 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))) 1278 { 1279 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD); 1280 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT)) 1281 { 1282 GetWindowRect( ctrl, &rc); 1283 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2); 1284 if( rc.top > rcview.bottom) 1285 { 1286 /* if it was below the shell view 1287 * move to bottom */ 1288 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy, 1289 rc.right - rc.left, rc.bottom - rc.top, 1290 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); 1291 } 1292 else if( rc.left > rcview.right) 1293 { 1294 /* if it was to the right of the shell view 1295 * move to right */ 1296 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top, 1297 rc.right - rc.left, rc.bottom - rc.top, 1298 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); 1299 } 1300 } 1301 /* size the custom dialog at the end: some applications do some 1302 * control re-arranging at this point */ 1303 GetClientRect(hwnd, &rc); 1304 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL, 1305 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); 1306 } 1307 EndDeferWindowPos( hdwp); 1308 /* should not be needed */ 1309 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE ); 1310 return TRUE; 1311 } 1312 1313 /*********************************************************************** 1314 * FileOpenDlgProc95 1315 * 1316 * File open dialog procedure 1317 */ 1318 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 1319 { 1320 #if 0 1321 TRACE("%p 0x%04x\n", hwnd, uMsg); 1322 #endif 1323 1324 switch(uMsg) 1325 { 1326 case WM_INITDIALOG: 1327 { 1328 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam; 1329 RECT rc, rcstc; 1330 int gripx = GetSystemMetrics( SM_CYHSCROLL); 1331 int gripy = GetSystemMetrics( SM_CYVSCROLL); 1332 1333 /* Some shell namespace extensions depend on COM being initialized. */ 1334 if (SUCCEEDED(OleInitialize(NULL))) 1335 fodInfos->ole_initialized = TRUE; 1336 1337 SetPropW(hwnd, filedlg_info_propnameW, fodInfos); 1338 1339 FILEDLG95_InitControls(hwnd); 1340 1341 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING) 1342 { 1343 DWORD style = GetWindowLongW(hwnd, GWL_STYLE); 1344 DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE); 1345 RECT client, client_adjusted; 1346 1347 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING) 1348 { 1349 style |= WS_SIZEBOX; 1350 ex_style |= WS_EX_WINDOWEDGE; 1351 } 1352 else 1353 style &= ~WS_SIZEBOX; 1354 SetWindowLongW(hwnd, GWL_STYLE, style); 1355 SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style); 1356 1357 GetClientRect( hwnd, &client ); 1358 GetClientRect( hwnd, &client_adjusted ); 1359 AdjustWindowRectEx( &client_adjusted, style, FALSE, ex_style ); 1360 1361 GetWindowRect( hwnd, &rc ); 1362 rc.right += client_adjusted.right - client.right; 1363 rc.bottom += client_adjusted.bottom - client.bottom; 1364 SetWindowPos(hwnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOACTIVATE | 1365 SWP_NOZORDER | SWP_NOMOVE); 1366 1367 GetWindowRect( hwnd, &rc ); 1368 fodInfos->DlgInfos.hwndGrip = 1369 CreateWindowExA( 0, "SCROLLBAR", NULL, 1370 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | 1371 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 1372 rc.right - gripx, rc.bottom - gripy, 1373 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL); 1374 } 1375 1376 fodInfos->DlgInfos.hwndCustomDlg = 1377 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd); 1378 1379 FILEDLG95_ResizeControls(hwnd, wParam, lParam); 1380 FILEDLG95_FillControls(hwnd, wParam, lParam); 1381 1382 if( fodInfos->DlgInfos.hwndCustomDlg) 1383 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW); 1384 1385 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) { 1386 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE); 1387 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE); 1388 } 1389 1390 /* if the app has changed the position of the invisible listbox, 1391 * change that of the listview (browser) as well */ 1392 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc); 1393 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc); 1394 if( !EqualRect( &rc, &rcstc)) 1395 { 1396 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2); 1397 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL, 1398 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top, 1399 SWP_NOACTIVATE | SWP_NOZORDER); 1400 } 1401 1402 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING) 1403 { 1404 GetWindowRect( hwnd, &rc); 1405 fodInfos->sizedlg.cx = rc.right - rc.left; 1406 fodInfos->sizedlg.cy = rc.bottom - rc.top; 1407 fodInfos->initial_size.x = fodInfos->sizedlg.cx; 1408 fodInfos->initial_size.y = fodInfos->sizedlg.cy; 1409 GetClientRect( hwnd, &rc); 1410 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL, 1411 rc.right - gripx, rc.bottom - gripy, 1412 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); 1413 /* resize the dialog to the previous invocation */ 1414 if( MemDialogSize.cx && MemDialogSize.cy) 1415 SetWindowPos( hwnd, NULL, 1416 0, 0, MemDialogSize.cx, MemDialogSize.cy, 1417 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); 1418 } 1419 1420 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 1421 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE); 1422 1423 return 0; 1424 } 1425 case WM_SIZE: 1426 return FILEDLG95_OnWMSize(hwnd, wParam); 1427 case WM_GETMINMAXINFO: 1428 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam); 1429 case WM_COMMAND: 1430 return FILEDLG95_OnWMCommand(hwnd, wParam); 1431 case WM_DRAWITEM: 1432 { 1433 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID) 1434 { 1435 case IDC_LOOKIN: 1436 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam); 1437 return TRUE; 1438 } 1439 } 1440 return FALSE; 1441 1442 case WM_GETISHELLBROWSER: 1443 return FILEDLG95_OnWMGetIShellBrowser(hwnd); 1444 1445 case WM_DESTROY: 1446 { 1447 FileOpenDlgInfos * fodInfos = get_filedlg_infoptr(hwnd); 1448 HWND places_bar = GetDlgItem(hwnd, IDC_TOOLBARPLACES); 1449 HIMAGELIST himl; 1450 1451 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING) 1452 MemDialogSize = fodInfos->sizedlg; 1453 1454 if (places_bar) 1455 { 1456 himl = (HIMAGELIST)SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_GETIMAGELIST, 0, 0); 1457 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, 0); 1458 ImageList_Destroy(himl); 1459 } 1460 return FALSE; 1461 } 1462 1463 case WM_NCDESTROY: 1464 RemovePropW(hwnd, filedlg_info_propnameW); 1465 return 0; 1466 1467 case WM_NOTIFY: 1468 { 1469 LPNMHDR lpnmh = (LPNMHDR)lParam; 1470 UINT stringId = -1; 1471 1472 /* set up the button tooltips strings */ 1473 if(TTN_GETDISPINFOA == lpnmh->code ) 1474 { 1475 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam; 1476 switch(lpnmh->idFrom ) 1477 { 1478 /* Up folder button */ 1479 case FCIDM_TB_UPFOLDER: 1480 stringId = IDS_UPFOLDER; 1481 break; 1482 /* New folder button */ 1483 case FCIDM_TB_NEWFOLDER: 1484 stringId = IDS_NEWFOLDER; 1485 break; 1486 /* List option button */ 1487 case FCIDM_TB_SMALLICON: 1488 stringId = IDS_LISTVIEW; 1489 break; 1490 /* Details option button */ 1491 case FCIDM_TB_REPORTVIEW: 1492 stringId = IDS_REPORTVIEW; 1493 break; 1494 /* Desktop button */ 1495 case FCIDM_TB_DESKTOP: 1496 stringId = IDS_TODESKTOP; 1497 break; 1498 default: 1499 stringId = 0; 1500 } 1501 lpdi->hinst = COMDLG32_hInstance; 1502 lpdi->lpszText = MAKEINTRESOURCEA(stringId); 1503 } 1504 return FALSE; 1505 } 1506 default : 1507 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST) 1508 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam); 1509 return FALSE; 1510 } 1511 } 1512 1513 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info ) 1514 { 1515 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) && 1516 (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)); 1517 } 1518 1519 /*********************************************************************** 1520 * FILEDLG95_InitControls 1521 * 1522 * WM_INITDIALOG message handler (before hook notification) 1523 */ 1524 static LRESULT FILEDLG95_InitControls(HWND hwnd) 1525 { 1526 BOOL win2000plus = FALSE; 1527 BOOL win98plus = FALSE; 1528 BOOL handledPath = FALSE; 1529 OSVERSIONINFOW osVi; 1530 static const WCHAR szwSlash[] = { '\\', 0 }; 1531 static const WCHAR szwStar[] = { '*',0 }; 1532 1533 static const TBBUTTON tbb[] = 1534 { 1535 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, 1536 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, 1537 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, 1538 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, 1539 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, 1540 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, 1541 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, 1542 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, 1543 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, 1544 }; 1545 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR}; 1546 1547 RECT rectTB; 1548 RECT rectlook; 1549 1550 HIMAGELIST toolbarImageList; 1551 ITEMIDLIST *desktopPidl; 1552 SHFILEINFOW fileinfo; 1553 1554 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 1555 1556 TRACE("%p\n", fodInfos); 1557 1558 /* Get windows version emulating */ 1559 osVi.dwOSVersionInfoSize = sizeof(osVi); 1560 GetVersionExW(&osVi); 1561 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { 1562 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0))); 1563 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) { 1564 win2000plus = (osVi.dwMajorVersion > 4); 1565 if (win2000plus) win98plus = TRUE; 1566 } 1567 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus); 1568 1569 1570 /* Use either the edit or the comboboxex for the filename control */ 1571 if (filename_is_edit( fodInfos )) 1572 { 1573 DestroyWindow( GetDlgItem( hwnd, cmb13 ) ); 1574 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 ); 1575 } 1576 else 1577 { 1578 DestroyWindow( GetDlgItem( hwnd, edt1 ) ); 1579 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 ); 1580 } 1581 1582 /* Get the hwnd of the controls */ 1583 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE); 1584 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN); 1585 1586 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook); 1587 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2); 1588 1589 /* construct the toolbar */ 1590 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB); 1591 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2); 1592 1593 rectTB.right = rectlook.right + rectTB.right - rectTB.left; 1594 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top; 1595 rectTB.left = rectlook.right; 1596 rectTB.top = rectlook.top-1; 1597 1598 if (fodInfos->unicode) 1599 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, 1600 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE, 1601 rectTB.left, rectTB.top, 1602 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top, 1603 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL); 1604 else 1605 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, 1606 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE, 1607 rectTB.left, rectTB.top, 1608 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top, 1609 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL); 1610 1611 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); 1612 1613 /* FIXME: use TB_LOADIMAGES when implemented */ 1614 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/ 1615 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0); 1616 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba); 1617 1618 /* Retrieve and add desktop icon to the toolbar */ 1619 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L); 1620 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl); 1621 SHGetFileInfoW((const WCHAR *)desktopPidl, 0, &fileinfo, sizeof(fileinfo), 1622 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON); 1623 ImageList_AddIcon(toolbarImageList, fileinfo.hIcon); 1624 1625 DestroyIcon(fileinfo.hIcon); 1626 CoTaskMemFree(desktopPidl); 1627 1628 /* Finish Toolbar Construction */ 1629 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb); 1630 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0); 1631 1632 if (is_places_bar_enabled(fodInfos)) 1633 { 1634 TBBUTTON tb = { 0 }; 1635 HIMAGELIST himl; 1636 RECT rect; 1637 int i, cx; 1638 1639 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_BUTTONSTRUCTSIZE, 0, 0); 1640 GetClientRect(GetDlgItem(hwnd, IDC_TOOLBARPLACES), &rect); 1641 cx = rect.right - rect.left; 1642 1643 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cx, cx)); 1644 himl = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32, 4, 1); 1645 1646 filedlg_collect_places_pidls(fodInfos); 1647 for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++) 1648 { 1649 int index; 1650 1651 if (!fodInfos->places[i]) 1652 continue; 1653 1654 memset(&fileinfo, 0, sizeof(fileinfo)); 1655 SHGetFileInfoW((const WCHAR *)fodInfos->places[i], 0, &fileinfo, sizeof(fileinfo), 1656 SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON); 1657 index = ImageList_AddIcon(himl, fileinfo.hIcon); 1658 1659 tb.iBitmap = index; 1660 tb.iString = (INT_PTR)fileinfo.szDisplayName; 1661 tb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP; 1662 tb.idCommand = TBPLACES_CMDID_PLACE0 + i; 1663 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_ADDBUTTONSW, 1, (LPARAM)&tb); 1664 1665 DestroyIcon(fileinfo.hIcon); 1666 } 1667 1668 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, (LPARAM)himl); 1669 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cx * 3 / 4)); 1670 } 1671 1672 /* Set the window text with the text specified in the OPENFILENAME structure */ 1673 if(fodInfos->title) 1674 { 1675 SetWindowTextW(hwnd,fodInfos->title); 1676 } 1677 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) 1678 { 1679 WCHAR buf[64]; 1680 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, ARRAY_SIZE(buf)); 1681 SetWindowTextW(hwnd, buf); 1682 } 1683 1684 /* Initialise the file name edit control */ 1685 handledPath = FALSE; 1686 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); 1687 1688 if(fodInfos->filename) 1689 { 1690 /* 1. If win2000 or higher and filename contains a path, use it 1691 in preference over the lpstrInitialDir */ 1692 if (win2000plus && *fodInfos->filename && wcspbrk(fodInfos->filename, szwSlash)) { 1693 WCHAR tmpBuf[MAX_PATH]; 1694 WCHAR *nameBit; 1695 DWORD result; 1696 1697 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit); 1698 if (result) { 1699 1700 /* nameBit is always shorter than the original filename. It may be NULL 1701 * when the filename contains only a drive name instead of file name */ 1702 if (nameBit) 1703 { 1704 lstrcpyW(fodInfos->filename,nameBit); 1705 *nameBit = 0x00; 1706 } 1707 else 1708 *fodInfos->filename = '\0'; 1709 1710 heap_free(fodInfos->initdir); 1711 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR)); 1712 lstrcpyW(fodInfos->initdir, tmpBuf); 1713 handledPath = TRUE; 1714 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n", 1715 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); 1716 } 1717 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename ); 1718 1719 } else { 1720 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename ); 1721 } 1722 } 1723 1724 /* 2. (All platforms) If initdir is not null, then use it */ 1725 if (!handledPath && fodInfos->initdir && *fodInfos->initdir) 1726 { 1727 /* Work out the proper path as supplied one might be relative */ 1728 /* (Here because supplying '.' as dir browses to My Computer) */ 1729 WCHAR tmpBuf[MAX_PATH]; 1730 WCHAR tmpBuf2[MAX_PATH]; 1731 WCHAR *nameBit; 1732 DWORD result; 1733 1734 lstrcpyW(tmpBuf, fodInfos->initdir); 1735 if (PathFileExistsW(tmpBuf)) { 1736 /* initdir does not have to be a directory. If a file is 1737 * specified, the dir part is taken */ 1738 if (PathIsDirectoryW(tmpBuf)) { 1739 PathAddBackslashW(tmpBuf); 1740 lstrcatW(tmpBuf, szwStar); 1741 } 1742 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit); 1743 if (result) { 1744 *nameBit = 0x00; 1745 heap_free(fodInfos->initdir); 1746 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR)); 1747 lstrcpyW(fodInfos->initdir, tmpBuf2); 1748 handledPath = TRUE; 1749 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir)); 1750 } 1751 } 1752 else if (fodInfos->initdir) 1753 { 1754 heap_free(fodInfos->initdir); 1755 fodInfos->initdir = NULL; 1756 TRACE("Value in InitDir is not an existing path, changed to (nil)\n"); 1757 } 1758 } 1759 1760 #ifdef __REACTOS__ 1761 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir)) 1762 { 1763 /* 2.5. Win2000+: Recently used defext */ 1764 if (win2000plus) { 1765 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR)); 1766 fodInfos->initdir[0] = '\0'; 1767 1768 FILEDLG95_MRU_load_ext(fodInfos->initdir, MAX_PATH, fodInfos->defext); 1769 1770 if (fodInfos->initdir[0] && PathIsDirectoryW(fodInfos->initdir)) { 1771 handledPath = TRUE; 1772 } else { 1773 heap_free(fodInfos->initdir); 1774 fodInfos->initdir = NULL; 1775 } 1776 } 1777 } 1778 #endif 1779 1780 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir)) 1781 { 1782 /* 3. All except w2k+: if filename contains a path use it */ 1783 if (!win2000plus && fodInfos->filename && 1784 *fodInfos->filename && 1785 wcspbrk(fodInfos->filename, szwSlash)) { 1786 WCHAR tmpBuf[MAX_PATH]; 1787 WCHAR *nameBit; 1788 DWORD result; 1789 1790 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, 1791 tmpBuf, &nameBit); 1792 if (result) { 1793 int len; 1794 1795 /* nameBit is always shorter than the original filename */ 1796 lstrcpyW(fodInfos->filename, nameBit); 1797 *nameBit = 0x00; 1798 1799 len = lstrlenW(tmpBuf); 1800 heap_free(fodInfos->initdir); 1801 fodInfos->initdir = heap_alloc((len+1)*sizeof(WCHAR)); 1802 lstrcpyW(fodInfos->initdir, tmpBuf); 1803 1804 handledPath = TRUE; 1805 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n", 1806 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); 1807 } 1808 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename ); 1809 } 1810 1811 /* 4. Win2000+: Recently used */ 1812 if (!handledPath && win2000plus) { 1813 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR)); 1814 fodInfos->initdir[0] = '\0'; 1815 1816 FILEDLG95_MRU_load_filename(fodInfos->initdir); 1817 1818 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){ 1819 handledPath = TRUE; 1820 }else{ 1821 heap_free(fodInfos->initdir); 1822 fodInfos->initdir = NULL; 1823 } 1824 } 1825 1826 /* 5. win98+ and win2000+ if any files of specified filter types in 1827 current directory, use it */ 1828 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) { 1829 1830 LPCWSTR lpstrPos = fodInfos->filter; 1831 WIN32_FIND_DATAW FindFileData; 1832 HANDLE hFind; 1833 1834 while (1) 1835 { 1836 /* filter is a list... title\0ext\0......\0\0 */ 1837 1838 /* Skip the title */ 1839 if(! *lpstrPos) break; /* end */ 1840 lpstrPos += lstrlenW(lpstrPos) + 1; 1841 1842 /* See if any files exist in the current dir with this extension */ 1843 if(! *lpstrPos) break; /* end */ 1844 1845 hFind = FindFirstFileW(lpstrPos, &FindFileData); 1846 1847 if (hFind == INVALID_HANDLE_VALUE) { 1848 /* None found - continue search */ 1849 lpstrPos += lstrlenW(lpstrPos) + 1; 1850 1851 } else { 1852 1853 heap_free(fodInfos->initdir); 1854 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR)); 1855 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir); 1856 1857 handledPath = TRUE; 1858 TRACE("No initial dir specified, but files of type %s found in current, so using it\n", 1859 debugstr_w(lpstrPos)); 1860 FindClose(hFind); 1861 break; 1862 } 1863 } 1864 } 1865 1866 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */ 1867 if (!handledPath && (win2000plus || win98plus)) { 1868 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR)); 1869 1870 if (SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir) == S_OK) 1871 { 1872 if (SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir) == S_OK) 1873 { 1874 /* last fallback */ 1875 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir); 1876 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir)); 1877 } 1878 else 1879 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir)); 1880 } 1881 else 1882 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir)); 1883 1884 handledPath = TRUE; 1885 } else if (!handledPath) { 1886 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR)); 1887 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir); 1888 handledPath = TRUE; 1889 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir)); 1890 } 1891 } 1892 SetFocus( fodInfos->DlgInfos.hwndFileName ); 1893 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); 1894 1895 /* Must the open as read only check box be checked ?*/ 1896 if(fodInfos->ofnInfos->Flags & OFN_READONLY) 1897 { 1898 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0); 1899 } 1900 1901 /* Must the open as read only check box be hidden? */ 1902 if (filedialog_is_readonly_hidden(fodInfos)) 1903 { 1904 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE); 1905 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE); 1906 } 1907 1908 /* Must the help button be hidden? */ 1909 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP)) 1910 { 1911 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE); 1912 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE); 1913 } 1914 1915 /* change Open to Save */ 1916 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) 1917 { 1918 WCHAR buf[16]; 1919 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, ARRAY_SIZE(buf)); 1920 SetDlgItemTextW(hwnd, IDOK, buf); 1921 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, ARRAY_SIZE(buf)); 1922 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf); 1923 } 1924 1925 /* Initialize the filter combo box */ 1926 FILEDLG95_FILETYPE_Init(hwnd); 1927 1928 return 0; 1929 } 1930 1931 /*********************************************************************** 1932 * FILEDLG95_ResizeControls 1933 * 1934 * WM_INITDIALOG message handler (after hook notification) 1935 */ 1936 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam) 1937 { 1938 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam; 1939 1940 if (fodInfos->DlgInfos.hwndCustomDlg) 1941 { 1942 RECT rc; 1943 UINT flags = SWP_NOACTIVATE; 1944 1945 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd, 1946 filedialog_is_readonly_hidden(fodInfos) && !(fodInfos->ofnInfos->Flags & OFN_SHOWHELP)); 1947 1948 /* resize the custom dialog to the parent size */ 1949 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)) 1950 GetClientRect(hwnd, &rc); 1951 else 1952 { 1953 /* our own fake template is zero sized and doesn't have children, so 1954 * there is no need to resize it. Picasa depends on it. 1955 */ 1956 flags |= SWP_NOSIZE; 1957 SetRectEmpty(&rc); 1958 } 1959 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM, 1960 0, 0, rc.right, rc.bottom, flags); 1961 } 1962 else 1963 { 1964 /* Resize the height; if opened as read-only, checkbox and help button are 1965 * hidden and we are not using a custom template nor a customDialog 1966 */ 1967 if (filedialog_is_readonly_hidden(fodInfos) && 1968 (!(fodInfos->ofnInfos->Flags & 1969 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE)))) 1970 { 1971 RECT rectDlg, rectHelp, rectCancel; 1972 GetWindowRect(hwnd, &rectDlg); 1973 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp); 1974 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel); 1975 /* subtract the height of the help button plus the space between the help 1976 * button and the cancel button to the height of the dialog 1977 */ 1978 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left, 1979 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom), 1980 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); 1981 } 1982 } 1983 return TRUE; 1984 } 1985 1986 /*********************************************************************** 1987 * FILEDLG95_FillControls 1988 * 1989 * WM_INITDIALOG message handler (after hook notification) 1990 */ 1991 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam) 1992 { 1993 LPITEMIDLIST pidlItemId = NULL; 1994 1995 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam; 1996 1997 TRACE("dir=%s file=%s\n", 1998 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename)); 1999 2000 /* Get the initial directory pidl */ 2001 2002 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir))) 2003 { 2004 WCHAR path[MAX_PATH]; 2005 2006 GetCurrentDirectoryW(MAX_PATH,path); 2007 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path); 2008 } 2009 2010 /* Initialise shell objects */ 2011 FILEDLG95_SHELL_Init(hwnd); 2012 2013 /* Initialize the Look In combo box */ 2014 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB); 2015 2016 /* Browse to the initial directory */ 2017 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE); 2018 2019 ILFree(pidlItemId); 2020 2021 return TRUE; 2022 } 2023 /*********************************************************************** 2024 * FILEDLG95_Clean 2025 * 2026 * Regroups all the cleaning functions of the filedlg 2027 */ 2028 void FILEDLG95_Clean(HWND hwnd) 2029 { 2030 FILEDLG95_FILETYPE_Clean(hwnd); 2031 FILEDLG95_LOOKIN_Clean(hwnd); 2032 FILEDLG95_SHELL_Clean(hwnd); 2033 } 2034 2035 2036 /*********************************************************************** 2037 * Browse to arbitrary pidl 2038 */ 2039 static void filedlg_browse_to_pidl(const FileOpenDlgInfos *info, LPITEMIDLIST pidl) 2040 { 2041 TRACE("%p, %p\n", info->ShellInfos.hwndOwner, pidl); 2042 2043 IShellBrowser_BrowseObject(info->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE); 2044 if (info->ofnInfos->Flags & OFN_EXPLORER) 2045 SendCustomDlgNotificationMessage(info->ShellInfos.hwndOwner, CDN_FOLDERCHANGE); 2046 } 2047 2048 /*********************************************************************** 2049 * FILEDLG95_OnWMCommand 2050 * 2051 * WM_COMMAND message handler 2052 */ 2053 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam) 2054 { 2055 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 2056 WORD wNotifyCode = HIWORD(wParam); /* notification code */ 2057 WORD id = LOWORD(wParam); /* item, control, or accelerator identifier */ 2058 2059 switch (id) 2060 { 2061 /* OK button */ 2062 case IDOK: 2063 FILEDLG95_OnOpen(hwnd); 2064 break; 2065 /* Cancel button */ 2066 case IDCANCEL: 2067 FILEDLG95_Clean(hwnd); 2068 EndDialog(hwnd, FALSE); 2069 break; 2070 /* Filetype combo box */ 2071 case IDC_FILETYPE: 2072 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode); 2073 break; 2074 /* LookIn combo box */ 2075 case IDC_LOOKIN: 2076 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode); 2077 break; 2078 2079 /* --- toolbar --- */ 2080 /* Up folder button */ 2081 case FCIDM_TB_UPFOLDER: 2082 FILEDLG95_SHELL_UpFolder(hwnd); 2083 break; 2084 /* New folder button */ 2085 case FCIDM_TB_NEWFOLDER: 2086 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA); 2087 break; 2088 /* List option button */ 2089 case FCIDM_TB_SMALLICON: 2090 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA); 2091 break; 2092 /* Details option button */ 2093 case FCIDM_TB_REPORTVIEW: 2094 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA); 2095 break; 2096 2097 case FCIDM_TB_DESKTOP: 2098 { 2099 LPITEMIDLIST pidl; 2100 2101 SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidl); 2102 filedlg_browse_to_pidl(fodInfos, pidl); 2103 ILFree(pidl); 2104 break; 2105 } 2106 2107 /* Places bar */ 2108 case TBPLACES_CMDID_PLACE0: 2109 case TBPLACES_CMDID_PLACE1: 2110 case TBPLACES_CMDID_PLACE2: 2111 case TBPLACES_CMDID_PLACE3: 2112 case TBPLACES_CMDID_PLACE4: 2113 filedlg_browse_to_pidl(fodInfos, fodInfos->places[id - TBPLACES_CMDID_PLACE0]); 2114 break; 2115 2116 case edt1: 2117 case cmb13: 2118 break; 2119 2120 } 2121 /* Do not use the listview selection anymore */ 2122 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW; 2123 return 0; 2124 } 2125 2126 /*********************************************************************** 2127 * FILEDLG95_OnWMGetIShellBrowser 2128 * 2129 * WM_GETISHELLBROWSER message handler 2130 */ 2131 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd) 2132 { 2133 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 2134 2135 TRACE("\n"); 2136 2137 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser); 2138 2139 return TRUE; 2140 } 2141 2142 2143 /*********************************************************************** 2144 * FILEDLG95_SendFileOK 2145 * 2146 * Sends the CDN_FILEOK notification if required 2147 * 2148 * RETURNS 2149 * TRUE if the dialog should close 2150 * FALSE if the dialog should not be closed 2151 */ 2152 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos ) 2153 { 2154 /* ask the hook if we can close */ 2155 if (is_dialog_hooked(fodInfos)) 2156 { 2157 LRESULT retval = 0; 2158 2159 TRACE("---\n"); 2160 /* First send CDN_FILEOK as MSDN doc says */ 2161 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 2162 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK); 2163 if( retval) 2164 { 2165 TRACE("canceled\n"); 2166 return FALSE; 2167 } 2168 2169 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */ 2170 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, 2171 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos); 2172 if( retval) 2173 { 2174 TRACE("canceled\n"); 2175 return FALSE; 2176 } 2177 } 2178 return TRUE; 2179 } 2180 2181 /*********************************************************************** 2182 * FILEDLG95_OnOpenMultipleFiles 2183 * 2184 * Handles the opening of multiple files. 2185 * 2186 * FIXME 2187 * check destination buffer size 2188 */ 2189 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed) 2190 { 2191 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 2192 WCHAR lpstrPathSpec[MAX_PATH] = {0}; 2193 UINT nCount, nSizePath; 2194 2195 TRACE("\n"); 2196 2197 if(fodInfos->unicode) 2198 { 2199 LPOPENFILENAMEW ofn = fodInfos->ofnInfos; 2200 ofn->lpstrFile[0] = '\0'; 2201 } 2202 else 2203 { 2204 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos; 2205 ofn->lpstrFile[0] = '\0'; 2206 } 2207 2208 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec ); 2209 2210 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) && 2211 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) && 2212 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) ) 2213 { 2214 LPWSTR lpstrTemp = lpstrFileList; 2215 2216 for ( nCount = 0; nCount < nFileCount; nCount++ ) 2217 { 2218 LPITEMIDLIST pidl; 2219 2220 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp); 2221 if (!pidl) 2222 { 2223 WCHAR lpstrNotFound[100]; 2224 WCHAR lpstrMsg[100]; 2225 WCHAR tmp[400]; 2226 static const WCHAR nl[] = {'\n',0}; 2227 2228 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100); 2229 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100); 2230 2231 lstrcpyW(tmp, lpstrTemp); 2232 lstrcatW(tmp, nl); 2233 lstrcatW(tmp, lpstrNotFound); 2234 lstrcatW(tmp, nl); 2235 lstrcatW(tmp, lpstrMsg); 2236 2237 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION); 2238 return FALSE; 2239 } 2240 2241 /* move to the next file in the list of files */ 2242 lpstrTemp += lstrlenW(lpstrTemp) + 1; 2243 ILFree(pidl); 2244 } 2245 } 2246 2247 nSizePath = lstrlenW(lpstrPathSpec) + 1; 2248 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) ) 2249 { 2250 /* For "oldstyle" dialog the components have to 2251 be separated by blanks (not '\0'!) and short 2252 filenames have to be used! */ 2253 FIXME("Components have to be separated by blanks\n"); 2254 } 2255 if(fodInfos->unicode) 2256 { 2257 LPOPENFILENAMEW ofn = fodInfos->ofnInfos; 2258 lstrcpyW( ofn->lpstrFile, lpstrPathSpec); 2259 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) ); 2260 } 2261 else 2262 { 2263 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; 2264 2265 if (ofn->lpstrFile != NULL) 2266 { 2267 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1, 2268 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL); 2269 if (ofn->nMaxFile > nSizePath) 2270 { 2271 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, 2272 ofn->lpstrFile + nSizePath, 2273 ofn->nMaxFile - nSizePath, NULL, NULL); 2274 } 2275 } 2276 } 2277 2278 fodInfos->ofnInfos->nFileOffset = nSizePath; 2279 fodInfos->ofnInfos->nFileExtension = 0; 2280 2281 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) ) 2282 return FALSE; 2283 2284 /* clean and exit */ 2285 FILEDLG95_Clean(hwnd); 2286 return EndDialog(hwnd,TRUE); 2287 } 2288 2289 /* Returns the 'slot name' of the given module_name in the registry's 2290 * most-recently-used list. This will be an ASCII value in the 2291 * range ['a','z'). Returns zero on error. 2292 * 2293 * The slot's value in the registry has the form: 2294 * module_name\0mru_path\0 2295 * 2296 * If stored_path is given, then stored_path will contain the path name 2297 * stored in the registry's MRU list for the given module_name. 2298 * 2299 * If hkey_ret is given, then hkey_ret will be a handle to the registry's 2300 * MRU list key for the given module_name. 2301 */ 2302 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret) 2303 { 2304 WCHAR mru_list[32], *cur_mru_slot; 2305 BOOL taken[25] = {0}; 2306 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i; 2307 HKEY hkey_tmp, *hkey; 2308 LONG ret; 2309 2310 if(hkey_ret) 2311 hkey = hkey_ret; 2312 else 2313 hkey = &hkey_tmp; 2314 2315 if(stored_path) 2316 *stored_path = '\0'; 2317 2318 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey); 2319 if(ret){ 2320 WARN("Unable to create MRU key: %d\n", ret); 2321 return 0; 2322 } 2323 2324 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type, 2325 (LPBYTE)mru_list, &mru_list_size); 2326 if(ret || key_type != REG_SZ){ 2327 if(ret == ERROR_FILE_NOT_FOUND) 2328 return 'a'; 2329 2330 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret); 2331 RegCloseKey(*hkey); 2332 return 0; 2333 } 2334 2335 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){ 2336 WCHAR value_data[MAX_PATH], value_name[2] = {0}; 2337 DWORD value_data_size = sizeof(value_data); 2338 2339 *value_name = *cur_mru_slot; 2340 2341 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY, 2342 &key_type, (LPBYTE)value_data, &value_data_size); 2343 if(ret || key_type != REG_BINARY){ 2344 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret); 2345 continue; 2346 } 2347 2348 if(!wcsicmp(module_name, value_data)){ 2349 if(!hkey_ret) 2350 RegCloseKey(*hkey); 2351 if(stored_path) 2352 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1); 2353 return *value_name; 2354 } 2355 } 2356 2357 if(!hkey_ret) 2358 RegCloseKey(*hkey); 2359 2360 /* the module name isn't in the registry, so find the next open slot */ 2361 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot) 2362 taken[*cur_mru_slot - 'a'] = TRUE; 2363 for(i = 0; i < 25; ++i){ 2364 if(!taken[i]) 2365 return i + 'a'; 2366 } 2367 2368 /* all slots are taken, so return the last one in MRUList */ 2369 --cur_mru_slot; 2370 return *cur_mru_slot; 2371 } 2372 2373 /* save the given filename as most-recently-used path for this module */ 2374 static void FILEDLG95_MRU_save_filename(LPCWSTR filename) 2375 { 2376 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0}; 2377 LONG ret; 2378 HKEY hkey; 2379 2380 /* get the current executable's name */ 2381 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path))) 2382 { 2383 WARN("GotModuleFileName failed: %d\n", GetLastError()); 2384 return; 2385 } 2386 module_name = wcsrchr(module_path, '\\'); 2387 if(!module_name) 2388 module_name = module_path; 2389 else 2390 module_name += 1; 2391 2392 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey); 2393 if(!slot) 2394 return; 2395 *slot_name = slot; 2396 2397 { /* update the slot's info */ 2398 WCHAR *path_ends, *final; 2399 DWORD path_len, final_len; 2400 2401 /* use only the path segment of `filename' */ 2402 path_ends = wcsrchr(filename, '\\'); 2403 path_len = path_ends - filename; 2404 2405 final_len = path_len + lstrlenW(module_name) + 2; 2406 2407 final = heap_alloc(final_len * sizeof(WCHAR)); 2408 if(!final) 2409 return; 2410 lstrcpyW(final, module_name); 2411 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR)); 2412 final[final_len-1] = '\0'; 2413 2414 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final, 2415 final_len * sizeof(WCHAR)); 2416 if(ret){ 2417 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret); 2418 heap_free(final); 2419 RegCloseKey(hkey); 2420 return; 2421 } 2422 2423 heap_free(final); 2424 } 2425 2426 { /* update MRUList value */ 2427 WCHAR old_mru_list[32], new_mru_list[32]; 2428 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list; 2429 DWORD mru_list_size = sizeof(old_mru_list), key_type; 2430 2431 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type, 2432 (LPBYTE)old_mru_list, &mru_list_size); 2433 if(ret || key_type != REG_SZ){ 2434 if(ret == ERROR_FILE_NOT_FOUND){ 2435 new_mru_list[0] = slot; 2436 new_mru_list[1] = '\0'; 2437 }else{ 2438 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret); 2439 RegCloseKey(hkey); 2440 return; 2441 } 2442 }else{ 2443 /* copy old list data over so that the new slot is at the start 2444 * of the list */ 2445 *new_mru_slot++ = slot; 2446 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){ 2447 if(*old_mru_slot != slot) 2448 *new_mru_slot++ = *old_mru_slot; 2449 } 2450 *new_mru_slot = '\0'; 2451 } 2452 2453 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list, 2454 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR)); 2455 if(ret){ 2456 WARN("Error saving MRUList data: %d\n", ret); 2457 RegCloseKey(hkey); 2458 return; 2459 } 2460 } 2461 } 2462 2463 /* load the most-recently-used path for this module */ 2464 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path) 2465 { 2466 WCHAR module_path[MAX_PATH], *module_name; 2467 2468 /* get the current executable's name */ 2469 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path))) 2470 { 2471 WARN("GotModuleFileName failed: %d\n", GetLastError()); 2472 return; 2473 } 2474 module_name = wcsrchr(module_path, '\\'); 2475 if(!module_name) 2476 module_name = module_path; 2477 else 2478 module_name += 1; 2479 2480 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL); 2481 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path)); 2482 } 2483 #ifdef __REACTOS__ 2484 2485 static const WCHAR s_subkey[] = 2486 { 2487 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', 2488 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s', 2489 'i','o','n','\\','E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g', 2490 '3','2','\\','O','p','e','n','S','a','v','e','M','R','U',0 2491 }; 2492 static const WCHAR s_szAst[] = { '*', 0 }; 2493 2494 typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs); 2495 typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length); 2496 2497 /* https://docs.microsoft.com/en-us/windows/desktop/shell/mruinfo */ 2498 typedef struct tagMRUINFOW 2499 { 2500 DWORD cbSize; 2501 UINT uMax; 2502 UINT fFlags; 2503 HKEY hKey; 2504 LPCWSTR lpszSubKey; 2505 union 2506 { 2507 MRUStringCmpFnW string_cmpfn; 2508 MRUBinaryCmpFn binary_cmpfn; 2509 } u; 2510 } MRUINFOW, *LPMRUINFOW; 2511 2512 /* flags for MRUINFOW.fFlags */ 2513 #define MRU_STRING 0x0000 2514 #define MRU_BINARY 0x0001 2515 #define MRU_CACHEWRITE 0x0002 2516 2517 static HINSTANCE s_hComCtl32 = NULL; 2518 2519 /* comctl32.400: CreateMRUListW */ 2520 typedef HANDLE (WINAPI *CREATEMRULISTW)(const MRUINFOW *); 2521 static CREATEMRULISTW s_pCreateMRUListW = NULL; 2522 2523 /* comctl32.401: AddMRUStringW */ 2524 typedef INT (WINAPI *ADDMRUSTRINGW)(HANDLE, LPCWSTR); 2525 static ADDMRUSTRINGW s_pAddMRUStringW = NULL; 2526 2527 /* comctl32.402: FindMRUStringW */ 2528 typedef INT (WINAPI *FINDMRUSTRINGW)(HANDLE, LPCWSTR, LPINT); 2529 static FINDMRUSTRINGW s_pFindMRUStringW = NULL; 2530 2531 /* comctl32.403: EnumMRUListW */ 2532 typedef INT (WINAPI *ENUMMRULISTW)(HANDLE, INT, LPVOID, DWORD); 2533 static ENUMMRULISTW s_pEnumMRUListW = NULL; 2534 2535 /* comctl32.152: FreeMRUList */ 2536 typedef void (WINAPI *FREEMRULIST)(HANDLE); 2537 static FREEMRULIST s_pFreeMRUList = NULL; 2538 2539 static BOOL FILEDLG_InitMRUList(void) 2540 { 2541 if (s_hComCtl32) 2542 return TRUE; 2543 2544 s_hComCtl32 = GetModuleHandleA("comctl32"); 2545 if (!s_hComCtl32) 2546 return FALSE; 2547 2548 s_pCreateMRUListW = (CREATEMRULISTW)GetProcAddress(s_hComCtl32, (LPCSTR)400); 2549 s_pAddMRUStringW = (ADDMRUSTRINGW)GetProcAddress(s_hComCtl32, (LPCSTR)401); 2550 s_pFindMRUStringW = (FINDMRUSTRINGW)GetProcAddress(s_hComCtl32, (LPCSTR)402); 2551 s_pEnumMRUListW = (ENUMMRULISTW)GetProcAddress(s_hComCtl32, (LPCSTR)403); 2552 s_pFreeMRUList = (FREEMRULIST)GetProcAddress(s_hComCtl32, (LPCSTR)152); 2553 if (!s_pCreateMRUListW || 2554 !s_pAddMRUStringW || 2555 !s_pFindMRUStringW || 2556 !s_pEnumMRUListW || 2557 !s_pFreeMRUList) 2558 { 2559 s_hComCtl32 = NULL; 2560 return FALSE; 2561 } 2562 2563 return TRUE; 2564 } 2565 2566 static BOOL ExtIsPicture(LPCWSTR ext) 2567 { 2568 static const WCHAR s_image_exts[][6] = 2569 { 2570 { 'b','m','p',0 }, 2571 { 'd','i','b',0 }, 2572 { 'j','p','g',0 }, 2573 { 'j','p','e','g',0 }, 2574 { 'j','p','e',0 }, 2575 { 'j','f','i','f',0 }, 2576 { 'p','n','g',0 }, 2577 { 'g','i','f',0 }, 2578 { 't','i','f',0 }, 2579 { 't','i','f','f',0 } 2580 }; 2581 size_t i; 2582 2583 for (i = 0; i < ARRAY_SIZE(s_image_exts); ++i) 2584 { 2585 if (lstrcmpiW(ext, s_image_exts[i]) == 0) 2586 { 2587 return TRUE; 2588 } 2589 } 2590 return FALSE; 2591 } 2592 2593 static void FILEDLG95_MRU_load_ext(LPWSTR stored_path, size_t cchMax, LPCWSTR defext) 2594 { 2595 HKEY hOpenSaveMRT = NULL; 2596 LONG result; 2597 MRUINFOW mi; 2598 HANDLE hList; 2599 WCHAR szText[MAX_PATH]; 2600 INT ret = 0; 2601 2602 stored_path[0] = 0; 2603 2604 if (!defext || !*defext || !FILEDLG_InitMRUList()) 2605 { 2606 return; 2607 } 2608 2609 if (*defext == '.') 2610 ++defext; 2611 2612 result = RegOpenKeyW(HKEY_CURRENT_USER, s_subkey, &hOpenSaveMRT); 2613 if (!result && hOpenSaveMRT) 2614 { 2615 ZeroMemory(&mi, sizeof(mi)); 2616 mi.cbSize = sizeof(mi); 2617 mi.uMax = 26; 2618 mi.fFlags = MRU_STRING; 2619 mi.hKey = hOpenSaveMRT; 2620 mi.lpszSubKey = defext; 2621 mi.u.string_cmpfn = lstrcmpiW; 2622 hList = (*s_pCreateMRUListW)(&mi); 2623 if (hList) 2624 { 2625 ret = (*s_pEnumMRUListW)(hList, 0, szText, sizeof(szText)); 2626 if (ret > 0) 2627 { 2628 lstrcpynW(stored_path, szText, cchMax); 2629 PathRemoveFileSpecW(stored_path); 2630 } 2631 (*s_pFreeMRUList)(hList); 2632 } 2633 2634 RegCloseKey(hOpenSaveMRT); 2635 } 2636 2637 if (stored_path[0] == 0) 2638 { 2639 LPITEMIDLIST pidl; 2640 if (ExtIsPicture(defext)) 2641 { 2642 SHGetSpecialFolderLocation(NULL, CSIDL_MYPICTURES, &pidl); 2643 } 2644 else 2645 { 2646 SHGetSpecialFolderLocation(NULL, CSIDL_MYDOCUMENTS, &pidl); 2647 } 2648 SHGetPathFromIDListW(pidl, stored_path); 2649 ILFree(pidl); 2650 } 2651 } 2652 2653 static void FILEDLG95_MRU_save_ext(LPCWSTR filename) 2654 { 2655 HKEY hOpenSaveMRT = NULL; 2656 LONG result; 2657 MRUINFOW mi; 2658 HANDLE hList; 2659 LPCWSTR defext = PathFindExtensionW(filename); 2660 2661 if (!defext || !*defext || !FILEDLG_InitMRUList()) 2662 { 2663 return; 2664 } 2665 2666 if (*defext == '.') 2667 ++defext; 2668 2669 result = RegOpenKeyW(HKEY_CURRENT_USER, s_subkey, &hOpenSaveMRT); 2670 if (!result && hOpenSaveMRT) 2671 { 2672 ZeroMemory(&mi, sizeof(mi)); 2673 mi.cbSize = sizeof(mi); 2674 mi.uMax = 26; 2675 mi.fFlags = MRU_STRING; 2676 mi.hKey = hOpenSaveMRT; 2677 mi.lpszSubKey = defext; 2678 mi.u.string_cmpfn = lstrcmpiW; 2679 hList = (*s_pCreateMRUListW)(&mi); 2680 if (hList) 2681 { 2682 (*s_pAddMRUStringW)(hList, filename); 2683 (*s_pFreeMRUList)(hList); 2684 } 2685 2686 mi.cbSize = sizeof(mi); 2687 mi.uMax = 26; 2688 mi.fFlags = MRU_STRING; 2689 mi.hKey = hOpenSaveMRT; 2690 mi.lpszSubKey = s_szAst; 2691 mi.u.string_cmpfn = lstrcmpiW; 2692 hList = (*s_pCreateMRUListW)(&mi); 2693 if (hList) 2694 { 2695 (*s_pAddMRUStringW)(hList, filename); 2696 (*s_pFreeMRUList)(hList); 2697 } 2698 2699 RegCloseKey(hOpenSaveMRT); 2700 } 2701 } 2702 2703 #endif /* __REACTOS__ */ 2704 2705 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText) 2706 { 2707 WCHAR strMsgTitle[MAX_PATH]; 2708 WCHAR strMsgText [MAX_PATH]; 2709 if (idCaption) 2710 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, ARRAY_SIZE(strMsgTitle)); 2711 else 2712 strMsgTitle[0] = '\0'; 2713 LoadStringW(COMDLG32_hInstance, idText, strMsgText, ARRAY_SIZE(strMsgText)); 2714 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND); 2715 } 2716 2717 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf, 2718 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction) 2719 { 2720 int nOpenAction = defAction; 2721 LPWSTR lpszTemp, lpszTemp1; 2722 LPITEMIDLIST pidl = NULL; 2723 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0}; 2724 2725 /* check for invalid chars */ 2726 if((wcspbrk(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE)) 2727 { 2728 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME); 2729 return FALSE; 2730 } 2731 2732 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE; 2733 2734 lpszTemp1 = lpszTemp = lpstrPathAndFile; 2735 while (lpszTemp1) 2736 { 2737 LPSHELLFOLDER lpsfChild; 2738 WCHAR lpwstrTemp[MAX_PATH]; 2739 DWORD dwEaten, dwAttributes; 2740 LPWSTR p; 2741 2742 lstrcpyW(lpwstrTemp, lpszTemp); 2743 p = PathFindNextComponentW(lpwstrTemp); 2744 2745 if (!p) break; /* end of path */ 2746 2747 *p = 0; 2748 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp); 2749 2750 /* There are no wildcards when OFN_NOVALIDATE is set */ 2751 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE)) 2752 { 2753 static const WCHAR wszWild[] = { '*', '?', 0 }; 2754 /* if the last element is a wildcard do a search */ 2755 if(wcspbrk(lpszTemp1, wszWild) != NULL) 2756 { 2757 nOpenAction = ONOPEN_SEARCH; 2758 break; 2759 } 2760 } 2761 lpszTemp1 = lpszTemp; 2762 2763 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf); 2764 2765 /* append a backslash to drive letters */ 2766 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' && 2767 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') || 2768 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z'))) 2769 { 2770 PathAddBackslashW(lpwstrTemp); 2771 } 2772 2773 dwAttributes = SFGAO_FOLDER; 2774 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes))) 2775 { 2776 /* the path component is valid, we have a pidl of the next path component */ 2777 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl); 2778 if(dwAttributes & SFGAO_FOLDER) 2779 { 2780 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild))) 2781 { 2782 ERR("bind to failed\n"); /* should not fail */ 2783 break; 2784 } 2785 IShellFolder_Release(*ppsf); 2786 *ppsf = lpsfChild; 2787 lpsfChild = NULL; 2788 } 2789 else 2790 { 2791 TRACE("value\n"); 2792 2793 /* end dialog, return value */ 2794 nOpenAction = ONOPEN_OPEN; 2795 break; 2796 } 2797 ILFree(pidl); 2798 pidl = NULL; 2799 } 2800 else if (!(flags & OFN_NOVALIDATE)) 2801 { 2802 if(*lpszTemp || /* points to trailing null for last path element */ 2803 (lpwstrTemp[lstrlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */ 2804 { 2805 if(flags & OFN_PATHMUSTEXIST) 2806 { 2807 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING); 2808 break; 2809 } 2810 } 2811 else 2812 { 2813 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg ) 2814 { 2815 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING); 2816 break; 2817 } 2818 } 2819 /* change to the current folder */ 2820 nOpenAction = ONOPEN_OPEN; 2821 break; 2822 } 2823 else 2824 { 2825 nOpenAction = ONOPEN_OPEN; 2826 break; 2827 } 2828 } 2829 ILFree(pidl); 2830 2831 return nOpenAction; 2832 } 2833 2834 /*********************************************************************** 2835 * FILEDLG95_OnOpen 2836 * 2837 * Ok button WM_COMMAND message handler 2838 * 2839 * If the function succeeds, the return value is nonzero. 2840 */ 2841 BOOL FILEDLG95_OnOpen(HWND hwnd) 2842 { 2843 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 2844 LPWSTR lpstrFileList; 2845 UINT nFileCount = 0; 2846 UINT sizeUsed = 0; 2847 BOOL ret = TRUE; 2848 WCHAR lpstrPathAndFile[MAX_PATH]; 2849 LPSHELLFOLDER lpsf = NULL; 2850 int nOpenAction; 2851 2852 TRACE("hwnd=%p\n", hwnd); 2853 2854 /* try to browse the selected item */ 2855 if(BrowseSelectedFolder(hwnd)) 2856 return FALSE; 2857 2858 /* get the files from the edit control */ 2859 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed); 2860 2861 if(nFileCount == 0) 2862 return FALSE; 2863 2864 if(nFileCount > 1) 2865 { 2866 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed); 2867 goto ret; 2868 } 2869 2870 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList)); 2871 2872 /* 2873 Step 1: Build a complete path name from the current folder and 2874 the filename or path in the edit box. 2875 Special cases: 2876 - the path in the edit box is a root path 2877 (with or without drive letter) 2878 - the edit box contains ".." (or a path with ".." in it) 2879 */ 2880 2881 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile); 2882 heap_free(lpstrFileList); 2883 2884 /* 2885 Step 2: here we have a cleaned up path 2886 2887 We have to parse the path step by step to see if we have to browse 2888 to a folder if the path points to a directory or the last 2889 valid element is a directory. 2890 2891 valid variables: 2892 lpstrPathAndFile: cleaned up path 2893 */ 2894 2895 if (nFileCount && 2896 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) && 2897 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST)) 2898 nOpenAction = ONOPEN_OPEN; 2899 else 2900 nOpenAction = ONOPEN_BROWSE; 2901 2902 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd, 2903 fodInfos->ofnInfos->Flags, 2904 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG, 2905 nOpenAction); 2906 if(!nOpenAction) 2907 goto ret; 2908 2909 /* 2910 Step 3: here we have a cleaned up and validated path 2911 2912 valid variables: 2913 lpsf: ShellFolder bound to the rightmost valid path component 2914 lpstrPathAndFile: cleaned up path 2915 nOpenAction: action to do 2916 */ 2917 TRACE("end validate sf=%p\n", lpsf); 2918 2919 switch(nOpenAction) 2920 { 2921 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */ 2922 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile)); 2923 { 2924 int iPos; 2925 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile); 2926 DWORD len; 2927 2928 /* replace the current filter */ 2929 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter); 2930 len = lstrlenW(lpszTemp)+1; 2931 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc(len * sizeof(WCHAR)); 2932 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp); 2933 2934 /* set the filter cb to the extension when possible */ 2935 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp))) 2936 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, iPos, 0); 2937 } 2938 /* fall through */ 2939 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */ 2940 TRACE("ONOPEN_BROWSE\n"); 2941 { 2942 IPersistFolder2 * ppf2; 2943 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2))) 2944 { 2945 LPITEMIDLIST pidlCurrent; 2946 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent); 2947 IPersistFolder2_Release(ppf2); 2948 if (!ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent)) 2949 { 2950 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)) 2951 && fodInfos->ofnInfos->Flags & OFN_EXPLORER) 2952 { 2953 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); 2954 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)""); 2955 } 2956 } 2957 else if( nOpenAction == ONOPEN_SEARCH ) 2958 { 2959 if (fodInfos->Shell.FOIShellView) 2960 IShellView_Refresh(fodInfos->Shell.FOIShellView); 2961 } 2962 ILFree(pidlCurrent); 2963 if (filename_is_edit( fodInfos )) 2964 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1); 2965 else 2966 { 2967 HWND hwnd; 2968 2969 hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0); 2970 SendMessageW(hwnd, EM_SETSEL, 0, -1); 2971 } 2972 } 2973 } 2974 ret = FALSE; 2975 break; 2976 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */ 2977 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile)); 2978 { 2979 WCHAR *ext = NULL; 2980 2981 /* update READONLY check box flag */ 2982 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED) 2983 fodInfos->ofnInfos->Flags |= OFN_READONLY; 2984 else 2985 fodInfos->ofnInfos->Flags &= ~OFN_READONLY; 2986 2987 /* Attach the file extension with file name*/ 2988 ext = PathFindExtensionW(lpstrPathAndFile); 2989 #ifdef __REACTOS__ 2990 { 2991 LPWSTR filterExt = NULL, lpstrFilter = NULL, pch, pchNext; 2992 LPCWSTR the_ext = NULL; 2993 static const WCHAR szwDot[] = {'.',0}; 2994 int PathLength = lstrlenW(lpstrPathAndFile); 2995 2996 /* get filter extensions */ 2997 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 2998 fodInfos->ofnInfos->nFilterIndex - 1); 2999 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */ 3000 { 3001 LPWSTR filterSearchIndex, pchFirst = NULL; 3002 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR)); 3003 if (filterExt) 3004 { 3005 strcpyW(filterExt, lpstrFilter); 3006 3007 if (ext && *ext) 3008 { 3009 /* find ext in filter */ 3010 for (pch = filterExt; pch && *pch; pch = pchNext) 3011 { 3012 filterSearchIndex = strchrW(pch, ';'); 3013 if (filterSearchIndex) 3014 { 3015 filterSearchIndex[0] = 0; 3016 pchNext = filterSearchIndex + 1; 3017 } 3018 else 3019 { 3020 pchNext = NULL; 3021 } 3022 3023 while (*pch == '*' || *pch == '.' || *pch == '?') 3024 { 3025 ++pch; 3026 } 3027 3028 if (!pchFirst) 3029 pchFirst = pch; 3030 3031 if (lstrcmpiW(pch, &ext[1]) == 0) 3032 { 3033 the_ext = pch; 3034 break; 3035 } 3036 } 3037 3038 /* use first one if not found */ 3039 if (!the_ext && pchFirst && *pchFirst) 3040 { 3041 the_ext = pchFirst; 3042 } 3043 } 3044 } 3045 } 3046 3047 if (!the_ext) 3048 { 3049 /* use default extension if no extension in filter */ 3050 the_ext = fodInfos->defext; 3051 } 3052 3053 if (the_ext && *the_ext && lstrcmpiW(&ext[1], the_ext) != 0) 3054 { 3055 if (strlenW(lpstrPathAndFile) + 1 + strlenW(the_ext) + 1 <= 3056 fodInfos->ofnInfos->nMaxFile) 3057 { 3058 /* append the dot */ 3059 lstrcatW(lpstrPathAndFile, szwDot); 3060 /* append the extension */ 3061 lstrcatW(lpstrPathAndFile, the_ext); 3062 /* update ext */ 3063 ext = PathFindExtensionW(lpstrPathAndFile); 3064 } 3065 } 3066 3067 heap_free(filterExt); 3068 3069 /* In Open dialog: if file does not exist try without extension */ 3070 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile)) 3071 lpstrPathAndFile[PathLength] = 0; 3072 3073 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */ 3074 if (*ext) 3075 ext++; 3076 if (!lstrcmpiW(fodInfos->defext, ext)) 3077 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT; 3078 else 3079 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT; 3080 } 3081 3082 /* update dialog data */ 3083 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, PathFindFileNameW(lpstrPathAndFile)); 3084 #else /* __REACTOS__ */ 3085 if (! *ext && fodInfos->defext) 3086 { 3087 /* if no extension is specified with file name, then */ 3088 /* attach the extension from file filter or default one */ 3089 3090 WCHAR *filterExt = NULL; 3091 LPWSTR lpstrFilter = NULL; 3092 static const WCHAR szwDot[] = {'.',0}; 3093 int PathLength = lstrlenW(lpstrPathAndFile); 3094 3095 /*Get the file extension from file type filter*/ 3096 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3097 fodInfos->ofnInfos->nFilterIndex-1); 3098 3099 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */ 3100 { 3101 WCHAR* filterSearchIndex; 3102 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR)); 3103 lstrcpyW(filterExt, lpstrFilter); 3104 3105 /* if a semicolon-separated list of file extensions was given, do not include the 3106 semicolon or anything after it in the extension. 3107 example: if filterExt was "*.abc;*.def", it will become "*.abc" */ 3108 filterSearchIndex = wcschr(filterExt, ';'); 3109 if (filterSearchIndex) 3110 { 3111 filterSearchIndex[0] = '\0'; 3112 } 3113 3114 /* find the file extension by searching for the first dot in filterExt */ 3115 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */ 3116 /* if the extension is invalid or contains a glob, ignore it */ 3117 filterSearchIndex = wcschr(filterExt, '.'); 3118 if (filterSearchIndex++ && !wcschr(filterSearchIndex, '*') && !wcschr(filterSearchIndex, '?')) 3119 { 3120 lstrcpyW(filterExt, filterSearchIndex); 3121 } 3122 else 3123 { 3124 heap_free(filterExt); 3125 filterExt = NULL; 3126 } 3127 } 3128 3129 if (!filterExt) 3130 { 3131 /* use the default file extension */ 3132 filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR)); 3133 lstrcpyW(filterExt, fodInfos->defext); 3134 } 3135 3136 if (*filterExt) /* ignore filterExt="" */ 3137 { 3138 /* Attach the dot*/ 3139 lstrcatW(lpstrPathAndFile, szwDot); 3140 /* Attach the extension */ 3141 lstrcatW(lpstrPathAndFile, filterExt); 3142 } 3143 3144 heap_free(filterExt); 3145 3146 /* In Open dialog: if file does not exist try without extension */ 3147 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile)) 3148 lpstrPathAndFile[PathLength] = '\0'; 3149 3150 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */ 3151 if (*ext) 3152 ext++; 3153 if (!lstrcmpiW(fodInfos->defext, ext)) 3154 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT; 3155 else 3156 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT; 3157 } 3158 #endif /* __REACTOS__ */ 3159 3160 /* In Save dialog: check if the file already exists */ 3161 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG 3162 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT 3163 && PathFileExistsW(lpstrPathAndFile)) 3164 { 3165 WCHAR lpstrOverwrite[100]; 3166 int answer; 3167 3168 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100); 3169 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title, 3170 MB_YESNO | MB_ICONEXCLAMATION); 3171 if (answer == IDNO || answer == IDCANCEL) 3172 { 3173 ret = FALSE; 3174 goto ret; 3175 } 3176 } 3177 3178 /* In Open dialog: check if it should be created if it doesn't exist */ 3179 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) 3180 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT 3181 && !PathFileExistsW(lpstrPathAndFile)) 3182 { 3183 WCHAR lpstrCreate[100]; 3184 int answer; 3185 3186 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100); 3187 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title, 3188 MB_YESNO | MB_ICONEXCLAMATION); 3189 if (answer == IDNO || answer == IDCANCEL) 3190 { 3191 ret = FALSE; 3192 goto ret; 3193 } 3194 } 3195 3196 /* Check that the size of the file does not exceed buffer size. 3197 (Allow for extra \0 if OFN_MULTISELECT is set.) */ 3198 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile - 3199 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0)) 3200 { 3201 3202 /* fill destination buffer */ 3203 if (fodInfos->ofnInfos->lpstrFile) 3204 { 3205 if(fodInfos->unicode) 3206 { 3207 LPOPENFILENAMEW ofn = fodInfos->ofnInfos; 3208 3209 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile); 3210 if (ofn->Flags & OFN_ALLOWMULTISELECT) 3211 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0'; 3212 } 3213 else 3214 { 3215 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; 3216 3217 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1, 3218 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL); 3219 if (ofn->Flags & OFN_ALLOWMULTISELECT) 3220 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0'; 3221 } 3222 } 3223 3224 if(fodInfos->unicode) 3225 { 3226 LPWSTR lpszTemp; 3227 3228 /* set filename offset */ 3229 lpszTemp = PathFindFileNameW(lpstrPathAndFile); 3230 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile); 3231 3232 /* set extension offset */ 3233 lpszTemp = PathFindExtensionW(lpstrPathAndFile); 3234 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0; 3235 } 3236 else 3237 { 3238 LPSTR lpszTemp; 3239 CHAR tempFileA[MAX_PATH]; 3240 3241 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */ 3242 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1, 3243 tempFileA, sizeof(tempFileA), NULL, NULL); 3244 3245 /* set filename offset */ 3246 lpszTemp = PathFindFileNameA(tempFileA); 3247 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA); 3248 3249 /* set extension offset */ 3250 lpszTemp = PathFindExtensionA(tempFileA); 3251 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0; 3252 } 3253 3254 /* copy currently selected filter to lpstrCustomFilter */ 3255 if (fodInfos->ofnInfos->lpstrCustomFilter) 3256 { 3257 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; 3258 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1, 3259 NULL, 0, NULL, NULL); 3260 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter) 3261 { 3262 LPSTR s = ofn->lpstrCustomFilter; 3263 s += strlen(ofn->lpstrCustomFilter)+1; 3264 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1, 3265 s, len, NULL, NULL); 3266 } 3267 } 3268 3269 3270 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) ) 3271 goto ret; 3272 3273 FILEDLG95_MRU_save_filename(lpstrPathAndFile); 3274 #ifdef __REACTOS__ 3275 FILEDLG95_MRU_save_ext(lpstrPathAndFile); 3276 #endif 3277 3278 TRACE("close\n"); 3279 FILEDLG95_Clean(hwnd); 3280 ret = EndDialog(hwnd, TRUE); 3281 } 3282 else 3283 { 3284 WORD size; 3285 3286 size = lstrlenW(lpstrPathAndFile) + 1; 3287 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) 3288 size += 1; 3289 /* return needed size in first two bytes of lpstrFile */ 3290 if(fodInfos->ofnInfos->lpstrFile) 3291 *(WORD *)fodInfos->ofnInfos->lpstrFile = size; 3292 FILEDLG95_Clean(hwnd); 3293 ret = EndDialog(hwnd, FALSE); 3294 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL); 3295 } 3296 } 3297 break; 3298 } 3299 3300 ret: 3301 if(lpsf) IShellFolder_Release(lpsf); 3302 return ret; 3303 } 3304 3305 /*********************************************************************** 3306 * FILEDLG95_SHELL_Init 3307 * 3308 * Initialisation of the shell objects 3309 */ 3310 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd) 3311 { 3312 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3313 3314 TRACE("%p\n", hwnd); 3315 3316 /* 3317 * Initialisation of the FileOpenDialogInfos structure 3318 */ 3319 3320 /* Shell */ 3321 3322 /*ShellInfos */ 3323 fodInfos->ShellInfos.hwndOwner = hwnd; 3324 3325 /* Disable multi-select if flag not set */ 3326 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)) 3327 { 3328 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL; 3329 } 3330 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT; 3331 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST; 3332 3333 /* Construct the IShellBrowser interface */ 3334 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd); 3335 3336 return NOERROR; 3337 } 3338 3339 /*********************************************************************** 3340 * FILEDLG95_SHELL_ExecuteCommand 3341 * 3342 * Change the folder option and refresh the view 3343 * If the function succeeds, the return value is nonzero. 3344 */ 3345 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb) 3346 { 3347 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3348 IContextMenu * pcm; 3349 3350 TRACE("(%p,%p)\n", hwnd, lpVerb); 3351 3352 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView, 3353 SVGIO_BACKGROUND, 3354 &IID_IContextMenu, 3355 (LPVOID*)&pcm))) 3356 { 3357 CMINVOKECOMMANDINFO ci; 3358 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO)); 3359 ci.cbSize = sizeof(CMINVOKECOMMANDINFO); 3360 ci.lpVerb = lpVerb; 3361 ci.hwnd = hwnd; 3362 3363 IContextMenu_InvokeCommand(pcm, &ci); 3364 IContextMenu_Release(pcm); 3365 } 3366 3367 return FALSE; 3368 } 3369 3370 /*********************************************************************** 3371 * FILEDLG95_SHELL_UpFolder 3372 * 3373 * Browse to the specified object 3374 * If the function succeeds, the return value is nonzero. 3375 */ 3376 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd) 3377 { 3378 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3379 3380 TRACE("\n"); 3381 3382 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, 3383 NULL, 3384 SBSP_PARENT))) 3385 { 3386 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 3387 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); 3388 return TRUE; 3389 } 3390 return FALSE; 3391 } 3392 /*********************************************************************** 3393 * FILEDLG95_SHELL_Clean 3394 * 3395 * Cleans the memory used by shell objects 3396 */ 3397 static void FILEDLG95_SHELL_Clean(HWND hwnd) 3398 { 3399 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3400 3401 TRACE("\n"); 3402 3403 ILFree(fodInfos->ShellInfos.pidlAbsCurrent); 3404 3405 /* clean Shell interfaces */ 3406 if (fodInfos->Shell.FOIShellView) 3407 { 3408 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView); 3409 IShellView_Release(fodInfos->Shell.FOIShellView); 3410 } 3411 if (fodInfos->Shell.FOIShellFolder) 3412 IShellFolder_Release(fodInfos->Shell.FOIShellFolder); 3413 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser); 3414 if (fodInfos->Shell.FOIDataObject) 3415 IDataObject_Release(fodInfos->Shell.FOIDataObject); 3416 } 3417 3418 /*********************************************************************** 3419 * FILEDLG95_FILETYPE_Init 3420 * 3421 * Initialisation of the file type combo box 3422 */ 3423 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd) 3424 { 3425 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3426 int nFilters = 0; /* number of filters */ 3427 int nFilterIndexCB; 3428 3429 TRACE("%p\n", hwnd); 3430 3431 if(fodInfos->customfilter) 3432 { 3433 /* customfilter has one entry... title\0ext\0 3434 * Set first entry of combo box item with customfilter 3435 */ 3436 LPWSTR lpstrExt; 3437 LPCWSTR lpstrPos = fodInfos->customfilter; 3438 3439 /* Get the title */ 3440 lpstrPos += lstrlenW(fodInfos->customfilter) + 1; 3441 3442 /* Copy the extensions */ 3443 if (! *lpstrPos) return E_FAIL; /* malformed filter */ 3444 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL; 3445 lstrcpyW(lpstrExt,lpstrPos); 3446 3447 /* Add the item at the end of the combo */ 3448 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter); 3449 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt); 3450 3451 nFilters++; 3452 } 3453 if(fodInfos->filter) 3454 { 3455 LPCWSTR lpstrPos = fodInfos->filter; 3456 3457 for(;;) 3458 { 3459 /* filter is a list... title\0ext\0......\0\0 3460 * Set the combo item text to the title and the item data 3461 * to the ext 3462 */ 3463 LPCWSTR lpstrDisplay; 3464 LPWSTR lpstrExt; 3465 3466 /* Get the title */ 3467 if(! *lpstrPos) break; /* end */ 3468 lpstrDisplay = lpstrPos; 3469 lpstrPos += lstrlenW(lpstrPos) + 1; 3470 3471 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay); 3472 3473 nFilters++; 3474 3475 /* Copy the extensions */ 3476 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL; 3477 lstrcpyW(lpstrExt,lpstrPos); 3478 lpstrPos += lstrlenW(lpstrPos) + 1; 3479 3480 /* Add the item at the end of the combo */ 3481 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt); 3482 3483 /* malformed filters are added anyway... */ 3484 if (!*lpstrExt) break; 3485 } 3486 } 3487 3488 /* 3489 * Set the current filter to the one specified 3490 * in the initialisation structure 3491 */ 3492 if (fodInfos->filter || fodInfos->customfilter) 3493 { 3494 LPWSTR lpstrFilter; 3495 3496 /* Check to make sure our index isn't out of bounds. */ 3497 if ( fodInfos->ofnInfos->nFilterIndex > 3498 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) ) 3499 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0); 3500 3501 /* set default filter index */ 3502 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL) 3503 fodInfos->ofnInfos->nFilterIndex = 1; 3504 3505 /* calculate index of Combo Box item */ 3506 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex; 3507 if (fodInfos->customfilter == NULL) 3508 nFilterIndexCB--; 3509 3510 /* Set the current index selection. */ 3511 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0); 3512 3513 /* Get the corresponding text string from the combo box. */ 3514 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3515 nFilterIndexCB); 3516 3517 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */ 3518 lpstrFilter = NULL; 3519 3520 if(lpstrFilter) 3521 { 3522 DWORD len; 3523 CharLowerW(lpstrFilter); /* lowercase */ 3524 len = lstrlenW(lpstrFilter)+1; 3525 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) ); 3526 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter); 3527 } 3528 } else 3529 fodInfos->ofnInfos->nFilterIndex = 0; 3530 return S_OK; 3531 } 3532 3533 /*********************************************************************** 3534 * FILEDLG95_FILETYPE_OnCommand 3535 * 3536 * WM_COMMAND of the file type combo box 3537 * If the function succeeds, the return value is nonzero. 3538 */ 3539 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode) 3540 { 3541 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3542 3543 switch(wNotifyCode) 3544 { 3545 case CBN_SELENDOK: 3546 { 3547 LPWSTR lpstrFilter; 3548 3549 /* Get the current item of the filetype combo box */ 3550 int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0); 3551 3552 /* set the current filter index */ 3553 fodInfos->ofnInfos->nFilterIndex = iItem + 3554 (fodInfos->customfilter == NULL ? 1 : 0); 3555 3556 /* Set the current filter with the current selection */ 3557 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter); 3558 3559 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3560 iItem); 3561 if((INT_PTR)lpstrFilter != CB_ERR) 3562 { 3563 DWORD len; 3564 CharLowerW(lpstrFilter); /* lowercase */ 3565 len = lstrlenW(lpstrFilter)+1; 3566 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) ); 3567 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter); 3568 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 3569 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE); 3570 } 3571 3572 /* Refresh the actual view to display the included items*/ 3573 if (fodInfos->Shell.FOIShellView) 3574 IShellView_Refresh(fodInfos->Shell.FOIShellView); 3575 } 3576 } 3577 return FALSE; 3578 } 3579 /*********************************************************************** 3580 * FILEDLG95_FILETYPE_SearchExt 3581 * 3582 * searches for an extension in the filetype box 3583 */ 3584 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt) 3585 { 3586 int i, iCount; 3587 3588 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0); 3589 3590 TRACE("%s\n", debugstr_w(lpstrExt)); 3591 3592 if(iCount != CB_ERR) 3593 { 3594 for(i=0;i<iCount;i++) 3595 { 3596 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i))) 3597 return i; 3598 } 3599 } 3600 return -1; 3601 } 3602 3603 /*********************************************************************** 3604 * FILEDLG95_FILETYPE_Clean 3605 * 3606 * Clean the memory used by the filetype combo box 3607 */ 3608 static void FILEDLG95_FILETYPE_Clean(HWND hwnd) 3609 { 3610 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3611 int iPos; 3612 int iCount; 3613 3614 iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0); 3615 3616 TRACE("\n"); 3617 3618 /* Delete each string of the combo and their associated data */ 3619 if(iCount != CB_ERR) 3620 { 3621 for(iPos = iCount-1;iPos>=0;iPos--) 3622 { 3623 heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos)); 3624 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0); 3625 } 3626 } 3627 /* Current filter */ 3628 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter); 3629 } 3630 3631 /*********************************************************************** 3632 * FILEDLG95_LOOKIN_Init 3633 * 3634 * Initialisation of the look in combo box 3635 */ 3636 3637 /* Small helper function, to determine if the unixfs shell extension is rooted 3638 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 3639 */ 3640 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) { 3641 HKEY hKey; 3642 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\', 3643 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', 3644 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 3645 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\', 3646 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8', 3647 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-', 3648 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 }; 3649 3650 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 3651 return FALSE; 3652 3653 RegCloseKey(hKey); 3654 return TRUE; 3655 } 3656 3657 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo) 3658 { 3659 IShellFolder *psfRoot, *psfDrives; 3660 IEnumIDList *lpeRoot, *lpeDrives; 3661 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp; 3662 HDC hdc; 3663 TEXTMETRICW tm; 3664 LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos)); 3665 3666 TRACE("%p\n", hwndCombo); 3667 3668 liInfos->iMaxIndentation = 0; 3669 3670 SetPropA(hwndCombo, LookInInfosStr, liInfos); 3671 3672 hdc = GetDC( hwndCombo ); 3673 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 )); 3674 GetTextMetricsW( hdc, &tm ); 3675 ReleaseDC( hwndCombo, hdc ); 3676 3677 /* set item height for both text field and listbox */ 3678 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON))); 3679 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON))); 3680 3681 /* Turn on the extended UI for the combo box like Windows does */ 3682 SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0); 3683 3684 /* Initialise data of Desktop folder */ 3685 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp); 3686 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND); 3687 ILFree(pidlTmp); 3688 3689 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives); 3690 3691 SHGetDesktopFolder(&psfRoot); 3692 3693 if (psfRoot) 3694 { 3695 /* enumerate the contents of the desktop */ 3696 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot))) 3697 { 3698 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL)) 3699 { 3700 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND); 3701 3702 /* If the unixfs extension is rooted, we don't expand the drives by default */ 3703 if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 3704 { 3705 /* special handling for CSIDL_DRIVES */ 3706 if (ILIsEqual(pidlTmp, pidlDrives)) 3707 { 3708 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives))) 3709 { 3710 /* enumerate the drives */ 3711 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives))) 3712 { 3713 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL)) 3714 { 3715 pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1); 3716 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND); 3717 ILFree(pidlAbsTmp); 3718 ILFree(pidlTmp1); 3719 } 3720 IEnumIDList_Release(lpeDrives); 3721 } 3722 IShellFolder_Release(psfDrives); 3723 } 3724 } 3725 } 3726 3727 ILFree(pidlTmp); 3728 } 3729 IEnumIDList_Release(lpeRoot); 3730 } 3731 IShellFolder_Release(psfRoot); 3732 } 3733 3734 ILFree(pidlDrives); 3735 } 3736 3737 /*********************************************************************** 3738 * FILEDLG95_LOOKIN_DrawItem 3739 * 3740 * WM_DRAWITEM message handler 3741 */ 3742 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct) 3743 { 3744 COLORREF crWin = GetSysColor(COLOR_WINDOW); 3745 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT); 3746 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT); 3747 RECT rectText; 3748 RECT rectIcon; 3749 SHFILEINFOW sfi; 3750 HIMAGELIST ilItemImage; 3751 int iIndentation; 3752 TEXTMETRICW tm; 3753 LPSFOLDER tmpFolder; 3754 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME; 3755 UINT icon_width, icon_height; 3756 3757 TRACE("\n"); 3758 3759 if(pDIStruct->itemID == -1) 3760 return 0; 3761 3762 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem, 3763 pDIStruct->itemID))) 3764 return 0; 3765 3766 3767 icon_width = GetSystemMetrics(SM_CXICON); 3768 icon_height = GetSystemMetrics(SM_CYICON); 3769 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height) 3770 { 3771 icon_width = GetSystemMetrics(SM_CXSMICON); 3772 icon_height = GetSystemMetrics(SM_CYSMICON); 3773 shgfi_flags |= SHGFI_SMALLICON; 3774 } 3775 3776 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem, 3777 0, &sfi, sizeof (sfi), shgfi_flags ); 3778 3779 /* Is this item selected ? */ 3780 if(pDIStruct->itemState & ODS_SELECTED) 3781 { 3782 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText))); 3783 SetBkColor(pDIStruct->hDC,crHighLight); 3784 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT)); 3785 } 3786 else 3787 { 3788 SetTextColor(pDIStruct->hDC,crText); 3789 SetBkColor(pDIStruct->hDC,crWin); 3790 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW)); 3791 } 3792 3793 /* Do not indent item if drawing in the edit of the combo */ 3794 if(pDIStruct->itemState & ODS_COMBOBOXEDIT) 3795 iIndentation = 0; 3796 else 3797 iIndentation = tmpFolder->m_iIndent; 3798 3799 /* Draw text and icon */ 3800 3801 /* Initialise the icon display area */ 3802 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation; 3803 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2; 3804 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET; 3805 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2; 3806 3807 /* Initialise the text display area */ 3808 GetTextMetricsW(pDIStruct->hDC, &tm); 3809 rectText.left = rectIcon.right; 3810 rectText.top = 3811 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2; 3812 rectText.right = pDIStruct->rcItem.right; 3813 rectText.bottom = 3814 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2; 3815 3816 /* Draw the icon from the image list */ 3817 ImageList_Draw(ilItemImage, 3818 sfi.iIcon, 3819 pDIStruct->hDC, 3820 rectIcon.left, 3821 rectIcon.top, 3822 ILD_TRANSPARENT ); 3823 3824 /* Draw the associated text */ 3825 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName)); 3826 return NOERROR; 3827 } 3828 3829 /*********************************************************************** 3830 * FILEDLG95_LOOKIN_OnCommand 3831 * 3832 * LookIn combo box WM_COMMAND message handler 3833 * If the function succeeds, the return value is nonzero. 3834 */ 3835 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode) 3836 { 3837 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3838 3839 TRACE("%p\n", fodInfos); 3840 3841 switch(wNotifyCode) 3842 { 3843 case CBN_SELENDOK: 3844 { 3845 LPSFOLDER tmpFolder; 3846 int iItem; 3847 3848 iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0); 3849 3850 if( iItem == CB_ERR) return FALSE; 3851 3852 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB, 3853 iItem))) 3854 return FALSE; 3855 3856 3857 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, 3858 tmpFolder->pidlItem, 3859 SBSP_ABSOLUTE))) 3860 { 3861 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 3862 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); 3863 return TRUE; 3864 } 3865 break; 3866 } 3867 3868 } 3869 return FALSE; 3870 } 3871 3872 /*********************************************************************** 3873 * FILEDLG95_LOOKIN_AddItem 3874 * 3875 * Adds an absolute pidl item to the lookin combo box 3876 * returns the index of the inserted item 3877 */ 3878 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId) 3879 { 3880 LPITEMIDLIST pidlNext; 3881 SHFILEINFOW sfi; 3882 SFOLDER *tmpFolder; 3883 LookInInfos *liInfos; 3884 3885 TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId); 3886 3887 if(!pidl) 3888 return -1; 3889 3890 if(!(liInfos = GetPropA(hwnd,LookInInfosStr))) 3891 return -1; 3892 3893 tmpFolder = heap_alloc_zero(sizeof(*tmpFolder)); 3894 tmpFolder->m_iIndent = 0; 3895 3896 /* Calculate the indentation of the item in the lookin*/ 3897 pidlNext = pidl; 3898 while ((pidlNext = ILGetNext(pidlNext))) 3899 { 3900 tmpFolder->m_iIndent++; 3901 } 3902 3903 tmpFolder->pidlItem = ILClone(pidl); 3904 3905 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation) 3906 liInfos->iMaxIndentation = tmpFolder->m_iIndent; 3907 3908 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM; 3909 SHGetFileInfoW((LPCWSTR)pidl, 3910 0, 3911 &sfi, 3912 sizeof(sfi), 3913 SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED); 3914 3915 TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes); 3916 3917 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM)) 3918 { 3919 int iItemID; 3920 3921 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent); 3922 3923 /* Add the item at the end of the list */ 3924 if(iInsertId < 0) 3925 { 3926 iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName); 3927 } 3928 /* Insert the item at the iInsertId position*/ 3929 else 3930 { 3931 iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName); 3932 } 3933 3934 SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder); 3935 return iItemID; 3936 } 3937 3938 ILFree( tmpFolder->pidlItem ); 3939 heap_free( tmpFolder ); 3940 return -1; 3941 3942 } 3943 3944 /*********************************************************************** 3945 * FILEDLG95_LOOKIN_InsertItemAfterParent 3946 * 3947 * Insert an item below its parent 3948 */ 3949 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl) 3950 { 3951 3952 LPITEMIDLIST pidlParent = GetParentPidl(pidl); 3953 int iParentPos; 3954 3955 TRACE("\n"); 3956 3957 if (pidl == pidlParent) 3958 return -1; 3959 3960 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL); 3961 3962 if(iParentPos < 0) 3963 { 3964 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent); 3965 } 3966 3967 ILFree(pidlParent); 3968 3969 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1); 3970 } 3971 3972 /*********************************************************************** 3973 * FILEDLG95_LOOKIN_SelectItem 3974 * 3975 * Adds an absolute pidl item to the lookin combo box 3976 * returns the index of the inserted item 3977 */ 3978 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl) 3979 { 3980 int iItemPos; 3981 LookInInfos *liInfos; 3982 3983 TRACE("%p, %p\n", hwnd, pidl); 3984 3985 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL); 3986 3987 liInfos = GetPropA(hwnd,LookInInfosStr); 3988 3989 if(iItemPos < 0) 3990 { 3991 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1); 3992 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl); 3993 } 3994 3995 else 3996 { 3997 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos); 3998 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent) 3999 { 4000 int iRemovedItem; 4001 4002 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd))) 4003 break; 4004 if(iRemovedItem < iItemPos) 4005 iItemPos--; 4006 } 4007 } 4008 4009 SendMessageW(hwnd, CB_SETCURSEL, iItemPos, 0); 4010 liInfos->uSelectedItem = iItemPos; 4011 4012 return 0; 4013 4014 } 4015 4016 /*********************************************************************** 4017 * FILEDLG95_LOOKIN_RemoveMostExpandedItem 4018 * 4019 * Remove the item with an expansion level over iExpansionLevel 4020 */ 4021 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd) 4022 { 4023 int iItemPos; 4024 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr); 4025 4026 TRACE("\n"); 4027 4028 if(liInfos->iMaxIndentation <= 2) 4029 return -1; 4030 4031 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0) 4032 { 4033 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos); 4034 ILFree(tmpFolder->pidlItem); 4035 heap_free(tmpFolder); 4036 SendMessageW(hwnd, CB_DELETESTRING, iItemPos, 0); 4037 liInfos->iMaxIndentation--; 4038 4039 return iItemPos; 4040 } 4041 4042 return -1; 4043 } 4044 4045 /*********************************************************************** 4046 * FILEDLG95_LOOKIN_SearchItem 4047 * 4048 * Search for pidl in the lookin combo box 4049 * returns the index of the found item 4050 */ 4051 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod) 4052 { 4053 int i = 0; 4054 int iCount; 4055 4056 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0); 4057 4058 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod); 4059 4060 if (iCount != CB_ERR) 4061 { 4062 for(;i<iCount;i++) 4063 { 4064 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i); 4065 4066 if (iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg, tmpFolder->pidlItem)) 4067 return i; 4068 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg) 4069 return i; 4070 } 4071 } 4072 4073 return -1; 4074 } 4075 4076 /*********************************************************************** 4077 * FILEDLG95_LOOKIN_Clean 4078 * 4079 * Clean the memory used by the lookin combo box 4080 */ 4081 static void FILEDLG95_LOOKIN_Clean(HWND hwnd) 4082 { 4083 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4084 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr); 4085 int iPos, iCount; 4086 4087 iCount = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCOUNT, 0, 0); 4088 4089 TRACE("\n"); 4090 4091 /* Delete each string of the combo and their associated data */ 4092 if (iCount != CB_ERR) 4093 { 4094 for(iPos = iCount-1;iPos>=0;iPos--) 4095 { 4096 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos); 4097 ILFree(tmpFolder->pidlItem); 4098 heap_free(tmpFolder); 4099 SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_DELETESTRING, iPos, 0); 4100 } 4101 } 4102 4103 /* LookInInfos structure */ 4104 heap_free(liInfos); 4105 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr); 4106 } 4107 4108 /*********************************************************************** 4109 * get_def_format 4110 * 4111 * Fill the FORMATETC used in the shell id list 4112 */ 4113 static FORMATETC get_def_format(void) 4114 { 4115 static CLIPFORMAT cfFormat; 4116 FORMATETC formatetc; 4117 4118 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA); 4119 formatetc.cfFormat = cfFormat; 4120 formatetc.ptd = 0; 4121 formatetc.dwAspect = DVASPECT_CONTENT; 4122 formatetc.lindex = -1; 4123 formatetc.tymed = TYMED_HGLOBAL; 4124 return formatetc; 4125 } 4126 4127 /*********************************************************************** 4128 * FILEDLG95_FILENAME_FillFromSelection 4129 * 4130 * fills the edit box from the cached DataObject 4131 */ 4132 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd) 4133 { 4134 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4135 LPITEMIDLIST pidl; 4136 LPWSTR lpstrAllFiles, lpstrTmp; 4137 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength; 4138 STGMEDIUM medium; 4139 LPIDA cida; 4140 FORMATETC formatetc = get_def_format(); 4141 4142 TRACE("\n"); 4143 4144 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium))) 4145 return; 4146 4147 cida = GlobalLock(medium.u.hGlobal); 4148 nFileSelected = cida->cidl; 4149 4150 /* Allocate a buffer */ 4151 nAllFilesMaxLength = MAX_PATH + 3; 4152 lpstrAllFiles = heap_alloc_zero(nAllFilesMaxLength * sizeof(WCHAR)); 4153 if (!lpstrAllFiles) 4154 goto ret; 4155 4156 /* Loop through the selection, handle only files (not folders) */ 4157 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++) 4158 { 4159 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]); 4160 if (pidl) 4161 { 4162 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) 4163 { 4164 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength) 4165 { 4166 nAllFilesMaxLength *= 2; 4167 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR)); 4168 if (!lpstrTmp) 4169 goto ret; 4170 lpstrAllFiles = lpstrTmp; 4171 } 4172 nFiles += 1; 4173 lpstrAllFiles[nAllFilesLength++] = '"'; 4174 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength); 4175 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength); 4176 nAllFilesLength += nThisFileLength; 4177 lpstrAllFiles[nAllFilesLength++] = '"'; 4178 lpstrAllFiles[nAllFilesLength++] = ' '; 4179 } 4180 } 4181 } 4182 4183 if (nFiles != 0) 4184 { 4185 /* If there's only one file, use the name as-is without quotes */ 4186 lpstrTmp = lpstrAllFiles; 4187 if (nFiles == 1) 4188 { 4189 lpstrTmp += 1; 4190 lpstrTmp[nThisFileLength] = 0; 4191 } 4192 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp); 4193 /* Select the file name like Windows does */ 4194 if (filename_is_edit(fodInfos)) 4195 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1); 4196 } 4197 4198 ret: 4199 heap_free(lpstrAllFiles); 4200 COMCTL32_ReleaseStgMedium(medium); 4201 } 4202 4203 4204 /* copied from shell32 to avoid linking to it 4205 * Although shell32 is already linked the behaviour of exported StrRetToStrN 4206 * is dependent on whether emulated OS is unicode or not. 4207 */ 4208 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl) 4209 { 4210 switch (src->uType) 4211 { 4212 case STRRET_WSTR: 4213 lstrcpynW(dest, src->u.pOleStr, len); 4214 CoTaskMemFree(src->u.pOleStr); 4215 break; 4216 4217 case STRRET_CSTR: 4218 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len) 4219 dest[len-1] = 0; 4220 break; 4221 4222 case STRRET_OFFSET: 4223 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len) 4224 dest[len-1] = 0; 4225 break; 4226 4227 default: 4228 FIXME("unknown type %x!\n", src->uType); 4229 if (len) *dest = '\0'; 4230 return E_FAIL; 4231 } 4232 return S_OK; 4233 } 4234 4235 /*********************************************************************** 4236 * FILEDLG95_FILENAME_GetFileNames 4237 * 4238 * Copies the filenames to a delimited string list. 4239 */ 4240 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed) 4241 { 4242 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4243 UINT nFileCount = 0; /* number of files */ 4244 UINT nStrLen = 0; /* length of string in edit control */ 4245 LPWSTR lpstrEdit; /* buffer for string from edit control */ 4246 4247 TRACE("\n"); 4248 4249 /* get the filenames from the filename control */ 4250 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName ); 4251 lpstrEdit = heap_alloc( (nStrLen+1)*sizeof(WCHAR) ); 4252 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1); 4253 4254 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit)); 4255 4256 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed); 4257 heap_free(lpstrEdit); 4258 return nFileCount; 4259 } 4260 4261 /* 4262 * DATAOBJECT Helper functions 4263 */ 4264 4265 /*********************************************************************** 4266 * COMCTL32_ReleaseStgMedium 4267 * 4268 * like ReleaseStgMedium from ole32 4269 */ 4270 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium) 4271 { 4272 if(medium.pUnkForRelease) 4273 { 4274 IUnknown_Release(medium.pUnkForRelease); 4275 } 4276 else 4277 { 4278 GlobalUnlock(medium.u.hGlobal); 4279 GlobalFree(medium.u.hGlobal); 4280 } 4281 } 4282 4283 /*********************************************************************** 4284 * GetPidlFromDataObject 4285 * 4286 * Return pidl(s) by number from the cached DataObject 4287 * 4288 * nPidlIndex=0 gets the fully qualified root path 4289 */ 4290 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex) 4291 { 4292 4293 STGMEDIUM medium; 4294 FORMATETC formatetc = get_def_format(); 4295 LPITEMIDLIST pidl = NULL; 4296 4297 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex); 4298 4299 if (!doSelected) 4300 return NULL; 4301 4302 /* Get the pidls from IDataObject */ 4303 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium))) 4304 { 4305 LPIDA cida = GlobalLock(medium.u.hGlobal); 4306 if(nPidlIndex <= cida->cidl) 4307 { 4308 pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]])); 4309 } 4310 COMCTL32_ReleaseStgMedium(medium); 4311 } 4312 return pidl; 4313 } 4314 4315 /*********************************************************************** 4316 * GetNumSelected 4317 * 4318 * Return the number of selected items in the DataObject. 4319 * 4320 */ 4321 static UINT GetNumSelected( IDataObject *doSelected ) 4322 { 4323 UINT retVal = 0; 4324 STGMEDIUM medium; 4325 FORMATETC formatetc = get_def_format(); 4326 4327 TRACE("sv=%p\n", doSelected); 4328 4329 if (!doSelected) return 0; 4330 4331 /* Get the pidls from IDataObject */ 4332 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium))) 4333 { 4334 LPIDA cida = GlobalLock(medium.u.hGlobal); 4335 retVal = cida->cidl; 4336 COMCTL32_ReleaseStgMedium(medium); 4337 return retVal; 4338 } 4339 return 0; 4340 } 4341 4342 /* 4343 * TOOLS 4344 */ 4345 4346 /*********************************************************************** 4347 * GetName 4348 * 4349 * Get the pidl's display name (relative to folder) and 4350 * put it in lpstrFileName. 4351 * 4352 * Return NOERROR on success, 4353 * E_FAIL otherwise 4354 */ 4355 4356 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName) 4357 { 4358 STRRET str; 4359 HRESULT hRes; 4360 4361 TRACE("sf=%p pidl=%p\n", lpsf, pidl); 4362 4363 if(!lpsf) 4364 { 4365 SHGetDesktopFolder(&lpsf); 4366 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName); 4367 IShellFolder_Release(lpsf); 4368 return hRes; 4369 } 4370 4371 /* Get the display name of the pidl relative to the folder */ 4372 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str))) 4373 { 4374 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl); 4375 } 4376 return E_FAIL; 4377 } 4378 4379 /*********************************************************************** 4380 * GetShellFolderFromPidl 4381 * 4382 * pidlRel is the item pidl relative 4383 * Return the IShellFolder of the absolute pidl 4384 */ 4385 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs) 4386 { 4387 IShellFolder *psf = NULL,*psfParent; 4388 4389 TRACE("%p\n", pidlAbs); 4390 4391 if(SUCCEEDED(SHGetDesktopFolder(&psfParent))) 4392 { 4393 psf = psfParent; 4394 if(pidlAbs && pidlAbs->mkid.cb) 4395 { 4396 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf))) 4397 { 4398 IShellFolder_Release(psfParent); 4399 return psf; 4400 } 4401 } 4402 /* return the desktop */ 4403 return psfParent; 4404 } 4405 return NULL; 4406 } 4407 4408 /*********************************************************************** 4409 * GetParentPidl 4410 * 4411 * Return the LPITEMIDLIST to the parent of the pidl in the list 4412 */ 4413 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl) 4414 { 4415 LPITEMIDLIST pidlParent; 4416 4417 TRACE("%p\n", pidl); 4418 4419 pidlParent = ILClone(pidl); 4420 ILRemoveLastID(pidlParent); 4421 4422 return pidlParent; 4423 } 4424 4425 /*********************************************************************** 4426 * GetPidlFromName 4427 * 4428 * returns the pidl of the file name relative to folder 4429 * NULL if an error occurred 4430 */ 4431 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName) 4432 { 4433 LPITEMIDLIST pidl = NULL; 4434 ULONG ulEaten; 4435 4436 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName)); 4437 4438 if(!lpcstrFileName) return NULL; 4439 if(!*lpcstrFileName) return NULL; 4440 4441 if(!lpsf) 4442 { 4443 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) { 4444 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL); 4445 IShellFolder_Release(lpsf); 4446 } 4447 } 4448 else 4449 { 4450 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL); 4451 } 4452 return pidl; 4453 } 4454 4455 /* 4456 */ 4457 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl) 4458 { 4459 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER; 4460 HRESULT ret; 4461 4462 TRACE("%p, %p\n", psf, pidl); 4463 4464 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr ); 4465 4466 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret); 4467 /* see documentation shell 4.1*/ 4468 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER); 4469 } 4470 4471 /*********************************************************************** 4472 * BrowseSelectedFolder 4473 */ 4474 static BOOL BrowseSelectedFolder(HWND hwnd) 4475 { 4476 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4477 BOOL bBrowseSelFolder = FALSE; 4478 4479 TRACE("\n"); 4480 4481 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1) 4482 { 4483 LPITEMIDLIST pidlSelection; 4484 4485 /* get the file selected */ 4486 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1); 4487 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection)) 4488 { 4489 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser, 4490 pidlSelection, SBSP_RELATIVE ) ) ) 4491 { 4492 WCHAR buf[64]; 4493 LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, ARRAY_SIZE(buf)); 4494 MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION ); 4495 } 4496 bBrowseSelFolder = TRUE; 4497 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 4498 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE); 4499 } 4500 ILFree( pidlSelection ); 4501 } 4502 4503 return bBrowseSelFolder; 4504 } 4505 4506 static inline BOOL valid_struct_size( DWORD size ) 4507 { 4508 return (size == OPENFILENAME_SIZE_VERSION_400W) || 4509 (size == sizeof( OPENFILENAMEW )); 4510 } 4511 4512 static inline BOOL is_win16_looks(DWORD flags) 4513 { 4514 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) && 4515 !(flags & OFN_EXPLORER)); 4516 } 4517 4518 /* ------------------ APIs ---------------------- */ 4519 4520 /*********************************************************************** 4521 * GetOpenFileNameA (COMDLG32.@) 4522 * 4523 * Creates a dialog box for the user to select a file to open. 4524 * 4525 * RETURNS 4526 * TRUE on success: user enters a valid file 4527 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4528 * 4529 */ 4530 BOOL WINAPI GetOpenFileNameA(OPENFILENAMEA *ofn) 4531 { 4532 TRACE("flags 0x%08x\n", ofn->Flags); 4533 4534 if (!valid_struct_size( ofn->lStructSize )) 4535 { 4536 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4537 return FALSE; 4538 } 4539 4540 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */ 4541 if (ofn->Flags & OFN_FILEMUSTEXIST) 4542 ofn->Flags |= OFN_PATHMUSTEXIST; 4543 4544 if (is_win16_looks(ofn->Flags)) 4545 return GetFileName31A(ofn, OPEN_DIALOG); 4546 else 4547 { 4548 FileOpenDlgInfos info; 4549 4550 init_filedlg_infoA(ofn, &info); 4551 return GetFileDialog95(&info, OPEN_DIALOG); 4552 } 4553 } 4554 4555 /*********************************************************************** 4556 * GetOpenFileNameW (COMDLG32.@) 4557 * 4558 * Creates a dialog box for the user to select a file to open. 4559 * 4560 * RETURNS 4561 * TRUE on success: user enters a valid file 4562 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4563 * 4564 */ 4565 BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn) 4566 { 4567 TRACE("flags 0x%08x\n", ofn->Flags); 4568 4569 if (!valid_struct_size( ofn->lStructSize )) 4570 { 4571 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4572 return FALSE; 4573 } 4574 4575 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */ 4576 if (ofn->Flags & OFN_FILEMUSTEXIST) 4577 ofn->Flags |= OFN_PATHMUSTEXIST; 4578 4579 if (is_win16_looks(ofn->Flags)) 4580 return GetFileName31W(ofn, OPEN_DIALOG); 4581 else 4582 { 4583 FileOpenDlgInfos info; 4584 4585 init_filedlg_infoW(ofn, &info); 4586 return GetFileDialog95(&info, OPEN_DIALOG); 4587 } 4588 } 4589 4590 4591 /*********************************************************************** 4592 * GetSaveFileNameA (COMDLG32.@) 4593 * 4594 * Creates a dialog box for the user to select a file to save. 4595 * 4596 * RETURNS 4597 * TRUE on success: user enters a valid file 4598 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4599 * 4600 */ 4601 BOOL WINAPI GetSaveFileNameA(OPENFILENAMEA *ofn) 4602 { 4603 if (!valid_struct_size( ofn->lStructSize )) 4604 { 4605 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4606 return FALSE; 4607 } 4608 4609 if (is_win16_looks(ofn->Flags)) 4610 return GetFileName31A(ofn, SAVE_DIALOG); 4611 else 4612 { 4613 FileOpenDlgInfos info; 4614 4615 init_filedlg_infoA(ofn, &info); 4616 return GetFileDialog95(&info, SAVE_DIALOG); 4617 } 4618 } 4619 4620 /*********************************************************************** 4621 * GetSaveFileNameW (COMDLG32.@) 4622 * 4623 * Creates a dialog box for the user to select a file to save. 4624 * 4625 * RETURNS 4626 * TRUE on success: user enters a valid file 4627 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4628 * 4629 */ 4630 BOOL WINAPI GetSaveFileNameW( 4631 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */ 4632 { 4633 if (!valid_struct_size( ofn->lStructSize )) 4634 { 4635 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4636 return FALSE; 4637 } 4638 4639 if (is_win16_looks(ofn->Flags)) 4640 return GetFileName31W(ofn, SAVE_DIALOG); 4641 else 4642 { 4643 FileOpenDlgInfos info; 4644 4645 init_filedlg_infoW(ofn, &info); 4646 return GetFileDialog95(&info, SAVE_DIALOG); 4647 } 4648 } 4649 4650 /*********************************************************************** 4651 * GetFileTitleA (COMDLG32.@) 4652 * 4653 * See GetFileTitleW. 4654 */ 4655 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf) 4656 { 4657 int ret; 4658 UNICODE_STRING strWFile; 4659 LPWSTR lpWTitle; 4660 4661 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile); 4662 lpWTitle = heap_alloc(cbBuf * sizeof(WCHAR)); 4663 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf); 4664 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL ); 4665 RtlFreeUnicodeString( &strWFile ); 4666 heap_free( lpWTitle ); 4667 return ret; 4668 } 4669 4670 4671 /*********************************************************************** 4672 * GetFileTitleW (COMDLG32.@) 4673 * 4674 * Get the name of a file. 4675 * 4676 * PARAMS 4677 * lpFile [I] name and location of file 4678 * lpTitle [O] returned file name 4679 * cbBuf [I] buffer size of lpTitle 4680 * 4681 * RETURNS 4682 * Success: zero 4683 * Failure: negative number. 4684 */ 4685 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf) 4686 { 4687 int i, len; 4688 static const WCHAR brkpoint[] = {'*','[',']',0}; 4689 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf); 4690 4691 if(lpFile == NULL || lpTitle == NULL) 4692 return -1; 4693 4694 len = lstrlenW(lpFile); 4695 4696 if (len == 0) 4697 return -1; 4698 4699 if(wcspbrk(lpFile, brkpoint)) 4700 return -1; 4701 4702 len--; 4703 4704 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':') 4705 return -1; 4706 4707 for(i = len; i >= 0; i--) 4708 { 4709 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':') 4710 { 4711 i++; 4712 break; 4713 } 4714 } 4715 4716 if(i == -1) 4717 i++; 4718 4719 TRACE("---> %s\n", debugstr_w(&lpFile[i])); 4720 4721 len = lstrlenW(lpFile+i)+1; 4722 if(cbBuf < len) 4723 return len; 4724 4725 lstrcpyW(lpTitle, &lpFile[i]); 4726 return 0; 4727 } 4728