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