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