comdlg32: Fix memory leak in colour dialog.
[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 specified 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
2144           /* fill destination buffer */
2145           if (fodInfos->ofnInfos->lpstrFile)
2146           {
2147              if(fodInfos->unicode)
2148              {
2149                LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2150
2151                lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2152                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2153                  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2154              }
2155              else
2156              {
2157                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2158
2159                WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2160                                    ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2161                if (ofn->Flags & OFN_ALLOWMULTISELECT)
2162                  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2163              }
2164           }
2165
2166           if(fodInfos->unicode)
2167           {
2168               LPWSTR lpszTemp;
2169
2170               /* set filename offset */
2171               lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2172               fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2173
2174               /* set extension offset */
2175               lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2176               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2177           }
2178           else
2179           {
2180                LPSTR lpszTemp;
2181                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2182
2183               /* set filename offset */
2184               lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2185               fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2186
2187               /* set extension offset */
2188               lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2189               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2190           }
2191
2192           /* set the lpstrFileTitle */
2193           if(fodInfos->ofnInfos->lpstrFileTitle)
2194           {
2195             LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2196             if(fodInfos->unicode)
2197             {
2198               LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2199               lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2200             }
2201             else
2202             {
2203               LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2204               WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2205                     ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2206             }
2207           }
2208
2209           /* copy currently selected filter to lpstrCustomFilter */
2210           if (fodInfos->ofnInfos->lpstrCustomFilter)
2211           {
2212             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2213             int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2214                                           NULL, 0, NULL, NULL);
2215             if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2216             {
2217               LPSTR s = ofn->lpstrCustomFilter;
2218               s += strlen(ofn->lpstrCustomFilter)+1;
2219               WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2220                                   s, len, NULL, NULL);
2221             }
2222           }
2223
2224
2225           if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2226               goto ret;
2227
2228           TRACE("close\n");
2229           FILEDLG95_Clean(hwnd);
2230           ret = EndDialog(hwnd, TRUE);
2231         }
2232         else
2233         {
2234           WORD size;
2235
2236           size = lstrlenW(lpstrPathAndFile) + 1;
2237           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2238              size += 1;
2239           /* return needed size in first two bytes of lpstrFile */
2240           *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2241           FILEDLG95_Clean(hwnd);
2242           ret = EndDialog(hwnd, FALSE);
2243           COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2244         }
2245         goto ret;
2246       }
2247       break;
2248   }
2249
2250 ret:
2251   if(lpsf) IShellFolder_Release(lpsf);
2252   return ret;
2253 }
2254
2255 /***********************************************************************
2256  *      FILEDLG95_SHELL_Init
2257  *
2258  * Initialisation of the shell objects
2259  */
2260 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2261 {
2262   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2263
2264   TRACE("\n");
2265
2266   /*
2267    * Initialisation of the FileOpenDialogInfos structure
2268    */
2269
2270   /* Shell */
2271
2272   /*ShellInfos */
2273   fodInfos->ShellInfos.hwndOwner = hwnd;
2274
2275   /* Disable multi-select if flag not set */
2276   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2277   {
2278      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2279   }
2280   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2281   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2282
2283   /* Construct the IShellBrowser interface */
2284   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2285
2286   return NOERROR;
2287 }
2288
2289 /***********************************************************************
2290  *      FILEDLG95_SHELL_ExecuteCommand
2291  *
2292  * Change the folder option and refresh the view
2293  * If the function succeeds, the return value is nonzero.
2294  */
2295 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2296 {
2297   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2298
2299   IContextMenu * pcm;
2300   TRACE("(%p,%p)\n", hwnd, lpVerb);
2301
2302   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2303                                         SVGIO_BACKGROUND,
2304                                         &IID_IContextMenu,
2305                                         (LPVOID*)&pcm)))
2306   {
2307     CMINVOKECOMMANDINFO ci;
2308     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2309     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2310     ci.lpVerb = lpVerb;
2311     ci.hwnd = hwnd;
2312
2313     IContextMenu_InvokeCommand(pcm, &ci);
2314     IContextMenu_Release(pcm);
2315   }
2316
2317   return FALSE;
2318 }
2319
2320 /***********************************************************************
2321  *      FILEDLG95_SHELL_UpFolder
2322  *
2323  * Browse to the specified object
2324  * If the function succeeds, the return value is nonzero.
2325  */
2326 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2327 {
2328   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2329
2330   TRACE("\n");
2331
2332   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2333                                           NULL,
2334                                           SBSP_PARENT)))
2335   {
2336     SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2337     return TRUE;
2338   }
2339   return FALSE;
2340 }
2341
2342 /***********************************************************************
2343  *      FILEDLG95_SHELL_BrowseToDesktop
2344  *
2345  * Browse to the Desktop
2346  * If the function succeeds, the return value is nonzero.
2347  */
2348 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2349 {
2350   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2351   LPITEMIDLIST pidl;
2352   HRESULT hres;
2353
2354   TRACE("\n");
2355
2356   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2357   hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2358   SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2359   COMDLG32_SHFree(pidl);
2360   return SUCCEEDED(hres);
2361 }
2362 /***********************************************************************
2363  *      FILEDLG95_SHELL_Clean
2364  *
2365  * Cleans the memory used by shell objects
2366  */
2367 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2368 {
2369     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2370
2371     TRACE("\n");
2372
2373     COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2374
2375     /* clean Shell interfaces */
2376     if (fodInfos->Shell.FOIShellView)
2377     {
2378       IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2379       IShellView_Release(fodInfos->Shell.FOIShellView);
2380     }
2381     IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2382     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2383     if (fodInfos->Shell.FOIDataObject)
2384       IDataObject_Release(fodInfos->Shell.FOIDataObject);
2385 }
2386
2387 /***********************************************************************
2388  *      FILEDLG95_FILETYPE_Init
2389  *
2390  * Initialisation of the file type combo box
2391  */
2392 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2393 {
2394   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2395   int nFilters = 0;  /* number of filters */
2396   int nFilterIndexCB;
2397
2398   TRACE("\n");
2399
2400   if(fodInfos->customfilter)
2401   {
2402       /* customfilter has one entry...  title\0ext\0
2403        * Set first entry of combo box item with customfilter
2404        */
2405       LPWSTR  lpstrExt;
2406       LPCWSTR lpstrPos = fodInfos->customfilter;
2407
2408       /* Get the title */
2409       lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2410
2411       /* Copy the extensions */
2412       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
2413       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2414       lstrcpyW(lpstrExt,lpstrPos);
2415
2416       /* Add the item at the end of the combo */
2417       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2418       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2419       nFilters++;
2420   }
2421   if(fodInfos->filter)
2422   {
2423     LPCWSTR lpstrPos = fodInfos->filter;
2424
2425     for(;;)
2426     {
2427       /* filter is a list...  title\0ext\0......\0\0
2428        * Set the combo item text to the title and the item data
2429        *  to the ext
2430        */
2431       LPCWSTR lpstrDisplay;
2432       LPWSTR lpstrExt;
2433
2434       /* Get the title */
2435       if(! *lpstrPos) break;    /* end */
2436       lpstrDisplay = lpstrPos;
2437       lpstrPos += lstrlenW(lpstrPos) + 1;
2438
2439       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2440
2441       nFilters++;
2442
2443       /* Copy the extensions */
2444       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2445       lstrcpyW(lpstrExt,lpstrPos);
2446       lpstrPos += lstrlenW(lpstrPos) + 1;
2447
2448       /* Add the item at the end of the combo */
2449       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2450
2451       /* malformed filters are added anyway... */
2452       if (!*lpstrExt) break;
2453     }
2454   }
2455
2456   /*
2457    * Set the current filter to the one specified
2458    * in the initialisation structure
2459    */
2460   if (fodInfos->filter || fodInfos->customfilter)
2461   {
2462     LPWSTR lpstrFilter;
2463
2464     /* Check to make sure our index isn't out of bounds. */
2465     if ( fodInfos->ofnInfos->nFilterIndex >
2466          nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2467       fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2468
2469     /* set default filter index */
2470     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2471       fodInfos->ofnInfos->nFilterIndex = 1;
2472
2473     /* calculate index of Combo Box item */
2474     nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2475     if (fodInfos->customfilter == NULL)
2476       nFilterIndexCB--;
2477
2478     /* Set the current index selection. */
2479     CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2480
2481     /* Get the corresponding text string from the combo box. */
2482     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2483                                              nFilterIndexCB);
2484
2485     if ((INT_PTR)lpstrFilter == CB_ERR)  /* control is empty */
2486       lpstrFilter = NULL;
2487
2488     if(lpstrFilter)
2489     {
2490       DWORD len;
2491       CharLowerW(lpstrFilter); /* lowercase */
2492       len = lstrlenW(lpstrFilter)+1;
2493       fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2494       lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2495     }
2496   } else
2497       fodInfos->ofnInfos->nFilterIndex = 0;
2498   return S_OK;
2499 }
2500
2501 /***********************************************************************
2502  *      FILEDLG95_FILETYPE_OnCommand
2503  *
2504  * WM_COMMAND of the file type combo box
2505  * If the function succeeds, the return value is nonzero.
2506  */
2507 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2508 {
2509   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2510
2511   switch(wNotifyCode)
2512   {
2513     case CBN_SELENDOK:
2514     {
2515       LPWSTR lpstrFilter;
2516
2517       /* Get the current item of the filetype combo box */
2518       int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2519
2520       /* set the current filter index */
2521       fodInfos->ofnInfos->nFilterIndex = iItem +
2522         (fodInfos->customfilter == NULL ? 1 : 0);
2523
2524       /* Set the current filter with the current selection */
2525       MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2526
2527       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2528                                              iItem);
2529       if((INT_PTR)lpstrFilter != CB_ERR)
2530       {
2531           DWORD len;
2532           CharLowerW(lpstrFilter); /* lowercase */
2533           len = lstrlenW(lpstrFilter)+1;
2534           fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2535           lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2536           SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2537       }
2538
2539       /* Refresh the actual view to display the included items*/
2540       if (fodInfos->Shell.FOIShellView)
2541         IShellView_Refresh(fodInfos->Shell.FOIShellView);
2542     }
2543   }
2544   return FALSE;
2545 }
2546 /***********************************************************************
2547  *      FILEDLG95_FILETYPE_SearchExt
2548  *
2549  * searches for an extension in the filetype box
2550  */
2551 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2552 {
2553   int i, iCount = CBGetCount(hwnd);
2554
2555   TRACE("%s\n", debugstr_w(lpstrExt));
2556
2557   if(iCount != CB_ERR)
2558   {
2559     for(i=0;i<iCount;i++)
2560     {
2561       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2562           return i;
2563     }
2564   }
2565   return -1;
2566 }
2567
2568 /***********************************************************************
2569  *      FILEDLG95_FILETYPE_Clean
2570  *
2571  * Clean the memory used by the filetype combo box
2572  */
2573 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2574 {
2575   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2576   int iPos;
2577   int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2578
2579   TRACE("\n");
2580
2581   /* Delete each string of the combo and their associated data */
2582   if(iCount != CB_ERR)
2583   {
2584     for(iPos = iCount-1;iPos>=0;iPos--)
2585     {
2586       MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2587       CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2588     }
2589   }
2590   /* Current filter */
2591   MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2592
2593 }
2594
2595 /***********************************************************************
2596  *      FILEDLG95_LOOKIN_Init
2597  *
2598  * Initialisation of the look in combo box
2599  */
2600
2601 /* Small helper function, to determine if the unixfs shell extension is rooted 
2602  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 
2603  */
2604 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2605     HKEY hKey;
2606     static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2607         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2608         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2609         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2610         'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2611         '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2612         '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2613     
2614     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2615         return FALSE;
2616         
2617     RegCloseKey(hKey);
2618     return TRUE;
2619 }
2620
2621 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2622 {
2623   IShellFolder  *psfRoot, *psfDrives;
2624   IEnumIDList   *lpeRoot, *lpeDrives;
2625   LPITEMIDLIST  pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2626
2627   LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2628
2629   TRACE("\n");
2630
2631   liInfos->iMaxIndentation = 0;
2632
2633   SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2634
2635   /* set item height for both text field and listbox */
2636   CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2637   CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2638    
2639   /* Turn on the extended UI for the combo box like Windows does */
2640   CBSetExtendedUI(hwndCombo, TRUE);
2641
2642   /* Initialise data of Desktop folder */
2643   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2644   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2645   COMDLG32_SHFree(pidlTmp);
2646
2647   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2648
2649   SHGetDesktopFolder(&psfRoot);
2650
2651   if (psfRoot)
2652   {
2653     /* enumerate the contents of the desktop */
2654     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2655     {
2656       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2657       {
2658         FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2659
2660         /* If the unixfs extension is rooted, we don't expand the drives by default */
2661         if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 
2662         {
2663           /* special handling for CSIDL_DRIVES */
2664           if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2665           {
2666             if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2667             {
2668               /* enumerate the drives */
2669               if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2670               {
2671                 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2672                 {
2673                   pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2674                   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2675                   COMDLG32_SHFree(pidlAbsTmp);
2676                   COMDLG32_SHFree(pidlTmp1);
2677                 }
2678                 IEnumIDList_Release(lpeDrives);
2679               }
2680               IShellFolder_Release(psfDrives);
2681             }
2682           }
2683         }
2684
2685         COMDLG32_SHFree(pidlTmp);
2686       }
2687       IEnumIDList_Release(lpeRoot);
2688     }
2689     IShellFolder_Release(psfRoot);
2690   }
2691
2692   COMDLG32_SHFree(pidlDrives);
2693 }
2694
2695 /***********************************************************************
2696  *      FILEDLG95_LOOKIN_DrawItem
2697  *
2698  * WM_DRAWITEM message handler
2699  */
2700 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2701 {
2702   COLORREF crWin = GetSysColor(COLOR_WINDOW);
2703   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2704   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2705   RECT rectText;
2706   RECT rectIcon;
2707   SHFILEINFOW sfi;
2708   HIMAGELIST ilItemImage;
2709   int iIndentation;
2710   TEXTMETRICW tm;
2711   LPSFOLDER tmpFolder;
2712
2713
2714   LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2715
2716   TRACE("\n");
2717
2718   if(pDIStruct->itemID == -1)
2719     return 0;
2720
2721   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2722                             pDIStruct->itemID)))
2723     return 0;
2724
2725
2726   if(pDIStruct->itemID == liInfos->uSelectedItem)
2727   {
2728     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2729                                                0,
2730                                                &sfi,
2731                                                sizeof (sfi),
2732                                                SHGFI_PIDL | SHGFI_SMALLICON |
2733                                                SHGFI_OPENICON | SHGFI_SYSICONINDEX    |
2734                                                SHGFI_DISPLAYNAME );
2735   }
2736   else
2737   {
2738     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2739                                                   0,
2740                                                   &sfi,
2741                                                   sizeof (sfi),
2742                                                   SHGFI_PIDL | SHGFI_SMALLICON |
2743                                                   SHGFI_SYSICONINDEX |
2744                                                   SHGFI_DISPLAYNAME);
2745   }
2746
2747   /* Is this item selected ? */
2748   if(pDIStruct->itemState & ODS_SELECTED)
2749   {
2750     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2751     SetBkColor(pDIStruct->hDC,crHighLight);
2752     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2753   }
2754   else
2755   {
2756     SetTextColor(pDIStruct->hDC,crText);
2757     SetBkColor(pDIStruct->hDC,crWin);
2758     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2759   }
2760
2761   /* Do not indent item if drawing in the edit of the combo */
2762   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2763   {
2764     iIndentation = 0;
2765     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2766                                                 0,
2767                                                 &sfi,
2768                                                 sizeof (sfi),
2769                                                 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2770                                                 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME  );
2771
2772   }
2773   else
2774   {
2775     iIndentation = tmpFolder->m_iIndent;
2776   }
2777   /* Draw text and icon */
2778
2779   /* Initialise the icon display area */
2780   rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2781   rectIcon.top = pDIStruct->rcItem.top;
2782   rectIcon.right = rectIcon.left + ICONWIDTH;
2783   rectIcon.bottom = pDIStruct->rcItem.bottom;
2784
2785   /* Initialise the text display area */
2786   GetTextMetricsW(pDIStruct->hDC, &tm);
2787   rectText.left = rectIcon.right;
2788   rectText.top =
2789           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2790   rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2791   rectText.bottom =
2792           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2793
2794   /* Draw the icon from the image list */
2795   ImageList_Draw(ilItemImage,
2796                  sfi.iIcon,
2797                  pDIStruct->hDC,
2798                  rectIcon.left,
2799                  rectIcon.top,
2800                  ILD_TRANSPARENT );
2801
2802   /* Draw the associated text */
2803   if(sfi.szDisplayName)
2804     TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2805
2806
2807   return NOERROR;
2808 }
2809
2810 /***********************************************************************
2811  *      FILEDLG95_LOOKIN_OnCommand
2812  *
2813  * LookIn combo box WM_COMMAND message handler
2814  * If the function succeeds, the return value is nonzero.
2815  */
2816 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2817 {
2818   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2819
2820   TRACE("%p\n", fodInfos);
2821
2822   switch(wNotifyCode)
2823   {
2824     case CBN_SELENDOK:
2825     {
2826       LPSFOLDER tmpFolder;
2827       int iItem;
2828
2829       iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2830
2831       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2832                                                iItem)))
2833         return FALSE;
2834
2835
2836       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2837                                               tmpFolder->pidlItem,
2838                                               SBSP_ABSOLUTE)))
2839       {
2840         SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2841         return TRUE;
2842       }
2843       break;
2844     }
2845
2846   }
2847   return FALSE;
2848 }
2849
2850 /***********************************************************************
2851  *      FILEDLG95_LOOKIN_AddItem
2852  *
2853  * Adds an absolute pidl item to the lookin combo box
2854  * returns the index of the inserted item
2855  */
2856 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2857 {
2858   LPITEMIDLIST pidlNext;
2859   SHFILEINFOW sfi;
2860   SFOLDER *tmpFolder;
2861   LookInInfos *liInfos;
2862
2863   TRACE("%08x\n", iInsertId);
2864
2865   if(!pidl)
2866     return -1;
2867
2868   if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2869     return -1;
2870
2871   tmpFolder = MemAlloc(sizeof(SFOLDER));
2872   tmpFolder->m_iIndent = 0;
2873
2874   /* Calculate the indentation of the item in the lookin*/
2875   pidlNext = pidl;
2876   while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2877   {
2878     tmpFolder->m_iIndent++;
2879   }
2880
2881   tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2882
2883   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2884     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2885
2886   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2887   SHGetFileInfoW((LPCWSTR)pidl,
2888                   0,
2889                   &sfi,
2890                   sizeof(sfi),
2891                   SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2892                   | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2893
2894   TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2895
2896   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2897   {
2898     int iItemID;
2899
2900     TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2901
2902     /* Add the item at the end of the list */
2903     if(iInsertId < 0)
2904     {
2905       iItemID = CBAddString(hwnd,sfi.szDisplayName);
2906     }
2907     /* Insert the item at the iInsertId position*/
2908     else
2909     {
2910       iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2911     }
2912
2913     CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2914     return iItemID;
2915   }
2916
2917   COMDLG32_SHFree( tmpFolder->pidlItem );
2918   MemFree( tmpFolder );
2919   return -1;
2920
2921 }
2922
2923 /***********************************************************************
2924  *      FILEDLG95_LOOKIN_InsertItemAfterParent
2925  *
2926  * Insert an item below its parent
2927  */
2928 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2929 {
2930
2931   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2932   int iParentPos;
2933
2934   TRACE("\n");
2935
2936   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2937
2938   if(iParentPos < 0)
2939   {
2940     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2941   }
2942
2943   /* Free pidlParent memory */
2944   COMDLG32_SHFree((LPVOID)pidlParent);
2945
2946   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2947 }
2948
2949 /***********************************************************************
2950  *      FILEDLG95_LOOKIN_SelectItem
2951  *
2952  * Adds an absolute pidl item to the lookin combo box
2953  * returns the index of the inserted item
2954  */
2955 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2956 {
2957   int iItemPos;
2958   LookInInfos *liInfos;
2959
2960   TRACE("\n");
2961
2962   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2963
2964   liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2965
2966   if(iItemPos < 0)
2967   {
2968     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2969     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2970   }
2971
2972   else
2973   {
2974     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2975     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2976     {
2977       int iRemovedItem;
2978
2979       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2980         break;
2981       if(iRemovedItem < iItemPos)
2982         iItemPos--;
2983     }
2984   }
2985
2986   CBSetCurSel(hwnd,iItemPos);
2987   liInfos->uSelectedItem = iItemPos;
2988
2989   return 0;
2990
2991 }
2992
2993 /***********************************************************************
2994  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
2995  *
2996  * Remove the item with an expansion level over iExpansionLevel
2997  */
2998 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2999 {
3000   int iItemPos;
3001
3002   LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
3003
3004   TRACE("\n");
3005
3006   if(liInfos->iMaxIndentation <= 2)
3007     return -1;
3008
3009   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3010   {
3011     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3012     COMDLG32_SHFree(tmpFolder->pidlItem);
3013     MemFree(tmpFolder);
3014     CBDeleteString(hwnd,iItemPos);
3015     liInfos->iMaxIndentation--;
3016
3017     return iItemPos;
3018   }
3019
3020   return -1;
3021 }
3022
3023 /***********************************************************************
3024  *      FILEDLG95_LOOKIN_SearchItem
3025  *
3026  * Search for pidl in the lookin combo box
3027  * returns the index of the found item
3028  */
3029 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3030 {
3031   int i = 0;
3032   int iCount = CBGetCount(hwnd);
3033
3034   TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3035
3036   if (iCount != CB_ERR)
3037   {
3038     for(;i<iCount;i++)
3039     {
3040       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3041
3042       if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3043         return i;
3044       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3045         return i;
3046     }
3047   }
3048
3049   return -1;
3050 }
3051
3052 /***********************************************************************
3053  *      FILEDLG95_LOOKIN_Clean
3054  *
3055  * Clean the memory used by the lookin combo box
3056  */
3057 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3058 {
3059     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3060     int iPos;
3061     int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3062
3063     TRACE("\n");
3064
3065     /* Delete each string of the combo and their associated data */
3066     if (iCount != CB_ERR)
3067     {
3068       for(iPos = iCount-1;iPos>=0;iPos--)
3069       {
3070         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3071         COMDLG32_SHFree(tmpFolder->pidlItem);
3072         MemFree(tmpFolder);
3073         CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3074       }
3075     }
3076
3077     /* LookInInfos structure */
3078     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3079
3080 }
3081 /***********************************************************************
3082  * FILEDLG95_FILENAME_FillFromSelection
3083  *
3084  * fills the edit box from the cached DataObject
3085  */
3086 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3087 {
3088     FileOpenDlgInfos *fodInfos;
3089     LPITEMIDLIST      pidl;
3090     UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3091     WCHAR             lpstrTemp[MAX_PATH];
3092     LPWSTR            lpstrAllFile, lpstrCurrFile;
3093
3094     TRACE("\n");
3095     fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3096
3097     /* Count how many files we have */
3098     nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3099
3100     /* calculate the string length, count files */
3101     if (nFileSelected >= 1)
3102     {
3103       nLength += 3;     /* first and last quotes, trailing \0 */
3104       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3105       {
3106         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3107
3108         if (pidl)
3109         {
3110           /* get the total length of the selected file names */
3111           lpstrTemp[0] = '\0';
3112           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3113
3114           if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3115           {
3116             nLength += lstrlenW( lpstrTemp ) + 3;
3117             nFiles++;
3118           }
3119           COMDLG32_SHFree( pidl );
3120         }
3121       }
3122     }
3123
3124     /* allocate the buffer */
3125     if (nFiles <= 1) nLength = MAX_PATH;
3126     lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3127
3128     /* Generate the string for the edit control */
3129     if(nFiles >= 1)
3130     {
3131       lpstrCurrFile = lpstrAllFile;
3132       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3133       {
3134         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3135
3136         if (pidl)
3137         {
3138           /* get the file name */
3139           lpstrTemp[0] = '\0';
3140           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3141
3142           if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3143           {
3144             if ( nFiles > 1)
3145             {
3146               *lpstrCurrFile++ =  '\"';
3147               lstrcpyW( lpstrCurrFile, lpstrTemp );
3148               lpstrCurrFile += lstrlenW( lpstrTemp );
3149               *lpstrCurrFile++ = '\"';
3150               *lpstrCurrFile++ = ' ';
3151               *lpstrCurrFile = 0;
3152             }
3153             else
3154             {
3155               lstrcpyW( lpstrAllFile, lpstrTemp );
3156             }
3157           }
3158           COMDLG32_SHFree( (LPVOID) pidl );
3159         }
3160       }
3161       SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3162        
3163       /* Select the file name like Windows does */ 
3164       SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3165     }
3166     HeapFree(GetProcessHeap(),0, lpstrAllFile );
3167 }
3168
3169
3170 /* copied from shell32 to avoid linking to it
3171  * Although shell32 is already linked the behaviour of exported StrRetToStrN
3172  * is dependent on whether emulated OS is unicode or not.
3173  */
3174 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3175 {
3176         switch (src->uType)
3177         {
3178           case STRRET_WSTR:
3179             lstrcpynW(dest, src->u.pOleStr, len);
3180             COMDLG32_SHFree(src->u.pOleStr);
3181             break;
3182
3183           case STRRET_CSTR:
3184             if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3185                   dest[len-1] = 0;
3186             break;
3187
3188           case STRRET_OFFSET:
3189             if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3190                   dest[len-1] = 0;
3191             break;
3192
3193           default:
3194             FIXME("unknown type %x!\n", src->uType);
3195             if (len) *dest = '\0';
3196             return E_FAIL;
3197         }
3198         return S_OK;
3199 }
3200
3201 /***********************************************************************
3202  * FILEDLG95_FILENAME_GetFileNames
3203  *
3204  * Copies the filenames to a delimited string list.
3205  * The delimiter is specified by the parameter 'separator',
3206  *  usually either a space or a nul
3207  */
3208 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3209 {
3210         FileOpenDlgInfos *fodInfos  = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3211         UINT nStrCharCount = 0; /* index in src buffer */
3212         UINT nFileIndex = 0;    /* index in dest buffer */
3213         UINT nFileCount = 0;    /* number of files */
3214         UINT nStrLen = 0;       /* length of string in edit control */
3215         LPWSTR lpstrEdit;       /* buffer for string from edit control */
3216
3217         TRACE("\n");
3218
3219         /* get the filenames from the edit control */
3220         nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3221         lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3222         GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3223
3224         TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3225
3226         /* we might get single filename without any '"',
3227          * so we need nStrLen + terminating \0 + end-of-list \0 */
3228         *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3229         *sizeUsed = 0;
3230
3231         /* build delimited file list from filenames */
3232         while ( nStrCharCount <= nStrLen )
3233         {
3234           if ( lpstrEdit[nStrCharCount]=='"' )
3235           {
3236             nStrCharCount++;
3237             while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3238             {
3239               (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3240               (*sizeUsed)++;
3241               nStrCharCount++;
3242             }
3243             (*lpstrFileList)[nFileIndex++] = separator;
3244             (*sizeUsed)++;
3245             nFileCount++;
3246           }
3247           nStrCharCount++;
3248         }
3249
3250         /* single, unquoted string */
3251         if ((nStrLen > 0) && (*sizeUsed == 0) )
3252         {
3253           lstrcpyW(*lpstrFileList, lpstrEdit);
3254           nFileIndex = lstrlenW(lpstrEdit) + 1;
3255           (*sizeUsed) = nFileIndex;
3256           nFileCount = 1;
3257         }
3258
3259         /* trailing \0 */
3260         (*lpstrFileList)[nFileIndex] = '\0';
3261         (*sizeUsed)++;
3262
3263         MemFree(lpstrEdit);
3264         return nFileCount;
3265 }
3266
3267 #define SETDefFormatEtc(fe,cf,med) \
3268 { \
3269     (fe).cfFormat = cf;\
3270     (fe).dwAspect = DVASPECT_CONTENT; \
3271     (fe).ptd =NULL;\
3272     (fe).tymed = med;\
3273     (fe).lindex = -1;\
3274 };
3275
3276 /*
3277  * DATAOBJECT Helper functions
3278  */
3279
3280 /***********************************************************************
3281  * COMCTL32_ReleaseStgMedium
3282  *
3283  * like ReleaseStgMedium from ole32
3284  */
3285 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3286 {
3287       if(medium.pUnkForRelease)
3288       {
3289         IUnknown_Release(medium.pUnkForRelease);
3290       }
3291       else
3292       {
3293         GlobalUnlock(medium.u.hGlobal);
3294         GlobalFree(medium.u.hGlobal);
3295       }
3296 }
3297
3298 /***********************************************************************
3299  *          GetPidlFromDataObject
3300  *
3301  * Return pidl(s) by number from the cached DataObject
3302  *
3303  * nPidlIndex=0 gets the fully qualified root path
3304  */
3305 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3306 {
3307
3308     STGMEDIUM medium;
3309     FORMATETC formatetc;
3310     LPITEMIDLIST pidl = NULL;
3311
3312     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3313
3314     if (!doSelected)
3315         return NULL;
3316         
3317     /* Set the FORMATETC structure*/
3318     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3319
3320     /* Get the pidls from IDataObject */
3321     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3322     {
3323       LPIDA cida = GlobalLock(medium.u.hGlobal);
3324       if(nPidlIndex <= cida->cidl)
3325       {
3326         pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3327       }
3328       COMCTL32_ReleaseStgMedium(medium);
3329     }
3330     return pidl;
3331 }
3332
3333 /***********************************************************************
3334  *          GetNumSelected
3335  *
3336  * Return the number of selected items in the DataObject.
3337  *
3338 */
3339 UINT GetNumSelected( IDataObject *doSelected )
3340 {
3341     UINT retVal = 0;
3342     STGMEDIUM medium;
3343     FORMATETC formatetc;
3344
3345     TRACE("sv=%p\n", doSelected);
3346
3347     if (!doSelected) return 0;
3348
3349     /* Set the FORMATETC structure*/
3350     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3351
3352     /* Get the pidls from IDataObject */
3353     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3354     {
3355       LPIDA cida = GlobalLock(medium.u.hGlobal);
3356       retVal = cida->cidl;
3357       COMCTL32_ReleaseStgMedium(medium);
3358       return retVal;
3359     }
3360     return 0;
3361 }
3362
3363 /*
3364  * TOOLS
3365  */
3366
3367 /***********************************************************************
3368  *      GetName
3369  *
3370  * Get the pidl's display name (relative to folder) and
3371  * put it in lpstrFileName.
3372  *
3373  * Return NOERROR on success,
3374  * E_FAIL otherwise
3375  */
3376
3377 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3378 {
3379   STRRET str;
3380   HRESULT hRes;
3381
3382   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3383
3384   if(!lpsf)
3385   {
3386     SHGetDesktopFolder(&lpsf);
3387     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3388     IShellFolder_Release(lpsf);
3389     return hRes;
3390   }
3391
3392   /* Get the display name of the pidl relative to the folder */
3393   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3394   {
3395       return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3396   }
3397   return E_FAIL;
3398 }
3399
3400 /***********************************************************************
3401  *      GetShellFolderFromPidl
3402  *
3403  * pidlRel is the item pidl relative
3404  * Return the IShellFolder of the absolute pidl
3405  */
3406 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3407 {
3408   IShellFolder *psf = NULL,*psfParent;
3409
3410   TRACE("%p\n", pidlAbs);
3411
3412   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3413   {
3414     psf = psfParent;
3415     if(pidlAbs && pidlAbs->mkid.cb)
3416     {
3417       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3418       {
3419         IShellFolder_Release(psfParent);
3420         return psf;
3421       }
3422     }
3423     /* return the desktop */
3424     return psfParent;
3425   }
3426   return NULL;
3427 }
3428
3429 /***********************************************************************
3430  *      GetParentPidl
3431  *
3432  * Return the LPITEMIDLIST to the parent of the pidl in the list
3433  */
3434 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3435 {
3436   LPITEMIDLIST pidlParent;
3437
3438   TRACE("%p\n", pidl);
3439
3440   pidlParent = COMDLG32_PIDL_ILClone(pidl);
3441   COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3442
3443   return pidlParent;
3444 }
3445
3446 /***********************************************************************
3447  *      GetPidlFromName
3448  *
3449  * returns the pidl of the file name relative to folder
3450  * NULL if an error occurred
3451  */
3452 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3453 {
3454   LPITEMIDLIST pidl = NULL;
3455   ULONG ulEaten;
3456
3457   TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3458
3459   if(!lpcstrFileName) return NULL;
3460   if(!*lpcstrFileName) return NULL;
3461
3462   if(!lpsf)
3463   {
3464     if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3465         IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3466         IShellFolder_Release(lpsf);
3467     }
3468   }
3469   else
3470   {
3471     IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3472   }
3473   return pidl;
3474 }
3475
3476 /*
3477 */
3478 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3479 {
3480         ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3481         HRESULT ret;
3482
3483         TRACE("%p, %p\n", psf, pidl);
3484
3485         ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3486
3487         TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3488         /* see documentation shell 4.1*/
3489         return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3490 }
3491
3492 /***********************************************************************
3493  *      BrowseSelectedFolder
3494  */
3495 static BOOL BrowseSelectedFolder(HWND hwnd)
3496 {
3497   BOOL bBrowseSelFolder = FALSE;
3498   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3499
3500   TRACE("\n");
3501
3502   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3503   {
3504       LPITEMIDLIST pidlSelection;
3505
3506       /* get the file selected */
3507       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3508       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3509       {
3510           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3511                          pidlSelection, SBSP_RELATIVE ) ) )
3512           {
3513                static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3514                                    ' ','n','o','t',' ','e','x','i','s','t',0};
3515                MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3516           }
3517           bBrowseSelFolder = TRUE;
3518           SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3519       }
3520       COMDLG32_SHFree( pidlSelection );
3521   }
3522
3523   return bBrowseSelFolder;
3524 }
3525
3526 /*
3527  * Memory allocation methods */
3528 static void *MemAlloc(UINT size)
3529 {
3530     return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3531 }
3532
3533 static void MemFree(void *mem)
3534 {
3535     HeapFree(GetProcessHeap(),0,mem);
3536 }
3537
3538 /*
3539  * Old-style (win3.1) dialogs */
3540
3541 /***********************************************************************
3542  *           FD32_GetTemplate                                  [internal]
3543  *
3544  * Get a template (or FALSE if failure) when 16 bits dialogs are used
3545  * by a 32 bits application
3546  *
3547  */
3548 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3549 {
3550     LPOPENFILENAMEW ofnW = lfs->ofnW;
3551     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3552     HANDLE hDlgTmpl;
3553
3554     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3555     {
3556         if (!(lfs->template = LockResource( ofnW->hInstance )))
3557         {
3558             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3559             return FALSE;
3560         }
3561     }
3562     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3563     {
3564         HRSRC hResInfo;
3565         if (priv->ofnA)
3566             hResInfo = FindResourceA(priv->ofnA->hInstance,
3567                                  priv->ofnA->lpTemplateName,
3568                                  (LPSTR)RT_DIALOG);
3569         else
3570             hResInfo = FindResourceW(ofnW->hInstance,
3571                                  ofnW->lpTemplateName,
3572                                  (LPWSTR)RT_DIALOG);
3573         if (!hResInfo)
3574         {
3575             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3576             return FALSE;
3577         }
3578         if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3579                                 hResInfo)) ||
3580                     !(lfs->template = LockResource(hDlgTmpl)))
3581         {
3582             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3583             return FALSE;
3584         }
3585     } else { /* get it from internal Wine resource */
3586         HRSRC hResInfo;
3587         if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3588              lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3589         {
3590             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3591             return FALSE;
3592         }
3593         if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3594                 !(lfs->template = LockResource( hDlgTmpl )))
3595         {
3596             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3597             return FALSE;
3598         }
3599     }
3600     return TRUE;
3601 }
3602
3603
3604 /************************************************************************
3605  *                              FD32_Init          [internal]
3606  *      called from the common 16/32 code to initialize 32 bit data
3607  */
3608 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3609 {
3610     BOOL IsUnicode = (BOOL) data;
3611     PFD32_PRIVATE priv;
3612
3613     priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3614     lfs->private1632 = priv;
3615     if (NULL == lfs->private1632) return FALSE;
3616     if (IsUnicode)
3617     {
3618         lfs->ofnW = (LPOPENFILENAMEW) lParam;
3619         if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3620             if (lfs->ofnW->lpfnHook)
3621                 lfs->hook = TRUE;
3622     }
3623     else
3624     {
3625         priv->ofnA = (LPOPENFILENAMEA) lParam;
3626         if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3627             if (priv->ofnA->lpfnHook)
3628                 lfs->hook = TRUE;
3629         lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3630         FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3631     }
3632
3633     if (! FD32_GetTemplate(lfs)) return FALSE;
3634
3635     return TRUE;
3636 }
3637
3638 /***********************************************************************
3639  *                              FD32_CallWindowProc          [internal]
3640  *
3641  *      called from the common 16/32 code to call the appropriate hook
3642  */
3643 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3644                                  LPARAM lParam)
3645 {
3646     BOOL ret;
3647     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3648
3649     if (priv->ofnA)
3650     {
3651         TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3652                priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3653         ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3654         TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3655                priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3656         return ret;
3657     }
3658
3659     TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3660            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3661     ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3662     TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3663            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3664     return ret;
3665 }
3666
3667 /***********************************************************************
3668  *                              FD32_UpdateResult            [internal]
3669  *          update the real client structures if any
3670  */
3671 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3672 {
3673     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3674     LPOPENFILENAMEW ofnW = lfs->ofnW;
3675
3676     if (priv->ofnA)
3677     {
3678         LPSTR lpszTemp;
3679         if (ofnW->nMaxFile &&
3680             !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3681                                   priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3682             priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3683
3684         /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3685         /* set filename offset */
3686         lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3687         priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3688
3689         /* set extension offset */
3690         lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3691         priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3692     }
3693 }
3694
3695 /***********************************************************************
3696  *                              FD32_UpdateFileTitle            [internal]
3697  *          update the real client structures if any
3698  */
3699 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3700 {
3701     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3702     LPOPENFILENAMEW ofnW = lfs->ofnW;
3703
3704     if (priv->ofnA)
3705     {
3706         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3707                                   priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3708             priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3709     }
3710 }
3711
3712
3713 /***********************************************************************
3714  *                              FD32_SendLbGetCurSel         [internal]
3715  *          retrieve selected listbox item
3716  */
3717 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3718 {
3719     return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3720 }
3721
3722
3723 /************************************************************************
3724  *                              FD32_Destroy          [internal]
3725  *      called from the common 16/32 code to cleanup 32 bit data
3726  */
3727 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3728 {
3729     PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3730
3731     /* if ofnW has been allocated, have to free everything in it */
3732     if (NULL != priv && NULL != priv->ofnA)
3733     {
3734         FD31_FreeOfnW(lfs->ofnW);
3735         HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3736     }
3737 }
3738
3739 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3740 {
3741     callbacks->Init = FD32_Init;
3742     callbacks->CWP = FD32_CallWindowProc;
3743     callbacks->UpdateResult = FD32_UpdateResult;
3744     callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3745     callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3746     callbacks->Destroy = FD32_Destroy;
3747 }
3748
3749 /***********************************************************************
3750  *                              FD32_WMMeasureItem           [internal]
3751  */
3752 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3753 {
3754     LPMEASUREITEMSTRUCT lpmeasure;
3755
3756     lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3757     lpmeasure->itemHeight = FD31_GetFldrHeight();
3758     return TRUE;
3759 }
3760
3761
3762 /***********************************************************************
3763  *           FileOpenDlgProc                                    [internal]
3764  *      Used for open and save, in fact.
3765  */
3766 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3767                                              WPARAM wParam, LPARAM lParam)
3768 {
3769     PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3770
3771     TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3772     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3773         {
3774             INT_PTR lRet;
3775             lRet  = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3776             if (lRet)
3777                 return lRet;         /* else continue message processing */
3778         }
3779     switch (wMsg)
3780     {
3781     case WM_INITDIALOG:
3782         return FD31_WMInitDialog(hWnd, wParam, lParam);
3783
3784     case WM_MEASUREITEM:
3785         return FD32_WMMeasureItem(hWnd, wParam, lParam);
3786
3787     case WM_DRAWITEM:
3788         return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3789
3790     case WM_COMMAND:
3791         return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3792 #if 0
3793     case WM_CTLCOLOR:
3794          SetBkColor((HDC16)wParam, 0x00C0C0C0);
3795          switch (HIWORD(lParam))
3796          {
3797          case CTLCOLOR_BTN:
3798              SetTextColor((HDC16)wParam, 0x00000000);
3799              return hGRAYBrush;
3800         case CTLCOLOR_STATIC:
3801              SetTextColor((HDC16)wParam, 0x00000000);
3802              return hGRAYBrush;
3803         }
3804       break;
3805 #endif
3806     }
3807     return FALSE;
3808 }
3809
3810
3811 /***********************************************************************
3812  *           GetFileName31A                                 [internal]
3813  *
3814  * Creates a win31 style dialog box for the user to select a file to open/save.
3815  */
3816 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3817                            UINT dlgType /* type dialogue : open/save */
3818                            )
3819 {
3820     HINSTANCE hInst;
3821     BOOL bRet = FALSE;
3822     PFD31_DATA lfs;
3823     FD31_CALLBACKS callbacks;
3824
3825     if (!lpofn || !FD31_Init()) return FALSE;
3826
3827     TRACE("ofn flags %08x\n", lpofn->Flags);
3828     FD32_SetupCallbacks(&callbacks);
3829     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3830     if (lfs)
3831     {
3832         hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3833         bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3834                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
3835         FD31_DestroyPrivate(lfs);
3836     }
3837
3838     TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3839     return bRet;
3840 }
3841
3842 /***********************************************************************
3843  *           GetFileName31W                                 [internal]
3844  *
3845  * Creates a win31 style dialog box for the user to select a file to open/save
3846  */
3847 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3848                            UINT dlgType /* type dialogue : open/save */
3849                            )
3850 {
3851     HINSTANCE hInst;
3852     BOOL bRet = FALSE;
3853     PFD31_DATA lfs;
3854     FD31_CALLBACKS callbacks;
3855
3856     if (!lpofn || !FD31_Init()) return FALSE;
3857
3858     FD32_SetupCallbacks(&callbacks);
3859     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3860     if (lfs)
3861     {
3862         hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3863         bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3864                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
3865         FD31_DestroyPrivate(lfs);
3866     }
3867
3868     TRACE("file %s, file offset %d, ext offset %d\n",
3869           debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3870     return bRet;
3871 }
3872
3873 /* ------------------ APIs ---------------------- */
3874
3875 /***********************************************************************
3876  *            GetOpenFileNameA  (COMDLG32.@)
3877  *
3878  * Creates a dialog box for the user to select a file to open.
3879  *
3880  * RETURNS
3881  *    TRUE on success: user enters a valid file
3882  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3883  *
3884  */
3885 BOOL WINAPI GetOpenFileNameA(
3886         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3887 {
3888     BOOL win16look = FALSE;
3889
3890     TRACE("flags %08x\n", ofn->Flags);
3891
3892     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3893     if (ofn->Flags & OFN_FILEMUSTEXIST)
3894         ofn->Flags |= OFN_PATHMUSTEXIST;
3895
3896     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3897         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3898
3899     if (win16look)
3900         return GetFileName31A(ofn, OPEN_DIALOG);
3901     else
3902         return GetFileDialog95A(ofn, OPEN_DIALOG);
3903 }
3904
3905 /***********************************************************************
3906  *            GetOpenFileNameW (COMDLG32.@)
3907  *
3908  * Creates a dialog box for the user to select a file to open.
3909  *
3910  * RETURNS
3911  *    TRUE on success: user enters a valid file
3912  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3913  *
3914  */
3915 BOOL WINAPI GetOpenFileNameW(
3916         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3917 {
3918     BOOL win16look = FALSE;
3919
3920     TRACE("flags %08x\n", ofn->Flags);
3921
3922     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3923     if (ofn->Flags & OFN_FILEMUSTEXIST)
3924         ofn->Flags |= OFN_PATHMUSTEXIST;
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 GetFileName31W(ofn, OPEN_DIALOG);
3931     else
3932         return GetFileDialog95W(ofn, OPEN_DIALOG);
3933 }
3934
3935
3936 /***********************************************************************
3937  *            GetSaveFileNameA  (COMDLG32.@)
3938  *
3939  * Creates a dialog box for the user to select a file to save.
3940  *
3941  * RETURNS
3942  *    TRUE on success: user enters a valid file
3943  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3944  *
3945  */
3946 BOOL WINAPI GetSaveFileNameA(
3947         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3948 {
3949     BOOL win16look = FALSE;
3950
3951     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3952         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3953
3954     if (win16look)
3955         return GetFileName31A(ofn, SAVE_DIALOG);
3956     else
3957         return GetFileDialog95A(ofn, SAVE_DIALOG);
3958 }
3959
3960 /***********************************************************************
3961  *            GetSaveFileNameW  (COMDLG32.@)
3962  *
3963  * Creates a dialog box for the user to select a file to save.
3964  *
3965  * RETURNS
3966  *    TRUE on success: user enters a valid file
3967  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3968  *
3969  */
3970 BOOL WINAPI GetSaveFileNameW(
3971         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3972 {
3973     BOOL win16look = FALSE;
3974
3975     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3976         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3977
3978     if (win16look)
3979         return GetFileName31W(ofn, SAVE_DIALOG);
3980     else
3981         return GetFileDialog95W(ofn, SAVE_DIALOG);
3982 }
3983
3984 /***********************************************************************
3985  *      GetFileTitleA           (COMDLG32.@)
3986  *
3987  * See GetFileTitleW.
3988  */
3989 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3990 {
3991     int ret;
3992     UNICODE_STRING strWFile;
3993     LPWSTR lpWTitle;
3994
3995     RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3996     lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3997     ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3998     if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3999     RtlFreeUnicodeString( &strWFile );
4000     RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4001     return ret;
4002 }
4003
4004
4005 /***********************************************************************
4006  *      GetFileTitleW           (COMDLG32.@)
4007  *
4008  * Get the name of a file.
4009  *
4010  * PARAMS
4011  *  lpFile  [I] name and location of file
4012  *  lpTitle [O] returned file name
4013  *  cbBuf   [I] buffer size of lpTitle
4014  *
4015  * RETURNS
4016  *  Success: zero
4017  *  Failure: negative number.
4018  */
4019 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4020 {
4021         int i, len;
4022         static const WCHAR brkpoint[] = {'*','[',']',0};
4023         TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4024
4025         if(lpFile == NULL || lpTitle == NULL)
4026                 return -1;
4027
4028         len = lstrlenW(lpFile);
4029
4030         if (len == 0)
4031                 return -1;
4032
4033         if(strpbrkW(lpFile, brkpoint))
4034                 return -1;
4035
4036         len--;
4037
4038         if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4039                 return -1;
4040
4041         for(i = len; i >= 0; i--)
4042         {
4043                 if (lpFile[i] == '/' ||  lpFile[i] == '\\' ||  lpFile[i] == ':')
4044                 {
4045                         i++;
4046                         break;
4047                 }
4048         }
4049
4050         if(i == -1)
4051                 i++;
4052
4053         TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4054
4055         len = lstrlenW(lpFile+i)+1;
4056         if(cbBuf < len)
4057                 return len;
4058
4059         lstrcpyW(lpTitle, &lpFile[i]);
4060         return 0;
4061 }