~ [ 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);
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;
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 (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1189          {
1190              GetWindowRect( hwnd, &rc);
1191              fodInfos->sizedlg.cx = rc.right - rc.left;
1192              fodInfos->sizedlg.cy = rc.bottom - rc.top;
1193              fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1194              fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1195              GetClientRect( hwnd, &rc);
1196              SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1197                      rc.right - gripx, rc.bottom - gripy,
1198                      0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1199              /* resize the dialog to the previous invocation */
1200              if( MemDialogSize.cx && MemDialogSize.cy)
1201                  SetWindowPos( hwnd, NULL,
1202                          0, 0, MemDialogSize.cx, MemDialogSize.cy,
1203                          SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1204          }
1205 
1206          if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1207              SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1208 
1209          return 0;
1210        }
1211     case WM_SIZE:
1212       return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1213     case WM_GETMINMAXINFO:
1214       return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1215     case WM_COMMAND:
1216       return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1217     case WM_DRAWITEM:
1218       {
1219         switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1220         {
1221         case IDC_LOOKIN:
1222           FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1223           return TRUE;
1224         }
1225       }
1226       return FALSE;
1227 
1228     case WM_GETISHELLBROWSER:
1229       return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1230 
1231     case WM_DESTROY:
1232       {
1233           FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1234           if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1235               MemDialogSize = fodInfos->sizedlg;
1236           RemovePropA(hwnd, FileOpenDlgInfosStr);
1237           return FALSE;
1238       }
1239     case WM_NOTIFY:
1240     {
1241         LPNMHDR lpnmh = (LPNMHDR)lParam;
1242         UINT stringId = -1;
1243 
1244         /* set up the button tooltips strings */
1245         if(TTN_GETDISPINFOA == lpnmh->code )
1246         {
1247             LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1248             switch(lpnmh->idFrom )
1249             {
1250                 /* Up folder button */
1251                 case FCIDM_TB_UPFOLDER:
1252                     stringId = IDS_UPFOLDER;
1253                     break;
1254                 /* New folder button */
1255                 case FCIDM_TB_NEWFOLDER:
1256                     stringId = IDS_NEWFOLDER;
1257                     break;
1258                 /* List option button */
1259                 case FCIDM_TB_SMALLICON:
1260                     stringId = IDS_LISTVIEW;
1261                     break;
1262                 /* Details option button */
1263                 case FCIDM_TB_REPORTVIEW:
1264                     stringId = IDS_REPORTVIEW;
1265                     break;
1266                 /* Desktop button */
1267                 case FCIDM_TB_DESKTOP:
1268                     stringId = IDS_TODESKTOP;
1269                     break;
1270                 default:
1271                     stringId = 0;
1272             }
1273             lpdi->hinst = COMDLG32_hInstance;
1274             lpdi->lpszText =  MAKEINTRESOURCEA(stringId);
1275         }
1276         return FALSE;
1277     }
1278     default :
1279       if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1280         return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1281       return FALSE;
1282   }
1283 }
1284 
1285 /***********************************************************************
1286  *      FILEDLG95_InitControls
1287  *
1288  * WM_INITDIALOG message handler (before hook notification)
1289  */
1290 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1291 {
1292   int win2000plus = 0;
1293   int win98plus   = 0;
1294   int handledPath = FALSE;
1295   OSVERSIONINFOW osVi;
1296   static const WCHAR szwSlash[] = { '\\', 0 };
1297   static const WCHAR szwStar[] = { '*',0 };
1298 
1299   static const TBBUTTON tbb[] =
1300   {
1301    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1302    {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER,   TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1303    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1304    {VIEW_NEWFOLDER+1,  FCIDM_TB_DESKTOP,    TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1305    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1306    {VIEW_NEWFOLDER,    FCIDM_TB_NEWFOLDER,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1307    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1308    {VIEW_LIST,         FCIDM_TB_SMALLICON,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1309    {VIEW_DETAILS,      FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1310   };
1311   TBADDBITMAP tba[2];
1312   RECT rectTB;
1313   RECT rectlook;
1314   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1315 
1316   tba[0].hInst = HINST_COMMCTRL;
1317   tba[0].nID   = IDB_VIEW_SMALL_COLOR;
1318   tba[1].hInst = COMDLG32_hInstance;
1319   tba[1].nID   = 800;
1320 
1321   TRACE("%p\n", fodInfos);
1322 
1323   /* Get windows version emulating */
1324   osVi.dwOSVersionInfoSize = sizeof(osVi);
1325   GetVersionExW(&osVi);
1326   if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1327     win98plus   = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1328   } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1329     win2000plus = (osVi.dwMajorVersion > 4);
1330     if (win2000plus) win98plus = TRUE;
1331   }
1332   TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1333 
1334   /* Get the hwnd of the controls */
1335   fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1336   fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1337   fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1338 
1339   GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1340   MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1341 
1342   /* construct the toolbar */
1343   GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1344   MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1345 
1346   rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1347   rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1348   rectTB.left = rectlook.right;
1349   rectTB.top = rectlook.top-1;
1350 
1351   if (fodInfos->unicode)
1352       fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1353           WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1354           rectTB.left, rectTB.top,
1355           rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1356           hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1357   else
1358       fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1359           WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1360           rectTB.left, rectTB.top,
1361           rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1362           hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1363 
1364   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1365 
1366 /* FIXME: use TB_LOADIMAGES when implemented */
1367 /*  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1368   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1369   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1370   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1371 
1372   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1373   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1374 
1375   /* Set the window text with the text specified in the OPENFILENAME structure */
1376   if(fodInfos->title)
1377   {
1378       SetWindowTextW(hwnd,fodInfos->title);
1379   }
1380   else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1381   {
1382       WCHAR buf[16];
1383       LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1384       SetWindowTextW(hwnd, buf);
1385   }
1386 
1387   /* Initialise the file name edit control */
1388   handledPath = FALSE;
1389   TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1390 
1391   if(fodInfos->filename)
1392   {
1393       /* 1. If win2000 or higher and filename contains a path, use it
1394          in preference over the lpstrInitialDir                       */
1395       if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1396          WCHAR tmpBuf[MAX_PATH];
1397          WCHAR *nameBit;
1398          DWORD result;
1399 
1400          result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1401          if (result) {
1402 
1403             /* nameBit is always shorter than the original filename */
1404             lstrcpyW(fodInfos->filename,nameBit);
1405 
1406             *nameBit = 0x00;
1407             if (fodInfos->initdir == NULL)
1408                 MemFree(fodInfos->initdir);
1409             fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1410             lstrcpyW(fodInfos->initdir, tmpBuf);
1411             handledPath = TRUE;
1412             TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1413                     debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1414          }
1415          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1416 
1417       } else {
1418          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1419       }
1420   }
1421 
1422   /* 2. (All platforms) If initdir is not null, then use it */
1423   if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1424                                 (*fodInfos->initdir!=0x00))
1425   {
1426       /* Work out the proper path as supplied one might be relative          */
1427       /* (Here because supplying '.' as dir browses to My Computer)          */
1428       if (handledPath==FALSE) {
1429           WCHAR tmpBuf[MAX_PATH];
1430           WCHAR tmpBuf2[MAX_PATH];
1431           WCHAR *nameBit;
1432           DWORD result;
1433 
1434           lstrcpyW(tmpBuf, fodInfos->initdir);
1435           if( PathFileExistsW(tmpBuf) ) {
1436               /* initdir does not have to be a directory. If a file is
1437                * specified, the dir part is taken */
1438               if( PathIsDirectoryW(tmpBuf)) {
1439                   if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1440                      lstrcatW(tmpBuf, szwSlash);
1441                   }
1442                   lstrcatW(tmpBuf, szwStar);
1443               }
1444               result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1445               if (result) {
1446                  *nameBit = 0x00;
1447                  MemFree(fodInfos->initdir);
1448                  fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1449                  lstrcpyW(fodInfos->initdir, tmpBuf2);
1450                  handledPath = TRUE;
1451                  TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1452               }
1453           }
1454           else if (fodInfos->initdir)
1455           {
1456                     MemFree(fodInfos->initdir);
1457                     fodInfos->initdir = NULL;
1458                     TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1459           }
1460       }
1461   }
1462 
1463   if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1464                                  (*fodInfos->initdir==0x00)))
1465   {
1466       /* 3. All except w2k+: if filename contains a path use it */
1467       if (!win2000plus && fodInfos->filename &&
1468           *fodInfos->filename &&
1469           strpbrkW(fodInfos->filename, szwSlash)) {
1470          WCHAR tmpBuf[MAX_PATH];
1471          WCHAR *nameBit;
1472          DWORD result;
1473 
1474          result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1475                                   tmpBuf, &nameBit);
1476          if (result) {
1477             int len;
1478 
1479             /* nameBit is always shorter than the original filename */
1480             lstrcpyW(fodInfos->filename, nameBit);
1481             *nameBit = 0x00;
1482 
1483             len = lstrlenW(tmpBuf);
1484             MemFree(fodInfos->initdir);
1485             fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1486             lstrcpyW(fodInfos->initdir, tmpBuf);
1487 
1488             handledPath = TRUE;
1489             TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1490                  debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1491          }
1492          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1493       }
1494 
1495       /* 4. win98+ and win2000+ if any files of specified filter types in
1496             current directory, use it                                      */
1497       if ( win98plus && handledPath == FALSE &&
1498            fodInfos->filter && *fodInfos->filter) {
1499 
1500          BOOL   searchMore = TRUE;
1501          LPCWSTR lpstrPos = fodInfos->filter;
1502          WIN32_FIND_DATAW FindFileData;
1503          HANDLE hFind;
1504 
1505          while (searchMore)
1506          {
1507            /* filter is a list...  title\0ext\0......\0\0 */
1508 
1509            /* Skip the title */
1510            if(! *lpstrPos) break;       /* end */
1511            lpstrPos += lstrlenW(lpstrPos) + 1;
1512 
1513            /* See if any files exist in the current dir with this extension */
1514            if(! *lpstrPos) break;       /* end */
1515 
1516            hFind = FindFirstFileW(lpstrPos, &FindFileData);
1517 
1518            if (hFind == INVALID_HANDLE_VALUE) {
1519                /* None found - continue search */
1520                lpstrPos += lstrlenW(lpstrPos) + 1;
1521 
1522            } else {
1523                searchMore = FALSE;
1524 
1525                MemFree(fodInfos->initdir);
1526                fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1527                GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1528 
1529                handledPath = TRUE;
1530                TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1531                  debugstr_w(lpstrPos));
1532                break;
1533            }
1534          }
1535       }
1536 
1537       /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1538 
1539       /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1540       if (handledPath == FALSE && (win2000plus || win98plus)) {
1541           fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1542 
1543           if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1544           {
1545             if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1546             {
1547                 /* last fallback */
1548                 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1549                 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1550             } else {
1551                 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1552             }
1553           } else {
1554             TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1555           }
1556           handledPath = TRUE;
1557       } else if (handledPath==FALSE) {
1558           fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1559           GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1560           handledPath = TRUE;
1561           TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1562       }
1563   }
1564   SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1565   TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1566 
1567   /* Must the open as read only check box be checked ?*/
1568   if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1569   {
1570     SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1571   }
1572 
1573   /* Must the open as read only check box be hidden? */
1574   if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1575   {
1576     ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1577     EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1578   }
1579 
1580   /* Must the help button be hidden? */
1581   if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1582   {
1583     ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1584     EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1585   }
1586 
1587   /* change Open to Save */
1588   if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1589   {
1590       WCHAR buf[16];
1591       LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1592       SetDlgItemTextW(hwnd, IDOK, buf);
1593       LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1594       SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1595   }
1596 
1597   /* Initialize the filter combo box */
1598   FILEDLG95_FILETYPE_Init(hwnd);
1599 
1600   return 0;
1601 }
1602 
1603 /***********************************************************************
1604  *      FILEDLG95_ResizeControls
1605  *
1606  * WM_INITDIALOG message handler (after hook notification)
1607  */
1608 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1609 {
1610   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1611 
1612   if (fodInfos->DlgInfos.hwndCustomDlg)
1613   {
1614     RECT rc;
1615     UINT flags = SWP_NOACTIVATE;
1616 
1617     ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1618         (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1619 
1620     /* resize the custom dialog to the parent size */
1621     if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1622       GetClientRect(hwnd, &rc);
1623     else
1624     {
1625       /* our own fake template is zero sized and doesn't have children, so
1626        * there is no need to resize it. Picasa depends on it.
1627        */
1628       flags |= SWP_NOSIZE;
1629       SetRectEmpty(&rc);
1630     }
1631       SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1632           0, 0, rc.right, rc.bottom, flags);
1633   }
1634   else
1635   {
1636     /* Resize the height, if open as read only checkbox ad help button are
1637      * hidden and we are not using a custom template nor a customDialog
1638      */
1639     if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1640                 (!(fodInfos->ofnInfos->Flags &
1641                    (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1642     {
1643       RECT rectDlg, rectHelp, rectCancel;
1644       GetWindowRect(hwnd, &rectDlg);
1645       GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1646       GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1647       /* subtract the height of the help button plus the space between the help
1648        * button and the cancel button to the height of the dialog
1649        */
1650       SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1651           (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1652           SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1653     }
1654   }
1655   return TRUE;
1656 }
1657 
1658 /***********************************************************************
1659  *      FILEDLG95_FillControls
1660  *
1661  * WM_INITDIALOG message handler (after hook notification)
1662  */
1663 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1664 {
1665   LPITEMIDLIST pidlItemId = NULL;
1666 
1667   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1668 
1669   TRACE("dir=%s file=%s\n",
1670   debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1671 
1672   /* Get the initial directory pidl */
1673 
1674   if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1675   {
1676     WCHAR path[MAX_PATH];
1677 
1678     GetCurrentDirectoryW(MAX_PATH,path);
1679     pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1680   }
1681 
1682   /* Initialise shell objects */
1683   FILEDLG95_SHELL_Init(hwnd);
1684 
1685   /* Initialize the Look In combo box */
1686   FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1687 
1688   /* Browse to the initial directory */
1689   IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1690 
1691   /* Free pidlItem memory */
1692   COMDLG32_SHFree(pidlItemId);
1693 
1694   return TRUE;
1695 }
1696 /***********************************************************************
1697  *      FILEDLG95_Clean
1698  *
1699  * Regroups all the cleaning functions of the filedlg
1700  */
1701 void FILEDLG95_Clean(HWND hwnd)
1702 {
1703       FILEDLG95_FILETYPE_Clean(hwnd);
1704       FILEDLG95_LOOKIN_Clean(hwnd);
1705       FILEDLG95_SHELL_Clean(hwnd);
1706 }
1707 /***********************************************************************
1708  *      FILEDLG95_OnWMCommand
1709  *
1710  * WM_COMMAND message handler
1711  */
1712 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1713 {
1714   WORD wNotifyCode = HIWORD(wParam); /* notification code */
1715   WORD wID = LOWORD(wParam);         /* item, control, or accelerator identifier */
1716   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1717 
1718   switch(wID)
1719   {
1720     /* OK button */
1721   case IDOK:
1722     FILEDLG95_OnOpen(hwnd);
1723     break;
1724     /* Cancel button */
1725   case IDCANCEL:
1726     FILEDLG95_Clean(hwnd);
1727     EndDialog(hwnd, FALSE);
1728     break;
1729     /* Filetype combo box */
1730   case IDC_FILETYPE:
1731     FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1732     break;
1733     /* LookIn combo box */
1734   case IDC_LOOKIN:
1735     FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1736     break;
1737 
1738   /* --- toolbar --- */
1739     /* Up folder button */
1740   case FCIDM_TB_UPFOLDER:
1741     FILEDLG95_SHELL_UpFolder(hwnd);
1742     break;
1743     /* New folder button */
1744   case FCIDM_TB_NEWFOLDER:
1745     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1746     break;
1747     /* List option button */
1748   case FCIDM_TB_SMALLICON:
1749     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1750     break;
1751     /* Details option button */
1752   case FCIDM_TB_REPORTVIEW:
1753     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1754     break;
1755     /* Details option button */
1756   case FCIDM_TB_DESKTOP:
1757     FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1758     break;
1759 
1760   case IDC_FILENAME:
1761     break;
1762 
1763   }
1764   /* Do not use the listview selection anymore */
1765   fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1766   return 0;
1767 }
1768 
1769 /***********************************************************************
1770  *      FILEDLG95_OnWMGetIShellBrowser
1771  *
1772  * WM_GETISHELLBROWSER message handler
1773  */
1774 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1775 {
1776   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1777 
1778   TRACE("\n");
1779 
1780   SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1781 
1782   return TRUE;
1783 }
1784 
1785 
1786 /***********************************************************************
1787  *      FILEDLG95_SendFileOK
1788  *
1789  * Sends the CDN_FILEOK notification if required
1790  *
1791  * RETURNS
1792  *  TRUE if the dialog should close
1793  *  FALSE if the dialog should not be closed
1794  */
1795 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1796 {
1797     /* ask the hook if we can close */
1798     if(IsHooked(fodInfos))
1799     {
1800         LRESULT retval = 0;
1801 
1802         TRACE("---\n");
1803         /* First send CDN_FILEOK as MSDN doc says */
1804         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1805             retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1806         if( retval)
1807         {
1808             TRACE("canceled\n");
1809             return FALSE;
1810         }
1811 
1812         /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1813         retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1814                               fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1815         if( retval)
1816         {
1817             TRACE("canceled\n");
1818             return FALSE;
1819         }
1820     }
1821     return TRUE;
1822 }
1823 
1824 /***********************************************************************
1825  *      FILEDLG95_OnOpenMultipleFiles
1826  *
1827  * Handles the opening of multiple files.
1828  *
1829  * FIXME
1830  *  check destination buffer size
1831  */
1832 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1833 {
1834   WCHAR   lpstrPathSpec[MAX_PATH] = {0};
1835   UINT   nCount, nSizePath;
1836   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1837 
1838   TRACE("\n");
1839 
1840   if(fodInfos->unicode)
1841   {
1842      LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1843      ofn->lpstrFile[0] = '\0';
1844   }
1845   else
1846   {
1847      LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1848      ofn->lpstrFile[0] = '\0';
1849   }
1850 
1851   COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1852 
1853   if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1854       ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1855        ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1856   {
1857     LPWSTR lpstrTemp = lpstrFileList;
1858 
1859     for ( nCount = 0; nCount < nFileCount; nCount++ )
1860     {
1861       LPITEMIDLIST pidl;
1862 
1863       pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1864       if (!pidl)
1865       {
1866         WCHAR lpstrNotFound[100];
1867         WCHAR lpstrMsg[100];
1868         WCHAR tmp[400];
1869         static const WCHAR nl[] = {'\n',0};
1870 
1871         LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1872         LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1873 
1874         lstrcpyW(tmp, lpstrTemp);
1875         lstrcatW(tmp, nl);
1876         lstrcatW(tmp, lpstrNotFound);
1877         lstrcatW(tmp, nl);
1878         lstrcatW(tmp, lpstrMsg);
1879 
1880         MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1881         return FALSE;
1882       }
1883 
1884       /* move to the next file in the list of files */
1885       lpstrTemp += lstrlenW(lpstrTemp) + 1;
1886       COMDLG32_SHFree(pidl);
1887     }
1888   }
1889 
1890   nSizePath = lstrlenW(lpstrPathSpec) + 1;
1891   if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1892   {
1893     /* For "oldstyle" dialog the components have to
1894        be separated by blanks (not '\0'!) and short
1895        filenames have to be used! */
1896     FIXME("Components have to be separated by blanks\n");
1897   }
1898   if(fodInfos->unicode)
1899   {
1900     LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1901     lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1902     memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1903   }
1904   else
1905   {
1906     LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1907 
1908     if (ofn->lpstrFile != NULL)
1909     {
1910       nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1911                           ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1912       if (ofn->nMaxFile > nSizePath)
1913       {
1914         WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1915                             ofn->lpstrFile + nSizePath,
1916                             ofn->nMaxFile - nSizePath, NULL, NULL);
1917       }
1918     }
1919   }
1920 
1921   fodInfos->ofnInfos->nFileOffset = nSizePath;
1922   fodInfos->ofnInfos->nFileExtension = 0;
1923 
1924   if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1925     return FALSE;
1926 
1927   /* clean and exit */
1928   FILEDLG95_Clean(hwnd);
1929   return EndDialog(hwnd,TRUE);
1930 }
1931 
1932 /***********************************************************************
1933  *      FILEDLG95_OnOpen
1934  *
1935  * Ok button WM_COMMAND message handler
1936  *
1937  * If the function succeeds, the return value is nonzero.
1938  */
1939 #define ONOPEN_BROWSE 1
1940 #define ONOPEN_OPEN   2
1941 #define ONOPEN_SEARCH 3
1942 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1943 {
1944   WCHAR strMsgTitle[MAX_PATH];
1945   WCHAR strMsgText [MAX_PATH];
1946   if (idCaption)
1947     LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1948   else
1949     strMsgTitle[0] = '\0';
1950   LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1951   MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1952 }
1953 
1954 BOOL FILEDLG95_OnOpen(HWND hwnd)
1955 {
1956   LPWSTR lpstrFileList;
1957   UINT nFileCount = 0;
1958   UINT sizeUsed = 0;
1959   BOOL ret = TRUE;
1960   WCHAR lpstrPathAndFile[MAX_PATH];
1961   WCHAR lpstrTemp[MAX_PATH];
1962   LPSHELLFOLDER lpsf = NULL;
1963   int nOpenAction;
1964   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1965 
1966   TRACE("hwnd=%p\n", hwnd);
1967 
1968   /* get the files from the edit control */
1969   nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1970 
1971   /* try if the user selected a folder in the shellview */
1972   if(nFileCount == 0)
1973   {
1974       BrowseSelectedFolder(hwnd);
1975       return FALSE;
1976   }
1977 
1978   if(nFileCount > 1)
1979   {
1980       ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1981       goto ret;
1982   }
1983 
1984   TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1985 
1986 /*
1987   Step 1:  Build a complete path name from the current folder and
1988   the filename or path in the edit box.
1989   Special cases:
1990   - the path in the edit box is a root path
1991     (with or without drive letter)
1992   - the edit box contains ".." (or a path with ".." in it)
1993 */
1994 
1995   /* Get the current directory name */
1996   if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1997   {
1998     /* last fallback */
1999     GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2000   }
2001   PathAddBackslashW(lpstrPathAndFile);
2002 
2003   TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2004 
2005   /* if the user specified a fully qualified path use it */
2006   if(PathIsRelativeW(lpstrFileList))
2007   {
2008     lstrcatW(lpstrPathAndFile, lpstrFileList);
2009   }
2010   else
2011   {
2012     /* does the path have a drive letter? */
2013     if (PathGetDriveNumberW(lpstrFileList) == -1)
2014       lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2015     else
2016       lstrcpyW(lpstrPathAndFile, lpstrFileList);
2017   }
2018 
2019   /* resolve "." and ".." */
2020   PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2021   lstrcpyW(lpstrPathAndFile, lpstrTemp);
2022   TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2023 
2024   MemFree(lpstrFileList);
2025 
2026 /*
2027   Step 2: here we have a cleaned up path
2028 
2029   We have to parse the path step by step to see if we have to browse
2030   to a folder if the path points to a directory or the last
2031   valid element is a directory.
2032 
2033   valid variables:
2034     lpstrPathAndFile: cleaned up path
2035  */
2036 
2037   if (nFileCount &&
2038       (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2039       !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2040     nOpenAction = ONOPEN_OPEN;
2041   else
2042     nOpenAction = ONOPEN_BROWSE;
2043 
2044   /* don't apply any checks with OFN_NOVALIDATE */
2045   {
2046     LPWSTR lpszTemp, lpszTemp1;
2047     LPITEMIDLIST pidl = NULL;
2048     static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2049 
2050     /* check for invalid chars */
2051     if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2052     {
2053       FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2054       ret = FALSE;
2055       goto ret;
2056     }
2057 
2058     if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2059 
2060     lpszTemp1 = lpszTemp = lpstrPathAndFile;
2061     while (lpszTemp1)
2062     {
2063       LPSHELLFOLDER lpsfChild;
2064       WCHAR lpwstrTemp[MAX_PATH];
2065       DWORD dwEaten, dwAttributes;
2066       LPWSTR p;
2067 
2068       lstrcpyW(lpwstrTemp, lpszTemp);
2069       p = PathFindNextComponentW(lpwstrTemp);
2070 
2071       if (!p) break; /* end of path */
2072 
2073       *p = 0;
2074       lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2075 
2076       /* There are no wildcards when OFN_NOVALIDATE is set */
2077       if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2078       {
2079         static const WCHAR wszWild[] = { '*', '?', 0 };
2080         /* if the last element is a wildcard do a search */
2081         if(strpbrkW(lpszTemp1, wszWild) != NULL)
2082         {
2083           nOpenAction = ONOPEN_SEARCH;
2084           break;
2085         }
2086       }
2087       lpszTemp1 = lpszTemp;
2088 
2089       TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2090 
2091       /* append a backslash to drive letters */
2092       if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' && 
2093          ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2094           (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z'))) 
2095       {
2096         PathAddBackslashW(lpwstrTemp);
2097       }
2098 
2099       dwAttributes = SFGAO_FOLDER;
2100       if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2101       {
2102         /* the path component is valid, we have a pidl of the next path component */
2103         TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2104         if(dwAttributes & SFGAO_FOLDER)
2105         {
2106           if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2107           {
2108             ERR("bind to failed\n"); /* should not fail */
2109             break;
2110           }
2111           IShellFolder_Release(lpsf);
2112           lpsf = lpsfChild;
2113           lpsfChild = NULL;
2114         }
2115         else
2116         {
2117           TRACE("value\n");
2118 
2119           /* end dialog, return value */
2120           nOpenAction = ONOPEN_OPEN;
2121           break;
2122         }
2123         COMDLG32_SHFree(pidl);
2124         pidl = NULL;
2125       }
2126       else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2127       {
2128         if(*lpszTemp || /* points to trailing null for last path element */
2129            (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2130         {
2131           if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2132           {
2133             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2134             break;
2135           }
2136         }
2137         else
2138         {
2139           if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2140              !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2141           {
2142             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2143             break;
2144           }
2145         }
2146         /* change to the current folder */
2147         nOpenAction = ONOPEN_OPEN;
2148         break;
2149       }
2150       else
2151       {
2152         nOpenAction = ONOPEN_OPEN;
2153         break;
2154       }
2155     }
2156     if(pidl) COMDLG32_SHFree(pidl);
2157   }
2158 
2159 /*
2160   Step 3: here we have a cleaned up and validated path
2161 
2162   valid variables:
2163    lpsf:             ShellFolder bound to the rightmost valid path component
2164    lpstrPathAndFile: cleaned up path
2165    nOpenAction:      action to do
2166 */
2167   TRACE("end validate sf=%p\n", lpsf);
2168 
2169   switch(nOpenAction)
2170   {
2171     case ONOPEN_SEARCH:   /* set the current filter to the file mask and refresh */
2172       TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2173       {
2174         int iPos;
2175         LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2176         DWORD len;
2177 
2178         /* replace the current filter */
2179         MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2180         len = lstrlenW(lpszTemp)+1;
2181         fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2182         lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2183 
2184         /* set the filter cb to the extension when possible */
2185         if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2186         CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2187       }
2188       /* fall through */
2189     case ONOPEN_BROWSE:   /* browse to the highest folder we could bind to */
2190       TRACE("ONOPEN_BROWSE\n");
2191       {
2192         IPersistFolder2 * ppf2;
2193         if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2194         {
2195           LPITEMIDLIST pidlCurrent;
2196           IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2197           IPersistFolder2_Release(ppf2);
2198           if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2199           {
2200             if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2201                 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2202             {
2203               SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2204             }
2205           }
2206           else if( nOpenAction == ONOPEN_SEARCH )
2207           {
2208             if (fodInfos->Shell.FOIShellView)
2209               IShellView_Refresh(fodInfos->Shell.FOIShellView);
2210           }
2211           COMDLG32_SHFree(pidlCurrent);
2212           SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2213         }
2214       }
2215       ret = FALSE;
2216       break;
2217     case ONOPEN_OPEN:   /* fill in the return struct and close the dialog */
2218       TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2219       {
2220         WCHAR *ext = NULL;
2221 
2222         /* update READONLY check box flag */
2223         if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2224           fodInfos->ofnInfos->Flags |= OFN_READONLY;
2225         else
2226           fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2227 
2228         /* Attach the file extension with file name*/
2229         ext = PathFindExtensionW(lpstrPathAndFile);
2230         if (! *ext)
2231         {
2232             /* if no extension is specified with file name, then */
2233             /* attach the extension from file filter or default one */
2234             
2235             WCHAR *filterExt = NULL;
2236             LPWSTR lpstrFilter = NULL;
2237             static const WCHAR szwDot[] = {'.',0};
2238             int PathLength = lstrlenW(lpstrPathAndFile);
2239 
2240             /* Attach the dot*/
2241             lstrcatW(lpstrPathAndFile, szwDot);
2242     
2243             /*Get the file extension from file type filter*/
2244             lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2245                                              fodInfos->ofnInfos->nFilterIndex-1);
2246 
2247             if (lpstrFilter != (LPWSTR)CB_ERR)  /* control is not empty */
2248                 filterExt = PathFindExtensionW(lpstrFilter);
2249 
2250             if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2251                 lstrcatW(lpstrPathAndFile, filterExt + 1);
2252             else if ( fodInfos->defext ) /* attach the default file extension*/
2253                 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2254 
2255             /* In Open dialog: if file does not exist try without extension */
2256             if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2257                   lpstrPathAndFile[PathLength] = '\0';
2258         }
2259 
2260         if (fodInfos->defext) /* add default extension */
2261         {
2262           /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2263           if (*ext)
2264             ext++;
2265           if (!lstrcmpiW(fodInfos->defext, ext))
2266             fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2267           else
2268             fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2269         }
2270 
2271         /* In Save dialog: check if the file already exists */
2272         if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2273             && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2274             && PathFileExistsW(lpstrPathAndFile))
2275         {
2276           WCHAR lpstrOverwrite[100];
2277           int answer;
2278 
2279           LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2280           answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2281                                MB_YESNO | MB_ICONEXCLAMATION);
2282           if (answer == IDNO)
2283           {
2284             ret = FALSE;
2285             goto ret;
2286           }
2287         }
2288 
2289         /* In Open dialog: check if it should be created if it doesn't exist */
2290         if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2291             && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2292             && !PathFileExistsW(lpstrPathAndFile))
2293         {
2294           WCHAR lpstrCreate[100];
2295           int answer;
2296 
2297           LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2298           answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2299                                MB_YESNO | MB_ICONEXCLAMATION);
2300           if (answer == IDNO)
2301           {
2302             ret = FALSE;
2303             goto ret;
2304           }
2305         }
2306 
2307         /* Check that the size of the file does not exceed buffer size.
2308              (Allow for extra \0 if OFN_MULTISELECT is set.) */
2309         if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2310             ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2311         {
2312 
2313           /* fill destination buffer */
2314           if (fodInfos->ofnInfos->lpstrFile)
2315           {
2316              if(fodInfos->unicode)
2317              {
2318                LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2319 
2320                lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2321                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2322                  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2323              }
2324              else
2325              {
2326                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2327 
2328                WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2329                                    ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2330                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2331                  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2332              }
2333           }
2334 
2335           if(fodInfos->unicode)
2336           {
2337               LPWSTR lpszTemp;
2338 
2339               /* set filename offset */
2340               lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2341               fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2342 
2343               /* set extension offset */
2344               lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2345               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2346           }
2347           else
2348           {
2349                LPSTR lpszTemp;
2350                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2351 
2352               /* set filename offset */
2353               lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2354               fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2355 
2356               /* set extension offset */
2357               lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2358               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2359           }
2360 
2361           /* set the lpstrFileTitle */
2362           if(fodInfos->ofnInfos->lpstrFileTitle)
2363           {
2364             LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2365             if(fodInfos->unicode)
2366             {
2367               LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2368               lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2369             }
2370             else
2371             {
2372               LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2373               WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2374                     ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2375             }
2376           }
2377 
2378           /* copy currently selected filter to lpstrCustomFilter */
2379           if (fodInfos->ofnInfos->lpstrCustomFilter)
2380           {
2381             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2382             int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2383                                           NULL, 0, NULL, NULL);
2384             if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2385             {
2386               LPSTR s = ofn->lpstrCustomFilter;
2387               s += strlen(ofn->lpstrCustomFilter)+1;
2388               WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2389                                   s, len, NULL, NULL);
2390             }
2391           }
2392 
2393 
2394           if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2395               goto ret;
2396 
2397           TRACE("close\n");
2398           FILEDLG95_Clean(hwnd);
2399           ret = EndDialog(hwnd, TRUE);
2400         }
2401         else
2402         {
2403           WORD size;
2404 
2405           size = lstrlenW(lpstrPathAndFile) + 1;
2406           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2407              size += 1;
2408           /* return needed size in first two bytes of lpstrFile */
2409           *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2410           FILEDLG95_Clean(hwnd);
2411           ret = EndDialog(hwnd, FALSE);
2412           COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2413         }
2414       }
2415       break;
2416   }
2417 
2418 ret:
2419   if(lpsf) IShellFolder_Release(lpsf);
2420   return ret;
2421 }
2422 
2423 /***********************************************************************
2424  *      FILEDLG95_SHELL_Init
2425  *
2426  * Initialisation of the shell objects
2427  */
2428 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2429 {
2430   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2431 
2432   TRACE("\n");
2433 
2434   /*
2435    * Initialisation of the FileOpenDialogInfos structure
2436    */
2437 
2438   /* Shell */
2439 
2440   /*ShellInfos */
2441   fodInfos->ShellInfos.hwndOwner = hwnd;
2442 
2443   /* Disable multi-select if flag not set */
2444   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2445   {
2446      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2447   }
2448   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2449   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2450 
2451   /* Construct the IShellBrowser interface */
2452   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2453 
2454   return NOERROR;
2455 }
2456 
2457 /***********************************************************************
2458  *      FILEDLG95_SHELL_ExecuteCommand
2459  *
2460  * Change the folder option and refresh the view
2461  * If the function succeeds, the return value is nonzero.
2462  */
2463 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2464 {
2465   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2466   IContextMenu * pcm;
2467 
2468   TRACE("(%p,%p)\n", hwnd, lpVerb);
2469 
2470   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2471                                         SVGIO_BACKGROUND,
2472                                         &IID_IContextMenu,
2473                                         (LPVOID*)&pcm)))
2474   {
2475     CMINVOKECOMMANDINFO ci;
2476     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2477     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2478     ci.lpVerb = lpVerb;
2479     ci.hwnd = hwnd;
2480 
2481     IContextMenu_InvokeCommand(pcm, &ci);
2482     IContextMenu_Release(pcm);
2483   }
2484 
2485   return FALSE;
2486 }
2487 
2488 /***********************************************************************
2489  *      FILEDLG95_SHELL_UpFolder
2490  *
2491  * Browse to the specified object
2492  * If the function succeeds, the return value is nonzero.
2493  */
2494 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2495 {
2496   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2497 
2498   TRACE("\n");
2499 
2500   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2501                                           NULL,
2502                                           SBSP_PARENT)))
2503   {
2504     if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2505         SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2506     return TRUE;
2507   }
2508   return FALSE;
2509 }
2510 
2511 /***********************************************************************
2512  *      FILEDLG95_SHELL_BrowseToDesktop
2513  *
2514  * Browse to the Desktop
2515  * If the function succeeds, the return value is nonzero.
2516  */
2517 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2518 {
2519   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2520   LPITEMIDLIST pidl;
2521   HRESULT hres;
2522 
2523   TRACE("\n");
2524 
2525   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2526   hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2527   if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2528       SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2529   COMDLG32_SHFree(pidl);
2530   return SUCCEEDED(hres);
2531 }
2532 /***********************************************************************
2533  *      FILEDLG95_SHELL_Clean
2534  *
2535  * Cleans the memory used by shell objects
2536  */
2537 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2538 {
2539     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2540 
2541     TRACE("\n");
2542 
2543     COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2544 
2545     /* clean Shell interfaces */
2546     if (fodInfos->Shell.FOIShellView)
2547     {
2548       IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2549       IShellView_Release(fodInfos->Shell.FOIShellView);
2550     }
2551     IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2552     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2553     if (fodInfos->Shell.FOIDataObject)
2554       IDataObject_Release(fodInfos->Shell.FOIDataObject);
2555 }
2556 
2557 /***********************************************************************
2558  *      FILEDLG95_FILETYPE_Init
2559  *
2560  * Initialisation of the file type combo box
2561  */
2562 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2563 {
2564   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2565   int nFilters = 0;  /* number of filters */
2566   int nFilterIndexCB;
2567 
2568   TRACE("\n");
2569 
2570   if(fodInfos->customfilter)
2571   {
2572       /* customfilter has one entry...  title\0ext\0
2573        * Set first entry of combo box item with customfilter
2574        */
2575       LPWSTR  lpstrExt;
2576       LPCWSTR lpstrPos = fodInfos->customfilter;
2577 
2578       /* Get the title */
2579       lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2580 
2581       /* Copy the extensions */
2582       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
2583       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2584       lstrcpyW(lpstrExt,lpstrPos);
2585 
2586       /* Add the item at the end of the combo */
2587       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2588       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2589       nFilters++;
2590   }
2591   if(fodInfos->filter)
2592   {
2593     LPCWSTR lpstrPos = fodInfos->filter;
2594 
2595     for(;;)
2596     {
2597       /* filter is a list...  title\0ext\0......\0\0
2598        * Set the combo item text to the title and the item data
2599        *  to the ext
2600        */
2601       LPCWSTR lpstrDisplay;
2602       LPWSTR lpstrExt;
2603 
2604       /* Get the title */
2605       if(! *lpstrPos) break;    /* end */
2606       lpstrDisplay = lpstrPos;
2607       lpstrPos += lstrlenW(lpstrPos) + 1;
2608 
2609       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2610 
2611       nFilters++;
2612 
2613       /* Copy the extensions */
2614       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2615       lstrcpyW(lpstrExt,lpstrPos);
2616       lpstrPos += lstrlenW(lpstrPos) + 1;
2617 
2618       /* Add the item at the end of the combo */
2619       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2620 
2621       /* malformed filters are added anyway... */
2622       if (!*lpstrExt) break;
2623     }
2624   }
2625 
2626   /*
2627    * Set the current filter to the one specified
2628    * in the initialisation structure
2629    */
2630   if (fodInfos->filter || fodInfos->customfilter)
2631   {
2632     LPWSTR lpstrFilter;
2633 
2634     /* Check to make sure our index isn't out of bounds. */
2635     if ( fodInfos->ofnInfos->nFilterIndex >
2636          nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2637       fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2638 
2639     /* set default filter index */
2640     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2641       fodInfos->ofnInfos->nFilterIndex = 1;
2642 
2643     /* calculate index of Combo Box item */
2644     nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2645     if (fodInfos->customfilter == NULL)
2646       nFilterIndexCB--;
2647 
2648     /* Set the current index selection. */
2649     CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2650 
2651     /* Get the corresponding text string from the combo box. */
2652     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2653                                              nFilterIndexCB);
2654 
2655     if ((INT_PTR)lpstrFilter == CB_ERR)  /* control is empty */
2656       lpstrFilter = NULL;
2657 
2658     if(lpstrFilter)
2659     {
2660       DWORD len;
2661       CharLowerW(lpstrFilter); /* lowercase */
2662       len = lstrlenW(lpstrFilter)+1;
2663       fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2664       lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2665     }
2666   } else
2667       fodInfos->ofnInfos->nFilterIndex = 0;
2668   return S_OK;
2669 }
2670 
2671 /***********************************************************************
2672  *      FILEDLG95_FILETYPE_OnCommand
2673  *
2674  * WM_COMMAND of the file type combo box
2675  * If the function succeeds, the return value is nonzero.
2676  */
2677 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2678 {
2679   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2680 
2681   switch(wNotifyCode)
2682   {
2683     case CBN_SELENDOK:
2684     {
2685       LPWSTR lpstrFilter;
2686 
2687       /* Get the current item of the filetype combo box */
2688       int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2689 
2690       /* set the current filter index */
2691       fodInfos->ofnInfos->nFilterIndex = iItem +
2692         (fodInfos->customfilter == NULL ? 1 : 0);
2693 
2694       /* Set the current filter with the current selection */
2695       MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2696 
2697       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2698                                              iItem);
2699       if((INT_PTR)lpstrFilter != CB_ERR)
2700       {
2701           DWORD len;
2702           CharLowerW(lpstrFilter); /* lowercase */
2703           len = lstrlenW(lpstrFilter)+1;
2704           fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2705           lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2706           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2707               SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2708       }
2709 
2710       /* Refresh the actual view to display the included items*/
2711       if (fodInfos->Shell.FOIShellView)
2712         IShellView_Refresh(fodInfos->Shell.FOIShellView);
2713     }
2714   }
2715   return FALSE;
2716 }
2717 /***********************************************************************
2718  *      FILEDLG95_FILETYPE_SearchExt
2719  *
2720  * searches for an extension in the filetype box
2721  */
2722 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2723 {
2724   int i, iCount = CBGetCount(hwnd);
2725 
2726   TRACE("%s\n", debugstr_w(lpstrExt));
2727 
2728   if(iCount != CB_ERR)
2729   {
2730     for(i=0;i<iCount;i++)
2731     {
2732       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2733           return i;
2734     }
2735   }
2736   return -1;
2737 }
2738 
2739 /***********************************************************************
2740  *      FILEDLG95_FILETYPE_Clean
2741  *
2742  * Clean the memory used by the filetype combo box
2743  */
2744 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2745 {
2746   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2747   int iPos;
2748   int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2749 
2750   TRACE("\n");
2751 
2752   /* Delete each string of the combo and their associated data */
2753   if(iCount != CB_ERR)
2754   {
2755     for(iPos = iCount-1;iPos>=0;iPos--)
2756     {
2757       MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2758       CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2759     }
2760   }
2761   /* Current filter */
2762   MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2763 
2764 }
2765 
2766 /***********************************************************************
2767  *      FILEDLG95_LOOKIN_Init
2768  *
2769  * Initialisation of the look in combo box
2770  */
2771 
2772 /* Small helper function, to determine if the unixfs shell extension is rooted 
2773  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 
2774  */
2775 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2776     HKEY hKey;
2777     static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2778         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2779         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2780         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2781         'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','','A','A','E','8',
2782         '-','','6','2','5','-','4','4','B','','-','9','C','A','7','-',
2783         '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2784     
2785     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2786         return FALSE;
2787         
2788     RegCloseKey(hKey);
2789     return TRUE;
2790 }
2791 
2792 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2793 {
2794   IShellFolder  *psfRoot, *psfDrives;
2795   IEnumIDList   *lpeRoot, *lpeDrives;
2796   LPITEMIDLIST  pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2797 
2798   LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2799 
2800   TRACE("\n");
2801 
2802   liInfos->iMaxIndentation = 0;
2803 
2804   SetPropA(hwndCombo, LookInInfosStr, liInfos);
2805 
2806   /* set item height for both text field and listbox */
2807   CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2808   CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2809    
2810   /* Turn on the extended UI for the combo box like Windows does */
2811   CBSetExtendedUI(hwndCombo, TRUE);
2812 
2813   /* Initialise data of Desktop folder */
2814   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2815   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2816   COMDLG32_SHFree(pidlTmp);
2817 
2818   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2819 
2820   SHGetDesktopFolder(&psfRoot);
2821 
2822   if (psfRoot)
2823   {
2824     /* enumerate the contents of the desktop */
2825     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2826     {
2827       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2828       {
2829         FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2830 
2831         /* If the unixfs extension is rooted, we don't expand the drives by default */
2832         if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 
2833         {
2834           /* special handling for CSIDL_DRIVES */
2835           if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2836           {
2837             if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2838             {
2839               /* enumerate the drives */
2840               if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2841               {
2842                 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2843                 {
2844                   pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2845                   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2846                   COMDLG32_SHFree(pidlAbsTmp);
2847                   COMDLG32_SHFree(pidlTmp1);
2848                 }
2849                 IEnumIDList_Release(lpeDrives);
2850               }
2851               IShellFolder_Release(psfDrives);
2852             }
2853           }
2854         }
2855 
2856         COMDLG32_SHFree(pidlTmp);
2857       }
2858       IEnumIDList_Release(lpeRoot);
2859     }
2860     IShellFolder_Release(psfRoot);
2861   }
2862 
2863   COMDLG32_SHFree(pidlDrives);
2864 }
2865 
2866 /***********************************************************************
2867  *      FILEDLG95_LOOKIN_DrawItem
2868  *
2869  * WM_DRAWITEM message handler
2870  */
2871 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2872 {
2873   COLORREF crWin = GetSysColor(COLOR_WINDOW);
2874   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2875   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2876   RECT rectText;
2877   RECT rectIcon;
2878   SHFILEINFOW sfi;
2879   HIMAGELIST ilItemImage;
2880   int iIndentation;
2881   TEXTMETRICW tm;
2882   LPSFOLDER tmpFolder;
2883   LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2884 
2885   TRACE("\n");
2886 
2887   if(pDIStruct->itemID == -1)
2888     return 0;
2889 
2890   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2891                             pDIStruct->itemID)))
2892     return 0;
2893 
2894 
2895   if(pDIStruct->itemID == liInfos->uSelectedItem)
2896   {
2897     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2898                                                0,
2899                                                &sfi,
2900                                                sizeof (sfi),
2901                                                SHGFI_PIDL | SHGFI_SMALLICON |
2902                                                SHGFI_OPENICON | SHGFI_SYSICONINDEX    |
2903                                                SHGFI_DISPLAYNAME );
2904   }
2905   else
2906   {
2907     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2908                                                   0,
2909                                                   &sfi,
2910                                                   sizeof (sfi),
2911                                                   SHGFI_PIDL | SHGFI_SMALLICON |
2912                                                   SHGFI_SYSICONINDEX |
2913                                                   SHGFI_DISPLAYNAME);
2914   }
2915 
2916   /* Is this item selected ? */
2917   if(pDIStruct->itemState & ODS_SELECTED)
2918   {
2919     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2920     SetBkColor(pDIStruct->hDC,crHighLight);
2921     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2922   }
2923   else
2924   {
2925     SetTextColor(pDIStruct->hDC,crText);
2926     SetBkColor(pDIStruct->hDC,crWin);
2927     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2928   }
2929 
2930   /* Do not indent item if drawing in the edit of the combo */
2931   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2932   {
2933     iIndentation = 0;
2934     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2935                                                 0,
2936                                                 &sfi,
2937                                                 sizeof (sfi),
2938                                                 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2939                                                 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME  );
2940 
2941   }
2942   else
2943   {
2944     iIndentation = tmpFolder->m_iIndent;
2945   }
2946   /* Draw text and icon */
2947 
2948   /* Initialise the icon display area */
2949   rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2950   rectIcon.top = pDIStruct->rcItem.top;
2951   rectIcon.right = rectIcon.left + ICONWIDTH;
2952   rectIcon.bottom = pDIStruct->rcItem.bottom;
2953 
2954   /* Initialise the text display area */
2955   GetTextMetricsW(pDIStruct->hDC, &tm);
2956   rectText.left = rectIcon.right;
2957   rectText.top =
2958           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2959   rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2960   rectText.bottom =
2961           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2962 
2963   /* Draw the icon from the image list */
2964   ImageList_Draw(ilItemImage,
2965                  sfi.iIcon,
2966                  pDIStruct->hDC,
2967                  rectIcon.left,
2968                  rectIcon.top,
2969                  ILD_TRANSPARENT );
2970 
2971   /* Draw the associated text */
2972   if(sfi.szDisplayName)
2973     TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2974 
2975 
2976   return NOERROR;
2977 }
2978 
2979 /***********************************************************************
2980  *      FILEDLG95_LOOKIN_OnCommand
2981  *
2982  * LookIn combo box WM_COMMAND message handler
2983  * If the function succeeds, the return value is nonzero.
2984  */
2985 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2986 {
2987   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2988 
2989   TRACE("%p\n", fodInfos);
2990 
2991   switch(wNotifyCode)
2992   {
2993     case CBN_SELENDOK:
2994     {
2995       LPSFOLDER tmpFolder;
2996       int iItem;
2997 
2998       iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2999 
3000       if( iItem == CB_ERR) return FALSE;
3001 
3002       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3003                                                iItem)))
3004         return FALSE;
3005 
3006 
3007       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3008                                               tmpFolder->pidlItem,
3009                                               SBSP_ABSOLUTE)))
3010       {
3011         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3012             SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3013         return TRUE;
3014       }
3015       break;
3016     }
3017 
3018   }
3019   return FALSE;
3020 }
3021 
3022 /***********************************************************************
3023  *      FILEDLG95_LOOKIN_AddItem
3024  *
3025  * Adds an absolute pidl item to the lookin combo box
3026  * returns the index of the inserted item
3027  */
3028 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3029 {
3030   LPITEMIDLIST pidlNext;
3031   SHFILEINFOW sfi;
3032   SFOLDER *tmpFolder;
3033   LookInInfos *liInfos;
3034 
3035   TRACE("%08x\n", iInsertId);
3036 
3037   if(!pidl)
3038     return -1;
3039 
3040   if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3041     return -1;
3042 
3043   tmpFolder = MemAlloc(sizeof(SFOLDER));
3044   tmpFolder->m_iIndent = 0;
3045 
3046   /* Calculate the indentation of the item in the lookin*/
3047   pidlNext = pidl;
3048   while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3049   {
3050     tmpFolder->m_iIndent++;
3051   }
3052 
3053   tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3054 
3055   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3056     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3057 
3058   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3059   SHGetFileInfoW((LPCWSTR)pidl,
3060                   0,
3061                   &sfi,
3062                   sizeof(sfi),
3063                   SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3064                   | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3065 
3066   TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3067 
3068   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3069   {
3070     int iItemID;
3071 
3072     TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3073 
3074     /* Add the item at the end of the list */
3075     if(iInsertId < 0)
3076     {
3077       iItemID = CBAddString(hwnd,sfi.szDisplayName);
3078     }
3079     /* Insert the item at the iInsertId position*/
3080     else
3081     {
3082       iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3083     }
3084 
3085     CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3086     return iItemID;
3087   }
3088 
3089   COMDLG32_SHFree( tmpFolder->pidlItem );
3090   MemFree( tmpFolder );
3091   return -1;
3092 
3093 }
3094 
3095 /***********************************************************************
3096  *      FILEDLG95_LOOKIN_InsertItemAfterParent
3097  *
3098  * Insert an item below its parent
3099  */
3100 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3101 {
3102 
3103   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3104   int iParentPos;
3105 
3106   TRACE("\n");
3107 
3108   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3109 
3110   if(iParentPos < 0)
3111   {
3112     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3113   }
3114 
3115   /* Free pidlParent memory */
3116   COMDLG32_SHFree(pidlParent);
3117 
3118   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3119 }
3120 
3121 /***********************************************************************
3122  *      FILEDLG95_LOOKIN_SelectItem
3123  *
3124  * Adds an absolute pidl item to the lookin combo box
3125  * returns the index of the inserted item
3126  */
3127 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3128 {
3129   int iItemPos;
3130   LookInInfos *liInfos;
3131 
3132   TRACE("\n");
3133 
3134   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3135 
3136   liInfos = GetPropA(hwnd,LookInInfosStr);
3137 
3138   if(iItemPos < 0)
3139   {
3140     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3141     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3142   }
3143 
3144   else
3145   {
3146     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3147     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3148     {
3149       int iRemovedItem;
3150 
3151       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3152         break;
3153       if(iRemovedItem < iItemPos)
3154         iItemPos--;
3155     }
3156   }
3157 
3158   CBSetCurSel(hwnd,iItemPos);
3159   liInfos->uSelectedItem = iItemPos;
3160 
3161   return 0;
3162 
3163 }
3164 
3165 /***********************************************************************
3166  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
3167  *
3168  * Remove the item with an expansion level over iExpansionLevel
3169  */
3170 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3171 {
3172   int iItemPos;
3173   LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3174 
3175   TRACE("\n");
3176 
3177   if(liInfos->iMaxIndentation <= 2)
3178     return -1;
3179 
3180   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3181   {
3182     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3183     COMDLG32_SHFree(tmpFolder->pidlItem);
3184     MemFree(tmpFolder);
3185     CBDeleteString(hwnd,iItemPos);
3186     liInfos->iMaxIndentation--;
3187 
3188     return iItemPos;
3189   }
3190 
3191   return -1;
3192 }
3193 
3194 /***********************************************************************
3195  *      FILEDLG95_LOOKIN_SearchItem
3196  *
3197  * Search for pidl in the lookin combo box
3198  * returns the index of the found item
3199  */
3200 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3201 {
3202   int i = 0;
3203   int iCount = CBGetCount(hwnd);
3204 
3205   TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3206 
3207   if (iCount != CB_ERR)
3208   {
3209     for(;i<iCount;i++)
3210     {
3211       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3212 
3213       if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3214         return i;
3215       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3216         return i;
3217     }
3218   }
3219 
3220   return -1;
3221 }
3222 
3223 /***********************************************************************
3224  *      FILEDLG95_LOOKIN_Clean
3225  *
3226  * Clean the memory used by the lookin combo box
3227  */
3228 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3229 {
3230     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3231     int iPos;
3232     int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3233 
3234     TRACE("\n");
3235 
3236     /* Delete each string of the combo and their associated data */
3237     if (iCount != CB_ERR)
3238     {
3239       for(iPos = iCount-1;iPos>=0;iPos--)
3240       {
3241         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3242         COMDLG32_SHFree(tmpFolder->pidlItem);
3243         MemFree(tmpFolder);
3244         CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3245       }
3246     }
3247 
3248     /* LookInInfos structure */
3249     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3250 
3251 }
3252 /***********************************************************************
3253  * FILEDLG95_FILENAME_FillFromSelection
3254  *
3255  * fills the edit box from the cached DataObject
3256  */
3257 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3258 {
3259     FileOpenDlgInfos *fodInfos;
3260     LPITEMIDLIST      pidl;
3261     UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3262     WCHAR             lpstrTemp[MAX_PATH];
3263     LPWSTR            lpstrAllFile, lpstrCurrFile;
3264 
3265     TRACE("\n");
3266     fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3267 
3268     /* Count how many files we have */
3269     nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3270 
3271     /* calculate the string length, count files */
3272     if (nFileSelected >= 1)
3273     {
3274       nLength += 3;     /* first and last quotes, trailing \0 */
3275       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3276       {
3277         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3278 
3279         if (pidl)
3280         {
3281           /* get the total length of the selected file names */
3282           lpstrTemp[0] = '\0';
3283           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3284 
3285           if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3286           {
3287             nLength += lstrlenW( lpstrTemp ) + 3;
3288             nFiles++;
3289           }
3290           COMDLG32_SHFree( pidl );
3291         }
3292       }
3293     }
3294 
3295     /* allocate the buffer */
3296     if (nFiles <= 1) nLength = MAX_PATH;
3297     lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3298 
3299     /* Generate the string for the edit control */
3300     if(nFiles >= 1)
3301     {
3302       lpstrCurrFile = lpstrAllFile;
3303       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3304       {
3305         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3306 
3307         if (pidl)
3308         {
3309           /* get the file name */
3310           lpstrTemp[0] = '\0';
3311           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3312 
3313           if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3314           {
3315             if ( nFiles > 1)
3316             {
3317               *lpstrCurrFile++ =  '\"';
3318               lstrcpyW( lpstrCurrFile, lpstrTemp );
3319               lpstrCurrFile += lstrlenW( lpstrTemp );
3320               *lpstrCurrFile++ = '\"';
3321               *lpstrCurrFile++ = ' ';
3322               *lpstrCurrFile = 0;
3323             }
3324             else
3325             {
3326               lstrcpyW( lpstrAllFile, lpstrTemp );
3327             }
3328           }
3329           COMDLG32_SHFree( pidl );
3330         }
3331       }
3332       SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3333        
3334       /* Select the file name like Windows does */ 
3335       SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3336     }
3337     HeapFree(GetProcessHeap(),0, lpstrAllFile );
3338 }
3339 
3340 
3341 /* copied from shell32 to avoid linking to it
3342  * Although shell32 is already linked the behaviour of exported StrRetToStrN
3343  * is dependent on whether emulated OS is unicode or not.
3344  */
3345 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3346 {
3347         switch (src->uType)
3348         {
3349           case STRRET_WSTR:
3350             lstrcpynW(dest, src->u.pOleStr, len);
3351             COMDLG32_SHFree(src->u.pOleStr);
3352             break;
3353 
3354           case STRRET_CSTR:
3355             if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3356                   dest[len-1] = 0;
3357             break;
3358 
3359           case STRRET_OFFSET:
3360             if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3361                   dest[len-1] = 0;
3362             break;
3363 
3364           default:
3365             FIXME("unknown type %x!\n", src->uType);
3366             if (len) *dest = '\0';
3367             return E_FAIL;
3368         }
3369         return S_OK;
3370 }
3371 
3372 /***********************************************************************
3373  * FILEDLG95_FILENAME_GetFileNames
3374  *
3375  * Copies the filenames to a delimited string list.
3376  * The delimiter is specified by the parameter 'separator',
3377  *  usually either a space or a nul
3378  */
3379 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3380 {
3381         FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3382         UINT nStrCharCount = 0; /* index in src buffer */
3383         UINT nFileIndex = 0;    /* index in dest buffer */
3384         UINT nFileCount = 0;    /* number of files */
3385         UINT nStrLen = 0;       /* length of string in edit control */
3386         LPWSTR lpstrEdit;       /* buffer for string from edit control */
3387 
3388         TRACE("\n");
3389 
3390         /* get the filenames from the edit control */
3391         nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3392         lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3393         GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3394 
3395         TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3396 
3397         /* we might get single filename without any '"',
3398          * so we need nStrLen + terminating \0 + end-of-list \0 */
3399         *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3400         *sizeUsed = 0;
3401 
3402         /* build delimited file list from filenames */
3403         while ( nStrCharCount <= nStrLen )
3404         {
3405           if ( lpstrEdit[nStrCharCount]=='"' )
3406           {
3407             nStrCharCount++;
3408             while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3409             {
3410               (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3411               nStrCharCount++;
3412             }
3413             (*lpstrFileList)[nFileIndex++] = 0;
3414             nFileCount++;
3415           }
3416           nStrCharCount++;
3417         }
3418 
3419         /* single, unquoted string */
3420         if ((nStrLen > 0) && (nFileIndex == 0) )
3421         {
3422           lstrcpyW(*lpstrFileList, lpstrEdit);
3423           nFileIndex = lstrlenW(lpstrEdit) + 1;
3424           nFileCount = 1;
3425         }
3426 
3427         /* trailing \0 */
3428         (*lpstrFileList)[nFileIndex++] = '\0';
3429 
3430         *sizeUsed = nFileIndex;
3431