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