1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_fpicker.hxx" 26 27 //------------------------------------------------------------------------ 28 // includes 29 //------------------------------------------------------------------------ 30 31 #include <stdio.h> 32 #include <osl/diagnose.h> 33 #include "getfilenamewrapper.hxx" 34 35 #if defined _MSC_VER 36 #pragma warning(push, 1) 37 #endif 38 #include <objbase.h> 39 #include <process.h> 40 #if defined _MSC_VER 41 #pragma warning(pop) 42 #endif 43 44 namespace /* private */ 45 { 46 47 //----------------------------------------------- 48 // This class prevents changing of the working 49 // directory. 50 //----------------------------------------------- 51 class CurDirGuard 52 { 53 sal_Bool m_bValid; 54 wchar_t* m_pBuffer; 55 DWORD m_nBufLen; 56 57 public: 58 CurDirGuard() 59 : m_bValid( sal_False ) 60 , m_pBuffer( NULL ) 61 , m_nBufLen( 0 ) 62 { 63 m_nBufLen = GetCurrentDirectoryW( 0, NULL ); 64 if ( m_nBufLen ) 65 { 66 m_pBuffer = new wchar_t[m_nBufLen]; 67 m_bValid = ( GetCurrentDirectoryW( m_nBufLen, m_pBuffer ) == ( m_nBufLen - 1 ) ); 68 } 69 } 70 71 ~CurDirGuard() 72 { 73 bool bDirSet = false; 74 75 if ( m_pBuffer ) 76 { 77 if ( m_bValid ) 78 { 79 if ( m_nBufLen - 1 > MAX_PATH ) 80 { 81 if ( (LONG32)GetVersion() < 0 ) 82 { 83 // this is Win 98/ME branch, such a long path can not be set 84 // use the system path as fallback later 85 } 86 else 87 { 88 DWORD nNewLen = m_nBufLen + 8; 89 wchar_t* pNewBuffer = new wchar_t[nNewLen]; 90 if ( m_nBufLen > 3 && m_pBuffer[0] == (wchar_t)'\\' && m_pBuffer[1] == (wchar_t)'\\' ) 91 { 92 if ( m_pBuffer[2] == (wchar_t)'?' ) 93 _snwprintf( pNewBuffer, nNewLen, L"%s", m_pBuffer ); 94 else 95 _snwprintf( pNewBuffer, nNewLen, L"\\\\?\\UNC\\%s", m_pBuffer+2 ); 96 } 97 else 98 _snwprintf( pNewBuffer, nNewLen, L"\\\\?\\%s", m_pBuffer ); 99 bDirSet = SetCurrentDirectoryW( pNewBuffer ); 100 101 delete [] pNewBuffer; 102 } 103 } 104 else 105 bDirSet = SetCurrentDirectoryW( m_pBuffer ); 106 } 107 108 delete [] m_pBuffer; 109 m_pBuffer = NULL; 110 } 111 112 if ( !bDirSet ) 113 { 114 // the fallback solution 115 wchar_t pPath[MAX_PATH+1]; 116 if ( GetWindowsDirectoryW( pPath, MAX_PATH+1 ) <= MAX_PATH ) 117 { 118 SetCurrentDirectoryW( pPath ); 119 } 120 else 121 { 122 // the system path is also too long?!! 123 } 124 } 125 } 126 }; 127 128 //----------------------------------------------- 129 // 130 //----------------------------------------------- 131 132 struct GetFileNameParam 133 { 134 GetFileNameParam(bool bOpen, LPOPENFILENAME lpofn) : 135 m_bOpen(bOpen), 136 m_lpofn(lpofn), 137 m_bRet(false), 138 m_ExtErr(0) 139 {} 140 141 bool m_bOpen; 142 LPOPENFILENAME m_lpofn; 143 bool m_bRet; 144 int m_ExtErr; 145 }; 146 147 //----------------------------------------------- 148 // 149 //----------------------------------------------- 150 151 unsigned __stdcall ThreadProc(void* pParam) 152 { 153 CurDirGuard aGuard; 154 155 GetFileNameParam* lpgfnp = 156 reinterpret_cast<GetFileNameParam*>(pParam); 157 158 HRESULT hr = OleInitialize( NULL ); 159 160 if (lpgfnp->m_bOpen) 161 lpgfnp->m_bRet = GetOpenFileName(lpgfnp->m_lpofn); 162 else 163 lpgfnp->m_bRet = GetSaveFileName(lpgfnp->m_lpofn); 164 165 lpgfnp->m_ExtErr = CommDlgExtendedError(); 166 167 if ( SUCCEEDED( hr ) ) 168 OleUninitialize(); 169 170 return 0; 171 } 172 173 //----------------------------------------------- 174 // exceutes GetOpenFileName/GetSaveFileName in 175 // a separat thread 176 //----------------------------------------------- 177 178 bool ThreadExecGetFileName(LPOPENFILENAME lpofn, bool bOpen, /*out*/ int& ExtErr) 179 { 180 GetFileNameParam gfnp(bOpen,lpofn); 181 unsigned id; 182 183 HANDLE hThread = reinterpret_cast<HANDLE>( 184 _beginthreadex(0, 0, ThreadProc, &gfnp, 0, &id)); 185 186 OSL_POSTCOND(hThread, "could not create STA thread"); 187 188 WaitForSingleObject(hThread, INFINITE); 189 CloseHandle(hThread); 190 191 ExtErr = gfnp.m_ExtErr; 192 193 return gfnp.m_bRet; 194 } 195 196 //----------------------------------------------- 197 // This function returns true if the calling 198 // thread belongs to a Multithreaded Appartment 199 // (MTA) 200 //----------------------------------------------- 201 202 bool IsMTA() 203 { 204 HRESULT hr = CoInitialize(NULL); 205 206 if (RPC_E_CHANGED_MODE == hr) 207 return true; 208 209 if(SUCCEEDED(hr)) 210 CoUninitialize(); 211 212 return false; 213 } 214 215 } // namespace private 216 217 218 //----------------------------------------------- 219 // 220 //----------------------------------------------- 221 222 CGetFileNameWrapper::CGetFileNameWrapper() : 223 m_ExtendedDialogError(0) 224 { 225 } 226 227 //----------------------------------------------- 228 // 229 //----------------------------------------------- 230 231 bool CGetFileNameWrapper::getOpenFileName(LPOPENFILENAME lpofn) 232 { 233 OSL_PRECOND(lpofn,"invalid parameter"); 234 235 bool bRet = false; 236 237 if (IsMTA()) 238 { 239 bRet = ThreadExecGetFileName( 240 lpofn, true, m_ExtendedDialogError); 241 } 242 else 243 { 244 CurDirGuard aGuard; 245 246 HRESULT hr = OleInitialize( NULL ); 247 248 bRet = GetOpenFileName(lpofn); 249 m_ExtendedDialogError = CommDlgExtendedError(); 250 251 if ( SUCCEEDED( hr ) ) 252 OleUninitialize(); 253 } 254 255 return bRet; 256 } 257 258 //----------------------------------------------- 259 // 260 //----------------------------------------------- 261 262 bool CGetFileNameWrapper::getSaveFileName(LPOPENFILENAME lpofn) 263 { 264 OSL_PRECOND(lpofn,"invalid parameter"); 265 266 bool bRet = false; 267 268 if (IsMTA()) 269 { 270 bRet = ThreadExecGetFileName( 271 lpofn, false, m_ExtendedDialogError); 272 } 273 else 274 { 275 CurDirGuard aGuard; 276 277 bRet = GetSaveFileName(lpofn); 278 m_ExtendedDialogError = CommDlgExtendedError(); 279 } 280 281 return bRet; 282 } 283 284 //----------------------------------------------- 285 // 286 //----------------------------------------------- 287 288 int CGetFileNameWrapper::commDlgExtendedError( ) 289 { 290 return m_ExtendedDialogError; 291 } 292 293