1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 using System
.Collections
;
31 using System
.Diagnostics
;
32 using System
.Reflection
;
33 using System
.Runtime
.InteropServices
;
34 using System
.Runtime
.Remoting
;
35 using System
.Runtime
.Remoting
.Messaging
;
36 using System
.Runtime
.Remoting
.Proxies
;
42 namespace com
.sun
.star
.bridges
.mono_uno
/* FIXME use some uno.foo namespace ? */
45 public unsafe class UnoInterfaceInfo
47 public IntPtr UnoInterface
; // wrapped interface
48 public Type Type
; // mapped type
49 public com
.sun
.star
.bridges
.mono_uno
.Bridge Bridge
;
50 public InterfaceTypeDescription
*TypeDesc
;
52 public UnoInterfaceInfo(com
.sun
.star
.bridges
.mono_uno
.Bridge bridge
,
54 InterfaceTypeDescription
*td
)
57 UnoInterface
= unoInterface
;
58 Type
= Bridge
.MapUnoType((TypeDescription
*)td
);
59 uno
.Binary
.Interface
.Acquire(UnoInterface
);
61 InterfaceTypeDescription
.Acquire(TypeDesc
);
63 fixed (InterfaceTypeDescription
**ppTypeDesc
= &TypeDesc
)
64 if (((TypeDescription
*)TypeDesc
)->bComplete
== 0 &&
65 TypeDescription
.Complete((TypeDescription
**)ppTypeDesc
))
67 // FIXME throw a uno runtime exception
73 Bridge
.RevokeFromUnoEnvironment(UnoInterface
);
74 uno
.Binary
.Interface
.Release(UnoInterface
);
75 InterfaceTypeDescription
.Release(TypeDesc
);
79 public unsafe class UnoInterfaceProxy
: RealProxy
, IRemotingTypeInfo
81 /** used for IRemotingTypeInfo.TypeName
83 string typeName
= "System.Object";
85 /** The list is filled with UnoInterfaceInfo objects. The list can only
86 grow and elements are never changed. If an element was added it
89 ArrayList interfaces
= new ArrayList(10); // of UnoInterfaceInfo
91 /** The list is filled with additional UnoInterfaceProxy object due
92 to aggregation via bridges. Though the latter is strongly
93 discouraged, this has to be supported.
95 ArrayList additionalProxies
= new ArrayList();
100 private unsafe UnoInterfaceProxy(Bridge bridge
, IntPtr unoInterface
,
101 InterfaceTypeDescription
*TD
, string oid
)
102 : base(typeof(MarshalByRefObject
)) // FIXME is there a better type?
104 this.bridge
= bridge
;
106 AddUnoInterface(unoInterface
, TD
);
111 // FIXME should revokeInterface from environment, but can't
112 // access managed string oid any longer.
115 public static unsafe object Create(Bridge bridge
, IntPtr unoInterface
,
116 InterfaceTypeDescription
*TD
, string oid
)
118 UnoInterfaceProxy realProxy
= new UnoInterfaceProxy(bridge
, unoInterface
,
120 object proxy
= realProxy
.GetTransparentProxy();
121 bridge
.RegisterWithCliEnvironment(proxy
, oid
);
126 public unsafe override IMessage
Invoke(IMessage request
)
128 IMethodCallMessage callmsg
= (IMethodCallMessage
)request
;
130 // Find out which UNO interface is being called
131 string typeName
= callmsg
.TypeName
;
132 typeName
= typeName
.Substring(0, typeName
.IndexOf(','));
134 // Special Handling for System.Object methods
135 if (typeName
.IndexOf("System.Object") != -1)
137 return InvokeObjectMethod(request
);
140 Type typeBeingCalled
= Bridge
.LoadCliType(typeName
);
141 UnoInterfaceInfo info
= FindInfo(typeBeingCalled
);
143 Trace
.Assert(info
!= null);
145 string methodName
= callmsg
.MethodName
;
146 TypeDescriptionReference
**ppAllMembers
=
147 info
.TypeDesc
->ppAllMembers
;
148 int numMembers
= info
.TypeDesc
->nAllMembers
;
149 for (int i
= numMembers
- 1; i
>= 0; --i
)
151 TypeDescriptionReference
*memberTD
= *(ppAllMembers
+ i
);
153 // FIXME do without string conversion?
154 string memberTypeName
= UString
.UStringToString(memberTD
->pTypeName
);
155 // check methodName against fully qualified memberTypeName
156 // of memberTD; memberTypeName is of the form
157 // <name> "::" <methodName> *(":@" <idx> "," <idx> ":" <name>)
159 int offset
= memberTypeName
.IndexOf(':') + 2;
160 int remainder
= memberTypeName
.Length
- offset
;
161 if (memberTD
->eTypeClass
== TypeClass
.INTERFACE_METHOD
)
163 if ((methodName
.Length
== remainder
||
164 (methodName
.Length
< remainder
&&
165 memberTypeName
[offset
+ methodName
.Length
] == ':')) &&
166 String
.Compare(memberTypeName
, offset
,
167 methodName
, 0, methodName
.Length
) == 0)
169 TypeDescription
*methodTD
= null;
171 TypeDescriptionReference
.GetDescription(&methodTD
, memberTD
);
175 bridge
.CallUno(info
.UnoInterface
,
177 ((InterfaceMethodTypeDescription
*)methodTD
)->pReturnTypeRef
,
178 ((InterfaceMethodTypeDescription
*)methodTD
)->nParams
,
179 ((InterfaceMethodTypeDescription
*)methodTD
)->pParams
,
181 /* FIXME this is an implementation detail,
182 documented on MSDN, but still an implementation
183 detail. cli_uno does the same */
184 (System
.Type
[])callmsg
.MethodSignature
,
186 return ConstructReturnMessage(result
, callmsg
.Args
,
187 (InterfaceMethodTypeDescription
*)methodTD
,
191 else // INTERFACE_ATTRIBUTE
193 if (methodName
.Length
> 4 &&
194 (methodName
.Length
- 4 == remainder
||
195 (methodName
.Length
- 4 < remainder
&&
196 memberTypeName
[offset
+ methodName
.Length
- 4] == ':')) &&
197 methodName
[1] == 'e' && methodName
[2] == 't' &&
198 String
.Compare(memberTypeName
, offset
,
199 methodName
, 4, methodName
.Length
- 4) == 0)
201 InterfaceAttributeTypeDescription
*attributeTD
= null;
203 TypeDescriptionReference
.GetDescription( (TypeDescription
**)&attributeTD
,
208 if (methodName
[0] == 'g') // "get"
210 result
= bridge
.CallUno(info
.UnoInterface
,
211 (TypeDescription
*)attributeTD
,
212 attributeTD
->pAttributeTypeRef
,
215 return ConstructReturnMessage(result
, null, null,
218 else if (methodName
[0] == 's') // "set"
220 if (attributeTD
->bReadOnly
!= 0)
221 /* FIXME should we generate an exception? */
222 return ConstructReturnMessage(uno
.Any
.VOID
, null, null,
223 callmsg
, uno
.Any
.VOID
);
225 MethodParameter param
;
226 param
.pTypeRef
= attributeTD
->pAttributeTypeRef
;
231 bridge
.CallUno(info
.UnoInterface
,
232 (TypeDescription
*)attributeTD
,
233 TypeDescription
.VoidType
,
235 callmsg
.Args
, null, /* FIXME ??? from cli_uno */
237 return ConstructReturnMessage(uno
.Any
.VOID
, null, null,
244 // FIXME check if the message of the exception is not crippled
246 // the thing that should not be... no method info found!
247 // FIXME throw unoidl.com.sun.star.uno.RuntimeException
252 // IRemotingTypeInfo members
253 public string TypeName
255 get { return typeName; }
256 set { typeName = value; }
259 public unsafe bool CanCastTo(Type fromType
, object o
)
261 if (fromType
== typeof(Object
))
265 if (FindInfo(fromType
) != null)
266 // type is already in our list of Interfaces
269 // queryInterface for the required type
270 // there is always a least one interface in our list
271 UnoInterfaceInfo info
= (UnoInterfaceInfo
)interfaces
[0];
272 // ppAllMembers[0] corresponds to queryInterface
273 TypeDescription
*queryI
= null;
275 TypeDescriptionReference
.GetDescription( // FIXME release it when you're done
276 &queryI
, *(info
.TypeDesc
->ppAllMembers
));
278 object[] args
= new object[] { fromType }
;
281 uno
.Any result
= bridge
.CallUno(info
.UnoInterface
,
283 ((InterfaceMethodTypeDescription
*)queryI
)->pReturnTypeRef
,
284 1, ((InterfaceMethodTypeDescription
*)queryI
)->pParams
, args
, null,
287 // queryInterface doesn't throw exceptions.
289 if (result
.Type
!= typeof(void)) // result has a value
291 if (FindInfo(fromType
) != null)
293 // the proxy supports the requested interface now
297 // via aggregation: it is possible that queryInterface() returns
298 // and interface with a different oid.
299 // That way, this type is supported for the CLI
300 // interpreter (CanCastTo() returns true)
301 object obj
= result
.Value
;
302 if (RemotingServices
.IsTransparentProxy(obj
))
304 UnoInterfaceProxy proxy
=
305 (UnoInterfaceProxy
)RemotingServices
.GetRealProxy(obj
);
306 additionalProxies
.Add(proxy
);
315 public unsafe void AddUnoInterface(IntPtr unoInterface
, InterfaceTypeDescription
*TD
)
319 foreach (UnoInterfaceInfo info
in interfaces
)
321 if (InterfaceTypeDescription
.Equal(info
.TypeDesc
, TD
))
324 // This proxy does not contain the unoInterface. Add it.
325 bridge
.RegisterWithUnoEnvironment(ref unoInterface
,
327 interfaces
.Add(new UnoInterfaceInfo(bridge
, unoInterface
, TD
));
331 UnoInterfaceInfo
FindInfo(Type type
)
333 foreach (UnoInterfaceInfo info
in interfaces
)
335 if (type
.IsAssignableFrom(info
.Type
))
338 foreach (UnoInterfaceProxy proxy
in additionalProxies
)
340 UnoInterfaceInfo info
= proxy
.FindInfo(type
);
347 static Type
MapUnoType(TypeDescription
*TD
)
349 return MapUnoType(TD
->pWeakRef
);
352 static Type
MapUnoType(TypeDescriptionReference
*TD
)
356 switch(TD
->eTypeClass
)
359 result
= typeof(void);
362 result
= typeof(char);
364 case TypeClass
.BOOLEAN
:
365 result
= typeof(bool);
368 result
= typeof(byte);
370 case TypeClass
.SHORT
:
371 result
= typeof(short);
373 case TypeClass
.UNSIGNED_SHORT
:
374 result
= typeof(ushort);
377 result
= typeof(int);
379 case TypeClass
.UNSIGNED_LONG
:
380 result
= typeof(uint);
382 case TypeClass
.HYPER
:
383 result
= typeof(long);
385 case TypeClass
.UNSIGNED_HYPER
:
386 result
= typeof(ulong);
388 case TypeClass
.FLOAT
:
389 result
= typeof(float);
391 case TypeClass
.DOUBLE
:
392 result
= typeof(double);
394 case TypeClass
.STRING
:
395 result
= typeof(string);
398 result
= typeof(Type
);
401 result
= typeof(uno
.Any
);
404 case TypeClass
.STRUCT
:
405 case TypeClass
.EXCEPTION
:
406 result
= Bridge
.LoadCliType(TD
->pTypeName
);
408 case TypeClass
.INTERFACE
:
409 // special handling for XInterface, since it does not exist in cli.
410 if (UString
.UStringToString(TD
->pTypeName
) == "com.sun.star.uno.XInterface")
411 result
= typeof(object);
413 result
= Bridge
.LoadCliType(TD
->pTypeName
);
415 case TypeClass
.SEQUENCE
:
417 // FIXME do something with TD here?
418 TypeDescriptionReference
*elementTDRef
=
419 ((IndirectTypeDescription
*)TD
)->pType
;
420 switch (elementTDRef
->eTypeClass
)
423 result
= Type
.GetType("System.Char[]");
425 case TypeClass
.BOOLEAN
:
426 result
= Type
.GetType("System.Boolean[]");
429 result
= Type
.GetType("System.Byte[]");
431 case TypeClass
.SHORT
:
432 result
= Type
.GetType("System.Int16[]");
434 case TypeClass
.UNSIGNED_SHORT
:
435 result
= Type
.GetType("System.UInt16[]");
438 result
= Type
.GetType("System.Int32[]");
440 case TypeClass
.UNSIGNED_LONG
:
441 result
= Type
.GetType("System.UInt32[]");
443 case TypeClass
.HYPER
:
444 result
= Type
.GetType("System.Int64[]");
446 case TypeClass
.UNSIGNED_HYPER
:
447 result
= Type
.GetType("System.UInt64[]");
449 case TypeClass
.FLOAT
:
450 result
= Type
.GetType("System.Single[]");
452 case TypeClass
.DOUBLE
:
453 result
= Type
.GetType("System.Double[]");
455 case TypeClass
.STRING
:
456 result
= Type
.GetType("System.String[]");
459 result
= Type
.GetType("System.Type[]");
463 case TypeClass
.EXCEPTION
:
464 case TypeClass
.STRUCT
:
465 case TypeClass
.INTERFACE
:
466 case TypeClass
.SEQUENCE
:
467 result
= Bridge
.LoadCliType(TD
->pTypeName
);
470 // FIXME can't happen
477 // FIXME can't happen
484 IMessage
InvokeObjectMethod(IMessage request
)
486 IMethodMessage methodmsg
= (IMethodMessage
)request
;
488 switch (methodmsg
.MethodName
)
493 if (RemotingServices
.IsTransparentProxy(methodmsg
.Args
[0]))
495 UnoInterfaceProxy unoProxy
=
496 RemotingServices
.GetRealProxy(methodmsg
.Args
[0]) as UnoInterfaceProxy
;
498 if (unoProxy
!= null)
500 ret
= oid
.Equals(unoProxy
.Oid
);
506 ret
= oid
.GetHashCode();
509 ret
= typeof(System
.Object
);
512 ret
= String
.Format("Uno object proxy. OID: {0}", oid
);
520 return new ReturnMessage(ret
, new object[0], 0,
521 methodmsg
.LogicalCallContext
,
522 (IMethodCallMessage
)methodmsg
);
529 IMessage
ConstructReturnMessage(uno
.Any result
, object[] args
,
530 InterfaceMethodTypeDescription
*methodTD
,
531 IMethodCallMessage callmsg
, uno
.Any exception
)
533 if (exception
.hasValue())
535 throw (System
.Exception
)exception
.Value
;
541 object[] outArgs
= new object[methodTD
->nParams
];
543 for (int i
= 0; i
< methodTD
->nParams
; ++i
)
545 if (methodTD
->pParams
[i
].bOut
== 1)
547 outArgs
[i
] = args
[i
];
551 return new ReturnMessage(result
.Value
, outArgs
, numOutArgs
,
552 callmsg
.LogicalCallContext
,
557 return new ReturnMessage(result
.Value
, null, 0,
558 callmsg
.LogicalCallContext
,