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

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

Version: ~ [ 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       return hChildDlg;
793     }
794     else if( IsHooked(fodInfos))
795     {
796       RECT rectHwnd;
797       struct  {
798          DLGTEMPLATE tmplate;
799          WORD menu,class,title;
800          } temp;
801       GetClientRect(hwnd,&rectHwnd);
802       temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
803       temp.tmplate.dwExtendedStyle = 0;
804       temp.tmplate.cdit = 0;
805       temp.tmplate.x = 0;
806       temp.tmplate.y = 0;
807       temp.tmplate.cx = 0;
808       temp.tmplate.cy = 0;
809       temp.menu = temp.class = temp.title = 0;
810 
811       hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
812                   hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
813 
814       return hChildDlg;
815     }
816     return NULL;
817 }
818 
819 /***********************************************************************
820 *          SendCustomDlgNotificationMessage
821 *
822 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
823 */
824 
825 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
826 {
827     LRESULT hook_result = 0;
828     FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
829 
830     TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
831 
832     if(!fodInfos) return 0;
833 
834     if(fodInfos->DlgInfos.hwndCustomDlg)
835     {
836         TRACE("CALL NOTIFY for %x\n", uCode);
837         if(fodInfos->unicode)
838         {
839             OFNOTIFYW ofnNotify;
840             ofnNotify.hdr.hwndFrom=hwndParentDlg;
841             ofnNotify.hdr.idFrom=0;
842             ofnNotify.hdr.code = uCode;
843             ofnNotify.lpOFN = fodInfos->ofnInfos;
844             ofnNotify.pszFile = NULL;
845             hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
846         }
847         else
848         {
849             OFNOTIFYA ofnNotify;
850             ofnNotify.hdr.hwndFrom=hwndParentDlg;
851             ofnNotify.hdr.idFrom=0;
852             ofnNotify.hdr.code = uCode;
853             ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
854             ofnNotify.pszFile = NULL;
855             hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
856         }
857         TRACE("RET NOTIFY\n");
858     }
859     TRACE("Retval: 0x%08lx\n", hook_result);
860     return hook_result;
861 }
862 
863 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
864 {
865     UINT len, total;
866     WCHAR *p, *buffer;
867     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
868 
869     TRACE("CDM_GETFILEPATH:\n");
870 
871     if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
872         return -1;
873 
874     /* get path and filenames */
875     len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
876     buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
877     COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
878     if (len)
879     {
880         p = buffer + strlenW(buffer);
881         *p++ = '\\';
882         SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
883     }
884     if (fodInfos->unicode)
885     {
886         total = strlenW( buffer) + 1;
887         if (result) lstrcpynW( result, buffer, size );
888         TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
889     }
890     else
891     {
892         total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
893         if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
894         TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
895     }
896     HeapFree( GetProcessHeap(), 0, buffer );
897     return total;
898 }
899 
900 /***********************************************************************
901 *         FILEDLG95_HandleCustomDialogMessages
902 *
903 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
904 */
905 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
906 {
907     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
908     WCHAR lpstrPath[MAX_PATH];
909     INT_PTR retval;
910 
911     if(!fodInfos) return FALSE;
912 
913     switch(uMsg)
914     {
915         case CDM_GETFILEPATH:
916             retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
917             break;
918 
919         case CDM_GETFOLDERPATH:
920             TRACE("CDM_GETFOLDERPATH:\n");
921             COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
922             if (lParam) 
923             {
924                 if (fodInfos->unicode)
925                     lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
926                 else
927                     WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1, 
928                                         (LPSTR)lParam, (int)wParam, NULL, NULL);
929             }        
930             retval = lstrlenW(lpstrPath);
931             break;
932 
933         case CDM_GETFOLDERIDLIST:
934             retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
935             if (retval <= wParam)
936                 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
937             break;
938 
939         case CDM_GETSPEC:
940             TRACE("CDM_GETSPEC:\n");
941             retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
942             if (lParam)
943             {
944                 if (fodInfos->unicode)
945                     SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
946                 else
947                     SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
948             }
949             break;
950 
951         case CDM_SETCONTROLTEXT:
952             TRACE("CDM_SETCONTROLTEXT:\n");
953             if ( lParam )
954             {
955                 if( fodInfos->unicode )
956                     SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
957                 else
958                     SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
959             }
960             retval = TRUE;
961             break;
962 
963         case CDM_HIDECONTROL:
964             /* MSDN states that it should fail for not OFN_EXPLORER case */
965             if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
966             {
967                 HWND control = GetDlgItem( hwnd, wParam );
968                 if (control) ShowWindow( control, SW_HIDE );
969                 retval = TRUE;
970             }
971             else retval = FALSE;
972             break;
973 
974         default:
975             if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
976                 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
977             return FALSE;
978     }
979     SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
980     return TRUE;
981 }
982 
983 /***********************************************************************
984  *          FILEDLG95_OnWMGetMMI
985  *
986  * WM_GETMINMAXINFO message handler for resizable dialogs
987  */
988 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
989 {
990     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
991     if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
992     if( fodInfos->initial_size.x || fodInfos->initial_size.y)
993     {
994         mmiptr->ptMinTrackSize = fodInfos->initial_size;
995     }
996     return TRUE;
997 }
998 
999 /***********************************************************************
1000  *          FILEDLG95_OnWMSize
1001  *
1002  * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1003  *
1004  * FIXME: this could be made more elaborate. Now use a simple scheme
1005  * where the file view is enlarged and the controls are either moved
1006  * vertically or horizontally to get out of the way. Only the "grip"
1007  * is moved in both directions to stay in the corner.
1008  */
1009 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1010 {
1011     RECT rc, rcview;
1012     int chgx, chgy;
1013     HWND ctrl;
1014     HDWP hdwp;
1015     FileOpenDlgInfos *fodInfos;
1016 
1017     if( wParam != SIZE_RESTORED) return FALSE;
1018     fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1019     if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1020     /* get the new dialog rectangle */
1021     GetWindowRect( hwnd, &rc);
1022     /* not initialized yet */
1023     if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1024         ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1025              (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1026         return FALSE;
1027     chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1028     chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1029     fodInfos->sizedlg.cx = rc.right - rc.left;
1030     fodInfos->sizedlg.cy = rc.bottom - rc.top;
1031     /* change the size of the view window */
1032     GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1033     MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1034     hdwp = BeginDeferWindowPos( 10);
1035     DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1036             rcview.right - rcview.left + chgx,
1037             rcview.bottom - rcview.top + chgy,
1038             SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1039     /* change position and sizes of the controls */
1040     for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1041     {
1042         GetWindowRect( ctrl, &rc);
1043         MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1044         if( ctrl == fodInfos->DlgInfos.hwndGrip)
1045         {
1046             DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1047                     0, 0,
1048                     SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1049         }
1050         else if( GetDlgCtrlID( ctrl) == IDC_SHELLSTATIC)
1051         {
1052             DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1053                     rc.right - rc.left + chgx,
1054                     rc.bottom - rc.top + chgy,
1055                     SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1056         }
1057         else if( rc.top > rcview.bottom)
1058         {
1059             /* if it was below the shell view
1060              * move to bottom */
1061             DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1062                     rc.right - rc.left, rc.bottom - rc.top,
1063                     SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1064         }
1065         else if( rc.left > rcview.right)
1066         {
1067             /* if it was to the right of the shell view
1068              * move to right */
1069             DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1070                     rc.right - rc.left, rc.bottom - rc.top,
1071                     SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1072         }
1073     }
1074     if(fodInfos->DlgInfos.hwndCustomDlg &&
1075         (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1076     {
1077         GetClientRect(hwnd, &rc);
1078         DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1079             0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1080         for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1081                 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1082         {
1083             GetWindowRect( ctrl, &rc);
1084             MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1085             if( rc.top > rcview.bottom)
1086             {
1087                 /* if it was below the shell view
1088                  * move to bottom */
1089                 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1090                         rc.right - rc.left, rc.bottom - rc.top,
1091                         SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1092             }
1093             else if( rc.left > rcview.right)
1094             {
1095                 /* if it was to the right of the shell view
1096                  * move to right */
1097                 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1098                         rc.right - rc.left, rc.bottom - rc.top,
1099                         SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1100             }
1101         }
1102     }
1103     EndDeferWindowPos( hdwp);
1104     /* should not be needed */
1105     RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1106     return TRUE;
1107 }
1108 
1109 /***********************************************************************
1110  *          FileOpenDlgProc95
1111  *
1112  * File open dialog procedure
1113  */
1114 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1115 {
1116 #if 0
1117   TRACE("%p 0x%04x\n", hwnd, uMsg);
1118 #endif
1119 
1120   switch(uMsg)
1121   {
1122     case WM_INITDIALOG:
1123       {
1124          FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1125          RECT rc;
1126          int gripx = GetSystemMetrics( SM_CYHSCROLL);
1127          int gripy = GetSystemMetrics( SM_CYVSCROLL);
1128 
1129          /* Adds the FileOpenDlgInfos in the property list of the dialog
1130             so it will be easily accessible through a GetPropA(...) */
1131          SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1132 
1133          FILEDLG95_InitControls(hwnd);
1134 
1135          if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1136          {
1137              GetWindowRect( hwnd, &rc);
1138              fodInfos->DlgInfos.hwndGrip =
1139                  CreateWindowExA( 0, "SCROLLBAR", NULL,
1140                      WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1141                      SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1142                      rc.right - gripx, rc.bottom - gripy,
1143                      gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1144          }
1145 
1146          fodInfos->DlgInfos.hwndCustomDlg =
1147            CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1148 
1149          FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1150          FILEDLG95_FillControls(hwnd, wParam, lParam);
1151 
1152          if( fodInfos->DlgInfos.hwndCustomDlg)
1153              ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1154 
1155          if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1156              SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1157 
1158          if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1159          {
1160              GetWindowRect( hwnd, &rc);
1161              /* FIXME: should remember sizes of last invocation */
1162              fodInfos->sizedlg.cx = rc.right - rc.left;
1163              fodInfos->sizedlg.cy = rc.bottom - rc.top;
1164              fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1165              fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1166              GetClientRect( hwnd, &rc);
1167              SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1168                      rc.right - gripx, rc.bottom - gripy,
1169                      0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1170          }
1171 
1172          if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1173          {
1174              SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1175              SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1176          }
1177          return 0;
1178        }
1179     case WM_SIZE:
1180       return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1181     case WM_GETMINMAXINFO:
1182       return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1183     case WM_COMMAND:
1184       return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1185     case WM_DRAWITEM:
1186       {
1187         switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1188         {
1189         case IDC_LOOKIN:
1190           FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1191           return TRUE;
1192         }
1193       }
1194       return FALSE;
1195 
1196     case WM_GETISHELLBROWSER:
1197       return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1198 
1199     case WM_DESTROY:
1200       RemovePropA(hwnd, FileOpenDlgInfosStr);
1201       return FALSE;
1202 
1203     case WM_NOTIFY:
1204     {
1205         LPNMHDR lpnmh = (LPNMHDR)lParam;
1206         UINT stringId = -1;
1207 
1208         /* set up the button tooltips strings */
1209         if(TTN_GETDISPINFOA == lpnmh->code )
1210         {
1211             LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1212             switch(lpnmh->idFrom )
1213             {
1214                 /* Up folder button */
1215                 case FCIDM_TB_UPFOLDER:
1216                     stringId = IDS_UPFOLDER;
1217                     break;
1218                 /* New folder button */
1219                 case FCIDM_TB_NEWFOLDER:
1220                     stringId = IDS_NEWFOLDER;
1221                     break;
1222                 /* List option button */
1223                 case FCIDM_TB_SMALLICON:
1224                     stringId = IDS_LISTVIEW;
1225                     break;
1226                 /* Details option button */
1227                 case FCIDM_TB_REPORTVIEW:
1228                     stringId = IDS_REPORTVIEW;
1229                     break;
1230                 /* Desktop button */
1231                 case FCIDM_TB_DESKTOP:
1232                     stringId = IDS_TODESKTOP;
1233                     break;
1234                 default:
1235                     stringId = 0;
1236             }
1237             lpdi->hinst = COMDLG32_hInstance;
1238             lpdi->lpszText =  MAKEINTRESOURCEA(stringId);
1239         }
1240         return FALSE;
1241     }
1242     default :
1243       if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1244         return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1245       return FALSE;
1246   }
1247 }
1248 
1249 /***********************************************************************
1250  *      FILEDLG95_InitControls
1251  *
1252  * WM_INITDIALOG message handler (before hook notification)
1253  */
1254 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1255 {
1256   int win2000plus = 0;
1257   int win98plus   = 0;
1258   int handledPath = FALSE;
1259   OSVERSIONINFOW osVi;
1260   static const WCHAR szwSlash[] = { '\\', 0 };
1261   static const WCHAR szwStar[] = { '*',0 };
1262 
1263   static const TBBUTTON tbb[] =
1264   {
1265    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1266    {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER,   TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1267    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1268    {VIEW_NEWFOLDER+1,  FCIDM_TB_DESKTOP,    TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1269    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1270    {VIEW_NEWFOLDER,    FCIDM_TB_NEWFOLDER,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1271    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1272    {VIEW_LIST,         FCIDM_TB_SMALLICON,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1273    {VIEW_DETAILS,      FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1274   };
1275   TBADDBITMAP tba[2];
1276   RECT rectTB;
1277   RECT rectlook;
1278   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1279 
1280   tba[0].hInst = HINST_COMMCTRL;
1281   tba[0].nID   = IDB_VIEW_SMALL_COLOR;
1282   tba[1].hInst = COMDLG32_hInstance;
1283   tba[1].nID   = 800;
1284 
1285   TRACE("%p\n", fodInfos);
1286 
1287   /* Get windows version emulating */
1288   osVi.dwOSVersionInfoSize = sizeof(osVi);
1289   GetVersionExW(&osVi);
1290   if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1291     win98plus   = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1292   } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1293     win2000plus = (osVi.dwMajorVersion > 4);
1294     if (win2000plus) win98plus = TRUE;
1295   }
1296   TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1297 
1298   /* Get the hwnd of the controls */
1299   fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1300   fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1301   fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1302 
1303   GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1304   MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1305 
1306   /* construct the toolbar */
1307   GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1308   MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1309 
1310   rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1311   rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1312   rectTB.left = rectlook.right;
1313   rectTB.top = rectlook.top-1;
1314 
1315   if (fodInfos->unicode)
1316       fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1317           WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1318           rectTB.left, rectTB.top,
1319           rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1320           hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1321   else
1322       fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1323           WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1324           rectTB.left, rectTB.top,
1325           rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1326           hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1327 
1328   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1329 
1330 /* FIXME: use TB_LOADIMAGES when implemented */
1331 /*  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1332   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1333   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1334 
1335   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1336   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1337 
1338   /* Set the window text with the text specified in the OPENFILENAME structure */
1339   if(fodInfos->title)
1340   {
1341       SetWindowTextW(hwnd,fodInfos->title);
1342   }
1343   else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1344   {
1345       WCHAR buf[16];
1346       LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1347       SetWindowTextW(hwnd, buf);
1348   }
1349 
1350   /* Initialise the file name edit control */
1351   handledPath = FALSE;
1352   TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1353 
1354   if(fodInfos->filename)
1355   {
1356       /* 1. If win2000 or higher and filename contains a path, use it
1357          in preference over the lpstrInitialDir                       */
1358       if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1359          WCHAR tmpBuf[MAX_PATH];
1360          WCHAR *nameBit;
1361          DWORD result;
1362 
1363          result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1364          if (result) {
1365 
1366             /* nameBit is always shorter than the original filename */
1367             lstrcpyW(fodInfos->filename,nameBit);
1368 
1369             *nameBit = 0x00;
1370             if (fodInfos->initdir == NULL)
1371                 MemFree(fodInfos->initdir);
1372             fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1373             lstrcpyW(fodInfos->initdir, tmpBuf);
1374             handledPath = TRUE;
1375             TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1376                     debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1377          }
1378          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1379 
1380       } else {
1381          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1382       }
1383   }
1384 
1385   /* 2. (All platforms) If initdir is not null, then use it */
1386   if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1387                                 (*fodInfos->initdir!=0x00))
1388   {
1389       /* Work out the proper path as supplied one might be relative          */
1390       /* (Here because supplying '.' as dir browses to My Computer)          */
1391       if (handledPath==FALSE) {
1392           WCHAR tmpBuf[MAX_PATH];
1393           WCHAR tmpBuf2[MAX_PATH];
1394           WCHAR *nameBit;
1395           DWORD result;
1396 
1397           lstrcpyW(tmpBuf, fodInfos->initdir);
1398           if( PathFileExistsW(tmpBuf) ) {
1399               /* initdir does not have to be a directory. If a file is
1400                * specified, the dir part is taken */
1401               if( PathIsDirectoryW(tmpBuf)) {
1402                   if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1403                      lstrcatW(tmpBuf, szwSlash);
1404                   }
1405                   lstrcatW(tmpBuf, szwStar);
1406               }
1407               result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1408               if (result) {
1409                  *nameBit = 0x00;
1410                  MemFree(fodInfos->initdir);
1411                  fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1412                  lstrcpyW(fodInfos->initdir, tmpBuf2);
1413                  handledPath = TRUE;
1414                  TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1415               }
1416           }
1417           else if (fodInfos->initdir)
1418           {
1419                     MemFree(fodInfos->initdir);
1420                     fodInfos->initdir = NULL;
1421                     TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1422           }
1423       }
1424   }
1425 
1426   if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1427                                  (*fodInfos->initdir==0x00)))
1428   {
1429       /* 3. All except w2k+: if filename contains a path use it */
1430       if (!win2000plus && fodInfos->filename &&
1431           *fodInfos->filename &&
1432           strpbrkW(fodInfos->filename, szwSlash)) {
1433          WCHAR tmpBuf[MAX_PATH];
1434          WCHAR *nameBit;
1435          DWORD result;
1436 
1437          result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1438                                   tmpBuf, &nameBit);
1439          if (result) {
1440             int len;
1441 
1442             /* nameBit is always shorter than the original filename */
1443             lstrcpyW(fodInfos->filename, nameBit);
1444             *nameBit = 0x00;
1445 
1446             len = lstrlenW(tmpBuf);
1447             MemFree(fodInfos->initdir);
1448             fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1449             lstrcpyW(fodInfos->initdir, tmpBuf);
1450 
1451             handledPath = TRUE;
1452             TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1453                  debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1454          }
1455          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1456       }
1457 
1458       /* 4. win98+ and win2000+ if any files of specified filter types in
1459             current directory, use it                                      */
1460       if ( win98plus && handledPath == FALSE &&
1461            fodInfos->filter && *fodInfos->filter) {
1462 
1463          BOOL   searchMore = TRUE;
1464          LPCWSTR lpstrPos = fodInfos->filter;
1465          WIN32_FIND_DATAW FindFileData;
1466          HANDLE hFind;
1467 
1468          while (searchMore)
1469          {
1470            /* filter is a list...  title\0ext\0......\0\0 */
1471 
1472            /* Skip the title */
1473            if(! *lpstrPos) break;       /* end */
1474            lpstrPos += lstrlenW(lpstrPos) + 1;
1475 
1476            /* See if any files exist in the current dir with this extension */
1477            if(! *lpstrPos) break;       /* end */
1478 
1479            hFind = FindFirstFileW(lpstrPos, &FindFileData);
1480 
1481            if (hFind == INVALID_HANDLE_VALUE) {
1482                /* None found - continue search */
1483                lpstrPos += lstrlenW(lpstrPos) + 1;
1484 
1485            } else {
1486                searchMore = FALSE;
1487 
1488                MemFree(fodInfos->initdir);
1489                fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1490                GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1491 
1492                handledPath = TRUE;
1493                TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1494                  debugstr_w(lpstrPos));
1495                break;
1496            }
1497          }
1498       }
1499 
1500       /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1501 
1502       /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1503       if (handledPath == FALSE && (win2000plus || win98plus)) {
1504           fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1505 
1506           if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1507           {
1508             if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1509             {
1510                 /* last fallback */
1511                 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1512                 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1513             } else {
1514                 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1515             }
1516           } else {
1517             TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1518           }
1519           handledPath = TRUE;
1520       } else if (handledPath==FALSE) {
1521           fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1522           GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1523           handledPath = TRUE;
1524           TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1525       }
1526   }
1527   SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1528   TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1529 
1530   /* Must the open as read only check box be checked ?*/
1531   if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1532   {
1533     SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1534   }
1535 
1536   /* Must the open as read only check box be hidden? */
1537   if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1538   {
1539     ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1540     EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1541   }
1542 
1543   /* Must the help button be hidden? */
1544   if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1545   {
1546     ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1547     EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1548   }
1549 
1550   /* change Open to Save */
1551   if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1552   {
1553       WCHAR buf[16];
1554       LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1555       SetDlgItemTextW(hwnd, IDOK, buf);
1556       LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1557       SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1558   }
1559 
1560   /* Initialize the filter combo box */
1561   FILEDLG95_FILETYPE_Init(hwnd);
1562 
1563   return 0;
1564 }
1565 
1566 /***********************************************************************
1567  *      FILEDLG95_ResizeControls
1568  *
1569  * WM_INITDIALOG message handler (after hook notification)
1570  */
1571 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1572 {
1573   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1574 
1575   if (fodInfos->DlgInfos.hwndCustomDlg)
1576   {
1577     RECT rc;
1578     UINT flags = SWP_NOACTIVATE;
1579 
1580     ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1581         (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1582 
1583     /* resize the custom dialog to the parent size */
1584     if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1585       GetClientRect(hwnd, &rc);
1586     else
1587     {
1588       /* our own fake template is zero sized and doesn't have children, so
1589        * there is no need to resize it. Picasa depends on it.
1590        */
1591       flags |= SWP_NOSIZE;
1592       SetRectEmpty(&rc);
1593     }
1594       SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1595           0, 0, rc.right, rc.bottom, flags);
1596   }
1597   else
1598   {
1599     /* Resize the height, if open as read only checkbox ad help button are
1600      * hidden and we are not using a custom template nor a customDialog
1601      */
1602     if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1603                 (!(fodInfos->ofnInfos->Flags &
1604                    (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1605     {
1606       RECT rectDlg, rectHelp, rectCancel;
1607       GetWindowRect(hwnd, &rectDlg);
1608       GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1609       GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1610       /* subtract the height of the help button plus the space between the help
1611        * button and the cancel button to the height of the dialog
1612        */
1613       SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1614           (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1615           SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1616     }
1617   }
1618   return TRUE;
1619 }
1620 
1621 /***********************************************************************
1622  *      FILEDLG95_FillControls
1623  *
1624  * WM_INITDIALOG message handler (after hook notification)
1625  */
1626 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1627 {
1628   LPITEMIDLIST pidlItemId = NULL;
1629 
1630   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1631 
1632   TRACE("dir=%s file=%s\n",
1633   debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1634 
1635   /* Get the initial directory pidl */
1636 
1637   if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1638   {
1639     WCHAR path[MAX_PATH];
1640 
1641     GetCurrentDirectoryW(MAX_PATH,path);
1642     pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1643   }
1644 
1645   /* Initialise shell objects */
1646   FILEDLG95_SHELL_Init(hwnd);
1647 
1648   /* Initialize the Look In combo box */
1649   FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1650 
1651   /* Browse to the initial directory */
1652   IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1653 
1654   /* Free pidlItem memory */
1655   COMDLG32_SHFree(pidlItemId);
1656 
1657   return TRUE;
1658 }
1659 /***********************************************************************
1660  *      FILEDLG95_Clean
1661  *
1662  * Regroups all the cleaning functions of the filedlg
1663  */
1664 void FILEDLG95_Clean(HWND hwnd)
1665 {
1666       FILEDLG95_FILETYPE_Clean(hwnd);
1667       FILEDLG95_LOOKIN_Clean(hwnd);
1668       FILEDLG95_SHELL_Clean(hwnd);
1669 }
1670 /***********************************************************************
1671  *      FILEDLG95_OnWMCommand
1672  *
1673  * WM_COMMAND message handler
1674  */
1675 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1676 {
1677   WORD wNotifyCode = HIWORD(wParam); /* notification code */
1678   WORD wID = LOWORD(wParam);         /* item, control, or accelerator identifier */
1679   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1680 
1681   switch(wID)
1682   {
1683     /* OK button */
1684   case IDOK:
1685     FILEDLG95_OnOpen(hwnd);
1686     break;
1687     /* Cancel button */
1688   case IDCANCEL:
1689     FILEDLG95_Clean(hwnd);
1690     EndDialog(hwnd, FALSE);
1691     break;
1692     /* Filetype combo box */
1693   case IDC_FILETYPE:
1694     FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1695     break;
1696     /* LookIn combo box */
1697   case IDC_LOOKIN:
1698     FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1699     break;
1700 
1701   /* --- toolbar --- */
1702     /* Up folder button */
1703   case FCIDM_TB_UPFOLDER:
1704     FILEDLG95_SHELL_UpFolder(hwnd);
1705     break;
1706     /* New folder button */
1707   case FCIDM_TB_NEWFOLDER:
1708     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1709     break;
1710     /* List option button */
1711   case FCIDM_TB_SMALLICON:
1712     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1713     break;
1714     /* Details option button */
1715   case FCIDM_TB_REPORTVIEW:
1716     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1717     break;
1718     /* Details option button */
1719   case FCIDM_TB_DESKTOP:
1720     FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1721     break;
1722 
1723   case IDC_FILENAME:
1724     break;
1725 
1726   }
1727   /* Do not use the listview selection anymore */
1728   fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1729   return 0;
1730 }
1731 
1732 /***********************************************************************
1733  *      FILEDLG95_OnWMGetIShellBrowser
1734  *
1735  * WM_GETISHELLBROWSER message handler
1736  */
1737 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1738 {
1739   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1740 
1741   TRACE("\n");
1742 
1743   SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1744 
1745   return TRUE;
1746 }
1747 
1748 
1749 /***********************************************************************
1750  *      FILEDLG95_SendFileOK
1751  *
1752  * Sends the CDN_FILEOK notification if required
1753  *
1754  * RETURNS
1755  *  TRUE if the dialog should close
1756  *  FALSE if the dialog should not be closed
1757  */
1758 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1759 {
1760     /* ask the hook if we can close */
1761     if(IsHooked(fodInfos))
1762     {
1763         LRESULT retval = 0;
1764 
1765         TRACE("---\n");
1766         /* First send CDN_FILEOK as MSDN doc says */
1767         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1768             retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1769         if( retval)
1770         {
1771             TRACE("canceled\n");
1772             return FALSE;
1773         }
1774 
1775         /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1776         retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1777                               fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1778         if( retval)
1779         {
1780             TRACE("canceled\n");
1781             return FALSE;
1782         }
1783     }
1784     return TRUE;
1785 }
1786 
1787 /***********************************************************************
1788  *      FILEDLG95_OnOpenMultipleFiles
1789  *
1790  * Handles the opening of multiple files.
1791  *
1792  * FIXME
1793  *  check destination buffer size
1794  */
1795 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1796 {
1797   WCHAR   lpstrPathSpec[MAX_PATH] = {0};
1798   UINT   nCount, nSizePath;
1799   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1800 
1801   TRACE("\n");
1802 
1803   if(fodInfos->unicode)
1804   {
1805      LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1806      ofn->lpstrFile[0] = '\0';
1807   }
1808   else
1809   {
1810      LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1811      ofn->lpstrFile[0] = '\0';
1812   }
1813 
1814   COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1815 
1816   if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1817       ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1818        ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1819   {
1820     LPWSTR lpstrTemp = lpstrFileList;
1821 
1822     for ( nCount = 0; nCount < nFileCount; nCount++ )
1823     {
1824       LPITEMIDLIST pidl;
1825 
1826       pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1827       if (!pidl)
1828       {
1829         WCHAR lpstrNotFound[100];
1830         WCHAR lpstrMsg[100];
1831         WCHAR tmp[400];
1832         static const WCHAR nl[] = {'\n',0};
1833 
1834         LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1835         LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1836 
1837         lstrcpyW(tmp, lpstrTemp);
1838         lstrcatW(tmp, nl);
1839         lstrcatW(tmp, lpstrNotFound);
1840         lstrcatW(tmp, nl);
1841         lstrcatW(tmp, lpstrMsg);
1842 
1843         MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1844         return FALSE;
1845       }
1846 
1847       /* move to the next file in the list of files */
1848       lpstrTemp += lstrlenW(lpstrTemp) + 1;
1849       COMDLG32_SHFree(pidl);
1850     }
1851   }
1852 
1853   nSizePath = lstrlenW(lpstrPathSpec) + 1;
1854   if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1855   {
1856     /* For "oldstyle" dialog the components have to
1857        be separated by blanks (not '\0'!) and short
1858        filenames have to be used! */
1859     FIXME("Components have to be separated by blanks\n");
1860   }
1861   if(fodInfos->unicode)
1862   {
1863     LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1864     lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1865     memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1866   }
1867   else
1868   {
1869     LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1870 
1871     if (ofn->lpstrFile != NULL)
1872     {
1873       nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1874                           ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1875       if (ofn->nMaxFile > nSizePath)
1876       {
1877         WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1878                             ofn->lpstrFile + nSizePath,
1879                             ofn->nMaxFile - nSizePath, NULL, NULL);
1880       }
1881     }
1882   }
1883 
1884   fodInfos->ofnInfos->nFileOffset = nSizePath;
1885   fodInfos->ofnInfos->nFileExtension = 0;
1886 
1887   if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1888     return FALSE;
1889 
1890   /* clean and exit */
1891   FILEDLG95_Clean(hwnd);
1892   return EndDialog(hwnd,TRUE);
1893 }
1894 
1895 /***********************************************************************
1896  *      FILEDLG95_OnOpen
1897  *
1898  * Ok button WM_COMMAND message handler
1899  *
1900  * If the function succeeds, the return value is nonzero.
1901  */
1902 #define ONOPEN_BROWSE 1
1903 #define ONOPEN_OPEN   2
1904 #define ONOPEN_SEARCH 3
1905 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1906 {
1907   WCHAR strMsgTitle[MAX_PATH];
1908   WCHAR strMsgText [MAX_PATH];
1909   if (idCaption)
1910     LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1911   else
1912     strMsgTitle[0] = '\0';
1913   LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1914   MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1915 }
1916 
1917 BOOL FILEDLG95_OnOpen(HWND hwnd)
1918 {
1919   LPWSTR lpstrFileList;
1920   UINT nFileCount = 0;
1921   UINT sizeUsed = 0;
1922   BOOL ret = TRUE;
1923   WCHAR lpstrPathAndFile[MAX_PATH];
1924   WCHAR lpstrTemp[MAX_PATH];
1925   LPSHELLFOLDER lpsf = NULL;
1926   int nOpenAction;
1927   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1928 
1929   TRACE("hwnd=%p\n", hwnd);
1930 
1931   /* get the files from the edit control */
1932   nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1933 
1934   /* try if the user selected a folder in the shellview */
1935   if(nFileCount == 0)
1936   {
1937       BrowseSelectedFolder(hwnd);
1938       return FALSE;
1939   }
1940 
1941   if(nFileCount > 1)
1942   {
1943       ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1944       goto ret;
1945   }
1946 
1947   TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1948 
1949 /*
1950   Step 1:  Build a complete path name from the current folder and
1951   the filename or path in the edit box.
1952   Special cases:
1953   - the path in the edit box is a root path
1954     (with or without drive letter)
1955   - the edit box contains ".." (or a path with ".." in it)
1956 */
1957 
1958   /* Get the current directory name */
1959   if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1960   {
1961     /* last fallback */
1962     GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1963   }
1964   PathAddBackslashW(lpstrPathAndFile);
1965 
1966   TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1967 
1968   /* if the user specified a fully qualified path use it */
1969   if(PathIsRelativeW(lpstrFileList))
1970   {
1971     lstrcatW(lpstrPathAndFile, lpstrFileList);
1972   }
1973   else
1974   {
1975     /* does the path have a drive letter? */
1976     if (PathGetDriveNumberW(lpstrFileList) == -1)
1977       lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1978     else
1979       lstrcpyW(lpstrPathAndFile, lpstrFileList);
1980   }
1981 
1982   /* resolve "." and ".." */
1983   PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1984   lstrcpyW(lpstrPathAndFile, lpstrTemp);
1985   TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1986 
1987   MemFree(lpstrFileList);
1988 
1989 /*
1990   Step 2: here we have a cleaned up path
1991 
1992   We have to parse the path step by step to see if we have to browse
1993   to a folder if the path points to a directory or the last
1994   valid element is a directory.
1995 
1996   valid variables:
1997     lpstrPathAndFile: cleaned up path
1998  */
1999 
2000   if (nFileCount &&
2001       (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2002       !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2003     nOpenAction = ONOPEN_OPEN;
2004   else
2005     nOpenAction = ONOPEN_BROWSE;
2006 
2007   /* don't apply any checks with OFN_NOVALIDATE */
2008   {
2009     LPWSTR lpszTemp, lpszTemp1;
2010     LPITEMIDLIST pidl = NULL;
2011     static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2012 
2013     /* check for invalid chars */
2014     if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2015     {
2016       FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2017       ret = FALSE;
2018       goto ret;
2019     }
2020 
2021     if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2022 
2023     lpszTemp1 = lpszTemp = lpstrPathAndFile;
2024     while (lpszTemp1)
2025     {
2026       LPSHELLFOLDER lpsfChild;
2027       WCHAR lpwstrTemp[MAX_PATH];
2028       DWORD dwEaten, dwAttributes;
2029       LPWSTR p;
2030 
2031       lstrcpyW(lpwstrTemp, lpszTemp);
2032       p = PathFindNextComponentW(lpwstrTemp);
2033 
2034       if (!p) break; /* end of path */
2035 
2036       *p = 0;
2037       lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2038 
2039       /* There are no wildcards when OFN_NOVALIDATE is set */
2040       if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2041       {
2042         static const WCHAR wszWild[] = { '*', '?', 0 };
2043         /* if the last element is a wildcard do a search */
2044         if(strpbrkW(lpszTemp1, wszWild) != NULL)
2045         {
2046           nOpenAction = ONOPEN_SEARCH;
2047           break;
2048         }
2049       }
2050       lpszTemp1 = lpszTemp;
2051 
2052       TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2053 
2054       /* append a backslash to drive letters */
2055       if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' && 
2056          ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2057           (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z'))) 
2058       {
2059         PathAddBackslashW(lpwstrTemp);
2060       }
2061 
2062       dwAttributes = SFGAO_FOLDER;
2063       if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2064       {
2065         /* the path component is valid, we have a pidl of the next path component */
2066         TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2067         if(dwAttributes & SFGAO_FOLDER)
2068         {
2069           if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2070           {
2071             ERR("bind to failed\n"); /* should not fail */
2072             break;
2073           }
2074           IShellFolder_Release(lpsf);
2075           lpsf = lpsfChild;
2076           lpsfChild = NULL;
2077         }
2078         else
2079         {
2080           TRACE("value\n");
2081 
2082           /* end dialog, return value */
2083           nOpenAction = ONOPEN_OPEN;
2084           break;
2085         }
2086         COMDLG32_SHFree(pidl);
2087         pidl = NULL;
2088       }
2089       else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2090       {
2091         if(*lpszTemp || /* points to trailing null for last path element */
2092            (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2093         {
2094           if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2095           {
2096             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2097             break;
2098           }
2099         }
2100         else
2101         {
2102           if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2103              !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2104           {
2105             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2106             break;
2107           }
2108         }
2109         /* change to the current folder */
2110         nOpenAction = ONOPEN_OPEN;
2111         break;
2112       }
2113       else
2114       {
2115         nOpenAction = ONOPEN_OPEN;
2116         break;
2117       }
2118     }
2119     if(pidl) COMDLG32_SHFree(pidl);
2120   }
2121 
2122 /*
2123   Step 3: here we have a cleaned up and validated path
2124 
2125   valid variables:
2126    lpsf:             ShellFolder bound to the rightmost valid path component
2127    lpstrPathAndFile: cleaned up path
2128    nOpenAction:      action to do
2129 */
2130   TRACE("end validate sf=%p\n", lpsf);
2131 
2132   switch(nOpenAction)
2133   {
2134     case ONOPEN_SEARCH:   /* set the current filter to the file mask and refresh */
2135       TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2136       {
2137         int iPos;
2138         LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2139         DWORD len;
2140 
2141         /* replace the current filter */
2142         MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2143         len = lstrlenW(lpszTemp)+1;
2144         fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2145         lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2146 
2147         /* set the filter cb to the extension when possible */
2148         if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2149         CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2150       }
2151       /* fall through */
2152     case ONOPEN_BROWSE:   /* browse to the highest folder we could bind to */
2153       TRACE("ONOPEN_BROWSE\n");
2154       {
2155         IPersistFolder2 * ppf2;
2156         if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2157         {
2158           LPITEMIDLIST pidlCurrent;
2159           IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2160           IPersistFolder2_Release(ppf2);
2161           if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2162           {
2163             if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2164                 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2165             {
2166               SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2167             }
2168           }
2169           else if( nOpenAction == ONOPEN_SEARCH )
2170           {
2171             if (fodInfos->Shell.FOIShellView)
2172               IShellView_Refresh(fodInfos->Shell.FOIShellView);
2173           }
2174           COMDLG32_SHFree(pidlCurrent);
2175           SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2176         }
2177       }
2178       ret = FALSE;
2179       break;
2180     case ONOPEN_OPEN:   /* fill in the return struct and close the dialog */
2181       TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2182       {
2183         WCHAR *ext = NULL;
2184 
2185         /* update READONLY check box flag */
2186         if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2187           fodInfos->ofnInfos->Flags |= OFN_READONLY;
2188         else
2189           fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2190 
2191         /* Attach the file extension with file name*/
2192         ext = PathFindExtensionW(lpstrPathAndFile);
2193         if (! *ext)
2194         {
2195             /* if no extension is specified with file name, then */
2196             /* attach the extension from file filter or default one */
2197             
2198             WCHAR *filterExt = NULL;
2199             LPWSTR lpstrFilter = NULL;
2200             static const WCHAR szwDot[] = {'.',0};
2201             int PathLength = lstrlenW(lpstrPathAndFile);
2202 
2203             /* Attach the dot*/
2204             lstrcatW(lpstrPathAndFile, szwDot);
2205     
2206             /*Get the file extension from file type filter*/
2207             lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2208                                              fodInfos->ofnInfos->nFilterIndex-1);
2209 
2210             if (lpstrFilter != (LPWSTR)CB_ERR)  /* control is not empty */
2211                 filterExt = PathFindExtensionW(lpstrFilter);
2212 
2213             if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2214                 lstrcatW(lpstrPathAndFile, filterExt + 1);
2215             else if ( fodInfos->defext ) /* attach the default file extension*/
2216                 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2217 
2218             /* In Open dialog: if file does not exist try without extension */
2219             if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2220                   lpstrPathAndFile[PathLength] = '\0';
2221         }
2222 
2223         if (fodInfos->defext) /* add default extension */
2224         {
2225           /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2226           if (*ext)
2227             ext++;
2228           if (!lstrcmpiW(fodInfos->defext, ext))
2229             fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2230           else
2231             fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2232         }
2233 
2234         /* In Save dialog: check if the file already exists */
2235         if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2236             && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2237             && PathFileExistsW(lpstrPathAndFile))
2238         {
2239           WCHAR lpstrOverwrite[100];
2240           int answer;
2241 
2242           LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2243           answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2244                                MB_YESNO | MB_ICONEXCLAMATION);
2245           if (answer == IDNO)
2246           {
2247             ret = FALSE;
2248             goto ret;
2249           }
2250         }
2251 
2252         /* In Open dialog: check if it should be created if it doesn't exist */
2253         if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2254             && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2255             && !PathFileExistsW(lpstrPathAndFile))
2256         {
2257           WCHAR lpstrCreate[100];
2258           int answer;
2259 
2260           LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2261           answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2262                                MB_YESNO | MB_ICONEXCLAMATION);
2263           if (answer == IDNO)
2264           {
2265             ret = FALSE;
2266             goto ret;
2267           }
2268         }
2269 
2270         /* Check that the size of the file does not exceed buffer size.
2271              (Allow for extra \0 if OFN_MULTISELECT is set.) */
2272         if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2273             ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2274         {
2275 
2276           /* fill destination buffer */
2277           if (fodInfos->ofnInfos->lpstrFile)
2278           {
2279              if(fodInfos->unicode)
2280              {
2281                LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2282 
2283                lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2284                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2285                  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2286              }
2287              else
2288              {
2289                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2290 
2291                WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2292                                    ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2293                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2294                  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2295              }
2296           }
2297 
2298           if(fodInfos->unicode)
2299           {
2300               LPWSTR lpszTemp;
2301 
2302               /* set filename offset */
2303               lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2304               fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2305 
2306               /* set extension offset */
2307               lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2308               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2309           }
2310           else
2311           {
2312                LPSTR lpszTemp;
2313                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2314 
2315               /* set filename offset */
2316               lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2317               fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2318 
2319               /* set extension offset */
2320               lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2321               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2322           }
2323 
2324           /* set the lpstrFileTitle */
2325           if(fodInfos->ofnInfos->lpstrFileTitle)
2326           {
2327             LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2328             if(fodInfos->unicode)
2329             {
2330               LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2331               lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2332             }
2333             else
2334             {
2335               LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2336               WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2337                     ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2338             }
2339           }
2340 
2341           /* copy currently selected filter to lpstrCustomFilter */
2342           if (fodInfos->ofnInfos->lpstrCustomFilter)
2343           {
2344             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2345             int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2346                                           NULL, 0, NULL, NULL);
2347             if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2348             {
2349               LPSTR s = ofn->lpstrCustomFilter;
2350               s += strlen(ofn->lpstrCustomFilter)+1;
2351               WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2352                                   s, len, NULL, NULL);
2353             }
2354           }
2355 
2356 
2357           if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2358               goto ret;
2359 
2360           TRACE("close\n");
2361           FILEDLG95_Clean(hwnd);
2362           ret = EndDialog(hwnd, TRUE);
2363         }
2364         else
2365         {
2366           WORD size;
2367 
2368           size = lstrlenW(lpstrPathAndFile) + 1;
2369           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2370              size += 1;
2371           /* return needed size in first two bytes of lpstrFile */
2372           *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2373           FILEDLG95_Clean(hwnd);
2374           ret = EndDialog(hwnd, FALSE);
2375           COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2376         }
2377       }
2378       break;
2379   }
2380 
2381 ret:
2382   if(lpsf) IShellFolder_Release(lpsf);
2383   return ret;
2384 }
2385 
2386 /***********************************************************************
2387  *      FILEDLG95_SHELL_Init
2388  *
2389  * Initialisation of the shell objects
2390  */
2391 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2392 {
2393   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2394 
2395   TRACE("\n");
2396 
2397   /*
2398    * Initialisation of the FileOpenDialogInfos structure
2399    */
2400 
2401   /* Shell */
2402 
2403   /*ShellInfos */
2404   fodInfos->ShellInfos.hwndOwner = hwnd;
2405 
2406   /* Disable multi-select if flag not set */
2407   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2408   {
2409      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2410   }
2411   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2412   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2413 
2414   /* Construct the IShellBrowser interface */
2415   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2416 
2417   return NOERROR;
2418 }
2419 
2420 /***********************************************************************
2421  *      FILEDLG95_SHELL_ExecuteCommand
2422  *
2423  * Change the folder option and refresh the view
2424  * If the function succeeds, the return value is nonzero.
2425  */
2426 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2427 {
2428   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2429   IContextMenu * pcm;
2430 
2431   TRACE("(%p,%p)\n", hwnd, lpVerb);
2432 
2433   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2434                                         SVGIO_BACKGROUND,
2435                                         &IID_IContextMenu,
2436                                         (LPVOID*)&pcm)))
2437   {
2438     CMINVOKECOMMANDINFO ci;
2439     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2440     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2441     ci.lpVerb = lpVerb;
2442     ci.hwnd = hwnd;
2443 
2444     IContextMenu_InvokeCommand(pcm, &ci);
2445     IContextMenu_Release(pcm);
2446   }
2447 
2448   return FALSE;
2449 }
2450 
2451 /***********************************************************************
2452  *      FILEDLG95_SHELL_UpFolder
2453  *
2454  * Browse to the specified object
2455  * If the function succeeds, the return value is nonzero.
2456  */
2457 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2458 {
2459   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2460 
2461   TRACE("\n");
2462 
2463   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2464                                           NULL,
2465                                           SBSP_PARENT)))
2466   {
2467     if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2468         SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2469     return TRUE;
2470   }
2471   return FALSE;
2472 }
2473 
2474 /***********************************************************************
2475  *      FILEDLG95_SHELL_BrowseToDesktop
2476  *
2477  * Browse to the Desktop
2478  * If the function succeeds, the return value is nonzero.
2479  */
2480 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2481 {
2482   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2483   LPITEMIDLIST pidl;
2484   HRESULT hres;
2485 
2486   TRACE("\n");
2487 
2488   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2489   hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2490   if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2491       SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2492   COMDLG32_SHFree(pidl);
2493   return SUCCEEDED(hres);
2494 }
2495 /***********************************************************************
2496  *      FILEDLG95_SHELL_Clean
2497  *
2498  * Cleans the memory used by shell objects
2499  */
2500 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2501 {
2502     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2503 
2504     TRACE("\n");
2505 
2506     COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2507 
2508     /* clean Shell interfaces */
2509     if (fodInfos->Shell.FOIShellView)
2510     {
2511       IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2512       IShellView_Release(fodInfos->Shell.FOIShellView);
2513     }
2514     IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2515     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2516     if (fodInfos->Shell.FOIDataObject)
2517       IDataObject_Release(fodInfos->Shell.FOIDataObject);
2518 }
2519 
2520 /***********************************************************************
2521  *      FILEDLG95_FILETYPE_Init
2522  *
2523  * Initialisation of the file type combo box
2524  */
2525 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2526 {
2527   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2528   int nFilters = 0;  /* number of filters */
2529   int nFilterIndexCB;
2530 
2531   TRACE("\n");
2532 
2533   if(fodInfos->customfilter)
2534   {
2535       /* customfilter has one entry...  title\0ext\0
2536        * Set first entry of combo box item with customfilter
2537        */
2538       LPWSTR  lpstrExt;
2539       LPCWSTR lpstrPos = fodInfos->customfilter;
2540 
2541       /* Get the title */
2542       lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2543 
2544       /* Copy the extensions */
2545       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
2546       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2547       lstrcpyW(lpstrExt,lpstrPos);
2548 
2549       /* Add the item at the end of the combo */
2550       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2551       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2552       nFilters++;
2553   }
2554   if(fodInfos->filter)
2555   {
2556     LPCWSTR lpstrPos = fodInfos->filter;
2557 
2558     for(;;)
2559     {
2560       /* filter is a list...  title\0ext\0......\0\0
2561        * Set the combo item text to the title and the item data
2562        *  to the ext
2563        */
2564       LPCWSTR lpstrDisplay;
2565       LPWSTR lpstrExt;
2566 
2567       /* Get the title */
2568       if(! *lpstrPos) break;    /* end */
2569       lpstrDisplay = lpstrPos;
2570       lpstrPos += lstrlenW(lpstrPos) + 1;
2571 
2572       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2573 
2574       nFilters++;
2575 
2576       /* Copy the extensions */
2577       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2578       lstrcpyW(lpstrExt,lpstrPos);
2579       lpstrPos += lstrlenW(lpstrPos) + 1;
2580 
2581       /* Add the item at the end of the combo */
2582       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2583 
2584       /* malformed filters are added anyway... */
2585       if (!*lpstrExt) break;
2586     }
2587   }
2588 
2589   /*
2590    * Set the current filter to the one specified
2591    * in the initialisation structure
2592    */
2593   if (fodInfos->filter || fodInfos->customfilter)
2594   {
2595     LPWSTR lpstrFilter;
2596 
2597     /* Check to make sure our index isn't out of bounds. */
2598     if ( fodInfos->ofnInfos->nFilterIndex >
2599          nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2600       fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2601 
2602     /* set default filter index */
2603     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2604       fodInfos->ofnInfos->nFilterIndex = 1;
2605 
2606     /* calculate index of Combo Box item */
2607     nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2608     if (fodInfos->customfilter == NULL)
2609       nFilterIndexCB--;
2610 
2611     /* Set the current index selection. */
2612     CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2613 
2614     /* Get the corresponding text string from the combo box. */
2615     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2616                                              nFilterIndexCB);
2617 
2618     if ((INT_PTR)lpstrFilter == CB_ERR)  /* control is empty */
2619       lpstrFilter = NULL;
2620 
2621     if(lpstrFilter)
2622     {
2623       DWORD len;
2624       CharLowerW(lpstrFilter); /* lowercase */
2625       len = lstrlenW(lpstrFilter)+1;
2626       fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2627       lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2628     }
2629   } else
2630       fodInfos->ofnInfos->nFilterIndex = 0;
2631   return S_OK;
2632 }
2633 
2634 /***********************************************************************
2635  *      FILEDLG95_FILETYPE_OnCommand
2636  *
2637  * WM_COMMAND of the file type combo box
2638  * If the function succeeds, the return value is nonzero.
2639  */
2640 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2641 {
2642   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2643 
2644   switch(wNotifyCode)
2645   {
2646     case CBN_SELENDOK:
2647     {
2648       LPWSTR lpstrFilter;
2649 
2650       /* Get the current item of the filetype combo box */
2651       int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2652 
2653       /* set the current filter index */
2654       fodInfos->ofnInfos->nFilterIndex = iItem +
2655         (fodInfos->customfilter == NULL ? 1 : 0);
2656 
2657       /* Set the current filter with the current selection */
2658       MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2659 
2660       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2661                                              iItem);
2662       if((INT_PTR)lpstrFilter != CB_ERR)
2663       {
2664           DWORD len;
2665           CharLowerW(lpstrFilter); /* lowercase */
2666           len = lstrlenW(lpstrFilter)+1;
2667           fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2668           lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2669           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2670               SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2671       }
2672 
2673       /* Refresh the actual view to display the included items*/
2674       if (fodInfos->Shell.FOIShellView)
2675         IShellView_Refresh(fodInfos->Shell.FOIShellView);
2676     }
2677   }
2678   return FALSE;
2679 }
2680 /***********************************************************************
2681  *      FILEDLG95_FILETYPE_SearchExt
2682  *
2683  * searches for an extension in the filetype box
2684  */
2685 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2686 {
2687   int i, iCount = CBGetCount(hwnd);
2688 
2689   TRACE("%s\n", debugstr_w(lpstrExt));
2690 
2691   if(iCount != CB_ERR)
2692   {
2693     for(i=0;i<iCount;i++)
2694     {
2695       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2696           return i;
2697     }
2698   }
2699   return -1;
2700 }
2701 
2702 /***********************************************************************
2703  *      FILEDLG95_FILETYPE_Clean
2704  *
2705  * Clean the memory used by the filetype combo box
2706  */
2707 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2708 {
2709   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2710   int iPos;
2711   int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2712 
2713   TRACE("\n");
2714 
2715   /* Delete each string of the combo and their associated data */
2716   if(iCount != CB_ERR)
2717   {
2718     for(iPos = iCount-1;iPos>=0;iPos--)
2719     {
2720       MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2721       CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2722     }
2723   }
2724   /* Current filter */
2725   MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2726 
2727 }
2728 
2729 /***********************************************************************
2730  *      FILEDLG95_LOOKIN_Init
2731  *
2732  * Initialisation of the look in combo box
2733  */
2734 
2735 /* Small helper function, to determine if the unixfs shell extension is rooted 
2736  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 
2737  */
2738 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2739     HKEY hKey;
2740     static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2741         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2742         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2743         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2744         'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','','A','A','E','8',
2745         '-','','6','2','5','-','4','4','B','','-','9','C','A','7','-',
2746         '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2747     
2748     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2749         return FALSE;
2750         
2751     RegCloseKey(hKey);
2752     return TRUE;
2753 }
2754 
2755 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2756 {
2757   IShellFolder  *psfRoot, *psfDrives;
2758   IEnumIDList   *lpeRoot, *lpeDrives;
2759   LPITEMIDLIST  pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2760 
2761   LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2762 
2763   TRACE("\n");
2764 
2765   liInfos->iMaxIndentation = 0;
2766 
2767   SetPropA(hwndCombo, LookInInfosStr, liInfos);
2768 
2769   /* set item height for both text field and listbox */
2770   CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2771   CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2772    
2773   /* Turn on the extended UI for the combo box like Windows does */
2774   CBSetExtendedUI(hwndCombo, TRUE);
2775 
2776   /* Initialise data of Desktop folder */
2777   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2778   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2779   COMDLG32_SHFree(pidlTmp);
2780 
2781   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2782 
2783   SHGetDesktopFolder(&psfRoot);
2784 
2785   if (psfRoot)
2786   {
2787     /* enumerate the contents of the desktop */
2788     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2789     {
2790       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2791       {
2792         FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2793 
2794         /* If the unixfs extension is rooted, we don't expand the drives by default */
2795         if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 
2796         {
2797           /* special handling for CSIDL_DRIVES */
2798           if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2799           {
2800             if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2801             {
2802               /* enumerate the drives */
2803               if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2804               {
2805                 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2806                 {
2807                   pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2808                   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2809                   COMDLG32_SHFree(pidlAbsTmp);
2810                   COMDLG32_SHFree(pidlTmp1);
2811                 }
2812                 IEnumIDList_Release(lpeDrives);
2813               }
2814               IShellFolder_Release(psfDrives);
2815             }
2816           }
2817         }
2818 
2819         COMDLG32_SHFree(pidlTmp);
2820       }
2821       IEnumIDList_Release(lpeRoot);
2822     }
2823     IShellFolder_Release(psfRoot);
2824   }
2825 
2826   COMDLG32_SHFree(pidlDrives);
2827 }
2828 
2829 /***********************************************************************
2830  *      FILEDLG95_LOOKIN_DrawItem
2831  *
2832  * WM_DRAWITEM message handler
2833  */
2834 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2835 {
2836   COLORREF crWin = GetSysColor(COLOR_WINDOW);
2837   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2838   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2839   RECT rectText;
2840   RECT rectIcon;
2841   SHFILEINFOW sfi;
2842   HIMAGELIST ilItemImage;
2843   int iIndentation;
2844   TEXTMETRICW tm;
2845   LPSFOLDER tmpFolder;
2846   LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2847 
2848   TRACE("\n");
2849 
2850   if(pDIStruct->itemID == -1)
2851     return 0;
2852 
2853   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2854                             pDIStruct->itemID)))
2855     return 0;
2856 
2857 
2858   if(pDIStruct->itemID == liInfos->uSelectedItem)
2859   {
2860     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2861                                                0,
2862                                                &sfi,
2863                                                sizeof (sfi),
2864                                                SHGFI_PIDL | SHGFI_SMALLICON |
2865                                                SHGFI_OPENICON | SHGFI_SYSICONINDEX    |
2866                                                SHGFI_DISPLAYNAME );
2867   }
2868   else
2869   {
2870     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2871                                                   0,
2872                                                   &sfi,
2873                                                   sizeof (sfi),
2874                                                   SHGFI_PIDL | SHGFI_SMALLICON |
2875                                                   SHGFI_SYSICONINDEX |
2876                                                   SHGFI_DISPLAYNAME);
2877   }
2878 
2879   /* Is this item selected ? */
2880   if(pDIStruct->itemState & ODS_SELECTED)
2881   {
2882     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2883     SetBkColor(pDIStruct->hDC,crHighLight);
2884     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2885   }
2886   else
2887   {
2888     SetTextColor(pDIStruct->hDC,crText);
2889     SetBkColor(pDIStruct->hDC,crWin);
2890     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2891   }
2892 
2893   /* Do not indent item if drawing in the edit of the combo */
2894   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2895   {
2896     iIndentation = 0;
2897     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2898                                                 0,
2899                                                 &sfi,
2900                                                 sizeof (sfi),
2901                                                 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2902                                                 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME  );
2903 
2904   }
2905   else
2906   {
2907     iIndentation = tmpFolder->m_iIndent;
2908   }
2909   /* Draw text and icon */
2910 
2911   /* Initialise the icon display area */
2912   rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2913   rectIcon.top = pDIStruct->rcItem.top;
2914   rectIcon.right = rectIcon.left + ICONWIDTH;
2915   rectIcon.bottom = pDIStruct->rcItem.bottom;
2916 
2917   /* Initialise the text display area */
2918   GetTextMetricsW(pDIStruct->hDC, &tm);
2919   rectText.left = rectIcon.right;
2920   rectText.top =
2921           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2922   rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2923   rectText.bottom =
2924           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2925 
2926   /* Draw the icon from the image list */
2927   ImageList_Draw(ilItemImage,
2928                  sfi.iIcon,
2929                  pDIStruct->hDC,
2930                  rectIcon.left,
2931                  rectIcon.top,
2932                  ILD_TRANSPARENT );
2933 
2934   /* Draw the associated text */
2935   if(sfi.szDisplayName)
2936     TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2937 
2938 
2939   return NOERROR;
2940 }
2941 
2942 /***********************************************************************
2943  *      FILEDLG95_LOOKIN_OnCommand
2944  *
2945  * LookIn combo box WM_COMMAND message handler
2946  * If the function succeeds, the return value is nonzero.
2947  */
2948 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2949 {
2950   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2951 
2952   TRACE("%p\n", fodInfos);
2953 
2954   switch(wNotifyCode)
2955   {
2956     case CBN_SELENDOK:
2957     {
2958       LPSFOLDER tmpFolder;
2959       int iItem;
2960 
2961       iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2962 
2963       if( iItem == CB_ERR) return FALSE;
2964 
2965       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2966                                                iItem)))
2967         return FALSE;
2968 
2969 
2970       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2971                                               tmpFolder->pidlItem,
2972                                               SBSP_ABSOLUTE)))
2973       {
2974         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2975             SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2976         return TRUE;
2977       }
2978       break;
2979     }
2980 
2981   }
2982   return FALSE;
2983 }
2984 
2985 /***********************************************************************
2986  *      FILEDLG95_LOOKIN_AddItem
2987  *
2988  * Adds an absolute pidl item to the lookin combo box
2989  * returns the index of the inserted item
2990  */
2991 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2992 {
2993   LPITEMIDLIST pidlNext;
2994   SHFILEINFOW sfi;
2995   SFOLDER *tmpFolder;
2996   LookInInfos *liInfos;
2997 
2998   TRACE("%08x\n", iInsertId);
2999 
3000   if(!pidl)
3001     return -1;
3002 
3003   if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3004     return -1;
3005 
3006   tmpFolder = MemAlloc(sizeof(SFOLDER));
3007   tmpFolder->m_iIndent = 0;
3008 
3009   /* Calculate the indentation of the item in the lookin*/
3010   pidlNext = pidl;
3011   while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3012   {
3013     tmpFolder->m_iIndent++;
3014   }
3015 
3016   tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3017 
3018   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3019     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3020 
3021   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3022   SHGetFileInfoW((LPCWSTR)pidl,
3023                   0,
3024                   &sfi,
3025                   sizeof(sfi),
3026                   SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3027                   | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3028 
3029   TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3030 
3031   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3032   {
3033     int iItemID;
3034 
3035     TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3036 
3037     /* Add the item at the end of the list */
3038     if(iInsertId < 0)
3039     {
3040       iItemID = CBAddString(hwnd,sfi.szDisplayName);
3041     }
3042     /* Insert the item at the iInsertId position*/
3043     else
3044     {
3045       iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3046     }
3047 
3048     CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3049     return iItemID;
3050   }
3051 
3052   COMDLG32_SHFree( tmpFolder->pidlItem );
3053   MemFree( tmpFolder );
3054   return -1;
3055 
3056 }
3057 
3058 /***********************************************************************
3059  *      FILEDLG95_LOOKIN_InsertItemAfterParent
3060  *
3061  * Insert an item below its parent
3062  */
3063 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3064 {
3065 
3066   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3067   int iParentPos;
3068 
3069   TRACE("\n");
3070 
3071   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3072 
3073   if(iParentPos < 0)
3074   {
3075     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3076   }
3077 
3078   /* Free pidlParent memory */
3079   COMDLG32_SHFree(pidlParent);
3080 
3081   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3082 }
3083 
3084 /***********************************************************************
3085  *      FILEDLG95_LOOKIN_SelectItem
3086  *
3087  * Adds an absolute pidl item to the lookin combo box
3088  * returns the index of the inserted item
3089  */
3090 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3091 {
3092   int iItemPos;
3093   LookInInfos *liInfos;
3094 
3095   TRACE("\n");
3096 
3097   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3098 
3099   liInfos = GetPropA(hwnd,LookInInfosStr);
3100 
3101   if(iItemPos < 0)
3102   {
3103     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3104     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3105   }
3106 
3107   else
3108   {
3109     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3110     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3111     {
3112       int iRemovedItem;
3113 
3114       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3115         break;
3116       if(iRemovedItem < iItemPos)
3117         iItemPos--;
3118     }
3119   }
3120 
3121   CBSetCurSel(hwnd,iItemPos);
3122   liInfos->uSelectedItem = iItemPos;
3123 
3124   return 0;
3125 
3126 }
3127 
3128 /***********************************************************************
3129  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
3130  *
3131  * Remove the item with an expansion level over iExpansionLevel
3132  */
3133 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3134 {
3135   int iItemPos;
3136   LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3137 
3138   TRACE("\n");
3139 
3140   if(liInfos->iMaxIndentation <= 2)
3141     return -1;
3142 
3143   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3144   {
3145     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3146     COMDLG32_SHFree(tmpFolder->pidlItem);
3147     MemFree(tmpFolder);
3148     CBDeleteString(hwnd,iItemPos);
3149     liInfos->iMaxIndentation--;
3150 
3151     return iItemPos;
3152   }
3153 
3154   return -1;
3155 }
3156 
3157 /***********************************************************************
3158  *      FILEDLG95_LOOKIN_SearchItem
3159  *
3160  * Search for pidl in the lookin combo box
3161  * returns the index of the found item
3162  */
3163 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3164 {
3165   int i = 0;
3166   int iCount = CBGetCount(hwnd);
3167 
3168   TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3169 
3170   if (iCount != CB_ERR)
3171   {
3172     for(;i<iCount;i++)
3173     {
3174       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3175 
3176       if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3177         return i;
3178       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3179         return i;
3180     }
3181   }
3182 
3183   return -1;
3184 }
3185 
3186 /***********************************************************************
3187  *      FILEDLG95_LOOKIN_Clean
3188  *
3189  * Clean the memory used by the lookin combo box
3190  */
3191 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3192 {
3193     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3194     int iPos;
3195     int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3196 
3197     TRACE("\n");
3198 
3199     /* Delete each string of the combo and their associated data */
3200     if (iCount != CB_ERR)
3201     {
3202       for(iPos = iCount-1;iPos>=0;iPos--)
3203       {
3204         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3205         COMDLG32_SHFree(tmpFolder->pidlItem);
3206         MemFree(tmpFolder);
3207         CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3208       }
3209     }
3210 
3211     /* LookInInfos structure */
3212     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3213 
3214 }
3215 /***********************************************************************
3216  * FILEDLG95_FILENAME_FillFromSelection
3217  *
3218  * fills the edit box from the cached DataObject
3219  */
3220 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3221 {
3222     FileOpenDlgInfos *fodInfos;
3223     LPITEMIDLIST      pidl;
3224     UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3225     WCHAR             lpstrTemp[MAX_PATH];
3226     LPWSTR            lpstrAllFile, lpstrCurrFile;
3227 
3228     TRACE("\n");
3229     fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3230 
3231     /* Count how many files we have */
3232     nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3233 
3234     /* calculate the string length, count files */
3235     if (nFileSelected >= 1)
3236     {
3237       nLength += 3;     /* first and last quotes, trailing \0 */
3238       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3239       {
3240         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3241 
3242         if (pidl)
3243         {
3244           /* get the total length of the selected file names */
3245           lpstrTemp[0] = '\0';
3246           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3247 
3248           if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3249           {
3250             nLength += lstrlenW( lpstrTemp ) + 3;
3251             nFiles++;
3252           }
3253           COMDLG32_SHFree( pidl );
3254         }
3255       }
3256     }
3257 
3258     /* allocate the buffer */
3259     if (nFiles <= 1) nLength = MAX_PATH;
3260     lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3261 
3262     /* Generate the string for the edit control */
3263     if(nFiles >= 1)
3264     {
3265       lpstrCurrFile = lpstrAllFile;
3266       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3267       {
3268         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3269 
3270         if (pidl)
3271         {
3272           /* get the file name */
3273           lpstrTemp[0] = '\0';
3274           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3275 
3276           if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3277           {
3278             if ( nFiles > 1)
3279             {
3280               *lpstrCurrFile++ =  '\"';
3281               lstrcpyW( lpstrCurrFile, lpstrTemp );
3282               lpstrCurrFile += lstrlenW( lpstrTemp );
3283               *lpstrCurrFile++ = '\"';
3284               *lpstrCurrFile++ = ' ';
3285               *lpstrCurrFile = 0;
3286             }
3287             else
3288             {
3289               lstrcpyW( lpstrAllFile, lpstrTemp );
3290             }
3291           }
3292           COMDLG32_SHFree( pidl );
3293         }
3294       }
3295       SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3296        
3297       /* Select the file name like Windows does */ 
3298       SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3299     }
3300     HeapFree(GetProcessHeap(),0, lpstrAllFile );
3301 }
3302 
3303 
3304 /* copied from shell32 to avoid linking to it
3305  * Although shell32 is already linked the behaviour of exported StrRetToStrN
3306  * is dependent on whether emulated OS is unicode or not.
3307  */
3308 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3309 {
3310         switch (src->uType)
3311         {
3312           case STRRET_WSTR:
3313             lstrcpynW(dest, src->u.pOleStr, len);
3314             COMDLG32_SHFree(src->u.pOleStr);
3315             break;
3316 
3317           case STRRET_CSTR:
3318             if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3319                   dest[len-1] = 0;
3320             break;
3321 
3322           case STRRET_OFFSET:
3323             if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3324                   dest[len-1] = 0;
3325             break;
3326 
3327           default:
3328             FIXME("unknown type %x!\n", src->uType);
3329             if (len) *dest = '\0';
3330             return E_FAIL;
3331         }
3332         return S_OK;
3333 }
3334 
3335 /***********************************************************************
3336  * FILEDLG95_FILENAME_GetFileNames
3337  *
3338  * Copies the filenames to a delimited string list.
3339  * The delimiter is specified by the parameter 'separator',
3340  *  usually either a space or a nul
3341  */
3342 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3343 {
3344         FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3345         UINT nStrCharCount = 0; /* index in src buffer */
3346         UINT nFileIndex = 0;    /* index in dest buffer */
3347         UINT nFileCount = 0;    /* number of files */
3348         UINT nStrLen = 0;       /* length of string in edit control */
3349         LPWSTR lpstrEdit;       /* buffer for string from edit control */
3350 
3351         TRACE("\n");
3352 
3353         /* get the filenames from the edit control */
3354         nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3355         lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3356         GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3357 
3358         TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3359 
3360         /* we might get single filename without any '"',
3361          * so we need nStrLen + terminating \0 + end-of-list \0 */
3362         *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3363         *sizeUsed = 0;
3364 
3365         /* build delimited file list from filenames */
3366         while ( nStrCharCount <= nStrLen )
3367         {
3368           if ( lpstrEdit[nStrCharCount]=='"' )
3369           {
3370             nStrCharCount++;
3371             while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3372             {
3373               (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3374               nStrCharCount++;
3375             }
3376             (*lpstrFileList)[nFileIndex++] = 0;
3377             nFileCount++;
3378           }
3379           nStrCharCount++;
3380         }
3381 
3382         /* single, unquoted string */
3383         if ((nStrLen > 0) && (nFileIndex == 0) )
3384         {
3385           lstrcpyW(*lpstrFileList, lpstrEdit);
3386           nFileIndex = lstrlenW(lpstrEdit) + 1;
3387           nFileCount = 1;
3388         }
3389 
3390         /* trailing \0 */
3391         (*lpstrFileList)[nFileIndex++] = '\0';
3392 
3393         *sizeUsed = nFileIndex;
3394         MemFree(lpstrEdit);
3395         return nFileCount;
3396 }
3397 
3398 #define SETDefFormatEtc(fe,cf,med) \
3399 { \
3400     (fe).cfFormat = cf;\
3401     (fe).dwAspect = DVASPECT_CONTENT; \
3402     (fe).ptd =NULL;\
3403     (fe).tymed = med;\
3404     (fe).lindex = -1;\
3405 };
3406 
3407 /*
3408  * DATAOBJECT Helper functions
3409  */
3410 
3411 /***********************************************************************
3412  * COMCTL32_ReleaseStgMedium
3413  *
3414  * like ReleaseStgMedium from ole32
3415  */
3416 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3417 {
3418       if(medium.pUnkForRelease)
3419       {
3420         IUnknown_Release(medium.pUnkForRelease);
3421       }
3422       else
3423       {
3424         GlobalUnlock(medium.u.hGlobal);
3425         GlobalFree(medium.u.hGlobal);
3426       }
3427 }
3428 
3429 /***********************************************************************
3430  *          GetPidlFromDataObject
3431  *
3432  * Return pidl(s) by number from the cached DataObject
3433  *
3434  * nPidlIndex=0 gets the fully qualified root path
3435  */
3436 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3437 {
3438 
3439     STGMEDIUM medium;
3440     FORMATETC formatetc;
3441     LPITEMIDLIST pidl = NULL;
3442 
3443     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3444 
3445     if (!doSelected)
3446         return NULL;
3447         
3448     /* Set the FORMATETC structure*/
3449     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3450 
3451     /* Get the pidls from IDataObject */
3452     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3453     {
3454       LPIDA cida = GlobalLock(medium.u.hGlobal);
3455       if(nPidlIndex <= cida->cidl)
3456       {
3457         pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3458       }
3459       COMCTL32_ReleaseStgMedium(medium);
3460     }
3461     return pidl;
3462 }
3463 
3464 /***********************************************************************
3465  *          GetNumSelected
3466  *
3467  * Return the number of selected items in the DataObject.
3468  *
3469 */
3470 static UINT GetNumSelected( IDataObject *doSelected )
3471 {
3472     UINT retVal = 0;
3473     STGMEDIUM medium;
3474     FORMATETC formatetc;
3475 
3476     TRACE("sv=%p\n", doSelected);
3477 
3478     if (!doSelected) return 0;
3479 
3480     /* Set the FORMATETC structure*/
3481     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3482 
3483     /* Get the pidls from IDataObject */
3484     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3485     {
3486       LPIDA cida = GlobalLock(medium.u.hGlobal);
3487       retVal = cida->cidl;
3488       COMCTL32_ReleaseStgMedium(medium);
3489       return retVal;
3490     }
3491     return 0;
3492 }
3493 
3494 /*
3495  * TOOLS
3496  */
3497 
3498 /***********************************************************************
3499  *      GetName
3500  *
3501  * Get the pidl's display name (relative to folder) and
3502  * put it in lpstrFileName.
3503  *
3504  * Return NOERROR on success,
3505  * E_FAIL otherwise
3506  */
3507 
3508 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3509 {
3510   STRRET str;
3511   HRESULT hRes;
3512 
3513   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3514 
3515   if(!lpsf)
3516   {
3517     SHGetDesktopFolder(&lpsf);
3518     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3519     IShellFolder_Release(lpsf);
3520     return hRes;
3521   }
3522 
3523   /* Get the display name of the pidl relative to the folder */
3524   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3525   {
3526       return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3527   }
3528   return E_FAIL;
3529 }
3530 
3531 /***********************************************************************
3532  *      GetShellFolderFromPidl
3533  *
3534  * pidlRel is the item pidl relative
3535  * Return the IShellFolder of the absolute pidl
3536  */
3537 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3538 {
3539   IShellFolder *psf = NULL,*psfParent;
3540 
3541   TRACE("%p\n", pidlAbs);
3542 
3543   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3544   {
3545     psf = psfParent;
3546     if(pidlAbs && pidlAbs->mkid.cb)
3547     {
3548       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3549       {
3550         IShellFolder_Release(psfParent);
3551         return psf;
3552       }
3553     }
3554     /* return the desktop */
3555     return psfParent;
3556   }
3557   return NULL;
3558 }
3559 
3560 /***********************************************************************
3561  *      GetParentPidl
3562  *
3563  * Return the LPITEMIDLIST to the parent of the pidl in the list
3564  */
3565 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3566 {
3567   LPITEMIDLIST pidlParent;
3568 
3569   TRACE("%p\n", pidl);
3570 
3571   pidlParent = COMDLG32_PIDL_ILClone(pidl);
3572   COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3573 
3574   return pidlParent;
3575 }
3576 
3577 /***********************************************************************
3578  *      GetPidlFromName
3579  *
3580  * returns the pidl of the file name relative to folder
3581  * NULL if an error occurred
3582  */
3583 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3584 {
3585   LPITEMIDLIST pidl = NULL;
3586   ULONG ulEaten;
3587 
3588   TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3589 
3590   if(!lpcstrFileName) return NULL;
3591   if(!*lpcstrFileName) return NULL;
3592 
3593   if(!lpsf)
3594   {
3595     if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3596         IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3597         IShellFolder_Release(lpsf);
3598     }
3599   }
3600   else
3601   {
3602     IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3603   }
3604   return pidl;
3605 }
3606 
3607 /*
3608 */
3609 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3610 {
3611         ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3612         HRESULT ret;
3613 
3614         TRACE("%p, %p\n", psf, pidl);
3615 
3616         ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3617 
3618         TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3619         /* see documentation shell 4.1*/
3620         return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3621 }
3622 
3623 /***********************************************************************
3624  *      BrowseSelectedFolder
3625  */
3626 static BOOL BrowseSelectedFolder(HWND hwnd)
3627 {
3628   BOOL bBrowseSelFolder = FALSE;
3629   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3630 
3631   TRACE("\n");
3632 
3633   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3634   {
3635       LPITEMIDLIST pidlSelection;
3636 
3637       /* get the file selected */
3638       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3639       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3640       {
3641           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3642                          pidlSelection, SBSP_RELATIVE ) ) )
3643           {
3644                static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3645                                    ' ','n','o','t',' ','e','x','i','s','t',0};
3646                MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3647           }
3648           bBrowseSelFolder = TRUE;
3649           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3650               SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3651       }
3652       COMDLG32_SHFree( pidlSelection );
3653   }
3654 
3655   return bBrowseSelFolder;
3656 }
3657 
3658 /*
3659  * Memory allocation methods */
3660 static void *MemAlloc(UINT size)
3661 {
3662     return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3663 }
3664 
3665 static void MemFree(void *mem)
3666 {
3667     HeapFree(GetProcessHeap(),0,mem);
3668 }
3669 
3670 /*
3671  * Old-style (win3.1) dialogs */
3672 
3673 /***********************************************************************
3674  *           FD32_GetTemplate                                  [internal]
3675  *
3676  * Get a template (or FALSE if failure) when 16 bits dialogs are used
3677  * by a 32 bits application
3678  *
3679  */
3680 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3681 {
3682     LPOPENFILENAMEW ofnW = lfs->ofnW;
3683     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3684     HANDLE hDlgTmpl;
3685 
3686     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3687     {
3688         if (!(lfs->template = LockResource( ofnW->hInstance )))
3689         {
3690             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3691             return FALSE;
3692         }
3693     }
3694     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3695     {
3696         HRSRC hResInfo;
3697         if (priv->ofnA)
3698             hResInfo = FindResourceA(priv->ofnA->hInstance,
3699                                  priv->ofnA->lpTemplateName,
3700                                  (LPSTR)RT_DIALOG);
3701         else
3702             hResInfo = FindResourceW(ofnW->hInstance,
3703                                  ofnW->lpTemplateName,
3704                                  (LPWSTR)RT_DIALOG);
3705         if (!hResInfo)
3706         {
3707             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3708             return FALSE;
3709         }
3710         if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3711                                 hResInfo)) ||
3712                     !(lfs->template = LockResource(hDlgTmpl)))
3713         {
3714             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3715             return FALSE;
3716         }
3717     } else { /* get it from internal Wine resource */
3718         HRSRC hResInfo;
3719         if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3720              lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3721         {
3722             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3723             return FALSE;
3724         }
3725         if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3726                 !(lfs->template = LockResource( hDlgTmpl )))
3727         {
3728             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3729             return FALSE;
3730         }
3731     }
3732     return TRUE;
3733 }
3734 
3735 
3736 /************************************************************************
3737  *                              FD32_Init          [internal]
3738  *      called from the common 16/32 code to initialize 32 bit data
3739  */
3740 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3741 {
3742     BOOL IsUnicode = (BOOL) data;
3743     PFD32_PRIVATE priv;
3744 
3745     priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3746     lfs->private1632 = priv;
3747     if (NULL == lfs->private1632) return FALSE;
3748     if (IsUnicode)
3749     {
3750         lfs->ofnW = (LPOPENFILENAMEW) lParam;
3751         if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3752             if (lfs->ofnW->lpfnHook)
3753                 lfs->hook = TRUE;
3754     }
3755     else
3756     {
3757         priv->ofnA = (LPOPENFILENAMEA) lParam;
3758         if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3759             if (priv->ofnA->lpfnHook)
3760                 lfs->hook = TRUE;
3761         lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3762         FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3763     }
3764 
3765     if (! FD32_GetTemplate(lfs)) return FALSE;
3766 
3767     return TRUE;
3768 }
3769 
3770 /***********************************************************************
3771  *                              FD32_CallWindowProc          [internal]
3772  *
3773  *      called from the common 16/32 code to call the appropriate hook
3774  */
3775 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3776                                  LPARAM lParam)
3777 {
3778     BOOL ret;
3779     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3780 
3781     if (priv->ofnA)
3782     {
3783         TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3784                priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3785         ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3786         TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3787                priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3788         return ret;
3789     }
3790 
3791     TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3792            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3793     ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3794     TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3795            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3796     return ret;
3797 }
3798 
3799 /***********************************************************************
3800  *                              FD32_UpdateResult            [internal]
3801  *          update the real client structures if any
3802  */
3803 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3804 {
3805     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3806     LPOPENFILENAMEW ofnW = lfs->ofnW;
3807 
3808     if (priv->ofnA)
3809     {
3810         LPSTR lpszTemp;
3811         if (ofnW->nMaxFile &&
3812             !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3813                                   priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3814             priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3815 
3816         /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3817         /* set filename offset */
3818         lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3819         priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3820 
3821         /* set extension offset */
3822         lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3823         priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3824     }
3825 }
3826 
3827 /***********************************************************************
3828  *                              FD32_UpdateFileTitle            [internal]
3829  *          update the real client structures if any
3830  */
3831 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3832 {
3833     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3834     LPOPENFILENAMEW ofnW = lfs->ofnW;
3835 
3836     if (priv->ofnA)
3837     {
3838         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3839                                   priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3840             priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3841     }
3842 }
3843 
3844 
3845 /***********************************************************************
3846  *                              FD32_SendLbGetCurSel         [internal]
3847  *          retrieve selected listbox item
3848  */
3849 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3850 {
3851     return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3852 }
3853 
3854 
3855 /************************************************************************
3856  *                              FD32_Destroy          [internal]
3857  *      called from the common 16/32 code to cleanup 32 bit data
3858  */
3859 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3860 {
3861     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3862 
3863     /* if ofnW has been allocated, have to free everything in it */
3864     if (NULL != priv && NULL != priv->ofnA)
3865     {
3866         FD31_FreeOfnW(lfs->ofnW);
3867         HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3868     }
3869 }
3870 
3871 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3872 {
3873     callbacks->Init = FD32_Init;
3874     callbacks->CWP = FD32_CallWindowProc;
3875     callbacks->UpdateResult = FD32_UpdateResult;
3876     callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3877     callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3878     callbacks->Destroy = FD32_Destroy;
3879 }
3880 
3881 /***********************************************************************
3882  *                              FD32_WMMeasureItem           [internal]
3883  */
3884 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3885 {
3886     LPMEASUREITEMSTRUCT lpmeasure;
3887 
3888     lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3889     lpmeasure->itemHeight = FD31_GetFldrHeight();
3890     return TRUE;
3891 }
3892 
3893 
3894 /***********************************************************************
3895  *           FileOpenDlgProc                                    [internal]
3896  *      Used for open and save, in fact.
3897  */
3898 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3899                                              WPARAM wParam, LPARAM lParam)
3900 {
3901     PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3902 
3903     TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3904     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3905         {
3906             INT_PTR lRet;
3907             lRet  = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3908             if (lRet)
3909                 return lRet;         /* else continue message processing */
3910         }
3911     switch (wMsg)
3912     {
3913     case WM_INITDIALOG:
3914         return FD31_WMInitDialog(hWnd, wParam, lParam);
3915 
3916     case WM_MEASUREITEM:
3917         return FD32_WMMeasureItem(hWnd, wParam, lParam);
3918 
3919     case WM_DRAWITEM:
3920         return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3921 
3922     case WM_COMMAND:
3923         return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3924 #if 0
3925     case WM_CTLCOLOR:
3926          SetBkColor((HDC16)wParam, 0x00C0C0C0);
3927          switch (HIWORD(lParam))
3928          {
3929          case CTLCOLOR_BTN:
3930              SetTextColor((HDC16)wParam, 0x00000000);
3931              return hGRAYBrush;
3932         case CTLCOLOR_STATIC:
3933              SetTextColor((HDC16)wParam, 0x00000000);
3934              return hGRAYBrush;
3935         }
3936       break;
3937 #endif
3938     }
3939     return FALSE;
3940 }
3941 
3942 
3943 /***********************************************************************
3944  *           GetFileName31A                                 [internal]
3945  *
3946  * Creates a win31 style dialog box for the user to select a file to open/save.
3947  */
3948 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3949                            UINT dlgType /* type dialogue : open/save */
3950                            )
3951 {
3952     HINSTANCE hInst;
3953     BOOL bRet = FALSE;
3954     PFD31_DATA lfs;
3955     FD31_CALLBACKS callbacks;
3956 
3957     if (!lpofn || !FD31_Init()) return FALSE;
3958 
3959     TRACE("ofn flags %08x\n", lpofn->Flags);
3960     FD32_SetupCallbacks(&callbacks);
3961     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3962     if (lfs)
3963     {
3964         hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3965         bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3966                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
3967         FD31_DestroyPrivate(lfs);
3968     }
3969 
3970     TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3971     return bRet;
3972 }
3973 
3974 /***********************************************************************
3975  *           GetFileName31W                                 [internal]
3976  *
3977  * Creates a win31 style dialog box for the user to select a file to open/save
3978  */
3979 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3980                            UINT dlgType /* type dialogue : open/save */
3981                            )
3982 {
3983     HINSTANCE hInst;
3984     BOOL bRet = FALSE;
3985     PFD31_DATA lfs;
3986     FD31_CALLBACKS callbacks;
3987 
3988     if (!lpofn || !FD31_Init()) return FALSE;
3989 
3990     FD32_SetupCallbacks(&callbacks);
3991     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3992     if (lfs)
3993     {
3994         hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3995         bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3996                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
3997         FD31_DestroyPrivate(lfs);
3998     }
3999 
4000     TRACE("file %s, file offset %d, ext offset %d\n",
4001           debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4002     return bRet;
4003 }
4004 
4005 /* ------------------ APIs ---------------------- */
4006 
4007 /***********************************************************************
4008  *            GetOpenFileNameA  (COMDLG32.@)
4009  *
4010  * Creates a dialog box for the user to select a file to open.
4011  *
4012  * RETURNS
4013  *    TRUE on success: user enters a valid file
4014  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4015  *
4016  */
4017 BOOL WINAPI GetOpenFileNameA(
4018         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4019 {
4020     BOOL win16look = FALSE;
4021 
4022     TRACE("flags %08x\n", ofn->Flags);
4023 
4024     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4025     if (ofn->Flags & OFN_FILEMUSTEXIST)
4026         ofn->Flags |= OFN_PATHMUSTEXIST;
4027 
4028     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4029         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4030 
4031     if (win16look)
4032         return GetFileName31A(ofn, OPEN_DIALOG);
4033     else
4034         return GetFileDialog95A(ofn, OPEN_DIALOG);
4035 }
4036 
4037 /***********************************************************************
4038  *            GetOpenFileNameW (COMDLG32.@)
4039  *
4040  * Creates a dialog box for the user to select a file to open.
4041  *
4042  * RETURNS
4043  *    TRUE on success: user enters a valid file
4044  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4045  *
4046  */
4047 BOOL WINAPI GetOpenFileNameW(
4048         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4049 {
4050     BOOL win16look = FALSE;
4051 
4052     TRACE("flags %08x\n", ofn->Flags);
4053 
4054     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4055     if (ofn->Flags & OFN_FILEMUSTEXIST)
4056         ofn->Flags |= OFN_PATHMUSTEXIST;
4057 
4058     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4059         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4060 
4061     if (win16look)
4062         return GetFileName31W(ofn, OPEN_DIALOG);
4063     else
4064         return GetFileDialog95W(ofn, OPEN_DIALOG);
4065 }
4066 
4067 
4068 /***********************************************************************
4069  *            GetSaveFileNameA  (COMDLG32.@)
4070  *
4071  * Creates a dialog box for the user to select a file to save.
4072  *
4073  * RETURNS
4074  *    TRUE on success: user enters a valid file
4075  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4076  *
4077  */
4078 BOOL WINAPI GetSaveFileNameA(
4079         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4080 {
4081     BOOL win16look = FALSE;
4082 
4083     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4084         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4085 
4086     if (win16look)
4087         return GetFileName31A(ofn, SAVE_DIALOG);
4088     else
4089         return GetFileDialog95A(ofn, SAVE_DIALOG);
4090 }
4091 
4092 /***********************************************************************
4093  *            GetSaveFileNameW  (COMDLG32.@)
4094  *
4095  * Creates a dialog box for the user to select a file to save.
4096  *
4097  * RETURNS
4098  *    TRUE on success: user enters a valid file
4099  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4100  *
4101  */
4102 BOOL WINAPI GetSaveFileNameW(
4103         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4104 {
4105     BOOL win16look = FALSE;
4106 
4107     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4108         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4109 
4110     if (win16look)
4111         return GetFileName31W(ofn, SAVE_DIALOG);
4112     else
4113         return