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