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