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