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