update dev300-m58
[ooovba.git] / cli_ure / source / mono_bridge / managed_proxy.cs
blobfb3e1afd0ef36be2c926deb57f6560eaa932f8d5
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 namespace com.sun.star.bridges.mono_uno /* FIXME use some uno.foo namespace ? */
65 using System;
66 using System.Reflection;
67 using System.Runtime;
69 using uno.Typelib;
70 using uno.rtl;
72 public unsafe class ManagedProxy
74 Bridge bridge;
75 object managedI;
76 TypeDescription *unoType;
77 UString* unoOid;
78 string oid;
79 Type type;
80 IntPtr nativeProxy;
82 enum MethodKind {METHOD = 0, SET, GET};
84 /** The array contains MethodInfos of the cli object. Each one reflects an
85 implemented interface method of the interface for which this proxy was
86 created. The MethodInfos are from the object's method and not from the
87 interface type. That is, they can be used to invoke the methods. The
88 order of the MethodInfo objects corresponds to the order of the
89 interface methods (see member m_type). Position 0 contains the
90 MethodInfo of the first method of the interface which represents the
91 root of the inheritance chain. The last MethodInfo represents the last
92 method of the furthest derived interface.
94 The array is completely initialized in the constructor of this object.
96 When the uno_DispatchMethod is called for this proxy then it receives
97 a typelib_TypeDescription of the member which is either an attribute
98 (setter or getter) or method. After determining the position of the
99 method within the UNO interface one can use the position to obtain the
100 MethodInfo of the corresponding cli method. To obtain the index for the
101 m_arMethodInfos array the function position has to be decreased by 3.
102 This is becaus, the cli interface does not contain the XInterface
103 methods.
105 MethodInfo[] methodInfos;
107 /** This array is similar to m_arMethodInfos but it contains the MethodInfo
108 objects of the interface (not the object). When a call is made from uno
109 to cli then the uno method name is compared to the cli method name. The
110 cli method name can be obtained from the MethodInfo object in this
111 array. The name of the actual implemented method may not be the same as
112 the interface method.
114 MethodInfo[] interfaceMethodInfos;
116 /** Maps the position of the method in the UNO interface to the position of
117 the corresponding MethodInfo in m_arMethodInfos. The Uno position must
118 not include the XInterface methods. For example,
119 pos 0 = XInterface::queryInterface
120 pos 1 = XInterface::acquire
121 pos 2 = XInterface::release
123 That is the real Uno position has to be deducted by 3. Then
124 arUnoPosToCliPos[pos] contains the index for m_arMethodInfos.
127 int[] unoPosToCliPos;
129 /** Count of inherited interfaces of the cli interface.
131 int inheritedInterfacesCount = 0;
132 /** Contains the number of methods of each interface.
134 int[] interfaceMethodCounts;
136 public unsafe ManagedProxy(Bridge bridge, object managedI,
137 TypeDescription* TD, UString* oid)
139 this.bridge = bridge;
140 this.managedI = managedI;
141 this.unoType = TD;
142 TypeDescription.Acquire(this.unoType);
143 this.unoOid = oid;
144 UString.Acquire(this.unoOid);
145 this.oid = UString.UStringToString(oid);
147 if (TD != null && TD->bComplete == 0)
148 TypeDescription.Complete(&TD);
150 this.type = Bridge.MapUnoType(this.unoType);
151 this.nativeProxy = IntPtr.Zero;
152 makeMethodInfos();
155 ~ManagedProxy()
157 UString.Release(this.unoOid);
158 TypeDescription.Release(this.unoType);
161 /** Prepares an array (m_arMethoInfos) containing MethodInfo object of the
162 interface and all inherited interfaces. At index null is the first
163 method of the base interface and at the last position is the last method
164 of the furthest derived interface.
165 If a UNO call is received then one can determine the position of the
166 method (or getter or setter for an attribute) from the passed type
167 information. The position minus 3 (there is no XInterface in the cli
168 mapping) corresponds to the index of the cli interface method in the
169 array.
171 void makeMethodInfos()
173 if (!type.IsInterface)
174 return;
176 MethodInfo[] thisMethods = type.GetMethods();
177 // get the inherited interfaces
178 Type[] inheritedIfaces = type.GetInterfaces();
179 inheritedInterfacesCount = inheritedIfaces.Length;
181 // array containing the number of methods for the interface
182 // and its inherited interfaces
183 interfaceMethodCounts = new int[inheritedInterfacesCount + 1];
185 // determine the number of all interface methods, including
186 // the inherited interfaces
187 int methodCount = thisMethods.Length;
188 foreach (Type iface in inheritedIfaces)
189 methodCount += iface.GetMethods().Length;
191 // array containing MethodInfos of the managed object
192 methodInfos = new MethodInfo[methodCount];
194 // array containing MethodInfos of the interface
195 interfaceMethodInfos = new MethodInfo[methodCount];
197 // array containing the mapping of UNO interface pos to pos in
198 // methodInfos
199 unoPosToCliPos = new int[methodCount];
201 for (int i = 0; i < methodCount; ++i)
202 unoPosToCliPos[i] = -1;
204 // fill methodInfos with the mappings
205 // !!! InterfaceMapping.TargetMethods should be MethodInfo*[] according
206 // to documentation
207 // but it is Type*[] instead. Bug in the framework?
208 // FIXME ^ what does mono do?
209 Type objType = managedI.GetType();
212 int index = 0;
213 // now get the methods from the inherited interface
214 // inheritedIfaces[0] is the direct base interface
215 // inheritedIfaces[n] is the furthest inherited interface
216 // Start with the base interface
217 for (int i = inheritedIfaces.Length - 1; i >= 0; --i)
219 InterfaceMapping mapInherited =
220 objType.GetInterfaceMap(inheritedIfaces[i]);
222 interfaceMethodCounts[i] = mapInherited.TargetMethods.Length;
223 for (int j = 0; j < interfaceMethodCounts[i]; ++j, ++index)
225 methodInfos[index] = mapInherited.TargetMethods[j] as MethodInfo;
226 interfaceMethodInfos[index] =
227 mapInherited.InterfaceMethods[j] as MethodInfo;
231 // At last come the methods of the furthest derived interface
232 InterfaceMapping map = objType.GetInterfaceMap(type);
233 interfaceMethodCounts[inheritedInterfacesCount] =
234 map.TargetMethods.Length;
235 for (int j = 0;
236 j < interfaceMethodCounts[inheritedInterfacesCount]; ++j, ++index)
238 methodInfos[index] = map.TargetMethods[j] as MethodInfo;
239 interfaceMethodInfos[index] =
240 map.InterfaceMethods[j] as MethodInfo;
243 catch (InvalidCastException)
245 // FIXME do something (can this happen, is "as" not the
246 // proper translation for "__try_cast" ?
250 /**Obtains a MethodInfo which can be used to invoke the cli object.
251 Internally it maps nUnoFunctionPos to an index that is used to get the
252 corresponding MethodInfo object from m_arMethoInfos. The mapping table
253 is dynamically initialized. If the cli interface has no base interface
254 or exactly one then the mapping table is initialized in one go at the
255 first call. In all ensuing calls the MethodInfo object is immediately
256 retrieved through the mapping table.
258 If the interface has more then one interface in its inheritance chain,
259 that is Type.GetInterfaces return more then one Type, then the mapping
260 table is partially initiallized. On the first call the mappings for the
261 methods of the belonging interface are created.
263 The implementation assumes that the order of interface methods as
264 provided by InterfaceMapping.InterfaceMethods corresponds to the order
265 of methods in the interface declaration.
267 @param nUnoFunctionPos
268 Position of the method in the uno interface.
270 unsafe MethodInfo getMethodInfo(int unoFunctionPos, UString* unoMethodName, MethodKind methodKind)
272 MethodInfo result = null;
274 // deduct 3 for XInterface methods
275 unoFunctionPos -= 3;
276 lock (unoPosToCliPos)
278 int cliPos = unoPosToCliPos[unoFunctionPos];
279 if (cliPos != -1)
280 return methodInfos[cliPos];
282 // create the method function name
283 string methodName = UString.UStringToString(unoMethodName);
284 switch (methodKind)
286 case MethodKind.METHOD:
287 break;
288 case MethodKind.SET:
289 methodName = "set_" + methodName;
290 break;
291 case MethodKind.GET:
292 methodName = "get_" + methodName;
293 break;
294 default:
295 // FIXME assert not reached
296 break;
299 // Find the cli interface method that corresponds to the Uno method
300 int indexCliMethod = -1;
301 // If the cli interfaces and their methods are in the same order
302 // as they were declared (inheritance chain and within the interface)
303 // then unoFunctionPos should lead to the correct method. However,
304 // the documentation does not say that this ordering is given.
305 if (methodName == interfaceMethodInfos[unoFunctionPos].Name)
306 indexCliMethod = unoFunctionPos;
307 else
309 int methodCount = interfaceMethodInfos.Length;
310 for (int i = 0; i < methodCount; ++i)
312 if (interfaceMethodInfos[i].Name == methodName)
314 indexCliMethod = i;
315 break;
320 if (indexCliMethod == -1 )
322 // FIXME throw some exception
323 return null;
325 unoPosToCliPos[unoFunctionPos] = indexCliMethod;
326 result = methodInfos[indexCliMethod];
329 return result;
332 void Acquire()
334 uno.Binary.Interface.Acquire(nativeProxy);
337 void Release()
339 uno.Binary.Interface.Release(nativeProxy);
342 unsafe void Dispatch(TypeDescription* memberTD, void* unoRet, void** unoArgs,
343 uno.Binary.Any** unoExc)
345 switch (memberTD->eTypeClass)
347 case TypeClass.INTERFACE_ATTRIBUTE:
349 int memberPos = ((InterfaceMemberTypeDescription*)memberTD)->nPosition;
350 InterfaceTypeDescription* ifaceTD = (InterfaceTypeDescription*)unoType;
351 int functionPos = ifaceTD->pMapMemberIndexToFunctionIndex[memberPos];
353 if (unoRet != null) // is getter method
355 MethodInfo info = getMethodInfo(
356 functionPos,
357 ((InterfaceMemberTypeDescription*)memberTD)->pMemberName,
358 MethodKind.GET);
359 bridge.CallManaged(
360 managedI, type, info,
361 ((InterfaceAttributeTypeDescription*)memberTD)->pAttributeTypeRef,
362 null, 0, // no params
363 unoRet, null, unoExc);
365 else // is setter method
367 MethodInfo info = getMethodInfo(
368 // set follows get method
369 functionPos + 1,
370 ((InterfaceMemberTypeDescription*)memberTD)->pMemberName,
371 MethodKind.SET);
372 MethodParameter param;
373 param.pTypeRef = ((InterfaceAttributeTypeDescription*)memberTD)->pAttributeTypeRef;
374 param.bIn = 1;
375 param.bOut = 0;
377 bridge.CallManaged(
378 managedI, type, info,
379 null /* indicated void return */, &param, 1,
380 null, unoArgs, unoExc);
382 break;
384 case TypeClass.INTERFACE_METHOD:
386 int memberPos = ((InterfaceMemberTypeDescription*)memberTD)->nPosition;
387 InterfaceTypeDescription* ifaceTD = (InterfaceTypeDescription*)unoType;
388 int functionPos = ifaceTD->pMapMemberIndexToFunctionIndex[memberPos];
390 switch (functionPos)
392 case 0: // queryInterface()
394 TypeDescription* requestedTD = null;
395 // FIXME leak
396 TypeDescriptionReference * argTD = *(TypeDescriptionReference **) unoArgs[0];
397 if (argTD != null)
398 TypeDescriptionReference.GetDescription(&requestedTD, argTD);
399 if (requestedTD == null || requestedTD->eTypeClass != TypeClass.INTERFACE)
401 uno.Binary.Any.Construct((uno.Binary.Any*)unoRet, null, null, null);
402 *unoExc = null;
403 break;
406 IntPtr unoInterface = IntPtr.Zero;
408 bridge.GetInterfaceFromUnoEnvironment(ref unoInterface, unoOid,
409 (InterfaceTypeDescription*)requestedTD);
411 if (unoInterface == IntPtr.Zero)
413 Type requestedType = Bridge.MapUnoType(requestedTD);
414 if (requestedType.IsInstanceOfType(managedI))
416 IntPtr unoI = bridge.MapManagedToUno(managedI, requestedTD);
417 uno.Binary.Any.Construct(
418 (uno.Binary.Any*)unoRet, &unoI, requestedTD, null);
419 uno.Binary.Interface.Release(unoI);
421 else // object does not support requested interface
423 uno.Binary.Any.Construct((uno.Binary.Any*)unoRet, null, null, null);
425 // no exception occurred
426 *unoExc = null;
428 else
430 uno.Binary.Any.Construct((uno.Binary.Any*)unoRet, &unoInterface,
431 requestedTD, null);
432 *unoExc = null;
434 break;
436 case 1: // acquire this proxy()
437 Acquire();
438 *unoExc = null;
439 break;
440 case 2: // release this proxy()
441 Release();
442 *unoExc = null;
443 break;
444 default: // arbitrary method call
446 InterfaceMethodTypeDescription* methodTD =
447 (InterfaceMethodTypeDescription*)memberTD;
448 UString* methodName = ((InterfaceMemberTypeDescription*)memberTD)->pMemberName;
450 MethodInfo info = getMethodInfo(functionPos, methodName, MethodKind.METHOD);
452 bridge.CallManaged(
453 managedI, type, info,
454 methodTD->pReturnTypeRef, methodTD->pParams,
455 methodTD->nParams,
456 unoRet, unoArgs, unoExc);
457 break;
461 break;
463 default: // Cannot happen
465 break;// FIXME Throw an error
470 public IntPtr NativeProxy
472 get { return nativeProxy; }
473 set { nativeProxy = value; }