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