diff options
Diffstat (limited to 'src/mscorlib/src/System/Runtime/InteropServices')
140 files changed, 21970 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ArrayWithOffset.cs b/src/mscorlib/src/System/Runtime/InteropServices/ArrayWithOffset.cs new file mode 100644 index 0000000000..15872a0e6c --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ArrayWithOffset.cs @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Runtime.InteropServices { + + using System; + using System.Runtime.CompilerServices; + using System.Runtime.Versioning; + + [Serializable] + [System.Runtime.InteropServices.ComVisible(true)] + public struct ArrayWithOffset + { + //private ArrayWithOffset() + //{ + // throw new Exception(); + //} + + [System.Security.SecuritySafeCritical] // auto-generated + public ArrayWithOffset(Object array, int offset) + { + m_array = array; + m_offset = offset; + m_count = 0; + m_count = CalculateCount(); + } + + public Object GetArray() + { + return m_array; + } + + public int GetOffset() + { + return m_offset; + } + + public override int GetHashCode() + { + return m_count + m_offset; + } + + public override bool Equals(Object obj) + { + if (obj is ArrayWithOffset) + return Equals((ArrayWithOffset)obj); + else + return false; + } + + public bool Equals(ArrayWithOffset obj) + { + return obj.m_array == m_array && obj.m_offset == m_offset && obj.m_count == m_count; + } + + public static bool operator ==(ArrayWithOffset a, ArrayWithOffset b) + { + return a.Equals(b); + } + + public static bool operator !=(ArrayWithOffset a, ArrayWithOffset b) + { + return !(a == b); + } + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private extern int CalculateCount(); + + private Object m_array; + private int m_offset; + private int m_count; + } + +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/Attributes.cs b/src/mscorlib/src/System/Runtime/InteropServices/Attributes.cs new file mode 100644 index 0000000000..162cd94901 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/Attributes.cs @@ -0,0 +1,1134 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +namespace System.Runtime.InteropServices{ + + using System; + using System.Reflection; + using System.Diagnostics.Contracts; + + [AttributeUsage(AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class UnmanagedFunctionPointerAttribute : Attribute + { + CallingConvention m_callingConvention; + + public UnmanagedFunctionPointerAttribute(CallingConvention callingConvention) { m_callingConvention = callingConvention; } + + public CallingConvention CallingConvention { get { return m_callingConvention; } } + + public CharSet CharSet; + public bool BestFitMapping; + public bool ThrowOnUnmappableChar; + + // This field is ignored and marshaling behaves as if it was true (for historical reasons). + public bool SetLastError; + + // P/Invoke via delegate always preserves signature, HRESULT swapping is not supported. + //public bool PreserveSig; + } + + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Struct | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(false)] + public sealed class TypeIdentifierAttribute : Attribute + { + public TypeIdentifierAttribute() { } + public TypeIdentifierAttribute(string scope, string identifier) { Scope_ = scope; Identifier_ = identifier; } + + public String Scope { get { return Scope_; } } + public String Identifier { get { return Identifier_; } } + + internal String Scope_; + internal String Identifier_; + } + + // To be used on methods that sink reverse P/Invoke calls. + // This attribute is a CoreCLR-only security measure, currently ignored by the desktop CLR. + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public sealed class AllowReversePInvokeCallsAttribute : Attribute + { + public AllowReversePInvokeCallsAttribute() + { + } + } + + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Event, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class DispIdAttribute : Attribute + { + internal int _val; + public DispIdAttribute(int dispId) + { + _val = dispId; + } + public int Value { get { return _val; } } + } + + [Serializable] + [System.Runtime.InteropServices.ComVisible(true)] + public enum ComInterfaceType + { + InterfaceIsDual = 0, + InterfaceIsIUnknown = 1, + InterfaceIsIDispatch = 2, + + [System.Runtime.InteropServices.ComVisible(false)] + InterfaceIsIInspectable = 3, + } + + [AttributeUsage(AttributeTargets.Interface, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class InterfaceTypeAttribute : Attribute + { + internal ComInterfaceType _val; + public InterfaceTypeAttribute(ComInterfaceType interfaceType) + { + _val = interfaceType; + } + public InterfaceTypeAttribute(short interfaceType) + { + _val = (ComInterfaceType)interfaceType; + } + public ComInterfaceType Value { get { return _val; } } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ComDefaultInterfaceAttribute : Attribute + { + internal Type _val; + + public ComDefaultInterfaceAttribute(Type defaultInterface) + { + _val = defaultInterface; + } + + public Type Value { get { return _val; } } + } + + [Serializable] + [System.Runtime.InteropServices.ComVisible(true)] + public enum ClassInterfaceType + { + None = 0, + AutoDispatch = 1, + AutoDual = 2 + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ClassInterfaceAttribute : Attribute + { + internal ClassInterfaceType _val; + public ClassInterfaceAttribute(ClassInterfaceType classInterfaceType) + { + _val = classInterfaceType; + + } + public ClassInterfaceAttribute(short classInterfaceType) + { + _val = (ClassInterfaceType)classInterfaceType; + } + public ClassInterfaceType Value { get { return _val; } } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ComVisibleAttribute : Attribute + { + internal bool _val; + public ComVisibleAttribute(bool visibility) + { + _val = visibility; + } + public bool Value { get { return _val; } } + } + + [AttributeUsage(AttributeTargets.Interface, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class TypeLibImportClassAttribute : Attribute + { + internal String _importClassName; + public TypeLibImportClassAttribute(Type importClass) + { + _importClassName = importClass.ToString(); + } + public String Value { get { return _importClassName; } } + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class LCIDConversionAttribute : Attribute + { + internal int _val; + public LCIDConversionAttribute(int lcid) + { + _val = lcid; + } + public int Value { get {return _val;} } + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ComRegisterFunctionAttribute : Attribute + { + public ComRegisterFunctionAttribute() + { + } + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ComUnregisterFunctionAttribute : Attribute + { + public ComUnregisterFunctionAttribute() + { + } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ProgIdAttribute : Attribute + { + internal String _val; + public ProgIdAttribute(String progId) + { + _val = progId; + } + public String Value { get {return _val;} } + } + + [AttributeUsage(AttributeTargets.Assembly, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ImportedFromTypeLibAttribute : Attribute + { + internal String _val; + public ImportedFromTypeLibAttribute(String tlbFile) + { + _val = tlbFile; + } + public String Value { get {return _val;} } + } + + [Obsolete("The IDispatchImplAttribute is deprecated.", false)] + [Serializable] + [System.Runtime.InteropServices.ComVisible(true)] + public enum IDispatchImplType + { + SystemDefinedImpl = 0, + InternalImpl = 1, + CompatibleImpl = 2, + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly, Inherited = false)] + [Obsolete("This attribute is deprecated and will be removed in a future version.", false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class IDispatchImplAttribute : Attribute + { + internal IDispatchImplType _val; + public IDispatchImplAttribute(IDispatchImplType implType) + { + _val = implType; + } + public IDispatchImplAttribute(short implType) + { + _val = (IDispatchImplType)implType; + } + public IDispatchImplType Value { get {return _val;} } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = true)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ComSourceInterfacesAttribute : Attribute + { + internal String _val; + public ComSourceInterfacesAttribute(String sourceInterfaces) + { + _val = sourceInterfaces; + } + public ComSourceInterfacesAttribute(Type sourceInterface) + { + _val = sourceInterface.FullName; + } + public ComSourceInterfacesAttribute(Type sourceInterface1, Type sourceInterface2) + { + _val = sourceInterface1.FullName + "\0" + sourceInterface2.FullName; + } + public ComSourceInterfacesAttribute(Type sourceInterface1, Type sourceInterface2, Type sourceInterface3) + { + _val = sourceInterface1.FullName + "\0" + sourceInterface2.FullName + "\0" + sourceInterface3.FullName; + } + public ComSourceInterfacesAttribute(Type sourceInterface1, Type sourceInterface2, Type sourceInterface3, Type sourceInterface4) + { + _val = sourceInterface1.FullName + "\0" + sourceInterface2.FullName + "\0" + sourceInterface3.FullName + "\0" + sourceInterface4.FullName; + } + public String Value { get {return _val;} } + } + + [AttributeUsage(AttributeTargets.All, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ComConversionLossAttribute : Attribute + { + public ComConversionLossAttribute() + { + } + } + +[Serializable] +[Flags()] + [System.Runtime.InteropServices.ComVisible(true)] + public enum TypeLibTypeFlags + { + FAppObject = 0x0001, + FCanCreate = 0x0002, + FLicensed = 0x0004, + FPreDeclId = 0x0008, + FHidden = 0x0010, + FControl = 0x0020, + FDual = 0x0040, + FNonExtensible = 0x0080, + FOleAutomation = 0x0100, + FRestricted = 0x0200, + FAggregatable = 0x0400, + FReplaceable = 0x0800, + FDispatchable = 0x1000, + FReverseBind = 0x2000, + } + +[Serializable] +[Flags()] + [System.Runtime.InteropServices.ComVisible(true)] + public enum TypeLibFuncFlags + { + FRestricted = 0x0001, + FSource = 0x0002, + FBindable = 0x0004, + FRequestEdit = 0x0008, + FDisplayBind = 0x0010, + FDefaultBind = 0x0020, + FHidden = 0x0040, + FUsesGetLastError = 0x0080, + FDefaultCollelem = 0x0100, + FUiDefault = 0x0200, + FNonBrowsable = 0x0400, + FReplaceable = 0x0800, + FImmediateBind = 0x1000, + } + +[Serializable] +[Flags()] + [System.Runtime.InteropServices.ComVisible(true)] + public enum TypeLibVarFlags + { + FReadOnly = 0x0001, + FSource = 0x0002, + FBindable = 0x0004, + FRequestEdit = 0x0008, + FDisplayBind = 0x0010, + FDefaultBind = 0x0020, + FHidden = 0x0040, + FRestricted = 0x0080, + FDefaultCollelem = 0x0100, + FUiDefault = 0x0200, + FNonBrowsable = 0x0400, + FReplaceable = 0x0800, + FImmediateBind = 0x1000, + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Struct, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class TypeLibTypeAttribute : Attribute + { + internal TypeLibTypeFlags _val; + public TypeLibTypeAttribute(TypeLibTypeFlags flags) + { + _val = flags; + } + public TypeLibTypeAttribute(short flags) + { + _val = (TypeLibTypeFlags)flags; + } + public TypeLibTypeFlags Value { get {return _val;} } + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class TypeLibFuncAttribute : Attribute + { + internal TypeLibFuncFlags _val; + public TypeLibFuncAttribute(TypeLibFuncFlags flags) + { + _val = flags; + } + public TypeLibFuncAttribute(short flags) + { + _val = (TypeLibFuncFlags)flags; + } + public TypeLibFuncFlags Value { get {return _val;} } + } + + [AttributeUsage(AttributeTargets.Field, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class TypeLibVarAttribute : Attribute + { + internal TypeLibVarFlags _val; + public TypeLibVarAttribute(TypeLibVarFlags flags) + { + _val = flags; + } + public TypeLibVarAttribute(short flags) + { + _val = (TypeLibVarFlags)flags; + } + public TypeLibVarFlags Value { get {return _val;} } + } + + [Serializable] + [System.Runtime.InteropServices.ComVisible(true)] + public enum VarEnum + { + VT_EMPTY = 0, + VT_NULL = 1, + VT_I2 = 2, + VT_I4 = 3, + VT_R4 = 4, + VT_R8 = 5, + VT_CY = 6, + VT_DATE = 7, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_ERROR = 10, + VT_BOOL = 11, + VT_VARIANT = 12, + VT_UNKNOWN = 13, + VT_DECIMAL = 14, + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_INT = 22, + VT_UINT = 23, + VT_VOID = 24, + VT_HRESULT = 25, + VT_PTR = 26, + VT_SAFEARRAY = 27, + VT_CARRAY = 28, + VT_USERDEFINED = 29, + VT_LPSTR = 30, + VT_LPWSTR = 31, + VT_RECORD = 36, + VT_FILETIME = 64, + VT_BLOB = 65, + VT_STREAM = 66, + VT_STORAGE = 67, + VT_STREAMED_OBJECT = 68, + VT_STORED_OBJECT = 69, + VT_BLOB_OBJECT = 70, + VT_CF = 71, + VT_CLSID = 72, + VT_VECTOR = 0x1000, + VT_ARRAY = 0x2000, + VT_BYREF = 0x4000 + } + + [Serializable] + [System.Runtime.InteropServices.ComVisible(true)] + // Note that this enum should remain in-sync with the CorNativeType enum in corhdr.h + public enum UnmanagedType + { + Bool = 0x2, // 4 byte boolean value (true != 0, false == 0) + + I1 = 0x3, // 1 byte signed value + + U1 = 0x4, // 1 byte unsigned value + + I2 = 0x5, // 2 byte signed value + + U2 = 0x6, // 2 byte unsigned value + + I4 = 0x7, // 4 byte signed value + + U4 = 0x8, // 4 byte unsigned value + + I8 = 0x9, // 8 byte signed value + + U8 = 0xa, // 8 byte unsigned value + + R4 = 0xb, // 4 byte floating point + + R8 = 0xc, // 8 byte floating point + + Currency = 0xf, // A currency + + BStr = 0x13, // OLE Unicode BSTR + + LPStr = 0x14, // Ptr to SBCS string + + LPWStr = 0x15, // Ptr to Unicode string + + LPTStr = 0x16, // Ptr to OS preferred (SBCS/Unicode) string + + ByValTStr = 0x17, // OS preferred (SBCS/Unicode) inline string (only valid in structs) + + IUnknown = 0x19, // COM IUnknown pointer. + + IDispatch = 0x1a, // COM IDispatch pointer + + Struct = 0x1b, // Structure + + Interface = 0x1c, // COM interface + + SafeArray = 0x1d, // OLE SafeArray + + ByValArray = 0x1e, // Array of fixed size (only valid in structs) + + SysInt = 0x1f, // Hardware natural sized signed integer + + SysUInt = 0x20, + + VBByRefStr = 0x22, + + AnsiBStr = 0x23, // OLE BSTR containing SBCS characters + + TBStr = 0x24, // Ptr to OS preferred (SBCS/Unicode) BSTR + + VariantBool = 0x25, // OLE defined BOOLEAN (2 bytes, true == -1, false == 0) + + FunctionPtr = 0x26, // Function pointer + + AsAny = 0x28, // Paired with Object type and does runtime marshalling determination + + LPArray = 0x2a, // C style array + + LPStruct = 0x2b, // Pointer to a structure + + CustomMarshaler = 0x2c, + + Error = 0x2d, + + [System.Runtime.InteropServices.ComVisible(false)] + IInspectable = 0x2e, + + [System.Runtime.InteropServices.ComVisible(false)] + HString = 0x2f, // Windows Runtime HSTRING + } + + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.ReturnValue, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public unsafe sealed class MarshalAsAttribute : Attribute + { + [System.Security.SecurityCritical] // auto-generated + internal static Attribute GetCustomAttribute(RuntimeParameterInfo parameter) + { + return GetCustomAttribute(parameter.MetadataToken, parameter.GetRuntimeModule()); + } + + [System.Security.SecurityCritical] // auto-generated + internal static bool IsDefined(RuntimeParameterInfo parameter) + { + return GetCustomAttribute(parameter) != null; + } + + [System.Security.SecurityCritical] // auto-generated + internal static Attribute GetCustomAttribute(RuntimeFieldInfo field) + { + return GetCustomAttribute(field.MetadataToken, field.GetRuntimeModule()); ; + } + + [System.Security.SecurityCritical] // auto-generated + internal static bool IsDefined(RuntimeFieldInfo field) + { + return GetCustomAttribute(field) != null; + } + + [System.Security.SecurityCritical] // auto-generated + internal static Attribute GetCustomAttribute(int token, RuntimeModule scope) + { + UnmanagedType unmanagedType, arraySubType; + VarEnum safeArraySubType; + int sizeParamIndex = 0, sizeConst = 0; + string marshalTypeName = null, marshalCookie = null, safeArrayUserDefinedTypeName = null; + int iidParamIndex = 0; + ConstArray nativeType = ModuleHandle.GetMetadataImport(scope.GetNativeHandle()).GetFieldMarshal(token); + + if (nativeType.Length == 0) + return null; + + MetadataImport.GetMarshalAs(nativeType, + out unmanagedType, out safeArraySubType, out safeArrayUserDefinedTypeName, out arraySubType, out sizeParamIndex, + out sizeConst, out marshalTypeName, out marshalCookie, out iidParamIndex); + + RuntimeType safeArrayUserDefinedType = safeArrayUserDefinedTypeName == null || safeArrayUserDefinedTypeName.Length == 0 ? null : + RuntimeTypeHandle.GetTypeByNameUsingCARules(safeArrayUserDefinedTypeName, scope); + RuntimeType marshalTypeRef = null; + + try + { + marshalTypeRef = marshalTypeName == null ? null : RuntimeTypeHandle.GetTypeByNameUsingCARules(marshalTypeName, scope); + } + catch (System.TypeLoadException) + { + // The user may have supplied a bad type name string causing this TypeLoadException + // Regardless, we return the bad type name + Contract.Assert(marshalTypeName != null); + } + + return new MarshalAsAttribute( + unmanagedType, safeArraySubType, safeArrayUserDefinedType, arraySubType, + (short)sizeParamIndex, sizeConst, marshalTypeName, marshalTypeRef, marshalCookie, iidParamIndex); + } + + internal MarshalAsAttribute(UnmanagedType val, VarEnum safeArraySubType, RuntimeType safeArrayUserDefinedSubType, UnmanagedType arraySubType, + short sizeParamIndex, int sizeConst, string marshalType, RuntimeType marshalTypeRef, string marshalCookie, int iidParamIndex) + { + _val = val; + SafeArraySubType = safeArraySubType; + SafeArrayUserDefinedSubType = safeArrayUserDefinedSubType; + IidParameterIndex = iidParamIndex; + ArraySubType = arraySubType; + SizeParamIndex = sizeParamIndex; + SizeConst = sizeConst; + MarshalType = marshalType; + MarshalTypeRef = marshalTypeRef; + MarshalCookie = marshalCookie; + } + + internal UnmanagedType _val; + public MarshalAsAttribute(UnmanagedType unmanagedType) + { + _val = unmanagedType; + } + public MarshalAsAttribute(short unmanagedType) + { + _val = (UnmanagedType)unmanagedType; + } + public UnmanagedType Value { get { return _val; } } + + // Fields used with SubType = SafeArray. + public VarEnum SafeArraySubType; + public Type SafeArrayUserDefinedSubType; + + // Field used with iid_is attribute (interface pointers). + public int IidParameterIndex; + + // Fields used with SubType = ByValArray and LPArray. + // Array size = parameter(PI) * PM + C + public UnmanagedType ArraySubType; + public short SizeParamIndex; // param index PI + public int SizeConst; // constant C + + // Fields used with SubType = CustomMarshaler + [System.Runtime.InteropServices.ComVisible(true)] + public String MarshalType; // Name of marshaler class + [System.Runtime.InteropServices.ComVisible(true)] + public Type MarshalTypeRef; // Type of marshaler class + public String MarshalCookie; // cookie to pass to marshaler + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ComImportAttribute : Attribute + { + internal static Attribute GetCustomAttribute(RuntimeType type) + { + if ((type.Attributes & TypeAttributes.Import) == 0) + return null; + + return new ComImportAttribute(); + } + + internal static bool IsDefined(RuntimeType type) + { + return (type.Attributes & TypeAttributes.Import) != 0; + } + + public ComImportAttribute() + { + } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Struct | AttributeTargets.Delegate, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class GuidAttribute : Attribute + { + internal String _val; + public GuidAttribute(String guid) + { + _val = guid; + } + public String Value { get { return _val; } } + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class PreserveSigAttribute : Attribute + { + internal static Attribute GetCustomAttribute(RuntimeMethodInfo method) + { + if ((method.GetMethodImplementationFlags() & MethodImplAttributes.PreserveSig) == 0) + return null; + + return new PreserveSigAttribute(); + } + + internal static bool IsDefined(RuntimeMethodInfo method) + { + return (method.GetMethodImplementationFlags() & MethodImplAttributes.PreserveSig) != 0; + } + + public PreserveSigAttribute() + { + } + } + + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class InAttribute : Attribute + { + internal static Attribute GetCustomAttribute(RuntimeParameterInfo parameter) + { + return parameter.IsIn ? new InAttribute() : null; + } + internal static bool IsDefined(RuntimeParameterInfo parameter) + { + return parameter.IsIn; + } + + public InAttribute() + { + } + } + + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class OutAttribute : Attribute + { + internal static Attribute GetCustomAttribute(RuntimeParameterInfo parameter) + { + return parameter.IsOut ? new OutAttribute() : null; + } + internal static bool IsDefined(RuntimeParameterInfo parameter) + { + return parameter.IsOut; + } + + public OutAttribute() + { + } + } + + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class OptionalAttribute : Attribute + { + internal static Attribute GetCustomAttribute(RuntimeParameterInfo parameter) + { + return parameter.IsOptional ? new OptionalAttribute() : null; + } + internal static bool IsDefined(RuntimeParameterInfo parameter) + { + return parameter.IsOptional; + } + + public OptionalAttribute() + { + } + } + + [Flags] + public enum DllImportSearchPath + { + UseDllDirectoryForDependencies = 0x100, + ApplicationDirectory = 0x200, + UserDirectories = 0x400, + System32 = 0x800, + SafeDirectories = 0x1000, + AssemblyDirectory = 0x2, + LegacyBehavior = 0x0 + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Method, AllowMultiple = false)] + [System.Runtime.InteropServices.ComVisible(false)] + public sealed class DefaultDllImportSearchPathsAttribute : Attribute + { + internal DllImportSearchPath _paths; + public DefaultDllImportSearchPathsAttribute(DllImportSearchPath paths) + { + _paths = paths; + } + + public DllImportSearchPath Paths { get { return _paths; } } + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public unsafe sealed class DllImportAttribute : Attribute + { + [System.Security.SecurityCritical] // auto-generated + internal static Attribute GetCustomAttribute(RuntimeMethodInfo method) + { + if ((method.Attributes & MethodAttributes.PinvokeImpl) == 0) + return null; + + MetadataImport scope = ModuleHandle.GetMetadataImport(method.Module.ModuleHandle.GetRuntimeModule()); + string entryPoint, dllName = null; + int token = method.MetadataToken; + PInvokeAttributes flags = 0; + + scope.GetPInvokeMap(token, out flags, out entryPoint, out dllName); + + CharSet charSet = CharSet.None; + + switch (flags & PInvokeAttributes.CharSetMask) + { + case PInvokeAttributes.CharSetNotSpec: charSet = CharSet.None; break; + case PInvokeAttributes.CharSetAnsi: charSet = CharSet.Ansi; break; + case PInvokeAttributes.CharSetUnicode: charSet = CharSet.Unicode; break; + case PInvokeAttributes.CharSetAuto: charSet = CharSet.Auto; break; + + // Invalid: default to CharSet.None + default: break; + } + + CallingConvention callingConvention = CallingConvention.Cdecl; + + switch (flags & PInvokeAttributes.CallConvMask) + { + case PInvokeAttributes.CallConvWinapi: callingConvention = CallingConvention.Winapi; break; + case PInvokeAttributes.CallConvCdecl: callingConvention = CallingConvention.Cdecl; break; + case PInvokeAttributes.CallConvStdcall: callingConvention = CallingConvention.StdCall; break; + case PInvokeAttributes.CallConvThiscall: callingConvention = CallingConvention.ThisCall; break; + case PInvokeAttributes.CallConvFastcall: callingConvention = CallingConvention.FastCall; break; + + // Invalid: default to CallingConvention.Cdecl + default: break; + } + + bool exactSpelling = (flags & PInvokeAttributes.NoMangle) != 0; + bool setLastError = (flags & PInvokeAttributes.SupportsLastError) != 0; + bool bestFitMapping = (flags & PInvokeAttributes.BestFitMask) == PInvokeAttributes.BestFitEnabled; + bool throwOnUnmappableChar = (flags & PInvokeAttributes.ThrowOnUnmappableCharMask) == PInvokeAttributes.ThrowOnUnmappableCharEnabled; + bool preserveSig = (method.GetMethodImplementationFlags() & MethodImplAttributes.PreserveSig) != 0; + + return new DllImportAttribute( + dllName, entryPoint, charSet, exactSpelling, setLastError, preserveSig, + callingConvention, bestFitMapping, throwOnUnmappableChar); + } + + internal static bool IsDefined(RuntimeMethodInfo method) + { + return (method.Attributes & MethodAttributes.PinvokeImpl) != 0; + } + + + internal DllImportAttribute( + string dllName, string entryPoint, CharSet charSet, bool exactSpelling, bool setLastError, bool preserveSig, + CallingConvention callingConvention, bool bestFitMapping, bool throwOnUnmappableChar) + { + _val = dllName; + EntryPoint = entryPoint; + CharSet = charSet; + ExactSpelling = exactSpelling; + SetLastError = setLastError; + PreserveSig = preserveSig; + CallingConvention = callingConvention; + BestFitMapping = bestFitMapping; + ThrowOnUnmappableChar = throwOnUnmappableChar; + } + + internal String _val; + + public DllImportAttribute(String dllName) + { + _val = dllName; + } + public String Value { get { return _val; } } + + public String EntryPoint; + public CharSet CharSet; + public bool SetLastError; + public bool ExactSpelling; + public bool PreserveSig; + public CallingConvention CallingConvention; + public bool BestFitMapping; + public bool ThrowOnUnmappableChar; + + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public unsafe sealed class StructLayoutAttribute : Attribute + { + private const int DEFAULT_PACKING_SIZE = 8; + + [System.Security.SecurityCritical] // auto-generated + internal static Attribute GetCustomAttribute(RuntimeType type) + { + if (!IsDefined(type)) + return null; + + int pack = 0, size = 0; + LayoutKind layoutKind = LayoutKind.Auto; + switch (type.Attributes & TypeAttributes.LayoutMask) + { + case TypeAttributes.ExplicitLayout: layoutKind = LayoutKind.Explicit; break; + case TypeAttributes.AutoLayout: layoutKind = LayoutKind.Auto; break; + case TypeAttributes.SequentialLayout: layoutKind = LayoutKind.Sequential; break; + default: Contract.Assume(false); break; + } + + CharSet charSet = CharSet.None; + switch (type.Attributes & TypeAttributes.StringFormatMask) + { + case TypeAttributes.AnsiClass: charSet = CharSet.Ansi; break; + case TypeAttributes.AutoClass: charSet = CharSet.Auto; break; + case TypeAttributes.UnicodeClass: charSet = CharSet.Unicode; break; + default: Contract.Assume(false); break; + } + type.GetRuntimeModule().MetadataImport.GetClassLayout(type.MetadataToken, out pack, out size); + + // Metadata parameter checking should not have allowed 0 for packing size. + // The runtime later converts a packing size of 0 to 8 so do the same here + // because it's more useful from a user perspective. + if (pack == 0) + pack = DEFAULT_PACKING_SIZE; + + return new StructLayoutAttribute(layoutKind, pack, size, charSet); + } + + internal static bool IsDefined(RuntimeType type) + { + if (type.IsInterface || type.HasElementType || type.IsGenericParameter) + return false; + + return true; + } + + internal LayoutKind _val; + + internal StructLayoutAttribute(LayoutKind layoutKind, int pack, int size, CharSet charSet) + { + _val = layoutKind; + Pack = pack; + Size = size; + CharSet = charSet; + } + + public StructLayoutAttribute(LayoutKind layoutKind) + { + _val = layoutKind; + } + public StructLayoutAttribute(short layoutKind) + { + _val = (LayoutKind)layoutKind; + } + public LayoutKind Value { get { return _val; } } + public int Pack; + public int Size; + public CharSet CharSet; + } + + [AttributeUsage(AttributeTargets.Field, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public unsafe sealed class FieldOffsetAttribute : Attribute + { + [System.Security.SecurityCritical] // auto-generated + internal static Attribute GetCustomAttribute(RuntimeFieldInfo field) + { + int fieldOffset; + + if (field.DeclaringType != null && + field.GetRuntimeModule().MetadataImport.GetFieldOffset(field.DeclaringType.MetadataToken, field.MetadataToken, out fieldOffset)) + return new FieldOffsetAttribute(fieldOffset); + + return null; + } + + [System.Security.SecurityCritical] // auto-generated + internal static bool IsDefined(RuntimeFieldInfo field) + { + return GetCustomAttribute(field) != null; + } + + internal int _val; + public FieldOffsetAttribute(int offset) + { + _val = offset; + } + public int Value { get { return _val; } } + } + + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ComAliasNameAttribute : Attribute + { + internal String _val; + public ComAliasNameAttribute(String alias) + { + _val = alias; + } + public String Value { get {return _val;} } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Interface, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class AutomationProxyAttribute : Attribute + { + internal bool _val; + public AutomationProxyAttribute(bool val) + { + _val = val; + } + public bool Value { get {return _val;} } + } + + [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = true)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class PrimaryInteropAssemblyAttribute : Attribute + { + internal int _major; + internal int _minor; + + public PrimaryInteropAssemblyAttribute(int major, int minor) + { + _major = major; + _minor = minor; + } + + public int MajorVersion { get {return _major;} } + public int MinorVersion { get {return _minor;} } + } + + [AttributeUsage(AttributeTargets.Interface, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class CoClassAttribute : Attribute + { + internal Type _CoClass; + + public CoClassAttribute(Type coClass) + { + _CoClass = coClass; + } + + public Type CoClass { get { return _CoClass; } } + } + + [AttributeUsage(AttributeTargets.Interface, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ComEventInterfaceAttribute : Attribute + { + internal Type _SourceInterface; + internal Type _EventProvider; + + public ComEventInterfaceAttribute(Type SourceInterface, Type EventProvider) + { + _SourceInterface = SourceInterface; + _EventProvider = EventProvider; + } + + public Type SourceInterface { get {return _SourceInterface;} } + public Type EventProvider { get {return _EventProvider;} } + } + + [AttributeUsage(AttributeTargets.Assembly, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class TypeLibVersionAttribute : Attribute + { + internal int _major; + internal int _minor; + + public TypeLibVersionAttribute(int major, int minor) + { + _major = major; + _minor = minor; + } + + public int MajorVersion { get {return _major;} } + public int MinorVersion { get {return _minor;} } + } + + [AttributeUsage(AttributeTargets.Assembly, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class ComCompatibleVersionAttribute : Attribute + { + internal int _major; + internal int _minor; + internal int _build; + internal int _revision; + + public ComCompatibleVersionAttribute(int major, int minor, int build, int revision) + { + _major = major; + _minor = minor; + _build = build; + _revision = revision; + } + + public int MajorVersion { get {return _major;} } + public int MinorVersion { get {return _minor;} } + public int BuildNumber { get {return _build;} } + public int RevisionNumber { get {return _revision;} } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class BestFitMappingAttribute : Attribute + { + internal bool _bestFitMapping; + + public BestFitMappingAttribute(bool BestFitMapping) + { + _bestFitMapping = BestFitMapping; + } + + public bool BestFitMapping { get { return _bestFitMapping; } } + public bool ThrowOnUnmappableChar; + } + + [AttributeUsage(AttributeTargets.Module, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class DefaultCharSetAttribute : Attribute + { + internal CharSet _CharSet; + + public DefaultCharSetAttribute(CharSet charSet) + { + _CharSet = charSet; + } + + public CharSet CharSet { get { return _CharSet; } } + } + + [Obsolete("This attribute has been deprecated. Application Domains no longer respect Activation Context boundaries in IDispatch calls.", false)] + [AttributeUsage(AttributeTargets.Assembly, Inherited = false)] + [System.Runtime.InteropServices.ComVisible(true)] + public sealed class SetWin32ContextInIDispatchAttribute : Attribute + { + public SetWin32ContextInIDispatchAttribute() + { + } + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] + [System.Runtime.InteropServices.ComVisible(false)] + public sealed class ManagedToNativeComInteropStubAttribute : Attribute + { + internal Type _classType; + internal String _methodName; + + public ManagedToNativeComInteropStubAttribute(Type classType, String methodName) + { + _classType = classType; + _methodName = methodName; + } + + public Type ClassType { get { return _classType; } } + public String MethodName { get { return _methodName; } } + } + +} + diff --git a/src/mscorlib/src/System/Runtime/InteropServices/BStrWrapper.cs b/src/mscorlib/src/System/Runtime/InteropServices/BStrWrapper.cs new file mode 100644 index 0000000000..756ed3f7e5 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/BStrWrapper.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Wrapper that is converted to a variant with VT_BSTR. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using System.Security; + using System.Security.Permissions; + + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public sealed class BStrWrapper + { + [System.Security.SecuritySafeCritical] // auto-generated +#pragma warning disable 618 + [SecurityPermissionAttribute(SecurityAction.Demand,Flags=SecurityPermissionFlag.UnmanagedCode)] +#pragma warning restore 618 + public BStrWrapper(String value) + { + m_WrappedObject = value; + } + + [System.Security.SecuritySafeCritical] // auto-generated +#pragma warning disable 618 + [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] +#pragma warning restore 618 + public BStrWrapper(Object value) + { + m_WrappedObject = (String)value; + } + + public String WrappedObject + { + get + { + return m_WrappedObject; + } + } + + private String m_WrappedObject; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs b/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs new file mode 100644 index 0000000000..555b2519bd --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Exception class for all errors from COM Interop where we don't +** recognize the HResult. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + using System; + using System.Runtime.Serialization; + using System.Globalization; + using System.Security; + using Microsoft.Win32; + + // Exception for COM Interop errors where we don't recognize the HResult. + // + [ComVisible(true)] + [Serializable] + public class COMException : ExternalException { + public COMException() + : base(Environment.GetResourceString("Arg_COMException")) + { + SetErrorCode(__HResults.E_FAIL); + } + + public COMException(String message) + : base(message) + { + SetErrorCode(__HResults.E_FAIL); + } + + public COMException(String message, Exception inner) + : base(message, inner) { + SetErrorCode(__HResults.E_FAIL); + } + + public COMException(String message,int errorCode) + : base(message) { + SetErrorCode(errorCode); + } + + [SecuritySafeCritical] + internal COMException(int hresult) + : base(Win32Native.GetMessage(hresult)) + { + SetErrorCode(hresult); + } + + internal COMException(String message, int hresult, Exception inner) + : base(message, inner) + { + SetErrorCode(hresult); + } + + protected COMException(SerializationInfo info, StreamingContext context) : base(info, context) { + } + + public override String ToString() { + String message = Message; + String s; + String _className = GetType().ToString(); + s = _className + " (0x" + HResult.ToString("X8", CultureInfo.InvariantCulture) + ")"; + + if (!(message == null || message.Length <= 0)) { + s = s + ": " + message; + } + + Exception _innerException = InnerException; + + if (_innerException!=null) { + s = s + " ---> " + _innerException.ToString(); + } + + + if (StackTrace != null) + s += Environment.NewLine + StackTrace; + + return s; + } + + + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/CallingConvention.cs b/src/mscorlib/src/System/Runtime/InteropServices/CallingConvention.cs new file mode 100644 index 0000000000..2fc5fcbf56 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/CallingConvention.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +namespace System.Runtime.InteropServices { + + using System; + // Used for the CallingConvention named argument to the DllImport attribute + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public enum CallingConvention + { + Winapi = 1, + Cdecl = 2, + StdCall = 3, + ThisCall = 4, + FastCall = 5, + } + +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/CharSet.cs b/src/mscorlib/src/System/Runtime/InteropServices/CharSet.cs new file mode 100644 index 0000000000..6e4e99bdf5 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/CharSet.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +namespace System.Runtime.InteropServices { + using System; + // Use this in P/Direct function prototypes to specify + // which character set to use when marshalling Strings. + // Using Ansi will marshal the strings as 1 byte char*'s. + // Using Unicode will marshal the strings as 2 byte wchar*'s. + // Generally you probably want to use Auto, which does the + // right thing 99% of the time. + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public enum CharSet + { + None = 1, // User didn't specify how to marshal strings. + Ansi = 2, // Strings should be marshalled as ANSI 1 byte chars. + Unicode = 3, // Strings should be marshalled as Unicode 2 byte chars. + Auto = 4, // Marshal Strings in the right way for the target system. + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComEventsHelper.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComEventsHelper.cs new file mode 100644 index 0000000000..7af80ff7b2 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComEventsHelper.cs @@ -0,0 +1,201 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +/*============================================================ +** +** +** Purpose: ComEventHelpers APIs allow binding +** managed delegates to COM's connection point based events. +** +**/ +namespace System.Runtime.InteropServices { + // + // #ComEventsFeature + // + // code:#ComEventsFeature defines two public methods allowing to add/remove .NET delegates handling + // events from COM objects. Those methods are defined as part of code:ComEventsHelper static class + // * code:ComEventsHelper.Combine - will create/reuse-an-existing COM event sink and register the + // specified delegate to be raised when corresponding COM event is raised + // * code:ComEventsHelper.Remove + // + // + // To bind an event handler to the COM object you need to provide the following data: + // * rcw - the instance of the COM object you want to bind to + // * iid - Guid of the source interface you want the sink to implement + // * dispid - dispatch identifier of the event on the source interface you are interested in + // * d - delegate to invoked when corresponding COM event is raised. + // + // #ComEventsArchitecture: + // In COM world, events are handled by so-called event sinks. What these are? COM-based Object Models + // (OMs) define "source" interfaces that need to be implemented by the COM clients to receive events. So, + // event sinks are COM objects implementing a source interfaces. Once an event sink is passed to the COM + // server (through a mechanism known as 'binding/advising to connection point'), COM server will be + // calling source interface methods to "fire events" (advising, connection points, firing events etc. - + // is all COM jargon). + // + // There are few interesting obervations about source interfaces. Usually source interfaces are defined + // as 'dispinterface' - meaning that only late-bound invocations on this interface are allowed. Even + // though it is not illegal to use early bound invocations on source interfaces - the practice is + // discouraged because of versioning concerns. + // + // Notice also that each COM server object might define multiple source interfaces and hence have + // multiple connection points (each CP handles exactly one source interface). COM objects that want to + // fire events are required to implement IConnectionPointContainer interface which is used by the COM + // clients to discovery connection poitns - objects implementing IConnectionPoint interface. Once + // connection point is found - clients can bind to it using IConnectionPoint::Advise (see + // code:ComEventsSink.Advise). + // + // The idea behind code:#ComEventsFeature is to write a "universal event sink" COM component that is + // generic enough to handle all late-bound event firings and invoke corresponding COM delegates (through + // reflection). + // + // When delegate is registered (using code:ComEventsHelper.Combine) we will verify we have corresponding + // event sink created and bound. + // + // But what happens when COM events are fired? code:ComEventsSink.Invoke implements IDispatch::Invoke method + // and this is the entry point that is called. Once our event sink is invoked, we need to find the + // corresponding delegate to invoke . We need to match the dispid of the call that is coming in to a + // dispid of .NET delegate that has been registered for this object. Once this is found we do call the + // delegates using reflection (code:ComEventsMethod.Invoke). + // + // #ComEventsArgsMarshalling + // Notice, that we may not have a delegate registered against every method on the source interface. If we + // were to marshal all the input parameters for methods that do not reach user code - we would end up + // generatic RCWs that are not reachable for user code (the inconvenience it might create is there will + // be RCWs that users can not call Marshal.ReleaseComObject on to explicitly manage the lifetime of these + // COM objects). The above behavior was one of the shortcoimings of legacy TLBIMP's implementation of COM + // event sinking. In our code we will not marshal any data if there is no delegate registered to handle + // the event. (code:ComEventsMethod.Invoke) + // + // #ComEventsFinalization: + // Additional area of interest is when COM sink should be unadvised from the connection point. Legacy + // TLBIMP's implementation of COM event sinks will unadvises the sink when corresponding RCW is GCed. + // This is achieved by rooting the event sinks in a finalizable object stored in RCW's property bag + // (using Marshal.SetComObjectData). Hence, once RCW is no longer reachable - the finalizer is called and + // it would unadvise all the event sinks. We are employing the same strategy here. See storing an + // instance in the RCW at code:ComEventsInfo.FromObject and undadvsing the sinks at + // code:ComEventsInfo.~ComEventsInfo + // + // Classes of interest: + // * code:ComEventsHelpers - defines public methods but there are also a number of internal classes that + // implement the actual COM event sink: + // * code:ComEventsInfo - represents a finalizable container for all event sinks for a particular RCW. + // Lifetime of this instance corresponds to the lifetime of the RCW object + // * code:ComEventsSink - represents a single event sink. Maintains an internal pointer to the next + // instance (in a singly linked list). A collection of code:ComEventsSink is stored at + // code:ComEventsInfo._sinks + // * code:ComEventsMethod - represents a single method from the source interface which has .NET delegates + // attached to it. Maintains an internal pointer to the next instance (in a singly linked list). A + // collection of code:ComEventMethod is stored at code:ComEventsSink._methods + // + // #ComEventsRetValIssue: + // Issue: normally, COM events would not return any value. However, it may happen as described in + // http://support.microsoft.com/kb/810228. Such design might represent a problem for us - e.g. what is + // the return value of a chain of delegates - is it the value of the last call in the chain or the the + // first one? As the above KB article indicates, in cases where OM has events returning values, it is + // suggested that people implement their event sink by explicitly implementing the source interface. This + // means that the problem is already quite complex and we should not be dealing with it - see + // code:ComEventsMethod.Invoke + + using System; + using System.Runtime.Remoting; + + /// <summary> + /// The static methods provided in ComEventsHelper allow using .NET delegates to subscribe to events + /// raised COM objects. + /// </summary> + public static class ComEventsHelper { + + /// <summary> + /// Adds a delegate to the invocation list of events originating from the COM object. + /// </summary> + /// <param name="rcw">COM object firing the events the caller would like to respond to</param> + /// <param name="iid">identifier of the source interface used by COM object to fire events</param> + /// <param name="dispid">dispatch identifier of the method on the source interface</param> + /// <param name="d">delegate to invoke when specifed COM event is fired</param> + [System.Security.SecurityCritical] + public static void Combine(object rcw, Guid iid, int dispid, System.Delegate d) { + + rcw = UnwrapIfTransparentProxy(rcw); + + lock (rcw) { + ComEventsInfo eventsInfo = ComEventsInfo.FromObject(rcw); + + ComEventsSink sink = eventsInfo.FindSink(ref iid); + if (sink == null) { + sink = eventsInfo.AddSink(ref iid); + } + + + ComEventsMethod method = sink.FindMethod(dispid); + if (method == null) { + method = sink.AddMethod(dispid); + } + + method.AddDelegate(d); + } + } + + /// <summary> + /// Removes a delegate from the invocation list of events originating from the COM object. + /// </summary> + /// <param name="rcw">COM object the delegate is attached to</param> + /// <param name="iid">identifier of the source interface used by COM object to fire events</param> + /// <param name="dispid">dispatch identifier of the method on the source interface</param> + /// <param name="d">delegate to remove from the invocation list</param> + /// <returns></returns> + [System.Security.SecurityCritical] + public static Delegate Remove(object rcw, Guid iid, int dispid, System.Delegate d) { + + rcw = UnwrapIfTransparentProxy(rcw); + + lock (rcw) { + + ComEventsInfo eventsInfo = ComEventsInfo.Find(rcw); + if (eventsInfo == null) + return null; + ComEventsSink sink = eventsInfo.FindSink(ref iid); + if (sink == null) + return null; + ComEventsMethod method = sink.FindMethod(dispid); + if (method == null) + return null; + + method.RemoveDelegate(d); + + if (method.Empty) { + // removed the last event handler for this dispid - need to remove dispid handler + method = sink.RemoveMethod(method); + } + if (method == null) { + // removed last dispid handler for this sink - need to remove the sink + sink = eventsInfo.RemoveSink(sink); + } + if (sink == null) { + // removed last sink for this rcw - need to remove all traces of event info + Marshal.SetComObjectData(rcw, typeof(ComEventsInfo), null); + GC.SuppressFinalize(eventsInfo); + } + + return d; + } + } + + [System.Security.SecurityCritical] + internal static object UnwrapIfTransparentProxy(object rcw) { +#if FEATURE_REMOTING + if (RemotingServices.IsTransparentProxy(rcw)) { + IntPtr punk = Marshal.GetIUnknownForObject(rcw); + try { + rcw = Marshal.GetObjectForIUnknown(punk); + } finally { + Marshal.Release(punk); + } + } +#endif + return rcw; + } + } + +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComEventsInfo.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComEventsInfo.cs new file mode 100644 index 0000000000..b91253d9b5 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComEventsInfo.cs @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +/*============================================================ +** +** +** Purpose: part of ComEventHelpers APIs which allow binding +** managed delegates to COM's connection point based events. +** +**/ + +namespace System.Runtime.InteropServices { + + using System; + using ComTypes = System.Runtime.InteropServices.ComTypes; + + // see code:ComEventsHelper#ComEventsArchitecture + [System.Security.SecurityCritical] + internal class ComEventsInfo { + + +#region fields + + private ComEventsSink _sinks; + private object _rcw; + +#endregion + + +#region ctor/dtor + + ComEventsInfo(object rcw) { + _rcw = rcw; + } + + [System.Security.SecuritySafeCritical] + ~ComEventsInfo() { + // see code:ComEventsHelper#ComEventsFinalization + _sinks = ComEventsSink.RemoveAll(_sinks); + } + +#endregion + + +#region static methods + + [System.Security.SecurityCritical] + internal static ComEventsInfo Find(object rcw) { + return (ComEventsInfo)Marshal.GetComObjectData(rcw, typeof(ComEventsInfo)); + } + + // it is caller's responsibility to call this method under lock(rcw) + [System.Security.SecurityCritical] + internal static ComEventsInfo FromObject(object rcw) { + ComEventsInfo eventsInfo = Find(rcw); + if (eventsInfo == null) { + eventsInfo = new ComEventsInfo(rcw); + Marshal.SetComObjectData(rcw, typeof(ComEventsInfo), eventsInfo); + } + return eventsInfo; + } + +#endregion + + +#region internal methods + + internal ComEventsSink FindSink(ref Guid iid) { + return ComEventsSink.Find(_sinks, ref iid); + } + + // it is caller's responsibility to call this method under lock(rcw) + internal ComEventsSink AddSink(ref Guid iid) { + ComEventsSink sink = new ComEventsSink(_rcw, iid); + _sinks = ComEventsSink.Add(_sinks, sink); + + return _sinks; + } + + // it is caller's responsibility to call this method under lock(rcw) + [System.Security.SecurityCritical] + internal ComEventsSink RemoveSink(ComEventsSink sink) { + _sinks = ComEventsSink.Remove(_sinks, sink); + return _sinks; + } + +#endregion + + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComEventsMethod.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComEventsMethod.cs new file mode 100644 index 0000000000..5b851f3dae --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComEventsMethod.cs @@ -0,0 +1,245 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +/*============================================================ +** +** +** Purpose: part of ComEventHelpers APIs which allow binding +** managed delegates to COM's connection point based events. +** +**/ +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Reflection; + + +namespace System.Runtime.InteropServices { + + // see code:ComEventsHelper#ComEventsArchitecture + internal class ComEventsMethod { + + // This delegate wrapper class handles dynamic invocation of delegates. The reason for the wrapper's + // existence is that under certain circumstances we need to coerce arguments to types expected by the + // delegates signature. Normally, reflection (Delegate.DynamicInvoke) handles types coercion + // correctly but one known case is when the expected signature is 'ref Enum' - in this case + // reflection by design does not do the coercion. Since we need to be compatible with COM interop + // handling of this scenario - we are pre-processing delegate's signature by looking for 'ref enums' + // and cache the types required for such coercion. + internal class DelegateWrapper { + private Delegate _d; + + private bool _once = false; + private int _expectedParamsCount; + private Type[] _cachedTargetTypes; + + public DelegateWrapper(Delegate d) { + _d = d; + } + + public Delegate Delegate { + get { return _d; } + set { _d = value; } + } + + public object Invoke(object[] args) { + if (_d == null) + return null; + + if (_once == false) { + PreProcessSignature(); + _once = true; + } + + if (_cachedTargetTypes != null && _expectedParamsCount == args.Length) { + for (int i = 0; i < _expectedParamsCount; i++) { + if (_cachedTargetTypes[i] != null) { + args[i] = Enum.ToObject(_cachedTargetTypes[i], args[i]); + } + } + } + + return _d.DynamicInvoke(args); + } + + private void PreProcessSignature() { + ParameterInfo[] parameters = _d.Method.GetParameters(); + _expectedParamsCount = parameters.Length; + + Type[] enumTypes = new Type[_expectedParamsCount]; + + bool needToHandleCoercion = false; + + for (int i = 0; i < _expectedParamsCount; i++) { + ParameterInfo pi = parameters[i]; + // recognize only 'ref Enum' signatures and cache + // both enum type and the underlying type. + if (pi.ParameterType.IsByRef && + pi.ParameterType.HasElementType && + pi.ParameterType.GetElementType().IsEnum) { + + needToHandleCoercion = true; + enumTypes[i] = pi.ParameterType.GetElementType(); + } + } + + if (needToHandleCoercion == true) { + _cachedTargetTypes = enumTypes; + } + } + } + + #region private fields + + /// <summary> + /// Invoking ComEventsMethod means invoking a multi-cast delegate attached to it. + /// Since multicast delegate's built-in chaining supports only chaining instances of the same type, + /// we need to complement this design by using an explicit linked list data structure. + /// </summary> + private DelegateWrapper [] _delegateWrappers; + + private int _dispid; + private ComEventsMethod _next; + + #endregion + + + #region ctor + + internal ComEventsMethod(int dispid) { + _delegateWrappers = null; + _dispid = dispid; + } + + #endregion + + + #region static internal methods + + internal static ComEventsMethod Find(ComEventsMethod methods, int dispid) { + while (methods != null && methods._dispid != dispid) { + methods = methods._next; + } + return methods; + } + + internal static ComEventsMethod Add(ComEventsMethod methods, ComEventsMethod method) { + method._next = methods; + return method; + } + + internal static ComEventsMethod Remove(ComEventsMethod methods, ComEventsMethod method) { + if (methods == method) { + methods = methods._next; + } else { + ComEventsMethod current = methods; + while (current != null && current._next != method) + current = current._next; + if (current != null) + current._next = method._next; + } + + return methods; + } + + #endregion + + + #region public properties / methods + + internal int DispId { + get { return _dispid; } + } + + internal bool Empty { + get { return _delegateWrappers == null || _delegateWrappers.Length == 0; } + } + + internal void AddDelegate(Delegate d) { + int count = 0; + if (_delegateWrappers != null) { + count = _delegateWrappers.Length; + } + + for (int i = 0; i < count; i++) { + if (_delegateWrappers[i].Delegate.GetType() == d.GetType()) { + _delegateWrappers[i].Delegate = Delegate.Combine(_delegateWrappers[i].Delegate, d); + return; + } + } + + DelegateWrapper [] newDelegateWrappers = new DelegateWrapper[count + 1]; + if (count > 0) { + _delegateWrappers.CopyTo(newDelegateWrappers, 0); + } + + DelegateWrapper wrapper = new DelegateWrapper(d); + newDelegateWrappers[count] = wrapper; + + _delegateWrappers = newDelegateWrappers; + } + + internal void RemoveDelegate(Delegate d) { + + int count = _delegateWrappers.Length; + int removeIdx = -1; + + for (int i = 0; i < count; i++) { + if (_delegateWrappers[i].Delegate.GetType() == d.GetType()) { + removeIdx = i; + break; + } + } + + if (removeIdx < 0) + return; + + Delegate newDelegate = Delegate.Remove(_delegateWrappers[removeIdx].Delegate, d); + if (newDelegate != null) { + _delegateWrappers[removeIdx].Delegate = newDelegate; + return; + } + + // now remove the found entry from the _delegates array + + if (count == 1) { + _delegateWrappers = null; + return; + } + + DelegateWrapper [] newDelegateWrappers = new DelegateWrapper[count - 1]; + int j = 0; + while (j < removeIdx) { + newDelegateWrappers[j] = _delegateWrappers[j]; + j++; + } + while (j < count-1) { + newDelegateWrappers[j] = _delegateWrappers[j + 1]; + j++; + } + + _delegateWrappers = newDelegateWrappers; + } + + internal object Invoke(object[] args) { + BCLDebug.Assert(Empty == false, "event sink is executed but delegates list is empty"); + + // Issue: see code:ComEventsHelper#ComEventsRetValIssue + object result = null; + DelegateWrapper[] invocationList = _delegateWrappers; + foreach (DelegateWrapper wrapper in invocationList) { + if (wrapper == null || wrapper.Delegate == null) + continue; + + result = wrapper.Invoke(args); + } + + return result; + } + + #endregion + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComEventsSink.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComEventsSink.cs new file mode 100644 index 0000000000..1b8f965faf --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComEventsSink.cs @@ -0,0 +1,285 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +/*============================================================ +** +** +** Purpose: part of ComEventHelpers APIs which allow binding +** managed delegates to COM's connection point based events. +** +**/ + +namespace System.Runtime.InteropServices { + using System; + using System.Diagnostics; + + // see code:ComEventsHelper#ComEventsArchitecture + [System.Security.SecurityCritical] + internal class ComEventsSink : NativeMethods.IDispatch, ICustomQueryInterface + { +#region private fields + + private Guid _iidSourceItf; + private ComTypes.IConnectionPoint _connectionPoint; + private int _cookie; + private ComEventsMethod _methods; + private ComEventsSink _next; + +#endregion + + +#region ctor + + internal ComEventsSink(object rcw, Guid iid) { + _iidSourceItf = iid; + this.Advise(rcw); + } + +#endregion + + +#region static members + + internal static ComEventsSink Find(ComEventsSink sinks, ref Guid iid) { + + ComEventsSink sink = sinks; + while (sink != null && sink._iidSourceItf != iid) { + sink = sink._next; + } + + return sink; + } + + internal static ComEventsSink Add(ComEventsSink sinks, ComEventsSink sink) { + sink._next = sinks; + return sink; + } + + [System.Security.SecurityCritical] + internal static ComEventsSink RemoveAll(ComEventsSink sinks) { + while (sinks != null) { + sinks.Unadvise(); + sinks = sinks._next; + } + + return null; + } + + [System.Security.SecurityCritical] + internal static ComEventsSink Remove(ComEventsSink sinks, ComEventsSink sink) { + BCLDebug.Assert(sinks != null, "removing event sink from empty sinks collection"); + BCLDebug.Assert(sink != null, "specify event sink is null"); + + if (sink == sinks) { + sinks = sinks._next; + } else { + ComEventsSink current = sinks; + while (current != null && current._next != sink) + current = current._next; + + if (current != null) { + current._next = sink._next; + } + } + + sink.Unadvise(); + + return sinks; + } + +#endregion + + +#region public methods + + public ComEventsMethod RemoveMethod(ComEventsMethod method) { + _methods = ComEventsMethod.Remove(_methods, method); + return _methods; + } + + public ComEventsMethod FindMethod(int dispid) { + return ComEventsMethod.Find(_methods, dispid); + } + + public ComEventsMethod AddMethod(int dispid) { + ComEventsMethod method = new ComEventsMethod(dispid); + _methods = ComEventsMethod.Add(_methods, method); + return method; + } + +#endregion + + +#region IDispatch Members + + [System.Security.SecurityCritical] + void NativeMethods.IDispatch.GetTypeInfoCount(out uint pctinfo) { + pctinfo = 0; + } + + [System.Security.SecurityCritical] + void NativeMethods.IDispatch.GetTypeInfo(uint iTInfo, int lcid, out IntPtr info) { + throw new NotImplementedException(); + } + + [System.Security.SecurityCritical] + void NativeMethods.IDispatch.GetIDsOfNames(ref Guid iid, string[] names, uint cNames, int lcid, int[] rgDispId) { + throw new NotImplementedException(); + } + + private const VarEnum VT_BYREF_VARIANT = VarEnum.VT_BYREF | VarEnum.VT_VARIANT; + private const VarEnum VT_TYPEMASK = (VarEnum) 0x0fff; + private const VarEnum VT_BYREF_TYPEMASK = VT_TYPEMASK | VarEnum.VT_BYREF; + + private static unsafe Variant *GetVariant(Variant *pSrc) + { + if (pSrc->VariantType == VT_BYREF_VARIANT) + { + // For VB6 compatibility reasons, if the VARIANT is a VT_BYREF | VT_VARIANT that + // contains another VARIANT with VT_BYREF | VT_VARIANT, then we need to extract the + // inner VARIANT and use it instead of the outer one. Note that if the inner VARIANT + // is VT_BYREF | VT_VARIANT | VT_ARRAY, it will pass the below test too. + Variant *pByRefVariant = (Variant *)pSrc->AsByRefVariant; + if ((pByRefVariant->VariantType & VT_BYREF_TYPEMASK) == VT_BYREF_VARIANT) + return (Variant *)pByRefVariant; + } + + return pSrc; + } + + [System.Security.SecurityCritical] + unsafe void NativeMethods.IDispatch.Invoke( + int dispid, + ref Guid riid, + int lcid, + ComTypes.INVOKEKIND wFlags, + ref ComTypes.DISPPARAMS pDispParams, + IntPtr pvarResult, + IntPtr pExcepInfo, + IntPtr puArgErr) { + + ComEventsMethod method = FindMethod(dispid); + if (method == null) + return; + + // notice the unsafe pointers we are using. This is to avoid unnecessary + // arguments marshalling. see code:ComEventsHelper#ComEventsArgsMarshalling + + object [] args = new object[pDispParams.cArgs]; + int [] byrefsMap = new int[pDispParams.cArgs]; + bool [] usedArgs = new bool[pDispParams.cArgs]; + + Variant* pvars = (Variant*)pDispParams.rgvarg; + int* pNamedArgs = (int*)pDispParams.rgdispidNamedArgs; + + // copy the named args (positional) as specified + int i; + int pos; + for (i = 0; i < pDispParams.cNamedArgs; i++) { + pos = pNamedArgs[i]; + + Variant* pvar = GetVariant(&pvars[i]); + args[pos] = pvar->ToObject(); + usedArgs[pos] = true; + + if (pvar->IsByRef) { + byrefsMap[pos] = i; + } else { + byrefsMap[pos] = -1; + } + } + + // copy the rest of the arguments in the reverse order + pos = 0; + for (; i < pDispParams.cArgs; i++) { + // find the next unassigned argument + while (usedArgs[pos]) { + ++pos; + } + + Variant* pvar = GetVariant(&pvars[pDispParams.cArgs - 1 - i]); + args[pos] = pvar->ToObject(); + + if (pvar->IsByRef) + byrefsMap[pos] = pDispParams.cArgs - 1 - i; + else + byrefsMap[pos] = -1; + + pos++; + } + + // Do the actual delegate invocation + object result; + result = method.Invoke(args); + + // convert result to VARIANT + if (pvarResult != IntPtr.Zero) { + Marshal.GetNativeVariantForObject(result, pvarResult); + } + + // Now we need to marshal all the byrefs back + for (i = 0; i < pDispParams.cArgs; i++) { + int idxToPos = byrefsMap[i]; + if (idxToPos == -1) + continue; + + GetVariant(&pvars[idxToPos])->CopyFromIndirect(args[i]); + } + } + +#endregion + + static Guid IID_IManagedObject = new Guid("{C3FCC19E-A970-11D2-8B5A-00A0C9B7C9C4}"); + + [System.Security.SecurityCritical] + CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out IntPtr ppv) { + ppv = IntPtr.Zero; + if (iid == this._iidSourceItf || iid == typeof(NativeMethods.IDispatch).GUID) { + ppv = Marshal.GetComInterfaceForObject(this, typeof(NativeMethods.IDispatch), CustomQueryInterfaceMode.Ignore); + return CustomQueryInterfaceResult.Handled; + } + else if (iid == IID_IManagedObject) + { + return CustomQueryInterfaceResult.Failed; + } + + return CustomQueryInterfaceResult.NotHandled; + } + +#region private methods + + + private void Advise(object rcw) { + BCLDebug.Assert(_connectionPoint == null, "comevent sink is already advised"); + + ComTypes.IConnectionPointContainer cpc = (ComTypes.IConnectionPointContainer)rcw; + ComTypes.IConnectionPoint cp; + cpc.FindConnectionPoint(ref _iidSourceItf, out cp); + + object sinkObject = this; + + cp.Advise(sinkObject, out _cookie); + + _connectionPoint = cp; + } + + [System.Security.SecurityCritical] + private void Unadvise() { + BCLDebug.Assert(_connectionPoint != null, "can not unadvise from empty connection point"); + + try { + _connectionPoint.Unadvise(_cookie); + Marshal.ReleaseComObject(_connectionPoint); + } catch (System.Exception) { + // swallow all exceptions on unadvise + // the host may not be available at this point + } finally { + _connectionPoint = null; + } + + } + +#endregion + }; +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComMemberType.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComMemberType.cs new file mode 100644 index 0000000000..748b9d11ba --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComMemberType.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +namespace System.Runtime.InteropServices { + + using System; + + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public enum ComMemberType + { + Method = 0, + PropGet = 1, + PropSet = 2 + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IBindCtx.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IBindCtx.cs new file mode 100644 index 0000000000..b62cf29eea --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IBindCtx.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IBindCtx interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [StructLayout(LayoutKind.Sequential)] + + public struct BIND_OPTS + { + public int cbStruct; + public int grfFlags; + public int grfMode; + public int dwTickCountDeadline; + } + + [Guid("0000000e-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IBindCtx + { + void RegisterObjectBound([MarshalAs(UnmanagedType.Interface)] Object punk); + void RevokeObjectBound([MarshalAs(UnmanagedType.Interface)] Object punk); + void ReleaseBoundObjects(); + void SetBindOptions([In()] ref BIND_OPTS pbindopts); + void GetBindOptions(ref BIND_OPTS pbindopts); + void GetRunningObjectTable(out IRunningObjectTable pprot); + void RegisterObjectParam([MarshalAs(UnmanagedType.LPWStr)] String pszKey, [MarshalAs(UnmanagedType.Interface)] Object punk); + void GetObjectParam([MarshalAs(UnmanagedType.LPWStr)] String pszKey, [MarshalAs(UnmanagedType.Interface)] out Object ppunk); + void EnumObjectParam(out IEnumString ppenum); + [PreserveSig] + int RevokeObjectParam([MarshalAs(UnmanagedType.LPWStr)] String pszKey); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IConnectionPoint.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IConnectionPoint.cs new file mode 100644 index 0000000000..f6c1a9db90 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IConnectionPoint.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IConnectionPoint interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("B196B286-BAB4-101A-B69C-00AA00341D07")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IConnectionPoint + { + void GetConnectionInterface(out Guid pIID); + void GetConnectionPointContainer(out IConnectionPointContainer ppCPC); + void Advise([MarshalAs(UnmanagedType.Interface)] Object pUnkSink, out int pdwCookie); + void Unadvise(int dwCookie); + void EnumConnections(out IEnumConnections ppEnum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IConnectionPointContainer.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IConnectionPointContainer.cs new file mode 100644 index 0000000000..5ad02da7e2 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IConnectionPointContainer.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IConnectionPointContainer interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("B196B284-BAB4-101A-B69C-00AA00341D07")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IConnectionPointContainer + { + void EnumConnectionPoints(out IEnumConnectionPoints ppEnum); + void FindConnectionPoint([In] ref Guid riid, out IConnectionPoint ppCP); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumConnectionPoints.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumConnectionPoints.cs new file mode 100644 index 0000000000..8631e287ad --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumConnectionPoints.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IEnumConnectionPoints interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("B196B285-BAB4-101A-B69C-00AA00341D07")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IEnumConnectionPoints + { + [PreserveSig] + int Next(int celt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Out] IConnectionPoint[] rgelt, IntPtr pceltFetched); + [PreserveSig] + int Skip(int celt); + void Reset(); + void Clone(out IEnumConnectionPoints ppenum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumConnections.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumConnections.cs new file mode 100644 index 0000000000..91db513494 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumConnections.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IEnumConnections interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct CONNECTDATA + { + [MarshalAs(UnmanagedType.Interface)] + public Object pUnk; + public int dwCookie; + } + + [Guid("B196B287-BAB4-101A-B69C-00AA00341D07")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IEnumConnections + { + [PreserveSig] + int Next(int celt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Out] CONNECTDATA[] rgelt, IntPtr pceltFetched); + [PreserveSig] + int Skip(int celt); + void Reset(); + void Clone(out IEnumConnections ppenum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumMoniker.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumMoniker.cs new file mode 100644 index 0000000000..a01895ec4d --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumMoniker.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IEnumMoniker interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("00000102-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IEnumMoniker + { + [PreserveSig] + int Next(int celt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Out] IMoniker[] rgelt, IntPtr pceltFetched); + [PreserveSig] + int Skip(int celt); + void Reset(); + void Clone(out IEnumMoniker ppenum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumString.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumString.cs new file mode 100644 index 0000000000..efdc46be35 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumString.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IEnumString interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("00000101-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IEnumString + { + [PreserveSig] + int Next(int celt, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 0), Out] String[] rgelt, IntPtr pceltFetched); + [PreserveSig] + int Skip(int celt); + void Reset(); + void Clone(out IEnumString ppenum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumVARIANT.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumVARIANT.cs new file mode 100644 index 0000000000..e4f527470c --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumVARIANT.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IEnumVARIANT interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("00020404-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IEnumVARIANT + { + [PreserveSig] + int Next(int celt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0), Out] object[] rgVar, IntPtr pceltFetched); + + [PreserveSig] + int Skip(int celt); + + [PreserveSig] + int Reset(); + + IEnumVARIANT Clone(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumerable.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumerable.cs new file mode 100644 index 0000000000..96f05696a3 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumerable.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*========================================================================== +** +** Interface: IEnumerable +** +** +** Purpose: +** This interface is redefined here since the original IEnumerable interface +** has all its methods marked as ecall's since it is a managed standard +** interface. This interface is used from within the runtime to make a call +** on the COM server directly when it implements the IEnumerable interface. +** +** +==========================================================================*/ +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")] + internal interface IEnumerable + { + [DispId(-4)] + System.Collections.IEnumerator GetEnumerator(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumerator.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumerator.cs new file mode 100644 index 0000000000..58084f16c2 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IEnumerator.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*========================================================================== +** +** Interface: IEnumerator +** +** +** Purpose: +** This interface is redefined here since the original IEnumerator interface +** has all its methods marked as ecall's since it is a managed standard +** interface. This interface is used from within the runtime to make a call +** on the COM server directly when it implements the IEnumerator interface. +** +** +==========================================================================*/ +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")] + internal interface IEnumerator + { + bool MoveNext(); + + Object Current + { + get; + } + + void Reset(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IExpando.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IExpando.cs new file mode 100644 index 0000000000..7cafcacc34 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IExpando.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*========================================================================== +** +** Interface: IExpando +** +** +** Purpose: +** This interface is redefined here since the original IExpando interface +** has all its methods marked as ecall's since it is a managed standard +** interface. This interface is used from within the runtime to make a call +** on the COM server directly when it implements the IExpando interface. +** +** +==========================================================================*/ +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + using System.Reflection; + + [Guid("AFBF15E6-C37C-11d2-B88E-00A0C9B471B8")] + internal interface IExpando : IReflect + { + FieldInfo AddField(String name); + PropertyInfo AddProperty(String name); + MethodInfo AddMethod(String name, Delegate method); + void RemoveMember(MemberInfo m); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IMoniker.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IMoniker.cs new file mode 100644 index 0000000000..a42d7b04ac --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IMoniker.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IMoniker interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [StructLayout(LayoutKind.Sequential)] + + public struct FILETIME + { + public int dwLowDateTime; + public int dwHighDateTime; + } + + [Guid("0000000f-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IMoniker + { + // IPersist portion + void GetClassID(out Guid pClassID); + + // IPersistStream portion + [PreserveSig] + int IsDirty(); + void Load(IStream pStm); + void Save(IStream pStm, [MarshalAs(UnmanagedType.Bool)] bool fClearDirty); + void GetSizeMax(out Int64 pcbSize); + + // IMoniker portion + void BindToObject(IBindCtx pbc, IMoniker pmkToLeft, [In()] ref Guid riidResult, [MarshalAs(UnmanagedType.Interface)] out Object ppvResult); + void BindToStorage(IBindCtx pbc, IMoniker pmkToLeft, [In()] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out Object ppvObj); + void Reduce(IBindCtx pbc, int dwReduceHowFar, ref IMoniker ppmkToLeft, out IMoniker ppmkReduced); + void ComposeWith(IMoniker pmkRight, [MarshalAs(UnmanagedType.Bool)] bool fOnlyIfNotGeneric, out IMoniker ppmkComposite); + void Enum([MarshalAs(UnmanagedType.Bool)] bool fForward, out IEnumMoniker ppenumMoniker); + [PreserveSig] + int IsEqual(IMoniker pmkOtherMoniker); + void Hash(out int pdwHash); + [PreserveSig] + int IsRunning(IBindCtx pbc, IMoniker pmkToLeft, IMoniker pmkNewlyRunning); + void GetTimeOfLastChange(IBindCtx pbc, IMoniker pmkToLeft, out FILETIME pFileTime); + void Inverse(out IMoniker ppmk); + void CommonPrefixWith(IMoniker pmkOther, out IMoniker ppmkPrefix); + void RelativePathTo(IMoniker pmkOther, out IMoniker ppmkRelPath); + void GetDisplayName(IBindCtx pbc, IMoniker pmkToLeft, [MarshalAs(UnmanagedType.LPWStr)] out String ppszDisplayName); + void ParseDisplayName(IBindCtx pbc, IMoniker pmkToLeft, [MarshalAs(UnmanagedType.LPWStr)] String pszDisplayName, out int pchEaten, out IMoniker ppmkOut); + [PreserveSig] + int IsSystemMoniker(out int pdwMksys); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IPersistFile.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IPersistFile.cs new file mode 100644 index 0000000000..657ab66103 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IPersistFile.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IPersistFile interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("0000010b-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IPersistFile + { + // IPersist portion + void GetClassID(out Guid pClassID); + + // IPersistFile portion + [PreserveSig] + int IsDirty(); + void Load([MarshalAs(UnmanagedType.LPWStr)] String pszFileName, int dwMode); + void Save([MarshalAs(UnmanagedType.LPWStr)] String pszFileName, [MarshalAs(UnmanagedType.Bool)] bool fRemember); + void SaveCompleted([MarshalAs(UnmanagedType.LPWStr)] String pszFileName); + void GetCurFile([MarshalAs(UnmanagedType.LPWStr)] out String ppszFileName); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IReflect.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IReflect.cs new file mode 100644 index 0000000000..0e0e36d20f --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IReflect.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*========================================================================== +** +** Interface: IReflect +** +** +** Purpose: +** This interface is redefined here since the original IReflect interface +** has all its methods marked as ecall's since it is a managed standard +** interface. This interface is used from within the runtime to make a call +** on the COM server directly when it implements the IReflect interface. +** +** +==========================================================================*/ +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + using System.Reflection; + using CultureInfo = System.Globalization.CultureInfo; + + [Guid("AFBF15E5-C37C-11d2-B88E-00A0C9B471B8")] + internal interface IReflect + { + MethodInfo GetMethod(String name,BindingFlags bindingAttr,Binder binder, + Type[] types,ParameterModifier[] modifiers); + + MethodInfo GetMethod(String name,BindingFlags bindingAttr); + + MethodInfo[] GetMethods( + BindingFlags bindingAttr); + + FieldInfo GetField( + String name, + BindingFlags bindingAttr); + + FieldInfo[] GetFields( + BindingFlags bindingAttr); + + PropertyInfo GetProperty( + String name, + BindingFlags bindingAttr); + + PropertyInfo GetProperty( + String name, + BindingFlags bindingAttr, + Binder binder, + Type returnType, + Type[] types, + ParameterModifier[] modifiers); + + PropertyInfo[] GetProperties( + BindingFlags bindingAttr); + + MemberInfo[] GetMember( + String name, + BindingFlags bindingAttr); + + MemberInfo[] GetMembers( + BindingFlags bindingAttr); + + Object InvokeMember( + String name, + BindingFlags invokeAttr, + Binder binder, + Object target, + Object[] args, + ParameterModifier[] modifiers, + CultureInfo culture, + String[] namedParameters); + + Type UnderlyingSystemType + { + get; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IRunningObjectTable.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IRunningObjectTable.cs new file mode 100644 index 0000000000..1155eecd4f --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IRunningObjectTable.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IRunningObjectTable interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("00000010-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IRunningObjectTable + { + int Register(int grfFlags, [MarshalAs(UnmanagedType.Interface)] Object punkObject, IMoniker pmkObjectName); + void Revoke(int dwRegister); + [PreserveSig] + int IsRunning(IMoniker pmkObjectName); + [PreserveSig] + int GetObject(IMoniker pmkObjectName, [MarshalAs(UnmanagedType.Interface)] out Object ppunkObject); + void NoteChangeTime(int dwRegister, ref FILETIME pfiletime); + [PreserveSig] + int GetTimeOfLastChange(IMoniker pmkObjectName, out FILETIME pfiletime); + void EnumRunning(out IEnumMoniker ppenumMoniker); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IStream.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IStream.cs new file mode 100644 index 0000000000..4a9904b6c5 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/IStream.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: IStream interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct STATSTG + { + public String pwcsName; + public int type; + public Int64 cbSize; + public FILETIME mtime; + public FILETIME ctime; + public FILETIME atime; + public int grfMode; + public int grfLocksSupported; + public Guid clsid; + public int grfStateBits; + public int reserved; + } + + [Guid("0000000c-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IStream + { + // ISequentialStream portion + void Read([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] Byte[] pv, int cb, IntPtr pcbRead); + void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] Byte[] pv, int cb, IntPtr pcbWritten); + + // IStream portion + void Seek(Int64 dlibMove, int dwOrigin, IntPtr plibNewPosition); + void SetSize(Int64 libNewSize); + void CopyTo(IStream pstm, Int64 cb, IntPtr pcbRead, IntPtr pcbWritten); + void Commit(int grfCommitFlags); + void Revert(); + void LockRegion(Int64 libOffset, Int64 cb, int dwLockType); + void UnlockRegion(Int64 libOffset, Int64 cb, int dwLockType); + void Stat(out STATSTG pstatstg, int grfStatFlag); + void Clone(out IStream ppstm); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeComp.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeComp.cs new file mode 100644 index 0000000000..f73dec1b66 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeComp.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: ITypeComp interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Serializable] + public enum DESCKIND + { + DESCKIND_NONE = 0, + DESCKIND_FUNCDESC = DESCKIND_NONE + 1, + DESCKIND_VARDESC = DESCKIND_FUNCDESC + 1, + DESCKIND_TYPECOMP = DESCKIND_VARDESC + 1, + DESCKIND_IMPLICITAPPOBJ = DESCKIND_TYPECOMP + 1, + DESCKIND_MAX = DESCKIND_IMPLICITAPPOBJ + 1 + } + + [StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)] + + public struct BINDPTR + { + [FieldOffset(0)] + public IntPtr lpfuncdesc; + [FieldOffset(0)] + public IntPtr lpvardesc; + [FieldOffset(0)] + public IntPtr lptcomp; + } + + [Guid("00020403-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ITypeComp + { + void Bind([MarshalAs(UnmanagedType.LPWStr)] String szName, int lHashVal, Int16 wFlags, out ITypeInfo ppTInfo, out DESCKIND pDescKind, out BINDPTR pBindPtr); + void BindType([MarshalAs(UnmanagedType.LPWStr)] String szName, int lHashVal, out ITypeInfo ppTInfo, out ITypeComp ppTComp); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeInfo.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeInfo.cs new file mode 100644 index 0000000000..ccd4576910 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeInfo.cs @@ -0,0 +1,334 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: ITypeInfo interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Serializable] + public enum TYPEKIND + { + TKIND_ENUM = 0, + TKIND_RECORD = TKIND_ENUM + 1, + TKIND_MODULE = TKIND_RECORD + 1, + TKIND_INTERFACE = TKIND_MODULE + 1, + TKIND_DISPATCH = TKIND_INTERFACE + 1, + TKIND_COCLASS = TKIND_DISPATCH + 1, + TKIND_ALIAS = TKIND_COCLASS + 1, + TKIND_UNION = TKIND_ALIAS + 1, + TKIND_MAX = TKIND_UNION + 1 + } + +[Serializable] +[Flags()] + public enum TYPEFLAGS : short + { + TYPEFLAG_FAPPOBJECT = 0x1, + TYPEFLAG_FCANCREATE = 0x2, + TYPEFLAG_FLICENSED = 0x4, + TYPEFLAG_FPREDECLID = 0x8, + TYPEFLAG_FHIDDEN = 0x10, + TYPEFLAG_FCONTROL = 0x20, + TYPEFLAG_FDUAL = 0x40, + TYPEFLAG_FNONEXTENSIBLE = 0x80, + TYPEFLAG_FOLEAUTOMATION = 0x100, + TYPEFLAG_FRESTRICTED = 0x200, + TYPEFLAG_FAGGREGATABLE = 0x400, + TYPEFLAG_FREPLACEABLE = 0x800, + TYPEFLAG_FDISPATCHABLE = 0x1000, + TYPEFLAG_FREVERSEBIND = 0x2000, + TYPEFLAG_FPROXY = 0x4000 + } + +[Serializable] +[Flags()] + public enum IMPLTYPEFLAGS + { + IMPLTYPEFLAG_FDEFAULT = 0x1, + IMPLTYPEFLAG_FSOURCE = 0x2, + IMPLTYPEFLAG_FRESTRICTED = 0x4, + IMPLTYPEFLAG_FDEFAULTVTABLE = 0x8, + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct TYPEATTR + { + // Constant used with the memid fields. + public const int MEMBER_ID_NIL = unchecked((int)0xFFFFFFFF); + + // Actual fields of the TypeAttr struct. + public Guid guid; + public Int32 lcid; + public Int32 dwReserved; + public Int32 memidConstructor; + public Int32 memidDestructor; + public IntPtr lpstrSchema; + public Int32 cbSizeInstance; + public TYPEKIND typekind; + public Int16 cFuncs; + public Int16 cVars; + public Int16 cImplTypes; + public Int16 cbSizeVft; + public Int16 cbAlignment; + public TYPEFLAGS wTypeFlags; + public Int16 wMajorVerNum; + public Int16 wMinorVerNum; + public TYPEDESC tdescAlias; + public IDLDESC idldescType; + } + + [StructLayout(LayoutKind.Sequential)] + + public struct FUNCDESC + { + public int memid; //MEMBERID memid; + public IntPtr lprgscode; // /* [size_is(cScodes)] */ SCODE RPC_FAR *lprgscode; + public IntPtr lprgelemdescParam; // /* [size_is(cParams)] */ ELEMDESC __RPC_FAR *lprgelemdescParam; + public FUNCKIND funckind; //FUNCKIND funckind; + public INVOKEKIND invkind; //INVOKEKIND invkind; + public CALLCONV callconv; //CALLCONV callconv; + public Int16 cParams; //short cParams; + public Int16 cParamsOpt; //short cParamsOpt; + public Int16 oVft; //short oVft; + public Int16 cScodes; //short cScodes; + public ELEMDESC elemdescFunc; //ELEMDESC elemdescFunc; + public Int16 wFuncFlags; //WORD wFuncFlags; + } + +[Serializable] +[Flags()] + public enum IDLFLAG : short + { + IDLFLAG_NONE = PARAMFLAG.PARAMFLAG_NONE, + IDLFLAG_FIN = PARAMFLAG.PARAMFLAG_FIN, + IDLFLAG_FOUT = PARAMFLAG.PARAMFLAG_FOUT, + IDLFLAG_FLCID = PARAMFLAG.PARAMFLAG_FLCID, + IDLFLAG_FRETVAL = PARAMFLAG.PARAMFLAG_FRETVAL + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct IDLDESC + { + public IntPtr dwReserved; + public IDLFLAG wIDLFlags; + } + +[Serializable] +[Flags()] + public enum PARAMFLAG :short + { + PARAMFLAG_NONE = 0, + PARAMFLAG_FIN = 0x1, + PARAMFLAG_FOUT = 0x2, + PARAMFLAG_FLCID = 0x4, + PARAMFLAG_FRETVAL = 0x8, + PARAMFLAG_FOPT = 0x10, + PARAMFLAG_FHASDEFAULT = 0x20, + PARAMFLAG_FHASCUSTDATA = 0x40 + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct PARAMDESC + { + public IntPtr lpVarValue; + public PARAMFLAG wParamFlags; + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct TYPEDESC + { + public IntPtr lpValue; + public Int16 vt; + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct ELEMDESC + { + public TYPEDESC tdesc; + + [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)] + + public struct DESCUNION + { + [FieldOffset(0)] + public IDLDESC idldesc; + [FieldOffset(0)] + public PARAMDESC paramdesc; + }; + public DESCUNION desc; + } + + [Serializable] + public enum VARKIND : int + { + VAR_PERINSTANCE = 0x0, + VAR_STATIC = 0x1, + VAR_CONST = 0x2, + VAR_DISPATCH = 0x3 + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct VARDESC + { + public int memid; + public String lpstrSchema; + + [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)] + + public struct DESCUNION + { + [FieldOffset(0)] + public int oInst; + [FieldOffset(0)] + public IntPtr lpvarValue; + }; + + public DESCUNION desc; + + public ELEMDESC elemdescVar; + public short wVarFlags; + public VARKIND varkind; + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct DISPPARAMS + { + public IntPtr rgvarg; + public IntPtr rgdispidNamedArgs; + public int cArgs; + public int cNamedArgs; + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct EXCEPINFO + { + public Int16 wCode; + public Int16 wReserved; + [MarshalAs(UnmanagedType.BStr)] public String bstrSource; + [MarshalAs(UnmanagedType.BStr)] public String bstrDescription; + [MarshalAs(UnmanagedType.BStr)] public String bstrHelpFile; + public int dwHelpContext; + public IntPtr pvReserved; + public IntPtr pfnDeferredFillIn; + public Int32 scode; + } + + [Serializable] + public enum FUNCKIND : int + { + FUNC_VIRTUAL = 0, + FUNC_PUREVIRTUAL = 1, + FUNC_NONVIRTUAL = 2, + FUNC_STATIC = 3, + FUNC_DISPATCH = 4 + } + +[Serializable] +[Flags] + public enum INVOKEKIND : int + { + INVOKE_FUNC = 0x1, + INVOKE_PROPERTYGET = 0x2, + INVOKE_PROPERTYPUT = 0x4, + INVOKE_PROPERTYPUTREF = 0x8 + } + + [Serializable] + public enum CALLCONV : int + { + CC_CDECL =1, + CC_MSCPASCAL=2, + CC_PASCAL =CC_MSCPASCAL, + CC_MACPASCAL=3, + CC_STDCALL =4, + CC_RESERVED =5, + CC_SYSCALL =6, + CC_MPWCDECL =7, + CC_MPWPASCAL=8, + CC_MAX =9 + } + +[Serializable] +[Flags()] + public enum FUNCFLAGS : short + { + FUNCFLAG_FRESTRICTED= 0x1, + FUNCFLAG_FSOURCE = 0x2, + FUNCFLAG_FBINDABLE = 0x4, + FUNCFLAG_FREQUESTEDIT = 0x8, + FUNCFLAG_FDISPLAYBIND = 0x10, + FUNCFLAG_FDEFAULTBIND = 0x20, + FUNCFLAG_FHIDDEN = 0x40, + FUNCFLAG_FUSESGETLASTERROR= 0x80, + FUNCFLAG_FDEFAULTCOLLELEM= 0x100, + FUNCFLAG_FUIDEFAULT = 0x200, + FUNCFLAG_FNONBROWSABLE = 0x400, + FUNCFLAG_FREPLACEABLE = 0x800, + FUNCFLAG_FIMMEDIATEBIND = 0x1000 + } + +[Serializable] +[Flags()] + public enum VARFLAGS : short + { + VARFLAG_FREADONLY =0x1, + VARFLAG_FSOURCE =0x2, + VARFLAG_FBINDABLE =0x4, + VARFLAG_FREQUESTEDIT =0x8, + VARFLAG_FDISPLAYBIND =0x10, + VARFLAG_FDEFAULTBIND =0x20, + VARFLAG_FHIDDEN =0x40, + VARFLAG_FRESTRICTED =0x80, + VARFLAG_FDEFAULTCOLLELEM =0x100, + VARFLAG_FUIDEFAULT =0x200, + VARFLAG_FNONBROWSABLE =0x400, + VARFLAG_FREPLACEABLE =0x800, + VARFLAG_FIMMEDIATEBIND =0x1000 + } + + [Guid("00020401-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ITypeInfo + { + void GetTypeAttr(out IntPtr ppTypeAttr); + void GetTypeComp(out ITypeComp ppTComp); + void GetFuncDesc(int index, out IntPtr ppFuncDesc); + void GetVarDesc(int index, out IntPtr ppVarDesc); + void GetNames(int memid, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] String[] rgBstrNames, int cMaxNames, out int pcNames); + void GetRefTypeOfImplType(int index, out int href); + void GetImplTypeFlags(int index, out IMPLTYPEFLAGS pImplTypeFlags); + void GetIDsOfNames([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1), In] String[] rgszNames, int cNames, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] int[] pMemId); + void Invoke([MarshalAs(UnmanagedType.IUnknown)] Object pvInstance, int memid, Int16 wFlags, ref DISPPARAMS pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, out int puArgErr); + void GetDocumentation(int index, out String strName, out String strDocString, out int dwHelpContext, out String strHelpFile); + void GetDllEntry(int memid, INVOKEKIND invKind, IntPtr pBstrDllName, IntPtr pBstrName, IntPtr pwOrdinal); + void GetRefTypeInfo(int hRef, out ITypeInfo ppTI); + void AddressOfMember(int memid, INVOKEKIND invKind, out IntPtr ppv); + void CreateInstance([MarshalAs(UnmanagedType.IUnknown)] Object pUnkOuter, [In] ref Guid riid, [MarshalAs(UnmanagedType.IUnknown), Out] out Object ppvObj); + void GetMops(int memid, out String pBstrMops); + void GetContainingTypeLib(out ITypeLib ppTLB, out int pIndex); + [PreserveSig] + void ReleaseTypeAttr(IntPtr pTypeAttr); + [PreserveSig] + void ReleaseFuncDesc(IntPtr pFuncDesc); + [PreserveSig] + void ReleaseVarDesc(IntPtr pVarDesc); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeInfo2.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeInfo2.cs new file mode 100644 index 0000000000..3b13ebab35 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeInfo2.cs @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: ITypeInfo2 interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("00020412-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ITypeInfo2 : ITypeInfo + { + new void GetTypeAttr(out IntPtr ppTypeAttr); + new void GetTypeComp(out ITypeComp ppTComp); + new void GetFuncDesc(int index, out IntPtr ppFuncDesc); + new void GetVarDesc(int index, out IntPtr ppVarDesc); + new void GetNames(int memid, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] String[] rgBstrNames, int cMaxNames, out int pcNames); + new void GetRefTypeOfImplType(int index, out int href); + new void GetImplTypeFlags(int index, out IMPLTYPEFLAGS pImplTypeFlags); + new void GetIDsOfNames([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1), In] String[] rgszNames, int cNames, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] int[] pMemId); + new void Invoke([MarshalAs(UnmanagedType.IUnknown)] Object pvInstance, int memid, Int16 wFlags, ref DISPPARAMS pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, out int puArgErr); + new void GetDocumentation(int index, out String strName, out String strDocString, out int dwHelpContext, out String strHelpFile); + new void GetDllEntry(int memid, INVOKEKIND invKind, IntPtr pBstrDllName, IntPtr pBstrName, IntPtr pwOrdinal); + new void GetRefTypeInfo(int hRef, out ITypeInfo ppTI); + new void AddressOfMember(int memid, INVOKEKIND invKind, out IntPtr ppv); + new void CreateInstance([MarshalAs(UnmanagedType.IUnknown)] Object pUnkOuter, [In] ref Guid riid, [MarshalAs(UnmanagedType.IUnknown), Out] out Object ppvObj); + new void GetMops(int memid, out String pBstrMops); + new void GetContainingTypeLib(out ITypeLib ppTLB, out int pIndex); + [PreserveSig] + new void ReleaseTypeAttr(IntPtr pTypeAttr); + [PreserveSig] + new void ReleaseFuncDesc(IntPtr pFuncDesc); + [PreserveSig] + new void ReleaseVarDesc(IntPtr pVarDesc); + void GetTypeKind(out TYPEKIND pTypeKind); + void GetTypeFlags(out int pTypeFlags); + void GetFuncIndexOfMemId(int memid, INVOKEKIND invKind, out int pFuncIndex); + void GetVarIndexOfMemId(int memid, out int pVarIndex); + void GetCustData(ref Guid guid, out Object pVarVal); + void GetFuncCustData(int index, ref Guid guid, out Object pVarVal); + void GetParamCustData(int indexFunc, int indexParam, ref Guid guid, out Object pVarVal); + void GetVarCustData(int index, ref Guid guid, out Object pVarVal); + void GetImplTypeCustData(int index, ref Guid guid, out Object pVarVal); + [LCIDConversionAttribute(1)] + void GetDocumentation2(int memid, out String pbstrHelpString, out int pdwHelpStringContext, out String pbstrHelpStringDll); + void GetAllCustData(IntPtr pCustData); + void GetAllFuncCustData(int index, IntPtr pCustData); + void GetAllParamCustData(int indexFunc, int indexParam, IntPtr pCustData); + void GetAllVarCustData(int index, IntPtr pCustData); + void GetAllImplTypeCustData(int index, IntPtr pCustData); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeLib.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeLib.cs new file mode 100644 index 0000000000..14f0c87c27 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeLib.cs @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: ITypeLib interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Serializable] + public enum SYSKIND + { + SYS_WIN16 = 0, + SYS_WIN32 = SYS_WIN16 + 1, + SYS_MAC = SYS_WIN32 + 1, + SYS_WIN64 = SYS_MAC + 1 + } + +[Serializable] +[Flags()] + public enum LIBFLAGS : short + { + LIBFLAG_FRESTRICTED = 0x1, + LIBFLAG_FCONTROL = 0x2, + LIBFLAG_FHIDDEN = 0x4, + LIBFLAG_FHASDISKIMAGE = 0x8 + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + [Serializable] + public struct TYPELIBATTR + { + public Guid guid; + public int lcid; + public SYSKIND syskind; + public Int16 wMajorVerNum; + public Int16 wMinorVerNum; + public LIBFLAGS wLibFlags; + } + + [Guid("00020402-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ITypeLib + { + [PreserveSig] + int GetTypeInfoCount(); + void GetTypeInfo(int index, out ITypeInfo ppTI); + void GetTypeInfoType(int index, out TYPEKIND pTKind); + void GetTypeInfoOfGuid(ref Guid guid, out ITypeInfo ppTInfo); + void GetLibAttr(out IntPtr ppTLibAttr); + void GetTypeComp(out ITypeComp ppTComp); + void GetDocumentation(int index, out String strName, out String strDocString, out int dwHelpContext, out String strHelpFile); + [return : MarshalAs(UnmanagedType.Bool)] + bool IsName([MarshalAs(UnmanagedType.LPWStr)] String szNameBuf, int lHashVal); + void FindName([MarshalAs(UnmanagedType.LPWStr)] String szNameBuf, int lHashVal, [MarshalAs(UnmanagedType.LPArray), Out] ITypeInfo[] ppTInfo, [MarshalAs(UnmanagedType.LPArray), Out] int[] rgMemId, ref Int16 pcFound); + [PreserveSig] + void ReleaseTLibAttr(IntPtr pTLibAttr); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeLib2.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeLib2.cs new file mode 100644 index 0000000000..d5d4c365e0 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ComTypes/ITypeLib2.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: ITypeLib2 interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices.ComTypes +{ + using System; + + [Guid("00020411-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ITypeLib2 : ITypeLib + { + [PreserveSig] + new int GetTypeInfoCount(); + new void GetTypeInfo(int index, out ITypeInfo ppTI); + new void GetTypeInfoType(int index, out TYPEKIND pTKind); + new void GetTypeInfoOfGuid(ref Guid guid, out ITypeInfo ppTInfo); + new void GetLibAttr(out IntPtr ppTLibAttr); + new void GetTypeComp(out ITypeComp ppTComp); + new void GetDocumentation(int index, out String strName, out String strDocString, out int dwHelpContext, out String strHelpFile); + [return : MarshalAs(UnmanagedType.Bool)] + new bool IsName([MarshalAs(UnmanagedType.LPWStr)] String szNameBuf, int lHashVal); + new void FindName([MarshalAs(UnmanagedType.LPWStr)] String szNameBuf, int lHashVal, [MarshalAs(UnmanagedType.LPArray), Out] ITypeInfo[] ppTInfo, [MarshalAs(UnmanagedType.LPArray), Out] int[] rgMemId, ref Int16 pcFound); + [PreserveSig] + new void ReleaseTLibAttr(IntPtr pTLibAttr); + void GetCustData(ref Guid guid, out Object pVarVal); + [LCIDConversionAttribute(1)] + void GetDocumentation2(int index, out String pbstrHelpString, out int pdwHelpStringContext, out String pbstrHelpStringDll); + void GetLibStatistics(IntPtr pcUniqueNames, out int pcchUniqueNames); + void GetAllCustData(IntPtr pCustData); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/CriticalHandle.cs b/src/mscorlib/src/System/Runtime/InteropServices/CriticalHandle.cs new file mode 100644 index 0000000000..f36ab28d61 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/CriticalHandle.cs @@ -0,0 +1,274 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================ +** +** +** +** A specially designed handle wrapper to ensure we never leak +** an OS handle. The runtime treats this class specially during +** P/Invoke marshaling and finalization. Users should write +** subclasses of CriticalHandle for each distinct handle type. +** This class is similar to SafeHandle, but lacks the ref counting +** behavior on marshaling that prevents handle recycling errors +** or security holes. This lowers the overhead of using the handle +** considerably, but leaves the onus on the caller to protect +** themselves from any recycling effects. +** +** **** NOTE **** +** +** Since there are no ref counts tracking handle usage there is +** no thread safety either. Your application must ensure that +** usages of the handle do not cross with attempts to close the +** handle (or tolerate such crossings). Normal GC mechanics will +** prevent finalization until the handle class isn't used any more, +** but explicit Close or Dispose operations may be initiated at any +** time. +** +** Similarly, multiple calls to Close or Dispose on different +** threads at the same time may cause the ReleaseHandle method to be +** called more than once. +** +** In general (and as might be inferred from the lack of handle +** recycle protection) you should be very cautious about exposing +** CriticalHandle instances directly or indirectly to untrusted users. +** At a minimum you should restrict their ability to queue multiple +** operations against a single handle at the same time or block their +** access to Close and Dispose unless you are very comfortable with the +** semantics of passing an invalid (or possibly invalidated and +** reallocated) to the unamanged routines you marshal your handle to +** (and the effects of closing such a handle while those calls are in +** progress). The runtime cannot protect you from undefined program +** behvior that might result from such scenarios. You have been warned. +** +** +===========================================================*/ + +using System; +using System.Reflection; +using System.Threading; +using System.Security.Permissions; +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; +using System.Runtime.ConstrainedExecution; +using System.IO; + +/* + Problems addressed by the CriticalHandle class: + 1) Critical finalization - ensure we never leak OS resources in SQL. Done + without running truly arbitrary & unbounded amounts of managed code. + 2) Reduced graph promotion - during finalization, keep object graph small + 3) GC.KeepAlive behavior - P/Invoke vs. finalizer thread race condition (HandleRef) + 4) Enforcement of the above via the type system - Don't use IntPtr anymore. + + Subclasses of CriticalHandle will implement the ReleaseHandle + abstract method used to execute any code required to free the + handle. This method will be prepared as a constrained execution + region at instance construction time (along with all the methods in + its statically determinable call graph). This implies that we won't + get any inconvenient jit allocation errors or rude thread abort + interrupts while releasing the handle but the user must still write + careful code to avoid injecting fault paths of their own (see the + CER spec for more details). In particular, any sub-methods you call + should be decorated with a reliability contract of the appropriate + level. In most cases this should be: + ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success) + Also, any P/Invoke methods should use the + SuppressUnmanagedCodeSecurity attribute to avoid a runtime security + check that can also inject failures (even if the check is guaranteed + to pass). + + Subclasses must also implement the IsInvalid property so that the + infrastructure can tell when critical finalization is actually required. + Again, this method is prepared ahead of time. It's envisioned that direct + subclasses of CriticalHandle will provide an IsInvalid implementation that suits + the general type of handle they support (null is invalid, -1 is invalid etc.) + and then these classes will be further derived for specific handle types. + + Most classes using CriticalHandle should not provide a finalizer. If they do + need to do so (ie, for flushing out file buffers, needing to write some data + back into memory, etc), then they can provide a finalizer that will be + guaranteed to run before the CriticalHandle's critical finalizer. + + Subclasses are expected to be written as follows (note that + SuppressUnmanagedCodeSecurity should always be used on any P/Invoke methods + invoked as part of ReleaseHandle, in order to switch the security check from + runtime to jit time and thus remove a possible failure path from the + invocation of the method): + + internal sealed MyCriticalHandleSubclass : CriticalHandle { + // Called by P/Invoke when returning CriticalHandles + private MyCriticalHandleSubclass() : base(IntPtr.Zero) + { + } + + // Do not provide a finalizer - CriticalHandle's critical finalizer will + // call ReleaseHandle for you. + + public override bool IsInvalid { + get { return handle == IntPtr.Zero; } + } + + [DllImport(Win32Native.KERNEL32), SuppressUnmanagedCodeSecurity, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private static extern bool CloseHandle(IntPtr handle); + + override protected bool ReleaseHandle() + { + return CloseHandle(handle); + } + } + + Then elsewhere to create one of these CriticalHandles, define a method + with the following type of signature (CreateFile follows this model). + Note that when returning a CriticalHandle like this, P/Invoke will call your + classes default constructor. + + [DllImport(Win32Native.KERNEL32)] + private static extern MyCriticalHandleSubclass CreateHandle(int someState); + + */ + +namespace System.Runtime.InteropServices +{ + +// This class should not be serializable - it's a handle. We require unmanaged +// code permission to subclass CriticalHandle to prevent people from writing a +// subclass and suddenly being able to run arbitrary native code with the +// same signature as CloseHandle. This is technically a little redundant, but +// we'll do this to ensure we've cut off all attack vectors. Similarly, all +// methods have a link demand to ensure untrusted code cannot directly edit +// or alter a handle. +[System.Security.SecurityCritical] // auto-generated_required +#if !FEATURE_CORECLR +[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode=true)] +#endif +public abstract class CriticalHandle : CriticalFinalizerObject, IDisposable +{ + // ! Do not add or rearrange fields as the EE depends on this layout. + //------------------------------------------------------------------ +#if DEBUG + private String _stackTrace; // Where we allocated this CriticalHandle. +#endif + protected IntPtr handle; // This must be protected so derived classes can use out params. + private bool _isClosed; // Set by SetHandleAsInvalid or Close/Dispose/finalization. + + // Creates a CriticalHandle class. Users must then set the Handle property or allow P/Invoke marshaling to set it implicitly. + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected CriticalHandle(IntPtr invalidHandleValue) + { + handle = invalidHandleValue; + _isClosed = false; + +#if DEBUG + if (BCLDebug.SafeHandleStackTracesEnabled) + _stackTrace = Environment.GetStackTrace(null, false); + else + _stackTrace = "For a stack trace showing who allocated this CriticalHandle, set SafeHandleStackTraces to 1 and rerun your app."; +#endif + } + +#if FEATURE_CORECLR + // Adding an empty default constructor for annotation purposes + private CriticalHandle(){} +#endif + + [System.Security.SecuritySafeCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + ~CriticalHandle() + { + Dispose(false); + } + + [System.Security.SecurityCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private void Cleanup() + { + if (IsClosed) + return; + _isClosed = true; + + if (IsInvalid) + return; + + // Save last error from P/Invoke in case the implementation of + // ReleaseHandle trashes it (important because this ReleaseHandle could + // occur implicitly as part of unmarshaling another P/Invoke). + int lastError = Marshal.GetLastWin32Error(); + + if (!ReleaseHandle()) + FireCustomerDebugProbe(); + + Marshal.SetLastWin32Error(lastError); + + GC.SuppressFinalize(this); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private extern void FireCustomerDebugProbe(); + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + protected void SetHandle(IntPtr handle) { + this.handle = handle; + } + + // Returns whether the handle has been explicitly marked as closed + // (Close/Dispose) or invalid (SetHandleAsInvalid). + public bool IsClosed { + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + get { return _isClosed; } + } + + // Returns whether the handle looks like an invalid value (i.e. matches one + // of the handle's designated illegal values). CriticalHandle itself doesn't + // know what an invalid handle looks like, so this method is abstract and + // must be provided by a derived type. + public abstract bool IsInvalid { + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + get; + } + + [System.Security.SecurityCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public void Close() { + Dispose(true); + } + + [System.Security.SecuritySafeCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public void Dispose() + { + Dispose(true); + } + + [System.Security.SecurityCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + protected virtual void Dispose(bool disposing) + { + Cleanup(); + } + + // This should only be called for cases when you know for a fact that + // your handle is invalid and you want to record that information. + // An example is calling a syscall and getting back ERROR_INVALID_HANDLE. + // This method will normally leak handles! + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public void SetHandleAsInvalid() + { + _isClosed = true; + GC.SuppressFinalize(this); + } + + // Implement this abstract method in your derived class to specify how to + // free the handle. Be careful not write any code that's subject to faults + // in this method (the runtime will prepare the infrastructure for you so + // that no jit allocations etc. will occur, but don't allocate memory unless + // you can deal with the failure and still free the handle). + // The boolean returned should be true for success and false if a + // catastrophic error occured and you wish to trigger a diagnostic for + // debugging purposes (the SafeHandleCriticalFailure MDA). + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + protected abstract bool ReleaseHandle(); +} + +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/CurrencyWrapper.cs b/src/mscorlib/src/System/Runtime/InteropServices/CurrencyWrapper.cs new file mode 100644 index 0000000000..6fe3bb7df7 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/CurrencyWrapper.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Wrapper that is converted to a variant with VT_CURRENCY. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public sealed class CurrencyWrapper + { + public CurrencyWrapper(Decimal obj) + { + m_WrappedObject = obj; + } + + public CurrencyWrapper(Object obj) + { + if (!(obj is Decimal)) + throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDecimal"), "obj"); + m_WrappedObject = (Decimal)obj; + } + + public Decimal WrappedObject + { + get + { + return m_WrappedObject; + } + } + + private Decimal m_WrappedObject; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/DispatchWrapper.cs b/src/mscorlib/src/System/Runtime/InteropServices/DispatchWrapper.cs new file mode 100644 index 0000000000..66c9e80039 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/DispatchWrapper.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Wrapper that is converted to a variant with VT_DISPATCH. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using System.Security; + using System.Security.Permissions; + + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public sealed class DispatchWrapper + { + [System.Security.SecuritySafeCritical] // auto-generated +#pragma warning disable 618 + [SecurityPermissionAttribute(SecurityAction.Demand,Flags=SecurityPermissionFlag.UnmanagedCode)] +#pragma warning restore 618 + public DispatchWrapper(Object obj) + { + if (obj != null) + { + // Make sure this guy has an IDispatch + IntPtr pdisp = Marshal.GetIDispatchForObject(obj); + + // If we got here without throwing an exception, the QI for IDispatch succeeded. + Marshal.Release(pdisp); + } + m_WrappedObject = obj; + } + + public Object WrappedObject + { + get + { + return m_WrappedObject; + } + } + + private Object m_WrappedObject; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ErrorWrapper.cs b/src/mscorlib/src/System/Runtime/InteropServices/ErrorWrapper.cs new file mode 100644 index 0000000000..008ee3579b --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ErrorWrapper.cs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Wrapper that is converted to a variant with VT_ERROR. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using System.Security.Permissions; + + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public sealed class ErrorWrapper + { + public ErrorWrapper(int errorCode) + { + m_ErrorCode = errorCode; + } + + public ErrorWrapper(Object errorCode) + { + if (!(errorCode is int)) + throw new ArgumentException(Environment.GetResourceString("Arg_MustBeInt32"), "errorCode"); + m_ErrorCode = (int)errorCode; + } + + [System.Security.SecuritySafeCritical] // auto-generated +#pragma warning disable 618 + [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] +#pragma warning restore 618 + public ErrorWrapper(Exception e) + { + m_ErrorCode = Marshal.GetHRForException(e); + } + + public int ErrorCode + { + get + { + return m_ErrorCode; + } + } + + private int m_ErrorCode; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/Expando/IExpando.cs b/src/mscorlib/src/System/Runtime/InteropServices/Expando/IExpando.cs new file mode 100644 index 0000000000..6940157638 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/Expando/IExpando.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// IExpando is an interface which allows Objects implemeningt this interface +// support the ability to modify the object by adding and removing members, +// represented by MemberInfo objects. +// +// +// The IExpando Interface. +namespace System.Runtime.InteropServices.Expando { + + using System; + using System.Reflection; + + [Guid("AFBF15E6-C37C-11d2-B88E-00A0C9B471B8")] +[System.Runtime.InteropServices.ComVisible(true)] + public interface IExpando : IReflect + { + // Add a new Field to the reflection object. The field has + // name as its name. + FieldInfo AddField(String name); + + // Add a new Property to the reflection object. The property has + // name as its name. + PropertyInfo AddProperty(String name); + + // Add a new Method to the reflection object. The method has + // name as its name and method is a delegate + // to the method. + MethodInfo AddMethod(String name, Delegate method); + + // Removes the specified member. + void RemoveMember(MemberInfo m); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ExtensibleClassFactory.cs b/src/mscorlib/src/System/Runtime/InteropServices/ExtensibleClassFactory.cs new file mode 100644 index 0000000000..b8202f6410 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ExtensibleClassFactory.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Methods used to customize the creation of managed objects that +** extend from unmanaged objects. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + using System.Runtime.InteropServices; + using System.Runtime.Remoting; + using System.Runtime.CompilerServices; + using System.Runtime.Versioning; + + using System; +[System.Runtime.InteropServices.ComVisible(true)] + public sealed class ExtensibleClassFactory + { + + // Prevent instantiation. + private ExtensibleClassFactory() {} + + // Register a delegate that will be called whenever an instance of a managed + // type that extends from an unmanaged type needs to allocate the aggregated + // unmanaged object. This delegate is expected to allocate and aggregate the + // unmanaged object and is called in place of a CoCreateInstance. This + // routine must be called in the context of the static initializer for the + // class for which the callbacks will be made. + // It is not legal to register this callback from a class that has any + // parents that have already registered a callback. + [System.Security.SecuritySafeCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern void RegisterObjectCreationCallback(ObjectCreationDelegate callback); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ExternalException.cs b/src/mscorlib/src/System/Runtime/InteropServices/ExternalException.cs new file mode 100644 index 0000000000..ea9f8667fa --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ExternalException.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Exception base class for all errors from Interop or Structured +** Exception Handling code. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using System.Globalization; + using System.Runtime.Serialization; + // Base exception for COM Interop errors &; Structured Exception Handler + // exceptions. + // +[System.Runtime.InteropServices.ComVisible(true)] + [Serializable] + public class ExternalException : SystemException { + public ExternalException() + : base(Environment.GetResourceString("Arg_ExternalException")) { + SetErrorCode(__HResults.E_FAIL); + } + + public ExternalException(String message) + : base(message) { + SetErrorCode(__HResults.E_FAIL); + } + + public ExternalException(String message, Exception inner) + : base(message, inner) { + SetErrorCode(__HResults.E_FAIL); + } + + public ExternalException(String message,int errorCode) + : base(message) { + SetErrorCode(errorCode); + } + + protected ExternalException(SerializationInfo info, StreamingContext context) : base(info, context) { + } + + public virtual int ErrorCode { + get { + return HResult; + } + } + +#if !FEATURE_CORECLR // Breaks the subset-of-Orcas property + public override String ToString() { + String message = Message; + String s; + String _className = GetType().ToString(); + s = _className + " (0x" + HResult.ToString("X8", CultureInfo.InvariantCulture) + ")"; + + if (!(String.IsNullOrEmpty(message))) { + s = s + ": " + message; + } + + Exception _innerException = InnerException; + + if (_innerException!=null) { + s = s + " ---> " + _innerException.ToString(); + } + + + if (StackTrace != null) + s += Environment.NewLine + StackTrace; + + return s; + } +#endif // !FEATURE_CORECLR + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/GCHandleCookieTable.cs b/src/mscorlib/src/System/Runtime/InteropServices/GCHandleCookieTable.cs new file mode 100644 index 0000000000..e4ba66c8c3 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/GCHandleCookieTable.cs @@ -0,0 +1,218 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if MDA_SUPPORTED + +namespace System.Runtime.InteropServices +{ + using System; + using System.Collections.Generic; + using System.Threading; + + using ObjectHandle = IntPtr; + using GCHandleCookie = IntPtr; + + // Internal class used to map a GCHandle to an IntPtr. Instead of handing out the underlying CLR + // handle, we now hand out a cookie that can later be converted back to the CLR handle it + // is associated with. + + // NOTE: + // this implementation uses a single lock between FindOrAddHandle and RemoveHandleIfPresent which + // could create some scalability issues when this MDA is turned on. if this is affecting perf + // then additional tuning work will be required. + + internal class GCHandleCookieTable + { + private const int InitialHandleCount = 10; + private const int MaxListSize = 0xFFFFFF; + private const uint CookieMaskIndex = 0x00FFFFFF; + private const uint CookieMaskSentinal = 0xFF000000; + + internal GCHandleCookieTable() + { + m_HandleList = new ObjectHandle[InitialHandleCount]; + m_CycleCounts = new byte[InitialHandleCount]; + m_HandleToCookieMap = new Dictionary<ObjectHandle, GCHandleCookie>(InitialHandleCount); + m_syncObject = new object(); + + for (int i = 0; i < InitialHandleCount; i++) + { + m_HandleList[i] = ObjectHandle.Zero; + m_CycleCounts[i] = 0; + } + } + + // Retrieve a cookie for the passed in handle. If no cookie has yet been allocated for + // this handle, one will be created. This method is thread safe. + internal GCHandleCookie FindOrAddHandle(ObjectHandle handle) + { + // Don't accept a null object handle + if (handle == ObjectHandle.Zero) + return GCHandleCookie.Zero; + + GCHandleCookie cookie = GCHandleCookie.Zero; + + lock (m_syncObject) + { + // First see if we already have a cookie for this handle. + if (m_HandleToCookieMap.ContainsKey(handle)) + return m_HandleToCookieMap[handle]; + + if ((m_FreeIndex < m_HandleList.Length) && (Volatile.Read(ref m_HandleList[m_FreeIndex]) == ObjectHandle.Zero)) + { + Volatile.Write(ref m_HandleList[m_FreeIndex], handle); + cookie = GetCookieFromData((uint)m_FreeIndex, m_CycleCounts[m_FreeIndex]); + + // Set our next guess just one higher as this index is now in use. + // it's ok if this sets m_FreeIndex > m_HandleList.Length as this condition is + // checked at the beginning of the if statement. + ++m_FreeIndex; + } + else + { + for (m_FreeIndex = 0; m_FreeIndex < MaxListSize; ++m_FreeIndex) + { + if (m_HandleList[m_FreeIndex] == ObjectHandle.Zero) + { + Volatile.Write(ref m_HandleList[m_FreeIndex], handle); + cookie = GetCookieFromData((uint)m_FreeIndex, m_CycleCounts[m_FreeIndex]); + + // this will be our next guess for a free index. + // it's ok if this sets m_FreeIndex > m_HandleList.Length + // since we check for this condition in the if statement. + ++m_FreeIndex; + break; + } + + if (m_FreeIndex + 1 == m_HandleList.Length) + GrowArrays(); + } + } + + if (cookie == GCHandleCookie.Zero) + throw new OutOfMemoryException(Environment.GetResourceString("OutOfMemory_GCHandleMDA")); + + // This handle hasn't been added to the map yet so add it. + m_HandleToCookieMap.Add(handle, cookie); + } + + return cookie; + } + + // Get a handle. + internal ObjectHandle GetHandle(GCHandleCookie cookie) + { + ObjectHandle oh = ObjectHandle.Zero; + + if (!ValidateCookie(cookie)) + return ObjectHandle.Zero; + + oh = Volatile.Read(ref m_HandleList[GetIndexFromCookie(cookie)]); + + return oh; + } + + // Remove the handle from the cookie table if it is present. + // + internal void RemoveHandleIfPresent(ObjectHandle handle) + { + if (handle == ObjectHandle.Zero) + return; + + lock (m_syncObject) + { + if (m_HandleToCookieMap.ContainsKey(handle)) + { + GCHandleCookie cookie = m_HandleToCookieMap[handle]; + + // Remove it from the array first + if (!ValidateCookie(cookie)) + return; + + int index = GetIndexFromCookie(cookie); + + m_CycleCounts[index]++; + Volatile.Write(ref m_HandleList[index], ObjectHandle.Zero); + + // Remove it from the hashtable last + m_HandleToCookieMap.Remove(handle); + + // Update our guess + m_FreeIndex = index; + } + } + } + + private bool ValidateCookie(GCHandleCookie cookie) + { + int index; + byte xorData; + + GetDataFromCookie(cookie, out index, out xorData); + + // Validate the index + if (index >= MaxListSize) + return false; + + if (index >= m_HandleList.Length) + return false; + + if (Volatile.Read(ref m_HandleList[index]) == ObjectHandle.Zero) + return false; + + // Validate the xorData byte (this contains the cycle count and appdomain id). + byte ADID = (byte)(AppDomain.CurrentDomain.Id % 0xFF); + byte goodData = (byte)(Volatile.Read(ref m_CycleCounts[index]) ^ ADID); + if (xorData != goodData) + return false; + + return true; + } + + // Double the size of our arrays - must be called with the lock taken. + private void GrowArrays() + { + int CurrLength = m_HandleList.Length; + + ObjectHandle[] newHandleList = new ObjectHandle[CurrLength * 2]; + byte[] newCycleCounts = new byte[CurrLength * 2]; + + Array.Copy(m_HandleList, newHandleList, CurrLength); + Array.Copy(m_CycleCounts, newCycleCounts, CurrLength); + + m_HandleList = newHandleList; + m_CycleCounts = newCycleCounts; + } + + // Generate a cookie based on the index, cyclecount, and current domain id. + private GCHandleCookie GetCookieFromData(uint index, byte cycleCount) + { + byte ADID = (byte)(AppDomain.CurrentDomain.Id % 0xFF); + return (GCHandleCookie)(((cycleCount ^ ADID) << 24) + index + 1); + } + + // Break down the cookie into its parts + private void GetDataFromCookie(GCHandleCookie cookie, out int index, out byte xorData) + { + uint intCookie = (uint)cookie; + index = (int)(intCookie & CookieMaskIndex) - 1; + xorData = (byte)((intCookie & CookieMaskSentinal) >> 24); + } + + // Just get the index from the cookie + private int GetIndexFromCookie(GCHandleCookie cookie) + { + uint intCookie = (uint)cookie; + return (int)(intCookie & CookieMaskIndex) - 1; + } + + private Dictionary<ObjectHandle, GCHandleCookie> m_HandleToCookieMap; + private volatile ObjectHandle[] m_HandleList; + private volatile byte[] m_CycleCounts; + private int m_FreeIndex; + private readonly object m_syncObject; + } +} + +#endif + diff --git a/src/mscorlib/src/System/Runtime/InteropServices/GcHandle.cs b/src/mscorlib/src/System/Runtime/InteropServices/GcHandle.cs new file mode 100644 index 0000000000..c2799e0330 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/GcHandle.cs @@ -0,0 +1,329 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Runtime.InteropServices +{ + using System; + using System.Security.Permissions; + using System.Runtime.CompilerServices; + using System.Threading; + using System.Runtime.Versioning; + using System.Diagnostics.Contracts; + + // These are the types of handles used by the EE. + // IMPORTANT: These must match the definitions in ObjectHandle.h in the EE. + // IMPORTANT: If new values are added to the enum the GCHandle::MaxHandleType + // constant must be updated. + [Serializable] + [System.Runtime.InteropServices.ComVisible(true)] + public enum GCHandleType + { + Weak = 0, + WeakTrackResurrection = 1, + Normal = 2, + Pinned = 3 + } + + // This class allows you to create an opaque, GC handle to any + // COM+ object. A GC handle is used when an object reference must be + // reachable from unmanaged memory. There are 3 kinds of roots: + // Normal - keeps the object from being collected. + // Weak - allows object to be collected and handle contents will be zeroed. + // Weak references are zeroed before the finalizer runs, so if the + // object is resurrected in the finalizer the weak reference is + // still zeroed. + // WeakTrackResurrection - Same as weak, but stays until after object is + // really gone. + // Pinned - same as normal, but allows the address of the actual object + // to be taken. + // + + [StructLayout(LayoutKind.Sequential)] + [System.Runtime.InteropServices.ComVisible(true)] + public struct GCHandle + { + // IMPORTANT: This must be kept in sync with the GCHandleType enum. + private const GCHandleType MaxHandleType = GCHandleType.Pinned; + +#if MDA_SUPPORTED + [System.Security.SecuritySafeCritical] // auto-generated + static GCHandle() + { + s_probeIsActive = Mda.IsInvalidGCHandleCookieProbeEnabled(); + if (s_probeIsActive) + s_cookieTable = new GCHandleCookieTable(); + } +#endif + + // Allocate a handle storing the object and the type. + [System.Security.SecurityCritical] // auto-generated + internal GCHandle(Object value, GCHandleType type) + { + // Make sure the type parameter is within the valid range for the enum. + if ((uint)type > (uint)MaxHandleType) + throw new ArgumentOutOfRangeException("type", Environment.GetResourceString("ArgumentOutOfRange_Enum")); + Contract.EndContractBlock(); + + m_handle = InternalAlloc(value, type); + + // Record if the handle is pinned. + if (type == GCHandleType.Pinned) + SetIsPinned(); + } + + // Used in the conversion functions below. + [System.Security.SecurityCritical] // auto-generated + internal GCHandle(IntPtr handle) + { + InternalCheckDomain(handle); + m_handle = handle; + } + + // Creates a new GC handle for an object. + // + // value - The object that the GC handle is created for. + // type - The type of GC handle to create. + // + // returns a new GC handle that protects the object. + [System.Security.SecurityCritical] // auto-generated_required + public static GCHandle Alloc(Object value) + { + return new GCHandle(value, GCHandleType.Normal); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static GCHandle Alloc(Object value, GCHandleType type) + { + return new GCHandle(value, type); + } + + + // Frees a GC handle. + [System.Security.SecurityCritical] // auto-generated_required + public void Free() + { + // Copy the handle instance member to a local variable. This is required to prevent + // race conditions releasing the handle. + IntPtr handle = m_handle; + + // Free the handle if it hasn't already been freed. + if (handle != IntPtr.Zero && Interlocked.CompareExchange(ref m_handle, IntPtr.Zero, handle) == handle) + { +#if MDA_SUPPORTED + // If this handle was passed out to unmanaged code, we need to remove it + // from the cookie table. + // NOTE: the entry in the cookie table must be released before the + // internal handle is freed to prevent a race with reusing GC handles. + if (s_probeIsActive) + s_cookieTable.RemoveHandleIfPresent(handle); +#endif + +#if WIN32 + InternalFree((IntPtr)(((int)handle) & ~1)); +#else + InternalFree((IntPtr)(((long)handle) & ~1L)); +#endif + } + else + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized")); + } + } + + // Target property - allows getting / updating of the handle's referent. + public Object Target + { + [System.Security.SecurityCritical] // auto-generated_required + get + { + // Check if the handle was never initialized or was freed. + if (m_handle == IntPtr.Zero) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized")); + + return InternalGet(GetHandleValue()); + } + + [System.Security.SecurityCritical] // auto-generated_required + set + { + // Check if the handle was never initialized or was freed. + if (m_handle == IntPtr.Zero) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized")); + + InternalSet(GetHandleValue(), value, IsPinned()); + } + } + + // Retrieve the address of an object in a Pinned handle. This throws + // an exception if the handle is any type other than Pinned. + [System.Security.SecurityCritical] // auto-generated_required + public IntPtr AddrOfPinnedObject() + { + // Check if the handle was not a pinned handle. + if (!IsPinned()) + { + // Check if the handle was never initialized for was freed. + if (m_handle == IntPtr.Zero) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized")); + + // You can only get the address of pinned handles. + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotPinned")); + } + + // Get the address. + return InternalAddrOfPinnedObject(GetHandleValue()); + } + + // Determine whether this handle has been allocated or not. + public bool IsAllocated + { + get + { + return m_handle != IntPtr.Zero; + } + } + + // Used to create a GCHandle from an int. This is intended to + // be used with the reverse conversion. + [System.Security.SecurityCritical] // auto-generated_required + public static explicit operator GCHandle(IntPtr value) + { + return FromIntPtr(value); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static GCHandle FromIntPtr(IntPtr value) + { + if (value == IntPtr.Zero) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized")); + Contract.EndContractBlock(); + + IntPtr handle = value; + +#if MDA_SUPPORTED + if (s_probeIsActive) + { + // Make sure this cookie matches up with a GCHandle we've passed out a cookie for. + handle = s_cookieTable.GetHandle(value); + if (IntPtr.Zero == handle) + { + // Fire an MDA if we were unable to retrieve the GCHandle. + Mda.FireInvalidGCHandleCookieProbe(value); + return new GCHandle(IntPtr.Zero); + } + } +#endif + + return new GCHandle(handle); + } + + // Used to get the internal integer representation of the handle out. + public static explicit operator IntPtr(GCHandle value) + { + return ToIntPtr(value); + } + + public static IntPtr ToIntPtr(GCHandle value) + { +#if MDA_SUPPORTED + if (s_probeIsActive) + { + // Remember that we passed this GCHandle out by storing the cookie we returned so we + // can later validate. + return s_cookieTable.FindOrAddHandle(value.m_handle); + } +#endif + return value.m_handle; + } + + public override int GetHashCode() + { + return m_handle.GetHashCode(); + } + + public override bool Equals(Object o) + { + GCHandle hnd; + + // Check that o is a GCHandle first + if(o == null || !(o is GCHandle)) + return false; + else + hnd = (GCHandle) o; + + return m_handle == hnd.m_handle; + } + + public static bool operator ==(GCHandle a, GCHandle b) + { + return a.m_handle == b.m_handle; + } + + public static bool operator !=(GCHandle a, GCHandle b) + { + return a.m_handle != b.m_handle; + } + + internal IntPtr GetHandleValue() + { +#if WIN32 + return new IntPtr(((int)m_handle) & ~1); +#else + return new IntPtr(((long)m_handle) & ~1L); +#endif + } + + internal bool IsPinned() + { +#if WIN32 + return (((int)m_handle) & 1) != 0; +#else + return (((long)m_handle) & 1) != 0; +#endif + } + + internal void SetIsPinned() + { +#if WIN32 + m_handle = new IntPtr(((int)m_handle) | 1); +#else + m_handle = new IntPtr(((long)m_handle) | 1L); +#endif + } + + // Internal native calls that this implementation uses. + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern IntPtr InternalAlloc(Object value, GCHandleType type); + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void InternalFree(IntPtr handle); + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern Object InternalGet(IntPtr handle); + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void InternalSet(IntPtr handle, Object value, bool isPinned); + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern Object InternalCompareExchange(IntPtr handle, Object value, Object oldValue, bool isPinned); + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern IntPtr InternalAddrOfPinnedObject(IntPtr handle); + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void InternalCheckDomain(IntPtr handle); + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern GCHandleType InternalGetHandleType(IntPtr handle); + + // The actual integer handle value that the EE uses internally. + private IntPtr m_handle; + +#if MDA_SUPPORTED + // The GCHandle cookie table. + static private volatile GCHandleCookieTable s_cookieTable = null; + static private volatile bool s_probeIsActive = false; +#endif + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/HandleRef.cs b/src/mscorlib/src/System/Runtime/InteropServices/HandleRef.cs new file mode 100644 index 0000000000..5b7644b521 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/HandleRef.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Runtime.InteropServices +{ + + using System; + + [System.Runtime.InteropServices.ComVisible(true)] + public struct HandleRef + { + + // ! Do not add or rearrange fields as the EE depends on this layout. + //------------------------------------------------------------------ + internal Object m_wrapper; + internal IntPtr m_handle; + //------------------------------------------------------------------ + + + public HandleRef(Object wrapper, IntPtr handle) + { + m_wrapper = wrapper; + m_handle = handle; + } + + public Object Wrapper { + get { + return m_wrapper; + } + } + + public IntPtr Handle { + get { + return m_handle; + } + } + + + public static explicit operator IntPtr(HandleRef value) + { + return value.m_handle; + } + + public static IntPtr ToIntPtr(HandleRef value) + { + return value.m_handle; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ICustomAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/ICustomAdapter.cs new file mode 100644 index 0000000000..ba5d622a0d --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ICustomAdapter.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: This the base interface that custom adapters can chose to implement +** when they want to expose the underlying object. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + using System; + +[System.Runtime.InteropServices.ComVisible(true)] + public interface ICustomAdapter + { + [return:MarshalAs(UnmanagedType.IUnknown)] Object GetUnderlyingObject(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ICustomFactory.cs b/src/mscorlib/src/System/Runtime/InteropServices/ICustomFactory.cs new file mode 100644 index 0000000000..6b06b46d6a --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ICustomFactory.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +namespace System.Runtime.InteropServices { + + using System; + +[System.Runtime.InteropServices.ComVisible(true)] + public interface ICustomFactory + { + MarshalByRefObject CreateInstance(Type serverType); + } + +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ICustomMarshaler.cs b/src/mscorlib/src/System/Runtime/InteropServices/ICustomMarshaler.cs new file mode 100644 index 0000000000..e02db98bb3 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ICustomMarshaler.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: This the base interface that must be implemented by all custom +** marshalers. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + using System; + +[System.Runtime.InteropServices.ComVisible(true)] + public interface ICustomMarshaler + { + Object MarshalNativeToManaged( IntPtr pNativeData ); + + IntPtr MarshalManagedToNative( Object ManagedObj ); + + void CleanUpNativeData( IntPtr pNativeData ); + + void CleanUpManagedData( Object ManagedObj ); + + int GetNativeDataSize(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ICustomQueryInterface.cs b/src/mscorlib/src/System/Runtime/InteropServices/ICustomQueryInterface.cs new file mode 100644 index 0000000000..b6c057be02 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ICustomQueryInterface.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: This the interface that be implemented by class that want to +** customize the behavior of QueryInterface. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + using System; + + //==================================================================== + // The enum of the return value of IQuerable.GetInterface + //==================================================================== + [Serializable] + [System.Runtime.InteropServices.ComVisible(false)] + public enum CustomQueryInterfaceResult + { + Handled = 0, + NotHandled = 1, + Failed = 2, + } + + //==================================================================== + // The interface for customizing IQueryInterface + //==================================================================== + [System.Runtime.InteropServices.ComVisible(false)] + public interface ICustomQueryInterface + { + [System.Security.SecurityCritical] + CustomQueryInterfaceResult GetInterface([In]ref Guid iid, out IntPtr ppv); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/IException.cs b/src/mscorlib/src/System/Runtime/InteropServices/IException.cs new file mode 100644 index 0000000000..314e571187 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/IException.cs @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** Interface: _Exception +** +** +** Purpose: COM backwards compatibility with v1 Exception +** object layout. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + using System; + using System.Reflection; + using System.Runtime.Serialization; + using System.Security.Permissions; + + [GuidAttribute("b36b5c63-42ef-38bc-a07e-0b34c98f164a")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)] + [CLSCompliant(false)] +[System.Runtime.InteropServices.ComVisible(true)] + public interface _Exception + { +#if !FEATURE_CORECLR + // This contains all of our V1 Exception class's members. + + // From Object + String ToString(); + bool Equals (Object obj); + int GetHashCode (); + Type GetType (); + + // From V1's Exception class + String Message { + get; + } + + Exception GetBaseException(); + + String StackTrace { + get; + } + + String HelpLink { + get; + set; + } + + String Source { + #if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + #endif + get; + #if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + #endif + set; + } + [System.Security.SecurityCritical] // auto-generated_required + void GetObjectData(SerializationInfo info, StreamingContext context); +#endif + + // + // This method is intentionally included in CoreCLR to make Exception.get_InnerException "newslot virtual final". + // Some phone apps include MEF from desktop Silverlight. MEF's ComposablePartException depends on implicit interface + // implementations of get_InnerException to be provided by the base class. It works only if Exception.get_InnerException + // is virtual. + // + Exception InnerException { + get; + } + +#if !FEATURE_CORECLR + MethodBase TargetSite { + get; + } +#endif + } + +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/IRegistrationServices.cs b/src/mscorlib/src/System/Runtime/InteropServices/IRegistrationServices.cs new file mode 100644 index 0000000000..5c5c6cdc88 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/IRegistrationServices.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: This interface provides services for registering and unregistering +** a managed server for use by COM. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using System.Reflection; + using System.Security; + using System.Security.Permissions; + + [Flags()] +[System.Runtime.InteropServices.ComVisible(true)] + public enum AssemblyRegistrationFlags + { + None = 0x00000000, + SetCodeBase = 0x00000001, + } + + [Guid("CCBD682C-73A5-4568-B8B0-C7007E11ABA2")] +[System.Runtime.InteropServices.ComVisible(true)] + public interface IRegistrationServices + { + [System.Security.SecurityCritical] // auto-generated_required + bool RegisterAssembly(Assembly assembly, AssemblyRegistrationFlags flags); + + [System.Security.SecurityCritical] // auto-generated_required + bool UnregisterAssembly(Assembly assembly); + + [System.Security.SecurityCritical] // auto-generated_required + Type[] GetRegistrableTypesInAssembly(Assembly assembly); + + [System.Security.SecurityCritical] // auto-generated_required + String GetProgIdForType(Type type); + + [System.Security.SecurityCritical] // auto-generated_required + void RegisterTypeForComClients(Type type, ref Guid g); + + Guid GetManagedCategoryGuid(); + + [System.Security.SecurityCritical] // auto-generated_required + bool TypeRequiresRegistration(Type type); + + bool TypeRepresentsComType(Type type); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ITypeLibConverter.cs b/src/mscorlib/src/System/Runtime/InteropServices/ITypeLibConverter.cs new file mode 100644 index 0000000000..ff6d73866d --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ITypeLibConverter.cs @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Methods used to convert a TypeLib to metadata and vice versa. +** +** +=============================================================================*/ + +// *************************************************************************** +// *** Note: The following definitions must remain synchronized with the IDL +// *** in src/inc/TlbImpExp.idl. +// *************************************************************************** + +namespace System.Runtime.InteropServices { + + using System; + using System.Reflection; + using System.Reflection.Emit; + +[Serializable] +[Flags()] +[System.Runtime.InteropServices.ComVisible(true)] + public enum TypeLibImporterFlags + { + None = 0x00000000, + PrimaryInteropAssembly = 0x00000001, + UnsafeInterfaces = 0x00000002, + SafeArrayAsSystemArray = 0x00000004, + TransformDispRetVals = 0x00000008, + PreventClassMembers = 0x00000010, + SerializableValueClasses = 0x00000020, + ImportAsX86 = 0x00000100, + ImportAsX64 = 0x00000200, + ImportAsItanium = 0x00000400, + ImportAsAgnostic = 0x00000800, + ReflectionOnlyLoading = 0x00001000, + NoDefineVersionResource = 0x00002000, + ImportAsArm = 0x00004000, + } + +[Serializable] +[Flags()] +[System.Runtime.InteropServices.ComVisible(true)] + public enum TypeLibExporterFlags + { + None = 0x00000000, + OnlyReferenceRegistered = 0x00000001, + CallerResolvedReferences = 0x00000002, + OldNames = 0x00000004, + ExportAs32Bit = 0x00000010, + ExportAs64Bit = 0x00000020, + } + + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public enum ImporterEventKind + { + NOTIF_TYPECONVERTED = 0, + NOTIF_CONVERTWARNING = 1, + ERROR_REFTOINVALIDTYPELIB = 2, + } + + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public enum ExporterEventKind + { + NOTIF_TYPECONVERTED = 0, + NOTIF_CONVERTWARNING = 1, + ERROR_REFTOINVALIDASSEMBLY = 2 + } + + [GuidAttribute("F1C3BF76-C3E4-11d3-88E7-00902754C43A")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] +[System.Runtime.InteropServices.ComVisible(true)] + public interface ITypeLibImporterNotifySink + { + void ReportEvent( + ImporterEventKind eventKind, + int eventCode, + String eventMsg); + Assembly ResolveRef( + [MarshalAs(UnmanagedType.Interface)] Object typeLib); + } + + [GuidAttribute("F1C3BF77-C3E4-11d3-88E7-00902754C43A")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] +[System.Runtime.InteropServices.ComVisible(true)] + public interface ITypeLibExporterNotifySink + { + void ReportEvent( + ExporterEventKind eventKind, + int eventCode, + String eventMsg); + + [return : MarshalAs(UnmanagedType.Interface)] + Object ResolveRef( + Assembly assembly); + } + + [GuidAttribute("F1C3BF78-C3E4-11d3-88E7-00902754C43A")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] +[System.Runtime.InteropServices.ComVisible(true)] + public interface ITypeLibConverter + { + AssemblyBuilder ConvertTypeLibToAssembly( + [MarshalAs(UnmanagedType.Interface)] Object typeLib, + String asmFileName, + TypeLibImporterFlags flags, + ITypeLibImporterNotifySink notifySink, + byte[] publicKey, + StrongNameKeyPair keyPair, + String asmNamespace, + Version asmVersion); + + [return : MarshalAs(UnmanagedType.Interface)] + Object ConvertAssemblyToTypeLib( + Assembly assembly, + String typeLibName, + TypeLibExporterFlags flags, + ITypeLibExporterNotifySink notifySink); + + bool GetPrimaryInteropAssembly(Guid g, Int32 major, Int32 minor, Int32 lcid, out String asmName, out String asmCodeBase); + + AssemblyBuilder ConvertTypeLibToAssembly([MarshalAs(UnmanagedType.Interface)] Object typeLib, + String asmFileName, + int flags, + ITypeLibImporterNotifySink notifySink, + byte[] publicKey, + StrongNameKeyPair keyPair, + bool unsafeInterfaces); + } + + [GuidAttribute("FA1F3615-ACB9-486d-9EAC-1BEF87E36B09")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] +[System.Runtime.InteropServices.ComVisible(true)] + public interface ITypeLibExporterNameProvider + { + [return : MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR)] + String[] GetNames(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs b/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs new file mode 100644 index 0000000000..ae1f006417 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** Purpose: This exception is thrown when an invalid COM object is used. This +** happens when a the __ComObject type is used directly without +** having a backing class factory. +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using System.Runtime.Serialization; + +[System.Runtime.InteropServices.ComVisible(true)] + [Serializable] + public class InvalidComObjectException : SystemException { + public InvalidComObjectException() + : base(Environment.GetResourceString("Arg_InvalidComObjectException")) { + SetErrorCode(__HResults.COR_E_INVALIDCOMOBJECT); + } + + public InvalidComObjectException(String message) + : base(message) { + SetErrorCode(__HResults.COR_E_INVALIDCOMOBJECT); + } + + public InvalidComObjectException(String message, Exception inner) + : base(message, inner) { + SetErrorCode(__HResults.COR_E_INVALIDCOMOBJECT); + } + + protected InvalidComObjectException(SerializationInfo info, StreamingContext context) : base(info, context) { + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs b/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs new file mode 100644 index 0000000000..81ace87f0a --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** Purpose: The type of an OLE variant that was passed into the runtime is +** invalid. +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using System.Runtime.Serialization; + +[System.Runtime.InteropServices.ComVisible(true)] + [Serializable] public class InvalidOleVariantTypeException : SystemException { + public InvalidOleVariantTypeException() + : base(Environment.GetResourceString("Arg_InvalidOleVariantTypeException")) { + SetErrorCode(__HResults.COR_E_INVALIDOLEVARIANTTYPE); + } + + public InvalidOleVariantTypeException(String message) + : base(message) { + SetErrorCode(__HResults.COR_E_INVALIDOLEVARIANTTYPE); + } + + public InvalidOleVariantTypeException(String message, Exception inner) + : base(message, inner) { + SetErrorCode(__HResults.COR_E_INVALIDOLEVARIANTTYPE); + } + + protected InvalidOleVariantTypeException(SerializationInfo info, StreamingContext context) : base(info, context) { + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/LayoutKind.cs b/src/mscorlib/src/System/Runtime/InteropServices/LayoutKind.cs new file mode 100644 index 0000000000..6eed1af070 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/LayoutKind.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +namespace System.Runtime.InteropServices { + using System; + // Used in the StructLayoutAttribute class + [System.Runtime.InteropServices.ComVisible(true)] + [Serializable] + public enum LayoutKind + { + Sequential = 0, // 0x00000008, + Explicit = 2, // 0x00000010, + Auto = 3, // 0x00000000, + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs b/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs new file mode 100644 index 0000000000..a46999a004 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs @@ -0,0 +1,2677 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: This class contains methods that are mainly used to marshal +** between unmanaged and managed types. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + using System.Collections.Generic; + using System.Reflection; + using System.Reflection.Emit; + using System.Security; + using System.Security.Permissions; + using System.Text; + using System.Threading; + using System.Runtime.Remoting; + using System.Runtime.CompilerServices; + using System.Globalization; + using System.Runtime.ConstrainedExecution; + using System.Runtime.Versioning; + using Win32Native = Microsoft.Win32.Win32Native; + using Microsoft.Win32.SafeHandles; + using System.Diagnostics.Contracts; + using System.Runtime.InteropServices.ComTypes; + + [Serializable] + public enum CustomQueryInterfaceMode + { + Ignore = 0, + Allow = 1 + } + + //======================================================================== + // All public methods, including PInvoke, are protected with linkchecks. + // Remove the default demands for all PInvoke methods with this global + // declaration on the class. + //======================================================================== + + #if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + #endif + public static partial class Marshal + { + //==================================================================== + // Defines used inside the Marshal class. + //==================================================================== + private const int LMEM_FIXED = 0; + private const int LMEM_MOVEABLE = 2; +#if !FEATURE_PAL + private const long HIWORDMASK = unchecked((long)0xffffffffffff0000L); +#endif //!FEATURE_PAL +#if FEATURE_COMINTEROP + private static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046"); +#endif //FEATURE_COMINTEROP + + // Win32 has the concept of Atoms, where a pointer can either be a pointer + // or an int. If it's less than 64K, this is guaranteed to NOT be a + // pointer since the bottom 64K bytes are reserved in a process' page table. + // We should be careful about deallocating this stuff. Extracted to + // a function to avoid C# problems with lack of support for IntPtr. + // We have 2 of these methods for slightly different semantics for NULL. + private static bool IsWin32Atom(IntPtr ptr) + { +#if FEATURE_PAL + return false; +#else + long lPtr = (long)ptr; + return 0 == (lPtr & HIWORDMASK); +#endif + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private static bool IsNotWin32Atom(IntPtr ptr) + { +#if FEATURE_PAL + return true; +#else + long lPtr = (long)ptr; + return 0 != (lPtr & HIWORDMASK); +#endif + } + + //==================================================================== + // The default character size for the system. This is always 2 because + // the framework only runs on UTF-16 systems. + //==================================================================== + public static readonly int SystemDefaultCharSize = 2; + + //==================================================================== + // The max DBCS character size for the system. + //==================================================================== + public static readonly int SystemMaxDBCSCharSize = GetSystemMaxDBCSCharSize(); + + + //==================================================================== + // The name, title and description of the assembly that will contain + // the dynamically generated interop types. + //==================================================================== + private const String s_strConvertedTypeInfoAssemblyName = "InteropDynamicTypes"; + private const String s_strConvertedTypeInfoAssemblyTitle = "Interop Dynamic Types"; + private const String s_strConvertedTypeInfoAssemblyDesc = "Type dynamically generated from ITypeInfo's"; + private const String s_strConvertedTypeInfoNameSpace = "InteropDynamicTypes"; + + + //==================================================================== + // Helper method to retrieve the system's maximum DBCS character size. + //==================================================================== + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern int GetSystemMaxDBCSCharSize(); + + [System.Security.SecurityCritical] // auto-generated_required + unsafe public static String PtrToStringAnsi(IntPtr ptr) + { + if (IntPtr.Zero == ptr) { + return null; + } + else if (IsWin32Atom(ptr)) { + return null; + } + else { + int nb = Win32Native.lstrlenA(ptr); + if( nb == 0) { + return string.Empty; + } + else { + return new String((sbyte *)ptr); + } + } + } + + [System.Security.SecurityCritical] // auto-generated_required + unsafe public static String PtrToStringAnsi(IntPtr ptr, int len) + { + if (ptr == IntPtr.Zero) + throw new ArgumentNullException("ptr"); + if (len < 0) + throw new ArgumentException("len"); + + return new String((sbyte *)ptr, 0, len); + } + + [System.Security.SecurityCritical] // auto-generated_required + unsafe public static String PtrToStringUni(IntPtr ptr, int len) + { + if (ptr == IntPtr.Zero) + throw new ArgumentNullException("ptr"); + if (len < 0) + throw new ArgumentException("len"); + + return new String((char *)ptr, 0, len); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static String PtrToStringAuto(IntPtr ptr, int len) + { + // Ansi platforms are no longer supported + return PtrToStringUni(ptr, len); + } + + [System.Security.SecurityCritical] // auto-generated_required + unsafe public static String PtrToStringUni(IntPtr ptr) + { + if (IntPtr.Zero == ptr) { + return null; + } + else if (IsWin32Atom(ptr)) { + return null; + } + else { + return new String((char *)ptr); + } + } + + [System.Security.SecurityCritical] // auto-generated_required + public static String PtrToStringAuto(IntPtr ptr) + { + // Ansi platforms are no longer supported + return PtrToStringUni(ptr); + } + + //==================================================================== + // SizeOf() + //==================================================================== + [System.Runtime.InteropServices.ComVisible(true)] + public static int SizeOf(Object structure) + { + if (structure == null) + throw new ArgumentNullException("structure"); + // we never had a check for generics here + Contract.EndContractBlock(); + + return SizeOfHelper(structure.GetType(), true); + } + + public static int SizeOf<T>(T structure) + { + return SizeOf((object)structure); + } + + [Pure] + public static int SizeOf(Type t) + { + if (t == null) + throw new ArgumentNullException("t"); + if (!(t is RuntimeType)) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "t"); + if (t.IsGenericType) + throw new ArgumentException(Environment.GetResourceString("Argument_NeedNonGenericType"), "t"); + Contract.EndContractBlock(); + + return SizeOfHelper(t, true); + } + + public static int SizeOf<T>() + { + return SizeOf(typeof(T)); + } + + /// <summary> + /// Returns the aligned size of an instance of a value type. + /// </summary> + /// <typeparam name="T">Provide a value type to figure out its size</typeparam> + /// <returns>The aligned size of T in bytes.</returns> + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + internal static uint AlignedSizeOf<T>() where T : struct + { + uint size = SizeOfType(typeof(T)); + if (size == 1 || size == 2) + { + return size; + } + if (IntPtr.Size == 8 && size == 4) + { + return size; + } + return AlignedSizeOfType(typeof(T)); + } + + // Type must be a value type with no object reference fields. We only + // assert this, due to the lack of a suitable generic constraint. + [MethodImpl(MethodImplOptions.InternalCall)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern uint SizeOfType(Type type); + + // Type must be a value type with no object reference fields. We only + // assert this, due to the lack of a suitable generic constraint. + [MethodImpl(MethodImplOptions.InternalCall)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private static extern uint AlignedSizeOfType(Type type); + +#if !FEATURE_CORECLR // Marshal is critical in CoreCLR, so SafeCritical members trigger Annotator violations + [System.Security.SecuritySafeCritical] +#endif // !FEATURE_CORECLR + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern int SizeOfHelper(Type t, bool throwIfNotMarshalable); + + //==================================================================== + // OffsetOf() + //==================================================================== + public static IntPtr OffsetOf(Type t, String fieldName) + { + if (t == null) + throw new ArgumentNullException("t"); + Contract.EndContractBlock(); + + FieldInfo f = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (f == null) + throw new ArgumentException(Environment.GetResourceString("Argument_OffsetOfFieldNotFound", t.FullName), "fieldName"); + RtFieldInfo rtField = f as RtFieldInfo; + if (rtField == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeFieldInfo"), "fieldName"); + + return OffsetOfHelper(rtField); + } + public static IntPtr OffsetOf<T>(string fieldName) + { + return OffsetOf(typeof(T), fieldName); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern IntPtr OffsetOfHelper(IRuntimeFieldInfo f); + + //==================================================================== + // UnsafeAddrOfPinnedArrayElement() + // + // IMPORTANT NOTICE: This method does not do any verification on the + // array. It must be used with EXTREME CAUTION since passing in + // an array that is not pinned or in the fixed heap can cause + // unexpected results ! + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern IntPtr UnsafeAddrOfPinnedArrayElement(Array arr, int index); + + [System.Security.SecurityCritical] + public static IntPtr UnsafeAddrOfPinnedArrayElement<T>(T[] arr, int index) + { + return UnsafeAddrOfPinnedArrayElement((Array)arr, index); + } + + //==================================================================== + // Copy blocks from CLR arrays to native memory. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(int[] source, int startIndex, IntPtr destination, int length) + { + CopyToNative(source, startIndex, destination, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(char[] source, int startIndex, IntPtr destination, int length) + { + CopyToNative(source, startIndex, destination, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(short[] source, int startIndex, IntPtr destination, int length) + { + CopyToNative(source, startIndex, destination, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(long[] source, int startIndex, IntPtr destination, int length) + { + CopyToNative(source, startIndex, destination, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(float[] source, int startIndex, IntPtr destination, int length) + { + CopyToNative(source, startIndex, destination, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(double[] source, int startIndex, IntPtr destination, int length) + { + CopyToNative(source, startIndex, destination, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(byte[] source, int startIndex, IntPtr destination, int length) + { + CopyToNative(source, startIndex, destination, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(IntPtr[] source, int startIndex, IntPtr destination, int length) + { + CopyToNative(source, startIndex, destination, length); + } + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void CopyToNative(Object source, int startIndex, IntPtr destination, int length); + + //==================================================================== + // Copy blocks from native memory to CLR arrays + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(IntPtr source, int[] destination, int startIndex, int length) + { + CopyToManaged(source, destination, startIndex, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(IntPtr source, char[] destination, int startIndex, int length) + { + CopyToManaged(source, destination, startIndex, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(IntPtr source, short[] destination, int startIndex, int length) + { + CopyToManaged(source, destination, startIndex, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(IntPtr source, long[] destination, int startIndex, int length) + { + CopyToManaged(source, destination, startIndex, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(IntPtr source, float[] destination, int startIndex, int length) + { + CopyToManaged(source, destination, startIndex, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(IntPtr source, double[] destination, int startIndex, int length) + { + CopyToManaged(source, destination, startIndex, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(IntPtr source, byte[] destination, int startIndex, int length) + { + CopyToManaged(source, destination, startIndex, length); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void Copy(IntPtr source, IntPtr[] destination, int startIndex, int length) + { + CopyToManaged(source, destination, startIndex, length); + } + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void CopyToManaged(IntPtr source, Object destination, int startIndex, int length); + + //==================================================================== + // Read from memory + //==================================================================== + [DllImport(Win32Native.SHIM, EntryPoint="ND_RU1")] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + public static extern byte ReadByte([MarshalAs(UnmanagedType.AsAny), In] Object ptr, int ofs); + + [System.Security.SecurityCritical] // auto-generated_required + public static unsafe byte ReadByte(IntPtr ptr, int ofs) + { + try + { + byte *addr = (byte *)ptr + ofs; + return *addr; + } + catch (NullReferenceException) + { + // this method is documented to throw AccessViolationException on any AV + throw new AccessViolationException(); + } + } + + [System.Security.SecurityCritical] // auto-generated_required + public static byte ReadByte(IntPtr ptr) + { + return ReadByte(ptr,0); + } + + [DllImport(Win32Native.SHIM, EntryPoint="ND_RI2")] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + public static extern short ReadInt16([MarshalAs(UnmanagedType.AsAny),In] Object ptr, int ofs); + + [System.Security.SecurityCritical] // auto-generated_required + public static unsafe short ReadInt16(IntPtr ptr, int ofs) + { + try + { + byte *addr = (byte *)ptr + ofs; + if ((unchecked((int)addr) & 0x1) == 0) + { + // aligned read + return *((short *)addr); + } + else + { + // unaligned read + short val; + byte *valPtr = (byte *)&val; + valPtr[0] = addr[0]; + valPtr[1] = addr[1]; + return val; + } + } + catch (NullReferenceException) + { + // this method is documented to throw AccessViolationException on any AV + throw new AccessViolationException(); + } + } + + [System.Security.SecurityCritical] // auto-generated_required + public static short ReadInt16(IntPtr ptr) + { + return ReadInt16(ptr, 0); + } + + [DllImport(Win32Native.SHIM, EntryPoint="ND_RI4"), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + public static extern int ReadInt32([MarshalAs(UnmanagedType.AsAny),In] Object ptr, int ofs); + + [System.Security.SecurityCritical] // auto-generated_required + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static unsafe int ReadInt32(IntPtr ptr, int ofs) + { + try + { + byte *addr = (byte *)ptr + ofs; + if ((unchecked((int)addr) & 0x3) == 0) + { + // aligned read + return *((int *)addr); + } + else + { + // unaligned read + int val; + byte *valPtr = (byte *)&val; + valPtr[0] = addr[0]; + valPtr[1] = addr[1]; + valPtr[2] = addr[2]; + valPtr[3] = addr[3]; + return val; + } + } + catch (NullReferenceException) + { + // this method is documented to throw AccessViolationException on any AV + throw new AccessViolationException(); + } + } + + [System.Security.SecurityCritical] // auto-generated_required + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static int ReadInt32(IntPtr ptr) + { + return ReadInt32(ptr,0); + } + + [System.Security.SecurityCritical] // auto-generated_required + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static IntPtr ReadIntPtr([MarshalAs(UnmanagedType.AsAny),In] Object ptr, int ofs) + { + #if WIN32 + return (IntPtr) ReadInt32(ptr, ofs); + #else + return (IntPtr) ReadInt64(ptr, ofs); + #endif + } + + [System.Security.SecurityCritical] // auto-generated_required + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static IntPtr ReadIntPtr(IntPtr ptr, int ofs) + { + #if WIN32 + return (IntPtr) ReadInt32(ptr, ofs); + #else + return (IntPtr) ReadInt64(ptr, ofs); + #endif + } + + [System.Security.SecurityCritical] // auto-generated_required + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static IntPtr ReadIntPtr(IntPtr ptr) + { + #if WIN32 + return (IntPtr) ReadInt32(ptr, 0); + #else + return (IntPtr) ReadInt64(ptr, 0); + #endif + } + + [DllImport(Win32Native.SHIM, EntryPoint="ND_RI8"), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + public static extern long ReadInt64([MarshalAs(UnmanagedType.AsAny),In] Object ptr, int ofs); + + [System.Security.SecurityCritical] // auto-generated_required + public static unsafe long ReadInt64(IntPtr ptr, int ofs) + { + try + { + byte *addr = (byte *)ptr + ofs; + if ((unchecked((int)addr) & 0x7) == 0) + { + // aligned read + return *((long *)addr); + } + else + { + // unaligned read + long val; + byte *valPtr = (byte *)&val; + valPtr[0] = addr[0]; + valPtr[1] = addr[1]; + valPtr[2] = addr[2]; + valPtr[3] = addr[3]; + valPtr[4] = addr[4]; + valPtr[5] = addr[5]; + valPtr[6] = addr[6]; + valPtr[7] = addr[7]; + return val; + } + } + catch (NullReferenceException) + { + // this method is documented to throw AccessViolationException on any AV + throw new AccessViolationException(); + } + } + + [System.Security.SecurityCritical] // auto-generated_required + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static long ReadInt64(IntPtr ptr) + { + return ReadInt64(ptr,0); + } + + + //==================================================================== + // Write to memory + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static unsafe void WriteByte(IntPtr ptr, int ofs, byte val) + { + try + { + byte *addr = (byte *)ptr + ofs; + *addr = val; + } + catch (NullReferenceException) + { + // this method is documented to throw AccessViolationException on any AV + throw new AccessViolationException(); + } + } + + [DllImport(Win32Native.SHIM, EntryPoint="ND_WU1")] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + public static extern void WriteByte([MarshalAs(UnmanagedType.AsAny),In,Out] Object ptr, int ofs, byte val); + + [System.Security.SecurityCritical] // auto-generated_required + public static void WriteByte(IntPtr ptr, byte val) + { + WriteByte(ptr, 0, val); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static unsafe void WriteInt16(IntPtr ptr, int ofs, short val) + { + try + { + byte *addr = (byte *)ptr + ofs; + if ((unchecked((int)addr) & 0x1) == 0) + { + // aligned write + *((short *)addr) = val; + } + else + { + // unaligned write + byte *valPtr = (byte *)&val; + addr[0] = valPtr[0]; + addr[1] = valPtr[1]; + } + } + catch (NullReferenceException) + { + // this method is documented to throw AccessViolationException on any AV + throw new AccessViolationException(); + } + } + + [DllImport(Win32Native.SHIM, EntryPoint="ND_WI2")] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + public static extern void WriteInt16([MarshalAs(UnmanagedType.AsAny),In,Out] Object ptr, int ofs, short val); + + [System.Security.SecurityCritical] // auto-generated_required + public static void WriteInt16(IntPtr ptr, short val) + { + WriteInt16(ptr, 0, val); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static void WriteInt16(IntPtr ptr, int ofs, char val) + { + WriteInt16(ptr, ofs, (short)val); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static void WriteInt16([In,Out]Object ptr, int ofs, char val) + { + WriteInt16(ptr, ofs, (short)val); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static void WriteInt16(IntPtr ptr, char val) + { + WriteInt16(ptr, 0, (short)val); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static unsafe void WriteInt32(IntPtr ptr, int ofs, int val) + { + try + { + byte *addr = (byte *)ptr + ofs; + if ((unchecked((int)addr) & 0x3) == 0) + { + // aligned write + *((int *)addr) = val; + } + else + { + // unaligned write + byte *valPtr = (byte *)&val; + addr[0] = valPtr[0]; + addr[1] = valPtr[1]; + addr[2] = valPtr[2]; + addr[3] = valPtr[3]; + } + } + catch (NullReferenceException) + { + // this method is documented to throw AccessViolationException on any AV + throw new AccessViolationException(); + } + } + + [DllImport(Win32Native.SHIM, EntryPoint="ND_WI4")] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + public static extern void WriteInt32([MarshalAs(UnmanagedType.AsAny),In,Out] Object ptr, int ofs, int val); + + [System.Security.SecurityCritical] // auto-generated_required + public static void WriteInt32(IntPtr ptr, int val) + { + WriteInt32(ptr,0,val); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static void WriteIntPtr(IntPtr ptr, int ofs, IntPtr val) + { + #if WIN32 + WriteInt32(ptr, ofs, (int)val); + #else + WriteInt64(ptr, ofs, (long)val); + #endif + } + + [System.Security.SecurityCritical] // auto-generated_required + public static void WriteIntPtr([MarshalAs(UnmanagedType.AsAny),In,Out] Object ptr, int ofs, IntPtr val) + { + #if WIN32 + WriteInt32(ptr, ofs, (int)val); + #else + WriteInt64(ptr, ofs, (long)val); + #endif + } + + [System.Security.SecurityCritical] // auto-generated_required + public static void WriteIntPtr(IntPtr ptr, IntPtr val) + { + #if WIN32 + WriteInt32(ptr, 0, (int)val); + #else + WriteInt64(ptr, 0, (long)val); + #endif + } + + [System.Security.SecurityCritical] // auto-generated_required + public static unsafe void WriteInt64(IntPtr ptr, int ofs, long val) + { + try + { + byte *addr = (byte *)ptr + ofs; + if ((unchecked((int)addr) & 0x7) == 0) + { + // aligned write + *((long *)addr) = val; + } + else + { + // unaligned write + byte *valPtr = (byte *)&val; + addr[0] = valPtr[0]; + addr[1] = valPtr[1]; + addr[2] = valPtr[2]; + addr[3] = valPtr[3]; + addr[4] = valPtr[4]; + addr[5] = valPtr[5]; + addr[6] = valPtr[6]; + addr[7] = valPtr[7]; + } + } + catch (NullReferenceException) + { + // this method is documented to throw AccessViolationException on any AV + throw new AccessViolationException(); + } + } + + [DllImport(Win32Native.SHIM, EntryPoint="ND_WI8")] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + public static extern void WriteInt64([MarshalAs(UnmanagedType.AsAny),In,Out] Object ptr, int ofs, long val); + + [System.Security.SecurityCritical] // auto-generated_required + public static void WriteInt64(IntPtr ptr, long val) + { + WriteInt64(ptr, 0, val); + } + + + //==================================================================== + // GetLastWin32Error + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static extern int GetLastWin32Error(); + + + //==================================================================== + // SetLastWin32Error + //==================================================================== + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern void SetLastWin32Error(int error); + + + //==================================================================== + // GetHRForLastWin32Error + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static int GetHRForLastWin32Error() + { + int dwLastError = GetLastWin32Error(); + if ((dwLastError & 0x80000000) == 0x80000000) + return dwLastError; + else + return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000); + } + + + //==================================================================== + // Prelink + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static void Prelink(MethodInfo m) + { + if (m == null) + throw new ArgumentNullException("m"); + Contract.EndContractBlock(); + + RuntimeMethodInfo rmi = m as RuntimeMethodInfo; + + if (rmi == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo")); + + InternalPrelink(rmi); + } + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] + [SecurityCritical] + private static extern void InternalPrelink(IRuntimeMethodInfo m); + + [System.Security.SecurityCritical] // auto-generated_required + public static void PrelinkAll(Type c) + { + if (c == null) + throw new ArgumentNullException("c"); + Contract.EndContractBlock(); + + MethodInfo[] mi = c.GetMethods(); + if (mi != null) + { + for (int i = 0; i < mi.Length; i++) + { + Prelink(mi[i]); + } + } + } + + //==================================================================== + // NumParamBytes + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static int NumParamBytes(MethodInfo m) + { + if (m == null) + throw new ArgumentNullException("m"); + Contract.EndContractBlock(); + + RuntimeMethodInfo rmi = m as RuntimeMethodInfo; + if (rmi == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo")); + + return InternalNumParamBytes(rmi); + } + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] + [SecurityCritical] + private static extern int InternalNumParamBytes(IRuntimeMethodInfo m); + + //==================================================================== + // Win32 Exception stuff + // These are mostly interesting for Structured exception handling, + // but need to be exposed for all exceptions (not just SEHException). + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [System.Runtime.InteropServices.ComVisible(true)] + public static extern /* struct _EXCEPTION_POINTERS* */ IntPtr GetExceptionPointers(); + + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern int GetExceptionCode(); + + + //==================================================================== + // Marshals data from a structure class to a native memory block. + // If the structure contains pointers to allocated blocks and + // "fDeleteOld" is true, this routine will call DestroyStructure() first. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + [System.Runtime.InteropServices.ComVisible(true)] + public static extern void StructureToPtr(Object structure, IntPtr ptr, bool fDeleteOld); + + [System.Security.SecurityCritical] + public static void StructureToPtr<T>(T structure, IntPtr ptr, bool fDeleteOld) + { + StructureToPtr((object)structure, ptr, fDeleteOld); + } + + //==================================================================== + // Marshals data from a native memory block to a preallocated structure class. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [System.Runtime.InteropServices.ComVisible(true)] + public static void PtrToStructure(IntPtr ptr, Object structure) + { + PtrToStructureHelper(ptr, structure, false); + } + + [System.Security.SecurityCritical] + public static void PtrToStructure<T>(IntPtr ptr, T structure) + { + PtrToStructure(ptr, (object)structure); + } + + //==================================================================== + // Creates a new instance of "structuretype" and marshals data from a + // native memory block to it. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [System.Runtime.InteropServices.ComVisible(true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable + public static Object PtrToStructure(IntPtr ptr, Type structureType) + { + if (ptr == IntPtr.Zero) return null; + + if (structureType == null) + throw new ArgumentNullException("structureType"); + + if (structureType.IsGenericType) + throw new ArgumentException(Environment.GetResourceString("Argument_NeedNonGenericType"), "structureType"); + + RuntimeType rt = structureType.UnderlyingSystemType as RuntimeType; + + if (rt == null) + throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "type"); + + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + + Object structure = rt.CreateInstanceDefaultCtor(false /*publicOnly*/, false /*skipCheckThis*/, false /*fillCache*/, ref stackMark); + PtrToStructureHelper(ptr, structure, true); + return structure; + } + + [System.Security.SecurityCritical] + public static T PtrToStructure<T>(IntPtr ptr) + { + return (T)PtrToStructure(ptr, typeof(T)); + } + + //==================================================================== + // Helper function to copy a pointer into a preallocated structure. + //==================================================================== + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void PtrToStructureHelper(IntPtr ptr, Object structure, bool allowValueClasses); + + + //==================================================================== + // Freeds all substructures pointed to by the native memory block. + // "structureclass" is used to provide layout information. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [System.Runtime.InteropServices.ComVisible(true)] + public static extern void DestroyStructure(IntPtr ptr, Type structuretype); + + [System.Security.SecurityCritical] + public static void DestroyStructure<T>(IntPtr ptr) + { + DestroyStructure(ptr, typeof(T)); + } + + //==================================================================== + // Returns the HInstance for this module. Returns -1 if the module + // doesn't have an HInstance. In Memory (Dynamic) Modules won't have + // an HInstance. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr GetHINSTANCE(Module m) + { + if (m == null) + throw new ArgumentNullException("m"); + Contract.EndContractBlock(); + + RuntimeModule rtModule = m as RuntimeModule; + if (rtModule == null) + { + ModuleBuilder mb = m as ModuleBuilder; + if (mb != null) + rtModule = mb.InternalModule; + } + + if (rtModule == null) + throw new ArgumentNullException(Environment.GetResourceString("Argument_MustBeRuntimeModule")); + + return GetHINSTANCE(rtModule.GetNativeHandle()); + } + + [System.Security.SecurityCritical] // auto-generated_required + [SuppressUnmanagedCodeSecurity] + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] + private extern static IntPtr GetHINSTANCE(RuntimeModule m); + + //==================================================================== + // Throws a CLR exception based on the HRESULT. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static void ThrowExceptionForHR(int errorCode) + { + if (errorCode < 0) + ThrowExceptionForHRInternal(errorCode, IntPtr.Zero); + } + [System.Security.SecurityCritical] // auto-generated_required + public static void ThrowExceptionForHR(int errorCode, IntPtr errorInfo) + { + if (errorCode < 0) + ThrowExceptionForHRInternal(errorCode, errorInfo); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void ThrowExceptionForHRInternal(int errorCode, IntPtr errorInfo); + + + //==================================================================== + // Converts the HRESULT to a CLR exception. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static Exception GetExceptionForHR(int errorCode) + { + if (errorCode < 0) + return GetExceptionForHRInternal(errorCode, IntPtr.Zero); + else + return null; + } + [System.Security.SecurityCritical] // auto-generated_required + public static Exception GetExceptionForHR(int errorCode, IntPtr errorInfo) + { + if (errorCode < 0) + return GetExceptionForHRInternal(errorCode, errorInfo); + else + return null; + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern Exception GetExceptionForHRInternal(int errorCode, IntPtr errorInfo); + + + //==================================================================== + // Converts the CLR exception to an HRESULT. This function also sets + // up an IErrorInfo for the exception. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern int GetHRForException(Exception e); + + //==================================================================== + // Converts the CLR exception to an HRESULT. This function also sets + // up an IErrorInfo for the exception. + // This function is only used in WinRT and converts ObjectDisposedException + // to RO_E_CLOSED + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern int GetHRForException_WinRT(Exception e); + + //==================================================================== + // This method is intended for compiler code generators rather + // than applications. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [ObsoleteAttribute("The GetUnmanagedThunkForManagedMethodPtr method has been deprecated and will be removed in a future release.", false)] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern IntPtr GetUnmanagedThunkForManagedMethodPtr(IntPtr pfnMethodToWrap, IntPtr pbSignature, int cbSignature); + + //==================================================================== + // This method is intended for compiler code generators rather + // than applications. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [ObsoleteAttribute("The GetManagedThunkForUnmanagedMethodPtr method has been deprecated and will be removed in a future release.", false)] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern IntPtr GetManagedThunkForUnmanagedMethodPtr(IntPtr pfnMethodToWrap, IntPtr pbSignature, int cbSignature); + + //==================================================================== + // The hosting APIs allow a sophisticated host to schedule fibers + // onto OS threads, so long as they notify the runtime of this + // activity. A fiber cookie can be redeemed for its managed Thread + // object by calling the following service. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [ObsoleteAttribute("The GetThreadFromFiberCookie method has been deprecated. Use the hosting API to perform this operation.", false)] + public static Thread GetThreadFromFiberCookie(int cookie) + { + if (cookie == 0) + throw new ArgumentException(Environment.GetResourceString("Argument_ArgumentZero"), "cookie"); + Contract.EndContractBlock(); + + return InternalGetThreadFromFiberCookie(cookie); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern Thread InternalGetThreadFromFiberCookie(int cookie); + + + //==================================================================== + // Memory allocation and deallocation. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + public static IntPtr AllocHGlobal(IntPtr cb) + { + // For backwards compatibility on 32 bit platforms, ensure we pass values between + // Int32.MaxValue and UInt32.MaxValue to Windows. If the binary has had the + // LARGEADDRESSAWARE bit set in the PE header, it may get 3 or 4 GB of user mode + // address space. It is remotely that those allocations could have succeeded, + // though I couldn't reproduce that. In either case, that means we should continue + // throwing an OOM instead of an ArgumentOutOfRangeException for "negative" amounts of memory. + UIntPtr numBytes; +#if WIN32 + numBytes = new UIntPtr(unchecked((uint)cb.ToInt32())); +#else + numBytes = new UIntPtr(unchecked((ulong)cb.ToInt64())); +#endif + + IntPtr pNewMem = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, unchecked(numBytes)); + + if (pNewMem == IntPtr.Zero) { + throw new OutOfMemoryException(); + } + return pNewMem; + } + + [System.Security.SecurityCritical] // auto-generated_required + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + public static IntPtr AllocHGlobal(int cb) + { + return AllocHGlobal((IntPtr)cb); + } + + [System.Security.SecurityCritical] // auto-generated_required + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static void FreeHGlobal(IntPtr hglobal) + { + if (IsNotWin32Atom(hglobal)) { + if (IntPtr.Zero != Win32Native.LocalFree(hglobal)) { + ThrowExceptionForHR(GetHRForLastWin32Error()); + } + } + } + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr ReAllocHGlobal(IntPtr pv, IntPtr cb) + { + IntPtr pNewMem = Win32Native.LocalReAlloc(pv, cb, LMEM_MOVEABLE); + if (pNewMem == IntPtr.Zero) { + throw new OutOfMemoryException(); + } + return pNewMem; + } + + + //==================================================================== + // String convertions. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + unsafe public static IntPtr StringToHGlobalAnsi(String s) + { + if (s == null) + { + return IntPtr.Zero; + } + else + { + int nb = (s.Length + 1) * SystemMaxDBCSCharSize; + + // Overflow checking + if (nb < s.Length) + throw new ArgumentOutOfRangeException("s"); + + UIntPtr len = new UIntPtr((uint)nb); + IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len); + + if (hglobal == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + else + { + s.ConvertToAnsi((byte *)hglobal, nb, false, false); + return hglobal; + } + } + } + + [System.Security.SecurityCritical] // auto-generated_required + unsafe public static IntPtr StringToHGlobalUni(String s) + { + if (s == null) + { + return IntPtr.Zero; + } + else + { + int nb = (s.Length + 1) * 2; + + // Overflow checking + if (nb < s.Length) + throw new ArgumentOutOfRangeException("s"); + + UIntPtr len = new UIntPtr((uint)nb); + IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len); + + if (hglobal == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + else + { + fixed (char* firstChar = s) + { + String.wstrcpy((char*)hglobal, firstChar, s.Length + 1); + } + return hglobal; + } + } + } + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr StringToHGlobalAuto(String s) + { + // Ansi platforms are no longer supported + return StringToHGlobalUni(s); + } + +#if FEATURE_COMINTEROP + + internal static readonly Guid ManagedNameGuid = new Guid("{0F21F359-AB84-41E8-9A78-36D110E6D2F9}"); + + //==================================================================== + // Given a managed object that wraps a UCOMITypeLib, return its name + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [Obsolete("Use System.Runtime.InteropServices.Marshal.GetTypeLibName(ITypeLib pTLB) instead. http://go.microsoft.com/fwlink/?linkid=14202&ID=0000011.", false)] + public static String GetTypeLibName(UCOMITypeLib pTLB) + { + return GetTypeLibName((ITypeLib)pTLB); + } + + + //==================================================================== + // Given a managed object that wraps an ITypeLib, return its name + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static String GetTypeLibName(ITypeLib typelib) + { + if (typelib == null) + throw new ArgumentNullException("typelib"); + Contract.EndContractBlock(); + + String strTypeLibName = null; + String strDocString = null; + int dwHelpContext = 0; + String strHelpFile = null; + + typelib.GetDocumentation(-1, out strTypeLibName, out strDocString, out dwHelpContext, out strHelpFile); + + return strTypeLibName; + } + + //==================================================================== + // Internal version of GetTypeLibName + // Support GUID_ManagedName which aligns with TlbImp + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + internal static String GetTypeLibNameInternal(ITypeLib typelib) + { + if (typelib == null) + throw new ArgumentNullException("typelib"); + Contract.EndContractBlock(); + + // Try GUID_ManagedName first + ITypeLib2 typeLib2 = typelib as ITypeLib2; + if (typeLib2 != null) + { + Guid guid = ManagedNameGuid; + object val; + + try + { + typeLib2.GetCustData(ref guid, out val); + } + catch(Exception) + { + val = null; + } + + if (val != null && val.GetType() == typeof(string)) + { + string customManagedNamespace = (string)val; + customManagedNamespace = customManagedNamespace.Trim(); + if (customManagedNamespace.EndsWith(".DLL", StringComparison.OrdinalIgnoreCase)) + customManagedNamespace = customManagedNamespace.Substring(0, customManagedNamespace.Length - 4); + else if (customManagedNamespace.EndsWith(".EXE", StringComparison.OrdinalIgnoreCase)) + customManagedNamespace = customManagedNamespace.Substring(0, customManagedNamespace.Length - 4); + return customManagedNamespace; + } + } + + return GetTypeLibName(typelib); + } + + + //==================================================================== + // Given an managed object that wraps an UCOMITypeLib, return its guid + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [Obsolete("Use System.Runtime.InteropServices.Marshal.GetTypeLibGuid(ITypeLib pTLB) instead. http://go.microsoft.com/fwlink/?linkid=14202&ID=0000011.", false)] + public static Guid GetTypeLibGuid(UCOMITypeLib pTLB) + { + return GetTypeLibGuid((ITypeLib)pTLB); + } + + //==================================================================== + // Given an managed object that wraps an ITypeLib, return its guid + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static Guid GetTypeLibGuid(ITypeLib typelib) + { + Guid result = new Guid (); + FCallGetTypeLibGuid (ref result, typelib); + return result; + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void FCallGetTypeLibGuid(ref Guid result, ITypeLib pTLB); + + //==================================================================== + // Given a managed object that wraps a UCOMITypeLib, return its lcid + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [Obsolete("Use System.Runtime.InteropServices.Marshal.GetTypeLibLcid(ITypeLib pTLB) instead. http://go.microsoft.com/fwlink/?linkid=14202&ID=0000011.", false)] + public static int GetTypeLibLcid(UCOMITypeLib pTLB) + { + return GetTypeLibLcid((ITypeLib)pTLB); + } + + //==================================================================== + // Given a managed object that wraps an ITypeLib, return its lcid + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern int GetTypeLibLcid(ITypeLib typelib); + + //==================================================================== + // Given a managed object that wraps an ITypeLib, return it's + // version information. + //==================================================================== + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void GetTypeLibVersion(ITypeLib typeLibrary, out int major, out int minor); + + //==================================================================== + // Given a managed object that wraps an ITypeInfo, return its guid. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated + internal static Guid GetTypeInfoGuid(ITypeInfo typeInfo) + { + Guid result = new Guid (); + FCallGetTypeInfoGuid (ref result, typeInfo); + return result; + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void FCallGetTypeInfoGuid(ref Guid result, ITypeInfo typeInfo); + + //==================================================================== + // Given a assembly, return the TLBID that will be generated for the + // typelib exported from the assembly. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static Guid GetTypeLibGuidForAssembly(Assembly asm) + { + if (asm == null) + throw new ArgumentNullException("asm"); + Contract.EndContractBlock(); + + RuntimeAssembly rtAssembly = asm as RuntimeAssembly; + if (rtAssembly == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"), "asm"); + + Guid result = new Guid(); + FCallGetTypeLibGuidForAssembly(ref result, rtAssembly); + return result; + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void FCallGetTypeLibGuidForAssembly(ref Guid result, RuntimeAssembly asm); + + //==================================================================== + // Given a assembly, return the version number of the type library + // that would be exported from the assembly. + //==================================================================== + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void _GetTypeLibVersionForAssembly(RuntimeAssembly inputAssembly, out int majorVersion, out int minorVersion); + + [System.Security.SecurityCritical] // auto-generated_required + public static void GetTypeLibVersionForAssembly(Assembly inputAssembly, out int majorVersion, out int minorVersion) + { + if (inputAssembly == null) + throw new ArgumentNullException("inputAssembly"); + Contract.EndContractBlock(); + + RuntimeAssembly rtAssembly = inputAssembly as RuntimeAssembly; + if (rtAssembly == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"), "inputAssembly"); + + _GetTypeLibVersionForAssembly(rtAssembly, out majorVersion, out minorVersion); + } + + //==================================================================== + // Given a managed object that wraps an UCOMITypeInfo, return its name + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [Obsolete("Use System.Runtime.InteropServices.Marshal.GetTypeInfoName(ITypeInfo pTLB) instead. http://go.microsoft.com/fwlink/?linkid=14202&ID=0000011.", false)] + public static String GetTypeInfoName(UCOMITypeInfo pTI) + { + return GetTypeInfoName((ITypeInfo)pTI); + } + + //==================================================================== + // Given a managed object that wraps an ITypeInfo, return its name + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static String GetTypeInfoName(ITypeInfo typeInfo) + { + if (typeInfo == null) + throw new ArgumentNullException("typeInfo"); + Contract.EndContractBlock(); + + String strTypeLibName = null; + String strDocString = null; + int dwHelpContext = 0; + String strHelpFile = null; + + typeInfo.GetDocumentation(-1, out strTypeLibName, out strDocString, out dwHelpContext, out strHelpFile); + + return strTypeLibName; + } + + //==================================================================== + // Internal version of GetTypeInfoName + // Support GUID_ManagedName which aligns with TlbImp + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + internal static String GetTypeInfoNameInternal(ITypeInfo typeInfo, out bool hasManagedName) + { + if (typeInfo == null) + throw new ArgumentNullException("typeInfo"); + Contract.EndContractBlock(); + + // Try ManagedNameGuid first + ITypeInfo2 typeInfo2 = typeInfo as ITypeInfo2; + if (typeInfo2 != null) + { + Guid guid = ManagedNameGuid; + object val; + + try + { + typeInfo2.GetCustData(ref guid, out val); + } + catch(Exception) + { + val = null; + } + + if (val != null && val.GetType() == typeof(string)) + { + hasManagedName = true; + return (string)val; + } + } + + hasManagedName = false; + return GetTypeInfoName(typeInfo); + } + + //==================================================================== + // Get the corresponding managed name as converted by TlbImp + // Used to get the type using GetType() from imported assemblies + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + internal static String GetManagedTypeInfoNameInternal(ITypeLib typeLib, ITypeInfo typeInfo) + { + bool hasManagedName; + string name = GetTypeInfoNameInternal(typeInfo, out hasManagedName); + if (hasManagedName) + return name; + else + return GetTypeLibNameInternal(typeLib) + "." + name; + } + + //==================================================================== + // If a type with the specified GUID is loaded, this method will + // return the reflection type that represents it. Otherwise it returns + // NULL. + //==================================================================== + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern Type GetLoadedTypeForGUID(ref Guid guid); + +#if !FEATURE_CORECLR // current implementation requires reflection only load + //==================================================================== + // map ITypeInfo* to Type + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static Type GetTypeForITypeInfo(IntPtr /* ITypeInfo* */ piTypeInfo) + { + ITypeInfo pTI = null; + ITypeLib pTLB = null; + Type TypeObj = null; + Assembly AsmBldr = null; + TypeLibConverter TlbConverter = null; + int Index = 0; + Guid clsid; + + // If the input ITypeInfo is NULL then return NULL. + if (piTypeInfo == IntPtr.Zero) + return null; + + // Wrap the ITypeInfo in a CLR object. + pTI = (ITypeInfo)GetObjectForIUnknown(piTypeInfo); + + // Check to see if a class exists with the specified GUID. + + clsid = GetTypeInfoGuid(pTI); + TypeObj = GetLoadedTypeForGUID(ref clsid); + + // If we managed to find the type based on the GUID then return it. + if (TypeObj != null) + return TypeObj; + + // There is no type with the specified GUID in the app domain so lets + // try and convert the containing typelib. + try + { + pTI.GetContainingTypeLib(out pTLB, out Index); + } + catch(COMException) + { + pTLB = null; + } + + // Check to see if we managed to get a containing typelib. + if (pTLB != null) + { + // Get the assembly name from the typelib. + AssemblyName AsmName = TypeLibConverter.GetAssemblyNameFromTypelib(pTLB, null, null, null, null, AssemblyNameFlags.None); + String AsmNameString = AsmName.FullName; + + // Check to see if the assembly that will contain the type already exists. + Assembly[] aAssemblies = Thread.GetDomain().GetAssemblies(); + int NumAssemblies = aAssemblies.Length; + for (int i = 0; i < NumAssemblies; i++) + { + if (String.Compare(aAssemblies[i].FullName, + AsmNameString,StringComparison.Ordinal) == 0) + AsmBldr = aAssemblies[i]; + } + + // If we haven't imported the assembly yet then import it. + if (AsmBldr == null) + { + TlbConverter = new TypeLibConverter(); + AsmBldr = TlbConverter.ConvertTypeLibToAssembly(pTLB, + GetTypeLibName(pTLB) + ".dll", 0, new ImporterCallback(), null, null, null, null); + } + + // Load the type object from the imported typelib. + // Call GetManagedTypeInfoNameInternal to align with TlbImp behavior + TypeObj = AsmBldr.GetType(GetManagedTypeInfoNameInternal(pTLB, pTI), true, false); + if (TypeObj != null && !TypeObj.IsVisible) + TypeObj = null; + } + else + { + // If the ITypeInfo does not have a containing typelib then simply + // return Object as the type. + TypeObj = typeof(Object); + } + + return TypeObj; + } +#endif // #if !FEATURE_CORECLR + + // This method is identical to Type.GetTypeFromCLSID. Since it's interop specific, we expose it + // on Marshal for more consistent API surface. +#if !FEATURE_CORECLR + [System.Security.SecuritySafeCritical] +#endif //!FEATURE_CORECLR + public static Type GetTypeFromCLSID(Guid clsid) + { + return RuntimeType.GetTypeFromCLSIDImpl(clsid, null, false); + } + + //==================================================================== + // map Type to ITypeInfo* + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern IntPtr /* ITypeInfo* */ GetITypeInfoForType(Type t); + + //==================================================================== + // return the IUnknown* for an Object if the current context + // is the one where the RCW was first seen. Will return null + // otherwise. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr /* IUnknown* */ GetIUnknownForObject(Object o) + { + return GetIUnknownForObjectNative(o, false); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr /* IUnknown* */ GetIUnknownForObjectInContext(Object o) + { + return GetIUnknownForObjectNative(o, true); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern IntPtr /* IUnknown* */ GetIUnknownForObjectNative(Object o, bool onlyInContext); + + //==================================================================== + // return the raw IUnknown* for a COM Object not related to current + // context + // Does not call AddRef + //==================================================================== + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern IntPtr /* IUnknown* */ GetRawIUnknownForComObjectNoAddRef(Object o); + + //==================================================================== + // return the IDispatch* for an Object + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr /* IDispatch */ GetIDispatchForObject(Object o) + { + return GetIDispatchForObjectNative(o, false); + } + + //==================================================================== + // return the IDispatch* for an Object if the current context + // is the one where the RCW was first seen. Will return null + // otherwise. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr /* IUnknown* */ GetIDispatchForObjectInContext(Object o) + { + return GetIDispatchForObjectNative(o, true); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern IntPtr /* IUnknown* */ GetIDispatchForObjectNative(Object o, bool onlyInContext); + + //==================================================================== + // return the IUnknown* representing the interface for the Object + // Object o should support Type T + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type T) + { + return GetComInterfaceForObjectNative(o, T, false, true); + } + + [System.Security.SecurityCritical] + public static IntPtr GetComInterfaceForObject<T, TInterface>(T o) + { + return GetComInterfaceForObject(o, typeof(TInterface)); + } + + //==================================================================== + // return the IUnknown* representing the interface for the Object + // Object o should support Type T, it refer the value of mode to + // invoke customized QueryInterface or not + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type T, CustomQueryInterfaceMode mode) + { + bool bEnableCustomizedQueryInterface = ((mode == CustomQueryInterfaceMode.Allow) ? true : false); + return GetComInterfaceForObjectNative(o, T, false, bEnableCustomizedQueryInterface); + } + + //==================================================================== + // return the IUnknown* representing the interface for the Object + // Object o should support Type T if the current context + // is the one where the RCW was first seen. Will return null + // otherwise. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr /* IUnknown* */ GetComInterfaceForObjectInContext(Object o, Type t) + { + return GetComInterfaceForObjectNative(o, t, true, true); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern IntPtr /* IUnknown* */ GetComInterfaceForObjectNative(Object o, Type t, bool onlyInContext, bool fEnalbeCustomizedQueryInterface); + + //==================================================================== + // return an Object for IUnknown + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern Object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk); + + //==================================================================== + // Return a unique Object given an IUnknown. This ensures that you + // receive a fresh object (we will not look in the cache to match up this + // IUnknown to an already existing object). This is useful in cases + // where you want to be able to call ReleaseComObject on a RCW + // and not worry about other active uses of said RCW. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern Object GetUniqueObjectForIUnknown(IntPtr unknown); + + //==================================================================== + // return an Object for IUnknown, using the Type T, + // NOTE: + // Type T should be either a COM imported Type or a sub-type of COM + // imported Type + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern Object GetTypedObjectForIUnknown(IntPtr /* IUnknown* */ pUnk, Type t); + + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern IntPtr CreateAggregatedObject(IntPtr pOuter, Object o); + + [System.Security.SecurityCritical] + public static IntPtr CreateAggregatedObject<T>(IntPtr pOuter, T o) + { + return CreateAggregatedObject(pOuter, (object)o); + } + + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern void CleanupUnusedObjectsInCurrentContext(); + + [System.Security.SecurityCritical] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern bool AreComObjectsAvailableForCleanup(); + + //==================================================================== + // check if the object is classic COM component + //==================================================================== +#if !FEATURE_CORECLR // with FEATURE_CORECLR, the whole type is SecurityCritical + [System.Security.SecuritySafeCritical] +#endif + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern bool IsComObject(Object o); + +#endif // FEATURE_COMINTEROP + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr AllocCoTaskMem(int cb) + { + IntPtr pNewMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)cb)); + if (pNewMem == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + return pNewMem; + } + + [System.Security.SecurityCritical] // auto-generated_required + unsafe public static IntPtr StringToCoTaskMemUni(String s) + { + if (s == null) + { + return IntPtr.Zero; + } + else + { + int nb = (s.Length + 1) * 2; + + // Overflow checking + if (nb < s.Length) + throw new ArgumentOutOfRangeException("s"); + + IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb)); + + if (hglobal == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + else + { + fixed (char* firstChar = s) + { + String.wstrcpy((char *)hglobal, firstChar, s.Length + 1); + } + return hglobal; + } + } + } + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr StringToCoTaskMemAuto(String s) + { + // Ansi platforms are no longer supported + return StringToCoTaskMemUni(s); + } + + [System.Security.SecurityCritical] // auto-generated_required + unsafe public static IntPtr StringToCoTaskMemAnsi(String s) + { + if (s == null) + { + return IntPtr.Zero; + } + else + { + int nb = (s.Length + 1) * SystemMaxDBCSCharSize; + + // Overflow checking + if (nb < s.Length) + throw new ArgumentOutOfRangeException("s"); + + IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb)); + + if (hglobal == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + else + { + s.ConvertToAnsi((byte *)hglobal, nb, false, false); + return hglobal; + } + } + } + + [System.Security.SecurityCritical] // auto-generated_required + public static void FreeCoTaskMem(IntPtr ptr) + { + if (IsNotWin32Atom(ptr)) { + Win32Native.CoTaskMemFree(ptr); + } + } + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr ReAllocCoTaskMem(IntPtr pv, int cb) + { + IntPtr pNewMem = Win32Native.CoTaskMemRealloc(pv, new UIntPtr((uint)cb)); + if (pNewMem == IntPtr.Zero && cb != 0) + { + throw new OutOfMemoryException(); + } + return pNewMem; + } + + +#if FEATURE_COMINTEROP + //==================================================================== + // release the COM component and if the reference hits 0 zombie this object + // further usage of this Object might throw an exception + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static int ReleaseComObject(Object o) + { + __ComObject co = null; + + // Make sure the obj is an __ComObject. + try + { + co = (__ComObject)o; + } + catch (InvalidCastException) + { + throw new ArgumentException(Environment.GetResourceString("Argument_ObjNotComObject"), "o"); + } + + return co.ReleaseSelf(); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern int InternalReleaseComObject(Object o); + + + //==================================================================== + // release the COM component and zombie this object + // further usage of this Object might throw an exception + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static Int32 FinalReleaseComObject(Object o) + { + if (o == null) + throw new ArgumentNullException("o"); + Contract.EndContractBlock(); + + __ComObject co = null; + + // Make sure the obj is an __ComObject. + try + { + co = (__ComObject)o; + } + catch (InvalidCastException) + { + throw new ArgumentException(Environment.GetResourceString("Argument_ObjNotComObject"), "o"); + } + + co.FinalReleaseSelf(); + + return 0; + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void InternalFinalReleaseComObject(Object o); + + //==================================================================== + // This method retrieves data from the COM object. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static Object GetComObjectData(Object obj, Object key) + { + // Validate that the arguments aren't null. + if (obj == null) + throw new ArgumentNullException("obj"); + if (key == null) + throw new ArgumentNullException("key"); + Contract.EndContractBlock(); + + __ComObject comObj = null; + + // Make sure the obj is an __ComObject. + try + { + comObj = (__ComObject)obj; + } + catch (InvalidCastException) + { + throw new ArgumentException(Environment.GetResourceString("Argument_ObjNotComObject"), "obj"); + } + + if (obj.GetType().IsWindowsRuntimeObject) + { + throw new ArgumentException(Environment.GetResourceString("Argument_ObjIsWinRTObject"), "obj"); + } + + // Retrieve the data from the __ComObject. + return comObj.GetData(key); + } + + //==================================================================== + // This method sets data on the COM object. The data can only be set + // once for a given key and cannot be removed. This function returns + // true if the data has been added, false if the data could not be + // added because there already was data for the specified key. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static bool SetComObjectData(Object obj, Object key, Object data) + { + // Validate that the arguments aren't null. The data can validly be null. + if (obj == null) + throw new ArgumentNullException("obj"); + if (key == null) + throw new ArgumentNullException("key"); + Contract.EndContractBlock(); + + __ComObject comObj = null; + + // Make sure the obj is an __ComObject. + try + { + comObj = (__ComObject)obj; + } + catch (InvalidCastException) + { + throw new ArgumentException(Environment.GetResourceString("Argument_ObjNotComObject"), "obj"); + } + + if (obj.GetType().IsWindowsRuntimeObject) + { + throw new ArgumentException(Environment.GetResourceString("Argument_ObjIsWinRTObject"), "obj"); + } + + // Retrieve the data from the __ComObject. + return comObj.SetData(key, data); + } + + //==================================================================== + // This method takes the given COM object and wraps it in an object + // of the specified type. The type must be derived from __ComObject. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static Object CreateWrapperOfType(Object o, Type t) + { + // Validate the arguments. + if (t == null) + throw new ArgumentNullException("t"); + if (!t.IsCOMObject) + throw new ArgumentException(Environment.GetResourceString("Argument_TypeNotComObject"), "t"); + if (t.IsGenericType) + throw new ArgumentException(Environment.GetResourceString("Argument_NeedNonGenericType"), "t"); + Contract.EndContractBlock(); + + if (t.IsWindowsRuntimeObject) + throw new ArgumentException(Environment.GetResourceString("Argument_TypeIsWinRTType"), "t"); + + // Check for the null case. + if (o == null) + return null; + + // Make sure the object is a COM object. + if (!o.GetType().IsCOMObject) + throw new ArgumentException(Environment.GetResourceString("Argument_ObjNotComObject"), "o"); + if (o.GetType().IsWindowsRuntimeObject) + throw new ArgumentException(Environment.GetResourceString("Argument_ObjIsWinRTObject"), "o"); + + // Check to see if the type of the object is the requested type. + if (o.GetType() == t) + return o; + + // Check to see if we already have a cached wrapper for this type. + Object Wrapper = GetComObjectData(o, t); + if (Wrapper == null) + { + // Create the wrapper for the specified type. + Wrapper = InternalCreateWrapperOfType(o, t); + + // Attempt to cache the wrapper on the object. + if (!SetComObjectData(o, t, Wrapper)) + { + // Another thead already cached the wrapper so use that one instead. + Wrapper = GetComObjectData(o, t); + } + } + + return Wrapper; + } + + [System.Security.SecurityCritical] + public static TWrapper CreateWrapperOfType<T, TWrapper>(T o) + { + return (TWrapper)CreateWrapperOfType(o, typeof(TWrapper)); + } + + //==================================================================== + // Helper method called from CreateWrapperOfType. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern Object InternalCreateWrapperOfType(Object o, Type t); + + //==================================================================== + // There may be a thread-based cache of COM components. This service can + // force the aggressive release of the current thread's cache. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [Obsolete("This API did not perform any operation and will be removed in future versions of the CLR.", false)] + public static void ReleaseThreadCache() + { + } + + //==================================================================== + // check if the type is visible from COM. + //==================================================================== + [System.Security.SecuritySafeCritical] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern bool IsTypeVisibleFromCom(Type t); + + //==================================================================== + // IUnknown Helpers + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern int /* HRESULT */ QueryInterface(IntPtr /* IUnknown */ pUnk, ref Guid iid, out IntPtr ppv); + + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern int /* ULONG */ AddRef(IntPtr /* IUnknown */ pUnk ); + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static extern int /* ULONG */ Release(IntPtr /* IUnknown */ pUnk ); + + //==================================================================== + // BSTR allocation and dealocation. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static void FreeBSTR(IntPtr ptr) + { + if (IsNotWin32Atom(ptr)) { + Win32Native.SysFreeString(ptr); + } + } + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr StringToBSTR(String s) + { + if (s == null) + return IntPtr.Zero; + + // Overflow checking + if (s.Length+1 < s.Length) + throw new ArgumentOutOfRangeException("s"); + + IntPtr bstr = Win32Native.SysAllocStringLen(s, s.Length); + if (bstr == IntPtr.Zero) + throw new OutOfMemoryException(); + + return bstr; + } + + [System.Security.SecurityCritical] // auto-generated_required + public static String PtrToStringBSTR(IntPtr ptr) + { + return PtrToStringUni(ptr, (int)Win32Native.SysStringLen(ptr)); + } + + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern void GetNativeVariantForObject(Object obj, /* VARIANT * */ IntPtr pDstNativeVariant); + + [System.Security.SecurityCritical] + public static void GetNativeVariantForObject<T>(T obj, IntPtr pDstNativeVariant) + { + GetNativeVariantForObject((object)obj, pDstNativeVariant); + } + + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern Object GetObjectForNativeVariant(/* VARIANT * */ IntPtr pSrcNativeVariant ); + + [System.Security.SecurityCritical] + public static T GetObjectForNativeVariant<T>(IntPtr pSrcNativeVariant) + { + return (T)GetObjectForNativeVariant(pSrcNativeVariant); + } + + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern Object[] GetObjectsForNativeVariants(/* VARIANT * */ IntPtr aSrcNativeVariant, int cVars ); + + [System.Security.SecurityCritical] + public static T[] GetObjectsForNativeVariants<T>(IntPtr aSrcNativeVariant, int cVars) + { + object[] objects = GetObjectsForNativeVariants(aSrcNativeVariant, cVars); + T[] result = null; + + if (objects != null) + { + result = new T[objects.Length]; + Array.Copy(objects, result, objects.Length); + } + + return result; + } + + /// <summary> + /// <para>Returns the first valid COM slot that GetMethodInfoForSlot will work on + /// This will be 3 for IUnknown based interfaces and 7 for IDispatch based interfaces. </para> + /// </summary> + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern int GetStartComSlot(Type t); + + /// <summary> + /// <para>Returns the last valid COM slot that GetMethodInfoForSlot will work on. </para> + /// </summary> + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern int GetEndComSlot(Type t); + + /// <summary> + /// <para>Returns the MemberInfo that COM callers calling through the exposed + /// vtable on the given slot will be calling. The slot should take into account + /// if the exposed interface is IUnknown based or IDispatch based. + /// For classes, the lookup is done on the default interface that will be + /// exposed for the class. </para> + /// </summary> + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern MemberInfo GetMethodInfoForComSlot(Type t, int slot, ref ComMemberType memberType); + + /// <summary> + /// <para>Returns the COM slot for a memeber info, taking into account whether + /// the exposed interface is IUnknown based or IDispatch based</para> + /// </summary> + [System.Security.SecurityCritical] // auto-generated_required + public static int GetComSlotForMethodInfo(MemberInfo m) + { + if (m== null) + throw new ArgumentNullException("m"); + + if (!(m is RuntimeMethodInfo)) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo"), "m"); + + if (!m.DeclaringType.IsInterface) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeInterfaceMethod"), "m"); + if (m.DeclaringType.IsGenericType) + throw new ArgumentException(Environment.GetResourceString("Argument_NeedNonGenericType"), "m"); + Contract.EndContractBlock(); + + return InternalGetComSlotForMethodInfo((IRuntimeMethodInfo)m); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern int InternalGetComSlotForMethodInfo(IRuntimeMethodInfo m); + + //==================================================================== + // This method generates a GUID for the specified type. If the type + // has a GUID in the metadata then it is returned otherwise a stable + // guid GUID is generated based on the fully qualified name of the + // type. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static Guid GenerateGuidForType(Type type) + { + Guid result = new Guid (); + FCallGenerateGuidForType (ref result, type); + return result; + } + + // The full assembly name is used to compute the GUID, so this should be SxS-safe + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void FCallGenerateGuidForType(ref Guid result, Type type); + + //==================================================================== + // This method generates a PROGID for the specified type. If the type + // has a PROGID in the metadata then it is returned otherwise a stable + // PROGID is generated based on the fully qualified name of the + // type. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static String GenerateProgIdForType(Type type) + { + if (type == null) + throw new ArgumentNullException("type"); + if (type.IsImport) + throw new ArgumentException(Environment.GetResourceString("Argument_TypeMustNotBeComImport"), "type"); + if (type.IsGenericType) + throw new ArgumentException(Environment.GetResourceString("Argument_NeedNonGenericType"), "type"); + Contract.EndContractBlock(); + + if (!RegistrationServices.TypeRequiresRegistrationHelper(type)) + throw new ArgumentException(Environment.GetResourceString("Argument_TypeMustBeComCreatable"), "type"); + + IList<CustomAttributeData> cas = CustomAttributeData.GetCustomAttributes(type); + for (int i = 0; i < cas.Count; i ++) + { + if (cas[i].Constructor.DeclaringType == typeof(ProgIdAttribute)) + { + // Retrieve the PROGID string from the ProgIdAttribute. + IList<CustomAttributeTypedArgument> caConstructorArgs = cas[i].ConstructorArguments; + Contract.Assert(caConstructorArgs.Count == 1, "caConstructorArgs.Count == 1"); + + CustomAttributeTypedArgument progIdConstructorArg = caConstructorArgs[0]; + Contract.Assert(progIdConstructorArg.ArgumentType == typeof(String), "progIdConstructorArg.ArgumentType == typeof(String)"); + + String strProgId = (String)progIdConstructorArg.Value; + + if (strProgId == null) + strProgId = String.Empty; + + return strProgId; + } + } + + // If there is no prog ID attribute then use the full name of the type as the prog id. + return type.FullName; + } + + //==================================================================== + // This method binds to the specified moniker. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static Object BindToMoniker(String monikerName) + { + Object obj = null; + IBindCtx bindctx = null; + CreateBindCtx(0, out bindctx); + + UInt32 cbEaten; + IMoniker pmoniker = null; + MkParseDisplayName(bindctx, monikerName, out cbEaten, out pmoniker); + + BindMoniker(pmoniker, 0, ref IID_IUnknown, out obj); + return obj; + } + + //==================================================================== + // This method gets the currently running object. + //==================================================================== + [System.Security.SecurityCritical] // auto-generated_required + public static Object GetActiveObject(String progID) + { + Object obj = null; + Guid clsid; + + // Call CLSIDFromProgIDEx first then fall back on CLSIDFromProgID if + // CLSIDFromProgIDEx doesn't exist. + try + { + CLSIDFromProgIDEx(progID, out clsid); + } +// catch + catch(Exception) + { + CLSIDFromProgID(progID, out clsid); + } + + GetActiveObject(ref clsid, IntPtr.Zero, out obj); + return obj; + } + + [DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + private static extern void CLSIDFromProgIDEx([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid); + + [DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + private static extern void CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid); + + [DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + private static extern void CreateBindCtx(UInt32 reserved, out IBindCtx ppbc); + + [DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + private static extern void MkParseDisplayName(IBindCtx pbc, [MarshalAs(UnmanagedType.LPWStr)] String szUserName, out UInt32 pchEaten, out IMoniker ppmk); + + [DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + private static extern void BindMoniker(IMoniker pmk, UInt32 grfOpt, ref Guid iidResult, [MarshalAs(UnmanagedType.Interface)] out Object ppvResult); + + [DllImport(Microsoft.Win32.Win32Native.OLEAUT32, PreserveSig = false)] + [SuppressUnmanagedCodeSecurity] + [System.Security.SecurityCritical] // auto-generated + private static extern void GetActiveObject(ref Guid rclsid, IntPtr reserved, [MarshalAs(UnmanagedType.Interface)] out Object ppunk); + + //======================================================================== + // Private method called from remoting to support ServicedComponents. + //======================================================================== + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern bool InternalSwitchCCW(Object oldtp, Object newtp); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern Object InternalWrapIUnknownWithComObject(IntPtr i); + + //======================================================================== + // Private method called from EE upon use of license/ICF2 marshaling. + //======================================================================== + [SecurityCritical] + private static IntPtr LoadLicenseManager() + { + Assembly sys = Assembly.Load("System, Version="+ ThisAssembly.Version + + ", Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken); + Type t = sys.GetType("System.ComponentModel.LicenseManager"); + if (t == null || !t.IsVisible) + return IntPtr.Zero; + return t.TypeHandle.Value; + } + + [System.Security.SecurityCritical] // auto-generated_required + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern void ChangeWrapperHandleStrength(Object otp, bool fIsWeak); + + [System.Security.SecurityCritical] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void InitializeWrapperForWinRT(object o, ref IntPtr pUnk); + +#if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION + [System.Security.SecurityCritical] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void InitializeManagedWinRTFactoryObject(object o, RuntimeType runtimeClassType); +#endif + + //======================================================================== + // Create activation factory and wraps it with a unique RCW + //======================================================================== + [System.Security.SecurityCritical] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern object GetNativeActivationFactory(Type type); + + //======================================================================== + // Methods allowing retrieval of the IIDs exposed by an underlying WinRT + // object, as specified by the object's IInspectable::GetIids() + //======================================================================== + [System.Security.SecurityCritical] + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] + private static extern void _GetInspectableIids(ObjectHandleOnStack obj, ObjectHandleOnStack guids); + + [System.Security.SecurityCritical] + internal static System.Guid[] GetInspectableIids(object obj) + { + System.Guid[] result = null; + System.__ComObject comObj = obj as System.__ComObject; + if (comObj != null) + { + _GetInspectableIids(JitHelpers.GetObjectHandleOnStack(ref comObj), + JitHelpers.GetObjectHandleOnStack(ref result)); + } + + return result; + } + + //======================================================================== + // Methods allowing retrieval of the cached WinRT type corresponding to + // the specified GUID + //======================================================================== + [System.Security.SecurityCritical] + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] + private static extern void _GetCachedWinRTTypeByIid( + ObjectHandleOnStack appDomainObj, + System.Guid iid, + out IntPtr rthHandle); + + [System.Security.SecurityCritical] + internal static System.Type GetCachedWinRTTypeByIid( + System.AppDomain ad, + System.Guid iid) + { + IntPtr rthHandle; + _GetCachedWinRTTypeByIid(JitHelpers.GetObjectHandleOnStack(ref ad), + iid, + out rthHandle); + System.Type res = Type.GetTypeFromHandleUnsafe(rthHandle); + return res; + } + + + //======================================================================== + // Methods allowing retrieval of the WinRT types cached in the specified + // app domain + //======================================================================== + [System.Security.SecurityCritical] + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] + private static extern void _GetCachedWinRTTypes( + ObjectHandleOnStack appDomainObj, + ref int epoch, + ObjectHandleOnStack winrtTypes); + + [System.Security.SecurityCritical] + internal static System.Type[] GetCachedWinRTTypes( + System.AppDomain ad, + ref int epoch) + { + System.IntPtr[] res = null; + + _GetCachedWinRTTypes(JitHelpers.GetObjectHandleOnStack(ref ad), + ref epoch, + JitHelpers.GetObjectHandleOnStack(ref res)); + + System.Type[] result = new System.Type[res.Length]; + for (int i = 0; i < res.Length; ++i) + { + result[i] = Type.GetTypeFromHandleUnsafe(res[i]); + } + + return result; + } + + [System.Security.SecurityCritical] + internal static System.Type[] GetCachedWinRTTypes( + System.AppDomain ad) + { + int dummyEpoch = 0; + return GetCachedWinRTTypes(ad, ref dummyEpoch); + } + + +#endif // FEATURE_COMINTEROP + + [System.Security.SecurityCritical] // auto-generated_required + public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t) + { + // Validate the parameters + if (ptr == IntPtr.Zero) + throw new ArgumentNullException("ptr"); + + if (t == null) + throw new ArgumentNullException("t"); + Contract.EndContractBlock(); + + if ((t as RuntimeType) == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "t"); + + if (t.IsGenericType) + throw new ArgumentException(Environment.GetResourceString("Argument_NeedNonGenericType"), "t"); + + Type c = t.BaseType; + if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate))) + throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDelegate"), "t"); + + return GetDelegateForFunctionPointerInternal(ptr, t); + } + + [System.Security.SecurityCritical] + public static TDelegate GetDelegateForFunctionPointer<TDelegate>(IntPtr ptr) + { + return (TDelegate)(object)GetDelegateForFunctionPointer(ptr, typeof(TDelegate)); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern Delegate GetDelegateForFunctionPointerInternal(IntPtr ptr, Type t); + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr GetFunctionPointerForDelegate(Delegate d) + { + if (d == null) + throw new ArgumentNullException("d"); + Contract.EndContractBlock(); + + return GetFunctionPointerForDelegateInternal(d); + } + + [System.Security.SecurityCritical] + public static IntPtr GetFunctionPointerForDelegate<TDelegate>(TDelegate d) + { + return GetFunctionPointerForDelegate((Delegate)(object)d); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern IntPtr GetFunctionPointerForDelegateInternal(Delegate d); + +#if FEATURE_LEGACYSURFACE + +#if FEATURE_COMINTEROP + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr SecureStringToBSTR(SecureString s) { + if( s == null) { + throw new ArgumentNullException("s"); + } + Contract.EndContractBlock(); + + return s.ToBSTR(); + } +#endif + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr SecureStringToCoTaskMemAnsi(SecureString s) { + if( s == null) { + throw new ArgumentNullException("s"); + } + Contract.EndContractBlock(); + + return s.ToAnsiStr(false); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr SecureStringToCoTaskMemUnicode(SecureString s) + { + if (s == null) + { + throw new ArgumentNullException("s"); + } + Contract.EndContractBlock(); + + return s.ToUniStr(false); + } + +#endif // FEATURE_LEGACYSURFACE + + +#if FEATURE_COMINTEROP + [System.Security.SecurityCritical] // auto-generated_required + public static void ZeroFreeBSTR(IntPtr s) + { + Win32Native.ZeroMemory(s, (UIntPtr)(Win32Native.SysStringLen(s) * 2)); + FreeBSTR(s); + } +#endif + + [System.Security.SecurityCritical] // auto-generated_required + public static void ZeroFreeCoTaskMemAnsi(IntPtr s) + { + Win32Native.ZeroMemory(s, (UIntPtr)(Win32Native.lstrlenA(s))); + FreeCoTaskMem(s); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static void ZeroFreeCoTaskMemUnicode(IntPtr s) + { + Win32Native.ZeroMemory(s, (UIntPtr)(Win32Native.lstrlenW(s) * 2)); + FreeCoTaskMem(s); + } + +#if FEATURE_LEGACYSURFACE + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr SecureStringToGlobalAllocAnsi(SecureString s) { + if( s == null) { + throw new ArgumentNullException("s"); + } + Contract.EndContractBlock(); + + return s.ToAnsiStr(true); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static IntPtr SecureStringToGlobalAllocUnicode(SecureString s) { + if( s == null) { + throw new ArgumentNullException("s"); + } + Contract.EndContractBlock(); + + return s.ToUniStr(true); + } +#endif // FEATURE_LEGACYSURFACE + + [System.Security.SecurityCritical] // auto-generated_required + public static void ZeroFreeGlobalAllocAnsi(IntPtr s) { + Win32Native.ZeroMemory(s, (UIntPtr)(Win32Native.lstrlenA(s))); + FreeHGlobal(s); + } + + [System.Security.SecurityCritical] // auto-generated_required + public static void ZeroFreeGlobalAllocUnicode(IntPtr s) { + Win32Native.ZeroMemory(s, (UIntPtr)(Win32Native.lstrlenW(s) * 2)); + FreeHGlobal(s); + } + } + +#if FEATURE_COMINTEROP && !FEATURE_CORECLR // current implementation requires reflection only load + //======================================================================== + // Typelib importer callback implementation. + //======================================================================== + internal class ImporterCallback : ITypeLibImporterNotifySink + { + public void ReportEvent(ImporterEventKind EventKind, int EventCode, String EventMsg) + { + } + + [System.Security.SecuritySafeCritical] // overrides transparent public member + public Assembly ResolveRef(Object TypeLib) + { + try + { + // Create the TypeLibConverter. + ITypeLibConverter TLBConv = new TypeLibConverter(); + + // Convert the typelib. + return TLBConv.ConvertTypeLibToAssembly(TypeLib, + Marshal.GetTypeLibName((ITypeLib)TypeLib) + ".dll", + 0, + new ImporterCallback(), + null, + null, + null, + null); + } + catch(Exception) +// catch + { + return null; + } + } + } +#endif // FEATURE_COMINTEROP && !FEATURE_CORECLR +} + diff --git a/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs b/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs new file mode 100644 index 0000000000..076307feb8 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** Purpose: This exception is thrown when the marshaller encounters a signature +** that has an invalid MarshalAs CA for a given argument or is not +** supported. +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using System.Runtime.Serialization; + +[System.Runtime.InteropServices.ComVisible(true)] + [Serializable] + public class MarshalDirectiveException : SystemException { + public MarshalDirectiveException() + : base(Environment.GetResourceString("Arg_MarshalDirectiveException")) { + SetErrorCode(__HResults.COR_E_MARSHALDIRECTIVE); + } + + public MarshalDirectiveException(String message) + : base(message) { + SetErrorCode(__HResults.COR_E_MARSHALDIRECTIVE); + } + + public MarshalDirectiveException(String message, Exception inner) + : base(message, inner) { + SetErrorCode(__HResults.COR_E_MARSHALDIRECTIVE); + } + + protected MarshalDirectiveException(SerializationInfo info, StreamingContext context) : base(info, context) { + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/NativeMethods.cs b/src/mscorlib/src/System/Runtime/InteropServices/NativeMethods.cs new file mode 100644 index 0000000000..585e7a6b25 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/NativeMethods.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +/*============================================================ +** +** +** Purpose: part of ComEventHelpers APIs which allow binding +** managed delegates to COM's connection point based events. +** +**/ +#if FEATURE_COMINTEROP + +namespace System.Runtime.InteropServices { + + internal static class NativeMethods { + + [ + System.Security.SuppressUnmanagedCodeSecurity, + DllImport("oleaut32.dll", PreserveSig = false), + System.Security.SecurityCritical + ] + internal static extern void VariantClear(IntPtr variant); + + [ + System.Security.SuppressUnmanagedCodeSecurity, + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid("00020400-0000-0000-C000-000000000046") + ] + internal interface IDispatch { + + [System.Security.SecurityCritical] + void GetTypeInfoCount(out uint pctinfo); + + [System.Security.SecurityCritical] + void GetTypeInfo(uint iTInfo, int lcid, out IntPtr info); + + [System.Security.SecurityCritical] + void GetIDsOfNames( + ref Guid iid, + [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] + string[] names, + uint cNames, + int lcid, + [Out] + [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I4, SizeParamIndex = 2)] + int[] rgDispId); + + [System.Security.SecurityCritical] + void Invoke( + int dispIdMember, + ref Guid riid, + int lcid, + ComTypes.INVOKEKIND wFlags, + ref ComTypes.DISPPARAMS pDispParams, + IntPtr pvarResult, + IntPtr pExcepInfo, + IntPtr puArgErr); + } + } +} + +#endif diff --git a/src/mscorlib/src/System/Runtime/InteropServices/NonPortable.cs b/src/mscorlib/src/System/Runtime/InteropServices/NonPortable.cs new file mode 100644 index 0000000000..5fbea85516 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/NonPortable.cs @@ -0,0 +1,220 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// Dummy implementations of non-portable interop methods that just throw PlatformNotSupportedException + +namespace System.Runtime.InteropServices +{ + public static partial class Marshal + { + [System.Security.SecurityCriticalAttribute] + public static int AddRef(System.IntPtr pUnk) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static bool AreComObjectsAvailableForCleanup() + { + return false; + } + + [System.Security.SecurityCriticalAttribute] + public static System.IntPtr CreateAggregatedObject(System.IntPtr pOuter, object o) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static System.IntPtr CreateAggregatedObject<T>(System.IntPtr pOuter, T o) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static object CreateWrapperOfType(object o, System.Type t) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static TWrapper CreateWrapperOfType<T, TWrapper>(T o) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static int FinalReleaseComObject(object o) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static void FreeBSTR(System.IntPtr ptr) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static System.IntPtr GetComInterfaceForObject(object o, System.Type T) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static System.IntPtr GetComInterfaceForObject(object o, System.Type T, System.Runtime.InteropServices.CustomQueryInterfaceMode mode) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static System.IntPtr GetComInterfaceForObject<T, TInterface>(T o) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static System.IntPtr GetIUnknownForObject(object o) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static void GetNativeVariantForObject(object obj, System.IntPtr pDstNativeVariant) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static void GetNativeVariantForObject<T>(T obj, System.IntPtr pDstNativeVariant) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static object GetObjectForIUnknown(System.IntPtr pUnk) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static object GetObjectForNativeVariant(System.IntPtr pSrcNativeVariant) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static T GetObjectForNativeVariant<T>(System.IntPtr pSrcNativeVariant) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static object[] GetObjectsForNativeVariants(System.IntPtr aSrcNativeVariant, int cVars) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static T[] GetObjectsForNativeVariants<T>(System.IntPtr aSrcNativeVariant, int cVars) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static int GetStartComSlot(System.Type t) + { + throw new PlatformNotSupportedException(); + } + + public static System.Type GetTypeFromCLSID(System.Guid clsid) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static string GetTypeInfoName(System.Runtime.InteropServices.ComTypes.ITypeInfo typeInfo) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static object GetUniqueObjectForIUnknown(System.IntPtr unknown) + { + throw new PlatformNotSupportedException(); + } + + public static bool IsComObject(object o) + { + return false; + } + + [System.Security.SecurityCriticalAttribute] + public static string PtrToStringBSTR(System.IntPtr ptr) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static int QueryInterface(System.IntPtr pUnk, ref System.Guid iid, out System.IntPtr ppv) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static int Release(System.IntPtr pUnk) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static int ReleaseComObject(object o) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static System.IntPtr StringToBSTR(string s) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static void ZeroFreeBSTR(System.IntPtr s) + { + throw new PlatformNotSupportedException(); + } + } + + public class DispatchWrapper + { + public DispatchWrapper(object obj) + { + throw new PlatformNotSupportedException(); + } + + public object WrappedObject + { + get + { + throw new PlatformNotSupportedException(); + } + } + } + + public static class ComEventsHelper + { + [System.Security.SecurityCriticalAttribute] + public static void Combine(object rcw, System.Guid iid, int dispid, System.Delegate d) + { + throw new PlatformNotSupportedException(); + } + + [System.Security.SecurityCriticalAttribute] + public static System.Delegate Remove(object rcw, System.Guid iid, int dispid, System.Delegate d) + { + throw new PlatformNotSupportedException(); + } + } +} + diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ObjectCreationDelegate.cs b/src/mscorlib/src/System/Runtime/InteropServices/ObjectCreationDelegate.cs new file mode 100644 index 0000000000..a01061e74a --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/ObjectCreationDelegate.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** Delegate: ObjectCreationDelegate +** +** +** Purpose: Delegate called to create a classic COM object as an alternative to +** CoCreateInstance. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + // Delegate called when a managed object wishes to instantiate its unmanaged + // portion. The IUnknown of the managed object (the aggregator) is passed as a + // parameter and the delegate should return the IUnknown of the unmanaged object + // (the aggregatee). Both are passed as int's to avoid any marshalling. +[System.Runtime.InteropServices.ComVisible(true)] + public delegate IntPtr ObjectCreationDelegate(IntPtr aggregator); +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/PInvokeMap.cs b/src/mscorlib/src/System/Runtime/InteropServices/PInvokeMap.cs new file mode 100644 index 0000000000..9b16a5f866 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/PInvokeMap.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// PInvokeMap is an enum that defines the PInvoke attributes. These +// values are defined in CorHdr.h. +// +// +namespace System.Runtime.InteropServices { + using System.Runtime.InteropServices; + using System; + + // This Enum matchs the CorPinvokeMap defined in CorHdr.h + [Serializable] + internal enum PInvokeMap + { + NoMangle = 0x0001, // Pinvoke is to use the member name as specified. + CharSetMask = 0x0006, // Heuristic used in data type & name mapping. + CharSetNotSpec = 0x0000, + CharSetAnsi = 0x0002, + CharSetUnicode = 0x0004, + CharSetAuto = 0x0006, + + PinvokeOLE = 0x0020, // Heuristic: pinvoke will return hresult, with return value becoming the retval param. Not relevant for fields. + SupportsLastError = 0x0040, // Information about target function. Not relevant for fields. + + BestFitMask = 0x0030, + BestFitEnabled = 0x0010, + BestFitDisabled = 0x0020, + BestFitUseAsm = 0x0030, + + ThrowOnUnmappableCharMask = 0x3000, + ThrowOnUnmappableCharEnabled = 0x1000, + ThrowOnUnmappableCharDisabled = 0x2000, + ThrowOnUnmappableCharUseAsm = 0x3000, + + // None of the calling convention flags is relevant for fields. + CallConvMask = 0x0700, + CallConvWinapi = 0x0100, // Pinvoke will use native callconv appropriate to target windows platform. + CallConvCdecl = 0x0200, + CallConvStdcall = 0x0300, + CallConvThiscall = 0x0400, // In M9, pinvoke will raise exception. + CallConvFastcall = 0x0500, + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/RegistrationServices.cs b/src/mscorlib/src/System/Runtime/InteropServices/RegistrationServices.cs new file mode 100644 index 0000000000..6b83e92057 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/RegistrationServices.cs @@ -0,0 +1,1086 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: This class provides services for registering and unregistering +** a managed server for use by COM. +** +** +** +** +** Change the way how to register and unregister a managed server +** +=============================================================================*/ +namespace System.Runtime.InteropServices { + + using System; + using System.Collections; + using System.IO; + using System.Reflection; + using System.Security; + using System.Security.Permissions; + using System.Text; + using System.Threading; + using Microsoft.Win32; + using System.Runtime.CompilerServices; + using System.Globalization; + using System.Runtime.Versioning; + using System.Diagnostics.Contracts; + + [Flags] + public enum RegistrationClassContext + { + + + InProcessServer = 0x1, + InProcessHandler = 0x2, + LocalServer = 0x4, + InProcessServer16 = 0x8, + RemoteServer = 0x10, + InProcessHandler16 = 0x20, + Reserved1 = 0x40, + Reserved2 = 0x80, + Reserved3 = 0x100, + Reserved4 = 0x200, + NoCodeDownload = 0x400, + Reserved5 = 0x800, + NoCustomMarshal = 0x1000, + EnableCodeDownload = 0x2000, + NoFailureLog = 0x4000, + DisableActivateAsActivator = 0x8000, + EnableActivateAsActivator = 0x10000, + FromDefaultContext = 0x20000 + } + + + [Flags] + public enum RegistrationConnectionType + { + SingleUse = 0, + MultipleUse = 1, + MultiSeparate = 2, + Suspended = 4, + Surrogate = 8, + } + + [Guid("475E398F-8AFA-43a7-A3BE-F4EF8D6787C9")] + [ClassInterface(ClassInterfaceType.None)] +[System.Runtime.InteropServices.ComVisible(true)] + public class RegistrationServices : IRegistrationServices + { + #region Constants + + private const String strManagedCategoryGuid = "{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}"; + private const String strDocStringPrefix = ""; + private const String strManagedTypeThreadingModel = "Both"; + private const String strComponentCategorySubKey = "Component Categories"; + private const String strManagedCategoryDescription = ".NET Category"; + private const String strImplementedCategoriesSubKey = "Implemented Categories"; + private const String strMsCorEEFileName = "mscoree.dll"; + private const String strRecordRootName = "Record"; + private const String strClsIdRootName = "CLSID"; + private const String strTlbRootName = "TypeLib"; + private static Guid s_ManagedCategoryGuid = new Guid(strManagedCategoryGuid); + + #endregion + + + #region IRegistrationServices + + [System.Security.SecurityCritical] // auto-generated_required + public virtual bool RegisterAssembly(Assembly assembly, AssemblyRegistrationFlags flags) + { + // Validate the arguments. + if (assembly == null) + throw new ArgumentNullException("assembly"); + + if (assembly.ReflectionOnly) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsmLoadedForReflectionOnly")); + Contract.EndContractBlock(); + + RuntimeAssembly rtAssembly = assembly as RuntimeAssembly; + if (rtAssembly == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly")); + + // Retrieve the assembly names. + String strAsmName = assembly.FullName; + if (strAsmName == null) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NoAsmName")); + + // Retrieve the assembly codebase. + String strAsmCodeBase = null; + if ((flags & AssemblyRegistrationFlags.SetCodeBase) != 0) + { + strAsmCodeBase = rtAssembly.GetCodeBase(false); + if (strAsmCodeBase == null) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NoAsmCodeBase")); + } + + // Go through all the registerable types in the assembly and register them. + Type[] aTypes = GetRegistrableTypesInAssembly(assembly); + int NumTypes = aTypes.Length; + + String strAsmVersion = rtAssembly.GetVersion().ToString(); + + // Retrieve the runtime version used to build the assembly. + String strRuntimeVersion = assembly.ImageRuntimeVersion; + + for (int cTypes = 0; cTypes < NumTypes; cTypes++) + { + if (IsRegisteredAsValueType(aTypes[cTypes])) + RegisterValueType(aTypes[cTypes], strAsmName, strAsmVersion, strAsmCodeBase, strRuntimeVersion); + else if (TypeRepresentsComType(aTypes[cTypes])) + RegisterComImportedType(aTypes[cTypes], strAsmName, strAsmVersion, strAsmCodeBase, strRuntimeVersion); + else + RegisterManagedType(aTypes[cTypes], strAsmName, strAsmVersion, strAsmCodeBase, strRuntimeVersion); + + CallUserDefinedRegistrationMethod(aTypes[cTypes], true); + } + + // If this assembly has the PIA attribute, then register it as a PIA. + Object[] aPIAAttrs = assembly.GetCustomAttributes(typeof(PrimaryInteropAssemblyAttribute), false); + int NumPIAAttrs = aPIAAttrs.Length; + for (int cPIAAttrs = 0; cPIAAttrs < NumPIAAttrs; cPIAAttrs++) + RegisterPrimaryInteropAssembly(rtAssembly, strAsmCodeBase, (PrimaryInteropAssemblyAttribute)aPIAAttrs[cPIAAttrs]); + + // Return value indicating if we actually registered any types. + if (aTypes.Length > 0 || NumPIAAttrs > 0) + return true; + else + return false; + } + + [System.Security.SecurityCritical] // auto-generated_required + public virtual bool UnregisterAssembly(Assembly assembly) + { + // Validate the arguments. + if (assembly == null) + throw new ArgumentNullException("assembly"); + + if (assembly.ReflectionOnly) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsmLoadedForReflectionOnly")); + Contract.EndContractBlock(); + + RuntimeAssembly rtAssembly = assembly as RuntimeAssembly; + if (rtAssembly == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly")); + + bool bAllVersionsGone = true; + + // Go through all the registrable types in the assembly and register them. + Type[] aTypes = GetRegistrableTypesInAssembly(assembly); + int NumTypes = aTypes.Length; + + // Retrieve the assembly version + String strAsmVersion = rtAssembly.GetVersion().ToString(); + for (int cTypes = 0;cTypes < NumTypes;cTypes++) + { + CallUserDefinedRegistrationMethod(aTypes[cTypes], false); + + if (IsRegisteredAsValueType(aTypes[cTypes])) + { + if (!UnregisterValueType(aTypes[cTypes], strAsmVersion)) + bAllVersionsGone = false; + } + else if (TypeRepresentsComType(aTypes[cTypes])) + { + if (!UnregisterComImportedType(aTypes[cTypes], strAsmVersion)) + bAllVersionsGone = false; + } + else + { + if (!UnregisterManagedType(aTypes[cTypes], strAsmVersion)) + bAllVersionsGone = false; + } + } + + // If this assembly has the PIA attribute, then unregister it as a PIA. + Object[] aPIAAttrs = assembly.GetCustomAttributes(typeof(PrimaryInteropAssemblyAttribute),false); + int NumPIAAttrs = aPIAAttrs.Length; + if (bAllVersionsGone) + { + for (int cPIAAttrs = 0;cPIAAttrs < NumPIAAttrs;cPIAAttrs++) + UnregisterPrimaryInteropAssembly(assembly, (PrimaryInteropAssemblyAttribute)aPIAAttrs[cPIAAttrs]); + } + + // Return value indicating if we actually un-registered any types. + if (aTypes.Length > 0 || NumPIAAttrs > 0) + return true; + else + return false; + } + + [System.Security.SecurityCritical] // auto-generated_required + public virtual Type[] GetRegistrableTypesInAssembly(Assembly assembly) + { + // Validate the arguments. + if (assembly == null) + throw new ArgumentNullException("assembly"); + Contract.EndContractBlock(); + + if (!(assembly is RuntimeAssembly)) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"), "assembly"); + + // Retrieve the list of types in the assembly. + Type[] aTypes = assembly.GetExportedTypes(); + int NumTypes = aTypes.Length; + + // Create an array list that will be filled in. + ArrayList TypeList = new ArrayList(); + + // Register all the types that require registration. + for (int cTypes = 0; cTypes < NumTypes; cTypes++) + { + Type CurrentType = aTypes[cTypes]; + if (TypeRequiresRegistration(CurrentType)) + TypeList.Add(CurrentType); + } + + // Copy the array list to an array and return it. + Type[] RetArray = new Type[TypeList.Count]; + TypeList.CopyTo(RetArray); + return RetArray; + } + + [System.Security.SecurityCritical] // auto-generated_required + public virtual String GetProgIdForType(Type type) + { + return Marshal.GenerateProgIdForType(type); + } + + [System.Security.SecurityCritical] // auto-generated_required + public virtual void RegisterTypeForComClients(Type type, ref Guid g) + { +#if FEATURE_COMINTEROP_MANAGED_ACTIVATION + if(type == null) + throw new ArgumentNullException("type"); + Contract.EndContractBlock(); + if((type as RuntimeType) == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"),"type"); + if(!TypeRequiresRegistration(type)) + throw new ArgumentException(Environment.GetResourceString("Argument_TypeMustBeComCreatable"),"type"); + + // Call the native method to do CoRegisterClassObject + RegisterTypeForComClientsNative(type, ref g); +#else // FEATURE_COMINTEROP_MANAGED_ACTIVATION + throw new NotImplementedException("CoreCLR_REMOVED -- managed activation removed"); +#endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION + } + + public virtual Guid GetManagedCategoryGuid() + { + return s_ManagedCategoryGuid; + } + + [System.Security.SecurityCritical] // auto-generated_required + public virtual bool TypeRequiresRegistration(Type type) + { + return TypeRequiresRegistrationHelper(type); + } + + [System.Security.SecuritySafeCritical] // auto-generated + public virtual bool TypeRepresentsComType(Type type) + { + // If the type is not a COM import, then it does not represent a COM type. + if (!type.IsCOMObject) + return false; + + // If it is marked as tdImport, then it represents a COM type directly. + if (type.IsImport) + return true; + + // If the type is derived from a tdImport class and has the same GUID as the + // imported class, then it represents a COM type. + Type baseComImportType = GetBaseComImportType(type); + Contract.Assert(baseComImportType != null, "baseComImportType != null"); + if (Marshal.GenerateGuidForType(type) == Marshal.GenerateGuidForType(baseComImportType)) + return true; + + return false; + } + + #endregion + + + #region Public methods not on IRegistrationServices + [System.Security.SecurityCritical] // auto-generated_required + [ComVisible(false)] + public virtual int RegisterTypeForComClients(Type type, RegistrationClassContext classContext, RegistrationConnectionType flags) + { +#if FEATURE_COMINTEROP_MANAGED_ACTIVATION + if (type == null) + throw new ArgumentNullException("type"); + Contract.EndContractBlock(); + if ((type as RuntimeType) == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"),"type"); + if (!TypeRequiresRegistration(type)) + throw new ArgumentException(Environment.GetResourceString("Argument_TypeMustBeComCreatable"),"type"); + + // Call the native method to do CoRegisterClassObject + return RegisterTypeForComClientsExNative(type, classContext, flags); +#else // FEATURE_COMINTEROP_MANAGED_ACTIVATION + throw new NotImplementedException("CoreCLR_REMOVED -- managed activation removed"); +#endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION + } + + [System.Security.SecurityCritical] // auto-generated_required + [ComVisible(false)] + public virtual void UnregisterTypeForComClients(int cookie) + { + // Call the native method to do CoRevokeClassObject. + CoRevokeClassObject(cookie); + } + + #endregion + + + #region Internal helpers + + [System.Security.SecurityCritical] // auto-generated_required + internal static bool TypeRequiresRegistrationHelper(Type type) + { + // If the type is not a class or a value class, then it does not get registered. + if (!type.IsClass && !type.IsValueType) + return false; + + // If the type is abstract then it does not get registered. + if (type.IsAbstract) + return false; + + // If the does not have a public default constructor then is not creatable from COM so + // it does not require registration unless it is a value class. + if (!type.IsValueType && type.GetConstructor(BindingFlags.Instance | BindingFlags.Public,null,new Type[0],null) == null) + return false; + + // All other conditions are met so check to see if the type is visible from COM. + return Marshal.IsTypeVisibleFromCom(type); + } + + #endregion + + + #region Private helpers + + [System.Security.SecurityCritical] // auto-generated + private void RegisterValueType(Type type, String strAsmName, String strAsmVersion, String strAsmCodeBase, String strRuntimeVersion) + { + // Retrieve some information that will be used during the registration process. + String strRecordId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; + + // Create the HKEY_CLASS_ROOT\Record key. + using (RegistryKey RecordRootKey = Registry.ClassesRoot.CreateSubKey(strRecordRootName)) + { + // Create the HKEY_CLASS_ROOT\Record\<RecordID> key. + using (RegistryKey RecordKey = RecordRootKey.CreateSubKey(strRecordId)) + { + // Create the HKEY_CLASS_ROOT\Record\<RecordId>\<version> key. + using (RegistryKey RecordVersionKey = RecordKey.CreateSubKey(strAsmVersion)) + { + // Set the class value. + RecordVersionKey.SetValue("Class", type.FullName); + + // Set the assembly value. + RecordVersionKey.SetValue("Assembly", strAsmName); + + // Set the runtime version value. + RecordVersionKey.SetValue("RuntimeVersion", strRuntimeVersion); + + // Set the assembly code base value if a code base was specified. + if (strAsmCodeBase != null) + RecordVersionKey.SetValue("CodeBase", strAsmCodeBase); + } + } + } + } + + [System.Security.SecurityCritical] // auto-generated + private void RegisterManagedType(Type type, String strAsmName, String strAsmVersion, String strAsmCodeBase, String strRuntimeVersion) + { + // + // Retrieve some information that will be used during the registration process. + // + + String strDocString = strDocStringPrefix + type.FullName; + String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; + String strProgId = GetProgIdForType(type); + + + // + // Write the actual type information in the registry. + // + + if (strProgId != String.Empty) + { + // Create the HKEY_CLASS_ROOT\<wzProgId> key. + using (RegistryKey TypeNameKey = Registry.ClassesRoot.CreateSubKey(strProgId)) + { + TypeNameKey.SetValue("", strDocString); + + // Create the HKEY_CLASS_ROOT\<wzProgId>\CLSID key. + using (RegistryKey ProgIdClsIdKey = TypeNameKey.CreateSubKey("CLSID")) + { + ProgIdClsIdKey.SetValue("", strClsId); + } + } + } + + // Create the HKEY_CLASS_ROOT\CLSID key. + using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.CreateSubKey(strClsIdRootName)) + { + // Create the HKEY_CLASS_ROOT\CLSID\<CLSID> key. + using (RegistryKey ClsIdKey = ClsIdRootKey.CreateSubKey(strClsId)) + { + ClsIdKey.SetValue("", strDocString); + + // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32 key. + using (RegistryKey InProcServerKey = ClsIdKey.CreateSubKey("InprocServer32")) + { + InProcServerKey.SetValue("", strMsCorEEFileName); + InProcServerKey.SetValue("ThreadingModel", strManagedTypeThreadingModel); + InProcServerKey.SetValue("Class", type.FullName); + InProcServerKey.SetValue("Assembly", strAsmName); + InProcServerKey.SetValue("RuntimeVersion", strRuntimeVersion); + if (strAsmCodeBase != null) + InProcServerKey.SetValue("CodeBase", strAsmCodeBase); + + // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32\<Version> subkey + using (RegistryKey VersionSubKey = InProcServerKey.CreateSubKey(strAsmVersion)) + { + VersionSubKey.SetValue("Class", type.FullName); + VersionSubKey.SetValue("Assembly", strAsmName); + VersionSubKey.SetValue("RuntimeVersion", strRuntimeVersion); + if (strAsmCodeBase != null) + VersionSubKey.SetValue("CodeBase", strAsmCodeBase); + } + + if (strProgId != String.Empty) + { + // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\ProdId key. + using (RegistryKey ProgIdKey = ClsIdKey.CreateSubKey("ProgId")) + { + ProgIdKey.SetValue("", strProgId); + } + } + } + + // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\Implemented Categories\<Managed Category Guid> key. + using (RegistryKey CategoryKey = ClsIdKey.CreateSubKey(strImplementedCategoriesSubKey)) + { + using (RegistryKey ManagedCategoryKey = CategoryKey.CreateSubKey(strManagedCategoryGuid)) {} + } + } + } + + + // + // Ensure that the managed category exists. + // + + EnsureManagedCategoryExists(); + } + + [System.Security.SecurityCritical] // auto-generated + private void RegisterComImportedType(Type type, String strAsmName, String strAsmVersion, String strAsmCodeBase, String strRuntimeVersion) + { + // Retrieve some information that will be used during the registration process. + String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; + + // Create the HKEY_CLASS_ROOT\CLSID key. + using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.CreateSubKey(strClsIdRootName)) + { + // Create the HKEY_CLASS_ROOT\CLSID\<CLSID> key. + using (RegistryKey ClsIdKey = ClsIdRootKey.CreateSubKey(strClsId)) + { + // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\InProcServer32 key. + using (RegistryKey InProcServerKey = ClsIdKey.CreateSubKey("InprocServer32")) + { + // Set the class value. + InProcServerKey.SetValue("Class", type.FullName); + + // Set the assembly value. + InProcServerKey.SetValue("Assembly", strAsmName); + + // Set the runtime version value. + InProcServerKey.SetValue("RuntimeVersion", strRuntimeVersion); + + // Set the assembly code base value if a code base was specified. + if (strAsmCodeBase != null) + InProcServerKey.SetValue("CodeBase", strAsmCodeBase); + + // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32\<Version> subkey + using (RegistryKey VersionSubKey = InProcServerKey.CreateSubKey(strAsmVersion)) + { + VersionSubKey.SetValue("Class", type.FullName); + VersionSubKey.SetValue("Assembly", strAsmName); + VersionSubKey.SetValue("RuntimeVersion", strRuntimeVersion); + if (strAsmCodeBase != null) + VersionSubKey.SetValue("CodeBase", strAsmCodeBase); + } + } + } + } + } + + [System.Security.SecurityCritical] // auto-generated + private bool UnregisterValueType(Type type, String strAsmVersion) + { + bool bAllVersionsGone = true; + + // Try to open the HKEY_CLASS_ROOT\Record key. + String strRecordId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; + + using (RegistryKey RecordRootKey = Registry.ClassesRoot.OpenSubKey(strRecordRootName, true)) + { + if (RecordRootKey != null) + { + // Open the HKEY_CLASS_ROOT\Record\{RecordId} key. + using (RegistryKey RecordKey = RecordRootKey.OpenSubKey(strRecordId,true)) + { + if (RecordKey != null) + { + using (RegistryKey VersionSubKey = RecordKey.OpenSubKey(strAsmVersion,true)) + { + if (VersionSubKey != null) + { + // Delete the values we created. + VersionSubKey.DeleteValue("Assembly",false); + VersionSubKey.DeleteValue("Class",false); + VersionSubKey.DeleteValue("CodeBase",false); + VersionSubKey.DeleteValue("RuntimeVersion",false); + + // delete the version sub key if no value or subkeys under it + if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0)) + RecordKey.DeleteSubKey(strAsmVersion); + } + } + + // If there are sub keys left then there are versions left. + if (RecordKey.SubKeyCount != 0) + bAllVersionsGone = false; + + // If there are no other values or subkeys then we can delete the HKEY_CLASS_ROOT\Record\{RecordId}. + if ((RecordKey.SubKeyCount == 0) && (RecordKey.ValueCount == 0)) + RecordRootKey.DeleteSubKey(strRecordId); + } + } + + // If there are no other values or subkeys then we can delete the HKEY_CLASS_ROOT\Record. + if ((RecordRootKey.SubKeyCount == 0) && (RecordRootKey.ValueCount == 0)) + Registry.ClassesRoot.DeleteSubKey(strRecordRootName); + } + } + + return bAllVersionsGone; + } + + // UnregisterManagedType + // + // Return : + // true: All versions are gone. + // false: Some versions are still left in registry + [System.Security.SecurityCritical] // auto-generated + private bool UnregisterManagedType(Type type,String strAsmVersion) + { + bool bAllVersionsGone = true; + + // + // Create the CLSID string. + // + + String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; + String strProgId = GetProgIdForType(type); + + + // + // Remove the entries under HKEY_CLASS_ROOT\CLSID key. + // + + using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.OpenSubKey(strClsIdRootName, true)) + { + if (ClsIdRootKey != null) + { + // + // Remove the entries under HKEY_CLASS_ROOT\CLSID\<CLSID> key. + // + + using (RegistryKey ClsIdKey = ClsIdRootKey.OpenSubKey(strClsId, true)) + { + if (ClsIdKey != null) + { + // + // Remove the entries in the HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32 key. + // + + using (RegistryKey InProcServerKey = ClsIdKey.OpenSubKey("InprocServer32", true)) + { + if (InProcServerKey != null) + { + // + // Remove the entries in HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32\<Version> + // + + using (RegistryKey VersionSubKey = InProcServerKey.OpenSubKey(strAsmVersion, true)) + { + if (VersionSubKey != null) + { + // Delete the values we created + VersionSubKey.DeleteValue("Assembly",false); + VersionSubKey.DeleteValue("Class",false); + VersionSubKey.DeleteValue("RuntimeVersion",false); + VersionSubKey.DeleteValue("CodeBase",false); + + // If there are no other values or subkeys then we can delete the VersionSubKey. + if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0)) + InProcServerKey.DeleteSubKey(strAsmVersion); + } + } + + // If there are sub keys left then there are versions left. + if (InProcServerKey.SubKeyCount != 0) + bAllVersionsGone = false; + + // If there are no versions left, then delete the threading model and default value. + if (bAllVersionsGone) + { + InProcServerKey.DeleteValue("",false); + InProcServerKey.DeleteValue("ThreadingModel",false); + } + + InProcServerKey.DeleteValue("Assembly",false); + InProcServerKey.DeleteValue("Class",false); + InProcServerKey.DeleteValue("RuntimeVersion",false); + InProcServerKey.DeleteValue("CodeBase",false); + + // If there are no other values or subkeys then we can delete the InProcServerKey. + if ((InProcServerKey.SubKeyCount == 0) && (InProcServerKey.ValueCount == 0)) + ClsIdKey.DeleteSubKey("InprocServer32"); + } + } + + // remove HKEY_CLASS_ROOT\CLSID\<CLSID>\ProgId + // and HKEY_CLASS_ROOT\CLSID\<CLSID>\Implemented Category + // only when all versions are removed + if (bAllVersionsGone) + { + // Delete the value we created. + ClsIdKey.DeleteValue("",false); + + if (strProgId != String.Empty) + { + // + // Remove the entries in the HKEY_CLASS_ROOT\CLSID\<CLSID>\ProgId key. + // + + using (RegistryKey ProgIdKey = ClsIdKey.OpenSubKey("ProgId", true)) + { + if (ProgIdKey != null) + { + // Delete the value we created. + ProgIdKey.DeleteValue("",false); + + // If there are no other values or subkeys then we can delete the ProgIdSubKey. + if ((ProgIdKey.SubKeyCount == 0) && (ProgIdKey.ValueCount == 0)) + ClsIdKey.DeleteSubKey("ProgId"); + } + } + } + + + // + // Remove entries in the HKEY_CLASS_ROOT\CLSID\<CLSID>\Implemented Categories\<Managed Category Guid> key. + // + + using (RegistryKey CategoryKey = ClsIdKey.OpenSubKey(strImplementedCategoriesSubKey, true)) + { + if (CategoryKey != null) + { + using (RegistryKey ManagedCategoryKey = CategoryKey.OpenSubKey(strManagedCategoryGuid, true)) + { + if (ManagedCategoryKey != null) + { + // If there are no other values or subkeys then we can delete the ManagedCategoryKey. + if ((ManagedCategoryKey.SubKeyCount == 0) && (ManagedCategoryKey.ValueCount == 0)) + CategoryKey.DeleteSubKey(strManagedCategoryGuid); + } + } + + // If there are no other values or subkeys then we can delete the CategoryKey. + if ((CategoryKey.SubKeyCount == 0) && (CategoryKey.ValueCount == 0)) + ClsIdKey.DeleteSubKey(strImplementedCategoriesSubKey); + } + } + } + + // If there are no other values or subkeys then we can delete the ClsIdKey. + if ((ClsIdKey.SubKeyCount == 0) && (ClsIdKey.ValueCount == 0)) + ClsIdRootKey.DeleteSubKey(strClsId); + } + } + + // If there are no other values or subkeys then we can delete the CLSID key. + if ((ClsIdRootKey.SubKeyCount == 0) && (ClsIdRootKey.ValueCount == 0)) + Registry.ClassesRoot.DeleteSubKey(strClsIdRootName); + } + + + // + // Remove the entries under HKEY_CLASS_ROOT\<wzProgId> key. + // + + if (bAllVersionsGone) + { + if (strProgId != String.Empty) + { + using (RegistryKey TypeNameKey = Registry.ClassesRoot.OpenSubKey(strProgId, true)) + { + if (TypeNameKey != null) + { + // Delete the values we created. + TypeNameKey.DeleteValue("",false); + + + // + // Remove the entries in the HKEY_CLASS_ROOT\<wzProgId>\CLSID key. + // + + using (RegistryKey ProgIdClsIdKey = TypeNameKey.OpenSubKey("CLSID", true)) + { + if (ProgIdClsIdKey != null) + { + // Delete the values we created. + ProgIdClsIdKey.DeleteValue("",false); + + // If there are no other values or subkeys then we can delete the ProgIdClsIdKey. + if ((ProgIdClsIdKey.SubKeyCount == 0) && (ProgIdClsIdKey.ValueCount == 0)) + TypeNameKey.DeleteSubKey("CLSID"); + } + } + + // If there are no other values or subkeys then we can delete the TypeNameKey. + if ((TypeNameKey.SubKeyCount == 0) && (TypeNameKey.ValueCount == 0)) + Registry.ClassesRoot.DeleteSubKey(strProgId); + } + } + } + } + } + + return bAllVersionsGone; + } + + // UnregisterComImportedType + // Return: + // true: All version information are gone. + // false: There are still some version left in registry + [System.Security.SecurityCritical] // auto-generated + private bool UnregisterComImportedType(Type type, String strAsmVersion) + { + bool bAllVersionsGone = true; + + String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; + + // Try to open the HKEY_CLASS_ROOT\CLSID key. + using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.OpenSubKey(strClsIdRootName, true)) + { + if (ClsIdRootKey != null) + { + // Try to open the HKEY_CLASS_ROOT\CLSID\<CLSID> key. + using (RegistryKey ClsIdKey = ClsIdRootKey.OpenSubKey(strClsId, true)) + { + if (ClsIdKey != null) + { + // Try to open the HKEY_CLASS_ROOT\CLSID\<CLSID>\InProcServer32 key. + using (RegistryKey InProcServerKey = ClsIdKey.OpenSubKey("InprocServer32", true)) + { + if (InProcServerKey != null) + { + // Delete the values we created. + InProcServerKey.DeleteValue("Assembly",false); + InProcServerKey.DeleteValue("Class",false); + InProcServerKey.DeleteValue("RuntimeVersion",false); + InProcServerKey.DeleteValue("CodeBase",false); + + // Try to open the entries in HKEY_CLASS_ROOT\CLSID\<CLSID>\InProcServer32\<Version> + using (RegistryKey VersionSubKey = InProcServerKey.OpenSubKey(strAsmVersion,true)) + { + if (VersionSubKey != null) + { + // Delete the value we created + VersionSubKey.DeleteValue("Assembly",false); + VersionSubKey.DeleteValue("Class",false); + VersionSubKey.DeleteValue("RuntimeVersion",false); + VersionSubKey.DeleteValue("CodeBase",false); + + // If there are no other values or subkeys then we can delete the VersionSubKey + if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0)) + InProcServerKey.DeleteSubKey(strAsmVersion); + } + } + + // If there are sub keys left then there are versions left. + if (InProcServerKey.SubKeyCount != 0) + bAllVersionsGone = false; + + // If there are no other values or subkeys then we can delete the InProcServerKey. + if ((InProcServerKey.SubKeyCount == 0) && (InProcServerKey.ValueCount == 0)) + ClsIdKey.DeleteSubKey("InprocServer32"); + } + } + + // If there are no other values or subkeys then we can delete the ClsIdKey. + if ((ClsIdKey.SubKeyCount == 0) && (ClsIdKey.ValueCount == 0)) + ClsIdRootKey.DeleteSubKey(strClsId); + } + } + + // If there are no other values or subkeys then we can delete the CLSID key. + if ((ClsIdRootKey.SubKeyCount == 0) && (ClsIdRootKey.ValueCount == 0)) + Registry.ClassesRoot.DeleteSubKey(strClsIdRootName); + } + } + + return bAllVersionsGone; + } + + [System.Security.SecurityCritical] // auto-generated + private void RegisterPrimaryInteropAssembly(RuntimeAssembly assembly, String strAsmCodeBase, PrimaryInteropAssemblyAttribute attr) + { + // Validate that the PIA has a strong name. + if (assembly.GetPublicKey().Length == 0) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_PIAMustBeStrongNamed")); + + String strTlbId = "{" + Marshal.GetTypeLibGuidForAssembly(assembly).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; + String strVersion = attr.MajorVersion.ToString("x", CultureInfo.InvariantCulture) + "." + attr.MinorVersion.ToString("x", CultureInfo.InvariantCulture); + + // Create the HKEY_CLASS_ROOT\TypeLib key. + using (RegistryKey TypeLibRootKey = Registry.ClassesRoot.CreateSubKey(strTlbRootName)) + { + // Create the HKEY_CLASS_ROOT\TypeLib\<TLBID> key. + using (RegistryKey TypeLibKey = TypeLibRootKey.CreateSubKey(strTlbId)) + { + // Create the HKEY_CLASS_ROOT\TypeLib\<TLBID>\<Major.Minor> key. + using (RegistryKey VersionSubKey = TypeLibKey.CreateSubKey(strVersion)) + { + // Create the HKEY_CLASS_ROOT\TypeLib\<TLBID>\PrimaryInteropAssembly key. + VersionSubKey.SetValue("PrimaryInteropAssemblyName", assembly.FullName); + if (strAsmCodeBase != null) + VersionSubKey.SetValue("PrimaryInteropAssemblyCodeBase", strAsmCodeBase); + } + } + } + } + + [System.Security.SecurityCritical] // auto-generated + private void UnregisterPrimaryInteropAssembly(Assembly assembly, PrimaryInteropAssemblyAttribute attr) + { + String strTlbId = "{" + Marshal.GetTypeLibGuidForAssembly(assembly).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; + String strVersion = attr.MajorVersion.ToString("x", CultureInfo.InvariantCulture) + "." + attr.MinorVersion.ToString("x", CultureInfo.InvariantCulture); + + // Try to open the HKEY_CLASS_ROOT\TypeLib key. + using (RegistryKey TypeLibRootKey = Registry.ClassesRoot.OpenSubKey(strTlbRootName, true)) + { + if (TypeLibRootKey != null) + { + // Try to open the HKEY_CLASS_ROOT\TypeLib\<TLBID> key. + using (RegistryKey TypeLibKey = TypeLibRootKey.OpenSubKey(strTlbId, true)) + { + if (TypeLibKey != null) + { + // Try to open the HKEY_CLASS_ROOT\TypeLib<TLBID>\<Major.Minor> key. + using (RegistryKey VersionSubKey = TypeLibKey.OpenSubKey(strVersion, true)) + { + if (VersionSubKey != null) + { + // Delete the values we created. + VersionSubKey.DeleteValue("PrimaryInteropAssemblyName",false); + VersionSubKey.DeleteValue("PrimaryInteropAssemblyCodeBase",false); + + // If there are no other values or subkeys then we can delete the VersionKey. + if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0)) + TypeLibKey.DeleteSubKey(strVersion); + } + } + + // If there are no other values or subkeys then we can delete the TypeLibKey. + if ((TypeLibKey.SubKeyCount == 0) && (TypeLibKey.ValueCount == 0)) + TypeLibRootKey.DeleteSubKey(strTlbId); + } + } + + // If there are no other values or subkeys then we can delete the TypeLib key. + if ((TypeLibRootKey.SubKeyCount == 0) && (TypeLibRootKey.ValueCount == 0)) + Registry.ClassesRoot.DeleteSubKey(strTlbRootName); + } + } + } + + private void EnsureManagedCategoryExists() + { + if (!ManagedCategoryExists()) + { + // Create the HKEY_CLASS_ROOT\Component Category key. + using (RegistryKey ComponentCategoryKey = Registry.ClassesRoot.CreateSubKey(strComponentCategorySubKey)) + { + // Create the HKEY_CLASS_ROOT\Component Category\<Managed Category Guid> key. + using (RegistryKey ManagedCategoryKey = ComponentCategoryKey.CreateSubKey(strManagedCategoryGuid)) + { + ManagedCategoryKey.SetValue("0", strManagedCategoryDescription); + } + } + } + } + + private static bool ManagedCategoryExists() + { + using (RegistryKey componentCategoryKey = Registry.ClassesRoot.OpenSubKey(strComponentCategorySubKey, +#if FEATURE_MACL + RegistryKeyPermissionCheck.ReadSubTree)) +#else + false)) +#endif + { + if (componentCategoryKey == null) + return false; + using (RegistryKey managedCategoryKey = componentCategoryKey.OpenSubKey(strManagedCategoryGuid, +#if FEATURE_MACL + RegistryKeyPermissionCheck.ReadSubTree)) +#else + false)) +#endif + { + if (managedCategoryKey == null) + return false; + object value = managedCategoryKey.GetValue("0"); + if (value == null || value.GetType() != typeof(string)) + return false; + string stringValue = (string)value; + if (stringValue != strManagedCategoryDescription) + return false; + } + } + + return true; + } + + [System.Security.SecurityCritical] // auto-generated + private void CallUserDefinedRegistrationMethod(Type type, bool bRegister) + { + bool bFunctionCalled = false; + + // Retrieve the attribute type to use to determine if a function is the requested user defined + // registration function. + Type RegFuncAttrType = null; + if(bRegister) + RegFuncAttrType = typeof(ComRegisterFunctionAttribute); + else + RegFuncAttrType = typeof(ComUnregisterFunctionAttribute); + + for(Type currType = type; !bFunctionCalled && currType != null; currType = currType.BaseType) + { + // Retrieve all the methods. + MethodInfo[] aMethods = currType.GetMethods(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static); + int NumMethods = aMethods.Length; + + // Go through all the methods and check for the ComRegisterMethod custom attribute. + for(int cMethods = 0;cMethods < NumMethods;cMethods++) + { + MethodInfo CurrentMethod = aMethods[cMethods]; + + // Check to see if the method has the custom attribute. + if(CurrentMethod.GetCustomAttributes(RegFuncAttrType, true).Length != 0) + { + // Check to see if the method is static before we call it. + if(!CurrentMethod.IsStatic) + { + if(bRegister) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NonStaticComRegFunction",CurrentMethod.Name,currType.Name)); + else + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NonStaticComUnRegFunction",CurrentMethod.Name,currType.Name)); + } + + // Finally check that the signature is string ret void. + ParameterInfo[] aParams = CurrentMethod.GetParameters(); + if (CurrentMethod.ReturnType != typeof(void) || + aParams == null || + aParams.Length != 1 || + (aParams[0].ParameterType != typeof(String) && aParams[0].ParameterType != typeof(Type))) + { + if(bRegister) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_InvalidComRegFunctionSig",CurrentMethod.Name,currType.Name)); + else + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_InvalidComUnRegFunctionSig",CurrentMethod.Name,currType.Name)); + } + + // There can only be one register and one unregister function per type. + if(bFunctionCalled) + { + if(bRegister) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MultipleComRegFunctions",currType.Name)); + else + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MultipleComUnRegFunctions",currType.Name)); + } + + // The function is valid so set up the arguments to call it. + Object[] objs = new Object[1]; + if(aParams[0].ParameterType == typeof(String)) + { + // We are dealing with the string overload of the function. + objs[0] = "HKEY_CLASSES_ROOT\\CLSID\\{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; + } + else + { + // We are dealing with the type overload of the function. + objs[0] = type; + } + + // Invoke the COM register function. + CurrentMethod.Invoke(null, objs); + + // Mark the function as having been called. + bFunctionCalled = true; + } + } + } + } + + private Type GetBaseComImportType(Type type) + { + for (; type != null && !type.IsImport; type = type.BaseType); + return type; + } + + private bool IsRegisteredAsValueType(Type type) + { + if (!type.IsValueType) + return false; + + return true; + } + + #endregion + + + #region FCalls and DllImports + +#if FEATURE_COMINTEROP_MANAGED_ACTIVATION + // GUID versioning can be controlled by using the GuidAttribute or + // letting the runtime generate it based on type and assembly strong name. + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void RegisterTypeForComClientsNative(Type type,ref Guid g); + + // GUID versioning can be controlled by using the GuidAttribute or + // letting the runtime generate it based on type and assembly strong name. + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern int RegisterTypeForComClientsExNative(Type t, RegistrationClassContext clsContext, RegistrationConnectionType flags); +#endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION + + [DllImport(Win32Native.OLE32,CharSet=CharSet.Auto,PreserveSig=false)] + private static extern void CoRevokeClassObject(int cookie); + #endregion + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/RuntimeEnvironment.cs b/src/mscorlib/src/System/Runtime/InteropServices/RuntimeEnvironment.cs new file mode 100644 index 0000000000..e7aa9ad062 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/RuntimeEnvironment.cs @@ -0,0 +1,164 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Runtime information +** +** +=============================================================================*/ + +using System; +using System.Text; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Permissions; +using System.Reflection; +using Microsoft.Win32; +using System.Runtime.Versioning; +using StackCrawlMark = System.Threading.StackCrawlMark; + +namespace System.Runtime.InteropServices { +[System.Runtime.InteropServices.ComVisible(true)] +#if FEATURE_CORECLR + static +#endif + public class RuntimeEnvironment { + +#if !FEATURE_CORECLR + // This should have been a static class, but wasn't as of v3.5. Clearly, this is + // broken. We'll keep this in V4 for binary compat, but marked obsolete as error + // so migrated source code gets fixed. On Silverlight, this type exists but is + // not public. + [Obsolete("Do not create instances of the RuntimeEnvironment class. Call the static methods directly on this type instead", true)] + public RuntimeEnvironment() + { + // Should not have been instantiable - here for binary compatibility in V4. + } +#endif + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern String GetModuleFileName(); + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern String GetDeveloperPath(); + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern String GetHostBindingFile(); + +#if !FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + internal static extern void _GetSystemVersion(StringHandleOnStack retVer); +#endif //!FEATURE_CORECLR + + public static bool FromGlobalAccessCache(Assembly a) + { + return a.GlobalAssemblyCache; + } + +#if !FEATURE_CORECLR + [System.Security.SecuritySafeCritical] // public member +#endif + [MethodImpl (MethodImplOptions.NoInlining)] + public static String GetSystemVersion() + { +#if FEATURE_CORECLR + + return Assembly.GetExecutingAssembly().ImageRuntimeVersion; + +#else // FEATURE_CORECLR + + String ver = null; + _GetSystemVersion(JitHelpers.GetStringHandleOnStack(ref ver)); + return ver; + +#endif // FEATURE_CORECLR + + } + + [System.Security.SecuritySafeCritical] // auto-generated + public static String GetRuntimeDirectory() + { + String dir = GetRuntimeDirectoryImpl(); + new FileIOPermission(FileIOPermissionAccess.PathDiscovery, dir).Demand(); + return dir; + } + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern String GetRuntimeDirectoryImpl(); + + // Returns the system ConfigurationFile + public static String SystemConfigurationFile { + [System.Security.SecuritySafeCritical] // auto-generated + get { + StringBuilder sb = new StringBuilder(Path.MAX_PATH); + sb.Append(GetRuntimeDirectory()); + sb.Append(AppDomainSetup.RuntimeConfigurationFile); + String path = sb.ToString(); + + // Do security check + new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand(); + + return path; + } + } + +#if FEATURE_COMINTEROP + [System.Security.SecurityCritical] + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + private static extern IntPtr GetRuntimeInterfaceImpl( + [In, MarshalAs(UnmanagedType.LPStruct)] Guid clsid, + [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid); + + // + // This function does the equivalent of calling GetInterface(clsid, riid) on the + // ICLRRuntimeInfo representing this runtime. See MetaHost.idl for a list of + // CLSIDs and IIDs supported by this method. + // + // Returns unmanaged pointer to requested interface on success. Throws + // COMException with failed HR if there is a QI failure. + // + [System.Security.SecurityCritical] // do not allow partial trust callers + [ComVisible(false)] + public static IntPtr GetRuntimeInterfaceAsIntPtr(Guid clsid, Guid riid) + { + return GetRuntimeInterfaceImpl(clsid, riid); + } + + // + // This function does the equivalent of calling GetInterface(clsid, riid) on the + // ICLRRuntimeInfo representing this runtime. See MetaHost.idl for a list of + // CLSIDs and IIDs supported by this method. + // + // Returns an RCW to requested interface on success. Throws + // COMException with failed HR if there is a QI failure. + // + [System.Security.SecurityCritical] // do not allow partial trust callers + [ComVisible(false)] + public static object GetRuntimeInterfaceAsObject(Guid clsid, Guid riid) + { + IntPtr p = IntPtr.Zero; + try { + p = GetRuntimeInterfaceImpl(clsid, riid); + return Marshal.GetObjectForIUnknown(p); + } finally { + if(p != IntPtr.Zero) { + Marshal.Release(p); + } + } + } + +#endif // FEATURE_COMINTEROP + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs b/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs new file mode 100644 index 0000000000..b7ab8999c8 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Exception class for all Structured Exception Handling code. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + using System.Runtime.InteropServices; + using System; + using System.Runtime.Serialization; + // Exception for Structured Exception Handler exceptions. + // +[System.Runtime.InteropServices.ComVisible(true)] + [Serializable] + public class SEHException : ExternalException { + public SEHException() + : base() { + SetErrorCode(__HResults.E_FAIL); + } + + public SEHException(String message) + : base(message) { + SetErrorCode(__HResults.E_FAIL); + } + + public SEHException(String message, Exception inner) + : base(message, inner) { + SetErrorCode(__HResults.E_FAIL); + } + + protected SEHException(SerializationInfo info, StreamingContext context) : base(info, context) { + } + + // Exceptions can be resumable, meaning a filtered exception + // handler can correct the problem that caused the exception, + // and the code will continue from the point that threw the + // exception. + // + // Resumable exceptions aren't implemented in this version, + // but this method exists and always returns false. + // + public virtual bool CanResume() + { + return false; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs new file mode 100644 index 0000000000..3185a3d63e --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** Purpose: This exception is thrown when the runtime rank of a safe array +** is different than the array rank specified in the metadata. +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using System.Runtime.Serialization; + +[System.Runtime.InteropServices.ComVisible(true)] + [Serializable] public class SafeArrayRankMismatchException : SystemException { + public SafeArrayRankMismatchException() + : base(Environment.GetResourceString("Arg_SafeArrayRankMismatchException")) { + SetErrorCode(__HResults.COR_E_SAFEARRAYRANKMISMATCH); + } + + public SafeArrayRankMismatchException(String message) + : base(message) { + SetErrorCode(__HResults.COR_E_SAFEARRAYRANKMISMATCH); + } + + public SafeArrayRankMismatchException(String message, Exception inner) + : base(message, inner) { + SetErrorCode(__HResults.COR_E_SAFEARRAYRANKMISMATCH); + } + + protected SafeArrayRankMismatchException(SerializationInfo info, StreamingContext context) : base(info, context) { + } + + } + +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs new file mode 100644 index 0000000000..3c6bffb06a --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** Purpose: This exception is thrown when the runtime type of an array +** is different than the safe array sub type specified in the +** metadata. +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using System.Runtime.Serialization; + +[System.Runtime.InteropServices.ComVisible(true)] + [Serializable] public class SafeArrayTypeMismatchException : SystemException { + public SafeArrayTypeMismatchException() + : base(Environment.GetResourceString("Arg_SafeArrayTypeMismatchException")) { + SetErrorCode(__HResults.COR_E_SAFEARRAYTYPEMISMATCH); + } + + public SafeArrayTypeMismatchException(String message) + : base(message) { + SetErrorCode(__HResults.COR_E_SAFEARRAYTYPEMISMATCH); + } + + public SafeArrayTypeMismatchException(String message, Exception inner) + : base(message, inner) { + SetErrorCode(__HResults.COR_E_SAFEARRAYTYPEMISMATCH); + } + + protected SafeArrayTypeMismatchException(SerializationInfo info, StreamingContext context) : base(info, context) { + } + + } + +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SafeBuffer.cs b/src/mscorlib/src/System/Runtime/InteropServices/SafeBuffer.cs new file mode 100644 index 0000000000..ad63decbb1 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/SafeBuffer.cs @@ -0,0 +1,414 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================ +** +** Purpose: Unsafe code that uses pointers should use +** SafePointer to fix subtle lifetime problems with the +** underlying resource. +** +===========================================================*/ + +// Design points: +// *) Avoid handle-recycling problems (including ones triggered via +// resurrection attacks) for all accesses via pointers. This requires tying +// together the lifetime of the unmanaged resource with the code that reads +// from that resource, in a package that uses synchronization to enforce +// the correct semantics during finalization. We're using SafeHandle's +// ref count as a gate on whether the pointer can be dereferenced because that +// controls the lifetime of the resource. +// +// *) Keep the penalties for using this class small, both in terms of space +// and time. Having multiple threads reading from a memory mapped file +// will already require 2 additional interlocked operations. If we add in +// a "current position" concept, that requires additional space in memory and +// synchronization. Since the position in memory is often (but not always) +// something that can be stored on the stack, we can save some memory by +// excluding it from this object. However, avoiding the need for +// synchronization is a more significant win. This design allows multiple +// threads to read and write memory simultaneously without locks (as long as +// you don't write to a region of memory that overlaps with what another +// thread is accessing). +// +// *) Space-wise, we use the following memory, including SafeHandle's fields: +// Object Header MT* handle int bool bool <2 pad bytes> length +// On 32 bit platforms: 24 bytes. On 64 bit platforms: 40 bytes. +// (We can safe 4 bytes on x86 only by shrinking SafeHandle) +// +// *) Wrapping a SafeHandle would have been a nice solution, but without an +// ordering between critical finalizable objects, it would have required +// changes to each SafeHandle subclass to opt in to being usable from a +// SafeBuffer (or some clever exposure of SafeHandle's state fields and a +// way of forcing ReleaseHandle to run even after the SafeHandle has been +// finalized with a ref count > 1). We can use less memory and create fewer +// objects by simply inserting a SafeBuffer into the class hierarchy. +// +// *) In an ideal world, we could get marshaling support for SafeBuffer that +// would allow us to annotate a P/Invoke declaration, saying this parameter +// specifies the length of the buffer, and the units of that length are X. +// P/Invoke would then pass that size parameter to SafeBuffer. +// [DllImport(...)] +// static extern SafeMemoryHandle AllocCharBuffer(int numChars); +// If we could put an attribute on the SafeMemoryHandle saying numChars is +// the element length, and it must be multiplied by 2 to get to the byte +// length, we can simplify the usage model for SafeBuffer. +// +// *) This class could benefit from a constraint saying T is a value type +// containing no GC references. + +// Implementation notes: +// *) The Initialize method must be called before you use any instance of +// a SafeBuffer. To avoid race conditions when storing SafeBuffers in statics, +// you either need to take a lock when publishing the SafeBuffer, or you +// need to create a local, initialize the SafeBuffer, then assign to the +// static variable (perhaps using Interlocked.CompareExchange). Of course, +// assignments in a static class constructor are under a lock implicitly. + + +namespace System.Runtime.InteropServices +{ +using System; +using System.Security.Permissions; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; +using System.Runtime.Versioning; +using Microsoft.Win32.SafeHandles; +using System.Diagnostics.Contracts; + + + [System.Security.SecurityCritical] + public abstract unsafe class SafeBuffer : SafeHandleZeroOrMinusOneIsInvalid + { + // Steal UIntPtr.MaxValue as our uninitialized value. + private static readonly UIntPtr Uninitialized = (UIntPtr.Size == 4) ? + ((UIntPtr) UInt32.MaxValue) : ((UIntPtr) UInt64.MaxValue); + + private UIntPtr _numBytes; + + protected SafeBuffer(bool ownsHandle) : base(ownsHandle) + { + _numBytes = Uninitialized; + } + + /// <summary> + /// Specifies the size of the region of memory, in bytes. Must be + /// called before using the SafeBuffer. + /// </summary> + /// <param name="numBytes">Number of valid bytes in memory.</param> + [CLSCompliant(false)] + public void Initialize(ulong numBytes) + { + if (numBytes < 0) + throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + if (IntPtr.Size == 4 && numBytes > UInt32.MaxValue) + throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_AddressSpace")); + Contract.EndContractBlock(); + + if (numBytes >= (ulong)Uninitialized) + throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_UIntPtrMax-1")); + + _numBytes = (UIntPtr) numBytes; + } + + /// <summary> + /// Specifies the the size of the region in memory, as the number of + /// elements in an array. Must be called before using the SafeBuffer. + /// </summary> + [CLSCompliant(false)] + public void Initialize(uint numElements, uint sizeOfEachElement) + { + if (numElements < 0) + throw new ArgumentOutOfRangeException("numElements", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + if (sizeOfEachElement < 0) + throw new ArgumentOutOfRangeException("sizeOfEachElement", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (IntPtr.Size == 4 && numElements * sizeOfEachElement > UInt32.MaxValue) + throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_AddressSpace")); + Contract.EndContractBlock(); + + if (numElements * sizeOfEachElement >= (ulong)Uninitialized) + throw new ArgumentOutOfRangeException("numElements", Environment.GetResourceString("ArgumentOutOfRange_UIntPtrMax-1")); + + _numBytes = checked((UIntPtr) (numElements * sizeOfEachElement)); + } + + /// <summary> + /// Specifies the the size of the region in memory, as the number of + /// elements in an array. Must be called before using the SafeBuffer. + /// </summary> + [CLSCompliant(false)] + public void Initialize<T>(uint numElements) where T : struct + { + Initialize(numElements, Marshal.AlignedSizeOf<T>()); + } + + // Callers should ensure that they check whether the pointer ref param + // is null when AcquirePointer returns. If it is not null, they must + // call ReleasePointer in a CER. This method calls DangerousAddRef + // & exposes the pointer. Unlike Read, it does not alter the "current + // position" of the pointer. Here's how to use it: + // + // byte* pointer = null; + // RuntimeHelpers.PrepareConstrainedRegions(); + // try { + // safeBuffer.AcquirePointer(ref pointer); + // // Use pointer here, with your own bounds checking + // } + // finally { + // if (pointer != null) + // safeBuffer.ReleasePointer(); + // } + // + // Note: If you cast this byte* to a T*, you have to worry about + // whether your pointer is aligned. Additionally, you must take + // responsibility for all bounds checking with this pointer. + /// <summary> + /// Obtain the pointer from a SafeBuffer for a block of code, + /// with the express responsibility for bounds checking and calling + /// ReleasePointer later within a CER to ensure the pointer can be + /// freed later. This method either completes successfully or + /// throws an exception and returns with pointer set to null. + /// </summary> + /// <param name="pointer">A byte*, passed by reference, to receive + /// the pointer from within the SafeBuffer. You must set + /// pointer to null before calling this method.</param> + [CLSCompliant(false)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + public void AcquirePointer(ref byte* pointer) + { + if (_numBytes == Uninitialized) + throw NotInitialized(); + + pointer = null; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + } + finally + { + bool junk = false; + DangerousAddRef(ref junk); + pointer = (byte*)handle; + } + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public void ReleasePointer() + { + if (_numBytes == Uninitialized) + throw NotInitialized(); + + DangerousRelease(); + } + + /// <summary> + /// Read a value type from memory at the given offset. This is + /// equivalent to: return *(T*)(bytePtr + byteOffset); + /// </summary> + /// <typeparam name="T">The value type to read</typeparam> + /// <param name="byteOffset">Where to start reading from memory. You + /// may have to consider alignment.</param> + /// <returns>An instance of T read from memory.</returns> + [CLSCompliant(false)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + public T Read<T>(ulong byteOffset) where T : struct { + if (_numBytes == Uninitialized) + throw NotInitialized(); + + uint sizeofT = Marshal.SizeOfType(typeof(T)); + byte* ptr = (byte*)handle + byteOffset; + SpaceCheck(ptr, sizeofT); + + // return *(T*) (_ptr + byteOffset); + T value; + bool mustCallRelease = false; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + DangerousAddRef(ref mustCallRelease); + + GenericPtrToStructure<T>(ptr, out value, sizeofT); + } + finally + { + if (mustCallRelease) + DangerousRelease(); + } + return value; + } + + [CLSCompliant(false)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + public void ReadArray<T>(ulong byteOffset, T[] array, int index, int count) + where T : struct + { + if (array == null) + throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer")); + if (index < 0) + throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + if (count < 0) + throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + if (array.Length - index < count) + throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); + Contract.EndContractBlock(); + + if (_numBytes == Uninitialized) + throw NotInitialized(); + + uint sizeofT = Marshal.SizeOfType(typeof(T)); + uint alignedSizeofT = Marshal.AlignedSizeOf<T>(); + byte* ptr = (byte*)handle + byteOffset; + SpaceCheck(ptr, checked((ulong)(alignedSizeofT * count))); + + bool mustCallRelease = false; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + DangerousAddRef(ref mustCallRelease); + + for (int i = 0; i < count; i++) + unsafe { GenericPtrToStructure<T>(ptr + alignedSizeofT * i, out array[i + index], sizeofT); } + } + finally + { + if (mustCallRelease) + DangerousRelease(); + } + } + + /// <summary> + /// Write a value type to memory at the given offset. This is + /// equivalent to: *(T*)(bytePtr + byteOffset) = value; + /// </summary> + /// <typeparam name="T">The type of the value type to write to memory.</typeparam> + /// <param name="byteOffset">The location in memory to write to. You + /// may have to consider alignment.</param> + /// <param name="value">The value type to write to memory.</param> + [CLSCompliant(false)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + public void Write<T>(ulong byteOffset, T value) where T : struct { + if (_numBytes == Uninitialized) + throw NotInitialized(); + + uint sizeofT = Marshal.SizeOfType(typeof(T)); + byte* ptr = (byte*)handle + byteOffset; + SpaceCheck(ptr, sizeofT); + + // *((T*) (_ptr + byteOffset)) = value; + bool mustCallRelease = false; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + DangerousAddRef(ref mustCallRelease); + GenericStructureToPtr(ref value, ptr, sizeofT); + } + finally + { + if (mustCallRelease) + DangerousRelease(); + } + } + + [CLSCompliant(false)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + public void WriteArray<T>(ulong byteOffset, T[] array, int index, int count) + where T : struct + { + if (array == null) + throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer")); + if (index < 0) + throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + if (count < 0) + throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + if (array.Length - index < count) + throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); + Contract.EndContractBlock(); + + if (_numBytes == Uninitialized) + throw NotInitialized(); + + uint sizeofT = Marshal.SizeOfType(typeof(T)); + uint alignedSizeofT = Marshal.AlignedSizeOf<T>(); + byte* ptr = (byte*)handle + byteOffset; + SpaceCheck(ptr, checked((ulong)(alignedSizeofT * count))); + + bool mustCallRelease = false; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + DangerousAddRef(ref mustCallRelease); + for (int i = 0; i < count; i++) + unsafe { GenericStructureToPtr(ref array[i + index], ptr + alignedSizeofT * i, sizeofT); } + } + finally + { + if (mustCallRelease) + DangerousRelease(); + } + } + + + /// <summary> + /// Returns the number of bytes in the memory region. + /// </summary> + [CLSCompliant(false)] + public ulong ByteLength { + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + get { + if (_numBytes == Uninitialized) + throw NotInitialized(); + + return (ulong) _numBytes; + } + } + + /* No indexer. The perf would be misleadingly bad. People should use + * AcquirePointer and ReleasePointer instead. */ + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private void SpaceCheck(byte* ptr, ulong sizeInBytes) + { + if ((ulong)_numBytes < sizeInBytes) + NotEnoughRoom(); + if ((ulong)(ptr - (byte*) handle) > ((ulong)_numBytes) - sizeInBytes) + NotEnoughRoom(); + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private static void NotEnoughRoom() + { + throw new ArgumentException(Environment.GetResourceString("Arg_BufferTooSmall")); + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private static InvalidOperationException NotInitialized() + { + Contract.Assert(false, "Uninitialized SafeBuffer! Someone needs to call Initialize before using this instance!"); + return new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MustCallInitialize")); + } + + // FCALL limitations mean we can't have generic FCALL methods. However, we can pass + // TypedReferences to FCALL methods. + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static void GenericPtrToStructure<T>(byte* ptr, out T structure, uint sizeofT) where T : struct + { + structure = default(T); // Dummy assignment to silence the compiler + PtrToStructureNative(ptr, __makeref(structure), sizeofT); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private static extern void PtrToStructureNative(byte* ptr, /*out T*/ TypedReference structure, uint sizeofT); + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static void GenericStructureToPtr<T>(ref T structure, byte* ptr, uint sizeofT) where T : struct + { + StructureToPtrNative(__makeref(structure), ptr, sizeofT); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private static extern void StructureToPtrNative(/*ref T*/ TypedReference structure, byte* ptr, uint sizeofT); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SafeHandle.cs b/src/mscorlib/src/System/Runtime/InteropServices/SafeHandle.cs new file mode 100644 index 0000000000..d839be3897 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/SafeHandle.cs @@ -0,0 +1,316 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================ +** +** +** +** A specially designed handle wrapper to ensure we never leak +** an OS handle. The runtime treats this class specially during +** P/Invoke marshaling and finalization. Users should write +** subclasses of SafeHandle for each distinct handle type. +** +** +===========================================================*/ + +namespace System.Runtime.InteropServices { + +using System; +using System.Reflection; +using System.Threading; +using System.Security.Permissions; +using System.Runtime; +using System.Runtime.CompilerServices; +using System.IO; +using System.Runtime.ConstrainedExecution; +using System.Runtime.Versioning; + +/* + Problems addressed by the SafeHandle class: + 1) Critical finalization - ensure we never leak OS resources in SQL. Done + without running truly arbitrary & unbounded amounts of managed code. + 2) Reduced graph promotion - during finalization, keep object graph small + 3) GC.KeepAlive behavior - P/Invoke vs. finalizer thread race conditions (HandleRef) + 4) Elimination of security race conditions w/ explicit calls to Close (HandleProtector) + 5) Enforcement of the above via the type system - Don't use IntPtr anymore. + 6) Allows the handle lifetime to be controlled externally via a boolean. + + Subclasses of SafeHandle will implement the ReleaseHandle abstract method + used to execute any code required to free the handle. This method will be + prepared as a constrained execution region at instance construction time + (along with all the methods in its statically determinable call graph). This + implies that we won't get any inconvenient jit allocation errors or rude + thread abort interrupts while releasing the handle but the user must still + write careful code to avoid injecting fault paths of their own (see the CER + spec for more details). In particular, any sub-methods you call should be + decorated with a reliability contract of the appropriate level. In most cases + this should be: + ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success) + Also, any P/Invoke methods should use the SuppressUnmanagedCodeSecurity + attribute to avoid a runtime security check that can also inject failures + (even if the check is guaranteed to pass). + + The GC will run ReleaseHandle methods after any normal finalizers have been + run for objects that were collected at the same time. This ensures classes + like FileStream can run a normal finalizer to flush out existing buffered + data. This is key - it means adding this class to a class like FileStream does + not alter our current semantics w.r.t. finalization today. + + Subclasses must also implement the IsInvalid property so that the + infrastructure can tell when critical finalization is actually required. + Again, this method is prepared ahead of time. It's envisioned that direct + subclasses of SafeHandle will provide an IsInvalid implementation that suits + the general type of handle they support (null is invalid, -1 is invalid etc.) + and then these classes will be further derived for specific safe handle types. + + Most classes using SafeHandle should not provide a finalizer. If they do + need to do so (ie, for flushing out file buffers, needing to write some data + back into memory, etc), then they can provide a finalizer that will be + guaranteed to run before the SafeHandle's critical finalizer. + + Note that SafeHandle's ReleaseHandle is called from a constrained execution + region, and is eagerly prepared before we create your class. This means you + should only call methods with an appropriate reliability contract from your + ReleaseHandle method. + + Subclasses are expected to be written as follows (note that + SuppressUnmanagedCodeSecurity should always be used on any P/Invoke methods + invoked as part of ReleaseHandle, in order to switch the security check from + runtime to jit time and thus remove a possible failure path from the + invocation of the method): + + internal sealed MySafeHandleSubclass : SafeHandle { + // Called by P/Invoke when returning SafeHandles + private MySafeHandleSubclass() : base(IntPtr.Zero, true) + { + } + + // If & only if you need to support user-supplied handles + internal MySafeHandleSubclass(IntPtr preexistingHandle, bool ownsHandle) : base(IntPtr.Zero, ownsHandle) + { + SetHandle(preexistingHandle); + } + + // Do not provide a finalizer - SafeHandle's critical finalizer will + // call ReleaseHandle for you. + + public override bool IsInvalid { + get { return handle == IntPtr.Zero; } + } + + override protected bool ReleaseHandle() + { + return MyNativeMethods.CloseHandle(handle); + } + } + + Then elsewhere to create one of these SafeHandles, define a method + with the following type of signature (CreateFile follows this model). + Note that when returning a SafeHandle like this, P/Invoke will call your + class's default constructor. Also, you probably want to define CloseHandle + somewhere, and remember to apply a reliability contract to it. + + [SuppressUnmanagedCodeSecurity] + internal static class MyNativeMethods { + [DllImport("kernel32")] + private static extern MySafeHandleSubclass CreateHandle(int someState); + + [DllImport("kernel32", SetLastError=true), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private static extern bool CloseHandle(IntPtr handle); + } + + Drawbacks with this implementation: + 1) Requires some magic to run the critical finalizer. + 2) Requires more memory than just an IntPtr. + 3) If you use DangerousAddRef and forget to call DangerousRelease, you can leak a SafeHandle. Use CER's & don't do that. + */ + + +// This class should not be serializable - it's a handle. We require unmanaged +// code permission to subclass SafeHandle to prevent people from writing a +// subclass and suddenly being able to run arbitrary native code with the +// same signature as CloseHandle. This is technically a little redundant, but +// we'll do this to ensure we've cut off all attack vectors. Similarly, all +// methods have a link demand to ensure untrusted code cannot directly edit +// or alter a handle. +[System.Security.SecurityCritical] // auto-generated_required +#if !FEATURE_CORECLR +[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode=true)] +#endif +public abstract class SafeHandle : CriticalFinalizerObject, IDisposable +{ + // ! Do not add or rearrange fields as the EE depends on this layout. + //------------------------------------------------------------------ +#if DEBUG + // FxCop thinks this field is marshaled and so it raises a CA2101 error unless + // we specify this. In practice this is never presented to Win32. + [MarshalAs(UnmanagedType.LPWStr)] + private String _stackTrace; // Where we allocated this SafeHandle. +#endif + protected IntPtr handle; // this must be protected so derived classes can use out params. + private int _state; // Combined ref count and closed/disposed flags (so we can atomically modify them). + private bool _ownsHandle; // Whether we can release this handle. +#pragma warning disable 414 + private bool _fullyInitialized; // Whether constructor completed. +#pragma warning restore 414 + + // Creates a SafeHandle class. Users must then set the Handle property. + // To prevent the SafeHandle from being freed, write a subclass that + // doesn't define a finalizer. + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected SafeHandle(IntPtr invalidHandleValue, bool ownsHandle) + { + handle = invalidHandleValue; + _state = 4; // Ref count 1 and not closed or disposed. + _ownsHandle = ownsHandle; + + if (!ownsHandle) + GC.SuppressFinalize(this); + +#if DEBUG + if (BCLDebug.SafeHandleStackTracesEnabled) + _stackTrace = Environment.GetStackTrace(null, false); + else + _stackTrace = "For a stack trace showing who allocated this SafeHandle, set SafeHandleStackTraces to 1 and rerun your app."; +#endif + + // Set this last to prevent SafeHandle's finalizer from freeing an + // invalid handle. This means we don't have to worry about + // ThreadAbortExceptions interrupting this constructor or the managed + // constructors on subclasses that call this constructor. + _fullyInitialized = true; + } + +#if FEATURE_CORECLR + // Migrating InheritanceDemands requires this default ctor, so we can mark it critical + protected SafeHandle() + { + BCLDebug.Assert(false, "SafeHandle's protected default ctor should never be used!"); + throw new NotImplementedException(); + } +#endif + + [System.Security.SecuritySafeCritical] // auto-generated + ~SafeHandle() + { + Dispose(false); + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + extern void InternalFinalize(); + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + protected void SetHandle(IntPtr handle) { + this.handle = handle; + } + + // This method is necessary for getting an IntPtr out of a SafeHandle. + // Used to tell whether a call to create the handle succeeded by comparing + // the handle against a known invalid value, and for backwards + // compatibility to support the handle properties returning IntPtrs on + // many of our Framework classes. + // Note that this method is dangerous for two reasons: + // 1) If the handle has been marked invalid with SetHandleasInvalid, + // DangerousGetHandle will still return the original handle value. + // 2) The handle returned may be recycled at any point. At best this means + // the handle might stop working suddenly. At worst, if the handle or + // the resource the handle represents is exposed to untrusted code in + // any way, this can lead to a handle recycling security attack (i.e. an + // untrusted caller can query data on the handle you've just returned + // and get back information for an entirely unrelated resource). + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public IntPtr DangerousGetHandle() + { + return handle; + } + + public bool IsClosed { + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + get { return (_state & 1) == 1; } + } + + public abstract bool IsInvalid { + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + get; + } + + [System.Security.SecurityCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public void Close() { + Dispose(true); + } + + [System.Security.SecuritySafeCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public void Dispose() { + Dispose(true); + } + + [System.Security.SecurityCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + protected virtual void Dispose(bool disposing) + { + if (disposing) + InternalDispose(); + else + InternalFinalize(); + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private extern void InternalDispose(); + + // This should only be called for cases when you know for a fact that + // your handle is invalid and you want to record that information. + // An example is calling a syscall and getting back ERROR_INVALID_HANDLE. + // This method will normally leak handles! + [System.Security.SecurityCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public extern void SetHandleAsInvalid(); + + // Implement this abstract method in your derived class to specify how to + // free the handle. Be careful not write any code that's subject to faults + // in this method (the runtime will prepare the infrastructure for you so + // that no jit allocations etc. will occur, but don't allocate memory unless + // you can deal with the failure and still free the handle). + // The boolean returned should be true for success and false if the runtime + // should fire a SafeHandleCriticalFailure MDA (CustomerDebugProbe) if that + // MDA is enabled. + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + protected abstract bool ReleaseHandle(); + + // Add a reason why this handle should not be relinquished (i.e. have + // ReleaseHandle called on it). This method has dangerous in the name since + // it must always be used carefully (e.g. called within a CER) to avoid + // leakage of the handle. It returns a boolean indicating whether the + // increment was actually performed to make it easy for program logic to + // back out in failure cases (i.e. is a call to DangerousRelease needed). + // It is passed back via a ref parameter rather than as a direct return so + // that callers need not worry about the atomicity of calling the routine + // and assigning the return value to a variable (the variable should be + // explicitly set to false prior to the call). The only failure cases are + // when the method is interrupted prior to processing by a thread abort or + // when the handle has already been (or is in the process of being) + // released. + [System.Security.SecurityCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public extern void DangerousAddRef(ref bool success); + + // Partner to DangerousAddRef. This should always be successful when used in + // a correct manner (i.e. matching a successful DangerousAddRef and called + // from a region such as a CER where a thread abort cannot interrupt + // processing). In the same way that unbalanced DangerousAddRef calls can + // cause resource leakage, unbalanced DangerousRelease calls may cause + // invalid handle states to become visible to other threads. This + // constitutes a potential security hole (via handle recycling) as well as a + // correctness problem -- so don't ever expose Dangerous* calls out to + // untrusted code. + [System.Security.SecurityCritical] // auto-generated + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public extern void DangerousRelease(); +} +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventItfInfo.cs b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventItfInfo.cs new file mode 100644 index 0000000000..52ebd09b80 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventItfInfo.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Runtime.InteropServices.TCEAdapterGen { + + using System; + using System.Reflection; + using System.Collections; + + internal class EventItfInfo + { + public EventItfInfo(String strEventItfName, + String strSrcItfName, + String strEventProviderName, + RuntimeAssembly asmImport, + RuntimeAssembly asmSrcItf) + { + m_strEventItfName = strEventItfName; + m_strSrcItfName = strSrcItfName; + m_strEventProviderName = strEventProviderName; + m_asmImport = asmImport; + m_asmSrcItf = asmSrcItf; + } + + public Type GetEventItfType() + { + Type t = m_asmImport.GetType(m_strEventItfName, true, false); + if (t != null && !t.IsVisible) + t = null; + return t; + } + + public Type GetSrcItfType() + { + Type t = m_asmSrcItf.GetType(m_strSrcItfName, true, false); + if (t != null && !t.IsVisible) + t = null; + return t; + } + + public String GetEventProviderName() + { + return m_strEventProviderName; + } + + private String m_strEventItfName; + private String m_strSrcItfName; + private String m_strEventProviderName; + private RuntimeAssembly m_asmImport; + private RuntimeAssembly m_asmSrcItf; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventProviderWriter.cs b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventProviderWriter.cs new file mode 100644 index 0000000000..2427a5fb39 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventProviderWriter.cs @@ -0,0 +1,772 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Runtime.InteropServices.TCEAdapterGen { + using System.Runtime.InteropServices.ComTypes; + using ubyte = System.Byte; + using System; + using System.Reflection; + using System.Reflection.Emit; + using System.Collections; + using System.Threading; + using System.Diagnostics.Contracts; + + internal class EventProviderWriter + { + private const BindingFlags DefaultLookup = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public; + + private readonly Type[] MonitorEnterParamTypes = new Type[] { typeof(Object), Type.GetType("System.Boolean&") }; + + public EventProviderWriter( ModuleBuilder OutputModule, String strDestTypeName, Type EventItfType, Type SrcItfType, Type SinkHelperType ) + { + m_OutputModule = OutputModule; + m_strDestTypeName = strDestTypeName; + m_EventItfType = EventItfType; + m_SrcItfType = SrcItfType; + m_SinkHelperType = SinkHelperType; + } + + public Type Perform() + { + // Create the event provider class. + TypeBuilder OutputTypeBuilder = m_OutputModule.DefineType( + m_strDestTypeName, + TypeAttributes.Sealed | TypeAttributes.NotPublic, + typeof(Object), + new Type[]{m_EventItfType, typeof(IDisposable)} + ); + + // Create the event source field. + FieldBuilder fbCPC = OutputTypeBuilder.DefineField( + "m_ConnectionPointContainer", + typeof(IConnectionPointContainer), + FieldAttributes.Private + ); + + // Create array of event sink helpers. + FieldBuilder fbSinkHelper = OutputTypeBuilder.DefineField( + "m_aEventSinkHelpers", + typeof(ArrayList), + FieldAttributes.Private + ); + + // Define the connection point field. + FieldBuilder fbEventCP = OutputTypeBuilder.DefineField( + "m_ConnectionPoint", + typeof(IConnectionPoint), + FieldAttributes.Private + ); + + // Define the InitXXX method. + MethodBuilder InitSrcItfMethodBuilder = + DefineInitSrcItfMethod( OutputTypeBuilder, m_SrcItfType, fbSinkHelper, fbEventCP, fbCPC ); + + // Process all the methods in the event interface. + MethodInfo[] aMethods = TCEAdapterGenerator.GetNonPropertyMethods(m_SrcItfType); + for ( int cMethods = 0; cMethods < aMethods.Length; cMethods++ ) + { + if ( m_SrcItfType == aMethods[cMethods].DeclaringType ) + { + // Define the add_XXX method. + MethodBuilder AddEventMethodBuilder = DefineAddEventMethod( + OutputTypeBuilder, aMethods[cMethods], m_SinkHelperType, fbSinkHelper, fbEventCP, InitSrcItfMethodBuilder ); + + // Define the remove_XXX method. + MethodBuilder RemoveEventMethodBuilder = DefineRemoveEventMethod( + OutputTypeBuilder, aMethods[cMethods], m_SinkHelperType, fbSinkHelper, fbEventCP ); + } + } + + // Define the constructor. + DefineConstructor( OutputTypeBuilder, fbCPC ); + + // Define the finalize method. + MethodBuilder FinalizeMethod = DefineFinalizeMethod( OutputTypeBuilder, m_SinkHelperType, fbSinkHelper, fbEventCP ); + + // Define the Dispose method. + DefineDisposeMethod( OutputTypeBuilder, FinalizeMethod); + + return OutputTypeBuilder.CreateType(); + } + + private MethodBuilder DefineAddEventMethod( TypeBuilder OutputTypeBuilder, MethodInfo SrcItfMethod, Type SinkHelperClass, FieldBuilder fbSinkHelperArray, FieldBuilder fbEventCP, MethodBuilder mbInitSrcItf ) + { + Type[] aParamTypes; + + // Find the delegate on the event sink helper. + FieldInfo DelegateField = SinkHelperClass.GetField( "m_" + SrcItfMethod.Name + "Delegate" ); + Contract.Assert(DelegateField != null, "Unable to find the field m_" + SrcItfMethod.Name + "Delegate on the sink helper"); + + // Find the cookie on the event sink helper. + FieldInfo CookieField = SinkHelperClass.GetField( "m_dwCookie" ); + Contract.Assert(CookieField != null, "Unable to find the field m_dwCookie on the sink helper"); + + // Retrieve the sink helper's constructor. + ConstructorInfo SinkHelperCons = SinkHelperClass.GetConstructor(EventProviderWriter.DefaultLookup | BindingFlags.NonPublic, null, new Type[0], null ); + Contract.Assert(SinkHelperCons != null, "Unable to find the constructor for the sink helper"); + + // Retrieve the IConnectionPoint.Advise method. + MethodInfo CPAdviseMethod = typeof(IConnectionPoint).GetMethod( "Advise" ); + Contract.Assert(CPAdviseMethod != null, "Unable to find the method ConnectionPoint.Advise"); + + // Retrieve the ArrayList.Add method. + aParamTypes = new Type[1]; + aParamTypes[0] = typeof(Object); + MethodInfo ArrayListAddMethod = typeof(ArrayList).GetMethod( "Add", aParamTypes, null ); + Contract.Assert(ArrayListAddMethod != null, "Unable to find the method ArrayList.Add"); + + // Retrieve the Monitor.Enter() method. + MethodInfo MonitorEnterMethod = typeof(Monitor).GetMethod( "Enter", MonitorEnterParamTypes, null ); + Contract.Assert(MonitorEnterMethod != null, "Unable to find the method Monitor.Enter()"); + + // Retrieve the Monitor.Exit() method. + aParamTypes[0] = typeof(Object); + MethodInfo MonitorExitMethod = typeof(Monitor).GetMethod( "Exit", aParamTypes, null ); + Contract.Assert(MonitorExitMethod != null, "Unable to find the method Monitor.Exit()"); + + // Define the add_XXX method. + Type[] parameterTypes; + parameterTypes = new Type[1]; + parameterTypes[0] = DelegateField.FieldType; + MethodBuilder Meth = OutputTypeBuilder.DefineMethod( + "add_" + SrcItfMethod.Name, + MethodAttributes.Public | MethodAttributes.Virtual, + null, + parameterTypes ); + + ILGenerator il = Meth.GetILGenerator(); + + // Define a label for the m_IFooEventsCP comparision. + Label EventCPNonNullLabel = il.DefineLabel(); + + // Declare the local variables. + LocalBuilder ltSinkHelper = il.DeclareLocal( SinkHelperClass ); + LocalBuilder ltCookie = il.DeclareLocal( typeof(Int32) ); + LocalBuilder ltLockTaken = il.DeclareLocal( typeof(bool) ); + + // Generate the following code: + // try { + il.BeginExceptionBlock(); + + // Generate the following code: + // Monitor.Enter(this, ref lockTaken); + il.Emit(OpCodes.Ldarg, (short)0); + il.Emit(OpCodes.Ldloca_S, ltLockTaken); + il.Emit(OpCodes.Call, MonitorEnterMethod); + + // Generate the following code: + // if ( m_IFooEventsCP != null ) goto EventCPNonNullLabel; + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbEventCP ); + il.Emit( OpCodes.Brtrue, EventCPNonNullLabel ); + + // Generate the following code: + // InitIFooEvents(); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Call, mbInitSrcItf ); + + // Mark this as label to jump to if the CP is not null. + il.MarkLabel( EventCPNonNullLabel ); + + // Generate the following code: + // IFooEvents_SinkHelper SinkHelper = new IFooEvents_SinkHelper; + il.Emit( OpCodes.Newobj, SinkHelperCons ); + il.Emit( OpCodes.Stloc, ltSinkHelper ); + + // Generate the following code: + // dwCookie = 0; + il.Emit( OpCodes.Ldc_I4_0 ); + il.Emit( OpCodes.Stloc, ltCookie ); + + // Generate the following code: + // m_IFooEventsCP.Advise( SinkHelper, dwCookie ); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbEventCP ); + il.Emit( OpCodes.Ldloc, ltSinkHelper ); + il.Emit( OpCodes.Castclass, typeof(Object) ); + il.Emit( OpCodes.Ldloca, ltCookie ); + il.Emit( OpCodes.Callvirt, CPAdviseMethod ); + + // Generate the following code: + // SinkHelper.m_dwCookie = dwCookie; + il.Emit( OpCodes.Ldloc, ltSinkHelper ); + il.Emit( OpCodes.Ldloc, ltCookie ); + il.Emit( OpCodes.Stfld, CookieField ); + + // Generate the following code: + // SinkHelper.m_FooDelegate = d; + il.Emit( OpCodes.Ldloc, ltSinkHelper ); + il.Emit( OpCodes.Ldarg, (short)1 ); + il.Emit( OpCodes.Stfld, DelegateField ); + + // Generate the following code: + // m_aIFooEventsHelpers.Add( SinkHelper ); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbSinkHelperArray ); + il.Emit( OpCodes.Ldloc, ltSinkHelper ); + il.Emit( OpCodes.Castclass, typeof(Object) ); + il.Emit( OpCodes.Callvirt, ArrayListAddMethod ); + il.Emit( OpCodes.Pop ); + + // Generate the following code: + // } finally { + il.BeginFinallyBlock(); + + // Generate the following code: + // if (lockTaken) + // Monitor.Exit(this); + Label skipExit = il.DefineLabel(); + il.Emit( OpCodes.Ldloc, ltLockTaken ); + il.Emit( OpCodes.Brfalse_S, skipExit ); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Call, MonitorExitMethod ); + il.MarkLabel(skipExit); + + // Generate the following code: + // } + il.EndExceptionBlock(); + + // Generate the return opcode. + il.Emit( OpCodes.Ret ); + + return Meth; + } + + private MethodBuilder DefineRemoveEventMethod( TypeBuilder OutputTypeBuilder, MethodInfo SrcItfMethod, Type SinkHelperClass, FieldBuilder fbSinkHelperArray, FieldBuilder fbEventCP ) + { + Type[] aParamTypes; + + // Find the delegate on the event sink helper. + FieldInfo DelegateField = SinkHelperClass.GetField( "m_" + SrcItfMethod.Name + "Delegate" ); + Contract.Assert(DelegateField != null, "Unable to find the field m_" + SrcItfMethod.Name + "Delegate on the sink helper"); + + // Find the cookie on the event sink helper. + FieldInfo CookieField = SinkHelperClass.GetField( "m_dwCookie" ); + Contract.Assert(CookieField != null, "Unable to find the field m_dwCookie on the sink helper"); + + // Retrieve the ArrayList.RemoveAt method. + aParamTypes = new Type[1]; + aParamTypes[0] = typeof(Int32); + MethodInfo ArrayListRemoveMethod = typeof(ArrayList).GetMethod( "RemoveAt", aParamTypes, null ); + Contract.Assert(ArrayListRemoveMethod != null, "Unable to find the method ArrayList.RemoveAt()"); + + // Retrieve the ArrayList.Item property get method. + PropertyInfo ArrayListItemProperty = typeof(ArrayList).GetProperty( "Item" ); + Contract.Assert(ArrayListItemProperty != null, "Unable to find the property ArrayList.Item"); + MethodInfo ArrayListItemGetMethod = ArrayListItemProperty.GetGetMethod(); + Contract.Assert(ArrayListItemGetMethod != null, "Unable to find the get method for property ArrayList.Item"); + + // Retrieve the ArrayList.Count property get method. + PropertyInfo ArrayListSizeProperty = typeof(ArrayList).GetProperty( "Count" ); + Contract.Assert(ArrayListSizeProperty != null, "Unable to find the property ArrayList.Count"); + MethodInfo ArrayListSizeGetMethod = ArrayListSizeProperty.GetGetMethod(); + Contract.Assert(ArrayListSizeGetMethod != null, "Unable to find the get method for property ArrayList.Count"); + + // Retrieve the Delegate.Equals() method. + aParamTypes[0] = typeof(Delegate); + MethodInfo DelegateEqualsMethod = typeof(Delegate).GetMethod( "Equals", aParamTypes, null ); + Contract.Assert(DelegateEqualsMethod != null, "Unable to find the method Delegate.Equlals()"); + + // Retrieve the Monitor.Enter() method. + MethodInfo MonitorEnterMethod = typeof(Monitor).GetMethod("Enter", MonitorEnterParamTypes, null); + Contract.Assert(MonitorEnterMethod != null, "Unable to find the method Monitor.Enter()"); + + // Retrieve the Monitor.Exit() method. + aParamTypes[0] = typeof(Object); + MethodInfo MonitorExitMethod = typeof(Monitor).GetMethod( "Exit", aParamTypes, null ); + Contract.Assert(MonitorExitMethod != null, "Unable to find the method Monitor.Exit()"); + + // Retrieve the ConnectionPoint.Unadvise() method. + MethodInfo CPUnadviseMethod = typeof(IConnectionPoint).GetMethod( "Unadvise" ); + Contract.Assert(CPUnadviseMethod != null, "Unable to find the method ConnectionPoint.Unadvise()"); + + // Retrieve the Marshal.ReleaseComObject() method. + MethodInfo ReleaseComObjectMethod = typeof(Marshal).GetMethod( "ReleaseComObject" ); + Contract.Assert(ReleaseComObjectMethod != null, "Unable to find the method Marshal.ReleaseComObject()"); + + // Define the remove_XXX method. + Type[] parameterTypes; + parameterTypes = new Type[1]; + parameterTypes[0] = DelegateField.FieldType; + MethodBuilder Meth = OutputTypeBuilder.DefineMethod( + "remove_" + SrcItfMethod.Name, + MethodAttributes.Public | MethodAttributes.Virtual, + null, + parameterTypes ); + + ILGenerator il = Meth.GetILGenerator(); + + // Declare the local variables. + LocalBuilder ltNumSinkHelpers = il.DeclareLocal( typeof(Int32) ); + LocalBuilder ltSinkHelperCounter = il.DeclareLocal( typeof(Int32) ); + LocalBuilder ltCurrSinkHelper = il.DeclareLocal( SinkHelperClass ); + LocalBuilder ltLockTaken = il.DeclareLocal(typeof(bool)); + + // Generate the labels for the for loop. + Label ForBeginLabel = il.DefineLabel(); + Label ForEndLabel = il.DefineLabel(); + Label FalseIfLabel = il.DefineLabel(); + Label MonitorExitLabel = il.DefineLabel(); + + // Generate the following code: + // try { + il.BeginExceptionBlock(); + + // Generate the following code: + // Monitor.Enter(this, ref lockTaken); + il.Emit(OpCodes.Ldarg, (short)0); + il.Emit(OpCodes.Ldloca_S, ltLockTaken); + il.Emit(OpCodes.Call, MonitorEnterMethod); + + // Generate the following code: + // if ( m_aIFooEventsHelpers == null ) goto ForEndLabel; + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbSinkHelperArray ); + il.Emit( OpCodes.Brfalse, ForEndLabel ); + + // Generate the following code: + // int NumEventHelpers = m_aIFooEventsHelpers.Count; + // int cEventHelpers = 0; + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbSinkHelperArray ); + il.Emit( OpCodes.Callvirt, ArrayListSizeGetMethod ); + il.Emit( OpCodes.Stloc, ltNumSinkHelpers ); + il.Emit( OpCodes.Ldc_I4, 0 ); + il.Emit( OpCodes.Stloc, ltSinkHelperCounter ); + + // Generate the following code: + // if ( 0 >= NumEventHelpers ) goto ForEndLabel; + il.Emit( OpCodes.Ldc_I4, 0 ); + il.Emit( OpCodes.Ldloc, ltNumSinkHelpers ); + il.Emit( OpCodes.Bge, ForEndLabel ); + + // Mark this as the beginning of the for loop's body. + il.MarkLabel( ForBeginLabel ); + + // Generate the following code: + // CurrentHelper = (IFooEvents_SinkHelper)m_aIFooEventsHelpers.Get( cEventHelpers ); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbSinkHelperArray ); + il.Emit( OpCodes.Ldloc, ltSinkHelperCounter ); + il.Emit( OpCodes.Callvirt, ArrayListItemGetMethod ); + il.Emit( OpCodes.Castclass, SinkHelperClass ); + il.Emit( OpCodes.Stloc, ltCurrSinkHelper ); + + // Generate the following code: + // if ( CurrentHelper.m_FooDelegate ) + il.Emit( OpCodes.Ldloc, ltCurrSinkHelper ); + il.Emit( OpCodes.Ldfld, DelegateField ); + il.Emit( OpCodes.Ldnull ); + il.Emit( OpCodes.Beq, FalseIfLabel ); + + // Generate the following code: + // if ( CurrentHelper.m_FooDelegate.Equals( d ) ) + il.Emit( OpCodes.Ldloc, ltCurrSinkHelper ); + il.Emit( OpCodes.Ldfld, DelegateField ); + il.Emit( OpCodes.Ldarg, (short)1 ); + il.Emit( OpCodes.Castclass, typeof(Object) ); + il.Emit( OpCodes.Callvirt, DelegateEqualsMethod ); + il.Emit( OpCodes.Ldc_I4, 0xff ); + il.Emit( OpCodes.And ); + il.Emit( OpCodes.Ldc_I4, 0 ); + il.Emit( OpCodes.Beq, FalseIfLabel ); + + // Generate the following code: + // m_aIFooEventsHelpers.RemoveAt( cEventHelpers ); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbSinkHelperArray ); + il.Emit( OpCodes.Ldloc, ltSinkHelperCounter ); + il.Emit( OpCodes.Callvirt, ArrayListRemoveMethod ); + + // Generate the following code: + // m_IFooEventsCP.Unadvise( CurrentHelper.m_dwCookie ); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbEventCP ); + il.Emit( OpCodes.Ldloc, ltCurrSinkHelper ); + il.Emit( OpCodes.Ldfld, CookieField ); + il.Emit( OpCodes.Callvirt, CPUnadviseMethod ); + + // Generate the following code: + // if ( NumEventHelpers > 1) break; + il.Emit( OpCodes.Ldloc, ltNumSinkHelpers ); + il.Emit( OpCodes.Ldc_I4, 1 ); + il.Emit( OpCodes.Bgt, ForEndLabel ); + + // Generate the following code: + // Marshal.ReleaseComObject(m_IFooEventsCP); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbEventCP ); + il.Emit( OpCodes.Call, ReleaseComObjectMethod ); + il.Emit( OpCodes.Pop ); + + // Generate the following code: + // m_IFooEventsCP = null; + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldnull ); + il.Emit( OpCodes.Stfld, fbEventCP ); + + // Generate the following code: + // m_aIFooEventsHelpers = null; + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldnull ); + il.Emit( OpCodes.Stfld, fbSinkHelperArray ); + + // Generate the following code: + // break; + il.Emit( OpCodes.Br, ForEndLabel ); + + // Mark this as the label to jump to when the if statement is false. + il.MarkLabel( FalseIfLabel ); + + // Generate the following code: + // cEventHelpers++; + il.Emit( OpCodes.Ldloc, ltSinkHelperCounter ); + il.Emit( OpCodes.Ldc_I4, 1 ); + il.Emit( OpCodes.Add ); + il.Emit( OpCodes.Stloc, ltSinkHelperCounter ); + + // Generate the following code: + // if ( cEventHelpers < NumEventHelpers ) goto ForBeginLabel; + il.Emit( OpCodes.Ldloc, ltSinkHelperCounter ); + il.Emit( OpCodes.Ldloc, ltNumSinkHelpers ); + il.Emit( OpCodes.Blt, ForBeginLabel ); + + // Mark this as the end of the for loop's body. + il.MarkLabel( ForEndLabel ); + + // Generate the following code: + // } finally { + il.BeginFinallyBlock(); + + // Generate the following code: + // if (lockTaken) + // Monitor.Exit(this); + Label skipExit = il.DefineLabel(); + il.Emit(OpCodes.Ldloc, ltLockTaken); + il.Emit(OpCodes.Brfalse_S, skipExit); + il.Emit(OpCodes.Ldarg, (short)0); + il.Emit(OpCodes.Call, MonitorExitMethod); + il.MarkLabel(skipExit); + + // Generate the following code: + // } + il.EndExceptionBlock(); + + // Generate the return opcode. + il.Emit( OpCodes.Ret ); + + return Meth; + } + + private MethodBuilder DefineInitSrcItfMethod( TypeBuilder OutputTypeBuilder, Type SourceInterface, FieldBuilder fbSinkHelperArray, FieldBuilder fbEventCP, FieldBuilder fbCPC ) + { + // Retrieve the constructor info for the array list's default constructor. + ConstructorInfo DefaultArrayListCons = typeof(ArrayList).GetConstructor(EventProviderWriter.DefaultLookup, null, new Type[0], null ); + Contract.Assert(DefaultArrayListCons != null, "Unable to find the constructor for class ArrayList"); + + // Temp byte array for Guid + ubyte[] rgByteGuid = new ubyte[16]; + + // Retrieve the constructor info for the Guid constructor. + Type[] aParamTypes = new Type[1]; + aParamTypes[0] = typeof(Byte[]); + ConstructorInfo ByteArrayGUIDCons = typeof(Guid).GetConstructor(EventProviderWriter.DefaultLookup, null, aParamTypes, null ); + Contract.Assert(ByteArrayGUIDCons != null, "Unable to find the constructor for GUID that accepts a string as argument"); + + // Retrieve the IConnectionPointContainer.FindConnectionPoint() method. + MethodInfo CPCFindCPMethod = typeof(IConnectionPointContainer).GetMethod( "FindConnectionPoint" ); + Contract.Assert(CPCFindCPMethod != null, "Unable to find the method ConnectionPointContainer.FindConnectionPoint()"); + + // Define the Init method itself. + MethodBuilder Meth = OutputTypeBuilder.DefineMethod( + "Init", + MethodAttributes.Private, + null, + null ); + + ILGenerator il = Meth.GetILGenerator(); + + // Declare the local variables. + LocalBuilder ltCP = il.DeclareLocal( typeof(IConnectionPoint) ); + LocalBuilder ltEvGuid = il.DeclareLocal( typeof(Guid) ); + LocalBuilder ltByteArrayGuid = il.DeclareLocal( typeof(Byte[]) ); + + // Generate the following code: + // IConnectionPoint CP = NULL; + il.Emit( OpCodes.Ldnull ); + il.Emit( OpCodes.Stloc, ltCP ); + + // Get unsigned byte array for the GUID of the event interface. + rgByteGuid = SourceInterface.GUID.ToByteArray(); + + // Generate the following code: + // ubyte rgByteArray[] = new ubyte [16]; + il.Emit( OpCodes.Ldc_I4, 0x10 ); + il.Emit( OpCodes.Newarr, typeof(Byte) ); + il.Emit( OpCodes.Stloc, ltByteArrayGuid ); + + // Generate the following code: + // rgByteArray[i] = rgByteGuid[i]; + for (int i = 0; i < 16; i++ ) + { + il.Emit( OpCodes.Ldloc, ltByteArrayGuid ); + il.Emit( OpCodes.Ldc_I4, i ); + il.Emit( OpCodes.Ldc_I4, (int) (rgByteGuid[i]) ); + il.Emit( OpCodes.Stelem_I1); + } + + // Generate the following code: + // EventItfGuid = Guid( ubyte b[] ); + il.Emit( OpCodes.Ldloca, ltEvGuid ); + il.Emit( OpCodes.Ldloc, ltByteArrayGuid ); + il.Emit( OpCodes.Call, ByteArrayGUIDCons ); + + // Generate the following code: + // m_ConnectionPointContainer.FindConnectionPoint( EventItfGuid, CP ); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbCPC ); + il.Emit( OpCodes.Ldloca, ltEvGuid ); + il.Emit( OpCodes.Ldloca, ltCP ); + il.Emit( OpCodes.Callvirt, CPCFindCPMethod ); + + // Generate the following code: + // m_ConnectionPoint = (IConnectionPoint)CP; + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldloc, ltCP ); + il.Emit( OpCodes.Castclass, typeof(IConnectionPoint) ); + il.Emit( OpCodes.Stfld, fbEventCP ); + + // Generate the following code: + // m_aEventSinkHelpers = new ArrayList; + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Newobj, DefaultArrayListCons ); + il.Emit( OpCodes.Stfld, fbSinkHelperArray ); + + // Generate the return opcode. + il.Emit( OpCodes.Ret ); + + return Meth; + } + + private void DefineConstructor( TypeBuilder OutputTypeBuilder, FieldBuilder fbCPC ) + { + // Retrieve the constructor info for the base class's constructor. + ConstructorInfo DefaultBaseClsCons = typeof(Object).GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null ); + Contract.Assert(DefaultBaseClsCons != null, "Unable to find the object's public default constructor"); + + // Define the default constructor. + MethodAttributes ctorAttributes = MethodAttributes.SpecialName | (DefaultBaseClsCons.Attributes & MethodAttributes.MemberAccessMask); + MethodBuilder Cons = OutputTypeBuilder.DefineMethod( + ".ctor", + ctorAttributes, + null, + new Type[]{typeof(Object)} ); + + ILGenerator il = Cons.GetILGenerator(); + + // Generate the call to the base class constructor. + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Call, DefaultBaseClsCons ); + + // Generate the following code: + // m_ConnectionPointContainer = (IConnectionPointContainer)EventSource; + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldarg, (short)1 ); + il.Emit( OpCodes.Castclass, typeof(IConnectionPointContainer) ); + il.Emit( OpCodes.Stfld, fbCPC ); + + // Generate the return opcode. + il.Emit( OpCodes.Ret ); + } + + private MethodBuilder DefineFinalizeMethod( TypeBuilder OutputTypeBuilder, Type SinkHelperClass, FieldBuilder fbSinkHelper, FieldBuilder fbEventCP ) + { + // Find the cookie on the event sink helper. + FieldInfo CookieField = SinkHelperClass.GetField( "m_dwCookie" ); + Contract.Assert(CookieField != null, "Unable to find the field m_dwCookie on the sink helper"); + + // Retrieve the ArrayList.Item property get method. + PropertyInfo ArrayListItemProperty = typeof(ArrayList).GetProperty( "Item" ); + Contract.Assert(ArrayListItemProperty != null, "Unable to find the property ArrayList.Item"); + MethodInfo ArrayListItemGetMethod = ArrayListItemProperty.GetGetMethod(); + Contract.Assert(ArrayListItemGetMethod != null, "Unable to find the get method for property ArrayList.Item"); + + // Retrieve the ArrayList.Count property get method. + PropertyInfo ArrayListSizeProperty = typeof(ArrayList).GetProperty( "Count" ); + Contract.Assert(ArrayListSizeProperty != null, "Unable to find the property ArrayList.Count"); + MethodInfo ArrayListSizeGetMethod = ArrayListSizeProperty.GetGetMethod(); + Contract.Assert(ArrayListSizeGetMethod != null, "Unable to find the get method for property ArrayList.Count"); + + // Retrieve the ConnectionPoint.Unadvise() method. + MethodInfo CPUnadviseMethod = typeof(IConnectionPoint).GetMethod( "Unadvise" ); + Contract.Assert(CPUnadviseMethod != null, "Unable to find the method ConnectionPoint.Unadvise()"); + + // Retrieve the Marshal.ReleaseComObject() method. + MethodInfo ReleaseComObjectMethod = typeof(Marshal).GetMethod( "ReleaseComObject" ); + Contract.Assert(ReleaseComObjectMethod != null, "Unable to find the method Marshal.ReleaseComObject()"); + + // Retrieve the Monitor.Enter() method. + MethodInfo MonitorEnterMethod = typeof(Monitor).GetMethod("Enter", MonitorEnterParamTypes, null); + Contract.Assert(MonitorEnterMethod != null, "Unable to find the method Monitor.Enter()"); + + // Retrieve the Monitor.Exit() method. + Type[] aParamTypes = new Type[1]; + aParamTypes[0] = typeof(Object); + MethodInfo MonitorExitMethod = typeof(Monitor).GetMethod( "Exit", aParamTypes, null ); + Contract.Assert(MonitorExitMethod != null, "Unable to find the method Monitor.Exit()"); + + // Define the Finalize method itself. + MethodBuilder Meth = OutputTypeBuilder.DefineMethod( "Finalize", MethodAttributes.Public | MethodAttributes.Virtual, null, null ); + + ILGenerator il = Meth.GetILGenerator(); + + // Declare the local variables. + LocalBuilder ltNumSinkHelpers = il.DeclareLocal( typeof(Int32) ); + LocalBuilder ltSinkHelperCounter = il.DeclareLocal( typeof(Int32) ); + LocalBuilder ltCurrSinkHelper = il.DeclareLocal( SinkHelperClass ); + LocalBuilder ltLockTaken = il.DeclareLocal(typeof(bool)); + + // Generate the following code: + // try { + il.BeginExceptionBlock(); + + // Generate the following code: + // Monitor.Enter(this, ref lockTaken); + il.Emit(OpCodes.Ldarg, (short)0); + il.Emit(OpCodes.Ldloca_S, ltLockTaken); + il.Emit(OpCodes.Call, MonitorEnterMethod); + + // Generate the labels. + Label ForBeginLabel = il.DefineLabel(); + Label ReleaseComObjectLabel = il.DefineLabel(); + Label AfterReleaseComObjectLabel = il.DefineLabel(); + + // Generate the following code: + // if ( m_IFooEventsCP == null ) goto AfterReleaseComObjectLabel; + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbEventCP ); + il.Emit( OpCodes.Brfalse, AfterReleaseComObjectLabel ); + + // Generate the following code: + // int NumEventHelpers = m_aIFooEventsHelpers.Count; + // int cEventHelpers = 0; + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbSinkHelper ); + il.Emit( OpCodes.Callvirt, ArrayListSizeGetMethod ); + il.Emit( OpCodes.Stloc, ltNumSinkHelpers ); + il.Emit( OpCodes.Ldc_I4, 0 ); + il.Emit( OpCodes.Stloc, ltSinkHelperCounter ); + + // Generate the following code: + // if ( 0 >= NumEventHelpers ) goto ReleaseComObjectLabel; + il.Emit( OpCodes.Ldc_I4, 0 ); + il.Emit( OpCodes.Ldloc, ltNumSinkHelpers ); + il.Emit( OpCodes.Bge, ReleaseComObjectLabel ); + + // Mark this as the beginning of the for loop's body. + il.MarkLabel( ForBeginLabel ); + + // Generate the following code: + // CurrentHelper = (IFooEvents_SinkHelper)m_aIFooEventsHelpers.Get( cEventHelpers ); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbSinkHelper ); + il.Emit( OpCodes.Ldloc, ltSinkHelperCounter ); + il.Emit( OpCodes.Callvirt, ArrayListItemGetMethod ); + il.Emit( OpCodes.Castclass, SinkHelperClass ); + il.Emit( OpCodes.Stloc, ltCurrSinkHelper ); + + // Generate the following code: + // m_IFooEventsCP.Unadvise( CurrentHelper.m_dwCookie ); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbEventCP ); + il.Emit( OpCodes.Ldloc, ltCurrSinkHelper ); + il.Emit( OpCodes.Ldfld, CookieField ); + il.Emit( OpCodes.Callvirt, CPUnadviseMethod ); + + // Generate the following code: + // cEventHelpers++; + il.Emit( OpCodes.Ldloc, ltSinkHelperCounter ); + il.Emit( OpCodes.Ldc_I4, 1 ); + il.Emit( OpCodes.Add ); + il.Emit( OpCodes.Stloc, ltSinkHelperCounter ); + + // Generate the following code: + // if ( cEventHelpers < NumEventHelpers ) goto ForBeginLabel; + il.Emit( OpCodes.Ldloc, ltSinkHelperCounter ); + il.Emit( OpCodes.Ldloc, ltNumSinkHelpers ); + il.Emit( OpCodes.Blt, ForBeginLabel ); + + // Mark this as the end of the for loop's body. + il.MarkLabel( ReleaseComObjectLabel ); + + // Generate the following code: + // Marshal.ReleaseComObject(m_IFooEventsCP); + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbEventCP ); + il.Emit( OpCodes.Call, ReleaseComObjectMethod ); + il.Emit( OpCodes.Pop ); + + // Mark this as the end of the for loop's body. + il.MarkLabel( AfterReleaseComObjectLabel ); + + // Generate the following code: + // } catch { + il.BeginCatchBlock(typeof(System.Exception)); + il.Emit( OpCodes.Pop ); + + // Generate the following code: + // } finally { + il.BeginFinallyBlock(); + + // Generate the following code: + // if (lockTaken) + // Monitor.Exit(this); + Label skipExit = il.DefineLabel(); + il.Emit(OpCodes.Ldloc, ltLockTaken); + il.Emit(OpCodes.Brfalse_S, skipExit); + il.Emit(OpCodes.Ldarg, (short)0); + il.Emit(OpCodes.Call, MonitorExitMethod); + il.MarkLabel(skipExit); + + // Generate the following code: + // } + il.EndExceptionBlock(); + + // Generate the return opcode. + il.Emit( OpCodes.Ret ); + + return Meth; + } + + private void DefineDisposeMethod( TypeBuilder OutputTypeBuilder, MethodBuilder FinalizeMethod ) + { + // Retrieve the method info for GC.SuppressFinalize(). + MethodInfo SuppressFinalizeMethod = typeof(GC).GetMethod("SuppressFinalize"); + Contract.Assert(SuppressFinalizeMethod != null, "Unable to find the GC.SuppressFinalize"); + + // Define the Finalize method itself. + MethodBuilder Meth = OutputTypeBuilder.DefineMethod( "Dispose", MethodAttributes.Public | MethodAttributes.Virtual, null, null ); + + ILGenerator il = Meth.GetILGenerator(); + + // Generate the following code: + // Finalize() + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Callvirt, FinalizeMethod ); + + // Generate the following code: + // GC.SuppressFinalize() + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Call, SuppressFinalizeMethod ); + + // Generate the return opcode. + il.Emit( OpCodes.Ret ); + } + + private ModuleBuilder m_OutputModule; + private String m_strDestTypeName; + private Type m_EventItfType; + private Type m_SrcItfType; + private Type m_SinkHelperType; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventSinkHelperWriter.cs b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventSinkHelperWriter.cs new file mode 100644 index 0000000000..5fde67ff89 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventSinkHelperWriter.cs @@ -0,0 +1,296 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Runtime.InteropServices.TCEAdapterGen { + using System.Runtime.InteropServices; + using System; + using System.Reflection; + using System.Reflection.Emit; + using System.Collections; + using System.Diagnostics.Contracts; + internal class EventSinkHelperWriter + { + public static readonly String GeneratedTypeNamePostfix = "_SinkHelper"; + + public EventSinkHelperWriter( ModuleBuilder OutputModule, Type InputType, Type EventItfType ) + { + m_InputType = InputType; + m_OutputModule = OutputModule; + m_EventItfType = EventItfType; + } + + public Type Perform() + { + // Create the output Type. + Type[] aInterfaces = new Type[1]; + aInterfaces[0] = m_InputType; + String strFullName = null; + String strNameSpace = NameSpaceExtractor.ExtractNameSpace( m_EventItfType.FullName ); + + if (strNameSpace != "") + strFullName = strNameSpace + "."; + + strFullName += m_InputType.Name + GeneratedTypeNamePostfix; + TypeBuilder OutputTypeBuilder = TCEAdapterGenerator.DefineUniqueType( + strFullName, + TypeAttributes.Sealed | TypeAttributes.Public, + null, + aInterfaces, + m_OutputModule + ); + // Hide the _SinkProvider interface + TCEAdapterGenerator.SetHiddenAttribute(OutputTypeBuilder); + + // Set the class interface to none. + TCEAdapterGenerator.SetClassInterfaceTypeToNone(OutputTypeBuilder); + + // Retrieve the property methods on the input interface and give them a dummy implementation. + MethodInfo[] pMethods = TCEAdapterGenerator.GetPropertyMethods(m_InputType); + foreach (MethodInfo method in pMethods) + { + DefineBlankMethod(OutputTypeBuilder, method); + } + + // Retrieve the non-property methods on the input interface. + MethodInfo[] aMethods = TCEAdapterGenerator.GetNonPropertyMethods(m_InputType); + + // Allocate an array to contain the delegate fields. + FieldBuilder[] afbDelegates = new FieldBuilder[aMethods.Length]; + // Process all the methods on the input interface. + for ( int cMethods = 0; cMethods < aMethods.Length; cMethods++ ) + { + if ( m_InputType == aMethods[cMethods].DeclaringType ) + { + // Retrieve the delegate type from the add_XXX method. + MethodInfo AddMeth = m_EventItfType.GetMethod( "add_" + aMethods[cMethods].Name ); + ParameterInfo[] aParams = AddMeth.GetParameters(); + Contract.Assert(aParams.Length == 1, "All event interface methods must take a single delegate derived type and have a void return type"); + Type DelegateCls = aParams[0].ParameterType; + + // Define the delegate instance field. + afbDelegates[cMethods] = OutputTypeBuilder.DefineField( + "m_" + aMethods[cMethods].Name + "Delegate", + DelegateCls, + FieldAttributes.Public + ); + + // Define the event method itself. + DefineEventMethod( OutputTypeBuilder, aMethods[cMethods], DelegateCls, afbDelegates[cMethods] ); + } + } + + // Create the cookie field. + FieldBuilder fbCookie = OutputTypeBuilder.DefineField( + "m_dwCookie", + typeof(Int32), + FieldAttributes.Public + ); + + // Define the constructor. + DefineConstructor( OutputTypeBuilder, fbCookie, afbDelegates ); + + return OutputTypeBuilder.CreateType(); + } + + private void DefineBlankMethod(TypeBuilder OutputTypeBuilder, MethodInfo Method) + { + ParameterInfo[] PIs = Method.GetParameters(); + Type[] parameters = new Type[PIs.Length]; + for (int i=0; i < PIs.Length; i++) + { + parameters[i] = PIs[i].ParameterType; + } + + MethodBuilder Meth = OutputTypeBuilder.DefineMethod(Method.Name, + Method.Attributes & ~MethodAttributes.Abstract, + Method.CallingConvention, + Method.ReturnType, + parameters); + + ILGenerator il = Meth.GetILGenerator(); + + AddReturn(Method.ReturnType, il, Meth); + + il.Emit(OpCodes.Ret); + } + + private void DefineEventMethod( TypeBuilder OutputTypeBuilder, MethodInfo Method, Type DelegateCls, FieldBuilder fbDelegate ) + { + // Retrieve the method info for the invoke method on the delegate. + MethodInfo DelegateInvokeMethod = DelegateCls.GetMethod( "Invoke" ); + Contract.Assert(DelegateInvokeMethod != null, "Unable to find method Delegate.Invoke()"); + + // Retrieve the return type. + Type ReturnType = Method.ReturnType; + + // Define the actual event method. + ParameterInfo[] paramInfos = Method.GetParameters(); + Type[] parameterTypes; + if (paramInfos != null) + { + parameterTypes = new Type[paramInfos.Length]; + for (int i = 0; i < paramInfos.Length; i++) + { + parameterTypes[i] = paramInfos[i].ParameterType; + } + } + else + parameterTypes = null; + + MethodAttributes attr = MethodAttributes.Public | MethodAttributes.Virtual; + MethodBuilder Meth = OutputTypeBuilder.DefineMethod( Method.Name, + attr, + CallingConventions.Standard, + ReturnType, + parameterTypes); + + // We explicitly do not specify parameter name and attributes since this Type + // is not meant to be exposed to the user. It is only used internally to do the + // connection point to TCE mapping. + + ILGenerator il = Meth.GetILGenerator(); + + // Create the exit branch. + Label ExitLabel = il.DefineLabel(); + + // Generate the code that verifies that the delegate is not null. + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbDelegate ); + il.Emit( OpCodes.Brfalse, ExitLabel ); + + // The delegate is not NULL so we need to invoke it. + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldfld, fbDelegate ); + + // Generate the code to load the arguments before we call invoke. + ParameterInfo[] aParams = Method.GetParameters(); + for ( int cParams = 0; cParams < aParams.Length; cParams++ ) + { + il.Emit( OpCodes.Ldarg, (short)(cParams + 1) ); + } + + // Generate a tail call to invoke. This will cause the callvirt to return + // directly to the caller of the current method instead of actually coming + // back to the current method and returning. This will cause the value returned + // from the call to the COM server to be returned to the caller of this method. + + il.Emit( OpCodes.Callvirt, DelegateInvokeMethod ); + il.Emit( OpCodes.Ret ); + + // This is the label that will be jumped to if no delegate is present. + il.MarkLabel( ExitLabel ); + + AddReturn(ReturnType, il, Meth); + + il.Emit( OpCodes.Ret ); + + } + + private void AddReturn(Type ReturnType, ILGenerator il, MethodBuilder Meth) + { + // Place a dummy return value on the stack before we return. + if ( ReturnType == typeof(void) ) + { + // There is nothing to place on the stack. + } + else if ( ReturnType.IsPrimitive ) + { + switch (System.Type.GetTypeCode(ReturnType)) + { + case TypeCode.Boolean: + case TypeCode.Char: + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + il.Emit( OpCodes.Ldc_I4_0 ); + break; + + case TypeCode.Int64: + case TypeCode.UInt64: + il.Emit( OpCodes.Ldc_I4_0 ); + il.Emit( OpCodes.Conv_I8 ); + break; + + case TypeCode.Single: + il.Emit( OpCodes.Ldc_R4, 0 ); + break; + + case TypeCode.Double: + il.Emit( OpCodes.Ldc_R4, 0 ); + il.Emit( OpCodes.Conv_R8 ); + break; + + default: + // "TypeCode" does not include IntPtr, so special case it. + if ( ReturnType == typeof(IntPtr) ) + il.Emit( OpCodes.Ldc_I4_0 ); + else + Contract.Assert(false, "Unexpected type for Primitive type."); + break; + } + } + else if ( ReturnType.IsValueType ) + { + // Allocate stack space for the return value type. Zero-init. + Meth.InitLocals = true; + LocalBuilder ltRetVal = il.DeclareLocal( ReturnType ); + + // Load the value class on the stack. + il.Emit( OpCodes.Ldloc_S, ltRetVal ); + + } + else + { + // The return type is a normal type. + il.Emit( OpCodes.Ldnull ); + } + } + + private void DefineConstructor( TypeBuilder OutputTypeBuilder, FieldBuilder fbCookie, FieldBuilder[] afbDelegates ) + { + // Retrieve the constructor info for the base classe's constructor. + ConstructorInfo DefaultBaseClsCons = typeof(Object).GetConstructor(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public, null, new Type[0], null ); + Contract.Assert(DefaultBaseClsCons != null, "Unable to find the constructor for class " + m_InputType.Name); + + // Define the default constructor. + MethodBuilder Cons = OutputTypeBuilder.DefineMethod( ".ctor", + MethodAttributes.Assembly | MethodAttributes.SpecialName, + CallingConventions.Standard, + null, + null); + + ILGenerator il = Cons.GetILGenerator(); + + // Generate the code to call the constructor of the base class. + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Call, DefaultBaseClsCons ); + + // Generate the code to set the cookie field to 0. + il.Emit( OpCodes.Ldarg, (short)0 ); + il.Emit( OpCodes.Ldc_I4, 0 ); + il.Emit( OpCodes.Stfld, fbCookie ); + + // Generate the code to set all the delegates to NULL. + for ( int cDelegates = 0; cDelegates < afbDelegates.Length; cDelegates++ ) + { + if (afbDelegates[cDelegates] != null) + { + il.Emit( OpCodes.Ldarg,(short)0 ); + il.Emit( OpCodes.Ldnull ); + il.Emit( OpCodes.Stfld, afbDelegates[cDelegates] ); + } + } + + // Emit the return opcode. + il.Emit( OpCodes.Ret ); + + } + + private Type m_InputType; + private Type m_EventItfType; + private ModuleBuilder m_OutputModule; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/NameSpaceExtractor.cs b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/NameSpaceExtractor.cs new file mode 100644 index 0000000000..a6e999197b --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/NameSpaceExtractor.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Runtime.InteropServices.TCEAdapterGen { + + using System; + internal static class NameSpaceExtractor + { + private static char NameSpaceSeperator = '.'; + + public static String ExtractNameSpace(String FullyQualifiedTypeName) + { + int TypeNameStartPos = FullyQualifiedTypeName.LastIndexOf(NameSpaceSeperator); + if (TypeNameStartPos == -1) + return ""; + else + return FullyQualifiedTypeName.Substring(0, TypeNameStartPos); + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/TCEAdapterGenerator.cs b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/TCEAdapterGenerator.cs new file mode 100644 index 0000000000..87dd52fd21 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/TCEAdapterGenerator.cs @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Runtime.InteropServices.TCEAdapterGen { + using System.Runtime.InteropServices; + using System; + using System.Reflection; + using System.Reflection.Emit; + using System.Collections; + using System.Threading; + + internal class TCEAdapterGenerator + { + public void Process(ModuleBuilder ModBldr, ArrayList EventItfList) + { + // Store the input/output module. + m_Module = ModBldr; + + // Generate the TCE adapters for all the event sources. + int NumEvItfs = EventItfList.Count; + for ( int cEventItfs = 0; cEventItfs < NumEvItfs; cEventItfs++ ) + { + // Retrieve the event interface info. + EventItfInfo CurrEventItf = (EventItfInfo)EventItfList[cEventItfs]; + + // Retrieve the information from the event interface info. + Type EventItfType = CurrEventItf.GetEventItfType(); + Type SrcItfType = CurrEventItf.GetSrcItfType(); + String EventProviderName = CurrEventItf.GetEventProviderName(); + + // Generate the sink interface helper. + Type SinkHelperType = new EventSinkHelperWriter( m_Module, SrcItfType, EventItfType ).Perform(); + + // Generate the event provider. + new EventProviderWriter( m_Module, EventProviderName, EventItfType, SrcItfType, SinkHelperType ).Perform(); + } + } + + internal static void SetClassInterfaceTypeToNone(TypeBuilder tb) + { + // Create the ClassInterface(ClassInterfaceType.None) CA builder if we haven't created it yet. + if (s_NoClassItfCABuilder == null) + { + Type []aConsParams = new Type[1]; + aConsParams[0] = typeof(ClassInterfaceType); + ConstructorInfo Cons = typeof(ClassInterfaceAttribute).GetConstructor(aConsParams); + + Object[] aArgs = new Object[1]; + aArgs[0] = ClassInterfaceType.None; + s_NoClassItfCABuilder = new CustomAttributeBuilder(Cons, aArgs); + } + + // Set the class interface type to none. + tb.SetCustomAttribute(s_NoClassItfCABuilder); + } + + internal static TypeBuilder DefineUniqueType(String strInitFullName, TypeAttributes attrs, Type BaseType, Type[] aInterfaceTypes, ModuleBuilder mb) + { + String strFullName = strInitFullName; + int PostFix = 2; + + // Find the first unique name for the type. + for (; mb.GetType(strFullName) != null; strFullName = strInitFullName + "_" + PostFix, PostFix++); + + // Define a type with the determined unique name. + return mb.DefineType(strFullName, attrs, BaseType, aInterfaceTypes); + } + + internal static void SetHiddenAttribute(TypeBuilder tb) + { + if (s_HiddenCABuilder == null) + { + // Hide the type from Object Browsers + Type []aConsParams = new Type[1]; + aConsParams[0] = typeof(TypeLibTypeFlags); + ConstructorInfo Cons = typeof(TypeLibTypeAttribute).GetConstructor(aConsParams); + + Object []aArgs = new Object[1]; + aArgs[0] = TypeLibTypeFlags.FHidden; + s_HiddenCABuilder = new CustomAttributeBuilder(Cons, aArgs); + } + + tb.SetCustomAttribute(s_HiddenCABuilder); + } + + internal static MethodInfo[] GetNonPropertyMethods(Type type) + { + MethodInfo[] aMethods = type.GetMethods(); + ArrayList methods = new ArrayList(aMethods); + + PropertyInfo[] props = type.GetProperties(); + + foreach(PropertyInfo prop in props) + { + MethodInfo[] accessors = prop.GetAccessors(); + foreach (MethodInfo accessor in accessors) + { + for (int i=0; i < methods.Count; i++) + { + if ((MethodInfo)methods[i] == accessor) + methods.RemoveAt(i); + } + } + } + + MethodInfo[] retMethods = new MethodInfo[methods.Count]; + methods.CopyTo(retMethods); + + return retMethods; + } + + internal static MethodInfo[] GetPropertyMethods(Type type) + { + MethodInfo[] aMethods = type.GetMethods(); + ArrayList methods = new ArrayList(); + + PropertyInfo[] props = type.GetProperties(); + + foreach(PropertyInfo prop in props) + { + MethodInfo[] accessors = prop.GetAccessors(); + foreach (MethodInfo accessor in accessors) + { + methods.Add(accessor); + } + } + + MethodInfo[] retMethods = new MethodInfo[methods.Count]; + methods.CopyTo(retMethods); + + return retMethods; + } + + + private ModuleBuilder m_Module = null; + private Hashtable m_SrcItfToSrcItfInfoMap = new Hashtable(); + private static volatile CustomAttributeBuilder s_NoClassItfCABuilder = null; + private static volatile CustomAttributeBuilder s_HiddenCABuilder = null; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/TypeLibConverter.cs b/src/mscorlib/src/System/Runtime/InteropServices/TypeLibConverter.cs new file mode 100644 index 0000000000..650af9c4e6 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/TypeLibConverter.cs @@ -0,0 +1,594 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Component that implements the ITypeLibConverter interface and +** does the actual work of converting a typelib to metadata and +** vice versa. +** +** +=============================================================================*/ +#if !FEATURE_CORECLR // current implementation requires reflection only load +namespace System.Runtime.InteropServices { + + using System; + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Runtime.InteropServices.TCEAdapterGen; + using System.IO; + using System.Reflection; + using System.Reflection.Emit; + using System.Configuration.Assemblies; + using Microsoft.Win32; + using System.Runtime.CompilerServices; + using System.Globalization; + using System.Security; + using System.Security.Permissions; + using System.Runtime.InteropServices.ComTypes; + using System.Runtime.Versioning; + using WORD = System.UInt16; + using DWORD = System.UInt32; + using _TYPELIBATTR = System.Runtime.InteropServices.ComTypes.TYPELIBATTR; + + [Guid("F1C3BF79-C3E4-11d3-88E7-00902754C43A")] + [ClassInterface(ClassInterfaceType.None)] +[System.Runtime.InteropServices.ComVisible(true)] + public sealed class TypeLibConverter : ITypeLibConverter + { + private const String s_strTypeLibAssemblyTitlePrefix = "TypeLib "; + private const String s_strTypeLibAssemblyDescPrefix = "Assembly generated from typelib "; + private const int MAX_NAMESPACE_LENGTH = 1024; + + + // + // ITypeLibConverter interface. + // + + [System.Security.SecuritySafeCritical] // auto-generated + [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] + public AssemblyBuilder ConvertTypeLibToAssembly([MarshalAs(UnmanagedType.Interface)] Object typeLib, + String asmFileName, + int flags, + ITypeLibImporterNotifySink notifySink, + byte[] publicKey, + StrongNameKeyPair keyPair, + bool unsafeInterfaces) + { + return ConvertTypeLibToAssembly(typeLib, + asmFileName, + (unsafeInterfaces + ? TypeLibImporterFlags.UnsafeInterfaces + : 0), + notifySink, + publicKey, + keyPair, + null, + null); + } + + + + + [System.Security.SecuritySafeCritical] // auto-generated + [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] + public AssemblyBuilder ConvertTypeLibToAssembly([MarshalAs(UnmanagedType.Interface)] Object typeLib, + String asmFileName, + TypeLibImporterFlags flags, + ITypeLibImporterNotifySink notifySink, + byte[] publicKey, + StrongNameKeyPair keyPair, + String asmNamespace, + Version asmVersion) + { + // Validate the arguments. + if (typeLib == null) + throw new ArgumentNullException("typeLib"); + if (asmFileName == null) + throw new ArgumentNullException("asmFileName"); + if (notifySink == null) + throw new ArgumentNullException("notifySink"); + if (String.Empty.Equals(asmFileName)) + throw new ArgumentException(Environment.GetResourceString("Arg_InvalidFileName"), "asmFileName"); + if (asmFileName.Length > Path.MAX_PATH) + throw new ArgumentException(Environment.GetResourceString("IO.PathTooLong"), asmFileName); + if ((flags & TypeLibImporterFlags.PrimaryInteropAssembly) != 0 && publicKey == null && keyPair == null) + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_PIAMustBeStrongNamed")); + Contract.EndContractBlock(); + + ArrayList eventItfInfoList = null; + + // Determine the AssemblyNameFlags + AssemblyNameFlags asmNameFlags = AssemblyNameFlags.None; + + // Retrieve the assembly name from the typelib. + AssemblyName asmName = GetAssemblyNameFromTypelib(typeLib, asmFileName, publicKey, keyPair, asmVersion, asmNameFlags); + + // Create the dynamic assembly that will contain the converted typelib types. + AssemblyBuilder asmBldr = CreateAssemblyForTypeLib(typeLib, asmFileName, asmName, + (flags & TypeLibImporterFlags.PrimaryInteropAssembly) != 0, + (flags & TypeLibImporterFlags.ReflectionOnlyLoading) != 0, + (flags & TypeLibImporterFlags.NoDefineVersionResource) != 0); + + // Define a dynamic module that will contain the contain the imported types. + String strNonQualifiedAsmFileName = Path.GetFileName(asmFileName); + ModuleBuilder modBldr = asmBldr.DefineDynamicModule(strNonQualifiedAsmFileName, strNonQualifiedAsmFileName); + + // If the namespace hasn't been specified, then use the assembly name. + if (asmNamespace == null) + asmNamespace = asmName.Name; + + // Create a type resolve handler that will also intercept resolve ref messages + // on the sink interface to build up a list of referenced assemblies. + TypeResolveHandler typeResolveHandler = new TypeResolveHandler(modBldr, notifySink); + + // Add a listener for the type resolve events. + AppDomain currentDomain = Thread.GetDomain(); + ResolveEventHandler resolveHandler = new ResolveEventHandler(typeResolveHandler.ResolveEvent); + ResolveEventHandler asmResolveHandler = new ResolveEventHandler(typeResolveHandler.ResolveAsmEvent); + ResolveEventHandler ROAsmResolveHandler = new ResolveEventHandler(typeResolveHandler.ResolveROAsmEvent); + currentDomain.TypeResolve += resolveHandler; + currentDomain.AssemblyResolve += asmResolveHandler; + currentDomain.ReflectionOnlyAssemblyResolve += ROAsmResolveHandler; + + // Convert the types contained in the typelib into metadata and add them to the assembly. + nConvertTypeLibToMetadata(typeLib, asmBldr.InternalAssembly, modBldr.InternalModule, asmNamespace, flags, typeResolveHandler, out eventItfInfoList); + + // Update the COM types in the assembly. + UpdateComTypesInAssembly(asmBldr, modBldr); + + // If there are any event sources then generate the TCE adapters. + if (eventItfInfoList.Count > 0) + new TCEAdapterGenerator().Process(modBldr, eventItfInfoList); + + // Remove the listener for the type resolve events. + currentDomain.TypeResolve -= resolveHandler; + currentDomain.AssemblyResolve -= asmResolveHandler; + currentDomain.ReflectionOnlyAssemblyResolve -= ROAsmResolveHandler; + + // We have finished converting the typelib and now have a fully formed assembly. + return asmBldr; + } + + [System.Security.SecuritySafeCritical] // auto-generated + [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] + [return : MarshalAs(UnmanagedType.Interface)] + public Object ConvertAssemblyToTypeLib(Assembly assembly, String strTypeLibName, TypeLibExporterFlags flags, ITypeLibExporterNotifySink notifySink) + { + RuntimeAssembly rtAssembly; + AssemblyBuilder ab = assembly as AssemblyBuilder; + if (ab != null) + rtAssembly = ab.InternalAssembly; + else + rtAssembly = assembly as RuntimeAssembly; + + return nConvertAssemblyToTypeLib(rtAssembly, strTypeLibName, flags, notifySink); + } + + public bool GetPrimaryInteropAssembly(Guid g, Int32 major, Int32 minor, Int32 lcid, out String asmName, out String asmCodeBase) + { + String strTlbId = "{" + g.ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; + String strVersion = major.ToString("x", CultureInfo.InvariantCulture) + "." + minor.ToString("x", CultureInfo.InvariantCulture); + + // Set the two out values to null before we start. + asmName = null; + asmCodeBase = null; + + // Try to open the HKEY_CLASS_ROOT\TypeLib key. + using (RegistryKey TypeLibKey = Registry.ClassesRoot.OpenSubKey("TypeLib", false)) + { + if (TypeLibKey != null) + { + // Try to open the HKEY_CLASS_ROOT\TypeLib\<TLBID> key. + using (RegistryKey TypeLibSubKey = TypeLibKey.OpenSubKey(strTlbId)) + { + if (TypeLibSubKey != null) + { + // Try to open the HKEY_CLASS_ROOT\TypeLib\<TLBID>\<Major.Minor> key. + using (RegistryKey VersionKey = TypeLibSubKey.OpenSubKey(strVersion, false)) + { + if (VersionKey != null) + { + // Attempt to retrieve the assembly name and codebase under the version key. + asmName = (String)VersionKey.GetValue("PrimaryInteropAssemblyName"); + asmCodeBase = (String)VersionKey.GetValue("PrimaryInteropAssemblyCodeBase"); + } + } + } + } + } + } + + // If the assembly name isn't null, then we found an PIA. + return asmName != null; + } + + + // + // Non native helper methods. + // + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable + private static AssemblyBuilder CreateAssemblyForTypeLib(Object typeLib, String asmFileName, AssemblyName asmName, bool bPrimaryInteropAssembly, bool bReflectionOnly, bool bNoDefineVersionResource) + { + // Retrieve the current app domain. + AppDomain currentDomain = Thread.GetDomain(); + + // Retrieve the directory from the assembly file name. + String dir = null; + if (asmFileName != null) + { + dir = Path.GetDirectoryName(asmFileName); + if (String.IsNullOrEmpty(dir)) + dir = null; + } + + AssemblyBuilderAccess aba; + if (bReflectionOnly) + { + aba = AssemblyBuilderAccess.ReflectionOnly; + } + else + { + aba = AssemblyBuilderAccess.RunAndSave; + } + + // Create the dynamic assembly itself. + AssemblyBuilder asmBldr; + + List<CustomAttributeBuilder> assemblyAttributes = new List<CustomAttributeBuilder>(); +#if !FEATURE_CORECLR + // mscorlib.dll must specify the security rules that assemblies it emits are to use, since by + // default all assemblies will follow security rule set level 2, and we want to make that an + // explicit decision. + ConstructorInfo securityRulesCtor = typeof(SecurityRulesAttribute).GetConstructor(new Type[] { typeof(SecurityRuleSet) }); + CustomAttributeBuilder securityRulesAttribute = + new CustomAttributeBuilder(securityRulesCtor, new object[] { SecurityRuleSet.Level2 }); + assemblyAttributes.Add(securityRulesAttribute); +#endif // !FEATURE_CORECLR + + asmBldr = currentDomain.DefineDynamicAssembly(asmName, aba, dir, false, assemblyAttributes); + + // Set the Guid custom attribute on the assembly. + SetGuidAttributeOnAssembly(asmBldr, typeLib); + + // Set the imported from COM attribute on the assembly and return it. + SetImportedFromTypeLibAttrOnAssembly(asmBldr, typeLib); + + // Set the version information on the typelib. + if (bNoDefineVersionResource) + { + SetTypeLibVersionAttribute(asmBldr, typeLib); + } + else + { + SetVersionInformation(asmBldr, typeLib, asmName); + } + + // If we are generating a PIA, then set the PIA custom attribute. + if (bPrimaryInteropAssembly) + SetPIAAttributeOnAssembly(asmBldr, typeLib); + + return asmBldr; + } + + [System.Security.SecurityCritical] // auto-generated + internal static AssemblyName GetAssemblyNameFromTypelib(Object typeLib, String asmFileName, byte[] publicKey, StrongNameKeyPair keyPair, Version asmVersion, AssemblyNameFlags asmNameFlags) + { + // Extract the name of the typelib. + String strTypeLibName = null; + String strDocString = null; + int dwHelpContext = 0; + String strHelpFile = null; + ITypeLib pTLB = (ITypeLib)typeLib; + pTLB.GetDocumentation(-1, out strTypeLibName, out strDocString, out dwHelpContext, out strHelpFile); + + // Retrieve the name to use for the assembly. + if (asmFileName == null) + { + asmFileName = strTypeLibName; + } + else + { + Contract.Assert((asmFileName != null) && (asmFileName.Length > 0), "The assembly file name cannot be an empty string!"); + + String strFileNameNoPath = Path.GetFileName(asmFileName); + String strExtension = Path.GetExtension(asmFileName); + + // Validate that the extension is valid. + bool bExtensionValid = ".dll".Equals(strExtension, StringComparison.OrdinalIgnoreCase); + + // If the extension is not valid then tell the user and quit. + if (!bExtensionValid) + throw new ArgumentException(Environment.GetResourceString("Arg_InvalidFileExtension")); + + // The assembly cannot contain the path nor the extension. + asmFileName = strFileNameNoPath.Substring(0, strFileNameNoPath.Length - ".dll".Length); + } + + // If the version information was not specified, then retrieve it from the typelib. + if (asmVersion == null) + { + int major; + int minor; + Marshal.GetTypeLibVersion(pTLB, out major, out minor); + asmVersion = new Version(major, minor, 0, 0); + } + + // Create the assembly name for the imported typelib's assembly. + AssemblyName AsmName = new AssemblyName(); + AsmName.Init( + asmFileName, + publicKey, + null, + asmVersion, + null, + AssemblyHashAlgorithm.None, + AssemblyVersionCompatibility.SameMachine, + null, + asmNameFlags, + keyPair); + + return AsmName; + } + + private static void UpdateComTypesInAssembly(AssemblyBuilder asmBldr, ModuleBuilder modBldr) + { + // Retrieve the AssemblyBuilderData associated with the assembly builder. + AssemblyBuilderData AsmBldrData = asmBldr.m_assemblyData; + + // Go through the types in the module and add them as public COM types. + Type[] aTypes = modBldr.GetTypes(); + int NumTypes = aTypes.Length; + for (int cTypes = 0; cTypes < NumTypes; cTypes++) + AsmBldrData.AddPublicComType(aTypes[cTypes]); + } + + + [System.Security.SecurityCritical] // auto-generated + private static void SetGuidAttributeOnAssembly(AssemblyBuilder asmBldr, Object typeLib) + { + // Retrieve the GuidAttribute constructor. + Type []aConsParams = new Type[1] {typeof(String)}; + ConstructorInfo GuidAttrCons = typeof(GuidAttribute).GetConstructor(aConsParams); + + // Create an instance of the custom attribute builder. + Object[] aArgs = new Object[1] {Marshal.GetTypeLibGuid((ITypeLib)typeLib).ToString()}; + CustomAttributeBuilder GuidCABuilder = new CustomAttributeBuilder(GuidAttrCons, aArgs); + + // Set the GuidAttribute on the assembly builder. + asmBldr.SetCustomAttribute(GuidCABuilder); + } + + [System.Security.SecurityCritical] // auto-generated + private static void SetImportedFromTypeLibAttrOnAssembly(AssemblyBuilder asmBldr, Object typeLib) + { + // Retrieve the ImportedFromTypeLibAttribute constructor. + Type []aConsParams = new Type[1] {typeof(String)}; + ConstructorInfo ImpFromComAttrCons = typeof(ImportedFromTypeLibAttribute).GetConstructor(aConsParams); + + // Retrieve the name of the typelib. + String strTypeLibName = Marshal.GetTypeLibName((ITypeLib)typeLib); + + // Create an instance of the custom attribute builder. + Object[] aArgs = new Object[1] {strTypeLibName}; + CustomAttributeBuilder ImpFromComCABuilder = new CustomAttributeBuilder(ImpFromComAttrCons, aArgs); + + // Set the ImportedFromTypeLibAttribute on the assembly builder. + asmBldr.SetCustomAttribute(ImpFromComCABuilder); + } + + [System.Security.SecurityCritical] // auto-generated + private static void SetTypeLibVersionAttribute(AssemblyBuilder asmBldr, Object typeLib) + { + Type []aConsParams = new Type[2] {typeof(int), typeof(int)}; + ConstructorInfo TypeLibVerCons = typeof(TypeLibVersionAttribute).GetConstructor(aConsParams); + + // Get the typelib version + int major; + int minor; + Marshal.GetTypeLibVersion((ITypeLib)typeLib, out major, out minor); + + // Create an instance of the custom attribute builder. + Object[] aArgs = new Object[2] {major, minor}; + CustomAttributeBuilder TypeLibVerBuilder = new CustomAttributeBuilder(TypeLibVerCons, aArgs); + + // Set the attribute on the assembly builder. + asmBldr.SetCustomAttribute(TypeLibVerBuilder); + } + + [System.Security.SecurityCritical] // auto-generated + private static void SetVersionInformation(AssemblyBuilder asmBldr, Object typeLib, AssemblyName asmName) + { + // Extract the name of the typelib. + String strTypeLibName = null; + String strDocString = null; + int dwHelpContext = 0; + String strHelpFile = null; + ITypeLib pTLB = (ITypeLib)typeLib; + pTLB.GetDocumentation(-1, out strTypeLibName, out strDocString, out dwHelpContext, out strHelpFile); + + // Generate the product name string from the named of the typelib. + String strProductName = String.Format(CultureInfo.InvariantCulture, Environment.GetResourceString("TypeLibConverter_ImportedTypeLibProductName"), strTypeLibName); + + // Set the OS version information. + asmBldr.DefineVersionInfoResource(strProductName, asmName.Version.ToString(), null, null, null); + + // Set the TypeLibVersion attribute + SetTypeLibVersionAttribute(asmBldr, typeLib); + } + + [System.Security.SecurityCritical] // auto-generated + private static void SetPIAAttributeOnAssembly(AssemblyBuilder asmBldr, Object typeLib) + { + IntPtr pAttr = IntPtr.Zero; + _TYPELIBATTR Attr; + ITypeLib pTLB = (ITypeLib)typeLib; + int Major = 0; + int Minor = 0; + + // Retrieve the PrimaryInteropAssemblyAttribute constructor. + Type []aConsParams = new Type[2] {typeof(int), typeof(int)}; + ConstructorInfo PIAAttrCons = typeof(PrimaryInteropAssemblyAttribute).GetConstructor(aConsParams); + + // Retrieve the major and minor version from the typelib. + try + { + pTLB.GetLibAttr(out pAttr); + Attr = (_TYPELIBATTR)Marshal.PtrToStructure(pAttr, typeof(_TYPELIBATTR)); + Major = Attr.wMajorVerNum; + Minor = Attr.wMinorVerNum; + } + finally + { + // Release the typelib attributes. + if (pAttr != IntPtr.Zero) + pTLB.ReleaseTLibAttr(pAttr); + } + + // Create an instance of the custom attribute builder. + Object[] aArgs = new Object[2] {Major, Minor}; + CustomAttributeBuilder PIACABuilder = new CustomAttributeBuilder(PIAAttrCons, aArgs); + + // Set the PrimaryInteropAssemblyAttribute on the assembly builder. + asmBldr.SetCustomAttribute(PIACABuilder); + } + + + // + // Native helper methods. + // + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void nConvertTypeLibToMetadata(Object typeLib, RuntimeAssembly asmBldr, RuntimeModule modBldr, String nameSpace, TypeLibImporterFlags flags, ITypeLibImporterNotifySink notifySink, out ArrayList eventItfInfoList); + + // Must use assembly versioning or GuidAttribute to avoid collisions in typelib export or registration. + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern Object nConvertAssemblyToTypeLib(RuntimeAssembly assembly, String strTypeLibName, TypeLibExporterFlags flags, ITypeLibExporterNotifySink notifySink); + + [System.Security.SecurityCritical] // auto-generated + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] + internal extern static void LoadInMemoryTypeByName(RuntimeModule module, String className); + + // + // Helper class called when a resolve type event is fired. + // + + private class TypeResolveHandler : ITypeLibImporterNotifySink + { + public TypeResolveHandler(ModuleBuilder mod, ITypeLibImporterNotifySink userSink) + { + m_Module = mod; + m_UserSink = userSink; + } + + public void ReportEvent(ImporterEventKind eventKind, int eventCode, String eventMsg) + { + m_UserSink.ReportEvent(eventKind, eventCode, eventMsg); + } + + public Assembly ResolveRef(Object typeLib) + { + Contract.Ensures(Contract.Result<Assembly>() != null && Contract.Result<Assembly>() is RuntimeAssembly); + Contract.EndContractBlock(); + + // Call the user sink to resolve the reference. + Assembly asm = m_UserSink.ResolveRef(typeLib); + + if (asm == null) + throw new ArgumentNullException(); + + // Return the resolved assembly. We extract the internal assembly because we are called + // by the VM which accesses fields of the object directly and does not go via those + // delegating properties (the fields are empty if asm is an (external) AssemblyBuilder). + + RuntimeAssembly rtAssembly = asm as RuntimeAssembly; + if (rtAssembly == null) + { + AssemblyBuilder ab = asm as AssemblyBuilder; + if (ab != null) + rtAssembly = ab.InternalAssembly; + } + + if (rtAssembly == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly")); + + // Add the assembly to the list of assemblies. + m_AsmList.Add(rtAssembly); + + return rtAssembly; + } + + [System.Security.SecurityCritical] // auto-generated + public Assembly ResolveEvent(Object sender, ResolveEventArgs args) + { + // We need to load the type in the resolve event so that we will deal with + // cases where we are trying to load the CoClass before the interface has + // been loaded. + try + { + LoadInMemoryTypeByName(m_Module.GetNativeHandle(), args.Name); + return m_Module.Assembly; + } + catch (TypeLoadException e) + { + if (e.ResourceId != System.__HResults.COR_E_TYPELOAD) // type not found + throw; + } + + foreach (RuntimeAssembly asm in m_AsmList) + { + try + { + asm.GetType(args.Name, true, false); + return asm; + } + catch (TypeLoadException e) + { + if (e._HResult != System.__HResults.COR_E_TYPELOAD) // type not found + throw; + } + } + + return null; + } + + public Assembly ResolveAsmEvent(Object sender, ResolveEventArgs args) + { + foreach (RuntimeAssembly asm in m_AsmList) + { + if (String.Compare(asm.FullName, args.Name, StringComparison.OrdinalIgnoreCase) == 0) + return asm; + } + + return null; + } + + public Assembly ResolveROAsmEvent(Object sender, ResolveEventArgs args) + { + foreach (RuntimeAssembly asm in m_AsmList) + { + if (String.Compare(asm.FullName, args.Name, StringComparison.OrdinalIgnoreCase) == 0) + return asm; + } + + // We failed to find the referenced assembly in our pre-loaded assemblies, so try to load it based on policy. + string asmName = AppDomain.CurrentDomain.ApplyPolicy(args.Name); + return Assembly.ReflectionOnlyLoad(asmName); + } + + private ModuleBuilder m_Module; + private ITypeLibImporterNotifySink m_UserSink; + private List<RuntimeAssembly> m_AsmList = new List<RuntimeAssembly>(); + } + } +} +#endif // !FEATURE_CORECLR // current implementation requires reflection only load + diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIBindCtx.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIBindCtx.cs new file mode 100644 index 0000000000..c1b44e14f0 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIBindCtx.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIBindCtx interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.BIND_OPTS instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential)] + + public struct BIND_OPTS + { + public int cbStruct; + public int grfFlags; + public int grfMode; + public int dwTickCountDeadline; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IBindCtx instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("0000000e-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIBindCtx + { + void RegisterObjectBound([MarshalAs(UnmanagedType.Interface)] Object punk); + void RevokeObjectBound([MarshalAs(UnmanagedType.Interface)] Object punk); + void ReleaseBoundObjects(); + void SetBindOptions([In()] ref BIND_OPTS pbindopts); + void GetBindOptions(ref BIND_OPTS pbindopts); + void GetRunningObjectTable(out UCOMIRunningObjectTable pprot); + void RegisterObjectParam([MarshalAs(UnmanagedType.LPWStr)] String pszKey, [MarshalAs(UnmanagedType.Interface)] Object punk); + void GetObjectParam([MarshalAs(UnmanagedType.LPWStr)] String pszKey, [MarshalAs(UnmanagedType.Interface)] out Object ppunk); + void EnumObjectParam(out UCOMIEnumString ppenum); + void RevokeObjectParam([MarshalAs(UnmanagedType.LPWStr)] String pszKey); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIConnectionPoint.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIConnectionPoint.cs new file mode 100644 index 0000000000..4fde2a47dd --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIConnectionPoint.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIConnectionPoint interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IConnectionPoint instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("B196B286-BAB4-101A-B69C-00AA00341D07")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIConnectionPoint + { + void GetConnectionInterface(out Guid pIID); + void GetConnectionPointContainer(out UCOMIConnectionPointContainer ppCPC); + void Advise([MarshalAs(UnmanagedType.Interface)] Object pUnkSink, out int pdwCookie); + void Unadvise(int dwCookie); + void EnumConnections(out UCOMIEnumConnections ppEnum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIConnectionPointContainer.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIConnectionPointContainer.cs new file mode 100644 index 0000000000..c70f253bd9 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIConnectionPointContainer.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIConnectionPointContainer interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IConnectionPointContainer instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("B196B284-BAB4-101A-B69C-00AA00341D07")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIConnectionPointContainer + { + void EnumConnectionPoints(out UCOMIEnumConnectionPoints ppEnum); + void FindConnectionPoint(ref Guid riid, out UCOMIConnectionPoint ppCP); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumConnectionPoints.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumConnectionPoints.cs new file mode 100644 index 0000000000..3ffeb25ed0 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumConnectionPoints.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIEnumConnectionPoints interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IEnumConnectionPoints instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("B196B285-BAB4-101A-B69C-00AA00341D07")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIEnumConnectionPoints + { + [PreserveSig] + int Next(int celt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Out] UCOMIConnectionPoint[] rgelt, out int pceltFetched); + [PreserveSig] + int Skip(int celt); + [PreserveSig] + int Reset(); + void Clone(out UCOMIEnumConnectionPoints ppenum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumConnections.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumConnections.cs new file mode 100644 index 0000000000..1a7a6e52e9 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumConnections.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIEnumConnections interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.CONNECTDATA instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct CONNECTDATA + { + [MarshalAs(UnmanagedType.Interface)] + public Object pUnk; + public int dwCookie; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IEnumConnections instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("B196B287-BAB4-101A-B69C-00AA00341D07")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIEnumConnections + { + [PreserveSig] + int Next(int celt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Out] CONNECTDATA[] rgelt, out int pceltFetched); + [PreserveSig] + int Skip(int celt); + [PreserveSig] + void Reset(); + void Clone(out UCOMIEnumConnections ppenum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumMoniker.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumMoniker.cs new file mode 100644 index 0000000000..9a90dea638 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumMoniker.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIEnumMoniker interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + using DWORD = System.UInt32; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IEnumMoniker instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("00000102-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIEnumMoniker + { + [PreserveSig] + int Next(int celt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Out] UCOMIMoniker[] rgelt, out int pceltFetched); + [PreserveSig] + int Skip(int celt); + [PreserveSig] + int Reset(); + void Clone(out UCOMIEnumMoniker ppenum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumString.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumString.cs new file mode 100644 index 0000000000..93fbcec53c --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumString.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIEnumString interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IEnumString instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("00000101-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIEnumString + { + [PreserveSig] + int Next(int celt, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 0), Out] String[] rgelt, out int pceltFetched); + [PreserveSig] + int Skip(int celt); + [PreserveSig] + int Reset(); + void Clone(out UCOMIEnumString ppenum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumVARIANT.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumVARIANT.cs new file mode 100644 index 0000000000..c74c0b3568 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumVARIANT.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIEnumVARIANT interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IEnumVARIANT instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("00020404-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIEnumVARIANT + { + [PreserveSig] + int Next(int celt, int rgvar, int pceltFetched); + + [PreserveSig] + int Skip(int celt); + + [PreserveSig] + int Reset(); + + void Clone(int ppenum); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumerable.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumerable.cs new file mode 100644 index 0000000000..3fcd279070 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumerable.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*========================================================================== +** +** Interface: UCOMIEnumerable +** +** +** Purpose: +** This interface is redefined here since the original IEnumerable interface +** has all its methods marked as ecall's since it is a managed standard +** interface. This interface is used from within the runtime to make a call +** on the COM server directly when it implements the IEnumerable interface. +** +** +==========================================================================*/ +namespace System.Runtime.InteropServices +{ + using System; + using System.Collections; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IEnumerable instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")] + internal interface UCOMIEnumerable + { + [DispId(-4)] + IEnumerator GetEnumerator(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumerator.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumerator.cs new file mode 100644 index 0000000000..4e9eb5ce2f --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIEnumerator.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*========================================================================== +** +** Interface: UCOMIEnumerator +** +** +** Purpose: +** This interface is redefined here since the original IEnumerator interface +** has all its methods marked as ecall's since it is a managed standard +** interface. This interface is used from within the runtime to make a call +** on the COM server directly when it implements the IEnumerator interface. +** +** +==========================================================================*/ +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IEnumerator instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")] + internal interface UCOMIEnumerator + { + bool MoveNext(); + Object Current { + get; + } + void Reset(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIExpando.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIExpando.cs new file mode 100644 index 0000000000..60774b8ac4 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIExpando.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*========================================================================== +** +** Interface: UCOMIExpando +** +** +** Purpose: +** This interface is redefined here since the original IExpando interface +** has all its methods marked as ecall's since it is a managed standard +** interface. This interface is used from within the runtime to make a call +** on the COM server directly when it implements the IExpando interface. +** +** +==========================================================================*/ +namespace System.Runtime.InteropServices +{ + + using System; + using System.Reflection; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IExpando instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("AFBF15E6-C37C-11d2-B88E-00A0C9B471B8")] + internal interface UCOMIExpando : UCOMIReflect + { + FieldInfo AddField(String name); + PropertyInfo AddProperty(String name); + MethodInfo AddMethod(String name, Delegate method); + void RemoveMember(MemberInfo m); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIMoniker.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIMoniker.cs new file mode 100644 index 0000000000..8e0108d98e --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIMoniker.cs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIMoniker interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.FILETIME instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential)] + + public struct FILETIME + { + public int dwLowDateTime; + public int dwHighDateTime; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IMoniker instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("0000000f-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIMoniker + { + // IPersist portion + void GetClassID(out Guid pClassID); + + // IPersistStream portion + [PreserveSig] + int IsDirty(); + void Load(UCOMIStream pStm); + void Save(UCOMIStream pStm, [MarshalAs(UnmanagedType.Bool)] bool fClearDirty); + void GetSizeMax(out Int64 pcbSize); + + // IMoniker portion + void BindToObject(UCOMIBindCtx pbc, UCOMIMoniker pmkToLeft, [In()] ref Guid riidResult, [MarshalAs(UnmanagedType.Interface)] out Object ppvResult); + void BindToStorage(UCOMIBindCtx pbc, UCOMIMoniker pmkToLeft, [In()] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out Object ppvObj); + void Reduce(UCOMIBindCtx pbc, int dwReduceHowFar, ref UCOMIMoniker ppmkToLeft, out UCOMIMoniker ppmkReduced); + void ComposeWith(UCOMIMoniker pmkRight, [MarshalAs(UnmanagedType.Bool)] bool fOnlyIfNotGeneric, out UCOMIMoniker ppmkComposite); + void Enum([MarshalAs(UnmanagedType.Bool)] bool fForward, out UCOMIEnumMoniker ppenumMoniker); + void IsEqual(UCOMIMoniker pmkOtherMoniker); + void Hash(out int pdwHash); + void IsRunning(UCOMIBindCtx pbc, UCOMIMoniker pmkToLeft, UCOMIMoniker pmkNewlyRunning); + void GetTimeOfLastChange(UCOMIBindCtx pbc, UCOMIMoniker pmkToLeft, out FILETIME pFileTime); + void Inverse(out UCOMIMoniker ppmk); + void CommonPrefixWith(UCOMIMoniker pmkOther, out UCOMIMoniker ppmkPrefix); + void RelativePathTo(UCOMIMoniker pmkOther, out UCOMIMoniker ppmkRelPath); + void GetDisplayName(UCOMIBindCtx pbc, UCOMIMoniker pmkToLeft, [MarshalAs(UnmanagedType.LPWStr)] out String ppszDisplayName); + void ParseDisplayName(UCOMIBindCtx pbc, UCOMIMoniker pmkToLeft, [MarshalAs(UnmanagedType.LPWStr)] String pszDisplayName, out int pchEaten, out UCOMIMoniker ppmkOut); + void IsSystemMoniker(out int pdwMksys); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIPersistFile.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIPersistFile.cs new file mode 100644 index 0000000000..5ba4851f37 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIPersistFile.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIPersistFile interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + using DWORD = System.UInt32; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IPersistFile instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("0000010b-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIPersistFile + { + // IPersist portion + void GetClassID(out Guid pClassID); + + // IPersistFile portion + [PreserveSig] + int IsDirty(); + void Load([MarshalAs(UnmanagedType.LPWStr)] String pszFileName, int dwMode); + void Save([MarshalAs(UnmanagedType.LPWStr)] String pszFileName, [MarshalAs(UnmanagedType.Bool)] bool fRemember); + void SaveCompleted([MarshalAs(UnmanagedType.LPWStr)] String pszFileName); + void GetCurFile([MarshalAs(UnmanagedType.LPWStr)] out String ppszFileName); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIReflect.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIReflect.cs new file mode 100644 index 0000000000..476c671e85 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIReflect.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*========================================================================== +** +** Interface: UCOMIReflect +** +** +** Purpose: +** This interface is redefined here since the original IReflect interface +** has all its methods marked as ecall's since it is a managed standard +** interface. This interface is used from within the runtime to make a call +** on the COM server directly when it implements the IReflect interface. +** +** +==========================================================================*/ +namespace System.Runtime.InteropServices +{ + using System; + using System.Reflection; + using CultureInfo = System.Globalization.CultureInfo; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IReflect instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("AFBF15E5-C37C-11d2-B88E-00A0C9B471B8")] + internal interface UCOMIReflect + { + MethodInfo GetMethod(String name,BindingFlags bindingAttr,Binder binder, + Type[] types,ParameterModifier[] modifiers); + + MethodInfo GetMethod(String name,BindingFlags bindingAttr); + + MethodInfo[] GetMethods( + BindingFlags bindingAttr); + + FieldInfo GetField( + String name, + BindingFlags bindingAttr); + + FieldInfo[] GetFields( + BindingFlags bindingAttr); + + PropertyInfo GetProperty( + String name, + BindingFlags bindingAttr); + + PropertyInfo GetProperty( + String name, + BindingFlags bindingAttr, + Binder binder, + Type returnType, + Type[] types, + ParameterModifier[] modifiers); + + PropertyInfo[] GetProperties( + BindingFlags bindingAttr); + + MemberInfo[] GetMember( + String name, + BindingFlags bindingAttr); + + MemberInfo[] GetMembers( + BindingFlags bindingAttr); + + Object InvokeMember( + String name, + BindingFlags invokeAttr, + Binder binder, + Object target, + Object[] args, + ParameterModifier[] modifiers, + CultureInfo culture, + String[] namedParameters); + + Type UnderlyingSystemType { + get; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIRunningObjectTable.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIRunningObjectTable.cs new file mode 100644 index 0000000000..e5e40a11a7 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIRunningObjectTable.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIRunningObjectTable interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IRunningObjectTable instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("00000010-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIRunningObjectTable + { + void Register(int grfFlags, [MarshalAs(UnmanagedType.Interface)] Object punkObject, UCOMIMoniker pmkObjectName, out int pdwRegister); + void Revoke(int dwRegister); + void IsRunning(UCOMIMoniker pmkObjectName); + void GetObject(UCOMIMoniker pmkObjectName, [MarshalAs(UnmanagedType.Interface)] out Object ppunkObject); + void NoteChangeTime(int dwRegister, ref FILETIME pfiletime); + void GetTimeOfLastChange(UCOMIMoniker pmkObjectName, out FILETIME pfiletime); + void EnumRunning(out UCOMIEnumMoniker ppenumMoniker); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMIStream.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIStream.cs new file mode 100644 index 0000000000..aed024f579 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMIStream.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMIStream interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.STATSTG instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + + public struct STATSTG + { + public String pwcsName; + public int type; + public Int64 cbSize; + public FILETIME mtime; + public FILETIME ctime; + public FILETIME atime; + public int grfMode; + public int grfLocksSupported; + public Guid clsid; + public int grfStateBits; + public int reserved; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IStream instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("0000000c-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMIStream + { + // ISequentialStream portion + void Read([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] Byte[] pv, int cb,IntPtr pcbRead); + void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] Byte[] pv, int cb, IntPtr pcbWritten); + + // IStream portion + void Seek(Int64 dlibMove, int dwOrigin, IntPtr plibNewPosition); + void SetSize(Int64 libNewSize); + void CopyTo(UCOMIStream pstm, Int64 cb, IntPtr pcbRead, IntPtr pcbWritten); + void Commit(int grfCommitFlags); + void Revert(); + void LockRegion(Int64 libOffset, Int64 cb, int dwLockType); + void UnlockRegion(Int64 libOffset, Int64 cb, int dwLockType); + void Stat(out STATSTG pstatstg, int grfStatFlag); + void Clone(out UCOMIStream ppstm); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMITypeComp.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMITypeComp.cs new file mode 100644 index 0000000000..7d6c89937f --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMITypeComp.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMITypeComp interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.DESCKIND instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Serializable] + public enum DESCKIND + { + DESCKIND_NONE = 0, + DESCKIND_FUNCDESC = DESCKIND_NONE + 1, + DESCKIND_VARDESC = DESCKIND_FUNCDESC + 1, + DESCKIND_TYPECOMP = DESCKIND_VARDESC + 1, + DESCKIND_IMPLICITAPPOBJ = DESCKIND_TYPECOMP + 1, + DESCKIND_MAX = DESCKIND_IMPLICITAPPOBJ + 1 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.BINDPTR instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)] + + public struct BINDPTR + { + [FieldOffset(0)] + public IntPtr lpfuncdesc; + [FieldOffset(0)] + public IntPtr lpvardesc; + [FieldOffset(0)] + public IntPtr lptcomp; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.ITypeComp instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("00020403-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMITypeComp + { + void Bind([MarshalAs(UnmanagedType.LPWStr)] String szName, int lHashVal, Int16 wFlags, out UCOMITypeInfo ppTInfo, out DESCKIND pDescKind, out BINDPTR pBindPtr); + void BindType([MarshalAs(UnmanagedType.LPWStr)] String szName, int lHashVal, out UCOMITypeInfo ppTInfo, out UCOMITypeComp ppTComp); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMITypeInfo.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMITypeInfo.cs new file mode 100644 index 0000000000..2978bf9ac8 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMITypeInfo.cs @@ -0,0 +1,329 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMITypeInfo interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.TYPEKIND instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Serializable] + public enum TYPEKIND + { + TKIND_ENUM = 0, + TKIND_RECORD = TKIND_ENUM + 1, + TKIND_MODULE = TKIND_RECORD + 1, + TKIND_INTERFACE = TKIND_MODULE + 1, + TKIND_DISPATCH = TKIND_INTERFACE + 1, + TKIND_COCLASS = TKIND_DISPATCH + 1, + TKIND_ALIAS = TKIND_COCLASS + 1, + TKIND_UNION = TKIND_ALIAS + 1, + TKIND_MAX = TKIND_UNION + 1 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.TYPEFLAGS instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] +[Serializable] +[Flags()] + public enum TYPEFLAGS : short + { + TYPEFLAG_FAPPOBJECT = 0x1, + TYPEFLAG_FCANCREATE = 0x2, + TYPEFLAG_FLICENSED = 0x4, + TYPEFLAG_FPREDECLID = 0x8, + TYPEFLAG_FHIDDEN = 0x10, + TYPEFLAG_FCONTROL = 0x20, + TYPEFLAG_FDUAL = 0x40, + TYPEFLAG_FNONEXTENSIBLE = 0x80, + TYPEFLAG_FOLEAUTOMATION = 0x100, + TYPEFLAG_FRESTRICTED = 0x200, + TYPEFLAG_FAGGREGATABLE = 0x400, + TYPEFLAG_FREPLACEABLE = 0x800, + TYPEFLAG_FDISPATCHABLE = 0x1000, + TYPEFLAG_FREVERSEBIND = 0x2000, + TYPEFLAG_FPROXY = 0x4000 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IMPLTYPEFLAGS instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] +[Serializable] +[Flags()] + public enum IMPLTYPEFLAGS + { + IMPLTYPEFLAG_FDEFAULT = 0x1, + IMPLTYPEFLAG_FSOURCE = 0x2, + IMPLTYPEFLAG_FRESTRICTED = 0x4, + IMPLTYPEFLAG_FDEFAULTVTABLE = 0x8, + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.TYPEATTR instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + public struct TYPEATTR + { + // Constant used with the memid fields. + public const int MEMBER_ID_NIL = unchecked((int)0xFFFFFFFF); + + // Actual fields of the TypeAttr struct. + public Guid guid; + public Int32 lcid; + public Int32 dwReserved; + public Int32 memidConstructor; + public Int32 memidDestructor; + public IntPtr lpstrSchema; + public Int32 cbSizeInstance; + public TYPEKIND typekind; + public Int16 cFuncs; + public Int16 cVars; + public Int16 cImplTypes; + public Int16 cbSizeVft; + public Int16 cbAlignment; + public TYPEFLAGS wTypeFlags; + public Int16 wMajorVerNum; + public Int16 wMinorVerNum; + public TYPEDESC tdescAlias; + public IDLDESC idldescType; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.FUNCDESC instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential)] + public struct FUNCDESC + { + public int memid; //MEMBERID memid; + public IntPtr lprgscode; // /* [size_is(cScodes)] */ SCODE RPC_FAR *lprgscode; + public IntPtr lprgelemdescParam; // /* [size_is(cParams)] */ ELEMDESC __RPC_FAR *lprgelemdescParam; + public FUNCKIND funckind; //FUNCKIND funckind; + public INVOKEKIND invkind; //INVOKEKIND invkind; + public CALLCONV callconv; //CALLCONV callconv; + public Int16 cParams; //short cParams; + public Int16 cParamsOpt; //short cParamsOpt; + public Int16 oVft; //short oVft; + public Int16 cScodes; //short cScodes; + public ELEMDESC elemdescFunc; //ELEMDESC elemdescFunc; + public Int16 wFuncFlags; //WORD wFuncFlags; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IDLFLAG instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] +[Serializable] +[Flags()] + public enum IDLFLAG : short + { + IDLFLAG_NONE = PARAMFLAG.PARAMFLAG_NONE, + IDLFLAG_FIN = PARAMFLAG.PARAMFLAG_FIN, + IDLFLAG_FOUT = PARAMFLAG.PARAMFLAG_FOUT, + IDLFLAG_FLCID = PARAMFLAG.PARAMFLAG_FLCID, + IDLFLAG_FRETVAL = PARAMFLAG.PARAMFLAG_FRETVAL + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.IDLDESC instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + public struct IDLDESC + { + public int dwReserved; + public IDLFLAG wIDLFlags; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.PARAMFLAG instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] +[Serializable] +[Flags()] + public enum PARAMFLAG :short + { + PARAMFLAG_NONE = 0, + PARAMFLAG_FIN = 0x1, + PARAMFLAG_FOUT = 0x2, + PARAMFLAG_FLCID = 0x4, + PARAMFLAG_FRETVAL = 0x8, + PARAMFLAG_FOPT = 0x10, + PARAMFLAG_FHASDEFAULT = 0x20, + PARAMFLAG_FHASCUSTDATA = 0x40 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.PARAMDESC instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + public struct PARAMDESC + { + public IntPtr lpVarValue; + public PARAMFLAG wParamFlags; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.TYPEDESC instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + public struct TYPEDESC + { + public IntPtr lpValue; + public Int16 vt; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.ELEMDESC instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + public struct ELEMDESC + { + public TYPEDESC tdesc; + + [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)] + [ComVisible(false)] + public struct DESCUNION + { + [FieldOffset(0)] + public IDLDESC idldesc; + [FieldOffset(0)] + public PARAMDESC paramdesc; + }; + public DESCUNION desc; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.VARDESC instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + public struct VARDESC + { + public int memid; + public String lpstrSchema; + + [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)] + [ComVisible(false)] + public struct DESCUNION + { + [FieldOffset(0)] + public int oInst; + [FieldOffset(0)] + public IntPtr lpvarValue; + }; + + public ELEMDESC elemdescVar; + public short wVarFlags; + public VarEnum varkind; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.DISPPARAMS instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + public struct DISPPARAMS + { + public IntPtr rgvarg; + public IntPtr rgdispidNamedArgs; + public int cArgs; + public int cNamedArgs; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.EXCEPINFO instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + public struct EXCEPINFO + { + public Int16 wCode; + public Int16 wReserved; + [MarshalAs(UnmanagedType.BStr)] public String bstrSource; + [MarshalAs(UnmanagedType.BStr)] public String bstrDescription; + [MarshalAs(UnmanagedType.BStr)] public String bstrHelpFile; + public int dwHelpContext; + public IntPtr pvReserved; + public IntPtr pfnDeferredFillIn; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.FUNCKIND instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Serializable] + public enum FUNCKIND : int + { + FUNC_VIRTUAL = 0, + FUNC_PUREVIRTUAL = 1, + FUNC_NONVIRTUAL = 2, + FUNC_STATIC = 3, + FUNC_DISPATCH = 4 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.INVOKEKIND instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Serializable] + public enum INVOKEKIND : int + { + INVOKE_FUNC = 0x1, + INVOKE_PROPERTYGET = 0x2, + INVOKE_PROPERTYPUT = 0x4, + INVOKE_PROPERTYPUTREF = 0x8 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.CALLCONV instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Serializable] + public enum CALLCONV : int + { + CC_CDECL =1, + CC_MSCPASCAL=2, + CC_PASCAL =CC_MSCPASCAL, + CC_MACPASCAL=3, + CC_STDCALL =4, + CC_RESERVED =5, + CC_SYSCALL =6, + CC_MPWCDECL =7, + CC_MPWPASCAL=8, + CC_MAX =9 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.FUNCFLAGS instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] +[Serializable] +[Flags()] + public enum FUNCFLAGS : short + { + FUNCFLAG_FRESTRICTED= 0x1, + FUNCFLAG_FSOURCE = 0x2, + FUNCFLAG_FBINDABLE = 0x4, + FUNCFLAG_FREQUESTEDIT = 0x8, + FUNCFLAG_FDISPLAYBIND = 0x10, + FUNCFLAG_FDEFAULTBIND = 0x20, + FUNCFLAG_FHIDDEN = 0x40, + FUNCFLAG_FUSESGETLASTERROR= 0x80, + FUNCFLAG_FDEFAULTCOLLELEM= 0x100, + FUNCFLAG_FUIDEFAULT = 0x200, + FUNCFLAG_FNONBROWSABLE = 0x400, + FUNCFLAG_FREPLACEABLE = 0x800, + FUNCFLAG_FIMMEDIATEBIND = 0x1000 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.VARFLAGS instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] +[Serializable] +[Flags()] + public enum VARFLAGS : short + { + VARFLAG_FREADONLY =0x1, + VARFLAG_FSOURCE =0x2, + VARFLAG_FBINDABLE =0x4, + VARFLAG_FREQUESTEDIT =0x8, + VARFLAG_FDISPLAYBIND =0x10, + VARFLAG_FDEFAULTBIND =0x20, + VARFLAG_FHIDDEN =0x40, + VARFLAG_FRESTRICTED =0x80, + VARFLAG_FDEFAULTCOLLELEM =0x100, + VARFLAG_FUIDEFAULT =0x200, + VARFLAG_FNONBROWSABLE =0x400, + VARFLAG_FREPLACEABLE =0x800, + VARFLAG_FIMMEDIATEBIND =0x1000 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.ITypeInfo instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("00020401-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMITypeInfo + { + void GetTypeAttr(out IntPtr ppTypeAttr); + void GetTypeComp(out UCOMITypeComp ppTComp); + void GetFuncDesc(int index, out IntPtr ppFuncDesc); + void GetVarDesc(int index, out IntPtr ppVarDesc); + void GetNames(int memid, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] String[] rgBstrNames, int cMaxNames, out int pcNames); + void GetRefTypeOfImplType(int index, out int href); + void GetImplTypeFlags(int index, out int pImplTypeFlags); + void GetIDsOfNames([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1), In] String[] rgszNames, int cNames, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] int[] pMemId); + void Invoke([MarshalAs(UnmanagedType.IUnknown)] Object pvInstance, int memid, Int16 wFlags, ref DISPPARAMS pDispParams, out Object pVarResult, out EXCEPINFO pExcepInfo, out int puArgErr); + void GetDocumentation(int index, out String strName, out String strDocString, out int dwHelpContext, out String strHelpFile); + void GetDllEntry(int memid, INVOKEKIND invKind, out String pBstrDllName, out String pBstrName, out Int16 pwOrdinal); + void GetRefTypeInfo(int hRef, out UCOMITypeInfo ppTI); + void AddressOfMember(int memid, INVOKEKIND invKind, out IntPtr ppv); + void CreateInstance([MarshalAs(UnmanagedType.IUnknown)] Object pUnkOuter, ref Guid riid, [MarshalAs(UnmanagedType.IUnknown), Out] out Object ppvObj); + void GetMops(int memid, out String pBstrMops); + void GetContainingTypeLib(out UCOMITypeLib ppTLB, out int pIndex); + void ReleaseTypeAttr(IntPtr pTypeAttr); + void ReleaseFuncDesc(IntPtr pFuncDesc); + void ReleaseVarDesc(IntPtr pVarDesc); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UCOMITypeLib.cs b/src/mscorlib/src/System/Runtime/InteropServices/UCOMITypeLib.cs new file mode 100644 index 0000000000..b67347b7e2 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UCOMITypeLib.cs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: UCOMITypeLib interface definition. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices +{ + using System; + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.SYSKIND instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Serializable] + public enum SYSKIND + { + SYS_WIN16 = 0, + SYS_WIN32 = SYS_WIN16 + 1, + SYS_MAC = SYS_WIN32 + 1 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.LIBFLAGS instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] +[Serializable] +[Flags()] + public enum LIBFLAGS : short + { + LIBFLAG_FRESTRICTED = 0x1, + LIBFLAG_FCONTROL = 0x2, + LIBFLAG_FHIDDEN = 0x4, + LIBFLAG_FHASDISKIMAGE = 0x8 + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.TYPELIBATTR instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + [Serializable] + public struct TYPELIBATTR + { + public Guid guid; + public int lcid; + public SYSKIND syskind; + public Int16 wMajorVerNum; + public Int16 wMinorVerNum; + public LIBFLAGS wLibFlags; + } + + [Obsolete("Use System.Runtime.InteropServices.ComTypes.ITypeLib instead. http://go.microsoft.com/fwlink/?linkid=14202", false)] + [Guid("00020402-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface UCOMITypeLib + { + [PreserveSig] + int GetTypeInfoCount(); + void GetTypeInfo(int index, out UCOMITypeInfo ppTI); + void GetTypeInfoType(int index, out TYPEKIND pTKind); + void GetTypeInfoOfGuid(ref Guid guid, out UCOMITypeInfo ppTInfo); + void GetLibAttr(out IntPtr ppTLibAttr); + void GetTypeComp(out UCOMITypeComp ppTComp); + void GetDocumentation(int index, out String strName, out String strDocString, out int dwHelpContext, out String strHelpFile); + [return : MarshalAs(UnmanagedType.Bool)] + bool IsName([MarshalAs(UnmanagedType.LPWStr)] String szNameBuf, int lHashVal); + void FindName([MarshalAs(UnmanagedType.LPWStr)] String szNameBuf, int lHashVal, [MarshalAs(UnmanagedType.LPArray), Out] UCOMITypeInfo[] ppTInfo, [MarshalAs(UnmanagedType.LPArray), Out] int[] rgMemId, ref Int16 pcFound); + [PreserveSig] + void ReleaseTLibAttr(IntPtr pTLibAttr); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/UnknownWrapper.cs b/src/mscorlib/src/System/Runtime/InteropServices/UnknownWrapper.cs new file mode 100644 index 0000000000..c9084f715f --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/UnknownWrapper.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Wrapper that is converted to a variant with VT_UNKNOWN. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public sealed class UnknownWrapper + { + public UnknownWrapper(Object obj) + { + m_WrappedObject = obj; + } + + public Object WrappedObject + { + get + { + return m_WrappedObject; + } + } + + private Object m_WrappedObject; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/Variant.cs b/src/mscorlib/src/System/Runtime/InteropServices/Variant.cs new file mode 100644 index 0000000000..fbd1b3c15d --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/Variant.cs @@ -0,0 +1,658 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Runtime.InteropServices { + using System.Diagnostics; + + /// <summary> + /// Variant is the basic COM type for late-binding. It can contain any other COM data type. + /// This type definition precisely matches the unmanaged data layout so that the struct can be passed + /// to and from COM calls. + /// </summary> + [StructLayout(LayoutKind.Explicit)] + [System.Security.SecurityCritical] + internal struct Variant { + +#if DEBUG + static Variant() { + // Variant size is the size of 4 pointers (16 bytes) on a 32-bit processor, + // and 3 pointers (24 bytes) on a 64-bit processor. + int variantSize = Marshal.SizeOf(typeof(Variant)); + if (IntPtr.Size == 4) { + BCLDebug.Assert(variantSize == (4 * IntPtr.Size), "variant"); + } else { + BCLDebug.Assert(IntPtr.Size == 8, "variant"); + BCLDebug.Assert(variantSize == (3 * IntPtr.Size), "variant"); + } + } +#endif + + // Most of the data types in the Variant are carried in _typeUnion + [FieldOffset(0)] private TypeUnion _typeUnion; + + // Decimal is the largest data type and it needs to use the space that is normally unused in TypeUnion._wReserved1, etc. + // Hence, it is declared to completely overlap with TypeUnion. A Decimal does not use the first two bytes, and so + // TypeUnion._vt can still be used to encode the type. + [FieldOffset(0)] private Decimal _decimal; + + [StructLayout(LayoutKind.Sequential)] + private struct TypeUnion { + internal ushort _vt; + internal ushort _wReserved1; + internal ushort _wReserved2; + internal ushort _wReserved3; + + internal UnionTypes _unionTypes; + } + + [StructLayout(LayoutKind.Sequential)] + private struct Record { + private IntPtr _record; + private IntPtr _recordInfo; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")] + [StructLayout(LayoutKind.Explicit)] + private struct UnionTypes { + #region Generated Variant union types + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_UnionTypes from: generate_comdispatch.py + + [FieldOffset(0)] internal SByte _i1; + [FieldOffset(0)] internal Int16 _i2; + [FieldOffset(0)] internal Int32 _i4; + [FieldOffset(0)] internal Int64 _i8; + [FieldOffset(0)] internal Byte _ui1; + [FieldOffset(0)] internal UInt16 _ui2; + [FieldOffset(0)] internal UInt32 _ui4; + [FieldOffset(0)] internal UInt64 _ui8; + [FieldOffset(0)] internal Int32 _int; + [FieldOffset(0)] internal UInt32 _uint; + [FieldOffset(0)] internal Int16 _bool; + [FieldOffset(0)] internal Int32 _error; + [FieldOffset(0)] internal Single _r4; + [FieldOffset(0)] internal Double _r8; + [FieldOffset(0)] internal Int64 _cy; + [FieldOffset(0)] internal double _date; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] + [FieldOffset(0)] internal IntPtr _bstr; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] + [FieldOffset(0)] internal IntPtr _unknown; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] + [FieldOffset(0)] internal IntPtr _dispatch; + + // *** END GENERATED CODE *** + + #endregion + + [FieldOffset(0)] internal IntPtr _pvarVal; + [FieldOffset(0)] internal IntPtr _byref; + [FieldOffset(0)] internal Record _record; + } + + /// <summary> + /// Primitive types are the basic COM types. It includes valuetypes like ints, but also reference types + /// like BStrs. It does not include composite types like arrays and user-defined COM types (IUnknown/IDispatch). + /// </summary> + internal static bool IsPrimitiveType(VarEnum varEnum) { + switch(varEnum) { + #region Generated Variant IsPrimitiveType + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_IsPrimitiveType from: generate_comdispatch.py + + case VarEnum.VT_I1: + case VarEnum.VT_I2: + case VarEnum.VT_I4: + case VarEnum.VT_I8: + case VarEnum.VT_UI1: + case VarEnum.VT_UI2: + case VarEnum.VT_UI4: + case VarEnum.VT_UI8: + case VarEnum.VT_INT: + case VarEnum.VT_UINT: + case VarEnum.VT_BOOL: + case VarEnum.VT_R4: + case VarEnum.VT_R8: + case VarEnum.VT_DECIMAL: + case VarEnum.VT_DATE: + case VarEnum.VT_BSTR: + + // *** END GENERATED CODE *** + + #endregion + return true; + } + + return false; + } + + unsafe public void CopyFromIndirect(object value) { + + VarEnum vt = (VarEnum)(((int)this.VariantType) & ~((int)VarEnum.VT_BYREF)); + + if (value == null) { + if (vt == VarEnum.VT_DISPATCH || vt == VarEnum.VT_UNKNOWN || vt == VarEnum.VT_BSTR) { + *(IntPtr*)this._typeUnion._unionTypes._byref = IntPtr.Zero; + } + return; + } + + switch (vt) { + case VarEnum.VT_I1: + *(sbyte*)this._typeUnion._unionTypes._byref = (sbyte)value; + break; + + case VarEnum.VT_UI1: + *(byte*)this._typeUnion._unionTypes._byref = (byte)value; + break; + + case VarEnum.VT_I2: + *(short*)this._typeUnion._unionTypes._byref = (short)value; + break; + + case VarEnum.VT_UI2: + *(ushort*)this._typeUnion._unionTypes._byref = (ushort)value; + break; + + case VarEnum.VT_BOOL: + *(short*)this._typeUnion._unionTypes._byref = (bool)value ? (short)-1 : (short)0; + break; + + case VarEnum.VT_I4: + case VarEnum.VT_INT: + *(int*)this._typeUnion._unionTypes._byref = (int)value; + break; + + case VarEnum.VT_UI4: + case VarEnum.VT_UINT: + *(uint*)this._typeUnion._unionTypes._byref = (uint)value; + break; + + case VarEnum.VT_ERROR: + *(int*)this._typeUnion._unionTypes._byref = ((ErrorWrapper)value).ErrorCode; + break; + + case VarEnum.VT_I8: + *(Int64*)this._typeUnion._unionTypes._byref = (Int64)value; + break; + + case VarEnum.VT_UI8: + *(UInt64*)this._typeUnion._unionTypes._byref = (UInt64)value; + break; + + case VarEnum.VT_R4: + *(float*)this._typeUnion._unionTypes._byref = (float)value; + break; + + case VarEnum.VT_R8: + *(double*)this._typeUnion._unionTypes._byref = (double)value; + break; + + case VarEnum.VT_DATE: + *(double*)this._typeUnion._unionTypes._byref = ((DateTime)value).ToOADate(); + break; + + case VarEnum.VT_UNKNOWN: + *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.GetIUnknownForObject(value); + break; + + case VarEnum.VT_DISPATCH: + *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.GetIDispatchForObject(value); + break; + + case VarEnum.VT_BSTR: + *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.StringToBSTR((string)value); + break; + + case VarEnum.VT_CY: + *(long*)this._typeUnion._unionTypes._byref = decimal.ToOACurrency((decimal)value); + break; + + case VarEnum.VT_DECIMAL: + *(decimal*)this._typeUnion._unionTypes._byref = (decimal)value; + break; + + case VarEnum.VT_VARIANT: + Marshal.GetNativeVariantForObject(value, this._typeUnion._unionTypes._byref); + break; + + default: + throw new ArgumentException("invalid argument type"); + } + } + + /// <summary> + /// Get the managed object representing the Variant. + /// </summary> + /// <returns></returns> + public object ToObject() { + // Check the simple case upfront + if (IsEmpty) { + return null; + } + + switch (VariantType) { + case VarEnum.VT_NULL: return DBNull.Value; + + #region Generated Variant ToObject + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_ToObject from: generate_comdispatch.py + + case VarEnum.VT_I1: return AsI1; + case VarEnum.VT_I2: return AsI2; + case VarEnum.VT_I4: return AsI4; + case VarEnum.VT_I8: return AsI8; + case VarEnum.VT_UI1: return AsUi1; + case VarEnum.VT_UI2: return AsUi2; + case VarEnum.VT_UI4: return AsUi4; + case VarEnum.VT_UI8: return AsUi8; + case VarEnum.VT_INT: return AsInt; + case VarEnum.VT_UINT: return AsUint; + case VarEnum.VT_BOOL: return AsBool; + case VarEnum.VT_ERROR: return AsError; + case VarEnum.VT_R4: return AsR4; + case VarEnum.VT_R8: return AsR8; + case VarEnum.VT_DECIMAL: return AsDecimal; + case VarEnum.VT_CY: return AsCy; + case VarEnum.VT_DATE: return AsDate; + case VarEnum.VT_BSTR: return AsBstr; + case VarEnum.VT_UNKNOWN: return AsUnknown; + case VarEnum.VT_DISPATCH: return AsDispatch; + // VarEnum.VT_VARIANT is handled by Marshal.GetObjectForNativeVariant below + + // *** END GENERATED CODE *** + + #endregion + + default: + try { + unsafe { + fixed (void* pThis = &this) { + return Marshal.GetObjectForNativeVariant((System.IntPtr)pThis); + } + } + } + catch (Exception ex) { + throw new NotImplementedException("Variant.ToObject cannot handle" + VariantType, ex); + } + } + } + + /// <summary> + /// Release any unmanaged memory associated with the Variant + /// </summary> + /// <returns></returns> + public void Clear() { + // We do not need to call OLE32's VariantClear for primitive types or ByRefs + // to safe ourselves the cost of interop transition. + // ByRef indicates the memory is not owned by the VARIANT itself while + // primitive types do not have any resources to free up. + // Hence, only safearrays, BSTRs, interfaces and user types are + // handled differently. + VarEnum vt = VariantType; + if ((vt & VarEnum.VT_BYREF) != 0) { + VariantType = VarEnum.VT_EMPTY; + } else if ( + ((vt & VarEnum.VT_ARRAY) != 0) || + ((vt) == VarEnum.VT_BSTR) || + ((vt) == VarEnum.VT_UNKNOWN) || + ((vt) == VarEnum.VT_DISPATCH) || + ((vt) == VarEnum.VT_VARIANT) || + ((vt) == VarEnum.VT_RECORD) || + ((vt) == VarEnum.VT_VARIANT) + ) { + unsafe { + fixed (void* pThis = &this) { + NativeMethods.VariantClear((IntPtr)pThis); + } + } + BCLDebug.Assert(IsEmpty, "variant"); + } else { + VariantType = VarEnum.VT_EMPTY; + } + } + + public VarEnum VariantType { + get { + return (VarEnum)_typeUnion._vt; + } + set { + _typeUnion._vt = (ushort)value; + } + } + + internal bool IsEmpty { + get { + return _typeUnion._vt == ((ushort)VarEnum.VT_EMPTY); + } + } + + internal bool IsByRef { + get { + return (_typeUnion._vt & ((ushort)VarEnum.VT_BYREF)) != 0; + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly")] + public void SetAsNULL() { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_NULL; + } + + #region Generated Variant accessors + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_accessors from: generate_comdispatch.py + + // VT_I1 + + public SByte AsI1 { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_I1, "variant"); + return _typeUnion._unionTypes._i1; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_I1; + _typeUnion._unionTypes._i1 = value; + } + } + + // VT_I2 + + public Int16 AsI2 { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_I2, "variant"); + return _typeUnion._unionTypes._i2; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_I2; + _typeUnion._unionTypes._i2 = value; + } + } + + // VT_I4 + + public Int32 AsI4 { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_I4, "variant"); + return _typeUnion._unionTypes._i4; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_I4; + _typeUnion._unionTypes._i4 = value; + } + } + + // VT_I8 + + public Int64 AsI8 { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_I8, "variant"); + return _typeUnion._unionTypes._i8; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_I8; + _typeUnion._unionTypes._i8 = value; + } + } + + // VT_UI1 + + public Byte AsUi1 { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_UI1, "variant"); + return _typeUnion._unionTypes._ui1; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_UI1; + _typeUnion._unionTypes._ui1 = value; + } + } + + // VT_UI2 + + public UInt16 AsUi2 { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_UI2, "variant"); + return _typeUnion._unionTypes._ui2; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_UI2; + _typeUnion._unionTypes._ui2 = value; + } + } + + // VT_UI4 + + public UInt32 AsUi4 { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_UI4, "variant"); + return _typeUnion._unionTypes._ui4; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_UI4; + _typeUnion._unionTypes._ui4 = value; + } + } + + // VT_UI8 + + public UInt64 AsUi8 { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_UI8, "variant"); + return _typeUnion._unionTypes._ui8; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_UI8; + _typeUnion._unionTypes._ui8 = value; + } + } + + // VT_INT + + public Int32 AsInt { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_INT, "variant"); + return _typeUnion._unionTypes._int; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_INT; + _typeUnion._unionTypes._int = value; + } + } + + // VT_UINT + + public UInt32 AsUint { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_UINT, "variant"); + return _typeUnion._unionTypes._uint; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_UINT; + _typeUnion._unionTypes._uint = value; + } + } + + // VT_BOOL + + public bool AsBool { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_BOOL, "variant"); + return _typeUnion._unionTypes._bool != 0; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_BOOL; + _typeUnion._unionTypes._bool = value ? (short)-1 : (short)0; + } + } + + // VT_ERROR + + public Int32 AsError { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_ERROR, "variant"); + return _typeUnion._unionTypes._error; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_ERROR; + _typeUnion._unionTypes._error = value; + } + } + + // VT_R4 + + public Single AsR4 { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_R4, "variant"); + return _typeUnion._unionTypes._r4; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_R4; + _typeUnion._unionTypes._r4 = value; + } + } + + // VT_R8 + + public Double AsR8 { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_R8, "variant"); + return _typeUnion._unionTypes._r8; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_R8; + _typeUnion._unionTypes._r8 = value; + } + } + + // VT_DECIMAL + + public Decimal AsDecimal { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_DECIMAL, "variant"); + // The first byte of Decimal is unused, but usually set to 0 + Variant v = this; + v._typeUnion._vt = 0; + return v._decimal; + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_DECIMAL; + _decimal = value; + // _vt overlaps with _decimal, and should be set after setting _decimal + _typeUnion._vt = (ushort)VarEnum.VT_DECIMAL; + } + } + + // VT_CY + + public Decimal AsCy { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_CY, "variant"); + return Decimal.FromOACurrency(_typeUnion._unionTypes._cy); + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_CY; + _typeUnion._unionTypes._cy = Decimal.ToOACurrency(value); + } + } + + // VT_DATE + + public DateTime AsDate { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_DATE, "variant"); + return DateTime.FromOADate(_typeUnion._unionTypes._date); + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_DATE; + _typeUnion._unionTypes._date = value.ToOADate(); + } + } + + // VT_BSTR + + public String AsBstr { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_BSTR, "variant"); + return (string)Marshal.PtrToStringBSTR(this._typeUnion._unionTypes._bstr); + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_BSTR; + this._typeUnion._unionTypes._bstr = Marshal.StringToBSTR(value); + } + } + + // VT_UNKNOWN + + public Object AsUnknown { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_UNKNOWN, "variant"); + if (_typeUnion._unionTypes._unknown == IntPtr.Zero) + return null; + return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._unknown); + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_UNKNOWN; + if (value == null) + _typeUnion._unionTypes._unknown = IntPtr.Zero; + else + _typeUnion._unionTypes._unknown = Marshal.GetIUnknownForObject(value); + } + } + + // VT_DISPATCH + + public Object AsDispatch { + get { + BCLDebug.Assert(VariantType == VarEnum.VT_DISPATCH, "variant"); + if (_typeUnion._unionTypes._dispatch == IntPtr.Zero) + return null; + return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._dispatch); + } + set { + BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise + VariantType = VarEnum.VT_DISPATCH; + if (value == null) + _typeUnion._unionTypes._dispatch = IntPtr.Zero; + else + _typeUnion._unionTypes._dispatch = Marshal.GetIDispatchForObject(value); + } + } + + + // *** END GENERATED CODE *** + + internal IntPtr AsByRefVariant + { + get { + BCLDebug.Assert(VariantType == (VarEnum.VT_BYREF | VarEnum.VT_VARIANT), "variant"); + return _typeUnion._unionTypes._pvarVal; + } + } + + #endregion + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/VariantWrapper.cs b/src/mscorlib/src/System/Runtime/InteropServices/VariantWrapper.cs new file mode 100644 index 0000000000..c57ed61054 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/VariantWrapper.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** Purpose: Wrapper that is converted to a variant with VT_BYREF | VT_VARIANT. +** +** +=============================================================================*/ + +namespace System.Runtime.InteropServices { + + using System; + + [Serializable] + + public sealed class VariantWrapper + { + public VariantWrapper(Object obj) + { + m_WrappedObject = obj; + } + + public Object WrappedObject + { + get + { + return m_WrappedObject; + } + } + + private Object m_WrappedObject; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/Attributes.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/Attributes.cs new file mode 100644 index 0000000000..5bc5a7dd22 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/Attributes.cs @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // DefaultInterfaceAttribute marks a WinRT class (or interface group) that has its default interface specified. + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] + public sealed class DefaultInterfaceAttribute : Attribute + { + private Type m_defaultInterface; + + public DefaultInterfaceAttribute(Type defaultInterface) + { + m_defaultInterface = defaultInterface; + } + + public Type DefaultInterface + { + get { return m_defaultInterface; } + } + } + + // WindowsRuntimeImport is a pseudo custom attribute which causes us to emit the tdWindowsRuntime bit + // onto types which are decorated with the attribute. This is needed to mark Windows Runtime types + // which are redefined in mscorlib.dll and System.Runtime.WindowsRuntime.dll, as the C# compiler does + // not have a built in syntax to mark tdWindowsRuntime. These two assemblies are special as they + // implement the CLR's support for WinRT, so this type is internal as marking tdWindowsRuntime should + // generally be done via winmdexp for user code. + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Struct | AttributeTargets.Delegate, Inherited = false)] + [System.Runtime.CompilerServices.FriendAccessAllowed] + internal sealed class WindowsRuntimeImportAttribute : Attribute + { + public WindowsRuntimeImportAttribute() + { } + } + + // This attribute is applied to class interfaces in a generated projection assembly. It is used by Visual Studio + // and other tools to find out what version of a component (eg. Windows) a WinRT class began to implement + // a particular interfaces. + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = true)] + public sealed class InterfaceImplementedInVersionAttribute : Attribute + { + public InterfaceImplementedInVersionAttribute(Type interfaceType, byte majorVersion, byte minorVersion, byte buildVersion, byte revisionVersion) + { + m_interfaceType = interfaceType; + m_majorVersion = majorVersion; + m_minorVersion = minorVersion; + m_buildVersion = buildVersion; + m_revisionVersion = revisionVersion; + } + + public Type InterfaceType + { + get { return m_interfaceType; } + } + + public byte MajorVersion + { + get { return m_majorVersion; } + } + + public byte MinorVersion + { + get { return m_minorVersion; } + } + + public byte BuildVersion + { + get { return m_buildVersion; } + } + + public byte RevisionVersion + { + get { return m_revisionVersion; } + } + + private Type m_interfaceType; + private byte m_majorVersion; + private byte m_minorVersion; + private byte m_buildVersion; + private byte m_revisionVersion; + } + + // Applies to read-only array parameters + [AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)] + public sealed class ReadOnlyArrayAttribute : Attribute + { + public ReadOnlyArrayAttribute() {} + } + + // Applies to write-only array parameters + [AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)] + public sealed class WriteOnlyArrayAttribute : Attribute + { + public WriteOnlyArrayAttribute() {} + } + + + + // This attribute is applied on the return value to specify the name of the return value. + // In WindowsRuntime all parameters including return value need to have unique names. + // This is essential in JS as one of the ways to get at the results of a method in JavaScript is via a Dictionary object keyed by parameter name. + [AttributeUsage(AttributeTargets.ReturnValue | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] + public sealed class ReturnValueNameAttribute : Attribute + { + private string m_Name; + public ReturnValueNameAttribute(string name) + { + m_Name = name; + } + + public string Name + { + get { return m_Name; } + } + } + +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToCollectionAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToCollectionAdapter.cs new file mode 100644 index 0000000000..2f15428ae1 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToCollectionAdapter.cs @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Runtime; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the ICollection interface on WinRT + // objects that support IBindableVector. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not BindableVectorToCollectionAdapter objects. Rather, they are + // of type IBindableVector. No actual BindableVectorToCollectionAdapter object is ever instantiated. + // Thus, you will see a lot of expressions that cast "this" to "IBindableVector". + internal sealed class BindableVectorToCollectionAdapter + { + private BindableVectorToCollectionAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // int Count { get } + [Pure] + [SecurityCritical] + internal int Count() + { + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + uint size = _this.Size; + if (((uint)Int32.MaxValue) < size) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + return (int)size; + } + + // bool IsSynchronized { get } + [Pure] + [SecurityCritical] + internal bool IsSynchronized() + { + return false; + } + + // object SyncRoot { get } + [Pure] + [SecurityCritical] + internal object SyncRoot() + { + return this; + } + + // void CopyTo(Array array, int index) + [Pure] + [SecurityCritical] + internal void CopyTo(Array array, int arrayIndex) + { + if (array == null) + throw new ArgumentNullException("array"); + + // ICollection expects the destination array to be single-dimensional. + if (array.Rank != 1) + throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); + + int destLB = array.GetLowerBound(0); + + int srcLen = Count(); + int destLen = array.GetLength(0); + + if (arrayIndex < destLB) + throw new ArgumentOutOfRangeException("arrayIndex"); + + // Does the dimension in question have sufficient space to copy the expected number of entries? + // We perform this check before valid index check to ensure the exception message is in sync with + // the following snippet that uses regular framework code: + // + // ArrayList list = new ArrayList(); + // list.Add(1); + // Array items = Array.CreateInstance(typeof(object), new int[] { 1 }, new int[] { -1 }); + // list.CopyTo(items, 0); + + if(srcLen > (destLen - (arrayIndex - destLB))) + throw new ArgumentException(Environment.GetResourceString("Argument_InsufficientSpaceToCopyCollection")); + + if(arrayIndex - destLB > destLen) + throw new ArgumentException(Environment.GetResourceString("Argument_IndexOutOfArrayBounds")); + + // We need to verify the index as we; + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + + for (uint i = 0; i < srcLen; i++) + { + array.SetValue(_this.GetAt(i), i + arrayIndex); + } + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToListAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToListAdapter.cs new file mode 100644 index 0000000000..fddc7588c2 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToListAdapter.cs @@ -0,0 +1,240 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Runtime; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IList interface on WinRT + // objects that support IBindableVector. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not BindableVectorToListAdapter objects. Rather, they are + // of type IBindableVector. No actual BindableVectorToListAdapter object is ever instantiated. + // Thus, you will see a lot of expressions that cast "this" to "IBindableVector". + internal sealed class BindableVectorToListAdapter + { + private BindableVectorToListAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // object this[int index] { get } + [SecurityCritical] + internal object Indexer_Get(int index) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + return GetAt(_this, (uint)index); + } + + // object this[int index] { set } + [SecurityCritical] + internal void Indexer_Set(int index, object value) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + SetAt(_this, (uint)index, value); + } + + // int Add(object value) + [SecurityCritical] + internal int Add(object value) + { + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + _this.Append(value); + + uint size = _this.Size; + if (((uint)Int32.MaxValue) < size) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + return (int)(size - 1); + } + + // bool Contains(object item) + [SecurityCritical] + internal bool Contains(object item) + { + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + + uint index; + return _this.IndexOf(item, out index); + } + + // void Clear() + [SecurityCritical] + internal void Clear() + { + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + _this.Clear(); + } + + // bool IsFixedSize { get } + [Pure] + [SecurityCritical] + internal bool IsFixedSize() + { + return false; + } + + // bool IsReadOnly { get } + [Pure] + [SecurityCritical] + internal bool IsReadOnly() + { + return false; + } + + // int IndexOf(object item) + [SecurityCritical] + internal int IndexOf(object item) + { + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + + uint index; + bool exists = _this.IndexOf(item, out index); + + if (!exists) + return -1; + + if (((uint)Int32.MaxValue) < index) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + return (int)index; + } + + // void Insert(int index, object item) + [SecurityCritical] + internal void Insert(int index, object item) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + InsertAtHelper(_this, (uint)index, item); + } + + // bool Remove(object item) + [SecurityCritical] + internal void Remove(object item) + { + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + + uint index; + bool exists = _this.IndexOf(item, out index); + + if (exists) + { + if (((uint)Int32.MaxValue) < index) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + RemoveAtHelper(_this, index); + } + } + + // void RemoveAt(int index) + [SecurityCritical] + internal void RemoveAt(int index) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + + IBindableVector _this = JitHelpers.UnsafeCast<IBindableVector>(this); + RemoveAtHelper(_this, (uint)index); + } + + // Helpers: + + private static object GetAt(IBindableVector _this, uint index) + { + try + { + return _this.GetAt(index); + + // We delegate bounds checking to the underlying collection and if it detected a fault, + // we translate it to the right exception: + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + throw new ArgumentOutOfRangeException("index"); + + throw; + } + } + + private static void SetAt(IBindableVector _this, uint index, object value) + { + try + { + _this.SetAt(index, value); + + // We delegate bounds checking to the underlying collection and if it detected a fault, + // we translate it to the right exception: + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + throw new ArgumentOutOfRangeException("index"); + + throw; + } + } + + private static void InsertAtHelper(IBindableVector _this, uint index, object item) + { + try + { + _this.InsertAt(index, item); + + // We delegate bounds checking to the underlying collection and if it detected a fault, + // we translate it to the right exception: + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + throw new ArgumentOutOfRangeException("index"); + + throw; + } + } + + private static void RemoveAtHelper(IBindableVector _this, uint index) + { + try + { + _this.RemoveAt(index); + + // We delegate bounds checking to the underlying collection and if it detected a fault, + // we translate it to the right exception: + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + throw new ArgumentOutOfRangeException("index"); + + throw; + } + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIKeyValuePairImpl.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIKeyValuePairImpl.cs new file mode 100644 index 0000000000..683a7f3327 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIKeyValuePairImpl.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // Provides access to a System.Collections.Generic.KeyValuePair<K, V> via the IKeyValuePair<K, V> WinRT interface. + internal sealed class CLRIKeyValuePairImpl<K, V> : IKeyValuePair<K, V> + { + private readonly KeyValuePair<K, V> _pair; + + public CLRIKeyValuePairImpl([In] ref KeyValuePair<K, V> pair) + { + _pair = pair; + } + + // IKeyValuePair<K, V> implementation + [Pure] + public K Key + { + get { return _pair.Key; } + } + + [Pure] + public V Value + { + get { return _pair.Value; } + } + + // Called from the VM to wrap a boxed KeyValuePair with a CLRIKeyValuePairImpl. + internal static object BoxHelper(object pair) + { + Contract.Requires(pair != null); + + KeyValuePair<K, V> unboxedPair = (KeyValuePair<K, V>)pair; + return new CLRIKeyValuePairImpl<K, V>(ref unboxedPair); + } + + // Called from the VM to get a boxed KeyValuePair out of a CLRIKeyValuePairImpl. + internal static object UnboxHelper(object wrapper) + { + Contract.Requires(wrapper != null); + + CLRIKeyValuePairImpl<K, V> reference = (CLRIKeyValuePairImpl<K, V>)wrapper; + return reference._pair; + } + + public override string ToString() + { + return _pair.ToString(); + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIPropertyValueImpl.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIPropertyValueImpl.cs new file mode 100644 index 0000000000..2cd5cfd20a --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIPropertyValueImpl.cs @@ -0,0 +1,554 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; +using System.Security; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + internal class CLRIPropertyValueImpl : IPropertyValue + { + private PropertyType _type; + private Object _data; + + // Numeric scalar types which participate in coersion + private static volatile Tuple<Type, PropertyType>[] s_numericScalarTypes; + + internal CLRIPropertyValueImpl(PropertyType type, Object data) + { + _type = type; + _data = data; + } + + private static Tuple<Type, PropertyType>[] NumericScalarTypes { + get { + if (s_numericScalarTypes == null) { + Tuple<Type, PropertyType>[] numericScalarTypes = new Tuple<Type, PropertyType>[] { + new Tuple<Type, PropertyType>(typeof(Byte), PropertyType.UInt8), + new Tuple<Type, PropertyType>(typeof(Int16), PropertyType.Int16), + new Tuple<Type, PropertyType>(typeof(UInt16), PropertyType.UInt16), + new Tuple<Type, PropertyType>(typeof(Int32), PropertyType.Int32), + new Tuple<Type, PropertyType>(typeof(UInt32), PropertyType.UInt32), + new Tuple<Type, PropertyType>(typeof(Int64), PropertyType.Int64), + new Tuple<Type, PropertyType>(typeof(UInt64), PropertyType.UInt64), + new Tuple<Type, PropertyType>(typeof(Single), PropertyType.Single), + new Tuple<Type, PropertyType>(typeof(Double), PropertyType.Double) + }; + + s_numericScalarTypes = numericScalarTypes; + } + + return s_numericScalarTypes; + } + } + + public PropertyType Type { + [Pure] + get { return _type; } + } + + public bool IsNumericScalar { + [Pure] + get { + return IsNumericScalarImpl(_type, _data); + } + } + + public override string ToString() + { + if (_data != null) + { + return _data.ToString(); + } + else + { + return base.ToString(); + } + } + + [Pure] + public Byte GetUInt8() + { + return CoerceScalarValue<Byte>(PropertyType.UInt8); + } + + [Pure] + public Int16 GetInt16() + { + return CoerceScalarValue<Int16>(PropertyType.Int16); + } + + public UInt16 GetUInt16() + { + return CoerceScalarValue<UInt16>(PropertyType.UInt16); + } + + [Pure] + public Int32 GetInt32() + { + return CoerceScalarValue<Int32>(PropertyType.Int32); + } + + [Pure] + public UInt32 GetUInt32() + { + return CoerceScalarValue<UInt32>(PropertyType.UInt32); + } + + [Pure] + public Int64 GetInt64() + { + return CoerceScalarValue<Int64>(PropertyType.Int64); + } + + [Pure] + public UInt64 GetUInt64() + { + return CoerceScalarValue<UInt64>(PropertyType.UInt64); + } + + [Pure] + public Single GetSingle() + { + return CoerceScalarValue<Single>(PropertyType.Single); + } + + [Pure] + public Double GetDouble() + { + return CoerceScalarValue<Double>(PropertyType.Double); + } + + [Pure] + public char GetChar16() + { + if (this.Type != PropertyType.Char16) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Char16"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + return (char)_data; + } + + [Pure] + public Boolean GetBoolean() + { + if (this.Type != PropertyType.Boolean) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Boolean"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + return (bool)_data; + } + + [Pure] + public String GetString() + { + return CoerceScalarValue<String>(PropertyType.String); + } + + [Pure] + public Object GetInspectable() + { + if (this.Type != PropertyType.Inspectable) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Inspectable"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + return _data; + } + + + [Pure] + public Guid GetGuid() + { + return CoerceScalarValue<Guid>(PropertyType.Guid); + } + + + [Pure] + public DateTimeOffset GetDateTime() + { + if (this.Type != PropertyType.DateTime) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "DateTime"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + return (DateTimeOffset)_data; + } + + [Pure] + public TimeSpan GetTimeSpan() + { + if (this.Type != PropertyType.TimeSpan) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "TimeSpan"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + return (TimeSpan)_data; + } + + [Pure] + [SecuritySafeCritical] + public Point GetPoint() + { + if (this.Type != PropertyType.Point) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Point"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + + return Unbox<Point>(IReferenceFactory.s_pointType); + } + + [Pure] + [SecuritySafeCritical] + public Size GetSize() + { + if (this.Type != PropertyType.Size) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Size"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + + return Unbox<Size>(IReferenceFactory.s_sizeType); + } + + [Pure] + [SecuritySafeCritical] + public Rect GetRect() + { + if (this.Type != PropertyType.Rect) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Rect"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + + return Unbox<Rect>(IReferenceFactory.s_rectType); + } + + [Pure] + public Byte[] GetUInt8Array() + { + return CoerceArrayValue<Byte>(PropertyType.UInt8Array); + } + + [Pure] + public Int16[] GetInt16Array() + { + return CoerceArrayValue<Int16>(PropertyType.Int16Array); + } + + [Pure] + public UInt16[] GetUInt16Array() + { + return CoerceArrayValue<UInt16>(PropertyType.UInt16Array); + } + + [Pure] + public Int32[] GetInt32Array() + { + return CoerceArrayValue<Int32>(PropertyType.Int32Array); + } + + [Pure] + public UInt32[] GetUInt32Array() + { + return CoerceArrayValue<UInt32>(PropertyType.UInt32Array); + } + + [Pure] + public Int64[] GetInt64Array() + { + return CoerceArrayValue<Int64>(PropertyType.Int64Array); + } + + [Pure] + public UInt64[] GetUInt64Array() + { + return CoerceArrayValue<UInt64>(PropertyType.UInt64Array); + } + + [Pure] + public Single[] GetSingleArray() + { + return CoerceArrayValue<Single>(PropertyType.SingleArray); + } + + [Pure] + public Double[] GetDoubleArray() + { + return CoerceArrayValue<Double>(PropertyType.DoubleArray); + } + + [Pure] + public char[] GetChar16Array() + { + if (this.Type != PropertyType.Char16Array) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Char16[]"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + return (char[])_data; + } + + [Pure] + public Boolean[] GetBooleanArray() + { + if (this.Type != PropertyType.BooleanArray) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Boolean[]"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + return (bool[])_data; + } + + [Pure] + public String[] GetStringArray() + { + return CoerceArrayValue<String>(PropertyType.StringArray); + } + + [Pure] + public Object[] GetInspectableArray() + { + if (this.Type != PropertyType.InspectableArray) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Inspectable[]"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + return (Object[])_data; + } + + [Pure] + public Guid[] GetGuidArray() + { + return CoerceArrayValue<Guid>(PropertyType.GuidArray); + } + + [Pure] + public DateTimeOffset[] GetDateTimeArray() + { + if (this.Type != PropertyType.DateTimeArray) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "DateTimeOffset[]"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + return (DateTimeOffset[])_data; + } + + [Pure] + public TimeSpan[] GetTimeSpanArray() + { + if (this.Type != PropertyType.TimeSpanArray) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "TimeSpan[]"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + return (TimeSpan[])_data; + } + + [Pure] + [SecuritySafeCritical] + public Point[] GetPointArray() + { + if (this.Type != PropertyType.PointArray) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Point[]"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + + return UnboxArray<Point>(IReferenceFactory.s_pointType); + } + + [Pure] + [SecuritySafeCritical] + public Size[] GetSizeArray() + { + if (this.Type != PropertyType.SizeArray) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Size[]"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + + + return UnboxArray<Size>(IReferenceFactory.s_sizeType); + } + + [Pure] + [SecuritySafeCritical] + public Rect[] GetRectArray() + { + if (this.Type != PropertyType.RectArray) + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, "Rect[]"), __HResults.TYPE_E_TYPEMISMATCH); + Contract.EndContractBlock(); + + return UnboxArray<Rect>(IReferenceFactory.s_rectType); + } + + private T[] CoerceArrayValue<T>(PropertyType unboxType) { + // If we contain the type being looked for directly, then take the fast-path + if (Type == unboxType) { + return (T[])_data; + } + + // Make sure we have an array to begin with + Array dataArray = _data as Array; + if (dataArray == null) { + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", this.Type, typeof(T).MakeArrayType().Name), __HResults.TYPE_E_TYPEMISMATCH); + } + + // Array types are 1024 larger than their equivilent scalar counterpart + BCLDebug.Assert((int)Type > 1024, "Unexpected array PropertyType value"); + PropertyType scalarType = Type - 1024; + + // If we do not have the correct array type, then we need to convert the array element-by-element + // to a new array of the requested type + T[] coercedArray = new T[dataArray.Length]; + for (int i = 0; i < dataArray.Length; ++i) { + try { + coercedArray[i] = CoerceScalarValue<T>(scalarType, dataArray.GetValue(i)); + } catch (InvalidCastException elementCastException) { + Exception e = new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueArrayCoersion", this.Type, typeof(T).MakeArrayType().Name, i, elementCastException.Message), elementCastException); + e.SetErrorCode(elementCastException._HResult); + throw e; + } + } + + return coercedArray; + } + + private T CoerceScalarValue<T>(PropertyType unboxType) + { + // If we are just a boxed version of the requested type, then take the fast path out + if (Type == unboxType) { + return (T)_data; + } + + return CoerceScalarValue<T>(Type, _data); + } + + private static T CoerceScalarValue<T>(PropertyType type, object value) { + // If the property type is neither one of the coercable numeric types nor IInspectable, we + // should not attempt coersion, even if the underlying value is technically convertable + if (!IsCoercable(type, value) && type != PropertyType.Inspectable) { + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", type, typeof(T).Name), __HResults.TYPE_E_TYPEMISMATCH); + } + + try { + // Try to coerce: + // * String <--> Guid + // * Numeric scalars + if (type == PropertyType.String && typeof(T) == typeof(Guid)) { + return (T)(object)Guid.Parse((string)value); + } + else if (type == PropertyType.Guid && typeof(T) == typeof(String)) { + return (T)(object)((Guid)value).ToString("D", System.Globalization.CultureInfo.InvariantCulture); + } + else { + // Iterate over the numeric scalars, to see if we have a match for one of the known conversions + foreach (Tuple<Type, PropertyType> numericScalar in NumericScalarTypes) { + if (numericScalar.Item1 == typeof(T)) { + return (T)Convert.ChangeType(value, typeof(T), System.Globalization.CultureInfo.InvariantCulture); + } + } + } + } + catch (FormatException) { + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", type, typeof(T).Name), __HResults.TYPE_E_TYPEMISMATCH); + } + catch (InvalidCastException) { + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", type, typeof(T).Name), __HResults.TYPE_E_TYPEMISMATCH); + } + catch (OverflowException) { + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueCoersion", type, value, typeof(T).Name), __HResults.DISP_E_OVERFLOW); + } + + // If the property type is IInspectable, and we have a nested IPropertyValue, then we need + // to pass along the request to coerce the value. + IPropertyValue ipv = value as IPropertyValue; + if (type == PropertyType.Inspectable && ipv != null) { + if (typeof(T) == typeof(Byte)) { + return (T)(object)ipv.GetUInt8(); + } + else if (typeof(T) == typeof(Int16)) { + return (T)(object)ipv.GetInt16(); + } + else if (typeof(T) == typeof(UInt16)) { + return (T)(object)ipv.GetUInt16(); + } + else if (typeof(T) == typeof(Int32)) { + return (T)(object)ipv.GetUInt32(); + } + else if (typeof(T) == typeof(UInt32)) { + return (T)(object)ipv.GetUInt32(); + } + else if (typeof(T) == typeof(Int64)) { + return (T)(object)ipv.GetInt64(); + } + else if (typeof(T) == typeof(UInt64)) { + return (T)(object)ipv.GetUInt64(); + } + else if (typeof(T) == typeof(Single)) { + return (T)(object)ipv.GetSingle(); + } + else if (typeof(T) == typeof(Double)) { + return (T)(object)ipv.GetDouble(); + } + else { + BCLDebug.Assert(false, "T in coersion function wasn't understood as a type that can be coerced - make sure that CoerceScalarValue and NumericScalarTypes are in sync"); + } + } + + // Otherwise, this is an invalid coersion + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", type, typeof(T).Name), __HResults.TYPE_E_TYPEMISMATCH); + } + + private static bool IsCoercable(PropertyType type, object data) { + // String <--> Guid is allowed + if (type == PropertyType.Guid || type == PropertyType.String) { + return true; + } + + // All numeric scalars can also be coerced + return IsNumericScalarImpl(type, data); + } + + private static bool IsNumericScalarImpl(PropertyType type, object data) { + if (data.GetType().IsEnum) { + return true; + } + + foreach (Tuple<Type, PropertyType> numericScalar in NumericScalarTypes) { + if (numericScalar.Item2 == type) { + return true; + } + } + + return false; + } + + // Unbox the data stored in the property value to a structurally equivilent type + [Pure] + [SecurityCritical] + private unsafe T Unbox<T>(Type expectedBoxedType) where T : struct { + Contract.Requires(expectedBoxedType != null); + Contract.Requires(Marshal.SizeOf(expectedBoxedType) == Marshal.SizeOf(typeof(T))); + + if (_data.GetType() != expectedBoxedType) { + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", _data.GetType(), expectedBoxedType.Name), __HResults.TYPE_E_TYPEMISMATCH); + } + + T unboxed = new T(); + + fixed (byte *pData = &JitHelpers.GetPinningHelper(_data).m_data) { + byte* pUnboxed = (byte*)JitHelpers.UnsafeCastToStackPointer(ref unboxed); + Buffer.Memcpy(pUnboxed, pData, Marshal.SizeOf(unboxed)); + } + + return unboxed; + } + + // Convert the array stored in the property value to a structurally equivilent array type + [Pure] + [SecurityCritical] + private unsafe T[] UnboxArray<T>(Type expectedArrayElementType) where T : struct { + Contract.Requires(expectedArrayElementType != null); + Contract.Requires(Marshal.SizeOf(expectedArrayElementType) == Marshal.SizeOf(typeof(T))); + + Array dataArray = _data as Array; + if (dataArray == null || _data.GetType().GetElementType() != expectedArrayElementType) { + throw new InvalidCastException(Environment.GetResourceString("InvalidCast_WinRTIPropertyValueElement", _data.GetType(), expectedArrayElementType.MakeArrayType().Name), __HResults.TYPE_E_TYPEMISMATCH); + } + + T[] converted = new T[dataArray.Length]; + + if (converted.Length > 0) { + fixed (byte * dataPin = &JitHelpers.GetPinningHelper(dataArray).m_data) { + fixed (byte * convertedPin = &JitHelpers.GetPinningHelper(converted).m_data) { + byte *pData = (byte *)Marshal.UnsafeAddrOfPinnedArrayElement(dataArray, 0); + byte *pConverted = (byte *)Marshal.UnsafeAddrOfPinnedArrayElement(converted, 0); + + Buffer.Memcpy(pConverted, pData, checked(Marshal.SizeOf(typeof(T)) * converted.Length)); + } + } + } + + return converted; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs new file mode 100644 index 0000000000..99c546a392 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs @@ -0,0 +1,457 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Collections; +using System.Diagnostics.Contracts; +using System.Reflection; +using System.Security; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + internal sealed class CLRIReferenceImpl<T> : CLRIPropertyValueImpl, IReference<T>, ICustomPropertyProvider + { + private T _value; + + public CLRIReferenceImpl(PropertyType type, T obj) + : base(type, obj) + { + BCLDebug.Assert(obj != null, "Must not be null"); + _value = obj; + } + + public T Value { + get { return _value; } + } + + public override string ToString() + { + if (_value != null) + { + return _value.ToString(); + } + else + { + return base.ToString(); + } + } + + [Pure] + ICustomProperty ICustomPropertyProvider.GetCustomProperty(string name) + { + // _value should not be null + return ICustomPropertyProviderImpl.CreateProperty((object)_value, name); + } + + [Pure] + ICustomProperty ICustomPropertyProvider.GetIndexedProperty(string name, Type indexParameterType) + { + // _value should not be null + return ICustomPropertyProviderImpl.CreateIndexedProperty((object)_value, name, indexParameterType); + } + + [Pure] + string ICustomPropertyProvider.GetStringRepresentation() + { + // _value should not be null + return ((object)_value).ToString(); + } + + Type ICustomPropertyProvider.Type + { + [Pure] + get + { + // _value should not be null + return ((object)_value).GetType(); + } + } + + // We have T in an IReference<T>. Need to QI for IReference<T> with the appropriate GUID, call + // the get_Value property, allocate an appropriately-sized managed object, marshal the native object + // to the managed object, and free the native method. Also we want the return value boxed (aka normal value type boxing). + // + // This method is called by VM. Mark the method with FriendAccessAllowed attribute to ensure that the unreferenced method + // optimization skips it and the code will be saved into NGen image. + [System.Runtime.CompilerServices.FriendAccessAllowed] + internal static Object UnboxHelper(Object wrapper) + { + Contract.Requires(wrapper != null); + IReference<T> reference = (IReference<T>) wrapper; + Contract.Assert(reference != null, "CLRIReferenceImpl::UnboxHelper - QI'ed for IReference<"+typeof(T)+">, but that failed."); + return reference.Value; + } + } + + // T can be any WinRT-compatible type + internal sealed class CLRIReferenceArrayImpl<T> : CLRIPropertyValueImpl, + IReferenceArray<T>, + ICustomPropertyProvider, + IList // Jupiter data binding needs IList/IEnumerable + { + private T[] _value; + private IList _list; + + public CLRIReferenceArrayImpl(PropertyType type, T[] obj) + : base(type, obj) + { + BCLDebug.Assert(obj != null, "Must not be null"); + + _value = obj; + + _list = (IList) _value; + } + + public T[] Value { + get { return _value; } + } + + public override string ToString() + { + if (_value != null) + { + return _value.ToString(); + } + else + { + return base.ToString(); + } + } + + [Pure] + ICustomProperty ICustomPropertyProvider.GetCustomProperty(string name) + { + // _value should not be null + return ICustomPropertyProviderImpl.CreateProperty((object)_value, name); + } + + [Pure] + ICustomProperty ICustomPropertyProvider.GetIndexedProperty(string name, Type indexParameterType) + { + // _value should not be null + return ICustomPropertyProviderImpl.CreateIndexedProperty((object)_value, name, indexParameterType); + } + + [Pure] + string ICustomPropertyProvider.GetStringRepresentation() + { + // _value should not be null + return ((object)_value).ToString(); + } + + Type ICustomPropertyProvider.Type + { + [Pure] + get + { + // _value should not be null + return ((object)_value).GetType(); + } + } + + // + // IEnumerable methods. Used by data-binding in Jupiter when you try to data bind + // against a managed array + // + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)_value).GetEnumerator(); + } + + // + // IList & ICollection methods. + // This enables two-way data binding and index access in Jupiter + // + Object IList.this[int index] { + get + { + return _list[index]; + } + + set + { + _list[index] = value; + } + } + + int IList.Add(Object value) + { + return _list.Add(value); + } + + bool IList.Contains(Object value) + { + return _list.Contains(value); + } + + void IList.Clear() + { + _list.Clear(); + } + + bool IList.IsReadOnly + { + get + { + return _list.IsReadOnly; + } + } + + bool IList.IsFixedSize + { + get + { + return _list.IsFixedSize; + } + } + + int IList.IndexOf(Object value) + { + return _list.IndexOf(value); + } + + void IList.Insert(int index, Object value) + { + _list.Insert(index, value); + } + + void IList.Remove(Object value) + { + _list.Remove(value); + } + + void IList.RemoveAt(int index) + { + _list.RemoveAt(index); + } + + void ICollection.CopyTo(Array array, int index) + { + _list.CopyTo(array, index); + } + + int ICollection.Count + { + get + { + return _list.Count; + } + } + + Object ICollection.SyncRoot + { + get + { + return _list.SyncRoot; + } + } + + bool ICollection.IsSynchronized + { + get + { + return _list.IsSynchronized; + } + } + + // We have T in an IReferenceArray<T>. Need to QI for IReferenceArray<T> with the appropriate GUID, call + // the get_Value property, allocate an appropriately-sized managed object, marshal the native object + // to the managed object, and free the native method. + // + // This method is called by VM. Mark the method with FriendAccessAllowed attribute to ensure that the unreferenced method + // optimization skips it and the code will be saved into NGen image. + [System.Runtime.CompilerServices.FriendAccessAllowed] + internal static Object UnboxHelper(Object wrapper) + { + Contract.Requires(wrapper != null); + IReferenceArray<T> reference = (IReferenceArray<T>)wrapper; + Contract.Assert(reference != null, "CLRIReferenceArrayImpl::UnboxHelper - QI'ed for IReferenceArray<" + typeof(T) + ">, but that failed."); + T[] marshaled = reference.Value; + return marshaled; + } + } + + // For creating instances of Windows Runtime's IReference<T> and IReferenceArray<T>. + internal static class IReferenceFactory + { + internal static readonly Type s_pointType = Type.GetType("Windows.Foundation.Point, " + AssemblyRef.SystemRuntimeWindowsRuntime); + internal static readonly Type s_rectType = Type.GetType("Windows.Foundation.Rect, " + AssemblyRef.SystemRuntimeWindowsRuntime); + internal static readonly Type s_sizeType = Type.GetType("Windows.Foundation.Size, " + AssemblyRef.SystemRuntimeWindowsRuntime); + + [SecuritySafeCritical] + internal static Object CreateIReference(Object obj) + { + Contract.Requires(obj != null, "Null should not be boxed."); + Contract.Ensures(Contract.Result<Object>() != null); + + Type type = obj.GetType(); + + if (type.IsArray) + return CreateIReferenceArray((Array) obj); + + if (type == typeof(int)) + return new CLRIReferenceImpl<int>(PropertyType.Int32, (int)obj); + if (type == typeof(String)) + return new CLRIReferenceImpl<String>(PropertyType.String, (String)obj); + if (type == typeof(byte)) + return new CLRIReferenceImpl<byte>(PropertyType.UInt8, (byte)obj); + if (type == typeof(short)) + return new CLRIReferenceImpl<short>(PropertyType.Int16, (short)obj); + if (type == typeof(ushort)) + return new CLRIReferenceImpl<ushort>(PropertyType.UInt16, (ushort)obj); + if (type == typeof(uint)) + return new CLRIReferenceImpl<uint>(PropertyType.UInt32, (uint)obj); + if (type == typeof(long)) + return new CLRIReferenceImpl<long>(PropertyType.Int64, (long)obj); + if (type == typeof(ulong)) + return new CLRIReferenceImpl<ulong>(PropertyType.UInt64, (ulong)obj); + if (type == typeof(float)) + return new CLRIReferenceImpl<float>(PropertyType.Single, (float)obj); + if (type == typeof(double)) + return new CLRIReferenceImpl<double>(PropertyType.Double, (double)obj); + if (type == typeof(char)) + return new CLRIReferenceImpl<char>(PropertyType.Char16, (char)obj); + if (type == typeof(bool)) + return new CLRIReferenceImpl<bool>(PropertyType.Boolean, (bool)obj); + if (type == typeof(Guid)) + return new CLRIReferenceImpl<Guid>(PropertyType.Guid, (Guid)obj); + if (type == typeof(DateTimeOffset)) + return new CLRIReferenceImpl<DateTimeOffset>(PropertyType.DateTime, (DateTimeOffset)obj); + if (type == typeof(TimeSpan)) + return new CLRIReferenceImpl<TimeSpan>(PropertyType.TimeSpan, (TimeSpan)obj); + if (type == typeof(Object)) + return new CLRIReferenceImpl<Object>(PropertyType.Inspectable, (Object)obj); + if (type == typeof(RuntimeType)) + { // If the type is System.RuntimeType, we want to use System.Type marshaler (it's parent of the type) + return new CLRIReferenceImpl<Type>(PropertyType.Other, (Type)obj); + } + + // Handle arbitrary WinRT-compatible value types, and recognize a few special types. + PropertyType? propType = null; + if (type == s_pointType) + { + propType = PropertyType.Point; + } + else if (type == s_rectType) + { + propType = PropertyType.Rect; + } + else if (type == s_sizeType) + { + propType = PropertyType.Size; + } + else if (type.IsValueType || obj is Delegate) + { + propType = PropertyType.Other; + } + + if (propType.HasValue) + { + Type specificType = typeof(CLRIReferenceImpl<>).MakeGenericType(type); + return Activator.CreateInstance(specificType, new Object[] { propType.Value, obj }); + } + + Contract.Assert(false, "We should not see non-WinRT type here"); + return null; + } + + [SecuritySafeCritical] + internal static Object CreateIReferenceArray(Array obj) + { + Contract.Requires(obj != null); + Contract.Requires(obj.GetType().IsArray); + Contract.Ensures(Contract.Result<Object>() != null); + + Type type = obj.GetType().GetElementType(); + + Contract.Assert(obj.Rank == 1 && obj.GetLowerBound(0) == 0 && !type.IsArray); + + if (type == typeof(int)) + return new CLRIReferenceArrayImpl<int>(PropertyType.Int32Array, (int[])obj); + if (type == typeof(String)) + return new CLRIReferenceArrayImpl<String>(PropertyType.StringArray, (String[])obj); + if (type == typeof(byte)) + return new CLRIReferenceArrayImpl<byte>(PropertyType.UInt8Array, (byte[])obj); + if (type == typeof(short)) + return new CLRIReferenceArrayImpl<short>(PropertyType.Int16Array, (short[])obj); + if (type == typeof(ushort)) + return new CLRIReferenceArrayImpl<ushort>(PropertyType.UInt16Array, (ushort[])obj); + if (type == typeof(uint)) + return new CLRIReferenceArrayImpl<uint>(PropertyType.UInt32Array, (uint[])obj); + if (type == typeof(long)) + return new CLRIReferenceArrayImpl<long>(PropertyType.Int64Array, (long[])obj); + if (type == typeof(ulong)) + return new CLRIReferenceArrayImpl<ulong>(PropertyType.UInt64Array, (ulong[])obj); + if (type == typeof(float)) + return new CLRIReferenceArrayImpl<float>(PropertyType.SingleArray, (float[])obj); + if (type == typeof(double)) + return new CLRIReferenceArrayImpl<double>(PropertyType.DoubleArray, (double[])obj); + if (type == typeof(char)) + return new CLRIReferenceArrayImpl<char>(PropertyType.Char16Array, (char[])obj); + if (type == typeof(bool)) + return new CLRIReferenceArrayImpl<bool>(PropertyType.BooleanArray, (bool[])obj); + if (type == typeof(Guid)) + return new CLRIReferenceArrayImpl<Guid>(PropertyType.GuidArray, (Guid[])obj); + if (type == typeof(DateTimeOffset)) + return new CLRIReferenceArrayImpl<DateTimeOffset>(PropertyType.DateTimeArray, (DateTimeOffset[])obj); + if (type == typeof(TimeSpan)) + return new CLRIReferenceArrayImpl<TimeSpan>(PropertyType.TimeSpanArray, (TimeSpan[])obj); + if (type == typeof(Type)) + { // Note: The array type will be System.Type, not System.RuntimeType + return new CLRIReferenceArrayImpl<Type>(PropertyType.OtherArray, (Type[])obj); + } + + PropertyType? propType = null; + if (type == s_pointType) + { + propType = PropertyType.PointArray; + } + else if (type == s_rectType) + { + propType = PropertyType.RectArray; + } + else if (type == s_sizeType) + { + propType = PropertyType.SizeArray; + } + else if (type.IsValueType) + { + // note that KeyValuePair`2 is a reference type on the WinRT side so the array + // must be wrapped with CLRIReferenceArrayImpl<Object> + if (type.IsGenericType && + type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.KeyValuePair<,>)) + { + Object[] objArray = new Object[obj.Length]; + for (int i = 0; i < objArray.Length; i++) + { + objArray[i] = obj.GetValue(i); + } + obj = objArray; + } + else + { + propType = PropertyType.OtherArray; + } + } + else if (typeof(Delegate).IsAssignableFrom(type)) + { + propType = PropertyType.OtherArray; + } + + + if (propType.HasValue) + { + // All WinRT value type will be Property.Other + Type specificType = typeof(CLRIReferenceArrayImpl<>).MakeGenericType(type); + return Activator.CreateInstance(specificType, new Object[] { propType.Value, obj }); + } + else + { + // All WinRT reference type (including arbitary managed type) will be PropertyType.ObjectArray + return new CLRIReferenceArrayImpl<Object>(PropertyType.InspectableArray, (Object[])obj); + } + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs new file mode 100644 index 0000000000..a23d484a6f --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs @@ -0,0 +1,287 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; + + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + /// <summary> + /// This is a constant map aimed to efficiently support a Split operation (map decomposition). + /// A Split operation returns two non-overlapping, non-empty views of the existing map (or both + /// values are set to NULL). The two views returned should contain roughly the same number of elements. + /// This map is backed by a sorted array. Thus, split operations are O(1) and enumerations are fast; + /// however, look-up in the map are O(log n). + /// </summary> + /// <typeparam name="TKey">Type of objects that act as keys.</typeparam> + /// <typeparam name="TValue">Type of objects that act as entries / values.</typeparam> + [Serializable] + [DebuggerDisplay("Count = {Count}")] + internal sealed class ConstantSplittableMap<TKey, TValue> : IMapView<TKey, TValue> + { + private class KeyValuePairComparator : IComparer<KeyValuePair<TKey, TValue>> + { + private static readonly IComparer<TKey> keyComparator = Comparer<TKey>.Default; + + public Int32 Compare(KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y) + { + return keyComparator.Compare(x.Key, y.Key); + } + } // private class KeyValuePairComparator + + + private static readonly KeyValuePairComparator keyValuePairComparator = new KeyValuePairComparator(); + + private readonly KeyValuePair<TKey, TValue>[] items; + private readonly int firstItemIndex; + private readonly int lastItemIndex; + + internal ConstantSplittableMap(IReadOnlyDictionary<TKey, TValue> data) + { + if (data == null) + throw new ArgumentNullException("data"); + Contract.EndContractBlock(); + + this.firstItemIndex = 0; + this.lastItemIndex = data.Count - 1; + this.items = CreateKeyValueArray(data.Count, data.GetEnumerator()); + } + + internal ConstantSplittableMap(IMapView<TKey, TValue> data) + { + if (data == null) + throw new ArgumentNullException("data"); + + if (((UInt32)Int32.MaxValue) < data.Size) + { + Exception e = new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingDictionaryTooLarge")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + + int size = (int)data.Size; + + this.firstItemIndex = 0; + this.lastItemIndex = size - 1; + this.items = CreateKeyValueArray(size, data.GetEnumerator()); + } + + + private ConstantSplittableMap(KeyValuePair<TKey, TValue>[] items, Int32 firstItemIndex, Int32 lastItemIndex) + { + this.items = items; + this.firstItemIndex = firstItemIndex; + this.lastItemIndex = lastItemIndex; + } + + + private KeyValuePair<TKey, TValue>[] CreateKeyValueArray(Int32 count, IEnumerator<KeyValuePair<TKey, TValue>> data) + { + KeyValuePair<TKey, TValue>[] kvArray = new KeyValuePair<TKey, TValue>[count]; + + Int32 i = 0; + while (data.MoveNext()) + kvArray[i++] = data.Current; + + Array.Sort(kvArray, keyValuePairComparator); + + return kvArray; + } + + private KeyValuePair<TKey, TValue>[] CreateKeyValueArray(Int32 count, IEnumerator<IKeyValuePair<TKey, TValue>> data) + { + KeyValuePair<TKey, TValue>[] kvArray = new KeyValuePair<TKey, TValue>[count]; + + Int32 i = 0; + while (data.MoveNext()) + { + IKeyValuePair<TKey, TValue> current = data.Current; + kvArray[i++] = new KeyValuePair<TKey, TValue>(current.Key, current.Value); + } + + Array.Sort(kvArray, keyValuePairComparator); + + return kvArray; + } + + + public int Count { + get { + return lastItemIndex - firstItemIndex + 1; + } + } + + + // [CLSCompliant(false)] + public UInt32 Size { + get { + return (UInt32)(lastItemIndex - firstItemIndex + 1); + } + } + + + public TValue Lookup(TKey key) + { + TValue value; + bool found = TryGetValue(key, out value); + + if (!found) + { + Exception e = new KeyNotFoundException(Environment.GetResourceString("Arg_KeyNotFound")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + + return value; + } + + + public bool HasKey(TKey key) + { + TValue value; + bool hasKey = TryGetValue(key, out value); + return hasKey; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable<IKeyValuePair<TKey, TValue>>)this).GetEnumerator(); + } + + public IIterator<IKeyValuePair<TKey, TValue>> First() + { + return new EnumeratorToIteratorAdapter<IKeyValuePair<TKey, TValue>>(GetEnumerator()); + } + + public IEnumerator<IKeyValuePair<TKey, TValue>> GetEnumerator() + { + return new IKeyValuePairEnumerator(items, firstItemIndex, lastItemIndex); + } + + public void Split(out IMapView<TKey, TValue> firstPartition, out IMapView<TKey, TValue> secondPartition) + { + if (Count < 2) + { + firstPartition = null; + secondPartition = null; + return; + } + + int pivot = (Int32)(((Int64)firstItemIndex + (Int64)lastItemIndex) / (Int64)2); + + firstPartition = new ConstantSplittableMap<TKey, TValue>(items, firstItemIndex, pivot); + secondPartition = new ConstantSplittableMap<TKey, TValue>(items, pivot + 1, lastItemIndex); + } + + #region IReadOnlyDictionary members + + public bool ContainsKey(TKey key) + { + KeyValuePair<TKey, TValue> searchKey = new KeyValuePair<TKey, TValue>(key, default(TValue)); + int index = Array.BinarySearch(items, firstItemIndex, Count, searchKey, keyValuePairComparator); + return index >= 0; + } + + public bool TryGetValue(TKey key, out TValue value) + { + KeyValuePair<TKey, TValue> searchKey = new KeyValuePair<TKey, TValue>(key, default(TValue)); + int index = Array.BinarySearch(items, firstItemIndex, Count, searchKey, keyValuePairComparator); + + if (index < 0) + { + value = default(TValue); + return false; + } + + value = items[index].Value; + return true; + } + + public TValue this[TKey key] { + get { + return Lookup(key); + } + } + + public IEnumerable<TKey> Keys { + get { + throw new NotImplementedException("NYI"); + } + } + + public IEnumerable<TValue> Values { + get { + throw new NotImplementedException("NYI"); + } + } + + #endregion IReadOnlyDictionary members + + #region IKeyValuePair Enumerator + + [Serializable] + internal struct IKeyValuePairEnumerator : IEnumerator<IKeyValuePair<TKey, TValue>> + { + private KeyValuePair<TKey, TValue>[] _array; + private int _start; + private int _end; + private int _current; + + internal IKeyValuePairEnumerator(KeyValuePair<TKey, TValue>[] items, int first, int end) + { + Contract.Requires(items != null); + Contract.Requires(first >= 0); + Contract.Requires(end >= 0); + Contract.Requires(first < items.Length); + Contract.Requires(end < items.Length); + + _array = items; + _start = first; + _end = end; + _current = _start - 1; + } + + public bool MoveNext() + { + if (_current < _end) + { + _current++; + return true; + } + return false; + } + + public IKeyValuePair<TKey, TValue> Current { + get { + if (_current < _start) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); + if (_current > _end) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded)); + return new CLRIKeyValuePairImpl<TKey, TValue>(ref _array[_current]); + } + } + + Object IEnumerator.Current { + get { + return Current; + } + } + + void IEnumerator.Reset() + { + _current = _start - 1; + } + + public void Dispose() + { + } + } + + #endregion IKeyValuePair Enumerator + + } // internal ConstantSplittableMap<TKey, TValue> + +} // namespace System.Runtime.InteropServices.WindowsRuntime diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CustomPropertyImpl.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CustomPropertyImpl.cs new file mode 100644 index 0000000000..01a6bc81de --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CustomPropertyImpl.cs @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Reflection; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; +using System.StubHelpers; +using System.Globalization; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // + // ICustomProperty implementation - basically a wrapper of PropertyInfo + // + internal sealed class CustomPropertyImpl : ICustomProperty + { + private PropertyInfo m_property; + + // + // Constructor + // + public CustomPropertyImpl(PropertyInfo propertyInfo) + { + if (propertyInfo == null) + throw new ArgumentNullException("propertyInfo"); + + m_property = propertyInfo; + } + + // + // ICustomProperty interface implementation + // + + public string Name + { + get + { + return m_property.Name; + } + } + + public bool CanRead + { + get + { + // Return false if the getter is not public + return m_property.GetGetMethod() != null; + } + } + + public bool CanWrite + { + get + { + // Return false if the setter is not public + return m_property.GetSetMethod() != null; + } + } + + public object GetValue(object target) + { + return InvokeInternal(target, null, true); + } + + // Unlike normal .Net, Jupiter properties can have at most one indexer parameter. A null + // indexValue here means that the property has an indexer argument and its value is null. + public object GetValue(object target, object indexValue) + { + return InvokeInternal(target, new object[] { indexValue }, true); + } + + public void SetValue(object target, object value) + { + InvokeInternal(target, new object[] { value }, false); + } + + // Unlike normal .Net, Jupiter properties can have at most one indexer parameter. A null + // indexValue here means that the property has an indexer argument and its value is null. + public void SetValue(object target, object value, object indexValue) + { + InvokeInternal(target, new object[] { indexValue, value }, false); + } + + [SecuritySafeCritical] + private object InvokeInternal(object target, object[] args, bool getValue) + { + // Forward to the right object if we are dealing with a proxy + IGetProxyTarget proxy = target as IGetProxyTarget; + if (proxy != null) + { + target = proxy.GetTarget(); + } + + // You can get PropertyInfo for properties with a private getter/public setter (or vice versa) + // even if you pass BindingFlags.Public only. And in this case, passing binding flags to + // GetValue/SetValue won't work as the default binder ignores those values + // Use GetGetMethod/GetSetMethod instead + + // We get non-public accessors just so that we can throw the correct exception. + MethodInfo accessor = getValue ? m_property.GetGetMethod(true) : m_property.GetSetMethod(true); + + if (accessor == null) + throw new ArgumentException(System.Environment.GetResourceString(getValue ? "Arg_GetMethNotFnd" : "Arg_SetMethNotFnd")); + + if (!accessor.IsPublic) + throw new MethodAccessException( + String.Format( + CultureInfo.CurrentCulture, + Environment.GetResourceString("Arg_MethodAccessException_WithMethodName"), + accessor.ToString(), + accessor.DeclaringType.FullName)); + + RuntimeMethodInfo rtMethod = accessor as RuntimeMethodInfo; + if (rtMethod == null) + throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo")); + + // We can safely skip access check because this is only used in full trust scenarios. + // And we have already verified that the property accessor is public. + Contract.Assert(AppDomain.CurrentDomain.PermissionSet.IsUnrestricted()); + return rtMethod.UnsafeInvoke(target, BindingFlags.Default, null, args, null); + } + + public Type Type + { + get + { + return m_property.PropertyType; + } + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryKeyCollection.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryKeyCollection.cs new file mode 100644 index 0000000000..6c56c10c46 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryKeyCollection.cs @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [Serializable] + [DebuggerDisplay("Count = {Count}")] + internal sealed class DictionaryKeyCollection<TKey, TValue> : ICollection<TKey> + { + private readonly IDictionary<TKey, TValue> dictionary; + + public DictionaryKeyCollection(IDictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + throw new ArgumentNullException("dictionary"); + + this.dictionary = dictionary; + } + + public void CopyTo(TKey[] array, int index) + { + if (array == null) + throw new ArgumentNullException("array"); + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + if (array.Length <= index && this.Count > 0) + throw new ArgumentException(Environment.GetResourceString("Arg_IndexOutOfRangeException")); + if (array.Length - index < dictionary.Count) + throw new ArgumentException(Environment.GetResourceString("Argument_InsufficientSpaceToCopyCollection")); + + int i = index; + foreach (KeyValuePair<TKey, TValue> mapping in dictionary) + { + array[i++] = mapping.Key; + } + } + + public int Count { + get { return dictionary.Count; } + } + + bool ICollection<TKey>.IsReadOnly { + get { return true; } + } + + void ICollection<TKey>.Add(TKey item) + { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_KeyCollectionSet")); + } + + void ICollection<TKey>.Clear() + { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_KeyCollectionSet")); + } + + public bool Contains(TKey item) + { + return dictionary.ContainsKey(item); + } + + bool ICollection<TKey>.Remove(TKey item) + { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_KeyCollectionSet")); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable<TKey>)this).GetEnumerator(); + } + + public IEnumerator<TKey> GetEnumerator() + { + return new DictionaryKeyEnumerator<TKey, TValue>(dictionary); + } + } // public class DictionaryKeyCollection<TKey, TValue> + + + [Serializable] + internal sealed class DictionaryKeyEnumerator<TKey, TValue> : IEnumerator<TKey> + { + private readonly IDictionary<TKey, TValue> dictionary; + private IEnumerator<KeyValuePair<TKey, TValue>> enumeration; + + public DictionaryKeyEnumerator(IDictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + throw new ArgumentNullException("dictionary"); + + this.dictionary = dictionary; + this.enumeration = dictionary.GetEnumerator(); + } + + void IDisposable.Dispose() + { + enumeration.Dispose(); + } + + public bool MoveNext() + { + return enumeration.MoveNext(); + } + + Object IEnumerator.Current { + get { return ((IEnumerator<TKey>)this).Current; } + } + + public TKey Current { + get { return enumeration.Current.Key; } + } + + public void Reset() + { + enumeration = dictionary.GetEnumerator(); + } + } // class DictionaryKeyEnumerator<TKey, TValue> +} + +// DictionaryKeyCollection.cs diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs new file mode 100644 index 0000000000..1dcdeadcc3 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IMap`2 interface on managed + // objects that implement IDictionary`2. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not DictionaryToMapAdapter objects. Rather, they are of type + // IDictionary<K, V>. No actual DictionaryToMapAdapter object is ever instantiated. Thus, you will + // see a lot of expressions that cast "this" to "IDictionary<K, V>". + internal sealed class DictionaryToMapAdapter + { + private DictionaryToMapAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // V Lookup(K key) + [SecurityCritical] + internal V Lookup<K, V>(K key) + { + IDictionary<K, V> _this = JitHelpers.UnsafeCast<IDictionary<K, V>>(this); + V value; + bool keyFound = _this.TryGetValue(key, out value); + + if (!keyFound) + { + Exception e = new KeyNotFoundException(Environment.GetResourceString("Arg_KeyNotFound")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + + return value; + } + + // uint Size { get } + [SecurityCritical] + internal uint Size<K, V>() + { + IDictionary<K, V> _this = JitHelpers.UnsafeCast<IDictionary<K, V>>(this); + return (uint)_this.Count; + } + + // bool HasKey(K key) + [SecurityCritical] + internal bool HasKey<K, V>(K key) + { + IDictionary<K, V> _this = JitHelpers.UnsafeCast<IDictionary<K, V>>(this); + return _this.ContainsKey(key); + } + + // IMapView<K, V> GetView() + [SecurityCritical] + internal IReadOnlyDictionary<K, V> GetView<K, V>() + { + IDictionary<K, V> _this = JitHelpers.UnsafeCast<IDictionary<K, V>>(this); + Contract.Assert(_this != null); + + // Note: This dictionary is not really read-only - you could QI for a modifiable + // dictionary. We gain some perf by doing this. We believe this is acceptable. + IReadOnlyDictionary<K, V> roDictionary = _this as IReadOnlyDictionary<K, V>; + if (roDictionary == null) + { + roDictionary = new ReadOnlyDictionary<K, V>(_this); + } + return roDictionary; + } + + // bool Insert(K key, V value) + [SecurityCritical] + internal bool Insert<K, V>(K key, V value) + { + IDictionary<K, V> _this = JitHelpers.UnsafeCast<IDictionary<K, V>>(this); + bool replacing = _this.ContainsKey(key); + _this[key] = value; + return replacing; + } + + // void Remove(K key) + [SecurityCritical] + internal void Remove<K, V>(K key) + { + IDictionary<K, V> _this = JitHelpers.UnsafeCast<IDictionary<K, V>>(this); + bool removed = _this.Remove(key); + + if (!removed) + { + Exception e = new KeyNotFoundException(Environment.GetResourceString("Arg_KeyNotFound")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + } + + // void Clear() + [SecurityCritical] + internal void Clear<K, V>() + { + IDictionary<K, V> _this = JitHelpers.UnsafeCast<IDictionary<K, V>>(this); + _this.Clear(); + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryValueCollection.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryValueCollection.cs new file mode 100644 index 0000000000..f8e4ea555b --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryValueCollection.cs @@ -0,0 +1,130 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.WindowsRuntime; + + +namespace System.Runtime.InteropServices.WindowsRuntime { + [Serializable] + [DebuggerDisplay("Count = {Count}")] + internal sealed class DictionaryValueCollection<TKey, TValue> : ICollection<TValue> + { + private readonly IDictionary<TKey, TValue> dictionary; + + public DictionaryValueCollection(IDictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + throw new ArgumentNullException("dictionary"); + + this.dictionary = dictionary; + } + + public void CopyTo(TValue[] array, int index) + { + if (array == null) + throw new ArgumentNullException("array"); + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + if (array.Length <= index && this.Count > 0) + throw new ArgumentException(Environment.GetResourceString("Arg_IndexOutOfRangeException")); + if (array.Length - index < dictionary.Count) + throw new ArgumentException(Environment.GetResourceString("Argument_InsufficientSpaceToCopyCollection")); + + int i = index; + foreach (KeyValuePair<TKey, TValue> mapping in dictionary) + { + array[i++] = mapping.Value; + } + } + + public int Count { + get { return dictionary.Count; } + } + + bool ICollection<TValue>.IsReadOnly { + get { return true; } + } + + void ICollection<TValue>.Add(TValue item) + { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_ValueCollectionSet")); + } + + void ICollection<TValue>.Clear() + { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_ValueCollectionSet")); + } + + public bool Contains(TValue item) + { + EqualityComparer<TValue> comparer = EqualityComparer<TValue>.Default; + foreach (TValue value in this) + if (comparer.Equals(item, value)) + return true; + return false; + } + + bool ICollection<TValue>.Remove(TValue item) + { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_ValueCollectionSet")); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable<TValue>)this).GetEnumerator(); + } + + public IEnumerator<TValue> GetEnumerator() + { + return new DictionaryValueEnumerator<TKey, TValue>(dictionary); + } + } // public class DictionaryValueCollection<TKey, TValue> + + + [Serializable] + internal sealed class DictionaryValueEnumerator<TKey, TValue> : IEnumerator<TValue> + { + private readonly IDictionary<TKey, TValue> dictionary; + private IEnumerator<KeyValuePair<TKey, TValue>> enumeration; + + public DictionaryValueEnumerator(IDictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + throw new ArgumentNullException("dictionary"); + + this.dictionary = dictionary; + this.enumeration = dictionary.GetEnumerator(); + } + + void IDisposable.Dispose() + { + enumeration.Dispose(); + } + + public bool MoveNext() + { + return enumeration.MoveNext(); + } + + Object IEnumerator.Current { + get { return ((IEnumerator<TValue>)this).Current; } + } + + public TValue Current { + get { return enumeration.Current.Value; } + } + + public void Reset() + { + enumeration = dictionary.GetEnumerator(); + } + } // class DictionaryValueEnumerator<TKey, TValue> +} + +// DictionaryValueCollection.cs diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EnumeratorToIteratorAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EnumeratorToIteratorAdapter.cs new file mode 100644 index 0000000000..9c203bcefa --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EnumeratorToIteratorAdapter.cs @@ -0,0 +1,167 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IIterable`1 interface on managed + // objects that implement IEnumerable`1. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not EnumerableToIterableAdapter objects. Rather, they are of type + // IEnumerable<T>. No actual EnumerableToIterableAdapter object is ever instantiated. Thus, you will + // see a lot of expressions that cast "this" to "IEnumerable<T>". + internal sealed class EnumerableToIterableAdapter + { + private EnumerableToIterableAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // This method is invoked when First is called on a managed implementation of IIterable<T>. + [System.Security.SecurityCritical] + internal IIterator<T> First_Stub<T>() + { + IEnumerable<T> _this = JitHelpers.UnsafeCast<IEnumerable<T>>(this); + return new EnumeratorToIteratorAdapter<T>(_this.GetEnumerator()); + } + } + + internal sealed class EnumerableToBindableIterableAdapter + { + private EnumerableToBindableIterableAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + internal sealed class NonGenericToGenericEnumerator : IEnumerator<object> + { + private IEnumerator enumerator; + + public NonGenericToGenericEnumerator(IEnumerator enumerator) + { this.enumerator = enumerator; } + + public object Current { get { return enumerator.Current; } } + public bool MoveNext() { return enumerator.MoveNext(); } + public void Reset() { enumerator.Reset(); } + public void Dispose() { } + } + + // This method is invoked when First is called on a managed implementation of IBindableIterable. + [System.Security.SecurityCritical] + internal IBindableIterator First_Stub() + { + IEnumerable _this = JitHelpers.UnsafeCast<IEnumerable>(this); + return new EnumeratorToIteratorAdapter<object>(new NonGenericToGenericEnumerator(_this.GetEnumerator()) ); + } + } + + // Adapter class which holds a managed IEnumerator<T>, exposing it as a Windows Runtime IIterator<T> + internal sealed class EnumeratorToIteratorAdapter<T> : IIterator<T>, IBindableIterator + { + private IEnumerator<T> m_enumerator; + private bool m_firstItem = true; + private bool m_hasCurrent; + + internal EnumeratorToIteratorAdapter(IEnumerator<T> enumerator) + { + Contract.Requires(enumerator != null); + m_enumerator = enumerator; + } + + public T Current + { + get + { + // IEnumerator starts at item -1, while IIterators start at item 0. Therefore, if this is the + // first access to the iterator we need to advance to the first item. + if (m_firstItem) + { + m_firstItem = false; + MoveNext(); + } + + if (!m_hasCurrent) + { + throw WindowsRuntimeMarshal.GetExceptionForHR(__HResults.E_BOUNDS, null); + } + + return m_enumerator.Current; + } + } + + object IBindableIterator.Current + { + get + { + return (object)((IIterator<T>)this).Current; + } + } + + public bool HasCurrent + { + get + { + // IEnumerator starts at item -1, while IIterators start at item 0. Therefore, if this is the + // first access to the iterator we need to advance to the first item. + if (m_firstItem) + { + m_firstItem = false; + MoveNext(); + } + + return m_hasCurrent; + } + } + + public bool MoveNext() + { + try + { + m_hasCurrent = m_enumerator.MoveNext(); + } + catch (InvalidOperationException e) + { + throw WindowsRuntimeMarshal.GetExceptionForHR(__HResults.E_CHANGED_STATE, e); + } + + return m_hasCurrent; + } + + public int GetMany(T[] items) + { + if (items == null) + { + return 0; + } + + int index = 0; + while (index < items.Length && HasCurrent) + { + items[index] = Current; + MoveNext(); + ++index; + } + + if (typeof(T) == typeof(string)) + { + string[] stringItems = items as string[]; + + // Fill the rest of the array with String.Empty to avoid marshaling failure + for (int i = index; i < items.Length; ++i) + stringItems[i] = String.Empty; + } + + return index; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationToken.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationToken.cs new file mode 100644 index 0000000000..e9126d122a --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationToken.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // Event registration tokens are 64 bit opaque structures returned from WinRT style event adders, in order + // to signify a registration of a particular delegate to an event. The token's only real use is to + // unregister the same delgate from the event at a later time. + public struct EventRegistrationToken + { + internal ulong m_value; + + internal EventRegistrationToken(ulong value) + { + m_value = value; + } + + internal ulong Value + { + get { return m_value; } + } + + public static bool operator ==(EventRegistrationToken left, EventRegistrationToken right) + { + return left.Equals(right); + } + + public static bool operator !=(EventRegistrationToken left, EventRegistrationToken right) + { + return !left.Equals(right); + } + + public override bool Equals(object obj) + { + if (!(obj is EventRegistrationToken)) + { + return false; + } + + return ((EventRegistrationToken)obj).Value == Value; + } + + public override int GetHashCode() + { + return m_value.GetHashCode(); + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs new file mode 100644 index 0000000000..91b123bee7 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs @@ -0,0 +1,254 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Threading; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // An event registration token table stores mappings from delegates to event tokens, in order to support + // sourcing WinRT style events from managed code. + public sealed class EventRegistrationTokenTable<T> where T : class + { + // Note this dictionary is also used as the synchronization object for this table + private Dictionary<EventRegistrationToken, T> m_tokens = new Dictionary<EventRegistrationToken, T>(); + + // Cached multicast delegate which will invoke all of the currently registered delegates. This + // will be accessed frequently in common coding paterns, so we don't want to calculate it repeatedly. + private volatile T m_invokeList; + + public EventRegistrationTokenTable() + { + // T must be a delegate type, but we cannot constrain on being a delegate. Therefore, we'll do a + // static check at construction time + if (!typeof(Delegate).IsAssignableFrom(typeof(T))) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EventTokenTableRequiresDelegate", typeof(T))); + } + } + + // The InvocationList property provides access to a delegate which will invoke every registered event handler + // in this table. If the property is set, the new value will replace any existing token registrations. + public T InvocationList + { + get + { + return m_invokeList; + } + + set + { + lock (m_tokens) + { + // The value being set replaces any of the existing values + m_tokens.Clear(); + m_invokeList = null; + + if (value != null) + { + AddEventHandlerNoLock(value); + } + } + } + } + + public EventRegistrationToken AddEventHandler(T handler) + { + // Windows Runtime allows null handlers. Assign those a token value of 0 for easy identity + if (handler == null) + { + return new EventRegistrationToken(0); + } + + lock (m_tokens) + { + return AddEventHandlerNoLock(handler); + } + } + + private EventRegistrationToken AddEventHandlerNoLock(T handler) + { + Contract.Requires(handler != null); + + // Get a registration token, making sure that we haven't already used the value. This should be quite + // rare, but in the case it does happen, just keep trying until we find one that's unused. + EventRegistrationToken token = GetPreferredToken(handler); + while (m_tokens.ContainsKey(token)) + { + token = new EventRegistrationToken(token.Value + 1); + } + m_tokens[token] = handler; + + // Update the current invocation list to include the newly added delegate + Delegate invokeList = (Delegate)(object)m_invokeList; + invokeList = MulticastDelegate.Combine(invokeList, (Delegate)(object)handler); + m_invokeList = (T)(object)invokeList; + + return token; + } + + // Get the delegate associated with an event registration token if it exists. Additionally, + // remove the registration from the table at the same time. If the token is not registered, + // Extract returns null and does not modify the table. + [System.Runtime.CompilerServices.FriendAccessAllowed] + internal T ExtractHandler(EventRegistrationToken token) + { + T handler = null; + lock (m_tokens) + { + if (m_tokens.TryGetValue(token, out handler)) + { + RemoveEventHandlerNoLock(token); + } + } + + return handler; + } + + // Generate a token that may be used for a particular event handler. We will frequently be called + // upon to look up a token value given only a delegate to start from. Therefore, we want to make + // an initial token value that is easily determined using only the delegate instance itself. Although + // in the common case this token value will be used to uniquely identify the handler, it is not + // the only possible token that can represent the handler. + // + // This means that both: + // * if there is a handler assigned to the generated initial token value, it is not necessarily + // this handler. + // * if there is no handler assigned to the generated initial token value, the handler may still + // be registered under a different token + // + // Effectively the only reasonable thing to do with this value is either to: + // 1. Use it as a good starting point for generating a token for handler + // 2. Use it as a guess to quickly see if the handler was really assigned this token value + private static EventRegistrationToken GetPreferredToken(T handler) + { + Contract.Requires(handler != null); + + // We want to generate a token value that has the following properties: + // 1. is quickly obtained from the handler instance + // 2. uses bits in the upper 32 bits of the 64 bit value, in order to avoid bugs where code + // may assume the value is realy just 32 bits + // 3. uses bits in the bottom 32 bits of the 64 bit value, in order to ensure that code doesn't + // take a dependency on them always being 0. + // + // The simple algorithm chosen here is to simply assign the upper 32 bits the metadata token of the + // event handler type, and the lower 32 bits the hash code of the handler instance itself. Using the + // metadata token for the upper 32 bits gives us at least a small chance of being able to identify a + // totally corrupted token if we ever come across one in a minidump or other scenario. + // + // The hash code of a unicast delegate is not tied to the method being invoked, so in the case + // of a unicast delegate, the hash code of the target method is used instead of the full delegate + // hash code. + // + // While calculating this initial value will be somewhat more expensive than just using a counter + // for events that have few registrations, it will also gives us a shot at preventing unregistration + // from becoming an O(N) operation. + // + // We should feel free to change this algorithm as other requirements / optimizations become + // available. This implementation is sufficiently random that code cannot simply guess the value to + // take a dependency upon it. (Simply applying the hash-value algorithm directly won't work in the + // case of collisions, where we'll use a different token value). + + uint handlerHashCode = 0; + Delegate[] invocationList = ((Delegate)(object)handler).GetInvocationList(); + if (invocationList.Length == 1) + { + handlerHashCode = (uint)invocationList[0].Method.GetHashCode(); + } + else + { + handlerHashCode = (uint)handler.GetHashCode(); + } + + ulong tokenValue = ((ulong)(uint)typeof(T).MetadataToken << 32) | handlerHashCode; + return new EventRegistrationToken(tokenValue); + } + + public void RemoveEventHandler(EventRegistrationToken token) + { + // The 0 token is assigned to null handlers, so there's nothing to do + if (token.Value == 0) + { + return; + } + + lock (m_tokens) + { + RemoveEventHandlerNoLock(token); + } + } + + public void RemoveEventHandler(T handler) + { + // To match the Windows Runtime behaivor when adding a null handler, removing one is a no-op + if (handler == null) + { + return; + } + + lock (m_tokens) + { + // Fast path - if the delegate is stored with its preferred token, then there's no need to do + // a full search of the table for it. Note that even if we find something stored using the + // preferred token value, it's possible we have a collision and another delegate was using that + // value. Therefore we need to make sure we really have the handler we want before taking the + // fast path. + EventRegistrationToken preferredToken = GetPreferredToken(handler); + T registeredHandler; + if (m_tokens.TryGetValue(preferredToken, out registeredHandler)) + { + if (registeredHandler == handler) + { + RemoveEventHandlerNoLock(preferredToken); + return; + } + } + + // Slow path - we didn't find the delegate with its preferred token, so we need to fall + // back to a search of the table + foreach (KeyValuePair<EventRegistrationToken, T> registration in m_tokens) + { + if (registration.Value == (T)(object)handler) + { + RemoveEventHandlerNoLock(registration.Key); + + // If a delegate has been added multiple times to handle an event, then it + // needs to be removed the same number of times to stop handling the event. + // Stop after the first one we find. + return; + } + } + + // Note that falling off the end of the loop is not an error, as removing a registration + // for a handler that is not currently registered is simply a no-op + } + } + + private void RemoveEventHandlerNoLock(EventRegistrationToken token) + { + T handler; + if (m_tokens.TryGetValue(token, out handler)) + { + m_tokens.Remove(token); + + // Update the current invocation list to remove the delegate + Delegate invokeList = (Delegate)(object)m_invokeList; + invokeList = MulticastDelegate.Remove(invokeList, (Delegate)(object)handler); + m_invokeList = (T)(object)invokeList; + } + } + + public static EventRegistrationTokenTable<T> GetOrCreateEventRegistrationTokenTable(ref EventRegistrationTokenTable<T> refEventTable) + { + if (refEventTable == null) + { + Interlocked.CompareExchange(ref refEventTable, new EventRegistrationTokenTable<T>(), null); + } + return refEventTable; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IActivationFactory.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IActivationFactory.cs new file mode 100644 index 0000000000..85377187d2 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IActivationFactory.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Runtime.InteropServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("00000035-0000-0000-C000-000000000046")] + [WindowsRuntimeImport] + public interface IActivationFactory + { + object ActivateInstance(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IClosable.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IClosable.cs new file mode 100644 index 0000000000..28841fe661 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IClosable.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + + // Local definition of Windows.Foundation.IClosable + [ComImport] + [Guid("30d5a829-7fa4-4026-83bb-d75bae4ea99e")] + [WindowsRuntimeImport] + internal interface IClosable + { + void Close(); + } + + // Adapter class - converts IClosable.Close calls to Disposable.Dispose + internal sealed class IDisposableToIClosableAdapter + { + private IDisposableToIClosableAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + [SecurityCritical] + public void Close() + { + IDisposable _this = JitHelpers.UnsafeCast<IDisposable>(this); + _this.Dispose(); + } + } + + // Adapter class which converts IDisposable.Dispose calls into IClosable.Close + [SecurityCritical] + internal sealed class IClosableToIDisposableAdapter + { + private IClosableToIDisposableAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + [SecurityCritical] + private void Dispose() + { + IClosable _this = JitHelpers.UnsafeCast<IClosable>(this); + _this.Close(); + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ICustomProperty.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ICustomProperty.cs new file mode 100644 index 0000000000..aa7ea5fdb2 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ICustomProperty.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Diagnostics.Contracts; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("30DA92C0-23E8-42A0-AE7C-734A0E5D2782")] + [WindowsRuntimeImport] + internal interface ICustomProperty + { + Type Type + { + [Pure] + get; + } + + string Name + { + [Pure] + get; + } + + [Pure] + object GetValue(object target); + + void SetValue(object target, object value); + + [Pure] + object GetValue(object target, object indexValue); + + void SetValue(object target, object value, object indexValue); + + bool CanWrite + { + [Pure] + get; + } + + bool CanRead + { + [Pure] + get; + } + } +} + diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ICustomPropertyProvider.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ICustomPropertyProvider.cs new file mode 100644 index 0000000000..51c62618c5 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ICustomPropertyProvider.cs @@ -0,0 +1,586 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.StubHelpers; +using System.Reflection; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Security; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("7C925755-3E48-42B4-8677-76372267033F")] + [WindowsRuntimeImport] + internal interface ICustomPropertyProvider + { + [Pure] + ICustomProperty GetCustomProperty(string name); + + [Pure] + ICustomProperty GetIndexedProperty(string name, Type indexParameterType); + + [Pure] + string GetStringRepresentation(); + + Type Type + { + [Pure] + get; + } + } + + // + // Implementation helpers + // + internal static class ICustomPropertyProviderImpl + { + // + // Creates a ICustomProperty implementation for Jupiter + // Called from ICustomPropertyProvider_GetProperty from within runtime + // + static internal ICustomProperty CreateProperty(object target, string propertyName) + { + Contract.Requires(target != null); + Contract.Requires(propertyName != null); + + // Only return public instance/static properties + PropertyInfo propertyInfo = target.GetType().GetProperty( + propertyName, + BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + + if (propertyInfo == null) + return null; + else + return new CustomPropertyImpl(propertyInfo); + } + + // + // Creates a ICustomProperty implementation for Jupiter + // Called from ICustomPropertyProvider_GetIndexedProperty from within runtime + // + [System.Security.SecurityCritical] + static internal unsafe ICustomProperty CreateIndexedProperty(object target, string propertyName, TypeNameNative *pIndexedParamType) + { + Contract.Requires(target != null); + Contract.Requires(propertyName != null); + + Type indexedParamType = null; + SystemTypeMarshaler.ConvertToManaged(pIndexedParamType, ref indexedParamType); + + return CreateIndexedProperty(target, propertyName, indexedParamType); + } + + static internal ICustomProperty CreateIndexedProperty(object target, string propertyName, Type indexedParamType) + { + Contract.Requires(target != null); + Contract.Requires(propertyName != null); + + // Only return public instance/static properties + PropertyInfo propertyInfo = target.GetType().GetProperty( + propertyName, + BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public, + null, // default binder + null, // ignore return type + new Type[] { indexedParamType }, // indexed parameter type + null // ignore type modifier + ); + + if (propertyInfo == null) + return null; + else + return new CustomPropertyImpl(propertyInfo); + } + + [System.Security.SecurityCritical] + static internal unsafe void GetType(object target, TypeNameNative *pIndexedParamType) + { + SystemTypeMarshaler.ConvertToNative(target.GetType(), pIndexedParamType); + } + } + + [Flags] + enum InterfaceForwardingSupport + { + None = 0, + IBindableVector = 0x1, // IBindableVector -> IBindableVector + IVector = 0x2, // IBindableVector -> IVector<T> + IBindableVectorView = 0x4, // IBindableVectorView -> IBindableVectorView + IVectorView = 0x8, // IBindableVectorView -> IVectorView<T> + IBindableIterableOrIIterable= 0x10 // IBindableIterable -> IBindableIterable/IIterable<T> + } + + // + // Interface for data binding code (CustomPropertyImpl) to retreive the target object + // See CustomPropertyImpl.InvokeInternal for details + // + internal interface IGetProxyTarget + { + object GetTarget(); + } + + // + // Proxy that supports data binding on another object + // + // This serves two purposes: + // + // 1. Delegate data binding interfaces to another object + // Note that this proxy implements the native interfaces directly to avoid unnecessary overhead + // (such as the adapter code that addresses behavior differences between IBindableVector & List + // as well as simplify forwarding code (except for IEnumerable) + // + // 2. ICLRServices.CreateManagedReference will hand out ICCW* of a new instance of this object + // and will hold the other object alive + // + // + internal class ICustomPropertyProviderProxy<T1, T2> : IGetProxyTarget, + ICustomPropertyProvider, + ICustomQueryInterface, + IEnumerable, // IBindableIterable -> IBindableIterable/IIterable<T> + IBindableVector, // IBindableVector -> IBindableVector/IVector<T> + IBindableVectorView // IBindableVectorView -> IBindableVectorView/IVectorView<T> + { + private object _target; + private InterfaceForwardingSupport _flags; + + internal ICustomPropertyProviderProxy(object target, InterfaceForwardingSupport flags) + { + _target = target; + _flags = flags; + } + + // + // Creates a new instance of ICustomPropertyProviderProxy<T1, T2> and assign appropriate + // flags + // + internal static object CreateInstance(object target) + { + InterfaceForwardingSupport supportFlags = InterfaceForwardingSupport.None; + + // + // QI and figure out the right flags + // + if (target as IList != null) + supportFlags |= InterfaceForwardingSupport.IBindableVector; + + // NOTE: We need to use the directed type here + // If we use IVector_Raw<T1> here, it derives from a different IIterable<T> which the runtime + // doesn't recognize, and therefore IEnumerable cast won't be able to take advantage of this QI + if (target as IList<T1> != null) + supportFlags |= InterfaceForwardingSupport.IVector; + + if (target as IBindableVectorView != null) + supportFlags |= InterfaceForwardingSupport.IBindableVectorView; + + // NOTE: We need to use the redirected type here + // If we use IVector_Raw<T1> here, it derives from a different IIterable<T> which the runtime + // doesn't recognize, and therefore IEnumerable cast won't be able to take advantage of this QI + if (target as IReadOnlyList<T2> != null) + supportFlags |= InterfaceForwardingSupport.IVectorView; + + // Verify IEnumerable last because the first few QIs might succeed and we need + // IEnumerable cast to use that cache (instead of having ICustomPropertyProvider to + // forward it manually) + // For example, if we try to shoot in the dark by trying IVector<IInspectable> and it + // succeeded, IEnumerable needs to know that + if (target as IEnumerable != null) + supportFlags |= InterfaceForwardingSupport.IBindableIterableOrIIterable; + + return new ICustomPropertyProviderProxy<T1, T2>(target, supportFlags); + } + + // + // ICustomPropertyProvider implementation + // + ICustomProperty ICustomPropertyProvider.GetCustomProperty(string name) + { + return ICustomPropertyProviderImpl.CreateProperty(_target, name); + } + + ICustomProperty ICustomPropertyProvider.GetIndexedProperty(string name, Type indexParameterType) + { + return ICustomPropertyProviderImpl.CreateIndexedProperty(_target, name, indexParameterType); + } + + string ICustomPropertyProvider.GetStringRepresentation() + { + return WindowsRuntime.IStringableHelper.ToString(_target); + } + + Type ICustomPropertyProvider.Type + { + get + { + return _target.GetType(); + } + } + + // + // override ToString() to make sure callers get correct IStringable.ToString() behavior in native code + // + public override string ToString() + { + return WindowsRuntime.IStringableHelper.ToString(_target); + } + + // + // IGetProxyTarget - unwraps the target object and use it for data binding + // + object IGetProxyTarget.GetTarget() + { + return _target; + } + + // + // ICustomQueryInterface methods + // + [System.Security.SecurityCritical] + public CustomQueryInterfaceResult GetInterface([In]ref Guid iid, out IntPtr ppv) + { + ppv = IntPtr.Zero; + + if (iid == typeof(IBindableIterable).GUID) + { + // Reject the QI if target doesn't implement IEnumerable + if ((_flags & (InterfaceForwardingSupport.IBindableIterableOrIIterable)) == 0) + return CustomQueryInterfaceResult.Failed; + } + + if (iid == typeof(IBindableVector).GUID) + { + // Reject the QI if target doesn't implement IBindableVector/IVector + if ((_flags & (InterfaceForwardingSupport.IBindableVector | InterfaceForwardingSupport.IVector)) == 0) + return CustomQueryInterfaceResult.Failed; + } + + if (iid == typeof(IBindableVectorView).GUID) + { + // Reject the QI if target doesn't implement IBindableVectorView/IVectorView + if ((_flags & (InterfaceForwardingSupport.IBindableVectorView | InterfaceForwardingSupport.IVectorView)) == 0) + return CustomQueryInterfaceResult.Failed; + } + + return CustomQueryInterfaceResult.NotHandled; + } + + // + // IEnumerable methods + // + public IEnumerator GetEnumerator() + { + return ((IEnumerable)_target).GetEnumerator(); + } + + // + // IBindableVector implementation (forwards to IBindableVector / IVector<T>) + // + [Pure] + object IBindableVector.GetAt(uint index) + { + IBindableVector bindableVector = GetIBindableVectorNoThrow(); + if (bindableVector != null) + { + // IBindableVector -> IBindableVector + return bindableVector.GetAt(index); + } + else + { + // IBindableVector -> IVector<T> + return GetVectorOfT().GetAt(index); + } + } + + [Pure] + uint IBindableVector.Size + { + get + { + IBindableVector bindableVector = GetIBindableVectorNoThrow(); + if (bindableVector != null) + { + // IBindableVector -> IBindableVector + return bindableVector.Size; + } + else + { + // IBindableVector -> IVector<T> + return GetVectorOfT().Size; + } + } + } + + [Pure] + IBindableVectorView IBindableVector.GetView() + { + IBindableVector bindableVector = GetIBindableVectorNoThrow(); + if (bindableVector != null) + { + // IBindableVector -> IBindableVector + return bindableVector.GetView(); + } + else + { + // IBindableVector -> IVector<T> + return new IVectorViewToIBindableVectorViewAdapter<T1>(GetVectorOfT().GetView()); + } + } + + private sealed class IVectorViewToIBindableVectorViewAdapter<T> : IBindableVectorView + { + private IVectorView<T> _vectorView; + + public IVectorViewToIBindableVectorViewAdapter(IVectorView<T> vectorView) + { + this._vectorView = vectorView; + } + + [Pure] + object IBindableVectorView.GetAt(uint index) + { + return _vectorView.GetAt(index); + } + + [Pure] + uint IBindableVectorView.Size + { + get + { + return _vectorView.Size; + } + } + + [Pure] + bool IBindableVectorView.IndexOf(object value, out uint index) + { + return _vectorView.IndexOf(ConvertTo<T>(value), out index); + } + + IBindableIterator IBindableIterable.First() + { + return new IteratorOfTToIteratorAdapter<T>(_vectorView.First()); + } + + } + + [Pure] + bool IBindableVector.IndexOf(object value, out uint index) + { + IBindableVector bindableVector = GetIBindableVectorNoThrow(); + if (bindableVector != null) + { + // IBindableVector -> IBindableVector + return bindableVector.IndexOf(value, out index); + } + else + { + // IBindableVector -> IVector<T> + return GetVectorOfT().IndexOf(ConvertTo<T1>(value), out index); + } + } + + void IBindableVector.SetAt(uint index, object value) + { + IBindableVector bindableVector = GetIBindableVectorNoThrow(); + if (bindableVector != null) + { + // IBindableVector -> IBindableVector + bindableVector.SetAt(index, value); + } + else + { + // IBindableVector -> IVector<T> + GetVectorOfT().SetAt(index, ConvertTo<T1>(value)); + } + } + + void IBindableVector.InsertAt(uint index, object value) + { + IBindableVector bindableVector = GetIBindableVectorNoThrow(); + if (bindableVector != null) + { + // IBindableVector -> IBindableVector + bindableVector.InsertAt(index, value); + } + else + { + // IBindableVector -> IVector<T> + GetVectorOfT().InsertAt(index, ConvertTo<T1>(value)); + } + } + + void IBindableVector.RemoveAt(uint index) + { + IBindableVector bindableVector = GetIBindableVectorNoThrow(); + if (bindableVector != null) + { + // IBindableVector -> IBindableVector + bindableVector.RemoveAt(index); + } + else + { + // IBindableVector -> IVector<T> + GetVectorOfT().RemoveAt(index); + } + } + + void IBindableVector.Append(object value) + { + IBindableVector bindableVector = GetIBindableVectorNoThrow(); + if (bindableVector != null) + { + // IBindableVector -> IBindableVector + bindableVector.Append(value); + } + else + { + // IBindableVector -> IVector<T> + GetVectorOfT().Append(ConvertTo<T1>(value)); + } + } + + void IBindableVector.RemoveAtEnd() + { + IBindableVector bindableVector = GetIBindableVectorNoThrow(); + if (bindableVector != null) + { + // IBindableVector -> IBindableVector + bindableVector.RemoveAtEnd(); + } + else + { + // IBindableVector -> IVector<T> + GetVectorOfT().RemoveAtEnd(); + } + } + + void IBindableVector.Clear() + { + IBindableVector bindableVector = GetIBindableVectorNoThrow(); + if (bindableVector != null) + { + // IBindableVector -> IBindableVector + bindableVector.Clear(); + } + else + { + // IBindableVector -> IVector<T> + GetVectorOfT().Clear(); + } + } + + [SecuritySafeCritical] + private IBindableVector GetIBindableVectorNoThrow() + { + if ((_flags & InterfaceForwardingSupport.IBindableVector) != 0) + return JitHelpers.UnsafeCast<IBindableVector>(_target); + else + return null; + } + + [SecuritySafeCritical] + private IVector_Raw<T1> GetVectorOfT() + { + if ((_flags & InterfaceForwardingSupport.IVector) != 0) + return JitHelpers.UnsafeCast<IVector_Raw<T1>>(_target); + else + throw new InvalidOperationException(); // We should not go down this path, unless Jupiter pass this out to managed code + // and managed code use reflection to do the cast + } + + // + // IBindableVectorView implementation (forwarding to IBindableVectorView or IVectorView<T>) + // + [Pure] + object IBindableVectorView.GetAt(uint index) + { + IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow(); + if (bindableVectorView != null) + return bindableVectorView.GetAt(index); + else + return GetVectorViewOfT().GetAt(index); + } + + [Pure] + uint IBindableVectorView.Size + { + get + { + IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow(); + if (bindableVectorView != null) + return bindableVectorView.Size; + else + return GetVectorViewOfT().Size; + } + } + + [Pure] + bool IBindableVectorView.IndexOf(object value, out uint index) + { + IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow(); + if (bindableVectorView != null) + return bindableVectorView.IndexOf(value, out index); + else + return GetVectorViewOfT().IndexOf(ConvertTo<T2>(value), out index); + } + + IBindableIterator IBindableIterable.First() + { + IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow(); + if (bindableVectorView != null) + return bindableVectorView.First(); + else + return new IteratorOfTToIteratorAdapter<T2>(GetVectorViewOfT().First()); + } + + private sealed class IteratorOfTToIteratorAdapter<T> : IBindableIterator + { + private IIterator<T> _iterator; + + public IteratorOfTToIteratorAdapter(IIterator<T> iterator) + { this._iterator = iterator; } + + public bool HasCurrent { get { return _iterator.HasCurrent; } } + public object Current { get { return (object)_iterator.Current; } } + public bool MoveNext() { return _iterator.MoveNext(); } + } + + [SecuritySafeCritical] + private IBindableVectorView GetIBindableVectorViewNoThrow() + { + if ((_flags & InterfaceForwardingSupport.IBindableVectorView) != 0) + return JitHelpers.UnsafeCast<IBindableVectorView>(_target); + else + return null; + } + + [SecuritySafeCritical] + private IVectorView<T2> GetVectorViewOfT() + { + if ((_flags & InterfaceForwardingSupport.IVectorView) != 0) + return JitHelpers.UnsafeCast<IVectorView<T2>>(_target); + else + throw new InvalidOperationException(); // We should not go down this path, unless Jupiter pass this out to managed code + // and managed code use reflection to do the cast + } + + // + // Convert to type T + // + private static T ConvertTo<T>(object value) + { + // Throw ArgumentNullException if value is null (otherwise we'll throw NullReferenceException + // when casting value to T) + ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value); + + // No coersion support needed. If we need coersion later, this is the place + return (T) value; + } + } +} + diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IIterable.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IIterable.cs new file mode 100644 index 0000000000..e0fad0c4ee --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IIterable.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; + +// Windows.Foundation.Collections.IIterable`1 cannot be referenced from managed code because it's hidden +// by the metadata adapter. We redeclare the interface manually to be able to talk to native WinRT objects. +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("faa585ea-6214-4217-afda-7f46de5869b3")] + [WindowsRuntimeImport] + internal interface IIterable<T> : IEnumerable<T> + { + [Pure] + IIterator<T> First(); + } + + [ComImport] + [Guid("036d2c08-df29-41af-8aa2-d774be62ba6f")] + [WindowsRuntimeImport] + internal interface IBindableIterable + { + [Pure] + IBindableIterator First(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IIterator.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IIterator.cs new file mode 100644 index 0000000000..a663de248e --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IIterator.cs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Diagnostics.Contracts; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [WindowsRuntimeImport] + [Guid("6a79e863-4300-459a-9966-cbb660963ee1")] + internal interface IIterator<T> + { + [Pure] + T Current + { + get; + } + + [Pure] + bool HasCurrent + { + get; + } + + bool MoveNext(); + + [Pure] + int GetMany([Out] T[] items); + } + + [ComImport] + [WindowsRuntimeImport] + [Guid("6a1d6c07-076d-49f2-8314-f52c9c9a8331")] + internal interface IBindableIterator + { + [Pure] + object Current + { + get; + } + + [Pure] + bool HasCurrent + { + get; + } + + bool MoveNext(); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMap.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMap.cs new file mode 100644 index 0000000000..72cf85cd3e --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMap.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; + +// Windows.Foundation.Collections.IMap`2, IMapView`2, and IKeyValuePair`2 cannot be referenced from +// managed code because they're hidden by the metadata adapter. We redeclare the interfaces manually +// to be able to talk to native WinRT objects. +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("3c2925fe-8519-45c1-aa79-197b6718c1c1")] + [WindowsRuntimeImport] + internal interface IMap<K, V> : IIterable<IKeyValuePair<K, V>> + { + [Pure] + V Lookup(K key); + [Pure] + uint Size { get; } + [Pure] + bool HasKey(K key); + [Pure] + IReadOnlyDictionary<K, V> GetView(); // Really an IMapView<K, V> + bool Insert(K key, V value); + void Remove(K key); + void Clear(); + } + + [ComImport] + [Guid("e480ce40-a338-4ada-adcf-272272e48cb9")] + [WindowsRuntimeImport] + internal interface IMapView<K, V> : IIterable<IKeyValuePair<K, V>> + { + [Pure] + V Lookup(K key); + [Pure] + uint Size { get; } + [Pure] + bool HasKey(K key); + [Pure] + void Split(out IMapView<K, V> first, out IMapView<K, V> second); + } + + [ComImport] + [Guid("02b51929-c1c4-4a7e-8940-0312b5c18500")] + [WindowsRuntimeImport] + internal interface IKeyValuePair<K, V> + { + [Pure] + K Key { get; } + [Pure] + V Value { get; } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs new file mode 100644 index 0000000000..f26d50f953 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs @@ -0,0 +1,323 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IReadOnlyDictionary`2 interface on WinRT + // objects that support IMapView`2. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not IMapViewToIReadOnlyDictionaryAdapter objects. Rather, they are of type + // IMapView<K, V>. No actual IMapViewToIReadOnlyDictionaryAdapter object is ever instantiated. Thus, you will see + // a lot of expressions that cast "this" to "IMapView<K, V>". + [DebuggerDisplay("Count = {Count}")] + internal sealed class IMapViewToIReadOnlyDictionaryAdapter + { + private IMapViewToIReadOnlyDictionaryAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // V this[K key] { get } + [SecurityCritical] + internal V Indexer_Get<K, V>(K key) + { + if (key == null) + throw new ArgumentNullException("key"); + Contract.EndContractBlock(); + + IMapView<K, V> _this = JitHelpers.UnsafeCast<IMapView<K, V>>(this); + return Lookup(_this, key); + } + + // IEnumerable<K> Keys { get } + [SecurityCritical] + internal IEnumerable<K> Keys<K, V>() + { + IMapView<K, V> _this = JitHelpers.UnsafeCast<IMapView<K, V>>(this); + IReadOnlyDictionary<K, V> roDictionary = (IReadOnlyDictionary<K, V>)_this; + return new ReadOnlyDictionaryKeyCollection<K, V>(roDictionary); + } + + // IEnumerable<V> Values { get } + [SecurityCritical] + internal IEnumerable<V> Values<K, V>() + { + IMapView<K, V> _this = JitHelpers.UnsafeCast<IMapView<K, V>>(this); + IReadOnlyDictionary<K, V> roDictionary = (IReadOnlyDictionary<K, V>)_this; + return new ReadOnlyDictionaryValueCollection<K, V>(roDictionary); + } + + // bool ContainsKey(K key) + [Pure] + [SecurityCritical] + internal bool ContainsKey<K, V>(K key) + { + if (key == null) + throw new ArgumentNullException("key"); + + IMapView<K, V> _this = JitHelpers.UnsafeCast<IMapView<K, V>>(this); + return _this.HasKey(key); + } + + // bool TryGetValue(TKey key, out TValue value) + [SecurityCritical] + internal bool TryGetValue<K, V>(K key, out V value) + { + if (key == null) + throw new ArgumentNullException("key"); + + IMapView<K, V> _this = JitHelpers.UnsafeCast<IMapView<K, V>>(this); + + // It may be faster to call HasKey then Lookup. On failure, we would otherwise + // throw an exception from Lookup. + if (!_this.HasKey(key)) + { + value = default(V); + return false; + } + + try + { + value = _this.Lookup(key); + return true; + } + catch (Exception ex) // Still may hit this case due to a race condition + { + if (__HResults.E_BOUNDS == ex._HResult) + { + value = default(V); + return false; + } + throw; + } + } + + #region Helpers + + private static V Lookup<K, V>(IMapView<K, V> _this, K key) + { + Contract.Requires(null != key); + + try + { + return _this.Lookup(key); + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + throw new KeyNotFoundException(Environment.GetResourceString("Arg_KeyNotFound")); + throw; + } + } + + #endregion Helpers + } + + // Note: One day we may make these return IReadOnlyCollection<T> + [Serializable] + [DebuggerDisplay("Count = {Count}")] + internal sealed class ReadOnlyDictionaryKeyCollection<TKey, TValue> : IEnumerable<TKey> + { + private readonly IReadOnlyDictionary<TKey, TValue> dictionary; + + public ReadOnlyDictionaryKeyCollection(IReadOnlyDictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + throw new ArgumentNullException("dictionary"); + + this.dictionary = dictionary; + } + + /* + public void CopyTo(TKey[] array, int index) + { + if (array == null) + throw new ArgumentNullException("array"); + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + if (array.Length <= index && this.Count > 0) + throw new ArgumentException(Environment.GetResourceString("Arg_IndexOutOfRangeException")); + if (array.Length - index < dictionary.Count) + throw new ArgumentException(Environment.GetResourceString("Argument_InsufficientSpaceToCopyCollection")); + + int i = index; + foreach (KeyValuePair<TKey, TValue> mapping in dictionary) + { + array[i++] = mapping.Key; + } + } + + public int Count { + get { return dictionary.Count; } + } + + public bool Contains(TKey item) + { + return dictionary.ContainsKey(item); + } + */ + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable<TKey>)this).GetEnumerator(); + } + + public IEnumerator<TKey> GetEnumerator() + { + return new ReadOnlyDictionaryKeyEnumerator<TKey, TValue>(dictionary); + } + } // public class ReadOnlyDictionaryKeyCollection<TKey, TValue> + + + [Serializable] + internal sealed class ReadOnlyDictionaryKeyEnumerator<TKey, TValue> : IEnumerator<TKey> + { + private readonly IReadOnlyDictionary<TKey, TValue> dictionary; + private IEnumerator<KeyValuePair<TKey, TValue>> enumeration; + + public ReadOnlyDictionaryKeyEnumerator(IReadOnlyDictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + throw new ArgumentNullException("dictionary"); + + this.dictionary = dictionary; + this.enumeration = dictionary.GetEnumerator(); + } + + void IDisposable.Dispose() + { + enumeration.Dispose(); + } + + public bool MoveNext() + { + return enumeration.MoveNext(); + } + + Object IEnumerator.Current { + get { return ((IEnumerator<TKey>)this).Current; } + } + + public TKey Current { + get { return enumeration.Current.Key; } + } + + public void Reset() + { + enumeration = dictionary.GetEnumerator(); + } + } // class ReadOnlyDictionaryKeyEnumerator<TKey, TValue> + + + [Serializable] + [DebuggerDisplay("Count = {Count}")] + internal sealed class ReadOnlyDictionaryValueCollection<TKey, TValue> : IEnumerable<TValue> + { + private readonly IReadOnlyDictionary<TKey, TValue> dictionary; + + public ReadOnlyDictionaryValueCollection(IReadOnlyDictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + throw new ArgumentNullException("dictionary"); + + this.dictionary = dictionary; + } + + /* + public void CopyTo(TValue[] array, int index) + { + if (array == null) + throw new ArgumentNullException("array"); + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + if (array.Length <= index && this.Count > 0) + throw new ArgumentException(Environment.GetResourceString("Arg_IndexOutOfRangeException")); + if (array.Length - index < dictionary.Count) + throw new ArgumentException(Environment.GetResourceString("Argument_InsufficientSpaceToCopyCollection")); + + int i = index; + foreach (KeyValuePair<TKey, TValue> mapping in dictionary) + { + array[i++] = mapping.Value; + } + } + + public int Count { + get { return dictionary.Count; } + } + + public bool Contains(TValue item) + { + EqualityComparer<TValue> comparer = EqualityComparer<TValue>.Default; + foreach (TValue value in this) + if (comparer.Equals(item, value)) + return true; + return false; + } + */ + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable<TValue>)this).GetEnumerator(); + } + + public IEnumerator<TValue> GetEnumerator() + { + return new ReadOnlyDictionaryValueEnumerator<TKey, TValue>(dictionary); + } + } // public class ReadOnlyDictionaryValueCollection<TKey, TValue> + + + [Serializable] + internal sealed class ReadOnlyDictionaryValueEnumerator<TKey, TValue> : IEnumerator<TValue> + { + private readonly IReadOnlyDictionary<TKey, TValue> dictionary; + private IEnumerator<KeyValuePair<TKey, TValue>> enumeration; + + public ReadOnlyDictionaryValueEnumerator(IReadOnlyDictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + throw new ArgumentNullException("dictionary"); + + this.dictionary = dictionary; + this.enumeration = dictionary.GetEnumerator(); + } + + void IDisposable.Dispose() + { + enumeration.Dispose(); + } + + public bool MoveNext() + { + return enumeration.MoveNext(); + } + + Object IEnumerator.Current { + get { return ((IEnumerator<TValue>)this).Current; } + } + + public TValue Current { + get { return enumeration.Current.Value; } + } + + public void Reset() + { + enumeration = dictionary.GetEnumerator(); + } + } // class ReadOnlyDictionaryValueEnumerator<TKey, TValue> + +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IPropertyValue.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IPropertyValue.cs new file mode 100644 index 0000000000..792e6c1550 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IPropertyValue.cs @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Diagnostics.Contracts; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("4bd682dd-7554-40e9-9a9b-82654ede7e62")] + [WindowsRuntimeImport] + internal interface IPropertyValue + { + PropertyType Type + { + [Pure] + get; + } + + bool IsNumericScalar + { + [Pure] + get; + } + + [Pure] + Byte GetUInt8(); + + [Pure] + Int16 GetInt16(); + + [Pure] + UInt16 GetUInt16(); + + [Pure] + Int32 GetInt32(); + + [Pure] + UInt32 GetUInt32(); + + [Pure] + Int64 GetInt64(); + + [Pure] + UInt64 GetUInt64(); + + [Pure] + Single GetSingle(); + + [Pure] + Double GetDouble(); + + [Pure] + char GetChar16(); + + [Pure] + Boolean GetBoolean(); + + [Pure] + String GetString(); + + [Pure] + Guid GetGuid(); + + [Pure] + DateTimeOffset GetDateTime(); + + [Pure] + TimeSpan GetTimeSpan(); + + [Pure] + Point GetPoint(); + + [Pure] + Size GetSize(); + + [Pure] + Rect GetRect(); + + [Pure] + Byte[] GetUInt8Array(); + + [Pure] + Int16[] GetInt16Array(); + + [Pure] + UInt16[] GetUInt16Array(); + + [Pure] + Int32[] GetInt32Array(); + + [Pure] + UInt32[] GetUInt32Array(); + + [Pure] + Int64[] GetInt64Array(); + + [Pure] + UInt64[] GetUInt64Array(); + + [Pure] + Single[] GetSingleArray(); + + [Pure] + Double[] GetDoubleArray(); + + [Pure] + char[] GetChar16Array(); + + [Pure] + Boolean[] GetBooleanArray(); + + [Pure] + String[] GetStringArray(); + + [Pure] + object[] GetInspectableArray(); + + [Pure] + Guid[] GetGuidArray(); + + [Pure] + DateTimeOffset[] GetDateTimeArray(); + + [Pure] + TimeSpan[] GetTimeSpanArray(); + + [Pure] + Point[] GetPointArray(); + + [Pure] + Size[] GetSizeArray(); + + [Pure] + Rect[] GetRectArray(); + } + + // Specify size directly instead of fields to avoid warnings + [StructLayoutAttribute(LayoutKind.Sequential, Size=8)] + [WindowsRuntimeImport] + internal struct Point + { + + // float X; + // float Y; + } + + // Specify size directly instead of fields to avoid warnings + [StructLayoutAttribute(LayoutKind.Sequential, Size=8)] + [WindowsRuntimeImport] + internal struct Size + { + + // float Width; + // float Height; + } + + // Specify size directly instead of fields to avoid warnings + [StructLayoutAttribute(LayoutKind.Sequential, Size=16)] + [WindowsRuntimeImport] + internal struct Rect + { + // float X; + // float Y; + // float Width; + // float Height; + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs new file mode 100644 index 0000000000..65feecc447 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IMapView`2 interface on managed + // objects that implement IReadOnlyDictionary`2. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not IReadOnlyDictionaryToIMapViewAdapter objects. Rather, they are of type + // IReadOnlyDictionary<K, V>. No actual IReadOnlyDictionaryToIMapViewAdapter object is ever instantiated. Thus, you will + // see a lot of expressions that cast "this" to "IReadOnlyDictionary<K, V>". + [DebuggerDisplay("Size = {Size}")] + internal sealed class IReadOnlyDictionaryToIMapViewAdapter + { + private IReadOnlyDictionaryToIMapViewAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // V Lookup(K key) + [SecurityCritical] + internal V Lookup<K, V>(K key) + { + IReadOnlyDictionary<K, V> _this = JitHelpers.UnsafeCast<IReadOnlyDictionary<K, V>>(this); + V value; + bool keyFound = _this.TryGetValue(key, out value); + + if (!keyFound) + { + Exception e = new KeyNotFoundException(Environment.GetResourceString("Arg_KeyNotFound")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + + return value; + } + + // uint Size { get } + [SecurityCritical] + internal uint Size<K, V>() + { + IReadOnlyDictionary<K, V> _this = JitHelpers.UnsafeCast<IReadOnlyDictionary<K, V>>(this); + return (uint)_this.Count; + } + + // bool HasKey(K key) + [SecurityCritical] + internal bool HasKey<K, V>(K key) + { + IReadOnlyDictionary<K, V> _this = JitHelpers.UnsafeCast<IReadOnlyDictionary<K, V>>(this); + return _this.ContainsKey(key); + } + + // void Split(out IMapView<K, V> first, out IMapView<K, V> second) + [SecurityCritical] + internal void Split<K, V>(out IMapView<K, V> first, out IMapView<K, V> second) + { + IReadOnlyDictionary<K, V> _this = JitHelpers.UnsafeCast<IReadOnlyDictionary<K, V>>(this); + + if (_this.Count < 2) { + first = null; + second = null; + return; + } + + ConstantSplittableMap<K, V> splittableMap = _this as ConstantSplittableMap<K, V>; + + if (splittableMap == null) + splittableMap = new ConstantSplittableMap<K, V>(_this); + + splittableMap.Split(out first, out second); + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListToIVectorViewAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListToIVectorViewAdapter.cs new file mode 100644 index 0000000000..719bddc67e --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListToIVectorViewAdapter.cs @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IVectorView`1 interface on managed + // objects that implement IReadOnlyList`1. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not IReadOnlyListToIVectorViewAdapter objects. Rather, they are of type + // IReadOnlyList<T>. No actual IReadOnlyListToIVectorViewAdapter object is ever instantiated. Thus, you will + // see a lot of expressions that cast "this" to "IReadOnlyList<T>". + [DebuggerDisplay("Size = {Size}")] + internal sealed class IReadOnlyListToIVectorViewAdapter + { + private IReadOnlyListToIVectorViewAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // T GetAt(uint index) + [SecurityCritical] + internal T GetAt<T>(uint index) + { + IReadOnlyList<T> _this = JitHelpers.UnsafeCast<IReadOnlyList<T>>(this); + EnsureIndexInt32(index, _this.Count); + + try + { + return _this[(int) index]; + } + catch (ArgumentOutOfRangeException ex) + { + ex.SetErrorCode(__HResults.E_BOUNDS); + throw; + } + } + + // uint Size { get } + [SecurityCritical] + internal uint Size<T>() + { + IReadOnlyList<T> _this = JitHelpers.UnsafeCast<IReadOnlyList<T>>(this); + return (uint)_this.Count; + } + + // bool IndexOf(T value, out uint index) + [SecurityCritical] + internal bool IndexOf<T>(T value, out uint index) + { + IReadOnlyList<T> _this = JitHelpers.UnsafeCast<IReadOnlyList<T>>(this); + + int ind = -1; + int max = _this.Count; + for (int i = 0; i < max; i++) + { + if (EqualityComparer<T>.Default.Equals(value, _this[i])) + { + ind = i; + break; + } + } + + if (-1 == ind) + { + index = 0; + return false; + } + + index = (uint)ind; + return true; + } + + // uint GetMany(uint startIndex, T[] items) + [SecurityCritical] + internal uint GetMany<T>(uint startIndex, T[] items) + { + IReadOnlyList<T> _this = JitHelpers.UnsafeCast<IReadOnlyList<T>>(this); + + // REX spec says "calling GetMany with startIndex equal to the length of the vector + // (last valid index + 1) and any specified capacity will succeed and return zero actual + // elements". + if (startIndex == _this.Count) + return 0; + + EnsureIndexInt32(startIndex, _this.Count); + + if (items == null) + { + return 0; + } + + uint itemCount = Math.Min((uint)items.Length, (uint)_this.Count - startIndex); + + for (uint i = 0; i < itemCount; ++i) + { + items[i] = _this[(int)(i + startIndex)]; + } + + if (typeof(T) == typeof(string)) + { + string[] stringItems = items as string[]; + + // Fill in the rest of the array with String.Empty to avoid marshaling failure + for (uint i = itemCount; i < items.Length; ++i) + stringItems[i] = String.Empty; + } + + return itemCount; + } + + #region Helpers + + private static void EnsureIndexInt32(uint index, int listCapacity) + { + // We use '<=' and not '<' because Int32.MaxValue == index would imply + // that Size > Int32.MaxValue: + if (((uint)Int32.MaxValue) <= index || index >= (uint)listCapacity) + { + Exception e = new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_IndexLargerThanMaxValue")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + } + + #endregion Helpers + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReference.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReference.cs new file mode 100644 index 0000000000..864f6f5038 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReference.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("61c17706-2d65-11e0-9ae8-d48564015472")] + [WindowsRuntimeImport] + // Note that ideally, T should be constrained to be a value type. However, Windows uses IReference<HSTRING> + // and the projection may not be exactly pretty. + internal interface IReference<T> : IPropertyValue + { + T Value { get; } + } + + [ComImport] + [Guid("61c17707-2d65-11e0-9ae8-d48564015472")] + [WindowsRuntimeImport] + // T can be any WinRT-compatible type, including reference types. + internal interface IReferenceArray<T> : IPropertyValue + { + T[] Value { get; } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IRestrictedErrorInfo.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IRestrictedErrorInfo.cs new file mode 100644 index 0000000000..8bd4502fe7 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IRestrictedErrorInfo.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ +#if FEATURE_CORECLR + [System.Runtime.CompilerServices.FriendAccessAllowed] +#endif + [ComImport] + [Guid("82BA7092-4C88-427D-A7BC-16DD93FEB67E")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IRestrictedErrorInfo + { + void GetErrorDetails([MarshalAs(UnmanagedType.BStr)] out string description, + out int error, + [MarshalAs(UnmanagedType.BStr)] out string restrictedDescription, + [MarshalAs(UnmanagedType.BStr)] out string capabilitySid); + + void GetReference([MarshalAs(UnmanagedType.BStr)] out string reference); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVector.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVector.cs new file mode 100644 index 0000000000..99952e5825 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVector.cs @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; + +// Windows.Foundation.Collections.IVector`1 and IVectorView`1 cannot be referenced from managed +// code because they're hidden by the metadata adapter. We redeclare the interfaces manually +// to be able to talk to native WinRT objects. +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("913337e9-11a1-4345-a3a2-4e7f956e222d")] + [WindowsRuntimeImport] + internal interface IVector<T> : IIterable<T> + { + [Pure] + T GetAt(uint index); + [Pure] + uint Size { get; } + [Pure] + IReadOnlyList<T> GetView(); // Really an IVectorView<T>. + [Pure] + bool IndexOf(T value, out uint index); + void SetAt(uint index, T value); + void InsertAt(uint index, T value); + void RemoveAt(uint index); + void Append(T value); + void RemoveAtEnd(); + void Clear(); + [Pure] + uint GetMany(uint startIndex, [Out] T[] items); + void ReplaceAll(T[] items); + } + + // Same as IVector - the only difference is that GetView returns IVectorView<T> + [ComImport] + [Guid("913337e9-11a1-4345-a3a2-4e7f956e222d")] + [WindowsRuntimeImport] + internal interface IVector_Raw<T> : IIterable<T> + { + [Pure] + T GetAt(uint index); + [Pure] + uint Size { get; } + [Pure] + IVectorView<T> GetView(); + [Pure] + bool IndexOf(T value, out uint index); + void SetAt(uint index, T value); + void InsertAt(uint index, T value); + void RemoveAt(uint index); + void Append(T value); + void RemoveAtEnd(); + void Clear(); + [Pure] + uint GetMany(uint startIndex, [Out] T[] items); + void ReplaceAll(T[] items); + } + + [ComImport] + [Guid("bbe1fa4c-b0e3-4583-baef-1f1b2e483e56")] + [WindowsRuntimeImport] + internal interface IVectorView<T> : IIterable<T> + { + [Pure] + T GetAt(uint index); + [Pure] + uint Size { get; } + [Pure] + bool IndexOf(T value, out uint index); + [Pure] + uint GetMany(uint startIndex, [Out] T[] items); + } + + [ComImport] + [Guid("393de7de-6fd0-4c0d-bb71-47244a113e93")] + [WindowsRuntimeImport] + internal interface IBindableVector : IBindableIterable + { + [Pure] + object GetAt(uint index); + [Pure] + uint Size { get; } + [Pure] + IBindableVectorView GetView(); + [Pure] + bool IndexOf(object value, out uint index); + void SetAt(uint index, object value); + void InsertAt(uint index, object value); + void RemoveAt(uint index); + void Append(object value); + void RemoveAtEnd(); + void Clear(); + } + + [ComImport] + [Guid("346dd6e7-976e-4bc3-815d-ece243bc0f33")] + [WindowsRuntimeImport] + internal interface IBindableVectorView : IBindableIterable + { + [Pure] + object GetAt(uint index); + [Pure] + uint Size { get; } + [Pure] + bool IndexOf(object value, out uint index); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVectorViewToIReadOnlyListAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVectorViewToIReadOnlyListAdapter.cs new file mode 100644 index 0000000000..ceba967db0 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVectorViewToIReadOnlyListAdapter.cs @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + internal delegate T Indexer_Get_Delegate<out T>(int index); + + // This is a set of stub methods implementing the support for the IReadOnlyList`1 interface on WinRT + // objects that support IVectorView`1. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not IVectorViewToIReadOnlyListAdapter objects. Rather, they are of type + // IVectorView<T>. No actual IVectorViewToIReadOnlyListAdapter object is ever instantiated. Thus, you will see + // a lot of expressions that cast "this" to "IVectorView<T>". + [DebuggerDisplay("Count = {Count}")] + internal sealed class IVectorViewToIReadOnlyListAdapter + { + private IVectorViewToIReadOnlyListAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // T this[int index] { get } + [SecurityCritical] + internal T Indexer_Get<T>(int index) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + + IVectorView<T> _this = JitHelpers.UnsafeCast<IVectorView<T>>(this); + + try + { + return _this.GetAt((uint) index); + + // We delegate bounds checking to the underlying collection and if it detected a fault, + // we translate it to the right exception: + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + throw new ArgumentOutOfRangeException("index"); + + throw; + } + } + + // T this[int index] { get } + [SecurityCritical] + internal T Indexer_Get_Variance<T>(int index) where T : class + { + bool fUseString; + Delegate target = System.StubHelpers.StubHelpers.GetTargetForAmbiguousVariantCall( + this, + typeof(IReadOnlyList<T>).TypeHandle.Value, + out fUseString); + + if (target != null) + { + return (JitHelpers.UnsafeCast<Indexer_Get_Delegate<T>>(target))(index); + } + + if (fUseString) + { + return JitHelpers.UnsafeCast<T>(Indexer_Get<string>(index)); + } + + return Indexer_Get<T>(index); + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs new file mode 100644 index 0000000000..c1656ce7f8 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs @@ -0,0 +1,209 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Security; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + internal delegate IEnumerator<T> GetEnumerator_Delegate<out T>(); + + // This is a set of stub methods implementing the support for the IEnumerable`1 interface on WinRT + // objects that implement IIterable`1. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not IterableToEnumerableAdapter objects. Rather, they are of type + // IIterable<T>. No actual IterableToEnumerableAdapter object is ever instantiated. Thus, you will + // see a lot of expressions that cast "this" to "IIterable<T>". + internal sealed class IterableToEnumerableAdapter + { + private IterableToEnumerableAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // This method is invoked when GetEnumerator is called on a WinRT-backed implementation of IEnumerable<T>. + [SecurityCritical] + internal IEnumerator<T> GetEnumerator_Stub<T>() + { + IIterable<T> _this = JitHelpers.UnsafeCast<IIterable<T>>(this); + return new IteratorToEnumeratorAdapter<T>(_this.First()); + } + + // This method is invoked when GetEnumerator is called on a WinRT-backed implementation of IEnumerable<T> + // and it is possible that the implementation supports IEnumerable<Type>/IEnumerable<string>/IEnumerable<Exception>/ + // IEnumerable<array>/IEnumerable<delegate> rather than IEnumerable<T> because T is assignable from Type/string/ + // Exception/array/delegate via co-variance. + [SecurityCritical] + internal IEnumerator<T> GetEnumerator_Variance_Stub<T>() where T : class + { + bool fUseString; + Delegate target = System.StubHelpers.StubHelpers.GetTargetForAmbiguousVariantCall( + this, + typeof(IEnumerable<T>).TypeHandle.Value, + out fUseString); + + if (target != null) + { + return (JitHelpers.UnsafeCast<GetEnumerator_Delegate<T>>(target))(); + } + + if (fUseString) + { + return JitHelpers.UnsafeCast<IEnumerator<T>>(GetEnumerator_Stub<string>()); + } + + return GetEnumerator_Stub<T>(); + } + } + + internal sealed class BindableIterableToEnumerableAdapter + { + private BindableIterableToEnumerableAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + private sealed class NonGenericToGenericIterator : IIterator<object> + { + private IBindableIterator iterator; + + public NonGenericToGenericIterator(IBindableIterator iterator) + { this.iterator = iterator; } + + public object Current { get { return iterator.Current; } } + public bool HasCurrent { get { return iterator.HasCurrent; } } + public bool MoveNext() { return iterator.MoveNext(); } + public int GetMany(object[] items) { throw new NotSupportedException(); } + } + + // This method is invoked when GetEnumerator is called on a WinRT-backed implementation of IEnumerable. + [SecurityCritical] + internal IEnumerator GetEnumerator_Stub() + { + IBindableIterable _this = JitHelpers.UnsafeCast<IBindableIterable>(this); + return new IteratorToEnumeratorAdapter<object>(new NonGenericToGenericIterator(_this.First())); + } + } + + // Adapter class which holds a Windows Runtime IIterator<T>, exposing it as a managed IEnumerator<T> + + + // There are a few implementation differences between the Iterator and IEnumerator which need to be + // addressed. Iterator starts at index 0 while IEnumerator starts at index -1 as a result of which + // the first call to IEnumerator.Current is correct only after calling MoveNext(). + // Also IEnumerator throws an exception when we call Current after reaching the end of collection. + internal sealed class IteratorToEnumeratorAdapter<T> : IEnumerator<T> + { + private IIterator<T> m_iterator; + private bool m_hadCurrent; + private T m_current; + private bool m_isInitialized; + + internal IteratorToEnumeratorAdapter(IIterator<T> iterator) + { + Contract.Requires(iterator != null); + m_iterator = iterator; + m_hadCurrent = true; + m_isInitialized = false; + } + + public T Current + { + get + { + // The enumerator has not been advanced to the first element yet. + if (!m_isInitialized) + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumNotStarted); + // The enumerator has reached the end of the collection + if (!m_hadCurrent) + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumEnded); + return m_current; + } + } + + object IEnumerator.Current + { + get + { + // The enumerator has not been advanced to the first element yet. + if (!m_isInitialized) + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumNotStarted); + // The enumerator has reached the end of the collection + if (!m_hadCurrent) + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumEnded); + return m_current; + } + } + + [SecuritySafeCritical] + public bool MoveNext() + { + // If we've passed the end of the iteration, IEnumerable<T> should return false, while + // IIterable will fail the interface call + if (!m_hadCurrent) + { + return false; + } + + // IIterators start at index 0, rather than -1. If this is the first call, we need to just + // check HasCurrent rather than actually moving to the next element + try + { + if (!m_isInitialized) + { + m_hadCurrent = m_iterator.HasCurrent; + m_isInitialized = true; + } + else + { + m_hadCurrent = m_iterator.MoveNext(); + } + + // We want to save away the current value for two reasons: + // 1. Accessing .Current is cheap on other iterators, so having it be a property which is a + // simple field access preserves the expected performance characteristics (as opposed to + // triggering a COM call every time the property is accessed) + // + // 2. This allows us to preserve the same semantics as generic collection iteration when iterating + // beyond the end of the collection - namely that Current continues to return the last value + // of the collection + if (m_hadCurrent) + { + m_current = m_iterator.Current; + } + } + catch (Exception e) + { + // Translate E_CHANGED_STATE into an InvalidOperationException for an updated enumeration + if (Marshal.GetHRForException(e) == __HResults.E_CHANGED_STATE) + { + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion); + } + else + { + throw; + } + } + + return m_hadCurrent; + } + + public void Reset() + { + throw new NotSupportedException(); + } + + public void Dispose() + { + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorAdapter.cs new file mode 100644 index 0000000000..e9fbdcf960 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorAdapter.cs @@ -0,0 +1,187 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IBindableVector interface on managed + // objects that implement IList. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not ListToBindableVectorAdapter objects. Rather, they are of type + // IList. No actual ListToVectorBindableAdapter object is ever instantiated. Thus, you will + // see a lot of expressions that cast "this" to "IList". + internal sealed class ListToBindableVectorAdapter + { + private ListToBindableVectorAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // object GetAt(uint index) + [SecurityCritical] + internal object GetAt(uint index) + { + IList _this = JitHelpers.UnsafeCast<IList>(this); + EnsureIndexInt32(index, _this.Count); + + try + { + return _this[(Int32)index]; + } + catch (ArgumentOutOfRangeException ex) + { + throw WindowsRuntimeMarshal.GetExceptionForHR(__HResults.E_BOUNDS, ex, "ArgumentOutOfRange_IndexOutOfRange"); + } + } + + // uint Size { get } + [SecurityCritical] + internal uint Size() + { + IList _this = JitHelpers.UnsafeCast<IList>(this); + return (uint)_this.Count; + } + + // IBindableVectorView GetView() + [SecurityCritical] + internal IBindableVectorView GetView() + { + IList _this = JitHelpers.UnsafeCast<IList>(this); + return new ListToBindableVectorViewAdapter(_this); + } + + // bool IndexOf(object value, out uint index) + [SecurityCritical] + internal bool IndexOf(object value, out uint index) + { + IList _this = JitHelpers.UnsafeCast<IList>(this); + int ind = _this.IndexOf(value); + + if (-1 == ind) + { + index = 0; + return false; + } + + index = (uint)ind; + return true; + } + + // void SetAt(uint index, object value) + [SecurityCritical] + internal void SetAt(uint index, object value) + { + IList _this = JitHelpers.UnsafeCast<IList>(this); + EnsureIndexInt32(index, _this.Count); + + try + { + _this[(int)index] = value; + } + catch (ArgumentOutOfRangeException ex) + { + throw WindowsRuntimeMarshal.GetExceptionForHR(__HResults.E_BOUNDS, ex, "ArgumentOutOfRange_IndexOutOfRange"); + } + } + + // void InsertAt(uint index, object value) + [SecurityCritical] + internal void InsertAt(uint index, object value) + { + IList _this = JitHelpers.UnsafeCast<IList>(this); + + // Inserting at an index one past the end of the list is equivalent to appending + // so we need to ensure that we're within (0, count + 1). + EnsureIndexInt32(index, _this.Count + 1); + + try + { + _this.Insert((int)index, value); + } + catch (ArgumentOutOfRangeException ex) + { + // Change error code to match what WinRT expects + ex.SetErrorCode(__HResults.E_BOUNDS); + throw; + } + } + + // void RemoveAt(uint index) + [SecurityCritical] + internal void RemoveAt(uint index) + { + IList _this = JitHelpers.UnsafeCast<IList>(this); + EnsureIndexInt32(index, _this.Count); + + try + { + _this.RemoveAt((Int32)index); + } + catch (ArgumentOutOfRangeException ex) + { + // Change error code to match what WinRT expects + ex.SetErrorCode(__HResults.E_BOUNDS); + throw; + } + } + + // void Append(object value) + [SecurityCritical] + internal void Append(object value) + { + IList _this = JitHelpers.UnsafeCast<IList>(this); + _this.Add(value); + } + + // void RemoveAtEnd() + [SecurityCritical] + internal void RemoveAtEnd() + { + IList _this = JitHelpers.UnsafeCast<IList>(this); + if (_this.Count == 0) + { + Exception e = new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotRemoveLastFromEmptyCollection")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + + uint size = (uint)_this.Count; + RemoveAt(size - 1); + } + + // void Clear() + [SecurityCritical] + internal void Clear() + { + IList _this = JitHelpers.UnsafeCast<IList>(this); + _this.Clear(); + } + + // Helpers: + + private static void EnsureIndexInt32(uint index, int listCapacity) + { + // We use '<=' and not '<' becasue Int32.MaxValue == index would imply + // that Size > Int32.MaxValue: + if (((uint)Int32.MaxValue) <= index || index >= (uint)listCapacity) + { + Exception e = new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_IndexLargerThanMaxValue")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorViewAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorViewAdapter.cs new file mode 100644 index 0000000000..f89d9a7e90 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorViewAdapter.cs @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + /// A Windows Runtime IBindableVectorView implementation that wraps around a managed IList exposing + /// it to Windows runtime interop. + internal sealed class ListToBindableVectorViewAdapter : IBindableVectorView + { + private readonly IList list; + + internal ListToBindableVectorViewAdapter(IList list) + { + if (list == null) + throw new ArgumentNullException("list"); + + Contract.EndContractBlock(); + + this.list = list; + } + + private static void EnsureIndexInt32(uint index, int listCapacity) + { + // We use '<=' and not '<' becasue Int32.MaxValue == index would imply + // that Size > Int32.MaxValue: + if (((uint)Int32.MaxValue) <= index || index >= (uint)listCapacity) + { + Exception e = new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_IndexLargerThanMaxValue")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + } + + // IBindableIterable implementation: + + public IBindableIterator First() + { + IEnumerator enumerator = list.GetEnumerator(); + return new EnumeratorToIteratorAdapter<object>(new EnumerableToBindableIterableAdapter.NonGenericToGenericEnumerator(enumerator)); + } + + // IBindableVectorView implementation: + + public object GetAt(uint index) + { + EnsureIndexInt32(index, list.Count); + + try + { + return list[(int)index]; + + } + catch (ArgumentOutOfRangeException ex) + { + throw WindowsRuntimeMarshal.GetExceptionForHR(__HResults.E_BOUNDS, ex, "ArgumentOutOfRange_IndexOutOfRange"); + } + } + + public uint Size + { + get + { + return (uint)list.Count; + } + } + + public bool IndexOf(object value, out uint index) + { + int ind = list.IndexOf(value); + + if (-1 == ind) + { + index = 0; + return false; + } + + index = (uint)ind; + return true; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToVectorAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToVectorAdapter.cs new file mode 100644 index 0000000000..1087fe2154 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToVectorAdapter.cs @@ -0,0 +1,254 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IVector`1 interface on managed + // objects that implement IList`1. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not ListToVectorAdapter objects. Rather, they are of type + // IList<T>. No actual ListToVectorAdapter object is ever instantiated. Thus, you will + // see a lot of expressions that cast "this" to "IList<T>". + internal sealed class ListToVectorAdapter + { + private ListToVectorAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // T GetAt(uint index) + [SecurityCritical] + internal T GetAt<T>(uint index) + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + EnsureIndexInt32(index, _this.Count); + + try + { + return _this[(Int32)index]; + } + catch (ArgumentOutOfRangeException ex) + { + throw WindowsRuntimeMarshal.GetExceptionForHR(__HResults.E_BOUNDS, ex, "ArgumentOutOfRange_IndexOutOfRange"); + } + } + + // uint Size { get } + [SecurityCritical] + internal uint Size<T>() + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + return (uint)_this.Count; + } + + // IVectorView<T> GetView() + [SecurityCritical] + internal IReadOnlyList<T> GetView<T>() + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + Contract.Assert(_this != null); + + // Note: This list is not really read-only - you could QI for a modifiable + // list. We gain some perf by doing this. We believe this is acceptable. + IReadOnlyList<T> roList = _this as IReadOnlyList<T>; + if (roList == null) + { + roList = new ReadOnlyCollection<T>(_this); + } + return roList; + } + + // bool IndexOf(T value, out uint index) + [SecurityCritical] + internal bool IndexOf<T>(T value, out uint index) + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + int ind = _this.IndexOf(value); + + if (-1 == ind) + { + index = 0; + return false; + } + + index = (uint)ind; + return true; + } + + // void SetAt(uint index, T value) + [SecurityCritical] + internal void SetAt<T>(uint index, T value) + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + EnsureIndexInt32(index, _this.Count); + + try + { + _this[(int)index] = value; + } + catch (ArgumentOutOfRangeException ex) + { + throw WindowsRuntimeMarshal.GetExceptionForHR(__HResults.E_BOUNDS, ex, "ArgumentOutOfRange_IndexOutOfRange"); + } + } + + // void InsertAt(uint index, T value) + [SecurityCritical] + internal void InsertAt<T>(uint index, T value) + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + + // Inserting at an index one past the end of the list is equivalent to appending + // so we need to ensure that we're within (0, count + 1). + EnsureIndexInt32(index, _this.Count + 1); + + try + { + _this.Insert((int)index, value); + } + catch (ArgumentOutOfRangeException ex) + { + // Change error code to match what WinRT expects + ex.SetErrorCode(__HResults.E_BOUNDS); + throw; + } + } + + // void RemoveAt(uint index) + [SecurityCritical] + internal void RemoveAt<T>(uint index) + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + EnsureIndexInt32(index, _this.Count); + + try + { + _this.RemoveAt((Int32)index); + } + catch (ArgumentOutOfRangeException ex) + { + // Change error code to match what WinRT expects + ex.SetErrorCode(__HResults.E_BOUNDS); + throw; + } + } + + // void Append(T value) + [SecurityCritical] + internal void Append<T>(T value) + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + _this.Add(value); + } + + // void RemoveAtEnd() + [SecurityCritical] + internal void RemoveAtEnd<T>() + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + if (_this.Count == 0) + { + Exception e = new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotRemoveLastFromEmptyCollection")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + + uint size = (uint)_this.Count; + RemoveAt<T>(size - 1); + } + + // void Clear() + [SecurityCritical] + internal void Clear<T>() + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + _this.Clear(); + } + + // uint GetMany(uint startIndex, T[] items) + [SecurityCritical] + internal uint GetMany<T>(uint startIndex, T[] items) + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + return GetManyHelper<T>(_this, startIndex, items); + } + + // void ReplaceAll(T[] items) + [SecurityCritical] + internal void ReplaceAll<T>(T[] items) + { + IList<T> _this = JitHelpers.UnsafeCast<IList<T>>(this); + _this.Clear(); + + if (items != null) + { + foreach (T item in items) + { + _this.Add(item); + } + } + } + + // Helpers: + + private static void EnsureIndexInt32(uint index, int listCapacity) + { + // We use '<=' and not '<' becasue Int32.MaxValue == index would imply + // that Size > Int32.MaxValue: + if (((uint)Int32.MaxValue) <= index || index >= (uint)listCapacity) + { + Exception e = new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_IndexLargerThanMaxValue")); + e.SetErrorCode(__HResults.E_BOUNDS); + throw e; + } + } + + private static uint GetManyHelper<T>(IList<T> sourceList, uint startIndex, T[] items) + { + // Calling GetMany with a start index equal to the size of the list should always + // return 0 elements, regardless of the input item size + if (startIndex == sourceList.Count) + { + return 0; + } + + EnsureIndexInt32(startIndex, sourceList.Count); + + if (items == null) + { + return 0; + } + + uint itemCount = Math.Min((uint)items.Length, (uint)sourceList.Count - startIndex); + for (uint i = 0; i < itemCount; ++i) + { + items[i] = sourceList[(int)(i + startIndex)]; + } + + if (typeof(T) == typeof(string)) + { + string[] stringItems = items as string[]; + + // Fill in rest of the array with String.Empty to avoid marshaling failure + for (uint i = itemCount; i < items.Length; ++i) + stringItems[i] = String.Empty; + } + + return itemCount; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ManagedActivationFactory.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ManagedActivationFactory.cs new file mode 100644 index 0000000000..6ff37cbc5e --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ManagedActivationFactory.cs @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Diagnostics.Contracts; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("60D27C8D-5F61-4CCE-B751-690FAE66AA53")] + [WindowsRuntimeImport] + internal interface IManagedActivationFactory + { + void RunClassConstructor(); + } + + // A ManangedActivationFactory provides the IActivationFactory implementation for managed types which are + // constructable via Windows Runtime. Implementation of specialized factory and static WinRT interfaces is + // provided using VM functionality (see Marshal.InitializeWinRTFactoryObject for details). + // + // In order to be activatable via the ManagedActivationFactory type, the type must be decorated with either + // ActivatableAttribute, or StaticAttribute. + [ComVisible(true)] + [ClassInterface(ClassInterfaceType.None)] + internal sealed class ManagedActivationFactory : IActivationFactory, IManagedActivationFactory + { + private Type m_type; + + [SecurityCritical] + internal ManagedActivationFactory(Type type) + { + if (type == null) + throw new ArgumentNullException("type"); + + // Check whether the type is "exported to WinRT", i.e. it is declared in a managed .winmd and is decorated + // with at least one ActivatableAttribute or StaticAttribute. + if (!(type is RuntimeType) || !type.IsExportedToWindowsRuntime) + throw new ArgumentException(Environment.GetResourceString("Argument_TypeNotActivatableViaWindowsRuntime", type), "type"); + + m_type = type; + } + + // Activate an instance of the managed type by using its default constructor. + public object ActivateInstance() + { + try + { + return Activator.CreateInstance(m_type); + } + catch (MissingMethodException) + { + // If the type doesn't expose a default constructor, then we fail with E_NOTIMPL + throw new NotImplementedException(); + } + catch (TargetInvocationException e) + { + throw e.InnerException; + } + } + + // Runs the class constructor + // Currently only Jupiter use this to run class constructor in order to + // initialize DependencyProperty objects and do necessary work + void IManagedActivationFactory.RunClassConstructor() + { + RuntimeHelpers.RunClassConstructor(m_type.TypeHandle); + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToCollectionAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToCollectionAdapter.cs new file mode 100644 index 0000000000..3558bf3b2a --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToCollectionAdapter.cs @@ -0,0 +1,191 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // These stubs will be used when a call via ICollection<KeyValuePair<K, V>> is made in managed code. + // This can mean two things - either the underlying unmanaged object implements IMap<K, V> or it + // implements IVector<IKeyValuePair<K, V>> and we cannot determine this statically in the general + // case so we have to cast at run-time. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not MapToCollectionAdapter objects. Rather, they are of type + // IVector<KeyValuePair<K, V>> or IMap<K, V>. No actual MapToCollectionAdapter object is ever + // instantiated. Thus, you will see a lot of expressions that cast "this" to "IVector<KeyValuePair<K, V>>" + // or "IMap<K, V>". + internal sealed class MapToCollectionAdapter + { + private MapToCollectionAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // int Count { get } + [Pure] + [SecurityCritical] + internal int Count<K, V>() + { + object _this = JitHelpers.UnsafeCast<object>(this); + + IMap<K, V> _this_map = _this as IMap<K, V>; + if (_this_map != null) + { + uint size = _this_map.Size; + + if (((uint)Int32.MaxValue) < size) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingDictionaryTooLarge")); + } + + return (int)size; + } + else + { + IVector<KeyValuePair<K, V>> _this_vector = JitHelpers.UnsafeCast<IVector<KeyValuePair<K, V>>>(this); + uint size = _this_vector.Size; + + if (((uint)Int32.MaxValue) < size) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + return (int)size; + } + } + + // bool IsReadOnly { get } + [SecurityCritical] + internal bool IsReadOnly<K, V>() + { + return false; + } + + // void Add(T item) + [SecurityCritical] + internal void Add<K, V>(KeyValuePair<K, V> item) + { + object _this = JitHelpers.UnsafeCast<object>(this); + + IDictionary<K, V> _this_dictionary = _this as IDictionary<K, V>; + if (_this_dictionary != null) + { + _this_dictionary.Add(item.Key, item.Value); + } + else + { + IVector<KeyValuePair<K, V>> _this_vector = JitHelpers.UnsafeCast<IVector<KeyValuePair<K, V>>>(this); + _this_vector.Append(item); + } + } + + // void Clear() + [SecurityCritical] + internal void Clear<K, V>() + { + object _this = JitHelpers.UnsafeCast<object>(this); + + IMap<K, V> _this_map = _this as IMap<K, V>; + if (_this_map != null) + { + _this_map.Clear(); + } + else + { + IVector<KeyValuePair<K, V>> _this_vector = JitHelpers.UnsafeCast<IVector<KeyValuePair<K, V>>>(this); + _this_vector.Clear(); + } + } + + // bool Contains(T item) + [SecurityCritical] + internal bool Contains<K, V>(KeyValuePair<K, V> item) + { + object _this = JitHelpers.UnsafeCast<object>(this); + + IDictionary<K, V> _this_dictionary = _this as IDictionary<K, V>; + if (_this_dictionary != null) + { + V value; + bool hasKey = _this_dictionary.TryGetValue(item.Key, out value); + + if (!hasKey) + return false; + + return EqualityComparer<V>.Default.Equals(value, item.Value); + } + else + { + IVector<KeyValuePair<K, V>> _this_vector = JitHelpers.UnsafeCast<IVector<KeyValuePair<K, V>>>(this); + + uint index; + return _this_vector.IndexOf(item, out index); + } + } + + // void CopyTo(T[] array, int arrayIndex) + [SecurityCritical] + internal void CopyTo<K, V>(KeyValuePair<K, V>[] array, int arrayIndex) + { + if (array == null) + throw new ArgumentNullException("array"); + + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException("arrayIndex"); + + if (array.Length <= arrayIndex && Count<K, V>() > 0) + throw new ArgumentException(Environment.GetResourceString("Argument_IndexOutOfArrayBounds")); + + if (array.Length - arrayIndex < Count<K, V>()) + throw new ArgumentException(Environment.GetResourceString("Argument_InsufficientSpaceToCopyCollection")); + + Contract.EndContractBlock(); + + IIterable<KeyValuePair<K, V>> _this = JitHelpers.UnsafeCast<IIterable<KeyValuePair<K, V>>>(this); + foreach (KeyValuePair<K, V> mapping in _this) + { + array[arrayIndex++] = mapping; + } + } + + // bool Remove(T item) + [SecurityCritical] + internal bool Remove<K, V>(KeyValuePair<K, V> item) + { + object _this = JitHelpers.UnsafeCast<object>(this); + + IDictionary<K, V> _this_dictionary = _this as IDictionary<K, V>; + if (_this_dictionary != null) + { + return _this_dictionary.Remove(item.Key); + } + else + { + IVector<KeyValuePair<K, V>> _this_vector = JitHelpers.UnsafeCast<IVector<KeyValuePair<K, V>>>(this); + uint index; + bool exists = _this_vector.IndexOf(item, out index); + + if (!exists) + return false; + + if (((uint)Int32.MaxValue) < index) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + VectorToListAdapter.RemoveAtHelper<KeyValuePair<K, V>>(_this_vector, index); + return true; + } + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs new file mode 100644 index 0000000000..d5c28c4abf --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IDictionary`2 interface on WinRT + // objects that support IMap`2. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not MapToDictionaryAdapter objects. Rather, they are of type + // IMap<K, V>. No actual MapToDictionaryAdapter object is ever instantiated. Thus, you will see + // a lot of expressions that cast "this" to "IMap<K, V>". + internal sealed class MapToDictionaryAdapter + { + private MapToDictionaryAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // V this[K key] { get } + [SecurityCritical] + internal V Indexer_Get<K, V>(K key) + { + if (key == null) + throw new ArgumentNullException("key"); + + Contract.EndContractBlock(); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + return Lookup(_this, key); + } + + // V this[K key] { set } + [SecurityCritical] + internal void Indexer_Set<K, V>(K key, V value) + { + if (key == null) + throw new ArgumentNullException("key"); + + Contract.EndContractBlock(); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + Insert(_this, key, value); + } + + // ICollection<K> Keys { get } + [SecurityCritical] + internal ICollection<K> Keys<K, V>() + { + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + IDictionary<K, V> dictionary = (IDictionary<K, V>)_this; + return new DictionaryKeyCollection<K, V>(dictionary); + } + + // ICollection<V> Values { get } + [SecurityCritical] + internal ICollection<V> Values<K, V>() + { + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + IDictionary<K, V> dictionary = (IDictionary<K, V>)_this; + return new DictionaryValueCollection<K, V>(dictionary); + } + + // bool ContainsKey(K key) + [Pure] + [SecurityCritical] + internal bool ContainsKey<K, V>(K key) + { + if (key == null) + throw new ArgumentNullException("key"); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + return _this.HasKey(key); + } + + // void Add(K key, V value) + [SecurityCritical] + internal void Add<K, V>(K key, V value) + { + if (key == null) + throw new ArgumentNullException("key"); + + if (ContainsKey<K, V>(key)) + throw new ArgumentException(Environment.GetResourceString("Argument_AddingDuplicate")); + + Contract.EndContractBlock(); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + Insert(_this, key, value); + } + + // bool Remove(TKey key) + [SecurityCritical] + internal bool Remove<K, V>(K key) + { + if (key == null) + throw new ArgumentNullException("key"); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + if (!_this.HasKey(key)) + return false; + + try + { + _this.Remove(key); + return true; + + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + return false; + + throw; + } + } + + // bool TryGetValue(TKey key, out TValue value) + [SecurityCritical] + internal bool TryGetValue<K, V>(K key, out V value) + { + if (key == null) + throw new ArgumentNullException("key"); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + if (!_this.HasKey(key)) + { + value = default(V); + return false; + } + + try + { + value = Lookup(_this, key); + return true; + } + catch (KeyNotFoundException) + { + value = default(V); + return false; + } + } + + // Helpers: + + private static V Lookup<K, V>(IMap<K, V> _this, K key) + { + Contract.Requires(null != key); + + try + { + return _this.Lookup(key); + } + catch (Exception ex) + { + + if (__HResults.E_BOUNDS == ex._HResult) + throw new KeyNotFoundException(Environment.GetResourceString("Arg_KeyNotFound")); + throw; + } + } + + private static bool Insert<K, V>(IMap<K, V> _this, K key, V value) + { + Contract.Requires(null != key); + + bool replaced = _this.Insert(key, value); + return replaced; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapViewToReadOnlyCollectionAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapViewToReadOnlyCollectionAdapter.cs new file mode 100644 index 0000000000..583903acf8 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapViewToReadOnlyCollectionAdapter.cs @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // These stubs will be used when a call via IReadOnlyCollection<KeyValuePair<K, V>> is made in managed code. + // This can mean two things - either the underlying unmanaged object implements IMapView<K, V> or it + // implements IVectorView<IKeyValuePair<K, V>> and we cannot determine this statically in the general + // case so we have to cast at run-time. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not MapViewToReadOnlyCollectionAdapter objects. Rather, they are of type + // IVectorView<KeyValuePair<K, V>> or IMapView<K, V>. No actual MapViewToReadOnlyCollectionAdapter object is ever + // instantiated. Thus, you will see a lot of expressions that cast "this" to "IVectorView<KeyValuePair<K, V>>" + // or "IMapView<K, V>". + internal sealed class MapViewToReadOnlyCollectionAdapter + { + private MapViewToReadOnlyCollectionAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // int Count { get } + [Pure] + [SecurityCritical] + internal int Count<K, V>() + { + object _this = JitHelpers.UnsafeCast<object>(this); + + IMapView<K, V> _this_map = _this as IMapView<K, V>; + if (_this_map != null) + { + uint size = _this_map.Size; + + if (((uint)Int32.MaxValue) < size) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingDictionaryTooLarge")); + } + + return (int)size; + } + else + { + IVectorView<KeyValuePair<K, V>> _this_vector = JitHelpers.UnsafeCast<IVectorView<KeyValuePair<K, V>>>(this); + uint size = _this_vector.Size; + + if (((uint)Int32.MaxValue) < size) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + return (int)size; + } + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/NativeMethods.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/NativeMethods.cs new file mode 100644 index 0000000000..bf011955c2 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/NativeMethods.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Runtime.InteropServices; +using System.Security; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ +#if WIN64 + [StructLayout(LayoutKind.Explicit, Size = 24)] +#else + [StructLayout(LayoutKind.Explicit, Size = 20)] +#endif + internal unsafe struct HSTRING_HEADER + { + } + + internal static class UnsafeNativeMethods + { + [DllImport("api-ms-win-core-winrt-error-l1-1-1.dll", PreserveSig = false)] + [SecurityCritical] + [SuppressUnmanagedCodeSecurity] + internal static extern IRestrictedErrorInfo GetRestrictedErrorInfo(); + + [DllImport("api-ms-win-core-winrt-error-l1-1-1.dll")] + [SecurityCritical] + [SuppressUnmanagedCodeSecurity] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool RoOriginateLanguageException(int error, [MarshalAs(UnmanagedType.HString)]string message, IntPtr languageException); + + [DllImport("api-ms-win-core-winrt-error-l1-1-1.dll", PreserveSig = false)] + [SecurityCritical] + [SuppressUnmanagedCodeSecurity] + internal static extern void RoReportUnhandledError(IRestrictedErrorInfo error); + + [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] + [SecurityCritical] + [SuppressUnmanagedCodeSecurity] + internal static unsafe extern int WindowsCreateString([MarshalAs(UnmanagedType.LPWStr)] string sourceString, + int length, + [Out] IntPtr *hstring); + + [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] + [SecurityCritical] + [SuppressUnmanagedCodeSecurity] + internal static unsafe extern int WindowsCreateStringReference(char *sourceString, + int length, + [Out] HSTRING_HEADER *hstringHeader, + [Out] IntPtr *hstring); + + [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] + [SecurityCritical] + [SuppressUnmanagedCodeSecurity] + internal static extern int WindowsDeleteString(IntPtr hstring); + + [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] + [SecurityCritical] + [SuppressUnmanagedCodeSecurity] + internal static unsafe extern char* WindowsGetStringRawBuffer(IntPtr hstring, [Out] uint *length); + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/PropertyValue.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/PropertyValue.cs new file mode 100644 index 0000000000..23f8539f84 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/PropertyValue.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // Note this is a copy of the PropertyType enumeration from Windows.Foundation.winmd + internal enum PropertyType + { + // WARNING: These values have to match enum Windows.Foundation.PropertyType !!! + Empty = 0, + UInt8 = 1, + Int16 = 2, + UInt16 = 3, + Int32 = 4, + UInt32 = 5, + Int64 = 6, + UInt64 = 7, + Single = 8, + Double = 9, + Char16 = 10, + Boolean = 11, + String = 12, + Inspectable = 13, + DateTime = 14, + TimeSpan = 15, + Guid = 16, + Point = 17, + Size = 18, + Rect = 19, + + Other = 20, + + UInt8Array = UInt8 + 1024, + Int16Array = Int16 + 1024, + UInt16Array = UInt16 + 1024, + Int32Array = Int32 + 1024, + UInt32Array = UInt32 + 1024, + Int64Array = Int64 + 1024, + UInt64Array = UInt64 + 1024, + SingleArray = Single + 1024, + DoubleArray = Double + 1024, + Char16Array = Char16 + 1024, + BooleanArray = Boolean + 1024, + StringArray = String + 1024, + InspectableArray = Inspectable + 1024, + DateTimeArray = DateTime + 1024, + TimeSpanArray = TimeSpan + 1024, + GuidArray = Guid + 1024, + PointArray = Point + 1024, + SizeArray = Size + 1024, + RectArray = Rect + 1024, + OtherArray = Other + 1024, + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/RuntimeClass.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/RuntimeClass.cs new file mode 100644 index 0000000000..0139fab27a --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/RuntimeClass.cs @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================ +** +** +** +** RuntimeClass is the base class of all WinRT types +** +** +===========================================================*/ +namespace System.Runtime.InteropServices.WindowsRuntime { + + using System; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.WindowsRuntime; + using System.Runtime.CompilerServices; + using System.Security; + + + // Local definition of Windows.Foundation.IStringable + [ComImport] + [Guid("96369f54-8eb6-48f0-abce-c1b211e627c3")] + [WindowsRuntimeImport] + internal interface IStringable + { + string ToString(); + } + + internal class IStringableHelper + { + internal static string ToString(object obj) + { + // Check whether the type implements IStringable. + IStringable stringableType = obj as IStringable; + if (stringableType != null) + { + return stringableType.ToString(); + } + + return obj.ToString(); + } + } + + // + // Base class for every WinRT class + // We'll make it a ComImport and WindowsRuntimeImport in the type loader + // as C# compiler won't allow putting code in ComImport type + // + internal abstract class RuntimeClass : __ComObject + { + // + // Support for ToString/GetHashCode/Equals override + // + [System.Security.SecurityCritical] + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern IntPtr GetRedirectedGetHashCodeMD(); + + [System.Security.SecurityCritical] + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern int RedirectGetHashCode(IntPtr pMD); + + [System.Security.SecuritySafeCritical] + public override int GetHashCode() + { + IntPtr pMD = GetRedirectedGetHashCodeMD(); + if (pMD == IntPtr.Zero) + return base.GetHashCode(); + return RedirectGetHashCode(pMD); + } + + [System.Security.SecurityCritical] + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern IntPtr GetRedirectedToStringMD(); + + [System.Security.SecurityCritical] + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern string RedirectToString(IntPtr pMD); + + [System.Security.SecuritySafeCritical] + public override string ToString() + { + // Check whether the type implements IStringable. + IStringable stringableType = this as IStringable; + if (stringableType != null) + { + return stringableType.ToString(); + } + else + { + IntPtr pMD = GetRedirectedToStringMD(); + + if (pMD == IntPtr.Zero) + return base.ToString(); + + return RedirectToString(pMD); + } + } + + [System.Security.SecurityCritical] + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern IntPtr GetRedirectedEqualsMD(); + + [System.Security.SecurityCritical] + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern bool RedirectEquals(object obj, IntPtr pMD); + + [System.Security.SecuritySafeCritical] + public override bool Equals(object obj) + { + IntPtr pMD = GetRedirectedEqualsMD(); + if (pMD == IntPtr.Zero) + return base.Equals(obj); + return RedirectEquals(obj, pMD); + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToCollectionAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToCollectionAdapter.cs new file mode 100644 index 0000000000..91d9346604 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToCollectionAdapter.cs @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the ICollection`1 interface on WinRT + // objects that support IVector`1. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not VectorToCollectionAdapter objects. Rather, they are of type + // IVector<T>. No actual VectorToCollectionAdapter object is ever instantiated. Thus, you will see + // a lot of expressions that cast "this" to "IVector<T>". + internal sealed class VectorToCollectionAdapter + { + private VectorToCollectionAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // int Count { get } + [Pure] + [SecurityCritical] + internal int Count<T>() + { + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + uint size = _this.Size; + if (((uint)Int32.MaxValue) < size) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + return (int)size; + } + + // bool IsReadOnly { get } + [SecurityCritical] + internal bool IsReadOnly<T>() + { + return false; + } + + // void Add(T item) + [SecurityCritical] + internal void Add<T>(T item) + { + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + _this.Append(item); + } + + // void Clear() + [SecurityCritical] + internal void Clear<T>() + { + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + _this.Clear(); + } + + // bool Contains(T item) + [SecurityCritical] + internal bool Contains<T>(T item) + { + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + + uint index; + return _this.IndexOf(item, out index); + } + + // void CopyTo(T[] array, int arrayIndex) + [SecurityCritical] + internal void CopyTo<T>(T[] array, int arrayIndex) + { + if (array == null) + throw new ArgumentNullException("array"); + + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException("arrayIndex"); + + if (array.Length <= arrayIndex && Count<T>() > 0) + throw new ArgumentException(Environment.GetResourceString("Argument_IndexOutOfArrayBounds")); + + if (array.Length - arrayIndex < Count<T>()) + throw new ArgumentException(Environment.GetResourceString("Argument_InsufficientSpaceToCopyCollection")); + + Contract.EndContractBlock(); + + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + int count = Count<T>(); + for (int i = 0; i < count; i++) + { + array[i + arrayIndex] = VectorToListAdapter.GetAt<T>(_this, (uint)i); + } + } + + // bool Remove(T item) + [SecurityCritical] + internal bool Remove<T>(T item) + { + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + + uint index; + bool exists = _this.IndexOf(item, out index); + + if (!exists) + return false; + + if (((uint)Int32.MaxValue) < index) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + VectorToListAdapter.RemoveAtHelper<T>(_this, index); + return true; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToListAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToListAdapter.cs new file mode 100644 index 0000000000..4fed70c63f --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToListAdapter.cs @@ -0,0 +1,169 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IList`1 interface on WinRT + // objects that support IVector`1. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not VectorToListAdapter objects. Rather, they are of type + // IVector<T>. No actual VectorToListAdapter object is ever instantiated. Thus, you will see + // a lot of expressions that cast "this" to "IVector<T>". + internal sealed class VectorToListAdapter + { + private VectorToListAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // T this[int index] { get } + [SecurityCritical] + internal T Indexer_Get<T>(int index) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + return GetAt(_this, (uint)index); + } + + // T this[int index] { set } + [SecurityCritical] + internal void Indexer_Set<T>(int index, T value) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + SetAt(_this, (uint)index, value); + } + + // int IndexOf(T item) + [SecurityCritical] + internal int IndexOf<T>(T item) + { + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + + uint index; + bool exists = _this.IndexOf(item, out index); + + if (!exists) + return -1; + + if (((uint)Int32.MaxValue) < index) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + return (int)index; + } + + // void Insert(int index, T item) + [SecurityCritical] + internal void Insert<T>(int index, T item) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + InsertAtHelper<T>(_this, (uint)index, item); + } + + // void RemoveAt(int index) + [SecurityCritical] + internal void RemoveAt<T>(int index) + { + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + + IVector<T> _this = JitHelpers.UnsafeCast<IVector<T>>(this); + RemoveAtHelper<T>(_this, (uint)index); + } + + // Helpers: + + internal static T GetAt<T>(IVector<T> _this, uint index) + { + try + { + return _this.GetAt(index); + + // We delegate bounds checking to the underlying collection and if it detected a fault, + // we translate it to the right exception: + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + throw new ArgumentOutOfRangeException("index"); + + throw; + } + } + + private static void SetAt<T>(IVector<T> _this, UInt32 index, T value) + { + try + { + _this.SetAt(index, value); + + // We deligate bounds checking to the underlying collection and if it detected a fault, + // we translate it to the right exception: + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + throw new ArgumentOutOfRangeException("index"); + + throw; + } + } + + private static void InsertAtHelper<T>(IVector<T> _this, uint index, T item) + { + try + { + _this.InsertAt(index, item); + + // We delegate bounds checking to the underlying collection and if it detected a fault, + // we translate it to the right exception: + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + throw new ArgumentOutOfRangeException("index"); + + throw; + } + } + + internal static void RemoveAtHelper<T>(IVector<T> _this, uint index) + { + try + { + _this.RemoveAt(index); + + // We delegate bounds checking to the underlying collection and if it detected a fault, + // we translate it to the right exception: + } + catch (Exception ex) + { + if (__HResults.E_BOUNDS == ex._HResult) + throw new ArgumentOutOfRangeException("index"); + + throw; + } + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorViewToReadOnlyCollectionAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorViewToReadOnlyCollectionAdapter.cs new file mode 100644 index 0000000000..eea37b3bdc --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorViewToReadOnlyCollectionAdapter.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Security; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // This is a set of stub methods implementing the support for the IReadOnlyCollection<T> interface on WinRT + // objects that support IVectorView<T>. Used by the interop mashaling infrastructure. + // + // The methods on this class must be written VERY carefully to avoid introducing security holes. + // That's because they are invoked with special "this"! The "this" object + // for all of these methods are not VectorViewToReadOnlyCollectionAdapter objects. Rather, they are of type + // IVectorView<T>. No actual VectorViewToReadOnlyCollectionAdapter object is ever instantiated. Thus, you will see + // a lot of expressions that cast "this" to "IVectorView<T>". + internal sealed class VectorViewToReadOnlyCollectionAdapter + { + private VectorViewToReadOnlyCollectionAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // int Count { get } + [Pure] + [SecurityCritical] + internal int Count<T>() + { + IVectorView<T> _this = JitHelpers.UnsafeCast<IVectorView<T>>(this); + uint size = _this.Size; + if (((uint)Int32.MaxValue) < size) + { + throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CollectionBackingListTooLarge")); + } + + return (int)size; + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsFoundationEventHandler.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsFoundationEventHandler.cs new file mode 100644 index 0000000000..e057846e2f --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsFoundationEventHandler.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // WindowsFoundationEventHandler<T> a copy of the definition for the Windows.Foundation.EventHandler<T> delegate + [Guid("9de1c535-6ae1-11e0-84e1-18a905bcc53f")] + [WindowsRuntimeImport] + internal delegate void WindowsFoundationEventHandler<T>(object sender, T args); +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBufferHelper.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBufferHelper.cs new file mode 100644 index 0000000000..12cf107a47 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBufferHelper.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; +using System.Runtime.Versioning; +using System.Security; +using System.Threading; + + +namespace System.Runtime.InteropServices.WindowsRuntime { + +/// <summary> +/// Exposes a helper method that allows <code>WindowsRuntimeBuffer : IBuffer, IBufferInternal</code> which is implemented in +/// <code>System.Runtime.WindowsRuntime.dll</code> to call into the VM. +/// </summary> +[FriendAccessAllowed] +internal static class WindowsRuntimeBufferHelper { + + + [SecurityCritical] + [DllImport(JitHelpers.QCall)] + [SuppressUnmanagedCodeSecurity] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + private unsafe extern static void StoreOverlappedPtrInCCW(ObjectHandleOnStack windowsRuntimeBuffer, NativeOverlapped* overlapped); + + + [FriendAccessAllowed] + [SecurityCritical] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal unsafe static void StoreOverlappedInCCW(Object windowsRuntimeBuffer, NativeOverlapped* overlapped) { + + StoreOverlappedPtrInCCW(JitHelpers.GetObjectHandleOnStack(ref windowsRuntimeBuffer), overlapped); + } + +} // class WindowsRuntimeBufferHelper + +} // namespace + +// WindowsRuntimeBufferHelper.cs diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeMarshal.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeMarshal.cs new file mode 100644 index 0000000000..dbf1a8a1f1 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeMarshal.cs @@ -0,0 +1,1334 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using System.Security; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + // Helper functions to manually marshal data between .NET and WinRT + public static class WindowsRuntimeMarshal + { + // Add an event handler to a Windows Runtime style event, such that it can be removed via a delegate + // lookup at a later time. This method adds the handler to the add method using the supplied + // delegate. It then stores the corresponding token in a dictionary for easy access by RemoveEventHandler + // later. Note that the dictionary is indexed by the remove method that will be used for RemoveEventHandler + // so the removeMethod given here must match the remove method supplied there exactly. + [SecurityCritical] + public static void AddEventHandler<T>(Func<T, EventRegistrationToken> addMethod, + Action<EventRegistrationToken> removeMethod, + T handler) + { + if (addMethod == null) + throw new ArgumentNullException("addMethod"); + if (removeMethod == null) + throw new ArgumentNullException("removeMethod"); + Contract.EndContractBlock(); + + // Managed code allows adding a null event handler, the effect is a no-op. To match this behavior + // for WinRT events, we simply ignore attempts to add null. + if (handler == null) + { + return; + } + + // Delegate to managed event registration implementation or native event registration implementation + // They have completely different implementation because native side has its own unique problem to solve - + // there could be more than one RCW for the same COM object + // it would be more confusing and less-performant if we were to merge them together + object target = removeMethod.Target; + if (target == null || Marshal.IsComObject(target)) + NativeOrStaticEventRegistrationImpl.AddEventHandler<T>(addMethod, removeMethod, handler); + else + ManagedEventRegistrationImpl.AddEventHandler<T>(addMethod, removeMethod, handler); + } + + // Remove the delegate handler from the Windows Runtime style event registration by looking for + // its token, previously stored via AddEventHandler<T> + [SecurityCritical] + public static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler) + { + if (removeMethod == null) + throw new ArgumentNullException("removeMethod"); + Contract.EndContractBlock(); + + // Managed code allows removing a null event handler, the effect is a no-op. To match this behavior + // for WinRT events, we simply ignore attempts to remove null. + if (handler == null) + { + return; + } + + // Delegate to managed event registration implementation or native event registration implementation + // They have completely different implementation because native side has its own unique problem to solve - + // there could be more than one RCW for the same COM object + // it would be more confusing and less-performant if we were to merge them together + object target = removeMethod.Target; + if (target == null || Marshal.IsComObject(target)) + NativeOrStaticEventRegistrationImpl.RemoveEventHandler<T>(removeMethod, handler); + else + ManagedEventRegistrationImpl.RemoveEventHandler<T>(removeMethod, handler); + } + + [SecurityCritical] + public static void RemoveAllEventHandlers(Action<EventRegistrationToken> removeMethod) + { + if (removeMethod == null) + throw new ArgumentNullException("removeMethod"); + Contract.EndContractBlock(); + + // Delegate to managed event registration implementation or native event registration implementation + // They have completely different implementation because native side has its own unique problem to solve - + // there could be more than one RCW for the same COM object + // it would be more confusing and less-performant if we were to merge them together + object target = removeMethod.Target; + if (target == null || Marshal.IsComObject(target)) + NativeOrStaticEventRegistrationImpl.RemoveAllEventHandlers(removeMethod); + else + ManagedEventRegistrationImpl.RemoveAllEventHandlers(removeMethod); + } + + // Returns the total cache size + // Used by test only to verify we don't leak event cache + internal static int GetRegistrationTokenCacheSize() + { + int count = 0; + + if (ManagedEventRegistrationImpl.s_eventRegistrations != null) + { + lock (ManagedEventRegistrationImpl.s_eventRegistrations) + { + count += ManagedEventRegistrationImpl.s_eventRegistrations.Keys.Count; + } + } + + if (NativeOrStaticEventRegistrationImpl.s_eventRegistrations != null) + { + lock (NativeOrStaticEventRegistrationImpl.s_eventRegistrations) + { + count += NativeOrStaticEventRegistrationImpl.s_eventRegistrations.Count; + } + } + + return count; + } + + // + // Optimized version of List of EventRegistrationToken + // It is made a struct to reduce overhead + // + internal struct EventRegistrationTokenList + { + private EventRegistrationToken firstToken; // Optimization for common case where there is only one token + private List<EventRegistrationToken> restTokens; // Rest of the tokens + + internal EventRegistrationTokenList(EventRegistrationToken token) + { + firstToken = token; + restTokens = null; + } + + internal EventRegistrationTokenList(EventRegistrationTokenList list) + { + firstToken = list.firstToken; + restTokens = list.restTokens; + } + + // Push a new token into this list + // Returns true if you need to copy back this list into the dictionary (so that you + // don't lose change outside the dictionary). false otherwise. + public bool Push(EventRegistrationToken token) + { + bool needCopy = false; + + if (restTokens == null) + { + restTokens = new List<EventRegistrationToken>(); + needCopy = true; + } + + restTokens.Add(token); + + return needCopy; + } + + // Pops the last token + // Returns false if no more tokens left, true otherwise + public bool Pop(out EventRegistrationToken token) + { + // Only 1 token in this list and we just removed the last token + if (restTokens == null || restTokens.Count == 0) + { + token = firstToken; + return false; + } + + int last = restTokens.Count - 1; + token = restTokens[last]; + restTokens.RemoveAt(last); + + return true; + } + + public void CopyTo(List<EventRegistrationToken> tokens) + { + tokens.Add(firstToken); + if (restTokens != null) + tokens.AddRange(restTokens); + } + } + + // + // Event registration support for managed objects events & static events + // + internal static class ManagedEventRegistrationImpl + { + // Mappings of delegates registered for events -> their registration tokens. + // These mappings are stored indexed by the remove method which can be used to undo the registrations. + // + // The full structure of this table is: + // object the event is being registered on -> + // Table [RemoveMethod] -> + // Table [Handler] -> Token + // + // Note: There are a couple of optimizations I didn't do here because they don't make sense for managed events: + // 1. Flatten the event cache (see EventCacheKey in native WinRT event implementation below) + // + // This is because managed events use ConditionalWeakTable to hold Objects->(Event->(Handler->Tokens)), + // and when object goes away everything else will be nicely cleaned up. If I flatten it like native WinRT events, + // I'll have to use Dictionary (as ConditionalWeakTable won't work - nobody will hold the new key alive anymore) + // instead, and that means I'll have to add more code from native WinRT events into managed WinRT event to support + // self-cleanup in the finalization, as well as reader/writer lock to protect against race conditions in the finalization, + // which adds a lot more complexity and doesn't really worth it. + // + // 2. Use conditionalWeakTable to hold Handler->Tokens. + // + // The reason is very simple - managed object use dictionary (see EventRegistrationTokenTable) to hold delegates alive. + // If the delegates aren't alive, it means either they have been unsubscribed, or the object itself is gone, + // and in either case, they've been already taken care of. + // + internal volatile static + ConditionalWeakTable<object, Dictionary<MethodInfo, Dictionary<object, EventRegistrationTokenList>>> s_eventRegistrations = + new ConditionalWeakTable<object, Dictionary<MethodInfo, Dictionary<object, EventRegistrationTokenList>>>(); + + [SecurityCritical] + internal static void AddEventHandler<T>(Func<T, EventRegistrationToken> addMethod, + Action<EventRegistrationToken> removeMethod, + T handler) + { + Contract.Requires(addMethod != null); + Contract.Requires(removeMethod != null); + + // Add the method, and make a note of the token -> delegate mapping. + object instance = removeMethod.Target; + Dictionary<object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod); + EventRegistrationToken token = addMethod(handler); + lock (registrationTokens) + { + EventRegistrationTokenList tokens; + if (!registrationTokens.TryGetValue(handler, out tokens)) + { + tokens = new EventRegistrationTokenList(token); + registrationTokens[handler] = tokens; + } + else + { + bool needCopy = tokens.Push(token); + + // You need to copy back this list into the dictionary (so that you don't lose change outside dictionary) + if (needCopy) + registrationTokens[handler] = tokens; + } + + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event subscribed for managed instance = " + instance + ", handler = " + handler + "\n"); + } + } + + // Get the event registration token table for an event. These are indexed by the remove method of the event. + private static Dictionary<object, EventRegistrationTokenList> GetEventRegistrationTokenTable(object instance, Action<EventRegistrationToken> removeMethod) + { + Contract.Requires(instance != null); + Contract.Requires(removeMethod != null); + Contract.Requires(s_eventRegistrations != null); + + lock (s_eventRegistrations) + { + Dictionary<MethodInfo, Dictionary<object, EventRegistrationTokenList>> instanceMap = null; + if (!s_eventRegistrations.TryGetValue(instance, out instanceMap)) + { + instanceMap = new Dictionary<MethodInfo, Dictionary<object, EventRegistrationTokenList>>(); + s_eventRegistrations.Add(instance, instanceMap); + } + + Dictionary<object, EventRegistrationTokenList> tokens = null; + if (!instanceMap.TryGetValue(removeMethod.Method, out tokens)) + { + tokens = new Dictionary<object, EventRegistrationTokenList>(); + instanceMap.Add(removeMethod.Method, tokens); + } + + return tokens; + } + } + + [SecurityCritical] + internal static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler) + { + Contract.Requires(removeMethod != null); + + object instance = removeMethod.Target; + Dictionary<object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod); + EventRegistrationToken token; + + lock (registrationTokens) + { + EventRegistrationTokenList tokens; + + // Failure to find a registration for a token is not an error - it's simply a no-op. + if (!registrationTokens.TryGetValue(handler, out tokens)) + { + BCLDebug.Log("INTEROP", "[WinRT_Eventing] no registrationTokens found for instance=" + instance + ", handler= " + handler + "\n"); + + return; + } + + // Select a registration token to unregister + // We don't care which one but I'm returning the last registered token to be consistent + // with native event registration implementation + bool moreItems = tokens.Pop(out token); + if (!moreItems) + { + // Remove it from cache if this list become empty + // This must be done because EventRegistrationTokenList now becomes invalid + // (mostly because there is no safe default value for EventRegistrationToken to express 'no token') + // NOTE: We should try to remove registrationTokens itself from cache if it is empty, otherwise + // we could run into a race condition where one thread removes it from cache and another thread adds + // into the empty registrationToken table + registrationTokens.Remove(handler); + } + } + + removeMethod(token); + + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for managed instance = " + instance + ", handler = " + handler + ", token = " + token.m_value + "\n"); + } + + [SecurityCritical] + internal static void RemoveAllEventHandlers(Action<EventRegistrationToken> removeMethod) + { + Contract.Requires(removeMethod != null); + + object instance = removeMethod.Target; + Dictionary<object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod); + + List<EventRegistrationToken> tokensToRemove = new List<EventRegistrationToken>(); + + lock (registrationTokens) + { + // Copy all tokens to tokensToRemove array which later we'll call removeMethod on + // outside this lock + foreach (EventRegistrationTokenList tokens in registrationTokens.Values) + { + tokens.CopyTo(tokensToRemove); + } + + // Clear the dictionary - at this point all event handlers are no longer in the cache + // but they are not removed yet + registrationTokens.Clear(); + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Cache cleared for managed instance = " + instance + "\n"); + } + + // + // Remove all handlers outside the lock + // + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Start removing all events for instance = " + instance + "\n"); + CallRemoveMethods(removeMethod, tokensToRemove); + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finished removing all events for instance = " + instance + "\n"); + } + } + + // + // WinRT event registration implementation code + // + internal static class NativeOrStaticEventRegistrationImpl + { + // + // Key = (target object, event) + // We use a key of object+event to save an extra dictionary + // + internal struct EventCacheKey + { + internal object target; + internal MethodInfo method; + + public override string ToString() + { + return "(" + target + ", " + method + ")"; + } + } + + internal class EventCacheKeyEqualityComparer : IEqualityComparer<EventCacheKey> + { + public bool Equals(EventCacheKey lhs, EventCacheKey rhs) + { + return (Object.Equals(lhs.target, rhs.target) && Object.Equals(lhs.method, rhs.method)); + } + + public int GetHashCode(EventCacheKey key) + { + return key.target.GetHashCode() ^ key.method.GetHashCode(); + } + } + + // + // EventRegistrationTokenListWithCount + // + // A list of EventRegistrationTokens that maintains a count + // + // The reason this needs to be a separate class is that we need a finalizer for this class + // If the delegate is collected, it will take this list away with it (due to dependent handles), + // and we need to remove the PerInstancEntry from cache + // See ~EventRegistrationTokenListWithCount for more details + // + internal class EventRegistrationTokenListWithCount + { + private TokenListCount _tokenListCount; + EventRegistrationTokenList _tokenList; + + internal EventRegistrationTokenListWithCount(TokenListCount tokenListCount, EventRegistrationToken token) + { + _tokenListCount = tokenListCount; + _tokenListCount.Inc(); + + _tokenList = new EventRegistrationTokenList(token); + } + + ~EventRegistrationTokenListWithCount() + { + // Decrement token list count + // This is need to correctly keep trace of number of tokens for EventCacheKey + // and remove it from cache when the token count drop to 0 + // we don't need to take locks for decrement the count - we only need to take a global + // lock when we decide to destroy cache for the IUnknown */type instance + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finalizing EventRegistrationTokenList for " + _tokenListCount.Key + "\n"); + _tokenListCount.Dec(); + } + + public void Push(EventRegistrationToken token) + { + // Since EventRegistrationTokenListWithCount is a reference type, there is no need + // to copy back. Ignore the return value + _tokenList.Push(token); + } + + public bool Pop(out EventRegistrationToken token) + { + return _tokenList.Pop(out token); + } + + public void CopyTo(List<EventRegistrationToken> tokens) + { + _tokenList.CopyTo(tokens); + } + } + + // + // Maintains the number of tokens for a particular EventCacheKey + // TokenListCount is a class for two reasons: + // 1. Efficient update in the Dictionary to avoid lookup twice to update the value + // 2. Update token count without taking a global lock. Only takes a global lock when drop to 0 + // + internal class TokenListCount + { + private int _count; + private EventCacheKey _key; + + internal TokenListCount(EventCacheKey key) + { + _key = key; + } + + internal EventCacheKey Key + { + + get { return _key; } + } + + internal void Inc() + { + int newCount = Interlocked.Increment(ref _count); + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Incremented TokenListCount for " + _key + ", Value = " + newCount + "\n"); + } + + internal void Dec() + { + // Avoid racing with Add/Remove event entries into the cache + // You don't want this removing the key in the middle of a Add/Remove + s_eventCacheRWLock.AcquireWriterLock(Timeout.Infinite); + try + { + int newCount = Interlocked.Decrement(ref _count); + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Decremented TokenListCount for " + _key + ", Value = " + newCount + "\n"); + if (newCount == 0) + CleanupCache(); + } + finally + { + s_eventCacheRWLock.ReleaseWriterLock(); + } + } + + private void CleanupCache() + { + // Time to destroy cache for this IUnknown */type instance + // because the total token list count has dropped to 0 and we don't have any events subscribed + Contract.Requires(s_eventRegistrations != null); + + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Removing " + _key + " from cache" + "\n"); + s_eventRegistrations.Remove(_key); + BCLDebug.Log("INTEROP", "[WinRT_Eventing] s_eventRegistrations size = " + s_eventRegistrations.Count + "\n"); + } + } + + internal struct EventCacheEntry + { + // [Handler] -> Token + internal ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTable; + + // Maintains current total count for the EventRegistrationTokenListWithCount for this event cache key + internal TokenListCount tokenListCount; + } + + // Mappings of delegates registered for events -> their registration tokens. + // These mappings are stored indexed by the remove method which can be used to undo the registrations. + // + // The full structure of this table is: + // EventCacheKey (instanceKey, eventMethod) -> EventCacheEntry (Handler->tokens) + // + // A InstanceKey is the IUnknown * or static type instance + // + // Couple of things to note: + // 1. We need to use IUnknown* because we want to be able to unscribe to the event for another RCW + // based on the same COM object. For example: + // m_canvas.GetAt(0).Event += Func; + // m_canvas.GetAt(0).Event -= Func; // GetAt(0) might create a new RCW + // + // 2. Handler->Token is a ConditionalWeakTable because we don't want to keep the delegate alive + // and we want EventRegistrationTokenListWithCount to be finalized after the delegate is no longer alive + // 3. It is possible another COM object is created at the same address + // before the entry in cache is destroyed. More specifically, + // a. The same delegate is being unsubscribed. In this case we'll give them a + // stale token - unlikely to be a problem + // b. The same delegate is subscribed then unsubscribed. We need to make sure give + // them the latest token in this case. This is guaranteed by always giving the last token and always use equality to + // add/remove event handlers + internal volatile static Dictionary<EventCacheKey, EventCacheEntry> s_eventRegistrations = + new Dictionary<EventCacheKey, EventCacheEntry>(new EventCacheKeyEqualityComparer()); + + // Prevent add/remove handler code to run at the same with with cache cleanup code + private volatile static MyReaderWriterLock s_eventCacheRWLock = new MyReaderWriterLock(); + + // Get InstanceKey to use in the cache + [SecuritySafeCritical] + private static object GetInstanceKey(Action<EventRegistrationToken> removeMethod) + { + object target = removeMethod.Target; + Contract.Assert(target == null || Marshal.IsComObject(target), "Must be null or a RCW"); + if (target == null) + return removeMethod.Method.DeclaringType; + + // Need the "Raw" IUnknown pointer for the RCW that is not bound to the current context + return (object) Marshal.GetRawIUnknownForComObjectNoAddRef(target); + } + + [SecurityCritical] + internal static void AddEventHandler<T>(Func<T, EventRegistrationToken> addMethod, + Action<EventRegistrationToken> removeMethod, + T handler) + { + // The instanceKey will be IUnknown * of the target object + object instanceKey = GetInstanceKey(removeMethod); + + // Call addMethod outside of RW lock + // At this point we don't need to worry about race conditions and we can avoid deadlocks + // if addMethod waits on finalizer thread + // If we later throw we need to remove the method + EventRegistrationToken token = addMethod(handler); + + bool tokenAdded = false; + + try + { + EventRegistrationTokenListWithCount tokens; + + // + // The whole add/remove code has to be protected by a reader/writer lock + // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time + // + s_eventCacheRWLock.AcquireReaderLock(Timeout.Infinite); + try + { + // Add the method, and make a note of the delegate -> token mapping. + TokenListCount tokenListCount; + ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTokens = GetOrCreateEventRegistrationTokenTable(instanceKey, removeMethod, out tokenListCount); + lock (registrationTokens) + { + // + // We need to find the key that equals to this handler + // Suppose we have 3 handlers A, B, C that are equal (refer to the same object and method), + // the first handler (let's say A) will be used as the key and holds all the tokens. + // We don't need to hold onto B and C, because the COM object itself will keep them alive, + // and they won't die anyway unless the COM object dies or they get unsubscribed. + // It may appear that it is fine to hold A, B, C, and add them and their corresponding tokens + // into registrationTokens table. However, this is very dangerous, because this COM object + // may die, but A, B, C might not get collected yet, and another COM object comes into life + // with the same IUnknown address, and we subscribe event B. In this case, the right token + // will be added into B's token list, but once we unsubscribe B, we might end up removing + // the last token in C, and that may lead to crash. + // + object key = registrationTokens.FindEquivalentKeyUnsafe(handler, out tokens); + if (key == null) + { + tokens = new EventRegistrationTokenListWithCount(tokenListCount, token); + registrationTokens.Add(handler, tokens); + } + else + { + tokens.Push(token); + } + + tokenAdded = true; + } + } + finally + { + s_eventCacheRWLock.ReleaseReaderLock(); + } + + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event subscribed for instance = " + instanceKey + ", handler = " + handler + "\n"); + } + catch(Exception) + { + // If we've already added the token and go there, we don't need to "UNDO" anything + if (!tokenAdded) + { + // Otherwise, "Undo" addMethod if any exception occurs + // There is no need to cleanup our data structure as we haven't added the token yet + removeMethod(token); + } + + + throw; + } + } + + private static ConditionalWeakTable<object, EventRegistrationTokenListWithCount> GetEventRegistrationTokenTableNoCreate(object instance, Action<EventRegistrationToken> removeMethod, out TokenListCount tokenListCount) + { + Contract.Requires(instance != null); + Contract.Requires(removeMethod != null); + + return GetEventRegistrationTokenTableInternal(instance, removeMethod, out tokenListCount, /* createIfNotFound = */ false); + } + + private static ConditionalWeakTable<object, EventRegistrationTokenListWithCount> GetOrCreateEventRegistrationTokenTable(object instance, Action<EventRegistrationToken> removeMethod, out TokenListCount tokenListCount) + { + Contract.Requires(instance != null); + Contract.Requires(removeMethod != null); + + return GetEventRegistrationTokenTableInternal(instance, removeMethod, out tokenListCount, /* createIfNotFound = */ true); + } + + // Get the event registration token table for an event. These are indexed by the remove method of the event. + private static ConditionalWeakTable<object, EventRegistrationTokenListWithCount> GetEventRegistrationTokenTableInternal(object instance, Action<EventRegistrationToken> removeMethod, out TokenListCount tokenListCount, bool createIfNotFound) + { + Contract.Requires(instance != null); + Contract.Requires(removeMethod != null); + Contract.Requires(s_eventRegistrations != null); + + EventCacheKey eventCacheKey; + eventCacheKey.target = instance; + eventCacheKey.method = removeMethod.Method; + + lock (s_eventRegistrations) + { + EventCacheEntry eventCacheEntry; + if (!s_eventRegistrations.TryGetValue(eventCacheKey, out eventCacheEntry)) + { + if (!createIfNotFound) + { + // No need to create an entry in this case + tokenListCount = null; + return null; + } + + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Adding (" + instance + "," + removeMethod.Method + ") into cache" + "\n"); + + eventCacheEntry = new EventCacheEntry(); + eventCacheEntry.registrationTable = new ConditionalWeakTable<object, EventRegistrationTokenListWithCount>(); + eventCacheEntry.tokenListCount = new TokenListCount(eventCacheKey); + + s_eventRegistrations.Add(eventCacheKey, eventCacheEntry); + } + + tokenListCount = eventCacheEntry.tokenListCount; + + return eventCacheEntry.registrationTable; + } + } + + [SecurityCritical] + internal static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler) + { + object instanceKey = GetInstanceKey(removeMethod); + + EventRegistrationToken token; + + // + // The whole add/remove code has to be protected by a reader/writer lock + // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time + // + s_eventCacheRWLock.AcquireReaderLock(Timeout.Infinite); + try + { + TokenListCount tokenListCount; + ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTokens = GetEventRegistrationTokenTableNoCreate(instanceKey, removeMethod, out tokenListCount); + if (registrationTokens == null) + { + // We have no information regarding this particular instance (IUnknown*/type) - just return + // This is necessary to avoid leaking empty dictionary/conditionalWeakTables for this instance + BCLDebug.Log("INTEROP", "[WinRT_Eventing] no registrationTokens found for instance=" + instanceKey + ", handler= " + handler + "\n"); + return; + } + + lock (registrationTokens) + { + EventRegistrationTokenListWithCount tokens; + + // Note: + // When unsubscribing events, we allow subscribing the event using a different delegate + // (but with the same object/method), so we need to find the first delegate that matches + // and unsubscribe it + // It actually doesn't matter which delegate - as long as it matches + // Note that inside TryGetValueWithValueEquality we assumes that any delegate + // with the same value equality would have the same hash code + object key = registrationTokens.FindEquivalentKeyUnsafe(handler, out tokens); + Contract.Assert((key != null && tokens != null) || (key == null && tokens == null), + "key and tokens must be both null or non-null"); + if (tokens == null) + { + // Failure to find a registration for a token is not an error - it's simply a no-op. + BCLDebug.Log("INTEROP", "[WinRT_Eventing] no token list found for instance=" + instanceKey + ", handler= " + handler + "\n"); + return; + } + + // Select a registration token to unregister + // Note that we need to always get the last token just in case another COM object + // is created at the same address before the entry for the old one goes away. + // See comments above s_eventRegistrations for more details + bool moreItems = tokens.Pop(out token); + + // If the last token is removed from token list, we need to remove it from the cache + // otherwise FindEquivalentKeyUnsafe may found this empty token list even though there could be other + // equivalent keys in there with non-0 token list + if (!moreItems) + { + // Remove it from (handler)->(tokens) + // NOTE: We should not check whether registrationTokens has 0 entries and remove it from the cache + // (just like managed event implementation), because this might have raced with the finalizer of + // EventRegistrationTokenList + registrationTokens.Remove(key); + } + + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for managed instance = " + instanceKey + ", handler = " + handler + ", token = " + token.m_value + "\n"); + } + } + finally + { + s_eventCacheRWLock.ReleaseReaderLock(); + } + + // Call removeMethod outside of RW lock + // At this point we don't need to worry about race conditions and we can avoid deadlocks + // if removeMethod waits on finalizer thread + removeMethod(token); + } + + [SecurityCritical] + internal static void RemoveAllEventHandlers(Action<EventRegistrationToken> removeMethod) + { + object instanceKey = GetInstanceKey(removeMethod); + + List<EventRegistrationToken> tokensToRemove = new List<EventRegistrationToken>(); + + // + // The whole add/remove code has to be protected by a reader/writer lock + // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time + // + s_eventCacheRWLock.AcquireReaderLock(Timeout.Infinite); + try + { + TokenListCount tokenListCount; + ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTokens = GetEventRegistrationTokenTableNoCreate(instanceKey, removeMethod, out tokenListCount); + if (registrationTokens == null) + { + // We have no information regarding this particular instance (IUnknown*/type) - just return + // This is necessary to avoid leaking empty dictionary/conditionalWeakTables for this instance + return; + } + + lock (registrationTokens) + { + // Copy all tokens to tokensToRemove array which later we'll call removeMethod on + // outside this lock + foreach (EventRegistrationTokenListWithCount tokens in registrationTokens.Values) + { + tokens.CopyTo(tokensToRemove); + } + + // Clear the table - at this point all event handlers are no longer in the cache + // but they are not removed yet + registrationTokens.Clear(); + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Cache cleared for managed instance = " + instanceKey + "\n"); + } + } + finally + { + s_eventCacheRWLock.ReleaseReaderLock(); + } + + // + // Remove all handlers outside the lock + // + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Start removing all events for instance = " + instanceKey + "\n"); + CallRemoveMethods(removeMethod, tokensToRemove); + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finished removing all events for instance = " + instanceKey + "\n"); + } + + + internal class ReaderWriterLockTimedOutException : ApplicationException + { + } + + /// I borrowed Vance's reader writer lock implementation from his blog as ReaderWriterLockSlim is + /// available in System.Core.dll! + /// + /// <summary> + /// A reader-writer lock implementation that is intended to be simple, yet very + /// efficient. In particular only 1 interlocked operation is taken for any lock + /// operation (we use spin locks to achieve this). The spin lock is never held + /// for more than a few instructions (in particular, we never call event APIs + /// or in fact any non-trivial API while holding the spin lock). + /// + /// Currently this ReaderWriterLock does not support recurision, however it is + /// not hard to add + /// </summary> + internal class MyReaderWriterLock + { + // Lock specifiation for myLock: This lock protects exactly the local fields associted + // instance of MyReaderWriterLock. It does NOT protect the memory associted with the + // the events that hang off this lock (eg writeEvent, readEvent upgradeEvent). + int myLock; + + // Who owns the lock owners > 0 => readers + // owners = -1 means there is one writer. Owners must be >= -1. + int owners; + + // These variables allow use to avoid Setting events (which is expensive) if we don't have to. + uint numWriteWaiters; // maximum number of threads that can be doing a WaitOne on the writeEvent + uint numReadWaiters; // maximum number of threads that can be doing a WaitOne on the readEvent + + // conditions we wait on. + EventWaitHandle writeEvent; // threads waiting to aquire a write lock go here. + EventWaitHandle readEvent; // threads waiting to aquire a read lock go here (will be released in bulk) + + internal MyReaderWriterLock() + { + // All state can start out zeroed. + } + + internal void AcquireReaderLock(int millisecondsTimeout) + { + EnterMyLock(); + for (; ; ) + { + // We can enter a read lock if there are only read-locks have been given out + // and a writer is not trying to get in. + if (owners >= 0 && numWriteWaiters == 0) + { + // Good case, there is no contention, we are basically done + owners++; // Indicate we have another reader + break; + } + + // Drat, we need to wait. Mark that we have waiters and wait. + if (readEvent == null) // Create the needed event + { + LazyCreateEvent(ref readEvent, false); + continue; // since we left the lock, start over. + } + + WaitOnEvent(readEvent, ref numReadWaiters, millisecondsTimeout); + } + ExitMyLock(); + } + + internal void AcquireWriterLock(int millisecondsTimeout) + { + EnterMyLock(); + for (; ; ) + { + if (owners == 0) + { + // Good case, there is no contention, we are basically done + owners = -1; // indicate we have a writer. + break; + } + + // Drat, we need to wait. Mark that we have waiters and wait. + if (writeEvent == null) // create the needed event. + { + LazyCreateEvent(ref writeEvent, true); + continue; // since we left the lock, start over. + } + + WaitOnEvent(writeEvent, ref numWriteWaiters, millisecondsTimeout); + } + ExitMyLock(); + } + + internal void ReleaseReaderLock() + { + EnterMyLock(); + Contract.Assert(owners > 0, "ReleasingReaderLock: releasing lock and no read lock taken"); + --owners; + ExitAndWakeUpAppropriateWaiters(); + } + + internal void ReleaseWriterLock() + { + EnterMyLock(); + Contract.Assert(owners == -1, "Calling ReleaseWriterLock when no write lock is held"); + owners++; + ExitAndWakeUpAppropriateWaiters(); + } + + /// <summary> + /// A routine for lazily creating a event outside the lock (so if errors + /// happen they are outside the lock and that we don't do much work + /// while holding a spin lock). If all goes well, reenter the lock and + /// set 'waitEvent' + /// </summary> + private void LazyCreateEvent(ref EventWaitHandle waitEvent, bool makeAutoResetEvent) { + Contract.Assert(myLock != 0, "Lock must be held"); + Contract.Assert(waitEvent == null, "Wait event must be null"); + + ExitMyLock(); + EventWaitHandle newEvent; + if (makeAutoResetEvent) + newEvent = new AutoResetEvent(false); + else + newEvent = new ManualResetEvent(false); + EnterMyLock(); + if (waitEvent == null) // maybe someone snuck in. + waitEvent = newEvent; + } + + /// <summary> + /// Waits on 'waitEvent' with a timeout of 'millisceondsTimeout. + /// Before the wait 'numWaiters' is incremented and is restored before leaving this routine. + /// </summary> + private void WaitOnEvent(EventWaitHandle waitEvent, ref uint numWaiters, int millisecondsTimeout) + { + Contract.Assert(myLock != 0, "Lock must be held"); + + waitEvent.Reset(); + numWaiters++; + + bool waitSuccessful = false; + ExitMyLock(); // Do the wait outside of any lock + try + { + if (!waitEvent.WaitOne(millisecondsTimeout, false)) + throw new ReaderWriterLockTimedOutException(); + + waitSuccessful = true; + } + finally + { + EnterMyLock(); + --numWaiters; + if (!waitSuccessful) // We are going to throw for some reason. Exit myLock. + ExitMyLock(); + } + } + + /// <summary> + /// Determines the appropriate events to set, leaves the locks, and sets the events. + /// </summary> + private void ExitAndWakeUpAppropriateWaiters() + { + Contract.Assert(myLock != 0, "Lock must be held"); + + if (owners == 0 && numWriteWaiters > 0) + { + ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock) + writeEvent.Set(); // release one writer. + } + else if (owners >= 0 && numReadWaiters != 0) + { + ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock) + readEvent.Set(); // release all readers. + } + else + ExitMyLock(); + } + + private void EnterMyLock() { + if (Interlocked.CompareExchange(ref myLock, 1, 0) != 0) + EnterMyLockSpin(); + } + + private void EnterMyLockSpin() + { + for (int i = 0; ;i++) + { + if (i < 3 && Environment.ProcessorCount > 1) + Thread.SpinWait(20); // Wait a few dozen instructions to let another processor release lock. + else + Thread.Sleep(0); // Give up my quantum. + + if (Interlocked.CompareExchange(ref myLock, 1, 0) == 0) + return; + } + } + private void ExitMyLock() + { + Contract.Assert(myLock != 0, "Exiting spin lock that is not held"); + myLock = 0; + } + }; + } + + // + // Call removeMethod on each token and aggregate all exceptions thrown from removeMethod into one in case of failure + // + internal static void CallRemoveMethods(Action<EventRegistrationToken> removeMethod, List<EventRegistrationToken> tokensToRemove) + { + + List<Exception> exceptions = new List<Exception>(); + + foreach (EventRegistrationToken token in tokensToRemove) + { + try + { + removeMethod(token); + } + catch(Exception ex) + { + exceptions.Add(ex); + } + + BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for token = " + token.m_value + "\n"); + } + + if (exceptions.Count > 0) + throw new AggregateException(exceptions.ToArray()); + } + + [SecurityCritical] + internal static unsafe string HStringToString(IntPtr hstring) + { + Contract.Requires(Environment.IsWinRTSupported); + + // There is no difference between a null and empty HSTRING + if (hstring == IntPtr.Zero) + { + return String.Empty; + } + + unsafe + { + uint length; + char* rawBuffer = UnsafeNativeMethods.WindowsGetStringRawBuffer(hstring, &length); + return new String(rawBuffer, 0, checked((int)length)); + } + } + + internal static Exception GetExceptionForHR(int hresult, Exception innerException, string messageResource) + { + Exception e = null; + if (innerException != null) + { + string message = innerException.Message; + if (message == null && messageResource != null) + { + message = Environment.GetResourceString(messageResource); + } + e = new Exception(message, innerException); + } + else + { + string message = (messageResource != null ? Environment.GetResourceString(messageResource) : null); + e = new Exception(message); + } + + e.SetErrorCode(hresult); + return e; + } + + internal static Exception GetExceptionForHR(int hresult, Exception innerException) + { + return GetExceptionForHR(hresult, innerException, null); + } + + private static bool s_haveBlueErrorApis = true; + + [SecurityCritical] + private static bool RoOriginateLanguageException(int error, string message, IntPtr languageException) + { + if (s_haveBlueErrorApis) + { + try + { + return UnsafeNativeMethods.RoOriginateLanguageException(error, message, languageException); + } + catch (EntryPointNotFoundException) + { + s_haveBlueErrorApis = false; + } + } + + return false; + } + + [SecurityCritical] + private static void RoReportUnhandledError(IRestrictedErrorInfo error) + { + if (s_haveBlueErrorApis) + { + try + { + UnsafeNativeMethods.RoReportUnhandledError(error); + } + catch (EntryPointNotFoundException) + { + s_haveBlueErrorApis = false; + } + } + } + + private static Guid s_iidIErrorInfo = new Guid(0x1CF2B120, 0x547D, 0x101B, 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19); + + /// <summary> + /// Report that an exception has occured which went user unhandled. This allows the global error handler + /// for the application to be invoked to process the error. + /// </summary> + /// <returns>true if the error was reported, false if not (ie running on Win8)</returns> + [FriendAccessAllowed] + [SecuritySafeCritical] + internal static bool ReportUnhandledError(Exception e) + { + // Only report to the WinRT global exception handler in modern apps + if (!AppDomain.IsAppXModel()) + { + return false; + } + + // If we don't have the capability to report to the global error handler, early out + if (!s_haveBlueErrorApis) + { + return false; + } + + if (e != null) + { + IntPtr exceptionIUnknown = IntPtr.Zero; + IntPtr exceptionIErrorInfo = IntPtr.Zero; + try + { + // Get an IErrorInfo for the current exception and originate it as a langauge error in order to have + // Windows generate an IRestrictedErrorInfo corresponding to the exception object. We can then + // notify the global error handler that this IRestrictedErrorInfo instance represents an exception that + // went unhandled in managed code. + // + // Note that we need to get an IUnknown for the exception object and then QI for IErrorInfo since Exception + // doesn't implement IErrorInfo in managed code - only its CCW does. + exceptionIUnknown = Marshal.GetIUnknownForObject(e); + if (exceptionIUnknown != IntPtr.Zero) + { + Marshal.QueryInterface(exceptionIUnknown, ref s_iidIErrorInfo, out exceptionIErrorInfo); + if (exceptionIErrorInfo != IntPtr.Zero) + { + if (RoOriginateLanguageException(Marshal.GetHRForException_WinRT(e), e.Message, exceptionIErrorInfo)) + { + IRestrictedErrorInfo restrictedError = UnsafeNativeMethods.GetRestrictedErrorInfo(); + if (restrictedError != null) + { + RoReportUnhandledError(restrictedError); + return true; + } + } + } + } + } + finally + { + if (exceptionIErrorInfo != IntPtr.Zero) + { + Marshal.Release(exceptionIErrorInfo); + } + + if (exceptionIUnknown != IntPtr.Zero) + { + Marshal.Release(exceptionIUnknown); + } + } + } + + // If we got here, then some step of the marshaling failed, which means the GEH was not invoked + return false; + } + +#if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION + // Get an IActivationFactory * for a managed type + [SecurityCritical] + internal static IntPtr GetActivationFactoryForType(Type type) + { + ManagedActivationFactory activationFactory = GetManagedActivationFactory(type); + return Marshal.GetComInterfaceForObject(activationFactory, typeof(IActivationFactory)); + } + + [SecurityCritical] + internal static ManagedActivationFactory GetManagedActivationFactory(Type type) + { + ManagedActivationFactory activationFactory = new ManagedActivationFactory(type); + + // If the type has any associated factory interfaces (i.e. supports non-default activation + // or has statics), the CCW for this instance of ManagedActivationFactory must support them. + Marshal.InitializeManagedWinRTFactoryObject(activationFactory, (RuntimeType)type); + return activationFactory; + } + +#if FEATURE_COMINTEROP_WINRT_DESKTOP_HOST + // Currently we use only a single class activator since we have a requirement that all class activations come from the same + // app base and we haven't sorted through the various code sharing implications of spinning up multiple AppDomains. This + // holds the IWinRTClassActivator* that is used for the process + private static IntPtr s_pClassActivator = IntPtr.Zero; + + [SecurityCritical] + internal static IntPtr GetClassActivatorForApplication(string appBase) + { + if (s_pClassActivator == IntPtr.Zero) + { + AppDomainSetup hostDomainSetup = new AppDomainSetup() + { + ApplicationBase = appBase, + }; + + AppDomain hostDomain = AppDomain.CreateDomain(Environment.GetResourceString("WinRTHostDomainName", appBase), null, hostDomainSetup); + WinRTClassActivator activator = (WinRTClassActivator)hostDomain.CreateInstanceAndUnwrap(typeof(WinRTClassActivator).Assembly.FullName, typeof(WinRTClassActivator).FullName); + IntPtr pActivator = activator.GetIWinRTClassActivator(); + + if (Interlocked.CompareExchange(ref s_pClassActivator, pActivator, IntPtr.Zero) != IntPtr.Zero) + { + Marshal.Release(pActivator); + activator = null; + + try + { + AppDomain.Unload(hostDomain); + } + catch (CannotUnloadAppDomainException) { } + } + } + + Marshal.AddRef(s_pClassActivator); + return s_pClassActivator; + } +#endif // FEATURE_COMINTEROP_WINRT_DESKTOP_HOST + +#endif // FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION + + // + // Get activation factory object for a specified WinRT type + // If the WinRT type is a native type, we'll always create a unique RCW for it, + // This is necessary because WinRT factories are often implemented as a singleton, + // and getting back a RCW for such WinRT factory would usually get back a RCW from + // another apartment, even if the interface pointe returned from GetActivationFactory + // is a raw pointer. As a result, user would randomly get back RCWs for activation + // factories from other apartments and make transiton to those apartments and cause + // deadlocks and create objects in incorrect apartments + // + [SecurityCritical] + public static IActivationFactory GetActivationFactory(Type type) + { + if (type == null) + throw new ArgumentNullException("type"); + + if (type.IsWindowsRuntimeObject && type.IsImport) + { + return (IActivationFactory)Marshal.GetNativeActivationFactory(type); + } + else + { +#if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION + return GetManagedActivationFactory(type); +#else + // Managed factories are not supported so as to minimize public surface (and test effort) + throw new NotSupportedException(); +#endif + } + } + + // HSTRING marshaling methods: + + [SecurityCritical] + public static IntPtr StringToHString(String s) + { + if (!Environment.IsWinRTSupported) + throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_WinRT")); + + if (s == null) + throw new ArgumentNullException("s"); + + unsafe + { + IntPtr hstring; + int hrCreate = UnsafeNativeMethods.WindowsCreateString(s, s.Length, &hstring); + Marshal.ThrowExceptionForHR(hrCreate, new IntPtr(-1)); + return hstring; + } + } + + [SecurityCritical] + public static String PtrToStringHString(IntPtr ptr) + { + if (!Environment.IsWinRTSupported) + { + throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_WinRT")); + } + + return HStringToString(ptr); + } + + [SecurityCritical] + public static void FreeHString(IntPtr ptr) + { + if (!Environment.IsWinRTSupported) + throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_WinRT")); + + if (ptr != IntPtr.Zero) + { + UnsafeNativeMethods.WindowsDeleteString(ptr); + } + } + } +} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeMetadata.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeMetadata.cs new file mode 100644 index 0000000000..5fe3bdde08 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeMetadata.cs @@ -0,0 +1,215 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Diagnostics.Contracts; + using System.Reflection; + using System.Reflection.Emit; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using System.Security; + + public static class WindowsRuntimeMetadata + { + // Wrapper for Win8 API RoResolveNamespace with default Windows SDK path as installed .winmd files in %WINDIR%\system32\WinMetadata. + [System.Security.SecurityCritical] + public static IEnumerable<string> ResolveNamespace(string namespaceName, IEnumerable<string> packageGraphFilePaths) + { + return ResolveNamespace(namespaceName, null, packageGraphFilePaths); + } + + // Wrapper for Win8 API RoResolveNamespace. + [System.Security.SecurityCritical] + public static IEnumerable<string> ResolveNamespace(string namespaceName, string windowsSdkFilePath, IEnumerable<string> packageGraphFilePaths) + { + if (namespaceName == null) + throw new ArgumentNullException("namespaceName"); + Contract.EndContractBlock(); + + string[] packageGraphFilePathsArray = null; + if (packageGraphFilePaths != null) + { + List<string> packageGraphFilePathsList = new List<string>(packageGraphFilePaths); + packageGraphFilePathsArray = new string[packageGraphFilePathsList.Count]; + + int index = 0; + foreach (string packageGraphFilePath in packageGraphFilePathsList) + { + packageGraphFilePathsArray[index] = packageGraphFilePath; + index++; + } + } + + string[] retFileNames = null; + nResolveNamespace( + namespaceName, + windowsSdkFilePath, + packageGraphFilePathsArray, + ((packageGraphFilePathsArray == null) ? 0 : packageGraphFilePathsArray.Length), + JitHelpers.GetObjectHandleOnStack(ref retFileNames)); + + return retFileNames; + } + + [System.Security.SecurityCritical] + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + private extern static void nResolveNamespace( + string namespaceName, + string windowsSdkFilePath, + string[] packageGraphFilePaths, + int cPackageGraphFilePaths, + ObjectHandleOnStack retFileNames); + +#if FEATURE_REFLECTION_ONLY_LOAD + [method: System.Security.SecurityCritical] + public static event EventHandler<NamespaceResolveEventArgs> ReflectionOnlyNamespaceResolve; + + internal static RuntimeAssembly[] OnReflectionOnlyNamespaceResolveEvent(AppDomain appDomain, RuntimeAssembly assembly, string namespaceName) + { + EventHandler<NamespaceResolveEventArgs> eventHandler = ReflectionOnlyNamespaceResolve; + if (eventHandler != null) + { + Delegate[] ds = eventHandler.GetInvocationList(); + int len = ds.Length; + for (int i = 0; i < len; i++) + { + NamespaceResolveEventArgs eventArgs = new NamespaceResolveEventArgs(namespaceName, assembly); + + ((EventHandler<NamespaceResolveEventArgs>)ds[i])(appDomain, eventArgs); + + Collection<Assembly> assembliesCollection = eventArgs.ResolvedAssemblies; + if (assembliesCollection.Count > 0) + { + RuntimeAssembly[] retAssemblies = new RuntimeAssembly[assembliesCollection.Count]; + int retIndex = 0; + foreach (Assembly asm in assembliesCollection) + { + retAssemblies[retIndex] = AppDomain.GetRuntimeAssembly(asm); + retIndex++; + } + return retAssemblies; + } + } + } + + return null; + } +#endif //FEATURE_REFLECTION_ONLY + + [method: System.Security.SecurityCritical] + public static event EventHandler<DesignerNamespaceResolveEventArgs> DesignerNamespaceResolve; + + internal static string[] OnDesignerNamespaceResolveEvent(AppDomain appDomain, string namespaceName) + { + EventHandler<DesignerNamespaceResolveEventArgs> eventHandler = DesignerNamespaceResolve; + if (eventHandler != null) + { + Delegate[] ds = eventHandler.GetInvocationList(); + int len = ds.Length; + for (int i = 0; i < len; i++) + { + DesignerNamespaceResolveEventArgs eventArgs = new DesignerNamespaceResolveEventArgs(namespaceName); + + ((EventHandler<DesignerNamespaceResolveEventArgs>)ds[i])(appDomain, eventArgs); + + Collection<string> assemblyFilesCollection = eventArgs.ResolvedAssemblyFiles; + if (assemblyFilesCollection.Count > 0) + { + string[] retAssemblyFiles = new string[assemblyFilesCollection.Count]; + int retIndex = 0; + foreach (string assemblyFile in assemblyFilesCollection) + { + if (String.IsNullOrEmpty(assemblyFile)) + { // DesignerNamespaceResolve event returned null or empty file name - that is not allowed + throw new ArgumentException(Environment.GetResourceString("Arg_EmptyOrNullString"), "DesignerNamespaceResolveEventArgs.ResolvedAssemblyFiles"); + } + retAssemblyFiles[retIndex] = assemblyFile; + retIndex++; + } + + return retAssemblyFiles; + } + } + } + + return null; + } + } + +#if FEATURE_REFLECTION_ONLY_LOAD + [ComVisible(false)] + public class NamespaceResolveEventArgs : EventArgs + { + private string _NamespaceName; + private Assembly _RequestingAssembly; + private Collection<Assembly> _ResolvedAssemblies; + + public string NamespaceName + { + get + { + return _NamespaceName; + } + } + + public Assembly RequestingAssembly + { + get + { + return _RequestingAssembly; + } + } + + public Collection<Assembly> ResolvedAssemblies + { + get + { + return _ResolvedAssemblies; + } + } + + public NamespaceResolveEventArgs(string namespaceName, Assembly requestingAssembly) + { + _NamespaceName = namespaceName; + _RequestingAssembly = requestingAssembly; + _ResolvedAssemblies = new Collection<Assembly>(); + } + } +#endif //FEATURE_REFLECTION_ONLY + + [ComVisible(false)] + public class DesignerNamespaceResolveEventArgs : EventArgs + { + private string _NamespaceName; + private Collection<string> _ResolvedAssemblyFiles; + + public string NamespaceName + { + get + { + return _NamespaceName; + } + } + + public Collection<string> ResolvedAssemblyFiles + { + get + { + return _ResolvedAssemblyFiles; + } + } + + public DesignerNamespaceResolveEventArgs(string namespaceName) + { + _NamespaceName = namespaceName; + _ResolvedAssemblyFiles = new Collection<string>(); + } + } +} |