Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfiledlg.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
1.7.6.1
|