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