filedlg.c 135 KB
Newer Older
1
/*
2
 * COMMDLG - File Open Dialogs Win95 look and feel
3
 *
4 5
 * Copyright 1999 Francois Boisvert
 * Copyright 1999, 2000 Juergen Schmied
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *
 * FIXME: The whole concept of handling unicode is badly broken.
 *	many hook-messages expect a pointer to a
 *	OPENFILENAMEA or W structure. With the current architecture
 *	we would have to convert the beast at every call to a hook.
 *	we have to find a better solution but it would likely cause
 *	a complete rewrite after which we should handle the
 *	OPENFILENAME structure without any converting (jsch).
 *
 * FIXME: any hook gets a OPENFILENAMEA structure
 *
 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
 *
 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
 *
 * FIXME: algorithm for selecting the initial directory is too simple
 *
 * FIXME: add to recent docs
 *
39
 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40
 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41
 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
42 43 44 45
 *
 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
 *
 *
46
 */
47 48 49 50

#include "config.h"
#include "wine/port.h"

51 52
#include <ctype.h>
#include <stdlib.h>
53
#include <stdarg.h>
54
#include <stdio.h>
55
#include <string.h>
56

57
#define COBJMACROS
58 59
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
60

61
#include "windef.h"
62
#include "winbase.h"
63
#include "winternl.h"
64
#include "winnls.h"
65
#include "wingdi.h"
66
#include "winreg.h"
67
#include "winuser.h"
68
#include "commdlg.h"
69 70
#include "dlgs.h"
#include "cdlg.h"
71
#include "cderr.h"
72 73 74 75 76
#include "shellapi.h"
#include "shlobj.h"
#include "filedlgbrowser.h"
#include "shlwapi.h"

77 78 79
#include "wine/unicode.h"
#include "wine/debug.h"

80 81 82
WINE_DEFAULT_DEBUG_CHANNEL(commdlg);

#define UNIMPLEMENTED_FLAGS \
83
(OFN_DONTADDTORECENT |\
84
OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
85
OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

#define IsHooked(fodInfos) \
	((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
/***********************************************************************
 * Data structure and global variables
 */
typedef struct SFolder
{
  int m_iImageIndex;    /* Index of picture in image list */
  HIMAGELIST hImgList;
  int m_iIndent;      /* Indentation index */
  LPITEMIDLIST pidlItem;  /* absolute pidl of the item */

} SFOLDER,*LPSFOLDER;

typedef struct tagLookInInfo
{
  int iMaxIndentation;
  UINT uSelectedItem;
} LookInInfos;


/***********************************************************************
 * Defines and global variables
 */

/* Draw item constant */
#define XTEXTOFFSET 3

/* AddItem flags*/
#define LISTEND -1

/* SearchItem methods */
#define SEARCH_PIDL 1
#define SEARCH_EXP  2
#define ITEM_NOTFOUND -1

/* Undefined windows message sent by CreateViewObject*/
#define WM_GETISHELLBROWSER  WM_USER+7

/* NOTE
 * Those macros exist in windowsx.h. However, you can't really use them since
 * they rely on the UNICODE defines and can't be used inside Wine itself.
 */

/* Combo box macros */
#define CBAddString(hwnd,str) \
133
    SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
134 135

#define CBInsertString(hwnd,str,pos) \
136
    SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
137 138

#define CBDeleteString(hwnd,pos) \
139
    SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
140 141

#define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
142
    SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
143 144

#define CBGetItemDataPtr(hwnd,iItemId) \
145
    SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
146 147

#define CBGetLBText(hwnd,iItemId,str) \
148
    SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
149 150

#define CBGetCurSel(hwnd) \
151
    SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
152 153

#define CBSetCurSel(hwnd,pos) \
154
    SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
155 156

#define CBGetCount(hwnd) \
157
    SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
158
#define CBShowDropDown(hwnd,show) \
159
    SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
160
#define CBSetItemHeight(hwnd,index,height) \
161
    SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
162

163
#define CBSetExtendedUI(hwnd,flag) \
164
    SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
165

166 167
const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
168
static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
169

170 171 172 173 174 175 176
static const WCHAR LastVisitedMRUW[] =
    {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
        'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
        'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
        'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};

177 178 179 180 181
/***********************************************************************
 * Prototypes
 */

/* Internal functions used by the dialog */
182
static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183
static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184
static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
185
static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
186
static BOOL    FILEDLG95_OnOpen(HWND hwnd);
187 188 189 190 191 192 193 194 195 196
static LRESULT FILEDLG95_InitControls(HWND hwnd);
static void    FILEDLG95_Clean(HWND hwnd);

/* Functions used by the shell navigation */
static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
static BOOL    FILEDLG95_SHELL_UpFolder(HWND hwnd);
static BOOL    FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
static void    FILEDLG95_SHELL_Clean(HWND hwnd);
static BOOL    FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);

197
/* Functions used by the EDIT box */
198
static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
199

200 201 202 203 204 205 206
/* Functions used by the filetype combo box */
static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
static BOOL    FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
static int     FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
static void    FILEDLG95_FILETYPE_Clean(HWND hwnd);

/* Functions used by the Look In combo box */
207
static void    FILEDLG95_LOOKIN_Init(HWND hwndCombo);
208 209 210 211 212 213 214 215 216
static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
static BOOL    FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
static int     FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
static int     FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
static int     FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
static int     FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
       int     FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
static void    FILEDLG95_LOOKIN_Clean(HWND hwnd);

217 218 219 220 221
/* Functions for dealing with the most-recently-used registry keys */
static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
static void FILEDLG95_MRU_save_filename(LPCWSTR filename);

222
/* Miscellaneous tool functions */
223
static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
224 225
IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
LPITEMIDLIST  GetParentPidl(LPITEMIDLIST pidl);
226
static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
227 228
static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
static UINT GetNumSelected( IDataObject *doSelected );
229 230 231 232 233

/* Shell memory allocation */
static void *MemAlloc(UINT size);
static void MemFree(void *mem);

234
static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
235 236
static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
237 238 239 240 241 242 243 244 245 246 247 248
static BOOL BrowseSelectedFolder(HWND hwnd);

/***********************************************************************
 *      GetFileName95
 *
 * Creates an Open common dialog box that lets the user select
 * the drive, directory, and the name of a file or set of files to open.
 *
 * IN  : The FileOpenDlgInfos structure associated with the dialog
 * OUT : TRUE on success
 *       FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
 */
249
static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
250 251 252
{

    LRESULT lRes;
253 254 255
    LPCVOID origTemplate;
    DWORD dwSize;
    LPDLGTEMPLATEW template;
256 257
    HRSRC hRes;
    HANDLE hDlgTmpl = 0;
258
    HRESULT hr;
259 260 261 262

    /* test for missing functionality */
    if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
    {
263
      FIXME("Flags 0x%08x not yet implemented\n",
264 265 266 267 268
         fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
    }

    /* Create the dialog from a template */

269
    if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
270 271 272 273
    {
        COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
        return FALSE;
    }
274 275 276
    if (!(dwSize = SizeofResource(COMDLG32_hInstance, hRes)) ||
        !(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes)) ||
        !(origTemplate = LockResource(hDlgTmpl)))
277 278 279 280
    {
        COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
        return FALSE;
    }
281 282 283 284 285 286
    if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize)))
    {
        COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE);
        return FALSE;
    }
    memcpy(template, origTemplate, dwSize);
287

288 289 290 291 292 293 294
    /* msdn: explorer style dialogs permit sizing by default.
     * The OFN_ENABLESIZING flag is only needed when a hook or
     * custom tmeplate is provided */
    if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
            !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
        fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;

295 296
    if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
    {
297
        template->style |= WS_SIZEBOX;
298 299 300
        fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
        fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
    }
301
    else
302
        template->style &= ~WS_SIZEBOX;
303

304

305 306 307
    /* old style hook messages */
    if (IsHooked(fodInfos))
    {
308 309 310 311
      fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
      fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
      fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
      fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
312 313
    }

314
    /* Some shell namespace extensions depend on COM being initialized. */
315
    hr = OleInitialize(NULL);
316

317 318 319 320 321 322 323 324
    if (fodInfos->unicode)
      lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
                                     template,
                                     fodInfos->ofnInfos->hwndOwner,
                                     FileOpenDlgProc95,
                                     (LPARAM) fodInfos);
    else
      lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
325
                                     template,
326 327 328
                                     fodInfos->ofnInfos->hwndOwner,
                                     FileOpenDlgProc95,
                                     (LPARAM) fodInfos);
329
    if (SUCCEEDED(hr)) 
330
        OleUninitialize();
331

332 333
    HeapFree(GetProcessHeap(), 0, template);

334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
    /* Unable to create the dialog */
    if( lRes == -1)
        return FALSE;

    return lRes;
}

/***********************************************************************
 *      GetFileDialog95A
 *
 * Call GetFileName95 with this structure and clean the memory.
 *
 * IN  : The OPENFILENAMEA initialisation structure passed to
 *       GetOpenFileNameA win api function (see filedlg.c)
 */
349
static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
350 351 352 353 354 355 356 357
{
  BOOL ret;
  FileOpenDlgInfos fodInfos;
  LPSTR lpstrSavDir = NULL;
  LPWSTR title = NULL;
  LPWSTR defext = NULL;
  LPWSTR filter = NULL;
  LPWSTR customfilter = NULL;
358 359 360 361 362 363
  INITCOMMONCONTROLSEX icc;

  /* Initialize ComboBoxEx32 */
  icc.dwSize = sizeof(icc);
  icc.dwICC = ICC_USEREX_CLASSES;
  InitCommonControlsEx(&icc);
364

365 366 367
  /* Initialize CommDlgExtendedError() */
  COMDLG32_SetCommDlgExtendedError(0);

368 369 370 371
  /* Initialize FileOpenDlgInfos structure */
  ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));

  /* Pass in the original ofn */
Jacek Caban's avatar
Jacek Caban committed
372
  fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438

  /* save current directory */
  if (ofn->Flags & OFN_NOCHANGEDIR)
  {
     lpstrSavDir = MemAlloc(MAX_PATH);
     GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
  }

  fodInfos.unicode = FALSE;

  /* convert all the input strings to unicode */
  if(ofn->lpstrInitialDir)
  {
    DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
    fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
    MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
  }
  else
    fodInfos.initdir = NULL;

  if(ofn->lpstrFile)
  {
    fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
    MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
  }
  else
    fodInfos.filename = NULL;

  if(ofn->lpstrDefExt)
  {
    DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
    defext = MemAlloc((len+1)*sizeof(WCHAR));
    MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
  }
  fodInfos.defext = defext;

  if(ofn->lpstrTitle)
  {
    DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
    title = MemAlloc((len+1)*sizeof(WCHAR));
    MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
  }
  fodInfos.title = title;

  if (ofn->lpstrFilter)
  {
    LPCSTR s;
    int n, len;

    /* filter is a list...  title\0ext\0......\0\0 */
    s = ofn->lpstrFilter;
    while (*s) s = s+strlen(s)+1;
    s++;
    n = s - ofn->lpstrFilter;
    len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
    filter = MemAlloc(len*sizeof(WCHAR));
    MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
  }
  fodInfos.filter = filter;

  /* convert lpstrCustomFilter */
  if (ofn->lpstrCustomFilter)
  {
    LPCSTR s;
    int n, len;

439
    /* customfilter contains a pair of strings...  title\0ext\0 */
440
    s = ofn->lpstrCustomFilter;
441 442
    if (*s) s = s+strlen(s)+1;
    if (*s) s = s+strlen(s)+1;
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
    n = s - ofn->lpstrCustomFilter;
    len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
    customfilter = MemAlloc(len*sizeof(WCHAR));
    MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
  }
  fodInfos.customfilter = customfilter;

  /* Initialize the dialog property */
  fodInfos.DlgInfos.dwDlgProp = 0;
  fodInfos.DlgInfos.hwndCustomDlg = NULL;

  switch(iDlgType)
  {
    case OPEN_DIALOG :
      ret = GetFileName95(&fodInfos);
      break;
    case SAVE_DIALOG :
      fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
      ret = GetFileName95(&fodInfos);
      break;
    default :
      ret = 0;
  }

  if (lpstrSavDir)
  {
      SetCurrentDirectoryA(lpstrSavDir);
      MemFree(lpstrSavDir);
  }

473 474 475 476 477 478
  MemFree(title);
  MemFree(defext);
  MemFree(filter);
  MemFree(customfilter);
  MemFree(fodInfos.initdir);
  MemFree(fodInfos.filename);
479 480 481 482 483 484 485 486 487 488 489 490 491

  TRACE("selected file: %s\n",ofn->lpstrFile);

  return ret;
}

/***********************************************************************
 *      GetFileDialog95W
 *
 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
 * Call GetFileName95 with this structure and clean the memory.
 *
 */
492
static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
493 494 495
{
  BOOL ret;
  FileOpenDlgInfos fodInfos;
Jacek Caban's avatar
Jacek Caban committed
496
  LPWSTR lpstrSavDir = NULL;
497 498 499 500 501 502
  INITCOMMONCONTROLSEX icc;

  /* Initialize ComboBoxEx32 */
  icc.dwSize = sizeof(icc);
  icc.dwICC = ICC_USEREX_CLASSES;
  InitCommonControlsEx(&icc);
503

504 505 506
  /* Initialize CommDlgExtendedError() */
  COMDLG32_SetCommDlgExtendedError(0);

507 508 509 510
  /* Initialize FileOpenDlgInfos structure */
  ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));

  /*  Pass in the original ofn */
Jacek Caban's avatar
Jacek Caban committed
511
  fodInfos.ofnInfos = ofn;
512 513 514 515 516 517 518 519 520 521

  fodInfos.title = ofn->lpstrTitle;
  fodInfos.defext = ofn->lpstrDefExt;
  fodInfos.filter = ofn->lpstrFilter;
  fodInfos.customfilter = ofn->lpstrCustomFilter;

  /* convert string arguments, save others */
  if(ofn->lpstrFile)
  {
    fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
522
    lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
523 524 525 526 527 528
  }
  else
    fodInfos.filename = NULL;

  if(ofn->lpstrInitialDir)
  {
529
    /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
530
    DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
531 532
    fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
    memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
533 534 535 536 537 538 539
  }
  else
    fodInfos.initdir = NULL;

  /* save current directory */
  if (ofn->Flags & OFN_NOCHANGEDIR)
  {
Jacek Caban's avatar
Jacek Caban committed
540 541
     lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
     GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
  }

  fodInfos.unicode = TRUE;

  switch(iDlgType)
  {
  case OPEN_DIALOG :
      ret = GetFileName95(&fodInfos);
      break;
  case SAVE_DIALOG :
      fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
      ret = GetFileName95(&fodInfos);
      break;
  default :
      ret = 0;
  }

  if (lpstrSavDir)
  {
Jacek Caban's avatar
Jacek Caban committed
561
      SetCurrentDirectoryW(lpstrSavDir);
562 563 564 565 566 567 568 569 570
      MemFree(lpstrSavDir);
  }

  /* restore saved IN arguments and convert OUT arguments back */
  MemFree(fodInfos.filename);
  MemFree(fodInfos.initdir);
  return ret;
}

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
/******************************************************************************
 * COMDLG32_GetDisplayNameOf [internal]
 *
 * Helper function to get the display name for a pidl.
 */
static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
    LPSHELLFOLDER psfDesktop;
    STRRET strret;
        
    if (FAILED(SHGetDesktopFolder(&psfDesktop)))
        return FALSE;

    if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
        IShellFolder_Release(psfDesktop);
        return FALSE;
    }

    IShellFolder_Release(psfDesktop);
    return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
}

592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
/******************************************************************************
 * COMDLG32_GetCanonicalPath [internal]
 *
 * Helper function to get the canonical path.
 */
void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
                               LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
{
  WCHAR lpstrTemp[MAX_PATH];

  /* Get the current directory name */
  if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
  {
    /* last fallback */
    GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
  }
  PathAddBackslashW(lpstrPathAndFile);

  TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));

  /* if the user specified a fully qualified path use it */
  if(PathIsRelativeW(lpstrFile))
  {
    lstrcatW(lpstrPathAndFile, lpstrFile);
  }
  else
  {
    /* does the path have a drive letter? */
    if (PathGetDriveNumberW(lpstrFile) == -1)
      lstrcpyW(lpstrPathAndFile+2, lpstrFile);
    else
      lstrcpyW(lpstrPathAndFile, lpstrFile);
  }

  /* resolve "." and ".." */
  PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
  lstrcpyW(lpstrPathAndFile, lpstrTemp);
  TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
}

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
/***********************************************************************
 *      COMDLG32_SplitFileNames [internal]
 *
 * Creates a delimited list of filenames.
 */
int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
{
	UINT nStrCharCount = 0;	/* index in src buffer */
	UINT nFileIndex = 0;	/* index in dest buffer */
	UINT nFileCount = 0;	/* number of files */

	/* we might get single filename without any '"',
	 * so we need nStrLen + terminating \0 + end-of-list \0 */
	*lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
	*sizeUsed = 0;

	/* build delimited file list from filenames */
	while ( nStrCharCount <= nStrLen )
	{
	  if ( lpstrEdit[nStrCharCount]=='"' )
	  {
	    nStrCharCount++;
	    while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
	    {
	      (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
	      nStrCharCount++;
	    }
	    (*lpstrFileList)[nFileIndex++] = 0;
	    nFileCount++;
	  }
	  nStrCharCount++;
	}

	/* single, unquoted string */
	if ((nStrLen > 0) && (nFileIndex == 0) )
	{
	  lstrcpyW(*lpstrFileList, lpstrEdit);
	  nFileIndex = lstrlenW(lpstrEdit) + 1;
	  nFileCount = 1;
	}

        /* trailing \0 */
        (*lpstrFileList)[nFileIndex++] = '\0';

        *sizeUsed = nFileIndex;
	return nFileCount;
}

680 681 682
/***********************************************************************
 *      ArrangeCtrlPositions [internal]
 *
683
 * NOTE: Make sure to add testcases for any changes made here.
684 685 686 687 688
 */
static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
{
    HWND hwndChild, hwndStc32;
    RECT rectParent, rectChild, rectStc32;
689 690
    INT help_fixup = 0;
    int chgx, chgy;
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757

    /* Take into account if open as read only checkbox and help button
     * are hidden
     */
     if (hide_help)
     {
         RECT rectHelp, rectCancel;
         GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
         GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
         /* subtract the height of the help button plus the space between
          * the help button and the cancel button to the height of the dialog
          */
          help_fixup = rectHelp.bottom - rectCancel.bottom;
    }

    /*
      There are two possibilities to add components to the default file dialog box.

      By default, all the new components are added below the standard dialog box (the else case).

      However, if there is a static text component with the stc32 id, a special case happens.
      The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
      in the window and the cx and cy indicate how to size the window.
      Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left 
      of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
      
     */

    GetClientRect(hwndParentDlg, &rectParent);

    /* when arranging controls we have to use fixed parent size */
    rectParent.bottom -= help_fixup;

    hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
    if (hwndStc32)
    {
        GetWindowRect(hwndStc32, &rectStc32);
        MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);

        /* set the size of the stc32 control according to the size of
         * client area of the parent dialog
         */
        SetWindowPos(hwndStc32, 0,
                     0, 0,
                     rectParent.right, rectParent.bottom,
                     SWP_NOMOVE | SWP_NOZORDER);
    }
    else
        SetRectEmpty(&rectStc32);

    /* this part moves controls of the child dialog */
    hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
    while (hwndChild)
    {
        if (hwndChild != hwndStc32)
        {
            GetWindowRect(hwndChild, &rectChild);
            MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);

            /* move only if stc32 exist */
            if (hwndStc32 && rectChild.left > rectStc32.right)
            {
                /* move to the right of visible controls of the parent dialog */
                rectChild.left += rectParent.right;
                rectChild.left -= rectStc32.right;
            }
            /* move even if stc32 doesn't exist */
758
            if (rectChild.top >= rectStc32.bottom)
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
            {
                /* move below visible controls of the parent dialog */
                rectChild.top += rectParent.bottom;
                rectChild.top -= rectStc32.bottom - rectStc32.top;
            }

            SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
                         0, 0, SWP_NOSIZE | SWP_NOZORDER);
        }
        hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
    }

    /* this part moves controls of the parent dialog */
    hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
    while (hwndChild)
    {
        if (hwndChild != hwndChildDlg)
        {
            GetWindowRect(hwndChild, &rectChild);
            MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);

            /* left,top of stc32 marks the position of controls
             * from the parent dialog
             */
            rectChild.left += rectStc32.left;
            rectChild.top += rectStc32.top;

            SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
                         0, 0, SWP_NOSIZE | SWP_NOZORDER);
        }
        hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
    }

    /* calculate the size of the resulting dialog */

    /* here we have to use original parent size */
    GetClientRect(hwndParentDlg, &rectParent);
    GetClientRect(hwndChildDlg, &rectChild);
797 798
    TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
            wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
799 800 801

    if (hwndStc32)
    {
802 803 804
        /* width */
        if (rectParent.right > rectStc32.right - rectStc32.left)
            chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
805
        else
806 807 808 809
            chgx = rectChild.right - rectParent.right;
        /* height */
        if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
            chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
810
        else
811 812
            /* Unconditionally set new dialog
             * height to that of the child
813
             */
814
            chgy = rectChild.bottom - rectParent.bottom;
815 816 817
    }
    else
    {
818 819
        chgx = 0;
        chgy = rectChild.bottom - help_fixup;
820 821
    }
    /* set the size of the parent dialog */
822
    GetWindowRect(hwndParentDlg, &rectParent);
823 824
    SetWindowPos(hwndParentDlg, 0,
                 0, 0,
825 826
                 rectParent.right - rectParent.left + chgx,
                 rectParent.bottom - rectParent.top + chgy,
827 828 829
                 SWP_NOMOVE | SWP_NOZORDER);
}

Mike McCormack's avatar
Mike McCormack committed
830
static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
831
{
832 833 834
    switch(uMsg) {
    case WM_INITDIALOG:
        return TRUE;
835
    }
836
    return FALSE;
837 838
}

Mike McCormack's avatar
Mike McCormack committed
839
static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
{
    LPCVOID template;
    HRSRC hRes;
    HANDLE hDlgTmpl = 0;
    HWND hChildDlg = 0;

    TRACE("\n");

    /*
     * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
     * structure's hInstance parameter is not a HINSTANCE, but
     * instead a pointer to a template resource to use.
     */
    if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
    {
      HINSTANCE hinst;
      if (fodInfos->ofnInfos->Flags  & OFN_ENABLETEMPLATEHANDLE)
      {
858
        hinst = COMDLG32_hInstance;
859 860 861 862 863 864 865 866 867 868 869
        if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
        {
          COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
          return NULL;
        }
      }
      else
      {
        hinst = fodInfos->ofnInfos->hInstance;
        if(fodInfos->unicode)
        {
Jacek Caban's avatar
Jacek Caban committed
870
            LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
871 872 873 874
            hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
        }
        else
        {
Jacek Caban's avatar
Jacek Caban committed
875
            LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
876 877 878 879 880 881 882 883 884 885 886 887 888 889
            hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
        }
        if (!hRes)
        {
          COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
          return NULL;
        }
        if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
            !(template = LockResource( hDlgTmpl )))
        {
          COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
          return NULL;
    	}
      }
890 891 892 893 894 895 896 897
      if (fodInfos->unicode)
          hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
              IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
              (LPARAM)fodInfos->ofnInfos);
      else
          hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
              IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
              (LPARAM)fodInfos->ofnInfos);
898
      return hChildDlg;
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
    }
    else if( IsHooked(fodInfos))
    {
      RECT rectHwnd;
      struct  {
         DLGTEMPLATE tmplate;
         WORD menu,class,title;
         } temp;
      GetClientRect(hwnd,&rectHwnd);
      temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
      temp.tmplate.dwExtendedStyle = 0;
      temp.tmplate.cdit = 0;
      temp.tmplate.x = 0;
      temp.tmplate.y = 0;
      temp.tmplate.cx = 0;
      temp.tmplate.cy = 0;
      temp.menu = temp.class = temp.title = 0;

      hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
918
                  hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
919 920 921 922 923 924 925 926 927 928 929 930

      return hChildDlg;
    }
    return NULL;
}

/***********************************************************************
*          SendCustomDlgNotificationMessage
*
* Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
*/

931
LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
932
{
933
    LRESULT hook_result = 0;
934
    FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
935 936 937

    TRACE("%p 0x%04x\n",hwndParentDlg, uCode);

938
    if(!fodInfos) return 0;
939 940 941 942

    if(fodInfos->DlgInfos.hwndCustomDlg)
    {
	TRACE("CALL NOTIFY for %x\n", uCode);
943 944 945 946 947 948
        if(fodInfos->unicode)
        {
            OFNOTIFYW ofnNotify;
            ofnNotify.hdr.hwndFrom=hwndParentDlg;
            ofnNotify.hdr.idFrom=0;
            ofnNotify.hdr.code = uCode;
Jacek Caban's avatar
Jacek Caban committed
949
            ofnNotify.lpOFN = fodInfos->ofnInfos;
950
            ofnNotify.pszFile = NULL;
951
            hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
952 953 954 955 956 957 958
        }
        else
        {
            OFNOTIFYA ofnNotify;
            ofnNotify.hdr.hwndFrom=hwndParentDlg;
            ofnNotify.hdr.idFrom=0;
            ofnNotify.hdr.code = uCode;
Jacek Caban's avatar
Jacek Caban committed
959
            ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
960
            ofnNotify.pszFile = NULL;
961
            hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
962
        }
963 964
	TRACE("RET NOTIFY\n");
    }
965 966
    TRACE("Retval: 0x%08lx\n", hook_result);
    return hook_result;
967 968
}

969
static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
970
{
971 972
    UINT len, total;
    WCHAR *p, *buffer;
973
    FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
974 975 976 977 978 979 980

    TRACE("CDM_GETFILEPATH:\n");

    if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
        return -1;

    /* get path and filenames */
981 982 983 984
    len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
    buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
    COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
    if (len)
985
    {
986 987 988
        p = buffer + strlenW(buffer);
        *p++ = '\\';
        SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
989
    }
990
    if (fodInfos->unicode)
991
    {
992 993 994
        total = strlenW( buffer) + 1;
        if (result) lstrcpynW( result, buffer, size );
        TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
995 996 997
    }
    else
    {
998 999 1000
        total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
        if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
        TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
1001
    }
1002 1003
    HeapFree( GetProcessHeap(), 0, buffer );
    return total;
1004 1005 1006 1007 1008 1009 1010
}

/***********************************************************************
*         FILEDLG95_HandleCustomDialogMessages
*
* Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
*/
1011
static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1012
{
1013
    FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1014
    WCHAR lpstrPath[MAX_PATH];
1015
    INT_PTR retval;
1016 1017

    if(!fodInfos) return FALSE;
1018 1019 1020 1021

    switch(uMsg)
    {
        case CDM_GETFILEPATH:
1022 1023
            retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
            break;
1024 1025 1026

        case CDM_GETFOLDERPATH:
            TRACE("CDM_GETFOLDERPATH:\n");
1027 1028
            COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
            if (lParam) 
1029
            {
1030 1031 1032 1033 1034 1035
                if (fodInfos->unicode)
                    lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
                else
                    WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1, 
                                        (LPSTR)lParam, (int)wParam, NULL, NULL);
            }        
1036
            retval = lstrlenW(lpstrPath) + 1;
1037
            break;
1038

1039 1040 1041 1042 1043 1044
        case CDM_GETFOLDERIDLIST:
            retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
            if (retval <= wParam)
                memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
            break;

1045
        case CDM_GETSPEC:
1046 1047 1048 1049 1050 1051 1052 1053 1054
            TRACE("CDM_GETSPEC:\n");
            retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
            if (lParam)
            {
                if (fodInfos->unicode)
                    SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
                else
                    SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
            }
1055
            break;
1056 1057 1058

        case CDM_SETCONTROLTEXT:
            TRACE("CDM_SETCONTROLTEXT:\n");
1059 1060 1061 1062 1063 1064 1065
	    if ( lParam )
            {
                if( fodInfos->unicode )
	            SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
                else
	            SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
            }
1066 1067
            retval = TRUE;
            break;
1068 1069

        case CDM_HIDECONTROL:
1070 1071 1072 1073 1074 1075 1076 1077
            /* MSDN states that it should fail for not OFN_EXPLORER case */
            if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
            {
                HWND control = GetDlgItem( hwnd, wParam );
                if (control) ShowWindow( control, SW_HIDE );
                retval = TRUE;
            }
            else retval = FALSE;
1078 1079 1080
            break;

        default:
1081 1082
            if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
                FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1083
            return FALSE;
1084
    }
1085
    SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1086 1087 1088
    return TRUE;
}

1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
/***********************************************************************
 *          FILEDLG95_OnWMGetMMI
 *
 * WM_GETMINMAXINFO message handler for resizable dialogs
 */
static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
{
    FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
    if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
    if( fodInfos->initial_size.x || fodInfos->initial_size.y)
    {
        mmiptr->ptMinTrackSize = fodInfos->initial_size;
    }
    return TRUE;
}

/***********************************************************************
 *          FILEDLG95_OnWMSize
 *
 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
 *
 * FIXME: this could be made more elaborate. Now use a simple scheme
 * where the file view is enlarged and the controls are either moved
 * vertically or horizontally to get out of the way. Only the "grip"
 * is moved in both directions to stay in the corner.
 */
1115
static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
{
    RECT rc, rcview;
    int chgx, chgy;
    HWND ctrl;
    HDWP hdwp;
    FileOpenDlgInfos *fodInfos;

    if( wParam != SIZE_RESTORED) return FALSE;
    fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
    if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
    /* get the new dialog rectangle */
    GetWindowRect( hwnd, &rc);
1128 1129
    TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
            rc.right -rc.left, rc.bottom -rc.top);
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
    /* not initialized yet */
    if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
        ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
             (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
        return FALSE;
    chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
    chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
    fodInfos->sizedlg.cx = rc.right - rc.left;
    fodInfos->sizedlg.cy = rc.bottom - rc.top;
    /* change the size of the view window */
    GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
    MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
    hdwp = BeginDeferWindowPos( 10);
    DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
            rcview.right - rcview.left + chgx,
            rcview.bottom - rcview.top + chgy,
            SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
    /* change position and sizes of the controls */
    for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
    {
1150
        int ctrlid = GetDlgCtrlID( ctrl);
1151 1152 1153 1154 1155 1156 1157
        GetWindowRect( ctrl, &rc);
        MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
        if( ctrl == fodInfos->DlgInfos.hwndGrip)
        {
            DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
                    0, 0,
                    SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1158
        }
1159 1160 1161 1162
        else if( rc.top > rcview.bottom)
        {
            /* if it was below the shell view
             * move to bottom */
1163 1164
            switch( ctrlid)
            {
1165
                /* file name (edit or comboboxex) and file types combo change also width */
1166
                case edt1:
1167
                case cmb13:
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
                case cmb1:
                    DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
                            rc.right - rc.left + chgx, rc.bottom - rc.top,
                            SWP_NOACTIVATE | SWP_NOZORDER);
                    break;
                    /* then these buttons must move out of the way */
                case IDOK:
                case IDCANCEL:
                case pshHelp:
                    DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
                            0, 0,
                            SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
                    break;
                default:
                DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
                        0, 0,
                        SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
            }
1186 1187 1188 1189 1190 1191
        }
        else if( rc.left > rcview.right)
        {
            /* if it was to the right of the shell view
             * move to right */
            DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1192
                    0, 0,
1193 1194
                    SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
        }
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
        else
            /* special cases */
        {
            switch( ctrlid)
            {
#if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
                case IDC_LOOKIN:
                    DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
                            rc.right - rc.left + chgx, rc.bottom - rc.top,
                            SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
                    break;
                case IDC_TOOLBARSTATIC:
                case IDC_TOOLBAR:
                    DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
                            0, 0,
                            SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
                    break;
#endif
                /* not resized in windows. Since wine uses this invisible control
                 * to size the browser view it needs to be resized */
                case IDC_SHELLSTATIC:
                    DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
                            rc.right - rc.left + chgx,
                            rc.bottom - rc.top + chgy,
                            SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
                    break;
            }
        }
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
    }
    if(fodInfos->DlgInfos.hwndCustomDlg &&
        (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
    {
        for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
                ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
        {
            GetWindowRect( ctrl, &rc);
            MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
            if( rc.top > rcview.bottom)
            {
                /* if it was below the shell view
                 * move to bottom */
                DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
                        rc.right - rc.left, rc.bottom - rc.top,
                        SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
            }
            else if( rc.left > rcview.right)
            {
                /* if it was to the right of the shell view
                 * move to right */
                DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
                        rc.right - rc.left, rc.bottom - rc.top,
                        SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
            }
        }
1249 1250 1251 1252 1253
        /* size the custom dialog at the end: some applications do some
         * control re-arranging at this point */
        GetClientRect(hwnd, &rc);
        DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
            0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1254 1255 1256 1257 1258 1259 1260
    }
    EndDeferWindowPos( hdwp);
    /* should not be needed */
    RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
    return TRUE;
}

1261 1262 1263 1264 1265 1266 1267 1268
/***********************************************************************
 *          FileOpenDlgProc95
 *
 * File open dialog procedure
 */
INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
#if 0
1269
  TRACE("%p 0x%04x\n", hwnd, uMsg);
1270 1271 1272 1273 1274 1275 1276
#endif

  switch(uMsg)
  {
    case WM_INITDIALOG:
      {
         FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1277
         RECT rc, rcstc;
1278 1279
         int gripx = GetSystemMetrics( SM_CYHSCROLL);
         int gripy = GetSystemMetrics( SM_CYVSCROLL);
1280 1281 1282

	 /* Adds the FileOpenDlgInfos in the property list of the dialog
            so it will be easily accessible through a GetPropA(...) */
1283
         SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1284

1285 1286
         FILEDLG95_InitControls(hwnd);

1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
         if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
         {
             GetWindowRect( hwnd, &rc);
             fodInfos->DlgInfos.hwndGrip =
                 CreateWindowExA( 0, "SCROLLBAR", NULL,
                     WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
                     SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
                     rc.right - gripx, rc.bottom - gripy,
                     gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
         }

1298 1299 1300
      	 fodInfos->DlgInfos.hwndCustomDlg =
     	   CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);

1301
         FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1302 1303
      	 FILEDLG95_FillControls(hwnd, wParam, lParam);

1304 1305 1306
         if( fodInfos->DlgInfos.hwndCustomDlg)
             ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);

1307
         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1308
             SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1309 1310
             SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
         }
1311

1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323
         /* if the app has changed the position of the invisible listbox,
          * change that of the listview (browser) as well */
         GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
         GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
         if( !EqualRect( &rc, &rcstc))
         {
             MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
             SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
                     rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
                     SWP_NOACTIVATE | SWP_NOZORDER);
         }

1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
         if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
         {
             GetWindowRect( hwnd, &rc);
             fodInfos->sizedlg.cx = rc.right - rc.left;
             fodInfos->sizedlg.cy = rc.bottom - rc.top;
             fodInfos->initial_size.x = fodInfos->sizedlg.cx;
             fodInfos->initial_size.y = fodInfos->sizedlg.cy;
             GetClientRect( hwnd, &rc);
             SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
                     rc.right - gripx, rc.bottom - gripy,
                     0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1335 1336 1337 1338 1339
             /* resize the dialog to the previous invocation */
             if( MemDialogSize.cx && MemDialogSize.cy)
                 SetWindowPos( hwnd, NULL,
                         0, 0, MemDialogSize.cx, MemDialogSize.cy,
                         SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1340 1341
         }

1342 1343
         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
             SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1344

1345 1346
         return 0;
       }
1347
    case WM_SIZE:
1348
      return FILEDLG95_OnWMSize(hwnd, wParam);
1349 1350
    case WM_GETMINMAXINFO:
      return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1351
    case WM_COMMAND:
1352
      return FILEDLG95_OnWMCommand(hwnd, wParam);
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367
    case WM_DRAWITEM:
      {
        switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
        {
        case IDC_LOOKIN:
          FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
          return TRUE;
        }
      }
      return FALSE;

    case WM_GETISHELLBROWSER:
      return FILEDLG95_OnWMGetIShellBrowser(hwnd);

    case WM_DESTROY:
1368 1369 1370 1371 1372 1373 1374
      {
          FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
          if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
              MemDialogSize = fodInfos->sizedlg;
          RemovePropA(hwnd, FileOpenDlgInfosStr);
          return FALSE;
      }
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409
    case WM_NOTIFY:
    {
	LPNMHDR lpnmh = (LPNMHDR)lParam;
	UINT stringId = -1;

	/* set up the button tooltips strings */
	if(TTN_GETDISPINFOA == lpnmh->code )
	{
	    LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
	    switch(lpnmh->idFrom )
	    {
		/* Up folder button */
		case FCIDM_TB_UPFOLDER:
		    stringId = IDS_UPFOLDER;
		    break;
		/* New folder button */
		case FCIDM_TB_NEWFOLDER:
		    stringId = IDS_NEWFOLDER;
		    break;
		/* List option button */
		case FCIDM_TB_SMALLICON:
		    stringId = IDS_LISTVIEW;
		    break;
		/* Details option button */
		case FCIDM_TB_REPORTVIEW:
		    stringId = IDS_REPORTVIEW;
		    break;
		/* Desktop button */
		case FCIDM_TB_DESKTOP:
		    stringId = IDS_TODESKTOP;
		    break;
		default:
		    stringId = 0;
	    }
	    lpdi->hinst = COMDLG32_hInstance;
Kevin Koltzau's avatar
Kevin Koltzau committed
1410
	    lpdi->lpszText =  MAKEINTRESOURCEA(stringId);
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
	}
        return FALSE;
    }
    default :
      if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
        return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
      return FALSE;
  }
}

1421 1422 1423 1424 1425 1426
static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
{
    return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
        (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
}

1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
/***********************************************************************
 *      FILEDLG95_InitControls
 *
 * WM_INITDIALOG message handler (before hook notification)
 */
static LRESULT FILEDLG95_InitControls(HWND hwnd)
{
  int win2000plus = 0;
  int win98plus   = 0;
  int handledPath = FALSE;
1437
  OSVERSIONINFOW osVi;
1438 1439
  static const WCHAR szwSlash[] = { '\\', 0 };
  static const WCHAR szwStar[] = { '*',0 };
1440

1441
  static const TBBUTTON tbb[] =
1442
  {
1443 1444 1445 1446 1447 1448 1449 1450 1451
   {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
   {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER,   TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
   {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
   {VIEW_NEWFOLDER+1,  FCIDM_TB_DESKTOP,    TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
   {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
   {VIEW_NEWFOLDER,    FCIDM_TB_NEWFOLDER,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
   {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
   {VIEW_LIST,         FCIDM_TB_SMALLICON,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
   {VIEW_DETAILS,      FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1452
  };
1453 1454
  static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};

1455 1456 1457
  RECT rectTB;
  RECT rectlook;

1458 1459 1460 1461 1462
  HIMAGELIST toolbarImageList;
  SHFILEINFOA shFileInfo;
  ITEMIDLIST *desktopPidl;

  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1463 1464 1465 1466

  TRACE("%p\n", fodInfos);

  /* Get windows version emulating */
1467 1468
  osVi.dwOSVersionInfoSize = sizeof(osVi);
  GetVersionExW(&osVi);
1469 1470 1471 1472 1473 1474 1475 1476
  if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
    win98plus   = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
  } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
    win2000plus = (osVi.dwMajorVersion > 4);
    if (win2000plus) win98plus = TRUE;
  }
  TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);

1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489

  /* Use either the edit or the comboboxex for the filename control */
  if (filename_is_edit( fodInfos ))
  {
      DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
      fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
  }
  else
  {
      DestroyWindow( GetDlgItem( hwnd, edt1 ) );
      fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
  }

1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
  /* Get the hwnd of the controls */
  fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
  fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);

  GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
  MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);

  /* construct the toolbar */
  GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
  MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);

  rectTB.right = rectlook.right + rectTB.right - rectTB.left;
  rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
  rectTB.left = rectlook.right;
  rectTB.top = rectlook.top-1;

1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
  if (fodInfos->unicode)
      fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
          WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
          rectTB.left, rectTB.top,
          rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
          hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
  else
      fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
          WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
          rectTB.left, rectTB.top,
          rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
          hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1518

1519
  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1520 1521

/* FIXME: use TB_LOADIMAGES when implemented */
1522
/*  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1523
  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534
  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);

  /* Retrieve and add desktop icon to the toolbar */
  toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
  SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
  SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
    SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
  ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);

  DestroyIcon(shFileInfo.hIcon);
  CoTaskMemFree(desktopPidl);
1535

1536
  /* Finish Toolbar Construction */
1537
  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1538
  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1539 1540 1541 1542 1543 1544 1545 1546

  /* Set the window text with the text specified in the OPENFILENAME structure */
  if(fodInfos->title)
  {
      SetWindowTextW(hwnd,fodInfos->title);
  }
  else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
  {
1547
      WCHAR buf[64];
1548
      LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, sizeof(buf)/sizeof(WCHAR));
1549
      SetWindowTextW(hwnd, buf);
1550 1551 1552 1553
  }

  /* Initialise the file name edit control */
  handledPath = FALSE;
1554
  TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568

  if(fodInfos->filename)
  {
      /* 1. If win2000 or higher and filename contains a path, use it
         in preference over the lpstrInitialDir                       */
      if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
         WCHAR tmpBuf[MAX_PATH];
         WCHAR *nameBit;
         DWORD result;

         result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
         if (result) {

            /* nameBit is always shorter than the original filename */
1569
            lstrcpyW(fodInfos->filename,nameBit);
1570 1571

            *nameBit = 0x00;
Ken Thomases's avatar
Ken Thomases committed
1572
            MemFree(fodInfos->initdir);
1573 1574
            fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
            lstrcpyW(fodInfos->initdir, tmpBuf);
1575 1576 1577 1578
            handledPath = TRUE;
            TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
                    debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
         }
1579
         SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1580 1581

      } else {
1582
         SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597
      }
  }

  /* 2. (All platforms) If initdir is not null, then use it */
  if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
                                (*fodInfos->initdir!=0x00))
  {
      /* Work out the proper path as supplied one might be relative          */
      /* (Here because supplying '.' as dir browses to My Computer)          */
      if (handledPath==FALSE) {
          WCHAR tmpBuf[MAX_PATH];
          WCHAR tmpBuf2[MAX_PATH];
          WCHAR *nameBit;
          DWORD result;

1598
          lstrcpyW(tmpBuf, fodInfos->initdir);
1599 1600 1601 1602
          if( PathFileExistsW(tmpBuf) ) {
              /* initdir does not have to be a directory. If a file is
               * specified, the dir part is taken */
              if( PathIsDirectoryW(tmpBuf)) {
1603 1604
                  if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
                     lstrcatW(tmpBuf, szwSlash);
1605
                  }
1606
                  lstrcatW(tmpBuf, szwStar);
1607 1608 1609 1610
              }
              result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
              if (result) {
                 *nameBit = 0x00;
1611
                 MemFree(fodInfos->initdir);
1612 1613
                 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
                 lstrcpyW(fodInfos->initdir, tmpBuf2);
1614 1615 1616
                 handledPath = TRUE;
                 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
              }
1617
          }
1618 1619 1620 1621 1622
          else if (fodInfos->initdir)
          {
                    MemFree(fodInfos->initdir);
                    fodInfos->initdir = NULL;
                    TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
          }
      }
  }

  if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
                                 (*fodInfos->initdir==0x00)))
  {
      /* 3. All except w2k+: if filename contains a path use it */
      if (!win2000plus && fodInfos->filename &&
          *fodInfos->filename &&
          strpbrkW(fodInfos->filename, szwSlash)) {
         WCHAR tmpBuf[MAX_PATH];
         WCHAR *nameBit;
         DWORD result;

         result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
                                  tmpBuf, &nameBit);
         if (result) {
            int len;

            /* nameBit is always shorter than the original filename */
1644
            lstrcpyW(fodInfos->filename, nameBit);
1645 1646
            *nameBit = 0x00;

1647
            len = lstrlenW(tmpBuf);
1648
            MemFree(fodInfos->initdir);
1649
            fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1650
            lstrcpyW(fodInfos->initdir, tmpBuf);
1651 1652 1653 1654 1655

            handledPath = TRUE;
            TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
                 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
         }
1656
         SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1657 1658
      }

1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674
      /* 4. Win2000+: Recently used */
      if (handledPath == FALSE && win2000plus) {
          fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
          fodInfos->initdir[0] = '\0';

          FILEDLG95_MRU_load_filename(fodInfos->initdir);

          if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
             handledPath = TRUE;
          }else{
             MemFree(fodInfos->initdir);
             fodInfos->initdir = NULL;
          }
      }

      /* 5. win98+ and win2000+ if any files of specified filter types in
1675 1676 1677 1678 1679 1680 1681 1682
            current directory, use it                                      */
      if ( win98plus && handledPath == FALSE &&
           fodInfos->filter && *fodInfos->filter) {

         LPCWSTR lpstrPos = fodInfos->filter;
         WIN32_FIND_DATAW FindFileData;
         HANDLE hFind;

1683
         while (1)
1684 1685 1686 1687 1688
         {
           /* filter is a list...  title\0ext\0......\0\0 */

           /* Skip the title */
           if(! *lpstrPos) break;	/* end */
1689
           lpstrPos += lstrlenW(lpstrPos) + 1;
1690 1691 1692 1693 1694 1695 1696 1697

           /* See if any files exist in the current dir with this extension */
           if(! *lpstrPos) break;	/* end */

           hFind = FindFirstFileW(lpstrPos, &FindFileData);

           if (hFind == INVALID_HANDLE_VALUE) {
               /* None found - continue search */
1698
               lpstrPos += lstrlenW(lpstrPos) + 1;
1699 1700 1701

           } else {

1702
               MemFree(fodInfos->initdir);
1703 1704 1705 1706 1707 1708
               fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
               GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);

               handledPath = TRUE;
               TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
                 debugstr_w(lpstrPos));
1709
               FindClose(hFind);
1710 1711 1712 1713 1714 1715 1716 1717 1718
               break;
           }
         }
      }

      /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
      if (handledPath == FALSE && (win2000plus || win98plus)) {
          fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));

1719
          if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1720
          {
1721
            if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739
            {
                /* last fallback */
                GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
                TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
            } else {
                TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
            }
          } else {
            TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
          }
          handledPath = TRUE;
      } else if (handledPath==FALSE) {
          fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
          GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
          handledPath = TRUE;
          TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
      }
  }
1740
  SetFocus( fodInfos->DlgInfos.hwndFileName );
1741 1742 1743 1744 1745
  TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));

  /* Must the open as read only check box be checked ?*/
  if(fodInfos->ofnInfos->Flags & OFN_READONLY)
  {
1746
    SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762
  }

  /* Must the open as read only check box be hidden? */
  if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
  {
    ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
    EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
  }

  /* Must the help button be hidden? */
  if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
  {
    ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
    EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
  }

1763
  /* change Open to Save */
1764 1765
  if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
  {
1766 1767 1768 1769 1770
      WCHAR buf[16];
      LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
      SetDlgItemTextW(hwnd, IDOK, buf);
      LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
      SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1771
  }
1772 1773 1774 1775

  /* Initialize the filter combo box */
  FILEDLG95_FILETYPE_Init(hwnd);

1776 1777 1778
  return 0;
}

1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806
/***********************************************************************
 *      FILEDLG95_ResizeControls
 *
 * WM_INITDIALOG message handler (after hook notification)
 */
static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
  FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;

  if (fodInfos->DlgInfos.hwndCustomDlg)
  {
    RECT rc;
    UINT flags = SWP_NOACTIVATE;

    ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
        (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);

    /* resize the custom dialog to the parent size */
    if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
      GetClientRect(hwnd, &rc);
    else
    {
      /* our own fake template is zero sized and doesn't have children, so
       * there is no need to resize it. Picasa depends on it.
       */
      flags |= SWP_NOSIZE;
      SetRectEmpty(&rc);
    }
1807 1808
    SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
                 0, 0, rc.right, rc.bottom, flags);
1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833
  }
  else
  {
    /* Resize the height, if open as read only checkbox ad help button are
     * hidden and we are not using a custom template nor a customDialog
     */
    if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
                (!(fodInfos->ofnInfos->Flags &
                   (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
    {
      RECT rectDlg, rectHelp, rectCancel;
      GetWindowRect(hwnd, &rectDlg);
      GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
      GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
      /* subtract the height of the help button plus the space between the help
       * button and the cancel button to the height of the dialog
       */
      SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
          (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
          SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
    }
  }
  return TRUE;
}

1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887
/***********************************************************************
 *      FILEDLG95_FillControls
 *
 * WM_INITDIALOG message handler (after hook notification)
 */
static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
  LPITEMIDLIST pidlItemId = NULL;

  FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;

  TRACE("dir=%s file=%s\n",
  debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));

  /* Get the initial directory pidl */

  if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
  {
    WCHAR path[MAX_PATH];

    GetCurrentDirectoryW(MAX_PATH,path);
    pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
  }

  /* Initialise shell objects */
  FILEDLG95_SHELL_Init(hwnd);

  /* Initialize the Look In combo box */
  FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);

  /* Browse to the initial directory */
  IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);

  /* Free pidlItem memory */
  COMDLG32_SHFree(pidlItemId);

  return TRUE;
}
/***********************************************************************
 *      FILEDLG95_Clean
 *
 * Regroups all the cleaning functions of the filedlg
 */
void FILEDLG95_Clean(HWND hwnd)
{
      FILEDLG95_FILETYPE_Clean(hwnd);
      FILEDLG95_LOOKIN_Clean(hwnd);
      FILEDLG95_SHELL_Clean(hwnd);
}
/***********************************************************************
 *      FILEDLG95_OnWMCommand
 *
 * WM_COMMAND message handler
 */
1888
static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1889 1890 1891
{
  WORD wNotifyCode = HIWORD(wParam); /* notification code */
  WORD wID = LOWORD(wParam);         /* item, control, or accelerator identifier */
1892
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935

  switch(wID)
  {
    /* OK button */
  case IDOK:
    FILEDLG95_OnOpen(hwnd);
    break;
    /* Cancel button */
  case IDCANCEL:
    FILEDLG95_Clean(hwnd);
    EndDialog(hwnd, FALSE);
    break;
    /* Filetype combo box */
  case IDC_FILETYPE:
    FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
    break;
    /* LookIn combo box */
  case IDC_LOOKIN:
    FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
    break;

  /* --- toolbar --- */
    /* Up folder button */
  case FCIDM_TB_UPFOLDER:
    FILEDLG95_SHELL_UpFolder(hwnd);
    break;
    /* New folder button */
  case FCIDM_TB_NEWFOLDER:
    FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
    break;
    /* List option button */
  case FCIDM_TB_SMALLICON:
    FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
    break;
    /* Details option button */
  case FCIDM_TB_REPORTVIEW:
    FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
    break;
    /* Details option button */
  case FCIDM_TB_DESKTOP:
    FILEDLG95_SHELL_BrowseToDesktop(hwnd);
    break;

1936 1937
  case edt1:
  case cmb13:
1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
    break;

  }
  /* Do not use the listview selection anymore */
  fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
  return 0;
}

/***********************************************************************
 *      FILEDLG95_OnWMGetIShellBrowser
 *
 * WM_GETISHELLBROWSER message handler
 */
static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
{
1953
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1954 1955 1956

  TRACE("\n");

1957
  SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976

  return TRUE;
}


/***********************************************************************
 *      FILEDLG95_SendFileOK
 *
 * Sends the CDN_FILEOK notification if required
 *
 * RETURNS
 *  TRUE if the dialog should close
 *  FALSE if the dialog should not be closed
 */
static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
{
    /* ask the hook if we can close */
    if(IsHooked(fodInfos))
    {
1977
        LRESULT retval = 0;
1978

1979 1980
        TRACE("---\n");
        /* First send CDN_FILEOK as MSDN doc says */
1981 1982
        if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
            retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1983
        if( retval)
1984 1985
        {
            TRACE("canceled\n");
1986
            return FALSE;
1987
        }
1988 1989

        /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1990 1991
        retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
                              fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1992
        if( retval)
1993 1994
        {
            TRACE("canceled\n");
1995
            return FALSE;
1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
        }
    }
    return TRUE;
}

/***********************************************************************
 *      FILEDLG95_OnOpenMultipleFiles
 *
 * Handles the opening of multiple files.
 *
 * FIXME
 *  check destination buffer size
 */
BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
{
  WCHAR   lpstrPathSpec[MAX_PATH] = {0};
  UINT   nCount, nSizePath;
2013
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2014 2015 2016 2017 2018

  TRACE("\n");

  if(fodInfos->unicode)
  {
Jacek Caban's avatar
Jacek Caban committed
2019
     LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2020 2021 2022 2023
     ofn->lpstrFile[0] = '\0';
  }
  else
  {
Jacek Caban's avatar
Jacek Caban committed
2024
     LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2025 2026 2027
     ofn->lpstrFile[0] = '\0';
  }

2028
  COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045

  if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
      ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
       ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
  {
    LPWSTR lpstrTemp = lpstrFileList;

    for ( nCount = 0; nCount < nFileCount; nCount++ )
    {
      LPITEMIDLIST pidl;

      pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
      if (!pidl)
      {
        WCHAR lpstrNotFound[100];
        WCHAR lpstrMsg[100];
        WCHAR tmp[400];
2046
        static const WCHAR nl[] = {'\n',0};
2047 2048 2049 2050

        LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
        LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);

2051 2052 2053 2054 2055
        lstrcpyW(tmp, lpstrTemp);
        lstrcatW(tmp, nl);
        lstrcatW(tmp, lpstrNotFound);
        lstrcatW(tmp, nl);
        lstrcatW(tmp, lpstrMsg);
2056 2057 2058 2059 2060 2061

        MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
        return FALSE;
      }

      /* move to the next file in the list of files */
2062
      lpstrTemp += lstrlenW(lpstrTemp) + 1;
2063 2064 2065 2066
      COMDLG32_SHFree(pidl);
    }
  }

2067
  nSizePath = lstrlenW(lpstrPathSpec) + 1;
2068 2069 2070
  if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
  {
    /* For "oldstyle" dialog the components have to
2071
       be separated by blanks (not '\0'!) and short
2072
       filenames have to be used! */
2073
    FIXME("Components have to be separated by blanks\n");
2074 2075 2076
  }
  if(fodInfos->unicode)
  {
Jacek Caban's avatar
Jacek Caban committed
2077
    LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2078
    lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2079 2080 2081 2082
    memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
  }
  else
  {
Jacek Caban's avatar
Jacek Caban committed
2083
    LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2084 2085 2086

    if (ofn->lpstrFile != NULL)
    {
2087
      nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2088 2089 2090 2091 2092 2093 2094 2095 2096 2097
			  ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
      if (ofn->nMaxFile > nSizePath)
      {
	WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
			    ofn->lpstrFile + nSizePath,
			    ofn->nMaxFile - nSizePath, NULL, NULL);
      }
    }
  }

2098
  fodInfos->ofnInfos->nFileOffset = nSizePath;
2099 2100 2101 2102 2103 2104 2105 2106 2107 2108
  fodInfos->ofnInfos->nFileExtension = 0;

  if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
    return FALSE;

  /* clean and exit */
  FILEDLG95_Clean(hwnd);
  return EndDialog(hwnd,TRUE);
}

2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200
/* Returns the 'slot name' of the given module_name in the registry's
 * most-recently-used list.  This will be an ASCII value in the
 * range ['a','z'). Returns zero on error.
 *
 * The slot's value in the registry has the form:
 *   module_name\0mru_path\0
 *
 * If stored_path is given, then stored_path will contain the path name
 * stored in the registry's MRU list for the given module_name.
 *
 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
 * MRU list key for the given module_name.
 */
static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
{
    WCHAR mru_list[32], *cur_mru_slot;
    BOOL taken[25] = {0};
    DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
    HKEY hkey_tmp, *hkey;
    LONG ret;

    if(hkey_ret)
        hkey = hkey_ret;
    else
        hkey = &hkey_tmp;

    if(stored_path)
        *stored_path = '\0';

    ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
    if(ret){
        WARN("Unable to create MRU key: %d\n", ret);
        return 0;
    }

    ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
            (LPBYTE)mru_list, &mru_list_size);
    if(ret || key_type != REG_SZ){
        if(ret == ERROR_FILE_NOT_FOUND)
            return 'a';

        WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
        RegCloseKey(*hkey);
        return 0;
    }

    for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
        WCHAR value_data[MAX_PATH], value_name[2] = {0};
        DWORD value_data_size = sizeof(value_data);

        *value_name = *cur_mru_slot;

        ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
                &key_type, (LPBYTE)value_data, &value_data_size);
        if(ret || key_type != REG_BINARY){
            WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
            continue;
        }

        if(!strcmpiW(module_name, value_data)){
            if(!hkey_ret)
                RegCloseKey(*hkey);
            if(stored_path)
                lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
            return *value_name;
        }
    }

    if(!hkey_ret)
        RegCloseKey(*hkey);

    /* the module name isn't in the registry, so find the next open slot */
    for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
        taken[*cur_mru_slot - 'a'] = TRUE;
    for(i = 0; i < 25; ++i){
        if(!taken[i])
            return i + 'a';
    }

    /* all slots are taken, so return the last one in MRUList */
    --cur_mru_slot;
    return *cur_mru_slot;
}

/* save the given filename as most-recently-used path for this module */
static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
{
    WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
    LONG ret;
    HKEY hkey;

    /* get the current executable's name */
2201
    if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
        WARN("GotModuleFileName failed: %d\n", GetLastError());
        return;
    }
    module_name = strrchrW(module_path, '\\');
    if(!module_name)
        module_name = module_path;
    else
        module_name += 1;

    slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
    if(!slot)
        return;
    *slot_name = slot;

    { /* update the slot's info */
        WCHAR *path_ends, *final;
        DWORD path_len, final_len;

        /* use only the path segment of `filename' */
        path_ends = strrchrW(filename, '\\');
        path_len = path_ends - filename;

        final_len = path_len + lstrlenW(module_name) + 2;

        final = MemAlloc(final_len * sizeof(WCHAR));
        if(!final)
            return;
        lstrcpyW(final, module_name);
        memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
        final[final_len-1] = '\0';

        ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
                final_len * sizeof(WCHAR));
        if(ret){
            WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
            MemFree(final);
            RegCloseKey(hkey);
            return;
        }

        MemFree(final);
    }

    { /* update MRUList value */
        WCHAR old_mru_list[32], new_mru_list[32];
        WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
        DWORD mru_list_size = sizeof(old_mru_list), key_type;

        ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
                (LPBYTE)old_mru_list, &mru_list_size);
        if(ret || key_type != REG_SZ){
            if(ret == ERROR_FILE_NOT_FOUND){
                new_mru_list[0] = slot;
                new_mru_list[1] = '\0';
            }else{
                WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
                RegCloseKey(hkey);
                return;
            }
        }else{
            /* copy old list data over so that the new slot is at the start
             * of the list */
            *new_mru_slot++ = slot;
            for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
                if(*old_mru_slot != slot)
                    *new_mru_slot++ = *old_mru_slot;
            }
            *new_mru_slot = '\0';
        }

        ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
                (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
        if(ret){
            WARN("Error saving MRUList data: %d\n", ret);
            RegCloseKey(hkey);
            return;
        }
    }
}

/* load the most-recently-used path for this module */
static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
{
    WCHAR module_path[MAX_PATH], *module_name;

    /* get the current executable's name */
2288
    if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301
        WARN("GotModuleFileName failed: %d\n", GetLastError());
        return;
    }
    module_name = strrchrW(module_path, '\\');
    if(!module_name)
        module_name = module_path;
    else
        module_name += 1;

    FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
    TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
}

2302
void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2303
{
2304 2305
  WCHAR strMsgTitle[MAX_PATH];
  WCHAR strMsgText [MAX_PATH];
2306
  if (idCaption)
2307
    LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2308 2309
  else
    strMsgTitle[0] = '\0';
2310 2311
  LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
  MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2312 2313
}

2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437
int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
                                 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
{
    int nOpenAction = defAction;
    LPWSTR lpszTemp, lpszTemp1;
    LPITEMIDLIST pidl = NULL;
    static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};

    /* check for invalid chars */
    if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
    {
        FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
        return FALSE;
    }

    if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;

    lpszTemp1 = lpszTemp = lpstrPathAndFile;
    while (lpszTemp1)
    {
        LPSHELLFOLDER lpsfChild;
        WCHAR lpwstrTemp[MAX_PATH];
        DWORD dwEaten, dwAttributes;
        LPWSTR p;

        lstrcpyW(lpwstrTemp, lpszTemp);
        p = PathFindNextComponentW(lpwstrTemp);

        if (!p) break; /* end of path */

        *p = 0;
        lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);

        /* There are no wildcards when OFN_NOVALIDATE is set */
        if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
        {
            static const WCHAR wszWild[] = { '*', '?', 0 };
            /* if the last element is a wildcard do a search */
            if(strpbrkW(lpszTemp1, wszWild) != NULL)
            {
                nOpenAction = ONOPEN_SEARCH;
                break;
            }
        }
        lpszTemp1 = lpszTemp;

        TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);

        /* append a backslash to drive letters */
        if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
           ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
            (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
        {
            PathAddBackslashW(lpwstrTemp);
        }

        dwAttributes = SFGAO_FOLDER;
        if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
        {
            /* the path component is valid, we have a pidl of the next path component */
            TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
            if(dwAttributes & SFGAO_FOLDER)
            {
                if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
                {
                    ERR("bind to failed\n"); /* should not fail */
                    break;
                }
                IShellFolder_Release(*ppsf);
                *ppsf = lpsfChild;
                lpsfChild = NULL;
            }
            else
            {
                TRACE("value\n");

                /* end dialog, return value */
                nOpenAction = ONOPEN_OPEN;
                break;
            }
            COMDLG32_SHFree(pidl);
            pidl = NULL;
        }
        else if (!(flags & OFN_NOVALIDATE))
        {
            if(*lpszTemp ||	/* points to trailing null for last path element */
               (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
            {
                if(flags & OFN_PATHMUSTEXIST)
                {
                    FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
                    break;
                }
            }
            else
            {
                if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
                {
                    FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
                    break;
                }
            }
            /* change to the current folder */
            nOpenAction = ONOPEN_OPEN;
            break;
        }
        else
        {
            nOpenAction = ONOPEN_OPEN;
            break;
        }
    }
    if(pidl) COMDLG32_SHFree(pidl);

    return nOpenAction;
}

/***********************************************************************
 *      FILEDLG95_OnOpen
 *
 * Ok button WM_COMMAND message handler
 *
 * If the function succeeds, the return value is nonzero.
 */
2438 2439 2440 2441 2442 2443 2444 2445 2446
BOOL FILEDLG95_OnOpen(HWND hwnd)
{
  LPWSTR lpstrFileList;
  UINT nFileCount = 0;
  UINT sizeUsed = 0;
  BOOL ret = TRUE;
  WCHAR lpstrPathAndFile[MAX_PATH];
  LPSHELLFOLDER lpsf = NULL;
  int nOpenAction;
2447
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2448 2449 2450

  TRACE("hwnd=%p\n", hwnd);

2451 2452 2453 2454
  /* try to browse the selected item */
  if(BrowseSelectedFolder(hwnd))
      return FALSE;

2455
  /* get the files from the edit control */
2456
  nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477

  if(nFileCount == 0)
      return FALSE;

  if(nFileCount > 1)
  {
      ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
      goto ret;
  }

  TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));

/*
  Step 1:  Build a complete path name from the current folder and
  the filename or path in the edit box.
  Special cases:
  - the path in the edit box is a root path
    (with or without drive letter)
  - the edit box contains ".." (or a path with ".." in it)
*/

2478
  COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491
  MemFree(lpstrFileList);

/*
  Step 2: here we have a cleaned up path

  We have to parse the path step by step to see if we have to browse
  to a folder if the path points to a directory or the last
  valid element is a directory.

  valid variables:
    lpstrPathAndFile: cleaned up path
 */

2492 2493 2494 2495 2496 2497
  if (nFileCount &&
      (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
      !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
    nOpenAction = ONOPEN_OPEN;
  else
    nOpenAction = ONOPEN_BROWSE;
2498

2499 2500 2501 2502 2503
  nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
                                             fodInfos->ofnInfos->Flags,
                                             fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
                                             nOpenAction);
  if(!nOpenAction)
2504
      goto ret;
2505

2506 2507
/*
  Step 3: here we have a cleaned up and validated path
2508

2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525
  valid variables:
   lpsf:             ShellFolder bound to the rightmost valid path component
   lpstrPathAndFile: cleaned up path
   nOpenAction:      action to do
*/
  TRACE("end validate sf=%p\n", lpsf);

  switch(nOpenAction)
  {
    case ONOPEN_SEARCH:   /* set the current filter to the file mask and refresh */
      TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
      {
        int iPos;
        LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
        DWORD len;

        /* replace the current filter */
2526
        MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2527
        len = lstrlenW(lpszTemp)+1;
2528
        fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2529
        lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2530 2531 2532 2533

        /* set the filter cb to the extension when possible */
        if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
        CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2534 2535 2536 2537 2538 2539
      }
      /* fall through */
    case ONOPEN_BROWSE:   /* browse to the highest folder we could bind to */
      TRACE("ONOPEN_BROWSE\n");
      {
	IPersistFolder2 * ppf2;
2540 2541 2542 2543 2544 2545 2546
        if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
        {
          LPITEMIDLIST pidlCurrent;
          IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
          IPersistFolder2_Release(ppf2);
	  if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
	  {
2547 2548
            if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
                && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2549 2550 2551
            {
              SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
            }
2552
	  }
2553
	  else if( nOpenAction == ONOPEN_SEARCH )
2554
	  {
2555 2556
            if (fodInfos->Shell.FOIShellView)
              IShellView_Refresh(fodInfos->Shell.FOIShellView);
2557 2558
	  }
          COMDLG32_SHFree(pidlCurrent);
2559 2560
          if (filename_is_edit( fodInfos ))
              SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2561 2562 2563 2564 2565 2566 2567
        }
      }
      ret = FALSE;
      break;
    case ONOPEN_OPEN:   /* fill in the return struct and close the dialog */
      TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
      {
2568 2569
        WCHAR *ext = NULL;

2570
        /* update READONLY check box flag */
2571
	if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2572 2573 2574 2575
	  fodInfos->ofnInfos->Flags |= OFN_READONLY;
	else
	  fodInfos->ofnInfos->Flags &= ~OFN_READONLY;

2576
        /* Attach the file extension with file name*/
2577
        ext = PathFindExtensionW(lpstrPathAndFile);
2578
        if (! *ext && fodInfos->defext)
2579
        {
2580 2581
            /* if no extension is specified with file name, then */
            /* attach the extension from file filter or default one */
2582
            
2583
            WCHAR *filterExt = NULL;
2584 2585
            LPWSTR lpstrFilter = NULL;
            static const WCHAR szwDot[] = {'.',0};
2586
            int PathLength = lstrlenW(lpstrPathAndFile);
2587

2588 2589 2590
            /*Get the file extension from file type filter*/
            lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
                                             fodInfos->ofnInfos->nFilterIndex-1);
2591

2592
            if (lpstrFilter != (LPWSTR)CB_ERR)  /* control is not empty */
2593
            {
2594 2595
                WCHAR* filterSearchIndex;
                filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2596 2597 2598 2599 2600
                strcpyW(filterExt, lpstrFilter);

                /* if a semicolon-separated list of file extensions was given, do not include the
                   semicolon or anything after it in the extension.
                   example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2601 2602
                filterSearchIndex = strchrW(filterExt, ';');
                if (filterSearchIndex)
2603
                {
2604
                    filterSearchIndex[0] = '\0';
2605 2606 2607
                }

                /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2608 2609 2610 2611 2612 2613 2614
                /* if the extension is invalid or contains a glob, ignore it */
                filterSearchIndex = PathFindExtensionW(filterExt);
                if (*filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
                {
                    strcpyW(filterExt, filterSearchIndex);
                }
                else
2615 2616 2617 2618 2619
                {
                    HeapFree(GetProcessHeap(), 0, filterExt);
                    filterExt = NULL;
                }
            }
2620

2621 2622 2623
            if (!filterExt)
            {
                /* use the default file extension */
2624
                filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2625 2626
                strcpyW(filterExt, fodInfos->defext);
            }
2627

2628
            if (*filterExt) /* ignore filterExt="" */
2629 2630 2631 2632
            {
                /* Attach the dot*/
                lstrcatW(lpstrPathAndFile, szwDot);
                /* Attach the extension */
2633
                lstrcatW(lpstrPathAndFile, filterExt);
2634
            }
2635

2636 2637
            HeapFree(GetProcessHeap(), 0, filterExt);

2638 2639 2640
            /* In Open dialog: if file does not exist try without extension */
            if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
                  lpstrPathAndFile[PathLength] = '\0';
2641

2642 2643 2644 2645 2646 2647 2648
            /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
            if (*ext)
                ext++;
            if (!lstrcmpiW(fodInfos->defext, ext))
                fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
            else
                fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2649 2650
	}

2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661
	/* In Save dialog: check if the file already exists */
	if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
	    && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
	    && PathFileExistsW(lpstrPathAndFile))
	{
	  WCHAR lpstrOverwrite[100];
	  int answer;

	  LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
	  answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
			       MB_YESNO | MB_ICONEXCLAMATION);
2662
	  if (answer == IDNO || answer == IDCANCEL)
2663 2664 2665 2666
	  {
	    ret = FALSE;
	    goto ret;
	  }
2667 2668
	}

2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679
        /* In Open dialog: check if it should be created if it doesn't exist */
        if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
            && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
            && !PathFileExistsW(lpstrPathAndFile))
        {
          WCHAR lpstrCreate[100];
          int answer;

          LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
          answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
                               MB_YESNO | MB_ICONEXCLAMATION);
2680
          if (answer == IDNO || answer == IDCANCEL)
2681 2682 2683 2684 2685 2686
          {
            ret = FALSE;
            goto ret;
          }
        }

2687 2688
        /* Check that the size of the file does not exceed buffer size.
             (Allow for extra \0 if OFN_MULTISELECT is set.) */
2689
        if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2690 2691 2692 2693 2694 2695 2696 2697
            ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
        {

          /* fill destination buffer */
          if (fodInfos->ofnInfos->lpstrFile)
          {
             if(fodInfos->unicode)
             {
Jacek Caban's avatar
Jacek Caban committed
2698
               LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2699

2700
               lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2701 2702 2703 2704 2705
               if (ofn->Flags & OFN_ALLOWMULTISELECT)
                 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
             }
             else
             {
Jacek Caban's avatar
Jacek Caban committed
2706
               LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2707 2708 2709 2710 2711 2712 2713 2714

               WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
                                   ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
               if (ofn->Flags & OFN_ALLOWMULTISELECT)
                 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
             }
          }

2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728
          if(fodInfos->unicode)
          {
              LPWSTR lpszTemp;

              /* set filename offset */
              lpszTemp = PathFindFileNameW(lpstrPathAndFile);
              fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);

              /* set extension offset */
              lpszTemp = PathFindExtensionW(lpstrPathAndFile);
              fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
          }
          else
          {
2729 2730 2731 2732 2733 2734
              LPSTR lpszTemp;
              CHAR tempFileA[MAX_PATH];

              /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
              WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
                                  tempFileA, sizeof(tempFileA), NULL, NULL);
2735 2736

              /* set filename offset */
2737 2738
              lpszTemp = PathFindFileNameA(tempFileA);
              fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2739

2740
              /* set extension offset */
2741 2742
              lpszTemp = PathFindExtensionA(tempFileA);
              fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2743
          }
2744 2745 2746 2747 2748 2749 2750

          /* set the lpstrFileTitle */
          if(fodInfos->ofnInfos->lpstrFileTitle)
	  {
            LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
            if(fodInfos->unicode)
            {
Jacek Caban's avatar
Jacek Caban committed
2751
              LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2752
	      lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2753 2754 2755
            }
            else
            {
Jacek Caban's avatar
Jacek Caban committed
2756
              LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2757 2758 2759 2760 2761
              WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
                    ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
            }
	  }

2762 2763 2764
          /* copy currently selected filter to lpstrCustomFilter */
          if (fodInfos->ofnInfos->lpstrCustomFilter)
          {
Jacek Caban's avatar
Jacek Caban committed
2765
            LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777
            int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
                                          NULL, 0, NULL, NULL);
            if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
            {
              LPSTR s = ofn->lpstrCustomFilter;
              s += strlen(ofn->lpstrCustomFilter)+1;
              WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
                                  s, len, NULL, NULL);
            }
          }


2778 2779 2780
          if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
	      goto ret;

2781 2782
          FILEDLG95_MRU_save_filename(lpstrPathAndFile);

2783 2784 2785 2786 2787 2788
          TRACE("close\n");
	  FILEDLG95_Clean(hwnd);
          ret = EndDialog(hwnd, TRUE);
	}
	else
        {
2789 2790
          WORD size;

2791
          size = lstrlenW(lpstrPathAndFile) + 1;
2792 2793 2794
          if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
             size += 1;
          /* return needed size in first two bytes of lpstrFile */
2795 2796
          if(fodInfos->ofnInfos->lpstrFile)
              *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2797 2798
          FILEDLG95_Clean(hwnd);
          ret = EndDialog(hwnd, FALSE);
2799
          COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2800 2801 2802 2803
        }
      }
      break;
  }
2804

2805 2806 2807 2808
ret:
  if(lpsf) IShellFolder_Release(lpsf);
  return ret;
}
2809

2810
/***********************************************************************
2811
 *      FILEDLG95_SHELL_Init
2812
 *
2813
 * Initialisation of the shell objects
2814
 */
2815
static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2816
{
2817
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2818 2819

  TRACE("\n");
2820

2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836
  /*
   * Initialisation of the FileOpenDialogInfos structure
   */

  /* Shell */

  /*ShellInfos */
  fodInfos->ShellInfos.hwndOwner = hwnd;

  /* Disable multi-select if flag not set */
  if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
  {
     fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
  }
  fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
  fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2837

2838 2839 2840 2841 2842
  /* Construct the IShellBrowser interface */
  fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);

  return NOERROR;
}
2843

2844
/***********************************************************************
2845 2846 2847 2848
 *      FILEDLG95_SHELL_ExecuteCommand
 *
 * Change the folder option and refresh the view
 * If the function succeeds, the return value is nonzero.
2849
 */
2850
static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2851
{
2852
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2853
  IContextMenu * pcm;
2854

2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870
  TRACE("(%p,%p)\n", hwnd, lpVerb);

  if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
					SVGIO_BACKGROUND,
					&IID_IContextMenu,
					(LPVOID*)&pcm)))
  {
    CMINVOKECOMMANDINFO ci;
    ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
    ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
    ci.lpVerb = lpVerb;
    ci.hwnd = hwnd;

    IContextMenu_InvokeCommand(pcm, &ci);
    IContextMenu_Release(pcm);
  }
2871

2872 2873
  return FALSE;
}
2874

2875
/***********************************************************************
2876
 *      FILEDLG95_SHELL_UpFolder
2877
 *
2878 2879
 * Browse to the specified object
 * If the function succeeds, the return value is nonzero.
2880
 */
2881
static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2882
{
2883
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2884

2885 2886 2887 2888 2889 2890
  TRACE("\n");

  if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
                                          NULL,
                                          SBSP_PARENT)))
  {
2891 2892
    if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
        SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2893
    return TRUE;
2894 2895
  }
  return FALSE;
2896 2897 2898
}

/***********************************************************************
2899
 *      FILEDLG95_SHELL_BrowseToDesktop
2900
 *
2901 2902
 * Browse to the Desktop
 * If the function succeeds, the return value is nonzero.
2903
 */
2904
static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2905
{
2906
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2907 2908
  LPITEMIDLIST pidl;
  HRESULT hres;
2909

2910
  TRACE("\n");
2911

2912 2913
  SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
  hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2914 2915
  if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
      SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2916 2917 2918
  COMDLG32_SHFree(pidl);
  return SUCCEEDED(hres);
}
2919
/***********************************************************************
2920 2921 2922
 *      FILEDLG95_SHELL_Clean
 *
 * Cleans the memory used by shell objects
2923
 */
2924
static void FILEDLG95_SHELL_Clean(HWND hwnd)
2925
{
2926
    FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2927

2928
    TRACE("\n");
2929

2930
    COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2931

2932
    /* clean Shell interfaces */
2933 2934 2935 2936 2937
    if (fodInfos->Shell.FOIShellView)
    {
      IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
      IShellView_Release(fodInfos->Shell.FOIShellView);
    }
2938 2939 2940 2941 2942
    IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
    IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
    if (fodInfos->Shell.FOIDataObject)
      IDataObject_Release(fodInfos->Shell.FOIDataObject);
}
2943

2944
/***********************************************************************
2945
 *      FILEDLG95_FILETYPE_Init
2946
 *
2947
 * Initialisation of the file type combo box
2948
 */
2949
static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2950
{
2951
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2952 2953
  int nFilters = 0;  /* number of filters */
  int nFilterIndexCB;
2954 2955 2956

  TRACE("\n");

2957 2958 2959 2960 2961 2962 2963 2964 2965
  if(fodInfos->customfilter)
  {
      /* customfilter has one entry...  title\0ext\0
       * Set first entry of combo box item with customfilter
       */
      LPWSTR  lpstrExt;
      LPCWSTR lpstrPos = fodInfos->customfilter;

      /* Get the title */
2966
      lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2967 2968 2969

      /* Copy the extensions */
      if (! *lpstrPos) return E_FAIL;	/* malformed filter */
2970 2971
      if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
      lstrcpyW(lpstrExt,lpstrPos);
2972 2973

      /* Add the item at the end of the combo */
2974
      CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2975 2976 2977
      CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
      nFilters++;
  }
2978 2979 2980 2981 2982
  if(fodInfos->filter)
  {
    LPCWSTR lpstrPos = fodInfos->filter;

    for(;;)
2983
    {
2984 2985 2986 2987 2988 2989 2990 2991 2992 2993
      /* filter is a list...  title\0ext\0......\0\0
       * Set the combo item text to the title and the item data
       *  to the ext
       */
      LPCWSTR lpstrDisplay;
      LPWSTR lpstrExt;

      /* Get the title */
      if(! *lpstrPos) break;	/* end */
      lpstrDisplay = lpstrPos;
2994
      lpstrPos += lstrlenW(lpstrPos) + 1;
2995

2996
      CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2997 2998 2999

      nFilters++;

3000
      /* Copy the extensions */
3001 3002 3003
      if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
      lstrcpyW(lpstrExt,lpstrPos);
      lpstrPos += lstrlenW(lpstrPos) + 1;
3004 3005

      /* Add the item at the end of the combo */
3006
      CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
3007 3008 3009

      /* malformed filters are added anyway... */
      if (!*lpstrExt) break;
3010
    }
3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024
  }

  /*
   * Set the current filter to the one specified
   * in the initialisation structure
   */
  if (fodInfos->filter || fodInfos->customfilter)
  {
    LPWSTR lpstrFilter;

    /* Check to make sure our index isn't out of bounds. */
    if ( fodInfos->ofnInfos->nFilterIndex >
         nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
      fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3025 3026 3027 3028 3029

    /* set default filter index */
    if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
      fodInfos->ofnInfos->nFilterIndex = 1;

3030 3031 3032 3033
    /* calculate index of Combo Box item */
    nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
    if (fodInfos->customfilter == NULL)
      nFilterIndexCB--;
3034

3035
    /* Set the current index selection. */
3036
    CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
3037 3038 3039

    /* Get the corresponding text string from the combo box. */
    lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3040
                                             nFilterIndexCB);
3041

Kevin Koltzau's avatar
Kevin Koltzau committed
3042
    if ((INT_PTR)lpstrFilter == CB_ERR)  /* control is empty */
3043 3044 3045
      lpstrFilter = NULL;

    if(lpstrFilter)
3046
    {
3047 3048
      DWORD len;
      CharLowerW(lpstrFilter); /* lowercase */
3049
      len = lstrlenW(lpstrFilter)+1;
3050
      fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3051
      lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3052
    }
3053 3054
  } else
      fodInfos->ofnInfos->nFilterIndex = 0;
3055
  return S_OK;
3056
}
3057

3058
/***********************************************************************
3059 3060 3061 3062
 *      FILEDLG95_FILETYPE_OnCommand
 *
 * WM_COMMAND of the file type combo box
 * If the function succeeds, the return value is nonzero.
3063
 */
3064
static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3065
{
3066
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3067

3068 3069 3070 3071 3072 3073 3074 3075
  switch(wNotifyCode)
  {
    case CBN_SELENDOK:
    {
      LPWSTR lpstrFilter;

      /* Get the current item of the filetype combo box */
      int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3076

3077 3078 3079
      /* set the current filter index */
      fodInfos->ofnInfos->nFilterIndex = iItem +
        (fodInfos->customfilter == NULL ? 1 : 0);
3080

3081
      /* Set the current filter with the current selection */
3082
      MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3083 3084 3085

      lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
                                             iItem);
Kevin Koltzau's avatar
Kevin Koltzau committed
3086
      if((INT_PTR)lpstrFilter != CB_ERR)
3087 3088 3089
      {
          DWORD len;
          CharLowerW(lpstrFilter); /* lowercase */
3090
          len = lstrlenW(lpstrFilter)+1;
3091
          fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3092
          lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3093 3094
          if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
              SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3095 3096 3097
      }

      /* Refresh the actual view to display the included items*/
3098 3099
      if (fodInfos->Shell.FOIShellView)
        IShellView_Refresh(fodInfos->Shell.FOIShellView);
3100
    }
3101 3102
  }
  return FALSE;
3103
}
3104 3105 3106
/***********************************************************************
 *      FILEDLG95_FILETYPE_SearchExt
 *
3107
 * searches for an extension in the filetype box
3108 3109 3110 3111 3112 3113
 */
static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
{
  int i, iCount = CBGetCount(hwnd);

  TRACE("%s\n", debugstr_w(lpstrExt));
3114

3115 3116 3117 3118 3119 3120 3121 3122 3123 3124
  if(iCount != CB_ERR)
  {
    for(i=0;i<iCount;i++)
    {
      if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
          return i;
    }
  }
  return -1;
}
3125

3126
/***********************************************************************
3127 3128 3129
 *      FILEDLG95_FILETYPE_Clean
 *
 * Clean the memory used by the filetype combo box
3130
 */
3131
static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3132
{
3133
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145
  int iPos;
  int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);

  TRACE("\n");

  /* Delete each string of the combo and their associated data */
  if(iCount != CB_ERR)
  {
    for(iPos = iCount-1;iPos>=0;iPos--)
    {
      MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
      CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3146
    }
3147 3148
  }
  /* Current filter */
3149
  MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3150

3151 3152 3153
}

/***********************************************************************
3154 3155 3156
 *      FILEDLG95_LOOKIN_Init
 *
 * Initialisation of the look in combo box
3157
 */
3158 3159 3160 3161 3162 3163

/* Small helper function, to determine if the unixfs shell extension is rooted 
 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 
 */
static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
    HKEY hKey;
3164
    static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178
        'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
        'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
        'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
        'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
        '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
        '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
    
    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
        return FALSE;
        
    RegCloseKey(hKey);
    return TRUE;
}

3179
static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3180
{
3181 3182 3183
  IShellFolder	*psfRoot, *psfDrives;
  IEnumIDList	*lpeRoot, *lpeDrives;
  LPITEMIDLIST	pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3184 3185
  HDC hdc;
  TEXTMETRICW tm;
3186
  LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3187

3188
  TRACE("\n");
3189

3190
  liInfos->iMaxIndentation = 0;
3191

3192
  SetPropA(hwndCombo, LookInInfosStr, liInfos);
3193

3194 3195 3196 3197 3198
  hdc = GetDC( hwndCombo );
  SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
  GetTextMetricsW( hdc, &tm );
  ReleaseDC( hwndCombo, hdc );

3199
  /* set item height for both text field and listbox */
3200 3201 3202
  CBSetItemHeight( hwndCombo, -1, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
  CBSetItemHeight( hwndCombo, 0, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));

3203 3204
  /* Turn on the extended UI for the combo box like Windows does */
  CBSetExtendedUI(hwndCombo, TRUE);
3205

3206 3207 3208 3209
  /* Initialise data of Desktop folder */
  SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
  FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
  COMDLG32_SHFree(pidlTmp);
3210

3211
  SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3212

3213
  SHGetDesktopFolder(&psfRoot);
3214

3215 3216 3217 3218
  if (psfRoot)
  {
    /* enumerate the contents of the desktop */
    if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3219
    {
3220 3221 3222
      while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
      {
	FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3223

3224 3225
	/* If the unixfs extension is rooted, we don't expand the drives by default */
	if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 
3226
	{
3227 3228
	  /* special handling for CSIDL_DRIVES */
	  if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3229
	  {
3230
	    if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3231
	    {
3232 3233
	      /* enumerate the drives */
	      if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3234
	      {
3235 3236 3237 3238 3239 3240 3241 3242
	        while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
	        {
	          pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
	          FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
	          COMDLG32_SHFree(pidlAbsTmp);
	          COMDLG32_SHFree(pidlTmp1);
	        }
	        IEnumIDList_Release(lpeDrives);
3243
	      }
3244
	      IShellFolder_Release(psfDrives);
3245 3246
	    }
	  }
3247
	}
3248

3249 3250 3251
        COMDLG32_SHFree(pidlTmp);
      }
      IEnumIDList_Release(lpeRoot);
3252
    }
3253
    IShellFolder_Release(psfRoot);
3254 3255 3256
  }

  COMDLG32_SHFree(pidlDrives);
3257 3258 3259
}

/***********************************************************************
3260 3261 3262
 *      FILEDLG95_LOOKIN_DrawItem
 *
 * WM_DRAWITEM message handler
3263
 */
3264
static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3265
{
3266 3267 3268 3269 3270
  COLORREF crWin = GetSysColor(COLOR_WINDOW);
  COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
  COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
  RECT rectText;
  RECT rectIcon;
3271
  SHFILEINFOW sfi;
3272 3273
  HIMAGELIST ilItemImage;
  int iIndentation;
3274
  TEXTMETRICW tm;
3275
  LPSFOLDER tmpFolder;
3276
  LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
3277 3278
  UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
  UINT icon_width, icon_height;
3279

3280
  TRACE("\n");
3281

3282 3283
  if(pDIStruct->itemID == -1)
    return 0;
3284

3285 3286 3287
  if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
                            pDIStruct->itemID)))
    return 0;
3288

3289

3290 3291 3292 3293 3294 3295 3296 3297 3298
  icon_width = GetSystemMetrics(SM_CXICON);
  icon_height = GetSystemMetrics(SM_CYICON);
  if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
  {
      icon_width = GetSystemMetrics(SM_CXSMICON);
      icon_height = GetSystemMetrics(SM_CYSMICON);
      shgfi_flags |= SHGFI_SMALLICON;
  }

3299 3300
  if(pDIStruct->itemID == liInfos->uSelectedItem)
  {
3301
    ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3302
                                               0, &sfi, sizeof (sfi), shgfi_flags );
3303 3304
  }
  else
3305
  {
3306
    ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3307
                                               0, &sfi, sizeof (sfi), shgfi_flags );
3308
  }
3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327

  /* Is this item selected ? */
  if(pDIStruct->itemState & ODS_SELECTED)
  {
    SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
    SetBkColor(pDIStruct->hDC,crHighLight);
    FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
  }
  else
  {
    SetTextColor(pDIStruct->hDC,crText);
    SetBkColor(pDIStruct->hDC,crWin);
    FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
  }

  /* Do not indent item if drawing in the edit of the combo */
  if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
  {
    iIndentation = 0;
3328
    ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3329
                                               0, &sfi, sizeof (sfi), shgfi_flags );
3330 3331 3332 3333 3334 3335 3336 3337 3338

  }
  else
  {
    iIndentation = tmpFolder->m_iIndent;
  }
  /* Draw text and icon */

  /* Initialise the icon display area */
3339 3340 3341 3342
  rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
  rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
  rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
  rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3343 3344

  /* Initialise the text display area */
3345
  GetTextMetricsW(pDIStruct->hDC, &tm);
3346 3347 3348
  rectText.left = rectIcon.right;
  rectText.top =
	  (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3349
  rectText.right = pDIStruct->rcItem.right;
3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361
  rectText.bottom =
	  (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;

  /* Draw the icon from the image list */
  ImageList_Draw(ilItemImage,
                 sfi.iIcon,
                 pDIStruct->hDC,
                 rectIcon.left,
                 rectIcon.top,
                 ILD_TRANSPARENT );

  /* Draw the associated text */
3362
  TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3363
  return NOERROR;
3364 3365 3366
}

/***********************************************************************
3367 3368 3369 3370
 *      FILEDLG95_LOOKIN_OnCommand
 *
 * LookIn combo box WM_COMMAND message handler
 * If the function succeeds, the return value is nonzero.
3371
 */
3372
static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3373
{
3374
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3375 3376 3377 3378 3379 3380

  TRACE("%p\n", fodInfos);

  switch(wNotifyCode)
  {
    case CBN_SELENDOK:
3381
    {
3382 3383 3384 3385 3386
      LPSFOLDER tmpFolder;
      int iItem;

      iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);

3387 3388
      if( iItem == CB_ERR) return FALSE;

3389 3390 3391 3392 3393 3394 3395 3396 3397
      if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
                                               iItem)))
	return FALSE;


      if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
                                              tmpFolder->pidlItem,
                                              SBSP_ABSOLUTE)))
      {
3398 3399
        if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
            SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3400 3401 3402
        return TRUE;
      }
      break;
3403 3404
    }

3405 3406 3407
  }
  return FALSE;
}
3408 3409

/***********************************************************************
3410 3411 3412 3413
 *      FILEDLG95_LOOKIN_AddItem
 *
 * Adds an absolute pidl item to the lookin combo box
 * returns the index of the inserted item
3414
 */
3415
static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3416
{
3417
  LPITEMIDLIST pidlNext;
3418
  SHFILEINFOW sfi;
3419 3420 3421 3422 3423 3424 3425 3426
  SFOLDER *tmpFolder;
  LookInInfos *liInfos;

  TRACE("%08x\n", iInsertId);

  if(!pidl)
    return -1;

3427
  if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445
    return -1;

  tmpFolder = MemAlloc(sizeof(SFOLDER));
  tmpFolder->m_iIndent = 0;

  /* Calculate the indentation of the item in the lookin*/
  pidlNext = pidl;
  while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
  {
    tmpFolder->m_iIndent++;
  }

  tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);

  if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
    liInfos->iMaxIndentation = tmpFolder->m_iIndent;

  sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3446
  SHGetFileInfoW((LPCWSTR)pidl,
3447 3448 3449 3450 3451 3452
                  0,
                  &sfi,
                  sizeof(sfi),
                  SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
                  | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);

3453
  TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3454 3455 3456 3457 3458

  if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
  {
    int iItemID;

3459
    TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3460 3461 3462

    /* Add the item at the end of the list */
    if(iInsertId < 0)
3463
    {
3464
      iItemID = CBAddString(hwnd,sfi.szDisplayName);
3465
    }
3466 3467
    /* Insert the item at the iInsertId position*/
    else
3468
    {
3469
      iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3470
    }
3471 3472 3473

    CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
    return iItemID;
3474
  }
3475

3476 3477 3478
  COMDLG32_SHFree( tmpFolder->pidlItem );
  MemFree( tmpFolder );
  return -1;
3479

3480
}
3481 3482

/***********************************************************************
3483 3484 3485
 *      FILEDLG95_LOOKIN_InsertItemAfterParent
 *
 * Insert an item below its parent
3486
 */
3487
static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3488 3489
{

3490 3491 3492 3493 3494
  LPITEMIDLIST pidlParent = GetParentPidl(pidl);
  int iParentPos;

  TRACE("\n");

3495 3496 3497
  if (pidl == pidlParent)
    return -1;

3498 3499 3500 3501 3502 3503 3504 3505
  iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);

  if(iParentPos < 0)
  {
    iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
  }

  /* Free pidlParent memory */
3506
  COMDLG32_SHFree(pidlParent);
3507

3508 3509
  return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
}
3510

3511
/***********************************************************************
3512 3513 3514 3515
 *      FILEDLG95_LOOKIN_SelectItem
 *
 * Adds an absolute pidl item to the lookin combo box
 * returns the index of the inserted item
3516
 */
3517
int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3518
{
3519 3520
  int iItemPos;
  LookInInfos *liInfos;
3521

3522
  TRACE("\n");
3523

3524 3525
  iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);

3526
  liInfos = GetPropA(hwnd,LookInInfosStr);
3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537

  if(iItemPos < 0)
  {
    while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
    iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
  }

  else
  {
    SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
    while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3538
    {
3539 3540 3541 3542 3543 3544
      int iRemovedItem;

      if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
        break;
      if(iRemovedItem < iItemPos)
        iItemPos--;
3545
    }
3546 3547 3548 3549 3550 3551 3552
  }

  CBSetCurSel(hwnd,iItemPos);
  liInfos->uSelectedItem = iItemPos;

  return 0;

3553
}
3554

3555
/***********************************************************************
3556 3557 3558
 *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
 *
 * Remove the item with an expansion level over iExpansionLevel
3559
 */
3560
static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3561
{
3562
  int iItemPos;
3563
  LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3564

3565
  TRACE("\n");
3566

3567 3568
  if(liInfos->iMaxIndentation <= 2)
    return -1;
3569

3570
  if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3571 3572 3573 3574 3575 3576
  {
    SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
    COMDLG32_SHFree(tmpFolder->pidlItem);
    MemFree(tmpFolder);
    CBDeleteString(hwnd,iItemPos);
    liInfos->iMaxIndentation--;
3577

3578 3579
    return iItemPos;
  }
3580

3581 3582
  return -1;
}
3583

3584 3585 3586 3587 3588 3589 3590 3591 3592 3593
/***********************************************************************
 *      FILEDLG95_LOOKIN_SearchItem
 *
 * Search for pidl in the lookin combo box
 * returns the index of the found item
 */
static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
{
  int i = 0;
  int iCount = CBGetCount(hwnd);
3594

3595
  TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3596

3597 3598 3599
  if (iCount != CB_ERR)
  {
    for(;i<iCount;i++)
3600
    {
3601
      LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3602

3603 3604 3605 3606
      if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
        return i;
      if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
        return i;
3607
    }
3608 3609 3610
  }

  return -1;
3611 3612 3613
}

/***********************************************************************
3614 3615 3616
 *      FILEDLG95_LOOKIN_Clean
 *
 * Clean the memory used by the lookin combo box
3617
 */
3618
static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3619
{
3620
    FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3621
    LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3622 3623
    int iPos;
    int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3624

3625
    TRACE("\n");
3626

3627 3628
    /* Delete each string of the combo and their associated data */
    if (iCount != CB_ERR)
3629
    {
3630 3631 3632 3633 3634 3635 3636
      for(iPos = iCount-1;iPos>=0;iPos--)
      {
        SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
        COMDLG32_SHFree(tmpFolder->pidlItem);
        MemFree(tmpFolder);
        CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
      }
3637 3638
    }

3639
    /* LookInInfos structure */
3640
    MemFree(liInfos);
3641
    RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3642
}
3643

3644
/***********************************************************************
3645 3646 3647
 * FILEDLG95_FILENAME_FillFromSelection
 *
 * fills the edit box from the cached DataObject
3648
 */
3649
void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3650
{
3651 3652 3653
    FileOpenDlgInfos *fodInfos;
    LPITEMIDLIST      pidl;
    UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3654 3655
    WCHAR             lpstrTemp[MAX_PATH];
    LPWSTR            lpstrAllFile, lpstrCurrFile;
3656

3657
    TRACE("\n");
3658
    fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3659

3660 3661
    /* Count how many files we have */
    nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3662

3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678
    /* calculate the string length, count files */
    if (nFileSelected >= 1)
    {
      nLength += 3;	/* first and last quotes, trailing \0 */
      for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
      {
        pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );

        if (pidl)
	{
          /* get the total length of the selected file names */
          lpstrTemp[0] = '\0';
          GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );

          if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
	  {
3679
            nLength += lstrlenW( lpstrTemp ) + 3;
3680 3681 3682 3683 3684 3685
            nFiles++;
	  }
          COMDLG32_SHFree( pidl );
	}
      }
    }
3686

3687 3688
    /* allocate the buffer */
    if (nFiles <= 1) nLength = MAX_PATH;
3689
    lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3690

3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709
    /* Generate the string for the edit control */
    if(nFiles >= 1)
    {
      lpstrCurrFile = lpstrAllFile;
      for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
      {
        pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );

        if (pidl)
	{
	  /* get the file name */
          lpstrTemp[0] = '\0';
          GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );

          if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
	  {
            if ( nFiles > 1)
	    {
              *lpstrCurrFile++ =  '\"';
3710 3711 3712 3713 3714
              lstrcpyW( lpstrCurrFile, lpstrTemp );
              lpstrCurrFile += lstrlenW( lpstrTemp );
              *lpstrCurrFile++ = '\"';
              *lpstrCurrFile++ = ' ';
              *lpstrCurrFile = 0;
3715 3716 3717
	    }
	    else
	    {
3718
              lstrcpyW( lpstrAllFile, lpstrTemp );
3719 3720
	    }
          }
3721
          COMDLG32_SHFree( pidl );
3722 3723
	}
      }
3724
      SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3725
       
3726 3727 3728
      /* Select the file name like Windows does */
      if (filename_is_edit( fodInfos ))
          SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3729 3730 3731
    }
    HeapFree(GetProcessHeap(),0, lpstrAllFile );
}
3732

3733

3734
/* copied from shell32 to avoid linking to it
3735 3736
 * Although shell32 is already linked the behaviour of exported StrRetToStrN
 * is dependent on whether emulated OS is unicode or not.
3737
 */
3738
static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3739 3740 3741 3742
{
	switch (src->uType)
	{
	  case STRRET_WSTR:
3743
	    lstrcpynW(dest, src->u.pOleStr, len);
3744 3745 3746 3747
	    COMDLG32_SHFree(src->u.pOleStr);
	    break;

	  case STRRET_CSTR:
3748 3749
            if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
                  dest[len-1] = 0;
3750 3751 3752
	    break;

	  case STRRET_OFFSET:
3753 3754
            if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
                  dest[len-1] = 0;
3755 3756 3757
	    break;

	  default:
3758 3759 3760
	    FIXME("unknown type %x!\n", src->uType);
	    if (len) *dest = '\0';
	    return E_FAIL;
3761 3762
	}
	return S_OK;
3763 3764 3765
}

/***********************************************************************
3766 3767
 * FILEDLG95_FILENAME_GetFileNames
 *
3768
 * Copies the filenames to a delimited string list.
3769
 */
3770
static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3771
{
3772
	FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3773 3774 3775
	UINT nFileCount = 0;	/* number of files */
	UINT nStrLen = 0;	/* length of string in edit control */
	LPWSTR lpstrEdit;	/* buffer for string from edit control */
3776

3777
	TRACE("\n");
3778

3779 3780
	/* get the filenames from the filename control */
	nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3781
	lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3782
	GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3783

3784
	TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3785

3786
	nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3787 3788
	MemFree(lpstrEdit);
	return nFileCount;
3789
}
3790

3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803
#define SETDefFormatEtc(fe,cf,med) \
{ \
    (fe).cfFormat = cf;\
    (fe).dwAspect = DVASPECT_CONTENT; \
    (fe).ptd =NULL;\
    (fe).tymed = med;\
    (fe).lindex = -1;\
};

/*
 * DATAOBJECT Helper functions
 */

3804
/***********************************************************************
3805 3806 3807
 * COMCTL32_ReleaseStgMedium
 *
 * like ReleaseStgMedium from ole32
3808
 */
3809
static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3810
{
3811 3812 3813 3814 3815 3816 3817 3818 3819
      if(medium.pUnkForRelease)
      {
        IUnknown_Release(medium.pUnkForRelease);
      }
      else
      {
        GlobalUnlock(medium.u.hGlobal);
        GlobalFree(medium.u.hGlobal);
      }
3820 3821
}

3822 3823 3824 3825 3826 3827
/***********************************************************************
 *          GetPidlFromDataObject
 *
 * Return pidl(s) by number from the cached DataObject
 *
 * nPidlIndex=0 gets the fully qualified root path
3828
 */
3829
LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3830 3831
{

3832 3833 3834
    STGMEDIUM medium;
    FORMATETC formatetc;
    LPITEMIDLIST pidl = NULL;
3835

3836
    TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3837

3838 3839 3840
    if (!doSelected)
        return NULL;
	
3841
    /* Set the FORMATETC structure*/
3842
    SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3843

3844 3845
    /* Get the pidls from IDataObject */
    if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3846
    {
3847 3848 3849 3850 3851 3852
      LPIDA cida = GlobalLock(medium.u.hGlobal);
      if(nPidlIndex <= cida->cidl)
      {
        pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
      }
      COMCTL32_ReleaseStgMedium(medium);
3853
    }
3854
    return pidl;
3855
}
3856

3857 3858 3859 3860 3861 3862
/***********************************************************************
 *          GetNumSelected
 *
 * Return the number of selected items in the DataObject.
 *
*/
3863
static UINT GetNumSelected( IDataObject *doSelected )
3864
{
3865 3866 3867 3868 3869 3870 3871 3872 3873
    UINT retVal = 0;
    STGMEDIUM medium;
    FORMATETC formatetc;

    TRACE("sv=%p\n", doSelected);

    if (!doSelected) return 0;

    /* Set the FORMATETC structure*/
3874
    SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3875 3876 3877

    /* Get the pidls from IDataObject */
    if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3878
    {
3879 3880 3881 3882
      LPIDA cida = GlobalLock(medium.u.hGlobal);
      retVal = cida->cidl;
      COMCTL32_ReleaseStgMedium(medium);
      return retVal;
3883
    }
3884
    return 0;
3885 3886
}

3887 3888 3889
/*
 * TOOLS
 */
3890

3891 3892 3893 3894 3895 3896 3897 3898
/***********************************************************************
 *      GetName
 *
 * Get the pidl's display name (relative to folder) and
 * put it in lpstrFileName.
 *
 * Return NOERROR on success,
 * E_FAIL otherwise
3899
 */
3900

3901
static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3902
{
3903 3904
  STRRET str;
  HRESULT hRes;
3905

3906
  TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3907

3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918
  if(!lpsf)
  {
    SHGetDesktopFolder(&lpsf);
    hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
    IShellFolder_Release(lpsf);
    return hRes;
  }

  /* Get the display name of the pidl relative to the folder */
  if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
  {
3919
      return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3920 3921
  }
  return E_FAIL;
3922 3923
}

3924 3925 3926 3927 3928
/***********************************************************************
 *      GetShellFolderFromPidl
 *
 * pidlRel is the item pidl relative
 * Return the IShellFolder of the absolute pidl
3929
 */
3930
IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3931
{
3932
  IShellFolder *psf = NULL,*psfParent;
3933

3934
  TRACE("%p\n", pidlAbs);
3935

3936 3937 3938 3939
  if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
  {
    psf = psfParent;
    if(pidlAbs && pidlAbs->mkid.cb)
3940
    {
3941 3942 3943 3944 3945
      if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
      {
	IShellFolder_Release(psfParent);
        return psf;
      }
3946
    }
3947 3948 3949 3950
    /* return the desktop */
    return psfParent;
  }
  return NULL;
3951 3952 3953
}

/***********************************************************************
3954
 *      GetParentPidl
3955
 *
3956
 * Return the LPITEMIDLIST to the parent of the pidl in the list
3957
 */
3958
LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3959
{
3960
  LPITEMIDLIST pidlParent;
3961

3962
  TRACE("%p\n", pidl);
3963

3964 3965
  pidlParent = COMDLG32_PIDL_ILClone(pidl);
  COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3966

3967
  return pidlParent;
3968 3969 3970
}

/***********************************************************************
3971
 *      GetPidlFromName
3972
 *
3973 3974
 * returns the pidl of the file name relative to folder
 * NULL if an error occurred
3975
 */
3976
static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3977
{
3978 3979
  LPITEMIDLIST pidl = NULL;
  ULONG ulEaten;
3980

3981
  TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3982

3983 3984 3985 3986 3987 3988 3989 3990
  if(!lpcstrFileName) return NULL;
  if(!*lpcstrFileName) return NULL;

  if(!lpsf)
  {
    if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
        IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
        IShellFolder_Release(lpsf);
3991
    }
3992 3993 3994 3995 3996 3997 3998 3999 4000 4001
  }
  else
  {
    IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
  }
  return pidl;
}

/*
*/
4002
static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
4003 4004 4005 4006 4007 4008 4009
{
	ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
	HRESULT ret;

	TRACE("%p, %p\n", psf, pidl);

  	ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4010

4011
	TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
4012 4013
	/* see documentation shell 4.1*/
        return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4014 4015 4016
}

/***********************************************************************
4017
 *      BrowseSelectedFolder
4018
 */
4019
static BOOL BrowseSelectedFolder(HWND hwnd)
4020
{
4021
  BOOL bBrowseSelFolder = FALSE;
4022
  FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
4023

4024
  TRACE("\n");
4025

4026 4027 4028
  if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
  {
      LPITEMIDLIST pidlSelection;
4029

4030 4031 4032 4033 4034 4035 4036
      /* get the file selected */
      pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
      if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
      {
          if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
                         pidlSelection, SBSP_RELATIVE ) ) )
          {
4037
               static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
4038 4039 4040
                                   ' ','n','o','t',' ','e','x','i','s','t',0};
               MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
          }
4041
          bBrowseSelFolder = TRUE;
4042 4043
          if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
              SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4044 4045 4046
      }
      COMDLG32_SHFree( pidlSelection );
  }
4047

4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059
  return bBrowseSelFolder;
}

/*
 * Memory allocation methods */
static void *MemAlloc(UINT size)
{
    return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
}

static void MemFree(void *mem)
{
4060
    HeapFree(GetProcessHeap(),0,mem);
4061 4062
}

4063 4064 4065 4066 4067 4068
static inline BOOL valid_struct_size( DWORD size )
{
    return (size == OPENFILENAME_SIZE_VERSION_400W) ||
        (size == sizeof( OPENFILENAMEW ));
}

4069 4070 4071 4072 4073 4074
static inline BOOL is_win16_looks(DWORD flags)
{
    return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
            !(flags & OFN_EXPLORER));
}

4075
/* ------------------ APIs ---------------------- */
4076

4077
/***********************************************************************
4078
 *            GetOpenFileNameA  (COMDLG32.@)
4079 4080 4081 4082
 *
 * Creates a dialog box for the user to select a file to open.
 *
 * RETURNS
4083
 *    TRUE on success: user enters a valid file
4084 4085 4086 4087
 *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
 *
 */
BOOL WINAPI GetOpenFileNameA(
4088
	LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4089
{
4090
    TRACE("flags %08x\n", ofn->Flags);
4091

4092 4093 4094 4095 4096 4097
    if (!valid_struct_size( ofn->lStructSize ))
    {
        COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
        return FALSE;
    }

4098 4099 4100 4101
    /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
    if (ofn->Flags & OFN_FILEMUSTEXIST)
        ofn->Flags |= OFN_PATHMUSTEXIST;

4102
    if (is_win16_looks(ofn->Flags))
4103 4104
        return GetFileName31A(ofn, OPEN_DIALOG);
    else
4105 4106
        return GetFileDialog95A(ofn, OPEN_DIALOG);
}
4107 4108

/***********************************************************************
4109
 *            GetOpenFileNameW (COMDLG32.@)
4110 4111 4112 4113
 *
 * Creates a dialog box for the user to select a file to open.
 *
 * RETURNS
4114
 *    TRUE on success: user enters a valid file
4115 4116 4117 4118
 *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
 *
 */
BOOL WINAPI GetOpenFileNameW(
4119
	LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4120
{
4121
    TRACE("flags %08x\n", ofn->Flags);
4122

4123 4124 4125 4126 4127 4128
    if (!valid_struct_size( ofn->lStructSize ))
    {
        COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
        return FALSE;
    }

4129 4130 4131 4132
    /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
    if (ofn->Flags & OFN_FILEMUSTEXIST)
        ofn->Flags |= OFN_PATHMUSTEXIST;

4133
    if (is_win16_looks(ofn->Flags))
4134 4135
        return GetFileName31W(ofn, OPEN_DIALOG);
    else
4136 4137
        return GetFileDialog95W(ofn, OPEN_DIALOG);
}
4138

4139

4140
/***********************************************************************
4141
 *            GetSaveFileNameA  (COMDLG32.@)
4142 4143 4144 4145
 *
 * Creates a dialog box for the user to select a file to save.
 *
 * RETURNS
4146
 *    TRUE on success: user enters a valid file
4147 4148 4149 4150
 *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
 *
 */
BOOL WINAPI GetSaveFileNameA(
4151
	LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4152
{
4153 4154 4155 4156 4157 4158
    if (!valid_struct_size( ofn->lStructSize ))
    {
        COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
        return FALSE;
    }

4159
    if (is_win16_looks(ofn->Flags))
4160 4161
        return GetFileName31A(ofn, SAVE_DIALOG);
    else
4162 4163 4164
        return GetFileDialog95A(ofn, SAVE_DIALOG);
}

4165
/***********************************************************************
4166
 *            GetSaveFileNameW  (COMDLG32.@)
4167 4168 4169 4170
 *
 * Creates a dialog box for the user to select a file to save.
 *
 * RETURNS
4171
 *    TRUE on success: user enters a valid file
4172 4173 4174 4175
 *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
 *
 */
BOOL WINAPI GetSaveFileNameW(
4176
	LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4177
{
4178 4179 4180 4181 4182 4183
    if (!valid_struct_size( ofn->lStructSize ))
    {
        COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
        return FALSE;
    }

4184
    if (is_win16_looks(ofn->Flags))
4185 4186 4187
        return GetFileName31W(ofn, SAVE_DIALOG);
    else
        return GetFileDialog95W(ofn, SAVE_DIALOG);
4188
}
4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233

/***********************************************************************
 *	GetFileTitleA		(COMDLG32.@)
 *
 * See GetFileTitleW.
 */
short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
{
    int ret;
    UNICODE_STRING strWFile;
    LPWSTR lpWTitle;

    RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
    lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
    ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
    if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
    RtlFreeUnicodeString( &strWFile );
    RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
    return ret;
}


/***********************************************************************
 *	GetFileTitleW		(COMDLG32.@)
 *
 * Get the name of a file.
 *
 * PARAMS
 *  lpFile  [I] name and location of file
 *  lpTitle [O] returned file name
 *  cbBuf   [I] buffer size of lpTitle
 *
 * RETURNS
 *  Success: zero
 *  Failure: negative number.
 */
short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
{
	int i, len;
        static const WCHAR brkpoint[] = {'*','[',']',0};
	TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);

	if(lpFile == NULL || lpTitle == NULL)
		return -1;

4234
	len = lstrlenW(lpFile);
4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258

	if (len == 0)
		return -1;

	if(strpbrkW(lpFile, brkpoint))
		return -1;

	len--;

	if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
		return -1;

	for(i = len; i >= 0; i--)
	{
		if (lpFile[i] == '/' ||  lpFile[i] == '\\' ||  lpFile[i] == ':')
		{
			i++;
			break;
		}
	}

	if(i == -1)
		i++;

4259
	TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4260

4261
	len = lstrlenW(lpFile+i)+1;
4262 4263 4264
	if(cbBuf < len)
		return len;

4265
	lstrcpyW(lpTitle, &lpFile[i]);
4266 4267
	return 0;
}