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