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:
CurDirGuard()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 
~CurDirGuard()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 	{
GetFileNameParam__anon87bd22bc0111::GetFileNameParam134 		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 
ThreadProc(void * pParam)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 
ThreadExecGetFileName(LPOPENFILENAME lpofn,bool bOpen,int & ExtErr)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 
IsMTA()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 
CGetFileNameWrapper()222 CGetFileNameWrapper::CGetFileNameWrapper() :
223 	m_ExtendedDialogError(0)
224 {
225 }
226 
227 //-----------------------------------------------
228 //
229 //-----------------------------------------------
230 
getOpenFileName(LPOPENFILENAME lpofn)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 
getSaveFileName(LPOPENFILENAME lpofn)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 
commDlgExtendedError()288 int CGetFileNameWrapper::commDlgExtendedError( )
289 {
290     return m_ExtendedDialogError;
291 }
292 
293