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