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