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