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