~ [ 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_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 | OFN_ENABLESIZING |\
 86 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
 87 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
 88 
 89 #define IsHooked(fodInfos) \
 90         ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
 91 /***********************************************************************
 92  * Data structure and global variables
 93  */
 94 typedef struct SFolder
 95 {
 96   int m_iImageIndex;    /* Index of picture in image list */
 97   HIMAGELIST hImgList;
 98   int m_iIndent;      /* Indentation index */
 99   LPITEMIDLIST pidlItem;  /* absolute pidl of the item */
100 
101 } SFOLDER,*LPSFOLDER;
102 
103 typedef struct tagLookInInfo
104 {
105   int iMaxIndentation;
106   UINT uSelectedItem;
107 } LookInInfos;
108 
109 typedef struct tagFD32_PRIVATE
110 {
111     OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
112 } FD32_PRIVATE, *PFD32_PRIVATE;
113 
114 
115 /***********************************************************************
116  * Defines and global variables
117  */
118 
119 /* Draw item constant */
120 #define ICONWIDTH 18
121 #define XTEXTOFFSET 3
122 
123 /* AddItem flags*/
124 #define LISTEND -1
125 
126 /* SearchItem methods */
127 #define SEARCH_PIDL 1
128 #define SEARCH_EXP  2
129 #define ITEM_NOTFOUND -1
130 
131 /* Undefined windows message sent by CreateViewObject*/
132 #define WM_GETISHELLBROWSER  WM_USER+7
133 
134 /* NOTE
135  * Those macros exist in windowsx.h. However, you can't really use them since
136  * they rely on the UNICODE defines and can't be used inside Wine itself.
137  */
138 
139 /* Combo box macros */
140 #define CBAddString(hwnd,str) \
141     SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
142 
143 #define CBInsertString(hwnd,str,pos) \
144     SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
145 
146 #define CBDeleteString(hwnd,pos) \
147     SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
148 
149 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
150     SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
151 
152 #define CBGetItemDataPtr(hwnd,iItemId) \
153     SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
154 
155 #define CBGetLBText(hwnd,iItemId,str) \
156     SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
157 
158 #define CBGetCurSel(hwnd) \
159     SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
160 
161 #define CBSetCurSel(hwnd,pos) \
162     SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
163 
164 #define CBGetCount(hwnd) \
165     SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
166 #define CBShowDropDown(hwnd,show) \
167     SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
168 #define CBSetItemHeight(hwnd,index,height) \
169     SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
170 
171 #define CBSetExtendedUI(hwnd,flag) \
172     SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
173 
174 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
175 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
176 
177 /***********************************************************************
178  * Prototypes
179  */
180 
181 /* Internal functions used by the dialog */
182 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
186 static BOOL    FILEDLG95_OnOpen(HWND hwnd);
187 static LRESULT FILEDLG95_InitControls(HWND hwnd);
188 static void    FILEDLG95_Clean(HWND hwnd);
189 
190 /* Functions used by the shell navigation */
191 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
192 static BOOL    FILEDLG95_SHELL_UpFolder(HWND hwnd);
193 static BOOL    FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
194 static void    FILEDLG95_SHELL_Clean(HWND hwnd);
195 static BOOL    FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
196 
197 /* Functions used by the EDIT box */
198 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
199 
200 /* Functions used by the filetype combo box */
201 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
202 static BOOL    FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
203 static int     FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
204 static void    FILEDLG95_FILETYPE_Clean(HWND hwnd);
205 
206 /* Functions used by the Look In combo box */
207 static void    FILEDLG95_LOOKIN_Init(HWND hwndCombo);
208 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
209 static BOOL    FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
210 static int     FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
211 static int     FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
212 static int     FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
213 static int     FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
214        int     FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
215 static void    FILEDLG95_LOOKIN_Clean(HWND hwnd);
216 
217 /* Miscellaneous tool functions */
218 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
219 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
220 LPITEMIDLIST  GetParentPidl(LPITEMIDLIST pidl);
221 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
222 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
223 static UINT GetNumSelected( IDataObject *doSelected );
224 
225 /* Shell memory allocation */
226 static void *MemAlloc(UINT size);
227 static void MemFree(void *mem);
228 
229 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
232 static BOOL BrowseSelectedFolder(HWND hwnd);
233 
234 /***********************************************************************
235  *      GetFileName95
236  *
237  * Creates an Open common dialog box that lets the user select
238  * the drive, directory, and the name of a file or set of files to open.
239  *
240  * IN  : The FileOpenDlgInfos structure associated with the dialog
241  * OUT : TRUE on success
242  *       FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
243  */
244 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
245 {
246 
247     LRESULT lRes;
248     LPCVOID template;
249     HRSRC hRes;
250     HANDLE hDlgTmpl = 0;
251     HRESULT hr;
252 
253     /* test for missing functionality */
254     if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255     {
256       FIXME("Flags 0x%08x not yet implemented\n",
257          fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
258     }
259 
260     /* Create the dialog from a template */
261 
262     if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
263     {
264         COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
265         return FALSE;
266     }
267     if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
268         !(template = LockResource( hDlgTmpl )))
269     {
270         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
271         return FALSE;
272     }
273 
274     /* old style hook messages */
275     if (IsHooked(fodInfos))
276     {
277       fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
278       fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
279       fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
280       fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
281     }
282 
283     /* Some shell namespace extensions depend on COM being initialized. */
284     hr = OleInitialize(NULL);
285 
286     if (fodInfos->unicode)
287       lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
288                                      template,
289                                      fodInfos->ofnInfos->hwndOwner,
290                                      FileOpenDlgProc95,
291                                      (LPARAM) fodInfos);
292     else
293       lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
294                                      template,
295                                      fodInfos->ofnInfos->hwndOwner,
296                                      FileOpenDlgProc95,
297                                      (LPARAM) fodInfos);
298     if (SUCCEEDED(hr)) 
299         OleUninitialize();
300 
301     /* Unable to create the dialog */
302     if( lRes == -1)
303         return FALSE;
304 
305     return lRes;
306 }
307 
308 /***********************************************************************
309  *      GetFileDialog95A
310  *
311  * Call GetFileName95 with this structure and clean the memory.
312  *
313  * IN  : The OPENFILENAMEA initialisation structure passed to
314  *       GetOpenFileNameA win api function (see filedlg.c)
315  */
316 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
317 {
318   BOOL ret;
319   FileOpenDlgInfos fodInfos;
320   LPSTR lpstrSavDir = NULL;
321   LPWSTR title = NULL;
322   LPWSTR defext = NULL;
323   LPWSTR filter = NULL;
324   LPWSTR customfilter = NULL;
325 
326   /* Initialize CommDlgExtendedError() */
327   COMDLG32_SetCommDlgExtendedError(0);
328 
329   /* Initialize FileOpenDlgInfos structure */
330   ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
331 
332   /* Pass in the original ofn */
333   fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
334 
335   /* save current directory */
336   if (ofn->Flags & OFN_NOCHANGEDIR)
337   {
338      lpstrSavDir = MemAlloc(MAX_PATH);
339      GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
340   }
341 
342   fodInfos.unicode = FALSE;
343 
344   /* convert all the input strings to unicode */
345   if(ofn->lpstrInitialDir)
346   {
347     DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
348     fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
349     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
350   }
351   else
352     fodInfos.initdir = NULL;
353 
354   if(ofn->lpstrFile)
355   {
356     fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
357     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
358   }
359   else
360     fodInfos.filename = NULL;
361 
362   if(ofn->lpstrDefExt)
363   {
364     DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
365     defext = MemAlloc((len+1)*sizeof(WCHAR));
366     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
367   }
368   fodInfos.defext = defext;
369 
370   if(ofn->lpstrTitle)
371   {
372     DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
373     title = MemAlloc((len+1)*sizeof(WCHAR));
374     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
375   }
376   fodInfos.title = title;
377 
378   if (ofn->lpstrFilter)
379   {
380     LPCSTR s;
381     int n, len;
382 
383     /* filter is a list...  title\0ext\0......\0\0 */
384     s = ofn->lpstrFilter;
385     while (*s) s = s+strlen(s)+1;
386     s++;
387     n = s - ofn->lpstrFilter;
388     len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
389     filter = MemAlloc(len*sizeof(WCHAR));
390     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
391   }
392   fodInfos.filter = filter;
393 
394   /* convert lpstrCustomFilter */
395   if (ofn->lpstrCustomFilter)
396   {
397     LPCSTR s;
398     int n, len;
399 
400     /* customfilter contains a pair of strings...  title\0ext\0 */
401     s = ofn->lpstrCustomFilter;
402     if (*s) s = s+strlen(s)+1;
403     if (*s) s = s+strlen(s)+1;
404     n = s - ofn->lpstrCustomFilter;
405     len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
406     customfilter = MemAlloc(len*sizeof(WCHAR));
407     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
408   }
409   fodInfos.customfilter = customfilter;
410 
411   /* Initialize the dialog property */
412   fodInfos.DlgInfos.dwDlgProp = 0;
413   fodInfos.DlgInfos.hwndCustomDlg = NULL;
414 
415   switch(iDlgType)
416   {
417     case OPEN_DIALOG :
418       ret = GetFileName95(&fodInfos);
419       break;
420     case SAVE_DIALOG :
421       fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
422       ret = GetFileName95(&fodInfos);
423       break;
424     default :
425       ret = 0;
426   }
427 
428   if (lpstrSavDir)
429   {
430       SetCurrentDirectoryA(lpstrSavDir);
431       MemFree(lpstrSavDir);
432   }
433 
434   MemFree(title);
435   MemFree(defext);
436   MemFree(filter);
437   MemFree(customfilter);
438   MemFree(fodInfos.initdir);
439   MemFree(fodInfos.filename);
440 
441   TRACE("selected file: %s\n",ofn->lpstrFile);
442 
443   return ret;
444 }
445 
446 /***********************************************************************
447  *      GetFileDialog95W
448  *
449  * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
450  * Call GetFileName95 with this structure and clean the memory.
451  *
452  */
453 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
454 {
455   BOOL ret;
456   FileOpenDlgInfos fodInfos;
457   LPWSTR lpstrSavDir = NULL;
458 
459   /* Initialize CommDlgExtendedError() */
460   COMDLG32_SetCommDlgExtendedError(0);
461 
462   /* Initialize FileOpenDlgInfos structure */
463   ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
464 
465   /*  Pass in the original ofn */
466   fodInfos.ofnInfos = ofn;
467 
468   fodInfos.title = ofn->lpstrTitle;
469   fodInfos.defext = ofn->lpstrDefExt;
470   fodInfos.filter = ofn->lpstrFilter;
471   fodInfos.customfilter = ofn->lpstrCustomFilter;
472 
473   /* convert string arguments, save others */
474   if(ofn->lpstrFile)
475   {
476     fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
477     lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
478   }
479   else
480     fodInfos.filename = NULL;
481 
482   if(ofn->lpstrInitialDir)
483   {
484     /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
485     DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
486     fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
487     memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
488   }
489   else
490     fodInfos.initdir = NULL;
491 
492   /* save current directory */
493   if (ofn->Flags & OFN_NOCHANGEDIR)
494   {
495      lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
496      GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
497   }
498 
499   fodInfos.unicode = TRUE;
500 
501   switch(iDlgType)
502   {
503   case OPEN_DIALOG :
504       ret = GetFileName95(&fodInfos);
505       break;
506   case SAVE_DIALOG :
507       fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
508       ret = GetFileName95(&fodInfos);
509       break;
510   default :
511       ret = 0;
512   }
513 
514   if (lpstrSavDir)
515   {
516       SetCurrentDirectoryW(lpstrSavDir);
517       MemFree(lpstrSavDir);
518   }
519 
520   /* restore saved IN arguments and convert OUT arguments back */
521   MemFree(fodInfos.filename);
522   MemFree(fodInfos.initdir);
523   return ret;
524 }
525 
526 /******************************************************************************
527  * COMDLG32_GetDisplayNameOf [internal]
528  *
529  * Helper function to get the display name for a pidl.
530  */
531 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
532     LPSHELLFOLDER psfDesktop;
533     STRRET strret;
534         
535     if (FAILED(SHGetDesktopFolder(&psfDesktop)))
536         return FALSE;
537 
538     if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
539         IShellFolder_Release(psfDesktop);
540         return FALSE;
541     }
542 
543     IShellFolder_Release(psfDesktop);
544     return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
545 }
546 
547 /***********************************************************************
548  *      ArrangeCtrlPositions [internal]
549  *
550  * NOTE: Do not change anything here without a lot of testing.
551  */
552 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
553 {
554     HWND hwndChild, hwndStc32;
555     RECT rectParent, rectChild, rectStc32;
556     INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
557 
558     /* Take into account if open as read only checkbox and help button
559      * are hidden
560      */
561      if (hide_help)
562      {
563          RECT rectHelp, rectCancel;
564          GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
565          GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
566          /* subtract the height of the help button plus the space between
567           * the help button and the cancel button to the height of the dialog
568           */
569           help_fixup = rectHelp.bottom - rectCancel.bottom;
570     }
571 
572     /*
573       There are two possibilities to add components to the default file dialog box.
574 
575       By default, all the new components are added below the standard dialog box (the else case).
576 
577       However, if there is a static text component with the stc32 id, a special case happens.
578       The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
579       in the window and the cx and cy indicate how to size the window.
580       Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left 
581       of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
582       
583      */
584 
585     GetClientRect(hwndParentDlg, &rectParent);
586 
587     /* when arranging controls we have to use fixed parent size */
588     rectParent.bottom -= help_fixup;
589 
590     hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
591     if (hwndStc32)
592     {
593         GetWindowRect(hwndStc32, &rectStc32);
594         MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
595 
596         /* set the size of the stc32 control according to the size of
597          * client area of the parent dialog
598          */
599         SetWindowPos(hwndStc32, 0,
600                      0, 0,
601                      rectParent.right, rectParent.bottom,
602                      SWP_NOMOVE | SWP_NOZORDER);
603     }
604     else
605         SetRectEmpty(&rectStc32);
606 
607     /* this part moves controls of the child dialog */
608     hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
609     while (hwndChild)
610     {
611         if (hwndChild != hwndStc32)
612         {
613             GetWindowRect(hwndChild, &rectChild);
614             MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
615 
616             /* move only if stc32 exist */
617             if (hwndStc32 && rectChild.left > rectStc32.right)
618             {
619                 LONG old_left = rectChild.left;
620 
621                 /* move to the right of visible controls of the parent dialog */
622                 rectChild.left += rectParent.right;
623                 rectChild.left -= rectStc32.right;
624 
625                 child_width_fixup = rectChild.left - old_left;
626             }
627             /* move even if stc32 doesn't exist */
628             if (rectChild.top >= rectStc32.bottom)
629             {
630                 LONG old_top = rectChild.top;
631 
632                 /* move below visible controls of the parent dialog */
633                 rectChild.top += rectParent.bottom;
634                 rectChild.top -= rectStc32.bottom - rectStc32.top;
635 
636                 child_height_fixup = rectChild.top - old_top;
637             }
638 
639             SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
640                          0, 0, SWP_NOSIZE | SWP_NOZORDER);
641         }
642         hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
643     }
644 
645     /* this part moves controls of the parent dialog */
646     hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
647     while (hwndChild)
648     {
649         if (hwndChild != hwndChildDlg)
650         {
651             GetWindowRect(hwndChild, &rectChild);
652             MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
653 
654             /* left,top of stc32 marks the position of controls
655              * from the parent dialog
656              */
657             rectChild.left += rectStc32.left;
658             rectChild.top += rectStc32.top;
659 
660             SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
661                          0, 0, SWP_NOSIZE | SWP_NOZORDER);
662         }
663         hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
664     }
665 
666     /* calculate the size of the resulting dialog */
667 
668     /* here we have to use original parent size */
669     GetClientRect(hwndParentDlg, &rectParent);
670     GetClientRect(hwndChildDlg, &rectChild);
671 
672     if (hwndStc32)
673     {
674         rectChild.right += child_width_fixup;
675         rectChild.bottom += child_height_fixup;
676 
677         if (rectParent.right > rectChild.right)
678         {
679             rectParent.right += rectChild.right;
680             rectParent.right -= rectStc32.right - rectStc32.left;
681         }
682         else
683         {
684             rectParent.right = rectChild.right;
685         }
686 
687         if (rectParent.bottom > rectChild.bottom)
688         {
689             rectParent.bottom += rectChild.bottom;
690             rectParent.bottom -= rectStc32.bottom - rectStc32.top;
691         }
692         else
693         {
694             /* child dialog is higher, unconditionally set new dialog
695              * height to its size (help_fixup will be subtracted below)
696              */
697             rectParent.bottom = rectChild.bottom + help_fixup;
698         }
699     }
700     else
701     {
702         rectParent.bottom += rectChild.bottom;
703     }
704 
705     /* finally use fixed parent size */
706     rectParent.bottom -= help_fixup;
707 
708     /* set the size of the parent dialog */
709     AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
710                        FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
711     SetWindowPos(hwndParentDlg, 0,
712                  0, 0,
713                  rectParent.right - rectParent.left,
714                  rectParent.bottom - rectParent.top,
715                  SWP_NOMOVE | SWP_NOZORDER);
716 }
717 
718 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
719 {
720     switch(uMsg) {
721     case WM_INITDIALOG:
722         return TRUE;
723     }
724     return FALSE;
725 }
726 
727 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
728 {
729     LPCVOID template;
730     HRSRC hRes;
731     HANDLE hDlgTmpl = 0;
732     HWND hChildDlg = 0;
733 
734     TRACE("\n");
735 
736     /*
737      * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
738      * structure's hInstance parameter is not a HINSTANCE, but
739      * instead a pointer to a template resource to use.
740      */
741     if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
742     {
743       HINSTANCE hinst;
744       if (fodInfos->ofnInfos->Flags  & OFN_ENABLETEMPLATEHANDLE)
745       {
746         hinst = COMDLG32_hInstance;
747         if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
748         {
749           COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
750           return NULL;
751         }
752       }
753       else
754       {
755         hinst = fodInfos->ofnInfos->hInstance;
756         if(fodInfos->unicode)
757         {
758             LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
759             hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
760         }
761         else
762         {
763             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
764             hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
765         }
766         if (!hRes)
767         {
768           COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
769           return NULL;
770         }
771         if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
772             !(template = LockResource( hDlgTmpl )))
773         {
774           COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
775           return NULL;
776         }
777       }
778       if (fodInfos->unicode)
779           hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
780               IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
781               (LPARAM)fodInfos->ofnInfos);
782       else
783           hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
784               IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
785               (LPARAM)fodInfos->ofnInfos);
786       if(hChildDlg)
787       {
788         ShowWindow(hChildDlg,SW_SHOW);
789         return hChildDlg;
790       }
791     }
792     else if( IsHooked(fodInfos))
793     {
794       RECT rectHwnd;
795       struct  {
796          DLGTEMPLATE tmplate;
797          WORD menu,class,title;
798          } temp;
799       GetClientRect(hwnd,&rectHwnd);
800       temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
801       temp.tmplate.dwExtendedStyle = 0;
802       temp.tmplate.cdit = 0;
803       temp.tmplate.x = 0;
804       temp.tmplate.y = 0;
805       temp.tmplate.cx = 0;
806       temp.tmplate.cy = 0;
807       temp.menu = temp.class = temp.title = 0;
808 
809       hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
810                   hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
811 
812       return hChildDlg;
813     }
814     return NULL;
815 }
816 
817 /***********************************************************************
818 *          SendCustomDlgNotificationMessage
819 *
820 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
821 */
822 
823 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
824 {
825     LRESULT hook_result = 0;
826     FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
827 
828     TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
829 
830     if(!fodInfos) return 0;
831 
832     if(fodInfos->DlgInfos.hwndCustomDlg)
833     {
834         TRACE("CALL NOTIFY for %x\n", uCode);
835         if(fodInfos->unicode)
836         {
837             OFNOTIFYW ofnNotify;
838             ofnNotify.hdr.hwndFrom=hwndParentDlg;
839             ofnNotify.hdr.idFrom=0;
840             ofnNotify.hdr.code = uCode;
841             ofnNotify.lpOFN = fodInfos->ofnInfos;
842             ofnNotify.pszFile = NULL;
843             hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
844         }
845         else
846         {
847             OFNOTIFYA ofnNotify;
848             ofnNotify.hdr.hwndFrom=hwndParentDlg;
849             ofnNotify.hdr.idFrom=0;
850             ofnNotify.hdr.code = uCode;
851             ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
852             ofnNotify.pszFile = NULL;
853             hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
854         }
855         TRACE("RET NOTIFY\n");
856     }
857     TRACE("Retval: 0x%08lx\n", hook_result);
858     return hook_result;
859 }
860 
861 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
862 {
863     UINT len, total;
864     WCHAR *p, *buffer;
865     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
866 
867     TRACE("CDM_GETFILEPATH:\n");
868 
869     if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
870         return -1;
871 
872     /* get path and filenames */
873     len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
874     buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
875     COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
876     if (len)
877     {
878         p = buffer + strlenW(buffer);
879         *p++ = '\\';
880         SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
881     }
882     if (fodInfos->unicode)
883     {
884         total = strlenW( buffer) + 1;
885         if (result) lstrcpynW( result, buffer, size );
886         TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
887     }
888     else
889     {
890         total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
891         if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
892         TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
893     }
894     HeapFree( GetProcessHeap(), 0, buffer );
895     return total;
896 }
897 
898 /***********************************************************************
899 *         FILEDLG95_HandleCustomDialogMessages
900 *
901 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
902 */
903 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
904 {
905     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
906     WCHAR lpstrPath[MAX_PATH];
907     INT_PTR retval;
908 
909     if(!fodInfos) return FALSE;
910 
911     switch(uMsg)
912     {
913         case CDM_GETFILEPATH:
914             retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
915             break;
916 
917         case CDM_GETFOLDERPATH:
918             TRACE("CDM_GETFOLDERPATH:\n");
919             COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
920             if (lParam) 
921             {
922                 if (fodInfos->unicode)
923                     lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
924                 else
925                     WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1, 
926                                         (LPSTR)lParam, (int)wParam, NULL, NULL);
927             }        
928             retval = lstrlenW(lpstrPath);
929             break;
930 
931         case CDM_GETFOLDERIDLIST:
932             retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
933             if (retval <= wParam)
934                 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
935             break;
936 
937         case CDM_GETSPEC:
938             TRACE("CDM_GETSPEC:\n");
939             retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
940             if (lParam)
941             {
942                 if (fodInfos->unicode)
943                     SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
944                 else
945                     SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
946             }
947             break;
948 
949         case CDM_SETCONTROLTEXT:
950             TRACE("CDM_SETCONTROLTEXT:\n");
951             if ( lParam )
952             {
953                 if( fodInfos->unicode )
954                     SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
955                 else
956                     SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
957             }
958             retval = TRUE;
959             break;
960 
961         case CDM_HIDECONTROL:
962             /* MSDN states that it should fail for not OFN_EXPLORER case */
963             if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
964             {
965                 HWND control = GetDlgItem( hwnd, wParam );
966                 if (control) ShowWindow( control, SW_HIDE );
967                 retval = TRUE;
968             }
969             else retval = FALSE;
970             break;
971 
972         default:
973             if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
974                 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
975             return FALSE;
976     }
977     SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
978     return TRUE;
979 }
980 
981 /***********************************************************************
982  *          FileOpenDlgProc95
983  *
984  * File open dialog procedure
985  */
986 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
987 {
988 #if 0
989   TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
990 #endif
991 
992   switch(uMsg)
993   {
994     case WM_INITDIALOG:
995       {
996          FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
997 
998          /* Adds the FileOpenDlgInfos in the property list of the dialog
999             so it will be easily accessible through a GetPropA(...) */
1000          SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1001 
1002          FILEDLG95_InitControls(hwnd);
1003 
1004          fodInfos->DlgInfos.hwndCustomDlg =
1005            CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1006 
1007          FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1008          FILEDLG95_FillControls(hwnd, wParam, lParam);
1009 
1010          SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1011          SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1012          SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1013          return 0;
1014        }
1015     case WM_COMMAND:
1016       return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1017     case WM_DRAWITEM:
1018       {
1019         switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1020         {
1021         case IDC_LOOKIN:
1022           FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1023           return TRUE;
1024         }
1025       }
1026       return FALSE;
1027 
1028     case WM_GETISHELLBROWSER:
1029       return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1030 
1031     case WM_DESTROY:
1032       RemovePropA(hwnd, FileOpenDlgInfosStr);
1033       return FALSE;
1034 
1035     case WM_NOTIFY:
1036     {
1037         LPNMHDR lpnmh = (LPNMHDR)lParam;
1038         UINT stringId = -1;
1039 
1040         /* set up the button tooltips strings */
1041         if(TTN_GETDISPINFOA == lpnmh->code )
1042         {
1043             LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1044             switch(lpnmh->idFrom )
1045             {
1046                 /* Up folder button */
1047                 case FCIDM_TB_UPFOLDER:
1048                     stringId = IDS_UPFOLDER;
1049                     break;
1050                 /* New folder button */
1051                 case FCIDM_TB_NEWFOLDER:
1052                     stringId = IDS_NEWFOLDER;
1053                     break;
1054                 /* List option button */
1055                 case FCIDM_TB_SMALLICON:
1056                     stringId = IDS_LISTVIEW;
1057                     break;
1058                 /* Details option button */
1059                 case FCIDM_TB_REPORTVIEW:
1060                     stringId = IDS_REPORTVIEW;
1061                     break;
1062                 /* Desktop button */
1063                 case FCIDM_TB_DESKTOP:
1064                     stringId = IDS_TODESKTOP;
1065                     break;
1066                 default:
1067                     stringId = 0;
1068             }
1069             lpdi->hinst = COMDLG32_hInstance;
1070             lpdi->lpszText =  MAKEINTRESOURCEA(stringId);
1071         }
1072         return FALSE;
1073     }
1074     default :
1075       if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1076         return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1077       return FALSE;
1078   }
1079 }
1080 
1081 /***********************************************************************
1082  *      FILEDLG95_InitControls
1083  *
1084  * WM_INITDIALOG message handler (before hook notification)
1085  */
1086 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1087 {
1088   int win2000plus = 0;
1089   int win98plus   = 0;
1090   int handledPath = FALSE;
1091   OSVERSIONINFOW osVi;
1092   static const WCHAR szwSlash[] = { '\\', 0 };
1093   static const WCHAR szwStar[] = { '*',0 };
1094 
1095   static const TBBUTTON tbb[] =
1096   {
1097    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1098    {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER,   TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1099    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1100    {VIEW_NEWFOLDER+1,  FCIDM_TB_DESKTOP,    TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1101    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1102    {VIEW_NEWFOLDER,    FCIDM_TB_NEWFOLDER,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1103    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1104    {VIEW_LIST,         FCIDM_TB_SMALLICON,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1105    {VIEW_DETAILS,      FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1106   };
1107   TBADDBITMAP tba[2];
1108   RECT rectTB;
1109   RECT rectlook;
1110   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1111 
1112   tba[0].hInst = HINST_COMMCTRL;
1113   tba[0].nID   = IDB_VIEW_SMALL_COLOR;
1114   tba[1].hInst = COMDLG32_hInstance;
1115   tba[1].nID   = 800;
1116 
1117   TRACE("%p\n", fodInfos);
1118 
1119   /* Get windows version emulating */
1120   osVi.dwOSVersionInfoSize = sizeof(osVi);
1121   GetVersionExW(&osVi);
1122   if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1123     win98plus   = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1124   } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1125     win2000plus = (osVi.dwMajorVersion > 4);
1126     if (win2000plus) win98plus = TRUE;
1127   }
1128   TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1129 
1130   /* Get the hwnd of the controls */
1131   fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1132   fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1133   fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1134 
1135   GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1136   MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1137 
1138   /* construct the toolbar */
1139   GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1140   MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1141 
1142   rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1143   rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1144   rectTB.left = rectlook.right;
1145   rectTB.top = rectlook.top-1;
1146 
1147   if (fodInfos->unicode)
1148       fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1149           WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1150           rectTB.left, rectTB.top,
1151           rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1152           hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1153   else
1154       fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1155           WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1156           rectTB.left, rectTB.top,
1157           rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1158           hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1159 
1160   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1161 
1162 /* FIXME: use TB_LOADIMAGES when implemented */
1163 /*  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1164   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1165   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1166 
1167   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1168   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1169 
1170   /* Set the window text with the text specified in the OPENFILENAME structure */
1171   if(fodInfos->title)
1172   {
1173       SetWindowTextW(hwnd,fodInfos->title);
1174   }
1175   else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1176   {
1177       WCHAR buf[16];
1178       LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1179       SetWindowTextW(hwnd, buf);
1180   }
1181 
1182   /* Initialise the file name edit control */
1183   handledPath = FALSE;
1184   TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1185 
1186   if(fodInfos->filename)
1187   {
1188       /* 1. If win2000 or higher and filename contains a path, use it
1189          in preference over the lpstrInitialDir                       */
1190       if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1191          WCHAR tmpBuf[MAX_PATH];
1192          WCHAR *nameBit;
1193          DWORD result;
1194 
1195          result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1196          if (result) {
1197 
1198             /* nameBit is always shorter than the original filename */
1199             lstrcpyW(fodInfos->filename,nameBit);
1200 
1201             *nameBit = 0x00;
1202             if (fodInfos->initdir == NULL)
1203                 MemFree(fodInfos->initdir);
1204             fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1205             lstrcpyW(fodInfos->initdir, tmpBuf);
1206             handledPath = TRUE;
1207             TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1208                     debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1209          }
1210          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1211 
1212       } else {
1213          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1214       }
1215   }
1216 
1217   /* 2. (All platforms) If initdir is not null, then use it */
1218   if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1219                                 (*fodInfos->initdir!=0x00))
1220   {
1221       /* Work out the proper path as supplied one might be relative          */
1222       /* (Here because supplying '.' as dir browses to My Computer)          */
1223       if (handledPath==FALSE) {
1224           WCHAR tmpBuf[MAX_PATH];
1225           WCHAR tmpBuf2[MAX_PATH];
1226           WCHAR *nameBit;
1227           DWORD result;
1228 
1229           lstrcpyW(tmpBuf, fodInfos->initdir);
1230           if( PathFileExistsW(tmpBuf) ) {
1231               /* initdir does not have to be a directory. If a file is
1232                * specified, the dir part is taken */
1233               if( PathIsDirectoryW(tmpBuf)) {
1234                   if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1235                      lstrcatW(tmpBuf, szwSlash);
1236                   }
1237                   lstrcatW(tmpBuf, szwStar);
1238               }
1239               result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1240               if (result) {
1241                  *nameBit = 0x00;
1242                  MemFree(fodInfos->initdir);
1243                  fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1244                  lstrcpyW(fodInfos->initdir, tmpBuf2);
1245                  handledPath = TRUE;
1246                  TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1247               }
1248           }
1249           else if (fodInfos->initdir)
1250           {
1251                     MemFree(fodInfos->initdir);
1252                     fodInfos->initdir = NULL;
1253                     TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1254           }
1255       }
1256   }
1257 
1258   if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1259                                  (*fodInfos->initdir==0x00)))
1260   {
1261       /* 3. All except w2k+: if filename contains a path use it */
1262       if (!win2000plus && fodInfos->filename &&
1263           *fodInfos->filename &&
1264           strpbrkW(fodInfos->filename, szwSlash)) {
1265          WCHAR tmpBuf[MAX_PATH];
1266          WCHAR *nameBit;
1267          DWORD result;
1268 
1269          result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1270                                   tmpBuf, &nameBit);
1271          if (result) {
1272             int len;
1273 
1274             /* nameBit is always shorter than the original filename */
1275             lstrcpyW(fodInfos->filename, nameBit);
1276             *nameBit = 0x00;
1277 
1278             len = lstrlenW(tmpBuf);
1279             MemFree(fodInfos->initdir);
1280             fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1281             lstrcpyW(fodInfos->initdir, tmpBuf);
1282 
1283             handledPath = TRUE;
1284             TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1285                  debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1286          }
1287          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1288       }
1289 
1290       /* 4. win98+ and win2000+ if any files of specified filter types in
1291             current directory, use it                                      */
1292       if ( win98plus && handledPath == FALSE &&
1293            fodInfos->filter && *fodInfos->filter) {
1294 
1295          BOOL   searchMore = TRUE;
1296          LPCWSTR lpstrPos = fodInfos->filter;
1297          WIN32_FIND_DATAW FindFileData;
1298          HANDLE hFind;
1299 
1300          while (searchMore)
1301          {
1302            /* filter is a list...  title\0ext\0......\0\0 */
1303 
1304            /* Skip the title */
1305            if(! *lpstrPos) break;       /* end */
1306            lpstrPos += lstrlenW(lpstrPos) + 1;
1307 
1308            /* See if any files exist in the current dir with this extension */
1309            if(! *lpstrPos) break;       /* end */
1310 
1311            hFind = FindFirstFileW(lpstrPos, &FindFileData);
1312 
1313            if (hFind == INVALID_HANDLE_VALUE) {
1314                /* None found - continue search */
1315                lpstrPos += lstrlenW(lpstrPos) + 1;
1316 
1317            } else {
1318                searchMore = FALSE;
1319 
1320                MemFree(fodInfos->initdir);
1321                fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1322                GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1323 
1324                handledPath = TRUE;
1325                TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1326                  debugstr_w(lpstrPos));
1327                break;
1328            }
1329          }
1330       }
1331 
1332       /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1333 
1334       /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1335       if (handledPath == FALSE && (win2000plus || win98plus)) {
1336           fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1337 
1338           if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1339           {
1340             if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1341             {
1342                 /* last fallback */
1343                 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1344                 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1345             } else {
1346                 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1347             }
1348           } else {
1349             TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1350           }
1351           handledPath = TRUE;
1352       } else if (handledPath==FALSE) {
1353           fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1354           GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1355           handledPath = TRUE;
1356           TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1357       }
1358   }
1359   SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1360   TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1361 
1362   /* Must the open as read only check box be checked ?*/
1363   if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1364   {
1365     SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1366   }
1367 
1368   /* Must the open as read only check box be hidden? */
1369   if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1370   {
1371     ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1372     EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1373   }
1374 
1375   /* Must the help button be hidden? */
1376   if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1377   {
1378     ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1379     EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1380   }
1381 
1382   /* change Open to Save */
1383   if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1384   {
1385       WCHAR buf[16];
1386       LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1387       SetDlgItemTextW(hwnd, IDOK, buf);
1388       LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1389       SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1390   }
1391 
1392   /* Initialize the filter combo box */
1393   FILEDLG95_FILETYPE_Init(hwnd);
1394 
1395   return 0;
1396 }
1397 
1398 /***********************************************************************
1399  *      FILEDLG95_ResizeControls
1400  *
1401  * WM_INITDIALOG message handler (after hook notification)
1402  */
1403 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1404 {
1405   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1406 
1407   if (fodInfos->DlgInfos.hwndCustomDlg)
1408   {
1409     RECT rc;
1410     UINT flags = SWP_NOACTIVATE;
1411 
1412     ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1413         (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1414 
1415     /* resize the custom dialog to the parent size */
1416     if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1417       GetClientRect(hwnd, &rc);
1418     else
1419     {
1420       /* our own fake template is zero sized and doesn't have children, so
1421        * there is no need to resize it. Picasa depends on it.
1422        */
1423       flags |= SWP_NOSIZE;
1424       SetRectEmpty(&rc);
1425     }
1426       SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1427           0, 0, rc.right, rc.bottom, flags);
1428   }
1429   else
1430   {
1431     /* Resize the height, if open as read only checkbox ad help button are
1432      * hidden and we are not using a custom template nor a customDialog
1433      */
1434     if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1435                 (!(fodInfos->ofnInfos->Flags &
1436                    (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1437     {
1438       RECT rectDlg, rectHelp, rectCancel;
1439       GetWindowRect(hwnd, &rectDlg);
1440       GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1441       GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1442       /* subtract the height of the help button plus the space between the help
1443        * button and the cancel button to the height of the dialog
1444        */
1445       SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1446           (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1447           SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1448     }
1449   }
1450   return TRUE;
1451 }
1452 
1453 /***********************************************************************
1454  *      FILEDLG95_FillControls
1455  *
1456  * WM_INITDIALOG message handler (after hook notification)
1457  */
1458 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1459 {
1460   LPITEMIDLIST pidlItemId = NULL;
1461 
1462   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1463 
1464   TRACE("dir=%s file=%s\n",
1465   debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1466 
1467   /* Get the initial directory pidl */
1468 
1469   if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1470   {
1471     WCHAR path[MAX_PATH];
1472 
1473     GetCurrentDirectoryW(MAX_PATH,path);
1474     pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1475   }
1476 
1477   /* Initialise shell objects */
1478   FILEDLG95_SHELL_Init(hwnd);
1479 
1480   /* Initialize the Look In combo box */
1481   FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1482 
1483   /* Browse to the initial directory */
1484   IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1485 
1486   /* Free pidlItem memory */
1487   COMDLG32_SHFree(pidlItemId);
1488 
1489   return TRUE;
1490 }
1491 /***********************************************************************
1492  *      FILEDLG95_Clean
1493  *
1494  * Regroups all the cleaning functions of the filedlg
1495  */
1496 void FILEDLG95_Clean(HWND hwnd)
1497 {
1498       FILEDLG95_FILETYPE_Clean(hwnd);
1499       FILEDLG95_LOOKIN_Clean(hwnd);
1500       FILEDLG95_SHELL_Clean(hwnd);
1501 }
1502 /***********************************************************************
1503  *      FILEDLG95_OnWMCommand
1504  *
1505  * WM_COMMAND message handler
1506  */
1507 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1508 {
1509   WORD wNotifyCode = HIWORD(wParam); /* notification code */
1510   WORD wID = LOWORD(wParam);         /* item, control, or accelerator identifier */
1511   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1512 
1513   switch(wID)
1514   {
1515     /* OK button */
1516   case IDOK:
1517     FILEDLG95_OnOpen(hwnd);
1518     break;
1519     /* Cancel button */
1520   case IDCANCEL:
1521     FILEDLG95_Clean(hwnd);
1522     EndDialog(hwnd, FALSE);
1523     break;
1524     /* Filetype combo box */
1525   case IDC_FILETYPE:
1526     FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1527     break;
1528     /* LookIn combo box */
1529   case IDC_LOOKIN:
1530     FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1531     break;
1532 
1533   /* --- toolbar --- */
1534     /* Up folder button */
1535   case FCIDM_TB_UPFOLDER:
1536     FILEDLG95_SHELL_UpFolder(hwnd);
1537     break;
1538     /* New folder button */
1539   case FCIDM_TB_NEWFOLDER:
1540     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1541     break;
1542     /* List option button */
1543   case FCIDM_TB_SMALLICON:
1544     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1545     break;
1546     /* Details option button */
1547   case FCIDM_TB_REPORTVIEW:
1548     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1549     break;
1550     /* Details option button */
1551   case FCIDM_TB_DESKTOP:
1552     FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1553     break;
1554 
1555   case IDC_FILENAME:
1556     break;
1557 
1558   }
1559   /* Do not use the listview selection anymore */
1560   fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1561   return 0;
1562 }
1563 
1564 /***********************************************************************
1565  *      FILEDLG95_OnWMGetIShellBrowser
1566  *
1567  * WM_GETISHELLBROWSER message handler
1568  */
1569 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1570 {
1571   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1572 
1573   TRACE("\n");
1574 
1575   SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1576 
1577   return TRUE;
1578 }
1579 
1580 
1581 /***********************************************************************
1582  *      FILEDLG95_SendFileOK
1583  *
1584  * Sends the CDN_FILEOK notification if required
1585  *
1586  * RETURNS
1587  *  TRUE if the dialog should close
1588  *  FALSE if the dialog should not be closed
1589  */
1590 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1591 {
1592     /* ask the hook if we can close */
1593     if(IsHooked(fodInfos))
1594     {
1595         LRESULT retval;
1596 
1597         TRACE("---\n");
1598         /* First send CDN_FILEOK as MSDN doc says */
1599         retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1600         if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1601         {
1602             TRACE("canceled\n");
1603             return (retval == 0);
1604         }
1605 
1606         /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1607         retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1608                               fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1609         if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1610         {
1611             TRACE("canceled\n");
1612             return (retval == 0);
1613         }
1614     }
1615     return TRUE;
1616 }
1617 
1618 /***********************************************************************
1619  *      FILEDLG95_OnOpenMultipleFiles
1620  *
1621  * Handles the opening of multiple files.
1622  *
1623  * FIXME
1624  *  check destination buffer size
1625  */
1626 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1627 {
1628   WCHAR   lpstrPathSpec[MAX_PATH] = {0};
1629   UINT   nCount, nSizePath;
1630   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1631 
1632   TRACE("\n");
1633 
1634   if(fodInfos->unicode)
1635   {
1636      LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1637      ofn->lpstrFile[0] = '\0';
1638   }
1639   else
1640   {
1641      LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1642      ofn->lpstrFile[0] = '\0';
1643   }
1644 
1645   COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1646 
1647   if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1648       ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1649        ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1650   {
1651     LPWSTR lpstrTemp = lpstrFileList;
1652 
1653     for ( nCount = 0; nCount < nFileCount; nCount++ )
1654     {
1655       LPITEMIDLIST pidl;
1656 
1657       pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1658       if (!pidl)
1659       {
1660         WCHAR lpstrNotFound[100];
1661         WCHAR lpstrMsg[100];
1662         WCHAR tmp[400];
1663         static const WCHAR nl[] = {'\n',0};
1664 
1665         LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1666         LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1667 
1668         lstrcpyW(tmp, lpstrTemp);
1669         lstrcatW(tmp, nl);
1670         lstrcatW(tmp, lpstrNotFound);
1671         lstrcatW(tmp, nl);
1672         lstrcatW(tmp, lpstrMsg);
1673 
1674         MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1675         return FALSE;
1676       }
1677 
1678       /* move to the next file in the list of files */
1679       lpstrTemp += lstrlenW(lpstrTemp) + 1;
1680       COMDLG32_SHFree(pidl);
1681     }
1682   }
1683 
1684   nSizePath = lstrlenW(lpstrPathSpec) + 1;
1685   if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1686   {
1687     /* For "oldstyle" dialog the components have to
1688        be separated by blanks (not '\0'!) and short
1689        filenames have to be used! */
1690     FIXME("Components have to be separated by blanks\n");
1691   }
1692   if(fodInfos->unicode)
1693   {
1694     LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1695     lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1696     memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1697   }
1698   else
1699   {
1700     LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1701 
1702     if (ofn->lpstrFile != NULL)
1703     {
1704       nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1705                           ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1706       if (ofn->nMaxFile > nSizePath)
1707       {
1708         WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1709                             ofn->lpstrFile + nSizePath,
1710                             ofn->nMaxFile - nSizePath, NULL, NULL);
1711       }
1712     }
1713   }
1714 
1715   fodInfos->ofnInfos->nFileOffset = nSizePath;
1716   fodInfos->ofnInfos->nFileExtension = 0;
1717 
1718   if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1719     return FALSE;
1720 
1721   /* clean and exit */
1722   FILEDLG95_Clean(hwnd);
1723   return EndDialog(hwnd,TRUE);
1724 }
1725 
1726 /***********************************************************************
1727  *      FILEDLG95_OnOpen
1728  *
1729  * Ok button WM_COMMAND message handler
1730  *
1731  * If the function succeeds, the return value is nonzero.
1732  */
1733 #define ONOPEN_BROWSE 1
1734 #define ONOPEN_OPEN   2
1735 #define ONOPEN_SEARCH 3
1736 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1737 {
1738   WCHAR strMsgTitle[MAX_PATH];
1739   WCHAR strMsgText [MAX_PATH];
1740   if (idCaption)
1741     LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1742   else
1743     strMsgTitle[0] = '\0';
1744   LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1745   MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1746 }
1747 
1748 BOOL FILEDLG95_OnOpen(HWND hwnd)
1749 {
1750   LPWSTR lpstrFileList;
1751   UINT nFileCount = 0;
1752   UINT sizeUsed = 0;
1753   BOOL ret = TRUE;
1754   WCHAR lpstrPathAndFile[MAX_PATH];
1755   WCHAR lpstrTemp[MAX_PATH];
1756   LPSHELLFOLDER lpsf = NULL;
1757   int nOpenAction;
1758   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1759 
1760   TRACE("hwnd=%p\n", hwnd);
1761 
1762   /* get the files from the edit control */
1763   nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1764 
1765   /* try if the user selected a folder in the shellview */
1766   if(nFileCount == 0)
1767   {
1768       BrowseSelectedFolder(hwnd);
1769       return FALSE;
1770   }
1771 
1772   if(nFileCount > 1)
1773   {
1774       ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1775       goto ret;
1776   }
1777 
1778   TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1779 
1780 /*
1781   Step 1:  Build a complete path name from the current folder and
1782   the filename or path in the edit box.
1783   Special cases:
1784   - the path in the edit box is a root path
1785     (with or without drive letter)
1786   - the edit box contains ".." (or a path with ".." in it)
1787 */
1788 
1789   /* Get the current directory name */
1790   if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1791   {
1792     /* last fallback */
1793     GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1794   }
1795   PathAddBackslashW(lpstrPathAndFile);
1796 
1797   TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1798 
1799   /* if the user specified a fully qualified path use it */
1800   if(PathIsRelativeW(lpstrFileList))
1801   {
1802     lstrcatW(lpstrPathAndFile, lpstrFileList);
1803   }
1804   else
1805   {
1806     /* does the path have a drive letter? */
1807     if (PathGetDriveNumberW(lpstrFileList) == -1)
1808       lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1809     else
1810       lstrcpyW(lpstrPathAndFile, lpstrFileList);
1811   }
1812 
1813   /* resolve "." and ".." */
1814   PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1815   lstrcpyW(lpstrPathAndFile, lpstrTemp);
1816   TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1817 
1818   MemFree(lpstrFileList);
1819 
1820 /*
1821   Step 2: here we have a cleaned up path
1822 
1823   We have to parse the path step by step to see if we have to browse
1824   to a folder if the path points to a directory or the last
1825   valid element is a directory.
1826 
1827   valid variables:
1828     lpstrPathAndFile: cleaned up path
1829  */
1830 
1831   if (nFileCount &&
1832       (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1833       !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1834     nOpenAction = ONOPEN_OPEN;
1835   else
1836     nOpenAction = ONOPEN_BROWSE;
1837 
1838   /* don't apply any checks with OFN_NOVALIDATE */
1839   {
1840     LPWSTR lpszTemp, lpszTemp1;
1841     LPITEMIDLIST pidl = NULL;
1842     static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1843 
1844     /* check for invalid chars */
1845     if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1846     {
1847       FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1848       ret = FALSE;
1849       goto ret;
1850     }
1851 
1852     if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1853 
1854     lpszTemp1 = lpszTemp = lpstrPathAndFile;
1855     while (lpszTemp1)
1856     {
1857       LPSHELLFOLDER lpsfChild;
1858       WCHAR lpwstrTemp[MAX_PATH];
1859       DWORD dwEaten, dwAttributes;
1860       LPWSTR p;
1861 
1862       lstrcpyW(lpwstrTemp, lpszTemp);
1863       p = PathFindNextComponentW(lpwstrTemp);
1864 
1865       if (!p) break; /* end of path */
1866 
1867       *p = 0;
1868       lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1869 
1870       /* There are no wildcards when OFN_NOVALIDATE is set */
1871       if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1872       {
1873         static const WCHAR wszWild[] = { '*', '?', 0 };
1874         /* if the last element is a wildcard do a search */
1875         if(strpbrkW(lpszTemp1, wszWild) != NULL)
1876         {
1877           nOpenAction = ONOPEN_SEARCH;
1878           break;
1879         }
1880       }
1881       lpszTemp1 = lpszTemp;
1882 
1883       TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1884 
1885       /* append a backslash to drive letters */
1886       if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' && 
1887          ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1888           (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z'))) 
1889       {
1890         PathAddBackslashW(lpwstrTemp);
1891       }
1892 
1893       dwAttributes = SFGAO_FOLDER;
1894       if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1895       {
1896         /* the path component is valid, we have a pidl of the next path component */
1897         TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1898         if(dwAttributes & SFGAO_FOLDER)
1899         {
1900           if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1901           {
1902             ERR("bind to failed\n"); /* should not fail */
1903             break;
1904           }
1905           IShellFolder_Release(lpsf);
1906           lpsf = lpsfChild;
1907           lpsfChild = NULL;
1908         }
1909         else
1910         {
1911           TRACE("value\n");
1912 
1913           /* end dialog, return value */
1914           nOpenAction = ONOPEN_OPEN;
1915           break;
1916         }
1917         COMDLG32_SHFree(pidl);
1918         pidl = NULL;
1919       }
1920       else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1921       {
1922         if(*lpszTemp || /* points to trailing null for last path element */
1923            (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
1924         {
1925           if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1926           {
1927             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1928             break;
1929           }
1930         }
1931         else
1932         {
1933           if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1934              !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1935           {
1936             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1937             break;
1938           }
1939         }
1940         /* change to the current folder */
1941         nOpenAction = ONOPEN_OPEN;
1942         break;
1943       }
1944       else
1945       {
1946         nOpenAction = ONOPEN_OPEN;
1947         break;
1948       }
1949     }
1950     if(pidl) COMDLG32_SHFree(pidl);
1951   }
1952 
1953 /*
1954   Step 3: here we have a cleaned up and validated path
1955 
1956   valid variables:
1957    lpsf:             ShellFolder bound to the rightmost valid path component
1958    lpstrPathAndFile: cleaned up path
1959    nOpenAction:      action to do
1960 */
1961   TRACE("end validate sf=%p\n", lpsf);
1962 
1963   switch(nOpenAction)
1964   {
1965     case ONOPEN_SEARCH:   /* set the current filter to the file mask and refresh */
1966       TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1967       {
1968         int iPos;
1969         LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1970         DWORD len;
1971 
1972         /* replace the current filter */
1973         MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
1974         len = lstrlenW(lpszTemp)+1;
1975         fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1976         lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1977 
1978         /* set the filter cb to the extension when possible */
1979         if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1980         CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1981       }
1982       /* fall through */
1983     case ONOPEN_BROWSE:   /* browse to the highest folder we could bind to */
1984       TRACE("ONOPEN_BROWSE\n");
1985       {
1986         IPersistFolder2 * ppf2;
1987         if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1988         {
1989           LPITEMIDLIST pidlCurrent;
1990           IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1991           IPersistFolder2_Release(ppf2);
1992           if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1993           {
1994             if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
1995             {
1996               SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
1997             }
1998           }
1999           else if( nOpenAction == ONOPEN_SEARCH )
2000           {
2001             if (fodInfos->Shell.FOIShellView)
2002               IShellView_Refresh(fodInfos->Shell.FOIShellView);
2003           }
2004           COMDLG32_SHFree(pidlCurrent);
2005           SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2006         }
2007       }
2008       ret = FALSE;
2009       break;
2010     case ONOPEN_OPEN:   /* fill in the return struct and close the dialog */
2011       TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2012       {
2013         WCHAR *ext = NULL;
2014 
2015         /* update READONLY check box flag */
2016         if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2017           fodInfos->ofnInfos->Flags |= OFN_READONLY;
2018         else
2019           fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2020 
2021         /* Attach the file extension with file name*/
2022         ext = PathFindExtensionW(lpstrPathAndFile);
2023         if (! *ext)
2024         {
2025             /* if no extension is specified with file name, then */
2026             /* attach the extension from file filter or default one */
2027             
2028             WCHAR *filterExt = NULL;
2029             LPWSTR lpstrFilter = NULL;
2030             static const WCHAR szwDot[] = {'.',0};
2031             int PathLength = lstrlenW(lpstrPathAndFile);
2032 
2033             /* Attach the dot*/
2034             lstrcatW(lpstrPathAndFile, szwDot);
2035     
2036             /*Get the file extension from file type filter*/
2037             lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2038                                              fodInfos->ofnInfos->nFilterIndex-1);
2039 
2040             if (lpstrFilter != (LPWSTR)CB_ERR)  /* control is not empty */
2041                 filterExt = PathFindExtensionW(lpstrFilter);
2042 
2043             if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2044                 lstrcatW(lpstrPathAndFile, filterExt + 1);
2045             else if ( fodInfos->defext ) /* attach the default file extension*/
2046                 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2047 
2048             /* In Open dialog: if file does not exist try without extension */
2049             if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2050                   lpstrPathAndFile[PathLength] = '\0';
2051         }
2052 
2053         if (fodInfos->defext) /* add default extension */
2054         {
2055           /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2056           if (*ext)
2057             ext++;
2058           if (!lstrcmpiW(fodInfos->defext, ext))
2059             fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2060           else
2061             fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2062         }
2063 
2064         /* In Save dialog: check if the file already exists */
2065         if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2066             && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2067             && PathFileExistsW(lpstrPathAndFile))
2068         {
2069           WCHAR lpstrOverwrite[100];
2070           int answer;
2071 
2072           LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2073           answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2074                                MB_YESNO | MB_ICONEXCLAMATION);
2075           if (answer == IDNO)
2076           {
2077             ret = FALSE;
2078             goto ret;
2079           }
2080         }
2081 
2082         /* In Open dialog: check if it should be created if it doesn't exist */
2083         if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2084             && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2085             && !PathFileExistsW(lpstrPathAndFile))
2086         {
2087           WCHAR lpstrCreate[100];
2088           int answer;
2089 
2090           LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2091           answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2092                                MB_YESNO | MB_ICONEXCLAMATION);
2093           if (answer == IDNO)
2094           {
2095             ret = FALSE;
2096             goto ret;
2097           }
2098         }
2099 
2100         /* Check that the size of the file does not exceed buffer size.
2101              (Allow for extra \0 if OFN_MULTISELECT is set.) */
2102         if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2103             ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2104         {
2105 
2106           /* fill destination buffer */
2107           if (fodInfos->ofnInfos->lpstrFile)
2108           {
2109              if(fodInfos->unicode)
2110              {
2111                LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2112 
2113                lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2114                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2115                  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2116              }
2117              else
2118              {
2119                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2120 
2121                WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2122                                    ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2123                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2124                  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2125              }
2126           }
2127 
2128           if(fodInfos->unicode)
2129           {
2130               LPWSTR lpszTemp;
2131 
2132               /* set filename offset */
2133               lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2134               fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2135 
2136               /* set extension offset */
2137               lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2138               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2139           }
2140           else
2141           {
2142                LPSTR lpszTemp;
2143                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2144 
2145               /* set filename offset */
2146               lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2147               fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2148 
2149               /* set extension offset */
2150               lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2151               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2152           }
2153 
2154           /* set the lpstrFileTitle */
2155           if(fodInfos->ofnInfos->lpstrFileTitle)
2156           {
2157             LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2158             if(fodInfos->unicode)
2159             {
2160               LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2161               lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2162             }
2163             else
2164             {
2165               LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2166               WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2167                     ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2168             }
2169           }
2170 
2171           /* copy currently selected filter to lpstrCustomFilter */
2172           if (fodInfos->ofnInfos->lpstrCustomFilter)
2173           {
2174             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2175             int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2176                                           NULL, 0, NULL, NULL);
2177             if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2178             {
2179               LPSTR s = ofn->lpstrCustomFilter;
2180               s += strlen(ofn->lpstrCustomFilter)+1;
2181               WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2182                                   s, len, NULL, NULL);
2183             }
2184           }
2185 
2186 
2187           if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2188               goto ret;
2189 
2190           TRACE("close\n");
2191           FILEDLG95_Clean(hwnd);
2192           ret = EndDialog(hwnd, TRUE);
2193         }
2194         else
2195         {
2196           WORD size;
2197 
2198           size = lstrlenW(lpstrPathAndFile) + 1;
2199           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2200              size += 1;
2201           /* return needed size in first two bytes of lpstrFile */
2202           *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2203           FILEDLG95_Clean(hwnd);
2204           ret = EndDialog(hwnd, FALSE);
2205           COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2206         }
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(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, 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(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( 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 static 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 static 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  */
<