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