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