xref: /reactos/dll/win32/comdlg32/filedlg.c (revision 98e8827a)
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         {
3103             LPWSTR filterExt = NULL, lpstrFilter = NULL, pch, pchNext;
3104             LPCWSTR the_ext = NULL;
3105             static const WCHAR szwDot[] = {'.',0};
3106             int PathLength = lstrlenW(lpstrPathAndFile);
3107 
3108             /* get filter extensions */
3109             lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3110                                                     fodInfos->ofnInfos->nFilterIndex - 1);
3111             if (lpstrFilter != (LPWSTR)CB_ERR)  /* control is not empty */
3112             {
3113                 LPWSTR filterSearchIndex, pchFirst = NULL;
3114                 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
3115                 if (filterExt)
3116                 {
3117                     strcpyW(filterExt, lpstrFilter);
3118 
3119                     if (ext && *ext)
3120                     {
3121                         /* find ext in filter */
3122                         for (pch = filterExt; pch && *pch; pch = pchNext)
3123                         {
3124                             filterSearchIndex = strchrW(pch, ';');
3125                             if (filterSearchIndex)
3126                             {
3127                                 filterSearchIndex[0] = 0;
3128                                 pchNext = filterSearchIndex + 1;
3129                             }
3130                             else
3131                             {
3132                                 pchNext = NULL;
3133                             }
3134 
3135                             while (*pch == '*' || *pch == '.' || *pch == '?')
3136                             {
3137                                 ++pch;
3138                             }
3139 
3140                             if (!pchFirst)
3141                                 pchFirst = pch;
3142 
3143                             if (lstrcmpiW(pch, &ext[1]) == 0)
3144                             {
3145                                 the_ext = pch;
3146                                 break;
3147                             }
3148                         }
3149 
3150                         /* use first one if not found */
3151                         if (!the_ext && pchFirst && *pchFirst)
3152                         {
3153                             the_ext = pchFirst;
3154                         }
3155                     }
3156                 }
3157             }
3158 
3159             if (!the_ext)
3160             {
3161                 /* use default extension if no extension in filter */
3162                 the_ext = fodInfos->defext;
3163             }
3164 
3165             if (the_ext && *the_ext && lstrcmpiW(&ext[1], the_ext) != 0)
3166             {
3167                 if (strlenW(lpstrPathAndFile) + 1 + strlenW(the_ext) + 1 <=
3168                     fodInfos->ofnInfos->nMaxFile)
3169                 {
3170                     /* append the dot */
3171                     lstrcatW(lpstrPathAndFile, szwDot);
3172                     /* append the extension */
3173                     lstrcatW(lpstrPathAndFile, the_ext);
3174                     /* update ext */
3175                     ext = PathFindExtensionW(lpstrPathAndFile);
3176                 }
3177             }
3178 
3179             heap_free(filterExt);
3180 
3181             /* In Open dialog: if file does not exist try without extension */
3182             if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
3183                 lpstrPathAndFile[PathLength] = 0;
3184 
3185             /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
3186             if (*ext)
3187                 ext++;
3188             if (!lstrcmpiW(fodInfos->defext, ext))
3189                 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
3190             else
3191                 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
3192         }
3193 
3194         /* update dialog data */
3195         SetWindowTextW(fodInfos->DlgInfos.hwndFileName, PathFindFileNameW(lpstrPathAndFile));
3196 #else /* __REACTOS__ */
3197         if (! *ext && fodInfos->defext)
3198         {
3199             /* if no extension is specified with file name, then */
3200             /* attach the extension from file filter or default one */
3201 
3202             WCHAR *filterExt = NULL;
3203             LPWSTR lpstrFilter = NULL;
3204             static const WCHAR szwDot[] = {'.',0};
3205             int PathLength = lstrlenW(lpstrPathAndFile);
3206 
3207             /*Get the file extension from file type filter*/
3208             lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3209                                              fodInfos->ofnInfos->nFilterIndex-1);
3210 
3211             if (lpstrFilter != (LPWSTR)CB_ERR)  /* control is not empty */
3212             {
3213                 WCHAR* filterSearchIndex;
3214                 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
3215                 lstrcpyW(filterExt, lpstrFilter);
3216 
3217                 /* if a semicolon-separated list of file extensions was given, do not include the
3218                    semicolon or anything after it in the extension.
3219                    example: if filterExt was "*.abc;*.def", it will become "*.abc" */
3220                 filterSearchIndex = wcschr(filterExt, ';');
3221                 if (filterSearchIndex)
3222                 {
3223                     filterSearchIndex[0] = '\0';
3224                 }
3225 
3226                 /* find the file extension by searching for the first dot in filterExt */
3227                 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
3228                 /* if the extension is invalid or contains a glob, ignore it */
3229                 filterSearchIndex = wcschr(filterExt, '.');
3230                 if (filterSearchIndex++ && !wcschr(filterSearchIndex, '*') && !wcschr(filterSearchIndex, '?'))
3231                 {
3232                     lstrcpyW(filterExt, filterSearchIndex);
3233                 }
3234                 else
3235                 {
3236                     heap_free(filterExt);
3237                     filterExt = NULL;
3238                 }
3239             }
3240 
3241             if (!filterExt)
3242             {
3243                 /* use the default file extension */
3244                 filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
3245                 lstrcpyW(filterExt, fodInfos->defext);
3246             }
3247 
3248             if (*filterExt) /* ignore filterExt="" */
3249             {
3250                 /* Attach the dot*/
3251                 lstrcatW(lpstrPathAndFile, szwDot);
3252                 /* Attach the extension */
3253                 lstrcatW(lpstrPathAndFile, filterExt);
3254             }
3255 
3256             heap_free(filterExt);
3257 
3258             /* In Open dialog: if file does not exist try without extension */
3259             if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
3260                   lpstrPathAndFile[PathLength] = '\0';
3261 
3262             /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
3263             if (*ext)
3264                 ext++;
3265             if (!lstrcmpiW(fodInfos->defext, ext))
3266                 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
3267             else
3268                 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
3269 	}
3270 #endif /* __REACTOS__ */
3271 
3272 	/* In Save dialog: check if the file already exists */
3273 	if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
3274 	    && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
3275 	    && PathFileExistsW(lpstrPathAndFile))
3276 	{
3277 	  WCHAR lpstrOverwrite[100];
3278 	  int answer;
3279 
3280 	  LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
3281 	  answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
3282 			       MB_YESNO | MB_ICONEXCLAMATION);
3283 	  if (answer == IDNO || answer == IDCANCEL)
3284 	  {
3285 	    ret = FALSE;
3286 	    goto ret;
3287 	  }
3288 	}
3289 
3290         /* In Open dialog: check if it should be created if it doesn't exist */
3291         if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
3292             && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
3293             && !PathFileExistsW(lpstrPathAndFile))
3294         {
3295           WCHAR lpstrCreate[100];
3296           int answer;
3297 
3298           LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
3299           answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
3300                                MB_YESNO | MB_ICONEXCLAMATION);
3301           if (answer == IDNO || answer == IDCANCEL)
3302           {
3303             ret = FALSE;
3304             goto ret;
3305           }
3306         }
3307 
3308         /* Check that the size of the file does not exceed buffer size.
3309              (Allow for extra \0 if OFN_MULTISELECT is set.) */
3310         if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
3311             ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
3312         {
3313 
3314           /* fill destination buffer */
3315           if (fodInfos->ofnInfos->lpstrFile)
3316           {
3317              if(fodInfos->unicode)
3318              {
3319                LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
3320 
3321                lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
3322                if (ofn->Flags & OFN_ALLOWMULTISELECT)
3323                  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
3324              }
3325              else
3326              {
3327                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
3328 
3329                WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
3330                                    ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
3331                if (ofn->Flags & OFN_ALLOWMULTISELECT)
3332                  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
3333              }
3334           }
3335 
3336           if(fodInfos->unicode)
3337           {
3338               LPWSTR lpszTemp;
3339 
3340               /* set filename offset */
3341               lpszTemp = PathFindFileNameW(lpstrPathAndFile);
3342               fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
3343 
3344               /* set extension offset */
3345               lpszTemp = PathFindExtensionW(lpstrPathAndFile);
3346               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
3347           }
3348           else
3349           {
3350               LPSTR lpszTemp;
3351               CHAR tempFileA[MAX_PATH];
3352 
3353               /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
3354               WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
3355                                   tempFileA, sizeof(tempFileA), NULL, NULL);
3356 
3357               /* set filename offset */
3358               lpszTemp = PathFindFileNameA(tempFileA);
3359               fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
3360 
3361               /* set extension offset */
3362               lpszTemp = PathFindExtensionA(tempFileA);
3363               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
3364           }
3365 
3366           /* copy currently selected filter to lpstrCustomFilter */
3367           if (fodInfos->ofnInfos->lpstrCustomFilter)
3368           {
3369             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
3370             int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
3371                                           NULL, 0, NULL, NULL);
3372             if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
3373             {
3374               LPSTR s = ofn->lpstrCustomFilter;
3375               s += strlen(ofn->lpstrCustomFilter)+1;
3376               WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
3377                                   s, len, NULL, NULL);
3378             }
3379           }
3380 
3381 
3382           if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
3383 	      goto ret;
3384 
3385           FILEDLG95_MRU_save_filename(lpstrPathAndFile);
3386 #ifdef __REACTOS__
3387           FILEDLG95_MRU_save_ext(lpstrPathAndFile);
3388 #endif
3389 
3390           TRACE("close\n");
3391 	  FILEDLG95_Clean(hwnd);
3392           ret = EndDialog(hwnd, TRUE);
3393 	}
3394 	else
3395         {
3396           WORD size;
3397 
3398           size = lstrlenW(lpstrPathAndFile) + 1;
3399           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
3400              size += 1;
3401           /* return needed size in first two bytes of lpstrFile */
3402           if(fodInfos->ofnInfos->lpstrFile)
3403               *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
3404           FILEDLG95_Clean(hwnd);
3405           ret = EndDialog(hwnd, FALSE);
3406           COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
3407         }
3408       }
3409       break;
3410   }
3411 
3412 ret:
3413   if(lpsf) IShellFolder_Release(lpsf);
3414   return ret;
3415 }
3416 
3417 /***********************************************************************
3418  *      FILEDLG95_SHELL_Init
3419  *
3420  * Initialisation of the shell objects
3421  */
3422 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
3423 {
3424   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3425 
3426   TRACE("%p\n", hwnd);
3427 
3428   /*
3429    * Initialisation of the FileOpenDialogInfos structure
3430    */
3431 
3432   /* Shell */
3433 
3434   /*ShellInfos */
3435   fodInfos->ShellInfos.hwndOwner = hwnd;
3436 
3437   /* Disable multi-select if flag not set */
3438   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
3439   {
3440      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
3441   }
3442   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
3443   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
3444 
3445   /* Construct the IShellBrowser interface */
3446   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
3447 
3448   return NOERROR;
3449 }
3450 
3451 /***********************************************************************
3452  *      FILEDLG95_SHELL_ExecuteCommand
3453  *
3454  * Change the folder option and refresh the view
3455  * If the function succeeds, the return value is nonzero.
3456  */
3457 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
3458 {
3459   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3460   IContextMenu * pcm;
3461 
3462   TRACE("(%p,%p)\n", hwnd, lpVerb);
3463 
3464   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
3465 					SVGIO_BACKGROUND,
3466 					&IID_IContextMenu,
3467 					(LPVOID*)&pcm)))
3468   {
3469     CMINVOKECOMMANDINFO ci;
3470     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
3471     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
3472     ci.lpVerb = lpVerb;
3473     ci.hwnd = hwnd;
3474 
3475     IContextMenu_InvokeCommand(pcm, &ci);
3476     IContextMenu_Release(pcm);
3477   }
3478 
3479   return FALSE;
3480 }
3481 
3482 /***********************************************************************
3483  *      FILEDLG95_SHELL_UpFolder
3484  *
3485  * Browse to the specified object
3486  * If the function succeeds, the return value is nonzero.
3487  */
3488 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
3489 {
3490   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3491 
3492   TRACE("\n");
3493 
3494   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3495                                           NULL,
3496                                           SBSP_PARENT)))
3497   {
3498     if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3499         SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3500     return TRUE;
3501   }
3502   return FALSE;
3503 }
3504 /***********************************************************************
3505  *      FILEDLG95_SHELL_Clean
3506  *
3507  * Cleans the memory used by shell objects
3508  */
3509 static void FILEDLG95_SHELL_Clean(HWND hwnd)
3510 {
3511     FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3512 
3513     TRACE("\n");
3514 
3515     ILFree(fodInfos->ShellInfos.pidlAbsCurrent);
3516 
3517     /* clean Shell interfaces */
3518     if (fodInfos->Shell.FOIShellView)
3519     {
3520       IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
3521       IShellView_Release(fodInfos->Shell.FOIShellView);
3522     }
3523     if (fodInfos->Shell.FOIShellFolder)
3524       IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
3525     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
3526     if (fodInfos->Shell.FOIDataObject)
3527       IDataObject_Release(fodInfos->Shell.FOIDataObject);
3528 }
3529 
3530 /***********************************************************************
3531  *      FILEDLG95_FILETYPE_Init
3532  *
3533  * Initialisation of the file type combo box
3534  */
3535 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
3536 {
3537   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3538   int nFilters = 0;  /* number of filters */
3539   int nFilterIndexCB;
3540 
3541   TRACE("%p\n", hwnd);
3542 
3543   if(fodInfos->customfilter)
3544   {
3545       /* customfilter has one entry...  title\0ext\0
3546        * Set first entry of combo box item with customfilter
3547        */
3548       LPWSTR  lpstrExt;
3549       LPCWSTR lpstrPos = fodInfos->customfilter;
3550 
3551       /* Get the title */
3552       lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
3553 
3554       /* Copy the extensions */
3555       if (! *lpstrPos) return E_FAIL;	/* malformed filter */
3556       if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3557       lstrcpyW(lpstrExt,lpstrPos);
3558 
3559       /* Add the item at the end of the combo */
3560       SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter);
3561       SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt);
3562 
3563       nFilters++;
3564   }
3565   if(fodInfos->filter)
3566   {
3567     LPCWSTR lpstrPos = fodInfos->filter;
3568 
3569     for(;;)
3570     {
3571       /* filter is a list...  title\0ext\0......\0\0
3572        * Set the combo item text to the title and the item data
3573        *  to the ext
3574        */
3575       LPCWSTR lpstrDisplay;
3576       LPWSTR lpstrExt;
3577 
3578       /* Get the title */
3579       if(! *lpstrPos) break;	/* end */
3580       lpstrDisplay = lpstrPos;
3581       lpstrPos += lstrlenW(lpstrPos) + 1;
3582 
3583       SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay);
3584 
3585       nFilters++;
3586 
3587       /* Copy the extensions */
3588       if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3589       lstrcpyW(lpstrExt,lpstrPos);
3590       lpstrPos += lstrlenW(lpstrPos) + 1;
3591 
3592       /* Add the item at the end of the combo */
3593       SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt);
3594 
3595       /* malformed filters are added anyway... */
3596       if (!*lpstrExt) break;
3597     }
3598   }
3599 
3600   /*
3601    * Set the current filter to the one specified
3602    * in the initialisation structure
3603    */
3604   if (fodInfos->filter || fodInfos->customfilter)
3605   {
3606     LPWSTR lpstrFilter;
3607 
3608     /* Check to make sure our index isn't out of bounds. */
3609     if ( fodInfos->ofnInfos->nFilterIndex >
3610          nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3611       fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3612 
3613     /* set default filter index */
3614     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3615       fodInfos->ofnInfos->nFilterIndex = 1;
3616 
3617     /* calculate index of Combo Box item */
3618     nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3619     if (fodInfos->customfilter == NULL)
3620       nFilterIndexCB--;
3621 
3622     /* Set the current index selection. */
3623     SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0);
3624 
3625     /* Get the corresponding text string from the combo box. */
3626     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3627                                              nFilterIndexCB);
3628 
3629     if ((INT_PTR)lpstrFilter == CB_ERR)  /* control is empty */
3630       lpstrFilter = NULL;
3631 
3632     if(lpstrFilter)
3633     {
3634       DWORD len;
3635       CharLowerW(lpstrFilter); /* lowercase */
3636       len = lstrlenW(lpstrFilter)+1;
3637       fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3638       lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3639     }
3640   } else
3641       fodInfos->ofnInfos->nFilterIndex = 0;
3642   return S_OK;
3643 }
3644 
3645 /***********************************************************************
3646  *      FILEDLG95_FILETYPE_OnCommand
3647  *
3648  * WM_COMMAND of the file type combo box
3649  * If the function succeeds, the return value is nonzero.
3650  */
3651 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3652 {
3653   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3654 
3655   switch(wNotifyCode)
3656   {
3657     case CBN_SELENDOK:
3658     {
3659       LPWSTR lpstrFilter;
3660 
3661       /* Get the current item of the filetype combo box */
3662       int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0);
3663 
3664       /* set the current filter index */
3665       fodInfos->ofnInfos->nFilterIndex = iItem +
3666         (fodInfos->customfilter == NULL ? 1 : 0);
3667 
3668       /* Set the current filter with the current selection */
3669       heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3670 
3671       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3672                                              iItem);
3673       if((INT_PTR)lpstrFilter != CB_ERR)
3674       {
3675           DWORD len;
3676           CharLowerW(lpstrFilter); /* lowercase */
3677           len = lstrlenW(lpstrFilter)+1;
3678           fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3679           lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3680           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3681               SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3682       }
3683 
3684       /* Refresh the actual view to display the included items*/
3685       if (fodInfos->Shell.FOIShellView)
3686         IShellView_Refresh(fodInfos->Shell.FOIShellView);
3687     }
3688   }
3689   return FALSE;
3690 }
3691 /***********************************************************************
3692  *      FILEDLG95_FILETYPE_SearchExt
3693  *
3694  * searches for an extension in the filetype box
3695  */
3696 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3697 {
3698   int i, iCount;
3699 
3700   iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3701 
3702   TRACE("%s\n", debugstr_w(lpstrExt));
3703 
3704   if(iCount != CB_ERR)
3705   {
3706     for(i=0;i<iCount;i++)
3707     {
3708       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3709           return i;
3710     }
3711   }
3712   return -1;
3713 }
3714 
3715 /***********************************************************************
3716  *      FILEDLG95_FILETYPE_Clean
3717  *
3718  * Clean the memory used by the filetype combo box
3719  */
3720 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3721 {
3722   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3723   int iPos;
3724   int iCount;
3725 
3726   iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0);
3727 
3728   TRACE("\n");
3729 
3730   /* Delete each string of the combo and their associated data */
3731   if(iCount != CB_ERR)
3732   {
3733     for(iPos = iCount-1;iPos>=0;iPos--)
3734     {
3735       heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3736       SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0);
3737     }
3738   }
3739   /* Current filter */
3740   heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3741 }
3742 
3743 /***********************************************************************
3744  *      FILEDLG95_LOOKIN_Init
3745  *
3746  * Initialisation of the look in combo box
3747  */
3748 
3749 /* Small helper function, to determine if the unixfs shell extension is rooted
3750  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3751  */
3752 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3753     HKEY hKey;
3754     static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3755         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3756         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3757         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3758         'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3759         '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3760         '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3761 
3762     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3763         return FALSE;
3764 
3765     RegCloseKey(hKey);
3766     return TRUE;
3767 }
3768 
3769 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3770 {
3771   IShellFolder	*psfRoot, *psfDrives;
3772   IEnumIDList	*lpeRoot, *lpeDrives;
3773   LPITEMIDLIST	pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3774   HDC hdc;
3775   TEXTMETRICW tm;
3776   LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos));
3777 
3778   TRACE("%p\n", hwndCombo);
3779 
3780   liInfos->iMaxIndentation = 0;
3781 
3782   SetPropA(hwndCombo, LookInInfosStr, liInfos);
3783 
3784   hdc = GetDC( hwndCombo );
3785   SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3786   GetTextMetricsW( hdc, &tm );
3787   ReleaseDC( hwndCombo, hdc );
3788 
3789   /* set item height for both text field and listbox */
3790   SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3791   SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3792 
3793   /* Turn on the extended UI for the combo box like Windows does */
3794   SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0);
3795 
3796   /* Initialise data of Desktop folder */
3797   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3798   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3799   ILFree(pidlTmp);
3800 
3801   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3802 
3803   SHGetDesktopFolder(&psfRoot);
3804 
3805   if (psfRoot)
3806   {
3807     /* enumerate the contents of the desktop */
3808     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3809     {
3810       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3811       {
3812 	FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3813 
3814 	/* If the unixfs extension is rooted, we don't expand the drives by default */
3815 	if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3816 	{
3817 	  /* special handling for CSIDL_DRIVES */
3818 	  if (ILIsEqual(pidlTmp, pidlDrives))
3819 	  {
3820 	    if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3821 	    {
3822 	      /* enumerate the drives */
3823 	      if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3824 	      {
3825 	        while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3826 	        {
3827 	          pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1);
3828 	          FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3829 	          ILFree(pidlAbsTmp);
3830 	          ILFree(pidlTmp1);
3831 	        }
3832 	        IEnumIDList_Release(lpeDrives);
3833 	      }
3834 	      IShellFolder_Release(psfDrives);
3835 	    }
3836 	  }
3837 	}
3838 
3839         ILFree(pidlTmp);
3840       }
3841       IEnumIDList_Release(lpeRoot);
3842     }
3843     IShellFolder_Release(psfRoot);
3844   }
3845 
3846   ILFree(pidlDrives);
3847 }
3848 
3849 /***********************************************************************
3850  *      FILEDLG95_LOOKIN_DrawItem
3851  *
3852  * WM_DRAWITEM message handler
3853  */
3854 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3855 {
3856   COLORREF crWin = GetSysColor(COLOR_WINDOW);
3857   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3858   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3859   RECT rectText;
3860   RECT rectIcon;
3861   SHFILEINFOW sfi;
3862   HIMAGELIST ilItemImage;
3863   int iIndentation;
3864   TEXTMETRICW tm;
3865   LPSFOLDER tmpFolder;
3866   UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3867   UINT icon_width, icon_height;
3868 
3869   TRACE("\n");
3870 
3871   if(pDIStruct->itemID == -1)
3872     return 0;
3873 
3874   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3875                             pDIStruct->itemID)))
3876     return 0;
3877 
3878 
3879   icon_width = GetSystemMetrics(SM_CXICON);
3880   icon_height = GetSystemMetrics(SM_CYICON);
3881   if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3882   {
3883       icon_width = GetSystemMetrics(SM_CXSMICON);
3884       icon_height = GetSystemMetrics(SM_CYSMICON);
3885       shgfi_flags |= SHGFI_SMALLICON;
3886   }
3887 
3888   ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3889                                              0, &sfi, sizeof (sfi), shgfi_flags );
3890 
3891   /* Is this item selected ? */
3892   if(pDIStruct->itemState & ODS_SELECTED)
3893   {
3894     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3895     SetBkColor(pDIStruct->hDC,crHighLight);
3896     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3897   }
3898   else
3899   {
3900     SetTextColor(pDIStruct->hDC,crText);
3901     SetBkColor(pDIStruct->hDC,crWin);
3902     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3903   }
3904 
3905   /* Do not indent item if drawing in the edit of the combo */
3906   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3907     iIndentation = 0;
3908   else
3909     iIndentation = tmpFolder->m_iIndent;
3910 
3911   /* Draw text and icon */
3912 
3913   /* Initialise the icon display area */
3914   rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3915   rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3916   rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3917   rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3918 
3919   /* Initialise the text display area */
3920   GetTextMetricsW(pDIStruct->hDC, &tm);
3921   rectText.left = rectIcon.right;
3922   rectText.top =
3923 	  (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3924   rectText.right = pDIStruct->rcItem.right;
3925   rectText.bottom =
3926 	  (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3927 
3928   /* Draw the icon from the image list */
3929   ImageList_Draw(ilItemImage,
3930                  sfi.iIcon,
3931                  pDIStruct->hDC,
3932                  rectIcon.left,
3933                  rectIcon.top,
3934                  ILD_TRANSPARENT );
3935 
3936   /* Draw the associated text */
3937   TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3938   return NOERROR;
3939 }
3940 
3941 /***********************************************************************
3942  *      FILEDLG95_LOOKIN_OnCommand
3943  *
3944  * LookIn combo box WM_COMMAND message handler
3945  * If the function succeeds, the return value is nonzero.
3946  */
3947 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3948 {
3949   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3950 
3951   TRACE("%p\n", fodInfos);
3952 
3953   switch(wNotifyCode)
3954   {
3955     case CBN_SELENDOK:
3956     {
3957       LPSFOLDER tmpFolder;
3958       int iItem;
3959 
3960       iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0);
3961 
3962       if( iItem == CB_ERR) return FALSE;
3963 
3964       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3965                                                iItem)))
3966 	return FALSE;
3967 
3968 
3969       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3970                                               tmpFolder->pidlItem,
3971                                               SBSP_ABSOLUTE)))
3972       {
3973         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3974             SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3975         return TRUE;
3976       }
3977       break;
3978     }
3979 
3980   }
3981   return FALSE;
3982 }
3983 
3984 /***********************************************************************
3985  *      FILEDLG95_LOOKIN_AddItem
3986  *
3987  * Adds an absolute pidl item to the lookin combo box
3988  * returns the index of the inserted item
3989  */
3990 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3991 {
3992   LPITEMIDLIST pidlNext;
3993   SHFILEINFOW sfi;
3994   SFOLDER *tmpFolder;
3995   LookInInfos *liInfos;
3996 
3997   TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId);
3998 
3999   if(!pidl)
4000     return -1;
4001 
4002   if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
4003     return -1;
4004 
4005   tmpFolder = heap_alloc_zero(sizeof(*tmpFolder));
4006   tmpFolder->m_iIndent = 0;
4007 
4008   /* Calculate the indentation of the item in the lookin*/
4009   pidlNext = pidl;
4010   while ((pidlNext = ILGetNext(pidlNext)))
4011   {
4012     tmpFolder->m_iIndent++;
4013   }
4014 
4015   tmpFolder->pidlItem = ILClone(pidl);
4016 
4017   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
4018     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
4019 
4020   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
4021   SHGetFileInfoW((LPCWSTR)pidl,
4022                   0,
4023                   &sfi,
4024                   sizeof(sfi),
4025                   SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
4026 
4027   TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
4028 
4029   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
4030   {
4031     int iItemID;
4032 
4033     TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
4034 
4035     /* Add the item at the end of the list */
4036     if(iInsertId < 0)
4037     {
4038       iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName);
4039     }
4040     /* Insert the item at the iInsertId position*/
4041     else
4042     {
4043       iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName);
4044     }
4045 
4046     SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder);
4047     return iItemID;
4048   }
4049 
4050   ILFree( tmpFolder->pidlItem );
4051   heap_free( tmpFolder );
4052   return -1;
4053 
4054 }
4055 
4056 /***********************************************************************
4057  *      FILEDLG95_LOOKIN_InsertItemAfterParent
4058  *
4059  * Insert an item below its parent
4060  */
4061 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
4062 {
4063 
4064   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
4065   int iParentPos;
4066 
4067   TRACE("\n");
4068 
4069   if (pidl == pidlParent)
4070     return -1;
4071 
4072   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
4073 
4074   if(iParentPos < 0)
4075   {
4076     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
4077   }
4078 
4079   ILFree(pidlParent);
4080 
4081   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
4082 }
4083 
4084 /***********************************************************************
4085  *      FILEDLG95_LOOKIN_SelectItem
4086  *
4087  * Adds an absolute pidl item to the lookin combo box
4088  * returns the index of the inserted item
4089  */
4090 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
4091 {
4092   int iItemPos;
4093   LookInInfos *liInfos;
4094 
4095   TRACE("%p, %p\n", hwnd, pidl);
4096 
4097   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
4098 
4099   liInfos = GetPropA(hwnd,LookInInfosStr);
4100 
4101   if(iItemPos < 0)
4102   {
4103     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
4104     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
4105   }
4106 
4107   else
4108   {
4109     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
4110     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
4111     {
4112       int iRemovedItem;
4113 
4114       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
4115         break;
4116       if(iRemovedItem < iItemPos)
4117         iItemPos--;
4118     }
4119   }
4120 
4121   SendMessageW(hwnd, CB_SETCURSEL, iItemPos, 0);
4122   liInfos->uSelectedItem = iItemPos;
4123 
4124   return 0;
4125 
4126 }
4127 
4128 /***********************************************************************
4129  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
4130  *
4131  * Remove the item with an expansion level over iExpansionLevel
4132  */
4133 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
4134 {
4135   int iItemPos;
4136   LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
4137 
4138   TRACE("\n");
4139 
4140   if(liInfos->iMaxIndentation <= 2)
4141     return -1;
4142 
4143   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
4144   {
4145     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
4146     ILFree(tmpFolder->pidlItem);
4147     heap_free(tmpFolder);
4148     SendMessageW(hwnd, CB_DELETESTRING, iItemPos, 0);
4149     liInfos->iMaxIndentation--;
4150 
4151     return iItemPos;
4152   }
4153 
4154   return -1;
4155 }
4156 
4157 /***********************************************************************
4158  *      FILEDLG95_LOOKIN_SearchItem
4159  *
4160  * Search for pidl in the lookin combo box
4161  * returns the index of the found item
4162  */
4163 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
4164 {
4165   int i = 0;
4166   int iCount;
4167 
4168   iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
4169 
4170   TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
4171 
4172   if (iCount != CB_ERR)
4173   {
4174     for(;i<iCount;i++)
4175     {
4176       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
4177 
4178       if (iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg, tmpFolder->pidlItem))
4179         return i;
4180       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
4181         return i;
4182     }
4183   }
4184 
4185   return -1;
4186 }
4187 
4188 /***********************************************************************
4189  *      FILEDLG95_LOOKIN_Clean
4190  *
4191  * Clean the memory used by the lookin combo box
4192  */
4193 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
4194 {
4195     FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
4196     LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
4197     int iPos, iCount;
4198 
4199     iCount = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCOUNT, 0, 0);
4200 
4201     TRACE("\n");
4202 
4203     /* Delete each string of the combo and their associated data */
4204     if (iCount != CB_ERR)
4205     {
4206       for(iPos = iCount-1;iPos>=0;iPos--)
4207       {
4208         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
4209         ILFree(tmpFolder->pidlItem);
4210         heap_free(tmpFolder);
4211         SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_DELETESTRING, iPos, 0);
4212       }
4213     }
4214 
4215     /* LookInInfos structure */
4216     heap_free(liInfos);
4217     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
4218 }
4219 
4220 /***********************************************************************
4221  *          get_def_format
4222  *
4223  * Fill the FORMATETC used in the shell id list
4224  */
4225 static FORMATETC get_def_format(void)
4226 {
4227     static CLIPFORMAT cfFormat;
4228     FORMATETC formatetc;
4229 
4230     if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
4231     formatetc.cfFormat = cfFormat;
4232     formatetc.ptd = 0;
4233     formatetc.dwAspect = DVASPECT_CONTENT;
4234     formatetc.lindex = -1;
4235     formatetc.tymed = TYMED_HGLOBAL;
4236     return formatetc;
4237 }
4238 
4239 /***********************************************************************
4240  * FILEDLG95_FILENAME_FillFromSelection
4241  *
4242  * fills the edit box from the cached DataObject
4243  */
4244 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
4245 {
4246     FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
4247     LPITEMIDLIST      pidl;
4248     LPWSTR            lpstrAllFiles, lpstrTmp;
4249     UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
4250     STGMEDIUM medium;
4251     LPIDA cida;
4252     FORMATETC formatetc = get_def_format();
4253 
4254     TRACE("\n");
4255 
4256     if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
4257         return;
4258 
4259     cida = GlobalLock(medium.u.hGlobal);
4260     nFileSelected = cida->cidl;
4261 
4262     /* Allocate a buffer */
4263     nAllFilesMaxLength = MAX_PATH + 3;
4264     lpstrAllFiles = heap_alloc_zero(nAllFilesMaxLength * sizeof(WCHAR));
4265     if (!lpstrAllFiles)
4266         goto ret;
4267 
4268     /* Loop through the selection, handle only files (not folders) */
4269     for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
4270     {
4271         pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
4272         if (pidl)
4273         {
4274             if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
4275             {
4276                 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
4277                 {
4278                     nAllFilesMaxLength *= 2;
4279                     lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
4280                     if (!lpstrTmp)
4281                         goto ret;
4282                     lpstrAllFiles = lpstrTmp;
4283                 }
4284                 nFiles += 1;
4285                 lpstrAllFiles[nAllFilesLength++] = '"';
4286                 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
4287                 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
4288                 nAllFilesLength += nThisFileLength;
4289                 lpstrAllFiles[nAllFilesLength++] = '"';
4290                 lpstrAllFiles[nAllFilesLength++] = ' ';
4291             }
4292         }
4293     }
4294 
4295     if (nFiles != 0)
4296     {
4297         /* If there's only one file, use the name as-is without quotes */
4298         lpstrTmp = lpstrAllFiles;
4299         if (nFiles == 1)
4300         {
4301             lpstrTmp += 1;
4302             lpstrTmp[nThisFileLength] = 0;
4303         }
4304         SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
4305         /* Select the file name like Windows does */
4306         if (filename_is_edit(fodInfos))
4307             SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
4308     }
4309 
4310 ret:
4311     heap_free(lpstrAllFiles);
4312     COMCTL32_ReleaseStgMedium(medium);
4313 }
4314 
4315 
4316 /* copied from shell32 to avoid linking to it
4317  * Although shell32 is already linked the behaviour of exported StrRetToStrN
4318  * is dependent on whether emulated OS is unicode or not.
4319  */
4320 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
4321 {
4322 	switch (src->uType)
4323 	{
4324 	  case STRRET_WSTR:
4325 	    lstrcpynW(dest, src->u.pOleStr, len);
4326 	    CoTaskMemFree(src->u.pOleStr);
4327 	    break;
4328 
4329 	  case STRRET_CSTR:
4330             if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
4331                   dest[len-1] = 0;
4332 	    break;
4333 
4334 	  case STRRET_OFFSET:
4335             if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
4336                   dest[len-1] = 0;
4337 	    break;
4338 
4339 	  default:
4340 	    FIXME("unknown type %x!\n", src->uType);
4341 	    if (len) *dest = '\0';
4342 	    return E_FAIL;
4343 	}
4344 	return S_OK;
4345 }
4346 
4347 /***********************************************************************
4348  * FILEDLG95_FILENAME_GetFileNames
4349  *
4350  * Copies the filenames to a delimited string list.
4351  */
4352 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
4353 {
4354 	FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
4355 	UINT nFileCount = 0;	/* number of files */
4356 	UINT nStrLen = 0;	/* length of string in edit control */
4357 	LPWSTR lpstrEdit;	/* buffer for string from edit control */
4358 
4359 	TRACE("\n");
4360 
4361 	/* get the filenames from the filename control */
4362 	nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
4363 	lpstrEdit = heap_alloc( (nStrLen+1)*sizeof(WCHAR) );
4364 	GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
4365 
4366 	TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
4367 
4368 	nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
4369 	heap_free(lpstrEdit);
4370 	return nFileCount;
4371 }
4372 
4373 /*
4374  * DATAOBJECT Helper functions
4375  */
4376 
4377 /***********************************************************************
4378  * COMCTL32_ReleaseStgMedium
4379  *
4380  * like ReleaseStgMedium from ole32
4381  */
4382 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
4383 {
4384       if(medium.pUnkForRelease)
4385       {
4386         IUnknown_Release(medium.pUnkForRelease);
4387       }
4388       else
4389       {
4390         GlobalUnlock(medium.u.hGlobal);
4391         GlobalFree(medium.u.hGlobal);
4392       }
4393 }
4394 
4395 /***********************************************************************
4396  *          GetPidlFromDataObject
4397  *
4398  * Return pidl(s) by number from the cached DataObject
4399  *
4400  * nPidlIndex=0 gets the fully qualified root path
4401  */
4402 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
4403 {
4404 
4405     STGMEDIUM medium;
4406     FORMATETC formatetc = get_def_format();
4407     LPITEMIDLIST pidl = NULL;
4408 
4409     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
4410 
4411     if (!doSelected)
4412         return NULL;
4413 
4414     /* Get the pidls from IDataObject */
4415     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
4416     {
4417       LPIDA cida = GlobalLock(medium.u.hGlobal);
4418       if(nPidlIndex <= cida->cidl)
4419       {
4420         pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
4421       }
4422       COMCTL32_ReleaseStgMedium(medium);
4423     }
4424     return pidl;
4425 }
4426 
4427 /***********************************************************************
4428  *          GetNumSelected
4429  *
4430  * Return the number of selected items in the DataObject.
4431  *
4432 */
4433 static UINT GetNumSelected( IDataObject *doSelected )
4434 {
4435     UINT retVal = 0;
4436     STGMEDIUM medium;
4437     FORMATETC formatetc = get_def_format();
4438 
4439     TRACE("sv=%p\n", doSelected);
4440 
4441     if (!doSelected) return 0;
4442 
4443     /* Get the pidls from IDataObject */
4444     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
4445     {
4446       LPIDA cida = GlobalLock(medium.u.hGlobal);
4447       retVal = cida->cidl;
4448       COMCTL32_ReleaseStgMedium(medium);
4449       return retVal;
4450     }
4451     return 0;
4452 }
4453 
4454 /*
4455  * TOOLS
4456  */
4457 
4458 /***********************************************************************
4459  *      GetName
4460  *
4461  * Get the pidl's display name (relative to folder) and
4462  * put it in lpstrFileName.
4463  *
4464  * Return NOERROR on success,
4465  * E_FAIL otherwise
4466  */
4467 
4468 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
4469 {
4470   STRRET str;
4471   HRESULT hRes;
4472 
4473   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
4474 
4475   if(!lpsf)
4476   {
4477     SHGetDesktopFolder(&lpsf);
4478     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
4479     IShellFolder_Release(lpsf);
4480     return hRes;
4481   }
4482 
4483   /* Get the display name of the pidl relative to the folder */
4484   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
4485   {
4486       return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
4487   }
4488   return E_FAIL;
4489 }
4490 
4491 /***********************************************************************
4492  *      GetShellFolderFromPidl
4493  *
4494  * pidlRel is the item pidl relative
4495  * Return the IShellFolder of the absolute pidl
4496  */
4497 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
4498 {
4499   IShellFolder *psf = NULL,*psfParent;
4500 
4501   TRACE("%p\n", pidlAbs);
4502 
4503   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
4504   {
4505     psf = psfParent;
4506     if(pidlAbs && pidlAbs->mkid.cb)
4507     {
4508       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
4509       {
4510 	IShellFolder_Release(psfParent);
4511         return psf;
4512       }
4513     }
4514     /* return the desktop */
4515     return psfParent;
4516   }
4517   return NULL;
4518 }
4519 
4520 /***********************************************************************
4521  *      GetParentPidl
4522  *
4523  * Return the LPITEMIDLIST to the parent of the pidl in the list
4524  */
4525 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
4526 {
4527   LPITEMIDLIST pidlParent;
4528 
4529   TRACE("%p\n", pidl);
4530 
4531   pidlParent = ILClone(pidl);
4532   ILRemoveLastID(pidlParent);
4533 
4534   return pidlParent;
4535 }
4536 
4537 /***********************************************************************
4538  *      GetPidlFromName
4539  *
4540  * returns the pidl of the file name relative to folder
4541  * NULL if an error occurred
4542  */
4543 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
4544 {
4545   LPITEMIDLIST pidl = NULL;
4546   ULONG ulEaten;
4547 
4548   TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
4549 
4550   if(!lpcstrFileName) return NULL;
4551   if(!*lpcstrFileName) return NULL;
4552 
4553   if(!lpsf)
4554   {
4555     if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
4556         IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4557         IShellFolder_Release(lpsf);
4558     }
4559   }
4560   else
4561   {
4562     IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4563   }
4564   return pidl;
4565 }
4566 
4567 /*
4568 */
4569 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
4570 {
4571 	ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR;
4572 	HRESULT ret;
4573 
4574 	TRACE("%p, %p\n", psf, pidl);
4575 
4576   	ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4577 
4578 	TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
4579 	/* see documentation shell 4.1*/
4580         return (uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER)) && (uAttr & SFGAO_FILESYSANCESTOR);
4581 }
4582 
4583 /***********************************************************************
4584  *      BrowseSelectedFolder
4585  */
4586 static BOOL BrowseSelectedFolder(HWND hwnd)
4587 {
4588   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
4589   BOOL bBrowseSelFolder = FALSE;
4590 
4591   TRACE("\n");
4592 
4593   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4594   {
4595       LPITEMIDLIST pidlSelection;
4596 
4597       /* get the file selected */
4598       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4599       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4600       {
4601           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4602                          pidlSelection, SBSP_RELATIVE ) ) )
4603           {
4604                WCHAR buf[64];
4605                LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, ARRAY_SIZE(buf));
4606                MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4607           }
4608           bBrowseSelFolder = TRUE;
4609           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4610               SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4611       }
4612       ILFree( pidlSelection );
4613   }
4614 
4615   return bBrowseSelFolder;
4616 }
4617 
4618 static inline BOOL valid_struct_size( DWORD size )
4619 {
4620     return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4621         (size == sizeof( OPENFILENAMEW ));
4622 }
4623 
4624 static inline BOOL is_win16_looks(DWORD flags)
4625 {
4626     return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4627             !(flags & OFN_EXPLORER));
4628 }
4629 
4630 /* ------------------ APIs ---------------------- */
4631 
4632 /***********************************************************************
4633  *            GetOpenFileNameA  (COMDLG32.@)
4634  *
4635  * Creates a dialog box for the user to select a file to open.
4636  *
4637  * RETURNS
4638  *    TRUE on success: user enters a valid file
4639  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4640  *
4641  */
4642 BOOL WINAPI GetOpenFileNameA(OPENFILENAMEA *ofn)
4643 {
4644     TRACE("flags 0x%08x\n", ofn->Flags);
4645 
4646     if (!valid_struct_size( ofn->lStructSize ))
4647     {
4648         COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4649         return FALSE;
4650     }
4651 
4652     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4653     if (ofn->Flags & OFN_FILEMUSTEXIST)
4654         ofn->Flags |= OFN_PATHMUSTEXIST;
4655 
4656     if (is_win16_looks(ofn->Flags))
4657         return GetFileName31A(ofn, OPEN_DIALOG);
4658     else
4659     {
4660         FileOpenDlgInfos info;
4661 
4662         init_filedlg_infoA(ofn, &info);
4663         return GetFileDialog95(&info, OPEN_DIALOG);
4664     }
4665 }
4666 
4667 /***********************************************************************
4668  *            GetOpenFileNameW (COMDLG32.@)
4669  *
4670  * Creates a dialog box for the user to select a file to open.
4671  *
4672  * RETURNS
4673  *    TRUE on success: user enters a valid file
4674  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4675  *
4676  */
4677 BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn)
4678 {
4679     TRACE("flags 0x%08x\n", ofn->Flags);
4680 
4681     if (!valid_struct_size( ofn->lStructSize ))
4682     {
4683         COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4684         return FALSE;
4685     }
4686 
4687     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4688     if (ofn->Flags & OFN_FILEMUSTEXIST)
4689         ofn->Flags |= OFN_PATHMUSTEXIST;
4690 
4691     if (is_win16_looks(ofn->Flags))
4692         return GetFileName31W(ofn, OPEN_DIALOG);
4693     else
4694     {
4695         FileOpenDlgInfos info;
4696 
4697         init_filedlg_infoW(ofn, &info);
4698         return GetFileDialog95(&info, OPEN_DIALOG);
4699     }
4700 }
4701 
4702 
4703 /***********************************************************************
4704  *            GetSaveFileNameA  (COMDLG32.@)
4705  *
4706  * Creates a dialog box for the user to select a file to save.
4707  *
4708  * RETURNS
4709  *    TRUE on success: user enters a valid file
4710  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4711  *
4712  */
4713 BOOL WINAPI GetSaveFileNameA(OPENFILENAMEA *ofn)
4714 {
4715     if (!valid_struct_size( ofn->lStructSize ))
4716     {
4717         COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4718         return FALSE;
4719     }
4720 
4721     if (is_win16_looks(ofn->Flags))
4722         return GetFileName31A(ofn, SAVE_DIALOG);
4723     else
4724     {
4725         FileOpenDlgInfos info;
4726 
4727         init_filedlg_infoA(ofn, &info);
4728         return GetFileDialog95(&info, SAVE_DIALOG);
4729     }
4730 }
4731 
4732 /***********************************************************************
4733  *            GetSaveFileNameW  (COMDLG32.@)
4734  *
4735  * Creates a dialog box for the user to select a file to save.
4736  *
4737  * RETURNS
4738  *    TRUE on success: user enters a valid file
4739  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4740  *
4741  */
4742 BOOL WINAPI GetSaveFileNameW(
4743 	LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4744 {
4745     if (!valid_struct_size( ofn->lStructSize ))
4746     {
4747         COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4748         return FALSE;
4749     }
4750 
4751     if (is_win16_looks(ofn->Flags))
4752         return GetFileName31W(ofn, SAVE_DIALOG);
4753     else
4754     {
4755         FileOpenDlgInfos info;
4756 
4757         init_filedlg_infoW(ofn, &info);
4758         return GetFileDialog95(&info, SAVE_DIALOG);
4759     }
4760 }
4761 
4762 /***********************************************************************
4763  *	GetFileTitleA		(COMDLG32.@)
4764  *
4765  * See GetFileTitleW.
4766  */
4767 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4768 {
4769     int ret;
4770     UNICODE_STRING strWFile;
4771     LPWSTR lpWTitle;
4772 
4773     RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4774     lpWTitle = heap_alloc(cbBuf * sizeof(WCHAR));
4775     ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4776     if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4777     RtlFreeUnicodeString( &strWFile );
4778     heap_free( lpWTitle );
4779     return ret;
4780 }
4781 
4782 
4783 /***********************************************************************
4784  *	GetFileTitleW		(COMDLG32.@)
4785  *
4786  * Get the name of a file.
4787  *
4788  * PARAMS
4789  *  lpFile  [I] name and location of file
4790  *  lpTitle [O] returned file name
4791  *  cbBuf   [I] buffer size of lpTitle
4792  *
4793  * RETURNS
4794  *  Success: zero
4795  *  Failure: negative number.
4796  */
4797 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4798 {
4799 	int i, len;
4800         static const WCHAR brkpoint[] = {'*','[',']',0};
4801 	TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4802 
4803 	if(lpFile == NULL || lpTitle == NULL)
4804 		return -1;
4805 
4806 	len = lstrlenW(lpFile);
4807 
4808 	if (len == 0)
4809 		return -1;
4810 
4811 	if(wcspbrk(lpFile, brkpoint))
4812 		return -1;
4813 
4814 	len--;
4815 
4816 	if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4817 		return -1;
4818 
4819 	for(i = len; i >= 0; i--)
4820 	{
4821 		if (lpFile[i] == '/' ||  lpFile[i] == '\\' ||  lpFile[i] == ':')
4822 		{
4823 			i++;
4824 			break;
4825 		}
4826 	}
4827 
4828 	if(i == -1)
4829 		i++;
4830 
4831 	TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4832 
4833 	len = lstrlenW(lpFile+i)+1;
4834 	if(cbBuf < len)
4835 		return len;
4836 
4837 	lstrcpyW(lpTitle, &lpFile[i]);
4838 	return 0;
4839 }
4840