~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/comdlg32/filedlg.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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