~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/comdlg32/filedlg.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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