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