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

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

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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