Fix gcc 4.0 -Wpointer-sign warnings.
[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     INT_PTR 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     INT_PTR 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_OPEN   1
1715 #define ONOPEN_SEARCH 2
1716 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1717 {
1718   WCHAR strMsgTitle[MAX_PATH];
1719   WCHAR strMsgText [MAX_PATH];
1720   if (idCaption)
1721     LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1722   else
1723     strMsgTitle[0] = '\0';
1724   LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1725   MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1726 }
1727
1728 BOOL FILEDLG95_OnOpen(HWND hwnd)
1729 {
1730   LPWSTR lpstrFileList;
1731   UINT nFileCount = 0;
1732   UINT sizeUsed = 0;
1733   BOOL ret = TRUE;
1734   WCHAR lpstrPathAndFile[MAX_PATH];
1735   WCHAR lpstrTemp[MAX_PATH];
1736   LPSHELLFOLDER lpsf = NULL;
1737   int nOpenAction;
1738   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1739
1740   TRACE("hwnd=%p\n", hwnd);
1741
1742   if(BrowseSelectedFolder(hwnd))
1743       return FALSE;
1744
1745   /* get the files from the edit control */
1746   nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1747
1748   /* try if the user selected a folder in the shellview */
1749   if(nFileCount == 0)
1750       return FALSE;
1751
1752   if(nFileCount > 1)
1753   {
1754       ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1755       goto ret;
1756   }
1757
1758   TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1759
1760 /*
1761   Step 1:  Build a complete path name from the current folder and
1762   the filename or path in the edit box.
1763   Special cases:
1764   - the path in the edit box is a root path
1765     (with or without drive letter)
1766   - the edit box contains ".." (or a path with ".." in it)
1767 */
1768
1769   /* Get the current directory name */
1770   if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1771   {
1772     /* last fallback */
1773     GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1774   }
1775   PathAddBackslashW(lpstrPathAndFile);
1776
1777   TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1778
1779   /* if the user specifyed a fully qualified path use it */
1780   if(PathIsRelativeW(lpstrFileList))
1781   {
1782     strcatW(lpstrPathAndFile, lpstrFileList);
1783   }
1784   else
1785   {
1786     /* does the path have a drive letter? */
1787     if (PathGetDriveNumberW(lpstrFileList) == -1)
1788       strcpyW(lpstrPathAndFile+2, lpstrFileList);
1789     else
1790       strcpyW(lpstrPathAndFile, lpstrFileList);
1791   }
1792
1793   /* resolve "." and ".." */
1794   PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1795   strcpyW(lpstrPathAndFile, lpstrTemp);
1796   TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1797
1798   MemFree(lpstrFileList);
1799
1800 /*
1801   Step 2: here we have a cleaned up path
1802
1803   We have to parse the path step by step to see if we have to browse
1804   to a folder if the path points to a directory or the last
1805   valid element is a directory.
1806
1807   valid variables:
1808     lpstrPathAndFile: cleaned up path
1809  */
1810
1811   nOpenAction = ONOPEN_OPEN;
1812
1813   /* don't apply any checks with OFN_NOVALIDATE */
1814   {
1815     LPWSTR lpszTemp, lpszTemp1;
1816     LPITEMIDLIST pidl = NULL;
1817     static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1818
1819     /* check for invalid chars */
1820     if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1821     {
1822       FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1823       ret = FALSE;
1824       goto ret;
1825     }
1826
1827     if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1828
1829     lpszTemp1 = lpszTemp = lpstrPathAndFile;
1830     while (lpszTemp1)
1831     {
1832       LPSHELLFOLDER lpsfChild;
1833       WCHAR lpwstrTemp[MAX_PATH];
1834       DWORD dwEaten, dwAttributes;
1835       LPWSTR p;
1836
1837       strcpyW(lpwstrTemp, lpszTemp);
1838       p = PathFindNextComponentW(lpwstrTemp);
1839
1840       if (!p) break; /* end of path */
1841
1842       *p = 0;
1843       lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1844
1845       if(*lpszTemp==0)
1846       {
1847         static const WCHAR wszWild[] = { '*', '?', 0 };
1848         /* if the last element is a wildcard do a search */
1849         if(strpbrkW(lpszTemp1, wszWild) != NULL)
1850         {
1851           nOpenAction = ONOPEN_SEARCH;
1852           break;
1853         }
1854       }
1855       lpszTemp1 = lpszTemp;
1856
1857       TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1858
1859       /* append a backslash to drive letters */
1860       if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' && 
1861          ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1862           (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z'))) 
1863       {
1864         PathAddBackslashW(lpwstrTemp);
1865       }
1866
1867       dwAttributes = SFGAO_FOLDER;
1868       if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1869       {
1870         /* the path component is valid, we have a pidl of the next path component */
1871         TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1872         if(dwAttributes & SFGAO_FOLDER)
1873         {
1874           if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1875           {
1876             ERR("bind to failed\n"); /* should not fail */
1877             break;
1878           }
1879           IShellFolder_Release(lpsf);
1880           lpsf = lpsfChild;
1881           lpsfChild = NULL;
1882         }
1883         else
1884         {
1885           TRACE("value\n");
1886
1887           /* end dialog, return value */
1888           nOpenAction = ONOPEN_OPEN;
1889           break;
1890         }
1891         COMDLG32_SHFree(pidl);
1892         pidl = NULL;
1893       }
1894       else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1895       {
1896         if(*lpszTemp)   /* points to trailing null for last path element */
1897         {
1898           if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1899           {
1900             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1901             break;
1902           }
1903         }
1904         else
1905         {
1906           if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1907              !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1908           {
1909             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1910             break;
1911           }
1912         }
1913         /* change to the current folder */
1914         nOpenAction = ONOPEN_OPEN;
1915         break;
1916       }
1917       else
1918       {
1919         nOpenAction = ONOPEN_OPEN;
1920         break;
1921       }
1922     }
1923     if(pidl) COMDLG32_SHFree(pidl);
1924   }
1925
1926 /*
1927   Step 3: here we have a cleaned up and validated path
1928
1929   valid variables:
1930    lpsf:             ShellFolder bound to the rightmost valid path component
1931    lpstrPathAndFile: cleaned up path
1932    nOpenAction:      action to do
1933 */
1934   TRACE("end validate sf=%p\n", lpsf);
1935
1936   switch(nOpenAction)
1937   {
1938     case ONOPEN_SEARCH:   /* set the current filter to the file mask and refresh */
1939       TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1940       {
1941         int iPos;
1942         LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1943         DWORD len;
1944         IPersistFolder2 * ppf2;
1945
1946         /* replace the current filter */
1947         if(fodInfos->ShellInfos.lpstrCurrentFilter)
1948           MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1949         len = strlenW(lpszTemp)+1;
1950         fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1951         strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1952
1953         /* set the filter cb to the extension when possible */
1954         if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1955         CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1956
1957         if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1958         {
1959           LPITEMIDLIST pidlCurrent;
1960           IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1961           IPersistFolder2_Release(ppf2);
1962           if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1963           {
1964             IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1965           }
1966           else
1967           {
1968             IShellView_Refresh(fodInfos->Shell.FOIShellView);
1969           }
1970           SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
1971           COMDLG32_SHFree(pidlCurrent);
1972         }
1973       }
1974       ret = FALSE;
1975       break;
1976     case ONOPEN_OPEN:   /* fill in the return struct and close the dialog */
1977       TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1978       {
1979         WCHAR *ext = NULL;
1980
1981         /* update READONLY check box flag */
1982         if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1983           fodInfos->ofnInfos->Flags |= OFN_READONLY;
1984         else
1985           fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1986
1987         /* Attach the file extension with file name*/
1988
1989         if(!PathIsDirectoryW(lpstrPathAndFile))
1990         {
1991             if((ext = PathFindExtensionW(lpstrPathAndFile)) == NULL)
1992             {
1993                 /* if no extension is specified with file name, then */
1994                 /* attach the extension from file filter or default one */
1995             
1996                 WCHAR *filterExt = NULL;
1997                 LPWSTR lpstrFilter = NULL;
1998                 static const WCHAR szwDot[] = {'.',0};
1999                 int PathLength = strlenW(lpstrPathAndFile);
2000
2001                 /* Attach the dot*/
2002                 strcatW(lpstrPathAndFile, szwDot);
2003     
2004                 /*Get the file extension from file type filter*/
2005                 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2006                                                         fodInfos->ofnInfos->nFilterIndex-1);
2007
2008                 if (lpstrFilter != (LPWSTR)CB_ERR)  /* control is not empty */
2009                     filterExt = PathFindExtensionW(lpstrFilter);
2010
2011                 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2012                     strcatW(lpstrPathAndFile, filterExt + 1);
2013                 else if ( fodInfos->defext ) /* attach the default file extension*/
2014                     strcatW(lpstrPathAndFile, fodInfos->defext);
2015
2016                 /* In Open dialog: if file does not exist try without extension */
2017                 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2018                     lpstrPathAndFile[PathLength] = '\0';
2019             }
2020         
2021             if (fodInfos->defext) /* add default extension */
2022             {
2023                 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2024                 if (*ext)
2025                     ext++;
2026                 if (!lstrcmpiW(fodInfos->defext, ext))
2027                     fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2028                 else
2029                     fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2030             }
2031         }
2032
2033         /* In Save dialog: check if the file already exists */
2034         if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2035             && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2036             && PathFileExistsW(lpstrPathAndFile))
2037         {
2038           WCHAR lpstrOverwrite[100];
2039           int answer;
2040
2041           LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2042           answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2043                                MB_YESNO | MB_ICONEXCLAMATION);
2044           if (answer == IDNO)
2045           {
2046             ret = FALSE;
2047             goto ret;
2048           }
2049         }
2050
2051         /* Check that the size of the file does not exceed buffer size.
2052              (Allow for extra \0 if OFN_MULTISELECT is set.) */
2053         if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2054             ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2055         {
2056           LPWSTR lpszTemp;
2057
2058           /* fill destination buffer */
2059           if (fodInfos->ofnInfos->lpstrFile)
2060           {
2061              if(fodInfos->unicode)
2062              {
2063                LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2064
2065                lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2066                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2067                  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2068              }
2069              else
2070              {
2071                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2072
2073                WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2074                                    ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2075                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2076                  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2077              }
2078           }
2079
2080           /* set filename offset */
2081           lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2082           fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2083
2084           /* set extension offset */
2085           lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2086           fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2087
2088           /* set the lpstrFileTitle */
2089           if(fodInfos->ofnInfos->lpstrFileTitle)
2090           {
2091             LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2092             if(fodInfos->unicode)
2093             {
2094               LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2095               lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2096             }
2097             else
2098             {
2099               LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2100               WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2101                     ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2102             }
2103           }
2104
2105           /* copy currently selected filter to lpstrCustomFilter */
2106           if (fodInfos->ofnInfos->lpstrCustomFilter)
2107           {
2108             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2109             int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2110                                           NULL, 0, NULL, NULL);
2111             if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2112             {
2113               LPSTR s = ofn->lpstrCustomFilter;
2114               s += strlen(ofn->lpstrCustomFilter)+1;
2115               WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2116                                   s, len, NULL, NULL);
2117             }
2118           }
2119
2120
2121           if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2122               goto ret;
2123
2124           TRACE("close\n");
2125           FILEDLG95_Clean(hwnd);
2126           ret = EndDialog(hwnd, TRUE);
2127         }
2128         else
2129         {
2130           WORD size;
2131
2132           size = strlenW(lpstrPathAndFile) + 1;
2133           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2134              size += 1;
2135           /* return needed size in first two bytes of lpstrFile */
2136           *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2137           FILEDLG95_Clean(hwnd);
2138           ret = EndDialog(hwnd, FALSE);
2139           COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2140         }
2141         goto ret;
2142       }
2143       break;
2144   }
2145
2146 ret:
2147   if(lpsf) IShellFolder_Release(lpsf);
2148   return ret;
2149 }
2150
2151 /***********************************************************************
2152  *      FILEDLG95_SHELL_Init
2153  *
2154  * Initialisation of the shell objects
2155  */
2156 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2157 {
2158   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2159
2160   TRACE("\n");
2161
2162   /*
2163    * Initialisation of the FileOpenDialogInfos structure
2164    */
2165
2166   /* Shell */
2167
2168   /*ShellInfos */
2169   fodInfos->ShellInfos.hwndOwner = hwnd;
2170
2171   /* Disable multi-select if flag not set */
2172   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2173   {
2174      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2175   }
2176   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2177   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2178
2179   /* Construct the IShellBrowser interface */
2180   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2181
2182   return NOERROR;
2183 }
2184
2185 /***********************************************************************
2186  *      FILEDLG95_SHELL_ExecuteCommand
2187  *
2188  * Change the folder option and refresh the view
2189  * If the function succeeds, the return value is nonzero.
2190  */
2191 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2192 {
2193   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2194
2195   IContextMenu * pcm;
2196   TRACE("(%p,%p)\n", hwnd, lpVerb);
2197
2198   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2199                                         SVGIO_BACKGROUND,
2200                                         &IID_IContextMenu,
2201                                         (LPVOID*)&pcm)))
2202   {
2203     CMINVOKECOMMANDINFO ci;
2204     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2205     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2206     ci.lpVerb = lpVerb;
2207     ci.hwnd = hwnd;
2208
2209     IContextMenu_InvokeCommand(pcm, &ci);
2210     IContextMenu_Release(pcm);
2211   }
2212
2213   return FALSE;
2214 }
2215
2216 /***********************************************************************
2217  *      FILEDLG95_SHELL_UpFolder
2218  *
2219  * Browse to the specified object
2220  * If the function succeeds, the return value is nonzero.
2221  */
2222 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2223 {
2224   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2225
2226   TRACE("\n");
2227
2228   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2229                                           NULL,
2230                                           SBSP_PARENT)))
2231   {
2232     SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2233     return TRUE;
2234   }
2235   return FALSE;
2236 }
2237
2238 /***********************************************************************
2239  *      FILEDLG95_SHELL_BrowseToDesktop
2240  *
2241  * Browse to the Desktop
2242  * If the function succeeds, the return value is nonzero.
2243  */
2244 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2245 {
2246   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2247   LPITEMIDLIST pidl;
2248   HRESULT hres;
2249
2250   TRACE("\n");
2251
2252   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2253   hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2254   SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2255   COMDLG32_SHFree(pidl);
2256   return SUCCEEDED(hres);
2257 }
2258 /***********************************************************************
2259  *      FILEDLG95_SHELL_Clean
2260  *
2261  * Cleans the memory used by shell objects
2262  */
2263 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2264 {
2265     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2266
2267     TRACE("\n");
2268
2269     COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2270
2271     /* clean Shell interfaces */
2272     IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2273     IShellView_Release(fodInfos->Shell.FOIShellView);
2274     IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2275     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2276     if (fodInfos->Shell.FOIDataObject)
2277       IDataObject_Release(fodInfos->Shell.FOIDataObject);
2278 }
2279
2280 /***********************************************************************
2281  *      FILEDLG95_FILETYPE_Init
2282  *
2283  * Initialisation of the file type combo box
2284  */
2285 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2286 {
2287   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2288   int nFilters = 0;  /* number of filters */
2289   int nFilterIndexCB;
2290
2291   TRACE("\n");
2292
2293   if(fodInfos->customfilter)
2294   {
2295       /* customfilter has one entry...  title\0ext\0
2296        * Set first entry of combo box item with customfilter
2297        */
2298       LPWSTR  lpstrExt;
2299       LPCWSTR lpstrPos = fodInfos->customfilter;
2300
2301       /* Get the title */
2302       lpstrPos += strlenW(fodInfos->customfilter) + 1;
2303
2304       /* Copy the extensions */
2305       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
2306       if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2307       strcpyW(lpstrExt,lpstrPos);
2308
2309       /* Add the item at the end of the combo */
2310       CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2311       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2312       nFilters++;
2313   }
2314   if(fodInfos->filter)
2315   {
2316     LPCWSTR lpstrPos = fodInfos->filter;
2317
2318     for(;;)
2319     {
2320       /* filter is a list...  title\0ext\0......\0\0
2321        * Set the combo item text to the title and the item data
2322        *  to the ext
2323        */
2324       LPCWSTR lpstrDisplay;
2325       LPWSTR lpstrExt;
2326
2327       /* Get the title */
2328       if(! *lpstrPos) break;    /* end */
2329       lpstrDisplay = lpstrPos;
2330       lpstrPos += strlenW(lpstrPos) + 1;
2331
2332       /* Copy the extensions */
2333       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
2334       if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2335       strcpyW(lpstrExt,lpstrPos);
2336       lpstrPos += strlenW(lpstrPos) + 1;
2337
2338       /* Add the item at the end of the combo */
2339       CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2340       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2341       nFilters++;
2342     }
2343   }
2344
2345   /*
2346    * Set the current filter to the one specified
2347    * in the initialisation structure
2348    */
2349   if (fodInfos->filter || fodInfos->customfilter)
2350   {
2351     LPWSTR lpstrFilter;
2352
2353     /* Check to make sure our index isn't out of bounds. */
2354     if ( fodInfos->ofnInfos->nFilterIndex >
2355          nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2356       fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2357
2358     /* set default filter index */
2359     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2360       fodInfos->ofnInfos->nFilterIndex = 1;
2361
2362     /* calculate index of Combo Box item */
2363     nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2364     if (fodInfos->customfilter == NULL)
2365       nFilterIndexCB--;
2366
2367     /* Set the current index selection. */
2368     CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2369
2370     /* Get the corresponding text string from the combo box. */
2371     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2372                                              nFilterIndexCB);
2373
2374     if ((INT)lpstrFilter == CB_ERR)  /* control is empty */
2375       lpstrFilter = NULL;
2376
2377     if(lpstrFilter)
2378     {
2379       DWORD len;
2380       CharLowerW(lpstrFilter); /* lowercase */
2381       len = strlenW(lpstrFilter)+1;
2382       fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2383       strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2384     }
2385   } else
2386       fodInfos->ofnInfos->nFilterIndex = 0;
2387   return S_OK;
2388 }
2389
2390 /***********************************************************************
2391  *      FILEDLG95_FILETYPE_OnCommand
2392  *
2393  * WM_COMMAND of the file type combo box
2394  * If the function succeeds, the return value is nonzero.
2395  */
2396 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2397 {
2398   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2399
2400   switch(wNotifyCode)
2401   {
2402     case CBN_SELENDOK:
2403     {
2404       LPWSTR lpstrFilter;
2405
2406       /* Get the current item of the filetype combo box */
2407       int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2408
2409       /* set the current filter index */
2410       fodInfos->ofnInfos->nFilterIndex = iItem +
2411         (fodInfos->customfilter == NULL ? 1 : 0);
2412
2413       /* Set the current filter with the current selection */
2414       if(fodInfos->ShellInfos.lpstrCurrentFilter)
2415          MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2416
2417       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2418                                              iItem);
2419       if((int)lpstrFilter != CB_ERR)
2420       {
2421           DWORD len;
2422           CharLowerW(lpstrFilter); /* lowercase */
2423           len = strlenW(lpstrFilter)+1;
2424           fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2425           strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2426           SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2427       }
2428
2429       /* Refresh the actual view to display the included items*/
2430       IShellView_Refresh(fodInfos->Shell.FOIShellView);
2431     }
2432   }
2433   return FALSE;
2434 }
2435 /***********************************************************************
2436  *      FILEDLG95_FILETYPE_SearchExt
2437  *
2438  * searches for an extension in the filetype box
2439  */
2440 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2441 {
2442   int i, iCount = CBGetCount(hwnd);
2443
2444   TRACE("%s\n", debugstr_w(lpstrExt));
2445
2446   if(iCount != CB_ERR)
2447   {
2448     for(i=0;i<iCount;i++)
2449     {
2450       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2451           return i;
2452     }
2453   }
2454   return -1;
2455 }
2456
2457 /***********************************************************************
2458  *      FILEDLG95_FILETYPE_Clean
2459  *
2460  * Clean the memory used by the filetype combo box
2461  */
2462 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2463 {
2464   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2465   int iPos;
2466   int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2467
2468   TRACE("\n");
2469
2470   /* Delete each string of the combo and their associated data */
2471   if(iCount != CB_ERR)
2472   {
2473     for(iPos = iCount-1;iPos>=0;iPos--)
2474     {
2475       MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2476       CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2477     }
2478   }
2479   /* Current filter */
2480   if(fodInfos->ShellInfos.lpstrCurrentFilter)
2481      MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2482
2483 }
2484
2485 /***********************************************************************
2486  *      FILEDLG95_LOOKIN_Init
2487  *
2488  * Initialisation of the look in combo box
2489  */
2490
2491 /* Small helper function, to determine if the unixfs shell extension is rooted 
2492  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 
2493  */
2494 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2495     HKEY hKey;
2496     const static WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2497         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2498         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2499         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2500         'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2501         '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2502         '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2503     
2504     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2505         return FALSE;
2506         
2507     RegCloseKey(hKey);
2508     return TRUE;
2509 }
2510
2511 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2512 {
2513   IShellFolder  *psfRoot, *psfDrives;
2514   IEnumIDList   *lpeRoot, *lpeDrives;
2515   LPITEMIDLIST  pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2516
2517   LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2518
2519   TRACE("\n");
2520
2521   liInfos->iMaxIndentation = 0;
2522
2523   SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2524
2525   /* set item height for both text field and listbox */
2526   CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2527   CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2528    
2529   /* Turn on the extended UI for the combo box like Windows does */
2530   CBSetExtendedUI(hwndCombo, TRUE);
2531
2532   /* Initialise data of Desktop folder */
2533   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2534   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2535   COMDLG32_SHFree(pidlTmp);
2536
2537   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2538
2539   SHGetDesktopFolder(&psfRoot);
2540
2541   if (psfRoot)
2542   {
2543     /* enumerate the contents of the desktop */
2544     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2545     {
2546       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2547       {
2548         FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2549
2550         /* If the unixfs extension is rooted, we don't expand the drives by default */
2551         if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 
2552         {
2553           /* special handling for CSIDL_DRIVES */
2554           if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2555           {
2556             if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2557             {
2558               /* enumerate the drives */
2559               if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2560               {
2561                 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2562                 {
2563                   pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2564                   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2565                   COMDLG32_SHFree(pidlAbsTmp);
2566                   COMDLG32_SHFree(pidlTmp1);
2567                 }
2568                 IEnumIDList_Release(lpeDrives);
2569               }
2570               IShellFolder_Release(psfDrives);
2571             }
2572           }
2573         }
2574
2575         COMDLG32_SHFree(pidlTmp);
2576       }
2577       IEnumIDList_Release(lpeRoot);
2578     }
2579     IShellFolder_Release(psfRoot);
2580   }
2581
2582   COMDLG32_SHFree(pidlDrives);
2583 }
2584
2585 /***********************************************************************
2586  *      FILEDLG95_LOOKIN_DrawItem
2587  *
2588  * WM_DRAWITEM message handler
2589  */
2590 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2591 {
2592   COLORREF crWin = GetSysColor(COLOR_WINDOW);
2593   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2594   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2595   RECT rectText;
2596   RECT rectIcon;
2597   SHFILEINFOA sfi;
2598   HIMAGELIST ilItemImage;
2599   int iIndentation;
2600   TEXTMETRICA tm;
2601   LPSFOLDER tmpFolder;
2602
2603
2604   LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2605
2606   TRACE("\n");
2607
2608   if(pDIStruct->itemID == -1)
2609     return 0;
2610
2611   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2612                             pDIStruct->itemID)))
2613     return 0;
2614
2615
2616   if(pDIStruct->itemID == liInfos->uSelectedItem)
2617   {
2618     ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2619                                                0,
2620                                                &sfi,
2621                                                sizeof (SHFILEINFOA),
2622                                                SHGFI_PIDL | SHGFI_SMALLICON |
2623                                                SHGFI_OPENICON | SHGFI_SYSICONINDEX    |
2624                                                SHGFI_DISPLAYNAME );
2625   }
2626   else
2627   {
2628     ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2629                                                   0,
2630                                                   &sfi,
2631                                                   sizeof (SHFILEINFOA),
2632                                                   SHGFI_PIDL | SHGFI_SMALLICON |
2633                                                   SHGFI_SYSICONINDEX |
2634                                                   SHGFI_DISPLAYNAME);
2635   }
2636
2637   /* Is this item selected ? */
2638   if(pDIStruct->itemState & ODS_SELECTED)
2639   {
2640     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2641     SetBkColor(pDIStruct->hDC,crHighLight);
2642     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2643   }
2644   else
2645   {
2646     SetTextColor(pDIStruct->hDC,crText);
2647     SetBkColor(pDIStruct->hDC,crWin);
2648     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2649   }
2650
2651   /* Do not indent item if drawing in the edit of the combo */
2652   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2653   {
2654     iIndentation = 0;
2655     ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2656                                                 0,
2657                                                 &sfi,
2658                                                 sizeof (SHFILEINFOA),
2659                                                 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2660                                                 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME  );
2661
2662   }
2663   else
2664   {
2665     iIndentation = tmpFolder->m_iIndent;
2666   }
2667   /* Draw text and icon */
2668
2669   /* Initialise the icon display area */
2670   rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2671   rectIcon.top = pDIStruct->rcItem.top;
2672   rectIcon.right = rectIcon.left + ICONWIDTH;
2673   rectIcon.bottom = pDIStruct->rcItem.bottom;
2674
2675   /* Initialise the text display area */
2676   GetTextMetricsA(pDIStruct->hDC, &tm);
2677   rectText.left = rectIcon.right;
2678   rectText.top =
2679           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2680   rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2681   rectText.bottom =
2682           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2683
2684   /* Draw the icon from the image list */
2685   ImageList_Draw(ilItemImage,
2686                  sfi.iIcon,
2687                  pDIStruct->hDC,
2688                  rectIcon.left,
2689                  rectIcon.top,
2690                  ILD_TRANSPARENT );
2691
2692   /* Draw the associated text */
2693   if(sfi.szDisplayName)
2694     TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2695
2696
2697   return NOERROR;
2698 }
2699
2700 /***********************************************************************
2701  *      FILEDLG95_LOOKIN_OnCommand
2702  *
2703  * LookIn combo box WM_COMMAND message handler
2704  * If the function succeeds, the return value is nonzero.
2705  */
2706 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2707 {
2708   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2709
2710   TRACE("%p\n", fodInfos);
2711
2712   switch(wNotifyCode)
2713   {
2714     case CBN_SELENDOK:
2715     {
2716       LPSFOLDER tmpFolder;
2717       int iItem;
2718
2719       iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2720
2721       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2722                                                iItem)))
2723         return FALSE;
2724
2725
2726       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2727                                               tmpFolder->pidlItem,
2728                                               SBSP_ABSOLUTE)))
2729       {
2730         SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2731         return TRUE;
2732       }
2733       break;
2734     }
2735
2736   }
2737   return FALSE;
2738 }
2739
2740 /***********************************************************************
2741  *      FILEDLG95_LOOKIN_AddItem
2742  *
2743  * Adds an absolute pidl item to the lookin combo box
2744  * returns the index of the inserted item
2745  */
2746 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2747 {
2748   LPITEMIDLIST pidlNext;
2749   SHFILEINFOA sfi;
2750   SFOLDER *tmpFolder;
2751   LookInInfos *liInfos;
2752
2753   TRACE("%08x\n", iInsertId);
2754
2755   if(!pidl)
2756     return -1;
2757
2758   if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2759     return -1;
2760
2761   tmpFolder = MemAlloc(sizeof(SFOLDER));
2762   tmpFolder->m_iIndent = 0;
2763
2764   /* Calculate the indentation of the item in the lookin*/
2765   pidlNext = pidl;
2766   while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2767   {
2768     tmpFolder->m_iIndent++;
2769   }
2770
2771   tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2772
2773   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2774     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2775
2776   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2777   SHGetFileInfoA((LPSTR)pidl,
2778                   0,
2779                   &sfi,
2780                   sizeof(sfi),
2781                   SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2782                   | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2783
2784   TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2785
2786   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2787   {
2788     int iItemID;
2789
2790     TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2791
2792     /* Add the item at the end of the list */
2793     if(iInsertId < 0)
2794     {
2795       iItemID = CBAddString(hwnd,sfi.szDisplayName);
2796     }
2797     /* Insert the item at the iInsertId position*/
2798     else
2799     {
2800       iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2801     }
2802
2803     CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2804     return iItemID;
2805   }
2806
2807   COMDLG32_SHFree( tmpFolder->pidlItem );
2808   MemFree( tmpFolder );
2809   return -1;
2810
2811 }
2812
2813 /***********************************************************************
2814  *      FILEDLG95_LOOKIN_InsertItemAfterParent
2815  *
2816  * Insert an item below its parent
2817  */
2818 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2819 {
2820
2821   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2822   int iParentPos;
2823
2824   TRACE("\n");
2825
2826   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2827
2828   if(iParentPos < 0)
2829   {
2830     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2831   }
2832
2833   /* Free pidlParent memory */
2834   COMDLG32_SHFree((LPVOID)pidlParent);
2835
2836   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2837 }
2838
2839 /***********************************************************************
2840  *      FILEDLG95_LOOKIN_SelectItem
2841  *
2842  * Adds an absolute pidl item to the lookin combo box
2843  * returns the index of the inserted item
2844  */
2845 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2846 {
2847   int iItemPos;
2848   LookInInfos *liInfos;
2849
2850   TRACE("\n");
2851
2852   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2853
2854   liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2855
2856   if(iItemPos < 0)
2857   {
2858     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2859     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2860   }
2861
2862   else
2863   {
2864     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2865     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2866     {
2867       int iRemovedItem;
2868
2869       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2870         break;
2871       if(iRemovedItem < iItemPos)
2872         iItemPos--;
2873     }
2874   }
2875
2876   CBSetCurSel(hwnd,iItemPos);
2877   liInfos->uSelectedItem = iItemPos;
2878
2879   return 0;
2880
2881 }
2882
2883 /***********************************************************************
2884  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
2885  *
2886  * Remove the item with an expansion level over iExpansionLevel
2887  */
2888 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2889 {
2890   int iItemPos;
2891
2892   LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2893
2894   TRACE("\n");
2895
2896   if(liInfos->iMaxIndentation <= 2)
2897     return -1;
2898
2899   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2900   {
2901     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2902     COMDLG32_SHFree(tmpFolder->pidlItem);
2903     MemFree(tmpFolder);
2904     CBDeleteString(hwnd,iItemPos);
2905     liInfos->iMaxIndentation--;
2906
2907     return iItemPos;
2908   }
2909
2910   return -1;
2911 }
2912
2913 /***********************************************************************
2914  *      FILEDLG95_LOOKIN_SearchItem
2915  *
2916  * Search for pidl in the lookin combo box
2917  * returns the index of the found item
2918  */
2919 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2920 {
2921   int i = 0;
2922   int iCount = CBGetCount(hwnd);
2923
2924   TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2925
2926   if (iCount != CB_ERR)
2927   {
2928     for(;i<iCount;i++)
2929     {
2930       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2931
2932       if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2933         return i;
2934       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2935         return i;
2936     }
2937   }
2938
2939   return -1;
2940 }
2941
2942 /***********************************************************************
2943  *      FILEDLG95_LOOKIN_Clean
2944  *
2945  * Clean the memory used by the lookin combo box
2946  */
2947 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2948 {
2949     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2950     int iPos;
2951     int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2952
2953     TRACE("\n");
2954
2955     /* Delete each string of the combo and their associated data */
2956     if (iCount != CB_ERR)
2957     {
2958       for(iPos = iCount-1;iPos>=0;iPos--)
2959       {
2960         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2961         COMDLG32_SHFree(tmpFolder->pidlItem);
2962         MemFree(tmpFolder);
2963         CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2964       }
2965     }
2966
2967     /* LookInInfos structure */
2968     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2969
2970 }
2971 /***********************************************************************
2972  * FILEDLG95_FILENAME_FillFromSelection
2973  *
2974  * fills the edit box from the cached DataObject
2975  */
2976 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2977 {
2978     FileOpenDlgInfos *fodInfos;
2979     LPITEMIDLIST      pidl;
2980     UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2981     char              lpstrTemp[MAX_PATH];
2982     LPSTR             lpstrAllFile = NULL, lpstrCurrFile = NULL;
2983
2984     TRACE("\n");
2985     fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2986
2987     /* Count how many files we have */
2988     nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2989
2990     /* calculate the string length, count files */
2991     if (nFileSelected >= 1)
2992     {
2993       nLength += 3;     /* first and last quotes, trailing \0 */
2994       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2995       {
2996         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2997
2998         if (pidl)
2999         {
3000           /* get the total length of the selected file names */
3001           lpstrTemp[0] = '\0';
3002           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3003
3004           if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3005           {
3006             nLength += strlen( lpstrTemp ) + 3;
3007             nFiles++;
3008           }
3009           COMDLG32_SHFree( pidl );
3010         }
3011       }
3012     }
3013
3014     /* allocate the buffer */
3015     if (nFiles <= 1) nLength = MAX_PATH;
3016     lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
3017     lpstrAllFile[0] = '\0';
3018
3019     /* Generate the string for the edit control */
3020     if(nFiles >= 1)
3021     {
3022       lpstrCurrFile = lpstrAllFile;
3023       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3024       {
3025         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3026
3027         if (pidl)
3028         {
3029           /* get the file name */
3030           lpstrTemp[0] = '\0';
3031           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3032
3033           if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3034           {
3035             if ( nFiles > 1)
3036             {
3037               *lpstrCurrFile++ =  '\"';
3038               strcpy( lpstrCurrFile, lpstrTemp );
3039               lpstrCurrFile += strlen( lpstrTemp );
3040               strcpy( lpstrCurrFile, "\" " );
3041               lpstrCurrFile += 2;
3042             }
3043             else
3044             {
3045               strcpy( lpstrAllFile, lpstrTemp );
3046             }
3047           }
3048           COMDLG32_SHFree( (LPVOID) pidl );
3049         }
3050       }
3051       SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3052        
3053       /* Select the file name like Windows does */ 
3054       SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3055     }
3056     HeapFree(GetProcessHeap(),0, lpstrAllFile );
3057 }
3058
3059
3060 /* copied from shell32 to avoid linking to it
3061  * FIXME: why?  shell32 is already linked
3062  */
3063 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3064 {
3065         switch (src->uType)
3066         {
3067           case STRRET_WSTR:
3068             WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3069             COMDLG32_SHFree(src->u.pOleStr);
3070             break;
3071
3072           case STRRET_CSTR:
3073             lstrcpynA((LPSTR)dest, src->u.cStr, len);
3074             break;
3075
3076           case STRRET_OFFSET:
3077             lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3078             break;
3079
3080           default:
3081             FIXME("unknown type!\n");
3082             if (len)
3083             {
3084               *(LPSTR)dest = '\0';
3085             }
3086             return(E_FAIL);
3087         }
3088         return S_OK;
3089 }
3090
3091 /***********************************************************************
3092  * FILEDLG95_FILENAME_GetFileNames
3093  *
3094  * Copies the filenames to a delimited string list.
3095  * The delimiter is specified by the parameter 'separator',
3096  *  usually either a space or a nul
3097  */
3098 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3099 {
3100         FileOpenDlgInfos *fodInfos  = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3101         UINT nStrCharCount = 0; /* index in src buffer */
3102         UINT nFileIndex = 0;    /* index in dest buffer */
3103         UINT nFileCount = 0;    /* number of files */
3104         UINT nStrLen = 0;       /* length of string in edit control */
3105         LPWSTR lpstrEdit;       /* buffer for string from edit control */
3106
3107         TRACE("\n");
3108
3109         /* get the filenames from the edit control */
3110         nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3111         lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3112         GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3113
3114         TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3115
3116         /* we might get single filename without any '"',
3117          * so we need nStrLen + terminating \0 + end-of-list \0 */
3118         *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3119         *sizeUsed = 0;
3120
3121         /* build delimited file list from filenames */
3122         while ( nStrCharCount <= nStrLen )
3123         {
3124           if ( lpstrEdit[nStrCharCount]=='"' )
3125           {
3126             nStrCharCount++;
3127             while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3128             {
3129               (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3130               (*sizeUsed)++;
3131               nStrCharCount++;
3132             }
3133             (*lpstrFileList)[nFileIndex++] = separator;
3134             (*sizeUsed)++;
3135             nFileCount++;
3136           }
3137           nStrCharCount++;
3138         }
3139
3140         /* single, unquoted string */
3141         if ((nStrLen > 0) && (*sizeUsed == 0) )
3142         {
3143           strcpyW(*lpstrFileList, lpstrEdit);
3144           nFileIndex = strlenW(lpstrEdit) + 1;
3145           (*sizeUsed) = nFileIndex;
3146           nFileCount = 1;
3147         }
3148
3149         /* trailing \0 */
3150         (*lpstrFileList)[nFileIndex] = '\0';
3151         (*sizeUsed)++;
3152
3153         MemFree(lpstrEdit);
3154         return nFileCount;
3155 }
3156
3157 #define SETDefFormatEtc(fe,cf,med) \
3158 { \
3159     (fe).cfFormat = cf;\
3160     (fe).dwAspect = DVASPECT_CONTENT; \
3161     (fe).ptd =NULL;\
3162     (fe).tymed = med;\
3163     (fe).lindex = -1;\
3164 };
3165
3166 /*
3167  * DATAOBJECT Helper functions
3168  */
3169
3170 /***********************************************************************
3171  * COMCTL32_ReleaseStgMedium
3172  *
3173  * like ReleaseStgMedium from ole32
3174  */
3175 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3176 {
3177       if(medium.pUnkForRelease)
3178       {
3179         IUnknown_Release(medium.pUnkForRelease);
3180       }
3181       else
3182       {
3183         GlobalUnlock(medium.u.hGlobal);
3184         GlobalFree(medium.u.hGlobal);
3185       }
3186 }
3187
3188 /***********************************************************************
3189  *          GetPidlFromDataObject
3190  *
3191  * Return pidl(s) by number from the cached DataObject
3192  *
3193  * nPidlIndex=0 gets the fully qualified root path
3194  */
3195 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3196 {
3197
3198     STGMEDIUM medium;
3199     FORMATETC formatetc;
3200     LPITEMIDLIST pidl = NULL;
3201
3202     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3203
3204     /* Set the FORMATETC structure*/
3205     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3206
3207     /* Get the pidls from IDataObject */
3208     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3209     {
3210       LPIDA cida = GlobalLock(medium.u.hGlobal);
3211       if(nPidlIndex <= cida->cidl)
3212       {
3213         pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3214       }
3215       COMCTL32_ReleaseStgMedium(medium);
3216     }
3217     return pidl;
3218 }
3219
3220 /***********************************************************************
3221  *          GetNumSelected
3222  *
3223  * Return the number of selected items in the DataObject.
3224  *
3225 */
3226 UINT GetNumSelected( IDataObject *doSelected )
3227 {
3228     UINT retVal = 0;
3229     STGMEDIUM medium;
3230     FORMATETC formatetc;
3231
3232     TRACE("sv=%p\n", doSelected);
3233
3234     if (!doSelected) return 0;
3235
3236     /* Set the FORMATETC structure*/
3237     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3238
3239     /* Get the pidls from IDataObject */
3240     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3241     {
3242       LPIDA cida = GlobalLock(medium.u.hGlobal);
3243       retVal = cida->cidl;
3244       COMCTL32_ReleaseStgMedium(medium);
3245       return retVal;
3246     }
3247     return 0;
3248 }
3249
3250 /*
3251  * TOOLS
3252  */
3253
3254 /***********************************************************************
3255  *      GetName
3256  *
3257  * Get the pidl's display name (relative to folder) and
3258  * put it in lpstrFileName.
3259  *
3260  * Return NOERROR on success,
3261  * E_FAIL otherwise
3262  */
3263
3264 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3265 {
3266   STRRET str;
3267   HRESULT hRes;
3268
3269   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3270
3271   if(!lpsf)
3272   {
3273     SHGetDesktopFolder(&lpsf);
3274     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3275     IShellFolder_Release(lpsf);
3276     return hRes;
3277   }
3278
3279   /* Get the display name of the pidl relative to the folder */
3280   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3281   {
3282       return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3283   }
3284   return E_FAIL;
3285 }
3286
3287 /***********************************************************************
3288  *      GetShellFolderFromPidl
3289  *
3290  * pidlRel is the item pidl relative
3291  * Return the IShellFolder of the absolute pidl
3292  */
3293 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3294 {
3295   IShellFolder *psf = NULL,*psfParent;
3296
3297   TRACE("%p\n", pidlAbs);
3298
3299   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3300   {
3301     psf = psfParent;
3302     if(pidlAbs && pidlAbs->mkid.cb)
3303     {
3304       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3305       {
3306         IShellFolder_Release(psfParent);
3307         return psf;
3308       }
3309     }
3310     /* return the desktop */
3311     return psfParent;
3312   }
3313   return NULL;
3314 }
3315
3316 /***********************************************************************
3317  *      GetParentPidl
3318  *
3319  * Return the LPITEMIDLIST to the parent of the pidl in the list
3320  */
3321 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3322 {
3323   LPITEMIDLIST pidlParent;
3324
3325   TRACE("%p\n", pidl);
3326
3327   pidlParent = COMDLG32_PIDL_ILClone(pidl);
3328   COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3329
3330   return pidlParent;
3331 }
3332
3333 /***********************************************************************
3334  *      GetPidlFromName
3335  *
3336  * returns the pidl of the file name relative to folder
3337  * NULL if an error occurred
3338  */
3339 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3340 {
3341   LPITEMIDLIST pidl = NULL;
3342   ULONG ulEaten;
3343
3344   TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3345
3346   if(!lpcstrFileName) return NULL;
3347   if(!*lpcstrFileName) return NULL;
3348
3349   if(!lpsf)
3350   {
3351     if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3352         IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3353         IShellFolder_Release(lpsf);
3354     }
3355   }
3356   else
3357   {
3358     IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3359   }
3360   return pidl;
3361 }
3362
3363 /*
3364 */
3365 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3366 {
3367         ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3368         HRESULT ret;
3369
3370         TRACE("%p, %p\n", psf, pidl);
3371
3372         ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3373
3374         TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3375         /* see documentation shell 4.1*/
3376         return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3377 }
3378
3379 /***********************************************************************
3380  *      BrowseSelectedFolder
3381  */
3382 static BOOL BrowseSelectedFolder(HWND hwnd)
3383 {
3384   BOOL bBrowseSelFolder = FALSE;
3385   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3386
3387   TRACE("\n");
3388
3389   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3390   {
3391       LPITEMIDLIST pidlSelection;
3392
3393       /* get the file selected */
3394       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3395       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3396       {
3397           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3398                          pidlSelection, SBSP_RELATIVE ) ) )
3399           {
3400                static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3401                                    ' ','n','o','t',' ','e','x','i','s','t',0};
3402                MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3403           }
3404           bBrowseSelFolder = TRUE;
3405           SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3406       }
3407       COMDLG32_SHFree( pidlSelection );
3408   }
3409
3410   return bBrowseSelFolder;
3411 }
3412
3413 /*
3414  * Memory allocation methods */
3415 static void *MemAlloc(UINT size)
3416 {
3417     return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3418 }
3419
3420 static void MemFree(void *mem)
3421 {
3422     HeapFree(GetProcessHeap(),0,mem);
3423 }
3424
3425 /*
3426  * Old-style (win3.1) dialogs */
3427
3428 /***********************************************************************
3429  *           FD32_GetTemplate                                  [internal]
3430  *
3431  * Get a template (or FALSE if failure) when 16 bits dialogs are used
3432  * by a 32 bits application
3433  *
3434  */
3435 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3436 {
3437     LPOPENFILENAMEW ofnW = lfs->ofnW;
3438     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3439     HANDLE hDlgTmpl;
3440
3441     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3442     {
3443         if (!(lfs->template = LockResource( ofnW->hInstance )))
3444         {
3445             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3446             return FALSE;
3447         }
3448     }
3449     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3450     {
3451         HRSRC hResInfo;
3452         if (priv->ofnA)
3453             hResInfo = FindResourceA(priv->ofnA->hInstance,
3454                                  priv->ofnA->lpTemplateName,
3455                                  (LPSTR)RT_DIALOG);
3456         else
3457             hResInfo = FindResourceW(ofnW->hInstance,
3458                                  ofnW->lpTemplateName,
3459                                  (LPWSTR)RT_DIALOG);
3460         if (!hResInfo)
3461         {
3462             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3463             return FALSE;
3464         }
3465         if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3466                                 hResInfo)) ||
3467                     !(lfs->template = LockResource(hDlgTmpl)))
3468         {
3469             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3470             return FALSE;
3471         }
3472     } else { /* get it from internal Wine resource */
3473         HRSRC hResInfo;
3474         if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3475              lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3476         {
3477             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3478             return FALSE;
3479         }
3480         if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3481                 !(lfs->template = LockResource( hDlgTmpl )))
3482         {
3483             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3484             return FALSE;
3485         }
3486     }
3487     return TRUE;
3488 }
3489
3490
3491 /************************************************************************
3492  *                              FD32_Init          [internal]
3493  *      called from the common 16/32 code to initialize 32 bit data
3494  */
3495 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3496 {
3497     BOOL IsUnicode = (BOOL) data;
3498     PFD32_PRIVATE priv;
3499
3500     priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3501     lfs->private1632 = priv;
3502     if (NULL == lfs->private1632) return FALSE;
3503     if (IsUnicode)
3504     {
3505         lfs->ofnW = (LPOPENFILENAMEW) lParam;
3506         if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3507             if (lfs->ofnW->lpfnHook)
3508                 lfs->hook = TRUE;
3509     }
3510     else
3511     {
3512         priv->ofnA = (LPOPENFILENAMEA) lParam;
3513         if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3514             if (priv->ofnA->lpfnHook)
3515                 lfs->hook = TRUE;
3516         lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3517         FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3518     }
3519
3520     if (! FD32_GetTemplate(lfs)) return FALSE;
3521
3522     return TRUE;
3523 }
3524
3525 /***********************************************************************
3526  *                              FD32_CallWindowProc          [internal]
3527  *
3528  *      called from the common 16/32 code to call the appropriate hook
3529  */
3530 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3531                                  LPARAM lParam)
3532 {
3533     BOOL ret;
3534     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3535
3536     if (priv->ofnA)
3537     {
3538         TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3539                priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3540         ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3541         TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3542                priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3543         return ret;
3544     }
3545
3546     TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3547            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3548     ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3549     TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3550            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3551     return ret;
3552 }
3553
3554 /***********************************************************************
3555  *                              FD32_UpdateResult            [internal]
3556  *          update the real client structures if any
3557  */
3558 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3559 {
3560     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3561     LPOPENFILENAMEW ofnW = lfs->ofnW;
3562
3563     if (priv->ofnA)
3564     {
3565         if (ofnW->nMaxFile &&
3566             !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3567                                   priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3568             priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3569         priv->ofnA->nFileOffset = ofnW->nFileOffset;
3570         priv->ofnA->nFileExtension = ofnW->nFileExtension;
3571     }
3572 }
3573
3574 /***********************************************************************
3575  *                              FD32_UpdateFileTitle            [internal]
3576  *          update the real client structures if any
3577  */
3578 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3579 {
3580     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3581     LPOPENFILENAMEW ofnW = lfs->ofnW;
3582
3583     if (priv->ofnA)
3584     {
3585         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3586                                   priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3587             priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3588     }
3589 }
3590
3591
3592 /***********************************************************************
3593  *                              FD32_SendLbGetCurSel         [internal]
3594  *          retrieve selected listbox item
3595  */
3596 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3597 {
3598     return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3599 }
3600
3601
3602 /************************************************************************
3603  *                              FD32_Destroy          [internal]
3604  *      called from the common 16/32 code to cleanup 32 bit data
3605  */
3606 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3607 {
3608     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3609
3610     /* if ofnW has been allocated, have to free everything in it */
3611     if (NULL != priv && NULL != priv->ofnA)
3612     {
3613         FD31_FreeOfnW(lfs->ofnW);
3614         HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3615     }
3616 }
3617
3618 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3619 {
3620     callbacks->Init = FD32_Init;
3621     callbacks->CWP = FD32_CallWindowProc;
3622     callbacks->UpdateResult = FD32_UpdateResult;
3623     callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3624     callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3625     callbacks->Destroy = FD32_Destroy;
3626 }
3627
3628 /***********************************************************************
3629  *                              FD32_WMMeasureItem           [internal]
3630  */
3631 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3632 {
3633     LPMEASUREITEMSTRUCT lpmeasure;
3634
3635     lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3636     lpmeasure->itemHeight = FD31_GetFldrHeight();
3637     return TRUE;
3638 }
3639
3640
3641 /***********************************************************************
3642  *           FileOpenDlgProc                                    [internal]
3643  *      Used for open and save, in fact.
3644  */
3645 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3646                                              WPARAM wParam, LPARAM lParam)
3647 {
3648     PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3649
3650     TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3651     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3652         {
3653             INT_PTR lRet;
3654             lRet  = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3655             if (lRet)
3656                 return lRet;         /* else continue message processing */
3657         }
3658     switch (wMsg)
3659     {
3660     case WM_INITDIALOG:
3661         return FD31_WMInitDialog(hWnd, wParam, lParam);
3662
3663     case WM_MEASUREITEM:
3664         return FD32_WMMeasureItem(hWnd, wParam, lParam);
3665
3666     case WM_DRAWITEM:
3667         return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3668
3669     case WM_COMMAND:
3670         return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3671 #if 0
3672     case WM_CTLCOLOR:
3673          SetBkColor((HDC16)wParam, 0x00C0C0C0);
3674          switch (HIWORD(lParam))
3675          {
3676          case CTLCOLOR_BTN:
3677              SetTextColor((HDC16)wParam, 0x00000000);
3678              return hGRAYBrush;
3679         case CTLCOLOR_STATIC:
3680              SetTextColor((HDC16)wParam, 0x00000000);
3681              return hGRAYBrush;
3682         }
3683       break;
3684 #endif
3685     }
3686     return FALSE;
3687 }
3688
3689
3690 /***********************************************************************
3691  *           GetFileName31A                                 [internal]
3692  *
3693  * Creates a win31 style dialog box for the user to select a file to open/save.
3694  */
3695 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3696                            UINT dlgType /* type dialogue : open/save */
3697                            )
3698 {
3699     HINSTANCE hInst;
3700     BOOL bRet = FALSE;
3701     PFD31_DATA lfs;
3702     FD31_CALLBACKS callbacks;
3703
3704     if (!lpofn || !FD31_Init()) return FALSE;
3705
3706     TRACE("ofn flags %08lx\n", lpofn->Flags);
3707     FD32_SetupCallbacks(&callbacks);
3708     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3709     if (lfs)
3710     {
3711         hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3712         bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3713                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
3714         FD31_DestroyPrivate(lfs);
3715     }
3716
3717     TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3718     return bRet;
3719 }
3720
3721 /***********************************************************************
3722  *           GetFileName31W                                 [internal]
3723  *
3724  * Creates a win31 style dialog box for the user to select a file to open/save
3725  */
3726 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3727                            UINT dlgType /* type dialogue : open/save */
3728                            )
3729 {
3730     HINSTANCE hInst;
3731     BOOL bRet = FALSE;
3732     PFD31_DATA lfs;
3733     FD31_CALLBACKS callbacks;
3734
3735     if (!lpofn || !FD31_Init()) return FALSE;
3736
3737     FD32_SetupCallbacks(&callbacks);
3738     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3739     if (lfs)
3740     {
3741         hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3742         bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3743                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
3744         FD31_DestroyPrivate(lfs);
3745     }
3746
3747     TRACE("file %s, file offset %d, ext offset %d\n",
3748           debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3749     return bRet;
3750 }
3751
3752 /* ------------------ APIs ---------------------- */
3753
3754 /***********************************************************************
3755  *            GetOpenFileNameA  (COMDLG32.@)
3756  *
3757  * Creates a dialog box for the user to select a file to open.
3758  *
3759  * RETURNS
3760  *    TRUE on success: user enters a valid file
3761  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3762  *
3763  */
3764 BOOL WINAPI GetOpenFileNameA(
3765         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3766 {
3767     BOOL win16look = FALSE;
3768
3769     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3770     if (ofn->Flags & OFN_FILEMUSTEXIST)
3771         ofn->Flags |= OFN_PATHMUSTEXIST;
3772
3773     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3774         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3775
3776     if (win16look)
3777         return GetFileName31A(ofn, OPEN_DIALOG);
3778     else
3779         return GetFileDialog95A(ofn, OPEN_DIALOG);
3780 }
3781
3782 /***********************************************************************
3783  *            GetOpenFileNameW (COMDLG32.@)
3784  *
3785  * Creates a dialog box for the user to select a file to open.
3786  *
3787  * RETURNS
3788  *    TRUE on success: user enters a valid file
3789  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3790  *
3791  */
3792 BOOL WINAPI GetOpenFileNameW(
3793         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3794 {
3795     BOOL win16look = FALSE;
3796
3797     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3798         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3799
3800     if (win16look)
3801         return GetFileName31W(ofn, OPEN_DIALOG);
3802     else
3803         return GetFileDialog95W(ofn, OPEN_DIALOG);
3804 }
3805
3806
3807 /***********************************************************************
3808  *            GetSaveFileNameA  (COMDLG32.@)
3809  *
3810  * Creates a dialog box for the user to select a file to save.
3811  *
3812  * RETURNS
3813  *    TRUE on success: user enters a valid file
3814  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3815  *
3816  */
3817 BOOL WINAPI GetSaveFileNameA(
3818         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3819 {
3820     BOOL win16look = FALSE;
3821
3822     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3823         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3824
3825     if (win16look)
3826         return GetFileName31A(ofn, SAVE_DIALOG);
3827     else
3828         return GetFileDialog95A(ofn, SAVE_DIALOG);
3829 }
3830
3831 /***********************************************************************
3832  *            GetSaveFileNameW  (COMDLG32.@)
3833  *
3834  * Creates a dialog box for the user to select a file to save.
3835  *
3836  * RETURNS
3837  *    TRUE on success: user enters a valid file
3838  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3839  *
3840  */
3841 BOOL WINAPI GetSaveFileNameW(
3842         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3843 {
3844     BOOL win16look = FALSE;
3845
3846     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3847         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3848
3849     if (win16look)
3850         return GetFileName31W(ofn, SAVE_DIALOG);
3851     else
3852         return GetFileDialog95W(ofn, SAVE_DIALOG);
3853 }