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