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