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