~ [ 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                                      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, 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(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       }
2209       break;
2210   }
2211 
2212 ret:
2213   if(lpsf) IShellFolder_Release(lpsf);
2214   return ret;
2215 }
2216 
2217 /***********************************************************************
2218  *      FILEDLG95_SHELL_Init
2219  *
2220  * Initialisation of the shell objects
2221  */
2222 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2223 {
2224   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2225 
2226   TRACE("\n");
2227 
2228   /*
2229    * Initialisation of the FileOpenDialogInfos structure
2230    */
2231 
2232   /* Shell */
2233 
2234   /*ShellInfos */
2235   fodInfos->ShellInfos.hwndOwner = hwnd;
2236 
2237   /* Disable multi-select if flag not set */
2238   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2239   {
2240      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2241   }
2242   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2243   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2244 
2245   /* Construct the IShellBrowser interface */
2246   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2247 
2248   return NOERROR;
2249 }
2250 
2251 /***********************************************************************
2252  *      FILEDLG95_SHELL_ExecuteCommand
2253  *
2254  * Change the folder option and refresh the view
2255  * If the function succeeds, the return value is nonzero.
2256  */
2257 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2258 {
2259   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2260   IContextMenu * pcm;
2261 
2262   TRACE("(%p,%p)\n", hwnd, lpVerb);
2263 
2264   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2265                                         SVGIO_BACKGROUND,
2266                                         &IID_IContextMenu,
2267                                         (LPVOID*)&pcm)))
2268   {
2269     CMINVOKECOMMANDINFO ci;
2270     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2271     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2272     ci.lpVerb = lpVerb;
2273     ci.hwnd = hwnd;
2274 
2275     IContextMenu_InvokeCommand(pcm, &ci);
2276     IContextMenu_Release(pcm);
2277   }
2278 
2279   return FALSE;
2280 }
2281 
2282 /***********************************************************************
2283  *      FILEDLG95_SHELL_UpFolder
2284  *
2285  * Browse to the specified object
2286  * If the function succeeds, the return value is nonzero.
2287  */
2288 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2289 {
2290   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2291 
2292   TRACE("\n");
2293 
2294   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2295                                           NULL,
2296                                           SBSP_PARENT)))
2297   {
2298     SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2299     return TRUE;
2300   }
2301   return FALSE;
2302 }
2303 
2304 /***********************************************************************
2305  *      FILEDLG95_SHELL_BrowseToDesktop
2306  *
2307  * Browse to the Desktop
2308  * If the function succeeds, the return value is nonzero.
2309  */
2310 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2311 {
2312   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2313   LPITEMIDLIST pidl;
2314   HRESULT hres;
2315 
2316   TRACE("\n");
2317 
2318   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2319   hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2320   SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2321   COMDLG32_SHFree(pidl);
2322   return SUCCEEDED(hres);
2323 }
2324 /***********************************************************************
2325  *      FILEDLG95_SHELL_Clean
2326  *
2327  * Cleans the memory used by shell objects
2328  */
2329 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2330 {
2331     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2332 
2333     TRACE("\n");
2334 
2335     COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2336 
2337     /* clean Shell interfaces */
2338     if (fodInfos->Shell.FOIShellView)
2339     {
2340       IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2341       IShellView_Release(fodInfos->Shell.FOIShellView);
2342     }
2343     IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2344     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2345     if (fodInfos->Shell.FOIDataObject)
2346       IDataObject_Release(fodInfos->Shell.FOIDataObject);
2347 }
2348 
2349 /***********************************************************************
2350  *      FILEDLG95_FILETYPE_Init
2351  *
2352  * Initialisation of the file type combo box
2353  */
2354 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2355 {
2356   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2357   int nFilters = 0;  /* number of filters */
2358   int nFilterIndexCB;
2359 
2360   TRACE("\n");
2361 
2362   if(fodInfos->customfilter)
2363   {
2364       /* customfilter has one entry...  title\0ext\0
2365        * Set first entry of combo box item with customfilter
2366        */
2367       LPWSTR  lpstrExt;
2368       LPCWSTR lpstrPos = fodInfos->customfilter;
2369 
2370       /* Get the title */
2371       lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2372 
2373       /* Copy the extensions */
2374       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
2375       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2376       lstrcpyW(lpstrExt,lpstrPos);
2377 
2378       /* Add the item at the end of the combo */
2379       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2380       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2381       nFilters++;
2382   }
2383   if(fodInfos->filter)
2384   {
2385     LPCWSTR lpstrPos = fodInfos->filter;
2386 
2387     for(;;)
2388     {
2389       /* filter is a list...  title\0ext\0......\0\0
2390        * Set the combo item text to the title and the item data
2391        *  to the ext
2392        */
2393       LPCWSTR lpstrDisplay;
2394       LPWSTR lpstrExt;
2395 
2396       /* Get the title */
2397       if(! *lpstrPos) break;    /* end */
2398       lpstrDisplay = lpstrPos;
2399       lpstrPos += lstrlenW(lpstrPos) + 1;
2400 
2401       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2402 
2403       nFilters++;
2404 
2405       /* Copy the extensions */
2406       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2407       lstrcpyW(lpstrExt,lpstrPos);
2408       lpstrPos += lstrlenW(lpstrPos) + 1;
2409 
2410       /* Add the item at the end of the combo */
2411       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2412 
2413       /* malformed filters are added anyway... */
2414       if (!*lpstrExt) break;
2415     }
2416   }
2417 
2418   /*
2419    * Set the current filter to the one specified
2420    * in the initialisation structure
2421    */
2422   if (fodInfos->filter || fodInfos->customfilter)
2423   {
2424     LPWSTR lpstrFilter;
2425 
2426     /* Check to make sure our index isn't out of bounds. */
2427     if ( fodInfos->ofnInfos->nFilterIndex >
2428          nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2429       fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2430 
2431     /* set default filter index */
2432     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2433       fodInfos->ofnInfos->nFilterIndex = 1;
2434 
2435     /* calculate index of Combo Box item */
2436     nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2437     if (fodInfos->customfilter == NULL)
2438       nFilterIndexCB--;
2439 
2440     /* Set the current index selection. */
2441     CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2442 
2443     /* Get the corresponding text string from the combo box. */
2444     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2445                                              nFilterIndexCB);
2446 
2447     if ((INT_PTR)lpstrFilter == CB_ERR)  /* control is empty */
2448       lpstrFilter = NULL;
2449 
2450     if(lpstrFilter)
2451     {
2452       DWORD len;
2453       CharLowerW(lpstrFilter); /* lowercase */
2454       len = lstrlenW(lpstrFilter)+1;
2455       fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2456       lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2457     }
2458   } else
2459       fodInfos->ofnInfos->nFilterIndex = 0;
2460   return S_OK;
2461 }
2462 
2463 /***********************************************************************
2464  *      FILEDLG95_FILETYPE_OnCommand
2465  *
2466  * WM_COMMAND of the file type combo box
2467  * If the function succeeds, the return value is nonzero.
2468  */
2469 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2470 {
2471   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2472 
2473   switch(wNotifyCode)
2474   {
2475     case CBN_SELENDOK:
2476     {
2477       LPWSTR lpstrFilter;
2478 
2479       /* Get the current item of the filetype combo box */
2480       int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2481 
2482       /* set the current filter index */
2483       fodInfos->ofnInfos->nFilterIndex = iItem +
2484         (fodInfos->customfilter == NULL ? 1 : 0);
2485 
2486       /* Set the current filter with the current selection */
2487       MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2488 
2489       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2490                                              iItem);
2491       if((INT_PTR)lpstrFilter != CB_ERR)
2492       {
2493           DWORD len;
2494           CharLowerW(lpstrFilter); /* lowercase */
2495           len = lstrlenW(lpstrFilter)+1;
2496           fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2497           lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2498           SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2499       }
2500 
2501       /* Refresh the actual view to display the included items*/
2502       if (fodInfos->Shell.FOIShellView)
2503         IShellView_Refresh(fodInfos->Shell.FOIShellView);
2504     }
2505   }
2506   return FALSE;
2507 }
2508 /***********************************************************************
2509  *      FILEDLG95_FILETYPE_SearchExt
2510  *
2511  * searches for an extension in the filetype box
2512  */
2513 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2514 {
2515   int i, iCount = CBGetCount(hwnd);
2516 
2517   TRACE("%s\n", debugstr_w(lpstrExt));
2518 
2519   if(iCount != CB_ERR)
2520   {
2521     for(i=0;i<iCount;i++)
2522     {
2523       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2524           return i;
2525     }
2526   }
2527   return -1;
2528 }
2529 
2530 /***********************************************************************
2531  *      FILEDLG95_FILETYPE_Clean
2532  *
2533  * Clean the memory used by the filetype combo box
2534  */
2535 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2536 {
2537   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2538   int iPos;
2539   int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2540 
2541   TRACE("\n");
2542 
2543   /* Delete each string of the combo and their associated data */
2544   if(iCount != CB_ERR)
2545   {
2546     for(iPos = iCount-1;iPos>=0;iPos--)
2547     {
2548       MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2549       CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2550     }
2551   }
2552   /* Current filter */
2553   MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2554 
2555 }
2556 
2557 /***********************************************************************
2558  *      FILEDLG95_LOOKIN_Init
2559  *
2560  * Initialisation of the look in combo box
2561  */
2562 
2563 /* Small helper function, to determine if the unixfs shell extension is rooted 
2564  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 
2565  */
2566 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2567     HKEY hKey;
2568     static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2569         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2570         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2571         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2572         'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','','A','A','E','8',
2573         '-','','6','2','5','-','4','4','B','','-','9','C','A','7','-',
2574         '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2575     
2576     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2577         return FALSE;
2578         
2579     RegCloseKey(hKey);
2580     return TRUE;
2581 }
2582 
2583 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2584 {
2585   IShellFolder  *psfRoot, *psfDrives;
2586   IEnumIDList   *lpeRoot, *lpeDrives;
2587   LPITEMIDLIST  pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2588 
2589   LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2590 
2591   TRACE("\n");
2592 
2593   liInfos->iMaxIndentation = 0;
2594 
2595   SetPropA(hwndCombo, LookInInfosStr, liInfos);
2596 
2597   /* set item height for both text field and listbox */
2598   CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2599   CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2600    
2601   /* Turn on the extended UI for the combo box like Windows does */
2602   CBSetExtendedUI(hwndCombo, TRUE);
2603 
2604   /* Initialise data of Desktop folder */
2605   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2606   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2607   COMDLG32_SHFree(pidlTmp);
2608 
2609   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2610 
2611   SHGetDesktopFolder(&psfRoot);
2612 
2613   if (psfRoot)
2614   {
2615     /* enumerate the contents of the desktop */
2616     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2617     {
2618       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2619       {
2620         FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2621 
2622         /* If the unixfs extension is rooted, we don't expand the drives by default */
2623         if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 
2624         {
2625           /* special handling for CSIDL_DRIVES */
2626           if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2627           {
2628             if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2629             {
2630               /* enumerate the drives */
2631               if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2632               {
2633                 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2634                 {
2635                   pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2636                   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2637                   COMDLG32_SHFree(pidlAbsTmp);
2638                   COMDLG32_SHFree(pidlTmp1);
2639                 }
2640                 IEnumIDList_Release(lpeDrives);
2641               }
2642               IShellFolder_Release(psfDrives);
2643             }
2644           }
2645         }
2646 
2647         COMDLG32_SHFree(pidlTmp);
2648       }
2649       IEnumIDList_Release(lpeRoot);
2650     }
2651     IShellFolder_Release(psfRoot);
2652   }
2653 
2654   COMDLG32_SHFree(pidlDrives);
2655 }
2656 
2657 /***********************************************************************
2658  *      FILEDLG95_LOOKIN_DrawItem
2659  *
2660  * WM_DRAWITEM message handler
2661  */
2662 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2663 {
2664   COLORREF crWin = GetSysColor(COLOR_WINDOW);
2665   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2666   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2667   RECT rectText;
2668   RECT rectIcon;
2669   SHFILEINFOW sfi;
2670   HIMAGELIST ilItemImage;
2671   int iIndentation;
2672   TEXTMETRICW tm;
2673   LPSFOLDER tmpFolder;
2674   LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2675 
2676   TRACE("\n");
2677 
2678   if(pDIStruct->itemID == -1)
2679     return 0;
2680 
2681   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2682                             pDIStruct->itemID)))
2683     return 0;
2684 
2685 
2686   if(pDIStruct->itemID == liInfos->uSelectedItem)
2687   {
2688     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2689                                                0,
2690                                                &sfi,
2691                                                sizeof (sfi),
2692                                                SHGFI_PIDL | SHGFI_SMALLICON |
2693                                                SHGFI_OPENICON | SHGFI_SYSICONINDEX    |
2694                                                SHGFI_DISPLAYNAME );
2695   }
2696   else
2697   {
2698     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2699                                                   0,
2700                                                   &sfi,
2701                                                   sizeof (sfi),
2702                                                   SHGFI_PIDL | SHGFI_SMALLICON |
2703                                                   SHGFI_SYSICONINDEX |
2704                                                   SHGFI_DISPLAYNAME);
2705   }
2706 
2707   /* Is this item selected ? */
2708   if(pDIStruct->itemState & ODS_SELECTED)
2709   {
2710     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2711     SetBkColor(pDIStruct->hDC,crHighLight);
2712     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2713   }
2714   else
2715   {
2716     SetTextColor(pDIStruct->hDC,crText);
2717     SetBkColor(pDIStruct->hDC,crWin);
2718     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2719   }
2720 
2721   /* Do not indent item if drawing in the edit of the combo */
2722   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2723   {
2724     iIndentation = 0;
2725     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2726                                                 0,
2727                                                 &sfi,
2728                                                 sizeof (sfi),
2729                                                 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2730                                                 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME  );
2731 
2732   }
2733   else
2734   {
2735     iIndentation = tmpFolder->m_iIndent;
2736   }
2737   /* Draw text and icon */
2738 
2739   /* Initialise the icon display area */
2740   rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2741   rectIcon.top = pDIStruct->rcItem.top;
2742   rectIcon.right = rectIcon.left + ICONWIDTH;
2743   rectIcon.bottom = pDIStruct->rcItem.bottom;
2744 
2745   /* Initialise the text display area */
2746   GetTextMetricsW(pDIStruct->hDC, &tm);
2747   rectText.left = rectIcon.right;
2748   rectText.top =
2749           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2750   rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2751   rectText.bottom =
2752           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2753 
2754   /* Draw the icon from the image list */
2755   ImageList_Draw(ilItemImage,
2756                  sfi.iIcon,
2757                  pDIStruct->hDC,
2758                  rectIcon.left,
2759                  rectIcon.top,
2760                  ILD_TRANSPARENT );
2761 
2762   /* Draw the associated text */
2763   if(sfi.szDisplayName)
2764     TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2765 
2766 
2767   return NOERROR;
2768 }
2769 
2770 /***********************************************************************
2771  *      FILEDLG95_LOOKIN_OnCommand
2772  *
2773  * LookIn combo box WM_COMMAND message handler
2774  * If the function succeeds, the return value is nonzero.
2775  */
2776 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2777 {
2778   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2779 
2780   TRACE("%p\n", fodInfos);
2781 
2782   switch(wNotifyCode)
2783   {
2784     case CBN_SELENDOK:
2785     {
2786       LPSFOLDER tmpFolder;
2787       int iItem;
2788 
2789       iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2790 
2791       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2792                                                iItem)))
2793         return FALSE;
2794 
2795 
2796       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2797                                               tmpFolder->pidlItem,
2798                                               SBSP_ABSOLUTE)))
2799       {
2800         SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2801         return TRUE;
2802       }
2803       break;
2804     }
2805 
2806   }
2807   return FALSE;
2808 }
2809 
2810 /***********************************************************************
2811  *      FILEDLG95_LOOKIN_AddItem
2812  *
2813  * Adds an absolute pidl item to the lookin combo box
2814  * returns the index of the inserted item
2815  */
2816 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2817 {
2818   LPITEMIDLIST pidlNext;
2819   SHFILEINFOW sfi;
2820   SFOLDER *tmpFolder;
2821   LookInInfos *liInfos;
2822 
2823   TRACE("%08x\n", iInsertId);
2824 
2825   if(!pidl)
2826     return -1;
2827 
2828   if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
2829     return -1;
2830 
2831   tmpFolder = MemAlloc(sizeof(SFOLDER));
2832   tmpFolder->m_iIndent = 0;
2833 
2834   /* Calculate the indentation of the item in the lookin*/
2835   pidlNext = pidl;
2836   while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2837   {
2838     tmpFolder->m_iIndent++;
2839   }
2840 
2841   tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2842 
2843   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2844     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2845 
2846   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2847   SHGetFileInfoW((LPCWSTR)pidl,
2848                   0,
2849                   &sfi,
2850                   sizeof(sfi),
2851                   SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2852                   | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2853 
2854   TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2855 
2856   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2857   {
2858     int iItemID;
2859 
2860     TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2861 
2862     /* Add the item at the end of the list */
2863     if(iInsertId < 0)
2864     {
2865       iItemID = CBAddString(hwnd,sfi.szDisplayName);
2866     }
2867     /* Insert the item at the iInsertId position*/
2868     else
2869     {
2870       iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2871     }
2872 
2873     CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2874     return iItemID;
2875   }
2876 
2877   COMDLG32_SHFree( tmpFolder->pidlItem );
2878   MemFree( tmpFolder );
2879   return -1;
2880 
2881 }
2882 
2883 /***********************************************************************
2884  *      FILEDLG95_LOOKIN_InsertItemAfterParent
2885  *
2886  * Insert an item below its parent
2887  */
2888 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2889 {
2890 
2891   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2892   int iParentPos;
2893 
2894   TRACE("\n");
2895 
2896   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2897 
2898   if(iParentPos < 0)
2899   {
2900     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2901   }
2902 
2903   /* Free pidlParent memory */
2904   COMDLG32_SHFree(pidlParent);
2905 
2906   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2907 }
2908 
2909 /***********************************************************************
2910  *      FILEDLG95_LOOKIN_SelectItem
2911  *
2912  * Adds an absolute pidl item to the lookin combo box
2913  * returns the index of the inserted item
2914  */
2915 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2916 {
2917   int iItemPos;
2918   LookInInfos *liInfos;
2919 
2920   TRACE("\n");
2921 
2922   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2923 
2924   liInfos = GetPropA(hwnd,LookInInfosStr);
2925 
2926   if(iItemPos < 0)
2927   {
2928     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2929     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2930   }
2931 
2932   else
2933   {
2934     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2935     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2936     {
2937       int iRemovedItem;
2938 
2939       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2940         break;
2941       if(iRemovedItem < iItemPos)
2942         iItemPos--;
2943     }
2944   }
2945 
2946   CBSetCurSel(hwnd,iItemPos);
2947   liInfos->uSelectedItem = iItemPos;
2948 
2949   return 0;
2950 
2951 }
2952 
2953 /***********************************************************************
2954  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
2955  *
2956  * Remove the item with an expansion level over iExpansionLevel
2957  */
2958 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2959 {
2960   int iItemPos;
2961   LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
2962 
2963   TRACE("\n");
2964 
2965   if(liInfos->iMaxIndentation <= 2)
2966     return -1;
2967 
2968   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2969   {
2970     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2971     COMDLG32_SHFree(tmpFolder->pidlItem);
2972     MemFree(tmpFolder);
2973     CBDeleteString(hwnd,iItemPos);
2974     liInfos->iMaxIndentation--;
2975 
2976     return iItemPos;
2977   }
2978 
2979   return -1;
2980 }
2981 
2982 /***********************************************************************
2983  *      FILEDLG95_LOOKIN_SearchItem
2984  *
2985  * Search for pidl in the lookin combo box
2986  * returns the index of the found item
2987  */
2988 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2989 {
2990   int i = 0;
2991   int iCount = CBGetCount(hwnd);
2992 
2993   TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
2994 
2995   if (iCount != CB_ERR)
2996   {
2997     for(;i<iCount;i++)
2998     {
2999       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3000 
3001       if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3002         return i;
3003       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3004         return i;
3005     }
3006   }
3007 
3008   return -1;
3009 }
3010 
3011 /***********************************************************************
3012  *      FILEDLG95_LOOKIN_Clean
3013  *
3014  * Clean the memory used by the lookin combo box
3015  */
3016 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3017 {
3018     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3019     int iPos;
3020     int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3021 
3022     TRACE("\n");
3023 
3024     /* Delete each string of the combo and their associated data */
3025     if (iCount != CB_ERR)
3026     {
3027       for(iPos = iCount-1;iPos>=0;iPos--)
3028       {
3029         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3030         COMDLG32_SHFree(tmpFolder->pidlItem);
3031         MemFree(tmpFolder);
3032         CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3033       }
3034     }
3035 
3036     /* LookInInfos structure */
3037     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3038 
3039 }
3040 /***********************************************************************
3041  * FILEDLG95_FILENAME_FillFromSelection
3042  *
3043  * fills the edit box from the cached DataObject
3044  */
3045 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3046 {
3047     FileOpenDlgInfos *fodInfos;
3048     LPITEMIDLIST      pidl;
3049     UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3050     WCHAR             lpstrTemp[MAX_PATH];
3051     LPWSTR            lpstrAllFile, lpstrCurrFile;
3052 
3053     TRACE("\n");
3054     fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3055 
3056     /* Count how many files we have */
3057     nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3058 
3059     /* calculate the string length, count files */
3060     if (nFileSelected >= 1)
3061     {
3062       nLength += 3;     /* first and last quotes, trailing \0 */
3063       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3064       {
3065         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3066 
3067         if (pidl)
3068         {
3069           /* get the total length of the selected file names */
3070           lpstrTemp[0] = '\0';
3071           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3072 
3073           if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3074           {
3075             nLength += lstrlenW( lpstrTemp ) + 3;
3076             nFiles++;
3077           }
3078           COMDLG32_SHFree( pidl );
3079         }
3080       }
3081     }
3082 
3083     /* allocate the buffer */
3084     if (nFiles <= 1) nLength = MAX_PATH;
3085     lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3086 
3087     /* Generate the string for the edit control */
3088     if(nFiles >= 1)
3089     {
3090       lpstrCurrFile = lpstrAllFile;
3091       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3092       {
3093         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3094 
3095         if (pidl)
3096         {
3097           /* get the file name */
3098           lpstrTemp[0] = '\0';
3099           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3100 
3101           if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3102           {
3103             if ( nFiles > 1)
3104             {
3105               *lpstrCurrFile++ =  '\"';
3106               lstrcpyW( lpstrCurrFile, lpstrTemp );
3107               lpstrCurrFile += lstrlenW( lpstrTemp );
3108               *lpstrCurrFile++ = '\"';
3109               *lpstrCurrFile++ = ' ';
3110               *lpstrCurrFile = 0;
3111             }
3112             else
3113             {
3114               lstrcpyW( lpstrAllFile, lpstrTemp );
3115             }
3116           }
3117           COMDLG32_SHFree( pidl );
3118         }
3119       }
3120       SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3121        
3122       /* Select the file name like Windows does */ 
3123       SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3124     }
3125     HeapFree(GetProcessHeap(),0, lpstrAllFile );
3126 }
3127 
3128 
3129 /* copied from shell32 to avoid linking to it
3130  * Although shell32 is already linked the behaviour of exported StrRetToStrN
3131  * is dependent on whether emulated OS is unicode or not.
3132  */
3133 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3134 {
3135         switch (src->uType)
3136         {
3137           case STRRET_WSTR:
3138             lstrcpynW(dest, src->u.pOleStr, len);
3139             COMDLG32_SHFree(src->u.pOleStr);
3140             break;
3141 
3142           case STRRET_CSTR:
3143             if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3144                   dest[len-1] = 0;
3145             break;
3146 
3147           case STRRET_OFFSET:
3148             if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3149                   dest[len-1] = 0;
3150             break;
3151 
3152           default:
3153             FIXME("unknown type %x!\n", src->uType);
3154             if (len) *dest = '\0';
3155             return E_FAIL;
3156         }
3157         return S_OK;
3158 }
3159 
3160 /***********************************************************************
3161  * FILEDLG95_FILENAME_GetFileNames
3162  *
3163  * Copies the filenames to a delimited string list.
3164  * The delimiter is specified by the parameter 'separator',
3165  *  usually either a space or a nul
3166  */
3167 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3168 {
3169         FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3170         UINT nStrCharCount = 0; /* index in src buffer */
3171         UINT nFileIndex = 0;    /* index in dest buffer */
3172         UINT nFileCount = 0;    /* number of files */
3173         UINT nStrLen = 0;       /* length of string in edit control */
3174         LPWSTR lpstrEdit;       /* buffer for string from edit control */
3175 
3176         TRACE("\n");
3177 
3178         /* get the filenames from the edit control */
3179         nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3180         lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3181         GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3182 
3183         TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3184 
3185         /* we might get single filename without any '"',
3186          * so we need nStrLen + terminating \0 + end-of-list \0 */
3187         *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3188         *sizeUsed = 0;
3189 
3190         /* build delimited file list from filenames */
3191         while ( nStrCharCount <= nStrLen )
3192         {
3193           if ( lpstrEdit[nStrCharCount]=='"' )
3194           {
3195             nStrCharCount++;
3196             while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3197             {
3198               (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3199               nStrCharCount++;
3200             }
3201             (*lpstrFileList)[nFileIndex++] = 0;
3202             nFileCount++;
3203           }
3204           nStrCharCount++;
3205         }
3206 
3207         /* single, unquoted string */
3208         if ((nStrLen > 0) && (nFileIndex == 0) )
3209         {
3210           lstrcpyW(*lpstrFileList, lpstrEdit);
3211           nFileIndex = lstrlenW(lpstrEdit) + 1;
3212           nFileCount = 1;
3213         }
3214 
3215         /* trailing \0 */
3216         (*lpstrFileList)[nFileIndex++] = '\0';
3217 
3218         *sizeUsed = nFileIndex;
3219         MemFree(lpstrEdit);
3220         return nFileCount;
3221 }
3222 
3223 #define SETDefFormatEtc(fe,cf,med) \
3224 { \
3225     (fe).cfFormat = cf;\
3226     (fe).dwAspect = DVASPECT_CONTENT; \
3227     (fe).ptd =NULL;\
3228     (fe).tymed = med;\
3229     (fe).lindex = -1;\
3230 };
3231 
3232 /*
3233  * DATAOBJECT Helper functions
3234  */
3235 
3236 /***********************************************************************
3237  * COMCTL32_ReleaseStgMedium
3238  *
3239  * like ReleaseStgMedium from ole32
3240  */
3241 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3242 {
3243       if(medium.pUnkForRelease)
3244       {
3245         IUnknown_Release(medium.pUnkForRelease);
3246       }
3247       else
3248       {
3249         GlobalUnlock(medium.u.hGlobal);
3250         GlobalFree(medium.u.hGlobal);
3251       }
3252 }
3253 
3254 /***********************************************************************
3255  *          GetPidlFromDataObject
3256  *
3257  * Return pidl(s) by number from the cached DataObject
3258  *
3259  * nPidlIndex=0 gets the fully qualified root path
3260  */
3261 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3262 {
3263 
3264     STGMEDIUM medium;
3265     FORMATETC formatetc;
3266     LPITEMIDLIST pidl = NULL;
3267 
3268     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3269 
3270     if (!doSelected)
3271         return NULL;
3272         
3273     /* Set the FORMATETC structure*/
3274     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3275 
3276     /* Get the pidls from IDataObject */
3277     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3278     {
3279       LPIDA cida = GlobalLock(medium.u.hGlobal);
3280       if(nPidlIndex <= cida->cidl)
3281       {
3282         pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3283       }
3284       COMCTL32_ReleaseStgMedium(medium);
3285     }
3286     return pidl;
3287 }
3288 
3289 /***********************************************************************
3290  *          GetNumSelected
3291  *
3292  * Return the number of selected items in the DataObject.
3293  *
3294 */
3295 static UINT GetNumSelected( IDataObject *doSelected )
3296 {
3297     UINT retVal = 0;
3298     STGMEDIUM medium;
3299     FORMATETC formatetc;
3300 
3301     TRACE("sv=%p\n", doSelected);
3302 
3303     if (!doSelected) return 0;
3304 
3305     /* Set the FORMATETC structure*/
3306     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3307 
3308     /* Get the pidls from IDataObject */
3309     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3310     {
3311       LPIDA cida = GlobalLock(medium.u.hGlobal);
3312       retVal = cida->cidl;
3313       COMCTL32_ReleaseStgMedium(medium);
3314       return retVal;
3315     }
3316     return 0;
3317 }
3318 
3319 /*
3320  * TOOLS
3321  */
3322 
3323 /***********************************************************************
3324  *      GetName
3325  *
3326  * Get the pidl's display name (relative to folder) and
3327  * put it in lpstrFileName.
3328  *
3329  * Return NOERROR on success,
3330  * E_FAIL otherwise
3331  */
3332 
3333 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3334 {
3335   STRRET str;
3336   HRESULT hRes;
3337 
3338   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3339 
3340   if(!lpsf)
3341   {
3342     SHGetDesktopFolder(&lpsf);
3343     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3344     IShellFolder_Release(lpsf);
3345     return hRes;
3346   }
3347 
3348   /* Get the display name of the pidl relative to the folder */
3349   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3350   {
3351       return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3352   }
3353   return E_FAIL;
3354 }
3355 
3356 /***********************************************************************
3357  *      GetShellFolderFromPidl
3358  *
3359  * pidlRel is the item pidl relative
3360  * Return the IShellFolder of the absolute pidl
3361  */
3362 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3363 {
3364   IShellFolder *psf = NULL,*psfParent;
3365 
3366   TRACE("%p\n", pidlAbs);
3367 
3368   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3369   {
3370     psf = psfParent;
3371     if(pidlAbs && pidlAbs->mkid.cb)
3372     {
3373       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3374       {
3375         IShellFolder_Release(psfParent);
3376         return psf;
3377       }
3378     }
3379     /* return the desktop */
3380     return psfParent;
3381   }
3382   return NULL;
3383 }
3384 
3385 /***********************************************************************
3386  *      GetParentPidl
3387  *
3388  * Return the LPITEMIDLIST to the parent of the pidl in the list
3389  */
3390 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3391 {
3392   LPITEMIDLIST pidlParent;
3393 
3394   TRACE("%p\n", pidl);
3395 
3396   pidlParent = COMDLG32_PIDL_ILClone(pidl);
3397   COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3398 
3399   return pidlParent;
3400 }
3401 
3402 /***********************************************************************
3403  *      GetPidlFromName
3404  *
3405  * returns the pidl of the file name relative to folder
3406  * NULL if an error occurred
3407  */
3408 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3409 {
3410   LPITEMIDLIST pidl = NULL;
3411   ULONG ulEaten;
3412 
3413   TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3414 
3415   if(!lpcstrFileName) return NULL;
3416   if(!*lpcstrFileName) return NULL;
3417 
3418   if(!lpsf)
3419   {
3420     if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3421         IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3422         IShellFolder_Release(lpsf);
3423     }
3424   }
3425   else
3426   {
3427     IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3428   }
3429   return pidl;
3430 }
3431 
3432 /*
3433 */
3434 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3435 {
3436         ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3437         HRESULT ret;
3438 
3439         TRACE("%p, %p\n", psf, pidl);
3440 
3441         ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3442 
3443         TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3444         /* see documentation shell 4.1*/
3445         return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3446 }
3447 
3448 /***********************************************************************
3449  *      BrowseSelectedFolder
3450  */
3451 static BOOL BrowseSelectedFolder(HWND hwnd)
3452 {
3453   BOOL bBrowseSelFolder = FALSE;
3454   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3455 
3456   TRACE("\n");
3457 
3458   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3459   {
3460       LPITEMIDLIST pidlSelection;
3461 
3462       /* get the file selected */
3463       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3464       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3465       {
3466           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3467                          pidlSelection, SBSP_RELATIVE ) ) )
3468           {
3469                static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3470                                    ' ','n','o','t',' ','e','x','i','s','t',0};
3471                MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3472           }
3473           bBrowseSelFolder = TRUE;
3474           SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3475       }
3476       COMDLG32_SHFree( pidlSelection );
3477   }
3478 
3479   return bBrowseSelFolder;
3480 }
3481 
3482 /*
3483  * Memory allocation methods */
3484 static void *MemAlloc(UINT size)
3485 {
3486     return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3487 }
3488 
3489 static void MemFree(void *mem)
3490 {
3491     HeapFree(GetProcessHeap(),0,mem);
3492 }
3493 
3494 /*
3495  * Old-style (win3.1) dialogs */
3496 
3497 /***********************************************************************
3498  *           FD32_GetTemplate                                  [internal]
3499  *
3500  * Get a template (or FALSE if failure) when 16 bits dialogs are used
3501  * by a 32 bits application
3502  *
3503  */
3504 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3505 {
3506     LPOPENFILENAMEW ofnW = lfs->ofnW;
3507     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3508     HANDLE hDlgTmpl;
3509 
3510     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3511     {
3512         if (!(lfs->template = LockResource( ofnW->hInstance )))
3513         {
3514             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3515             return FALSE;
3516         }
3517     }
3518     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3519     {
3520         HRSRC hResInfo;
3521         if (priv->ofnA)