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 if (*ext == UNICODE_NULL && fodInfos->defext) 3103 { 3104 LPWSTR filterExt = NULL, lpstrFilter = NULL, pch, pchNext; 3105 LPCWSTR the_ext = NULL; 3106 static const WCHAR szwDot[] = {'.',0}; 3107 int PathLength = lstrlenW(lpstrPathAndFile); 3108 3109 /* get filter extensions */ 3110 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3111 fodInfos->ofnInfos->nFilterIndex - 1); 3112 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */ 3113 { 3114 LPWSTR filterSearchIndex, pchFirst = NULL; 3115 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR)); 3116 if (filterExt) 3117 { 3118 strcpyW(filterExt, lpstrFilter); 3119 3120 if (ext && *ext) 3121 { 3122 /* find ext in filter */ 3123 for (pch = filterExt; pch && *pch; pch = pchNext) 3124 { 3125 filterSearchIndex = strchrW(pch, ';'); 3126 if (filterSearchIndex) 3127 { 3128 filterSearchIndex[0] = 0; 3129 pchNext = filterSearchIndex + 1; 3130 } 3131 else 3132 { 3133 pchNext = NULL; 3134 } 3135 3136 while (*pch == '*' || *pch == '.' || *pch == '?') 3137 { 3138 ++pch; 3139 } 3140 3141 if (!pchFirst) 3142 pchFirst = pch; 3143 3144 if (lstrcmpiW(pch, &ext[1]) == 0) 3145 { 3146 the_ext = pch; 3147 break; 3148 } 3149 } 3150 3151 /* use first one if not found */ 3152 if (!the_ext && pchFirst && *pchFirst) 3153 { 3154 the_ext = pchFirst; 3155 } 3156 } 3157 } 3158 } 3159 3160 if (!the_ext) 3161 { 3162 /* use default extension if no extension in filter */ 3163 the_ext = fodInfos->defext; 3164 } 3165 3166 if (the_ext && *the_ext && lstrcmpiW(&ext[1], the_ext) != 0) 3167 { 3168 if (strlenW(lpstrPathAndFile) + 1 + strlenW(the_ext) + 1 <= 3169 fodInfos->ofnInfos->nMaxFile) 3170 { 3171 /* append the dot */ 3172 lstrcatW(lpstrPathAndFile, szwDot); 3173 /* append the extension */ 3174 lstrcatW(lpstrPathAndFile, the_ext); 3175 /* update ext */ 3176 ext = PathFindExtensionW(lpstrPathAndFile); 3177 } 3178 } 3179 3180 heap_free(filterExt); 3181 3182 /* In Open dialog: if file does not exist try without extension */ 3183 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile)) 3184 lpstrPathAndFile[PathLength] = 0; 3185 3186 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */ 3187 if (*ext) 3188 ext++; 3189 if (!lstrcmpiW(fodInfos->defext, ext)) 3190 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT; 3191 else 3192 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT; 3193 } 3194 3195 /* update dialog data */ 3196 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, PathFindFileNameW(lpstrPathAndFile)); 3197 #else /* __REACTOS__ */ 3198 if (! *ext && fodInfos->defext) 3199 { 3200 /* if no extension is specified with file name, then */ 3201 /* attach the extension from file filter or default one */ 3202 3203 WCHAR *filterExt = NULL; 3204 LPWSTR lpstrFilter = NULL; 3205 static const WCHAR szwDot[] = {'.',0}; 3206 int PathLength = lstrlenW(lpstrPathAndFile); 3207 3208 /*Get the file extension from file type filter*/ 3209 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3210 fodInfos->ofnInfos->nFilterIndex-1); 3211 3212 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */ 3213 { 3214 WCHAR* filterSearchIndex; 3215 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR)); 3216 lstrcpyW(filterExt, lpstrFilter); 3217 3218 /* if a semicolon-separated list of file extensions was given, do not include the 3219 semicolon or anything after it in the extension. 3220 example: if filterExt was "*.abc;*.def", it will become "*.abc" */ 3221 filterSearchIndex = wcschr(filterExt, ';'); 3222 if (filterSearchIndex) 3223 { 3224 filterSearchIndex[0] = '\0'; 3225 } 3226 3227 /* find the file extension by searching for the first dot in filterExt */ 3228 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */ 3229 /* if the extension is invalid or contains a glob, ignore it */ 3230 filterSearchIndex = wcschr(filterExt, '.'); 3231 if (filterSearchIndex++ && !wcschr(filterSearchIndex, '*') && !wcschr(filterSearchIndex, '?')) 3232 { 3233 lstrcpyW(filterExt, filterSearchIndex); 3234 } 3235 else 3236 { 3237 heap_free(filterExt); 3238 filterExt = NULL; 3239 } 3240 } 3241 3242 if (!filterExt) 3243 { 3244 /* use the default file extension */ 3245 filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR)); 3246 lstrcpyW(filterExt, fodInfos->defext); 3247 } 3248 3249 if (*filterExt) /* ignore filterExt="" */ 3250 { 3251 /* Attach the dot*/ 3252 lstrcatW(lpstrPathAndFile, szwDot); 3253 /* Attach the extension */ 3254 lstrcatW(lpstrPathAndFile, filterExt); 3255 } 3256 3257 heap_free(filterExt); 3258 3259 /* In Open dialog: if file does not exist try without extension */ 3260 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile)) 3261 lpstrPathAndFile[PathLength] = '\0'; 3262 3263 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */ 3264 if (*ext) 3265 ext++; 3266 if (!lstrcmpiW(fodInfos->defext, ext)) 3267 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT; 3268 else 3269 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT; 3270 } 3271 #endif /* __REACTOS__ */ 3272 3273 /* In Save dialog: check if the file already exists */ 3274 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG 3275 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT 3276 && PathFileExistsW(lpstrPathAndFile)) 3277 { 3278 WCHAR lpstrOverwrite[100]; 3279 int answer; 3280 3281 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100); 3282 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title, 3283 MB_YESNO | MB_ICONEXCLAMATION); 3284 if (answer == IDNO || answer == IDCANCEL) 3285 { 3286 ret = FALSE; 3287 goto ret; 3288 } 3289 } 3290 3291 /* In Open dialog: check if it should be created if it doesn't exist */ 3292 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) 3293 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT 3294 && !PathFileExistsW(lpstrPathAndFile)) 3295 { 3296 WCHAR lpstrCreate[100]; 3297 int answer; 3298 3299 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100); 3300 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title, 3301 MB_YESNO | MB_ICONEXCLAMATION); 3302 if (answer == IDNO || answer == IDCANCEL) 3303 { 3304 ret = FALSE; 3305 goto ret; 3306 } 3307 } 3308 3309 /* Check that the size of the file does not exceed buffer size. 3310 (Allow for extra \0 if OFN_MULTISELECT is set.) */ 3311 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile - 3312 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0)) 3313 { 3314 3315 /* fill destination buffer */ 3316 if (fodInfos->ofnInfos->lpstrFile) 3317 { 3318 if(fodInfos->unicode) 3319 { 3320 LPOPENFILENAMEW ofn = fodInfos->ofnInfos; 3321 3322 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile); 3323 if (ofn->Flags & OFN_ALLOWMULTISELECT) 3324 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0'; 3325 } 3326 else 3327 { 3328 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; 3329 3330 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1, 3331 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL); 3332 if (ofn->Flags & OFN_ALLOWMULTISELECT) 3333 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0'; 3334 } 3335 } 3336 3337 if(fodInfos->unicode) 3338 { 3339 LPWSTR lpszTemp; 3340 3341 /* set filename offset */ 3342 lpszTemp = PathFindFileNameW(lpstrPathAndFile); 3343 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile); 3344 3345 /* set extension offset */ 3346 lpszTemp = PathFindExtensionW(lpstrPathAndFile); 3347 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0; 3348 } 3349 else 3350 { 3351 LPSTR lpszTemp; 3352 CHAR tempFileA[MAX_PATH]; 3353 3354 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */ 3355 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1, 3356 tempFileA, sizeof(tempFileA), NULL, NULL); 3357 3358 /* set filename offset */ 3359 lpszTemp = PathFindFileNameA(tempFileA); 3360 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA); 3361 3362 /* set extension offset */ 3363 lpszTemp = PathFindExtensionA(tempFileA); 3364 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0; 3365 } 3366 3367 /* copy currently selected filter to lpstrCustomFilter */ 3368 if (fodInfos->ofnInfos->lpstrCustomFilter) 3369 { 3370 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; 3371 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1, 3372 NULL, 0, NULL, NULL); 3373 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter) 3374 { 3375 LPSTR s = ofn->lpstrCustomFilter; 3376 s += strlen(ofn->lpstrCustomFilter)+1; 3377 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1, 3378 s, len, NULL, NULL); 3379 } 3380 } 3381 3382 3383 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) ) 3384 goto ret; 3385 3386 FILEDLG95_MRU_save_filename(lpstrPathAndFile); 3387 #ifdef __REACTOS__ 3388 FILEDLG95_MRU_save_ext(lpstrPathAndFile); 3389 #endif 3390 3391 TRACE("close\n"); 3392 FILEDLG95_Clean(hwnd); 3393 ret = EndDialog(hwnd, TRUE); 3394 } 3395 else 3396 { 3397 WORD size; 3398 3399 size = lstrlenW(lpstrPathAndFile) + 1; 3400 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) 3401 size += 1; 3402 /* return needed size in first two bytes of lpstrFile */ 3403 if(fodInfos->ofnInfos->lpstrFile) 3404 *(WORD *)fodInfos->ofnInfos->lpstrFile = size; 3405 FILEDLG95_Clean(hwnd); 3406 ret = EndDialog(hwnd, FALSE); 3407 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL); 3408 } 3409 } 3410 break; 3411 } 3412 3413 ret: 3414 if(lpsf) IShellFolder_Release(lpsf); 3415 return ret; 3416 } 3417 3418 /*********************************************************************** 3419 * FILEDLG95_SHELL_Init 3420 * 3421 * Initialisation of the shell objects 3422 */ 3423 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd) 3424 { 3425 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3426 3427 TRACE("%p\n", hwnd); 3428 3429 /* 3430 * Initialisation of the FileOpenDialogInfos structure 3431 */ 3432 3433 /* Shell */ 3434 3435 /*ShellInfos */ 3436 fodInfos->ShellInfos.hwndOwner = hwnd; 3437 3438 /* Disable multi-select if flag not set */ 3439 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)) 3440 { 3441 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL; 3442 } 3443 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT; 3444 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST; 3445 3446 /* Construct the IShellBrowser interface */ 3447 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd); 3448 3449 return NOERROR; 3450 } 3451 3452 /*********************************************************************** 3453 * FILEDLG95_SHELL_ExecuteCommand 3454 * 3455 * Change the folder option and refresh the view 3456 * If the function succeeds, the return value is nonzero. 3457 */ 3458 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb) 3459 { 3460 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3461 IContextMenu * pcm; 3462 3463 TRACE("(%p,%p)\n", hwnd, lpVerb); 3464 3465 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView, 3466 SVGIO_BACKGROUND, 3467 &IID_IContextMenu, 3468 (LPVOID*)&pcm))) 3469 { 3470 CMINVOKECOMMANDINFO ci; 3471 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO)); 3472 ci.cbSize = sizeof(CMINVOKECOMMANDINFO); 3473 ci.lpVerb = lpVerb; 3474 ci.hwnd = hwnd; 3475 3476 IContextMenu_InvokeCommand(pcm, &ci); 3477 IContextMenu_Release(pcm); 3478 } 3479 3480 return FALSE; 3481 } 3482 3483 /*********************************************************************** 3484 * FILEDLG95_SHELL_UpFolder 3485 * 3486 * Browse to the specified object 3487 * If the function succeeds, the return value is nonzero. 3488 */ 3489 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd) 3490 { 3491 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3492 3493 TRACE("\n"); 3494 3495 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, 3496 NULL, 3497 SBSP_PARENT))) 3498 { 3499 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 3500 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); 3501 return TRUE; 3502 } 3503 return FALSE; 3504 } 3505 /*********************************************************************** 3506 * FILEDLG95_SHELL_Clean 3507 * 3508 * Cleans the memory used by shell objects 3509 */ 3510 static void FILEDLG95_SHELL_Clean(HWND hwnd) 3511 { 3512 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3513 3514 TRACE("\n"); 3515 3516 ILFree(fodInfos->ShellInfos.pidlAbsCurrent); 3517 3518 /* clean Shell interfaces */ 3519 if (fodInfos->Shell.FOIShellView) 3520 { 3521 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView); 3522 IShellView_Release(fodInfos->Shell.FOIShellView); 3523 } 3524 if (fodInfos->Shell.FOIShellFolder) 3525 IShellFolder_Release(fodInfos->Shell.FOIShellFolder); 3526 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser); 3527 if (fodInfos->Shell.FOIDataObject) 3528 IDataObject_Release(fodInfos->Shell.FOIDataObject); 3529 } 3530 3531 /*********************************************************************** 3532 * FILEDLG95_FILETYPE_Init 3533 * 3534 * Initialisation of the file type combo box 3535 */ 3536 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd) 3537 { 3538 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3539 int nFilters = 0; /* number of filters */ 3540 int nFilterIndexCB; 3541 3542 TRACE("%p\n", hwnd); 3543 3544 if(fodInfos->customfilter) 3545 { 3546 /* customfilter has one entry... title\0ext\0 3547 * Set first entry of combo box item with customfilter 3548 */ 3549 LPWSTR lpstrExt; 3550 LPCWSTR lpstrPos = fodInfos->customfilter; 3551 3552 /* Get the title */ 3553 lpstrPos += lstrlenW(fodInfos->customfilter) + 1; 3554 3555 /* Copy the extensions */ 3556 if (! *lpstrPos) return E_FAIL; /* malformed filter */ 3557 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL; 3558 lstrcpyW(lpstrExt,lpstrPos); 3559 3560 /* Add the item at the end of the combo */ 3561 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter); 3562 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt); 3563 3564 nFilters++; 3565 } 3566 if(fodInfos->filter) 3567 { 3568 LPCWSTR lpstrPos = fodInfos->filter; 3569 3570 for(;;) 3571 { 3572 /* filter is a list... title\0ext\0......\0\0 3573 * Set the combo item text to the title and the item data 3574 * to the ext 3575 */ 3576 LPCWSTR lpstrDisplay; 3577 LPWSTR lpstrExt; 3578 3579 /* Get the title */ 3580 if(! *lpstrPos) break; /* end */ 3581 lpstrDisplay = lpstrPos; 3582 lpstrPos += lstrlenW(lpstrPos) + 1; 3583 3584 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay); 3585 3586 nFilters++; 3587 3588 /* Copy the extensions */ 3589 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL; 3590 lstrcpyW(lpstrExt,lpstrPos); 3591 lpstrPos += lstrlenW(lpstrPos) + 1; 3592 3593 /* Add the item at the end of the combo */ 3594 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt); 3595 3596 /* malformed filters are added anyway... */ 3597 if (!*lpstrExt) break; 3598 } 3599 } 3600 3601 /* 3602 * Set the current filter to the one specified 3603 * in the initialisation structure 3604 */ 3605 if (fodInfos->filter || fodInfos->customfilter) 3606 { 3607 LPWSTR lpstrFilter; 3608 3609 /* Check to make sure our index isn't out of bounds. */ 3610 if ( fodInfos->ofnInfos->nFilterIndex > 3611 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) ) 3612 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0); 3613 3614 /* set default filter index */ 3615 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL) 3616 fodInfos->ofnInfos->nFilterIndex = 1; 3617 3618 /* calculate index of Combo Box item */ 3619 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex; 3620 if (fodInfos->customfilter == NULL) 3621 nFilterIndexCB--; 3622 3623 /* Set the current index selection. */ 3624 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0); 3625 3626 /* Get the corresponding text string from the combo box. */ 3627 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3628 nFilterIndexCB); 3629 3630 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */ 3631 lpstrFilter = NULL; 3632 3633 if(lpstrFilter) 3634 { 3635 DWORD len; 3636 CharLowerW(lpstrFilter); /* lowercase */ 3637 len = lstrlenW(lpstrFilter)+1; 3638 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) ); 3639 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter); 3640 } 3641 } else 3642 fodInfos->ofnInfos->nFilterIndex = 0; 3643 return S_OK; 3644 } 3645 3646 /*********************************************************************** 3647 * FILEDLG95_FILETYPE_OnCommand 3648 * 3649 * WM_COMMAND of the file type combo box 3650 * If the function succeeds, the return value is nonzero. 3651 */ 3652 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode) 3653 { 3654 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3655 3656 switch(wNotifyCode) 3657 { 3658 case CBN_SELENDOK: 3659 { 3660 LPWSTR lpstrFilter; 3661 3662 /* Get the current item of the filetype combo box */ 3663 int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0); 3664 3665 /* set the current filter index */ 3666 fodInfos->ofnInfos->nFilterIndex = iItem + 3667 (fodInfos->customfilter == NULL ? 1 : 0); 3668 3669 /* Set the current filter with the current selection */ 3670 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter); 3671 3672 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, 3673 iItem); 3674 if((INT_PTR)lpstrFilter != CB_ERR) 3675 { 3676 DWORD len; 3677 CharLowerW(lpstrFilter); /* lowercase */ 3678 len = lstrlenW(lpstrFilter)+1; 3679 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) ); 3680 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter); 3681 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 3682 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE); 3683 } 3684 3685 /* Refresh the actual view to display the included items*/ 3686 if (fodInfos->Shell.FOIShellView) 3687 IShellView_Refresh(fodInfos->Shell.FOIShellView); 3688 } 3689 } 3690 return FALSE; 3691 } 3692 /*********************************************************************** 3693 * FILEDLG95_FILETYPE_SearchExt 3694 * 3695 * searches for an extension in the filetype box 3696 */ 3697 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt) 3698 { 3699 int i, iCount; 3700 3701 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0); 3702 3703 TRACE("%s\n", debugstr_w(lpstrExt)); 3704 3705 if(iCount != CB_ERR) 3706 { 3707 for(i=0;i<iCount;i++) 3708 { 3709 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i))) 3710 return i; 3711 } 3712 } 3713 return -1; 3714 } 3715 3716 /*********************************************************************** 3717 * FILEDLG95_FILETYPE_Clean 3718 * 3719 * Clean the memory used by the filetype combo box 3720 */ 3721 static void FILEDLG95_FILETYPE_Clean(HWND hwnd) 3722 { 3723 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3724 int iPos; 3725 int iCount; 3726 3727 iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0); 3728 3729 TRACE("\n"); 3730 3731 /* Delete each string of the combo and their associated data */ 3732 if(iCount != CB_ERR) 3733 { 3734 for(iPos = iCount-1;iPos>=0;iPos--) 3735 { 3736 heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos)); 3737 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0); 3738 } 3739 } 3740 /* Current filter */ 3741 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter); 3742 } 3743 3744 /*********************************************************************** 3745 * FILEDLG95_LOOKIN_Init 3746 * 3747 * Initialisation of the look in combo box 3748 */ 3749 3750 /* Small helper function, to determine if the unixfs shell extension is rooted 3751 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 3752 */ 3753 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) { 3754 HKEY hKey; 3755 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\', 3756 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', 3757 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 3758 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\', 3759 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8', 3760 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-', 3761 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 }; 3762 3763 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 3764 return FALSE; 3765 3766 RegCloseKey(hKey); 3767 return TRUE; 3768 } 3769 3770 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo) 3771 { 3772 IShellFolder *psfRoot, *psfDrives; 3773 IEnumIDList *lpeRoot, *lpeDrives; 3774 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp; 3775 HDC hdc; 3776 TEXTMETRICW tm; 3777 LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos)); 3778 3779 TRACE("%p\n", hwndCombo); 3780 3781 liInfos->iMaxIndentation = 0; 3782 3783 SetPropA(hwndCombo, LookInInfosStr, liInfos); 3784 3785 hdc = GetDC( hwndCombo ); 3786 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 )); 3787 GetTextMetricsW( hdc, &tm ); 3788 ReleaseDC( hwndCombo, hdc ); 3789 3790 /* set item height for both text field and listbox */ 3791 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON))); 3792 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON))); 3793 3794 /* Turn on the extended UI for the combo box like Windows does */ 3795 SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0); 3796 3797 /* Initialise data of Desktop folder */ 3798 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp); 3799 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND); 3800 ILFree(pidlTmp); 3801 3802 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives); 3803 3804 SHGetDesktopFolder(&psfRoot); 3805 3806 if (psfRoot) 3807 { 3808 /* enumerate the contents of the desktop */ 3809 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot))) 3810 { 3811 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL)) 3812 { 3813 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND); 3814 3815 /* If the unixfs extension is rooted, we don't expand the drives by default */ 3816 if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 3817 { 3818 /* special handling for CSIDL_DRIVES */ 3819 if (ILIsEqual(pidlTmp, pidlDrives)) 3820 { 3821 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives))) 3822 { 3823 /* enumerate the drives */ 3824 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives))) 3825 { 3826 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL)) 3827 { 3828 pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1); 3829 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND); 3830 ILFree(pidlAbsTmp); 3831 ILFree(pidlTmp1); 3832 } 3833 IEnumIDList_Release(lpeDrives); 3834 } 3835 IShellFolder_Release(psfDrives); 3836 } 3837 } 3838 } 3839 3840 ILFree(pidlTmp); 3841 } 3842 IEnumIDList_Release(lpeRoot); 3843 } 3844 IShellFolder_Release(psfRoot); 3845 } 3846 3847 ILFree(pidlDrives); 3848 } 3849 3850 /*********************************************************************** 3851 * FILEDLG95_LOOKIN_DrawItem 3852 * 3853 * WM_DRAWITEM message handler 3854 */ 3855 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct) 3856 { 3857 COLORREF crWin = GetSysColor(COLOR_WINDOW); 3858 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT); 3859 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT); 3860 RECT rectText; 3861 RECT rectIcon; 3862 SHFILEINFOW sfi; 3863 HIMAGELIST ilItemImage; 3864 int iIndentation; 3865 TEXTMETRICW tm; 3866 LPSFOLDER tmpFolder; 3867 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME; 3868 UINT icon_width, icon_height; 3869 3870 TRACE("\n"); 3871 3872 if(pDIStruct->itemID == -1) 3873 return 0; 3874 3875 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem, 3876 pDIStruct->itemID))) 3877 return 0; 3878 3879 3880 icon_width = GetSystemMetrics(SM_CXICON); 3881 icon_height = GetSystemMetrics(SM_CYICON); 3882 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height) 3883 { 3884 icon_width = GetSystemMetrics(SM_CXSMICON); 3885 icon_height = GetSystemMetrics(SM_CYSMICON); 3886 shgfi_flags |= SHGFI_SMALLICON; 3887 } 3888 3889 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem, 3890 0, &sfi, sizeof (sfi), shgfi_flags ); 3891 3892 /* Is this item selected ? */ 3893 if(pDIStruct->itemState & ODS_SELECTED) 3894 { 3895 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText))); 3896 SetBkColor(pDIStruct->hDC,crHighLight); 3897 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT)); 3898 } 3899 else 3900 { 3901 SetTextColor(pDIStruct->hDC,crText); 3902 SetBkColor(pDIStruct->hDC,crWin); 3903 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW)); 3904 } 3905 3906 /* Do not indent item if drawing in the edit of the combo */ 3907 if(pDIStruct->itemState & ODS_COMBOBOXEDIT) 3908 iIndentation = 0; 3909 else 3910 iIndentation = tmpFolder->m_iIndent; 3911 3912 /* Draw text and icon */ 3913 3914 /* Initialise the icon display area */ 3915 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation; 3916 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2; 3917 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET; 3918 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2; 3919 3920 /* Initialise the text display area */ 3921 GetTextMetricsW(pDIStruct->hDC, &tm); 3922 rectText.left = rectIcon.right; 3923 rectText.top = 3924 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2; 3925 rectText.right = pDIStruct->rcItem.right; 3926 rectText.bottom = 3927 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2; 3928 3929 /* Draw the icon from the image list */ 3930 ImageList_Draw(ilItemImage, 3931 sfi.iIcon, 3932 pDIStruct->hDC, 3933 rectIcon.left, 3934 rectIcon.top, 3935 ILD_TRANSPARENT ); 3936 3937 /* Draw the associated text */ 3938 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName)); 3939 return NOERROR; 3940 } 3941 3942 /*********************************************************************** 3943 * FILEDLG95_LOOKIN_OnCommand 3944 * 3945 * LookIn combo box WM_COMMAND message handler 3946 * If the function succeeds, the return value is nonzero. 3947 */ 3948 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode) 3949 { 3950 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 3951 3952 TRACE("%p\n", fodInfos); 3953 3954 switch(wNotifyCode) 3955 { 3956 case CBN_SELENDOK: 3957 { 3958 LPSFOLDER tmpFolder; 3959 int iItem; 3960 3961 iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0); 3962 3963 if( iItem == CB_ERR) return FALSE; 3964 3965 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB, 3966 iItem))) 3967 return FALSE; 3968 3969 3970 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, 3971 tmpFolder->pidlItem, 3972 SBSP_ABSOLUTE))) 3973 { 3974 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 3975 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); 3976 return TRUE; 3977 } 3978 break; 3979 } 3980 3981 } 3982 return FALSE; 3983 } 3984 3985 /*********************************************************************** 3986 * FILEDLG95_LOOKIN_AddItem 3987 * 3988 * Adds an absolute pidl item to the lookin combo box 3989 * returns the index of the inserted item 3990 */ 3991 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId) 3992 { 3993 LPITEMIDLIST pidlNext; 3994 SHFILEINFOW sfi; 3995 SFOLDER *tmpFolder; 3996 LookInInfos *liInfos; 3997 3998 TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId); 3999 4000 if(!pidl) 4001 return -1; 4002 4003 if(!(liInfos = GetPropA(hwnd,LookInInfosStr))) 4004 return -1; 4005 4006 tmpFolder = heap_alloc_zero(sizeof(*tmpFolder)); 4007 tmpFolder->m_iIndent = 0; 4008 4009 /* Calculate the indentation of the item in the lookin*/ 4010 pidlNext = pidl; 4011 while ((pidlNext = ILGetNext(pidlNext))) 4012 { 4013 tmpFolder->m_iIndent++; 4014 } 4015 4016 tmpFolder->pidlItem = ILClone(pidl); 4017 4018 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation) 4019 liInfos->iMaxIndentation = tmpFolder->m_iIndent; 4020 4021 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM; 4022 SHGetFileInfoW((LPCWSTR)pidl, 4023 0, 4024 &sfi, 4025 sizeof(sfi), 4026 SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED); 4027 4028 TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes); 4029 4030 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM)) 4031 { 4032 int iItemID; 4033 4034 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent); 4035 4036 /* Add the item at the end of the list */ 4037 if(iInsertId < 0) 4038 { 4039 iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName); 4040 } 4041 /* Insert the item at the iInsertId position*/ 4042 else 4043 { 4044 iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName); 4045 } 4046 4047 SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder); 4048 return iItemID; 4049 } 4050 4051 ILFree( tmpFolder->pidlItem ); 4052 heap_free( tmpFolder ); 4053 return -1; 4054 4055 } 4056 4057 /*********************************************************************** 4058 * FILEDLG95_LOOKIN_InsertItemAfterParent 4059 * 4060 * Insert an item below its parent 4061 */ 4062 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl) 4063 { 4064 4065 LPITEMIDLIST pidlParent = GetParentPidl(pidl); 4066 int iParentPos; 4067 4068 TRACE("\n"); 4069 4070 if (pidl == pidlParent) 4071 return -1; 4072 4073 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL); 4074 4075 if(iParentPos < 0) 4076 { 4077 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent); 4078 } 4079 4080 ILFree(pidlParent); 4081 4082 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1); 4083 } 4084 4085 /*********************************************************************** 4086 * FILEDLG95_LOOKIN_SelectItem 4087 * 4088 * Adds an absolute pidl item to the lookin combo box 4089 * returns the index of the inserted item 4090 */ 4091 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl) 4092 { 4093 int iItemPos; 4094 LookInInfos *liInfos; 4095 4096 TRACE("%p, %p\n", hwnd, pidl); 4097 4098 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL); 4099 4100 liInfos = GetPropA(hwnd,LookInInfosStr); 4101 4102 if(iItemPos < 0) 4103 { 4104 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1); 4105 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl); 4106 } 4107 4108 else 4109 { 4110 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos); 4111 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent) 4112 { 4113 int iRemovedItem; 4114 4115 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd))) 4116 break; 4117 if(iRemovedItem < iItemPos) 4118 iItemPos--; 4119 } 4120 } 4121 4122 SendMessageW(hwnd, CB_SETCURSEL, iItemPos, 0); 4123 liInfos->uSelectedItem = iItemPos; 4124 4125 return 0; 4126 4127 } 4128 4129 /*********************************************************************** 4130 * FILEDLG95_LOOKIN_RemoveMostExpandedItem 4131 * 4132 * Remove the item with an expansion level over iExpansionLevel 4133 */ 4134 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd) 4135 { 4136 int iItemPos; 4137 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr); 4138 4139 TRACE("\n"); 4140 4141 if(liInfos->iMaxIndentation <= 2) 4142 return -1; 4143 4144 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0) 4145 { 4146 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos); 4147 ILFree(tmpFolder->pidlItem); 4148 heap_free(tmpFolder); 4149 SendMessageW(hwnd, CB_DELETESTRING, iItemPos, 0); 4150 liInfos->iMaxIndentation--; 4151 4152 return iItemPos; 4153 } 4154 4155 return -1; 4156 } 4157 4158 /*********************************************************************** 4159 * FILEDLG95_LOOKIN_SearchItem 4160 * 4161 * Search for pidl in the lookin combo box 4162 * returns the index of the found item 4163 */ 4164 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod) 4165 { 4166 int i = 0; 4167 int iCount; 4168 4169 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0); 4170 4171 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod); 4172 4173 if (iCount != CB_ERR) 4174 { 4175 for(;i<iCount;i++) 4176 { 4177 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i); 4178 4179 if (iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg, tmpFolder->pidlItem)) 4180 return i; 4181 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg) 4182 return i; 4183 } 4184 } 4185 4186 return -1; 4187 } 4188 4189 /*********************************************************************** 4190 * FILEDLG95_LOOKIN_Clean 4191 * 4192 * Clean the memory used by the lookin combo box 4193 */ 4194 static void FILEDLG95_LOOKIN_Clean(HWND hwnd) 4195 { 4196 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4197 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr); 4198 int iPos, iCount; 4199 4200 iCount = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCOUNT, 0, 0); 4201 4202 TRACE("\n"); 4203 4204 /* Delete each string of the combo and their associated data */ 4205 if (iCount != CB_ERR) 4206 { 4207 for(iPos = iCount-1;iPos>=0;iPos--) 4208 { 4209 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos); 4210 ILFree(tmpFolder->pidlItem); 4211 heap_free(tmpFolder); 4212 SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_DELETESTRING, iPos, 0); 4213 } 4214 } 4215 4216 /* LookInInfos structure */ 4217 heap_free(liInfos); 4218 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr); 4219 } 4220 4221 /*********************************************************************** 4222 * get_def_format 4223 * 4224 * Fill the FORMATETC used in the shell id list 4225 */ 4226 static FORMATETC get_def_format(void) 4227 { 4228 static CLIPFORMAT cfFormat; 4229 FORMATETC formatetc; 4230 4231 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA); 4232 formatetc.cfFormat = cfFormat; 4233 formatetc.ptd = 0; 4234 formatetc.dwAspect = DVASPECT_CONTENT; 4235 formatetc.lindex = -1; 4236 formatetc.tymed = TYMED_HGLOBAL; 4237 return formatetc; 4238 } 4239 4240 /*********************************************************************** 4241 * FILEDLG95_FILENAME_FillFromSelection 4242 * 4243 * fills the edit box from the cached DataObject 4244 */ 4245 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd) 4246 { 4247 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4248 LPITEMIDLIST pidl; 4249 LPWSTR lpstrAllFiles, lpstrTmp; 4250 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength; 4251 STGMEDIUM medium; 4252 LPIDA cida; 4253 FORMATETC formatetc = get_def_format(); 4254 4255 TRACE("\n"); 4256 4257 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium))) 4258 return; 4259 4260 cida = GlobalLock(medium.u.hGlobal); 4261 nFileSelected = cida->cidl; 4262 4263 /* Allocate a buffer */ 4264 nAllFilesMaxLength = MAX_PATH + 3; 4265 lpstrAllFiles = heap_alloc_zero(nAllFilesMaxLength * sizeof(WCHAR)); 4266 if (!lpstrAllFiles) 4267 goto ret; 4268 4269 /* Loop through the selection, handle only files (not folders) */ 4270 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++) 4271 { 4272 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]); 4273 if (pidl) 4274 { 4275 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) 4276 { 4277 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength) 4278 { 4279 nAllFilesMaxLength *= 2; 4280 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR)); 4281 if (!lpstrTmp) 4282 goto ret; 4283 lpstrAllFiles = lpstrTmp; 4284 } 4285 nFiles += 1; 4286 lpstrAllFiles[nAllFilesLength++] = '"'; 4287 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength); 4288 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength); 4289 nAllFilesLength += nThisFileLength; 4290 lpstrAllFiles[nAllFilesLength++] = '"'; 4291 lpstrAllFiles[nAllFilesLength++] = ' '; 4292 } 4293 } 4294 } 4295 4296 if (nFiles != 0) 4297 { 4298 /* If there's only one file, use the name as-is without quotes */ 4299 lpstrTmp = lpstrAllFiles; 4300 if (nFiles == 1) 4301 { 4302 lpstrTmp += 1; 4303 lpstrTmp[nThisFileLength] = 0; 4304 } 4305 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp); 4306 /* Select the file name like Windows does */ 4307 if (filename_is_edit(fodInfos)) 4308 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1); 4309 } 4310 4311 ret: 4312 heap_free(lpstrAllFiles); 4313 COMCTL32_ReleaseStgMedium(medium); 4314 } 4315 4316 4317 /* copied from shell32 to avoid linking to it 4318 * Although shell32 is already linked the behaviour of exported StrRetToStrN 4319 * is dependent on whether emulated OS is unicode or not. 4320 */ 4321 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl) 4322 { 4323 switch (src->uType) 4324 { 4325 case STRRET_WSTR: 4326 lstrcpynW(dest, src->u.pOleStr, len); 4327 CoTaskMemFree(src->u.pOleStr); 4328 break; 4329 4330 case STRRET_CSTR: 4331 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len) 4332 dest[len-1] = 0; 4333 break; 4334 4335 case STRRET_OFFSET: 4336 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len) 4337 dest[len-1] = 0; 4338 break; 4339 4340 default: 4341 FIXME("unknown type %x!\n", src->uType); 4342 if (len) *dest = '\0'; 4343 return E_FAIL; 4344 } 4345 return S_OK; 4346 } 4347 4348 /*********************************************************************** 4349 * FILEDLG95_FILENAME_GetFileNames 4350 * 4351 * Copies the filenames to a delimited string list. 4352 */ 4353 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed) 4354 { 4355 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4356 UINT nFileCount = 0; /* number of files */ 4357 UINT nStrLen = 0; /* length of string in edit control */ 4358 LPWSTR lpstrEdit; /* buffer for string from edit control */ 4359 4360 TRACE("\n"); 4361 4362 /* get the filenames from the filename control */ 4363 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName ); 4364 lpstrEdit = heap_alloc( (nStrLen+1)*sizeof(WCHAR) ); 4365 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1); 4366 4367 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit)); 4368 4369 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed); 4370 heap_free(lpstrEdit); 4371 return nFileCount; 4372 } 4373 4374 /* 4375 * DATAOBJECT Helper functions 4376 */ 4377 4378 /*********************************************************************** 4379 * COMCTL32_ReleaseStgMedium 4380 * 4381 * like ReleaseStgMedium from ole32 4382 */ 4383 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium) 4384 { 4385 if(medium.pUnkForRelease) 4386 { 4387 IUnknown_Release(medium.pUnkForRelease); 4388 } 4389 else 4390 { 4391 GlobalUnlock(medium.u.hGlobal); 4392 GlobalFree(medium.u.hGlobal); 4393 } 4394 } 4395 4396 /*********************************************************************** 4397 * GetPidlFromDataObject 4398 * 4399 * Return pidl(s) by number from the cached DataObject 4400 * 4401 * nPidlIndex=0 gets the fully qualified root path 4402 */ 4403 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex) 4404 { 4405 4406 STGMEDIUM medium; 4407 FORMATETC formatetc = get_def_format(); 4408 LPITEMIDLIST pidl = NULL; 4409 4410 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex); 4411 4412 if (!doSelected) 4413 return NULL; 4414 4415 /* Get the pidls from IDataObject */ 4416 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium))) 4417 { 4418 LPIDA cida = GlobalLock(medium.u.hGlobal); 4419 if(nPidlIndex <= cida->cidl) 4420 { 4421 pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]])); 4422 } 4423 COMCTL32_ReleaseStgMedium(medium); 4424 } 4425 return pidl; 4426 } 4427 4428 /*********************************************************************** 4429 * GetNumSelected 4430 * 4431 * Return the number of selected items in the DataObject. 4432 * 4433 */ 4434 static UINT GetNumSelected( IDataObject *doSelected ) 4435 { 4436 UINT retVal = 0; 4437 STGMEDIUM medium; 4438 FORMATETC formatetc = get_def_format(); 4439 4440 TRACE("sv=%p\n", doSelected); 4441 4442 if (!doSelected) return 0; 4443 4444 /* Get the pidls from IDataObject */ 4445 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium))) 4446 { 4447 LPIDA cida = GlobalLock(medium.u.hGlobal); 4448 retVal = cida->cidl; 4449 COMCTL32_ReleaseStgMedium(medium); 4450 return retVal; 4451 } 4452 return 0; 4453 } 4454 4455 /* 4456 * TOOLS 4457 */ 4458 4459 /*********************************************************************** 4460 * GetName 4461 * 4462 * Get the pidl's display name (relative to folder) and 4463 * put it in lpstrFileName. 4464 * 4465 * Return NOERROR on success, 4466 * E_FAIL otherwise 4467 */ 4468 4469 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName) 4470 { 4471 STRRET str; 4472 HRESULT hRes; 4473 4474 TRACE("sf=%p pidl=%p\n", lpsf, pidl); 4475 4476 if(!lpsf) 4477 { 4478 SHGetDesktopFolder(&lpsf); 4479 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName); 4480 IShellFolder_Release(lpsf); 4481 return hRes; 4482 } 4483 4484 /* Get the display name of the pidl relative to the folder */ 4485 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str))) 4486 { 4487 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl); 4488 } 4489 return E_FAIL; 4490 } 4491 4492 /*********************************************************************** 4493 * GetShellFolderFromPidl 4494 * 4495 * pidlRel is the item pidl relative 4496 * Return the IShellFolder of the absolute pidl 4497 */ 4498 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs) 4499 { 4500 IShellFolder *psf = NULL,*psfParent; 4501 4502 TRACE("%p\n", pidlAbs); 4503 4504 if(SUCCEEDED(SHGetDesktopFolder(&psfParent))) 4505 { 4506 psf = psfParent; 4507 if(pidlAbs && pidlAbs->mkid.cb) 4508 { 4509 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf))) 4510 { 4511 IShellFolder_Release(psfParent); 4512 return psf; 4513 } 4514 } 4515 /* return the desktop */ 4516 return psfParent; 4517 } 4518 return NULL; 4519 } 4520 4521 /*********************************************************************** 4522 * GetParentPidl 4523 * 4524 * Return the LPITEMIDLIST to the parent of the pidl in the list 4525 */ 4526 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl) 4527 { 4528 LPITEMIDLIST pidlParent; 4529 4530 TRACE("%p\n", pidl); 4531 4532 pidlParent = ILClone(pidl); 4533 ILRemoveLastID(pidlParent); 4534 4535 return pidlParent; 4536 } 4537 4538 /*********************************************************************** 4539 * GetPidlFromName 4540 * 4541 * returns the pidl of the file name relative to folder 4542 * NULL if an error occurred 4543 */ 4544 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName) 4545 { 4546 LPITEMIDLIST pidl = NULL; 4547 ULONG ulEaten; 4548 4549 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName)); 4550 4551 if(!lpcstrFileName) return NULL; 4552 if(!*lpcstrFileName) return NULL; 4553 4554 if(!lpsf) 4555 { 4556 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) { 4557 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL); 4558 IShellFolder_Release(lpsf); 4559 } 4560 } 4561 else 4562 { 4563 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL); 4564 } 4565 return pidl; 4566 } 4567 4568 /* 4569 */ 4570 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl) 4571 { 4572 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR; 4573 HRESULT ret; 4574 4575 TRACE("%p, %p\n", psf, pidl); 4576 4577 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr ); 4578 4579 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret); 4580 /* see documentation shell 4.1*/ 4581 return (uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER)) && (uAttr & SFGAO_FILESYSANCESTOR); 4582 } 4583 4584 /*********************************************************************** 4585 * BrowseSelectedFolder 4586 */ 4587 static BOOL BrowseSelectedFolder(HWND hwnd) 4588 { 4589 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd); 4590 BOOL bBrowseSelFolder = FALSE; 4591 4592 TRACE("\n"); 4593 4594 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1) 4595 { 4596 LPITEMIDLIST pidlSelection; 4597 4598 /* get the file selected */ 4599 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1); 4600 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection)) 4601 { 4602 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser, 4603 pidlSelection, SBSP_RELATIVE ) ) ) 4604 { 4605 WCHAR buf[64]; 4606 LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, ARRAY_SIZE(buf)); 4607 MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION ); 4608 } 4609 bBrowseSelFolder = TRUE; 4610 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) 4611 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE); 4612 } 4613 ILFree( pidlSelection ); 4614 } 4615 4616 return bBrowseSelFolder; 4617 } 4618 4619 static inline BOOL valid_struct_size( DWORD size ) 4620 { 4621 return (size == OPENFILENAME_SIZE_VERSION_400W) || 4622 (size == sizeof( OPENFILENAMEW )); 4623 } 4624 4625 static inline BOOL is_win16_looks(DWORD flags) 4626 { 4627 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) && 4628 !(flags & OFN_EXPLORER)); 4629 } 4630 4631 /* ------------------ APIs ---------------------- */ 4632 4633 /*********************************************************************** 4634 * GetOpenFileNameA (COMDLG32.@) 4635 * 4636 * Creates a dialog box for the user to select a file to open. 4637 * 4638 * RETURNS 4639 * TRUE on success: user enters a valid file 4640 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4641 * 4642 */ 4643 BOOL WINAPI GetOpenFileNameA(OPENFILENAMEA *ofn) 4644 { 4645 TRACE("flags 0x%08x\n", ofn->Flags); 4646 4647 if (!valid_struct_size( ofn->lStructSize )) 4648 { 4649 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4650 return FALSE; 4651 } 4652 4653 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */ 4654 if (ofn->Flags & OFN_FILEMUSTEXIST) 4655 ofn->Flags |= OFN_PATHMUSTEXIST; 4656 4657 if (is_win16_looks(ofn->Flags)) 4658 return GetFileName31A(ofn, OPEN_DIALOG); 4659 else 4660 { 4661 FileOpenDlgInfos info; 4662 4663 init_filedlg_infoA(ofn, &info); 4664 return GetFileDialog95(&info, OPEN_DIALOG); 4665 } 4666 } 4667 4668 /*********************************************************************** 4669 * GetOpenFileNameW (COMDLG32.@) 4670 * 4671 * Creates a dialog box for the user to select a file to open. 4672 * 4673 * RETURNS 4674 * TRUE on success: user enters a valid file 4675 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4676 * 4677 */ 4678 BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn) 4679 { 4680 TRACE("flags 0x%08x\n", ofn->Flags); 4681 4682 if (!valid_struct_size( ofn->lStructSize )) 4683 { 4684 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4685 return FALSE; 4686 } 4687 4688 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */ 4689 if (ofn->Flags & OFN_FILEMUSTEXIST) 4690 ofn->Flags |= OFN_PATHMUSTEXIST; 4691 4692 if (is_win16_looks(ofn->Flags)) 4693 return GetFileName31W(ofn, OPEN_DIALOG); 4694 else 4695 { 4696 FileOpenDlgInfos info; 4697 4698 init_filedlg_infoW(ofn, &info); 4699 return GetFileDialog95(&info, OPEN_DIALOG); 4700 } 4701 } 4702 4703 4704 /*********************************************************************** 4705 * GetSaveFileNameA (COMDLG32.@) 4706 * 4707 * Creates a dialog box for the user to select a file to save. 4708 * 4709 * RETURNS 4710 * TRUE on success: user enters a valid file 4711 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4712 * 4713 */ 4714 BOOL WINAPI GetSaveFileNameA(OPENFILENAMEA *ofn) 4715 { 4716 if (!valid_struct_size( ofn->lStructSize )) 4717 { 4718 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4719 return FALSE; 4720 } 4721 4722 if (is_win16_looks(ofn->Flags)) 4723 return GetFileName31A(ofn, SAVE_DIALOG); 4724 else 4725 { 4726 FileOpenDlgInfos info; 4727 4728 init_filedlg_infoA(ofn, &info); 4729 return GetFileDialog95(&info, SAVE_DIALOG); 4730 } 4731 } 4732 4733 /*********************************************************************** 4734 * GetSaveFileNameW (COMDLG32.@) 4735 * 4736 * Creates a dialog box for the user to select a file to save. 4737 * 4738 * RETURNS 4739 * TRUE on success: user enters a valid file 4740 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. 4741 * 4742 */ 4743 BOOL WINAPI GetSaveFileNameW( 4744 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */ 4745 { 4746 if (!valid_struct_size( ofn->lStructSize )) 4747 { 4748 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE ); 4749 return FALSE; 4750 } 4751 4752 if (is_win16_looks(ofn->Flags)) 4753 return GetFileName31W(ofn, SAVE_DIALOG); 4754 else 4755 { 4756 FileOpenDlgInfos info; 4757 4758 init_filedlg_infoW(ofn, &info); 4759 return GetFileDialog95(&info, SAVE_DIALOG); 4760 } 4761 } 4762 4763 /*********************************************************************** 4764 * GetFileTitleA (COMDLG32.@) 4765 * 4766 * See GetFileTitleW. 4767 */ 4768 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf) 4769 { 4770 int ret; 4771 UNICODE_STRING strWFile; 4772 LPWSTR lpWTitle; 4773 4774 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile); 4775 lpWTitle = heap_alloc(cbBuf * sizeof(WCHAR)); 4776 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf); 4777 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL ); 4778 RtlFreeUnicodeString( &strWFile ); 4779 heap_free( lpWTitle ); 4780 return ret; 4781 } 4782 4783 4784 /*********************************************************************** 4785 * GetFileTitleW (COMDLG32.@) 4786 * 4787 * Get the name of a file. 4788 * 4789 * PARAMS 4790 * lpFile [I] name and location of file 4791 * lpTitle [O] returned file name 4792 * cbBuf [I] buffer size of lpTitle 4793 * 4794 * RETURNS 4795 * Success: zero 4796 * Failure: negative number. 4797 */ 4798 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf) 4799 { 4800 int i, len; 4801 static const WCHAR brkpoint[] = {'*','[',']',0}; 4802 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf); 4803 4804 if(lpFile == NULL || lpTitle == NULL) 4805 return -1; 4806 4807 len = lstrlenW(lpFile); 4808 4809 if (len == 0) 4810 return -1; 4811 4812 if(wcspbrk(lpFile, brkpoint)) 4813 return -1; 4814 4815 len--; 4816 4817 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':') 4818 return -1; 4819 4820 for(i = len; i >= 0; i--) 4821 { 4822 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':') 4823 { 4824 i++; 4825 break; 4826 } 4827 } 4828 4829 if(i == -1) 4830 i++; 4831 4832 TRACE("---> %s\n", debugstr_w(&lpFile[i])); 4833 4834 len = lstrlenW(lpFile+i)+1; 4835 if(cbBuf < len) 4836 return len; 4837 4838 lstrcpyW(lpTitle, &lpFile[i]); 4839 return 0; 4840 } 4841