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