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