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