gdiplus: Stub GdipGetHemfFromMetafile.
[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)/sizeof(module_path[0]))) {
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)/sizeof(module_path[0]))) {
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             const WCHAR *filterExt = NULL;
2478             LPWSTR lpstrFilter = NULL;
2479             static const WCHAR szwDot[] = {'.',0};
2480             int PathLength = lstrlenW(lpstrPathAndFile);
2481
2482             /*Get the file extension from file type filter*/
2483             lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2484                                              fodInfos->ofnInfos->nFilterIndex-1);
2485
2486             if (lpstrFilter != (LPWSTR)CB_ERR)  /* control is not empty */
2487                 filterExt = PathFindExtensionW(lpstrFilter);
2488
2489             if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2490                 filterExt = filterExt + 1;
2491             else if ( fodInfos->defext ) /* attach the default file extension*/
2492                 filterExt = fodInfos->defext;
2493
2494             /* If extension is .*, ignore it */
2495             if (filterExt[0] != '*')
2496             {
2497                 /* Attach the dot*/
2498                 lstrcatW(lpstrPathAndFile, szwDot);
2499                 /* Attach the extension */
2500                 lstrcatW(lpstrPathAndFile, filterExt );
2501             }
2502
2503             /* In Open dialog: if file does not exist try without extension */
2504             if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2505                   lpstrPathAndFile[PathLength] = '\0';
2506         }
2507
2508         if (fodInfos->defext) /* add default extension */
2509         {
2510           /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2511           if (*ext)
2512             ext++;
2513           if (!lstrcmpiW(fodInfos->defext, ext))
2514             fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2515           else
2516             fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2517         }
2518
2519         /* In Save dialog: check if the file already exists */
2520         if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2521             && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2522             && PathFileExistsW(lpstrPathAndFile))
2523         {
2524           WCHAR lpstrOverwrite[100];
2525           int answer;
2526
2527           LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2528           answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2529                                MB_YESNO | MB_ICONEXCLAMATION);
2530           if (answer == IDNO || answer == IDCANCEL)
2531           {
2532             ret = FALSE;
2533             goto ret;
2534           }
2535         }
2536
2537         /* In Open dialog: check if it should be created if it doesn't exist */
2538         if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2539             && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2540             && !PathFileExistsW(lpstrPathAndFile))
2541         {
2542           WCHAR lpstrCreate[100];
2543           int answer;
2544
2545           LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2546           answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2547                                MB_YESNO | MB_ICONEXCLAMATION);
2548           if (answer == IDNO || answer == IDCANCEL)
2549           {
2550             ret = FALSE;
2551             goto ret;
2552           }
2553         }
2554
2555         /* Check that the size of the file does not exceed buffer size.
2556              (Allow for extra \0 if OFN_MULTISELECT is set.) */
2557         if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2558             ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2559         {
2560
2561           /* fill destination buffer */
2562           if (fodInfos->ofnInfos->lpstrFile)
2563           {
2564              if(fodInfos->unicode)
2565              {
2566                LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2567
2568                lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2569                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2570                  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2571              }
2572              else
2573              {
2574                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2575
2576                WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2577                                    ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2578                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2579                  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2580              }
2581           }
2582
2583           if(fodInfos->unicode)
2584           {
2585               LPWSTR lpszTemp;
2586
2587               /* set filename offset */
2588               lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2589               fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2590
2591               /* set extension offset */
2592               lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2593               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2594           }
2595           else
2596           {
2597                LPSTR lpszTemp;
2598                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2599
2600               /* set filename offset */
2601               lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2602               fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2603
2604               /* set extension offset */
2605               lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2606               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2607           }
2608
2609           /* set the lpstrFileTitle */
2610           if(fodInfos->ofnInfos->lpstrFileTitle)
2611           {
2612             LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2613             if(fodInfos->unicode)
2614             {
2615               LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2616               lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2617             }
2618             else
2619             {
2620               LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2621               WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2622                     ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2623             }
2624           }
2625
2626           /* copy currently selected filter to lpstrCustomFilter */
2627           if (fodInfos->ofnInfos->lpstrCustomFilter)
2628           {
2629             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2630             int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2631                                           NULL, 0, NULL, NULL);
2632             if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2633             {
2634               LPSTR s = ofn->lpstrCustomFilter;
2635               s += strlen(ofn->lpstrCustomFilter)+1;
2636               WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2637                                   s, len, NULL, NULL);
2638             }
2639           }
2640
2641
2642           if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2643               goto ret;
2644
2645           FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2646
2647           TRACE("close\n");
2648           FILEDLG95_Clean(hwnd);
2649           ret = EndDialog(hwnd, TRUE);
2650         }
2651         else
2652         {
2653           WORD size;
2654
2655           size = lstrlenW(lpstrPathAndFile) + 1;
2656           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2657              size += 1;
2658           /* return needed size in first two bytes of lpstrFile */
2659           *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2660           FILEDLG95_Clean(hwnd);
2661           ret = EndDialog(hwnd, FALSE);
2662           COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2663         }
2664       }
2665       break;
2666   }
2667
2668 ret:
2669   if(lpsf) IShellFolder_Release(lpsf);
2670   return ret;
2671 }
2672
2673 /***********************************************************************
2674  *      FILEDLG95_SHELL_Init
2675  *
2676  * Initialisation of the shell objects
2677  */
2678 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2679 {
2680   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2681
2682   TRACE("\n");
2683
2684   /*
2685    * Initialisation of the FileOpenDialogInfos structure
2686    */
2687
2688   /* Shell */
2689
2690   /*ShellInfos */
2691   fodInfos->ShellInfos.hwndOwner = hwnd;
2692
2693   /* Disable multi-select if flag not set */
2694   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2695   {
2696      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2697   }
2698   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2699   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2700
2701   /* Construct the IShellBrowser interface */
2702   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2703
2704   return NOERROR;
2705 }
2706
2707 /***********************************************************************
2708  *      FILEDLG95_SHELL_ExecuteCommand
2709  *
2710  * Change the folder option and refresh the view
2711  * If the function succeeds, the return value is nonzero.
2712  */
2713 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2714 {
2715   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2716   IContextMenu * pcm;
2717
2718   TRACE("(%p,%p)\n", hwnd, lpVerb);
2719
2720   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2721                                         SVGIO_BACKGROUND,
2722                                         &IID_IContextMenu,
2723                                         (LPVOID*)&pcm)))
2724   {
2725     CMINVOKECOMMANDINFO ci;
2726     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2727     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2728     ci.lpVerb = lpVerb;
2729     ci.hwnd = hwnd;
2730
2731     IContextMenu_InvokeCommand(pcm, &ci);
2732     IContextMenu_Release(pcm);
2733   }
2734
2735   return FALSE;
2736 }
2737
2738 /***********************************************************************
2739  *      FILEDLG95_SHELL_UpFolder
2740  *
2741  * Browse to the specified object
2742  * If the function succeeds, the return value is nonzero.
2743  */
2744 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2745 {
2746   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2747
2748   TRACE("\n");
2749
2750   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2751                                           NULL,
2752                                           SBSP_PARENT)))
2753   {
2754     if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2755         SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2756     return TRUE;
2757   }
2758   return FALSE;
2759 }
2760
2761 /***********************************************************************
2762  *      FILEDLG95_SHELL_BrowseToDesktop
2763  *
2764  * Browse to the Desktop
2765  * If the function succeeds, the return value is nonzero.
2766  */
2767 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2768 {
2769   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2770   LPITEMIDLIST pidl;
2771   HRESULT hres;
2772
2773   TRACE("\n");
2774
2775   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2776   hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2777   if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2778       SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2779   COMDLG32_SHFree(pidl);
2780   return SUCCEEDED(hres);
2781 }
2782 /***********************************************************************
2783  *      FILEDLG95_SHELL_Clean
2784  *
2785  * Cleans the memory used by shell objects
2786  */
2787 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2788 {
2789     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2790
2791     TRACE("\n");
2792
2793     COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2794
2795     /* clean Shell interfaces */
2796     if (fodInfos->Shell.FOIShellView)
2797     {
2798       IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2799       IShellView_Release(fodInfos->Shell.FOIShellView);
2800     }
2801     IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2802     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2803     if (fodInfos->Shell.FOIDataObject)
2804       IDataObject_Release(fodInfos->Shell.FOIDataObject);
2805 }
2806
2807 /***********************************************************************
2808  *      FILEDLG95_FILETYPE_Init
2809  *
2810  * Initialisation of the file type combo box
2811  */
2812 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2813 {
2814   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2815   int nFilters = 0;  /* number of filters */
2816   int nFilterIndexCB;
2817
2818   TRACE("\n");
2819
2820   if(fodInfos->customfilter)
2821   {
2822       /* customfilter has one entry...  title\0ext\0
2823        * Set first entry of combo box item with customfilter
2824        */
2825       LPWSTR  lpstrExt;
2826       LPCWSTR lpstrPos = fodInfos->customfilter;
2827
2828       /* Get the title */
2829       lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2830
2831       /* Copy the extensions */
2832       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
2833       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2834       lstrcpyW(lpstrExt,lpstrPos);
2835
2836       /* Add the item at the end of the combo */
2837       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2838       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2839       nFilters++;
2840   }
2841   if(fodInfos->filter)
2842   {
2843     LPCWSTR lpstrPos = fodInfos->filter;
2844
2845     for(;;)
2846     {
2847       /* filter is a list...  title\0ext\0......\0\0
2848        * Set the combo item text to the title and the item data
2849        *  to the ext
2850        */
2851       LPCWSTR lpstrDisplay;
2852       LPWSTR lpstrExt;
2853
2854       /* Get the title */
2855       if(! *lpstrPos) break;    /* end */
2856       lpstrDisplay = lpstrPos;
2857       lpstrPos += lstrlenW(lpstrPos) + 1;
2858
2859       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2860
2861       nFilters++;
2862
2863       /* Copy the extensions */
2864       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2865       lstrcpyW(lpstrExt,lpstrPos);
2866       lpstrPos += lstrlenW(lpstrPos) + 1;
2867
2868       /* Add the item at the end of the combo */
2869       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2870
2871       /* malformed filters are added anyway... */
2872       if (!*lpstrExt) break;
2873     }
2874   }
2875
2876   /*
2877    * Set the current filter to the one specified
2878    * in the initialisation structure
2879    */
2880   if (fodInfos->filter || fodInfos->customfilter)
2881   {
2882     LPWSTR lpstrFilter;
2883
2884     /* Check to make sure our index isn't out of bounds. */
2885     if ( fodInfos->ofnInfos->nFilterIndex >
2886          nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2887       fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2888
2889     /* set default filter index */
2890     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2891       fodInfos->ofnInfos->nFilterIndex = 1;
2892
2893     /* calculate index of Combo Box item */
2894     nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2895     if (fodInfos->customfilter == NULL)
2896       nFilterIndexCB--;
2897
2898     /* Set the current index selection. */
2899     CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2900
2901     /* Get the corresponding text string from the combo box. */
2902     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2903                                              nFilterIndexCB);
2904
2905     if ((INT_PTR)lpstrFilter == CB_ERR)  /* control is empty */
2906       lpstrFilter = NULL;
2907
2908     if(lpstrFilter)
2909     {
2910       DWORD len;
2911       CharLowerW(lpstrFilter); /* lowercase */
2912       len = lstrlenW(lpstrFilter)+1;
2913       fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2914       lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2915     }
2916   } else
2917       fodInfos->ofnInfos->nFilterIndex = 0;
2918   return S_OK;
2919 }
2920
2921 /***********************************************************************
2922  *      FILEDLG95_FILETYPE_OnCommand
2923  *
2924  * WM_COMMAND of the file type combo box
2925  * If the function succeeds, the return value is nonzero.
2926  */
2927 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2928 {
2929   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2930
2931   switch(wNotifyCode)
2932   {
2933     case CBN_SELENDOK:
2934     {
2935       LPWSTR lpstrFilter;
2936
2937       /* Get the current item of the filetype combo box */
2938       int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2939
2940       /* set the current filter index */
2941       fodInfos->ofnInfos->nFilterIndex = iItem +
2942         (fodInfos->customfilter == NULL ? 1 : 0);
2943
2944       /* Set the current filter with the current selection */
2945       MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2946
2947       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2948                                              iItem);
2949       if((INT_PTR)lpstrFilter != CB_ERR)
2950       {
2951           DWORD len;
2952           CharLowerW(lpstrFilter); /* lowercase */
2953           len = lstrlenW(lpstrFilter)+1;
2954           fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2955           lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2956           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2957               SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2958       }
2959
2960       /* Refresh the actual view to display the included items*/
2961       if (fodInfos->Shell.FOIShellView)
2962         IShellView_Refresh(fodInfos->Shell.FOIShellView);
2963     }
2964   }
2965   return FALSE;
2966 }
2967 /***********************************************************************
2968  *      FILEDLG95_FILETYPE_SearchExt
2969  *
2970  * searches for an extension in the filetype box
2971  */
2972 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2973 {
2974   int i, iCount = CBGetCount(hwnd);
2975
2976   TRACE("%s\n", debugstr_w(lpstrExt));
2977
2978   if(iCount != CB_ERR)
2979   {
2980     for(i=0;i<iCount;i++)
2981     {
2982       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2983           return i;
2984     }
2985   }
2986   return -1;
2987 }
2988
2989 /***********************************************************************
2990  *      FILEDLG95_FILETYPE_Clean
2991  *
2992  * Clean the memory used by the filetype combo box
2993  */
2994 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2995 {
2996   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2997   int iPos;
2998   int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2999
3000   TRACE("\n");
3001
3002   /* Delete each string of the combo and their associated data */
3003   if(iCount != CB_ERR)
3004   {
3005     for(iPos = iCount-1;iPos>=0;iPos--)
3006     {
3007       MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3008       CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3009     }
3010   }
3011   /* Current filter */
3012   MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3013
3014 }
3015
3016 /***********************************************************************
3017  *      FILEDLG95_LOOKIN_Init
3018  *
3019  * Initialisation of the look in combo box
3020  */
3021
3022 /* Small helper function, to determine if the unixfs shell extension is rooted 
3023  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 
3024  */
3025 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3026     HKEY hKey;
3027     static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3028         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3029         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3030         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3031         'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3032         '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3033         '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3034     
3035     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3036         return FALSE;
3037         
3038     RegCloseKey(hKey);
3039     return TRUE;
3040 }
3041
3042 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3043 {
3044   IShellFolder  *psfRoot, *psfDrives;
3045   IEnumIDList   *lpeRoot, *lpeDrives;
3046   LPITEMIDLIST  pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3047
3048   LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3049
3050   TRACE("\n");
3051
3052   liInfos->iMaxIndentation = 0;
3053
3054   SetPropA(hwndCombo, LookInInfosStr, liInfos);
3055
3056   /* set item height for both text field and listbox */
3057   CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
3058   CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
3059    
3060   /* Turn on the extended UI for the combo box like Windows does */
3061   CBSetExtendedUI(hwndCombo, TRUE);
3062
3063   /* Initialise data of Desktop folder */
3064   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3065   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3066   COMDLG32_SHFree(pidlTmp);
3067
3068   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3069
3070   SHGetDesktopFolder(&psfRoot);
3071
3072   if (psfRoot)
3073   {
3074     /* enumerate the contents of the desktop */
3075     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3076     {
3077       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3078       {
3079         FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3080
3081         /* If the unixfs extension is rooted, we don't expand the drives by default */
3082         if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 
3083         {
3084           /* special handling for CSIDL_DRIVES */
3085           if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3086           {
3087             if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3088             {
3089               /* enumerate the drives */
3090               if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3091               {
3092                 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3093                 {
3094                   pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3095                   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3096                   COMDLG32_SHFree(pidlAbsTmp);
3097                   COMDLG32_SHFree(pidlTmp1);
3098                 }
3099                 IEnumIDList_Release(lpeDrives);
3100               }
3101               IShellFolder_Release(psfDrives);
3102             }
3103           }
3104         }
3105
3106         COMDLG32_SHFree(pidlTmp);
3107       }
3108       IEnumIDList_Release(lpeRoot);
3109     }
3110     IShellFolder_Release(psfRoot);
3111   }
3112
3113   COMDLG32_SHFree(pidlDrives);
3114 }
3115
3116 /***********************************************************************
3117  *      FILEDLG95_LOOKIN_DrawItem
3118  *
3119  * WM_DRAWITEM message handler
3120  */
3121 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3122 {
3123   COLORREF crWin = GetSysColor(COLOR_WINDOW);
3124   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3125   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3126   RECT rectText;
3127   RECT rectIcon;
3128   SHFILEINFOW sfi;
3129   HIMAGELIST ilItemImage;
3130   int iIndentation;
3131   TEXTMETRICW tm;
3132   LPSFOLDER tmpFolder;
3133   LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
3134
3135   TRACE("\n");
3136
3137   if(pDIStruct->itemID == -1)
3138     return 0;
3139
3140   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3141                             pDIStruct->itemID)))
3142     return 0;
3143
3144
3145   if(pDIStruct->itemID == liInfos->uSelectedItem)
3146   {
3147     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3148                                                0,
3149                                                &sfi,
3150                                                sizeof (sfi),
3151                                                SHGFI_PIDL | SHGFI_SMALLICON |
3152                                                SHGFI_OPENICON | SHGFI_SYSICONINDEX    |
3153                                                SHGFI_DISPLAYNAME );
3154   }
3155   else
3156   {
3157     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3158                                                   0,
3159                                                   &sfi,
3160                                                   sizeof (sfi),
3161                                                   SHGFI_PIDL | SHGFI_SMALLICON |
3162                                                   SHGFI_SYSICONINDEX |
3163                                                   SHGFI_DISPLAYNAME);
3164   }
3165
3166   /* Is this item selected ? */
3167   if(pDIStruct->itemState & ODS_SELECTED)
3168   {
3169     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3170     SetBkColor(pDIStruct->hDC,crHighLight);
3171     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3172   }
3173   else
3174   {
3175     SetTextColor(pDIStruct->hDC,crText);
3176     SetBkColor(pDIStruct->hDC,crWin);
3177     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3178   }
3179
3180   /* Do not indent item if drawing in the edit of the combo */
3181   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3182   {
3183     iIndentation = 0;
3184     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3185                                                 0,
3186                                                 &sfi,
3187                                                 sizeof (sfi),
3188                                                 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
3189                                                 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME  );
3190
3191   }
3192   else
3193   {
3194     iIndentation = tmpFolder->m_iIndent;
3195   }
3196   /* Draw text and icon */
3197
3198   /* Initialise the icon display area */
3199   rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
3200   rectIcon.top = pDIStruct->rcItem.top;
3201   rectIcon.right = rectIcon.left + ICONWIDTH;
3202   rectIcon.bottom = pDIStruct->rcItem.bottom;
3203
3204   /* Initialise the text display area */
3205   GetTextMetricsW(pDIStruct->hDC, &tm);
3206   rectText.left = rectIcon.right;
3207   rectText.top =
3208           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3209   rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
3210   rectText.bottom =
3211           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3212
3213   /* Draw the icon from the image list */
3214   ImageList_Draw(ilItemImage,
3215                  sfi.iIcon,
3216                  pDIStruct->hDC,
3217                  rectIcon.left,
3218                  rectIcon.top,
3219                  ILD_TRANSPARENT );
3220
3221   /* Draw the associated text */
3222   if(sfi.szDisplayName)
3223     TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3224
3225
3226   return NOERROR;
3227 }
3228
3229 /***********************************************************************
3230  *      FILEDLG95_LOOKIN_OnCommand
3231  *
3232  * LookIn combo box WM_COMMAND message handler
3233  * If the function succeeds, the return value is nonzero.
3234  */
3235 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3236 {
3237   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3238
3239   TRACE("%p\n", fodInfos);
3240
3241   switch(wNotifyCode)
3242   {
3243     case CBN_SELENDOK:
3244     {
3245       LPSFOLDER tmpFolder;
3246       int iItem;
3247
3248       iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3249
3250       if( iItem == CB_ERR) return FALSE;
3251
3252       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3253                                                iItem)))
3254         return FALSE;
3255
3256
3257       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3258                                               tmpFolder->pidlItem,
3259                                               SBSP_ABSOLUTE)))
3260       {
3261         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3262             SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3263         return TRUE;
3264       }
3265       break;
3266     }
3267
3268   }
3269   return FALSE;
3270 }
3271
3272 /***********************************************************************
3273  *      FILEDLG95_LOOKIN_AddItem
3274  *
3275  * Adds an absolute pidl item to the lookin combo box
3276  * returns the index of the inserted item
3277  */
3278 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3279 {
3280   LPITEMIDLIST pidlNext;
3281   SHFILEINFOW sfi;
3282   SFOLDER *tmpFolder;
3283   LookInInfos *liInfos;
3284
3285   TRACE("%08x\n", iInsertId);
3286
3287   if(!pidl)
3288     return -1;
3289
3290   if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3291     return -1;
3292
3293   tmpFolder = MemAlloc(sizeof(SFOLDER));
3294   tmpFolder->m_iIndent = 0;
3295
3296   /* Calculate the indentation of the item in the lookin*/
3297   pidlNext = pidl;
3298   while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3299   {
3300     tmpFolder->m_iIndent++;
3301   }
3302
3303   tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3304
3305   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3306     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3307
3308   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3309   SHGetFileInfoW((LPCWSTR)pidl,
3310                   0,
3311                   &sfi,
3312                   sizeof(sfi),
3313                   SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3314                   | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3315
3316   TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3317
3318   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3319   {
3320     int iItemID;
3321
3322     TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3323
3324     /* Add the item at the end of the list */
3325     if(iInsertId < 0)
3326     {
3327       iItemID = CBAddString(hwnd,sfi.szDisplayName);
3328     }
3329     /* Insert the item at the iInsertId position*/
3330     else
3331     {
3332       iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3333     }
3334
3335     CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3336     return iItemID;
3337   }
3338
3339   COMDLG32_SHFree( tmpFolder->pidlItem );
3340   MemFree( tmpFolder );
3341   return -1;
3342
3343 }
3344
3345 /***********************************************************************
3346  *      FILEDLG95_LOOKIN_InsertItemAfterParent
3347  *
3348  * Insert an item below its parent
3349  */
3350 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3351 {
3352
3353   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3354   int iParentPos;
3355
3356   TRACE("\n");
3357
3358   if (pidl == pidlParent)
3359     return -1;
3360
3361   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3362
3363   if(iParentPos < 0)
3364   {
3365     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3366   }
3367
3368   /* Free pidlParent memory */
3369   COMDLG32_SHFree(pidlParent);
3370
3371   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3372 }
3373
3374 /***********************************************************************
3375  *      FILEDLG95_LOOKIN_SelectItem
3376  *
3377  * Adds an absolute pidl item to the lookin combo box
3378  * returns the index of the inserted item
3379  */
3380 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3381 {
3382   int iItemPos;
3383   LookInInfos *liInfos;
3384
3385   TRACE("\n");
3386
3387   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3388
3389   liInfos = GetPropA(hwnd,LookInInfosStr);
3390
3391   if(iItemPos < 0)
3392   {
3393     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3394     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3395   }
3396
3397   else
3398   {
3399     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3400     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3401     {
3402       int iRemovedItem;
3403
3404       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3405         break;
3406       if(iRemovedItem < iItemPos)
3407         iItemPos--;
3408     }
3409   }
3410
3411   CBSetCurSel(hwnd,iItemPos);
3412   liInfos->uSelectedItem = iItemPos;
3413
3414   return 0;
3415
3416 }
3417
3418 /***********************************************************************
3419  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
3420  *
3421  * Remove the item with an expansion level over iExpansionLevel
3422  */
3423 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3424 {
3425   int iItemPos;
3426   LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3427
3428   TRACE("\n");
3429
3430   if(liInfos->iMaxIndentation <= 2)
3431     return -1;
3432
3433   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3434   {
3435     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3436     COMDLG32_SHFree(tmpFolder->pidlItem);
3437     MemFree(tmpFolder);
3438     CBDeleteString(hwnd,iItemPos);
3439     liInfos->iMaxIndentation--;
3440
3441     return iItemPos;
3442   }
3443
3444   return -1;
3445 }
3446
3447 /***********************************************************************
3448  *      FILEDLG95_LOOKIN_SearchItem
3449  *
3450  * Search for pidl in the lookin combo box
3451  * returns the index of the found item
3452  */
3453 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3454 {
3455   int i = 0;
3456   int iCount = CBGetCount(hwnd);
3457
3458   TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3459
3460   if (iCount != CB_ERR)
3461   {
3462     for(;i<iCount;i++)
3463     {
3464       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3465
3466       if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3467         return i;
3468       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3469         return i;
3470     }
3471   }
3472
3473   return -1;
3474 }
3475
3476 /***********************************************************************
3477  *      FILEDLG95_LOOKIN_Clean
3478  *
3479  * Clean the memory used by the lookin combo box
3480  */
3481 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3482 {
3483     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3484     LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3485     int iPos;
3486     int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3487
3488     TRACE("\n");
3489
3490     /* Delete each string of the combo and their associated data */
3491     if (iCount != CB_ERR)
3492     {
3493       for(iPos = iCount-1;iPos>=0;iPos--)
3494       {
3495         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3496         COMDLG32_SHFree(tmpFolder->pidlItem);
3497         MemFree(tmpFolder);
3498         CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3499       }
3500     }
3501
3502     /* LookInInfos structure */
3503     MemFree(liInfos);
3504     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3505 }
3506
3507 /***********************************************************************
3508  * FILEDLG95_FILENAME_FillFromSelection
3509  *
3510  * fills the edit box from the cached DataObject
3511  */
3512 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3513 {
3514     FileOpenDlgInfos *fodInfos;
3515     LPITEMIDLIST      pidl;
3516     UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3517     WCHAR             lpstrTemp[MAX_PATH];
3518     LPWSTR            lpstrAllFile, lpstrCurrFile;
3519
3520     TRACE("\n");
3521     fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3522
3523     /* Count how many files we have */
3524     nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3525
3526     /* calculate the string length, count files */
3527     if (nFileSelected >= 1)
3528     {
3529       nLength += 3;     /* first and last quotes, trailing \0 */
3530       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3531       {
3532         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3533
3534         if (pidl)
3535         {
3536           /* get the total length of the selected file names */
3537           lpstrTemp[0] = '\0';
3538           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3539
3540           if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3541           {
3542             nLength += lstrlenW( lpstrTemp ) + 3;
3543             nFiles++;
3544           }
3545           COMDLG32_SHFree( pidl );
3546         }
3547       }
3548     }
3549
3550     /* allocate the buffer */
3551     if (nFiles <= 1) nLength = MAX_PATH;
3552     lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3553
3554     /* Generate the string for the edit control */
3555     if(nFiles >= 1)
3556     {
3557       lpstrCurrFile = lpstrAllFile;
3558       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3559       {
3560         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3561
3562         if (pidl)
3563         {
3564           /* get the file name */
3565           lpstrTemp[0] = '\0';
3566           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3567
3568           if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3569           {
3570             if ( nFiles > 1)
3571             {
3572               *lpstrCurrFile++ =  '\"';
3573               lstrcpyW( lpstrCurrFile, lpstrTemp );
3574               lpstrCurrFile += lstrlenW( lpstrTemp );
3575               *lpstrCurrFile++ = '\"';
3576               *lpstrCurrFile++ = ' ';
3577               *lpstrCurrFile = 0;
3578             }
3579             else
3580             {
3581               lstrcpyW( lpstrAllFile, lpstrTemp );
3582             }
3583           }
3584           COMDLG32_SHFree( pidl );
3585         }
3586       }
3587       SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3588        
3589       /* Select the file name like Windows does */ 
3590       SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3591     }
3592     HeapFree(GetProcessHeap(),0, lpstrAllFile );
3593 }
3594
3595
3596 /* copied from shell32 to avoid linking to it
3597  * Although shell32 is already linked the behaviour of exported StrRetToStrN
3598  * is dependent on whether emulated OS is unicode or not.
3599  */
3600 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3601 {
3602         switch (src->uType)
3603         {
3604           case STRRET_WSTR:
3605             lstrcpynW(dest, src->u.pOleStr, len);
3606             COMDLG32_SHFree(src->u.pOleStr);
3607             break;
3608
3609           case STRRET_CSTR:
3610             if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3611                   dest[len-1] = 0;
3612             break;
3613
3614           case STRRET_OFFSET:
3615             if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3616                   dest[len-1] = 0;
3617             break;
3618
3619           default:
3620             FIXME("unknown type %x!\n", src->uType);
3621             if (len) *dest = '\0';
3622             return E_FAIL;
3623         }
3624         return S_OK;
3625 }
3626
3627 /***********************************************************************
3628  * FILEDLG95_FILENAME_GetFileNames
3629  *
3630  * Copies the filenames to a delimited string list.
3631  * The delimiter is specified by the parameter 'separator',
3632  *  usually either a space or a nul
3633  */
3634 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3635 {
3636         FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3637         UINT nStrCharCount = 0; /* index in src buffer */
3638         UINT nFileIndex = 0;    /* index in dest buffer */
3639         UINT nFileCount = 0;    /* number of files */
3640         UINT nStrLen = 0;       /* length of string in edit control */
3641         LPWSTR lpstrEdit;       /* buffer for string from edit control */
3642
3643         TRACE("\n");
3644
3645         /* get the filenames from the edit control */
3646         nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3647         lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3648         GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3649
3650         TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3651
3652         /* we might get single filename without any '"',
3653          * so we need nStrLen + terminating \0 + end-of-list \0 */
3654         *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3655         *sizeUsed = 0;
3656
3657         /* build delimited file list from filenames */
3658         while ( nStrCharCount <= nStrLen )
3659         {
3660           if ( lpstrEdit[nStrCharCount]=='"' )
3661           {
3662             nStrCharCount++;
3663             while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3664             {
3665               (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3666               nStrCharCount++;
3667             }
3668             (*lpstrFileList)[nFileIndex++] = 0;
3669             nFileCount++;
3670           }
3671           nStrCharCount++;
3672         }
3673
3674         /* single, unquoted string */
3675         if ((nStrLen > 0) && (nFileIndex == 0) )
3676         {
3677           lstrcpyW(*lpstrFileList, lpstrEdit);
3678           nFileIndex = lstrlenW(lpstrEdit) + 1;
3679           nFileCount = 1;
3680         }
3681
3682         /* trailing \0 */
3683         (*lpstrFileList)[nFileIndex++] = '\0';
3684
3685         *sizeUsed = nFileIndex;
3686         MemFree(lpstrEdit);
3687         return nFileCount;
3688 }
3689
3690 #define SETDefFormatEtc(fe,cf,med) \
3691 { \
3692     (fe).cfFormat = cf;\
3693     (fe).dwAspect = DVASPECT_CONTENT; \
3694     (fe).ptd =NULL;\
3695     (fe).tymed = med;\
3696     (fe).lindex = -1;\
3697 };
3698
3699 /*
3700  * DATAOBJECT Helper functions
3701  */
3702
3703 /***********************************************************************
3704  * COMCTL32_ReleaseStgMedium
3705  *
3706  * like ReleaseStgMedium from ole32
3707  */
3708 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3709 {
3710       if(medium.pUnkForRelease)
3711       {
3712         IUnknown_Release(medium.pUnkForRelease);
3713       }
3714       else
3715       {
3716         GlobalUnlock(medium.u.hGlobal);
3717         GlobalFree(medium.u.hGlobal);
3718       }
3719 }
3720
3721 /***********************************************************************
3722  *          GetPidlFromDataObject
3723  *
3724  * Return pidl(s) by number from the cached DataObject
3725  *
3726  * nPidlIndex=0 gets the fully qualified root path
3727  */
3728 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3729 {
3730
3731     STGMEDIUM medium;
3732     FORMATETC formatetc;
3733     LPITEMIDLIST pidl = NULL;
3734
3735     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3736
3737     if (!doSelected)
3738         return NULL;
3739         
3740     /* Set the FORMATETC structure*/
3741     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3742
3743     /* Get the pidls from IDataObject */
3744     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3745     {
3746       LPIDA cida = GlobalLock(medium.u.hGlobal);
3747       if(nPidlIndex <= cida->cidl)
3748       {
3749         pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3750       }
3751       COMCTL32_ReleaseStgMedium(medium);
3752     }
3753     return pidl;
3754 }
3755
3756 /***********************************************************************
3757  *          GetNumSelected
3758  *
3759  * Return the number of selected items in the DataObject.
3760  *
3761 */
3762 static UINT GetNumSelected( IDataObject *doSelected )
3763 {
3764     UINT retVal = 0;
3765     STGMEDIUM medium;
3766     FORMATETC formatetc;
3767
3768     TRACE("sv=%p\n", doSelected);
3769
3770     if (!doSelected) return 0;
3771
3772     /* Set the FORMATETC structure*/
3773     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3774
3775     /* Get the pidls from IDataObject */
3776     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3777     {
3778       LPIDA cida = GlobalLock(medium.u.hGlobal);
3779       retVal = cida->cidl;
3780       COMCTL32_ReleaseStgMedium(medium);
3781       return retVal;
3782     }
3783     return 0;
3784 }
3785
3786 /*
3787  * TOOLS
3788  */
3789
3790 /***********************************************************************
3791  *      GetName
3792  *
3793  * Get the pidl's display name (relative to folder) and
3794  * put it in lpstrFileName.
3795  *
3796  * Return NOERROR on success,
3797  * E_FAIL otherwise
3798  */
3799
3800 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3801 {
3802   STRRET str;
3803   HRESULT hRes;
3804
3805   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3806
3807   if(!lpsf)
3808   {
3809     SHGetDesktopFolder(&lpsf);
3810     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3811     IShellFolder_Release(lpsf);
3812     return hRes;
3813   }
3814
3815   /* Get the display name of the pidl relative to the folder */
3816   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3817   {
3818       return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3819   }
3820   return E_FAIL;
3821 }
3822
3823 /***********************************************************************
3824  *      GetShellFolderFromPidl
3825  *
3826  * pidlRel is the item pidl relative
3827  * Return the IShellFolder of the absolute pidl
3828  */
3829 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3830 {
3831   IShellFolder *psf = NULL,*psfParent;
3832
3833   TRACE("%p\n", pidlAbs);
3834
3835   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3836   {
3837     psf = psfParent;
3838     if(pidlAbs && pidlAbs->mkid.cb)
3839     {
3840       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3841       {
3842         IShellFolder_Release(psfParent);
3843         return psf;
3844       }
3845     }
3846     /* return the desktop */
3847     return psfParent;
3848   }
3849   return NULL;
3850 }
3851
3852 /***********************************************************************
3853  *      GetParentPidl
3854  *
3855  * Return the LPITEMIDLIST to the parent of the pidl in the list
3856  */
3857 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3858 {
3859   LPITEMIDLIST pidlParent;
3860
3861   TRACE("%p\n", pidl);
3862
3863   pidlParent = COMDLG32_PIDL_ILClone(pidl);
3864   COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3865
3866   return pidlParent;
3867 }
3868
3869 /***********************************************************************
3870  *      GetPidlFromName
3871  *
3872  * returns the pidl of the file name relative to folder
3873  * NULL if an error occurred
3874  */
3875 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3876 {
3877   LPITEMIDLIST pidl = NULL;
3878   ULONG ulEaten;
3879
3880   TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3881
3882   if(!lpcstrFileName) return NULL;
3883   if(!*lpcstrFileName) return NULL;
3884
3885   if(!lpsf)
3886   {
3887     if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3888         IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3889         IShellFolder_Release(lpsf);
3890     }
3891   }
3892   else
3893   {
3894     IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3895   }
3896   return pidl;
3897 }
3898
3899 /*
3900 */
3901 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3902 {
3903         ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3904         HRESULT ret;
3905
3906         TRACE("%p, %p\n", psf, pidl);
3907
3908         ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3909
3910         TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3911         /* see documentation shell 4.1*/
3912         return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3913 }
3914
3915 /***********************************************************************
3916  *      BrowseSelectedFolder
3917  */
3918 static BOOL BrowseSelectedFolder(HWND hwnd)
3919 {
3920   BOOL bBrowseSelFolder = FALSE;
3921   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3922
3923   TRACE("\n");
3924
3925   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3926   {
3927       LPITEMIDLIST pidlSelection;
3928
3929       /* get the file selected */
3930       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3931       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3932       {
3933           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3934                          pidlSelection, SBSP_RELATIVE ) ) )
3935           {
3936                static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3937                                    ' ','n','o','t',' ','e','x','i','s','t',0};
3938                MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3939           }
3940           bBrowseSelFolder = TRUE;
3941           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3942               SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3943       }
3944       COMDLG32_SHFree( pidlSelection );
3945   }
3946
3947   return bBrowseSelFolder;
3948 }
3949
3950 /*
3951  * Memory allocation methods */
3952 static void *MemAlloc(UINT size)
3953 {
3954     return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3955 }
3956
3957 static void MemFree(void *mem)
3958 {
3959     HeapFree(GetProcessHeap(),0,mem);
3960 }
3961
3962 /*
3963  * Old-style (win3.1) dialogs */
3964
3965 /***********************************************************************
3966  *           FD32_GetTemplate                                  [internal]
3967  *
3968  * Get a template (or FALSE if failure) when 16 bits dialogs are used
3969  * by a 32 bits application
3970  *
3971  */
3972 BOOL FD32_GetTemplate(PFD31_DATA lfs)
3973 {
3974     LPOPENFILENAMEW ofnW = lfs->ofnW;
3975     LPOPENFILENAMEA ofnA = lfs->ofnA;
3976     HANDLE hDlgTmpl;
3977
3978     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3979     {
3980         if (!(lfs->template = LockResource( ofnW->hInstance )))
3981         {
3982             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3983             return FALSE;
3984         }
3985     }
3986     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3987     {
3988         HRSRC hResInfo;
3989         if (ofnA)
3990             hResInfo = FindResourceA(ofnA->hInstance,
3991                                  ofnA->lpTemplateName,
3992                                  (LPSTR)RT_DIALOG);
3993         else
3994             hResInfo = FindResourceW(ofnW->hInstance,
3995                                  ofnW->lpTemplateName,
3996                                  (LPWSTR)RT_DIALOG);
3997         if (!hResInfo)
3998         {
3999             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4000             return FALSE;
4001         }
4002         if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
4003                                 hResInfo)) ||
4004                     !(lfs->template = LockResource(hDlgTmpl)))
4005         {
4006             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4007             return FALSE;
4008         }
4009     } else { /* get it from internal Wine resource */
4010         HRSRC hResInfo;
4011         if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
4012              lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
4013         {
4014             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4015             return FALSE;
4016         }
4017         if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
4018                 !(lfs->template = LockResource( hDlgTmpl )))
4019         {
4020             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4021             return FALSE;
4022         }
4023     }
4024     return TRUE;
4025 }
4026
4027
4028 /***********************************************************************
4029  *                              FD32_WMMeasureItem           [internal]
4030  */
4031 static LONG FD32_WMMeasureItem(LPARAM lParam)
4032 {
4033     LPMEASUREITEMSTRUCT lpmeasure;
4034
4035     lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
4036     lpmeasure->itemHeight = FD31_GetFldrHeight();
4037     return TRUE;
4038 }
4039
4040
4041 /***********************************************************************
4042  *           FileOpenDlgProc                                    [internal]
4043  *      Used for open and save, in fact.
4044  */
4045 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
4046                                              WPARAM wParam, LPARAM lParam)
4047 {
4048     PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
4049
4050     TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
4051     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
4052         {
4053             INT_PTR lRet;
4054             lRet  = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
4055             if (lRet)
4056                 return lRet;         /* else continue message processing */
4057         }
4058     switch (wMsg)
4059     {
4060     case WM_INITDIALOG:
4061         return FD31_WMInitDialog(hWnd, wParam, lParam);
4062
4063     case WM_MEASUREITEM:
4064         return FD32_WMMeasureItem(lParam);
4065
4066     case WM_DRAWITEM:
4067         return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
4068
4069     case WM_COMMAND:
4070         return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
4071 #if 0
4072     case WM_CTLCOLOR:
4073          SetBkColor((HDC16)wParam, 0x00C0C0C0);
4074          switch (HIWORD(lParam))
4075          {
4076          case CTLCOLOR_BTN:
4077              SetTextColor((HDC16)wParam, 0x00000000);
4078              return hGRAYBrush;
4079         case CTLCOLOR_STATIC:
4080              SetTextColor((HDC16)wParam, 0x00000000);
4081              return hGRAYBrush;
4082         }
4083       break;
4084 #endif
4085     }
4086     return FALSE;
4087 }
4088
4089
4090 /***********************************************************************
4091  *           GetFileName31A                                 [internal]
4092  *
4093  * Creates a win31 style dialog box for the user to select a file to open/save.
4094  */
4095 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4096                            UINT dlgType /* type dialogue : open/save */
4097                            )
4098 {
4099     BOOL bRet = FALSE;
4100     PFD31_DATA lfs;
4101
4102     if (!lpofn || !FD31_Init()) return FALSE;
4103
4104     TRACE("ofn flags %08x\n", lpofn->Flags);
4105     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
4106     if (lfs)
4107     {
4108         bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4109                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
4110         FD31_DestroyPrivate(lfs);
4111     }
4112
4113     TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4114     return bRet;
4115 }
4116
4117 /***********************************************************************
4118  *           GetFileName31W                                 [internal]
4119  *
4120  * Creates a win31 style dialog box for the user to select a file to open/save
4121  */
4122 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4123                            UINT dlgType /* type dialogue : open/save */
4124                            )
4125 {
4126     BOOL bRet = FALSE;
4127     PFD31_DATA lfs;
4128
4129     if (!lpofn || !FD31_Init()) return FALSE;
4130
4131     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
4132     if (lfs)
4133     {
4134         bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4135                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
4136         FD31_DestroyPrivate(lfs);
4137     }
4138
4139     TRACE("file %s, file offset %d, ext offset %d\n",
4140           debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4141     return bRet;
4142 }
4143
4144 /* ------------------ APIs ---------------------- */
4145
4146 /***********************************************************************
4147  *            GetOpenFileNameA  (COMDLG32.@)
4148  *
4149  * Creates a dialog box for the user to select a file to open.
4150  *
4151  * RETURNS
4152  *    TRUE on success: user enters a valid file
4153  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4154  *
4155  */
4156 BOOL WINAPI GetOpenFileNameA(
4157         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4158 {
4159     BOOL win16look = FALSE;
4160
4161     TRACE("flags %08x\n", ofn->Flags);
4162
4163     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4164     if (ofn->Flags & OFN_FILEMUSTEXIST)
4165         ofn->Flags |= OFN_PATHMUSTEXIST;
4166
4167     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4168         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4169
4170     if (win16look)
4171         return GetFileName31A(ofn, OPEN_DIALOG);
4172     else
4173         return GetFileDialog95A(ofn, OPEN_DIALOG);
4174 }
4175
4176 /***********************************************************************
4177  *            GetOpenFileNameW (COMDLG32.@)
4178  *
4179  * Creates a dialog box for the user to select a file to open.
4180  *
4181  * RETURNS
4182  *    TRUE on success: user enters a valid file
4183  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4184  *
4185  */
4186 BOOL WINAPI GetOpenFileNameW(
4187         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4188 {
4189     BOOL win16look = FALSE;
4190
4191     TRACE("flags %08x\n", ofn->Flags);
4192
4193     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4194     if (ofn->Flags & OFN_FILEMUSTEXIST)
4195         ofn->Flags |= OFN_PATHMUSTEXIST;
4196
4197     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4198         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4199
4200     if (win16look)
4201         return GetFileName31W(ofn, OPEN_DIALOG);
4202     else
4203         return GetFileDialog95W(ofn, OPEN_DIALOG);
4204 }
4205
4206
4207 /***********************************************************************
4208  *            GetSaveFileNameA  (COMDLG32.@)
4209  *
4210  * Creates a dialog box for the user to select a file to save.
4211  *
4212  * RETURNS
4213  *    TRUE on success: user enters a valid file
4214  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4215  *
4216  */
4217 BOOL WINAPI GetSaveFileNameA(
4218         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4219 {
4220     BOOL win16look = FALSE;
4221
4222     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4223         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4224
4225     if (win16look)
4226         return GetFileName31A(ofn, SAVE_DIALOG);
4227     else
4228         return GetFileDialog95A(ofn, SAVE_DIALOG);
4229 }
4230
4231 /***********************************************************************
4232  *            GetSaveFileNameW  (COMDLG32.@)
4233  *
4234  * Creates a dialog box for the user to select a file to save.
4235  *
4236  * RETURNS
4237  *    TRUE on success: user enters a valid file
4238  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4239  *
4240  */
4241 BOOL WINAPI GetSaveFileNameW(
4242         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4243 {
4244     BOOL win16look = FALSE;
4245
4246     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4247         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4248
4249     if (win16look)
4250         return GetFileName31W(ofn, SAVE_DIALOG);
4251     else
4252         return GetFileDialog95W(ofn, SAVE_DIALOG);
4253 }
4254
4255 /***********************************************************************
4256  *      GetFileTitleA           (COMDLG32.@)
4257  *
4258  * See GetFileTitleW.
4259  */
4260 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4261 {
4262     int ret;
4263     UNICODE_STRING strWFile;
4264     LPWSTR lpWTitle;
4265
4266     RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4267     lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4268     ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4269     if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4270     RtlFreeUnicodeString( &strWFile );
4271     RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4272     return ret;
4273 }
4274
4275
4276 /***********************************************************************
4277  *      GetFileTitleW           (COMDLG32.@)
4278  *
4279  * Get the name of a file.
4280  *
4281  * PARAMS
4282  *  lpFile  [I] name and location of file
4283  *  lpTitle [O] returned file name
4284  *  cbBuf   [I] buffer size of lpTitle
4285  *
4286  * RETURNS
4287  *  Success: zero
4288  *  Failure: negative number.
4289  */
4290 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4291 {
4292         int i, len;
4293         static const WCHAR brkpoint[] = {'*','[',']',0};
4294         TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4295
4296         if(lpFile == NULL || lpTitle == NULL)
4297                 return -1;
4298
4299         len = lstrlenW(lpFile);
4300
4301         if (len == 0)
4302                 return -1;
4303
4304         if(strpbrkW(lpFile, brkpoint))
4305                 return -1;
4306
4307         len--;
4308
4309         if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4310                 return -1;
4311
4312         for(i = len; i >= 0; i--)
4313         {
4314                 if (lpFile[i] == '/' ||  lpFile[i] == '\\' ||  lpFile[i] == ':')
4315                 {
4316                         i++;
4317                         break;
4318                 }
4319         }
4320
4321         if(i == -1)
4322                 i++;
4323
4324         TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4325
4326         len = lstrlenW(lpFile+i)+1;
4327         if(cbBuf < len)
4328                 return len;
4329
4330         lstrcpyW(lpTitle, &lpFile[i]);
4331         return 0;
4332 }