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