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