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