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