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