msvcrt: Don't include msvcrt headers, instead duplicate the definitions in msvcrt.h.
[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                                      (LPCDLGTEMPLATEA) 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, (HANDLE) 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((LPVOID)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         goto ret;
2209       }
2210       break;
2211   }
2212
2213 ret:
2214   if(lpsf) IShellFolder_Release(lpsf);
2215   return ret;
2216 }
2217
2218 /***********************************************************************
2219  *      FILEDLG95_SHELL_Init
2220  *
2221  * Initialisation of the shell objects
2222  */
2223 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2224 {
2225   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2226
2227   TRACE("\n");
2228
2229   /*
2230    * Initialisation of the FileOpenDialogInfos structure
2231    */
2232
2233   /* Shell */
2234
2235   /*ShellInfos */
2236   fodInfos->ShellInfos.hwndOwner = hwnd;
2237
2238   /* Disable multi-select if flag not set */
2239   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2240   {
2241      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2242   }
2243   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2244   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2245
2246   /* Construct the IShellBrowser interface */
2247   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2248
2249   return NOERROR;
2250 }
2251
2252 /***********************************************************************
2253  *      FILEDLG95_SHELL_ExecuteCommand
2254  *
2255  * Change the folder option and refresh the view
2256  * If the function succeeds, the return value is nonzero.
2257  */
2258 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2259 {
2260   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2261   IContextMenu * pcm;
2262
2263   TRACE("(%p,%p)\n", hwnd, lpVerb);
2264
2265   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2266                                         SVGIO_BACKGROUND,
2267                                         &IID_IContextMenu,
2268                                         (LPVOID*)&pcm)))
2269   {
2270     CMINVOKECOMMANDINFO ci;
2271     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2272     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2273     ci.lpVerb = lpVerb;
2274     ci.hwnd = hwnd;
2275
2276     IContextMenu_InvokeCommand(pcm, &ci);
2277     IContextMenu_Release(pcm);
2278   }
2279
2280   return FALSE;
2281 }
2282
2283 /***********************************************************************
2284  *      FILEDLG95_SHELL_UpFolder
2285  *
2286  * Browse to the specified object
2287  * If the function succeeds, the return value is nonzero.
2288  */
2289 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2290 {
2291   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2292
2293   TRACE("\n");
2294
2295   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2296                                           NULL,
2297                                           SBSP_PARENT)))
2298   {
2299     SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2300     return TRUE;
2301   }
2302   return FALSE;
2303 }
2304
2305 /***********************************************************************
2306  *      FILEDLG95_SHELL_BrowseToDesktop
2307  *
2308  * Browse to the Desktop
2309  * If the function succeeds, the return value is nonzero.
2310  */
2311 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2312 {
2313   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2314   LPITEMIDLIST pidl;
2315   HRESULT hres;
2316
2317   TRACE("\n");
2318
2319   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2320   hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2321   SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2322   COMDLG32_SHFree(pidl);
2323   return SUCCEEDED(hres);
2324 }
2325 /***********************************************************************
2326  *      FILEDLG95_SHELL_Clean
2327  *
2328  * Cleans the memory used by shell objects
2329  */
2330 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2331 {
2332     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2333
2334     TRACE("\n");
2335
2336     COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2337
2338     /* clean Shell interfaces */
2339     if (fodInfos->Shell.FOIShellView)
2340     {
2341       IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2342       IShellView_Release(fodInfos->Shell.FOIShellView);
2343     }
2344     IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2345     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2346     if (fodInfos->Shell.FOIDataObject)
2347       IDataObject_Release(fodInfos->Shell.FOIDataObject);
2348 }
2349
2350 /***********************************************************************
2351  *      FILEDLG95_FILETYPE_Init
2352  *
2353  * Initialisation of the file type combo box
2354  */
2355 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2356 {
2357   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2358   int nFilters = 0;  /* number of filters */
2359   int nFilterIndexCB;
2360
2361   TRACE("\n");
2362
2363   if(fodInfos->customfilter)
2364   {
2365       /* customfilter has one entry...  title\0ext\0
2366        * Set first entry of combo box item with customfilter
2367        */
2368       LPWSTR  lpstrExt;
2369       LPCWSTR lpstrPos = fodInfos->customfilter;
2370
2371       /* Get the title */
2372       lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2373
2374       /* Copy the extensions */
2375       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
2376       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2377       lstrcpyW(lpstrExt,lpstrPos);
2378
2379       /* Add the item at the end of the combo */
2380       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2381       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2382       nFilters++;
2383   }
2384   if(fodInfos->filter)
2385   {
2386     LPCWSTR lpstrPos = fodInfos->filter;
2387
2388     for(;;)
2389     {
2390       /* filter is a list...  title\0ext\0......\0\0
2391        * Set the combo item text to the title and the item data
2392        *  to the ext
2393        */
2394       LPCWSTR lpstrDisplay;
2395       LPWSTR lpstrExt;
2396
2397       /* Get the title */
2398       if(! *lpstrPos) break;    /* end */
2399       lpstrDisplay = lpstrPos;
2400       lpstrPos += lstrlenW(lpstrPos) + 1;
2401
2402       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2403
2404       nFilters++;
2405
2406       /* Copy the extensions */
2407       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2408       lstrcpyW(lpstrExt,lpstrPos);
2409       lpstrPos += lstrlenW(lpstrPos) + 1;
2410
2411       /* Add the item at the end of the combo */
2412       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2413
2414       /* malformed filters are added anyway... */
2415       if (!*lpstrExt) break;
2416     }
2417   }
2418
2419   /*
2420    * Set the current filter to the one specified
2421    * in the initialisation structure
2422    */
2423   if (fodInfos->filter || fodInfos->customfilter)
2424   {
2425     LPWSTR lpstrFilter;
2426
2427     /* Check to make sure our index isn't out of bounds. */
2428     if ( fodInfos->ofnInfos->nFilterIndex >
2429          nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2430       fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2431
2432     /* set default filter index */
2433     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2434       fodInfos->ofnInfos->nFilterIndex = 1;
2435
2436     /* calculate index of Combo Box item */
2437     nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2438     if (fodInfos->customfilter == NULL)
2439       nFilterIndexCB--;
2440
2441     /* Set the current index selection. */
2442     CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2443
2444     /* Get the corresponding text string from the combo box. */
2445     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2446                                              nFilterIndexCB);
2447
2448     if ((INT_PTR)lpstrFilter == CB_ERR)  /* control is empty */
2449       lpstrFilter = NULL;
2450
2451     if(lpstrFilter)
2452     {
2453       DWORD len;
2454       CharLowerW(lpstrFilter); /* lowercase */
2455       len = lstrlenW(lpstrFilter)+1;
2456       fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2457       lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2458     }
2459   } else
2460       fodInfos->ofnInfos->nFilterIndex = 0;
2461   return S_OK;
2462 }
2463
2464 /***********************************************************************
2465  *      FILEDLG95_FILETYPE_OnCommand
2466  *
2467  * WM_COMMAND of the file type combo box
2468  * If the function succeeds, the return value is nonzero.
2469  */
2470 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2471 {
2472   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2473
2474   switch(wNotifyCode)
2475   {
2476     case CBN_SELENDOK:
2477     {
2478       LPWSTR lpstrFilter;
2479
2480       /* Get the current item of the filetype combo box */
2481       int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2482
2483       /* set the current filter index */
2484       fodInfos->ofnInfos->nFilterIndex = iItem +
2485         (fodInfos->customfilter == NULL ? 1 : 0);
2486
2487       /* Set the current filter with the current selection */
2488       MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2489
2490       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2491                                              iItem);
2492       if((INT_PTR)lpstrFilter != CB_ERR)
2493       {
2494           DWORD len;
2495           CharLowerW(lpstrFilter); /* lowercase */
2496           len = lstrlenW(lpstrFilter)+1;
2497           fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2498           lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2499           SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2500       }
2501
2502       /* Refresh the actual view to display the included items*/
2503       if (fodInfos->Shell.FOIShellView)
2504         IShellView_Refresh(fodInfos->Shell.FOIShellView);
2505     }
2506   }
2507   return FALSE;
2508 }
2509 /***********************************************************************
2510  *      FILEDLG95_FILETYPE_SearchExt
2511  *
2512  * searches for an extension in the filetype box
2513  */
2514 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2515 {
2516   int i, iCount = CBGetCount(hwnd);
2517
2518   TRACE("%s\n", debugstr_w(lpstrExt));
2519
2520   if(iCount != CB_ERR)
2521   {
2522     for(i=0;i<iCount;i++)
2523     {
2524       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2525           return i;
2526     }
2527   }
2528   return -1;
2529 }
2530
2531 /***********************************************************************
2532  *      FILEDLG95_FILETYPE_Clean
2533  *
2534  * Clean the memory used by the filetype combo box
2535  */
2536 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2537 {
2538   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2539   int iPos;
2540   int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2541
2542   TRACE("\n");
2543
2544   /* Delete each string of the combo and their associated data */
2545   if(iCount != CB_ERR)
2546   {
2547     for(iPos = iCount-1;iPos>=0;iPos--)
2548     {
2549       MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2550       CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2551     }
2552   }
2553   /* Current filter */
2554   MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2555
2556 }
2557
2558 /***********************************************************************
2559  *      FILEDLG95_LOOKIN_Init
2560  *
2561  * Initialisation of the look in combo box
2562  */
2563
2564 /* Small helper function, to determine if the unixfs shell extension is rooted 
2565  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 
2566  */
2567 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2568     HKEY hKey;
2569     static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2570         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2571         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2572         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2573         'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2574         '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2575         '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2576     
2577     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2578         return FALSE;
2579         
2580     RegCloseKey(hKey);
2581     return TRUE;
2582 }
2583
2584 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2585 {
2586   IShellFolder  *psfRoot, *psfDrives;
2587   IEnumIDList   *lpeRoot, *lpeDrives;
2588   LPITEMIDLIST  pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2589
2590   LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2591
2592   TRACE("\n");
2593
2594   liInfos->iMaxIndentation = 0;
2595
2596   SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2597
2598   /* set item height for both text field and listbox */
2599   CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2600   CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2601    
2602   /* Turn on the extended UI for the combo box like Windows does */
2603   CBSetExtendedUI(hwndCombo, TRUE);
2604
2605   /* Initialise data of Desktop folder */
2606   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2607   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2608   COMDLG32_SHFree(pidlTmp);
2609
2610   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2611
2612   SHGetDesktopFolder(&psfRoot);
2613
2614   if (psfRoot)
2615   {
2616     /* enumerate the contents of the desktop */
2617     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2618     {
2619       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2620       {
2621         FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2622
2623         /* If the unixfs extension is rooted, we don't expand the drives by default */
2624         if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 
2625         {
2626           /* special handling for CSIDL_DRIVES */
2627           if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2628           {
2629             if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2630             {
2631               /* enumerate the drives */
2632               if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2633               {
2634                 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2635                 {
2636                   pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2637                   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2638                   COMDLG32_SHFree(pidlAbsTmp);
2639                   COMDLG32_SHFree(pidlTmp1);
2640                 }
2641                 IEnumIDList_Release(lpeDrives);
2642               }
2643               IShellFolder_Release(psfDrives);
2644             }
2645           }
2646         }
2647
2648         COMDLG32_SHFree(pidlTmp);
2649       }
2650       IEnumIDList_Release(lpeRoot);
2651     }
2652     IShellFolder_Release(psfRoot);
2653   }
2654
2655   COMDLG32_SHFree(pidlDrives);
2656 }
2657
2658 /***********************************************************************
2659  *      FILEDLG95_LOOKIN_DrawItem
2660  *
2661  * WM_DRAWITEM message handler
2662  */
2663 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2664 {
2665   COLORREF crWin = GetSysColor(COLOR_WINDOW);
2666   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2667   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2668   RECT rectText;
2669   RECT rectIcon;
2670   SHFILEINFOW sfi;
2671   HIMAGELIST ilItemImage;
2672   int iIndentation;
2673   TEXTMETRICW tm;
2674   LPSFOLDER tmpFolder;
2675   LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2676
2677   TRACE("\n");
2678
2679   if(pDIStruct->itemID == -1)
2680     return 0;
2681
2682   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2683                             pDIStruct->itemID)))
2684     return 0;
2685
2686
2687   if(pDIStruct->itemID == liInfos->uSelectedItem)
2688   {
2689     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2690                                                0,
2691                                                &sfi,
2692                                                sizeof (sfi),
2693                                                SHGFI_PIDL | SHGFI_SMALLICON |
2694                                                SHGFI_OPENICON | SHGFI_SYSICONINDEX    |
2695                                                SHGFI_DISPLAYNAME );
2696   }
2697   else
2698   {
2699     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2700                                                   0,
2701                                                   &sfi,
2702                                                   sizeof (sfi),
2703                                                   SHGFI_PIDL | SHGFI_SMALLICON |
2704                                                   SHGFI_SYSICONINDEX |
2705                                                   SHGFI_DISPLAYNAME);
2706   }
2707
2708   /* Is this item selected ? */
2709   if(pDIStruct->itemState & ODS_SELECTED)
2710   {
2711     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2712     SetBkColor(pDIStruct->hDC,crHighLight);
2713     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2714   }
2715   else
2716   {
2717     SetTextColor(pDIStruct->hDC,crText);
2718     SetBkColor(pDIStruct->hDC,crWin);
2719     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2720   }
2721
2722   /* Do not indent item if drawing in the edit of the combo */
2723   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2724   {
2725     iIndentation = 0;
2726     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2727                                                 0,
2728                                                 &sfi,
2729                                                 sizeof (sfi),
2730                                                 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2731                                                 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME  );
2732
2733   }
2734   else
2735   {
2736     iIndentation = tmpFolder->m_iIndent;
2737   }
2738   /* Draw text and icon */
2739
2740   /* Initialise the icon display area */
2741   rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2742   rectIcon.top = pDIStruct->rcItem.top;
2743   rectIcon.right = rectIcon.left + ICONWIDTH;
2744   rectIcon.bottom = pDIStruct->rcItem.bottom;
2745
2746   /* Initialise the text display area */
2747   GetTextMetricsW(pDIStruct->hDC, &tm);
2748   rectText.left = rectIcon.right;
2749   rectText.top =
2750           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2751   rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2752   rectText.bottom =
2753           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2754
2755   /* Draw the icon from the image list */
2756   ImageList_Draw(ilItemImage,
2757                  sfi.iIcon,
2758                  pDIStruct->hDC,
2759                  rectIcon.left,
2760                  rectIcon.top,
2761                  ILD_TRANSPARENT );
2762
2763   /* Draw the associated text */
2764   if(sfi.szDisplayName)
2765     TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2766
2767
2768   return NOERROR;
2769 }
2770
2771 /***********************************************************************
2772  *      FILEDLG95_LOOKIN_OnCommand
2773  *
2774  * LookIn combo box WM_COMMAND message handler
2775  * If the function succeeds, the return value is nonzero.
2776  */
2777 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2778 {
2779   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2780
2781   TRACE("%p\n", fodInfos);
2782
2783   switch(wNotifyCode)
2784   {
2785     case CBN_SELENDOK:
2786     {
2787       LPSFOLDER tmpFolder;
2788       int iItem;
2789
2790       iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2791
2792       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2793                                                iItem)))
2794         return FALSE;
2795
2796
2797       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2798                                               tmpFolder->pidlItem,
2799                                               SBSP_ABSOLUTE)))
2800       {
2801         SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2802         return TRUE;
2803       }
2804       break;
2805     }
2806
2807   }
2808   return FALSE;
2809 }
2810
2811 /***********************************************************************
2812  *      FILEDLG95_LOOKIN_AddItem
2813  *
2814  * Adds an absolute pidl item to the lookin combo box
2815  * returns the index of the inserted item
2816  */
2817 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2818 {
2819   LPITEMIDLIST pidlNext;
2820   SHFILEINFOW sfi;
2821   SFOLDER *tmpFolder;
2822   LookInInfos *liInfos;
2823
2824   TRACE("%08x\n", iInsertId);
2825
2826   if(!pidl)
2827     return -1;
2828
2829   if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
2830     return -1;
2831
2832   tmpFolder = MemAlloc(sizeof(SFOLDER));
2833   tmpFolder->m_iIndent = 0;
2834
2835   /* Calculate the indentation of the item in the lookin*/
2836   pidlNext = pidl;
2837   while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2838   {
2839     tmpFolder->m_iIndent++;
2840   }
2841
2842   tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2843
2844   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2845     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2846
2847   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2848   SHGetFileInfoW((LPCWSTR)pidl,
2849                   0,
2850                   &sfi,
2851                   sizeof(sfi),
2852                   SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2853                   | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2854
2855   TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2856
2857   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2858   {
2859     int iItemID;
2860
2861     TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2862
2863     /* Add the item at the end of the list */
2864     if(iInsertId < 0)
2865     {
2866       iItemID = CBAddString(hwnd,sfi.szDisplayName);
2867     }
2868     /* Insert the item at the iInsertId position*/
2869     else
2870     {
2871       iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2872     }
2873
2874     CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2875     return iItemID;
2876   }
2877
2878   COMDLG32_SHFree( tmpFolder->pidlItem );
2879   MemFree( tmpFolder );
2880   return -1;
2881
2882 }
2883
2884 /***********************************************************************
2885  *      FILEDLG95_LOOKIN_InsertItemAfterParent
2886  *
2887  * Insert an item below its parent
2888  */
2889 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2890 {
2891
2892   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2893   int iParentPos;
2894
2895   TRACE("\n");
2896
2897   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2898
2899   if(iParentPos < 0)
2900   {
2901     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2902   }
2903
2904   /* Free pidlParent memory */
2905   COMDLG32_SHFree((LPVOID)pidlParent);
2906
2907   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2908 }
2909
2910 /***********************************************************************
2911  *      FILEDLG95_LOOKIN_SelectItem
2912  *
2913  * Adds an absolute pidl item to the lookin combo box
2914  * returns the index of the inserted item
2915  */
2916 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2917 {
2918   int iItemPos;
2919   LookInInfos *liInfos;
2920
2921   TRACE("\n");
2922
2923   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2924
2925   liInfos = GetPropA(hwnd,LookInInfosStr);
2926
2927   if(iItemPos < 0)
2928   {
2929     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2930     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2931   }
2932
2933   else
2934   {
2935     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2936     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2937     {
2938       int iRemovedItem;
2939
2940       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2941         break;
2942       if(iRemovedItem < iItemPos)
2943         iItemPos--;
2944     }
2945   }
2946
2947   CBSetCurSel(hwnd,iItemPos);
2948   liInfos->uSelectedItem = iItemPos;
2949
2950   return 0;
2951
2952 }
2953
2954 /***********************************************************************
2955  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
2956  *
2957  * Remove the item with an expansion level over iExpansionLevel
2958  */
2959 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2960 {
2961   int iItemPos;
2962   LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
2963
2964   TRACE("\n");
2965
2966   if(liInfos->iMaxIndentation <= 2)
2967     return -1;
2968
2969   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2970   {
2971     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2972     COMDLG32_SHFree(tmpFolder->pidlItem);
2973     MemFree(tmpFolder);
2974     CBDeleteString(hwnd,iItemPos);
2975     liInfos->iMaxIndentation--;
2976
2977     return iItemPos;
2978   }
2979
2980   return -1;
2981 }
2982
2983 /***********************************************************************
2984  *      FILEDLG95_LOOKIN_SearchItem
2985  *
2986  * Search for pidl in the lookin combo box
2987  * returns the index of the found item
2988  */
2989 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2990 {
2991   int i = 0;
2992   int iCount = CBGetCount(hwnd);
2993
2994   TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
2995
2996   if (iCount != CB_ERR)
2997   {
2998     for(;i<iCount;i++)
2999     {
3000       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3001
3002       if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3003         return i;
3004       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3005         return i;
3006     }
3007   }
3008
3009   return -1;
3010 }
3011
3012 /***********************************************************************
3013  *      FILEDLG95_LOOKIN_Clean
3014  *
3015  * Clean the memory used by the lookin combo box
3016  */
3017 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3018 {
3019     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3020     int iPos;
3021     int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3022
3023     TRACE("\n");
3024
3025     /* Delete each string of the combo and their associated data */
3026     if (iCount != CB_ERR)
3027     {
3028       for(iPos = iCount-1;iPos>=0;iPos--)
3029       {
3030         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3031         COMDLG32_SHFree(tmpFolder->pidlItem);
3032         MemFree(tmpFolder);
3033         CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3034       }
3035     }
3036
3037     /* LookInInfos structure */
3038     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3039
3040 }
3041 /***********************************************************************
3042  * FILEDLG95_FILENAME_FillFromSelection
3043  *
3044  * fills the edit box from the cached DataObject
3045  */
3046 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3047 {
3048     FileOpenDlgInfos *fodInfos;
3049     LPITEMIDLIST      pidl;
3050     UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3051     WCHAR             lpstrTemp[MAX_PATH];
3052     LPWSTR            lpstrAllFile, lpstrCurrFile;
3053
3054     TRACE("\n");
3055     fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3056
3057     /* Count how many files we have */
3058     nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3059
3060     /* calculate the string length, count files */
3061     if (nFileSelected >= 1)
3062     {
3063       nLength += 3;     /* first and last quotes, trailing \0 */
3064       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3065       {
3066         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3067
3068         if (pidl)
3069         {
3070           /* get the total length of the selected file names */
3071           lpstrTemp[0] = '\0';
3072           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3073
3074           if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3075           {
3076             nLength += lstrlenW( lpstrTemp ) + 3;
3077             nFiles++;
3078           }
3079           COMDLG32_SHFree( pidl );
3080         }
3081       }
3082     }
3083
3084     /* allocate the buffer */
3085     if (nFiles <= 1) nLength = MAX_PATH;
3086     lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3087
3088     /* Generate the string for the edit control */
3089     if(nFiles >= 1)
3090     {
3091       lpstrCurrFile = lpstrAllFile;
3092       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3093       {
3094         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3095
3096         if (pidl)
3097         {
3098           /* get the file name */
3099           lpstrTemp[0] = '\0';
3100           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3101
3102           if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3103           {
3104             if ( nFiles > 1)
3105             {
3106               *lpstrCurrFile++ =  '\"';
3107               lstrcpyW( lpstrCurrFile, lpstrTemp );
3108               lpstrCurrFile += lstrlenW( lpstrTemp );
3109               *lpstrCurrFile++ = '\"';
3110               *lpstrCurrFile++ = ' ';
3111               *lpstrCurrFile = 0;
3112             }
3113             else
3114             {
3115               lstrcpyW( lpstrAllFile, lpstrTemp );
3116             }
3117           }
3118           COMDLG32_SHFree( (LPVOID) pidl );
3119         }
3120       }
3121       SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3122        
3123       /* Select the file name like Windows does */ 
3124       SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3125     }
3126     HeapFree(GetProcessHeap(),0, lpstrAllFile );
3127 }
3128
3129
3130 /* copied from shell32 to avoid linking to it
3131  * Although shell32 is already linked the behaviour of exported StrRetToStrN
3132  * is dependent on whether emulated OS is unicode or not.
3133  */
3134 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3135 {
3136         switch (src->uType)
3137         {
3138           case STRRET_WSTR:
3139             lstrcpynW(dest, src->u.pOleStr, len);
3140             COMDLG32_SHFree(src->u.pOleStr);
3141             break;
3142
3143           case STRRET_CSTR:
3144             if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3145                   dest[len-1] = 0;
3146             break;
3147
3148           case STRRET_OFFSET:
3149             if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3150                   dest[len-1] = 0;
3151             break;
3152
3153           default:
3154             FIXME("unknown type %x!\n", src->uType);
3155             if (len) *dest = '\0';
3156             return E_FAIL;
3157         }
3158         return S_OK;
3159 }
3160
3161 /***********************************************************************
3162  * FILEDLG95_FILENAME_GetFileNames
3163  *
3164  * Copies the filenames to a delimited string list.
3165  * The delimiter is specified by the parameter 'separator',
3166  *  usually either a space or a nul
3167  */
3168 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3169 {
3170         FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3171         UINT nStrCharCount = 0; /* index in src buffer */
3172         UINT nFileIndex = 0;    /* index in dest buffer */
3173         UINT nFileCount = 0;    /* number of files */
3174         UINT nStrLen = 0;       /* length of string in edit control */
3175         LPWSTR lpstrEdit;       /* buffer for string from edit control */
3176
3177         TRACE("\n");
3178
3179         /* get the filenames from the edit control */
3180         nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3181         lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3182         GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3183
3184         TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3185
3186         /* we might get single filename without any '"',
3187          * so we need nStrLen + terminating \0 + end-of-list \0 */
3188         *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3189         *sizeUsed = 0;
3190
3191         /* build delimited file list from filenames */
3192         while ( nStrCharCount <= nStrLen )
3193         {
3194           if ( lpstrEdit[nStrCharCount]=='"' )
3195           {
3196             nStrCharCount++;
3197             while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3198             {
3199               (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3200               nStrCharCount++;
3201             }
3202             (*lpstrFileList)[nFileIndex++] = 0;
3203             nFileCount++;
3204           }
3205           nStrCharCount++;
3206         }
3207
3208         /* single, unquoted string */
3209         if ((nStrLen > 0) && (nFileIndex == 0) )
3210         {
3211           lstrcpyW(*lpstrFileList, lpstrEdit);
3212           nFileIndex = lstrlenW(lpstrEdit) + 1;
3213           nFileCount = 1;
3214         }
3215
3216         /* trailing \0 */
3217         (*lpstrFileList)[nFileIndex++] = '\0';
3218
3219         *sizeUsed = nFileIndex;
3220         MemFree(lpstrEdit);
3221         return nFileCount;
3222 }
3223
3224 #define SETDefFormatEtc(fe,cf,med) \
3225 { \
3226     (fe).cfFormat = cf;\
3227     (fe).dwAspect = DVASPECT_CONTENT; \
3228     (fe).ptd =NULL;\
3229     (fe).tymed = med;\
3230     (fe).lindex = -1;\
3231 };
3232
3233 /*
3234  * DATAOBJECT Helper functions
3235  */
3236
3237 /***********************************************************************
3238  * COMCTL32_ReleaseStgMedium
3239  *
3240  * like ReleaseStgMedium from ole32
3241  */
3242 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3243 {
3244       if(medium.pUnkForRelease)
3245       {
3246         IUnknown_Release(medium.pUnkForRelease);
3247       }
3248       else
3249       {
3250         GlobalUnlock(medium.u.hGlobal);
3251         GlobalFree(medium.u.hGlobal);
3252       }
3253 }
3254
3255 /***********************************************************************
3256  *          GetPidlFromDataObject
3257  *
3258  * Return pidl(s) by number from the cached DataObject
3259  *
3260  * nPidlIndex=0 gets the fully qualified root path
3261  */
3262 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3263 {
3264
3265     STGMEDIUM medium;
3266     FORMATETC formatetc;
3267     LPITEMIDLIST pidl = NULL;
3268
3269     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3270
3271     if (!doSelected)
3272         return NULL;
3273         
3274     /* Set the FORMATETC structure*/
3275     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3276
3277     /* Get the pidls from IDataObject */
3278     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3279     {
3280       LPIDA cida = GlobalLock(medium.u.hGlobal);
3281       if(nPidlIndex <= cida->cidl)
3282       {
3283         pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3284       }
3285       COMCTL32_ReleaseStgMedium(medium);
3286     }
3287     return pidl;
3288 }
3289
3290 /***********************************************************************
3291  *          GetNumSelected
3292  *
3293  * Return the number of selected items in the DataObject.
3294  *
3295 */
3296 static UINT GetNumSelected( IDataObject *doSelected )
3297 {
3298     UINT retVal = 0;
3299     STGMEDIUM medium;
3300     FORMATETC formatetc;
3301
3302     TRACE("sv=%p\n", doSelected);
3303
3304     if (!doSelected) return 0;
3305
3306     /* Set the FORMATETC structure*/
3307     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3308
3309     /* Get the pidls from IDataObject */
3310     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3311     {
3312       LPIDA cida = GlobalLock(medium.u.hGlobal);
3313       retVal = cida->cidl;
3314       COMCTL32_ReleaseStgMedium(medium);
3315       return retVal;
3316     }
3317     return 0;
3318 }
3319
3320 /*
3321  * TOOLS
3322  */
3323
3324 /***********************************************************************
3325  *      GetName
3326  *
3327  * Get the pidl's display name (relative to folder) and
3328  * put it in lpstrFileName.
3329  *
3330  * Return NOERROR on success,
3331  * E_FAIL otherwise
3332  */
3333
3334 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3335 {
3336   STRRET str;
3337   HRESULT hRes;
3338
3339   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3340
3341   if(!lpsf)
3342   {
3343     SHGetDesktopFolder(&lpsf);
3344     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3345     IShellFolder_Release(lpsf);
3346     return hRes;
3347   }
3348
3349   /* Get the display name of the pidl relative to the folder */
3350   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3351   {
3352       return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3353   }
3354   return E_FAIL;
3355 }
3356
3357 /***********************************************************************
3358  *      GetShellFolderFromPidl
3359  *
3360  * pidlRel is the item pidl relative
3361  * Return the IShellFolder of the absolute pidl
3362  */
3363 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3364 {
3365   IShellFolder *psf = NULL,*psfParent;
3366
3367   TRACE("%p\n", pidlAbs);
3368
3369   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3370   {
3371     psf = psfParent;
3372     if(pidlAbs && pidlAbs->mkid.cb)
3373     {
3374       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3375       {
3376         IShellFolder_Release(psfParent);
3377         return psf;
3378       }
3379     }
3380     /* return the desktop */
3381     return psfParent;
3382   }
3383   return NULL;
3384 }
3385
3386 /***********************************************************************
3387  *      GetParentPidl
3388  *
3389  * Return the LPITEMIDLIST to the parent of the pidl in the list
3390  */
3391 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3392 {
3393   LPITEMIDLIST pidlParent;
3394
3395   TRACE("%p\n", pidl);
3396
3397   pidlParent = COMDLG32_PIDL_ILClone(pidl);
3398   COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3399
3400   return pidlParent;
3401 }
3402
3403 /***********************************************************************
3404  *      GetPidlFromName
3405  *
3406  * returns the pidl of the file name relative to folder
3407  * NULL if an error occurred
3408  */
3409 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3410 {
3411   LPITEMIDLIST pidl = NULL;
3412   ULONG ulEaten;
3413
3414   TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3415
3416   if(!lpcstrFileName) return NULL;
3417   if(!*lpcstrFileName) return NULL;
3418
3419   if(!lpsf)
3420   {
3421     if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3422         IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3423         IShellFolder_Release(lpsf);
3424     }
3425   }
3426   else
3427   {
3428     IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3429   }
3430   return pidl;
3431 }
3432
3433 /*
3434 */
3435 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3436 {
3437         ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3438         HRESULT ret;
3439
3440         TRACE("%p, %p\n", psf, pidl);
3441
3442         ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3443
3444         TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3445         /* see documentation shell 4.1*/
3446         return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3447 }
3448
3449 /***********************************************************************
3450  *      BrowseSelectedFolder
3451  */
3452 static BOOL BrowseSelectedFolder(HWND hwnd)
3453 {
3454   BOOL bBrowseSelFolder = FALSE;
3455   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3456
3457   TRACE("\n");
3458
3459   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3460   {
3461       LPITEMIDLIST pidlSelection;
3462
3463       /* get the file selected */
3464       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3465       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3466       {
3467           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3468                          pidlSelection, SBSP_RELATIVE ) ) )
3469           {
3470                static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3471                                    ' ','n','o','t',' ','e','x','i','s','t',0};
3472                MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3473           }
3474           bBrowseSelFolder = TRUE;
3475           SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3476       }
3477       COMDLG32_SHFree( pidlSelection );
3478   }
3479
3480   return bBrowseSelFolder;
3481 }
3482
3483 /*
3484  * Memory allocation methods */
3485 static void *MemAlloc(UINT size)
3486 {
3487     return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3488 }
3489
3490 static void MemFree(void *mem)
3491 {
3492     HeapFree(GetProcessHeap(),0,mem);
3493 }
3494
3495 /*
3496  * Old-style (win3.1) dialogs */
3497
3498 /***********************************************************************
3499  *           FD32_GetTemplate                                  [internal]
3500  *
3501  * Get a template (or FALSE if failure) when 16 bits dialogs are used
3502  * by a 32 bits application
3503  *
3504  */
3505 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3506 {
3507     LPOPENFILENAMEW ofnW = lfs->ofnW;
3508     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3509     HANDLE hDlgTmpl;
3510
3511     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3512     {
3513         if (!(lfs->template = LockResource( ofnW->hInstance )))
3514         {
3515             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3516             return FALSE;
3517         }
3518     }
3519     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3520     {
3521         HRSRC hResInfo;
3522         if (priv->ofnA)
3523             hResInfo = FindResourceA(priv->ofnA->hInstance,
3524                                  priv->ofnA->lpTemplateName,
3525                                  (LPSTR)RT_DIALOG);
3526         else
3527             hResInfo = FindResourceW(ofnW->hInstance,
3528                                  ofnW->lpTemplateName,
3529                                  (LPWSTR)RT_DIALOG);
3530         if (!hResInfo)
3531         {
3532             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3533             return FALSE;
3534         }
3535         if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3536                                 hResInfo)) ||
3537                     !(lfs->template = LockResource(hDlgTmpl)))
3538         {
3539             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3540             return FALSE;
3541         }
3542     } else { /* get it from internal Wine resource */
3543         HRSRC hResInfo;
3544         if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3545              lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3546         {
3547             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3548             return FALSE;
3549         }
3550         if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3551                 !(lfs->template = LockResource( hDlgTmpl )))
3552         {
3553             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3554             return FALSE;
3555         }
3556     }
3557     return TRUE;
3558 }
3559
3560
3561 /************************************************************************
3562  *                              FD32_Init          [internal]
3563  *      called from the common 16/32 code to initialize 32 bit data
3564  */
3565 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3566 {
3567     BOOL IsUnicode = (BOOL) data;
3568     PFD32_PRIVATE priv;
3569
3570     priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3571     lfs->private1632 = priv;
3572     if (NULL == lfs->private1632) return FALSE;
3573     if (IsUnicode)
3574     {
3575         lfs->ofnW = (LPOPENFILENAMEW) lParam;
3576         if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3577             if (lfs->ofnW->lpfnHook)
3578                 lfs->hook = TRUE;
3579     }
3580     else
3581     {
3582         priv->ofnA = (LPOPENFILENAMEA) lParam;
3583         if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3584             if (priv->ofnA->lpfnHook)
3585                 lfs->hook = TRUE;
3586         lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3587         FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3588     }
3589
3590     if (! FD32_GetTemplate(lfs)) return FALSE;
3591
3592     return TRUE;
3593 }
3594
3595 /***********************************************************************
3596  *                              FD32_CallWindowProc          [internal]
3597  *
3598  *      called from the common 16/32 code to call the appropriate hook
3599  */
3600 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3601                                  LPARAM lParam)
3602 {
3603     BOOL ret;
3604     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3605
3606     if (priv->ofnA)
3607     {
3608         TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3609                priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3610         ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3611         TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3612                priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3613         return ret;
3614     }
3615
3616     TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3617            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3618     ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3619     TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3620            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3621     return ret;
3622 }
3623
3624 /***********************************************************************
3625  *                              FD32_UpdateResult            [internal]
3626  *          update the real client structures if any
3627  */
3628 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3629 {
3630     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3631     LPOPENFILENAMEW ofnW = lfs->ofnW;
3632
3633     if (priv->ofnA)
3634     {
3635         LPSTR lpszTemp;
3636         if (ofnW->nMaxFile &&
3637             !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3638                                   priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3639             priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3640
3641         /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3642         /* set filename offset */
3643         lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3644         priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3645
3646         /* set extension offset */
3647         lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3648         priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3649     }
3650 }
3651
3652 /***********************************************************************
3653  *                              FD32_UpdateFileTitle            [internal]
3654  *          update the real client structures if any
3655  */
3656 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3657 {
3658     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3659     LPOPENFILENAMEW ofnW = lfs->ofnW;
3660
3661     if (priv->ofnA)
3662     {
3663         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3664                                   priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3665             priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3666     }
3667 }
3668
3669
3670 /***********************************************************************
3671  *                              FD32_SendLbGetCurSel         [internal]
3672  *          retrieve selected listbox item
3673  */
3674 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3675 {
3676     return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3677 }
3678
3679
3680 /************************************************************************
3681  *                              FD32_Destroy          [internal]
3682  *      called from the common 16/32 code to cleanup 32 bit data
3683  */
3684 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3685 {
3686     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3687
3688     /* if ofnW has been allocated, have to free everything in it */
3689     if (NULL != priv && NULL != priv->ofnA)
3690     {
3691         FD31_FreeOfnW(lfs->ofnW);
3692         HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3693     }
3694 }
3695
3696 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3697 {
3698     callbacks->Init = FD32_Init;
3699     callbacks->CWP = FD32_CallWindowProc;
3700     callbacks->UpdateResult = FD32_UpdateResult;
3701     callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3702     callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3703     callbacks->Destroy = FD32_Destroy;
3704 }
3705
3706 /***********************************************************************
3707  *                              FD32_WMMeasureItem           [internal]
3708  */
3709 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3710 {
3711     LPMEASUREITEMSTRUCT lpmeasure;
3712
3713     lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3714     lpmeasure->itemHeight = FD31_GetFldrHeight();
3715     return TRUE;
3716 }
3717
3718
3719 /***********************************************************************
3720  *           FileOpenDlgProc                                    [internal]
3721  *      Used for open and save, in fact.
3722  */
3723 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3724                                              WPARAM wParam, LPARAM lParam)
3725 {
3726     PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3727
3728     TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3729     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3730         {
3731             INT_PTR lRet;
3732             lRet  = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3733             if (lRet)
3734                 return lRet;         /* else continue message processing */
3735         }
3736     switch (wMsg)
3737     {
3738     case WM_INITDIALOG:
3739         return FD31_WMInitDialog(hWnd, wParam, lParam);
3740
3741     case WM_MEASUREITEM:
3742         return FD32_WMMeasureItem(hWnd, wParam, lParam);
3743
3744     case WM_DRAWITEM:
3745         return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3746
3747     case WM_COMMAND:
3748         return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3749 #if 0
3750     case WM_CTLCOLOR:
3751          SetBkColor((HDC16)wParam, 0x00C0C0C0);
3752          switch (HIWORD(lParam))
3753          {
3754          case CTLCOLOR_BTN:
3755              SetTextColor((HDC16)wParam, 0x00000000);
3756              return hGRAYBrush;
3757         case CTLCOLOR_STATIC:
3758              SetTextColor((HDC16)wParam, 0x00000000);
3759              return hGRAYBrush;
3760         }
3761       break;
3762 #endif
3763     }
3764     return FALSE;
3765 }
3766
3767
3768 /***********************************************************************
3769  *           GetFileName31A                                 [internal]
3770  *
3771  * Creates a win31 style dialog box for the user to select a file to open/save.
3772  */
3773 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3774                            UINT dlgType /* type dialogue : open/save */
3775                            )
3776 {
3777     HINSTANCE hInst;
3778     BOOL bRet = FALSE;
3779     PFD31_DATA lfs;
3780     FD31_CALLBACKS callbacks;
3781
3782     if (!lpofn || !FD31_Init()) return FALSE;
3783
3784     TRACE("ofn flags %08x\n", lpofn->Flags);
3785     FD32_SetupCallbacks(&callbacks);
3786     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3787     if (lfs)
3788     {
3789         hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3790         bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3791                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
3792         FD31_DestroyPrivate(lfs);
3793     }
3794
3795     TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3796     return bRet;
3797 }
3798
3799 /***********************************************************************
3800  *           GetFileName31W                                 [internal]
3801  *
3802  * Creates a win31 style dialog box for the user to select a file to open/save
3803  */
3804 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3805                            UINT dlgType /* type dialogue : open/save */
3806                            )
3807 {
3808     HINSTANCE hInst;
3809     BOOL bRet = FALSE;
3810     PFD31_DATA lfs;
3811     FD31_CALLBACKS callbacks;
3812
3813     if (!lpofn || !FD31_Init()) return FALSE;
3814
3815     FD32_SetupCallbacks(&callbacks);
3816     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3817     if (lfs)
3818     {
3819         hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3820         bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3821                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
3822         FD31_DestroyPrivate(lfs);
3823     }
3824
3825     TRACE("file %s, file offset %d, ext offset %d\n",
3826           debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3827     return bRet;
3828 }
3829
3830 /* ------------------ APIs ---------------------- */
3831
3832 /***********************************************************************
3833  *            GetOpenFileNameA  (COMDLG32.@)
3834  *
3835  * Creates a dialog box for the user to select a file to open.
3836  *
3837  * RETURNS
3838  *    TRUE on success: user enters a valid file
3839  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3840  *
3841  */
3842 BOOL WINAPI GetOpenFileNameA(
3843         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3844 {
3845     BOOL win16look = FALSE;
3846
3847     TRACE("flags %08x\n", ofn->Flags);
3848
3849     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3850     if (ofn->Flags & OFN_FILEMUSTEXIST)
3851         ofn->Flags |= OFN_PATHMUSTEXIST;
3852
3853     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3854         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3855
3856     if (win16look)
3857         return GetFileName31A(ofn, OPEN_DIALOG);
3858     else
3859         return GetFileDialog95A(ofn, OPEN_DIALOG);
3860 }
3861
3862 /***********************************************************************
3863  *            GetOpenFileNameW (COMDLG32.@)
3864  *
3865  * Creates a dialog box for the user to select a file to open.
3866  *
3867  * RETURNS
3868  *    TRUE on success: user enters a valid file
3869  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3870  *
3871  */
3872 BOOL WINAPI GetOpenFileNameW(
3873         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3874 {
3875     BOOL win16look = FALSE;
3876
3877     TRACE("flags %08x\n", ofn->Flags);
3878
3879     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3880     if (ofn->Flags & OFN_FILEMUSTEXIST)
3881         ofn->Flags |= OFN_PATHMUSTEXIST;
3882
3883     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3884         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3885
3886     if (win16look)
3887         return GetFileName31W(ofn, OPEN_DIALOG);
3888     else
3889         return GetFileDialog95W(ofn, OPEN_DIALOG);
3890 }
3891
3892
3893 /***********************************************************************
3894  *            GetSaveFileNameA  (COMDLG32.@)
3895  *
3896  * Creates a dialog box for the user to select a file to save.
3897  *
3898  * RETURNS
3899  *    TRUE on success: user enters a valid file
3900  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3901  *
3902  */
3903 BOOL WINAPI GetSaveFileNameA(
3904         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3905 {
3906     BOOL win16look = FALSE;
3907
3908     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3909         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3910
3911     if (win16look)
3912         return GetFileName31A(ofn, SAVE_DIALOG);
3913     else
3914         return GetFileDialog95A(ofn, SAVE_DIALOG);
3915 }
3916
3917 /***********************************************************************
3918  *            GetSaveFileNameW  (COMDLG32.@)
3919  *
3920  * Creates a dialog box for the user to select a file to save.
3921  *
3922  * RETURNS
3923  *    TRUE on success: user enters a valid file
3924  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3925  *
3926  */
3927 BOOL WINAPI GetSaveFileNameW(
3928         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3929 {
3930     BOOL win16look = FALSE;
3931
3932     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3933         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3934
3935     if (win16look)
3936         return GetFileName31W(ofn, SAVE_DIALOG);
3937     else
3938         return GetFileDialog95W(ofn, SAVE_DIALOG);
3939 }
3940
3941 /***********************************************************************
3942  *      GetFileTitleA           (COMDLG32.@)
3943  *
3944  * See GetFileTitleW.
3945  */
3946 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3947 {
3948     int ret;
3949     UNICODE_STRING strWFile;
3950     LPWSTR lpWTitle;
3951
3952     RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3953     lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3954     ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3955     if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3956     RtlFreeUnicodeString( &strWFile );
3957     RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3958     return ret;
3959 }
3960
3961
3962 /***********************************************************************
3963  *      GetFileTitleW           (COMDLG32.@)
3964  *
3965  * Get the name of a file.
3966  *
3967  * PARAMS
3968  *  lpFile  [I] name and location of file
3969  *  lpTitle [O] returned file name
3970  *  cbBuf   [I] buffer size of lpTitle
3971  *
3972  * RETURNS
3973  *  Success: zero
3974  *  Failure: negative number.
3975  */
3976 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
3977 {
3978         int i, len;
3979         static const WCHAR brkpoint[] = {'*','[',']',0};
3980         TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
3981
3982         if(lpFile == NULL || lpTitle == NULL)
3983                 return -1;
3984
3985         len = lstrlenW(lpFile);
3986
3987         if (len == 0)
3988                 return -1;
3989
3990         if(strpbrkW(lpFile, brkpoint))
3991                 return -1;
3992
3993         len--;
3994
3995         if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
3996                 return -1;
3997
3998         for(i = len; i >= 0; i--)
3999         {
4000                 if (lpFile[i] == '/' ||  lpFile[i] == '\\' ||  lpFile[i] == ':')
4001                 {
4002                         i++;
4003                         break;
4004                 }
4005         }
4006
4007         if(i == -1)
4008                 i++;
4009
4010         TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4011
4012         len = lstrlenW(lpFile+i)+1;
4013         if(cbBuf < len)
4014                 return len;
4015
4016         lstrcpyW(lpTitle, &lpFile[i]);
4017         return 0;
4018 }