Bump for 3.6-28
[LibreOffice.git] / cli_ure / source / mono_bridge / uno_proxy.cs
blob76f649b70d4cdfc3e75e6b08ad1cb72862f9c584
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.
5 *
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 ************************************************************************/
29 using System;
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;
38 using uno.Binary;
39 using uno.Typelib;
40 using uno.rtl;
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,
53 IntPtr unoInterface,
54 InterfaceTypeDescription *td)
56 Bridge = bridge;
57 UnoInterface = unoInterface;
58 Type = Bridge.MapUnoType((TypeDescription *)td);
59 uno.Binary.Interface.Acquire(UnoInterface);
60 TypeDesc = td;
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
71 ~UnoInterfaceInfo()
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
87 must not be changed!
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();
97 Bridge bridge;
98 string oid;
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;
105 this.oid = oid;
106 AddUnoInterface(unoInterface, TD);
109 ~UnoInterfaceProxy()
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,
119 TD, oid);
120 object proxy = realProxy.GetTransparentProxy();
121 bridge.RegisterWithCliEnvironment(proxy, oid);
122 return proxy;
125 // RealProxy members
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;
170 // FIXME release it
171 TypeDescriptionReference.GetDescription(&methodTD, memberTD);
173 uno.Any exception;
174 uno.Any result =
175 bridge.CallUno(info.UnoInterface,
176 methodTD,
177 ((InterfaceMethodTypeDescription *)methodTD)->pReturnTypeRef,
178 ((InterfaceMethodTypeDescription *)methodTD)->nParams,
179 ((InterfaceMethodTypeDescription *)methodTD)->pParams,
180 callmsg.Args,
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,
185 out exception);
186 return ConstructReturnMessage(result, callmsg.Args,
187 (InterfaceMethodTypeDescription *)methodTD,
188 callmsg, exception);
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;
202 // FIXME release it
203 TypeDescriptionReference.GetDescription( (TypeDescription **)&attributeTD,
204 memberTD );
205 uno.Any exception;
206 uno.Any result;
208 if (methodName[0] == 'g') // "get"
210 result = bridge.CallUno(info.UnoInterface,
211 (TypeDescription *)attributeTD,
212 attributeTD->pAttributeTypeRef,
213 0, null, null, null,
214 out exception);
215 return ConstructReturnMessage(result, null, null,
216 callmsg, exception);
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;
227 param.bIn = 1;
228 param.bOut = 0;
230 result =
231 bridge.CallUno(info.UnoInterface,
232 (TypeDescription *)attributeTD,
233 TypeDescription.VoidType,
234 1, &param,
235 callmsg.Args, null, /* FIXME ??? from cli_uno */
236 out exception);
237 return ConstructReturnMessage(uno.Any.VOID, null, null,
238 callmsg, exception);
240 break;
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
249 return null;
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))
262 return true;
264 lock (this) {
265 if (FindInfo(fromType) != null)
266 // type is already in our list of Interfaces
267 return true;
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 };
279 uno.Any exception;
281 uno.Any result = bridge.CallUno(info.UnoInterface,
282 queryI,
283 ((InterfaceMethodTypeDescription *)queryI)->pReturnTypeRef,
284 1, ((InterfaceMethodTypeDescription *)queryI)->pParams, args, null,
285 out exception);
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
294 return true;
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);
307 return true;
311 return false;
314 // internals
315 public unsafe void AddUnoInterface(IntPtr unoInterface, InterfaceTypeDescription *TD)
317 lock (this)
319 foreach (UnoInterfaceInfo info in interfaces)
321 if (InterfaceTypeDescription.Equal(info.TypeDesc, TD))
322 return;
324 // This proxy does not contain the unoInterface. Add it.
325 bridge.RegisterWithUnoEnvironment(ref unoInterface,
326 oid, TD);
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))
336 return info;
338 foreach (UnoInterfaceProxy proxy in additionalProxies)
340 UnoInterfaceInfo info = proxy.FindInfo(type);
341 if (info != null)
342 return info;
344 return null;
347 static Type MapUnoType(TypeDescription *TD)
349 return MapUnoType(TD->pWeakRef);
352 static Type MapUnoType(TypeDescriptionReference *TD)
354 Type result;
356 switch(TD->eTypeClass)
358 case TypeClass.VOID:
359 result = typeof(void);
360 break;
361 case TypeClass.CHAR:
362 result = typeof(char);
363 break;
364 case TypeClass.BOOLEAN:
365 result = typeof(bool);
366 break;
367 case TypeClass.BYTE:
368 result = typeof(byte);
369 break;
370 case TypeClass.SHORT:
371 result = typeof(short);
372 break;
373 case TypeClass.UNSIGNED_SHORT:
374 result = typeof(ushort);
375 break;
376 case TypeClass.LONG:
377 result = typeof(int);
378 break;
379 case TypeClass.UNSIGNED_LONG:
380 result = typeof(uint);
381 break;
382 case TypeClass.HYPER:
383 result = typeof(long);
384 break;
385 case TypeClass.UNSIGNED_HYPER:
386 result = typeof(ulong);
387 break;
388 case TypeClass.FLOAT:
389 result = typeof(float);
390 break;
391 case TypeClass.DOUBLE:
392 result = typeof(double);
393 break;
394 case TypeClass.STRING:
395 result = typeof(string);
396 break;
397 case TypeClass.TYPE:
398 result = typeof(Type);
399 break;
400 case TypeClass.ANY:
401 result = typeof(uno.Any);
402 break;
403 case TypeClass.ENUM:
404 case TypeClass.STRUCT:
405 case TypeClass.EXCEPTION:
406 result = Bridge.LoadCliType(TD->pTypeName);
407 break;
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);
412 else
413 result = Bridge.LoadCliType(TD->pTypeName);
414 break;
415 case TypeClass.SEQUENCE:
417 // FIXME do something with TD here?
418 TypeDescriptionReference *elementTDRef =
419 ((IndirectTypeDescription *)TD)->pType;
420 switch (elementTDRef->eTypeClass)
422 case TypeClass.CHAR:
423 result = Type.GetType("System.Char[]");
424 break;
425 case TypeClass.BOOLEAN:
426 result = Type.GetType("System.Boolean[]");
427 break;
428 case TypeClass.BYTE:
429 result = Type.GetType("System.Byte[]");
430 break;
431 case TypeClass.SHORT:
432 result = Type.GetType("System.Int16[]");
433 break;
434 case TypeClass.UNSIGNED_SHORT:
435 result = Type.GetType("System.UInt16[]");
436 break;
437 case TypeClass.LONG:
438 result = Type.GetType("System.Int32[]");
439 break;
440 case TypeClass.UNSIGNED_LONG:
441 result = Type.GetType("System.UInt32[]");
442 break;
443 case TypeClass.HYPER:
444 result = Type.GetType("System.Int64[]");
445 break;
446 case TypeClass.UNSIGNED_HYPER:
447 result = Type.GetType("System.UInt64[]");
448 break;
449 case TypeClass.FLOAT:
450 result = Type.GetType("System.Single[]");
451 break;
452 case TypeClass.DOUBLE:
453 result = Type.GetType("System.Double[]");
454 break;
455 case TypeClass.STRING:
456 result = Type.GetType("System.String[]");
457 break;
458 case TypeClass.TYPE:
459 result = Type.GetType("System.Type[]");
460 break;
461 case TypeClass.ANY:
462 case TypeClass.ENUM:
463 case TypeClass.EXCEPTION:
464 case TypeClass.STRUCT:
465 case TypeClass.INTERFACE:
466 case TypeClass.SEQUENCE:
467 result = Bridge.LoadCliType(TD->pTypeName);
468 break;
469 default:
470 // FIXME can't happen
471 result = null;
472 break;
474 break;
476 default:
477 // FIXME can't happen
478 result = null;
479 break;
481 return result;
484 IMessage InvokeObjectMethod(IMessage request)
486 IMethodMessage methodmsg = (IMethodMessage)request;
487 object ret;
488 switch (methodmsg.MethodName)
490 case "Equals":
491 ret = false;
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);
501 break;
504 break;
505 case "GetHashCode":
506 ret = oid.GetHashCode();
507 break;
508 case "GetType":
509 ret = typeof(System.Object);
510 break;
511 case "ToString":
512 ret = String.Format("Uno object proxy. OID: {0}", oid);
513 break;
514 default:
515 // Cannot happen
516 ret = null;
517 break;
520 return new ReturnMessage(ret, new object[0], 0,
521 methodmsg.LogicalCallContext,
522 (IMethodCallMessage)methodmsg);
525 public string Oid {
526 get { return oid; }
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;
537 else
539 if (args != null)
541 object[] outArgs = new object[methodTD->nParams];
542 int numOutArgs = 0;
543 for (int i = 0; i < methodTD->nParams; ++i)
545 if (methodTD->pParams[i].bOut == 1)
547 outArgs[i] = args[i];
548 ++numOutArgs;
551 return new ReturnMessage(result.Value, outArgs, numOutArgs,
552 callmsg.LogicalCallContext,
553 callmsg);
555 else
557 return new ReturnMessage(result.Value, null, 0,
558 callmsg.LogicalCallContext,
559 callmsg);