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