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