1 /*************************************************************************
7 * last change: $Author: $ $Date: $
9 * The Contents of this file are made available subject to the terms of
10 * either of the following licenses
12 * - GNU Lesser General Public License Version 2.1
13 * - Sun Industry Standards Source License Version 1.1
15 * Sun Microsystems Inc., October, 2000
17 * GNU Lesser General Public License Version 2.1
18 * =============================================
19 * Copyright 2000 by Sun Microsystems, Inc.
20 * 901 San Antonio Road, Palo Alto, CA 94303, USA
22 * This library is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU Lesser General Public
24 * License version 2.1, as published by the Free Software Foundation.
26 * This library is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 * Lesser General Public License for more details.
31 * You should have received a copy of the GNU Lesser General Public
32 * License along with this library; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
37 * Sun Industry Standards Source License Version 1.1
38 * =================================================
39 * The contents of this file are subject to the Sun Industry Standards
40 * Source License Version 1.1 (the "License"); You may not use this file
41 * except in compliance with the License. You may obtain a copy of the
42 * License at http://www.openoffice.org/license.html.
44 * Software provided under this License is provided on an "AS IS" basis,
45 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
46 * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
47 * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
48 * See the License for the specific provisions governing your rights and
49 * obligations concerning the Software.
51 * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
53 * Copyright: 2000 by Sun Microsystems, Inc.
55 * All Rights Reserved.
57 * Contributor(s): _______________________________________
60 ************************************************************************/
63 using System
.Collections
;
64 using System
.Diagnostics
;
65 using System
.Reflection
;
66 using System
.Runtime
.InteropServices
;
67 using System
.Runtime
.Remoting
;
68 using System
.Runtime
.Remoting
.Messaging
;
69 using System
.Runtime
.Remoting
.Proxies
;
75 namespace com
.sun
.star
.bridges
.mono_uno
/* FIXME use some uno.foo namespace ? */
78 public unsafe class UnoInterfaceInfo
80 public IntPtr UnoInterface
; // wrapped interface
81 public Type Type
; // mapped type
82 public com
.sun
.star
.bridges
.mono_uno
.Bridge Bridge
;
83 public InterfaceTypeDescription
*TypeDesc
;
85 public UnoInterfaceInfo(com
.sun
.star
.bridges
.mono_uno
.Bridge bridge
,
87 InterfaceTypeDescription
*td
)
90 UnoInterface
= unoInterface
;
91 Type
= Bridge
.MapUnoType((TypeDescription
*)td
);
92 uno
.Binary
.Interface
.Acquire(UnoInterface
);
94 InterfaceTypeDescription
.Acquire(TypeDesc
);
96 fixed (InterfaceTypeDescription
**ppTypeDesc
= &TypeDesc
)
97 if (((TypeDescription
*)TypeDesc
)->bComplete
== 0 &&
98 TypeDescription
.Complete((TypeDescription
**)ppTypeDesc
))
100 // FIXME throw a uno runtime exception
106 Bridge
.RevokeFromUnoEnvironment(UnoInterface
);
107 uno
.Binary
.Interface
.Release(UnoInterface
);
108 InterfaceTypeDescription
.Release(TypeDesc
);
112 public unsafe class UnoInterfaceProxy
: RealProxy
, IRemotingTypeInfo
114 /** used for IRemotingTypeInfo.TypeName
116 string typeName
= "System.Object";
118 /** The list is filled with UnoInterfaceInfo objects. The list can only
119 grow and elements are never changed. If an element was added it
122 ArrayList interfaces
= new ArrayList(10); // of UnoInterfaceInfo
124 /** The list is filled with additional UnoInterfaceProxy object due
125 to aggregation via bridges. Though the latter is strongly
126 discouraged, this has to be supported.
128 ArrayList additionalProxies
= new ArrayList();
133 private unsafe UnoInterfaceProxy(Bridge bridge
, IntPtr unoInterface
,
134 InterfaceTypeDescription
*TD
, string oid
)
135 : base(typeof(MarshalByRefObject
)) // FIXME is there a better type?
137 this.bridge
= bridge
;
139 AddUnoInterface(unoInterface
, TD
);
144 // FIXME should revokeInterface from environment, but can't
145 // access managed string oid any longer.
148 public static unsafe object Create(Bridge bridge
, IntPtr unoInterface
,
149 InterfaceTypeDescription
*TD
, string oid
)
151 UnoInterfaceProxy realProxy
= new UnoInterfaceProxy(bridge
, unoInterface
,
153 object proxy
= realProxy
.GetTransparentProxy();
154 bridge
.RegisterWithCliEnvironment(proxy
, oid
);
159 public unsafe override IMessage
Invoke(IMessage request
)
161 IMethodCallMessage callmsg
= (IMethodCallMessage
)request
;
163 // Find out which UNO interface is being called
164 string typeName
= callmsg
.TypeName
;
165 typeName
= typeName
.Substring(0, typeName
.IndexOf(','));
167 // Special Handling for System.Object methods
168 if (typeName
.IndexOf("System.Object") != -1)
170 return InvokeObjectMethod(request
);
173 Type typeBeingCalled
= Bridge
.LoadCliType(typeName
);
174 UnoInterfaceInfo info
= FindInfo(typeBeingCalled
);
176 Trace
.Assert(info
!= null);
178 string methodName
= callmsg
.MethodName
;
179 TypeDescriptionReference
**ppAllMembers
=
180 info
.TypeDesc
->ppAllMembers
;
181 int numMembers
= info
.TypeDesc
->nAllMembers
;
182 for (int i
= numMembers
- 1; i
>= 0; --i
)
184 TypeDescriptionReference
*memberTD
= *(ppAllMembers
+ i
);
186 // FIXME do without string conversion?
187 string memberTypeName
= UString
.UStringToString(memberTD
->pTypeName
);
188 // check methodName against fully qualified memberTypeName
189 // of memberTD; memberTypeName is of the form
190 // <name> "::" <methodName> *(":@" <idx> "," <idx> ":" <name>)
192 int offset
= memberTypeName
.IndexOf(':') + 2;
193 int remainder
= memberTypeName
.Length
- offset
;
194 if (memberTD
->eTypeClass
== TypeClass
.INTERFACE_METHOD
)
196 if ((methodName
.Length
== remainder
||
197 (methodName
.Length
< remainder
&&
198 memberTypeName
[offset
+ methodName
.Length
] == ':')) &&
199 String
.Compare(memberTypeName
, offset
,
200 methodName
, 0, methodName
.Length
) == 0)
202 TypeDescription
*methodTD
= null;
204 TypeDescriptionReference
.GetDescription(&methodTD
, memberTD
);
208 bridge
.CallUno(info
.UnoInterface
,
210 ((InterfaceMethodTypeDescription
*)methodTD
)->pReturnTypeRef
,
211 ((InterfaceMethodTypeDescription
*)methodTD
)->nParams
,
212 ((InterfaceMethodTypeDescription
*)methodTD
)->pParams
,
214 /* FIXME this is an implementation detail,
215 documented on MSDN, but still an implementation
216 detail. cli_uno does the same */
217 (System
.Type
[])callmsg
.MethodSignature
,
219 return ConstructReturnMessage(result
, callmsg
.Args
,
220 (InterfaceMethodTypeDescription
*)methodTD
,
224 else // INTERFACE_ATTRIBUTE
226 if (methodName
.Length
> 4 &&
227 (methodName
.Length
- 4 == remainder
||
228 (methodName
.Length
- 4 < remainder
&&
229 memberTypeName
[offset
+ methodName
.Length
- 4] == ':')) &&
230 methodName
[1] == 'e' && methodName
[2] == 't' &&
231 String
.Compare(memberTypeName
, offset
,
232 methodName
, 4, methodName
.Length
- 4) == 0)
234 InterfaceAttributeTypeDescription
*attributeTD
= null;
236 TypeDescriptionReference
.GetDescription( (TypeDescription
**)&attributeTD
,
241 if (methodName
[0] == 'g') // "get"
243 result
= bridge
.CallUno(info
.UnoInterface
,
244 (TypeDescription
*)attributeTD
,
245 attributeTD
->pAttributeTypeRef
,
248 return ConstructReturnMessage(result
, null, null,
251 else if (methodName
[0] == 's') // "set"
253 if (attributeTD
->bReadOnly
!= 0)
254 /* FIXME should we generate an exception? */
255 return ConstructReturnMessage(uno
.Any
.VOID
, null, null,
256 callmsg
, uno
.Any
.VOID
);
258 MethodParameter param
;
259 param
.pTypeRef
= attributeTD
->pAttributeTypeRef
;
264 bridge
.CallUno(info
.UnoInterface
,
265 (TypeDescription
*)attributeTD
,
266 TypeDescription
.VoidType
,
268 callmsg
.Args
, null, /* FIXME ??? from cli_uno */
270 return ConstructReturnMessage(uno
.Any
.VOID
, null, null,
277 // FIXME check if the message of the exception is not crippled
279 // the thing that should not be... no method info found!
280 // FIXME throw unoidl.com.sun.star.uno.RuntimeException
285 // IRemotingTypeInfo members
286 public string TypeName
288 get { return typeName; }
289 set { typeName = value; }
292 public unsafe bool CanCastTo(Type fromType
, object o
)
294 if (fromType
== typeof(Object
))
298 if (FindInfo(fromType
) != null)
299 // type is already in our list of Interfaces
302 // queryInterface for the required type
303 // there is always a least one interface in our list
304 UnoInterfaceInfo info
= (UnoInterfaceInfo
)interfaces
[0];
305 // ppAllMembers[0] corresponds to queryInterface
306 TypeDescription
*queryI
= null;
308 TypeDescriptionReference
.GetDescription( // FIXME release it when you're done
309 &queryI
, *(info
.TypeDesc
->ppAllMembers
));
311 object[] args
= new object[] { fromType }
;
314 uno
.Any result
= bridge
.CallUno(info
.UnoInterface
,
316 ((InterfaceMethodTypeDescription
*)queryI
)->pReturnTypeRef
,
317 1, ((InterfaceMethodTypeDescription
*)queryI
)->pParams
, args
, null,
320 // queryInterface doesn't throw exceptions.
322 if (result
.Type
!= typeof(void)) // result has a value
324 if (FindInfo(fromType
) != null)
326 // the proxy supports the requested interface now
330 // via aggregation: it is possible that queryInterface() returns
331 // and interface with a different oid.
332 // That way, this type is supported for the CLI
333 // interpreter (CanCastTo() returns true)
334 object obj
= result
.Value
;
335 if (RemotingServices
.IsTransparentProxy(obj
))
337 UnoInterfaceProxy proxy
=
338 (UnoInterfaceProxy
)RemotingServices
.GetRealProxy(obj
);
339 additionalProxies
.Add(proxy
);
348 public unsafe void AddUnoInterface(IntPtr unoInterface
, InterfaceTypeDescription
*TD
)
352 foreach (UnoInterfaceInfo info
in interfaces
)
354 if (InterfaceTypeDescription
.Equal(info
.TypeDesc
, TD
))
357 // This proxy does not contain the unoInterface. Add it.
358 bridge
.RegisterWithUnoEnvironment(ref unoInterface
,
360 interfaces
.Add(new UnoInterfaceInfo(bridge
, unoInterface
, TD
));
364 UnoInterfaceInfo
FindInfo(Type type
)
366 foreach (UnoInterfaceInfo info
in interfaces
)
368 if (type
.IsAssignableFrom(info
.Type
))
371 foreach (UnoInterfaceProxy proxy
in additionalProxies
)
373 UnoInterfaceInfo info
= proxy
.FindInfo(type
);
380 static Type
MapUnoType(TypeDescription
*TD
)
382 return MapUnoType(TD
->pWeakRef
);
385 static Type
MapUnoType(TypeDescriptionReference
*TD
)
389 switch(TD
->eTypeClass
)
392 result
= typeof(void);
395 result
= typeof(char);
397 case TypeClass
.BOOLEAN
:
398 result
= typeof(bool);
401 result
= typeof(byte);
403 case TypeClass
.SHORT
:
404 result
= typeof(short);
406 case TypeClass
.UNSIGNED_SHORT
:
407 result
= typeof(ushort);
410 result
= typeof(int);
412 case TypeClass
.UNSIGNED_LONG
:
413 result
= typeof(uint);
415 case TypeClass
.HYPER
:
416 result
= typeof(long);
418 case TypeClass
.UNSIGNED_HYPER
:
419 result
= typeof(ulong);
421 case TypeClass
.FLOAT
:
422 result
= typeof(float);
424 case TypeClass
.DOUBLE
:
425 result
= typeof(double);
427 case TypeClass
.STRING
:
428 result
= typeof(string);
431 result
= typeof(Type
);
434 result
= typeof(uno
.Any
);
437 case TypeClass
.STRUCT
:
438 case TypeClass
.EXCEPTION
:
439 result
= Bridge
.LoadCliType(TD
->pTypeName
);
441 case TypeClass
.INTERFACE
:
442 // special handling for XInterface, since it does not exist in cli.
443 if (UString
.UStringToString(TD
->pTypeName
) == "com.sun.star.uno.XInterface")
444 result
= typeof(object);
446 result
= Bridge
.LoadCliType(TD
->pTypeName
);
448 case TypeClass
.SEQUENCE
:
450 // FIXME do something with TD here?
451 TypeDescriptionReference
*elementTDRef
=
452 ((IndirectTypeDescription
*)TD
)->pType
;
453 switch (elementTDRef
->eTypeClass
)
456 result
= Type
.GetType("System.Char[]");
458 case TypeClass
.BOOLEAN
:
459 result
= Type
.GetType("System.Boolean[]");
462 result
= Type
.GetType("System.Byte[]");
464 case TypeClass
.SHORT
:
465 result
= Type
.GetType("System.Int16[]");
467 case TypeClass
.UNSIGNED_SHORT
:
468 result
= Type
.GetType("System.UInt16[]");
471 result
= Type
.GetType("System.Int32[]");
473 case TypeClass
.UNSIGNED_LONG
:
474 result
= Type
.GetType("System.UInt32[]");
476 case TypeClass
.HYPER
:
477 result
= Type
.GetType("System.Int64[]");
479 case TypeClass
.UNSIGNED_HYPER
:
480 result
= Type
.GetType("System.UInt64[]");
482 case TypeClass
.FLOAT
:
483 result
= Type
.GetType("System.Single[]");
485 case TypeClass
.DOUBLE
:
486 result
= Type
.GetType("System.Double[]");
488 case TypeClass
.STRING
:
489 result
= Type
.GetType("System.String[]");
492 result
= Type
.GetType("System.Type[]");
496 case TypeClass
.EXCEPTION
:
497 case TypeClass
.STRUCT
:
498 case TypeClass
.INTERFACE
:
499 case TypeClass
.SEQUENCE
:
500 result
= Bridge
.LoadCliType(TD
->pTypeName
);
503 // FIXME can't happen
510 // FIXME can't happen
517 IMessage
InvokeObjectMethod(IMessage request
)
519 IMethodMessage methodmsg
= (IMethodMessage
)request
;
521 switch (methodmsg
.MethodName
)
526 if (RemotingServices
.IsTransparentProxy(methodmsg
.Args
[0]))
528 UnoInterfaceProxy unoProxy
=
529 RemotingServices
.GetRealProxy(methodmsg
.Args
[0]) as UnoInterfaceProxy
;
531 if (unoProxy
!= null)
533 ret
= oid
.Equals(unoProxy
.Oid
);
539 ret
= oid
.GetHashCode();
542 ret
= typeof(System
.Object
);
545 ret
= String
.Format("Uno object proxy. OID: {0}", oid
);
553 return new ReturnMessage(ret
, new object[0], 0,
554 methodmsg
.LogicalCallContext
,
555 (IMethodCallMessage
)methodmsg
);
562 IMessage
ConstructReturnMessage(uno
.Any result
, object[] args
,
563 InterfaceMethodTypeDescription
*methodTD
,
564 IMethodCallMessage callmsg
, uno
.Any exception
)
566 if (exception
.hasValue())
568 throw (System
.Exception
)exception
.Value
;
574 object[] outArgs
= new object[methodTD
->nParams
];
576 for (int i
= 0; i
< methodTD
->nParams
; ++i
)
578 if (methodTD
->pParams
[i
].bOut
== 1)
580 outArgs
[i
] = args
[i
];
584 return new ReturnMessage(result
.Value
, outArgs
, numOutArgs
,
585 callmsg
.LogicalCallContext
,
590 return new ReturnMessage(result
.Value
, null, 0,
591 callmsg
.LogicalCallContext
,