xref: /aoo42x/main/pyuno/source/module/pyuno.cxx (revision 77dc4149)
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 #include "pyuno_impl.hxx"
25 
26 #include <rtl/strbuf.hxx>
27 #include <rtl/ustrbuf.hxx>
28 
29 #include <osl/thread.h>
30 
31 #include <com/sun/star/lang/XServiceInfo.hpp>
32 #include <com/sun/star/lang/XTypeProvider.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/beans/XMaterialHolder.hpp>
35 
36 #define TO_ASCII(x) OUStringToOString( x , RTL_TEXTENCODING_ASCII_US).getStr()
37 
38 using rtl::OStringBuffer;
39 using rtl::OUStringBuffer;
40 using rtl::OUStringToOString;
41 using rtl::OUString;
42 using com::sun::star::uno::Sequence;
43 using com::sun::star::uno::Reference;
44 using com::sun::star::uno::XInterface;
45 using com::sun::star::uno::Any;
46 using com::sun::star::uno::makeAny;
47 using com::sun::star::uno::UNO_QUERY;
48 using com::sun::star::uno::Type;
49 using com::sun::star::uno::TypeClass;
50 using com::sun::star::uno::RuntimeException;
51 using com::sun::star::uno::Exception;
52 using com::sun::star::uno::XComponentContext;
53 using com::sun::star::lang::XSingleServiceFactory;
54 using com::sun::star::lang::XServiceInfo;
55 using com::sun::star::lang::XTypeProvider;
56 using com::sun::star::script::XTypeConverter;
57 using com::sun::star::script::XInvocation2;
58 using com::sun::star::beans::XMaterialHolder;
59 
60 namespace pyuno
61 {
62 
63 PyObject *PyUNO_str( PyObject * self );
64 
65 void PyUNO_del (PyObject* self)
66 {
67     PyUNO* me = reinterpret_cast< PyUNO* > (self);
68     {
69         PyThreadDetach antiguard;
70         delete me->members;
71     }
72     PyObject_Del (self);
73 }
74 
75 
76 
77 OUString val2str( const void * pVal, typelib_TypeDescriptionReference * pTypeRef , sal_Int32 mode ) SAL_THROW( () )
78 {
79 	OSL_ASSERT( pVal );
80 	if (pTypeRef->eTypeClass == typelib_TypeClass_VOID)
81 		return OUString( RTL_CONSTASCII_USTRINGPARAM("void") );
82 
83 	OUStringBuffer buf( 64 );
84 	buf.append( (sal_Unicode)'(' );
85 	buf.append( pTypeRef->pTypeName );
86 	buf.append( (sal_Unicode)')' );
87 
88 	switch (pTypeRef->eTypeClass)
89 	{
90 	case typelib_TypeClass_INTERFACE:
91     {
92 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
93 		buf.append( reinterpret_cast< sal_IntPtr >(*(void **)pVal), 16 );
94         if( VAL2STR_MODE_DEEP == mode )
95         {
96             buf.appendAscii( "{" );        Reference< XInterface > r = *( Reference< XInterface > * ) pVal;
97             Reference< XServiceInfo > serviceInfo( r, UNO_QUERY);
98             Reference< XTypeProvider > typeProvider(r,UNO_QUERY);
99             if( serviceInfo.is() )
100             {
101                 buf.appendAscii("implementationName=" );
102                 buf.append(serviceInfo->getImplementationName() );
103                 buf.appendAscii(", supportedServices={" );
104                 Sequence< OUString > seq = serviceInfo->getSupportedServiceNames();
105                 for( int i = 0 ; i < seq.getLength() ; i ++ )
106                 {
107                     buf.append( seq[i] );
108                     if( i +1 != seq.getLength() )
109                         buf.appendAscii( "," );
110                 }
111                 buf.appendAscii("}");
112             }
113 
114             if( typeProvider.is() )
115             {
116                 buf.appendAscii(", supportedInterfaces={" );
117                 Sequence< Type > seq (typeProvider->getTypes());
118                 for( int i = 0 ; i < seq.getLength() ; i ++ )
119                 {
120                     buf.append(seq[i].getTypeName());
121                     if( i +1 != seq.getLength() )
122                         buf.appendAscii( "," );
123                 }
124                 buf.appendAscii("}");
125             }
126             buf.appendAscii( "}" );
127         }
128 
129 		break;
130     }
131 	case typelib_TypeClass_UNION:
132 	{
133 //  		typelib_TypeDescription * pTypeDescr = 0;
134 //  		TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
135 //  		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") );
136 //  		buf.append( val2str( (char *)pVal + ((typelib_UnionTypeDescription *)pTypeDescr)->nValueOffset,
137 //  							 union_getSetType( pVal, pTypeDescr ) ) );
138 //  		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") );
139 //  		TYPELIB_DANGER_RELEASE( pTypeDescr );
140 		break;
141 	}
142 	case typelib_TypeClass_STRUCT:
143 	case typelib_TypeClass_EXCEPTION:
144 	{
145 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") );
146 		typelib_TypeDescription * pTypeDescr = 0;
147 		TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
148 		OSL_ASSERT( pTypeDescr );
149 
150 		typelib_CompoundTypeDescription * pCompType = (typelib_CompoundTypeDescription *)pTypeDescr;
151 		sal_Int32 nDescr = pCompType->nMembers;
152 
153 		if (pCompType->pBaseTypeDescription)
154 		{
155 			buf.append( val2str( pVal, ((typelib_TypeDescription *)pCompType->pBaseTypeDescription)->pWeakRef,mode ) );
156 			if (nDescr)
157 				buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
158 		}
159 
160 		typelib_TypeDescriptionReference ** ppTypeRefs = pCompType->ppTypeRefs;
161 		sal_Int32 * pMemberOffsets = pCompType->pMemberOffsets;
162 		rtl_uString ** ppMemberNames = pCompType->ppMemberNames;
163 
164 		for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos )
165 		{
166 			buf.append( ppMemberNames[nPos] );
167 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" = ") );
168 			typelib_TypeDescription * pMemberType = 0;
169 			TYPELIB_DANGER_GET( &pMemberType, ppTypeRefs[nPos] );
170 			buf.append( val2str( (char *)pVal + pMemberOffsets[nPos], pMemberType->pWeakRef, mode ) );
171 			TYPELIB_DANGER_RELEASE( pMemberType );
172 			if (nPos < (nDescr -1))
173 				buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
174 		}
175 
176 		TYPELIB_DANGER_RELEASE( pTypeDescr );
177 
178 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") );
179 		break;
180 	}
181 	case typelib_TypeClass_SEQUENCE:
182 	{
183 		typelib_TypeDescription * pTypeDescr = 0;
184 		TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
185 
186 		uno_Sequence * pSequence = *(uno_Sequence **)pVal;
187 		typelib_TypeDescription * pElementTypeDescr = 0;
188 		TYPELIB_DANGER_GET( &pElementTypeDescr, ((typelib_IndirectTypeDescription *)pTypeDescr)->pType );
189 
190 		sal_Int32 nElementSize = pElementTypeDescr->nSize;
191 		sal_Int32 nElements	   = pSequence->nElements;
192 
193 		if (nElements)
194 		{
195 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") );
196 			char * pElements = pSequence->elements;
197 			for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
198 			{
199 				buf.append( val2str( pElements + (nElementSize * nPos), pElementTypeDescr->pWeakRef, mode ) );
200 				if (nPos < (nElements -1))
201 					buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
202 			}
203 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") );
204 		}
205 		else
206 		{
207 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{}") );
208 		}
209 		TYPELIB_DANGER_RELEASE( pElementTypeDescr );
210 		TYPELIB_DANGER_RELEASE( pTypeDescr );
211 		break;
212 	}
213 	case typelib_TypeClass_ANY:
214 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") );
215 		buf.append( val2str( ((uno_Any *)pVal)->pData,
216 							 ((uno_Any *)pVal)->pType ,
217                              mode) );
218 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") );
219 		break;
220 	case typelib_TypeClass_TYPE:
221 		buf.append( (*(typelib_TypeDescriptionReference **)pVal)->pTypeName );
222 		break;
223 	case typelib_TypeClass_STRING:
224 		buf.append( (sal_Unicode)'\"' );
225 		buf.append( *(rtl_uString **)pVal );
226 		buf.append( (sal_Unicode)'\"' );
227 		break;
228 	case typelib_TypeClass_ENUM:
229 	{
230 		typelib_TypeDescription * pTypeDescr = 0;
231 		TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
232 
233 		sal_Int32 * pValues = ((typelib_EnumTypeDescription *)pTypeDescr)->pEnumValues;
234 		sal_Int32 nPos = ((typelib_EnumTypeDescription *)pTypeDescr)->nEnumValues;
235 		while (nPos--)
236 		{
237 			if (pValues[nPos] == *(int *)pVal)
238 				break;
239 		}
240 		if (nPos >= 0)
241 			buf.append( ((typelib_EnumTypeDescription *)pTypeDescr)->ppEnumNames[nPos] );
242 		else
243 			buf.append( (sal_Unicode)'?' );
244 
245 		TYPELIB_DANGER_RELEASE( pTypeDescr );
246 		break;
247 	}
248 	case typelib_TypeClass_BOOLEAN:
249 		if (*(sal_Bool *)pVal)
250 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("true") );
251 		else
252 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("false") );
253 		break;
254 	case typelib_TypeClass_CHAR:
255 		buf.append( (sal_Unicode)'\'' );
256 		buf.append( *(sal_Unicode *)pVal );
257 		buf.append( (sal_Unicode)'\'' );
258 		break;
259 	case typelib_TypeClass_FLOAT:
260 		buf.append( *(float *)pVal );
261 		break;
262 	case typelib_TypeClass_DOUBLE:
263 		buf.append( *(double *)pVal );
264 		break;
265 	case typelib_TypeClass_BYTE:
266 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
267 		buf.append( (sal_Int32)*(sal_Int8 *)pVal, 16 );
268 		break;
269 	case typelib_TypeClass_SHORT:
270 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
271 		buf.append( (sal_Int32)*(sal_Int16 *)pVal, 16 );
272 		break;
273 	case typelib_TypeClass_UNSIGNED_SHORT:
274 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
275 		buf.append( (sal_Int32)*(sal_uInt16 *)pVal, 16 );
276 		break;
277 	case typelib_TypeClass_LONG:
278 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
279 		buf.append( *(sal_Int32 *)pVal, 16 );
280 		break;
281 	case typelib_TypeClass_UNSIGNED_LONG:
282 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
283 		buf.append( (sal_Int64)*(sal_uInt32 *)pVal, 16 );
284 		break;
285 	case typelib_TypeClass_HYPER:
286 	case typelib_TypeClass_UNSIGNED_HYPER:
287 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
288 #if defined(GCC) && defined(SPARC)
289 		{
290 			sal_Int64 aVal;
291 			*(sal_Int32 *)&aVal = *(sal_Int32 *)pVal;
292 			*((sal_Int32 *)&aVal +1)= *((sal_Int32 *)pVal +1);
293 			buf.append( aVal, 16 );
294 		}
295 #else
296 		buf.append( *(sal_Int64 *)pVal, 16 );
297 #endif
298 		break;
299 
300 	case typelib_TypeClass_VOID:
301 	case typelib_TypeClass_ARRAY:
302 	case typelib_TypeClass_UNKNOWN:
303 	case typelib_TypeClass_SERVICE:
304 	case typelib_TypeClass_MODULE:
305 	default:
306 		buf.append( (sal_Unicode)'?' );
307 	}
308 
309 	return buf.makeStringAndClear();
310 }
311 
312 
313 PyObject *PyUNO_repr( PyObject  * self )
314 {
315     PyUNO *me = (PyUNO * ) self;
316     PyObject * ret = 0;
317 
318     if( me->members->wrappedObject.getValueType().getTypeClass()
319         == com::sun::star::uno::TypeClass_EXCEPTION )
320     {
321         Reference< XMaterialHolder > rHolder(me->members->xInvocation,UNO_QUERY);
322         if( rHolder.is() )
323         {
324             Any a = rHolder->getMaterial();
325             Exception e;
326             a >>= e;
327             ret = ustring2PyUnicode(e.Message ).getAcquired();
328         }
329     }
330     else
331     {
332         ret = PyUNO_str( self );
333     }
334     return ret;
335 }
336 
337 PyObject *PyUNO_invoke( PyObject *object, const char *name , PyObject *args )
338 {
339     PyRef ret;
340     try
341     {
342         Runtime runtime;
343 
344         PyRef paras,callable;
345         if( PyObject_IsInstance( object, getPyUnoClass().get() ) )
346         {
347             PyUNO* me = (PyUNO*) object;
348             OUString attrName = OUString::createFromAscii(name);
349             if (! me->members->xInvocation->hasMethod (attrName))
350             {
351                 OUStringBuffer buf;
352                 buf.appendAscii( "Attribute " );
353                 buf.append( attrName );
354                 buf.appendAscii( " unknown" );
355                 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () );
356             }
357             callable = PyUNO_callable_new (
358                 me->members->xInvocation,
359                 attrName,
360                 runtime.getImpl()->cargo->xInvocation,
361                 runtime.getImpl()->cargo->xTypeConverter,
362                 ACCEPT_UNO_ANY);
363             paras = args;
364         }
365         else
366         {
367             // clean the tuple from uno.Any !
368             int size = PyTuple_Size( args );
369             { // for CC, keeping ref-count of tuple being 1
370             paras = PyRef(PyTuple_New( size ), SAL_NO_ACQUIRE);
371             }
372             for( int i = 0 ; i < size ;i ++ )
373             {
374                 PyObject * element = PyTuple_GetItem( args , i );
375                 if( PyObject_IsInstance( element , getAnyClass( runtime ).get() ) )
376                 {
377                     element = PyObject_GetAttrString(
378                         element, const_cast< char * >("value") );
379                 }
380                 else
381                 {
382                     Py_XINCREF( element );
383                 }
384                 PyTuple_SetItem( paras.get(), i , element );
385             }
386             callable = PyRef( PyObject_GetAttrString( object , (char*)name ), SAL_NO_ACQUIRE );
387             if( !callable.is() )
388                 return 0;
389         }
390         ret = PyRef( PyObject_CallObject( callable.get(), paras.get() ), SAL_NO_ACQUIRE );
391     }
392     catch (::com::sun::star::lang::IllegalArgumentException &e)
393     {
394         raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
395     }
396     catch (::com::sun::star::script::CannotConvertException &e)
397     {
398         raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
399     }
400     catch (::com::sun::star::uno::RuntimeException &e)
401     {
402         raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
403     }
404     catch (::com::sun::star::uno::Exception &e)
405     {
406         raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
407     }
408 
409     return ret.getAcquired();
410 }
411 
412 PyObject *PyUNO_str( PyObject * self )
413 {
414     PyUNO *me = ( PyUNO * ) self;
415 
416     OStringBuffer buf;
417 
418 
419     if( me->members->wrappedObject.getValueType().getTypeClass()
420         == com::sun::star::uno::TypeClass_STRUCT ||
421         me->members->wrappedObject.getValueType().getTypeClass()
422         == com::sun::star::uno::TypeClass_EXCEPTION)
423     {
424         Reference< XMaterialHolder > rHolder(me->members->xInvocation,UNO_QUERY);
425         if( rHolder.is() )
426         {
427             PyThreadDetach antiguard;
428             Any a = rHolder->getMaterial();
429             OUString s = val2str( (void*) a.getValue(), a.getValueType().getTypeLibType() );
430             buf.append( OUStringToOString(s,RTL_TEXTENCODING_ASCII_US) );
431         }
432     }
433     else
434     {
435         // a common UNO object
436         PyThreadDetach antiguard;
437         buf.append( "pyuno object " );
438 
439         OUString s = val2str( (void*)me->members->wrappedObject.getValue(),
440                               me->members->wrappedObject.getValueType().getTypeLibType() );
441         buf.append( OUStringToOString(s,RTL_TEXTENCODING_ASCII_US) );
442     }
443 
444     return PYSTR_FROMSTR( buf.getStr() );
445 }
446 
447 #if PY_MAJOR_VERSION >= 3
448 PyObject* PyUNO_getattr (PyObject* self, PyObject* attr_name)
449 #else
450 PyObject* PyUNO_getattr (PyObject* self, char* name)
451 #endif
452 {
453     PyUNO* me;
454 
455 #if PY_VERSION_HEX >= 0x03030000
456     char *name = PyUnicode_AsUTF8(attr_name);
457 #elif PY_MAJOR_VERSION >= 3
458     PyRef pUtf8(PyUnicode_AsUTF8String(attr_name), SAL_NO_ACQUIRE);
459     char *name = PyBytes_AsString(pUtf8.get());
460 #endif
461     try
462     {
463 
464         Runtime runtime;
465 
466         me = (PyUNO*) self;
467 #if PY_MAJOR_VERSION < 3
468         //Handle Python dir () stuff first...
469         if (strcmp (name, "__members__") == 0)
470         {
471             PyObject* member_list;
472             Sequence<OUString> oo_member_list;
473 
474             oo_member_list = me->members->xInvocation->getMemberNames ();
475             member_list = PyList_New (oo_member_list.getLength ());
476             for (int i = 0; i < oo_member_list.getLength (); i++)
477             {
478                 // setitem steals a reference
479                 PyList_SetItem (member_list, i, ustring2PyString(oo_member_list[i]).getAcquired() );
480             }
481             return member_list;
482         }
483 #endif
484 
485         if (strcmp (name, "__dict__") == 0)
486         {
487             Py_INCREF (Py_None);
488             return Py_None;
489         }
490 #if PY_MAJOR_VERSION < 3
491         if (strcmp (name, "__methods__") == 0)
492         {
493             Py_INCREF (Py_None);
494             return Py_None;
495         }
496 #endif
497         if (strcmp (name, "__class__") == 0)
498         {
499             if( me->members->wrappedObject.getValueTypeClass() ==
500                 com::sun::star::uno::TypeClass_STRUCT ||
501                 me->members->wrappedObject.getValueTypeClass() ==
502                 com::sun::star::uno::TypeClass_EXCEPTION )
503             {
504                 return getClass(
505                     me->members->wrappedObject.getValueType().getTypeName(), runtime ).getAcquired();
506             }
507             Py_INCREF (Py_None);
508             return Py_None;
509         }
510 
511         OUString attrName( OUString::createFromAscii( name ) );
512         //We need to find out if it's a method...
513         if (me->members->xInvocation->hasMethod (attrName))
514         {
515             //Create a callable object to invoke this...
516             PyRef ret = PyUNO_callable_new (
517                 me->members->xInvocation,
518                 attrName,
519                 runtime.getImpl()->cargo->xInvocation,
520                 runtime.getImpl()->cargo->xTypeConverter);
521             Py_XINCREF( ret.get() );
522             return ret.get();
523 
524         }
525 
526         //or a property
527         if (me->members->xInvocation->hasProperty ( attrName))
528         {
529             //Return the value of the property
530             Any anyRet;
531             {
532                 PyThreadDetach antiguard;
533                 anyRet = me->members->xInvocation->getValue (attrName);
534             }
535             PyRef ret = runtime.any2PyObject(anyRet);
536             Py_XINCREF( ret.get() );
537             return ret.get();
538         }
539 
540         //or else...
541         PyErr_SetString (PyExc_AttributeError, name);
542     }
543     catch( com::sun::star::reflection::InvocationTargetException & e )
544     {
545         raisePyExceptionWithAny( makeAny(e.TargetException) );
546     }
547     catch( com::sun::star::beans::UnknownPropertyException & e )
548     {
549         raisePyExceptionWithAny( makeAny(e) );
550     }
551     catch( com::sun::star::lang::IllegalArgumentException &e )
552     {
553         raisePyExceptionWithAny( makeAny(e) );
554     }
555     catch( com::sun::star::script::CannotConvertException &e )
556     {
557         raisePyExceptionWithAny( makeAny(e) );
558     }
559     catch( RuntimeException &e )
560     {
561         raisePyExceptionWithAny( makeAny(e) );
562     }
563 
564     return NULL;
565 }
566 
567 #if PY_MAJOR_VERSION >= 3
568 int PyUNO_setattr (PyObject* self, PyObject* attr_name, PyObject* value)
569 #else
570 int PyUNO_setattr (PyObject* self, char* name, PyObject* value)
571 #endif
572 {
573     PyUNO* me;
574 
575 #if PY_VERSION_HEX >= 0x03030000
576     char *name = PyUnicode_AsUTF8(attr_name);
577 #elif PY_MAJOR_VERSION >= 3
578     PyRef pUtf8(PyUnicode_AsUTF8String(attr_name), SAL_NO_ACQUIRE);
579     char *name = PyBytes_AsString(pUtf8.get());
580 #endif
581     me = (PyUNO*) self;
582     try
583     {
584         Runtime runtime;
585         Any val= runtime.pyObject2Any(value, ACCEPT_UNO_ANY);
586 
587         OUString attrName( OUString::createFromAscii( name ) );
588         {
589             PyThreadDetach antiguard;
590             if (me->members->xInvocation->hasProperty (attrName))
591             {
592                 me->members->xInvocation->setValue (attrName, val);
593                 return 0; //Keep with Python's boolean system
594             }
595         }
596     }
597     catch( com::sun::star::reflection::InvocationTargetException & e )
598     {
599         raisePyExceptionWithAny( makeAny(e.TargetException) );
600         return 1;
601     }
602     catch( com::sun::star::beans::UnknownPropertyException & e )
603     {
604         raisePyExceptionWithAny( makeAny(e) );
605         return 1;
606     }
607     catch( com::sun::star::script::CannotConvertException &e )
608     {
609         raisePyExceptionWithAny( makeAny(e) );
610         return 1;
611     }
612     catch( RuntimeException & e )
613     {
614         raisePyExceptionWithAny( makeAny( e ) );
615         return 1;
616     }
617     PyErr_SetString (PyExc_AttributeError, name);
618     return 1; //as above.
619 }
620 
621 #if PY_MAJOR_VERSION >= 3
622 static PyObject *PyUNO_dir( PyObject *self, PyObject *that )
623 {
624     PyUNO* me;
625     PyObject* member_list;
626     Sequence<OUString> oo_member_list;
627 
628     me = (PyUNO*) self;
629     oo_member_list = me->members->xInvocation->getMemberNames ();
630     member_list = PyList_New (oo_member_list.getLength ());
631     for (int i = 0; i < oo_member_list.getLength (); i++)
632     {
633         // setitem steals a reference
634         PyList_SetItem (member_list, i, ustring2PyUnicode(oo_member_list[i]).getAcquired() );
635     }
636     return member_list;
637 }
638 
639 static PyObject *PyUNO_richcompare( PyObject *self, PyObject *that, int op )
640 {
641     switch (op)
642     {
643     case Py_EQ:
644     case Py_NE:
645         if( self == that )
646         {
647             if (op == Py_EQ)
648                 Py_RETURN_TRUE;
649             else
650                 Py_RETURN_FALSE;
651         }
652         try
653         {
654             Runtime runtime;
655             if( PyObject_IsInstance( that, getPyUnoClass().get() ) )
656             {
657                 PyUNO *me = reinterpret_cast< PyUNO*> ( self );
658                 PyUNO *other = reinterpret_cast< PyUNO *> (that );
659                 com::sun::star::uno::TypeClass tcMe = me->members->wrappedObject.getValueTypeClass();
660                 com::sun::star::uno::TypeClass tcOther = other->members->wrappedObject.getValueTypeClass();
661 
662                 if( tcMe == tcOther )
663                 {
664                     if( tcMe == com::sun::star::uno::TypeClass_STRUCT ||
665                         tcMe == com::sun::star::uno::TypeClass_EXCEPTION )
666                     {
667                         Reference< XMaterialHolder > xMe( me->members->xInvocation,UNO_QUERY);
668                         Reference< XMaterialHolder > xOther( other->members->xInvocation,UNO_QUERY );
669                         if( xMe->getMaterial() == xOther->getMaterial() )
670                         {
671                             if (op == Py_EQ)
672                                 Py_RETURN_TRUE;
673                             else
674                                 Py_RETURN_FALSE;
675                         }
676                     }
677                     else if( tcMe == com::sun::star::uno::TypeClass_INTERFACE )
678                     {
679                         if( me->members->wrappedObject == other->members->wrappedObject )
680                         {
681                             if (op == Py_EQ)
682                                 Py_RETURN_TRUE;
683                             else
684                                 Py_RETURN_FALSE;
685                         }
686                     }
687                 }
688             }
689             if (op == Py_EQ)
690                 Py_RETURN_FALSE;
691             else
692                 Py_RETURN_TRUE;
693         }
694         catch( com::sun::star::uno::RuntimeException & e)
695         {
696             raisePyExceptionWithAny( makeAny( e ) );
697         }
698         break;
699     default:
700         PyErr_SetString(Py_NotImplemented, "not implemented");
701         break;
702     }
703 
704     return NULL;
705 }
706 
707 
708 static struct PyMethodDef PyUNO_methods[] = {
709     { "__dir__", (PyCFunction)PyUNO_dir, METH_VARARGS, NULL},
710     { NULL, NULL }
711 };
712 
713 #else
714 // ensure object identity and struct equality
715 static int PyUNO_cmp( PyObject *self, PyObject *that )
716 {
717     if( self == that )
718         return 0;
719     int retDefault = self > that ? 1 : -1;
720     try
721     {
722         Runtime runtime;
723         if( PyObject_IsInstance( that, getPyUnoClass().get() ) )
724         {
725 
726             PyUNO *me = reinterpret_cast< PyUNO*> ( self );
727             PyUNO *other = reinterpret_cast< PyUNO *> (that );
728             com::sun::star::uno::TypeClass tcMe = me->members->wrappedObject.getValueTypeClass();
729             com::sun::star::uno::TypeClass tcOther = other->members->wrappedObject.getValueTypeClass();
730 
731             if( tcMe == tcOther )
732             {
733                 if( tcMe == com::sun::star::uno::TypeClass_STRUCT ||
734                     tcMe == com::sun::star::uno::TypeClass_EXCEPTION )
735                 {
736                     Reference< XMaterialHolder > xMe( me->members->xInvocation,UNO_QUERY);
737                     Reference< XMaterialHolder > xOther( other->members->xInvocation,UNO_QUERY );
738                     if( xMe->getMaterial() == xOther->getMaterial() )
739                         return 0;
740                 }
741                 else if( tcMe == com::sun::star::uno::TypeClass_INTERFACE )
742                 {
743                     if( me->members->wrappedObject == other->members->wrappedObject )
744 //                     if( me->members->xInvocation == other->members->xInvocation )
745                         return 0;
746                 }
747             }
748         }
749     }
750     catch( com::sun::star::uno::RuntimeException & e)
751     {
752         raisePyExceptionWithAny( makeAny( e ) );
753     }
754     return retDefault;
755 }
756 #endif
757 
758 static PyTypeObject PyUNOType =
759 {
760     PyVarObject_HEAD_INIT(&PyType_Type, 0)
761     const_cast< char * >("pyuno"),
762     sizeof (PyUNO),
763     0,
764     (destructor) PyUNO_del,
765     (printfunc) 0,
766 #if PY_MAJOR_VERSION >= 3
767     (getattrfunc) 0,
768     (setattrfunc) 0,
769     0,
770 #else
771     (getattrfunc) PyUNO_getattr, /* tp_getattr */
772     (setattrfunc) PyUNO_setattr, /* tp_setattr */
773     (cmpfunc) PyUNO_cmp,
774 #endif
775     (reprfunc) PyUNO_repr,
776     0,
777     0,
778     0,
779     (hashfunc) 0,
780     (ternaryfunc) 0,
781     (reprfunc) PyUNO_str,
782 #if PY_MAJOR_VERSION >= 3
783     (getattrofunc)PyUNO_getattr, /* tp_getattro */
784     (setattrofunc)PyUNO_setattr, /* tp_setattro */
785 #else
786     (getattrofunc)0,
787     (setattrofunc)0,
788 #endif
789     NULL,
790     0,
791     NULL,
792     (traverseproc)0,
793     (inquiry)0,
794 #if PY_MAJOR_VERSION >= 3
795     PyUNO_richcompare, /* tp_richcompare */
796 #else
797     (richcmpfunc)0,
798 #endif
799     0,
800     (getiterfunc)0,
801     (iternextfunc)0,
802 #if PY_MAJOR_VERSION >= 3
803     PyUNO_methods, /* tp_methods */
804 #else
805     NULL,
806 #endif
807     NULL,
808     NULL,
809     NULL,
810     NULL,
811     (descrgetfunc)0,
812     (descrsetfunc)0,
813     0,
814     (initproc)0,
815     (allocfunc)0,
816     (newfunc)0,
817     (freefunc)0,
818     (inquiry)0,
819     NULL,
820     NULL,
821     NULL,
822     NULL,
823     NULL,
824     (destructor)0
825 #if PY_VERSION_HEX >= 0x02060000
826     , 0
827 #endif
828 };
829 
830 PyRef getPyUnoClass()
831 {
832     return PyRef( reinterpret_cast< PyObject * > ( &PyUNOType ) );
833 }
834 
835 PyObject* PyUNO_new (
836     const Any & targetInterface, const Reference<XSingleServiceFactory> &ssf)
837 {
838     Reference<XInterface> tmp_interface;
839 
840     targetInterface >>= tmp_interface;
841     if (!tmp_interface.is ())
842     {
843         // empty reference !
844         Py_INCREF( Py_None );
845         return Py_None;
846     }
847 
848     return PyUNO_new_UNCHECKED (targetInterface, ssf);
849 }
850 
851 
852 PyObject* PyUNO_new_UNCHECKED (
853     const Any &targetInterface,
854     const Reference<XSingleServiceFactory> &ssf )
855 {
856     PyUNO* self;
857     Sequence<Any> arguments (1);
858     Reference<XInterface> tmp_interface;
859 
860     self = PyObject_New (PyUNO, &PyUNOType);
861     if (self == NULL)
862         return NULL; //NULL == error
863     self->members = new PyUNOInternals();
864 
865     arguments[0] <<= targetInterface;
866     {
867         PyThreadDetach antiguard;
868         tmp_interface = ssf->createInstanceWithArguments (arguments);
869         Reference<XInvocation2> tmp_invocation (tmp_interface, UNO_QUERY);
870         self->members->xInvocation = tmp_invocation;
871         self->members->wrappedObject = targetInterface;
872     }
873     return (PyObject*) self;
874 }
875 
876 }
877