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