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