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