diff options
author | Petr Mladek <pmladek@suse.cz> | 2011-08-02 18:20:02 +0200 |
---|---|---|
committer | Andras Timar <atimar@suse.com> | 2012-10-13 12:24:42 +0200 |
commit | c3ab6901890abeacb524608a93e7dd9bde79eb01 (patch) | |
tree | 2cb8dd4ea4aeadc52795d7e21fdae217a2ebe5f5 /cli_ure | |
parent | 390c81a50c514606857b49f56762db9a2d9c13ae (diff) |
[mono] cli_ure-mono-bridge.diff: add mono support
merged with mono-bridge-version.diff: add mono support
Diffstat (limited to 'cli_ure')
-rw-r--r-- | cli_ure/prj/build.lst | 1 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/assemblyinfo.cs | 4 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/binaryuno.cs | 159 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/bridge.cs | 1840 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/cli_environment.cs | 171 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/makefile.mk | 102 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/managed_proxy.cs | 444 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/mono_bridge.cxx | 419 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/mono_bridge.h | 125 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/mono_proxy.cxx | 167 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/rtl_ustring.cs | 105 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/typeclass.cs | 99 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/typedescription.cs | 612 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/uik.cs | 45 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/uno_glue.cxx | 84 | ||||
-rw-r--r-- | cli_ure/source/mono_bridge/uno_proxy.cs | 565 |
16 files changed, 4942 insertions, 0 deletions
diff --git a/cli_ure/prj/build.lst b/cli_ure/prj/build.lst index a46a8297d12d..d72c5250d225 100644 --- a/cli_ure/prj/build.lst +++ b/cli_ure/prj/build.lst @@ -8,5 +8,6 @@ ure cli_ure\source\climaker nmake - w,vc7 ure_source_climaker ure_source_basety ure cli_ure\unotypes nmake - w,vc7 ure_unotypes ure_source_version ure_source_source.w ure_source_climaker.w ure_inc NULL ure cli_ure\source\ure nmake - w,vc7 ure_source_ure ure_source_version ure_source_source.w ure_source_basetypes.w ure_unotypes.w ure_inc NULL ure cli_ure\source\uno_bridge nmake - w,vc7 ure_source_uno_bridge ure_source_basetypes.w ure_unotypes.w ure_source_ure.w ure_inc NULL +ure cli_ure\source\mono_bridge nmake - u ure_source_mono_bridge ure_unotypes ure_source_ure ure_inc NULL ure cli_ure\source\native nmake - w,vc7 ure_source_native ure_source_version ure_source_source.w ure_source_ure.w ure_unotypes.w ure_source_uno_bridge.w ure_inc NULL #ure cli_ure\util nmake - w,vc7 ure_util ure_source_ure.w ure_source_native.w NULL diff --git a/cli_ure/source/mono_bridge/assemblyinfo.cs b/cli_ure/source/mono_bridge/assemblyinfo.cs new file mode 100644 index 000000000000..bc8fe96e5804 --- /dev/null +++ b/cli_ure/source/mono_bridge/assemblyinfo.cs @@ -0,0 +1,4 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +[assembly: AssemblyVersion("1.0.0.0")] diff --git a/cli_ure/source/mono_bridge/binaryuno.cs b/cli_ure/source/mono_bridge/binaryuno.cs new file mode 100644 index 000000000000..2f3973616c7c --- /dev/null +++ b/cli_ure/source/mono_bridge/binaryuno.cs @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +namespace uno.Binary { + +using System; +using System.Runtime.InteropServices; +using uno.Typelib; +using uno.rtl; + +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct Any +{ + /** type of value + */ + public uno.Typelib.TypeDescriptionReference *pType; + + /** pointer to value; this may point to pReserved and thus the uno_Any is not anytime + mem-copyable! You may have to correct the pData pointer to pReserved. Otherwise you need + not, because the data is stored in heap space. + */ + public void *pData; + /** reserved space for storing value + */ + public void *pReserved; + + [ DllImport("uno_cppu", EntryPoint="uno_any_construct") ] + public static unsafe extern void Construct(/* Any */ void *dest, + void *source, + /* uno.Typelib.TypeDescriptionReference */ void *type, + void *acquireFunction); + + [ DllImport("uno_cppu", EntryPoint="uno_any_destruct") ] + public static unsafe extern void Destroy(/* Any */ void *value, void *releaseFunction); +} + +// FIXME wrap this nicely +public struct Interface +{ + [ DllImport("cli_uno", EntryPoint="cli_uno_interface_acquire") ] + public static extern void Acquire(IntPtr unoInterface); + + [ DllImport("cli_uno", EntryPoint="cli_uno_interface_release") ] + public static extern void Release(IntPtr unoInterface); + + [ DllImport("cli_uno", EntryPoint="cli_uno_interface_dispatch") ] + public static unsafe extern void Dispatch(IntPtr unoInterface, + /* uno.Typelib.TypeDescription */ void *memberTD, + void *result, + void **args, + uno.Binary.Any **exception); +} + +// FIXME and this +public class Environment +{ + [ DllImport("cli_uno", EntryPoint="cli_uno_environment_getObjectIdentifier") ] + public static unsafe extern void GetObjectIdentifier(IntPtr unoEnvironment, + UString** oid, + IntPtr unoInterface); + + [ DllImport("cli_uno", EntryPoint="cli_uno_environment_registerInterface") ] + public static unsafe extern void RegisterInterface( + IntPtr unoEnvironment, + ref IntPtr ppInterface, + /* UString */ void* oid, + /* InterfaceTypeDescription */ void *td); + + [ DllImport("cli_uno", EntryPoint="cli_uno_environment_getRegisteredInterface") ] + public static unsafe extern void GetRegisteredInterface( + IntPtr unoEnvironment, + ref IntPtr ppInterface, + /* UString */ void* oid, + /* InterfaceTypeDescription */ void *td); +} + +public struct Data +{ + [ DllImport("uno_cppu", EntryPoint="uno_type_destructData") ] + public static unsafe extern void Destroy(void *data, + /* uno.Typelib.TypeDescription */ void *td, + // FIXME is this okay? release is a function pointer + void *release); +} + +public unsafe struct SequencePtr +{ + int *sal_Sequence; + + // sal_Int32 nRefCount; + // sal_Int32 nElements; + // char elements[1]; + + /** element count<br> + */ + /** elements array<br> + */ + + /** reference count of sequence<br> + */ + private unsafe int nRefCount + { + get { return *(sal_Sequence); } + set { *(sal_Sequence) = value; } + } + + public unsafe int nElements + { + get { return *(sal_Sequence + 1); } + set { *(sal_Sequence + 1) = value; } + } + + public unsafe IntPtr elementsPtr + { + get { return new IntPtr((void *)(sal_Sequence + 2)); } + } + + private unsafe SequencePtr(void *mem) + { + sal_Sequence = (int*)mem; + } + + private const int HEADER_SIZE = 8; // FIXME alignment + + public static SequencePtr Allocate(int length, int elementSize) + { + void *rtlPtr = uno.rtl.Mem.Allocate(HEADER_SIZE + (length * elementSize)); + SequencePtr seqPtr = new SequencePtr(rtlPtr); + seqPtr.nRefCount = 1; + seqPtr.nElements = length; + return seqPtr; + } +} +} diff --git a/cli_ure/source/mono_bridge/bridge.cs b/cli_ure/source/mono_bridge/bridge.cs new file mode 100644 index 000000000000..df2a615f3e98 --- /dev/null +++ b/cli_ure/source/mono_bridge/bridge.cs @@ -0,0 +1,1840 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +namespace com.sun.star.bridges.mono_uno /* FIXME use some uno.foo namespace ? */ +{ + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Remoting; +using System.Text; +using uno.Binary; +using uno.rtl; +using uno.Typelib; + +public unsafe class Bridge +{ + static IntPtr unoEnvironment; + static cli_uno.Cli_environment managedEnvironment; + + Bridge(IntPtr unoEnv) + { + unoEnvironment = unoEnv; + managedEnvironment = new cli_uno.Cli_environment(); + } + + public unsafe IntPtr MapManagedToUno(object managedData, TypeDescription *td) + { + IntPtr result = new IntPtr(null); + + // get oid from managed environment + string oid = cli_uno.Cli_environment.getObjectIdentifier(managedData); + + UString* unoOid = null; + UString.NewFromString(&unoOid, oid); + uno.Binary.Environment.GetRegisteredInterface(unoEnvironment, + ref result, + unoOid, + (InterfaceTypeDescription *)td); + if (result == IntPtr.Zero) + lock (typeof(cli_uno.Cli_environment)) + { + uno.Binary.Environment.GetRegisteredInterface(unoEnvironment, + ref result, + unoOid, + (InterfaceTypeDescription *)td); + if (result == IntPtr.Zero) + result = CreateManagedProxy(managedData, td, unoOid); + } + + UString.Release(unoOid); + + return result; + } + + public unsafe object MapUnoToManaged(IntPtr unoInterface, InterfaceTypeDescription *iTD) + { + object result = null; + + UString* oidPtr = null; + uno.Binary.Environment.GetObjectIdentifier(unoEnvironment, &oidPtr, unoInterface); + + // See if the interface was already mapped + Type ifaceType = MapUnoType((TypeDescription *)iTD); + string oid = UString.UStringToString(oidPtr); + // the string is owned by unoEnvironment + oidPtr = null; + + lock (managedEnvironment) + { + result = managedEnvironment.getRegisteredInterface(oid, ifaceType); + if (result != null) + { + // There is already an registered object. It can either be a proxy + // for the UNO object or a real cli object. In the first case we + // tell the proxy that it shall also represent the current UNO + // interface. If it already does that, then it does nothing + if (RemotingServices.IsTransparentProxy(result)) + { + UnoInterfaceProxy p = (UnoInterfaceProxy)RemotingServices.GetRealProxy(result); + p.AddUnoInterface(unoInterface, iTD); + } + } + else + { + result = UnoInterfaceProxy.Create(this, unoInterface, iTD, oid); + } + } + + return result; + } + + // FIXME convert cli types to expected types, e.g a long to a short where the uno type + // is a sal_Int16. This could be necessary if a scripting language (typeless) is used + // @param assign the uno_data has to be destructed (in/out args) + unsafe void MapToUno(void *unoData, object managedData, + // FIXME it's a TypeDescriptionReference + TypeDescription *type, bool assign) + { + // FIXME acquire the TypeDescription? + // FIXME assert that all the type equivalences in the comments hold + switch (type->eTypeClass) + { + case TypeClass.VOID: + break; + case TypeClass.CHAR: + *(ushort *)unoData = (char)managedData; // sal_Unicode = ushort + break; + case TypeClass.BOOLEAN: + *(byte *)unoData = (bool)managedData ? (byte)1 : (byte)0; // sal_Bool = byte + break; + case TypeClass.BYTE: + *(byte *)unoData = (byte)managedData; // sal_Int8 = byte + break; + case TypeClass.SHORT: + *(short *)unoData = (short)managedData; // sal_Int16 = short + break; + case TypeClass.UNSIGNED_SHORT: + *(ushort *)unoData = (ushort)managedData; // sal_uInt16 = ushort + break; + case TypeClass.LONG: + *(int *)unoData = (int)managedData; // sal_Int32 = int + break; + case TypeClass.UNSIGNED_LONG: + *(uint *)unoData = (uint)managedData; // sal_uInt32 = uint + break; + case TypeClass.HYPER: + *(long *)unoData = (long)managedData; // sal_Int64 = long + break; + case TypeClass.UNSIGNED_HYPER: + *(ulong *)unoData = (ulong)managedData; // sal_uInt64 = ulong + break; + case TypeClass.FLOAT: + *(float *)unoData = (float)managedData; // C++ float = C# float + break; + case TypeClass.DOUBLE: + *(double *)unoData = (double)managedData; // C++ double = C# double + break; + case TypeClass.STRING: + { + if (assign && *(UString **)unoData != null) + UString.Release(*(UString **)unoData); + + *(UString **)unoData = null; + if (managedData == null) + { + UString.New((UString **)unoData); + } + else + { + string s = (string)managedData; + UString.NewFromString((UString **)unoData, s); + } + } + break; + case TypeClass.TYPE: + if (assign) + TypeDescriptionReference.Release(*(TypeDescriptionReference **)unoData); + + *(TypeDescriptionReference **)unoData = MapManagedType((Type)managedData); + break; + case TypeClass.ANY: + { + uno.Binary.Any *binAny = (uno.Binary.Any *)unoData; + + if (assign) + uno.Binary.Any.Destroy(binAny, null); + + if (managedData == null) + { + uno.Binary.Any.Construct(binAny, null, null, null); + break; + } + + uno.Any any = (uno.Any)managedData; + TypeDescription *valueTD = (TypeDescription *)MapManagedType(any.Type); + + // if there's enough room in void *pReserved, store the value in the pointer + binAny->pData = &binAny->pReserved; // this triggers a bug in mcs < 1.1.4 + switch (valueTD->eTypeClass) + { + case TypeClass.VOID: + break; + case TypeClass.CHAR: + *(ushort *)binAny->pData = (char)any.Value; + break; + case TypeClass.BOOLEAN: + *(byte *)binAny->pData = (bool)any.Value ? (byte)1 : (byte)0; + break; + case TypeClass.BYTE: + *(byte *)binAny->pData = (byte)any.Value; + break; + case TypeClass.SHORT: + *(short *)binAny->pData = (short)any.Value; + break; + case TypeClass.UNSIGNED_SHORT: + *(ushort *)binAny->pData = (ushort)any.Value; + break; + case TypeClass.LONG: + *(int *)binAny->pData = (int)any.Value; + break; + case TypeClass.UNSIGNED_LONG: + *(uint *)binAny->pData = (uint)any.Value; + break; + case TypeClass.HYPER: + if (sizeof(long) > sizeof(void *)) + binAny->pData = uno.rtl.Mem.Allocate(sizeof(long)); + + *(long *)binAny->pData = (long)any.Value; + break; + case TypeClass.UNSIGNED_HYPER: + if (sizeof(ulong) > sizeof(void *)) + binAny->pData = uno.rtl.Mem.Allocate(sizeof(ulong)); + + *(ulong *)binAny->pData = (ulong)any.Value; + break; + case TypeClass.FLOAT: + if (sizeof(float) > sizeof(void *)) // FIXME can this happen? + binAny->pData = uno.rtl.Mem.Allocate(sizeof(float)); + + *(float *)binAny->pData = (float)any.Value; + break; + case TypeClass.DOUBLE: + if (sizeof(double) > sizeof(void *)) + binAny->pData = uno.rtl.Mem.Allocate(sizeof(double)); + + *(double *)binAny->pData = (double)any.Value; + break; + case TypeClass.STRING: + // string anies are used so often, that we handle them + // separately, to be a little faster than with an + // extra MapToUno call + + // the Any was already destroyed, can't contain a + // valid string that we could leak here. + *(UString **)binAny->pData = null; + + if (managedData == null) + { + UString.New((UString **)binAny->pData); + } + else + { + string s = (string)any.Value; + UString.NewFromString((UString **)binAny->pData, s); + } + // the string is owned by the Any + break; + case TypeClass.ENUM: + *(int *) binAny->pData = System.Convert.ToInt32(any.Value); + break; + case TypeClass.TYPE: + case TypeClass.SEQUENCE: + case TypeClass.INTERFACE: + binAny->pReserved = null; + MapToUno(binAny->pData, any.Value, valueTD, false /* no assign */); + break; + case TypeClass.STRUCT: + case TypeClass.EXCEPTION: + binAny->pData = uno.rtl.Mem.Allocate(valueTD->nSize); + MapToUno(binAny->pData, any.Value, valueTD, false /* no assign */); + break; + default: + // FIXME + throw new Exception(); + } + binAny->pType = (TypeDescriptionReference *)valueTD; + TypeDescriptionReference.Acquire(binAny->pType); + } + break; + case TypeClass.ENUM: + *(int *)unoData = System.Convert.ToInt32(managedData); + break; + case TypeClass.STRUCT: + case TypeClass.EXCEPTION: + { + TypeDescription *td = null; // FIXME leak + TypeDescriptionReference.GetDescription(&td, (TypeDescriptionReference *)type); + CompoundTypeDescription *compTD = (CompoundTypeDescription *)td; + StructTypeDescription *structTD = null; + + if (type->eTypeClass == TypeClass.STRUCT) + structTD = (StructTypeDescription *)type; + + if (((TypeDescription *)compTD)->bComplete == 0) + TypeDescription.Complete((TypeDescription **)&compTD); + + int members = compTD->nMembers; + Type managedType = null; + if (managedData != null) + managedType = managedData.GetType(); + + if (compTD->pBaseTypeDescription != null) + MapToUno(unoData, managedData, + (TypeDescription *)((TypeDescription *)compTD->pBaseTypeDescription)->pWeakRef, + assign); + + TypeDescriptionReference *memberType = null; + for (int i = 0; i < members; ++i) + { + memberType = compTD->ppTypeRefs[i]; + + object val = null; + if (managedData != null) + { + string fieldName = UString.UStringToString(compTD->ppMemberNames[i]); + FieldInfo fieldInfo = managedType.GetField(fieldName); + // special case for Exception.Message property + // The com.sun.star.uno.Exception.Message field is mapped to the + // System.Exception property. Type.GetField("Message") returns null + if (fieldInfo == null && + UString.UStringToString(type->pTypeName) == "com.sun.star.uno.Exception") + { + // get ExceptionMessage property + if (fieldName == "Message") + { + PropertyInfo propInfo = managedType.GetProperty(fieldName); + val = propInfo.GetValue(managedData, null); + } // FIXME else throw exception + } + else if (fieldInfo != null) + { + val = fieldInfo.GetValue(managedData); + } // FIXME else throw exception + } + + void *p = (byte *)unoData + compTD->pMemberOffsets[i]; + // When using polymorphic structs then the parameterized members can be null. + // Then we set a default value. + bool useDefault = ((structTD != null && + structTD->pParameterizedTypes != null && + structTD->pParameterizedTypes[i] == 1 && + val == null) || + managedData == null); + switch (memberType->eTypeClass) + { + case TypeClass.CHAR: + if (useDefault) + *(ushort *)p = 0; + else + *(ushort *)p = (char)val; + break; + case TypeClass.BOOLEAN: + if (useDefault) + *(byte *)p = (byte)0; + else + *(byte *)p = (bool)val ? (byte)1 : (byte)0; + break; + case TypeClass.BYTE: + if (useDefault) + *(byte *)p = (byte)0; + else + *(byte *)p = (byte)val; + break; + case TypeClass.SHORT: + if (useDefault) + *(short *)p = (short)0; + else + *(short *)p = (short)val; + break; + case TypeClass.UNSIGNED_SHORT: + if (useDefault) + *(ushort *)p = (ushort)0; + else + *(ushort *)p = (ushort)val; + break; + case TypeClass.LONG: + if (useDefault) + *(int *)p = 0; + else + *(int *)p = (int)val; + break; + case TypeClass.UNSIGNED_LONG: + if (useDefault) + *(uint *)p = (uint)0; + else + *(uint *)p = (uint)val; + break; + case TypeClass.HYPER: + if (useDefault) + *(long *)p = (long)0; + else + *(long *)p = (long)val; + break; + case TypeClass.UNSIGNED_HYPER: + if (useDefault) + *(ulong *)p = (ulong)0; + else + *(ulong *)p = (ulong)val; + break; + case TypeClass.FLOAT: + if (useDefault) + *(float *)p = 0.0F; + else + *(float *)p = (float)val; + break; + case TypeClass.DOUBLE: + if (useDefault) + *(double *)p = 0.0; + else + *(double *)p = (double)val; + break; + default: + // FIXME enum should be converted here + MapToUno(p, val, (TypeDescription *)memberType, assign); + break; + } + } + // FIXME exception handling + } + break; + case TypeClass.SEQUENCE: + { + TypeDescription *td = null; // FIXME + TypeDescriptionReference.GetDescription(&td, (TypeDescriptionReference *)type); + TypeDescriptionReference *elementType = + ((IndirectTypeDescription *)td)->pType; + + SequencePtr seq = new SequencePtr(); + + if (managedData != null) + { + Array array = (Array)managedData; + int length = array.GetLength(0); + + switch (elementType->eTypeClass) + { + case TypeClass.CHAR: + seq = SequencePtr.Allocate(length, sizeof(ushort)); + Marshal.Copy((char [])managedData, 0, seq.elementsPtr, length); + break; +/* case TypeClass.BOOLEAN: + // FIXME bool vs. byte ??? + seq = SequencePtr.Allocate(length, sizeof(byte)); + Marshal.Copy((byte [])managedData, 0, seq.elementsPtr, length); + break;*/ + case TypeClass.BYTE: + seq = SequencePtr.Allocate(length, sizeof(byte)); + Marshal.Copy((byte [])managedData, 0, seq.elementsPtr, length); + break; + case TypeClass.SHORT: + seq = SequencePtr.Allocate(length, sizeof(short)); + Marshal.Copy((short [])managedData, 0, seq.elementsPtr, length); + break; +/* case TypeClass.UNSIGNED_SHORT: + seq = SequencePtr.Allocate(length, sizeof(ushort)); + Marshal.Copy((short [])managedData, 0, seq.elementsPtr, length); + break; */ + case TypeClass.LONG: + seq = SequencePtr.Allocate(length, sizeof(int)); + Marshal.Copy((int [])managedData, 0, seq.elementsPtr, length); + break; +/* case TypeClass.UNSIGNED_LONG: + seq = SequencePtr.Allocate(length, sizeof(uint)); + Marshal.Copy((int [])managedData, 0, seq.elementsPtr, length); + break; */ + case TypeClass.HYPER: + seq = SequencePtr.Allocate(length, sizeof(long)); + Marshal.Copy((long [])managedData, 0, seq.elementsPtr, length); + break; +/* case TypeClass.UNSIGNED_HYPER: + seq = SequencePtr.Allocate(length, sizeof(ulong)); + Marshal.Copy((long [])managedData, 0, seq.elementsPtr, length); + break; */ + case TypeClass.FLOAT: + seq = SequencePtr.Allocate(length, sizeof(float)); + Marshal.Copy((float [])managedData, 0, seq.elementsPtr, length); + break; + case TypeClass.DOUBLE: + seq = SequencePtr.Allocate(length, sizeof(double)); + Marshal.Copy((double [])managedData, 0, seq.elementsPtr, length); + break; + case TypeClass.STRING: + { + seq = SequencePtr.Allocate(length, sizeof(void *)); + string[] stringArray = (string [])managedData; + for (int i = 0; i < length; ++i) + { + UString** pStr = ((UString** )seq.elementsPtr) + i; + *pStr = null; + UString.NewFromString(pStr, stringArray[i]); + // string ownership goes to callee + } + } + break; + case TypeClass.ENUM: + seq = SequencePtr.Allocate(length, sizeof(int)); + for (int i = 0; i < length; ++i) + ((int *)seq.elementsPtr)[i] = + Convert.ToInt32(array.GetValue(i)); + break; + case TypeClass.TYPE: + case TypeClass.ANY: + case TypeClass.STRUCT: + case TypeClass.EXCEPTION: + case TypeClass.SEQUENCE: + case TypeClass.INTERFACE: + // FIXME: surely we can do better for this lot [!] - sign problems ... + case TypeClass.BOOLEAN: + case TypeClass.UNSIGNED_SHORT: + case TypeClass.UNSIGNED_LONG: + case TypeClass.UNSIGNED_HYPER: + { + seq = SequencePtr.Allocate( + length, ((TypeDescription *)elementType)->nSize); + + for (int i = 0; i < length; ++i) + { + void *p = + (byte *)seq.elementsPtr + + i * ((TypeDescription *)elementType)->nSize; + object elementData = ((Array)managedData).GetValue(i); + MapToUno(p, elementData, + (TypeDescription *)((TypeDescription *)elementType)->pWeakRef, + false /* no assign */); + } + // FIXME exception handling + } + break; + default: + break; // FIXME throw some exception + } + } + else + { + seq = SequencePtr.Allocate(0, sizeof(int)); + } + *(SequencePtr *)unoData = seq; + } + break; + case TypeClass.INTERFACE: + { + if (assign && *(void **)unoData != null) + uno.Binary.Interface.Release(new IntPtr(*(void **)unoData)); + + if (managedData == null) + *(void **)unoData = null; + else + { + TypeDescription *td = null; // FIXME leak + TypeDescriptionReference.GetDescription(&td, (TypeDescriptionReference *)type); + *(void **)unoData = MapManagedToUno(managedData, td).ToPointer(); + } + break; + } + default: + // FIXME throw some exception + break; + } + } + + unsafe void MapToManaged(ref object managedData, void *unoData, + TypeDescriptionReference *type, Type info, bool dontCreateObj) + { + switch (type->eTypeClass) + { + case TypeClass.CHAR: + managedData = (char)*(ushort *)unoData; + break; + case TypeClass.BOOLEAN: + managedData = (*(byte *)unoData != 0); + break; + case TypeClass.BYTE: + managedData = *(byte *)unoData; + break; + case TypeClass.SHORT: + managedData = *(short *)unoData; + break; + case TypeClass.UNSIGNED_SHORT: + managedData = *(ushort *)unoData; + break; + case TypeClass.LONG: + managedData = *(int *)unoData; + break; + case TypeClass.UNSIGNED_LONG: + managedData = *(uint *)unoData; + break; + case TypeClass.HYPER: + managedData = *(long *)unoData; + break; + case TypeClass.UNSIGNED_HYPER: + managedData = *(ulong *)unoData; + break; + case TypeClass.FLOAT: + managedData = *(float *)unoData; + break; + case TypeClass.DOUBLE: + managedData = *(double *)unoData; + break; + case TypeClass.STRING: + managedData = UString.UStringToString(*(UString **)unoData); + break; + case TypeClass.TYPE: + managedData = MapUnoType(*(TypeDescriptionReference **)unoData); + break; + case TypeClass.ANY: + { + uno.Binary.Any *binAny = (uno.Binary.Any *)unoData; + if (binAny->pType->eTypeClass != TypeClass.VOID) + { + object value = null; + MapToManaged(ref value, binAny->pData, binAny->pType, null, false); + managedData = new uno.Any(MapUnoType(binAny->pType), value); + } + else + { + managedData = uno.Any.VOID; + } + break; + } + case TypeClass.ENUM: + if (info != null) + managedData = Enum.ToObject( + info.GetElementType(), *(int *)unoData); + else + managedData = Enum.ToObject( + MapUnoType(type), *(int *)unoData); + break; + case TypeClass.STRUCT: + case TypeClass.EXCEPTION: + { + TypeDescription *td = null; // FIXME leak + TypeDescriptionReference.GetDescription(&td, (TypeDescriptionReference *)type); + CompoundTypeDescription *compTD = (CompoundTypeDescription *)td; + + if (((TypeDescription *)compTD)->bComplete == 0) + TypeDescription.Complete((TypeDescription **)&compTD); + + // create the type + Type managedType = LoadCliType(td->pTypeName); + + // detect if we recursivly convert inherited + // structures. If this point is reached because of a + // recursive call during converting a struct then we must + // not create a new object rather we use the one in + // cli_data argument. + object managedObject; + if (dontCreateObj) + managedObject = managedData; + else + { + // Special handling for Exception conversion. We must + // call constructor System::Exception to pass the + // message string + if (typeof(unoidl.com.sun.star.uno.Exception).IsAssignableFrom(managedType)) + { + // We need to get the Message field. Therefore we + // must obtain the offset from the + // typedescription. The base interface of all + // exceptions is com::sun::star::uno::Exception + // which contains the message + CompoundTypeDescription *pCTD = compTD; + while (pCTD->pBaseTypeDescription != null) + pCTD = pCTD->pBaseTypeDescription; + + int pos = -1; + for (int i = 0; i < pCTD->nMembers; ++i) + { + if (UString.UStringToString(pCTD->ppMemberNames[i]) == "Message") + { + pos = i; + break; + } + } + + int offset = pCTD->pMemberOffsets[pos]; + // With the offset within the exception we can get + // the message string + string message = UString.UStringToString( + (*(UString **)((byte *)unoData + offset))); + // We need to find a constructor for the exception + // that takes the message string. We assume that + // the first argument is the message string + ConstructorInfo[] ctorInfos = managedType.GetConstructors(); + ConstructorInfo ctorInfo = null; + // Constructor must at least have 2 params for the base + // unoidl.com.sun.star.uno.Exception (String, Object); + int numArgs = -1; + foreach (ConstructorInfo ci in ctorInfos) + { + numArgs = ci.GetParameters().Length; + if (numArgs < 2) + continue; + ctorInfo = ci; + break; + } + + // Prepare parameters for constructor + object[] args = new object[numArgs]; + // only initialize the first argument with the + // message. All unoidl.<Foo Exception>s are + // autogenerated, we know that this is safe. + args[0] = message; + managedObject = ctorInfo.Invoke(args); + } + else + managedObject = Activator.CreateInstance(managedType); + } + + TypeDescriptionReference **memberTypeRefs = compTD->ppTypeRefs; + int *memberOffsets = compTD->pMemberOffsets; + + if (compTD->pBaseTypeDescription != null) + { + // convert inherited struct + // cliObj is passed inout (args in_param, out_param are true), hence the passed + // cliObj is used by the callee instead of a newly created struct + MapToManaged(ref managedObject, unoData, + ((TypeDescription *)compTD->pBaseTypeDescription)->pWeakRef, + null, + true); + } + for (int i = compTD->nMembers - 1; i >= 0; --i) + { + TypeDescriptionReference *memberType = memberTypeRefs[i]; + string memberName = UString.UStringToString(compTD->ppMemberNames[i]); + FieldInfo fieldInfo = managedType.GetField(memberName); + // special case for Exception.Message. The field has already been + // set while constructing cli object + if (fieldInfo == null && + UString.UStringToString(type->pTypeName) == "com.sun.star.uno.Exception") + continue; + + void *p = (byte *)unoData + memberOffsets[i]; + switch (memberType->eTypeClass) + { + case TypeClass.CHAR: + fieldInfo.SetValue(managedObject, (char)*(short *)p); + break; + case TypeClass.BOOLEAN: + fieldInfo.SetValue(managedObject, (*(byte *)p) != 0); + break; + case TypeClass.BYTE: + fieldInfo.SetValue(managedObject, *(byte *)p); + break; + case TypeClass.SHORT: + fieldInfo.SetValue(managedObject, *(short *)p); + break; + case TypeClass.UNSIGNED_SHORT: + fieldInfo.SetValue(managedObject, *(ushort *)p); + break; + case TypeClass.LONG: + fieldInfo.SetValue(managedObject, *(int *)p); + break; + case TypeClass.UNSIGNED_LONG: + fieldInfo.SetValue(managedObject, *(uint *)p); + break; + case TypeClass.HYPER: + fieldInfo.SetValue(managedObject, *(long *)p); + break; + case TypeClass.UNSIGNED_HYPER: + fieldInfo.SetValue(managedObject, *(ulong *)p); + break; + case TypeClass.FLOAT: + fieldInfo.SetValue(managedObject, *(float *)p); + break; + case TypeClass.DOUBLE: + fieldInfo.SetValue(managedObject, *(double *)p); + break; + default: + { + object managedValue = null; + MapToManaged(ref managedValue, p, memberType, null, false); + fieldInfo.SetValue(managedObject, managedValue); + break; + } + } + } + managedData = managedObject; + break; + } + case TypeClass.SEQUENCE: + { + SequencePtr seq = *(SequencePtr *)unoData; + int length = seq.nElements; + + TypeDescription *td = null; // FIXME leak + TypeDescriptionReference.GetDescription(&td, (TypeDescriptionReference *)type); + TypeDescriptionReference *elementType = ((IndirectTypeDescription *)td)->pType; + + switch (elementType->eTypeClass) + { + case TypeClass.CHAR: + { + char[] array = new char[length]; + Marshal.Copy(seq.elementsPtr, array, 0, length); + managedData = array; + break; + } + case TypeClass.BOOLEAN: + { + bool[] array = new bool[length]; + byte *source = (byte *)seq.elementsPtr; + if (length > 0) fixed (bool *arrayPtr = array) + { + bool *dest = arrayPtr; + for (int i = 0; i < length; ++i) + *dest++ = (*source++ != 0); + } + managedData = array; + break; + } + case TypeClass.BYTE: + { + byte[] array = new byte[length]; + byte *source = (byte *)seq.elementsPtr; + if (length > 0) fixed (byte *arrayPtr = array) + { + byte *dest = arrayPtr; + for (int i = 0; i < length; ++i) + *dest++ = *source++; + } + managedData = array; + break; + } + case TypeClass.SHORT: + { + short[] array = new short[length]; + Marshal.Copy(seq.elementsPtr, array, 0, length); + managedData = array; + break; + } + case TypeClass.UNSIGNED_SHORT: + { + ushort[] array = new ushort[length]; + ushort *source = (ushort *)seq.elementsPtr; + if (length > 0) fixed (ushort *arrayPtr = array) + { + ushort *dest = arrayPtr; + for (int i = 0; i < length; ++i) + *dest++ = *source++; + } + managedData = array; + break; + } + case TypeClass.LONG: + { + int[] array = new int[length]; + Marshal.Copy(seq.elementsPtr, array, 0, length); + managedData = array; + break; + } + case TypeClass.UNSIGNED_LONG: + { + uint[] array = new uint[length]; + uint *source = (uint *)seq.elementsPtr; + if (length > 0) fixed (uint *arrayPtr = array) + { + uint *dest = arrayPtr; + for (int i = 0; i < length; ++i) + *dest++ = *source++; + } + managedData = array; + break; + } + case TypeClass.HYPER: + { + long[] array = new long[length]; + Marshal.Copy(seq.elementsPtr, array, 0, length); + managedData = array; + break; + } + case TypeClass.UNSIGNED_HYPER: + { + ulong[] array = new ulong[length]; + ulong *source = (ulong *)seq.elementsPtr; + if (length > 0) fixed (ulong *arrayPtr = array) + { + ulong *dest = arrayPtr; + for (int i = 0; i < length; ++i) + *dest++ = *source++; + } + managedData = array; + break; + } + case TypeClass.FLOAT: + { + float[] array = new float[length]; + Marshal.Copy(seq.elementsPtr, array, 0, length); + managedData = array; + break; + } + case TypeClass.DOUBLE: + { + double[] array = new double[length]; + Marshal.Copy(seq.elementsPtr, array, 0, length); + managedData = array; + break; + } + case TypeClass.STRING: + { + string[] array = new string[length]; + for (int i = 0; i < length; ++i) + { + UString *us = ((UString **)seq.elementsPtr)[i]; + array[i] = UString.UStringToString(us); + } + managedData = array; + break; + } + case TypeClass.TYPE: + { + Type[] array = new Type[length]; + for (int i = 0; i < length; ++i) + array[i] = MapUnoType(((TypeDescriptionReference **) + seq.elementsPtr)[i]); + managedData = array; + break; + } + case TypeClass.ANY: + { + uno.Any[] array = new uno.Any[length]; + uno.Binary.Any *binAny = (uno.Binary.Any *)seq.elementsPtr; + for (int i = 0; i < length; ++i) + { + object any = new uno.Any(); + MapToManaged(ref any, (void **)(binAny + i), + (TypeDescriptionReference *)elementType, + null, false); + array[i] = (uno.Any)any; + } + managedData = array; + break; + } + case TypeClass.ENUM: + { + Type enumType = null; + if (info != null) + { + enumType = info.GetElementType(); + // enumType is EnumType[], get EnumType + enumType = enumType.GetElementType(); + } + else + enumType = MapUnoType(elementType); + + Array array = Array.CreateInstance(enumType, length); + for (int i = 0; i < length; ++i) + { + array.SetValue(Enum.ToObject(enumType, + ((int *)seq.elementsPtr)[i]), + i); + } + managedData = array; + break; + } + case TypeClass.STRUCT: + case TypeClass.EXCEPTION: + { + Array array = Array.CreateInstance(MapUnoType(elementType), length); + if (length > 0) + { + // FIXME check this + byte *p = (byte *)seq.elementsPtr; + int size = ((TypeDescription *)elementType)->nSize; + for (int i = 0; i < length; ++i) + { + object val = null; + MapToManaged(ref val, p + (size * i), elementType, null, false); + array.SetValue(val, i); + } + } + managedData = array; + break; + } + // FIXME verify (says cli_data.cxx) + case TypeClass.SEQUENCE: + { + Array array = Array.CreateInstance( + MapUnoType(elementType), length); + if (length > 0) + { + SequencePtr *elements = (SequencePtr *)seq.elementsPtr; + for (int i = 0; i < length; ++i) + { + object val = null; + MapToManaged(ref val, elements + i, elementType, null, false); + array.SetValue(val, i); + } + } + managedData = array; + break; + } + case TypeClass.INTERFACE: + { + Type ifaceType = MapUnoType(elementType); + Array array = Array.CreateInstance(ifaceType, length); + + byte *p = (byte *)seq.elementsPtr; + int size = ((TypeDescription *)elementType)->nSize; + for (int i = 0; i < length; ++i) + { + object val = null; + MapToManaged(ref val, p + (size * i), elementType, null, false); + array.SetValue(val, i); + } + managedData = array; + break; + } + default: + { + // FIXME throw some exception + break; + } + } + break; + } + case TypeClass.INTERFACE: + { + IntPtr unoI = new IntPtr(*(void **)unoData); + if (unoI != IntPtr.Zero) + { + TypeDescription *td = null; // FIXME leak + TypeDescriptionReference.GetDescription(&td, type); + managedData = MapUnoToManaged(unoI, (InterfaceTypeDescription *)td); + } + else + managedData = null; + break; + } + default: + { + // FIXME throw some exception + break; + } + } + } + + public static Type MapUnoType(TypeDescription *TD) + { + return MapUnoType(TD->pWeakRef); + } + + public static Type MapUnoType(TypeDescriptionReference *TD) + { + Type result; + + switch(TD->eTypeClass) + { + case TypeClass.VOID: + result = typeof(void); + break; + case TypeClass.CHAR: + result = typeof(char); + break; + case TypeClass.BOOLEAN: + result = typeof(bool); + break; + case TypeClass.BYTE: + result = typeof(byte); + break; + case TypeClass.SHORT: + result = typeof(short); + break; + case TypeClass.UNSIGNED_SHORT: + result = typeof(ushort); + break; + case TypeClass.LONG: + result = typeof(int); + break; + case TypeClass.UNSIGNED_LONG: + result = typeof(uint); + break; + case TypeClass.HYPER: + result = typeof(long); + break; + case TypeClass.UNSIGNED_HYPER: + result = typeof(ulong); + break; + case TypeClass.FLOAT: + result = typeof(float); + break; + case TypeClass.DOUBLE: + result = typeof(double); + break; + case TypeClass.STRING: + result = typeof(string); + break; + case TypeClass.TYPE: + result = typeof(Type); + break; + case TypeClass.ANY: + result = typeof(uno.Any); + break; + case TypeClass.ENUM: + case TypeClass.STRUCT: + case TypeClass.EXCEPTION: + result = LoadCliType(TD->pTypeName); + break; + case TypeClass.INTERFACE: + // special handling for XInterface, since it does not exist in cli. + if (UString.UStringToString(TD->pTypeName) == "com.sun.star.uno.XInterface") + result = typeof(object); + else + result = LoadCliType(TD->pTypeName); + break; + case TypeClass.SEQUENCE: + { + TypeDescription *seqType = null; // FIXME leak + TypeDescriptionReference.GetDescription(&seqType, TD); + + // FIXME do something with TD here? + TypeDescriptionReference *elementTDRef = + ((IndirectTypeDescription *)seqType)->pType; + + switch (elementTDRef->eTypeClass) + { + case TypeClass.CHAR: + result = Type.GetType("System.Char[]"); + break; + case TypeClass.BOOLEAN: + result = Type.GetType("System.Boolean[]"); + break; + case TypeClass.BYTE: + result = Type.GetType("System.Byte[]"); + break; + case TypeClass.SHORT: + result = Type.GetType("System.Int16[]"); + break; + case TypeClass.UNSIGNED_SHORT: + result = Type.GetType("System.UInt16[]"); + break; + case TypeClass.LONG: + result = Type.GetType("System.Int32[]"); + break; + case TypeClass.UNSIGNED_LONG: + result = Type.GetType("System.UInt32[]"); + break; + case TypeClass.HYPER: + result = Type.GetType("System.Int64[]"); + break; + case TypeClass.UNSIGNED_HYPER: + result = Type.GetType("System.UInt64[]"); + break; + case TypeClass.FLOAT: + result = Type.GetType("System.Single[]"); + break; + case TypeClass.DOUBLE: + result = Type.GetType("System.Double[]"); + break; + case TypeClass.STRING: + result = Type.GetType("System.String[]"); + break; + case TypeClass.TYPE: + result = Type.GetType("System.Type[]"); + break; + case TypeClass.ANY: + case TypeClass.ENUM: + case TypeClass.EXCEPTION: + case TypeClass.STRUCT: + case TypeClass.INTERFACE: + case TypeClass.SEQUENCE: + result = LoadCliType(TD->pTypeName); + break; + default: + // FIXME can't happen + result = null; + break; + } + break; + } + default: + // FIXME can't happen + result = null; + break; + } + return result; + } + + public static Type LoadCliType(UString* unoName) + { + return LoadCliType(MapUnoTypeName(UString.UStringToString(unoName))); + } + + public static Type LoadCliType(string unoName) + { + Type result = null; + bool isPolymorphic = false; + + string loadName = unoName; + int index = unoName.IndexOf('<'); + if (index != -1) + { + loadName = unoName.Substring(0, index); + isPolymorphic = true; + } + + result = Type.GetType(loadName + ",cli_uretypes"); + + if (result == null) + result = Type.GetType(loadName + ",cli_basetypes"); + + if (result == null) + result = Type.GetType(loadName, false); + + if (result == null) + { + foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) + { + result = a.GetType(loadName, false); + if (result != null) + break; + } + } + + if (result == null) + // FIXME don't use generic Exception type + throw new Exception("A type could not be loaded: " + loadName); + + if (isPolymorphic) + result = uno.PolymorphicType.GetType(result, unoName); + + return result; + } + + static TypeDescriptionReference *MapManagedType(Type managedType) + { + TypeDescriptionReference *result = null; + if (managedType == null) + { + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.VOID); + TypeDescriptionReference.Acquire(result); + return result; + } + + // check for Enum first, + // because otherwise case System.TypeCode.Int32 applies + if (managedType.IsEnum) + { + UString* unoTypeName = MapManagedTypeName(managedType.FullName); + TypeDescriptionReference.New(&result, TypeClass.ENUM, unoTypeName); + TypeDescriptionReference.Acquire(result); + } + else + { + switch (System.Type.GetTypeCode(managedType)) + { + case System.TypeCode.Boolean: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.BOOLEAN); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.Char: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.CHAR); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.Byte: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.BYTE); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.Int16: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.SHORT); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.Int32: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.LONG); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.Int64: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.HYPER); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.UInt16: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.UNSIGNED_SHORT); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.UInt32: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.UNSIGNED_LONG); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.UInt64: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.UNSIGNED_HYPER); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.Single: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.FLOAT); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.Double: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.DOUBLE); + TypeDescriptionReference.Acquire(result); + break; + case System.TypeCode.String: + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.STRING); + TypeDescriptionReference.Acquire(result); + break; + } + } + + if (result == null) + { + string managedTypeName = managedType.FullName; + if (managedTypeName == "System.Void") + { + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.VOID); + TypeDescriptionReference.Acquire(result); + } + else if (managedTypeName == "System.Type") + { + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.TYPE); + TypeDescriptionReference.Acquire(result); + } + else if (managedTypeName == "uno.Any") + { + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.ANY); + TypeDescriptionReference.Acquire(result); + } + else + { + UString* unoTypeName; + + uno.PolymorphicType poly = managedType as uno.PolymorphicType; + if (poly != null) + unoTypeName = MapManagedTypeName(poly.PolymorphicName); + else + unoTypeName = MapManagedTypeName(managedTypeName); + + TypeDescription *td = null; + TypeDescription.GetByName(&td, unoTypeName); + if (td != null) + { + result = td->pWeakRef; + TypeDescriptionReference.Acquire(result); + TypeDescription.Release(td); + } + } + } + + if (result == null) + { + // FIXME - quite probably we should throw an exception here instead. + result = *TypeDescriptionReference.GetByTypeClass(TypeClass.VOID); + TypeDescriptionReference.Acquire(result); + } + + return result; + } + + static string MapUnoTypeName(string typeName) + { + StringBuilder buf = new StringBuilder(); + + // determine if the type is a sequence and its dimensions + int dims = 0; + if (typeName[0] == '[') + { + int index = 1; + while (true) + { + if (typeName[index++] == ']') + ++dims; + if (typeName[index++] != '[') + break; + } + typeName = typeName.Substring(index - 1); + } + + switch (typeName) + { + case "boolean": + buf.Append("System.Boolean"); + break; + case "char": + buf.Append("System.Char"); + break; + case "byte": + buf.Append("System.Byte"); + break; + case "short": + buf.Append("System.Int16"); + break; + case "unsigned short": + buf.Append("System.UInt16"); + break; + case "long": + buf.Append("System.Int32"); + break; + case "unsigned long": + buf.Append("System.UInt32"); + break; + case "hyper": + buf.Append("System.Int64"); + break; + case "unsigned hyper": + buf.Append("System.UInt64"); + break; + case "float": + buf.Append("System.Single"); + break; + case "double": + buf.Append("System.Double"); + break; + case "string": + buf.Append("System.String"); + break; + case "void": + buf.Append("System.Void"); + break; + case "type": + buf.Append("System.Type"); + break; + case "com.sun.star.uno.XInterface": + buf.Append("System.Object"); + break; + case "any": + buf.Append("uno.Any"); + break; + default: + // put "unoidl." at the beginning + buf.Append("unoidl."); + // for polymorphic struct types remove the brackets, e.g. mystruct<bool> -> mystruct + buf.Append(MapUnoPolymorphicName(typeName)); + break; + } + + // append [] + for ( ; dims > 0; --dims) + buf.Append("[]"); + + return buf.ToString(); + } + + /** For example, there is a uno type + com.sun.star.Foo<char, long>. + The values in the type list + are uno types and are replaced by cli types, such as System.Char, + System.Int32, etc. + */ + static string MapUnoPolymorphicName(string unoName) + { + int startIndex = unoName.LastIndexOf('<'); + if (startIndex == -1) + return unoName; + + // get the type list within < and > + int endIndex = unoName.LastIndexOf('>'); + string list = unoName.Substring(startIndex + 1, endIndex - startIndex - 1); + + // parse the type list and replace the types with the corresponding CLI types + char[] delimiters = new char[] { ',' }; + string[] unoTypes = list.Split(delimiters); + + StringBuilder builder = new StringBuilder(unoName.Substring(0, startIndex + 1)); + + int typeCount = unoTypes.Length; + for (int i = 0; i < typeCount; ++i) + builder.Append(MapUnoTypeName(unoTypes[i])); + + builder.Append('>'); + return builder.ToString(); + } + + static UString* MapManagedTypeName(string typeName) + { + int dims = 0; + int index = 0; + + if ((index = typeName.IndexOf("[]")) > 0) + { + dims = 1; + + int curIndex = index; + while ((curIndex + 2) < typeName.Length && + (curIndex = typeName.IndexOf("[]", curIndex + 2)) > 0) + ++dims; + + // get the element name by removing the brackets + typeName = typeName.Substring(0, index); + } + + StringBuilder buf = new StringBuilder(256); + for (; dims > 0; --dims) + buf.Append("[]"); + + switch (typeName) + { + case "System.Boolean": + buf.Append("boolean"); + break; + case "System.Char": + buf.Append("char"); + break; + case "System.Byte": + buf.Append("byte"); + break; + case "System.Int16": + buf.Append("short"); + break; + case "System.UInt16": + buf.Append("unsigned short"); + break; + case "System.Int32": + buf.Append("long"); + break; + case "System.UInt32": + buf.Append("unsigned long"); + break; + case "System.Int64": + buf.Append("hyper"); + break; + case "System.UInt64": + buf.Append("unsigned hyper"); + break; + case "System.Single": + buf.Append("float"); + break; + case "System.Double": + buf.Append("double"); + break; + case "System.String": + buf.Append("string"); + break; + case "System.Void": + buf.Append("void"); + break; + case "System.Type": + buf.Append("type"); + break; + case "System.Object": + buf.Append("com.sun.star.uno.XInterface"); + break; + case "uno.Any": + buf.Append("any"); + break; + default: + { + string name = MapManagedPolymorphicName(typeName); + int i = name.IndexOf('.'); + buf.Append(name.Substring(i + 1)); + break; + } + } + + UString *rtl_uString = null; + UString.NewFromStringBuilder(&rtl_uString, buf); + return rtl_uString; + } + + static string MapManagedPolymorphicName(string unoName) + { + int startIndex = unoName.LastIndexOf('<'); + if (startIndex == -1) + return unoName; + + // get the type list withing < and > + int endIndex = unoName.LastIndexOf('>'); + string list = unoName.Substring(startIndex + 1, endIndex - startIndex - 1); + + // parse the type list and replace the types with the corresponding CLI types + char[] delimiters = new char[] { ',' }; + string[] unoTypes = list.Split(delimiters); + + StringBuilder builder = new StringBuilder(unoName.Substring(0, startIndex + 1)); + + int typeCount = unoTypes.Length; + for (int i = 0; i < typeCount; ++i) + builder.Append(UString.UStringToString(MapManagedTypeName(unoTypes[i]))); + builder.Append('>'); + return builder.ToString(); + } + + [StructLayout(LayoutKind.Explicit)] + private unsafe struct largest + { + [FieldOffset(0)] long n; + [FieldOffset(0)] double d; + [FieldOffset(0)] void *p; + [FieldOffset(0)] uno.Binary.Any a; + } + + // FIXME args[i] must be of same type as return value + public unsafe uno.Any CallUno(IntPtr unoInterface, TypeDescription *memberTD, + TypeDescriptionReference *returnType, int nParams, + MethodParameter *parameters, object[] args, + Type[] argTypes, out uno.Any exception) + { + int returnSize = sizeof(largest); + + if (returnType != null && + (returnType->eTypeClass == TypeClass.STRUCT || + returnType->eTypeClass == TypeClass.EXCEPTION)) + { + // FIXME leak + TypeDescription *td = null; + TypeDescriptionReference.GetDescription(&td, returnType); + + if (td->nSize > returnSize) + returnSize = td->nSize; + } + + // Prepare memory that contains all converted arguments and + // return values. The memory block contains first pointers to + // the arguments which are in the same block For example, 2 + // arguments, 1 ret. + // + // | Pointer + // | Pointer + // | Return value + // | Arg 1 + // | Arg 2 + // + // If an argument is larger then struct largest, such as some + // structures, then the pointer points to an extra block of + // memory. The same goes for a big return value. + // FIXME the last sentence is bullshit. Get it deleted from cli_uno ;) + byte *mem = stackalloc byte[nParams * sizeof(void *) + + returnSize + + nParams * sizeof(largest)]; + + // array of pointers to args + void **unoArgPtrs = (void **)mem; + + // Return Value + void *unoRetPtr = null; + largest *unoArgs = (largest *)(unoArgPtrs + nParams); + if (memberTD->eTypeClass != TypeClass.INTERFACE_ATTRIBUTE || nParams != 1) + { + // If an attribute is set, then unoRet must be null, e.g. void setAttribute(int) + unoRetPtr = (void *)unoArgs; + unoArgs = (largest *)((byte *)unoRetPtr + returnSize); + } + + for (int i = 0; i < nParams; ++i) + { + // FIXME it's a TypeDescriptionReference + TypeDescription *type = (TypeDescription *)parameters[i].pTypeRef; + + unoArgPtrs[i] = unoArgs + i; + if ((type->eTypeClass == TypeClass.STRUCT || + type->eTypeClass == TypeClass.EXCEPTION) && + (type->nSize > sizeof(largest))) + { + // stackalloc is only allowed in initializers + byte *bigArgPtr = stackalloc byte[type->nSize]; + + unoArgPtrs[i] = bigArgPtr; + } + + if (parameters[i].bIn != 0) + { + // FIXME error handling + MapToUno(unoArgPtrs[i], args[i], type, false /* no assign */); + } + } + + uno.Binary.Any unoExceptionHolder; + uno.Binary.Any *unoExc = &unoExceptionHolder; + + // call binary uno + uno.Binary.Interface.Dispatch( + unoInterface, memberTD, unoRetPtr, unoArgPtrs, &unoExc); + + if (unoExc == null) + { + exception = uno.Any.VOID; + + // convert out args, destroy uno args + for (int i = 0; i < nParams; ++i) + { + // FIXME it's a TypeDescriptionReference + TypeDescription *type = (TypeDescription *)parameters[i].pTypeRef; + + if (parameters[i].bOut != 0) + { + // FIXME error handling + MapToManaged(ref args[i], unoArgPtrs[i], parameters[i].pTypeRef, + argTypes != null ? argTypes[i] : null, false); + } + + // cleanup args + if (type->eTypeClass < TypeClass.DOUBLE && + type->eTypeClass != TypeClass.ENUM) // no need to destroy these + uno.Binary.Data.Destroy(unoArgPtrs[i], type, null); + } + + if (returnType != null && returnType->eTypeClass != TypeClass.VOID) + { + // convert uno return value + object result = null; + // FIXME error handling + MapToManaged(ref result, unoRetPtr, returnType, null, false); + uno.Binary.Data.Destroy(unoRetPtr, (TypeDescription *)returnType, null); + return new uno.Any(MapUnoType(returnType), result); // FIXME is this correct? + } + + return uno.Any.VOID; + } + else // exception occured + { + for (int i = 0; i < nParams; ++i) + if (parameters[i].bIn != 0) + uno.Binary.Data.Destroy(unoArgPtrs[i], (TypeDescription *)parameters[i].pTypeRef, null); + + // FIXME needs uno.Any vs System.Object clarification + object exc = null; + MapToManaged(ref exc, unoExceptionHolder.pData, + unoExceptionHolder.pType, null, false); + exception = new uno.Any(MapUnoType(unoExceptionHolder.pType), exc); + return uno.Any.VOID; + } + + // FIXME error handling + } + + // FIXME rename, to say what it does, not how it does this + public void RegisterWithCliEnvironment(object managedI, string oid) + { + managedEnvironment.registerInterface(managedI, oid); + } + + public void RegisterWithCliEnvironment(object managedI, string oid, Type type) + { + managedEnvironment.registerInterface(managedI, oid, type); + } + + public void RegisterWithUnoEnvironment(ref IntPtr unoInterface, string oid, InterfaceTypeDescription *TD) + { + UString *unoOid = null; + UString.NewFromString(&unoOid, oid); + + uno.Binary.Environment.RegisterInterface(unoEnvironment, ref unoInterface, unoOid, TD); + + UString.Release(unoOid); + } + + public void GetInterfaceFromUnoEnvironment(ref IntPtr unoInterface, UString* unoOid, InterfaceTypeDescription* TD) + { + uno.Binary.Environment.GetRegisteredInterface(unoEnvironment, ref unoInterface, unoOid, TD); + } + + public void RevokeFromUnoEnvironment(IntPtr unoInterface) + { + throw new NotImplementedException(); + } + + public unsafe IntPtr CreateManagedProxy(object managedInterface, + TypeDescription* td, + UString* oid) + { + // register original interface + RegisterWithCliEnvironment(managedInterface, + UString.UStringToString(oid), + Bridge.MapUnoType(td)); + + ManagedProxy proxy = new ManagedProxy(this, managedInterface, td, oid); + GCHandle gchandle = GCHandle.Alloc(proxy); + + // create binary uno uno_Interface and register proxy with target environment + IntPtr unoI = CreateBinaryProxyAndRegister(unoEnvironment, (IntPtr)gchandle, + oid, td); + + proxy.NativeProxy = unoI; + return unoI; + } + + [ DllImport("cli_uno", EntryPoint="cli_uno_environment_createMonoProxyAndRegister") ] + public static unsafe extern IntPtr CreateBinaryProxyAndRegister( + IntPtr unoEnvironment, + IntPtr monoProxy, + /* UString */ void* oid, + /* InterfaceTypeDescription */ void* td); + + public unsafe void CallManaged(object managedI, Type ifaceType, MethodInfo method, + TypeDescriptionReference* returnType, + MethodParameter* parameters, int nParams, void* unoRet, + void** unoArgs, uno.Binary.Any** unoExc) + { + object[] args = new object[nParams]; + for (int i = 0; i < nParams; ++i) + if (parameters[i].bIn != 0) + MapToManaged(ref args[i], unoArgs[i], parameters[i].pTypeRef, null, false); + + object invocationResult = null; + try + { + invocationResult = method.Invoke(managedI, args); + } + catch (TargetInvocationException e) + { + Exception exc = e.InnerException; + TypeDescription* td = null; + // FIXME leak + TypeDescriptionReference.GetDescription(&td, MapManagedType(exc.GetType())); + void* memExc = uno.rtl.Mem.Allocate(td->nSize); + MapToUno(memExc, exc, /* FIXME !!!*/ (TypeDescription*)td->pWeakRef, false); + (*unoExc)->pType = td->pWeakRef; + (*unoExc)->pData = memExc; + return; + } + catch (Exception e) + { + // FIXME + } + + // convert out, in/out params + for (int i = 0; i < nParams; ++i) + { + if (parameters[i].bOut != 0) + { + MapToUno( + unoArgs[i], args[i], /* FIXME !!! */(TypeDescription*)parameters[i].pTypeRef, + parameters[i].bIn != 0 /* assign if inout */); + // FIXME error handling + } + } + + // return value + if (returnType != null) + MapToUno(unoRet, invocationResult, /* FIXME !!! */(TypeDescription*)returnType, false /* no assign */); + + // no exception occurred + *unoExc = null; + } +} + +} diff --git a/cli_ure/source/mono_bridge/cli_environment.cs b/cli_ure/source/mono_bridge/cli_environment.cs new file mode 100644 index 000000000000..dfacbd96ff61 --- /dev/null +++ b/cli_ure/source/mono_bridge/cli_environment.cs @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +namespace cli_uno +{ + +using System; +using System.Collections; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Proxies; +using System.Text; + +using com.sun.star.bridges.mono_uno; + +public class Cli_environment +{ + static string sOidPart = ";cli[0];"; + + static Hashtable m_objects = Hashtable.Synchronized(new Hashtable()); + + static string createKey(string oid, Type t) + { + return oid + t.FullName; + } + +// FIXME setup debugging info here +// public Cli_environment() +// { +// } + +// FIXME assert there are no more registered objects +// public ~Cli_environment() +// { +// } + + /** + Registers an UNO object as being mapped by this bridge. The resulting + cli object is represents all interfaces of the UNO object. Therefore the + object can be registered only with its OID; a type is not necessary. + */ + public object registerInterface(object obj, string oid) + { + // FIXME debugging stuff + m_objects.Add(oid, obj); // new WeakReference(obj)); + return obj; + } + + /** + Registers a CLI object as being mapped by this bridge. The resulting + object represents exactly one UNO interface. + */ + public object registerInterface(object obj, string oid, Type type) + { + // FIXME debugging stuff + string key = createKey(oid, type); + m_objects.Add(key, obj); // new WeakReference(obj)); + return obj; + } + + /** + By revoking an interface it is declared that the respective interface has + not been mapped. The proxy implementations call revoke interface in their + destructors. + */ + public void revokeInterface(string oid) + { + revokeInterface(oid, null); + } + + public void revokeInterface(string oid, Type type) + { + // FIXME debugging stuff + string key = type != null ? createKey(oid, type) : oid; + m_objects.Remove(key); + } + + /** + * Retrieves an interface identified by its object id and type from this + * environment. + * + * @param oid object id of interface to be retrieved + * @param type the type description of the interface to be retrieved + * @see com.sun.star.uno.IEnvironment#getRegisteredInterface + */ + public object getRegisteredInterface(string oid, Type type) + { + // try if it is a UNO interface + object ret = null; + ret = m_objects[oid]; + if (ret == null) + { + // try if it is a proxy for a cli object + oid = createKey(oid, type); + ret = m_objects[oid]; + } +/* if (ret != null) + { + WeakReference weakIface = (WeakReference)ret; + ret = weakIface.Target; + } */ + + if (ret == null) + m_objects.Remove(oid); + + return ret; + } + + /** + * Generates a worldwide unique object identifier (oid) for the given object. It is + * guaranteed, that subsequent calls to the method with the same object + * will give the same id. + * <p> + * @return the generated oid. + * @param object the object for which a Oid should be generated. + */ + public static string getObjectIdentifier(object obj) + { + string oid = null; + RealProxy realProxy = null; + + if (RemotingServices.IsTransparentProxy(obj)) + realProxy = RemotingServices.GetRealProxy(obj); + + if (realProxy != null) + { + UnoInterfaceProxy proxyImpl = realProxy as UnoInterfaceProxy; + if (proxyImpl != null) + oid = proxyImpl.Oid; + } + + if (oid == null) + { + Guid gd = typeof(Cli_environment).GUID; // FIXME apparently not a good idea with mono + StringBuilder buf = new StringBuilder(128); + buf.Append(obj.GetHashCode()); + buf.Append(sOidPart); + buf.Append(gd); + oid = buf.ToString(); + } + + return oid; + } + +} + +} diff --git a/cli_ure/source/mono_bridge/makefile.mk b/cli_ure/source/mono_bridge/makefile.mk new file mode 100644 index 000000000000..262f929b89dc --- /dev/null +++ b/cli_ure/source/mono_bridge/makefile.mk @@ -0,0 +1,102 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=bridges +TARGET=cli_uno +USE_DEFFILE=TRUE +ENABLE_EXCEPTIONS=TRUE + +.IF "$(ENABLE_MONO)" != "YES" +dummy: + @echo "Mono binding disabled - skipping ..." +.ELSE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +CFLAGS+=$(MONO_CFLAGS) + +# --- Files -------------------------------------------------------- + +ALLTAR : \ + $(SHL1TARGETN) \ + $(BIN)$/cli_uno_bridge.dll + +CSFILES= \ + assemblyinfo.cs \ + binaryuno.cs \ + bridge.cs \ + cli_environment.cs \ + managed_proxy.cs \ + rtl_ustring.cs \ + typeclass.cs \ + typedescription.cs \ + uik.cs \ + uno_proxy.cs + +ASSEMBLIES_DIR=$(SOLARVERSION)$/$(INPATH)$/bin$(EXT_UPDMINOR) +$(BIN)$/cli_uno_bridge.dll : $(CSFILES) + +$(CSC) $(CSCFLAGS) \ + -target:library \ + -unsafe \ + -out:$@ \ + -keyfile:$(BIN)$/cliuno.snk \ + -reference:$(BIN)$/cli_basetypes.dll \ + -reference:$(BIN)$/cli_uretypes.dll \ + $(CSFILES) + +SLOFILES= \ + $(SLO)$/mono_bridge.obj \ + $(SLO)$/mono_proxy.obj \ + $(SLO)$/uno_glue.obj + +SHL1TARGET=$(TARGET) + +SHL1STDLIBS= \ + $(CPPULIB) \ + $(SALLIB) \ + $(SALHELPERLIB) + + +SHL1STDLIBS+=$(MONO_LIBS) + +# SHL1VERSIONMAP=..$/bridge_exports.map + +SHL1IMPLIB=i$(TARGET) +SHL1LIBS=$(SLB)$/$(TARGET).lib +SHL1DEF=$(MISC)$/$(SHL1TARGET).def +DEF1NAME=$(SHL1TARGET) + + + +# --- Targets ------------------------------------------------------ + +.ENDIF + +.INCLUDE : target.mk diff --git a/cli_ure/source/mono_bridge/managed_proxy.cs b/cli_ure/source/mono_bridge/managed_proxy.cs new file mode 100644 index 000000000000..40eb2dbe6643 --- /dev/null +++ b/cli_ure/source/mono_bridge/managed_proxy.cs @@ -0,0 +1,444 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +namespace com.sun.star.bridges.mono_uno /* FIXME use some uno.foo namespace ? */ +{ + +using System; +using System.Reflection; +using System.Runtime; + +using uno.Typelib; +using uno.rtl; + +public unsafe class ManagedProxy +{ + Bridge bridge; + object managedI; + TypeDescription *unoType; + UString* unoOid; + string oid; + Type type; + IntPtr nativeProxy; + + enum MethodKind {METHOD = 0, SET, GET}; + + /** The array contains MethodInfos of the cli object. Each one reflects an + implemented interface method of the interface for which this proxy was + created. The MethodInfos are from the object's method and not from the + interface type. That is, they can be used to invoke the methods. The + order of the MethodInfo objects corresponds to the order of the + interface methods (see member m_type). Position 0 contains the + MethodInfo of the first method of the interface which represents the + root of the inheritance chain. The last MethodInfo represents the last + method of the furthest derived interface. + + The array is completely initialized in the constructor of this object. + + When the uno_DispatchMethod is called for this proxy then it receives + a typelib_TypeDescription of the member which is either an attribute + (setter or getter) or method. After determining the position of the + method within the UNO interface one can use the position to obtain the + MethodInfo of the corresponding cli method. To obtain the index for the + m_arMethodInfos array the function position has to be decreased by 3. + This is becaus, the cli interface does not contain the XInterface + methods. + */ + MethodInfo[] methodInfos; + + /** This array is similar to m_arMethodInfos but it contains the MethodInfo + objects of the interface (not the object). When a call is made from uno + to cli then the uno method name is compared to the cli method name. The + cli method name can be obtained from the MethodInfo object in this + array. The name of the actual implemented method may not be the same as + the interface method. + */ + MethodInfo[] interfaceMethodInfos; + + /** Maps the position of the method in the UNO interface to the position of + the corresponding MethodInfo in m_arMethodInfos. The Uno position must + not include the XInterface methods. For example, + pos 0 = XInterface::queryInterface + pos 1 = XInterface::acquire + pos 2 = XInterface::release + + That is the real Uno position has to be deducted by 3. Then + arUnoPosToCliPos[pos] contains the index for m_arMethodInfos. + + */ + int[] unoPosToCliPos; + + /** Count of inherited interfaces of the cli interface. + */ + int inheritedInterfacesCount = 0; + /** Contains the number of methods of each interface. + */ + int[] interfaceMethodCounts; + + public unsafe ManagedProxy(Bridge bridge, object managedI, + TypeDescription* TD, UString* oid) + { + this.bridge = bridge; + this.managedI = managedI; + this.unoType = TD; + TypeDescription.Acquire(this.unoType); + this.unoOid = oid; + UString.Acquire(this.unoOid); + this.oid = UString.UStringToString(oid); + + if (TD != null && TD->bComplete == 0) + TypeDescription.Complete(&TD); + + this.type = Bridge.MapUnoType(this.unoType); + this.nativeProxy = IntPtr.Zero; + makeMethodInfos(); + } + + ~ManagedProxy() + { + UString.Release(this.unoOid); + TypeDescription.Release(this.unoType); + } + + /** Prepares an array (m_arMethoInfos) containing MethodInfo object of the + interface and all inherited interfaces. At index null is the first + method of the base interface and at the last position is the last method + of the furthest derived interface. + If a UNO call is received then one can determine the position of the + method (or getter or setter for an attribute) from the passed type + information. The position minus 3 (there is no XInterface in the cli + mapping) corresponds to the index of the cli interface method in the + array. + */ + void makeMethodInfos() + { + if (!type.IsInterface) + return; + + MethodInfo[] thisMethods = type.GetMethods(); + // get the inherited interfaces + Type[] inheritedIfaces = type.GetInterfaces(); + inheritedInterfacesCount = inheritedIfaces.Length; + + // array containing the number of methods for the interface + // and its inherited interfaces + interfaceMethodCounts = new int[inheritedInterfacesCount + 1]; + + // determine the number of all interface methods, including + // the inherited interfaces + int methodCount = thisMethods.Length; + foreach (Type iface in inheritedIfaces) + methodCount += iface.GetMethods().Length; + + // array containing MethodInfos of the managed object + methodInfos = new MethodInfo[methodCount]; + + // array containing MethodInfos of the interface + interfaceMethodInfos = new MethodInfo[methodCount]; + + // array containing the mapping of UNO interface pos to pos in + // methodInfos + unoPosToCliPos = new int[methodCount]; + + for (int i = 0; i < methodCount; ++i) + unoPosToCliPos[i] = -1; + + // fill methodInfos with the mappings + // !!! InterfaceMapping.TargetMethods should be MethodInfo*[] according + // to documentation + // but it is Type*[] instead. Bug in the framework? + // FIXME ^ what does mono do? + Type objType = managedI.GetType(); + try + { + int index = 0; + // now get the methods from the inherited interface + // inheritedIfaces[0] is the direct base interface + // inheritedIfaces[n] is the furthest inherited interface + // Start with the base interface + for (int i = inheritedIfaces.Length - 1; i >= 0; --i) + { + InterfaceMapping mapInherited = + objType.GetInterfaceMap(inheritedIfaces[i]); + + interfaceMethodCounts[i] = mapInherited.TargetMethods.Length; + for (int j = 0; j < interfaceMethodCounts[i]; ++j, ++index) + { + methodInfos[index] = mapInherited.TargetMethods[j] as MethodInfo; + interfaceMethodInfos[index] = + mapInherited.InterfaceMethods[j] as MethodInfo; + } + } + + // At last come the methods of the furthest derived interface + InterfaceMapping map = objType.GetInterfaceMap(type); + interfaceMethodCounts[inheritedInterfacesCount] = + map.TargetMethods.Length; + for (int j = 0; + j < interfaceMethodCounts[inheritedInterfacesCount]; ++j, ++index) + { + methodInfos[index] = map.TargetMethods[j] as MethodInfo; + interfaceMethodInfos[index] = + map.InterfaceMethods[j] as MethodInfo; + } + } + catch (InvalidCastException) + { + // FIXME do something (can this happen, is "as" not the + // proper translation for "__try_cast" ? + } + } + + /**Obtains a MethodInfo which can be used to invoke the cli object. + Internally it maps nUnoFunctionPos to an index that is used to get the + corresponding MethodInfo object from m_arMethoInfos. The mapping table + is dynamically initialized. If the cli interface has no base interface + or exactly one then the mapping table is initialized in one go at the + first call. In all ensuing calls the MethodInfo object is immediately + retrieved through the mapping table. + + If the interface has more then one interface in its inheritance chain, + that is Type.GetInterfaces return more then one Type, then the mapping + table is partially initiallized. On the first call the mappings for the + methods of the belonging interface are created. + + The implementation assumes that the order of interface methods as + provided by InterfaceMapping.InterfaceMethods corresponds to the order + of methods in the interface declaration. + + @param nUnoFunctionPos + Position of the method in the uno interface. + */ + unsafe MethodInfo getMethodInfo(int unoFunctionPos, UString* unoMethodName, MethodKind methodKind) + { + MethodInfo result = null; + + // deduct 3 for XInterface methods + unoFunctionPos -= 3; + lock (unoPosToCliPos) + { + int cliPos = unoPosToCliPos[unoFunctionPos]; + if (cliPos != -1) + return methodInfos[cliPos]; + + // create the method function name + string methodName = UString.UStringToString(unoMethodName); + switch (methodKind) + { + case MethodKind.METHOD: + break; + case MethodKind.SET: + methodName = "set_" + methodName; + break; + case MethodKind.GET: + methodName = "get_" + methodName; + break; + default: + // FIXME assert not reached + break; + } + + // Find the cli interface method that corresponds to the Uno method + int indexCliMethod = -1; + // If the cli interfaces and their methods are in the same order + // as they were declared (inheritance chain and within the interface) + // then unoFunctionPos should lead to the correct method. However, + // the documentation does not say that this ordering is given. + if (methodName == interfaceMethodInfos[unoFunctionPos].Name) + indexCliMethod = unoFunctionPos; + else + { + int methodCount = interfaceMethodInfos.Length; + for (int i = 0; i < methodCount; ++i) + { + if (interfaceMethodInfos[i].Name == methodName) + { + indexCliMethod = i; + break; + } + } + } + + if (indexCliMethod == -1 ) + { + // FIXME throw some exception + return null; + } + unoPosToCliPos[unoFunctionPos] = indexCliMethod; + result = methodInfos[indexCliMethod]; + } + + return result; + } + + void Acquire() + { + uno.Binary.Interface.Acquire(nativeProxy); + } + + void Release() + { + uno.Binary.Interface.Release(nativeProxy); + } + + unsafe void Dispatch(TypeDescription* memberTD, void* unoRet, void** unoArgs, + uno.Binary.Any** unoExc) + { + switch (memberTD->eTypeClass) + { + case TypeClass.INTERFACE_ATTRIBUTE: + { + int memberPos = ((InterfaceMemberTypeDescription*)memberTD)->nPosition; + InterfaceTypeDescription* ifaceTD = (InterfaceTypeDescription*)unoType; + int functionPos = ifaceTD->pMapMemberIndexToFunctionIndex[memberPos]; + + if (unoRet != null) // is getter method + { + MethodInfo info = getMethodInfo( + functionPos, + ((InterfaceMemberTypeDescription*)memberTD)->pMemberName, + MethodKind.GET); + bridge.CallManaged( + managedI, type, info, + ((InterfaceAttributeTypeDescription*)memberTD)->pAttributeTypeRef, + null, 0, // no params + unoRet, null, unoExc); + } + else // is setter method + { + MethodInfo info = getMethodInfo( + // set follows get method + functionPos + 1, + ((InterfaceMemberTypeDescription*)memberTD)->pMemberName, + MethodKind.SET); + MethodParameter param; + param.pTypeRef = ((InterfaceAttributeTypeDescription*)memberTD)->pAttributeTypeRef; + param.bIn = 1; + param.bOut = 0; + + bridge.CallManaged( + managedI, type, info, + null /* indicated void return */, ¶m, 1, + null, unoArgs, unoExc); + } + break; + } + case TypeClass.INTERFACE_METHOD: + { + int memberPos = ((InterfaceMemberTypeDescription*)memberTD)->nPosition; + InterfaceTypeDescription* ifaceTD = (InterfaceTypeDescription*)unoType; + int functionPos = ifaceTD->pMapMemberIndexToFunctionIndex[memberPos]; + + switch (functionPos) + { + case 0: // queryInterface() + { + TypeDescription* requestedTD = null; + // FIXME leak + TypeDescriptionReference * argTD = *(TypeDescriptionReference **) unoArgs[0]; + if (argTD != null) + TypeDescriptionReference.GetDescription(&requestedTD, argTD); + if (requestedTD == null || requestedTD->eTypeClass != TypeClass.INTERFACE) + { + uno.Binary.Any.Construct((uno.Binary.Any*)unoRet, null, null, null); + *unoExc = null; + break; + } + + IntPtr unoInterface = IntPtr.Zero; + + bridge.GetInterfaceFromUnoEnvironment(ref unoInterface, unoOid, + (InterfaceTypeDescription*)requestedTD); + + if (unoInterface == IntPtr.Zero) + { + Type requestedType = Bridge.MapUnoType(requestedTD); + if (requestedType.IsInstanceOfType(managedI)) + { + IntPtr unoI = bridge.MapManagedToUno(managedI, requestedTD); + uno.Binary.Any.Construct( + (uno.Binary.Any*)unoRet, &unoI, requestedTD, null); + uno.Binary.Interface.Release(unoI); + } + else // object does not support requested interface + { + uno.Binary.Any.Construct((uno.Binary.Any*)unoRet, null, null, null); + } + // no exception occurred + *unoExc = null; + } + else + { + uno.Binary.Any.Construct((uno.Binary.Any*)unoRet, &unoInterface, + requestedTD, null); + *unoExc = null; + } + break; + } + case 1: // acquire this proxy() + Acquire(); + *unoExc = null; + break; + case 2: // release this proxy() + Release(); + *unoExc = null; + break; + default: // arbitrary method call + { + InterfaceMethodTypeDescription* methodTD = + (InterfaceMethodTypeDescription*)memberTD; + UString* methodName = ((InterfaceMemberTypeDescription*)memberTD)->pMemberName; + + MethodInfo info = getMethodInfo(functionPos, methodName, MethodKind.METHOD); + + bridge.CallManaged( + managedI, type, info, + methodTD->pReturnTypeRef, methodTD->pParams, + methodTD->nParams, + unoRet, unoArgs, unoExc); + break; + } + } + + break; + } + default: // Cannot happen + { + break;// FIXME Throw an error + } + } + } + + public IntPtr NativeProxy + { + get { return nativeProxy; } + set { nativeProxy = value; } + } +} + +} diff --git a/cli_ure/source/mono_bridge/mono_bridge.cxx b/cli_ure/source/mono_bridge/mono_bridge.cxx new file mode 100644 index 000000000000..039a136fafff --- /dev/null +++ b/cli_ure/source/mono_bridge/mono_bridge.cxx @@ -0,0 +1,419 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <string.h> + +#include "uno/dispatcher.h" +#include "uno/environment.h" +#include "uno/lbnames.h" + +#include "osl/diagnose.h" +#include "rtl/unload.h" +#include "rtl/ustring.hxx" +#include "glib/gtypes.h" + +#include "uno/mapping.hxx" + +extern "C" { +#include "mono/metadata/appdomain.h" +#include "mono/metadata/assembly.h" +#include "mono/metadata/debug-helpers.h" +#include "mono/metadata/object.h" +#include "mono/metadata/threads.h" +} + +#include "mono_bridge.h" + +#ifndef MONO_PUBLIC_KEY_TOKEN_LENGTH +#define MONO_PUBLIC_KEY_TOKEN_LENGTH 17 +struct _MonoAssemblyName { + const char *name; + const char *culture; + const char *hash_value; + const guint8* public_key; + guchar public_key_token [MONO_PUBLIC_KEY_TOKEN_LENGTH]; + guint32 hash_alg; + guint32 hash_len; + guint32 flags; + guint16 major, minor, build, revision; +}; +#endif + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + +using namespace ::rtl; +using namespace ::mono_uno; + +extern "C" { + +void SAL_CALL Mapping_acquire( uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + static_cast< Mapping const * >( mapping )->m_bridge->acquire(); +} + +void SAL_CALL Mapping_release( uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + static_cast< Mapping const * >( mapping )->m_bridge->release(); +} + +void SAL_CALL Mapping_map_to_uno( + uno_Mapping * mapping, void ** ppOut, + void * pIn, typelib_InterfaceTypeDescription * td ) + SAL_THROW_EXTERN_C() +{ + uno_Interface ** ppUnoI = (uno_Interface **)ppOut; + void * monoI = pIn; + +// FIXME do this here? OSL_ASSERT( sizeof (void *) >= sizeof (guint32)) + OSL_ENSURE( ppUnoI && td, "### null ptr!" ); + + if (0 != *ppUnoI) + { + uno_Interface * pUnoI = *ppUnoI; + (*pUnoI->release)( pUnoI ); + *ppUnoI = 0; + } + + try + { + Bridge const *bridge = + static_cast< Mapping const * >( mapping )->m_bridge; + // FIXME any wrapper necessary around mono calls? cf. JNI_guarded_context + uno_Interface * pUnoI = bridge->map_to_uno( + monoI, (typelib_TypeDescription *)td ); + *ppUnoI = pUnoI; + } + catch (BridgeRuntimeError & err) + { +#if OSL_DEBUG_LEVEL > 0 + OString cstr_msg( + OUStringToOString( + OUSTR("[mono_uno bridge error] ") + err.m_message, + RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr_msg.getStr() ); +#endif + } +} + +void SAL_CALL Mapping_map_to_mono( + uno_Mapping * mapping, void ** ppOut, + void * pIn, typelib_InterfaceTypeDescription * td ) + SAL_THROW_EXTERN_C() +{ + void ** pMonoI = ppOut; + uno_Interface * pUnoI = (uno_Interface *)pIn; + + OSL_ENSURE( ppOut && td, "### null ptr!" ); + + if (0 != *pMonoI) + { + // FIXME JNI bridge has guarded_context here + // FIXME: do the right thing in the managed bridge + // mono_gchandle_free( *pMonoI ); + } + + try + { + if (0 != pUnoI) + { + Bridge const * bridge = + static_cast< Mapping const *>( mapping )->m_bridge; + // FIXME guarded context + *ppOut = (void *)bridge->map_to_mono( + pUnoI, (typelib_TypeDescription *)td ); + OSL_ASSERT( ppOut && *ppOut ); + } + } + catch (BridgeRuntimeError & err) + { +#if OSL_DEBUG_LEVEL >= 1 + rtl::OString cstr_msg( + rtl::OUStringToOString( + OUSTR("[mono_uno bridge error] ") + err.m_message, + RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr_msg.getStr() ); +#endif + } +} + +void SAL_CALL Bridge_free( uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + Mapping * that = static_cast< Mapping * >( mapping ); + delete that->m_bridge; +} + +} // extern "C" + +rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT; + +namespace mono_uno +{ + +void Bridge::acquire() const SAL_THROW( () ) +{ + if (1 == osl_incrementInterlockedCount( &m_ref )) + { + if (m_registered_mono2uno) + { + uno_Mapping * mapping = const_cast< Mapping * >( &m_mono2uno ); + uno_registerMapping( + &mapping, Bridge_free, + m_mono_env, (uno_Environment *)m_uno_env, 0 ); + } + else + { + uno_Mapping * mapping = const_cast< Mapping * >( &m_uno2mono ); + uno_registerMapping( + &mapping, Bridge_free, + (uno_Environment *)m_uno_env, m_mono_env, 0 ); + } + } +} + +void Bridge::release() const SAL_THROW( () ) +{ + if (! osl_decrementInterlockedCount( &m_ref )) + { + uno_revokeMapping( + m_registered_mono2uno + ? const_cast< Mapping * >( &m_mono2uno ) + : const_cast< Mapping * >( &m_uno2mono ) ); + } +} + +MonoAssembly * +DoLoad (MonoDomain * /* domain */, char * /* fullname */) +{ + MonoAssemblyName aname; + MonoImageOpenStatus status = MONO_IMAGE_OK; + MonoAssembly *ass; + + memset (&aname, 0, sizeof (aname)); + aname.culture = ""; + strncpy ((char *)aname.public_key_token, "ce2cb7e279207b9e", MONO_PUBLIC_KEY_TOKEN_LENGTH); + aname.name = "cli_uno_bridge"; + aname.major=1; + aname.minor=0; + aname.build=0; + aname.revision=0; + + ass = mono_assembly_load (&aname, NULL, &status); + if (status != MONO_IMAGE_OK) + return NULL; + return ass; +} + +Bridge::Bridge( + uno_Environment * mono_env, uno_ExtEnvironment * uno_env, + bool registered_mono2uno ) + : m_ref( 1 ), + m_uno_env( uno_env ), + m_mono_env( mono_env ), + m_registered_mono2uno( registered_mono2uno ) +{ + MonoDomain * pDomain = mono_get_root_domain(); + // FIXME where is this freed? + MonoAssembly * pAssembly = DoLoad (pDomain, "cli_uno_bridge, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce2cb7e279207b9e"); + // FIXME and this, is this needed later? + MonoClass * pClass = mono_class_from_name ( + (MonoImage *)mono_assembly_get_image( pAssembly ), "com.sun.star.bridges.mono_uno", "Bridge" ); + OSL_ASSERT( 0 != pClass ); + /* FIXME add args to method description string */ + MonoMethodDesc * pMethodDesc = mono_method_desc_new( ":.ctor", FALSE ); + MonoMethod * pCtor = mono_method_desc_search_in_class( pMethodDesc, pClass ); + mono_method_desc_free( pMethodDesc ); + OSL_ASSERT( 0 != pCtor ); + + pMethodDesc = mono_method_desc_new( "Bridge:MapManagedToUno", FALSE ); + m_mapManagedToUnoMethod = mono_method_desc_search_in_class( pMethodDesc, pClass ); + mono_method_desc_free( pMethodDesc ); + OSL_ASSERT( 0 != m_mapManagedToUnoMethod ); + + pMethodDesc = mono_method_desc_new( "Bridge:MapUnoToManaged", FALSE ); + m_mapUnoToManagedMethod = mono_method_desc_search_in_class( pMethodDesc, pClass ); + mono_method_desc_free( pMethodDesc ); + OSL_ASSERT( 0 != m_mapUnoToManagedMethod ); + + gpointer pParams[1]; + pParams[0] = &uno_env; + m_managedBridge = mono_object_new( pDomain, pClass ); + mono_uno::runtime_invoke( pCtor, m_managedBridge, pParams, NULL, + mono_object_get_domain( m_managedBridge ) ); + + OSL_ASSERT( 0 != m_mono_env && 0 != m_uno_env ); + (*((uno_Environment *)m_uno_env)->acquire)( (uno_Environment *)m_uno_env ); + (*m_mono_env->acquire)( m_mono_env ); + + // mono2uno mapping + m_mono2uno.acquire = Mapping_acquire; + m_mono2uno.release = Mapping_release; + m_mono2uno.mapInterface = Mapping_map_to_uno; + m_mono2uno.m_bridge = this; + // uno2mono mapping + m_uno2mono.acquire = Mapping_acquire; + m_uno2mono.release = Mapping_release; + m_uno2mono.mapInterface = Mapping_map_to_mono; + m_uno2mono.m_bridge = this; + + (*g_moduleCount.modCnt.acquire)( &g_moduleCount.modCnt ); +} + +Bridge::~Bridge() SAL_THROW( () ) +{ + (*m_mono_env->release)( m_mono_env ); + (*((uno_Environment *)m_uno_env)->release)( (uno_Environment *)m_uno_env ); + // FIXME release managed bridge + + (*g_moduleCount.modCnt.release)( &g_moduleCount.modCnt ); +} + +void * Bridge::map_to_mono( + uno_Interface *pUnoI, typelib_TypeDescription * pTD ) const +{ + gpointer pMonoParams[2]; + + pMonoParams[0] = &pUnoI; + pMonoParams[1] = pTD; + + return + mono_uno::runtime_invoke( m_mapUnoToManagedMethod, + m_managedBridge, pMonoParams, NULL, + mono_object_get_domain( m_managedBridge ) ); +} + +uno_Interface * Bridge::map_to_uno( + void * pMonoI, typelib_TypeDescription * pTD ) const +{ + gpointer pMonoParams[2]; + uno_Interface ** ppResult; + + pMonoParams[0] = pMonoI; + pMonoParams[1] = pTD; + + ppResult = (uno_Interface **)mono_object_unbox( + mono_uno::runtime_invoke( m_mapManagedToUnoMethod, + m_managedBridge, pMonoParams, NULL, + mono_object_get_domain( m_managedBridge ) ) ); + + return *ppResult; +} + +} // namespace mono_uno + +extern "C" { + +// void SAL_CALL mono_environmentDisposing( uno_Environment * mono_env ) +// SAL_THROW_EXTERN_C() +// { +// } + +void SAL_CALL uno_initEnvironment( uno_Environment * mono_env ) + SAL_THROW_EXTERN_C() +{ + // mono_env->environmentDisposing = mono_environmentDisposing; + mono_env->pExtEnv = 0; /* no extended support */ +} + +void SAL_CALL uno_ext_getMapping( + uno_Mapping ** ppMapping, uno_Environment *pFrom, uno_Environment *pTo ) + SAL_THROW_EXTERN_C() +{ + OSL_ASSERT( 0 != ppMapping && 0 != pFrom && 0 != pTo ); + if (0 != *ppMapping) + { + (*(*ppMapping)->release)( *ppMapping ); + *ppMapping = 0; + } + + /* FIXME check that mono's and sal's types have matching sizes + * like jni_bridge does? */ + + OUString const & from_env_typename = OUString::unacquired( &pFrom->pTypeName ); + OUString const & to_env_typename = OUString::unacquired( &pTo->pTypeName ); + + uno_Mapping * mapping = 0; + + try + { + if (from_env_typename.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( UNO_LB_CLI )) && + to_env_typename.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( UNO_LB_UNO))) + { + Bridge * bridge = + new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1 + mapping = &bridge->m_mono2uno; + uno_registerMapping( + &mapping, Bridge_free, pFrom, + (uno_Environment *)pTo->pExtEnv, 0); + } + else if (from_env_typename.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( UNO_LB_UNO)) && + to_env_typename.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( UNO_LB_CLI))) + { + Bridge * bridge = + new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1 + mapping = &bridge->m_uno2mono; + uno_registerMapping( + &mapping, Bridge_free, + (uno_Environment *)pFrom->pExtEnv, pTo, 0); + } + } + catch (BridgeRuntimeError & err) + { +#if OSL_DEBUG_LEVEL >= 1 + OString cstr_msg( + OUStringToOString( + OUSTR("[mono_uno bridge error] ") + err.m_message, + RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr_msg.getStr() ); +#endif + } + + *ppMapping = mapping; +} + +sal_Bool SAL_CALL component_canUnload( TimeValue * pTime ) + SAL_THROW_EXTERN_C() +{ + return (*g_moduleCount.canUnload)( &g_moduleCount, pTime ); +} + +} // extern "C" + +MonoObject* +mono_uno::runtime_invoke (MonoMethod *method, void *obj, void **params, + MonoObject **exc, MonoDomain *domain) +{ + mono_thread_attach( domain ); + return mono_runtime_invoke( method, obj, params, exc ); +} diff --git a/cli_ure/source/mono_bridge/mono_bridge.h b/cli_ure/source/mono_bridge/mono_bridge.h new file mode 100644 index 000000000000..858ae19b8370 --- /dev/null +++ b/cli_ure/source/mono_bridge/mono_bridge.h @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_MONO_BRIDGE_H +#define INCLUDED_MONO_BRIDGE_H + +#include "glib/gtypes.h" +#include "osl/interlck.h" +#include "rtl/ustring.hxx" +#include "typelib/typedescription.hxx" +#include "uno/dispatcher.h" +#include "uno/mapping.h" + +extern "C" { +#include "mono/metadata/appdomain.h" +#include "mono/metadata/debug-helpers.h" +#include "mono/metadata/object.h" +#include "mono/metadata/threads.h" +} + +namespace cssu = com::sun::star::uno; + +typedef struct _uno_ExtEnvironment uno_ExtEnvironment; +typedef struct _uno_Environment uno_Environment; +typedef struct _typelib_TypeDescription typelib_TypeDescription; + +namespace mono_uno +{ + +MonoObject* runtime_invoke (MonoMethod *method, void *obj, void **params, + MonoObject **exc, MonoDomain *domain); + +//==== holds environments and mappings ========================================= +struct Bridge; +struct Mapping : public uno_Mapping +{ + Bridge * m_bridge; +}; + +//============================================================================== +struct Bridge +{ + mutable oslInterlockedCount m_ref; + MonoObject * m_managedBridge; + + uno_ExtEnvironment * m_uno_env; + uno_Environment * m_mono_env; + + Mapping m_mono2uno; + Mapping m_uno2mono; + bool m_registered_mono2uno; + + MonoMethod * m_mapUnoToManagedMethod; + MonoMethod * m_mapManagedToUnoMethod; + + ~Bridge() SAL_THROW( () ); + explicit Bridge( + uno_Environment * mono_env, uno_ExtEnvironment * uno_env, + bool registered_mono2uno ); + + void acquire() const; + void release() const; + + void * map_to_mono( + uno_Interface * pUnoI, typelib_TypeDescription * pTD ) const; + + uno_Interface * map_to_uno( + void * pMonoI, typelib_TypeDescription * pTD ) const; +}; + +struct MonoProxy : public uno_Interface +{ + mutable oslInterlockedCount m_ref; + guint32 m_managedProxy; + uno_ExtEnvironment * m_unoEnv; + const cssu::TypeDescription m_unoType; + const rtl::OUString m_Oid; + MonoMethod * m_managedDispatch; + + void acquire() const; + void release() const; + void dispatch(typelib_TypeDescription const * member_td, void * uno_ret, + void * uno_args [], uno_Any ** uno_exc); + + MonoProxy(uno_ExtEnvironment * pUnoEnv, guint32 managedProxy, + rtl_uString * pOid, typelib_TypeDescription * pTD); +}; + +struct BridgeRuntimeError +{ + ::rtl::OUString m_message; + + inline BridgeRuntimeError( ::rtl::OUString const & message ) + : m_message( message ) + {} +}; + +} + +#endif diff --git a/cli_ure/source/mono_bridge/mono_proxy.cxx b/cli_ure/source/mono_bridge/mono_proxy.cxx new file mode 100644 index 000000000000..6304c9ac9537 --- /dev/null +++ b/cli_ure/source/mono_bridge/mono_proxy.cxx @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "mono_bridge.h" + +#include "rtl/ustring.h" +#include "uno/dispatcher.h" +#include "uno/environment.h" +#include "typelib/typedescription.h" + +extern "C" { +#include "mono/metadata/threads.h" +} + +using namespace mono_uno; + +extern "C" { + +static void SAL_CALL mono_proxy_free( uno_ExtEnvironment * /* env */, void * proxy) +{ + MonoProxy * monoProxy = reinterpret_cast< MonoProxy * >( proxy ); + + delete monoProxy; +} + +uno_Interface * SAL_CALL cli_uno_environment_createMonoProxyAndRegister( + uno_ExtEnvironment *pUnoEnv, void *pMonoProxy, rtl_uString *pOid, + typelib_TypeDescription *pTD ) + SAL_THROW_EXTERN_C() +{ + uno_Interface * proxy = static_cast< uno_Interface * >( + new MonoProxy( pUnoEnv, + static_cast< guint32 >( reinterpret_cast< sal_IntPtr >( pMonoProxy ) ), + pOid, pTD ) ); + + pUnoEnv->registerProxyInterface( + pUnoEnv, + reinterpret_cast< void ** >( &proxy ), + mono_proxy_free, + pOid, + (typelib_InterfaceTypeDescription*) pTD ); + + return proxy; +} + +static void SAL_CALL mono_proxy_acquire( uno_Interface * pUnoI ) +{ + MonoProxy const * that = static_cast< MonoProxy const * >( pUnoI ); + that->acquire(); +} + +static void SAL_CALL mono_proxy_release( uno_Interface * pUnoI ) +{ + MonoProxy const * that = static_cast< MonoProxy const * >( pUnoI ); + that->release(); +} + +static void SAL_CALL mono_proxy_dispatch( + uno_Interface * pUnoI, typelib_TypeDescription const * member_td, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) + SAL_THROW_EXTERN_C() +{ + MonoProxy * that = static_cast< MonoProxy * >( pUnoI ); + that->dispatch( member_td, uno_ret, uno_args, uno_exc ); +} + +} // extern "C" + +namespace mono_uno +{ + +MonoProxy::MonoProxy(uno_ExtEnvironment * pUnoEnv, guint32 managedProxy, + rtl_uString *pOid, typelib_TypeDescription * pTD): + m_ref(1), + m_managedProxy(managedProxy), // FIXME free this in the destructor? + m_unoEnv(pUnoEnv), + m_unoType(pTD), + m_Oid(pOid) +{ + uno_Interface::acquire = mono_proxy_acquire; + uno_Interface::release = mono_proxy_release; + uno_Interface::pDispatcher = mono_proxy_dispatch; + + MonoObject * pObj = mono_gchandle_get_target( m_managedProxy ); + MonoClass * pClass = mono_object_get_class( pObj ); + MonoMethodDesc * pMethodDesc = mono_method_desc_new( "ManagedProxy:Dispatch", FALSE ); + m_managedDispatch = mono_method_desc_search_in_class( pMethodDesc, pClass ); + mono_method_desc_free( pMethodDesc ); + OSL_ASSERT( 0 != m_managedDispatch ); +} + +inline void MonoProxy::acquire() const +{ + if (1 == osl_incrementInterlockedCount( &m_ref )) + { + // rebirth of proxy zombie + void * that = const_cast< MonoProxy * >( this ); + // register at uno env + (*m_unoEnv->registerProxyInterface)( + m_unoEnv, &that, + mono_proxy_free, m_Oid.pData, + (typelib_InterfaceTypeDescription *)m_unoType.get() ); +#if OSL_DEBUG_LEVEL >= 2 + OSL_ASSERT( this == (void const * const)that ); +#endif + } +} + +inline void MonoProxy::release() const +{ + if (0 == osl_decrementInterlockedCount( &m_ref )) + { + // revoke from uno env on last release, + // The proxy can be resurrected if acquire is called before the uno + // environment calls mono_proxy_free. mono_proxy_free will + //delete the proxy. The environment does not acquire a registered + //proxy. + (*m_unoEnv->revokeInterface)( + m_unoEnv, const_cast< MonoProxy * >( this ) ); + } +} + +inline void MonoProxy::dispatch( typelib_TypeDescription const * member_td, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) +{ + OSL_ASSERT( m_managedDispatch != 0 ); + + gpointer pMonoParams[4]; + + pMonoParams[0] = const_cast< typelib_TypeDescription * >(member_td); + pMonoParams[1] = uno_ret; + pMonoParams[2] = uno_args; + pMonoParams[3] = uno_exc; + + MonoObject *obj = mono_gchandle_get_target( m_managedProxy ); + + mono_uno::runtime_invoke( m_managedDispatch, + obj, pMonoParams, NULL, + mono_object_get_domain( obj ) ); +} + +} diff --git a/cli_ure/source/mono_bridge/rtl_ustring.cs b/cli_ure/source/mono_bridge/rtl_ustring.cs new file mode 100644 index 000000000000..431e9e1dc762 --- /dev/null +++ b/cli_ure/source/mono_bridge/rtl_ustring.cs @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +namespace uno.rtl { + +using System; +using System.Runtime.InteropServices; +using System.Text; + +public unsafe struct UString +{ + public int RefCount; + public int Length; + public char FirstChar; + + [DllImport("sal")] + private static extern void rtl_uString_acquire(void* data); + + [DllImport("sal")] + private static unsafe extern void rtl_uString_release(void* data); + + [DllImport("sal")] + private static unsafe extern void rtl_uString_new(void* data); + + [DllImport("sal")] + private static unsafe extern void rtl_uString_newFromStr_WithLength( + void* data, + // this should pass a pointer to the original string's char[] + [MarshalAs(UnmanagedType.LPWStr)] string value, + int len); + + [DllImport("sal")] + private static unsafe extern void rtl_uString_newFromStr_WithLength( + void* data, + // this should pass a pointer to the stringbuilder's internal char[] + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder buffer, + int len); + + public static unsafe void Acquire(UString* us) + { + rtl_uString_acquire(us); + } + + public static unsafe void Release(UString* us) + { + rtl_uString_release(us); + } + + public static unsafe void New(UString** p) + { + rtl_uString_new(p); + } + + public static unsafe void NewFromString(UString **p, string s) + { + rtl_uString_newFromStr_WithLength(p, s, s.Length); + } + + public static unsafe void NewFromStringBuilder(UString **p, StringBuilder sb) + { + rtl_uString_newFromStr_WithLength(p, sb, sb.Length); + } + + public static unsafe string UStringToString(UString *p) + { + return new String(&(p->FirstChar), 0, p->Length); + } +} + +// FIXME move this to its own file or rename this file to e.g. sal +public unsafe struct Mem +{ + // FIXME parameter is a sal_Size which is unsigned and has the + // size of a native long. Thus this is not 64bit safe. Might have + // to write a glue function that always takes 32bit. + [DllImport("sal", EntryPoint="rtl_allocateMemory")] + public static unsafe extern void *Allocate(int bytes); +} + +} diff --git a/cli_ure/source/mono_bridge/typeclass.cs b/cli_ure/source/mono_bridge/typeclass.cs new file mode 100644 index 000000000000..5a5383ddb215 --- /dev/null +++ b/cli_ure/source/mono_bridge/typeclass.cs @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +namespace uno.Typelib { + +public class TypeClass +{ + /** type class of void */ + public const int VOID = 0; + /** type class of char */ + public const int CHAR = 1; + /** type class of boolean */ + public const int BOOLEAN = 2; + /** type class of byte */ + public const int BYTE = 3; + /** type class of short */ + public const int SHORT = 4; + /** type class of unsigned short */ + public const int UNSIGNED_SHORT = 5; + /** type class of long */ + public const int LONG = 6; + /** type class of unsigned long */ + public const int UNSIGNED_LONG = 7; + /** type class of hyper */ + public const int HYPER = 8; + /** type class of unsigned hyper */ + public const int UNSIGNED_HYPER = 9; + /** type class of float */ + public const int FLOAT = 10; + /** type class of double */ + public const int DOUBLE = 11; + /** type class of string */ + public const int STRING = 12; + /** type class of type */ + public const int TYPE = 13; + /** type class of any */ + public const int ANY = 14; + /** type class of enum */ + public const int ENUM = 15; + /** type class of typedef */ + public const int TYPEDEF = 16; + /** type class of struct */ + public const int STRUCT = 17; + /** type class of union (not implemented) */ + public const int UNION = 18; + /** type class of exception */ + public const int EXCEPTION = 19; + /** type class of sequence */ + public const int SEQUENCE = 20; + /** type class of array (not implemented) */ + public const int ARRAY = 21; + /** type class of interface */ + public const int INTERFACE = 22; + /** type class of service (not implemented) */ + public const int SERVICE = 23; + /** type class of module (not implemented) */ + public const int MODULE = 24; + /** type class of interface method */ + public const int INTERFACE_METHOD = 25; + /** type class of interface attribute */ + public const int INTERFACE_ATTRIBUTE = 26; + /** type class of unknown type */ + public const int UNKNOWN = 27; + /** type class of properties */ + public const int PROPERTY = 28; + /** type class of constants */ + public const int CONSTANT = 29; + /** type class of constants groups */ + public const int CONSTANTS = 30; + /** type class of singletons */ + public const int SINGLETON = 31; +} + +} diff --git a/cli_ure/source/mono_bridge/typedescription.cs b/cli_ure/source/mono_bridge/typedescription.cs new file mode 100644 index 000000000000..fa1076be7481 --- /dev/null +++ b/cli_ure/source/mono_bridge/typedescription.cs @@ -0,0 +1,612 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +namespace uno.Typelib { + +using System; +using System.Runtime.InteropServices; + +/** Holds a weak reference to a type description. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct TypeDescriptionReference +{ + /** reference count of type; don't ever modify this by yourself, use + typedescriptionreference_acquire() and typedescriptionreference_release() + */ + public int nRefCount; + /** number of static references of type, because of the fact that some types are needed + until program termination and are commonly held static. + */ + public int nStaticRefCount; + /** type class of type + */ + public int eTypeClass; + /** fully qualified name of type. + */ + public uno.rtl.UString * pTypeName; + /** pointer to full typedescription; this value is only valid if the type is never swapped out + */ + public TypeDescription * pType; + /** pointer to optimize the runtime; not for public use + */ + public void * pUniqueIdentifier; + /** reserved for future use; 0 if not used + */ + public void * pReserved; + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescriptionreference_acquire") ] + public static extern void Acquire(/* TypeDescriptionReference */ void *td); + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescriptionreference_release") ] + public static extern void Release(/* TypeDescriptionReference */ void *td); + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescriptionreference_new") ] + public static extern void New(TypeDescriptionReference **ppTDR, + int /* enum typelib_TypeClass */ eTypeClass, + /* uno.rtl.UString */ void *pTypeName); + + [ DllImport("uno_cppu", EntryPoint="typelib_static_type_getByTypeClass") ] + public static extern TypeDescriptionReference **GetByTypeClass( + int /* enum typelib_TypeClass */ eTypeClass); + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescriptionreference_getDescription") ] + public static extern void GetDescription( + TypeDescription ** ppRet, /* TypeDescriptionReference */ void * pRef); +} + +/** Full type description of a type. Memory layout of this struct is identical to the + TypeDescriptionReference for the first six members. + So a typedescription can be used as type reference. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct TypeDescription +{ + /** reference count; don't ever modify this by yourself, use + typedescription_acquire() and typedescription_release() + */ + public int nRefCount; + /** number of static references of type, because of the fact that some types are needed + until program termination and are commonly held static. + */ + public int nStaticRefCount; + /** type class of type + */ + public int eTypeClass; + /** fully qualified name of type. + */ + public uno.rtl.UString * pTypeName; + /** pointer to self to distinguish reference from description; for internal use only + */ + public TypeDescription * pSelf; + /** pointer to optimize the runtime; not for public use + */ + public void * pUniqueIdentifier; + /** reserved for future use; 0 if not used + */ + public void * pReserved; + + /** flag to determine whether the description is complete: + compound and union types lack of member names, enums lack of member types and names, + interfaces lack of members and table init. + Call typedescription_complete() if false. + */ + public byte bComplete; + /** size of type + */ + public int nSize; + /** alignment of type + */ + public int nAlignment; + /** pointer to weak reference + */ + public TypeDescriptionReference * pWeakRef; + /** determines, if type can be unloaded (and it is possible to reloaded it) + */ + public byte bOnDemand; + + /* FIXME move to TypeDescriptionReference */ + public static TypeDescriptionReference *VoidType + { + get { return null; /* FIXME, use typelib_static_type_getByTypeClass(VOID) */ } + } + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescription_getByName") ] + public static extern void GetByName(TypeDescription **pTD, + /* uno.rtl.UString */ void *name); + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescription_acquire") ] + public static extern void Acquire(/* TypeDescription */ void *td); + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescription_release") ] + public static extern void Release(/* TypeDescription */ void *td); + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescription_complete") ] + public static extern bool Complete(TypeDescription **pTD); +} + +/** Type description for exception types. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct CompoundTypeDescription +{ + /** inherits all members of TypeDescription + */ + public TypeDescription aBase; + + /** pointer to base type description, else 0 + */ + public CompoundTypeDescription * pBaseTypeDescription; + + /** number of members + */ + public int nMembers; + /** byte offsets of each member including the size the base type + */ + public int * pMemberOffsets; + /** members of the struct or exception + */ + public TypeDescriptionReference ** ppTypeRefs; + /** member names of the struct or exception. + */ + public uno.rtl.UString ** ppMemberNames; +} + +/** + Type description for struct types. + + This is only used to represent plain struct types and instantiated + polymorphic struct types; there is no representation of polymorphic struct + type templates at this level. + + @since UDK 3.2.0 + */ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct StructTypeDescription +{ + /** + Derived from CompoundTypeDescription. + */ + public CompoundTypeDescription aBase; + + /** + Flags for direct members, specifying whether they are of parameterized + type (true) or explict type (false). + + For a plain struct type, this is a null pointer. + */ + public byte * pParameterizedTypes; +} + +/** Type description of a union. The type class of this description is TypeClass_UNION. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct UnionTypeDescription +{ + /** inherits all members of TypeDescription + */ + public TypeDescription aBase; + + /** type of the discriminant + */ + public TypeDescriptionReference * pDiscriminantTypeRef; + + /** union default descriminant + */ + public long nDefaultDiscriminant; + /** union default member type (may be 0) + */ + public TypeDescriptionReference * pDefaultTypeRef; + /** number of union member types + */ + public int nMembers; + /** union member discriminant values (same order as idl declaration) + */ + public long * pDiscriminants; + /** union member value types (same order as idl declaration) + */ + public TypeDescriptionReference ** ppTypeRefs; + /** union member value names (same order as idl declaration) + */ + public uno.rtl.UString ** ppMemberNames; + /** union value offset for data access + */ + public int nValueOffset; +} + +/** Type description of an array or sequence. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct IndirectTypeDescription +{ + /** inherits all members of TypeDescription + */ + public TypeDescription aBase; + + /** array, sequence: pointer to element type + */ + public TypeDescriptionReference * pType; +} + +/** Type description of an array. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct ArrayTypeDescription +{ + /** inherits all members of IndirectTypeDescription + */ + public IndirectTypeDescription aBase; + + /** number of dimensions + */ + public int nDimensions; + /** number of total array elements + */ + public int nTotalElements; + /** array of dimensions + */ + public int * pDimensions; +} + +/** Type description of an enum. The type class of this description is TypeClass_ENUM. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct EnumTypeDescription +{ + /** inherits all members of TypeDescription + */ + public TypeDescription aBase; + + /** first value of the enum + */ + public int nDefaultEnumValue; + /** number of enum values + */ + public int nEnumValues; + /** names of enum values + */ + public uno.rtl.UString ** ppEnumNames; + /** values of enum (corresponding to names in similar order) + */ + public int * pEnumValues; +} + +/** Description of an interface method parameter. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct MethodParameter +{ + /** name of parameter + */ + public uno.rtl.UString * pName; + /** type of parameter + */ + public TypeDescriptionReference * pTypeRef; + /** true: the call type of this parameter is [in] or [inout] + false: the call type of this parameter is [out] + */ + public byte bIn; + /** true: the call type of this parameter is [out] or [inout] + false: the call type of this parameter is [in] + */ + public byte bOut; +} + +/** Common base type description of InterfaceMethodTypeDescription and + InterfaceAttributeTypeDescription. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct InterfaceMemberTypeDescription +{ + /** inherits all members of TypeDescription + */ + public TypeDescription aBase; + + /** position of member in the interface including the number of members of + any base interfaces + */ + public int nPosition; + /** name of member + */ + public uno.rtl.UString * pMemberName; +} + +/** Type description of an interface method. The type class of this description is + TypeClass_INTERFACE_METHOD. The size and the alignment are 0. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct InterfaceMethodTypeDescription +{ + /** inherits all members of InterfaceMemberTypeDescription + */ + public InterfaceMemberTypeDescription aBase; + + /** type of the return value + */ + public TypeDescriptionReference * pReturnTypeRef; + /** number of parameters + */ + public int nParams; + /** array of parameters + */ + public MethodParameter * pParams; + /** number of exceptions + */ + public int nExceptions; + /** array of exception types + */ + public TypeDescriptionReference ** ppExceptions; + /** determines whether method is declared oneway + */ + public byte bOneWay; + + /** the interface description this method is a member of + + @since #i21150# + */ + public InterfaceTypeDescription * pInterface; + /** the inherited direct base method (null for a method that is not + inherited) + + @since UDK 3.2.0 + */ + public TypeDescriptionReference * pBaseRef; + /** if pBaseRef is null, the member position of this method within + pInterface, not counting members inherited from bases; if pBaseRef is + not null, the index of the direct base within pInterface from which this + method is inherited + + @since UDK 3.2.0 + */ + public int nIndex; +} + +/** The description of an interface attribute. The type class of this description is + TypeClass_INTERFACE_ATTRIBUTE. The size and the alignment are 0. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct InterfaceAttributeTypeDescription +{ + /** inherits all members of InterfaceMemberTypeDescription + */ + public InterfaceMemberTypeDescription aBase; + + /** determines whether attribute is read only + */ + public byte bReadOnly; + /** type of the attribute + */ + public TypeDescriptionReference * pAttributeTypeRef; + + /** the interface description this attribute is a member of + + @since #i21150# + */ + public InterfaceTypeDescription * pInterface; + /** the inherited direct base attribute (null for an attribute that is not + inherited) + + @since UDK 3.2.0 + */ + public TypeDescriptionReference * pBaseRef; + /** if pBaseRef is null, the member position of this attribute within + pInterface, not counting members inherited from bases; if pBaseRef is + not null, the index of the direct base within pInterface from which this + attribute is inherited + + @since UDK 3.2.0 + */ + public int nIndex; + /** number of getter exceptions + + @since UDK 3.2.0 + */ + public int nGetExceptions; + /** array of getter exception types + + @since UDK 3.2.0 + */ + public TypeDescriptionReference ** ppGetExceptions; + /** number of setter exceptions + + @since UDK 3.2.0 + */ + public int nSetExceptions; + /** array of setter exception types + + @since UDK 3.2.0 + */ + public TypeDescriptionReference ** ppSetExceptions; +} + +/// @HTML +/** Type description of an interface. + + <p>Not all members are always initialized (not yet initialized members being + null); there are three levels:</p> + <ul> + <li>Minimally, only <code>aBase</code>, + <code>pBaseTypeDescription</code>, <code>aUik</code>, + <code>nBaseTypes</code>, and <code>ppBaseTypes</code> are initialized; + <code>aBase.bComplete</code> is false. This only happens when an + interface type description is created with + <code>static_mi_interface_type_init</code> or + <code>static_interface_type_init</code>.</li> + + <li>At the next level, <code>nMembers</code>, <code>ppMembers</code>, + <code>nAllMembers</code>, <code>ppAllMembers</code> are also + initialized; <code>aBase.bComplete</code> is still false. This happens + when an interface type description is created with + <code>typedescription_newMIInterface</cocde> or + <code>typedescription_newInterface</code>.</li> + + <li>At the final level, <code>pMapMemberIndexToFunctionIndex</code>, + <code>nMapFunctionIndexToMemberIndex</code>, and + <code>pMapFunctionIndexToMemberIndex</code> are also initialized; + <code>aBase.bComplete</code> is true. This happens after a call to + <code>typedescription_complete</code>.</li> + </ul> +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct InterfaceTypeDescription +/// @NOHTML +{ + /** inherits all members of TypeDescription + */ + public TypeDescription aBase; + + /** pointer to base type description, else 0 + + @deprecated + use nBaseTypes and ppBaseTypes instead + */ + public InterfaceTypeDescription * pBaseTypeDescription; + /** unique identifier of interface + */ + public Uik aUik; + /** number of members + */ + public int nMembers; + /** array of members; references attributes or methods + */ + public TypeDescriptionReference ** ppMembers; + /** number of members including members of base interface + */ + public int nAllMembers; + /** array of members including members of base interface; references attributes or methods + */ + public TypeDescriptionReference ** ppAllMembers; + /** array mapping index of the member description to an index doubling for read-write + attributes (called function index); size of array is nAllMembers + */ + public int * pMapMemberIndexToFunctionIndex; + /** number of members plus number of read-write attributes + */ + public int nMapFunctionIndexToMemberIndex; + /** array mapping function index to member index; size of arry is nMapFunctionIndexToMemberIndex + */ + public int * pMapFunctionIndexToMemberIndex; + /** number of base types + + @since UDK 3.2.0 + */ + public int nBaseTypes; + /** array of base type descriptions + + @since UDK 3.2.0 + */ + public InterfaceTypeDescription ** ppBaseTypes; + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescription_release") ] + public static extern void Release(/* InterfaceTypeDescription */ void *td); + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescription_acquire") ] + public static extern void Acquire(/* InterfaceTypeDescription */ void *td); + + [ DllImport("uno_cppu", EntryPoint="typelib_typedescription_equals") ] + public static extern bool Equal(/* InterfaceTypeDescription */ void *td1, /* InterfaceTypeDescription */ void *td2); +} + +/** Init struct of compound members for typedescription_new(). +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct CompoundMember_Init +{ + /** type class of compound member + */ + public int eTypeClass; + /** name of type of compound member + + For a member of an instantiated polymorphic struct type that is of + parameterized type, this will be a null pointer. + */ + public uno.rtl.UString * pTypeName; + /** name of compound member + */ + public uno.rtl.UString * pMemberName; +} + +/** + Init struct of members for typedescription_newStruct(). + + @since UDK 3.2.0 + */ +[ StructLayout(LayoutKind.Sequential) ] +public struct StructMember_Init +{ + /** + Derived from CompoundMember_Init; + */ + public CompoundMember_Init aBase; + + /** + Flag specifying whether the member is of parameterized type (true) or + explict type (false). + */ + public byte bParameterizedType; +} + +/** Init struct of interface methods for typedescription_new(). +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct Parameter_Init +{ + /** type class of parameter + */ + public int eTypeClass; + /** name of parameter + */ + public uno.rtl.UString * pTypeName; + /** name of parameter + */ + public uno.rtl.UString * pParamName; + /** true, if parameter is [in] or [inout] + */ + public byte bIn; + /** true, if parameter is [out] or [inout] + */ + public byte bOut; +} + +/** Init struct of union types for typedescription_newUnion(). +*/ +[ StructLayout(LayoutKind.Sequential) ] +public unsafe struct Union_Init +{ + /** union member discriminant + */ + public long nDiscriminant; + /** union member name + */ + public uno.rtl.UString * pMemberName; + /** union member type + */ + public TypeDescriptionReference * pTypeRef; +} + +} diff --git a/cli_ure/source/mono_bridge/uik.cs b/cli_ure/source/mono_bridge/uik.cs new file mode 100644 index 000000000000..87c7e85c9d04 --- /dev/null +++ b/cli_ure/source/mono_bridge/uik.cs @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +namespace uno.Typelib { + +using System.Runtime.InteropServices; + +/** Binary typelib uik struct. Internally not used anymore. +*/ +[ StructLayout(LayoutKind.Sequential) ] +public struct Uik +{ + int m_Data1; + short m_Data2; + short m_Data3; + int m_Data4; + int m_Data5; +} + +} diff --git a/cli_ure/source/mono_bridge/uno_glue.cxx b/cli_ure/source/mono_bridge/uno_glue.cxx new file mode 100644 index 000000000000..de73166e9080 --- /dev/null +++ b/cli_ure/source/mono_bridge/uno_glue.cxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "rtl/ustring.h" +#include "uno/dispatcher.h" +#include "uno/environment.h" +#include <stdio.h> + +extern "C" { + +/* uno_Interface */ + +void SAL_CALL cli_uno_interface_acquire( uno_Interface *pInterface ) + SAL_THROW_EXTERN_C() +{ + (*pInterface->acquire)( pInterface ); +} + +void SAL_CALL cli_uno_interface_release( uno_Interface *pInterface ) + SAL_THROW_EXTERN_C() +{ + (*pInterface->release)( pInterface ); +} + +void SAL_CALL cli_uno_interface_dispatch( + uno_Interface *pInterface, const struct _typelib_TypeDescription *pMemberType, + void *pReturn, void *pArgs[], uno_Any **ppException ) + SAL_THROW_EXTERN_C() +{ + (*pInterface->pDispatcher)( pInterface, pMemberType, pReturn, pArgs, ppException ); +} + +/* uno_ExtEnvironment */ + +void SAL_CALL cli_uno_environment_getObjectIdentifier( + uno_ExtEnvironment *pUnoEnv, rtl_uString **ppOId, uno_Interface *pUnoI ) + SAL_THROW_EXTERN_C() +{ + (*pUnoEnv->getObjectIdentifier)( pUnoEnv, ppOId, pUnoI ); +} + +void SAL_CALL cli_uno_environment_registerInterface( + uno_ExtEnvironment *pUnoEnv, void **ppInterface, rtl_uString *pOId, + struct _typelib_InterfaceTypeDescription *pTypeDescr ) + SAL_THROW_EXTERN_C() +{ + (*pUnoEnv->registerInterface)( pUnoEnv, ppInterface, pOId, pTypeDescr ); +} + +void SAL_CALL cli_uno_environment_getRegisteredInterface( + uno_ExtEnvironment *pUnoEnv, void **ppInterface, rtl_uString *pOId, + struct _typelib_InterfaceTypeDescription *pTypeDescr ) + SAL_THROW_EXTERN_C() +{ + (*pUnoEnv->getRegisteredInterface)( pUnoEnv, ppInterface, pOId, pTypeDescr ); +} + + +} diff --git a/cli_ure/source/mono_bridge/uno_proxy.cs b/cli_ure/source/mono_bridge/uno_proxy.cs new file mode 100644 index 000000000000..76f649b70d4c --- /dev/null +++ b/cli_ure/source/mono_bridge/uno_proxy.cs @@ -0,0 +1,565 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +using System; +using System.Collections; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Proxies; + +using uno.Binary; +using uno.Typelib; +using uno.rtl; + +namespace com.sun.star.bridges.mono_uno /* FIXME use some uno.foo namespace ? */ +{ + +public unsafe class UnoInterfaceInfo +{ + public IntPtr UnoInterface; // wrapped interface + public Type Type; // mapped type + public com.sun.star.bridges.mono_uno.Bridge Bridge; + public InterfaceTypeDescription *TypeDesc; + + public UnoInterfaceInfo(com.sun.star.bridges.mono_uno.Bridge bridge, + IntPtr unoInterface, + InterfaceTypeDescription *td) + { + Bridge = bridge; + UnoInterface = unoInterface; + Type = Bridge.MapUnoType((TypeDescription *)td); + uno.Binary.Interface.Acquire(UnoInterface); + TypeDesc = td; + InterfaceTypeDescription.Acquire(TypeDesc); + + fixed (InterfaceTypeDescription **ppTypeDesc = &TypeDesc) + if (((TypeDescription *)TypeDesc)->bComplete == 0 && + TypeDescription.Complete((TypeDescription **)ppTypeDesc)) + { + // FIXME throw a uno runtime exception + } + } + + ~UnoInterfaceInfo() + { + Bridge.RevokeFromUnoEnvironment(UnoInterface); + uno.Binary.Interface.Release(UnoInterface); + InterfaceTypeDescription.Release(TypeDesc); + } +} + +public unsafe class UnoInterfaceProxy: RealProxy, IRemotingTypeInfo +{ + /** used for IRemotingTypeInfo.TypeName + */ + string typeName = "System.Object"; + + /** The list is filled with UnoInterfaceInfo objects. The list can only + grow and elements are never changed. If an element was added it + must not be changed! + */ + ArrayList interfaces = new ArrayList(10); // of UnoInterfaceInfo + + /** The list is filled with additional UnoInterfaceProxy object due + to aggregation via bridges. Though the latter is strongly + discouraged, this has to be supported. + */ + ArrayList additionalProxies = new ArrayList(); + + Bridge bridge; + string oid; + + private unsafe UnoInterfaceProxy(Bridge bridge, IntPtr unoInterface, + InterfaceTypeDescription *TD, string oid) + : base(typeof(MarshalByRefObject)) // FIXME is there a better type? + { + this.bridge = bridge; + this.oid = oid; + AddUnoInterface(unoInterface, TD); + } + + ~UnoInterfaceProxy() + { + // FIXME should revokeInterface from environment, but can't + // access managed string oid any longer. + } + + public static unsafe object Create(Bridge bridge, IntPtr unoInterface, + InterfaceTypeDescription *TD, string oid) + { + UnoInterfaceProxy realProxy = new UnoInterfaceProxy(bridge, unoInterface, + TD, oid); + object proxy = realProxy.GetTransparentProxy(); + bridge.RegisterWithCliEnvironment(proxy, oid); + return proxy; + } + + // RealProxy members + public unsafe override IMessage Invoke(IMessage request) + { + IMethodCallMessage callmsg = (IMethodCallMessage)request; + + // Find out which UNO interface is being called + string typeName = callmsg.TypeName; + typeName = typeName.Substring(0, typeName.IndexOf(',')); + + // Special Handling for System.Object methods + if (typeName.IndexOf("System.Object") != -1) + { + return InvokeObjectMethod(request); + } + + Type typeBeingCalled = Bridge.LoadCliType(typeName); + UnoInterfaceInfo info = FindInfo(typeBeingCalled); + + Trace.Assert(info != null); + + string methodName = callmsg.MethodName; + TypeDescriptionReference **ppAllMembers = + info.TypeDesc->ppAllMembers; + int numMembers = info.TypeDesc->nAllMembers; + for (int i = numMembers - 1; i >= 0; --i) + { + TypeDescriptionReference *memberTD = *(ppAllMembers + i); + + // FIXME do without string conversion? + string memberTypeName = UString.UStringToString(memberTD->pTypeName); + // check methodName against fully qualified memberTypeName + // of memberTD; memberTypeName is of the form + // <name> "::" <methodName> *(":@" <idx> "," <idx> ":" <name>) + + int offset = memberTypeName.IndexOf(':') + 2; + int remainder = memberTypeName.Length - offset; + if (memberTD->eTypeClass == TypeClass.INTERFACE_METHOD) + { + if ((methodName.Length == remainder || + (methodName.Length < remainder && + memberTypeName[offset + methodName.Length] == ':')) && + String.Compare(memberTypeName, offset, + methodName, 0, methodName.Length) == 0) + { + TypeDescription *methodTD = null; + // FIXME release it + TypeDescriptionReference.GetDescription(&methodTD, memberTD); + + uno.Any exception; + uno.Any result = + bridge.CallUno(info.UnoInterface, + methodTD, + ((InterfaceMethodTypeDescription *)methodTD)->pReturnTypeRef, + ((InterfaceMethodTypeDescription *)methodTD)->nParams, + ((InterfaceMethodTypeDescription *)methodTD)->pParams, + callmsg.Args, + /* FIXME this is an implementation detail, + documented on MSDN, but still an implementation + detail. cli_uno does the same */ + (System.Type[])callmsg.MethodSignature, + out exception); + return ConstructReturnMessage(result, callmsg.Args, + (InterfaceMethodTypeDescription *)methodTD, + callmsg, exception); + } + } + else // INTERFACE_ATTRIBUTE + { + if (methodName.Length > 4 && + (methodName.Length - 4 == remainder || + (methodName.Length - 4 < remainder && + memberTypeName[offset + methodName.Length - 4] == ':')) && + methodName[1] == 'e' && methodName[2] == 't' && + String.Compare(memberTypeName, offset, + methodName, 4, methodName.Length - 4) == 0) + { + InterfaceAttributeTypeDescription *attributeTD = null; + // FIXME release it + TypeDescriptionReference.GetDescription( (TypeDescription **)&attributeTD, + memberTD ); + uno.Any exception; + uno.Any result; + + if (methodName[0] == 'g') // "get" + { + result = bridge.CallUno(info.UnoInterface, + (TypeDescription *)attributeTD, + attributeTD->pAttributeTypeRef, + 0, null, null, null, + out exception); + return ConstructReturnMessage(result, null, null, + callmsg, exception); + } + else if (methodName[0] == 's') // "set" + { + if (attributeTD->bReadOnly != 0) + /* FIXME should we generate an exception? */ + return ConstructReturnMessage(uno.Any.VOID, null, null, + callmsg, uno.Any.VOID); + + MethodParameter param; + param.pTypeRef = attributeTD->pAttributeTypeRef; + param.bIn = 1; + param.bOut = 0; + + result = + bridge.CallUno(info.UnoInterface, + (TypeDescription *)attributeTD, + TypeDescription.VoidType, + 1, ¶m, + callmsg.Args, null, /* FIXME ??? from cli_uno */ + out exception); + return ConstructReturnMessage(uno.Any.VOID, null, null, + callmsg, exception); + } + break; + } + } + } + // FIXME check if the message of the exception is not crippled + + // the thing that should not be... no method info found! + // FIXME throw unoidl.com.sun.star.uno.RuntimeException + + return null; + } + + // IRemotingTypeInfo members + public string TypeName + { + get { return typeName; } + set { typeName = value; } + } + + public unsafe bool CanCastTo(Type fromType, object o) + { + if (fromType == typeof(Object)) + return true; + + lock (this) { + if (FindInfo(fromType) != null) + // type is already in our list of Interfaces + return true; + + // queryInterface for the required type + // there is always a least one interface in our list + UnoInterfaceInfo info = (UnoInterfaceInfo)interfaces[0]; + // ppAllMembers[0] corresponds to queryInterface + TypeDescription *queryI = null; + + TypeDescriptionReference.GetDescription( // FIXME release it when you're done + &queryI, *(info.TypeDesc->ppAllMembers)); + + object[] args = new object[] { fromType }; + uno.Any exception; + + uno.Any result = bridge.CallUno(info.UnoInterface, + queryI, + ((InterfaceMethodTypeDescription *)queryI)->pReturnTypeRef, + 1, ((InterfaceMethodTypeDescription *)queryI)->pParams, args, null, + out exception); + + // queryInterface doesn't throw exceptions. + + if (result.Type != typeof(void)) // result has a value + { + if (FindInfo(fromType) != null) + { + // the proxy supports the requested interface now + return true; + } + + // via aggregation: it is possible that queryInterface() returns + // and interface with a different oid. + // That way, this type is supported for the CLI + // interpreter (CanCastTo() returns true) + object obj = result.Value; + if (RemotingServices.IsTransparentProxy(obj)) + { + UnoInterfaceProxy proxy = + (UnoInterfaceProxy)RemotingServices.GetRealProxy(obj); + additionalProxies.Add(proxy); + return true; + } + } + } + return false; + } + + // internals + public unsafe void AddUnoInterface(IntPtr unoInterface, InterfaceTypeDescription *TD) + { + lock (this) + { + foreach (UnoInterfaceInfo info in interfaces) + { + if (InterfaceTypeDescription.Equal(info.TypeDesc, TD)) + return; + } + // This proxy does not contain the unoInterface. Add it. + bridge.RegisterWithUnoEnvironment(ref unoInterface, + oid, TD); + interfaces.Add(new UnoInterfaceInfo(bridge, unoInterface, TD)); + } + } + + UnoInterfaceInfo FindInfo(Type type) + { + foreach (UnoInterfaceInfo info in interfaces) + { + if (type.IsAssignableFrom(info.Type)) + return info; + } + foreach (UnoInterfaceProxy proxy in additionalProxies) + { + UnoInterfaceInfo info = proxy.FindInfo(type); + if (info != null) + return info; + } + return null; + } + + static Type MapUnoType(TypeDescription *TD) + { + return MapUnoType(TD->pWeakRef); + } + + static Type MapUnoType(TypeDescriptionReference *TD) + { + Type result; + + switch(TD->eTypeClass) + { + case TypeClass.VOID: + result = typeof(void); + break; + case TypeClass.CHAR: + result = typeof(char); + break; + case TypeClass.BOOLEAN: + result = typeof(bool); + break; + case TypeClass.BYTE: + result = typeof(byte); + break; + case TypeClass.SHORT: + result = typeof(short); + break; + case TypeClass.UNSIGNED_SHORT: + result = typeof(ushort); + break; + case TypeClass.LONG: + result = typeof(int); + break; + case TypeClass.UNSIGNED_LONG: + result = typeof(uint); + break; + case TypeClass.HYPER: + result = typeof(long); + break; + case TypeClass.UNSIGNED_HYPER: + result = typeof(ulong); + break; + case TypeClass.FLOAT: + result = typeof(float); + break; + case TypeClass.DOUBLE: + result = typeof(double); + break; + case TypeClass.STRING: + result = typeof(string); + break; + case TypeClass.TYPE: + result = typeof(Type); + break; + case TypeClass.ANY: + result = typeof(uno.Any); + break; + case TypeClass.ENUM: + case TypeClass.STRUCT: + case TypeClass.EXCEPTION: + result = Bridge.LoadCliType(TD->pTypeName); + break; + case TypeClass.INTERFACE: + // special handling for XInterface, since it does not exist in cli. + if (UString.UStringToString(TD->pTypeName) == "com.sun.star.uno.XInterface") + result = typeof(object); + else + result = Bridge.LoadCliType(TD->pTypeName); + break; + case TypeClass.SEQUENCE: + { + // FIXME do something with TD here? + TypeDescriptionReference *elementTDRef = + ((IndirectTypeDescription *)TD)->pType; + switch (elementTDRef->eTypeClass) + { + case TypeClass.CHAR: + result = Type.GetType("System.Char[]"); + break; + case TypeClass.BOOLEAN: + result = Type.GetType("System.Boolean[]"); + break; + case TypeClass.BYTE: + result = Type.GetType("System.Byte[]"); + break; + case TypeClass.SHORT: + result = Type.GetType("System.Int16[]"); + break; + case TypeClass.UNSIGNED_SHORT: + result = Type.GetType("System.UInt16[]"); + break; + case TypeClass.LONG: + result = Type.GetType("System.Int32[]"); + break; + case TypeClass.UNSIGNED_LONG: + result = Type.GetType("System.UInt32[]"); + break; + case TypeClass.HYPER: + result = Type.GetType("System.Int64[]"); + break; + case TypeClass.UNSIGNED_HYPER: + result = Type.GetType("System.UInt64[]"); + break; + case TypeClass.FLOAT: + result = Type.GetType("System.Single[]"); + break; + case TypeClass.DOUBLE: + result = Type.GetType("System.Double[]"); + break; + case TypeClass.STRING: + result = Type.GetType("System.String[]"); + break; + case TypeClass.TYPE: + result = Type.GetType("System.Type[]"); + break; + case TypeClass.ANY: + case TypeClass.ENUM: + case TypeClass.EXCEPTION: + case TypeClass.STRUCT: + case TypeClass.INTERFACE: + case TypeClass.SEQUENCE: + result = Bridge.LoadCliType(TD->pTypeName); + break; + default: + // FIXME can't happen + result = null; + break; + } + break; + } + default: + // FIXME can't happen + result = null; + break; + } + return result; + } + + IMessage InvokeObjectMethod(IMessage request) + { + IMethodMessage methodmsg = (IMethodMessage)request; + object ret; + switch (methodmsg.MethodName) + { + case "Equals": + ret = false; + + if (RemotingServices.IsTransparentProxy(methodmsg.Args[0])) + { + UnoInterfaceProxy unoProxy = + RemotingServices.GetRealProxy(methodmsg.Args[0]) as UnoInterfaceProxy; + + if (unoProxy != null) + { + ret = oid.Equals(unoProxy.Oid); + break; + } + } + break; + case "GetHashCode": + ret = oid.GetHashCode(); + break; + case "GetType": + ret = typeof(System.Object); + break; + case "ToString": + ret = String.Format("Uno object proxy. OID: {0}", oid); + break; + default: + // Cannot happen + ret = null; + break; + } + + return new ReturnMessage(ret, new object[0], 0, + methodmsg.LogicalCallContext, + (IMethodCallMessage)methodmsg); + } + + public string Oid { + get { return oid; } + } + + IMessage ConstructReturnMessage(uno.Any result, object[] args, + InterfaceMethodTypeDescription *methodTD, + IMethodCallMessage callmsg, uno.Any exception) + { + if (exception.hasValue()) + { + throw (System.Exception)exception.Value; + } + else + { + if (args != null) + { + object[] outArgs = new object[methodTD->nParams]; + int numOutArgs = 0; + for (int i = 0; i < methodTD->nParams; ++i) + { + if (methodTD->pParams[i].bOut == 1) + { + outArgs[i] = args[i]; + ++numOutArgs; + } + } + return new ReturnMessage(result.Value, outArgs, numOutArgs, + callmsg.LogicalCallContext, + callmsg); + } + else + { + return new ReturnMessage(result.Value, null, 0, + callmsg.LogicalCallContext, + callmsg); + } + } + } +} + +} |