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