Update OFN_READONLY flag when closing file dialog.
[wine] / dlls / commdlg / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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: lpstrCustomFilter not handled
36  *
37  * FIXME: algorithm for selecting the initial directory is too simple
38  *
39  * FIXME: add to recent docs
40  *
41  * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
42  * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
43  * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
44  * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
45  *
46  * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
47  *
48  *
49  */
50
51 #include "config.h"
52 #include "wine/port.h"
53
54 #include <ctype.h>
55 #include <stdlib.h>
56 #include <stdarg.h>
57 #include <stdio.h>
58 #include <string.h>
59
60 #define NONAMELESSUNION
61 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winreg.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "commdlg.h"
71 #include "dlgs.h"
72 #include "cdlg.h"
73 #include "wine/debug.h"
74 #include "cderr.h"
75 #include "shellapi.h"
76 #include "shlguid.h"
77 #include "shlobj.h"
78 #include "filedlgbrowser.h"
79 #include "shlwapi.h"
80
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
82
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
85 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
86 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
87 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
88
89 #define IsHooked(fodInfos) \
90         ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
91 /***********************************************************************
92  * Data structure and global variables
93  */
94 typedef struct SFolder
95 {
96   int m_iImageIndex;    /* Index of picture in image list */
97   HIMAGELIST hImgList;
98   int m_iIndent;      /* Indentation index */
99   LPITEMIDLIST pidlItem;  /* absolute pidl of the item */
100
101 } SFOLDER,*LPSFOLDER;
102
103 typedef struct tagLookInInfo
104 {
105   int iMaxIndentation;
106   UINT uSelectedItem;
107 } LookInInfos;
108
109
110 /***********************************************************************
111  * Defines and global variables
112  */
113
114 /* Draw item constant */
115 #define ICONWIDTH 18
116 #define XTEXTOFFSET 3
117
118 /* AddItem flags*/
119 #define LISTEND -1
120
121 /* SearchItem methods */
122 #define SEARCH_PIDL 1
123 #define SEARCH_EXP  2
124 #define ITEM_NOTFOUND -1
125
126 /* Undefined windows message sent by CreateViewObject*/
127 #define WM_GETISHELLBROWSER  WM_USER+7
128
129 /* NOTE
130  * Those macros exist in windowsx.h. However, you can't really use them since
131  * they rely on the UNICODE defines and can't be used inside Wine itself.
132  */
133
134 /* Combo box macros */
135 #define CBAddString(hwnd,str) \
136   SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
137 #define CBAddStringW(hwnd,str) \
138   SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
139
140 #define CBInsertString(hwnd,str,pos) \
141   SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
142
143 #define CBDeleteString(hwnd,pos) \
144   SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
145
146 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
147   SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
148
149 #define CBGetItemDataPtr(hwnd,iItemId) \
150   SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
151
152 #define CBGetLBText(hwnd,iItemId,str) \
153   SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
154
155 #define CBGetCurSel(hwnd) \
156   SendMessageA(hwnd,CB_GETCURSEL,0,0);
157
158 #define CBSetCurSel(hwnd,pos) \
159   SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
160
161 #define CBGetCount(hwnd) \
162     SendMessageA(hwnd,CB_GETCOUNT,0,0);
163 #define CBShowDropDown(hwnd,show) \
164   SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
165 #define CBSetItemHeight(hwnd,index,height) \
166   SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
167
168 #define CBSetExtendedUI(hwnd,flag) \
169   SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
170
171 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
172 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
173
174 /***********************************************************************
175  * Prototypes
176  */
177
178 /* Internal functions used by the dialog */
179 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
180 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
181 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
182        BOOL    FILEDLG95_OnOpen(HWND hwnd);
183 static LRESULT FILEDLG95_InitControls(HWND hwnd);
184 static void    FILEDLG95_Clean(HWND hwnd);
185
186 /* Functions used by the shell navigation */
187 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
188 static BOOL    FILEDLG95_SHELL_UpFolder(HWND hwnd);
189 static BOOL    FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
190 static void    FILEDLG95_SHELL_Clean(HWND hwnd);
191 static BOOL    FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
192
193 /* Functions used by the filetype combo box */
194 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
195 static BOOL    FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
196 static int     FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
197 static void    FILEDLG95_FILETYPE_Clean(HWND hwnd);
198
199 /* Functions used by the Look In combo box */
200 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
201 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
202 static BOOL    FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
203 static int     FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
204 static int     FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
205 static int     FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
206 static int     FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
207        int     FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
208 static void    FILEDLG95_LOOKIN_Clean(HWND hwnd);
209
210 /* Miscellaneous tool functions */
211 HRESULT       GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
212 HRESULT       GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
213 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
214 LPITEMIDLIST  GetParentPidl(LPITEMIDLIST pidl);
215 LPITEMIDLIST  GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
216
217 /* Shell memory allocation */
218 static void *MemAlloc(UINT size);
219 static void MemFree(void *mem);
220
221 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
222 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
223 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
224 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
225 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
226 static BOOL BrowseSelectedFolder(HWND hwnd);
227
228 /* old style dialogs */
229 extern BOOL GetFileName31A(LPOPENFILENAMEA lpofn, UINT dlgType);
230 extern BOOL GetFileName31W(LPOPENFILENAMEW lpofn, UINT dlgType);
231
232 /***********************************************************************
233  *      GetFileName95
234  *
235  * Creates an Open common dialog box that lets the user select
236  * the drive, directory, and the name of a file or set of files to open.
237  *
238  * IN  : The FileOpenDlgInfos structure associated with the dialog
239  * OUT : TRUE on success
240  *       FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
241  */
242 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
243 {
244
245     LRESULT lRes;
246     LPCVOID template;
247     HRSRC hRes;
248     HANDLE hDlgTmpl = 0;
249
250     /* test for missing functionality */
251     if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
252     {
253       FIXME("Flags 0x%08lx not yet implemented\n",
254          fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
255     }
256
257     /* Create the dialog from a template */
258
259     if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
260     {
261         COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
262         return FALSE;
263     }
264     if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
265         !(template = LockResource( hDlgTmpl )))
266     {
267         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
268         return FALSE;
269     }
270
271     /* old style hook messages */
272     if (IsHooked(fodInfos))
273     {
274       fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
275       fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
276       fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
277       fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
278     }
279
280     lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
281                                   (LPDLGTEMPLATEA) template,
282                                   fodInfos->ofnInfos->hwndOwner,
283                                   FileOpenDlgProc95,
284                                   (LPARAM) fodInfos);
285
286     /* Unable to create the dialog */
287     if( lRes == -1)
288         return FALSE;
289
290     return lRes;
291 }
292
293 /***********************************************************************
294  *      GetFileDialog95A
295  *
296  * Call GetFileName95 with this structure and clean the memory.
297  *
298  * IN  : The OPENFILENAMEA initialisation structure passed to
299  *       GetOpenFileNameA win api function (see filedlg.c)
300  */
301 BOOL  WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
302 {
303   BOOL ret;
304   FileOpenDlgInfos fodInfos;
305   LPSTR lpstrSavDir = NULL;
306   LPWSTR title = NULL;
307   LPWSTR defext = NULL;
308   LPWSTR filter = NULL;
309   LPWSTR customfilter = NULL;
310
311   /* Initialize FileOpenDlgInfos structure */
312   ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
313
314   /* Pass in the original ofn */
315   fodInfos.ofnInfos = ofn;
316
317   /* save current directory */
318   if (ofn->Flags & OFN_NOCHANGEDIR)
319   {
320      lpstrSavDir = MemAlloc(MAX_PATH);
321      GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
322   }
323
324   fodInfos.unicode = FALSE;
325
326   /* convert all the input strings to unicode */
327   if(ofn->lpstrInitialDir)
328   {
329     DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
330     fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
331     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
332   }
333   else
334     fodInfos.initdir = NULL;
335
336   if(ofn->lpstrFile)
337   {
338     fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
339     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
340   }
341   else
342     fodInfos.filename = NULL;
343
344   if(ofn->lpstrDefExt)
345   {
346     DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
347     defext = MemAlloc((len+1)*sizeof(WCHAR));
348     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
349   }
350   fodInfos.defext = defext;
351
352   if(ofn->lpstrTitle)
353   {
354     DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
355     title = MemAlloc((len+1)*sizeof(WCHAR));
356     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
357   }
358   fodInfos.title = title;
359
360   if (ofn->lpstrFilter)
361   {
362     LPCSTR s;
363     int n, len;
364
365     /* filter is a list...  title\0ext\0......\0\0 */
366     s = ofn->lpstrFilter;
367     while (*s) s = s+strlen(s)+1;
368     s++;
369     n = s - ofn->lpstrFilter;
370     len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
371     filter = MemAlloc(len*sizeof(WCHAR));
372     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
373   }
374   fodInfos.filter = filter;
375
376   /* convert lpstrCustomFilter */
377   if (ofn->lpstrCustomFilter)
378   {
379     LPCSTR s;
380     int n, len;
381
382     /* filter is a list...  title\0ext\0......\0\0 */
383     s = ofn->lpstrCustomFilter;
384     while (*s) s = s+strlen(s)+1;
385     s++;
386     n = s - ofn->lpstrCustomFilter;
387     len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
388     customfilter = MemAlloc(len*sizeof(WCHAR));
389     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
390   }
391   fodInfos.customfilter = customfilter;
392
393   /* Initialize the dialog property */
394   fodInfos.DlgInfos.dwDlgProp = 0;
395   fodInfos.DlgInfos.hwndCustomDlg = NULL;
396
397   switch(iDlgType)
398   {
399     case OPEN_DIALOG :
400       ret = GetFileName95(&fodInfos);
401       break;
402     case SAVE_DIALOG :
403       fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
404       ret = GetFileName95(&fodInfos);
405       break;
406     default :
407       ret = 0;
408   }
409
410   if (lpstrSavDir)
411   {
412       SetCurrentDirectoryA(lpstrSavDir);
413       MemFree(lpstrSavDir);
414   }
415
416   if(title)
417     MemFree(title);
418   if(defext)
419     MemFree(defext);
420   if(filter)
421     MemFree(filter);
422   if(customfilter)
423     MemFree(customfilter);
424   if(fodInfos.initdir)
425     MemFree(fodInfos.initdir);
426
427   if(fodInfos.filename)
428     MemFree(fodInfos.filename);
429
430   TRACE("selected file: %s\n",ofn->lpstrFile);
431
432   return ret;
433 }
434
435 /***********************************************************************
436  *      GetFileDialog95W
437  *
438  * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
439  * Call GetFileName95 with this structure and clean the memory.
440  *
441  * FIXME: lpstrCustomFilter has to be converted back
442  *
443  */
444 BOOL  WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
445 {
446   BOOL ret;
447   FileOpenDlgInfos fodInfos;
448   LPSTR lpstrSavDir = NULL;
449
450   /* Initialize FileOpenDlgInfos structure */
451   ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
452
453   /*  Pass in the original ofn */
454   fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
455
456   fodInfos.title = ofn->lpstrTitle;
457   fodInfos.defext = ofn->lpstrDefExt;
458   fodInfos.filter = ofn->lpstrFilter;
459   fodInfos.customfilter = ofn->lpstrCustomFilter;
460
461   /* convert string arguments, save others */
462   if(ofn->lpstrFile)
463   {
464     fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
465     strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
466   }
467   else
468     fodInfos.filename = NULL;
469
470   if(ofn->lpstrInitialDir)
471   {
472     DWORD len = strlenW(ofn->lpstrInitialDir);
473     fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
474     strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
475   }
476   else
477     fodInfos.initdir = NULL;
478
479   /* save current directory */
480   if (ofn->Flags & OFN_NOCHANGEDIR)
481   {
482      lpstrSavDir = MemAlloc(MAX_PATH);
483      GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
484   }
485
486   fodInfos.unicode = TRUE;
487
488   switch(iDlgType)
489   {
490   case OPEN_DIALOG :
491       ret = GetFileName95(&fodInfos);
492       break;
493   case SAVE_DIALOG :
494       fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
495       ret = GetFileName95(&fodInfos);
496       break;
497   default :
498       ret = 0;
499   }
500
501   if (lpstrSavDir)
502   {
503       SetCurrentDirectoryA(lpstrSavDir);
504       MemFree(lpstrSavDir);
505   }
506
507   /* restore saved IN arguments and convert OUT arguments back */
508   MemFree(fodInfos.filename);
509   MemFree(fodInfos.initdir);
510   return ret;
511 }
512
513 /***********************************************************************
514  *      ArrangeCtrlPositions [internal]
515  *
516  * NOTE: Do not change anything here without a lot of testing.
517  */
518 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
519 {
520     HWND hwndChild, hwndStc32;
521     RECT rectParent, rectChild, rectStc32;
522     INT help_fixup = 0;
523
524     /* Take into account if open as read only checkbox and help button
525      * are hidden
526      */
527      if (hide_help)
528      {
529          RECT rectHelp, rectCancel;
530          GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
531          GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
532          /* subtract the height of the help button plus the space between
533           * the help button and the cancel button to the height of the dialog
534           */
535           help_fixup = rectHelp.bottom - rectCancel.bottom;
536     }
537
538     /*
539       There are two possibilities to add components to the default file dialog box.
540
541       By default, all the new components are added below the standard dialog box (the else case).
542
543       However, if there is a static text component with the stc32 id, a special case happens.
544       The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
545       in the window and the cx and cy indicate how to size the window.
546       Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left 
547       of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
548       
549      */
550
551     GetClientRect(hwndParentDlg, &rectParent);
552
553     /* when arranging controls we have to use fixed parent size */
554     rectParent.bottom -= help_fixup;
555
556     hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
557     if (hwndStc32)
558     {
559         GetWindowRect(hwndStc32, &rectStc32);
560         MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
561
562         /* set the size of the stc32 control according to the size of
563          * client area of the parent dialog
564          */
565         SetWindowPos(hwndStc32, 0,
566                      0, 0,
567                      rectParent.right, rectParent.bottom,
568                      SWP_NOMOVE | SWP_NOZORDER);
569     }
570     else
571         SetRectEmpty(&rectStc32);
572
573     /* this part moves controls of the child dialog */
574     hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
575     while (hwndChild)
576     {
577         if (hwndChild != hwndStc32)
578         {
579             GetWindowRect(hwndChild, &rectChild);
580             MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
581
582             /* move only if stc32 exist */
583             if (hwndStc32 && rectChild.left > rectStc32.right)
584             {
585                 /* move to the right of visible controls of the parent dialog */
586                 rectChild.left += rectParent.right;
587                 rectChild.left -= rectStc32.right;
588             }
589             /* move even if stc32 doesn't exist */
590             if (rectChild.top > rectStc32.bottom)
591             {
592                 /* move below visible controls of the parent dialog */
593                 rectChild.top += rectParent.bottom;
594                 rectChild.top -= rectStc32.bottom - rectStc32.top;
595             }
596
597             SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
598                          0, 0, SWP_NOSIZE | SWP_NOZORDER);
599         }
600         hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
601     }
602
603     /* this part moves controls of the parent dialog */
604     hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
605     while (hwndChild)
606     {
607         if (hwndChild != hwndChildDlg)
608         {
609             GetWindowRect(hwndChild, &rectChild);
610             MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
611
612             /* left,top of stc32 marks the position of controls
613              * from the parent dialog
614              */
615             rectChild.left += rectStc32.left;
616             rectChild.top += rectStc32.top;
617
618             SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
619                          0, 0, SWP_NOSIZE | SWP_NOZORDER);
620         }
621         hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
622     }
623
624     /* calculate the size of the resulting dialog */
625
626     /* here we have to use original parent size */
627     GetClientRect(hwndParentDlg, &rectParent);
628     GetClientRect(hwndChildDlg, &rectChild);
629
630     if (hwndStc32)
631     {
632         if (rectParent.right > rectChild.right)
633         {
634             rectParent.right += rectChild.right;
635             rectParent.right -= rectStc32.right - rectStc32.left;
636         }
637         else
638         {
639             rectParent.right = rectChild.right;
640         }
641
642         if (rectParent.bottom > rectChild.bottom)
643         {
644             rectParent.bottom += rectChild.bottom;
645             rectParent.bottom -= rectStc32.bottom - rectStc32.top;
646         }
647         else
648         {
649             rectParent.bottom = rectChild.bottom;
650         }
651     }
652     else
653     {
654         rectParent.bottom += rectChild.bottom;
655     }
656
657     /* finally use fixed parent size */
658     rectParent.bottom -= help_fixup;
659
660     /* save the size of the parent's client area */
661     rectChild.right = rectParent.right;
662     rectChild.bottom = rectParent.bottom;
663
664     /* set the size of the parent dialog */
665     AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
666                        FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
667     SetWindowPos(hwndParentDlg, 0,
668                  0, 0,
669                  rectParent.right - rectParent.left,
670                  rectParent.bottom - rectParent.top,
671                  SWP_NOMOVE | SWP_NOZORDER);
672
673     /* set the size of the child dialog */
674     SetWindowPos(hwndChildDlg, HWND_BOTTOM,
675                  0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
676 }
677
678 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
679 {
680     switch(uMsg) {
681     case WM_INITDIALOG:
682         return TRUE;
683     }
684     return FALSE;
685 }
686
687 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
688 {
689     LPCVOID template;
690     HRSRC hRes;
691     HANDLE hDlgTmpl = 0;
692     HWND hChildDlg = 0;
693
694     TRACE("\n");
695
696     /*
697      * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
698      * structure's hInstance parameter is not a HINSTANCE, but
699      * instead a pointer to a template resource to use.
700      */
701     if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
702     {
703       HINSTANCE hinst;
704       if (fodInfos->ofnInfos->Flags  & OFN_ENABLETEMPLATEHANDLE)
705       {
706         hinst = 0;
707         if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
708         {
709           COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
710           return NULL;
711         }
712       }
713       else
714       {
715         hinst = fodInfos->ofnInfos->hInstance;
716         if(fodInfos->unicode)
717         {
718             LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
719             hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
720         }
721         else
722         {
723             LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
724             hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
725         }
726         if (!hRes)
727         {
728           COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
729           return NULL;
730         }
731         if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
732             !(template = LockResource( hDlgTmpl )))
733         {
734           COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
735           return NULL;
736         }
737       }
738       hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
739                                              IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
740                                              (LPARAM)fodInfos->ofnInfos);
741       if(hChildDlg)
742       {
743         ShowWindow(hChildDlg,SW_SHOW);
744         return hChildDlg;
745       }
746     }
747     else if( IsHooked(fodInfos))
748     {
749       RECT rectHwnd;
750       struct  {
751          DLGTEMPLATE tmplate;
752          WORD menu,class,title;
753          } temp;
754       GetClientRect(hwnd,&rectHwnd);
755       temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
756       temp.tmplate.dwExtendedStyle = 0;
757       temp.tmplate.cdit = 0;
758       temp.tmplate.x = 0;
759       temp.tmplate.y = 0;
760       temp.tmplate.cx = 0;
761       temp.tmplate.cy = 0;
762       temp.menu = temp.class = temp.title = 0;
763
764       hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
765                   hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
766
767       return hChildDlg;
768     }
769     return NULL;
770 }
771
772 /***********************************************************************
773 *          SendCustomDlgNotificationMessage
774 *
775 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
776 */
777
778 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
779 {
780     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
781
782     TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
783
784     if(!fodInfos) return 0;
785
786     if(fodInfos->unicode)
787       FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
788
789     if(fodInfos->DlgInfos.hwndCustomDlg)
790     {
791         OFNOTIFYA ofnNotify;
792         HRESULT ret;
793         ofnNotify.hdr.hwndFrom=hwndParentDlg;
794         ofnNotify.hdr.idFrom=0;
795         ofnNotify.hdr.code = uCode;
796         ofnNotify.lpOFN = fodInfos->ofnInfos;
797         ofnNotify.pszFile = NULL;
798         TRACE("CALL NOTIFY for %x\n", uCode);
799         ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
800         TRACE("RET NOTIFY\n");
801         return ret;
802     }
803     return TRUE;
804 }
805
806 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPSTR buffer)
807 {
808     UINT sizeUsed = 0, n, total;
809     LPWSTR lpstrFileList = NULL;
810     WCHAR lpstrCurrentDir[MAX_PATH];
811     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
812
813     TRACE("CDM_GETFILEPATH:\n");
814
815     if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
816         return -1;
817
818     /* get path and filenames */
819     SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
820     n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
821
822     TRACE("path >%s< filespec >%s< %d files\n",
823          debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
824
825     total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1, 
826                                 NULL, 0, NULL, NULL);
827     total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, 
828                                 NULL, 0, NULL, NULL);
829
830     /* Prepend the current path */
831     n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1, 
832                             buffer, size, NULL, NULL);
833
834     if(n<size)
835     {
836         /* 'n' includes trailing \0 */
837         buffer[n-1] = '\\';
838         WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, 
839                             &buffer[n], size-n, NULL, NULL);
840     }
841     MemFree(lpstrFileList);
842
843     TRACE("returned -> %s\n",debugstr_a(buffer));
844
845     return total;
846 }
847
848 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPSTR buffer)
849 {
850     UINT sizeUsed = 0;
851     LPWSTR lpstrFileList = NULL;
852
853     TRACE("CDM_GETSPEC:\n");
854
855     FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
856     WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, buffer, size, NULL, NULL);
857     MemFree(lpstrFileList);
858
859     return sizeUsed;
860 }
861
862 /***********************************************************************
863 *         FILEDLG95_HandleCustomDialogMessages
864 *
865 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
866 */
867 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
868 {
869     char lpstrPath[MAX_PATH];
870     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
871     if(!fodInfos) return -1;
872
873     switch(uMsg)
874     {
875         case CDM_GETFILEPATH:
876             return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPSTR)lParam);
877
878         case CDM_GETFOLDERPATH:
879             TRACE("CDM_GETFOLDERPATH:\n");
880             SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
881             if ((LPSTR)lParam!=NULL)
882                 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
883             return strlen(lpstrPath);
884
885         case CDM_GETSPEC:
886             return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
887
888         case CDM_SETCONTROLTEXT:
889             TRACE("CDM_SETCONTROLTEXT:\n");
890             if ( 0 != lParam )
891                 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
892             return TRUE;
893
894         case CDM_HIDECONTROL:
895         case CDM_SETDEFEXT:
896             FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
897             return -1;
898     }
899     return TRUE;
900 }
901
902 /***********************************************************************
903  *          FileOpenDlgProc95
904  *
905  * File open dialog procedure
906  */
907 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
908 {
909 #if 0
910   TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
911 #endif
912
913   switch(uMsg)
914   {
915     case WM_INITDIALOG:
916       {
917          FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
918
919          /* Adds the FileOpenDlgInfos in the property list of the dialog
920             so it will be easily accessible through a GetPropA(...) */
921          SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
922
923          fodInfos->DlgInfos.hwndCustomDlg =
924            CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
925
926          FILEDLG95_InitControls(hwnd);
927
928          if (fodInfos->DlgInfos.hwndCustomDlg)
929              ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
930                  (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
931
932          FILEDLG95_FillControls(hwnd, wParam, lParam);
933
934          SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
935          SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
936          SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
937          return 0;
938        }
939     case WM_COMMAND:
940       return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
941     case WM_DRAWITEM:
942       {
943         switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
944         {
945         case IDC_LOOKIN:
946           FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
947           return TRUE;
948         }
949       }
950       return FALSE;
951
952     case WM_GETISHELLBROWSER:
953       return FILEDLG95_OnWMGetIShellBrowser(hwnd);
954
955     case WM_DESTROY:
956       RemovePropA(hwnd, FileOpenDlgInfosStr);
957       return FALSE;
958
959     case WM_NOTIFY:
960     {
961         LPNMHDR lpnmh = (LPNMHDR)lParam;
962         UINT stringId = -1;
963
964         /* set up the button tooltips strings */
965         if(TTN_GETDISPINFOA == lpnmh->code )
966         {
967             LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
968             switch(lpnmh->idFrom )
969             {
970                 /* Up folder button */
971                 case FCIDM_TB_UPFOLDER:
972                     stringId = IDS_UPFOLDER;
973                     break;
974                 /* New folder button */
975                 case FCIDM_TB_NEWFOLDER:
976                     stringId = IDS_NEWFOLDER;
977                     break;
978                 /* List option button */
979                 case FCIDM_TB_SMALLICON:
980                     stringId = IDS_LISTVIEW;
981                     break;
982                 /* Details option button */
983                 case FCIDM_TB_REPORTVIEW:
984                     stringId = IDS_REPORTVIEW;
985                     break;
986                 /* Desktop button */
987                 case FCIDM_TB_DESKTOP:
988                     stringId = IDS_TODESKTOP;
989                     break;
990                 default:
991                     stringId = 0;
992             }
993             lpdi->hinst = COMDLG32_hInstance;
994             lpdi->lpszText =  (LPSTR) stringId;
995         }
996         return FALSE;
997     }
998     default :
999       if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1000         return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1001       return FALSE;
1002   }
1003 }
1004
1005 /***********************************************************************
1006  *      FILEDLG95_InitControls
1007  *
1008  * WM_INITDIALOG message handler (before hook notification)
1009  */
1010 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1011 {
1012   int win2000plus = 0;
1013   int win98plus   = 0;
1014   int handledPath = FALSE;
1015   OSVERSIONINFOA osVi;
1016   static const WCHAR szwSlash[] = { '\\', 0 };
1017   static const WCHAR szwStar[] = { '*',0 };
1018
1019   TBBUTTON tbb[] =
1020   {
1021    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1022    {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER,   TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1023    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1024    {VIEW_NEWFOLDER+1,  FCIDM_TB_DESKTOP,    TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1025    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1026    {VIEW_NEWFOLDER,    FCIDM_TB_NEWFOLDER,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1027    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1028    {VIEW_LIST,         FCIDM_TB_SMALLICON,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1029    {VIEW_DETAILS,      FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1030   };
1031   TBADDBITMAP tba[2];
1032   RECT rectTB;
1033   RECT rectlook;
1034   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1035
1036   tba[0].hInst = HINST_COMMCTRL;
1037   tba[0].nID   = IDB_VIEW_SMALL_COLOR;
1038   tba[1].hInst = COMDLG32_hInstance;
1039   tba[1].nID   = 800;
1040
1041   TRACE("%p\n", fodInfos);
1042
1043   /* Get windows version emulating */
1044   osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1045   GetVersionExA(&osVi);
1046   if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1047     win98plus   = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1048   } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1049     win2000plus = (osVi.dwMajorVersion > 4);
1050     if (win2000plus) win98plus = TRUE;
1051   }
1052   TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1053
1054   /* Get the hwnd of the controls */
1055   fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1056   fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1057   fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1058
1059   GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1060   MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1061
1062   /* construct the toolbar */
1063   GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1064   MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1065
1066   rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1067   rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1068   rectTB.left = rectlook.right;
1069   rectTB.top = rectlook.top-1;
1070
1071   fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1072         WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1073         rectTB.left, rectTB.top,
1074         rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1075         hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1076
1077   SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1078
1079 /* FIXME: use TB_LOADIMAGES when implemented */
1080 /*  SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1081   SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1082   SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1083
1084   SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1085   SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1086
1087   /* Set the window text with the text specified in the OPENFILENAME structure */
1088   if(fodInfos->title)
1089   {
1090       SetWindowTextW(hwnd,fodInfos->title);
1091   }
1092   else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1093   {
1094       SetWindowTextA(hwnd,"Save");
1095   }
1096
1097   /* Initialise the file name edit control */
1098   handledPath = FALSE;
1099   TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1100
1101   if(fodInfos->filename)
1102   {
1103       /* 1. If win2000 or higher and filename contains a path, use it
1104          in preference over the lpstrInitialDir                       */
1105       if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1106          WCHAR tmpBuf[MAX_PATH];
1107          WCHAR *nameBit;
1108          DWORD result;
1109
1110          result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1111          if (result) {
1112
1113             /* nameBit is always shorter than the original filename */
1114             strcpyW(fodInfos->filename,nameBit);
1115
1116             *nameBit = 0x00;
1117             if (fodInfos->initdir == NULL)
1118                 MemFree(fodInfos->initdir);
1119             fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1120             strcpyW(fodInfos->initdir, tmpBuf);
1121             handledPath = TRUE;
1122             TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1123                     debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1124          }
1125          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1126
1127       } else {
1128          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1129       }
1130   }
1131
1132   /* 2. (All platforms) If initdir is not null, then use it */
1133   if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1134                                 (*fodInfos->initdir!=0x00))
1135   {
1136       /* Work out the proper path as supplied one might be relative          */
1137       /* (Here because supplying '.' as dir browses to My Computer)          */
1138       if (handledPath==FALSE) {
1139           WCHAR tmpBuf[MAX_PATH];
1140           WCHAR tmpBuf2[MAX_PATH];
1141           WCHAR *nameBit;
1142           DWORD result;
1143
1144           strcpyW(tmpBuf, fodInfos->initdir);
1145           if( PathFileExistsW(tmpBuf) ) {
1146               /* initdir does not have to be a directory. If a file is
1147                * specified, the dir part is taken */
1148               if( PathIsDirectoryW(tmpBuf)) {
1149                   if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1150                      strcatW(tmpBuf, szwSlash);
1151                   }
1152                   strcatW(tmpBuf, szwStar);
1153               }
1154               result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1155               if (result) {
1156                  *nameBit = 0x00;
1157                  if (fodInfos->initdir)
1158                     MemFree(fodInfos->initdir);
1159                  fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1160                  strcpyW(fodInfos->initdir, tmpBuf2);
1161                  handledPath = TRUE;
1162                  TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1163               }
1164           }
1165           else if (fodInfos->initdir)
1166           {
1167                     MemFree(fodInfos->initdir);
1168                     fodInfos->initdir = NULL;
1169                     TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1170           }
1171       }
1172   }
1173
1174   if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1175                                  (*fodInfos->initdir==0x00)))
1176   {
1177       /* 3. All except w2k+: if filename contains a path use it */
1178       if (!win2000plus && fodInfos->filename &&
1179           *fodInfos->filename &&
1180           strpbrkW(fodInfos->filename, szwSlash)) {
1181          WCHAR tmpBuf[MAX_PATH];
1182          WCHAR *nameBit;
1183          DWORD result;
1184
1185          result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1186                                   tmpBuf, &nameBit);
1187          if (result) {
1188             int len;
1189
1190             /* nameBit is always shorter than the original filename */
1191             strcpyW(fodInfos->filename, nameBit);
1192             *nameBit = 0x00;
1193
1194             len = strlenW(tmpBuf);
1195             if(fodInfos->initdir)
1196                MemFree(fodInfos->initdir);
1197             fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1198             strcpyW(fodInfos->initdir, tmpBuf);
1199
1200             handledPath = TRUE;
1201             TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1202                  debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1203          }
1204          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1205       }
1206
1207       /* 4. win98+ and win2000+ if any files of specified filter types in
1208             current directory, use it                                      */
1209       if ( win98plus && handledPath == FALSE &&
1210            fodInfos->filter && *fodInfos->filter) {
1211
1212          BOOL   searchMore = TRUE;
1213          LPCWSTR lpstrPos = fodInfos->filter;
1214          WIN32_FIND_DATAW FindFileData;
1215          HANDLE hFind;
1216
1217          while (searchMore)
1218          {
1219            /* filter is a list...  title\0ext\0......\0\0 */
1220
1221            /* Skip the title */
1222            if(! *lpstrPos) break;       /* end */
1223            lpstrPos += strlenW(lpstrPos) + 1;
1224
1225            /* See if any files exist in the current dir with this extension */
1226            if(! *lpstrPos) break;       /* end */
1227
1228            hFind = FindFirstFileW(lpstrPos, &FindFileData);
1229
1230            if (hFind == INVALID_HANDLE_VALUE) {
1231                /* None found - continue search */
1232                lpstrPos += strlenW(lpstrPos) + 1;
1233
1234            } else {
1235                searchMore = FALSE;
1236
1237                if(fodInfos->initdir)
1238                   MemFree(fodInfos->initdir);
1239                fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1240                GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1241
1242                handledPath = TRUE;
1243                TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1244                  debugstr_w(lpstrPos));
1245                break;
1246            }
1247          }
1248       }
1249
1250       /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1251
1252       /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1253       if (handledPath == FALSE && (win2000plus || win98plus)) {
1254           fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1255
1256           if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1257           {
1258             if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1259             {
1260                 /* last fallback */
1261                 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1262                 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1263             } else {
1264                 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1265             }
1266           } else {
1267             TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1268           }
1269           handledPath = TRUE;
1270       } else if (handledPath==FALSE) {
1271           fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1272           GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1273           handledPath = TRUE;
1274           TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1275       }
1276   }
1277   SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1278   TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1279
1280   /* Must the open as read only check box be checked ?*/
1281   if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1282   {
1283     SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1284   }
1285
1286   /* Must the open as read only check box be hidden? */
1287   if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1288   {
1289     ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1290     EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1291   }
1292
1293   /* Must the help button be hidden? */
1294   if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1295   {
1296     ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1297     EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1298   }
1299
1300   /* Resize the height, if open as read only checkbox ad help button
1301      are hidden and we are not using a custom template nor a customDialog
1302      */
1303   if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1304        (!(fodInfos->ofnInfos->Flags &
1305          (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) && 
1306        (!fodInfos->DlgInfos.hwndCustomDlg ))
1307   {
1308     RECT rectDlg, rectHelp, rectCancel;
1309     GetWindowRect(hwnd, &rectDlg);
1310     GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1311     GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1312     /* subtract the height of the help button plus the space between
1313        the help button and the cancel button to the height of the dialog */
1314     SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1315                  (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1316                  SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1317   }
1318   /* change Open to Save FIXME: use resources */
1319   if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1320   {
1321       SetDlgItemTextA(hwnd,IDOK,"&Save");
1322       SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1323   }
1324   return 0;
1325 }
1326
1327 /***********************************************************************
1328  *      FILEDLG95_FillControls
1329  *
1330  * WM_INITDIALOG message handler (after hook notification)
1331  */
1332 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1333 {
1334   LPITEMIDLIST pidlItemId = NULL;
1335
1336   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1337
1338   TRACE("dir=%s file=%s\n",
1339   debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1340
1341   /* Get the initial directory pidl */
1342
1343   if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1344   {
1345     WCHAR path[MAX_PATH];
1346
1347     GetCurrentDirectoryW(MAX_PATH,path);
1348     pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1349   }
1350
1351   /* Initialise shell objects */
1352   FILEDLG95_SHELL_Init(hwnd);
1353
1354   /* Initialize the Look In combo box */
1355   FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1356
1357   /* Initialize the filter combo box */
1358   FILEDLG95_FILETYPE_Init(hwnd);
1359
1360   /* Browse to the initial directory */
1361   IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1362
1363   /* Free pidlItem memory */
1364   COMDLG32_SHFree(pidlItemId);
1365
1366   return TRUE;
1367 }
1368 /***********************************************************************
1369  *      FILEDLG95_Clean
1370  *
1371  * Regroups all the cleaning functions of the filedlg
1372  */
1373 void FILEDLG95_Clean(HWND hwnd)
1374 {
1375       FILEDLG95_FILETYPE_Clean(hwnd);
1376       FILEDLG95_LOOKIN_Clean(hwnd);
1377       FILEDLG95_SHELL_Clean(hwnd);
1378 }
1379 /***********************************************************************
1380  *      FILEDLG95_OnWMCommand
1381  *
1382  * WM_COMMAND message handler
1383  */
1384 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1385 {
1386   WORD wNotifyCode = HIWORD(wParam); /* notification code */
1387   WORD wID = LOWORD(wParam);         /* item, control, or accelerator identifier */
1388   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1389
1390   switch(wID)
1391   {
1392     /* OK button */
1393   case IDOK:
1394     FILEDLG95_OnOpen(hwnd);
1395     break;
1396     /* Cancel button */
1397   case IDCANCEL:
1398     FILEDLG95_Clean(hwnd);
1399     EndDialog(hwnd, FALSE);
1400     break;
1401     /* Filetype combo box */
1402   case IDC_FILETYPE:
1403     FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1404     break;
1405     /* LookIn combo box */
1406   case IDC_LOOKIN:
1407     FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1408     break;
1409
1410   /* --- toolbar --- */
1411     /* Up folder button */
1412   case FCIDM_TB_UPFOLDER:
1413     FILEDLG95_SHELL_UpFolder(hwnd);
1414     break;
1415     /* New folder button */
1416   case FCIDM_TB_NEWFOLDER:
1417     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1418     break;
1419     /* List option button */
1420   case FCIDM_TB_SMALLICON:
1421     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1422     break;
1423     /* Details option button */
1424   case FCIDM_TB_REPORTVIEW:
1425     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1426     break;
1427     /* Details option button */
1428   case FCIDM_TB_DESKTOP:
1429     FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1430     break;
1431
1432   case IDC_FILENAME:
1433     break;
1434
1435   }
1436   /* Do not use the listview selection anymore */
1437   fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1438   return 0;
1439 }
1440
1441 /***********************************************************************
1442  *      FILEDLG95_OnWMGetIShellBrowser
1443  *
1444  * WM_GETISHELLBROWSER message handler
1445  */
1446 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1447 {
1448
1449   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1450
1451   TRACE("\n");
1452
1453   SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1454
1455   return TRUE;
1456 }
1457
1458
1459 /***********************************************************************
1460  *      FILEDLG95_SendFileOK
1461  *
1462  * Sends the CDN_FILEOK notification if required
1463  *
1464  * RETURNS
1465  *  TRUE if the dialog should close
1466  *  FALSE if the dialog should not be closed
1467  */
1468 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1469 {
1470     /* ask the hook if we can close */
1471     if(IsHooked(fodInfos))
1472     {
1473         TRACE("---\n");
1474         /* First send CDN_FILEOK as MSDN doc says */
1475         SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1476         if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1477         {
1478             TRACE("canceled\n");
1479             return FALSE;
1480         }
1481
1482         /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1483         SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1484                      fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1485         if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1486         {
1487             TRACE("canceled\n");
1488             return FALSE;
1489         }
1490     }
1491     return TRUE;
1492 }
1493
1494 /***********************************************************************
1495  *      FILEDLG95_OnOpenMultipleFiles
1496  *
1497  * Handles the opening of multiple files.
1498  *
1499  * FIXME
1500  *  check destination buffer size
1501  */
1502 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1503 {
1504   WCHAR   lpstrPathSpec[MAX_PATH] = {0};
1505   UINT   nCount, nSizePath;
1506   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1507
1508   TRACE("\n");
1509
1510   if(fodInfos->unicode)
1511   {
1512      LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1513      ofn->lpstrFile[0] = '\0';
1514   }
1515   else
1516   {
1517      LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1518      ofn->lpstrFile[0] = '\0';
1519   }
1520
1521   SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1522
1523   if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1524       ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1525        ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1526   {
1527     LPWSTR lpstrTemp = lpstrFileList;
1528
1529     for ( nCount = 0; nCount < nFileCount; nCount++ )
1530     {
1531       LPITEMIDLIST pidl;
1532
1533       pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1534       if (!pidl)
1535       {
1536         WCHAR lpstrNotFound[100];
1537         WCHAR lpstrMsg[100];
1538         WCHAR tmp[400];
1539         static const WCHAR nl[] = {'\n',0};
1540
1541         LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1542         LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1543
1544         strcpyW(tmp, lpstrTemp);
1545         strcatW(tmp, nl);
1546         strcatW(tmp, lpstrNotFound);
1547         strcatW(tmp, nl);
1548         strcatW(tmp, lpstrMsg);
1549
1550         MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1551         return FALSE;
1552       }
1553
1554       /* move to the next file in the list of files */
1555       lpstrTemp += strlenW(lpstrTemp) + 1;
1556       COMDLG32_SHFree(pidl);
1557     }
1558   }
1559
1560   nSizePath = strlenW(lpstrPathSpec) + 1;
1561   if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1562   {
1563     /* For "oldstyle" dialog the components have to
1564        be separated by blanks (not '\0'!) and short
1565        filenames have to be used! */
1566     FIXME("Components have to be separated by blanks\n");
1567   }
1568   if(fodInfos->unicode)
1569   {
1570     LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1571     strcpyW( ofn->lpstrFile, lpstrPathSpec);
1572     memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1573   }
1574   else
1575   {
1576     LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1577
1578     if (ofn->lpstrFile != NULL)
1579     {
1580       WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1581                           ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1582       if (ofn->nMaxFile > nSizePath)
1583       {
1584         WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1585                             ofn->lpstrFile + nSizePath,
1586                             ofn->nMaxFile - nSizePath, NULL, NULL);
1587       }
1588     }
1589   }
1590
1591   fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1592   fodInfos->ofnInfos->nFileExtension = 0;
1593
1594   if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1595     return FALSE;
1596
1597   /* clean and exit */
1598   FILEDLG95_Clean(hwnd);
1599   return EndDialog(hwnd,TRUE);
1600 }
1601
1602 /***********************************************************************
1603  *      FILEDLG95_OnOpen
1604  *
1605  * Ok button WM_COMMAND message handler
1606  *
1607  * If the function succeeds, the return value is nonzero.
1608  */
1609 #define ONOPEN_BROWSE 1
1610 #define ONOPEN_OPEN   2
1611 #define ONOPEN_SEARCH 3
1612 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1613 {
1614   char strMsgTitle[MAX_PATH];
1615   char strMsgText [MAX_PATH];
1616   if (idCaption)
1617     LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1618   else
1619     strMsgTitle[0] = '\0';
1620   LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1621   MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1622 }
1623
1624 BOOL FILEDLG95_OnOpen(HWND hwnd)
1625 {
1626   LPWSTR lpstrFileList;
1627   UINT nFileCount = 0;
1628   UINT sizeUsed = 0;
1629   BOOL ret = TRUE;
1630   WCHAR lpstrPathAndFile[MAX_PATH];
1631   WCHAR lpstrTemp[MAX_PATH];
1632   LPSHELLFOLDER lpsf = NULL;
1633   int nOpenAction;
1634   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1635
1636   TRACE("hwnd=%p\n", hwnd);
1637
1638   /* get the files from the edit control */
1639   nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1640
1641   /* try if the user selected a folder in the shellview */
1642   if(nFileCount == 0)
1643   {
1644       BrowseSelectedFolder(hwnd);
1645       return FALSE;
1646   }
1647
1648   if(nFileCount > 1)
1649   {
1650       ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1651       goto ret;
1652   }
1653
1654   TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1655
1656 /*
1657   Step 1:  Build a complete path name from the current folder and
1658   the filename or path in the edit box.
1659   Special cases:
1660   - the path in the edit box is a root path
1661     (with or without drive letter)
1662   - the edit box contains ".." (or a path with ".." in it)
1663 */
1664
1665   /* Get the current directory name */
1666   if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1667   {
1668     /* we are in a special folder, default to desktop */
1669     if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1670     {
1671       /* last fallback */
1672       GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1673     }
1674   }
1675   PathAddBackslashW(lpstrPathAndFile);
1676
1677   TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1678
1679   /* if the user specifyed a fully qualified path use it */
1680   if(PathIsRelativeW(lpstrFileList))
1681   {
1682     strcatW(lpstrPathAndFile, lpstrFileList);
1683   }
1684   else
1685   {
1686     /* does the path have a drive letter? */
1687     if (PathGetDriveNumberW(lpstrFileList) == -1)
1688       strcpyW(lpstrPathAndFile+2, lpstrFileList);
1689     else
1690       strcpyW(lpstrPathAndFile, lpstrFileList);
1691   }
1692
1693   /* resolve "." and ".." */
1694   PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1695   strcpyW(lpstrPathAndFile, lpstrTemp);
1696   TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1697
1698   MemFree(lpstrFileList);
1699
1700 /*
1701   Step 2: here we have a cleaned up path
1702
1703   We have to parse the path step by step to see if we have to browse
1704   to a folder if the path points to a directory or the last
1705   valid element is a directory.
1706
1707   valid variables:
1708     lpstrPathAndFile: cleaned up path
1709  */
1710
1711   nOpenAction = ONOPEN_BROWSE;
1712
1713   /* don't apply any checks with OFN_NOVALIDATE */
1714   {
1715     LPWSTR lpszTemp, lpszTemp1;
1716     LPITEMIDLIST pidl = NULL;
1717     static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1718
1719     /* check for invalid chars */
1720     if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1721     {
1722       FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1723       ret = FALSE;
1724       goto ret;
1725     }
1726
1727     if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1728
1729     lpszTemp1 = lpszTemp = lpstrPathAndFile;
1730     while (lpszTemp1)
1731     {
1732       LPSHELLFOLDER lpsfChild;
1733       WCHAR lpwstrTemp[MAX_PATH];
1734       DWORD dwEaten, dwAttributes;
1735       LPWSTR p;
1736
1737       strcpyW(lpwstrTemp, lpszTemp);
1738       p = PathFindNextComponentW(lpwstrTemp);
1739
1740       if (!p) break; /* end of path */
1741
1742       *p = 0;
1743       lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1744
1745       if(*lpszTemp==0)
1746       {
1747         static const WCHAR wszWild[] = { '*', '?', 0 };
1748         /* if the last element is a wildcard do a search */
1749         if(strpbrkW(lpszTemp1, wszWild) != NULL)
1750         {
1751           nOpenAction = ONOPEN_SEARCH;
1752           break;
1753         }
1754       }
1755       lpszTemp1 = lpszTemp;
1756
1757       TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1758
1759       if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1760
1761       dwAttributes = SFGAO_FOLDER;
1762       if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1763       {
1764         /* the path component is valid, we have a pidl of the next path component */
1765         TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1766         if(dwAttributes & SFGAO_FOLDER)
1767         {
1768           if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1769           {
1770             ERR("bind to failed\n"); /* should not fail */
1771             break;
1772           }
1773           IShellFolder_Release(lpsf);
1774           lpsf = lpsfChild;
1775           lpsfChild = NULL;
1776         }
1777         else
1778         {
1779           TRACE("value\n");
1780
1781           /* end dialog, return value */
1782           nOpenAction = ONOPEN_OPEN;
1783           break;
1784         }
1785         COMDLG32_SHFree(pidl);
1786         pidl = NULL;
1787       }
1788       else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1789       {
1790         if(*lpszTemp)   /* points to trailing null for last path element */
1791         {
1792           if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1793           {
1794             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1795             break;
1796           }
1797         }
1798         else
1799         {
1800           if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1801              !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1802           {
1803             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1804             break;
1805           }
1806         }
1807         /* change to the current folder */
1808         nOpenAction = ONOPEN_OPEN;
1809         break;
1810       }
1811       else
1812       {
1813         nOpenAction = ONOPEN_OPEN;
1814         break;
1815       }
1816     }
1817     if(pidl) COMDLG32_SHFree(pidl);
1818   }
1819
1820 /*
1821   Step 3: here we have a cleaned up and validated path
1822
1823   valid variables:
1824    lpsf:             ShellFolder bound to the rightmost valid path component
1825    lpstrPathAndFile: cleaned up path
1826    nOpenAction:      action to do
1827 */
1828   TRACE("end validate sf=%p\n", lpsf);
1829
1830   switch(nOpenAction)
1831   {
1832     case ONOPEN_SEARCH:   /* set the current filter to the file mask and refresh */
1833       TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1834       {
1835         int iPos;
1836         LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1837         DWORD len;
1838
1839         /* replace the current filter */
1840         if(fodInfos->ShellInfos.lpstrCurrentFilter)
1841           MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1842         len = strlenW(lpszTemp)+1;
1843         fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1844         strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1845
1846         /* set the filter cb to the extension when possible */
1847         if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1848         CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1849       }
1850       /* fall through */
1851     case ONOPEN_BROWSE:   /* browse to the highest folder we could bind to */
1852       TRACE("ONOPEN_BROWSE\n");
1853       {
1854         IPersistFolder2 * ppf2;
1855         if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1856         {
1857           LPITEMIDLIST pidlCurrent;
1858           IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1859           IPersistFolder2_Release(ppf2);
1860           if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1861           {
1862             IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1863           }
1864           else if( nOpenAction == ONOPEN_SEARCH )
1865           {
1866             IShellView_Refresh(fodInfos->Shell.FOIShellView);
1867           }
1868           COMDLG32_SHFree(pidlCurrent);
1869         }
1870       }
1871       ret = FALSE;
1872       break;
1873     case ONOPEN_OPEN:   /* fill in the return struct and close the dialog */
1874       TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1875       {
1876         /* update READONLY check box flag */
1877         if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1878           fodInfos->ofnInfos->Flags |= OFN_READONLY;
1879         else
1880           fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1881
1882         /* add default extension */
1883         if (fodInfos->defext)
1884         {
1885           WCHAR *ext = PathFindExtensionW(lpstrPathAndFile);
1886           
1887           if (! *ext)
1888           {
1889             /* only add "." in case a default extension does exist */
1890             if (*fodInfos->defext != '\0')
1891             {
1892                 static const WCHAR szwDot[] = {'.',0};
1893                 int PathLength = strlenW(lpstrPathAndFile);
1894
1895                 strcatW(lpstrPathAndFile, szwDot);
1896                 strcatW(lpstrPathAndFile, fodInfos->defext);
1897
1898                 /* In Open dialog: if file does not exist try without extension */
1899                 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1900                     && !PathFileExistsW(lpstrPathAndFile))
1901                   lpstrPathAndFile[PathLength] = '\0';
1902             }
1903           }
1904
1905           /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1906           if (*ext)
1907             ext++;
1908           if (!lstrcmpiW(fodInfos->defext, ext))
1909             fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
1910           else
1911             fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
1912         }
1913
1914         /* In Save dialog: check if the file already exists */
1915         if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
1916             && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
1917             && PathFileExistsW(lpstrPathAndFile))
1918         {
1919           WCHAR lpstrOverwrite[100];
1920           int answer;
1921
1922           LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
1923           answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
1924                                MB_YESNO | MB_ICONEXCLAMATION);
1925           if (answer == IDNO)
1926           {
1927             ret = FALSE;
1928             goto ret;
1929           }
1930         }
1931
1932         /* Check that the size of the file does not exceed buffer size.
1933              (Allow for extra \0 if OFN_MULTISELECT is set.) */
1934         if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1935             ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1936         {
1937           LPWSTR lpszTemp;
1938
1939           /* fill destination buffer */
1940           if (fodInfos->ofnInfos->lpstrFile)
1941           {
1942              if(fodInfos->unicode)
1943              {
1944                LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1945
1946                strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
1947                if (ofn->Flags & OFN_ALLOWMULTISELECT)
1948                  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
1949              }
1950              else
1951              {
1952                LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1953
1954                WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
1955                                    ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1956                if (ofn->Flags & OFN_ALLOWMULTISELECT)
1957                  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
1958              }
1959           }
1960
1961           /* set filename offset */
1962           lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1963           fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
1964
1965           /* set extension offset */
1966           lpszTemp = PathFindExtensionW(lpstrPathAndFile);
1967           fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
1968
1969           /* set the lpstrFileTitle */
1970           if(fodInfos->ofnInfos->lpstrFileTitle)
1971           {
1972             LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
1973             if(fodInfos->unicode)
1974             {
1975               LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1976               strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
1977             }
1978             else
1979             {
1980               LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1981               WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
1982                     ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
1983             }
1984           }
1985
1986           if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1987               goto ret;
1988
1989           TRACE("close\n");
1990           FILEDLG95_Clean(hwnd);
1991           ret = EndDialog(hwnd, TRUE);
1992         }
1993         else
1994         {
1995           WORD size;
1996
1997           size = strlenW(lpstrPathAndFile) + 1;
1998           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
1999              size += 1;
2000           /* return needed size in first two bytes of lpstrFile */
2001           *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2002           FILEDLG95_Clean(hwnd);
2003           ret = EndDialog(hwnd, FALSE);
2004           COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2005         }
2006         goto ret;
2007       }
2008       break;
2009   }
2010
2011 ret:
2012   if(lpsf) IShellFolder_Release(lpsf);
2013   return ret;
2014 }
2015
2016 /***********************************************************************
2017  *      FILEDLG95_SHELL_Init
2018  *
2019  * Initialisation of the shell objects
2020  */
2021 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2022 {
2023   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2024
2025   TRACE("\n");
2026
2027   /*
2028    * Initialisation of the FileOpenDialogInfos structure
2029    */
2030
2031   /* Shell */
2032
2033   /*ShellInfos */
2034   fodInfos->ShellInfos.hwndOwner = hwnd;
2035
2036   /* Disable multi-select if flag not set */
2037   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2038   {
2039      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2040   }
2041   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2042   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2043
2044   /* Construct the IShellBrowser interface */
2045   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2046
2047   return NOERROR;
2048 }
2049
2050 /***********************************************************************
2051  *      FILEDLG95_SHELL_ExecuteCommand
2052  *
2053  * Change the folder option and refresh the view
2054  * If the function succeeds, the return value is nonzero.
2055  */
2056 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2057 {
2058   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2059
2060   IContextMenu * pcm;
2061   TRACE("(%p,%p)\n", hwnd, lpVerb);
2062
2063   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2064                                         SVGIO_BACKGROUND,
2065                                         &IID_IContextMenu,
2066                                         (LPVOID*)&pcm)))
2067   {
2068     CMINVOKECOMMANDINFO ci;
2069     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2070     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2071     ci.lpVerb = lpVerb;
2072     ci.hwnd = hwnd;
2073
2074     IContextMenu_InvokeCommand(pcm, &ci);
2075     IContextMenu_Release(pcm);
2076   }
2077
2078   return FALSE;
2079 }
2080
2081 /***********************************************************************
2082  *      FILEDLG95_SHELL_UpFolder
2083  *
2084  * Browse to the specified object
2085  * If the function succeeds, the return value is nonzero.
2086  */
2087 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2088 {
2089   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2090
2091   TRACE("\n");
2092
2093   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2094                                           NULL,
2095                                           SBSP_PARENT)))
2096   {
2097     return TRUE;
2098   }
2099   return FALSE;
2100 }
2101
2102 /***********************************************************************
2103  *      FILEDLG95_SHELL_BrowseToDesktop
2104  *
2105  * Browse to the Desktop
2106  * If the function succeeds, the return value is nonzero.
2107  */
2108 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2109 {
2110   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2111   LPITEMIDLIST pidl;
2112   HRESULT hres;
2113
2114   TRACE("\n");
2115
2116   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2117   hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2118   COMDLG32_SHFree(pidl);
2119   return SUCCEEDED(hres);
2120 }
2121 /***********************************************************************
2122  *      FILEDLG95_SHELL_Clean
2123  *
2124  * Cleans the memory used by shell objects
2125  */
2126 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2127 {
2128     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2129
2130     TRACE("\n");
2131
2132     COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2133
2134     /* clean Shell interfaces */
2135     IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2136     IShellView_Release(fodInfos->Shell.FOIShellView);
2137     IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2138     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2139     if (fodInfos->Shell.FOIDataObject)
2140       IDataObject_Release(fodInfos->Shell.FOIDataObject);
2141 }
2142
2143 /***********************************************************************
2144  *      FILEDLG95_FILETYPE_Init
2145  *
2146  * Initialisation of the file type combo box
2147  */
2148 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2149 {
2150   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2151
2152   TRACE("\n");
2153
2154   if(fodInfos->filter)
2155   {
2156     int nFilters = 0;   /* number of filters */
2157     LPWSTR lpstrFilter;
2158     LPCWSTR lpstrPos = fodInfos->filter;
2159
2160     for(;;)
2161     {
2162       /* filter is a list...  title\0ext\0......\0\0
2163        * Set the combo item text to the title and the item data
2164        *  to the ext
2165        */
2166       LPCWSTR lpstrDisplay;
2167       LPWSTR lpstrExt;
2168
2169       /* Get the title */
2170       if(! *lpstrPos) break;    /* end */
2171       lpstrDisplay = lpstrPos;
2172       lpstrPos += strlenW(lpstrPos) + 1;
2173
2174       /* Copy the extensions */
2175       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
2176       if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2177       strcpyW(lpstrExt,lpstrPos);
2178       lpstrPos += strlenW(lpstrPos) + 1;
2179
2180       /* Add the item at the end of the combo */
2181       CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2182       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2183       nFilters++;
2184     }
2185     /*
2186      * Set the current filter to the one specified
2187      * in the initialisation structure
2188      * FIXME: lpstrCustomFilter not handled at all
2189      */
2190
2191     /* set default filter index */
2192     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2193       fodInfos->ofnInfos->nFilterIndex = 1;
2194
2195     /* First, check to make sure our index isn't out of bounds. */
2196     if ( fodInfos->ofnInfos->nFilterIndex > nFilters )
2197       fodInfos->ofnInfos->nFilterIndex = nFilters;
2198
2199     /* Set the current index selection. */
2200     CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->ofnInfos->nFilterIndex-1);
2201
2202     /* Get the corresponding text string from the combo box. */
2203     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2204                                              fodInfos->ofnInfos->nFilterIndex-1);
2205
2206     if ((INT)lpstrFilter == CB_ERR)  /* control is empty */
2207       lpstrFilter = NULL;
2208
2209     if(lpstrFilter)
2210     {
2211       DWORD len;
2212       CharLowerW(lpstrFilter); /* lowercase */
2213       len = strlenW(lpstrFilter)+1;
2214       fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2215       strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2216     }
2217   }
2218   return NOERROR;
2219 }
2220
2221 /***********************************************************************
2222  *      FILEDLG95_FILETYPE_OnCommand
2223  *
2224  * WM_COMMAND of the file type combo box
2225  * If the function succeeds, the return value is nonzero.
2226  */
2227 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2228 {
2229   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2230
2231   switch(wNotifyCode)
2232   {
2233     case CBN_SELENDOK:
2234     {
2235       LPWSTR lpstrFilter;
2236
2237       /* Get the current item of the filetype combo box */
2238       int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2239
2240       /* set the current filter index - indexed from 1 */
2241       fodInfos->ofnInfos->nFilterIndex = iItem + 1;
2242
2243       /* Set the current filter with the current selection */
2244       if(fodInfos->ShellInfos.lpstrCurrentFilter)
2245          MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2246
2247       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2248                                              iItem);
2249       if((int)lpstrFilter != CB_ERR)
2250       {
2251           DWORD len;
2252           CharLowerW(lpstrFilter); /* lowercase */
2253           len = strlenW(lpstrFilter)+1;
2254           fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2255           strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2256           SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2257       }
2258
2259       /* Refresh the actual view to display the included items*/
2260       IShellView_Refresh(fodInfos->Shell.FOIShellView);
2261     }
2262   }
2263   return FALSE;
2264 }
2265 /***********************************************************************
2266  *      FILEDLG95_FILETYPE_SearchExt
2267  *
2268  * searches for a extension in the filetype box
2269  */
2270 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2271 {
2272   int i, iCount = CBGetCount(hwnd);
2273
2274   TRACE("%s\n", debugstr_w(lpstrExt));
2275
2276   if(iCount != CB_ERR)
2277   {
2278     for(i=0;i<iCount;i++)
2279     {
2280       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2281           return i;
2282     }
2283   }
2284   return -1;
2285 }
2286
2287 /***********************************************************************
2288  *      FILEDLG95_FILETYPE_Clean
2289  *
2290  * Clean the memory used by the filetype combo box
2291  */
2292 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2293 {
2294   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2295   int iPos;
2296   int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2297
2298   TRACE("\n");
2299
2300   /* Delete each string of the combo and their associated data */
2301   if(iCount != CB_ERR)
2302   {
2303     for(iPos = iCount-1;iPos>=0;iPos--)
2304     {
2305       MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2306       CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2307     }
2308   }
2309   /* Current filter */
2310   if(fodInfos->ShellInfos.lpstrCurrentFilter)
2311      MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2312
2313 }
2314
2315 /***********************************************************************
2316  *      FILEDLG95_LOOKIN_Init
2317  *
2318  * Initialisation of the look in combo box
2319  */
2320 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2321 {
2322   IShellFolder  *psfRoot, *psfDrives;
2323   IEnumIDList   *lpeRoot, *lpeDrives;
2324   LPITEMIDLIST  pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2325
2326   LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2327
2328   TRACE("\n");
2329
2330   liInfos->iMaxIndentation = 0;
2331
2332   SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2333
2334   /* set item height for both text field and listbox */
2335   CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2336   CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2337    
2338   /* Turn on the extended UI for the combo box like Windows does */
2339   CBSetExtendedUI(hwndCombo, TRUE);
2340
2341   /* Initialise data of Desktop folder */
2342   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2343   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2344   COMDLG32_SHFree(pidlTmp);
2345
2346   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2347
2348   SHGetDesktopFolder(&psfRoot);
2349
2350   if (psfRoot)
2351   {
2352     /* enumerate the contents of the desktop */
2353     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2354     {
2355       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2356       {
2357         FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2358
2359         /* special handling for CSIDL_DRIVES */
2360         if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2361         {
2362           if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2363           {
2364             /* enumerate the drives */
2365             if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2366             {
2367               while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2368               {
2369                 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2370                 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2371                 COMDLG32_SHFree(pidlAbsTmp);
2372                 COMDLG32_SHFree(pidlTmp1);
2373               }
2374               IEnumIDList_Release(lpeDrives);
2375             }
2376             IShellFolder_Release(psfDrives);
2377           }
2378         }
2379         COMDLG32_SHFree(pidlTmp);
2380       }
2381       IEnumIDList_Release(lpeRoot);
2382     }
2383     IShellFolder_Release(psfRoot);
2384   }
2385
2386   COMDLG32_SHFree(pidlDrives);
2387   return NOERROR;
2388 }
2389
2390 /***********************************************************************
2391  *      FILEDLG95_LOOKIN_DrawItem
2392  *
2393  * WM_DRAWITEM message handler
2394  */
2395 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2396 {
2397   COLORREF crWin = GetSysColor(COLOR_WINDOW);
2398   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2399   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2400   RECT rectText;
2401   RECT rectIcon;
2402   SHFILEINFOA sfi;
2403   HIMAGELIST ilItemImage;
2404   int iIndentation;
2405   TEXTMETRICA tm;
2406   LPSFOLDER tmpFolder;
2407
2408
2409   LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2410
2411   TRACE("\n");
2412
2413   if(pDIStruct->itemID == -1)
2414     return 0;
2415
2416   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2417                             pDIStruct->itemID)))
2418     return 0;
2419
2420
2421   if(pDIStruct->itemID == liInfos->uSelectedItem)
2422   {
2423     ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2424                                                0,
2425                                                &sfi,
2426                                                sizeof (SHFILEINFOA),
2427                                                SHGFI_PIDL | SHGFI_SMALLICON |
2428                                                SHGFI_OPENICON | SHGFI_SYSICONINDEX    |
2429                                                SHGFI_DISPLAYNAME );
2430   }
2431   else
2432   {
2433     ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2434                                                   0,
2435                                                   &sfi,
2436                                                   sizeof (SHFILEINFOA),
2437                                                   SHGFI_PIDL | SHGFI_SMALLICON |
2438                                                   SHGFI_SYSICONINDEX |
2439                                                   SHGFI_DISPLAYNAME);
2440   }
2441
2442   /* Is this item selected ? */
2443   if(pDIStruct->itemState & ODS_SELECTED)
2444   {
2445     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2446     SetBkColor(pDIStruct->hDC,crHighLight);
2447     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2448   }
2449   else
2450   {
2451     SetTextColor(pDIStruct->hDC,crText);
2452     SetBkColor(pDIStruct->hDC,crWin);
2453     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2454   }
2455
2456   /* Do not indent item if drawing in the edit of the combo */
2457   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2458   {
2459     iIndentation = 0;
2460     ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2461                                                 0,
2462                                                 &sfi,
2463                                                 sizeof (SHFILEINFOA),
2464                                                 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2465                                                 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME  );
2466
2467   }
2468   else
2469   {
2470     iIndentation = tmpFolder->m_iIndent;
2471   }
2472   /* Draw text and icon */
2473
2474   /* Initialise the icon display area */
2475   rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2476   rectIcon.top = pDIStruct->rcItem.top;
2477   rectIcon.right = rectIcon.left + ICONWIDTH;
2478   rectIcon.bottom = pDIStruct->rcItem.bottom;
2479
2480   /* Initialise the text display area */
2481   GetTextMetricsA(pDIStruct->hDC, &tm);
2482   rectText.left = rectIcon.right;
2483   rectText.top =
2484           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2485   rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2486   rectText.bottom =
2487           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2488
2489   /* Draw the icon from the image list */
2490   ImageList_Draw(ilItemImage,
2491                  sfi.iIcon,
2492                  pDIStruct->hDC,
2493                  rectIcon.left,
2494                  rectIcon.top,
2495                  ILD_TRANSPARENT );
2496
2497   /* Draw the associated text */
2498   if(sfi.szDisplayName)
2499     TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2500
2501
2502   return NOERROR;
2503 }
2504
2505 /***********************************************************************
2506  *      FILEDLG95_LOOKIN_OnCommand
2507  *
2508  * LookIn combo box WM_COMMAND message handler
2509  * If the function succeeds, the return value is nonzero.
2510  */
2511 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2512 {
2513   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2514
2515   TRACE("%p\n", fodInfos);
2516
2517   switch(wNotifyCode)
2518   {
2519     case CBN_SELENDOK:
2520     {
2521       LPSFOLDER tmpFolder;
2522       int iItem;
2523
2524       iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2525
2526       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2527                                                iItem)))
2528         return FALSE;
2529
2530
2531       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2532                                               tmpFolder->pidlItem,
2533                                               SBSP_ABSOLUTE)))
2534       {
2535         return TRUE;
2536       }
2537       break;
2538     }
2539
2540   }
2541   return FALSE;
2542 }
2543
2544 /***********************************************************************
2545  *      FILEDLG95_LOOKIN_AddItem
2546  *
2547  * Adds an absolute pidl item to the lookin combo box
2548  * returns the index of the inserted item
2549  */
2550 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2551 {
2552   LPITEMIDLIST pidlNext;
2553   SHFILEINFOA sfi;
2554   SFOLDER *tmpFolder;
2555   LookInInfos *liInfos;
2556
2557   TRACE("%08x\n", iInsertId);
2558
2559   if(!pidl)
2560     return -1;
2561
2562   if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2563     return -1;
2564
2565   tmpFolder = MemAlloc(sizeof(SFOLDER));
2566   tmpFolder->m_iIndent = 0;
2567
2568   /* Calculate the indentation of the item in the lookin*/
2569   pidlNext = pidl;
2570   while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2571   {
2572     tmpFolder->m_iIndent++;
2573   }
2574
2575   tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2576
2577   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2578     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2579
2580   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2581   SHGetFileInfoA((LPSTR)pidl,
2582                   0,
2583                   &sfi,
2584                   sizeof(sfi),
2585                   SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2586                   | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2587
2588   TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2589
2590   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2591   {
2592     int iItemID;
2593
2594     TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2595
2596     /* Add the item at the end of the list */
2597     if(iInsertId < 0)
2598     {
2599       iItemID = CBAddString(hwnd,sfi.szDisplayName);
2600     }
2601     /* Insert the item at the iInsertId position*/
2602     else
2603     {
2604       iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2605     }
2606
2607     CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2608     return iItemID;
2609   }
2610
2611   COMDLG32_SHFree( tmpFolder->pidlItem );
2612   MemFree( tmpFolder );
2613   return -1;
2614
2615 }
2616
2617 /***********************************************************************
2618  *      FILEDLG95_LOOKIN_InsertItemAfterParent
2619  *
2620  * Insert an item below its parent
2621  */
2622 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2623 {
2624
2625   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2626   int iParentPos;
2627
2628   TRACE("\n");
2629
2630   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2631
2632   if(iParentPos < 0)
2633   {
2634     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2635   }
2636
2637   /* Free pidlParent memory */
2638   COMDLG32_SHFree((LPVOID)pidlParent);
2639
2640   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2641 }
2642
2643 /***********************************************************************
2644  *      FILEDLG95_LOOKIN_SelectItem
2645  *
2646  * Adds an absolute pidl item to the lookin combo box
2647  * returns the index of the inserted item
2648  */
2649 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2650 {
2651   int iItemPos;
2652   LookInInfos *liInfos;
2653
2654   TRACE("\n");
2655
2656   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2657
2658   liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2659
2660   if(iItemPos < 0)
2661   {
2662     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2663     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2664   }
2665
2666   else
2667   {
2668     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2669     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2670     {
2671       int iRemovedItem;
2672
2673       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2674         break;
2675       if(iRemovedItem < iItemPos)
2676         iItemPos--;
2677     }
2678   }
2679
2680   CBSetCurSel(hwnd,iItemPos);
2681   liInfos->uSelectedItem = iItemPos;
2682
2683   return 0;
2684
2685 }
2686
2687 /***********************************************************************
2688  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
2689  *
2690  * Remove the item with an expansion level over iExpansionLevel
2691  */
2692 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2693 {
2694   int iItemPos;
2695
2696   LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2697
2698   TRACE("\n");
2699
2700   if(liInfos->iMaxIndentation <= 2)
2701     return -1;
2702
2703   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2704   {
2705     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2706     COMDLG32_SHFree(tmpFolder->pidlItem);
2707     MemFree(tmpFolder);
2708     CBDeleteString(hwnd,iItemPos);
2709     liInfos->iMaxIndentation--;
2710
2711     return iItemPos;
2712   }
2713
2714   return -1;
2715 }
2716
2717 /***********************************************************************
2718  *      FILEDLG95_LOOKIN_SearchItem
2719  *
2720  * Search for pidl in the lookin combo box
2721  * returns the index of the found item
2722  */
2723 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2724 {
2725   int i = 0;
2726   int iCount = CBGetCount(hwnd);
2727
2728   TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2729
2730   if (iCount != CB_ERR)
2731   {
2732     for(;i<iCount;i++)
2733     {
2734       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2735
2736       if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2737         return i;
2738       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2739         return i;
2740     }
2741   }
2742
2743   return -1;
2744 }
2745
2746 /***********************************************************************
2747  *      FILEDLG95_LOOKIN_Clean
2748  *
2749  * Clean the memory used by the lookin combo box
2750  */
2751 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2752 {
2753     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2754     int iPos;
2755     int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2756
2757     TRACE("\n");
2758
2759     /* Delete each string of the combo and their associated data */
2760     if (iCount != CB_ERR)
2761     {
2762       for(iPos = iCount-1;iPos>=0;iPos--)
2763       {
2764         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2765         COMDLG32_SHFree(tmpFolder->pidlItem);
2766         MemFree(tmpFolder);
2767         CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2768       }
2769     }
2770
2771     /* LookInInfos structure */
2772     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2773
2774 }
2775 /***********************************************************************
2776  * FILEDLG95_FILENAME_FillFromSelection
2777  *
2778  * fills the edit box from the cached DataObject
2779  */
2780 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2781 {
2782     FileOpenDlgInfos *fodInfos;
2783     LPITEMIDLIST      pidl;
2784     UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2785     char              lpstrTemp[MAX_PATH];
2786     LPSTR             lpstrAllFile = NULL, lpstrCurrFile = NULL;
2787
2788     TRACE("\n");
2789     fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2790
2791     /* Count how many files we have */
2792     nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2793
2794     /* calculate the string length, count files */
2795     if (nFileSelected >= 1)
2796     {
2797       nLength += 3;     /* first and last quotes, trailing \0 */
2798       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2799       {
2800         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2801
2802         if (pidl)
2803         {
2804           /* get the total length of the selected file names */
2805           lpstrTemp[0] = '\0';
2806           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2807
2808           if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2809           {
2810             nLength += strlen( lpstrTemp ) + 3;
2811             nFiles++;
2812           }
2813           COMDLG32_SHFree( pidl );
2814         }
2815       }
2816     }
2817
2818     /* allocate the buffer */
2819     if (nFiles <= 1) nLength = MAX_PATH;
2820     lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2821     lpstrAllFile[0] = '\0';
2822
2823     /* Generate the string for the edit control */
2824     if(nFiles >= 1)
2825     {
2826       lpstrCurrFile = lpstrAllFile;
2827       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2828       {
2829         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2830
2831         if (pidl)
2832         {
2833           /* get the file name */
2834           lpstrTemp[0] = '\0';
2835           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2836
2837           if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2838           {
2839             if ( nFiles > 1)
2840             {
2841               *lpstrCurrFile++ =  '\"';
2842               strcpy( lpstrCurrFile, lpstrTemp );
2843               lpstrCurrFile += strlen( lpstrTemp );
2844               strcpy( lpstrCurrFile, "\" " );
2845               lpstrCurrFile += 2;
2846             }
2847             else
2848             {
2849               strcpy( lpstrAllFile, lpstrTemp );
2850             }
2851           }
2852           COMDLG32_SHFree( (LPVOID) pidl );
2853         }
2854       }
2855       SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2856        
2857       /* Select the file name like Windows does */ 
2858       SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
2859     }
2860     HeapFree(GetProcessHeap(),0, lpstrAllFile );
2861 }
2862
2863
2864 /* copied from shell32 to avoid linking to it */
2865 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2866 {
2867         switch (src->uType)
2868         {
2869           case STRRET_WSTR:
2870             WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2871             COMDLG32_SHFree(src->u.pOleStr);
2872             break;
2873
2874           case STRRET_CSTR:
2875             lstrcpynA((LPSTR)dest, src->u.cStr, len);
2876             break;
2877
2878           case STRRET_OFFSET:
2879             lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
2880             break;
2881
2882           default:
2883             FIXME("unknown type!\n");
2884             if (len)
2885             {
2886               *(LPSTR)dest = '\0';
2887             }
2888             return(FALSE);
2889         }
2890         return S_OK;
2891 }
2892
2893 /***********************************************************************
2894  * FILEDLG95_FILENAME_GetFileNames
2895  *
2896  * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2897  */
2898 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
2899 {
2900         FileOpenDlgInfos *fodInfos  = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2901         UINT nStrCharCount = 0; /* index in src buffer */
2902         UINT nFileIndex = 0;    /* index in dest buffer */
2903         UINT nFileCount = 0;    /* number of files */
2904         UINT nStrLen = 0;       /* length of string in edit control */
2905         LPWSTR lpstrEdit;       /* buffer for string from edit control */
2906
2907         TRACE("\n");
2908
2909         /* get the filenames from the edit control */
2910         nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
2911         lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
2912         GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
2913
2914         TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
2915
2916         /* we might get single filename without any '"',
2917          * so we need nStrLen + terminating \0 + end-of-list \0 */
2918         *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
2919         *sizeUsed = 0;
2920
2921         /* build 0-delimited file list from filenames */
2922         while ( nStrCharCount <= nStrLen )
2923         {
2924           if ( lpstrEdit[nStrCharCount]=='"' )
2925           {
2926             nStrCharCount++;
2927             while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
2928             {
2929               (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
2930               (*sizeUsed)++;
2931               nStrCharCount++;
2932             }
2933             (*lpstrFileList)[nFileIndex++] = '\0';
2934             (*sizeUsed)++;
2935             nFileCount++;
2936           }
2937           nStrCharCount++;
2938         }
2939
2940         /* single, unquoted string */
2941         if ((nStrLen > 0) && (*sizeUsed == 0) )
2942         {
2943           strcpyW(*lpstrFileList, lpstrEdit);
2944           nFileIndex = strlenW(lpstrEdit) + 1;
2945           (*sizeUsed) = nFileIndex;
2946           nFileCount = 1;
2947         }
2948
2949         /* trailing \0 */
2950         (*lpstrFileList)[nFileIndex] = '\0';
2951         (*sizeUsed)++;
2952
2953         MemFree(lpstrEdit);
2954         return nFileCount;
2955 }
2956
2957 #define SETDefFormatEtc(fe,cf,med) \
2958 { \
2959     (fe).cfFormat = cf;\
2960     (fe).dwAspect = DVASPECT_CONTENT; \
2961     (fe).ptd =NULL;\
2962     (fe).tymed = med;\
2963     (fe).lindex = -1;\
2964 };
2965
2966 /*
2967  * DATAOBJECT Helper functions
2968  */
2969
2970 /***********************************************************************
2971  * COMCTL32_ReleaseStgMedium
2972  *
2973  * like ReleaseStgMedium from ole32
2974  */
2975 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
2976 {
2977       if(medium.pUnkForRelease)
2978       {
2979         IUnknown_Release(medium.pUnkForRelease);
2980       }
2981       else
2982       {
2983         GlobalUnlock(medium.u.hGlobal);
2984         GlobalFree(medium.u.hGlobal);
2985       }
2986 }
2987
2988 /***********************************************************************
2989  *          GetPidlFromDataObject
2990  *
2991  * Return pidl(s) by number from the cached DataObject
2992  *
2993  * nPidlIndex=0 gets the fully qualified root path
2994  */
2995 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
2996 {
2997
2998     STGMEDIUM medium;
2999     FORMATETC formatetc;
3000     LPITEMIDLIST pidl = NULL;
3001
3002     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3003
3004     /* Set the FORMATETC structure*/
3005     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3006
3007     /* Get the pidls from IDataObject */
3008     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3009     {
3010       LPIDA cida = GlobalLock(medium.u.hGlobal);
3011       if(nPidlIndex <= cida->cidl)
3012       {
3013         pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3014       }
3015       COMCTL32_ReleaseStgMedium(medium);
3016     }
3017     return pidl;
3018 }
3019
3020 /***********************************************************************
3021  *          GetNumSelected
3022  *
3023  * Return the number of selected items in the DataObject.
3024  *
3025 */
3026 UINT GetNumSelected( IDataObject *doSelected )
3027 {
3028     UINT retVal = 0;
3029     STGMEDIUM medium;
3030     FORMATETC formatetc;
3031
3032     TRACE("sv=%p\n", doSelected);
3033
3034     if (!doSelected) return 0;
3035
3036     /* Set the FORMATETC structure*/
3037     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3038
3039     /* Get the pidls from IDataObject */
3040     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3041     {
3042       LPIDA cida = GlobalLock(medium.u.hGlobal);
3043       retVal = cida->cidl;
3044       COMCTL32_ReleaseStgMedium(medium);
3045       return retVal;
3046     }
3047     return 0;
3048 }
3049
3050 /*
3051  * TOOLS
3052  */
3053
3054 /***********************************************************************
3055  *      GetName
3056  *
3057  * Get the pidl's display name (relative to folder) and
3058  * put it in lpstrFileName.
3059  *
3060  * Return NOERROR on success,
3061  * E_FAIL otherwise
3062  */
3063
3064 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3065 {
3066   STRRET str;
3067   HRESULT hRes;
3068
3069   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3070
3071   if(!lpsf)
3072   {
3073     HRESULT hRes;
3074     SHGetDesktopFolder(&lpsf);
3075     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3076     IShellFolder_Release(lpsf);
3077     return hRes;
3078   }
3079
3080   /* Get the display name of the pidl relative to the folder */
3081   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3082   {
3083       return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3084   }
3085   return E_FAIL;
3086 }
3087
3088 /***********************************************************************
3089  *      GetShellFolderFromPidl
3090  *
3091  * pidlRel is the item pidl relative
3092  * Return the IShellFolder of the absolute pidl
3093  */
3094 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3095 {
3096   IShellFolder *psf = NULL,*psfParent;
3097
3098   TRACE("%p\n", pidlAbs);
3099
3100   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3101   {
3102     psf = psfParent;
3103     if(pidlAbs && pidlAbs->mkid.cb)
3104     {
3105       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3106       {
3107         IShellFolder_Release(psfParent);
3108         return psf;
3109       }
3110     }
3111     /* return the desktop */
3112     return psfParent;
3113   }
3114   return NULL;
3115 }
3116
3117 /***********************************************************************
3118  *      GetParentPidl
3119  *
3120  * Return the LPITEMIDLIST to the parent of the pidl in the list
3121  */
3122 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3123 {
3124   LPITEMIDLIST pidlParent;
3125
3126   TRACE("%p\n", pidl);
3127
3128   pidlParent = COMDLG32_PIDL_ILClone(pidl);
3129   COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3130
3131   return pidlParent;
3132 }
3133
3134 /***********************************************************************
3135  *      GetPidlFromName
3136  *
3137  * returns the pidl of the file name relative to folder
3138  * NULL if an error occurred
3139  */
3140 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3141 {
3142   LPITEMIDLIST pidl = NULL;
3143   ULONG ulEaten;
3144
3145   TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3146
3147   if(!lpcstrFileName) return NULL;
3148   if(!*lpcstrFileName) return NULL;
3149
3150   if(!lpsf)
3151   {
3152     if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3153         IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3154         IShellFolder_Release(lpsf);
3155     }
3156   }
3157   else
3158   {
3159     IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3160   }
3161   return pidl;
3162 }
3163
3164 /*
3165 */
3166 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3167 {
3168         ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3169         HRESULT ret;
3170
3171         TRACE("%p, %p\n", psf, pidl);
3172
3173         ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3174
3175         TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3176         /* see documentation shell 4.1*/
3177         return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3178 }
3179
3180 /***********************************************************************
3181  *      BrowseSelectedFolder
3182  */
3183 static BOOL BrowseSelectedFolder(HWND hwnd)
3184 {
3185   BOOL bBrowseSelFolder = FALSE;
3186   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3187
3188   TRACE("\n");
3189
3190   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3191   {
3192       LPITEMIDLIST pidlSelection;
3193
3194       /* get the file selected */
3195       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3196       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3197       {
3198           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3199                          pidlSelection, SBSP_RELATIVE ) ) )
3200           {
3201                static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3202                                    ' ','n','o','t',' ','e','x','i','s','t',0};
3203                MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3204           }
3205
3206          bBrowseSelFolder = TRUE;
3207       }
3208       COMDLG32_SHFree( pidlSelection );
3209   }
3210
3211   return bBrowseSelFolder;
3212 }
3213
3214 /*
3215  * Memory allocation methods */
3216 static void *MemAlloc(UINT size)
3217 {
3218     return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3219 }
3220
3221 static void MemFree(void *mem)
3222 {
3223     if(mem)
3224     {
3225         HeapFree(GetProcessHeap(),0,mem);
3226     }
3227 }
3228
3229 /* ------------------ APIs ---------------------- */
3230
3231 /***********************************************************************
3232  *            GetOpenFileNameA  (COMDLG32.@)
3233  *
3234  * Creates a dialog box for the user to select a file to open.
3235  *
3236  * RETURNS
3237  *    TRUE on success: user enters a valid file
3238  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3239  *
3240  */
3241 BOOL WINAPI GetOpenFileNameA(
3242         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3243 {
3244     BOOL win16look = FALSE;
3245
3246     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3247         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3248
3249     if (win16look)
3250         return GetFileName31A(ofn, OPEN_DIALOG);
3251     else
3252         return GetFileDialog95A(ofn, OPEN_DIALOG);
3253 }
3254
3255 /***********************************************************************
3256  *            GetOpenFileNameW (COMDLG32.@)
3257  *
3258  * Creates a dialog box for the user to select a file to open.
3259  *
3260  * RETURNS
3261  *    TRUE on success: user enters a valid file
3262  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3263  *
3264  */
3265 BOOL WINAPI GetOpenFileNameW(
3266         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3267 {
3268     BOOL win16look = FALSE;
3269
3270     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3271         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3272
3273     if (win16look)
3274         return GetFileName31W(ofn, OPEN_DIALOG);
3275     else
3276         return GetFileDialog95W(ofn, OPEN_DIALOG);
3277 }
3278
3279
3280 /***********************************************************************
3281  *            GetSaveFileNameA  (COMDLG32.@)
3282  *
3283  * Creates a dialog box for the user to select a file to save.
3284  *
3285  * RETURNS
3286  *    TRUE on success: user enters a valid file
3287  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3288  *
3289  */
3290 BOOL WINAPI GetSaveFileNameA(
3291         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3292 {
3293     BOOL win16look = FALSE;
3294
3295     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3296         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3297
3298     if (win16look)
3299         return GetFileName31A(ofn, SAVE_DIALOG);
3300     else
3301         return GetFileDialog95A(ofn, SAVE_DIALOG);
3302 }
3303
3304 /***********************************************************************
3305  *            GetSaveFileNameW  (COMDLG32.@)
3306  *
3307  * Creates a dialog box for the user to select a file to save.
3308  *
3309  * RETURNS
3310  *    TRUE on success: user enters a valid file
3311  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3312  *
3313  */
3314 BOOL WINAPI GetSaveFileNameW(
3315         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3316 {
3317     BOOL win16look = FALSE;
3318
3319     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3320         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3321
3322     if (win16look)
3323         return GetFileName31W(ofn, SAVE_DIALOG);
3324     else
3325         return GetFileDialog95W(ofn, SAVE_DIALOG);
3326 }