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