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