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