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