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