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