xref: /reactos/dll/win32/comdlg32/filedlg.c (revision 02e84521)
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, file=%s\n", debugstr_w(lpstrPathAndFile), debugstr_w(lpstrFile));
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                 case IDC_TOOLBARPLACES:
1267                     DeferWindowPos( hdwp, ctrl, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + chgy,
1268                                     SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1269                     break;
1270             }
1271         }
1272     }
1273     if(fodInfos->DlgInfos.hwndCustomDlg &&
1274         (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1275     {
1276         for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1277                 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1278         {
1279             GetWindowRect( ctrl, &rc);
1280             MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1281             if( rc.top > rcview.bottom)
1282             {
1283                 /* if it was below the shell view
1284                  * move to bottom */
1285                 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1286                         rc.right - rc.left, rc.bottom - rc.top,
1287                         SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1288             }
1289             else if( rc.left > rcview.right)
1290             {
1291                 /* if it was to the right of the shell view
1292                  * move to right */
1293                 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1294                         rc.right - rc.left, rc.bottom - rc.top,
1295                         SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1296             }
1297         }
1298         /* size the custom dialog at the end: some applications do some
1299          * control re-arranging at this point */
1300         GetClientRect(hwnd, &rc);
1301         DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1302             0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1303     }
1304     EndDeferWindowPos( hdwp);
1305     /* should not be needed */
1306     RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1307     return TRUE;
1308 }
1309 
1310 /***********************************************************************
1311  *          FileOpenDlgProc95
1312  *
1313  * File open dialog procedure
1314  */
1315 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1316 {
1317 #if 0
1318   TRACE("%p 0x%04x\n", hwnd, uMsg);
1319 #endif
1320 
1321   switch(uMsg)
1322   {
1323     case WM_INITDIALOG:
1324       {
1325          FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1326          RECT rc, rcstc;
1327          int gripx = GetSystemMetrics( SM_CYHSCROLL);
1328          int gripy = GetSystemMetrics( SM_CYVSCROLL);
1329 
1330          /* Some shell namespace extensions depend on COM being initialized. */
1331          if (SUCCEEDED(OleInitialize(NULL)))
1332              fodInfos->ole_initialized = TRUE;
1333 
1334          SetPropW(hwnd, filedlg_info_propnameW, fodInfos);
1335 
1336          FILEDLG95_InitControls(hwnd);
1337 
1338          if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1339          {
1340              DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1341              DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE);
1342              RECT client, client_adjusted;
1343 
1344              if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1345              {
1346                  style |= WS_SIZEBOX;
1347                  ex_style |= WS_EX_WINDOWEDGE;
1348              }
1349              else
1350                  style &= ~WS_SIZEBOX;
1351              SetWindowLongW(hwnd, GWL_STYLE, style);
1352              SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style);
1353 
1354              GetClientRect( hwnd, &client );
1355              GetClientRect( hwnd, &client_adjusted );
1356              AdjustWindowRectEx( &client_adjusted, style, FALSE, ex_style );
1357 
1358              GetWindowRect( hwnd, &rc );
1359              rc.right += client_adjusted.right - client.right;
1360              rc.bottom += client_adjusted.bottom - client.bottom;
1361              SetWindowPos(hwnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOACTIVATE |
1362                  SWP_NOZORDER | SWP_NOMOVE);
1363 
1364              GetWindowRect( hwnd, &rc );
1365              fodInfos->DlgInfos.hwndGrip =
1366                  CreateWindowExA( 0, "SCROLLBAR", NULL,
1367                      WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1368                      SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1369                      rc.right - gripx, rc.bottom - gripy,
1370                      gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1371          }
1372 
1373       	 fodInfos->DlgInfos.hwndCustomDlg =
1374      	   CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1375 
1376          FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1377       	 FILEDLG95_FillControls(hwnd, wParam, lParam);
1378 
1379          if( fodInfos->DlgInfos.hwndCustomDlg)
1380              ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1381 
1382          if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1383              SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1384              SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1385          }
1386 
1387          /* if the app has changed the position of the invisible listbox,
1388           * change that of the listview (browser) as well */
1389          GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1390          GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1391          if( !EqualRect( &rc, &rcstc))
1392          {
1393              MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1394              SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1395                      rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1396                      SWP_NOACTIVATE | SWP_NOZORDER);
1397          }
1398 
1399          if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1400          {
1401              GetWindowRect( hwnd, &rc);
1402              fodInfos->sizedlg.cx = rc.right - rc.left;
1403              fodInfos->sizedlg.cy = rc.bottom - rc.top;
1404              fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1405              fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1406              GetClientRect( hwnd, &rc);
1407              SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1408                      rc.right - gripx, rc.bottom - gripy,
1409                      0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1410              /* resize the dialog to the previous invocation */
1411              if( MemDialogSize.cx && MemDialogSize.cy)
1412                  SetWindowPos( hwnd, NULL,
1413                          0, 0, MemDialogSize.cx, MemDialogSize.cy,
1414                          SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1415          }
1416 
1417          if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1418              SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1419 
1420          return 0;
1421        }
1422     case WM_SIZE:
1423       return FILEDLG95_OnWMSize(hwnd, wParam);
1424     case WM_GETMINMAXINFO:
1425       return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1426     case WM_COMMAND:
1427       return FILEDLG95_OnWMCommand(hwnd, wParam);
1428     case WM_DRAWITEM:
1429       {
1430         switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1431         {
1432         case IDC_LOOKIN:
1433           FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1434           return TRUE;
1435         }
1436       }
1437       return FALSE;
1438 
1439     case WM_GETISHELLBROWSER:
1440       return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1441 
1442     case WM_DESTROY:
1443       {
1444           FileOpenDlgInfos * fodInfos = get_filedlg_infoptr(hwnd);
1445           HWND places_bar = GetDlgItem(hwnd, IDC_TOOLBARPLACES);
1446           HIMAGELIST himl;
1447 
1448           if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1449               MemDialogSize = fodInfos->sizedlg;
1450 
1451           if (places_bar)
1452           {
1453               himl = (HIMAGELIST)SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_GETIMAGELIST, 0, 0);
1454               SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, 0);
1455               ImageList_Destroy(himl);
1456           }
1457           return FALSE;
1458       }
1459 
1460     case WM_NCDESTROY:
1461         RemovePropW(hwnd, filedlg_info_propnameW);
1462         return 0;
1463 
1464     case WM_NOTIFY:
1465     {
1466 	LPNMHDR lpnmh = (LPNMHDR)lParam;
1467 	UINT stringId = -1;
1468 
1469 	/* set up the button tooltips strings */
1470 	if(TTN_GETDISPINFOA == lpnmh->code )
1471 	{
1472 	    LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1473 	    switch(lpnmh->idFrom )
1474 	    {
1475 		/* Up folder button */
1476 		case FCIDM_TB_UPFOLDER:
1477 		    stringId = IDS_UPFOLDER;
1478 		    break;
1479 		/* New folder button */
1480 		case FCIDM_TB_NEWFOLDER:
1481 		    stringId = IDS_NEWFOLDER;
1482 		    break;
1483 		/* List option button */
1484 		case FCIDM_TB_SMALLICON:
1485 		    stringId = IDS_LISTVIEW;
1486 		    break;
1487 		/* Details option button */
1488 		case FCIDM_TB_REPORTVIEW:
1489 		    stringId = IDS_REPORTVIEW;
1490 		    break;
1491 		/* Desktop button */
1492 		case FCIDM_TB_DESKTOP:
1493 		    stringId = IDS_TODESKTOP;
1494 		    break;
1495 		default:
1496 		    stringId = 0;
1497 	    }
1498 	    lpdi->hinst = COMDLG32_hInstance;
1499 	    lpdi->lpszText =  MAKEINTRESOURCEA(stringId);
1500 	}
1501         return FALSE;
1502     }
1503     default :
1504       if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1505         return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1506       return FALSE;
1507   }
1508 }
1509 
1510 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1511 {
1512     return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1513         (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1514 }
1515 
1516 /***********************************************************************
1517  *      FILEDLG95_InitControls
1518  *
1519  * WM_INITDIALOG message handler (before hook notification)
1520  */
1521 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1522 {
1523   BOOL win2000plus = FALSE;
1524   BOOL win98plus   = FALSE;
1525   BOOL handledPath = FALSE;
1526   OSVERSIONINFOW osVi;
1527   static const WCHAR szwSlash[] = { '\\', 0 };
1528   static const WCHAR szwStar[] = { '*',0 };
1529 
1530   static const TBBUTTON tbb[] =
1531   {
1532    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1533    {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER,   TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1534    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1535    {VIEW_NEWFOLDER+1,  FCIDM_TB_DESKTOP,    TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1536    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1537    {VIEW_NEWFOLDER,    FCIDM_TB_NEWFOLDER,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1538    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1539    {VIEW_LIST,         FCIDM_TB_SMALLICON,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1540    {VIEW_DETAILS,      FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1541   };
1542   static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1543 
1544   RECT rectTB;
1545   RECT rectlook;
1546 
1547   HIMAGELIST toolbarImageList;
1548   ITEMIDLIST *desktopPidl;
1549   SHFILEINFOW fileinfo;
1550 
1551   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1552 
1553   TRACE("%p\n", fodInfos);
1554 
1555   /* Get windows version emulating */
1556   osVi.dwOSVersionInfoSize = sizeof(osVi);
1557   GetVersionExW(&osVi);
1558   if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1559     win98plus   = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1560   } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1561     win2000plus = (osVi.dwMajorVersion > 4);
1562     if (win2000plus) win98plus = TRUE;
1563   }
1564   TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1565 
1566 
1567   /* Use either the edit or the comboboxex for the filename control */
1568   if (filename_is_edit( fodInfos ))
1569   {
1570       DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1571       fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1572   }
1573   else
1574   {
1575       DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1576       fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1577   }
1578 
1579   /* Get the hwnd of the controls */
1580   fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1581   fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1582 
1583   GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1584   MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1585 
1586   /* construct the toolbar */
1587   GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1588   MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1589 
1590   rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1591   rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1592   rectTB.left = rectlook.right;
1593   rectTB.top = rectlook.top-1;
1594 
1595   if (fodInfos->unicode)
1596       fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1597           WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE,
1598           rectTB.left, rectTB.top,
1599           rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1600           hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1601   else
1602       fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1603           WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE,
1604           rectTB.left, rectTB.top,
1605           rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1606           hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1607 
1608   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1609 
1610 /* FIXME: use TB_LOADIMAGES when implemented */
1611 /*  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1612   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1613   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1614 
1615   /* Retrieve and add desktop icon to the toolbar */
1616   toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1617   SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1618   SHGetFileInfoW((const WCHAR *)desktopPidl, 0, &fileinfo, sizeof(fileinfo),
1619     SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1620   ImageList_AddIcon(toolbarImageList, fileinfo.hIcon);
1621 
1622   DestroyIcon(fileinfo.hIcon);
1623   CoTaskMemFree(desktopPidl);
1624 
1625   /* Finish Toolbar Construction */
1626   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1627   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1628 
1629   if (is_places_bar_enabled(fodInfos))
1630   {
1631       TBBUTTON tb = { 0 };
1632       HIMAGELIST himl;
1633       RECT rect;
1634       int i, cx;
1635 
1636       SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_BUTTONSTRUCTSIZE, 0, 0);
1637       GetClientRect(GetDlgItem(hwnd, IDC_TOOLBARPLACES), &rect);
1638       cx = rect.right - rect.left;
1639 
1640       SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cx, cx));
1641       himl = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32, 4, 1);
1642 
1643       filedlg_collect_places_pidls(fodInfos);
1644       for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
1645       {
1646           int index;
1647 
1648           if (!fodInfos->places[i])
1649               continue;
1650 
1651           memset(&fileinfo, 0, sizeof(fileinfo));
1652           SHGetFileInfoW((const WCHAR *)fodInfos->places[i], 0, &fileinfo, sizeof(fileinfo),
1653               SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON);
1654           index = ImageList_AddIcon(himl, fileinfo.hIcon);
1655 
1656           tb.iBitmap = index;
1657           tb.iString = (INT_PTR)fileinfo.szDisplayName;
1658           tb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP;
1659           tb.idCommand = TBPLACES_CMDID_PLACE0 + i;
1660           SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_ADDBUTTONSW, 1, (LPARAM)&tb);
1661 
1662           DestroyIcon(fileinfo.hIcon);
1663       }
1664 
1665       SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, (LPARAM)himl);
1666       SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cx * 3 / 4));
1667   }
1668 
1669   /* Set the window text with the text specified in the OPENFILENAME structure */
1670   if(fodInfos->title)
1671   {
1672       SetWindowTextW(hwnd,fodInfos->title);
1673   }
1674   else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1675   {
1676       WCHAR buf[64];
1677       LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, ARRAY_SIZE(buf));
1678       SetWindowTextW(hwnd, buf);
1679   }
1680 
1681   /* Initialise the file name edit control */
1682   handledPath = FALSE;
1683   TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1684 
1685   if(fodInfos->filename)
1686   {
1687       /* 1. If win2000 or higher and filename contains a path, use it
1688          in preference over the lpstrInitialDir                       */
1689       if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1690          WCHAR tmpBuf[MAX_PATH];
1691          WCHAR *nameBit;
1692          DWORD result;
1693 
1694          result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1695          if (result) {
1696 
1697             /* nameBit is always shorter than the original filename. It may be NULL
1698              * when the filename contains only a drive name instead of file name */
1699             if (nameBit)
1700             {
1701                 lstrcpyW(fodInfos->filename,nameBit);
1702                 *nameBit = 0x00;
1703             }
1704             else
1705                 *fodInfos->filename = '\0';
1706 
1707             heap_free(fodInfos->initdir);
1708             fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1709             lstrcpyW(fodInfos->initdir, tmpBuf);
1710             handledPath = TRUE;
1711             TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1712                     debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1713          }
1714          SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1715 
1716       } else {
1717          SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1718       }
1719   }
1720 
1721   /* 2. (All platforms) If initdir is not null, then use it */
1722   if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1723   {
1724         /* Work out the proper path as supplied one might be relative          */
1725         /* (Here because supplying '.' as dir browses to My Computer)          */
1726         WCHAR tmpBuf[MAX_PATH];
1727         WCHAR tmpBuf2[MAX_PATH];
1728         WCHAR *nameBit;
1729         DWORD result;
1730 
1731         lstrcpyW(tmpBuf, fodInfos->initdir);
1732         if (PathFileExistsW(tmpBuf)) {
1733             /* initdir does not have to be a directory. If a file is
1734              * specified, the dir part is taken */
1735             if (PathIsDirectoryW(tmpBuf)) {
1736                 PathAddBackslashW(tmpBuf);
1737                 lstrcatW(tmpBuf, szwStar);
1738             }
1739             result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1740             if (result) {
1741                 *nameBit = 0x00;
1742                 heap_free(fodInfos->initdir);
1743                 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1744                 lstrcpyW(fodInfos->initdir, tmpBuf2);
1745                 handledPath = TRUE;
1746                 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1747             }
1748         }
1749         else if (fodInfos->initdir)
1750         {
1751             heap_free(fodInfos->initdir);
1752             fodInfos->initdir = NULL;
1753             TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1754         }
1755   }
1756 
1757   if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1758   {
1759       /* 3. All except w2k+: if filename contains a path use it */
1760       if (!win2000plus && fodInfos->filename &&
1761           *fodInfos->filename &&
1762           strpbrkW(fodInfos->filename, szwSlash)) {
1763          WCHAR tmpBuf[MAX_PATH];
1764          WCHAR *nameBit;
1765          DWORD result;
1766 
1767          result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1768                                   tmpBuf, &nameBit);
1769          if (result) {
1770             int len;
1771 
1772             /* nameBit is always shorter than the original filename */
1773             lstrcpyW(fodInfos->filename, nameBit);
1774             *nameBit = 0x00;
1775 
1776             len = lstrlenW(tmpBuf);
1777             heap_free(fodInfos->initdir);
1778             fodInfos->initdir = heap_alloc((len+1)*sizeof(WCHAR));
1779             lstrcpyW(fodInfos->initdir, tmpBuf);
1780 
1781             handledPath = TRUE;
1782             TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1783                  debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1784          }
1785          SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1786       }
1787 
1788       /* 4. Win2000+: Recently used */
1789       if (!handledPath && win2000plus) {
1790           fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1791           fodInfos->initdir[0] = '\0';
1792 
1793           FILEDLG95_MRU_load_filename(fodInfos->initdir);
1794 
1795           if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1796              handledPath = TRUE;
1797           }else{
1798              heap_free(fodInfos->initdir);
1799              fodInfos->initdir = NULL;
1800           }
1801       }
1802 
1803       /* 5. win98+ and win2000+ if any files of specified filter types in
1804             current directory, use it                                      */
1805       if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1806 
1807          LPCWSTR lpstrPos = fodInfos->filter;
1808          WIN32_FIND_DATAW FindFileData;
1809          HANDLE hFind;
1810 
1811          while (1)
1812          {
1813            /* filter is a list...  title\0ext\0......\0\0 */
1814 
1815            /* Skip the title */
1816            if(! *lpstrPos) break;	/* end */
1817            lpstrPos += lstrlenW(lpstrPos) + 1;
1818 
1819            /* See if any files exist in the current dir with this extension */
1820            if(! *lpstrPos) break;	/* end */
1821 
1822            hFind = FindFirstFileW(lpstrPos, &FindFileData);
1823 
1824            if (hFind == INVALID_HANDLE_VALUE) {
1825                /* None found - continue search */
1826                lpstrPos += lstrlenW(lpstrPos) + 1;
1827 
1828            } else {
1829 
1830                heap_free(fodInfos->initdir);
1831                fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1832                GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1833 
1834                handledPath = TRUE;
1835                TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1836                  debugstr_w(lpstrPos));
1837                FindClose(hFind);
1838                break;
1839            }
1840          }
1841       }
1842 
1843       /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1844       if (!handledPath && (win2000plus || win98plus)) {
1845           fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1846 
1847           if (SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir) == S_OK)
1848           {
1849               if (SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir) == S_OK)
1850               {
1851                   /* last fallback */
1852                   GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1853                   TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1854               }
1855               else
1856                 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1857           }
1858           else
1859               TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1860 
1861           handledPath = TRUE;
1862       } else if (!handledPath) {
1863           fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1864           GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1865           handledPath = TRUE;
1866           TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1867       }
1868   }
1869   SetFocus( fodInfos->DlgInfos.hwndFileName );
1870   TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1871 
1872   /* Must the open as read only check box be checked ?*/
1873   if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1874   {
1875     SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1876   }
1877 
1878   /* Must the open as read only check box be hidden? */
1879   if (filedialog_is_readonly_hidden(fodInfos))
1880   {
1881     ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1882     EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1883   }
1884 
1885   /* Must the help button be hidden? */
1886   if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1887   {
1888     ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1889     EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1890   }
1891 
1892   /* change Open to Save */
1893   if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1894   {
1895       WCHAR buf[16];
1896       LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, ARRAY_SIZE(buf));
1897       SetDlgItemTextW(hwnd, IDOK, buf);
1898       LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, ARRAY_SIZE(buf));
1899       SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1900   }
1901 
1902   /* Initialize the filter combo box */
1903   FILEDLG95_FILETYPE_Init(hwnd);
1904 
1905   return 0;
1906 }
1907 
1908 /***********************************************************************
1909  *      FILEDLG95_ResizeControls
1910  *
1911  * WM_INITDIALOG message handler (after hook notification)
1912  */
1913 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1914 {
1915   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1916 
1917   if (fodInfos->DlgInfos.hwndCustomDlg)
1918   {
1919     RECT rc;
1920     UINT flags = SWP_NOACTIVATE;
1921 
1922     ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1923         filedialog_is_readonly_hidden(fodInfos) && !(fodInfos->ofnInfos->Flags & OFN_SHOWHELP));
1924 
1925     /* resize the custom dialog to the parent size */
1926     if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1927       GetClientRect(hwnd, &rc);
1928     else
1929     {
1930       /* our own fake template is zero sized and doesn't have children, so
1931        * there is no need to resize it. Picasa depends on it.
1932        */
1933       flags |= SWP_NOSIZE;
1934       SetRectEmpty(&rc);
1935     }
1936     SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1937                  0, 0, rc.right, rc.bottom, flags);
1938   }
1939   else
1940   {
1941     /* Resize the height; if opened as read-only, checkbox and help button are
1942      * hidden and we are not using a custom template nor a customDialog
1943      */
1944     if (filedialog_is_readonly_hidden(fodInfos) &&
1945                 (!(fodInfos->ofnInfos->Flags &
1946                    (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1947     {
1948       RECT rectDlg, rectHelp, rectCancel;
1949       GetWindowRect(hwnd, &rectDlg);
1950       GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1951       GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1952       /* subtract the height of the help button plus the space between the help
1953        * button and the cancel button to the height of the dialog
1954        */
1955       SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1956           (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1957           SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1958     }
1959   }
1960   return TRUE;
1961 }
1962 
1963 /***********************************************************************
1964  *      FILEDLG95_FillControls
1965  *
1966  * WM_INITDIALOG message handler (after hook notification)
1967  */
1968 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1969 {
1970   LPITEMIDLIST pidlItemId = NULL;
1971 
1972   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1973 
1974   TRACE("dir=%s file=%s\n",
1975   debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1976 
1977   /* Get the initial directory pidl */
1978 
1979   if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1980   {
1981     WCHAR path[MAX_PATH];
1982 
1983     GetCurrentDirectoryW(MAX_PATH,path);
1984     pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1985   }
1986 
1987   /* Initialise shell objects */
1988   FILEDLG95_SHELL_Init(hwnd);
1989 
1990   /* Initialize the Look In combo box */
1991   FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1992 
1993   /* Browse to the initial directory */
1994   IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1995 
1996   ILFree(pidlItemId);
1997 
1998   return TRUE;
1999 }
2000 /***********************************************************************
2001  *      FILEDLG95_Clean
2002  *
2003  * Regroups all the cleaning functions of the filedlg
2004  */
2005 void FILEDLG95_Clean(HWND hwnd)
2006 {
2007       FILEDLG95_FILETYPE_Clean(hwnd);
2008       FILEDLG95_LOOKIN_Clean(hwnd);
2009       FILEDLG95_SHELL_Clean(hwnd);
2010 }
2011 
2012 
2013 /***********************************************************************
2014  * Browse to arbitrary pidl
2015  */
2016 static void filedlg_browse_to_pidl(const FileOpenDlgInfos *info, LPITEMIDLIST pidl)
2017 {
2018     TRACE("%p, %p\n", info->ShellInfos.hwndOwner, pidl);
2019 
2020     IShellBrowser_BrowseObject(info->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2021     if (info->ofnInfos->Flags & OFN_EXPLORER)
2022         SendCustomDlgNotificationMessage(info->ShellInfos.hwndOwner, CDN_FOLDERCHANGE);
2023 }
2024 
2025 /***********************************************************************
2026  *      FILEDLG95_OnWMCommand
2027  *
2028  * WM_COMMAND message handler
2029  */
2030 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
2031 {
2032   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2033   WORD wNotifyCode = HIWORD(wParam); /* notification code */
2034   WORD id = LOWORD(wParam);         /* item, control, or accelerator identifier */
2035 
2036   switch (id)
2037   {
2038     /* OK button */
2039   case IDOK:
2040     FILEDLG95_OnOpen(hwnd);
2041     break;
2042     /* Cancel button */
2043   case IDCANCEL:
2044     FILEDLG95_Clean(hwnd);
2045     EndDialog(hwnd, FALSE);
2046     break;
2047     /* Filetype combo box */
2048   case IDC_FILETYPE:
2049     FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
2050     break;
2051     /* LookIn combo box */
2052   case IDC_LOOKIN:
2053     FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
2054     break;
2055 
2056   /* --- toolbar --- */
2057     /* Up folder button */
2058   case FCIDM_TB_UPFOLDER:
2059     FILEDLG95_SHELL_UpFolder(hwnd);
2060     break;
2061     /* New folder button */
2062   case FCIDM_TB_NEWFOLDER:
2063     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
2064     break;
2065     /* List option button */
2066   case FCIDM_TB_SMALLICON:
2067     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
2068     break;
2069     /* Details option button */
2070   case FCIDM_TB_REPORTVIEW:
2071     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
2072     break;
2073 
2074   case FCIDM_TB_DESKTOP:
2075   {
2076     LPITEMIDLIST pidl;
2077 
2078     SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidl);
2079     filedlg_browse_to_pidl(fodInfos, pidl);
2080     ILFree(pidl);
2081     break;
2082   }
2083 
2084   /* Places bar */
2085   case TBPLACES_CMDID_PLACE0:
2086   case TBPLACES_CMDID_PLACE1:
2087   case TBPLACES_CMDID_PLACE2:
2088   case TBPLACES_CMDID_PLACE3:
2089   case TBPLACES_CMDID_PLACE4:
2090     filedlg_browse_to_pidl(fodInfos, fodInfos->places[id - TBPLACES_CMDID_PLACE0]);
2091     break;
2092 
2093   case edt1:
2094   case cmb13:
2095     break;
2096 
2097   }
2098   /* Do not use the listview selection anymore */
2099   fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
2100   return 0;
2101 }
2102 
2103 /***********************************************************************
2104  *      FILEDLG95_OnWMGetIShellBrowser
2105  *
2106  * WM_GETISHELLBROWSER message handler
2107  */
2108 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
2109 {
2110   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2111 
2112   TRACE("\n");
2113 
2114   SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
2115 
2116   return TRUE;
2117 }
2118 
2119 
2120 /***********************************************************************
2121  *      FILEDLG95_SendFileOK
2122  *
2123  * Sends the CDN_FILEOK notification if required
2124  *
2125  * RETURNS
2126  *  TRUE if the dialog should close
2127  *  FALSE if the dialog should not be closed
2128  */
2129 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
2130 {
2131     /* ask the hook if we can close */
2132     if (is_dialog_hooked(fodInfos))
2133     {
2134         LRESULT retval = 0;
2135 
2136         TRACE("---\n");
2137         /* First send CDN_FILEOK as MSDN doc says */
2138         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2139             retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
2140         if( retval)
2141         {
2142             TRACE("canceled\n");
2143             return FALSE;
2144         }
2145 
2146         /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2147         retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
2148                               fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
2149         if( retval)
2150         {
2151             TRACE("canceled\n");
2152             return FALSE;
2153         }
2154     }
2155     return TRUE;
2156 }
2157 
2158 /***********************************************************************
2159  *      FILEDLG95_OnOpenMultipleFiles
2160  *
2161  * Handles the opening of multiple files.
2162  *
2163  * FIXME
2164  *  check destination buffer size
2165  */
2166 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2167 {
2168   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2169   WCHAR   lpstrPathSpec[MAX_PATH] = {0};
2170   UINT   nCount, nSizePath;
2171 
2172   TRACE("\n");
2173 
2174   if(fodInfos->unicode)
2175   {
2176      LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2177      ofn->lpstrFile[0] = '\0';
2178   }
2179   else
2180   {
2181      LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2182      ofn->lpstrFile[0] = '\0';
2183   }
2184 
2185   COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2186 
2187   if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2188       ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2189        ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2190   {
2191     LPWSTR lpstrTemp = lpstrFileList;
2192 
2193     for ( nCount = 0; nCount < nFileCount; nCount++ )
2194     {
2195       LPITEMIDLIST pidl;
2196 
2197       pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2198       if (!pidl)
2199       {
2200         WCHAR lpstrNotFound[100];
2201         WCHAR lpstrMsg[100];
2202         WCHAR tmp[400];
2203         static const WCHAR nl[] = {'\n',0};
2204 
2205         LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2206         LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2207 
2208         lstrcpyW(tmp, lpstrTemp);
2209         lstrcatW(tmp, nl);
2210         lstrcatW(tmp, lpstrNotFound);
2211         lstrcatW(tmp, nl);
2212         lstrcatW(tmp, lpstrMsg);
2213 
2214         MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2215         return FALSE;
2216       }
2217 
2218       /* move to the next file in the list of files */
2219       lpstrTemp += lstrlenW(lpstrTemp) + 1;
2220       ILFree(pidl);
2221     }
2222   }
2223 
2224   nSizePath = lstrlenW(lpstrPathSpec) + 1;
2225   if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2226   {
2227     /* For "oldstyle" dialog the components have to
2228        be separated by blanks (not '\0'!) and short
2229        filenames have to be used! */
2230     FIXME("Components have to be separated by blanks\n");
2231   }
2232   if(fodInfos->unicode)
2233   {
2234     LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2235     lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2236     memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2237   }
2238   else
2239   {
2240     LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2241 
2242     if (ofn->lpstrFile != NULL)
2243     {
2244       nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2245 			  ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2246       if (ofn->nMaxFile > nSizePath)
2247       {
2248 	WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2249 			    ofn->lpstrFile + nSizePath,
2250 			    ofn->nMaxFile - nSizePath, NULL, NULL);
2251       }
2252     }
2253   }
2254 
2255   fodInfos->ofnInfos->nFileOffset = nSizePath;
2256   fodInfos->ofnInfos->nFileExtension = 0;
2257 
2258   if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2259     return FALSE;
2260 
2261   /* clean and exit */
2262   FILEDLG95_Clean(hwnd);
2263   return EndDialog(hwnd,TRUE);
2264 }
2265 
2266 /* Returns the 'slot name' of the given module_name in the registry's
2267  * most-recently-used list.  This will be an ASCII value in the
2268  * range ['a','z'). Returns zero on error.
2269  *
2270  * The slot's value in the registry has the form:
2271  *   module_name\0mru_path\0
2272  *
2273  * If stored_path is given, then stored_path will contain the path name
2274  * stored in the registry's MRU list for the given module_name.
2275  *
2276  * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2277  * MRU list key for the given module_name.
2278  */
2279 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2280 {
2281     WCHAR mru_list[32], *cur_mru_slot;
2282     BOOL taken[25] = {0};
2283     DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2284     HKEY hkey_tmp, *hkey;
2285     LONG ret;
2286 
2287     if(hkey_ret)
2288         hkey = hkey_ret;
2289     else
2290         hkey = &hkey_tmp;
2291 
2292     if(stored_path)
2293         *stored_path = '\0';
2294 
2295     ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2296     if(ret){
2297         WARN("Unable to create MRU key: %d\n", ret);
2298         return 0;
2299     }
2300 
2301     ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2302             (LPBYTE)mru_list, &mru_list_size);
2303     if(ret || key_type != REG_SZ){
2304         if(ret == ERROR_FILE_NOT_FOUND)
2305             return 'a';
2306 
2307         WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2308         RegCloseKey(*hkey);
2309         return 0;
2310     }
2311 
2312     for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2313         WCHAR value_data[MAX_PATH], value_name[2] = {0};
2314         DWORD value_data_size = sizeof(value_data);
2315 
2316         *value_name = *cur_mru_slot;
2317 
2318         ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2319                 &key_type, (LPBYTE)value_data, &value_data_size);
2320         if(ret || key_type != REG_BINARY){
2321             WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2322             continue;
2323         }
2324 
2325         if(!strcmpiW(module_name, value_data)){
2326             if(!hkey_ret)
2327                 RegCloseKey(*hkey);
2328             if(stored_path)
2329                 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2330             return *value_name;
2331         }
2332     }
2333 
2334     if(!hkey_ret)
2335         RegCloseKey(*hkey);
2336 
2337     /* the module name isn't in the registry, so find the next open slot */
2338     for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2339         taken[*cur_mru_slot - 'a'] = TRUE;
2340     for(i = 0; i < 25; ++i){
2341         if(!taken[i])
2342             return i + 'a';
2343     }
2344 
2345     /* all slots are taken, so return the last one in MRUList */
2346     --cur_mru_slot;
2347     return *cur_mru_slot;
2348 }
2349 
2350 /* save the given filename as most-recently-used path for this module */
2351 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2352 {
2353     WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2354     LONG ret;
2355     HKEY hkey;
2356 
2357     /* get the current executable's name */
2358     if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2359     {
2360         WARN("GotModuleFileName failed: %d\n", GetLastError());
2361         return;
2362     }
2363     module_name = strrchrW(module_path, '\\');
2364     if(!module_name)
2365         module_name = module_path;
2366     else
2367         module_name += 1;
2368 
2369     slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2370     if(!slot)
2371         return;
2372     *slot_name = slot;
2373 
2374     { /* update the slot's info */
2375         WCHAR *path_ends, *final;
2376         DWORD path_len, final_len;
2377 
2378         /* use only the path segment of `filename' */
2379         path_ends = strrchrW(filename, '\\');
2380         path_len = path_ends - filename;
2381 
2382         final_len = path_len + lstrlenW(module_name) + 2;
2383 
2384         final = heap_alloc(final_len * sizeof(WCHAR));
2385         if(!final)
2386             return;
2387         lstrcpyW(final, module_name);
2388         memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2389         final[final_len-1] = '\0';
2390 
2391         ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2392                 final_len * sizeof(WCHAR));
2393         if(ret){
2394             WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2395             heap_free(final);
2396             RegCloseKey(hkey);
2397             return;
2398         }
2399 
2400         heap_free(final);
2401     }
2402 
2403     { /* update MRUList value */
2404         WCHAR old_mru_list[32], new_mru_list[32];
2405         WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2406         DWORD mru_list_size = sizeof(old_mru_list), key_type;
2407 
2408         ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2409                 (LPBYTE)old_mru_list, &mru_list_size);
2410         if(ret || key_type != REG_SZ){
2411             if(ret == ERROR_FILE_NOT_FOUND){
2412                 new_mru_list[0] = slot;
2413                 new_mru_list[1] = '\0';
2414             }else{
2415                 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2416                 RegCloseKey(hkey);
2417                 return;
2418             }
2419         }else{
2420             /* copy old list data over so that the new slot is at the start
2421              * of the list */
2422             *new_mru_slot++ = slot;
2423             for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2424                 if(*old_mru_slot != slot)
2425                     *new_mru_slot++ = *old_mru_slot;
2426             }
2427             *new_mru_slot = '\0';
2428         }
2429 
2430         ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2431                 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2432         if(ret){
2433             WARN("Error saving MRUList data: %d\n", ret);
2434             RegCloseKey(hkey);
2435             return;
2436         }
2437     }
2438 }
2439 
2440 /* load the most-recently-used path for this module */
2441 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2442 {
2443     WCHAR module_path[MAX_PATH], *module_name;
2444 
2445     /* get the current executable's name */
2446     if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2447     {
2448         WARN("GotModuleFileName failed: %d\n", GetLastError());
2449         return;
2450     }
2451     module_name = strrchrW(module_path, '\\');
2452     if(!module_name)
2453         module_name = module_path;
2454     else
2455         module_name += 1;
2456 
2457     FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2458     TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2459 }
2460 
2461 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2462 {
2463   WCHAR strMsgTitle[MAX_PATH];
2464   WCHAR strMsgText [MAX_PATH];
2465   if (idCaption)
2466     LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, ARRAY_SIZE(strMsgTitle));
2467   else
2468     strMsgTitle[0] = '\0';
2469   LoadStringW(COMDLG32_hInstance, idText, strMsgText, ARRAY_SIZE(strMsgText));
2470   MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2471 }
2472 
2473 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2474                                  HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2475 {
2476     int nOpenAction = defAction;
2477     LPWSTR lpszTemp, lpszTemp1;
2478     LPITEMIDLIST pidl = NULL;
2479     static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2480 
2481     /* check for invalid chars */
2482     if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2483     {
2484         FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2485         return FALSE;
2486     }
2487 
2488     if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2489 
2490     lpszTemp1 = lpszTemp = lpstrPathAndFile;
2491     while (lpszTemp1)
2492     {
2493         LPSHELLFOLDER lpsfChild;
2494         WCHAR lpwstrTemp[MAX_PATH];
2495         DWORD dwEaten, dwAttributes;
2496         LPWSTR p;
2497 
2498         lstrcpyW(lpwstrTemp, lpszTemp);
2499         p = PathFindNextComponentW(lpwstrTemp);
2500 
2501         if (!p) break; /* end of path */
2502 
2503         *p = 0;
2504         lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2505 
2506         /* There are no wildcards when OFN_NOVALIDATE is set */
2507         if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2508         {
2509             static const WCHAR wszWild[] = { '*', '?', 0 };
2510             /* if the last element is a wildcard do a search */
2511             if(strpbrkW(lpszTemp1, wszWild) != NULL)
2512             {
2513                 nOpenAction = ONOPEN_SEARCH;
2514                 break;
2515             }
2516         }
2517         lpszTemp1 = lpszTemp;
2518 
2519         TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2520 
2521         /* append a backslash to drive letters */
2522         if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2523            ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2524             (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2525         {
2526             PathAddBackslashW(lpwstrTemp);
2527         }
2528 
2529         dwAttributes = SFGAO_FOLDER;
2530         if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2531         {
2532             /* the path component is valid, we have a pidl of the next path component */
2533             TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2534             if(dwAttributes & SFGAO_FOLDER)
2535             {
2536                 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2537                 {
2538                     ERR("bind to failed\n"); /* should not fail */
2539                     break;
2540                 }
2541                 IShellFolder_Release(*ppsf);
2542                 *ppsf = lpsfChild;
2543                 lpsfChild = NULL;
2544             }
2545             else
2546             {
2547                 TRACE("value\n");
2548 
2549                 /* end dialog, return value */
2550                 nOpenAction = ONOPEN_OPEN;
2551                 break;
2552             }
2553             ILFree(pidl);
2554             pidl = NULL;
2555         }
2556         else if (!(flags & OFN_NOVALIDATE))
2557         {
2558             if(*lpszTemp ||	/* points to trailing null for last path element */
2559                (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2560             {
2561                 if(flags & OFN_PATHMUSTEXIST)
2562                 {
2563                     FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2564                     break;
2565                 }
2566             }
2567             else
2568             {
2569                 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2570                 {
2571                     FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2572                     break;
2573                 }
2574             }
2575             /* change to the current folder */
2576             nOpenAction = ONOPEN_OPEN;
2577             break;
2578         }
2579         else
2580         {
2581             nOpenAction = ONOPEN_OPEN;
2582             break;
2583         }
2584     }
2585     ILFree(pidl);
2586 
2587     return nOpenAction;
2588 }
2589 
2590 /***********************************************************************
2591  *      FILEDLG95_OnOpen
2592  *
2593  * Ok button WM_COMMAND message handler
2594  *
2595  * If the function succeeds, the return value is nonzero.
2596  */
2597 BOOL FILEDLG95_OnOpen(HWND hwnd)
2598 {
2599   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2600   LPWSTR lpstrFileList;
2601   UINT nFileCount = 0;
2602   UINT sizeUsed = 0;
2603   BOOL ret = TRUE;
2604   WCHAR lpstrPathAndFile[MAX_PATH];
2605   LPSHELLFOLDER lpsf = NULL;
2606   int nOpenAction;
2607 
2608   TRACE("hwnd=%p\n", hwnd);
2609 
2610   /* try to browse the selected item */
2611   if(BrowseSelectedFolder(hwnd))
2612       return FALSE;
2613 
2614   /* get the files from the edit control */
2615   nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2616 
2617   if(nFileCount == 0)
2618       return FALSE;
2619 
2620   if(nFileCount > 1)
2621   {
2622       ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2623       goto ret;
2624   }
2625 
2626   TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2627 
2628 /*
2629   Step 1:  Build a complete path name from the current folder and
2630   the filename or path in the edit box.
2631   Special cases:
2632   - the path in the edit box is a root path
2633     (with or without drive letter)
2634   - the edit box contains ".." (or a path with ".." in it)
2635 */
2636 
2637   COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2638   heap_free(lpstrFileList);
2639 
2640 /*
2641   Step 2: here we have a cleaned up path
2642 
2643   We have to parse the path step by step to see if we have to browse
2644   to a folder if the path points to a directory or the last
2645   valid element is a directory.
2646 
2647   valid variables:
2648     lpstrPathAndFile: cleaned up path
2649  */
2650 
2651   if (nFileCount &&
2652       (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2653       !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2654     nOpenAction = ONOPEN_OPEN;
2655   else
2656     nOpenAction = ONOPEN_BROWSE;
2657 
2658   nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2659                                              fodInfos->ofnInfos->Flags,
2660                                              fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2661                                              nOpenAction);
2662   if(!nOpenAction)
2663       goto ret;
2664 
2665 /*
2666   Step 3: here we have a cleaned up and validated path
2667 
2668   valid variables:
2669    lpsf:             ShellFolder bound to the rightmost valid path component
2670    lpstrPathAndFile: cleaned up path
2671    nOpenAction:      action to do
2672 */
2673   TRACE("end validate sf=%p\n", lpsf);
2674 
2675   switch(nOpenAction)
2676   {
2677     case ONOPEN_SEARCH:   /* set the current filter to the file mask and refresh */
2678       TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2679       {
2680         int iPos;
2681         LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2682         DWORD len;
2683 
2684         /* replace the current filter */
2685         heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
2686         len = lstrlenW(lpszTemp)+1;
2687         fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc(len * sizeof(WCHAR));
2688         lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2689 
2690         /* set the filter cb to the extension when possible */
2691         if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2692         SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, iPos, 0);
2693       }
2694       /* fall through */
2695     case ONOPEN_BROWSE:   /* browse to the highest folder we could bind to */
2696       TRACE("ONOPEN_BROWSE\n");
2697       {
2698 	IPersistFolder2 * ppf2;
2699         if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2700         {
2701           LPITEMIDLIST pidlCurrent;
2702           IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2703           IPersistFolder2_Release(ppf2);
2704           if (!ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2705 	  {
2706             if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2707                 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2708             {
2709               SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2710               SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
2711             }
2712 	  }
2713 	  else if( nOpenAction == ONOPEN_SEARCH )
2714 	  {
2715             if (fodInfos->Shell.FOIShellView)
2716               IShellView_Refresh(fodInfos->Shell.FOIShellView);
2717 	  }
2718           ILFree(pidlCurrent);
2719           if (filename_is_edit( fodInfos ))
2720               SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2721           else
2722           {
2723               HWND hwnd;
2724 
2725               hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
2726               SendMessageW(hwnd, EM_SETSEL, 0, -1);
2727           }
2728         }
2729       }
2730       ret = FALSE;
2731       break;
2732     case ONOPEN_OPEN:   /* fill in the return struct and close the dialog */
2733       TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2734       {
2735         WCHAR *ext = NULL;
2736 
2737         /* update READONLY check box flag */
2738 	if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2739 	  fodInfos->ofnInfos->Flags |= OFN_READONLY;
2740 	else
2741 	  fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2742 
2743         /* Attach the file extension with file name*/
2744         ext = PathFindExtensionW(lpstrPathAndFile);
2745         if (! *ext && fodInfos->defext)
2746         {
2747             /* if no extension is specified with file name, then */
2748             /* attach the extension from file filter or default one */
2749 
2750             WCHAR *filterExt = NULL;
2751             LPWSTR lpstrFilter = NULL;
2752             static const WCHAR szwDot[] = {'.',0};
2753             int PathLength = lstrlenW(lpstrPathAndFile);
2754 
2755             /*Get the file extension from file type filter*/
2756             lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2757                                              fodInfos->ofnInfos->nFilterIndex-1);
2758 
2759             if (lpstrFilter != (LPWSTR)CB_ERR)  /* control is not empty */
2760             {
2761                 WCHAR* filterSearchIndex;
2762                 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2763                 strcpyW(filterExt, lpstrFilter);
2764 
2765                 /* if a semicolon-separated list of file extensions was given, do not include the
2766                    semicolon or anything after it in the extension.
2767                    example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2768                 filterSearchIndex = strchrW(filterExt, ';');
2769                 if (filterSearchIndex)
2770                 {
2771                     filterSearchIndex[0] = '\0';
2772                 }
2773 
2774                 /* find the file extension by searching for the first dot in filterExt */
2775                 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2776                 /* if the extension is invalid or contains a glob, ignore it */
2777                 filterSearchIndex = strchrW(filterExt, '.');
2778                 if (filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2779                 {
2780                     strcpyW(filterExt, filterSearchIndex);
2781                 }
2782                 else
2783                 {
2784                     heap_free(filterExt);
2785                     filterExt = NULL;
2786                 }
2787             }
2788 
2789             if (!filterExt)
2790             {
2791                 /* use the default file extension */
2792                 filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2793                 strcpyW(filterExt, fodInfos->defext);
2794             }
2795 
2796             if (*filterExt) /* ignore filterExt="" */
2797             {
2798                 /* Attach the dot*/
2799                 lstrcatW(lpstrPathAndFile, szwDot);
2800                 /* Attach the extension */
2801                 lstrcatW(lpstrPathAndFile, filterExt);
2802             }
2803 
2804             heap_free(filterExt);
2805 
2806             /* In Open dialog: if file does not exist try without extension */
2807             if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2808                   lpstrPathAndFile[PathLength] = '\0';
2809 
2810             /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2811             if (*ext)
2812                 ext++;
2813             if (!lstrcmpiW(fodInfos->defext, ext))
2814                 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2815             else
2816                 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2817 	}
2818 
2819 	/* In Save dialog: check if the file already exists */
2820 	if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2821 	    && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2822 	    && PathFileExistsW(lpstrPathAndFile))
2823 	{
2824 	  WCHAR lpstrOverwrite[100];
2825 	  int answer;
2826 
2827 	  LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2828 	  answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2829 			       MB_YESNO | MB_ICONEXCLAMATION);
2830 	  if (answer == IDNO || answer == IDCANCEL)
2831 	  {
2832 	    ret = FALSE;
2833 	    goto ret;
2834 	  }
2835 	}
2836 
2837         /* In Open dialog: check if it should be created if it doesn't exist */
2838         if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2839             && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2840             && !PathFileExistsW(lpstrPathAndFile))
2841         {
2842           WCHAR lpstrCreate[100];
2843           int answer;
2844 
2845           LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2846           answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2847                                MB_YESNO | MB_ICONEXCLAMATION);
2848           if (answer == IDNO || answer == IDCANCEL)
2849           {
2850             ret = FALSE;
2851             goto ret;
2852           }
2853         }
2854 
2855         /* Check that the size of the file does not exceed buffer size.
2856              (Allow for extra \0 if OFN_MULTISELECT is set.) */
2857         if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2858             ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2859         {
2860 
2861           /* fill destination buffer */
2862           if (fodInfos->ofnInfos->lpstrFile)
2863           {
2864              if(fodInfos->unicode)
2865              {
2866                LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2867 
2868                lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2869                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2870                  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2871              }
2872              else
2873              {
2874                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2875 
2876                WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2877                                    ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2878                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2879                  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2880              }
2881           }
2882 
2883           if(fodInfos->unicode)
2884           {
2885               LPWSTR lpszTemp;
2886 
2887               /* set filename offset */
2888               lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2889               fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2890 
2891               /* set extension offset */
2892               lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2893               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2894           }
2895           else
2896           {
2897               LPSTR lpszTemp;
2898               CHAR tempFileA[MAX_PATH];
2899 
2900               /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2901               WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2902                                   tempFileA, sizeof(tempFileA), NULL, NULL);
2903 
2904               /* set filename offset */
2905               lpszTemp = PathFindFileNameA(tempFileA);
2906               fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2907 
2908               /* set extension offset */
2909               lpszTemp = PathFindExtensionA(tempFileA);
2910               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2911           }
2912 
2913           /* copy currently selected filter to lpstrCustomFilter */
2914           if (fodInfos->ofnInfos->lpstrCustomFilter)
2915           {
2916             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2917             int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2918                                           NULL, 0, NULL, NULL);
2919             if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2920             {
2921               LPSTR s = ofn->lpstrCustomFilter;
2922               s += strlen(ofn->lpstrCustomFilter)+1;
2923               WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2924                                   s, len, NULL, NULL);
2925             }
2926           }
2927 
2928 
2929           if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2930 	      goto ret;
2931 
2932           FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2933 
2934           TRACE("close\n");
2935 	  FILEDLG95_Clean(hwnd);
2936           ret = EndDialog(hwnd, TRUE);
2937 	}
2938 	else
2939         {
2940           WORD size;
2941 
2942           size = lstrlenW(lpstrPathAndFile) + 1;
2943           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2944              size += 1;
2945           /* return needed size in first two bytes of lpstrFile */
2946           if(fodInfos->ofnInfos->lpstrFile)
2947               *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2948           FILEDLG95_Clean(hwnd);
2949           ret = EndDialog(hwnd, FALSE);
2950           COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2951         }
2952       }
2953       break;
2954   }
2955 
2956 ret:
2957   if(lpsf) IShellFolder_Release(lpsf);
2958   return ret;
2959 }
2960 
2961 /***********************************************************************
2962  *      FILEDLG95_SHELL_Init
2963  *
2964  * Initialisation of the shell objects
2965  */
2966 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2967 {
2968   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2969 
2970   TRACE("%p\n", hwnd);
2971 
2972   /*
2973    * Initialisation of the FileOpenDialogInfos structure
2974    */
2975 
2976   /* Shell */
2977 
2978   /*ShellInfos */
2979   fodInfos->ShellInfos.hwndOwner = hwnd;
2980 
2981   /* Disable multi-select if flag not set */
2982   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2983   {
2984      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2985   }
2986   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2987   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2988 
2989   /* Construct the IShellBrowser interface */
2990   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2991 
2992   return NOERROR;
2993 }
2994 
2995 /***********************************************************************
2996  *      FILEDLG95_SHELL_ExecuteCommand
2997  *
2998  * Change the folder option and refresh the view
2999  * If the function succeeds, the return value is nonzero.
3000  */
3001 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
3002 {
3003   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3004   IContextMenu * pcm;
3005 
3006   TRACE("(%p,%p)\n", hwnd, lpVerb);
3007 
3008   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
3009 					SVGIO_BACKGROUND,
3010 					&IID_IContextMenu,
3011 					(LPVOID*)&pcm)))
3012   {
3013     CMINVOKECOMMANDINFO ci;
3014     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
3015     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
3016     ci.lpVerb = lpVerb;
3017     ci.hwnd = hwnd;
3018 
3019     IContextMenu_InvokeCommand(pcm, &ci);
3020     IContextMenu_Release(pcm);
3021   }
3022 
3023   return FALSE;
3024 }
3025 
3026 /***********************************************************************
3027  *      FILEDLG95_SHELL_UpFolder
3028  *
3029  * Browse to the specified object
3030  * If the function succeeds, the return value is nonzero.
3031  */
3032 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
3033 {
3034   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3035 
3036   TRACE("\n");
3037 
3038   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3039                                           NULL,
3040                                           SBSP_PARENT)))
3041   {
3042     if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3043         SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3044     return TRUE;
3045   }
3046   return FALSE;
3047 }
3048 /***********************************************************************
3049  *      FILEDLG95_SHELL_Clean
3050  *
3051  * Cleans the memory used by shell objects
3052  */
3053 static void FILEDLG95_SHELL_Clean(HWND hwnd)
3054 {
3055     FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3056 
3057     TRACE("\n");
3058 
3059     ILFree(fodInfos->ShellInfos.pidlAbsCurrent);
3060 
3061     /* clean Shell interfaces */
3062     if (fodInfos->Shell.FOIShellView)
3063     {
3064       IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
3065       IShellView_Release(fodInfos->Shell.FOIShellView);
3066     }
3067     if (fodInfos->Shell.FOIShellFolder)
3068       IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
3069     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
3070     if (fodInfos->Shell.FOIDataObject)
3071       IDataObject_Release(fodInfos->Shell.FOIDataObject);
3072 }
3073 
3074 /***********************************************************************
3075  *      FILEDLG95_FILETYPE_Init
3076  *
3077  * Initialisation of the file type combo box
3078  */
3079 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
3080 {
3081   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3082   int nFilters = 0;  /* number of filters */
3083   int nFilterIndexCB;
3084 
3085   TRACE("%p\n", hwnd);
3086 
3087   if(fodInfos->customfilter)
3088   {
3089       /* customfilter has one entry...  title\0ext\0
3090        * Set first entry of combo box item with customfilter
3091        */
3092       LPWSTR  lpstrExt;
3093       LPCWSTR lpstrPos = fodInfos->customfilter;
3094 
3095       /* Get the title */
3096       lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
3097 
3098       /* Copy the extensions */
3099       if (! *lpstrPos) return E_FAIL;	/* malformed filter */
3100       if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3101       lstrcpyW(lpstrExt,lpstrPos);
3102 
3103       /* Add the item at the end of the combo */
3104       SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter);
3105       SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt);
3106 
3107       nFilters++;
3108   }
3109   if(fodInfos->filter)
3110   {
3111     LPCWSTR lpstrPos = fodInfos->filter;
3112 
3113     for(;;)
3114     {
3115       /* filter is a list...  title\0ext\0......\0\0
3116        * Set the combo item text to the title and the item data
3117        *  to the ext
3118        */
3119       LPCWSTR lpstrDisplay;
3120       LPWSTR lpstrExt;
3121 
3122       /* Get the title */
3123       if(! *lpstrPos) break;	/* end */
3124       lpstrDisplay = lpstrPos;
3125       lpstrPos += lstrlenW(lpstrPos) + 1;
3126 
3127       SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay);
3128 
3129       nFilters++;
3130 
3131       /* Copy the extensions */
3132       if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3133       lstrcpyW(lpstrExt,lpstrPos);
3134       lpstrPos += lstrlenW(lpstrPos) + 1;
3135 
3136       /* Add the item at the end of the combo */
3137       SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt);
3138 
3139       /* malformed filters are added anyway... */
3140       if (!*lpstrExt) break;
3141     }
3142   }
3143 
3144   /*
3145    * Set the current filter to the one specified
3146    * in the initialisation structure
3147    */
3148   if (fodInfos->filter || fodInfos->customfilter)
3149   {
3150     LPWSTR lpstrFilter;
3151 
3152     /* Check to make sure our index isn't out of bounds. */
3153     if ( fodInfos->ofnInfos->nFilterIndex >
3154          nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3155       fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3156 
3157     /* set default filter index */
3158     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3159       fodInfos->ofnInfos->nFilterIndex = 1;
3160 
3161     /* calculate index of Combo Box item */
3162     nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3163     if (fodInfos->customfilter == NULL)
3164       nFilterIndexCB--;
3165 
3166     /* Set the current index selection. */
3167     SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0);
3168 
3169     /* Get the corresponding text string from the combo box. */
3170     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3171                                              nFilterIndexCB);
3172 
3173     if ((INT_PTR)lpstrFilter == CB_ERR)  /* control is empty */
3174       lpstrFilter = NULL;
3175 
3176     if(lpstrFilter)
3177     {
3178       DWORD len;
3179       CharLowerW(lpstrFilter); /* lowercase */
3180       len = lstrlenW(lpstrFilter)+1;
3181       fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3182       lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3183     }
3184   } else
3185       fodInfos->ofnInfos->nFilterIndex = 0;
3186   return S_OK;
3187 }
3188 
3189 /***********************************************************************
3190  *      FILEDLG95_FILETYPE_OnCommand
3191  *
3192  * WM_COMMAND of the file type combo box
3193  * If the function succeeds, the return value is nonzero.
3194  */
3195 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3196 {
3197   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3198 
3199   switch(wNotifyCode)
3200   {
3201     case CBN_SELENDOK:
3202     {
3203       LPWSTR lpstrFilter;
3204 
3205       /* Get the current item of the filetype combo box */
3206       int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0);
3207 
3208       /* set the current filter index */
3209       fodInfos->ofnInfos->nFilterIndex = iItem +
3210         (fodInfos->customfilter == NULL ? 1 : 0);
3211 
3212       /* Set the current filter with the current selection */
3213       heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3214 
3215       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3216                                              iItem);
3217       if((INT_PTR)lpstrFilter != CB_ERR)
3218       {
3219           DWORD len;
3220           CharLowerW(lpstrFilter); /* lowercase */
3221           len = lstrlenW(lpstrFilter)+1;
3222           fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3223           lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3224           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3225               SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3226       }
3227 
3228       /* Refresh the actual view to display the included items*/
3229       if (fodInfos->Shell.FOIShellView)
3230         IShellView_Refresh(fodInfos->Shell.FOIShellView);
3231     }
3232   }
3233   return FALSE;
3234 }
3235 /***********************************************************************
3236  *      FILEDLG95_FILETYPE_SearchExt
3237  *
3238  * searches for an extension in the filetype box
3239  */
3240 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3241 {
3242   int i, iCount;
3243 
3244   iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3245 
3246   TRACE("%s\n", debugstr_w(lpstrExt));
3247 
3248   if(iCount != CB_ERR)
3249   {
3250     for(i=0;i<iCount;i++)
3251     {
3252       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3253           return i;
3254     }
3255   }
3256   return -1;
3257 }
3258 
3259 /***********************************************************************
3260  *      FILEDLG95_FILETYPE_Clean
3261  *
3262  * Clean the memory used by the filetype combo box
3263  */
3264 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3265 {
3266   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3267   int iPos;
3268   int iCount;
3269 
3270   iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0);
3271 
3272   TRACE("\n");
3273 
3274   /* Delete each string of the combo and their associated data */
3275   if(iCount != CB_ERR)
3276   {
3277     for(iPos = iCount-1;iPos>=0;iPos--)
3278     {
3279       heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3280       SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0);
3281     }
3282   }
3283   /* Current filter */
3284   heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3285 }
3286 
3287 /***********************************************************************
3288  *      FILEDLG95_LOOKIN_Init
3289  *
3290  * Initialisation of the look in combo box
3291  */
3292 
3293 /* Small helper function, to determine if the unixfs shell extension is rooted
3294  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3295  */
3296 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3297     HKEY hKey;
3298     static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3299         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3300         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3301         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3302         'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3303         '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3304         '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3305 
3306     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3307         return FALSE;
3308 
3309     RegCloseKey(hKey);
3310     return TRUE;
3311 }
3312 
3313 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3314 {
3315   IShellFolder	*psfRoot, *psfDrives;
3316   IEnumIDList	*lpeRoot, *lpeDrives;
3317   LPITEMIDLIST	pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3318   HDC hdc;
3319   TEXTMETRICW tm;
3320   LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos));
3321 
3322   TRACE("%p\n", hwndCombo);
3323 
3324   liInfos->iMaxIndentation = 0;
3325 
3326   SetPropA(hwndCombo, LookInInfosStr, liInfos);
3327 
3328   hdc = GetDC( hwndCombo );
3329   SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3330   GetTextMetricsW( hdc, &tm );
3331   ReleaseDC( hwndCombo, hdc );
3332 
3333   /* set item height for both text field and listbox */
3334   SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3335   SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3336 
3337   /* Turn on the extended UI for the combo box like Windows does */
3338   SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0);
3339 
3340   /* Initialise data of Desktop folder */
3341   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3342   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3343   ILFree(pidlTmp);
3344 
3345   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3346 
3347   SHGetDesktopFolder(&psfRoot);
3348 
3349   if (psfRoot)
3350   {
3351     /* enumerate the contents of the desktop */
3352     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3353     {
3354       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3355       {
3356 	FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3357 
3358 	/* If the unixfs extension is rooted, we don't expand the drives by default */
3359 	if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3360 	{
3361 	  /* special handling for CSIDL_DRIVES */
3362 	  if (ILIsEqual(pidlTmp, pidlDrives))
3363 	  {
3364 	    if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3365 	    {
3366 	      /* enumerate the drives */
3367 	      if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3368 	      {
3369 	        while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3370 	        {
3371 	          pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1);
3372 	          FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3373 	          ILFree(pidlAbsTmp);
3374 	          ILFree(pidlTmp1);
3375 	        }
3376 	        IEnumIDList_Release(lpeDrives);
3377 	      }
3378 	      IShellFolder_Release(psfDrives);
3379 	    }
3380 	  }
3381 	}
3382 
3383         ILFree(pidlTmp);
3384       }
3385       IEnumIDList_Release(lpeRoot);
3386     }
3387     IShellFolder_Release(psfRoot);
3388   }
3389 
3390   ILFree(pidlDrives);
3391 }
3392 
3393 /***********************************************************************
3394  *      FILEDLG95_LOOKIN_DrawItem
3395  *
3396  * WM_DRAWITEM message handler
3397  */
3398 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3399 {
3400   COLORREF crWin = GetSysColor(COLOR_WINDOW);
3401   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3402   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3403   RECT rectText;
3404   RECT rectIcon;
3405   SHFILEINFOW sfi;
3406   HIMAGELIST ilItemImage;
3407   int iIndentation;
3408   TEXTMETRICW tm;
3409   LPSFOLDER tmpFolder;
3410   UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3411   UINT icon_width, icon_height;
3412 
3413   TRACE("\n");
3414 
3415   if(pDIStruct->itemID == -1)
3416     return 0;
3417 
3418   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3419                             pDIStruct->itemID)))
3420     return 0;
3421 
3422 
3423   icon_width = GetSystemMetrics(SM_CXICON);
3424   icon_height = GetSystemMetrics(SM_CYICON);
3425   if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3426   {
3427       icon_width = GetSystemMetrics(SM_CXSMICON);
3428       icon_height = GetSystemMetrics(SM_CYSMICON);
3429       shgfi_flags |= SHGFI_SMALLICON;
3430   }
3431 
3432   ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3433                                              0, &sfi, sizeof (sfi), shgfi_flags );
3434 
3435   /* Is this item selected ? */
3436   if(pDIStruct->itemState & ODS_SELECTED)
3437   {
3438     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3439     SetBkColor(pDIStruct->hDC,crHighLight);
3440     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3441   }
3442   else
3443   {
3444     SetTextColor(pDIStruct->hDC,crText);
3445     SetBkColor(pDIStruct->hDC,crWin);
3446     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3447   }
3448 
3449   /* Do not indent item if drawing in the edit of the combo */
3450   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3451     iIndentation = 0;
3452   else
3453     iIndentation = tmpFolder->m_iIndent;
3454 
3455   /* Draw text and icon */
3456 
3457   /* Initialise the icon display area */
3458   rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3459   rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3460   rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3461   rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3462 
3463   /* Initialise the text display area */
3464   GetTextMetricsW(pDIStruct->hDC, &tm);
3465   rectText.left = rectIcon.right;
3466   rectText.top =
3467 	  (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3468   rectText.right = pDIStruct->rcItem.right;
3469   rectText.bottom =
3470 	  (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3471 
3472   /* Draw the icon from the image list */
3473   ImageList_Draw(ilItemImage,
3474                  sfi.iIcon,
3475                  pDIStruct->hDC,
3476                  rectIcon.left,
3477                  rectIcon.top,
3478                  ILD_TRANSPARENT );
3479 
3480   /* Draw the associated text */
3481   TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3482   return NOERROR;
3483 }
3484 
3485 /***********************************************************************
3486  *      FILEDLG95_LOOKIN_OnCommand
3487  *
3488  * LookIn combo box WM_COMMAND message handler
3489  * If the function succeeds, the return value is nonzero.
3490  */
3491 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3492 {
3493   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3494 
3495   TRACE("%p\n", fodInfos);
3496 
3497   switch(wNotifyCode)
3498   {
3499     case CBN_SELENDOK:
3500     {
3501       LPSFOLDER tmpFolder;
3502       int iItem;
3503 
3504       iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0);
3505 
3506       if( iItem == CB_ERR) return FALSE;
3507 
3508       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3509                                                iItem)))
3510 	return FALSE;
3511 
3512 
3513       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3514                                               tmpFolder->pidlItem,
3515                                               SBSP_ABSOLUTE)))
3516       {
3517         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3518             SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3519         return TRUE;
3520       }
3521       break;
3522     }
3523 
3524   }
3525   return FALSE;
3526 }
3527 
3528 /***********************************************************************
3529  *      FILEDLG95_LOOKIN_AddItem
3530  *
3531  * Adds an absolute pidl item to the lookin combo box
3532  * returns the index of the inserted item
3533  */
3534 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3535 {
3536   LPITEMIDLIST pidlNext;
3537   SHFILEINFOW sfi;
3538   SFOLDER *tmpFolder;
3539   LookInInfos *liInfos;
3540 
3541   TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId);
3542 
3543   if(!pidl)
3544     return -1;
3545 
3546   if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3547     return -1;
3548 
3549   tmpFolder = heap_alloc_zero(sizeof(*tmpFolder));
3550   tmpFolder->m_iIndent = 0;
3551 
3552   /* Calculate the indentation of the item in the lookin*/
3553   pidlNext = pidl;
3554   while ((pidlNext = ILGetNext(pidlNext)))
3555   {
3556     tmpFolder->m_iIndent++;
3557   }
3558 
3559   tmpFolder->pidlItem = ILClone(pidl);
3560 
3561   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3562     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3563 
3564   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3565   SHGetFileInfoW((LPCWSTR)pidl,
3566                   0,
3567                   &sfi,
3568                   sizeof(sfi),
3569                   SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3570 
3571   TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3572 
3573   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3574   {
3575     int iItemID;
3576 
3577     TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3578 
3579     /* Add the item at the end of the list */
3580     if(iInsertId < 0)
3581     {
3582       iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName);
3583     }
3584     /* Insert the item at the iInsertId position*/
3585     else
3586     {
3587       iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName);
3588     }
3589 
3590     SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder);
3591     return iItemID;
3592   }
3593 
3594   ILFree( tmpFolder->pidlItem );
3595   heap_free( tmpFolder );
3596   return -1;
3597 
3598 }
3599 
3600 /***********************************************************************
3601  *      FILEDLG95_LOOKIN_InsertItemAfterParent
3602  *
3603  * Insert an item below its parent
3604  */
3605 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3606 {
3607 
3608   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3609   int iParentPos;
3610 
3611   TRACE("\n");
3612 
3613   if (pidl == pidlParent)
3614     return -1;
3615 
3616   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3617 
3618   if(iParentPos < 0)
3619   {
3620     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3621   }
3622 
3623   ILFree(pidlParent);
3624 
3625   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3626 }
3627 
3628 /***********************************************************************
3629  *      FILEDLG95_LOOKIN_SelectItem
3630  *
3631  * Adds an absolute pidl item to the lookin combo box
3632  * returns the index of the inserted item
3633  */
3634 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3635 {
3636   int iItemPos;
3637   LookInInfos *liInfos;
3638 
3639   TRACE("%p, %p\n", hwnd, pidl);
3640 
3641   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3642 
3643   liInfos = GetPropA(hwnd,LookInInfosStr);
3644 
3645   if(iItemPos < 0)
3646   {
3647     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3648     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3649   }
3650 
3651   else
3652   {
3653     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3654     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3655     {
3656       int iRemovedItem;
3657 
3658       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3659         break;
3660       if(iRemovedItem < iItemPos)
3661         iItemPos--;
3662     }
3663   }
3664 
3665   SendMessageW(hwnd, CB_SETCURSEL, iItemPos, 0);
3666   liInfos->uSelectedItem = iItemPos;
3667 
3668   return 0;
3669 
3670 }
3671 
3672 /***********************************************************************
3673  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
3674  *
3675  * Remove the item with an expansion level over iExpansionLevel
3676  */
3677 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3678 {
3679   int iItemPos;
3680   LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3681 
3682   TRACE("\n");
3683 
3684   if(liInfos->iMaxIndentation <= 2)
3685     return -1;
3686 
3687   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3688   {
3689     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3690     ILFree(tmpFolder->pidlItem);
3691     heap_free(tmpFolder);
3692     SendMessageW(hwnd, CB_DELETESTRING, iItemPos, 0);
3693     liInfos->iMaxIndentation--;
3694 
3695     return iItemPos;
3696   }
3697 
3698   return -1;
3699 }
3700 
3701 /***********************************************************************
3702  *      FILEDLG95_LOOKIN_SearchItem
3703  *
3704  * Search for pidl in the lookin combo box
3705  * returns the index of the found item
3706  */
3707 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3708 {
3709   int i = 0;
3710   int iCount;
3711 
3712   iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3713 
3714   TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3715 
3716   if (iCount != CB_ERR)
3717   {
3718     for(;i<iCount;i++)
3719     {
3720       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3721 
3722       if (iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg, tmpFolder->pidlItem))
3723         return i;
3724       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3725         return i;
3726     }
3727   }
3728 
3729   return -1;
3730 }
3731 
3732 /***********************************************************************
3733  *      FILEDLG95_LOOKIN_Clean
3734  *
3735  * Clean the memory used by the lookin combo box
3736  */
3737 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3738 {
3739     FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3740     LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3741     int iPos, iCount;
3742 
3743     iCount = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCOUNT, 0, 0);
3744 
3745     TRACE("\n");
3746 
3747     /* Delete each string of the combo and their associated data */
3748     if (iCount != CB_ERR)
3749     {
3750       for(iPos = iCount-1;iPos>=0;iPos--)
3751       {
3752         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3753         ILFree(tmpFolder->pidlItem);
3754         heap_free(tmpFolder);
3755         SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_DELETESTRING, iPos, 0);
3756       }
3757     }
3758 
3759     /* LookInInfos structure */
3760     heap_free(liInfos);
3761     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3762 }
3763 
3764 /***********************************************************************
3765  *          get_def_format
3766  *
3767  * Fill the FORMATETC used in the shell id list
3768  */
3769 static FORMATETC get_def_format(void)
3770 {
3771     static CLIPFORMAT cfFormat;
3772     FORMATETC formatetc;
3773 
3774     if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3775     formatetc.cfFormat = cfFormat;
3776     formatetc.ptd = 0;
3777     formatetc.dwAspect = DVASPECT_CONTENT;
3778     formatetc.lindex = -1;
3779     formatetc.tymed = TYMED_HGLOBAL;
3780     return formatetc;
3781 }
3782 
3783 /***********************************************************************
3784  * FILEDLG95_FILENAME_FillFromSelection
3785  *
3786  * fills the edit box from the cached DataObject
3787  */
3788 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3789 {
3790     FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3791     LPITEMIDLIST      pidl;
3792     LPWSTR            lpstrAllFiles, lpstrTmp;
3793     UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3794     STGMEDIUM medium;
3795     LPIDA cida;
3796     FORMATETC formatetc = get_def_format();
3797 
3798     TRACE("\n");
3799 
3800     if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3801         return;
3802 
3803     cida = GlobalLock(medium.u.hGlobal);
3804     nFileSelected = cida->cidl;
3805 
3806     /* Allocate a buffer */
3807     nAllFilesMaxLength = MAX_PATH + 3;
3808     lpstrAllFiles = heap_alloc_zero(nAllFilesMaxLength * sizeof(WCHAR));
3809     if (!lpstrAllFiles)
3810         goto ret;
3811 
3812     /* Loop through the selection, handle only files (not folders) */
3813     for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3814     {
3815         pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3816         if (pidl)
3817         {
3818             if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3819             {
3820                 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3821                 {
3822                     nAllFilesMaxLength *= 2;
3823                     lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3824                     if (!lpstrTmp)
3825                         goto ret;
3826                     lpstrAllFiles = lpstrTmp;
3827                 }
3828                 nFiles += 1;
3829                 lpstrAllFiles[nAllFilesLength++] = '"';
3830                 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3831                 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3832                 nAllFilesLength += nThisFileLength;
3833                 lpstrAllFiles[nAllFilesLength++] = '"';
3834                 lpstrAllFiles[nAllFilesLength++] = ' ';
3835             }
3836         }
3837     }
3838 
3839     if (nFiles != 0)
3840     {
3841         /* If there's only one file, use the name as-is without quotes */
3842         lpstrTmp = lpstrAllFiles;
3843         if (nFiles == 1)
3844         {
3845             lpstrTmp += 1;
3846             lpstrTmp[nThisFileLength] = 0;
3847         }
3848         SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3849         /* Select the file name like Windows does */
3850         if (filename_is_edit(fodInfos))
3851             SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3852     }
3853 
3854 ret:
3855     heap_free(lpstrAllFiles);
3856     COMCTL32_ReleaseStgMedium(medium);
3857 }
3858 
3859 
3860 /* copied from shell32 to avoid linking to it
3861  * Although shell32 is already linked the behaviour of exported StrRetToStrN
3862  * is dependent on whether emulated OS is unicode or not.
3863  */
3864 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3865 {
3866 	switch (src->uType)
3867 	{
3868 	  case STRRET_WSTR:
3869 	    lstrcpynW(dest, src->u.pOleStr, len);
3870 	    CoTaskMemFree(src->u.pOleStr);
3871 	    break;
3872 
3873 	  case STRRET_CSTR:
3874             if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3875                   dest[len-1] = 0;
3876 	    break;
3877 
3878 	  case STRRET_OFFSET:
3879             if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3880                   dest[len-1] = 0;
3881 	    break;
3882 
3883 	  default:
3884 	    FIXME("unknown type %x!\n", src->uType);
3885 	    if (len) *dest = '\0';
3886 	    return E_FAIL;
3887 	}
3888 	return S_OK;
3889 }
3890 
3891 /***********************************************************************
3892  * FILEDLG95_FILENAME_GetFileNames
3893  *
3894  * Copies the filenames to a delimited string list.
3895  */
3896 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3897 {
3898 	FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3899 	UINT nFileCount = 0;	/* number of files */
3900 	UINT nStrLen = 0;	/* length of string in edit control */
3901 	LPWSTR lpstrEdit;	/* buffer for string from edit control */
3902 
3903 	TRACE("\n");
3904 
3905 	/* get the filenames from the filename control */
3906 	nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3907 	lpstrEdit = heap_alloc( (nStrLen+1)*sizeof(WCHAR) );
3908 	GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3909 
3910 	TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3911 
3912 	nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3913 	heap_free(lpstrEdit);
3914 	return nFileCount;
3915 }
3916 
3917 /*
3918  * DATAOBJECT Helper functions
3919  */
3920 
3921 /***********************************************************************
3922  * COMCTL32_ReleaseStgMedium
3923  *
3924  * like ReleaseStgMedium from ole32
3925  */
3926 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3927 {
3928       if(medium.pUnkForRelease)
3929       {
3930         IUnknown_Release(medium.pUnkForRelease);
3931       }
3932       else
3933       {
3934         GlobalUnlock(medium.u.hGlobal);
3935         GlobalFree(medium.u.hGlobal);
3936       }
3937 }
3938 
3939 /***********************************************************************
3940  *          GetPidlFromDataObject
3941  *
3942  * Return pidl(s) by number from the cached DataObject
3943  *
3944  * nPidlIndex=0 gets the fully qualified root path
3945  */
3946 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3947 {
3948 
3949     STGMEDIUM medium;
3950     FORMATETC formatetc = get_def_format();
3951     LPITEMIDLIST pidl = NULL;
3952 
3953     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3954 
3955     if (!doSelected)
3956         return NULL;
3957 
3958     /* Get the pidls from IDataObject */
3959     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3960     {
3961       LPIDA cida = GlobalLock(medium.u.hGlobal);
3962       if(nPidlIndex <= cida->cidl)
3963       {
3964         pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3965       }
3966       COMCTL32_ReleaseStgMedium(medium);
3967     }
3968     return pidl;
3969 }
3970 
3971 /***********************************************************************
3972  *          GetNumSelected
3973  *
3974  * Return the number of selected items in the DataObject.
3975  *
3976 */
3977 static UINT GetNumSelected( IDataObject *doSelected )
3978 {
3979     UINT retVal = 0;
3980     STGMEDIUM medium;
3981     FORMATETC formatetc = get_def_format();
3982 
3983     TRACE("sv=%p\n", doSelected);
3984 
3985     if (!doSelected) return 0;
3986 
3987     /* Get the pidls from IDataObject */
3988     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3989     {
3990       LPIDA cida = GlobalLock(medium.u.hGlobal);
3991       retVal = cida->cidl;
3992       COMCTL32_ReleaseStgMedium(medium);
3993       return retVal;
3994     }
3995     return 0;
3996 }
3997 
3998 /*
3999  * TOOLS
4000  */
4001 
4002 /***********************************************************************
4003  *      GetName
4004  *
4005  * Get the pidl's display name (relative to folder) and
4006  * put it in lpstrFileName.
4007  *
4008  * Return NOERROR on success,
4009  * E_FAIL otherwise
4010  */
4011 
4012 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
4013 {
4014   STRRET str;
4015   HRESULT hRes;
4016 
4017   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
4018 
4019   if(!lpsf)
4020   {
4021     SHGetDesktopFolder(&lpsf);
4022     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
4023     IShellFolder_Release(lpsf);
4024     return hRes;
4025   }
4026 
4027   /* Get the display name of the pidl relative to the folder */
4028   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
4029   {
4030       return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
4031   }
4032   return E_FAIL;
4033 }
4034 
4035 /***********************************************************************
4036  *      GetShellFolderFromPidl
4037  *
4038  * pidlRel is the item pidl relative
4039  * Return the IShellFolder of the absolute pidl
4040  */
4041 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
4042 {
4043   IShellFolder *psf = NULL,*psfParent;
4044 
4045   TRACE("%p\n", pidlAbs);
4046 
4047   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
4048   {
4049     psf = psfParent;
4050     if(pidlAbs && pidlAbs->mkid.cb)
4051     {
4052       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
4053       {
4054 	IShellFolder_Release(psfParent);
4055         return psf;
4056       }
4057     }
4058     /* return the desktop */
4059     return psfParent;
4060   }
4061   return NULL;
4062 }
4063 
4064 /***********************************************************************
4065  *      GetParentPidl
4066  *
4067  * Return the LPITEMIDLIST to the parent of the pidl in the list
4068  */
4069 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
4070 {
4071   LPITEMIDLIST pidlParent;
4072 
4073   TRACE("%p\n", pidl);
4074 
4075   pidlParent = ILClone(pidl);
4076   ILRemoveLastID(pidlParent);
4077 
4078   return pidlParent;
4079 }
4080 
4081 /***********************************************************************
4082  *      GetPidlFromName
4083  *
4084  * returns the pidl of the file name relative to folder
4085  * NULL if an error occurred
4086  */
4087 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
4088 {
4089   LPITEMIDLIST pidl = NULL;
4090   ULONG ulEaten;
4091 
4092   TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
4093 
4094   if(!lpcstrFileName) return NULL;
4095   if(!*lpcstrFileName) return NULL;
4096 
4097   if(!lpsf)
4098   {
4099     if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
4100         IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4101         IShellFolder_Release(lpsf);
4102     }
4103   }
4104   else
4105   {
4106     IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4107   }
4108   return pidl;
4109 }
4110 
4111 /*
4112 */
4113 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
4114 {
4115 	ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
4116 	HRESULT ret;
4117 
4118 	TRACE("%p, %p\n", psf, pidl);
4119 
4120   	ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4121 
4122 	TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
4123 	/* see documentation shell 4.1*/
4124         return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4125 }
4126 
4127 /***********************************************************************
4128  *      BrowseSelectedFolder
4129  */
4130 static BOOL BrowseSelectedFolder(HWND hwnd)
4131 {
4132   FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
4133   BOOL bBrowseSelFolder = FALSE;
4134 
4135   TRACE("\n");
4136 
4137   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4138   {
4139       LPITEMIDLIST pidlSelection;
4140 
4141       /* get the file selected */
4142       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4143       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4144       {
4145           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4146                          pidlSelection, SBSP_RELATIVE ) ) )
4147           {
4148                WCHAR buf[64];
4149                LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, ARRAY_SIZE(buf));
4150                MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4151           }
4152           bBrowseSelFolder = TRUE;
4153           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4154               SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4155       }
4156       ILFree( pidlSelection );
4157   }
4158 
4159   return bBrowseSelFolder;
4160 }
4161 
4162 static inline BOOL valid_struct_size( DWORD size )
4163 {
4164     return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4165         (size == sizeof( OPENFILENAMEW ));
4166 }
4167 
4168 static inline BOOL is_win16_looks(DWORD flags)
4169 {
4170     return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4171             !(flags & OFN_EXPLORER));
4172 }
4173 
4174 /* ------------------ APIs ---------------------- */
4175 
4176 /***********************************************************************
4177  *            GetOpenFileNameA  (COMDLG32.@)
4178  *
4179  * Creates a dialog box for the user to select a file to open.
4180  *
4181  * RETURNS
4182  *    TRUE on success: user enters a valid file
4183  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4184  *
4185  */
4186 BOOL WINAPI GetOpenFileNameA(OPENFILENAMEA *ofn)
4187 {
4188     TRACE("flags 0x%08x\n", ofn->Flags);
4189 
4190     if (!valid_struct_size( ofn->lStructSize ))
4191     {
4192         COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4193         return FALSE;
4194     }
4195 
4196     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4197     if (ofn->Flags & OFN_FILEMUSTEXIST)
4198         ofn->Flags |= OFN_PATHMUSTEXIST;
4199 
4200     if (is_win16_looks(ofn->Flags))
4201         return GetFileName31A(ofn, OPEN_DIALOG);
4202     else
4203     {
4204         FileOpenDlgInfos info;
4205 
4206         init_filedlg_infoA(ofn, &info);
4207         return GetFileDialog95(&info, OPEN_DIALOG);
4208     }
4209 }
4210 
4211 /***********************************************************************
4212  *            GetOpenFileNameW (COMDLG32.@)
4213  *
4214  * Creates a dialog box for the user to select a file to open.
4215  *
4216  * RETURNS
4217  *    TRUE on success: user enters a valid file
4218  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4219  *
4220  */
4221 BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn)
4222 {
4223     TRACE("flags 0x%08x\n", ofn->Flags);
4224 
4225     if (!valid_struct_size( ofn->lStructSize ))
4226     {
4227         COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4228         return FALSE;
4229     }
4230 
4231     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4232     if (ofn->Flags & OFN_FILEMUSTEXIST)
4233         ofn->Flags |= OFN_PATHMUSTEXIST;
4234 
4235     if (is_win16_looks(ofn->Flags))
4236         return GetFileName31W(ofn, OPEN_DIALOG);
4237     else
4238     {
4239         FileOpenDlgInfos info;
4240 
4241         init_filedlg_infoW(ofn, &info);
4242         return GetFileDialog95(&info, OPEN_DIALOG);
4243     }
4244 }
4245 
4246 
4247 /***********************************************************************
4248  *            GetSaveFileNameA  (COMDLG32.@)
4249  *
4250  * Creates a dialog box for the user to select a file to save.
4251  *
4252  * RETURNS
4253  *    TRUE on success: user enters a valid file
4254  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4255  *
4256  */
4257 BOOL WINAPI GetSaveFileNameA(OPENFILENAMEA *ofn)
4258 {
4259     if (!valid_struct_size( ofn->lStructSize ))
4260     {
4261         COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4262         return FALSE;
4263     }
4264 
4265     if (is_win16_looks(ofn->Flags))
4266         return GetFileName31A(ofn, SAVE_DIALOG);
4267     else
4268     {
4269         FileOpenDlgInfos info;
4270 
4271         init_filedlg_infoA(ofn, &info);
4272         return GetFileDialog95(&info, SAVE_DIALOG);
4273     }
4274 }
4275 
4276 /***********************************************************************
4277  *            GetSaveFileNameW  (COMDLG32.@)
4278  *
4279  * Creates a dialog box for the user to select a file to save.
4280  *
4281  * RETURNS
4282  *    TRUE on success: user enters a valid file
4283  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4284  *
4285  */
4286 BOOL WINAPI GetSaveFileNameW(
4287 	LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4288 {
4289     if (!valid_struct_size( ofn->lStructSize ))
4290     {
4291         COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4292         return FALSE;
4293     }
4294 
4295     if (is_win16_looks(ofn->Flags))
4296         return GetFileName31W(ofn, SAVE_DIALOG);
4297     else
4298     {
4299         FileOpenDlgInfos info;
4300 
4301         init_filedlg_infoW(ofn, &info);
4302         return GetFileDialog95(&info, SAVE_DIALOG);
4303     }
4304 }
4305 
4306 /***********************************************************************
4307  *	GetFileTitleA		(COMDLG32.@)
4308  *
4309  * See GetFileTitleW.
4310  */
4311 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4312 {
4313     int ret;
4314     UNICODE_STRING strWFile;
4315     LPWSTR lpWTitle;
4316 
4317     RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4318     lpWTitle = heap_alloc(cbBuf * sizeof(WCHAR));
4319     ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4320     if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4321     RtlFreeUnicodeString( &strWFile );
4322     heap_free( lpWTitle );
4323     return ret;
4324 }
4325 
4326 
4327 /***********************************************************************
4328  *	GetFileTitleW		(COMDLG32.@)
4329  *
4330  * Get the name of a file.
4331  *
4332  * PARAMS
4333  *  lpFile  [I] name and location of file
4334  *  lpTitle [O] returned file name
4335  *  cbBuf   [I] buffer size of lpTitle
4336  *
4337  * RETURNS
4338  *  Success: zero
4339  *  Failure: negative number.
4340  */
4341 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4342 {
4343 	int i, len;
4344         static const WCHAR brkpoint[] = {'*','[',']',0};
4345 	TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4346 
4347 	if(lpFile == NULL || lpTitle == NULL)
4348 		return -1;
4349 
4350 	len = lstrlenW(lpFile);
4351 
4352 	if (len == 0)
4353 		return -1;
4354 
4355 	if(strpbrkW(lpFile, brkpoint))
4356 		return -1;
4357 
4358 	len--;
4359 
4360 	if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4361 		return -1;
4362 
4363 	for(i = len; i >= 0; i--)
4364 	{
4365 		if (lpFile[i] == '/' ||  lpFile[i] == '\\' ||  lpFile[i] == ':')
4366 		{
4367 			i++;
4368 			break;
4369 		}
4370 	}
4371 
4372 	if(i == -1)
4373 		i++;
4374 
4375 	TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4376 
4377 	len = lstrlenW(lpFile+i)+1;
4378 	if(cbBuf < len)
4379 		return len;
4380 
4381 	lstrcpyW(lpTitle, &lpFile[i]);
4382 	return 0;
4383 }
4384