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