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