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