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