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 #ifdef __REACTOS__ 1919 WCHAR buf[24]; 1920 #else 1921 WCHAR buf[16]; 1922 #endif 1923 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, ARRAY_SIZE(buf)); 1924 SetDlgItemTextW(hwnd, IDOK, buf); 1925 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, ARRAY_SIZE(buf)); 1926 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf); 1927 } 1928 1929 /* Initialize the filter combo box */ 1930 FILEDLG95_FILETYPE_Init(hwnd); 1931 1932 return 0; 1933 } 1934 1935 /*********************************************************************** 1936 * FILEDLG95_ResizeControls 1937 * 1938 * WM_INITDIALOG message handler (after hook notification) 1939 */ 1940 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam) 1941 { 1942 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam; 1943 1944 if (fodInfos->DlgInfos.hwndCustomDlg) 1945 { 1946 RECT rc; 1947 UINT flags = SWP_NOACTIVATE; 1948 1949 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd, 1950 filedialog_is_readonly_hidden(fodInfos) && !(fodInfos->ofnInfos->Flags & OFN_SHOWHELP)); 1951 1952 /* resize the custom dialog to the parent size */ 1953 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)) 1954 GetClientRect(hwnd, &rc); 1955 else 1956 { 1957 /* our own fake template is zero sized and doesn't have children, so 1958 * there is no need to resize it. Picasa depends on it. 1959 */ 1960 flags |= SWP_NOSIZE; 1961 SetRectEmpty(&rc); 1962 } 1963 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM, 1964 0, 0, rc.right, rc.bottom, flags); 1965 } 1966 else 1967 { 1968 /* Resize the height; if opened as read-only, checkbox and help button are 1969 * hidden and we are not using a custom template nor a customDialog 1970 */ 1971 if (filedialog_is_readonly_hidden(fodInfos) && 1972 (!(fodInfos->ofnInfos->Flags & 1973 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE)))) 1974 { 1975 RECT rectDlg, rectHelp, rectCancel; 1976 GetWindowRect(hwnd, &rectDlg); 1977 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp); 1978 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel); 1979 /* subtract the height of the help button plus the space between the help 1980 * button and the cancel button to the height of the dialog 1981 */ 1982 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left, 1983 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom), 1984 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); 1985 } 1986 } 1987 return TRUE; 1988 } 1989 1990 /*********************************************************************** 1991 * FILEDLG95_FillControls 1992 * 1993 * WM_INITDIALOG message handler (after hook notification) 1994 */ 1995 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam) 1996 { 1997 LPITEMIDLIST pidlItemId = NULL; 1998 1999 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam; 2000 2001 TRACE("dir=%s file=%s\n", 2002 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename)); 2003 2004 /* Get the initial directory pidl */ 2005 2006 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir))) 2007 { 2008 WCHAR path[MAX_PATH]; 2009 2010 GetCurrentDirectoryW(MAX_PATH,path); 2011 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path); 2012 } 2013 2014 /* Initialise shell objects */ 2015 FILEDLG95_SHELL_Init(hwnd); 2016 2017 /* Initialize the Look In combo box */ 2018 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB); 2019 2020 /* Browse to the initial directory */ 2021 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE); 2022 2023 ILFree(pidlItemId); 2024 2025 return TRUE; 2026 } 2027 /*********************************************************************** 2028 * FILEDLG95_Clean 2029 * 2030 * Regroups all the cleaning functions of the filedlg 2031 */ 2032 void FILEDLG95_Clean(HWND hwnd) 2033 { 2034 FILEDLG95_FILETYPE_Clean(hwnd); 2035 FILEDLG95_LOOKIN_Clean(hwnd); 2036 FILEDLG95_SHELL_Clean(hwnd); 2037 } 2038 2039 2040 /*********************************************************************** 2041 * Browse to arbitrary pidl 2042 */ 2043 static void filedlg_browse_to_pidl(const FileOpenDlgInfos *info, LPITEMIDLIST pidl) 2044 { 2045 TRACE("%p, %p\n", info->ShellInfos.hwndOwner, pidl); 2046 2047 IShellBrowser_BrowseObject(info->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE); 2048 if (info->ofnInfos->Flags & OFN_EXPLORER) 2049 SendCustomDlgNotificationMessage(info->ShellInfos.hwndOwner, CDN_FOLDERCHANGE); 2050 } 2051 2052 /*********************************************************************** 2053 * FILEDLG95_OnWMCommand 2054 * 2055 * WM_COMMAND message handler 2056 */ 2057 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam) 2058 { 2059 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 2060 WORD wNotifyCode = HIWORD(wParam); /* notification code */ 2061 WORD id = LOWORD(wParam); /* item, control, or accelerator identifier */ 2062 2063 switch (id) 2064 { 2065 /* OK button */ 2066 case IDOK: 2067 FILEDLG95_OnOpen(hwnd); 2068 break; 2069 /* Cancel button */ 2070 case IDCANCEL: 2071 FILEDLG95_Clean(hwnd); 2072 EndDialog(hwnd, FALSE); 2073 break; 2074 /* Filetype combo box */ 2075 case IDC_FILETYPE: 2076 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode); 2077 break; 2078 /* LookIn combo box */ 2079 case IDC_LOOKIN: 2080 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode); 2081 break; 2082 2083 /* --- toolbar --- */ 2084 /* Up folder button */ 2085 case FCIDM_TB_UPFOLDER: 2086 FILEDLG95_SHELL_UpFolder(hwnd); 2087 break; 2088 /* New folder button */ 2089 case FCIDM_TB_NEWFOLDER: 2090 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA); 2091 break; 2092 /* List option button */ 2093 case FCIDM_TB_SMALLICON: 2094 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA); 2095 break; 2096 /* Details option button */ 2097 case FCIDM_TB_REPORTVIEW: 2098 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA); 2099 break; 2100 2101 case FCIDM_TB_DESKTOP: 2102 { 2103 LPITEMIDLIST pidl; 2104 2105 SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidl); 2106 filedlg_browse_to_pidl(fodInfos, pidl); 2107 ILFree(pidl); 2108 break; 2109 } 2110 2111 /* Places bar */ 2112 case TBPLACES_CMDID_PLACE0: 2113 case TBPLACES_CMDID_PLACE1: 2114 case TBPLACES_CMDID_PLACE2: 2115 case TBPLACES_CMDID_PLACE3: 2116 case TBPLACES_CMDID_PLACE4: 2117 filedlg_browse_to_pidl(fodInfos, fodInfos->places[id - TBPLACES_CMDID_PLACE0]); 2118 break; 2119 2120 case edt1: 2121 case cmb13: 2122 break; 2123 2124 } 2125 /* Do not use the listview selection anymore */ 2126 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW; 2127 return 0; 2128 } 2129 2130 /*********************************************************************** 2131 * FILEDLG95_OnWMGetIShellBrowser 2132 * 2133 * WM_GETISHELLBROWSER message handler 2134 */ 2135 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd) 2136 { 2137 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 2138 2139 TRACE("\n"); 2140 2141 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser); 2142 2143 return TRUE; 2144 } 2145 2146 2147 /*********************************************************************** 2148 * FILEDLG95_SendFileOK 2149 * 2150 * Sends the CDN_FILEOK notification if required 2151 * 2152 * RETURNS 2153 * TRUE if the dialog should close 2154 * FALSE if the dialog should not be closed 2155 */ 2156 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos ) 2157 { 2158 /* ask the hook if we can close */ 2159 if (is_dialog_hooked(fodInfos)) 2160 { 2161 LRESULT retval = 0; 2162 2163 TRACE("---\n"); 2164 /* First send CDN_FILEOK as MSDN doc says */ 2165 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 2166 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK); 2167 if( retval) 2168 { 2169 TRACE("canceled\n"); 2170 return FALSE; 2171 } 2172 2173 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */ 2174 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, 2175 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos); 2176 if( retval) 2177 { 2178 TRACE("canceled\n"); 2179 return FALSE; 2180 } 2181 } 2182 return TRUE; 2183 } 2184 2185 /*********************************************************************** 2186 * FILEDLG95_OnOpenMultipleFiles 2187 * 2188 * Handles the opening of multiple files. 2189 * 2190 * FIXME 2191 * check destination buffer size 2192 */ 2193 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed) 2194 { 2195 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 2196 WCHAR lpstrPathSpec[MAX_PATH] = {0}; 2197 UINT nCount, nSizePath; 2198 2199 TRACE("\n"); 2200 2201 if(fodInfos->unicode) 2202 { 2203 LPOPENFILENAMEW ofn = fodInfos->ofnInfos; 2204 ofn->lpstrFile[0] = '\0'; 2205 } 2206 else 2207 { 2208 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos; 2209 ofn->lpstrFile[0] = '\0'; 2210 } 2211 2212 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec ); 2213 2214 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) && 2215 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) && 2216 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) ) 2217 { 2218 LPWSTR lpstrTemp = lpstrFileList; 2219 2220 for ( nCount = 0; nCount < nFileCount; nCount++ ) 2221 { 2222 LPITEMIDLIST pidl; 2223 2224 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp); 2225 if (!pidl) 2226 { 2227 WCHAR lpstrNotFound[100]; 2228 WCHAR lpstrMsg[100]; 2229 WCHAR tmp[400]; 2230 static const WCHAR nl[] = {'\n',0}; 2231 2232 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100); 2233 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100); 2234 2235 lstrcpyW(tmp, lpstrTemp); 2236 lstrcatW(tmp, nl); 2237 lstrcatW(tmp, lpstrNotFound); 2238 lstrcatW(tmp, nl); 2239 lstrcatW(tmp, lpstrMsg); 2240 2241 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION); 2242 return FALSE; 2243 } 2244 2245 /* move to the next file in the list of files */ 2246 lpstrTemp += lstrlenW(lpstrTemp) + 1; 2247 ILFree(pidl); 2248 } 2249 } 2250 2251 nSizePath = lstrlenW(lpstrPathSpec) + 1; 2252 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) ) 2253 { 2254 /* For "oldstyle" dialog the components have to 2255 be separated by blanks (not '\0'!) and short 2256 filenames have to be used! */ 2257 FIXME("Components have to be separated by blanks\n"); 2258 } 2259 if(fodInfos->unicode) 2260 { 2261 LPOPENFILENAMEW ofn = fodInfos->ofnInfos; 2262 lstrcpyW( ofn->lpstrFile, lpstrPathSpec); 2263 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) ); 2264 } 2265 else 2266 { 2267 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; 2268 2269 if (ofn->lpstrFile != NULL) 2270 { 2271 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1, 2272 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL); 2273 if (ofn->nMaxFile > nSizePath) 2274 { 2275 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, 2276 ofn->lpstrFile + nSizePath, 2277 ofn->nMaxFile - nSizePath, NULL, NULL); 2278 } 2279 } 2280 } 2281 2282 fodInfos->ofnInfos->nFileOffset = nSizePath; 2283 fodInfos->ofnInfos->nFileExtension = 0; 2284 2285 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) ) 2286 return FALSE; 2287 2288 /* clean and exit */ 2289 FILEDLG95_Clean(hwnd); 2290 return EndDialog(hwnd,TRUE); 2291 } 2292 2293 /* Returns the 'slot name' of the given module_name in the registry's 2294 * most-recently-used list. This will be an ASCII value in the 2295 * range ['a','z'). Returns zero on error. 2296 * 2297 * The slot's value in the registry has the form: 2298 * module_name\0mru_path\0 2299 * 2300 * If stored_path is given, then stored_path will contain the path name 2301 * stored in the registry's MRU list for the given module_name. 2302 * 2303 * If hkey_ret is given, then hkey_ret will be a handle to the registry's 2304 * MRU list key for the given module_name. 2305 */ 2306 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret) 2307 { 2308 WCHAR mru_list[32], *cur_mru_slot; 2309 BOOL taken[25] = {0}; 2310 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i; 2311 HKEY hkey_tmp, *hkey; 2312 LONG ret; 2313 2314 if(hkey_ret) 2315 hkey = hkey_ret; 2316 else 2317 hkey = &hkey_tmp; 2318 2319 if(stored_path) 2320 *stored_path = '\0'; 2321 2322 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey); 2323 if(ret){ 2324 WARN("Unable to create MRU key: %d\n", ret); 2325 return 0; 2326 } 2327 2328 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type, 2329 (LPBYTE)mru_list, &mru_list_size); 2330 if(ret || key_type != REG_SZ){ 2331 if(ret == ERROR_FILE_NOT_FOUND) 2332 return 'a'; 2333 2334 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret); 2335 RegCloseKey(*hkey); 2336 return 0; 2337 } 2338 2339 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){ 2340 WCHAR value_data[MAX_PATH], value_name[2] = {0}; 2341 DWORD value_data_size = sizeof(value_data); 2342 2343 *value_name = *cur_mru_slot; 2344 2345 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY, 2346 &key_type, (LPBYTE)value_data, &value_data_size); 2347 if(ret || key_type != REG_BINARY){ 2348 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret); 2349 continue; 2350 } 2351 2352 if(!wcsicmp(module_name, value_data)){ 2353 if(!hkey_ret) 2354 RegCloseKey(*hkey); 2355 if(stored_path) 2356 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1); 2357 return *value_name; 2358 } 2359 } 2360 2361 if(!hkey_ret) 2362 RegCloseKey(*hkey); 2363 2364 /* the module name isn't in the registry, so find the next open slot */ 2365 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot) 2366 taken[*cur_mru_slot - 'a'] = TRUE; 2367 for(i = 0; i < 25; ++i){ 2368 if(!taken[i]) 2369 return i + 'a'; 2370 } 2371 2372 /* all slots are taken, so return the last one in MRUList */ 2373 --cur_mru_slot; 2374 return *cur_mru_slot; 2375 } 2376 2377 /* save the given filename as most-recently-used path for this module */ 2378 static void FILEDLG95_MRU_save_filename(LPCWSTR filename) 2379 { 2380 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0}; 2381 LONG ret; 2382 HKEY hkey; 2383 2384 /* get the current executable's name */ 2385 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path))) 2386 { 2387 WARN("GotModuleFileName failed: %d\n", GetLastError()); 2388 return; 2389 } 2390 module_name = wcsrchr(module_path, '\\'); 2391 if(!module_name) 2392 module_name = module_path; 2393 else 2394 module_name += 1; 2395 2396 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey); 2397 if(!slot) 2398 return; 2399 *slot_name = slot; 2400 2401 { /* update the slot's info */ 2402 WCHAR *path_ends, *final; 2403 DWORD path_len, final_len; 2404 2405 /* use only the path segment of `filename' */ 2406 path_ends = wcsrchr(filename, '\\'); 2407 path_len = path_ends - filename; 2408 2409 final_len = path_len + lstrlenW(module_name) + 2; 2410 2411 final = heap_alloc(final_len * sizeof(WCHAR)); 2412 if(!final) 2413 return; 2414 lstrcpyW(final, module_name); 2415 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR)); 2416 final[final_len-1] = '\0'; 2417 2418 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final, 2419 final_len * sizeof(WCHAR)); 2420 if(ret){ 2421 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret); 2422 heap_free(final); 2423 RegCloseKey(hkey); 2424 return; 2425 } 2426 2427 heap_free(final); 2428 } 2429 2430 { /* update MRUList value */ 2431 WCHAR old_mru_list[32], new_mru_list[32]; 2432 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list; 2433 DWORD mru_list_size = sizeof(old_mru_list), key_type; 2434 2435 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type, 2436 (LPBYTE)old_mru_list, &mru_list_size); 2437 if(ret || key_type != REG_SZ){ 2438 if(ret == ERROR_FILE_NOT_FOUND){ 2439 new_mru_list[0] = slot; 2440 new_mru_list[1] = '\0'; 2441 }else{ 2442 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret); 2443 RegCloseKey(hkey); 2444 return; 2445 } 2446 }else{ 2447 /* copy old list data over so that the new slot is at the start 2448 * of the list */ 2449 *new_mru_slot++ = slot; 2450 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){ 2451 if(*old_mru_slot != slot) 2452 *new_mru_slot++ = *old_mru_slot; 2453 } 2454 *new_mru_slot = '\0'; 2455 } 2456 2457 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list, 2458 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR)); 2459 if(ret){ 2460 WARN("Error saving MRUList data: %d\n", ret); 2461 RegCloseKey(hkey); 2462 return; 2463 } 2464 } 2465 } 2466 2467 /* load the most-recently-used path for this module */ 2468 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path) 2469 { 2470 WCHAR module_path[MAX_PATH], *module_name; 2471 2472 /* get the current executable's name */ 2473 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path))) 2474 { 2475 WARN("GotModuleFileName failed: %d\n", GetLastError()); 2476 return; 2477 } 2478 module_name = wcsrchr(module_path, '\\'); 2479 if(!module_name) 2480 module_name = module_path; 2481 else 2482 module_name += 1; 2483 2484 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL); 2485 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path)); 2486 } 2487 #ifdef __REACTOS__ 2488 2489 static const WCHAR s_subkey[] = 2490 { 2491 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', 2492 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s', 2493 'i','o','n','\\','E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g', 2494 '3','2','\\','O','p','e','n','S','a','v','e','M','R','U',0 2495 }; 2496 static const WCHAR s_szAst[] = { '*', 0 }; 2497 2498 typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs); 2499 typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length); 2500 2501 /* https://docs.microsoft.com/en-us/windows/desktop/shell/mruinfo */ 2502 typedef struct tagMRUINFOW 2503 { 2504 DWORD cbSize; 2505 UINT uMax; 2506 UINT fFlags; 2507 HKEY hKey; 2508 LPCWSTR lpszSubKey; 2509 union 2510 { 2511 MRUStringCmpFnW string_cmpfn; 2512 MRUBinaryCmpFn binary_cmpfn; 2513 } u; 2514 } MRUINFOW, *LPMRUINFOW; 2515 2516 /* flags for MRUINFOW.fFlags */ 2517 #define MRU_STRING 0x0000 2518 #define MRU_BINARY 0x0001 2519 #define MRU_CACHEWRITE 0x0002 2520 2521 static HINSTANCE s_hComCtl32 = NULL; 2522 2523 /* comctl32.400: CreateMRUListW */ 2524 typedef HANDLE (WINAPI *CREATEMRULISTW)(const MRUINFOW *); 2525 static CREATEMRULISTW s_pCreateMRUListW = NULL; 2526 2527 /* comctl32.401: AddMRUStringW */ 2528 typedef INT (WINAPI *ADDMRUSTRINGW)(HANDLE, LPCWSTR); 2529 static ADDMRUSTRINGW s_pAddMRUStringW = NULL; 2530 2531 /* comctl32.402: FindMRUStringW */ 2532 typedef INT (WINAPI *FINDMRUSTRINGW)(HANDLE, LPCWSTR, LPINT); 2533 static FINDMRUSTRINGW s_pFindMRUStringW = NULL; 2534 2535 /* comctl32.403: EnumMRUListW */ 2536 typedef INT (WINAPI *ENUMMRULISTW)(HANDLE, INT, LPVOID, DWORD); 2537 static ENUMMRULISTW s_pEnumMRUListW = NULL; 2538 2539 /* comctl32.152: FreeMRUList */ 2540 typedef void (WINAPI *FREEMRULIST)(HANDLE); 2541 static FREEMRULIST s_pFreeMRUList = NULL; 2542 2543 static BOOL FILEDLG_InitMRUList(void) 2544 { 2545 if (s_hComCtl32) 2546 return TRUE; 2547 2548 s_hComCtl32 = GetModuleHandleA("comctl32"); 2549 if (!s_hComCtl32) 2550 return FALSE; 2551 2552 s_pCreateMRUListW = (CREATEMRULISTW)GetProcAddress(s_hComCtl32, (LPCSTR)400); 2553 s_pAddMRUStringW = (ADDMRUSTRINGW)GetProcAddress(s_hComCtl32, (LPCSTR)401); 2554 s_pFindMRUStringW = (FINDMRUSTRINGW)GetProcAddress(s_hComCtl32, (LPCSTR)402); 2555 s_pEnumMRUListW = (ENUMMRULISTW)GetProcAddress(s_hComCtl32, (LPCSTR)403); 2556 s_pFreeMRUList = (FREEMRULIST)GetProcAddress(s_hComCtl32, (LPCSTR)152); 2557 if (!s_pCreateMRUListW || 2558 !s_pAddMRUStringW || 2559 !s_pFindMRUStringW || 2560 !s_pEnumMRUListW || 2561 !s_pFreeMRUList) 2562 { 2563 s_hComCtl32 = NULL; 2564 return FALSE; 2565 } 2566 2567 return TRUE; 2568 } 2569 2570 static BOOL ExtIsPicture(LPCWSTR ext) 2571 { 2572 static const WCHAR s_image_exts[][6] = 2573 { 2574 { 'b','m','p',0 }, 2575 { 'd','i','b',0 }, 2576 { 'j','p','g',0 }, 2577 { 'j','p','e','g',0 }, 2578 { 'j','p','e',0 }, 2579 { 'j','f','i','f',0 }, 2580 { 'p','n','g',0 }, 2581 { 'g','i','f',0 }, 2582 { 't','i','f',0 }, 2583 { 't','i','f','f',0 } 2584 }; 2585 size_t i; 2586 2587 for (i = 0; i < ARRAY_SIZE(s_image_exts); ++i) 2588 { 2589 if (lstrcmpiW(ext, s_image_exts[i]) == 0) 2590 { 2591 return TRUE; 2592 } 2593 } 2594 return FALSE; 2595 } 2596 2597 static void FILEDLG95_MRU_load_ext(LPWSTR stored_path, size_t cchMax, LPCWSTR defext) 2598 { 2599 HKEY hOpenSaveMRT = NULL; 2600 LONG result; 2601 MRUINFOW mi; 2602 HANDLE hList; 2603 WCHAR szText[MAX_PATH]; 2604 INT ret = 0; 2605 2606 stored_path[0] = 0; 2607 2608 if (!defext || !*defext || !FILEDLG_InitMRUList()) 2609 { 2610 return; 2611 } 2612 2613 if (*defext == '.') 2614 ++defext; 2615 2616 result = RegOpenKeyW(HKEY_CURRENT_USER, s_subkey, &hOpenSaveMRT); 2617 if (!result && hOpenSaveMRT) 2618 { 2619 ZeroMemory(&mi, sizeof(mi)); 2620 mi.cbSize = sizeof(mi); 2621 mi.uMax = 26; 2622 mi.fFlags = MRU_STRING; 2623 mi.hKey = hOpenSaveMRT; 2624 mi.lpszSubKey = defext; 2625 mi.u.string_cmpfn = lstrcmpiW; 2626 hList = (*s_pCreateMRUListW)(&mi); 2627 if (hList) 2628 { 2629 ret = (*s_pEnumMRUListW)(hList, 0, szText, sizeof(szText)); 2630 if (ret > 0) 2631 { 2632 lstrcpynW(stored_path, szText, cchMax); 2633 PathRemoveFileSpecW(stored_path); 2634 } 2635 (*s_pFreeMRUList)(hList); 2636 } 2637 2638 RegCloseKey(hOpenSaveMRT); 2639 } 2640 2641 if (stored_path[0] == 0) 2642 { 2643 LPITEMIDLIST pidl; 2644 if (ExtIsPicture(defext)) 2645 { 2646 SHGetSpecialFolderLocation(NULL, CSIDL_MYPICTURES, &pidl); 2647 } 2648 else 2649 { 2650 SHGetSpecialFolderLocation(NULL, CSIDL_MYDOCUMENTS, &pidl); 2651 } 2652 SHGetPathFromIDListW(pidl, stored_path); 2653 ILFree(pidl); 2654 } 2655 } 2656 2657 static void FILEDLG95_MRU_save_ext(LPCWSTR filename) 2658 { 2659 HKEY hOpenSaveMRT = NULL; 2660 LONG result; 2661 MRUINFOW mi; 2662 HANDLE hList; 2663 LPCWSTR defext = PathFindExtensionW(filename); 2664 2665 if (!defext || !*defext || !FILEDLG_InitMRUList()) 2666 { 2667 return; 2668 } 2669 2670 if (*defext == '.') 2671 ++defext; 2672 2673 result = RegOpenKeyW(HKEY_CURRENT_USER, s_subkey, &hOpenSaveMRT); 2674 if (!result && hOpenSaveMRT) 2675 { 2676 ZeroMemory(&mi, sizeof(mi)); 2677 mi.cbSize = sizeof(mi); 2678 mi.uMax = 26; 2679 mi.fFlags = MRU_STRING; 2680 mi.hKey = hOpenSaveMRT; 2681 mi.lpszSubKey = defext; 2682 mi.u.string_cmpfn = lstrcmpiW; 2683 hList = (*s_pCreateMRUListW)(&mi); 2684 if (hList) 2685 { 2686 (*s_pAddMRUStringW)(hList, filename); 2687 (*s_pFreeMRUList)(hList); 2688 } 2689 2690 mi.cbSize = sizeof(mi); 2691 mi.uMax = 26; 2692 mi.fFlags = MRU_STRING; 2693 mi.hKey = hOpenSaveMRT; 2694 mi.lpszSubKey = s_szAst; 2695 mi.u.string_cmpfn = lstrcmpiW; 2696 hList = (*s_pCreateMRUListW)(&mi); 2697 if (hList) 2698 { 2699 (*s_pAddMRUStringW)(hList, filename); 2700 (*s_pFreeMRUList)(hList); 2701 } 2702 2703 RegCloseKey(hOpenSaveMRT); 2704 } 2705 } 2706 2707 #endif /* __REACTOS__ */ 2708 2709 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText) 2710 { 2711 WCHAR strMsgTitle[MAX_PATH]; 2712 WCHAR strMsgText [MAX_PATH]; 2713 if (idCaption) 2714 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, ARRAY_SIZE(strMsgTitle)); 2715 else 2716 strMsgTitle[0] = '\0'; 2717 LoadStringW(COMDLG32_hInstance, idText, strMsgText, ARRAY_SIZE(strMsgText)); 2718 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND); 2719 } 2720 2721 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf, 2722 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction) 2723 { 2724 int nOpenAction = defAction; 2725 LPWSTR lpszTemp, lpszTemp1; 2726 LPITEMIDLIST pidl = NULL; 2727 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0}; 2728 2729 /* check for invalid chars */ 2730 if((wcspbrk(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE)) 2731 { 2732 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME); 2733 return FALSE; 2734 } 2735 2736 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE; 2737 2738 lpszTemp1 = lpszTemp = lpstrPathAndFile; 2739 while (lpszTemp1) 2740 { 2741 LPSHELLFOLDER lpsfChild; 2742 WCHAR lpwstrTemp[MAX_PATH]; 2743 DWORD dwEaten, dwAttributes; 2744 LPWSTR p; 2745 2746 lstrcpyW(lpwstrTemp, lpszTemp); 2747 p = PathFindNextComponentW(lpwstrTemp); 2748 2749 if (!p) break; /* end of path */ 2750 2751 *p = 0; 2752 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp); 2753 2754 /* There are no wildcards when OFN_NOVALIDATE is set */ 2755 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE)) 2756 { 2757 static const WCHAR wszWild[] = { '*', '?', 0 }; 2758 /* if the last element is a wildcard do a search */ 2759 if(wcspbrk(lpszTemp1, wszWild) != NULL) 2760 { 2761 nOpenAction = ONOPEN_SEARCH; 2762 break; 2763 } 2764 } 2765 lpszTemp1 = lpszTemp; 2766 2767 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf); 2768 2769 /* append a backslash to drive letters */ 2770 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' && 2771 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') || 2772 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z'))) 2773 { 2774 PathAddBackslashW(lpwstrTemp); 2775 } 2776 2777 dwAttributes = SFGAO_FOLDER; 2778 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes))) 2779 { 2780 /* the path component is valid, we have a pidl of the next path component */ 2781 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl); 2782 if(dwAttributes & SFGAO_FOLDER) 2783 { 2784 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild))) 2785 { 2786 ERR("bind to failed\n"); /* should not fail */ 2787 break; 2788 } 2789 IShellFolder_Release(*ppsf); 2790 *ppsf = lpsfChild; 2791 lpsfChild = NULL; 2792 } 2793 else 2794 { 2795 TRACE("value\n"); 2796 2797 /* end dialog, return value */ 2798 nOpenAction = ONOPEN_OPEN; 2799 break; 2800 } 2801 ILFree(pidl); 2802 pidl = NULL; 2803 } 2804 else if (!(flags & OFN_NOVALIDATE)) 2805 { 2806 if(*lpszTemp || /* points to trailing null for last path element */ 2807 (lpwstrTemp[lstrlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */ 2808 { 2809 if(flags & OFN_PATHMUSTEXIST) 2810 { 2811 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING); 2812 break; 2813 } 2814 } 2815 else 2816 { 2817 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg ) 2818 { 2819 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING); 2820 break; 2821 } 2822 } 2823 /* change to the current folder */ 2824 nOpenAction = ONOPEN_OPEN; 2825 break; 2826 } 2827 else 2828 { 2829 nOpenAction = ONOPEN_OPEN; 2830 break; 2831 } 2832 } 2833 ILFree(pidl); 2834 2835 return nOpenAction; 2836 } 2837 2838 /*********************************************************************** 2839 * FILEDLG95_OnOpen 2840 * 2841 * Ok button WM_COMMAND message handler 2842 * 2843 * If the function succeeds, the return value is nonzero. 2844 */ 2845 BOOL FILEDLG95_OnOpen(HWND hwnd) 2846 { 2847 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 2848 LPWSTR lpstrFileList; 2849 UINT nFileCount = 0; 2850 UINT sizeUsed = 0; 2851 BOOL ret = TRUE; 2852 WCHAR lpstrPathAndFile[MAX_PATH]; 2853 LPSHELLFOLDER lpsf = NULL; 2854 int nOpenAction; 2855 2856 TRACE("hwnd=%p\n", hwnd); 2857 2858 /* try to browse the selected item */ 2859 if(BrowseSelectedFolder(hwnd)) 2860 return FALSE; 2861 2862 /* get the files from the edit control */ 2863 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed); 2864 2865 if(nFileCount == 0) 2866 return FALSE; 2867 2868 if(nFileCount > 1) 2869 { 2870 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed); 2871 goto ret; 2872 } 2873 2874 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList)); 2875 2876 /* 2877 Step 1: Build a complete path name from the current folder and 2878 the filename or path in the edit box. 2879 Special cases: 2880 - the path in the edit box is a root path 2881 (with or without drive letter) 2882 - the edit box contains ".." (or a path with ".." in it) 2883 */ 2884 2885 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile); 2886 heap_free(lpstrFileList); 2887 2888 /* 2889 Step 2: here we have a cleaned up path 2890 2891 We have to parse the path step by step to see if we have to browse 2892 to a folder if the path points to a directory or the last 2893 valid element is a directory. 2894 2895 valid variables: 2896 lpstrPathAndFile: cleaned up path 2897 */ 2898 2899 if (nFileCount && 2900 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) && 2901 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST)) 2902 nOpenAction = ONOPEN_OPEN; 2903 else 2904 nOpenAction = ONOPEN_BROWSE; 2905 2906 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd, 2907 fodInfos->ofnInfos->Flags, 2908 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG, 2909 nOpenAction); 2910 if(!nOpenAction) 2911 goto ret; 2912 2913 /* 2914 Step 3: here we have a cleaned up and validated path 2915 2916 valid variables: 2917 lpsf: ShellFolder bound to the rightmost valid path component 2918 lpstrPathAndFile: cleaned up path 2919 nOpenAction: action to do 2920 */ 2921 TRACE("end validate sf=%p\n", lpsf); 2922 2923 switch(nOpenAction) 2924 { 2925 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */ 2926 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile)); 2927 { 2928 int iPos; 2929 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile); 2930 DWORD len; 2931 2932 /* replace the current filter */ 2933 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter); 2934 len = lstrlenW(lpszTemp)+1; 2935 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc(len * sizeof(WCHAR)); 2936 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp); 2937 2938 /* set the filter cb to the extension when possible */ 2939 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp))) 2940 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, iPos, 0); 2941 } 2942 /* fall through */ 2943 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */ 2944 TRACE("ONOPEN_BROWSE\n"); 2945 { 2946 IPersistFolder2 * ppf2; 2947 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2))) 2948 { 2949 LPITEMIDLIST pidlCurrent; 2950 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent); 2951 IPersistFolder2_Release(ppf2); 2952 if (!ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent)) 2953 { 2954 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)) 2955 && fodInfos->ofnInfos->Flags & OFN_EXPLORER) 2956 { 2957 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); 2958 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)""); 2959 } 2960 } 2961 else if( nOpenAction == ONOPEN_SEARCH ) 2962 { 2963 if (fodInfos->Shell.FOIShellView) 2964 IShellView_Refresh(fodInfos->Shell.FOIShellView); 2965 } 2966 ILFree(pidlCurrent); 2967 if (filename_is_edit( fodInfos )) 2968 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1); 2969 else 2970 { 2971 HWND hwnd; 2972 2973 hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0); 2974 SendMessageW(hwnd, EM_SETSEL, 0, -1); 2975 } 2976 } 2977 } 2978 ret = FALSE; 2979 break; 2980 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */ 2981 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile)); 2982 { 2983 WCHAR *ext = NULL; 2984 2985 /* update READONLY check box flag */ 2986 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED) 2987 fodInfos->ofnInfos->Flags |= OFN_READONLY; 2988 else 2989 fodInfos->ofnInfos->Flags &= ~OFN_READONLY; 2990 2991 /* Attach the file extension with file name*/ 2992 ext = PathFindExtensionW(lpstrPathAndFile); 2993 #ifdef __REACTOS__ 2994 { 2995 LPWSTR filterExt = NULL, lpstrFilter = NULL, pch, pchNext; 2996 LPCWSTR the_ext = NULL; 2997 static const WCHAR szwDot[] = {'.',0}; 2998 int PathLength = lstrlenW(lpstrPathAndFile); 2999 3000 /* get filter extensions */ 3001 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3002 fodInfos->ofnInfos->nFilterIndex - 1); 3003 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */ 3004 { 3005 LPWSTR filterSearchIndex, pchFirst = NULL; 3006 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR)); 3007 if (filterExt) 3008 { 3009 strcpyW(filterExt, lpstrFilter); 3010 3011 if (ext && *ext) 3012 { 3013 /* find ext in filter */ 3014 for (pch = filterExt; pch && *pch; pch = pchNext) 3015 { 3016 filterSearchIndex = strchrW(pch, ';'); 3017 if (filterSearchIndex) 3018 { 3019 filterSearchIndex[0] = 0; 3020 pchNext = filterSearchIndex + 1; 3021 } 3022 else 3023 { 3024 pchNext = NULL; 3025 } 3026 3027 while (*pch == '*' || *pch == '.' || *pch == '?') 3028 { 3029 ++pch; 3030 } 3031 3032 if (!pchFirst) 3033 pchFirst = pch; 3034 3035 if (lstrcmpiW(pch, &ext[1]) == 0) 3036 { 3037 the_ext = pch; 3038 break; 3039 } 3040 } 3041 3042 /* use first one if not found */ 3043 if (!the_ext && pchFirst && *pchFirst) 3044 { 3045 the_ext = pchFirst; 3046 } 3047 } 3048 } 3049 } 3050 3051 if (!the_ext) 3052 { 3053 /* use default extension if no extension in filter */ 3054 the_ext = fodInfos->defext; 3055 } 3056 3057 if (the_ext && *the_ext && lstrcmpiW(&ext[1], the_ext) != 0) 3058 { 3059 if (strlenW(lpstrPathAndFile) + 1 + strlenW(the_ext) + 1 <= 3060 fodInfos->ofnInfos->nMaxFile) 3061 { 3062 /* append the dot */ 3063 lstrcatW(lpstrPathAndFile, szwDot); 3064 /* append the extension */ 3065 lstrcatW(lpstrPathAndFile, the_ext); 3066 /* update ext */ 3067 ext = PathFindExtensionW(lpstrPathAndFile); 3068 } 3069 } 3070 3071 heap_free(filterExt); 3072 3073 /* In Open dialog: if file does not exist try without extension */ 3074 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile)) 3075 lpstrPathAndFile[PathLength] = 0; 3076 3077 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */ 3078 if (*ext) 3079 ext++; 3080 if (!lstrcmpiW(fodInfos->defext, ext)) 3081 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT; 3082 else 3083 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT; 3084 } 3085 3086 /* update dialog data */ 3087 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, PathFindFileNameW(lpstrPathAndFile)); 3088 #else /* __REACTOS__ */ 3089 if (! *ext && fodInfos->defext) 3090 { 3091 /* if no extension is specified with file name, then */ 3092 /* attach the extension from file filter or default one */ 3093 3094 WCHAR *filterExt = NULL; 3095 LPWSTR lpstrFilter = NULL; 3096 static const WCHAR szwDot[] = {'.',0}; 3097 int PathLength = lstrlenW(lpstrPathAndFile); 3098 3099 /*Get the file extension from file type filter*/ 3100 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3101 fodInfos->ofnInfos->nFilterIndex-1); 3102 3103 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */ 3104 { 3105 WCHAR* filterSearchIndex; 3106 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR)); 3107 lstrcpyW(filterExt, lpstrFilter); 3108 3109 /* if a semicolon-separated list of file extensions was given, do not include the 3110 semicolon or anything after it in the extension. 3111 example: if filterExt was "*.abc;*.def", it will become "*.abc" */ 3112 filterSearchIndex = wcschr(filterExt, ';'); 3113 if (filterSearchIndex) 3114 { 3115 filterSearchIndex[0] = '\0'; 3116 } 3117 3118 /* find the file extension by searching for the first dot in filterExt */ 3119 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */ 3120 /* if the extension is invalid or contains a glob, ignore it */ 3121 filterSearchIndex = wcschr(filterExt, '.'); 3122 if (filterSearchIndex++ && !wcschr(filterSearchIndex, '*') && !wcschr(filterSearchIndex, '?')) 3123 { 3124 lstrcpyW(filterExt, filterSearchIndex); 3125 } 3126 else 3127 { 3128 heap_free(filterExt); 3129 filterExt = NULL; 3130 } 3131 } 3132 3133 if (!filterExt) 3134 { 3135 /* use the default file extension */ 3136 filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR)); 3137 lstrcpyW(filterExt, fodInfos->defext); 3138 } 3139 3140 if (*filterExt) /* ignore filterExt="" */ 3141 { 3142 /* Attach the dot*/ 3143 lstrcatW(lpstrPathAndFile, szwDot); 3144 /* Attach the extension */ 3145 lstrcatW(lpstrPathAndFile, filterExt); 3146 } 3147 3148 heap_free(filterExt); 3149 3150 /* In Open dialog: if file does not exist try without extension */ 3151 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile)) 3152 lpstrPathAndFile[PathLength] = '\0'; 3153 3154 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */ 3155 if (*ext) 3156 ext++; 3157 if (!lstrcmpiW(fodInfos->defext, ext)) 3158 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT; 3159 else 3160 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT; 3161 } 3162 #endif /* __REACTOS__ */ 3163 3164 /* In Save dialog: check if the file already exists */ 3165 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG 3166 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT 3167 && PathFileExistsW(lpstrPathAndFile)) 3168 { 3169 WCHAR lpstrOverwrite[100]; 3170 int answer; 3171 3172 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100); 3173 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title, 3174 MB_YESNO | MB_ICONEXCLAMATION); 3175 if (answer == IDNO || answer == IDCANCEL) 3176 { 3177 ret = FALSE; 3178 goto ret; 3179 } 3180 } 3181 3182 /* In Open dialog: check if it should be created if it doesn't exist */ 3183 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) 3184 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT 3185 && !PathFileExistsW(lpstrPathAndFile)) 3186 { 3187 WCHAR lpstrCreate[100]; 3188 int answer; 3189 3190 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100); 3191 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title, 3192 MB_YESNO | MB_ICONEXCLAMATION); 3193 if (answer == IDNO || answer == IDCANCEL) 3194 { 3195 ret = FALSE; 3196 goto ret; 3197 } 3198 } 3199 3200 /* Check that the size of the file does not exceed buffer size. 3201 (Allow for extra \0 if OFN_MULTISELECT is set.) */ 3202 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile - 3203 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0)) 3204 { 3205 3206 /* fill destination buffer */ 3207 if (fodInfos->ofnInfos->lpstrFile) 3208 { 3209 if(fodInfos->unicode) 3210 { 3211 LPOPENFILENAMEW ofn = fodInfos->ofnInfos; 3212 3213 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile); 3214 if (ofn->Flags & OFN_ALLOWMULTISELECT) 3215 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0'; 3216 } 3217 else 3218 { 3219 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; 3220 3221 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1, 3222 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL); 3223 if (ofn->Flags & OFN_ALLOWMULTISELECT) 3224 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0'; 3225 } 3226 } 3227 3228 if(fodInfos->unicode) 3229 { 3230 LPWSTR lpszTemp; 3231 3232 /* set filename offset */ 3233 lpszTemp = PathFindFileNameW(lpstrPathAndFile); 3234 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile); 3235 3236 /* set extension offset */ 3237 lpszTemp = PathFindExtensionW(lpstrPathAndFile); 3238 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0; 3239 } 3240 else 3241 { 3242 LPSTR lpszTemp; 3243 CHAR tempFileA[MAX_PATH]; 3244 3245 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */ 3246 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1, 3247 tempFileA, sizeof(tempFileA), NULL, NULL); 3248 3249 /* set filename offset */ 3250 lpszTemp = PathFindFileNameA(tempFileA); 3251 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA); 3252 3253 /* set extension offset */ 3254 lpszTemp = PathFindExtensionA(tempFileA); 3255 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0; 3256 } 3257 3258 /* copy currently selected filter to lpstrCustomFilter */ 3259 if (fodInfos->ofnInfos->lpstrCustomFilter) 3260 { 3261 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; 3262 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1, 3263 NULL, 0, NULL, NULL); 3264 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter) 3265 { 3266 LPSTR s = ofn->lpstrCustomFilter; 3267 s += strlen(ofn->lpstrCustomFilter)+1; 3268 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1, 3269 s, len, NULL, NULL); 3270 } 3271 } 3272 3273 3274 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) ) 3275 goto ret; 3276 3277 FILEDLG95_MRU_save_filename(lpstrPathAndFile); 3278 #ifdef __REACTOS__ 3279 FILEDLG95_MRU_save_ext(lpstrPathAndFile); 3280 #endif 3281 3282 TRACE("close\n"); 3283 FILEDLG95_Clean(hwnd); 3284 ret = EndDialog(hwnd, TRUE); 3285 } 3286 else 3287 { 3288 WORD size; 3289 3290 size = lstrlenW(lpstrPathAndFile) + 1; 3291 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) 3292 size += 1; 3293 /* return needed size in first two bytes of lpstrFile */ 3294 if(fodInfos->ofnInfos->lpstrFile) 3295 *(WORD *)fodInfos->ofnInfos->lpstrFile = size; 3296 FILEDLG95_Clean(hwnd); 3297 ret = EndDialog(hwnd, FALSE); 3298 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL); 3299 } 3300 } 3301 break; 3302 } 3303 3304 ret: 3305 if(lpsf) IShellFolder_Release(lpsf); 3306 return ret; 3307 } 3308 3309 /*********************************************************************** 3310 * FILEDLG95_SHELL_Init 3311 * 3312 * Initialisation of the shell objects 3313 */ 3314 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd) 3315 { 3316 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3317 3318 TRACE("%p\n", hwnd); 3319 3320 /* 3321 * Initialisation of the FileOpenDialogInfos structure 3322 */ 3323 3324 /* Shell */ 3325 3326 /*ShellInfos */ 3327 fodInfos->ShellInfos.hwndOwner = hwnd; 3328 3329 /* Disable multi-select if flag not set */ 3330 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)) 3331 { 3332 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL; 3333 } 3334 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT; 3335 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST; 3336 3337 /* Construct the IShellBrowser interface */ 3338 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd); 3339 3340 return NOERROR; 3341 } 3342 3343 /*********************************************************************** 3344 * FILEDLG95_SHELL_ExecuteCommand 3345 * 3346 * Change the folder option and refresh the view 3347 * If the function succeeds, the return value is nonzero. 3348 */ 3349 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb) 3350 { 3351 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3352 IContextMenu * pcm; 3353 3354 TRACE("(%p,%p)\n", hwnd, lpVerb); 3355 3356 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView, 3357 SVGIO_BACKGROUND, 3358 &IID_IContextMenu, 3359 (LPVOID*)&pcm))) 3360 { 3361 CMINVOKECOMMANDINFO ci; 3362 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO)); 3363 ci.cbSize = sizeof(CMINVOKECOMMANDINFO); 3364 ci.lpVerb = lpVerb; 3365 ci.hwnd = hwnd; 3366 3367 IContextMenu_InvokeCommand(pcm, &ci); 3368 IContextMenu_Release(pcm); 3369 } 3370 3371 return FALSE; 3372 } 3373 3374 /*********************************************************************** 3375 * FILEDLG95_SHELL_UpFolder 3376 * 3377 * Browse to the specified object 3378 * If the function succeeds, the return value is nonzero. 3379 */ 3380 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd) 3381 { 3382 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3383 3384 TRACE("\n"); 3385 3386 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, 3387 NULL, 3388 SBSP_PARENT))) 3389 { 3390 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 3391 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); 3392 return TRUE; 3393 } 3394 return FALSE; 3395 } 3396 /*********************************************************************** 3397 * FILEDLG95_SHELL_Clean 3398 * 3399 * Cleans the memory used by shell objects 3400 */ 3401 static void FILEDLG95_SHELL_Clean(HWND hwnd) 3402 { 3403 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3404 3405 TRACE("\n"); 3406 3407 ILFree(fodInfos->ShellInfos.pidlAbsCurrent); 3408 3409 /* clean Shell interfaces */ 3410 if (fodInfos->Shell.FOIShellView) 3411 { 3412 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView); 3413 IShellView_Release(fodInfos->Shell.FOIShellView); 3414 } 3415 if (fodInfos->Shell.FOIShellFolder) 3416 IShellFolder_Release(fodInfos->Shell.FOIShellFolder); 3417 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser); 3418 if (fodInfos->Shell.FOIDataObject) 3419 IDataObject_Release(fodInfos->Shell.FOIDataObject); 3420 } 3421 3422 /*********************************************************************** 3423 * FILEDLG95_FILETYPE_Init 3424 * 3425 * Initialisation of the file type combo box 3426 */ 3427 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd) 3428 { 3429 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3430 int nFilters = 0; /* number of filters */ 3431 int nFilterIndexCB; 3432 3433 TRACE("%p\n", hwnd); 3434 3435 if(fodInfos->customfilter) 3436 { 3437 /* customfilter has one entry... title\0ext\0 3438 * Set first entry of combo box item with customfilter 3439 */ 3440 LPWSTR lpstrExt; 3441 LPCWSTR lpstrPos = fodInfos->customfilter; 3442 3443 /* Get the title */ 3444 lpstrPos += lstrlenW(fodInfos->customfilter) + 1; 3445 3446 /* Copy the extensions */ 3447 if (! *lpstrPos) return E_FAIL; /* malformed filter */ 3448 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL; 3449 lstrcpyW(lpstrExt,lpstrPos); 3450 3451 /* Add the item at the end of the combo */ 3452 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter); 3453 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt); 3454 3455 nFilters++; 3456 } 3457 if(fodInfos->filter) 3458 { 3459 LPCWSTR lpstrPos = fodInfos->filter; 3460 3461 for(;;) 3462 { 3463 /* filter is a list... title\0ext\0......\0\0 3464 * Set the combo item text to the title and the item data 3465 * to the ext 3466 */ 3467 LPCWSTR lpstrDisplay; 3468 LPWSTR lpstrExt; 3469 3470 /* Get the title */ 3471 if(! *lpstrPos) break; /* end */ 3472 lpstrDisplay = lpstrPos; 3473 lpstrPos += lstrlenW(lpstrPos) + 1; 3474 3475 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay); 3476 3477 nFilters++; 3478 3479 /* Copy the extensions */ 3480 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL; 3481 lstrcpyW(lpstrExt,lpstrPos); 3482 lpstrPos += lstrlenW(lpstrPos) + 1; 3483 3484 /* Add the item at the end of the combo */ 3485 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt); 3486 3487 /* malformed filters are added anyway... */ 3488 if (!*lpstrExt) break; 3489 } 3490 } 3491 3492 /* 3493 * Set the current filter to the one specified 3494 * in the initialisation structure 3495 */ 3496 if (fodInfos->filter || fodInfos->customfilter) 3497 { 3498 LPWSTR lpstrFilter; 3499 3500 /* Check to make sure our index isn't out of bounds. */ 3501 if ( fodInfos->ofnInfos->nFilterIndex > 3502 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) ) 3503 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0); 3504 3505 /* set default filter index */ 3506 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL) 3507 fodInfos->ofnInfos->nFilterIndex = 1; 3508 3509 /* calculate index of Combo Box item */ 3510 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex; 3511 if (fodInfos->customfilter == NULL) 3512 nFilterIndexCB--; 3513 3514 /* Set the current index selection. */ 3515 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0); 3516 3517 /* Get the corresponding text string from the combo box. */ 3518 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3519 nFilterIndexCB); 3520 3521 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */ 3522 lpstrFilter = NULL; 3523 3524 if(lpstrFilter) 3525 { 3526 DWORD len; 3527 CharLowerW(lpstrFilter); /* lowercase */ 3528 len = lstrlenW(lpstrFilter)+1; 3529 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) ); 3530 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter); 3531 } 3532 } else 3533 fodInfos->ofnInfos->nFilterIndex = 0; 3534 return S_OK; 3535 } 3536 3537 /*********************************************************************** 3538 * FILEDLG95_FILETYPE_OnCommand 3539 * 3540 * WM_COMMAND of the file type combo box 3541 * If the function succeeds, the return value is nonzero. 3542 */ 3543 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode) 3544 { 3545 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3546 3547 switch(wNotifyCode) 3548 { 3549 case CBN_SELENDOK: 3550 { 3551 LPWSTR lpstrFilter; 3552 3553 /* Get the current item of the filetype combo box */ 3554 int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0); 3555 3556 /* set the current filter index */ 3557 fodInfos->ofnInfos->nFilterIndex = iItem + 3558 (fodInfos->customfilter == NULL ? 1 : 0); 3559 3560 /* Set the current filter with the current selection */ 3561 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter); 3562 3563 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3564 iItem); 3565 if((INT_PTR)lpstrFilter != CB_ERR) 3566 { 3567 DWORD len; 3568 CharLowerW(lpstrFilter); /* lowercase */ 3569 len = lstrlenW(lpstrFilter)+1; 3570 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) ); 3571 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter); 3572 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 3573 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE); 3574 } 3575 3576 /* Refresh the actual view to display the included items*/ 3577 if (fodInfos->Shell.FOIShellView) 3578 IShellView_Refresh(fodInfos->Shell.FOIShellView); 3579 } 3580 } 3581 return FALSE; 3582 } 3583 /*********************************************************************** 3584 * FILEDLG95_FILETYPE_SearchExt 3585 * 3586 * searches for an extension in the filetype box 3587 */ 3588 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt) 3589 { 3590 int i, iCount; 3591 3592 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0); 3593 3594 TRACE("%s\n", debugstr_w(lpstrExt)); 3595 3596 if(iCount != CB_ERR) 3597 { 3598 for(i=0;i<iCount;i++) 3599 { 3600 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i))) 3601 return i; 3602 } 3603 } 3604 return -1; 3605 } 3606 3607 /*********************************************************************** 3608 * FILEDLG95_FILETYPE_Clean 3609 * 3610 * Clean the memory used by the filetype combo box 3611 */ 3612 static void FILEDLG95_FILETYPE_Clean(HWND hwnd) 3613 { 3614 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3615 int iPos; 3616 int iCount; 3617 3618 iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0); 3619 3620 TRACE("\n"); 3621 3622 /* Delete each string of the combo and their associated data */ 3623 if(iCount != CB_ERR) 3624 { 3625 for(iPos = iCount-1;iPos>=0;iPos--) 3626 { 3627 heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos)); 3628 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0); 3629 } 3630 } 3631 /* Current filter */ 3632 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter); 3633 } 3634 3635 /*********************************************************************** 3636 * FILEDLG95_LOOKIN_Init 3637 * 3638 * Initialisation of the look in combo box 3639 */ 3640 3641 /* Small helper function, to determine if the unixfs shell extension is rooted 3642 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 3643 */ 3644 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) { 3645 HKEY hKey; 3646 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\', 3647 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', 3648 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 3649 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\', 3650 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8', 3651 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-', 3652 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 }; 3653 3654 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 3655 return FALSE; 3656 3657 RegCloseKey(hKey); 3658 return TRUE; 3659 } 3660 3661 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo) 3662 { 3663 IShellFolder *psfRoot, *psfDrives; 3664 IEnumIDList *lpeRoot, *lpeDrives; 3665 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp; 3666 HDC hdc; 3667 TEXTMETRICW tm; 3668 LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos)); 3669 3670 TRACE("%p\n", hwndCombo); 3671 3672 liInfos->iMaxIndentation = 0; 3673 3674 SetPropA(hwndCombo, LookInInfosStr, liInfos); 3675 3676 hdc = GetDC( hwndCombo ); 3677 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 )); 3678 GetTextMetricsW( hdc, &tm ); 3679 ReleaseDC( hwndCombo, hdc ); 3680 3681 /* set item height for both text field and listbox */ 3682 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON))); 3683 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON))); 3684 3685 /* Turn on the extended UI for the combo box like Windows does */ 3686 SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0); 3687 3688 /* Initialise data of Desktop folder */ 3689 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp); 3690 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND); 3691 ILFree(pidlTmp); 3692 3693 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives); 3694 3695 SHGetDesktopFolder(&psfRoot); 3696 3697 if (psfRoot) 3698 { 3699 /* enumerate the contents of the desktop */ 3700 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot))) 3701 { 3702 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL)) 3703 { 3704 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND); 3705 3706 /* If the unixfs extension is rooted, we don't expand the drives by default */ 3707 if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 3708 { 3709 /* special handling for CSIDL_DRIVES */ 3710 if (ILIsEqual(pidlTmp, pidlDrives)) 3711 { 3712 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives))) 3713 { 3714 /* enumerate the drives */ 3715 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives))) 3716 { 3717 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL)) 3718 { 3719 pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1); 3720 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND); 3721 ILFree(pidlAbsTmp); 3722 ILFree(pidlTmp1); 3723 } 3724 IEnumIDList_Release(lpeDrives); 3725 } 3726 IShellFolder_Release(psfDrives); 3727 } 3728 } 3729 } 3730 3731 ILFree(pidlTmp); 3732 } 3733 IEnumIDList_Release(lpeRoot); 3734 } 3735 IShellFolder_Release(psfRoot); 3736 } 3737 3738 ILFree(pidlDrives); 3739 } 3740 3741 /*********************************************************************** 3742 * FILEDLG95_LOOKIN_DrawItem 3743 * 3744 * WM_DRAWITEM message handler 3745 */ 3746 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct) 3747 { 3748 COLORREF crWin = GetSysColor(COLOR_WINDOW); 3749 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT); 3750 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT); 3751 RECT rectText; 3752 RECT rectIcon; 3753 SHFILEINFOW sfi; 3754 HIMAGELIST ilItemImage; 3755 int iIndentation; 3756 TEXTMETRICW tm; 3757 LPSFOLDER tmpFolder; 3758 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME; 3759 UINT icon_width, icon_height; 3760 3761 TRACE("\n"); 3762 3763 if(pDIStruct->itemID == -1) 3764 return 0; 3765 3766 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem, 3767 pDIStruct->itemID))) 3768 return 0; 3769 3770 3771 icon_width = GetSystemMetrics(SM_CXICON); 3772 icon_height = GetSystemMetrics(SM_CYICON); 3773 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height) 3774 { 3775 icon_width = GetSystemMetrics(SM_CXSMICON); 3776 icon_height = GetSystemMetrics(SM_CYSMICON); 3777 shgfi_flags |= SHGFI_SMALLICON; 3778 } 3779 3780 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem, 3781 0, &sfi, sizeof (sfi), shgfi_flags ); 3782 3783 /* Is this item selected ? */ 3784 if(pDIStruct->itemState & ODS_SELECTED) 3785 { 3786 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText))); 3787 SetBkColor(pDIStruct->hDC,crHighLight); 3788 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT)); 3789 } 3790 else 3791 { 3792 SetTextColor(pDIStruct->hDC,crText); 3793 SetBkColor(pDIStruct->hDC,crWin); 3794 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW)); 3795 } 3796 3797 /* Do not indent item if drawing in the edit of the combo */ 3798 if(pDIStruct->itemState & ODS_COMBOBOXEDIT) 3799 iIndentation = 0; 3800 else 3801 iIndentation = tmpFolder->m_iIndent; 3802 3803 /* Draw text and icon */ 3804 3805 /* Initialise the icon display area */ 3806 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation; 3807 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2; 3808 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET; 3809 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2; 3810 3811 /* Initialise the text display area */ 3812 GetTextMetricsW(pDIStruct->hDC, &tm); 3813 rectText.left = rectIcon.right; 3814 rectText.top = 3815 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2; 3816 rectText.right = pDIStruct->rcItem.right; 3817 rectText.bottom = 3818 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2; 3819 3820 /* Draw the icon from the image list */ 3821 ImageList_Draw(ilItemImage, 3822 sfi.iIcon, 3823 pDIStruct->hDC, 3824 rectIcon.left, 3825 rectIcon.top, 3826 ILD_TRANSPARENT ); 3827 3828 /* Draw the associated text */ 3829 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName)); 3830 return NOERROR; 3831 } 3832 3833 /*********************************************************************** 3834 * FILEDLG95_LOOKIN_OnCommand 3835 * 3836 * LookIn combo box WM_COMMAND message handler 3837 * If the function succeeds, the return value is nonzero. 3838 */ 3839 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode) 3840 { 3841 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3842 3843 TRACE("%p\n", fodInfos); 3844 3845 switch(wNotifyCode) 3846 { 3847 case CBN_SELENDOK: 3848 { 3849 LPSFOLDER tmpFolder; 3850 int iItem; 3851 3852 iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0); 3853 3854 if( iItem == CB_ERR) return FALSE; 3855 3856 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB, 3857 iItem))) 3858 return FALSE; 3859 3860 3861 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, 3862 tmpFolder->pidlItem, 3863 SBSP_ABSOLUTE))) 3864 { 3865 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 3866 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); 3867 return TRUE; 3868 } 3869 break; 3870 } 3871 3872 } 3873 return FALSE; 3874 } 3875 3876 /*********************************************************************** 3877 * FILEDLG95_LOOKIN_AddItem 3878 * 3879 * Adds an absolute pidl item to the lookin combo box 3880 * returns the index of the inserted item 3881 */ 3882 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId) 3883 { 3884 LPITEMIDLIST pidlNext; 3885 SHFILEINFOW sfi; 3886 SFOLDER *tmpFolder; 3887 LookInInfos *liInfos; 3888 3889 TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId); 3890 3891 if(!pidl) 3892 return -1; 3893 3894 if(!(liInfos = GetPropA(hwnd,LookInInfosStr))) 3895 return -1; 3896 3897 tmpFolder = heap_alloc_zero(sizeof(*tmpFolder)); 3898 tmpFolder->m_iIndent = 0; 3899 3900 /* Calculate the indentation of the item in the lookin*/ 3901 pidlNext = pidl; 3902 while ((pidlNext = ILGetNext(pidlNext))) 3903 { 3904 tmpFolder->m_iIndent++; 3905 } 3906 3907 tmpFolder->pidlItem = ILClone(pidl); 3908 3909 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation) 3910 liInfos->iMaxIndentation = tmpFolder->m_iIndent; 3911 3912 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM; 3913 SHGetFileInfoW((LPCWSTR)pidl, 3914 0, 3915 &sfi, 3916 sizeof(sfi), 3917 SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED); 3918 3919 TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes); 3920 3921 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM)) 3922 { 3923 int iItemID; 3924 3925 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent); 3926 3927 /* Add the item at the end of the list */ 3928 if(iInsertId < 0) 3929 { 3930 iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName); 3931 } 3932 /* Insert the item at the iInsertId position*/ 3933 else 3934 { 3935 iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName); 3936 } 3937 3938 SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder); 3939 return iItemID; 3940 } 3941 3942 ILFree( tmpFolder->pidlItem ); 3943 heap_free( tmpFolder ); 3944 return -1; 3945 3946 } 3947 3948 /*********************************************************************** 3949 * FILEDLG95_LOOKIN_InsertItemAfterParent 3950 * 3951 * Insert an item below its parent 3952 */ 3953 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl) 3954 { 3955 3956 LPITEMIDLIST pidlParent = GetParentPidl(pidl); 3957 int iParentPos; 3958 3959 TRACE("\n"); 3960 3961 if (pidl == pidlParent) 3962 return -1; 3963 3964 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL); 3965 3966 if(iParentPos < 0) 3967 { 3968 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent); 3969 } 3970 3971 ILFree(pidlParent); 3972 3973 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1); 3974 } 3975 3976 /*********************************************************************** 3977 * FILEDLG95_LOOKIN_SelectItem 3978 * 3979 * Adds an absolute pidl item to the lookin combo box 3980 * returns the index of the inserted item 3981 */ 3982 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl) 3983 { 3984 int iItemPos; 3985 LookInInfos *liInfos; 3986 3987 TRACE("%p, %p\n", hwnd, pidl); 3988 3989 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL); 3990 3991 liInfos = GetPropA(hwnd,LookInInfosStr); 3992 3993 if(iItemPos < 0) 3994 { 3995 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1); 3996 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl); 3997 } 3998 3999 else 4000 { 4001 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos); 4002 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent) 4003 { 4004 int iRemovedItem; 4005 4006 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd))) 4007 break; 4008 if(iRemovedItem < iItemPos) 4009 iItemPos--; 4010 } 4011 } 4012 4013 SendMessageW(hwnd, CB_SETCURSEL, iItemPos, 0); 4014 liInfos->uSelectedItem = iItemPos; 4015 4016 return 0; 4017 4018 } 4019 4020 /*********************************************************************** 4021 * FILEDLG95_LOOKIN_RemoveMostExpandedItem 4022 * 4023 * Remove the item with an expansion level over iExpansionLevel 4024 */ 4025 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd) 4026 { 4027 int iItemPos; 4028 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr); 4029 4030 TRACE("\n"); 4031 4032 if(liInfos->iMaxIndentation <= 2) 4033 return -1; 4034 4035 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0) 4036 { 4037 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos); 4038 ILFree(tmpFolder->pidlItem); 4039 heap_free(tmpFolder); 4040 SendMessageW(hwnd, CB_DELETESTRING, iItemPos, 0); 4041 liInfos->iMaxIndentation--; 4042 4043 return iItemPos; 4044 } 4045 4046 return -1; 4047 } 4048 4049 /*********************************************************************** 4050 * FILEDLG95_LOOKIN_SearchItem 4051 * 4052 * Search for pidl in the lookin combo box 4053 * returns the index of the found item 4054 */ 4055 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod) 4056 { 4057 int i = 0; 4058 int iCount; 4059 4060 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0); 4061 4062 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod); 4063 4064 if (iCount != CB_ERR) 4065 { 4066 for(;i<iCount;i++) 4067 { 4068 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i); 4069 4070 if (iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg, tmpFolder->pidlItem)) 4071 return i; 4072 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg) 4073 return i; 4074 } 4075 } 4076 4077 return -1; 4078 } 4079 4080 /*********************************************************************** 4081 * FILEDLG95_LOOKIN_Clean 4082 * 4083 * Clean the memory used by the lookin combo box 4084 */ 4085 static void FILEDLG95_LOOKIN_Clean(HWND hwnd) 4086 { 4087 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4088 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr); 4089 int iPos, iCount; 4090 4091 iCount = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCOUNT, 0, 0); 4092 4093 TRACE("\n"); 4094 4095 /* Delete each string of the combo and their associated data */ 4096 if (iCount != CB_ERR) 4097 { 4098 for(iPos = iCount-1;iPos>=0;iPos--) 4099 { 4100 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos); 4101 ILFree(tmpFolder->pidlItem); 4102 heap_free(tmpFolder); 4103 SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_DELETESTRING, iPos, 0); 4104 } 4105 } 4106 4107 /* LookInInfos structure */ 4108 heap_free(liInfos); 4109 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr); 4110 } 4111 4112 /*********************************************************************** 4113 * get_def_format 4114 * 4115 * Fill the FORMATETC used in the shell id list 4116 */ 4117 static FORMATETC get_def_format(void) 4118 { 4119 static CLIPFORMAT cfFormat; 4120 FORMATETC formatetc; 4121 4122 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA); 4123 formatetc.cfFormat = cfFormat; 4124 formatetc.ptd = 0; 4125 formatetc.dwAspect = DVASPECT_CONTENT; 4126 formatetc.lindex = -1; 4127 formatetc.tymed = TYMED_HGLOBAL; 4128 return formatetc; 4129 } 4130 4131 /*********************************************************************** 4132 * FILEDLG95_FILENAME_FillFromSelection 4133 * 4134 * fills the edit box from the cached DataObject 4135 */ 4136 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd) 4137 { 4138 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4139 LPITEMIDLIST pidl; 4140 LPWSTR lpstrAllFiles, lpstrTmp; 4141 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength; 4142 STGMEDIUM medium; 4143 LPIDA cida; 4144 FORMATETC formatetc = get_def_format(); 4145 4146 TRACE("\n"); 4147 4148 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium))) 4149 return; 4150 4151 cida = GlobalLock(medium.u.hGlobal); 4152 nFileSelected = cida->cidl; 4153 4154 /* Allocate a buffer */ 4155 nAllFilesMaxLength = MAX_PATH + 3; 4156 lpstrAllFiles = heap_alloc_zero(nAllFilesMaxLength * sizeof(WCHAR)); 4157 if (!lpstrAllFiles) 4158 goto ret; 4159 4160 /* Loop through the selection, handle only files (not folders) */ 4161 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++) 4162 { 4163 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]); 4164 if (pidl) 4165 { 4166 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) 4167 { 4168 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength) 4169 { 4170 nAllFilesMaxLength *= 2; 4171 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR)); 4172 if (!lpstrTmp) 4173 goto ret; 4174 lpstrAllFiles = lpstrTmp; 4175 } 4176 nFiles += 1; 4177 lpstrAllFiles[nAllFilesLength++] = '"'; 4178 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength); 4179 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength); 4180 nAllFilesLength += nThisFileLength; 4181 lpstrAllFiles[nAllFilesLength++] = '"'; 4182 lpstrAllFiles[nAllFilesLength++] = ' '; 4183 } 4184 } 4185 } 4186 4187 if (nFiles != 0) 4188 { 4189 /* If there's only one file, use the name as-is without quotes */ 4190 lpstrTmp = lpstrAllFiles; 4191 if (nFiles == 1) 4192 { 4193 lpstrTmp += 1; 4194 lpstrTmp[nThisFileLength] = 0; 4195 } 4196 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp); 4197 /* Select the file name like Windows does */ 4198 if (filename_is_edit(fodInfos)) 4199 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1); 4200 } 4201 4202 ret: 4203 heap_free(lpstrAllFiles); 4204 COMCTL32_ReleaseStgMedium(medium); 4205 } 4206 4207 4208 /* copied from shell32 to avoid linking to it 4209 * Although shell32 is already linked the behaviour of exported StrRetToStrN 4210 * is dependent on whether emulated OS is unicode or not. 4211 */ 4212 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl) 4213 { 4214 switch (src->uType) 4215 { 4216 case STRRET_WSTR: 4217 lstrcpynW(dest, src->u.pOleStr, len); 4218 CoTaskMemFree(src->u.pOleStr); 4219 break; 4220 4221 case STRRET_CSTR: 4222 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len) 4223 dest[len-1] = 0; 4224 break; 4225 4226 case STRRET_OFFSET: 4227 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len) 4228 dest[len-1] = 0; 4229 break; 4230 4231 default: 4232 FIXME("unknown type %x!\n", src->uType); 4233 if (len) *dest = '\0'; 4234 return E_FAIL; 4235 } 4236 return S_OK; 4237 } 4238 4239 /*********************************************************************** 4240 * FILEDLG95_FILENAME_GetFileNames 4241 * 4242 * Copies the filenames to a delimited string list. 4243 */ 4244 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed) 4245 { 4246 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4247 UINT nFileCount = 0; /* number of files */ 4248 UINT nStrLen = 0; /* length of string in edit control */ 4249 LPWSTR lpstrEdit; /* buffer for string from edit control */ 4250 4251 TRACE("\n"); 4252 4253 /* get the filenames from the filename control */ 4254 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName ); 4255 lpstrEdit = heap_alloc( (nStrLen+1)*sizeof(WCHAR) ); 4256 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1); 4257 4258 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit)); 4259 4260 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed); 4261 heap_free(lpstrEdit); 4262 return nFileCount; 4263 } 4264 4265 /* 4266 * DATAOBJECT Helper functions 4267 */ 4268 4269 /*********************************************************************** 4270 * COMCTL32_ReleaseStgMedium 4271 * 4272 * like ReleaseStgMedium from ole32 4273 */ 4274 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium) 4275 { 4276 if(medium.pUnkForRelease) 4277 { 4278 IUnknown_Release(medium.pUnkForRelease); 4279 } 4280 else 4281 { 4282 GlobalUnlock(medium.u.hGlobal); 4283 GlobalFree(medium.u.hGlobal); 4284 } 4285 } 4286 4287 /*********************************************************************** 4288 * GetPidlFromDataObject 4289 * 4290 * Return pidl(s) by number from the cached DataObject 4291 * 4292 * nPidlIndex=0 gets the fully qualified root path 4293 */ 4294 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex) 4295 { 4296 4297 STGMEDIUM medium; 4298 FORMATETC formatetc = get_def_format(); 4299 LPITEMIDLIST pidl = NULL; 4300 4301 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex); 4302 4303 if (!doSelected) 4304 return NULL; 4305 4306 /* Get the pidls from IDataObject */ 4307 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium))) 4308 { 4309 LPIDA cida = GlobalLock(medium.u.hGlobal); 4310 if(nPidlIndex <= cida->cidl) 4311 { 4312 pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]])); 4313 } 4314 COMCTL32_ReleaseStgMedium(medium); 4315 } 4316 return pidl; 4317 } 4318 4319 /*********************************************************************** 4320 * GetNumSelected 4321 * 4322 * Return the number of selected items in the DataObject. 4323 * 4324 */ 4325 static UINT GetNumSelected( IDataObject *doSelected ) 4326 { 4327 UINT retVal = 0; 4328 STGMEDIUM medium; 4329 FORMATETC formatetc = get_def_format(); 4330 4331 TRACE("sv=%p\n", doSelected); 4332 4333 if (!doSelected) return 0; 4334 4335 /* Get the pidls from IDataObject */ 4336 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium))) 4337 { 4338 LPIDA cida = GlobalLock(medium.u.hGlobal); 4339 retVal = cida->cidl; 4340 COMCTL32_ReleaseStgMedium(medium); 4341 return retVal; 4342 } 4343 return 0; 4344 } 4345 4346 /* 4347 * TOOLS 4348 */ 4349 4350 /*********************************************************************** 4351 * GetName 4352 * 4353 * Get the pidl's display name (relative to folder) and 4354 * put it in lpstrFileName. 4355 * 4356 * Return NOERROR on success, 4357 * E_FAIL otherwise 4358 */ 4359 4360 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName) 4361 { 4362 STRRET str; 4363 HRESULT hRes; 4364 4365 TRACE("sf=%p pidl=%p\n", lpsf, pidl); 4366 4367 if(!lpsf) 4368 { 4369 SHGetDesktopFolder(&lpsf); 4370 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName); 4371 IShellFolder_Release(lpsf); 4372 return hRes; 4373 } 4374 4375 /* Get the display name of the pidl relative to the folder */ 4376 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str))) 4377 { 4378 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl); 4379 } 4380 return E_FAIL; 4381 } 4382 4383 /*********************************************************************** 4384 * GetShellFolderFromPidl 4385 * 4386 * pidlRel is the item pidl relative 4387 * Return the IShellFolder of the absolute pidl 4388 */ 4389 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs) 4390 { 4391 IShellFolder *psf = NULL,*psfParent; 4392 4393 TRACE("%p\n", pidlAbs); 4394 4395 if(SUCCEEDED(SHGetDesktopFolder(&psfParent))) 4396 { 4397 psf = psfParent; 4398 if(pidlAbs && pidlAbs->mkid.cb) 4399 { 4400 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf))) 4401 { 4402 IShellFolder_Release(psfParent); 4403 return psf; 4404 } 4405 } 4406 /* return the desktop */ 4407 return psfParent; 4408 } 4409 return NULL; 4410 } 4411 4412 /*********************************************************************** 4413 * GetParentPidl 4414 * 4415 * Return the LPITEMIDLIST to the parent of the pidl in the list 4416 */ 4417 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl) 4418 { 4419 LPITEMIDLIST pidlParent; 4420 4421 TRACE("%p\n", pidl); 4422 4423 pidlParent = ILClone(pidl); 4424 ILRemoveLastID(pidlParent); 4425 4426 return pidlParent; 4427 } 4428 4429 /*********************************************************************** 4430 * GetPidlFromName 4431 * 4432 * returns the pidl of the file name relative to folder 4433 * NULL if an error occurred 4434 */ 4435 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName) 4436 { 4437 LPITEMIDLIST pidl = NULL; 4438 ULONG ulEaten; 4439 4440 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName)); 4441 4442 if(!lpcstrFileName) return NULL; 4443 if(!*lpcstrFileName) return NULL; 4444 4445 if(!lpsf) 4446 { 4447 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) { 4448 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL); 4449 IShellFolder_Release(lpsf); 4450 } 4451 } 4452 else 4453 { 4454 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL); 4455 } 4456 return pidl; 4457 } 4458 4459 /* 4460 */ 4461 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl) 4462 { 4463 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER; 4464 HRESULT ret; 4465 4466 TRACE("%p, %p\n", psf, pidl); 4467 4468 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr ); 4469 4470 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret); 4471 /* see documentation shell 4.1*/ 4472 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER); 4473 } 4474 4475 /*********************************************************************** 4476 * BrowseSelectedFolder 4477 */ 4478 static BOOL BrowseSelectedFolder(HWND hwnd) 4479 { 4480 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4481 BOOL bBrowseSelFolder = FALSE; 4482 4483 TRACE("\n"); 4484 4485 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1) 4486 { 4487 LPITEMIDLIST pidlSelection; 4488 4489 /* get the file selected */ 4490 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1); 4491 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection)) 4492 { 4493 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser, 4494 pidlSelection, SBSP_RELATIVE ) ) ) 4495 { 4496 WCHAR buf[64]; 4497 LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, ARRAY_SIZE(buf)); 4498 MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION ); 4499 } 4500 bBrowseSelFolder = TRUE; 4501 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 4502 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE); 4503 } 4504 ILFree( pidlSelection ); 4505 } 4506 4507 return bBrowseSelFolder; 4508 } 4509 4510 static inline BOOL valid_struct_size( DWORD size ) 4511 { 4512 return (size == OPENFILENAME_SIZE_VERSION_400W) || 4513 (size == sizeof( OPENFILENAMEW )); 4514 } 4515 4516 static inline BOOL is_win16_looks(DWORD flags) 4517 { 4518 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) && 4519 !(flags & OFN_EXPLORER)); 4520 } 4521 4522 /* ------------------ APIs ---------------------- */ 4523 4524 /*********************************************************************** 4525 * GetOpenFileNameA (COMDLG32.@) 4526 * 4527 * Creates a dialog box for the user to select a file to open. 4528 * 4529 * RETURNS 4530 * TRUE on success: user enters a valid file 4531 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4532 * 4533 */ 4534 BOOL WINAPI GetOpenFileNameA(OPENFILENAMEA *ofn) 4535 { 4536 TRACE("flags 0x%08x\n", ofn->Flags); 4537 4538 if (!valid_struct_size( ofn->lStructSize )) 4539 { 4540 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4541 return FALSE; 4542 } 4543 4544 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */ 4545 if (ofn->Flags & OFN_FILEMUSTEXIST) 4546 ofn->Flags |= OFN_PATHMUSTEXIST; 4547 4548 if (is_win16_looks(ofn->Flags)) 4549 return GetFileName31A(ofn, OPEN_DIALOG); 4550 else 4551 { 4552 FileOpenDlgInfos info; 4553 4554 init_filedlg_infoA(ofn, &info); 4555 return GetFileDialog95(&info, OPEN_DIALOG); 4556 } 4557 } 4558 4559 /*********************************************************************** 4560 * GetOpenFileNameW (COMDLG32.@) 4561 * 4562 * Creates a dialog box for the user to select a file to open. 4563 * 4564 * RETURNS 4565 * TRUE on success: user enters a valid file 4566 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4567 * 4568 */ 4569 BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn) 4570 { 4571 TRACE("flags 0x%08x\n", ofn->Flags); 4572 4573 if (!valid_struct_size( ofn->lStructSize )) 4574 { 4575 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4576 return FALSE; 4577 } 4578 4579 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */ 4580 if (ofn->Flags & OFN_FILEMUSTEXIST) 4581 ofn->Flags |= OFN_PATHMUSTEXIST; 4582 4583 if (is_win16_looks(ofn->Flags)) 4584 return GetFileName31W(ofn, OPEN_DIALOG); 4585 else 4586 { 4587 FileOpenDlgInfos info; 4588 4589 init_filedlg_infoW(ofn, &info); 4590 return GetFileDialog95(&info, OPEN_DIALOG); 4591 } 4592 } 4593 4594 4595 /*********************************************************************** 4596 * GetSaveFileNameA (COMDLG32.@) 4597 * 4598 * Creates a dialog box for the user to select a file to save. 4599 * 4600 * RETURNS 4601 * TRUE on success: user enters a valid file 4602 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4603 * 4604 */ 4605 BOOL WINAPI GetSaveFileNameA(OPENFILENAMEA *ofn) 4606 { 4607 if (!valid_struct_size( ofn->lStructSize )) 4608 { 4609 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4610 return FALSE; 4611 } 4612 4613 if (is_win16_looks(ofn->Flags)) 4614 return GetFileName31A(ofn, SAVE_DIALOG); 4615 else 4616 { 4617 FileOpenDlgInfos info; 4618 4619 init_filedlg_infoA(ofn, &info); 4620 return GetFileDialog95(&info, SAVE_DIALOG); 4621 } 4622 } 4623 4624 /*********************************************************************** 4625 * GetSaveFileNameW (COMDLG32.@) 4626 * 4627 * Creates a dialog box for the user to select a file to save. 4628 * 4629 * RETURNS 4630 * TRUE on success: user enters a valid file 4631 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4632 * 4633 */ 4634 BOOL WINAPI GetSaveFileNameW( 4635 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */ 4636 { 4637 if (!valid_struct_size( ofn->lStructSize )) 4638 { 4639 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4640 return FALSE; 4641 } 4642 4643 if (is_win16_looks(ofn->Flags)) 4644 return GetFileName31W(ofn, SAVE_DIALOG); 4645 else 4646 { 4647 FileOpenDlgInfos info; 4648 4649 init_filedlg_infoW(ofn, &info); 4650 return GetFileDialog95(&info, SAVE_DIALOG); 4651 } 4652 } 4653 4654 /*********************************************************************** 4655 * GetFileTitleA (COMDLG32.@) 4656 * 4657 * See GetFileTitleW. 4658 */ 4659 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf) 4660 { 4661 int ret; 4662 UNICODE_STRING strWFile; 4663 LPWSTR lpWTitle; 4664 4665 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile); 4666 lpWTitle = heap_alloc(cbBuf * sizeof(WCHAR)); 4667 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf); 4668 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL ); 4669 RtlFreeUnicodeString( &strWFile ); 4670 heap_free( lpWTitle ); 4671 return ret; 4672 } 4673 4674 4675 /*********************************************************************** 4676 * GetFileTitleW (COMDLG32.@) 4677 * 4678 * Get the name of a file. 4679 * 4680 * PARAMS 4681 * lpFile [I] name and location of file 4682 * lpTitle [O] returned file name 4683 * cbBuf [I] buffer size of lpTitle 4684 * 4685 * RETURNS 4686 * Success: zero 4687 * Failure: negative number. 4688 */ 4689 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf) 4690 { 4691 int i, len; 4692 static const WCHAR brkpoint[] = {'*','[',']',0}; 4693 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf); 4694 4695 if(lpFile == NULL || lpTitle == NULL) 4696 return -1; 4697 4698 len = lstrlenW(lpFile); 4699 4700 if (len == 0) 4701 return -1; 4702 4703 if(wcspbrk(lpFile, brkpoint)) 4704 return -1; 4705 4706 len--; 4707 4708 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':') 4709 return -1; 4710 4711 for(i = len; i >= 0; i--) 4712 { 4713 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':') 4714 { 4715 i++; 4716 break; 4717 } 4718 } 4719 4720 if(i == -1) 4721 i++; 4722 4723 TRACE("---> %s\n", debugstr_w(&lpFile[i])); 4724 4725 len = lstrlenW(lpFile+i)+1; 4726 if(cbBuf < len) 4727 return len; 4728 4729 lstrcpyW(lpTitle, &lpFile[i]); 4730 return 0; 4731 } 4732