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