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