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