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