diff options
Diffstat (limited to 'cli_ure/source')
46 files changed, 11628 insertions, 0 deletions
diff --git a/cli_ure/source/basetypes/assembly.cs b/cli_ure/source/basetypes/assembly.cs new file mode 100644 index 000000000000..13acf48b59a7 --- /dev/null +++ b/cli_ure/source/basetypes/assembly.cs @@ -0,0 +1,2 @@ +[assembly:System.Reflection.AssemblyDescription( "CLI-UNO: Language Binding specific types" )] +[assembly:System.Reflection.AssemblyCompany( "OpenOffice.org" )] diff --git a/cli_ure/source/basetypes/cli_basetypes_config b/cli_ure/source/basetypes/cli_basetypes_config new file mode 100644 index 000000000000..44ef6060061f --- /dev/null +++ b/cli_ure/source/basetypes/cli_basetypes_config @@ -0,0 +1,11 @@ +<?xml version="1.0"?> +<configuration> + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="cli_basetypes" publicKeyToken="ce2cb7e279207b9e"/> + <bindingRedirect oldVersion="CLI_BASETYPES_OLD_VERSION" newVersion="CLI_BASETYPES_NEW_VERSION" /> + </dependentAssembly> + </assemblyBinding> + </runtime> +</configuration>
\ No newline at end of file diff --git a/cli_ure/source/basetypes/makefile.mk b/cli_ure/source/basetypes/makefile.mk new file mode 100644 index 000000000000..5547c32de0df --- /dev/null +++ b/cli_ure/source/basetypes/makefile.mk @@ -0,0 +1,105 @@ +#************************************************************************* +# +# 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 = cli_ure + +# for dummy +TARGET = basetypes + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +.INCLUDE : $(PRJ)$/util$/target.pmk +.INCLUDE : target.mk + +.IF "$(BUILD_FOR_CLI)" != "" + +.INCLUDE : $(BIN)$/cliureversion.mk + +ASSEMBLY_ATTRIBUTES = $(MISC)$/assembly_ure_$(TARGET).cs +POLICY_ASSEMBLY_FILE=$(BIN)$/$(CLI_BASETYPES_POLICY_ASSEMBLY).dll + +ALLTAR : \ + $(BIN)$/cli_basetypes.dll \ + $(POLICY_ASSEMBLY_FILE) + +.IF "$(CCNUMVER)" >= "001399999999" +CSCFLAGS+=-keyfile:"$(BIN)$/cliuno.snk" +.ENDIF + +CSFILES = \ + uno$/Any.cs \ + uno$/BoundAttribute.cs \ + uno$/ExceptionAttribute.cs \ + uno$/ParameterizedTypeAttribute.cs \ + uno$/TypeParametersAttribute.cs \ + uno$/TypeArgumentsAttribute.cs \ + uno$/OnewayAttribute.cs \ + uno$/PolymorphicType.cs \ + $(ASSEMBLY_ATTRIBUTES) + +.IF "$(CCNUMVER)" <= "001399999999" +$(ASSEMBLY_ATTRIBUTES) : assembly.cs makefile.mk $(BIN)$/cliuno.snk $(BIN)$/cliureversion.mk + $(GNUCOPY) -p assembly.cs $@ + echo \ + '[assembly:System.Reflection.AssemblyVersion( "$(CLI_BASETYPES_NEW_VERSION)")] \ + [assembly:System.Reflection.AssemblyKeyFile(@"$(BIN)$/cliuno.snk")]' \ + >> $@ +.ELSE +$(ASSEMBLY_ATTRIBUTES) : assembly.cs makefile.mk $(BIN)$/cliuno.snk $(BIN)$/cliureversion.mk + $(GNUCOPY) -p assembly.cs $@ + echo \ + '[assembly:System.Reflection.AssemblyVersion( "$(CLI_BASETYPES_NEW_VERSION)")]' \ + >> $@ +.ENDIF + +$(BIN)$/cli_basetypes.dll : $(CSFILES) $(BIN)$/cliureversion.mk + $(CSC) $(CSCFLAGS) \ + -target:library \ + -out:$@ \ + -reference:System.dll \ + $(CSFILES) + @echo "If code has changed then provide a policy assembly and change the version!" + +#do not forget to deliver cli_uretypes.config. It is NOT embedded in the policy file. +$(POLICY_ASSEMBLY_FILE) : $(BIN)$/cli_basetypes.config + $(WRAPCMD) AL.exe -out:$@ \ + -version:$(CLI_BASETYPES_POLICY_VERSION) \ + -keyfile:$(BIN)$/cliuno.snk \ + -link:$(BIN)$/cli_basetypes.config + + +#Create the config file that is used with the policy assembly +$(BIN)$/cli_basetypes.config: cli_basetypes_config $(BIN)$/cliureversion.mk + $(PERL) $(SOLARENV)$/bin$/clipatchconfig.pl \ + $< $@ + + +.ENDIF + + diff --git a/cli_ure/source/basetypes/uno/Any.cs b/cli_ure/source/basetypes/uno/Any.cs new file mode 100644 index 000000000000..69ba69c2754e --- /dev/null +++ b/cli_ure/source/basetypes/uno/Any.cs @@ -0,0 +1,211 @@ +/************************************************************************* + * + * 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.Text; + +namespace uno +{ + +/** This class can be used as a base class for UNO objects. + It implements the capability to be kept weakly + (unoidl.com.sun.star.uno.XWeak) and it implements + unoidl.com.sun.star.lang.XTypeProvider which is necessary for + using the object from StarBasic. +*/ +public struct Any +{ + private object _value; + private Type _type; + + public static Any VOID = new Any(typeof(void), null); + + private static void checkArgs(Type type, Object value) + { + //value can only be null if type == void + if (type == null + || (value == null + && type != typeof(void) + && type != typeof(object) + && type.IsInterface == false)) + throw new System.Exception( + "uno.Any: Constructor called with illegal arguments!"); + //If value is a polymorphic struct then type must be + //uno.Polymorphic + if (value != null) + { + TypeParametersAttribute t = (TypeParametersAttribute) Attribute.GetCustomAttribute( + value.GetType(), typeof(TypeParametersAttribute)); + if (t != null && !(type is PolymorphicType)) + throw new System.Exception( + "uno.Any: The value has a polymorphic type but the type argument is not " + + "uno.PolymorphicType. Please use the constructor Any(Type, object) and " + + "supply a uno.PolymorphicType as type argument!"); + } + } + + /** constructs an instance. + + <p>If the arguments ar invalid then an exception is thrown.</p> + @exception System.Exception + */ + public Any(Type type, object value) + { + checkArgs(type, value); + _type = type; + _value = value; + } + + /** sets the type and value. + <p>If the arguments ar invalid then an exception is thrown.</p> + @exception System.Exception + */ + public void setValue(Type type, object value) + { + checkArgs(type, value); + _type = type; + _value = value; + } + + public Type Type + { + get + { + if (_type == null) + _type = typeof(void); + return _type; + } + } + + public Object Value + { + get + { + return _value; + } + } + + public Any(char value): this(typeof(char), value) + { + } + + public Any(bool value): this(typeof(bool), value) + { + } + + public Any(byte value): this(typeof(byte), value) + { + } + + public Any(short value): this(typeof(short), value) + { + } + + public Any(ushort value): this(typeof(ushort), value) + { + } + + public Any(int value): this(typeof(int), value) + { + } + + public Any(uint value): this(typeof(uint), value) + { + } + + public Any(long value): this(typeof(long), value) + { + } + + public Any(ulong value): this(typeof(ulong), value) + { + } + + public Any(float value): this(typeof(float), value) + { + } + + public Any(double value): this(typeof(double), value) + { + } + + public Any(Type value): this(typeof(Type), value) + { + } + + public Any(string value): this(typeof(string), value) + { + } + + public override string ToString() + { + StringBuilder msg = new StringBuilder("uno.Any { Type= "); + msg.Append(Type.ToString()); + msg.Append(", Value="); + msg.Append(Value.ToString()); + msg.Append("}"); + return msg.ToString(); + } + + public bool hasValue() + { + if (Type == null || Type == typeof(void)) + return false; + return true; + } + + public override bool Equals(object obj) + { + if (obj != null) + { + try + { + return Equals((Any) obj); + } + catch (InvalidCastException) + { + } + } + return false; + } + + public bool Equals(Any obj) + { + return Type.Equals(obj.Type) + && (Value == null ? + obj.Value == null : + Value.Equals(obj.Value)); + } + + public override int GetHashCode() + { + return Type.GetHashCode() ^ (Value != null ? Value.GetHashCode() : 0); + } +} + +} + diff --git a/cli_ure/source/basetypes/uno/BoundAttribute.cs b/cli_ure/source/basetypes/uno/BoundAttribute.cs new file mode 100644 index 000000000000..145e41a05439 --- /dev/null +++ b/cli_ure/source/basetypes/uno/BoundAttribute.cs @@ -0,0 +1,46 @@ +/************************************************************************* + * + * 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; + + +namespace uno +{ +/** is used to mark UNO interface attributes as "bound". + + <p>It corresponds to <const + scope="com::sun::star::beans">PropertyAttribute::BOUND</const>. + </p> + UNO interface attributes are mapped to CLI properties. + */ +[AttributeUsage(AttributeTargets.Property, Inherited=false)] +public sealed class BoundAttribute: System.Attribute +{ +} + +} + diff --git a/cli_ure/source/basetypes/uno/ExceptionAttribute.cs b/cli_ure/source/basetypes/uno/ExceptionAttribute.cs new file mode 100644 index 000000000000..4370477f943b --- /dev/null +++ b/cli_ure/source/basetypes/uno/ExceptionAttribute.cs @@ -0,0 +1,70 @@ +/************************************************************************* + * + * 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; + + +namespace uno +{ +/** is used to mark a UNO method to throw exceptions. + + <p>A method can be an ordinary interface method, a get or set method from + an interface attribute, or the constructor methods of service creator + classes. If there are no exceptions specified for a method then this + attribute should not be applied. Because a + <type scope="com.sun.star.uno">RuntimeException</type> + can always be thrown it is not specified. Hence no + <code>ExceptionAttribute</code> + should be applied in that case.</p> + */ +[AttributeUsage(AttributeTargets.Method, Inherited=false)] +public sealed class ExceptionAttribute: System.Attribute +{ + /** initializes an instance with the specified values. + + @param raises + array of types of Exceptions which are declared in UNOIDL. + It must not be null. + */ + public ExceptionAttribute(Type[] raises) + { + m_raises = raises; + } + + public Type[] Raises + { + get + { + return m_raises; + } + } + + private Type[] m_raises; +} + +} + diff --git a/cli_ure/source/basetypes/uno/OnewayAttribute.cs b/cli_ure/source/basetypes/uno/OnewayAttribute.cs new file mode 100644 index 000000000000..8873ac42ce38 --- /dev/null +++ b/cli_ure/source/basetypes/uno/OnewayAttribute.cs @@ -0,0 +1,43 @@ +/************************************************************************* + * + * 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; + + +namespace uno +{ +/** is used to mark UNO interface methods as being one - way according to the + UNOIDL <code>oneway<code> attribute. + <p> + */ +[AttributeUsage(AttributeTargets.Method, Inherited=false)] +public sealed class OnewayAttribute: System.Attribute +{ + +} +} + diff --git a/cli_ure/source/basetypes/uno/ParameterizedTypeAttribute.cs b/cli_ure/source/basetypes/uno/ParameterizedTypeAttribute.cs new file mode 100644 index 000000000000..056dc6eea13b --- /dev/null +++ b/cli_ure/source/basetypes/uno/ParameterizedTypeAttribute.cs @@ -0,0 +1,68 @@ +/************************************************************************* + * + * 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; + + +namespace uno +{ +/** is used to mark a UNO entity to have a parameterized type. + + <p>Currently it is only applied to members of polymorphic structs. That is structs, + which have a type parameter list. + </p> + + @see TypeParametersAttribute + */ +[AttributeUsage(AttributeTargets.Field, Inherited=false)] +public sealed class ParameterizedTypeAttribute: System.Attribute +{ + /** initializes an instance with the specified value. + + @param parameter + the name of parameter from the parameter list from + <type scope="uno.idl">TypeParametersAttribute</type> + It must not be null. + */ + public ParameterizedTypeAttribute(string parameter) + { + m_parameter = parameter; + } + + public string Type + { + get + { + return m_parameter; + } + } + + private string m_parameter; +} + +} + diff --git a/cli_ure/source/basetypes/uno/PolymorphicType.cs b/cli_ure/source/basetypes/uno/PolymorphicType.cs new file mode 100644 index 000000000000..3a299bef3bdd --- /dev/null +++ b/cli_ure/source/basetypes/uno/PolymorphicType.cs @@ -0,0 +1,443 @@ +/************************************************************************* + * + * 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.Reflection; +using System.Globalization; + +namespace uno { + + + +/** represents a polymorphic type. + + This class is used to carry type information for polymorphic struct types + and arrays of polymorphic struct types. These types would be easiest represented + with type templates, which are not available in .NET 1.1. Therefore + the System.Type cannot contain information about template parameters. To + retain this information we use PolymorphicType which directly inherits from + System.Type. The additional information about type parameters are passed + as simple string when creating an instance of PolymorphicType. Usually one + only needs a PolymorphicType when a polymporphic type is put into an + uno.Any. For example, let's assume there is a idl type PolyStruct: + + module test { + struct PolyStruct< T > + { + T member; + }; + }; + + Then one would use it in C# in this way: + + uno.Any myAny = new uno.Any( PolymorphicType.GetType( + typeof(PolyStruct), "unoidl.test.PolyStruct<System.Boolean>"), + new PolyStruct(true)); + + or if one has a sequence of polymorphic structs: + + uno.Any myAny = new uno.Any( PolymorphicType.GetType( + typeof(PolyStruct), "unoidl.test.PolyStruct<System.Boolean>[]"), + new PolyStruct[] {new PolyStruct(true)} ); + + + To get a new instance of PolymorphicType one uses the static method + PolymorphicType.GetType. The method ensures that there is only one instance + for each distinct name. For example, if GetType is called multiple times with + the name "unoidl.test.PolyStruct<System.Boolean>" then the same instance of + PolymorphicType is returned. This makes it possible to compare the instances + by reference, thas is using the operator "==". + + The polymorphic name, which is passed as second argument to PolymorphicType.GetType, + contains a list of type names. Only type names common + to all CLI languages can be used. That is, instead of using names, such as + char, int, float, the names System.Char, System.Int32 and + System.Single are to be used. Spaces are not allowed. + The name will always start with "unoidl", when the type was generated by climaker. + Here are a couple of possible strings: + + unoidl.test.PolyStruct<System.Int32> + unoidl.test.PolyStruct<System.Char[]> + unoidl.test.PolyStruct<System.Int64>[] + unoidl.test.PolyStruct<unoidl.test.PolyStruct<System.Int64>> + unoidl.test.PolyStruct<unoidl.test.PolyStruct<System.Int64[]>[]>[] + + In the future, when the CLI supports templates, we will probably adapt the cli-uno + bridge accordingly to use real template types. Then this class will become obsolete. + */ +public class PolymorphicType: Type +{ + private Type m_base; + private string m_type_name; + + private static Hashtable m_ht_types = Hashtable.Synchronized(new Hashtable(256)); + + /** provides a unique instance of this class. + + This function returns null if the specified type is no polymorphic struct. + + @param type + the type of the polymorphic struct. For example, created by + <code>typeof(unoidl.com.sun.star.beans.Defaulted)</code> + @param name + the full name of the struct (including the type list). + @return + null - the argument type is no valid polymorphic struct or <br> + an instance of this class. + @exception System.ArgumentNullException + The argument was null. + */ + public static PolymorphicType GetType(Type type, string name) + { + if (name == null || type == null) + throw new ArgumentNullException( + "cli-uno: uno.PolymorphicType.GetType was called with a null argument"); + //check if the type is either a array of structs or a polymorphic struct. + if (type.IsArray) + { + Type elementType = type; + while ((elementType = elementType.GetElementType()).IsArray); + //unfortunately we cannot check if it is a real polymorphic struct here. + if ( ! elementType.IsClass) + return null; + + + } + else if (Attribute.GetCustomAttribute(type, typeof(uno.TypeParametersAttribute)) + == null) + { + return null; + } + + lock (m_ht_types.SyncRoot) + { + PolymorphicType t = (PolymorphicType) m_ht_types[name]; + if (t == null) + { + t = new PolymorphicType(type, name); + m_ht_types.Add(name, t); + } + return t; + } + } + + private PolymorphicType(Type type, string name) + { + m_type_name = name; + m_base = type; + } + + public string PolymorphicName + { + get + { + return m_type_name; + } + } + + public Type OriginalType + { + get + { + return m_base; + } + } + + + //implementations of abstract methods and properties from base class + public override string Name + { + get + { + return m_base.Name; + } + } + + public override Assembly Assembly + { + get + { + return m_base.Assembly; + } + } + + public override string AssemblyQualifiedName + { + get + { + return m_base.AssemblyQualifiedName; + } + } + + public override Type BaseType + { + get + { + return m_base.BaseType; + } + } + + public override string FullName + { + get + { + return m_base.FullName; + } + } + + public override Guid GUID + { + get + { + return m_base.GUID; + } + } + + public override Module Module + { + get + { + return m_base.Module; + } + } + + public override string Namespace + { + get + { + return m_base.Namespace; + } + } + + public override RuntimeTypeHandle TypeHandle + { + get + { + return m_base.TypeHandle; + } + } + + public override Type UnderlyingSystemType + { + get + { + return m_base.UnderlyingSystemType; + } + } + + public override Type DeclaringType + { + get + { + return m_base.DeclaringType; + } + } + + public override object[] GetCustomAttributes( + bool inherit) + { + return m_base.GetCustomAttributes(inherit); + } + + public override object[] GetCustomAttributes( + Type attributeType, + bool inherit) + { + return m_base.GetCustomAttributes(attributeType, inherit); + } + + public override bool IsDefined( + Type attributeType, + bool inherit) + { + return IsDefined(attributeType, inherit); + } + + protected override TypeAttributes GetAttributeFlagsImpl() + { + return m_base.Attributes; + } + + protected override ConstructorInfo GetConstructorImpl( + BindingFlags bindingAttr, + Binder binder, + CallingConventions callConvention, + Type[] types, + ParameterModifier[] modifiers) + { + return m_base.GetConstructor( + bindingAttr, binder, callConvention, types, modifiers); + } + + public override ConstructorInfo[] GetConstructors( + BindingFlags bindingAttr) + { + return m_base.GetConstructors(bindingAttr); + } + + public override Type GetElementType() + { + return m_base.GetElementType(); + } + + public override EventInfo GetEvent( + string name, + BindingFlags bindingAttr) + { + return m_base.GetEvent(name, bindingAttr); + } + + public override EventInfo[] GetEvents( + BindingFlags bindingAttr) + { + return m_base.GetEvents(bindingAttr); + } + + public override FieldInfo GetField( + string name, + BindingFlags bindingAttr) + { + return m_base.GetField(name, bindingAttr); + } + + public override FieldInfo[] GetFields( + BindingFlags bindingAttr) + { + return m_base.GetFields(bindingAttr); + } + + public override Type GetInterface( + string name, bool ignoreCase) + { + return m_base.GetInterface(name, ignoreCase); + } + + public override Type[] GetInterfaces() + { + return m_base.GetInterfaces(); + } + + public override MemberInfo[] GetMembers( + BindingFlags bindingAttr) + { + return m_base.GetMembers(bindingAttr); + } + + protected override MethodInfo GetMethodImpl( + string name, + BindingFlags bindingAttr, + Binder binder, + CallingConventions callConvention, + Type[] types, + ParameterModifier[] modifiers) + { + return m_base.GetMethod( + name, bindingAttr, binder, callConvention, types, modifiers); + } + + public override MethodInfo[] GetMethods( + BindingFlags bindingAttr) + { + return m_base.GetMethods(bindingAttr); + } + + public override Type GetNestedType( + string name, BindingFlags bindingAttr) + { + return m_base.GetNestedType(name, bindingAttr); + } + + public override Type[] GetNestedTypes( + BindingFlags bindingAttr) + { + return m_base.GetNestedTypes(bindingAttr); + } + + public override PropertyInfo[] GetProperties( + BindingFlags bindingAttr) + { + return m_base.GetProperties(bindingAttr); + } + + protected override PropertyInfo GetPropertyImpl( + string name, + BindingFlags bindingAttr, + Binder binder, + Type returnType, + Type[] types, + ParameterModifier[] modifiers) + { + return m_base.GetProperty( + name, bindingAttr, binder, returnType, types, modifiers); + } + + protected override bool HasElementTypeImpl() + { + return m_base.HasElementType; + } + + public override object InvokeMember( + string name, + BindingFlags invokeAttr, + Binder binder, + object target, + object[] args, + ParameterModifier[] modifiers, + CultureInfo culture, + string[] namedParameters) + { + return m_base.InvokeMember( + name, invokeAttr, binder, target, args, modifiers, culture, namedParameters); + } + + protected override bool IsArrayImpl() + { + return m_base.IsArray; + } + + protected override bool IsByRefImpl() + { + return m_base.IsByRef; + } + + protected override bool IsCOMObjectImpl() + { + return m_base.IsCOMObject; + } + + protected override bool IsPointerImpl() + { + return m_base.IsPointer; + } + + protected override bool IsPrimitiveImpl() + { + return m_base.IsPrimitive; + } +} +} diff --git a/cli_ure/source/basetypes/uno/TypeArgumentsAttribute.cs b/cli_ure/source/basetypes/uno/TypeArgumentsAttribute.cs new file mode 100644 index 000000000000..79c3745a161a --- /dev/null +++ b/cli_ure/source/basetypes/uno/TypeArgumentsAttribute.cs @@ -0,0 +1,84 @@ +/************************************************************************* + * + * 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; + + +namespace uno +{ +/** is used to mark a parameterized UNO entity(i.e. struct) + to be an instantiation of a + template with the specified type arguments. + + <p>Currently only UNO structs can have type parameters.</p> + + <pre> + + [TypeParameters(new string[]{"T"})] + struct Foo { + [ParameterizedType("T")] + Object member; + } + + public interface XFoo { + [return:TypeArguments(new string[]{typeof(char)})] + Foo func( [TypeArguments(new string[]{typeof(char)})] Foo f); + } + </pre> + + @see TypeParametersAttribute + @see ParameterizedTypeAttribute + */ +[AttributeUsage(AttributeTargets.ReturnValue + | AttributeTargets.Parameter + | AttributeTargets.Field, Inherited=false)] +public sealed class TypeArgumentsAttribute: System.Attribute +{ + /** initializes an instance with the specified value. + + @param parameters + arrayay of names representing the types. + It must not be null. + */ + public TypeArgumentsAttribute(Type[] arguments) + { + m_arguments = arguments; + } + + public Type[] Arguments + { + get + { + return m_arguments; + } + } + + private Type[] m_arguments; +} + +} + diff --git a/cli_ure/source/basetypes/uno/TypeParametersAttribute.cs b/cli_ure/source/basetypes/uno/TypeParametersAttribute.cs new file mode 100644 index 000000000000..273f59393c5f --- /dev/null +++ b/cli_ure/source/basetypes/uno/TypeParametersAttribute.cs @@ -0,0 +1,65 @@ +/************************************************************************* + * + * 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; + + +namespace uno +{ +/** is used to mark a UNO entity to have type parameters. + + <p>Currently it is only applied with polymorphic structs. That is structs, + which have a type parameter list. + </p> + */ +[AttributeUsage(AttributeTargets.Class, Inherited=false)] +public sealed class TypeParametersAttribute: System.Attribute +{ + /** initializes an instance with the specified value. + + @param parameters + array of names representing the types. + It must not be null. + */ + public TypeParametersAttribute(string[] parameters) + { + m_parameters = parameters; + } + + public string[] Parameters + { + get + { + return m_parameters; + } + } + + private string[] m_parameters; +} + +} + diff --git a/cli_ure/source/climaker/climaker.exe.config b/cli_ure/source/climaker/climaker.exe.config new file mode 100644 index 000000000000..5ff03513900c --- /dev/null +++ b/cli_ure/source/climaker/climaker.exe.config @@ -0,0 +1,10 @@ +<?xml version="1.0"?>
+<configuration>
+ <runtime>
+ <gcConcurrent enabled="true" />
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <publisherPolicy apply="no" />
+ <probing privatePath="" />
+ </assemblyBinding>
+ </runtime>
+</configuration>
\ No newline at end of file diff --git a/cli_ure/source/climaker/climaker_app.cxx b/cli_ure/source/climaker/climaker_app.cxx new file mode 100644 index 000000000000..9c257d079682 --- /dev/null +++ b/cli_ure/source/climaker/climaker_app.cxx @@ -0,0 +1,749 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" + +#include <stdio.h> +#include <vector> +#include <memory> + +#include "climaker_share.h" + +#include "sal/main.h" +#include "osl/process.h" +#include "osl/file.hxx" +#include "osl/thread.h" +#include "rtl/ustrbuf.hxx" +#include "cppuhelper/shlib.hxx" +#include "cppuhelper/bootstrap.hxx" +#include "com/sun/star/lang/XInitialization.hpp" +#include "com/sun/star/lang/XSingleComponentFactory.hpp" +#include "com/sun/star/lang/XComponent.hpp" +#include "com/sun/star/container/XHierarchicalNameAccess.hpp" +#include "com/sun/star/container/XSet.hpp" +#include "com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp" +#include "com/sun/star/registry/XSimpleRegistry.hpp" + +using namespace ::std; +using namespace ::System::Reflection; + + +using namespace ::rtl; +using namespace ::osl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace climaker +{ + +//------------------------------------------------------------------------------ +static char const s_usingText [] = +"\n" +"using: climaker <switches> [registry-file-1 registry-file-2 ...]\n" +"\n" +"switches:\n" +" -O, --out <output-file> output assembly file;\n" +" defaults to cli_unotypes.dll if more than one\n" +" registry-file is given, else <registry-file>.dll\n" +" -T, --types types to be generated (if none is given,\n" +" <type1[;type2;...]> then all types of given registries are emitted\n" +" -X, --extra <rdb-file> additional rdb to saturate referenced types in\n" +" given registry file(s); these types will not be\n" +" emitted into the output assembly file\n" +" -r, --reference reference metadata from assembly file\n" +" <assembly-file>\n" +" -k, --keyfile keyfile needed for strong name\n" +" --assembly-version <version> sets assembly version\n" +" --assembly-description <text> sets assembly description text\n" +" --assembly-product <text> sets assembly product name\n" +" --assembly-company <text> sets assembly company\n" +" --assembly-copyright <text> sets assembly copyright\n" +" --assembly-trademark <text> sets assembly trademark\n" +" -v, --verbose verbose output to stdout\n" +" -h, --help this message\n" +"\n" +"example: climaker --out cli_mytypes.dll \\\n" +" --reference cli_uretypes.dll \\\n" +" --extra types.rdb \\\n" +" mytypes.rdb\n" +"\n"; + +struct OptionInfo +{ + char const * m_name; + sal_uInt32 m_name_length; + sal_Unicode m_short_option; + bool m_has_argument; +}; + +bool g_verbose = false; + +//------------------------------------------------------------------------------ +static const OptionInfo s_option_infos [] = { + { RTL_CONSTASCII_STRINGPARAM("out"), 'O', true }, + { RTL_CONSTASCII_STRINGPARAM("types"), 'T', true }, + { RTL_CONSTASCII_STRINGPARAM("extra"), 'X', true }, + { RTL_CONSTASCII_STRINGPARAM("reference"), 'r', true }, + { RTL_CONSTASCII_STRINGPARAM("keyfile"), 'k', true }, + { RTL_CONSTASCII_STRINGPARAM("delaySign"), 'd', true }, + { RTL_CONSTASCII_STRINGPARAM("assembly-version"), '\0', true }, + { RTL_CONSTASCII_STRINGPARAM("assembly-description"), '\0', true }, + { RTL_CONSTASCII_STRINGPARAM("assembly-product"), '\0', true }, + { RTL_CONSTASCII_STRINGPARAM("assembly-company"), '\0', true }, + { RTL_CONSTASCII_STRINGPARAM("assembly-copyright"), '\0', true }, + { RTL_CONSTASCII_STRINGPARAM("assembly-trademark"), '\0', true }, + { RTL_CONSTASCII_STRINGPARAM("verbose"), 'v', false }, + { RTL_CONSTASCII_STRINGPARAM("help"), 'h', false } +}; + +//============================================================================== +static OptionInfo const * get_option_info( + OUString const & opt, sal_Unicode copt = '\0' ) +{ + for ( sal_Int32 pos = 0; + pos < (sizeof (s_option_infos) / sizeof (OptionInfo)); + ++pos ) + { + OptionInfo const & option_info = s_option_infos[ pos ]; + + if (opt.getLength() > 0) + { + if (opt.equalsAsciiL( + option_info.m_name, option_info.m_name_length ) && + (copt == '\0' || copt == option_info.m_short_option)) + { + return &option_info; + } + } + else + { + OSL_ASSERT( copt != '\0' ); + if (copt == option_info.m_short_option) + { + return &option_info; + } + } + } + OSL_ENSURE( + 0, OUStringToOString( opt, osl_getThreadTextEncoding() ).getStr() ); + return 0; +} + +//============================================================================== +static bool is_option( + OptionInfo const * option_info, sal_uInt32 * pIndex ) +{ + OSL_ASSERT( option_info != 0 ); + if (osl_getCommandArgCount() <= *pIndex) + return false; + + OUString arg; + osl_getCommandArg( *pIndex, &arg.pData ); + sal_Int32 len = arg.getLength(); + + if (len < 2 || arg[ 0 ] != '-') + return false; + + if (len == 2 && arg[ 1 ] == option_info->m_short_option) + { + ++(*pIndex); +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( + __FILE__": identified option \'%c\'", option_info->m_short_option ); +#endif + return true; + } + if (arg[ 1 ] == '-' && rtl_ustr_ascii_compare( + arg.pData->buffer + 2, option_info->m_name ) == 0) + { + ++(*pIndex); +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( __FILE__": identified option \'%s\'", option_info->m_name ); +#endif + return true; + } + return false; +} + +//============================================================================== +static inline bool read_option( + bool * flag, OptionInfo const * option_info, sal_uInt32 * pIndex ) +{ + bool ret = is_option( option_info, pIndex ); + if (ret) + *flag = true; + return ret; +} + +//============================================================================== +static bool read_argument( + OUString * pValue, OptionInfo const * option_info, sal_uInt32 * pIndex ) +{ + if (is_option( option_info, pIndex )) + { + if (*pIndex < osl_getCommandArgCount()) + { + osl_getCommandArg( *pIndex, &pValue->pData ); + ++(*pIndex); +#if OSL_DEBUG_LEVEL > 1 + OString cstr_val( + OUStringToOString( *pValue, osl_getThreadTextEncoding() ) ); + OSL_TRACE( __FILE__": argument value: %s\n", cstr_val.getStr() ); +#endif + return true; + } + --(*pIndex); + } + return false; +} + +//============================================================================== +static OUString const & path_get_working_dir() +{ + static OUString s_workingDir; + if (! s_workingDir.getLength()) + osl_getProcessWorkingDir( &s_workingDir.pData ); + return s_workingDir; +} + +//============================================================================== +static OUString path_make_absolute_file_url( OUString const & path ) +{ + OUString file_url; + oslFileError rc = osl_getFileURLFromSystemPath( + path.pData, &file_url.pData ); + if (osl_File_E_None == rc) + { + OUString abs; + rc = osl_getAbsoluteFileURL( + path_get_working_dir().pData, file_url.pData, &abs.pData ); + if (osl_File_E_None == rc) + { + return abs; + } + else + { + throw RuntimeException( + OUSTR("cannot make absolute: ") + file_url, + Reference< XInterface >() ); + } + } + else + { + throw RuntimeException( + OUSTR("cannot get file url from system path: ") + path, + Reference< XInterface >() ); + } +} + +//============================================================================== +Reference< registry::XSimpleRegistry > open_registries( + vector< OUString > const & registries, + Reference< XComponentContext > xContext ) +{ + if (registries.empty()) + { + throw RuntimeException( + OUSTR("no registries given!"), + Reference< XInterface >() ); + } + + Reference< registry::XSimpleRegistry > xSimReg; + for ( size_t nPos = registries.size(); nPos--; ) + { + Reference< registry::XSimpleRegistry > xReg( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), xContext ), + UNO_QUERY_THROW ); + xReg->open( registries[ nPos ], sal_True, sal_False ); + if (! xReg->isValid()) + { + throw RuntimeException( + OUSTR("invalid registry: ") + registries[ nPos ], + Reference< XInterface >() ); + } + + if (xSimReg.is()) // nest? + { + Reference< registry::XSimpleRegistry > xNested( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.NestedRegistry"), xContext ), + UNO_QUERY_THROW ); + Reference< lang::XInitialization > xInit( + xNested, UNO_QUERY_THROW ); + Sequence< Any > args( 2 ); + args[ 0 ] <<= xReg; + args[ 1 ] <<= xSimReg; + xInit->initialize( args ); + xSimReg = xNested; + } + else + { + xSimReg = xReg; + } + } + + return xSimReg; +} + +} + +using namespace ::climaker; + +//############################################################################## +SAL_IMPLEMENT_MAIN() +{ + sal_uInt32 nCount = osl_getCommandArgCount(); + if (0 == nCount) + { + printf( s_usingText ); + return 0; + } + + int ret = 0; + Reference< XComponentContext > xContext; + + try + { + OptionInfo const * info_help = + get_option_info( OUSTR("help") ); + OptionInfo const * info_verbose = + get_option_info( OUSTR("verbose") ); + OptionInfo const * info_out = + get_option_info( OUSTR("out") ); + OptionInfo const * info_types = + get_option_info( OUSTR("types") ); + OptionInfo const * info_reference = + get_option_info( OUSTR("reference") ); + OptionInfo const * info_extra = + get_option_info( OUSTR("extra") ); + OptionInfo const * info_keyfile = + get_option_info( OUSTR("keyfile") ); + OptionInfo const * info_delaySign = + get_option_info( OUSTR("delaySign") ); + OptionInfo const * info_version = + get_option_info( OUSTR("assembly-version") ); + OptionInfo const * info_product = + get_option_info( OUSTR("assembly-product") ); + OptionInfo const * info_description = + get_option_info( OUSTR("assembly-description") ); + OptionInfo const * info_company = + get_option_info( OUSTR("assembly-company") ); + OptionInfo const * info_copyright = + get_option_info( OUSTR("assembly-copyright") ); + OptionInfo const * info_trademark = + get_option_info( OUSTR("assembly-trademark") ); + + OUString output; + vector< OUString > mandatory_registries; + vector< OUString > extra_registries; + vector< OUString > extra_assemblies; + vector< OUString > explicit_types; + OUString version, product, description, company, copyright, trademark, + keyfile, delaySign; + + OUString cmd_arg; + for ( sal_uInt32 nPos = 0; nPos < nCount; ) + { + // options + if (is_option( info_help, &nPos )) + { + printf( s_usingText ); + return 0; + } + else if (read_argument( &cmd_arg, info_types, &nPos )) + { + sal_Int32 index = 0; + do + { + explicit_types.push_back( + cmd_arg.getToken( 0, ';', index ) ); + } + while (index >= 0); + } + else if (read_argument( &cmd_arg, info_extra, &nPos )) + { + extra_registries.push_back( + path_make_absolute_file_url( cmd_arg ) ); + } + else if (read_argument( &cmd_arg, info_reference, &nPos )) + { + extra_assemblies.push_back( + path_make_absolute_file_url( cmd_arg ) ); + } + else if (!read_option( &g_verbose, info_verbose, &nPos ) && + !read_argument( &output, info_out, &nPos ) && + !read_argument( &version, info_version, &nPos ) && + !read_argument( &description, info_description, &nPos ) && + !read_argument( &product, info_product, &nPos ) && + !read_argument( &company, info_company, &nPos ) && + !read_argument( ©right, info_copyright, &nPos ) && + !read_argument( &trademark, info_trademark, &nPos ) && + !read_argument( &keyfile, info_keyfile, &nPos ) && + !read_argument( &delaySign, info_delaySign, &nPos )) + { + if ( osl_getCommandArg( nPos, &cmd_arg.pData ) != + osl_Process_E_None ) + { + OSL_ASSERT( false ); + } + ++nPos; + cmd_arg = cmd_arg.trim(); + if (cmd_arg.getLength() > 0) + { + if (cmd_arg[ 0 ] == '-') // is option + { + OptionInfo const * option_info = 0; + if (cmd_arg.getLength() > 2 && + cmd_arg[ 1 ] == '-') + { + // long option + option_info = get_option_info( + cmd_arg.copy( 2 ), '\0' ); + } + else if (cmd_arg.getLength() == 2 && + cmd_arg[ 1 ] != '-') + { + // short option + option_info = get_option_info( + OUString(), cmd_arg[ 1 ] ); + } + if (option_info == 0) + { + OUStringBuffer buf; + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("unknown option ") ); + buf.append( cmd_arg ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "! Use climaker --help " + "to print all options.") ); + throw RuntimeException( + buf.makeStringAndClear(), + Reference< XInterface >() ); + } + else + { + OSL_ENSURE( 0, "unhandled valid option?!" ); + if (option_info->m_has_argument) + ++nPos; + } + } + else + { + mandatory_registries.push_back( + path_make_absolute_file_url( cmd_arg ) ); + } + } + } + } + + // bootstrap uno + xContext = ::cppu::bootstrap_InitialComponentContext( + Reference< registry::XSimpleRegistry >() ); + Reference< container::XHierarchicalNameAccess > xTDmgr( + xContext->getValueByName( + OUSTR("/singletons/com.sun.star.reflection." + "theTypeDescriptionManager") ), + UNO_QUERY_THROW ); + + // get rdb tdprovider factory + Reference< lang::XSingleComponentFactory > xTDprov_factory( + ::cppu::loadSharedLibComponentFactory( + OUSTR("bootstrap.uno" SAL_DLLEXTENSION), OUString(), + OUSTR("com.sun.star.comp.stoc.RegistryTypeDescriptionProvider"), + Reference< lang::XMultiServiceFactory >( + xContext->getServiceManager(), UNO_QUERY ), + Reference< registry::XRegistryKey >() ), UNO_QUERY ); + if (! xTDprov_factory.is()) + { + throw RuntimeException( + OUSTR("cannot get registry typedescription provider: " + "bootstrap.uno" SAL_DLLEXTENSION "!"), + Reference< XInterface >() ); + } + + // create registry td provider for mandatory registry files + Any arg( makeAny( open_registries( mandatory_registries, xContext ) ) ); + Reference< XInterface > xTD_provider( + xTDprov_factory->createInstanceWithArgumentsAndContext( + Sequence< Any >( &arg, 1 ), xContext ) ); + // insert provider to tdmgr + Reference< container::XSet > xSet( xTDmgr, UNO_QUERY_THROW ); + Any provider( makeAny( xTD_provider ) ); + xSet->insert( provider ); + OSL_ASSERT( xSet->has( provider ) ); + if (! extra_registries.empty()) + { + arg = makeAny( open_registries( extra_registries, xContext ) ); + provider = makeAny( + xTDprov_factory->createInstanceWithArgumentsAndContext( + Sequence< Any >( &arg, 1 ), xContext ) ); + xSet->insert( provider ); + OSL_ASSERT( xSet->has( provider ) ); + } + + if (0 == output.getLength()) // no output file specified + { + // if only one rdb has been given, then take rdb name + if (1 == mandatory_registries.size()) + { + output = mandatory_registries[ 0 ]; + output = output.copy( output.lastIndexOf( '/' ) +1 ); + sal_Int32 dot = output.lastIndexOf( '.' ); + if (dot > 0) + output = output.copy( 0, dot ); + } + else + { + output = OUSTR("cli_unotypes"); + } + } + output = path_make_absolute_file_url( output ); + sal_Int32 slash = output.lastIndexOf( '/' ); + OUString sys_output_dir; + if (FileBase::E_None != FileBase::getSystemPathFromFileURL( + output.copy( 0, slash ), sys_output_dir )) + { + throw RuntimeException( + OUSTR("cannot get system path from file url ") + + output.copy( 0, slash ), + Reference< XInterface >() ); + } + OUString filename( output.copy( slash +1 ) ); + sal_Int32 dot = filename.lastIndexOf( '.' ); + OUString name( filename ); + if (dot < 0) // has no extension + filename += OUSTR(".dll"); + else + name = name.copy( 0, dot ); + ::System::String * output_dir = ustring_to_String( sys_output_dir ); + ::System::String * output_file = ustring_to_String( filename ); + + //Get the key pair for making a strong name + StrongNameKeyPair* kp = NULL; + if (keyfile.getLength() > 0) + { + ::System::String * sKeyFile = ustring_to_String(keyfile); + try { + System::IO::FileStream* fs = new System::IO::FileStream( + sKeyFile, System::IO::FileMode::Open); + kp = new StrongNameKeyPair(fs); + fs->Close(); + } + catch (System::IO::FileNotFoundException * ) + { + throw Exception(OUSTR("Could not find the keyfile. Verify the --keyfile argument!"), 0); + } + } + else + { + if (g_verbose) + { + ::System::Console::Write( + S"> no key file specified. Cannot create strong name!\n"); + } + } + // setup assembly info: xxx todo set more? e.g. avoid strong versioning + AssemblyName * assembly_name = new AssemblyName(); + assembly_name->set_CodeBase( output_dir ); + assembly_name->set_Name( name ); + if (kp != NULL) + assembly_name->set_KeyPair(kp); + + if (version.getLength() != 0) + { + assembly_name->set_Version( + new ::System::Version( ustring_to_String( version ) ) ); + } + + // app domain + ::System::AppDomain * current_appdomain = + ::System::AppDomain::get_CurrentDomain(); + // target assembly + Emit::AssemblyBuilder * assembly_builder = + current_appdomain->DefineDynamicAssembly( + assembly_name, Emit::AssemblyBuilderAccess::Save, output_dir ); + if (product.getLength() != 0) + { + ::System::Type * params __gc [] = new ::System::Type * __gc [ 1 ]; + ::System::Object * args __gc [] = new ::System::Object * __gc [ 1 ]; + params[ 0 ] = __typeof (::System::String); + args[ 0 ] = ustring_to_String( product ); + assembly_builder->SetCustomAttribute( + new Emit::CustomAttributeBuilder( + __typeof (AssemblyProductAttribute)->GetConstructor( + params ), args ) ); + } + if (description.getLength() != 0) + { + ::System::Type * params __gc [] = new ::System::Type * __gc [ 1 ]; + ::System::Object * args __gc [] = new ::System::Object * __gc [ 1 ]; + params[ 0 ] = __typeof (::System::String); + args[ 0 ] = ustring_to_String( description ); + assembly_builder->SetCustomAttribute( + new Emit::CustomAttributeBuilder( + __typeof (AssemblyDescriptionAttribute)->GetConstructor( + params ), args ) ); + } + if (company.getLength() != 0) + { + ::System::Type * params __gc [] = new ::System::Type * __gc [ 1 ]; + ::System::Object * args __gc [] = new ::System::Object * __gc [ 1 ]; + params[ 0 ] = __typeof (::System::String); + args[ 0 ] = ustring_to_String( company ); + assembly_builder->SetCustomAttribute( + new Emit::CustomAttributeBuilder( + __typeof (AssemblyCompanyAttribute)->GetConstructor( + params ), args ) ); + } + if (copyright.getLength() != 0) + { + ::System::Type * params __gc [] = new ::System::Type * __gc [ 1 ]; + ::System::Object * args __gc [] = new ::System::Object * __gc [ 1 ]; + params[ 0 ] = __typeof (::System::String); + args[ 0 ] = ustring_to_String( copyright ); + assembly_builder->SetCustomAttribute( + new Emit::CustomAttributeBuilder( + __typeof (AssemblyCopyrightAttribute)->GetConstructor( + params ), args ) ); + } + if (trademark.getLength() != 0) + { + ::System::Type * params __gc [] = new ::System::Type * __gc [ 1 ]; + ::System::Object * args __gc [] = new ::System::Object * __gc [ 1 ]; + params[ 0 ] = __typeof (::System::String); + args[ 0 ] = ustring_to_String( trademark ); + assembly_builder->SetCustomAttribute( + new Emit::CustomAttributeBuilder( + __typeof (AssemblyTrademarkAttribute)->GetConstructor( + params ), args ) ); + } + + // load extra assemblies + Assembly * assemblies __gc [] = + new Assembly * __gc [ extra_assemblies.size() ]; + for ( size_t pos = 0; pos < extra_assemblies.size(); ++pos ) + { + assemblies[ pos ] = Assembly::LoadFrom( + ustring_to_String( extra_assemblies[ pos ] ) ); + } + + // type emitter + TypeEmitter * type_emitter = new TypeEmitter( + assembly_builder->DefineDynamicModule( output_file ), assemblies ); + // add handler resolving assembly's types + ::System::ResolveEventHandler * type_resolver = + new ::System::ResolveEventHandler( + type_emitter, &TypeEmitter::type_resolve ); + current_appdomain->add_TypeResolve( type_resolver ); + + // and emit types to it + if (explicit_types.empty()) + { + Reference< reflection::XTypeDescriptionEnumeration > xTD_enum( + Reference< reflection::XTypeDescriptionEnumerationAccess >( + xTD_provider, UNO_QUERY_THROW ) + ->createTypeDescriptionEnumeration( + OUString() /* all IDL modules */, + Sequence< TypeClass >() /* all classes of types */, + reflection::TypeDescriptionSearchDepth_INFINITE ) ); + while (xTD_enum->hasMoreElements()) + { + type_emitter->get_type( xTD_enum->nextTypeDescription() ); + } + } + else + { + Reference< container::XHierarchicalNameAccess > xHNA( + xTD_provider, UNO_QUERY_THROW ); + for ( size_t nPos = explicit_types.size(); nPos--; ) + { + type_emitter->get_type( + Reference< reflection::XTypeDescription >( + xHNA->getByHierarchicalName( explicit_types[ nPos ] ), + UNO_QUERY_THROW ) ); + } + } + type_emitter->Dispose(); + + if (g_verbose) + { + ::System::Console::Write( + S"> saving assembly {0}{1}{2}...", + output_dir, + new ::System::String( + ::System::IO::Path::DirectorySeparatorChar, 1 ), + output_file ); + } + assembly_builder->Save( output_file ); + if (g_verbose) + { + ::System::Console::WriteLine( S"ok." ); + } + current_appdomain->remove_TypeResolve( type_resolver ); + } + catch (Exception & exc) + { + OString msg( + OUStringToOString( exc.Message, osl_getThreadTextEncoding() ) ); + fprintf( + stderr, "\n> error: %s\n> dying abnormally...\n", msg.getStr() ); + ret = 1; + } + catch (::System::Exception * exc) + { + OString msg( OUStringToOString( + String_to_ustring( exc->ToString() ), + osl_getThreadTextEncoding() ) ); + fprintf( + stderr, + "\n> error: .NET exception occured: %s\n> dying abnormally...", + msg.getStr() ); + ret = 1; + } + + try + { + Reference< lang::XComponent > xComp( xContext, UNO_QUERY ); + if (xComp.is()) + xComp->dispose(); + } + catch (Exception & exc) + { + OString msg( + OUStringToOString( exc.Message, osl_getThreadTextEncoding() ) ); + fprintf( + stderr, + "\n> error disposing component context: %s\n" + "> dying abnormally...\n", + msg.getStr() ); + ret = 1; + } + + return ret; +} diff --git a/cli_ure/source/climaker/climaker_emit.cxx b/cli_ure/source/climaker/climaker_emit.cxx new file mode 100644 index 000000000000..24a10ce2ddbb --- /dev/null +++ b/cli_ure/source/climaker/climaker_emit.cxx @@ -0,0 +1,2323 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" + +#include "climaker_share.h" + +#include "rtl/string.hxx" +#include "rtl/ustrbuf.hxx" +#include "com/sun/star/reflection/XIndirectTypeDescription.hpp" +#include "com/sun/star/reflection/XStructTypeDescription.hpp" +#include "com/sun/star/reflection/XInterfaceTypeDescription2.hpp" +#include "com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp" +#include "com/sun/star/reflection/XInterfaceAttributeTypeDescription.hpp" +#include "com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp" +#include <vector> + +using namespace ::System::Reflection; + +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace climaker +{ +System::String* mapUnoPolymorphicName(System::String* unoName); +//------------------------------------------------------------------------------ +static inline ::System::String * to_cts_name( + OUString const & uno_name ) +{ + OUStringBuffer buf( 7 + uno_name.getLength() ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("unoidl.") ); + buf.append( uno_name ); + return ustring_to_String( buf.makeStringAndClear() ); +} + +//------------------------------------------------------------------------------ +static inline ::System::Object * to_cli_constant( Any const & value ) +{ + switch (value.getValueTypeClass()) + { + case TypeClass_CHAR: + return __box + ((::System::Char) *reinterpret_cast< sal_Unicode const * >( + value.getValue() )); + case TypeClass_BOOLEAN: + return __box + ((::System::Boolean) + sal_False != *reinterpret_cast< sal_Bool const * >( + value.getValue() )); + case TypeClass_BYTE: + return __box + ((::System::Byte) *reinterpret_cast< sal_Int8 const * >( + value.getValue() )); + case TypeClass_SHORT: + return __box + ((::System::Int16) *reinterpret_cast< sal_Int16 const * >( + value.getValue() )); + case TypeClass_UNSIGNED_SHORT: + return __box + ((::System::UInt16) *reinterpret_cast< sal_uInt16 const * >( + value.getValue() )); + case TypeClass_LONG: + return __box + ((::System::Int32) *reinterpret_cast< sal_Int32 const * >( + value.getValue() )); + case TypeClass_UNSIGNED_LONG: + return __box + ((::System::UInt32) *reinterpret_cast< sal_uInt32 const * >( + value.getValue() )); + case TypeClass_HYPER: + return __box + ((::System::Int64) *reinterpret_cast< sal_Int64 const * >( + value.getValue() )); + case TypeClass_UNSIGNED_HYPER: + return __box + ((::System::UInt64) *reinterpret_cast< sal_uInt64 const * >( + value.getValue() )); + case TypeClass_FLOAT: + return __box + ((::System::Single) *reinterpret_cast< float const * >( + value.getValue() )); + case TypeClass_DOUBLE: + return __box + ((::System::Double) *reinterpret_cast< double const * >( + value.getValue() )); + default: + throw RuntimeException( + OUSTR("unexpected constant type ") + + value.getValueType().getTypeName(), + Reference< XInterface >() ); + } +} + +//------------------------------------------------------------------------------ +static inline void emit_ldarg( Emit::ILGenerator * code, ::System::Int32 index ) +{ + switch (index) + { + case 0: + code->Emit( Emit::OpCodes::Ldarg_0 ); + break; + case 1: + code->Emit( Emit::OpCodes::Ldarg_1 ); + break; + case 2: + code->Emit( Emit::OpCodes::Ldarg_2 ); + break; + case 3: + code->Emit( Emit::OpCodes::Ldarg_3 ); + break; + default: + if (index < 0x100) + code->Emit( Emit::OpCodes::Ldarg_S, (::System::Byte) index ); + else if (index < 0x8000) + code->Emit( Emit::OpCodes::Ldarg_S, (::System::Int16) index ); + else + code->Emit( Emit::OpCodes::Ldarg, index ); + break; + } +} + +void polymorphicStructNameToStructName(::System::String ** sPolyName) +{ + if ((*sPolyName)->EndsWith(S">") == false) + return; + + int index = (*sPolyName)->IndexOf('<'); + OSL_ASSERT(index != -1); + *sPolyName = (*sPolyName)->Substring(0, index); +} + + +System::String* mapUnoTypeName(System::String * typeName) +{ + ::System::Text::StringBuilder* buf= new System::Text::StringBuilder(); + ::System::String * sUnoName = ::System::String::Copy(typeName); + //determine if the type is a sequence and its dimensions + int dims= 0; + if (typeName->StartsWith(S"["))//if (usUnoName[0] == '[') + { + int index= 1; + while (true) + { + if (typeName->get_Chars(index++) == ']')//if (usUnoName[index++] == ']') + dims++; + if (typeName->get_Chars(index++) != '[')//usUnoName[index++] != '[') + break; + } + sUnoName = sUnoName->Substring(index - 1);//usUnoName = usUnoName.copy(index - 1); + } + if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoBool))) + buf->Append(const_cast<System::String*>(Constants::sBoolean)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoChar))) + buf->Append(const_cast<System::String*>(Constants::sChar)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoByte))) + buf->Append(const_cast<System::String*>(Constants::sByte)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoShort))) + buf->Append(const_cast<System::String*>(Constants::sInt16)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoUShort))) + buf->Append(const_cast<System::String*>(Constants::sUInt16)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoLong))) + buf->Append(const_cast<System::String*>(Constants::sInt32)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoULong))) + buf->Append(const_cast<System::String*>(Constants::sUInt32)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoHyper))) + buf->Append(const_cast<System::String*>(Constants::sInt64)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoUHyper))) + buf->Append(const_cast<System::String*>(Constants::sUInt64)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoFloat))) + buf->Append(const_cast<System::String*>(Constants::sSingle)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoDouble))) + buf->Append(const_cast<System::String*>(Constants::sDouble)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoString))) + buf->Append(const_cast<System::String*>(Constants::sString)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoVoid))) + buf->Append(const_cast<System::String*>(Constants::sVoid)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoType))) + buf->Append(const_cast<System::String*>(Constants::sType)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoXInterface))) + buf->Append(const_cast<System::String*>(Constants::sObject)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoAny))) + { + buf->Append(const_cast<System::String*>(Constants::sAny)); + } + else + { + //put "unoidl." at the beginning + buf->Append(const_cast<System::String*>(Constants::sUnoidl)); + buf->Append(mapUnoPolymorphicName(sUnoName)); + } + // apend [] + for (;dims--;) + buf->Append(const_cast<System::String*>(Constants::sBrackets)); + + 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. + + Strings can be as complicated as this + test.MyStruct<char,test.MyStruct<long, []string>> + */ +System::String* mapUnoPolymorphicName(System::String* unoName) +{ + int index = unoName->IndexOf('<'); + if (index == -1) + return unoName; + + System::Text::StringBuilder * builder = + new System::Text::StringBuilder(unoName->Substring(0, index +1 )); + + //Find the first occurrence of ',' + //If the parameter is a polymorphic struct then we neede to ignore everything + //between the brackets because it can also contain commas + //get the type list within < and > + int endIndex = unoName->Length - 1; + index++; + int cur = index; + int countParams = 0; + while (cur <= endIndex) + { + System::Char c = unoName->Chars[cur]; + if (c == ',' || c == '>') + { + //insert a comma if needed + if (countParams != 0) + builder->Append(S","); + countParams++; + System::String * sParam = unoName->Substring(index, cur - index); + //skip the comma + cur++; + //the the index to the beginning of the next param + index = cur; + builder->Append(mapUnoTypeName(sParam)); + } + else if (c == '<') + { + cur++; + //continue until the matching '>' + int numNested = 0; + for (;;cur++) + { + System::Char curChar = unoName->Chars[cur]; + if (curChar == '<') + { + numNested ++; + } + else if (curChar == '>') + { + if (numNested > 0) + numNested--; + else + break; + } + } + } + cur++; + } + + builder->Append((System::Char) '>'); + return builder->ToString(); +} + + + +//______________________________________________________________________________ +Assembly * TypeEmitter::type_resolve( + ::System::Object *, ::System::ResolveEventArgs * args ) +{ + ::System::String * cts_name = args->get_Name(); + ::System::Type * ret_type = m_module_builder->GetType( + cts_name, false /* no exc */ ); + if (0 == ret_type) + { + iface_entry * entry = dynamic_cast< iface_entry * >( + m_incomplete_ifaces->get_Item( cts_name ) ); + if (0 != entry) + ret_type = entry->m_type_builder; + } + if (0 == ret_type) + { + sal_Int32 len = m_extra_assemblies->get_Length(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + ret_type = m_extra_assemblies[ pos ]->GetType( + cts_name, false /* no exc */ ); + if (0 != ret_type) + { + if (g_verbose) + { + ::System::Console::WriteLine( + "> resolving type {0} from {1}.", + cts_name, ret_type->get_Assembly()->get_FullName() ); + } + break; + } + } + } + if (0 != ret_type) + return ret_type->get_Assembly(); + return 0; +} + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_type( + ::System::String * cts_name, bool throw_exc ) +{ + ::System::Type * ret_type = m_module_builder->GetType( cts_name, false ); + //We get the type from the ModuleBuilder even if the type is not complete + //but have been defined. + //if (ret_type == 0) + //{ + // iface_entry * entry = dynamic_cast< iface_entry * >( + // m_incomplete_ifaces->get_Item( cts_name ) ); + // if (0 != entry) + // ret_type = entry->m_type_builder; + //} + //try the cli_basetypes assembly + if (ret_type == 0) + { + ::System::Text::StringBuilder * builder = new ::System::Text::StringBuilder(cts_name); + builder->Append(S",cli_basetypes"); + ret_type = ::System::Type::GetType(builder->ToString()); + } + + if (ret_type == 0) + { + try + { + // may call on type_resolve() + return ::System::Type::GetType( cts_name, throw_exc ); + } + catch (::System::Exception* exc) + { + //If the type is not found one may have forgotten to specify assemblies with + //additional types + ::System::Text::StringBuilder * sb = new ::System::Text::StringBuilder(); + sb->Append(new ::System::String(S"\nThe type ")); + sb->Append(cts_name); + sb->Append(new ::System::String(S" \n could not be found. Did you forget to " \ + S"specify an additional assembly with the --reference option?\n")); + if (throw_exc) + throw new ::System::Exception(sb->ToString(), exc); + } + } + else + { + return ret_type; + } +} + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_type_Exception() +{ + if (0 == m_type_Exception) + { + m_type_Exception = get_type( + S"unoidl.com.sun.star.uno.Exception", false /* no exc */ ); + if (0 == m_type_Exception) + { + // define hardcoded type unoidl.com.sun.star.uno.Exception + Emit::TypeBuilder * type_builder = + m_module_builder->DefineType( + S"unoidl.com.sun.star.uno.Exception", + (TypeAttributes) (TypeAttributes::Public | + TypeAttributes::BeforeFieldInit | + TypeAttributes::AnsiClass), + __typeof (::System::Exception) ); + Emit::FieldBuilder * field_Context = type_builder->DefineField( + S"Context", __typeof (::System::Object), + FieldAttributes::Public ); + // default .ctor + type_builder->DefineDefaultConstructor( c_ctor_method_attr ); + // .ctor + ::System::Type * param_types[] = + new ::System::Type *[ 2 ]; + param_types[ 0 ] = __typeof (::System::String); + param_types[ 1 ] = __typeof (::System::Object); + Emit::ConstructorBuilder * ctor_builder = + type_builder->DefineConstructor( + c_ctor_method_attr, CallingConventions::Standard, + param_types ); + ctor_builder->DefineParameter( + 1, ParameterAttributes::In, S"Message" ); + ctor_builder->DefineParameter( + 2, ParameterAttributes::In, S"Context" ); + Emit::ILGenerator * code = ctor_builder->GetILGenerator(); + code->Emit( Emit::OpCodes::Ldarg_0 ); + code->Emit( Emit::OpCodes::Ldarg_1 ); + param_types = new ::System::Type * [ 1 ]; + param_types[ 0 ] = __typeof (::System::String); + code->Emit( + Emit::OpCodes::Call, + __typeof (::System::Exception) + ->GetConstructor( param_types ) ); + code->Emit( Emit::OpCodes::Ldarg_0 ); + code->Emit( Emit::OpCodes::Ldarg_2 ); + code->Emit( Emit::OpCodes::Stfld, field_Context ); + code->Emit( Emit::OpCodes::Ret ); + + if (g_verbose) + { + ::System::Console::WriteLine( + "> emitting exception type " + "unoidl.com.sun.star.uno.Exception" ); + } + m_type_Exception = type_builder->CreateType(); + } + } + return m_type_Exception; +} + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_type_RuntimeException() +{ + if (0 == m_type_RuntimeException) + { + m_type_RuntimeException = get_type( + S"unoidl.com.sun.star.uno.RuntimeException", false /* no exc */ ); + if (0 == m_type_RuntimeException) + { + // define hardcoded type unoidl.com.sun.star.uno.RuntimeException + ::System::Type * type_Exception = get_type_Exception(); + Emit::TypeBuilder * type_builder = + m_module_builder->DefineType( + S"unoidl.com.sun.star.uno.RuntimeException", + (TypeAttributes) (TypeAttributes::Public | + TypeAttributes::BeforeFieldInit | + TypeAttributes::AnsiClass), + type_Exception ); + // default .ctor + type_builder->DefineDefaultConstructor( c_ctor_method_attr ); + // .ctor + ::System::Type * param_types [] = + new ::System::Type * [ 2 ]; + param_types[ 0 ] = __typeof (::System::String); + param_types[ 1 ] = __typeof (::System::Object); + Emit::ConstructorBuilder * ctor_builder = + type_builder->DefineConstructor( + c_ctor_method_attr, CallingConventions::Standard, + param_types ); + ctor_builder->DefineParameter( + 1, ParameterAttributes::In, S"Message" ); + ctor_builder->DefineParameter( + 2, ParameterAttributes::In, S"Context" ); + Emit::ILGenerator * code = ctor_builder->GetILGenerator(); + code->Emit( Emit::OpCodes::Ldarg_0 ); + code->Emit( Emit::OpCodes::Ldarg_1 ); + code->Emit( Emit::OpCodes::Ldarg_2 ); + code->Emit( + Emit::OpCodes::Call, + type_Exception->GetConstructor( param_types ) ); + code->Emit( Emit::OpCodes::Ret ); + + if (g_verbose) + { + ::System::Console::WriteLine( + "> emitting exception type " + "unoidl.com.sun.star.uno.RuntimeException" ); + } + m_type_RuntimeException = type_builder->CreateType(); + } + } + return m_type_RuntimeException; +} + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_type( + Reference< reflection::XConstantTypeDescription > const & xType ) +{ + ::System::String * cts_name = to_cts_name( xType->getName() ); + ::System::Type * ret_type = get_type( cts_name, false /* no exc */ ); + if (0 == ret_type) + { + Reference< reflection::XConstantTypeDescription > xConstant( + xType, UNO_QUERY_THROW ); + ::System::Object * constant = + to_cli_constant( xConstant->getConstantValue() ); + Emit::TypeBuilder * type_builder = + m_module_builder->DefineType( + cts_name, + (TypeAttributes) (TypeAttributes::Public | + TypeAttributes::Sealed | + TypeAttributes::BeforeFieldInit | + TypeAttributes::AnsiClass) ); + + Emit::FieldBuilder * field_builder = type_builder->DefineField( + cts_name->Substring( cts_name->LastIndexOf( '.' ) +1 ), + constant->GetType(), + (FieldAttributes) (FieldAttributes::Public | + FieldAttributes::Static | + FieldAttributes::Literal) ); + field_builder->SetConstant( constant ); + + if (g_verbose) + { + ::System::Console::WriteLine( + "> emitting constant type {0}", cts_name ); + } + ret_type = type_builder->CreateType(); + } + return ret_type; +} + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_type( + Reference< reflection::XConstantsTypeDescription > const & xType ) +{ + ::System::String * cts_name = to_cts_name( xType->getName() ); + ::System::Type * ret_type = get_type( cts_name, false /* no exc */ ); + if (0 == ret_type) + { + Emit::TypeBuilder * type_builder = + m_module_builder->DefineType( + cts_name, + (TypeAttributes) (TypeAttributes::Public | + TypeAttributes::Sealed | + TypeAttributes::BeforeFieldInit | + TypeAttributes::AnsiClass) ); + + Sequence< Reference< + reflection::XConstantTypeDescription > > seq_constants( + xType->getConstants() ); + Reference< reflection::XConstantTypeDescription > const * constants = + seq_constants.getConstArray(); + sal_Int32 constants_length = seq_constants.getLength(); + for ( sal_Int32 constants_pos = 0; + constants_pos < constants_length; ++constants_pos ) + { + Reference< + reflection::XConstantTypeDescription > const & xConstant = + constants[ constants_pos ]; + ::System::Object * constant = + to_cli_constant( xConstant->getConstantValue() ); + ::System::String * uno_name = + ustring_to_String( xConstant->getName() ); + Emit::FieldBuilder * field_builder = type_builder->DefineField( + uno_name->Substring( uno_name->LastIndexOf( '.' ) +1 ), + constant->GetType(), + (FieldAttributes) (FieldAttributes::Public | + FieldAttributes::Static | + FieldAttributes::Literal) ); + field_builder->SetConstant( constant ); + } + + if (g_verbose) + { + ::System::Console::WriteLine( + "> emitting constants group type {0}", cts_name ); + } + ret_type = type_builder->CreateType(); + } + return ret_type; +} + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_type( + Reference< reflection::XEnumTypeDescription > const & xType ) +{ + ::System::String * cts_name = to_cts_name( xType->getName() ); + ::System::Type * ret_type = get_type( cts_name, false /* no exc */ ); + if (0 == ret_type) + { +// Emit::EnumBuilder * enum_builder = +// m_module_builder->DefineEnum( +// cts_name, +// (TypeAttributes) (TypeAttributes::Public | +// // TypeAttributes::Sealed | +// TypeAttributes::AnsiClass), +// __typeof (::System::Int32) ); + // workaround enum builder bug + Emit::TypeBuilder * enum_builder = + m_module_builder->DefineType( + cts_name, + (TypeAttributes) (TypeAttributes::Public | + TypeAttributes::Sealed), + __typeof (::System::Enum) ); + enum_builder->DefineField( + S"value__", __typeof (::System::Int32), + (FieldAttributes) (FieldAttributes::Private | + FieldAttributes::SpecialName | + FieldAttributes::RTSpecialName) ); + Sequence< OUString > seq_enum_names( xType->getEnumNames() ); + Sequence< sal_Int32 > seq_enum_values( xType->getEnumValues() ); + sal_Int32 enum_length = seq_enum_names.getLength(); + OSL_ASSERT( enum_length == seq_enum_values.getLength() ); + OUString const * enum_names = seq_enum_names.getConstArray(); + sal_Int32 const * enum_values = seq_enum_values.getConstArray(); + for ( sal_Int32 enum_pos = 0; enum_pos < enum_length; ++enum_pos ) + { +// enum_builder->DefineLiteral( +// ustring_to_String( enum_names[ enum_pos ] ), +// __box ((::System::Int32) enum_values[ enum_pos ]) ); + Emit::FieldBuilder * field_builder = + enum_builder->DefineField( + ustring_to_String( enum_names[ enum_pos ] ), + enum_builder, + (FieldAttributes) (FieldAttributes::Public | + FieldAttributes::Static | + FieldAttributes::Literal) ); + field_builder->SetConstant( + __box ((::System::Int32) enum_values[ enum_pos ]) ); + } + + if (g_verbose) + { + ::System::Console::WriteLine( + "> emitting enum type {0}", cts_name ); + } + ret_type = enum_builder->CreateType(); + } + return ret_type; +} + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_type( + Reference< reflection::XCompoundTypeDescription > const & xType ) +{ + OUString uno_name( xType->getName() ); + if (TypeClass_EXCEPTION == xType->getTypeClass()) + { + if (uno_name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( + "com.sun.star.uno.Exception") )) + { + return get_type_Exception(); + } + if (uno_name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( + "com.sun.star.uno.RuntimeException") )) + { + return get_type_RuntimeException(); + } + } + ::System::String * cts_name = to_cts_name( uno_name ); + // if the struct is an instantiated polymorpic struct then we create the simple struct name + // For example: + // void func ([in] PolyStruct<boolean> arg); + //PolyStruct<boolean> will be converted to PolyStruct + polymorphicStructNameToStructName( & cts_name); + + ::System::Type * ret_type = get_type( cts_name, false /* no exc */ ); + if (0 == ret_type) + { + Reference< reflection::XCompoundTypeDescription > xBaseType( + xType->getBaseType(), UNO_QUERY ); + ::System::Type * base_type = (xBaseType.is() + ? get_type( xBaseType ) + : __typeof (::System::Object)); + Emit::TypeBuilder * type_builder = + m_module_builder->DefineType( + cts_name, + (TypeAttributes) (TypeAttributes::Public | + TypeAttributes::BeforeFieldInit | + TypeAttributes::AnsiClass), + base_type ); + + + // insert to be completed + struct_entry * entry = new struct_entry(); + xType->acquire(); + entry->m_xType = xType.get(); + entry->m_type_builder = type_builder; + entry->m_base_type = base_type; + m_incomplete_structs->Add( cts_name, entry ); + + // type is incomplete + ret_type = type_builder; + } + + //In case of an instantiated polymorphic struct we want to return a + //uno.PolymorphicType (inherits Type) rather then Type. This is neaded for constructing + //the service code. We can only do that if the struct is completed. + if (m_generated_structs->get_Item(cts_name)) + { + Reference< reflection::XStructTypeDescription> xStructTypeDesc( + xType, UNO_QUERY); + + if (xStructTypeDesc.is()) + { + Sequence< Reference< reflection::XTypeDescription > > seqTypeArgs = xStructTypeDesc->getTypeArguments(); + sal_Int32 numTypes = seqTypeArgs.getLength(); + if (numTypes > 0) + { + //it is an instantiated polymorphic struct + ::System::String * sCliName = mapUnoTypeName(ustring_to_String(xType->getName())); + ret_type = ::uno::PolymorphicType::GetType(ret_type, sCliName); + } + } + } + return ret_type; +} + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_type( + Reference< reflection::XInterfaceTypeDescription2 > const & xType ) +{ + OUString uno_name( xType->getName() ); + if (uno_name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") )) + { + return __typeof (::System::Object); + } + + ::System::String * cts_name = to_cts_name( xType->getName() ); + ::System::Type * ret_type = get_type( cts_name, false /* no exc */ ); + if (0 == ret_type) + { + Emit::TypeBuilder * type_builder; + + TypeAttributes attr = (TypeAttributes) (TypeAttributes::Public | + TypeAttributes::Interface | + TypeAttributes::Abstract | + TypeAttributes::AnsiClass); + + std::vector<Reference<reflection::XInterfaceTypeDescription2> > vecBaseTypes; + Sequence<Reference< reflection::XTypeDescription > > seqBaseTypes = + xType->getBaseTypes(); + if (seqBaseTypes.getLength() > 0) + { + for (int i = 0; i < seqBaseTypes.getLength(); i++) + { + Reference<reflection::XInterfaceTypeDescription2> xIfaceTd = + resolveInterfaceTypedef(seqBaseTypes[i]); + + if (xIfaceTd->getName().equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") ) == sal_False) + { + vecBaseTypes.push_back(xIfaceTd); + } + } + + ::System::Type * base_interfaces [] = + new ::System::Type * [ vecBaseTypes.size() ]; + + typedef std::vector<Reference<reflection::XInterfaceTypeDescription2> >::const_iterator it; + int index = 0; + for (it i = vecBaseTypes.begin(); i != vecBaseTypes.end(); i++, index++) + base_interfaces[ index ] = get_type( *i ); + type_builder = m_module_builder->DefineType( + cts_name, attr, 0, base_interfaces ); + } + else + { + ::System::Console::WriteLine( + "warning: IDL interface {0} is not derived from " + "com.sun.star.uno.XInterface!", + ustring_to_String( uno_name ) ); + + type_builder = m_module_builder->DefineType( cts_name, attr ); + } + + // insert to be completed + iface_entry * entry = new iface_entry(); + xType->acquire(); + entry->m_xType = xType.get(); + entry->m_type_builder = type_builder; + m_incomplete_ifaces->Add( cts_name, entry ); + + // type is incomplete + ret_type = type_builder; + } + return ret_type; +} + + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_type( + Reference< reflection::XServiceTypeDescription2 > const & xType ) +{ + if (xType->isSingleInterfaceBased() == sal_False) + return NULL; + + System::String * cts_name = to_cts_name( xType->getName() ); + System::Type * ret_type = get_type( cts_name, false /* no exc */ ); + if (ret_type != NULL) + return ret_type; + + TypeAttributes attr = (TypeAttributes) (TypeAttributes::Public | + TypeAttributes::Sealed | + TypeAttributes::BeforeFieldInit | + TypeAttributes::AnsiClass); + + Emit::TypeBuilder * type_builder = m_module_builder->DefineType( + cts_name, attr); + + // insert to be completed + service_entry * entry = new service_entry(); + xType->acquire(); + entry->m_xType = xType.get(); + entry->m_type_builder = type_builder; + m_incomplete_services->Add(cts_name,entry ); + + return type_builder; +} + +::System::Type * TypeEmitter::get_type( + Reference<reflection::XSingletonTypeDescription2 > const & xType ) +{ + if (xType->isInterfaceBased() == sal_False) + return NULL; + + ::System::String* cts_name = to_cts_name( xType->getName() ); + ::System::Type * ret_type = get_type( cts_name, false /* no exc */ ); + if (ret_type != NULL) + return ret_type; + + TypeAttributes attr = static_cast<TypeAttributes>( + TypeAttributes::Public | + TypeAttributes::Sealed | + TypeAttributes::BeforeFieldInit | + TypeAttributes::AnsiClass); + + Emit::TypeBuilder * type_builder = m_module_builder->DefineType( + cts_name, attr); + + // insert to be completed + singleton_entry * entry = new singleton_entry(); + xType->acquire(); + entry->m_xType = xType.get(); + entry->m_type_builder = type_builder; + m_incomplete_singletons->Add(cts_name,entry ); + + return type_builder; + +} + +//______________________________________________________________________________ +::System::Type * TypeEmitter::complete_iface_type( iface_entry * entry ) +{ + Emit::TypeBuilder * type_builder = entry->m_type_builder; + reflection::XInterfaceTypeDescription2 * xType = entry->m_xType; + + Sequence<Reference< reflection::XTypeDescription > > seqBaseTypes( xType->getBaseTypes() ); + if (seqBaseTypes.getLength() > 0) + { + for (int i = 0; i < seqBaseTypes.getLength(); i++) + { + //make sure we get the interface rather then a typedef + Reference<reflection::XInterfaceTypeDescription2> aBaseType = + resolveInterfaceTypedef( seqBaseTypes[i]); + + if (aBaseType->getName().equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") ) == sal_False) + { + ::System::String * basetype_name = to_cts_name( aBaseType->getName() ); + iface_entry * base_entry = dynamic_cast< iface_entry * >( + m_incomplete_ifaces->get_Item( basetype_name ) ); + if (0 != base_entry) + { + // complete uncompleted base type first + complete_iface_type( base_entry ); + } + } + } + } + + Sequence< + Reference< reflection::XInterfaceMemberTypeDescription > > seq_members( + xType->getMembers() ); + Reference< reflection::XInterfaceMemberTypeDescription > const * members = + seq_members.getConstArray(); + sal_Int32 members_length = seq_members.getLength(); + for ( sal_Int32 members_pos = 0; + members_pos < members_length; ++members_pos ) + { + Reference< + reflection::XInterfaceMemberTypeDescription > const & xMember = + members[ members_pos ]; + Sequence< Reference< reflection::XTypeDescription > > seq_exceptions; + Emit::MethodBuilder * method_builder; + + const MethodAttributes c_method_attr = (MethodAttributes) + (MethodAttributes::Public | + MethodAttributes::Abstract | + MethodAttributes::Virtual | + MethodAttributes::NewSlot | + MethodAttributes::HideBySig); +//#if defined(_MSC_VER) && (_MSC_VER < 1400) +// MethodAttributes::Instance); +//#else +// Instance); +//#endif + + if (TypeClass_INTERFACE_METHOD == xMember->getTypeClass()) + { + Reference< reflection::XInterfaceMethodTypeDescription > xMethod( + xMember, UNO_QUERY_THROW ); + + Sequence< + Reference< reflection::XMethodParameter > > seq_parameters( + xMethod->getParameters() ); + sal_Int32 params_length = seq_parameters.getLength(); + ::System::Type * param_types [] = + new ::System::Type * [ params_length ]; + Reference< reflection::XMethodParameter > const * parameters = + seq_parameters.getConstArray(); + // first determine all types + //Make the first param type as return type + sal_Int32 params_pos = 0; + for ( ; params_pos < params_length; ++params_pos ) + { + Reference< reflection::XMethodParameter > const & xParam = + parameters[ params_pos ]; + ::System::Type * param_type = get_type( xParam->getType() ); + ::System::String * param_type_name = param_type->get_FullName(); + if (xParam->isOut()) + { + param_type = get_type( + ::System::String::Concat( + param_type_name, S"&" ), true ); + } + param_types[ xParam->getPosition() ] = param_type; + } + + + // create method +// if (tb) +// method_builder = type_builder->DefineMethod( +// ustring_to_String( xMethod->getMemberName() ), +// c_method_attr, tb, +// param_types ); +// else + method_builder = type_builder->DefineMethod( + ustring_to_String( xMethod->getMemberName() ), + c_method_attr, get_type( xMethod->getReturnType() ), + param_types ); + // then define parameter infos + params_pos = 0; + for ( ; params_pos < params_length; ++params_pos ) + { + Reference< reflection::XMethodParameter > const & xParam = + parameters[ params_pos ]; + long param_flags = 0; + if (xParam->isIn()) + param_flags |= ParameterAttributes::In; + if (xParam->isOut()) + param_flags |= ParameterAttributes::Out; + OSL_ASSERT( 0 != param_flags ); + method_builder->DefineParameter( + xParam->getPosition() +1 /* starts with 1 */, + (ParameterAttributes) param_flags, + ustring_to_String( xParam->getName() ) ); + } + //Apply attribute TypeParametersAttribute to return value if it + //is a parameterized Type. Currently only structs can have parameters. + Reference<reflection::XStructTypeDescription> xReturnStruct( + xMethod->getReturnType(), UNO_QUERY); + + if (xReturnStruct.is()) + { + Sequence<Reference<reflection::XTypeDescription> > seq_type_args = + xReturnStruct->getTypeArguments(); + if (seq_type_args.getLength() != 0) + { + //get th ctor of the attribute + ::System::Type * arCtor[] = {::System::Type::GetType(S"System.Type[]")}; + //Get the arguments for the attribute's ctor + Reference<reflection::XTypeDescription> const * arXTypeArgs = + seq_type_args.getConstArray(); + int numTypes = seq_type_args.getLength(); + ::System::Type * arCtsTypes[] = new ::System::Type*[numTypes]; + for (int i = 0; i < numTypes; i++) + arCtsTypes[i] = get_type(arXTypeArgs[i]); + ::System::Object * arArgs[] = {arCtsTypes}; + + Emit::CustomAttributeBuilder * attrBuilder = + new Emit::CustomAttributeBuilder( + __typeof(::uno::TypeArgumentsAttribute) + ->GetConstructor( arCtor), + arArgs); + + method_builder->SetCustomAttribute(attrBuilder); + } + } + + //define UNO exception attribute (exceptions)-------------------------------------- + Emit::CustomAttributeBuilder* attrBuilder = + get_iface_method_exception_attribute(xMethod); + if (attrBuilder != NULL) + method_builder->SetCustomAttribute(attrBuilder); + + // oneway attribute + if (xMethod->isOneway()) + { + ::System::Type * arCtorOneway[] = new ::System::Type*[0]; + ::System::Object * arArgs[] = new ::System::Object*[0]; + Emit::CustomAttributeBuilder * attrBuilder = + new Emit::CustomAttributeBuilder( + __typeof(::uno::OnewayAttribute)->GetConstructor( arCtorOneway), + arArgs); + method_builder->SetCustomAttribute(attrBuilder); + } + } + else // attribute + { + OSL_ASSERT( + TypeClass_INTERFACE_ATTRIBUTE == xMember->getTypeClass() ); + Reference< + reflection::XInterfaceAttributeTypeDescription2 > xAttribute( + xMember, UNO_QUERY_THROW ); + + const MethodAttributes c_property_method_attr = (MethodAttributes) + (c_method_attr | MethodAttributes::SpecialName); + + ::System::Type * attribute_type = get_type( xAttribute->getType() ); + ::System::Type * parameters [] = + new ::System::Type * [ 0 ]; + + Emit::PropertyBuilder * property_builder = + type_builder->DefineProperty( + ustring_to_String( xAttribute->getMemberName() ), + PropertyAttributes::None, + attribute_type, parameters ); + + //set BoundAttribute, if necessary + if (xAttribute->isBound()) + { + ConstructorInfo * ctorBoundAttr = + __typeof(::uno::BoundAttribute)->GetConstructor( + new System::Type*[0]); + Emit::CustomAttributeBuilder * attrBuilderBound = + new Emit::CustomAttributeBuilder( + ctorBoundAttr, new ::System::Object*[0]); + property_builder->SetCustomAttribute(attrBuilderBound); + } + + // getter + Emit::MethodBuilder * method_builder = + type_builder->DefineMethod( + ustring_to_String( OUSTR("get_") + + xAttribute->getMemberName() ), + c_property_method_attr, attribute_type, parameters ); + + //define UNO exception attribute (exceptions)-------------------------------------- + Emit::CustomAttributeBuilder* attrBuilder = + get_exception_attribute(xAttribute->getGetExceptions()); + if (attrBuilder != NULL) + method_builder->SetCustomAttribute(attrBuilder); + + property_builder->SetGetMethod( method_builder ); + + if (! xAttribute->isReadOnly()) + { + // setter + parameters = new ::System::Type * [ 1 ]; + parameters[ 0 ] = attribute_type; + method_builder = + type_builder->DefineMethod( + ustring_to_String( OUSTR("set_") + + xAttribute->getMemberName() ), + c_property_method_attr, 0, parameters ); + // define parameter info + method_builder->DefineParameter( + 1 /* starts with 1 */, ParameterAttributes::In, S"value" ); + //define UNO exception attribute (exceptions)-------------------------------------- + Emit::CustomAttributeBuilder* attrBuilder = + get_exception_attribute(xAttribute->getSetExceptions()); + if (attrBuilder != NULL) + method_builder->SetCustomAttribute(attrBuilder); + + property_builder->SetSetMethod( method_builder ); + } + } + } + + // remove from incomplete types map + ::System::String * cts_name = type_builder->get_FullName(); + m_incomplete_ifaces->Remove( cts_name ); + xType->release(); + + if (g_verbose) + { + ::System::Console::WriteLine( + "> emitting interface type {0}", cts_name ); + } + return type_builder->CreateType(); +} + +::System::Type * TypeEmitter::complete_struct_type( struct_entry * entry ) +{ + OSL_ASSERT(entry); + ::System::String * cts_name = entry->m_type_builder->get_FullName(); + + //Polymorphic struct, define uno.TypeParametersAttribute + //A polymorphic struct cannot have a basetype. + //When we create the template of the struct then we have no exact types + //and the name does not contain a parameter list + Sequence< OUString > seq_type_parameters; + Reference< reflection::XStructTypeDescription> xStructTypeDesc( + entry->m_xType, UNO_QUERY); + if (xStructTypeDesc.is()) + { + seq_type_parameters = xStructTypeDesc->getTypeParameters(); + int numTypes = 0; + if ((numTypes = seq_type_parameters.getLength()) > 0) + { + ::System::Object * aArg[] = new ::System::Object*[numTypes]; + for (int i = 0; i < numTypes; i++) + aArg[i] = ustring_to_String(seq_type_parameters.getConstArray()[i]); + ::System::Object * args[] = {aArg}; + + ::System::Type * arTypesCtor[] = + {::System::Type::GetType(S"System.String[]")}; + Emit::CustomAttributeBuilder * attrBuilder = + new Emit::CustomAttributeBuilder( + __typeof(::uno::TypeParametersAttribute)->GetConstructor(arTypesCtor), + args); + entry->m_type_builder->SetCustomAttribute(attrBuilder); + } + } + + // optional: lookup base type whether generated entry of this session + struct_entry * base_type_entry = 0; + if (0 != entry->m_base_type) + { + //ToDo maybe get from incomplete structs + base_type_entry = + dynamic_cast< struct_entry * >( + m_generated_structs->get_Item( + entry->m_base_type->get_FullName() ) ); + } + + // members + Sequence< Reference< reflection::XTypeDescription > > seq_members( + entry->m_xType->getMemberTypes() ); + Sequence< OUString > seq_member_names( entry->m_xType->getMemberNames() ); + sal_Int32 members_length = seq_members.getLength(); + OSL_ASSERT( seq_member_names.getLength() == members_length ); + //check if we have a XTypeDescription for every member. If not then the user may + //have forgotten to specify additional rdbs with the --extra option. + Reference< reflection::XTypeDescription > const * pseq_members = + seq_members.getConstArray(); + OUString const * pseq_member_names = + seq_member_names.getConstArray(); + for (int i = 0; i < members_length; i++) + { + const OUString sType(entry->m_xType->getName()); + const OUString sMemberName(pseq_member_names[i]); + if ( ! pseq_members[i].is()) + throw RuntimeException(OUSTR("Missing type description . Check if you need to " \ + "specify additional RDBs with the --extra option. Type missing for: ") + sType + + OUSTR("::") + sMemberName,0); + } + + sal_Int32 all_members_length = 0; + sal_Int32 member_pos; + sal_Int32 type_param_pos = 0; + + // collect base types; wrong order + ::System::Collections::ArrayList * base_types_list = + new ::System::Collections::ArrayList( 3 /* initial capacity */ ); + for (::System::Type * base_type_pos = entry->m_base_type; + ! base_type_pos->Equals( __typeof (::System::Object) ); + base_type_pos = base_type_pos->get_BaseType() ) + { + base_types_list->Add( base_type_pos ); + if (base_type_pos->Equals( __typeof (::System::Exception) )) + { + // special Message member + all_members_length += 1; + break; // don't include System.Exception base classes + } + else + { + //ensure the base type is complete. Otherwise GetFields won't work + get_complete_struct(base_type_pos->get_FullName()); + all_members_length += + base_type_pos->GetFields( + (BindingFlags) (BindingFlags::Instance | + BindingFlags::Public | + BindingFlags::DeclaredOnly) ) + ->get_Length(); + } + } + + // create all_members arrays; right order + ::System::String * all_member_names[] = + new ::System::String * [all_members_length + members_length ]; + ::System::Type * all_param_types[] = + new ::System::Type * [all_members_length + members_length ]; + member_pos = 0; + for ( sal_Int32 pos = base_types_list->get_Count(); pos--; ) + { + ::System::Type * base_type = __try_cast< ::System::Type * >( + base_types_list->get_Item( pos ) ); + if (base_type->Equals( __typeof (::System::Exception) )) + { + all_member_names[ member_pos ] = S"Message"; + all_param_types[ member_pos ] = __typeof (::System::String); + ++member_pos; + } + else + { + ::System::String * base_type_name = base_type->get_FullName(); + + //ToDo m_generated_structs? + struct_entry * entry = + dynamic_cast< struct_entry * >( + m_generated_structs->get_Item( base_type_name ) ); + if (0 == entry) + { + // complete type + FieldInfo * fields [] = + base_type->GetFields( + (BindingFlags) (BindingFlags::Instance | + BindingFlags::Public | + BindingFlags::DeclaredOnly) ); + sal_Int32 len = fields->get_Length(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + FieldInfo * field = fields[ pos ]; + all_member_names[ member_pos ] = field->get_Name(); + all_param_types[ member_pos ] = field->get_FieldType(); + ++member_pos; + } + } + else // generated during this session: + // members may be incomplete ifaces + { + sal_Int32 len = entry->m_member_names->get_Length(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + all_member_names[ member_pos ] = + entry->m_member_names[ pos ]; + all_param_types[ member_pos ] = + entry->m_param_types[ pos ]; + ++member_pos; + } + } + } + } + OSL_ASSERT( all_members_length == member_pos ); + + // build up entry +// struct_entry * entry = new struct_entry(); + entry->m_member_names = new ::System::String * [ members_length ]; + entry->m_param_types = new ::System::Type * [ members_length ]; + + // add members + Emit::FieldBuilder * members[] = new Emit::FieldBuilder * [ members_length ]; + //Reference< reflection::XTypeDescription > const * pseq_members = + // seq_members.getConstArray(); + //OUString const * pseq_member_names = + // seq_member_names.getConstArray(); + + int curParamIndex = 0; //count the fields which have parameterized types + for ( member_pos = 0; member_pos < members_length; ++member_pos ) + { + ::System::String * field_name = + ustring_to_String( pseq_member_names[ member_pos ] ); + ::System::Type * field_type; + //Special handling of struct parameter types + bool bParameterizedType = false; + if (pseq_members[ member_pos ]->getTypeClass() == TypeClass_UNKNOWN) + { + bParameterizedType = true; + if (type_param_pos < seq_type_parameters.getLength()) + { + field_type = __typeof(::System::Object); + type_param_pos++; + } + else + { + throw RuntimeException( + OUSTR("unexpected member type in ") + entry->m_xType->getName(), + Reference< XInterface >() ); + } + } + else + { + field_type = + get_type( pseq_members[ member_pos ] ); + } + members[ member_pos ] = + entry->m_type_builder->DefineField( + field_name, field_type, FieldAttributes::Public ); + + //parameterized type (polymorphic struct) ? + if (bParameterizedType && xStructTypeDesc.is()) + { + //get the name + OSL_ASSERT(seq_type_parameters.getLength() > curParamIndex); + ::System::String* sTypeName = ustring_to_String( + seq_type_parameters.getConstArray()[curParamIndex++]); + ::System::Object * args[] = {sTypeName}; + //set ParameterizedTypeAttribute + ::System::Type * arCtorTypes[] = {__typeof(::System::String)}; + + Emit::CustomAttributeBuilder * attrBuilder = + new Emit::CustomAttributeBuilder( + __typeof(::uno::ParameterizedTypeAttribute) + ->GetConstructor(arCtorTypes), + args); + + members[member_pos]->SetCustomAttribute(attrBuilder); + } + // add to all_members + all_member_names[ all_members_length + member_pos ] = field_name; + all_param_types[ all_members_length + member_pos ] = field_type; + // add to entry + entry->m_member_names[ member_pos ] = field_name; + entry->m_param_types[ member_pos ] = field_type; + } + all_members_length += members_length; + + // default .ctor + Emit::ConstructorBuilder * ctor_builder = + entry->m_type_builder->DefineConstructor( + c_ctor_method_attr, CallingConventions::Standard, + new ::System::Type * [ 0 ] ); + Emit::ILGenerator * code = ctor_builder->GetILGenerator(); + code->Emit( Emit::OpCodes::Ldarg_0 ); + code->Emit( + Emit::OpCodes::Call, + 0 == base_type_entry + ? entry->m_base_type->GetConstructor( new ::System::Type * [ 0 ] ) + : base_type_entry->m_default_ctor ); + // default initialize members + for ( member_pos = 0; member_pos < members_length; ++member_pos ) + { + FieldInfo * field = members[ member_pos ]; + ::System::Type * field_type = field->get_FieldType(); + // ::System::Type * new_field_type = m_module_builder->GetType(field_type->FullName, false); + // default initialize: + // string, type, enum, sequence, struct, exception, any + if (field_type->Equals( __typeof (::System::String) )) + { + code->Emit( Emit::OpCodes::Ldarg_0 ); + code->Emit( Emit::OpCodes::Ldstr, S"" ); + code->Emit( Emit::OpCodes::Stfld, field ); + } + else if (field_type->Equals( __typeof (::System::Type) )) + { + code->Emit( Emit::OpCodes::Ldarg_0 ); + code->Emit( + Emit::OpCodes::Ldtoken, __typeof (::System::Void) ); + code->Emit( + Emit::OpCodes::Call, m_method_info_Type_GetTypeFromHandle ); + code->Emit( Emit::OpCodes::Stfld, field ); + } + else if (field_type->get_IsArray()) + { + //Find the value type. In case of sequence<sequence< ... > > find the actual value type + ::System::Type * value = field_type; + while ((value = value->GetElementType())->get_IsArray()); + //If the value type is a struct then make sure it is fully created. + get_complete_struct(value->get_FullName()); + + code->Emit( Emit::OpCodes::Ldarg_0 ); + code->Emit( Emit::OpCodes::Ldc_I4_0 ); + code->Emit( + Emit::OpCodes::Newarr, field_type->GetElementType() ); + code->Emit( Emit::OpCodes::Stfld, field ); + } + else if (field_type->get_IsValueType()) + { + if (field_type->get_FullName()->Equals( S"uno.Any" )) + { + code->Emit( Emit::OpCodes::Ldarg_0 ); + code->Emit( Emit::OpCodes::Ldsfld, __typeof(::uno::Any)->GetField(S"VOID")); + code->Emit( Emit::OpCodes::Stfld, field ); + } + } + else if (field_type->get_IsClass()) + { + /* may be XInterface */ + if (! field_type->Equals( __typeof (::System::Object) )) + { + // struct, exception + //make sure the struct is already complete. + get_complete_struct(field_type->get_FullName()); + code->Emit( Emit::OpCodes::Ldarg_0 ); + code->Emit( + Emit::OpCodes::Newobj, + //GetConstructor requies that the member types of the object which is to be constructed are already known. + field_type->GetConstructor( + new ::System::Type * [ 0 ] ) ); + code->Emit( Emit::OpCodes::Stfld, field ); + } + } + } + code->Emit( Emit::OpCodes::Ret ); + entry->m_default_ctor = ctor_builder; + + // parameterized .ctor including all base members + ctor_builder = entry->m_type_builder->DefineConstructor( + c_ctor_method_attr, CallingConventions::Standard, all_param_types ); + for ( member_pos = 0; member_pos < all_members_length; ++member_pos ) + { + ctor_builder->DefineParameter( + member_pos +1 /* starts with 1 */, ParameterAttributes::In, + all_member_names[ member_pos ] ); + } + code = ctor_builder->GetILGenerator(); + // call base .ctor + code->Emit( Emit::OpCodes::Ldarg_0 ); // push this + sal_Int32 base_members_length = all_members_length - members_length; + ::System::Type * param_types [] = + new ::System::Type * [ base_members_length ]; + for ( member_pos = 0; member_pos < base_members_length; ++member_pos ) + { + emit_ldarg( code, member_pos +1 ); + param_types[ member_pos ] = all_param_types[ member_pos ]; + } + code->Emit( + Emit::OpCodes::Call, + 0 == base_type_entry + ? entry->m_base_type->GetConstructor( param_types ) + : base_type_entry->m_ctor ); + // initialize members + for ( member_pos = 0; member_pos < members_length; ++member_pos ) + { + code->Emit( Emit::OpCodes::Ldarg_0 ); // push this + emit_ldarg( code, member_pos + base_members_length +1 ); + code->Emit( Emit::OpCodes::Stfld, members[ member_pos ] ); + } + code->Emit( Emit::OpCodes::Ret ); + entry->m_ctor = ctor_builder; + + if (g_verbose) + { + ::System::Console::WriteLine( + "> emitting {0} type {1}", + TypeClass_STRUCT == entry->m_xType->getTypeClass() + ? S"struct" + : S"exception", + cts_name); + } + // new entry + m_generated_structs->Add(cts_name, entry ); + ::System::Type * ret_type = entry->m_type_builder->CreateType(); + + // remove from incomplete types map + m_incomplete_structs->Remove( cts_name ); + entry->m_xType->release(); + + if (g_verbose) + { + ::System::Console::WriteLine( + "> emitting struct type {0}", cts_name); + } + return ret_type; +} + +//Examples of generated code +// public static XWeak constructor1(XComponentContext ctx) +// { +// XMultiComponentFactory factory = ctx.getServiceManager(); +// if (factory == null) +// throw new com.sun.star.uno.DeploymentException("bla", null); +// return (XWeak) factory.createInstanceWithContext("service_specifier", ctx); +// } +// public static XWeak constructor2(XComponentContext ctx, int a, int b, Any c) +// { +// XMultiComponentFactory factory = ctx.getServiceManager(); +// if (factory == null) +// throw new com.sun.star.uno.DeploymentException("bla", null); +// Any[] arAny = new Any[3]; +// arAny[0] = new Any(typeof(int), a); +// arAny[1] = new Any(typeof(int), b); +// arAny[2] = new Any(c.Type, c.Value); +// return (XWeak) factory.createInstanceWithArgumentsAndContext("service_specifier", arAny, ctx); +// } +// Notice that a any parameter is NOT wrapped by another any. Instead the new any is created with the type and value +// of the parameter. + +// public static XWeak constructor3(XComponentContext ctx, params Any[] c) +// { +// XMultiComponentFactory factory = ctx.getServiceManager(); +// if (factory == null) +// throw new com.sun.star.uno.DeploymentException("bla", null); +// return (XWeak) factory.createInstanceWithArgumentsAndContext("service_specifier", c, ctx); +// } +::System::Type * TypeEmitter::complete_service_type(service_entry * entry) +{ + Emit::TypeBuilder * type_builder = entry->m_type_builder; + reflection::XServiceTypeDescription2 * xServiceType = entry->m_xType; + + //Create the private default constructor + Emit::ConstructorBuilder* ctor_builder = + type_builder->DefineConstructor( + (MethodAttributes) (MethodAttributes::Private | + MethodAttributes::HideBySig | + MethodAttributes::SpecialName | + MethodAttributes::RTSpecialName), + CallingConventions::Standard, NULL); + + Emit::ILGenerator* ilGen = ctor_builder->GetILGenerator(); + ilGen->Emit( Emit::OpCodes::Ldarg_0 ); // push this + ilGen->Emit( + Emit::OpCodes::Call, + type_builder->BaseType->GetConstructor(new ::System::Type*[0])); + ilGen->Emit( Emit::OpCodes::Ret ); + + + //Create the service constructors. + //obtain the interface which makes up this service, it is the return + //type of the constructor functions + Reference<reflection::XInterfaceTypeDescription2> xIfaceType( + xServiceType->getInterface(), UNO_QUERY); + if (xIfaceType.is () == sal_False) + xIfaceType = resolveInterfaceTypedef(xServiceType->getInterface()); + System::Type * retType = get_type(xIfaceType); + + //Create the ConstructorInfo for a DeploymentException + ::System::Type * typeDeploymentExc = + get_type(S"unoidl.com.sun.star.uno.DeploymentException", true); + + ::System::Type * arTypeCtor[] = {__typeof(::System::String), + __typeof(::System::Object)}; + ::System::Reflection::ConstructorInfo * ctorDeploymentException = + typeDeploymentExc->GetConstructor(arTypeCtor); + + Sequence<Reference<reflection::XServiceConstructorDescription> > seqCtors = + xServiceType->getConstructors(); + + ::System::Type * type_uno_exception = get_type(S"unoidl.com.sun.star.uno.Exception", true); + + for (int i = seqCtors.getLength() - 1; i >= 0; i--) + { + bool bParameterArray = false; + ::System::Type * typeAny = __typeof(::uno::Any); + const Reference<reflection::XServiceConstructorDescription> & ctorDes = + seqCtors[i]; + //obtain the parameter types + Sequence<Reference<reflection::XParameter> > seqParams = + ctorDes->getParameters(); + Reference<reflection::XParameter> const * arXParams = seqParams.getConstArray(); + sal_Int32 cParams = seqParams.getLength(); + ::System::Type * arTypeParameters[] = new ::System::Type* [cParams + 1]; + arTypeParameters[0] = get_type(S"unoidl.com.sun.star.uno.XComponentContext", true); + for (int iparam = 0; iparam != cParams; iparam++) + { + if (arXParams[iparam]->isRestParameter()) + arTypeParameters[iparam + 1] = __typeof(::uno::Any[]); + else + arTypeParameters[iparam + 1] = get_type(arXParams[iparam]->getType()); + } + //The array arTypeParameters can contain: + //System.Type and uno.PolymorphicType. + //Passing PolymorphicType to MethodBuilder.DefineMethod will cause a problem. + //The exception will read something like no on information for parameter # d + //Maybe we need no override another Type method in PolymorphicType ... + //Until we have figured this out, we will create another array of System.Type which + //we pass on to DefineMethod. + ::System::Type * arParamTypes[] = new ::System::Type * [cParams + 1]; +// arParamTypes[0] = get_type(S"unoidl.com.sun.star.uno.XComponentContext", true); + for (int i = 0; i < cParams + 1; i++) + { + ::uno::PolymorphicType * pT = dynamic_cast< ::uno::PolymorphicType * >(arTypeParameters[i]); + if (pT) + arParamTypes[i] = pT->OriginalType; + else + arParamTypes[i] = arTypeParameters[i]; + } + //define method + System::String * ctorName; + if (ctorDes->isDefaultConstructor()) + ctorName = new ::System::String(S"create"); + else + ctorName = ustring_to_String(ctorDes->getName()); + Emit::MethodBuilder* method_builder = type_builder->DefineMethod( + ctorName, + static_cast<MethodAttributes>(MethodAttributes::Public | MethodAttributes::HideBySig | + MethodAttributes::Static), + retType, +// arTypeParameters); + arParamTypes); + + //define UNO exception attribute (exceptions)-------------------------------------- + Emit::CustomAttributeBuilder* attrBuilder = get_service_exception_attribute(ctorDes); + if (attrBuilder != NULL) + method_builder->SetCustomAttribute(attrBuilder); + + //------------------------------------------------------------- + //define parameter attributes (paramarray), names etc. + //The first parameter is the XComponentContext, which cannot be obtained + //from reflection. + //The context is not part of the idl description + method_builder->DefineParameter( + 1, ParameterAttributes::In, S"the_context"); + + Emit::ParameterBuilder * arParameterBuilder[] = + new Emit::ParameterBuilder * [cParams]; + for (int iparam = 0; iparam != cParams; iparam++) + { + Reference<reflection::XParameter> const & aParam = arXParams[iparam]; + ::System::String * sParamName = ustring_to_String(aParam->getName()); + + arParameterBuilder[iparam] = method_builder->DefineParameter( + iparam + 2, ParameterAttributes::In, sParamName); + + if (aParam->isRestParameter()) + { + bParameterArray = true; + //set the ParameterArrayAttribute + ::System::Reflection::ConstructorInfo* ctor_info = + __typeof(System::ParamArrayAttribute)->GetConstructor( + new ::System::Type*[0]); + Emit::CustomAttributeBuilder * attr_builder = + new Emit::CustomAttributeBuilder(ctor_info, new ::System::Object*[0]); + arParameterBuilder[iparam]->SetCustomAttribute(attr_builder); + break; + } + } + + Emit::ILGenerator * ilGen = method_builder->GetILGenerator(); + + //Define locals --------------------------------- + //XMultiComponentFactory + Emit::LocalBuilder* local_factory = + ilGen->DeclareLocal( + get_type(S"unoidl.com.sun.star.lang.XMultiComponentFactory", true)); + + //The return type + Emit::LocalBuilder* local_return_val = + ilGen->DeclareLocal(retType); + + //Obtain the XMultiComponentFactory and throw an exception if we do not get one + ilGen->Emit(Emit::OpCodes::Ldarg_0); + + ::System::Reflection::MethodInfo * methodGetServiceManager = get_type( + S"unoidl.com.sun.star.uno.XComponentContext", true) + ->GetMethod(S"getServiceManager"); + ilGen->Emit(Emit::OpCodes::Callvirt, methodGetServiceManager); + ilGen->Emit(Emit::OpCodes::Stloc, local_factory); + ilGen->Emit(Emit::OpCodes::Ldloc, local_factory); + Emit::Label label1 = ilGen->DefineLabel(); + ilGen->Emit(Emit::OpCodes::Brtrue, label1); + //The string for the exception + ::System::Text::StringBuilder * strbuilder = new ::System::Text::StringBuilder(256); + strbuilder->Append(S"The service "); + strbuilder->Append(to_cts_name(xServiceType->getName())); + strbuilder->Append(S" could not be created. The context failed to supply the service manager."); + + ilGen->Emit(Emit::OpCodes::Ldstr, strbuilder->ToString()); + ilGen->Emit(Emit::OpCodes::Ldarg_0); + ilGen->Emit(Emit::OpCodes::Newobj, ctorDeploymentException); + ilGen->Emit(Emit::OpCodes::Throw); + ilGen->MarkLabel(label1); + + //We create a try/ catch around the createInstanceWithContext, etc. functions + //There are 3 cases + //1. function do not specify exceptions. Then RuntimeExceptions are retrhown and other + // exceptions produce a DeploymentException. + //2. function specify Exception. Then all exceptions fly through + //3. function specifies exceptions but no Exception. Then these are rethrown + // and other exceptions, except RuntimeException, produce a deployment exception. + //In case there are no parameters we call + //XMultiComponentFactory.createInstanceWithContext + + ::System::Collections::ArrayList * arExceptionTypes = + get_service_ctor_method_exceptions_reduced(ctorDes->getExceptions()); + if (arExceptionTypes->Contains( + type_uno_exception) == false) + { + ilGen->BeginExceptionBlock(); + } + if (cParams == 0) + { + ilGen->Emit(Emit::OpCodes::Ldloc, local_factory); + ilGen->Emit(Emit::OpCodes::Ldstr, ustring_to_String(xServiceType->getName())); + ilGen->Emit(Emit::OpCodes::Ldarg_0); + + ::System::Reflection::MethodInfo * methodCreate = + local_factory->get_LocalType()->GetMethod(S"createInstanceWithContext"); + ilGen->Emit(Emit::OpCodes::Callvirt, methodCreate); + } + else if(bParameterArray) + { + //Service constructor with parameter array + ilGen->Emit(Emit::OpCodes::Ldloc, local_factory); + ilGen->Emit(Emit::OpCodes::Ldstr, ustring_to_String(xServiceType->getName())); + ilGen->Emit(Emit::OpCodes::Ldarg_1); + ilGen->Emit(Emit::OpCodes::Ldarg_0); + ::System::Reflection::MethodInfo * methodCreate = + local_factory->get_LocalType()->GetMethod(S"createInstanceWithArgumentsAndContext"); + ilGen->Emit(Emit::OpCodes::Callvirt, methodCreate); + } + else + { + // Any param1, Any param2, etc. + // For each parameter,except the component context, and parameter array + // and Any is created. + Emit::LocalBuilder * arLocalAny[] = new Emit::LocalBuilder* [cParams]; + + for (int iParam = 0; iParam < cParams; iParam ++) + { + arLocalAny[iParam] = ilGen->DeclareLocal(typeAny); + } + + //Any[]. This array is filled with the created Anys which contain the parameters + //and the values contained in the parameter array + Emit::LocalBuilder * local_anyParams = + ilGen->DeclareLocal(__typeof(::uno::Any[])); + + //Create the Any for every argument, except for the parameter array + //arLocalAny contains the LocalBuilder for all these parameters. + //we call the ctor Any(Type, Object) + //If the parameter is an Any then the Any is created with Any(param.Type, param.Value); + ::System::Type * arTypesCtorAny[] = {__typeof(::System::Type), + __typeof(::System::Object)}; + ::System::Reflection::ConstructorInfo * ctorAny = + typeAny->GetConstructor( arTypesCtorAny); + ::System::Reflection::MethodInfo * methodAnyGetType = + typeAny->GetProperty(S"Type")->GetGetMethod(); + ::System::Reflection::MethodInfo * methodAnyGetValue = + typeAny->GetProperty(S"Value")->GetGetMethod(); + for (int i = 0; i < arLocalAny->Length; i ++) + { + //check if the parameter is a polymorphic struct + ::uno::PolymorphicType *polyType = dynamic_cast< ::uno::PolymorphicType* >(arTypeParameters[i+1]); + //arTypeParameters[i+1] = polyType->OriginalType; + if (polyType) + { + //It is a polymorphic struct + //Load the uninitialized local Any on which we will call the ctor + ilGen->Emit(Emit::OpCodes::Ldloca, arLocalAny[i]); + // Call PolymorphicType PolymorphicType::GetType(Type t, String polyName) + // Prepare the first parameter + ilGen->Emit(Emit::OpCodes::Ldtoken, polyType->get_OriginalType()); + ::System::Type * arTypeParams[] = {__typeof(::System::RuntimeTypeHandle)}; + ilGen->Emit(Emit::OpCodes::Call, + __typeof(::System::Type)->GetMethod( + S"GetTypeFromHandle", arTypeParams)); + // Prepare the second parameter + ilGen->Emit(Emit::OpCodes::Ldstr, polyType->get_PolymorphicName()); + // Make the actual call + ::System::Type * arTypeParam_GetType[] = { + __typeof(::System::Type), __typeof(::System::String) }; + ilGen->Emit(Emit::OpCodes::Call, + __typeof(::uno::PolymorphicType)->GetMethod(new System::String(S"GetType"), + arTypeParam_GetType)); + + //Stack is: localAny, PolymorphicType + //Call Any::Any(Type, Object) + //Prepare the second parameter for the any ctor + ilGen->Emit(Emit::OpCodes::Ldarg, i + 1); + // if the parameter is a value type then we need to box it, because + // the Any ctor takes an Object + if (arTypeParameters[i+1]->IsValueType) + ilGen->Emit(Emit::OpCodes::Box, arTypeParameters[i+1]); + ilGen->Emit(Emit::OpCodes::Call, ctorAny); + } + else if (arTypeParameters[i+1] == typeAny) + { + //Create the call new Any(param.Type,param,Value) + //Stack must be Any,Type,Value + //First load the Any which is to be constructed + ilGen->Emit(Emit::OpCodes::Ldloca, arLocalAny[i]); + //Load the Type, which is obtained by calling param.Type + ilGen->Emit(Emit::OpCodes::Ldarga, i + 1); + ilGen->Emit(Emit::OpCodes::Call, methodAnyGetType); + //Load the Value, which is obtained by calling param.Value + ilGen->Emit(Emit::OpCodes::Ldarga, i + 1); + ilGen->Emit(Emit::OpCodes::Call, methodAnyGetValue); + //Call the Any ctor. + ilGen->Emit(Emit::OpCodes::Call, ctorAny); + } + else + { + ilGen->Emit(Emit::OpCodes::Ldloca, arLocalAny[i]); + ilGen->Emit(Emit::OpCodes::Ldtoken, arTypeParameters[i+1]); + + ::System::Type * arTypeParams[] = {__typeof(::System::RuntimeTypeHandle)}; + ilGen->Emit(Emit::OpCodes::Call, + __typeof(::System::Type)->GetMethod( + S"GetTypeFromHandle", arTypeParams)); + ilGen->Emit(Emit::OpCodes::Ldarg, i + 1); + // if the parameter is a value type then we need to box it, because + // the Any ctor takes an Object + if (arTypeParameters[i+1]->IsValueType) + ilGen->Emit(Emit::OpCodes::Box, arTypeParameters[i+1]); + ilGen->Emit(Emit::OpCodes::Call, ctorAny); + } + } + + //Create the Any[] that is passed to the + //createInstanceWithContext[AndArguments] function + ilGen->Emit(Emit::OpCodes::Ldc_I4, arLocalAny->Length); + ilGen->Emit(Emit::OpCodes::Newarr, typeAny); + ilGen->Emit(Emit::OpCodes::Stloc, local_anyParams); + + //Assign all anys created from the parameters + //array to the Any[] + for (int i = 0; i < arLocalAny->Length; i++) + { + ilGen->Emit(Emit::OpCodes::Ldloc, local_anyParams); + ilGen->Emit(Emit::OpCodes::Ldc_I4, i); + ilGen->Emit(Emit::OpCodes::Ldelema, typeAny); + ilGen->Emit(Emit::OpCodes::Ldloc, arLocalAny[i]); + ilGen->Emit(Emit::OpCodes::Stobj, typeAny); + } + // call createInstanceWithContextAndArguments + ilGen->Emit(Emit::OpCodes::Ldloc, local_factory); + ilGen->Emit(Emit::OpCodes::Ldstr, ustring_to_String(xServiceType->getName())); + ilGen->Emit(Emit::OpCodes::Ldloc, local_anyParams); + ilGen->Emit(Emit::OpCodes::Ldarg_0); + ::System::Reflection::MethodInfo * methodCreate = + local_factory->get_LocalType()->GetMethod(S"createInstanceWithArgumentsAndContext"); + ilGen->Emit(Emit::OpCodes::Callvirt, methodCreate); + } + //cast the object returned by the functions createInstanceWithContext or + //createInstanceWithArgumentsAndContext to the interface type + ilGen->Emit(Emit::OpCodes::Castclass, retType); + ilGen->Emit(Emit::OpCodes::Stloc, local_return_val); + + //catch exceptions thrown by createInstanceWithArgumentsAndContext and createInstanceWithContext + if (arExceptionTypes->Contains(type_uno_exception) == false) + { + // catch (unoidl.com.sun.star.uno.RuntimeException) {throw;} + ilGen->BeginCatchBlock(get_type(S"unoidl.com.sun.star.uno.RuntimeException", true)); + ilGen->Emit(Emit::OpCodes::Pop); + ilGen->Emit(Emit::OpCodes::Rethrow); + + //catch and rethrow all other defined Exceptions + for (int i = 0; i < arExceptionTypes->Count; i++) + { + ::System::Type * excType = __try_cast< ::System::Type* >( + arExceptionTypes->get_Item(i)); + if (excType->IsInstanceOfType( + get_type(S"unoidl.com.sun.star.uno.RuntimeException", true))) + {// we have a catch for RuntimeException already defined + continue; + } + + //catch Exception and rethrow + ilGen->BeginCatchBlock(excType); + ilGen->Emit(Emit::OpCodes::Pop); + ilGen->Emit(Emit::OpCodes::Rethrow); + } + //catch (unoidl.com.sun.star.uno.Exception) {throw DeploymentException...} + ilGen->BeginCatchBlock(type_uno_exception); + + //Define the local variabe that keeps the exception + Emit::LocalBuilder * local_exception = ilGen->DeclareLocal( + type_uno_exception); + + //Store the exception + ilGen->Emit(Emit::OpCodes::Stloc, local_exception); + + //prepare the construction of the exception + strbuilder = new ::System::Text::StringBuilder(256); + strbuilder->Append(S"The context (com.sun.star.uno.XComponentContext) failed to supply the service "); + strbuilder->Append(to_cts_name(xServiceType->getName())); + strbuilder->Append(S": "); + + ilGen->Emit(Emit::OpCodes::Ldstr, strbuilder->ToString()); + + //add to the string the Exception.Message + ilGen->Emit(Emit::OpCodes::Ldloc, local_exception); + ilGen->Emit(Emit::OpCodes::Callvirt, + type_uno_exception->GetProperty(S"Message")->GetGetMethod()); + ::System::Type * arConcatParams [] = {__typeof(System::String), + __typeof(System::String)}; + ilGen->Emit(Emit::OpCodes::Call, + __typeof(System::String)->GetMethod(S"Concat", arConcatParams)); + //load contex argument + ilGen->Emit(Emit::OpCodes::Ldarg_0); + ilGen->Emit(Emit::OpCodes::Newobj, ctorDeploymentException); + ilGen->Emit(Emit::OpCodes::Throw);//Exception(typeDeploymentExc); + + ilGen->EndExceptionBlock(); + } + + + //Check if the service instance was create and throw a exception if not. + Emit::Label label_service_created = ilGen->DefineLabel(); + ilGen->Emit(Emit::OpCodes::Ldloc, local_return_val); + ilGen->Emit(Emit::OpCodes::Brtrue_S, label_service_created); + + strbuilder = new ::System::Text::StringBuilder(256); + strbuilder->Append(S"The context (com.sun.star.uno.XComponentContext) failed to supply the service "); + strbuilder->Append(to_cts_name(xServiceType->getName())); + strbuilder->Append(S"."); + ilGen->Emit(Emit::OpCodes::Ldstr, strbuilder->ToString()); + ilGen->Emit(Emit::OpCodes::Ldarg_0); + ilGen->Emit(Emit::OpCodes::Newobj, ctorDeploymentException); + ilGen->Emit(Emit::OpCodes::Throw);//Exception(typeDeploymentExc); + + ilGen->MarkLabel(label_service_created); + ilGen->Emit(Emit::OpCodes::Ldloc, local_return_val); + ilGen->Emit(Emit::OpCodes::Ret); + + } + // remove from incomplete types map + ::System::String * cts_name = type_builder->get_FullName(); + m_incomplete_services->Remove( cts_name ); + xServiceType->release(); + if (g_verbose) + { + ::System::Console::WriteLine( + "> emitting service type {0}", cts_name ); + } + return type_builder->CreateType(); +} + + +Emit::CustomAttributeBuilder* TypeEmitter::get_service_exception_attribute( + const Reference<reflection::XServiceConstructorDescription> & ctorDes ) +{ + return get_exception_attribute(ctorDes->getExceptions()); +} + +Emit::CustomAttributeBuilder* TypeEmitter::get_iface_method_exception_attribute( + const Reference< reflection::XInterfaceMethodTypeDescription >& xMethod ) +{ + + const Sequence<Reference<reflection::XTypeDescription> > seqTD = xMethod->getExceptions(); + int len = seqTD.getLength(); + Sequence<Reference<reflection::XCompoundTypeDescription> > seqCTD(len); + Reference<reflection::XCompoundTypeDescription> * arCTD = seqCTD.getArray(); + for (int i = 0; i < len; i++) + arCTD[i] = Reference<reflection::XCompoundTypeDescription>(seqTD[i], UNO_QUERY_THROW); + return get_exception_attribute(seqCTD); +} + +Emit::CustomAttributeBuilder* TypeEmitter::get_exception_attribute( + + const Sequence<Reference< reflection::XCompoundTypeDescription > >& seq_exceptionsTd ) +{ + Emit::CustomAttributeBuilder * attr_builder = NULL; + + Reference< reflection::XCompoundTypeDescription > const * exceptions = + seq_exceptionsTd.getConstArray(); + + ::System::Type * arTypesCtor[] = {::System::Type::GetType(S"System.Type[]")}; + ConstructorInfo * ctor_ExceptionAttribute = + __typeof(::uno::ExceptionAttribute)->GetConstructor(arTypesCtor); + + sal_Int32 exc_length = seq_exceptionsTd.getLength(); + if (exc_length != 0) // opt + { + ::System::Type * exception_types [] = + new ::System::Type * [ exc_length ]; + for ( sal_Int32 exc_pos = 0; exc_pos < exc_length; ++exc_pos ) + { + Reference< reflection::XCompoundTypeDescription > const & xExc = + exceptions[ exc_pos ]; + exception_types[ exc_pos ] = get_type( xExc ); + } + ::System::Object * args [] = {exception_types}; + attr_builder = new Emit::CustomAttributeBuilder( + ctor_ExceptionAttribute, args ); + } + return attr_builder; +} + + +::System::Type * TypeEmitter::complete_singleton_type(singleton_entry * entry) +{ + Emit::TypeBuilder * type_builder = entry->m_type_builder; + reflection::XSingletonTypeDescription2 * xSingletonType = entry->m_xType; + ::System::String* sSingletonName = to_cts_name(xSingletonType->getName()); + + //Create the private default constructor + Emit::ConstructorBuilder* ctor_builder = + type_builder->DefineConstructor( + static_cast<MethodAttributes>(MethodAttributes::Private | + MethodAttributes::HideBySig | + MethodAttributes::SpecialName | + MethodAttributes::RTSpecialName), + CallingConventions::Standard, NULL); + + Emit::ILGenerator* ilGen = ctor_builder->GetILGenerator(); + ilGen->Emit( Emit::OpCodes::Ldarg_0 ); // push this + ilGen->Emit( + Emit::OpCodes::Call, + type_builder->BaseType->GetConstructor(new ::System::Type*[0])); + ilGen->Emit( Emit::OpCodes::Ret ); + + + //obtain the interface which makes up this service, it is the return + //type of the constructor functions + Reference<reflection::XInterfaceTypeDescription2> xIfaceType( + xSingletonType->getInterface(), UNO_QUERY); + if (xIfaceType.is () == sal_False) + xIfaceType = resolveInterfaceTypedef(xSingletonType->getInterface()); + System::Type * retType = get_type(xIfaceType); + + //define method + ::System::Type * arTypeParameters[] = {get_type(S"unoidl.com.sun.star.uno.XComponentContext", true)}; + Emit::MethodBuilder* method_builder = type_builder->DefineMethod( + new System::String(S"get"), + static_cast<MethodAttributes>(MethodAttributes::Public | MethodAttributes::HideBySig | + MethodAttributes::Static), + retType, + arTypeParameters); + + +// method_builder->SetCustomAttribute(get_service_ctor_method_attribute(ctorDes)); + + //The first parameter is the XComponentContext, which cannot be obtained + //from reflection. + //The context is not part of the idl description + method_builder->DefineParameter(1, ParameterAttributes::In, S"the_context"); + + + ilGen = method_builder->GetILGenerator(); + //Define locals --------------------------------- + // Any, returned by XComponentContext.getValueByName + Emit::LocalBuilder* local_any = + ilGen->DeclareLocal(__typeof(::uno::Any)); + + //Call XContext::getValueByName + ilGen->Emit(Emit::OpCodes::Ldarg_0); + // build the singleton name : /singleton/unoidl.com.sun.star.XXX + ::System::Text::StringBuilder* sBuilder = + new ::System::Text::StringBuilder(S"/singletons/"); + sBuilder->Append(sSingletonName); + ilGen->Emit(Emit::OpCodes::Ldstr, sBuilder->ToString()); + + ::System::Reflection::MethodInfo * methodGetValueByName = + get_type(S"unoidl.com.sun.star.uno.XComponentContext", true)->GetMethod(S"getValueByName"); + ilGen->Emit(Emit::OpCodes::Callvirt, methodGetValueByName); + ilGen->Emit(Emit::OpCodes::Stloc_0); + + //Contains the returned Any a value? + ilGen->Emit(Emit::OpCodes::Ldloca_S, local_any); + ::System::Reflection::MethodInfo * methodHasValue = + __typeof(::uno::Any)->GetMethod(S"hasValue"); + ilGen->Emit(Emit::OpCodes::Call, methodHasValue); + + //If not, then throw an DeploymentException + Emit::Label label_singleton_exists = ilGen->DefineLabel(); + ilGen->Emit(Emit::OpCodes::Brtrue_S, label_singleton_exists); + sBuilder = new ::System::Text::StringBuilder( + S"Component context fails to supply singleton "); + sBuilder->Append(sSingletonName); + sBuilder->Append(S" of type "); + sBuilder->Append(retType->FullName); + sBuilder->Append(S"."); + ilGen->Emit(Emit::OpCodes::Ldstr, sBuilder->ToString()); + ilGen->Emit(Emit::OpCodes::Ldarg_0); + ::System::Type * arTypesCtorDeploymentException[] = { + __typeof(::System::String), __typeof(::System::Object)}; + ilGen->Emit(Emit::OpCodes::Newobj, + get_type(S"unoidl.com.sun.star.uno.DeploymentException",true) + ->GetConstructor(arTypesCtorDeploymentException)); + ilGen->Emit(Emit::OpCodes::Throw); + ilGen->MarkLabel(label_singleton_exists); + + //Cast the singleton contained in the Any to the expected interface and return it. + ilGen->Emit(Emit::OpCodes::Ldloca_S, local_any); + ilGen->Emit(Emit::OpCodes::Call, __typeof(::uno::Any)->GetProperty(S"Value")->GetGetMethod()); + ilGen->Emit(Emit::OpCodes::Castclass, retType); + ilGen->Emit(Emit::OpCodes::Ret); + + // remove from incomplete types map + ::System::String * cts_name = type_builder->get_FullName(); + m_incomplete_singletons->Remove( cts_name ); + xSingletonType->release(); + if (g_verbose) + { + ::System::Console::WriteLine( + "> emitting singleton type {0}", cts_name ); + } + return type_builder->CreateType(); +} + + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_type( + Reference< reflection::XTypeDescription > const & xType ) +{ + switch (xType->getTypeClass()) + { + case TypeClass_VOID: + return __typeof (::System::Void); + case TypeClass_CHAR: + return __typeof (::System::Char); + case TypeClass_BOOLEAN: + return __typeof (::System::Boolean); + case TypeClass_BYTE: + return __typeof (::System::Byte); + case TypeClass_SHORT: + return __typeof (::System::Int16); + case TypeClass_UNSIGNED_SHORT: + return __typeof (::System::UInt16); + case TypeClass_LONG: + return __typeof (::System::Int32); + case TypeClass_UNSIGNED_LONG: + return __typeof (::System::UInt32); + case TypeClass_HYPER: + return __typeof (::System::Int64); + case TypeClass_UNSIGNED_HYPER: + return __typeof (::System::UInt64); + case TypeClass_FLOAT: + return __typeof (::System::Single); + case TypeClass_DOUBLE: + return __typeof (::System::Double); + case TypeClass_STRING: + return __typeof (::System::String); + case TypeClass_TYPE: + return __typeof (::System::Type); + case TypeClass_ANY: + return __typeof(::uno::Any); + case TypeClass_ENUM: + return get_type( Reference< reflection::XEnumTypeDescription >( + xType, UNO_QUERY_THROW ) ); + case TypeClass_TYPEDEF: + // unwind typedefs + return get_type( + Reference< reflection::XIndirectTypeDescription >( + xType, UNO_QUERY_THROW )->getReferencedType() ); + case TypeClass_STRUCT: + case TypeClass_EXCEPTION: + return get_type( + Reference< reflection::XCompoundTypeDescription >( + xType, UNO_QUERY_THROW ) ); + case TypeClass_SEQUENCE: + { + ::System::Type * element_type = get_type( + Reference< reflection::XIndirectTypeDescription >( + xType, UNO_QUERY_THROW )->getReferencedType() ); + ::System::Type * retType = get_type( + ::System::String::Concat( + element_type->get_FullName(), S"[]" ), true ); + + ::uno::PolymorphicType * pt = dynamic_cast< ::uno::PolymorphicType * >(element_type); + if (pt) + { + ::System::String * sName = ::System::String::Concat(pt->PolymorphicName, S"[]"); + retType = ::uno::PolymorphicType::GetType(retType, sName); + } + return retType; + } + case TypeClass_INTERFACE: + return get_type( + Reference< reflection::XInterfaceTypeDescription2 >( + xType, UNO_QUERY_THROW ) ); + case TypeClass_CONSTANT: + return get_type( + Reference< reflection::XConstantTypeDescription >( + xType, UNO_QUERY_THROW ) ); + case TypeClass_CONSTANTS: + return get_type( + Reference< reflection::XConstantsTypeDescription >( + xType, UNO_QUERY_THROW ) ); + case TypeClass_SERVICE: + return get_type( + Reference< reflection::XServiceTypeDescription2 >( + xType, UNO_QUERY_THROW) ); + case TypeClass_SINGLETON: + return get_type( + Reference< reflection::XSingletonTypeDescription2 >( + xType, UNO_QUERY_THROW) ); + case TypeClass_MODULE: + // ignore these + return 0; + default: + throw RuntimeException( + OUSTR("unexpected type ") + xType->getName(), + Reference< XInterface >() ); + } +} + +//______________________________________________________________________________ +::System::Type * TypeEmitter::get_complete_struct( ::System::String * sName) +{ + struct_entry * pStruct = __try_cast< struct_entry *>( + m_incomplete_structs->get_Item(sName)); + if (pStruct) + { + complete_struct_type(pStruct); + } + //get_type will asked the module builder for the type or otherwise all known assemblies. + return get_type(sName, true); +} +void TypeEmitter::Dispose() +{ + while (true) + { + ::System::Collections::IDictionaryEnumerator * enumerator = + m_incomplete_ifaces->GetEnumerator(); + if (! enumerator->MoveNext()) + break; + complete_iface_type( + __try_cast< iface_entry * >( enumerator->get_Value() ) ); + } + + while (true) + { + ::System::Collections::IDictionaryEnumerator * enumerator = + m_incomplete_structs->GetEnumerator(); + if (! enumerator->MoveNext()) + break; + complete_struct_type( + __try_cast< struct_entry * >( enumerator->get_Value() ) ); + } + + + while (true) + { + ::System::Collections::IDictionaryEnumerator * enumerator = + m_incomplete_services->GetEnumerator(); + if (! enumerator->MoveNext()) + break; + complete_service_type( + __try_cast< service_entry * >( enumerator->get_Value() ) ); + } + + while (true) + { + ::System::Collections::IDictionaryEnumerator * enumerator = + m_incomplete_singletons->GetEnumerator(); + if (! enumerator->MoveNext()) + break; + complete_singleton_type( + __try_cast< singleton_entry * >( enumerator->get_Value() ) ); + } +} +//______________________________________________________________________________ +TypeEmitter::TypeEmitter( + ::System::Reflection::Emit::ModuleBuilder * module_builder, + ::System::Reflection::Assembly * extra_assemblies [] ) + : m_module_builder( module_builder ), + m_extra_assemblies( extra_assemblies ), + m_method_info_Type_GetTypeFromHandle( 0 ), + m_type_Exception( 0 ), + m_type_RuntimeException( 0 ), + m_incomplete_ifaces( new ::System::Collections::Hashtable() ), + m_incomplete_structs( new ::System::Collections::Hashtable() ), + m_incomplete_services(new ::System::Collections::Hashtable() ), + m_incomplete_singletons(new ::System::Collections::Hashtable() ), + m_generated_structs( new ::System::Collections::Hashtable() ) +{ + ::System::Type * param_types[] = new ::System::Type * [ 1 ]; + param_types[ 0 ] = __typeof (::System::RuntimeTypeHandle); + m_method_info_Type_GetTypeFromHandle = + __typeof (::System::Type) + ->GetMethod( "GetTypeFromHandle", param_types ); +} + +::System::Collections::ArrayList * TypeEmitter::get_service_ctor_method_exceptions_reduced( + const Sequence<Reference<reflection::XCompoundTypeDescription> > & seqExceptionsTd) +{ + if (seqExceptionsTd.getLength() == 0) + return new ::System::Collections::ArrayList(); + + ::System::Collections::ArrayList * arTypes = new ::System::Collections::ArrayList(); + for (int i = 0; i < seqExceptionsTd.getLength(); i++) + arTypes->Add(get_type(to_cts_name(seqExceptionsTd[i]->getName()), true)); + + int start = 0; + while (true) + { + bool bRemove = false; + for (int i = start; i < arTypes->Count; i++) + { + ::System::Type * t = __try_cast< ::System::Type* >(arTypes->get_Item(i)); + for (int j = 0; j < arTypes->Count; j++) + { + if (t->IsSubclassOf(__try_cast< ::System::Type* >(arTypes->get_Item(j)))) + { + arTypes->RemoveAt(i); + bRemove = true; + break; + } + } + if (bRemove) + break; + start++; + } + + if (bRemove == false) + break; + } + return arTypes; +} + + +css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > +resolveInterfaceTypedef( + const css::uno::Reference<css::reflection::XTypeDescription>& type) +{ + Reference<reflection::XInterfaceTypeDescription2> + xIfaceTd(type, UNO_QUERY); + + if (xIfaceTd.is()) + return xIfaceTd; + + Reference<reflection::XIndirectTypeDescription> xIndTd( + type, UNO_QUERY); + if (xIndTd.is() == sal_False) + throw css::uno::Exception( + OUSTR("resolveInterfaceTypedef was called with an invalid argument"), 0); + + return resolveInterfaceTypedef(xIndTd->getReferencedType()); +} + + +} diff --git a/cli_ure/source/climaker/climaker_share.h b/cli_ure/source/climaker/climaker_share.h new file mode 100644 index 000000000000..c663f007015b --- /dev/null +++ b/cli_ure/source/climaker/climaker_share.h @@ -0,0 +1,268 @@ +/************************************************************************* + * + * 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 <mscorlib.dll> +#using <cli_basetypes.dll> + +#include <vcclr.h> + +#include "osl/diagnose.h" +#include "com/sun/star/reflection/XConstantTypeDescription.hpp" +#include "com/sun/star/reflection/XConstantsTypeDescription.hpp" +#include "com/sun/star/reflection/XEnumTypeDescription.hpp" +#include "com/sun/star/reflection/XInterfaceTypeDescription2.hpp" +#include "com/sun/star/reflection/XCompoundTypeDescription.hpp" +#include "com/sun/star/reflection/XServiceTypeDescription2.hpp" +#include "com/sun/star/reflection/XSingletonTypeDescription2.hpp" +#include "com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp" + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + + +namespace css = ::com::sun::star; + +namespace climaker +{ + +//------------------------------------------------------------------------------ +extern bool g_verbose; + +__gc struct Constants +{ + static const ::System::String * sUnoVoid = S"void"; + static const ::System::String * sUnoType = S"type"; + static const ::System::String * sUnoAny = S"any"; + static const ::System::String * sUnoBool = S"boolean"; + static const ::System::String * sUnoByte = S"byte"; + static const ::System::String * sUnoChar = S"char"; + static const ::System::String * sUnoShort = S"short"; + static const ::System::String * sUnoUShort = S"unsigned short"; + static const ::System::String * sUnoLong = S"long"; + static const ::System::String * sUnoULong = S"unsigned long"; + static const ::System::String * sUnoHyper = S"hyper"; + static const ::System::String * sUnoUHyper = S"unsigned hyper"; + static const ::System::String * sUnoString = S"string"; + static const ::System::String * sUnoFloat = S"float"; + static const ::System::String * sUnoDouble = S"double"; + static const ::System::String * sUnoXInterface = S"com.sun.star.uno.XInterface"; + static const ::System::String * sBrackets = S"[]"; + + static const System::String* sObject = S"System.Object"; + static const System::String* sType = S"System.Type"; + static const System::String* sUnoidl = S"unoidl."; + static const System::String* sVoid = S"System.Void"; + static const System::String* sAny = S"uno.Any"; + static const System::String* sBoolean = S"System.Boolean"; + static const System::String* sChar = S"System.Char"; + static const System::String* sByte = S"System.Byte"; + static const System::String* sInt16 = S"System.Int16"; + static const System::String* sUInt16 = S"System.UInt16"; + static const System::String* sInt32 = S"System.Int32"; + static const System::String* sUInt32 = S"System.UInt32"; + static const System::String* sInt64 = S"System.Int64"; + static const System::String* sUInt64 = S"System.UInt64"; + static const System::String* sString = S"System.String"; + static const System::String* sSingle = S"System.Single"; + static const System::String* sDouble = S"System.Double"; + static const System::String* sComma = new System::String(S","); + +}; + +//------------------------------------------------------------------------------ +inline ::System::String * ustring_to_String( ::rtl::OUString const & ustr ) +{ + return new ::System::String( ustr.getStr(), 0, ustr.getLength() ); +} + +//------------------------------------------------------------------------------ +inline ::rtl::OUString String_to_ustring( ::System::String * str ) +{ + OSL_ASSERT( sizeof (wchar_t) == sizeof (sal_Unicode) ); + wchar_t const __pin * chars = PtrToStringChars( str ); + return ::rtl::OUString( chars, str->get_Length() ); +} + +/* If the argument type is a typedef for an interface then the interface + type description is returned, otherwise an exeption is thrown. +*/ +css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > +resolveInterfaceTypedef(const css::uno::Reference<css::reflection::XTypeDescription>& type); + +const ::System::Reflection::MethodAttributes c_ctor_method_attr = +(::System::Reflection::MethodAttributes) + (::System::Reflection::MethodAttributes::Public | + ::System::Reflection::MethodAttributes::HideBySig | + ::System::Reflection::MethodAttributes::SpecialName | + ::System::Reflection::MethodAttributes::RTSpecialName + /* | xxx todo: ??? compiler does not know Instance ??? + ::System::Reflection::MethodAttributes::Instance*/); + +//============================================================================== +__gc class TypeEmitter : public ::System::IDisposable +{ + ::System::Reflection::Emit::ModuleBuilder * m_module_builder; + ::System::Reflection::Assembly * m_extra_assemblies __gc []; + + ::System::Reflection::MethodInfo * m_method_info_Type_GetTypeFromHandle; + + ::System::Type * m_type_Exception; + ::System::Type * get_type_Exception(); + ::System::Type * m_type_RuntimeException; + ::System::Type * get_type_RuntimeException(); + + ::System::Reflection::Emit::CustomAttributeBuilder* get_service_exception_attribute( + const css::uno::Reference<css::reflection::XServiceConstructorDescription> & ctorDesc); + ::System::Reflection::Emit::CustomAttributeBuilder* get_iface_method_exception_attribute( + const css::uno::Reference< css::reflection::XInterfaceMethodTypeDescription >& xMethod ); + ::System::Reflection::Emit::CustomAttributeBuilder* get_exception_attribute( + const css::uno::Sequence<css::uno::Reference< + css::reflection::XCompoundTypeDescription > >& seq_exceptionsTd ); +/* Creates ::System::Type object for UNO exceptions. The UNO exceptions are + obtained by + com::sun::star::reflection::XServiceConstructorDescription::getExceptions + In a first step the respective CLI types are created. Then it is examined + if a Type represents a super class of another class. If so the Type of the + derived class is discarded. For example there are a uno RuntimeException and + a DeploymentException which inherits RuntimeException. Then only the cli Type + of the RuntimeException is returned. + The purpose of this function is to provide exceptions for which catch blocks + are generated in the service constructor code. + + It is always an instance of an ArrayList returned, even if the sequence argument + does not contain elements. + */ + ::System::Collections::ArrayList * get_service_ctor_method_exceptions_reduced( + const css::uno::Sequence< + css::uno::Reference<css::reflection::XCompoundTypeDescription> > & seqExceptionsTd); + + + __gc class iface_entry + { + public: + css::reflection::XInterfaceTypeDescription2 * m_xType; + ::System::Reflection::Emit::TypeBuilder * m_type_builder; + }; + ::System::Collections::Hashtable * m_incomplete_ifaces; + ::System::Type * complete_iface_type( iface_entry * entry ); + + __gc class struct_entry + { + public: + css::reflection::XCompoundTypeDescription * m_xType; + ::System::Reflection::Emit::TypeBuilder * m_type_builder; + ::System::Type * m_base_type; + + ::System::String * m_member_names __gc []; + ::System::Type * m_param_types __gc []; + ::System::Reflection::ConstructorInfo * m_default_ctor; + ::System::Reflection::ConstructorInfo * m_ctor; + }; + ::System::Collections::Hashtable * m_incomplete_structs; + ::System::Type * complete_struct_type( struct_entry * entry ); + + /* returns the type for the name. If it is a struct then it may + complete the struct if not already done. This also refers to its + base types. + + @param sName + the full name of the type. + @return the type object for sName. Not necessarily a struct. + */ + ::System::Type * get_complete_struct( ::System::String * sName); + + __gc class service_entry + { + public: + ::System::Reflection::Emit::TypeBuilder * m_type_builder; + css::reflection::XServiceTypeDescription2 * m_xType; + }; + ::System::Collections::Hashtable * m_incomplete_services; + ::System::Type * complete_service_type(service_entry * entry); + + __gc class singleton_entry + { + public: + ::System::Reflection::Emit::TypeBuilder * m_type_builder; + css::reflection::XSingletonTypeDescription2 * m_xType; + }; + + + ::System::Collections::Hashtable * m_incomplete_singletons; + ::System::Type * complete_singleton_type(singleton_entry * entry); + + + ::System::Collections::Hashtable * m_generated_structs; + + ::System::Type * get_type( + ::System::String * cli_name, bool throw_exc ); + ::System::Type * get_type( + css::uno::Reference< + css::reflection::XConstantTypeDescription > const & xType ); + ::System::Type * get_type( + css::uno::Reference< + css::reflection::XConstantsTypeDescription > const & xType ); + ::System::Type * get_type( + css::uno::Reference< + css::reflection::XEnumTypeDescription > const & xType ); + /* returns the type for a struct or exception. In case of a polymorphic struct it may + return a ::uno::PolymorphicType (cli_basetypes.dll) only if the struct is already + complete. + */ + ::System::Type * get_type( + css::uno::Reference< + css::reflection::XCompoundTypeDescription > const & xType ); + ::System::Type * get_type( + css::uno::Reference< + css::reflection::XInterfaceTypeDescription2 > const & xType ); + ::System::Type * get_type( + css::uno::Reference< + css::reflection::XSingletonTypeDescription2 > const & xType ); + + /* + May return NULL if the service description is an obsolete. See + description of + com.sun.star.reflection.XServiceTypeDescription2.isSingleInterfaceBased + */ + ::System::Type * get_type( + css::uno::Reference< + css::reflection::XServiceTypeDescription2 > const & xType ); +public: + TypeEmitter( + ::System::Reflection::Emit::ModuleBuilder * module_builder, + ::System::Reflection::Assembly * assemblies __gc [] ); + // must be called to finish up uncompleted types + void Dispose(); + + ::System::Reflection::Assembly * type_resolve( + ::System::Object * sender, ::System::ResolveEventArgs * args ); + + ::System::Type * get_type( + css::uno::Reference< + css::reflection::XTypeDescription > const & xType ); +}; + +} diff --git a/cli_ure/source/climaker/makefile.mk b/cli_ure/source/climaker/makefile.mk new file mode 100644 index 000000000000..b001a1545fae --- /dev/null +++ b/cli_ure/source/climaker/makefile.mk @@ -0,0 +1,137 @@ +#************************************************************************* +# +# 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 = cli_ure + +TARGET = climaker +TARGETTYPE = CUI +LIBTARGET = NO +ENABLE_EXCEPTIONS = TRUE + +# disable caching to avoid stale objects +# on version changes +CCACHE_DISABLE=TRUE +.EXPORT : CCACHE_DISABLE + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +.IF "$(BUILD_FOR_CLI)" != "" + +NO_OFFUH=TRUE +CPPUMAKERFLAGS = + +UNOTYPES = \ + com.sun.star.uno.TypeClass \ + com.sun.star.uno.XAggregation \ + com.sun.star.uno.XWeak \ + com.sun.star.uno.XComponentContext \ + com.sun.star.lang.XTypeProvider \ + com.sun.star.lang.XInitialization \ + com.sun.star.lang.XComponent \ + com.sun.star.lang.XMultiComponentFactory \ + com.sun.star.lang.XMultiServiceFactory \ + com.sun.star.lang.XSingleComponentFactory \ + com.sun.star.container.XSet \ + com.sun.star.container.XHierarchicalNameAccess \ + com.sun.star.loader.XImplementationLoader \ + com.sun.star.registry.XSimpleRegistry \ + com.sun.star.registry.XRegistryKey \ + com.sun.star.reflection.XTypeDescriptionEnumerationAccess \ + com.sun.star.reflection.XConstantTypeDescription \ + com.sun.star.reflection.XConstantsTypeDescription \ + com.sun.star.reflection.XIndirectTypeDescription \ + com.sun.star.reflection.XEnumTypeDescription \ + com.sun.star.reflection.XInterfaceTypeDescription2 \ + com.sun.star.reflection.XInterfaceMethodTypeDescription \ + com.sun.star.reflection.XInterfaceAttributeTypeDescription2 \ + com.sun.star.reflection.XCompoundTypeDescription \ + com.sun.star.reflection.XServiceTypeDescription2 \ + com.sun.star.reflection.XSingletonTypeDescription2 \ + com.sun.star.reflection.XStructTypeDescription + +CFLAGSCXX +=-AI$(BIN) + + +# When compiling for CLR, disable "warning C4339: use of undefined type detected +# in CLR meta-data - use of this type may lead to a runtime exception": +.IF "$(COMEX)"=="10" +CFLAGSCXX += -clr:noAssembly -wd4339 +.ELSE +CFLAGSCXX += -clr:oldSyntax -LN -wd4339 -wd4715 +.ENDIF + +OBJFILES = \ + $(OBJ)$/climaker_app.obj \ + $(OBJ)$/climaker_emit.obj + +APP1TARGET = $(TARGET) +APP1OBJS = $(OBJFILES) + + +APP1STDLIBS = \ + $(CPPUHELPERLIB) \ + $(CPPULIB) \ + $(SALLIB) \ + mscoree.lib + +.IF "$(CCNUMVER)" >= "001399999999" +APP1STDLIBS += \ + msvcmrt.lib +.ENDIF + +.ENDIF + + + +.INCLUDE : $(PRJ)$/util$/target.pmk +.INCLUDE : target.mk + +CLIMAKER_CONFIG = $(BIN)$/climaker.exe.config + +ALLTAR: \ + $(CLIMAKER_CONFIG) + + + +#Create the config file that is used with the policy assembly +$(CLIMAKER_CONFIG): climaker.exe.config + $(COPY) $< $@ + chmod +x $@ + + +.IF "$(BUILD_FOR_CLI)" != "" + +$(OBJFILES): $(BIN)$/cli_basetypes.dll + + +.ENDIF + + + + diff --git a/cli_ure/source/cliuno.snk b/cli_ure/source/cliuno.snk Binary files differnew file mode 100644 index 000000000000..938f16939fdd --- /dev/null +++ b/cli_ure/source/cliuno.snk diff --git a/cli_ure/source/makefile.mk b/cli_ure/source/makefile.mk new file mode 100644 index 000000000000..a6183f28739c --- /dev/null +++ b/cli_ure/source/makefile.mk @@ -0,0 +1,48 @@ +#************************************************************************* +# +# 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 = cli_ure + +# for dummy +TARGET = sourcedir + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +.INCLUDE : $(PRJ)$/util$/target.pmk +.INCLUDE : target.mk + +.IF "$(BUILD_FOR_CLI)" != "" + +ALLTAR : \ + $(OUT)$/bin$/cliuno.snk + +$(OUT)$/bin$/cliuno.snk : + $(GNUCOPY) -p cliuno.snk $@ + +.ENDIF diff --git a/cli_ure/source/native/assembly.cxx b/cli_ure/source/native/assembly.cxx new file mode 100644 index 000000000000..c7a979b49f81 --- /dev/null +++ b/cli_ure/source/native/assembly.cxx @@ -0,0 +1,36 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" +#using <mscorlib.dll> + +[assembly:System::Reflection::AssemblyProduct( "CLI-UNO Language Binding" )]; +[assembly:System::Reflection::AssemblyDescription( "CLI-UNO Helper Library" )]; +[assembly:System::Reflection::AssemblyDelaySign(true)]; +[assembly:System::Reflection::AssemblyCompany( "OpenOffice.org" )]; diff --git a/cli_ure/source/native/cli_cppuhelper_config b/cli_ure/source/native/cli_cppuhelper_config new file mode 100644 index 000000000000..627a3a564f27 --- /dev/null +++ b/cli_ure/source/native/cli_cppuhelper_config @@ -0,0 +1,11 @@ +<?xml version="1.0"?> +<configuration> + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="cli_cppuhelper" publicKeyToken="ce2cb7e279207b9e"/> + <bindingRedirect oldVersion="CLI_CPPUHELPER_OLD_VERSION" newVersion="CLI_CPPUHELPER_NEW_VERSION" /> + </dependentAssembly> + </assemblyBinding> + </runtime> +</configuration>
\ No newline at end of file diff --git a/cli_ure/source/native/makefile.mk b/cli_ure/source/native/makefile.mk new file mode 100644 index 000000000000..2c8be1a9b5b9 --- /dev/null +++ b/cli_ure/source/native/makefile.mk @@ -0,0 +1,184 @@ +#************************************************************************* +# +# 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 = cli_ure + +TARGET = cli_cppuhelper +NO_BSYMBOLIC = TRUE +ENABLE_EXCEPTIONS = TRUE +LIBTARGET = NO +USE_DEFFILE = TRUE + +# disable caching to avoid stale objects +# on version changes +CCACHE_DISABLE=TRUE +.EXPORT : CCACHE_DISABLE + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +use_shl_versions= + +.IF "$(BUILD_FOR_CLI)" == "" +#do not even build the cxx files because they contain cli cpp +all: +.ELSE + +.INCLUDE : $(BIN)$/cliureversion.mk + +ASSEMBLY_KEY="$(BIN)$/cliuno.snk" + +ASSEMBLY_ATTRIBUTES = $(MISC)$/assembly_cppuhelper.cxx + +POLICY_ASSEMBLY_FILE=$(BIN)$/$(CLI_CPPUHELPER_POLICY_ASSEMBLY).dll + +ASSEMBLY_KEY_X=$(subst,\,\\ $(ASSEMBLY_KEY)) + + +LINKFLAGS += /delayload:cppuhelper3MSC.dll \ + /delayload:cppu3.dll \ + /delayload:sal3.dll + +UWINAPILIB= + +NO_OFFUH=TRUE +CPPUMAKERFLAGS = +UNOTYPES = \ + com.sun.star.lang.XSingleComponentFactory \ + com.sun.star.loader.CannotActivateFactoryException \ + com.sun.star.container.XHierarchicalNameAccess \ + com.sun.star.registry.CannotRegisterImplementationException \ + com.sun.star.registry.XRegistryKey \ + com.sun.star.registry.XSimpleRegistry + +#loader lock was solved as of VS 2005 (CCNUMVER = 0014..) +# When compiling for CLR, disable "warning C4339: use of undefined type detected +# in CLR meta-data - use of this type may lead to a runtime exception": +.IF "$(CCNUMVER)" >= "001399999999" +CFLAGSCXX += -clr:oldSyntax -AI $(BIN) -wd4339 +.ELSE +CFLAGSCXX += -clr -AI $(BIN) -wd4339 +#see Microsoft Knowledge Base Article - 814472 +LINKFLAGS += -NOENTRY -NODEFAULTLIB:nochkclr.obj -INCLUDE:__DllMainCRTStartup@12 +.ENDIF + +SLOFILES = \ + $(SLO)$/native_bootstrap.obj \ + $(SLO)$/path.obj \ + $(SLO)$/assembly_cppuhelper.obj + + +SHL1OBJS = $(SLOFILES) + +SHL1TARGET = $(TARGET) + +SHL1STDLIBS = \ + $(CPPUHELPERLIB) \ + $(CPPULIB) \ + $(SALLIB) \ + delayimp.lib \ + advapi32.lib \ + mscoree.lib \ + Advapi32.lib + +.IF "$(CCNUMVER)" >= "001399999999" +SHL1STDLIBS += \ + msvcmrt.lib +.ENDIF + +SHL1VERSIONMAP = msvc.map + +SHL1DEF = $(MISC)$/$(SHL1TARGET).def +DEF1NAME = $(SHL1TARGET) + + +.INCLUDE : $(PRJ)$/util$/target.pmk +.INCLUDE : target.mk + +SIGN= $(MISC)$/cppuhelper_is_signed_flag + +ALLTAR: \ + $(POLICY_ASSEMBLY_FILE) \ + $(SIGN) + + + +.IF "$(CCNUMVER)" >= "001399999999" +CFLAGSCXX += -clr:oldSyntax +.ENDIF + +$(ASSEMBLY_ATTRIBUTES) : assembly.cxx $(BIN)$/cliuno.snk $(BIN)$/cliureversion.mk + @echo $(ASSEMBLY_KEY_X) + $(GNUCOPY) -p assembly.cxx $@ + echo \ + '[assembly:System::Reflection::AssemblyVersion( "$(CLI_CPPUHELPER_NEW_VERSION)" )];' \ + >> $(OUT)$/misc$/assembly_cppuhelper.cxx + echo \ + '[assembly:System::Reflection::AssemblyKeyFile($(ASSEMBLY_KEY_X))];' \ + >> $(OUT)$/misc$/assembly_cppuhelper.cxx + + + +#make sure we build cli_cppuhelper after the version changed +$(SHL1OBJS) : $(BIN)$/cli_cppuhelper.config + + + +$(SIGN): $(SHL1TARGETN) + $(WRAPCMD) sn.exe -R $(BIN)$/$(TARGET).dll $(BIN)$/cliuno.snk && $(TOUCH) $@ + +#do not forget to deliver cli_cppuhelper.config. It is NOT embedded in the policy file. +.IF "$(CCNUMVER)" >= "001399999999" +#.NET 2 and higher +# If the x86 switch is ommitted then the system assumes the assembly to be MSIL. +# The policy file is still found when an application tries to load an older +# cli_cppuhelper.dll but the system cannot locate it. It possibly assumes that the +# assembly is also 'MSIL' like its policy file. +$(POLICY_ASSEMBLY_FILE) : $(BIN)$/cli_cppuhelper.config + $(WRAPCMD) AL.exe -out:$@ \ + -version:$(CLI_CPPUHELPER_POLICY_VERSION) \ + -keyfile:$(BIN)$/cliuno.snk \ + -link:$(BIN)$/cli_cppuhelper.config \ + -platform:x86 +.ELSE +#.NET 1.1: platform flag not needed +$(POLICY_ASSEMBLY_FILE) : $(BIN)$/cli_cppuhelper.config + $(WRAPCMD) AL.exe -out:$@ \ + -version:$(CLI_CPPUHELPER_POLICY_VERSION) \ + -keyfile:$(BIN)$/cliuno.snk \ + -link:$(BIN)$/cli_cppuhelper.config +.ENDIF + +#Create the config file that is used with the policy assembly +$(BIN)$/cli_cppuhelper.config: cli_cppuhelper_config $(BIN)$/cliureversion.mk + $(PERL) $(SOLARENV)$/bin$/clipatchconfig.pl \ + $< $@ + +.ENDIF # "$(BUILD_FOR_CLI)" != "" + diff --git a/cli_ure/source/native/msvc.map b/cli_ure/source/native/msvc.map new file mode 100644 index 000000000000..429f750cc2b0 --- /dev/null +++ b/cli_ure/source/native/msvc.map @@ -0,0 +1,6 @@ +UDK_3_0_0 { + global: + + local: + *; +}; diff --git a/cli_ure/source/native/native_bootstrap.cxx b/cli_ure/source/native/native_bootstrap.cxx new file mode 100644 index 000000000000..13be868dc9fd --- /dev/null +++ b/cli_ure/source/native/native_bootstrap.cxx @@ -0,0 +1,433 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// Use UNICODE Windows and C API. +#define _UNICODE +#define UNICODE + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif +#include <windows.h> +#include "uno/environment.hxx" +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include <tchar.h> + +#include "native_share.h" + +#include "rtl/bootstrap.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "cppuhelper/bootstrap.hxx" +#include <delayimp.h> +#include <stdio.h> + +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace cli_ure { + WCHAR * resolveLink(WCHAR * path); +} + +#define INSTALL_PATH L"Software\\OpenOffice.org\\UNO\\InstallPath" +#define BASIS_LINK L"\\basis-link" +#define URE_LINK L"\\ure-link" +#define URE_BIN L"\\bin" +#define UNO_PATH L"UNO_PATH" + +namespace +{ + + /* + * Gets the installation path from the Windows Registry for the specified + * registry key. + * + * @param hroot open handle to predefined root registry key + * @param subKeyName name of the subkey to open + * + * @return the installation path or NULL, if no installation was found or + * if an error occured + */ +WCHAR* getPathFromRegistryKey( HKEY hroot, LPCWSTR subKeyName ) +{ + HKEY hkey; + DWORD type; + TCHAR* data = NULL; + DWORD size; + + /* open the specified registry key */ + if ( RegOpenKeyEx( hroot, subKeyName, 0, KEY_READ, &hkey ) != ERROR_SUCCESS ) + { + return NULL; + } + + /* find the type and size of the default value */ + if ( RegQueryValueEx( hkey, NULL, NULL, &type, NULL, &size) != ERROR_SUCCESS ) + { + RegCloseKey( hkey ); + return NULL; + } + + /* get memory to hold the default value */ + data = new WCHAR[size]; + + /* read the default value */ + if ( RegQueryValueEx( hkey, NULL, NULL, &type, (LPBYTE) data, &size ) != ERROR_SUCCESS ) + { + RegCloseKey( hkey ); + return NULL; + } + + /* release registry key handle */ + RegCloseKey( hkey ); + + return data; +} + +/* If the path does not end with '\' the las segment will be removed. + path: C:\a\b + -> C:\a + @param io_path + in/out parameter. The string is not reallocated. Simply a '\0' + will be inserted to shorten the string. +*/ +void oneDirUp(LPTSTR io_path) +{ + WCHAR * pEnd = io_path + lstrlen(io_path) - 1; + while (pEnd > io_path //prevent crashing if provided string does not contain a backslash + && *pEnd != L'\\') + pEnd --; + *pEnd = L'\0'; +} + + +/* Returns the path to the program folder of the brand layer, + for example c:/openoffice.org 3/program + This path is either obtained from the environment variable UNO_PATH + or the registry item + "Software\\OpenOffice.org\\UNO\\InstallPath" + either in HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE + The return value must be freed with delete[] +*/ +WCHAR * getInstallPath() +{ + WCHAR * szInstallPath = NULL; + + DWORD cChars = GetEnvironmentVariable(UNO_PATH, NULL, 0); + if (cChars > 0) + { + szInstallPath = new WCHAR[cChars]; + cChars = GetEnvironmentVariable(UNO_PATH, szInstallPath, cChars); + //If PATH is not set then it is no error + if (cChars == 0) + { + delete[] szInstallPath; + return NULL; + } + } + + if (! szInstallPath) + { + szInstallPath = getPathFromRegistryKey( HKEY_CURRENT_USER, INSTALL_PATH ); + if ( szInstallPath == NULL ) + { + /* read the key's default value from HKEY_LOCAL_MACHINE */ + szInstallPath = getPathFromRegistryKey( HKEY_LOCAL_MACHINE, INSTALL_PATH ); + } + } + return szInstallPath; +} + +/* Returns the path to the URE/bin path, where cppuhelper lib resides. + The returned string must be freed with delete[] +*/ +WCHAR* getUnoPath() +{ + WCHAR * szLinkPath = NULL; + WCHAR * szUrePath = NULL; + WCHAR * szUreBin = NULL; //the return value + + WCHAR * szInstallPath = getInstallPath(); + if (szInstallPath) + { + //build the path tho the basis-link file + oneDirUp(szInstallPath); + int sizeLinkPath = lstrlen(szInstallPath) + lstrlen(INSTALL_PATH) + 1; + if (sizeLinkPath < MAX_PATH) + sizeLinkPath = MAX_PATH; + szLinkPath = new WCHAR[sizeLinkPath]; + szLinkPath[0] = L'\0'; + lstrcat(szLinkPath, szInstallPath); + lstrcat(szLinkPath, BASIS_LINK); + + //get the path to the actual Basis folder + if (cli_ure::resolveLink(szLinkPath)) + { + //build the path to the ure-link file + int sizeUrePath = lstrlen(szLinkPath) + lstrlen(URE_LINK) + 1; + if (sizeUrePath < MAX_PATH) + sizeUrePath = MAX_PATH; + szUrePath = new WCHAR[sizeUrePath]; + szUrePath[0] = L'\0'; + lstrcat(szUrePath, szLinkPath); + lstrcat(szUrePath, URE_LINK); + + //get the path to the actual Ure folder + if (cli_ure::resolveLink(szUrePath)) + { + //build the path to the URE/bin directory + szUreBin = new WCHAR[lstrlen(szUrePath) + lstrlen(URE_BIN) + 1]; + szUreBin[0] = L'\0'; + lstrcat(szUreBin, szUrePath); + lstrcat(szUreBin, URE_BIN); + } + } + } +#if OSL_DEBUG_LEVEL >=2 + if (szUreBin) + { + fwprintf(stdout,L"[cli_cppuhelper]: Path to URE libraries:\n %s \n", szUreBin); + } + else + { + fwprintf(stdout,L"[cli_cppuhelper]: Failed to determine location of URE.\n"); + } +#endif + delete[] szInstallPath; + delete[] szLinkPath; + delete[] szUrePath; + return szUreBin; +} + + +/*We extend the path to contain the Ure/bin folder, + so that components can use osl_loadModule with arguments, such as + "reg3.dll". That is, the arguments are only the library names. +*/ +void extendPath(LPCWSTR szUreBinPath) +{ + if (!szUreBinPath) + return; + + WCHAR * sEnvPath = NULL; + DWORD cChars = GetEnvironmentVariable(L"PATH", sEnvPath, 0); + if (cChars > 0) + { + sEnvPath = new WCHAR[cChars]; + cChars = GetEnvironmentVariable(L"PATH", sEnvPath, cChars); + //If PATH is not set then it is no error + if (cChars == 0 && GetLastError() != ERROR_ENVVAR_NOT_FOUND) + { + delete[] sEnvPath; + return; + } + } + //prepare the new PATH. Add the Ure/bin directory at the front. + //note also adding ';' + WCHAR * sNewPath = new WCHAR[lstrlen(sEnvPath) + lstrlen(szUreBinPath) + 2]; + sNewPath[0] = L'\0'; + lstrcat(sNewPath, szUreBinPath); + if (lstrlen(sEnvPath)) + { + lstrcat(sNewPath, L";"); + lstrcat(sNewPath, sEnvPath); + } + BOOL bSet = SetEnvironmentVariable(L"PATH", sNewPath); + + delete[] sEnvPath; + delete[] sNewPath; +} + + +HMODULE loadFromPath(LPCWSTR sLibName) +{ + if (sLibName == NULL) + return NULL; + + WCHAR * szUreBinPath = getUnoPath(); + if (!szUreBinPath) + return NULL; + + extendPath(szUreBinPath); + + WCHAR* szFullPath = new WCHAR[lstrlen(sLibName) + lstrlen(szUreBinPath) + 2]; + szFullPath[0] = L'\0'; + lstrcat(szFullPath, szUreBinPath); + lstrcat(szFullPath, L"\\"); + lstrcat(szFullPath, sLibName); + HMODULE handle = LoadLibraryEx(szFullPath, NULL, + LOAD_WITH_ALTERED_SEARCH_PATH); + + delete[] szFullPath; + delete[] szUreBinPath; + return handle; +} + +/*Hook for delayed loading of libraries which this library is linked with. + This is a failure hook. That is, it is only called when the loading of + a library failed. It will be called when loading of cppuhelper failed. + Because we extend the PATH to the URE/bin folder while this function is + executed (see extendPath), all other libraries are found. +*/ +extern "C" FARPROC WINAPI delayLoadHook( + unsigned dliNotify, + PDelayLoadInfo pdli + ) +{ + if (dliNotify == dliFailLoadLib) + { + LPWSTR szLibName = NULL; + //Convert the ansi file name to wchar_t* + int size = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pdli->szDll, -1, NULL, 0); + if (size > 0) + { + szLibName = new WCHAR[size]; + if (! MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pdli->szDll, -1, szLibName, size)) + { + return 0; + } + } + HANDLE h = loadFromPath(szLibName); + delete[] szLibName; + return (FARPROC) h; + } + return 0; +} +} + +ExternC +PfnDliHook __pfnDliFailureHook2 = delayLoadHook; + +namespace uno +{ +namespace util +{ + +/** Bootstrapping native UNO. + + Bootstrapping requires the existence of many libraries which are contained + in an URE installation. To find and load these libraries the Windows + registry keys HKEY_CURRENT_USER\Software\OpenOffice.org\Layer\URE\1 + and HKEY_LOCAL_MACHINE\Software\OpenOffice.org\Layer\URE\1 are examined. + These contain a named value UREINSTALLLOCATION which holds a path to the URE + installation folder. +*/ +public __sealed __gc class Bootstrap +{ + inline Bootstrap() {} + +public: + + /** Bootstraps the initial component context from a native UNO installation. + + @see cppuhelper/bootstrap.hxx:defaultBootstrap_InitialComponentContext() + */ + static ::unoidl::com::sun::star::uno::XComponentContext * + defaultBootstrap_InitialComponentContext(); + + /** Bootstraps the initial component context from a native UNO installation. + + @param ini_file + a file URL of an ini file, e.g. uno.ini/unorc. (The ini file must + reside next to the cppuhelper library) + @param bootstrap_parameters + bootstrap parameters (maybe null) + + @see cppuhelper/bootstrap.hxx:defaultBootstrap_InitialComponentContext() + */ + static ::unoidl::com::sun::star::uno::XComponentContext * + defaultBootstrap_InitialComponentContext( + ::System::String * ini_file, + ::System::Collections::IDictionaryEnumerator * + bootstrap_parameters ); + + /** Bootstraps the initial component context from a native UNO installation. + + @see cppuhelper/bootstrap.hxx:bootstrap() + */ + static ::unoidl::com::sun::star::uno::XComponentContext * + bootstrap(); +}; + +//______________________________________________________________________________ +::unoidl::com::sun::star::uno::XComponentContext * +Bootstrap::defaultBootstrap_InitialComponentContext( + ::System::String * ini_file, + ::System::Collections::IDictionaryEnumerator * bootstrap_parameters ) +{ + if (0 != bootstrap_parameters) + { + bootstrap_parameters->Reset(); + while (bootstrap_parameters->MoveNext()) + { + OUString key( + String_to_ustring( __try_cast< ::System::String * >( + bootstrap_parameters->get_Key() ) ) ); + OUString value( + String_to_ustring( __try_cast< ::System::String * >( + bootstrap_parameters->get_Value() ) ) ); + + ::rtl::Bootstrap::set( key, value ); + } + } + + // bootstrap native uno + Reference< XComponentContext > xContext; + if (0 == ini_file) + { + xContext = ::cppu::defaultBootstrap_InitialComponentContext(); + } + else + { + xContext = ::cppu::defaultBootstrap_InitialComponentContext( + String_to_ustring( __try_cast< ::System::String * >( ini_file ) ) ); + } + + return __try_cast< ::unoidl::com::sun::star::uno::XComponentContext * >( + to_cli( xContext ) ); +} + +//______________________________________________________________________________ +::unoidl::com::sun::star::uno::XComponentContext * +Bootstrap::defaultBootstrap_InitialComponentContext() +{ + return defaultBootstrap_InitialComponentContext( 0, 0 ); +} + +::unoidl::com::sun::star::uno::XComponentContext * Bootstrap::bootstrap() +{ + Reference<XComponentContext> xContext = ::cppu::bootstrap(); + return __try_cast< ::unoidl::com::sun::star::uno::XComponentContext * >( + to_cli( xContext ) ); + +} + +} +} diff --git a/cli_ure/source/native/native_share.h b/cli_ure/source/native/native_share.h new file mode 100644 index 000000000000..dff079b8d1db --- /dev/null +++ b/cli_ure/source/native/native_share.h @@ -0,0 +1,120 @@ +/************************************************************************* + * + * 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 <mscorlib.dll> +#using "cli_ure.dll" +#using "cli_uretypes.dll" + +#include "rtl/ustring.hxx" +#include "uno/mapping.hxx" + +#include <vcclr.h> + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + + +namespace uno +{ +namespace util +{ + +//------------------------------------------------------------------------------ +inline ::System::String * ustring_to_String( ::rtl::OUString const & ustr ) +{ + return new ::System::String( ustr.getStr(), 0, ustr.getLength() ); +} +//------------------------------------------------------------------------------ +inline ::rtl::OUString String_to_ustring( ::System::String * str ) +{ + OSL_ASSERT( sizeof (wchar_t) == sizeof (sal_Unicode) ); + wchar_t const __pin * chars = PtrToStringChars( str ); + return ::rtl::OUString( chars, str->get_Length() ); +} + +template< typename T > +inline ::System::Object * to_cli( + ::com::sun::star::uno::Reference< T > const & x ) +{ + ::com::sun::star::uno::Mapping mapping( + OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME), OUSTR(UNO_LB_CLI) ); + OSL_ASSERT( mapping.is() ); + if (! mapping.is()) + { + throw ::com::sun::star::uno::RuntimeException( + OUSTR("cannot get mapping from C++ to CLI!"), + ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XInterface >() ); + } + + intptr_t intptr = + reinterpret_cast< intptr_t >( + mapping.mapInterface( x.get(), ::getCppuType( &x ) ) ); + ::System::Runtime::InteropServices::GCHandle handle( + ::System::Runtime::InteropServices::GCHandle::op_Explicit( intptr ) ); + ::System::Object * ret = handle.get_Target(); + handle.Free(); + return ret; +} + +template< typename T > +inline void to_uno( + ::com::sun::star::uno::Reference< T > * pRet, ::System::Object * x ) +{ + ::com::sun::star::uno::Mapping mapping( + OUSTR(UNO_LB_CLI), OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME) ); + OSL_ASSERT( mapping.is() ); + if (! mapping.is()) + { + throw ::com::sun::star::uno::RuntimeException( + OUSTR("cannot get mapping from CLI to C++!"), + ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XInterface >() ); + } + + ::System::Runtime::InteropServices::GCHandle handle( + ::System::Runtime::InteropServices::GCHandle::Alloc( x ) ); + T * ret = 0; + mapping.mapInterface( + reinterpret_cast< void ** >( &ret ), + reinterpret_cast< void * >( + ::System::Runtime::InteropServices::GCHandle::op_Explicit( handle ) +#if defined _WIN32 + .ToInt32() +#elif defined _WIN64 + .ToInt64() +#else +#error ERROR: either _WIN64 or _WIN32 must be defined + ERROR: either _WIN64 or _WIN32 must be defined +#endif + ), + ::getCppuType( pRet ) ); + handle.Free(); + pRet->set( ret, SAL_NO_ACQUIRE /* takeover ownership */ ); +} + +} +} diff --git a/cli_ure/source/native/path.cxx b/cli_ure/source/native/path.cxx new file mode 100644 index 000000000000..56b5caf3b299 --- /dev/null +++ b/cli_ure/source/native/path.cxx @@ -0,0 +1,218 @@ +/************************************************************************* + * + * 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 "sal/config.h" + +#if defined WNT + +#include <cstddef> + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +#include "sal/types.h" +//#include "tools/pathutils.hxx" + +namespace cli_ure { + +WCHAR * filename(WCHAR * path) { + WCHAR * f = path; + for (WCHAR * p = path;;) { + switch (*p++) { + case L'\0': + return f; + case L'\\': + f = p; + break; + } + } +} + +WCHAR * buildPath( + WCHAR * path, WCHAR const * frontBegin, WCHAR const * frontEnd, + WCHAR const * backBegin, std::size_t backLength) +{ + // Remove leading ".." segments in the second path together with matching + // segments in the first path that are neither empty nor "." nor ".." nor + // end in ":" (which is not foolprove, as it can erroneously erase the start + // of a UNC path, but only if the input is bad data): + while (backLength >= 2 && backBegin[0] == L'.' && backBegin[1] == L'.' && + (backLength == 2 || backBegin[2] == L'\\')) + { + if (frontEnd - frontBegin < 2 || frontEnd[-1] != L'\\' || + frontEnd[-2] == L'\\' || frontEnd[-2] == L':' || + (frontEnd[-2] == L'.' && + (frontEnd - frontBegin < 3 || frontEnd[-3] == L'\\' || + (frontEnd[-3] == L'.' && + (frontEnd - frontBegin < 4 || frontEnd[-4] == L'\\'))))) + { + break; + } + WCHAR const * p = frontEnd - 1; + while (p != frontBegin && p[-1] != L'\\') { + --p; + } + if (p == frontBegin) { + break; + } + frontEnd = p; + if (backLength == 2) { + backBegin += 2; + backLength -= 2; + } else { + backBegin += 3; + backLength -= 3; + } + } + if (backLength < + static_cast< std::size_t >(MAX_PATH - (frontEnd - frontBegin))) + // hopefully std::size_t is large enough + { + WCHAR * p; + if (frontBegin == path) { + p = const_cast< WCHAR * >(frontEnd); + } else { + p = path; + while (frontBegin != frontEnd) { + *p++ = *frontBegin++; + } + } + for (; backLength > 0; --backLength) { + *p++ = *backBegin++; + } + *p = L'\0'; + return p; + } else { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return NULL; + } +} + +WCHAR * resolveLink(WCHAR * path) { + HANDLE h = CreateFileW( + path, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (h == INVALID_HANDLE_VALUE) { + return NULL; + } + char p1[MAX_PATH]; + DWORD n; + BOOL ok = ReadFile(h, p1, MAX_PATH, &n, NULL); + CloseHandle(h); + if (!ok) { + return NULL; + } + WCHAR p2[MAX_PATH]; + std::size_t n2 = 0; + bool colon = false; + for (DWORD i = 0; i < n;) { + unsigned char c = static_cast< unsigned char >(p1[i++]); + switch (c) { + case '\0': + SetLastError(ERROR_BAD_PATHNAME); + return NULL; + case '\x0A': + case '\x0D': + if (n2 == MAX_PATH) { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return NULL; + } + p2[n2] = L'\0'; + break; + case ':': + colon = true; + // fall through + default: + // Convert from UTF-8 to UTF-16: + if (c <= 0x7F) { + p2[n2++] = c; + } else if (c >= 0xC2 && c <= 0xDF && i < n && + static_cast< unsigned char >(p1[i]) >= 0x80 && + static_cast< unsigned char >(p1[i]) <= 0xBF) + { + p2[n2++] = ((c & 0x1F) << 6) | + (static_cast< unsigned char >(p1[i++]) & 0x3F); + } else if (n - i > 1 && + ((c == 0xE0 && + static_cast< unsigned char >(p1[i]) >= 0xA0 && + static_cast< unsigned char >(p1[i]) <= 0xBF) || + ((c >= 0xE1 && c <= 0xEC || c >= 0xEE && c <= 0xEF) && + static_cast< unsigned char >(p1[i]) >= 0x80 && + static_cast< unsigned char >(p1[i]) <= 0xBF) || + (c == 0xED && + static_cast< unsigned char >(p1[i]) >= 0x80 && + static_cast< unsigned char >(p1[i]) <= 0x9F)) && + static_cast< unsigned char >(p1[i + 1]) >= 0x80 && + static_cast< unsigned char >(p1[i + 1]) <= 0xBF) + { + p2[n2++] = ((c & 0x0F) << 12) | + ((static_cast< unsigned char >(p1[i]) & 0x3F) << 6) | + (static_cast< unsigned char >(p1[i + 1]) & 0x3F); + i += 2; + } else if (n - 2 > 1 && + ((c == 0xF0 && + static_cast< unsigned char >(p1[i]) >= 0x90 && + static_cast< unsigned char >(p1[i]) <= 0xBF) || + (c >= 0xF1 && c <= 0xF3 && + static_cast< unsigned char >(p1[i]) >= 0x80 && + static_cast< unsigned char >(p1[i]) <= 0xBF) || + (c == 0xF4 && + static_cast< unsigned char >(p1[i]) >= 0x80 && + static_cast< unsigned char >(p1[i]) <= 0x8F)) && + static_cast< unsigned char >(p1[i + 1]) >= 0x80 && + static_cast< unsigned char >(p1[i + 1]) <= 0xBF && + static_cast< unsigned char >(p1[i + 2]) >= 0x80 && + static_cast< unsigned char >(p1[i + 2]) <= 0xBF) + { + sal_Int32 u = ((c & 0x07) << 18) | + ((static_cast< unsigned char >(p1[i]) & 0x3F) << 12) | + ((static_cast< unsigned char >(p1[i + 1]) & 0x3F) << 6) | + (static_cast< unsigned char >(p1[i + 2]) & 0x3F); + i += 3; + p2[n2++] = static_cast< WCHAR >(((u - 0x10000) >> 10) | 0xD800); + p2[n2++] = static_cast< WCHAR >( + ((u - 0x10000) & 0x3FF) | 0xDC00); + } else { + SetLastError(ERROR_BAD_PATHNAME); + return NULL; + } + break; + } + } + WCHAR * end; + if (colon || p2[0] == L'\\') { + // Interpret p2 as an absolute path: + end = path; + } else { + // Interpret p2 as a relative path: + end = filename(path); + } + return buildPath(path, path, end, p2, n2); +} + +} + +#endif diff --git a/cli_ure/source/scripts/increment_version.pl b/cli_ure/source/scripts/increment_version.pl new file mode 100644 index 000000000000..9b677b314d03 --- /dev/null +++ b/cli_ure/source/scripts/increment_version.pl @@ -0,0 +1,281 @@ +#************************************************************************* +# +# 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. +# +#************************************************************************* + +use warnings; +use strict; +use diagnostics; + +sub trim; +sub readIncVersions($); +sub processLine($$); +sub checkName($); +sub incrementNewVersion($); +sub incrementOldVersion($); +sub incrementPolicyVersion($); +my $usage = +"The tool increments the minor version of assemblies and the major version of ". +"the respective policy files. This is only done if new uno types have been added since". +"the last product upate. This information is obtained from the file which is passed as ". +"argument changedTypes. The names in the version file must have a particular form. ". +"They must end on one of folling terms: NEW_VERSION, OLD_VERSION, POLICY_VERSION\n". +"If no new published types habe been added then no output, argument newVersions, is written". +"Usage is: \n increment_version.pl oldVersions incVersions newVersions changedTypes\n\n". +"oldVersion: Contains name value pairs, which are used for forming the config files of ". +"the policy assemblies, for building the assemblies. \n\n". +"incVersions: File containing the names of which the versions are to be incremented. ". +"Every line may only contain one name. The names must exactly match those from the ". +"oldVersion file.\n\n". +"newVersions: Contains all entries from oldVersions, but the values of the names,". +"which occur in selection, have been incremented.\n\n". +"changedTypes: File that contains the information if new published types have been added ". +"since the last product update.\n\n" ; + +my $sNameForm = +"The names must end on one of these names: NEW_VERSION, OLD_VERSION, POLICY_VERSION\n". +"For example, valid names are: \n". +"CLI_URETYPES_NEW_VERSION\nCLI_URETYPES_OLD_VERSION\nCLI_URETYPES_POLICY_VERSION\n"; + +if (scalar @ARGV < 4) { + print $usage; + exit -1; +} + +-e "$ARGV[0]" or die "Error: wrong arguments. \n".$usage; +-e "$ARGV[1]" or die "Error: wrong arguments. \n".$usage; +-e "$ARGV[3]" or die "Error: wrong arguments. \n".$usage; + +#check if new types have been added since last release. +#If not, then there is nothing to be done. +#read in oldVersions line by line and apply the increment operation +open TYPES, "$ARGV[3]" or die "Cannot open to $ARGV[3] $!"; + +my $newTypes; + +#We look for the line that contains the number of new types +while(<TYPES>) +{ + if (/New and published types/i) + { + $_ =~ /=\s*(\d+)/; + if ( ! defined $1) + { + print "\n###$ARGV[3] contains an invalid entry for 'New and published types'. \n\n"; + exit -1; + } + $newTypes = $1; + } +} + +#Check if changeTypes contained the line we are looking for +if (! defined $newTypes) +{ + print "\n###$ARGV[3] does not contain entry about the new types ". + "or we are looking for the wrong string! \n\n"; + exit -1; +} + +if ( $newTypes == 0) +{ + print "\nNo new UNO types since las product update.\n"; + exit 0; +} +else +{ + print "\nNew UNO types were addes since last release. The version will be increased.\n\n"; +} + +#read in incVersions in a list +my @incVersions = readIncVersions($ARGV[1]); +#print "@incVersions"; + +#read in oldVersions line by line and apply the increment operation +open OLDVERSION, "$ARGV[0]" or die "Cannot open to $ARGV[0] $!"; + +#open file we want to write to +open NEWVERSION, "> $ARGV[2]" or die "Cannot write to $ARGV[2] $!"; + +print NEWVERSION processLine($_, @incVersions) while(<OLDVERSION>); + +close NEWVERSION; +close OLDVERSION; + +exit 0; + +sub processLine($$) +{ + my $line = $_[0]; + #skip empty lines + my $trimmed; + return $line if (length($trimmed = trim($line)) == 0); + #Skip comment symbol: # + return $line if ($trimmed =~ /^#/); + + #Get the left part of '=' + my $i = index($line, "="); + if( $i == -1) + { + print "Error: No '=' found in line:,: \n $line \n"; + exit -1; + } + my $name = substr($line, 0, $i); + $name = trim($name); + #We do not check the names here because the file can contain + #other names, e.g. CLI_URETYPES_POLICY_ASSEMBLY + if (length($name) == 0) { + print "Wrong line in $ARGV[0]\n", $sNameForm; + exit -1; + } + my $value = substr($line, $i + 1); + $value = trim($value); + + #Check if the entry shall be incremented, this information is in the second + #argument + my $found; + for(@incVersions) { + if ($_ eq $name) { + $found = 1; + last; + } + } + if ( ! defined($found)) { + return $line; + } + + #Check if the name represents a version we need to change + if ($name =~ /NEW_VERSION$/) + { + $value = incrementNewVersion($value); + } + elsif ($name =~ /OLD_VERSION$/) + { + $value = incrementOldVersion($value); + } + elsif ($name =~ /POLICY_VERSION$/) + { + $value = incrementPolicyVersion($value); + } + else + { + #other name which we ignore + return $line; + } + return "${name}=${value}\n"; +} + +#The value of a new version has the form x.x.x.x +#We increment the third position from the left. +#Te argument must already be trimmed. +sub incrementNewVersion($) +{ + my @parts = split /\./,$_[0]; + if (scalar @parts != 4) + { + print "Error, no valid version given in $ARGV[0]\n. A 'new version' has four parts."; + exit -1; + } + $parts[2]++; + #build the version string and return + return "$parts[0].$parts[1].$parts[2].$parts[3]"; +} + +#The value of a new version has the form x.x.x.x-x.x.x.x +#We increment the third position of the second part. +#Te argument must already be trimmed. +sub incrementOldVersion($) +{ + my @parts = split /[\.-]/,$_[0]; + if (scalar @parts != 8) + { + print "Error, no valid version given in $ARGV[0]\n. A 'old version' has the form +x.x.x.x-x.x.x.x\n."; + exit -1; + } + $parts[6]++; + return "$parts[0].$parts[1].$parts[2].$parts[3]-$parts[4].$parts[5].$parts[6].$parts[7]"; + return $_[0]; +} + +sub incrementPolicyVersion($) +{ + my @parts = split /\./,$_[0]; + if (scalar @parts != 4) + { + print "Error, no valid version given in $ARGV[0]\n. A 'policy version' has four parts."; + exit -1; + } + $parts[0]++; + #build the version string and return + return "$parts[0].$parts[1].$parts[2].$parts[3]"; +} + + +sub readIncVersions($) +{ + open INC, $_[0] or die "Could not open $_[0] $!"; + my $arg = $_[0]; + my @names; + + while(<INC>) + { + chomp; + #Skip empty lines + my $line; + if (length($line = trim($_)) == 0) { + next; + } + #Skip comment symbol: # + if ($line =~ /^#/) { + next; + } + if (!checkName($line)) { + print "Wrong entry in file $_[0]\n", $sNameForm; + exit -1; + } + push @names, $line; + } + print "No entries found in $arg\n" if(scalar @names == 0); + return @names; +} + +#The argument must already be trimmed +#returns 1 if ok +sub checkName($) +{ + my $name = $_[0]; + if ( $name !~/NEW_VERSION$|OLD_VERSION$|POLICY_VERSION$/) { + return 0; + } + return 1; +} + +sub trim($) +{ + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} diff --git a/cli_ure/source/scripts/subst_template.pl b/cli_ure/source/scripts/subst_template.pl new file mode 100644 index 000000000000..7358103f78c1 --- /dev/null +++ b/cli_ure/source/scripts/subst_template.pl @@ -0,0 +1,133 @@ +#************************************************************************* +# +# 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. +# +#************************************************************************* + +use warnings; +use strict; +use diagnostics; + +sub trim; +sub readRedirectionValues($); + +my $usage = + "Usage is: \n subst_template.pl configTemplate redirections policyConfig + + configTemplate: The config file which is used for the policy assembly. It + contains place holders for the binding redirection. + + redirections: file containing the values for oldVersion and newVersion tags + which are used in the BindingRedirect element of the config files. + + policyConfig: Name of the file in which we want to write the config file. +"; + + +if (scalar @ARGV < 3) { + print $usage; + exit -1; +} + + +my %redirectionValue = readRedirectionValues($ARGV[1]); +#print "|$_| |$redirectionValue{$_}|\n", for keys %redirectionValue; + + +#Read config file in which we will replace the versions +$/ = undef; +open TEMPLATE, $ARGV[0] or die $!; +my $templ = <TEMPLATE>; + +#Open the config file we are goint to write to +open CONFIG, "> $ARGV[2]" or die "Cannot write to $ARGV[2] $!"; + +#No substitute the place holders for oldVersion and new Version in the config template with +#the values obtained from the redirections file +for (keys %redirectionValue) { + $templ=~ s/\b$_\b/$redirectionValue{$_}/; +} +#Write the config file +print CONFIG $templ; + +#Reads the key value pairs from the files, which name must be passed in +#the parameter. The file contains lines of the form name=value, for example +#CLI_TYPES_OLD_VERSION=1.1.0.0-1.1.1.0 +sub readRedirectionValues($) +{ + #Read in the values for the version redirection + open REDIR, $_[0] or die $!; + + my %redirectionValues; + + while (<REDIR>) + { + chomp; + my $trimmed; + #Skip empty lines + if (length($trimmed = trim($_)) == 0) { + next; + } + + #Skip comment symbol: # + if ($trimmed =~ /^#/) { + next; + } + + my @lineParts = split /=/,$_; + + #Check if we have valid name value pairs. + if (scalar @lineParts != 2) { + print "Error: Values in $ARGV[1] are not correct (Entries must have the form name=value). Invalid line: \n$_\n"; + exit -1; + } + + #Trim the strings and check if they still contain characters + my $name = trim($lineParts[0]); + my $value = trim($lineParts[1]); + if (length($name) == 0 || length($value) == 0) { + print "Error: Values in $ARGV[1] are not correct. Invalid line: \n$_\n"; + exit -1; + } + + #Check if we have duplicate key names + for (keys %redirectionValues) { + if ( $name eq $_) { + print "Error: Values in $ARGV[1] are not correct. The name $_ is not unique.\n"; + exit -1; + } + } + + $redirectionValues{$name} = $value; + } + return %redirectionValues; +} + +sub trim($) +{ + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} diff --git a/cli_ure/source/uno_bridge/README.txt b/cli_ure/source/uno_bridge/README.txt new file mode 100644 index 000000000000..39b3ce3648fe --- /dev/null +++ b/cli_ure/source/uno_bridge/README.txt @@ -0,0 +1,20 @@ +Because of the LoaderLock bug in .NET Framework 1.0 and 1.1 the cli_uno.dll is linked +with the /NOENTRY switch, which prevent that the C-runtime is initialized when loading +the dll. + +Also I removed all static c++ objects which need construction by the CRT, +exception handling seems to need an initialised CRT. Therefore +I added CRT initialization code in uno_initEnvironment (cli_bridge.cxx) +However there is no deinitialization done because bridge libraries remain +in memory until the process dies. There is actually no good place where +this had to be called. If we would do that we would have to implement that +the bridge can be disposed. + + +Sell also: + +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/vcconmixeddllloadingproblem.asp +http://support.microsoft.com/?id=814472 +http://www.ddj.com/dept/windows/184416689 +http://blogs.msdn.com/cbrumme/archive/2003/08/20/51504.aspx +http://msdn2.microsoft.com/en-US/library/ms172219.aspx
\ No newline at end of file diff --git a/cli_ure/source/uno_bridge/bridge_exports.map b/cli_ure/source/uno_bridge/bridge_exports.map new file mode 100644 index 000000000000..df39965a2b51 --- /dev/null +++ b/cli_ure/source/uno_bridge/bridge_exports.map @@ -0,0 +1,8 @@ +UDK_3_0_0 { + global: + component_canUnload; + uno_initEnvironment; + uno_ext_getMapping; + local: + *; +}; diff --git a/cli_ure/source/uno_bridge/cli_base.h b/cli_ure/source/uno_bridge/cli_base.h new file mode 100644 index 000000000000..0ff3f40f9762 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_base.h @@ -0,0 +1,180 @@ +/************************************************************************* + * + * 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_CLI_BASE_H +#define INCLUDED_CLI_BASE_H + +#pragma unmanaged +// Workaround: osl/mutex.h contains only a forward declaration of _oslMutexImpls. +// When using the inline class in Mutex in osl/mutex.hxx, the loader needs to find +// a declaration for the struct. If not found a TypeLoadException is being thrown. +struct _oslMutexImpl +{ +}; +#pragma managed +#include <memory> +#include "rtl/ustring.hxx" +#include "typelib/typedescription.hxx" + +#using <mscorlib.dll> +#using <system.dll> + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + +namespace cli_uno +{ +System::Type* loadCliType(System::String * typeName); +System::Type* mapUnoType(typelib_TypeDescription const * pTD); +System::Type* mapUnoType(typelib_TypeDescriptionReference const * pTD); +typelib_TypeDescriptionReference* mapCliType(System::Type* cliType); +rtl::OUString mapCliString(System::String const * data); +System::String* mapUnoString(rtl_uString const * data); +System::String* mapUnoTypeName(rtl_uString const * typeName); + +__gc struct Constants +{ + static const System::String* sXInterfaceName= new System::String( + S"unoidl.com.sun.star.uno.XInterface"); + static const System::String* sObject= new System::String(S"System.Object"); + static const System::String* sType= new System::String(S"System.Type"); + static const System::String* sUnoidl= new System::String(S"unoidl."); + static const System::String* sVoid= new System::String(S"System.Void"); + static const System::String* sAny= new System::String(S"uno.Any"); + static const System::String* sArArray= new System::String(S"System.Array[]"); + static const System::String* sBoolean= new System::String(S"System.Boolean"); + static const System::String* sChar= new System::String(S"System.Char"); + static const System::String* sByte= new System::String(S"System.Byte"); + static const System::String* sInt16= new System::String(S"System.Int16"); + static const System::String* sUInt16= new System::String(S"System.UInt16"); + static const System::String* sInt32= new System::String(S"System.Int32"); + static const System::String* sUInt32= new System::String(S"System.UInt32"); + static const System::String* sInt64= new System::String(S"System.Int64"); + static const System::String* sUInt64= new System::String(S"System.UInt64"); + static const System::String* sString= new System::String(S"System.String"); + static const System::String* sSingle= new System::String(S"System.Single"); + static const System::String* sDouble= new System::String(S"System.Double"); + static const System::String* sArBoolean= new System::String(S"System.Boolean[]"); + static const System::String* sArChar= new System::String(S"System.Char[]"); + static const System::String* sArByte= new System::String(S"System.Byte[]"); + static const System::String* sArInt16= new System::String(S"System.Int16[]"); + static const System::String* sArUInt16= new System::String(S"System.UInt16[]"); + static const System::String* sArInt32= new System::String(S"System.Int32[]"); + static const System::String* sArUInt32= new System::String(S"System.UInt32[]"); + static const System::String* sArInt64= new System::String(S"System.Int64[]"); + static const System::String* sArUInt64= new System::String(S"System.UInt64[]"); + static const System::String* sArString= new System::String(S"System.String[]"); + static const System::String* sArSingle= new System::String(S"System.Single[]"); + static const System::String* sArDouble= new System::String(S"System.Double[]"); + static const System::String* sArType= new System::String(S"System.Type[]"); + static const System::String* sArObject= new System::String(S"System.Object[]"); + static const System::String* sBrackets= new System::String(S"[]"); + static const System::String* sAttributeSet= new System::String(S"set_"); + static const System::String* sAttributeGet= new System::String(S"get_"); + + static const System::String* usXInterface = S"com.sun.star.uno.XInterface"; + static const System::String* usVoid = S"void"; + static const System::String* usType = S"type"; + static const System::String* usAny = S"any"; + static const System::String* usBrackets = S"[]"; + static const System::String* usBool = S"boolean"; + static const System::String* usByte = S"byte"; + static const System::String* usChar = S"char"; + static const System::String* usShort = S"short"; + static const System::String* usUShort = S"unsigned short"; + static const System::String* usLong = S"long"; + static const System::String* usULong = S"unsigned long"; + static const System::String* usHyper = S"hyper"; + static const System::String* usUHyper = S"unsigned hyper"; + static const System::String* usString = S"string"; + static const System::String* usFloat = S"float"; + static const System::String* usDouble = S"double"; +}; + +struct BridgeRuntimeError +{ + ::rtl::OUString m_message; + + inline BridgeRuntimeError( ::rtl::OUString const & message ) + : m_message( message ) + {} +}; + +//================================================================================================== +struct rtl_mem +{ + inline static void * operator new ( size_t nSize ) + { return rtl_allocateMemory( nSize ); } + inline static void operator delete ( void * mem ) + { if (mem) rtl_freeMemory( mem ); } + inline static void * operator new ( size_t, void * mem ) + { return mem; } + inline static void operator delete ( void *, void * ) + {} + + static inline ::std::auto_ptr< rtl_mem > allocate( ::std::size_t bytes ); +}; +//-------------------------------------------------------------------------------------------------- +inline ::std::auto_ptr< rtl_mem > rtl_mem::allocate( ::std::size_t bytes ) +{ + void * p = rtl_allocateMemory( bytes ); + if (0 == p) + throw BridgeRuntimeError(OUSTR("out of memory!") ); + return ::std::auto_ptr< rtl_mem >( (rtl_mem *)p ); +} + +//================================================================================================== +class TypeDescr +{ + typelib_TypeDescription * m_td; + + TypeDescr( TypeDescr & ); // not impl + void operator = ( TypeDescr ); // not impl + +public: + inline explicit TypeDescr( typelib_TypeDescriptionReference * td_ref ); + inline ~TypeDescr() SAL_THROW( () ) + { TYPELIB_DANGER_RELEASE( m_td ); } + + inline typelib_TypeDescription * get() const + { return m_td; } +}; + +inline TypeDescr::TypeDescr( typelib_TypeDescriptionReference * td_ref ) + : m_td( 0 ) +{ + TYPELIB_DANGER_GET( &m_td, td_ref ); + if (0 == m_td) + { + throw BridgeRuntimeError( + OUSTR("cannot get comprehensive type description for ") + + *reinterpret_cast< ::rtl::OUString const * >( &td_ref->pTypeName ) ); + } +} + + +} //end namespace cli_uno + #endif diff --git a/cli_ure/source/uno_bridge/cli_bridge.cxx b/cli_ure/source/uno_bridge/cli_bridge.cxx new file mode 100644 index 000000000000..ab78b2f9d95b --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_bridge.cxx @@ -0,0 +1,369 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" + +#include <vcclr.h> +//ToDo: remove when build with .NET 2 +#pragma warning(push, 1) +#include <windows.h> +#include "uno/environment.hxx" +#pragma warning(pop) +#include "rtl/unload.h" +#include "uno/lbnames.h" +#include "uno/mapping.hxx" +#include "typelib/typedescription.hxx" +#include "rtl/ustring.hxx" + +#include "cli_bridge.h" +#include "cli_proxy.h" +namespace srr= System::Runtime::Remoting; +namespace srrp= System::Runtime::Remoting::Proxies; +#using <mscorlib.dll> +#if defined(_MSC_VER) && (_MSC_VER < 1400) +#include <_vcclrit.h> +#endif + +namespace cssu= com::sun::star::uno; + + +namespace sri= System::Runtime::InteropServices; +using namespace rtl; + +namespace cli_uno +{ + +extern "C" +{ +void SAL_CALL Mapping_acquire( uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + Mapping const * that = static_cast< Mapping const * >( mapping ); + that->m_bridge->acquire(); +} +//-------------------------------------------------------------------------------------------------- +void SAL_CALL Mapping_release( uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + Mapping const * that = static_cast< Mapping const * >( mapping ); + that->m_bridge->release(); +} + + +//-------------------------------------------------------------------------------------------------- +void SAL_CALL Mapping_cli2uno( + uno_Mapping * mapping, void ** ppOut, + void * pIn, typelib_InterfaceTypeDescription * td ) + SAL_THROW_EXTERN_C() +{ + uno_Interface ** ppUnoI = (uno_Interface **)ppOut; + intptr_t cliI = (intptr_t)pIn; + + OSL_ENSURE( ppUnoI && td, "### null ptr!" ); + + if (0 != *ppUnoI) + { + uno_Interface * pUnoI = *(uno_Interface **)ppUnoI; + (*pUnoI->release)( pUnoI ); + *ppUnoI = 0; + } + try + { + Mapping const * that = static_cast< Mapping const * >( mapping ); + Bridge * bridge = that->m_bridge; + + if (0 != cliI) + { + System::Object* cliObj= sri::GCHandle::op_Explicit(cliI).Target; + (*ppOut)= bridge->map_cli2uno(cliObj, (typelib_TypeDescription*) td); + } + } + catch (BridgeRuntimeError & err) + { +#if OSL_DEBUG_LEVEL >= 1 + OString cstr_msg( + OUStringToOString( + OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr_msg.getStr() ); +#else + (void) err; // unused +#endif + } +} +//-------------------------------------------------------------------------------------------------- +void SAL_CALL Mapping_uno2cli( + uno_Mapping * mapping, void ** ppOut, + void * pIn, typelib_InterfaceTypeDescription * td ) + SAL_THROW_EXTERN_C() +{ + try + { + OSL_ENSURE( td && ppOut, "### null ptr!" ); + OSL_ENSURE( (sizeof(System::Char) == sizeof(sal_Unicode)) + && (sizeof(System::Boolean) == sizeof(sal_Bool)) + && (sizeof(System::SByte) == sizeof(sal_Int8)) + && (sizeof(System::Int16) == sizeof(sal_Int16)) + && (sizeof(System::UInt16) == sizeof(sal_uInt16)) + && (sizeof(System::Int32) == sizeof(sal_Int32)) + && (sizeof(System::UInt32) == sizeof(sal_uInt32)) + && (sizeof(System::Int64) == sizeof(sal_Int64)) + && (sizeof(System::UInt64) == sizeof(sal_uInt64)) + && (sizeof(System::Single) == sizeof(float)) + && (sizeof(System::Double) == sizeof(double)), + "[cli_uno bridge] incompatible .NET data types"); + intptr_t * ppDNetI = (intptr_t *)ppOut; + uno_Interface * pUnoI = (uno_Interface *)pIn; + + Mapping const * that = static_cast< Mapping const * >( mapping ); + Bridge * bridge = that->m_bridge; + + if (0 != *ppDNetI) + { + sri::GCHandle::op_Explicit(ppDNetI).Free(); + } + + if (0 != pUnoI) + { + System::Object* cliI= bridge->map_uno2cli(pUnoI, td); + intptr_t ptr= NULL; + if(cliI) + { + ptr= sri::GCHandle::op_Explicit(sri::GCHandle::Alloc(cliI)) +#ifdef _WIN32 + .ToInt32(); +#else /* defined(_WIN64) */ .ToInt64(); +#endif + } + (*ppOut)= reinterpret_cast<void*>(ptr); + } + } + catch (BridgeRuntimeError & err) + { +#if OSL_DEBUG_LEVEL >= 1 + rtl::OString cstr_msg( + rtl::OUStringToOString( + OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr_msg.getStr() ); +#else + (void) err; // unused +#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 +} //namespace + +namespace cli_uno +{ + +//__________________________________________________________________________________________________ +/** ToDo + I doubt that the the case that the ref count raises from 0 to 1 + can occur. uno_ext_getMapping returns an acquired mapping. Every time + that function is called then a new mapping is created. Following the + rules of ref counted objects, then if the ref count is null noone has + a reference to the object anymore. Hence noone can call acquire. If someone + calls acquire then they must have kept an unacquired pointer which is + illegal. + */ +void Bridge::acquire() const SAL_THROW( () ) +{ + if (1 == osl_incrementInterlockedCount( &m_ref )) + { + if (m_registered_cli2uno) + { + uno_Mapping * mapping = const_cast<Mapping*>(&m_cli2uno); + uno_registerMapping( + & const_cast<uno_Mapping*>(mapping), Bridge_free, m_uno_cli_env, (uno_Environment *)m_uno_env, 0 ); + } + else + { + uno_Mapping * mapping = const_cast<Mapping*>(&m_uno2cli); + uno_registerMapping( + &mapping, Bridge_free, (uno_Environment *)m_uno_env, m_uno_cli_env, 0 ); + } + } +} +//__________________________________________________________________________________________________ +void Bridge::release() const SAL_THROW( () ) +{ + if (! osl_decrementInterlockedCount( &m_ref )) + { + uno_revokeMapping( + m_registered_cli2uno + ? const_cast<Mapping*>(&m_cli2uno) + : const_cast<Mapping*>(&m_uno2cli) ); + } +} +//__________________________________________________________________________________________________ +Bridge::Bridge( + uno_Environment * uno_cli_env, uno_ExtEnvironment * uno_env, + bool registered_cli2uno ) + : m_ref( 1 ), + m_uno_env( uno_env ), + m_uno_cli_env( uno_cli_env ), + m_registered_cli2uno( registered_cli2uno ) +{ + OSL_ASSERT( 0 != m_uno_cli_env && 0 != m_uno_env ); + (*((uno_Environment *)m_uno_env)->acquire)( (uno_Environment *)m_uno_env ); + (*m_uno_cli_env->acquire)( m_uno_cli_env ); + + // cli2uno + m_cli2uno.acquire = Mapping_acquire; + m_cli2uno.release = Mapping_release; + m_cli2uno.mapInterface = Mapping_cli2uno; + m_cli2uno.m_bridge = this; + // uno2cli + m_uno2cli.acquire = Mapping_acquire; + m_uno2cli.release = Mapping_release; + m_uno2cli.mapInterface = Mapping_uno2cli; + m_uno2cli.m_bridge = this; + +} + +//__________________________________________________________________________________________________ +Bridge::~Bridge() SAL_THROW( () ) +{ + //System::GC::Collect(); + (*m_uno_cli_env->release)( m_uno_cli_env ); + (*((uno_Environment *)m_uno_env)->release)( (uno_Environment *)m_uno_env ); +} + + + +} //namespace cli_uno + +extern "C" +{ + +namespace cli_uno +{ +//-------------------------------------------------------------------------------------------------- +void SAL_CALL cli_env_disposing( uno_Environment * uno_cli_env ) + SAL_THROW_EXTERN_C() +{ + uno_cli_env->pContext = 0; +} + +//################################################################################################## +void SAL_CALL uno_initEnvironment( uno_Environment * uno_cli_env ) + SAL_THROW_EXTERN_C() +{ + //ToDo: remove when compiled with .NET 2 +#if defined(_MSC_VER) && (_MSC_VER < 1400) + __crt_dll_initialize(); +#endif + + uno_cli_env->environmentDisposing= cli_env_disposing; + uno_cli_env->pExtEnv = 0; + //Set the console to print Trace messages +#if OSL_DEBUG_LEVEL >= 1 + System::Diagnostics::Trace::get_Listeners()-> + Add( new System::Diagnostics::TextWriterTraceListener(System::Console::get_Out())); +#endif + OSL_ASSERT( 0 == uno_cli_env->pContext ); + + // We let the Cli_environment leak, since there is no good point where we could destruct it. + //dispose is not used because we would have then also synchronize the calls to proxies. If the + //Cli_environment is disposed, we must prevent all calls, otherwise we may crash at points + //where g_cli_env is accessed. + //When we compile the bridge with .NET 2 then we can again hold g_cli_env as a static gcroot + //member in a unmanaged class, such as Bridge. + CliEnvHolder::g_cli_env = new Cli_environment(); +} +//################################################################################################## +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 (*ppMapping) + { + (*(*ppMapping)->release)( *ppMapping ); + *ppMapping = 0; + } + + + OUString const & from_env_typename = *reinterpret_cast< OUString const * >( + &pFrom->pTypeName ); + OUString const & to_env_typename = *reinterpret_cast< OUString const * >( + &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_cli2uno; + 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_uno2cli; + uno_registerMapping( + &mapping, Bridge_free, (uno_Environment *)pFrom->pExtEnv, pTo, 0 ); + } + } + catch (BridgeRuntimeError & err) + { +#if OSL_DEBUG_LEVEL >= 1 + OString cstr_msg( + OUStringToOString( + OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr_msg.getStr() ); +#else + (void) err; // unused +#endif + } + *ppMapping = mapping; +} + + +//################################################################################################## +sal_Bool SAL_CALL component_canUnload( TimeValue * ) + SAL_THROW_EXTERN_C() +{ + return true; +} + +} +} diff --git a/cli_ure/source/uno_bridge/cli_bridge.h b/cli_ure/source/uno_bridge/cli_bridge.h new file mode 100644 index 000000000000..1bc3a926519e --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_bridge.h @@ -0,0 +1,120 @@ +/************************************************************************* + * + * 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_CLI_BRIDGE_H +#define INCLUDED_CLI_BRIDGE_H +#include <vcclr.h> +#include "osl/interlck.h" +#include "uno/mapping.h" +#include "uno/environment.h" +#include "uno/dispatcher.h" +#include "cli_base.h" +#include "cli_environment.h" +#using <mscorlib.dll> +//#using <cli_uretypes.dll> +#using <cli_basetypes.dll> +#using <system.dll> + +namespace sr = System::Reflection; + +namespace cli_uno +{ + + +//==== holds environments and mappings ============================================================= +struct Bridge; +struct Mapping : public uno_Mapping +{ + Bridge* m_bridge; +}; + +// The environment will be created in uno_initEnvironment. See also the remarks there +//Managed cli environment for cli objects an UNO proxies (which are cli +//objects. The uno_Environment is not used for cli objects. +__gc struct CliEnvHolder { +static Cli_environment * g_cli_env = NULL; +}; + +//================================================================================================== +/** An instance of Bridge represents exactly one mapping therefore either + m_cli2uno or m_uno2cli is valid. +*/ +struct Bridge +{ + mutable oslInterlockedCount m_ref; + uno_ExtEnvironment * m_uno_env; + uno_Environment * m_uno_cli_env; + + Mapping m_cli2uno; + Mapping m_uno2cli; + bool m_registered_cli2uno; + + ~Bridge() SAL_THROW( () ); + Bridge( uno_Environment * java_env, uno_ExtEnvironment * uno_env, bool registered_java2uno ); + + void acquire() const; + void release() const; + + void map_to_uno( + void * uno_data, System::Object* cli_data, + typelib_TypeDescriptionReference * type, + bool assign) const; + + /** + @param info + the type of the converted data. It may be a byref type. + */ + void map_to_cli( + System::Object* *cli_data, void const * uno_data, + typelib_TypeDescriptionReference * type, System::Type* info /* maybe 0 */, + bool bDontCreateObj) const; + + System::Object* map_uno2cli(uno_Interface * pUnoI, typelib_InterfaceTypeDescription* pTD) const; + + System::Object* Bridge::call_uno(uno_Interface * pUnoI, + typelib_TypeDescription* member_td, + typelib_TypeDescriptionReference * return_type, + sal_Int32 nParams, typelib_MethodParameter const * pParams, + System::Object * args[], System::Type* argTypes[], + System::Object** pException) const; + + + void call_cli( + System::Object* cliI, sr::MethodInfo* method, + typelib_TypeDescriptionReference * return_type, + typelib_MethodParameter * params, int nParams, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const; + + uno_Interface * map_cli2uno( + System::Object* cliI, typelib_TypeDescription* pTD) const; + +}; + +} //namespace cli_uno + + +#endif diff --git a/cli_ure/source/uno_bridge/cli_data.cxx b/cli_ure/source/uno_bridge/cli_data.cxx new file mode 100644 index 000000000000..99f4bda82563 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_data.cxx @@ -0,0 +1,2011 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" + +#pragma warning(push, 1) +#include "windows.h" +#pragma warning(pop) + +#include <memory> + + +#include "rtl/ustring.hxx" +#include "rtl/ustrbuf.hxx" +#include "uno/sequence2.h" +#include "typelib/typedescription.hxx" +#include "cli_proxy.h" +#include "cli_base.h" +#include "cli_bridge.h" + +#using <cli_uretypes.dll> + + +#undef VOID + +namespace css = com::sun::star; + +namespace sri = System::Runtime::InteropServices; +namespace sr = System::Reflection; +namespace st = System::Text; +namespace ucss = unoidl::com::sun::star; + +using namespace rtl; +using namespace std; + + +namespace cli_uno +{ +System::String* mapUnoPolymorphicName(System::String* unoName); +OUString mapCliTypeName(System::String* typeName); +System::String* mapCliPolymorphicName(System::String* unoName); +System::String* mapPolymorphicName(System::String* unoName, bool bCliToUno); + +inline auto_ptr< rtl_mem > seq_allocate( sal_Int32 nElements, sal_Int32 nSize ) +{ + auto_ptr< rtl_mem > seq( + rtl_mem::allocate( SAL_SEQUENCE_HEADER_SIZE + (nElements * nSize) ) ); + uno_Sequence * p = (uno_Sequence *)seq.get(); + p->nRefCount = 1; + p->nElements = nElements; + return seq; +} + + +System::Object* Bridge::map_uno2cli(uno_Interface * pUnoI, typelib_InterfaceTypeDescription *pTD) const +{ + System::Object* retVal= NULL; +// get oid + rtl_uString * pOid = 0; + (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI ); + OSL_ASSERT( 0 != pOid ); + OUString oid(pOid, SAL_NO_ACQUIRE); + + //see if the interface was already mapped + System::Type* ifaceType= mapUnoType(reinterpret_cast<typelib_TypeDescription*>(pTD)); + System::String* sOid= mapUnoString(oid.pData); + + System::Threading::Monitor::Enter( CliEnvHolder::g_cli_env ); + try + { + retVal = CliEnvHolder::g_cli_env->getRegisteredInterface(sOid, ifaceType); + if (retVal) + { + // 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 (srr::RemotingServices::IsTransparentProxy(retVal)) + { + UnoInterfaceProxy* p = static_cast<UnoInterfaceProxy*>( + srr::RemotingServices::GetRealProxy(retVal)); + p->addUnoInterface(pUnoI, pTD); + } + } + else + { + retVal = UnoInterfaceProxy::create( + (Bridge *) this, pUnoI, pTD, oid ); + } + } + __finally + { + System::Threading::Monitor::Exit( CliEnvHolder::g_cli_env ); + } + + return retVal; +} + +uno_Interface* Bridge::map_cli2uno(System::Object* cliObj, typelib_TypeDescription *pTD) const +{ + uno_Interface* retIface = NULL; + // get oid from dot net environment + System::String* ds_oid = CliEnvHolder::g_cli_env->getObjectIdentifier( cliObj); + OUString ousOid = mapCliString(ds_oid); + // look if interface is already mapped + m_uno_env->getRegisteredInterface(m_uno_env, (void**) &retIface, ousOid.pData, + (typelib_InterfaceTypeDescription*) pTD); + if ( ! retIface) + { + System::Threading::Monitor::Enter(__typeof(Cli_environment)); + try + { + m_uno_env->getRegisteredInterface(m_uno_env, (void**) &retIface, ousOid.pData, + (typelib_InterfaceTypeDescription*) pTD); + if ( ! retIface) + { + retIface = CliProxy::create((Bridge*)this, cliObj, pTD, ousOid); + } + } + __finally + { + System::Threading::Monitor::Exit(__typeof(Cli_environment)); + } + } + return retIface; +} + +inline System::Type* loadCliType(rtl_uString * unoName) +{ + return loadCliType(mapUnoTypeName(unoName)); +} + +System::Type* loadCliType(System::String * unoName) +{ + System::Type* retVal= NULL; + try + { + //If unoName denotes a polymorphic type, e.g com.sun.star.beans.Defaulted<System.Char> + //then we remove the type list, otherwise the type could not be loaded. + bool bIsPolymorphic = false; + + System::String * loadName = unoName; + int index = unoName->IndexOf('<'); + if (index != -1) + { + loadName = unoName->Substring(0, index); + bIsPolymorphic = true; + } + System::AppDomain* currentDomain = System::AppDomain::CurrentDomain; + sr::Assembly* assems[] = currentDomain->GetAssemblies(); + for (int i = 0; i < assems->Length; i++) + { + retVal = assems[i]->GetType(loadName, false); + if (retVal) + break; + } + + if (retVal == NULL) + { + System::String * msg = new System::String(S"A type could not be loaded: "); + msg = System::String::Concat(msg, loadName); + throw BridgeRuntimeError(mapCliString(msg)); + } + + if (bIsPolymorphic) + { + retVal = uno::PolymorphicType::GetType(retVal, unoName); + } + } + catch( System::Exception * e) + { + rtl::OUString ouMessage(mapCliString(e->get_Message())); + throw BridgeRuntimeError(ouMessage); + } + return retVal; +} + + +System::Type* mapUnoType(typelib_TypeDescription const * pTD) +{ + return mapUnoType(pTD->pWeakRef); +} + +System::Type* mapUnoType(typelib_TypeDescriptionReference const * pTD) +{ + System::Type * retVal = 0; + switch (pTD->eTypeClass) + { + case typelib_TypeClass_VOID: + retVal= __typeof(void); break; + case typelib_TypeClass_CHAR: + retVal= __typeof(System::Char); break; + case typelib_TypeClass_BOOLEAN: + retVal= __typeof(System::Boolean); break; + case typelib_TypeClass_BYTE: + retVal= __typeof(System::Byte); break; + case typelib_TypeClass_SHORT: + retVal= __typeof(System::Int16); break; + case typelib_TypeClass_UNSIGNED_SHORT: + retVal= __typeof(System::UInt16); break; + case typelib_TypeClass_LONG: + retVal= __typeof(System::Int32); break; + case typelib_TypeClass_UNSIGNED_LONG: + retVal= __typeof(System::UInt32); break; + case typelib_TypeClass_HYPER: + retVal= __typeof(System::Int64); break; + case typelib_TypeClass_UNSIGNED_HYPER: + retVal= __typeof(System::UInt64); break; + case typelib_TypeClass_FLOAT: + retVal= __typeof(System::Single); break; + case typelib_TypeClass_DOUBLE: + retVal= __typeof(System::Double); break; + case typelib_TypeClass_STRING: + retVal= __typeof(System::String); break; + case typelib_TypeClass_TYPE: + retVal= __typeof(System::Type); break; + case typelib_TypeClass_ANY: + retVal= __typeof(uno::Any); break; + case typelib_TypeClass_ENUM: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + retVal= loadCliType(pTD->pTypeName); break; + case typelib_TypeClass_INTERFACE: + { + //special handling for XInterface, since it does not exist in cli. + rtl::OUString usXInterface(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.XInterface")); + if (usXInterface.equals(pTD->pTypeName)) + retVal= __typeof(System::Object); + else + retVal= loadCliType(pTD->pTypeName); + break; + } + case typelib_TypeClass_SEQUENCE: + { + css::uno::TypeDescription seqType( + const_cast<typelib_TypeDescriptionReference*>(pTD)); + typelib_TypeDescriptionReference* pElementTDRef= + reinterpret_cast<typelib_IndirectTypeDescription*>(seqType.get())->pType; + switch (pElementTDRef->eTypeClass) + { + case typelib_TypeClass_CHAR: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArChar)); break; + case typelib_TypeClass_BOOLEAN: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArBoolean)); + break; + case typelib_TypeClass_BYTE: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArByte)); + break; + case typelib_TypeClass_SHORT: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArInt16)); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArUInt16)); + break; + case typelib_TypeClass_LONG: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArInt32)); + break; + case typelib_TypeClass_UNSIGNED_LONG: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArUInt32)); + break; + case typelib_TypeClass_HYPER: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArInt64)); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArUInt64)); + break; + case typelib_TypeClass_FLOAT: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArSingle)); + break; + case typelib_TypeClass_DOUBLE: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArDouble)); + break; + case typelib_TypeClass_STRING: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArString)); + break; + case typelib_TypeClass_TYPE: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArType)); + break; + case typelib_TypeClass_ANY: + case typelib_TypeClass_ENUM: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_INTERFACE: + case typelib_TypeClass_SEQUENCE: + { + retVal= loadCliType(pTD->pTypeName); + break; + } + default: + //All cases should be handled by the case statements above + OSL_ASSERT(0); + break; + } + break; + } + default: + OSL_ASSERT(false); + break; + } + return retVal; +} + +/** Returns an acquired td. + */ +typelib_TypeDescriptionReference* mapCliType(System::Type* cliType) +{ + typelib_TypeDescriptionReference* retVal= NULL; + if (cliType == NULL) + { + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_VOID ); + typelib_typedescriptionreference_acquire( retVal ); + return retVal; + } + //check for Enum first, + //because otherwise case System::TypeCode::Int32 applies + if (cliType->get_IsEnum()) + { + OUString usTypeName= mapCliTypeName(cliType->get_FullName()); + css::uno::Type unoType(css::uno::TypeClass_ENUM, usTypeName); + retVal= unoType.getTypeLibType(); + typelib_typedescriptionreference_acquire(retVal); + } + else + { + switch (System::Type::GetTypeCode(cliType)) + { + case System::TypeCode::Boolean: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_BOOLEAN ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Char: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_CHAR ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Byte: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_BYTE ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Int16: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_SHORT ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Int32: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_LONG ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Int64: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_HYPER ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::UInt16: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_UNSIGNED_SHORT ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::UInt32: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_UNSIGNED_LONG ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::UInt64: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_UNSIGNED_HYPER ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Single: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_FLOAT ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Double: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_DOUBLE ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::String: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_STRING ); + typelib_typedescriptionreference_acquire( retVal ); + break; + default: + break; + } + } + if (retVal == NULL) + { + System::String* cliTypeName= cliType->get_FullName(); + // Void + if (const_cast<System::String*>(Constants::sVoid)->Equals( + cliTypeName)) + { + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_VOID ); + typelib_typedescriptionreference_acquire( retVal ); + } + // Type + else if (const_cast<System::String*>(Constants::sType)->Equals( + cliTypeName)) + { + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_TYPE ); + typelib_typedescriptionreference_acquire( retVal ); + } + // Any + else if (const_cast<System::String*>(Constants::sAny)->Equals( + cliTypeName)) + { + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_ANY ); + typelib_typedescriptionreference_acquire( retVal ); + } + //struct, interfaces, sequences + else + { + OUString usTypeName; + uno::PolymorphicType * poly = dynamic_cast<uno::PolymorphicType*>(cliType); + if (poly != NULL) + usTypeName = mapCliTypeName( poly->PolymorphicName); + else + usTypeName = mapCliTypeName(cliTypeName); + typelib_TypeDescription* td = NULL; + typelib_typedescription_getByName(&td, usTypeName.pData); + if (td) + { + retVal = td->pWeakRef; + typelib_typedescriptionreference_acquire(retVal); + typelib_typedescription_release(td); + } + } + } + if (retVal == NULL) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("[cli_uno bridge] mapCliType():" + "could not map type: ") ); + buf.append(mapCliString(cliType->get_FullName())); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + return retVal; +} + +/** + Otherwise a leading "unoidl." is removed. + */ +System::String* mapUnoTypeName(rtl_uString const * typeName) +{ + OUString usUnoName( const_cast< rtl_uString * >( typeName ) ); + st::StringBuilder* buf= new st::StringBuilder(); + //determine if the type is a sequence and its dimensions + int dims= 0; + if (usUnoName[0] == '[') + { + sal_Int32 index= 1; + while (true) + { + if (usUnoName[index++] == ']') + dims++; + if (usUnoName[index++] != '[') + break; + } + usUnoName = usUnoName.copy(index - 1); + } + System::String * sUnoName = mapUnoString(usUnoName.pData); + if (sUnoName->Equals(const_cast<System::String*>(Constants::usBool))) + buf->Append(const_cast<System::String*>(Constants::sBoolean)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usChar))) + buf->Append(const_cast<System::String*>(Constants::sChar)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usByte))) + buf->Append(const_cast<System::String*>(Constants::sByte)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usShort))) + buf->Append(const_cast<System::String*>(Constants::sInt16)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usUShort))) + buf->Append(const_cast<System::String*>(Constants::sUInt16)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usLong))) + buf->Append(const_cast<System::String*>(Constants::sInt32)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usULong))) + buf->Append(const_cast<System::String*>(Constants::sUInt32)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usHyper))) + buf->Append(const_cast<System::String*>(Constants::sInt64)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usUHyper))) + buf->Append(const_cast<System::String*>(Constants::sUInt64)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usFloat))) + buf->Append(const_cast<System::String*>(Constants::sSingle)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usDouble))) + buf->Append(const_cast<System::String*>(Constants::sDouble)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usString))) + buf->Append(const_cast<System::String*>(Constants::sString)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usVoid))) + buf->Append(const_cast<System::String*>(Constants::sVoid)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usType))) + buf->Append(const_cast<System::String*>(Constants::sType)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usXInterface))) + buf->Append(const_cast<System::String*>(Constants::sObject)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usAny))) + { + buf->Append(const_cast<System::String*>(Constants::sAny)); + } + else + { + //put "unoidl." at the beginning + buf->Append(const_cast<System::String*>(Constants::sUnoidl)); + //for polymorphic struct types remove the brackets, e.g mystruct<bool> -> mystruct + System::String * sName = mapUnoPolymorphicName(sUnoName); + buf->Append(sName); + } + // apend [] + for (;dims--;) + buf->Append(const_cast<System::String*>(Constants::sBrackets)); + + 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. + The präfix unoidl is not added. + */ +inline System::String* mapUnoPolymorphicName(System::String* unoName) +{ + return mapPolymorphicName(unoName, false); +} +/** For example, there is a type name such as + com.sun.star.Foo<System.Char, System.Int32>. + The values in the type list + are CLI types and are replaced by uno types, such as char, + long, etc. + The präfix unoidl remains. + */ +inline System::String* mapCliPolymorphicName(System::String* unoName) +{ + return mapPolymorphicName(unoName, true); +} + +System::String* mapPolymorphicName(System::String* unoName, bool bCliToUno) +{ + int index = unoName->IndexOf('<'); + if (index == -1) + return unoName; + + System::Text::StringBuilder * builder = new System::Text::StringBuilder(256); + builder->Append(unoName->Substring(0, index +1 )); + + //Find the first occurrence of ',' + //If the parameter is a polymorphic struct then we neede to ignore everything + //between the brackets because it can also contain commas + //get the type list within < and > + int endIndex = unoName->Length - 1; + index++; + int cur = index; + int countParams = 0; + while (cur <= endIndex) + { + System::Char c = unoName->Chars[cur]; + if (c == ',' || c == '>') + { + //insert a comma if needed + if (countParams != 0) + builder->Append(S","); + countParams++; + System::String * sParam = unoName->Substring(index, cur - index); + //skip the comma + cur++; + //the the index to the beginning of the next param + index = cur; + if (bCliToUno) + { + builder->Append(mapCliTypeName(sParam)); + } + else + { + OUString s = mapCliString(sParam); + builder->Append(mapUnoTypeName(s.pData)); + } + } + else if (c == '<') + { + cur++; + //continue until the matching '>' + int numNested = 0; + for (;;cur++) + { + System::Char curChar = unoName->Chars[cur]; + if (curChar == '<') + { + numNested ++; + } + else if (curChar == '>') + { + if (numNested > 0) + numNested--; + else + break; + } + } + } + cur++; + } + + builder->Append((System::Char) '>'); + return builder->ToString(); +} + +OUString mapCliTypeName(System::String* typeName) +{ + int dims= 0; + // Array? determine the "rank" (number of "[]") + // move from the rightmost end to the left, for example + // unoidl.PolymorphicStruct<System.Char[]>[] + // has only a "dimension" of 1 + int cur = typeName->Length - 1; + bool bRightBracket = false; + while (cur >= 0) + { + System::Char c = typeName->Chars[cur]; + if (c == ']') + { + bRightBracket = true; + } + else if (c == '[') + { + if (!bRightBracket) + throw BridgeRuntimeError( + OUSTR("Typename is wrong. No matching brackets for sequence. Name is: ") + + mapCliString(typeName)); + bRightBracket = false; + dims ++; + } + else + { + if (bRightBracket) + throw BridgeRuntimeError( + OUSTR("Typename is wrong. No matching brackets for sequence. Name is: ") + + mapCliString(typeName)); + break; + } + cur--; + } + + if (bRightBracket || cur < 0) + throw BridgeRuntimeError( + OUSTR("Typename is wrong. ") + + mapCliString(typeName)); + + typeName = typeName->Substring(0, cur + 1); + + System::Text::StringBuilder * buf = new System::Text::StringBuilder(512); + + //Put the "[]" at the beginning of the uno type name + for (;dims--;) + buf->Append(const_cast<System::String*>(Constants::usBrackets)); + + if (typeName->Equals(const_cast<System::String*>(Constants::sBoolean))) + buf->Append(const_cast<System::String*>(Constants::usBool)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sChar))) + buf->Append(const_cast<System::String*>(Constants::usChar)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sByte))) + buf->Append(const_cast<System::String*>(Constants::usByte)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sInt16))) + buf->Append(const_cast<System::String*>(Constants::usShort)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sUInt16))) + buf->Append(const_cast<System::String*>(Constants::usUShort)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sInt32))) + buf->Append(const_cast<System::String*>(Constants::usLong)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sUInt32))) + buf->Append(const_cast<System::String*>(Constants::usULong)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sInt64))) + buf->Append(const_cast<System::String*>(Constants::usHyper)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sUInt64))) + buf->Append(const_cast<System::String*>(Constants::usUHyper)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sSingle))) + buf->Append(const_cast<System::String*>(Constants::usFloat)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sDouble))) + buf->Append(const_cast<System::String*>(Constants::usDouble)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sString))) + buf->Append(const_cast<System::String*>(Constants::usString)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sVoid))) + buf->Append(const_cast<System::String*>(Constants::usVoid)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sType))) + buf->Append(const_cast<System::String*>(Constants::usType)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sObject))) + buf->Append(const_cast<System::String*>(Constants::usXInterface)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sAny))) + buf->Append(const_cast<System::String*>(Constants::usAny)); + else + { + System::String * sName = mapCliPolymorphicName(typeName); + int i= sName->IndexOf(L'.'); + buf->Append(sName->Substring(i + 1)); + } + return mapCliString(buf->ToString()); +} +/** Maps uno types to dot net types. + * If uno_data is null then the type description is converted to System::Type + */ +inline System::String* mapUnoString( rtl_uString const * data) +{ + OSL_ASSERT(data); + return new System::String((__wchar_t*) data->buffer, 0, data->length); +} + +OUString mapCliString(System::String const * data) +{ + + if (data != NULL) + { + OSL_ASSERT(sizeof(wchar_t) == sizeof(sal_Unicode)); + wchar_t const __pin * pdata= PtrToStringChars(data); + return OUString(pdata, const_cast<System::String*>(data)->get_Length()); + } + else + { + return OUString(); + } +} + +// ToDo 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) +void Bridge::map_to_uno(void * uno_data, System::Object* cli_data, + typelib_TypeDescriptionReference * type, + bool assign) const +{ + try{ + switch (type->eTypeClass) + { + case typelib_TypeClass_VOID: + break; + case typelib_TypeClass_CHAR: + { + System::Char aChar= *__try_cast<System::Char*>(cli_data); + *(sal_Unicode*) uno_data= aChar; + break; + } + case typelib_TypeClass_BOOLEAN: + { + System::Boolean aBool= *__try_cast<System::Boolean*>(cli_data); + *(sal_Bool*)uno_data= aBool == true ? sal_True : sal_False; + break; + } + case typelib_TypeClass_BYTE: + { + System::Byte aByte= *__try_cast<System::Byte*>(cli_data); + *(sal_Int8*) uno_data= aByte; + break; + } + case typelib_TypeClass_SHORT: + { + System::Int16 aShort= *__try_cast<System::Int16*>(cli_data); + *(sal_Int16*) uno_data= aShort; + break; + } + case typelib_TypeClass_UNSIGNED_SHORT: + { + System::UInt16 aUShort= *__try_cast<System::UInt16*>(cli_data); + *(sal_uInt16*) uno_data= aUShort; + break; + } + case typelib_TypeClass_LONG: + { + System::Int32 aLong= *__try_cast<System::Int32*>(cli_data); + *(sal_Int32*) uno_data= aLong; + break; + } + case typelib_TypeClass_UNSIGNED_LONG: + { + System::UInt32 aULong= *__try_cast<System::UInt32*>(cli_data); + *(sal_uInt32*) uno_data= aULong; + break; + } + case typelib_TypeClass_HYPER: + { + System::Int64 aHyper= *__try_cast<System::Int64*>(cli_data); + *(sal_Int64*) uno_data= aHyper; + break; + } + case typelib_TypeClass_UNSIGNED_HYPER: + { + System::UInt64 aLong= *__try_cast<System::UInt64*>(cli_data); + *(sal_uInt64*) uno_data= aLong; + break; + } + case typelib_TypeClass_FLOAT: + { + System::Single aFloat= *__try_cast<System::Single*>(cli_data); + *(float*) uno_data= aFloat; + break; + } + case typelib_TypeClass_DOUBLE: + { + System::Double aDouble= *__try_cast<System::Double*>(cli_data); + *(double*) uno_data= aDouble; + break; + } + case typelib_TypeClass_STRING: + { + if (assign && *(rtl_uString**) uno_data) + rtl_uString_release(*(rtl_uString**) uno_data); + + *(rtl_uString **)uno_data = 0; + if (cli_data == NULL) + { + rtl_uString_new((rtl_uString**) uno_data); + } + else + { + System::String *s= __try_cast<System::String*>(cli_data); + wchar_t const __pin * pdata= PtrToStringChars(s); + rtl_uString_newFromStr_WithLength( (rtl_uString**) uno_data, + pdata, s->get_Length() ); + } + break; + } + case typelib_TypeClass_TYPE: + { + typelib_TypeDescriptionReference* td= mapCliType(__try_cast<System::Type*>( + cli_data)); + if (assign) + { + typelib_typedescriptionreference_release( + *(typelib_TypeDescriptionReference **)uno_data ); + } + *(typelib_TypeDescriptionReference **)uno_data = td; + break; + } + case typelib_TypeClass_ANY: + { + uno_Any * pAny = (uno_Any *)uno_data; + if (cli_data == NULL) // null-ref or uninitialized any maps to empty any + { + if (assign) + uno_any_destruct( pAny, 0 ); + uno_any_construct( pAny, 0, 0, 0 ); + break; + } + uno::Any aAny= *__try_cast<uno::Any*>(cli_data); + css::uno::Type value_td( mapCliType(aAny.Type), SAL_NO_ACQUIRE); + + if (assign) + uno_any_destruct( pAny, 0 ); + + try + { + switch (value_td.getTypeClass()) + { + case typelib_TypeClass_VOID: + pAny->pData = &pAny->pReserved; + break; + case typelib_TypeClass_CHAR: + pAny->pData = &pAny->pReserved; + *(sal_Unicode*) &pAny->pReserved = *__try_cast<System::Char*>(aAny.Value); + break; + case typelib_TypeClass_BOOLEAN: + pAny->pData = &pAny->pReserved; + *(sal_Bool *) &pAny->pReserved = *__try_cast<System::Boolean*>(aAny.Value); + break; + case typelib_TypeClass_BYTE: + pAny->pData = &pAny->pReserved; + *(sal_Int8*) &pAny->pReserved = *__try_cast<System::Byte*>(aAny.Value); + break; + case typelib_TypeClass_SHORT: + pAny->pData = &pAny->pReserved; + *(sal_Int16*) &pAny->pReserved = *__try_cast<System::Int16*>(aAny.Value); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + pAny->pData = &pAny->pReserved; + *(sal_uInt16*) &pAny->pReserved = *__try_cast<System::UInt16*>(aAny.Value); + break; + case typelib_TypeClass_LONG: + pAny->pData = &pAny->pReserved; + *(sal_Int32*) &pAny->pReserved = *__try_cast<System::Int32*>(aAny.Value); + break; + case typelib_TypeClass_UNSIGNED_LONG: + pAny->pData = &pAny->pReserved; + *(sal_uInt32*) &pAny->pReserved = *__try_cast<System::UInt32*>(aAny.Value); + break; + case typelib_TypeClass_HYPER: + if (sizeof (sal_Int64) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(sal_Int64*) &pAny->pReserved = *__try_cast<System::Int64*>(aAny.Value); + } + else + { + auto_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (sal_Int64) ) ); + *(sal_Int64 *) mem.get()= *__try_cast<System::Int64*>(aAny.Value); + pAny->pData = mem.release(); + } + break; + case typelib_TypeClass_UNSIGNED_HYPER: + if (sizeof (sal_uInt64) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(sal_uInt64*) &pAny->pReserved = *__try_cast<System::UInt64*>(aAny.Value); + } + else + { + auto_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (sal_uInt64) ) ); + *(sal_uInt64 *) mem.get()= *__try_cast<System::UInt64*>(aAny.Value); + pAny->pData = mem.release(); + } + break; + case typelib_TypeClass_FLOAT: + if (sizeof (float) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(float*) &pAny->pReserved = *__try_cast<System::Single*>(aAny.Value); + } + else + { + auto_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (float) ) ); + *(float*) mem.get() = *__try_cast<System::Single*>(aAny.Value); + pAny->pData = mem.release(); + } + break; + case typelib_TypeClass_DOUBLE: + if (sizeof (double) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(double*) &pAny->pReserved= *__try_cast<System::Double*>(aAny.Value); + } + else + { + auto_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (double) ) ); + *(double*) mem.get()= *__try_cast<System::Double*>(aAny.Value); + pAny->pData= mem.release(); + } + break; + case typelib_TypeClass_STRING: // anies often contain strings; copy string directly + { + pAny->pData= &pAny->pReserved; + OUString _s = mapCliString(static_cast<System::String*>(aAny.Value)); + pAny->pReserved= _s.pData; + rtl_uString_acquire(_s.pData); + break; + } + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ENUM: //ToDo copy enum direct + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_INTERFACE: + pAny->pData = &pAny->pReserved; + pAny->pReserved = 0; + map_to_uno( + &pAny->pReserved, aAny.Value, value_td.getTypeLibType(), + false /* no assign */); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + css::uno::Type anyType(value_td); + typelib_TypeDescription* td= NULL; + anyType.getDescription(&td); + auto_ptr< rtl_mem > mem(rtl_mem::allocate(td->nSize)); + typelib_typedescription_release(td); + map_to_uno( + mem.get(), aAny.Value, value_td.getTypeLibType(), + false /* no assign */); + pAny->pData = mem.release(); + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append(value_td.getTypeName()); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported value type of any!") ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + } + catch(System::InvalidCastException* ) + { +// ToDo check this + if (assign) + uno_any_construct( pAny, 0, 0, 0 ); // restore some valid any + OUStringBuffer buf( 256 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():Any") ); + buf.append(value_td.getTypeName()); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("]The Any type ")); + buf.append(value_td.getTypeName()); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" does not correspont " + "to its value type: ") ); + if(aAny.Value != NULL) + { + css::uno::Type td(mapCliType(aAny.Value->GetType()), SAL_NO_ACQUIRE); + buf.append(td.getTypeName()); + } + if (assign) + uno_any_construct( pAny, 0, 0, 0 ); // restore some valid any + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (BridgeRuntimeError& ) + { + if (assign) + uno_any_construct( pAny, 0, 0, 0 ); // restore some valid any + throw; + } + catch (...) + { + if (assign) + uno_any_construct( pAny, 0, 0, 0 ); // restore some valid any + throw; + } + + pAny->pType = value_td.getTypeLibType(); + typelib_typedescriptionreference_acquire(pAny->pType); + break; + } + case typelib_TypeClass_ENUM: + { + // InvalidCastException is caught at the end of this method + System::Int32 aEnum= System::Convert::ToInt32((cli_data)); + *(sal_Int32*) uno_data = aEnum; + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + css::uno::TypeDescription td(type); + typelib_CompoundTypeDescription * comp_td = + (typelib_CompoundTypeDescription*) td.get(); + + typelib_StructTypeDescription * struct_td = NULL; + if (type->eTypeClass == typelib_TypeClass_STRUCT) + struct_td = (typelib_StructTypeDescription*) td.get(); + + if ( ! ((typelib_TypeDescription*) comp_td)->bComplete) + ::typelib_typedescription_complete( + (typelib_TypeDescription**) & comp_td ); + + sal_Int32 nMembers = comp_td->nMembers; + boolean bException= false; + System::Type* cliType = NULL; + if (cli_data) + cliType = cli_data->GetType(); + + if (0 != comp_td->pBaseTypeDescription) + { + map_to_uno( + uno_data, cli_data, + ((typelib_TypeDescription *)comp_td->pBaseTypeDescription)->pWeakRef, + assign); + } + sal_Int32 nPos = 0; + try + { + typelib_TypeDescriptionReference * member_type= NULL; + + rtl::OUString usUnoException(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.Exception")); + for (; nPos < nMembers; ++nPos) + { + member_type= comp_td->ppTypeRefs[nPos]; +#if OSL_DEBUG_LEVEL >= 2 + System::String* __s; + sr::FieldInfo* arFields[]; + __s = mapUnoString(comp_td->ppMemberNames[nPos]); + arFields = cliType != NULL ? cliType->GetFields() : NULL; +#endif + System::Object* val= NULL; + if (cli_data != NULL) + { + sr::FieldInfo* aField= cliType->GetField( + mapUnoString(comp_td->ppMemberNames[nPos])); + // 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 ( ! aField && usUnoException.equals(td.get()->pTypeName)) + {// get Exception.Message property + rtl::OUString usMessageMember(RTL_CONSTASCII_USTRINGPARAM("Message")); + if (usMessageMember.equals(comp_td->ppMemberNames[nPos])) + { + sr::PropertyInfo* pi= cliType->GetProperty( + mapUnoString(comp_td->ppMemberNames[nPos])); + val= pi->GetValue(cli_data, NULL); + } + else + { + OUStringBuffer buf(512); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("[map_to_uno(): Member: ")); + buf.append(comp_td->ppMemberNames[nPos]); + throw BridgeRuntimeError(buf.makeStringAndClear()); + } + } + else + { + val= aField->GetValue(cli_data); + } + } + void * p = (char *) uno_data + comp_td->pMemberOffsets[ nPos ]; + //When using polymorphic structs then the parameterized members can be null. + //Then we set a default value. + bool bDefault = ((struct_td != NULL + && struct_td->pParameterizedTypes != NULL + && struct_td->pParameterizedTypes[nPos] == sal_True + && val == NULL) + || cli_data == NULL) ? true : false; + switch (member_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + if (bDefault) + *(sal_Unicode*) p = 0; + else + *(sal_Unicode*) p = *__try_cast<System::Char*>(val); + break; + case typelib_TypeClass_BOOLEAN: + if (bDefault) + *(sal_Bool*) p = sal_False; + else + *(sal_Bool*) p = *__try_cast<System::Boolean*>(val); + break; + case typelib_TypeClass_BYTE: + if (bDefault) + *(sal_Int8*) p = 0; + else + *(sal_Int8*) p = *__try_cast<System::Byte*>(val); + break; + case typelib_TypeClass_SHORT: + if (bDefault) + *(sal_Int16*) p = 0; + else + *(sal_Int16*) p = *__try_cast<System::Int16*>(val); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + if (bDefault) + *(sal_uInt16*) p = 0; + else + *(sal_uInt16*) p = *__try_cast<System::UInt16*>(val); + break; + case typelib_TypeClass_LONG: + if (bDefault) + *(sal_Int32*) p = 0; + else + *(sal_Int32*) p = *__try_cast<System::Int32*>(val); + break; + case typelib_TypeClass_UNSIGNED_LONG: + if (bDefault) + *(sal_uInt32*) p = 0; + else + *(sal_uInt32*) p = *__try_cast<System::UInt32*>(val); + break; + case typelib_TypeClass_HYPER: + if (bDefault) + *(sal_Int64*) p = 0; + else + *(sal_Int64*) p = *__try_cast<System::Int64*>(val); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + if (bDefault) + *(sal_uInt64*) p = 0; + else + *(sal_uInt64*) p= *__try_cast<System::UInt64*>(val); + break; + case typelib_TypeClass_FLOAT: + if (bDefault) + *(float*) p = 0.; + else + *(float*) p = *__try_cast<System::Single*>(val); + break; + case typelib_TypeClass_DOUBLE: + if (bDefault) + *(double*) p = 0.; + else + *(double*) p = *__try_cast<System::Double*>(val); + break; + default: + { // ToDo enum, should be converted here + map_to_uno(p, val, member_type, assign); + break; + } + } + } + } + catch (BridgeRuntimeError& e) + { + bException= true; + OUStringBuffer buf(512); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("[map_to_uno():")); + if (cliType) + { + buf.append(mapCliString(cliType->get_FullName())); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(".")); + buf.append(comp_td->ppMemberNames[nPos]); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" ")); + } + buf.append(e.m_message); + throw BridgeRuntimeError(buf.makeStringAndClear()); + } + catch (System::InvalidCastException* ) + { + bException= true; + OUStringBuffer buf( 256 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + if (cliType) + { + buf.append(mapCliString(cliType->get_FullName())); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(".")); + buf.append(comp_td->ppMemberNames[nPos]); + } + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] Value has not the required type.")); + throw BridgeRuntimeError(buf.makeStringAndClear()); + } + catch (...) + { + OSL_ASSERT(0); + bException= true; + throw; + } + __finally + { + if (bException && !assign) // if assign then caller cleans up + { + // cleanup the members which we have converted so far + for ( sal_Int32 nCleanup = 0; nCleanup < nPos; ++nCleanup ) + { + uno_type_destructData( + uno_data, comp_td->ppTypeRefs[ nCleanup ], 0 ); + } + if (0 != comp_td->pBaseTypeDescription) + { + uno_destructData( + uno_data, (typelib_TypeDescription *)comp_td->pBaseTypeDescription, 0 ); + } + } + } + break; + } + case typelib_TypeClass_SEQUENCE: + { + TypeDescr td( type ); + typelib_TypeDescriptionReference * element_type = + ((typelib_IndirectTypeDescription *)td.get())->pType; + + auto_ptr< rtl_mem > seq; + + System::Array* ar = NULL; + if (cli_data != NULL) + { + ar = __try_cast<System::Array*>(cli_data); + sal_Int32 nElements = ar->GetLength(0); + + try + { + switch (element_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + seq = seq_allocate(nElements, sizeof (sal_Unicode)); + sri::Marshal::Copy(__try_cast<System::Char[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_BOOLEAN: + seq = seq_allocate(nElements, sizeof (sal_Bool)); + sri::Marshal::Copy(__try_cast<System::Boolean[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_BYTE: + seq = seq_allocate( nElements, sizeof (sal_Int8) ); + sri::Marshal::Copy(__try_cast<System::Byte[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_SHORT: + seq = seq_allocate(nElements, sizeof (sal_Int16)); + sri::Marshal::Copy(__try_cast<System::Int16[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + seq = seq_allocate( nElements, sizeof (sal_uInt16) ); + sri::Marshal::Copy(static_cast<System::Int16[]>( + __try_cast<System::UInt16[]>(cli_data)), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_LONG: + seq = seq_allocate(nElements, sizeof (sal_Int32)); + sri::Marshal::Copy(__try_cast<System::Int32[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_UNSIGNED_LONG: + seq = seq_allocate( nElements, sizeof (sal_uInt32) ); + sri::Marshal::Copy(static_cast<System::Int32[]>( + __try_cast<System::UInt32[]>(cli_data)), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_HYPER: + seq = seq_allocate(nElements, sizeof (sal_Int64)); + sri::Marshal::Copy(__try_cast<System::Int64[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + seq = seq_allocate(nElements, sizeof (sal_uInt64)); + sri::Marshal::Copy(static_cast<System::Int64[]>( + __try_cast<System::UInt64[]>(cli_data)), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_FLOAT: + seq = seq_allocate(nElements, sizeof (float)); + sri::Marshal::Copy(__try_cast<System::Single[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_DOUBLE: + seq = seq_allocate(nElements, sizeof (double)); + sri::Marshal::Copy(__try_cast<System::Double[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_STRING: + { + seq = seq_allocate(nElements, sizeof (rtl_uString*)); + System::String* arStr[]= __try_cast<System::String*[]>(cli_data); + for (int i= 0; i < nElements; i++) + { + wchar_t const __pin * pdata= PtrToStringChars(arStr[i]); + rtl_uString** pStr= & ((rtl_uString**) & + ((uno_Sequence*) seq.get())->elements)[i]; + *pStr= NULL; + rtl_uString_newFromStr_WithLength( pStr, pdata, + arStr[i]->get_Length()); + } + break; + } + case typelib_TypeClass_ENUM: + seq = seq_allocate(nElements, sizeof (sal_Int32)); + for (int i= 0; i < nElements; i++) + { + ((sal_Int32*) &((uno_Sequence*) seq.get())->elements)[i]= + System::Convert::ToInt32(ar->GetValue(i)); + } + break; + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ANY: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_INTERFACE: + { + TypeDescr element_td( element_type ); + seq = seq_allocate( nElements, element_td.get()->nSize ); + + for (sal_Int32 nPos = 0; nPos < nElements; ++nPos) + { + try + { + void * p= ((uno_Sequence *) seq.get())->elements + + (nPos * element_td.get()->nSize); + System::Object* elemData= dynamic_cast<System::Array*>(cli_data)->GetValue(nPos); + map_to_uno( + p, elemData, element_td.get()->pWeakRef, + false /* no assign */); + } + catch (...) + { + // cleanup + for ( sal_Int32 nCleanPos = 0; nCleanPos < nPos; ++nCleanPos ) + { + void * p = + ((uno_Sequence *)seq.get())->elements + + (nCleanPos * element_td.get()->nSize); + uno_destructData( p, element_td.get(), 0 ); + } + throw; + } + } + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported sequence element type: ") ); + buf.append( *reinterpret_cast< OUString const * >( &element_type->pTypeName ) ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + } + catch (BridgeRuntimeError& e) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName )); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] conversion failed\n ")); + buf.append(e.m_message); + throw BridgeRuntimeError(buf.makeStringAndClear()); + } + catch (System::InvalidCastException* ) + { + // Ok, checked + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] could not convert sequence element type: ") ); + buf.append( *reinterpret_cast< OUString const * >( &element_type->pTypeName ) ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (...) + { + OSL_ASSERT(0); + throw; + } + __finally + { + if (assign) + uno_destructData( uno_data, td.get(), 0 ); + } + } + else + { + seq = seq_allocate(0, sizeof (sal_Int32)); + } + *(uno_Sequence **)uno_data = (uno_Sequence *)seq.release(); + break; + } + case typelib_TypeClass_INTERFACE: + { + if (assign) + { + uno_Interface * p = *(uno_Interface **)uno_data; + if (0 != p) + (*p->release)( p ); + } + if (0 == cli_data) // null-ref + { + *(uno_Interface **)uno_data = 0; + } + else + { + TypeDescr td( type ); + uno_Interface * pUnoI = map_cli2uno(cli_data, td.get()); + *(uno_Interface **)uno_data = pUnoI; + } + break; + } + default: + { + //ToDo check + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported type!") ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + } + // BridgeRuntimeError are allowed to be thrown + catch (System::InvalidCastException* ) + { + //ToDo check + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] could not convert type!") ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (System::NullReferenceException * e) + { + OUStringBuffer buf(512); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( + "[map_to_uno()] Illegal null reference passed!\n")); + buf.append(mapCliString(e->get_StackTrace())); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (BridgeRuntimeError& ) + { + throw; + } + catch (...) + { + OSL_ASSERT(0); + throw; + } + +} + +/** + @param info + The expected target type. Currently info is provdided when this method is called + to convert the in/out and out parameters of a call from cli to uno. Then info + is always a byref type, e.g. "System.String&". info is used for Any and Enum conversion. + @param bDontCreateObj + false - a new object is created which holds the mapped uno value and is assigned to + cli_data. + true - cli_data already contains the newly constructed object. This is the case if + a struct is converted then on the first call to map_to_cli the new object is created. + If the struct inherits another struct then this function is called recursivly while the + newly created object is passed in cli_data. + */ +void Bridge::map_to_cli( + System::Object* *cli_data, void const * uno_data, + typelib_TypeDescriptionReference * type, System::Type* info, + bool bDontCreateObj) const +{ + switch (type->eTypeClass) + { + case typelib_TypeClass_CHAR: + *cli_data= __box(*(__wchar_t const*)uno_data); + break; + case typelib_TypeClass_BOOLEAN: + *cli_data = __box((*(bool const*)uno_data) == sal_True ? true : false); + break; + case typelib_TypeClass_BYTE: + *cli_data = __box(*(unsigned char const*) uno_data); + break; + case typelib_TypeClass_SHORT: + *cli_data= __box(*(short const*) uno_data); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + *cli_data= __box(*(unsigned short const*) uno_data); + break; + case typelib_TypeClass_LONG: + *cli_data= __box(*(int const*) uno_data); + break; + case typelib_TypeClass_UNSIGNED_LONG: + *cli_data= __box(*(unsigned int const*) uno_data); + break; + case typelib_TypeClass_HYPER: + *cli_data= __box(*(__int64 const*) uno_data); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + *cli_data= __box(*(unsigned __int64 const*) uno_data); + break; + case typelib_TypeClass_FLOAT: + *cli_data= __box(*(float const*) uno_data); + break; + case typelib_TypeClass_DOUBLE: + *cli_data= __box(*(double const*) uno_data); + break; + case typelib_TypeClass_STRING: + { + rtl_uString const* sVal= NULL; + sVal= *(rtl_uString* const*) uno_data; + *cli_data= new System::String((__wchar_t*) sVal->buffer,0, sVal->length); + break; + } + case typelib_TypeClass_TYPE: + { + *cli_data= mapUnoType( *(typelib_TypeDescriptionReference * const *)uno_data ); + break; + } + case typelib_TypeClass_ANY: + { + uno_Any const * pAny = (uno_Any const *)uno_data; + if (typelib_TypeClass_VOID != pAny->pType->eTypeClass) + { + System::Object* objCli= NULL; + map_to_cli( + &objCli, pAny->pData, pAny->pType, 0, + false); + + uno::Any anyVal(mapUnoType(pAny->pType), objCli); + *cli_data= __box(anyVal); + } + else + { // void any + *cli_data= __box(uno::Any::VOID); + } + break; + } + case typelib_TypeClass_ENUM: + { + if (info != NULL) + { + OSL_ASSERT(info->get_IsByRef()); + info= info->GetElementType(); + *cli_data= System::Enum::ToObject(info, *(System::Int32*) uno_data); + } + else + *cli_data= System::Enum::ToObject( + mapUnoType(type), *(System::Int32*) uno_data); + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + TypeDescr td( type ); + typelib_CompoundTypeDescription * comp_td = + (typelib_CompoundTypeDescription *) td.get(); + if ( ! ((typelib_TypeDescription*) comp_td)->bComplete) + ::typelib_typedescription_complete( + (typelib_TypeDescription**) & comp_td ); + + + //create the type + System::Type* cliType= loadCliType(td.get()->pTypeName); + //detect if we recursivly convert inherited structures + //If this point is reached because of a recursive call during convering a + //struct then we must not create a new object rather we use the one in + // cli_data argument. + System::Object* cliObj; + if (bDontCreateObj) + cliObj = *cli_data; // recursive call + else + { + //Special handling for Exception conversion. We must call constructor System::Exception + //to pass the message string + if (__typeof(ucss::uno::Exception)->IsAssignableFrom(cliType)) + { + //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 + typelib_CompoundTypeDescription* pCTD = comp_td; + while (pCTD->pBaseTypeDescription) + pCTD = pCTD->pBaseTypeDescription; + int nPos = -1; + + rtl::OUString usMessageMember(RTL_CONSTASCII_USTRINGPARAM("Message")); + for (int i = 0; i < pCTD->nMembers; i ++) + { +#if OSL_DEBUG_LEVEL >= 2 + System::String* sMember; + sMember = mapUnoString(pCTD->ppMemberNames[i]); +#endif + if (usMessageMember.equals(pCTD->ppMemberNames[i])) + { + nPos = i; + break; + } + } + OSL_ASSERT (nPos != -1); + int offset = pCTD->pMemberOffsets[nPos]; + //Whith the offset within the exception we can get the message string + System::String* sMessage = mapUnoString(*(rtl_uString**) + ((char*) uno_data + 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 + sr::ConstructorInfo* arCtorInfo[] = cliType->GetConstructors(); + sr::ConstructorInfo* ctorInfo = NULL; + int numCtors = arCtorInfo->get_Length(); + //Constructor must at least have 2 params for the base + //unoidl.com.sun.star.uno.Exception (String, Object); + sr::ParameterInfo * arParamInfo[]; + for (int i = 0; i < numCtors; i++) + { + arParamInfo = arCtorInfo[i]->GetParameters(); + if (arParamInfo->get_Length() < 2) + continue; + ctorInfo = arCtorInfo[i]; + break; + } + OSL_ASSERT(arParamInfo[0]->get_ParameterType()->Equals(__typeof(System::String)) + && arParamInfo[1]->get_ParameterType()->Equals(__typeof(System::Object)) + && arParamInfo[0]->get_Position() == 0 + && arParamInfo[1]->get_Position() == 1); + //Prepare parameters for constructor + int numArgs = arParamInfo->get_Length(); + System::Object * args[] = new System::Object*[numArgs]; + //only initialize the first argument with the message + args[0] = sMessage; + cliObj = ctorInfo->Invoke(args); + } + else + cliObj = System::Activator::CreateInstance(cliType); + } + sal_Int32 * pMemberOffsets = comp_td->pMemberOffsets; + + if (comp_td->pBaseTypeDescription) + { + //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 + map_to_cli( + &cliObj, uno_data, + ((typelib_TypeDescription *)comp_td->pBaseTypeDescription)->pWeakRef, 0, + true); + } + rtl::OUString usUnoException(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.Exception")); + for (sal_Int32 nPos = comp_td->nMembers; nPos--; ) + { + typelib_TypeDescriptionReference * member_type = comp_td->ppTypeRefs[ nPos ]; + System::String* sMemberName= mapUnoString(comp_td->ppMemberNames[nPos]); + sr::FieldInfo* aField= cliType->GetField(sMemberName); + // special case for Exception.Message. The field has already been + // set while constructing cli object + if ( ! aField && usUnoException.equals(td.get()->pTypeName)) + { + continue; + } + void const * p = (char const *)uno_data + pMemberOffsets[ nPos ]; + switch (member_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + aField->SetValue(cliObj, __box(*(System::Char*) p)); + break; + case typelib_TypeClass_BOOLEAN: + aField->SetValue(cliObj, __box(*(System::Boolean*) p)); + break; + case typelib_TypeClass_BYTE: + aField->SetValue(cliObj, __box(*(System::Byte*) p)); + break; + case typelib_TypeClass_SHORT: + aField->SetValue(cliObj, __box(*(System::Int16*) p)); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + aField->SetValue(cliObj, __box(*(System::UInt16*) p)); + break; + case typelib_TypeClass_LONG: + aField->SetValue(cliObj, __box(*(System::Int32*) p)); + break; + case typelib_TypeClass_UNSIGNED_LONG: + aField->SetValue(cliObj, __box(*(System::UInt32*) p)); + break; + case typelib_TypeClass_HYPER: + aField->SetValue(cliObj, __box(*(System::Int64*) p)); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + aField->SetValue(cliObj, __box(*(System::UInt64*) p)); + break; + case typelib_TypeClass_FLOAT: + aField->SetValue(cliObj, __box(*(System::Single*) p)); + break; + case typelib_TypeClass_DOUBLE: + aField->SetValue(cliObj, __box(*(System::Double*) p)); + break; + default: + { + System::Object* cli_val; + map_to_cli( + &cli_val, p, member_type, 0, + false); + aField->SetValue(cliObj, cli_val); + break; + } + } + } + *cli_data= cliObj; + break; + } + case typelib_TypeClass_SEQUENCE: + { + sal_Int32 nElements; + uno_Sequence const * seq = 0; + seq = *(uno_Sequence * const *)uno_data; + nElements = seq->nElements; + + TypeDescr td( type ); + typelib_TypeDescriptionReference * element_type = + ((typelib_IndirectTypeDescription *)td.get())->pType; + + switch (element_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + { + System::Char arChar[]= new System::Char[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arChar, 0, nElements); + *cli_data= arChar; + break; + } + case typelib_TypeClass_BOOLEAN: + { + System::Boolean arBool[]= new System::Boolean[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arBool, 0, nElements); + *cli_data= arBool; + break; + } + case typelib_TypeClass_BYTE: + { + System::Byte arByte[]= new System::Byte[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arByte, 0, nElements); + *cli_data= arByte; + break; + } + case typelib_TypeClass_SHORT: + { + System::Int16 arShort[]= new System::Int16[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arShort, 0, nElements); + *cli_data= arShort; + break; + } + case typelib_TypeClass_UNSIGNED_SHORT: + { + System::UInt16 arUInt16[]= new System::UInt16[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, static_cast<System::Int16[]>(arUInt16), + 0, nElements); + *cli_data= arUInt16; + break; + } + case typelib_TypeClass_LONG: + { + System::Int32 arInt32[]= new System::Int32[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arInt32, 0, nElements); + *cli_data= arInt32; + break; + } + case typelib_TypeClass_UNSIGNED_LONG: + { + System::UInt32 arUInt32[]= new System::UInt32[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, static_cast<System::Int32[]>(arUInt32), + 0, nElements); + *cli_data= arUInt32; + break; + } + case typelib_TypeClass_HYPER: + { + System::Int64 arInt64[]= new System::Int64[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arInt64, 0, nElements); + *cli_data= arInt64; + break; + } + case typelib_TypeClass_UNSIGNED_HYPER: + { + System::UInt64 arUInt64[]= new System::UInt64[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arUInt64, 0, nElements); + *cli_data= arUInt64; + break; + } + case typelib_TypeClass_FLOAT: + { + System::Single arSingle[]= new System::Single[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arSingle, 0, nElements); + *cli_data= arSingle; + break; + } + case typelib_TypeClass_DOUBLE: + { + System::Double arDouble[]= new System::Double[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arDouble, 0, nElements); + *cli_data= arDouble; + break; + } + case typelib_TypeClass_STRING: + { + System::String* arString[]= new System::String*[nElements]; + for (int i= 0; i < nElements; i++) + { + rtl_uString *aStr= ((rtl_uString**)(&seq->elements))[i]; + arString[i]= new System::String( (__wchar_t *) &aStr->buffer, 0, aStr->length); + } + *cli_data= arString; + break; + } + case typelib_TypeClass_TYPE: + { + System::Type* arType[]= new System::Type*[nElements]; + for (int i= 0; i < nElements; i++) + { + arType[i]= + mapUnoType( ((typelib_TypeDescriptionReference**) seq->elements)[i]); + } + *cli_data= arType; + break; + } + case typelib_TypeClass_ANY: + { + uno::Any arCli[]= new uno::Any[nElements]; + uno_Any const * p = (uno_Any const *)seq->elements; + for (sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + System::Object* cli_obj = NULL; + map_to_cli( + &cli_obj, &p[ nPos ], element_type, 0, false); + arCli[nPos]= *__try_cast<__box uno::Any*>(cli_obj); + } + *cli_data= arCli; + break; + } + case typelib_TypeClass_ENUM: + { + //get the Enum type + System::Type* enumType= NULL; + if (info != NULL) + { + //info is EnumType[]&, remove & + OSL_ASSERT(info->IsByRef); + enumType = info->GetElementType(); + //enumType is EnumType[], remove [] + enumType = enumType->GetElementType(); + } + else + enumType= mapUnoType(element_type); + + System::Array* arEnum = System::Array::CreateInstance( + enumType, nElements); + for (int i= 0; i < nElements; i++) + { + arEnum->SetValue(System::Enum::ToObject(enumType, + ((sal_Int32*) seq->elements)[i]), i); + } + *cli_data = arEnum; + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + TypeDescr element_td( element_type ); + System::Array* ar= System::Array::CreateInstance( + mapUnoType(element_type),nElements); + if (0 < nElements) + { + // ToDo check this + char * p = (char *) &seq->elements; + sal_Int32 nSize = element_td.get()->nSize; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + System::Object* val; + map_to_cli( + &val, p + (nSize * nPos), element_type, 0, false); + ar->SetValue(val, nPos); + } + } + *cli_data = ar; + break; + } +// ToDo, verify + case typelib_TypeClass_SEQUENCE: + { + System::Array *ar= System::Array::CreateInstance( + mapUnoType(element_type), nElements); + if (0 < nElements) + { + TypeDescr element_td( element_type ); + uno_Sequence ** elements = (uno_Sequence**) seq->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + System::Object* val; + map_to_cli( + &val, &elements[nPos], element_type, 0, false); + ar->SetValue(val, nPos); + } + } + *cli_data = ar; + break; + } + case typelib_TypeClass_INTERFACE: + { + TypeDescr element_td( element_type ); + System::Type * ifaceType= mapUnoType(element_type); + System::Array* ar= System::Array::CreateInstance(ifaceType, nElements); + + char * p = (char *)seq->elements; + sal_Int32 nSize = element_td.get()->nSize; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + System::Object* val; + map_to_cli( + &val, p + (nSize * nPos), element_type, NULL, false); + + ar->SetValue(val, nPos); + } + *cli_data= ar; + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_cli():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported element type: ") ); + buf.append( *reinterpret_cast< OUString const * >( &element_type->pTypeName ) ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + break; + } + case typelib_TypeClass_INTERFACE: + { + uno_Interface * pUnoI = *(uno_Interface * const *)uno_data; + if (0 != pUnoI) + { + TypeDescr td( type ); + *cli_data= map_uno2cli( pUnoI, reinterpret_cast< + typelib_InterfaceTypeDescription*>(td.get())) ; + } + else + *cli_data= NULL; + break; + } + default: + { + //ToDo check this exception. The String is probably crippled + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_cli():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported type!") ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } +} +} diff --git a/cli_ure/source/uno_bridge/cli_environment.cxx b/cli_ure/source/uno_bridge/cli_environment.cxx new file mode 100644 index 000000000000..cfa0f8e57817 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_environment.cxx @@ -0,0 +1,173 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" + +#include "Cli_environment.h" + +#using <mscorlib.dll> +#using <cli_ure.dll> +#using <system.dll> +#include "osl/diagnose.h" +#include "cli_proxy.h" + +using namespace System::Runtime::Remoting; +using namespace System::Runtime::Remoting::Proxies; +using namespace System::Collections; +using namespace System::Text; +using namespace System::Diagnostics; +using namespace System::Threading; + +namespace cli_uno +{ + +inline System::String* Cli_environment::createKey(System::String* oid, System::Type* t) +{ + return System::String::Concat(oid, t->get_FullName()); +} + + +inline Cli_environment::Cli_environment() +{ +#if OSL_DEBUG_LEVEL >= 2 + _numRegisteredObjects = 0; +#endif +} + +Cli_environment::~Cli_environment() +{ + OSL_ENSURE(_numRegisteredObjects == 0, + "cli uno bridge: CLI environment contains unrevoked objects"); +} + + +System::Object* Cli_environment::registerInterface( + System::Object* obj, System::String* oid) +{ +#if OSL_DEBUG_LEVEL >= 1 + //obj must be a transparent proxy + OSL_ASSERT(RemotingServices::IsTransparentProxy(obj)); + _numRegisteredObjects ++; +#endif + OSL_ASSERT( ! m_objects->ContainsKey(oid)); + m_objects->Add(oid, new WeakReference(obj)); + return obj; +} +System::Object* Cli_environment::registerInterface ( + System::Object* obj, System::String* oid, System::Type* type) +{ +#if OSL_DEBUG_LEVEL >= 1 + //obj must be a real cli object + OSL_ASSERT( ! RemotingServices::IsTransparentProxy(obj)); + _numRegisteredObjects ++; +#endif + System::String* key = createKey(oid, type); + //see synchronization in map_uno2cli in cli_data.cxx + OSL_ASSERT( ! m_objects->ContainsKey(key)); + m_objects->Add(key, new WeakReference(obj)); + return obj; +} + +void Cli_environment::revokeInterface(System::String* oid, System::Type* type) +{ + System::String* key = type != NULL ? createKey(oid, type) : oid; +#if OSL_DEBUG_LEVEL >= 1 + _numRegisteredObjects --; +#endif +#if OSL_DEBUG_LEVEL >= 2 + int i = 1; + if (m_objects->ContainsKey(key) == false) + { + Trace::WriteLine("cli uno bridge: try to revoke unregistered interface"); + Trace::WriteLine(oid); + i = 0; + } + Trace::WriteLine(System::String::Format( + new System::String(S"cli uno bridge: {0} remaining registered interfaces"), + __box(m_objects->get_Count() - 1))); +#endif + m_objects->Remove(key); +} + +inline void Cli_environment::revokeInterface(System::String* oid) +{ + return revokeInterface(oid, NULL); +} + +System::Object* Cli_environment::getRegisteredInterface(System::String* oid, + System::Type* type) +{ + //try if it is a UNO interface + System::Object* ret = NULL; + ret = m_objects->get_Item(oid); + if (! ret) + { + //try if if it is a proxy for a cli object + oid = createKey(oid, type); + ret = m_objects->get_Item( oid ); + } + if (ret != 0) + { + System::WeakReference* weakIface = + static_cast< System::WeakReference * >( ret ); + ret = weakIface->Target; + } + if (ret == 0) + m_objects->Remove( oid ); + return ret; +} + +System::String* Cli_environment::getObjectIdentifier(System::Object* obj) +{ + System::String* oId= 0; + RealProxy* aProxy= RemotingServices::GetRealProxy(obj); + if (aProxy) + { + UnoInterfaceProxy* proxyImpl= dynamic_cast<UnoInterfaceProxy*>(aProxy); + if (proxyImpl) + oId= proxyImpl->getOid(); + } + + if (oId == 0) + { + StringBuilder * buf= new StringBuilder(256); + bool bFirst = false; + System::Threading::Monitor::Enter(__typeof(Cli_environment)); + try { + buf->Append(m_IDGen->GetId(obj, & bFirst)); + } __finally + { + System::Threading::Monitor::Exit(__typeof(Cli_environment)); + } + + buf->Append(sOidPart); + oId= buf->ToString(); + } + return oId; +} +} //namespace cli_uno diff --git a/cli_ure/source/uno_bridge/cli_environment.h b/cli_ure/source/uno_bridge/cli_environment.h new file mode 100644 index 000000000000..486d5c169807 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_environment.h @@ -0,0 +1,114 @@ +/************************************************************************* + * + * 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_CLI_ENVIRONMENT_H +#define INCLUDED_CLI_ENVIRONMENT_H + +#include "cli_base.h" +#using <mscorlib.dll> + +using namespace System; +using namespace System::Collections; +using namespace System::Runtime::Serialization; + +namespace cli_uno +{ + +public __gc class Cli_environment +{ + static System::String* sOidPart; + static Hashtable* m_objects; + static System::Runtime::Serialization::ObjectIDGenerator* m_IDGen; + inline static System::String* createKey(System::String* oid, System::Type* t); + +#if OSL_DEBUG_LEVEL >= 1 + int _numRegisteredObjects; +#endif + +public: + + static Cli_environment() + { + m_objects = Hashtable::Synchronized(new Hashtable()); + m_IDGen = new System::Runtime::Serialization::ObjectIDGenerator(); + System::Text::StringBuilder* buffer = new System::Text::StringBuilder(256); + Guid gd = Guid::NewGuid(); + buffer->Append(S";cli[0];"); + buffer->Append(gd.ToString()); + sOidPart = buffer->ToString(); + } + + inline Cli_environment(); + + ~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. + */ + Object* registerInterface(Object* obj, System::String* oid); + /** + Registers a CLI object as being mapped by this bridge. The resulting + object represents exactly one UNO interface. + */ + Object* registerInterface(Object* obj, System::String* oid, System::Type* type); + + /** + By revoking an interface it is declared that the respective interface has + not been mapped. The proxy implementations call revoke interface in their + destructors. + */ + inline void revokeInterface(System::String* oid); + + void revokeInterface(System::String* oid, System::Type* type); + /** + * 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 + */ + Object* getRegisteredInterface(System::String* oid, System::Type* type); + + /** + * 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. + */ + static System::String* getObjectIdentifier(Object* obj); + +}; + +} //namespace cli_uno + + +#endif diff --git a/cli_ure/source/uno_bridge/cli_proxy.cxx b/cli_ure/source/uno_bridge/cli_proxy.cxx new file mode 100644 index 000000000000..0fd662a24fe9 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_proxy.cxx @@ -0,0 +1,1178 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" +#include "typelib/typedescription.h" +#include "rtl/ustrbuf.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "osl/mutex.hxx" +#include "cli_proxy.h" +#include "cli_base.h" +#include "cli_bridge.h" + +#using <mscorlib.dll> +#using <cli_ure.dll> +#using <cli_uretypes.dll> + +namespace sr = System::Reflection; +namespace st = System::Text; +namespace sre = System::Reflection::Emit; +namespace sc = System::Collections; +namespace srrm = System::Runtime::Remoting::Messaging; +namespace srr = System::Runtime::Remoting; +namespace srrp = System::Runtime::Remoting::Proxies; +namespace sri = System::Runtime::InteropServices; +namespace sd = System::Diagnostics; +namespace css = com::sun::star; +namespace ucss = unoidl::com::sun::star; + +using namespace cli_uno; +using namespace rtl; +extern "C" +{ +//------------------------------------------------------------------------------ +void SAL_CALL cli_proxy_free( uno_ExtEnvironment * env, void * proxy ) + SAL_THROW_EXTERN_C(); +//------------------------------------------------------------------------------ +void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C(); +//------------------------------------------------------------------------------ +void SAL_CALL cli_proxy_release( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C(); +//------------------------------------------------------------------------------ +void SAL_CALL cli_proxy_dispatch( + uno_Interface * pUnoI, typelib_TypeDescription const * member_td, + void * uno_ret, void * uno_args[], uno_Any ** uno_exc ) + SAL_THROW_EXTERN_C(); + + +} + +namespace cli_uno +{ + +UnoInterfaceInfo::UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI, + typelib_InterfaceTypeDescription* td): + + m_unoI(unoI), + m_typeDesc(td), + m_bridge(bridge) +{ + m_bridge->acquire(); + m_type = mapUnoType(reinterpret_cast<typelib_TypeDescription*>(td)); + m_unoI->acquire(m_unoI); + typelib_typedescription_acquire(&m_typeDesc->aBase); + if ( ! m_typeDesc->aBase.bComplete) + { + typelib_TypeDescription* _pt = &m_typeDesc->aBase; + sal_Bool bComplete = ::typelib_typedescription_complete( & _pt); + if( ! bComplete) + { + OUStringBuffer buf( 128 ); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( + "cannot make type complete: ") ); + buf.append( *reinterpret_cast< OUString const * >( + & m_typeDesc->aBase.pTypeName)); + throw BridgeRuntimeError(buf.makeStringAndClear()); + } + } +} +UnoInterfaceInfo::~UnoInterfaceInfo() +{ + //accessing unmanaged objects is ok. + m_bridge->m_uno_env->revokeInterface( + m_bridge->m_uno_env, m_unoI ); + m_bridge->release(); + + m_unoI->release(m_unoI); + typelib_typedescription_release( + reinterpret_cast<typelib_TypeDescription*>(m_typeDesc)); +} + +UnoInterfaceProxy::UnoInterfaceProxy( + Bridge * bridge, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription* pTD, + const OUString& oid ) + :RealProxy(__typeof(MarshalByRefObject)), + m_bridge(bridge), + m_oid(mapUnoString(oid.pData)), + m_sTypeName(m_system_Object_String) +{ + m_bridge->acquire(); + // create the list that holds all UnoInterfaceInfos + m_listIfaces = new ArrayList(10); + m_numUnoIfaces = 0; + m_listAdditionalProxies = new ArrayList(); + m_nlistAdditionalProxies = 0; + //put the information of the first UNO interface into the arraylist +#if OSL_DEBUG_LEVEL >= 2 + _numInterfaces = 0; + _sInterfaces = NULL; +#endif + addUnoInterface(pUnoI, pTD); + +} + +UnoInterfaceProxy::~UnoInterfaceProxy() +{ +#if OSL_DEBUG_LEVEL >= 2 + sd::Trace::WriteLine(System::String::Format( + new System::String(S"cli uno bridge: Destroying proxy " + S"for UNO object, OID: \n\t{0} \n\twith uno interfaces: "), + m_oid)); + + sd::Trace::WriteLine( mapUnoString(_sInterfaces)); + rtl_uString_release(_sInterfaces); +#endif + //m_bridge is unmanaged, therefore we can access it in this finalizer + CliEnvHolder::g_cli_env->revokeInterface(m_oid); + m_bridge->release(); +} + + +System::Object* UnoInterfaceProxy::create( + Bridge * bridge, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription* pTD, + const OUString& oid) +{ + UnoInterfaceProxy* proxyHandler= + new UnoInterfaceProxy(bridge, pUnoI, pTD, oid); + System::Object* proxy= proxyHandler->GetTransparentProxy(); + CliEnvHolder::g_cli_env->registerInterface(proxy, mapUnoString(oid.pData)); + return proxy; +} + + +void UnoInterfaceProxy::addUnoInterface(uno_Interface* pUnoI, + typelib_InterfaceTypeDescription* pTd) +{ + sc::IEnumerator* enumInfos = m_listIfaces->GetEnumerator(); + System::Threading::Monitor::Enter(this); + try + { + while (enumInfos->MoveNext()) + { + UnoInterfaceInfo* info = static_cast<UnoInterfaceInfo*>( + enumInfos->Current); +#if OSL_DEBUG_LEVEL > 1 + System::Type * t1; + System::Type * t2; + t1 = mapUnoType( + reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc) ); + t2 = mapUnoType( + reinterpret_cast<typelib_TypeDescription*>(pTd) ); +#endif + if (typelib_typedescription_equals( + reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc), + reinterpret_cast<typelib_TypeDescription*>(pTd))) + { + return; + } + } + OUString oid(mapCliString(m_oid)); + (*m_bridge->m_uno_env->registerInterface)( + m_bridge->m_uno_env, reinterpret_cast< void ** >( &pUnoI ), + oid.pData, pTd); + //This proxy does not contain the uno_Interface. Add it. + m_listIfaces->Add(new UnoInterfaceInfo(m_bridge, pUnoI, pTd)); + m_numUnoIfaces = m_listIfaces->Count; +#if OSL_DEBUG_LEVEL >= 2 + System::String * sInterfaceName = static_cast<UnoInterfaceInfo*>( + m_listIfaces->get_Item(m_numUnoIfaces - 1))->m_type->FullName; + sd::Trace::WriteLine(System::String::Format( + new System::String(S"cli uno bridge: Creating proxy for uno object, " + S"id:\n\t{0}\n\t{1}"), m_oid, sInterfaceName)); + // add to the string that contains all interface names + _numInterfaces ++; + OUStringBuffer buf(512); + buf.appendAscii("\t"); + buf.append( OUString::valueOf((sal_Int32)_numInterfaces)); + buf.appendAscii(". "); + buf.append(mapCliString(sInterfaceName)); + buf.appendAscii("\n"); + OUString _sNewInterface = buf.makeStringAndClear(); + rtl_uString * __pin * pp_sInterfaces = & _sInterfaces; + rtl_uString_newConcat( pp_sInterfaces, * pp_sInterfaces, + _sNewInterface.pData); +#endif + } + __finally { + System::Threading::Monitor::Exit(this); + } +} + + +// IRemotingTypeInfo +bool UnoInterfaceProxy::CanCastTo(System::Type* fromType, + System::Object*) +{ + if (fromType == __typeof(System::Object)) // trivial case + return true; + + System::Threading::Monitor::Enter(this); + try + { + if (0 != findInfo( fromType )) // proxy supports demanded interface + return true; + + //query an uno interface for the required type + + // we use the first interface in the list (m_listIfaces) to make + // the queryInterface call + UnoInterfaceInfo* info = + static_cast<UnoInterfaceInfo*>(m_listIfaces->get_Item(0)); + css::uno::TypeDescription membertd( + reinterpret_cast<typelib_InterfaceTypeDescription*>( + info->m_typeDesc)->ppAllMembers[0]); + System::Object *args[] = new System::Object*[1]; + + args[0] = fromType; + __box uno::Any * pAny; + System::Object* pException = NULL; + + pAny= static_cast<__box uno::Any *>( + m_bridge->call_uno( + info->m_unoI, + membertd.get(), + ((typelib_InterfaceMethodTypeDescription*) + membertd.get())->pReturnTypeRef, + 1, + ((typelib_InterfaceMethodTypeDescription*) + membertd.get())->pParams, + args, NULL, &pException) ); + + // handle regular exception from target + OSL_ENSURE( + 0 == pException, + OUStringToOString( + mapCliString( pException->ToString()), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + if (pAny->Type != __typeof (void)) // has value? + { + if (0 != findInfo( fromType )) + { + // proxy now supports demanded interface + 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) + ::System::Object * obj = pAny->Value; + OSL_ASSERT( srr::RemotingServices::IsTransparentProxy( obj ) ); + if (srr::RemotingServices::IsTransparentProxy( obj )) + { + UnoInterfaceProxy * proxy = + static_cast< UnoInterfaceProxy * >( + srr::RemotingServices::GetRealProxy( obj ) ); + OSL_ASSERT( 0 != proxy->findInfo( fromType ) ); + m_listAdditionalProxies->Add( proxy ); + m_nlistAdditionalProxies = m_listAdditionalProxies->Count; + OSL_ASSERT( 0 != findInfo( fromType ) ); + return true; + } + } + } + catch (BridgeRuntimeError& e) + { + (void) e; // avoid warning + OSL_ENSURE( + 0, OUStringToOString( + e.m_message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + catch (System::Exception* e) + { + System::String* msg= new System::String( + S"An unexpected CLI exception occurred in " + S"UnoInterfaceProxy::CanCastTo(). Original" + S"message: \n"); + msg= System::String::Concat(msg, e->get_Message()); + OSL_ENSURE( + 0, OUStringToOString( + mapCliString(msg), RTL_TEXTENCODING_UTF8 ).getStr() ); + } + catch (...) + { + OSL_ENSURE( + 0, "An unexpected native C++ exception occurred in " + "UnoInterfaceProxy::CanCastTo()" ); + } + __finally + { + System::Threading::Monitor::Exit(this); + } + return false; +} + +srrm::IMessage* UnoInterfaceProxy::invokeObject( + sc::IDictionary* props, + srrm::LogicalCallContext* context, + srrm::IMethodCallMessage* mcm) +{ + System::Object* retMethod = 0; + System::String* sMethod = static_cast<System::String*> + (props->get_Item(m_methodNameString)); + System::Object* args[] = static_cast<System::Object*[]>( + props->get_Item(m_ArgsString)); + if (m_Equals_String->Equals(sMethod)) + { + // Object.Equals + OSL_ASSERT(args->get_Length() == 1); + srrp::RealProxy* rProxy = srr::RemotingServices::GetRealProxy(args[0]); + bool bDone = false; + if (rProxy) + { + UnoInterfaceProxy* unoProxy = + dynamic_cast<UnoInterfaceProxy*>(rProxy); + if (unoProxy) + { + bool b = m_oid->Equals(unoProxy->getOid()); + retMethod = __box(b); + bDone = true; + } + } + if (bDone == false) + { + //no proxy or not our proxy, therefore Equals must be false + retMethod = __box(false); + } + } + else if (m_GetHashCode_String->Equals(sMethod)) + { + // Object.GetHashCode + int nHash = m_oid->GetHashCode(); + retMethod = __box(nHash); + } + else if (m_GetType_String->Equals(sMethod)) + { + // Object.GetType + retMethod = __typeof(System::Object); + } + else if (m_ToString_String->Equals(sMethod)) + { + // Object.ToString + st::StringBuilder* sb = new st::StringBuilder(256); +// sb->AppendFormat(S"Uno object proxy. Implemented interface: {0}" +// S". OID: {1}", m_type->ToString(), m_oid); + sb->AppendFormat(S"Uno object proxy. OID: {0}", m_oid); + retMethod = sb->ToString(); + } + else + { + //Either Object has new functions or a protected method was called + //which should not be possible + OSL_ASSERT(0); + } + srrm::IMessage* retVal= new srrm::ReturnMessage( + retMethod, new System::Object*[0], 0, context, mcm); + return retVal; +} + +UnoInterfaceInfo * UnoInterfaceProxy::findInfo( ::System::Type * type ) +{ + for (int i = 0; i < m_numUnoIfaces; i++) + { + UnoInterfaceInfo* tmpInfo = static_cast<UnoInterfaceInfo*>( + m_listIfaces->get_Item(i)); + if (type->IsAssignableFrom(tmpInfo->m_type)) + return tmpInfo; + } + for ( int i = 0; i < m_nlistAdditionalProxies; ++i ) + { + UnoInterfaceProxy * proxy = + static_cast< UnoInterfaceProxy * >( + m_listAdditionalProxies->get_Item( i ) ); + UnoInterfaceInfo * info = proxy->findInfo( type ); + if (0 != info) + return info; + } + return 0; +} + +srrm::IMessage* UnoInterfaceProxy::Invoke(srrm::IMessage* callmsg) +{ + try + { + sc::IDictionary* props= callmsg->Properties; + srrm::LogicalCallContext* context= + static_cast<srrm::LogicalCallContext*>( + props->get_Item(m_CallContextString)); + srrm::IMethodCallMessage* mcm= + static_cast<srrm::IMethodCallMessage*>(callmsg); + + //Find out which UNO interface is being called + System::String* sTypeName = static_cast<System::String*>( + props->get_Item(m_typeNameString)); + sTypeName = sTypeName->Substring(0, sTypeName->IndexOf(',')); + + // Special Handling for System.Object methods + if(sTypeName->IndexOf(m_system_Object_String) != -1) + { + return invokeObject(props, context, mcm); + } + + System::Type* typeBeingCalled = loadCliType(sTypeName); + UnoInterfaceInfo* info = findInfo( typeBeingCalled ); + OSL_ASSERT( 0 != info ); + + // ToDo do without string conversion, a OUString is not needed here + // get the type description of the call + OUString usMethodName(mapCliString(static_cast<System::String*>( + props->get_Item(m_methodNameString)))); + typelib_TypeDescriptionReference ** ppAllMembers = + info->m_typeDesc->ppAllMembers; + sal_Int32 numberMembers = info->m_typeDesc->nAllMembers; + for ( sal_Int32 nPos = numberMembers; nPos--; ) + { + typelib_TypeDescriptionReference * member_type = ppAllMembers[nPos]; + + // check usMethodName against fully qualified usTypeName + // of member_type; usTypeName is of the form + // <name> "::" <usMethodName> *(":@" <idx> "," <idx> ":" <name>) + OUString const & usTypeName = + OUString::unacquired( & member_type->pTypeName ); + +#if OSL_DEBUG_LEVEL >= 2 + System::String * pTypeName; + pTypeName = mapUnoString(usTypeName.pData); +#endif + sal_Int32 offset = usTypeName.indexOf( ':' ) + 2; + OSL_ASSERT( + offset >= 2 && offset < usTypeName.getLength() + && usTypeName[offset - 1] == ':' ); + sal_Int32 remainder = usTypeName.getLength() - offset; + + if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass) + { + if ((usMethodName.getLength() == remainder + || (usMethodName.getLength() < remainder + && usTypeName[offset + usMethodName.getLength()] == ':')) + && usTypeName.match(usMethodName, offset)) + { + TypeDescr member_td( member_type ); + typelib_InterfaceMethodTypeDescription * method_td = + (typelib_InterfaceMethodTypeDescription *) + member_td.get(); + + System::Object* args[] = static_cast<System::Object*[]>( + props->get_Item(m_ArgsString)); + System::Type* argTypes[] = static_cast<System::Type*[]>( + props->get_Item(m_methodSignatureString)); + System::Object* pExc = NULL; + System::Object * cli_ret = m_bridge->call_uno( + info->m_unoI, member_td.get(), + method_td->pReturnTypeRef, method_td->nParams, + method_td->pParams, args, argTypes, &pExc); + return constructReturnMessage(cli_ret, args, method_td, + callmsg, pExc); + break; + } + } + else + { + OSL_ASSERT( typelib_TypeClass_INTERFACE_ATTRIBUTE == + member_type->eTypeClass ); + if (usMethodName.getLength() > 4 + && (usMethodName.getLength() - 4 == remainder + || (usMethodName.getLength() - 4 < remainder + && usTypeName[ + offset + (usMethodName.getLength() - 4)] == ':')) + && usMethodName[1] == 'e' && usMethodName[2] == 't' + && rtl_ustr_compare_WithLength( + usTypeName.getStr() + offset, + usMethodName.getLength() - 4, + usMethodName.getStr() + 4, + usMethodName.getLength() - 4) == 0) + { + if ('g' == usMethodName[0]) + { + TypeDescr member_td( member_type ); + typelib_InterfaceAttributeTypeDescription * attribute_td = + (typelib_InterfaceAttributeTypeDescription*) + member_td.get(); + + System::Object* pExc = NULL; + System::Object* cli_ret= m_bridge->call_uno( + info->m_unoI, member_td.get(), + attribute_td->pAttributeTypeRef, + 0, 0, + NULL, NULL, &pExc); + return constructReturnMessage(cli_ret, NULL, NULL, + callmsg, pExc); + } + else if ('s' == usMethodName[0]) + { + TypeDescr member_td( member_type ); + typelib_InterfaceAttributeTypeDescription * attribute_td = + (typelib_InterfaceAttributeTypeDescription *) + member_td.get(); + if (! attribute_td->bReadOnly) + { + typelib_MethodParameter param; + param.pTypeRef = attribute_td->pAttributeTypeRef; + param.bIn = sal_True; + param.bOut = sal_False; + + System::Object* args[] = + static_cast<System::Object*[]>( + props->get_Item(m_ArgsString)); + System::Object* pExc = NULL; + m_bridge->call_uno( + info->m_unoI, member_td.get(), + ::getCppuVoidType().getTypeLibType(), + 1, ¶m, args, NULL, &pExc); + return constructReturnMessage(NULL, NULL, NULL, + callmsg, pExc); + } + else + { + return constructReturnMessage(NULL, NULL, NULL, + callmsg, NULL); + } + } + break; + } + } + } + // ToDo check if the message of the exception is not crippled + // the thing that should not be... no method info found! + OUStringBuffer buf( 64 ); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( + "[cli_uno bridge]calling undeclared function on " + "interface ") ); + buf.append( *reinterpret_cast< OUString const * >( + & ((typelib_TypeDescription *)info->m_typeDesc)->pTypeName)); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") ); + buf.append( usMethodName ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (BridgeRuntimeError & err) + { + srrm::IMethodCallMessage* mcm = + static_cast<srrm::IMethodCallMessage*>(callmsg); + return new srrm::ReturnMessage(new ucss::uno::RuntimeException( + mapUnoString(err.m_message.pData), NULL), mcm); + } + catch (System::Exception* e) + { + st::StringBuilder * sb = new st::StringBuilder(512); + sb->Append(new System::String( + S"An unexpected CLI exception occurred in " + S"UnoInterfaceProxy::Invoke. Original" + S"message: \n")); + sb->Append(e->get_Message()); + sb->Append((__wchar_t) '\n'); + sb->Append(e->get_StackTrace()); + srrm::IMethodCallMessage* mcm = + static_cast<srrm::IMethodCallMessage*>(callmsg); + return new srrm::ReturnMessage(new ucss::uno::RuntimeException( + sb->ToString(), NULL), mcm); + } + catch (...) + { + System::String* msg = new System::String( + S"An unexpected native C++ exception occurred in " + S"UnoInterfaceProxy::Invoke."); + srrm::IMethodCallMessage* mcm = + static_cast<srrm::IMethodCallMessage*>(callmsg); + return new srrm::ReturnMessage(new ucss::uno::RuntimeException( + msg, NULL), mcm); + } + return NULL; +} +/** If the argument args is NULL then this function is called for an attribute + method (either setXXX or getXXX). + For attributes the argument mtd is also NULL. +*/ +srrm::IMessage* UnoInterfaceProxy::constructReturnMessage( + System::Object* cliReturn, + System::Object* args[], + typelib_InterfaceMethodTypeDescription* mtd, + srrm::IMessage* msg, System::Object* exc) +{ + srrm::IMessage * retVal= NULL; + srrm::IMethodCallMessage* mcm = static_cast<srrm::IMethodCallMessage*>(msg); + if (exc) + { + retVal = new srrm::ReturnMessage( + dynamic_cast<System::Exception*>(exc), mcm); + } + else + { + sc::IDictionary* props= msg->get_Properties(); + srrm::LogicalCallContext* context= + static_cast<srrm::LogicalCallContext*>( + props->get_Item(m_CallContextString)); + if (args != NULL) + { + // Method + //build the array of out parameters, allocate max length + System::Object* arOut[]= new System::Object*[mtd->nParams]; + int nOut = 0; + for (int i= 0; i < mtd->nParams; i++) + { + if (mtd->pParams[i].bOut) + { + arOut[i]= args[i]; + nOut++; + } + } + retVal= new srrm::ReturnMessage(cliReturn, arOut, nOut, + context, mcm); + } + else + { + // Attribute (getXXX) + retVal= new srrm::ReturnMessage(cliReturn, NULL, 0, + context, mcm); + } + } + return retVal; +} + +//################################################################################ +CliProxy::CliProxy(Bridge const* bridge, System::Object* cliI, + typelib_TypeDescription const* td, + const rtl::OUString& usOid): + m_ref(1), + m_bridge(bridge), + m_cliI(cliI), + m_unoType(const_cast<typelib_TypeDescription*>(td)), + m_usOid(usOid), + m_oid(mapUnoString(usOid.pData)), + m_nInheritedInterfaces(0) +{ + m_bridge->acquire(); + uno_Interface::acquire = cli_proxy_acquire; + uno_Interface::release = cli_proxy_release; + uno_Interface::pDispatcher = cli_proxy_dispatch; + + m_unoType.makeComplete(); + m_type= mapUnoType(m_unoType.get()); + + makeMethodInfos(); +#if OSL_DEBUG_LEVEL >= 2 + sd::Trace::WriteLine(System::String::Format( + new System::String(S"cli uno bridge: Creating proxy for cli object, " + S"id:\n\t{0}\n\t{1}"), m_oid, m_type)); +#endif + +} + +void CliProxy::makeMethodInfos() +{ +#if OSL_DEBUG_LEVEL >= 2 + System::Object* cliI; + System::Type* type; + cliI = m_cliI; + type = m_type; +#endif + + if (m_type->get_IsInterface() == false) + return; + sr::MethodInfo* arThisMethods[] = m_type->GetMethods(); + //get the inherited interfaces + System::Type* arInheritedIfaces[] = m_type->GetInterfaces(); + m_nInheritedInterfaces = arInheritedIfaces->get_Length(); + //array containing the number of methods for the interface and its + //inherited interfaces + m_arInterfaceMethodCount = new int __gc [m_nInheritedInterfaces + 1]; + //determine the number of all interface methods, including the inherited + //interfaces + int numMethods = arThisMethods->get_Length(); + for (int i= 0; i < m_nInheritedInterfaces; i++) + { + numMethods += arInheritedIfaces[i]->GetMethods()->get_Length(); + } + //array containing MethodInfos of the cli object + m_arMethodInfos = new sr::MethodInfo*[numMethods]; + //array containing MethodInfos of the interface + m_arInterfaceMethodInfos = new sr::MethodInfo*[numMethods]; + //array containing the mapping of Uno interface pos to pos in + //m_arMethodInfos + m_arUnoPosToCliPos = new System::Int32[numMethods]; + // initialize with -1 + for (int i = 0; i < numMethods; i++) + m_arUnoPosToCliPos[i] = -1; + +#if OSL_DEBUG_LEVEL >= 2 + sr::MethodInfo* arMethodInfosDbg[]; + sr::MethodInfo* arInterfaceMethodInfosDbg[]; + System::Int32 arInterfaceMethodCountDbg[]; + arMethodInfosDbg = m_arMethodInfos; + arInterfaceMethodInfosDbg = m_arInterfaceMethodInfos; + arInterfaceMethodCountDbg = m_arInterfaceMethodCount; +#endif + + + //fill m_arMethodInfos with the mappings + // !!! InterfaceMapping.TargetMethods should be MethodInfo*[] according + // to documentation + // but it is Type*[] instead. Bug in the framework? + System::Type* objType = m_cliI->GetType(); + try + { + int index = 0; + // now get the methods from the inherited interface + //arInheritedIfaces[0] is the direct base interface + //arInheritedIfaces[n] is the furthest inherited interface + //Start with the base interface + int nArLength = arInheritedIfaces->get_Length(); + for (;nArLength > 0; nArLength--) + { + sr::InterfaceMapping mapInherited = objType->GetInterfaceMap( + arInheritedIfaces[nArLength - 1]); + int numMethods = mapInherited.TargetMethods->get_Length(); + m_arInterfaceMethodCount[nArLength - 1] = numMethods; + for (int i = 0; i < numMethods; i++, index++) + { + m_arMethodInfos[index] = __try_cast<sr::MethodInfo*>( + mapInherited.TargetMethods[i]); + + m_arInterfaceMethodInfos[index] = __try_cast<sr::MethodInfo*>( + mapInherited.InterfaceMethods[i]); + } + } + //At last come the methods of the furthest derived interface + sr::InterfaceMapping map = objType->GetInterfaceMap(m_type); + nArLength = map.TargetMethods->get_Length(); + m_arInterfaceMethodCount[m_nInheritedInterfaces] = nArLength; + for (int i = 0; i < nArLength; i++,index++) + { + m_arMethodInfos[index]= __try_cast<sr::MethodInfo*>( + map.TargetMethods[i]); + m_arInterfaceMethodInfos[index]= __try_cast<sr::MethodInfo*>( + map.InterfaceMethods[i]); + } + } + catch (System::InvalidCastException* ) + { + OUStringBuffer buf( 128 ); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( + "[cli_uno bridge] preparing proxy for " + "cli interface: ") ); + buf.append(mapCliString(m_type->ToString() )); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" \nfailed!")); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } +} + +sr::MethodInfo* CliProxy::getMethodInfo(int nUnoFunctionPos, + const rtl::OUString& usMethodName, MethodKind methodKind) +{ + sr::MethodInfo* ret = NULL; +#if OSL_DEBUG_LEVEL >= 2 + System::String* sMethodNameDbg; + sr::MethodInfo* arMethodInfosDbg[]; + sr::MethodInfo* arInterfaceMethodInfosDbg[]; + System::Int32 arInterfaceMethodCountDbg[]; + System::Int32 arUnoPosToCliPosDbg[]; + sMethodNameDbg = mapUnoString(usMethodName.pData); + arMethodInfosDbg = m_arMethodInfos; + arInterfaceMethodInfosDbg = m_arInterfaceMethodInfos; + arInterfaceMethodCountDbg = m_arInterfaceMethodCount; + arUnoPosToCliPosDbg = m_arUnoPosToCliPos; +#endif + //deduct 3 for XInterface methods + nUnoFunctionPos -= 3; + System::Threading::Monitor::Enter(m_arUnoPosToCliPos); + try + { + int cliPos = m_arUnoPosToCliPos[nUnoFunctionPos]; + if (cliPos != -1) + return m_arMethodInfos[cliPos]; + + //create the method function name + System::String* sMethodName = mapUnoString(usMethodName.pData); + switch (methodKind) + { + case MK_METHOD: + break; + case MK_SET: + sMethodName = System::String::Concat( + const_cast<System::String*>(Constants::sAttributeSet), + sMethodName); + break; + case MK_GET: + sMethodName = System::String::Concat( + const_cast<System::String*>(Constants::sAttributeGet), + sMethodName); + break; + default: + OSL_ASSERT(0); + } + //Find the cli interface method that corresponds to the Uno method +// System::String* sMethodName= mapUnoString(usMethodName.pData); + 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 nUnoFunctionPos should lead to the correct method. However, + //the documentation does not say that this ordering is given. + if (sMethodName->Equals(m_arInterfaceMethodInfos[nUnoFunctionPos]->Name)) + indexCliMethod = nUnoFunctionPos; + else + { + int cMethods = m_arInterfaceMethodInfos->get_Length(); + for (int i = 0; i < cMethods; i++) + { + System::String* cliMethod = m_arInterfaceMethodInfos[i]->Name; + if (cliMethod->Equals(sMethodName)) + { + indexCliMethod = i; + break; + } + } + } + if (indexCliMethod == -1) + { + OUStringBuffer buf(256); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( + "[cli_uno bridge] CliProxy::getMethodInfo():" + "cli object does not implement interface method: ")); + buf.append(usMethodName); + throw BridgeRuntimeError(buf.makeStringAndClear()); + return 0; + } + m_arUnoPosToCliPos[nUnoFunctionPos] = indexCliMethod; + ret = m_arMethodInfos[indexCliMethod]; + } + __finally + { + System::Threading::Monitor::Exit(m_arUnoPosToCliPos); + } + + return ret; +} + +CliProxy::~CliProxy() +{ +#if OSL_DEBUG_LEVEL >= 2 + sd::Trace::WriteLine(System::String::Format( + new System::String( + S"cli uno bridge: Destroying proxy for cli object, " + S"id:\n\t{0}\n\t{1}\n"), + m_oid, m_type)); +#endif + CliEnvHolder::g_cli_env->revokeInterface(m_oid, mapUnoType(m_unoType.get())); + m_bridge->release(); +} + +uno_Interface* CliProxy::create(Bridge const * bridge, + System::Object* cliI, + typelib_TypeDescription const* pTD, + const rtl::OUString& ousOid) +{ + uno_Interface* proxy= static_cast<uno_Interface*>( + new CliProxy(bridge, cliI, pTD, ousOid)); + + //register proxy with target environment (uno) + (*bridge->m_uno_env->registerProxyInterface)( + bridge->m_uno_env, + reinterpret_cast<void**>(&proxy), + cli_proxy_free, + ousOid.pData, (typelib_InterfaceTypeDescription*) pTD); + //register original interface + CliEnvHolder::g_cli_env->registerInterface(cliI, mapUnoString(ousOid.pData), + mapUnoType((pTD))); + + return proxy; +} + + + +void SAL_CALL CliProxy::uno_DispatchMethod( + struct _uno_Interface *, + const struct _typelib_TypeDescription *, + void *, + void **, + uno_Any ** ) +{ +} +inline void CliProxy::acquire() const +{ + if (1 == osl_incrementInterlockedCount( &m_ref )) + { + // rebirth of proxy zombie + void * that = const_cast< CliProxy * >( this ); + // register at uno env + (*m_bridge->m_uno_env->registerProxyInterface)( + m_bridge->m_uno_env, &that, + cli_proxy_free, m_usOid.pData, + (typelib_InterfaceTypeDescription *)m_unoType.get() ); +#if OSL_DEBUG_LEVEL >= 2 + OSL_ASSERT( this == (void const * const)that ); +#endif + } +} +//--------------------------------------------------------------------------- +inline void CliProxy::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 cli_proxy_free. cli_proxy_free will + //delete the proxy. The environment does not acquire a registered + //proxy. + (*m_bridge->m_uno_env->revokeInterface)( + m_bridge->m_uno_env, const_cast< CliProxy * >( this ) ); + } +} +} + + + + +extern "C" +void SAL_CALL cli_proxy_free( uno_ExtEnvironment *, void * proxy ) + SAL_THROW_EXTERN_C() +{ + cli_uno::CliProxy * cliProxy = reinterpret_cast< + cli_uno::CliProxy * >( proxy ); + + delete cliProxy; +} + +extern "C" +void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C() +{ + CliProxy const * cliProxy = static_cast< CliProxy const * >( pUnoI ); + cliProxy->acquire(); +} +//----------------------------------------------------------------------------- +extern "C" +void SAL_CALL cli_proxy_release( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C() +{ + CliProxy * cliProxy = static_cast< CliProxy * >( pUnoI ); + cliProxy->release(); +} + +//------------------------------------------------------------------------------ +extern "C" + +void SAL_CALL cli_proxy_dispatch( + uno_Interface * pUnoI, typelib_TypeDescription const * member_td, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) + SAL_THROW_EXTERN_C() +{ + CliProxy * proxy = static_cast< CliProxy* >( pUnoI ); + try + { + Bridge const* bridge = proxy->m_bridge; + + switch (member_td->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + + sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *) + member_td)->nPosition; + typelib_InterfaceTypeDescription * iface_td = + (typelib_InterfaceTypeDescription *)proxy->m_unoType.get(); + OSL_ENSURE( + member_pos < iface_td->nAllMembers, + "### member pos out of range!" ); + sal_Int32 function_pos = + iface_td->pMapMemberIndexToFunctionIndex[ member_pos ]; + OSL_ENSURE( + function_pos < iface_td->nMapFunctionIndexToMemberIndex, + "### illegal function index!" ); + + if (uno_ret) // is getter method + { + OUString const& usAttrName= *(rtl_uString**)& + ((typelib_InterfaceMemberTypeDescription*) member_td) + ->pMemberName; + sr::MethodInfo* info = proxy->getMethodInfo(function_pos, + usAttrName, CliProxy::MK_GET); + bridge->call_cli( + proxy->m_cliI, + info, + ((typelib_InterfaceAttributeTypeDescription *)member_td) + ->pAttributeTypeRef, + 0, 0, // no params + uno_ret, 0, uno_exc ); + } + else // is setter method + { + OUString const& usAttrName= *(rtl_uString**) & + ((typelib_InterfaceMemberTypeDescription*) member_td) + ->pMemberName; + sr::MethodInfo* info = proxy->getMethodInfo(function_pos + 1, + usAttrName, CliProxy::MK_SET); + typelib_MethodParameter param; + param.pTypeRef = + ((typelib_InterfaceAttributeTypeDescription *)member_td) + ->pAttributeTypeRef; + param.bIn = sal_True; + param.bOut = sal_False; + + bridge->call_cli( + proxy->m_cliI, + // set follows get method + info, + 0 /* indicates void return */, ¶m, 1, + 0, uno_args, uno_exc ); + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *) + member_td)->nPosition; + typelib_InterfaceTypeDescription * iface_td = + (typelib_InterfaceTypeDescription *)proxy->m_unoType.get(); + OSL_ENSURE( + member_pos < iface_td->nAllMembers, + "### member pos out of range!" ); + sal_Int32 function_pos = + iface_td->pMapMemberIndexToFunctionIndex[ member_pos ]; + OSL_ENSURE( + function_pos < iface_td->nMapFunctionIndexToMemberIndex, + "### illegal function index!" ); + + switch (function_pos) + { + case 0: // queryInterface() + { + TypeDescr demanded_td( + *reinterpret_cast<typelib_TypeDescriptionReference **>( + uno_args[0])); + if (typelib_TypeClass_INTERFACE + != demanded_td.get()->eTypeClass) + { + throw BridgeRuntimeError( + OUSTR("queryInterface() call demands an INTERFACE type!")); + } + + uno_Interface * pInterface = 0; + (*bridge->m_uno_env->getRegisteredInterface)( + bridge->m_uno_env, + (void **)&pInterface, proxy->m_usOid.pData, + (typelib_InterfaceTypeDescription *)demanded_td.get() ); + + if (0 == pInterface) + { + System::Type* mgdDemandedType = + mapUnoType(demanded_td.get()); + if (mgdDemandedType->IsInstanceOfType( proxy->m_cliI )) + { +#if OSL_DEBUG_LEVEL > 0 + OUString usOid( + mapCliString( + CliEnvHolder::g_cli_env->getObjectIdentifier( + proxy->m_cliI ))); + OSL_ENSURE(usOid.equals( proxy->m_usOid ), + "### different oids!"); +#endif + uno_Interface* pUnoI = bridge->map_cli2uno( + proxy->m_cliI, demanded_td.get() ); + uno_any_construct( + (uno_Any *)uno_ret, &pUnoI, demanded_td.get(), 0 ); + (*pUnoI->release)( pUnoI ); + } + else // object does not support demanded interface + { + uno_any_construct( (uno_Any *)uno_ret, 0, 0, 0 ); + } + // no excetpion occured + *uno_exc = 0; + } + else + { + uno_any_construct( + reinterpret_cast< uno_Any * >( uno_ret ), + &pInterface, demanded_td.get(), 0 ); + (*pInterface->release)( pInterface ); + *uno_exc = 0; + } + break; + } + case 1: // acquire this proxy + cli_proxy_acquire(proxy); + *uno_exc = 0; + break; + case 2: // release this proxy + cli_proxy_release(proxy); + *uno_exc = 0; + break; + default: // arbitrary method call + { + typelib_InterfaceMethodTypeDescription * method_td = + (typelib_InterfaceMethodTypeDescription *)member_td; + OUString const& usMethodName= *(rtl_uString**) & + ((typelib_InterfaceMemberTypeDescription*) member_td) + ->pMemberName; + + sr::MethodInfo* info = proxy->getMethodInfo(function_pos, + usMethodName, CliProxy::MK_METHOD); + bridge->call_cli( + proxy->m_cliI, + info, + method_td->pReturnTypeRef, method_td->pParams, + method_td->nParams, + uno_ret, uno_args, uno_exc); + return; + } + } + break; + } + default: + { + throw BridgeRuntimeError( + OUSTR("illegal member type description!") ); + } + } + } + catch (BridgeRuntimeError & err) + { + // binary identical struct + ::com::sun::star::uno::RuntimeException exc( + OUSTR("[cli_uno bridge error] ") + err.m_message, + ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XInterface >() ); + ::com::sun::star::uno::Type const & exc_type = ::getCppuType( & exc); + uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0); +#if OSL_DEBUG_LEVEL >= 1 + OString cstr_msg(OUStringToOString(exc.Message, + RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE(0, cstr_msg.getStr()); +#endif + } +} + + + + + diff --git a/cli_ure/source/uno_bridge/cli_proxy.h b/cli_ure/source/uno_bridge/cli_proxy.h new file mode 100644 index 000000000000..2441bebf1365 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_proxy.h @@ -0,0 +1,299 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#ifndef INCLUDED_CLI_PROXY_H +#define INCLUDED_CLI_PROXY_H + +#pragma warning(push, 1) +#include "uno/environment.hxx" +#pragma warning(pop) +#include "uno/mapping.hxx" +#include "uno/dispatcher.h" +#include "cli_bridge.h" +#include "cli_environment.h" + +#using <mscorlib.dll> +#using <cli_ure.dll> + +namespace srrp = System::Runtime::Remoting::Proxies; +namespace srrm = System::Runtime::Remoting::Messaging; +namespace srr = System::Runtime::Remoting; +namespace sr = System::Reflection; +namespace sc = System::Collections; +using namespace uno; + +namespace cli_uno +{ + +public __gc class UnoInterfaceInfo +{ +public: + UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI, + typelib_InterfaceTypeDescription* td); + ~UnoInterfaceInfo(); + uno_Interface * m_unoI; // wrapped interface + System::Type * m_type; + typelib_InterfaceTypeDescription* m_typeDesc; + + Bridge const* m_bridge; +}; + +public __gc class UnoInterfaceProxy: public srrp::RealProxy, + public srr::IRemotingTypeInfo +{ + /** used for IRemotingTypeInfo.TypeName + */ + System::String* m_sTypeName; + /** 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! + */ + sc::ArrayList* m_listIfaces; + /** The number of UNO interfaces this proxy represents. It corresponds + to the the number of elements in m_listIfaces. + */ + int m_numUnoIfaces; + /** The list is filled with additional UnoInterfaceProxy object due + to aggregation via bridges. Though the latter is strongly + discouraged, this has to be supported. + */ + sc::ArrayList* m_listAdditionalProxies; + int m_nlistAdditionalProxies; + + UnoInterfaceInfo * findInfo( ::System::Type * type ); + + Bridge const* m_bridge; + System::String* m_oid; + +#if OSL_DEBUG_LEVEL >= 2 + /** The string contains all names of UNO interfaces which are + represented by this proxy. It is used to print out the interfaces + when this proxy dies. In the destructor it is not allowed to + access m_listIfaces or any other managed object. + */ + rtl_uString * _sInterfaces; +// /** Count of interfaces. Used in conjunction with _sInterfaces. +// */ + int _numInterfaces; +#endif + +public: + + /** Creates a proxy and registers it on the dot NET side. + */ + static System::Object* create(Bridge * bridge, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription* pTd, + const rtl::OUString& oid); + + /** RealProxy::Invoke */ + srrm::IMessage* Invoke(srrm::IMessage* msg); + + /** Must be called from within a synchronized section. + Add only the interface if it is not already contained. + This method is called from the constructor and as a result + of IRemotingTypeInfo::CanCastTo + */ + void addUnoInterface(uno_Interface* pUnoI, + typelib_InterfaceTypeDescription* pTd); + ~UnoInterfaceProxy(); + + /** + */ + inline System::String * getOid() + { return m_oid; } + + //IRemotingTypeInfo ---------------------------------------------- + bool CanCastTo(System::Type* fromType, System::Object* o); + + __property System::String* get_TypeName() + { + return m_sTypeName; + } + __property void set_TypeName(System::String* name) + { + m_sTypeName = name; + } + + +private: + UnoInterfaceProxy( + Bridge * bridge, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription* pTD, + const rtl::OUString& oid ); + + static srrm::IMessage* constructReturnMessage(System::Object* retVal, + System::Object* outArgs[], + typelib_InterfaceMethodTypeDescription* mtd, + srrm::IMessage* msg, System::Object* exc); + + static System::String* m_methodNameString = + new System::String("__MethodName"); + static System::String* m_typeNameString = new System::String("__TypeName"); + static System::String* m_ArgsString = new System::String("__Args"); + static System::String* m_CallContextString = + new System::String("__CallContext"); + static System::String* m_system_Object_String = + new System::String("System.Object"); + static System::String* m_methodSignatureString = + new System::String("__MethodSignature"); + static System::String* m_Equals_String = new System::String("Equals"); + static System::String* m_GetHashCode_String = + new System::String("GetHashCode"); + static System::String* m_GetType_String = new System::String("GetType"); + static System::String* m_ToString_String = new System::String("ToString"); + +protected: + srrm::IMessage* invokeObject(sc::IDictionary* properties, + srrm::LogicalCallContext* context, + srrm::IMethodCallMessage* mcm); +}; + + +//Cannot make this __gc because a managed type cannot derive from unmanaged type +struct CliProxy: public uno_Interface +{ + mutable oslInterlockedCount m_ref; + const Bridge* m_bridge; + const gcroot<System::Object*> m_cliI; + gcroot<System::Type*> m_type; + const com::sun::star::uno::TypeDescription m_unoType; + const gcroot<System::String*> m_oid; + const rtl::OUString m_usOid; + + enum MethodKind {MK_METHOD = 0, MK_SET, MK_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. + */ + gcroot<sr::MethodInfo*[]> m_arMethodInfos; + + /** 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. + */ + gcroot<sr::MethodInfo*[]> m_arInterfaceMethodInfos; + + /** 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. + + */ + gcroot<System::Int32[]> m_arUnoPosToCliPos; + + /** Count of inherited interfaces of the cli interface. + */ + int m_nInheritedInterfaces; + /** Contains the number of methods of each interface. + */ + gcroot<System::Int32[]> m_arInterfaceMethodCount; + + CliProxy( Bridge const* bridge, System::Object* cliI, + typelib_TypeDescription const* pTD, + const rtl::OUString& usOid); + ~CliProxy(); + + static uno_Interface* create(Bridge const * bridge, + System::Object* cliI, + typelib_TypeDescription const * TD, + rtl::OUString const & usOid ); + + /** 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(); + + /**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. + */ + sr::MethodInfo* getMethodInfo(int nUnoFunctionPos, + const rtl::OUString & usMethodName, + MethodKind mk); + + void SAL_CALL uno_DispatchMethod( + struct _uno_Interface * pUnoI, + const struct _typelib_TypeDescription * pMemberType, + void * pReturn, + void * pArgs[], + uno_Any ** ppException ); + + inline void acquire() const; + inline void release() const; +}; +} +#endif diff --git a/cli_ure/source/uno_bridge/cli_uno.cxx b/cli_ure/source/uno_bridge/cli_uno.cxx new file mode 100644 index 000000000000..34fdbe0c66ef --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_uno.cxx @@ -0,0 +1,290 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" + +#include <sal/alloca.h> +#include "rtl/ustrbuf.hxx" +#include "cli_base.h" +#include "cli_bridge.h" + +namespace sr=System::Reflection; +namespace css=com::sun::star; +using namespace rtl; + +namespace cli_uno +{ + +union largest +{ + sal_Int64 n; + double d; + void * p; + uno_Any a; +}; + +System::Object* Bridge::call_uno(uno_Interface * pUnoI, + typelib_TypeDescription* member_td, + typelib_TypeDescriptionReference * return_type, + sal_Int32 nParams, typelib_MethodParameter const * pParams, + System::Object * args[], System::Type* argTypes[], + System::Object** ppExc) const +{ + // return mem + sal_Int32 return_size = sizeof (largest); + if ((0 != return_type) && + (typelib_TypeClass_STRUCT == return_type->eTypeClass || + typelib_TypeClass_EXCEPTION == return_type->eTypeClass)) + { + TypeDescr return_td( return_type ); + if (return_td.get()->nSize > sizeof (largest)) + return_size = return_td.get()->nSize; + } + //Prepare memory that contains all converted arguments and return valuse + //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 union largest, such as some structures, then the pointer + // points to an extra block of memory. The same goes for a big return value. + + char * mem = (char *)alloca( + (nParams * sizeof (void *)) + return_size + (nParams * sizeof (largest)) ); + //array of pointers to args + void ** uno_args = (void **)mem; + //If an attribute is set, then uno_ret must be null, e.g void setAttribute(int ) + void * uno_ret= NULL; + if ( !(member_td->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE && nParams == 1)) + uno_ret = (mem + (nParams * sizeof (void *))); + largest * uno_args_mem = (largest *)(mem + (nParams * sizeof (void *)) + return_size); + + OSL_ASSERT( (0 == nParams) || (nParams == args->get_Length()) ); + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & param = pParams[ nPos ]; + typelib_TypeDescriptionReference * type = param.pTypeRef; + + uno_args[ nPos ] = &uno_args_mem[ nPos ]; + if (typelib_TypeClass_STRUCT == type->eTypeClass || + typelib_TypeClass_EXCEPTION == type->eTypeClass) + { + TypeDescr td( type ); + if (td.get()->nSize > sizeof (largest)) + uno_args[ nPos ] = alloca( td.get()->nSize ); + } + + if (param.bIn) + { + try + { + // in, in/out params + map_to_uno( + uno_args[ nPos ],args[nPos] , type, false /* no assign */); + } + catch (...) + { + // cleanup uno in args + for (sal_Int32 n = 0; n < nPos; ++n) + { + typelib_MethodParameter const & param = pParams[n]; + if (param.bIn) + { + uno_type_destructData(uno_args[n], param.pTypeRef, 0); + } + } + throw; + } + } + } + uno_Any uno_exc_holder; + uno_Any * uno_exc = &uno_exc_holder; + // call binary uno + + (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc ); + + if (0 == uno_exc) + { + // convert out args; destruct uno args + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & param = pParams[ nPos ]; + typelib_TypeDescriptionReference * type = param.pTypeRef; + if (param.bOut) + { + try + { + map_to_cli( + &args[nPos], uno_args[nPos], param.pTypeRef, + argTypes != NULL ? argTypes[nPos] : NULL, false ); + } + catch (...) + { + // cleanup further uno args + for ( sal_Int32 n = nPos; n < nParams; ++n ) + { + uno_type_destructData( uno_args[n], pParams[n].pTypeRef, 0 ); + } + // cleanup uno return value + uno_type_destructData( uno_ret, return_type, 0 ); + throw; + } + } + //cleanup args + if (typelib_TypeClass_DOUBLE < type->eTypeClass && + typelib_TypeClass_ENUM != type->eTypeClass) // opt + { + uno_type_destructData(uno_args[nPos], type, 0); + } + } + + if ((0 != return_type) && + (typelib_TypeClass_VOID != return_type->eTypeClass)) + { + // convert uno return value + try + { + System::Object* cli_ret; + map_to_cli( + &cli_ret, uno_ret, return_type, 0, false); + uno_type_destructData(uno_ret, return_type, 0); + return cli_ret; + } + catch (...) + { + uno_type_destructData(uno_ret, return_type, 0); + throw; + } + } + return 0; // void return + } + else // exception occured + { + // destruct uno in args + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & param = pParams[ nPos ]; + if (param.bIn) + { + uno_type_destructData( uno_args[ nPos ], param.pTypeRef, 0 ); + } + } + map_to_cli(ppExc, uno_exc_holder.pData, + uno_exc_holder.pType, NULL, false); + return 0; + } +} + +void Bridge::call_cli( + System::Object* cliI, + sr::MethodInfo* method, + typelib_TypeDescriptionReference * return_type, + typelib_MethodParameter * params, int nParams, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const +{ + System::Object *args[]= new System::Object*[nParams]; + for (int nPos= 0; nPos < nParams; nPos++) + { + typelib_MethodParameter const & param= params[nPos]; + if (param.bIn) + { + map_to_cli( &args[nPos], + uno_args[nPos], param.pTypeRef, 0, false); + } + } + System::Object* retInvoke= NULL; + try + { + retInvoke= method->Invoke(cliI, args); + } + catch (sr::TargetInvocationException* e) + { + System::Exception* exc= e->get_InnerException(); + css::uno::TypeDescription td(mapCliType(exc->GetType())); + // memory for exception + std::auto_ptr< rtl_mem > memExc(rtl_mem::allocate(td.get()->nSize)); + map_to_uno(memExc.get(), exc, td.get()->pWeakRef, false); + (*uno_exc)->pType= td.get()->pWeakRef; + (*uno_exc)->pData= memExc.release(); + return; + } + catch (System::Exception* e) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "Unexspected exception during invocation of cli object. " + "Original message is: \n") ); + buf.append(mapCliString(e->get_Message())); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + + //convert out, in/out params + for (int nPos = 0; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & param = params[ nPos ]; + + if (param.bOut) + { + try + { + map_to_uno( + uno_args[ nPos ], args[ nPos ], param.pTypeRef, + sal_True == param.bIn /* assign if inout */); + // out array + } + catch (...) + { + // cleanup uno pure out + for ( sal_Int32 n = 0; n < nPos; ++n ) + { + typelib_MethodParameter const & param = params[ n ]; + if (! param.bIn) + uno_type_destructData( uno_args[ n ], param.pTypeRef, 0 ); + } + throw; + } + } + } + // return value + if (0 != return_type) + { + map_to_uno( + uno_ret, retInvoke, return_type, false /* no assign */); + } + // no exception occured + *uno_exc = 0; +} + + + + +} diff --git a/cli_ure/source/uno_bridge/makefile.mk b/cli_ure/source/uno_bridge/makefile.mk new file mode 100644 index 000000000000..b7682aed4b1b --- /dev/null +++ b/cli_ure/source/uno_bridge/makefile.mk @@ -0,0 +1,95 @@ +#************************************************************************* +# +# 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 = cli_ure + +TARGET = cli_uno +NO_BSYMBOLIC = TRUE +ENABLE_EXCEPTIONS = TRUE +USE_DEFFILE = TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + + +.IF "$(COM)" == "MSC" +# When compiling for CLR, disable "warning C4339: use of undefined type detected +# in CLR meta-data - use of this type may lead to a runtime exception": +.IF "$(CCNUMVER)" <= "001399999999" +CFLAGSCXX += -clr -AI $(DLLDEST) -AI $(SOLARBINDIR) -wd4339 +.ELSE +CFLAGSCXX += -clr:oldSyntax -AI $(DLLDEST) -AI $(SOLARBINDIR) -wd4339 +.ENDIF + +.IF "$(debug)" != "" +CFLAGS += -Ob0 +.ENDIF + + + +.IF "$(CCNUMVER)" <= "001399999999" +#see Microsoft Knowledge Base Article - 814472 +LINKFLAGS += -NOENTRY -NODEFAULTLIB:nochkclr.obj -INCLUDE:__DllMainCRTStartup@12 +.ENDIF +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/cli_environment.obj \ + $(SLO)$/cli_bridge.obj \ + $(SLO)$/cli_data.obj \ + $(SLO)$/cli_proxy.obj \ + $(SLO)$/cli_uno.obj + +SHL1OBJS = $(SLOFILES) + +SHL1TARGET = $(TARGET) + +SHL1STDLIBS = \ + $(CPPULIB) \ + $(SALLIB) \ + mscoree.lib + +.IF "$(CCNUMVER)" >= "001399999999" +SHL1STDLIBS += \ + msvcmrt.lib +.ENDIF + +SHL1VERSIONMAP = bridge_exports.map + +SHL1IMPLIB = i$(TARGET) +SHL1LIBS = $(SLB)$/$(TARGET).lib +SHL1DEF = $(MISC)$/$(SHL1TARGET).def +DEF1NAME = $(SHL1TARGET) + +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/cli_ure/source/ure/assembly.cs b/cli_ure/source/ure/assembly.cs new file mode 100644 index 000000000000..8d6032ae15d9 --- /dev/null +++ b/cli_ure/source/ure/assembly.cs @@ -0,0 +1,2 @@ +[assembly:System.Reflection.AssemblyDescription( "CLI-UNO Runtime Library" )] +[assembly:System.Reflection.AssemblyCompany( "OpenOffice.org" )] diff --git a/cli_ure/source/ure/cli_ure_config b/cli_ure/source/ure/cli_ure_config new file mode 100644 index 000000000000..14dfd7a5a33f --- /dev/null +++ b/cli_ure/source/ure/cli_ure_config @@ -0,0 +1,11 @@ +<?xml version="1.0"?> +<configuration> + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="cli_ure" publicKeyToken="ce2cb7e279207b9e"/> + <bindingRedirect oldVersion="CLI_URE_OLD_VERSION" newVersion="CLI_URE_NEW_VERSION" /> + </dependentAssembly> + </assemblyBinding> + </runtime> +</configuration>
\ No newline at end of file diff --git a/cli_ure/source/ure/makefile.mk b/cli_ure/source/ure/makefile.mk new file mode 100644 index 000000000000..3e0290888cc5 --- /dev/null +++ b/cli_ure/source/ure/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 = cli_ure + +# for dummy +TARGET = ure + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +.INCLUDE : $(PRJ)$/util$/target.pmk +.INCLUDE : target.mk + +.IF "$(BUILD_FOR_CLI)" != "" + +.INCLUDE : $(BIN)$/cliureversion.mk + +ASSEMBLY_ATTRIBUTES = $(MISC)$/assembly_ure_$(TARGET).cs + +POLICY_ASSEMBLY_FILE=$(BIN)$/$(CLI_URE_POLICY_ASSEMBLY).dll +ALLTAR : \ + $(BIN)$/cli_ure.dll \ + $(POLICY_ASSEMBLY_FILE) + +.IF "$(CCNUMVER)" >= "001399999999" +CSCFLAGS+=-keyfile:"$(BIN)$/cliuno.snk" +.ENDIF + +CSFILES = \ + uno$/util$/DisposeGuard.cs \ + uno$/util$/WeakAdapter.cs \ + uno$/util$/WeakBase.cs \ + uno$/util$/WeakComponentBase.cs \ + $(ASSEMBLY_ATTRIBUTES) + +.IF "$(CCNUMVER)" <= "001399999999" +$(ASSEMBLY_ATTRIBUTES) : assembly.cs makefile.mk $(BIN)$/cliuno.snk $(BIN)$/cliureversion.mk + $(GNUCOPY) -p assembly.cs $@ + echo \ + '[assembly:System.Reflection.AssemblyVersion( "$(CLI_URE_NEW_VERSION)")] \ + [assembly:System.Reflection.AssemblyKeyFile(@"$(BIN)$/cliuno.snk")]' \ + >> $@ +.ELSE +$(ASSEMBLY_ATTRIBUTES) : assembly.cs makefile.mk $(BIN)$/cliuno.snk $(BIN)$/cliureversion.mk + $(GNUCOPY) -p assembly.cs $@ + echo \ + '[assembly:System.Reflection.AssemblyVersion( "$(CLI_URE_NEW_VERSION)")]' \ + >> $@ +.ENDIF + +$(BIN)$/cli_ure.dll : $(CSFILES) $(BIN)$/cli_uretypes.dll $(BIN)$/cliureversion.mk + $(CSC) $(CSCFLAGS) \ + -target:library \ + -out:$@ \ + -reference:$(OUT)$/bin$/cli_uretypes.dll \ + -reference:System.dll \ + $(CSFILES) + @echo "If code has changed then provide a policy assembly and change the version!" + + +#do not forget to deliver cli_ure.config. It is NOT embedded in the policy file. +$(POLICY_ASSEMBLY_FILE) : $(BIN)$/cli_ure.config + $(WRAPCMD) AL.exe -out:$@ \ + -version:$(CLI_URE_POLICY_VERSION) \ + -keyfile:$(BIN)$/cliuno.snk \ + -link:$(BIN)$/cli_ure.config + +#Create the config file that is used with the policy assembly +$(BIN)$/cli_ure.config: cli_ure_config $(BIN)$/cliureversion.mk + $(PERL) $(SOLARENV)$/bin$/clipatchconfig.pl \ + $< $@ + + +.ENDIF + + diff --git a/cli_ure/source/ure/uno/util/DisposeGuard.cs b/cli_ure/source/ure/uno/util/DisposeGuard.cs new file mode 100644 index 000000000000..3c6c7671d64e --- /dev/null +++ b/cli_ure/source/ure/uno/util/DisposeGuard.cs @@ -0,0 +1,59 @@ +/************************************************************************* + * + * 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 unoidl.com.sun.star.lang; + +namespace uno.util +{ + +/** Helper class to conveniently auto dispose UNO objects from within + managed code. +*/ +public struct DisposeGuard : IDisposable +{ + private XComponent m_xComponent; + + /** ctor. + + @param obj target object + */ + public DisposeGuard( XComponent obj ) + { + m_xComponent = obj; + } + + /** System.IDisposable impl + */ + public void Dispose() + { + if (null != m_xComponent) + m_xComponent.dispose(); + } +} + +} diff --git a/cli_ure/source/ure/uno/util/WeakAdapter.cs b/cli_ure/source/ure/uno/util/WeakAdapter.cs new file mode 100644 index 000000000000..6f5b971131d3 --- /dev/null +++ b/cli_ure/source/ure/uno/util/WeakAdapter.cs @@ -0,0 +1,120 @@ +/************************************************************************* + * + * 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 unoidl.com.sun.star.uno; +using unoidl.com.sun.star.lang; + +namespace uno.util +{ + +/** An XAdapter implementation that holds a weak reference + (System.WeakReference) to an object. + Clients can register listeners (unoidl.com.sun.star.lang.XReference) + which are notified when the object (the one which is kept weak) is + being finalized. That is, that object is being destroyed because there + are not any hard references to it. +*/ +public class WeakAdapter : XAdapter +{ + // references the XWeak implementation + private WeakReference m_weakRef; + // contains XReference objects registered by addReference + private delegate void XReference_dispose(); + private XReference_dispose m_XReference_dispose; + + /** ctor. + + @param obj the object that is to be held weakly + */ + public WeakAdapter( Object obj ) + { + m_weakRef = new WeakReference( obj ); + m_XReference_dispose = null; + } + + /** Called by the XWeak implementation (WeakBase) when it is being + finalized. It is only being called once. + The registererd XReference listeners are notified. On notification + they are to unregister themselves. The notification is thread-safe. + However, it is possible to add a listener during the notification + process, which will never receive a notification. + To prevent this, one would have to synchronize this method with + the addReference method. But this can result in deadlocks in a + multithreaded environment. + */ + internal /* non-virtual */ void referentDying() + { + XReference_dispose call; + lock (this) + { + call = m_XReference_dispose; + m_XReference_dispose = null; + } + if (null != call) + call(); + } + + // XAdapter impl + + /** Called to obtain a hard reference o the object which is kept weakly + by this instance. + + @return hard reference to the object + */ + public Object queryAdapted() + { + return m_weakRef.Target; + } + /** Called by clients to register listener which are notified when the + weak object is dying. + + @param xReference a listener + */ + public void removeReference( XReference xReference ) + { + lock (this) + { + m_XReference_dispose -= + new XReference_dispose( xReference.dispose ); + } + } + /** Called by clients to unregister listeners. + + @param xReference a listener + */ + public void addReference( XReference xReference ) + { + lock (this) + { + m_XReference_dispose += + new XReference_dispose( xReference.dispose ); + } + } +} + +} diff --git a/cli_ure/source/ure/uno/util/WeakBase.cs b/cli_ure/source/ure/uno/util/WeakBase.cs new file mode 100644 index 000000000000..9e7d9023f198 --- /dev/null +++ b/cli_ure/source/ure/uno/util/WeakBase.cs @@ -0,0 +1,178 @@ +/************************************************************************* + * + * 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 unoidl.com.sun.star.uno; +using unoidl.com.sun.star.lang; + +namespace uno.util +{ + +/** This class can be used as a base class for UNO objects. + It implements the capability to be kept weakly + (unoidl.com.sun.star.uno.XWeak) and it implements + unoidl.com.sun.star.lang.XTypeProvider which is necessary for + using the object from StarBasic. +*/ +public class WeakBase : XWeak, XTypeProvider +{ + // Contains all WeakAdapter which have been created in this class + // They have to be notified when this object dies + private WeakAdapter m_adapter = null; + + protected static Hashtable s_types = new Hashtable(); + protected static Hashtable s_impl_ids = new Hashtable(); + + // XWeak impl + /** The returned XAdapter implementation can be used to keap a + weak reference to this object. + + @return a weak adapter + */ + public XAdapter queryAdapter() + { + if (null == m_adapter) + { + lock (this) + { + if (null == m_adapter) + m_adapter = new WeakAdapter( this ); + } + } + return m_adapter; + } + + /** Overrides of Object.Finalize method. + When there are no references to this object anymore, then the + garbage collector calls this method, thereby causing the adapter + object to be notified. The adapter, in turn, notifies all + listeners (unoidl.com.sun.star.uno.XReference). + */ + ~WeakBase() + { + if (null != m_adapter) + m_adapter.referentDying(); + } + + // XTypeProvider impl + + /** Returns an array of Type objects which represent all implemented + UNO interfaces of this object. + + @return Type objects of all implemented interfaces. + */ + public Type [] getTypes() + { + Type [] types; + Type type = GetType(); + lock (s_types) + { + types = (Type []) s_types[ type ]; + if (null == types) + { + Type [] interfaces = type.GetInterfaces(); + ArrayList list = new ArrayList( interfaces.Length ); + for ( Int32 pos = 0; pos < interfaces.Length; ++pos ) + { + Type iface = interfaces[ pos ]; + // xxx todo: as long as the bridge cannot introduce + // native CTS types into UNO on the fly + if (iface.FullName.StartsWith( "unoidl." )) + { + list.Add( iface ); + } + } + Int32 len = list.Count; + Type [] ar = new Type [ len ]; + for ( Int32 pos = 0; pos < len; ++pos ) + ar[ pos ] = (Type) list[ pos ]; + s_types[ type ] = ar; + types = ar; + } + } + return types; + } + + /** Provides an identifier that represents the set of UNO interfaces + implemented by this class. All instances of this class which run + in the same CLR return the same array. + + @return identifier as array of bytes + */ + public byte [] getImplementationId() + { + byte [] id; + Type type = GetType(); + lock (s_impl_ids) + { + id = (byte []) s_impl_ids[ type ]; + if (null == id) + { + Int32 hash = GetHashCode(); + String name = type.FullName; + Int32 len= name.Length; + + id = new byte[ 4 + (2 * len) ]; + id[ 0 ]= (byte) (hash & 0xff); + id[ 1 ]= (byte) ((hash >> 8) & 0xff); + id[ 2 ]= (byte) ((hash >> 16) & 0xff); + id[ 3 ]= (byte) ((hash >> 24) & 0xff); + + for ( Int32 pos = 0; pos < len; ++pos ) + { + UInt16 c = Convert.ToUInt16( name[ pos ] ); + id[ 4 + (2 * pos) ] = (byte) (c & 0xff); + id[ 4 + (2 * pos) +1 ] = (byte) ((c >> 8) & 0xff); + } + s_impl_ids[ type ] = id; + } + } + return id; + } + + // System.Object + public override String ToString() + { + System.Text.StringBuilder buf = + new System.Text.StringBuilder( base.ToString(), 256 ); + buf.Append( "\nUNO Object Implementation:\n\tImplementationId: " ); + buf.Append( getImplementationId() ); + buf.Append( "\n\tInterfaces: " ); + Type [] types = getTypes(); + for ( Int32 pos = 0; pos < types.Length; ++pos ) + { + buf.Append( types[ pos ].FullName ); + if (pos < (types.Length -1)) + buf.Append( ", " ); + } + return buf.ToString(); + } +} + +} + diff --git a/cli_ure/source/ure/uno/util/WeakComponentBase.cs b/cli_ure/source/ure/uno/util/WeakComponentBase.cs new file mode 100644 index 000000000000..1b688a5b2a80 --- /dev/null +++ b/cli_ure/source/ure/uno/util/WeakComponentBase.cs @@ -0,0 +1,194 @@ +/************************************************************************* + * + * 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 unoidl.com.sun.star.lang; + +namespace uno.util +{ + +/** This class can be used as a base class for UNO objects. + It implements the capability to be kept weakly + (unoidl.com.sun.star.uno.XWeak) and it implements + unoidl.com.sun.star.lang.XTypeProvider which is necessary for + using the object from StarBasic. + In addition, it implements the interface + unoidl.com.sun.star.lang.XComponent to be disposed explicitly. +*/ +public class WeakComponentBase : WeakBase, XComponent +{ + private delegate void t_disposing( EventObject evt ); + private t_disposing m_disposing = null; + private bool m_inDispose = false; + private bool m_disposed = false; + + /** Indicates whether object is alrady disposed. + + @return + true, if object has been disposed + */ + protected bool isDisposed() + { + lock (this) + { + return m_disposed; + } + } + + /** Checks whether this object is disposed and throws a DisposedException + if it is already disposed. + */ + protected void checkUnDisposed() + { + if (! isDisposed()) + { + throw new unoidl.com.sun.star.lang.DisposedException( + "object already disposed!", this ); + } + } + + ~WeakComponentBase() + { + bool doDispose; + lock (this) + { + doDispose = (!m_inDispose && !m_disposed); + } + if (doDispose) + { + dispose(); + } + } + + /** Override to perform extra clean-up work. Provided for subclasses. + It is called during dispose() + */ + protected void preDisposing() + { + } + + /** Override to become notified right before the disposing action is + performed. + */ + protected void postDisposing() + { + } + + // XComponent impl + /** This method is called by the owner of this object to explicitly + dispose it. This implementation of dispose() first notifies this object + via preDisposing(), then all registered event listeners and + finally this object again calling postDisposing(). + */ + public void dispose() + { + // Determine in a thread-safe way if this is the first call to this + // method. Only then we proceed with the notification of event + // listeners. It is an error to call this method more then once. + bool doDispose = false; + t_disposing call = null; + lock (this) + { + if (! m_inDispose && !m_disposed) + { + call = m_disposing; + m_disposing = null; + m_inDispose = true; + doDispose = true; + } + } + // The notification occures in an unsynchronized block in order to avoid + // deadlocks if one of the listeners calls back in a different thread on + // a synchronized method which uses the same object. + if (doDispose) + { + try + { + // call sub class + preDisposing(); + // send disposing notifications to listeners + if (null != call) + { + EventObject evt = new EventObject( this ); + call( evt ); + } + // call sub class + postDisposing(); + } + finally + { + // finally makes sure that the flags are set ensuring + // that this function is only called once. + m_disposed = true; + m_inDispose = false; + } + } + else + { + // in a multithreaded environment, it can't be avoided, + // that dispose is called twice. + // However this condition is traced, because it MAY indicate an + // error. +#if DEBUG + Console.WriteLine( + "WeakComponentBase.dispose() - dispose called twice" ); +#endif +// Debug.Fail( "WeakComponentBase.dispose() - dispose called twice" ); + } + } + /** Registers an event listener being notified when this object is disposed. + + @param xListener event listener + */ + public void addEventListener( XEventListener xListener ) + { + bool add; + lock (this) + { + add = (! m_inDispose && !m_disposed); + if (add) + m_disposing += new t_disposing( xListener.disposing ); + } + if (! add) + xListener.disposing( new EventObject( this ) ); + } + /** Revokes an event listener from being notified when this object + is disposed. + + @param xListener event listener + */ + public void removeEventListener( XEventListener xListener ) + { + lock (this) + { + if (! m_inDispose && !m_disposed) + m_disposing -= new t_disposing( xListener.disposing ); + } + } +} + +} |