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