update dev300-m58
[ooovba.git] / cli_ure / source / mono_bridge / uno_proxy.cs
blobf292bf67fa9895cc970c569a69e949a0c148dc0b
1 /*************************************************************************
3 * $RCSfile: $
5 * $Revision: $
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,
34 * MA 02111-1307 USA
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 ************************************************************************/
62 using System;
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;
71 using uno.Binary;
72 using uno.Typelib;
73 using uno.rtl;
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,
86 IntPtr unoInterface,
87 InterfaceTypeDescription *td)
89 Bridge = bridge;
90 UnoInterface = unoInterface;
91 Type = Bridge.MapUnoType((TypeDescription *)td);
92 uno.Binary.Interface.Acquire(UnoInterface);
93 TypeDesc = td;
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
104 ~UnoInterfaceInfo()
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
120 must not be changed!
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();
130 Bridge bridge;
131 string oid;
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;
138 this.oid = oid;
139 AddUnoInterface(unoInterface, TD);
142 ~UnoInterfaceProxy()
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,
152 TD, oid);
153 object proxy = realProxy.GetTransparentProxy();
154 bridge.RegisterWithCliEnvironment(proxy, oid);
155 return proxy;
158 // RealProxy members
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;
203 // FIXME release it
204 TypeDescriptionReference.GetDescription(&methodTD, memberTD);
206 uno.Any exception;
207 uno.Any result =
208 bridge.CallUno(info.UnoInterface,
209 methodTD,
210 ((InterfaceMethodTypeDescription *)methodTD)->pReturnTypeRef,
211 ((InterfaceMethodTypeDescription *)methodTD)->nParams,
212 ((InterfaceMethodTypeDescription *)methodTD)->pParams,
213 callmsg.Args,
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,
218 out exception);
219 return ConstructReturnMessage(result, callmsg.Args,
220 (InterfaceMethodTypeDescription *)methodTD,
221 callmsg, exception);
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;
235 // FIXME release it
236 TypeDescriptionReference.GetDescription( (TypeDescription **)&attributeTD,
237 memberTD );
238 uno.Any exception;
239 uno.Any result;
241 if (methodName[0] == 'g') // "get"
243 result = bridge.CallUno(info.UnoInterface,
244 (TypeDescription *)attributeTD,
245 attributeTD->pAttributeTypeRef,
246 0, null, null, null,
247 out exception);
248 return ConstructReturnMessage(result, null, null,
249 callmsg, exception);
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;
260 param.bIn = 1;
261 param.bOut = 0;
263 result =
264 bridge.CallUno(info.UnoInterface,
265 (TypeDescription *)attributeTD,
266 TypeDescription.VoidType,
267 1, &param,
268 callmsg.Args, null, /* FIXME ??? from cli_uno */
269 out exception);
270 return ConstructReturnMessage(uno.Any.VOID, null, null,
271 callmsg, exception);
273 break;
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
282 return null;
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))
295 return true;
297 lock (this) {
298 if (FindInfo(fromType) != null)
299 // type is already in our list of Interfaces
300 return true;
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 };
312 uno.Any exception;
314 uno.Any result = bridge.CallUno(info.UnoInterface,
315 queryI,
316 ((InterfaceMethodTypeDescription *)queryI)->pReturnTypeRef,
317 1, ((InterfaceMethodTypeDescription *)queryI)->pParams, args, null,
318 out exception);
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
327 return true;
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);
340 return true;
344 return false;
347 // internals
348 public unsafe void AddUnoInterface(IntPtr unoInterface, InterfaceTypeDescription *TD)
350 lock (this)
352 foreach (UnoInterfaceInfo info in interfaces)
354 if (InterfaceTypeDescription.Equal(info.TypeDesc, TD))
355 return;
357 // This proxy does not contain the unoInterface. Add it.
358 bridge.RegisterWithUnoEnvironment(ref unoInterface,
359 oid, TD);
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))
369 return info;
371 foreach (UnoInterfaceProxy proxy in additionalProxies)
373 UnoInterfaceInfo info = proxy.FindInfo(type);
374 if (info != null)
375 return info;
377 return null;
380 static Type MapUnoType(TypeDescription *TD)
382 return MapUnoType(TD->pWeakRef);
385 static Type MapUnoType(TypeDescriptionReference *TD)
387 Type result;
389 switch(TD->eTypeClass)
391 case TypeClass.VOID:
392 result = typeof(void);
393 break;
394 case TypeClass.CHAR:
395 result = typeof(char);
396 break;
397 case TypeClass.BOOLEAN:
398 result = typeof(bool);
399 break;
400 case TypeClass.BYTE:
401 result = typeof(byte);
402 break;
403 case TypeClass.SHORT:
404 result = typeof(short);
405 break;
406 case TypeClass.UNSIGNED_SHORT:
407 result = typeof(ushort);
408 break;
409 case TypeClass.LONG:
410 result = typeof(int);
411 break;
412 case TypeClass.UNSIGNED_LONG:
413 result = typeof(uint);
414 break;
415 case TypeClass.HYPER:
416 result = typeof(long);
417 break;
418 case TypeClass.UNSIGNED_HYPER:
419 result = typeof(ulong);
420 break;
421 case TypeClass.FLOAT:
422 result = typeof(float);
423 break;
424 case TypeClass.DOUBLE:
425 result = typeof(double);
426 break;
427 case TypeClass.STRING:
428 result = typeof(string);
429 break;
430 case TypeClass.TYPE:
431 result = typeof(Type);
432 break;
433 case TypeClass.ANY:
434 result = typeof(uno.Any);
435 break;
436 case TypeClass.ENUM:
437 case TypeClass.STRUCT:
438 case TypeClass.EXCEPTION:
439 result = Bridge.LoadCliType(TD->pTypeName);
440 break;
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);
445 else
446 result = Bridge.LoadCliType(TD->pTypeName);
447 break;
448 case TypeClass.SEQUENCE:
450 // FIXME do something with TD here?
451 TypeDescriptionReference *elementTDRef =
452 ((IndirectTypeDescription *)TD)->pType;
453 switch (elementTDRef->eTypeClass)
455 case TypeClass.CHAR:
456 result = Type.GetType("System.Char[]");
457 break;
458 case TypeClass.BOOLEAN:
459 result = Type.GetType("System.Boolean[]");
460 break;
461 case TypeClass.BYTE:
462 result = Type.GetType("System.Byte[]");
463 break;
464 case TypeClass.SHORT:
465 result = Type.GetType("System.Int16[]");
466 break;
467 case TypeClass.UNSIGNED_SHORT:
468 result = Type.GetType("System.UInt16[]");
469 break;
470 case TypeClass.LONG:
471 result = Type.GetType("System.Int32[]");
472 break;
473 case TypeClass.UNSIGNED_LONG:
474 result = Type.GetType("System.UInt32[]");
475 break;
476 case TypeClass.HYPER:
477 result = Type.GetType("System.Int64[]");
478 break;
479 case TypeClass.UNSIGNED_HYPER:
480 result = Type.GetType("System.UInt64[]");
481 break;
482 case TypeClass.FLOAT:
483 result = Type.GetType("System.Single[]");
484 break;
485 case TypeClass.DOUBLE:
486 result = Type.GetType("System.Double[]");
487 break;
488 case TypeClass.STRING:
489 result = Type.GetType("System.String[]");
490 break;
491 case TypeClass.TYPE:
492 result = Type.GetType("System.Type[]");
493 break;
494 case TypeClass.ANY:
495 case TypeClass.ENUM:
496 case TypeClass.EXCEPTION:
497 case TypeClass.STRUCT:
498 case TypeClass.INTERFACE:
499 case TypeClass.SEQUENCE:
500 result = Bridge.LoadCliType(TD->pTypeName);
501 break;
502 default:
503 // FIXME can't happen
504 result = null;
505 break;
507 break;
509 default:
510 // FIXME can't happen
511 result = null;
512 break;
514 return result;
517 IMessage InvokeObjectMethod(IMessage request)
519 IMethodMessage methodmsg = (IMethodMessage)request;
520 object ret;
521 switch (methodmsg.MethodName)
523 case "Equals":
524 ret = false;
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);
534 break;
537 break;
538 case "GetHashCode":
539 ret = oid.GetHashCode();
540 break;
541 case "GetType":
542 ret = typeof(System.Object);
543 break;
544 case "ToString":
545 ret = String.Format("Uno object proxy. OID: {0}", oid);
546 break;
547 default:
548 // Cannot happen
549 ret = null;
550 break;
553 return new ReturnMessage(ret, new object[0], 0,
554 methodmsg.LogicalCallContext,
555 (IMethodCallMessage)methodmsg);
558 public string Oid {
559 get { return oid; }
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;
570 else
572 if (args != null)
574 object[] outArgs = new object[methodTD->nParams];
575 int numOutArgs = 0;
576 for (int i = 0; i < methodTD->nParams; ++i)
578 if (methodTD->pParams[i].bOut == 1)
580 outArgs[i] = args[i];
581 ++numOutArgs;
584 return new ReturnMessage(result.Value, outArgs, numOutArgs,
585 callmsg.LogicalCallContext,
586 callmsg);
588 else
590 return new ReturnMessage(result.Value, null, 0,
591 callmsg.LogicalCallContext,
592 callmsg);