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_cppuhelper.hxx"
26
27 #include "osl/diagnose.h"
28 #include "osl/doublecheckedlocking.h"
29 #include "osl/mutex.hxx"
30 #include "uno/dispatcher.hxx"
31 #include "uno/mapping.hxx"
32 #include "cppuhelper/detail/XExceptionThrower.hpp"
33 #include "com/sun/star/uno/RuntimeException.hpp"
34
35 #include "cppuhelper/exc_hlp.hxx"
36
37 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
38
39
40 using namespace ::rtl;
41 using namespace ::osl;
42 using namespace ::cppu;
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::uno;
45
46 namespace
47 {
48
49 using cppuhelper::detail::XExceptionThrower;
50
51 //==============================================================================
52 struct ExceptionThrower : public uno_Interface, XExceptionThrower
53 {
54 inline ExceptionThrower();
55
56 public:
57 static ExceptionThrower * get();
getCppuType__anonc25f52000111::ExceptionThrower58 static inline Type const & getCppuType()
59 {
60 return ::getCppuType(
61 reinterpret_cast< Reference< XExceptionThrower > const * >(0) );
62 }
63
64 // XInterface
65 virtual Any SAL_CALL queryInterface( Type const & type )
66 throw (RuntimeException);
67 virtual void SAL_CALL acquire() throw ();
68 virtual void SAL_CALL release() throw ();
69
70 // XExceptionThrower
71 virtual void SAL_CALL throwException( Any const & exc ) throw (Exception);
72 virtual void SAL_CALL rethrowException() throw (Exception);
73 };
74
75 extern "C"
76 {
77
78 //------------------------------------------------------------------------------
ExceptionThrower_acquire_release_nop(uno_Interface *)79 static void SAL_CALL ExceptionThrower_acquire_release_nop( uno_Interface * )
80 {
81 }
82
83 //------------------------------------------------------------------------------
ExceptionThrower_dispatch(uno_Interface * pUnoI,typelib_TypeDescription const * pMemberType,void * pReturn,void * pArgs[],uno_Any ** ppException)84 static void SAL_CALL ExceptionThrower_dispatch(
85 uno_Interface * pUnoI, typelib_TypeDescription const * pMemberType,
86 void * pReturn, void * pArgs [], uno_Any ** ppException )
87 {
88 OSL_ASSERT( pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD );
89
90 switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription * >(
91 const_cast< typelib_TypeDescription * >( pMemberType ) )->
92 nPosition)
93 {
94 case 0: // queryInterace()
95 {
96 Type const & rType_demanded =
97 *reinterpret_cast< Type const * >( pArgs[ 0 ] );
98 if (rType_demanded.equals(
99 ::getCppuType( reinterpret_cast<
100 Reference< XInterface > const * >(0) ) ) ||
101 rType_demanded.equals( ExceptionThrower::getCppuType() ))
102 {
103 typelib_TypeDescription * pTD = 0;
104 TYPELIB_DANGER_GET( &pTD, rType_demanded.getTypeLibType() );
105 uno_any_construct(
106 reinterpret_cast< uno_Any * >( pReturn ), &pUnoI, pTD, 0 );
107 TYPELIB_DANGER_RELEASE( pTD );
108 }
109 else
110 {
111 uno_any_construct(
112 reinterpret_cast< uno_Any * >( pReturn ), 0, 0, 0 );
113 }
114 *ppException = 0;
115 break;
116 }
117 case 1: // acquire()
118 case 2: // release()
119 *ppException = 0;
120 break;
121 case 3: // throwException()
122 {
123 uno_Any * pAny = reinterpret_cast< uno_Any * >( pArgs[ 0 ] );
124 OSL_ASSERT( pAny->pType->eTypeClass == typelib_TypeClass_EXCEPTION );
125 uno_type_any_construct( *ppException, pAny->pData, pAny->pType, 0 );
126 break;
127 }
128 default:
129 {
130 OSL_ASSERT( 0 );
131 RuntimeException exc(
132 OUSTR("not implemented!"), Reference< XInterface >() );
133 uno_type_any_construct(
134 *ppException, &exc, ::getCppuType( &exc ).getTypeLibType(), 0 );
135 break;
136 }
137 }
138 }
139
140 } // extern "C"
141
142 //______________________________________________________________________________
queryInterface(Type const & type)143 Any ExceptionThrower::queryInterface( Type const & type )
144 throw (RuntimeException)
145 {
146 if (type.equals( ::getCppuType( reinterpret_cast<
147 Reference< XInterface > const * >(0) ) ) ||
148 type.equals( ExceptionThrower::getCppuType() ))
149 {
150 XExceptionThrower * that = static_cast< XExceptionThrower * >( this );
151 return Any( &that, type );
152 }
153 return Any();
154 }
155
156 //______________________________________________________________________________
acquire()157 void ExceptionThrower::acquire() throw ()
158 {
159 }
160 //______________________________________________________________________________
release()161 void ExceptionThrower::release() throw ()
162 {
163 }
164
165 //______________________________________________________________________________
throwException(Any const & exc)166 void ExceptionThrower::throwException( Any const & exc ) throw (Exception)
167 {
168 OSL_ENSURE( 0, "unexpected!" );
169 ::cppu::throwException( exc );
170 }
171
172 //______________________________________________________________________________
rethrowException()173 void ExceptionThrower::rethrowException() throw (Exception)
174 {
175 throw;
176 }
177
178 //______________________________________________________________________________
ExceptionThrower()179 inline ExceptionThrower::ExceptionThrower()
180 {
181 uno_Interface::acquire = ExceptionThrower_acquire_release_nop;
182 uno_Interface::release = ExceptionThrower_acquire_release_nop;
183 uno_Interface::pDispatcher = ExceptionThrower_dispatch;
184 }
185
186 //______________________________________________________________________________
get()187 ExceptionThrower * ExceptionThrower::get()
188 {
189 ExceptionThrower * s_pThrower = 0;
190 if (s_pThrower == 0)
191 {
192 MutexGuard guard( Mutex::getGlobalMutex() );
193 static ExceptionThrower s_thrower;
194 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
195 s_pThrower = &s_thrower;
196 }
197 else
198 {
199 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
200 }
201 return s_pThrower;
202 }
203
204 } // anonymous namespace
205
206
207 namespace cppu
208 {
209
210 //==============================================================================
throwException(Any const & exc)211 void SAL_CALL throwException( Any const & exc ) SAL_THROW( (Exception) )
212 {
213 if (exc.getValueTypeClass() != TypeClass_EXCEPTION)
214 {
215 throw RuntimeException(
216 OUSTR("no UNO exception given "
217 "(must be derived from com::sun::star::uno::Exception)!"),
218 Reference< XInterface >() );
219 }
220
221 Mapping uno2cpp(Environment(OUSTR(UNO_LB_UNO)), Environment::getCurrent());
222 if (! uno2cpp.is())
223 {
224 throw RuntimeException(
225 OUSTR("cannot get binary UNO to C++ mapping!"),
226 Reference< XInterface >() );
227 }
228
229 Reference< XExceptionThrower > xThrower;
230 uno2cpp.mapInterface(
231 reinterpret_cast< void ** >( &xThrower ),
232 static_cast< uno_Interface * >( ExceptionThrower::get() ),
233 ExceptionThrower::getCppuType() );
234 OSL_ASSERT( xThrower.is() );
235 xThrower->throwException( exc );
236 }
237
238 //==============================================================================
getCaughtException()239 Any SAL_CALL getCaughtException()
240 {
241 Mapping cpp2uno(Environment::getCurrent(), Environment(OUSTR(UNO_LB_UNO)));
242 if (! cpp2uno.is())
243 {
244 throw RuntimeException(
245 OUSTR("cannot get C++ to binary UNO mapping!"),
246 Reference< XInterface >() );
247 }
248 Mapping uno2cpp(Environment(OUSTR(UNO_LB_UNO)), Environment::getCurrent());
249 if (! uno2cpp.is())
250 {
251 throw RuntimeException(
252 OUSTR("cannot get binary UNO to C++ mapping!"),
253 Reference< XInterface >() );
254 }
255
256 typelib_TypeDescription * pTD = 0;
257 TYPELIB_DANGER_GET(
258 &pTD, ExceptionThrower::getCppuType().getTypeLibType() );
259
260 UnoInterfaceReference unoI;
261 cpp2uno.mapInterface(
262 reinterpret_cast< void ** >( &unoI.m_pUnoI ),
263 static_cast< XExceptionThrower * >( ExceptionThrower::get() ), pTD );
264 OSL_ASSERT( unoI.is() );
265
266 typelib_TypeDescription * pMemberTD = 0;
267 TYPELIB_DANGER_GET(
268 &pMemberTD,
269 reinterpret_cast< typelib_InterfaceTypeDescription * >( pTD )->
270 ppMembers[ 1 ] /* rethrowException() */ );
271
272 uno_Any exc_mem;
273 uno_Any * exc = &exc_mem;
274 unoI.dispatch( pMemberTD, 0, 0, &exc );
275
276 TYPELIB_DANGER_RELEASE( pMemberTD );
277 TYPELIB_DANGER_RELEASE( pTD );
278
279 if (exc == 0)
280 {
281 throw RuntimeException(
282 OUSTR("rethrowing C++ exception failed!"),
283 Reference< XInterface >() );
284 }
285
286 Any ret;
287 uno_any_destruct( &ret, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
288 uno_type_any_constructAndConvert(
289 &ret, exc->pData, exc->pType, uno2cpp.get() );
290 uno_any_destruct( exc, 0 );
291 return ret;
292 }
293
294 }
295