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