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