ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

filedlg.c
Go to the documentation of this file.
00001 /*
00002  * COMMDLG - File Open Dialogs Win95 look and feel
00003  *
00004  * Copyright 1999 Francois Boisvert
00005  * Copyright 1999, 2000 Juergen Schmied
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  *
00021  * FIXME: The whole concept of handling unicode is badly broken.
00022  *  many hook-messages expect a pointer to a
00023  *  OPENFILENAMEA or W structure. With the current architecture
00024  *  we would have to convert the beast at every call to a hook.
00025  *  we have to find a better solution but it would likely cause
00026  *  a complete rewrite after which we should handle the
00027  *  OPENFILENAME structure without any converting (jsch).
00028  *
00029  * FIXME: any hook gets a OPENFILENAMEA structure
00030  *
00031  * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
00032  *
00033  * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
00034  *
00035  * FIXME: algorithm for selecting the initial directory is too simple
00036  *
00037  * FIXME: add to recent docs
00038  *
00039  * FIXME: flags not implemented: OFN_DONTADDTORECENT,
00040  * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
00041  * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
00042  *
00043  * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
00044  *
00045  *
00046  */
00047 
00048 // RegGetValueW is supported by Win2k3 SP1 but headers need Win Vista
00049 #undef _WIN32_WINNT
00050 #define _WIN32_WINNT 0x0600
00051 
00052 #include "config.h"
00053 #include "wine/port.h"
00054 
00055 #include <ctype.h>
00056 #include <stdlib.h>
00057 #include <stdarg.h>
00058 #include <stdio.h>
00059 #include <string.h>
00060 
00061 #define COBJMACROS
00062 #define NONAMELESSUNION
00063 #define NONAMELESSSTRUCT
00064 
00065 #include "windef.h"
00066 #include "winbase.h"
00067 #include "winternl.h"
00068 #include "winnls.h"
00069 #include "wingdi.h"
00070 #include "winreg.h"
00071 #include "winuser.h"
00072 #include "commdlg.h"
00073 #include "dlgs.h"
00074 #include "cdlg.h"
00075 #include "filedlg31.h"
00076 #include "cderr.h"
00077 #include "shellapi.h"
00078 #include "shlobj.h"
00079 #include "filedlgbrowser.h"
00080 #include "shlwapi.h"
00081 
00082 #include "wine/unicode.h"
00083 #include "wine/debug.h"
00084 
00085 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
00086 
00087 #define UNIMPLEMENTED_FLAGS \
00088 (OFN_DONTADDTORECENT |\
00089 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
00090 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
00091 
00092 #define IsHooked(fodInfos) \
00093     ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
00094 /***********************************************************************
00095  * Data structure and global variables
00096  */
00097 typedef struct SFolder
00098 {
00099   int m_iImageIndex;    /* Index of picture in image list */
00100   HIMAGELIST hImgList;
00101   int m_iIndent;      /* Indentation index */
00102   LPITEMIDLIST pidlItem;  /* absolute pidl of the item */
00103 
00104 } SFOLDER,*LPSFOLDER;
00105 
00106 typedef struct tagLookInInfo
00107 {
00108   int iMaxIndentation;
00109   UINT uSelectedItem;
00110 } LookInInfos;
00111 
00112 
00113 /***********************************************************************
00114  * Defines and global variables
00115  */
00116 
00117 /* Draw item constant */
00118 #define ICONWIDTH 18
00119 #define XTEXTOFFSET 3
00120 
00121 /* AddItem flags*/
00122 #define LISTEND -1
00123 
00124 /* SearchItem methods */
00125 #define SEARCH_PIDL 1
00126 #define SEARCH_EXP  2
00127 #define ITEM_NOTFOUND -1
00128 
00129 /* Undefined windows message sent by CreateViewObject*/
00130 #define WM_GETISHELLBROWSER  WM_USER+7
00131 
00132 /* NOTE
00133  * Those macros exist in windowsx.h. However, you can't really use them since
00134  * they rely on the UNICODE defines and can't be used inside Wine itself.
00135  */
00136 
00137 /* Combo box macros */
00138 #define CBAddString(hwnd,str) \
00139     SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
00140 
00141 #define CBInsertString(hwnd,str,pos) \
00142     SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
00143 
00144 #define CBDeleteString(hwnd,pos) \
00145     SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
00146 
00147 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
00148     SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
00149 
00150 #define CBGetItemDataPtr(hwnd,iItemId) \
00151     SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
00152 
00153 #define CBGetLBText(hwnd,iItemId,str) \
00154     SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
00155 
00156 #define CBGetCurSel(hwnd) \
00157     SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
00158 
00159 #define CBSetCurSel(hwnd,pos) \
00160     SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
00161 
00162 #define CBGetCount(hwnd) \
00163     SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
00164 #define CBShowDropDown(hwnd,show) \
00165     SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
00166 #define CBSetItemHeight(hwnd,index,height) \
00167     SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
00168 
00169 #define CBSetExtendedUI(hwnd,flag) \
00170     SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
00171 
00172 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
00173 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
00174 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
00175 
00176 static const WCHAR LastVisitedMRUW[] =
00177     {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
00178         'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
00179         'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
00180         'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
00181 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
00182 
00183 /***********************************************************************
00184  * Prototypes
00185  */
00186 
00187 /* Internal functions used by the dialog */
00188 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
00189 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
00190 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
00191 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
00192 static BOOL    FILEDLG95_OnOpen(HWND hwnd);
00193 static LRESULT FILEDLG95_InitControls(HWND hwnd);
00194 static void    FILEDLG95_Clean(HWND hwnd);
00195 
00196 /* Functions used by the shell navigation */
00197 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
00198 static BOOL    FILEDLG95_SHELL_UpFolder(HWND hwnd);
00199 static BOOL    FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
00200 static void    FILEDLG95_SHELL_Clean(HWND hwnd);
00201 static BOOL    FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
00202 
00203 /* Functions used by the EDIT box */
00204 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
00205 
00206 /* Functions used by the filetype combo box */
00207 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
00208 static BOOL    FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
00209 static int     FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
00210 static void    FILEDLG95_FILETYPE_Clean(HWND hwnd);
00211 
00212 /* Functions used by the Look In combo box */
00213 static void    FILEDLG95_LOOKIN_Init(HWND hwndCombo);
00214 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
00215 static BOOL    FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
00216 static int     FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
00217 static int     FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
00218 static int     FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
00219 static int     FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
00220        int     FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
00221 static void    FILEDLG95_LOOKIN_Clean(HWND hwnd);
00222 
00223 /* Functions for dealing with the most-recently-used registry keys */
00224 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
00225 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
00226 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
00227 
00228 /* Miscellaneous tool functions */
00229 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
00230 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
00231 LPITEMIDLIST  GetParentPidl(LPITEMIDLIST pidl);
00232 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
00233 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
00234 static UINT GetNumSelected( IDataObject *doSelected );
00235 
00236 /* Shell memory allocation */
00237 static void *MemAlloc(UINT size);
00238 static void MemFree(void *mem);
00239 
00240 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
00241 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
00242 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
00243 static BOOL BrowseSelectedFolder(HWND hwnd);
00244 
00245 /***********************************************************************
00246  *      GetFileName95
00247  *
00248  * Creates an Open common dialog box that lets the user select
00249  * the drive, directory, and the name of a file or set of files to open.
00250  *
00251  * IN  : The FileOpenDlgInfos structure associated with the dialog
00252  * OUT : TRUE on success
00253  *       FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
00254  */
00255 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
00256 {
00257 
00258     LRESULT lRes;
00259     LPVOID template;
00260     HRSRC hRes;
00261     HANDLE hDlgTmpl = 0;
00262     HRESULT hr;
00263 
00264     /* test for missing functionality */
00265     if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
00266     {
00267       FIXME("Flags 0x%08x not yet implemented\n",
00268          fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
00269     }
00270 
00271     /* Create the dialog from a template */
00272 
00273     if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
00274     {
00275         COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
00276         return FALSE;
00277     }
00278     if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
00279         !(template = LockResource( hDlgTmpl )))
00280     {
00281         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
00282         return FALSE;
00283     }
00284 
00285     /* msdn: explorer style dialogs permit sizing by default.
00286      * The OFN_ENABLESIZING flag is only needed when a hook or
00287      * custom tmeplate is provided */
00288     if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
00289             !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
00290         fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
00291 
00292     if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
00293     {
00294         ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
00295         fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
00296         fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
00297     }
00298     else
00299         ((LPDLGTEMPLATEW)template)->style &= ~WS_SIZEBOX;
00300 
00301 
00302     /* old style hook messages */
00303     if (IsHooked(fodInfos))
00304     {
00305       fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
00306       fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
00307       fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
00308       fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
00309     }
00310 
00311     /* Some shell namespace extensions depend on COM being initialized. */
00312     hr = OleInitialize(NULL);
00313 
00314     if (fodInfos->unicode)
00315       lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
00316                                      template,
00317                                      fodInfos->ofnInfos->hwndOwner,
00318                                      FileOpenDlgProc95,
00319                                      (LPARAM) fodInfos);
00320     else
00321       lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
00322                                      template,
00323                                      fodInfos->ofnInfos->hwndOwner,
00324                                      FileOpenDlgProc95,
00325                                      (LPARAM) fodInfos);
00326     if (SUCCEEDED(hr)) 
00327         OleUninitialize();
00328 
00329     /* Unable to create the dialog */
00330     if( lRes == -1)
00331         return FALSE;
00332 
00333     return lRes;
00334 }
00335 
00336 /***********************************************************************
00337  *      GetFileDialog95A
00338  *
00339  * Call GetFileName95 with this structure and clean the memory.
00340  *
00341  * IN  : The OPENFILENAMEA initialisation structure passed to
00342  *       GetOpenFileNameA win api function (see filedlg.c)
00343  */
00344 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
00345 {
00346   BOOL ret;
00347   FileOpenDlgInfos fodInfos;
00348   LPSTR lpstrSavDir = NULL;
00349   LPWSTR title = NULL;
00350   LPWSTR defext = NULL;
00351   LPWSTR filter = NULL;
00352   LPWSTR customfilter = NULL;
00353 
00354   /* Initialize CommDlgExtendedError() */
00355   COMDLG32_SetCommDlgExtendedError(0);
00356 
00357   /* Initialize FileOpenDlgInfos structure */
00358   ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
00359 
00360   /* Pass in the original ofn */
00361   fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
00362 
00363   /* save current directory */
00364   if (ofn->Flags & OFN_NOCHANGEDIR)
00365   {
00366      lpstrSavDir = MemAlloc(MAX_PATH);
00367      GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
00368   }
00369 
00370   fodInfos.unicode = FALSE;
00371 
00372   /* convert all the input strings to unicode */
00373   if(ofn->lpstrInitialDir)
00374   {
00375     DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
00376     fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
00377     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
00378   }
00379   else
00380     fodInfos.initdir = NULL;
00381 
00382   if(ofn->lpstrFile)
00383   {
00384     fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
00385     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
00386   }
00387   else
00388     fodInfos.filename = NULL;
00389 
00390   if(ofn->lpstrDefExt)
00391   {
00392     DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
00393     defext = MemAlloc((len+1)*sizeof(WCHAR));
00394     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
00395   }
00396   fodInfos.defext = defext;
00397 
00398   if(ofn->lpstrTitle)
00399   {
00400     DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
00401     title = MemAlloc((len+1)*sizeof(WCHAR));
00402     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
00403   }
00404   fodInfos.title = title;
00405 
00406   if (ofn->lpstrFilter)
00407   {
00408     LPCSTR s;
00409     int n, len;
00410 
00411     /* filter is a list...  title\0ext\0......\0\0 */
00412     s = ofn->lpstrFilter;
00413     while (*s) s = s+strlen(s)+1;
00414     s++;
00415     n = s - ofn->lpstrFilter;
00416     len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
00417     filter = MemAlloc(len*sizeof(WCHAR));
00418     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
00419   }
00420   fodInfos.filter = filter;
00421 
00422   /* convert lpstrCustomFilter */
00423   if (ofn->lpstrCustomFilter)
00424   {
00425     LPCSTR s;
00426     int n, len;
00427 
00428     /* customfilter contains a pair of strings...  title\0ext\0 */
00429     s = ofn->lpstrCustomFilter;
00430     if (*s) s = s+strlen(s)+1;
00431     if (*s) s = s+strlen(s)+1;
00432     n = s - ofn->lpstrCustomFilter;
00433     len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
00434     customfilter = MemAlloc(len*sizeof(WCHAR));
00435     MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
00436   }
00437   fodInfos.customfilter = customfilter;
00438 
00439   /* Initialize the dialog property */
00440   fodInfos.DlgInfos.dwDlgProp = 0;
00441   fodInfos.DlgInfos.hwndCustomDlg = NULL;
00442 
00443   switch(iDlgType)
00444   {
00445     case OPEN_DIALOG :
00446       ret = GetFileName95(&fodInfos);
00447       break;
00448     case SAVE_DIALOG :
00449       fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
00450       ret = GetFileName95(&fodInfos);
00451       break;
00452     default :
00453       ret = 0;
00454   }
00455 
00456   if (lpstrSavDir)
00457   {
00458       SetCurrentDirectoryA(lpstrSavDir);
00459       MemFree(lpstrSavDir);
00460   }
00461 
00462   MemFree(title);
00463   MemFree(defext);
00464   MemFree(filter);
00465   MemFree(customfilter);
00466   MemFree(fodInfos.initdir);
00467   MemFree(fodInfos.filename);
00468 
00469   TRACE("selected file: %s\n",ofn->lpstrFile);
00470 
00471   return ret;
00472 }
00473 
00474 /***********************************************************************
00475  *      GetFileDialog95W
00476  *
00477  * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
00478  * Call GetFileName95 with this structure and clean the memory.
00479  *
00480  */
00481 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
00482 {
00483   BOOL ret;
00484   FileOpenDlgInfos fodInfos;
00485   LPWSTR lpstrSavDir = NULL;
00486 
00487   /* Initialize CommDlgExtendedError() */
00488   COMDLG32_SetCommDlgExtendedError(0);
00489 
00490   /* Initialize FileOpenDlgInfos structure */
00491   ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
00492 
00493   /*  Pass in the original ofn */
00494   fodInfos.ofnInfos = ofn;
00495 
00496   fodInfos.title = ofn->lpstrTitle;
00497   fodInfos.defext = ofn->lpstrDefExt;
00498   fodInfos.filter = ofn->lpstrFilter;
00499   fodInfos.customfilter = ofn->lpstrCustomFilter;
00500 
00501   /* convert string arguments, save others */
00502   if(ofn->lpstrFile)
00503   {
00504     fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
00505     lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
00506   }
00507   else
00508     fodInfos.filename = NULL;
00509 
00510   if(ofn->lpstrInitialDir)
00511   {
00512     /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
00513     DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
00514     fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
00515     memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
00516   }
00517   else
00518     fodInfos.initdir = NULL;
00519 
00520   /* save current directory */
00521   if (ofn->Flags & OFN_NOCHANGEDIR)
00522   {
00523      lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
00524      GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
00525   }
00526 
00527   fodInfos.unicode = TRUE;
00528 
00529   switch(iDlgType)
00530   {
00531   case OPEN_DIALOG :
00532       ret = GetFileName95(&fodInfos);
00533       break;
00534   case SAVE_DIALOG :
00535       fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
00536       ret = GetFileName95(&fodInfos);
00537       break;
00538   default :
00539       ret = 0;
00540   }
00541 
00542   if (lpstrSavDir)
00543   {
00544       SetCurrentDirectoryW(lpstrSavDir);
00545       MemFree(lpstrSavDir);
00546   }
00547 
00548   /* restore saved IN arguments and convert OUT arguments back */
00549   MemFree(fodInfos.filename);
00550   MemFree(fodInfos.initdir);
00551   return ret;
00552 }
00553 
00554 /******************************************************************************
00555  * COMDLG32_GetDisplayNameOf [internal]
00556  *
00557  * Helper function to get the display name for a pidl.
00558  */
00559 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
00560     LPSHELLFOLDER psfDesktop;
00561     STRRET strret;
00562         
00563     if (FAILED(SHGetDesktopFolder(&psfDesktop)))
00564         return FALSE;
00565 
00566     if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
00567         IShellFolder_Release(psfDesktop);
00568         return FALSE;
00569     }
00570 
00571     IShellFolder_Release(psfDesktop);
00572     return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
00573 }
00574 
00575 /******************************************************************************
00576  * COMDLG32_GetCanonicalPath [internal]
00577  *
00578  * Helper function to get the canonical path.
00579  */
00580 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
00581                                LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
00582 {
00583   WCHAR lpstrTemp[MAX_PATH];
00584 
00585   /* Get the current directory name */
00586   if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
00587   {
00588     /* last fallback */
00589     GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
00590   }
00591   PathAddBackslashW(lpstrPathAndFile);
00592 
00593   TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
00594 
00595   /* if the user specified a fully qualified path use it */
00596   if(PathIsRelativeW(lpstrFile))
00597   {
00598     lstrcatW(lpstrPathAndFile, lpstrFile);
00599   }
00600   else
00601   {
00602     /* does the path have a drive letter? */
00603     if (PathGetDriveNumberW(lpstrFile) == -1)
00604       lstrcpyW(lpstrPathAndFile+2, lpstrFile);
00605     else
00606       lstrcpyW(lpstrPathAndFile, lpstrFile);
00607   }
00608 
00609   /* resolve "." and ".." */
00610   PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
00611   lstrcpyW(lpstrPathAndFile, lpstrTemp);
00612   TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
00613 }
00614 
00615 /***********************************************************************
00616  *      COMDLG32_SplitFileNames [internal]
00617  *
00618  * Creates a delimited list of filenames.
00619  */
00620 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
00621 {
00622     UINT nStrCharCount = 0; /* index in src buffer */
00623     UINT nFileIndex = 0;    /* index in dest buffer */
00624     UINT nFileCount = 0;    /* number of files */
00625 
00626     /* we might get single filename without any '"',
00627      * so we need nStrLen + terminating \0 + end-of-list \0 */
00628     *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
00629     *sizeUsed = 0;
00630 
00631     /* build delimited file list from filenames */
00632     while ( nStrCharCount <= nStrLen )
00633     {
00634       if ( lpstrEdit[nStrCharCount]=='"' )
00635       {
00636         nStrCharCount++;
00637         while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
00638         {
00639           (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
00640           nStrCharCount++;
00641         }
00642         (*lpstrFileList)[nFileIndex++] = 0;
00643         nFileCount++;
00644       }
00645       nStrCharCount++;
00646     }
00647 
00648     /* single, unquoted string */
00649     if ((nStrLen > 0) && (nFileIndex == 0) )
00650     {
00651       lstrcpyW(*lpstrFileList, lpstrEdit);
00652       nFileIndex = lstrlenW(lpstrEdit) + 1;
00653       nFileCount = 1;
00654     }
00655 
00656         /* trailing \0 */
00657         (*lpstrFileList)[nFileIndex++] = '\0';
00658 
00659         *sizeUsed = nFileIndex;
00660     return nFileCount;
00661 }
00662 
00663 /***********************************************************************
00664  *      ArrangeCtrlPositions [internal]
00665  *
00666  * NOTE: Make sure to add testcases for any changes made here.
00667  */
00668 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
00669 {
00670     HWND hwndChild, hwndStc32;
00671     RECT rectParent, rectChild, rectStc32;
00672     INT help_fixup = 0;
00673     int chgx, chgy;
00674 
00675     /* Take into account if open as read only checkbox and help button
00676      * are hidden
00677      */
00678      if (hide_help)
00679      {
00680          RECT rectHelp, rectCancel;
00681          GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
00682          GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
00683          /* subtract the height of the help button plus the space between
00684           * the help button and the cancel button to the height of the dialog
00685           */
00686           help_fixup = rectHelp.bottom - rectCancel.bottom;
00687     }
00688 
00689     /*
00690       There are two possibilities to add components to the default file dialog box.
00691 
00692       By default, all the new components are added below the standard dialog box (the else case).
00693 
00694       However, if there is a static text component with the stc32 id, a special case happens.
00695       The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
00696       in the window and the cx and cy indicate how to size the window.
00697       Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left 
00698       of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
00699       
00700      */
00701 
00702     GetClientRect(hwndParentDlg, &rectParent);
00703 
00704     /* when arranging controls we have to use fixed parent size */
00705     rectParent.bottom -= help_fixup;
00706 
00707     hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
00708     if (hwndStc32)
00709     {
00710         GetWindowRect(hwndStc32, &rectStc32);
00711         MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
00712 
00713         /* set the size of the stc32 control according to the size of
00714          * client area of the parent dialog
00715          */
00716         SetWindowPos(hwndStc32, 0,
00717                      0, 0,
00718                      rectParent.right, rectParent.bottom,
00719                      SWP_NOMOVE | SWP_NOZORDER);
00720     }
00721     else
00722         SetRectEmpty(&rectStc32);
00723 
00724     /* this part moves controls of the child dialog */
00725     hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
00726     while (hwndChild)
00727     {
00728         if (hwndChild != hwndStc32)
00729         {
00730             GetWindowRect(hwndChild, &rectChild);
00731             MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
00732 
00733             /* move only if stc32 exist */
00734             if (hwndStc32 && rectChild.left > rectStc32.right)
00735             {
00736                 /* move to the right of visible controls of the parent dialog */
00737                 rectChild.left += rectParent.right;
00738                 rectChild.left -= rectStc32.right;
00739             }
00740             /* move even if stc32 doesn't exist */
00741             if (rectChild.top >= rectStc32.bottom)
00742             {
00743                 /* move below visible controls of the parent dialog */
00744                 rectChild.top += rectParent.bottom;
00745                 rectChild.top -= rectStc32.bottom - rectStc32.top;
00746             }
00747 
00748             SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
00749                          0, 0, SWP_NOSIZE | SWP_NOZORDER);
00750         }
00751         hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
00752     }
00753 
00754     /* this part moves controls of the parent dialog */
00755     hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
00756     while (hwndChild)
00757     {
00758         if (hwndChild != hwndChildDlg)
00759         {
00760             GetWindowRect(hwndChild, &rectChild);
00761             MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
00762 
00763             /* left,top of stc32 marks the position of controls
00764              * from the parent dialog
00765              */
00766             rectChild.left += rectStc32.left;
00767             rectChild.top += rectStc32.top;
00768 
00769             SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
00770                          0, 0, SWP_NOSIZE | SWP_NOZORDER);
00771         }
00772         hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
00773     }
00774 
00775     /* calculate the size of the resulting dialog */
00776 
00777     /* here we have to use original parent size */
00778     GetClientRect(hwndParentDlg, &rectParent);
00779     GetClientRect(hwndChildDlg, &rectChild);
00780     TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
00781             wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
00782 
00783     if (hwndStc32)
00784     {
00785         /* width */
00786         if (rectParent.right > rectStc32.right - rectStc32.left)
00787             chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
00788         else
00789             chgx = rectChild.right - rectParent.right;
00790         /* height */
00791         if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
00792             chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
00793         else
00794             /* Unconditionally set new dialog
00795              * height to that of the child
00796              */
00797             chgy = rectChild.bottom - rectParent.bottom;
00798     }
00799     else
00800     {
00801         chgx = 0;
00802         chgy = rectChild.bottom - help_fixup;
00803     }
00804     /* set the size of the parent dialog */
00805     GetWindowRect(hwndParentDlg, &rectParent);
00806     SetWindowPos(hwndParentDlg, 0,
00807                  0, 0,
00808                  rectParent.right - rectParent.left + chgx,
00809                  rectParent.bottom - rectParent.top + chgy,
00810                  SWP_NOMOVE | SWP_NOZORDER);
00811 }
00812 
00813 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00814 {
00815     switch(uMsg) {
00816     case WM_INITDIALOG:
00817         return TRUE;
00818     }
00819     return FALSE;
00820 }
00821 
00822 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
00823 {
00824     LPCVOID template;
00825     HRSRC hRes;
00826     HANDLE hDlgTmpl = 0;
00827     HWND hChildDlg = 0;
00828 
00829     TRACE("\n");
00830 
00831     /*
00832      * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
00833      * structure's hInstance parameter is not a HINSTANCE, but
00834      * instead a pointer to a template resource to use.
00835      */
00836     if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
00837     {
00838       HINSTANCE hinst;
00839       if (fodInfos->ofnInfos->Flags  & OFN_ENABLETEMPLATEHANDLE)
00840       {
00841         hinst = COMDLG32_hInstance;
00842         if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
00843         {
00844           COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
00845           return NULL;
00846         }
00847       }
00848       else
00849       {
00850         hinst = fodInfos->ofnInfos->hInstance;
00851         if(fodInfos->unicode)
00852         {
00853             LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
00854             hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
00855         }
00856         else
00857         {
00858             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
00859             hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
00860         }
00861         if (!hRes)
00862         {
00863           COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
00864           return NULL;
00865         }
00866         if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
00867             !(template = LockResource( hDlgTmpl )))
00868         {
00869           COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
00870           return NULL;
00871         }
00872       }
00873       if (fodInfos->unicode)
00874           hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
00875               IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
00876               (LPARAM)fodInfos->ofnInfos);
00877       else
00878           hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
00879               IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
00880               (LPARAM)fodInfos->ofnInfos);
00881       return hChildDlg;
00882     }
00883     else if( IsHooked(fodInfos))
00884     {
00885       RECT rectHwnd;
00886       struct  {
00887          DLGTEMPLATE tmplate;
00888          WORD menu,class,title;
00889          } temp;
00890       GetClientRect(hwnd,&rectHwnd);
00891       temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
00892       temp.tmplate.dwExtendedStyle = 0;
00893       temp.tmplate.cdit = 0;
00894       temp.tmplate.x = 0;
00895       temp.tmplate.y = 0;
00896       temp.tmplate.cx = 0;
00897       temp.tmplate.cy = 0;
00898       temp.menu = temp.class = temp.title = 0;
00899 
00900       hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
00901                   hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
00902 
00903       return hChildDlg;
00904     }
00905     return NULL;
00906 }
00907 
00908 /***********************************************************************
00909 *          SendCustomDlgNotificationMessage
00910 *
00911 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
00912 */
00913 
00914 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
00915 {
00916     LRESULT hook_result = 0;
00917     FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
00918 
00919     TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
00920 
00921     if(!fodInfos) return 0;
00922 
00923     if(fodInfos->DlgInfos.hwndCustomDlg)
00924     {
00925     TRACE("CALL NOTIFY for %x\n", uCode);
00926         if(fodInfos->unicode)
00927         {
00928             OFNOTIFYW ofnNotify;
00929             ofnNotify.hdr.hwndFrom=hwndParentDlg;
00930             ofnNotify.hdr.idFrom=0;
00931             ofnNotify.hdr.code = uCode;
00932             ofnNotify.lpOFN = fodInfos->ofnInfos;
00933             ofnNotify.pszFile = NULL;
00934             hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
00935         }
00936         else
00937         {
00938             OFNOTIFYA ofnNotify;
00939             ofnNotify.hdr.hwndFrom=hwndParentDlg;
00940             ofnNotify.hdr.idFrom=0;
00941             ofnNotify.hdr.code = uCode;
00942             ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
00943             ofnNotify.pszFile = NULL;
00944             hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
00945         }
00946     TRACE("RET NOTIFY\n");
00947     }
00948     TRACE("Retval: 0x%08lx\n", hook_result);
00949     return hook_result;
00950 }
00951 
00952 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
00953 {
00954     UINT len, total;
00955     WCHAR *p, *buffer;
00956     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
00957 
00958     TRACE("CDM_GETFILEPATH:\n");
00959 
00960     if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
00961         return -1;
00962 
00963     /* get path and filenames */
00964     len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
00965     buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
00966     COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
00967     if (len)
00968     {
00969         p = buffer + strlenW(buffer);
00970         *p++ = '\\';
00971         SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
00972     }
00973     if (fodInfos->unicode)
00974     {
00975         total = strlenW( buffer) + 1;
00976         if (result) lstrcpynW( result, buffer, size );
00977         TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
00978     }
00979     else
00980     {
00981         total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
00982         if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
00983         TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
00984     }
00985     HeapFree( GetProcessHeap(), 0, buffer );
00986     return total;
00987 }
00988 
00989 /***********************************************************************
00990 *         FILEDLG95_HandleCustomDialogMessages
00991 *
00992 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
00993 */
00994 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00995 {
00996     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
00997     WCHAR lpstrPath[MAX_PATH];
00998     INT_PTR retval;
00999 
01000     if(!fodInfos) return FALSE;
01001 
01002     switch(uMsg)
01003     {
01004         case CDM_GETFILEPATH:
01005             retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
01006             break;
01007 
01008         case CDM_GETFOLDERPATH:
01009             TRACE("CDM_GETFOLDERPATH:\n");
01010             COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
01011             if (lParam) 
01012             {
01013                 if (fodInfos->unicode)
01014                     lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
01015                 else
01016                     WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1, 
01017                                         (LPSTR)lParam, (int)wParam, NULL, NULL);
01018             }        
01019             retval = lstrlenW(lpstrPath) + 1;
01020             break;
01021 
01022         case CDM_GETFOLDERIDLIST:
01023             retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
01024             if (retval <= wParam)
01025                 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
01026             break;
01027 
01028         case CDM_GETSPEC:
01029             TRACE("CDM_GETSPEC:\n");
01030             retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
01031             if (lParam)
01032             {
01033                 if (fodInfos->unicode)
01034                     SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
01035                 else
01036                     SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
01037             }
01038             break;
01039 
01040         case CDM_SETCONTROLTEXT:
01041             TRACE("CDM_SETCONTROLTEXT:\n");
01042         if ( lParam )
01043             {
01044                 if( fodInfos->unicode )
01045                 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
01046                 else
01047                 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
01048             }
01049             retval = TRUE;
01050             break;
01051 
01052         case CDM_HIDECONTROL:
01053             /* MSDN states that it should fail for not OFN_EXPLORER case */
01054             if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
01055             {
01056                 HWND control = GetDlgItem( hwnd, wParam );
01057                 if (control) ShowWindow( control, SW_HIDE );
01058                 retval = TRUE;
01059             }
01060             else retval = FALSE;
01061             break;
01062 
01063         default:
01064             if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
01065                 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
01066             return FALSE;
01067     }
01068     SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
01069     return TRUE;
01070 }
01071 
01072 /***********************************************************************
01073  *          FILEDLG95_OnWMGetMMI
01074  *
01075  * WM_GETMINMAXINFO message handler for resizable dialogs
01076  */
01077 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
01078 {
01079     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
01080     if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
01081     if( fodInfos->initial_size.x || fodInfos->initial_size.y)
01082     {
01083         mmiptr->ptMinTrackSize = fodInfos->initial_size;
01084     }
01085     return TRUE;
01086 }
01087 
01088 /***********************************************************************
01089  *          FILEDLG95_OnWMSize
01090  *
01091  * WM_SIZE message handler, resize the dialog. Re-arrange controls.
01092  *
01093  * FIXME: this could be made more elaborate. Now use a simple scheme
01094  * where the file view is enlarged and the controls are either moved
01095  * vertically or horizontally to get out of the way. Only the "grip"
01096  * is moved in both directions to stay in the corner.
01097  */
01098 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
01099 {
01100     RECT rc, rcview;
01101     int chgx, chgy;
01102     HWND ctrl;
01103     HDWP hdwp;
01104     FileOpenDlgInfos *fodInfos;
01105 
01106     if( wParam != SIZE_RESTORED) return FALSE;
01107     fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
01108     if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
01109     /* get the new dialog rectangle */
01110     GetWindowRect( hwnd, &rc);
01111     TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
01112             rc.right -rc.left, rc.bottom -rc.top);
01113     /* not initialized yet */
01114     if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
01115         ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
01116              (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
01117         return FALSE;
01118     chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
01119     chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
01120     fodInfos->sizedlg.cx = rc.right - rc.left;
01121     fodInfos->sizedlg.cy = rc.bottom - rc.top;
01122     /* change the size of the view window */
01123     GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
01124     MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
01125     hdwp = BeginDeferWindowPos( 10);
01126     DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
01127             rcview.right - rcview.left + chgx,
01128             rcview.bottom - rcview.top + chgy,
01129             SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
01130     /* change position and sizes of the controls */
01131     for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
01132     {
01133         int ctrlid = GetDlgCtrlID( ctrl);
01134         GetWindowRect( ctrl, &rc);
01135         MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
01136         if( ctrl == fodInfos->DlgInfos.hwndGrip)
01137         {
01138             DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
01139                     0, 0,
01140                     SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
01141         }
01142         else if( rc.top > rcview.bottom)
01143         {
01144             /* if it was below the shell view
01145              * move to bottom */
01146             switch( ctrlid)
01147             {
01148                 /* file name box and file types combo change also width */
01149                 case edt1:
01150                 case cmb1:
01151                     DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
01152                             rc.right - rc.left + chgx, rc.bottom - rc.top,
01153                             SWP_NOACTIVATE | SWP_NOZORDER);
01154                     break;
01155                     /* then these buttons must move out of the way */
01156                 case IDOK:
01157                 case IDCANCEL:
01158                 case pshHelp:
01159                     DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
01160                             0, 0,
01161                             SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
01162                     break;
01163                 default:
01164                 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
01165                         0, 0,
01166                         SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
01167             }
01168         }
01169         else if( rc.left > rcview.right)
01170         {
01171             /* if it was to the right of the shell view
01172              * move to right */
01173             DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
01174                     0, 0,
01175                     SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
01176         }
01177         else
01178             /* special cases */
01179         {
01180             switch( ctrlid)
01181             {
01182 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
01183                 case IDC_LOOKIN:
01184                     DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
01185                             rc.right - rc.left + chgx, rc.bottom - rc.top,
01186                             SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
01187                     break;
01188                 case IDC_TOOLBARSTATIC:
01189                 case IDC_TOOLBAR:
01190                     DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
01191                             0, 0,
01192                             SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
01193                     break;
01194 #endif
01195                 /* not resized in windows. Since wine uses this invisible control
01196                  * to size the browser view it needs to be resized */
01197                 case IDC_SHELLSTATIC:
01198                     DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
01199                             rc.right - rc.left + chgx,
01200                             rc.bottom - rc.top + chgy,
01201                             SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
01202                     break;
01203             }
01204         }
01205     }
01206     if(fodInfos->DlgInfos.hwndCustomDlg &&
01207         (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
01208     {
01209         for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
01210                 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
01211         {
01212             GetWindowRect( ctrl, &rc);
01213             MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
01214             if( rc.top > rcview.bottom)
01215             {
01216                 /* if it was below the shell view
01217                  * move to bottom */
01218                 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
01219                         rc.right - rc.left, rc.bottom - rc.top,
01220                         SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
01221             }
01222             else if( rc.left > rcview.right)
01223             {
01224                 /* if it was to the right of the shell view
01225                  * move to right */
01226                 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
01227                         rc.right - rc.left, rc.bottom - rc.top,
01228                         SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
01229             }
01230         }
01231         /* size the custom dialog at the end: some applications do some
01232          * control re-arranging at this point */
01233         GetClientRect(hwnd, &rc);
01234         DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
01235             0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
01236     }
01237     EndDeferWindowPos( hdwp);
01238     /* should not be needed */
01239     RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
01240     return TRUE;
01241 }
01242 
01243 /***********************************************************************
01244  *          FileOpenDlgProc95
01245  *
01246  * File open dialog procedure
01247  */
01248 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
01249 {
01250 #if 0
01251   TRACE("%p 0x%04x\n", hwnd, uMsg);
01252 #endif
01253 
01254   switch(uMsg)
01255   {
01256     case WM_INITDIALOG:
01257       {
01258          FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
01259          RECT rc, rcstc;
01260          int gripx = GetSystemMetrics( SM_CYHSCROLL);
01261          int gripy = GetSystemMetrics( SM_CYVSCROLL);
01262 
01263      /* Adds the FileOpenDlgInfos in the property list of the dialog
01264             so it will be easily accessible through a GetPropA(...) */
01265          SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
01266 
01267          FILEDLG95_InitControls(hwnd);
01268 
01269          if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
01270          {
01271              GetWindowRect( hwnd, &rc);
01272              fodInfos->DlgInfos.hwndGrip =
01273                  CreateWindowExA( 0, "SCROLLBAR", NULL,
01274                      WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
01275                      SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
01276                      rc.right - gripx, rc.bottom - gripy,
01277                      gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
01278          }
01279 
01280          fodInfos->DlgInfos.hwndCustomDlg =
01281            CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
01282 
01283          FILEDLG95_ResizeControls(hwnd, wParam, lParam);
01284          FILEDLG95_FillControls(hwnd, wParam, lParam);
01285 
01286          if( fodInfos->DlgInfos.hwndCustomDlg)
01287              ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
01288 
01289          if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
01290              SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
01291              SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
01292          }
01293 
01294          /* if the app has changed the position of the invisible listbox,
01295           * change that of the listview (browser) as well */
01296          GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
01297          GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
01298          if( !EqualRect( &rc, &rcstc))
01299          {
01300              MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
01301              SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
01302                      rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
01303                      SWP_NOACTIVATE | SWP_NOZORDER);
01304          }
01305 
01306          if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
01307          {
01308              GetWindowRect( hwnd, &rc);
01309              fodInfos->sizedlg.cx = rc.right - rc.left;
01310              fodInfos->sizedlg.cy = rc.bottom - rc.top;
01311              fodInfos->initial_size.x = fodInfos->sizedlg.cx;
01312              fodInfos->initial_size.y = fodInfos->sizedlg.cy;
01313              GetClientRect( hwnd, &rc);
01314              SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
01315                      rc.right - gripx, rc.bottom - gripy,
01316                      0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
01317              /* resize the dialog to the previous invocation */
01318              if( MemDialogSize.cx && MemDialogSize.cy)
01319                  SetWindowPos( hwnd, NULL,
01320                          0, 0, MemDialogSize.cx, MemDialogSize.cy,
01321                          SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
01322          }
01323 
01324          if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
01325              SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
01326 
01327          return 0;
01328        }
01329     case WM_SIZE:
01330       return FILEDLG95_OnWMSize(hwnd, wParam);
01331     case WM_GETMINMAXINFO:
01332       return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
01333     case WM_COMMAND:
01334       return FILEDLG95_OnWMCommand(hwnd, wParam);
01335     case WM_DRAWITEM:
01336       {
01337         switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
01338         {
01339         case IDC_LOOKIN:
01340           FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
01341           return TRUE;
01342         }
01343       }
01344       return FALSE;
01345 
01346     case WM_GETISHELLBROWSER:
01347       return FILEDLG95_OnWMGetIShellBrowser(hwnd);
01348 
01349     case WM_DESTROY:
01350       {
01351           FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
01352           if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
01353               MemDialogSize = fodInfos->sizedlg;
01354           RemovePropA(hwnd, FileOpenDlgInfosStr);
01355           return FALSE;
01356       }
01357     case WM_NOTIFY:
01358     {
01359     LPNMHDR lpnmh = (LPNMHDR)lParam;
01360     UINT stringId = -1;
01361 
01362     /* set up the button tooltips strings */
01363     if(TTN_GETDISPINFOA == lpnmh->code )
01364     {
01365         LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
01366         switch(lpnmh->idFrom )
01367         {
01368         /* Up folder button */
01369         case FCIDM_TB_UPFOLDER:
01370             stringId = IDS_UPFOLDER;
01371             break;
01372         /* New folder button */
01373         case FCIDM_TB_NEWFOLDER:
01374             stringId = IDS_NEWFOLDER;
01375             break;
01376         /* List option button */
01377         case FCIDM_TB_SMALLICON:
01378             stringId = IDS_LISTVIEW;
01379             break;
01380         /* Details option button */
01381         case FCIDM_TB_REPORTVIEW:
01382             stringId = IDS_REPORTVIEW;
01383             break;
01384         /* Desktop button */
01385         case FCIDM_TB_DESKTOP:
01386             stringId = IDS_TODESKTOP;
01387             break;
01388         default:
01389             stringId = 0;
01390         }
01391         lpdi->hinst = COMDLG32_hInstance;
01392         lpdi->lpszText =  MAKEINTRESOURCEA(stringId);
01393     }
01394         return FALSE;
01395     }
01396     default :
01397       if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
01398         return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
01399       return FALSE;
01400   }
01401 }
01402 
01403 /***********************************************************************
01404  *      FILEDLG95_InitControls
01405  *
01406  * WM_INITDIALOG message handler (before hook notification)
01407  */
01408 static LRESULT FILEDLG95_InitControls(HWND hwnd)
01409 {
01410   int win2000plus = 0;
01411   int win98plus   = 0;
01412   int handledPath = FALSE;
01413   OSVERSIONINFOW osVi;
01414   static const WCHAR szwSlash[] = { '\\', 0 };
01415   static const WCHAR szwStar[] = { '*',0 };
01416 
01417   static const TBBUTTON tbb[] =
01418   {
01419    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
01420    {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER,   TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
01421    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
01422    {VIEW_NEWFOLDER+1,  FCIDM_TB_DESKTOP,    TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
01423    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
01424    {VIEW_NEWFOLDER,    FCIDM_TB_NEWFOLDER,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
01425    {0,                 0,                   TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
01426    {VIEW_LIST,         FCIDM_TB_SMALLICON,  TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
01427    {VIEW_DETAILS,      FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
01428   };
01429   static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
01430 
01431   RECT rectTB;
01432   RECT rectlook;
01433 
01434   HIMAGELIST toolbarImageList;
01435   SHFILEINFOA shFileInfo;
01436   ITEMIDLIST *desktopPidl;
01437 
01438   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
01439 
01440   TRACE("%p\n", fodInfos);
01441 
01442   /* Get windows version emulating */
01443   osVi.dwOSVersionInfoSize = sizeof(osVi);
01444   GetVersionExW(&osVi);
01445   if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
01446     win98plus   = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
01447   } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
01448     win2000plus = (osVi.dwMajorVersion > 4);
01449     if (win2000plus) win98plus = TRUE;
01450   }
01451   TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
01452 
01453   /* Get the hwnd of the controls */
01454   fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
01455   fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
01456   fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
01457 
01458   GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
01459   MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
01460 
01461   /* construct the toolbar */
01462   GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
01463   MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
01464 
01465   rectTB.right = rectlook.right + rectTB.right - rectTB.left;
01466   rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
01467   rectTB.left = rectlook.right;
01468   rectTB.top = rectlook.top-1;
01469 
01470   if (fodInfos->unicode)
01471       fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
01472           WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
01473           rectTB.left, rectTB.top,
01474           rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
01475           hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
01476   else
01477       fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
01478           WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
01479           rectTB.left, rectTB.top,
01480           rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
01481           hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
01482 
01483   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
01484 
01485 /* FIXME: use TB_LOADIMAGES when implemented */
01486 /*  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
01487   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
01488   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
01489 
01490   /* Retrieve and add desktop icon to the toolbar */
01491   toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
01492   SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
01493   SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
01494     SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
01495   ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
01496 
01497   DestroyIcon(shFileInfo.hIcon);
01498   CoTaskMemFree(desktopPidl);
01499 
01500   /* Finish Toolbar Construction */
01501   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
01502   SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
01503 
01504   /* Set the window text with the text specified in the OPENFILENAME structure */
01505   if(fodInfos->title)
01506   {
01507       SetWindowTextW(hwnd,fodInfos->title);
01508   }
01509   else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
01510   {
01511       WCHAR buf[64];
01512       LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, sizeof(buf)/sizeof(WCHAR));
01513       SetWindowTextW(hwnd, buf);
01514   }
01515 
01516   /* Initialise the file name edit control */
01517   handledPath = FALSE;
01518   TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
01519 
01520   if(fodInfos->filename)
01521   {
01522       /* 1. If win2000 or higher and filename contains a path, use it
01523          in preference over the lpstrInitialDir                       */
01524       if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
01525          WCHAR tmpBuf[MAX_PATH];
01526          WCHAR *nameBit;
01527          DWORD result;
01528 
01529          result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
01530          if (result) {
01531 
01532             /* nameBit is always shorter than the original filename */
01533             lstrcpyW(fodInfos->filename,nameBit);
01534 
01535             *nameBit = 0x00;
01536             MemFree(fodInfos->initdir);
01537             fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
01538             lstrcpyW(fodInfos->initdir, tmpBuf);
01539             handledPath = TRUE;
01540             TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
01541                     debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
01542          }
01543          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
01544 
01545       } else {
01546          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
01547       }
01548   }
01549 
01550   /* 2. (All platforms) If initdir is not null, then use it */
01551   if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
01552                                 (*fodInfos->initdir!=0x00))
01553   {
01554       /* Work out the proper path as supplied one might be relative          */
01555       /* (Here because supplying '.' as dir browses to My Computer)          */
01556       if (handledPath==FALSE) {
01557           WCHAR tmpBuf[MAX_PATH];
01558           WCHAR tmpBuf2[MAX_PATH];
01559           WCHAR *nameBit;
01560           DWORD result;
01561 
01562           lstrcpyW(tmpBuf, fodInfos->initdir);
01563           if( PathFileExistsW(tmpBuf) ) {
01564               /* initdir does not have to be a directory. If a file is
01565                * specified, the dir part is taken */
01566               if( PathIsDirectoryW(tmpBuf)) {
01567                   if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
01568                      lstrcatW(tmpBuf, szwSlash);
01569                   }
01570                   lstrcatW(tmpBuf, szwStar);
01571               }
01572               result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
01573               if (result) {
01574                  *nameBit = 0x00;
01575                  MemFree(fodInfos->initdir);
01576                  fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
01577                  lstrcpyW(fodInfos->initdir, tmpBuf2);
01578                  handledPath = TRUE;
01579                  TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
01580               }
01581           }
01582           else if (fodInfos->initdir)
01583           {
01584                     MemFree(fodInfos->initdir);
01585                     fodInfos->initdir = NULL;
01586                     TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
01587           }
01588       }
01589   }
01590 
01591   if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
01592                                  (*fodInfos->initdir==0x00)))
01593   {
01594       /* 3. All except w2k+: if filename contains a path use it */
01595       if (!win2000plus && fodInfos->filename &&
01596           *fodInfos->filename &&
01597           strpbrkW(fodInfos->filename, szwSlash)) {
01598          WCHAR tmpBuf[MAX_PATH];
01599          WCHAR *nameBit;
01600          DWORD result;
01601 
01602          result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
01603                                   tmpBuf, &nameBit);
01604          if (result) {
01605             int len;
01606 
01607             /* nameBit is always shorter than the original filename */
01608             lstrcpyW(fodInfos->filename, nameBit);
01609             *nameBit = 0x00;
01610 
01611             len = lstrlenW(tmpBuf);
01612             MemFree(fodInfos->initdir);
01613             fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
01614             lstrcpyW(fodInfos->initdir, tmpBuf);
01615 
01616             handledPath = TRUE;
01617             TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
01618                  debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
01619          }
01620          SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
01621       }
01622 
01623       /* 4. Win2000+: Recently used */
01624       if (handledPath == FALSE && win2000plus) {
01625           fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
01626           fodInfos->initdir[0] = '\0';
01627 
01628           FILEDLG95_MRU_load_filename(fodInfos->initdir);
01629 
01630           if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
01631              handledPath = TRUE;
01632           }else{
01633              MemFree(fodInfos->initdir);
01634              fodInfos->initdir = NULL;
01635           }
01636       }
01637 
01638       /* 5. win98+ and win2000+ if any files of specified filter types in
01639             current directory, use it                                      */
01640       if ( win98plus && handledPath == FALSE &&
01641            fodInfos->filter && *fodInfos->filter) {
01642 
01643          LPCWSTR lpstrPos = fodInfos->filter;
01644          WIN32_FIND_DATAW FindFileData;
01645          HANDLE hFind;
01646 
01647          while (1)
01648          {
01649            /* filter is a list...  title\0ext\0......\0\0 */
01650 
01651            /* Skip the title */
01652            if(! *lpstrPos) break;   /* end */
01653            lpstrPos += lstrlenW(lpstrPos) + 1;
01654 
01655            /* See if any files exist in the current dir with this extension */
01656            if(! *lpstrPos) break;   /* end */
01657 
01658            hFind = FindFirstFileW(lpstrPos, &FindFileData);
01659 
01660            if (hFind == INVALID_HANDLE_VALUE) {
01661                /* None found - continue search */
01662                lpstrPos += lstrlenW(lpstrPos) + 1;
01663 
01664            } else {
01665 
01666                MemFree(fodInfos->initdir);
01667                fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
01668                GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
01669 
01670                handledPath = TRUE;
01671                TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
01672                  debugstr_w(lpstrPos));
01673                FindClose(hFind);
01674                break;
01675            }
01676          }
01677       }
01678 
01679       /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
01680       if (handledPath == FALSE && (win2000plus || win98plus)) {
01681           fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
01682 
01683           if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
01684           {
01685             if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
01686             {
01687                 /* last fallback */
01688                 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
01689                 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
01690             } else {
01691                 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
01692             }
01693           } else {
01694             TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
01695           }
01696           handledPath = TRUE;
01697       } else if (handledPath==FALSE) {
01698           fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
01699           GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
01700           handledPath = TRUE;
01701           TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
01702       }
01703   }
01704   SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
01705   TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
01706 
01707   /* Must the open as read only check box be checked ?*/
01708   if(fodInfos->ofnInfos->Flags & OFN_READONLY)
01709   {
01710     SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
01711   }
01712 
01713   /* Must the open as read only check box be hidden? */
01714   if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
01715   {
01716     ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
01717     EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
01718   }
01719 
01720   /* Must the help button be hidden? */
01721   if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
01722   {
01723     ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
01724     EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
01725   }
01726 
01727   /* change Open to Save */
01728   if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
01729   {
01730       WCHAR buf[16];
01731       LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
01732       SetDlgItemTextW(hwnd, IDOK, buf);
01733       LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
01734       SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
01735   }
01736 
01737   /* Initialize the filter combo box */
01738   FILEDLG95_FILETYPE_Init(hwnd);
01739 
01740   return 0;
01741 }
01742 
01743 /***********************************************************************
01744  *      FILEDLG95_ResizeControls
01745  *
01746  * WM_INITDIALOG message handler (after hook notification)
01747  */
01748 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
01749 {
01750   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
01751 
01752   if (fodInfos->DlgInfos.hwndCustomDlg)
01753   {
01754     RECT rc;
01755     UINT flags = SWP_NOACTIVATE;
01756 
01757     ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
01758         (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
01759 
01760     /* resize the custom dialog to the parent size */
01761     if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
01762       GetClientRect(hwnd, &rc);
01763     else
01764     {
01765       /* our own fake template is zero sized and doesn't have children, so
01766        * there is no need to resize it. Picasa depends on it.
01767        */
01768       flags |= SWP_NOSIZE;
01769       SetRectEmpty(&rc);
01770     }
01771       SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
01772           0, 0, rc.right, rc.bottom, flags);
01773   }
01774   else
01775   {
01776     /* Resize the height, if open as read only checkbox ad help button are
01777      * hidden and we are not using a custom template nor a customDialog
01778      */
01779     if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
01780                 (!(fodInfos->ofnInfos->Flags &
01781                    (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
01782     {
01783       RECT rectDlg, rectHelp, rectCancel;
01784       GetWindowRect(hwnd, &rectDlg);
01785       GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
01786       GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
01787       /* subtract the height of the help button plus the space between the help
01788        * button and the cancel button to the height of the dialog
01789        */
01790       SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
01791           (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
01792           SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
01793     }
01794   }
01795   return TRUE;
01796 }
01797 
01798 /***********************************************************************
01799  *      FILEDLG95_FillControls
01800  *
01801  * WM_INITDIALOG message handler (after hook notification)
01802  */
01803 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
01804 {
01805   LPITEMIDLIST pidlItemId = NULL;
01806 
01807   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
01808 
01809   TRACE("dir=%s file=%s\n",
01810   debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
01811 
01812   /* Get the initial directory pidl */
01813 
01814   if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
01815   {
01816     WCHAR path[MAX_PATH];
01817 
01818     GetCurrentDirectoryW(MAX_PATH,path);
01819     pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
01820   }
01821 
01822   /* Initialise shell objects */
01823   FILEDLG95_SHELL_Init(hwnd);
01824 
01825   /* Initialize the Look In combo box */
01826   FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
01827 
01828   /* Browse to the initial directory */
01829   IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
01830 
01831   /* Free pidlItem memory */
01832   COMDLG32_SHFree(pidlItemId);
01833 
01834   return TRUE;
01835 }
01836 /***********************************************************************
01837  *      FILEDLG95_Clean
01838  *
01839  * Regroups all the cleaning functions of the filedlg
01840  */
01841 void FILEDLG95_Clean(HWND hwnd)
01842 {
01843       FILEDLG95_FILETYPE_Clean(hwnd);
01844       FILEDLG95_LOOKIN_Clean(hwnd);
01845       FILEDLG95_SHELL_Clean(hwnd);
01846 }
01847 /***********************************************************************
01848  *      FILEDLG95_OnWMCommand
01849  *
01850  * WM_COMMAND message handler
01851  */
01852 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
01853 {
01854   WORD wNotifyCode = HIWORD(wParam); /* notification code */
01855   WORD wID = LOWORD(wParam);         /* item, control, or accelerator identifier */
01856   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
01857 
01858   switch(wID)
01859   {
01860     /* OK button */
01861   case IDOK:
01862     FILEDLG95_OnOpen(hwnd);
01863     break;
01864     /* Cancel button */
01865   case IDCANCEL:
01866     FILEDLG95_Clean(hwnd);
01867     EndDialog(hwnd, FALSE);
01868     break;
01869     /* Filetype combo box */
01870   case IDC_FILETYPE:
01871     FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
01872     break;
01873     /* LookIn combo box */
01874   case IDC_LOOKIN:
01875     FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
01876     break;
01877 
01878   /* --- toolbar --- */
01879     /* Up folder button */
01880   case FCIDM_TB_UPFOLDER:
01881     FILEDLG95_SHELL_UpFolder(hwnd);
01882     break;
01883     /* New folder button */
01884   case FCIDM_TB_NEWFOLDER:
01885     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
01886     break;
01887     /* List option button */
01888   case FCIDM_TB_SMALLICON:
01889     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
01890     break;
01891     /* Details option button */
01892   case FCIDM_TB_REPORTVIEW:
01893     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
01894     break;
01895     /* Details option button */
01896   case FCIDM_TB_DESKTOP:
01897     FILEDLG95_SHELL_BrowseToDesktop(hwnd);
01898     break;
01899 
01900   case IDC_FILENAME:
01901     break;
01902 
01903   }
01904   /* Do not use the listview selection anymore */
01905   fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
01906   return 0;
01907 }
01908 
01909 /***********************************************************************
01910  *      FILEDLG95_OnWMGetIShellBrowser
01911  *
01912  * WM_GETISHELLBROWSER message handler
01913  */
01914 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
01915 {
01916   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
01917 
01918   TRACE("\n");
01919 
01920   SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
01921 
01922   return TRUE;
01923 }
01924 
01925 
01926 /***********************************************************************
01927  *      FILEDLG95_SendFileOK
01928  *
01929  * Sends the CDN_FILEOK notification if required
01930  *
01931  * RETURNS
01932  *  TRUE if the dialog should close
01933  *  FALSE if the dialog should not be closed
01934  */
01935 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
01936 {
01937     /* ask the hook if we can close */
01938     if(IsHooked(fodInfos))
01939     {
01940         LRESULT retval = 0;
01941 
01942         TRACE("---\n");
01943         /* First send CDN_FILEOK as MSDN doc says */
01944         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
01945             retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
01946         if( retval)
01947         {
01948             TRACE("canceled\n");
01949             return FALSE;
01950         }
01951 
01952         /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
01953         retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
01954                               fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
01955         if( retval)
01956         {
01957             TRACE("canceled\n");
01958             return FALSE;
01959         }
01960     }
01961     return TRUE;
01962 }
01963 
01964 /***********************************************************************
01965  *      FILEDLG95_OnOpenMultipleFiles
01966  *
01967  * Handles the opening of multiple files.
01968  *
01969  * FIXME
01970  *  check destination buffer size
01971  */
01972 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
01973 {
01974   WCHAR   lpstrPathSpec[MAX_PATH] = {0};
01975   UINT   nCount, nSizePath;
01976   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
01977 
01978   TRACE("\n");
01979 
01980   if(fodInfos->unicode)
01981   {
01982      LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
01983      ofn->lpstrFile[0] = '\0';
01984   }
01985   else
01986   {
01987      LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
01988      ofn->lpstrFile[0] = '\0';
01989   }
01990 
01991   COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
01992 
01993   if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
01994       ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
01995        ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
01996   {
01997     LPWSTR lpstrTemp = lpstrFileList;
01998 
01999     for ( nCount = 0; nCount < nFileCount; nCount++ )
02000     {
02001       LPITEMIDLIST pidl;
02002 
02003       pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
02004       if (!pidl)
02005       {
02006         WCHAR lpstrNotFound[100];
02007         WCHAR lpstrMsg[100];
02008         WCHAR tmp[400];
02009         static const WCHAR nl[] = {'\n',0};
02010 
02011         LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
02012         LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
02013 
02014         lstrcpyW(tmp, lpstrTemp);
02015         lstrcatW(tmp, nl);
02016         lstrcatW(tmp, lpstrNotFound);
02017         lstrcatW(tmp, nl);
02018         lstrcatW(tmp, lpstrMsg);
02019 
02020         MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
02021         return FALSE;
02022       }
02023 
02024       /* move to the next file in the list of files */
02025       lpstrTemp += lstrlenW(lpstrTemp) + 1;
02026       COMDLG32_SHFree(pidl);
02027     }
02028   }
02029 
02030   nSizePath = lstrlenW(lpstrPathSpec) + 1;
02031   if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
02032   {
02033     /* For "oldstyle" dialog the components have to
02034        be separated by blanks (not '\0'!) and short
02035        filenames have to be used! */
02036     FIXME("Components have to be separated by blanks\n");
02037   }
02038   if(fodInfos->unicode)
02039   {
02040     LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
02041     lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
02042     memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
02043   }
02044   else
02045   {
02046     LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
02047 
02048     if (ofn->lpstrFile != NULL)
02049     {
02050       nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
02051               ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
02052       if (ofn->nMaxFile > nSizePath)
02053       {
02054     WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
02055                 ofn->lpstrFile + nSizePath,
02056                 ofn->nMaxFile - nSizePath, NULL, NULL);
02057       }
02058     }
02059   }
02060 
02061   fodInfos->ofnInfos->nFileOffset = nSizePath;
02062   fodInfos->ofnInfos->nFileExtension = 0;
02063 
02064   if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
02065     return FALSE;
02066 
02067   /* clean and exit */
02068   FILEDLG95_Clean(hwnd);
02069   return EndDialog(hwnd,TRUE);
02070 }
02071 
02072 /* Returns the 'slot name' of the given module_name in the registry's
02073  * most-recently-used list.  This will be an ASCII value in the
02074  * range ['a','z'). Returns zero on error.
02075  *
02076  * The slot's value in the registry has the form:
02077  *   module_name\0mru_path\0
02078  *
02079  * If stored_path is given, then stored_path will contain the path name
02080  * stored in the registry's MRU list for the given module_name.
02081  *
02082  * If hkey_ret is given, then hkey_ret will be a handle to the registry's
02083  * MRU list key for the given module_name.
02084  */
02085 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
02086 {
02087     WCHAR mru_list[32], *cur_mru_slot;
02088     BOOL taken[25] = {0};
02089     DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
02090     HKEY hkey_tmp, *hkey;
02091     LONG ret;
02092 
02093     if(hkey_ret)
02094         hkey = hkey_ret;
02095     else
02096         hkey = &hkey_tmp;
02097 
02098     if(stored_path)
02099         *stored_path = '\0';
02100 
02101     ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
02102     if(ret){
02103         WARN("Unable to create MRU key: %d\n", ret);
02104         return 0;
02105     }
02106 
02107     ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
02108             (LPBYTE)mru_list, &mru_list_size);
02109     if(ret || key_type != REG_SZ){
02110         if(ret == ERROR_FILE_NOT_FOUND)
02111             return 'a';
02112 
02113         WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
02114         RegCloseKey(*hkey);
02115         return 0;
02116     }
02117 
02118     for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
02119         WCHAR value_data[MAX_PATH], value_name[2] = {0};
02120         DWORD value_data_size = sizeof(value_data);
02121 
02122         *value_name = *cur_mru_slot;
02123 
02124         ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
02125                 &key_type, (LPBYTE)value_data, &value_data_size);
02126         if(ret || key_type != REG_BINARY){
02127             WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
02128             continue;
02129         }
02130 
02131         if(!strcmpiW(module_name, value_data)){
02132             if(!hkey_ret)
02133                 RegCloseKey(*hkey);
02134             if(stored_path)
02135                 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
02136             return *value_name;
02137         }
02138     }
02139 
02140     if(!hkey_ret)
02141         RegCloseKey(*hkey);
02142 
02143     /* the module name isn't in the registry, so find the next open slot */
02144     for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
02145         taken[*cur_mru_slot - 'a'] = TRUE;
02146     for(i = 0; i < 25; ++i){
02147         if(!taken[i])
02148             return i + 'a';
02149     }
02150 
02151     /* all slots are taken, so return the last one in MRUList */
02152     --cur_mru_slot;
02153     return *cur_mru_slot;
02154 }
02155 
02156 /* save the given filename as most-recently-used path for this module */
02157 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
02158 {
02159     WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
02160     LONG ret;
02161     HKEY hkey;
02162 
02163     /* get the current executable's name */
02164     if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
02165         WARN("GotModuleFileName failed: %d\n", GetLastError());
02166         return;
02167     }
02168     module_name = strrchrW(module_path, '\\');
02169     if(!module_name)
02170         module_name = module_path;
02171     else
02172         module_name += 1;
02173 
02174     slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
02175     if(!slot)
02176         return;
02177     *slot_name = slot;
02178 
02179     { /* update the slot's info */
02180         WCHAR *path_ends, *final;
02181         DWORD path_len, final_len;
02182 
02183         /* use only the path segment of `filename' */
02184         path_ends = strrchrW(filename, '\\');
02185         path_len = path_ends - filename;
02186 
02187         final_len = path_len + lstrlenW(module_name) + 2;
02188 
02189         final = MemAlloc(final_len * sizeof(WCHAR));
02190         if(!final)
02191             return;
02192         lstrcpyW(final, module_name);
02193         memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
02194         final[final_len-1] = '\0';
02195 
02196         ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
02197                 final_len * sizeof(WCHAR));
02198         if(ret){
02199             WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
02200             MemFree(final);
02201             RegCloseKey(hkey);
02202             return;
02203         }
02204 
02205         MemFree(final);
02206     }
02207 
02208     { /* update MRUList value */
02209         WCHAR old_mru_list[32], new_mru_list[32];
02210         WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
02211         DWORD mru_list_size = sizeof(old_mru_list), key_type;
02212 
02213         ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
02214                 (LPBYTE)old_mru_list, &mru_list_size);
02215         if(ret || key_type != REG_SZ){
02216             if(ret == ERROR_FILE_NOT_FOUND){
02217                 new_mru_list[0] = slot;
02218                 new_mru_list[1] = '\0';
02219             }else{
02220                 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
02221                 RegCloseKey(hkey);
02222                 return;
02223             }
02224         }else{
02225             /* copy old list data over so that the new slot is at the start
02226              * of the list */
02227             *new_mru_slot++ = slot;
02228             for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
02229                 if(*old_mru_slot != slot)
02230                     *new_mru_slot++ = *old_mru_slot;
02231             }
02232             *new_mru_slot = '\0';
02233         }
02234 
02235         ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
02236                 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
02237         if(ret){
02238             WARN("Error saving MRUList data: %d\n", ret);
02239             RegCloseKey(hkey);
02240             return;
02241         }
02242     }
02243 }
02244 
02245 /* load the most-recently-used path for this module */
02246 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
02247 {
02248     WCHAR module_path[MAX_PATH], *module_name;
02249 
02250     /* get the current executable's name */
02251     if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
02252         WARN("GotModuleFileName failed: %d\n", GetLastError());
02253         return;
02254     }
02255     module_name = strrchrW(module_path, '\\');
02256     if(!module_name)
02257         module_name = module_path;
02258     else
02259         module_name += 1;
02260 
02261     FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
02262     TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
02263 }
02264 
02265 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
02266 {
02267   WCHAR strMsgTitle[MAX_PATH];
02268   WCHAR strMsgText [MAX_PATH];
02269   if (idCaption)
02270     LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
02271   else
02272     strMsgTitle[0] = '\0';
02273   LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
02274   MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
02275 }
02276 
02277 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
02278                                  HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
02279 {
02280     int nOpenAction = defAction;
02281     LPWSTR lpszTemp, lpszTemp1;
02282     LPITEMIDLIST pidl = NULL;
02283     static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
02284 
02285     /* check for invalid chars */
02286     if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
02287     {
02288         FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
02289         return FALSE;
02290     }
02291 
02292     if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
02293 
02294     lpszTemp1 = lpszTemp = lpstrPathAndFile;
02295     while (lpszTemp1)
02296     {
02297         LPSHELLFOLDER lpsfChild;
02298         WCHAR lpwstrTemp[MAX_PATH];
02299         DWORD dwEaten, dwAttributes;
02300         LPWSTR p;
02301 
02302         lstrcpyW(lpwstrTemp, lpszTemp);
02303         p = PathFindNextComponentW(lpwstrTemp);
02304 
02305         if (!p) break; /* end of path */
02306 
02307         *p = 0;
02308         lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
02309 
02310         /* There are no wildcards when OFN_NOVALIDATE is set */
02311         if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
02312         {
02313             static const WCHAR wszWild[] = { '*', '?', 0 };
02314             /* if the last element is a wildcard do a search */
02315             if(strpbrkW(lpszTemp1, wszWild) != NULL)
02316             {
02317                 nOpenAction = ONOPEN_SEARCH;
02318                 break;
02319             }
02320         }
02321         lpszTemp1 = lpszTemp;
02322 
02323         TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
02324 
02325         /* append a backslash to drive letters */
02326         if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
02327            ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
02328             (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
02329         {
02330             PathAddBackslashW(lpwstrTemp);
02331         }
02332 
02333         dwAttributes = SFGAO_FOLDER;
02334         if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
02335         {
02336             /* the path component is valid, we have a pidl of the next path component */
02337             TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
02338             if(dwAttributes & SFGAO_FOLDER)
02339             {
02340                 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
02341                 {
02342                     ERR("bind to failed\n"); /* should not fail */
02343                     break;
02344                 }
02345                 IShellFolder_Release(*ppsf);
02346                 *ppsf = lpsfChild;
02347                 lpsfChild = NULL;
02348             }
02349             else
02350             {
02351                 TRACE("value\n");
02352 
02353                 /* end dialog, return value */
02354                 nOpenAction = ONOPEN_OPEN;
02355                 break;
02356             }
02357             COMDLG32_SHFree(pidl);
02358             pidl = NULL;
02359         }
02360         else if (!(flags & OFN_NOVALIDATE))
02361         {
02362             if(*lpszTemp || /* points to trailing null for last path element */
02363                (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
02364             {
02365                 if(flags & OFN_PATHMUSTEXIST)
02366                 {
02367                     FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
02368                     break;
02369                 }
02370             }
02371             else
02372             {
02373                 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
02374                 {
02375                     FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
02376                     break;
02377                 }
02378             }
02379             /* change to the current folder */
02380             nOpenAction = ONOPEN_OPEN;
02381             break;
02382         }
02383         else
02384         {
02385             nOpenAction = ONOPEN_OPEN;
02386             break;
02387         }
02388     }
02389     if(pidl) COMDLG32_SHFree(pidl);
02390 
02391     return nOpenAction;
02392 }
02393 
02394 /***********************************************************************
02395  *      FILEDLG95_OnOpen
02396  *
02397  * Ok button WM_COMMAND message handler
02398  *
02399  * If the function succeeds, the return value is nonzero.
02400  */
02401 BOOL FILEDLG95_OnOpen(HWND hwnd)
02402 {
02403   LPWSTR lpstrFileList;
02404   UINT nFileCount = 0;
02405   UINT sizeUsed = 0;
02406   BOOL ret = TRUE;
02407   WCHAR lpstrPathAndFile[MAX_PATH];
02408   LPSHELLFOLDER lpsf = NULL;
02409   int nOpenAction;
02410   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
02411 
02412   TRACE("hwnd=%p\n", hwnd);
02413 
02414   /* try to browse the selected item */
02415   if(BrowseSelectedFolder(hwnd))
02416       return FALSE;
02417 
02418   /* get the files from the edit control */
02419   nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
02420 
02421   if(nFileCount == 0)
02422       return FALSE;
02423 
02424   if(nFileCount > 1)
02425   {
02426       ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
02427       goto ret;
02428   }
02429 
02430   TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
02431 
02432 /*
02433   Step 1:  Build a complete path name from the current folder and
02434   the filename or path in the edit box.
02435   Special cases:
02436   - the path in the edit box is a root path
02437     (with or without drive letter)
02438   - the edit box contains ".." (or a path with ".." in it)
02439 */
02440 
02441   COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
02442   MemFree(lpstrFileList);
02443 
02444 /*
02445   Step 2: here we have a cleaned up path
02446 
02447   We have to parse the path step by step to see if we have to browse
02448   to a folder if the path points to a directory or the last
02449   valid element is a directory.
02450 
02451   valid variables:
02452     lpstrPathAndFile: cleaned up path
02453  */
02454 
02455   if (nFileCount &&
02456       (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
02457       !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
02458     nOpenAction = ONOPEN_OPEN;
02459   else
02460     nOpenAction = ONOPEN_BROWSE;
02461 
02462   nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
02463                                              fodInfos->ofnInfos->Flags,
02464                                              fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
02465                                              nOpenAction);
02466   if(!nOpenAction)
02467       goto ret;
02468 
02469 /*
02470   Step 3: here we have a cleaned up and validated path
02471 
02472   valid variables:
02473    lpsf:             ShellFolder bound to the rightmost valid path component
02474    lpstrPathAndFile: cleaned up path
02475    nOpenAction:      action to do
02476 */
02477   TRACE("end validate sf=%p\n", lpsf);
02478 
02479   switch(nOpenAction)
02480   {
02481     case ONOPEN_SEARCH:   /* set the current filter to the file mask and refresh */
02482       TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
02483       {
02484         int iPos;
02485         LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
02486         DWORD len;
02487 
02488         /* replace the current filter */
02489         MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
02490         len = lstrlenW(lpszTemp)+1;
02491         fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
02492         lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
02493 
02494         /* set the filter cb to the extension when possible */
02495         if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
02496         CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
02497       }
02498       /* fall through */
02499     case ONOPEN_BROWSE:   /* browse to the highest folder we could bind to */
02500       TRACE("ONOPEN_BROWSE\n");
02501       {
02502     IPersistFolder2 * ppf2;
02503         if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
02504         {
02505           LPITEMIDLIST pidlCurrent;
02506           IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
02507           IPersistFolder2_Release(ppf2);
02508       if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
02509       {
02510             if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
02511                 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
02512             {
02513               SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
02514             }
02515       }
02516       else if( nOpenAction == ONOPEN_SEARCH )
02517       {
02518             if (fodInfos->Shell.FOIShellView)
02519               IShellView_Refresh(fodInfos->Shell.FOIShellView);
02520       }
02521           COMDLG32_SHFree(pidlCurrent);
02522           SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
02523         }
02524       }
02525       ret = FALSE;
02526       break;
02527     case ONOPEN_OPEN:   /* fill in the return struct and close the dialog */
02528       TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
02529       {
02530         WCHAR *ext = NULL;
02531 
02532         /* update READONLY check box flag */
02533     if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
02534       fodInfos->ofnInfos->Flags |= OFN_READONLY;
02535     else
02536       fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
02537 
02538         /* Attach the file extension with file name*/
02539         ext = PathFindExtensionW(lpstrPathAndFile);
02540         if (! *ext)
02541         {
02542             /* if no extension is specified with file name, then */
02543             /* attach the extension from file filter or default one */
02544             
02545             const WCHAR *filterExt = NULL;
02546             LPWSTR lpstrFilter = NULL;
02547             static const WCHAR szwDot[] = {'.',0};
02548             int PathLength = lstrlenW(lpstrPathAndFile);
02549 
02550             /*Get the file extension from file type filter*/
02551             lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
02552                                              fodInfos->ofnInfos->nFilterIndex-1);
02553 
02554             if (lpstrFilter != (LPWSTR)CB_ERR)  /* control is not empty */
02555                 filterExt = PathFindExtensionW(lpstrFilter);
02556 
02557             if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
02558                 filterExt = filterExt + 1;
02559             else if ( fodInfos->defext ) /* attach the default file extension*/
02560                 filterExt = fodInfos->defext;
02561 
02562             /* If extension contains a glob, ignore it */
02563             if ( filterExt && !strchrW(filterExt, '*') && !strchrW(filterExt, '?') )
02564             {
02565                 /* Attach the dot*/
02566                 lstrcatW(lpstrPathAndFile, szwDot);
02567                 /* Attach the extension */
02568                 lstrcatW(lpstrPathAndFile, filterExt );
02569             }
02570 
02571             /* In Open dialog: if file does not exist try without extension */
02572             if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
02573                   lpstrPathAndFile[PathLength] = '\0';
02574         }
02575 
02576     if (fodInfos->defext) /* add default extension */
02577     {
02578       /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
02579       if (*ext)
02580         ext++;
02581       if (!lstrcmpiW(fodInfos->defext, ext))
02582         fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
02583       else
02584         fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
02585     }
02586 
02587     /* In Save dialog: check if the file already exists */
02588     if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
02589         && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
02590         && PathFileExistsW(lpstrPathAndFile))
02591     {
02592       WCHAR lpstrOverwrite[100];
02593       int answer;
02594 
02595       LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
02596       answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
02597                    MB_YESNO | MB_ICONEXCLAMATION);
02598       if (answer == IDNO || answer == IDCANCEL)
02599       {
02600         ret = FALSE;
02601         goto ret;
02602       }
02603     }
02604 
02605         /* In Open dialog: check if it should be created if it doesn't exist */
02606         if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
02607             && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
02608             && !PathFileExistsW(lpstrPathAndFile))
02609         {
02610           WCHAR lpstrCreate[100];
02611           int answer;
02612 
02613           LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
02614           answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
02615                                MB_YESNO | MB_ICONEXCLAMATION);
02616           if (answer == IDNO || answer == IDCANCEL)
02617           {
02618             ret = FALSE;
02619             goto ret;
02620           }
02621         }
02622 
02623         /* Check that the size of the file does not exceed buffer size.
02624              (Allow for extra \0 if OFN_MULTISELECT is set.) */
02625         if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
02626             ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
02627         {
02628 
02629           /* fill destination buffer */
02630           if (fodInfos->ofnInfos->lpstrFile)
02631           {
02632              if(fodInfos->unicode)
02633              {
02634                LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
02635 
02636                lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
02637                if (ofn->Flags & OFN_ALLOWMULTISELECT)
02638                  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
02639              }
02640              else
02641              {
02642                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
02643 
02644                WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
02645                                    ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
02646                if (ofn->Flags & OFN_ALLOWMULTISELECT)
02647                  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
02648              }
02649           }
02650 
02651           if(fodInfos->unicode)
02652           {
02653               LPWSTR lpszTemp;
02654 
02655               /* set filename offset */
02656               lpszTemp = PathFindFileNameW(lpstrPathAndFile);
02657               fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
02658 
02659               /* set extension offset */
02660               lpszTemp = PathFindExtensionW(lpstrPathAndFile);
02661               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
02662           }
02663           else
02664           {
02665                LPSTR lpszTemp;
02666                LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
02667 
02668               /* set filename offset */
02669               lpszTemp = PathFindFileNameA(ofn->lpstrFile);
02670               fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
02671 
02672               /* set extension offset */
02673               lpszTemp = PathFindExtensionA(ofn->lpstrFile);
02674               fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
02675           }
02676 
02677           /* set the lpstrFileTitle */
02678           if(fodInfos->ofnInfos->lpstrFileTitle)
02679       {
02680             LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
02681             if(fodInfos->unicode)
02682             {
02683               LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
02684           lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
02685             }
02686             else
02687             {
02688               LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
02689               WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
02690                     ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
02691             }
02692       }
02693 
02694           /* copy currently selected filter to lpstrCustomFilter */
02695           if (fodInfos->ofnInfos->lpstrCustomFilter)
02696           {
02697             LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
02698             int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
02699                                           NULL, 0, NULL, NULL);
02700             if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
02701             {
02702               LPSTR s = ofn->lpstrCustomFilter;
02703               s += strlen(ofn->lpstrCustomFilter)+1;
02704               WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
02705                                   s, len, NULL, NULL);
02706             }
02707           }
02708 
02709 
02710           if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
02711           goto ret;
02712 
02713           FILEDLG95_MRU_save_filename(lpstrPathAndFile);
02714 
02715           TRACE("close\n");
02716       FILEDLG95_Clean(hwnd);
02717           ret = EndDialog(hwnd, TRUE);
02718     }
02719     else
02720         {
02721           WORD size;
02722 
02723           size = lstrlenW(lpstrPathAndFile) + 1;
02724           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
02725              size += 1;
02726           /* return needed size in first two bytes of lpstrFile */
02727           *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
02728           FILEDLG95_Clean(hwnd);
02729           ret = EndDialog(hwnd, FALSE);
02730           COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
02731         }
02732       }
02733       break;
02734   }
02735 
02736 ret:
02737   if(lpsf) IShellFolder_Release(lpsf);
02738   return ret;
02739 }
02740 
02741 /***********************************************************************
02742  *      FILEDLG95_SHELL_Init
02743  *
02744  * Initialisation of the shell objects
02745  */
02746 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
02747 {
02748   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
02749 
02750   TRACE("\n");
02751 
02752   /*
02753    * Initialisation of the FileOpenDialogInfos structure
02754    */
02755 
02756   /* Shell */
02757 
02758   /*ShellInfos */
02759   fodInfos->ShellInfos.hwndOwner = hwnd;
02760 
02761   /* Disable multi-select if flag not set */
02762   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
02763   {
02764      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
02765   }
02766   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
02767   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
02768 
02769   /* Construct the IShellBrowser interface */
02770   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
02771 
02772   return NOERROR;
02773 }
02774 
02775 /***********************************************************************
02776  *      FILEDLG95_SHELL_ExecuteCommand
02777  *
02778  * Change the folder option and refresh the view
02779  * If the function succeeds, the return value is nonzero.
02780  */
02781 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
02782 {
02783   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
02784   IContextMenu * pcm;
02785 
02786   TRACE("(%p,%p)\n", hwnd, lpVerb);
02787 
02788   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
02789                     SVGIO_BACKGROUND,
02790                     &IID_IContextMenu,
02791                     (LPVOID*)&pcm)))
02792   {
02793     CMINVOKECOMMANDINFO ci;
02794     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
02795     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
02796     ci.lpVerb = lpVerb;
02797     ci.hwnd = hwnd;
02798 
02799     IContextMenu_InvokeCommand(pcm, &ci);
02800     IContextMenu_Release(pcm);
02801   }
02802 
02803   return FALSE;
02804 }
02805 
02806 /***********************************************************************
02807  *      FILEDLG95_SHELL_UpFolder
02808  *
02809  * Browse to the specified object
02810  * If the function succeeds, the return value is nonzero.
02811  */
02812 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
02813 {
02814   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
02815 
02816   TRACE("\n");
02817 
02818   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
02819                                           NULL,
02820                                           SBSP_PARENT)))
02821   {
02822     if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
02823         SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
02824     return TRUE;
02825   }
02826   return FALSE;
02827 }
02828 
02829 /***********************************************************************
02830  *      FILEDLG95_SHELL_BrowseToDesktop
02831  *
02832  * Browse to the Desktop
02833  * If the function succeeds, the return value is nonzero.
02834  */
02835 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
02836 {
02837   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
02838   LPITEMIDLIST pidl;
02839   HRESULT hres;
02840 
02841   TRACE("\n");
02842 
02843   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
02844   hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
02845   if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
02846       SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
02847   COMDLG32_SHFree(pidl);
02848   return SUCCEEDED(hres);
02849 }
02850 /***********************************************************************
02851  *      FILEDLG95_SHELL_Clean
02852  *
02853  * Cleans the memory used by shell objects
02854  */
02855 static void FILEDLG95_SHELL_Clean(HWND hwnd)
02856 {
02857     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
02858 
02859     TRACE("\n");
02860 
02861     COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
02862 
02863     /* clean Shell interfaces */
02864     if (fodInfos->Shell.FOIShellView)
02865     {
02866       IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
02867       IShellView_Release(fodInfos->Shell.FOIShellView);
02868     }
02869     IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
02870     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
02871     if (fodInfos->Shell.FOIDataObject)
02872       IDataObject_Release(fodInfos->Shell.FOIDataObject);
02873 }
02874 
02875 /***********************************************************************
02876  *      FILEDLG95_FILETYPE_Init
02877  *
02878  * Initialisation of the file type combo box
02879  */
02880 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
02881 {
02882   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
02883   int nFilters = 0;  /* number of filters */
02884   int nFilterIndexCB;
02885 
02886   TRACE("\n");
02887 
02888   if(fodInfos->customfilter)
02889   {
02890       /* customfilter has one entry...  title\0ext\0
02891        * Set first entry of combo box item with customfilter
02892        */
02893       LPWSTR  lpstrExt;
02894       LPCWSTR lpstrPos = fodInfos->customfilter;
02895 
02896       /* Get the title */
02897       lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
02898 
02899       /* Copy the extensions */
02900       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
02901       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
02902       lstrcpyW(lpstrExt,lpstrPos);
02903 
02904       /* Add the item at the end of the combo */
02905       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
02906       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
02907       nFilters++;
02908   }
02909   if(fodInfos->filter)
02910   {
02911     LPCWSTR lpstrPos = fodInfos->filter;
02912 
02913     for(;;)
02914     {
02915       /* filter is a list...  title\0ext\0......\0\0
02916        * Set the combo item text to the title and the item data
02917        *  to the ext
02918        */
02919       LPCWSTR lpstrDisplay;
02920       LPWSTR lpstrExt;
02921 
02922       /* Get the title */
02923       if(! *lpstrPos) break;    /* end */
02924       lpstrDisplay = lpstrPos;
02925       lpstrPos += lstrlenW(lpstrPos) + 1;
02926 
02927       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
02928 
02929       nFilters++;
02930 
02931       /* Copy the extensions */
02932       if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
02933       lstrcpyW(lpstrExt,lpstrPos);
02934       lpstrPos += lstrlenW(lpstrPos) + 1;
02935 
02936       /* Add the item at the end of the combo */
02937       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
02938 
02939       /* malformed filters are added anyway... */
02940       if (!*lpstrExt) break;
02941     }
02942   }
02943 
02944   /*
02945    * Set the current filter to the one specified
02946    * in the initialisation structure
02947    */
02948   if (fodInfos->filter || fodInfos->customfilter)
02949   {
02950     LPWSTR lpstrFilter;
02951 
02952     /* Check to make sure our index isn't out of bounds. */
02953     if ( fodInfos->ofnInfos->nFilterIndex >
02954          nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
02955       fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
02956 
02957     /* set default filter index */
02958     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
02959       fodInfos->ofnInfos->nFilterIndex = 1;
02960 
02961     /* calculate index of Combo Box item */
02962     nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
02963     if (fodInfos->customfilter == NULL)
02964       nFilterIndexCB--;
02965 
02966     /* Set the current index selection. */
02967     CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
02968 
02969     /* Get the corresponding text string from the combo box. */
02970     lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
02971                                              nFilterIndexCB);
02972 
02973     if ((INT_PTR)lpstrFilter == CB_ERR)  /* control is empty */
02974       lpstrFilter = NULL;
02975 
02976     if(lpstrFilter)
02977     {
02978       DWORD len;
02979       CharLowerW(lpstrFilter); /* lowercase */
02980       len = lstrlenW(lpstrFilter)+1;
02981       fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
02982       lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
02983     }
02984   } else
02985       fodInfos->ofnInfos->nFilterIndex = 0;
02986   return S_OK;
02987 }
02988 
02989 /***********************************************************************
02990  *      FILEDLG95_FILETYPE_OnCommand
02991  *
02992  * WM_COMMAND of the file type combo box
02993  * If the function succeeds, the return value is nonzero.
02994  */
02995 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
02996 {
02997   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
02998 
02999   switch(wNotifyCode)
03000   {
03001     case CBN_SELENDOK:
03002     {
03003       LPWSTR lpstrFilter;
03004 
03005       /* Get the current item of the filetype combo box */
03006       int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
03007 
03008       /* set the current filter index */
03009       fodInfos->ofnInfos->nFilterIndex = iItem +
03010         (fodInfos->customfilter == NULL ? 1 : 0);
03011 
03012       /* Set the current filter with the current selection */
03013       MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
03014 
03015       lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
03016                                              iItem);
03017       if((INT_PTR)lpstrFilter != CB_ERR)
03018       {
03019           DWORD len;
03020           CharLowerW(lpstrFilter); /* lowercase */
03021           len = lstrlenW(lpstrFilter)+1;
03022           fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
03023           lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
03024           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
03025               SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
03026       }
03027 
03028       /* Refresh the actual view to display the included items*/
03029       if (fodInfos->Shell.FOIShellView)
03030         IShellView_Refresh(fodInfos->Shell.FOIShellView);
03031     }
03032   }
03033   return FALSE;
03034 }
03035 /***********************************************************************
03036  *      FILEDLG95_FILETYPE_SearchExt
03037  *
03038  * searches for an extension in the filetype box
03039  */
03040 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
03041 {
03042   int i, iCount = CBGetCount(hwnd);
03043 
03044   TRACE("%s\n", debugstr_w(lpstrExt));
03045 
03046   if(iCount != CB_ERR)
03047   {
03048     for(i=0;i<iCount;i++)
03049     {
03050       if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
03051           return i;
03052     }
03053   }
03054   return -1;
03055 }
03056 
03057 /***********************************************************************
03058  *      FILEDLG95_FILETYPE_Clean
03059  *
03060  * Clean the memory used by the filetype combo box
03061  */
03062 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
03063 {
03064   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
03065   int iPos;
03066   int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
03067 
03068   TRACE("\n");
03069 
03070   /* Delete each string of the combo and their associated data */
03071   if(iCount != CB_ERR)
03072   {
03073     for(iPos = iCount-1;iPos>=0;iPos--)
03074     {
03075       MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
03076       CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
03077     }
03078   }
03079   /* Current filter */
03080   MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
03081 
03082 }
03083 
03084 /***********************************************************************
03085  *      FILEDLG95_LOOKIN_Init
03086  *
03087  * Initialisation of the look in combo box
03088  */
03089 
03090 /* Small helper function, to determine if the unixfs shell extension is rooted 
03091  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c. 
03092  */
03093 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
03094     HKEY hKey;
03095     static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
03096         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
03097         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
03098         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
03099         'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
03100         '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
03101         '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
03102     
03103     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
03104         return FALSE;
03105         
03106     RegCloseKey(hKey);
03107     return TRUE;
03108 }
03109 
03110 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
03111 {
03112   IShellFolder  *psfRoot, *psfDrives;
03113   IEnumIDList   *lpeRoot, *lpeDrives;
03114   LPITEMIDLIST  pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
03115 
03116   LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
03117 
03118   TRACE("\n");
03119 
03120   liInfos->iMaxIndentation = 0;
03121 
03122   SetPropA(hwndCombo, LookInInfosStr, liInfos);
03123 
03124   /* set item height for both text field and listbox */
03125   CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
03126   CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
03127    
03128   /* Turn on the extended UI for the combo box like Windows does */
03129   CBSetExtendedUI(hwndCombo, TRUE);
03130 
03131   /* Initialise data of Desktop folder */
03132   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
03133   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
03134   COMDLG32_SHFree(pidlTmp);
03135 
03136   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
03137 
03138   SHGetDesktopFolder(&psfRoot);
03139 
03140   if (psfRoot)
03141   {
03142     /* enumerate the contents of the desktop */
03143     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
03144     {
03145       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
03146       {
03147     FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
03148 
03149     /* If the unixfs extension is rooted, we don't expand the drives by default */
03150     if (!FILEDLG95_unixfs_is_rooted_at_desktop()) 
03151     {
03152       /* special handling for CSIDL_DRIVES */
03153       if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
03154       {
03155         if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
03156         {
03157           /* enumerate the drives */
03158           if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
03159           {
03160             while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
03161             {
03162               pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
03163               FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
03164               COMDLG32_SHFree(pidlAbsTmp);
03165               COMDLG32_SHFree(pidlTmp1);
03166             }
03167             IEnumIDList_Release(lpeDrives);
03168           }
03169           IShellFolder_Release(psfDrives);
03170         }
03171       }
03172     }
03173 
03174         COMDLG32_SHFree(pidlTmp);
03175       }
03176       IEnumIDList_Release(lpeRoot);
03177     }
03178     IShellFolder_Release(psfRoot);
03179   }
03180 
03181   COMDLG32_SHFree(pidlDrives);
03182 }
03183 
03184 /***********************************************************************
03185  *      FILEDLG95_LOOKIN_DrawItem
03186  *
03187  * WM_DRAWITEM message handler
03188  */
03189 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
03190 {
03191   COLORREF crWin = GetSysColor(COLOR_WINDOW);
03192   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
03193   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
03194   RECT rectText;
03195   RECT rectIcon;
03196   SHFILEINFOW sfi;
03197   HIMAGELIST ilItemImage;
03198   int iIndentation;
03199   TEXTMETRICW tm;
03200   LPSFOLDER tmpFolder;
03201   LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
03202 
03203   TRACE("\n");
03204 
03205   if(pDIStruct->itemID == -1)
03206     return 0;
03207 
03208   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
03209                             pDIStruct->itemID)))
03210     return 0;
03211 
03212 
03213   if(pDIStruct->itemID == liInfos->uSelectedItem)
03214   {
03215     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
03216                                                0,
03217                                                &sfi,
03218                                                sizeof (sfi),
03219                                                SHGFI_PIDL | SHGFI_SMALLICON |
03220                                                SHGFI_OPENICON | SHGFI_SYSICONINDEX    |
03221                                                SHGFI_DISPLAYNAME );
03222   }
03223   else
03224   {
03225     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
03226                                                   0,
03227                                                   &sfi,
03228                                                   sizeof (sfi),
03229                                                   SHGFI_PIDL | SHGFI_SMALLICON |
03230                                                   SHGFI_SYSICONINDEX |
03231                                                   SHGFI_DISPLAYNAME);
03232   }
03233 
03234   /* Is this item selected ? */
03235   if(pDIStruct->itemState & ODS_SELECTED)
03236   {
03237     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
03238     SetBkColor(pDIStruct->hDC,crHighLight);
03239     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
03240   }
03241   else
03242   {
03243     SetTextColor(pDIStruct->hDC,crText);
03244     SetBkColor(pDIStruct->hDC,crWin);
03245     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
03246   }
03247 
03248   /* Do not indent item if drawing in the edit of the combo */
03249   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
03250   {
03251     iIndentation = 0;
03252     ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
03253                                                 0,
03254                                                 &sfi,
03255                                                 sizeof (sfi),
03256                                                 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
03257                                                 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME  );
03258 
03259   }
03260   else
03261   {
03262     iIndentation = tmpFolder->m_iIndent;
03263   }
03264   /* Draw text and icon */
03265 
03266   /* Initialise the icon display area */
03267   rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
03268   rectIcon.top = pDIStruct->rcItem.top;
03269   rectIcon.right = rectIcon.left + ICONWIDTH;
03270   rectIcon.bottom = pDIStruct->rcItem.bottom;
03271 
03272   /* Initialise the text display area */
03273   GetTextMetricsW(pDIStruct->hDC, &tm);
03274   rectText.left = rectIcon.right;
03275   rectText.top =
03276       (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
03277   rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
03278   rectText.bottom =
03279       (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
03280 
03281   /* Draw the icon from the image list */
03282   ImageList_Draw(ilItemImage,
03283                  sfi.iIcon,
03284                  pDIStruct->hDC,
03285                  rectIcon.left,
03286                  rectIcon.top,
03287                  ILD_TRANSPARENT );
03288 
03289   /* Draw the associated text */
03290   TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
03291   return NOERROR;
03292 }
03293 
03294 /***********************************************************************
03295  *      FILEDLG95_LOOKIN_OnCommand
03296  *
03297  * LookIn combo box WM_COMMAND message handler
03298  * If the function succeeds, the return value is nonzero.
03299  */
03300 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
03301 {
03302   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
03303 
03304   TRACE("%p\n", fodInfos);
03305 
03306   switch(wNotifyCode)
03307   {
03308     case CBN_SELENDOK:
03309     {
03310       LPSFOLDER tmpFolder;
03311       int iItem;
03312 
03313       iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
03314 
03315       if( iItem == CB_ERR) return FALSE;
03316 
03317       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
03318                                                iItem)))
03319     return FALSE;
03320 
03321 
03322       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
03323                                               tmpFolder->pidlItem,
03324                                               SBSP_ABSOLUTE)))
03325       {
03326         if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
03327             SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
03328         return TRUE;
03329       }
03330       break;
03331     }
03332 
03333   }
03334   return FALSE;
03335 }
03336 
03337 /***********************************************************************
03338  *      FILEDLG95_LOOKIN_AddItem
03339  *
03340  * Adds an absolute pidl item to the lookin combo box
03341  * returns the index of the inserted item
03342  */
03343 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
03344 {
03345   LPITEMIDLIST pidlNext;
03346   SHFILEINFOW sfi;
03347   SFOLDER *tmpFolder;
03348   LookInInfos *liInfos;
03349 
03350   TRACE("%08x\n", iInsertId);
03351 
03352   if(!pidl)
03353     return -1;
03354 
03355   if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
03356     return -1;
03357 
03358   tmpFolder = MemAlloc(sizeof(SFOLDER));
03359   tmpFolder->m_iIndent = 0;
03360 
03361   /* Calculate the indentation of the item in the lookin*/
03362   pidlNext = pidl;
03363   while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
03364   {
03365     tmpFolder->m_iIndent++;
03366   }
03367 
03368   tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
03369 
03370   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
03371     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
03372 
03373   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
03374   SHGetFileInfoW((LPCWSTR)pidl,
03375                   0,
03376                   &sfi,
03377                   sizeof(sfi),
03378                   SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
03379                   | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
03380 
03381   TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
03382 
03383   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
03384   {
03385     int iItemID;
03386 
03387     TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
03388 
03389     /* Add the item at the end of the list */
03390     if(iInsertId < 0)
03391     {
03392       iItemID = CBAddString(hwnd,sfi.szDisplayName);
03393     }
03394     /* Insert the item at the iInsertId position*/
03395     else
03396     {
03397       iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
03398     }
03399 
03400     CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
03401     return iItemID;
03402   }
03403 
03404   COMDLG32_SHFree( tmpFolder->pidlItem );
03405   MemFree( tmpFolder );
03406   return -1;
03407 
03408 }
03409 
03410 /***********************************************************************
03411  *      FILEDLG95_LOOKIN_InsertItemAfterParent
03412  *
03413  * Insert an item below its parent
03414  */
03415 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
03416 {
03417 
03418   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
03419   int iParentPos;
03420 
03421   TRACE("\n");
03422 
03423   if (pidl == pidlParent)
03424     return -1;
03425 
03426   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
03427 
03428   if(iParentPos < 0)
03429   {
03430     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
03431   }
03432 
03433   /* Free pidlParent memory */
03434   COMDLG32_SHFree(pidlParent);
03435 
03436   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
03437 }
03438 
03439 /***********************************************************************
03440  *      FILEDLG95_LOOKIN_SelectItem
03441  *
03442  * Adds an absolute pidl item to the lookin combo box
03443  * returns the index of the inserted item
03444  */
03445 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
03446 {
03447   int iItemPos;
03448   LookInInfos *liInfos;
03449 
03450   TRACE("\n");
03451 
03452   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
03453 
03454   liInfos = GetPropA(hwnd,LookInInfosStr);
03455 
03456   if(iItemPos < 0)
03457   {
03458     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
03459     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
03460   }
03461 
03462   else
03463   {
03464     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
03465     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
03466     {
03467       int iRemovedItem;
03468 
03469       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
03470         break;
03471       if(iRemovedItem < iItemPos)
03472         iItemPos--;
03473     }
03474   }
03475 
03476   CBSetCurSel(hwnd,iItemPos);
03477   liInfos->uSelectedItem = iItemPos;
03478 
03479   return 0;
03480 
03481 }
03482 
03483 /***********************************************************************
03484  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
03485  *
03486  * Remove the item with an expansion level over iExpansionLevel
03487  */
03488 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
03489 {
03490   int iItemPos;
03491   LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
03492 
03493   TRACE("\n");
03494 
03495   if(liInfos->iMaxIndentation <= 2)
03496     return -1;
03497 
03498   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
03499   {
03500     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
03501     COMDLG32_SHFree(tmpFolder->pidlItem);
03502     MemFree(tmpFolder);
03503     CBDeleteString(hwnd,iItemPos);
03504     liInfos->iMaxIndentation--;
03505 
03506     return iItemPos;
03507   }
03508 
03509   return -1;
03510 }
03511 
03512 /***********************************************************************
03513  *      FILEDLG95_LOOKIN_SearchItem
03514  *
03515  * Search for pidl in the lookin combo box
03516  * returns the index of the found item
03517  */
03518 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
03519 {
03520   int i = 0;
03521   int iCount = CBGetCount(hwnd);
03522 
03523   TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
03524 
03525   if (iCount != CB_ERR)
03526   {
03527     for(;i<iCount;i++)
03528     {
03529       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
03530 
03531       if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
03532         return i;
03533       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
03534         return i;
03535     }
03536   }
03537 
03538   return -1;
03539 }
03540 
03541 /***********************************************************************
03542  *      FILEDLG95_LOOKIN_Clean
03543  *
03544  * Clean the memory used by the lookin combo box
03545  */
03546 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
03547 {
03548     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
03549     LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
03550     int iPos;
03551     int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
03552 
03553     TRACE("\n");
03554 
03555     /* Delete each string of the combo and their associated data */
03556     if (iCount != CB_ERR)
03557     {
03558       for(iPos = iCount-1;iPos>=0;iPos--)
03559       {
03560         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
03561         COMDLG32_SHFree(tmpFolder->pidlItem);
03562         MemFree(tmpFolder);
03563         CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
03564       }
03565     }
03566 
03567     /* LookInInfos structure */
03568     MemFree(liInfos);
03569     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
03570 }
03571 
03572 /***********************************************************************
03573  * FILEDLG95_FILENAME_FillFromSelection
03574  *
03575  * fills the edit box from the cached DataObject
03576  */
03577 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
03578 {
03579     FileOpenDlgInfos *fodInfos;
03580     LPITEMIDLIST      pidl;
03581     UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
03582     WCHAR             lpstrTemp[MAX_PATH];
03583     LPWSTR            lpstrAllFile, lpstrCurrFile;
03584 
03585     TRACE("\n");
03586     fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
03587 
03588     /* Count how many files we have */
03589     nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
03590 
03591     /* calculate the string length, count files */
03592     if (nFileSelected >= 1)
03593     {
03594       nLength += 3; /* first and last quotes, trailing \0 */
03595       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
03596       {
03597         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
03598 
03599         if (pidl)
03600     {
03601           /* get the total length of the selected file names */
03602           lpstrTemp[0] = '\0';
03603           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
03604 
03605           if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
03606       {
03607             nLength += lstrlenW( lpstrTemp ) + 3;
03608             nFiles++;
03609       }
03610           COMDLG32_SHFree( pidl );
03611     }
03612       }
03613     }
03614 
03615     /* allocate the buffer */
03616     if (nFiles <= 1) nLength = MAX_PATH;
03617     lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
03618 
03619     /* Generate the string for the edit control */
03620     if(nFiles >= 1)
03621     {
03622       lpstrCurrFile = lpstrAllFile;
03623       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
03624       {
03625         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
03626 
03627         if (pidl)
03628     {
03629       /* get the file name */
03630           lpstrTemp[0] = '\0';
03631           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
03632 
03633           if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
03634       {
03635             if ( nFiles > 1)
03636         {
03637               *lpstrCurrFile++ =  '\"';
03638               lstrcpyW( lpstrCurrFile, lpstrTemp );
03639               lpstrCurrFile += lstrlenW( lpstrTemp );
03640               *lpstrCurrFile++ = '\"';
03641               *lpstrCurrFile++ = ' ';
03642               *lpstrCurrFile = 0;
03643         }
03644         else
03645         {
03646               lstrcpyW( lpstrAllFile, lpstrTemp );
03647         }
03648           }
03649           COMDLG32_SHFree( pidl );
03650     }
03651       }
03652       SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
03653        
03654       /* Select the file name like Windows does */ 
03655       SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
03656     }
03657     HeapFree(GetProcessHeap(),0, lpstrAllFile );
03658 }
03659 
03660 
03661 /* copied from shell32 to avoid linking to it
03662  * Although shell32 is already linked the behaviour of exported StrRetToStrN
03663  * is dependent on whether emulated OS is unicode or not.
03664  */
03665 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
03666 {
03667     switch (src->uType)
03668     {
03669       case STRRET_WSTR:
03670         lstrcpynW(dest, src->u.pOleStr, len);
03671         COMDLG32_SHFree(src->u.pOleStr);
03672         break;
03673 
03674       case STRRET_CSTR:
03675             if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
03676                   dest[len-1] = 0;
03677         break;
03678 
03679       case STRRET_OFFSET:
03680             if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
03681                   dest[len-1] = 0;
03682         break;
03683 
03684       default:
03685         FIXME("unknown type %x!\n", src->uType);
03686         if (len) *dest = '\0';
03687         return E_FAIL;
03688     }
03689     return S_OK;
03690 }
03691 
03692 /***********************************************************************
03693  * FILEDLG95_FILENAME_GetFileNames
03694  *
03695  * Copies the filenames to a delimited string list.
03696  */
03697 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
03698 {
03699     FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
03700     UINT nFileCount = 0;    /* number of files */
03701     UINT nStrLen = 0;   /* length of string in edit control */
03702     LPWSTR lpstrEdit;   /* buffer for string from edit control */
03703 
03704     TRACE("\n");
03705 
03706     /* get the filenames from the edit control */
03707     nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
03708     lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
03709     GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
03710 
03711     TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
03712 
03713     nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
03714     MemFree(lpstrEdit);
03715     return nFileCount;
03716 }
03717 
03718 #define SETDefFormatEtc(fe,cf,med) \
03719 { \
03720     (fe).cfFormat = cf;\
03721     (fe).dwAspect = DVASPECT_CONTENT; \
03722     (fe).ptd =NULL;\
03723     (fe).tymed = med;\
03724     (fe).lindex = -1;\
03725 };
03726 
03727 /*
03728  * DATAOBJECT Helper functions
03729  */
03730 
03731 /***********************************************************************
03732  * COMCTL32_ReleaseStgMedium
03733  *
03734  * like ReleaseStgMedium from ole32
03735  */
03736 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
03737 {
03738       if(medium.pUnkForRelease)
03739       {
03740         IUnknown_Release(medium.pUnkForRelease);
03741       }
03742       else
03743       {
03744         GlobalUnlock(medium.u.hGlobal);
03745         GlobalFree(medium.u.hGlobal);
03746       }
03747 }
03748 
03749 /***********************************************************************
03750  *          GetPidlFromDataObject
03751  *
03752  * Return pidl(s) by number from the cached DataObject
03753  *
03754  * nPidlIndex=0 gets the fully qualified root path
03755  */
03756 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
03757 {
03758 
03759     STGMEDIUM medium;
03760     FORMATETC formatetc;
03761     LPITEMIDLIST pidl = NULL;
03762 
03763     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
03764 
03765     if (!doSelected)
03766         return NULL;
03767     
03768     /* Set the FORMATETC structure*/
03769     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
03770 
03771     /* Get the pidls from IDataObject */
03772     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
03773     {
03774       LPIDA cida = GlobalLock(medium.u.hGlobal);
03775       if(nPidlIndex <= cida->cidl)
03776       {
03777         pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
03778       }
03779       COMCTL32_ReleaseStgMedium(medium);
03780     }
03781     return pidl;
03782 }
03783 
03784 /***********************************************************************
03785  *          GetNumSelected
03786  *
03787  * Return the number of selected items in the DataObject.
03788  *
03789 */
03790 static UINT GetNumSelected( IDataObject *doSelected )
03791 {
03792     UINT retVal = 0;
03793     STGMEDIUM medium;
03794     FORMATETC formatetc;
03795 
03796     TRACE("sv=%p\n", doSelected);
03797 
03798     if (!doSelected) return 0;
03799 
03800     /* Set the FORMATETC structure*/
03801     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
03802 
03803     /* Get the pidls from IDataObject */
03804     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
03805     {
03806       LPIDA cida = GlobalLock(medium.u.hGlobal);
03807       retVal = cida->cidl;
03808       COMCTL32_ReleaseStgMedium(medium);
03809       return retVal;
03810     }
03811     return 0;
03812 }
03813 
03814 /*
03815  * TOOLS
03816  */
03817 
03818 /***********************************************************************
03819  *      GetName
03820  *
03821  * Get the pidl's display name (relative to folder) and
03822  * put it in lpstrFileName.
03823  *
03824  * Return NOERROR on success,
03825  * E_FAIL otherwise
03826  */
03827 
03828 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
03829 {
03830   STRRET str;
03831   HRESULT hRes;
03832 
03833   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
03834 
03835   if(!lpsf)
03836   {
03837     SHGetDesktopFolder(&lpsf);
03838     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
03839     IShellFolder_Release(lpsf);
03840     return hRes;
03841   }
03842 
03843   /* Get the display name of the pidl relative to the folder */
03844   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
03845   {
03846       return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
03847   }
03848   return E_FAIL;
03849 }
03850 
03851 /***********************************************************************
03852  *      GetShellFolderFromPidl
03853  *
03854  * pidlRel is the item pidl relative
03855  * Return the IShellFolder of the absolute pidl
03856  */
03857 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
03858 {
03859   IShellFolder *psf = NULL,*psfParent;
03860 
03861   TRACE("%p\n", pidlAbs);
03862 
03863   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
03864   {
03865     psf = psfParent;
03866     if(pidlAbs && pidlAbs->mkid.cb)
03867     {
03868       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
03869       {
03870     IShellFolder_Release(psfParent);
03871         return psf;
03872       }
03873     }
03874     /* return the desktop */
03875     return psfParent;
03876   }
03877   return NULL;
03878 }
03879 
03880 /***********************************************************************
03881  *      GetParentPidl
03882  *
03883  * Return the LPITEMIDLIST to the parent of the pidl in the list
03884  */
03885 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
03886 {
03887   LPITEMIDLIST pidlParent;
03888 
03889   TRACE("%p\n", pidl);
03890 
03891   pidlParent = COMDLG32_PIDL_ILClone(pidl);
03892   COMDLG32_PIDL_ILRemoveLastID(pidlParent);
03893 
03894   return pidlParent;
03895 }
03896 
03897 /***********************************************************************
03898  *      GetPidlFromName
03899  *
03900  * returns the pidl of the file name relative to folder
03901  * NULL if an error occurred
03902  */
03903 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
03904 {
03905   LPITEMIDLIST pidl = NULL;
03906   ULONG ulEaten;
03907 
03908   TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
03909 
03910   if(!lpcstrFileName) return NULL;
03911   if(!*lpcstrFileName) return NULL;
03912 
03913   if(!lpsf)
03914   {
03915     if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
03916         IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
03917         IShellFolder_Release(lpsf);
03918     }
03919   }
03920   else
03921   {
03922     IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
03923   }
03924   return pidl;
03925 }
03926 
03927 /*
03928 */
03929 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
03930 {
03931     ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
03932     HRESULT ret;
03933 
03934     TRACE("%p, %p\n", psf, pidl);
03935 
03936     ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
03937 
03938     TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
03939     /* see documentation shell 4.1*/
03940         return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
03941 }
03942 
03943 /***********************************************************************
03944  *      BrowseSelectedFolder
03945  */
03946 static BOOL BrowseSelectedFolder(HWND hwnd)
03947 {
03948   BOOL bBrowseSelFolder = FALSE;
03949   FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
03950 
03951   TRACE("\n");
03952 
03953   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
03954   {
03955       LPITEMIDLIST pidlSelection;
03956 
03957       /* get the file selected */
03958       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
03959       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
03960       {
03961           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
03962                          pidlSelection, SBSP_RELATIVE ) ) )
03963           {
03964                static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
03965                                    ' ','n','o','t',' ','e','x','i','s','t',0};
03966                MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
03967           }
03968           bBrowseSelFolder = TRUE;
03969           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
03970               SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
03971       }
03972       COMDLG32_SHFree( pidlSelection );
03973   }
03974 
03975   return bBrowseSelFolder;
03976 }
03977 
03978 /*
03979  * Memory allocation methods */
03980 static void *MemAlloc(UINT size)
03981 {
03982     return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
03983 }
03984 
03985 static void MemFree(void *mem)
03986 {
03987     HeapFree(GetProcessHeap(),0,mem);
03988 }
03989 
03990 /*
03991  * Old-style (win3.1) dialogs */
03992 
03993 /***********************************************************************
03994  *           FD32_GetTemplate                                  [internal]
03995  *
03996  * Get a template (or FALSE if failure) when 16 bits dialogs are used
03997  * by a 32 bits application
03998  *
03999  */
04000 BOOL FD32_GetTemplate(PFD31_DATA lfs)
04001 {
04002     LPOPENFILENAMEW ofnW = lfs->ofnW;
04003     LPOPENFILENAMEA ofnA = lfs->ofnA;
04004     HANDLE hDlgTmpl;
04005 
04006     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
04007     {
04008     if (!(lfs->template = LockResource( ofnW->hInstance )))
04009     {
04010         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
04011         return FALSE;
04012     }
04013     }
04014     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
04015     {
04016     HRSRC hResInfo;
04017         if (ofnA)
04018         hResInfo = FindResourceA(ofnA->hInstance,
04019                  ofnA->lpTemplateName,
04020                                  (LPSTR)RT_DIALOG);
04021         else
04022         hResInfo = FindResourceW(ofnW->hInstance,
04023                  ofnW->lpTemplateName,
04024                                  (LPWSTR)RT_DIALOG);
04025         if (!hResInfo)
04026     {
04027         COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
04028         return FALSE;
04029     }
04030     if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
04031                 hResInfo)) ||
04032             !(lfs->template = LockResource(hDlgTmpl)))
04033     {
04034         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
04035         return FALSE;
04036     }
04037     } else { /* get it from internal Wine resource */
04038     HRSRC hResInfo;
04039     if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
04040              lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
04041     {
04042         COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
04043         return FALSE;
04044         }
04045         if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
04046                 !(lfs->template = LockResource( hDlgTmpl )))
04047         {
04048             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
04049             return FALSE;
04050         }
04051     }
04052     return TRUE;
04053 }
04054 
04055 
04056 /***********************************************************************
04057  *                              FD32_WMMeasureItem           [internal]
04058  */
04059 static LONG FD32_WMMeasureItem(LPARAM lParam)
04060 {
04061     LPMEASUREITEMSTRUCT lpmeasure;
04062 
04063     lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
04064     lpmeasure->itemHeight = FD31_GetFldrHeight();
04065     return TRUE;
04066 }
04067 
04068 
04069 /***********************************************************************
04070  *           FileOpenDlgProc                                    [internal]
04071  *      Used for open and save, in fact.
04072  */
04073 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
04074                                              WPARAM wParam, LPARAM lParam)
04075 {
04076     PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
04077 
04078     TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
04079     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
04080         {
04081             INT_PTR lRet;
04082             lRet  = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
04083             if (lRet)
04084                 return lRet;         /* else continue message processing */
04085         }
04086     switch (wMsg)
04087     {
04088     case WM_INITDIALOG:
04089         return FD31_WMInitDialog(hWnd, wParam, lParam);
04090 
04091     case WM_MEASUREITEM:
04092         return FD32_WMMeasureItem(lParam);
04093 
04094     case WM_DRAWITEM:
04095         return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
04096 
04097     case WM_COMMAND:
04098         return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
04099 #if 0
04100     case WM_CTLCOLOR:
04101          SetBkColor((HDC16)wParam, 0x00C0C0C0);
04102          switch (HIWORD(lParam))
04103          {
04104      case CTLCOLOR_BTN:
04105          SetTextColor((HDC16)wParam, 0x00000000);
04106              return hGRAYBrush;
04107     case CTLCOLOR_STATIC:
04108              SetTextColor((HDC16)wParam, 0x00000000);
04109              return hGRAYBrush;
04110     }
04111       break;
04112 #endif
04113     }
04114     return FALSE;
04115 }
04116 
04117 
04118 /***********************************************************************
04119  *           GetFileName31A                                 [internal]
04120  *
04121  * Creates a win31 style dialog box for the user to select a file to open/save.
04122  */
04123 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
04124                            UINT dlgType /* type dialogue : open/save */
04125                            )
04126 {
04127     BOOL bRet = FALSE;
04128     PFD31_DATA lfs;
04129 
04130     if (!lpofn || !FD31_Init()) return FALSE;
04131 
04132     TRACE("ofn flags %08x\n", lpofn->Flags);
04133     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
04134     if (lfs)
04135     {
04136         bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
04137                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
04138         FD31_DestroyPrivate(lfs);
04139     }
04140 
04141     TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
04142     return bRet;
04143 }
04144 
04145 /***********************************************************************
04146  *           GetFileName31W                                 [internal]
04147  *
04148  * Creates a win31 style dialog box for the user to select a file to open/save
04149  */
04150 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
04151                            UINT dlgType /* type dialogue : open/save */
04152                            )
04153 {
04154     BOOL bRet = FALSE;
04155     PFD31_DATA lfs;
04156 
04157     if (!lpofn || !FD31_Init()) return FALSE;
04158 
04159     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
04160     if (lfs)
04161     {
04162         bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
04163                                         FD32_FileOpenDlgProc, (LPARAM)lfs);
04164         FD31_DestroyPrivate(lfs);
04165     }
04166 
04167     TRACE("file %s, file offset %d, ext offset %d\n",
04168           debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
04169     return bRet;
04170 }
04171 
04172 /* ------------------ APIs ---------------------- */
04173 
04174 /***********************************************************************
04175  *            GetOpenFileNameA  (COMDLG32.@)
04176  *
04177  * Creates a dialog box for the user to select a file to open.
04178  *
04179  * RETURNS
04180  *    TRUE on success: user enters a valid file
04181  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
04182  *
04183  */
04184 BOOL WINAPI GetOpenFileNameA(
04185     LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
04186 {
04187     BOOL win16look = FALSE;
04188 
04189     TRACE("flags %08x\n", ofn->Flags);
04190 
04191     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
04192     if (ofn->Flags & OFN_FILEMUSTEXIST)
04193         ofn->Flags |= OFN_PATHMUSTEXIST;
04194 
04195     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
04196         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
04197 
04198     if (win16look)
04199         return GetFileName31A(ofn, OPEN_DIALOG);
04200     else
04201         return GetFileDialog95A(ofn, OPEN_DIALOG);
04202 }
04203 
04204 /***********************************************************************
04205  *            GetOpenFileNameW (COMDLG32.@)
04206  *
04207  * Creates a dialog box for the user to select a file to open.
04208  *
04209  * RETURNS
04210  *    TRUE on success: user enters a valid file
04211  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
04212  *
04213  */
04214 BOOL WINAPI GetOpenFileNameW(
04215     LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
04216 {
04217     BOOL win16look = FALSE;
04218 
04219     TRACE("flags %08x\n", ofn->Flags);
04220 
04221     /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
04222     if (ofn->Flags & OFN_FILEMUSTEXIST)
04223         ofn->Flags |= OFN_PATHMUSTEXIST;
04224 
04225     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
04226         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
04227 
04228     if (win16look)
04229         return GetFileName31W(ofn, OPEN_DIALOG);
04230     else
04231         return GetFileDialog95W(ofn, OPEN_DIALOG);
04232 }
04233 
04234 
04235 /***********************************************************************
04236  *            GetSaveFileNameA  (COMDLG32.@)
04237  *
04238  * Creates a dialog box for the user to select a file to save.
04239  *
04240  * RETURNS
04241  *    TRUE on success: user enters a valid file
04242  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
04243  *
04244  */
04245 BOOL WINAPI GetSaveFileNameA(
04246     LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
04247 {
04248     BOOL win16look = FALSE;
04249 
04250     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
04251         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
04252 
04253     if (win16look)
04254         return GetFileName31A(ofn, SAVE_DIALOG);
04255     else
04256         return GetFileDialog95A(ofn, SAVE_DIALOG);
04257 }
04258 
04259 /***********************************************************************
04260  *            GetSaveFileNameW  (COMDLG32.@)
04261  *
04262  * Creates a dialog box for the user to select a file to save.
04263  *
04264  * RETURNS
04265  *    TRUE on success: user enters a valid file
04266  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
04267  *
04268  */
04269 BOOL WINAPI GetSaveFileNameW(
04270     LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
04271 {
04272     BOOL win16look = FALSE;
04273 
04274     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
04275         win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
04276 
04277     if (win16look)
04278         return GetFileName31W(ofn, SAVE_DIALOG);
04279     else
04280         return GetFileDialog95W(ofn, SAVE_DIALOG);
04281 }
04282 
04283 /***********************************************************************
04284  *  GetFileTitleA       (COMDLG32.@)
04285  *
04286  * See GetFileTitleW.
04287  */
04288 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
04289 {
04290     int ret;
04291     UNICODE_STRING strWFile;
04292     LPWSTR lpWTitle;
04293 
04294     RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
04295     lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
04296     ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
04297     if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
04298     RtlFreeUnicodeString( &strWFile );
04299     RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
04300     return ret;
04301 }
04302 
04303 
04304 /***********************************************************************
04305  *  GetFileTitleW       (COMDLG32.@)
04306  *
04307  * Get the name of a file.
04308  *
04309  * PARAMS
04310  *  lpFile  [I] name and location of file
04311  *  lpTitle [O] returned file name
04312  *  cbBuf   [I] buffer size of lpTitle
04313  *
04314  * RETURNS
04315  *  Success: zero
04316  *  Failure: negative number.
04317  */
04318 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
04319 {
04320     int i, len;
04321         static const WCHAR brkpoint[] = {'*','[',']',0};
04322     TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
04323 
04324     if(lpFile == NULL || lpTitle == NULL)
04325         return -1;
04326 
04327     len = lstrlenW(lpFile);
04328 
04329     if (len == 0)
04330         return -1;
04331 
04332     if(strpbrkW(lpFile, brkpoint))
04333         return -1;
04334 
04335     len--;
04336 
04337     if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
04338         return -1;
04339 
04340     for(i = len; i >= 0; i--)
04341     {
04342         if (lpFile[i] == '/' ||  lpFile[i] == '\\' ||  lpFile[i] == ':')
04343         {
04344             i++;
04345             break;
04346         }
04347     }
04348 
04349     if(i == -1)
04350         i++;
04351 
04352     TRACE("---> %s\n", debugstr_w(&lpFile[i]));
04353 
04354     len = lstrlenW(lpFile+i)+1;
04355     if(cbBuf < len)
04356         return len;
04357 
04358     lstrcpyW(lpTitle, &lpFile[i]);
04359     return 0;
04360 }

Generated on Sun May 27 2012 04:23:07 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.