Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTijoy Tom Kalathiparambil <tijoytk@microsoft.com>2015-12-30 02:56:21 +0300
committerTijoy Tom Kalathiparambil <tijoytk@microsoft.com>2015-12-30 02:56:21 +0300
commitdb8fd94184c69e9e9307641f4ed860e388e55aef (patch)
tree2e6065419f094f5ac06541eaff80b73692cf8857 /src/System.Private.Interop
parent84b4f44572da69e07325e2b09988c1727cefdbff (diff)
Interop implementation for CoreRT , System.Private.Interop.dll along with MCG provide CoreRT interop support.
[tfs-changeset: 1560387]
Diffstat (limited to 'src/System.Private.Interop')
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.COM.Windows.cs195
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.Common.Unix.cs40
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.Common.Windows.cs61
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.Localization.Windows.cs141
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.Memory.Unix.cs27
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.Memory.Windows.cs74
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.PlatformNotSupported.cs50
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.String.Unix.cs58
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.String.Windows.cs123
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.Sync.Windows.cs61
-rw-r--r--src/System.Private.Interop/src/Interop/Interop.WinRT.cs112
-rw-r--r--src/System.Private.Interop/src/InteropCallbacks.cs34
-rw-r--r--src/System.Private.Interop/src/Resources/Strings.resx378
-rw-r--r--src/System.Private.Interop/src/Shared/ComCallableObject.cs1590
-rw-r--r--src/System.Private.Interop/src/Shared/ComException.cs48
-rw-r--r--src/System.Private.Interop/src/Shared/ComInterop.cs366
-rw-r--r--src/System.Private.Interop/src/Shared/DebugAnnotations.cs24
-rw-r--r--src/System.Private.Interop/src/Shared/Dictionary.cs1167
-rw-r--r--src/System.Private.Interop/src/Shared/DictionaryBase.cs234
-rw-r--r--src/System.Private.Interop/src/Shared/EventRegistrationToken.cs50
-rw-r--r--src/System.Private.Interop/src/Shared/FixedHashTable.cs299
-rw-r--r--src/System.Private.Interop/src/Shared/GCEventProvider.cs110
-rw-r--r--src/System.Private.Interop/src/Shared/HashSet.cs226
-rw-r--r--src/System.Private.Interop/src/Shared/InternalModule.cs223
-rw-r--r--src/System.Private.Interop/src/Shared/Interop.Manual.cs245
-rw-r--r--src/System.Private.Interop/src/Shared/List.cs406
-rw-r--r--src/System.Private.Interop/src/Shared/Marshal.cs48
-rw-r--r--src/System.Private.Interop/src/Shared/McgAccessorAttribute.cs33
-rw-r--r--src/System.Private.Interop/src/Shared/McgComCallableAttribute.cs13
-rw-r--r--src/System.Private.Interop/src/Shared/McgComHelpers.cs847
-rw-r--r--src/System.Private.Interop/src/Shared/McgData.cs1300
-rw-r--r--src/System.Private.Interop/src/Shared/McgGeneratedAssemblyAttribute.cs18
-rw-r--r--src/System.Private.Interop/src/Shared/McgGeneratedMarshallingCodeAttribute.cs21
-rw-r--r--src/System.Private.Interop/src/Shared/McgGeneratedNativeCallCodeAttribute.cs14
-rw-r--r--src/System.Private.Interop/src/Shared/McgHelpers.cs1739
-rw-r--r--src/System.Private.Interop/src/Shared/McgIntrinsics.cs556
-rw-r--r--src/System.Private.Interop/src/Shared/McgMarshal.cs1147
-rw-r--r--src/System.Private.Interop/src/Shared/McgMethodNameAttribute.cs21
-rw-r--r--src/System.Private.Interop/src/Shared/McgModule.cs1745
-rw-r--r--src/System.Private.Interop/src/Shared/McgModuleManager.cs1332
-rw-r--r--src/System.Private.Interop/src/Shared/McgPInvokeMarshalStubAttribute.cs24
-rw-r--r--src/System.Private.Interop/src/Shared/McgRedirectedTypeAttribute.cs13
-rw-r--r--src/System.Private.Interop/src/Shared/McgRemovedType.cs18
-rw-r--r--src/System.Private.Interop/src/Shared/McgRootsTypeAttribute.cs22
-rw-r--r--src/System.Private.Interop/src/Shared/McgTypeHelpers.cs750
-rw-r--r--src/System.Private.Interop/src/Shared/McgWindowsRuntimeVersionAttribute.cs25
-rw-r--r--src/System.Private.Interop/src/Shared/McgredirectedMethodAttribute.cs13
-rw-r--r--src/System.Private.Interop/src/Shared/RCWWalker.cs1320
-rw-r--r--src/System.Private.Interop/src/Shared/Readme.txt1
-rw-r--r--src/System.Private.Interop/src/Shared/SR.Get.cs24
-rw-r--r--src/System.Private.Interop/src/Shared/StandardInterfaces.cs1933
-rw-r--r--src/System.Private.Interop/src/Shared/StringPool.cs296
-rw-r--r--src/System.Private.Interop/src/Shared/WindowsRuntimeMarshal.cs1275
-rw-r--r--src/System.Private.Interop/src/Shared/__ComObject.cs3429
-rw-r--r--src/System.Private.Interop/src/System.Private.Interop.csproj215
-rw-r--r--src/System.Private.Interop/src/System/DllNotFoundException.cs36
-rw-r--r--src/System.Private.Interop/src/System/Reflection/DispatchProxy.cs83
-rw-r--r--src/System.Private.Interop/src/System/Reflection/DispatchProxyEntry.cs18
-rw-r--r--src/System.Private.Interop/src/System/Reflection/DispatchProxyHelpers.cs75
-rw-r--r--src/System.Private.Interop/src/System/Reflection/DispatchProxyInstanceNotFoundException.cs28
-rw-r--r--src/System.Private.Interop/src/System/RhBaseName.cs3
-rw-r--r--src/System.Private.Interop/src/System/Runtime/CompilerServices/FunctionPointerHelpers.cs18
-rw-r--r--src/System.Private.Interop/src/System/Runtime/CompilerServices/IgnoresAccessChecksToAttribute.cs22
-rw-r--r--src/System.Private.Interop/src/System/Runtime/CompilerServices/McgResource.cs18
-rw-r--r--src/System.Private.Interop/src/System/Runtime/CompilerServices/ModuleConstructorAttribute.cs17
-rw-r--r--src/System.Private.Interop/src/System/Runtime/CompilerServices/UnmanagedValueTypeConstraintAttribute.cs13
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ArrayWithOffset.cs109
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/BStrWrapper.cs40
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/BestFitMappingAttribute.cs21
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ClassInterfaceAttribute.cs22
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ClassInterfaceType.cs14
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/CoClassAttribute.cs20
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComAwareEventInfo.cs186
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComDefaultInterfaceAttribute.cs20
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComEventInterfaceAttribute.cs23
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComEventsHelper.cs227
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComImportAttribute.cs12
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComInterfaceType.cs15
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComMemberType.cs12
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComSourceInterfacesAttribute.cs40
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IAdviseSink.cs56
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IBindCtx.cs35
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IConnectionPoint.cs29
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IConnectionPointContainer.cs26
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumConnectionPoints.cs30
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumConnections.cs30
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumFormatETC.cs46
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumMoniker.cs30
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumString.cs30
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumVARIANT.cs34
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IMoniker.cs53
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IPersistFile.cs34
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IRunningObjectTable.cs34
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IStream.cs38
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeComp.cs26
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeInfo.cs46
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeInfo2.cs62
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeLib.cs37
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeLib2.cs42
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/advf.cs19
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindopts.cs16
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindptr.cs18
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/callconv.cs21
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/connectdata.cs19
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/datadir.cs13
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/desckind.cs17
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dispparams.cs16
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dvaspect.cs16
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/elemdesc.cs23
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/excepinfo.cs24
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/filetime.cs14
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/formatetc.cs19
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcdesc.cs24
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcflags.cs25
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funckind.cs16
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idldesc.cs14
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idlflag.cs17
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/impltypeflags.cs16
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/invokekind.cs16
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/libflags.cs16
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramdesc.cs14
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramflag.cs20
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/statdata.cs15
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/statstg.cs23
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/stgmedium.cs15
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/syskind.cs15
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/tymed.cs20
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeattr.cs34
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typedesc.cs14
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeflags.cs31
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typekind.cs20
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typelibattr.cs18
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/vardesc.cs29
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/varflags.cs25
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/varkind.cs19
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ComWeakReferenceHelpers.cs180
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/CriticalHandle.cs236
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/CurrencyWrapper.cs47
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/CustomQueryInterfaceMode.cs15
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/CustomQueryInterfaceResult.cs19
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultCharSetAttribute.cs24
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultDllImportSearchPathAttribute.cs23
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultParameterValueAttribute.cs30
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/DispIdAttribute.cs22
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/DispatchWrapper.cs61
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/DllImportSearchPath.cs23
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ErrorWrapper.cs51
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ExceptionHelpers.cs948
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/GuidAttribute.cs18
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/HandleCollector.NETNative.cs17
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/HandleCollector.cs134
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ICustomAdapter.cs24
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/ICustomQueryInterface.cs26
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/InAttribute.cs14
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/InterfaceTypeAttribute.cs22
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/InteropEventProvider.cs607
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/InvalidComObjectException.cs38
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs41
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/LCIDConversionAttribute.cs22
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs1614
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAdapter.cs95
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAsAttribute.cs40
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalDirectiveException.cs38
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalImpl.cs47
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/MissingInteropDataException.cs30
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/OptionalAttribute.cs12
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/PreserveSigAttribute.cs12
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/SEHException.cs51
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs37
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs38
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/SafeBuffer.cs464
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/TypeIdentifierAttribute.cs24
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/UnknownWrapper.cs35
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/UnmanagedType.cs48
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/VarEnum.cs55
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/Variant.cs500
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/VariantWrapper.cs39
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/CustomPropertyImpl.cs296
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/DefaultInterfaceAttribute.cs26
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs295
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IActivationFactory.cs31
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/InterfaceImplementedInVersionAttribute.cs56
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReadOnlyArrayAttribute.cs16
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReturnValueNameAttribute.cs27
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeImportAttribute.cs22
-rw-r--r--src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/WriteOnlyArrayAttribute.cs16
-rw-r--r--src/System.Private.Interop/src/System/__HResults.cs233
-rw-r--r--src/System.Private.Interop/src/WinRT/ExceptionHelpers.cs954
-rw-r--r--src/System.Private.Interop/src/WinRT/Interop.WinRT.cs94
189 files changed, 34922 insertions, 0 deletions
diff --git a/src/System.Private.Interop/src/Interop/Interop.COM.Windows.cs b/src/System.Private.Interop/src/Interop/Interop.COM.Windows.cs
new file mode 100644
index 000000000..50ffb0904
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.COM.Windows.cs
@@ -0,0 +1,195 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+//
+
+//
+// All P/invokes used by System.Private.Interop and MCG generated code goes here.
+//
+// !!IMPORTANT!!
+//
+// Do not rely on MCG to generate marshalling code for these p/invokes as MCG might not see them at all
+// due to not seeing dependency to those calls (before the MCG generated code is generated). Instead,
+// always manually marshal the arguments
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.Runtime.InteropServices
+{
+
+ [CLSCompliant(false)]
+ public static partial class ExternalInterop
+ {
+ private static partial class Libraries
+ {
+#if TARGET_CORE_API_SET
+ internal const string CORE_COM = "api-ms-win-core-com-l1-1-0.dll";
+#else
+ internal const string CORE_COM = "ole32.dll";
+#endif
+ // @TODO: What is the matching dll in CoreSys?
+ // @TODO: Replace the below by the correspondent api-ms-win-core-...-0.dll
+ internal const string CORE_COM_AUT = "OleAut32.dll";
+ }
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ public static extern unsafe void* CoTaskMemAlloc(IntPtr size);
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ public extern static unsafe void CoTaskMemFree(void* pv);
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ public static extern unsafe int CoGetContextToken(IntPtr* ppToken);
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal extern IntPtr CoTaskMemRealloc(IntPtr pv, IntPtr size);
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal unsafe extern int CoGetObjectContext(Guid* iid, void* ppv);
+
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal unsafe extern int CoCreateInstanceFromApp(
+ Guid* clsid,
+ IntPtr pUnkOuter,
+ int context,
+ IntPtr reserved,
+ int count,
+ IntPtr results
+ );
+
+
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal unsafe extern int CoCreateFreeThreadedMarshaler(void* pOuter, void** ppunkMarshal);
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ private extern unsafe static int CoMarshalInterface(IntPtr pStream, Guid* iid, IntPtr pUnk, Interop.COM.MSHCTX dwDestContext, IntPtr pvDestContext, Interop.COM.MSHLFLAGS mshlflags);
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ private static unsafe extern int CoUnmarshalInterface(IntPtr pStream, Guid* iid, void** ppv);
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ private static unsafe extern int CoGetMarshalSizeMax(ulong* pulSize, Guid* iid, IntPtr pUnk, Interop.COM.MSHCTX dwDestContext, IntPtr pvDestContext, Interop.COM.MSHLFLAGS mshlflags);
+
+ [DllImport(Libraries.CORE_COM)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ static internal extern int CoReleaseMarshalData(IntPtr pStream);
+
+
+ [DllImport(Libraries.CORE_COM_AUT)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern unsafe void SysFreeString(void* pBSTR);
+
+ public static unsafe void SysFreeString(IntPtr pBstr)
+ {
+ SysFreeString((void*)pBstr);
+ }
+
+ [DllImport(Libraries.CORE_COM_AUT)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern unsafe uint SysStringLen(void* pBSTR);
+ public static unsafe uint SysStringLen(IntPtr pBSTR)
+ {
+ return SysStringLen((void*)pBSTR);
+ }
+
+ [DllImport(Libraries.CORE_COM_AUT)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern unsafe IntPtr SysAllocString(IntPtr pStrIn);
+
+ [DllImport(Libraries.CORE_COM_AUT)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern unsafe char* SysAllocStringLen(char* pStrIn, uint len);
+
+ [DllImport(Libraries.CORE_COM_AUT)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal extern void VariantClear(IntPtr pObject);
+
+ static internal unsafe int CoGetObjectContext(ref Guid iid, out IntPtr ppv)
+ {
+ fixed (void* unsafe_ppv = &ppv)
+ {
+ fixed (Guid* unsafe_iid = &iid)
+ {
+ return CoGetObjectContext(unsafe_iid, (void**)unsafe_ppv);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Marshal IUnknown * into IStream*
+ /// </summary>
+ /// <returns>HResult</returns>
+ static internal unsafe int CoMarshalInterface(IntPtr pStream, ref Guid iid, IntPtr pUnk, Interop.COM.MSHCTX dwDestContext, IntPtr pvDestContext, Interop.COM.MSHLFLAGS mshlflags)
+ {
+ fixed (Guid* unsafe_iid = &iid)
+ {
+ return CoMarshalInterface(pStream, unsafe_iid, pUnk, dwDestContext, pvDestContext, mshlflags);
+ }
+ }
+
+ /// <summary>
+ /// Marshal IStream* into IUnknown*
+ /// </summary>
+ /// <returns>HResult</returns>
+ static internal unsafe int CoUnmarshalInterface(IntPtr pStream, ref Guid iid, out IntPtr ppv)
+ {
+ fixed (Guid* unsafe_iid = &iid)
+ {
+ fixed (void* unsafe_ppv = &ppv)
+ {
+ return CoUnmarshalInterface(pStream, unsafe_iid, (void**)unsafe_ppv);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Returns an upper bound on the number of bytes needed to marshal the specified interface pointer to the specified object.
+ /// </summary>
+ /// <returns>HResult</returns>
+ static internal unsafe int CoGetMarshalSizeMax(out ulong pulSize, ref Guid iid, IntPtr pUnk, Interop.COM.MSHCTX dwDestContext, IntPtr pvDestContext, Interop.COM.MSHLFLAGS mshlflags)
+ {
+ fixed (ulong* unsafe_pulSize = &pulSize)
+ {
+ fixed (Guid* unsafe_iid = &iid)
+ {
+ return CoGetMarshalSizeMax(unsafe_pulSize, unsafe_iid, pUnk, dwDestContext, pvDestContext, mshlflags);
+ }
+ }
+ }
+
+ public static unsafe int CoGetContextToken(out IntPtr ppToken)
+ {
+ ppToken = IntPtr.Zero;
+ fixed (IntPtr* unsafePpToken = &ppToken)
+ {
+ return CoGetContextToken(unsafePpToken);
+ }
+ }
+
+ public static unsafe void SafeCoTaskMemFree(void* pv)
+ {
+ // Even though CoTaskMemFree is a no-op for NULLs, skipping the interop call entirely is faster
+ if (pv != null)
+ CoTaskMemFree(pv);
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Interop/Interop.Common.Unix.cs b/src/System.Private.Interop/src/Interop/Interop.Common.Unix.cs
new file mode 100644
index 000000000..293666029
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.Common.Unix.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;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+
+// TODO : Split this file , now it contains anything other than string and memoryreleated.
+
+namespace System.Runtime.InteropServices
+{
+ public partial class ExternalInterop
+ {
+ static internal int GetLastWin32Error()
+ {
+ throw new PlatformNotSupportedException("GetLastWin32Error");
+ }
+
+ static unsafe internal int FormatMessage(
+ int dwFlags,
+ IntPtr lpSource,
+ uint dwMessageId,
+ uint dwLanguageId,
+ char* lpBuffer,
+ uint nSize,
+ IntPtr Arguments)
+ {
+ // ??
+ return 0;
+ //throw new PlatformNotSupportedException("FormatMessage");
+ }
+
+ //TODO : implement in PAL
+ internal static unsafe void OutputDebugString(string outputString)
+ {
+ throw new PlatformNotSupportedException("OutputDebugString");
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Interop/Interop.Common.Windows.cs b/src/System.Private.Interop/src/Interop/Interop.Common.Windows.cs
new file mode 100644
index 000000000..037f3fb4a
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.Common.Windows.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.
+
+//
+
+//
+// All P/invokes used by System.Private.Interop and MCG generated code goes here.
+//
+// !!IMPORTANT!!
+//
+// Do not rely on MCG to generate marshalling code for these p/invokes as MCG might not see them at all
+// due to not seeing dependency to those calls (before the MCG generated code is generated). Instead,
+// always manually marshal the arguments
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+
+// TODO : Split this file , now it contains anything other than string and memoryreleated.
+namespace System.Runtime.InteropServices
+{
+
+ public static partial class ExternalInterop
+ {
+ private static partial class Libraries
+ {
+#if TARGET_CORE_API_SET
+ internal const string CORE_DEBUG = "api-ms-win-core-debug-l1-1-0.dll";
+ internal const string CORE_ERRORHANDLING = "api-ms-win-core-errorhandling-l1-1-0.dll";
+#else
+ internal const string CORE_DEBUG = "kernel32.dll";
+ internal const string CORE_ERRORHANDLING = "kernel32.dll";
+#endif //TARGET_CORE_API_SET
+ }
+
+ [DllImport(Libraries.CORE_DEBUG, EntryPoint = "OutputDebugStringW")]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal unsafe extern void OutputDebugString(char* lpOutputString);
+
+ internal static unsafe void OutputDebugString(string outputString)
+ {
+ fixed (char* pOutputString = outputString)
+ {
+ OutputDebugString(pOutputString);
+ }
+ }
+
+
+ [DllImport(Libraries.CORE_ERRORHANDLING, EntryPoint = "GetLastError")]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ static internal extern int GetLastWin32Error();
+
+ [DllImport(Libraries.CORE_ERRORHANDLING, EntryPoint = "SetLastError")]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ static internal extern void SetLastWin32Error(int errorCode);
+
+ }
+}
diff --git a/src/System.Private.Interop/src/Interop/Interop.Localization.Windows.cs b/src/System.Private.Interop/src/Interop/Interop.Localization.Windows.cs
new file mode 100644
index 000000000..82ae296a0
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.Localization.Windows.cs
@@ -0,0 +1,141 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+//
+
+//
+// All P/invokes used by System.Private.Interop and MCG generated code goes here.
+//
+// !!IMPORTANT!!
+//
+// Do not rely on MCG to generate marshalling code for these p/invokes as MCG might not see them at all
+// due to not seeing dependency to those calls (before the MCG generated code is generated). Instead,
+// always manually marshal the arguments
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.Runtime.InteropServices
+{
+
+ public static partial class ExternalInterop
+ {
+ private static partial class Libraries
+ {
+#if TARGET_CORE_API_SET
+ internal const string CORE_LOCALIZATION = "api-ms-win-core-localization-l1-2-0.dll";
+#else
+ internal const string CORE_LOCALIZATION = "kernel32.dll";
+#endif
+ }
+
+ internal struct CPINFO
+ {
+#pragma warning disable 0649
+ internal int MaxCharSize;
+
+ // BYTE DefaultChar[MAX_DEFAULTCHAR];
+ // I don't want to have MarshalAs in System.Private.Interop.dll
+ internal byte DefaultChar0;
+ internal byte DefaultChar1;
+ internal byte DefaultChar2;
+ internal byte DefaultChar3;
+ internal byte DefaultChar4;
+ internal byte DefaultChar5;
+ internal byte DefaultChar6;
+ internal byte DefaultChar7;
+ internal byte DefaultChar8;
+ internal byte DefaultChar9;
+ internal byte DefaultChar10;
+ internal byte DefaultChar11;
+
+ // BYTE LeadByte[MAX_LEADBYTES]
+ internal byte LeadByte0;
+ internal byte LeadByte1;
+#pragma warning restore 0649
+ }
+
+ [DllImport(Libraries.CORE_LOCALIZATION, EntryPoint = "FormatMessageW")]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal unsafe extern int FormatMessage(
+ int dwFlags,
+ IntPtr lpSource,
+ uint dwMessageId,
+ uint dwLanguageId,
+ char* lpBuffer,
+ uint nSize,
+ IntPtr Arguments);
+
+ [DllImport(Libraries.CORE_LOCALIZATION)]
+ [McgGeneratedNativeCallCodeAttribute]
+ internal static unsafe extern int GetCPInfo(uint codePage, CPINFO* lpCpInfo);
+
+
+ internal const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
+ internal const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
+ internal const int FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000;
+ internal const int FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF;
+ internal const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
+ //according to MSDN FormatMessage API doc, the buffer cannot be larger than 64K bytes.
+ private const int MaxAllowedBufferSize = 64 * 1024;
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="errorCode">HRESULT</param>
+ /// <param name="sb">buffer</param>
+ /// <param name="errorMsg">output error message</param>
+ /// <returns>Return false IFF when buffer space isnt enough</returns>
+ private static unsafe bool TryGetMessage(int errorCode, int bufferSize, out string errorMsg)
+ {
+ errorMsg = null;
+ char[] buffer = new char[bufferSize];
+ int result;
+ fixed (char* pinned_lpBuffer = buffer)
+ {
+ result = ExternalInterop.FormatMessage(
+ FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ IntPtr.Zero, (uint)errorCode, 0, pinned_lpBuffer,
+ (uint)buffer.Length, IntPtr.Zero);
+ }
+ if (result != 0) //result hold the number of WCHARs stored in the output buffer(sb)
+ {
+ if (buffer[result - 1] == ' ')
+ {
+ buffer[result - 1] = '\0';
+ result = result - 1;
+ }
+ errorMsg = new string(buffer, 0, result);
+ return true;
+ }
+ else
+ {
+ if (ExternalInterop.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER) return false;
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// Get Error Message according to HResult
+ /// </summary>
+ /// <param name="errorCode">HRESULT</param>
+ /// <returns></returns>
+ internal unsafe static String GetMessage(int errorCode)
+ {
+ string errorMsg;
+ int bufferSize = 1024;
+ do
+ {
+ if (TryGetMessage(errorCode, bufferSize, out errorMsg))
+ return errorMsg;
+ //Increase the size for buffer by 4
+ bufferSize = bufferSize * 4;
+
+ } while (bufferSize <= MaxAllowedBufferSize);
+
+ return null;
+ }
+
+ }
+}
diff --git a/src/System.Private.Interop/src/Interop/Interop.Memory.Unix.cs b/src/System.Private.Interop/src/Interop/Interop.Memory.Unix.cs
new file mode 100644
index 000000000..16cd719a7
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.Memory.Unix.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.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.Runtime.InteropServices
+{
+ internal static class Libraries
+ {
+ internal const string SystemPrivateCoreLibNative = "System.Private.CoreLib.Native";
+ }
+
+ [CLSCompliant(false)]
+ public partial class ExternalInterop
+ {
+ [DllImport(Libraries.SystemPrivateCoreLibNative)]
+ internal static unsafe extern IntPtr MemAlloc(UIntPtr sizeInBytes);
+
+ [DllImport(Libraries.SystemPrivateCoreLibNative)]
+ internal static unsafe extern void MemFree(IntPtr ptr);
+
+ [DllImport(Libraries.SystemPrivateCoreLibNative)]
+ internal static unsafe extern IntPtr MemReAlloc(IntPtr ptr, UIntPtr newSize);
+ }
+}
diff --git a/src/System.Private.Interop/src/Interop/Interop.Memory.Windows.cs b/src/System.Private.Interop/src/Interop/Interop.Memory.Windows.cs
new file mode 100644
index 000000000..a8288ed3b
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.Memory.Windows.cs
@@ -0,0 +1,74 @@
+// 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.CompilerServices;
+
+
+namespace System.Runtime.InteropServices
+{
+ public static partial class ExternalInterop
+ {
+ private static partial class Libraries
+ {
+#if TARGET_CORE_API_SET
+ internal const string CORE_HEAP = "api-ms-win-core-heap-l1-1-0.dll";
+#else
+ internal const string CORE_HEAP = "kernel32.dll";
+
+#endif //TARGET_CORE_API_SET
+ }
+
+ [DllImport(Libraries.CORE_HEAP)]
+ [McgGeneratedNativeCallCodeAttribute]
+ private static extern IntPtr GetProcessHeap();
+
+
+ [DllImport(Libraries.CORE_HEAP)]
+ [McgGeneratedNativeCallCodeAttribute]
+ private static unsafe extern IntPtr HeapAlloc(IntPtr hHeap, UInt32 dwFlags, UIntPtr sizeInBytes);
+
+
+ [DllImport(Libraries.CORE_HEAP)]
+ [McgGeneratedNativeCallCodeAttribute]
+ private static unsafe extern int HeapFree(IntPtr hHeap, UInt32 dwFlags, IntPtr lpMem);
+
+
+ [DllImport(Libraries.CORE_HEAP)]
+ [McgGeneratedNativeCallCodeAttribute]
+ private static unsafe extern IntPtr HeapReAlloc(IntPtr hHeap, UInt32 dwFlags, IntPtr lpMem, UIntPtr dwBytes);
+
+ public static IntPtr MemAlloc(UIntPtr sizeInBytes)
+ {
+ return HeapAlloc(GetProcessHeap(), 0, sizeInBytes);
+ }
+ public static unsafe void MemFree(IntPtr ptr)
+ {
+ HeapFree(GetProcessHeap(), 0, ptr);
+ }
+
+ public static unsafe IntPtr MemReAlloc(IntPtr ptr, UIntPtr newSize)
+ {
+ return HeapReAlloc(GetProcessHeap(), 0, ptr, newSize);
+ }
+
+ // Helper functions
+ internal static IntPtr MemAlloc(UIntPtr sizeInBytes, uint flags)
+ {
+ return HeapAlloc(GetProcessHeap(), flags, sizeInBytes);
+ }
+
+ internal unsafe static IntPtr MemAlloc(IntPtr sizeInBytes)
+ {
+ return HeapAlloc(GetProcessHeap(), 0,(UIntPtr)(void*)sizeInBytes);
+ }
+ internal unsafe static IntPtr MemReAlloc(IntPtr ptr, IntPtr newSize)
+ {
+ return HeapReAlloc(GetProcessHeap(), 0, ptr, (UIntPtr)(void*)newSize);
+ }
+ internal static IntPtr MemReAlloc(IntPtr ptr, UIntPtr newSize ,uint flags)
+ {
+ return HeapReAlloc(GetProcessHeap(), flags, ptr, newSize);
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Interop/Interop.PlatformNotSupported.cs b/src/System.Private.Interop/src/Interop/Interop.PlatformNotSupported.cs
new file mode 100644
index 000000000..a87b90ecd
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.PlatformNotSupported.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.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+
+#if !ENABLE_WINRT
+// These are all winrt specific , we need placeholder since the root of these calls are
+// are from McgMarshal , refactoring WinRT marshal API is TODO
+namespace System.Runtime.InteropServices
+{
+ public partial class ExternalInterop
+ {
+ static internal unsafe void RoGetActivationFactory(string className, ref Guid iid, out IntPtr ppv)
+ {
+ throw new PlatformNotSupportedException("RoGetActivationFactory");
+ }
+ }
+
+ public static partial class McgMarshal
+ {
+ public static string HStringToString(IntPtr hString)
+ {
+ throw new PlatformNotSupportedException("HStringToString");
+ }
+
+ public static string HStringToString(HSTRING hString)
+ {
+ throw new PlatformNotSupportedException("HStringToString");
+ }
+
+ public static HSTRING StringToHString(string sourceString)
+ {
+ throw new PlatformNotSupportedException("StringToHString");
+ }
+
+ internal static unsafe int StringToHStringNoNullCheck(string sourceString, HSTRING* hstring)
+ {
+ throw new PlatformNotSupportedException("StringToHStringNoNullCheck");
+ }
+
+ public static void FreeHString(IntPtr pHString)
+ {
+ throw new PlatformNotSupportedException("FreeHString");
+ }
+ }
+}
+#endif
diff --git a/src/System.Private.Interop/src/Interop/Interop.String.Unix.cs b/src/System.Private.Interop/src/Interop/Interop.String.Unix.cs
new file mode 100644
index 000000000..3ec93362d
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.String.Unix.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.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.Runtime.InteropServices
+{
+ public partial class ExternalInterop
+ {
+ public static partial class Constants
+ {
+ // TODO: These are windows specific , unfortunately
+ // the API signature is same for Windows and non-Windows and we need
+ // these defined to make the compiler happy.These are not used on non-windows
+ // platforms.
+ public const uint WC_NO_BEST_FIT_CHARS = 0x00000400;
+ public const uint CP_ACP = 0;
+ public const uint MB_PRECOMPOSED = 1;
+ }
+
+
+ internal static unsafe uint SysStringLen(void* pBSTR)
+ {
+ throw new PlatformNotSupportedException("SysStringLen");
+ }
+
+ internal static unsafe uint SysStringLen(IntPtr pBSTR)
+ {
+ throw new PlatformNotSupportedException("SysStringLen");
+ }
+
+ unsafe public static int ConvertWideCharToMultiByte(char* wideCharStr, int wideCharLen, IntPtr multiByteStr, int multiByteLen)
+ {
+ return System.Text.Encoding.UTF8.GetBytes(wideCharStr, wideCharLen,(byte*)multiByteStr, multiByteLen);
+ }
+
+ unsafe public static int GetByteCount(char* wideCharStr, int wideCharLen)
+ {
+ return System.Text.Encoding.UTF8.GetByteCount(wideCharStr, wideCharLen);
+ }
+
+ unsafe public static int ConvertMultiByteToWideChar(IntPtr multiByteStr,
+ int multiByteLen,
+ IntPtr wideCharStr,
+ int wideCharLen)
+ {
+ return System.Text.Encoding.UTF8.GetChars((byte*)multiByteStr, multiByteLen, (char*)wideCharStr, wideCharLen);
+ }
+
+ public static unsafe int GetCharCount(byte* multiByteStr, int multiByteLen)
+ {
+ return System.Text.Encoding.UTF8.GetCharCount(multiByteStr, multiByteLen);
+ }
+
+ }
+}
diff --git a/src/System.Private.Interop/src/Interop/Interop.String.Windows.cs b/src/System.Private.Interop/src/Interop/Interop.String.Windows.cs
new file mode 100644
index 000000000..76a37f231
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.String.Windows.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.
+
+//
+
+//
+// All P/invokes used by System.Private.Interop and MCG generated code goes here.
+//
+// !!IMPORTANT!!
+//
+// Do not rely on MCG to generate marshalling code for these p/invokes as MCG might not see them at all
+// due to not seeing dependency to those calls (before the MCG generated code is generated). Instead,
+// always manually marshal the arguments
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.Runtime.InteropServices
+{
+ public static partial class ExternalInterop
+ {
+ public static partial class Constants
+ {
+ public const uint WC_NO_BEST_FIT_CHARS = 0x00000400;
+ public const uint CP_ACP = 0;
+ public const uint MB_PRECOMPOSED = 1;
+ }
+
+ private static partial class Libraries
+ {
+#if TARGET_CORE_API_SET
+ internal const string CORE_STRING = "api-ms-win-core-string-l1-1-0.dll";
+#else
+ internal const string CORE_STRING = "kernel32.dll";
+#endif //TARGET_CORE_API_SET
+ }
+
+ [DllImport(Libraries.CORE_STRING, CallingConvention = CallingConvention.StdCall)]
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ [McgGeneratedNativeCallCodeAttribute]
+ unsafe private extern static int WideCharToMultiByte(
+ uint CodePage,
+ uint dwFlags,
+ char* lpWideCharStr,
+ int cchWideChar,
+ IntPtr lpMultiByteStr,
+ int cbMultiByte,
+ IntPtr lpDefaultChar,
+ IntPtr lpUsedDefaultChar);
+
+ [DllImport(Libraries.CORE_STRING, CallingConvention = CallingConvention.StdCall)]
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ [McgGeneratedNativeCallCodeAttribute]
+ private extern static int MultiByteToWideChar(
+ uint CodePage,
+ uint dwFlags,
+ IntPtr lpMultiByteStr,
+ int cbMultiByte,
+ IntPtr lpWideCharStr,
+ int cchWideChar);
+
+ // Convert a UTF16 string to ANSI byte array
+ unsafe public static int ConvertWideCharToMultiByte(char* wideCharStr, int wideCharLen, IntPtr multiByteStr, int multiByteLen)
+ {
+ return WideCharToMultiByte(Constants.CP_ACP,
+ 0,
+ wideCharStr,
+ wideCharLen,
+ multiByteStr,
+ multiByteLen,
+ default(IntPtr),
+ default(IntPtr)
+ );
+ }
+
+ // Return size in bytes required to convert a UTF16 string to byte array.
+ unsafe public static int GetByteCount(char* wideStr, int wideStrLen)
+ {
+ return WideCharToMultiByte(Constants.CP_ACP,
+ 0,
+ wideStr,
+ wideStrLen,
+ IntPtr.Zero,
+ 0,
+ default(IntPtr),
+ default(IntPtr)
+ );
+ }
+
+ // Convert a native byte array to UTF16
+ public static int ConvertMultiByteToWideChar(IntPtr multiByteStr, int multiByteLen, IntPtr wideCharStr, int wideCharLen)
+ {
+ return MultiByteToWideChar(Constants.CP_ACP, 0, multiByteStr, multiByteLen, wideCharStr, wideCharLen);
+ }
+
+ // Return number of charaters encoded in native byte array lpMultiByteStr
+
+ unsafe public static int GetCharCount(IntPtr multiByteStr, int multiByteLen)
+ {
+ return MultiByteToWideChar(Constants.CP_ACP, 0, multiByteStr, multiByteLen, IntPtr.Zero, 0);
+ }
+
+ // Convert a UTF16 string to ANSI byte array using flags
+ unsafe public static int ConvertWideCharToMultiByte(char* wideCharStr,
+ int wideCharLen,
+ IntPtr multiByteStr,
+ int multiByteLen,
+ uint flags,
+ IntPtr usedDefaultChar)
+ {
+ return WideCharToMultiByte(Constants.CP_ACP,
+ flags,
+ wideCharStr,
+ wideCharLen,
+ multiByteStr,
+ multiByteLen,
+ default(IntPtr),
+ usedDefaultChar
+ );
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Interop/Interop.Sync.Windows.cs b/src/System.Private.Interop/src/Interop/Interop.Sync.Windows.cs
new file mode 100644
index 000000000..042608bec
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.Sync.Windows.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.
+
+//
+
+//
+// All P/invokes used by System.Private.Interop and MCG generated code goes here.
+//
+// !!IMPORTANT!!
+//
+// Do not rely on MCG to generate marshalling code for these p/invokes as MCG might not see them at all
+// due to not seeing dependency to those calls (before the MCG generated code is generated). Instead,
+// always manually marshal the arguments
+
+using System;
+using System.Runtime.CompilerServices;
+
+
+namespace System.Runtime.InteropServices
+{
+ public static partial class ExternalInterop
+ {
+ internal struct CRITICAL_SECTION
+ {
+#pragma warning disable 169 // Field 'foo' is never used
+ IntPtr DebugInfo;
+ Int32 LockCount;
+ Int32 RecursionCount;
+ IntPtr OwningThread;
+ IntPtr LockSemaphore;
+ Int32 SpinCount;
+#pragma warning restore 169
+ }
+
+ private static partial class Libraries
+ {
+#if TARGET_CORE_API_SET
+ internal const string CORE_SYNCH_L1 = "api-ms-win-core-synch-l1-1-0.dll";
+#else
+ internal const string CORE_SYNCH_L1 = "kernel32.dll";
+#endif
+ }
+
+ [DllImport(Libraries.CORE_SYNCH_L1)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal unsafe extern void InitializeCriticalSectionEx(CRITICAL_SECTION* lpCriticalSection, int dwSpinCount, int flags);
+
+ [DllImport(Libraries.CORE_SYNCH_L1)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal unsafe extern void EnterCriticalSection(CRITICAL_SECTION* lpCriticalSection);
+
+ [DllImport(Libraries.CORE_SYNCH_L1)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal unsafe extern void LeaveCriticalSection(CRITICAL_SECTION* lpCriticalSection);
+
+ [DllImport(Libraries.CORE_SYNCH_L1)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal unsafe extern void DeleteCriticalSection(CRITICAL_SECTION* lpCriticalSection);
+
+ }
+}
diff --git a/src/System.Private.Interop/src/Interop/Interop.WinRT.cs b/src/System.Private.Interop/src/Interop/Interop.WinRT.cs
new file mode 100644
index 000000000..505bdb850
--- /dev/null
+++ b/src/System.Private.Interop/src/Interop/Interop.WinRT.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.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.Runtime.InteropServices
+{
+
+ public static partial class ExternalInterop
+ {
+ private static partial class Libraries
+ {
+ internal const string CORE_WINRT = "api-ms-win-core-winrt-l1-1-0.dll";
+ internal const string CORE_WINRT_STRING = "api-ms-win-core-winrt-string-l1-1-0.dll";
+ internal const string CORE_WINRT_ERROR1 = "api-ms-win-core-winrt-error-l1-1-1.dll";
+ internal const string CORE_WINRT_ERROR = "api-ms-win-core-winrt-error-l1-1-0.dll";
+
+ }
+
+ [DllImport(Libraries.CORE_WINRT_STRING)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern unsafe int WindowsCreateString(char* sourceString,
+ uint length,
+ void* hstring);
+
+
+ [DllImport(Libraries.CORE_WINRT_STRING)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ static internal extern unsafe int WindowsCreateStringReference(char* sourceString,
+ uint length,
+ HSTRING_HEADER* phstringHeader,
+ void* hstring);
+
+
+ [DllImport(Libraries.CORE_WINRT_STRING)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern unsafe void WindowsDeleteString(void* hstring);
+
+ [DllImport(Libraries.CORE_WINRT)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern unsafe int RoGetActivationFactory(void* hstring_typeName, Guid* iid, void* ppv);
+
+ [DllImport(Libraries.CORE_WINRT_STRING)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern unsafe char* WindowsGetStringRawBuffer(void* hstring, uint* pLength);
+
+ [DllImport(Libraries.CORE_WINRT)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern unsafe int RoActivateInstance(void* hActivableClassId, out void* ppv);
+
+
+ [DllImport(Libraries.CORE_WINRT_ERROR, PreserveSig = true)]
+ [McgGeneratedNativeCallCodeAttribute]
+ public static extern int GetRestrictedErrorInfo(out System.IntPtr pRestrictedErrorInfo);
+
+ [DllImport(Libraries.CORE_WINRT_ERROR, PreserveSig = true)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern int RoOriginateError(int hr, HSTRING hstring);
+
+ [DllImport(Libraries.CORE_WINRT_ERROR, PreserveSig = true)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern int SetRestrictedErrorInfo(System.IntPtr pRestrictedErrorInfo);
+
+ [DllImport(Libraries.CORE_WINRT_ERROR1, PreserveSig = true)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal extern int RoOriginateLanguageException(int hr, HSTRING message, IntPtr pLanguageException);
+
+ [DllImport(Libraries.CORE_WINRT_ERROR1, PreserveSig = true)]
+ [McgGeneratedNativeCallCodeAttribute]
+ internal static extern int RoReportUnhandledError(IntPtr pRestrictedErrorInfo);
+
+ static internal unsafe void RoGetActivationFactory(string className, ref Guid iid, out IntPtr ppv)
+ {
+ fixed (char* unsafe_className = className)
+ {
+ void* hstring_typeName = null;
+
+ HSTRING_HEADER hstringHeader;
+ int hr =
+ WindowsCreateStringReference(
+ unsafe_className,(uint) className.Length, &hstringHeader, &hstring_typeName);
+
+ if (hr < 0)
+ throw Marshal.GetExceptionForHR(hr);
+
+ fixed (Guid* unsafe_iid = &iid)
+ {
+ fixed (void* unsafe_ppv = &ppv)
+ {
+ hr = ExternalInterop.RoGetActivationFactory(
+ hstring_typeName,
+ unsafe_iid,
+ unsafe_ppv);
+
+ if (hr < 0)
+ throw Marshal.GetExceptionForHR(hr);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/InteropCallbacks.cs b/src/System.Private.Interop/src/InteropCallbacks.cs
new file mode 100644
index 000000000..929f4ff3c
--- /dev/null
+++ b/src/System.Private.Interop/src/InteropCallbacks.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.
+
+using global::System;
+using System.Runtime.InteropServices;
+
+namespace Internal.Interop
+{
+ /// <summary>
+ /// Used by CoreFX for async exception and COM weak reference support.
+ /// </summary>
+ public static class InteropCallbacks
+ {
+ public static bool ReportUnhandledError(this Exception ex)
+ {
+ return ExceptionHelpers.ReportUnhandledError(ex);
+ }
+
+ public static Exception AttachRestrictedErrorInfo(this Exception ex)
+ {
+ return ExceptionHelpers.AttachRestrictedErrorInfo(ex);
+ }
+
+ public static object GetCOMWeakReferenceTarget(object weakReference)
+ {
+ return COMWeakReferenceHelpers.GetTarget(weakReference);
+ }
+
+ public static void SetCOMWeakReferenceTarget(object weakReference, object target)
+ {
+ COMWeakReferenceHelpers.SetTarget(weakReference, target);
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Resources/Strings.resx b/src/System.Private.Interop/src/Resources/Strings.resx
new file mode 100644
index 000000000..973be6e19
--- /dev/null
+++ b/src/System.Private.Interop/src/Resources/Strings.resx
@@ -0,0 +1,378 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="Arg_BufferTooSmall" xml:space="preserve">
+ <value>Not enough space available in the buffer.</value>
+ </data>
+ <data name="Arg_DllNotFoundException" xml:space="preserve">
+ <value>Dll was not found.</value>
+ </data>
+ <data name="Arg_InvalidANSIString" xml:space="preserve">
+ <value>The ANSI string passed in could not be converted from the default ANSI code page to Unicode.</value>
+ </data>
+ <data name="Arg_InvalidComObjectException" xml:space="preserve">
+ <value>Attempt has been made to use a COM object that does not have a backing class factory.</value>
+ </data>
+ <data name="Arg_InvalidHandle" xml:space="preserve">
+ <value>Invalid handle.</value>
+ </data>
+ <data name="Arg_InvalidOleVariantTypeException" xml:space="preserve">
+ <value>Specified OLE variant was invalid.</value>
+ </data>
+ <data name="Arg_VariantTypeNotSupported" xml:space="preserve">
+ <value>Marshal for the specified variant type {0} not supported.</value>
+ </data>
+ <data name="Arg_InvalidThreshold" xml:space="preserve">
+ <value>maximumThreshold cannot be less than initialThreshold.</value>
+ </data>
+ <data name="Arg_MarshalDirectiveException" xml:space="preserve">
+ <value>Marshaling directives are invalid.</value>
+ </data>
+ <data name="Arg_MustBeDecimal" xml:space="preserve">
+ <value>Object must be of type Decimal.</value>
+ </data>
+ <data name="Arg_MustBeInt32" xml:space="preserve">
+ <value>Object must be of type Int32.</value>
+ </data>
+ <data name="Arg_MustBeStringPtrNotAtom" xml:space="preserve">
+ <value>The pointer passed in as a String must not be in the bottom 64K of the process's address space.</value>
+ </data>
+ <data name="Arg_NeedNonNegNumRequired" xml:space="preserve">
+ <value>Non-negative number required.</value>
+ </data>
+ <data name="Arg_NotIsomorphic" xml:space="preserve">
+ <value>Object contains non-primitive or non-blittable data.</value>
+ </data>
+ <data name="Arg_SafeArrayRankMismatchException" xml:space="preserve">
+ <value>Specified array was not of the expected rank.</value>
+ </data>
+ <data name="Arg_SafeArrayTypeMismatchException" xml:space="preserve">
+ <value>Specified array was not of the expected type.</value>
+ </data>
+ <data name="Arg_SizeOfNoTypeSizeInfo" xml:space="preserve">
+ <value>Marshal.SizeOf may only be used with blittable types and types used in the generic SizeOf&lt;T&gt; overload methods.</value>
+ </data>
+ <data name="Arg_SizeOfNonValueType" xml:space="preserve">
+ <value>Marshal.SizeOf may only be used with value types.</value>
+ </data>
+ <data name="Argument_InvalidOffLength" xml:space="preserve">
+ <value>The offset and length provided do not fit within the bounds of the array</value>
+ </data>
+ <data name="Argument_NeedNonGenericType" xml:space="preserve">
+ <value>The specified Type must not be a generic type definition.</value>
+ </data>
+ <data name="Argument_NeedStructWithNoRefs" xml:space="preserve">
+ <value>The specified Type must be a struct containing no references.</value>
+ </data>
+ <data name="Argument_ObjNotComObject" xml:space="preserve">
+ <value>The object's type must be __ComObject or derived from __ComObject.</value>
+ </data>
+ <data name="ArgumentNull_Buffer" xml:space="preserve">
+ <value>Buffer cannot be null.</value>
+ </data>
+ <data name="ArgumentOutOfRange_AddressSpace" xml:space="preserve">
+ <value>The number of bytes cannot exceed the virtual address space on a 32 bit machine.</value>
+ </data>
+ <data name="ArgumentOutOfRange_NeedNonNegNum" xml:space="preserve">
+ <value>Non-negative number required.</value>
+ </data>
+ <data name="ArgumentOutOfRange_UIntPtrMaxMinusOne" xml:space="preserve">
+ <value>The length of the buffer must be less than the maximum UIntPtr value for your platform.</value>
+ </data>
+ <data name="Null_HString" xml:space="preserve">
+ <value>Null strings may not be marshaled in Windows Runtime arguments.</value>
+ </data>
+ <data name="BadMarshalField_Null_HString" xml:space="preserve">
+ <value>Null strings may not be marshaled in Windows Runtime fields.</value>
+ </data>
+ <data name="ArrayWithOffsetOverflow" xml:space="preserve">
+ <value>ArrayWithOffset: offset exceeds array size.</value>
+ </data>
+ <data name="InvalidOperation_HCCountOverflow" xml:space="preserve">
+ <value>Handle collector count overflows or underflows.</value>
+ </data>
+ <data name="InvalidOperation_MustCallInitialize" xml:space="preserve">
+ <value>You must call Initialize on this object instance before using it.</value>
+ </data>
+ <data name="StructArrayTooLarge" xml:space="preserve">
+ <value>Array size exceeds addressing limitations.</value>
+ </data>
+ <data name="WrongSizeArrayInNStruct" xml:space="preserve">
+ <value>Type could not be marshaled because the length of an embedded array instance does not match the declared length in the layout.</value>
+ </data>
+ <data name="CustomPropertyProvider_DataBindingError" xml:space="preserve">
+ <value>Failed to bind to property '{0}'. {1}</value>
+ </data>
+ <data name="CustomPropertyProvider_MissingMetadata" xml:space="preserve">
+ <value>Failed to bind to property '{0}'. {1}</value>
+ </data>
+ <data name="Arg_GetMethNotFnd" xml:space="preserve">
+ <value>Property Get method not found.</value>
+ </data>
+ <data name="Arg_SetMethNotFnd" xml:space="preserve">
+ <value>Property Set method not found.</value>
+ </data>
+ <data name="Arg_MethodAccessException_WithMethodName" xml:space="preserve">
+ <value>Attempt to access the method '{0}' on type '{1}' failed.</value>
+ </data>
+ <data name="Arg_RemovedTypeInstantiated" xml:space="preserve">
+ <value>A type that was removed by MCG dependency reduction has been instantiated.</value>
+ </data>
+ <data name="Arg_NotImplementedInNonCoreApiSet" xml:space="preserve">
+ <value>{0} is not implemented for non-CORE_API_SET builds.</value>
+ </data>
+ <data name="Arg_DelegateTypeNotRecognized" xml:space="preserve">
+ <value>Delegate type is not recognized.</value>
+ </data>
+ <data name="Arg_NoMarshalCreatedObjectUsedOutOfTreadContext" xml:space="preserve">
+ <value>The Windows Runtime Object can only be used in the threading context where it was created, because it implements INoMarshal or has MarshalingBehaviorAttribute(MarshalingType.None) set.</value>
+ </data>
+ <data name="Arg_UnexpectedTypeKind" xml:space="preserve">
+ <value>Unexpected TypeKind.</value>
+ </data>
+ <data name="Arg_UnrecognizedTypeName" xml:space="preserve">
+ <value>Unrecognized type name.</value>
+ </data>
+ <data name="Arg_InvalidCustomTypeNameValue" xml:space="preserve">
+ <value>Invalid custom TypeName value.</value>
+ </data>
+ <data name="Arg_InteropMarshalUnmappableChar" xml:space="preserve">
+ <value>Cannot marshal: Encountered unmappable character.</value>
+ </data>
+ <data name="Argument_MustHaveLayoutOrBeBlittable" xml:space="preserve">
+ <value>The specified structure '{0}' must be blittable or have layout information.</value>
+ </data>
+ <data name="TypeNameMarshalling_MissingMetadata" xml:space="preserve">
+ <value>Failed to marshal System.Type instance using metadata information. {0}</value>
+ </data>
+ <data name="Excep_EnumNotStarted" xml:space="preserve">
+ <value>Enum Not Started</value>
+ </data>
+ <data name="Excep_EnumEnded" xml:space="preserve">
+ <value>Enum ended</value>
+ </data>
+ <data name="Excep_EnumFailedVersion" xml:space="preserve">
+ <value>Collection was modified; enumeration operation may not execute.</value>
+ </data>
+ <data name="Excep_NotSupported" xml:space="preserve">
+ <value>Not supported exception.</value>
+ </data>
+ <data name="Excep_CollectionBackingListTooLarge" xml:space="preserve">
+ <value>Collection backing list too large</value>
+ </data>
+ <data name="Excep_KeyNotFound" xml:space="preserve">
+ <value>The given key was not present in the dictionary.</value>
+ </data>
+ <data name="Excep_KeyCollectionSet" xml:space="preserve">
+ <value>Key collection set.</value>
+ </data>
+ <data name="Excep_ValueCollectionSet" xml:space="preserve">
+ <value>Value collection set.</value>
+ </data>
+ <data name="Excep_InsufficientSpaceToCopyCollection" xml:space="preserve">
+ <value>Insufficient space to copy collection.</value>
+ </data>
+ <data name="Excep_IndexOutOfArrayBounds" xml:space="preserve">
+ <value>Index out of array bounds.</value>
+ </data>
+ <data name="Excep_CannotRemoveFromEmptyCollection" xml:space="preserve">
+ <value>Cannot remove from empty collection.</value>
+ </data>
+ <data name="Excep_IndexLargerThanMaxValue" xml:space="preserve">
+ <value>Index larger than max value.</value>
+ </data>
+ <data name="Excep_IndexOutOfRange" xml:space="preserve">
+ <value>The specified index is outside the current index range of this collection.</value>
+ </data>
+ <data name="Excep_AddingDuplicate" xml:space="preserve">
+ <value>Adding duplicate.</value>
+ </data>
+ <data name="Excep_FromHResult" xml:space="preserve">
+ <value>Exception from HRESULT:</value>
+ </data>
+ <data name="Excep_InvalidMarshalAs_Param" xml:space="preserve">
+ <value>Incompatible MarshalAs detected in parameter named '{0}'. Please refer to MCG's warning message for more information.</value>
+ </data>
+ <data name="Excep_InvalidMarshalAs_Field" xml:space="preserve">
+ <value>Incompatible MarshalAs detected in field named '{0}'. Please refer to MCG's warning message for more information.</value>
+ </data>
+ <data name="Excep_InvalidMarshalAs_Return" xml:space="preserve">
+ <value>Incompatible MarshalAs detected in return value. Please refer to MCG's warning message for more information.</value>
+ </data>
+ <data name="Excep_InvalidComObject_NoRCW_Wrapper" xml:space="preserve">
+ <value>COM object that has been separated from its underlying RCW cannot be used.</value>
+ </data>
+ <data name="StructMarshalling_MissingInteropData" xml:space="preserve">
+ <value>{0} is missing structure marshalling data. To enable structure marshalling data, add a MarshalStructure directive to the application rd.xml file. For more information, please visit http://go.microsoft.com/fwlink/?LinkID=393965</value>
+ </data>
+ <data name="DelegateMarshalling_MissingInteropData" xml:space="preserve">
+ <value>{0} is missing delegate marshalling data. To enable delegate marshalling data, add a MarshalDelegate directive to the application rd.xml file. For more information, please visit http://go.microsoft.com/fwlink/?LinkID=393965</value>
+ </data>
+ <data name="ComTypeMarshalling_MissingInteropData" xml:space="preserve">
+ <value>{0} is missing interop type marshalling data. To enable interop type marshalling data, add a MarshalObject directive to the application rd.xml file. For more information, please visit http://go.microsoft.com/fwlink/?LinkID=393965</value>
+ </data>
+ <data name="Not_Enough_Thunks" xml:space="preserve">
+ <value>The maximum number of live delegates have been marshaled to function pointers. More aggressively freeing delegate instances that have been marshaled may resolve this problem. Please notify Microsoft that you have encountered this error.</value>
+ </data>
+ <data name="Arg_NativeToManagedCall" xml:space="preserve">
+ <value>Function has a parameter or return value of SafeHandle. Marshalling between a Windows HANDLE and .NET SafeHandle is not supported when a method is called from native code.</value>
+ </data>
+ <data name="Arg_NeedsDefaultCtor" xml:space="preserve">
+ <value>'{0}' does not have a default constructor. Subclasses of SafeHandle must have a default constructor to support marshaling a Windows HANDLE into managed code.</value>
+ </data>
+ <data name="Arg_OutSafeHandleAsFieldNotSupported" xml:space="preserve">
+ <value>Marshalling a Windows HANDLE to .NET SafeHandle within a structure field is not currently supported.</value>
+ </data>
+ <data name="PropertyValue_InvalidCoersion" xml:space="preserve">
+ <value>Object in an IPropertyValue is of type '{0}' with value '{1}', which cannot be converted to a '{2}'.</value>
+ </data>
+ <data name="PropertyValue_InvalidCast" xml:space="preserve">
+ <value>Object in an IPropertyValue is of type '{0}', which cannot be converted to a '{1}'.</value>
+ </data>
+ <data name="Arg_MustBeDelegateType" xml:space="preserve">
+ <value>Type must derive from Delegate.</value>
+ </data>
+ <data name="Arg_CriticalHandleCannotBeAbstract" xml:space="preserve">
+ <value>'{0}' is abstract. CriticalHandle types must not be abstract to support marshaling CriticalHandles into managed code.</value>
+ </data>
+ <data name="Arg_CriticalHandleMustHaveDefaultCtor" xml:space="preserve">
+ <value>'{0}' does not have a default constructor. CriticalHandle types must have a default constructor to support marshaling CriticalHandles into managed code.</value>
+ </data>
+ <data name="Arg_CriticalHandleReverse" xml:space="preserve">
+ <value>CriticalHandle types cannot be used in signatures of methods called from native code.</value>
+ </data>
+ <data name="Arg_OutCriticalHandleAsFieldNotSupported" xml:space="preserve">
+ <value>Marshalling a Windows HANDLE to .NET CriticalHandle within a structure field is not currently supported.</value>
+ </data>
+ <data name="Argument_OffsetOfFieldNotFound" xml:space="preserve">
+ <value>Field passed in is not a marshaled member of the type '{0}'.</value>
+ </data>
+ <data name="Argument_NeedNonGenericObject" xml:space="preserve">
+ <value>The specified object must not be an instance of a generic type.</value>
+ </data>
+ <data name="InvalidCast_WinRT" xml:space="preserve">
+ <value>Unable to cast object of type '{0}' to type '{1}'.</value>
+ </data>
+ <data name="InvalidCast_Com" xml:space="preserve">
+ <value>Unable to cast COM object of type '{0}' to interface type '{1}'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{2}' failed due to the following error: {3}.</value>
+ </data>
+ <data name="MissingMetadataType" xml:space="preserve">
+ <value>Unknown (Missing metadata for type)</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/System.Private.Interop/src/Shared/ComCallableObject.cs b/src/System.Private.Interop/src/Shared/ComCallableObject.cs
new file mode 100644
index 000000000..438066f5c
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/ComCallableObject.cs
@@ -0,0 +1,1590 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// ----------------------------------------------------------------------------------
+// Interop library code
+//
+// Implementation for CCWs
+//
+// NOTE:
+// These source code are being published to InternalAPIs and consumed by RH builds
+// Use PublishInteropAPI.bat to keep the InternalAPI copies in sync
+// ---------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Text;
+using System.Runtime;
+using System.Diagnostics.Contracts;
+using Internal.NativeFormat;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Cached (CCW, McgTypeInfo) pair
+ /// Used for look up CCW based on type/GUID
+ /// </summary>
+ internal struct CCWCacheEntry
+ {
+ internal McgTypeInfo TypeInfo;
+ internal IntPtr CCW;
+
+ internal CCWCacheEntry(McgTypeInfo typeInfo, IntPtr pCCW)
+ {
+ TypeInfo = typeInfo;
+ CCW = pCCW;
+ }
+ }
+
+ [Flags]
+ internal enum ComCallableObjectFlags : int
+ {
+ None = 0,
+
+ /// <summary>
+ /// The CCW is pegged and will be considered alive if it also has a non-0 Jupiter ref count
+ /// </summary>
+ IsPegged = 0x1,
+
+ /// <summary>
+ /// This CCW is aggregating another RCW - this happens when you have a managed class deriving from
+ /// a WinRT/ComImport type
+ /// </summary>
+ IsAggregatingRCW = 0x2
+ }
+
+ /// <summary>
+ /// Per-interface CCW that we pass out to native
+ /// These are lazily allocated for now (allocated when QI-ed for)
+ /// Native code will treat __interface_ccw* as a COM interface pointer
+ /// @TODO: We should optimize this by merging multiple interface ccws
+ /// into one, like desktop CLR
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ unsafe struct __interface_ccw
+ {
+ //
+ // Important note!!!!
+ //
+ // This structure mirrors the native type __interface_ccw in Interop.Native.lib.
+ // Any updates must be made in both places!
+ //
+ // Also note that SOS takes a dependency on the layout of __interface_ccw and __native_ccw structures.
+ // Please update SOS whenever these data structures are updated. See GetCCWTargetObject() in strike.cpp
+ //
+
+ void* m_pVtable; // Points to v-table
+ __native_ccw* m_pNativeCCW; // Points to a native CCW that manages ref count
+ // and all the __interface_ccw belong to this native CCW
+ __interface_ccw* m_pNext; // Points to the next __interface_ccw
+ // This is needed for cleaning up
+ McgTypeInfo m_McgTypeInfo; // Refer to McgInterfaceData so that we can share CcwVtable across multiple interfaces
+ // TODO: Define unqiue vtable for shared CCW instances, store McgInterfaceData pointer at negative offset
+
+ /// <summary>
+ /// Cache for single memory block, perfect for calls like IDependencyProperty.SetValue (System.Object converts to CCW, passed to native code, then released).
+ /// Last block not freed at shut-down. Consider more complicated caching when there are evidence for it
+ /// </summary>
+ static IntPtr s_cached_interface_ccw;
+
+ /// <summary>
+ /// Allocates a per-interface CCW based on the type
+ /// </summary>
+ internal static __interface_ccw* Allocate(ComCallableObject managedCCW, McgTypeInfo typeInfo)
+ {
+ __interface_ccw* pCcw = (__interface_ccw*)McgComHelpers.CachedAlloc(sizeof(__interface_ccw), ref s_cached_interface_ccw);
+
+ IntPtr vt = typeInfo.CcwVtable;
+
+ if (vt == default(IntPtr))
+ {
+ // McgTypeInfo.RawValue points to an individual McgInterfaceData static field which should have a symbol in pdb file
+
+#if ENABLE_WINRT
+ throw new MissingInteropDataException(McgTypeHelpers.GetDiagnosticMessageForMissingType(managedCCW.TargetObject.GetType().TypeHandle));
+#else
+ Environment.FailFast("CCW discarded.");
+#endif
+
+ }
+
+ pCcw->m_pVtable = vt.ToPointer();
+ pCcw->m_pNativeCCW = managedCCW.NativeCCW;
+ pCcw->m_McgTypeInfo = typeInfo;
+
+ managedCCW.NativeCCW->Link(pCcw);
+
+ return pCcw;
+ }
+
+ internal static void Destroy(__interface_ccw* pInterfaceCCW)
+ {
+ McgComHelpers.CachedFree(pInterfaceCCW, ref s_cached_interface_ccw);
+ }
+
+ internal __interface_ccw* Next
+ {
+ get
+ {
+ return m_pNext;
+ }
+
+ set
+ {
+ m_pNext = value;
+ }
+ }
+
+ internal McgTypeInfo InterfaceInfo
+ {
+ get
+ {
+ return m_McgTypeInfo;
+ }
+ }
+
+ /// <summary>
+ /// Returns the CCW
+ /// Will failfast if the CCW is "neutered"
+ /// </summary>
+ internal ComCallableObject ComCallableObject
+ {
+ get
+ {
+ return m_pNativeCCW->ComCallableObject;
+ }
+ }
+
+ /// <summary>
+ /// Returns NativeCCW
+ /// This works even if the CCW has been "neutered"
+ /// </summary>
+ internal __native_ccw* NativeCCW
+ {
+ /// <remarks>
+ /// WARNING: This function might be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ get
+ {
+ return m_pNativeCCW;
+ }
+ }
+
+ /// <summary>
+ /// Fast method for Release callable from internal managed code, without the cost of [NativeCallable]
+ /// </summary>
+#if !RHTESTCL
+ [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
+#endif
+ internal static int DirectRelease(IntPtr __IntPtr__pComThis)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+
+ //
+ // Use ->NativeCCW to support calling AddRef/Release for neutered CCWs
+ //
+ return pComThis->NativeCCW->ReleaseCOMRef();
+ }
+ }
+
+ /// <summary>
+ /// Native CCW
+ /// This contains all the basic states that needs to survive after the managed CCW and its target are
+ /// garbage collected. The main scenario for this is Jupiter holding a non-0 Jupiter ref count to a
+ /// managed object without pegging.
+ /// </summary>
+ unsafe struct __native_ccw
+ {
+ //
+ // Important note!!!!
+ //
+ // This structure mirrors the native type __native_ccw in Interop.Native.lib.
+ // Any updates must be made in both places!
+ //
+
+ /// <summary>
+ /// Combined Ref Count of COM and Jupiter
+ /// COM takes lower 32-bit while Jupiter takes higher 32-bit.
+ /// It's OK for COM ref count to overflow
+ /// Be verycareful when you read this because you can't read this atomicly under x86 directly.
+ /// Only use CombinedRefCount property for thread-safety
+ /// </summary>
+ long m_lRefCount;
+
+ /// <summary>
+ /// A ref counted handle that points to CCW
+ /// A ref counted handle can be strong or weak depending on the ref count
+ /// It has to pointing to CCW because our RefCount handle callback only work for a specific type of
+ /// object
+ /// </summary>
+ GCHandle m_hCCW;
+
+ /// <summary>
+ /// The first interface CCW
+ /// It is typed as IntPtr to make Interlocked.CompareExchange happy
+ /// The real type is __interface_ccw *
+ /// </summary>
+ IntPtr m_pFirstInterfaceCCW;
+
+ /// <summary>
+ /// Flags of CCW
+ /// Typed as int to make Interlocked.CompareExchange happy (otherwise you'll get error like
+ /// ComCallableObjectFlags must be a reference type to be used in CompareExchange...)
+ /// </summary>
+ int m_flags;
+
+ /// <summary>
+ /// Hashcode of the target object. This is used in CCW map lookup scenarios where we need to save
+ /// to save the hashcode in case the target object is dead
+ /// </summary>
+ int m_hashCode;
+
+ static IntPtr s_cached_native_ccw;
+
+ /// <summary>
+ /// Initialize a native CCW
+ /// </summary>
+ internal static __native_ccw* Allocate(ComCallableObject managedCCW, object targetObject)
+ {
+ __native_ccw* pNativeCCW = (__native_ccw*)McgComHelpers.CachedAlloc(sizeof(__native_ccw), ref s_cached_native_ccw);
+
+ if (pNativeCCW == null)
+ throw new OutOfMemoryException();
+
+ pNativeCCW->Init(managedCCW, targetObject);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWCreation((long)pNativeCCW, (long)0, (long)targetObject.GetTypeHandle().GetRawValue().ToInt64());
+
+ return pNativeCCW;
+ }
+
+ /// <summary>
+ /// Returns handle value for a specific object
+ /// </summary>
+ IntPtr GetObjectID()
+ {
+ IntPtr handleVal = default(IntPtr);
+ fixed (__native_ccw* pThis = &this)
+ {
+ handleVal = (IntPtr)pThis;
+ }
+ return handleVal;
+ }
+
+ /// <summary>
+ /// Initialize this native CCW
+ /// </summary>
+ private void Init(ComCallableObject ccw, object targetObject)
+ {
+ // Start with 1 - we'll release this extra ref count in marshalling code after we QI
+ m_lRefCount = 1;
+
+ m_flags = (int)ComCallableObjectFlags.None;
+
+ m_hCCW = GCHandle.FromIntPtr(
+ InteropExtensions.RuntimeHandleAllocRefCounted(ccw)
+ );
+
+
+ Debug.Assert(m_hCCW.IsAllocated); // GCHandle.FromIntPtr throws exception on null handle
+ m_pFirstInterfaceCCW = default(IntPtr);
+
+ // Using RuntimeHelpers.GetHashCode ensures that __native_ccw is looked up by identity and not
+ // based on semantics defined by a overridden GetHashCode implementation
+ m_hashCode = RuntimeHelpers.GetHashCode(targetObject);
+
+ if (ccw.IsAggregatingRCW)
+ {
+ m_flags |= (int)ComCallableObjectFlags.IsAggregatingRCW;
+
+ //
+ // In aggregation, lRefCount is added ref to 1 by default and we'll only release it when the RCW
+ // is finalized. This protect us from relying on the exact order of native COM object cleanup
+ // and the CCW cleanup as the native COM object might keep a Jupiter reference to the WinRT object
+ //
+ m_lRefCount++;
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWRefCountInc((long)GetObjectID(), m_lRefCount);
+ }
+ }
+
+ internal void Cleanup()
+ {
+ fixed (__native_ccw* pThis = &this)
+ {
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWFinalization((long)GetObjectID(), this.m_lRefCount);
+
+ //
+ // Remove from cache
+ // This should be done as first step to avoid GetOrCreateCCW walking on a CCW that has been
+ // freed
+ //
+ CCWLookupMap.Unregister(pThis);
+
+ //
+ // Walk the linked list of interface CCWs and destroy each one of them
+ //
+ __interface_ccw* pCurrentInterfaceCCW = (__interface_ccw*)m_pFirstInterfaceCCW.ToPointer();
+
+ while (pCurrentInterfaceCCW != null)
+ {
+ __interface_ccw* pNextInterfaceCCW = pCurrentInterfaceCCW->Next;
+ __interface_ccw.Destroy(pCurrentInterfaceCCW);
+ pCurrentInterfaceCCW = pNextInterfaceCCW;
+ }
+
+ // This tells whoever that is debugging that the CCW is dead
+ m_pFirstInterfaceCCW = new IntPtr(unchecked((int)0xbaadf00d));
+
+ m_hCCW.Free();
+
+ // Delete self
+ McgComHelpers.CachedFree(pThis, ref s_cached_native_ccw);
+ }
+ }
+
+ /// <summary>
+ /// Link the interfaceCCW to the interface ccw chain as the new first CCW
+ /// </summary>
+#if !RHTESTCL
+ [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
+#endif
+ internal void Link(__interface_ccw* pInterfaceCCW)
+ {
+ //
+ // Loop to handle possible races
+ //
+ while (true)
+ {
+ //
+ // See if we won the race by replacing the value
+ // NOTE: We don't walk this list unless we are cleaning, so no race condition beyond updating
+ // m_pFirstInterfaceCCW
+ //
+ IntPtr pFirstInterfaceCCW_PrevValue = m_pFirstInterfaceCCW;
+
+ if (Interlocked.CompareExchange(
+ ref m_pFirstInterfaceCCW,
+ (IntPtr)pInterfaceCCW,
+ (IntPtr)pFirstInterfaceCCW_PrevValue) == pFirstInterfaceCCW_PrevValue)
+ {
+ pInterfaceCCW->Next = (__interface_ccw*)pFirstInterfaceCCW_PrevValue.ToPointer();
+ break;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Returns the managed CCW
+ /// Will failfast if CCW is neutered
+ /// </summary>
+ internal ComCallableObject ComCallableObject
+ {
+ get
+ {
+ ComCallableObject ccw = InteropExtensions.UncheckedCast<ComCallableObject>(m_hCCW.Target);
+
+ if (ccw == null)
+ {
+ AccessNeuteredCCW_FailFast();
+ }
+
+ return ccw;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal void AccessNeuteredCCW_FailFast()
+ {
+ //
+ // Failfast to make sure Jupiter doesn't execute some random never-tested failure code
+ // path
+ //
+ Environment.FailFast(
+ "Failfast due to accessing a neutered CCW! " +
+ "You can only access a neutered CCW from ICCW or IUnknown::AddRef/Release");
+ }
+
+ /// <summary>
+ /// Returns managed CCW without checking. Could return null if CCW is neutered
+ /// (Neutered state: target object + CCW both garbage collected while native CCW is still alive due
+ /// to pending jupiter ref count)
+ /// </summary>
+ internal ComCallableObject ComCallableObjectUnsafe
+ {
+ get
+ {
+ return InteropExtensions.UncheckedCast<ComCallableObject>(m_hCCW.Target);
+ }
+ }
+
+ internal GCHandle CCWHandle
+ {
+ get
+ {
+ return m_hCCW;
+ }
+ }
+
+ internal bool IsAggregatingRCW
+ {
+ get
+ {
+ return (m_flags & (int)ComCallableObjectFlags.IsAggregatingRCW) != 0;
+ }
+ }
+
+
+ /// <summary>
+ /// Whether the CCW is pending cleanup
+ /// NOTE: We do want aggregated CCWs to be returned even if nobody is referencing them in native code
+ /// And in that case their ref count would be 1 and the same == 0 check would suffice
+ /// </summary>
+ internal bool IsCleanupPending
+ {
+ get
+ {
+ return (CombinedRefCount == 0);
+ }
+ }
+
+ /// <summary>
+ /// Whether the variable counted handle should be considered a strong one or a weak handle
+ /// If it is a strong handle, it'll keep the managed CCW and the target object alive
+ /// </summary>
+ internal bool IsAlive()
+ {
+ long lRefCount = CombinedRefCount;
+
+ if (lRefCount == 0)
+ return false;
+
+ //
+ // In aggregation, lRefCount is added ref to 1 by default and we'll only release it when the RCW
+ // is finalized. This protect us from relying on the exact order of native COM object cleanup
+ // and the CCW cleanup as the native COM object might keep a Jupiter reference to the WinRT object
+ //
+ if (lRefCount == 1 && IsAggregatingRCW)
+ {
+ return false;
+ }
+
+ return IsAlive(lRefCount);
+ }
+
+ /// <summary>
+ /// Calling IsAlive based on the specified new ref count
+ /// </summary>
+ private bool IsAlive(long lRefCount)
+ {
+ if (COMRefCountFrom(lRefCount) > 0)
+ return true;
+
+ if (IsPegged || RCWWalker.IsGlobalPeggingOn)
+ {
+ if (JupiterRefCountFrom(lRefCount) > 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ #region Ref Count Management
+
+ internal const long COM_REFCOUNT_MASK = 0x00000000FFFFFFFFL; // COM -> 32 bits
+ internal const long JUPITER_REFCOUNT_MASK = unchecked((long)0xFFFFFFFF00000000L); // Jupiter -> 32 bits
+ internal const int JUPITER_REFCOUNT_SHIFT = 32;
+ internal const long JUPITER_REFCOUNT_INC = 0x0000000100000000L;
+ internal const long ALL_REFCOUNT_MASK = unchecked((long)0xFFFFFFFFFFFFFFFFL);
+
+ /// <summary>
+ /// Thread-safe read operation that reads the 64-bit integer in one atomic operation
+ /// </summary>
+ private long CombinedRefCount
+ {
+ get
+ {
+ return Volatile.Read(ref m_lRefCount);
+ }
+ }
+
+ /// <summary>
+ /// Returns Jupiter ref count from the combined 64-bit ref count
+ /// This assumes the value in lRefCount is consistent
+ /// </summary>
+ private int JupiterRefCountFrom(long lRefCount)
+ {
+ return unchecked((int)((lRefCount & JUPITER_REFCOUNT_MASK) >> JUPITER_REFCOUNT_SHIFT));
+ }
+
+ /// <summary>
+ /// Returns COM ref count from the combined 64-bit ref count
+ /// This assumes the value in lRefCount is consistent
+ /// </summary>
+ private int COMRefCountFrom(long lRefCount)
+ {
+ int comRefCnt = (int)((lRefCount & COM_REFCOUNT_MASK));
+
+ //
+ // In aggregation, lRefCount is added ref to 1 by default and we'll only release it when the RCW
+ // is finalized. This protect us from relying on the exact order of native COM object cleanup
+ // and the CCW cleanup as the native COM object might keep a Jupiter reference to the WinRT object
+ //
+ if (IsAggregatingRCW)
+ comRefCnt--;
+
+ return comRefCnt;
+ }
+
+ /// <summary>
+ /// Returns the Jupiter ref count
+ /// Be very careful when you use both ref count to make a decision as you might run into a race
+ /// </summary>
+ internal int JupiterRefCount
+ {
+ get
+ {
+ return JupiterRefCountFrom(CombinedRefCount);
+ }
+ }
+
+ /// <summary>
+ /// Returns the COM ref count
+ /// Be very careful when you use both ref count to make a decision as you might run into a race
+ /// </summary>
+ internal int COMRefCount
+ {
+ get
+ {
+ return COMRefCountFrom(CombinedRefCount);
+ }
+ }
+
+ internal int AddJupiterRef()
+ {
+ long lNewRefCount = Interlocked.Add(ref m_lRefCount, JUPITER_REFCOUNT_INC);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWRefCountInc((long)GetObjectID(), lNewRefCount);
+
+ return JupiterRefCountFrom(lNewRefCount);
+ }
+
+ internal int ReleaseJupiterRef()
+ {
+ long lNewRefCount = Interlocked.Add(ref m_lRefCount, -1 * JUPITER_REFCOUNT_INC);
+
+ //
+ // Only cleanup if both ref count reaches 0
+ // This is a thread-safe way to observe both ref count in one big 64-bit integer
+ //
+ if (lNewRefCount == 0)
+ {
+ Cleanup();
+ return 0;
+ }
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWRefCountInc((long)GetObjectID(), lNewRefCount);
+
+ return JupiterRefCountFrom(lNewRefCount);
+ }
+
+ internal int AddCOMRef()
+ {
+ long lNewRefCount = Interlocked.Increment(ref m_lRefCount);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWRefCountInc((long)GetObjectID(), lNewRefCount);
+
+ return COMRefCountFrom(lNewRefCount);
+ }
+
+ /// <summary>
+ /// We consider ref count == 0 to be a state of pending cleanup and GetOrCreateCCW should never
+ /// return such CCW from the map
+ /// However, there is a possible race condition that the CCW ref count drops to 0 after the
+ /// IsPendingCleanup check. So we are doing our ultimate check by doing an addref here.
+ /// If the addref-ed refcount is not 1, then we've successfully done a addref and potentially 'rescued' the
+ /// CCW
+ /// If the ref count is 1, then we've seen a pending cleanup CCW and we should reset the ref
+ /// count and bail out
+ /// </summary>
+ /// <returns>True if AddRef is done successfully. false means the CCW is pending cleanup and
+ /// AddRef is failed</returns>
+ internal bool TryAddCOMRefIfNotCleanupPending()
+ {
+ long lNewRefCount = Interlocked.Increment(ref m_lRefCount);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWRefCountInc((long)GetObjectID(), lNewRefCount);
+
+ if (lNewRefCount == 1)
+ {
+ //
+ // We've just resurrected this CCW that is currently being cleaned up by a CCW
+ // Fortunately, that thread is still waiting on us to release the lock (we are in
+ // GetOrCreateCCW) so no harm is done yet. We should bail out and repair ref count
+ //
+ lNewRefCount = Interlocked.Decrement(ref m_lRefCount);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWRefCountDec((long)GetObjectID(), lNewRefCount);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ internal int ReleaseCOMRef()
+ {
+ long lNewRefCount = Interlocked.Decrement(ref m_lRefCount);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWRefCountDec((long)GetObjectID(), lNewRefCount);
+
+ //
+ // Only cleanup if both ref count reaches 0
+ // This is a thread-safe way to observe both ref count in one big 64-bit integer
+ //
+ if (lNewRefCount == 0)
+ {
+ // Perf optimization: when ref count reaches zero, handle is going to be freed, no need to change type
+ Cleanup();
+
+ return 0;
+ }
+
+ return COMRefCountFrom(lNewRefCount);
+ }
+
+ #endregion
+
+ #region Flags
+
+ /// <summary>
+ /// Whether the NativeCCW is neutered
+ /// (Neutered state: target object + CCW both garbage collected while native CCW is still alive due
+ /// to pending jupiter ref count)
+ /// </summary>
+ internal bool IsNeutered
+ {
+ get
+ {
+ return ComCallableObjectUnsafe == null;
+ }
+ }
+
+ /// <summary>
+ /// Whether this CCW is pegged
+ /// </summary>
+ internal bool IsPegged
+ {
+ get
+ {
+ return IsFlagSet(ComCallableObjectFlags.IsPegged);
+ }
+
+ set
+ {
+ SetFlag(ComCallableObjectFlags.IsPegged, value);
+ }
+ }
+
+ /// <summary>
+ /// Thread-safe version of setting flags
+ /// </summary>
+ private void SetFlag(ComCallableObjectFlags newFlag, bool isSet)
+ {
+ SpinWait spin = new SpinWait();
+
+ while (true)
+ {
+ int oldFlags = m_flags;
+ int updatedFlags = oldFlags;
+
+ if (isSet)
+ updatedFlags |= (int)newFlag;
+ else
+ updatedFlags &= (int)(~newFlag);
+
+ if (Interlocked.CompareExchange(ref m_flags, updatedFlags, oldFlags) == oldFlags)
+ return;
+
+ spin.SpinOnce();
+ }
+ }
+
+ private bool IsFlagSet(ComCallableObjectFlags flag)
+ {
+ return ((m_flags & (int)flag) != 0);
+ }
+
+ internal int GetFlags()
+ {
+ return m_flags;
+ }
+
+ #endregion
+
+ #region CCW lookup related
+
+ internal int GetHashCodeForLookup()
+ {
+ return m_hashCode;
+ }
+ #endregion
+ }
+
+ /// <summary>
+ /// System.IntPtr does not provide IEquatable<System.IntPtr>. So we need our own wrapper
+ /// </summary>
+ internal struct EquatableIntPtr : IEquatable<EquatableIntPtr>
+ {
+ unsafe private void* m_value;
+
+ unsafe internal EquatableIntPtr(void* p)
+ {
+ m_value = p;
+ }
+
+ internal unsafe void* ToPointer()
+ {
+ return m_value;
+ }
+
+ public unsafe bool Equals(EquatableIntPtr other)
+ {
+ return m_value == other.m_value;
+ }
+ }
+
+ /// <summary>
+ /// Maintains target object -> CCW mapping so that we could go from an object to its existing CCW without
+ /// creating a new one
+ /// The goal of this map is to maintain the mapping without introducing extra GCHandles, which means it
+ /// basically utilize the existing RefCounted Handle from CCWs
+ /// New implementation using Internal.HashSet<EquatableIntPtr> searching using RuntimeHelpers.GetHashCode(target) as hash code
+ /// </summary>
+ internal unsafe class CCWLookupMap
+ {
+ /// <summary>
+ /// Maintains target object -> CCW mapping
+ /// </summary>
+ static System.Collections.Generic.Internal.HashSet<EquatableIntPtr> s_ccwLookupMap;
+
+ /// <summary>
+ /// Lock for s_ccwLookupMap, much faster than locking through object
+ /// </summary>
+ static Lock s_ccwLookupMapLock;
+
+ static internal void InitializeStatics()
+ {
+ const int CCWLookupMapDefaultSize = 101;
+
+ s_ccwLookupMap = new System.Collections.Generic.Internal.HashSet<EquatableIntPtr>(CCWLookupMapDefaultSize);
+
+ s_ccwLookupMapLock = new Lock();
+ }
+
+ /// <summary>
+ /// Returns existing CCW or a new CCW for the target object
+ /// The returned CCW has been Addrefed to avoid race condition
+ /// </summary>
+ /// <remarks>If typeInfo is not empty, add it to newly created CCW under lock for perf</remarks>
+ internal static ComCallableObject GetOrCreateCCW(object target, McgTypeInfo typeInfo, out IntPtr interfaceCCW)
+ {
+ interfaceCCW = default(IntPtr);
+
+ try
+ {
+ s_ccwLookupMapLock.Acquire();
+
+ ComCallableObject ret = null;
+
+ // Hashcode to search for
+ int hashCode = RuntimeHelpers.GetHashCode(target);
+
+ // FindFirstKey/FindNextKey will return keys with matching hash code here
+ EquatableIntPtr key = default(EquatableIntPtr);
+
+ // Internal.HashSet's special replacement for TryGetValue, allowing us to operate on key only, also inline comparer
+ for (int entry = s_ccwLookupMap.FindFirstKey(ref key, hashCode); entry >= 0; entry = s_ccwLookupMap.FindNextKey(ref key, entry))
+ {
+ // Compare CCW to check for matching targets
+ __native_ccw* pNativeCCW = (__native_ccw*)key.ToPointer();
+
+ ComCallableObject ccw = pNativeCCW->ComCallableObjectUnsafe;
+
+ //
+ // It is possible that we walked up on a CCW that
+ // 1) has been 'neutered' and its variable handle field points to NULL.
+ // At that point, ComCallableObject and the managed target object are already gone
+ // 2) we might not finished removing it from the cache because the Unregister call
+ // is waiting on this lookup operation
+ //
+ // To avoid us from crashing, we should retrieve the ComCallableObject and see if it is
+ // null. If it is not null, proceed to retrieve its target object which could either be:
+ // 1) NULL and thus never matches your search
+ // 2) NON-NULL and might be a match. NOTE: There is no risk of resurrecting this object.
+ // If it is a match, then it must be alive in order to be the target of the lookup
+ //
+
+ // Using Object.ReferenceEquals ensures that the targetObject is looked up by identity and not
+ // based on semantics defined by a overridden Equals implementation
+ if ((ccw != null) && Object.ReferenceEquals(target, ccw.TargetObject) && !pNativeCCW->IsCleanupPending)
+ {
+ //
+ // If we successfully add ref this, we'll keep this CCW and we'll never race with a cleanup
+ // If we happen to addref this from 0 to 1, then TryAddCOMRefIfNotCleanupPending will reset it to 0
+ // and we'll skip this CCW
+ //
+ if (!pNativeCCW->TryAddCOMRefIfNotCleanupPending())
+ continue;
+
+ //
+ // Most likely the managed CCW is still there when we are making comparisons, but it might
+ // be gone right after that and before we call __native_ccw->ComCallableObject
+ // So call the unsafe version to avoid failing fast - we'll create a new CCW later
+ //
+ ret = ccw;
+
+ break;
+ }
+ }
+
+ if (ret == null)
+ {
+ ret = new ComCallableObject(target, true /* locked */);
+
+ // For newly created CCW, add typeInfo to it as first entry without extra locking for perf
+ if (!typeInfo.IsNull)
+ {
+ interfaceCCW = ret.AddFirstTypeInfo_NoAddRef(typeInfo);
+ }
+ }
+
+ //
+ // Make sure the target object will be alive at this point. See above for details
+ //
+ GC.KeepAlive(target);
+
+ return ret;
+ }
+ finally
+ {
+ s_ccwLookupMapLock.Release();
+ }
+ }
+
+ /// <summary>
+ /// Register the CCW for lookup
+ /// </summary>
+ internal static void Register(__native_ccw* pNativeCCW)
+ {
+ //
+ // Creates a lookup key that contains the native CCW
+ // We set target object to null because we don't want the target object to held alive
+ // target object will only be set to non-null if we are doing a lookup
+ //
+ EquatableIntPtr key = new EquatableIntPtr(pNativeCCW);
+
+ try
+ {
+ s_ccwLookupMapLock.Acquire();
+
+ bool existing = s_ccwLookupMap.Add(key, pNativeCCW->GetHashCodeForLookup());
+
+ Debug.Assert(!existing);
+ }
+ finally
+ {
+ s_ccwLookupMapLock.Release();
+ }
+ }
+
+ /// <summary>
+ /// Register the CCW for lookup under lock
+ /// </summary>
+#if !RHTESTCL
+ [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
+#endif
+ internal static void RegisterLocked(__native_ccw* pNativeCCW)
+ {
+ //
+ // Creates a lookup key that contains the native CCW
+ // We set target object to null because we don't want the target object to held alive
+ // target object will only be set to non-null if we are doing a lookup
+ //
+ EquatableIntPtr key = new EquatableIntPtr(pNativeCCW);
+
+ bool existing = s_ccwLookupMap.Add(key, pNativeCCW->GetHashCodeForLookup());
+
+ Debug.Assert(!existing);
+ }
+
+ internal static void Unregister(__native_ccw* pNativeCCW)
+ {
+ Debug.Assert(s_ccwLookupMapLock != null);
+
+ EquatableIntPtr key = new EquatableIntPtr(pNativeCCW);
+
+ Lock _lock = s_ccwLookupMapLock;
+
+ try
+ {
+ _lock.Acquire();
+
+ //
+ // Because CCWLookupMap will never resurrect a CCW from ref count 0 to 1
+ // We should always successfully remove this CCW from the map
+ //
+ bool removed = s_ccwLookupMap.Remove(key, pNativeCCW->GetHashCodeForLookup());
+ Debug.Assert(removed);
+ }
+ finally
+ {
+ _lock.Release();
+ }
+ }
+
+ /// <summary>
+ /// The actual CCW walk happens here.
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal static void LogCCWs()
+ {
+ EquatableIntPtr key = default(EquatableIntPtr);
+ int index = -1;
+
+ for (bool hasEntry = s_ccwLookupMap.GetNext(ref key, ref index); hasEntry; hasEntry = s_ccwLookupMap.GetNext(ref key, ref index))
+ {
+ __native_ccw* pNativeCCW = (__native_ccw*)key.ToPointer();
+ ComCallableObject ccw = pNativeCCW->ComCallableObjectUnsafe;
+
+ if (ccw != null)
+ {
+ //TODO extract CCW IUnk and pass it instead of null
+ GCEventProvider.TaskLogLiveCCW(GCHandle.ToIntPtr(pNativeCCW->CCWHandle),
+ InteropExtensions.GetObjectID(ccw.TargetObject), ccw.TargetObject.GetTypeHandle().GetRawValue(), (IntPtr)0,
+ pNativeCCW->COMRefCount, pNativeCCW->JupiterRefCount, pNativeCCW->GetFlags());
+ }
+ }
+ }
+ }
+
+#if RHTESTCL
+ //====================================================================
+ // The enum of the return value of ICustomQueryInterface.GetInterface
+ // NOTE: Public to MCG only
+ //====================================================================
+ public enum CustomQueryInterfaceResult
+ {
+ Handled = 0,
+ NotHandled = 1,
+ Failed = 2,
+ }
+
+ //====================================================================
+ // The interface for customizing IQueryInterface
+ // NOTE: Public to MCG only
+ //====================================================================
+ public interface ICustomQueryInterface
+ {
+ CustomQueryInterfaceResult GetInterface(ref Guid iid, out IntPtr ppv);
+ }
+#endif
+
+ /// <summary>
+ /// Managed CCW implementation
+ ///
+ /// The hierachy of CCW look like this:
+ ///
+ /// __interface_ccw ->
+ /// |
+ /// __interface_ccw -> __native_ccw -> (RefCountedHandle) -> managed CCW -> object
+ /// |
+ /// __interface_ccw ->
+ ///
+ /// 1. __interface_ccw is the per-interface CCW that acts likea COM interface pointer
+ /// 2. CCW manages the lifetime of all __interface_ccw(s) and points to the target object
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ unsafe internal class ComCallableObject
+ {
+ #region Private variables
+
+ __native_ccw* m_pNativeCCW; // Native CCW
+ LightweightList<CCWCacheEntry>.WithInlineStorage m_CCWs; // List of cached CCWs
+
+ /// <summary>
+ /// Managed object aggregating a native COM/WinRT object
+ /// CCW is the outer, and the RCW is the inner
+ /// </summary>
+ __ComObject m_innerRCW;
+
+ /// <summary>
+ /// Points to the target object
+ /// </summary>
+ object m_target;
+
+ /// <summary>
+ /// Points to the per-type CCWTemplateData which contains per-type information such as what is the
+ /// runtime class name for this CCW, etc
+ /// </summary>
+ CCWTemplateInfo m_ccwTemplateInfo;
+
+ #endregion
+
+
+ #region RefCounted handle support
+
+ static internal void InitRefCountedHandleCallback()
+ {
+ //
+ // Register the callback to ref-counted handles
+ // Inside this callback we'll determine whether the ref count handle to the target object
+ // should be weak or strong
+ //
+ InteropExtensions.RuntimeRegisterRefCountedHandleCallback(
+ AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIsAlive>(ComCallableObject.IsAlive),
+ typeof(ComCallableObject).TypeHandle
+ );
+ }
+
+ /// <summary>
+ /// Whether this CCW is alive
+ /// The ref-counted handle to the target object will be set to strong handle or weak handle depending on
+ /// the answer here
+ /// <summary>
+ [GCCallback]
+ internal static bool IsAlive(ComCallableObject ccw)
+ {
+ return ccw.NativeCCW->IsAlive();
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Per-Type CCW information. See CCWTemplateData for more details
+ /// </summary>
+ internal CCWTemplateInfo Template
+ {
+ get
+ {
+ return m_ccwTemplateInfo;
+ }
+ }
+
+ /// <summary>
+ /// Check whether the COM pointer is a CCW
+ /// If it is, return the corresponding CCW
+ /// </summary>
+ /// <param name="pComItf">Incoming COM pointer to check</param>
+ /// <param name="ccw">The returned CCW</param>
+ /// <returns>True if the com pointer is a CCW. False otherwise. </returns>
+ internal static unsafe bool TryGetCCW(IntPtr pComItf, out ComCallableObject ccw)
+ {
+ __com_IUnknown* pUnk = (__com_IUnknown*)(void*)pComItf;
+
+ //
+ // Check if the v-table slot matches - if it does, it is our __interface_ccw structure
+ //
+ if (pUnk->pVtable->pfnQueryInterface == ((__vtable_IUnknown*)__vtable_IUnknown.GetCcwvtable_IUnknown())->pfnQueryInterface)
+ {
+ ccw = ComCallableObject.FromThisPointer(new IntPtr(pUnk));
+ return true;
+ }
+ else
+ {
+ ccw = null;
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Get CCW from this pointer. You should only use inside a CCW v-table method where this pointer
+ /// is guaranteed to be correct
+ /// </summary>
+ /// <param name="pUnk">The IUnknown pointer</param>
+ /// <returns>The corresponding CCW. Will failfast if CCW is neutered</returns>
+ /// <remarks>
+ /// WARNING1: This function might be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// WARNING2: This will *CRASH* if the CCW is neutered.
+ /// </remarks>
+ [GCCallback]
+ internal static ComCallableObject FromThisPointer(IntPtr pUnk)
+ {
+ return ((__interface_ccw*)pUnk)->ComCallableObject;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ internal static object GetTarget(IntPtr pUnk)
+ {
+ ComCallableObject obj = ((__interface_ccw*)pUnk)->ComCallableObject;
+
+ return obj.TargetObject;
+ }
+
+ /// <summary>
+ /// Replacement for GetTarget for shared CCW implementation
+ /// 1) Get target object
+ /// 3) Return marshal index
+ /// 4) Return thunk function, stored in CcwVtable field
+ /// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ internal static object GetThunk(IntPtr pUnk, out int marshalIndex, out McgModule module,out IntPtr thunk)
+ {
+ McgTypeInfo typeInfo = ((__interface_ccw*)pUnk)->InterfaceInfo;
+
+ marshalIndex = typeInfo.MarshalIndex;
+
+ module = typeInfo.ContainingModule;
+
+ ComCallableObject obj = ((__interface_ccw*)pUnk)->ComCallableObject;
+
+ object target = obj.TargetObject;
+
+ // Casting will be performed when calling methods on interface from thunk function
+ Debug.Assert((typeInfo.Flags & McgInterfaceFlags.useSharedCCW) != 0);
+
+ thunk = typeInfo.InterfaceData.CcwVtable;
+
+ return target;
+ }
+
+ internal ComCallableObject(object target)
+ {
+ Init(target, null, false);
+ }
+
+ internal ComCallableObject(object target, bool locked)
+ {
+ Debug.Assert(locked);
+
+ Init(target, null, locked);
+ }
+
+ internal void Init(object target, __ComObject innerRCW, bool locked)
+ {
+ if (innerRCW != null)
+ {
+ Debug.Assert(!innerRCW.ExtendsComObject);
+
+ m_innerRCW = innerRCW;
+ m_innerRCW.ExtendsComObject = true;
+
+ //
+ // This forms a cycle between the CCW and the actual managed object (RCW)
+ // which keeps their lifetime tied together and is exactly what we want
+ //
+ m_innerRCW.Outer = this;
+ }
+
+ m_CCWs = new LightweightList<CCWCacheEntry>.WithInlineStorage();
+ m_pNativeCCW = __native_ccw.Allocate(this, target);
+ m_target = target;
+
+ if (locked)
+ CCWLookupMap.RegisterLocked(m_pNativeCCW);
+ else
+ CCWLookupMap.Register(m_pNativeCCW);
+
+ m_ccwTemplateInfo = McgModuleManager.GetCCWTemplateInfo(m_target.GetTypeHandle());
+ }
+
+ /// <summary>
+ /// Returns the native CCW that manages all the interface CCWs
+ /// </summary>
+ internal __native_ccw* NativeCCW
+ {
+ get
+ {
+ return m_pNativeCCW;
+ }
+ }
+
+ /// <summary>
+ /// Increase Jupiter ref count which will make ref count handle a strong handle if pegged & Jupiter
+ /// ref count > 0
+ /// </summary>
+ internal int AddJupiterRef()
+ {
+ return m_pNativeCCW->AddJupiterRef();
+ }
+
+ /// <summary>
+ /// Decrease Jupiter ref count
+ /// </summary>
+ internal int ReleaseJupiterRef()
+ {
+ return m_pNativeCCW->ReleaseJupiterRef();
+ }
+
+ /// <summary>
+ /// Peg this CCW - it'll make ref counted handle a strong handle if jupiter ref count > 0
+ /// NOTE: It is not a count, but rather a boolean state
+ /// </summary>
+ internal void Peg()
+ {
+ m_pNativeCCW->IsPegged = true;
+ }
+
+ /// <summary>
+ /// Unpeg this CCW
+ /// NOTE: It is not a count, but rather a boolean state
+ /// </summary>
+ internal void Unpeg()
+ {
+ m_pNativeCCW->IsPegged = false;
+ }
+
+ /// <summary>
+ /// Constructor that creates an CCW that aggregates a RCW
+ /// CCW is the outer, and RCW is the inner
+ /// This usually happens when you have a managed object deriving from a native object
+ /// </summary>
+ internal ComCallableObject(object target, __ComObject innerRCW)
+ {
+ Init(target, innerRCW, false);
+ }
+
+ /// <summary>
+ /// Returns target managed object that this CCW is holding onto
+ /// </summary
+ /// <remarks>
+ /// WARNING: This function might be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal object TargetObject
+ {
+ get
+ {
+ return m_target;
+ }
+ }
+
+ internal IntPtr GetComInterfaceForIID(ref Guid iid)
+ {
+ return GetComInterfaceForIID(ref iid, McgTypeInfo.Null);
+ }
+
+ internal IntPtr GetComInterfaceForIID(ref Guid iid, McgTypeInfo typeInfo)
+ {
+ IntPtr pRet = GetComInterfaceForIIDInternal(ref iid, typeInfo);
+
+ // The interface for a specific interface ID is not available. In this case, the returned interface is null.
+ // E_NOINTERFACE is fired in the event.
+ if ((pRet == default(IntPtr)) && (InteropEventProvider.IsEnabled()))
+ InteropEventProvider.Log.TaskCCWQueryInterfaceFailure((long)this.NativeCCW, iid);
+
+ return pRet;
+ }
+
+ private static bool SupportsWellKnownInterface(McgTypeInfo typeInfo, object targetObject)
+ {
+ bool isInternalModule = typeInfo.IsInternalModule;
+
+ if (isInternalModule)
+ {
+ switch ((InternalModule.Indexes)typeInfo.MarshalIndex)
+ {
+ // interfaces supported by every CCW
+ case InternalModule.Indexes.IUnknown:
+#if ENABLE_WINRT
+ case InternalModule.Indexes.IInspectable:
+ case InternalModule.Indexes.IWeakReferenceSource:
+ case InternalModule.Indexes.ICustomPropertyProvider:
+ case InternalModule.Indexes.IStringable:
+ // Implemented by all managed objects
+ return true;
+
+ case InternalModule.Indexes.IWeakReference:
+ return targetObject is WeakReferenceSource;
+
+ case InternalModule.Indexes.ICCW:
+#if X86 && RHTESTCL
+ //
+ // Make sure we don't tap into ICCW in rhtestcl x86. See ICCW implementation in RCWWalker for
+ // more details
+ //
+ return false;
+#else
+ return true;
+#endif // X86 && RHTESTCL
+
+ case InternalModule.Indexes.IJupiterObject:
+ // No CCW implements IJupiterObject
+ return false;
+
+ case InternalModule.Indexes.IRestrictedErrorInfo:
+ // No CCW implements IRestrictedErrorInfo
+ return false;
+
+ case InternalModule.Indexes.IActivationFactoryInternal:
+ return targetObject is IActivationFactoryInternal;
+
+ case InternalModule.Indexes.IManagedActivationFactory:
+ return targetObject is IManagedActivationFactory;
+#endif
+
+ case InternalModule.Indexes.IMarshal:
+ // Every CCW implements IMarshal
+ return true;
+
+ default:
+ Debug.Assert(false, "Unrecgonized InternalModule.Index");
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ private IntPtr GetComInterfaceForIIDInternal(ref Guid iid, McgTypeInfo typeInfo)
+ {
+#pragma warning disable 618
+ object targetObject = TargetObject;
+
+ if (InteropExtensions.GuidEquals(ref iid, ref Interop.COM.IID_IUnknown))
+ {
+ typeInfo = McgModuleManager.IUnknown;
+ return GetComInterfaceForTypeInfo_NoCheck(typeInfo);
+ }
+
+ //
+ // Simplified implementation of ICustomQueryInterface
+ // It is needed internally to customize CCW behavior
+ //
+ ICustomQueryInterface customQueryInterfaceImpl = targetObject as ICustomQueryInterface;
+
+ if (customQueryInterfaceImpl != null)
+ {
+ IntPtr pRet;
+ CustomQueryInterfaceResult result = customQueryInterfaceImpl.GetInterface(ref iid, out pRet);
+ if (result == CustomQueryInterfaceResult.Failed)
+ return default(IntPtr);
+ else if (result == CustomQueryInterfaceResult.Handled)
+ return pRet;
+ else
+ Debug.Assert(result == CustomQueryInterfaceResult.NotHandled);
+ }
+#pragma warning restore 618
+ //
+ // Check IAgileObject - all CCWs are agile by default
+ //
+ if (InteropExtensions.GuidEquals(ref iid, ref Interop.COM.IID_IAgileObject))
+ {
+ // Return the IUnknown pointer for IAgileObject - IAgileObject has no other methods anyway
+ return GetComInterfaceForTypeInfo_NoCheck(McgModuleManager.IUnknown);
+ }
+
+ CCWTemplateInfo ccwTemplateData = this.Template;
+
+ //
+ // Determine whether this interface is supported by this CCW
+ // Variance is supported by the template itself which includes all possible variant interfaces
+ //
+ if (!ccwTemplateData.IsNull)
+ {
+ InterfaceCheckResult checkResult =
+ ccwTemplateData.ContainingModule.SupportsInterface(ccwTemplateData.Index, ref iid, ref typeInfo);
+
+ if (checkResult == InterfaceCheckResult.Supported)
+ {
+ return GetComInterfaceForTypeInfo_NoCheck(typeInfo);
+ }
+ else if (checkResult == InterfaceCheckResult.Rejected)
+ {
+ //
+ // This interface is defined in a WinRT class and as a result we've rejected this
+ // interface. This happens because client QI for a interface from the WinRT base
+ // class, and we can simply let the base handle that request.
+ //
+ }
+ }
+
+ //
+ // Look it up in internal module (where all the well known interfaces are)
+ // NOTE: This needs to happen after we check the templates because we prefer user implementation
+ // over to our own implementation
+ //
+ if (typeInfo.IsNull)
+ typeInfo = McgModuleManager.s_internalModule.GetTypeInfo(ref iid);
+
+ if (!typeInfo.IsNull && SupportsWellKnownInterface(typeInfo, targetObject))
+ return GetComInterfaceForTypeInfo_NoCheck(typeInfo);
+
+ //
+ // If there isn't a McgTypeInfo for the iid and we are aggregating then QI on the inner
+ // since it may support the iid even if we haven't seen it before
+ //
+ //
+ // In phone, InfinitePivot is trying to QI on the outer for Windows.UI.Xaml.Phone.Pivot
+ // during their factory creation, and we are not yet ready for that because the inner RCW
+ // is not setup yet. We should reject that QI request.
+ //
+ if (m_innerRCW != null && m_innerRCW.BaseIUnknown_UnsafeNoAddRef != default(IntPtr))
+ {
+ return McgMarshal.ComQueryInterfaceNoThrow(m_innerRCW.BaseIUnknown_UnsafeNoAddRef, ref iid);
+ }
+
+ //
+ // Do a global McgTypeInfo lookup if everything else failed and we don't have a CCWTemplate
+ // We should never do a global McgTypeInfo lookup if we have a CCWTemplate - that would
+ // defeat the whole purpose of CCWTemplate
+ // NOTE: This is not correct in the case of aggregation, because the 'is' cast might
+ // should be made on the derived type itself, not the base, but there is no way to do that yet.
+ // However, because we would only miss CCWTemplate for MCG generated wrappers and there won't
+ // be any aggregation for them.
+ //
+ if (ccwTemplateData.IsNull)
+ {
+ //
+ // Fallback to old slow code path for types we don't have template for
+ // This does a global lookup across all modules so eventually we should try to get rid of
+ // this completely.
+ // I'm keeping this code path for now because there is no guarantee we'll have CCWTemplate
+ // for everything we need yet (such as IKeyValuePair adapters in MCG)
+ //
+ if (typeInfo.IsNull)
+ {
+ //
+ // Enumerate all McgTypeInfo with specified iid and check whether Object support any of these McgTypeInfo
+ // The reason for doing this is that the ccwTemplateData is null and thus we dont know which type does this Object support
+ // in future, we should try to fix ccwTemplateData is null case.
+ foreach (McgTypeInfo info in McgModuleManager.GetTypeInfosFromGuid(ref iid))
+ {
+ //
+ // This happens when there is a user managed object instance that doesn't implement any interop
+ // interface, while somebody QIs for a known interface that was imported but was reduced
+ // because we decided we don't need generate reverse interop methods for this interface (when
+ // no managed object that was constructed implementing this interface).
+ // In the future, once we generate CCW templates for all MCG generated wrappers, we don't have
+ // to handle this scenario anymore, and we can safely get rid of this slow path and the ugly
+ // 'is this interface reduced' check.
+ //
+ if (!info.IsNull && info.ItfType.Equals(McgModule.s_DependencyReductionTypeRemovedTypeHandle))
+ continue;
+
+ if (!info.IsNull && info.IsSupportedBy(targetObject))
+ return GetComInterfaceForTypeInfo_NoCheck(info);
+ }
+ }
+ else
+ {
+ //
+ // This happens when there is a user managed object instance that doesn't implement any interop
+ // interface, while somebody QIs for a known interface that was imported but was reduced
+ // because we decided we don't need generate reverse interop methods for this interface (when
+ // no managed object that was constructed implementing this interface).
+ // In the future, once we generate CCW templates for all MCG generated wrappers, we don't have
+ // to handle this scenario anymore, and we can safely get rid of this slow path and the ugly
+ // 'is this interface reduced' check.
+ //
+ if (!typeInfo.IsNull && typeInfo.ItfType.Equals(McgModule.s_DependencyReductionTypeRemovedTypeHandle))
+ return default(IntPtr);
+
+ if (!typeInfo.IsNull && typeInfo.IsSupportedBy(targetObject))
+ return GetComInterfaceForTypeInfo_NoCheck(typeInfo);
+ }
+ }
+
+ //
+ // We are not aggregating and don't have a McgTypeInfo for the iid so we must return null
+ //
+ return default(IntPtr);
+ }
+
+ internal IntPtr GetComInterfaceForTypeInfo_NoCheck_NoAddRef(McgTypeInfo typeInfo)
+ {
+ //
+ // Look up our existing list of CCWs and see if we can find a match
+ //
+ foreach (CCWCacheEntry entry in m_CCWs)
+ {
+ if (typeInfo == entry.TypeInfo)
+ {
+ return entry.CCW;
+ }
+ }
+
+ //
+ // Target object supports this interface
+ // Let's create a new CCW for it
+ //
+ IntPtr pNewCCW = new IntPtr(__interface_ccw.Allocate(this, typeInfo));
+
+ m_CCWs.Add(new CCWCacheEntry(typeInfo, pNewCCW));
+
+ return pNewCCW;
+ }
+
+ /// <summary>
+ /// Create first CCW to support an interface
+ /// </summary>
+ internal IntPtr AddFirstTypeInfo_NoAddRef(McgTypeInfo typeInfo)
+ {
+ // Target object supports this interface
+ // Let's create a new CCW for it
+ //
+ IntPtr pNewCCW = new IntPtr(__interface_ccw.Allocate(this, typeInfo));
+
+ m_CCWs.AddFirst(new CCWCacheEntry(typeInfo, pNewCCW));
+
+ return pNewCCW;
+ }
+
+ internal IntPtr GetComInterfaceForTypeInfo_NoCheck(McgTypeInfo typeInfo)
+ {
+ IntPtr result = GetComInterfaceForTypeInfo_NoCheck_NoAddRef(typeInfo);
+
+ if (result != default(IntPtr))
+ {
+ this.AddRef();
+ }
+
+ return result;
+ }
+
+ internal int AddRef()
+ {
+ return m_pNativeCCW->AddCOMRef();
+ }
+
+ internal int Release()
+ {
+ return m_pNativeCCW->ReleaseCOMRef();
+ }
+
+ #region Aggregation Support
+
+ internal bool IsAggregatingRCW
+ {
+ get
+ {
+ return m_innerRCW != null;
+ }
+ }
+ #endregion
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/ComException.cs b/src/System.Private.Interop/src/Shared/ComException.cs
new file mode 100644
index 000000000..bb0178bf8
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/ComException.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.
+
+/*=============================================================================
+**
+** Class: COMException
+**
+**
+** Purpose: Exception class for all errors from COM Interop where we don't
+** recognize the HResult.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ // Exception for COM Interop errors where we don't recognize the HResult.
+ //
+ public class COMException : System.Exception
+ {
+ internal COMException(int hr)
+ {
+ HResult = hr;
+ }
+
+ public COMException()
+ {
+ }
+
+ public COMException(string message) :
+ base(message)
+ {
+ }
+
+ public COMException(string message, Exception inner) :
+ base(message, inner)
+ {
+ }
+
+ public COMException(string message, int errorCode) :
+ base(message)
+ {
+ HResult = errorCode;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/ComInterop.cs b/src/System.Private.Interop/src/Shared/ComInterop.cs
new file mode 100644
index 000000000..9edcf526b
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/ComInterop.cs
@@ -0,0 +1,366 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// ----------------------------------------------------------------------------------
+// Interop library code
+//
+// NOTE:
+// These source code are being published to InternalAPIs and consumed by RH builds
+// Use PublishInteropAPI.bat to keep the InternalAPI copies in sync
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Text;
+using System.Runtime;
+using System.Diagnostics.Contracts;
+using Internal.NativeFormat;
+
+namespace System.Runtime.InteropServices
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct HSTRING
+ {
+ public IntPtr handle;
+
+ public HSTRING(IntPtr hndl)
+ {
+ handle = hndl;
+ }
+ }
+
+ // 24 a bit overkill in x86 (which needs 20) but it doesn't really matter as we always allocate
+ // it in stack
+ [StructLayout(LayoutKind.Explicit, Size = 24)]
+ public struct HSTRING_HEADER
+ {
+ }
+
+ /// <summary>
+ /// The native DECIMAL struct
+ /// The reason we have our own DECIMAL struct is for the 8-byte alignment caused by the ulong, other than
+ /// that it is considered blittable. Note that managed System.Decimal is 4-byte aligned
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential)]
+ public struct DECIMAL
+ {
+ ulong Hi64;
+ ulong Lo64;
+
+ internal unsafe DECIMAL(Decimal dec)
+ {
+ ulong* p = (ulong*)&dec;
+ Hi64 = *p;
+ Lo64 = *(p + 1);
+ }
+
+ internal unsafe Decimal ToDecimal()
+ {
+ Decimal dec;
+ ulong* p = (ulong*)&dec;
+ *p = Hi64;
+ *(p + 1) = Lo64;
+
+ return dec;
+ }
+
+ public static implicit operator Decimal(DECIMAL dec)
+ {
+ return dec.ToDecimal();
+ }
+
+ public static implicit operator DECIMAL(Decimal dec)
+ {
+ return new DECIMAL(dec);
+ }
+ }
+
+ internal enum TypeKind
+ {
+ Primitive,
+ Metadata,
+ Custom,
+ }
+
+#pragma warning disable 649 // The fields of TypeName are never used in RhTestCl, but still need to be there
+ internal struct TypeName
+ {
+ public HSTRING Name;
+ public TypeKind Kind;
+ }
+#pragma warning restore 649
+
+ internal enum TrustLevel
+ {
+ BaseTrust = 0,
+ PartialTrust = 1,
+ FullTrust = 2
+ };
+
+ //
+ // An array-based list type built for fast concurrent access. We support only adding items and enumerating
+ // existing items. However, enumerations can run conconcurrently on multiple threads, even while a write is
+ // in progress. (We only allow a single write at a time.)
+ //
+ // LightweightList is a struct to avoid extra object allocations. However, be careful not to copy these around
+ // accidentally. That will result in very bad behavior.
+ //
+ // An additional nested type, LightweightList<T>.WithInlineStorage, provides space for one item in the struct itself.
+ // For lists that often contain just one item, this eliminates allocations altogether.
+ //
+ internal struct LightweightList<T>
+ {
+ //
+ // Holds the data. When we run out of capacity, we double the size of the array.
+ //
+ T[] m_array;
+
+ //
+ // Bit 0: set if there is a thread modifying this list. Only one writer is allowed at any given time.
+ // Remaining bits: the number of items in the list.
+ //
+ int m_countAndLock;
+
+ const int InitialCapacity = 2;
+
+ private void AssertLockHeld()
+ {
+ Debug.Assert((Volatile.Read(ref m_countAndLock) & 1) == 1);
+ }
+
+ private int AcquireLockAndGetCount()
+ {
+ SpinWait spin = new SpinWait();
+
+ while (true)
+ {
+ int oldCountAndLock = Volatile.Read(ref m_countAndLock);
+
+ if ((oldCountAndLock & 1) == 0)
+ {
+ if (Interlocked.CompareExchange(ref m_countAndLock, oldCountAndLock | 1, oldCountAndLock) == oldCountAndLock)
+ {
+ return oldCountAndLock >> 1;
+ }
+ }
+
+ spin.SpinOnce();
+ }
+ }
+
+ private void ReleaseLockAndSetCount(int newCount)
+ {
+ AssertLockHeld();
+
+ //
+ // Volatile write to prevent reordering with previous writes.
+ //
+ Volatile.Write(ref m_countAndLock, newCount << 1);
+ }
+
+ private void SetArrayElement(int index, T value)
+ {
+ AssertLockHeld();
+
+ T[] oldArray = m_array;
+ T[] newArray;
+
+ if (oldArray == null)
+ {
+ newArray = new T[InitialCapacity];
+ }
+ else if (oldArray.Length <= index)
+ {
+ newArray = new T[oldArray.Length * 2];
+
+ for (int i = 0; i < oldArray.Length; i++)
+ {
+ newArray[i] = oldArray[i];
+ }
+ }
+ else
+ {
+ newArray = oldArray;
+ }
+
+ newArray[index] = value;
+
+ if (newArray != oldArray)
+ {
+ //
+ // Volatile write to ensure all previous writes are complete.
+ //
+ Volatile.Write(ref m_array, newArray);
+ }
+ }
+
+ private void GetArrayAndCount(out T[] array, out int count)
+ {
+ //
+ // Read the count, then the array. We have to do it in this order, so that we won't read
+ // a count that's larger than array we previously found. Note that the read from m_countAndLock
+ // is volatile, preventing reordering with the subsequent read from m_array.
+ //
+ count = Volatile.Read(ref m_countAndLock) >> 1;
+ array = m_array;
+ }
+
+ public void Add(T value)
+ {
+ int oldCount = AcquireLockAndGetCount();
+ SetArrayElement(oldCount, value);
+ ReleaseLockAndSetCount(oldCount + 1);
+ }
+
+ public Enumerator GetEnumerator()
+ {
+ T[] array;
+ int count;
+ GetArrayAndCount(out array, out count);
+
+ return new Enumerator(count, array);
+ }
+
+ public struct Enumerator
+ {
+ int m_current;
+ int m_count;
+ T[] m_array;
+
+ internal Enumerator(int count, T[] array)
+ {
+ m_current = -1;
+ m_count = count;
+ m_array = array;
+ }
+
+ public bool MoveNext()
+ {
+ return ++m_current < m_count;
+ }
+
+ public T Current
+ {
+ get
+ {
+ Debug.Assert(m_array != null);
+ return m_array[m_current];
+ }
+ }
+ }
+
+ //
+ // Wrapper around LightweightList to provide a single slot of inline storage. This prevents allocations
+ // for lists of just one item.
+ //
+ public struct WithInlineStorage
+ {
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "m_list" and field type:LightweightList
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::GetInterfaceData in debug\dbi\values.cpp
+ /// </summary>
+ LightweightList<T> m_list;
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "m_item0"
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::GetInterfaceData in debug\dbi\values.cpp
+ /// </summary>
+ T m_item0;
+
+ public void Add(T value)
+ {
+ int oldCount = m_list.AcquireLockAndGetCount();
+
+ if (oldCount == 0)
+ m_item0 = value;
+ else
+ m_list.SetArrayElement(oldCount - 1, value);
+
+ m_list.ReleaseLockAndSetCount(oldCount + 1);
+ }
+
+ /// <summary>
+ /// Add first entry for a new ComCallableObject, no locking needed
+ /// </summary>
+ /// <param name="value"></param>
+ public void AddFirst(T value)
+ {
+ Debug.Assert(m_list.m_countAndLock == 0);
+
+ m_item0 = value;
+
+ m_list.m_countAndLock = 1 << 1;
+ }
+
+ public Enumerator GetEnumerator()
+ {
+ T[] array;
+ int count;
+ m_list.GetArrayAndCount(out array, out count);
+ T item0 = m_item0;
+
+ return new Enumerator(count, array, item0);
+ }
+
+ public struct Enumerator
+ {
+ int m_current;
+ int m_count;
+ T[] m_array;
+ T m_item0;
+
+ internal Enumerator(int count, T[] array, T item0)
+ {
+ m_current = -1;
+ m_count = count;
+ m_array = array;
+ m_item0 = item0;
+ }
+
+ public bool MoveNext()
+ {
+ return ++m_current < m_count;
+ }
+
+ public T Current
+ {
+ get
+ {
+ if (m_current == 0)
+ {
+ return m_item0;
+ }
+ else
+ {
+ Debug.Assert(m_array != null);
+ return m_array[m_current - 1];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ internal enum InterfaceCheckResult
+ {
+ Supported,
+ Rejected,
+ NotFound
+ }
+}
+
+namespace System.Runtime.InteropServices.WindowsRuntime
+{
+ public interface IManagedActivationFactory
+ {
+ void RunClassConstructor();
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/DebugAnnotations.cs b/src/System.Private.Interop/src/Shared/DebugAnnotations.cs
new file mode 100644
index 000000000..260f28dee
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/DebugAnnotations.cs
@@ -0,0 +1,24 @@
+// 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;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Annotations used by debugger
+ /// </summary>
+ public static class DebugAnnotations
+ {
+ /// <summary>
+ /// Informs debugger that previous line contains user code and debugger needs to dive deeper inside
+ /// to find user code.
+ /// </summary>
+ [Conditional("DEBUG")]
+ public static void PreviousCallContainsUserCode()
+ {
+ // This is a marker method and has no code in method body
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/Dictionary.cs b/src/System.Private.Interop/src/Shared/Dictionary.cs
new file mode 100644
index 000000000..7a7d1fbc8
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/Dictionary.cs
@@ -0,0 +1,1167 @@
+// 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.CompilerServices;
+using System.Threading;
+
+namespace System.Collections.Generic.Internal
+{
+ /// <summary>
+ /// Simplified version of Dictionary<K,V>
+ /// 1. Deriving from DictionaryBase to share common code
+ /// 2. Hashing/bucket moved to DictionaryBase
+ /// 3. Seperate TKey,TValue array. This will get rid of array with both TKey and TValue
+ /// 4. No interface implementation. You pay for the methods called
+ /// 5. Support FindFirstKey/FindNextKey, hash code based search (returning key to caller for key comparison)
+ /// 6. If comparer is provided, it has to be non null. This allows reducing dependency on EqualityComparer<TKey>.Default
+ /// </summary>
+ /// <typeparam name="TKey"></typeparam>
+ /// <typeparam name="TValue"></typeparam>
+ internal class Dictionary<TKey, TValue> : DictionaryBase
+ {
+ private TKey[] keyArray;
+ private TValue[] valueArray;
+
+ private IEqualityComparer<TKey> comparer;
+ private Lock m_lock;
+
+ public Dictionary()
+ : this(0, EqualityComparer<TKey>.Default, false)
+ {
+ }
+
+ public Dictionary(bool sync) : this(0, EqualityComparer<TKey>.Default, sync)
+ {
+ }
+
+ public Dictionary(int capacity)
+ : this(capacity, EqualityComparer<TKey>.Default, false)
+ {
+ }
+
+ public Dictionary(int capacity, bool sync) : this(capacity, EqualityComparer<TKey>.Default, sync)
+ {
+ }
+
+ public Dictionary(IEqualityComparer<TKey> comparer)
+ : this(0, comparer, false)
+ {
+ }
+
+ public Dictionary(IEqualityComparer<TKey> comparer, bool sync) : this(0, comparer, sync)
+ {
+ }
+
+ public Dictionary(int capacity, IEqualityComparer<TKey> comparer) : this(capacity, comparer, false)
+ {
+ }
+
+ public Dictionary(int capacity, IEqualityComparer<TKey> comparer, bool sync)
+ {
+ // If comparer parameter is passed in, it can't be null
+ // This removes dependency on EqualityComparer<TKey>.Default which brings bunch of cost
+ Debug.Assert(comparer != null);
+
+ if (capacity > 0)
+ {
+ Initialize(capacity);
+ }
+
+ this.comparer = comparer;
+
+ if (sync)
+ {
+ m_lock = new Lock();
+ }
+ }
+
+ public Dictionary(IDictionary<TKey, TValue> dictionary) : this(dictionary, EqualityComparer<TKey>.Default)
+ {
+ }
+
+ public Dictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) :
+ this(dictionary != null ? dictionary.Count : 0, comparer)
+ {
+ if (dictionary == null)
+ {
+ throw new ArgumentNullException("dictionary");
+ }
+
+ foreach (KeyValuePair<TKey, TValue> pair in dictionary)
+ {
+ Add(pair.Key, pair.Value);
+ }
+ }
+
+ public void LockAcquire()
+ {
+ Debug.Assert(m_lock != null);
+
+ m_lock.Acquire();
+ }
+
+ public void LockRelease()
+ {
+ Debug.Assert(m_lock != null);
+
+ m_lock.Release();
+ }
+
+ public IEqualityComparer<TKey> Comparer
+ {
+ get
+ {
+ return comparer;
+ }
+ }
+
+ public KeyCollection Keys
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<KeyCollection>() != null);
+
+ return new KeyCollection(this);
+ }
+ }
+
+ public ValueCollection Values
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<ValueCollection>() != null);
+
+ return new ValueCollection(this);
+ }
+ }
+
+ public Enumerator GetEnumerator()
+ {
+ return new Enumerator(this, Enumerator.KeyValuePair);
+ }
+
+ public TValue this[TKey key]
+ {
+ get
+ {
+ int i = FindEntry(key);
+
+ if (i >= 0)
+ {
+ return valueArray[i];
+ }
+
+ throw new KeyNotFoundException();
+ }
+ set
+ {
+ Insert(key, value, false);
+ }
+ }
+
+ public void Add(TKey key, TValue value)
+ {
+ if (!Insert(key, value, true))
+ {
+ throw new ArgumentException(SR.Argument_AddingDuplicate);
+ }
+ }
+
+ public void Add(TKey key, TValue value, int hashCode)
+ {
+ if (!Insert(key, value, true, hashCode))
+ {
+ throw new ArgumentException(SR.Argument_AddingDuplicate);
+ }
+ }
+
+ public void Clear()
+ {
+ if (count > 0)
+ {
+ ClearBase();
+ Array.Clear(keyArray, 0, count);
+ Array.Clear(valueArray, 0, count);
+ }
+ }
+
+ public bool ContainsKey(TKey key)
+ {
+ return FindEntry(key) >= 0;
+ }
+
+ public bool ContainsValue(TValue value)
+ {
+ if (value == null)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ if (entries[i].hashCode >= 0 && valueArray[i] == null)
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ EqualityComparer<TValue> c = EqualityComparer<TValue>.Default;
+
+ for (int i = 0; i < count; i++)
+ {
+ if (entries[i].hashCode >= 0 && c.Equals(valueArray[i], value))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
+ {
+ if (array == null)
+ {
+ throw new ArgumentNullException("array");
+ }
+
+ if (index < 0 || index > array.Length)
+ {
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+
+ if (array.Length - index < Count)
+ {
+ throw new ArgumentException(SR.Arg_ArrayPlusOffTooSmall);
+ }
+
+ int count = this.count;
+ Entry[] entries = this.entries;
+
+ for (int i = 0; i < count; i++)
+ {
+ if (entries[i].hashCode >= 0)
+ {
+ array[index++] = new KeyValuePair<TKey, TValue>(keyArray[i], valueArray[i]);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get total count of items, including free cells
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [System.Runtime.InteropServices.GCCallback]
+ public int GetMaxCount()
+ {
+ return this.count;
+ }
+
+ /// <summary>
+ /// Get Key[i], return true if not free
+ /// </summary>
+ public bool GetKey(int index, ref TKey key)
+ {
+ Debug.Assert((index >= 0) && (index < this.count));
+
+ if (entries[index].hashCode >= 0)
+ {
+ key = keyArray[index];
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Get Value[i], return true if not free
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [System.Runtime.InteropServices.GCCallback]
+ public bool GetValue(int index, ref TValue value)
+ {
+ Debug.Assert((index >= 0) && (index < this.count));
+
+ if (entries[index].hashCode >= 0)
+ {
+ value = valueArray[index];
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private int FindEntry(TKey key)
+ {
+ if (entries != null)
+ {
+ int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
+
+ for (int i = entries[ModLength(hashCode)].bucket; i >= 0; i = entries[i].next)
+ {
+ if (entries[i].hashCode == hashCode && comparer.Equals(keyArray[i], key))
+ {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ private int FindEntry(TKey key, int hashCode)
+ {
+ if (entries != null)
+ {
+ hashCode = hashCode & 0x7FFFFFFF;
+
+ for (int i = entries[ModLength(hashCode)].bucket; i >= 0; i = entries[i].next)
+ {
+ if (entries[i].hashCode == hashCode && comparer.Equals(keyArray[i], key))
+ {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ /// <summary>
+ /// First first matching entry, returning index, update key
+ /// </summary>
+ /// <param name="key"></param>
+ /// <returns></returns>
+ public int FindFirstKey(ref TKey key)
+ {
+ int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
+
+ int entry = FindFirstEntry(hashCode);
+
+ if (entry >= 0)
+ {
+ key = keyArray[entry];
+ }
+
+ return entry;
+ }
+
+ /// <summary>
+ /// Find next matching entry, returning index, update key
+ /// </summary>
+ /// <param name="key"></param>
+ /// <param name="entry"></param>
+ /// <returns></returns>
+ public int FindNextKey(ref TKey key, int entry)
+ {
+ entry = FindNextEntry(entry);
+
+ if (entry >= 0)
+ {
+ key = keyArray[entry];
+ }
+
+ return entry;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void Initialize(int capacity)
+ {
+ int size = InitializeBase(capacity);
+
+ keyArray = new TKey[size];
+ valueArray = new TValue[size];
+ }
+
+ private bool Insert(TKey key, TValue value, bool add)
+ {
+ return Insert(key, value, add, comparer.GetHashCode(key));
+ }
+
+ private bool Insert(TKey key, TValue value, bool add, int hashCode)
+ {
+ if (entries == null)
+ {
+ Initialize(0);
+ }
+
+ hashCode = hashCode & 0x7FFFFFFF;
+ int targetBucket = ModLength(hashCode);
+
+ for (int i = entries[targetBucket].bucket; i >= 0; i = entries[i].next)
+ {
+ if (entries[i].hashCode == hashCode && comparer.Equals(keyArray[i], key))
+ {
+ if (add)
+ {
+ return false;
+ }
+
+ valueArray[i] = value;
+ version++;
+
+ return true;
+ }
+ }
+
+ int index;
+
+ if (freeCount > 0)
+ {
+ index = freeList;
+ freeList = entries[index].next;
+ freeCount--;
+ }
+ else
+ {
+ if (count == entries.Length)
+ {
+ Resize();
+ targetBucket = ModLength(hashCode);
+ }
+
+ index = count;
+ count++;
+ }
+
+ entries[index].hashCode = hashCode;
+ entries[index].next = entries[targetBucket].bucket;
+ keyArray[index] = key;
+ valueArray[index] = value;
+ entries[targetBucket].bucket = index;
+ version++;
+
+ return true;
+ }
+
+ private void Resize()
+ {
+ Resize(HashHelpers.ExpandPrime(count));
+ }
+
+ private void Resize(int newSize)
+ {
+#if !RHTESTCL
+ Contract.Assert(newSize >= entries.Length);
+#endif
+
+ Entry[] newEntries = ResizeBase1(newSize);
+
+ TKey[] newKeys = new TKey[newSize];
+ Array.Copy(keyArray, 0, newKeys, 0, count);
+
+ TValue[] newValues = new TValue[newSize];
+ Array.Copy(valueArray, 0, newValues, 0, count);
+
+ ResizeBase2(newEntries, newSize);
+
+ keyArray = newKeys;
+ valueArray = newValues;
+ }
+
+ public bool Remove(TKey key)
+ {
+ if (entries != null)
+ {
+ int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
+ int bucket = ModLength(hashCode);
+ int last = -1;
+
+ for (int i = entries[bucket].bucket; i >= 0; last = i, i = entries[i].next)
+ {
+ if (entries[i].hashCode == hashCode && comparer.Equals(keyArray[i], key))
+ {
+ if (last < 0)
+ {
+ entries[bucket].bucket = entries[i].next;
+ }
+ else
+ {
+ entries[last].next = entries[i].next;
+ }
+
+ entries[i].hashCode = -1;
+ entries[i].next = freeList;
+ keyArray[i] = default(TKey);
+ valueArray[i] = default(TValue);
+ freeList = i;
+ freeCount++;
+ version++;
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ int i = FindEntry(key);
+
+ if (i >= 0)
+ {
+ value = valueArray[i];
+ return true;
+ }
+
+ value = default(TValue);
+
+ return false;
+ }
+
+ public bool TryGetValue(TKey key, int hashCode, out TValue value)
+ {
+ int i = FindEntry(key, hashCode);
+
+ if (i >= 0)
+ {
+ value = valueArray[i];
+ return true;
+ }
+
+ value = default(TValue);
+
+ return false;
+ }
+
+ /// <summary>
+ /// Return matching key
+ /// </summary>
+ public bool TryGetKey(ref TKey key)
+ {
+ int i = FindEntry(key);
+
+ if (i >= 0)
+ {
+ key = keyArray[i];
+ return true;
+ }
+
+ return false;
+ }
+
+ public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>,
+ IDictionaryEnumerator
+ {
+ private Dictionary<TKey, TValue> dictionary;
+ private int version;
+ private int index;
+ private KeyValuePair<TKey, TValue> current;
+ private int getEnumeratorRetType; // What should Enumerator.Current return?
+
+ internal const int DictEntry = 1;
+ internal const int KeyValuePair = 2;
+
+ internal Enumerator(Dictionary<TKey, TValue> dictionary, int getEnumeratorRetType)
+ {
+ this.dictionary = dictionary;
+ version = dictionary.version;
+ index = 0;
+ this.getEnumeratorRetType = getEnumeratorRetType;
+ current = new KeyValuePair<TKey, TValue>();
+ }
+
+ public bool MoveNext()
+ {
+ if (version != dictionary.version)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
+ }
+
+ // Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
+ // dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
+ while ((uint)index < (uint)dictionary.count)
+ {
+ if (dictionary.entries[index].hashCode >= 0)
+ {
+ current = new KeyValuePair<TKey, TValue>(dictionary.keyArray[index], dictionary.valueArray[index]);
+ index++;
+
+ return true;
+ }
+
+ index++;
+ }
+
+ index = dictionary.count + 1;
+ current = new KeyValuePair<TKey, TValue>();
+
+ return false;
+ }
+
+ public KeyValuePair<TKey, TValue> Current
+ {
+ get { return current; }
+ }
+
+ public void Dispose()
+ {
+ }
+
+ object IEnumerator.Current
+ {
+ get
+ {
+ if (index == 0 || (index == dictionary.count + 1))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
+ }
+
+ if (getEnumeratorRetType == DictEntry)
+ {
+ return new System.Collections.DictionaryEntry(current.Key, current.Value);
+ }
+ else
+ {
+ return new KeyValuePair<TKey, TValue>(current.Key, current.Value);
+ }
+ }
+ }
+
+ void IEnumerator.Reset()
+ {
+ if (version != dictionary.version)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
+ }
+
+ index = 0;
+ current = new KeyValuePair<TKey, TValue>();
+ }
+
+ DictionaryEntry IDictionaryEnumerator.Entry
+ {
+ get
+ {
+ if (index == 0 || (index == dictionary.count + 1))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
+ }
+
+ return new DictionaryEntry(current.Key, current.Value);
+ }
+ }
+
+ object IDictionaryEnumerator.Key
+ {
+ get
+ {
+ if (index == 0 || (index == dictionary.count + 1))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
+ }
+
+ return current.Key;
+ }
+ }
+
+ object IDictionaryEnumerator.Value
+ {
+ get
+ {
+ if (index == 0 || (index == dictionary.count + 1))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
+ }
+
+ return current.Value;
+ }
+ }
+ }
+
+ public sealed class KeyCollection : ICollection<TKey>, ICollection
+ {
+ private Dictionary<TKey, TValue> dictionary;
+
+ public KeyCollection(Dictionary<TKey, TValue> dictionary)
+ {
+ if (dictionary == null)
+ {
+ throw new ArgumentNullException("dictionary");
+ }
+
+ this.dictionary = dictionary;
+ }
+
+ public Enumerator GetEnumerator()
+ {
+ return new Enumerator(dictionary);
+ }
+
+ public void CopyTo(TKey[] array, int index)
+ {
+ if (array == null)
+ {
+ throw new ArgumentNullException("array");
+ }
+
+ if (index < 0 || index > array.Length)
+ {
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+
+ if (array.Length - index < dictionary.Count)
+ {
+ throw new ArgumentException(SR.Arg_ArrayPlusOffTooSmall);
+ }
+
+ int count = dictionary.count;
+ TKey[] keys = dictionary.keyArray;
+ Entry[] entries = dictionary.entries;
+
+ for (int i = 0; i < count; i++)
+ {
+ if (entries[i].hashCode >= 0)
+ {
+ array[index++] = keys[i];
+ }
+ }
+ }
+
+ public int Count
+ {
+ get { return dictionary.Count; }
+ }
+
+ bool ICollection<TKey>.IsReadOnly
+ {
+ get { return true; }
+ }
+
+ void ICollection<TKey>.Add(TKey item)
+ {
+ throw new NotSupportedException(SR.NotSupported_KeyCollectionSet);
+ }
+
+ void ICollection<TKey>.Clear()
+ {
+ throw new NotSupportedException(SR.NotSupported_KeyCollectionSet);
+ }
+
+ bool ICollection<TKey>.Contains(TKey item)
+ {
+ return dictionary.ContainsKey(item);
+ }
+
+ bool ICollection<TKey>.Remove(TKey item)
+ {
+ throw new NotSupportedException(SR.NotSupported_KeyCollectionSet);
+ }
+
+ IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator()
+ {
+ return new Enumerator(dictionary);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return new Enumerator(dictionary);
+ }
+
+ void ICollection.CopyTo(Array array, int index)
+ {
+ if (array == null)
+ {
+ throw new ArgumentNullException("array");
+ }
+
+ if (array.Rank != 1)
+ {
+ throw new ArgumentException(SR.Arg_RankMultiDimNotSupported);
+ }
+
+ if (array.GetLowerBound(0) != 0)
+ {
+ throw new ArgumentException(SR.Arg_NonZeroLowerBound);
+ }
+
+ if (index < 0 || index > array.Length)
+ {
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+
+ if (array.Length - index < dictionary.Count)
+ {
+ throw new ArgumentException(SR.Arg_ArrayPlusOffTooSmall);
+ }
+
+ TKey[] keys = array as TKey[];
+
+ if (keys != null)
+ {
+ CopyTo(keys, index);
+ }
+ else
+ {
+ object[] objects = array as object[];
+
+ if (objects == null)
+ {
+ throw new ArgumentException(SR.Argument_InvalidArrayType);
+ }
+
+ int count = dictionary.count;
+ Entry[] entries = dictionary.entries;
+ TKey[] ks = dictionary.keyArray;
+
+ try
+ {
+ for (int i = 0; i < count; i++)
+ {
+ if (entries[i].hashCode >= 0)
+ {
+ objects[index++] = ks[i];
+ }
+ }
+ }
+ catch (ArrayTypeMismatchException)
+ {
+ throw new ArgumentException(SR.Argument_InvalidArrayType);
+ }
+ }
+ }
+
+ bool ICollection.IsSynchronized
+ {
+ get { return false; }
+ }
+
+ Object ICollection.SyncRoot
+ {
+ get { return ((ICollection)dictionary).SyncRoot; }
+ }
+
+ public struct Enumerator : IEnumerator<TKey>, System.Collections.IEnumerator
+ {
+ private Dictionary<TKey, TValue> dictionary;
+ private int index;
+ private int version;
+ private TKey currentKey;
+
+ internal Enumerator(Dictionary<TKey, TValue> dictionary)
+ {
+ this.dictionary = dictionary;
+ version = dictionary.version;
+ index = 0;
+ currentKey = default(TKey);
+ }
+
+ public void Dispose()
+ {
+ }
+
+ public bool MoveNext()
+ {
+ if (version != dictionary.version)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
+ }
+
+ while ((uint)index < (uint)dictionary.count)
+ {
+ if (dictionary.entries[index].hashCode >= 0)
+ {
+ currentKey = dictionary.keyArray[index];
+ index++;
+
+ return true;
+ }
+
+ index++;
+ }
+
+ index = dictionary.count + 1;
+ currentKey = default(TKey);
+
+ return false;
+ }
+
+ public TKey Current
+ {
+ get
+ {
+ return currentKey;
+ }
+ }
+
+ Object System.Collections.IEnumerator.Current
+ {
+ get
+ {
+ if (index == 0 || (index == dictionary.count + 1))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
+ }
+
+ return currentKey;
+ }
+ }
+
+ void System.Collections.IEnumerator.Reset()
+ {
+ if (version != dictionary.version)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
+ }
+
+ index = 0;
+ currentKey = default(TKey);
+ }
+ }
+ }
+
+ public sealed class ValueCollection : ICollection<TValue>, ICollection
+ {
+ private Dictionary<TKey, TValue> dictionary;
+
+ public ValueCollection(Dictionary<TKey, TValue> dictionary)
+ {
+ if (dictionary == null)
+ {
+ throw new ArgumentNullException("dictionary");
+ }
+
+ this.dictionary = dictionary;
+ }
+
+ public Enumerator GetEnumerator()
+ {
+ return new Enumerator(dictionary);
+ }
+
+ public void CopyTo(TValue[] array, int index)
+ {
+ if (array == null)
+ {
+ throw new ArgumentNullException("array");
+ }
+
+ if (index < 0 || index > array.Length)
+ {
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+
+ if (array.Length - index < dictionary.Count)
+ {
+ throw new ArgumentException(SR.Arg_ArrayPlusOffTooSmall);
+ }
+
+ int count = dictionary.count;
+ Entry[] entries = dictionary.entries;
+ TValue[] values = dictionary.valueArray;
+
+ for (int i = 0; i < count; i++)
+ {
+ if (entries[i].hashCode >= 0)
+ {
+ array[index++] = values[i];
+ }
+ }
+ }
+
+ public int Count
+ {
+ get { return dictionary.Count; }
+ }
+
+ bool ICollection<TValue>.IsReadOnly
+ {
+ get { return true; }
+ }
+
+ void ICollection<TValue>.Add(TValue item)
+ {
+ throw new NotSupportedException(SR.NotSupported_ValueCollectionSet);
+ }
+
+ bool ICollection<TValue>.Remove(TValue item)
+ {
+ throw new NotSupportedException(SR.NotSupported_ValueCollectionSet);
+ }
+
+ void ICollection<TValue>.Clear()
+ {
+ throw new NotSupportedException(SR.NotSupported_ValueCollectionSet);
+ }
+
+ bool ICollection<TValue>.Contains(TValue item)
+ {
+ return dictionary.ContainsValue(item);
+ }
+
+ IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
+ {
+ return new Enumerator(dictionary);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return new Enumerator(dictionary);
+ }
+
+ void ICollection.CopyTo(Array array, int index)
+ {
+ if (array == null)
+ {
+ throw new ArgumentNullException("array");
+ }
+
+ if (array.Rank != 1)
+ {
+ throw new ArgumentException(SR.Arg_RankMultiDimNotSupported);
+ }
+
+ if (array.GetLowerBound(0) != 0)
+ {
+ throw new ArgumentException(SR.Arg_NonZeroLowerBound);
+ }
+
+ if (index < 0 || index > array.Length)
+ {
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+
+ if (array.Length - index < dictionary.Count)
+ throw new ArgumentException(SR.Arg_ArrayPlusOffTooSmall);
+
+ TValue[] values = array as TValue[];
+
+ if (values != null)
+ {
+ CopyTo(values, index);
+ }
+ else
+ {
+ object[] objects = array as object[];
+
+ if (objects == null)
+ {
+ throw new ArgumentException(SR.Argument_InvalidArrayType);
+ }
+
+ int count = dictionary.count;
+ Entry[] entries = dictionary.entries;
+ TValue[] vs = dictionary.valueArray;
+
+ try
+ {
+ for (int i = 0; i < count; i++)
+ {
+ if (entries[i].hashCode >= 0)
+ {
+ objects[index++] = vs[i];
+ }
+ }
+ }
+ catch (ArrayTypeMismatchException)
+ {
+ throw new ArgumentException(SR.Argument_InvalidArrayType);
+ }
+ }
+ }
+
+ bool ICollection.IsSynchronized
+ {
+ get { return false; }
+ }
+
+ Object ICollection.SyncRoot
+ {
+ get { return ((ICollection)dictionary).SyncRoot; }
+ }
+
+ public struct Enumerator : IEnumerator<TValue>, System.Collections.IEnumerator
+ {
+ private Dictionary<TKey, TValue> dictionary;
+ private int index;
+ private int version;
+ private TValue currentValue;
+
+ internal Enumerator(Dictionary<TKey, TValue> dictionary)
+ {
+ this.dictionary = dictionary;
+ version = dictionary.version;
+ index = 0;
+ currentValue = default(TValue);
+ }
+
+ public void Dispose()
+ {
+ }
+
+ public bool MoveNext()
+ {
+ if (version != dictionary.version)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
+ }
+
+ while ((uint)index < (uint)dictionary.count)
+ {
+ if (dictionary.entries[index].hashCode >= 0)
+ {
+ currentValue = dictionary.valueArray[index];
+ index++;
+
+ return true;
+ }
+
+ index++;
+ }
+
+ index = dictionary.count + 1;
+ currentValue = default(TValue);
+
+ return false;
+ }
+
+ public TValue Current
+ {
+ get
+ {
+ return currentValue;
+ }
+ }
+
+ Object System.Collections.IEnumerator.Current
+ {
+ get
+ {
+ if (index == 0 || (index == dictionary.count + 1))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
+ }
+
+ return currentValue;
+ }
+ }
+
+ void System.Collections.IEnumerator.Reset()
+ {
+ if (version != dictionary.version)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
+ }
+
+ index = 0;
+ currentValue = default(TValue);
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/DictionaryBase.cs b/src/System.Private.Interop/src/Shared/DictionaryBase.cs
new file mode 100644
index 000000000..fa3392c30
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/DictionaryBase.cs
@@ -0,0 +1,234 @@
+// 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.CompilerServices;
+
+namespace System.Collections.Generic.Internal
+{
+ internal class SR
+ {
+ static internal string ArgumentOutOfRange_NeedNonNegNum = "ArgumentOutOfRange_NeedNonNegNum";
+ static internal string Arg_WrongType = "Arg_WrongType";
+ static internal string Arg_ArrayPlusOffTooSmall = "Arg_ArrayPlusOffTooSmall";
+ static internal string Arg_RankMultiDimNotSupported = "Arg_RankMultiDimNotSupported";
+ static internal string Arg_NonZeroLowerBound = "Arg_NonZeroLowerBound";
+ static internal string Argument_InvalidArrayType = "Argument_InvalidArrayType";
+ static internal string Argument_AddingDuplicate = "Argument_AddingDuplicate";
+ static internal string InvalidOperation_EnumFailedVersion = "InvalidOperation_EnumFailedVersion";
+ static internal string InvalidOperation_EnumOpCantHappen = "InvalidOperation_EnumOpCantHappen";
+ static internal string NotSupported_KeyCollectionSet = "NotSupported_KeyCollectionSet";
+ static internal string NotSupported_ValueCollectionSet = "NotSupported_ValueCollectionSet";
+ static internal string ArgumentOutOfRange_SmallCapacity = "ArgumentOutOfRange_SmallCapacity";
+ static internal string Argument_InvalidOffLen = "Argument_InvalidOffLen";
+ }
+
+ internal class HashHelpers
+ {
+ private const Int32 HashPrime = 101;
+
+ public static bool IsPrime(int candidate)
+ {
+ if ((candidate & 1) != 0)
+ {
+ for (int divisor = 3; divisor * divisor < candidate; divisor += 2)
+ {
+ if ((candidate % divisor) == 0)
+ return false;
+ }
+
+ return true;
+ }
+
+ return (candidate == 2);
+ }
+
+ public static int GetPrime(int min)
+ {
+ if (min < 0)
+ {
+ throw new ArgumentException("Arg_HTCapacityOverflow");
+ }
+
+ for (int i = (min | 1); i < Int32.MaxValue; i += 2)
+ {
+ if (((i - 1) % HashPrime != 0) && IsPrime(i))
+ {
+ return i;
+ }
+ }
+
+ return min;
+ }
+
+ // Returns size of hashtable to grow to.
+ public static int ExpandPrime(int oldSize)
+ {
+ int newSize = 2 * oldSize;
+
+ // Allow the hashtables to grow to maximum possible size (~2G elements) before encoutering capacity overflow.
+ // Note that this check works even when _items.Length overflowed thanks to the (uint) cast
+ if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
+ {
+ Contract.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
+
+ return MaxPrimeArrayLength;
+ }
+
+ return GetPrime(newSize);
+ }
+
+ // This is the maximum prime smaller than Array.MaxArrayLength
+ public const int MaxPrimeArrayLength = 0x7FEFFFFD;
+ }
+
+ // Non-generic part of Dictionary, single copy
+ internal class DictionaryBase
+ {
+ protected struct Entry
+ {
+ public int hashCode; // Lower 31 bits of hash code, -1 if unused
+ public int next; // Index of next entry, -1 if last
+ public int bucket;
+ }
+
+ protected int count;
+ protected int version;
+
+ protected int freeList;
+ protected int freeCount;
+
+ protected Entry[] entries;
+
+ public int Count
+ {
+ get
+ {
+ return count - freeCount;
+ }
+ }
+
+ /// <summary>
+ /// Allocate entry array, clear bucket
+ /// </summary>
+ protected int InitializeBase(int capacity)
+ {
+ int size = HashHelpers.GetPrime(capacity);
+
+ entries = new Entry[size];
+
+ for (int i = 0; i < entries.Length; i++)
+ {
+ entries[i].bucket = -1;
+ }
+
+ freeList = -1;
+
+ return size;
+ }
+
+ /// <summary>
+ /// Clear entry array, bucket, counts
+ /// </summary>
+ protected void ClearBase()
+ {
+ Array.Clear(entries, 0, count);
+
+ for (int i = 0; i < entries.Length; i++)
+ {
+ entries[i].bucket = -1;
+ }
+
+ freeList = -1;
+ count = 0;
+ freeCount = 0;
+ version++;
+ }
+
+ /// <summary>
+ /// Resize entry array, clean bucket, but do not set entries yet
+ /// </summary>
+ protected Entry[] ResizeBase1(int newSize)
+ {
+ Entry[] newEntries = new Entry[newSize];
+ Array.Copy(entries, 0, newEntries, 0, count);
+
+ for (int i = 0; i < newEntries.Length; i++)
+ {
+ newEntries[i].bucket = -1;
+ }
+
+ return newEntries;
+ }
+
+ /// <summary>
+ /// Relink buckets, set new entry array
+ /// </summary>
+ protected void ResizeBase2(Entry[] newEntries, int newSize)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ int bucket = newEntries[i].hashCode % newSize;
+ newEntries[i].next = newEntries[bucket].bucket;
+ newEntries[bucket].bucket = i;
+ }
+
+ entries = newEntries;
+ }
+
+#if !RHTESTCL
+ [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
+#endif
+ protected int ModLength(int hashCode)
+ {
+ // uint % operator is faster than int % operator
+ return (int)((uint)hashCode % (uint)entries.Length);
+ }
+
+ /// <summary>
+ /// Find the first entry with hashCode
+ /// </summary>
+ protected int FindFirstEntry(int hashCode)
+ {
+ if (entries != null)
+ {
+ hashCode = hashCode & 0x7FFFFFFF;
+
+ for (int i = entries[ModLength(hashCode)].bucket; i >= 0; i = entries[i].next)
+ {
+ if (entries[i].hashCode == hashCode)
+ {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ /// <summary>
+ /// Find the next entry with the same hashCode as entry
+ /// </summary>
+ protected int FindNextEntry(int entry)
+ {
+ if ((entry >= 0) && entries != null)
+ {
+ int hashCode = entries[entry].hashCode;
+
+ for (int i = entries[entry].next; i >= 0; i = entries[i].next)
+ {
+ if (entries[i].hashCode == hashCode)
+ {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/EventRegistrationToken.cs b/src/System.Private.Interop/src/Shared/EventRegistrationToken.cs
new file mode 100644
index 000000000..f149c006c
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/EventRegistrationToken.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.
+
+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 long m_value;
+
+ public EventRegistrationToken(long value)
+ {
+ m_value = value;
+ }
+
+ internal long 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/System.Private.Interop/src/Shared/FixedHashTable.cs b/src/System.Private.Interop/src/Shared/FixedHashTable.cs
new file mode 100644
index 000000000..d3c8abfda
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/FixedHashTable.cs
@@ -0,0 +1,299 @@
+// 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;
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices
+{
+#if RHTESTCL
+
+ static class InteropExtensions1
+ {
+ public static bool IsNull(this RuntimeTypeHandle handle)
+ {
+ return handle.Equals(default(RuntimeTypeHandle));
+ }
+
+ public static bool IsOfType(this Object obj, RuntimeTypeHandle handle)
+ {
+ return handle.Equals(obj.GetType().TypeHandle);
+ }
+ }
+
+#endif
+
+ /// <summary>
+ /// Simple fixed-size hash table. Create once and use to speed table lookup.
+ /// Good for tool time generated data table lookup. The hash table itself be generated at tool time, but runtime generation will take less disk space
+ ///
+ /// 1. Size is given in construtor and never change afterwards
+ /// 2. Only add is supported, but remove can be added quite easily
+ /// 3. For each entry, an integer index can be stored and received. If index is always the same as inserting order, this can be removed too.
+ /// 4. Value is not stored. It should be managed seperately
+ /// 5. Non-generic, there there is single copy in memory
+ /// 6. Searching is implemented using two methods: GetFirst and GetNext
+ ///
+ /// Check StringMap below for a Dictionary<string, int> like implementation where strings are stored elsewhere, possibly in compressed form
+ /// </summary>
+ internal class FixedHashTable
+ {
+ const int slot_bucket = 0;
+ const int slot_next = 1;
+ const int slot_index = 2;
+
+ int[] m_entries;
+ int m_size;
+ int m_count;
+
+ static internal bool IsPrime(int num)
+ {
+ int t = 3;
+
+ while (t * t < num)
+ {
+ if ((num % t) == 0)
+ {
+ return false;
+ }
+
+ t += 2;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// HashHelpers.GetPrime not accessible here
+ /// </summary>
+ static internal int GetNextPrime(int num)
+ {
+ if ((num & 1) == 0)
+ {
+ num++;
+ }
+
+ while (!IsPrime(num))
+ {
+ num += 2;
+ }
+
+ return num;
+ }
+
+ /// <summary>
+ /// Construct empty hash table
+ /// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ internal FixedHashTable(int size)
+ {
+ // Prime number is essential to reduce hash collision
+ // Add 10%, minimum 11 to make sure hash table has around 10% free entries to reduce collision
+ m_size = GetNextPrime(Math.Max(11, size * 11 / 10));
+
+ // Using int array instead of creating an Entry[] array with three ints to avoid
+ // adding a new array type, which costs around 3kb in binary size
+ m_entries = new int[m_size * 3];
+ }
+
+ /// <summary>
+ /// Add an entry: Dictionay<K,V>.Add(Key(index), index) = > FixedHashTable.Add(Key(index).GetHashCode(), index)
+ /// </summary>
+ /// <param name="hashCode">Hash code for data[slot]</param>
+ /// <param name="index">Normally index to external table</param>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ internal void Add(int hashCode, int index)
+ {
+ int bucket = (hashCode & 0x7FFFFFFF) % m_size;
+
+ m_entries[m_count * 3 + slot_index] = index; // This is not needed if m_count === index
+
+ m_entries[m_count * 3 + slot_next] = m_entries[bucket * 3 + slot_bucket];
+ m_entries[bucket * 3 + slot_bucket] = m_count + 1; // 0 for missing now
+
+ m_count++;
+ }
+
+ /// <summary>
+ /// Get first matching entry based on hash code for enumeration, -1 for missing
+ /// </summary>
+ internal int GetFirst(int hashCode)
+ {
+ int bucket = (hashCode & 0x7FFFFFFF) % m_size;
+
+ return m_entries[bucket * 3 + slot_bucket] - 1;
+ }
+
+ internal int GetIndex(int bucket)
+ {
+ return m_entries[bucket * 3 + slot_index];
+ }
+
+ /// <summary>
+ /// Get next entry for enumeration, -1 for missing
+ /// </summary>
+ internal int GetNext(int bucket)
+ {
+ return m_entries[bucket * 3 + slot_next] - 1;
+ }
+ }
+
+ /// <summary>
+ /// Virtual Dictionary<string, int> where strings are stored elsewhere, possibly in compressed form
+ /// </summary>
+ internal abstract class StringMap
+ {
+ int m_size;
+ FixedHashTable m_map;
+
+ internal StringMap(int size)
+ {
+ m_size = size;
+ }
+
+ internal abstract String GetString(int i);
+
+ /// <summary>
+ /// String(i).GetHashCode
+ /// </summary>
+ internal abstract int GetStringHash(int i);
+
+ /// <summary>
+ /// String(i) == name
+ /// </summary>
+ internal abstract bool IsStringEqual(string name, int i);
+
+ /// <summary>
+ /// Dictionary.TryGetValue(string)
+ /// </summary>
+ internal int FindString(string name)
+ {
+ if (m_map == null)
+ {
+ FixedHashTable map = new FixedHashTable(m_size);
+
+ for (int i = 0; i < m_size; i++)
+ {
+ map.Add(GetStringHash(i), i);
+ }
+
+ m_map = map;
+ }
+
+ int hash = StringPool.StableStringHash(name);
+
+ // Search hash table
+ for (int slot = m_map.GetFirst(hash); slot >= 0; slot = m_map.GetNext(slot))
+ {
+ int index = m_map.GetIndex(slot);
+
+ if (IsStringEqual(name, index))
+ {
+ return index;
+ }
+ }
+
+ return -1;
+ }
+ }
+
+ /// <summary>
+ /// StringMap using 16-bit indices, for normal applications
+ /// </summary>
+ internal class StringMap16 : StringMap
+ {
+ StringPool m_pool;
+ UInt16[] m_indices;
+
+ internal StringMap16(StringPool pool, UInt16[] indices) : base(indices.Length)
+ {
+ m_pool = pool;
+ m_indices = indices;
+ }
+
+ internal override string GetString(int i)
+ {
+ return m_pool.GetString(m_indices[i]);
+ }
+
+ internal override int GetStringHash(int i)
+ {
+ return m_pool.StableStringHash(m_indices[i]);
+ }
+
+ internal override bool IsStringEqual(string name, int i)
+ {
+ return m_pool.IsStringEqual(name, m_indices[i]);
+ }
+ }
+
+ /// <summary>
+ /// StringMap using 32-bit indices, for bigger applications
+ /// </summary>
+ internal class StringMap32 : StringMap
+ {
+ StringPool m_pool;
+ UInt32[] m_indices;
+
+ internal StringMap32(StringPool pool, UInt32[] indices) : base(indices.Length)
+ {
+ m_pool = pool;
+ m_indices = indices;
+ }
+
+ internal override string GetString(int i)
+ {
+ return m_pool.GetString(m_indices[i]);
+ }
+
+ internal override int GetStringHash(int i)
+ {
+ return m_pool.StableStringHash(m_indices[i]);
+ }
+
+ internal override bool IsStringEqual(string name, int i)
+ {
+ return m_pool.IsStringEqual(name, m_indices[i]);
+ }
+ }
+
+
+ /// <summary>
+ /// Fixed Dictionary<RuntimeTypeHandle, int> using delegate Func<int, RuntimeTypeHandle> to provide data
+ /// </summary>
+ internal class RuntimeTypeHandleMap : FixedHashTable
+ {
+ Func<int, RuntimeTypeHandle> m_getHandle;
+
+ internal RuntimeTypeHandleMap(int size, Func<int, RuntimeTypeHandle> getHandle) : base(size)
+ {
+ m_getHandle = getHandle;
+
+ for (int i = 0; i < size; i++)
+ {
+ RuntimeTypeHandle handle = getHandle(i);
+
+ if (!handle.Equals(McgModule.s_DependencyReductionTypeRemovedTypeHandle))
+ {
+ Add(handle.GetHashCode(), i);
+ }
+ }
+ }
+
+ internal int Lookup(RuntimeTypeHandle handle)
+ {
+ for (int slot = GetFirst(handle.GetHashCode()); slot >= 0; slot = GetNext(slot))
+ {
+ int index = GetIndex(slot);
+
+ if (handle.Equals(m_getHandle(index)))
+ {
+ return index;
+ }
+ }
+
+ return -1;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/GCEventProvider.cs b/src/System.Private.Interop/src/Shared/GCEventProvider.cs
new file mode 100644
index 000000000..dcd834f39
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/GCEventProvider.cs
@@ -0,0 +1,110 @@
+// 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;
+
+namespace System.Runtime.InteropServices
+{
+ internal static class GCEventProvider
+ {
+ #region TaskLogLiveCCW
+
+ public static bool IsETWHeapCollectionEnabled()
+ {
+#if !RHTESTCL
+ return InteropExtensions.RhpETWShouldWalkCom();
+#else
+ return false;
+#endif // !RHTESTCL
+ }
+
+ enum EVENT_TYPE
+ {
+ EVENT_LOG_CCW = 1,
+ EVENT_LOG_RCW,
+ EVENT_FLUSH_COM
+ };
+
+ // WARNING: If you want to pass new flags to native runtime
+ // you must make sure you update the ETW manifest to include the new flags.
+ // The description is located at:rh\src\rtetw\ClrEtwAll.man
+ // After adding the flags you need to make sure you update the ETW headers by running:
+ // 'perl EtwImportClrEvents.pl'
+ enum RCW_ETW_FLAGS
+ {
+ Duplicate = 0x1,
+ JupiterObject = 0x2,
+ ExtendsComObject = 0x4
+ };
+
+ enum CCW_ETW_FLAGS
+ {
+ Strong = 0x1,
+ Pegged = 0x2,
+ AggregatesRCW = 0x4
+ };
+
+ /// <summary>
+ /// Fired when a CCW is being found at GC time.
+ /// </summary>
+ /// <param name="CCWGCHandle">GC Root handle that keep this CCW alive.</param>
+ /// <param name="pCCW">CCW managed object base address.</param>
+ /// <param name="typeRawValue">Pointer to the type address.</param>
+ /// <param name="IUnknown">Address of the IUnknown interface.</param>
+ /// <param name="ComRefCount">CCW reference count.</param>
+ /// <param name="JupiterRefCount">CCW Jupiter reference count.</param>
+ /// <param name="flags">CCW's flags.</param>
+ [GCCallback]
+ public static void TaskLogLiveCCW(IntPtr CCWGCHandle, IntPtr pCCW, IntPtr typeRawValue, IntPtr IUnknown, int ComRefCount, int JupiterRefCount, int flags)
+ {
+ long ccwEtwFlags = 0;
+
+ if ((flags & (long)ComCallableObjectFlags.IsPegged) != 0)
+ ccwEtwFlags &= (long)CCW_ETW_FLAGS.Pegged;
+
+ if ((flags & (long)ComCallableObjectFlags.IsAggregatingRCW) != 0)
+ ccwEtwFlags &= (long)CCW_ETW_FLAGS.AggregatesRCW;
+#if !RHTESTCL
+ InteropExtensions.RhpETWLogLiveCom((int)EVENT_TYPE.EVENT_LOG_CCW, CCWGCHandle, pCCW, typeRawValue, IUnknown, (IntPtr)0, ComRefCount, JupiterRefCount, flags);
+#endif // !RHTESTCL
+ }
+
+ /// <summary>
+ /// Fired when a RCW is being found at GC time.
+ /// </summary>
+ /// <param name="pRCW">RCW managed object base address.</param>
+ /// <param name="typeRawValue">Pointer to the type address.</param>
+ /// <param name="IUnknown">Address of the IUnknown interface.</param>
+ /// <param name="VTable">Address of the VTable.</param>
+ /// <param name="refCount">RCW reference count.</param>
+ /// <param name="flags">RCW's flags.</param>
+ [GCCallback]
+ public static void TaskLogLiveRCW(IntPtr pRCW, IntPtr typeRawValue, IntPtr IUnknown, IntPtr VTable, int refCount, ComObjectFlags flags)
+ {
+ int rcwEtwFlags = 0;
+
+ if ((flags & ComObjectFlags.IsDuplicate) != 0)
+ rcwEtwFlags &= (int)RCW_ETW_FLAGS.Duplicate;
+ if ((flags & ComObjectFlags.IsJupiterObject) != 0)
+ rcwEtwFlags &= (int)RCW_ETW_FLAGS.JupiterObject;
+ if ((flags & ComObjectFlags.ExtendsComObject) != 0)
+ rcwEtwFlags &= (int)RCW_ETW_FLAGS.ExtendsComObject;
+#if !RHTESTCL
+ InteropExtensions.RhpETWLogLiveCom((int)EVENT_TYPE.EVENT_LOG_RCW, (IntPtr)0, pRCW, typeRawValue, IUnknown, VTable, refCount, 0, rcwEtwFlags);
+#endif // !RHTESTCL
+ }
+
+ /// <summary>
+ /// Fired when a CCW and RCW logging finished, allowing buffered events to be flushed out.
+ /// </summary>
+ [GCCallback]
+ public static void FlushComETW()
+ {
+#if !RHTESTCL
+ InteropExtensions.RhpETWLogLiveCom((int)EVENT_TYPE.EVENT_FLUSH_COM, (IntPtr)0, (IntPtr)0, (IntPtr)0, (IntPtr)0, (IntPtr)0, 0, 0, 0);
+#endif // !RHTESTCL
+ }
+ }
+ #endregion // TaskLogLiveCCW
+}
diff --git a/src/System.Private.Interop/src/Shared/HashSet.cs b/src/System.Private.Interop/src/Shared/HashSet.cs
new file mode 100644
index 000000000..059240208
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/HashSet.cs
@@ -0,0 +1,226 @@
+// 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.CompilerServices;
+
+namespace System.Collections.Generic.Internal
+{
+ /// <summary>
+ /// HashSet; Dictionary without Value
+ /// 1. Deriving from DictionaryBase to share common code
+ /// 2. Hashing/bucket moved to DictionaryBase
+ /// 3. No interface implementation. You pay for the methods called
+ /// 4. Support FindFirstKey/FindNextKey, hash code based search (returning key to caller for key comparison)
+ /// 5. Support GetNext for simple enumeration of items
+ /// 6. No comparer, no interface dispatching calls
+ /// </summary>
+ /// <typeparam name="TKey"></typeparam>
+ internal class HashSet<TKey> : DictionaryBase where TKey : IEquatable<TKey>
+ {
+ const int MinimalSize = 11; // Have non-zero minimal size so that we do not need to check for null entries
+
+ private TKey[] keyArray;
+
+ public HashSet(int capacity)
+ {
+ if (capacity < MinimalSize)
+ {
+ capacity = MinimalSize;
+ }
+
+ Initialize(capacity);
+ }
+
+ public void Clear()
+ {
+ if (count > 0)
+ {
+ ClearBase();
+ Array.Clear(keyArray, 0, count);
+ }
+ }
+
+ public bool ContainsKey(TKey key, int hashCode)
+ {
+ return FindEntry(key, hashCode) >= 0;
+ }
+
+ private int FindEntry(TKey key, int hashCode)
+ {
+ hashCode = hashCode & 0x7FFFFFFF;
+
+ for (int i = entries[ModLength(hashCode)].bucket; i >= 0; i = entries[i].next)
+ {
+ if (entries[i].hashCode == hashCode && key.Equals(keyArray[i]))
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /// <summary>
+ /// First first matching entry, returning index, update key
+ /// </summary>
+ /// <param name="key"></param>
+ /// <returns></returns>
+ public int FindFirstKey(ref TKey key, int hashCode)
+ {
+ int entry = FindFirstEntry(hashCode & 0x7FFFFFFF);
+
+ if (entry >= 0)
+ {
+ key = keyArray[entry];
+ }
+
+ return entry;
+ }
+
+ /// <summary>
+ /// Find next matching entry, returning index, update key
+ /// </summary>
+ /// <param name="key"></param>
+ /// <param name="entry"></param>
+ /// <returns></returns>
+ public int FindNextKey(ref TKey key, int entry)
+ {
+ entry = FindNextEntry(entry);
+
+ if (entry >= 0)
+ {
+ key = keyArray[entry];
+ }
+
+ return entry;
+ }
+
+ /// <summary>
+ /// Enumeration of items
+ /// </summary>
+ [System.Runtime.InteropServices.GCCallback]
+ internal bool GetNext(ref TKey key, ref int index)
+ {
+ for (int i = index + 1; i < this.count; i++)
+ {
+ if (entries[i].hashCode >= 0)
+ {
+ key = keyArray[i];
+
+ index = i;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void Initialize(int capacity)
+ {
+ int size = InitializeBase(capacity);
+
+ keyArray = new TKey[size];
+ }
+
+ public bool Add(TKey key, int hashCode)
+ {
+ hashCode = hashCode & 0x7FFFFFFF;
+ int targetBucket = ModLength(hashCode);
+
+ for (int i = entries[targetBucket].bucket; i >= 0; i = entries[i].next)
+ {
+ if (entries[i].hashCode == hashCode && key.Equals(keyArray[i]))
+ {
+ return true;
+ }
+ }
+
+ int index;
+
+ if (freeCount > 0)
+ {
+ index = freeList;
+ freeList = entries[index].next;
+ freeCount--;
+ }
+ else
+ {
+ if (count == entries.Length)
+ {
+ Resize();
+ targetBucket = ModLength(hashCode);
+ }
+
+ index = count;
+ count++;
+ }
+
+ entries[index].hashCode = hashCode;
+ entries[index].next = entries[targetBucket].bucket;
+ keyArray[index] = key;
+ entries[targetBucket].bucket = index;
+
+ return false;
+ }
+
+ private void Resize()
+ {
+ Resize(HashHelpers.ExpandPrime(count));
+ }
+
+ private void Resize(int newSize)
+ {
+#if !RHTESTCL
+ Contract.Assert(newSize >= entries.Length);
+#endif
+
+ Entry[] newEntries = ResizeBase1(newSize);
+
+ TKey[] newKeys = new TKey[newSize];
+ Array.Copy(keyArray, 0, newKeys, 0, count);
+
+ ResizeBase2(newEntries, newSize);
+
+ keyArray = newKeys;
+ }
+
+ public bool Remove(TKey key, int hashCode)
+ {
+ hashCode = hashCode & 0x7FFFFFFF;
+ int bucket = ModLength(hashCode);
+ int last = -1;
+
+ for (int i = entries[bucket].bucket; i >= 0; last = i, i = entries[i].next)
+ {
+ if (entries[i].hashCode == hashCode && key.Equals(keyArray[i]))
+ {
+ if (last < 0)
+ {
+ entries[bucket].bucket = entries[i].next;
+ }
+ else
+ {
+ entries[last].next = entries[i].next;
+ }
+
+ entries[i].hashCode = -1;
+ entries[i].next = freeList;
+ keyArray[i] = default(TKey);
+ freeList = i;
+ freeCount++;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/InternalModule.cs b/src/System.Private.Interop/src/Shared/InternalModule.cs
new file mode 100644
index 000000000..b9184dfff
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/InternalModule.cs
@@ -0,0 +1,223 @@
+// 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.Runtime.CompilerServices;
+using System.Text;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Singleton module that managed types implemented internally, rather than in MCG-generated code.
+ /// This works together with interface implementations in StandardInterfaces.cs
+ /// NOTE: Interfaces defined here are implemented by CCWs, but user might be able to override them
+ /// depending on the interface
+ /// </summary>
+
+ [EagerStaticClassConstruction]
+ internal class InternalModule : McgModule
+ {
+ /// <summary>
+ /// Index of each internal interface
+ /// Each internal McgInterfaceData should have MarshalIndex field with one of the enum values
+ /// </summary>
+ internal enum Indexes : short
+ {
+ IUnknown = 0,
+#if ENABLE_WINRT
+ IInspectable,
+ ICustomPropertyProvider,
+#endif
+ IWeakReferenceSource,
+ IWeakReference,
+#if ENABLE_WINRT
+ ICCW,
+ IJupiterObject,
+ IStringable,
+ IActivationFactoryInternal,
+ IManagedActivationFactory,
+ IRestrictedErrorInfo,
+#endif
+ IMarshal,
+#if ENABLE_WINRT
+ HSTRING
+#endif
+ }
+
+ // The internal module is always lower priority than all other modules.
+ private const int PriorityForInternalModule = -1;
+
+ unsafe internal InternalModule()
+ : base(
+ PriorityForInternalModule,
+ s_interfaceData,
+ null, // CCWTemplateData
+ null, // CCWTemplateInterfaceList
+ null, // classData,
+ null, // boxingData,
+ null, // additionalClassData,
+ null, // collectionData,
+ null, // DelegateData
+ null, // CCWFactories
+ null, // structMarshalData
+ null, // unsafeStructFieldOffsetData
+ null, // interfaceMarshalData
+ null, // hashcodeVerify
+ null, // interfaceTypeInfo_Hashtable
+ null, // ccwTemplateData_Hashtable
+ null, // classData_Hashtable
+ null, // collectionData_Hashtable
+ null // boxingData_Hashtable
+ )
+ {
+ // Following code is disabled due to lazy static constructor dependency from McgModule which is
+ // static eager constructor. Undo this when McgCurrentModule is using ModuleConstructorAttribute
+#if EAGER_CTOR_WORKAROUND
+ for (int i = 0; i < s_interfaceTypeInfo.Length; i++)
+ {
+ Debug.Assert((s_interfaceTypeInfo[i].InterfaceData->Flags & McgInterfaceFlags.useSharedCCW) == 0);
+ }
+#endif
+ }
+
+ // IUnknown
+ static internal McgInterfaceData s_IUnknown = new McgInterfaceData
+ {
+ ItfGuid = new Guid(0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46),
+ CcwVtable = __vtable_IUnknown.GetVtableFuncPtr(),
+ Flags = McgInterfaceFlags.isInternal,
+ MarshalIndex = (short)Indexes.IUnknown
+ };
+
+#if ENABLE_WINRT
+ // IInspectable
+ static internal McgInterfaceData s_IInspectable = new McgInterfaceData
+ {
+ ItfGuid = new Guid(unchecked((int)0xAF86E2E0u), unchecked((short)0xB12D), 0x4C6A, 0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90),
+ CcwVtable = __vtable_IInspectable.GetVtableFuncPtr(),
+ Flags = McgInterfaceFlags.isInternal | McgInterfaceFlags.isIInspectable,
+ MarshalIndex = (short)Indexes.IInspectable
+ };
+
+ // ICustomPropertyProvider
+ static internal McgInterfaceData s_ICustomPropertyProvider = new McgInterfaceData
+ {
+ ItfGuid = new Guid(0x7C925755, 0x3E48, 0x42B4, 0x86, 0x77, 0x76, 0x37, 0x22, 0x67, 0x3, 0x3F),
+ CcwVtable = __vtable_ICustomPropertyProvider.GetVtableFuncPtr(),
+ Flags = McgInterfaceFlags.isInternal | McgInterfaceFlags.isIInspectable,
+ MarshalIndex = (short)Indexes.ICustomPropertyProvider
+ };
+
+
+
+ // IWeakReferenceSource
+ static internal McgInterfaceData s_IWeakReferenceSource = new McgInterfaceData
+ {
+ ItfGuid = new Guid(0x00000038, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46),
+ CcwVtable = __vtable_IWeakReferenceSource.GetVtableFuncPtr(),
+ Flags = McgInterfaceFlags.isInternal,
+ MarshalIndex = (short)Indexes.IWeakReferenceSource
+ };
+
+ // IWeakReference
+ static internal McgInterfaceData s_IWeakReference = new McgInterfaceData
+ {
+ ItfGuid = new Guid(0x00000037, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46),
+ CcwVtable = __vtable_IWeakReference.GetVtableFuncPtr(),
+ Flags = McgInterfaceFlags.isInternal,
+ MarshalIndex = (short)Indexes.IWeakReference
+ };
+
+ // ICCW
+ static internal McgInterfaceData s_ICCW = new McgInterfaceData
+ {
+ ItfGuid = new Guid(0x64bd43f8, unchecked((short)0xBFEE), 0x4ec4, 0xb7, 0xeb, 0x29, 0x35, 0x15, 0x8d, 0xae, 0x21),
+ CcwVtable = __vtable_ICCW.GetVtableFuncPtr(),
+ Flags = McgInterfaceFlags.isInternal,
+ MarshalIndex = (short)Indexes.ICCW
+ };
+
+ // IJupiterObject
+ static internal McgInterfaceData s_IJupiterObject = new McgInterfaceData
+ {
+ ItfGuid = new Guid(0x11d3b13a, 0x180e, 0x4789, 0xa8, 0xbe, 0x77, 0x12, 0x88, 0x28, 0x93, 0xe6),
+ Flags = McgInterfaceFlags.isInternal,
+ MarshalIndex = (short)Indexes.IJupiterObject
+ };
+
+ // IStringable
+ static internal McgInterfaceData s_IStringable = new McgInterfaceData
+ {
+ ItfGuid = new Guid(unchecked((int)0x96369f54), unchecked((short)0x8eb6), 0x48f0, 0xab, 0xce, 0xc1, 0xb2, 0x11, 0xe6, 0x27, 0xc3),
+ CcwVtable = __vtable_IStringable.GetVtableFuncPtr(),
+ Flags = McgInterfaceFlags.isInternal,
+ MarshalIndex = (short)Indexes.IStringable
+ };
+
+ // IActivationFactoryInternal
+ static internal McgInterfaceData s_IActivationFactoryInternal = new McgInterfaceData
+ {
+ ItfGuid = new Guid(0x00000035, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46),
+ CcwVtable = __vtable_IActivationFactoryInternal.GetVtableFuncPtr(),
+ Flags = McgInterfaceFlags.isInternal,
+ MarshalIndex = (short)Indexes.IActivationFactoryInternal
+ };
+
+
+ // IManagedActivationFactory
+ static internal McgInterfaceData s_IManagedActivationFactory = new McgInterfaceData
+ {
+ ItfGuid = new Guid(0x60D27C8D, 0x5F61, 0x4CCE, 0xB7, 0x51, 0x69, 0x0F, 0xAE, 0x66, 0xAA, 0x53),
+ CcwVtable = __vtable_IManagedActivationFactory.GetVtableFuncPtr(),
+ Flags = McgInterfaceFlags.isInternal,
+ MarshalIndex = (short)Indexes.IManagedActivationFactory
+ };
+
+ // IRestrictedErrorInfo
+ static internal McgInterfaceData s_IRestrictedErrorInfo = new McgInterfaceData
+ {
+ ItfGuid = new Guid(unchecked((int)0x82BA7092), 0x4C88, 0x427D, 0xA7, 0xBC, 0x16, 0xDD, 0x93, 0xFE, 0xB6, 0x7E),
+ Flags = McgInterfaceFlags.isInternal,
+ MarshalIndex = (short)Indexes.IRestrictedErrorInfo
+ };
+#endif
+
+ // IMarshal
+ static internal McgInterfaceData s_IMarshal = new McgInterfaceData
+ {
+ ItfGuid = Interop.COM.IID_IMarshal,
+ CcwVtable = __vtable_IMarshal.GetVtableFuncPtr(),
+ Flags = McgInterfaceFlags.isInternal,
+ MarshalIndex = (short)Indexes.IMarshal
+ };
+
+ // HSTRING, just needed for McgTypeInfo comparison
+ static internal McgInterfaceData s_HSTRING = new McgInterfaceData
+ {
+
+ };
+
+ static readonly McgInterfaceData[] s_interfaceData = new McgInterfaceData[] {
+ s_IUnknown,
+#if ENABLE_WINRT
+ s_IInspectable,
+ s_ICustomPropertyProvider,
+ s_IWeakReferenceSource,
+ s_IWeakReference,
+ s_ICCW,
+ s_IJupiterObject,
+ s_IStringable,
+ s_IActivationFactoryInternal,
+
+ s_IManagedActivationFactory,
+ s_IRestrictedErrorInfo,
+#endif
+ s_IMarshal,
+
+#if ENABLE_WINRT
+ s_HSTRING
+#endif
+ };
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/Interop.Manual.cs b/src/System.Private.Interop/src/Shared/Interop.Manual.cs
new file mode 100644
index 000000000..3c9c5996e
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/Interop.Manual.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.
+
+//
+
+//
+// All P/invokes used by internal Interop code goes here
+//
+// !!IMPORTANT!!
+//
+// Do not rely on MCG to generate marshalling code for these p/invokes as MCG might not see them at all
+// due to not seeing dependency to those calls (before the MCG generated code is generated). Instead,
+// always manually marshal the arguments
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+
+
+// TODO : Remove the remaning methods in this file to correct interop*.cs files under Interop folder
+partial class Interop
+{
+#if TARGET_CORE_API_SET
+ internal const string CORE_SYNCH_L2 = "api-ms-win-core-synch-l1-2-0.dll";
+#else
+ //
+ // Define dll names for previous version of Windows earlier than Windows 8
+ //
+ internal const string CORE_SYNCH_L2 = "kernel32.dll";
+ internal const string CORE_COM = "ole32.dll";
+ internal const string CORE_COM_AUT = "OleAut32.dll";
+
+#endif
+
+ internal unsafe partial class MinCore
+ {
+
+#if RHTESTCL
+ [DllImport(CORE_SYNCH_L2)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal extern void Sleep(int milliseconds);
+#else
+ private static readonly System.Threading.WaitHandle s_sleepHandle = new System.Threading.ManualResetEvent(false);
+ static internal void Sleep(uint milliseconds)
+ {
+#if CORECLR
+ System.Threading.Thread.Sleep(0);
+#else
+ if (milliseconds == 0)
+ System.Threading.SpinWait.Yield();
+ else
+ s_sleepHandle.WaitOne((int)milliseconds);
+#endif
+ }
+#endif
+ }
+ internal unsafe partial class COM
+ {
+ //
+ // IIDs
+ //
+ internal static Guid IID_IUnknown = new Guid(0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+ internal static Guid IID_IMarshal = new Guid(0x00000003, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+ internal static Guid IID_IAgileObject = new Guid(unchecked((int)0x94ea2b94), unchecked((short)0xe9cc), 0x49e0, 0xc0, 0xff, 0xee, 0x64, 0xca, 0x8f, 0x5b, 0x90);
+ internal static Guid IID_IContextCallback = new Guid(0x000001da, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+ internal static Guid IID_IEnterActivityWithNoLock = new Guid(unchecked((int)0xd7174f82), 0x36b8, 0x4aa8, 0x80, 0x0a, 0xe9, 0x63, 0xab, 0x2d, 0xfa, 0xb9);
+ internal static Guid IID_ICustomPropertyProvider = new Guid(unchecked(((int)(0x7C925755u))), unchecked(((short)(0x3E48))), unchecked(((short)(0x42B4))), 0x86, 0x77, 0x76, 0x37, 0x22, 0x67, 0x3, 0x3F);
+ internal static Guid IID_IInspectable = new Guid(unchecked((int)0xAF86E2E0), unchecked((short)0xB12D), 0x4c6a, 0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90);
+ internal static Guid IID_IWeakReferenceSource = new Guid(0x00000038, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+ internal static Guid IID_IWeakReference = new Guid(0x00000037, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+ internal static Guid IID_IFindDependentWrappers = new Guid(0x04b3486c, 0x4687, 0x4229, 0x8d, 0x14, 0x50, 0x5a, 0xb5, 0x84, 0xdd, 0x88);
+ internal static Guid IID_IStringable = new Guid(unchecked((int)0x96369f54), unchecked((short)0x8eb6), 0x48f0, 0xab, 0xce, 0xc1, 0xb2, 0x11, 0xe6, 0x27, 0xc3);
+ internal static Guid IID_IRestrictedErrorInfo = new Guid(unchecked((int)0x82ba7092), unchecked((short)0x4c88), unchecked((short)0x427d), 0xa7, 0xbc, 0x16, 0xdd, 0x93, 0xfe, 0xb6, 0x7e);
+ internal static Guid IID_ILanguageExceptionErrorInfo = new Guid(unchecked((int)0x04a2dbf3), unchecked((short)0xdf83), unchecked((short)0x116c), 0x09, 0x46, 0x08, 0x12, 0xab, 0xf6, 0xe0, 0x7d);
+ internal static Guid IID_INoMarshal = new Guid(unchecked((int)0xECC8691B), unchecked((short)0xC1DB), 0x4DC0, 0x85, 0x5E, 0x65, 0xF6, 0xC5, 0x51, 0xAF, 0x49);
+ internal static Guid IID_IStream = new Guid(0x0000000C, 0x0000, 0x0000, 0xC0, 0x00, 0x00,0x00,0x00, 0x00,0x00, 0x46);
+ internal static Guid IID_ISequentialStream = new Guid(unchecked((int)0x0C733A30), 0x2A1C, 0x11CE, 0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D);
+
+ //
+ // Jupiter IIDs.
+ //
+ // Note that the Windows sources refer to these IIDs via different names:
+ //
+ // IClrServices = Windows.UI.Xaml.Hosting.IReferenceTrackerHost
+ // IJupiterObject = Windows.UI.Xaml.Hosting.IReferenceTracker
+ // ICCW = Windows.UI.Xaml.Hosting.IReferenceTrackerTarget
+ //
+ internal static Guid IID_ICLRServices = new Guid(0x29a71c6a, 0x3c42, 0x4416, 0xa3, 0x9d, 0xe2, 0x82, 0x5a, 0x07, 0xa7, 0x73);
+ internal static Guid IID_IJupiterObject = new Guid(0x11d3b13a, 0x180e, 0x4789, 0xa8, 0xbe, 0x77, 0x12, 0x88, 0x28, 0x93, 0xe6);
+ internal static Guid IID_ICCW = new Guid(0x64bd43f8, unchecked((short)0xbfee), 0x4ec4, 0xb7, 0xeb, 0x29, 0x35, 0x15, 0x8d, 0xae, 0x21);
+
+ //
+ // CLSIDs
+ //
+ internal static Guid CLSID_InProcFreeMarshaler = new Guid(0x0000033A, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MULTI_QI
+ {
+ internal IntPtr pIID;
+ internal IntPtr pItf;
+ internal int hr;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ static unsafe internal string ConvertBSTRToString(IntPtr pBSTR)
+ {
+ String myString = null;
+
+ if (pBSTR != default(IntPtr))
+ {
+ myString = new String((char*)pBSTR, 0, (int)ExternalInterop.SysStringLen(pBSTR));
+ }
+
+ return myString;
+ }
+
+ //
+ // Constants and enums
+ //
+ internal enum MSHCTX : uint
+ {
+ MSHCTX_LOCAL = 0, // unmarshal context is local (eg.shared memory)
+ MSHCTX_NOSHAREDMEM = 1, // unmarshal context has no shared memory access
+ MSHCTX_DIFFERENTMACHINE = 2,// unmarshal context is on a different machine
+ MSHCTX_INPROC = 3, // unmarshal context is on different thread
+ }
+
+ [Flags]
+ internal enum MSHLFLAGS : uint
+ {
+ MSHLFLAGS_NORMAL = 0, // normal marshaling via proxy/stub
+ MSHLFLAGS_TABLESTRONG = 1, // keep object alive; must explicitly release
+ MSHLFLAGS_TABLEWEAK = 2, // doesn't hold object alive; still must release
+ MSHLFLAGS_NOPING = 4 // remote clients dont 'ping' to keep objects alive
+ }
+
+ internal enum STREAM_SEEK : uint
+ {
+ STREAM_SEEK_SET = 0,
+ STREAM_SEEK_CUR = 1,
+ STREAM_SEEK_END = 2
+ }
+
+ //
+ // HRESULTs
+ //
+ internal const int S_OK = 0;
+ internal const int S_FALSE = 0x00000001;
+ internal const int E_FAIL = unchecked((int)0x80004005);
+ internal const int E_OUTOFMEMORY = unchecked((int)0x8007000E);
+ internal const int E_NOTIMPL = unchecked((int)0x80004001);
+ internal const int E_NOINTERFACE = unchecked((int)0x80004002);
+ internal const int E_INVALIDARG = unchecked((int)0x80070057);
+ internal const int E_BOUNDS = unchecked((int)0x8000000B);
+ internal const int E_POINTER = unchecked((int)0x80004003);
+ internal const int E_CHANGED_STATE = unchecked((int)0x8000000C);
+ internal const int COR_E_OBJECTDISPOSED = unchecked((int)0x80131622);
+ internal const int RO_E_CLOSED = unchecked((int)0x80000013);
+
+ /// <summary>
+ /// Error indicates that you are accessing a CCW whose target object has already been garbage
+ /// collected while the CCW still has non-0 jupiter ref counts
+ /// </summary>
+ internal const int COR_E_ACCESSING_CCW = unchecked((int)0x80131544);
+
+#pragma warning disable 649, 169 // Field 'blah' is never assigned to/Field 'blah' is never used
+
+ // I use __vtbl to distingush from MCG vtables that are used for CCWs
+ internal struct __vtbl_IUnknown
+ {
+ // IUnknown methods
+ internal IntPtr pfnQueryInterface;
+ internal IntPtr pfnAddRef;
+ internal IntPtr pfnRelease;
+ }
+
+ internal struct __vtbl_ISequentialStream
+ {
+ __vtbl_IUnknown parent;
+
+ internal IntPtr pfnRead;
+ internal IntPtr pfnWrite;
+ }
+
+ internal unsafe struct __IStream
+ {
+ internal __vtbl_IStream* vtbl;
+ }
+
+ internal struct __vtbl_IStream
+ {
+ __vtbl_ISequentialStream parent;
+
+ internal IntPtr pfnSeek;
+ internal IntPtr pfnSetSize;
+ internal IntPtr pfnCopyTo;
+ internal IntPtr pfnCommit;
+ internal IntPtr pfnRevert;
+ internal IntPtr pfnLockRegion;
+ internal IntPtr pfnUnlockRegion;
+ internal IntPtr pfnStat;
+ internal IntPtr pfnClone;
+ }
+
+ internal unsafe struct __IMarshal
+ {
+ internal __vtbl_IMarshal* vtbl;
+ }
+
+ internal struct __vtbl_IMarshal
+ {
+ __vtbl_IUnknown parent;
+
+ internal IntPtr pfnGetUnmarshalClass;
+ internal IntPtr pfnGetMarshalSizeMax;
+ internal IntPtr pfnMarshalInterface;
+ internal IntPtr pfnUnmarshalInterface;
+ internal IntPtr pfnReleaseMarshalData;
+ internal IntPtr pfnDisconnectObject;
+ }
+
+ internal unsafe struct __IContextCallback
+ {
+ internal __vtbl_IContextCallback* vtbl;
+ }
+
+ internal struct __vtbl_IContextCallback
+ {
+ __vtbl_IUnknown parent;
+
+ internal IntPtr pfnContextCallback;
+ }
+
+ internal struct ComCallData
+ {
+ internal uint dwDispid;
+ internal uint dwReserved;
+ internal IntPtr pUserDefined;
+ }
+#pragma warning restore 649, 169
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/List.cs b/src/System.Private.Interop/src/Shared/List.cs
new file mode 100644
index 000000000..68beb4223
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/List.cs
@@ -0,0 +1,406 @@
+// 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.CompilerServices;
+
+namespace System.Collections.Generic.Internal
+{
+ public class List<T>
+ {
+ private T[] _items;
+ private int _size;
+ private int _version;
+
+ public List()
+ {
+ _items = new T[0];
+ }
+
+ // Constructs a List with a given initial capacity. The list is
+ // initially empty, but will have room for the given number of elements
+ // before any reallocations are required.
+ //
+ public List(int capacity)
+ {
+ if (capacity < 0) throw new ArgumentOutOfRangeException("capacity", SR.ArgumentOutOfRange_NeedNonNegNum);
+ Contract.EndContractBlock();
+
+ _items = new T[capacity];
+ }
+
+ // Constructs a List, copying the contents of the given collection. The
+ // size and capacity of the new list will both be equal to the size of the
+ // given collection.
+ //
+ public List(IEnumerable<T> collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+ Contract.EndContractBlock();
+
+ ICollection<T> c = collection as ICollection<T>;
+
+ if (c != null)
+ {
+ int count = c.Count;
+
+ if (count == 0)
+ {
+ _items = new T[0];
+ }
+ else
+ {
+ _items = new T[count];
+ c.CopyTo(_items, 0);
+ _size = count;
+ }
+ }
+ else
+ {
+ _size = 0;
+ _items = new T[0];
+ // This enumerable could be empty. Let Add allocate a new array, if needed.
+ // Note it will also go to _defaultCapacity first, not 1, then 2, etc.
+
+ using (IEnumerator<T> en = collection.GetEnumerator())
+ {
+ while (en.MoveNext())
+ {
+ Add(en.Current);
+ }
+ }
+ }
+ }
+
+ // Gets and sets the capacity of this list. The capacity is the size of
+ // the internal array used to hold items. When set, the internal
+ // array of the list is reallocated to the given capacity.
+ //
+ public int Capacity
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<int>() >= 0);
+ return _items.Length;
+ }
+ set
+ {
+ if (value < _size)
+ {
+ throw new ArgumentOutOfRangeException("value", SR.ArgumentOutOfRange_SmallCapacity);
+ }
+
+ Contract.EndContractBlock();
+
+ if (value != _items.Length)
+ {
+ if (value > 0)
+ {
+ var newArray = new T[value];
+ Array.Copy(_items, 0, newArray, 0, _size);
+ _items = newArray;
+ }
+ else
+ {
+ _items = new T[0];
+ }
+ }
+ }
+ }
+
+ // Read-only property describing how many elements are in the List.
+ public int Count
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<int>() >= 0);
+ return _size;
+ }
+ }
+
+ // Sets or Gets the element at the given index.
+ //
+ public T this[int index]
+ {
+ get
+ {
+ // Following trick can reduce the range check by one
+ if ((uint)index >= (uint)_size)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+
+ Contract.EndContractBlock();
+
+ return _items[index];
+ }
+
+ set
+ {
+ if ((uint)index >= (uint)_size)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+
+ Contract.EndContractBlock();
+
+ _items[index] = value;
+ _version++;
+ }
+ }
+
+ // Adds the given object to the end of this list. The size of the list is
+ // increased by one. If required, the capacity of the list is doubled
+ // before adding the new element.
+ //
+ public void Add(T item)
+ {
+ if (_size == _items.Length)
+ {
+ EnsureCapacity(_size + 1);
+ }
+
+ _items[_size++] = item;
+ _version++;
+ }
+
+ // Clears the contents of List.
+ public void Clear()
+ {
+ if (_size > 0)
+ {
+ Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
+ _size = 0;
+ }
+
+ _version++;
+ }
+
+ // Contains returns true if the specified element is in the List.
+ // It does a linear, O(n) search. Equality is determined by calling
+ // item.Equals().
+ //
+ public bool Contains(T item)
+ {
+ if ((Object)item == null)
+ {
+ for (int i = 0; i < _size; i++)
+ if ((Object)_items[i] == null)
+ return true;
+
+ return false;
+ }
+ else
+ {
+ EqualityComparer<T> c = EqualityComparer<T>.Default;
+
+ for (int i = 0; i < _size; i++)
+ {
+ if (c.Equals(_items[i], item)) return true;
+ }
+
+ return false;
+ }
+ }
+
+ public void CopyTo(T[] array)
+ {
+ CopyTo(array, 0);
+ }
+
+ // Copies a section of this list to the given array at the given index.
+ //
+ // The method uses the Array.Copy method to copy the elements.
+ //
+ public void CopyTo(int index, T[] array, int arrayIndex, int count)
+ {
+ if (_size - index < count)
+ {
+ throw new ArgumentException(SR.Argument_InvalidOffLen);
+ }
+ Contract.EndContractBlock();
+
+ // Delegate rest of error checking to Array.Copy.
+ Array.Copy(_items, index, array, arrayIndex, count);
+ }
+
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ // Delegate rest of error checking to Array.Copy.
+ Array.Copy(_items, 0, array, arrayIndex, _size);
+ }
+
+ // Ensures that the capacity of this list is at least the given minimum
+ // value. If the currect capacity of the list is less than min, the
+ // capacity is increased to twice the current capacity or to min,
+ // whichever is larger.
+ private void EnsureCapacity(int min)
+ {
+ if (_items.Length < min)
+ {
+ int newCapacity = _items.Length == 0 ? 4 : _items.Length * 2;
+
+ // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
+ // Note that this check works even when _items.Length overflowed thanks to the (uint) cast
+ //if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;
+ if (newCapacity < min)
+ {
+ newCapacity = min;
+ }
+
+ Capacity = newCapacity;
+ }
+ }
+
+ // Returns the index of the first occurrence of a given value in a range of
+ // this list. The list is searched forwards from beginning to end.
+ // The elements of the list are compared to the given value using the
+ // Object.Equals method.
+ //
+ // This method uses the Array.IndexOf method to perform the
+ // search.
+ //
+ public int IndexOf(T item)
+ {
+ Contract.Ensures(Contract.Result<int>() >= -1);
+ Contract.Ensures(Contract.Result<int>() < Count);
+
+ return Array.IndexOf(_items, item, 0, _size);
+ }
+
+ // Returns the index of the first occurrence of a given value in a range of
+ // this list. The list is searched forwards, starting at index
+ // index and ending at count number of elements. The
+ // elements of the list are compared to the given value using the
+ // Object.Equals method.
+ //
+ // This method uses the Array.IndexOf method to perform the
+ // search.
+ //
+ public int IndexOf(T item, int index)
+ {
+ if (index > _size)
+ throw new ArgumentOutOfRangeException("index");
+
+ Contract.Ensures(Contract.Result<int>() >= -1);
+ Contract.Ensures(Contract.Result<int>() < Count);
+ Contract.EndContractBlock();
+
+ return Array.IndexOf(_items, item, index, _size - index);
+ }
+
+ // Returns the index of the first occurrence of a given value in a range of
+ // this list. The list is searched forwards, starting at index
+ // index and upto count number of elements. The
+ // elements of the list are compared to the given value using the
+ // Object.Equals method.
+ //
+ // This method uses the Array.IndexOf method to perform the
+ // search.
+ //
+ public int IndexOf(T item, int index, int count)
+ {
+ if (index > _size)
+ throw new ArgumentOutOfRangeException("index");
+
+ if (count < 0 || index > _size - count)
+ throw new ArgumentOutOfRangeException("count");
+
+ Contract.Ensures(Contract.Result<int>() >= -1);
+ Contract.Ensures(Contract.Result<int>() < Count);
+ Contract.EndContractBlock();
+
+ return Array.IndexOf(_items, item, index, count);
+ }
+
+ // Inserts an element into this list at a given index. The size of the list
+ // is increased by one. If required, the capacity of the list is doubled
+ // before inserting the new element.
+ //
+ public void Insert(int index, T item)
+ {
+ // Note that insertions at the end are legal.
+ if ((uint)index > (uint)_size)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ Contract.EndContractBlock();
+
+ if (_size == _items.Length) EnsureCapacity(_size + 1);
+
+ if (index < _size)
+ {
+ Array.Copy(_items, index, _items, index + 1, _size - index);
+ }
+
+ _items[index] = item;
+ _size++;
+ _version++;
+ }
+
+ // Removes the element at the given index. The size of the list is
+ // decreased by one.
+ //
+ public bool Remove(T item)
+ {
+ int index = IndexOf(item);
+
+ if (index >= 0)
+ {
+ RemoveAt(index);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Removes the element at the given index. The size of the list is
+ // decreased by one.
+ //
+ public void RemoveAt(int index)
+ {
+ if ((uint)index >= (uint)_size)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ Contract.EndContractBlock();
+
+ _size--;
+
+ if (index < _size)
+ {
+ Array.Copy(_items, index + 1, _items, index, _size - index);
+ }
+
+ _items[_size] = default(T);
+ _version++;
+ }
+
+ public T[] ToArray()
+ {
+ Contract.Ensures(Contract.Result<T[]>() != null);
+ Contract.Ensures(Contract.Result<T[]>().Length == Count);
+
+ T[] array = new T[_size];
+
+ Array.Copy(_items, 0, array, 0, _size);
+
+ return array;
+ }
+
+ public void TrimExcess()
+ {
+ int threshold = _items.Length * 9 / 10;
+
+ if (_size < threshold)
+ {
+ Capacity = _size;
+ }
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/Marshal.cs b/src/System.Private.Interop/src/Shared/Marshal.cs
new file mode 100644
index 000000000..2cf998d9f
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/Marshal.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.
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices
+{
+ public static partial class Marshal
+ {
+ public static int GetLastWin32Error()
+ {
+ return McgMarshal.s_lastWin32Error;
+ }
+
+ internal static void SetLastWin32Error(int errorCode)
+ {
+ McgMarshal.s_lastWin32Error = errorCode;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static int GetHRForException(Exception e)
+ {
+ if (e == null)
+ {
+ return Interop.COM.S_OK;
+ }
+
+ // @TODO: Setup IErrorInfo
+ return e.HResult;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static Exception GetExceptionForHR(int errorCode)
+ {
+#if ENABLE_WINRT
+ // In the default case, return a COM exception (same behavior in desktop CLR)
+ return ExceptionHelpers.GetMappingExceptionForHR(
+ errorCode,
+ message: null,
+ createCOMException : true,
+ hasErrorInfo: false);
+#else
+ return new Exception(errorCode.ToString());
+#endif
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgAccessorAttribute.cs b/src/System.Private.Interop/src/Shared/McgAccessorAttribute.cs
new file mode 100644
index 000000000..df7831aa7
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgAccessorAttribute.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Kind of accessor that the method represents. Must be kept in sync with il2il\src\Microsoft.Build.ILTasks\McgAccessorTransform.cs and
+ /// name expectations in MCG
+ /// </summary>
+ public enum McgAccessorKind
+ {
+ PropertyGet,
+ PropertySet,
+ EventAdd,
+ EventRemove,
+ }
+
+ /// <summary>
+ /// The McgAccessorAttribute is generated by MCG to indicate that a particular
+ /// property's setter shouldn't be named set_Foo, but put_Foo instead. Some .winmd
+ /// properties have setters named set_Foo, while others are named put_Foo, so we need
+ /// this attribute to mark the putters in MCG and rename them in a subsequent transform
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+ public sealed class McgAccessorAttribute : Attribute
+ {
+ public McgAccessorAttribute(McgAccessorKind accessorKind, string name)
+ {
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgComCallableAttribute.cs b/src/System.Private.Interop/src/Shared/McgComCallableAttribute.cs
new file mode 100644
index 000000000..5777d542a
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgComCallableAttribute.cs
@@ -0,0 +1,13 @@
+// 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
+{
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+ public sealed class McgComCallableAttribute : System.Attribute
+ {
+ public McgComCallableAttribute() { }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgComHelpers.cs b/src/System.Private.Interop/src/Shared/McgComHelpers.cs
new file mode 100644
index 000000000..eac1507c2
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgComHelpers.cs
@@ -0,0 +1,847 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// ----------------------------------------------------------------------------------
+// Interop library code
+//
+// COM Marshalling helpers used by MCG
+//
+// NOTE:
+// These source code are being published to InternalAPIs and consumed by RH builds
+// Use PublishInteropAPI.bat to keep the InternalAPI copies in sync
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Text;
+using System.Runtime;
+using System.Diagnostics.Contracts;
+using Internal.NativeFormat;
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices
+{
+ internal static unsafe class McgComHelpers
+ {
+ /// <summary>
+ /// Returns runtime class name for a specific object
+ /// </summary>
+ internal static string GetRuntimeClassName(Object obj)
+ {
+#if ENABLE_WINRT
+ System.IntPtr pWinRTItf = default(IntPtr);
+
+ try
+ {
+ pWinRTItf = McgMarshal.ObjectToIInspectable(obj);
+ if (pWinRTItf == default(IntPtr))
+ return String.Empty;
+ else
+ return GetRuntimeClassName(pWinRTItf);
+ }
+ finally
+ {
+ if (pWinRTItf != default(IntPtr)) McgMarshal.ComRelease(pWinRTItf);
+ }
+#else
+ throw new PlatformNotSupportedException("GetRuntimeClassName");
+#endif
+ }
+
+ /// <summary>
+ /// Returns runtime class name for a specific WinRT interface
+ /// </summary>
+ internal static string GetRuntimeClassName(IntPtr pWinRTItf)
+ {
+#if ENABLE_WINRT
+ void* unsafe_hstring = null;
+
+ try
+ {
+ int hr = CalliIntrinsics.StdCall__int(
+ ((__com_IInspectable*)(void*)pWinRTItf)->pVtable->pfnGetRuntimeClassName,
+ pWinRTItf, &unsafe_hstring);
+
+ // Don't throw if the call fails
+ if (hr < 0)
+ return String.Empty;
+
+ return McgMarshal.HStringToString(new IntPtr(unsafe_hstring));
+ }
+ finally
+ {
+ if (unsafe_hstring != null)
+ McgMarshal.FreeHString(new IntPtr(unsafe_hstring));
+ }
+#else
+ throw new PlatformNotSupportedException("GetRuntimeClassName");
+#endif
+ }
+
+ /// <summary>
+ /// Given a IStream*, seek to its beginning
+ /// </summary>
+ internal static unsafe bool SeekStreamToBeginning(IntPtr pStream)
+ {
+ Interop.COM.__IStream* pStreamNativePtr = (Interop.COM.__IStream*)(void*)pStream;
+ UInt64 newPosition;
+
+ int hr = CalliIntrinsics.StdCall<int>(
+ pStreamNativePtr->vtbl->pfnSeek,
+ pStreamNativePtr,
+ 0UL,
+ (uint)Interop.COM.STREAM_SEEK.STREAM_SEEK_SET,
+ &newPosition);
+ return (hr >= 0);
+ }
+
+ /// <summary>
+ /// Given a IStream*, change its size
+ /// </summary>
+ internal static unsafe bool SetStreamSize(IntPtr pStream, ulong lSize)
+ {
+ Interop.COM.__IStream* pStreamNativePtr = (Interop.COM.__IStream*)(void*)pStream;
+ UInt64 newPosition;
+
+ int hr = CalliIntrinsics.StdCall<int>(
+ pStreamNativePtr->vtbl->pfnSetSize,
+ pStreamNativePtr,
+ lSize,
+ (uint)Interop.COM.STREAM_SEEK.STREAM_SEEK_SET,
+ &newPosition);
+ return (hr >= 0);
+ }
+
+ /// <summary>
+ /// Release a IStream that has marshalled data in it
+ /// </summary>
+ internal static void SafeReleaseStream(IntPtr pStream)
+ {
+ Debug.Assert(pStream != default(IntPtr));
+#if ENABLE_WINRT
+ // Release marshalled data and ignore any error
+ ExternalInterop.CoReleaseMarshalData(pStream);
+
+ McgMarshal.ComRelease(pStream);
+#else
+ throw new PlatformNotSupportedException("SafeReleaseStream");
+#endif
+ }
+
+ /// <summary>
+ /// Returns whether the IUnknown* is a free-threaded COM object
+ /// </summary>
+ /// <param name="pUnknown"></param>
+ internal static unsafe bool IsFreeThreaded(IntPtr pUnknown)
+ {
+ //
+ // Does it support IAgileObject?
+ //
+ IntPtr pAgileObject = McgMarshal.ComQueryInterfaceNoThrow(pUnknown, ref Interop.COM.IID_IAgileObject);
+
+ if (pAgileObject != default(IntPtr))
+ {
+ // Anything that implements IAgileObject is considered to be free-threaded
+ // NOTE: This doesn't necessarily mean that the object is free-threaded - it only means
+ // we BELIEVE it is free-threaded
+ McgMarshal.ComRelease_StdCall(pAgileObject);
+ return true;
+ }
+
+ IntPtr pMarshal = McgMarshal.ComQueryInterfaceNoThrow(pUnknown, ref Interop.COM.IID_IMarshal);
+
+ if (pMarshal == default(IntPtr))
+ return false;
+
+ try
+ {
+ //
+ // Check the un-marshaler
+ //
+ Interop.COM.__IMarshal* pIMarshalNativePtr = (Interop.COM.__IMarshal*)(void*)pMarshal;
+
+ fixed (Guid* pGuid = &Interop.COM.IID_IUnknown)
+ {
+ Guid clsid;
+ int hr = CalliIntrinsics.StdCall<int>(
+ pIMarshalNativePtr->vtbl->pfnGetUnmarshalClass,
+ pIMarshalNativePtr,
+ pGuid,
+ default(IntPtr),
+ (uint)Interop.COM.MSHCTX.MSHCTX_INPROC,
+ default(IntPtr),
+ (uint)Interop.COM.MSHLFLAGS.MSHLFLAGS_NORMAL,
+ &clsid);
+
+ if (hr >= 0 && InteropExtensions.GuidEquals(ref clsid, ref Interop.COM.CLSID_InProcFreeMarshaler))
+ {
+ // The un-marshaller is indeed the unmarshaler for the FTM so this object
+ // is free threaded.
+ return true;
+ }
+ }
+
+ return false;
+ }
+ finally
+ {
+ McgMarshal.ComRelease_StdCall(pMarshal);
+ }
+ }
+
+ /// <summary>
+ /// Get from cache if available, else allocate from heap
+ /// </summary>
+#if !RHTESTCL
+ [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
+#endif
+ static internal void* CachedAlloc(int size, ref IntPtr cache)
+ {
+ // Read cache, clear it
+ void* pBlock = (void*)Interlocked.Exchange(ref cache, default(IntPtr));
+
+ if (pBlock == null)
+ {
+ pBlock =(void*) ExternalInterop.MemAlloc(new UIntPtr((uint)size));
+
+ if (pBlock == null)
+ {
+ throw new OutOfMemoryException();
+ }
+ }
+
+ return pBlock;
+ }
+
+ /// <summary>
+ /// Return to cache if empty, else free to heap
+ /// </summary>
+#if !RHTESTCL
+ [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
+#endif
+ static internal void CachedFree(void* block, ref IntPtr cache)
+ {
+ if ((void*)Interlocked.CompareExchange(ref cache, new IntPtr(block), default(IntPtr)) != null)
+ {
+ ExternalInterop.MemFree((IntPtr)block);
+ }
+ }
+
+ /// <summary>
+ /// Return true if the object is a RCW. False otherwise
+ /// </summary>
+ internal static bool IsComObject(object obj)
+ {
+ return (obj is __ComObject);
+ }
+
+ /// <summary>
+ /// Unwrap if this is a managed wrapper
+ /// Typically used in data binding
+ /// For example, you don't want to data bind against a KeyValuePairImpl<K, V> - you want the real
+ /// KeyValuePair<K, V>
+ /// </summary>
+ /// <param name="target">The object you want to unwrap</param>
+ /// <returns>The original object or the unwrapped object</returns>
+ internal static object UnboxManagedWrapperIfBoxed(object target)
+ {
+ //
+ // If the target is boxed by managed code:
+ // 1. ReferenceImpl/ReferenceArrayImpl
+ // 2. KeyValuePairImpl
+ // 3. CustomPropertyProviderProxy
+ //
+ // we should use its value for data binding
+ //
+ IManagedWrapper boxTarget = target as IManagedWrapper;
+
+ if (boxTarget != null)
+ target = boxTarget.GetTarget();
+
+ Debug.Assert(!(target is IManagedWrapper));
+
+ return target;
+ }
+
+ [Flags]
+ internal enum CreateComObjectFlags
+ {
+ None = 0,
+ IsWinRTObject,
+
+ /// <summary>
+ /// Don't attempt to find out the actual type (whether it is IInspectable nor IProvideClassInfo)
+ /// of the incoming interface and do not attempt to unbox them using WinRT rules
+ /// </summary>
+ SkipTypeResolutionAndUnboxing
+ }
+
+ /// <summary>
+ /// Returns the existing RCW or create a new RCW from the COM interface pointer
+ /// NOTE: Don't use this overload if you already have the identity IUnknown
+ /// </summary>
+ /// <param name="expectedContext">
+ /// The current context of this thread. If it is passed and is not Default, we'll check whether the
+ /// returned RCW from cache matches this expected context. If it is not a match (from a different
+ /// context, and is not free threaded), we'll go ahead ignoring the cached entry, and create a new
+ /// RCW instead - which will always end up in the current context
+ /// We'll skip the check if current == ContextCookie.Default.
+ /// </param>
+ internal static object ComInterfaceToComObject(
+ IntPtr pComItf,
+ McgTypeInfo interfaceTypeInfo,
+ McgClassInfo classInfoInSigature,
+ ContextCookie expectedContext,
+ CreateComObjectFlags flags
+ )
+ {
+ Debug.Assert(expectedContext.IsDefault || expectedContext.IsCurrent);
+
+ //
+ // Get identity IUnknown for lookup
+ //
+ IntPtr pComIdentityIUnknown = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IUnknown);
+
+ if (pComIdentityIUnknown == default(IntPtr))
+ throw new InvalidCastException();
+
+ try
+ {
+ object obj = ComInterfaceToComObjectInternal(
+ pComItf,
+ pComIdentityIUnknown,
+ interfaceTypeInfo,
+ classInfoInSigature,
+ expectedContext,
+ flags
+ );
+
+ return obj;
+ }
+ finally
+ {
+ McgMarshal.ComRelease(pComIdentityIUnknown);
+ }
+ }
+
+ /// <summary>
+ /// Returns the existing RCW or create a new RCW from the COM interface pointer
+ /// NOTE: This does unboxing unless CreateComObjectFlags.SkipTypeResolutionAndUnboxing is specified
+ /// </summary>
+ /// <param name="expectedContext">
+ /// The current context of this thread. If it is passed and is not Default, we'll check whether the
+ /// returned RCW from cache matches this expected context. If it is not a match (from a different
+ /// context, and is not free threaded), we'll go ahead ignoring the cached entry, and create a new
+ /// RCW instead - which will always end up in the current context
+ /// We'll skip the check if current == ContextCookie.Default.
+ /// </param>
+ internal static object ComInterfaceToComObjectInternal(
+ IntPtr pComItf,
+ IntPtr pComIdentityIUnknown,
+ McgTypeInfo interfaceTypeInfo,
+ McgClassInfo classInfoInSignature,
+ ContextCookie expectedContext,
+ CreateComObjectFlags flags
+ )
+ {
+ string className;
+ object obj = ComInterfaceToComObjectInternal_NoCache(
+ pComItf,
+ pComIdentityIUnknown,
+ interfaceTypeInfo,
+ classInfoInSignature,
+ expectedContext,
+ flags,
+ out className
+ );
+
+ //
+ // The assumption here is that if the classInfoInSignature is null and interfaceTypeInfo
+ // is either IUnknow and IInspectable we need to try unboxing.
+ //
+ bool doUnboxingCheck =
+ (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0 &&
+ obj != null &&
+ classInfoInSignature.IsNull &&
+ (interfaceTypeInfo == McgModuleManager.IUnknown ||
+ interfaceTypeInfo == McgModuleManager.IInspectable);
+
+ if (doUnboxingCheck)
+ {
+
+ //
+ // Try unboxing
+ // Even though this might just be a IUnknown * from the signature, we still attempt to unbox
+ // if it implements IInspectable
+ //
+ // @TODO - We might need to optimize this by pre-checking the names to see if they
+ // potentially represents a boxed type, but for now let's keep it simple and I also don't
+ // want to replicate the knowledge here
+ // @TODO2- We probably should skip the creating the COM object in the first place.
+ //
+ // NOTE: the RCW here could be a cached one (for a brief time if GC doesn't kick in. as there
+ // is nothing to hold the RCW alive for IReference<T> RCWs), so this could save us a RCW
+ // creation cost potentially. Desktop CLR doesn't do this. But we also paying for unnecessary
+ // cache management cost, and it is difficult to say which way is better without proper
+ // measuring
+ //
+ object unboxedObj = McgModuleManager.UnboxIfBoxed(obj, className);
+ if (unboxedObj != null)
+ return unboxedObj;
+ }
+
+ //
+ // In order for variance to work, we save the incoming interface pointer as specified in the
+ // signature into the cache, so that we know this RCW does support this interface and variance
+ // can take advantage of that later
+ // NOTE: In some cases, native might pass a WinRT object as a 'compatible' interface, for example,
+ // pass IVector<IFoo> as IVector<Object> because they are 'compatible', but QI for IVector<object>
+ // won't succeed. In this case, we'll just believe it implements IVector<Object> as in the
+ // signature while the underlying interface pointer is actually IVector<IFoo>
+ //
+ __ComObject comObject = obj as __ComObject;
+
+ if (comObject != null)
+ {
+ McgMarshal.ComAddRef(pComItf);
+
+ try
+ {
+ comObject.InsertIntoCache(interfaceTypeInfo, ContextCookie.Current, ref pComItf, true);
+ }
+ finally
+ {
+ //
+ // Only release when a exception is thrown or we didn't 'swallow' the ref count by
+ // inserting it into the cache
+ //
+ McgMarshal.ComSafeRelease(pComItf);
+ }
+ }
+
+ return obj;
+ }
+
+ /// <summary>
+ /// Returns the existing RCW or create a new RCW from the COM interface pointer
+ /// NOTE: This does not do any unboxing at all.
+ /// </summary>
+ /// <param name="expectedContext">
+ /// The current context of this thread. If it is passed and is not Default, we'll check whether the
+ /// returned RCW from cache matches this expected context. If it is not a match (from a different
+ /// context, and is not free threaded), we'll go ahead ignoring the cached entry, and create a new
+ /// RCW instead - which will always end up in the current context
+ /// We'll skip the check if current == ContextCookie.Default.
+ /// </param>
+ private static object ComInterfaceToComObjectInternal_NoCache(
+ IntPtr pComItf,
+ IntPtr pComIdentityIUnknown,
+ McgTypeInfo interfaceTypeInfo,
+ McgClassInfo classInfoInSignature,
+ ContextCookie expectedContext,
+ CreateComObjectFlags flags,
+ out string className
+ )
+ {
+ className = null;
+
+ //
+ // Lookup RCW in global RCW cache based on the identity IUnknown
+ //
+ __ComObject comObject = ComObjectCache.Lookup(pComIdentityIUnknown);
+
+ if (comObject != null)
+ {
+ bool useThisComObject = true;
+
+ if (!expectedContext.IsDefault)
+ {
+ //
+ // Make sure the returned RCW matches the context we specify (if any)
+ //
+ if (!comObject.IsFreeThreaded &&
+ !comObject.ContextCookie.Equals(expectedContext))
+ {
+ //
+ // This is a mismatch.
+ // We only care about context for WinRT factory RCWs (which is the only place we are
+ // passing in the context right now).
+ // When we get back a WinRT factory RCW created in a different context. This means the
+ // factory is a singleton, and the returned IActivationFactory could be either one of
+ // the following:
+ // 1) A raw pointer, and it acts like a free threaded object
+ // 2) A proxy that is used across different contexts. It might maintain a list of contexts
+ // that it is marshaled to, and will fail to be called if it is not marshaled to this
+ // context yet.
+ //
+ // In this case, it is unsafe to use this RCW in this context and we should proceed
+ // to create a duplicated one instead. It might make sense to have a context-sensitive
+ // RCW cache but I don't think this case will be common enough to justify it
+ //
+ // @TODO: Check for DCOM proxy as well
+ useThisComObject = false;
+ }
+ }
+
+ if (useThisComObject)
+ {
+ //
+ // We found one - AddRef and return
+ //
+ comObject.AddRef();
+ return comObject;
+ }
+ }
+
+ string winrtClassName = null;
+
+ bool isSealed = false;
+
+ if (!classInfoInSignature.IsNull)
+ {
+ isSealed = classInfoInSignature.IsSealed;
+ }
+
+ //
+ // Only look at runtime class name if the class type in signature is not sealed
+ // NOTE: In the case of System.Uri, we are not pass the class type, only the interface
+ //
+ if (!isSealed &&
+ (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0)
+ {
+ IntPtr pInspectable;
+
+ bool needRelease = false;
+
+ if (interfaceTypeInfo.IsIInspectable)
+ {
+ //
+ // Use the interface pointer as IInspectable as we know it is indeed a WinRT interface that
+ // derives from IInspectable
+ //
+ pInspectable = pComItf;
+ }
+ else if ((flags & CreateComObjectFlags.IsWinRTObject) != 0)
+ {
+ //
+ // Otherwise, if someone tells us that this is a WinRT object, but we don't have a
+ // IInspectable interface at hand, we'll QI for it
+ //
+ pInspectable = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IInspectable);
+ needRelease = true;
+ }
+ else
+ {
+ pInspectable = default(IntPtr);
+ }
+
+ try
+ {
+ if (pInspectable != default(IntPtr))
+ {
+ className = McgComHelpers.GetRuntimeClassName(pInspectable);
+ winrtClassName = className;
+ }
+ }
+ finally
+ {
+ if (needRelease && pInspectable != default(IntPtr))
+ {
+ McgMarshal.ComRelease(pInspectable);
+ pInspectable = default(IntPtr);
+ }
+ }
+ }
+
+ //
+ // 1. Prefer using the class returned from GetRuntimeClassName
+ // 2. Otherwise use the class (if there) in the signature
+ // 3. Out of options - create __ComObject
+ //
+ McgClassInfo classInfoToCreateRCW = McgClassInfo.Null;
+ McgTypeInfo interfaceInfo = McgTypeInfo.Null;
+
+ if (!String.IsNullOrEmpty(className))
+ {
+ if (!McgModuleManager.TryGetClassInfoFromName(className, out classInfoToCreateRCW))
+ {
+ //
+ // If we can't find the class name in our map, try interface as well
+ // Such as IVector<Int32>
+ // This apparently won't work if we haven't seen the interface type in MCG
+ //
+ McgModuleManager.TryGetInterfaceTypeInfoFromName(className, out interfaceInfo);
+ }
+ }
+
+ if (classInfoToCreateRCW.IsNull)
+ classInfoToCreateRCW = classInfoInSignature;
+
+ // Use identity IUnknown to create the new RCW
+ // @TODO: Transfer the ownership of ref count to the RCW
+ if (classInfoToCreateRCW.IsNull)
+ {
+ //
+ // Create a weakly typed RCW because we have no information about this particular RCW
+ // @TODO - what if this RCW is not seen by MCG but actually exists in WinMD and therefore we
+ // are missing GCPressure and ComMarshallingType information for this object?
+ //
+ comObject = new __ComObject(pComIdentityIUnknown, McgClassInfo.Null);
+ }
+ else
+ {
+ //
+ // Create a strongly typed RCW based on McgClassInfo
+ //
+ comObject = CreateComObjectInternal(classInfoToCreateRCW, pComIdentityIUnknown); // Use identity IUnknown to create the new RCW
+ }
+
+#if DEBUG
+ //
+ // Remember the runtime class name for debugging purpose
+ // This way you can tell what the class name is, even when we failed to create a strongly typed
+ // RCW for it
+ //
+ comObject.m_runtimeClassName = className;
+#endif
+
+ //
+ // Make sure we QI for that interface
+ //
+ if (!interfaceInfo.IsNull)
+ {
+ comObject.QueryInterface_NoAddRef_Internal(interfaceInfo, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false);
+ }
+
+ return comObject;
+ }
+
+ private static __ComObject CreateComObjectInternal(McgClassInfo classInfo, IntPtr pComItf)
+ {
+ Debug.Assert(!classInfo.IsNull);
+
+ if (classInfo.ClassType.Equals(McgModule.s_DependencyReductionTypeRemovedTypeHandle))
+ {
+ // We should filter out the strongly typed RCW in TryGetClassInfoFromName step
+#if !RHTESTCL
+ Environment.FailFast(McgTypeHelpers.GetDiagnosticMessageForMissingType(classInfo.ClassType));
+#else
+ Environment.FailFast("We should never see strongly typed RCW discarded here");
+#endif
+ }
+
+ //Note that this doesn't run the constructor in RH but probably do in your reflection based implementation.
+ //If this were a real RCW, you would actually 'new' the RCW which is wrong. Fortunately in CoreCLR we don't have
+ //this scenario so we are OK, but we should figure out a way to fix this by having a runtime API.
+ object newClass = InteropExtensions.RuntimeNewObject(classInfo.ClassType);
+
+ Debug.Assert(newClass is __ComObject);
+
+ __ComObject newObj = InteropExtensions.UncheckedCast<__ComObject>(newClass);
+
+ IntPtr pfnCtor = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfAttachingCtor>(__ComObject.AttachingCtor);
+ CalliIntrinsics.Call<int>(pfnCtor, newObj, pComItf, classInfo);
+
+ return newObj;
+ }
+
+
+ /// <summary>
+ /// Converts a COM interface pointer to a managed object
+ /// This either gets back a existing CCW, or a existing RCW, or create a new RCW
+ /// </summary>
+ internal static object ComInterfaceToObjectInternal(
+ IntPtr pComItf,
+ McgTypeInfo interfaceTypeInfo,
+ McgClassInfo classInfoInSignature,
+ CreateComObjectFlags flags)
+ {
+ bool needUnboxing = (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0;
+
+ object ret = ComInterfaceToObjectInternal_NoManagedUnboxing(pComItf, interfaceTypeInfo, classInfoInSignature, flags);
+ if (ret != null && needUnboxing)
+ {
+ return UnboxManagedWrapperIfBoxed(ret);
+ }
+
+ return ret;
+ }
+
+ static object ComInterfaceToObjectInternal_NoManagedUnboxing(
+ IntPtr pComItf,
+ McgTypeInfo interfaceTypeInfo,
+ McgClassInfo classInfoInSignature,
+ CreateComObjectFlags flags)
+ {
+ if (pComItf == default(IntPtr))
+ return null;
+
+ //
+ // Is this a CCW?
+ //
+ ComCallableObject ccw;
+
+ if (ComCallableObject.TryGetCCW(pComItf, out ccw))
+ {
+ return ccw.TargetObject;
+ }
+
+ //
+ // This pointer is not a CCW, but we need to do one additional check here for aggregation
+ // In case the COM pointer is a interface implementation from native, but the outer object is a
+ // managed object
+ //
+ IntPtr pComIdentityIUnknown = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IUnknown);
+
+ if (pComIdentityIUnknown == default(IntPtr))
+ throw new InvalidCastException();
+
+ try
+ {
+ //
+ // Check whether the identity COM pointer to see if it is a aggregating CCW
+ //
+ if (ComCallableObject.TryGetCCW(pComIdentityIUnknown, out ccw))
+ {
+ return ccw.TargetObject;
+ }
+
+ //
+ // Nope, not a CCW - let's go down our RCW creation code path
+ //
+ return ComInterfaceToComObjectInternal(
+ pComItf,
+ pComIdentityIUnknown,
+ interfaceTypeInfo,
+ classInfoInSignature,
+ ContextCookie.Default,
+ flags
+ );
+ }
+ finally
+ {
+ McgMarshal.ComRelease(pComIdentityIUnknown);
+ }
+ }
+
+
+ internal unsafe static IntPtr ObjectToComInterfaceInternal(Object obj, McgTypeInfo typeInfo)
+ {
+ if (obj == null)
+ return default(IntPtr);
+#if ENABLE_WINRT
+ //
+ // Try boxing if this is a WinRT object
+ //
+ if (typeInfo == McgModuleManager.IInspectable)
+ {
+ object unboxed = McgModuleManager.BoxIfBoxable(obj);
+
+ //
+ // Marshal ReferenceImpl<T> to WinRT as IInspectable
+ //
+ if (unboxed != null)
+ {
+ obj = unboxed;
+ }
+ else
+ {
+ //
+ // Anything that can be casted to object[] will be boxed as object[]
+ //
+ object[] objArray = obj as object[];
+ if (objArray != null)
+ {
+ unboxed = McgModuleManager.BoxIfBoxable(obj, typeof(object[]).TypeHandle);
+ if (unboxed != null)
+ obj = unboxed;
+ }
+ }
+ }
+#endif //ENABLE_WINRT
+
+ //
+ // If this is a RCW, and the RCW is not a base class (managed class deriving from RCW class),
+ // QI on the RCW
+ //
+ __ComObject comObject = obj as __ComObject;
+
+ if (comObject != null && !comObject.ExtendsComObject)
+ {
+ IntPtr pComPtr = comObject.QueryInterface_NoAddRef_Internal(typeInfo, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false);
+ if (pComPtr == default(IntPtr))
+ return default(IntPtr);
+
+ McgMarshal.ComAddRef(pComPtr);
+ GC.KeepAlive(comObject); // make sure we don't collect the object before adding a refcount.
+
+ return pComPtr;
+ }
+
+ //
+ // Otherwise, go down the CCW code path
+ //
+ Guid itfGuid = typeInfo.ItfGuid;
+ return ManagedObjectToComInterfaceInternal(obj, ref itfGuid, typeInfo);
+ }
+
+ internal static unsafe IntPtr ManagedObjectToComInterface(Object obj, McgTypeInfo itfTypeInfo)
+ {
+ Guid itfGuid = itfTypeInfo.ItfGuid;
+ return ManagedObjectToComInterfaceInternal(obj, ref itfGuid, itfTypeInfo);
+ }
+
+ internal static unsafe IntPtr ManagedObjectToComInterface(Object obj, RuntimeTypeHandle typeHandle)
+ {
+ McgTypeInfo secondTypeInfo;
+ return ManagedObjectToComInterface(obj, McgModuleManager.GetTypeInfoFromTypeHandle(typeHandle, out secondTypeInfo));
+ }
+
+ internal static unsafe IntPtr ManagedObjectToComInterface(Object obj, ref Guid iid)
+ {
+ return ManagedObjectToComInterfaceInternal(obj, ref iid, McgTypeInfo.Null);
+ }
+
+ private static unsafe IntPtr ManagedObjectToComInterfaceInternal(Object obj, ref Guid iid, McgTypeInfo itfTypeInfo)
+ {
+ if (obj == null)
+ {
+ return default(IntPtr);
+ }
+
+ //
+ // Look up ComCallableObject from the cache
+ // If couldn't find one, create a new one
+ //
+ ComCallableObject ccw = null;
+
+ try
+ {
+ //
+ // Either return existing one or create a new one
+ // In either case, the returned CCW is addref-ed to avoid race condition
+ //
+ IntPtr dummy;
+
+ ccw = CCWLookupMap.GetOrCreateCCW(obj, McgTypeInfo.Null, out dummy);
+ Debug.Assert(ccw != null);
+
+ return ccw.GetComInterfaceForIID(ref iid, itfTypeInfo);
+ }
+ finally
+ {
+ //
+ // Free the extra ref count added by GetOrCreateCCW (to protect the CCW from being collected)
+ //
+ if (ccw != null)
+ ccw.Release();
+ }
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgData.cs b/src/System.Private.Interop/src/Shared/McgData.cs
new file mode 100644
index 000000000..20f93575b
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgData.cs
@@ -0,0 +1,1300 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Internal.Runtime.CompilerServices;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+namespace System.Runtime.InteropServices
+{
+ [Flags]
+ public enum McgInterfaceFlags : byte
+ {
+ None = 0x00,
+ isIInspectable = 0x01, // this interface derives from IInspectable
+ isDelegate = 0x02, // this entry is for a WinRT delegate type, ItfType is the type of a managed delegate type
+ isInternal = 0x04,
+
+ useSharedCCW = 0x08, // this entry uses shared ccwVTable + thunk function
+ SharedCCWMask = 0xF8,
+
+ useSharedCCW_IVector = 0x08, // 4-bit shared ccw index: 16 max, 8 used
+ useSharedCCW_IVectorView = 0x18,
+ useSharedCCW_IIterable = 0x28,
+ useSharedCCW_IIterator = 0x38,
+ useSharedCCW_AsyncOperationCompletedHandler = 0x48,
+ useSharedCCW_IVectorBlittable = 0x58,
+ useSharedCCW_IVectorViewBlittable = 0x68,
+ useSharedCCW_IIteratorBlittable = 0x78,
+ }
+
+ [Flags]
+ public enum McgClassFlags : int
+ {
+ None = 0,
+
+ /// <summary>
+ /// This represents the types MarshalingBehavior.
+ /// </summary>
+ MarshalingBehavior_Inhibit = 1,
+ MarshalingBehavior_Free = 2,
+ MarshalingBehavior_Standard = 3,
+
+ MarshalingBehavior_Mask = 3,
+
+ /// <summary>
+ /// GCPressureRange
+ /// </summary>
+ GCPressureRange_WinRT_Default = 1 << 2,
+ GCPressureRange_WinRT_Low = 2 << 2,
+ GCPressureRange_WinRT_Medium = 3 << 2,
+ GCPressureRange_WinRT_High = 4 << 2,
+ GCPressureRange_Mask = 7 << 2,
+
+ /// <summary>
+ /// Either a WinRT value type, or a projected class type
+ /// In either case, it is not a __ComObject and we can't create it using CreateComObject
+ /// </summary>
+ NotComObject = 32,
+
+ /// <summary>
+ /// This type is sealed
+ /// </summary>
+ IsSealed = 64,
+
+ /// <summary>
+ /// This type is a WinRT type and we'll return Kind=Metadata in type name marshalling
+ /// </summary>
+ IsWinRT = 128
+ }
+
+ /// <summary>
+ /// Per-native-interface information generated by MCG
+ /// </summary>
+ [CLSCompliant(false)]
+ public struct McgInterfaceData // 36 bytes on 32-bit platforms
+ {
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "FixupItfType" and field type must be FixupRuntimeTypeHandle
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::WalkPtrAndTypeData in debug\dbi\values.cpp
+ /// </summary>
+ public FixupRuntimeTypeHandle FixupItfType; // 1 pointer
+
+ // Optional fields(FixupDispatchClassType and FixupDynamicAdapterClassType)
+ public FixupRuntimeTypeHandle FixupDispatchClassType; // 1 pointer, around 80% usage
+ public FixupRuntimeTypeHandle FixupDynamicAdapterClassType; // 1 pointer, around 20% usage
+ public RuntimeTypeHandle ItfType
+ {
+ get
+ {
+ return FixupItfType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupItfType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public RuntimeTypeHandle DispatchClassType
+ {
+ get
+ {
+ return FixupDispatchClassType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupDispatchClassType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public RuntimeTypeHandle DynamicAdapterClassType
+ {
+ get
+ {
+ return FixupDynamicAdapterClassType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupDynamicAdapterClassType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ // Fixed fields
+ public Guid ItfGuid; // 16 bytes
+
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "Flags" and field type must be an enum type
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::WalkPtrAndTypeData in debug\dbi\values.cpp
+ /// </summary>
+ public McgInterfaceFlags Flags; // 1 byte
+
+ public short MarshalIndex; // 2 bytes: Index into InterfaceMarshalData array for shared CCW, also used for internal module sequential type index
+ // Optional fields(CcwVtable)
+ // TODO fyuan define larger McgInterfaceData for merging interop code (shared CCW, default eventhandler)
+ public IntPtr CcwVtable; // 1 pointer, around 20-40% usage
+ }
+
+ [CLSCompliant(false)]
+ public struct McgGenericArgumentMarshalInfo // Marshal information for generic argument T
+ {
+ // sizeOf(T)
+ public uint ElementSize;
+ // Class Type Handle for sealed T winrt class
+ public FixupRuntimeTypeHandle FixupElementClassType;
+ // Interface Type Handle for T interface type
+ public FixupRuntimeTypeHandle FixupElementInterfaceType;
+ // Type Handle for IAsyncOperation<T>
+ public FixupRuntimeTypeHandle FixupAsyncOperationType;
+ // Type Handle for Iterator<T>
+ public FixupRuntimeTypeHandle FixupIteratorType;
+ // Type Handle for VectorView<T>
+ public FixupRuntimeTypeHandle FixupVectorViewType;
+ public RuntimeTypeHandle AsyncOperationType
+ {
+ get
+ {
+ return FixupAsyncOperationType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupAsyncOperationType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public RuntimeTypeHandle ElementClassType
+ {
+ get
+ {
+ return FixupElementClassType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupElementClassType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public RuntimeTypeHandle ElementInterfaceType
+ {
+ get
+ {
+ return FixupElementInterfaceType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupElementInterfaceType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+
+ public RuntimeTypeHandle IteratorType
+ {
+ get
+ {
+ return FixupIteratorType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupIteratorType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+
+ public RuntimeTypeHandle VectorViewType
+ {
+ get
+ {
+ return FixupVectorViewType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupVectorViewType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Per-WinRT-class information generated by MCG. This is used for TypeName marshalling and for
+ /// CreateComObject. For the TypeName marshalling case, we have Nullable<T> / KeyValuePair<K,V> value
+ /// classes as the ClassType field and WinRT names like Windows.Foundation.IReference`1<blah> in the name
+ /// field. These entries are filtered out by CreateComObject using the Flags field.
+ /// </summary>
+ [CLSCompliant(false)]
+ public struct McgClassData
+ {
+ public FixupRuntimeTypeHandle FixupClassType; // FixupRuntimeTypeHandle for type in CLR (projected) view
+ public RuntimeTypeHandle ClassType // RuntimeTypeHandle of FixupRuntimeTypeHandle
+ {
+ get
+ {
+ return FixupClassType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupClassType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public McgClassFlags Flags; // Flags (whether it is a ComObject, whether it can be boxed, etc)
+
+ /// <summary>
+ /// The type handle for its base class
+ ///
+ /// There are two ways to access base class: RuntimeTypeHandle or Index
+ /// Ideally we want to use typehandle for everything - but DR throws it away and breaks the inheritance chain
+ /// - therefore we would only use index for "same module" and type handle for "cross module"
+ ///
+ /// Code Pattern:
+ /// if (BaseClassIndex >=0) { // same module }
+ /// else if(!BaseClassType.Equals(default(RuntimeTypeHandle)) { // cross module}
+ /// else { // it doesn't have base}
+ /// </summary>
+ public FixupRuntimeTypeHandle FixupBaseClassType; // FixupRuntimeTypeHandle for Base class type in CLR (projected) view
+ public RuntimeTypeHandle BaseClassType // RuntimeTypeHandle of BaseClass
+ {
+ get
+ {
+ return FixupBaseClassType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupBaseClassType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public short BaseClassIndex; // Index to the base class;
+
+ /// <summary>
+ /// The type handle for its default Interface
+ /// The comment above for BaseClassType applies for DefaultInterface as well
+ /// </summary>
+ public FixupRuntimeTypeHandle FixupDefaultInterfaceType; // FixupRuntimeTypeHandle for DefaultInterface type in CLR (projected) view
+ public RuntimeTypeHandle DefaultInterfaceType // RuntimeTypeHandle of DefaultInterface
+ {
+ get
+ {
+ return FixupDefaultInterfaceType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupDefaultInterfaceType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public short DefaultInterfaceIndex; // Index to the default interface
+ }
+
+ [CLSCompliant(false)]
+ public struct McgHashcodeVerifyEntry
+ {
+ public FixupRuntimeTypeHandle FixupTypeHandle;
+ public RuntimeTypeHandle TypeHandle
+ {
+ get
+ {
+ return FixupTypeHandle.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupTypeHandle = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public uint HashCode;
+ }
+
+
+ /// <summary>
+ /// Mcg data used for boxing
+ /// Boxing refers to IReference/IReferenceArray boxing, as well as projection support when marshalling
+ /// IInspectable, such as IKeyValuePair, System.Uri, etc.
+ /// So this supports boxing in a broader sense that it supports WinRT type <-> native type projection
+ /// There are 3 cases:
+ /// 1. IReference<T> / IReferenceArray<T>. It is boxed to a managed wrapper and unboxed either from the wrapper or from native IReference/IReferenceArray RCW (through unboxing stub)
+ /// 2. IKeyValuePair<K, V>. Very similiar to #1 except that it does not have propertyType
+ /// 3. All other cases, including System.Uri, NotifyCollectionChangedEventArgs, etc. They go through boxing stub and unboxing stub.
+ ///
+ /// NOTE: Even though this struct doesn't have a name in itself, there is a parallel array
+ /// m_boxingDataNameMap that holds the corresponding class names for each boxing data
+ /// </summary>
+ [CLSCompliant(false)]
+ public struct McgBoxingData
+ {
+ /// <summary>
+ /// The target type that triggers the boxing. Used in search
+ /// </summary>
+ public FixupRuntimeTypeHandle FixupManagedClassType;
+
+ /// <summary>
+ /// HIDDEN
+ /// This is actually saved in m_boxingDataNameMap
+ /// The runtime class name that triggers the unboxing. Used in search.
+ /// </summary>
+ /// public string Name;
+
+ /// <summary>
+ /// A managed wrapper for IReference/IReferenceArray/IKeyValuePair boxing
+ /// We create the wrapper directly instead of going through a boxing stub. This saves us some
+ /// disk space (300+ boxing stub in a typical app), but we need to see whether this trade off
+ /// makes sense long term.
+ /// </summary>
+ public FixupRuntimeTypeHandle FixupCLRBoxingWrapperType;
+ public RuntimeTypeHandle ManagedClassType
+ {
+ get
+ {
+ return FixupManagedClassType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupManagedClassType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public RuntimeTypeHandle CLRBoxingWrapperType
+ {
+ get
+ {
+ return FixupCLRBoxingWrapperType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupCLRBoxingWrapperType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ /// <summary>
+ /// General boxing stub - boxing an managed object instance into a native object instance (RCW)
+ /// This is used for special cases where managed wrappers aren't suitable, mainly for projected types
+ /// such as System.Uri.
+ ///
+ /// Prototype:
+ /// object Boxing_Stub(object target)
+ /// </summary>
+ public IntPtr BoxingStub;
+
+ /// <summary>
+ /// General unboxing stub - unbox a native object instance (RCW) into a managed object (interestingly,
+ /// can be boxed in the managed sense)
+ ///
+ /// object UnboxingStub(object target)
+ /// </summary>
+ public IntPtr UnboxingStub;
+
+ /// <summary>
+ /// Corresponding PropertyType
+ /// Only used when boxing into a managed wrapper - because it is only meaningful in IReference
+ /// & IReferenceArray
+ /// </summary>
+ public short PropertyType;
+ }
+
+ /// <summary>
+ /// This information is separate from the McgClassData[]
+ /// as its captures the types which are not imported by the MCG.
+ /// </summary>
+ [CLSCompliant(false)]
+ public struct McgTypeNameMarshalingData
+ {
+ public FixupRuntimeTypeHandle FixupClassType;
+ public RuntimeTypeHandle ClassType
+ {
+ get
+ {
+ return FixupClassType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupClassType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ }
+
+ public enum McgStructMarshalFlags
+ {
+ None,
+
+ /// <summary>
+ /// This struct has invalid layout information, most likely because it is marked LayoutKind.Auto
+ /// </summary>
+ HasInvalidLayout
+ }
+
+ [CLSCompliant(false)]
+ public struct McgStructMarshalData
+ {
+ public FixupRuntimeTypeHandle FixupSafeStructType;
+ public FixupRuntimeTypeHandle FixupUnsafeStructType;
+ public RuntimeTypeHandle SafeStructType
+ {
+ get
+ {
+ return FixupSafeStructType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupSafeStructType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public RuntimeTypeHandle UnsafeStructType
+ {
+ get
+ {
+ return FixupUnsafeStructType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupUnsafeStructType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public IntPtr MarshalStub;
+ public IntPtr UnmarshalStub;
+ public IntPtr DestroyStructureStub;
+
+ public McgStructMarshalFlags Flags;
+
+ /// <summary>
+ /// This struct has invalid layout information, most likely because it is marked LayoutKind.Auto
+ /// We'll throw exception when this struct is getting marshalled
+ /// </summary>
+ internal bool HasInvalidLayout
+ {
+ get
+ {
+ return (Flags & McgStructMarshalFlags.HasInvalidLayout) != 0;
+ }
+ }
+
+ public int FieldOffsetStartIndex; // start index to its field offset data
+ public int NumOfFields; // number of fields
+ }
+
+ [CLSCompliant(false)]
+ public struct McgUnsafeStructFieldOffsetData
+ {
+ public uint Offset; // offset value in bytes
+ }
+
+ /// <summary>
+ /// Base class for KeyValuePairImpl<T>
+ /// </summary>
+ public abstract class BoxedKeyValuePair : IManagedWrapper
+ {
+ // Called by public object McgModule.Box(object obj, int boxingIndex) after allocating instance
+ public abstract object Initialize(object val);
+
+ public abstract object GetTarget();
+ }
+
+ /// <summary>
+ /// Supports unboxing managed wrappers such as ReferenceImpl / KeyValuePair
+ /// </summary>
+ public interface IManagedWrapper
+ {
+ object GetTarget();
+ }
+
+ /// <summary>
+ /// Base class for ReferenceImpl<T>/ReferenceArrayImpl<T>
+ /// </summary>
+ public class BoxedValue : IManagedWrapper
+ {
+ protected object m_data; // boxed value
+ protected short m_type; // Windows.Foundation.PropertyType
+ protected bool m_unboxed; // false if T ReferenceImpl<T>.m_value needs to be unboxed from m_data when needed
+
+ public BoxedValue(object val, int type)
+ {
+ m_data = val;
+ m_type = (short)type;
+ }
+
+ // Called by public object Box(object obj, int boxingIndex) after allocating instance
+ // T ReferenceImpl<T>.m_value needs to be unboxed from m_data when needed
+ virtual public void Initialize(object val, int type)
+ {
+ m_data = val;
+ m_type = (short)type;
+ }
+
+ public object GetTarget()
+ {
+ return m_data;
+ }
+
+ public override string ToString()
+ {
+ if (m_data != null)
+ {
+ return m_data.ToString();
+ }
+ else
+ {
+ return "null";
+ }
+ }
+ }
+
+ /// <summary>
+ /// Entries for WinRT classes that MCG didn't see in user code
+ /// We need to make sure when we are marshalling these types, we need to hand out the closest match
+ /// For example, if MCG only sees DependencyObject but native is passing MatrixTransform, we need
+ /// to give user the next best thing - dependencyObject, so that user can cast it to DependencyObject
+ ///
+ /// MatrixTransform -> DependencyObject
+ /// </summary>
+ [CLSCompliant(false)]
+ public struct McgAdditionalClassData
+ {
+ public int ClassDataIndex; // Pointing to the "next best" class (DependencyObject, for example)
+
+ public FixupRuntimeTypeHandle FixupClassType; // Pointing to the "next best" class (DependencyObject, for example)
+ public RuntimeTypeHandle ClassType
+ {
+ get
+ {
+ return FixupClassType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupClassType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Maps from an ICollection or IReadOnlyCollection type to the corresponding entries in m_interfaceTypeInfo
+ /// for IList, IDictionary, IReadOnlyList, IReadOnlyDictionary
+ /// </summary>
+ [CLSCompliant(false)]
+ public struct McgCollectionData
+ {
+ public FixupRuntimeTypeHandle FixupCollectionType;
+ public RuntimeTypeHandle CollectionType
+ {
+ get
+ {
+ return FixupCollectionType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupCollectionType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public FixupRuntimeTypeHandle FixupFirstType;
+ public RuntimeTypeHandle FirstType
+ {
+ get
+ {
+ return FixupFirstType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupFirstType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ public FixupRuntimeTypeHandle FixupSecondType;
+ public RuntimeTypeHandle SecondType
+ {
+ get
+ {
+ return FixupSecondType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupSecondType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Captures data for each P/invoke delegate type we decide to import
+ /// </summary>
+ [CLSCompliant(false)]
+ public struct McgPInvokeDelegateData
+ {
+ /// <summary>
+ /// Type of the delegate
+ /// </summary>
+ public FixupRuntimeTypeHandle FixupDelegate;
+ public RuntimeTypeHandle Delegate
+ {
+ get
+ {
+ return FixupDelegate.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupDelegate = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ /// <summary>
+ /// The stub called from thunk that does the marshalling when calling managed delegate (as a function
+ /// pointer) from native code
+ /// </summary>
+ public IntPtr ReverseStub;
+
+ /// <summary>
+ /// This creates a delegate wrapper class that wraps the native function pointer and allows managed
+ /// code to call it
+ /// </summary>
+ public IntPtr ForwardDelegateCreationStub;
+ }
+
+
+ /// <summary>
+ /// Base class for all 'wrapper' classes that wraps a native function pointer
+ /// The forward delegates (that wraps native function pointers) points to derived Invoke method of this
+ /// class, and the Invoke method would implement the marshalling and making the call
+ /// </summary>
+ public abstract class NativeFunctionPointerWrapper
+ {
+ public NativeFunctionPointerWrapper(IntPtr nativeFunctionPointer)
+ {
+ m_nativeFunctionPointer = nativeFunctionPointer;
+ }
+
+ IntPtr m_nativeFunctionPointer;
+
+ public IntPtr NativeFunctionPointer
+ {
+ get { return m_nativeFunctionPointer; }
+ }
+ }
+
+ [CLSCompliant(false)]
+ public struct McgCCWFactoryInfoEntry
+ {
+ public FixupRuntimeTypeHandle FixupFactoryType;
+ public RuntimeTypeHandle FactoryType
+ {
+ get
+ {
+ return FixupFactoryType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupFactoryType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+ }
+
+ /// <summary>
+ /// A wrapper for CCWTemplateData
+ /// </summary>
+ [CLSCompliant(false)]
+ public struct CCWTemplateInfo
+ {
+ int m_ModuleIndex;
+ int m_Index; // offset in m_CCWTemplateData[]
+
+ static CCWTemplateInfo s_CCWTemplateInfoNull = new CCWTemplateInfo(-1, -1);
+#if DEBUG
+ CCWTemplateData m_CCWTemplateData_DebugOnly;
+#endif
+ public CCWTemplateInfo(McgModule mcgModule, int ccwTemplateDataIndex)
+ {
+ m_ModuleIndex = McgModuleManager.GetModuleIndex(mcgModule);
+ m_Index = ccwTemplateDataIndex;
+#if DEBUG
+ m_CCWTemplateData_DebugOnly = mcgModule.CCWTemplateData[m_Index];
+#endif
+ }
+
+ private CCWTemplateInfo(int moduleIndex, int ccwTemplateDataIndex)
+ {
+ m_ModuleIndex = moduleIndex;
+ m_Index = ccwTemplateDataIndex;
+#if DEBUG
+ m_CCWTemplateData_DebugOnly = default(CCWTemplateData);
+#endif
+ }
+
+ public McgModule ContainingModule
+ {
+ get
+ {
+ return McgModuleManager.GetModule(m_ModuleIndex);
+ }
+ }
+
+ public int Index
+ {
+ get
+ {
+ return m_Index;
+ }
+ }
+
+ private CCWTemplateData CCWTemplateData
+ {
+ get
+ {
+ Debug.Assert(m_Index >= 0 && m_Index < ContainingModule.CCWTemplateData.Length);
+ return ContainingModule.CCWTemplateData[m_Index];
+ }
+ }
+
+ public RuntimeTypeHandle BaseType
+ {
+ get
+ {
+ int parentIndex = CCWTemplateData.ParentCCWTemplateIndex;
+ if (parentIndex >=0)
+ {
+ return ContainingModule.CCWTemplateData[parentIndex].ClassType;
+ }
+ else if(!CCWTemplateData.BaseType.Equals(default(RuntimeTypeHandle)))
+ {
+ return CCWTemplateData.BaseType;
+ }
+ return default(RuntimeTypeHandle);
+ }
+ }
+
+ /// <summary>
+ /// Whether this is NULL
+ /// </summary>
+ public bool IsNull
+ {
+ get
+ {
+ return m_ModuleIndex == Null.m_ModuleIndex && m_Index == Null.m_Index;
+ }
+ }
+
+ public static CCWTemplateInfo Null
+ {
+ get
+ {
+ return s_CCWTemplateInfoNull;
+ }
+ }
+
+ public bool Equals(CCWTemplateInfo classInfo)
+ {
+ if (IsNull && classInfo.IsNull)
+ return true;
+ if (IsNull || classInfo.IsNull)
+ return false;
+
+ return m_ModuleIndex == classInfo.m_ModuleIndex && m_Index == classInfo.m_Index;
+ }
+
+ public override int GetHashCode()
+ {
+ return CCWTemplateData.GetHashCode();
+ }
+ }
+
+ /// <summary>
+ /// Static per-type CCW information
+ /// </summary>
+ [CLSCompliant(false)]
+ public struct CCWTemplateData
+ {
+ /// <summary>
+ /// RuntimeTypeHandle of the class that this CCWTemplateData is for
+ /// </summary>
+ public FixupRuntimeTypeHandle FixupClassType;
+ public RuntimeTypeHandle ClassType
+ {
+ get
+ {
+ return FixupClassType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupClassType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+
+ /// <summary>
+ /// The type handle for its base class (that is also a managed type)
+ ///
+ /// There are two ways to access base class: RuntimeTypeHandle or Index
+ /// Ideally we want to use typehandle for everything - but DR throws it away and breaks the inheritance chain
+ /// - therefore we would only use index for "same module" and type handle for "cross module"
+ ///
+ /// Code Pattern:
+ /// if (ParentCCWTemplateIndex >=0) { // same module }
+ /// else if(!BaseClassType.Equals(default(RuntimeTypeHandle)) { // cross module}
+ /// else { // it doesn't have base}
+ /// </summary>
+ public FixupRuntimeTypeHandle FixupBaseType;
+ public RuntimeTypeHandle BaseType
+ {
+ get
+ {
+ return FixupBaseType.RuntimeTypeHandle;
+ }
+ set
+ {
+ FixupBaseType = new FixupRuntimeTypeHandle(value);
+ }
+ }
+
+ /// <summary>
+ /// The index of the CCWTemplateData for its base class (that is also a managed type)
+ /// < 0 if does not exist or there are multiple module involved(use its BaseType property instead)
+ /// </summary>
+ public int ParentCCWTemplateIndex;
+
+ /// <summary>
+ /// The beginning index of list of supported interface
+ /// NOTE: The list for this specific type only, excluding base classes
+ /// </summary>
+ public int SupportedInterfaceListBeginIndex;
+
+ /// <summary>
+ /// The total number of supported interface
+ /// NOTE: The list for this specific type only, excluding base classes
+ /// </summary>
+ public int NumberOfSupportedInterface;
+
+ /// <summary>
+ /// Whether this CCWTemplateData belongs to a WinRT type
+ /// Typically this only happens when we import a managed class that implements a WinRT type and
+ /// we'll import the base WinRT type as CCW template too, as a way to capture interfaces in the class
+ /// hierarchy and also know which are the ones implemented by managed class
+ /// </summary>
+ public bool IsWinRTType;
+ }
+
+ /// <summary>
+ /// Extra type/marshalling information for a given type used in MCG. You can think this as a more
+ /// complete version of System.Type. This struct is merely a container for a pointer to (unmovable) McgInterfaceData.
+ /// </summary>
+ [CLSCompliant(false)]
+ public unsafe struct McgTypeInfo
+ {
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "m_TypeIndex" and field type: int
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::WalkTypeInfo in debug\dbi\values.cpp
+ /// </summary>
+ int m_TypeIndex;
+
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "m_ModuleIndex" and field type: int
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::WalkTypeInfo in debug\dbi\values.cpp
+ /// </summary>
+ int m_ModuleIndex;
+
+ // default value(or null value) for McgTypeInfo
+ static McgTypeInfo s_McgTypeInfoNull = new McgTypeInfo(-1, -1);
+
+#if DEBUG
+ McgInterfaceData m_InterfaceData_DebugOnly;
+#endif
+
+ internal McgInterfaceData InterfaceData
+ {
+ get
+ {
+ return ContainingModule.GetInterfaceDataByIndex(m_TypeIndex);
+ }
+ }
+
+ /// <summary>
+ /// Constructor
+ /// </summary>
+ public McgTypeInfo(int index, McgModule mcgModule)
+ {
+ m_TypeIndex = index;
+ m_ModuleIndex = McgModuleManager.GetModuleIndex(mcgModule);
+#if DEBUG
+ m_InterfaceData_DebugOnly = mcgModule.GetInterfaceDataByIndex(m_TypeIndex);
+#endif
+ }
+
+ private McgTypeInfo(int typeIndex, int moduleIndex)
+ {
+ m_TypeIndex = typeIndex;
+ m_ModuleIndex = moduleIndex;
+#if DEBUG
+ m_InterfaceData_DebugOnly = default(McgInterfaceData);
+#endif
+ }
+
+ public McgModule ContainingModule
+ {
+ get
+ {
+ return McgModuleManager.GetModule(m_ModuleIndex);
+ }
+ }
+
+ /// <summary>
+ /// Whether this is NULL
+ /// </summary>
+ public bool IsNull
+ {
+ get
+ {
+ return m_ModuleIndex == Null.m_ModuleIndex && m_TypeIndex == Null.m_TypeIndex;
+ }
+ }
+
+ public static McgTypeInfo Null
+ {
+ get
+ {
+ return s_McgTypeInfoNull;
+ }
+ }
+
+ /// <summary>
+ /// Whether this type is a IInspectable type
+ /// </summary>
+ public bool IsIInspectable
+ {
+ get
+ {
+ return (InterfaceData.Flags & McgInterfaceFlags.isIInspectable) != McgInterfaceFlags.None;
+ }
+ }
+
+ /// <summary>
+ /// WinRT interface or WinRT delegate
+ /// </summary>
+ internal bool IsIInspectableOrDelegate
+ {
+ get
+ {
+ return (InterfaceData.Flags & (McgInterfaceFlags.isIInspectable | McgInterfaceFlags.isDelegate)) != McgInterfaceFlags.None;
+ }
+ }
+
+ internal bool IsInternalModule
+ {
+ get
+ {
+ return (InterfaceData.Flags & McgInterfaceFlags.isInternal) != McgInterfaceFlags.None;
+ }
+ }
+
+ /// <summary>
+ /// The guid of this type
+ /// </summary>
+ public Guid ItfGuid
+ {
+ get
+ {
+ return InterfaceData.ItfGuid;
+ }
+ }
+
+ public RuntimeTypeHandle ItfType
+ {
+ get
+ {
+ return InterfaceData.ItfType;
+ }
+ }
+
+ public McgInterfaceFlags Flags
+ {
+ get
+ {
+ return InterfaceData.Flags;
+ }
+ }
+
+ public short MarshalIndex
+ {
+ get
+ {
+ return InterfaceData.MarshalIndex;
+ }
+ }
+
+ static IntPtr[] SharedCCWList = new IntPtr[] {
+#if ENABLE_WINRT
+ SharedCcw_IVector.GetVtable(),
+ SharedCcw_IVectorView.GetVtable(),
+ SharedCcw_IIterable.GetVtable(),
+ SharedCcw_IIterator.GetVtable(),
+
+#if RHTESTCL || CORECLR
+ default(IntPtr),
+#else
+ SharedCcw_AsyncOperationCompletedHandler.GetVtable(),
+#endif
+ SharedCcw_IVector_Blittable.GetVtable(),
+ SharedCcw_IVectorView_Blittable.GetVtable(),
+
+#if RHTESTCL || CORECLR
+ default(IntPtr)
+#else
+ SharedCcw_IIterator_Blittable.GetVtable()
+#endif
+#endif //ENABLE_WINRT
+ };
+
+ internal unsafe IntPtr CcwVtable
+ {
+ get
+ {
+ McgInterfaceFlags flag = InterfaceData.Flags & McgInterfaceFlags.SharedCCWMask;
+
+ if (flag != 0)
+ {
+ return SharedCCWList[(int)flag >> 4];
+ }
+
+ return CalliIntrinsics.Call__GetCcwVtable(InterfaceData.CcwVtable);
+ }
+ set
+ {
+ ContainingModule.SetCCW(m_TypeIndex, value);
+ }
+ }
+
+ /// <summary>
+ /// Returns the corresponding interface type for this type
+ /// </summary>
+ internal RuntimeTypeHandle InterfaceType
+ {
+ get
+ {
+ return InterfaceData.ItfType;
+ }
+ }
+
+ /// <summary>
+ /// Returns the corresponding dispatch class type for this type
+ /// </summary>
+ internal RuntimeTypeHandle DispatchClassType
+ {
+ get
+ {
+ return InterfaceData.DispatchClassType;
+ }
+ }
+
+ internal RuntimeTypeHandle DynamicAdapterClassType
+ {
+ get
+ {
+ return InterfaceData.DynamicAdapterClassType;
+ }
+ }
+
+ internal bool HasDynamicAdapterClass
+ {
+ get { return !DynamicAdapterClassType.IsNull(); }
+ }
+
+ internal bool IsSupportedBy(object target)
+ {
+ if ((InterfaceData.Flags & McgInterfaceFlags.isDelegate) != McgInterfaceFlags.None)
+ {
+ // winRT delegates store the managed delegate type in the type table's ItfType field.
+ return InteropExtensions.IsInstanceOfClass(target, InterfaceData.ItfType);
+ }
+ else
+ {
+ // WARNING: We cannot pass any RuntimeTypeHandles here that are NOT interface types.
+ return InteropExtensions.IsInstanceOfInterface(target, InterfaceData.ItfType);
+ }
+ }
+
+ public static bool operator ==(McgTypeInfo left, McgTypeInfo right)
+ {
+ return left.m_TypeIndex == right.m_TypeIndex && left.m_ModuleIndex == right.m_ModuleIndex;
+ }
+
+ public static bool operator !=(McgTypeInfo left, McgTypeInfo right)
+ {
+ return left.m_TypeIndex != right.m_TypeIndex || left.m_ModuleIndex != right.m_ModuleIndex;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if ((obj == null) && this.IsNull)
+ return true;
+
+ if (!(obj is McgTypeInfo))
+ return false;
+
+ return (this == ((McgTypeInfo)obj));
+ }
+
+ public override int GetHashCode()
+ {
+ return InterfaceData.GetHashCode();
+ }
+ }
+
+ /// <summary>
+ /// Extra information for all the class types encoded by MCG
+ /// </summary>
+ [CLSCompliant(false)]
+ public unsafe struct McgClassInfo
+ {
+ int m_ClassDataIndex;
+ int m_ModuleIndex;
+
+#if DEBUG
+ McgClassData m_ClassData_DebugOnly;
+#endif
+ static McgClassInfo s_McgClassInfoNull = new McgClassInfo(-1, -1);
+
+ public McgClassInfo(int classDataIndex, McgModule mcgModule)
+ {
+ m_ClassDataIndex = classDataIndex;
+ m_ModuleIndex = McgModuleManager.GetModuleIndex(mcgModule);
+#if DEBUG
+ m_ClassData_DebugOnly = mcgModule.GetClassDataByIndex(m_ClassDataIndex);
+#endif
+ }
+
+ private McgClassInfo(int classDataIndex, int moduleIndex)
+ {
+ m_ClassDataIndex = classDataIndex;
+ m_ModuleIndex = moduleIndex;
+#if DEBUG
+ m_ClassData_DebugOnly = default(McgClassData);
+#endif
+ }
+
+ McgModule ContainingModule
+ {
+ get
+ {
+ return McgModuleManager.GetModule(m_ModuleIndex);
+ }
+ }
+
+ private McgClassData ClassData
+ {
+ get
+ {
+ return ContainingModule.GetClassDataByIndex(m_ClassDataIndex);
+ }
+ }
+
+ // Check whether the McgClassInfo is Null
+ public bool IsNull
+ {
+ get
+ {
+ return m_ModuleIndex == Null.m_ModuleIndex && m_ClassDataIndex == Null.m_ClassDataIndex;
+ }
+ }
+
+ public static McgClassInfo Null
+ {
+ get
+ {
+ return s_McgClassInfoNull;
+ }
+ }
+
+ internal RuntimeTypeHandle ClassType
+ {
+ get
+ {
+ return ClassData.ClassType;
+ }
+ }
+
+ internal RuntimeTypeHandle BaseClassType
+ {
+ get
+ {
+ int baseClassIndex = ClassData.BaseClassIndex;
+ if (baseClassIndex >= 0)
+ {
+ return ContainingModule.GetClassDataByIndex(baseClassIndex).ClassType;
+ }
+ else if (!ClassData.BaseClassType.Equals(default(RuntimeTypeHandle)))
+ {
+ return ClassData.BaseClassType;
+ }
+ // doesn't have base class
+ return default(RuntimeTypeHandle);
+ }
+ }
+
+ internal RuntimeTypeHandle DefaultInterface
+ {
+ get
+ {
+ int defaultInterfaceIndex = ClassData.DefaultInterfaceIndex;
+ if (defaultInterfaceIndex >= 0)
+ {
+ return ContainingModule.GetInterfaceDataByIndex(defaultInterfaceIndex).ItfType;
+ }
+ else
+ {
+ return ClassData.DefaultInterfaceType;
+ }
+ }
+ }
+
+ internal bool Equals(McgClassInfo classInfo)
+ {
+ if (IsNull && classInfo.IsNull)
+ return true;
+
+ if (IsNull || classInfo.IsNull)
+ return false;
+
+ return m_ClassDataIndex == classInfo.m_ClassDataIndex && m_ModuleIndex == classInfo.m_ModuleIndex;
+ }
+
+ internal bool IsSealed
+ {
+ get
+ {
+ return ((ClassData.Flags & McgClassFlags.IsSealed) != 0);
+ }
+ }
+
+ internal bool IsWinRT
+ {
+ get
+ {
+ return ((ClassData.Flags & McgClassFlags.IsWinRT) != 0);
+ }
+ }
+
+ internal ComMarshalingType MarshalingType
+ {
+ get
+ {
+ switch (ClassData.Flags & McgClassFlags.MarshalingBehavior_Mask)
+ {
+ case McgClassFlags.MarshalingBehavior_Inhibit:
+ return ComMarshalingType.Inhibit;
+
+ case McgClassFlags.MarshalingBehavior_Free:
+ return ComMarshalingType.Free;
+
+ case McgClassFlags.MarshalingBehavior_Standard:
+ return ComMarshalingType.Standard;
+
+ default:
+ return ComMarshalingType.Unknown;
+ }
+ }
+ }
+
+ internal GCPressureRange GCPressureRange
+ {
+ get
+ {
+ switch (ClassData.Flags & McgClassFlags.GCPressureRange_Mask)
+ {
+ case McgClassFlags.GCPressureRange_WinRT_Default:
+ return GCPressureRange.WinRT_Default;
+
+ case McgClassFlags.GCPressureRange_WinRT_Low:
+ return GCPressureRange.WinRT_Low;
+
+ case McgClassFlags.GCPressureRange_WinRT_Medium:
+ return GCPressureRange.WinRT_Medium;
+
+ case McgClassFlags.GCPressureRange_WinRT_High:
+ return GCPressureRange.WinRT_High;
+
+ default:
+ return GCPressureRange.None;
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgGeneratedAssemblyAttribute.cs b/src/System.Private.Interop/src/Shared/McgGeneratedAssemblyAttribute.cs
new file mode 100644
index 000000000..acbb61df0
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgGeneratedAssemblyAttribute.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;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Indicate that this assembly is generated by MCG
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
+ public sealed class McgGeneratedAssemblyAttribute : Attribute
+ {
+ public McgGeneratedAssemblyAttribute()
+ {
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgGeneratedMarshallingCodeAttribute.cs b/src/System.Private.Interop/src/Shared/McgGeneratedMarshallingCodeAttribute.cs
new file mode 100644
index 000000000..5da54821f
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgGeneratedMarshallingCodeAttribute.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// The McgGeneratedMarshallingCodeAttribute is applied to methods generated by
+ /// MCG for interop marshalling.
+ /// </summary>
+ [AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Constructor)]
+ public class McgGeneratedMarshallingCodeAttribute : Attribute
+ {
+ //
+ // Note: VS Debugger looks for this attribute by fullname "System.Runtime.InteropServices.McgGeneratedMarshallingCodeAttribute"
+ // when stepping through MCG generated interop methods.
+ // Make sure to update the logic in VS debugger too if you ever update the name of this attribute.
+ //
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgGeneratedNativeCallCodeAttribute.cs b/src/System.Private.Interop/src/Shared/McgGeneratedNativeCallCodeAttribute.cs
new file mode 100644
index 000000000..4db0ce8d9
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgGeneratedNativeCallCodeAttribute.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;
+
+/// <summary>
+/// This is used to mark our Interop APIs as generated by MCG so that MCG can skip them
+/// Ideally we should be able to ignore them when they are blittable but we still would emit the structs &
+/// enums today and I'd like to avoid that.
+/// </summary>
+[System.AttributeUsageAttribute(System.AttributeTargets.Method)]
+internal class McgGeneratedNativeCallCodeAttribute : System.Attribute
+{
+}
diff --git a/src/System.Private.Interop/src/Shared/McgHelpers.cs b/src/System.Private.Interop/src/Shared/McgHelpers.cs
new file mode 100644
index 000000000..4888efaea
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgHelpers.cs
@@ -0,0 +1,1739 @@
+// 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.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices.WindowsRuntime;
+
+namespace System.Runtime.InteropServices
+{
+#if ENABLE_WINRT
+ // Shared CCW Design (fyuan, 6/26/2013)
+
+ // Normal CCW is implemented by constructing a native virtual function table with specific functions for each interface using MCG generated code.
+ // For each CCW interface, there is a native class e.g. internal unsafe partial struct __vtable_Windows_ApplicationModel_Resources_Core__IResourceContext
+ // Static field s_theCcwVtable constructs the virtual function table, whose address is stored in McgInterfaceData.CcwVtable field.
+ // Each function within vtable is marked as [NativeCallable]. It has marsalling code and exception handling to set COM HRESULT.
+
+ // During runtime __interface_ccw.Allocate allocates a small piece of native memory and constructs the real CCW callable by native code
+
+ // Shared CCW is supported on generic interfaces, sharable across multiple instances of supported interfaces.
+ // For example SharedCcw_IVector supports all IVector<T> CCW where T is a reference type using a single copy of code.
+ // But to support individual element types, we need extra information about each element type and a thunk function to call real methods on interface instantiations.
+
+ // Information about element type is encoded in McgGenericArgumentMarshalInfo struct per element type. McgInterfaceData has an added index MarshalIndex indexing into the table.
+ // When constructing __inteface_ccw, an extra field m_pInterface is added to point back to McgInterfaceData, from which we can get McgGenericArgumentMarshalInfo.
+
+ // Each CCW interface supported by shared CCW has a thunk function which is normally an instance of a generic function. The function is set use the SetThunk function generated by MCG
+
+ // From a native CCW pointer, ComCallableObject.GetThunk functions returns target object, marshal index, and thunk function.
+ // Shared CCW code can use marshal index to marshal objects between native and managed worlds, and use thunk function to invoke functions on corresponding managed code.
+ // It also handles semantics of wrapper classes like ListToVectorAdapter for argument checking and exception -> HRESULT translation
+
+ // Here is a example:
+ // 1) SharedCCW_IVector supports IVector<T> where T is reference type
+ // 2) Its thunk function is int IListThunk<T>(IList<T> list, IList_Oper oper, int index, ref object item).
+ // 3) Thunk function handles 9 basic operations on IList<T>: GetCount, GetItem, IndexOf, SetItem, Insert, RemoveAt, Add, Clear, and ToReadOnly
+ // 4) Functions in SharedCCW_IVector handles [NativeCallable] protocol, getting thunk information, marshalling, invoking thunk function, and exception handling.
+ // 5) For a particular element type, say string, IListThunk<string> dispatches to basic operations on IList<string>.
+ // 6) Due to generic code sharing, there is a real implementation of IListThunk<Canon> and IListThunk<string> just calls it with the right 'Generic Dictionary'
+
+ /* Code generated by MCG for 4 shared CCW instances: IEnumerable<string> (IIterable), IIterator<T>, IList<T>(IVector), and IReadOnlyList<T>(IVectorView)
+
+ SetThunk(35, AddrOfIntrinsics.AddrOf(Toolbox.IEnumerableThunk<string>));
+ SetThunk(36, AddrOfIntrinsics.AddrOf(Toolbox.IIteratorThunk<string>));
+ SetThunk(69, AddrOfIntrinsics.AddrOf(System.Runtime.InteropServices.Toolbox.IListThunk<string>));
+ SetThunk(70, AddrOfIntrinsics.AddrOf(System.Runtime.InteropServices.Toolbox.IReadOnlyListThunk<string>));
+
+ new McgGenericArgumentMarshalInfo() { // index: 2, 'string' => 'HSTRING $'
+ ElementClassIndex = -1,
+ ElementInterfaceIndex = s_McgTypeInfoIndex___com_HSTRING,
+ VectorViewIndex = s_McgTypeInfoIndex___com_Windows_Foundation_Collections__IVectorView_A_string_V_,
+ IteratorIndex = s_McgTypeInfoIndex___com_Windows_Foundation_Collections__IIterator_A_string_V_, },
+
+ new McgInterfaceData() { ... // index: 35, System.Collections.Generic.IEnumerable<string>
+ MarshalIndex = 2,
+ Flags = McgInterfaceFlags.isIInspectable | McgInterfaceFlags.useSharedCCW_IIterable, },
+
+ new McgInterfaceData() { ... // index: 36, Windows.Foundation.Collections.IIterator<string>
+ MarshalIndex = 2,
+ Flags = McgInterfaceFlags.isIInspectable | McgInterfaceFlags.useSharedCCW_IIterator, },
+
+ new McgInterfaceData() { ... // index: 69, System.Collections.Generic.IList<string>
+ MarshalIndex = 2,
+ Flags = McgInterfaceFlags.isIInspectable | McgInterfaceFlags.useSharedCCW_IVector, },
+
+ new McgInterfaceData() { ... // index: 70, System.Collections.Generic.IReadOnlyList<string>
+ MarshalIndex = 2,
+ Flags = McgInterfaceFlags.isIInspectable | McgInterfaceFlags.useSharedCCW_IVectorView, },
+ */
+
+ public static partial class Toolbox
+ {
+ // Basic operations on IList/IReadOnlyList to support IVector/IVectorView
+ public enum IList_Oper
+ {
+ GetCount,
+ GetItem,
+ IndexOf,
+
+ SetItem,
+ Insert,
+ RemoveAt,
+ Add,
+ Clear,
+ ToReadOnly
+ };
+
+ /// <summary>
+ /// Static thunk function for calling methods on IList<T>
+ /// </summary>
+ public static int IListThunk<T>(IList<T> list, IList_Oper oper, int index, ref object item) where T : class
+ {
+ int result = 0;
+
+ switch (oper)
+ {
+ case IList_Oper.GetCount:
+ result = list.Count;
+ break;
+
+ case IList_Oper.GetItem:
+ item = list[index];
+ break;
+
+ case IList_Oper.IndexOf:
+ result = list.IndexOf(InteropExtensions.UncheckedCast<T>(item));
+ break;
+
+ case IList_Oper.SetItem:
+ list[index] = InteropExtensions.UncheckedCast<T>(item);
+ break;
+
+ case IList_Oper.Insert:
+ list.Insert(index, InteropExtensions.UncheckedCast<T>(item));
+ break;
+
+ case IList_Oper.RemoveAt:
+ list.RemoveAt(index);
+ break;
+
+ case IList_Oper.Add:
+ list.Add(InteropExtensions.UncheckedCast<T>(item));
+ break;
+
+ case IList_Oper.Clear:
+ list.Clear();
+ break;
+
+ case IList_Oper.ToReadOnly:
+ {
+ IReadOnlyList<T> view;
+
+ // 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.
+ view = list as IReadOnlyList<T>;
+
+ if (view == null)
+ {
+ view = new System.Collections.ObjectModel.ReadOnlyCollection<T>(list);
+ }
+
+ item = view; // return via item
+ }
+ break;
+
+ default:
+ Debug.Assert(false, "IListThunk wrong oper");
+ break;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Static thunk function for calling methods on IList<T>
+ /// </summary>
+ public static object IListBlittableThunk<T>(IList<T> list, IList_Oper oper, ref int index, ref T item) where T : struct
+ {
+ object result = null;
+
+ switch (oper)
+ {
+ case IList_Oper.GetCount:
+ index = list.Count;
+ break;
+
+ case IList_Oper.GetItem:
+ item = list[index];
+ break;
+
+ case IList_Oper.IndexOf:
+ index = list.IndexOf(item);
+ break;
+
+ case IList_Oper.SetItem:
+ list[index] = item;
+ break;
+
+ case IList_Oper.Insert:
+ list.Insert(index, item);
+ break;
+
+ case IList_Oper.RemoveAt:
+ list.RemoveAt(index);
+ break;
+
+ case IList_Oper.Add:
+ list.Add(item);
+ break;
+
+ case IList_Oper.Clear:
+ list.Clear();
+ break;
+
+ case IList_Oper.ToReadOnly:
+ {
+ // 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.
+ result = list as IReadOnlyList<T>;
+
+ if (result == null)
+ {
+ result = new System.Collections.ObjectModel.ReadOnlyCollection<T>(list);
+ }
+ }
+ break;
+
+ default:
+ Debug.Assert(false, "IListBlittableThunk wrong oper");
+ break;
+ }
+
+ return result;
+ }
+
+ internal static bool EnsureIndexInt32(uint index, uint listCapacity, ref int hr)
+ {
+ // We use '<=' and not '<' becasue Int32.MaxValue == index would imply
+ // that Size > Int32.MaxValue:
+ if (((uint)System.Int32.MaxValue) <= index || index >= listCapacity)
+ {
+ hr = Interop.COM.E_BOUNDS;
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Static thunk function for calling methods on IReadOnlyList<T>
+ /// </summary>
+ public static int IReadOnlyListThunk<T>(IReadOnlyList<T> list, IList_Oper oper, int index, ref T item) where T : class
+ {
+ int result = 0;
+
+ switch (oper)
+ {
+ case IList_Oper.GetCount:
+ result = list.Count;
+ break;
+
+ case IList_Oper.GetItem:
+ item = list[index];
+ break;
+
+ case IList_Oper.IndexOf:
+ {
+ result = -1;
+
+ index = list.Count;
+
+ for (int i = 0; i < index; i++)
+ {
+ if (InteropExtensions.ComparerEquals<T>(item, list[i]))
+ {
+ result = i;
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ Debug.Assert(false, "IReadOnlyListThunk wrong oper");
+ break;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Static thunk function for calling methods on IReadOnlyList<T>
+ /// </summary>
+ public static object IReadOnlyListBlittableThunk<T>(IReadOnlyList<T> list, IList_Oper oper, ref int index, ref T item) where T : struct
+ {
+ object result = null;
+
+ switch (oper)
+ {
+ case IList_Oper.GetCount:
+ index = list.Count;
+ break;
+
+ case IList_Oper.GetItem:
+ item = list[index];
+ break;
+
+ case IList_Oper.IndexOf:
+ {
+ index = -1;
+
+ int count = list.Count;
+
+ for (int i = 0; i < count; i++)
+ {
+ if (InteropExtensions.ComparerEquals<T>(item, list[i]))
+ {
+ index = i;
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ Debug.Assert(false, "IReadOnlyListThunk wrong oper");
+ break;
+ }
+
+ return result;
+ }
+ }
+
+
+ /// <summary>
+ /// Shared CCW for IVector<T> over IList<T> where T is a reference type marshalled to COM interface
+ /// </summary>
+ internal unsafe struct SharedCcw_IVector
+ {
+ public System.IntPtr pfnQueryInterface;
+ public System.IntPtr pfnAddRef;
+ public System.IntPtr pfnRelease;
+ public System.IntPtr pfnGetIids;
+ public System.IntPtr pfnGetRuntimeClassName;
+ public System.IntPtr pfnGetTrustLevel;
+
+ public System.IntPtr pfnGetAt;
+ public System.IntPtr pfnget_Size;
+ public System.IntPtr pfnGetView;
+ public System.IntPtr pfnIndexOf;
+ public System.IntPtr pfnSetAt;
+ public System.IntPtr pfnInsertAt;
+ public System.IntPtr pfnRemoveAt;
+ public System.IntPtr pfnAppend;
+ public System.IntPtr pfnRemoveAtEnd;
+ public System.IntPtr pfnClear;
+ public System.IntPtr pfnGetMany;
+ public System.IntPtr pfnReplaceAll;
+
+ [PreInitialized]
+ static SharedCcw_IVector s_theCcwVtable = new SharedCcw_IVector()
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+
+ pfnGetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(GetAt),
+ pfnget_Size = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_Size),
+ pfnGetView = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(GetView),
+ pfnIndexOf = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIndexOf>(IndexOf),
+ pfnSetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(SetAt),
+ pfnInsertAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(InsertAt),
+ pfnRemoveAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfRemoveAt>(RemoveAt),
+ pfnAppend = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(Append),
+ pfnRemoveAtEnd = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(RemoveAtEnd),
+ pfnClear = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(Clear),
+ pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany1>(GetMany),
+ pfnReplaceAll = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(ReplaceAll),
+ };
+
+ public static System.IntPtr GetVtable()
+ {
+ return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
+ }
+
+ [NativeCallable]
+ internal unsafe static int GetAt(IntPtr pComThis, uint index, IntPtr pItem)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object item = null;
+
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetItem, (int)index, ref item);
+
+ *((IntPtr*)pItem) = module.ObjectToComInterface(item, marshalIndex);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ if (hrExcep is ArgumentOutOfRangeException)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ internal unsafe static int get_Size(System.IntPtr pComThis, System.IntPtr pSize)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object dummy = null;
+
+ *((uint*)pSize) = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref dummy);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ unsafe static int GetView(System.IntPtr pComThis, System.IntPtr pView)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object view = null;
+
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.ToReadOnly, 0, ref view);
+
+ *((IntPtr*)pView) = module.MarshalToVectorView(view, marshalIndex);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ internal unsafe static int IndexOf(System.IntPtr pComThis, System.IntPtr _value, System.IntPtr pIndex, System.IntPtr pFound)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object value = module.MarshalToObject(_value, marshalIndex);
+
+ int index = CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.IndexOf, 0, ref value);
+
+ if (index >= 0)
+ {
+ *((byte*)pFound) = 1;
+ }
+ else
+ {
+ *((byte*)pFound) = 0;
+
+ index = 0;
+ }
+
+ *((int*)pIndex) = index;
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ unsafe static int SetAt(System.IntPtr pComThis, uint index, IntPtr _value)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object value = null;
+
+ uint listCount = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref value);
+
+ if (Toolbox.EnsureIndexInt32(index, listCount, ref hr))
+ {
+ value = module.MarshalToObject(_value, marshalIndex);
+
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.SetItem, (int)index, ref value);
+ }
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ if (hrExcep is ArgumentOutOfRangeException)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ unsafe static int InsertAt(System.IntPtr pComThis, uint index, IntPtr _value)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object value = null;
+
+ uint listCount = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref value);
+
+ // 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).
+ if (Toolbox.EnsureIndexInt32(index, listCount + 1, ref hr))
+ {
+ value = module.MarshalToObject(_value, marshalIndex);
+
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.Insert, (int)index, ref value);
+ }
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ if (hrExcep is ArgumentOutOfRangeException)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ unsafe static int RemoveAt(System.IntPtr pComThis, uint index)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object dummy = null;
+
+ uint listCount = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref dummy);
+
+ if (Toolbox.EnsureIndexInt32(index, listCount, ref hr))
+ {
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.RemoveAt, (int)index, ref dummy);
+ }
+ }
+
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ if (hrExcep is ArgumentOutOfRangeException)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ unsafe static int Append(System.IntPtr pComThis, IntPtr _value)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object value = module.MarshalToObject(_value, marshalIndex);
+
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.Add, 0, ref value);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ unsafe static int RemoveAtEnd(System.IntPtr pComThis)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object dummy = null;
+
+ uint listCount = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref dummy);
+
+ if (listCount == 0)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ else
+ {
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.RemoveAt, (int)(listCount - 1), ref dummy);
+ }
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ if (hrExcep is ArgumentOutOfRangeException)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ unsafe static int Clear(System.IntPtr pComThis)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module ,out thunk);
+
+ object dummy = null;
+
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.Clear, 0, ref dummy);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ internal unsafe static int GetMany(System.IntPtr pComThis, uint startIndex, uint len, System.IntPtr pDest, System.IntPtr pCount)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object value = null;
+
+ uint listCount = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref value);
+
+ uint itemCount = 0;
+
+ if ((startIndex != listCount) && Toolbox.EnsureIndexInt32(startIndex, listCount, ref hr))
+ {
+ itemCount = System.Math.Min(len, listCount - startIndex);
+
+ System.IntPtr* dst = (System.IntPtr*)pDest;
+
+ // Convert to COM interfaces, without allocating array
+ uint i = 0;
+
+ while (i < itemCount)
+ {
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetItem, (int)(i + startIndex), ref value);
+
+ dst[i] = module.ObjectToComInterface(value, marshalIndex);
+
+ i++;
+ }
+
+ // Fill the remaining with default value
+ while (i < len)
+ {
+ dst[i++] = default(IntPtr);
+ }
+ }
+
+ *((uint*)pCount) = itemCount;
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ unsafe static int ReplaceAll(System.IntPtr pComThis, uint length, IntPtr pItems)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ System.IntPtr* src = (System.IntPtr*)pItems;
+
+ object value = null;
+
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.Clear, 0, ref value);
+
+ for (uint i = 0; i < length; i++)
+ {
+ value = module.MarshalToObject(src[i], marshalIndex);
+
+ CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.Add, 0, ref value);
+ }
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+ }
+
+ /// <summary>
+ /// Shared CCW for IVector<T> over IList<T> where T is a blittable struct
+ /// </summary>
+ internal unsafe struct SharedCcw_IVector_Blittable
+ {
+ public System.IntPtr pfnQueryInterface;
+ public System.IntPtr pfnAddRef;
+ public System.IntPtr pfnRelease;
+ public System.IntPtr pfnGetIids;
+ public System.IntPtr pfnGetRuntimeClassName;
+ public System.IntPtr pfnGetTrustLevel;
+
+ public System.IntPtr pfnGetAt;
+ public System.IntPtr pfnget_Size;
+ public System.IntPtr pfnGetView;
+ public System.IntPtr pfnIndexOf;
+ public System.IntPtr pfnSetAt;
+ public System.IntPtr pfnInsertAt;
+ public System.IntPtr pfnRemoveAt;
+ public System.IntPtr pfnAppend;
+ public System.IntPtr pfnRemoveAtEnd;
+ public System.IntPtr pfnClear;
+ public System.IntPtr pfnGetMany;
+ public System.IntPtr pfnReplaceAll;
+
+ [PreInitialized]
+ static SharedCcw_IVector_Blittable s_theCcwVtable = new SharedCcw_IVector_Blittable()
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+
+ pfnGetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(GetAt),
+ pfnget_Size = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_Size),
+ pfnGetView = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(GetView),
+ pfnIndexOf = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIndexOf>(IndexOf),
+ pfnSetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(SetAt),
+ pfnInsertAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(InsertAt),
+ pfnRemoveAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfRemoveAt>(RemoveAt),
+ pfnAppend = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(Append),
+ pfnRemoveAtEnd = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(RemoveAtEnd),
+ pfnClear = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(Clear),
+ pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany1>(GetMany),
+ pfnReplaceAll = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(ReplaceAll),
+ };
+
+ public static System.IntPtr GetVtable()
+ {
+ return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
+ }
+
+ [NativeCallable]
+ internal unsafe static int GetAt(IntPtr pComThis, uint _index, IntPtr pItem)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int index = (int)_index;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.GetItem, ref index, pItem);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ if (hrExcep is ArgumentOutOfRangeException)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ internal unsafe static int get_Size(System.IntPtr pComThis, System.IntPtr pSize)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int size = 0;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.GetCount, ref size, default(IntPtr));
+
+ *((uint*)pSize) = (uint)size;
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ unsafe static int GetView(System.IntPtr pComThis, System.IntPtr pView)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int dummy = 0;
+
+ object view = CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.ToReadOnly, ref dummy, default(IntPtr));
+
+ *((IntPtr*)pView) = module.MarshalToVectorView(view, marshalIndex);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ internal unsafe static int IndexOf(System.IntPtr pComThis, System.IntPtr _value, System.IntPtr pIndex, System.IntPtr pFound)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int index = 0;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.IndexOf, ref index, (IntPtr)(&_value));
+
+ if (index >= 0)
+ {
+ *((byte*)pFound) = 1;
+ }
+ else
+ {
+ *((byte*)pFound) = 0;
+
+ index = 0;
+ }
+
+ *((int*)pIndex) = index;
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ unsafe static int SetAt(System.IntPtr pComThis, uint _index, IntPtr _value)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int index = (int)_index;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.SetItem, ref index, (IntPtr)(&_value));
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ if (hrExcep is ArgumentOutOfRangeException)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ unsafe static int InsertAt(System.IntPtr pComThis, uint _index, IntPtr _value)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int index = (int)_index;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.Insert, ref index, (IntPtr)(&_value));
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ if (hrExcep is ArgumentOutOfRangeException)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ unsafe static int RemoveAt(System.IntPtr pComThis, uint _index)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module,out thunk);
+
+ int index = (int)_index;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.RemoveAt, ref index, default(IntPtr));
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ if (hrExcep is ArgumentOutOfRangeException)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ unsafe static int Append(System.IntPtr pComThis, IntPtr _value)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module,out thunk);
+
+ int dummy = 0;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.Add, ref dummy, (IntPtr)(&_value));
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ unsafe static int RemoveAtEnd(System.IntPtr pComThis)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int index = 0;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.GetCount, ref index, default(IntPtr));
+
+ if (index == 0)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ else
+ {
+ index--;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.RemoveAt, ref index, default(IntPtr));
+ }
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ if (hrExcep is ArgumentOutOfRangeException)
+ {
+ hr = Interop.COM.E_BOUNDS;
+ }
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ unsafe static int Clear(System.IntPtr pComThis)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int dummy = 0;
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.Clear, ref dummy, default(IntPtr));
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+
+ [NativeCallable]
+ internal unsafe static int GetMany(System.IntPtr pComThis, uint startIndex, uint len, System.IntPtr pDest, System.IntPtr pCount)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module ,out thunk);
+
+ int listCount = 0;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.GetCount, ref listCount, default(IntPtr));
+
+ uint itemCount = 0;
+
+ if ((startIndex != listCount) && Toolbox.EnsureIndexInt32(startIndex, (uint)listCount, ref hr))
+ {
+ itemCount = System.Math.Min(len, (uint)listCount - startIndex);
+
+ // Convert to COM interfaces, without allocating array
+ uint i = 0;
+
+ int byteSize = module.GetByteSize(marshalIndex);
+
+ while (i < itemCount)
+ {
+ int index = (int)(i + startIndex);
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.GetItem, ref index, pDest);
+
+ pDest = (IntPtr)((byte*)pDest + byteSize);
+
+ i++;
+ }
+ }
+
+ *((uint*)pCount) = itemCount;
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ unsafe static int ReplaceAll(System.IntPtr pComThis, uint length, IntPtr pItems)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get IList object
+ object list = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int dummy = 0;
+
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.Clear, ref dummy, default(IntPtr));
+
+ int byteSize = module.GetByteSize(marshalIndex);
+
+ for (uint i = 0; i < length; i++)
+ {
+ CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.Add, ref dummy, pItems);
+
+ pItems = (IntPtr)((byte*)pItems + byteSize);
+ }
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+ }
+
+ /// <summary>
+ /// Shared CCW for IVectorView<T> over IReadOnlyList<T> where T is a reference type marshalled to COM interface
+ /// </summary>
+ internal unsafe struct SharedCcw_IVectorView
+ {
+ public System.IntPtr pfnQueryInterface;
+ public System.IntPtr pfnAddRef;
+ public System.IntPtr pfnRelease;
+ public System.IntPtr pfnGetIids;
+ public System.IntPtr pfnGetRuntimeClassName;
+ public System.IntPtr pfnGetTrustLevel;
+
+ public System.IntPtr pfnGetAt;
+ public System.IntPtr pfnget_Size;
+ public System.IntPtr pfnIndexOf;
+ public System.IntPtr pfnGetMany;
+
+ [PreInitialized]
+ static SharedCcw_IVectorView s_theCcwVtable = new SharedCcw_IVectorView()
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+
+ // The 4 SharedCcw_IVectorView functions have exactly the same implementation as those in SharedCcw_IVector, just use them for free
+ // The real difference is handled by IReadOnlyListThunk<T>
+ pfnGetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(SharedCcw_IVector.GetAt),
+ pfnget_Size = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(SharedCcw_IVector.get_Size),
+ pfnIndexOf = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIndexOf>(SharedCcw_IVector.IndexOf),
+ pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany1>(SharedCcw_IVector.GetMany),
+ };
+
+ public static System.IntPtr GetVtable()
+ {
+ return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
+ }
+ }
+
+ /// <summary>
+ /// Shared CCW for IVectorView<T> over IReadOnlyList<T> where T is blittable
+ /// </summary>
+ internal unsafe struct SharedCcw_IVectorView_Blittable
+ {
+ public System.IntPtr pfnQueryInterface;
+ public System.IntPtr pfnAddRef;
+ public System.IntPtr pfnRelease;
+ public System.IntPtr pfnGetIids;
+ public System.IntPtr pfnGetRuntimeClassName;
+ public System.IntPtr pfnGetTrustLevel;
+
+ public System.IntPtr pfnGetAt;
+ public System.IntPtr pfnget_Size;
+ public System.IntPtr pfnIndexOf;
+ public System.IntPtr pfnGetMany;
+
+ [PreInitialized]
+ static SharedCcw_IVectorView_Blittable s_theCcwVtable = new SharedCcw_IVectorView_Blittable()
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+
+ // The 4 SharedCcw_IVectorView_Blittable functions have exactly the same implementation as those in SharedCcw_IVector_Blittable, just use them for free
+ // The real difference is handled by IReadOnlyListBlittableThunk<T>
+ pfnGetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(SharedCcw_IVector_Blittable.GetAt),
+ pfnget_Size = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(SharedCcw_IVector_Blittable.get_Size),
+ pfnIndexOf = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIndexOf>(SharedCcw_IVector_Blittable.IndexOf),
+ pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany1>(SharedCcw_IVector_Blittable.GetMany),
+ };
+
+ public static System.IntPtr GetVtable()
+ {
+ return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
+ }
+ }
+
+ /// <summary>
+ /// Shared CCW for IIterable<T> over IEnumerable<T> where T is a reference type marshalled to COM interface
+ /// </summary>
+ internal unsafe struct SharedCcw_IIterable
+ {
+ public System.IntPtr pfnQueryInterface;
+ public System.IntPtr pfnAddRef;
+ public System.IntPtr pfnRelease;
+ public System.IntPtr pfnGetIids;
+ public System.IntPtr pfnGetRuntimeClassName;
+ public System.IntPtr pfnGetTrustLevel;
+
+ public System.IntPtr pfnFirst;
+
+ [PreInitialized]
+ static SharedCcw_IIterable s_theCcwVtable = new SharedCcw_IIterable()
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+
+ pfnFirst = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(First),
+ };
+
+ public static System.IntPtr GetVtable()
+ {
+ return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
+ }
+
+ // Thunk function in \RH\src\tools\mcg\be\Templates\McgHelpers.cs due to dependency on EnumeratorToIteratorAdapter
+ // public static object IEnumerableThunk<T>(System.Collections.Generic.IEnumerable<T> enumerable)
+ // {
+ // return new EnumeratorToIteratorAdapter<T>(enumerable.GetEnumerator());
+ // }
+
+ [NativeCallable]
+ static int First(System.IntPtr pComThis, System.IntPtr pResult)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ // Get enumerable
+ object enumerable = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ // Create enumerator using thunk function
+ object enumerator = CalliIntrinsics.Call<object>(thunk, enumerable);
+
+ // Marshal to native iterator
+ *((IntPtr*)pResult) = module.MarshalToIterator(enumerator, marshalIndex);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+ }
+
+ public static partial class Toolbox
+ {
+ public enum IIterator_Oper
+ {
+ get_Current,
+ get_HasCurrent,
+ MoveNext,
+ GetMany
+ };
+ }
+
+ /// <summary>
+ /// Shared CCW for IIterator<T> over IIterator<T> where T is a reference type marshalled to COM interface
+ /// </summary>
+ internal unsafe struct SharedCcw_IIterator
+ {
+ public System.IntPtr pfnQueryInterface;
+ public System.IntPtr pfnAddRef;
+ public System.IntPtr pfnRelease;
+ public System.IntPtr pfnGetIids;
+ public System.IntPtr pfnGetRuntimeClassName;
+ public System.IntPtr pfnGetTrustLevel;
+
+ public System.IntPtr pfnget_Current;
+ public System.IntPtr pfnget_HasCurrent;
+ public System.IntPtr pfnMoveNext;
+ public System.IntPtr pfnGetMany;
+
+ [PreInitialized]
+ static SharedCcw_IIterator s_theCcwVtable = new SharedCcw_IIterator()
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+
+ pfnget_Current = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_Current),
+ pfnget_HasCurrent = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_HasCurrent),
+ pfnMoveNext = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(MoveNext),
+ pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany2>(GetMany),
+ };
+
+ public static System.IntPtr GetVtable()
+ {
+ return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
+ }
+
+ [NativeCallable]
+ static int get_Current(System.IntPtr pComThis, System.IntPtr pValue)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object iterator = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object item = null;
+
+ CalliIntrinsics.Call<int>(thunk, iterator, Toolbox.IIterator_Oper.get_Current, ref item, 0);
+
+ *((IntPtr*)pValue) = module.ObjectToComInterface(item, marshalIndex);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ static int get_HasCurrent(System.IntPtr pComThis, System.IntPtr pValue)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object iterator = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object item = null;
+
+ *((byte*)pValue) = (byte)CalliIntrinsics.Call<int>(thunk, iterator, Toolbox.IIterator_Oper.get_HasCurrent, ref item, 0);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ static int MoveNext(System.IntPtr pComThis, System.IntPtr pValue)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object iterator = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object item = null;
+
+ *((byte*)pValue) = (byte)CalliIntrinsics.Call<int>(thunk, iterator, Toolbox.IIterator_Oper.MoveNext, ref item, 0);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ static int GetMany(System.IntPtr pComThis, uint len, System.IntPtr pDest, System.IntPtr pCount)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object iterator = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ object data = null;
+
+ *((int*)pCount) = CalliIntrinsics.Call<int>(thunk, iterator, Toolbox.IIterator_Oper.GetMany, ref data, (int)len);
+
+ System.IntPtr* dst = (System.IntPtr*)pDest;
+
+ object[] src = data as object[];
+
+ for (uint i = 0; i < len; i++)
+ {
+ dst[i] = module.ObjectToComInterface(src[i], marshalIndex);
+ }
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+ }
+
+#if !RHTESTCL && !CORECLR
+
+ /// <summary>
+ /// Shared CCW for IIterator<T> over IIterator<T> where T is a blittable struct
+ /// </summary>
+ internal unsafe struct SharedCcw_IIterator_Blittable
+ {
+ public System.IntPtr pfnQueryInterface;
+ public System.IntPtr pfnAddRef;
+ public System.IntPtr pfnRelease;
+ public System.IntPtr pfnGetIids;
+ public System.IntPtr pfnGetRuntimeClassName;
+ public System.IntPtr pfnGetTrustLevel;
+
+ public System.IntPtr pfnget_Current;
+ public System.IntPtr pfnget_HasCurrent;
+ public System.IntPtr pfnMoveNext;
+ public System.IntPtr pfnGetMany;
+
+ [PreInitialized]
+ static SharedCcw_IIterator_Blittable s_theCcwVtable = new SharedCcw_IIterator_Blittable()
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+
+ pfnget_Current = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_Current),
+ pfnget_HasCurrent = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_HasCurrent),
+ pfnMoveNext = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(MoveNext),
+ pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany2>(GetMany),
+ };
+
+ public static System.IntPtr GetVtable()
+ {
+ return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
+ }
+
+ // public static Array IIteratorBlittableThunk<T>(IIterator<T> it, IIterator_Oper oper, ref T data, ref int len) where T : struct
+
+ [NativeCallable]
+ static int get_Current(System.IntPtr pComThis, System.IntPtr pValue)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object iterator = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int dummy = 0;
+
+ CalliIntrinsics.Call<Array>(thunk, iterator, Toolbox.IIterator_Oper.get_Current, pValue, ref dummy);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ static int get_HasCurrent(System.IntPtr pComThis, System.IntPtr pValue)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object iterator = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int has = 0;
+
+ CalliIntrinsics.Call<Array>(thunk, iterator, Toolbox.IIterator_Oper.get_HasCurrent, default(IntPtr), ref has);
+
+ *((byte*)pValue) = (byte)has;
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ static int MoveNext(System.IntPtr pComThis, System.IntPtr pValue)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object iterator = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module,out thunk);
+
+ int has = 0;
+ CalliIntrinsics.Call<Array>(thunk, iterator, Toolbox.IIterator_Oper.MoveNext, default(IntPtr), ref has);
+
+ *((byte*)pValue) = (byte)has;
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+
+ [NativeCallable]
+ static int GetMany(System.IntPtr pComThis, uint len, System.IntPtr pDest, System.IntPtr pCount)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object iterator = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module, out thunk);
+
+ int count = (int)len;
+
+ Array data = CalliIntrinsics.Call<Array>(thunk, iterator, Toolbox.IIterator_Oper.GetMany, default(IntPtr), ref count);
+
+ *((uint*)pCount) = (uint)count;
+
+ InteropExtensions.CopyToNative(data, 0, pDest, count);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+ }
+
+
+ internal unsafe partial struct SharedCcw_AsyncOperationCompletedHandler
+ {
+ public System.IntPtr pfnQueryInterface;
+ public System.IntPtr pfnAddRef;
+ public System.IntPtr pfnRelease;
+
+ public System.IntPtr pfnInvoke;
+
+ [PreInitialized]
+ static SharedCcw_AsyncOperationCompletedHandler s_theCcwVtable = new SharedCcw_AsyncOperationCompletedHandler()
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ pfnInvoke = AddrOfIntrinsics.AddrOf<WinRTAddrOfIntrinsics.AddrOfTarget19>(Invoke),
+ };
+
+ public static System.IntPtr GetVtable()
+ {
+ return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
+ }
+
+ [NativeCallable]
+ static int Invoke(System.IntPtr pComThis, System.IntPtr _asyncInfo, Windows.Foundation.AsyncStatus asyncStatus)
+ {
+ int hr = Interop.COM.S_OK;
+
+ try
+ {
+ int marshalIndex;
+ IntPtr thunk;
+ McgModule module;
+ object handler = ComCallableObject.GetThunk(pComThis, out marshalIndex, out module,out thunk);
+
+ object asyncInfo = module.MarshalToAsyncOperation(_asyncInfo, marshalIndex);
+
+ // Call handler.Invoke(asyncInfo, asyncStatus)
+ CalliIntrinsics.Call<int>(thunk, handler, asyncInfo, asyncStatus);
+ }
+ catch (System.Exception hrExcep)
+ {
+ hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+
+ return hr;
+ }
+ }
+#endif
+#else
+ class Toolbox { }
+#endif // ENABLE_WINRT
+ public static class SpinWaitExtensions
+ {
+ public static void Yield()
+ {
+#if CORECLR
+ System.Threading.Thread.Sleep(0);
+#elif RHTESTCL
+ // nop
+#else
+ System.Threading.SpinWait.Yield();
+#endif
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgIntrinsics.cs b/src/System.Private.Interop/src/Shared/McgIntrinsics.cs
new file mode 100644
index 000000000..693230d9e
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgIntrinsics.cs
@@ -0,0 +1,556 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// ----------------------------------------------------------------------------------
+// Interop library code
+//
+// NOTE:
+// These source code are being published to InternalAPIs and consumed by RH builds
+// Use PublishInteropAPI.bat to keep the InternalAPI copies in sync
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Text;
+using System.Runtime;
+using System.Diagnostics.Contracts;
+using Internal.NativeFormat;
+
+namespace System.Runtime.InteropServices
+{
+ //
+ // This section contains the code that would have been generated by MCG in order to use the AddrOf and
+ // StdCall intrinsics, had we used it to generate all of our interop code. In general, the transformation
+ // done by the IL2IL step is simple. We search the assembly being transformed for a definition of the
+ // McgIntrinsics attribute and, then, any class marked with [McgIntrinsics] will be searched for methods
+ // named StdCall and AddrOf. For methods named StdCall, an implementation is provided that loads up the
+ // arguments and does an IL 'calli' instruction to the first argument to StdCall using the unmanaged
+ // stdcall calling convention. For methods named AddrOf, it is the callsites that are transformed. For
+ // this, the callsites are implicitly constructing a Func<T> delegate around a static method. The IL2IL
+ // transform will look at every callsite to an AddrOf and ensure that it matches the expected pattern. If
+ // it does, it will eliminate the delegate construction and the call to the methods defined below and
+ // simply leave the 'ldftn' IL instruction that was used as part of that delegate construction sequence.
+ //
+ // Note:In .NET Native NutC and binder on seeing an LDFTN with NativeCallable target method generate method
+ // callable from native , on CoreCLR we wrap NativeCallable in an UMThunk , which essentialy
+ // is the same code path as reverse PInvoke.
+
+ // Note: Because AddrOf depends on Func<T>, the arguments may not be pointer types (because generics can
+ // not be instantiated over pointer types).
+ //
+ // Note: Because StdCall is most commonly used with COM calls, void-returning StdCalls weren't implemented
+ // in MCG and we've also avoided them here (even though the IL2IL transform should support them).
+ //
+ [System.AttributeUsageAttribute(System.AttributeTargets.Class)]
+ internal class McgIntrinsicsAttribute : System.Attribute
+ {
+ }
+
+ [McgIntrinsics]
+ internal static unsafe partial class CalliIntrinsics
+ {
+ internal static int StdCall__QueryInterface(
+ IntPtr pfn,
+ IntPtr pComThis,
+ IntPtr arg0,
+ IntPtr arg1)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(int);
+ }
+
+ internal static int StdCall__AddRef(System.IntPtr pfn, IntPtr pComThis)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(int);
+ }
+
+ internal static int StdCall__Release(System.IntPtr pfn, IntPtr pComThis)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(int);
+ }
+
+ internal static int StdCall__int(
+ System.IntPtr pfn,
+ IntPtr pComThis)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(int);
+ }
+
+ internal static int StdCall__int(
+ IntPtr pfn,
+ IntPtr pComThis,
+ void* arg0)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(int);
+ }
+
+ internal static int StdCall__int(
+ IntPtr pfn,
+ IntPtr pComThis,
+ void* arg0,
+ void* arg1)
+ {
+
+ // This method is implemented elsewhere in the toolchain
+ return default(int);
+ }
+
+ internal static int StdCall__int(
+ IntPtr pfn,
+ IntPtr pComThis,
+ void* arg0,
+ int arg1,
+ IntPtr arg2)
+ {
+
+ // This method is implemented elsewhere in the toolchain
+ return default(int);
+ }
+
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ void* pComThis,
+ ulong arg0,
+ uint arg1,
+ void* arg2)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ void* pComThis,
+ IntPtr arg0,
+ void* arg1,
+ void* arg2,
+ int arg3,
+ IntPtr arg4)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ void* pComThis,
+ void* arg0,
+ IntPtr arg1,
+ uint arg2,
+ IntPtr arg3,
+ uint arg4,
+ void* arg5)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ uint arg0)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ void* arg0)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ void* arg0,
+ void* arg1)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ void* arg0,
+ uint arg1,
+ void* arg2)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ void* arg0,
+ void* arg1,
+ void* arg2)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ void* arg0,
+ uint arg1,
+ void* arg2,
+ void* arg3)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ int hr,
+ void* errorMsg,
+ System.IntPtr pUnk)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ System.IntPtr pComThis,
+ out System.IntPtr arg1,
+ out int arg2,
+ out System.IntPtr arg3,
+ out System.IntPtr arg4)
+ {
+ // This method is implemented elsewhere in the toolchain
+ arg1 = default(IntPtr);
+ arg3 = default(IntPtr);
+ arg4 = default(IntPtr);
+ arg2 = 0;
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ System.IntPtr pComThis,
+ out System.IntPtr arg)
+ {
+ // This method is implemented elsewhere in the toolchain
+ arg = default(IntPtr);
+ return default(T);
+ }
+ internal static T StdCall<T>(
+ System.IntPtr pfn,
+ System.IntPtr pComThis,
+ System.Guid arg1,
+ out System.IntPtr arg2)
+ {
+ // This method is implemented elsewhere in the toolchain
+ arg2 = default(IntPtr);
+ return default(T);
+ }
+
+ internal static T StdCall<T>(
+ IntPtr pfn,
+ void* pComThis,
+ IntPtr piid,
+ IntPtr pv,
+ int dwDestContext,
+ IntPtr pvDestContext,
+ int mshlflags,
+ IntPtr pclsid)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+
+ internal static T StdCall<T>(
+ IntPtr pfn,
+ void* pComThis,
+ IntPtr pStm,
+ IntPtr piid,
+ IntPtr pv,
+ int dwDestContext,
+ IntPtr pvDestContext,
+ int mshlflags)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+
+ internal static T StdCall<T>(
+ IntPtr pfn,
+ void* pComThis,
+ IntPtr pStm,
+ IntPtr piid,
+ IntPtr ppvObj)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+
+ internal static T StdCall<T>(
+ IntPtr pfn,
+ void* pComThis,
+ IntPtr pStm)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+
+ internal static T StdCall<T>(
+ IntPtr pfn,
+ void* pComThis,
+ int dwReserved)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(T);
+ }
+
+ private const MethodImplOptions InternalCall = (MethodImplOptions)0x1000;
+
+ // Cooperative GC versions of StdCall.
+ // We need to call via an imported stub to do a stdcall without triggering GC
+ // We can't use managed calli because the native target address could potentially satisfy a magic
+ // bit check and causing the stub to believe it is a managed method which leads to crash.
+#if !RHTESTCL && !CORECLR
+ [MethodImplAttribute(InternalCall)]
+#if X86
+ [RuntimeImport("*", "@StdCallCOOP0@8")]
+#else
+ [RuntimeImport("*", "StdCallCOOP0")]
+#endif // X86
+ internal static extern int StdCallCOOP(System.IntPtr pfn, void* pComThis);
+
+ [MethodImplAttribute(InternalCall)]
+#if X86
+ [RuntimeImport("*", "@StdCallCOOPV@12")]
+#else
+ [RuntimeImport("*", "StdCallCOOPV")]
+#endif // X86
+
+ internal static extern int StdCallCOOP(System.IntPtr pfn, void* pComThis, void* arg0);
+
+ [MethodImplAttribute(InternalCall)]
+#if X86
+ [RuntimeImport("*", "@StdCallCOOPI@12")]
+#else
+ [RuntimeImport("*", "StdCallCOOPI")]
+#endif // X86
+ internal static extern int StdCallCOOP(System.IntPtr pfn, void* pComThis, int arg0);
+#else
+ internal static int StdCallCOOP(System.IntPtr pfn, void* pComThis)
+ {
+ return Call<int>(pfn, pComThis);
+ }
+
+ internal static int StdCallCOOP(System.IntPtr pfn, void* pComThis, void* arg0)
+ {
+ return Call<int>(pfn, pComThis, arg0);
+ }
+
+ internal static int StdCallCOOP(System.IntPtr pfn, void* pComThis, int arg0)
+ {
+ return Call<int>(pfn, pComThis, arg0);
+ }
+#endif
+
+ // Used to invoke GetCcwVtable* methods which return pVtbl
+ internal static IntPtr Call__GetCcwVtable(
+ System.IntPtr pfn)
+ {
+ return default(IntPtr);
+ }
+ internal static T Call<T>(
+ System.IntPtr pfn,
+ void* arg0)
+ {
+ return default(T);
+ }
+ internal static T Call<T>(
+ System.IntPtr pfn,
+ Object arg0)
+ {
+ return default(T);
+ }
+ internal static T Call<T>(
+ System.IntPtr pfn,
+ System.Object arg0,
+ System.Object arg1,
+ int arg2)
+ {
+ return default(T);
+ }
+ internal static T Call<T>(
+ System.IntPtr pfn,
+ System.Object arg0,
+ int arg1)
+ {
+ return default(T);
+ }
+ internal static T Call<T>(
+ System.IntPtr pfn,
+ void* arg0,
+ void* arg1)
+ {
+ return default(T);
+ }
+ internal static T Call<T>(
+ System.IntPtr pfn,
+ void* arg0,
+ int arg1)
+ {
+ return default(T);
+ }
+ internal static T Call<T>(
+ System.IntPtr pfn,
+ System.IntPtr arg0,
+ uint arg1,
+ System.IntPtr arg2)
+ {
+ return default(T);
+ }
+ internal static T Call<T>(
+ System.IntPtr pfn,
+ System.IntPtr arg0,
+ uint arg1,
+ void* arg2,
+ System.IntPtr arg3)
+ {
+ return default(T);
+ }
+ internal static T Call<T>(
+ System.IntPtr pfn,
+ __ComObject arg0,
+ System.IntPtr arg1)
+ {
+ return default(T);
+ }
+ internal static T Call<T>(
+ System.IntPtr pfn,
+ __ComObject arg0,
+ System.IntPtr arg1,
+ McgClassInfo arg2)
+ {
+ return default(T);
+ }
+
+#if ENABLE_WINRT
+ // For SharedCCW_IVector/SharedCCW_IVectorView
+ internal static T Call<T>(IntPtr pfn, object list, Toolbox.IList_Oper oper, int index, ref object item)
+ {
+ return default(T);
+ }
+
+ // For SharedCCW_ITerator
+ internal static T Call<T>(IntPtr pfn, object iterator, Toolbox.IIterator_Oper oper, ref object data, int len)
+ {
+ return default(T);
+ }
+
+ internal static T Call<T>(IntPtr pfn, object iterator, Toolbox.IIterator_Oper oper, IntPtr pData, ref int len)
+ {
+ return default(T);
+ }
+
+#if !RHTESTCL && !CORECLR
+
+ // For SharedCcw_AsyncOperationCompletedHandler
+ internal static T Call<T>(IntPtr pfn, object handler, object asyncInfo, Windows.Foundation.AsyncStatus status)
+ {
+ return default(T);
+ }
+#endif
+ // For SharedCCW_IVector_Blittable/SharedCCW_IVectorView_Blittable
+ internal static T Call<T>(IntPtr pfn, object list, Toolbox.IList_Oper oper, ref int index, System.IntPtr pData)
+ {
+ return default(T);
+ }
+#endif // ENABLE_WINRT
+ // For ForwardDelegateCreationStub
+ internal static Delegate Call__Delegate(System.IntPtr pfn, System.IntPtr pStub)
+ {
+ return default(Delegate);
+ }
+ }
+
+ [McgIntrinsics]
+ internal static partial class AddrOfIntrinsics
+ {
+ internal static IntPtr AddrOf<T>(T ftn)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(IntPtr);
+ }
+
+ internal static IntPtr StaticFieldAddr<T>(ref T field)
+ {
+ // This method is implemented elsewhere in the toolchain
+ return default(IntPtr);
+ }
+
+ // Apart from AddRef , Release and QI there are lot other functions with same
+ // signature but different semantics.So keeping AddrOfTarget1 , AddrOfTarget4 around even though
+ // they have the same signature as AddrOfAddRef and AddrOfQueryInterface
+
+ // Common delegate signature for many functions
+ internal delegate int AddrOfTarget1(IntPtr p0);
+ internal delegate int AddrOfTarget2(IntPtr p0, int p1);
+ internal delegate int AddrOfTarget3(IntPtr p0, IntPtr p1);
+
+ // specialized delegates
+ internal delegate int AddrOfGetIID(IntPtr __IntPtr__pComThis, IntPtr __IntPtr__iidCount, IntPtr __IntPtr__iids);
+ internal delegate int AddrOfCreateManagedReference(System.IntPtr pComThis, IntPtr __IntPtr__pJupiterObject, IntPtr __IntPtr__ppNewReference);
+ internal delegate int AddrOfResolve(IntPtr __IntPtr__pComThis, IntPtr __IntPtr__piid, IntPtr __IntPtr__ppWeakReference);
+ internal delegate int AddrOfIndexOf(IntPtr p0, IntPtr p1, IntPtr p2, IntPtr p3);
+ internal delegate int AddrOfUnmarshalInterface(IntPtr p0, IntPtr p1, IntPtr p2, IntPtr p3);
+ internal delegate int AddrOfMarshalInterface(IntPtr p0, IntPtr p1, IntPtr p2, IntPtr p3, int p4, IntPtr p5, int p6);
+
+ internal delegate int AddrOfGetMarshalUnMarshal(IntPtr pComThis,
+ IntPtr piid,
+ IntPtr pv,
+ int dwDestContext,
+ IntPtr pvDestContext,
+ int mshlflags,
+ IntPtr pclsid);
+
+ internal delegate int AddrOfAttachingCtor(__ComObject comObject, IntPtr pBaseIUnknown, McgClassInfo classInfo);
+ internal delegate int AddrOfGetSetInsertReplaceAll(IntPtr pComThis, uint index, IntPtr pItem);
+ internal delegate int AddrOfRemoveAt(System.IntPtr pComThis, uint index);
+ internal delegate int AddrOfGetMany1(IntPtr pComThis, uint startIndex, uint len, IntPtr pDest, IntPtr pCount);
+ internal delegate int AddrOfGetMany2(IntPtr pComThis, uint len, IntPtr pDest, IntPtr pCount);
+ internal delegate int AddrOfHookGCCallbacks(int nCondemnedGeneration);
+ internal delegate int AddrOfAddRemoveMemoryPressure(System.IntPtr pComThis, ulong bytesAllocated);
+
+ internal delegate bool AddrOfIsAlive(ComCallableObject comCallableObject);
+
+ // IStream
+ internal delegate int AddrOfIStreamClone(IntPtr pComThis, out IntPtr ppstm);
+ internal delegate int AddrOfIStreamCopyTo(IntPtr pComThis, IntPtr pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);
+ internal delegate int AddrOfIStreamLockRegion(IntPtr pComThis, long libOffset, long cb, int dwLockType);
+ internal delegate int AddrOfIStreamRead(IntPtr pComThis, IntPtr pv, int cb, IntPtr pcbRead);
+ internal delegate int AddrOfIStreamSeek(IntPtr pComThis, long dlibMove, int dwOrigin, IntPtr plibNewPosition);
+ internal delegate int AddrOfIStreamSetSize(IntPtr pComThis, long libNewSize);
+ internal delegate int AddrOfIStreamStat(IntPtr pComThis, out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag);
+ internal delegate int AddrOfIStreamUnlockRegion(IntPtr pComThis, long libOffset, long cb, int dwLockType);
+ internal delegate int AddrOfIStreamWrite(IntPtr pComThis, IntPtr pv, int cb, IntPtr pcbWritten);
+ }
+
+#if !CORECLR && ENABLE_WINRT
+ [McgIntrinsics]
+ internal class WinRTAddrOfIntrinsics
+ {
+ internal delegate int AddrOfGetCustomProperty(System.IntPtr pComThis, HSTRING unsafe_name, IntPtr __IntPtr__unsafe_customProperty);
+ internal delegate int AddrOfGetIndexedProperty(System.IntPtr pComThis, HSTRING unsafe_name, TypeName unsafe_type, IntPtr __IntPtr__unsafe_customProperty);
+#if !RHTESTCL
+ internal delegate int AddrOfTarget19(IntPtr p0, IntPtr p1, Windows.Foundation.AsyncStatus p2);
+#endif // !RHTESTCL
+ }
+#endif // !CORECLR && ENABLE_WINRT
+
+ public delegate IntPtr AddrOfGetCCWVtable();
+ public delegate int AddrOfRelease(IntPtr pComThis);
+ public delegate int AddrOfAddRef(IntPtr pComThis);
+ public delegate int AddrOfQueryInterface(IntPtr __IntPtr__pComThis, IntPtr __IntPtr__pIID, IntPtr __IntPtr__ppvObject);
+
+ // Helper delegate to invoke mcg generated ForwardDelegateCreationStub(IntPtr functionPointer)
+ public delegate Delegate ForwardDelegateCreationStub(IntPtr pFunc);
+}
diff --git a/src/System.Private.Interop/src/Shared/McgMarshal.cs b/src/System.Private.Interop/src/Shared/McgMarshal.cs
new file mode 100644
index 000000000..fb84877a6
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgMarshal.cs
@@ -0,0 +1,1147 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// ----------------------------------------------------------------------------------
+// Interop library code
+//
+// Marshalling helpers used by MCG
+//
+// NOTE:
+// These source code are being published to InternalAPIs and consumed by RH builds
+// Use PublishInteropAPI.bat to keep the InternalAPI copies in sync
+// ----------------------------------------------------------------------------------
+
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.ComponentModel;
+ using System.Diagnostics;
+ using System.Reflection;
+ using System.Runtime.InteropServices.WindowsRuntime;
+ using System.Runtime.InteropServices;
+ using System.Threading;
+ using System.Text;
+ using System.Runtime;
+ using System.Diagnostics.Contracts;
+ using Internal.NativeFormat;
+ using System.Runtime.CompilerServices;
+
+#if RHTESTCL
+ using OutputClass = System.Console;
+#else
+ using OutputClass = System.Diagnostics.Debug;
+#endif
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Expose functionality from System.Private.CoreLib and forwards calls to InteropExtensions in System.Private.CoreLib
+ /// </summary>
+ [CLSCompliant(false)]
+ public static partial class McgMarshal
+ {
+ [ThreadStatic]
+ internal static int s_lastWin32Error;
+ public static void SaveLastWin32Error()
+ {
+ s_lastWin32Error = ExternalInterop.GetLastWin32Error();
+ }
+
+ public static bool GuidEquals(ref Guid left, ref Guid right)
+ {
+ return InteropExtensions.GuidEquals(ref left, ref right);
+ }
+
+ public static bool ComparerEquals<T>(T left, T right)
+ {
+ return InteropExtensions.ComparerEquals<T>(left, right);
+ }
+
+ public static T CreateClass<T>() where T : class
+ {
+ return InteropExtensions.UncheckedCast<T>(InteropExtensions.RuntimeNewObject(typeof(T).TypeHandle));
+ }
+
+ public static bool IsEnum(object obj)
+ {
+#if RHTESTCL
+ return false;
+#else
+ return InteropExtensions.IsEnum(obj.GetTypeHandle());
+#endif
+ }
+
+ public static bool IsCOMObject(Type type)
+ {
+#if RHTESTCL
+ return false;
+#else
+ return InteropExtensions.AreTypesAssignable(type.TypeHandle, typeof(__ComObject).TypeHandle);
+#endif
+ }
+
+ public static T FastCast<T>(object value) where T : class
+ {
+ // We have an assert here, to verify that a "real" cast would have succeeded.
+ // However, casting on weakly-typed RCWs modifies their state, by doing a QI and caching
+ // the result. This often makes things work which otherwise wouldn't work (especially variance).
+ Debug.Assert(value == null || value is T);
+ return InteropExtensions.UncheckedCast<T>(value);
+ }
+
+ /// <summary>
+ /// Converts a managed DateTime to native OLE datetime
+ /// Used by MCG marshalling code
+ /// </summary>
+ public static double ToNativeOleDate(DateTime dateTime)
+ {
+ return InteropExtensions.ToNativeOleDate(dateTime);
+ }
+
+ /// <summary>
+ /// Converts native OLE datetime to managed DateTime
+ /// Used by MCG marshalling code
+ /// </summary>
+ public static DateTime FromNativeOleDate(double nativeOleDate)
+ {
+ return InteropExtensions.FromNativeOleDate(nativeOleDate);
+ }
+
+ /// <summary>
+ /// Used in Marshalling code
+ /// Call safeHandle.InitializeHandle to set the internal _handle field
+ /// </summary>
+ public static void InitializeHandle(SafeHandle safeHandle, IntPtr win32Handle)
+ {
+ InteropExtensions.InitializeHandle(safeHandle, win32Handle);
+ }
+
+ /// <summary>
+ /// Check if obj's type is the same as represented by normalized handle
+ /// </summary>
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static bool IsOfType(object obj, RuntimeTypeHandle handle)
+ {
+ return obj.IsOfType(handle);
+ }
+
+#if ENABLE_WINRT
+ public static unsafe void SetExceptionErrorCode(Exception exception, int errorCode)
+ {
+ InteropExtensions.SetExceptionErrorCode(exception, errorCode);
+ }
+
+ /// <summary>
+ /// Used in Marshalling code
+ /// Gets the handle of the CriticalHandle
+ /// </summary>
+ public static IntPtr GetHandle(CriticalHandle criticalHandle)
+ {
+ return criticalHandle.handle;
+ }
+
+ /// <summary>
+ /// Used in Marshalling code
+ /// Sets the handle of the CriticalHandle
+ /// </summary>
+ public static void SetHandle(CriticalHandle criticalHandle, IntPtr handle)
+ {
+ criticalHandle.handle = handle;
+ }
+#endif
+ }
+
+ /// <summary>
+ /// McgMarshal helpers exposed to be used by MCG
+ /// </summary>
+ public static partial class McgMarshal
+ {
+ #region Type marshalling
+
+ public static Type TypeNameToType(HSTRING nativeTypeName, int nativeTypeKind)
+ {
+#if ENABLE_WINRT
+ return McgTypeHelpers.TypeNameToType(nativeTypeName, nativeTypeKind);
+#else
+ throw new NotSupportedException("TypeNameToType");
+#endif
+ }
+
+ public unsafe static void TypeToTypeName(
+ Type type,
+ out HSTRING nativeTypeName,
+ out int nativeTypeKind)
+ {
+#if ENABLE_WINRT
+ McgTypeHelpers.TypeToTypeName(type, out nativeTypeName, out nativeTypeKind);
+#else
+ throw new NotSupportedException("TypeToTypeName");
+#endif
+ }
+
+ #endregion
+
+ #region String marshalling
+
+ [CLSCompliant(false)]
+ public static unsafe void StringBuilderToUnicodeString(System.Text.StringBuilder stringBuilder, ushort* destination)
+ {
+ stringBuilder.UnsafeCopyTo((char*)destination);
+ }
+
+ [CLSCompliant(false)]
+ public static unsafe void UnicodeStringToStringBuilder(ushort* newBuffer, System.Text.StringBuilder stringBuilder)
+ {
+ stringBuilder.ReplaceBuffer((char*)newBuffer);
+ }
+
+#if !RHTESTCL
+
+ [CLSCompliant(false)]
+ public static unsafe void StringBuilderToAnsiString(System.Text.StringBuilder stringBuilder, byte* pNative,
+ bool bestFit, bool throwOnUnmappableChar)
+ {
+ int len;
+
+ // Convert StringBuilder to UNICODE string
+
+ // Optimize for the most common case. If there is only a single char[] in the StringBuilder,
+ // get it and convert it to ANSI
+ char[] buffer = stringBuilder.GetBuffer(out len);
+
+ if (buffer != null)
+ {
+ fixed (char* pManaged = buffer)
+ {
+ StringToAnsiString(pManaged, len, pNative, /*terminateWithNull=*/true, bestFit, throwOnUnmappableChar);
+ }
+ }
+ else // Otherwise, convert StringBuilder to string and then convert to ANSI
+ {
+ string str = stringBuilder.ToString();
+
+ // Convert UNICODE string to ANSI string
+ fixed (char* pManaged = str)
+ {
+ StringToAnsiString(pManaged, str.Length, pNative, /*terminateWithNull=*/true, bestFit, throwOnUnmappableChar);
+ }
+ }
+ }
+
+ [CLSCompliant(false)]
+ public static unsafe void AnsiStringToStringBuilder(byte* newBuffer, System.Text.StringBuilder stringBuilder)
+ {
+ if (newBuffer == null)
+ throw new ArgumentNullException();
+
+ int lenAnsi;
+ int lenUnicode;
+ CalculateStringLength(newBuffer, out lenAnsi, out lenUnicode);
+
+ if (lenUnicode > 0)
+ {
+ char[] buffer = new char[lenUnicode];
+ fixed (char* pTemp = buffer)
+ {
+ ExternalInterop.ConvertMultiByteToWideChar(new System.IntPtr(newBuffer),
+ lenAnsi,
+ new System.IntPtr(pTemp),
+ lenUnicode);
+ }
+ stringBuilder.ReplaceBuffer(buffer);
+ }
+ else
+ {
+ stringBuilder.Clear();
+ }
+ }
+
+ /// <summary>
+ /// Convert ANSI string to unicode string, with option to free native memory. Calls generated by MCG
+ /// </summary>
+ /// <remarks>Input assumed to be zero terminated. Generates String.Empty for zero length string.
+ /// This version is more efficient than ConvertToUnicode in src\Interop\System\Runtime\InteropServices\Marshal.cs in that it can skip calling
+ /// MultiByteToWideChar for ASCII string, and it does not need another char[] buffer</remarks>
+ [CLSCompliant(false)]
+ public static unsafe string AnsiStringToString(byte* pchBuffer)
+ {
+ if (pchBuffer == null)
+ {
+ return null;
+ }
+
+ int lenAnsi;
+ int lenUnicode;
+ CalculateStringLength(pchBuffer, out lenAnsi, out lenUnicode);
+
+ string result = String.Empty;
+
+ if (lenUnicode > 0)
+ {
+ result = new String(' ', lenUnicode); // TODO: FastAllocate not accessible here
+
+ fixed (char* pTemp = result)
+ {
+ ExternalInterop.ConvertMultiByteToWideChar(new System.IntPtr(pchBuffer),
+ lenAnsi,
+ new System.IntPtr(pTemp),
+ lenUnicode);
+ }
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Convert UNICODE string to ANSI string.
+ /// </summary>
+ /// <remarks>This version is more efficient than StringToHGlobalAnsi in Interop\System\Runtime\InteropServices\Marshal.cs in that
+ /// it could allocate single byte per character, instead of SystemMaxDBCSCharSize per char, and it can skip calling WideCharToMultiByte for ASCII string</remarks>
+ [CLSCompliant(false)]
+ public static unsafe byte* StringToAnsiString(string str, bool bestFit, bool throwOnUnmappableChar)
+ {
+ if (str != null)
+ {
+ int lenUnicode = str.Length;
+
+ fixed (char* pManaged = str)
+ {
+ return StringToAnsiString(pManaged, lenUnicode, null, /*terminateWithNull=*/true, bestFit, throwOnUnmappableChar);
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Convert UNICODE wide char array to ANSI ByVal byte array.
+ /// </summary>
+ /// <remarks>
+ /// * This version works with array instead string, it means that there will be NO NULL to terminate the array.
+ /// * The buffer to store the byte array must be allocated by the caller and must fit managedArray.Length.
+ /// </remarks>
+ /// <param name="managedArray">UNICODE wide char array</param>
+ /// <param name="pNative">Allocated buffer where the ansi characters must be placed. Could NOT be null. Buffer size must fit char[].Length.</param>
+ [CLSCompliant(false)]
+ public static unsafe void ByValWideCharArrayToAnsiCharArray(char[] managedArray, byte* pNative, int expectedCharCount,
+ bool bestFit, bool throwOnUnmappableChar)
+ {
+ // Zero-init pNative if it is NULL
+ if (managedArray == null)
+ {
+ // @TODO - Create a more efficient version of zero initialization
+ for (int i = 0; i < expectedCharCount; i++)
+ {
+ pNative[i] = 0;
+ }
+ }
+
+ int lenUnicode = managedArray.Length;
+ if (lenUnicode < expectedCharCount)
+ throw new ArgumentException(SR.WrongSizeArrayInNStruct);
+
+ fixed (char* pManaged = managedArray)
+ {
+ StringToAnsiString(pManaged, lenUnicode, pNative, /*terminateWithNull=*/false, bestFit, throwOnUnmappableChar);
+ }
+ }
+
+ [CLSCompliant(false)]
+ public static unsafe void ByValAnsiCharArrayToWideCharArray(byte* pNative, char[] managedArray)
+ {
+ // This should never happen because it is a embedded array
+ Debug.Assert(pNative != null);
+
+ // This should never happen because the array is always allocated by the marshaller
+ Debug.Assert(managedArray != null);
+
+ // COMPAT: Use the managed array length as the maximum length of native buffer
+ // This obviously doesn't make sense but desktop CLR does that
+ int lenInBytes = managedArray.Length;
+ fixed (char* pManaged = managedArray)
+ {
+ ExternalInterop.ConvertMultiByteToWideChar(new System.IntPtr(pNative),
+ lenInBytes,
+ new System.IntPtr(pManaged),
+ lenInBytes);
+ }
+ }
+
+ [CLSCompliant(false)]
+ public static unsafe void WideCharArrayToAnsiCharArray(char[] managedArray, byte* pNative, bool bestFit, bool throwOnUnmappableChar)
+ {
+ // Do nothing if array is NULL. This matches desktop CLR behavior
+ if (managedArray == null)
+ return;
+
+ // Desktop CLR crash (AV at runtime) - we can do better in .NET Native
+ if (pNative == null)
+ throw new ArgumentNullException();
+
+ int lenUnicode = managedArray.Length;
+ fixed (char* pManaged = managedArray)
+ {
+ StringToAnsiString(pManaged, lenUnicode, pNative, /*terminateWithNull=*/false, bestFit, throwOnUnmappableChar);
+ }
+ }
+
+ /// <summary>
+ /// Convert ANSI ByVal byte array to UNICODE wide char array, best fit
+ /// </summary>
+ /// <remarks>
+ /// * This version works with array instead to string, it means that the len must be provided and there will be NO NULL to
+ /// terminate the array.
+ /// * The buffer to the UNICODE wide char array must be allocated by the caller.
+ /// </remarks>
+ /// <param name="pNative">Pointer to the ANSI byte array. Could NOT be null.</param>
+ /// <param name="lenInBytes">Maximum buffer size.</param>
+ /// <param name="managedArray">Wide char array that has already been allocated.</param>
+ [CLSCompliant(false)]
+ public static unsafe void AnsiCharArrayToWideCharArray(byte* pNative, char[] managedArray)
+ {
+ // Do nothing if native is NULL. This matches desktop CLR behavior
+ if (pNative == null)
+ return;
+
+ // Desktop CLR crash (AV at runtime) - we can do better in .NET Native
+ if (managedArray == null)
+ throw new ArgumentNullException();
+
+ // COMPAT: Use the managed array length as the maximum length of native buffer
+ // This obviously doesn't make sense but desktop CLR does that
+ int lenInBytes = managedArray.Length;
+ fixed (char* pManaged = managedArray)
+ {
+ ExternalInterop.ConvertMultiByteToWideChar(new System.IntPtr(pNative),
+ lenInBytes,
+ new System.IntPtr(pManaged),
+ lenInBytes);
+ }
+ }
+
+ /// <summary>
+ /// Convert a single UNICODE wide char to a single ANSI byte.
+ /// </summary>
+ /// <param name="managedArray">single UNICODE wide char value</param>
+ public static unsafe byte WideCharToAnsiChar(char managedValue, bool bestFit, bool throwOnUnmappableChar)
+ {
+ // @TODO - we really shouldn't allocate one-byte arrays and then destroy it
+ byte* nativeArray = StringToAnsiString(&managedValue, 1, null, /*terminateWithNull=*/false, bestFit, throwOnUnmappableChar);
+ byte native = (*nativeArray);
+ ExternalInterop.CoTaskMemFree(nativeArray);
+ return native;
+ }
+
+ /// <summary>
+ /// Convert a single ANSI byte value to a single UNICODE wide char value, best fit.
+ /// </summary>
+ /// <param name="nativeValue">Single ANSI byte value.</param>
+ public static unsafe char AnsiCharToWideChar(byte nativeValue)
+ {
+ char[] buffer = new char[1];
+ fixed (char* pTemp = buffer)
+ {
+ ExternalInterop.ConvertMultiByteToWideChar(new System.IntPtr(&nativeValue), 1, new System.IntPtr(pTemp), 1);
+ return buffer[0];
+ }
+ }
+
+ /// <summary>
+ /// Convert UNICODE string to ANSI ByVal string.
+ /// </summary>
+ /// <remarks>This version is more efficient than StringToHGlobalAnsi in Interop\System\Runtime\InteropServices\Marshal.cs in that
+ /// it could allocate single byte per character, instead of SystemMaxDBCSCharSize per char, and it can skip calling WideCharToMultiByte for ASCII string</remarks>
+ /// <param name="str">Unicode string.</param>
+ /// <param name="pNative"> Allocated buffer where the ansi string must be placed. Could NOT be null. Buffer size must fit str.Length.</param>
+ [CLSCompliant(false)]
+ public static unsafe void StringToByValAnsiString(string str, byte* pNative, int charCount, bool bestFit, bool throwOnUnmappableChar)
+ {
+ if (pNative == null)
+ throw new ArgumentNullException();
+
+ if (str != null)
+ {
+ // Truncate the string if it is larger than specified by SizeConst
+ int lenUnicode = str.Length;
+ if (lenUnicode >= charCount)
+ lenUnicode = charCount - 1;
+
+ fixed (char* pManaged = str)
+ {
+ StringToAnsiString(pManaged, lenUnicode, pNative, /*terminateWithNull=*/true, bestFit, throwOnUnmappableChar);
+ }
+ }
+ else
+ {
+ (*pNative) = (byte)'\0';
+ }
+ }
+
+ /// <summary>
+ /// Convert ANSI string to unicode string, with option to free native memory. Calls generated by MCG
+ /// </summary>
+ /// <remarks>Input assumed to be zero terminated. Generates String.Empty for zero length string.
+ /// This version is more efficient than ConvertToUnicode in src\Interop\System\Runtime\InteropServices\Marshal.cs in that it can skip calling
+ /// MultiByteToWideChar for ASCII string, and it does not need another char[] buffer</remarks>
+ [CLSCompliant(false)]
+ public static unsafe string ByValAnsiStringToString(byte* pchBuffer, int charCount)
+ {
+ // Match desktop CLR behavior
+ if (charCount == 0)
+ throw new MarshalDirectiveException();
+
+ int lenAnsi = GetAnsiStringLen(pchBuffer);
+ int lenUnicode = charCount;
+
+ string result = String.Empty;
+
+ if (lenUnicode > 0)
+ {
+ char* unicodeBuf = stackalloc char[lenUnicode];
+ int unicodeCharWritten = ExternalInterop.ConvertMultiByteToWideChar(new System.IntPtr(pchBuffer),
+ lenAnsi,
+ new System.IntPtr(unicodeBuf),
+ lenUnicode);
+
+ // If conversion failure, return empty string to match desktop CLR behavior
+ if (unicodeCharWritten > 0)
+ result = new string(unicodeBuf, 0, unicodeCharWritten);
+ }
+
+ return result;
+ }
+
+ private static unsafe int GetAnsiStringLen(byte* pchBuffer)
+ {
+ byte* pchBufferOriginal = pchBuffer;
+ while (*pchBuffer != 0)
+ {
+ pchBuffer++;
+ }
+
+ return (int)(pchBuffer - pchBufferOriginal);
+ }
+
+ // c# string (UTF-16) to UTF-8 encoded byte array
+ private static unsafe byte* StringToAnsiString(char* pManaged, int lenUnicode, byte* pNative, bool terminateWithNull,
+ bool bestFit, bool throwOnUnmappableChar)
+ {
+ bool allAscii = true;
+
+ for (int i = 0; i < lenUnicode; i++)
+ {
+ if (pManaged[i] >= 128)
+ {
+ allAscii = false;
+ break;
+ }
+ }
+
+ int length;
+
+ if (allAscii) // If all ASCII, map one UNICODE character to one ANSI char
+ {
+ length = lenUnicode;
+ }
+ else // otherwise, let OS count number of ANSI chars
+ {
+ length = ExternalInterop.GetByteCount(pManaged, lenUnicode);
+ }
+
+ if (pNative == null)
+ {
+ pNative = (byte*)ExternalInterop.CoTaskMemAlloc((System.IntPtr)(length + 1));
+ }
+ if (allAscii) // ASCII conversion
+ {
+ byte* pDst = pNative;
+ char* pSrc = pManaged;
+
+ while (lenUnicode > 0)
+ {
+ unchecked
+ {
+ *pDst++ = (byte)(*pSrc++);
+ lenUnicode--;
+ }
+ }
+ }
+ else // Let OS convert
+ {
+ uint flags = (bestFit ? 0 : ExternalInterop.Constants.WC_NO_BEST_FIT_CHARS);
+ int defaultCharUsed = 0;
+ ExternalInterop.ConvertWideCharToMultiByte(pManaged,
+ lenUnicode,
+ new System.IntPtr(pNative),
+ length,
+ flags,
+ throwOnUnmappableChar ? new System.IntPtr(&defaultCharUsed) : default(IntPtr)
+ );
+ if (defaultCharUsed != 0)
+ {
+ throw new ArgumentException(SR.Arg_InteropMarshalUnmappableChar);
+ }
+ }
+
+ // Zero terminate
+ if (terminateWithNull)
+ *(pNative + length) = 0;
+
+ return pNative;
+ }
+
+ /// <summary>
+ /// This is a auxiliary function that counts the length of the ansi buffer and
+ /// estimate the length of the buffer in Unicode. It returns true if all bytes
+ /// in the buffer are ANSII.
+ /// </summary>
+ private static unsafe bool CalculateStringLength(byte* pchBuffer, out int ansiBufferLen, out int unicodeBufferLen)
+ {
+ ansiBufferLen = 0;
+
+ bool allAscii = true;
+
+ {
+ byte* p = pchBuffer;
+ byte b = *p++;
+
+ while (b != 0)
+ {
+ if (b >= 128)
+ {
+ allAscii = false;
+ }
+
+ ansiBufferLen++;
+
+ b = *p++;
+ }
+ }
+
+ if (allAscii)
+ {
+ unicodeBufferLen = ansiBufferLen;
+ }
+ else // If non ASCII, let OS calculate number of characters
+ {
+ unicodeBufferLen = ExternalInterop.GetCharCount(new IntPtr(pchBuffer), ansiBufferLen);
+ }
+ return allAscii;
+ }
+
+#endif
+
+#if ENABLE_WINRT
+ /// <summary>
+ /// Creates a temporary HSTRING on the staack
+ /// NOTE: pchPinnedSourceString must be pinned before calling this function, making sure the pointer
+ /// is valid during the entire interop call
+ /// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static unsafe void StringToHStringReference(
+ char *pchPinnedSourceString,
+ string sourceString,
+ HSTRING_HEADER* pHeader,
+ HSTRING* phString)
+ {
+ if (sourceString == null)
+ throw new ArgumentNullException(SR.Null_HString);
+
+ int hr = ExternalInterop.WindowsCreateStringReference(
+ pchPinnedSourceString,
+ (uint)sourceString.Length,
+ pHeader,
+ (void**)phString);
+
+ if (hr < 0)
+ throw Marshal.GetExceptionForHR(hr);
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static unsafe HSTRING StringToHString(string sourceString)
+ {
+ if (sourceString == null)
+ throw new ArgumentNullException(SR.Null_HString);
+
+ return StringToHStringInternal(sourceString);
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static unsafe HSTRING StringToHStringForField(string sourceString)
+ {
+#if !RHTESTCL
+ if (sourceString == null)
+ throw new MarshalDirectiveException(SR.BadMarshalField_Null_HString);
+#endif
+ return StringToHStringInternal(sourceString);
+ }
+
+ private static unsafe HSTRING StringToHStringInternal(string sourceString)
+ {
+ HSTRING ret;
+ int hr = StringToHStringNoNullCheck(sourceString, &ret);
+ if (hr < 0)
+ throw Marshal.GetExceptionForHR(hr);
+
+ return ret;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ internal static unsafe int StringToHStringNoNullCheck(string sourceString, HSTRING* hstring)
+ {
+ fixed (char* pChars = sourceString)
+ {
+ int hr = ExternalInterop.WindowsCreateString(pChars, (uint)sourceString.Length, (void*)hstring);
+
+ return hr;
+ }
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ internal static unsafe string HStringToString(IntPtr hString)
+ {
+ HSTRING hstring = new HSTRING(hString);
+ return HStringToString(hstring);
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static unsafe string HStringToString(HSTRING pHString)
+ {
+ if (pHString.handle == IntPtr.Zero)
+ {
+ return String.Empty;
+ }
+
+ uint length = 0;
+ char* pchBuffer = ExternalInterop.WindowsGetStringRawBuffer(pHString.handle.ToPointer(), &length);
+
+ return new string(pchBuffer, 0, (int)length);
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static unsafe void FreeHString(IntPtr pHString)
+ {
+ ExternalInterop.WindowsDeleteString(pHString.ToPointer());
+ }
+#endif //ENABLE_WINRT
+
+ #endregion
+
+ #region COM marshalling
+
+ /// <summary>
+ /// Explicit AddRef for RCWs
+ /// You can't call IFoo.AddRef anymore as IFoo no longer derive from IUnknown
+ /// You need to call McgMarshal.AddRef();
+ /// </summary>
+ /// <remarks>
+ /// Used by prefast MCG plugin (mcgimportpft) only
+ /// </remarks>
+ [CLSCompliant(false)]
+ public static int AddRef(__ComObject obj)
+ {
+ return obj.AddRef();
+ }
+
+ /// <summary>
+ /// Explicit Release for RCWs
+ /// You can't call IFoo.Release anymore as IFoo no longer derive from IUnknown
+ /// You need to call McgMarshal.Release();
+ /// </summary>
+ /// <remarks>
+ /// Used by prefast MCG plugin (mcgimportpft) only
+ /// </remarks>
+ [CLSCompliant(false)]
+ public static int Release(__ComObject obj)
+ {
+ return obj.Release();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public unsafe static int ComAddRef(IntPtr pComItf)
+ {
+ return CalliIntrinsics.StdCall__AddRef(((__com_IUnknown*)(void*)pComItf)->pVtable->
+ pfnAddRef, pComItf);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal unsafe static int ComRelease_StdCall(IntPtr pComItf)
+ {
+ return CalliIntrinsics.StdCall__Release(((__com_IUnknown*)(void*)pComItf)->pVtable->
+ pfnRelease, pComItf);
+ }
+
+ /// <summary>
+ /// Inline version of ComRelease
+ /// </summary>
+ [MethodImpl(MethodImplOptions.NoInlining)] //reduces MCG-generated code size
+ public unsafe static int ComRelease(IntPtr pComItf)
+ {
+ IntPtr pRelease = ((__com_IUnknown*)(void*)pComItf)->pVtable->pfnRelease;
+
+ // Check if the COM object is implemented by PN Interop code, for which we can call directly
+ if (pRelease == AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release))
+ {
+ return __interface_ccw.DirectRelease(pComItf);
+ }
+
+ // Normal slow path, do not inline
+ return ComRelease_StdCall(pComItf);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public unsafe static int ComSafeRelease(IntPtr pComItf)
+ {
+ if (pComItf != default(IntPtr))
+ {
+ return ComRelease(pComItf);
+ }
+
+ return 0;
+ }
+
+ /// <summary>
+ /// Returns the cached WinRT factory RCW under the current context
+ /// </summary>
+ [CLSCompliant(false)]
+ public static unsafe __ComObject GetActivationFactory(string className, McgTypeInfo factoryIntf)
+ {
+#if ENABLE_WINRT
+ return FactoryCache.Get().GetActivationFactory(className, factoryIntf);
+#else
+ throw new PlatformNotSupportedException("GetActivationFactory");
+#endif
+ }
+
+ /// <summary>
+ /// Used by CCW infrastructure code to return the target object from this pointer
+ /// </summary>
+ /// <returns>The target object pointed by this pointer</returns>
+ public static object ThisPointerToTargetObject(IntPtr pUnk)
+ {
+ return ComCallableObject.GetTarget(pUnk);
+ }
+
+ [CLSCompliant(false)]
+ public static object ComInterfaceToObject(
+ IntPtr pComItf,
+ McgTypeInfo interfaceTypeInfo)
+ {
+ return ComInterfaceToObject(pComItf, interfaceTypeInfo, McgClassInfo.Null);
+ }
+
+ [CLSCompliant(false)]
+ public static object ComInterfaceToObject_NoUnboxing(
+ IntPtr pComItf,
+ McgTypeInfo interfaceTypeInfo)
+ {
+ return McgComHelpers.ComInterfaceToObjectInternal(pComItf, interfaceTypeInfo, McgClassInfo.Null, McgComHelpers.CreateComObjectFlags.SkipTypeResolutionAndUnboxing);
+ }
+
+ [CLSCompliant(false)]
+ public static object ComInterfaceToObject(
+ IntPtr pComItf,
+ McgTypeInfo interfaceTypeInfo,
+ McgClassInfo classInfoInSignature)
+ {
+ object result = McgComHelpers.ComInterfaceToObjectInternal(pComItf, interfaceTypeInfo, classInfoInSignature, McgComHelpers.CreateComObjectFlags.None);
+
+ //
+ // Make sure the type we returned is actually of the right type
+ // NOTE: Don't pass null to IsInstanceOfClass as it'll return false
+ //
+ if (!classInfoInSignature.IsNull && result != null)
+ {
+ if (!InteropExtensions.IsInstanceOfClass(result, classInfoInSignature.ClassType))
+ throw new InvalidCastException();
+ }
+
+ return result;
+ }
+
+ public unsafe static IntPtr ComQueryInterfaceNoThrow(IntPtr pComItf, ref Guid iid)
+ {
+ int hr = 0;
+ return ComQueryInterfaceNoThrow(pComItf, ref iid, out hr);
+ }
+
+ public unsafe static IntPtr ComQueryInterfaceNoThrow(IntPtr pComItf, ref Guid iid, out int hr)
+ {
+ IntPtr pComIUnk;
+ hr = ComQueryInterfaceWithHR(pComItf, ref iid, out pComIUnk);
+
+ return pComIUnk;
+ }
+
+ internal unsafe static int ComQueryInterfaceWithHR(IntPtr pComItf, ref Guid iid, out IntPtr ppv)
+ {
+ IntPtr pComIUnk;
+ int hr;
+
+ fixed (Guid* unsafe_iid = &iid)
+ {
+ hr = CalliIntrinsics.StdCall__QueryInterface(((__com_IUnknown*)(void*)pComItf)->pVtable->
+ pfnQueryInterface,
+ pComItf,
+ new IntPtr(unsafe_iid),
+ new IntPtr(&pComIUnk));
+ }
+
+ if (hr != 0)
+ {
+ ppv = default(IntPtr);
+ }
+ else
+ {
+ ppv = pComIUnk;
+ }
+
+ return hr;
+ }
+
+ /// <summary>
+ /// Helper function to copy vTable to native heap on CoreCLR.
+ /// </summary>
+ /// <typeparam name="T">Vtbl type</typeparam>
+ /// <param name="pVtbl">static v-table field , always a valid pointer</param>
+ /// <param name="pNativeVtbl">Pointer to Vtable on native heap on CoreCLR , on N it's an alias for pVtbl</param>
+ public static unsafe IntPtr GetCCWVTableCopy(void* pVtbl, ref IntPtr pNativeVtbl, int size)
+ {
+ if (pNativeVtbl == default(IntPtr))
+ {
+#if CORECLR
+ // On CoreCLR copy vTable to native heap , on N VTable is frozen.
+ IntPtr pv = Marshal.AllocHGlobal(size);
+
+ int* pSrc = (int*)pVtbl;
+ int* pDest = (int*)pv.ToPointer();
+ int pSize = sizeof(int);
+
+ // this should never happen , if a CCW is discarded we never get here.
+ Debug.Assert(size >= pSize);
+ for (int i = 0; i < size; i += pSize)
+ {
+ *pDest++ = *pSrc++;
+ }
+ if (Interlocked.CompareExchange(ref pNativeVtbl, pv, default(IntPtr)) != default(IntPtr))
+ {
+ // Another thread sneaked-in and updated pNativeVtbl , just use the update from other thread
+ Marshal.FreeHGlobal(pv);
+ }
+#else // .NET NATIVE
+ // Wrap it in an IntPtr
+ pNativeVtbl = (IntPtr)pVtbl;
+#endif // CORECLR
+ }
+ return pNativeVtbl;
+ }
+
+
+
+
+ [CLSCompliant(false)]
+ public static IntPtr ObjectToComInterface(Object obj, McgTypeInfo typeInfo)
+ {
+ return McgComHelpers.ObjectToComInterfaceInternal(obj, typeInfo);
+ }
+
+ public static IntPtr ObjectToIInspectable(Object obj)
+ {
+#if ENABLE_WINRT
+ return ObjectToComInterface(obj, McgModuleManager.IInspectable);
+#else
+ throw new PlatformNotSupportedException("ObjectToIInspectable");
+#endif
+ }
+
+#if ENABLE_WINRT
+#if !RHTESTCL
+ [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
+#endif
+ /// <summary>
+ /// Get outer IInspectable for managed object deriving from native scenario
+ /// At this point the inner is not created yet - you need the outer first and pass it to the factory
+ /// to create the inner
+ /// </summary>
+ [CLSCompliant(false)]
+ public static IntPtr GetOuterIInspectableForManagedObject(__ComObject managedObject)
+ {
+ ComCallableObject ccw = null;
+
+ try
+ {
+ //
+ // Create the CCW over the RCW
+ // Note that they are actually both the same object
+ // Base class = inner
+ // Derived class = outer
+ //
+ ccw = new ComCallableObject(
+ managedObject, // The target object = managedObject
+ managedObject // The inner RCW (as __ComObject) = managedObject
+ );
+
+ //
+ // Retrieve the outer IInspectable
+ // Pass skipInterfaceCheck = true to avoid redundant checks
+ //
+ return ccw.GetComInterfaceForTypeInfo_NoCheck(McgModuleManager.IInspectable);
+ }
+ finally
+ {
+ //
+ // Free the extra ref count initialized by __native_ccw.Init (to protect the CCW from being collected)
+ //
+ if (ccw != null)
+ ccw.Release();
+ }
+ }
+#endif
+
+ [CLSCompliant(false)]
+ public static unsafe IntPtr ManagedObjectToComInterface(Object obj, McgTypeInfo itfTypeInfo)
+ {
+ return McgComHelpers.ManagedObjectToComInterface(obj, itfTypeInfo);
+ }
+
+ public static unsafe object IInspectableToObject(IntPtr pComItf)
+ {
+ return ComInterfaceToObject(pComItf, McgModuleManager.IInspectable, McgClassInfo.Null);
+ }
+
+ public static unsafe IntPtr CreateInstanceFromApp(Guid clsid)
+ {
+#if ENABLE_WINRT
+ Interop.COM.MULTI_QI results;
+ IntPtr pResults = new IntPtr(&results);
+ fixed (Guid* pIID = &Interop.COM.IID_IUnknown)
+ {
+ Guid* pClsid = &clsid;
+
+ results.pIID = new IntPtr(pIID);
+ results.pItf = IntPtr.Zero;
+ results.hr = 0;
+ int hr = ExternalInterop.CoCreateInstanceFromApp(pClsid, IntPtr.Zero, 0x15 /* (CLSCTX_SERVER) */, IntPtr.Zero, 1, pResults);
+ if (hr < 0)
+ {
+ throw McgMarshal.GetExceptionForHR(hr, /*isWinRTScenario = */ false);
+ }
+ if (results.hr < 0)
+ {
+ throw McgMarshal.GetExceptionForHR(results.hr, /* isWinRTScenario = */ false);
+ }
+ return results.pItf;
+ }
+#else
+ throw new PlatformNotSupportedException("CreateInstanceFromApp");
+#endif
+ }
+
+#endregion
+
+#region Testing
+
+ /// <summary>
+ /// Internal-only method to allow testing of apartment teardown code
+ /// </summary>
+ public static void ReleaseRCWsInCurrentApartment()
+ {
+ ContextEntry.RemoveCurrentContext();
+ }
+
+ /// <summary>
+ /// Used by detecting leaks
+ /// Used in prefast MCG only
+ /// </summary>
+ public static int GetTotalComObjectCount()
+ {
+ return ComObjectCache.s_comObjectMap.Count;
+ }
+
+ /// <summary>
+ /// Used by detecting and dumping leaks
+ /// Used in prefast MCG only
+ /// </summary>
+ public static IEnumerable<__ComObject> GetAllComObjects()
+ {
+ List<__ComObject> list = new List<__ComObject>();
+ for (int i = 0; i < ComObjectCache.s_comObjectMap.GetMaxCount(); ++i)
+ {
+ IntPtr pHandle = default(IntPtr);
+ if (ComObjectCache.s_comObjectMap.GetValue(i, ref pHandle) && (pHandle != default(IntPtr)))
+ {
+ GCHandle handle = GCHandle.FromIntPtr(pHandle);
+ list.Add(InteropExtensions.UncheckedCast<__ComObject>(handle.Target));
+ }
+ }
+
+ return list;
+ }
+
+#endregion
+
+ /// <summary>
+ /// This method returns HR for the exception being thrown.
+ /// 1. On Windows8+, WinRT scenarios we do the following.
+ /// a. Check whether the exception has any IRestrictedErrorInfo associated with it.
+ /// If so, it means that this exception was actually caused by a native exception in which case we do simply use the same
+ /// message and stacktrace.
+ /// b. If not, this is actually a managed exception and in this case we RoOriginateLanguageException with the msg, hresult and the IErrorInfo
+ /// aasociated with the managed exception. This helps us to retrieve the same exception in case it comes back to native.
+ /// 2. On win8 and for classic COM scenarios.
+ /// a. We create IErrorInfo for the given Exception object and SetErrorInfo with the given IErrorInfo.
+ /// </summary>
+ /// <param name="ex"></param>
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static int GetHRForExceptionWinRT(Exception ex)
+ {
+#if ENABLE_WINRT
+ return ExceptionHelpers.GetHRForExceptionWithErrorPropogationNoThrow(ex, true);
+#else
+ // TODO : ExceptionHelpers should be platform specific , move it to
+ // seperate source files
+ return 0;
+ //return Marshal.GetHRForException(ex);
+#endif
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static int GetHRForException(Exception ex)
+ {
+#if ENABLE_WINRT
+ return ExceptionHelpers.GetHRForExceptionWithErrorPropogationNoThrow(ex, false);
+#else
+ return ex.HResult;
+#endif
+ }
+
+ /// <summary>
+ /// This method returns a new Exception object given the HR value.
+ /// </summary>
+ /// <param name="hr"></param>
+ /// <param name="isWinRTScenario"></param>
+ public static Exception GetExceptionForHR(int hr, bool isWinRTScenario)
+ {
+#if ENABLE_WINRT
+ return ExceptionHelpers.GetExceptionForHRInternalNoThrow(hr, isWinRTScenario, !isWinRTScenario);
+#else
+ return new COMException(hr.ToString());
+#endif
+ }
+
+ #region Shared templates
+#if ENABLE_WINRT
+ public static void CleanupNative<T>(IntPtr pObject)
+ {
+ if (typeof(T) == typeof(string))
+ {
+ global::System.Runtime.InteropServices.McgMarshal.FreeHString(pObject);
+ }
+ else
+ {
+ global::System.Runtime.InteropServices.McgMarshal.ComSafeRelease(pObject);
+ }
+ }
+#endif
+ #endregion
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgMethodNameAttribute.cs b/src/System.Private.Interop/src/Shared/McgMethodNameAttribute.cs
new file mode 100644
index 000000000..6fbcfcd43
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgMethodNameAttribute.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// In the case of a WinRT name conflict, methods are renamed to something like the following:
+ /// IObservableVector`1<Foo>.GetAt
+ /// C# obviously doesn't like this syntax. In MCG, we had to choose a different name, encode the real
+ /// name in this attribute, and later rename the method in a IL transform
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+ public sealed class McgMethodNameAttribute : Attribute
+ {
+ public McgMethodNameAttribute(string realName)
+ {
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgModule.cs b/src/System.Private.Interop/src/Shared/McgModule.cs
new file mode 100644
index 000000000..c3846511e
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgModule.cs
@@ -0,0 +1,1745 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// ----------------------------------------------------------------------------------
+// Interop library code
+//
+// Contains McgModule and various data that describes interop information for types
+// seen by MCG. These data will be used at runtime for MCG to make runtime decisions
+// during marshalling.
+//
+// NOTE:
+// These source code are being published to InternalAPIs and consumed by RH builds
+// Use PublishInteropAPI.bat to keep the InternalAPI copies in sync
+// ---------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Text;
+using System.Runtime;
+using System.Diagnostics.Contracts;
+using Internal.NativeFormat;
+using Internal.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Module-level operations such as looking up strongly-typed RCWs
+ /// NOTE: This interface is not CLS compliant but it is only used in Mcg output which is C#
+ /// </summary>
+ [CLSCompliant(false)]
+ public unsafe abstract partial class McgModule
+ {
+ int m_mcgDataModulePriority; // access priority for this module in McgModuleManager
+
+ StringPool m_stringPool; // Compressed strings
+
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "m_interfaceData" and field type must be McgInterfaceData[]
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::WalkTypeInfo in debug\dbi\values.cpp
+ /// </summary>
+ McgInterfaceData[] m_interfaceData;
+ CCWTemplateData[] m_ccwTemplateData; // All CCWTemplateData is saved here
+ RuntimeTypeHandle [] m_supportedInterfaceList; // List of supported interfaces type handle
+ // CCWTemplateData
+ McgClassData[] m_classData; // Used for TypeName marshalling and for CreateComObject.
+ // Contains entries for WinRT classes and for interfaces
+ // projected as value types (i.e. Nullable<T>/KeyValuePair<K,V>)
+ McgBoxingData[] m_boxingData;
+ McgAdditionalClassData[] m_additionalClassData; // Additional class data that captures parent
+ // child relationship
+ McgCollectionData[] m_collectionData; // Maps from an ICollection or IReadOnlyCollection type to
+ // the corresponding entries in m_interfaceTypeInfo for IList,
+ // IDictionary, IReadOnlyList, IReadOnlyDictionary
+ McgPInvokeDelegateData[] m_pinvokeDelegateData; // List of pinvoke delegates
+ McgCCWFactoryInfoEntry[] m_ccwFactories; // List of CCW factories provided to native via DllGetActivationFactory
+ McgStructMarshalData[] m_structMarshalData; // List of struct marshalling data for Marshal APIs
+ McgUnsafeStructFieldOffsetData[] m_unsafeStructOffsetData;
+ McgGenericArgumentMarshalInfo[] m_genericArgumentMarshalInfo; // Array of generic argument marshal information for shared CCW
+ McgHashcodeVerifyEntry[] m_hashcodeVerifyData;
+#if CORECLR
+ private object m_DictionaryLock = new object();
+ Dictionary<RuntimeTypeHandle, int> m_interfaceTypeInfo_Hashtable;
+ Dictionary<RuntimeTypeHandle, int> m_ccwTemplateData_Hashtable;
+ Dictionary<RuntimeTypeHandle, int> m_classData_Hashtable;
+ Dictionary<RuntimeTypeHandle, int> m_collectionData_Hashtable;
+ Dictionary<RuntimeTypeHandle, int> m_typeNameMarshalingData_Hashtable;
+ Dictionary<RuntimeTypeHandle, int> m_boxingData_Hashtable;
+#else
+ NativeReader m_interfaceTypeInfo_Hashtable;
+ NativeReader m_ccwTemplateData_Hashtable;
+ NativeReader m_classData_Hashtable;
+ NativeReader m_collectionData_Hashtable;
+ NativeReader m_boxingData_Hashtable;
+#endif
+
+#if DEBUG
+ bool m_hashcodesVerified;
+#endif // DEBUG
+
+ FixedHashTable m_guidMap;
+
+#if CORECLR
+ Dictionary<RuntimeTypeHandle, int> InitializeLookupHashTable(Func<int, RuntimeTypeHandle> getEntryTypeHandle,
+ Func<int> getTableSize)
+ {
+ int tableSize = getTableSize();
+ Dictionary<RuntimeTypeHandle, int> hashtable = new Dictionary<RuntimeTypeHandle, int>();
+ for (int tableIndex = 0; tableIndex < tableSize; tableIndex++)
+ {
+ RuntimeTypeHandle handle = getEntryTypeHandle(tableIndex);
+ hashtable[handle] = tableIndex;
+ }
+ return hashtable;
+ }
+
+ // Build the lookup hashtable on the go since MCG can't generate table index lookup hashtable for CoreCLR.
+ // We aggressively cache everything on first lookup
+ int LookupTypeHandleInHashtable(
+ RuntimeTypeHandle typeHandle,
+ ref Dictionary<RuntimeTypeHandle, int> hashtable,
+ Func<int, RuntimeTypeHandle> getEntryTypeHandle,
+ Func<int> getTableSize)
+ {
+ if (hashtable == null)
+ {
+ Dictionary<RuntimeTypeHandle, int> lookupTable = InitializeLookupHashTable(getEntryTypeHandle, getTableSize);
+ if (Interlocked.CompareExchange(ref hashtable, lookupTable, null) != null)
+ {
+ // Another thread beat us to it , use the one from that thread
+ lookupTable = null;
+ }
+ }
+
+ int tableIndex;
+ if (hashtable.TryGetValue(typeHandle, out tableIndex))
+ return tableIndex;
+
+ // should never get here
+ return -1;
+ }
+
+#else
+ // The hashtables generated by MCG map from a RuntimeTypeHandle hashcode to a bucket of table indexes.
+ // These indexes are used to lookup an entry in a corresponding MCG-generated table. The table entry
+ // must also contain a RuntimeTypeHandle that uniquely identifies it. The getEntryTypeHandle delegate
+ // is used to perform this lookup for the specific MCG-generated table.
+ unsafe int LookupTypeHandleInHashtable(
+ RuntimeTypeHandle typeHandle,
+ ref NativeReader hashtable,
+ Func<int, RuntimeTypeHandle> getEntryTypeHandle,
+ Func<int> getTableSize)
+ {
+#if DEBUG
+ if (!m_hashcodesVerified)
+ {
+ bool allVerified = this.VerifyHashCodes();
+ Debug.Assert(allVerified);
+ m_hashcodesVerified = true;
+ }
+#endif // DEBUG
+
+ // Not all McgModules provide all hashtables. A notable exception is the 'internal' module.
+ // However, one could imagine if a particular compilation unit didn't have any entries in a table
+ // it could also have a null hashtable (instead of an empty hashtable).
+ if (hashtable == null)
+ return -1;
+
+ var htParser = new NativeParser(hashtable, 0);
+ var ht = new NativeHashtable(htParser);
+
+ NativeParser entryParser;
+ var enumBucket = ht.Lookup(typeHandle.GetHashCode());
+ while (!(entryParser = enumBucket.GetNext()).IsNull)
+ {
+ int tableIndex = (int)entryParser.GetUnsigned();
+ if (getEntryTypeHandle(tableIndex).Equals(typeHandle))
+ {
+ return tableIndex;
+ }
+ }
+ return -1;
+ }
+#endif
+
+
+
+ /// <summary>
+ /// Interface lookup on m_interfaceTypeInfo array using on-demand generated hash table
+ /// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ int InterfaceDataLookup(RuntimeTypeHandle typeHandle)
+ {
+ return LookupTypeHandleInHashtable(
+ typeHandle,
+ ref m_interfaceTypeInfo_Hashtable,
+ m_interfaceDataLookup_GetEntryTypeHandleCallback,
+ m_interfaceDataLookup_GetTableSizeCallback);
+ }
+
+ private Func<int, RuntimeTypeHandle> m_interfaceDataLookup_GetEntryTypeHandleCallback;
+ private Func<int> m_interfaceDataLookup_GetTableSizeCallback;
+
+ RuntimeTypeHandle InterfaceDataLookup_GetEntryTypeHandle(int index)
+ {
+ return m_interfaceData[index].ItfType;
+ }
+
+ int InterfaceDataLookup_GetTableSize()
+ {
+ return m_interfaceData.Length;
+ }
+
+ int CollectionDataLookup(RuntimeTypeHandle typeHandle)
+ {
+ return LookupTypeHandleInHashtable(
+ typeHandle,
+ ref m_collectionData_Hashtable,
+ m_collectionDataLookup_GetEntryTypeHandleCallback,
+ m_collectionDataLookup_GetTableSizeCallback);
+ }
+
+ private Func<int, RuntimeTypeHandle> m_collectionDataLookup_GetEntryTypeHandleCallback;
+ private Func<int> m_collectionDataLookup_GetTableSizeCallback;
+
+ RuntimeTypeHandle CollectionDataLookup_GetEntryTypeHandle(int index)
+ {
+ return m_collectionData[index].CollectionType;
+ }
+
+ int CollectionDataLookup_GetTableSize()
+ {
+ return m_collectionData.Length;
+ }
+
+ int ClassDataLookup(RuntimeTypeHandle typeHandle)
+ {
+ return LookupTypeHandleInHashtable(
+ typeHandle,
+ ref m_classData_Hashtable,
+ m_classData_GetEntryTypeHandleCallback,
+ m_classData_GetTableSizeCallback);
+ }
+
+ private Func<int, RuntimeTypeHandle> m_classData_GetEntryTypeHandleCallback;
+ private Func<int> m_classData_GetTableSizeCallback;
+
+ RuntimeTypeHandle ClassDataLookup_GetEntryTypeHandle(int index)
+ {
+ return m_classData[index].ClassType;
+ }
+
+ int ClassDataLookup_GetTableSize()
+ {
+ return m_classData.Length;
+ }
+
+ int BoxingDataLookup(RuntimeTypeHandle typeHandle)
+ {
+ return LookupTypeHandleInHashtable(
+ typeHandle,
+ ref m_boxingData_Hashtable,
+ m_boxingDataLookup_GetEntryTypeHandleCallback,
+ m_boxingDataLookup_GetTableSizeCallback);
+ }
+
+ private Func<int, RuntimeTypeHandle> m_boxingDataLookup_GetEntryTypeHandleCallback;
+ private Func<int> m_boxingDataLookup_GetTableSizeCallback;
+
+ RuntimeTypeHandle BoxingDataLookup_GetEntryTypeHandle(int index)
+ {
+ return m_boxingData[index].ManagedClassType;
+ }
+
+ int BoxingDataLookup_GetTableSize()
+ {
+ return m_boxingData.Length;
+ }
+
+ /// <summary>
+ /// Returns the corresponding CCW template index for the specified type
+ /// </summary>
+ /// <returns>index if the type is found. -1 if it is not a known type in current module</returns>
+ internal int CCWTemplateDataLookup(RuntimeTypeHandle typeHandle)
+ {
+ return LookupTypeHandleInHashtable(
+ typeHandle,
+ ref m_ccwTemplateData_Hashtable,
+ m_CCWTemplateDataLookup_GetEntryTypeHandleCallback,
+ m_CCWTemplateDataLookup_GetTableSizeCallback);
+
+ }
+
+ private Func<int, RuntimeTypeHandle> m_CCWTemplateDataLookup_GetEntryTypeHandleCallback;
+ private Func<int> m_CCWTemplateDataLookup_GetTableSizeCallback;
+
+ RuntimeTypeHandle CCWTemplateDataLookup_GetEntryTypeHandle(int index)
+ {
+ return m_ccwTemplateData[index].ClassType;
+ }
+
+ int CCWTemplateDataLookup_GetTableSize()
+ {
+ return m_ccwTemplateData == null ? 0 : m_ccwTemplateData.Length;
+ }
+
+ public static readonly RuntimeTypeHandle s_DependencyReductionTypeRemovedTypeHandle =
+ typeof(DependencyReductionTypeRemoved).TypeHandle;
+
+ /// <summary>
+ /// Construct McgModule
+ /// </summary>
+ public unsafe McgModule(
+ int mcgDataModulePriority,
+ McgInterfaceData[] interfaceData,
+ CCWTemplateData[] ccwTemplateData,
+ FixupRuntimeTypeHandle[] supportedInterfaceList,
+ McgClassData[] classData,
+ McgBoxingData[] boxingData,
+ McgAdditionalClassData[] additionalClassData,
+ McgCollectionData[] collectionData,
+ McgPInvokeDelegateData[] pinvokeDelegateData,
+ McgCCWFactoryInfoEntry[] ccwFactories,
+ McgStructMarshalData[] structMarshalData,
+ McgUnsafeStructFieldOffsetData[] unsafeStructFieldOffsetData,
+ McgGenericArgumentMarshalInfo[] genericArgumentMarshalInfo,
+ McgHashcodeVerifyEntry[] hashcodeVerifyData,
+ byte[] interfaceTypeInfo_Hashtable,
+ byte[] ccwTemplateData_Hashtable,
+ byte[] classData_Hashtable,
+ byte[] collectionData_Hashtable,
+ byte[] boxingData_Hashtable)
+ {
+ m_mcgDataModulePriority = mcgDataModulePriority;
+ m_interfaceData = interfaceData;
+ m_classData = classData;
+ m_boxingData = boxingData;
+ m_collectionData = collectionData;
+ m_pinvokeDelegateData = pinvokeDelegateData;
+ m_additionalClassData = additionalClassData;
+ m_ccwFactories = ccwFactories;
+ m_structMarshalData = structMarshalData;
+ m_unsafeStructOffsetData = unsafeStructFieldOffsetData;
+ m_genericArgumentMarshalInfo = genericArgumentMarshalInfo;
+
+ m_ccwTemplateData = ccwTemplateData;
+
+ // Following code is disabled due to lazy static constructor dependency from McgModule which is
+ // static eager constructor. Undo this when McgCurrentModule is using ModuleConstructorAttribute
+#if EAGER_CTOR_WORKAROUND
+ Debug.Assert(m_interfaceTypeInfo != null);
+#endif
+ if (supportedInterfaceList != null)
+ {
+ m_supportedInterfaceList = new RuntimeTypeHandle[supportedInterfaceList.Length];
+ for (int i = 0; i < supportedInterfaceList.Length; i++)
+ {
+ m_supportedInterfaceList[i] = supportedInterfaceList[i].RuntimeTypeHandle;
+ }
+ }
+ else
+ {
+ m_supportedInterfaceList = null;
+ }
+
+ m_hashcodeVerifyData = hashcodeVerifyData;
+#if CORECLR
+ // Will be Lazy intialized
+ m_interfaceTypeInfo_Hashtable = null;
+ m_ccwTemplateData_Hashtable = null;
+ m_classData_Hashtable = null;
+ m_collectionData_Hashtable = null;
+ m_typeNameMarshalingData_Hashtable = null;
+ m_boxingData_Hashtable = null;
+#else
+ m_interfaceTypeInfo_Hashtable = NewHashtableReader(interfaceTypeInfo_Hashtable);
+ m_ccwTemplateData_Hashtable = NewHashtableReader(ccwTemplateData_Hashtable);
+ m_classData_Hashtable = NewHashtableReader(classData_Hashtable);
+ m_collectionData_Hashtable = NewHashtableReader(collectionData_Hashtable);
+ m_boxingData_Hashtable = NewHashtableReader(boxingData_Hashtable);
+#endif
+
+ //
+ // Initialize cached instance delegates (we won't get that if you use lambda even though we only
+ // use instance member variables inside the lambda).
+ //
+ m_interfaceDataLookup_GetEntryTypeHandleCallback =
+ new Func<int, RuntimeTypeHandle>(this.InterfaceDataLookup_GetEntryTypeHandle);
+ m_interfaceDataLookup_GetTableSizeCallback =
+ new Func<int>(this.InterfaceDataLookup_GetTableSize);
+
+ m_collectionDataLookup_GetEntryTypeHandleCallback =
+ new Func<int, RuntimeTypeHandle>(this.CollectionDataLookup_GetEntryTypeHandle);
+ m_collectionDataLookup_GetTableSizeCallback =
+ new Func<int>(this.CollectionDataLookup_GetTableSize);
+
+ m_classData_GetEntryTypeHandleCallback =
+ new Func<int, RuntimeTypeHandle>(this.ClassDataLookup_GetEntryTypeHandle);
+ m_classData_GetTableSizeCallback =
+ new Func<int>(this.ClassDataLookup_GetTableSize);
+
+ m_boxingDataLookup_GetEntryTypeHandleCallback =
+ new Func<int, RuntimeTypeHandle>(this.BoxingDataLookup_GetEntryTypeHandle);
+ m_boxingDataLookup_GetTableSizeCallback =
+ new Func<int>(this.BoxingDataLookup_GetTableSize);
+
+ m_CCWTemplateDataLookup_GetEntryTypeHandleCallback =
+ new Func<int, RuntimeTypeHandle>(this.CCWTemplateDataLookup_GetEntryTypeHandle);
+ m_CCWTemplateDataLookup_GetTableSizeCallback =
+ new Func<int>(this.CCWTemplateDataLookup_GetTableSize);
+
+#if DEBUG
+ // Check no duplicate RuntimeTypeHandle in hashtable
+ if (m_interfaceData != null)
+ {
+ System.Collections.Generic.Internal.HashSet<EquatableRuntimeTypeHandle> intfHashSet =
+ new System.Collections.Generic.Internal.HashSet<EquatableRuntimeTypeHandle>(m_interfaceData.Length);
+ foreach (McgInterfaceData item in m_interfaceData)
+ {
+ RuntimeTypeHandle typeHnd = item.ItfType;
+ if (!typeHnd.Equals(s_DependencyReductionTypeRemovedTypeHandle) && !typeHnd.Equals(default(RuntimeTypeHandle)))
+ {
+ if (intfHashSet.Add(new EquatableRuntimeTypeHandle(typeHnd), typeHnd.GetHashCode()))
+ {
+ Debug.Assert(false, "Duplicate RuntimeTypeHandle found in m_interfaceData");
+ }
+ }
+ }
+ }
+
+ if (m_classData != null)
+ {
+ System.Collections.Generic.Internal.HashSet<EquatableRuntimeTypeHandle> classHashSet =
+ new System.Collections.Generic.Internal.HashSet<EquatableRuntimeTypeHandle>(m_classData.Length);
+ foreach (McgClassData item in m_classData)
+ {
+ RuntimeTypeHandle typeHnd = item.ClassType;
+ if (!typeHnd.Equals(s_DependencyReductionTypeRemovedTypeHandle) && !typeHnd.Equals(default(RuntimeTypeHandle)))
+ {
+ if (classHashSet.Add(new EquatableRuntimeTypeHandle(typeHnd), typeHnd.GetHashCode()))
+ {
+ Debug.Assert(false, "Duplicate RuntimeTypeHandle found in m_classData");
+ }
+ }
+ }
+ }
+#endif
+ }
+
+ public int ModulePriority
+ {
+ get
+ {
+ return m_mcgDataModulePriority;
+ }
+ }
+
+ private NativeReader NewHashtableReader(byte[] dataArray)
+ {
+ if (dataArray == null)
+ return null;
+
+ fixed (byte* pData = dataArray) // WARNING: must be pre-initialized and, therefore, frozen in place
+ {
+ return new NativeReader(pData, (uint)dataArray.Length);
+ }
+ }
+
+ /// <summary>
+ /// Set thunk function for interface using shared ccwVtable (generic AddrOf not supported by initdata transform + NUTC)
+ /// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public void SetThunk(int index, IntPtr thunk)
+ {
+ m_interfaceData[index].CcwVtable = thunk;
+ }
+
+ /// <summary>
+ /// Set data for compressed strings
+ /// </summary>
+ public void SetStringPool(byte[] dictionary, byte[] strings, ushort[] index)
+ {
+ m_stringPool = new StringPool(dictionary, strings, index);
+ }
+
+ StringMap m_interfaceNameMap;
+ StringMap m_classNameMap;
+ StringMap m_additionalClassNameMap;
+ StringMap m_ccwTemplateDataNameMap;
+ StringMap m_ccwFactoriesNameMap;
+ StringMap m_boxingDataNameMap;
+ StringMap m_typeNameMarshalingDataNameMap;
+ StringMap m_unsafeStructFieldNameMap;
+
+ // There are two sets of functions here: one for 16-bit indices, good for 64k characters, the other for 32-bit indices for bigger applications
+ // MCG will generate the right calls for the right width.
+ // Functions not called will be trimmed away by DR
+
+ public void SetinterfaceDataNameIndices(UInt16[] nameIndices)
+ {
+ m_interfaceNameMap = new StringMap16(m_stringPool, nameIndices);
+ }
+
+ public void SetclassDataNameIndices(UInt16[] nameIndices)
+ {
+ m_classNameMap = new StringMap16(m_stringPool, nameIndices);
+ }
+
+ public void SetadditionalClassDataNameIndices(UInt16[] nameIndices)
+ {
+ m_additionalClassNameMap = new StringMap16(m_stringPool, nameIndices);
+ }
+
+ public void SetccwFactoriesNameIndices(UInt16[] nameIndices)
+ {
+ m_ccwFactoriesNameMap = new StringMap16(m_stringPool, nameIndices);
+ }
+
+ public void SetccwTemplateDataNameIndices(UInt16[] nameIndices)
+ {
+ m_ccwTemplateDataNameMap = new StringMap16(m_stringPool, nameIndices);
+ }
+
+ public void SetboxingDataNameIndices(UInt16[] nameIndices)
+ {
+ m_boxingDataNameMap = new StringMap16(m_stringPool, nameIndices);
+ }
+
+ public void SettypeNameMarshalingDataNameIndices(UInt16[] nameIndices)
+ {
+ m_typeNameMarshalingDataNameMap = new StringMap16(m_stringPool, nameIndices);
+ }
+
+ public void SetinterfaceDataNameIndices(UInt32[] nameIndices)
+ {
+ m_interfaceNameMap = new StringMap32(m_stringPool, nameIndices);
+ }
+
+ public void SetclassDataNameIndices(UInt32[] nameIndices)
+ {
+ m_classNameMap = new StringMap32(m_stringPool, nameIndices);
+ }
+
+ public void SetadditionalClassDataNameIndices(UInt32[] nameIndices)
+ {
+ m_additionalClassNameMap = new StringMap32(m_stringPool, nameIndices);
+ }
+
+ public void SetccwFactoriesNameIndices(UInt32[] nameIndices)
+ {
+ m_ccwFactoriesNameMap = new StringMap32(m_stringPool, nameIndices);
+ }
+
+ public void SetccwTemplateDataNameIndices(UInt32[] nameIndices)
+ {
+ m_ccwTemplateDataNameMap = new StringMap32(m_stringPool, nameIndices);
+ }
+
+ public void SetboxingDataNameIndices(UInt32[] nameIndices)
+ {
+ m_boxingDataNameMap = new StringMap32(m_stringPool, nameIndices);
+ }
+
+ public void SettypeNameMarshalingDataNameIndices(UInt32[] nameIndices)
+ {
+ m_typeNameMarshalingDataNameMap = new StringMap32(m_stringPool, nameIndices);
+ }
+
+ public void SetunsafeStructFieldOffsetDataNameIndices(UInt16[] nameIndices)
+ {
+ m_unsafeStructFieldNameMap = new StringMap16(m_stringPool, nameIndices);
+ }
+
+ public void SetunsafeStructFieldOffsetDataNameIndices(UInt32[] nameIndices)
+ {
+ m_unsafeStructFieldNameMap = new StringMap32(m_stringPool, nameIndices);
+ }
+
+ internal CCWTemplateData[] CCWTemplateData
+ {
+ get
+ {
+ return m_ccwTemplateData;
+ }
+ }
+
+ internal unsafe string GetRuntimeClassName(int ccwTemplateIndex)
+ {
+ return m_ccwTemplateDataNameMap.GetString(ccwTemplateIndex);
+ }
+
+ /// <summary>
+ /// Try to get offset data according to McgStructMarshalData's FieldOffsetStartIndex/NumOfFields
+ /// </summary>
+ /// <param name="structMarshalData">The Struct Marshal Data</param>
+ /// <param name="fieldName">Name of field</param>
+ /// <param name="offset">offset in bytes</param>
+ /// <returns>if the offset value exists, return true; else return false </returns>
+ internal bool TryGetStructFieldOffset(McgStructMarshalData structMarshalData, string fieldName, out uint offset)
+ {
+ // Try to find its field in map
+ if (m_unsafeStructFieldNameMap != null)
+ {
+ int start = structMarshalData.FieldOffsetStartIndex;
+ int count = structMarshalData.NumOfFields;
+
+ for (int i = start; i < start + count; i++)
+ {
+ if (fieldName == m_unsafeStructFieldNameMap.GetString(i))
+ {
+ offset = m_unsafeStructOffsetData[i].Offset;
+ return true;
+ }
+ }
+ }
+
+ // Couldn't find its field
+ offset = 0;
+ return false;
+ }
+
+ /// <summary>
+ /// Return the list of IIDs
+ /// Used by IInspectable.GetIIDs implementation for every CCW
+ /// </summary>
+ internal unsafe System.Collections.Generic.Internal.List<Guid> GetIIDs(int ccwTemplateDataIndex)
+ {
+ System.Collections.Generic.Internal.List<Guid> iids = new System.Collections.Generic.Internal.List<Guid>();
+
+ // Every CCW implements ICPP
+ iids.Add(Interop.COM.IID_ICustomPropertyProvider);
+
+ GetIIDsImpl(ccwTemplateDataIndex, iids);
+
+ return iids;
+ }
+
+ private void GetIIDsImpl(int index, System.Collections.Generic.Internal.List<Guid> iids)
+ {
+ //
+ // Go through the parent template first - this is important to match desktop CLR behavior
+ //
+ int parentIndex = m_ccwTemplateData[index].ParentCCWTemplateIndex;
+ RuntimeTypeHandle baseClassTypeHandle = m_ccwTemplateData[index].BaseType;
+
+ if (parentIndex >=0)
+ {
+ GetIIDsImpl(parentIndex, iids);
+ }
+ else if (!baseClassTypeHandle.Equals(default(RuntimeTypeHandle)))
+ {
+ Debug.Assert(!baseClassTypeHandle.Equals(s_DependencyReductionTypeRemovedTypeHandle));
+ CCWTemplateInfo template = McgModuleManager.GetCCWTemplateInfo(baseClassTypeHandle);
+ Debug.Assert(!template.IsNull);
+ template.ContainingModule.GetIIDsImpl(template.Index, iids);
+ }
+
+ //
+ // After we've collected IIDs from base templates, insert IIDs implemented by this class only
+ //
+ int start = m_ccwTemplateData[index].SupportedInterfaceListBeginIndex;
+ int end = start + m_ccwTemplateData[index].NumberOfSupportedInterface;
+ for (int i = start; i < end; i++)
+ {
+ //
+ // Retrieve the GUID and add it to the list
+ // Skip ICustomPropertyProvider - we've already added it as the first item
+ //
+ RuntimeTypeHandle typeHandle = m_supportedInterfaceList[i];
+
+ // TODO: if customer depends on the result of GetIIDs,
+ // then fix this by keeping these handle alive
+ if (IsInvalidTypeHandle(typeHandle))
+ continue;
+
+ McgTypeInfo typeInfo = McgModuleManager.GetTypeInfoByHandle(typeHandle);
+ Guid guid = typeInfo.ItfGuid;
+
+ if (!InteropExtensions.GuidEquals(ref guid, ref Interop.COM.IID_ICustomPropertyProvider))
+ {
+ //
+ // Avoid duplicated ones
+ //
+ // The duplicates comes from duplicated interface declarations in the metadata across
+ // parent/child classes, as well as the "injected" override interfaces for protected
+ // virtual methods (for example, if a derived class implements a IShapeInternal protected
+ // method, it only implements a protected method and doesn't implement IShapeInternal
+ // directly, and we have to "inject" it in MCG
+ //
+ // Doing a linear lookup is slow, but people typically never call GetIIDs perhaps except
+ // for debugging purposes (because the GUIDs returned back aren't exactly useful and you
+ // can't map it back to type), so I don't care about perf here that much
+ //
+ if (!iids.Contains(guid))
+ iids.Add(guid);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get McgInterfaceData entry as an McgTypeInfo
+ /// </summary>
+ /// <param name="index"></param>
+#if !RHTESTCL
+ [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
+#endif
+ internal unsafe McgTypeInfo GetTypeInfoByIndex_Inline(int index)
+ {
+ Debug.Assert((index >= 0) && (index < m_interfaceData.Length));
+
+ return new McgTypeInfo(index, this);
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ internal unsafe McgTypeInfo GetTypeInfoByHandle(RuntimeTypeHandle typeHnd)
+ {
+ int tableIndex = InterfaceDataLookup(typeHnd);
+ if (tableIndex >= 0)
+ {
+ return GetTypeInfoByIndex_Inline(tableIndex);
+ }
+
+ return McgTypeInfo.Null;
+ }
+
+ internal unsafe McgClassInfo GetClassInfoByHandle(RuntimeTypeHandle typeHnd)
+ {
+ int tableIndex = ClassDataLookup(typeHnd);
+ if (tableIndex >= 0)
+ {
+ return GetClassInfoByIndex(tableIndex);
+ }
+
+ return McgClassInfo.Null;
+ }
+
+ /// <summary>
+ /// Shared CCW marshalling T to native
+ /// </summary>
+ internal IntPtr ObjectToComInterface(object data, int marshalIndex)
+ {
+ RuntimeTypeHandle typeHandle = m_genericArgumentMarshalInfo[marshalIndex].ElementInterfaceType;
+#if ENABLE_WINRT
+ if (typeHandle.Equals(typeof(object).TypeHandle))
+ {
+ return McgMarshal.ObjectToIInspectable(data);
+ }
+
+ if (typeHandle.Equals(typeof(string).TypeHandle))
+ {
+ return McgMarshal.StringToHString((string)data).handle;
+ }
+#endif
+ return McgMarshal.ObjectToComInterface(data, McgModuleManager.GetTypeInfoByHandle(typeHandle));
+ }
+
+ /// <summary>
+ /// Shared CCW marhsalling IVector<T> to IVectorView<T>
+ /// </summary>
+ internal IntPtr MarshalToVectorView(object data, int marshalIndex)
+ {
+ RuntimeTypeHandle typeHandle = m_genericArgumentMarshalInfo[marshalIndex].VectorViewType;
+ if(IsInvalidTypeHandle(typeHandle))
+ {
+#if !RHTESTCL
+ Environment.FailFast(String.Format("VectorView typehandle for CCW Thunk Index {0} discarded", marshalIndex));
+#else
+ Environment.FailFast("VectorView typehandle discarded");
+#endif
+ }
+ return McgMarshal.ObjectToComInterface(data, McgModuleManager.GetTypeInfoByHandle(typeHandle));
+ }
+
+ /// <summary>
+ /// Shared CCW marhsalling IEnumerable<T>> to IIterator<T>
+ /// </summary>
+ internal IntPtr MarshalToIterator(object data, int marshalIndex)
+ {
+ RuntimeTypeHandle typeHandle = m_genericArgumentMarshalInfo[marshalIndex].IteratorType;
+ if (IsInvalidTypeHandle(typeHandle))
+ {
+#if !RHTESTCL
+ Environment.FailFast(String.Format("Iterator typehandle for CCW Thunk Index {0} discarded", marshalIndex));
+#else
+ Environment.FailFast("Iterator typehandle discarded");
+#endif
+ }
+ return McgMarshal.ObjectToComInterface(data, McgModuleManager.GetTypeInfoByHandle(m_genericArgumentMarshalInfo[marshalIndex].IteratorType));
+ }
+
+ /// <summary>
+ /// Shared CCW marhsalling native to IAsyncOperation<T>
+ /// </summary>
+ internal object MarshalToAsyncOperation(IntPtr data, int marshalIndex)
+ {
+ RuntimeTypeHandle typeHandle = m_genericArgumentMarshalInfo[marshalIndex].AsyncOperationType;
+ if (IsInvalidTypeHandle(typeHandle))
+ {
+#if !RHTESTCL
+ Environment.FailFast(String.Format("AsyncOperation typehandle for CCW Thunk Index {0} discarded", marshalIndex));
+#else
+ Environment.FailFast("AsyncOperation typehandle discarded");
+#endif
+ }
+ return ComInterfaceToObject(data, m_genericArgumentMarshalInfo[marshalIndex].AsyncOperationType);
+ }
+
+ public object ComInterfaceToObject(System.IntPtr pComItf, RuntimeTypeHandle interfaceType)
+ {
+ return ComInterfaceToObject(pComItf, interfaceType, /* classIndexInSignature */ default(RuntimeTypeHandle));
+ }
+
+ internal object ComInterfaceToObject(System.IntPtr pComItf, McgTypeInfo interfaceTypeInfo)
+ {
+ return ComInterfaceToObject(pComItf, interfaceTypeInfo, McgClassInfo.Null);
+ }
+
+ public object ComInterfaceToObject(System.IntPtr pComItf, RuntimeTypeHandle interfaceType,
+ RuntimeTypeHandle classTypeInSignature)
+ {
+#if ENABLE_WINRT
+ if (interfaceType.Equals(typeof(string).TypeHandle))
+ {
+ return McgMarshal.HStringToString(pComItf);
+ }
+#endif
+
+ // Current Shared CCW scenario is only for generic WinRT Interface
+ // in WinRT, "typeof(object)" is IInspectable
+ McgTypeInfo typeInfo;
+ if (interfaceType.Equals(typeof(object).TypeHandle))
+ {
+ typeInfo = McgModuleManager.IInspectable;
+ }
+ else
+ {
+ typeInfo = GetTypeInfoByHandle(interfaceType);
+ }
+
+ return McgMarshal.ComInterfaceToObject(
+ pComItf,
+ typeInfo,
+ (classTypeInSignature.Equals(default(RuntimeTypeHandle)))
+ ? McgClassInfo.Null
+ : GetClassInfoByHandle(classTypeInSignature)
+ );
+ }
+
+ /// <summary>
+ /// Lookup existing CCW/RCW, or create a new RCW for a type in this module
+ /// </summary>
+ /// <param name="pComItf">GetRuntimeClassName on the interface is used to find class name</param>
+ /// <param name="interfaceTypeInfo">
+ /// The type Info of the native interface. If we are marshalling a class (as specified in the
+ /// functino signature), this would be the default interface of the class
+ /// </param>
+ /// <param name="classInfoInSignature">
+ /// The class Info of the class type as specified in the signature
+ /// </param>
+ private object ComInterfaceToObject(System.IntPtr pComItf, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSignature)
+ {
+#if ENABLE_WINRT
+ if (interfaceTypeInfo == McgModuleManager.HSTRING)
+ {
+ return McgMarshal.HStringToString(pComItf);
+ }
+#endif
+
+ return McgMarshal.ComInterfaceToObject(
+ pComItf,
+ interfaceTypeInfo,
+ classInfoInSignature
+ );
+ }
+
+ /// <summary>
+ /// Shared CCW marshalling to managed, use class form for sealed winrt class
+ /// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ internal object MarshalToObject(IntPtr data, int marshalIndex)
+ {
+ RuntimeTypeHandle classTypeHandle = m_genericArgumentMarshalInfo[marshalIndex].ElementClassType;
+ if (!classTypeHandle.Equals(default(RuntimeTypeHandle))) // for sealed winrt class
+ {
+ if (classTypeHandle.Equals(s_DependencyReductionTypeRemovedTypeHandle))
+ {
+#if !RHTESTCL
+ Environment.FailFast(String.Format("ElementClassType typehandle for CCW Thunk Index {0} discarded", marshalIndex));
+#else
+ Environment.FailFast("ElementClassType typehandle discarded");
+#endif
+ }
+
+ return ComInterfaceToObject(
+ data,
+ m_genericArgumentMarshalInfo[marshalIndex].ElementInterfaceType,
+ classTypeHandle);
+ }
+ else
+ {
+ return ComInterfaceToObject(data, m_genericArgumentMarshalInfo[marshalIndex].ElementInterfaceType);
+ }
+ }
+
+ /// <summary>
+ /// Return sizeof(T) where T is blittable struct
+ /// </summary>
+ internal int GetByteSize(int marshalIndex)
+ {
+ Debug.Assert(m_genericArgumentMarshalInfo[marshalIndex].ElementSize > 0);
+ return (int)m_genericArgumentMarshalInfo[marshalIndex].ElementSize;
+ }
+
+ /// <summary>
+ /// Given a GUID, retrieve the corresponding type info
+ /// @TODO: we should switch everything to McgTypeInfo instead of relying on Guid
+ /// </summary>
+ unsafe public McgTypeInfo GetTypeInfo(ref Guid guid)
+ {
+ if (m_interfaceData != null)
+ {
+ if (m_guidMap == null)
+ {
+ int size = m_interfaceData.Length;
+
+ FixedHashTable map = new FixedHashTable(size);
+
+ for (int i = 0; i < size; i++)
+ {
+ map.Add(m_interfaceData[i].ItfGuid.GetHashCode(), i);
+ }
+
+ Interlocked.CompareExchange(ref m_guidMap, map, null);
+ }
+
+ int hash = guid.GetHashCode();
+
+ // Search hash table
+ for (int slot = m_guidMap.GetFirst(hash); slot >= 0; slot = m_guidMap.GetNext(slot))
+ {
+ if (InteropExtensions.GuidEquals(ref guid, ref m_interfaceData[slot].ItfGuid))
+ {
+ return GetTypeInfoByIndex_Inline(slot);
+ }
+ }
+ }
+
+ return McgTypeInfo.Null;
+ }
+
+ /// <summary>
+ /// Given a RuntimeTypeHandle, return the corresonding McgTypeInfo in InterfaceData
+ /// NOTE: This method only search InterfaceData.
+ /// NOTE: Don't call this method directory--call McgModuleManager.GetTypeInfoFromTypeHandle instead
+ /// </summary>
+ public unsafe McgTypeInfo GetTypeInfoFromTypeHandleInInterfaceData(RuntimeTypeHandle typeHandle)
+ {
+ int slot = InterfaceDataLookup(typeHandle);
+
+ if (slot >= 0)
+ {
+ return GetTypeInfoByIndex_Inline(slot);
+ }
+
+ return McgTypeInfo.Null;
+ }
+
+ /// <summary>
+ /// Given a RuntimeTypeHandle, return the corresonding McgTypeInfo in CollectionData
+ /// This method can also return secondaryTypeInfo in case the returned mcgTypeInfo query fails at runtime.
+ /// This is done for ICollection<KeyValuePair<>> or IReadOnlyCollection<KeyValuePair<>>,
+ /// where the returned and secondaryTypeInfo's are IDictionary and IList<keyValuePair<>> or
+ /// IReadOnlyDictionary and IReadOnlyList<KeyValuePair<>> respectively in cases where we can't determine the
+ /// mcgTypeInfo statically.
+ /// </summary>
+ /// <param name="typeHandle"></param>
+ /// <param name="secondaryTypeInfo"></param>
+ /// <returns></returns>
+ public McgTypeInfo GetTypeInfoFromTypeHandleInCollectionData(RuntimeTypeHandle typeHandle, out McgTypeInfo secondaryTypeInfo)
+ {
+ secondaryTypeInfo = McgTypeInfo.Null;
+
+ // Loop over our I[ReadOnly]Collection<T1,T2> instantiations to find the type infos for
+ // I[ReadOnly]List<KeyValuePair<T1,T2>> and I[ReadOnly]Dictionary<T1,T2>
+ //
+ // Note that only one of IList/IDictionary may be present.
+ if (m_collectionData != null)
+ {
+ int slot = CollectionDataLookup(typeHandle);
+
+ if (slot >= 0)
+ {
+ RuntimeTypeHandle secondTypeHandle = m_collectionData[slot].SecondType;
+ if (!IsInvalidTypeHandle(secondTypeHandle))
+ secondaryTypeInfo = McgModuleManager.GetTypeInfoByHandle(secondTypeHandle);
+
+ return McgModuleManager.GetTypeInfoByHandle(m_collectionData[slot].FirstType);
+ }
+ }
+
+ return McgTypeInfo.Null;
+ }
+
+ /// <summary>
+ /// Can the target object be casted to the type?
+ /// </summary>
+ public bool SupportsInterface(object obj, McgTypeInfo typeInfo)
+ {
+ return InteropExtensions.IsInstanceOfInterface(obj, typeInfo.InterfaceType);
+ }
+
+ /// <summary>
+ /// Get the WinRT name of a given Type. If the type is projected, returns the projected name.
+ /// Sets isWinRT to true if the type definition is from a WinMD file.
+ /// </summary>
+ public unsafe string GetTypeName(RuntimeTypeHandle type, ref bool isWinRT)
+ {
+ int slot = InterfaceDataLookup(type);
+
+ if (slot >= 0)
+ {
+ //
+ // WinRT interface or WinRT delegate
+ //
+ isWinRT = GetTypeInfoByIndex_Inline(slot).IsIInspectableOrDelegate;
+
+ return m_interfaceNameMap.GetString(slot);
+ }
+
+ if (m_classData != null)
+ {
+ int i = ClassDataLookup(type);
+
+ if (i >= 0)
+ {
+ isWinRT = (m_classData[i].Flags & McgClassFlags.IsWinRT) != 0;
+
+ return m_classNameMap.GetString(i);
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Get a Type object representing the named type, along with a boolean indicating if the type
+ /// definition is from a WinMD file.
+ /// </summary>
+ public Type GetTypeFromName(string name, ref bool isWinRT)
+ {
+ if (m_interfaceNameMap != null)
+ {
+ int i = m_interfaceNameMap.FindString(name);
+
+ if (i >= 0)
+ {
+ isWinRT = GetTypeInfoByIndex_Inline(i).IsIInspectableOrDelegate;
+
+ return InteropExtensions.GetTypeFromHandle(GetTypeInfoByIndex_Inline(i).ItfType);
+ }
+ }
+
+ if (m_classNameMap != null)
+ {
+ int i = m_classNameMap.FindString(name);
+
+ if (i >= 0)
+ {
+ isWinRT = (m_classData[i].Flags & McgClassFlags.IsWinRT) != 0;
+
+ return InteropExtensions.GetTypeFromHandle(m_classData[i].ClassType);
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Checks whether the CCW supports specified interface
+ /// It could be either a GUID (in the case of a QI) or a TypeInfo (when marshaller asks for an
+ /// interface explicitly
+ /// NOTE: This support variances by having MCG injecting variant interfaces into the list of
+ /// supported interfaces
+ /// </summary>
+ /// <param name="ccwTemplateIndex">The index of the CCWTemplateData in the module</param>
+ /// <param name="guid">This value is always present</param>
+ /// <param name="typeInfo">
+ /// Can be null if in QI scenarios and it'll be updated to be the found typeInfo if we've found a
+ /// match (despite whether it is supported or rejected).
+ /// If not null, it'll be used to match against the list of interfaces in the template
+ /// </param>
+ internal unsafe InterfaceCheckResult SupportsInterface(int ccwTemplateIndex, ref Guid guid, ref McgTypeInfo typeInfo)
+ {
+ //
+ // If this is a CCW template for a WinRT type, this means we've come to a base WinRT type of
+ // a managed class, and we should fail at this point. Otherwise we'll be responding QIs to
+ // interfaces not implemented in managed code
+ //
+ if (m_ccwTemplateData[ccwTemplateIndex].IsWinRTType)
+ return InterfaceCheckResult.Rejected;
+
+ //
+ // Walk the interface list, looking for a matching interface
+ //
+ int begin = m_ccwTemplateData[ccwTemplateIndex].SupportedInterfaceListBeginIndex;
+ int end = begin + m_ccwTemplateData[ccwTemplateIndex].NumberOfSupportedInterface;
+ for (int index = begin; index < end; index++)
+ {
+ RuntimeTypeHandle currentInterfaceTypeHandle = m_supportedInterfaceList[index];
+ Debug.Assert(!IsInvalidTypeHandle(currentInterfaceTypeHandle));
+ McgTypeInfo currentInterfaceInfo = McgModuleManager.GetTypeInfoByHandle(currentInterfaceTypeHandle);
+
+ bool match = false;
+ if (typeInfo.IsNull)
+ {
+ Guid intfGuid = currentInterfaceInfo.ItfGuid;
+ match = InteropExtensions.GuidEquals(ref intfGuid, ref guid);
+ }
+ else
+ match = (typeInfo.InterfaceType.Equals(currentInterfaceTypeHandle));
+
+ if (match)
+ {
+ // we found out a match using Guid / TypeInfo
+ if (typeInfo.IsNull)
+ typeInfo = currentInterfaceInfo;
+
+ return InterfaceCheckResult.Supported;
+ }
+ }
+
+ //
+ // Walk the parent too (if it is a WinRT type we'll stop)
+ // Field ParentCCWTemplateIndex >=0 means that its baseclass is in the same module
+ // Field BaseType != default(RuntimeTypeHandle) means that its baseclass isn't in the same module
+ int parentIndex = m_ccwTemplateData[ccwTemplateIndex].ParentCCWTemplateIndex;
+ RuntimeTypeHandle baseTypeHandle = m_ccwTemplateData[ccwTemplateIndex].BaseType;
+
+ if (parentIndex >= 0)
+ {
+ return SupportsInterface(parentIndex, ref guid, ref typeInfo);
+ }
+ else if (!baseTypeHandle.Equals(default(RuntimeTypeHandle)))
+ {
+ // DR will keep all base types if one of its derived type is used(rooted)
+ if (baseTypeHandle.Equals(s_DependencyReductionTypeRemovedTypeHandle))
+ {
+#if !RHTESTCL
+ Environment.FailFast(String.Format("Base Type of {0} discarded.", m_ccwTemplateData[ccwTemplateIndex].ClassType.GetDisplayName()));
+#else
+ Environment.FailFast("Base Type discarded.");
+#endif
+ }
+
+ CCWTemplateInfo baseCCWTemplateData = McgModuleManager.GetCCWTemplateInfo(baseTypeHandle);
+ Debug.Assert(!baseCCWTemplateData.IsNull);
+ return baseCCWTemplateData.ContainingModule.SupportsInterface(baseCCWTemplateData.Index, ref guid, ref typeInfo);
+
+ }
+
+ typeInfo = McgTypeInfo.Null;
+
+ return InterfaceCheckResult.NotFound;
+ }
+
+ /// <summary>
+ /// Search this module's m_classData table for information on the requested type.
+ /// This function returns true if and only if it is able to locate a non-null McgClassInfo
+ /// record for the requested type.
+ /// </summary>
+ internal bool TryGetClassInfoFromClassDataTable(string name, out McgClassInfo classInfo)
+ {
+ classInfo = McgClassInfo.Null;
+
+ if (m_classNameMap != null)
+ {
+ //
+ // Search to see if we have a strong-typed RCW for this type.
+ //
+ int i = m_classNameMap.FindString(name);
+
+ if ((i >= 0) && ((m_classData[i].Flags & McgClassFlags.NotComObject) == 0))
+ {
+ //
+ // This module contains an m_classData row which matches the requested type. This row can
+ // be immediately used to compute the McgClassInfo that best describes the type.
+ //
+ classInfo = ComputeClassInfoForClassDataTableRow(i);
+ }
+ }
+
+ return !classInfo.IsNull;
+ }
+
+ /// <summary>
+ /// Search this module's m_additionalClassData table for information on the requested type.
+ /// This function returns true if and only if it is able to locate a non-null McgClassInfo
+ /// record for the requested type.
+ /// </summary>
+ internal bool TryGetClassInfoFromAdditionalClassDataTable(string name, out McgClassInfo classInfo)
+ {
+ classInfo = McgClassInfo.Null;
+
+ if (m_additionalClassNameMap != null)
+ {
+ //
+ // Search in additional class data for the closest match (for example, for MyButton, the
+ // closest match is probably Button)
+ //
+ int i = m_additionalClassNameMap.FindString(name);
+
+ if (i >= 0)
+ {
+ //
+ // We've found a match. The matching row points to the "next best" strongly-typed RCW
+ // type that we should create (in place of the original class)
+ // For example, if native code is passing MatrixTransform, and MCG only knows about its
+ // base class DependencyObject, we should hand out DependencyObject
+ //
+ int classDataIndex = m_additionalClassData[i].ClassDataIndex;
+ RuntimeTypeHandle typeHandle = m_additionalClassData[i].ClassType;
+
+ if (classDataIndex >= 0)
+ {
+ //
+ // This module's m_additionalClassData table points to a m_classData row which describes
+ // the nearest available base class of the requested type. This row can be immediately used
+ // to compute the McgClassInfo that best describes the type.
+ //
+ classInfo = ComputeClassInfoForClassDataTableRow(classDataIndex);
+ }
+ else
+ {
+ //
+ // This module's m_additionalClassData table lists a RuntimeTypeHandle which describes
+ // the nearest available base class of the requested type. If this nearest base class was
+ // not reduced away, then use it to locate McgClassInfo describing this "next best" type.
+ //
+ if (!typeHandle.Equals(s_DependencyReductionTypeRemovedTypeHandle))
+ {
+ classInfo = McgModuleManager.GetClassInfoFromTypeHandle(typeHandle);
+ Debug.Assert(!classInfo.IsNull);
+ }
+ }
+ }
+ }
+
+ return !classInfo.IsNull;
+ }
+
+ /// <summary>
+ /// This function computes an McgClassInfo instance that represents the best possible
+ /// description of the type associated with the requested row in the m_classData table.
+ ///
+ /// McgClassInfo can generally be attached directly to the requested row. That said, in the
+ /// case where the associated type was removed by the dependency reducer, it is necessary to
+ /// walk the base class chain to find the nearest base type that is actually present at
+ /// runtime.
+ ///
+ /// Note: This function can return McgClassInfo.Null if it determines that all information
+ /// associated with the supplied row has been reduced away.
+ /// </summary>
+ private McgClassInfo ComputeClassInfoForClassDataTableRow(int index)
+ {
+ Debug.Assert((index >= 0) && (index < m_classData.Length));
+
+ if (!m_classData[index].ClassType.Equals(s_DependencyReductionTypeRemovedTypeHandle))
+ {
+ //
+ // The current row lists either an non-reduced exact type or the nearest non-reduced base
+ // type and is therefore the best possible description of the requested row.
+ //
+ return new McgClassInfo(index, this);
+ }
+ else
+ {
+ //
+ // The type in the current row was reduced away. Try to proceed to the base class.
+ //
+ int baseClassIndex = m_classData[index].BaseClassIndex;
+
+ if (baseClassIndex >= 0)
+ {
+ //
+ // The base class is described elsewhere in this m_classData table. Make a recursive call
+ // to compute its associated McgClassInfo.
+ //
+ return ComputeClassInfoForClassDataTableRow(baseClassIndex);
+ }
+ else
+ {
+ RuntimeTypeHandle baseClassTypeHandle = m_classData[index].BaseClassType;
+
+ if (baseClassTypeHandle.Equals(default(RuntimeTypeHandle)) ||
+ baseClassTypeHandle.Equals(s_DependencyReductionTypeRemovedTypeHandle))
+ {
+ //
+ // The reduced type either does not have a base class or refers to a base class that the
+ // dependency reducer found to be unnecessary.
+ //
+ return McgClassInfo.Null;
+ }
+ else
+ {
+ //
+ // The base class is described by type handle (probably because it is associated with a
+ // different McgModule and therefore isn't listed in the current m_classData table). Use
+ // the type handle to compute an McgClassInfo which describes the base class.
+ //
+ McgClassInfo classInfo = McgModuleManager.GetClassInfoFromTypeHandle(baseClassTypeHandle);
+ Debug.Assert(!classInfo.IsNull);
+ return classInfo;
+ }
+ }
+ }
+ }
+
+ internal bool TryGetInterfaceTypeInfoFromName(string name, out McgTypeInfo typeInfo)
+ {
+ if (m_interfaceData != null && m_interfaceNameMap != null)
+ {
+ int index = m_interfaceNameMap.FindString(name);
+ if (index >= 0)
+ {
+ typeInfo = GetTypeInfoByIndex_Inline(index);
+ return true;
+ }
+ }
+
+ typeInfo = McgTypeInfo.Null;
+ return false;
+ }
+
+ private unsafe McgClassInfo GetClassInfoByIndex(int index)
+ {
+ Debug.Assert(index >= 0 && index < m_classData.Length);
+
+ return new McgClassInfo(index, this);
+ }
+
+ internal McgClassData GetClassDataByIndex(int index)
+ {
+ Debug.Assert(index >= 0 && index < m_classData.Length);
+
+ return m_classData[index];
+ }
+
+ internal McgInterfaceData GetInterfaceDataByIndex(int index)
+ {
+ Debug.Assert(index >= 0 && index < m_interfaceData.Length);
+
+ return m_interfaceData[index];
+ }
+
+ internal void SetCCW(int index, IntPtr value)
+ {
+ m_interfaceData[index].CcwVtable = value;
+ }
+
+ int m_boxingDataTypeSlot = -1; // Slot for System.Type in boxing data table
+
+ /// <summary>
+ /// Given a boxed value type, return a wrapper supports the IReference interface
+ /// </summary>
+ /// <param name="typeHandleOverride">
+ /// You might want to specify how to box this. For example, any object[] derived array could
+ /// potentially boxed as object[] if everything else fails
+ /// </param>
+ public object BoxIfBoxable(object target, RuntimeTypeHandle typeHandleOverride)
+ {
+ if ((m_boxingData == null) || (m_boxingData.Length == 0))
+ {
+ return null;
+ }
+
+ if (m_boxingDataTypeSlot == -1)
+ {
+ m_boxingDataTypeSlot = BoxingDataLookup(typeof(System.Type).TypeHandle);
+ }
+
+ RuntimeTypeHandle expectedTypeHandle = typeHandleOverride;
+ if (expectedTypeHandle.Equals(default(RuntimeTypeHandle)))
+ expectedTypeHandle = target.GetTypeHandle();
+
+ //
+ // Is this the exact type that we want? (Don't use 'is' check - it won't work well for
+ // arrays)
+ int slot = BoxingDataLookup(expectedTypeHandle);
+
+ // NOTE: For System.Type marshalling, use 'is' check instead, as the actual type would be
+ // some random internal type from reflection
+ //
+ if ((slot < 0) && (target is Type))
+ {
+ slot = m_boxingDataTypeSlot;
+ }
+
+ if (slot >= 0)
+ {
+ return Box(target, slot);
+ }
+
+ return null;
+ }
+
+ public object Box(object target, int boxingIndex)
+ {
+ if (!IsInvalidTypeHandle(m_boxingData[boxingIndex].CLRBoxingWrapperType))
+ {
+ //
+ // IReference<T> / IReferenceArray<T> / IKeyValuePair<K, V>
+ // All these scenarios require a managed wrapper
+ //
+
+ // Allocate the object
+ object refImplType = InteropExtensions.RuntimeNewObject(m_boxingData[boxingIndex].CLRBoxingWrapperType);
+
+ int type = m_boxingData[boxingIndex].PropertyType;
+
+ if (type >= 0)
+ {
+ Debug.Assert(refImplType is BoxedValue);
+
+ BoxedValue boxed = InteropExtensions.UncheckedCast<BoxedValue>(refImplType);
+
+ // Call ReferenceImpl<T>.Initialize(obj, type);
+ boxed.Initialize(target, type);
+ }
+ else
+ {
+ Debug.Assert(refImplType is BoxedKeyValuePair);
+
+ BoxedKeyValuePair boxed = InteropExtensions.UncheckedCast<BoxedKeyValuePair>(refImplType);
+
+ // IKeyValuePair<,>, call CLRIKeyValuePairImpl<K,V>.Initialize(object obj);
+ // IKeyValuePair<,>[], call CLRIKeyValuePairArrayImpl<K,V>.Initialize(object obj);
+ refImplType = boxed.Initialize(target);
+ }
+
+ return refImplType;
+ }
+ else
+ {
+ //
+ // General boxing for projected types, such as System.Uri
+ //
+ return CalliIntrinsics.Call<object>(m_boxingData[boxingIndex].BoxingStub, target);
+ }
+ }
+
+ private const int PropertyType_ArrayOffset = 1024;
+
+ /// <summary>
+ /// Unbox the WinRT boxed IReference<T>/IReferenceArray<T> and box it into Object so that managed
+ /// code can unbox it later into the real T
+ /// </summary>
+ public object UnboxIfBoxed(object target, string className)
+ {
+ if (m_boxingData == null)
+ {
+ return null;
+ }
+
+ Debug.Assert(!String.IsNullOrEmpty(className));
+ //
+ // Avoid searching for null/empty name. BoxingData has null name entries
+ //
+ int i = m_boxingDataNameMap.FindString(className);
+
+ if (i >= 0)
+ {
+ //
+ // Otherwise - call to our unboxing stub
+ //
+ return CallUnboxingStub(target, i);
+ }
+
+ return null;
+ }
+
+ private object CallUnboxingStub(object obj, int boxingIndex)
+ {
+ return CalliIntrinsics.Call<object>(m_boxingData[boxingIndex].UnboxingStub, obj);
+ }
+
+ public object Unbox(object obj, int boxingIndex)
+ {
+ //
+ // If it is our managed wrapper, unbox it
+ //
+ object unboxedObj = McgComHelpers.UnboxManagedWrapperIfBoxed(obj);
+ if (unboxedObj != obj)
+ return unboxedObj;
+
+ //
+ // Otherwise - call to our unboxing stub directly
+ //
+ return CallUnboxingStub(obj, boxingIndex);
+ }
+
+ /// <summary>
+ /// Retrieves delegate data for the specified delegate handle
+ /// </summary>
+ internal bool TryGetPInvokeDelegateData(RuntimeTypeHandle typeHandle, out McgPInvokeDelegateData pinvokeDelegateData)
+ {
+ if (m_pinvokeDelegateData != null)
+ {
+ for (int i = 0; i < m_pinvokeDelegateData.Length; i++)
+ {
+ if (typeHandle.Equals(m_pinvokeDelegateData[i].Delegate))
+ {
+ pinvokeDelegateData = m_pinvokeDelegateData[i];
+ return true;
+ }
+ }
+ }
+
+ pinvokeDelegateData = default(McgPInvokeDelegateData);
+ return false;
+ }
+
+ /// <summary>
+ /// Finds McgStructMarshalData for a struct if it is defined in this module
+ /// </summary>
+ /// <param name="structTypeHandle">TypeHandle for the safe struct</param>
+ /// <param name="structMarshalData">McgStructMarshalData for the struct</param>
+ /// <returns>True if the struct marshal data is available in this module</returns>
+ public bool TryGetStructMarshalData(RuntimeTypeHandle structTypeHandle, out McgStructMarshalData structMarshalData)
+ {
+ structMarshalData = default(McgStructMarshalData);
+
+ if (m_structMarshalData == null)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < m_structMarshalData.Length; i++)
+ {
+ if (structTypeHandle.Equals(m_structMarshalData[i].SafeStructType))
+ {
+ if (m_structMarshalData[i].HasInvalidLayout)
+ throw new ArgumentException(SR.Format(SR.Argument_MustHaveLayoutOrBeBlittable, structTypeHandle.GetDisplayName()));
+
+ structMarshalData = m_structMarshalData[i];
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ internal unsafe McgTypeInfo FindTypeInfo(Func<McgTypeInfo, bool> predecate)
+ {
+ for (int i = 0; i < m_interfaceData.Length; i++)
+ {
+ McgTypeInfo info = GetTypeInfoByIndex_Inline(i);
+
+ if (predecate(info))
+ return info;
+ }
+
+ return McgTypeInfo.Null;
+ }
+
+#if RHTESTCL
+
+ public object ComInterfaceToObjectType(System.IntPtr pComItf, RuntimeTypeHandle interfaceType)
+ {
+ return ComInterfaceToObject(pComItf, interfaceType, /* classTypeInSignature */ default(RuntimeTypeHandle));
+ }
+
+ public object ComInterfaceToObjectClass(System.IntPtr pComItf, RuntimeTypeHandle classTypeInSignature)
+ {
+ return ComInterfaceToObject(pComItf, default(RuntimeTypeHandle), classTypeInSignature);
+ }
+
+#endif
+
+#if ENABLE_WINRT
+ static Guid s_IID_IActivationFactory = new Guid(0x00000035, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+
+ /// <summary>
+ /// Returns the requested interface pointer specified by itfTypeInfo from the CCWActivationFactory
+ /// object instance. Typically the requested interface is the
+ /// System.Runtime.InteropServices.WindowsRuntime.IActivationFactory interface.
+ /// </summary>
+ public unsafe int GetCCWActivationFactory(HSTRING activatableClassId, McgTypeInfo itfTypeInfo, IntPtr* factoryOut)
+ {
+ try
+ {
+ string classId = McgMarshal.HStringToString(activatableClassId);
+
+ if (classId == null)
+ return Interop.COM.E_INVALIDARG;
+
+ RuntimeTypeHandle factoryTypeHandle = default(RuntimeTypeHandle);
+
+ if (m_ccwFactoriesNameMap != null)
+ {
+ int slot = m_ccwFactoriesNameMap.FindString(classId);
+
+ if (slot >= 0)
+ {
+ factoryTypeHandle = m_ccwFactories[slot].FactoryType;
+ }
+ }
+
+ if (factoryTypeHandle.IsNull())
+ return Interop.COM.E_NOINTERFACE;
+
+ object factory = InteropExtensions.RuntimeNewObject(factoryTypeHandle);
+
+ *factoryOut = McgMarshal.ObjectToComInterface(
+ factory,
+ itfTypeInfo);
+ }
+ catch (Exception ex)
+ {
+ *factoryOut = default(IntPtr);
+ return McgMarshal.GetHRForExceptionWinRT(ex);
+ }
+
+ return Interop.COM.S_OK;
+ }
+#endif
+
+ bool IsInvalidTypeHandle(RuntimeTypeHandle typeHandle)
+ {
+ if (typeHandle.Equals(typeof(DependencyReductionTypeRemoved).TypeHandle))
+ return true;
+
+ if (typeHandle.IsNull())
+ return true;
+
+ return false;
+ }
+
+#if DEBUG
+ bool VerifyHashCodes()
+ {
+ if (m_hashcodeVerifyData == null)
+ return true;
+
+ bool success = true;
+ RuntimeTypeHandle typeRemovedType = typeof(DependencyReductionTypeRemoved).TypeHandle;
+
+ for (int i = 0; i < m_hashcodeVerifyData.Length; i++)
+ {
+ McgHashcodeVerifyEntry entry = m_hashcodeVerifyData[i];
+ if (entry.TypeHandle.Equals(typeRemovedType))
+ continue;
+
+ uint nutcHashcode = unchecked((uint)entry.TypeHandle.GetHashCode());
+ uint mcgHashcode = entry.HashCode;
+
+ if (nutcHashcode != mcgHashcode)
+ {
+ success = false;
+ Debug.WriteLine("MCG hashcode mistatch at index: " + DebugUtil.BasicToString(i)
+ + " MCG: " + DebugUtil.ToHexStringUnsigned(mcgHashcode)
+ + " NUTC: " + DebugUtil.ToHexStringUnsigned(nutcHashcode));
+ }
+ }
+ return success;
+ }
+#endif // DEBUG
+ }
+
+#if DEBUG
+ // VerifyHashCodes must not call String.Format or any of the integer formatting routines in System.Private.CoreLib because
+ // they will trigger the globalization code which uses WinRT interop, which call back here creating an
+ // infinite recursion. So we have a simple implementation for printing hex numbers.
+ static class DebugUtil
+ {
+ static char GetHexChar(uint u)
+ {
+ if (u < 10)
+ {
+ return unchecked((char)('0' + u));
+ }
+ if (u < 16)
+ {
+ return unchecked((char)('a' + (u - 10)));
+ }
+ return (char)0;
+ }
+
+ static public string ToHexStringUnsigned(uint u)
+ {
+ return ToHexStringUnsignedLong(u, true, 8);
+ }
+ static public unsafe string ToHexStringUnsignedLong(ulong u, bool zeroPrepad, int numChars)
+ {
+ char[] chars = new char[numChars];
+
+ int i = numChars - 1;
+
+ for (; i >= 0; i--)
+ {
+ chars[i] = GetHexChar((uint)(u % 16));
+ u = u / 16;
+
+ if ((i == 0) || (!zeroPrepad && (u == 0)))
+ break;
+ }
+
+ string str;
+ fixed (char* p = &chars[i])
+ {
+ str = new String(p, 0, numChars - i);
+ }
+ return str;
+ }
+ static public unsafe string BasicToString(int num)
+ {
+ char* pRevBuffer = stackalloc char[16];
+ char* pFwdBuffer = stackalloc char[16];
+
+ bool isNegative = (num < 0);
+ if (isNegative)
+ num = -num;
+
+ int len = 0;
+ while (num > 0)
+ {
+ int ch = num % 10;
+ num = num / 10;
+
+ pRevBuffer[len++] = (char)('0' + ch);
+ }
+ if (isNegative)
+ pRevBuffer[len++] = '-';
+
+ for (int i = (len - 1); i >= 0; i--)
+ {
+ pFwdBuffer[i] = pRevBuffer[(len - 1) - i];
+ }
+ return new String(pFwdBuffer, 0, len);
+ }
+ }
+
+ internal class EquatableRuntimeTypeHandle : IEquatable<EquatableRuntimeTypeHandle>
+ {
+ internal RuntimeTypeHandle TypeHand;
+
+ internal EquatableRuntimeTypeHandle(RuntimeTypeHandle typeHand)
+ {
+ TypeHand = typeHand;
+ }
+
+ public bool Equals(EquatableRuntimeTypeHandle other)
+ {
+ return TypeHand.Equals(other.TypeHand);
+ }
+ }
+#endif // DEBUG
+}
diff --git a/src/System.Private.Interop/src/Shared/McgModuleManager.cs b/src/System.Private.Interop/src/Shared/McgModuleManager.cs
new file mode 100644
index 000000000..cd9bef11e
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgModuleManager.cs
@@ -0,0 +1,1332 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// ----------------------------------------------------------------------------------
+// Interop library code
+//
+// Implementation for McgModuleManager which provides access to all modules in the app
+// and does global lookup across all modules
+//
+// NOTE:
+// These source code are being published to InternalAPIs and consumed by RH builds
+// Use PublishInteropAPI.bat to keep the InternalAPI copies in sync
+// ---------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Text;
+using System.Runtime;
+using System.Diagnostics.Contracts;
+using Internal.NativeFormat;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Manage a list of McgModules
+ /// NOTE: This class is not CLS compliant but it is only used in Mcg output which is C#
+ /// NOTE: Managed debugger depends on class full name: "System.Runtime.InteropServices.McgModuleManager"
+ /// </summary>
+ [CLSCompliant(false)]
+ [EagerOrderedStaticConstructor(EagerStaticConstructorOrder.McgModuleManager)]
+ public static class McgModuleManager
+ {
+ internal const int MAX_MODULES = 8;
+
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "s_modules" and field type must be Array
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::InitMcgModules in debug\dbi\values.cpp for more info
+ /// </summary>
+ internal static McgModule[] s_modules; // work around for multi-file cctor ordering issue: don't initialize in cctor, initialize lazily
+ internal static volatile int s_moduleCount;
+
+ internal static int s_numInteropThunksAllocatedSinceLastCleanup = 0;
+#if !CORECLR
+ private static class AsmCode
+ {
+
+ private const MethodImplOptions InternalCall = (MethodImplOptions)0x1000;
+
+ [MethodImplAttribute(InternalCall)]
+ [RuntimeImport("*", "InteropNative_GetCurrentThunk")]
+ public static extern IntPtr GetCurrentInteropThunk();
+
+ [MethodImplAttribute(InternalCall)]
+
+ [RuntimeImport("*", "InteropNative_GetCommonStubAddress")]
+
+ public static extern IntPtr GetInteropCommonStubAddress();
+ }
+#endif
+
+ static McgModuleManager()
+ {
+ CCWLookupMap.InitializeStatics();
+ ContextEntry.ContextEntryManager.InitializeStatics();
+ ComObjectCache.InitializeStatics();
+ }
+
+
+ internal static InternalModule s_internalModule;
+
+ public static McgTypeInfo IUnknown
+ {
+ get
+ {
+ return new McgTypeInfo((int)InternalModule.Indexes.IUnknown, s_internalModule);
+ }
+ }
+
+ public static McgTypeInfo IInspectable
+ {
+ get
+ {
+#if ENABLE_WINRT
+ return new McgTypeInfo((int)InternalModule.Indexes.IInspectable, s_internalModule);
+#else
+ throw new PlatformNotSupportedException();
+#endif
+ }
+ }
+
+ public static McgTypeInfo HSTRING
+ {
+ get
+ {
+#if ENABLE_WINRT
+ return new McgTypeInfo((int)InternalModule.Indexes.HSTRING, s_internalModule);
+#else
+ throw new PlatformNotSupportedException();
+#endif
+ }
+ }
+
+ internal static McgTypeInfo IJupiterObject
+ {
+ get
+ {
+#if ENABLE_WINRT
+ return new McgTypeInfo((int)InternalModule.Indexes.IJupiterObject, s_internalModule);
+#else
+ throw new PlatformNotSupportedException();
+#endif
+ }
+ }
+
+ internal static McgTypeInfo IStringable
+ {
+ get
+ {
+#if ENABLE_WINRT
+ return new McgTypeInfo((int)InternalModule.Indexes.IStringable, s_internalModule);
+#else
+ throw new PlatformNotSupportedException();
+#endif
+ }
+ }
+
+#if ENABLE_WINRT
+
+
+ internal static McgTypeInfo ICCW
+ {
+ get
+ {
+ return new McgTypeInfo((int)InternalModule.Indexes.ICCW, s_internalModule);
+ }
+ }
+
+ internal static McgTypeInfo IRestrictedErrorInfo
+ {
+ get
+ {
+ return new McgTypeInfo((int)InternalModule.Indexes.IRestrictedErrorInfo, s_internalModule);
+ }
+ }
+
+
+ public static McgTypeInfo IActivationFactoryInternal
+ {
+ get
+ {
+ return new McgTypeInfo((int)InternalModule.Indexes.IActivationFactoryInternal, s_internalModule);
+ }
+ }
+
+
+
+
+#endif //ENABLE_WINRT
+ public unsafe static bool IsIJupiterObject(McgTypeInfo pEntry)
+ {
+#if ENABLE_WINRT
+ return (pEntry == IJupiterObject);
+#else
+ return false;
+#endif
+ }
+
+ internal static McgTypeInfo IWeakReferenceSource
+ {
+ get
+ {
+ return new McgTypeInfo((int)InternalModule.Indexes.IWeakReferenceSource, s_internalModule);
+ }
+ }
+
+ internal static McgTypeInfo IWeakReference
+ {
+ get
+ {
+ return new McgTypeInfo((int)InternalModule.Indexes.IWeakReference, s_internalModule);
+ }
+ }
+
+ internal static McgTypeInfo IMarshal
+ {
+ get
+ {
+ return new McgTypeInfo((int)InternalModule.Indexes.IMarshal, s_internalModule);
+ }
+ }
+
+
+
+ /// <summary>
+ /// Register the module and add it into global module list
+ /// This should always be called from eagerly constructed ctors so threading is not a concern
+ /// </summary>
+ public static void Register(McgModule module)
+ {
+ // This API is called by .cctors, so we don't need to support multi-threaded callers.
+ if (s_internalModule == null)
+ {
+ s_internalModule = new InternalModule();
+ Add(s_internalModule);
+ }
+
+ Add(module);
+ }
+
+ private static void Add(McgModule module)
+ {
+ if (s_moduleCount >= MAX_MODULES)
+ Environment.FailFast("Limit of modules reached"); //Can`t be localized, eager cctor dependency error.
+
+ // workaround for multifile cctor ordering issue: init s_modules lazily
+ if (s_modules == null)
+ {
+ s_modules = new McgModule[MAX_MODULES];
+ s_modules[s_moduleCount++] = module;
+ return;
+ }
+
+ // insert module into s_modules with correct order
+ // make sure modules with larger priority values are listed first
+ int index = s_moduleCount - 1;
+ for (; index >= 0; index--)
+ {
+ if (s_modules[index].ModulePriority < module.ModulePriority)
+ {
+ s_modules[index + 1] = s_modules[index];
+ }
+ else
+ break;
+ }
+
+ s_modules[index + 1] = module;
+
+ // Increment the count after we make the assignment to avoid off-by-1 mistakes
+ s_moduleCount++;
+ }
+
+ internal static int GetModuleIndex(McgModule module)
+ {
+ // Go through each module
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ if (s_modules[i] == module)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ internal static McgModule GetModule(int moduleIndex)
+ {
+ // the index value is added by 1 in GetModuleIndex()
+ Debug.Assert(moduleIndex >= 0);
+ return s_modules[moduleIndex];
+ }
+
+ /// <summary>
+ /// This function scans all McgModules in search of the m_classData table row that "best
+ /// describes" the requested type (i.e., describes the exact requested type or describes the
+ /// nearest base class of that type that is listed anywhere in the aggregate m_classData
+ /// content across all McgModules).
+ ///
+ /// If such a row is found, this function return true and returns an McgClassInfo attached
+ /// to that row. Otherwise, this function returns false.
+ /// </summary>
+ internal static bool TryGetClassInfoFromName(string name, out McgClassInfo typeInfo)
+ {
+ //
+ // Search all m_classData tables. If any of these tables contain a row describing the
+ // requested type, then it is the best possible match (i.e., it either contains precise
+ // information or anchors a linked list that reliably leads to the nearest available base
+ // class).
+ //
+ // Note that the module list is ordered (see McgModuleManager.Add). This guarantees that
+ // "higher layers" will be searched first (i.e., app will be searched first, then the
+ // highest shared library layer, then the next shared library layer, etc).
+ //
+ // Note: This search does NOT distinguish between public and private interop. This means it
+ // can erroneously return a private interop type which "should have" been hidden from the
+ // caller's layer, and can also erroneously return a public interop type in a higher layer
+ // when it "should have" returned a private interop type in the lower layer where the
+ // caller resides. As a result, requests targeting private interop types (at any layer) are
+ // currently unsupported (and do not occur in the product configurations that exist today).
+ //
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ if (s_modules[i].TryGetClassInfoFromClassDataTable(name, out typeInfo))
+ {
+ return true;
+ }
+ }
+
+ //
+ // The m_classData tables did not contain any information on the requested type. Fall back
+ // to searching the m_additionalClassData tables in case they contain information on the
+ // "next best" base class that should be used in the absence of an exact match.
+ //
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ if (s_modules[i].TryGetClassInfoFromAdditionalClassDataTable(name, out typeInfo))
+ {
+ return true;
+ }
+ }
+
+ //
+ // There were no matches in the m_classData or m_additionalClassData tables, so no class
+ // info is available for the requested type.
+ //
+ typeInfo = McgClassInfo.Null;
+ return false;
+ }
+
+ internal static bool TryGetInterfaceTypeInfoFromName(string name, out McgTypeInfo typeInfo)
+ {
+ // Go through each module
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ if (s_modules[i].TryGetInterfaceTypeInfoFromName(name, out typeInfo))
+ return true;
+ }
+
+ typeInfo = McgTypeInfo.Null;
+ return false;
+ }
+
+ public static string GetTypeName(RuntimeTypeHandle type, out bool isWinRT)
+ {
+ isWinRT = false;
+
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ string ret = s_modules[i].GetTypeName(type, ref isWinRT);
+
+ if (ret != null)
+ return ret;
+ }
+
+ return null;
+ }
+
+ public static Type GetTypeFromName(string name, out bool isWinRT)
+ {
+ isWinRT = false;
+
+ // Our type info tables could have types with no names, these are non-WinRT types. But we don't
+ // want to return just any one of those, so we have to special-case the null/empty string case here.
+ if (name == null || name == "")
+ return null;
+
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ Type ret = s_modules[i].GetTypeFromName(name, ref isWinRT);
+
+ if (ret != null)
+ return ret;
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Given a GUID, retrieve the corresponding type info(s)
+ /// </summary>
+ public static IEnumerable<McgTypeInfo> GetTypeInfosFromGuid(ref Guid guid)
+ {
+ List<McgTypeInfo> rets = new List<McgTypeInfo>(s_moduleCount);
+ McgTypeInfo ret;
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ ret = s_modules[i].GetTypeInfo(ref guid);
+
+ if (!ret.IsNull)
+ {
+ rets.Add(ret);
+ }
+ }
+
+ return rets;
+ }
+
+ /// <summary>
+ /// Given a RuntimeTypeHandle, return the corresonding McgTypeInfo
+ /// </summary>
+ internal static McgTypeInfo GetTypeInfoFromTypeHandle(RuntimeTypeHandle typeHandle, out McgTypeInfo secondTypeInfo)
+ {
+ McgTypeInfo ret;
+ secondTypeInfo = McgTypeInfo.Null;
+
+ // First, search interface data, if type exists in InterfaceData, then just return
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ ret = s_modules[i].GetTypeInfoFromTypeHandleInInterfaceData(typeHandle);
+
+ if (!ret.IsNull)
+ return ret;
+ }
+
+ // Second, search ICollectionData, if the type is ICollection<T>, try to get 2 McgTypeInfos
+ // The logical:
+ // if it find the first McgTypeInfo for ICollection<T>, it will continue search unless we found 2 McgTypeInfos or all module has been searched.
+ // The reason behind this logical is for multi-file mode--if we dont search all McgModules, we may miss one McgTypeInfo for ICollection<T>
+ // Example:
+ // If Dictionary<string, object> is used in shared assembly and List<KeyValuePair<string, object>> isn't used in shared assembly, we will generate
+ // a McgCollectionData entry in shared.Interop.dll:
+ // McgCollectionData {
+ // CollectionType : ICollection<KeyValuePair<string, object>>
+ // FirstType: Dictionary<string, object>
+ // SecondType: Null
+ // };
+ // And If List<KeyValuePair<string, object>> is used in app assembly, we will generate a McgCollectionData entry in App.Interop.dll:
+ // McgCollectionData {
+ // CollectionType : ICollection<KeyValuePair<string, object>>
+ // FirstType: List<KeyValuePair<string, object>>
+ // SecondType: Null
+ // };
+ // In this example, if we want to get all these McgTypeInfo for ICollection<KeyValuePair<string, object>> , we have to search all McgModules.
+ McgTypeInfo firstTypeInfoLocal = McgTypeInfo.Null; // store first McgTypeInfo for ICollection<T>
+ McgTypeInfo secondTypeInfoLocal = McgTypeInfo.Null; // store second McgTypeInfo for ICollection<T>
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ ret = s_modules[i].GetTypeInfoFromTypeHandleInCollectionData(typeHandle, out secondTypeInfoLocal);
+
+ if (ret.IsNull)
+ continue;
+
+ if (firstTypeInfoLocal.IsNull)
+ {
+ // store the first McgTypeInfo
+ firstTypeInfoLocal = ret;
+ }
+ else
+ {
+ // if we found the first McgTypeInfo and saved as firstTypeInfoLocal
+ // and current ret's value is different than firstTypeInfoLocal,
+ // then save ret value as secondTypeInfoLocal
+ if (secondTypeInfoLocal.IsNull && !ret.Equals(firstTypeInfoLocal))
+ {
+ secondTypeInfoLocal = ret;
+ }
+ }
+
+ // if find both McgTypeInfo, return
+ if(!firstTypeInfoLocal.IsNull && !secondTypeInfoLocal.IsNull)
+ {
+ secondTypeInfo = secondTypeInfoLocal;
+ return firstTypeInfoLocal;
+ }
+ }
+
+ // third, return either null or the only McgTypeInfo for ICollection<T>
+ return firstTypeInfoLocal;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static McgTypeInfo GetTypeInfoByHandle(RuntimeTypeHandle typeHnd)
+ {
+ McgTypeInfo typeInfo;
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ typeInfo = s_modules[i].GetTypeInfoByHandle(typeHnd);
+ if (!typeInfo.IsNull)
+ return typeInfo;
+ }
+
+ return McgTypeInfo.Null;
+ }
+
+ internal static McgTypeInfo FindTypeInfo(Func<McgTypeInfo, bool> predecate)
+ {
+ for (int i = 0; i < s_moduleCount; i++)
+ {
+ McgTypeInfo info = s_modules[i].FindTypeInfo(predecate);
+
+ if (!info.IsNull)
+ return info;
+ }
+
+ return McgTypeInfo.Null;
+ }
+
+ /// <summary>
+ /// Given a RuntimeTypeHandle, return the corresonding McgTypeInfo
+ /// </summary>
+ internal static McgClassInfo GetClassInfoFromTypeHandle(RuntimeTypeHandle typeHandle)
+ {
+ McgClassInfo ret;
+
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ ret = s_modules[i].GetClassInfoByHandle(typeHandle);
+
+ if (!ret.IsNull)
+ return ret;
+ }
+
+ return McgClassInfo.Null;
+ }
+
+ internal static CCWTemplateInfo GetCCWTemplateInfo(RuntimeTypeHandle handle)
+ {
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ int slot = s_modules[i].CCWTemplateDataLookup(handle);
+
+ if (slot >= 0)
+ return new CCWTemplateInfo(s_modules[i], slot);
+ }
+
+ return CCWTemplateInfo.Null;
+ }
+
+ public static object UnboxIfBoxed(object obj)
+ {
+ return UnboxIfBoxed(obj, null);
+ }
+
+ public static object UnboxIfBoxed(object obj, string className)
+ {
+ //
+ // If it is a managed wrapper, unbox it
+ //
+ object unboxedObj = McgComHelpers.UnboxManagedWrapperIfBoxed(obj);
+ if (unboxedObj != obj)
+ return unboxedObj;
+
+ if (className == null)
+ className = System.Runtime.InteropServices.McgComHelpers.GetRuntimeClassName(obj);
+
+ if (!String.IsNullOrEmpty(className))
+ {
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ object ret = s_modules[i].UnboxIfBoxed(obj, className);
+
+ if (ret != null)
+ return ret;
+ }
+ }
+
+ return null;
+ }
+
+ public static object BoxIfBoxable(object obj)
+ {
+ return BoxIfBoxable(obj, default(RuntimeTypeHandle));
+ }
+
+ public static object BoxIfBoxable(object obj, RuntimeTypeHandle typeHandleOverride)
+ {
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ object ret = s_modules[i].BoxIfBoxable(obj, typeHandleOverride);
+
+ if (ret != null)
+ return ret;
+ }
+
+ return null;
+ }
+
+ internal static bool TryGetStructMarshalData(RuntimeTypeHandle structureTypeHandle, out McgStructMarshalData structMarshalData)
+ {
+ for (int i = 0; i < s_moduleCount; i++)
+ {
+ if (s_modules[i].TryGetStructMarshalData(structureTypeHandle, out structMarshalData))
+ {
+ return true;
+ }
+ }
+
+ structMarshalData = default(McgStructMarshalData);
+ return false;
+ }
+
+ /// <summary>
+ /// Try to get Field Offset
+ /// </summary>
+ /// <param name="structureTypeHandle"></param>
+ /// <param name="fieldName">field Name</param>
+ /// <param name="structExists">whether the struct marshalling data exists or not</param>
+ /// <param name="offset"></param>
+ /// <returns></returns>
+ internal static bool TryGetStructFieldOffset(RuntimeTypeHandle structureTypeHandle, string fieldName, out bool structExists, out uint offset)
+ {
+ structExists = false;
+ offset = default(uint);
+
+ for (int i = 0; i < s_moduleCount; i++)
+ {
+ McgStructMarshalData structMarshalData;
+ if (s_modules[i].TryGetStructMarshalData(structureTypeHandle, out structMarshalData))
+ {
+ structExists = true;
+ if (s_modules[i].TryGetStructFieldOffset(structMarshalData, fieldName, out offset))
+ {
+ return true;
+ }
+ else
+ {
+ // Stop search other modules
+ return false;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public static object ComInterfaceToObject_NoUnboxing(System.IntPtr pComItf, RuntimeTypeHandle interfaceType)
+ {
+ McgTypeInfo secondTypeInfo;
+ McgTypeInfo typeInfo = GetTypeInfoFromTypeHandle(interfaceType, out secondTypeInfo);
+ return McgMarshal.ComInterfaceToObject_NoUnboxing(pComItf, typeInfo);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static IntPtr GetInterface(
+ __ComObject obj,
+ RuntimeTypeHandle typeHnd)
+ {
+ return obj.QueryInterface_NoAddRef_Internal(
+ typeHnd);
+ }
+
+ /// <summary>
+ /// Shared CCW marshalling to native: from type index to object, supporting HSTRING
+ /// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ static internal IntPtr ObjectToComInterface(object data, McgTypeInfo typeInfo)
+ {
+#if ENABLE_WINRT
+ if (typeInfo.Equals(McgModuleManager.IInspectable))
+ {
+ return McgMarshal.ObjectToIInspectable(data);
+ }
+ else if (typeInfo.Equals(McgModuleManager.HSTRING))
+ {
+ return McgMarshal.StringToHString((string)data).handle;
+ }
+#endif
+
+ return McgMarshal.ObjectToComInterface(data, typeInfo);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static IntPtr ObjectToComInterface(
+ object obj,
+ RuntimeTypeHandle typeHnd)
+ {
+#if ENABLE_WINRT
+ if (typeHnd.Equals(typeof(object).TypeHandle))
+ {
+ return McgMarshal.ObjectToIInspectable(obj);
+ }
+
+ if (typeHnd.Equals(typeof(string).TypeHandle))
+ {
+ return McgMarshal.StringToHString((string)obj).handle;
+ }
+
+ if (!InteropExtensions.IsInterface(typeHnd))
+ {
+ Debug.Assert(obj is __ComObject);
+ ///
+ /// This code path should be executed only for WinRT classes
+ ///
+ typeHnd = GetClassInfoFromTypeHandle(typeHnd).DefaultInterface;
+ Debug.Assert(!typeHnd.IsNull());
+ }
+#endif
+ McgTypeInfo typeInfo = McgModuleManager.GetTypeInfoByHandle(typeHnd);
+
+ return McgMarshal.ObjectToComInterface(
+ obj,
+ typeInfo
+ );
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static IntPtr ManagedObjectToComInterface(
+ object obj,
+ RuntimeTypeHandle typeHnd)
+ {
+ return McgMarshal.ManagedObjectToComInterface(
+ obj,
+ McgModuleManager.GetTypeInfoByHandle(typeHnd)
+ );
+ }
+
+ public static object ComInterfaceToObject(System.IntPtr pComItf, RuntimeTypeHandle typeHandle)
+ {
+#if ENABLE_WINRT
+ if (typeHandle.Equals(typeof(object).TypeHandle))
+ {
+ return McgMarshal.IInspectableToObject(pComItf);
+ }
+
+ if (typeHandle.Equals(typeof(string).TypeHandle))
+ {
+ return McgMarshal.HStringToString(pComItf);
+ }
+
+ if (!InteropExtensions.IsInterface(typeHandle))
+ {
+ return ComInterfaceToObject(pComItf, GetClassInfoFromTypeHandle(typeHandle).DefaultInterface, typeHandle);
+ }
+#endif
+ return ComInterfaceToObject(pComItf, typeHandle, default(RuntimeTypeHandle));
+
+ }
+ /// <summary>
+ /// Shared CCW Interface To Object
+ /// </summary>
+ /// <param name="pComItf"></param>
+ /// <param name="interfaceType"></param>
+ /// <param name="classTypeInSignature"></param>
+ /// <returns></returns>
+ public static object ComInterfaceToObject(System.IntPtr pComItf, RuntimeTypeHandle interfaceType,
+ RuntimeTypeHandle classTypeInSignature)
+ {
+ if (interfaceType.Equals(typeof(object).TypeHandle))
+ {
+ return McgMarshal.IInspectableToObject(pComItf);
+ }
+
+#if ENABLE_WINRT
+ if (interfaceType.Equals(typeof(string).TypeHandle))
+ {
+ return McgMarshal.HStringToString(pComItf);
+ }
+#endif
+
+ return ComInterfaceToObject(
+ pComItf,
+ GetTypeInfoByHandle(interfaceType),
+ (classTypeInSignature.Equals(default(RuntimeTypeHandle)))
+ ? McgClassInfo.Null
+ : GetClassInfoFromTypeHandle(classTypeInSignature)
+ );
+ }
+
+ public static object ComInterfaceToObject(System.IntPtr pComItf, McgTypeInfo interfaceTypeInfo)
+ {
+ return ComInterfaceToObject(pComItf, interfaceTypeInfo, McgClassInfo.Null);
+ }
+
+ public static object ComInterfaceToObject(System.IntPtr pComItf, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSignature)
+ {
+#if ENABLE_WINRT
+ if (interfaceTypeInfo == McgModuleManager.HSTRING)
+ {
+ return McgMarshal.HStringToString(pComItf);
+ }
+#endif
+ return McgMarshal.ComInterfaceToObject(
+ pComItf,
+ interfaceTypeInfo,
+ classInfoInSignature
+ );
+ }
+
+ // This is not a safe function to use for any funtion pointers that do not point
+ // at a static function. This is due to the behavior of shared generics,
+ // where instance function entry points may share the exact same address
+ // but static functions are always represented in delegates with customized
+ // stubs.
+ private static bool DelegateTargetMethodEquals(Delegate del, IntPtr pfn)
+ {
+ RuntimeTypeHandle thDummy;
+ return del.GetFunctionPointer(out thDummy) == pfn;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static IntPtr DelegateToComInterface(Delegate del, RuntimeTypeHandle typeHnd, IntPtr stubFunctionAddr)
+ {
+ if (del == null)
+ return default(IntPtr);
+
+ object targetObj;
+
+ //
+ // If the delegate points to the forward stub for the native delegate,
+ // then we want the RCW associated with the native interface. Otherwise,
+ // this is a managed delegate, and we want the CCW associated with it.
+ //
+ if (DelegateTargetMethodEquals(del, stubFunctionAddr))
+ targetObj = del.Target;
+ else
+ targetObj = del;
+
+ return McgMarshal.ObjectToComInterface(targetObj,
+ GetTypeInfoByHandle(typeHnd)
+ );
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Delegate ComInterfaceToDelegate(IntPtr pComItf, RuntimeTypeHandle typeHnd, IntPtr stubFunctionAddr)
+ {
+ if (pComItf == default(IntPtr))
+ return null;
+
+ object obj = ComInterfaceToObject(pComItf, typeHnd, /* classIndexInSignature */ default(RuntimeTypeHandle));
+
+ //
+ // If the object we got back was a managed delegate, then we're good. Otherwise,
+ // the object is an RCW for a native delegate, so we need to wrap it with a managed
+ // delegate that invokes the correct stub.
+ //
+ Delegate del = obj as Delegate;
+ if (del == null)
+ {
+ Debug.Assert(obj is __ComObject);
+ Debug.Assert(GetTypeInfoByHandle(typeHnd).InterfaceType.Equals(typeHnd));
+
+ del = InteropExtensions.CreateDelegate(
+ typeHnd,
+ stubFunctionAddr,
+ obj,
+ /*isStatic:*/ true,
+ /*isVirtual:*/ false,
+ /*isOpen:*/ false);
+ }
+
+ return del;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static __ComObject GetActivationFactory(
+ string typeName,
+ RuntimeTypeHandle typeHnd)
+ {
+ return McgMarshal.GetActivationFactory(
+ typeName,
+ McgModuleManager.GetTypeInfoByHandle(typeHnd)
+ );
+ }
+
+#if ENABLE_WINRT
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static unsafe IntPtr ActivateInstance(string typeName)
+ {
+ __ComObject target = McgMarshal.GetActivationFactory(
+ typeName,
+ McgModuleManager.IActivationFactoryInternal
+ );
+
+ IntPtr pIActivationFactoryInternalItf = target.QueryInterface_NoAddRef_Internal(
+ McgModuleManager.IActivationFactoryInternal,
+ /* cacheOnly= */ false,
+ /* throwOnQueryInterfaceFailure= */ true
+ );
+
+ __com_IActivationFactoryInternal* pIActivationFactoryInternal = (__com_IActivationFactoryInternal*)pIActivationFactoryInternalItf;
+
+ IntPtr pResult = default(IntPtr);
+
+ int hr = CalliIntrinsics.StdCall<int>(
+ pIActivationFactoryInternal->pVtable->pfnActivateInstance,
+ pIActivationFactoryInternal,
+ &pResult
+ );
+
+ GC.KeepAlive(target);
+
+ if (hr < 0)
+ {
+ throw McgMarshal.GetExceptionForHR(hr, /* isWinRTScenario = */ true);
+ }
+
+ return pResult;
+ }
+#endif
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static object GetDynamicAdapter(__ComObject obj, RuntimeTypeHandle typeHnd)
+ {
+ McgTypeInfo info = McgModuleManager.GetTypeInfoByHandle(typeHnd);
+ Debug.Assert(!info.IsNull);
+ return obj.GetDynamicAdapter(info);
+ }
+
+ /// <summary>
+ /// Marshal array of objects
+ /// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ unsafe public static void ObjectArrayToComInterfaceArray(uint len, System.IntPtr* dst, object[] src, RuntimeTypeHandle typeHnd)
+ {
+ for (uint i = 0; i < len; i++)
+ {
+ dst[i] = McgMarshal.ObjectToComInterface(src[i], McgModuleManager.GetTypeInfoByHandle(typeHnd));
+ }
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ unsafe public static void ObjectArrayToComInterfaceArray(uint len, System.IntPtr* dst, object[] src, McgTypeInfo specialTypeInfo)
+ {
+ Debug.Assert(!specialTypeInfo.IsNull); // this overload of the API is only for our 'special' indexes.
+ for (uint i = 0; i < len; i++)
+ {
+ dst[i] = McgModuleManager.ObjectToComInterface(src[i], specialTypeInfo);
+ }
+ }
+
+ /// <summary>
+ /// Allocate native memory, and then marshal array of objects
+ /// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ unsafe public static System.IntPtr* ObjectArrayToComInterfaceArrayAlloc(object[] src, RuntimeTypeHandle typeHnd, out uint len)
+ {
+ System.IntPtr* dst = null;
+
+ len = 0;
+
+ if (src != null)
+ {
+#if ENABLE_WINRT
+ // @TODO: this seems somewhat inefficient, should this be fixed by having the generated code
+ // call the right overload directly?
+ if (typeHnd.Equals(typeof(object).TypeHandle))
+ return ObjectArrayToComInterfaceArrayAlloc(src, McgModuleManager.IInspectable, out len);
+#endif
+ len = (uint)src.Length;
+
+ dst = (System.IntPtr*)ExternalInterop.CoTaskMemAlloc((System.IntPtr)(len * (sizeof(System.IntPtr))));
+
+ for (uint i = 0; i < len; i++)
+ {
+ dst[i] = McgMarshal.ObjectToComInterface(src[i], McgModuleManager.GetTypeInfoByHandle(typeHnd));
+ }
+ }
+
+ return dst;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ unsafe public static System.IntPtr* ObjectArrayToComInterfaceArrayAlloc(object[] src, McgTypeInfo specialTypeInfo, out uint len)
+ {
+ Debug.Assert(!specialTypeInfo.IsNull); // this overload of the API is only for our 'special' indexes.
+ System.IntPtr* dst = null;
+
+ len = 0;
+
+ if (src != null)
+ {
+ len = (uint)src.Length;
+
+ dst = (System.IntPtr*)ExternalInterop.CoTaskMemAlloc((System.IntPtr)(len * (sizeof(System.IntPtr))));
+
+ for (uint i = 0; i < len; i++)
+ {
+ dst[i] = McgModuleManager.ObjectToComInterface(src[i], specialTypeInfo);
+ }
+ }
+
+ return dst;
+ }
+
+ /// <summary>
+ /// (p/invoke delegate instance) -> (thunk)
+ /// Used in following scenarios:
+ /// 1) When marshalling managed delegates to native function pointer, the native function pointer
+ /// is pointing to the thunk address which calls the real marshalling code, which in turn retrieves
+ /// the current delegate instance based on the thunk address in order to make the call
+ /// 2) When marshalling the thunk address back, we need to retrieve the p/invoke delegate instance
+ ///
+ /// In both cases, the delegate is a managed delegate created from managed code
+ /// For delegates created from native function pointer, we use NativeFunctionWrapper to retrieve
+ /// the original function pointer. See GetStubForPInvokeDelegate for more details
+ /// </summary>
+ static System.Collections.Generic.Internal.Dictionary<IntPtr, DelegateInstEntry> s_thunkToPInvokeDelegateInstMap;
+
+ class DelegateInstEntry : IEquatable<DelegateInstEntry>
+ {
+ internal IntPtr Thunk;
+ internal GCHandle Handle;
+ internal int HashCode;
+
+ internal DelegateInstEntry(Delegate del, IntPtr pThunk)
+ {
+ Handle = GCHandle.Alloc(del, GCHandleType.Weak);
+ HashCode = RuntimeHelpers.GetHashCode(del);
+ Thunk = pThunk;
+ }
+
+ public static int GetHashCode(Delegate del)
+ {
+ return RuntimeHelpers.GetHashCode(del);
+ }
+
+ public bool Equals(DelegateInstEntry other)
+ {
+ return (Thunk == other.Thunk);
+ }
+
+ public bool Equals(Delegate del)
+ {
+ return (Object.ReferenceEquals(del, Handle.Target));
+ }
+ }
+
+ static bool GetPInvokeDelegateData(RuntimeTypeHandle delegateType, out McgPInvokeDelegateData pinvokeDelegateData)
+ {
+ pinvokeDelegateData = default(McgPInvokeDelegateData);
+
+ for (int i = 0; i < s_moduleCount; ++i)
+ {
+ if (s_modules[i].TryGetPInvokeDelegateData(delegateType, out pinvokeDelegateData))
+ {
+ return true;
+ }
+ }
+#if ENABLE_WINRT
+ throw new MissingInteropDataException(SR.DelegateMarshalling_MissingInteropData, Type.GetTypeFromHandle(delegateType));
+#else
+ return false;
+#endif
+ }
+
+ /// <summary>
+ /// Used to lookup whether a delegate already has an entry
+ /// </summary>
+ static System.Collections.Generic.Internal.HashSet<DelegateInstEntry> s_delegateInstEntryHashSet;
+
+ public static IntPtr GetStubForPInvokeDelegate(RuntimeTypeHandle delegateType, Delegate dele)
+ {
+ return GetStubForPInvokeDelegate(dele);
+ }
+
+ /// <summary>
+ /// Return the stub to the pinvoke marshalling stub
+ /// </summary>
+ /// <param name="del">The delegate</param>
+ static internal IntPtr GetStubForPInvokeDelegate(Delegate del)
+ {
+ if (del == null)
+ return IntPtr.Zero;
+
+ NativeFunctionPointerWrapper fpWrapper = del.Target as NativeFunctionPointerWrapper;
+ if (fpWrapper != null)
+ {
+ //
+ // Marshalling a delegate created from native function pointer back into function pointer
+ // This is easy - just return the 'wrapped' native function pointer
+ //
+ return fpWrapper.NativeFunctionPointer;
+ }
+ else
+ {
+ //
+ // Marshalling a managed delegate created from managed code into a native function pointer
+ //
+ return GetOrAllocateThunk(del);
+ }
+ }
+
+ static Collections.Generic.Internal.Dictionary<IntPtr, DelegateInstEntry> GetThunkMap(out System.Collections.Generic.Internal.HashSet<DelegateInstEntry> delegateMap)
+ {
+ //
+ // Create the map on-demand to avoid the dependency in the McgModule.ctor
+ // Otherwise NUTC will complain that McgModule being eager ctor depends on a deferred
+ // ctor type
+ //
+ if (s_thunkToPInvokeDelegateInstMap == null)
+ {
+ Interlocked.CompareExchange(
+ ref s_thunkToPInvokeDelegateInstMap,
+ new Collections.Generic.Internal.Dictionary<IntPtr, DelegateInstEntry>(/* sync = */ true),
+ null
+ );
+ }
+
+ if (s_delegateInstEntryHashSet == null)
+ {
+ Interlocked.CompareExchange(
+ ref s_delegateInstEntryHashSet,
+ new System.Collections.Generic.Internal.HashSet<DelegateInstEntry>(50),
+ null
+ );
+ }
+
+ delegateMap = s_delegateInstEntryHashSet;
+
+ return s_thunkToPInvokeDelegateInstMap;
+ }
+
+ const int THUNK_RECYCLING_FREQUENCY = 200; // Every 200 thunks that we allocate, do a round of cleanup
+ static List<IntPtr> s_thunksFreeupList = new List<IntPtr>(THUNK_RECYCLING_FREQUENCY); // Fixed sized buffer to keep track of thunks to free form the map
+
+ static private IntPtr GetOrAllocateThunk(Delegate del)
+ {
+#if ENABLE_WINRT
+ System.Collections.Generic.Internal.HashSet<DelegateInstEntry> delegateMap;
+ System.Collections.Generic.Internal.Dictionary<IntPtr, DelegateInstEntry> thunkMap = GetThunkMap(out delegateMap);
+
+ try
+ {
+ thunkMap.LockAcquire();
+
+ DelegateInstEntry key = null;
+ int hashCode = DelegateInstEntry.GetHashCode(del);
+ for (int entry = delegateMap.FindFirstKey(ref key, hashCode); entry >= 0; entry = delegateMap.FindNextKey(ref key, entry))
+ {
+ if (key.Equals(del))
+ return key.Thunk;
+ }
+
+ //
+ // Keep allocating thunks until we reach the recycling frequency - we have a virtually unlimited
+ // number of thunks that we can allocate (until we run out of virtual address space), but we
+ // still need to cleanup thunks that are no longer being used, to avoid leaking memory.
+ // This is helpful to detect bugs where user are calling into thunks whose delegate are already
+ // collected. In desktop CLR, they'll simple AV, while in .NET Native, there is a good chance we'll
+ // detect the delegate instance is NULL (by looking at the GCHandle in the map) and throw out a
+ // good exception
+ //
+ if (s_numInteropThunksAllocatedSinceLastCleanup == THUNK_RECYCLING_FREQUENCY)
+ {
+ //
+ // Cleanup the thunks that were previously allocated and are no longer in use to avoid memory leaks
+ //
+
+ GC.Collect();
+
+ foreach (var item in thunkMap)
+ {
+ // Don't exceed the size of the buffer to avoid new allocations during a freeing operation
+ if (s_thunksFreeupList.Count == THUNK_RECYCLING_FREQUENCY)
+ break;
+
+ DelegateInstEntry instEntry = item.Value;
+
+ if (instEntry.Handle.Target == null)
+ {
+ ThunkPool.FreeThunk(AsmCode.GetInteropCommonStubAddress(), instEntry.Thunk);
+ instEntry.Handle.Free();
+
+ bool removed = delegateMap.Remove(instEntry, instEntry.HashCode);
+ if (!removed)
+ Environment.FailFast("Inconsistency in delegate map");
+
+ s_thunksFreeupList.Add(instEntry.Thunk);
+ }
+ }
+ foreach (var item in s_thunksFreeupList)
+ {
+ bool removed = thunkMap.Remove(item);
+ if (!removed)
+ Environment.FailFast("Inconsistency in delegate map");
+ }
+ s_thunksFreeupList.Clear();
+
+ s_numInteropThunksAllocatedSinceLastCleanup = 0;
+ }
+
+
+ IntPtr pThunk = ThunkPool.AllocateThunk(AsmCode.GetInteropCommonStubAddress());
+
+ if (pThunk == IntPtr.Zero)
+ {
+ // We've either run out of memory, or failed to allocate a new thunk due to some other bug. Now we should fail fast
+ Environment.FailFast("Insufficient number of thunks.");
+ return IntPtr.Zero;
+ }
+ else
+ {
+ McgPInvokeDelegateData pinvokeDelegateData;
+ GetPInvokeDelegateData(del.GetTypeHandle(), out pinvokeDelegateData);
+ ThunkPool.SetThunkData(pThunk, pThunk, pinvokeDelegateData.ReverseStub);
+
+ s_numInteropThunksAllocatedSinceLastCleanup++;
+
+ //
+ // Allocate a weak GC handle pointing to the delegate
+ // Whenever the delegate dies, we'll know next time when we recycle thunks
+ //
+ DelegateInstEntry newEntry = new DelegateInstEntry(del, pThunk);
+
+ thunkMap.Add(pThunk, newEntry);
+ delegateMap.Add(newEntry, newEntry.HashCode);
+
+ return pThunk;
+ }
+ }
+ finally
+ {
+ thunkMap.LockRelease();
+ }
+#else
+ throw new PlatformNotSupportedException("GetOrAllocateThunk");
+#endif
+ }
+
+ /// <summary>
+ /// Retrieve the corresponding P/invoke instance from the stub
+ /// </summary>
+ static public Delegate GetPInvokeDelegateForStub(IntPtr pStub, RuntimeTypeHandle delegateType)
+ {
+ if (pStub == IntPtr.Zero)
+ return null;
+
+ System.Collections.Generic.Internal.HashSet<DelegateInstEntry> delegateMap;
+ System.Collections.Generic.Internal.Dictionary<IntPtr, DelegateInstEntry> thunkMap = GetThunkMap(out delegateMap);
+
+ //
+ // First try to see if this is one of the thunks we've allocated when we marshal a managed
+ // delegate to native code
+ //
+ try
+ {
+ thunkMap.LockAcquire();
+
+ DelegateInstEntry delegateEntry;
+ if (thunkMap.TryGetValue(pStub, out delegateEntry))
+ {
+ Delegate target = InteropExtensions.UncheckedCast<Delegate>(delegateEntry.Handle.Target);
+
+ //
+ // The delegate might already been garbage collected
+ // User should use GC.KeepAlive or whatever ways necessary to keep the delegate alive
+ // until they are done with the native function pointer
+ //
+ if (target == null)
+ {
+ Environment.FailFast(
+ "The corresponding delegate has been garbage collected. " +
+ "Please make sure the delegate is still referenced by managed code when you are using the marshalled native function pointer."
+ );
+ }
+
+ return target;
+ }
+ }
+ finally
+ {
+ thunkMap.LockRelease();
+ }
+
+ //
+ // Otherwise, the stub must be a pure native function pointer
+ // We need to create the delegate that points to the invoke method of a
+ // NativeFunctionPointerWrapper derived class
+ //
+ McgPInvokeDelegateData pInvokeDelegateData;
+ if (!GetPInvokeDelegateData(delegateType, out pInvokeDelegateData))
+ {
+ return null;
+ }
+
+ return CalliIntrinsics.Call__Delegate(
+ pInvokeDelegateData.ForwardDelegateCreationStub,
+ pStub
+ );
+ }
+
+ /// <summary>
+ /// Retrieves the current delegate that is being called
+ /// @TODO - We probably can do this more efficiently without taking a lock
+ /// </summary>
+ static public T GetCurrentCalleeDelegate<T>() where T : class // constraint can't be System.Delegate
+ {
+#if RHTESTCL || CORECLR
+ throw new NotSupportedException();
+#else
+ System.Collections.Generic.Internal.HashSet<DelegateInstEntry> delegateMap;
+ System.Collections.Generic.Internal.Dictionary<IntPtr, DelegateInstEntry> thunkMap = GetThunkMap(out delegateMap);
+
+ //
+ // RH keeps track of the current thunk that is being called through a secret argument / thread
+ // statics. No matter how that's implemented, we get the current thunk which we can use for
+ // look up later
+ //
+ IntPtr pThunk = AsmCode.GetCurrentInteropThunk();
+
+ try
+ {
+ thunkMap.LockAcquire();
+
+ DelegateInstEntry delegateEntry;
+ if (thunkMap.TryGetValue(pThunk, out delegateEntry))
+ {
+ object target = delegateEntry.Handle.Target;
+
+ //
+ // The delegate might already been garbage collected
+ // User should use GC.KeepAlive or whatever ways necessary to keep the delegate alive
+ // until they are done with the native function pointer
+ //
+ if (target == null)
+ {
+ Environment.FailFast(
+ "The corresponding delegate has been garbage collected. " +
+ "Please make sure the delegate is still referenced by managed code when you are using the marshalled native function pointer."
+ );
+ }
+
+ // Use a cast here to make sure we catch bugs in MCG code
+ return (T)target;
+ }
+ else
+ {
+ //
+ // The thunk is not in the map.
+ // This should never happen in current allocation policy because the thunk will not get
+ // released, but rather reused. If this indeed is happening, we have a bug
+ //
+ Environment.FailFast("Unrecongized thunk");
+
+ return (T)null;
+ }
+ }
+ finally
+ {
+ thunkMap.LockRelease();
+ }
+#endif
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgPInvokeMarshalStubAttribute.cs b/src/System.Private.Interop/src/Shared/McgPInvokeMarshalStubAttribute.cs
new file mode 100644
index 000000000..f10cab868
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgPInvokeMarshalStubAttribute.cs
@@ -0,0 +1,24 @@
+// 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
+{
+ /// <summary>
+ /// The McgPInvokeMarshalStubAttribute is generated by MCG to indicate what is exact method that this
+ /// particular P/Invoke is for.
+ ///
+ /// For example, user could write [DllImport] Program.MyFunc. MCG will import this P/Invoke and will
+ /// generate another function with the real marshalling code which has this attribute that tells us
+ /// what the user P/invoke really is. And our PInvokeTransform will take care of injecting the MCG
+ /// generated function body into the user P/invoke.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+ public sealed class McgPInvokeMarshalStubAttribute : Attribute
+ {
+ public McgPInvokeMarshalStubAttribute(string assemblyName, string typeName, string methodName)
+ {
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgRedirectedTypeAttribute.cs b/src/System.Private.Interop/src/Shared/McgRedirectedTypeAttribute.cs
new file mode 100644
index 000000000..150e64d53
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgRedirectedTypeAttribute.cs
@@ -0,0 +1,13 @@
+// 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
+{
+ [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+ public sealed class McgRedirectedTypeAttribute : System.Attribute
+ {
+ public McgRedirectedTypeAttribute(string assemblyQualifiedTypeName) { }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgRemovedType.cs b/src/System.Private.Interop/src/Shared/McgRemovedType.cs
new file mode 100644
index 000000000..044db4485
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgRemovedType.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.Diagnostics;
+
+namespace System.Runtime.InteropServices
+{
+ // This type should never be directly used. The RemoveDeadReferences transform
+ // can replace Types that should not be used with this type.
+ public class McgRemovedType
+ {
+ public McgRemovedType()
+ {
+ Debug.Assert(false, "A type that was removed by MCG dependency reduction has been instantiated.");
+ throw new Exception(SR.Arg_RemovedTypeInstantiated);
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgRootsTypeAttribute.cs b/src/System.Private.Interop/src/Shared/McgRootsTypeAttribute.cs
new file mode 100644
index 000000000..33abeebda
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgRootsTypeAttribute.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// MCG applies this attribute to CCW vtables with a parameter of their interface.
+ /// This has the effect of causing the vtable to root the interface, which may otherwise
+ /// be elligible for dependency reduction.
+ /// </summary>
+ /// <example>
+ /// [System.Runtime.InteropServices.McgRootsTypeAttribute(typeof(Windows.UI.Xaml.IDependencyObject))]
+ /// internal unsafe partial struct __vtable_Windows_UI_Xaml__IDependencyObject
+ /// </example>
+ [AttributeUsage(AttributeTargets.Struct, AllowMultiple = true, Inherited = false)]
+ public sealed class McgRootsTypeAttribute : System.Attribute
+ {
+ public McgRootsTypeAttribute(Type rootedType) { }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgTypeHelpers.cs b/src/System.Private.Interop/src/Shared/McgTypeHelpers.cs
new file mode 100644
index 000000000..5c32c3ade
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgTypeHelpers.cs
@@ -0,0 +1,750 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// ----------------------------------------------------------------------------------
+// Interop library code
+//
+// Type marshalling helpers used by MCG
+//
+// NOTE:
+// These source code are being published to InternalAPIs and consumed by RH builds
+// Use PublishInteropAPI.bat to keep the InternalAPI copies in sync
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Text;
+using System.Runtime;
+using System.Diagnostics.Contracts;
+using Internal.NativeFormat;
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices
+{
+ internal static class McgTypeHelpers
+ {
+ static readonly Type[] s_wellKnownTypes = new Type[]
+ {
+ typeof(Boolean),
+ typeof(Char),
+ typeof(Byte),
+ typeof(Int16),
+ typeof(UInt16),
+ typeof(Int32),
+ typeof(UInt32),
+ typeof(Int64),
+ typeof(UInt64),
+ typeof(Single),
+ typeof(Double),
+ typeof(String),
+ typeof(Object),
+ typeof(Guid)
+ };
+
+ static readonly string[] s_wellKnownTypeNames = new string[]
+ {
+ "Boolean",
+ "Char16",
+ "UInt8",
+ "Int16",
+ "UInt16",
+ "Int32",
+ "UInt32",
+ "Int64",
+ "UInt64",
+ "Single",
+ "Double",
+ "String",
+ "Object",
+ "Guid"
+ };
+
+ private const string PseudonymPrefix = "System.Runtime.InteropServices.RuntimePseudonyms.";
+#if ENABLE_WINRT
+ /// <summary>
+ /// A 'fake' System.Type instance for native WinMD types (metadata types) that are not needed in
+ /// managed code, which means it is:
+ /// 1. Imported in MCG, but reduced away by reducer
+ /// 2. Not imported by MCG at all
+ /// In either case, it is possible that it is needed only in native code, and native code can return
+ /// a IXamlType instance to C# xaml compiler generated code that attempts to call get_UnderlyingType
+ /// which tries to convert a TypeName to System.Type and then stick it into a cache. In order to make
+ /// such scenario work, we need to create a fake System.Type instance that is unique to the name
+ /// and is roundtrippable.
+ /// As long as it is only used in the cache scenarios in xaml compiler generated code, we should be
+ /// fine. Any other attempt to use such types will surely result an exception
+ /// NOTE: in order to avoid returning fake types for random non-existent metadata types, we look
+ /// in McgAdditionalClassData (which encodes all interesting class data) before we create such fake
+ /// types
+ /// </summary>
+ class McgFakeMetadataType
+#if RHTESTCL
+ : Type
+#else
+ : Internal.Reflection.Extensibility.ExtensibleType
+#endif
+ {
+ /// <summary>
+ /// Full type name of the WinMD type
+ /// </summary>
+ string _fullTypeName;
+
+ public McgFakeMetadataType(string fullTypeName, TypeKind typeKind)
+#if RHTESTCL
+ : base(default(RuntimeTypeHandle))
+#else
+ : base()
+#endif
+ {
+ _fullTypeName = fullTypeName;
+ TypeKind = typeKind;
+ }
+
+ public TypeKind TypeKind { get; private set; }
+
+#if RHTESTCL
+ public string FullName { get { return _fullTypeName; } }
+#else
+ public override String AssemblyQualifiedName { get { throw new System.Reflection.MissingMetadataException(_fullTypeName); } }
+
+ public override Type DeclaringType { get { throw new System.Reflection.MissingMetadataException(_fullTypeName); } }
+ public override String FullName { get { return _fullTypeName; } }
+ public override int GenericParameterPosition { get { throw new System.Reflection.MissingMetadataException(_fullTypeName); } }
+ public override Type[] GenericTypeArguments { get { throw new System.Reflection.MissingMetadataException(_fullTypeName); } }
+
+ public override bool IsConstructedGenericType { get { throw new System.Reflection.MissingMetadataException(_fullTypeName); } }
+ public override bool IsGenericParameter { get { throw new System.Reflection.MissingMetadataException(_fullTypeName); } }
+
+ public override String Name { get { throw new System.Reflection.MissingMetadataException(_fullTypeName); } }
+ public override String Namespace { get { throw new System.Reflection.MissingMetadataException(_fullTypeName); } }
+
+ public override int GetArrayRank() { throw new System.Reflection.MissingMetadataException(_fullTypeName); }
+ public override Type GetElementType() { throw new System.Reflection.MissingMetadataException(_fullTypeName); }
+ public override Type GetGenericTypeDefinition() { throw new System.Reflection.MissingMetadataException(_fullTypeName); }
+
+ public override Type MakeArrayType() { throw new System.Reflection.MissingMetadataException(_fullTypeName); }
+ public override Type MakeArrayType(int rank) { throw new System.Reflection.MissingMetadataException(_fullTypeName); }
+ public override Type MakeByRefType() { throw new System.Reflection.MissingMetadataException(_fullTypeName); }
+ public override Type MakeGenericType(params Type[] typeArguments) { throw new System.Reflection.MissingMetadataException(_fullTypeName); }
+ public override Type MakePointerType() { throw new System.Reflection.MissingMetadataException(_fullTypeName); }
+
+ public override String ToString()
+ {
+ return "Type: " + _fullTypeName;
+ }
+
+ public override bool Equals(Object o)
+ {
+ if (o == null)
+ return false;
+
+ //
+ // We guarantee uniqueness in Mcg marshalling code
+ //
+ if (o == this)
+ return true;
+
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return _fullTypeName.GetHashCode();
+ }
+#endif //RHTESTCL
+ }
+
+
+ internal unsafe static void TypeToTypeName(
+ Type type,
+ out HSTRING nativeTypeName,
+ out int nativeTypeKind)
+ {
+ if (type == null)
+ {
+ nativeTypeName.handle = default(IntPtr);
+ nativeTypeKind = (int)TypeKind.Custom;
+ }
+ else
+ {
+ McgFakeMetadataType fakeType = type as McgFakeMetadataType;
+ if (fakeType != null)
+ {
+ //
+ // Handle round tripping fake types
+ // See McgFakeMetadataType for details
+ //
+ nativeTypeKind = (int)fakeType.TypeKind;
+ nativeTypeName = McgMarshal.StringToHString(fakeType.FullName);
+ }
+ else
+ {
+ string typeName;
+ TypeKind typeKind;
+ TypeToTypeName(type.TypeHandle, out typeName, out typeKind);
+
+ nativeTypeName = McgMarshal.StringToHString(typeName);
+ nativeTypeKind = (int)typeKind;
+ }
+ }
+ }
+#endif //!CORECLR
+ private unsafe static void TypeToTypeName(
+ RuntimeTypeHandle typeHandle,
+ out string typeName,
+ out TypeKind typeKind)
+ {
+ //
+ // Primitive types
+ //
+ for (int i = 0; i < s_wellKnownTypes.Length; i++)
+ {
+ if (s_wellKnownTypes[i].TypeHandle.Equals(typeHandle))
+ {
+ typeName = s_wellKnownTypeNames[i];
+ typeKind = TypeKind.Primitive;
+
+ return;
+ }
+ }
+
+ //
+ // User-imported types
+ //
+ bool isWinRT;
+ string name = McgModuleManager.GetTypeName(typeHandle, out isWinRT);
+
+ if (name != null)
+ {
+ typeName = name;
+ typeKind =
+ (isWinRT ?
+ TypeKind.Metadata :
+ TypeKind.Custom);
+
+ return;
+ }
+
+ //
+ // Handle managed types
+ //
+ typeName = GetCustomTypeName(typeHandle);
+ typeKind = TypeKind.Custom;
+ }
+
+ static System.Collections.Generic.Internal.Dictionary<string, Type> s_fakeTypeMap
+ = new Collections.Generic.Internal.Dictionary<string, Type>();
+ static Lock s_fakeTypeMapLock = new Lock();
+ static System.Collections.Generic.Internal.Dictionary<RuntimeTypeHandle, Type> s_realToFakeTypeMap
+ = new System.Collections.Generic.Internal.Dictionary<RuntimeTypeHandle, Type>();
+
+#if ENABLE_WINRT
+ /// <summary>
+ /// Returns a type usable in XAML roundtripping whether it's reflectable or not
+ /// </summary>
+ /// <param name="realType">Type for the real object</param>
+ /// <returns>realType if realType is reflectable, otherwise a fake type that can be roundtripped
+ /// and won't throw for XAML usage.</returns>
+ internal static Type GetReflectableOrFakeType(Type realType)
+ {
+#if !RHTESTCL
+ if(realType.SupportsReflection())
+ {
+ return realType;
+ }
+#endif
+
+ s_fakeTypeMapLock.Acquire();
+ try
+ {
+ Type fakeType;
+ RuntimeTypeHandle realTypeHandle = realType.TypeHandle;
+ if (s_realToFakeTypeMap.TryGetValue(realTypeHandle, out fakeType))
+ {
+ return fakeType;
+ }
+
+ string pseudonym = GetPseudonymForType(realTypeHandle, /* useFake: */ true);
+ fakeType = new McgFakeMetadataType(pseudonym, TypeKind.Custom);
+ s_realToFakeTypeMap.Add(realTypeHandle, fakeType);
+ s_fakeTypeMap.Add(pseudonym, fakeType);
+
+ return fakeType;
+ }
+ finally
+ {
+ s_fakeTypeMapLock.Release();
+ }
+ }
+
+ internal static unsafe Type TypeNameToType(HSTRING nativeTypeName, int nativeTypeKind)
+ {
+ string name = McgMarshal.HStringToString(nativeTypeName);
+
+ if (!string.IsNullOrEmpty(name))
+ {
+ //
+ // Well-known types
+ //
+ for (int i = 0; i < s_wellKnownTypeNames.Length; i++)
+ {
+ if (s_wellKnownTypeNames[i] == name)
+ {
+ if (nativeTypeKind != (int)TypeKind.Primitive)
+ throw new ArgumentException(SR.Arg_UnexpectedTypeKind);
+
+ return s_wellKnownTypes[i];
+ }
+ }
+
+ if (nativeTypeKind == (int)TypeKind.Primitive)
+ {
+ //
+ // We've scanned all primitive types that we know of and came back nothing
+ //
+ throw new ArgumentException("Unrecognized primitive type name");
+ }
+
+ //
+ // User-imported types
+ // Try to get a type if MCG knows what this is
+ // If the returned type does not have metadata, the type is no good as Jupiter needs to pass
+ // it to XAML type provider code which needs to call FullName on it
+ //
+ bool isWinRT;
+ Type type = McgModuleManager.GetTypeFromName(name, out isWinRT);
+
+#if !RHTESTCL
+ if (type != null && !type.SupportsReflection())
+ type = null;
+#endif
+
+ //
+ // If we got back a type that is valid (not reduced)
+ //
+ if (type != null && !type.TypeHandle.Equals(McgModule.s_DependencyReductionTypeRemovedTypeHandle))
+ {
+ if (nativeTypeKind !=
+ (int)
+ (isWinRT ? TypeKind.Metadata : TypeKind.Custom))
+ throw new ArgumentException(SR.Arg_UnexpectedTypeKind);
+ return type;
+ }
+
+ if (nativeTypeKind == (int)TypeKind.Metadata)
+ {
+ //
+ // Handle converting native WinMD type names to fake McgFakeMetadataType to make C# xaml
+ // compiler happy
+ // See McgFakeMetadataType for more details
+ //
+ s_fakeTypeMapLock.Acquire();
+ try
+ {
+ if (s_fakeTypeMap.TryGetValue(name, out type))
+ {
+ return type;
+ }
+ else
+ {
+ type = new McgFakeMetadataType(name, TypeKind.Metadata);
+ s_fakeTypeMap.Add(name, type);
+ return type;
+ }
+ }
+ finally
+ {
+ s_fakeTypeMapLock.Release();
+ }
+ }
+
+
+ if (nativeTypeKind != (int)TypeKind.Custom)
+ throw new ArgumentException(SR.Arg_UnrecognizedTypeName);
+
+ //
+ // Arbitrary managed types. See comment in TypeToTypeName.
+ //
+ return StringToCustomType(name);
+ }
+
+ return null;
+ }
+#endif
+ private static string GetCustomTypeName(RuntimeTypeHandle type)
+ {
+ //
+ // For types loaded by the runtime, we may not have metadata from which to get the name.
+ // So we use the RuntimeTypeHandle instead. For types loaded via reflection, we may not
+ // have a RuntimeTypeHandle, in which case we will try to use the name.
+ //
+
+#if !RHTESTCL
+ Type realType = InteropExtensions.GetTypeFromHandle(type);
+ if (realType.SupportsReflection())
+ {
+ //
+ // Managed types that has reflection metadata
+ //
+ // Use the fully assembly qualified name to make Jupiter happy as Jupiter might parse the
+ // name (!!) to extract the assembly name to look up files from directory with the same
+ // name. A bug has filed to them to fix this for the next release, because the format
+ // of Custom TypeKind is up to the interpretation of the projection layer and is supposed
+ // to be an implementation detail
+ // NOTE: The try/catch is added as a fail-safe
+ //
+ try
+ {
+ return realType.AssemblyQualifiedName;
+ }
+ catch (MissingMetadataException ex)
+ {
+ ExternalInterop.OutputDebugString(
+ SR.Format(SR.TypeNameMarshalling_MissingMetadata, ex.Message)
+ );
+ }
+ }
+#endif
+
+ return GetPseudonymForType(type, /* useFake: */ false);
+ }
+
+ private static string GetPseudonymForType(RuntimeTypeHandle type, bool useFake)
+ {
+ // I'd really like to use the standard .net string formatting stuff here,
+ // but not enough of it is supported by rhtestcl.
+ ulong value = (ulong)type.GetRawValue();
+
+ StringBuilder sb = new StringBuilder(PseudonymPrefix, PseudonymPrefix.Length + 17);
+ if(useFake)
+ {
+ sb.Append('f');
+ }
+ else
+ {
+ sb.Append('r');
+ }
+
+ // append 64 bits, high to low, one nibble at a time
+ for (int shift = 60; shift >= 0; shift -= 4)
+ {
+ ulong nibble = (value >> shift) & 0xf;
+ if (nibble < 10)
+ sb.Append((char)(nibble + '0'));
+ else
+ sb.Append((char)((nibble - 10) + 'A'));
+ }
+
+ string result = sb.ToString();
+ return result;
+ }
+
+ private static Type StringToCustomType(string s)
+ {
+ ulong value = 0;
+
+ if (s.StartsWith(PseudonymPrefix))
+ {
+ //
+ // This is a name created from a RuntimeTypeHandle that does not have reflection metadata
+ //
+ if (s.Length != PseudonymPrefix.Length + 17)
+ throw new ArgumentException(SR.Arg_InvalidCustomTypeNameValue);
+
+ bool useFake = s[PseudonymPrefix.Length] == 'f';
+ if (useFake)
+ {
+ s_fakeTypeMapLock.Acquire();
+ try
+ {
+ return s_fakeTypeMap[s];
+ }
+ finally
+ {
+ s_fakeTypeMapLock.Release();
+ }
+ }
+
+ for (int i = PseudonymPrefix.Length + 1; i < s.Length; i++)
+ {
+ char c = s[i];
+ ulong nibble;
+
+ if (c >= '0' && c <= '9')
+ nibble = (ulong)(c - '0');
+ else if (c >= 'A' && c <= 'F')
+ nibble = (ulong)(c - 'A') + 10;
+ else
+ throw new ArgumentException(SR.Arg_InvalidCustomTypeNameValue);
+
+ value = (value << 4) | nibble;
+ }
+
+ return InteropExtensions.GetTypeFromHandle((IntPtr)value);
+ }
+#if !RHTESTCL
+ else
+ {
+ //
+ // Try reflection
+ // If reflection failed, this is a type name that we don't know about
+ // In theory we could support round tripping of such types.
+ //
+ Type reflectType = Type.GetType(s);
+ if (reflectType == null)
+ throw new ArgumentException("Unrecognized custom TypeName");
+
+ return reflectType;
+ }
+#else
+ else
+ {
+ return null;
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Try to get Diagnostic String for given RuntimeTypeHandle
+ /// Diagnostic usually means MissingMetadata Message
+ /// </summary>
+ /// <param name="interfaceType"></param>
+ /// <returns></returns>
+ public static string GetDiagnosticMessageForMissingType(RuntimeTypeHandle interfaceType)
+ {
+#if ENABLE_WINRT
+ string msg = string.Empty;
+ try
+ {
+ // case 1: missing reflection metadata for interfaceType
+ // if this throws, we just return MissMetadataException Message
+ string typeName = interfaceType.GetDisplayName();
+
+ // case 2: if intefaceType is ICollection<T>/IReadOnlyCollection<T>,
+ // we need to find out its corresponding WinRT Interface and ask users to root them.
+ // Current there is an issue for projected type in rd.xml file--if user specify IList<T> in rd.xml,
+ // DR will only root IList<T> instead of both IList<T> and IVector<T>
+
+ Type type = interfaceType.GetType();
+ if (InteropExtensions.IsGenericType(interfaceType)
+ && type.GenericTypeArguments != null
+ && type.GenericTypeArguments.Length == 1)
+ {
+ List<string> missTypeNames = new List<string>();
+ Type genericType = type.GetGenericTypeDefinition();
+ bool isICollectOfT = false;
+ bool isIReadOnlyCollectOfT = false;
+ if (genericType.TypeHandle.Equals(typeof(ICollection<>).TypeHandle))
+ {
+ isICollectOfT = true;
+ Type argType = type.GenericTypeArguments[0];
+ if (argType.IsConstructedGenericType && argType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
+ {
+ // the missing type could be either IMap<K,V> or IVector<IKeyValuePair<K,v>>
+ missTypeNames.Add(
+ McgTypeHelpers.ConstructGenericTypeFullName(
+ "Windows.Foundation.Collections.IMap",
+ new string[]
+ {
+ argType.GenericTypeArguments[0].ToString(),
+ argType.GenericTypeArguments[1].ToString()
+ }
+ )
+ );
+ missTypeNames.Add(
+ McgTypeHelpers.ConstructGenericTypeFullName(
+ "Windows.Foundation.Collections.IVector",
+ new String[]
+ {
+ McgTypeHelpers.ConstructGenericTypeFullName(
+ "Windows.Foundation.Collections.IKeyValuePair",
+ new string[]
+ {
+ argType.GenericTypeArguments[0].ToString(),
+ argType.GenericTypeArguments[1].ToString()
+ }
+ )
+ }
+ )
+ );
+ }
+ else
+ {
+ // the missing type is IVector<T>
+ missTypeNames.Add(
+ McgTypeHelpers.ConstructGenericTypeFullName(
+ "Windows.Foundation.Collections.IVector",
+ new string[]
+ {
+ argType.ToString()
+ }
+ )
+ );
+ }
+ } // genericType == typeof(ICollection<>)
+ else if (genericType == typeof(IReadOnlyCollection<>))
+ {
+ isIReadOnlyCollectOfT = true;
+ Type argType = type.GenericTypeArguments[0];
+ if (argType.IsConstructedGenericType && argType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
+ {
+ // the missing type could be either IVectorView<IKeyValuePair<K,v>> or IMapView<K,V>
+ missTypeNames.Add(
+ McgTypeHelpers.ConstructGenericTypeFullName(
+ "Windows.Foundation.Collections.IVectorView",
+ new String[]
+ {
+ McgTypeHelpers.ConstructGenericTypeFullName(
+ "Windows.Foundation.Collections.IKeyValuePair",
+ new string[]
+ {
+ argType.GenericTypeArguments[0].ToString(),
+ argType.GenericTypeArguments[1].ToString()
+ }
+ )
+ }
+ )
+ );
+ missTypeNames.Add(
+ McgTypeHelpers.ConstructGenericTypeFullName(
+ "Windows.Foundation.Collections.IMapView",
+ new string[]
+ {
+ argType.GenericTypeArguments[0].ToString(),
+ argType.GenericTypeArguments[1].ToString()
+ }
+ )
+ );
+ }
+ else
+ {
+ //the missing type is IVectorView<T>
+ missTypeNames.Add(
+ McgTypeHelpers.ConstructGenericTypeFullName(
+ "Windows.Foundation.Collections.IVectorView",
+ new string[]
+ {
+ argType.ToString()
+ }
+ )
+ );
+ }
+ }
+
+ if (isICollectOfT || isIReadOnlyCollectOfT)
+ {
+ // Concat all missing Type Names into one message
+ for (int i = 0; i < missTypeNames.Count; i++)
+ {
+ msg += String.Format(SR.ComTypeMarshalling_MissingInteropData, missTypeNames[i]);
+ if (i != missTypeNames.Count - 1)
+ msg += Environment.NewLine;
+ }
+ return msg;
+ }
+ }
+
+ // case 3: We can get type name but not McgTypeInfo, maybe another case similar to case 2
+ // definitely is a bug.
+ msg = String.Format(SR.ComTypeMarshalling_MissingInteropData, Type.GetTypeFromHandle(interfaceType));
+ }
+ catch (MissingMetadataException ex)
+ {
+ msg = ex.Message;
+ }
+ return msg;
+#else
+ return interfaceType.ToString();
+#endif //ENABLE_WINRT
+ }
+
+ // Construct Generic Type Full Name
+ private static string ConstructGenericTypeFullName(string genericTypeDefinitionFullName, string[] genericTypeArguments)
+ {
+ string fullName = genericTypeDefinitionFullName;
+ fullName += "<";
+ for (int i = 0; i < genericTypeArguments.Length; i++)
+ {
+ if (i != 0)
+ fullName += ",";
+ fullName += genericTypeArguments[i];
+ }
+ fullName += ">";
+ return fullName;
+ }
+ }
+ internal static class TypeHandleExtensions
+ {
+ internal static string GetDisplayName(this RuntimeTypeHandle handle)
+ {
+#if ENABLE_WINRT
+ return Internal.Reflection.Execution.PayForPlayExperience.MissingMetadataExceptionCreator.ComputeUsefulPertainantIfPossible(Type.GetTypeFromHandle(handle));
+#else
+ return handle.ToString();
+#endif
+ }
+ }
+ public static class TypeOfHelper
+ {
+ static void RuntimeTypeHandleOf_DidntGetTransformedAway()
+ {
+#if !RHTESTCL
+ Debug.Assert(false);
+#endif // RHTESTCL
+ }
+
+ public static RuntimeTypeHandle RuntimeTypeHandleOf(string typeName)
+ {
+ RuntimeTypeHandleOf_DidntGetTransformedAway();
+ return default(RuntimeTypeHandle);
+ }
+
+ public static RuntimeTypeHandle RuntimeTypeHandleOf(string typeName, string arg)
+ {
+ RuntimeTypeHandleOf_DidntGetTransformedAway();
+ return default(RuntimeTypeHandle);
+ }
+
+ public static RuntimeTypeHandle RuntimeTypeHandleOf(string typeName, string arg1, string arg2)
+ {
+ RuntimeTypeHandleOf_DidntGetTransformedAway();
+ return default(RuntimeTypeHandle);
+ }
+
+ public static RuntimeTypeHandle RuntimeTypeHandleOf(string typeName, string arg1, string arg2, string arg3)
+ {
+ RuntimeTypeHandleOf_DidntGetTransformedAway();
+ return default(RuntimeTypeHandle);
+ }
+
+ public static RuntimeTypeHandle RuntimeTypeHandleOf(string typeName, string arg1, string arg2, string arg3, string arg4)
+ {
+ RuntimeTypeHandleOf_DidntGetTransformedAway();
+ return default(RuntimeTypeHandle);
+ }
+
+ public static RuntimeTypeHandle RuntimeTypeHandleOf(string typeName, string arg1, string arg2, string arg3, string arg4, string arg5)
+ {
+ RuntimeTypeHandleOf_DidntGetTransformedAway();
+ return default(RuntimeTypeHandle);
+ }
+
+ public static RuntimeTypeHandle RuntimeTypeHandleOf(string typeName, string arg1, string arg2, string arg3, string arg4, string arg5, string arg6)
+ {
+ RuntimeTypeHandleOf_DidntGetTransformedAway();
+ return default(RuntimeTypeHandle);
+ }
+
+ public static Type TypeOf(string typeName)
+ {
+ RuntimeTypeHandleOf_DidntGetTransformedAway();
+ return default(Type);
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgWindowsRuntimeVersionAttribute.cs b/src/System.Private.Interop/src/Shared/McgWindowsRuntimeVersionAttribute.cs
new file mode 100644
index 000000000..3cd8024cd
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgWindowsRuntimeVersionAttribute.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
+{
+ /// <summary>
+ /// The McgWindowsRuntimeVersionAttribute is generated by MCG to indicate what version the code
+ /// generated for a WinRT type is meant to support. This is distinct from the WinRT Version attribute
+ /// in that the WinRT attribute indicates the minimum version required to use the decorated item.
+ /// This attribute indicates the maximum version that the generated code can be used for.
+ ///
+ /// For example, if a WinRT class has a Version(8), and an Activatable(9) attribute, then it would
+ /// get a McgWindowsRuntimeVersionAttribute(9) indicating that it has code to support up to version 9
+ /// of the type (when the activatable attribute was added).
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+ public sealed class McgWindowsRuntimeVersionAttribute : Attribute
+ {
+ public McgWindowsRuntimeVersionAttribute(int version)
+ {
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/McgredirectedMethodAttribute.cs b/src/System.Private.Interop/src/Shared/McgredirectedMethodAttribute.cs
new file mode 100644
index 000000000..1bde91f7c
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/McgredirectedMethodAttribute.cs
@@ -0,0 +1,13 @@
+// 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
+{
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+ public sealed class McgRedirectedMethodAttribute : System.Attribute
+ {
+ public McgRedirectedMethodAttribute(string assemblyQualifiedTypeName, string methodName) { }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/RCWWalker.cs b/src/System.Private.Interop/src/Shared/RCWWalker.cs
new file mode 100644
index 000000000..f26464d3d
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/RCWWalker.cs
@@ -0,0 +1,1320 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+// Jupiter Lifetime Support
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Threading;
+using System.Text;
+using System.Reflection;
+
+// Needed for NativeCallable attribute
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// GCCallbackAttribute
+ ///
+ /// This attribute doesn't do anything yet. It is there to tell whoever's looking at the code to be
+ /// very CAREFUL when changing the code that is marked by this attribute
+ ///
+ /// This attribute marks a function that could be called inside a GC Callback, which by its nature is
+ /// very dangerous. Any code inside this function (including the transitive closure) needs to satisfy
+ /// the following requirements:
+ ///
+ /// 1. NO MANAGED ALLOCATION
+ ///
+ /// The reason of this one is very simple: doing a 'new' could trigger a GC and triggering GC inside GC
+ /// would deadlock.
+ ///
+ /// Therefore, you can't write any code that call 'new', and you have to be VERY careful not to call any
+ /// code that could potentially do it - you might be really surprised to find out many of our library
+ /// routine does that in surprising places.
+ ///
+ /// This also implies no boxing, no throwing.
+ ///
+ /// The best way to make sure is to write your own code.
+ ///
+ /// 2. NO UNMANAGED CALLI AND NATIVECALLABLE
+ ///
+ /// The unmanaged calli and reverse calli thunks does a GC wait which again would deadlock. The simple
+ /// solution here is to simply converts all of them to managed calls (CalliIntrinsics.Call) and callbacks
+ /// (Simply don't add NativeCallable) and only utilize them under x64/arm (where the calling convention
+ /// doesn't matter). This works out just fine because x86 isn't a supported platform in .NET Native anyway,
+ /// and under x86 we can "safely" just let everything leak.
+ ///
+ /// See __vtable_IFindDependentWrappers for how to do this
+ ///
+ /// 3. NO CASTS (and whatever that is reading the EEType)
+ ///
+ /// GC will mark EETypes with a special bit and this will throw off whatever code that is not "GC-aware".
+ ///
+ /// </summary>
+ class GCCallbackAttribute : Attribute
+ {
+ }
+
+ /// <summary>
+ /// Windows.UI.Xaml.Hosting.IReferenceTracker
+ ///
+ /// Every Jupiter UI object implements IJupiterObject for lifetime management support
+ /// </summary>
+ internal unsafe struct __com_IJupiterObject
+ {
+#pragma warning disable 0649
+ public __vtable_IJupiterObject* pVtable;
+#pragma warning restore 0649
+ }
+
+ /// <summary>
+ /// V-table for IJupiterObject
+ /// NOTE: no need to implement this v-table because Jupiter implements it, not us
+ /// </summary>
+ internal unsafe struct __vtable_IJupiterObject
+ {
+ // rgIUnknown is only used for making sure the rest of the fields have the right offset
+#pragma warning disable 0169
+ __vtable_IUnknown rgIIUnknown;
+#pragma warning restore 0169
+
+ // We never implement these functions - instead, we call Jupiter's implementation
+#pragma warning disable 0649
+ internal System.IntPtr pfnConnect;
+ internal System.IntPtr pfnDisconnect;
+ internal System.IntPtr pfnFindDependentWrappers;
+ internal System.IntPtr pfnGetJupiterGCManager;
+ internal System.IntPtr pfnAfterAddRef;
+ internal System.IntPtr pfnBeforeRelease;
+ internal System.IntPtr pfnPeg;
+#pragma warning restore 0649
+ }
+
+ /// <summary>
+ /// Windows.UI.Xaml.Hosting.IFindReferenceTargetsCallback
+ ///
+ /// Jupiter fires this callback to tell us the corresponding CCWs reachable from a specific RCW
+ /// </summary>
+ internal unsafe struct __com_IFindDependentWrappers
+ {
+#pragma warning disable 0649
+ internal __vtable_IFindDependentWrappers* pVtable;
+#pragma warning restore 0649
+ }
+
+ /// <summary>
+ /// V-table implementation for IFindDependentWrappers
+ ///
+ /// NOTE: This v-table implementation doesn't rely on the default implementation of IUnknown -
+ /// instead it implements its own IUnknown and acts like a COM object by itself
+ /// </summary>
+ internal unsafe struct __vtable_IFindDependentWrappers
+ {
+ __vtable_IUnknown rgIIUnknown;
+ internal System.IntPtr pfnOnFoundDependentWrapper;
+
+ static __vtable_IFindDependentWrappers s_theVtable;
+
+ internal static __vtable_IFindDependentWrappers* GetVtable()
+ {
+ s_theVtable.InitVtable();
+
+ // REDHAWK-ONLY: static field storage is unmovable
+ fixed (__vtable_IFindDependentWrappers* pVtable = &s_theVtable)
+ return pVtable;
+ }
+
+ private void InitVtable()
+ {
+ rgIIUnknown.pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(AddRef__STUB);
+ rgIIUnknown.pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(Release__STUB);
+ rgIIUnknown.pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(QueryInterface__STUB);
+ pfnOnFoundDependentWrapper = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(OnFoundDependentWrapper__STUB);
+ }
+
+ /// <summary>
+ /// Implements AddRef
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function might be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ [NativeCallable]
+ static int AddRef__STUB(System.IntPtr pComThis)
+ {
+ // This never gets released from native
+ return 1;
+ }
+
+ /// <summary>
+ /// Implements Release
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function might be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ [NativeCallable]
+ static int Release__STUB(System.IntPtr pComThis)
+ {
+ // This never gets released from native
+ return 1;
+ }
+
+ /// <summary>
+ /// Implements QueryInterface
+ /// We only respond to IUnknown and IFindDependentWrappers
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function might be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ [NativeCallable]
+ static int QueryInterface__STUB(
+ System.IntPtr IntPtr__pComThis,
+ System.IntPtr IntPtr__pIID,
+ System.IntPtr IntPtr__ppvObject)
+ {
+ __com_IFindDependentWrappers* pComThis = (__com_IFindDependentWrappers*)IntPtr__pComThis.ToPointer();
+ Guid* pIID = (Guid*)IntPtr__pIID.ToPointer();
+ void** ppvObject = (void**)IntPtr__ppvObject.ToPointer();
+
+ if (pIID->Equals(Interop.COM.IID_IUnknown) ||
+ pIID->Equals(Interop.COM.IID_IFindDependentWrappers))
+ {
+ // You'll always get IFindDependentWrappers *
+ // No need to AddRef - this is always 'alive' in the sense that it will be a pointer to a
+ // static v-table
+ *ppvObject = pComThis;
+
+ return Interop.COM.S_OK;
+ }
+
+ return Interop.COM.E_NOINTERFACE;
+ }
+
+ /// <summary>
+ /// Implements OnFoundDependentWrapper
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function might be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ [NativeCallable]
+ static int OnFoundDependentWrapper__STUB(System.IntPtr pComThis, IntPtr IntPtr__pCCW)
+ {
+ return RCWWalker.OnDependentWrapperCallback(
+ ComCallableObject.FromThisPointer(IntPtr__pCCW)
+ );
+ }
+ }
+
+ /// <summary>
+ /// Windows.UI.Xaml.Hosting.IReferenceTrackerManager
+ ///
+ /// We send Jupiter notifications for lifetime management purposes
+ /// </summary>
+ internal unsafe struct __com_IJupiterGCManager
+ {
+#pragma warning disable 0649
+ internal __vtable_IJupiterGCManager* pVTable;
+#pragma warning restore 0649
+ }
+
+ /// <summary>
+ /// V-table for IJupiterGCManager
+ ///
+ /// NOTE: We don't implement IJupiterGCManager
+ /// </summary>
+ internal unsafe struct __vtable_IJupiterGCManager
+ {
+ // rgIUnknown is only used for making sure the rest of the fields have the right offset
+#pragma warning disable 0169
+ __vtable_IUnknown rgIIUnknown;
+#pragma warning restore 0169
+
+ // We never implement these functions - instead, we call Jupiter's implementation
+#pragma warning disable 0649
+ internal System.IntPtr pfnOnGCStarted;
+ internal System.IntPtr pfnOnRCWWalkFinished;
+ internal System.IntPtr pfnOnGCFinished;
+ internal System.IntPtr pfnSetCLRServices;
+#pragma warning restore 0649
+ }
+
+
+ /// <summary>
+ /// Exposed services from CLR. Consumed by Jupiter
+ /// Mostly lifetime related
+ /// </summary>
+ internal unsafe struct __com_ICLRServices
+ {
+#pragma warning disable 0649
+ public __vtable_ICLRServices* pVtable;
+#pragma warning restore 0649
+ }
+
+ /// <summary>
+ /// V-table implementation for ICLRServices
+ /// </summary>
+ internal unsafe struct __vtable_ICLRServices
+ {
+ __vtable_IUnknown rgIIUnknown;
+
+ internal System.IntPtr pfnGarbageCollect;
+ internal System.IntPtr pfnFinalizerThreadWait;
+ internal System.IntPtr pfnDisconnectRCWsInCurrentApartment;
+ internal System.IntPtr pfnCreateManagedReference;
+ internal System.IntPtr pfnAddMemoryPressure;
+ internal System.IntPtr pfnRemoveMemoryPressure;
+
+ static __vtable_ICLRServices s_theCcwVtable;
+
+ internal static __vtable_ICLRServices* GetVtable()
+ {
+ s_theCcwVtable.InitVtable();
+
+ // REDHAWK-ONLY: static field storage is unmovable
+ fixed (__vtable_ICLRServices* pVtable = &s_theCcwVtable)
+ return pVtable;
+ }
+
+ private void InitVtable()
+ {
+ rgIIUnknown.pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(AddRef__STUB);
+ rgIIUnknown.pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(Release__STUB);
+ rgIIUnknown.pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(QueryInterface__STUB);
+
+ pfnGarbageCollect = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget2>(GarbageCollect__STUB);
+ pfnFinalizerThreadWait = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(FinalizerThreadWait__STUB);
+ pfnDisconnectRCWsInCurrentApartment = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(DisconnectRCWsInCurrentApartment__STUB);
+ pfnCreateManagedReference = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfCreateManagedReference>(CreateManagedReference__STUB);
+ pfnAddMemoryPressure = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfAddRemoveMemoryPressure>(AddMemoryPressure__STUB);
+ pfnRemoveMemoryPressure = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfAddRemoveMemoryPressure>(RemoveMemoryPressure__STUB);
+ }
+
+ [NativeCallable]
+ static int AddRef__STUB(System.IntPtr pComThis)
+ {
+ // This never getes released from native
+ return 1;
+ }
+
+ [NativeCallable]
+ static int Release__STUB(System.IntPtr pComThis)
+ {
+ // This never gets released from native
+ return 1;
+ }
+
+ [NativeCallable]
+ static int QueryInterface__STUB(
+ System.IntPtr IntPtr__pComThis,
+ System.IntPtr IntPtr__pIID,
+ System.IntPtr IntPtr__ppvObject)
+ {
+ __com_ICLRServices* pComThis = (__com_ICLRServices*)IntPtr__pComThis.ToPointer();
+ Guid* pIID = (Guid*)IntPtr__pIID.ToPointer();
+ void** ppvObject = (void**)IntPtr__ppvObject.ToPointer();
+
+ if (pIID->Equals(Interop.COM.IID_IUnknown) ||
+ pIID->Equals(Interop.COM.IID_ICLRServices))
+ {
+ // You'll always get ICLRServices *
+ // No need to AddRef - this is always 'alive' in the sense that it will be a pointer to a
+ // static v-table
+ *ppvObject = pComThis;
+
+ return Interop.COM.S_OK;
+ }
+
+ return Interop.COM.E_NOINTERFACE;
+ }
+
+ [NativeCallable]
+ static int GarbageCollect__STUB(System.IntPtr pComThis, int flags)
+ {
+ GC.Collect(2, GCCollectionMode.Optimized, /* blocking = */ true);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskJupiterGarbageCollect();
+
+ return Interop.COM.S_OK;
+ }
+
+ [NativeCallable]
+ static int FinalizerThreadWait__STUB(System.IntPtr pComThis)
+ {
+ // This could lead to deadlock if finalizer thread is trying to get back to this thread, because
+ // we are not pumping anymore. Disable this for now and we'll target fixing this in v2
+ // GC.WaitForPendingFinalizers();
+
+ return Interop.COM.S_OK;
+ }
+
+ [NativeCallable]
+ static int DisconnectRCWsInCurrentApartment__STUB(System.IntPtr pComThis)
+ {
+ ContextEntry.RemoveCurrentContext();
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskJupiterDisconnectRCWsInCurrentApartment();
+
+ return Interop.COM.S_OK;
+ }
+
+ /// <summary>
+ /// Creates a proxy object that points to the given RCW
+ /// The proxy
+ /// 1. Has a managed reference pointing to the RCW, and therefore forms a cycle that can be resolved by GC
+ /// 2. Forwards data binding requests
+ /// For example:
+ ///
+ /// Grid <---- RCW Grid <------RCW
+ /// | ^ | ^
+ /// | | Becomes | |
+ /// v | v |
+ /// Rectangle Rectangle ----->Proxy
+ ///
+ /// Arguments
+ /// pJupiterObject - The identity IUnknown* where a RCW points to (Grid, in this case)
+ /// Note that
+ /// 1) we can either create a new RCW or get back an old one from cache
+ /// 2) This pJupiterObject could be a regular WinRT object (such as WinRT collection) for data binding
+ /// ppNewReference - The ICCW* for the proxy created
+ /// Jupiter will call ICCW to establish a jupiter reference
+ ///
+ /// NOTE: This is *NOT* entirely implemented yet
+ /// </summary>
+ [NativeCallable]
+ static int CreateManagedReference__STUB(System.IntPtr pComThis, IntPtr __IntPtr__pJupiterObject,
+ IntPtr __IntPtr__ppNewReference)
+ {
+ __com_ICCW** ppNewReference = (__com_ICCW**)__IntPtr__ppNewReference;
+ object comObj = null;
+#if ENABLE_WINRT
+ //
+ // Converts IJupiterObject * to a RCW with type resolution
+ // If it is already there in the cache, we return the existing one. Otherwise, we create a new
+ // one, and create the right instance using the return value of GetRuntimeClassName
+ //
+ comObj = McgComHelpers.ComInterfaceToComObject(
+ __IntPtr__pJupiterObject,
+ McgModuleManager.IJupiterObject,
+ McgClassInfo.Null,
+ ContextCookie.Default, // No restriction on context
+ McgComHelpers.CreateComObjectFlags.IsWinRTObject
+ );
+#endif
+ //
+ // Create a proxy to the RCW for pJupiterObject
+ // This ensures the object returned only supports standard interfaces and interfaces related to databinding.
+ // Supporting all interfaces that pJupiterObject supports isn't required and causes issues since we return
+ // our vtable instead of pJupiterObject's
+ //
+ IManagedWrapper customPropertyProviderProxy;
+ System.Collections.IList comObjList;
+ System.Collections.IEnumerable comObjEnumerable;
+
+ if ((comObjList = comObj as System.Collections.IList) != null)
+ {
+ customPropertyProviderProxy = new ListCustomPropertyProviderProxy(comObjList);
+ }
+ else if ((comObjEnumerable = comObj as System.Collections.IEnumerable) != null)
+ {
+ customPropertyProviderProxy = new EnumerableCustomPropertyProviderProxy(comObjEnumerable);
+ }
+ else
+ {
+ customPropertyProviderProxy = new StandardCustomPropertyProviderProxy(comObj);
+ }
+#if ENABLE_WINRT
+ //
+ // Then, create a new CCW that points to this RCW
+ // @TODO: Create a Proxy object that points to the RCW, and then get a CCW for the proxy
+ //
+#if X86 && RHTESTCL
+ // The contract is we must hand out ICCW (even though Jupiter probably doesn't care)
+ // but we don't have it in rhtestcl X86 because StdCallCOOP is not available in RHTESTCL
+ *ppNewReference = (__com_ICCW*)McgMarshal.ManagedObjectToComInterface(
+ customPropertyProviderProxy,
+ McgModuleManager.IInspectable
+ );
+#else // X86 && RHTESTCL
+ // The contract is we must hand out ICCW (even though Jupiter probably doesn't care)
+ *ppNewReference = (__com_ICCW*)McgMarshal.ManagedObjectToComInterface(
+ customPropertyProviderProxy,
+ McgModuleManager.ICCW
+
+ );
+#endif //
+
+#endif //ENABLE_WINRT
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskJupiterCreateManagedReference((long)__IntPtr__pJupiterObject, (long)comObj.GetTypeHandle().GetRawValue());
+
+ return Interop.COM.S_OK;
+ }
+
+ [NativeCallable]
+ static int AddMemoryPressure__STUB(System.IntPtr pComThis, ulong bytesAllocated)
+ {
+#if !RHTESTCL
+ GC.AddMemoryPressure((long)bytesAllocated);
+#endif
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskJupiterAddMemoryPressure((long)bytesAllocated);
+
+ return Interop.COM.S_OK;
+ }
+
+ [NativeCallable]
+ static int RemoveMemoryPressure__STUB(System.IntPtr pComThis, ulong bytesAllocated)
+ {
+#if !RHTESTCL
+ GC.RemoveMemoryPressure((long)bytesAllocated);
+#endif
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskJupiterRemoveMemoryPressure((long)bytesAllocated);
+
+ return Interop.COM.S_OK;
+ }
+ }
+
+ /// <summary>
+ /// RCW Walker
+ /// Walks jupiter RCW objects and create references from RCW to referenced CCW (in native side)
+ /// </summary>
+ static unsafe class RCWWalker
+ {
+ static DependentHandleList s_dependentHandleList; // List of dependent handles
+ static volatile IntPtr s_pGCManager; // Points to Jupiter's GC manager
+ static volatile bool s_bInitialized; // Whether RCWWalker has been fully
+ // initialized
+ static bool s_globalPeggingOn = true; // Global pegging. Default to true
+ static bool s_gcStarted; // Whether GC is started
+ static __com_ICLRServices s_clrServices; // The global CLRServices object
+
+ /// <summary>
+ /// Whether global pegging is on.
+ /// Global pegging is on by default except in gen2 GCs, where we temporarily set it to false.
+ /// It is a way to simply let all the CCWs leak by default, and do expensive RCW walks in Gen2 GC
+ /// </summary>
+ internal static bool IsGlobalPeggingOn
+ {
+ [GCCallback]
+ get
+ {
+ return s_globalPeggingOn;
+ }
+ }
+
+ /// <summary>
+ /// Initialize RCWWalker
+ /// </summary>
+ private unsafe static void Initialize(__com_IJupiterObject* pJupiterObject)
+ {
+ IntPtr pGCManager;
+ int hr = CalliIntrinsics.StdCall<int>(pJupiterObject->pVtable->pfnGetJupiterGCManager, pJupiterObject, &pGCManager);
+ if (hr >= 0)
+ {
+ // disable warning for ref volatile
+#pragma warning disable 0420
+ if (Interlocked.CompareExchange(ref s_pGCManager, pGCManager, default(IntPtr)) == default(IntPtr))
+#pragma warning restore 0420
+ {
+ // We won the race. Now start the real initialization
+ InitializeImpl();
+ }
+ }
+
+ McgMarshal.ComRelease(pGCManager);
+ }
+
+ /// <summary>
+ /// Real implementation of initializing RCW walker for jupiter lifetime feature
+ /// </summary>
+ [GCCallback]
+ private static void InitializeImpl()
+ {
+ __com_IJupiterGCManager* pGCManager = (__com_IJupiterGCManager*)s_pGCManager;
+
+ //
+ // AddRef on IGCManager
+ //
+ __com_IUnknown* pGCManagerUnk = (__com_IUnknown*)pGCManager;
+ CalliIntrinsics.StdCall<int>(pGCManagerUnk->pVtable->pfnAddRef, pGCManager);
+
+ s_clrServices.pVtable = __vtable_ICLRServices.GetVtable();
+
+ fixed (__com_ICLRServices* pCLRServices = &s_clrServices)
+ {
+ //
+ // Tell Jupiter that we are ready for tracking life time of objects and provide Jupiter with
+ // our life time realted services through ICLRServices
+ //
+ CalliIntrinsics.StdCall<int>(
+ pGCManager->pVTable->pfnSetCLRServices,
+ pGCManager,
+ pCLRServices
+ );
+
+ //
+ // No Jupiter lifetime on X86 RHTESTCL because StdCallCoop is not available
+ //
+#if !(X86 && RHTESTCL)
+ //
+ // Hook GC related callbacks
+ //
+ InteropExtensions.RuntimeRegisterGcCalloutForGCStart(AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfHookGCCallbacks>(OnGCStarted));
+ InteropExtensions.RuntimeRegisterGcCalloutForAfterMarkPhase(AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfHookGCCallbacks>(AfterMarkPhase));
+ InteropExtensions.RuntimeRegisterGcCalloutForGCEnd(AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfHookGCCallbacks>(OnGCFinished));
+#endif
+ }
+
+ s_bInitialized = true;
+ }
+
+ /// <summary>
+ /// Called when Jupiter RCW is being created
+ /// We do one-time initialization for RCW walker here
+ /// </summary>
+ internal static void OnJupiterRCWCreated(__ComObject comObject)
+ {
+ Debug.Assert(comObject.IsJupiterObject);
+
+ if (s_pGCManager == default(IntPtr))
+ {
+ RCWWalker.Initialize(comObject.GetIJupiterObject_NoAddRef());
+ }
+ }
+
+ /// <summary>
+ /// Called after Jupiter RCW has been created
+ /// </summary>
+ internal static void AfterJupiterRCWCreated(__ComObject comObject)
+ {
+ __com_IJupiterObject* pJupiterObject = comObject.GetIJupiterObject_NoAddRef();
+
+ //
+ // Notify Jupiter that we've created a new RCW for this Jupiter object
+ // To avoid surprises, we should notify them before we fire the first AfterAddRef
+ //
+ CalliIntrinsics.StdCall<int>(pJupiterObject->pVtable->pfnConnect, pJupiterObject);
+
+ //
+ // Tell Jupiter that we've done AddRef for IJupiterObject* and IUnknown*
+ // It's better to tell them later than earlier (prefering leaking than crashing)
+ //
+ AfterAddRef(comObject);
+ AfterAddRef(comObject);
+ }
+
+ /// <summary>
+ /// Reporting to Jupiter that we've done one AddRef to this object instance
+ ///
+ /// The ref count reporting is needed for Jupiter to determine whether there is something other than
+ /// Jupiter and RCW that is holding onto this Jupiter object. If there is, this Jupiter object and
+ /// all dependent CCWs must be pegged.
+ ///
+ /// We typically report the AddRef *after* an AddRef and report the Release *before* a Release
+ /// It's better to leak (temporarily) than crash.
+ /// </summary>
+ internal static void AfterAddRef(__ComObject comObject)
+ {
+ Debug.Assert(comObject.IsJupiterObject);
+
+ __com_IJupiterObject* pJupiterObject = comObject.GetIJupiterObject_NoAddRef();
+
+ //
+ // Send out AfterAddRef callbacks to notify Jupiter we've done AddRef for certain interfaces
+ // We should do this *after* we made a AddRef because we should never
+ // be in a state where report refs > actual refs
+ //
+ CalliIntrinsics.StdCall<int>(pJupiterObject->pVtable->pfnAfterAddRef, pJupiterObject);
+ }
+
+ /// <summary>
+ /// Reporting to Jupiter that we've done one Release to this object instance
+ ///
+ /// The ref count reporting is needed for Jupiter to determine whether there is something other than
+ /// Jupiter and RCW that is holding onto this Jupiter object. If there is, this Jupiter object and
+ /// all dependent CCWs must be pegged.
+ ///
+ /// We typically report the AddRef *after* an AddRef and report the Release *before* a Release
+ /// It's better to leak (temporarily) than crash.
+ /// </summary>
+ internal static void BeforeRelease(__ComObject comObject)
+ {
+ Debug.Assert(comObject.IsJupiterObject);
+
+ __com_IJupiterObject* pJupiterObject = comObject.GetIJupiterObject_NoAddRef();
+
+ CalliIntrinsics.StdCall<int>(pJupiterObject->pVtable->pfnBeforeRelease, pJupiterObject);
+ }
+
+ /// <summary>
+ /// Walk all the Jupiter RCWs and build references from RCW->CCW as we go using dependent handles
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal static bool WalkRCWs()
+ {
+ //
+ // Reset all dependent handles for use in the current GC
+ // We also clear them to make sure they are cleared
+ //
+ if (!s_dependentHandleList.ResetHandles())
+ return false;
+
+ //
+ // Go through each RCW
+ //
+
+ System.Collections.Generic.Internal.Dictionary<IntPtr, IntPtr> map = ComObjectCache.s_comObjectMap;
+
+ for (int i = 0; i < map.GetMaxCount(); ++i)
+ {
+ IntPtr pHandle = default(IntPtr);
+
+ if (map.GetValue(i, ref pHandle) && (pHandle != default(IntPtr)))
+ {
+ GCHandle handle = GCHandle.FromIntPtr(pHandle);
+
+ //
+ // Does a magic unchecked cast that assumes the GCHandle always points to __ComObject,
+ // which is true. Doing a real cast would crash because we are inside GC callout
+ //
+ __ComObject comObject = InteropExtensions.UncheckedCast<__ComObject>(handle.Target);
+
+ //
+ // Only walk RCWs that have >0 ref count. In theory we should never see RCW with
+ // 0 ref count and has been cleaned up by DisconnectRCWsInCurrentApartment but for some
+ // reason this is happening in GCSTRESS.
+ //
+ if (comObject != null &&
+ comObject.IsJupiterObject &&
+ comObject.PeekRefCount() > 0)
+ {
+ if (!WalkOneRCW(comObject))
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Ask Jupiter all the CCWs referenced (through native code) by this RCW and build reference for RCW -> CCW
+ /// so that GC knows about this reference
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal static bool WalkOneRCW(__ComObject comObject)
+ {
+ __com_IJupiterObject* pJupiterObject = comObject.GetIJupiterObject_NoAddRef();
+
+ s_currentComObjectToWalk = comObject;
+
+ //
+ // Start building references from this RCW to all dependent CCWs
+ //
+ // NOTE: StdCallCOOP is used instead of Calli to avoid deadlock
+ //
+ int hr = CalliIntrinsics.StdCallCOOP(
+ pJupiterObject->pVtable->pfnFindDependentWrappers,
+ pJupiterObject,
+ GetDependentWrapperCallbackObject()
+ );
+
+ s_currentComObjectToWalk = null;
+
+ return (hr >= 0);
+ }
+
+ /// <summary>
+ /// Walk all RCWs and log them each of them by using ETW.
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal static void LogRCWs()
+ {
+ //
+ // Go through each RCW
+ //
+
+ System.Collections.Generic.Internal.Dictionary<IntPtr, IntPtr> map = ComObjectCache.s_comObjectMap;
+
+ for (int i = 0; i < map.GetMaxCount(); ++i)
+ {
+ IntPtr pHandle = default(IntPtr);
+
+ if (map.GetValue(i, ref pHandle) && (pHandle != default(IntPtr)))
+ {
+ GCHandle handle = GCHandle.FromIntPtr(pHandle);
+
+ //
+ // Does a magic unchecked cast that assumes the GCHandle always points to __ComObject,
+ // which is true. Doing a real cast would crash because we are inside GC callout
+ //
+ __ComObject comObject = InteropExtensions.UncheckedCast<__ComObject>(handle.Target);
+
+ if (comObject != null)
+ {
+ GCEventProvider.TaskLogLiveRCW(InteropExtensions.GetObjectID(comObject), comObject.GetTypeHandle().GetRawValue(),
+ comObject.BaseIUnknown_UnsafeNoAddRef, comObject.SavedIUnknownVtbl, comObject.PeekRefCount(), comObject.Flags);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// The global instance of IFindDependentWrapperCallback implementation
+ /// </summary>
+ private static __com_IFindDependentWrappers s_findDependentWrapperCallbackObject;
+
+ /// <summary>
+ /// Points the current RCW that is being walked
+ /// It has to be static because we can't take address of this struct if this were a member
+ /// </summary>
+ internal static __ComObject s_currentComObjectToWalk;
+
+ /// <summary>
+ /// Returns a IFindDependentWrapper* to walk a specific RCW. Jupiter will call this interface to
+ /// return all the dependent CCWs for this RCW
+ /// </summary>
+ [GCCallback]
+ internal static __com_IFindDependentWrappers* GetDependentWrapperCallbackObject()
+ {
+ s_findDependentWrapperCallbackObject.pVtable = __vtable_IFindDependentWrappers.GetVtable();
+ fixed (__com_IFindDependentWrappers* pCallbackObject = &s_findDependentWrapperCallbackObject)
+ return pCallbackObject;
+ }
+
+ /// <summary>
+ /// Called from Jupiter when they've found a dependent CCW from a specific RCW
+ /// We'll create a dependent handle from RCW to this CCW to report the reference from RCW to CCW
+ /// formed in native side
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal static int OnDependentWrapperCallback(ComCallableObject ccw)
+ {
+ __ComObject rcw = s_currentComObjectToWalk;
+
+ //
+ // Skip dependent handle creation if RCW/CCW points to the same managed object
+ //
+ if (rcw == ccw.TargetObject)
+ return Interop.COM.S_OK;
+
+ //
+ // Avoid touching CCW target object that have already been GC collected
+ //
+ if (ccw.TargetObject == null)
+ return Interop.COM.S_OK;
+
+ //
+ // Allocate (or use existing) a dependent handle for RCW->CCW
+ //
+ if (!s_dependentHandleList.AllocateHandle(rcw, ccw))
+ return Interop.COM.E_FAIL;
+
+ return Interop.COM.S_OK;
+ }
+
+ /// <summary>
+ /// Called when mark phase is completed so that we can let Jupiter know which RCWs are about to die
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal static int AfterMarkPhase(int nCondemnedGeneration)
+ {
+ System.Collections.Generic.Internal.Dictionary<IntPtr, IntPtr> map = ComObjectCache.s_comObjectMap;
+
+ for (int i = 0; i < map.GetMaxCount(); ++i)
+ {
+ //
+ // I can't do this inside a generic .Equals(default(T)) because it will attempt to box
+ // IntPtr (which does a new and deadlocks inside a GCCallback)
+ // So the best option here is to do check explicitly outside
+ //
+ IntPtr pHandle = default(IntPtr);
+
+ if (map.GetValue(i, ref pHandle) && (pHandle != default(IntPtr)))
+ {
+ GCHandle handle = GCHandle.FromIntPtr(pHandle);
+
+ //
+ // Does a magic unchecked cast that assumes the GCHandle always points to __ComObject,
+ // which is true. Doing a real cast would crash because we are inside GC call out
+ //
+ __ComObject comObject = InteropExtensions.UncheckedCast<__ComObject>(handle.Target);
+
+ //
+ // Only walk RCWs that have >0 ref count. In theory we should never see RCW with
+ // 0 ref count and has been cleaned up by DisconnectRCWsInCurrentApartment but for some
+ // reason this is happening in GCSTRESS.
+ //
+ if (comObject != null &&
+ comObject.IsJupiterObject &&
+ !InteropExtensions.RuntimeIsPromoted(comObject) &&
+ comObject.PeekRefCount() > 0)
+ {
+ __com_IJupiterObject* pJupiterObject = comObject.GetIJupiterObject_NoAddRef();
+
+ //
+ // Notify Jupiter that we are about to destroy a RCW (same timing as short weak handle)
+ // for this Jupiter object.
+ // They need this information to disconnect weak refs and stop firing events,
+ // so that they can avoid resurrecting the Jupiter object (not the RCW - we prevent that)
+ // We only call this inside GC, so don't need to switch to preemptive here
+ // Ignore the failure as there is no way we can handle that failure during GC
+ // NOTE: StdCallCOOP must be used instead of Calli to avoid deadlock
+ //
+ CalliIntrinsics.StdCallCOOP(pJupiterObject->pVtable->pfnDisconnect, pJupiterObject);
+ }
+ }
+ }
+
+ // Technically OnGCStarted should return void, but our AddrOf doesn't support void return value
+ return 0;
+ }
+
+ /// <summary>
+ ///
+ /// Called when GC started
+ /// We do most of our work here
+ ///
+ /// Note that we could get nested GCStart/GCEnd calls, such as :
+ /// GCStart for Gen 2 background GC
+ /// GCStart for Gen 0/1 foregorund GC
+ /// GCEnd for Gen 0/1 foreground GC
+ /// ....
+ /// GCEnd for Gen 2 background GC
+ ///
+ /// The nCondemnedGeneration >= 2 check takes care of this nesting problem
+ ///
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal static int OnGCStarted(int nCondemnedGeneration)
+ {
+ if (NeedToWalkRCWs())
+ {
+ if (nCondemnedGeneration >= 2)
+ {
+ OnGCStartedWorker();
+ }
+ }
+
+ // Technically OnGCStarted should return void, but our AddrOf doesn't support void return value
+ return 0;
+ }
+
+ /// <summary>
+ /// Whether we need to walk RCWs in this GC
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ static bool NeedToWalkRCWs()
+ {
+ // If s_pGCManager != null, we've seen a Jupiter RCW and that means we should do the RCW walk
+ return (s_pGCManager != default(IntPtr) && s_bInitialized);
+ }
+
+ /// <summary>
+ /// The actual RCW walk happens here
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal static void OnGCStartedWorker()
+ {
+ __com_IJupiterGCManager* pGCManager = (__com_IJupiterGCManager*)s_pGCManager;
+
+ s_gcStarted = true;
+
+ //
+ // Let Jupiter know (Gen 2) GC started
+ // NOTE: StdCallCOOP is used instead of StdCall to avoid deadlock
+ //
+ CalliIntrinsics.StdCallCOOP(pGCManager->pVTable->pfnOnGCStarted, pGCManager);
+
+ //
+ // Life off the global pegging flag so that Jupiter can peg them individually to determine
+ // whether they should be rooted or not
+ //
+ s_globalPeggingOn = false;
+
+ //
+ // Walk all RCWs
+ //
+ int bRCWWalkFailed = 0;
+ if (!WalkRCWs())
+ {
+ bRCWWalkFailed = 1;
+ }
+
+ //
+ // Let Jupiter know we've finished RCW walking
+ // NOTE: StdCallCOOP is used instead of StdCall to avoid deadlock
+ //
+ CalliIntrinsics.StdCallCOOP(
+ pGCManager->pVTable->pfnOnRCWWalkFinished,
+ pGCManager,
+ bRCWWalkFailed
+ );
+ }
+
+ /// <summary>
+ ///
+ /// Called when GC finished
+ ///
+ /// Note that we could get nested GCStart/GCEnd calls, such as :
+ /// GCStart for Gen 2 background GC
+ /// GCStart for Gen 0/1 foregorund GC
+ /// GCEnd for Gen 0/1 foreground GC
+ /// ....
+ /// GCEnd for Gen 2 background GC
+ ///
+ /// The nCondemnedGeneration >= 2 check takes care of this nesting problem
+ ///
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal static int OnGCFinished(int nCondemnedGeneration)
+ {
+ if (NeedToWalkRCWs() &&
+ s_gcStarted &&
+ nCondemnedGeneration >= 2)
+ {
+ OnGCFinishedWorker();
+ }
+
+ if (GCEventProvider.IsETWHeapCollectionEnabled())
+ {
+ CCWLookupMap.LogCCWs();
+ RCWWalker.LogRCWs();
+
+ GCEventProvider.FlushComETW();
+ }
+
+ // Technically OnGCStarted should return void, but our AddrOf doesn't support void return value
+ return 0;
+ }
+
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ private static void OnGCFinishedWorker()
+ {
+ __com_IJupiterGCManager* pGCManager = (__com_IJupiterGCManager*)s_pGCManager;
+
+ //
+ // Let Jupiter know GC is finished
+ // NOTE: StdCallCOOP is used instead of StdCall to avoid deadlock
+ //
+ CalliIntrinsics.StdCallCOOP(pGCManager->pVTable->pfnOnGCFinished, pGCManager);
+ //
+ // Set global pegging flag to protect CCWs until the next walk happens
+ //
+ s_globalPeggingOn = true;
+ s_gcStarted = false;
+ }
+ }
+
+ //=========================================================================================
+ // This struct collects all operations on native DependentHandles. The DependentHandle
+ // merely wraps an IntPtr so this struct serves mainly as a "managed typedef."
+ //
+ // DependentHandles exist in one of two states:
+ //
+ // IsAllocated == false
+ // No actual handle is allocated underneath. Illegal to call GetPrimary
+ // or GetPrimaryAndSecondary(). Ok to call Free().
+ //
+ // Initializing a DependentHandle using the nullary ctor creates a DependentHandle
+ // that's in the !IsAllocated state.
+ // (! Right now, we get this guarantee for free because (IntPtr)0 == NULL unmanaged handle.
+ // ! If that assertion ever becomes false, we'll have to add an _isAllocated field
+ // ! to compensate.)
+ //
+ //
+ // IsAllocated == true
+ // There's a handle allocated underneath. You must call Free() on this eventually
+ // or you cause a native handle table leak.
+ //
+ // This struct intentionally does no self-synchronization. It's up to the caller to
+ // to use DependentHandles in a thread-safe way.
+ //=========================================================================================
+ [ComVisible(false)]
+ struct DependentHandle
+ {
+ #region Constructors
+
+ public DependentHandle(Object primary, Object secondary)
+ {
+ _handle = InteropExtensions.RuntimeHandleAllocDependent(primary, secondary);
+ }
+ #endregion
+
+ #region Public Members
+ public bool IsAllocated
+ {
+ get
+ {
+ return _handle != (IntPtr)0;
+ }
+ }
+
+ public void SetPrimaryAndSecondary(Object primary, object secondary)
+ {
+ InteropExtensions.RuntimeHandleSet(_handle, primary);
+ InteropExtensions.RuntimeHandleSetDependentSecondary(_handle, secondary);
+ }
+
+ //----------------------------------------------------------------------
+ // Forces dependentHandle back to non-allocated state (if not already there)
+ // and frees the handle if needed.
+ //----------------------------------------------------------------------
+ public void Free()
+ {
+ if (_handle != (IntPtr)0)
+ {
+ IntPtr handle = _handle;
+ _handle = (IntPtr)0;
+ InteropExtensions.RuntimeHandleFree(handle);
+ }
+ }
+ #endregion
+
+
+ #region Private Data Member
+ private IntPtr _handle;
+ #endregion
+
+ } // struct DependentHandle
+
+ /// <summary>
+ /// A list of dependent handles that is growable under GC callouts
+ /// </summary>
+ unsafe struct DependentHandleList
+ {
+ int m_freeIndex; // The next available slot
+ int m_capacity; // Total numbers of slots available in the list
+ IntPtr* m_pHandles; // All handles
+ int m_shrinkHint; // How many times we've consistently seen "hints" that a
+ // shrink is needed
+
+ internal const int DefaultCapacity = 100; // Default initial capacity of this list
+ internal const int ShrinkHintThreshold = 5; // The number of hints we've seen before we really
+ // shrink the list
+ internal const int HEAP_ZERO_MEMORY = 0x8; // Flag to zero memory
+
+ /// <summary>
+ /// Reset the list of handles to be used by the current GC
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal bool ResetHandles()
+ {
+ if (m_pHandles == null)
+ {
+ //
+ // This is the first time we use this list
+ // Initialize it
+ // NOTE: Call must be used instead of StdCall to avoid deadlock
+ //
+ m_capacity = DefaultCapacity;
+ uint newCapacity = (uint)(sizeof(IntPtr) * m_capacity);
+ m_pHandles = (IntPtr*)ExternalInterop.MemAlloc(new UIntPtr(newCapacity) , HEAP_ZERO_MEMORY);
+
+ if (m_pHandles == null)
+ return false;
+
+ // Our job is done if we are allocating this for the first time
+ return true;
+ }
+
+
+ if (m_freeIndex < m_capacity / 2 && m_capacity > DefaultCapacity)
+ {
+ m_shrinkHint++;
+ if (m_shrinkHint > ShrinkHintThreshold)
+ {
+ //
+ // If we ever seeing consistently (> 5 times) that free index is less than half of
+ // our current capacity, it is time to shrink the size
+ //
+ Shrink();
+
+ m_shrinkHint = 0;
+ }
+ }
+ else
+ {
+ //
+ // Reset shrink hint and start over the counting
+ //
+ m_shrinkHint = 0;
+ }
+
+ //
+ // Clear all the handles that were used
+ //
+ for (int index = 0; index < m_freeIndex; ++index)
+ {
+ IntPtr handle = m_pHandles[index];
+ if (handle != default(IntPtr))
+ {
+ InteropExtensions.RuntimeHandleSet(handle, null);
+ InteropExtensions.RuntimeHandleSetDependentSecondary(handle, null);
+ }
+ }
+
+ m_freeIndex = 0;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Allocate a DependentHandle by either reusing an existing one or creating a new one
+ /// </summary>
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal bool AllocateHandle(object primary, object secondary)
+ {
+ if (m_freeIndex >= m_capacity)
+ {
+ // We need a bigger dependent handle array
+ if (!Grow())
+ return false;
+ }
+
+ IntPtr pHandle = m_pHandles[m_freeIndex];
+ if (pHandle != default(IntPtr))
+ {
+ InteropExtensions.RuntimeHandleSet(pHandle, primary);
+ InteropExtensions.RuntimeHandleSetDependentSecondary(pHandle, secondary);
+ }
+ else
+ {
+ m_pHandles[m_freeIndex] = InteropExtensions.RuntimeHandleAllocDependent(primary, secondary);
+ }
+
+ m_freeIndex++;
+
+ return true;
+ }
+
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal bool Grow()
+ {
+ int newCapacity = m_capacity * 2;
+
+ // NOTE: Call must be used instead of StdCall to avoid deadlock
+ IntPtr* pNewHandles = (IntPtr*)ExternalInterop.MemReAlloc((IntPtr)m_pHandles,
+ new UIntPtr( (uint) (sizeof(IntPtr) * newCapacity)),
+ HEAP_ZERO_MEMORY);
+
+ if (pNewHandles == null)
+ return false;
+
+ m_pHandles = pNewHandles;
+ m_capacity = newCapacity;
+
+ return true;
+ }
+
+ /// <remarks>
+ /// WARNING: This function will be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal bool Shrink()
+ {
+ Debug.Assert(m_capacity > DefaultCapacity && m_capacity / 2 > 10);
+
+ int newCapacity = m_capacity / 2;
+
+ //
+ // Free all handles that will go away
+ //
+ for (int index = newCapacity; index < m_capacity; ++index)
+ {
+ if (m_pHandles[index] != default(IntPtr))
+ {
+ InteropExtensions.RuntimeHandleFree(m_pHandles[index]);
+
+ // Assign them back to null in case the reallocation fails
+ m_pHandles[index] = default(IntPtr);
+ }
+ }
+
+ //
+ // Shrink the size of the memory
+ // If this fails, we don't really care (very unlikely to fail, though)
+ // NOTE: Call must be used instead of StdCall to avoid deadlock
+ //
+ IntPtr* pNewHandles = (IntPtr*)ExternalInterop.MemReAlloc((IntPtr)m_pHandles, new UIntPtr((uint)(sizeof(IntPtr) * newCapacity) ) , HEAP_ZERO_MEMORY);
+
+ if (pNewHandles == null)
+ return false;
+
+ m_pHandles = pNewHandles;
+ m_capacity = newCapacity;
+
+ return true;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/Readme.txt b/src/System.Private.Interop/src/Shared/Readme.txt
new file mode 100644
index 000000000..165ccb972
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/Readme.txt
@@ -0,0 +1 @@
+This directory is kept in sync between multiple libraries. Please make sure you integrate whatever changes you've made to other libraries using integration scripts provided here.
diff --git a/src/System.Private.Interop/src/Shared/SR.Get.cs b/src/System.Private.Interop/src/Shared/SR.Get.cs
new file mode 100644
index 000000000..64b7e43f1
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/SR.Get.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace System
+{
+ internal static partial class SR
+ {
+ internal static string GetResourceString(string resourceKey, string defaultString)
+ {
+ return defaultString;
+ }
+
+ internal static string Format(string resourceId, params object[] par)
+ {
+ String reportStr = String.Empty;
+ foreach (object item in par)
+ {
+ reportStr = String.Concat(reportStr, " | ", item.ToString());
+ }
+ reportStr = String.Concat(resourceId, reportStr);
+ return reportStr;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/StandardInterfaces.cs b/src/System.Private.Interop/src/Shared/StandardInterfaces.cs
new file mode 100644
index 000000000..ffd5b48f4
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/StandardInterfaces.cs
@@ -0,0 +1,1933 @@
+// 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.ComponentModel;
+ using System.Diagnostics;
+ using System.Reflection;
+ using System.Runtime.InteropServices;
+ using System.Runtime.InteropServices.WindowsRuntime;
+ using System.Runtime.CompilerServices;
+ using System.Threading;
+ using System.Text;
+ using System.Runtime;
+ using System.Diagnostics.Contracts;
+ using Internal.NativeFormat;
+
+#if ENABLE_WINRT
+ using global::Windows.UI.Xaml.Data;
+#endif
+
+namespace System.Runtime.InteropServices
+{
+ unsafe struct __com_IUnknown
+ {
+#pragma warning disable 649 // Field 'blah' is never assigned to, and will always have its default value null
+ internal __vtable_IUnknown* pVtable;
+#pragma warning restore 649
+ }
+
+#pragma warning disable 414 // The field 'blah' is assigned but its value is never used
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [CLSCompliant(false)]
+ [EagerOrderedStaticConstructor(EagerStaticConstructorOrder.VtableIUnknown)]
+ public unsafe struct __vtable_IUnknown
+ {
+ // IUnknown
+ internal IntPtr pfnQueryInterface;
+ internal IntPtr pfnAddRef;
+ internal IntPtr pfnRelease;
+
+ public static IntPtr pNativeVtable;
+ private static __vtable_IUnknown s_theCcwVtable = new __vtable_IUnknown
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(Release),
+ };
+ internal static IntPtr GetVtableFuncPtr()
+ {
+ return AddrOfIntrinsics.AddrOf<AddrOfGetCCWVtable>(GetCcwvtable_IUnknown);
+ }
+ internal static unsafe IntPtr GetCcwvtable_IUnknown()
+ {
+ if (__vtable_IUnknown.pNativeVtable == default(IntPtr))
+ {
+ fixed (void* pVtbl = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtbl, ref __vtable_IUnknown.pNativeVtable,sizeof(__vtable_IUnknown));
+ }
+ }
+ return __vtable_IUnknown.pNativeVtable;
+ }
+
+ [NativeCallable]
+ public static int QueryInterface(
+ IntPtr __IntPtr__pComThis,
+ IntPtr __IntPtr__pIID,
+ IntPtr __IntPtr__ppvObject)
+ {
+ // Prevent reentrancy due to message pumping in blocking operations.
+ InteropExtensions.SuppressReentrantWaits();
+
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+ Guid* pIID = (Guid*)__IntPtr__pIID;
+ void** ppvObject = (void**)__IntPtr__ppvObject;
+
+ // @TODO: does not distinguish between E_NOINTERFACE and E_OUTOFMEMORY
+ var cco = pComThis->ComCallableObject;
+ IntPtr result = cco.GetComInterfaceForIID(ref *pIID);
+ *ppvObject = (void*)result;
+
+ int hr;
+ if (result == default(IntPtr))
+ hr = Interop.COM.E_NOINTERFACE;
+ else
+ hr = Interop.COM.S_OK;
+
+ // Restore reentrant waits. No need for a 'finally' because exceptions in NativeCallable methods will FailFast.
+ InteropExtensions.RestoreReentrantWaits();
+ return hr;
+ }
+
+ /// <summary>
+ /// Special NO GC region support helpers
+ ///
+ /// Declare the GC trigger helpers here because we want to call them directly to avoid
+ /// GC stress hijacking InteropExtensions.RhpSet/ClearThreadDoNoTriggerGC
+ ///
+ /// WARNING: Please avoid using this API whenver possible. If you find yourself must call this
+ /// API, please make sure you follow these rules:
+ /// 1. The block where GC is disabled need to be small and fast
+ /// 2. You can't allocate or call GC.Collect (you'll be surprised how many code actually do)
+ /// 3. You can't throw out exception (which allocates)
+ /// 4. You can't P/invoke
+ /// 5. others?
+ /// </summary>
+
+#if CORECLR
+
+ [NativeCallable]
+ public static int AddRef(IntPtr __IntPtr__pComThis)
+ {
+ int newRefCount;
+
+ //
+ // NO GC REGION
+ //
+ // Jupiter assumes AddRef doesn't block on GC and that is indeed the case in desktop CLR
+ // We need to match desktop CLR behavior, otherwise Jupiter would be taking a lock and then
+ // calling AddRef which triggers another GC and calls out to Jupiter OnGCStart code, which
+ // attempts to take the same lock.
+ //
+ // NOTE 1: We don't call SetDoNotTriggerGC in Release because we do allocate memory in Release()
+ // and Jupiter doesn't call it inside their lock for now
+ //
+ // NOTE 2: Typically you should put those calls in a try/finally, but since you can't throw new
+ // exception and even if we throw an existing exception we would failfast inside AddRef anyway,
+ // there is no need to put it in a finally
+ //
+
+ // RhpSetThreadDoNotTriggerGC are nop on CoreCLR
+ GCHelpers.RhpSetThreadDoNotTriggerGC();
+ {
+
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+
+ //
+ // Use ->NativeCCW to make sure we failfast when calling AddRef/Release for neutered CCWs
+ //
+ newRefCount = pComThis->NativeCCW->AddCOMRef();
+ }
+
+ GCHelpers.RhpClearThreadDoNotTriggerGC();
+
+ return newRefCount;
+ }
+
+ class GCHelpers
+ {
+ internal static void RhpClearThreadDoNotTriggerGC(){}
+ internal static void RhpSetThreadDoNotTriggerGC(){}
+ }
+#else
+ //
+ // AddRef is implemented in native code, via Interop.Native.lib. Here we link in the native code;
+ // a DllImport from "*" means "import the named method from a linked .lib file."
+ // NOTE:
+ // Having McgGeneratedNativeCallCodeAttribute is *REQUIRED* because this is not really a p/invoke but
+ // a reverse p/invoke in disguise. It is just convenient to use DllImport as a way to indicate a call
+ // into a externally linked module. Without this attribute, MCG will generate code for this as a
+ // p/invoke and disaster happens
+ //
+#if X86
+ [DllImport("*", EntryPoint = "_CCWAddRef@4")]
+#else
+ [DllImport("*", EntryPoint = "CCWAddRef")]
+#endif
+ [McgGeneratedNativeCallCodeAttribute]
+ public static extern int AddRef(IntPtr __IntPtr__pComThis);
+
+ class GCHelpers
+ {
+ private const string RuntimeLibrary = "[MRT]";
+ private const MethodImplOptions InternalCall = (MethodImplOptions)0x1000;
+
+ [MethodImplAttribute(InternalCall)]
+ [RuntimeImport(RuntimeLibrary, "RhpClearThreadDoNotTriggerGC")]
+ internal extern static void RhpClearThreadDoNotTriggerGC();
+
+ [MethodImplAttribute(InternalCall)]
+ [RuntimeImport(RuntimeLibrary, "RhpSetThreadDoNotTriggerGC")]
+ internal extern static void RhpSetThreadDoNotTriggerGC();
+ }
+#endif //CORECLR
+
+ static __vtable_IUnknown()
+ {
+ ComCallableObject.InitRefCountedHandleCallback();
+ }
+
+ [NativeCallable]
+ public static int Release(IntPtr __IntPtr__pComThis)
+ {
+ // Prevent reentrancy due to message pumping in blocking operations.
+ InteropExtensions.SuppressReentrantWaits();
+
+ int hr = __interface_ccw.DirectRelease(__IntPtr__pComThis);
+
+ // Restore reentrant waits. No need for a 'finally' because exceptions in NativeCallable methods will FailFast.
+ InteropExtensions.RestoreReentrantWaits();
+ return hr;
+ }
+ }
+
+ unsafe struct __com_IInspectable
+ {
+#pragma warning disable 649 // Field 'blah' is never assigned to, and will always have its default value null
+ public __vtable_IInspectable* pVtable;
+#pragma warning restore 649
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [CLSCompliant(false)]
+ public unsafe struct __vtable_IInspectable
+ {
+ // IUnknown
+ internal IntPtr pfnQueryInterface;
+ internal IntPtr pfnAddRef;
+ internal IntPtr pfnRelease;
+
+ // IInspectable
+ internal IntPtr pfnGetIids;
+ internal IntPtr pfnGetRuntimeClassName;
+ internal IntPtr pfnGetTrustLevel;
+
+ public static IntPtr pNativeVtable;
+ private static __vtable_IInspectable s_theCcwVtable = new __vtable_IInspectable
+ {
+ // IUnknown
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ // IInspectable
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(GetTrustLevel),
+ };
+ internal static IntPtr GetVtableFuncPtr()
+ {
+ return AddrOfIntrinsics.AddrOf<AddrOfGetCCWVtable>(GetCcwvtable_IInspectable);
+ }
+ internal static unsafe IntPtr GetCcwvtable_IInspectable()
+ {
+ if (pNativeVtable == default(IntPtr))
+ {
+ fixed (void* pVtbl = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtbl, ref __vtable_IInspectable.pNativeVtable,sizeof(__vtable_IInspectable));
+ }
+ }
+ return __vtable_IInspectable.pNativeVtable;
+ }
+
+ const int S_OK = 0;
+ const int E_NOTIMPL = unchecked((int)0x80000001);
+
+ [NativeCallable]
+ public static int GetIIDs(
+ IntPtr __IntPtr__pComThis,
+ IntPtr __IntPtr__iidCount,
+ IntPtr __IntPtr__iids)
+ {
+ // Prevent reentrancy due to message pumping in blocking operations.
+ InteropExtensions.SuppressReentrantWaits();
+ try
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+ int* iidCount = (int*)__IntPtr__iidCount;
+ Guid** iids = (Guid**)__IntPtr__iids;
+
+ if (iidCount == null || iids == null)
+ return Interop.COM.E_POINTER;
+
+ *iidCount = 0;
+ *iids = null;
+
+ CCWTemplateInfo template = pComThis->ComCallableObject.Template;
+
+ if (!template.IsNull)
+ {
+ System.Collections.Generic.Internal.List<Guid> guidList = template.ContainingModule.GetIIDs(template.Index);
+
+ int totalGuids = guidList.Count;
+
+ if (totalGuids > 0)
+ {
+ int guidArraySize = totalGuids * sizeof(Guid);
+ if (guidArraySize < 0)
+ return Interop.COM.E_OUTOFMEMORY;
+
+ *iids = (Guid*)ExternalInterop.CoTaskMemAlloc(new IntPtr(guidArraySize));
+
+ if (*iids == null)
+ {
+ return Interop.COM.E_OUTOFMEMORY;
+ }
+
+ for (int i = 0; i < totalGuids; ++i)
+ (*iids)[i] = guidList[i];
+
+ *iidCount = totalGuids;
+
+ return Interop.COM.S_OK;
+ }
+ }
+
+ return Interop.COM.S_OK;
+ }
+ finally
+ {
+ InteropExtensions.RestoreReentrantWaits();
+ }
+ }
+
+ [NativeCallable]
+ public static int GetRuntimeClassName(
+ IntPtr __IntPtr__pComThis,
+ IntPtr __IntPtr__className)
+ {
+#if ENABLE_WINRT
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+ HSTRING* pClassName = (HSTRING*)__IntPtr__className;
+
+ CCWTemplateInfo template = pComThis->ComCallableObject.Template;
+
+ if (!template.IsNull)
+ {
+ string runtimeClassName = template.ContainingModule.GetRuntimeClassName(template.Index);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWQueryRuntimeClassName((long)pComThis->NativeCCW, runtimeClassName);
+ return McgMarshal.StringToHStringNoNullCheck(runtimeClassName, pClassName);
+ }
+
+ *pClassName = default(HSTRING);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskCCWQueryRuntimeClassName((long)pComThis->NativeCCW, String.Empty);
+
+ return Interop.COM.S_OK;
+#else
+ throw new PlatformNotSupportedException("GetRuntimeClassName");
+#endif
+ }
+
+ const int BaseTrust = 0;
+
+ [NativeCallable]
+ public static int GetTrustLevel(
+ IntPtr __IntPtr__pComThis,
+ IntPtr __IntPtr__pTrustLevel)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+ int* pTrustLevel = (int*)__IntPtr__pTrustLevel;
+
+ *pTrustLevel = BaseTrust;
+
+ return S_OK;
+ }
+ }
+
+#if ENABLE_WINRT
+ internal unsafe struct __vtable_ICustomPropertyProvider
+ {
+ // The ICustomProperty interop implementation is generated by MCG so we need the
+ // IID to convert it between a managed object and COM interface
+ //30da92c0-23e8-42a0-ae7c-734a0e5d2782
+ static Guid ICustomPropertyIID = new Guid(0x30da92c0, 0x23e8, 0x42a0, 0xae, 0x7c, 0x73, 0x4a, 0x0e, 0x5d, 0x27, 0x82);
+
+ // IUnknown
+ IntPtr pfnQueryInterface;
+ IntPtr pfnAddRef;
+ IntPtr pfnRelease;
+ // IInspectable
+ IntPtr pfnGetIids;
+ IntPtr pfnGetRuntimeClassName;
+ IntPtr pfnGetTrustLevel;
+ // ICustomPropertyProvider
+ IntPtr pfnGetCustomProperty;
+ IntPtr pfnGetIndexedProperty;
+ IntPtr pfnGetStringRepresentation;
+ IntPtr pfnget_Type;
+
+ public static IntPtr pNativeVtable;
+ static __vtable_ICustomPropertyProvider s_theCcwVtable = new __vtable_ICustomPropertyProvider
+ {
+ // IUnknown
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ // IInspectable
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+ // ICustomPropertyProvider
+ pfnGetCustomProperty = AddrOfIntrinsics.AddrOf<WinRTAddrOfIntrinsics.AddrOfGetCustomProperty>(GetCustomProperty__STUB),
+ pfnGetIndexedProperty = AddrOfIntrinsics.AddrOf<WinRTAddrOfIntrinsics.AddrOfGetIndexedProperty>(GetIndexedProperty__STUB),
+ pfnGetStringRepresentation = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(GetStringRepresentation__STUB),
+ pfnget_Type = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_Type__STUB),
+ };
+ internal static IntPtr GetVtableFuncPtr()
+ {
+ return AddrOfIntrinsics.AddrOf<AddrOfGetCCWVtable>(GetCcwvtable_ICustomPropertyProvider);
+ }
+ internal static unsafe IntPtr GetCcwvtable_ICustomPropertyProvider()
+ {
+ if(pNativeVtable == default(IntPtr))
+ {
+ fixed (void* pVtbl = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtbl, ref __vtable_ICustomPropertyProvider.pNativeVtable,sizeof(__vtable_ICustomPropertyProvider));
+ }
+ }
+ return __vtable_ICustomPropertyProvider.pNativeVtable;
+ }
+
+ [NativeCallable]
+ static int GetCustomProperty__STUB(
+ System.IntPtr pComThis,
+ HSTRING unsafe_name,
+ IntPtr __IntPtr__unsafe_customProperty)
+ {
+
+ void** unsafe_customProperty = (void**)__IntPtr__unsafe_customProperty;
+
+ object target = ComCallableObject.FromThisPointer(pComThis).TargetObject;
+ string propertyName = McgMarshal.HStringToString(unsafe_name);
+ try
+ {
+ ICustomProperty property = ManagedGetCustomProperty(target, propertyName);
+ *unsafe_customProperty = (void*)McgComHelpers.ManagedObjectToComInterface(
+ property,
+ typeof(ICustomProperty).TypeHandle);
+ }
+ catch (Exception ex)
+ {
+ return McgMarshal.GetHRForExceptionWinRT(ex);
+ }
+ return Interop.COM.S_OK;
+ }
+
+ /// <summary>
+ /// Safe Implementation of ICustomPropertyProvider.GetCustomProperty
+ /// </summary>
+ /// <param name="target">Object to find a property on</param>
+ /// <param name="propertyName">Name of the property to find</param>
+ /// <returns>ICustomProperty representing the property</returns>
+ private static ICustomProperty ManagedGetCustomProperty(object target, string propertyName)
+ {
+ try
+ {
+ target = CustomPropertyImpl.UnwrapTarget(target);
+
+ PropertyInfo propertyInfo = target.GetType().GetRuntimeProperty(
+ propertyName);
+
+ if (propertyInfo != null)
+ return new CustomPropertyImpl(propertyInfo);
+
+ // Weakly-Typed RCW scenario
+ // Check cached interface to see whether it supports propertyName Property
+ if (McgMarshal.IsOfType(target, typeof(__ComObject).TypeHandle))
+ {
+ __ComObject comObj = (__ComObject)target;
+ propertyInfo = comObj.GetMatchingProperty(
+ (PropertyInfo p) => { if (p.Name == propertyName) return true; return false; }
+ );
+ if (propertyInfo != null)
+ return new CustomPropertyImpl(propertyInfo);
+ }
+ }
+ catch (MissingMetadataException ex)
+ {
+ CustomPropertyImpl.LogDataBindingError(propertyName, ex);
+ }
+
+ return null;
+ }
+
+ [NativeCallable]
+ static int GetIndexedProperty__STUB(
+ System.IntPtr pComThis,
+ HSTRING unsafe_name,
+ TypeName unsafe_type,
+ IntPtr __IntPtr__unsafe_customProperty)
+ {
+ //__com_Windows_UI_Xaml_Data__ICustomProperty** unsafe_customProperty = (__com_Windows_UI_Xaml_Data__ICustomProperty**)__IntPtr__unsafe_customProperty;
+ void** unsafe_customProperty = (void**)__IntPtr__unsafe_customProperty;
+
+ try
+ {
+ object target = ComCallableObject.FromThisPointer(pComThis).TargetObject;
+ string propertyName = McgMarshal.HStringToString(unsafe_name);
+ Type indexerType = McgMarshal.TypeNameToType(unsafe_type.Name, (int)unsafe_type.Kind);
+
+ ICustomProperty property = ManagedGetIndexedProperty(target, propertyName, indexerType);
+ *unsafe_customProperty = (void*)McgComHelpers.ManagedObjectToComInterface(
+ property,
+ typeof(ICustomProperty).TypeHandle);
+ }
+ catch (Exception ex)
+ {
+ return McgMarshal.GetHRForExceptionWinRT(ex);
+ }
+
+ return Interop.COM.S_OK;
+ }
+
+
+ /// <summary>
+ /// Determine whether specifed property is the matching one based on propertyName and indexerType
+ /// </summary>
+ /// <param name="property"></param>
+ /// <param name="propertyName"></param>
+ /// <param name="indexerType"></param>
+ /// <returns></returns>
+ private static bool IsMatchingIndexedProperty(PropertyInfo property, string propertyName, Type indexerType)
+ {
+ if (property.Name != propertyName)
+ {
+ return false;
+ }
+
+ ParameterInfo[] indexParameters = property.GetIndexParameters();
+ if (indexParameters.Length != 1)
+ {
+ return false;
+ }
+
+ if (indexParameters[0].ParameterType != indexerType)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Safe Implementation of ICustomPropertyProvider.GetIndexedProperty
+ /// </summary>
+ /// <param name="target">Object to find a property on</param>
+ /// <param name="propertyName">Name of the property to find</param>
+ /// <param name="indexerType">Type of indexer used on the indexed property to distinguish overloads</param>
+ /// <returns>ICustomProperty representing the property</returns>
+ private static ICustomProperty ManagedGetIndexedProperty(object target, string propertyName, Type indexerType)
+ {
+ target = CustomPropertyImpl.UnwrapTarget(target);
+
+ try
+ {
+ foreach (PropertyInfo property in target.GetType().GetRuntimeProperties())
+ {
+ if (IsMatchingIndexedProperty(property, propertyName, indexerType))
+ {
+ return new CustomPropertyImpl(property);
+ }
+ }
+
+ // Weakly-Typed RCW
+ // Check cached interface to see whether it supports propertyName Property
+ if (McgMarshal.IsOfType(target, typeof(__ComObject).TypeHandle))
+ {
+ __ComObject comObj = (__ComObject)target;
+ PropertyInfo property = comObj.GetMatchingProperty(
+ (PropertyInfo p) => { return IsMatchingIndexedProperty(p, propertyName, indexerType); }
+ );
+
+ if (property != null)
+ {
+ return new CustomPropertyImpl(property);
+ }
+ }
+ }
+ catch (MissingMetadataException ex)
+ {
+ CustomPropertyImpl.LogDataBindingError(propertyName, ex);
+ }
+
+ // We can do indexing on lists and dictionaries without metadata
+ if (target is IList || target is IDictionary)
+ {
+ return new CustomPropertyImpl(null, true, target.GetType());
+ }
+
+ return null;
+ }
+
+
+ [NativeCallable]
+ static int GetStringRepresentation__STUB(
+ System.IntPtr pComThis,
+ IntPtr __IntPtr__unsafe_stringRepresentation)
+ {
+ HSTRING* unsafe_stringRepresentation = (HSTRING*)__IntPtr__unsafe_stringRepresentation;
+
+ try
+ {
+ // Check whether the ICustomPropertyProvider implements IStringable.
+ // If so, we prefer IStringable implementation over object.ToString().
+ object target = ComCallableObject.FromThisPointer(pComThis).TargetObject;
+
+ string stringRepresentation;
+ if (!IStringableHelper.TryGetIStringableToString(target, out stringRepresentation))
+ {
+ stringRepresentation = ManagedGetStringRepresentation(target);
+ }
+
+ //
+ // To align with desktop behavior: this is the only place we convert null string to
+ // NULL HSTRING
+ //
+ if (stringRepresentation == null)
+ *unsafe_stringRepresentation = default(HSTRING);
+ else
+ *unsafe_stringRepresentation = McgMarshal.StringToHString(stringRepresentation);
+ }
+ catch (Exception ex)
+ {
+ return McgMarshal.GetHRForExceptionWinRT(ex);
+ }
+
+ return Interop.COM.S_OK;
+ }
+
+
+ /// <summary>
+ /// Safe Implementation of ICustomPropertyProvider.GetStringRepresentation.
+ /// Just calls .ToString()
+ /// </summary>
+ /// <param name="target">Object to get a string representation for</param>
+ /// <returns>String representation of the object</returns>
+ private static string ManagedGetStringRepresentation(object target)
+ {
+ return CustomPropertyImpl.UnwrapTarget(target).ToString();
+ }
+
+ [NativeCallable]
+ static int get_Type__STUB(
+ System.IntPtr pComThis,
+ IntPtr __IntPtr__unsafe_value)
+ {
+
+ TypeName* unsafe_value = (TypeName*)__IntPtr__unsafe_value;
+
+ int kind;
+ try
+ {
+ // Since this is only used for databinding, we want to round trip to a McgFakeType if
+ // the type is unreflectable. This prevents MissingMetadataExceptions in XAML-generated code.
+ Type realType = CustomPropertyImpl.UnwrapTarget(ComCallableObject.FromThisPointer(pComThis).TargetObject).GetType();
+ Type xamlSafeType = McgTypeHelpers.GetReflectableOrFakeType(realType);
+
+ McgTypeHelpers.TypeToTypeName(
+ xamlSafeType,
+ out unsafe_value->Name,
+ out kind);
+
+ unsafe_value->Kind = (TypeKind)kind;
+ }
+ catch (Exception ex)
+ {
+ return McgMarshal.GetHRForExceptionWinRT(ex);
+ }
+ return Interop.COM.S_OK;
+ }
+ }
+#endif //ENABLE_WINRT
+
+ /// <summary>
+ /// This is a special type we'll create CCW for but does not implement any WinRT interfaces
+ /// We need to ask MCG to generate templates for it explicitly by marking with McgComCallableAttribute
+ /// </summary>
+ [McgComCallableAttribute]
+ internal class StandardCustomPropertyProviderProxy : IManagedWrapper
+ {
+ Object m_target;
+
+ internal StandardCustomPropertyProviderProxy(object target)
+ {
+ m_target = target;
+ }
+
+ public object GetTarget()
+ {
+ return m_target;
+ }
+ }
+
+ internal class EnumerableCustomPropertyProviderProxy : IManagedWrapper, System.Collections.IEnumerable
+ {
+ System.Collections.IEnumerable m_target;
+
+ internal EnumerableCustomPropertyProviderProxy(System.Collections.IEnumerable target)
+ {
+ m_target = target;
+ }
+
+ public object GetTarget()
+ {
+ return m_target;
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return m_target.GetEnumerator();
+ }
+ }
+
+ internal class ListCustomPropertyProviderProxy : IManagedWrapper, System.Collections.IList
+ {
+ System.Collections.IList m_target;
+
+ internal ListCustomPropertyProviderProxy(System.Collections.IList target)
+ {
+ m_target = target;
+ }
+
+ public object GetTarget()
+ {
+ return m_target;
+ }
+
+ int System.Collections.IList.Add(object value)
+ {
+ return m_target.Add(value);
+ }
+
+ void System.Collections.IList.Clear()
+ {
+ m_target.Clear();
+ }
+
+ bool System.Collections.IList.Contains(object value)
+ {
+ return m_target.Contains(value);
+ }
+
+ int System.Collections.IList.IndexOf(object value)
+ {
+ return m_target.IndexOf(value);
+ }
+
+ void System.Collections.IList.Insert(int index, object value)
+ {
+ m_target.Insert(index, value);
+ }
+
+ bool System.Collections.IList.IsFixedSize
+ {
+ get { return m_target.IsFixedSize; }
+ }
+
+ bool System.Collections.IList.IsReadOnly
+ {
+ get { return m_target.IsReadOnly; }
+ }
+
+ void System.Collections.IList.Remove(object value)
+ {
+ m_target.Remove(value);
+ }
+
+ void System.Collections.IList.RemoveAt(int index)
+ {
+ m_target.RemoveAt(index);
+ }
+
+ object System.Collections.IList.this[int index]
+ {
+ get
+ {
+ return m_target[index];
+ }
+ set
+ {
+ m_target[index] = value;
+ }
+ }
+
+ void System.Collections.ICollection.CopyTo(Array array, int index)
+ {
+ m_target.CopyTo(array, index);
+ }
+
+ int System.Collections.ICollection.Count
+ {
+ get { return m_target.Count; }
+ }
+
+ bool System.Collections.ICollection.IsSynchronized
+ {
+ get { return m_target.IsSynchronized; }
+ }
+
+ object System.Collections.ICollection.SyncRoot
+ {
+ get { return m_target.SyncRoot; }
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return m_target.GetEnumerator();
+ }
+ }
+
+ /// <summary>
+ /// IWeakReferenceSource implementation
+ /// Because it doesn't actually implement IWeakReferenceSource, we'll ask MCG to import this as a
+ /// CCWTemplate explicitly to avoid global interface lookup.
+ /// </summary>
+ [McgComCallableAttribute]
+ internal class WeakReferenceSource
+ {
+ // Here we use WeakReference<Object> instead of WeakReference<ComCallableObject>
+ // The reason is:
+ // .if we use WeakReference<ComCallableObject>, then we will create a relationship: IWeakReference-->Managed Object CCW-->Managed Object,
+ // during this relationship, none will keep this Managed Object CCW alive(the link between IWeakReference to Managed Object CCW is WeakReference<T>).
+ // So if GC occurs and Managed Object CCW will be GCed, The call IWeakReference.Resolve will fail even managed object is still alive.
+ // .if use WeakReference<Object>, then we create a relationship:IWeakReference---> Managed Object, in this way, we don't care
+ // whether the managed object CCW is alive or not as long as managed object is alive.
+ // But there is a drawback for using WeakReference<Object>: The IUknown pointer of CCW will change.
+ // since we will create new CCW if the old one is Gced and the mangaed object still is alive.
+ // So if user try to cache this IUnknown pointer of CCW instead of IWeakReference Pointer, he/she may encounter problem during Resolve
+ // Workaround for this drawback is to cache IWeakReference instead of IUnknown pointer of CCW if user need to cache.
+ private WeakReference<Object> weakRef;
+
+ internal WeakReferenceSource(Object obj)
+ {
+ weakRef = new WeakReference<Object>(obj);
+ }
+
+ internal object Resolve()
+ {
+ Object targetObject;
+
+ if (weakRef.TryGetTarget(out targetObject))
+ {
+ return targetObject;
+ }
+
+ return null;
+ }
+ }
+
+ internal unsafe struct __com_IWeakReference
+ {
+#pragma warning disable 649 // Field 'blah' is never assigned to, and will always have its default value null
+ internal __vtable_IWeakReference* pVtable;
+#pragma warning restore 649
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal unsafe struct __vtable_IWeakReferenceSource
+ {
+ // IUnknown
+ IntPtr pfnQueryInterface;
+ IntPtr pfnAddRef;
+ IntPtr pfnRelease;
+ // IWeakReferenceSource
+ internal IntPtr pfnGetWeakReference;
+
+ public static IntPtr pNativeVtable;
+ private static __vtable_IWeakReferenceSource s_theCcwVtable = new __vtable_IWeakReferenceSource
+ {
+ // IUnknown
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ // IWeakReferenceSource
+ pfnGetWeakReference = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(GetWeakReference),
+ };
+
+ internal static IntPtr GetVtableFuncPtr()
+ {
+ return AddrOfIntrinsics.AddrOf<AddrOfGetCCWVtable>(GetCcwvtable_IWeakReferenceSource);
+ }
+ internal static unsafe IntPtr GetCcwvtable_IWeakReferenceSource()
+ {
+ if (pNativeVtable == default(IntPtr))
+ {
+ fixed (void* pVtbl = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtbl, ref __vtable_IWeakReferenceSource.pNativeVtable,sizeof(__vtable_IWeakReferenceSource));
+ }
+ }
+ return __vtable_IWeakReferenceSource.pNativeVtable;
+ }
+
+ [NativeCallable]
+ static private unsafe int GetWeakReference(
+ IntPtr __IntPtr__pComThis,
+ IntPtr __IntPtr__ppWeakReference)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+ __com_IWeakReference** ppWeakReference = (__com_IWeakReference**)__IntPtr__ppWeakReference;
+
+ if (ppWeakReference == null)
+ {
+ return Interop.COM.E_INVALIDARG;
+ }
+
+ var cco = pComThis->ComCallableObject;
+ WeakReferenceSource source = new WeakReferenceSource(cco.TargetObject);
+ (*ppWeakReference) = (__com_IWeakReference*)McgMarshal.ManagedObjectToComInterface(source, McgModuleManager.IWeakReference);
+
+ return Interop.COM.S_OK;
+ }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal unsafe struct __vtable_IWeakReference
+ {
+ // IUnknown
+ IntPtr pfnQueryInterface;
+ IntPtr pfnAddRef;
+ IntPtr pfnRelease;
+ // IWeakReference
+ internal IntPtr pfnResolve;
+
+ public static IntPtr pNativeVtable;
+ private static __vtable_IWeakReference s_theCcwVtable = new __vtable_IWeakReference
+ {
+ // IUnknown
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ // IWeakReference
+ pfnResolve = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfResolve>(Resolve),
+ };
+ internal static IntPtr GetVtableFuncPtr()
+ {
+ return AddrOfIntrinsics.AddrOf<AddrOfGetCCWVtable>(GetCcwvtable_IWeakReference);
+ }
+ internal static unsafe IntPtr GetCcwvtable_IWeakReference()
+ {
+ if (pNativeVtable == default(IntPtr))
+ {
+ fixed (void* pVtbl = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtbl, ref __vtable_IWeakReference.pNativeVtable,sizeof(__vtable_IWeakReference));
+ }
+ }
+ return __vtable_IWeakReference.pNativeVtable;
+ }
+
+ [NativeCallable]
+ static private unsafe int Resolve(
+ IntPtr __IntPtr__pComThis,
+ IntPtr __IntPtr__piid,
+ IntPtr __IntPtr__ppWeakReference)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+ Guid* piid = (Guid*)__IntPtr__piid;
+ __com_IInspectable** ppWeakReference = (__com_IInspectable**)__IntPtr__ppWeakReference;
+
+ if (ppWeakReference == null)
+ {
+ return Interop.COM.E_INVALIDARG;
+ }
+
+ int hr;
+ var cco = pComThis->ComCallableObject;
+ WeakReferenceSource source = (WeakReferenceSource)cco.TargetObject;
+ object targetObject = source.Resolve();
+
+ if (targetObject == null)
+ {
+ hr = Interop.COM.S_OK;
+ *ppWeakReference = null;
+ }
+ else
+ {
+ (*ppWeakReference) = (__com_IInspectable*)
+ McgComHelpers.ManagedObjectToComInterface(
+ targetObject,
+ ref *piid
+ );
+
+ hr = (*ppWeakReference) != null ? Interop.COM.S_OK : Interop.COM.E_NOINTERFACE;
+ }
+
+ if ((hr < 0) && (InteropEventProvider.IsEnabled()))
+ InteropEventProvider.Log.TaskCCWResolveFailure((long)pComThis->NativeCCW, (long)pComThis, *piid, hr);
+
+ return hr;
+ }
+ }
+
+#if ENABLE_WINRT
+ unsafe struct __com_IStringable
+ {
+#pragma warning disable 649 // Field 'blah' is never assigned to, and will always have its default value null
+ internal __vtable_IStringable* pVtable;
+#pragma warning restore 649
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal unsafe struct __vtable_IStringable
+ {
+ // IUnknown
+ IntPtr pfnQueryInterface;
+ IntPtr pfnAddRef;
+ IntPtr pfnRelease;
+
+ // IInspectable
+ IntPtr pfnGetIids;
+ IntPtr pfnGetRuntimeClassName;
+ IntPtr pfnGetTrustLevel;
+
+ // IStringable
+ internal IntPtr pfnToString;
+
+ public static IntPtr pNativeVtable;
+ private static __vtable_IStringable s_theCcwVtable = new __vtable_IStringable
+ {
+ // IUnknown
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+
+ // IInspectable
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+
+ // IStringable
+ pfnToString = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(ToString),
+ };
+
+ internal static IntPtr GetVtableFuncPtr()
+ {
+ return AddrOfIntrinsics.AddrOf<AddrOfGetCCWVtable>(GetCcwvtable_IStringable);
+ }
+ internal static unsafe IntPtr GetCcwvtable_IStringable()
+ {
+ if (pNativeVtable == default(IntPtr))
+ {
+ fixed (void* pVtbl = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtbl, ref __vtable_IStringable.pNativeVtable,sizeof(__vtable_IStringable));
+ }
+ }
+ return __vtable_IStringable.pNativeVtable;
+ }
+
+ [NativeCallable]
+ static private unsafe int ToString(
+ IntPtr pComThis,
+ IntPtr __IntPtr__pResult)
+ {
+ // If we have reached here then the managed object does not directly implement
+ // IStringable and hence we need to rely on the default Object.ToString() behavior.
+
+ // Since the default implementation is only a best effort scenario where we may or may
+ // not have the metadata to give the Type.FullName, this method call might not be very useful
+ HSTRING* pResult = (HSTRING*)__IntPtr__pResult;
+ int hr;
+
+ if (pResult == null)
+ return Interop.COM.E_POINTER;
+
+ object target = ComCallableObject.FromThisPointer(pComThis).TargetObject;
+ Contract.Requires(target != null);
+
+ try
+ {
+ string pResult_String = target.ToString();
+
+ if (pResult_String == null)
+ {
+ *pResult = default(HSTRING);
+ hr = Interop.COM.S_OK;
+ }
+ else
+ {
+ hr = McgMarshal.StringToHStringNoNullCheck(pResult_String, pResult);
+ }
+
+ return hr;
+ }
+ catch (Exception ex)
+ {
+ return McgMarshal.GetHRForExceptionWinRT(ex);
+ }
+ }
+ }
+#endif
+ /// <summary>
+ /// Implementation of ICCW for Jupiter Lifetime Feature
+ /// Currently this implementation doesn't do anything - it only delegates the Jupiter AddRef/Release
+ /// calls to real COM ref. This is done to avoid CCW gets destroyed when Jupiter does the following:
+ /// 1. COM Add Ref
+ /// 2. Jupiter Add Ref
+ /// 3. COM release
+ /// </summary>
+ internal unsafe struct __vtable_ICCW
+ {
+ // IUnknown
+ IntPtr pfnQueryInterface;
+ IntPtr pfnAddRef;
+ IntPtr pfnRelease;
+
+ // ICCW
+ IntPtr pfnAddRefFromJupiter;
+ IntPtr pfnReleaseFromJupiter;
+ IntPtr pfnPeg;
+ IntPtr pfnUnpeg;
+
+ public static IntPtr pNativeVtable;
+ static __vtable_ICCW s_theCcwVtable = new __vtable_ICCW
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(QueryInterface__STUB),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(AddRef__STUB),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(Release__STUB),
+ pfnAddRefFromJupiter = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(AddRefFromJupiter__STUB),
+ pfnReleaseFromJupiter = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(ReleaseFromJupiter__STUB),
+ pfnPeg = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(Peg__STUB),
+ pfnUnpeg = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(Unpeg__STUB),
+ };
+ internal static IntPtr GetVtableFuncPtr()
+ {
+ return AddrOfIntrinsics.AddrOf<AddrOfGetCCWVtable>(GetCcwvtable_ICCW);
+ }
+ internal static unsafe IntPtr GetCcwvtable_ICCW()
+ {
+ if (pNativeVtable == default(IntPtr))
+ {
+ fixed (void* pVtbl = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtbl, ref __vtable_ICCW.pNativeVtable,sizeof(__vtable_ICCW));
+ }
+ }
+ return __vtable_ICCW.pNativeVtable;
+ }
+
+ /// <remarks>
+ /// This is safe to mark as [NativeCallable] because Jupiter should never call it inside GC callout
+ /// in the first place
+ /// <remarks>
+ [NativeCallable]
+ static int QueryInterface__STUB(
+ IntPtr __IntPtr__pComThis,
+ IntPtr __IntPtr__pIID,
+ IntPtr __IntPtr__ppvObject)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+ Guid* pIID = (Guid*)__IntPtr__pIID;
+ void** ppvObject = (void**)__IntPtr__ppvObject;
+
+ //
+ // Check for neutered CCWs
+ // This is the only QI that can be called on a neutered CCW and we fail with a well defined
+ // COR_E_ACCESSING_CCW error code back to Jupiter
+ // NOTE: We should not use IsNeutered check here, instead, we have to keep a reference to CCW
+ // from here to avoid CCW getting neutered after the check.
+ //
+ var cco = pComThis->NativeCCW->ComCallableObjectUnsafe;
+
+ if (cco == null)
+ return Interop.COM.COR_E_ACCESSING_CCW;
+
+ // @TODO: does not distinguish between E_NOINTERFACE and E_OUTOFMEMORY
+ IntPtr result = cco.GetComInterfaceForIID(ref *pIID);
+ *ppvObject = (void*)result;
+
+ if (result == default(IntPtr))
+ return Interop.COM.E_NOINTERFACE;
+
+ return Interop.COM.S_OK;
+ }
+
+ [NativeCallable]
+ static int AddRef__STUB(IntPtr __IntPtr__pComThis)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+
+ //
+ // Use ->NativeCCW to support accessing neutered CCWs
+ //
+ return pComThis->NativeCCW->AddCOMRef();
+ }
+
+ [NativeCallable]
+ static int Release__STUB(IntPtr __IntPtr__pComThis)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+
+ //
+ // Use ->NativeCCW to support accessing neutered CCWs
+ //
+ return pComThis->NativeCCW->ReleaseCOMRef();
+ }
+
+ [NativeCallable]
+ static int AddRefFromJupiter__STUB(System.IntPtr __IntPtr__pComThis)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+
+ //
+ // Use ->NativeCCW to support accessing neutered CCWs
+ //
+ return pComThis->NativeCCW->AddJupiterRef();
+ }
+
+ [NativeCallable]
+ static int ReleaseFromJupiter__STUB(System.IntPtr __IntPtr__pComThis)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+
+ //
+ // Use ->NativeCCW to support accessing neutered CCWs
+ //
+ return pComThis->NativeCCW->ReleaseJupiterRef();
+ }
+
+ [NativeCallable]
+ static int Peg__STUB(System.IntPtr __IntPtr__pComThis)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+
+ //
+ // Use ->NativeCCW to support accessing neutered CCWs
+ //
+ pComThis->NativeCCW->IsPegged = true;
+
+ return 0;
+ }
+
+ [NativeCallable]
+ static int Unpeg__STUB(System.IntPtr __IntPtr__pComThis)
+ {
+ __interface_ccw* pComThis = (__interface_ccw*)__IntPtr__pComThis;
+
+ //
+ // Use ->NativeCCW to support accessing neutered CCWs
+ //
+ pComThis->NativeCCW->IsPegged = false;
+
+ return 0;
+ }
+ }
+
+#if ENABLE_WINRT
+ unsafe struct __com_IActivationFactoryInternal
+ {
+#pragma warning disable 649 // Field 'blah' is never assigned to, and will always have its default value null
+ internal __vtable_IActivationFactoryInternal* pVtable;
+#pragma warning restore 649
+ }
+
+ internal unsafe struct __vtable_IActivationFactoryInternal
+ {
+ // IUnknown
+ IntPtr pfnQueryInterface;
+ IntPtr pfnAddRef;
+ IntPtr pfnRelease;
+ // IInspectable
+ IntPtr pfnGetIids;
+ IntPtr pfnGetRuntimeClassName;
+ IntPtr pfnGetTrustLevel;
+ // IActivationFactoryInternal
+ internal IntPtr pfnActivateInstance;
+
+ static IntPtr pNativeVtable;
+ private static __vtable_IActivationFactoryInternal s_theCcwVtable = new __vtable_IActivationFactoryInternal
+ {
+ // IUnknown
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ // IInspectable
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+ // IActivationFactoryInternal
+ pfnActivateInstance = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(ActivateInstance)
+ };
+ internal static IntPtr GetVtableFuncPtr()
+ {
+ return AddrOfIntrinsics.AddrOf<AddrOfGetCCWVtable>(GetCcwvtable_IActivationFactoryInternal);
+ }
+ internal static unsafe IntPtr GetCcwvtable_IActivationFactoryInternal()
+ {
+ if (pNativeVtable == default(IntPtr))
+ {
+ fixed (void* pVtbl = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtbl, ref __vtable_IActivationFactoryInternal.pNativeVtable,sizeof(__vtable_IActivationFactoryInternal));
+ return __vtable_IActivationFactoryInternal.pNativeVtable;
+ }
+ }
+ return __vtable_IActivationFactoryInternal.pNativeVtable;
+ }
+
+ [NativeCallable]
+ internal static int ActivateInstance(
+ IntPtr pComThis,
+ IntPtr ppResult)
+ {
+ IntPtr* pResult = (IntPtr*)ppResult;
+ if (pResult == null)
+ return Interop.COM.E_POINTER;
+
+ try
+ {
+ object target = ComCallableObject.FromThisPointer(pComThis).TargetObject;
+ *pResult = (IntPtr)((IActivationFactoryInternal)target).ActivateInstance();
+ return Interop.COM.S_OK;
+ }
+ catch (System.Exception hrExcep)
+ {
+ *pResult = default(IntPtr);
+ return McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+ }
+ }
+#endif
+
+ internal unsafe struct __vtable_IManagedActivationFactory
+ {
+ // IUnknown
+ IntPtr pfnQueryInterface;
+ IntPtr pfnAddRef;
+ IntPtr pfnRelease;
+ // IInspectable
+ IntPtr pfnGetIids;
+ IntPtr pfnGetRuntimeClassName;
+ IntPtr pfnGetTrustLevel;
+ // IManagedActivationFactory
+ IntPtr pfnRunClassConstructor;
+
+ public static IntPtr pNativeVtable;
+ private static __vtable_IManagedActivationFactory s_theCcwVtable = new __vtable_IManagedActivationFactory
+ {
+ // IUnknown
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ // IInspectable
+ pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
+ pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
+ pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),
+ // IManagedActivationFactory
+ pfnRunClassConstructor = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(RunClassConstructor),
+ };
+ internal static IntPtr GetVtableFuncPtr()
+ {
+ return AddrOfIntrinsics.AddrOf<AddrOfGetCCWVtable>(GetCcwvtable_IManagedActivationFactory);
+ }
+ internal static unsafe IntPtr GetCcwvtable_IManagedActivationFactory()
+ {
+ if (pNativeVtable == default(IntPtr))
+ {
+ fixed (void* pVtbl = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtbl, ref __vtable_IManagedActivationFactory.pNativeVtable,sizeof(__vtable_IManagedActivationFactory));
+
+ }
+ }
+ return __vtable_IManagedActivationFactory.pNativeVtable;
+ }
+
+ [NativeCallable]
+ static int RunClassConstructor(
+ IntPtr pComThis)
+ {
+ try
+ {
+ ((IManagedActivationFactory)ComCallableObject.GetTarget(pComThis)).RunClassConstructor();
+ return Interop.COM.S_OK;
+ }
+ catch (System.Exception hrExcep)
+ {
+ return McgMarshal.GetHRForExceptionWinRT(hrExcep);
+ }
+ }
+ }
+
+ /// <summary>
+ /// IMarshal implementation that delegates to FTM
+ /// </summary>
+ internal unsafe struct __vtable_IMarshal
+ {
+ // IUnknown
+ IntPtr pfnQueryInterface;
+ IntPtr pfnAddRef;
+ IntPtr pfnRelease;
+ // IMarshal
+ IntPtr pfnGetUnmarshalClass;
+ IntPtr pfnGetMarshalSizeMax;
+ IntPtr pfnMarshalInterface;
+ IntPtr pfnUnmarshalInterface;
+ IntPtr pfnReleaseMarshalData;
+ IntPtr pfnDisconnectObject;
+
+ public static IntPtr pNativeVtable;
+ private static __vtable_IMarshal s_theCcwVtable = new __vtable_IMarshal
+ {
+ // IUnknown
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
+ // IMarshal
+ pfnGetUnmarshalClass = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMarshalUnMarshal>(__vtable_IMarshal.GetUnmarshalClass),
+ pfnGetMarshalSizeMax = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMarshalUnMarshal>(__vtable_IMarshal.GetMarshalSizeMax),
+ pfnMarshalInterface = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfMarshalInterface>(__vtable_IMarshal.MarshalInterface),
+ pfnUnmarshalInterface = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfUnmarshalInterface>(__vtable_IMarshal.UnmarshalInterface),
+ pfnReleaseMarshalData = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IMarshal.ReleaseMarshalData),
+ pfnDisconnectObject = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget2>(__vtable_IMarshal.DisconnectObject)
+ };
+
+ internal static IntPtr GetVtableFuncPtr()
+ {
+ return AddrOfIntrinsics.AddrOf<AddrOfGetCCWVtable>(GetCcwvtable_IMarshal);
+ }
+
+ internal static unsafe IntPtr GetCcwvtable_IMarshal()
+ {
+ if (pNativeVtable == default(IntPtr))
+ {
+ fixed (void* pVtbl = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtbl, ref __vtable_IMarshal.pNativeVtable,sizeof(__vtable_IMarshal));
+ }
+ }
+ return __vtable_IMarshal.pNativeVtable;
+ }
+
+ static unsafe int GetIMarshal(void **ppIMarshal)
+ {
+#if ENABLE_WINRT
+ void *pUnk = null;
+ int hr = ExternalInterop.CoCreateFreeThreadedMarshaler(null, (void **)&pUnk);
+ if (hr < 0) return hr;
+
+ *ppIMarshal = (void *)McgMarshal.ComQueryInterfaceNoThrow(
+ new IntPtr(pUnk), ref Interop.COM.IID_IMarshal, out hr);
+
+ McgMarshal.ComSafeRelease(new IntPtr(pUnk));
+
+ return hr;
+#else
+ throw new PlatformNotSupportedException("GetIMarshal");
+#endif
+ }
+
+ [NativeCallable]
+ static int GetUnmarshalClass(
+ IntPtr pComThis,
+ IntPtr piid,
+ IntPtr pv,
+ int dwDestContext,
+ IntPtr pvDestContext,
+ int mshlflags,
+ IntPtr pclsid
+ )
+ {
+ __vtable_IMarshal **pIMarshal = null;
+ try
+ {
+ int hr = GetIMarshal((void **)&pIMarshal);
+ if (hr < 0) return hr;
+
+ return CalliIntrinsics.StdCall<int>(
+ (*pIMarshal)->pfnGetUnmarshalClass,
+ pIMarshal,
+ piid,
+ pv,
+ dwDestContext,
+ pvDestContext,
+ mshlflags,
+ pclsid);
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(new IntPtr(pIMarshal));
+ }
+ }
+
+ [NativeCallable]
+ static int GetMarshalSizeMax(
+ IntPtr pComThis,
+ IntPtr piid,
+ IntPtr pv,
+ int dwDestContext,
+ IntPtr pvDestContext,
+ int mshlflags,
+ IntPtr pSize
+ )
+ {
+ __vtable_IMarshal **pIMarshal = null;
+ try
+ {
+ int hr = GetIMarshal((void**)&pIMarshal); ;
+ if (hr < 0) return hr;
+
+ return CalliIntrinsics.StdCall<int>(
+ (*pIMarshal)->pfnGetMarshalSizeMax,
+ pIMarshal,
+ piid,
+ pv,
+ dwDestContext,
+ pvDestContext,
+ mshlflags,
+ pSize);
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(new IntPtr(pIMarshal));
+ }
+ }
+
+ [NativeCallable]
+ static int MarshalInterface(
+ IntPtr pComThis,
+ IntPtr pStm,
+ IntPtr piid,
+ IntPtr pv,
+ int dwDestContext,
+ IntPtr pvDestContext,
+ int mshlflags
+ )
+ {
+ __vtable_IMarshal **pIMarshal = null;
+ try
+ {
+ int hr = GetIMarshal((void**)&pIMarshal);
+ if (hr < 0) return hr;
+
+ return CalliIntrinsics.StdCall<int>(
+ (*pIMarshal)->pfnMarshalInterface,
+ pIMarshal,
+ pStm,
+ piid,
+ pv,
+ dwDestContext,
+ pvDestContext,
+ mshlflags);
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(new IntPtr(pIMarshal));
+ }
+ }
+
+ [NativeCallable]
+ static int UnmarshalInterface(
+ IntPtr pComThis,
+ IntPtr pStm,
+ IntPtr piid,
+ IntPtr ppvObj
+ )
+ {
+ __vtable_IMarshal **pIMarshal = null;
+ try
+ {
+ int hr = GetIMarshal((void**)&pIMarshal);
+ if (hr < 0) return hr;
+
+ return CalliIntrinsics.StdCall<int>(
+ (*pIMarshal)->pfnUnmarshalInterface,
+ pIMarshal,
+ pStm,
+ piid,
+ ppvObj);
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(new IntPtr(pIMarshal));
+ }
+ }
+
+ [NativeCallable]
+ static int ReleaseMarshalData(
+ IntPtr pComThis,
+ IntPtr pStm
+ )
+ {
+ __vtable_IMarshal **pIMarshal = null;
+ try
+ {
+ int hr = GetIMarshal((void**)&pIMarshal);
+ if (hr < 0) return hr;
+
+ return CalliIntrinsics.StdCall<int>(
+ (*pIMarshal)->pfnReleaseMarshalData,
+ pIMarshal,
+ pStm);
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(new IntPtr(pIMarshal));
+ }
+ }
+
+ [NativeCallable]
+ static int DisconnectObject(
+ IntPtr pComThis,
+ int dwReserved
+ )
+ {
+ __vtable_IMarshal **pIMarshal = null;
+ try
+ {
+ int hr = GetIMarshal((void**)&pIMarshal);
+ if (hr < 0) return hr;
+
+ return CalliIntrinsics.StdCall<int>(
+ (*pIMarshal)->pfnDisconnectObject,
+ pIMarshal,
+ dwReserved);
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(new IntPtr(pIMarshal));
+ }
+ }
+ }
+
+ /// <summary>
+ /// Windows.UI.Xaml.Hosting.IReferenceTrackerTarget
+ /// Jupiter use this interface to coordinate with us
+ /// </summary>
+ internal unsafe struct __com_ICCW
+ {
+#pragma warning disable 0649
+ internal __vtable_ICCW* pVtable;
+#pragma warning restore 0649
+ }
+
+
+ unsafe struct __com_IStream
+ {
+#pragma warning disable 649 // Field 'blah' is never assigned to, and will always have its default value null
+ internal __vtable_IStream* pVtable;
+ public byte* m_pMem; // Memory for the read.
+ public int m_cbSize; // Size of the memory.
+#pragma warning restore 649
+
+ public int m_cbCurrent; // Current offset.
+ public int m_cRef; // Ref count.
+
+ /// <summary>
+ /// Create a predefined size of IStream*
+ /// </summary>
+ /// <remarks>
+ /// NOTE: The reason to create own IStream is that the API SHCreateMemStream doesn't belong to UWP API Sets
+ /// </remarks>
+ /// <param name="lSize">Requested size</param>
+ /// <returns>The IStream*</returns>
+ internal unsafe static IntPtr CreateMemStm(ulong lSize)
+ {
+#if ENABLE_WINRT
+ __com_IStream* pIStream = (__com_IStream*)ExternalInterop.CoTaskMemAlloc(new IntPtr(sizeof(__com_IStream)));
+ pIStream->pVtable = (__vtable_IStream*)__vtable_IStream.GetVtable();
+ pIStream->m_cbCurrent = 0;
+ pIStream->m_cRef = 1;
+ pIStream->m_cbSize = (int)lSize;
+ pIStream->m_pMem = (byte*)ExternalInterop.CoTaskMemAlloc(new IntPtr((int)lSize));
+
+ return new IntPtr(pIStream);
+#else
+ throw new PlatformNotSupportedException("CreateMemStm");
+#endif
+ }
+
+ internal unsafe static void DestroyMemStm(__com_IStream* pIStream)
+ {
+ // Release memory allocated by CreateMemStm
+ if (pIStream->m_pMem != null)
+ ExternalInterop.CoTaskMemFree(pIStream->m_pMem);
+
+ ExternalInterop.CoTaskMemFree(pIStream);
+ }
+ }
+
+ unsafe internal struct __vtable_IStream
+ {
+ // IUnknown
+ internal IntPtr pfnQueryInterface;
+ internal IntPtr pfnAddRef;
+ internal IntPtr pfnRelease;
+
+ // ISequentialStream
+ internal IntPtr pfnRead;
+ internal IntPtr pfnWrite;
+
+ // IStream
+ internal IntPtr pfnSeek;
+ internal IntPtr pfnSetSize;
+ internal IntPtr pfnCopyTo;
+ internal IntPtr pfnCommit;
+ internal IntPtr pfnRevert;
+ internal IntPtr pfnLockRegion;
+ internal IntPtr pfnUnlockRegion;
+ internal IntPtr pfnStat;
+ internal IntPtr pfnClone;
+
+ public static IntPtr pNativeVtable;
+
+ private static __vtable_IStream s_theCcwVtable = new __vtable_IStream
+ {
+ pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(QueryInterface),
+ pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(AddRef),
+ pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(Release),
+
+ pfnRead = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIStreamRead>(Read),
+ pfnWrite = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIStreamWrite>(Write),
+
+ pfnSeek = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIStreamSeek>(Seek),
+ pfnSetSize = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIStreamSetSize>(SetSize),
+ pfnCopyTo = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIStreamCopyTo>(CopyTo),
+ pfnCommit = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget2>(Commit),
+ pfnRevert = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(Revert),
+ pfnLockRegion = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIStreamLockRegion>(LockRegion),
+ pfnUnlockRegion = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIStreamUnlockRegion>(UnlockRegion),
+ pfnStat = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIStreamStat>(Stat),
+ pfnClone = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIStreamClone>(Clone),
+ };
+
+ internal static IntPtr GetVtable()
+ {
+ fixed (void* pVtable = &s_theCcwVtable)
+ {
+ McgMarshal.GetCCWVTableCopy(pVtable, ref __vtable_IStream.pNativeVtable, sizeof(__vtable_IStream));
+ }
+
+ return __vtable_IStream.pNativeVtable;
+ }
+
+ [NativeCallable]
+ internal static int QueryInterface(
+ IntPtr __IntPtr__pComThis,
+ IntPtr __IntPtr__pIID,
+ IntPtr __IntPtr__ppvObject)
+ {
+ __com_IStream* pIStream = (__com_IStream*)__IntPtr__pComThis;
+ void** ppvObject = (void**)__IntPtr__ppvObject;
+ Guid* pIID = (Guid*)__IntPtr__pIID;
+
+ if (ppvObject == null)
+ return Interop.COM.E_POINTER;
+
+ if (pIID->Equals(Interop.COM.IID_IUnknown) ||
+ pIID->Equals(Interop.COM.IID_IStream) ||
+ pIID->Equals(Interop.COM.IID_ISequentialStream))
+ {
+ *ppvObject = pIStream;
+ return Interop.COM.S_OK;
+ }
+ return Interop.COM.E_NOINTERFACE;
+ }
+
+ [NativeCallable]
+ internal static int AddRef(System.IntPtr pComThis)
+ {
+ // This never gets released from native
+ __com_IStream* pIStream = (__com_IStream*)pComThis;
+ int cRef = System.Threading.Interlocked.Increment(ref pIStream->m_cRef);
+ return cRef;
+ }
+
+ [NativeCallable]
+ internal static int Release(IntPtr pComThis)
+ {
+ __com_IStream* pIStream = (__com_IStream*)pComThis;
+ int cRef = System.Threading.Interlocked.Decrement(ref pIStream->m_cRef);
+ if (cRef == 0)
+ {
+ __com_IStream.DestroyMemStm(pIStream);
+ }
+ return cRef;
+ }
+
+ [NativeCallable]
+ internal static int CopyTo(System.IntPtr pComThis, IntPtr pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
+ {
+ // We don't handle pcbRead or pcbWritten.
+ System.Diagnostics.Debug.Assert(pcbRead == IntPtr.Zero);
+ System.Diagnostics.Debug.Assert(pcbWritten == IntPtr.Zero);
+ System.Diagnostics.Debug.Assert(cb >= 0);
+ try
+ {
+ __com_IStream* pIStream = (__com_IStream*)pComThis;
+ __com_IStream* pToIStream = (__com_IStream*)pstm;
+ long cbTotal = Math.Min(cb, pIStream->m_cbSize - pIStream->m_cbCurrent);
+ long cbRead = Math.Min(1024, cbTotal);
+ byte[] buffer = new byte[cbRead];
+
+ while (cbTotal > 0)
+ {
+ if (cbRead > cbTotal)
+ cbRead = cbTotal;
+ fixed (byte* pBuf = buffer)
+ {
+ CalliIntrinsics.StdCall__int(pIStream->pVtable->pfnRead, pComThis, pBuf, (int)cbRead, IntPtr.Zero);
+ CalliIntrinsics.StdCall__int(pToIStream->pVtable->pfnWrite, pstm, pBuf, (int)cbRead, IntPtr.Zero);
+ }
+ cbTotal -= cbRead;
+ }
+
+ // Adjust seek pointer to the end.
+ pIStream->m_cbCurrent = pIStream->m_cbSize;
+ return Interop.COM.S_OK;
+ }
+ catch (System.OutOfMemoryException ex)
+ {
+ return ex.HResult;
+ }
+ }
+
+ [NativeCallable]
+ internal static unsafe int Read(System.IntPtr pComThis, IntPtr pv, int cb, IntPtr pcb)
+ {
+ __com_IStream* pIStream = (__com_IStream*)pComThis;
+ byte* pByte = (byte*)pv;
+ int* pcbRead = (int*)pcb;
+
+ int cbRead = Math.Min(cb, pIStream->m_cbSize - pIStream->m_cbCurrent);
+ if (cbRead <= 0)
+ return Interop.COM.S_FALSE;
+
+ for (int i = 0; i < cbRead; i++)
+ {
+ pByte[i] = pIStream->m_pMem[pIStream->m_cbCurrent + i];
+ }
+ if (pcbRead != null)
+ *pcbRead = cbRead;
+ pIStream->m_cbCurrent += cbRead;
+ return Interop.COM.S_OK;
+ }
+
+ [NativeCallable]
+ internal static unsafe int Write(System.IntPtr pComThis, IntPtr pv, int cb, IntPtr pcbWritten)
+ {
+ __com_IStream* pIStream = (__com_IStream*)pComThis;
+ byte* pByte = (byte*)pv;
+ int* cbWritten = (int*)pcbWritten;
+ if (cb + pIStream->m_cbCurrent > pIStream->m_cbSize)
+ return Interop.COM.E_OUTOFMEMORY;
+
+ for (int i = 0; i < cb; i++)
+ {
+ pIStream->m_pMem[i + pIStream->m_cbCurrent] = pByte[i];
+ }
+ pIStream->m_cbCurrent += cb;
+
+ if (cbWritten != null)
+ *cbWritten = cb;
+ return Interop.COM.S_OK;
+ }
+
+ [NativeCallable]
+ internal static unsafe int Seek(System.IntPtr pComThis, long dlibMove, int dwOrigin, IntPtr plib)
+ {
+ __com_IStream* pIStream = (__com_IStream*)pComThis;
+ int* plibNewPosition = (int*)plib;
+ Debug.Assert(dwOrigin == (int)Interop.COM.STREAM_SEEK.STREAM_SEEK_SET ||
+ dwOrigin == (int)Interop.COM.STREAM_SEEK.STREAM_SEEK_CUR);
+ Debug.Assert(dlibMove >= 0);
+
+ if (dwOrigin == (int)Interop.COM.STREAM_SEEK.STREAM_SEEK_SET)
+ {
+ pIStream->m_cbCurrent = (int)dlibMove;
+ }
+ else if (dwOrigin == (int)Interop.COM.STREAM_SEEK.STREAM_SEEK_CUR)
+ {
+ pIStream->m_cbCurrent += (int)dlibMove;
+ }
+
+ if (plibNewPosition != null)
+ {
+ *plibNewPosition = pIStream->m_cbCurrent;
+ }
+
+ if (pIStream->m_cbCurrent > pIStream->m_cbSize)
+ return Interop.COM.E_FAIL;
+
+ return Interop.COM.S_OK;
+ }
+
+ [NativeCallable]
+ internal static unsafe int Stat(System.IntPtr pComThis, out ComTypes.STATSTG pstatstg, int grfStatFlag)
+ {
+ __com_IStream* pIStream = (__com_IStream*)pComThis;
+ pstatstg = new ComTypes.STATSTG();
+ pstatstg.cbSize = pIStream->m_cbSize;
+ return Interop.COM.S_OK;
+ }
+
+ #region "NotImplementedException"
+ [NativeCallable]
+ internal static int Clone(System.IntPtr pComThis, out IntPtr ppstm)
+ {
+ ppstm = default(IntPtr);
+ return Interop.COM.E_NOTIMPL;
+ }
+
+ [NativeCallable]
+ internal static int Commit(System.IntPtr pComThis, int grfCommitFlags)
+ {
+ return Interop.COM.E_NOTIMPL;
+ }
+
+ [NativeCallable]
+ internal static int LockRegion(System.IntPtr pComThis, long libOffset, long cb, int dwLockType)
+ {
+ return Interop.COM.E_NOTIMPL;
+ }
+
+ [NativeCallable]
+ internal static int Revert(System.IntPtr pComThis)
+ {
+ return Interop.COM.E_NOTIMPL;
+ }
+
+ [NativeCallable]
+ internal static int SetSize(System.IntPtr pComThis, long libNewSize)
+ {
+ return Interop.COM.E_NOTIMPL;
+ }
+
+ [NativeCallable]
+ internal static int UnlockRegion(System.IntPtr pComThis, long libOffset, long cb, int dwLockType)
+ {
+ return Interop.COM.E_NOTIMPL;
+ }
+ #endregion
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/StringPool.cs b/src/System.Private.Interop/src/Shared/StringPool.cs
new file mode 100644
index 000000000..c7fbc7f35
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/StringPool.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.
+
+using System;
+using System.Diagnostics;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Commpressed collection of strings represented by two byte arrays + one ushort array
+ /// m_typeNamespaces are shared substrings, limited to 128 strings, each represented by an index. Currently only namespaces are stored. E.g. "System.Runtime."
+ /// m_typeNames are compressed strings, each represented by an index. Within m_typeNames, [0x80 .. 0xFF] bytes are used to represented shared sub strings.
+ /// m_indices array maps index to start position
+ ///
+ /// All strings are zero-terminated. Tail reusing is possible, but not implemented by MCG.
+ /// If a string in m_typeNames start with 0x01, it's stored as complete UNICODE string (0x01 + two bytes for each char + two 0 bytes). lsb byte goes first.
+ ///
+ /// Functions:
+ /// 1. GetString converts compressed string represented by an index to original System.String
+ /// 2. StableStringHash computes hash code without decoding to System.String
+ /// 3. IsStringEqual compares compressed string represented by anindex with System.String
+ ///
+ /// TODO:
+ /// 1. More string reuse
+ /// </summary>
+ internal class StringPool
+ {
+ byte[] m_typeNamespaces; // Big byte array of all class/interface namespaces
+ byte[] m_typeNames; // Big byte array of all class/interface/value-type names
+ UInt16[] m_indices; // Map from >=0x80 bytes to first char in m_typeNamespaces array
+
+ internal StringPool(
+ byte[] typeNamespaces,
+ byte[] typeNames,
+ UInt16[] indices)
+ {
+ m_typeNamespaces = typeNamespaces;
+ m_typeNames = typeNames;
+ m_indices = indices;
+ }
+
+ internal const byte Escape_Start = 0x80;
+ internal const byte Unicode_Mark = 0x01; // If first byte is 0x01, whole string is UNICODE: two bytes for each char + two 0 bytes
+
+ /// <summary>
+ /// Convert string represented by an index back to original form, by expanding Unicode private use area characters to namespace names
+ /// </summary>
+ internal unsafe string GetString(UInt32 nameIdx)
+ {
+ Debug.Assert((nameIdx >= 0) && (nameIdx < m_typeNames.Length));
+
+ fixed (byte* pNs = m_typeNamespaces)
+ fixed (byte* pN = m_typeNames)
+ {
+ int len = 0;
+
+ bool unicode = false;
+
+ if (pN[nameIdx] == Unicode_Mark) // Check for UNICODE mark
+ {
+ unicode = true;
+ nameIdx++;
+ }
+
+ // Calculate final string length
+ for (byte* p = pN + nameIdx; ; p++)
+ {
+ int c = *p;
+
+ if (unicode)
+ {
+ c |= (*(++p)) << 8; // read the 2nd byte, forming a completer UTF16 char
+ }
+
+ if (c == 0)
+ break;
+
+ if (!unicode && (c >= Escape_Start)) // If not UNICODE mode, for char in [0x80 .. 0xFF] range read substring from m_typeNamespace array
+ {
+ int namespaceIndex = m_indices[c - Escape_Start];
+
+ Debug.Assert((namespaceIndex >= 0) && (namespaceIndex < m_typeNamespaces.Length));
+
+ for (byte* q = pNs + namespaceIndex; *q != 0; q++)
+ {
+ len++;
+ }
+ }
+ else
+ {
+ len++;
+ }
+ }
+
+ // Allocate string, TODO make FastAllocString accessible
+ string result = new string(' ', len);
+
+ // Fill characters
+ fixed (char* pResult = result)
+ {
+ char* pDest = pResult;
+
+ for (byte* p = pN + nameIdx; ; p++)
+ {
+ int c = *p;
+
+ if (unicode)
+ {
+ c |= (*(++p)) << 8;
+ }
+
+ if (c == 0)
+ break;
+
+ if (!unicode && (c >= Escape_Start))
+ {
+ int namespaceIndex = m_indices[c - Escape_Start];
+
+ Debug.Assert((namespaceIndex >= 0) && (namespaceIndex < m_typeNamespaces.Length));
+
+ for (byte* q = pNs + namespaceIndex; *q != 0; q++)
+ {
+ *pDest++ = (char)*q;
+ len++;
+ }
+ }
+ else
+ {
+ *pDest++ = (char)c;
+ }
+ }
+ }
+
+ return result;
+ }
+ }
+
+ const int Hash_Init = 5381;
+
+ /// <summary>
+ /// Should be inlined
+ /// </summary>
+ internal static int HashAccumulate(int hash, char val)
+ {
+ return ((hash << 5) + hash) ^ val;
+ }
+
+ /// <summary>
+ /// This version needs to be the same as in StableStringHash(int nameIdx)
+ /// </summary>
+ internal static int StableStringHash(string str)
+ {
+ int hash = Hash_Init;
+
+ if (str != null)
+ {
+ hash = HashAccumulate(hash, (char)0); // Make null and "" different
+
+ for (int i = 0; i < str.Length; i++)
+ {
+ hash = HashAccumulate(hash, str[i]);
+ }
+ }
+
+ return hash & 0x7FFFFFFF;
+ }
+
+ /// <summary>
+ /// Compute hash code same as StableStringHash(System.String)
+ /// </summary>
+ /// <param name="nameIdx"></param>
+ /// <returns></returns>
+ internal unsafe int StableStringHash(UInt32 nameIdx)
+ {
+ int hash = Hash_Init;
+
+ fixed (byte* pNs = m_typeNamespaces)
+ fixed (byte* pN = m_typeNames)
+ {
+ hash = HashAccumulate(hash, (char)0);
+
+ bool unicode = false;
+
+ if (pN[nameIdx] == Unicode_Mark)
+ {
+ unicode = true;
+ nameIdx++;
+ }
+
+ for (byte* p = pN + nameIdx; ; p++)
+ {
+ int c = *p;
+
+ if (unicode)
+ {
+ c |= (*(++p)) << 8;
+ }
+
+ if (c == 0)
+ {
+ break;
+ }
+
+ if (!unicode && c >= Escape_Start)
+ {
+ int namespaceIndex = m_indices[c - Escape_Start];
+
+ Debug.Assert((namespaceIndex >= 0) && (namespaceIndex < m_typeNamespaces.Length));
+
+ for (byte* q = pNs + namespaceIndex; *q != 0; q++)
+ {
+ hash = HashAccumulate(hash, (char)*q);
+ }
+ }
+ else
+ {
+ hash = HashAccumulate(hash, (char)c);
+ }
+ }
+ }
+
+ return hash & 0x7FFFFFFF;
+ }
+
+ /// <summary>
+ /// Check if name is the same as encoded string represented by nameIdx
+ /// </summary>
+ internal unsafe bool IsStringEqual(string name, UInt32 nameIdx)
+ {
+ Debug.Assert(nameIdx < m_typeNames.Length);
+
+ fixed (char* pNameStart = name)
+ fixed (byte* pNBlob = m_typeNames, pNsBlob = m_typeNamespaces)
+ {
+ bool unicode = false;
+
+ if (pNBlob[nameIdx] == Unicode_Mark)
+ {
+ unicode = true;
+ nameIdx++;
+ }
+
+ char* pName = pNameStart;
+ byte* pN = pNBlob + nameIdx;
+
+ for (; ; pN++)
+ {
+ int c = *pN;
+
+ if (unicode)
+ {
+ c |= (*(++pN)) << 8;
+ }
+
+ if (c == 0)
+ break;
+
+ if (!unicode && (c >= Escape_Start))
+ {
+ byte* pNs = pNsBlob + m_indices[c - Escape_Start];
+
+ for (; ; pNs++, pName++)
+ {
+ byte d = *pNs;
+
+ if (d == 0)
+ break;
+
+ if (d != *pName)
+ goto NoMatch;
+ }
+ }
+ else
+ {
+ if (c != *pName)
+ goto NoMatch;
+
+ pName++;
+ }
+ }
+
+ if (*pName != '\0')
+ goto NoMatch;
+ }
+
+ Debug.Assert(GetString(nameIdx) == name, "IsStringEqual returned a bad result");
+
+ return true;
+
+ NoMatch:
+ Debug.Assert(GetString(nameIdx) != name, "IsStringEqual returned a bad result");
+
+ return false;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/Shared/WindowsRuntimeMarshal.cs b/src/System.Private.Interop/src/Shared/WindowsRuntimeMarshal.cs
new file mode 100644
index 000000000..d6e7e8c91
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/WindowsRuntimeMarshal.cs
@@ -0,0 +1,1275 @@
+// 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.ComponentModel;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using System.Security;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+namespace System.Runtime.InteropServices.WindowsRuntime
+{
+#if ENABLE_WINRT
+ // 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.
+#if false
+ [SecurityCritical]
+#endif
+ 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 -
+ // Managed events are implemented using ConditionalWeakTable which is based on the weak reference of the event itself.
+ // Since the managed event will be alive till the event is used. This is OK.
+
+ // On the other hand native and static events can't follow the same model as managed object. Since the native event might be alive but the managed __ComObject might
+ // die, a different __ComObject instance might reference the same native event. Or same __ComObject instance might mean a different native event.
+ // and hence they both have different implementations.
+#if !RHTESTCL
+ object target = removeMethod.Target;
+ if (target == null || target is __ComObject)
+ NativeOrStaticEventRegistrationImpl.AddEventHandler<T>(addMethod, removeMethod, handler);
+ else
+#endif
+ 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>
+#if false
+ [SecurityCritical]
+#endif
+ 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
+#if !RHTESTCL
+ object target = removeMethod.Target;
+ if (target == null || target is __ComObject)
+ NativeOrStaticEventRegistrationImpl.RemoveEventHandler<T>(removeMethod, handler);
+ else
+#endif
+ ManagedEventRegistrationImpl.RemoveEventHandler<T>(removeMethod, handler);
+ }
+
+#if false
+ [SecurityCritical]
+#endif
+ 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
+#if !RHTESTCL
+ object target = removeMethod.Target;
+ if (target != null && target is __ComObject)
+ NativeOrStaticEventRegistrationImpl.RemoveAllEventHandlers(removeMethod);
+ else
+#endif
+ ManagedEventRegistrationImpl.RemoveAllEventHandlers(removeMethod);
+ }
+
+#if !RHTESTCL
+ // 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)
+ {
+ try
+ {
+ ManagedEventRegistrationImpl.s_eventRegistrationsLock.Acquire();
+
+ count += ManagedEventRegistrationImpl.s_eventRegistrations.GetKeys().Count;
+ }
+ finally
+ {
+ ManagedEventRegistrationImpl.s_eventRegistrationsLock.Release();
+ }
+ }
+
+ if (NativeOrStaticEventRegistrationImpl.s_eventRegistrations != null)
+ {
+ try
+ {
+ NativeOrStaticEventRegistrationImpl.s_eventRegistrationsLock.Acquire();
+
+ count += NativeOrStaticEventRegistrationImpl.s_eventRegistrations.Count;
+ }
+ finally
+ {
+ NativeOrStaticEventRegistrationImpl.s_eventRegistrationsLock.Release();
+ }
+ }
+
+ return count;
+ }
+#endif
+
+ //
+ // 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 System.Collections.Generic.Internal.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 System.Collections.Generic.Internal.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(System.Collections.Generic.Internal.List<EventRegistrationToken> tokens)
+ {
+ tokens.Add(firstToken);
+
+ if (restTokens != null)
+ {
+ for (int i = 0; i < restTokens.Count; i++)
+ {
+ tokens.Add(restTokens[i]);
+ }
+ }
+ }
+ }
+
+ //
+ // 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 races 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 static
+ ConditionalWeakTable<object, System.Collections.Generic.Internal.Dictionary<IntPtr, System.Collections.Generic.Internal.Dictionary<object, EventRegistrationTokenList>>> s_eventRegistrations =
+ new ConditionalWeakTable<object, System.Collections.Generic.Internal.Dictionary<IntPtr, System.Collections.Generic.Internal.Dictionary<object, EventRegistrationTokenList>>>();
+
+ internal static Lock s_eventRegistrationsLock = new Lock();
+
+#if false
+ [SecurityCritical]
+#endif
+ 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;
+
+#if !RHTESTCL
+ Contract.Requires(instance != null && !(instance is __ComObject));
+#endif
+ System.Collections.Generic.Internal.Dictionary<object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod);
+
+ EventRegistrationToken token = addMethod(handler);
+
+ try
+ {
+ registrationTokens.LockAcquire();
+
+ 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;
+ }
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event subscribed for managed instance = " + instance + ", handler = " + handler + "\n");
+#endif
+ }
+ finally
+ {
+ registrationTokens.LockRelease();
+ }
+ }
+
+ // Get the event registration token table for an event. These are indexed by the remove method of the event.
+ private static System.Collections.Generic.Internal.Dictionary<object, EventRegistrationTokenList> GetEventRegistrationTokenTable(object instance, Action<EventRegistrationToken> removeMethod)
+ {
+ Contract.Requires(instance != null);
+ Contract.Requires(removeMethod != null);
+ Contract.Requires(s_eventRegistrations != null);
+
+ try
+ {
+ s_eventRegistrationsLock.Acquire();
+
+ System.Collections.Generic.Internal.Dictionary<IntPtr, System.Collections.Generic.Internal.Dictionary<object, EventRegistrationTokenList>> instanceMap = null;
+
+ if (!s_eventRegistrations.TryGetValue(instance, out instanceMap))
+ {
+ instanceMap = new System.Collections.Generic.Internal.Dictionary<IntPtr, System.Collections.Generic.Internal.Dictionary<object, EventRegistrationTokenList>>();
+ s_eventRegistrations.Add(instance, instanceMap);
+ }
+
+ System.Collections.Generic.Internal.Dictionary<object, EventRegistrationTokenList> tokens = null;
+
+ // Because this code already is tied to a specific instance, the type handle associated with the
+ // delegate is not needed.
+ RuntimeTypeHandle thDummy;
+
+ if (!instanceMap.TryGetValue(removeMethod.GetFunctionPointer(out thDummy), out tokens))
+ {
+ tokens = new System.Collections.Generic.Internal.Dictionary<object, EventRegistrationTokenList>(true);
+ instanceMap.Add(removeMethod.GetFunctionPointer(out thDummy), tokens);
+ }
+
+ return tokens;
+ }
+ finally
+ {
+ s_eventRegistrationsLock.Release();
+ }
+ }
+
+#if false
+ [SecurityCritical]
+#endif
+ internal static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler)
+ {
+ Contract.Requires(removeMethod != null);
+
+ object instance = removeMethod.Target;
+
+ //
+ // Temporary static event support - this is bad for a couple of reasons:
+ // 1. This will leak the event delegates. Our real implementation fixes that
+ // 2. We need the type itself, but we don't have delegate.Method.DeclaringType (
+ // but I don't know what is the best replacement). Perhaps this isn't too bad
+ // 3. Unsubscription doesn't work due to ConditionalWeakTable work on reference equality.
+ // I can fix this but I figured it is easier to keep this broken so that we know we'll fix
+ // this (rather than using the slower value equality version which we might forget to fix
+ // later
+ // @TODO - Remove this and replace with real static support (that was #ifdef-ed out)
+ //
+ if (instance == null)
+ {
+ // Because this code only operates for delegates to static methods, the output typehandle of GetFunctionPointer is not used
+ RuntimeTypeHandle thDummy;
+ instance = removeMethod.GetFunctionPointer(out thDummy);
+ }
+
+ System.Collections.Generic.Internal.Dictionary<object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod);
+ EventRegistrationToken token;
+
+ try
+ {
+ registrationTokens.LockAcquire();
+
+ 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))
+ {
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] no registrationTokens found for instance=" + instance + ", handler= " + handler + "\n");
+#endif
+
+ 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);
+ }
+ }
+ finally
+ {
+ registrationTokens.LockRelease();
+ }
+
+ removeMethod(token);
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for managed instance = " + instance + ", handler = " + handler + ", token = " + token.m_value + "\n");
+#endif
+ }
+
+#if false
+ [SecurityCritical]
+#endif
+ internal static void RemoveAllEventHandlers(Action<EventRegistrationToken> removeMethod)
+ {
+ Contract.Requires(removeMethod != null);
+
+ object instance = removeMethod.Target;
+ System.Collections.Generic.Internal.Dictionary<object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod);
+
+ System.Collections.Generic.Internal.List<EventRegistrationToken> tokensToRemove = new System.Collections.Generic.Internal.List<EventRegistrationToken>();
+
+ try
+ {
+ registrationTokens.LockAcquire();
+
+ // 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();
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Cache cleared for managed instance = " + instance + "\n");
+#endif
+ }
+ finally
+ {
+ registrationTokens.LockRelease();
+ }
+
+ //
+ // Remove all handlers outside the lock
+ //
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Start removing all events for instance = " + instance + "\n");
+#endif
+ CallRemoveMethods(removeMethod, tokensToRemove);
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finished removing all events for instance = " + instance + "\n");
+#endif
+ }
+ }
+
+#if !RHTESTCL
+ //
+ // 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 object 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
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finalizing EventRegistrationTokenList for " + _tokenListCount.Key + "\n");
+#endif
+ _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(System.Collections.Generic.Internal.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);
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Incremented TokenListCount for " + _key + ", Value = " + newCount + "\n");
+#endif
+ }
+
+ 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);
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Decremented TokenListCount for " + _key + ", Value = " + newCount + "\n");
+#endif
+ 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);
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Removing " + _key + " from cache" + "\n");
+#endif
+ s_eventRegistrations.Remove(_key);
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] s_eventRegistrations size = " + s_eventRegistrations.Count + "\n");
+#endif
+ }
+ }
+
+ internal class EventCacheEntry
+ {
+ // [Handler] -> Token
+ internal ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTable;
+
+ // Maintains current total count for the EventRegistrationTokenListWithCount for this event cache key
+ internal TokenListCount tokenListCount;
+
+ // Lock for registrationTable + tokenListCount, much faster than locking ConditionalWeakTable itself
+ internal Lock _lock;
+
+ internal void LockAcquire()
+ {
+ _lock.Acquire();
+ }
+
+ internal void LockRelease()
+ {
+ _lock.Release();
+ }
+ }
+
+ // 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 static System.Collections.Generic.Internal.Dictionary<EventCacheKey, EventCacheEntry> s_eventRegistrations =
+ new System.Collections.Generic.Internal.Dictionary<EventCacheKey, EventCacheEntry>(new EventCacheKeyEqualityComparer());
+
+ internal static Lock s_eventRegistrationsLock = new Lock();
+
+ // Prevent add/remove handler code to run at the same with with cache cleanup code
+ private static MyReaderWriterLock s_eventCacheRWLock = new MyReaderWriterLock();
+
+ private static Object s_dummyStaticEventKey = new Object();
+ // Get InstanceKey to use in the cache
+#if false
+ [SecuritySafeCritical]
+#endif
+ private static object GetInstanceKey(Action<EventRegistrationToken> removeMethod)
+ {
+ object target = removeMethod.Target;
+ Contract.Assert(target == null || target is __ComObject, "Must be an RCW");
+
+ if (target == null)
+ {
+ // In .NET Native there is no good way to go from the static event to the declaring type, the instanceKey used for
+ // static events in desktop. Since the declaring type is only a way to organize the list of static events, we have
+ // chosen to use the dummyObject instead here.It flattens the hierarchy of static events but does not impact the functionality.
+ return s_dummyStaticEventKey;
+ }
+
+ // Need the "Raw" IUnknown pointer for the RCW that is not bound to the current context
+ __ComObject comObject = target as __ComObject;
+ return (object)comObject.BaseIUnknown_UnsafeNoAddRef;
+ }
+
+#if false
+ [SecurityCritical]
+#endif
+ 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.
+ EventCacheEntry registrationTokens = GetOrCreateEventRegistrationTokenTable(instanceKey, removeMethod);
+
+ try
+ {
+ registrationTokens.LockAcquire();
+
+ //
+ // 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.registrationTable.FindEquivalentKeyUnsafe(handler, out tokens);
+
+ if (key == null)
+ {
+ tokens = new EventRegistrationTokenListWithCount(registrationTokens.tokenListCount, token);
+ registrationTokens.registrationTable.Add(handler, tokens);
+ }
+ else
+ {
+ tokens.Push(token);
+ }
+
+ tokenAdded = true;
+ }
+ finally
+ {
+ registrationTokens.LockRelease();
+ }
+ }
+ finally
+ {
+ s_eventCacheRWLock.ReleaseReaderLock();
+ }
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event subscribed for instance = " + instanceKey + ", handler = " + handler + "\n");
+#endif
+ }
+ 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 EventCacheEntry GetEventRegistrationTokenTableNoCreate(object instance, Action<EventRegistrationToken> removeMethod)
+ {
+ Contract.Requires(instance != null);
+ Contract.Requires(removeMethod != null);
+
+ return GetEventRegistrationTokenTableInternal(instance, removeMethod, /* createIfNotFound = */ false);
+ }
+
+ private static EventCacheEntry GetOrCreateEventRegistrationTokenTable(object instance, Action<EventRegistrationToken> removeMethod)
+ {
+ Contract.Requires(instance != null);
+ Contract.Requires(removeMethod != null);
+
+ return GetEventRegistrationTokenTableInternal(instance, removeMethod, /* createIfNotFound = */ true);
+ }
+
+ // Get the event registration token table for an event. These are indexed by the remove method of the event.
+ private static EventCacheEntry GetEventRegistrationTokenTableInternal(object instance, Action<EventRegistrationToken> removeMethod, bool createIfNotFound)
+ {
+ Contract.Requires(instance != null);
+ Contract.Requires(removeMethod != null);
+ Contract.Requires(s_eventRegistrations != null);
+
+ EventCacheKey eventCacheKey;
+ eventCacheKey.target = instance;
+#if false
+ eventCacheKey.method = removeMethod.Method;
+#endif
+ RuntimeTypeHandle thDummy;
+ eventCacheKey.method = removeMethod.GetFunctionPointer(out thDummy);
+
+ try
+ {
+ s_eventRegistrationsLock.Acquire();
+
+ EventCacheEntry eventCacheEntry;
+
+ if (!s_eventRegistrations.TryGetValue(eventCacheKey, out eventCacheEntry))
+ {
+ if (!createIfNotFound)
+ {
+ // No need to create an entry in this case
+ return null;
+ }
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Adding (" + instance + "," + removeMethod.Method + ") into cache" + "\n");
+#endif
+ eventCacheEntry = new EventCacheEntry();
+ eventCacheEntry.registrationTable = new ConditionalWeakTable<object, EventRegistrationTokenListWithCount>();
+ eventCacheEntry.tokenListCount = new TokenListCount(eventCacheKey);
+ eventCacheEntry._lock = new Lock();
+
+ s_eventRegistrations.Add(eventCacheKey, eventCacheEntry);
+ }
+
+ return eventCacheEntry;
+ }
+ finally
+ {
+ s_eventRegistrationsLock.Release();
+ }
+ }
+
+#if false
+ [SecurityCritical]
+#endif
+ 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
+ {
+ EventCacheEntry registrationTokens = GetEventRegistrationTokenTableNoCreate(instanceKey, removeMethod);
+ 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
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] no registrationTokens found for instance=" + instanceKey + ", handler= " + handler + "\n");
+#endif
+ return;
+ }
+
+ try
+ {
+ registrationTokens.LockAcquire();
+
+ 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.registrationTable.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.
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] no token list found for instance=" + instanceKey + ", handler= " + handler + "\n");
+#endif
+ 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 race with the finalizer of
+ // EventRegistrationTokenList
+ registrationTokens.registrationTable.Remove(key);
+ }
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for managed instance = " + instanceKey + ", handler = " + handler + ", token = " + token.m_value + "\n");
+#endif
+ }
+ finally
+ {
+ registrationTokens.LockRelease();
+ }
+ }
+ 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);
+ }
+
+#if false
+ [SecurityCritical]
+#endif
+ internal static void RemoveAllEventHandlers(Action<EventRegistrationToken> removeMethod)
+ {
+ object instanceKey = GetInstanceKey(removeMethod);
+
+ System.Collections.Generic.Internal.List<EventRegistrationToken> tokensToRemove = new System.Collections.Generic.Internal.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
+ {
+ EventCacheEntry registrationTokens = GetEventRegistrationTokenTableNoCreate(instanceKey, removeMethod);
+ 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;
+ }
+
+ try
+ {
+ registrationTokens.LockAcquire();
+
+ // Copy all tokens to tokensToRemove array which later we'll call removeMethod on
+ // outside this lock
+ foreach (EventRegistrationTokenListWithCount tokens in registrationTokens.registrationTable.GetValues())
+ {
+ 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.registrationTable.Clear();
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Cache cleared for managed instance = " + instanceKey + "\n");
+#endif
+ }
+ finally
+ {
+ registrationTokens.LockRelease();
+ }
+ }
+ finally
+ {
+ s_eventCacheRWLock.ReleaseReaderLock();
+ }
+
+ //
+ // Remove all handlers outside the lock
+ //
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Start removing all events for instance = " + instanceKey + "\n");
+#endif
+ CallRemoveMethods(removeMethod, tokensToRemove);
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finished removing all events for instance = " + instanceKey + "\n");
+#endif
+ }
+
+
+ internal class ReaderWriterLockTimedOutException : /*ApplicationException*/ Exception
+ {
+ }
+
+ /// 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))
+ 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)
+ System.Threading.SpinWait.Spin(20); // Wait a few dozen instructions to let another processor release lock.
+
+ else
+ System.Threading.SpinWait.Yield();
+
+ 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;
+ }
+ };
+ }
+#endif
+
+ //
+ // 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, System.Collections.Generic.Internal.List<EventRegistrationToken> tokensToRemove)
+ {
+ System.Collections.Generic.Internal.List<Exception> exceptions = new System.Collections.Generic.Internal.List<Exception>();
+
+ for (int i = 0; i < tokensToRemove.Count; i++)
+ {
+ try
+ {
+ removeMethod(tokensToRemove[i]);
+ }
+ catch (Exception ex)
+ {
+ exceptions.Add(ex);
+ }
+#if false
+ BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for token = " + token.m_value + "\n");
+#endif
+ }
+
+ if (exceptions.Count > 0)
+#if false
+ throw new AggregateException(exceptions.ToArray());
+#else
+ throw exceptions[0];
+#endif
+ }
+
+ public static IntPtr StringToHString(string s)
+ {
+ return McgMarshal.StringToHString(s).handle;
+ }
+
+ public static void FreeHString(IntPtr ptr)
+ {
+ McgMarshal.FreeHString(ptr);
+ }
+
+ public static string PtrToStringHString(IntPtr ptr)
+ {
+ return McgMarshal.HStringToString(ptr);
+ }
+
+ /// <summary>
+ /// Returns the activation factory without using the cache. Avoiding cache behavior is important
+ /// for app that use this API because they need to deal with crashing broker scenarios where cached
+ /// factories would be stale (pointing to a bad proxy)
+ /// </summary>
+ public static IActivationFactory GetActivationFactory(Type type)
+ {
+ if (type == null)
+ throw new ArgumentNullException("type");
+
+ __ComObject factory = FactoryCache.Get().GetActivationFactory(
+ type.FullName,
+ McgModuleManager.IUnknown,
+ skipCache: true);
+ return (IActivationFactory) factory;
+ }
+ }
+#endif
+}
diff --git a/src/System.Private.Interop/src/Shared/__ComObject.cs b/src/System.Private.Interop/src/Shared/__ComObject.cs
new file mode 100644
index 000000000..b4a4897e2
--- /dev/null
+++ b/src/System.Private.Interop/src/Shared/__ComObject.cs
@@ -0,0 +1,3429 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// ----------------------------------------------------------------------------------
+// Interop library code
+//
+// Implementation for RCWs
+//
+// NOTE:
+// These source code are being published to InternalAPIs and consumed by RH builds
+// Use PublishInteropAPI.bat to keep the InternalAPI copies in sync
+// ---------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Text;
+using System.Runtime;
+using System.Diagnostics.Contracts;
+using Internal.NativeFormat;
+
+namespace System
+{
+ /// <summary>
+ /// Helper class to finalize this RCW object
+ /// When we have managed class deriving from native class, if it has a finalizer, the finalizer won't
+ /// have a call to base __ComObject because compiler doesn't see it. Also, developer can call
+ /// SuppressFinalize and by pass the finalizer altogether without knowing that they've by passed the
+ /// finalizer of the base __ComObject.
+ /// The solution here is to simply rely on another object to do the finalization.
+ /// Note that we can't do this in the ComCallableObject's finalizer (we don't have it now) because the
+ /// the CCW would have shorter life time than the actual managed object so it might've destroyed the base
+ /// RCW before managed class is gone.
+ /// </summary>
+ internal class RCWFinalizer
+ {
+ private __ComObject m_comObject;
+
+ internal RCWFinalizer(__ComObject comObject)
+ {
+ m_comObject = comObject;
+ }
+
+ ~RCWFinalizer()
+ {
+ m_comObject.Cleanup();
+ }
+ }
+
+ /// <summary>
+ /// This is the weakly-typed RCW and also base class of all strongly-typed RCWs
+ /// NOTE: Managed debugger depends on type name: "System.__ComObject"
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [CLSCompliant(false)]
+ public unsafe class __ComObject : ICastable
+ {
+ #region Private variables
+
+ /// <summary>
+ /// RCW Identity interface pointer + context
+ /// This supports all the cross-apartment marshalling
+ /// </summary>
+ ContextBoundInterfacePointer m_baseIUnknown;
+
+ /// <summary>
+ /// Base IUnknown of this RCW. When we QI we'll be using this IUnknown
+ /// Note that this is not necessarily the identity IUnknown, which is why I name it "Base" IUnknown
+ /// If this is default(IntPtr), this RCW is not initialized yet
+ /// </summary>
+ internal IntPtr BaseIUnknown_UnsafeNoAddRef { get { return m_baseIUnknown.ComPointer_UnsafeNoAddRef; } }
+
+ /// <summary>
+ /// Internal RCW ref count
+ /// NOTE: this is different from ref count on the underlying COM object
+ /// Each time when you marshal a native pointer into a RCW, the RCW gets one AddRef
+ /// Typically you don't need to release as garbage collector will automatically take care of it
+ /// But you can call Marshal.ReleaseComObject if you want explicit release it as early as possible
+ /// </summary>
+ int m_refCount;
+
+ /// <summary>
+ /// Flags of this __ComObject. See ComObjectFlags for the possible value
+ /// </summary>
+ ComObjectFlags m_flags;
+
+ /// <summary>
+ /// A reference to CCW
+ /// This makes sure the lifetime of the CCW and this RCW is tied together in aggregation scenario
+ /// </summary>
+ ComCallableObject m_outer;
+
+ /// <summary>
+ /// Saved identity IUnknown vtbl at creation time
+ /// This is mostly used as a way to diagnose what the underlying COM object really is (if the vtbl
+ /// is still there, of course) in case the COM object was destroyed due to an extra release
+ /// </summary>
+ IntPtr m_savedIUnknownVtbl;
+
+ internal IntPtr SavedIUnknownVtbl { get { return m_savedIUnknownVtbl; } }
+
+ /// <summary>
+ /// Fixed array of cached interfaces that are lock-free
+ /// @TODO: Make this a struct instead of an array object
+ /// NOTE: Managed Debugger depends on field name "m_cachedInterfaces" and field type:SimpleComInterfaceCacheItem
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::GetInterfaceData in debug\dbi\values.cpp
+ /// </summary>
+ internal SimpleComInterfaceCacheItem[] m_cachedInterfaces;
+ internal const int FIXED_CACHE_SIZE = 8;
+
+ /// <summary>
+ /// Growable additional cached interfaces. Access this via AcquireAdditionalCacheExclusive/ForRead
+ /// NOTE: Managed Debugger depends on field name: "m_additionalCachedInterfaces_dontAccessDirectly" and field type: AdditionalComInterfaceCacheContext
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::GetInterfaceData in debug\dbi\values.cpp
+ /// </summary>
+ private AdditionalComInterfaceCacheContext[] m_additionalCachedInterfaces_dontAccessDirectly;
+
+ // if m_additionalCachedInterfaces_dontAccessDirectly == CacheLocked, the cache is being updated and
+ // cannot be read or written from another thread. We do this instead of using a "real" lock, to save space.
+ private static readonly AdditionalComInterfaceCacheContext[] CacheLocked = new AdditionalComInterfaceCacheContext[0];
+
+ /// <summary>
+ /// Finalizer helper object that does cleanup.
+ /// See RCWFinalizer class for more details.
+ /// </summary>
+ private RCWFinalizer m_finalizer;
+
+ #endregion
+
+ #region Debugging Private Variables
+
+#if DEBUG
+ /// <summary>
+ /// Runtime class name of this WinRT __ComObject. This is helpful when you want to understand why
+ /// you get back a __ComObject instead of a strongly-typed RCW
+ /// </summary>
+ internal string m_runtimeClassName;
+
+ /// <summary>
+ /// sequential allocation ID of this COM object
+ /// useful when you are debugging bugs where the program's behavior is deterministic
+ /// </summary>
+ internal uint m_allocationId;
+
+ /// <summary>
+ /// Next allocation ID
+ /// Typed as int to make sure InterlockedExchange.Add is happy
+ /// </summary>
+ internal static int s_nextAllocationId;
+#endif
+
+ /// <summary>
+ /// Return allocation ID in debug build
+ /// INTERNAL only - not in public contract
+ /// </summary>
+ public uint AllocationId
+ {
+ get
+ {
+#if DEBUG
+ return m_allocationId;
+#else
+ return 0xffffffff;
+#endif
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets/sets the outer CCW
+ /// Only used in aggregation scenarios
+ /// We only set the outer CCW during creation of managed object that derives from native
+ /// </summary>
+ internal ComCallableObject Outer
+ {
+ get
+ {
+ return m_outer;
+ }
+ set
+ {
+ m_outer = value;
+ }
+ }
+
+ private AdditionalComInterfaceCacheContext[] AcquireAdditionalCacheExclusive()
+ {
+ AdditionalComInterfaceCacheContext[] additionalCache;
+
+ SpinWait spin = new SpinWait();
+
+ while ((additionalCache = Interlocked.Exchange(ref m_additionalCachedInterfaces_dontAccessDirectly, CacheLocked)) == CacheLocked)
+ spin.SpinOnce();
+
+ return additionalCache;
+ }
+
+ private void ReleaseAdditionalCacheExclusive(AdditionalComInterfaceCacheContext[] contexts)
+ {
+ Debug.Assert(m_additionalCachedInterfaces_dontAccessDirectly == CacheLocked);
+ Volatile.Write(ref m_additionalCachedInterfaces_dontAccessDirectly, contexts);
+ }
+
+ private AdditionalComInterfaceCacheContext[] AcquireAdditionalCacheForRead()
+ {
+ SpinWait spin = new SpinWait();
+ AdditionalComInterfaceCacheContext[] additionalCache;
+
+ while ((additionalCache = Volatile.Read(ref m_additionalCachedInterfaces_dontAccessDirectly)) == CacheLocked)
+ spin.SpinOnce();
+
+ return additionalCache;
+ }
+
+ /// <returns>True is added, false if duplication found</returns>
+ private bool AddToAdditionalCache(ContextCookie contextCookie, McgTypeInfo interfaceTypeInfo, IntPtr pComPtr, object adapter, bool checkDup)
+ {
+ var additionalCache = AcquireAdditionalCacheExclusive();
+
+ bool added = false;
+
+ try
+ {
+ //
+ // Try to find this context
+ //
+ int firstFree = -1;
+
+ if (additionalCache != null)
+ {
+ for (int i = 0; i < additionalCache.Length; i++)
+ {
+ if (additionalCache[i] == null)
+ {
+ if (firstFree == -1)
+ {
+ firstFree = i;
+ }
+ }
+ else if (additionalCache[i].context.ContextCookie.Equals(contextCookie))
+ {
+ return additionalCache[i].Add(interfaceTypeInfo, pComPtr, adapter, checkDup);
+ }
+ }
+ }
+
+ //
+ // This is a new context.
+ //
+ if (firstFree == -1)
+ {
+ //
+ // Need a bigger array
+ //
+ AdditionalComInterfaceCacheContext[] newCache;
+
+ if (additionalCache != null)
+ {
+ newCache = new AdditionalComInterfaceCacheContext[additionalCache.Length + 1];
+ Array.Copy(additionalCache, newCache, additionalCache.Length);
+ firstFree = additionalCache.Length;
+ }
+ else
+ {
+ newCache = new AdditionalComInterfaceCacheContext[1];
+ firstFree = 0;
+ }
+
+ additionalCache = newCache;
+ }
+
+ var newContext = new AdditionalComInterfaceCacheContext(contextCookie);
+ added = newContext.Add(interfaceTypeInfo, pComPtr, adapter, checkDup);
+ Volatile.Write(ref additionalCache[firstFree], newContext);
+ }
+ finally
+ {
+ ReleaseAdditionalCacheExclusive(additionalCache);
+ }
+
+ return added;
+ }
+
+ #region Constructor and Finalizer
+
+ /// <summary>
+ /// Default constructor for RCW 'new' code path
+ /// This only initialize __ComObject to a default, non-usable state
+ /// Please use Attach to initialize the RCW
+ /// Aggregation requires this to be a two-step process in order to access 'this' pointer
+ /// </summary>
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public __ComObject()
+ {
+ __InitToDefaultState();
+ }
+
+ /// <summary>
+ /// Attaching ctor of __ComObject for RCW marshalling code path in order to create a weakly typed RCW
+ /// Initialize and Attach to a existing Com Object
+ /// if pBaseIUnknown is default(IntPtr), does initialization only
+ /// </summary>
+ /// <param name="pBaseIUnknown">Base IUnknown*. Could be Zero</param>
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal __ComObject(IntPtr pBaseIUnknown, McgClassInfo classInfo)
+ {
+ this.__AttachingCtor(pBaseIUnknown, classInfo);
+ }
+
+ /// <summary>
+ /// Attaching ctor used by CreateComObjectInternal. Always used following RhNewObject call therefore the
+ /// default constructor is not ran. Other code should call __Attach/__AttachAndRelease (which assumes
+ /// default constructor has ran)
+ /// </summary>
+ /// <remarks>
+ /// 'int' return value type is a dummy here, it's used because of a limitation on our AddrOf/Call support
+ /// </remarks>
+ internal static int AttachingCtor(__ComObject comObject, IntPtr pBaseIUnknown, McgClassInfo classInfo)
+ {
+ comObject.__AttachingCtor(pBaseIUnknown, classInfo);
+ return 0;
+ }
+
+ /// <summary>
+ /// Attaching ctor used by CreateComObjectInternal. Always used following RhNewObject call therefore the
+ /// default constructor is not ran. Other code should call __Attach/__AttachAndRelease (which assumes
+ /// default constructor has ran)
+ /// </summary>
+ private void __AttachingCtor(IntPtr pBaseIUnknown, McgClassInfo classInfo)
+ {
+ __InitToDefaultState();
+
+ if (pBaseIUnknown != default(IntPtr))
+ __Attach(pBaseIUnknown, classInfo);
+ }
+
+ /// <summary>
+ /// This method updates the flags to represent the right GCPressureRange that is filtered by the MCG by reading the [Windows.Foundation.Metadata.GcPressureAttribute].
+ /// By default all the __ComObject get the default GCPressure.
+ /// This method, also calls the GC.AddMemoryPressure(); with the right mappings for different ranges created in GCMemoryPressureConstants
+ /// </summary>
+ /// <param name="gcMemoryPressureRange"></param>
+ private void AddGCMemoryPressure(GCPressureRange gcMemoryPressureRange)
+ {
+#if ENABLE_WINRT
+ switch (gcMemoryPressureRange)
+ {
+ case GCPressureRange.WinRT_Default:
+ m_flags |= ComObjectFlags.GCPressure_Set;
+ break;
+ case GCPressureRange.WinRT_Low:
+ m_flags |= (ComObjectFlags.GCPressureWinRT_Low | ComObjectFlags.GCPressure_Set);
+ break;
+ case GCPressureRange.WinRT_Medium:
+ m_flags |= (ComObjectFlags.GCPressureWinRT_Medium | ComObjectFlags.GCPressure_Set);
+ break;
+ case GCPressureRange.WinRT_High:
+ m_flags |= (ComObjectFlags.GCPressureWinRT_High | ComObjectFlags.GCPressure_Set);
+ break;
+ default:
+ Debug.Assert(false, "Incorrect GCPressure value");
+ return;
+ }
+
+ Debug.Assert(IsGCPressureSet);
+
+ GC.AddMemoryPressure(GCMemoryPressure);
+#endif
+ }
+
+ /// <summary>
+ /// This method updates the flags to represent the right GCPressureRange that is filtered by the MCG by reading the [Windows.Foundation.Metadata.GcPressureAttribute].
+ /// By default all the __ComObject get the default GCPressure.
+ /// This method, also calls the GC.AddMemoryPressure(); with the right mappings for different ranges created in GCMemoryPressureConstants
+ /// </summary>
+ /// <param name="gcMemoryPressureRange"></param>
+ private void UpdateComMarshalingType(ComMarshalingType marshallingType)
+ {
+ switch (marshallingType)
+ {
+ case ComMarshalingType.Inhibit:
+ m_flags |= ComObjectFlags.MarshalingBehavior_Inhibit;
+ break;
+ case ComMarshalingType.Free:
+ m_flags |= ComObjectFlags.MarshalingBehavior_Free;
+ break;
+ case ComMarshalingType.Standard:
+ m_flags |= ComObjectFlags.MarshalingBehavior_Standard;
+ break;
+ }
+ }
+
+ private ComMarshalingType MarshalingType
+ {
+ get
+ {
+ switch (m_flags & ComObjectFlags.MarshalingBehavior_Mask)
+ {
+ case ComObjectFlags.MarshalingBehavior_Inhibit:
+ return ComMarshalingType.Inhibit;
+
+ case ComObjectFlags.MarshalingBehavior_Free:
+ return ComMarshalingType.Free;
+
+ case ComObjectFlags.MarshalingBehavior_Standard:
+ return ComMarshalingType.Standard;
+
+ default:
+ return ComMarshalingType.Unknown;
+ }
+ }
+ }
+
+ private bool IsGCPressureSet
+ {
+ get
+ {
+ return ((m_flags & ComObjectFlags.GCPressure_Set) != 0);
+ }
+ }
+
+ /// <summary>
+ /// This property creates the mapping between the GCPressure ranges to the actual memory pressure in bytes per RCW.
+ /// The different mapping ranges are defined in GCMemoryPressureConstants
+ /// </summary>
+#if ENABLE_WINRT
+ private int GCMemoryPressure
+ {
+ get
+ {
+ Contract.Assert(IsGCPressureSet, "GCPressureRange.Unknown");
+
+ switch (m_flags & ComObjectFlags.GCPressureWinRT_Mask)
+ {
+ case ComObjectFlags.GCPressureWinRT_Low: return GCMemoryPressureConstants.GC_PRESSURE_WINRT_LOW;
+
+ case ComObjectFlags.GCPressureWinRT_Medium: return GCMemoryPressureConstants.GC_PRESSURE_WINRT_MEDIUM;
+
+ case ComObjectFlags.GCPressureWinRT_High: return GCMemoryPressureConstants.GC_PRESSURE_WINRT_HIGH;
+
+ default: return GCMemoryPressureConstants.GC_PRESSURE_DEFAULT;
+ }
+ }
+ }
+#endif
+
+ /// <summary>
+ /// Initialize RCW to default state
+ /// </summary>
+ private void __InitToDefaultState()
+ {
+ m_flags = ComObjectFlags.None;
+ m_refCount = 1;
+ m_cachedInterfaces = new SimpleComInterfaceCacheItem[FIXED_CACHE_SIZE];
+ for (int i=0; i< FIXED_CACHE_SIZE; i++)
+ {
+ m_cachedInterfaces[i].typeInfo = McgTypeInfo.Null;
+ m_cachedInterfaces[i].typeHandle = default(RuntimeTypeHandle);
+ }
+#if DEBUG
+ m_allocationId = (uint)Interlocked.Add(ref s_nextAllocationId, 1);
+#endif
+ }
+
+ private unsafe IntPtr GetVtbl(IntPtr pUnk)
+ {
+ return new IntPtr((*(void**)pUnk));
+ }
+
+ /// <summary>
+ /// Attach this RCW to a IUnknown *
+ /// NOTE: This function is not CLS-compliant but we'll only call this from C# code.
+ /// The '__' prefix is added to avoid name conflict in sub classes
+ /// </summary>
+ /// <remarks>
+ /// Should only be called from RCW 'new' code path
+ /// </remarks>
+ /// <param name="pBaseIUnknown">IUnknown *. Should never be Zero</param>
+ private void __Attach(IntPtr pBaseIUnknown)
+ {
+ // The cost of doing a look up is nothing compared to the RCW 'new' code path
+ McgClassInfo classInfo = McgModuleManager.GetClassInfoFromTypeHandle(this.GetTypeHandle());
+
+ __Attach(pBaseIUnknown, classInfo);
+ }
+
+ /// <summary>
+ /// Attach this RCW to a IUnknown *
+ /// NOTE: This function is not CLS-compliant but we'll only call this from C# code.
+ /// The '__' prefix is added to avoid name conflict in sub classes
+ /// </summary>
+ /// <param name="pBaseIUnknown">IUnknown *. Should never be Zero</param>
+ private void __Attach(IntPtr pBaseIUnknown, McgClassInfo classInfo)
+ {
+ Debug.Assert(pBaseIUnknown != default(IntPtr));
+
+ //
+ // Read information from McgClassInfo and apply on the RCW
+ //
+ if (!classInfo.IsNull)
+ {
+ GCPressureRange gcPressureRange = classInfo.GCPressureRange;
+ if (gcPressureRange != GCPressureRange.None)
+ AddGCMemoryPressure(gcPressureRange);
+
+ UpdateComMarshalingType(classInfo.MarshalingType);
+ }
+
+ // Save the IUnknown vtbl for debugging in case the object has been incorrectly destroyed
+ m_savedIUnknownVtbl = GetVtbl(pBaseIUnknown);
+
+ m_baseIUnknown.Initialize(pBaseIUnknown, MarshalingType);
+
+ IntPtr pJupiterObj =
+ McgMarshal.ComQueryInterfaceNoThrow(pBaseIUnknown, ref Interop.COM.IID_IJupiterObject);
+
+ if (pJupiterObj != default(IntPtr))
+ {
+ m_flags |= ComObjectFlags.IsJupiterObject;
+
+ m_cachedInterfaces[0].ptr = pJupiterObj;
+ m_cachedInterfaces[0].typeInfo = McgModuleManager.IJupiterObject;
+
+ RCWWalker.OnJupiterRCWCreated(this);
+
+ //
+ // If this COM object is aggregated, don't keep a ref count on IJupiterObject
+ // Otherwise this would keep the CCW alive and therefore keeping this RCW alive, forming
+ // a cycle
+ //
+ if (IsAggregated)
+ McgMarshal.ComRelease(pJupiterObj);
+
+ pJupiterObj = default(IntPtr);
+ }
+
+ // Insert self into global cache, assuming pBaseIUnknown *is* the identity
+ if (!ComObjectCache.Add(pBaseIUnknown, this))
+ {
+ // Add failed - this means somebody else beat us in creating the RCW
+ // We need to make this RCW a duplicate RCW
+ m_flags |= ComObjectFlags.IsDuplicate;
+ }
+
+ if (IsJupiterObject)
+ {
+ RCWWalker.AfterJupiterRCWCreated(this);
+ }
+
+ // Register for finalization of this RCW
+ m_finalizer = new RCWFinalizer(this);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskRCWCreation(
+ (long)InteropExtensions.GetObjectID(this),
+ this.GetTypeHandle().GetRawValue().ToInt64(),
+#if ENABLE_WINRT
+ McgComHelpers.GetRuntimeClassName(this),
+#else
+ null,
+#endif
+ (long)ContextCookie.pCookie,
+ (long)m_flags);
+ }
+
+ /// <summary>
+ /// Attach RCW to the returned interface pointer from the factory and release the extra release
+ /// Potentially we could optimize RCW to "swallow" the extra reference and avoid an extra pair of
+ /// AddRef & Release
+ /// </summary>
+ [CLSCompliant(false)]
+ public void __AttachAndRelease(IntPtr pBaseIUnknown)
+ {
+ try
+ {
+ if (pBaseIUnknown != default(IntPtr))
+ {
+ __Attach(pBaseIUnknown);
+ }
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pBaseIUnknown);
+ }
+ }
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// Whether this __ComObject represents a Jupiter UI object that implements IJupiterObject for life
+ /// time tracking purposes
+ /// </summary>
+ internal bool IsJupiterObject
+ {
+ [GCCallback]
+ get
+ {
+ return (m_flags & ComObjectFlags.IsJupiterObject) != 0;
+ }
+ }
+
+ /// <summary>
+ /// Whether this RCW is used as a baseclass of a managed class. For example, MyButton: Button
+ /// </summary>
+ internal bool ExtendsComObject
+ {
+ get
+ {
+ return (m_flags & ComObjectFlags.ExtendsComObject) != 0;
+ }
+
+ set
+ {
+ //
+ // NOTE: This isn't thread safe, but you are only supposed to call this from the constructor
+ // anyway from MCG inside a ctor
+ //
+ if (value)
+ m_flags |= ComObjectFlags.ExtendsComObject;
+ else
+ m_flags &= (~ComObjectFlags.ExtendsComObject);
+ }
+ }
+
+ /// <summary>
+ /// Whether this RCW/underlying COM object is being aggregated.
+ /// Note that ExtendsComObject is not necessarily the same as aggregation. It just that this is true
+ /// in .NET Native (but not true in desktop CLR, where extends a COM object could mean either
+ /// aggregation or containment, depending on whether the underlying COM objects supports it)
+ /// </summary>
+ internal bool IsAggregated
+ {
+ get
+ {
+ // In .NET Native - extending a COM base object means aggregation
+ return ExtendsComObject;
+ }
+ }
+
+ #endregion
+
+ #region Jupiter Lifetime
+
+ /// <remarks>
+ /// WARNING: This function might be called under a GC callback. Please read the comments in
+ /// GCCallbackAttribute to understand all the implications before you make any changes
+ /// </remarks>
+ [GCCallback]
+ internal unsafe __com_IJupiterObject* GetIJupiterObject_NoAddRef()
+ {
+ Debug.Assert(IsJupiterObject);
+ Debug.Assert(McgModuleManager.IsIJupiterObject(m_cachedInterfaces[0].typeInfo));
+
+ // Slot 0 is always IJupiterObject*
+ return (__com_IJupiterObject*)m_cachedInterfaces[0].ptr.ToPointer();
+ }
+
+ #endregion
+
+ #region Lifetime Management
+
+ /// <summary>
+ /// AddRef on the RCW
+ /// See m_refCount for more details
+ /// </summary>
+ internal int AddRef()
+ {
+ int newRefCount = Threading.Interlocked.Increment(ref m_refCount);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskRCWRefCountInc((long)InteropExtensions.GetObjectID(this), newRefCount);
+
+ return newRefCount;
+ }
+
+ /// <summary>
+ /// Release on the RCW
+ /// See m_refCount for more details
+ /// </summary>
+ internal int Release()
+ {
+ int newRefCount = Threading.Interlocked.Decrement(ref m_refCount);
+
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskRCWRefCountDec((long)InteropExtensions.GetObjectID(this), newRefCount);
+
+ if (newRefCount == 0)
+ {
+ Cleanup();
+ }
+
+ return newRefCount;
+ }
+
+ /// <summary>
+ /// Completely release the RCW by setting m_refCount to 0
+ /// </summary>
+ internal void FinalReleaseSelf()
+ {
+ int prevCount = Threading.Interlocked.Exchange(ref m_refCount, 0);
+
+ if (prevCount > 0)
+ {
+ Cleanup();
+ }
+ }
+
+ /// <summary>
+ /// Returns the current ref count
+ /// </summary>
+ internal int PeekRefCount()
+ {
+ return m_refCount;
+ }
+
+ internal void Cleanup()
+ {
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskRCWFinalization((long)InteropExtensions.GetObjectID(this), this.m_refCount);
+
+ //
+ // If the RCW hasn't been initialized yet or has already cleaned by ReleaseComObject - skip
+ //
+ if (m_baseIUnknown.IsDisposed)
+ {
+ return;
+ }
+
+ //
+ // Remove self from cache if this RCW is not a duplicate RCW
+ // Duplicate RCW is not stored in the cache
+ //
+ if (!IsDuplicate)
+ ComObjectCache.Remove(m_baseIUnknown.ComPointer_UnsafeNoAddRef, this);
+
+ //
+ // Check if we're in the right context for our base IUnknown
+ //
+ ContextEntry baseContext = m_baseIUnknown.ContextEntry;
+ bool inBaseContext = IsFreeThreaded || baseContext.IsCurrent;
+
+ //
+ // We didn't AddRef on cached interfaces if this is an aggregated COM object
+ // So don't release either
+ //
+ if (!IsAggregated)
+ {
+ //
+ // For Jupiter objects, start with index 1 because we need the IJupiterObject* to call
+ // BeforeRelease
+ //
+ int startIndex = 0;
+
+ if (IsJupiterObject)
+ {
+ Debug.Assert(McgModuleManager.IsIJupiterObject(m_cachedInterfaces[0].typeInfo));
+
+ startIndex = 1;
+ }
+
+ //
+ // Disposing simple fixed cache
+ //
+ for (int i = startIndex; i < FIXED_CACHE_SIZE; ++i)
+ {
+ if (!m_cachedInterfaces[i].IsFree)
+ {
+ if (IsJupiterObject)
+ RCWWalker.BeforeRelease(this);
+
+ if (inBaseContext)
+ McgMarshal.ComRelease(m_cachedInterfaces[i].ptr);
+ else
+ baseContext.EnqueueDelayedRelease(m_cachedInterfaces[i].ptr);
+ }
+ }
+
+ //
+ // Disposing additional cache
+ //
+ AdditionalComInterfaceCacheContext[] cacheContext = AcquireAdditionalCacheForRead();
+ if (cacheContext != null)
+ {
+ for (int i = 0; i < cacheContext.Length; i++)
+ {
+ var cache = cacheContext[i];
+ if (cache == null) continue;
+
+ bool isCacheContextCurrent = cache.context.IsCurrent;
+
+ foreach (var cacheEntry in cache.items)
+ {
+ if (IsJupiterObject)
+ RCWWalker.BeforeRelease(this);
+
+ if (isCacheContextCurrent)
+ McgMarshal.ComRelease(cacheEntry.ptr);
+ else
+ cache.context.EnqueueDelayedRelease(cacheEntry.ptr);
+ }
+ }
+ }
+ }
+
+ //
+ // Dispose self
+ //
+ if (IsJupiterObject)
+ RCWWalker.BeforeRelease(this);
+
+ m_baseIUnknown.Dispose(inBaseContext);
+
+ //
+ // Last step
+ // Dispose IJupiterObject*
+ //
+ if (IsJupiterObject && !IsAggregated)
+ {
+ Debug.Assert(McgModuleManager.IsIJupiterObject(m_cachedInterfaces[0].typeInfo));
+
+ RCWWalker.BeforeRelease(this);
+
+ if (inBaseContext)
+ McgMarshal.ComRelease(m_cachedInterfaces[0].ptr);
+ else
+ baseContext.EnqueueDelayedRelease(m_cachedInterfaces[0].ptr);
+ }
+
+ if (IsAggregated)
+ {
+ //
+ // Release the extra AddRef that we did when we create the aggregated CCW
+ // This makes sure the CCW is released is nobody else is holding on it and delay the cleanup
+ // if there is anybody holding on to it until the final release.
+ // For example, Jupiter object's release are posted to the STA thread, which means their
+ // final release won't get called until the STA thread process them, and this would
+ // create a problem if we clean up CCW in RCW finalization and the jupiter object's
+ // final release touch the CCW (such as as Release or QI on ICCW).
+ //
+ m_outer.Release();
+ }
+
+#if ENABLE_WINRT
+ if (IsGCPressureSet)
+ GC.RemoveMemoryPressure(GCMemoryPressure);
+#endif
+ }
+
+ internal void RemoveInterfacesForContext(ContextCookie currentContext)
+ {
+ Debug.Assert(currentContext.IsCurrent && !currentContext.IsDefault);
+
+ //
+ // Only clean up if this object is context bound, which could be either
+ // 1) context-bound and not free threaded
+ // 2) is a jupiter object (which is be free-threaded but considered STA)
+ //
+ if (IsFreeThreaded && !IsJupiterObject)
+ return;
+
+ if (m_baseIUnknown.ContextCookie.Equals(currentContext))
+ {
+ // We cannot use this object any more, as calls to IUnknown will fail.
+ FinalReleaseSelf();
+ }
+ else
+ {
+ // We know that the base IUnknown is not in this context; therefore nothing in the
+ // "simple" cache is in this context. But we may have marshaled interfaces into this context,
+ // and stored them in the "additional" cache. Remove and release those interfaces now.
+ AdditionalComInterfaceCacheContext[] cache = AcquireAdditionalCacheExclusive();
+
+ try
+ {
+ if (cache != null)
+ {
+ for (int i = 0; i < cache.Length; i++)
+ {
+ AdditionalComInterfaceCacheContext cacheContext = cache[i];
+
+ if (cacheContext != null &&
+ cacheContext.context.ContextCookie.Equals(currentContext))
+ {
+ // Remove the context from the cache . Note that there might be
+ // active readers using cache[i] and it's up to the reader to check
+ // if cache[i] is null
+ cache[i] = null;
+
+ if (!IsAggregated)
+ {
+ // Release all interfaces in the context
+ foreach (var cacheEntry in cacheContext.items)
+ {
+ if (IsJupiterObject)
+ RCWWalker.BeforeRelease(this);
+
+ McgMarshal.ComRelease(cacheEntry.ptr);
+ }
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ ReleaseAdditionalCacheExclusive(cache);
+ }
+ }
+ }
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// Whether the RCW is free-threaded
+ /// <summary>
+ internal bool IsFreeThreaded
+ {
+ get
+ {
+ return m_baseIUnknown.IsFreeThreaded;
+ }
+ }
+
+ /// <summary>
+ /// Whether the RCW is a duplicate RCW that is not saved in cache
+ /// </summary>
+ internal bool IsDuplicate
+ {
+ get
+ {
+ return (m_flags & ComObjectFlags.IsDuplicate) != 0;
+ }
+ }
+
+ /// <summary>
+ /// Returns the context cookie where this RCW is created
+ /// </summary>
+ internal ContextCookie ContextCookie
+ {
+ get
+ {
+ return m_baseIUnknown.ContextCookie;
+ }
+ }
+
+ internal ComObjectFlags Flags
+ {
+ get
+ {
+ return m_flags;
+ }
+ }
+
+ #endregion
+
+ #region QueryInterface
+ /// <summary>
+ /// QueryInterface for the specified IID and returns a Non-AddRefed COM interface pointer for the
+ /// the interface you've specified. The returned interface pointer is always callable from current
+ /// context
+ /// NOTE: This version uses McgTypeInfo and is much faster than GUID version
+ /// </summary>
+ /// <returns>A non-AddRef-ed interface pointer that is callable under current context</returns>
+ internal IntPtr QueryInterface_NoAddRef_Internal(
+ McgTypeInfo interfaceTypeInfo,
+ bool cacheOnly,
+ bool throwOnQueryInterfaceFailure)
+ {
+ int hr;
+ IntPtr pComPtr;
+
+ hr = QueryInterface_NoAddRef(interfaceTypeInfo, cacheOnly, out pComPtr);
+
+ if(throwOnQueryInterfaceFailure && pComPtr == default(IntPtr))
+ {
+ throw CreateInvalidCastExceptionForFailedQI(interfaceTypeInfo, hr);
+ }
+
+ return pComPtr;
+ }
+ private int QueryInterface_NoAddRef(
+ McgTypeInfo interfaceTypeInfo,
+ bool cacheOnly,
+ out IntPtr pComPtr)
+ {
+#if !RHTESTCL
+ // Throw if the underlying object is already disposed.
+ if (m_baseIUnknown.IsDisposed)
+ {
+ throw new InvalidComObjectException(SR.Excep_InvalidComObject_NoRCW_Wrapper);
+ }
+#endif
+
+ ContextCookie currentCookie = ContextCookie.Default;
+
+ //
+ // Do we have an existing cached interface in the simple cache that matches
+ //
+
+ // For free-threaded RCWs we don't care about context
+ bool matchContext = m_baseIUnknown.IsFreeThreaded;
+
+ if (!matchContext)
+ {
+ // In most cases WinRT objects are free-threaded, so we'll usually skip the context cookie
+ // check
+ // If we did came here, initialize the currentCookie for use later and check whether the
+ // coookie matches
+ currentCookie = ContextCookie.Current;
+ matchContext = currentCookie.Equals(m_baseIUnknown.ContextCookie);
+ }
+
+ if (matchContext)
+ {
+ //
+ // Search for simple fixed locking cache where context always match
+ // NOTE: it is important to use Length instead of the constant because the compiler would
+ // eliminate the range check (for the most part) when we are using Length
+ //
+ for (int i = 0; i < m_cachedInterfaces.Length; ++i)
+ {
+ //
+ // Check whether this is the same COM interface as cached
+ //
+ // Since Assign() set typeInfo field as last step, we can safely assume that with
+ // typeInfo != null, m_cachedInterfaces[i] is fully initialized
+ //
+ if (m_cachedInterfaces[i].typeInfo.Equals(interfaceTypeInfo))
+ {
+ pComPtr = m_cachedInterfaces[i].ptr;
+ return Interop.COM.S_OK;
+ }
+ }
+ }
+
+ //
+ // No match found in the simple interface cache
+ // Proceed to the slow path only if we want to do the actual cache look-up.
+ //
+ return QueryInterface_NoAddRef_Slow(interfaceTypeInfo, ref currentCookie, cacheOnly, out pComPtr);
+ }
+
+ /// <summary>
+ /// QueryInterface for the specified IID and returns a Non-AddRefed COM interface pointer for the
+ /// the interface you've specified. The returned interface pointer is always callable from current
+ /// context
+ /// NOTE: This version uses RuntimeTypeHandle and is much faster than McgTypeInfo version
+ /// </summary>
+ /// <returns>A non-AddRef-ed interface pointer that is callable under current context</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal IntPtr QueryInterface_NoAddRef_Internal(
+ RuntimeTypeHandle typeHandle)
+ {
+
+#if !RHTESTCL
+ // Throw if the underlying object is already disposed.
+ if (m_baseIUnknown.IsDisposed)
+ {
+ throw new InvalidComObjectException(SR.Excep_InvalidComObject_NoRCW_Wrapper);
+ }
+#endif
+ bool matchContext = m_baseIUnknown.IsFreeThreaded || m_baseIUnknown.ContextCookie.Equals(ContextCookie.Current);
+ if (matchContext)
+ {
+ //
+ // Search for simple fixed locking cache where context always match
+ // NOTE: it is important to use Length instead of the constant because the compiler would
+ // eliminate the range check (for the most part) when we are using Length
+ //
+ int i = 0;
+ do
+ {
+ SimpleComInterfaceCacheItem item = m_cachedInterfaces[i];
+ if (item.typeHandle.Equals(typeHandle))
+ {
+ return item.ptr;
+ }
+ } while(++i < m_cachedInterfaces.Length);
+ }
+
+ IntPtr pComPtr;
+ ContextCookie currentCookie = ContextCookie.Current;
+ //
+ // No match found in the simple interface cache
+ McgTypeInfo typeInfo = McgModuleManager.GetTypeInfoByHandle(typeHandle);
+ // Proceed to the slow path only if we want to do the actual cache look-up.
+ //
+ int hr = QueryInterface_NoAddRef_Slow(typeInfo, ref currentCookie, false, out pComPtr, typeHandle);
+ if (pComPtr == default(IntPtr))
+ {
+ throw CreateInvalidCastExceptionForFailedQI(typeInfo, hr);
+ }
+ return pComPtr;
+ }
+
+ /// <summary>
+ /// Slow path of QueryInterface that does not look at any cache.
+ /// NOTE: MethodImpl(NoInlining) is necessary becauase Bartok is trying to be "helpful" by inlining
+ /// these calls while in other cases it does not inline when it should.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private int QueryInterface_NoAddRef_SlowNoCacheLookup(
+ McgTypeInfo interfaceTypeInfo,
+ ContextCookie currentCookie,
+ out IntPtr pComPtr,
+ RuntimeTypeHandle typeHandle = default(RuntimeTypeHandle))
+ {
+
+#if ENABLE_WINRT
+ // Make sure cookie is initialized
+ Debug.Assert(!currentCookie.IsDefault);
+#endif
+
+ // Before we QI, we need to make sure we always QI in the right context by retrieving
+ // the right IUnknown under current context
+ // NOTE: This IUnknown* is AddRef-ed
+ //
+ if (m_baseIUnknown.IsFreeThreaded || m_baseIUnknown.ContextCookie.Equals(currentCookie))
+ {
+ //
+ // We are in the right context - we can use the IUnknown directly
+ //
+ return QueryInterfaceAndInsertToCache_NoAddRef(
+ m_baseIUnknown.ComPointer_UnsafeNoAddRef,
+ interfaceTypeInfo,
+ currentCookie,
+ out pComPtr,
+ typeHandle);
+ }
+ else
+ {
+ //
+ // Not in the right context - we need to get the right IUnknown through marshalling
+ //
+ IntPtr pIUnknown = default(IntPtr);
+
+ try
+ {
+ pIUnknown = m_baseIUnknown.GetIUnknownForCurrContext(currentCookie);
+
+ return QueryInterfaceAndInsertToCache_NoAddRef(
+ pIUnknown,
+ interfaceTypeInfo,
+ currentCookie,
+ out pComPtr,
+ typeHandle);
+ }
+ finally
+ {
+ if (pIUnknown != default(IntPtr))
+ {
+ McgMarshal.ComRelease(pIUnknown);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Slow path of QueryInterface that looks up additional interface cache and does a QueryInterface if
+ /// no match can be found in the cache
+ /// NOTE: MethodImpl(NoInlining) is necessary becauase Bartok is trying to be "helpful" by inlining
+ /// these calls while in other cases it does not inline when it should.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private int QueryInterface_NoAddRef_Slow(
+ McgTypeInfo interfaceTypeInfo,
+ ref ContextCookie currentCookie,
+ bool cacheOnly,
+ out IntPtr pComPtr,
+ RuntimeTypeHandle typeHandle = default(RuntimeTypeHandle))
+ {
+ // Make sure cookie is initialized
+ if (currentCookie.IsDefault)
+ currentCookie = ContextCookie.Current;
+
+ if (TryGetInterfacePointerFromAdditionalCache_NoAddRef(interfaceTypeInfo, out pComPtr, currentCookie))
+ {
+ //
+ // We've found a match in the additional interface cache
+ //
+ return 0;
+ }
+
+ if (!cacheOnly)
+ {
+ return QueryInterface_NoAddRef_SlowNoCacheLookup(interfaceTypeInfo, currentCookie, out pComPtr, typeHandle);
+ }
+
+ pComPtr = default(IntPtr);
+ return 0;
+ }
+
+ /// <summary>
+ /// Do a QueryInterface and insert the returned pointer to the cache
+ /// Return the QI-ed interface pointer as a result - no need to release
+ /// </summary>
+ private int QueryInterfaceAndInsertToCache_NoAddRef(
+ IntPtr pIUnknown,
+ McgTypeInfo interfaceTypeInfo,
+ ContextCookie currentCookie,
+ out IntPtr pComPtr,
+ RuntimeTypeHandle typeHandle)
+ {
+ int hr = 0;
+ //
+ // QI the underlying COM object and insert into cache
+ // Cache will assume it is already add-refed, so no need to release
+ //
+ Guid intfGuid = interfaceTypeInfo.ItfGuid;
+ pComPtr = McgMarshal.ComQueryInterfaceNoThrow(pIUnknown, ref intfGuid, out hr);
+ IntPtr pTempComPtr = pComPtr;
+
+ try
+ {
+ if (pComPtr == default(IntPtr))
+ {
+ if (InteropEventProvider.IsEnabled())
+ InteropEventProvider.Log.TaskRCWQueryInterfaceFailure(
+ (long)InteropExtensions.GetObjectID(this), (long)ContextCookie.pCookie,
+ intfGuid, hr);
+
+ return hr;
+ }
+
+ //
+ // Cache the result and zero out pComItf if we want to transfer the ref count
+ //
+ InsertIntoCache(interfaceTypeInfo, currentCookie, ref pTempComPtr, false, typeHandle);
+ return 0;
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pTempComPtr);
+ }
+ }
+
+ private InvalidCastException CreateInvalidCastExceptionForFailedQI(McgTypeInfo interfaceTypeInfo, int hr)
+ {
+#if RHTESTCL
+ throw new InvalidCastException();
+#elif ENABLE_WINRT
+ string comObjectDisplayName = this.GetType().TypeHandle.GetDisplayName();
+ string interfaceDisplayName = interfaceTypeInfo.ItfType.GetDisplayName();
+
+ if (comObjectDisplayName == null)
+ {
+ comObjectDisplayName = "System.__ComObject";
+ }
+
+ if (interfaceDisplayName == null)
+ {
+ interfaceDisplayName = SR.MissingMetadataType;
+ }
+
+ if (hr == Interop.COM.E_NOINTERFACE && interfaceTypeInfo.IsIInspectable)
+ {
+ // If this is a WinRT secenario and the failure is E_NOINTERFACE then display the standard
+ // InvalidCastException as most developers are not interested in IID's or HRESULTS
+ return new InvalidCastException(String.Format(SR.InvalidCast_WinRT, comObjectDisplayName, interfaceDisplayName));
+ }
+ else
+ {
+ string errorMessage = ExternalInterop.GetMessage(hr);
+
+ if(errorMessage == null)
+ {
+ errorMessage = String.Format("({0} 0x{1:X})", SR.Excep_FromHResult, hr);
+ }
+ else
+ {
+ errorMessage = String.Format("{0} ({1} 0x{2:X})", errorMessage, SR.Excep_FromHResult, hr);
+ }
+
+ return new InvalidCastException(String.Format(
+ SR.InvalidCast_Com,
+ comObjectDisplayName,
+ interfaceDisplayName,
+ interfaceTypeInfo.ItfGuid.ToString("B").ToUpper(),
+ errorMessage));
+ }
+#else // !ENABLE_WINRT
+ string errorMessage = String.Format("({0} 0x{1:X})", SR.Excep_FromHResult, hr);
+ string interfaceDisplayName = interfaceTypeInfo.ItfType.GetDisplayName();
+
+ return new InvalidCastException(String.Format(
+ SR.InvalidCast_Com,
+ "__ComObject",
+ interfaceDisplayName,
+ interfaceTypeInfo.ItfGuid.ToString("B").ToUpper(),
+ errorMessage));
+
+#endif
+ }
+
+ #endregion
+ #region Cache Management
+
+ /// <summary>
+ /// Insert COM interface pointer into our cache. The cache will NOT do a AddRef and will transfer
+ /// the ref count ownership to itself
+ /// Note: this function might introduce duplicates in the cache, but we don't really care
+ /// </summary>
+ internal void InsertIntoCache(
+ McgTypeInfo interfaceTypeInfo,
+ ContextCookie cookie,
+ ref IntPtr pComPtr,
+ bool checkDup,
+ RuntimeTypeHandle typeHandle = default(RuntimeTypeHandle)
+ )
+ {
+ Debug.Assert(cookie.IsCurrent);
+
+ bool cachedInSimpleCache = false;
+
+ //
+ // Instantiate the dynamic adapter object, if needed
+ //
+ ComInterfaceDynamicAdapter adapter = null;
+
+ if (interfaceTypeInfo.HasDynamicAdapterClass)
+ {
+ adapter = (ComInterfaceDynamicAdapter)InteropExtensions.RuntimeNewObject(interfaceTypeInfo.DynamicAdapterClassType);
+ adapter.Initialize(this);
+ }
+ else if (m_baseIUnknown.IsFreeThreaded || cookie.Equals(m_baseIUnknown.ContextCookie))
+ {
+ //
+ // Search for a match, or free slots in interface cache only when the context matches
+ //
+ for (int i = 0; i < FIXED_CACHE_SIZE; ++i)
+ {
+ IntPtr ptr = m_cachedInterfaces[i].ptr;
+
+ if (ptr == default(IntPtr)) // empty slot
+ {
+ if (m_cachedInterfaces[i].Assign(interfaceTypeInfo, pComPtr, typeHandle))
+ {
+ cachedInSimpleCache = true;
+ break;
+ }
+ }
+ else if (checkDup)
+ {
+ if ((ptr == pComPtr) && (m_cachedInterfaces[i].typeInfo == interfaceTypeInfo)) // found exact match, no need to store
+ {
+ return; // If duplicate found, skipping clear pComPtr and RCWWalker.AfterAddRef
+ }
+ }
+ }
+ }
+
+ if (!cachedInSimpleCache)
+ {
+ if (!AddToAdditionalCache(cookie, interfaceTypeInfo, pComPtr, adapter, checkDup))
+ {
+ return; // If duplicate found, skipping clear pComPtr and RCWWalker.AfterAddRef
+ }
+ }
+
+ if (!IsAggregated)
+ {
+ //
+ // "Swallow" the ref count and transfer it into our cache if this is not aggregation
+ // Optionally call out to jupiter to tell them we've "done an AddRef"
+ //
+ pComPtr = default(IntPtr);
+
+ if (IsJupiterObject)
+ RCWWalker.AfterAddRef(this);
+ }
+ else
+ {
+ //
+ // Otherwise, this COM object is aggregated
+ // We can't add ref on the interface pointer because this would keep the CCW
+ // alive which would keep this RCW alive, forming a cycle.
+ // NOTE: Since in aggregation it is invalid to maintain a tear-off's
+ // lifetime separately (due to the outer IUnknown delegation), we can safely
+ // keep this interface pointer cached without a AddRef
+ //
+ }
+ }
+
+ /// <summary>
+ /// Look up additional interface cache that are context-aware, growing cache which requires locking
+ /// </summary>
+ private bool TryGetInterfacePointerFromAdditionalCache_NoAddRef(McgTypeInfo interfaceTypeInfo, out IntPtr pComPtr, ContextCookie currentCookie)
+ {
+ //
+ // Search for additional growable interface cache
+ //
+ AdditionalComInterfaceCacheContext[] cacheContext = AcquireAdditionalCacheForRead();
+ if (cacheContext != null)
+ {
+ for (int i = 0; i < cacheContext.Length; i++)
+ {
+ var cache = cacheContext[i];
+ if (cache == null) continue;
+
+ if (cache.context.ContextCookie.Equals(currentCookie))
+ {
+ foreach (var item in cache.items)
+ {
+ if (item.typeInfo == interfaceTypeInfo)
+ {
+ pComPtr = item.ptr;
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ pComPtr = default(IntPtr);
+
+ return false;
+ }
+
+ #endregion
+
+ #region ICastable implementation for weakly typed RCWs
+
+ /// <summary>
+ /// ================================================================================================
+ /// COMMENTS from ICastable.IsInstanceOfInterface
+ ///
+ /// This is called if casting this object to the given interface type would otherwise fail. Casting
+ /// here means the IL isinst and castclass instructions in the case where they are given an interface
+ /// type as the target type.
+ ///
+ /// A return value of true indicates the cast is valid.
+ ///
+ /// If false is returned when this is called as part of a castclass then the usual InvalidCastException
+ /// will be thrown unless an alternate exception is assigned to the castError output parameter. This
+ /// parameter is ignored on successful casts or during the evaluation of an isinst (which returns null
+ /// rather than throwing on error).
+ ///
+ /// No exception should be thrown from this method (it will cause unpredictable effects, including the
+ /// possibility of an immediate failfast).
+ ///
+ /// The results of this call are not cached, so it is advisable to provide a performant implementation.
+ ///
+ /// The results of this call should be invariant for the same class, interface type pair. That is
+ /// because this is the only guard placed before an interface invocation at runtime. If a type decides
+ /// it no longer wants to implement a given interface it has no way to synchronize with callers that
+ /// have already cached this relationship and can invoke directly via the interface pointer.
+ /// ================================================================================================
+ ///
+ /// If this function is called, this means we are being casted with a non-supported interface.
+ /// This means:
+ /// 1. The object is a weakly-typed RCW __ComObject
+ /// 2. The object is a strongly-typed RCW __ComObject derived type, but might support more interface
+ /// than what its metadata has specified
+ ///
+ /// In this case, we perform a QueryInterface to see if we really support that interface
+ /// </summary>
+ /// <param name="interfaceType">The interface being casted to</param>
+ /// <param name="castError">More specific cast failure other than the default InvalidCastException
+ /// prepared by the runtime</param>
+ /// <returns>True means it is supported. False no. </returns>
+ bool ICastable.IsInstanceOfInterface(RuntimeTypeHandle interfaceType, out Exception castError)
+ {
+ castError = null;
+
+ try
+ {
+ //
+ // Look up the interface type and get back the corresponding McgTypeInfo
+ //
+ McgTypeInfo secondTypeInfo;
+ McgTypeInfo mcgTypeInfo = McgModuleManager.GetTypeInfoFromTypeHandle(interfaceType, out secondTypeInfo);
+
+ if (mcgTypeInfo.IsNull)
+ {
+ // If we can't find one, it means the type doesn't participate in any interop and we are not
+ // interested in it
+ return false;
+ }
+
+ if (!secondTypeInfo.IsNull)
+ {
+ // This is typeInfo for ICollection<KeyValuePair<>> which could be
+ // Dictionary or List<KeyValuePair<>>
+ return TryGetMcgTypeInfoForICollection(mcgTypeInfo, secondTypeInfo, out mcgTypeInfo);
+ }
+
+ //
+ // QI for that interfce
+ //
+ IntPtr pComPtr;
+ int hr = QueryInterface_NoAddRef(mcgTypeInfo, /* cacheOnly= */ false, out pComPtr);
+
+ if (pComPtr != default(IntPtr))
+ return true;
+
+ //
+ // Is there a dynamic adapter for the interface?
+ //
+ if (mcgTypeInfo.HasDynamicAdapterClass && GetDynamicAdapter(mcgTypeInfo) != null)
+ return true;
+
+ castError = CreateInvalidCastExceptionForFailedQI(mcgTypeInfo, hr);
+ return false;
+ }
+ catch (Exception ex)
+ {
+ // We are not allowed to leak exception out from here
+ // Instead, set castError to the exception being thrown
+ castError = ex;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ ///
+ /// ================================================================================================
+ /// COMMENTS from ICastable.GetImplType
+ ///
+ /// This is called as part of the interface dispatch mechanism when the dispatcher logic cannot find
+ /// the given interface type in the interface map of this object.
+ ///
+ /// It allows the implementor to return an alternate class type which does implement the interface. The
+ /// interface lookup shall be performed again on this type (failure to find the interface this time
+ /// resulting in a fail fast) and the corresponding implemented method on that class called instead.
+ ///
+ /// Naturally, since the call is dispatched to a method on a class which does not match the type of the
+ /// this pointer, extreme care must be taken in the implementation of the interface methods of this
+ /// surrogate type.
+ ///
+ /// No exception should be thrown from this method (it will cause unpredictable effects, including the
+ /// possibility of an immediate failfast).
+ ///
+ /// There is no error path defined here. By construction all interface dispatches will already have
+ /// been verified via the castclass/isinst mechanism (and thus a call to IsInstanceOfInterface above)
+ /// so this method is expected to succeed in all cases. The contract for interface dispatch does not
+ /// include any errors from the infrastructure, of which this is a part.
+ ///
+ /// The results of this lookup are cached so computation of the result is not as perf-sensitive as
+ /// IsInstanceOfInterface.
+ /// ==========================================================================================
+ ///
+ /// If we are here, it means we've previously succeeded in ICastable.IsInstanceOfInterface, and
+ /// we need to return the correct stub class that implement the interface so that RH knows how to
+ /// dispatch the call, for example:
+ ///
+ /// class IFoo_StubClass: __ComObject, IFoo
+ /// {
+ /// public IFoo.Bar()
+ /// {
+ /// // Interop code for IFoo.Bar goes here
+ /// }
+ /// }
+ ///
+ /// Note that the stub class in this case needs to be compatible in terms of object layout with
+ /// 'this', and the most obvious way to get that is to derive from __ComObject
+ /// </summary>
+ /// <param name="interfaceType">The interface type we need to dispatch</param>
+ /// <returns>The stub class where RH dispatch interface calls to</returns>
+ RuntimeTypeHandle ICastable.GetImplType(RuntimeTypeHandle interfaceType)
+ {
+ McgTypeInfo secondTypeInfo;
+ McgTypeInfo mcgTypeInfo = McgModuleManager.GetTypeInfoFromTypeHandle(interfaceType, out secondTypeInfo);
+ if (mcgTypeInfo.IsNull)
+ {
+#if !RHTESTCL
+ Environment.FailFast(McgTypeHelpers.GetDiagnosticMessageForMissingType(interfaceType));
+#else
+ Environment.FailFast("McgTypeInfo is null in __ComObject.GetImplType!");
+#endif
+ }
+
+ if (!secondTypeInfo.IsNull)
+ {
+ McgTypeInfo defaultTypeInfo = mcgTypeInfo;
+ if (!TryGetMcgTypeInfoForICollection(mcgTypeInfo, secondTypeInfo, out mcgTypeInfo))
+ {
+ // if _ComObject doesn't support QI for defaultTypeInfo and secondTypeInfo,
+ // return defaultTypeInfo, so later,we will have invalidcast exception
+ mcgTypeInfo = defaultTypeInfo;
+ }
+ }
+
+ if (mcgTypeInfo.DispatchClassType.IsNull() ||
+ mcgTypeInfo.DispatchClassType.Equals(McgModule.s_DependencyReductionTypeRemovedTypeHandle))
+ {
+#if !RHTESTCL
+ // RCW is discarded for this mcgTypeInfo
+ Environment.FailFast(McgTypeHelpers.GetDiagnosticMessageForMissingType(mcgTypeInfo.InterfaceType));
+#else
+ Environment.FailFast("RCW is discarded.");
+#endif
+ }
+ return mcgTypeInfo.DispatchClassType;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// This method resolves the typeInfo for ICollection<KeyValuePair<>> which can't be
+ /// determined statically.
+ /// </summary>
+ /// <param name="firstTypeInfo">McgTypeInfo for the Dictionary\ReadOnlyDictionary.</param>
+ /// <param name="secondTypeInfo">McgTypeInfo for the List or ReadOnlyList.</param>
+ /// <param name="resolvedTypeInfo">McgTypeInfo for ICollection<KeyValuePair<>> determined at runtime.</param>
+ /// <returns>Success or failure of resolution.</returns>
+ private bool TryGetMcgTypeInfoForICollection(McgTypeInfo firstTypeInfo, McgTypeInfo secondaryTypeInfo, out McgTypeInfo resolvedTypeInfo)
+ {
+ IntPtr interfacePtr;
+
+ // In case __ComObject can be type casted to both IDictionary and IList<KeyValuePair<>>
+ // we give IDictionary the preference. firstTypeInfo point to the McgTypeInfo for IDictionary.
+
+ // We first check in the cache for both.
+ // We then check for IDictionary first and IList later.
+
+ // In case none of them succeeds we return false with resolvedTypeInfo set to null.
+ resolvedTypeInfo = McgTypeInfo.Null;
+
+ // We first check the cache for the two interfaces if this does not succeed we then actually
+ // go to the query interface check.
+ interfacePtr = QueryInterface_NoAddRef_Internal(firstTypeInfo, /* cacheOnly= */ true, /* throwOnQueryInterfaceFailure= */ false);
+
+ if (interfacePtr != default(IntPtr))
+ {
+ resolvedTypeInfo = firstTypeInfo;
+ return true;
+ }
+
+ interfacePtr = QueryInterface_NoAddRef_Internal(secondaryTypeInfo, /* cacheOnly= */ true, /* throwOnQueryInterfaceFailure= */ false);
+
+ if (interfacePtr != default(IntPtr))
+ {
+ resolvedTypeInfo = secondaryTypeInfo;
+ return true;
+ }
+
+ ContextCookie currentCookie = ContextCookie.Current;
+ QueryInterface_NoAddRef_SlowNoCacheLookup(firstTypeInfo, currentCookie, out interfacePtr);
+
+ if (interfacePtr != default(IntPtr))
+ {
+ resolvedTypeInfo = firstTypeInfo;
+ return true;
+ }
+
+ if (secondaryTypeInfo.IsNull)
+ return false;
+
+ QueryInterface_NoAddRef_SlowNoCacheLookup(secondaryTypeInfo, currentCookie, out interfacePtr);
+
+ if (interfacePtr != default(IntPtr))
+ {
+ resolvedTypeInfo = secondaryTypeInfo;
+ return true;
+ }
+
+ return false;
+ }
+
+ //
+ // Get the dynamic adapter object associated with this COM object for the given interface.
+ //
+ internal unsafe object GetDynamicAdapter(McgTypeInfo requestedType)
+ {
+ Debug.Assert(requestedType.HasDynamicAdapterClass);
+
+ //
+ // Fast path: make a first pass through the cache to find an exact match we've already QI'd for.
+ //
+ AdditionalComInterfaceCacheContext[] cacheContext = AcquireAdditionalCacheForRead();
+ if (cacheContext != null)
+ {
+ for (int i = 0; i < cacheContext.Length; i++)
+ {
+ var cache = cacheContext[i];
+ if (cache == null) continue;
+
+ foreach (AdditionalComInterfaceCacheItem existingType in cache.items)
+ {
+ if (existingType.typeInfo == requestedType)
+ return existingType.dynamicAdapter;
+ }
+ }
+ }
+
+ //
+ // We may have already QI'd for an interface of a *compatible* type. For example, we may be asking for
+ // IEnumerable, and we know the object supports IEnumerable<Foo>. Or we may be asking for
+ // IReadOnlyList<object>, but the object supports IReadOnlyList<Foo>. So we search for any existing
+ // adapter that implements the requested interface.
+ //
+ if (cacheContext != null)
+ {
+ for (int i = 0; i < cacheContext.Length; i++)
+ {
+ var cache = cacheContext[i];
+ if (cache == null) continue;
+
+ foreach (AdditionalComInterfaceCacheItem existingType in cache.items)
+ {
+ if (existingType.dynamicAdapter != null && InteropExtensions.IsInstanceOfInterface(existingType.dynamicAdapter, requestedType.InterfaceType))
+ return existingType.dynamicAdapter;
+ }
+ }
+ }
+
+ //
+ // We may not have QI'd for this interface yet. Do so now, in case the object directly supports
+ // the requested interface. If we find it, call ourselves again so our fast path will pick it up.
+ //
+ if (QueryInterface_NoAddRef_Internal(requestedType, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false) != default(IntPtr))
+ return GetDynamicAdapter(requestedType);
+
+ //
+ // We may have already QI'd for an interface of a compatible type, but not a type with a dynamic adapter.
+ // For example, we've QI'd for IList<T>, and we're now asking for IEnumerable. Every IList<T> is an IEnumerable<T>,
+ // which is an IEnumerable - but we haven't constructed an adapter for IEnumerable<T> yet.
+ //
+ for (int i = 0; i < m_cachedInterfaces.Length; ++i)
+ {
+ if (!m_cachedInterfaces[i].typeInfo.IsNull)
+ {
+ object adapter = FindDynamicAdapterForInterface(requestedType.InterfaceType, m_cachedInterfaces[i].typeInfo.ItfType);
+
+ if (adapter != null)
+ return adapter;
+ }
+ }
+
+ if (cacheContext != null)
+ {
+ for (int i = 0; i < cacheContext.Length; i++)
+ {
+ var cache = cacheContext[i];
+ if (cache == null) continue;
+
+ foreach (AdditionalComInterfaceCacheItem existingType in cache.items)
+ {
+ // in a race, it's possible someone else already set up an adapter.
+ if (existingType.dynamicAdapter != null && InteropExtensions.IsInstanceOfInterface(existingType.dynamicAdapter, requestedType.InterfaceType))
+ return existingType.dynamicAdapter;
+
+ object adapter = FindDynamicAdapterForInterface(requestedType.InterfaceType, existingType.typeInfo.InterfaceType);
+
+ if (adapter != null)
+ return adapter;
+ }
+ }
+ }
+
+ //
+ // If this is a strongly-typed RCW, we may statically know of an interface we support, that we haven't QI'd for
+ // yet, but that is compatible with the requested type.
+ //
+ if (!McgMarshal.IsOfType(this, typeof(__ComObject).TypeHandle))
+ {
+ object adapter = FindDynamicAdapterForInterface(requestedType.InterfaceType, typeof(__ComObject).TypeHandle);
+
+ if (adapter != null)
+ return adapter;
+ }
+
+ //
+ // At this point we *could* just go ahead and QI for every known type that is assignable to the requested type.
+ // But that is potentially hundreds of types, and we may be making these calls across process boundaries, which
+ // would be very expensive. At any rate, the CLR doesn't do this, so we'll maintain compatibility and simply fail
+ // here.
+ //
+ return null;
+ }
+
+ private object FindDynamicAdapterForInterface(RuntimeTypeHandle requestedType, RuntimeTypeHandle existingType)
+ {
+ if (!existingType.IsNull() && // IJupiterObject has a null InterfaceType
+ InteropExtensions.AreTypesAssignable(existingType, requestedType))
+ {
+ //
+ // Now we need to find a type that is assignable *from* the compatible type, and *to* the requested
+ // type. So if we just found IList<T>, and are asking for IEnumerable, we need to find IEnumerable<T>.
+ // We can't directly construct a RuntimeTypeHandle for IEnumerable<T> without reflection, so we have to
+ // go search McgModuleManager for a suitable type.
+ //
+ McgTypeInfo intermediateType = McgModuleManager.FindTypeInfo(
+ type => type.HasDynamicAdapterClass &&
+ InteropExtensions.AreTypesAssignable(existingType, type.InterfaceType) &&
+ InteropExtensions.AreTypesAssignable(type.InterfaceType, requestedType) &&
+ QueryInterface_NoAddRef_Internal(type, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false) != default(IntPtr));
+
+ if (!intermediateType.IsNull)
+ return GetDynamicAdapter(intermediateType);
+ }
+
+ return null;
+ }
+
+#if ENABLE_WINRT
+
+ /// <summary>
+ /// Try to find matching Property in cached interface
+ /// </summary>
+ /// <param name="matchingDelegate"></param>
+ /// <returns>if it cann't find it, return null</returns>
+ internal PropertyInfo GetMatchingProperty(Func<PropertyInfo, bool> matchingDelegate)
+ {
+ // first check Simple ComInterface Cache
+ foreach (SimpleComInterfaceCacheItem item in m_cachedInterfaces)
+ {
+ McgTypeInfo typeInfo = item.typeInfo;
+ if (!typeInfo.IsNull)
+ {
+ Type interfaceType = InteropExtensions.GetTypeFromHandle(typeInfo.ItfType);
+ foreach (PropertyInfo propertyInfo in interfaceType.GetRuntimeProperties())
+ {
+ if (matchingDelegate(propertyInfo))
+ return propertyInfo;
+ }
+ }
+ }
+
+ // Check additional interface cache
+ AdditionalComInterfaceCacheContext[] cacheContext = AcquireAdditionalCacheForRead();
+ if (cacheContext != null)
+ {
+ for (int i = 0; i < cacheContext.Length; i++)
+ {
+ var item = cacheContext[i];
+ if (item != null)
+ {
+ Type interfaceType = InteropExtensions.GetTypeFromHandle(item.items.GetTypeHandle());
+ foreach (var propertyInfo in interfaceType.GetRuntimeProperties())
+ {
+ if (matchingDelegate(propertyInfo))
+ return propertyInfo;
+ }
+ }
+ }
+ }
+
+ // doesn't find anything
+ return null;
+ }
+#endif
+
+ /// <summary>
+ /// This method implements the ToString() method for weakly typed RCWs
+ /// 1. Compute whether the __ComObject supports IStringable and cache the value.
+ /// 2. If the __ComObject supports IStringable call ToString() of that method.
+ /// 3. else call default Object.ToString() method.
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+#if ENABLE_WINRT
+ string toString;
+
+ if (IStringableHelper.TryGetIStringableToString(this, out toString))
+ {
+ return toString;
+ }
+ else
+#endif
+ {
+ return base.ToString();
+ }
+ }
+ }
+
+}
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Represents COM context cookie
+ /// NOTE: The cookie could become INVALID if the context/apartment is gone and reused for another context!!!
+ /// It is only safe if you use it with ContextEntry which can make sure the context cookie can always
+ /// be valid
+ /// </summary>
+ internal struct ContextCookie
+ {
+ internal IntPtr pCookie;
+
+ private ContextCookie(IntPtr _pCookie)
+ {
+ pCookie = _pCookie;
+ }
+
+ /// <summary>
+ /// Returns the default context cookie
+ /// </summary>
+ static internal ContextCookie Default
+ {
+ get
+ {
+ return new ContextCookie(default(IntPtr));
+ }
+ }
+
+ /// <summary>
+ /// Whether this is a default context cookie
+ /// </summary>
+ internal bool IsDefault
+ {
+ get
+ {
+ return pCookie == default(IntPtr);
+ }
+ }
+
+ /// <summary>
+ /// Whether the two context cookie are the same
+ /// </summary>
+ internal bool Equals(ContextCookie cookie)
+ {
+ return (this.pCookie == cookie.pCookie);
+ }
+
+ /// <summary>
+ /// Whether this context cookie matches the current context
+ /// NOTE: This does a P/Invoke so try to avoid this whenever possible
+ /// </summary>
+ internal bool IsCurrent
+ {
+ get
+ {
+ return (Current.pCookie == this.pCookie);
+ }
+ }
+
+ /// <summary>
+ /// Retrieve ContextCookie of current apartment
+ /// NOTE: This does a P/Invoke so try to cache this whenever possible
+ /// </summary>
+ /// <returns>The current context cookie</returns>
+ static internal ContextCookie Current
+ {
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ get
+ {
+#if ENABLE_WINRT
+
+ IntPtr pCookie;
+ int hr = ExternalInterop.CoGetContextToken(out pCookie);
+ if (hr < 0)
+ {
+ Debug.Assert(false, "CoGetContextToken failed");
+ pCookie = default(IntPtr);
+ }
+ return new ContextCookie(pCookie);
+
+#else
+ return ContextCookie.Default;
+#endif
+ }
+ }
+ }
+
+ /// <summary>
+ /// Comparer for ContextCookie
+ /// </summary>
+ internal class ContextCookieComparer : IEqualityComparer<ContextCookie>
+ {
+ bool IEqualityComparer<ContextCookie>.Equals(ContextCookie x, ContextCookie y)
+ {
+ return x.Equals(y);
+ }
+
+ int IEqualityComparer<ContextCookie>.GetHashCode(ContextCookie obj)
+ {
+ return obj.pCookie.GetHashCode();
+ }
+ }
+
+ /// <summary>
+ /// Marshaling type of a ContextBoundInterfacePointer
+ /// </summary>
+ internal enum ComMarshalingType
+ {
+ /// <summary>
+ /// It has not yet been computed or the MarshalingBehavior[MarshalingType.InvalidMarshaling] or we found an unknown value in the attribute itself.
+ /// </summary>
+ Unknown,
+
+ /// <summary>
+ /// This COM object does not support marshalling and says so in its WinRT metadata
+ /// We should not attempt to do any marshalling and should fail immediately
+ /// </summary>
+ Inhibit,
+
+ /// <summary>
+ /// A free-threaded COM object
+ /// This is usually indicated by
+ /// 1. This object aggregates FTM
+ /// 2. This object implements IAgileObject
+ /// 3. This object says so in WinRT metadata
+ /// </summary>
+ Free,
+
+ /// <summary>
+ /// A normal COM interface pointer that supports marshalling
+ /// NOTE: This doesn't mean the actual underlying object supports marshalling - it only means
+ /// we ATTEMPT to do such marshalling
+ /// </summary>
+ Standard
+ }
+
+ /// <summary>
+ /// A interface pointer that is COM-context-aware and will always return you the correct marshalled
+ /// interface pointer for the current context
+ /// </summary>
+ internal struct ContextBoundInterfacePointer
+ {
+ /// <summary>
+ /// The COM interface pointer
+ /// </summary>
+ private IntPtr m_pComPtr;
+
+ /// <summary>
+ /// The ContextEntry where this COM interface pointer is obtained
+ /// NOTE: Unlike CLR, this is always non-null
+ /// </summary>
+ private ContextEntry m_context;
+
+ /// <summary>
+ /// Stream that contains a marshalled COM pointer that can be unmarshalled to any context
+ /// Once we've created a stream, we cache it here. A thread that needs to do marshaling will first
+ /// "check out" this stream by Interlocked.Exchange'ing a null into this field, and using the previous
+ /// value. In a race, another thread might see a null stream, in which case it will just create a new
+ /// one. This should be rare.
+ /// </summary>
+ private IntPtr m_pCachedStream;
+
+ /// <summary>
+ /// The threading type of this ContextBoundInterfacePointer
+ /// </summary>
+ private ComMarshalingType m_type;
+
+ /// <summary>
+ /// Initialize a context bound interface pointer with current context cookie
+ /// </summary>
+ /// <param name="currentCookie">Passed in for better perf</param>
+ internal void Initialize(IntPtr pComPtr, ComMarshalingType type)
+ {
+ m_pComPtr = pComPtr;
+ McgMarshal.ComAddRef(m_pComPtr);
+
+ // Initialize current context
+ // NOTE: Unlike CLR, we always initialize the current context cookie
+ // This is done to avoid having another m_contextCookie field
+ m_context = ContextEntry.GetCurrentContext(ContextCookie.Current);
+
+ // This is a good opportunity to clean up any interfaces that need released in this context
+ m_context.PerformDelayedCleanup();
+
+ if (type == ComMarshalingType.Unknown)
+ {
+ m_type = GetComMarshalingBehaviorAtRuntime();
+ }
+ else
+ {
+ m_type = type;
+ }
+
+ Contract.Assert(!IsUnknown, "m_type can't be null");
+ }
+
+ /// <summary>
+ /// Returns a AddRefed COM pointer - you'll need to release it by calling McgMarshal.ComRelease
+ /// </summary>
+ internal IntPtr GetIUnknownForCurrContext(ContextCookie currentCookie)
+ {
+ Debug.Assert(currentCookie.IsCurrent);
+
+ // Matching context or FreeThreaded should already be handled
+ Debug.Assert(!(m_context.ContextCookie.Equals(currentCookie) || IsFreeThreaded));
+
+#if !RHTESTCL
+ if (IsInhibit)
+ {
+ throw new System.InvalidCastException(SR.Arg_NoMarshalCreatedObjectUsedOutOfTreadContext);
+ }
+#endif
+ return GetAddRefedComPointerForCurrentContext();
+ }
+
+ /// <summary>
+ /// Returns the "raw" interface pointer without a AddRef
+ /// It can only be used as a comparison, or under the context where this context bound interface
+ /// pointer is obtained
+ /// </summary>
+ internal IntPtr ComPointer_UnsafeNoAddRef
+ {
+ get
+ {
+ return m_pComPtr;
+ }
+ }
+
+ /// <summary>
+ /// Returns the ContextCookie where this context bound interface pointer is obtained *INITIALLY*
+ /// </summary>
+ internal ContextCookie ContextCookie
+ {
+ get
+ {
+ return m_context.ContextCookie;
+ }
+ }
+
+ /// <summary>
+ /// Returns the ContextEntry where this context bound interface pointer is obtained *INITIALLY*
+ /// </summary>
+ internal ContextEntry ContextEntry
+ {
+ get
+ {
+ return m_context;
+ }
+ }
+
+ /// <summary>
+ /// This method get's the ComMarshalingType by checking the IntPtr at runtime.
+ /// </summary>
+ /// <returns></returns>
+ private ComMarshalingType GetComMarshalingBehaviorAtRuntime()
+ {
+ Contract.Assert(IsUnknown, "ComMarshalingType is not ComMarshalingType.Uknown");
+
+ if (McgComHelpers.IsFreeThreaded(m_pComPtr))
+ {
+ // The object is free threaded and hence.
+ return ComMarshalingType.Free;
+ }
+
+ IntPtr pINoMarshal = McgMarshal.ComQueryInterfaceNoThrow(m_pComPtr, ref Interop.COM.IID_INoMarshal);
+
+ if (pINoMarshal != default(IntPtr))
+ {
+ McgMarshal.ComSafeRelease(m_pComPtr);
+ pINoMarshal = default(IntPtr);
+
+ // This object implements INoMarshal and hence the marshaling across context is inhibited.
+ return ComMarshalingType.Inhibit;
+ }
+
+ return ComMarshalingType.Standard;
+ }
+
+ /// <summary>
+ /// Whether this interface pointer represents a free-threaded COM object
+ /// </summary>
+ internal bool IsFreeThreaded
+ {
+ get
+ {
+ return m_type == ComMarshalingType.Free;
+ }
+ }
+
+ /// <summary>
+ /// Whether this interface pointer represents a COM object which can't be marshaled to other contexts.
+ /// </summary>
+ internal bool IsInhibit
+ {
+ get
+ {
+ return m_type == ComMarshalingType.Inhibit;
+ }
+ }
+
+ /// <summary>
+ /// Whether this interface pointer represents a COM object that supports marshalling
+ /// </summary>
+ internal bool IsStandard
+ {
+ get
+ {
+ return m_type == ComMarshalingType.Standard;
+ }
+ }
+
+ /// <summary>
+ /// Whether this interface pointer represents a COM object that supports marshalling
+ /// </summary>
+ internal bool IsUnknown
+ {
+ get
+ {
+ return m_type == ComMarshalingType.Unknown;
+ }
+ }
+
+ // Used to indicate that there is a marshaled stream, but it's currently in use by some thread.
+ const int StreamInUse = 1;
+
+ /// <summary>
+ /// Marshales the IUnknown* into a stream and then unmarshal it back to the current context
+ /// </summary>
+ /// <returns>A AddRef-ed interface pointer that can be used under current context</returns>
+ private IntPtr GetAddRefedComPointerForCurrentContext()
+ {
+ Contract.Assert(IsStandard, "ComMarshalingType is not standard");
+ bool failedBefore = false;
+ IntPtr pStream = IntPtr.Zero;
+
+ //
+ // Acquire the cached stream.
+ //
+ SpinWait spin = new SpinWait();
+
+ while ((pStream = Interlocked.Exchange(ref m_pCachedStream, (IntPtr)StreamInUse)) == (IntPtr)StreamInUse)
+ spin.SpinOnce();
+
+ //
+ // Keep retrying until we encounter a critical failure, fail twice, or succeed
+ //
+ while (true)
+ {
+ try
+ {
+ //
+ // If we have a cached stream, use it. Otherwise, try to marshal this com pointer
+ // to a stream.
+ //
+ if (pStream == IntPtr.Zero)
+ {
+ pStream = MarshalComPointerToStream();
+ }
+
+ if (pStream == IntPtr.Zero)
+ {
+ //
+ // NOTE: This is different than CLR
+ // In CLR we hand out the raw IUnknown pointer and hope it works (and it usually does,
+ // until it does not).
+ // In ProjectN we try to do the right thing and fail here
+ //
+ throw new InvalidCastException();
+ }
+ else
+ {
+ //
+ // First, reset the stream (ignoring any errors).
+ //
+ McgComHelpers.SeekStreamToBeginning(pStream);
+
+ //
+ // Marshalling into stream has succeeded
+ // Now try unmarshal the stream into a pointer of current context
+ //
+ IntPtr pUnknown;
+ int hr = ExternalInterop.CoUnmarshalInterface(pStream, ref Interop.COM.IID_IUnknown, out pUnknown);
+
+ if (hr < 0)
+ {
+ //
+ // Unmarshalled failed and the stream is now no good.
+ //
+ McgComHelpers.SafeReleaseStream(pStream);
+ pStream = IntPtr.Zero;
+
+ // If we've already failed before, stop retrying and fail immediately
+ if (failedBefore)
+ {
+ throw new InvalidCastException();
+ }
+
+ // Remember we've already failed before and avoid infinite loop
+ failedBefore = true;
+ }
+ else
+ {
+ return pUnknown;
+ }
+ }
+ }
+ finally
+ {
+ Volatile.Write(ref m_pCachedStream, pStream);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Marshals m_pComPtr into a IStream*
+ /// </summary>
+ private IntPtr MarshalComPointerToStream()
+ {
+ if (!m_context.IsCurrent)
+ return MarshalComPointerToStream_InDifferentContext(m_context, m_pComPtr);
+
+ // Current Context
+ return MarshalComPointerToStream_InCurrentContext(m_pComPtr);
+ }
+
+ private static IntPtr MarshalComPointerToStream_InDifferentContext(ContextEntry context, IntPtr pComPtr)
+ {
+ IntPtr pStream = IntPtr.Zero;
+ context.EnterContext(() =>
+ {
+ pStream = MarshalComPointerToStream_InCurrentContext(pComPtr);
+ });
+ return pStream;
+ }
+
+ private static IntPtr MarshalComPointerToStream_InCurrentContext(IntPtr pComPtr)
+ {
+ IntPtr pStream;
+ if (MarshalInterThreadInterfaceInStream(ref Interop.COM.IID_IUnknown, pComPtr, out pStream))
+ return pStream;
+
+ return IntPtr.Zero;
+ }
+
+ /// <summary>
+ /// Marshal IUnknown * into a IStream*
+ /// </summary>
+ /// <returns>True if succeeded, false otherwise</returns>
+ private static bool MarshalInterThreadInterfaceInStream(ref Guid iid, IntPtr pUnknown, out IntPtr pRetStream)
+ {
+ ulong lSize;
+
+ //
+ // Retrieve maximum size required
+ //
+ int hr = ExternalInterop.CoGetMarshalSizeMax(
+ out lSize,
+ ref Interop.COM.IID_IUnknown,
+ pUnknown,
+ Interop.COM.MSHCTX.MSHCTX_INPROC,
+ IntPtr.Zero,
+ Interop.COM.MSHLFLAGS.MSHLFLAGS_TABLESTRONG
+ );
+
+ IntPtr pStream = IntPtr.Zero;
+
+ try
+ {
+ if (hr == Interop.COM.S_OK)
+ {
+ //
+ // Create a stream
+ //
+ pStream = __com_IStream.CreateMemStm(lSize);
+ if (pStream != IntPtr.Zero)
+ {
+ //
+ // Masrhal the interface into the stream TABLE STRONG
+ //
+ hr = ExternalInterop.CoMarshalInterface(
+ pStream,
+ ref iid,
+ pUnknown,
+ Interop.COM.MSHCTX.MSHCTX_INPROC,
+ IntPtr.Zero,
+ Interop.COM.MSHLFLAGS.MSHLFLAGS_TABLESTRONG
+ );
+ }
+ else
+ {
+ pRetStream = IntPtr.Zero;
+ return false;
+ }
+ }
+
+ if (hr >= 0)
+ {
+ if (McgComHelpers.SeekStreamToBeginning(pStream))
+ {
+ //
+ // Everything succeeded - transfer ownership to pRetStream
+ //
+ pRetStream = pStream;
+ pStream = IntPtr.Zero;
+
+ return true;
+ }
+ }
+
+ pRetStream = IntPtr.Zero;
+ return false;
+ }
+ finally
+ {
+ if (pStream != IntPtr.Zero)
+ {
+ McgMarshal.ComRelease(pStream);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Whether this has been already disposed
+ /// </summary>
+ internal bool IsDisposed
+ {
+ get
+ {
+ return m_pComPtr == default(IntPtr);
+ }
+ }
+
+ /// <summary>
+ /// Dispose and set status to disposed
+ /// </summary>
+ internal void Dispose(bool inCurrentContext)
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException("");
+
+ if (inCurrentContext)
+ McgMarshal.ComRelease(m_pComPtr);
+ else
+ m_context.EnqueueDelayedRelease(m_pComPtr);
+
+ m_pComPtr = default(IntPtr);
+
+ if (m_pCachedStream != default(IntPtr))
+ McgComHelpers.SafeReleaseStream(m_pCachedStream);
+ }
+ }
+
+ /// <summary>
+ /// Represents a COM context. It has the following characteristics:
+ /// 1. All ContextEntry objects are managed in a global cache, and as a result you won't get duplicated
+ /// ContextEntry for the same context.
+ /// 2. This ContextEntry keeps a ref count on m_pObjectContext - as a result the context won't become
+ /// invalid. This is VERY important
+ /// </summary>
+ internal class ContextEntry
+ {
+ /// <summary>
+ /// The cookie that represents the COM context
+ /// It is used as unique ID
+ /// </summary>
+ private ContextCookie m_cookie;
+
+ /// <summary>
+ /// The AddRefed IObjectContext* for this context
+ /// Used for the context transition
+ /// The AddRef is real important because it prevents the target context from going away, and prevents
+ /// m_cookie and m_pObjectContext becoming invalid
+ /// </summary>
+ private IntPtr m_pObjectContext;
+
+ /// <summary>
+ /// Initialize a new context entry
+ /// This is used by GetCurrentContext
+ /// After initialization, ref count = 1
+ /// </summary>
+ /// <param name="cookie">Current cookie. Passed for better perf</param>
+ private ContextEntry(ContextCookie cookie)
+ {
+ // Make sure the cookie is the current context cookie
+ // We pass the cookie in for better performance (avoid a P/Invoke)
+ Debug.Assert(cookie.IsCurrent);
+ m_cookie = cookie;
+ m_pObjectContext = IntPtr.Zero;
+
+ int hr = ExternalInterop.CoGetObjectContext(ref Interop.COM.IID_IUnknown, out m_pObjectContext);
+ if (hr < 0)
+ {
+ throw Marshal.GetExceptionForHR(hr);
+ }
+ }
+
+ /// <summary>
+ /// Returns the context cookie associated with this context
+ /// </summary>
+ internal ContextCookie ContextCookie
+ {
+ get
+ {
+ return m_cookie;
+ }
+ }
+
+ /// <summary>
+ /// Whether this context is the current context
+ /// </summary>
+ internal bool IsCurrent
+ {
+ get
+ {
+ return m_cookie.IsCurrent;
+ }
+ }
+
+ ~ContextEntry()
+ {
+ if (!Environment.HasShutdownStarted)
+ {
+ // m_pObjectContext could be NULL
+ McgMarshal.ComSafeRelease(m_pObjectContext);
+ m_pObjectContext = default(IntPtr);
+ }
+ }
+
+ internal static void RemoveCurrentContext()
+ {
+ ContextCookie cookie = ContextCookie.Current;
+ ComObjectCache.RemoveRCWsForContext(cookie);
+ ContextEntryManager.RemoveContextEntry(cookie);
+ }
+
+ /// <summary>
+ /// User-defined callback type
+ /// This callback will be called in the right context with data that was passed to EnterContext
+ /// </summary>
+ internal delegate void EnterContextCallback();
+
+ /// <summary>
+ /// Transition to this context and make the callback in that context
+ /// </summary>
+ /// <returns>True if succeed. False otherwise</returns>
+ internal unsafe bool EnterContext(EnterContextCallback callback)
+ {
+ //
+ // Retrieve the IContextCallback interface from the IObjectContext
+ //
+ IntPtr pContextCallback =
+ McgMarshal.ComQueryInterfaceNoThrow(m_pObjectContext, ref Interop.COM.IID_IContextCallback);
+
+ if (pContextCallback == IntPtr.Zero)
+ throw new InvalidCastException();
+
+ //
+ // Setup the callback data structure with the callback Args
+ //
+ Interop.COM.ComCallData comCallData = new Interop.COM.ComCallData();
+ comCallData.dwDispid = 0;
+ comCallData.dwReserved = 0;
+
+ //
+ // Allocate a GCHandle in order to pass a managed class in ComCallData.pUserDefined
+ //
+ GCHandle gchCallback = GCHandle.Alloc(callback);
+
+ try
+ {
+ comCallData.pUserDefined = GCHandle.ToIntPtr(gchCallback);
+
+ //
+ // Call IContextCallback::ContextCallback to transition into the right context
+ // This is a blocking operation
+ //
+ Interop.COM.__IContextCallback* pContextCallbackNativePtr =
+ (Interop.COM.__IContextCallback*)(void*)pContextCallback;
+ fixed (Guid* unsafe_iid = &Interop.COM.IID_IEnterActivityWithNoLock)
+ {
+ int hr = CalliIntrinsics.StdCall<int>(
+ pContextCallbackNativePtr->vtbl->pfnContextCallback,
+ pContextCallbackNativePtr, // Don't forget 'this pointer
+ AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(EnterContextCallbackProc),
+ &comCallData,
+ unsafe_iid,
+ (int)2,
+ IntPtr.Zero);
+
+ return (hr >= 0);
+ }
+ }
+ finally
+ {
+ gchCallback.Free();
+ }
+ }
+
+ /// <summary>
+ /// This is the callback gets called in the right context and we'll call to the user callback with
+ /// user supplied data
+ /// </summary>
+ [NativeCallable]
+ private static unsafe int EnterContextCallbackProc(IntPtr ptr)
+ {
+ Interop.COM.ComCallData* pComCallData = (Interop.COM.ComCallData*)ptr;
+ GCHandle gchCallback = GCHandle.FromIntPtr(pComCallData->pUserDefined);
+ EnterContextCallback callback = (EnterContextCallback)gchCallback.Target;
+ callback();
+ return Interop.COM.S_OK;
+ }
+
+ /// <summary>
+ /// Manage ContextCookie->ContextEntry mapping
+ /// </summary>
+ internal static class ContextEntryManager
+ {
+ [ThreadStatic]
+ static ContextEntry s_lastContextEntry;
+
+ internal static ContextEntry GetContextEntry(ContextCookie currentCookie)
+ {
+ ContextEntry last = s_lastContextEntry;
+
+ // Shortcut to skip locking + dictionary lookup
+ if ((last != null) && currentCookie.Equals(last.ContextCookie))
+ {
+ return last;
+ }
+ else
+ {
+ return GetContextEntrySlow(currentCookie);
+ }
+ }
+
+ static ContextEntry GetContextEntrySlow(ContextCookie currentCookie)
+ {
+ try
+ {
+ s_contextEntryLock.Acquire();
+
+ //
+ // Look up ContextEntry based on cache
+ //
+ ContextEntry contextEntry;
+
+ if (!s_contextEntryCache.TryGetValue(currentCookie, out contextEntry))
+ {
+ //
+ // Not found - create new entry in cache
+ //
+ contextEntry = new ContextEntry(currentCookie);
+
+ s_contextEntryCache.Add(currentCookie, contextEntry);
+ }
+
+ s_lastContextEntry = contextEntry; // Update cached entry
+
+ return contextEntry;
+ }
+ finally
+ {
+ s_contextEntryLock.Release();
+ }
+ }
+
+ /// <summary>
+ /// Remove context entry from global cache
+ /// </summary>
+ internal static void RemoveContextEntry(ContextCookie cookie)
+ {
+ try
+ {
+ s_contextEntryLock.Acquire();
+
+ s_lastContextEntry = null; // Clear cached entry
+
+ s_contextEntryCache.Remove(cookie);
+ }
+ finally
+ {
+ s_contextEntryLock.Release();
+ }
+ }
+
+ /// <summary>
+ /// Global cache for every contextEntry
+ /// This is done to avoid duplication
+ /// </summary>
+ static System.Collections.Generic.Internal.Dictionary<ContextCookie, ContextEntry> s_contextEntryCache;
+
+ /// <summary>
+ /// Lock that protects m_contextEntryCache
+ /// </summary>
+ static Lock s_contextEntryLock;
+
+ static internal void InitializeStatics()
+ {
+ s_contextEntryCache = new System.Collections.Generic.Internal.Dictionary<ContextCookie, ContextEntry>(new ContextCookieComparer());
+
+ s_contextEntryLock = new Lock();
+ }
+ }
+
+ /// <summary>
+ /// Retrieve current ContextEntry from cache
+ /// </summary>
+ /// <param name="currentCookie">Current context cookie. Passed in for better perf</param>
+ static internal ContextEntry GetCurrentContext(ContextCookie currentCookie)
+ {
+ Debug.Assert(currentCookie.IsCurrent);
+ return ContextEntryManager.GetContextEntry(currentCookie);
+ }
+
+ //
+ // Per-context list of interfaces that need to be released, next time we get a chance to do
+ // so in this context.
+ //
+ private Lock m_delayedReleaseListLock = new Lock();
+ private System.Collections.Generic.Internal.List<IntPtr> m_delayedReleaseList;
+
+ internal void EnqueueDelayedRelease(IntPtr pComPtr)
+ {
+ try
+ {
+ m_delayedReleaseListLock.Acquire();
+
+ if (m_delayedReleaseList == null)
+ m_delayedReleaseList = new System.Collections.Generic.Internal.List<IntPtr>(1);
+
+ m_delayedReleaseList.Add(pComPtr);
+ }
+ finally
+ {
+ m_delayedReleaseListLock.Release();
+ }
+ }
+
+ internal void PerformDelayedCleanup()
+ {
+ // fast path, hopefully inlined
+ if (m_delayedReleaseList != null)
+ PerformDelayedCleanupWorker();
+ }
+
+ private void PerformDelayedCleanupWorker()
+ {
+ Debug.Assert(this.IsCurrent);
+
+ System.Collections.Generic.Internal.List<IntPtr> list = null;
+
+ try
+ {
+ m_delayedReleaseListLock.Acquire();
+
+ if (m_delayedReleaseList != null)
+ {
+ list = m_delayedReleaseList;
+ m_delayedReleaseList = null;
+ }
+ }
+ finally
+ {
+ m_delayedReleaseListLock.Release();
+ }
+
+ if (list != null)
+ {
+ for (int i = 0; i < list.Count; i++)
+ {
+ McgMarshal.ComRelease(list[i]);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Simplified version of ComInterfaceCacheItem that only contains IID + ptr
+ /// The cached interface will always have the same context as the RCW
+ /// </summary>
+ internal unsafe struct SimpleComInterfaceCacheItem
+ {
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "typeInfo" and field type: McgTypeInfo
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::GetInterfaceData in debug\dbi\values.cpp
+ /// </summary>
+ internal McgTypeInfo typeInfo; // The table entry for the cached com interface
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name:"ptr" and field type:IntPtr
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::GetInterfaceData in debug\dbi\values.cpp
+ /// </summary>
+ internal volatile IntPtr ptr; // Interface pointer under this context
+
+ /// <summary>
+ /// RuntimeTypeHandle is added to the cache to make faster cache lookups. Instead
+ /// of getting the McgTypeInfo from RuntimeTypeHandle, which is very expensive, we
+ /// use the RuntimeTypeHandle to directly lookup the cache
+ /// </summary>
+ internal RuntimeTypeHandle typeHandle;
+
+ /// <summary>
+ /// Assign GUID/ComPointer
+ /// </summary>
+ /// <returns>Return true if winning race. False otherwise</returns>
+ internal bool Assign(McgTypeInfo interfaceTypeInfo, IntPtr pComPtr, RuntimeTypeHandle handle)
+ {
+ // disable warning for ref volatile
+#pragma warning disable 0420
+ if (Interlocked.CompareExchange(ref ptr, pComPtr, default(IntPtr)) == default(IntPtr))
+ {
+ // We win the race
+ // Note: We use either typeInfo or typeHandle as key to lookup the ptr from the cache
+ // The aforementioned compareExchange ensures that if the key is there the value will be there
+ // too. It doesn't guarantee the correct value of the other key. So we should be careful about retrieving
+ // cache item using one key and trying to access the other key of the cache as it might lead to interesting
+ // problems
+
+ typeInfo = interfaceTypeInfo;
+
+ // If the RuntimeTypeHandle has default value get the correct one from McgTypeInfo
+ if (handle.Equals(default(RuntimeTypeHandle)))
+ typeHandle = interfaceTypeInfo.ItfType;
+ else
+ typeHandle = handle;
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+#pragma warning restore 0420
+ }
+
+ /// <summary>
+ /// Whether the cache item is free
+ /// </summary>
+ internal bool IsFree
+ {
+ get
+ {
+ return ptr == default(IntPtr);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Caches information about a particular COM interface under a particular COM context
+ /// </summary>
+ internal struct AdditionalComInterfaceCacheItem
+ {
+ /// <summary>
+ /// Create a new cached item
+ /// Assumes the interface pointer has already been AddRef-ed
+ /// Will transfer the ref count to this data structure
+ /// </summary>
+ internal AdditionalComInterfaceCacheItem(McgTypeInfo interfaceTypeInfo, IntPtr pComPtr, object adapter)
+ {
+ typeInfo = interfaceTypeInfo;
+ ptr = pComPtr;
+ dynamicAdapter = adapter;
+ }
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "typeInfo" and field type: McgTypeInfo
+ /// See CordbObjectValue::WalkAdditionalCacheItem in debug\dbi\values.cpp
+ /// </summary>
+ internal readonly McgTypeInfo typeInfo; // Table entry of this cached COM interface
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "ptr" and field type: IntPtr
+ /// See CordbObjectValue::WalkAdditionalCacheItem in debug\dbi\values.cpp
+ /// </summary>
+ internal readonly IntPtr ptr; // Interface pointer under this context
+ internal readonly object dynamicAdapter; // Adapter object for this type. Only used for some projected interfaces.
+ }
+
+ internal class AdditionalComInterfaceCacheContext
+ {
+ internal AdditionalComInterfaceCacheContext(ContextCookie contextCookie)
+ {
+ context = ContextEntry.GetCurrentContext(contextCookie);
+ }
+
+ /// <returns>false if duplicate found</returns>
+ internal unsafe bool Add(McgTypeInfo interfaceTypeInfo, IntPtr pComPtr, object adapter, bool checkDup)
+ {
+ if (checkDup) // checkDup
+ {
+ foreach (AdditionalComInterfaceCacheItem existingType in items)
+ {
+ if (existingType.typeInfo.Equals(interfaceTypeInfo))
+ {
+ return false;
+ }
+ }
+ }
+
+ items.Add(new AdditionalComInterfaceCacheItem(interfaceTypeInfo, pComPtr, adapter));
+
+ return true;
+ }
+
+ internal readonly ContextEntry context;
+ /// <summary>
+ /// NOTE: Managed debugger depends on field name: "items" and field type:WithInlineStorage
+ /// Update managed debugger whenever field name/field type is changed.
+ /// See CordbObjectValue::GetInterfaceData in debug\dbi\values.cpp
+ /// </summary>
+ internal LightweightList<AdditionalComInterfaceCacheItem>.WithInlineStorage items;
+ }
+
+ [Flags]
+ enum ComObjectFlags
+ {
+ /// <summary>
+ /// Default value
+ /// </summary>
+ None = 0,
+
+ /// <summary>
+ /// A Duplicate RCW that has the same identity pointer as another RCW in the cache
+ /// This could be created due to a race or intentionally
+ /// We don't put duplicate RCWs into our cache
+ /// </summary>
+ IsDuplicate = 0x1,
+
+ /// <summary>
+ /// This RCW represents a Jupiter object
+ /// </summary>
+ IsJupiterObject = 0x2,
+
+ /// <summary>
+ /// Whether this is a managed class deriving from a RCW. For example, managed MyButton class deriving
+ /// from native Button class. Button RCW is being aggregated by MyButton CCW
+ /// </summary>
+ ExtendsComObject = 0x4,
+
+ /// <summary>
+ /// These enums are used to find the right GCPressure values.
+ /// We have 5 possible states.
+ /// a. None.
+ /// b. Default
+ /// c. GCPressureRange.Low
+ /// d. GCPressureRange.Medium
+ /// e. GCPressureRange.High
+ ///
+ /// We basically use 3 bits for the 5 values as follows.
+ /// 1. None - Represented by the absence of GCPressure_Set bit.
+ /// 2. Default - Presence of only GCPRessure_Set
+ /// 3. All the rest are marked by 2 in conjunction with specific GCPressureRange.
+ ///
+ /// We need to use the state None and Default both since some of the __ComObjects are created without really initiating them with any basePtr and hence while
+ /// releasing the ComObject we need to know whether we Added GC.AddMemoryPressure for the given __ComObject or not.
+ /// This also ensures 1-1 mapping between the AddMemoryPressure and RemoveMemoryPressure.
+ /// </summary>
+
+ GCPressure_Set = 0x8,
+ GCPressureWinRT_Low = 0x10,
+ GCPressureWinRT_Medium = 0x20,
+ GCPressureWinRT_High = 0x30,
+
+ GCPressureWinRT_Mask = 0x30,
+
+ /// <summary>
+ /// This represents the types MarshalingBehavior.
+ /// </summary>
+ MarshalingBehavior_Inhibit = 0x40,
+ MarshalingBehavior_Free = 0x80,
+ MarshalingBehavior_Standard = 0xc0,
+
+ MarshalingBehavior_Mask = 0xc0,
+ // Add other enums here.
+ }
+
+#if ENABLE_WINRT
+ /// <summary>
+ /// This class helps call the IStringableToString() by QI IStringable.ToString() method call.
+ /// </summary>
+ internal class IStringableHelper
+ {
+ internal unsafe static bool TryGetIStringableToString(object obj, out string toStringResult)
+ {
+ bool isIStringableToString = false;
+ toStringResult = String.Empty;
+
+ __ComObject comObject = obj as __ComObject;
+
+ if (comObject != null)
+ {
+ // Check whether the object implements IStringable
+ // If so, use IStringable.ToString() behavior
+ IntPtr pIStringableItf = comObject.QueryInterface_NoAddRef_Internal(McgModuleManager.IStringable, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false);
+
+ if (pIStringableItf != default(IntPtr))
+ {
+ __com_IStringable* pIStringable = (__com_IStringable*)pIStringableItf;
+ void* unsafe_hstring = null;
+
+ // The method implements isIStringableToString
+ isIStringableToString = true;
+
+ try
+ {
+ int hr = CalliIntrinsics.StdCall<int>(
+ pIStringable->pVtable->pfnToString,
+ pIStringable,
+ &unsafe_hstring
+ );
+
+ GC.KeepAlive(obj);
+
+ // Don't throw if the call fails
+ if (hr >= 0)
+ {
+ toStringResult = McgMarshal.HStringToString(new IntPtr(unsafe_hstring));
+ }
+ }
+ finally
+ {
+ if (unsafe_hstring != null)
+ McgMarshal.FreeHString(new IntPtr(unsafe_hstring));
+ }
+ }
+ }
+
+ return isIStringableToString;
+ }
+ }
+#endif
+
+ internal enum GCPressureRange
+ {
+ None,
+ WinRT_Default,
+ WinRT_Low,
+ WinRT_Medium,
+ WinRT_High
+ }
+
+#if !RHTESTCL
+ /// <summary>
+ /// These values are taken from the CLR implementation and can be changed later if perf shows so.
+ /// </summary>
+ internal struct GCMemoryPressureConstants
+ {
+#if WIN64
+ internal const int GC_PRESSURE_DEFAULT = 1000;
+ internal const int GC_PRESSURE_WINRT_LOW = 12000;
+ internal const int GC_PRESSURE_WINRT_MEDIUM = 120000;
+ internal const int GC_PRESSURE_WINRT_HIGH = 1200000;
+#else
+ internal const int GC_PRESSURE_DEFAULT = 750;
+ internal const int GC_PRESSURE_WINRT_LOW = 8000;
+ internal const int GC_PRESSURE_WINRT_MEDIUM = 80000;
+ internal const int GC_PRESSURE_WINRT_HIGH = 800000;
+#endif
+ }
+#endif
+
+
+ //
+ // Base class for all "dynamic adapters." This allows us to instantiate
+ // these via RhNewObject (which requires a default constructor), and also
+ // initialize them (via ComInterfaceDynamicAdapter.Initialize).
+ //
+ [CLSCompliant(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class ComInterfaceDynamicAdapter
+ {
+ __ComObject m_comObject;
+
+ internal void Initialize(__ComObject comObject)
+ {
+ m_comObject = comObject;
+ }
+
+ public __ComObject ComObject
+ {
+ get
+ {
+ return m_comObject;
+ }
+ }
+ }
+
+ /// <summary>
+ /// A global cache for all __ComObject(s)
+ /// We do a lookup based on IUnknown to find the corresponding cached __ComObject the cache
+ /// </summary>
+ /// <remarks>
+ /// If a __ComObject is in finalizer queue, it is no longer considered valid in the cache
+ /// The reason is to avoid unintentionally resurrecting __ComObject during marshalling and therefore
+ /// resurrecting anything that is pointed by __ComObject that might already been finalized.
+ /// Therefore, all __ComObject are tracked with short weak GC handles.
+ /// </remarks>
+ /// <remarks>
+ /// NOTE: Not all __ComObject are stored in ComObject cache. __ComObject with IsDuplicated == true
+ /// are not saved here, because they are not the "identity" RCW for that specific interface pointer and
+ /// there can only be one
+ /// </remarks>
+ internal static class ComObjectCache
+ {
+ /// <summary>
+ /// Adds the __ComObject into cache
+ /// This either insert its into the cache, or updates an inavlid entry with this __ComObject
+ /// </summary>
+ /// <returns>true if add/update succeeded. false if there is already a valid entry in the cache.
+ /// In that case, you should insert it as a duplicate RCW
+ /// </returns>
+ internal static bool Add(IntPtr pComItf, __ComObject o)
+ {
+ int hashCode = pComItf.GetHashCode();
+
+ try
+ {
+ s_lock.Acquire();
+
+ IntPtr handlePtr;
+
+ if (s_comObjectMap.TryGetValue(pComItf, hashCode, out handlePtr))
+ {
+ GCHandle handle = GCHandle.FromIntPtr(handlePtr);
+ __ComObject cachedComObject = (__ComObject)handle.Target;
+
+ if (cachedComObject == null)
+ {
+ //
+ // We have another __ComObject in the cache but it is now in the finalizer queue
+ // We can safely reuse this entry for this new object
+ // This could happen if the same interface pointer is marshalled back to managed
+ // code again
+ //
+ handle.Target = o;
+ }
+ else
+ {
+ //
+ // There is a already a valid __ComObject in the cache
+ // This is a "duplicate" RCW and we don't need to insert it into the cache as
+ // we won't be returning this RCW during lookup
+ //
+ return false;
+ }
+ }
+ else
+ {
+ GCHandle newHandle = GCHandle.Alloc(o, GCHandleType.Weak);
+ handlePtr = GCHandle.ToIntPtr(newHandle);
+ s_comObjectMap.Add(pComItf, handlePtr, hashCode);
+ }
+
+ return true;
+ }
+ finally
+ {
+ s_lock.Release();
+ }
+ }
+
+ /// <summary>
+ /// Remove entry from the global IUnknown->__ComObject map
+ /// </summary>
+ internal static void Remove(IntPtr pComItf, __ComObject o)
+ {
+ Debug.Assert(o != null);
+
+ try
+ {
+ s_lock.Acquire();
+
+ //
+ // Only remove if the entry is indeed in the cache and is a match
+ // The entry might not be even in the cache if the following event occurs:
+ // 1. a RCW A is created for interface pointer 0x100 and is added into cache with key=0x100
+ // 2. RCW A is not referenced anymore and is now in the fnialization queue
+ // 3. The same interface pointer 0x100 is marshalled back into managed again - this time
+ // we should NOT reuse the same RCW to resurrect it. See the remark section in this class
+ // for more details. We will create a new RCW B, and it's not a duplicate.
+ // 4. RCW B is also considered dead and enters the finalizer queue
+ // 5. RCW A now finally gets its chance to finalize, and remove 0x100 from the cache, as
+ // cachedObject is now null (was pointing to RCW B which is now in finalize queue)
+ // 5. RCW B eventually gets its chance to finalize, and there is no 0x100 in the cache
+ //
+ IntPtr handlePtr;
+
+ if (s_comObjectMap.TryGetValue(pComItf, out handlePtr))
+ {
+ GCHandle handle = GCHandle.FromIntPtr(handlePtr);
+ Object cachedObject = handle.Target;
+
+ //
+ // Only remove if
+ // 1) The cached object matches
+ // 2) The cached object is null, which means it is now invalidated and we can
+ // safely remove it now
+ //
+ // If the cached object is non-null and doesn't match, this means there is a new
+ // __ComObject that now occupies this cache entry and we should not remove it
+ //
+ if (cachedObject == o ||
+ cachedObject == null)
+ {
+ //
+ // Remove it from the map and free the handle
+ // The order is very important as GC could come at any time
+ // We want to destroy the handle after we've remove this entry from the list
+ // NOTE: if GC comes before we even remove it from the list, it's OK because we
+ // haven't actually released the interfaces in the RCW yet
+ //
+ s_comObjectMap.Remove(pComItf);
+ handle.Free();
+ }
+ }
+ }
+ finally
+ {
+ s_lock.Release();
+ }
+ }
+
+ /// <summary>
+ /// Return the corresponding __ComObject that has the IUnknown* as its identity
+ /// NOTE: If a __ComObject is in finalizer queue or is resurrected, it is not considered valid and
+ /// won't be returned. This is done to avoid resurrection by accident during marshalling
+ /// </summary>
+ internal static __ComObject Lookup(IntPtr pComItf)
+ {
+ try
+ {
+ s_lock.Acquire();
+
+ IntPtr handlePtr;
+
+ if (s_comObjectMap.TryGetValue(pComItf, out handlePtr))
+ {
+ object target = GCHandle.FromIntPtr(handlePtr).Target;
+ Debug.Assert(target == null || target is __ComObject);
+
+ return InteropExtensions.UncheckedCast<__ComObject>(target);
+ }
+
+ return null;
+ }
+ finally
+ {
+ s_lock.Release();
+ }
+ }
+
+ internal static void RemoveRCWsForContext(ContextCookie contextCookie)
+ {
+ try
+ {
+ s_lock.Acquire();
+
+ System.Collections.Generic.Internal.Dictionary<IntPtr, IntPtr> map = s_comObjectMap;
+
+ for (int i = 0; i < map.GetMaxCount(); i++)
+ {
+ IntPtr handlePtr = default(IntPtr);
+
+ if (map.GetValue(i, ref handlePtr) && (handlePtr != default(IntPtr)))
+ {
+ GCHandle handle = GCHandle.FromIntPtr(handlePtr);
+ __ComObject obj = handle.Target as __ComObject;
+
+ if (obj != null)
+ obj.RemoveInterfacesForContext(contextCookie);
+ }
+ }
+ }
+ finally
+ {
+ s_lock.Release();
+ }
+ }
+
+ static Lock s_lock;
+
+ /// <summary>
+ /// Map of all __ComObject instances
+ /// This points to an index in s_comObjectList
+ /// </summary>
+ internal static System.Collections.Generic.Internal.Dictionary<IntPtr, IntPtr> s_comObjectMap;
+
+ internal static void InitializeStatics()
+ {
+ s_lock = new Lock();
+
+ s_comObjectMap = new System.Collections.Generic.Internal.Dictionary<IntPtr, IntPtr>(101, new EqualityComparerForIntPtr());
+ }
+ }
+
+ internal sealed class EqualityComparerForIntPtr : EqualityComparer<IntPtr>
+ {
+ public override bool Equals(IntPtr x, IntPtr y)
+ {
+ return x == y;
+ }
+
+ public override int GetHashCode(IntPtr x)
+ {
+ return x.GetHashCode();
+ }
+ }
+
+#if ENABLE_WINRT
+ /// <summary>
+ /// WinRT factory cache item caching the context + factory RCW
+ /// </summary>
+ internal struct FactoryCacheItem
+ {
+ internal ContextEntry contextEntry;
+ internal __ComObject factoryObject;
+ }
+
+ /// <summary>
+ /// WinRT Factory cache
+ /// We only remember the last cached factory per context + type
+ /// The type part is obvious but the context part is probably less so.
+ /// When we retrieve a factory, we must make sure the factory interface pointer is the same as if we
+ /// were calling RoGetActivationFactory from the current context. This is VERY important for factories
+ /// that are 'BOTH'. If you have a 'BOTH' factory created in STA, and marshal that factory to a MTA,
+ /// when you call marshalled factory interface pointer in MTA, you'll get a STA object! That is different
+ /// from when you call RoGetActivationFactory in MTA and call the factory which creates a MTA object
+ /// </summary>
+ internal class FactoryCache
+ {
+ const int DefaultSize = 11; // Small prime number to avoid resizing dictionary resizing in start up code
+
+ private Lock m_factoryLock = new Lock();
+ private System.Collections.Generic.Internal.Dictionary<string, FactoryCacheItem> m_cachedFactories = new System.Collections.Generic.Internal.Dictionary<string, FactoryCacheItem>(DefaultSize);
+
+ private static volatile FactoryCache s_factoryCache;
+
+ static internal FactoryCache Get()
+ {
+#pragma warning disable 0420
+ if (s_factoryCache == null)
+ {
+ Interlocked.CompareExchange(ref s_factoryCache, new FactoryCache(), null);
+ }
+#pragma warning restore 0420
+
+ return s_factoryCache;
+ }
+
+ /// <summary>
+ /// Retrieve the class factory for a specific type
+ /// </summary>
+ private static unsafe __ComObject GetActivationFactoryInternal(
+ string typeName,
+ McgTypeInfo typeInfo,
+ ContextEntry currentContext)
+ {
+ IntPtr pFactory = default(IntPtr);
+ try
+ {
+ Guid itfGuid = typeInfo.ItfGuid;
+ ExternalInterop.RoGetActivationFactory(typeName, ref itfGuid, out pFactory);
+
+ return (__ComObject)McgComHelpers.ComInterfaceToComObject(
+ pFactory,
+ typeInfo,
+ McgClassInfo.Null,
+ currentContext.ContextCookie, // Only want factory RCW from matching context
+ McgComHelpers.CreateComObjectFlags.SkipTypeResolutionAndUnboxing
+ );
+ }
+ finally
+ {
+ if (pFactory != default(IntPtr))
+ McgMarshal.ComRelease(pFactory);
+ }
+ }
+
+ /// <summary>
+ /// Retrieves the class factory RCW for the specified class name + IID under the right context
+ /// The context part is really important
+ /// </summary>
+ internal __ComObject GetActivationFactory(string className, McgTypeInfo factoryIntf, bool skipCache = false)
+ {
+ ContextEntry currentContext = ContextEntry.GetCurrentContext(ContextCookie.Current);
+
+ FactoryCacheItem cacheItem;
+
+ int hashCode = className.GetHashCode();
+
+ if (!skipCache)
+ {
+ try
+ {
+ m_factoryLock.Acquire();
+
+ if (m_cachedFactories.TryGetValue(className, hashCode, out cacheItem))
+ {
+ if (cacheItem.contextEntry == currentContext)
+ {
+ //
+ // We've found a matching entry
+ //
+ return cacheItem.factoryObject;
+ }
+ }
+ }
+ finally
+ {
+ m_factoryLock.Release();
+ }
+ }
+
+ //
+ // No matching entry found - let's create a new one
+ // This is kinda slow so do it outside of a lock
+ //
+ __ComObject factoryObject = GetActivationFactoryInternal(className, factoryIntf, currentContext);
+
+ cacheItem.contextEntry = currentContext;
+ cacheItem.factoryObject = factoryObject;
+
+ if (!skipCache)
+ {
+ //
+ // Insert into or update cache
+ //
+ try
+ {
+ m_factoryLock.Acquire();
+
+ m_cachedFactories[className] = cacheItem;
+ }
+ finally
+ {
+ m_factoryLock.Release();
+ }
+ }
+
+ return cacheItem.factoryObject;
+ }
+
+ }
+#endif
+}
diff --git a/src/System.Private.Interop/src/System.Private.Interop.csproj b/src/System.Private.Interop/src/System.Private.Interop.csproj
new file mode 100644
index 000000000..e77033109
--- /dev/null
+++ b/src/System.Private.Interop/src/System.Private.Interop.csproj
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <AssemblyName>System.Private.Interop</AssemblyName>
+ <OutputType>Library</OutputType>
+ <ProjectGuid>{A85709C9-22D5-4704-8B7A-73751BB4386A}</ProjectGuid>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DefineConstants>$(DefineConstants);TARGET_CORE_API_SET</DefineConstants>
+ <SccProjectName>SAK</SccProjectName>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccProvider>SAK</SccProvider>
+ <!-- <NoWarn>618</NoWarn> -->
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the options -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|amd64' ">
+ <PlatformTarget>x64</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|amd64' ">
+ <PlatformTarget>x64</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|arm' ">
+ <PlatformTarget>arm</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|arm' ">
+ <PlatformTarget>arm</PlatformTarget>
+ </PropertyGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\AotPackageReference\AotPackageReference.depproj">
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+
+ <ProjectReference Include="..\..\System.Private.CoreLib\src\System.Private.CoreLib.csproj" />
+ <ProjectReference Include="..\..\System.Private.Threading\src\System.Private.Threading.csproj" />
+ <ProjectReference Include="..\..\System.Private.Reflection\src\System.Private.Reflection.csproj" />
+
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Runtime.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Runtime.Handles.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Runtime.Extensions.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.IO.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Collections.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Resources.ResourceManager.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Reflection.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Reflection.Extensions.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Reflection.Primitives.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Reflection.TypeExtensions.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Diagnostics.Tracing.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Diagnostics.Contracts.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Diagnostics.Debug.dll" />
+ <ReferencePath Include="$(AotPackageReferencePath)\System.Threading.Tasks.dll" />
+ </ItemGroup>
+
+ <!-- TODO We should not include anything from CompilerServices directly -->
+ <ItemGroup>
+ <Compile Include="System\RhBaseName.cs" />
+ <Compile Include="System\Runtime\CompilerServices\UnmanagedValueTypeConstraintAttribute.cs" />
+ <Compile Include="System\Runtime\CompilerServices\McgResource.cs" />
+ <Compile Include="System\Runtime\CompilerServices\ModuleConstructorAttribute.cs" />
+ <Compile Include="System\Runtime\CompilerServices\IgnoresAccessChecksToAttribute.cs" />
+ <Compile Include="System\Runtime\CompilerServices\FunctionPointerHelpers.cs" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <Compile Include="..\..\Common\src\Internal\NativeFormat\NativeFormatReader.cs" />
+ <Compile Include="..\..\Common\src\Internal\NativeFormat\NativeFormatReader.String.cs" />
+
+ <Compile Include="Shared\__ComObject.cs" />
+ <Compile Include="Shared\ComCallableObject.cs" />
+ <Compile Include="Shared\ComException.cs" />
+ <Compile Include="Shared\ComInterop.cs" />
+ <Compile Include="Shared\DebugAnnotations.cs" />
+ <Compile Include="Shared\Dictionary.cs" />
+ <Compile Include="Shared\DictionaryBase.cs" />
+ <Compile Include="Shared\EventRegistrationToken.cs" />
+ <Compile Include="Shared\FixedHashTable.cs" />
+ <Compile Include="Shared\GCEventProvider.cs" />
+ <Compile Include="Shared\HashSet.cs" />
+ <Compile Include="Shared\InternalModule.cs" />
+ <Compile Include="Shared\Interop.Manual.cs" />
+ <Compile Include="Shared\List.cs" />
+ <Compile Include="Shared\Marshal.cs" />
+ <Compile Include="Shared\McgAccessorAttribute.cs" />
+ <Compile Include="Shared\McgComCallableAttribute.cs" />
+ <Compile Include="Shared\McgComHelpers.cs" />
+ <Compile Include="Shared\McgData.cs" />
+ <Compile Include="Shared\McgGeneratedAssemblyAttribute.cs" />
+ <Compile Include="Shared\McgGeneratedMarshallingCodeAttribute.cs" />
+ <Compile Include="Shared\McgGeneratedNativeCallCodeAttribute.cs" />
+ <Compile Include="Shared\McgHelpers.cs" />
+ <Compile Include="Shared\McgIntrinsics.cs" />
+ <Compile Include="Shared\McgMarshal.cs" />
+ <Compile Include="Shared\McgMethodNameAttribute.cs" />
+ <Compile Include="Shared\McgModule.cs" />
+ <Compile Include="Shared\McgModuleManager.cs" />
+ <Compile Include="Shared\McgPInvokeMarshalStubAttribute.cs" />
+ <Compile Include="Shared\McgredirectedMethodAttribute.cs" />
+ <Compile Include="Shared\McgRedirectedTypeAttribute.cs" />
+ <Compile Include="Shared\McgRemovedType.cs" />
+ <Compile Include="Shared\McgRootsTypeAttribute.cs" />
+ <Compile Include="Shared\McgTypeHelpers.cs" />
+ <Compile Include="Shared\RCWWalker.cs" />
+ <Compile Include="Shared\StandardInterfaces.cs" />
+ <Compile Include="Shared\StringPool.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="System\Runtime\InteropServices\ArrayWithOffset.cs" />
+ <Compile Include="System\Runtime\InteropServices\BestFitMappingAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\BStrWrapper.cs" />
+ <Compile Include="System\Runtime\InteropServices\ClassInterfaceAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\ClassInterfaceType.cs" />
+ <Compile Include="System\Runtime\InteropServices\CoClassAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\ComDefaultInterfaceAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\ComEventInterfaceAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\ComEventsHelper.cs" />
+ <Compile Include="System\Runtime\InteropServices\ComImportAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\ComInterfaceType.cs" />
+ <Compile Include="System\Runtime\InteropServices\ComMemberType.cs" />
+ <Compile Include="System\Runtime\InteropServices\ComSourceInterfacesAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\CriticalHandle.cs" />
+ <Compile Include="System\Runtime\InteropServices\CurrencyWrapper.cs" />
+ <Compile Include="System\Runtime\InteropServices\CustomQueryInterfaceMode.cs" />
+ <Compile Include="System\Runtime\InteropServices\CustomQueryInterfaceResult.cs" />
+ <Compile Include="System\Runtime\InteropServices\DefaultCharSetAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\DefaultDllImportSearchPathAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\DispatchWrapper.cs" />
+ <Compile Include="System\Runtime\InteropServices\DispIdAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\DllImportSearchPath.cs" />
+ <Compile Include="System\Runtime\InteropServices\ErrorWrapper.cs" />
+ <Compile Include="System\Runtime\InteropServices\InteropEventProvider.cs" />
+ <Compile Include="System\Runtime\InteropServices\GuidAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\InAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\ICustomAdapter.cs" />
+ <Compile Include="System\Runtime\InteropServices\ICustomQueryInterface.cs" />
+ <Compile Include="System\Runtime\InteropServices\InterfaceTypeAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\InvalidComObjectException.cs" />
+ <Compile Include="System\Runtime\InteropServices\InvalidOleVariantTypeException.cs" />
+ <Compile Include="System\Runtime\InteropServices\LCIDConversionAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\Marshal.cs" />
+ <Compile Include="System\Runtime\InteropServices\MarshalAdapter.cs" />
+ <Compile Include="System\Runtime\InteropServices\MarshalImpl.cs" />
+ <Compile Include="System\Runtime\InteropServices\MarshalAsAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\MarshalDirectiveException.cs" />
+ <Compile Include="System\Runtime\InteropServices\MissingInteropDataException.cs" />
+ <Compile Include="System\Runtime\InteropServices\OptionalAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\PreserveSigAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\SafeArrayRankMismatchException.cs" />
+ <Compile Include="System\Runtime\InteropServices\SafeArrayTypeMismatchException.cs" />
+ <Compile Include="System\Runtime\InteropServices\SafeBuffer.cs" />
+ <Compile Include="System\Runtime\InteropServices\SEHException.cs" />
+ <Compile Include="System\Runtime\InteropServices\TypeIdentifierAttribute.cs" />
+ <Compile Include="System\Runtime\InteropServices\UnmanagedType.cs" />
+ <Compile Include="System\Runtime\InteropServices\UnknownWrapper.cs" />
+ <Compile Include="System\Runtime\InteropServices\VarEnum.cs" />
+ <Compile Include="System\Runtime\InteropServices\Variant.cs" />
+ <Compile Include="System\Runtime\InteropServices\VariantWrapper.cs" />
+ <Compile Include="System\Runtime\InteropServices\ComWeakReferenceHelpers.cs" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <!--TODO:Disable under FEATURE_COMN switch , now we need these to compile S.P.Interop.dll-->
+ <Compile Include="System\Runtime\InteropServices\ComTypes\statstg.cs" />
+ <Compile Include="System\Runtime\InteropServices\ComTypes\filetime.cs" />
+ </ItemGroup>
+
+ <ItemGroup Condition=" '$(TargetsWindows)' == 'true' ">
+ <Compile Include="Interop\Interop.Memory.Windows.cs" />
+ <Compile Include="Interop\Interop.String.Windows.cs" />
+ <Compile Include="Interop\Interop.WinRT.cs" />
+ <Compile Include="Interop\Interop.Localization.Windows.cs" />
+ <Compile Include="Interop\Interop.Sync.Windows.cs" />
+ <Compile Include="Interop\Interop.COM.Windows.cs" />
+ <Compile Include="Interop\Interop.Common.Windows.cs" />
+ <Compile Include="System\__HResults.cs" />
+ </ItemGroup>
+
+ <ItemGroup Condition=" '$(TargetsWindows)' != 'true' ">
+ <Compile Include="Interop\Interop.Memory.Unix.cs" />
+ <Compile Include="Interop\Interop.String.Unix.cs" />
+ <Compile Include="Interop\Interop.Common.Unix.cs" />
+ </ItemGroup>
+
+ <!--TODO : Not sure how this get shared with RHTest.This target never seem to execute when open.target is included
+ (see System.Private.Interop.NetNative.csproj) since open.target does it's own resource generation and the resource strings
+ appear in N binary.Also have to split the resource strings between N and CoreRT.We don't probably need many of the
+ N specific resource strings in CoreRT-->
+ <Target Name="AfterBuild" DependsOnTargets="SystemInteropCoreCLR_PreparePostBuildResourceGeneration;SystemInteropCoreCLR_PostBuildResourceGeneration" />
+ <Target Name="SystemInteropCoreCLR_PreparePostBuildResourceGeneration">
+ <!-- Generate SR.cs under InterIncAPICandidate\Interop path and always using /debug switch -->
+ <!-- to force generating the English strings which are required in rhtestcl -->
+ <PropertyGroup>
+ <InteropResInputFileFullPath>$(MSBuildProjectDirectory)\Resources\Strings.resx</InteropResInputFileFullPath>
+ <InteropResOutputFileDirectory>$(FXInterIncCandidatePath)\Interop\</InteropResOutputFileDirectory>
+ <InteropResOutputFileFullPath>$(InteropResOutputFileDirectory)SR.cs</InteropResOutputFileFullPath>
+ <_IntermediateResOutputFileFullPath>$(IntermediateOutputPath)SR.cs</_IntermediateResOutputFileFullPath>
+ <InteropResArgs>/debug</InteropResArgs>
+ <InteropResArgs>$(InteropResArgs) $(InteropResInputFileFullPath)</InteropResArgs>
+ <InteropResArgs>$(InteropResArgs) $(_IntermediateResOutputFileFullPath)</InteropResArgs>
+ <InteropResArgs>$(InteropResArgs) $(AssemblyName)</InteropResArgs>
+ <InteropResCmd>$(ResPath) $(InteropResArgs)</InteropResCmd>
+ </PropertyGroup>
+
+ </Target>
+ <Target Name="SystemInteropCoreCLR_PostBuildResourceGeneration" Inputs="$(InteropResInputFileFullPath)" Outputs="$(_IntermediateResOutputFileFullPath)">
+ <MakeDir Directories="$(InteropResOutputFileDirectory)" />
+ <Exec Command="$(InteropResCmd)" StandardOutputImportance="low" />
+ </Target>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/System.Private.Interop/src/System/DllNotFoundException.cs b/src/System.Private.Interop/src/System/DllNotFoundException.cs
new file mode 100644
index 000000000..b7cfaf7f2
--- /dev/null
+++ b/src/System.Private.Interop/src/System/DllNotFoundException.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.
+
+/*=============================================================================
+**
+** Class: DllNotFoundException
+**
+**
+** Purpose: The exception class for some failed P/Invoke calls.
+**
+**
+=============================================================================*/
+
+namespace System
+{
+ public class DllNotFoundException : TypeLoadException
+ {
+ public DllNotFoundException()
+ : base(SR.Arg_DllNotFoundException)
+ {
+ HResult = __HResults.COR_E_DLLNOTFOUND;
+ }
+
+ public DllNotFoundException(String message)
+ : base(message)
+ {
+ HResult = __HResults.COR_E_DLLNOTFOUND;
+ }
+
+ public DllNotFoundException(String message, Exception inner)
+ : base(message, inner)
+ {
+ HResult = __HResults.COR_E_DLLNOTFOUND;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Reflection/DispatchProxy.cs b/src/System.Private.Interop/src/System/Reflection/DispatchProxy.cs
new file mode 100644
index 000000000..1d840be2f
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Reflection/DispatchProxy.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.Runtime.InteropServices;
+
+namespace System.Reflection
+{
+ /// <summary>
+ /// Dispatch proxies are a mechanism for instantiating toolchain-generated proxy objects at
+ /// runtime that can both (1) implement methods defined by an interface, and (2) forward calls
+ /// made to these methods to a common proxy class that knows how to implement the behavior
+ /// of these methods.
+ /// </summary>
+ /// <remarks>
+ /// In some ways, this is the replacement for some of the functionality provided by transparent
+ /// proxies on Desktop CLR, and can enable a limited form of remoting. For example, a prominent
+ /// use case of dispatch proxies is the "service contract" architecture provided by WCF. In WCF,
+ /// a remote service declares a .NET interface that defines a service contract that clients can
+ /// use to talk to the remote service. On the client side, the client talks to the service by
+ /// interacting with an object via that interface, e.g.:
+ ///
+ /// IFooService serviceChannel = ChannelFactory<IFooService>.CreateChannel();
+ /// serviceChannel.MakeRequest();
+ ///
+ /// This 'serviceChannel' object is a representation of a served object on the client side, so
+ /// making method calls on it has the effect of making that same method call on the server side.
+ /// Under the hood, WCF asks DispatchProxy to create a proxy object that implements the given
+ /// service contract 'IFooService' and forwards its calls to a special WCF proxy class, e.g.:
+ ///
+ /// static class ChannelFactory<T>
+ /// {
+ /// static public T CreateChannel()
+ /// {
+ /// return DispatchProxy.Create<T, WcfProxy>();
+ /// }
+ /// }
+ ///
+ /// At compile time, the toolchain will generate class definitions for each of the requested proxy
+ /// objects, each of which need to implement one of the service contracts that the client interacts
+ /// with. The toolchain also generates a mechanism to register a mapping of the interface/proxy
+ /// class types to their corresponding generated proxy instance types.
+ ///
+ /// Using that table of mappings, the Create method can then look up the appropriate generated
+ /// proxy instance class for the requested interface type and proxy class type, and return an
+ /// instantiation of that proxy instance class.
+ /// </remarks>
+ public abstract class DispatchProxy
+ {
+ protected DispatchProxy()
+ {
+ }
+
+ /// <summary>
+ /// Whenever any method on the generated proxy type is called, this method
+ /// will be invoked to dispatch control to the DispatchProxy implementation class.
+ /// </summary>
+ /// <param name="targetMethod">The method the caller invoked</param>
+ /// <param name="args">The arguments the caller passed to the method</param>
+ /// <returns>The object to return to the caller, or <c>null</c> for void methods</returns>
+ protected abstract object Invoke(MethodInfo targetMethod, object[] args);
+
+ /// <summary>
+ /// Creates an object instance that derives from class <typeparamref name="TProxy"/>
+ /// and implements interface <typeparamref name="T"/>.
+ /// </summary>
+ /// <typeparam name="T">The interface the proxy should implement.</typeparam>
+ /// <typeparam name="TProxy">The base class to use for the proxy class.</typeparam>
+ /// <returns>An object instance that implements <typeparamref name="T"/>.</returns>
+ /// <exception cref="System.ArgumentException"><typeparamref name="T"/> is a class,
+ /// or <typeparamref name="TProxy"/> is sealed or does not have a parameterless constructor</exception>
+ public static T Create<T, TProxy>()
+ where TProxy : DispatchProxy
+ {
+ RuntimeTypeHandle proxyClassTypeHandle = typeof(TProxy).TypeHandle;
+ RuntimeTypeHandle interfaceTypeHandle = typeof(T).TypeHandle;
+
+ RuntimeTypeHandle implClassTypeHandle =
+ DispatchProxyHelpers.GetConcreteProxyType(proxyClassTypeHandle, interfaceTypeHandle);
+ return (T)InteropExtensions.RuntimeNewObject(implClassTypeHandle);
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Reflection/DispatchProxyEntry.cs b/src/System.Private.Interop/src/System/Reflection/DispatchProxyEntry.cs
new file mode 100644
index 000000000..fda3c256a
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Reflection/DispatchProxyEntry.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;
+
+namespace System.Reflection
+{
+ /// <summary>
+ /// A record for dispatch proxies that maps an interface type and proxy class type to a proxy
+ /// instance class type that was generated by the toolchain at compile-time.
+ /// </summary>
+ public struct DispatchProxyEntry
+ {
+ public RuntimeTypeHandle ProxyClassType { get; set; }
+ public RuntimeTypeHandle InterfaceType { get; set; }
+ public RuntimeTypeHandle ImplementationClassType { get; set; }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Reflection/DispatchProxyHelpers.cs b/src/System.Private.Interop/src/System/Reflection/DispatchProxyHelpers.cs
new file mode 100644
index 000000000..7bfb6e1d1
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Reflection/DispatchProxyHelpers.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;
+
+namespace System.Reflection
+{
+ /// <summary>
+ /// Provides supporting functionality for DispatchProxy. Primarily this maintains a lookup
+ /// table for dispatch proxy that maps proxy classes/interfaces => generated proxy instance
+ /// classes, for each call to DispatchProxy.Create<ItfT, ProxyClassT>.
+ /// </summary>
+ /// <seealso cref="System.Reflection.DispatchProxy" />
+ public static class DispatchProxyHelpers
+ {
+ private static DispatchProxyEntry[] s_entryTable;
+
+ /// <summary>
+ /// Mechanism for the toolchain to register a lookup table of DispatchProxyEntry
+ /// records.
+ /// </summary>
+ /// <param name="entryTable">The toolchain-generated lookup table of DispatchProxyEntry
+ /// records.</param>
+ /// <seealso cref="System.Reflection.DispatchProxyEntry "/>
+ public static void RegisterImplementations(DispatchProxyEntry[] entryTable)
+ {
+ s_entryTable = entryTable;
+ }
+
+ /// <summary>
+ /// Finds the appropriate toolchain-generated proxy instance class for the given
+ /// interface and proxy class.
+ /// </summary>
+ /// <param name="proxyClassTypeHandle">The proxy class the proxy instance class derives from/
+ /// forwards its method calls to.</param>
+ /// <param name="interfaceTypeHandle">The interface that the proxy instance class
+ /// implements.</param>
+ /// <returns>The type handle for the requested proxy instance class type.</returns>
+ /// <exception cref="System.Reflection.DispatchProxyInstanceNotFoundException">
+ /// Thrown when no generated proxy instance class exists for the requested proxy class
+ /// and interface class types.
+ /// </exception>
+ public static RuntimeTypeHandle GetConcreteProxyType(RuntimeTypeHandle proxyClassTypeHandle,
+ RuntimeTypeHandle interfaceTypeHandle)
+ {
+ for (int i = 0; i < s_entryTable.Length; i++)
+ {
+ if ((s_entryTable[i].ProxyClassType.Equals(proxyClassTypeHandle)) &&
+ (s_entryTable[i].InterfaceType.Equals(interfaceTypeHandle)))
+ {
+ return s_entryTable[i].ImplementationClassType;
+ }
+ }
+
+ throw new DispatchProxyInstanceNotFoundException(
+ "Could not find an DispatchProxy implementation class for the interface type '" +
+ interfaceTypeHandle.ToString() + "' and the proxy class type '" +
+ proxyClassTypeHandle.ToString() + "'."
+ );
+ }
+
+ /// <summary>
+ /// This is just a marker method to be picked up later during IL transformations. This is actually
+ /// implemented by the "DispatchProxyIntrinsics" IL transformation, where the calling method is
+ /// expected to have a methodimpl record indicating the implemented method. The IL transform will
+ /// emit a ldtoken in that method.
+ /// </summary>
+ /// <exception cref="System.NotSupportedException">This method should never be called, so if
+ /// someone tries to call it, we throw this exception instead.</exception>
+ public static RuntimeMethodHandle GetCorrespondingInterfaceMethodFromMethodImpl()
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Reflection/DispatchProxyInstanceNotFoundException.cs b/src/System.Private.Interop/src/System/Reflection/DispatchProxyInstanceNotFoundException.cs
new file mode 100644
index 000000000..a61a514d3
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Reflection/DispatchProxyInstanceNotFoundException.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.Reflection
+{
+ /// <summary>
+ /// Exception thrown if we cannot find an dispatch proxy instance type for a requested interface
+ /// and proxy class type.
+ /// </summary>
+ public class DispatchProxyInstanceNotFoundException : System.Exception
+ {
+ public DispatchProxyInstanceNotFoundException()
+ {
+ }
+
+ public DispatchProxyInstanceNotFoundException(string message) :
+ base(message)
+ {
+ }
+
+ public DispatchProxyInstanceNotFoundException(string message, Exception inner) :
+ base(message, inner)
+ {
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/RhBaseName.cs b/src/System.Private.Interop/src/System/RhBaseName.cs
new file mode 100644
index 000000000..9d1cbbfb0
--- /dev/null
+++ b/src/System.Private.Interop/src/System/RhBaseName.cs
@@ -0,0 +1,3 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+internal class Redhawk { public const string BaseName = "[MRT]"; }
diff --git a/src/System.Private.Interop/src/System/Runtime/CompilerServices/FunctionPointerHelpers.cs b/src/System.Private.Interop/src/System/Runtime/CompilerServices/FunctionPointerHelpers.cs
new file mode 100644
index 000000000..4fb9aedb2
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/CompilerServices/FunctionPointerHelpers.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.CompilerServices
+{
+ using Internal.Runtime.Augments;
+
+ public static class FunctionPointerHelpers
+ {
+ public static Delegate UnsafeDelegateFromStaticMethodFunctionPointer(System.Type delegateType, IntPtr pfnStaticManagedMethod)
+ {
+ return RuntimeAugments.CreateDelegate(
+ delegateType.TypeHandle,
+ pfnStaticManagedMethod,
+ thisObject: null, isStatic: true, isOpen: true);
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/CompilerServices/IgnoresAccessChecksToAttribute.cs b/src/System.Private.Interop/src/System/Runtime/CompilerServices/IgnoresAccessChecksToAttribute.cs
new file mode 100644
index 000000000..85e23e96d
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/CompilerServices/IgnoresAccessChecksToAttribute.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.
+
+using System;
+using System.Text;
+
+namespace System.Runtime.CompilerServices
+{
+ [AttributeUsageAttribute(AttributeTargets.Assembly, AllowMultiple = true)]
+ public class IgnoresAccessChecksToAttribute : Attribute
+ {
+ private string _assemblyName;
+ public IgnoresAccessChecksToAttribute(string assemblyName)
+ {
+ _assemblyName = assemblyName;
+ }
+ public string AssemblyName
+ {
+ get { return _assemblyName; }
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/CompilerServices/McgResource.cs b/src/System.Private.Interop/src/System/Runtime/CompilerServices/McgResource.cs
new file mode 100644
index 000000000..3c5223524
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/CompilerServices/McgResource.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;
+
+namespace System.Runtime.CompilerServices
+{
+ //
+ // DLL interface to the localization infrastructure.
+ //
+ public static class McgResource
+ {
+ public static string GetResourceString(string resourceKey, string defaultString)
+ {
+ return SR.GetResourceString(resourceKey, defaultString);
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/CompilerServices/ModuleConstructorAttribute.cs b/src/System.Private.Interop/src/System/Runtime/CompilerServices/ModuleConstructorAttribute.cs
new file mode 100644
index 000000000..62f49b7a9
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/CompilerServices/ModuleConstructorAttribute.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.
+
+using System;
+
+namespace System.Runtime.CompilerServices
+{
+ // If a class is marked with [ModuleConstructorAttribute], we will treat this class's .cctor as module .cctor during ILTransform since C# doesn't support write module .cctor directly
+ // We can use this attribute to control initialize order inside a module and module dependency(in StartUpCodeInjectorTransform) controls initialize order between modules
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
+ public sealed class ModuleConstructorAttribute : Attribute
+ {
+ public ModuleConstructorAttribute()
+ {
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/CompilerServices/UnmanagedValueTypeConstraintAttribute.cs b/src/System.Private.Interop/src/System/Runtime/CompilerServices/UnmanagedValueTypeConstraintAttribute.cs
new file mode 100644
index 000000000..1758f3f43
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/CompilerServices/UnmanagedValueTypeConstraintAttribute.cs
@@ -0,0 +1,13 @@
+// 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.CompilerServices
+{
+ /// <summary>
+ /// This attribute is applied by the system C# compiler on generic type arguments that are using
+ /// the "unmanaged struct" constraint.
+ /// </summary>
+ internal sealed class UnmanagedValueTypeConstraintAttribute : Attribute
+ {
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ArrayWithOffset.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ArrayWithOffset.cs
new file mode 100644
index 000000000..8bfd7bb7f
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ArrayWithOffset.cs
@@ -0,0 +1,109 @@
+// 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.CompilerServices;
+using System.Runtime.Versioning;
+
+namespace System.Runtime.InteropServices
+{
+ public struct ArrayWithOffset
+ {
+ // Fromm MAX_SIZE_FOR_INTEROP in mlinfo.h
+ private const int MaxSizeForInterop = 0x7ffffff0;
+
+ 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);
+ }
+
+ private int CalculateCount()
+ {
+ if (m_array == null)
+ {
+ if (m_offset != 0)
+ {
+ throw new IndexOutOfRangeException(SR.ArrayWithOffsetOverflow);
+ }
+
+ return 0;
+ }
+ else
+ {
+ Array arrayObj = m_array as Array;
+ if (arrayObj == null)
+ {
+ throw new ArgumentException(SR.Arg_NotIsomorphic);
+ }
+
+ if (arrayObj.Rank != 1)
+ {
+ throw new ArgumentException(SR.Arg_NotIsomorphic);
+ }
+
+ if (!arrayObj.IsElementTypeBlittable())
+ {
+ throw new ArgumentException(SR.Arg_NotIsomorphic);
+ }
+
+ int totalSize = checked(arrayObj.Length * arrayObj.GetElementSize());
+ if (totalSize > MaxSizeForInterop)
+ {
+ throw new ArgumentException(SR.StructArrayTooLarge);
+ }
+
+ if (m_offset > totalSize)
+ {
+ throw new IndexOutOfRangeException(SR.ArrayWithOffsetOverflow);
+ }
+
+ return totalSize - m_offset;
+ }
+ }
+
+ private Object m_array;
+ private int m_offset;
+ private int m_count;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/BStrWrapper.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/BStrWrapper.cs
new file mode 100644
index 000000000..120ca0036
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/BStrWrapper.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.
+
+/*=============================================================================
+**
+** Class: BStrWrapper.
+**
+**
+** Purpose: Wrapper that is converted to a variant with VT_BSTR.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public sealed class BStrWrapper
+ {
+ public BStrWrapper(String value)
+ {
+ m_WrappedObject = value;
+ }
+
+ public BStrWrapper(Object value)
+ {
+ m_WrappedObject = (String)value;
+ }
+
+ public String WrappedObject
+ {
+ get
+ {
+ return m_WrappedObject;
+ }
+ }
+
+ private String m_WrappedObject;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/BestFitMappingAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/BestFitMappingAttribute.cs
new file mode 100644
index 000000000..2b0f1c161
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/BestFitMappingAttribute.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)]
+ public sealed class BestFitMappingAttribute : Attribute
+ {
+ internal bool _bestFitMapping;
+
+ public BestFitMappingAttribute(bool BestFitMapping)
+ {
+ _bestFitMapping = BestFitMapping;
+ }
+
+ public bool BestFitMapping { get { return _bestFitMapping; } }
+ public bool ThrowOnUnmappableChar;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ClassInterfaceAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ClassInterfaceAttribute.cs
new file mode 100644
index 000000000..9de77250a
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ClassInterfaceAttribute.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, Inherited = false)]
+ 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; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ClassInterfaceType.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ClassInterfaceType.cs
new file mode 100644
index 000000000..d666746a4
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ClassInterfaceType.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
+{
+ public enum ClassInterfaceType
+ {
+ None = 0,
+ AutoDispatch = 1,
+ AutoDual = 2
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/CoClassAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/CoClassAttribute.cs
new file mode 100644
index 000000000..6e77dc962
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/CoClassAttribute.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Interface, Inherited = false)]
+ public sealed class CoClassAttribute : Attribute
+ {
+ internal Type _CoClass;
+
+ public CoClassAttribute(Type coClass)
+ {
+ _CoClass = coClass;
+ }
+
+ public Type CoClass { get { return _CoClass; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComAwareEventInfo.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComAwareEventInfo.cs
new file mode 100644
index 000000000..282e26dc9
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComAwareEventInfo.cs
@@ -0,0 +1,186 @@
+// 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.Reflection;
+
+using Internal.Reflection.Extensibility;
+
+namespace System.Runtime.InteropServices
+{
+ public class ComAwareEventInfo : ExtensibleEventInfo
+ {
+#if FEATURE_COMAWAREEVENTINFO
+ #region private fields
+ private System.Reflection.EventInfo _innerEventInfo;
+ #endregion
+
+ #region ctor
+ public ComAwareEventInfo(Type type, string eventName)
+ {
+ _innerEventInfo = type.GetEvent(eventName);
+ }
+ #endregion
+
+ #region protected overrides
+ public override void AddEventHandler(object target, Delegate handler)
+ {
+ if (Marshal.IsComObject(target))
+ {
+ // retrieve sourceIid and dispid
+ Guid sourceIid;
+ int dispid;
+ GetDataForComInvocation(_innerEventInfo, out sourceIid, out dispid);
+
+ // now validate the caller can call into native and redirect to ComEventHelpers.Combine
+ SecurityPermission perm = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
+ perm.Demand();
+ System.Runtime.InteropServices.ComEventsHelper.Combine(target, sourceIid, dispid, handler);
+ }
+ else
+ {
+ // we are dealing with a managed object - just add the delegate through reflection
+ _innerEventInfo.AddEventHandler(target, handler);
+ }
+ }
+
+ public override void RemoveEventHandler(object target, Delegate handler)
+ {
+ if (Marshal.IsComObject(target))
+ {
+ // retrieve sourceIid and dispid
+ Guid sourceIid;
+ int dispid;
+ GetDataForComInvocation(_innerEventInfo, out sourceIid, out dispid);
+
+ // now validate the caller can call into native and redirect to ComEventHelpers.Combine
+ SecurityPermission perm = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
+ perm.Demand();
+ System.Runtime.InteropServices.ComEventsHelper.Remove(target, sourceIid, dispid, handler);
+ }
+ else
+ {
+ // we are dealing with a managed object - just add the delegate through relection
+ _innerEventInfo.RemoveEventHandler(target, handler);
+ }
+ }
+ #endregion
+
+ #region public overrides
+ public override System.Reflection.EventAttributes Attributes
+ {
+ get { return _innerEventInfo.Attributes; }
+ }
+
+ public override System.Reflection.MethodInfo GetAddMethod(bool nonPublic)
+ {
+ return _innerEventInfo.GetAddMethod(nonPublic);
+ }
+
+ public override System.Reflection.MethodInfo GetRaiseMethod(bool nonPublic)
+ {
+ return _innerEventInfo.GetRaiseMethod(nonPublic);
+ }
+
+ public override System.Reflection.MethodInfo GetRemoveMethod(bool nonPublic)
+ {
+ return _innerEventInfo.GetRemoveMethod(nonPublic);
+ }
+
+ public override Type DeclaringType
+ {
+ get { return _innerEventInfo.DeclaringType; }
+ }
+
+ public override object[] GetCustomAttributes(Type attributeType, bool inherit)
+ {
+ return _innerEventInfo.GetCustomAttributes(attributeType, inherit);
+ }
+
+ public override object[] GetCustomAttributes(bool inherit)
+ {
+ return _innerEventInfo.GetCustomAttributes(inherit);
+ }
+
+ public override bool IsDefined(Type attributeType, bool inherit)
+ {
+ return _innerEventInfo.IsDefined(attributeType, inherit);
+ }
+
+ public override string Name
+ {
+ get { return _innerEventInfo.Name; }
+ }
+
+ public override Type ReflectedType
+ {
+ get { return _innerEventInfo.ReflectedType; }
+ }
+ #endregion
+
+ #region private methods
+
+ private static void GetDataForComInvocation(System.Reflection.EventInfo eventInfo, out Guid sourceIid, out int dispid)
+ {
+ object[] comEventInterfaces = eventInfo.DeclaringType.GetCustomAttributes(typeof(ComEventInterfaceAttribute), false);
+
+ if (comEventInterfaces == null || comEventInterfaces.Length == 0)
+ {
+ // TODO: event strings need to be localizable
+ throw new InvalidOperationException("event invocation for COM objects requires interface to be attributed with ComSourceInterfaceGuidAttribute");
+ }
+
+ if (comEventInterfaces.Length > 1)
+ {
+ // TODO: event strings need to be localizable
+ throw new System.Reflection.AmbiguousMatchException("more than one ComSourceInterfaceGuidAttribute found");
+ }
+
+ Type sourceItf = ((ComEventInterfaceAttribute)comEventInterfaces[0]).SourceInterface;
+ Guid guid = sourceItf.GUID;
+
+ System.Reflection.MethodInfo methodInfo = sourceItf.GetMethod(eventInfo.Name);
+ Attribute dispIdAttribute = Attribute.GetCustomAttribute(methodInfo, typeof(DispIdAttribute));
+ if (dispIdAttribute == null)
+ {
+ // TODO: event strings need to be localizable
+ throw new InvalidOperationException("event invocation for COM objects requires event to be attributed with DispIdAttribute");
+ }
+
+ sourceIid = guid;
+ dispid = ((DispIdAttribute)dispIdAttribute).Value;
+ }
+ #endregion
+#else
+ public ComAwareEventInfo(Type type, string eventName)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public override System.Reflection.EventAttributes Attributes
+ {
+ get { throw new PlatformNotSupportedException(); }
+ }
+
+ public override Type DeclaringType
+ {
+ get { throw new PlatformNotSupportedException(); }
+ }
+
+ public override string Name
+ {
+ get { throw new PlatformNotSupportedException(); }
+ }
+
+ public override void AddEventHandler(object target, Delegate handler)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public override void RemoveEventHandler(object target, Delegate handler)
+ {
+ throw new PlatformNotSupportedException();
+ }
+#endif // FEATURE_COMAWAREEVENTINFO
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComDefaultInterfaceAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComDefaultInterfaceAttribute.cs
new file mode 100644
index 000000000..077f95635
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComDefaultInterfaceAttribute.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Class, Inherited = false)]
+ public sealed class ComDefaultInterfaceAttribute : Attribute
+ {
+ internal Type _val;
+
+ public ComDefaultInterfaceAttribute(Type defaultInterface)
+ {
+ _val = defaultInterface;
+ }
+
+ public Type Value { get { return _val; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComEventInterfaceAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComEventInterfaceAttribute.cs
new file mode 100644
index 000000000..3fa237285
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComEventInterfaceAttribute.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Interface, Inherited = false)]
+ 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; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComEventsHelper.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComEventsHelper.cs
new file mode 100644
index 000000000..c7aec9998
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComEventsHelper.cs
@@ -0,0 +1,227 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+
+/*============================================================
+**
+** Class: ComEventsHelper
+**
+** Purpose: ComEventHelpers APIs allow binding
+** managed delegates to COM's connection point based events.
+**
+** Date: April 2008
+**/
+
+using System;
+
+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
+
+ /// <summary>
+ /// The static methods provided in ComEventsHelper allow using .NET delegates to subscribe to events
+ /// raised COM objects.
+ /// </summary>
+ public static class ComEventsHelper
+ {
+#if FEATURE_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 (RemotingServices.IsTransparentProxy(rcw))
+ {
+ IntPtr punk = Marshal.GetIUnknownForObject(rcw);
+ try
+ {
+ rcw = Marshal.GetObjectForIUnknown(punk);
+ }
+ finally
+ {
+ Marshal.Release(punk);
+ }
+ }
+
+ return rcw;
+ }
+#else
+ public static void Combine(object rcw, Guid iid, int dispid, Delegate d)
+ {
+ throw new PlatformNotSupportedException();
+ }
+ public static Delegate Remove(object rcw, Guid iid, int dispid, Delegate d)
+ {
+ throw new PlatformNotSupportedException();
+ }
+#endif // FEATURE_COMEVENTSHELPER
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComImportAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComImportAttribute.cs
new file mode 100644
index 000000000..95993d7a3
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComImportAttribute.cs
@@ -0,0 +1,12 @@
+// 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
+{
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = false)]
+ public sealed class ComImportAttribute : Attribute
+ {
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComInterfaceType.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComInterfaceType.cs
new file mode 100644
index 000000000..1c8c95776
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComInterfaceType.cs
@@ -0,0 +1,15 @@
+// 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
+{
+ public enum ComInterfaceType
+ {
+ InterfaceIsDual = 0,
+ InterfaceIsIUnknown = 1,
+ InterfaceIsIDispatch = 2,
+ InterfaceIsIInspectable = 3,
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComMemberType.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComMemberType.cs
new file mode 100644
index 000000000..602661f30
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComMemberType.cs
@@ -0,0 +1,12 @@
+// 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
+{
+ public enum ComMemberType
+ {
+ Method = 0,
+ PropGet = 1,
+ PropSet = 2
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComSourceInterfacesAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComSourceInterfacesAttribute.cs
new file mode 100644
index 000000000..3f406689b
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComSourceInterfacesAttribute.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;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Class, Inherited = 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; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IAdviseSink.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IAdviseSink.cs
new file mode 100644
index 000000000..daeab52d0
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IAdviseSink.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;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ /// <devdoc>
+ /// The IAdviseSink interface enables containers and other objects to
+ /// receive notifications of data changes, view changes, and compound-document
+ /// changes occurring in objects of interest. Container applications, for
+ /// example, require such notifications to keep cached presentations of their
+ /// linked and embedded objects up-to-date. Calls to IAdviseSink methods are
+ /// asynchronous, so the call is sent and then the next instruction is executed
+ /// without waiting for the call's return.
+ /// </devdoc>
+ [ComImport]
+ [Guid("0000010F-0000-0000-C000-000000000046")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IAdviseSink
+ {
+ /// <devdoc>
+ /// Called by the server to notify a data object's currently registered
+ /// advise sinks that data in the object has changed.
+ /// </devdoc>
+ [PreserveSig]
+ void OnDataChange([In] ref FORMATETC format, [In] ref STGMEDIUM stgmedium);
+
+ /// <devdoc>
+ /// Notifies an object's registered advise sinks that its view has changed.
+ /// </devdoc>
+ [PreserveSig]
+ void OnViewChange(int aspect, int index);
+
+ /// <devdoc>
+ /// Called by the server to notify all registered advisory sinks that
+ /// the object has been renamed.
+ /// </devdoc>
+ [PreserveSig]
+ void OnRename(IMoniker moniker);
+
+ /// <devdoc>
+ /// Called by the server to notify all registered advisory sinks that
+ /// the object has been saved.
+ /// </devdoc>
+ [PreserveSig]
+ void OnSave();
+
+ /// <devdoc>
+ /// Called by the server to notify all registered advisory sinks that the
+ /// object has changed from the running to the loaded state.
+ /// </devdoc>
+ [PreserveSig]
+ void OnClose();
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IBindCtx.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IBindCtx.cs
new file mode 100644
index 000000000..e9e37c09a
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IBindCtx.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.
+
+/*=============================================================================
+**
+** Class: IBindCtx
+**
+**
+** Purpose: IBindCtx interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IConnectionPoint.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IConnectionPoint.cs
new file mode 100644
index 000000000..80fef354c
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IConnectionPoint.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.
+
+/*=============================================================================
+**
+** Class: IConnectionPoint
+**
+**
+** Purpose: IConnectionPoint interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IConnectionPointContainer.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IConnectionPointContainer.cs
new file mode 100644
index 000000000..a397ae515
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IConnectionPointContainer.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.
+
+/*=============================================================================
+**
+** Class: IConnectionPointContainer
+**
+**
+** Purpose: IConnectionPointContainer interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumConnectionPoints.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumConnectionPoints.cs
new file mode 100644
index 000000000..8665f1a1c
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumConnectionPoints.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.
+
+/*=============================================================================
+**
+** Class: IEnumConnectionPoints
+**
+**
+** Purpose: IEnumConnectionPoints interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumConnections.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumConnections.cs
new file mode 100644
index 000000000..db1d9a354
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumConnections.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.
+
+/*=============================================================================
+**
+** Class: IEnumConnections
+**
+**
+** Purpose: IEnumConnections interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumFormatETC.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumFormatETC.cs
new file mode 100644
index 000000000..02c5f10f5
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumFormatETC.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.
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ /// <devdoc>
+ /// The IEnumFORMATETC interface is used to enumerate an array of FORMATETC
+ /// structures. IEnumFORMATETC has the same methods as all enumerator interfaces:
+ /// Next, Skip, Reset, and Clone.
+ /// </devdoc>
+ [ComImport()]
+ [Guid("00000103-0000-0000-C000-000000000046")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IEnumFORMATETC
+ {
+ /// <devdoc>
+ /// Retrieves the next celt items in the enumeration sequence. If there are
+ /// fewer than the requested number of elements left in the sequence, it
+ /// retrieves the remaining elements. The number of elements actually
+ /// retrieved is returned through pceltFetched (unless the caller passed
+ /// in NULL for that parameter).
+ /// </devdoc>
+ [PreserveSig]
+ int Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] FORMATETC[] rgelt, [Out, MarshalAs(UnmanagedType.LPArray)] int[] pceltFetched);
+
+ /// <devdoc>
+ /// Skips over the next specified number of elements in the enumeration sequence.
+ /// </devdoc>
+ [PreserveSig]
+ int Skip(int celt);
+
+ /// <devdoc>
+ /// Resets the enumeration sequence to the beginning.
+ /// </devdoc>
+ [PreserveSig]
+ int Reset();
+
+ /// <devdoc>
+ /// Creates another enumerator that contains the same enumeration state as
+ /// the current one. Using this function, a client can record a particular
+ /// point in the enumeration sequence and then return to that point at a
+ /// later time. The new enumerator supports the same interface as the original one.
+ /// </devdoc>
+ void Clone(out IEnumFORMATETC newEnum);
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumMoniker.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumMoniker.cs
new file mode 100644
index 000000000..fd324efb5
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumMoniker.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.
+
+/*=============================================================================
+**
+** Class: IEnumMoniker
+**
+**
+** Purpose: IEnumMoniker interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumString.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumString.cs
new file mode 100644
index 000000000..c33f5bc67
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumString.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.
+
+/*=============================================================================
+**
+** Class: IEnumString
+**
+**
+** Purpose: IEnumString interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumVARIANT.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumVARIANT.cs
new file mode 100644
index 000000000..584033faf
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IEnumVARIANT.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.
+
+/*=============================================================================
+**
+** Class: IEnumVARIANT
+**
+**
+** Purpose: IEnumVARIANT interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IMoniker.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IMoniker.cs
new file mode 100644
index 000000000..fe1512163
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IMoniker.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.
+
+/*=============================================================================
+**
+** Class: IMoniker
+**
+**
+** Purpose: IMoniker interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IPersistFile.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IPersistFile.cs
new file mode 100644
index 000000000..549492831
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IPersistFile.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.
+
+/*=============================================================================
+**
+** Class: IPersistFile
+**
+**
+** Purpose: IPersistFile interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IRunningObjectTable.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IRunningObjectTable.cs
new file mode 100644
index 000000000..5c3cdbc88
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IRunningObjectTable.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.
+
+/*=============================================================================
+**
+** Class: IRunningObjectTable
+**
+**
+** Purpose: IRunningObjectTable interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IStream.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IStream.cs
new file mode 100644
index 000000000..b7f0b0d9f
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/IStream.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.
+
+/*=============================================================================
+**
+** Class: IStream
+**
+**
+** Purpose: IStream interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeComp.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeComp.cs
new file mode 100644
index 000000000..a83514ab6
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeComp.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.
+
+/*=============================================================================
+**
+** Class: ITypeComp
+**
+**
+** Purpose: ITypeComp interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeInfo.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeInfo.cs
new file mode 100644
index 000000000..c8f2f239e
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeInfo.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.
+
+/*=============================================================================
+**
+** Class: ITypeInfo
+**
+**
+** Purpose: ITypeInfo interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeInfo2.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeInfo2.cs
new file mode 100644
index 000000000..c7a43e29f
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeInfo2.cs
@@ -0,0 +1,62 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/*=============================================================================
+**
+** Class: ITypeInfo2
+**
+**
+** Purpose: ITypeInfo2 interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeLib.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeLib.cs
new file mode 100644
index 000000000..f927fee85
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeLib.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.
+
+/*=============================================================================
+**
+** Class: ITypeLib
+**
+**
+** Purpose: ITypeLib interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeLib2.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeLib2.cs
new file mode 100644
index 000000000..f2b4e56cf
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/ITypeLib2.cs
@@ -0,0 +1,42 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/*=============================================================================
+**
+** Class: ITypeLib2
+**
+**
+** Purpose: ITypeLib2 interface definition.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/advf.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/advf.cs
new file mode 100644
index 000000000..72abada6b
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/advf.cs
@@ -0,0 +1,19 @@
+// 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.ComTypes
+{
+ [Flags]
+ public enum ADVF
+ {
+ ADVF_NODATA = 1,
+ ADVF_PRIMEFIRST = 2,
+ ADVF_ONLYONCE = 4,
+ ADVF_DATAONSTOP = 64,
+ ADVFCACHE_NOHANDLER = 8,
+ ADVFCACHE_FORCEBUILTIN = 16,
+ ADVFCACHE_ONSAVE = 32
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindopts.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindopts.cs
new file mode 100644
index 000000000..ded0fb547
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindopts.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct BIND_OPTS
+ {
+ public int cbStruct;
+ public int grfFlags;
+ public int grfMode;
+ public int dwTickCountDeadline;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindptr.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindptr.cs
new file mode 100644
index 000000000..c0fca49d7
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindptr.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;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
+ public struct BINDPTR
+ {
+ [FieldOffset(0)]
+ public IntPtr lpfuncdesc;
+ [FieldOffset(0)]
+ public IntPtr lpvardesc;
+ [FieldOffset(0)]
+ public IntPtr lptcomp;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/callconv.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/callconv.cs
new file mode 100644
index 000000000..9f78c534f
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/callconv.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ 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
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/connectdata.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/connectdata.cs
new file mode 100644
index 000000000..2ebfa6ba2
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/connectdata.cs
@@ -0,0 +1,19 @@
+// 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.ComTypes
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct CONNECTDATA
+ {
+ [MarshalAs(UnmanagedType.Interface)]
+ public Object pUnk;
+ public int dwCookie;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/datadir.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/datadir.cs
new file mode 100644
index 000000000..14d081b85
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/datadir.cs
@@ -0,0 +1,13 @@
+// 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.ComTypes
+{
+ public enum DATADIR
+ {
+ DATADIR_GET = 1,
+ DATADIR_SET = 2
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/desckind.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/desckind.cs
new file mode 100644
index 000000000..18700b345
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/desckind.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ 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
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dispparams.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dispparams.cs
new file mode 100644
index 000000000..7dca32172
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dispparams.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct DISPPARAMS
+ {
+ public IntPtr rgvarg;
+ public IntPtr rgdispidNamedArgs;
+ public int cArgs;
+ public int cNamedArgs;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dvaspect.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dvaspect.cs
new file mode 100644
index 000000000..dfc12329e
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dvaspect.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [Flags]
+ public enum DVASPECT
+ {
+ DVASPECT_CONTENT = 1,
+ DVASPECT_THUMBNAIL = 2,
+ DVASPECT_ICON = 4,
+ DVASPECT_DOCPRINT = 8
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/elemdesc.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/elemdesc.cs
new file mode 100644
index 000000000..b07e51e2f
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/elemdesc.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct ELEMDESC
+ {
+ public TYPEDESC tdesc;
+
+ [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
+ public struct DESCUNION
+ {
+ [FieldOffset(0)]
+ public IDLDESC idldesc;
+ [FieldOffset(0)]
+ public PARAMDESC paramdesc;
+ };
+ public DESCUNION desc;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/excepinfo.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/excepinfo.cs
new file mode 100644
index 000000000..fe95fce5c
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/excepinfo.cs
@@ -0,0 +1,24 @@
+// 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.ComTypes
+{
+ [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;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/filetime.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/filetime.cs
new file mode 100644
index 000000000..9901c7991
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/filetime.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.ComTypes
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct FILETIME
+ {
+ public int dwLowDateTime;
+ public int dwHighDateTime;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/formatetc.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/formatetc.cs
new file mode 100644
index 000000000..3e5ac49ee
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/formatetc.cs
@@ -0,0 +1,19 @@
+// 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.ComTypes
+{
+ public struct FORMATETC
+ {
+ [MarshalAs(UnmanagedType.U2)]
+ public short cfFormat;
+ public IntPtr ptd;
+ [MarshalAs(UnmanagedType.U4)]
+ public DVASPECT dwAspect;
+ public int lindex;
+ [MarshalAs(UnmanagedType.U4)]
+ public TYMED tymed;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcdesc.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcdesc.cs
new file mode 100644
index 000000000..eb5b1edcf
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcdesc.cs
@@ -0,0 +1,24 @@
+// 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.ComTypes
+{
+ [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;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcflags.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcflags.cs
new file mode 100644
index 000000000..a97f28542
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcflags.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.ComTypes
+{
+ [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
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funckind.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funckind.cs
new file mode 100644
index 000000000..c5ac2a391
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funckind.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ public enum FUNCKIND : int
+ {
+ FUNC_VIRTUAL = 0,
+ FUNC_PUREVIRTUAL = 1,
+ FUNC_NONVIRTUAL = 2,
+ FUNC_STATIC = 3,
+ FUNC_DISPATCH = 4
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idldesc.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idldesc.cs
new file mode 100644
index 000000000..65076727a
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idldesc.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.ComTypes
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct IDLDESC
+ {
+ public IntPtr dwReserved;
+ public IDLFLAG wIDLFlags;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idlflag.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idlflag.cs
new file mode 100644
index 000000000..ee6520be8
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idlflag.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/impltypeflags.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/impltypeflags.cs
new file mode 100644
index 000000000..ad20c6c74
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/impltypeflags.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [Flags]
+ public enum IMPLTYPEFLAGS
+ {
+ IMPLTYPEFLAG_FDEFAULT = 0x1,
+ IMPLTYPEFLAG_FSOURCE = 0x2,
+ IMPLTYPEFLAG_FRESTRICTED = 0x4,
+ IMPLTYPEFLAG_FDEFAULTVTABLE = 0x8,
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/invokekind.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/invokekind.cs
new file mode 100644
index 000000000..cf99ac35d
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/invokekind.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [Flags]
+ public enum INVOKEKIND : int
+ {
+ INVOKE_FUNC = 0x1,
+ INVOKE_PROPERTYGET = 0x2,
+ INVOKE_PROPERTYPUT = 0x4,
+ INVOKE_PROPERTYPUTREF = 0x8
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/libflags.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/libflags.cs
new file mode 100644
index 000000000..ec6789c19
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/libflags.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [Flags]
+ public enum LIBFLAGS : short
+ {
+ LIBFLAG_FRESTRICTED = 0x1,
+ LIBFLAG_FCONTROL = 0x2,
+ LIBFLAG_FHIDDEN = 0x4,
+ LIBFLAG_FHASDISKIMAGE = 0x8
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramdesc.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramdesc.cs
new file mode 100644
index 000000000..e19d6d5d0
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramdesc.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.ComTypes
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct PARAMDESC
+ {
+ public IntPtr lpVarValue;
+ public PARAMFLAG wParamFlags;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramflag.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramflag.cs
new file mode 100644
index 000000000..9f01746b2
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramflag.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/statdata.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/statdata.cs
new file mode 100644
index 000000000..c97472774
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/statdata.cs
@@ -0,0 +1,15 @@
+// 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.ComTypes
+{
+ public struct STATDATA
+ {
+ public FORMATETC formatetc;
+ public ADVF advf;
+ public IAdviseSink advSink;
+ public int connection;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/statstg.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/statstg.cs
new file mode 100644
index 000000000..f947d2dde
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/statstg.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/stgmedium.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/stgmedium.cs
new file mode 100644
index 000000000..8d7cf44c0
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/stgmedium.cs
@@ -0,0 +1,15 @@
+// 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.ComTypes
+{
+ public struct STGMEDIUM
+ {
+ public TYMED tymed;
+ public IntPtr unionmember;
+ [MarshalAs(UnmanagedType.IUnknown)]
+ public object pUnkForRelease;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/syskind.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/syskind.cs
new file mode 100644
index 000000000..a3744289c
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/syskind.cs
@@ -0,0 +1,15 @@
+// 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.ComTypes
+{
+ public enum SYSKIND
+ {
+ SYS_WIN16 = 0,
+ SYS_WIN32 = SYS_WIN16 + 1,
+ SYS_MAC = SYS_WIN32 + 1,
+ SYS_WIN64 = SYS_MAC + 1
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/tymed.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/tymed.cs
new file mode 100644
index 000000000..8408f538b
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/tymed.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [Flags]
+ public enum TYMED
+ {
+ TYMED_HGLOBAL = 1,
+ TYMED_FILE = 2,
+ TYMED_ISTREAM = 4,
+ TYMED_ISTORAGE = 8,
+ TYMED_GDI = 16,
+ TYMED_MFPICT = 32,
+ TYMED_ENHMF = 64,
+ TYMED_NULL = 0
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeattr.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeattr.cs
new file mode 100644
index 000000000..c322430d2
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeattr.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typedesc.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typedesc.cs
new file mode 100644
index 000000000..30af4a0f8
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typedesc.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.ComTypes
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct TYPEDESC
+ {
+ public IntPtr lpValue;
+ public Int16 vt;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeflags.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeflags.cs
new file mode 100644
index 000000000..bf650bfc8
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeflags.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;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [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
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typekind.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typekind.cs
new file mode 100644
index 000000000..cc3909864
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typekind.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ 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
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typelibattr.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typelibattr.cs
new file mode 100644
index 000000000..88514b4ba
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typelibattr.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;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct TYPELIBATTR
+ {
+ public Guid guid;
+ public int lcid;
+ public SYSKIND syskind;
+ public Int16 wMajorVerNum;
+ public Int16 wMinorVerNum;
+ public LIBFLAGS wLibFlags;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/vardesc.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/vardesc.cs
new file mode 100644
index 000000000..86f37b4e3
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/vardesc.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.
+
+using System;
+
+namespace System.Runtime.InteropServices.ComTypes
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct VARDESC
+ {
+ public int memid;
+ public String lpstrSchema;
+
+ [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;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/varflags.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/varflags.cs
new file mode 100644
index 000000000..633a01310
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/varflags.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.ComTypes
+{
+ [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
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/varkind.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/varkind.cs
new file mode 100644
index 000000000..1c4eb57f9
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/varkind.cs
@@ -0,0 +1,19 @@
+// 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.ComTypes
+{
+ public enum VARKIND : int
+ {
+ VAR_PERINSTANCE = 0x0,
+ VAR_STATIC = 0x1,
+ VAR_CONST = 0x2,
+ VAR_DISPATCH = 0x3
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ComWeakReferenceHelpers.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComWeakReferenceHelpers.cs
new file mode 100644
index 000000000..c082b63d8
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ComWeakReferenceHelpers.cs
@@ -0,0 +1,180 @@
+// 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.Threading;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Diagnostics.Contracts;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// This class stores the weak references to the native COM Objects to ensure a way to map the weak
+ /// reference to the native ComObject target and keep the mapping alive until the native object is alive
+ /// allowing the connection to remain alive even though the managed wrapper might die.
+ /// </summary>
+ public static class COMWeakReferenceHelpers
+ {
+ // Holds the mapping from the weak reference to the COMWeakReference which is a thin wrapper for native WeakReference.
+ static ConditionalWeakTable<object, ComWeakReference> s_COMWeakReferenceTable = new ConditionalWeakTable<object, ComWeakReference>();
+
+ /// <summary>
+ /// This class is a thin wrapper that holds the native IWeakReference.
+ /// </summary>
+ internal class ComWeakReference
+ {
+ private IntPtr m_pComWeakRef;
+
+ internal ComWeakReference(ref IntPtr pUnk)
+ {
+ Contract.Assert(pUnk != IntPtr.Zero);
+
+ m_pComWeakRef = pUnk;
+ pUnk = IntPtr.Zero;
+ }
+
+ /// <summary>
+ /// This method validates that the given weak reference is alive.
+ /// 1. IWeakReference->Resolve method returns the target's interface for the mapping IID passed to it.
+ /// 2. If the object is not alive it returns null.
+ /// 2. From the returned interface we get or create a new RCW and return it.
+ /// </summary>
+ /// <returns></returns>
+ internal unsafe object Resolve()
+ {
+ IntPtr pInspectable;
+ __com_IWeakReference* pComIWeakReference = (__com_IWeakReference*)m_pComWeakRef;
+ Guid inspectableIID = Interop.COM.IID_IInspectable;
+ int result = CalliIntrinsics.StdCall__int(
+ pComIWeakReference->pVtable->pfnResolve,
+ m_pComWeakRef,
+ &inspectableIID,
+ &pInspectable);
+
+ if (result >= 0 && pInspectable != IntPtr.Zero)
+ {
+ try
+ {
+ return McgMarshal.ComInterfaceToObject(pInspectable, McgModuleManager.IInspectable);
+ }
+ finally
+ {
+ // Release the pInspectable.
+ McgMarshal.ComRelease(pInspectable);
+ }
+ }
+
+ return null;
+ }
+
+ ~ComWeakReference()
+ {
+#pragma warning disable 420 // FYI - ref m_pComWeakRef causes this.
+ IntPtr handle = Interlocked.Exchange(ref m_pComWeakRef, IntPtr.Zero);
+#pragma warning restore 420
+ McgMarshal.ComSafeRelease(handle);
+ }
+ }
+#pragma warning disable 649, 169 // Field 'blah' is never assigned to/Field 'blah' is never used
+ private unsafe struct __com_IWeakReferenceSource
+ {
+ internal __vtable_IWeakReferenceSource* pVtable;
+ }
+#pragma warning restore 649, 169
+
+ /// <summary>
+ /// This method gets called every time the WeakReference or WeakReference'1 set the Target.
+ /// We can have 4 possible combination here.
+ /// a. Target is a GC object and it is either getting set for the first time or previous object is also GC object.
+ /// In this case we do not need to do anything.
+ ///
+ /// b. Target is a GC object and previous target was __ComObject
+ /// i. We remove the element from ConditionalWeakTable.
+ /// ii. When the GC collects this ComWeakReference the finalizer will ensure that the native object is released.
+ ///
+ /// c. Target is a __ComObject and the previous target was null or GC object.
+ /// We simply add the new target to the dictionary.
+ ///
+ /// d. Target is a __COmObject and the previous object was __COmObject.
+ /// i. We first remove the element from the ConditionalWeakTable.
+ /// ii. When the GC collects the previous ComWeakReference the finalizer will ensure that the native object is released.
+ /// iii. We add the new ComWeakReference to the conditionalWeakTable.
+ /// </summary>
+ /// <param name="weakReference"></param>
+ /// <param name="target"></param>
+ public static unsafe void SetTarget(object weakReference, object target)
+ {
+ Contract.Assert(weakReference != null);
+
+ // Check if this weakReference is already associated with a native target.
+ ComWeakReference pOldComWeakReference;
+ if (s_COMWeakReferenceTable.TryGetValue(weakReference, out pOldComWeakReference))
+ {
+ // Remove the previous target.
+ // We do not have to release the native ComWeakReference since it will be done as part of the finalizer.
+ s_COMWeakReferenceTable.Remove(weakReference);
+ }
+
+ // Now check whether the current target is __ComObject.
+ // However, we don't want to pass the QI to a managed object deriving from native object - we
+ // would end up passing the QI to back the CCW and end up stack overflow
+ __ComObject comObject = target as __ComObject;
+ if (comObject != null && !comObject.ExtendsComObject)
+ {
+ // Get the IWeakReferenceSource for the given object
+ IntPtr pWeakRefSource = McgMarshal.ObjectToComInterface(comObject, McgModuleManager.IWeakReferenceSource);
+
+ if (pWeakRefSource != IntPtr.Zero)
+ {
+ IntPtr pWeakRef = IntPtr.Zero;
+ try
+ {
+ // Now that we have the IWeakReferenceSource , we need to call the GetWeakReference method to get the corresponding IWeakReference
+ __com_IWeakReferenceSource* pComWeakRefSource = (__com_IWeakReferenceSource*)pWeakRefSource;
+ int result = CalliIntrinsics.StdCall<int>(
+ pComWeakRefSource->pVtable->pfnGetWeakReference,
+ pWeakRefSource,
+ out pWeakRef);
+ if (result >= 0 && pWeakRef != IntPtr.Zero)
+ {
+ // Since we have already checked s_COMWeakReferenceTable for the weak reference, we can simply add the entry w/o checking.
+ // PS - We do not release the pWeakRef as it should be alive until the ComWeakReference is alive.
+ s_COMWeakReferenceTable.Add(weakReference, new ComWeakReference(ref pWeakRef));
+ }
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pWeakRef);
+ McgMarshal.ComRelease(pWeakRefSource);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// This method gets the native target for the current weak reference if present.
+ /// This is done as a 2 step process.
+ /// a. Fetch the native target for the weakreference through conditionalweaktable lookup.
+ /// b. Checking whether the native object is alive by calling the IWeakReference->Resolve method.
+ /// </summary>
+ /// <param name="weakReference"></param>
+ /// <returns></returns>
+ public static object GetTarget(object weakReference)
+ {
+ Contract.Assert(weakReference != null);
+
+ ComWeakReference comWeakRef;
+ if (s_COMWeakReferenceTable.TryGetValue(weakReference, out comWeakRef))
+ {
+ return comWeakRef.Resolve();
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/CriticalHandle.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/CriticalHandle.cs
new file mode 100644
index 000000000..b842c6043
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/CriticalHandle.cs
@@ -0,0 +1,236 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+//
+
+//
+
+/*============================================================
+**
+** Class: CriticalHandle
+**
+**
+** 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.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+using System.Reflection;
+using System.Threading;
+
+/*
+ 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 (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.
+ public abstract class CriticalHandle : IDisposable
+ {
+ protected internal 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.
+ protected CriticalHandle(IntPtr invalidHandleValue)
+ {
+ handle = invalidHandleValue;
+ _isClosed = false;
+ }
+
+ ~CriticalHandle()
+ {
+ Dispose(false);
+ }
+
+ 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();
+
+ ReleaseHandle();
+
+ Marshal.SetLastWin32Error(lastError);
+
+ GC.SuppressFinalize(this);
+ }
+
+ 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
+ {
+ 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
+ {
+ get;
+ }
+
+ public void Close()
+ {
+ Dispose(true);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ 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!
+ 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).
+ protected abstract bool ReleaseHandle();
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/CurrencyWrapper.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/CurrencyWrapper.cs
new file mode 100644
index 000000000..4e7308319
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/CurrencyWrapper.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.
+
+//
+
+//
+
+/*=============================================================================
+**
+** Class: CurrencyWrapper.
+**
+**
+** Purpose: Wrapper that is converted to a variant with VT_CURRENCY.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public sealed class CurrencyWrapper
+ {
+ public CurrencyWrapper(Decimal obj)
+ {
+ m_WrappedObject = obj;
+ }
+
+ public CurrencyWrapper(Object obj)
+ {
+ if (!(obj is Decimal))
+ throw new ArgumentException(SR.Arg_MustBeDecimal, "obj");
+
+ m_WrappedObject = (Decimal)obj;
+ }
+
+ public Decimal WrappedObject
+ {
+ get
+ {
+ return m_WrappedObject;
+ }
+ }
+
+ private Decimal m_WrappedObject;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/CustomQueryInterfaceMode.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/CustomQueryInterfaceMode.cs
new file mode 100644
index 000000000..b71db7108
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/CustomQueryInterfaceMode.cs
@@ -0,0 +1,15 @@
+// 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
+{
+ public enum CustomQueryInterfaceMode
+ {
+ Ignore = 0,
+ Allow = 1,
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/CustomQueryInterfaceResult.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/CustomQueryInterfaceResult.cs
new file mode 100644
index 000000000..2a40296fc
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/CustomQueryInterfaceResult.cs
@@ -0,0 +1,19 @@
+// 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
+{
+ //====================================================================
+ // The enum of the return value of IQuerable.GetInterface
+ //====================================================================
+ public enum CustomQueryInterfaceResult
+ {
+ Handled = 0,
+ NotHandled = 1,
+ Failed = 2,
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultCharSetAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultCharSetAttribute.cs
new file mode 100644
index 000000000..8b1f4df9b
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultCharSetAttribute.cs
@@ -0,0 +1,24 @@
+// 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
+{
+ [AttributeUsage(AttributeTargets.Module, Inherited = false)]
+ public sealed class DefaultCharSetAttribute : Attribute
+ {
+ internal CharSet _CharSet;
+
+ public DefaultCharSetAttribute(CharSet charSet)
+ {
+ _CharSet = charSet;
+ }
+
+ public CharSet CharSet { get { return _CharSet; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultDllImportSearchPathAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultDllImportSearchPathAttribute.cs
new file mode 100644
index 000000000..0ef807068
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultDllImportSearchPathAttribute.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.
+
+//
+
+//
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Method, AllowMultiple = false)]
+ public sealed class DefaultDllImportSearchPathsAttribute : Attribute
+ {
+ internal DllImportSearchPath _paths;
+ public DefaultDllImportSearchPathsAttribute(DllImportSearchPath paths)
+ {
+ _paths = paths;
+ }
+
+ public DllImportSearchPath Paths { get { return _paths; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultParameterValueAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultParameterValueAttribute.cs
new file mode 100644
index 000000000..689b9804c
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/DefaultParameterValueAttribute.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.
+
+//
+
+//
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ //
+ // The DefaultParameterValueAttribute is used in C# to set
+ // the default value for parameters when calling methods
+ // from other languages. This is particularly useful for
+ // methods defined in COM interop interfaces.
+ //
+ [AttributeUsageAttribute(AttributeTargets.Parameter)]
+ public sealed class DefaultParameterValueAttribute : Attribute
+ {
+ public DefaultParameterValueAttribute(object value)
+ {
+ this.value = value;
+ }
+
+ public object Value { get { return this.value; } }
+
+ private object value;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/DispIdAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/DispIdAttribute.cs
new file mode 100644
index 000000000..1148847b1
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/DispIdAttribute.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.
+
+//
+
+//
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Event, Inherited = false)]
+ public sealed class DispIdAttribute : Attribute
+ {
+ internal int _val;
+ public DispIdAttribute(int dispId)
+ {
+ _val = dispId;
+ }
+ public int Value { get { return _val; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/DispatchWrapper.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/DispatchWrapper.cs
new file mode 100644
index 000000000..c2bcc2e02
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/DispatchWrapper.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.
+
+//
+
+//
+
+/*=============================================================================
+**
+** Class: DispatchWrapper.
+**
+**
+** Purpose: Wrapper that is converted to a variant with VT_DISPATCH.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public sealed class DispatchWrapper
+ {
+#if FEATURE_DISPATCHWRAPPER
+ 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;
+#else // FEATURE_DISPATCHWRAPPER
+ public DispatchWrapper(object obj)
+ {
+ throw new PlatformNotSupportedException();
+ }
+ public object WrappedObject
+ {
+ get
+ {
+ throw new PlatformNotSupportedException();
+ }
+ }
+#endif // FEATURE_DISPATCHWRAPPER
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/DllImportSearchPath.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/DllImportSearchPath.cs
new file mode 100644
index 000000000..2fdd87f37
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/DllImportSearchPath.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.
+
+//
+
+//
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ [Flags]
+ public enum DllImportSearchPath
+ {
+ UseDllDirectoryForDependencies = 0x100,
+ ApplicationDirectory = 0x200,
+ UserDirectories = 0x400,
+ System32 = 0x800,
+ SafeDirectories = 0x1000,
+ AssemblyDirectory = 0x2,
+ LegacyBehavior = 0x0
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ErrorWrapper.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ErrorWrapper.cs
new file mode 100644
index 000000000..0b00587ea
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ErrorWrapper.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.
+
+//
+
+//
+
+/*=============================================================================
+**
+** Class: ErrorWrapper.
+**
+**
+** Purpose: Wrapper that is converted to a variant with VT_ERROR.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public sealed class ErrorWrapper
+ {
+ public ErrorWrapper(int errorCode)
+ {
+ m_ErrorCode = errorCode;
+ }
+
+ public ErrorWrapper(Object errorCode)
+ {
+ if (!(errorCode is int))
+ throw new ArgumentException(SR.Arg_MustBeInt32, "errorCode");
+ m_ErrorCode = (int)errorCode;
+ }
+
+ public ErrorWrapper(Exception e)
+ {
+ m_ErrorCode = Marshal.GetHRForException(e);
+ }
+
+ public int ErrorCode
+ {
+ get
+ {
+ return m_ErrorCode;
+ }
+ }
+
+ private int m_ErrorCode;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ExceptionHelpers.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ExceptionHelpers.cs
new file mode 100644
index 000000000..06998cdd2
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ExceptionHelpers.cs
@@ -0,0 +1,948 @@
+// 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.CompilerServices;
+using System.Diagnostics.Contracts;
+using Internal.Runtime.Augments;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// This class has all the helpers which are needed to provide the Exception support for WinRT and ClassicCOM
+ /// </summary>
+ public unsafe static partial class ExceptionHelpers
+ {
+ /// <summary>
+ /// This class is a helper class to call into IRestrictedErrorInfo methods.
+ /// </summary>
+ private static class RestrictedErrorInfoHelper
+ {
+ internal static bool GetErrorDetails(System.IntPtr pRestrictedErrorInfo, out string errMsg, out int hr, out string resErrMsg, out string errCapSid)
+ {
+ Contract.Assert(pRestrictedErrorInfo != IntPtr.Zero);
+ IntPtr pErrDes, pResErrDes, pErrCapSid;
+
+ pErrDes = pResErrDes = pErrCapSid = IntPtr.Zero;
+ int result;
+ try
+ {
+ // Get the errorDetails associated with the restrictedErrorInfo.
+ __com_IRestrictedErrorInfo* pComRestrictedErrorInfo = (__com_IRestrictedErrorInfo*)pRestrictedErrorInfo;
+ result = CalliIntrinsics.StdCall<int>(
+ pComRestrictedErrorInfo->pVtable->pfnGetErrorDetails,
+ pRestrictedErrorInfo,
+ out pErrDes,
+ out hr,
+ out pResErrDes,
+ out pErrCapSid);
+
+ if (result >= 0)
+ {
+ // RestrictedErrorInfo details can be used since the pRestrictedErrorInfo has the same hr value as the hr returned by the native code.
+ errMsg = Interop.COM.ConvertBSTRToString(pErrDes);
+ resErrMsg = Interop.COM.ConvertBSTRToString(pResErrDes);
+ errCapSid = Interop.COM.ConvertBSTRToString(pErrCapSid);
+ }
+ else
+ {
+ errMsg = resErrMsg = errCapSid = null;
+ hr = 0;
+ }
+ }
+ finally
+ {
+ if (pErrDes != IntPtr.Zero)
+ Interop.COM.SysFreeString(pErrDes);
+ if (pResErrDes != IntPtr.Zero)
+ Interop.COM.SysFreeString(pResErrDes);
+ if (pErrCapSid != IntPtr.Zero)
+ Interop.COM.SysFreeString(pErrCapSid);
+ }
+
+ return result >= 0;
+ }
+
+ internal static void GetReference(System.IntPtr pRestrictedErrorInfo, out string errReference)
+ {
+ Contract.Assert(pRestrictedErrorInfo != IntPtr.Zero);
+ IntPtr pReference = IntPtr.Zero;
+ errReference = null;
+
+ try
+ {
+ __com_IRestrictedErrorInfo* pComRestrictedErrorInfo = (__com_IRestrictedErrorInfo*)pRestrictedErrorInfo;
+ int result = CalliIntrinsics.StdCall<int>(pComRestrictedErrorInfo->pVtable->pfnGetReference, pRestrictedErrorInfo, out pReference);
+ if (result >= 0)
+ {
+ errReference = Interop.COM.ConvertBSTRToString(pReference);
+ }
+ else
+ {
+ errReference = null;
+ }
+ }
+ finally
+ {
+ if (pReference != IntPtr.Zero)
+ Interop.COM.SysFreeString(pReference);
+ }
+ }
+ }
+
+ /// <summary>
+ /// The method calls RoOriginateLanguageException. The method has all the logic in try, catch block to ensure that none of the exception helpers
+ /// throw exception themselves.
+ /// </summary>
+ /// <param name="ex"></param>
+ /// <returns></returns>
+ private static bool OriginateLanguageException(Exception ex)
+ {
+ IntPtr pUnk = IntPtr.Zero;
+ HSTRING errorMsg = default(HSTRING);
+ try
+ {
+ pUnk = McgMarshal.ObjectToComInterface(ex, McgModuleManager.IUnknown);
+ if (pUnk != IntPtr.Zero)
+ {
+ RuntimeAugments.GenerateExceptionInformationForDump(ex, pUnk);
+
+ errorMsg = McgMarshal.StringToHString(ex.Message);
+
+ return Interop.WinRT.RoOriginateLanguageException(ex.HResult, errorMsg, pUnk) >= 0;
+ }
+ }
+ catch (Exception)
+ {
+ // We can't do anything here and hence simply swallow the exception
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pUnk);
+ if (errorMsg.handle != IntPtr.Zero)
+ {
+ ExternalInterop.WindowsDeleteString(errorMsg.handle.ToPointer());
+ }
+ }
+
+ return false;
+ }
+
+#pragma warning disable 649, 169 // Field 'blah' is never assigned to/Field 'blah' is never used
+
+ // Lets create vTables for these interfaces.
+ private unsafe struct __com_ILanguageExceptionErrorInfo
+ {
+ internal __vtable_ILanguageExceptionErrorInfo* pVtable;
+ }
+
+ private unsafe struct __vtable_ILanguageExceptionErrorInfo
+ {
+ private IntPtr pfnQueryInterface;
+ private IntPtr pfnAddRef;
+ private IntPtr pfnRelease;
+ internal System.IntPtr pfnGetLanguageException;
+ }
+
+ private unsafe struct __com_IRestrictedErrorInfo
+ {
+ internal __vtable_IRestrictedErrorInfo* pVtable;
+ }
+
+ private unsafe struct __vtable_IRestrictedErrorInfo
+ {
+ private IntPtr pfnQueryInterface;
+ private IntPtr pfnAddRef;
+ private IntPtr pfnRelease;
+ internal System.IntPtr pfnGetErrorDetails;
+ internal System.IntPtr pfnGetReference;
+ }
+#pragma warning restore 649, 169
+
+ /// <summary>
+ /// This method gets the mapping hr for the exception. and also does the right thing to propogate the hr correctly to the native layer.
+ ///
+ /// We check if the exception is a pure managed exception or an exception created from an hr that entered the system from native.
+ /// a. If it is a pure managed exception we create an IUnknown ptr from the exception and RoOriginateLanguageException on it.
+ /// This helps us to preserve our managed exception and throw the same exception in case this exception roundtrips and hence preserve the call stack.
+ /// Since the API RoOriginateLanguageException is available only on windows blue, we can't do the same in win8. In desktop CLR we use the non-modern SDK API
+ /// GetErroInfo\SetErrorInfo combination to preserve managed exception but unfortunately we can't do this in .NET Native and hence we only our able to preserve the exception message and
+ /// type and end up getting a rough stacktrace PS - Even this behavior in win8 is possible only in debug mode as RoSetErrorReportingFlags is set to UseSetErrorInfo only in debug mode.
+ ///
+ /// b. In case the exception is created due to an hr that entered managed world via native call, we will have restrictederrorInfo associated with it. In this case
+ /// we do not RoOriginateLanguageException\RoOriginateError and rather preserve the exception stack trace by simply calling the SetRestrictedErrorInfo.
+ ///
+ /// c. PS - Due to the use of modern SDK we have no way to round trip exceptions in classicCOM scenarios any more.
+ /// This is because we can't use SetErrorInfo\GetErrorInfo APIs at all. Unfortunately we have no workaround for this even in windowsBlue!
+ /// With the use of IRestrictedErrorInfo has some disadvantages as we lose other info available with IErrorInfo in terms of HelpFile etc.
+ ///
+ /// d. This class puts all the logic in try, catch block to ensure that none of the exception helpers.
+ /// throw exception themselves.
+ /// </summary>
+ /// <param name="ex"></param>
+ /// <param name="isWinRTScenario"></param>
+ /// <returns></returns>
+ internal static int GetHRForExceptionWithErrorPropogationNoThrow(Exception ex, bool isWinRTScenario)
+ {
+ int hr = ex.HResult;
+
+ if (hr == Interop.COM.COR_E_OBJECTDISPOSED && isWinRTScenario)
+ {
+ // Since ObjectDisposedException is projected to RO_E_CLOSED in WINRT we make sure to use the correct hr while updating the CRuntimeError object of Windows.
+ hr = Interop.COM.RO_E_CLOSED;
+ }
+
+ try
+ {
+ // Check whether the exception has an associated RestrictedErrorInfo associated with it.
+ if (isWinRTScenario)
+ {
+ IntPtr pRestrictedErrorInfo;
+ object restrictedErrorInfo;
+ if (InteropExtensions.TryGetRestrictedErrorObject(ex, out restrictedErrorInfo) && restrictedErrorInfo != null)
+ {
+ // We have the restricted errorInfo associated with this object and hence this exception was created by an hr entering managed through native.
+ pRestrictedErrorInfo = McgMarshal.ObjectToComInterface(restrictedErrorInfo, McgModuleManager.IRestrictedErrorInfo);
+ if (pRestrictedErrorInfo != IntPtr.Zero)
+ {
+ // We simply call SetRestrictedErrorInfo since we do not want to originate the exception again.
+ Interop.WinRT.SetRestrictedErrorInfo(pRestrictedErrorInfo);
+ McgMarshal.ComSafeRelease(pRestrictedErrorInfo);
+ }
+ }
+ else
+ {
+ // we are in windows blue and hence we can preserve our exception so that we can reuse this exception in case it comes back and provide richer exception support.
+ OriginateLanguageException(ex);
+ }
+ }
+ else
+ {
+ // We are either pre WinBlue or in classicCOM scenario and hence we can only RoOriginateError at this point.
+ // Desktop CLR uses SetErrorInfo and preserves the exception object which helps us give the same support as winBlue.
+ // Since .NET Native can only use modern SDK we have a compatibility break here by only preserving the restrictederrorMsg and exception type but the stack trace will be incorrect.
+
+ // Also RoOriginateError works only under the debugger since RoSetErrorReportingFlags is set to RO_ERROR_REPORTING_USESETERRORINFO.
+ // If we are not under the debugger we can't set this API since it is not part of the modernSDK and hence this will not work
+ // and will result in different behavior than the desktop.
+ HSTRING errorMsg = McgMarshal.StringToHString(ex.Message);
+ Interop.WinRT.RoOriginateError(ex.HResult, errorMsg);
+ ExternalInterop.WindowsDeleteString(errorMsg.handle.ToPointer());
+ }
+ }
+ catch (Exception)
+ {
+ // We can't throw an exception here and hence simply swallow it.
+ }
+
+ return hr;
+ }
+
+ /// <summary>
+ /// This does a mapping from hr to the exception and also takes care of making default exception in case of classic COM as COMException.
+ /// and in winrt and marshal APIs as Exception.
+ /// </summary>
+ /// <param name="errorCode"></param>
+ /// <param name="message"></param>
+ /// <param name="createCOMException"></param>
+ /// <returns></returns>
+ internal static Exception GetMappingExceptionForHR(int errorCode, string message, bool createCOMException, bool hasErrorInfo)
+ {
+ if (errorCode >= 0)
+ {
+ return null;
+ }
+
+ Exception exception = null;
+
+ bool shouldDisplayHR = false;
+
+ switch (errorCode)
+ {
+ case __HResults.COR_E_NOTFINITENUMBER: // NotFiniteNumberException
+ case __HResults.COR_E_ARITHMETIC:
+ exception = new ArithmeticException();
+ break;
+ case __HResults.COR_E_ARGUMENT:
+ case unchecked((int)0x800A01C1):
+ case unchecked((int)0x800A01C2):
+ case __HResults.CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT:
+ exception = new ArgumentException();
+
+ if (errorCode != __HResults.COR_E_ARGUMENT)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.E_BOUNDS:
+ case __HResults.COR_E_ARGUMENTOUTOFRANGE:
+ case __HResults.ERROR_NO_UNICODE_TRANSLATION:
+ exception = new ArgumentOutOfRangeException();
+
+ if (errorCode != __HResults.COR_E_ARGUMENTOUTOFRANGE)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_ARRAYTYPEMISMATCH:
+ exception = new ArrayTypeMismatchException();
+ break;
+ case __HResults.COR_E_BADIMAGEFORMAT:
+ case __HResults.CLDB_E_FILE_OLDVER:
+ case __HResults.CLDB_E_INDEX_NOTFOUND:
+ case __HResults.CLDB_E_FILE_CORRUPT:
+ case __HResults.COR_E_NEWER_RUNTIME:
+ case __HResults.COR_E_ASSEMBLYEXPECTED:
+ case __HResults.ERROR_BAD_EXE_FORMAT:
+ case __HResults.ERROR_EXE_MARKED_INVALID:
+ case __HResults.CORSEC_E_INVALID_IMAGE_FORMAT:
+ case __HResults.ERROR_NOACCESS:
+ case __HResults.ERROR_INVALID_ORDINAL:
+ case __HResults.ERROR_INVALID_DLL:
+ case __HResults.ERROR_FILE_CORRUPT:
+ case __HResults.COR_E_LOADING_REFERENCE_ASSEMBLY:
+ case __HResults.META_E_BAD_SIGNATURE:
+ exception = new BadImageFormatException();
+
+ // Always show HR for BadImageFormatException
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_CUSTOMATTRIBUTEFORMAT:
+ exception = new FormatException();
+ break; // CustomAttributeFormatException
+ case __HResults.COR_E_DATAMISALIGNED:
+ exception = InteropExtensions.CreateDataMisalignedException(message); // TODO: Do we need to add msg here?
+ break;
+ case __HResults.COR_E_DIVIDEBYZERO:
+ case __HResults.CTL_E_DIVISIONBYZERO:
+ exception = new DivideByZeroException();
+
+ if (errorCode != __HResults.COR_E_DIVIDEBYZERO)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_DLLNOTFOUND:
+ exception = new DllNotFoundException();
+ break;
+ case __HResults.COR_E_DUPLICATEWAITOBJECT:
+ exception = new ArgumentException();
+ break; // DuplicateWaitObjectException
+ case __HResults.COR_E_ENDOFSTREAM:
+ case unchecked((int)0x800A003E):
+ exception = new System.IO.EndOfStreamException();
+
+ if (errorCode != __HResults.COR_E_ENDOFSTREAM)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_TYPEACCESS: // TypeAccessException
+ case __HResults.COR_E_ENTRYPOINTNOTFOUND:
+ exception = new TypeLoadException();
+
+ break; // EntryPointNotFoundException
+ case __HResults.COR_E_EXCEPTION:
+ exception = new Exception();
+ break;
+ case __HResults.COR_E_DIRECTORYNOTFOUND:
+ case __HResults.STG_E_PATHNOTFOUND:
+ case __HResults.CTL_E_PATHNOTFOUND:
+ exception = new System.IO.DirectoryNotFoundException();
+
+ if (errorCode != __HResults.COR_E_DIRECTORYNOTFOUND)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_FILELOAD:
+ case __HResults.FUSION_E_INVALID_PRIVATE_ASM_LOCATION:
+ case __HResults.FUSION_E_SIGNATURE_CHECK_FAILED:
+ case __HResults.FUSION_E_LOADFROM_BLOCKED:
+ case __HResults.FUSION_E_CACHEFILE_FAILED:
+ case __HResults.FUSION_E_ASM_MODULE_MISSING:
+ case __HResults.FUSION_E_INVALID_NAME:
+ case __HResults.FUSION_E_PRIVATE_ASM_DISALLOWED:
+ case __HResults.FUSION_E_HOST_GAC_ASM_MISMATCH:
+ case __HResults.COR_E_MODULE_HASH_CHECK_FAILED:
+ case __HResults.FUSION_E_REF_DEF_MISMATCH:
+ case __HResults.SECURITY_E_INCOMPATIBLE_SHARE:
+ case __HResults.SECURITY_E_INCOMPATIBLE_EVIDENCE:
+ case __HResults.SECURITY_E_UNVERIFIABLE:
+ case __HResults.COR_E_FIXUPSINEXE:
+ case __HResults.ERROR_TOO_MANY_OPEN_FILES:
+ case __HResults.ERROR_SHARING_VIOLATION:
+ case __HResults.ERROR_LOCK_VIOLATION:
+ case __HResults.ERROR_OPEN_FAILED:
+ case __HResults.ERROR_DISK_CORRUPT:
+ case __HResults.ERROR_UNRECOGNIZED_VOLUME:
+ case __HResults.ERROR_DLL_INIT_FAILED:
+ case __HResults.FUSION_E_CODE_DOWNLOAD_DISABLED:
+ case __HResults.CORSEC_E_MISSING_STRONGNAME:
+ case __HResults.MSEE_E_ASSEMBLYLOADINPROGRESS:
+ case __HResults.ERROR_FILE_INVALID:
+ exception = new System.IO.FileLoadException();
+
+ shouldDisplayHR = true;
+ break;
+ case __HResults.COR_E_PATHTOOLONG:
+ exception = new System.IO.PathTooLongException();
+ break;
+ case __HResults.COR_E_IO:
+ case __HResults.CTL_E_DEVICEIOERROR:
+ case unchecked((int)0x800A793C):
+ case unchecked((int)0x800A793D):
+ exception = new System.IO.IOException();
+
+ if (errorCode != __HResults.COR_E_IO)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.ERROR_FILE_NOT_FOUND:
+ case __HResults.ERROR_MOD_NOT_FOUND:
+ case __HResults.ERROR_INVALID_NAME:
+ case __HResults.CTL_E_FILENOTFOUND:
+ case __HResults.ERROR_BAD_NET_NAME:
+ case __HResults.ERROR_BAD_NETPATH:
+ case __HResults.ERROR_NOT_READY:
+ case __HResults.ERROR_WRONG_TARGET_NAME:
+ case __HResults.INET_E_UNKNOWN_PROTOCOL:
+ case __HResults.INET_E_CONNECTION_TIMEOUT:
+ case __HResults.INET_E_CANNOT_CONNECT:
+ case __HResults.INET_E_RESOURCE_NOT_FOUND:
+ case __HResults.INET_E_OBJECT_NOT_FOUND:
+ case __HResults.INET_E_DOWNLOAD_FAILURE:
+ case __HResults.INET_E_DATA_NOT_AVAILABLE:
+ case __HResults.ERROR_DLL_NOT_FOUND:
+ case __HResults.CLR_E_BIND_ASSEMBLY_VERSION_TOO_LOW:
+ case __HResults.CLR_E_BIND_ASSEMBLY_PUBLIC_KEY_MISMATCH:
+ case __HResults.CLR_E_BIND_ASSEMBLY_NOT_FOUND:
+ exception = new System.IO.FileNotFoundException();
+
+ shouldDisplayHR = true;
+ break;
+ case __HResults.COR_E_FORMAT:
+ exception = new FormatException();
+ break;
+ case __HResults.COR_E_INDEXOUTOFRANGE:
+ case unchecked((int)0x800a0009):
+ exception = new IndexOutOfRangeException();
+
+ if (errorCode != __HResults.COR_E_INDEXOUTOFRANGE)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_INVALIDCAST:
+ exception = new InvalidCastException();
+ break;
+ case __HResults.COR_E_INVALIDCOMOBJECT:
+ exception = new InvalidComObjectException();
+ break;
+ case __HResults.COR_E_INVALIDOLEVARIANTTYPE:
+ exception = new InvalidOleVariantTypeException();
+ break;
+ case __HResults.COR_E_INVALIDOPERATION:
+ case __HResults.E_ILLEGAL_STATE_CHANGE:
+ case __HResults.E_ILLEGAL_METHOD_CALL:
+ case __HResults.E_ILLEGAL_DELEGATE_ASSIGNMENT:
+ case __HResults.APPMODEL_ERROR_NO_PACKAGE:
+ exception = new InvalidOperationException();
+
+ if (errorCode != __HResults.COR_E_INVALIDOPERATION)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_MARSHALDIRECTIVE:
+ exception = new MarshalDirectiveException();
+ break;
+ case __HResults.COR_E_METHODACCESS: // MethodAccessException
+ case __HResults.META_E_CA_FRIENDS_SN_REQUIRED: // MethodAccessException
+ case __HResults.COR_E_FIELDACCESS:
+ case __HResults.COR_E_MEMBERACCESS:
+ exception = new MemberAccessException();
+
+ if (errorCode != __HResults.COR_E_METHODACCESS)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_MISSINGFIELD: // MissingFieldException
+ case __HResults.COR_E_MISSINGMETHOD: // MissingMethodException
+ case __HResults.COR_E_MISSINGMEMBER:
+ case unchecked((int)0x800A01CD):
+ exception = new MissingMemberException();
+ break;
+ case __HResults.COR_E_MISSINGMANIFESTRESOURCE:
+ exception = new System.Resources.MissingManifestResourceException();
+ break;
+ case __HResults.COR_E_NOTSUPPORTED:
+ case unchecked((int)0x800A01B6):
+ case unchecked((int)0x800A01BD):
+ case unchecked((int)0x800A01CA):
+ case unchecked((int)0x800A01CB):
+ exception = new NotSupportedException();
+
+ if (errorCode != __HResults.COR_E_NOTSUPPORTED)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_NULLREFERENCE:
+ exception = new NullReferenceException();
+ break;
+ case __HResults.COR_E_OBJECTDISPOSED:
+ case __HResults.RO_E_CLOSED:
+ // No default constructor
+ exception = new ObjectDisposedException(String.Empty);
+ break;
+ case __HResults.COR_E_OPERATIONCANCELED:
+ exception = new OperationCanceledException();
+ break;
+ case __HResults.COR_E_OVERFLOW:
+ case __HResults.CTL_E_OVERFLOW:
+ exception = new OverflowException();
+ break;
+ case __HResults.COR_E_PLATFORMNOTSUPPORTED:
+ exception = new PlatformNotSupportedException(message);
+ break;
+ case __HResults.COR_E_RANK:
+ exception = new RankException();
+ break;
+ case __HResults.COR_E_REFLECTIONTYPELOAD:
+ exception = new System.Reflection.ReflectionTypeLoadException(null, null);
+ break;
+ case __HResults.COR_E_SECURITY:
+ case __HResults.CORSEC_E_INVALID_STRONGNAME:
+ case __HResults.CTL_E_PERMISSIONDENIED:
+ case unchecked((int)0x800A01A3):
+ case __HResults.CORSEC_E_INVALID_PUBLICKEY:
+ case __HResults.CORSEC_E_SIGNATURE_MISMATCH:
+ exception = new System.Security.SecurityException();
+ break;
+ case __HResults.COR_E_SAFEARRAYRANKMISMATCH:
+ exception = new SafeArrayRankMismatchException();
+ break;
+ case __HResults.COR_E_SAFEARRAYTYPEMISMATCH:
+ exception = new SafeArrayTypeMismatchException();
+ break;
+ case __HResults.COR_E_SERIALIZATION:
+ exception = ConstructExceptionUsingReflection(
+ "System.Runtime.Serialization.SerializationException, System.Runtime.Serialization.Primitives, Version=4.0.0.0",
+ message);
+ break;
+ case __HResults.COR_E_SYNCHRONIZATIONLOCK:
+ exception = new System.Threading.SynchronizationLockException();
+ break;
+ case __HResults.COR_E_TARGETINVOCATION:
+ exception = new System.Reflection.TargetInvocationException(null);
+ break;
+ case __HResults.COR_E_TARGETPARAMCOUNT:
+ exception = new System.Reflection.TargetParameterCountException();
+ break;
+ case __HResults.COR_E_TYPEINITIALIZATION:
+ exception = InteropExtensions.CreateTypeInitializationException(message);
+ break;
+ case __HResults.COR_E_TYPELOAD:
+ case __HResults.RO_E_METADATA_NAME_NOT_FOUND:
+ case __HResults.CLR_E_BIND_TYPE_NOT_FOUND:
+ exception = new TypeLoadException();
+
+ if (errorCode != __HResults.COR_E_TYPELOAD)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_UNAUTHORIZEDACCESS:
+ case __HResults.CTL_E_PATHFILEACCESSERROR:
+ case unchecked((int)0x800A014F):
+ exception = new UnauthorizedAccessException();
+
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_VERIFICATION:
+ exception = new System.Security.VerificationException();
+ break;
+ case __HResults.E_NOTIMPL:
+ exception = new NotImplementedException();
+ break;
+ case __HResults.E_OUTOFMEMORY:
+ case __HResults.CTL_E_OUTOFMEMORY:
+ case unchecked((int)0x800A7919):
+ exception = new OutOfMemoryException();
+
+ if (errorCode != __HResults.E_OUTOFMEMORY)
+ shouldDisplayHR = true;
+
+ break;
+#if ENABLE_WINRT
+ case __HResults.E_XAMLPARSEFAILED:
+ exception = new Windows.UI.Xaml.Markup.XamlParseException();
+ break;
+ case __HResults.E_ELEMENTNOTAVAILABLE:
+ exception = new Windows.UI.Xaml.Automation.ElementNotAvailableException();
+ break;
+ case __HResults.E_ELEMENTNOTENABLED:
+ exception = new Windows.UI.Xaml.Automation.ElementNotEnabledException();
+ break;
+ case __HResults.E_LAYOUTCYCLE:
+ exception = new Windows.UI.Xaml.LayoutCycleException();
+ break;
+#endif // ENABLE_WINRT
+ case __HResults.COR_E_AMBIGUOUSMATCH: // AmbiguousMatchException
+ case __HResults.COR_E_APPLICATION: // ApplicationException
+ case __HResults.COR_E_APPDOMAINUNLOADED: // AppDomainUnloadedException
+ case __HResults.COR_E_CANNOTUNLOADAPPDOMAIN: // CannotUnloadAppDomainException
+ case __HResults.COR_E_CODECONTRACTFAILED: // ContractException
+ case __HResults.COR_E_CONTEXTMARSHAL: // ContextMarshalException
+ case __HResults.CORSEC_E_CRYPTO: // CryptographicException
+ case __HResults.CORSEC_E_CRYPTO_UNEX_OPER: // CryptographicUnexpectedOperationException
+ case __HResults.COR_E_EXECUTIONENGINE: // ExecutionEngineException
+ case __HResults.COR_E_INSUFFICIENTEXECUTIONSTACK: // InsufficientExecutionStackException
+ case __HResults.COR_E_INVALIDFILTERCRITERIA: // InvalidFilterCriteriaException
+ case __HResults.COR_E_INVALIDPROGRAM: // InvalidProgramException
+ case __HResults.COR_E_MULTICASTNOTSUPPORTED: // MulticastNotSupportedException
+ case __HResults.COR_E_REMOTING: // RemotingException
+ case __HResults.COR_E_RUNTIMEWRAPPED: // RuntimeWrappedException
+ case __HResults.COR_E_SERVER: // ServerException
+ case __HResults.COR_E_STACKOVERFLOW: // StackOverflowException
+ case __HResults.CTL_E_OUTOFSTACKSPACE: // StackOverflowException
+ case __HResults.COR_E_SYSTEM: // SystemException
+ case __HResults.COR_E_TARGET: // TargetException
+ case __HResults.COR_E_THREADABORTED: // TargetException
+ case __HResults.COR_E_THREADINTERRUPTED: // ThreadInterruptedException
+ case __HResults.COR_E_THREADSTATE: // ThreadStateException
+ case __HResults.COR_E_THREADSTART: // ThreadStartException
+ case __HResults.COR_E_TYPEUNLOADED: // TypeUnloadedException
+ case __HResults.CORSEC_E_POLICY_EXCEPTION: // PolicyException
+ case __HResults.CORSEC_E_NO_EXEC_PERM: // PolicyException
+ case __HResults.CORSEC_E_MIN_GRANT_FAIL: // PolicyException
+ case __HResults.CORSEC_E_XMLSYNTAX: // XmlSyntaxException
+ case __HResults.ISS_E_ALLOC_TOO_LARGE: // IsolatedStorageException
+ case __HResults.ISS_E_BLOCK_SIZE_TOO_SMALL: // IsolatedStorageException
+ case __HResults.ISS_E_CALLER: // IsolatedStorageException
+ case __HResults.ISS_E_CORRUPTED_STORE_FILE: // IsolatedStorageException
+ case __HResults.ISS_E_CREATE_DIR: // IsolatedStorageException
+ case __HResults.ISS_E_CREATE_MUTEX: // IsolatedStorageException
+ case __HResults.ISS_E_DEPRECATE: // IsolatedStorageException
+ case __HResults.ISS_E_FILE_NOT_MAPPED: // IsolatedStorageException
+ case __HResults.ISS_E_FILE_WRITE: // IsolatedStorageException
+ case __HResults.ISS_E_GET_FILE_SIZE: // IsolatedStorageException
+ case __HResults.ISS_E_ISOSTORE: // IsolatedStorageException
+ case __HResults.ISS_E_LOCK_FAILED: // IsolatedStorageException
+ case __HResults.ISS_E_MACHINE: // IsolatedStorageException
+ case __HResults.ISS_E_MACHINE_DACL: // IsolatedStorageException
+ case __HResults.ISS_E_MAP_VIEW_OF_FILE: // IsolatedStorageException
+ case __HResults.ISS_E_OPEN_FILE_MAPPING: // IsolatedStorageException
+ case __HResults.ISS_E_OPEN_STORE_FILE: // IsolatedStorageException
+ case __HResults.ISS_E_PATH_LENGTH: // IsolatedStorageException
+ case __HResults.ISS_E_SET_FILE_POINTER: // IsolatedStorageException
+ case __HResults.ISS_E_STORE_NOT_OPEN: // IsolatedStorageException
+ case __HResults.ISS_E_STORE_VERSION: // IsolatedStorageException
+ case __HResults.ISS_E_TABLE_ROW_NOT_FOUND: // IsolatedStorageException
+ case __HResults.ISS_E_USAGE_WILL_EXCEED_QUOTA: // IsolatedStorageException
+ case __HResults.E_FAIL:
+ default:
+ break;
+ }
+
+ if (exception == null)
+ {
+ if (createCOMException)
+ {
+ exception = new COMException();
+ if (errorCode != __HResults.E_FAIL)
+ shouldDisplayHR = true;
+ }
+ else
+ {
+ exception = new Exception();
+ if (errorCode != __HResults.COR_E_EXCEPTION)
+ shouldDisplayHR = true;
+ }
+ }
+
+ bool shouldConstructMessage = false;
+ if (hasErrorInfo)
+ {
+ // If there is a IErrorInfo/IRestrictedErrorInfo, only construct a new error message if
+ // the message is not available and do not use the shouldDisplayHR setting
+ if (message == null)
+ shouldConstructMessage = true;
+ }
+ else
+ {
+ // If there is no IErrorInfo, use the shouldDisplayHR setting from the big switch/case above
+ shouldConstructMessage = shouldDisplayHR;
+ }
+
+ if (shouldConstructMessage)
+ {
+ //
+ // Append the HR into error message, just in case the app wants to look at the HR in
+ // message to determine behavior. We didn't expose HResult property until v4.5 and
+ // GetHRFromException has side effects so probably Message was their only choice.
+ // This behavior is probably not exactly the same as in desktop but it is fine to append
+ // more message at the end. In any case, having the HR in the error message are helpful
+ // to developers.
+ // This makes sure:
+ // 1. We always have a HR 0xNNNNNNNN in the message
+ // 2. Put in a nice "Exception thrown from HRESULT" message if we can
+ // 3. Wrap it in () if there is an existing message
+ //
+
+ // TODO: Add Symbolic Name into Messaage, convert 0x80020006 to DISP_E_UNKNOWNNAME
+ string hrMessage = String.Format("{0} 0x{1:X}", SR.Excep_FromHResult, errorCode);
+
+ message = Interop.MinCore.GetMessage(errorCode);
+
+ // Always make sure we have at least the HRESULT part in retail build or when the message
+ // is empty.
+ if (message == null)
+ message = hrMessage;
+ else
+ message = message + " (" + hrMessage + ")";
+ }
+
+ if (message != null)
+ {
+ // Set message explicitly rather than calling constructor because certain ctors would append a
+ // prefix to the message and that is not what we want
+ InteropExtensions.SetExceptionMessage(exception, message);
+ }
+
+ InteropExtensions.SetExceptionErrorCode(exception, errorCode);
+
+ return exception;
+ }
+
+ /// <summary>
+ /// Construct exception dynamically using reflection.
+ /// </summary>
+ /// <param name="exceptionTypeName">Assembly-qualified exception type name</param>
+ /// <param name="message">Message to use for exception creation (null = use parameterless constructor)</param>
+ static Exception ConstructExceptionUsingReflection(string exceptionTypeName, string message)
+ {
+ Exception result = null;
+
+ try
+ {
+ Type exceptionType = Type.GetType(exceptionTypeName);
+
+ if (exceptionType != null)
+ {
+ if (message == null)
+ {
+ result = (Exception)Activator.CreateInstance(exceptionType);
+ }
+ else
+ {
+ result = (Exception)Activator.CreateInstance(exceptionType, message);
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // Ignore exceptions during exception construction - a default exception will be returned
+ }
+ return result;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ static bool TryGetRestrictedErrorInfo(out IntPtr pRestrictedErrorInfo)
+ {
+ return Interop.WinRT.GetRestrictedErrorInfo(out pRestrictedErrorInfo) >= 0 && pRestrictedErrorInfo != IntPtr.Zero;
+ }
+
+ /// <summary>
+ /// This method returns a new Exception object given the HR value.
+ ///
+ /// 1. We check whether we have our own LanguageException associated with this hr. If so we simply use it since it helps preserve the stacktrace, message and type.
+ /// This is done using GetLanguageException API on ILanguageExceptionErrorInfo from IRestrictedErrorInfo. Since ILanguageExceptionErrorInfo is available only on Windows Blue
+ /// we can only do this WindowsBlue and above. In desktop CLR we could use GetErroInfo and check whether we have our IErroInfo and retrieve our own exception.
+ /// For Win8 in .NET Native we simply create the exception using the RestrictedErrorInfo and hence only able to give the exception with restrictedErrorMsg.
+ /// 2. In case we do not have the languageException we simply check RestrictedErrorInfo for errorMsg and create an exception using
+ /// <errorMsg>\r\n<restrictedErrorMsg>. This is done for only windows blue. To be backward compatible we only use errorMsg for creating exception in win8.
+ /// 3. PS - This class puts all the logic in try, catch block to ensure that none of the exception helpers
+ /// throw exception themselves.
+ /// </summary>
+ /// <param name="hr"></param>
+ /// <param name="isWinRTScenario"></param>
+ internal static Exception GetExceptionForHRInternalNoThrow(int hr, bool isWinRTScenario, bool isClassicCOM)
+ {
+ Exception ex;
+ IntPtr pRestrictedErrorInfo = IntPtr.Zero;
+
+ try
+ {
+ if (TryGetRestrictedErrorInfo(out pRestrictedErrorInfo))
+ {
+ // This is to check whether we need to give post win8 behavior or not.
+ if (isWinRTScenario)
+ {
+ // Check whether the given IRestrictedErrorInfo object supports ILanguageExceptionErrorInfo
+ IntPtr pLanguageExceptionErrorInfo = McgMarshal.ComQueryInterfaceNoThrow(pRestrictedErrorInfo, ref Interop.COM.IID_ILanguageExceptionErrorInfo);
+ if (pLanguageExceptionErrorInfo != IntPtr.Zero)
+ {
+ // We have an LanguageExceptionErrorInfo.
+ IntPtr pUnk;
+ __com_ILanguageExceptionErrorInfo* pComLanguageExceptionErrorInfo = (__com_ILanguageExceptionErrorInfo*)pLanguageExceptionErrorInfo;
+ int result = CalliIntrinsics.StdCall<int>(pComLanguageExceptionErrorInfo->pVtable->pfnGetLanguageException, pLanguageExceptionErrorInfo, out pUnk);
+ McgMarshal.ComSafeRelease(pLanguageExceptionErrorInfo);
+
+ if (result >= 0 && pUnk != IntPtr.Zero)
+ {
+ try
+ {
+ // Check whether the given pUnk is a managed exception.
+ ComCallableObject ccw;
+ if (ComCallableObject.TryGetCCW(pUnk, out ccw))
+ {
+ return ccw.TargetObject as Exception;
+ }
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pUnk);
+ }
+ }
+ }
+ }
+ String message = null, errorInfoReference = null;
+ string errMsg, errCapSid, resErrMsg;
+ int errHr;
+ object restrictedErrorInfo = null;
+
+ bool hasErrorInfo = false;
+ if (RestrictedErrorInfoHelper.GetErrorDetails(pRestrictedErrorInfo, out errMsg, out errHr, out resErrMsg, out errCapSid) && errHr == hr)
+ {
+ // RestrictedErrorInfo details can be used since the pRestrictedErrorInfo has the same hr value as the hr returned by the native code.
+ // We are in windows blue or above and hence the exceptionMsg is errMsg + "\r\n" + resErrMsg
+ message = String.IsNullOrEmpty(resErrMsg) ? errMsg : errMsg + "\r\n" + resErrMsg;
+ RestrictedErrorInfoHelper.GetReference(pRestrictedErrorInfo, out errorInfoReference);
+ restrictedErrorInfo = McgMarshal.ComInterfaceToObject(pRestrictedErrorInfo, McgModuleManager.IRestrictedErrorInfo);
+
+ hasErrorInfo = true;
+ }
+
+ if (hr == Interop.COM.RO_E_CLOSED && isWinRTScenario)
+ hr = Interop.COM.COR_E_OBJECTDISPOSED;
+
+ // Now we simply need to set the description and the resDescription by adding an internal method.
+ ex = GetMappingExceptionForHR(hr, message, isClassicCOM, hasErrorInfo);
+
+ if (restrictedErrorInfo != null)
+ {
+ InteropExtensions.AddExceptionDataForRestrictedErrorInfo(ex, resErrMsg, errorInfoReference, errCapSid, restrictedErrorInfo);
+ }
+
+ return ex;
+ }
+ }
+ catch (Exception)
+ {
+ // We can't do any thing here and hence we swallow the exception and get the corresponding hr.
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pRestrictedErrorInfo);
+ }
+
+ // We could not find any restrictedErrorInfo associated with this object and hence we simply use the hr to create the exception.
+ return GetMappingExceptionForHR(hr, null, isClassicCOM, hasErrorInfo: false);
+ }
+
+ internal static bool ReportUnhandledError(Exception e)
+ {
+ System.IntPtr pRestrictedErrorInfo = IntPtr.Zero;
+
+ if (e != null)
+ {
+ try
+ {
+#if ENABLE_WINRT
+ // Only report to the WinRT global exception handler in modern apps
+ WinRTInteropCallbacks callbacks = WinRTInterop.Callbacks;
+ if (callbacks == null || !callbacks.IsAppxModel())
+ {
+ return false;
+ }
+
+ // Get the IUnknown 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.
+ if (OriginateLanguageException(e) && TryGetRestrictedErrorInfo(out pRestrictedErrorInfo))
+ {
+ return Interop.WinRT.RoReportUnhandledError(pRestrictedErrorInfo) >= 0;
+ }
+#else
+ return false;
+#endif // ENABLE_WINRT
+ }
+ catch (Exception)
+ {
+ // We can't give an exception in this code, so we simply swallow the exception here.
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pRestrictedErrorInfo);
+ }
+ }
+ // If we have got here, then some step of the pInvoke failed, which means the GEH was not invoked
+ return false;
+ }
+
+ internal static Exception AttachRestrictedErrorInfo(Exception e)
+ {
+ // If there is no exception, then the restricted error info doesn't apply to it
+ if (e != null)
+ {
+ System.IntPtr pRestrictedErrorInfo = IntPtr.Zero;
+
+ try
+ {
+ // Get the restricted error info for this thread and see if it may correlate to the current
+ // exception object. Note that in general the thread's IRestrictedErrorInfo is not meant for
+ // exceptions that are marshaled Windows.Foundation.HResults and instead are intended for
+ // HRESULT ABI return values. However, in many cases async APIs will set the thread's restricted
+ // error info as a convention in order to provide extended debugging information for the ErrorCode
+ // property.
+ if (TryGetRestrictedErrorInfo(out pRestrictedErrorInfo))
+ {
+ string description;
+ string restrictedDescription;
+ string capabilitySid;
+ int restrictedErrorInfoHResult;
+ if (RestrictedErrorInfoHelper.GetErrorDetails(
+ pRestrictedErrorInfo,
+ out description,
+ out restrictedErrorInfoHResult,
+ out restrictedDescription,
+ out capabilitySid) && (e.HResult == restrictedErrorInfoHResult))
+ {
+ // Since this is a special case where by convention there may be a correlation, there is not a
+ // guarantee that the restricted error info does belong to the async error code. In order to
+ // reduce the risk that we associate incorrect information with the exception object, we need
+ // to apply a heuristic where we attempt to match the current exception's HRESULT with the
+ // HRESULT the IRestrictedErrorInfo belongs to. If it is a match we will assume association
+ // for the IAsyncInfo case.
+ string errorReference;
+ RestrictedErrorInfoHelper.GetReference(pRestrictedErrorInfo, out errorReference);
+ object restrictedErrorInfo = McgMarshal.ComInterfaceToObject(pRestrictedErrorInfo, McgModuleManager.IRestrictedErrorInfo);
+ InteropExtensions.AddExceptionDataForRestrictedErrorInfo(
+ e,
+ restrictedDescription,
+ errorReference,
+ capabilitySid,
+ restrictedErrorInfo);
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // If we can't get the restricted error info, then proceed as if it isn't associated with this
+ // error.
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pRestrictedErrorInfo);
+ }
+ }
+ return e;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/GuidAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/GuidAttribute.cs
new file mode 100644
index 000000000..0d89882fe
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/GuidAttribute.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;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Struct | AttributeTargets.Delegate, Inherited = false)]
+ public sealed class GuidAttribute : Attribute
+ {
+ internal String _val;
+ public GuidAttribute(String guid)
+ {
+ _val = guid;
+ }
+ public String Value { get { return _val; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/HandleCollector.NETNative.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/HandleCollector.NETNative.cs
new file mode 100644
index 000000000..180e893eb
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/HandleCollector.NETNative.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.
+
+using System;
+using System.Threading;
+
+namespace System.Runtime.InteropServices
+{
+ // .NET Native-specific HandleCollector implementation
+ public sealed partial class HandleCollector
+ {
+ private void Sleep(int milliseconds)
+ {
+ Interop.MinCore.Sleep((uint)milliseconds);
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/HandleCollector.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/HandleCollector.cs
new file mode 100644
index 000000000..3cd1d6f10
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/HandleCollector.cs
@@ -0,0 +1,134 @@
+// 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.Threading;
+
+namespace System.Runtime.InteropServices
+{
+ public sealed class HandleCollector
+ {
+ private const int deltaPercent = 10; // this is used for increasing the threshold.
+ private string name;
+ private int initialThreshold;
+ private int maximumThreshold;
+ private int threshold;
+ private int handleCount;
+
+ private int[] gc_counts = new int[3];
+ private int gc_gen = 0;
+
+ public HandleCollector(string name, int initialThreshold) :
+ this(name, initialThreshold, int.MaxValue)
+ {
+ }
+
+ public HandleCollector(string name, int initialThreshold, int maximumThreshold)
+ {
+ if (initialThreshold < 0)
+ {
+ throw new ArgumentOutOfRangeException("initialThreshold", SR.Arg_NeedNonNegNumRequired);
+ }
+
+ if (maximumThreshold < 0)
+ {
+ throw new ArgumentOutOfRangeException("maximumThreshold", SR.Arg_NeedNonNegNumRequired);
+ }
+
+ if (initialThreshold > maximumThreshold)
+ {
+ throw new ArgumentException(SR.Arg_InvalidThreshold);
+ }
+
+ if (name != null)
+ {
+ this.name = name;
+ }
+ else
+ {
+ this.name = String.Empty;
+ }
+
+ this.initialThreshold = initialThreshold;
+ this.maximumThreshold = maximumThreshold;
+ this.threshold = initialThreshold;
+ this.handleCount = 0;
+ }
+
+ public int Count { get { return handleCount; } }
+
+ public int InitialThreshold { get { return initialThreshold; } }
+
+ public int MaximumThreshold { get { return maximumThreshold; } }
+
+ public string Name { get { return name; } }
+
+ public void Add()
+ {
+ int gen_collect = -1;
+ Interlocked.Increment(ref handleCount);
+ if (handleCount < 0)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_HCCountOverflow);
+ }
+
+ if (handleCount > threshold)
+ {
+ lock (this)
+ {
+ threshold = handleCount + (handleCount / deltaPercent);
+ gen_collect = gc_gen;
+ if (gc_gen < 2)
+ {
+ gc_gen++;
+ }
+ }
+ }
+
+ if ((gen_collect >= 0) &&
+ ((gen_collect == 0) ||
+ (gc_counts[gen_collect] == GC.CollectionCount(gen_collect))))
+ {
+ GC.Collect(gen_collect);
+ Interop.MinCore.Sleep((uint)(10 * gen_collect));
+ }
+
+ //don't bother with gen0.
+ for (int i = 1; i < 3; i++)
+ {
+ gc_counts[i] = GC.CollectionCount(i);
+ }
+ }
+
+ public void Remove()
+ {
+ Interlocked.Decrement(ref handleCount);
+ if (handleCount < 0)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_HCCountOverflow);
+ }
+
+ int newThreshold = handleCount + handleCount / deltaPercent;
+ if (newThreshold < (threshold - threshold / deltaPercent))
+ {
+ lock (this)
+ {
+ if (newThreshold > initialThreshold)
+ {
+ threshold = newThreshold;
+ }
+ else
+ {
+ threshold = initialThreshold;
+ }
+ gc_gen = 0;
+ }
+ }
+
+ for (int i = 1; i < 3; i++)
+ {
+ gc_counts[i] = GC.CollectionCount(i);
+ }
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ICustomAdapter.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ICustomAdapter.cs
new file mode 100644
index 000000000..e1d8c6806
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ICustomAdapter.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/*=============================================================================
+**
+** Class: ICustomAdapter
+**
+**
+** Purpose: This the base interface that custom adapters can chose to implement
+** when they want to expose the underlying object.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public interface ICustomAdapter
+ {
+ [return: MarshalAs(UnmanagedType.IUnknown)]
+ object GetUnderlyingObject();
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/ICustomQueryInterface.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/ICustomQueryInterface.cs
new file mode 100644
index 000000000..3b25abaed
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/ICustomQueryInterface.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.
+
+/*=============================================================================
+**
+** Class: ICustomQueryInterface
+**
+**
+** Purpose: This the interface that be implemented by class that want to
+** customize the behavior of QueryInterface.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ //====================================================================
+ // The interface for customizing IQueryInterface
+ //====================================================================
+ public interface ICustomQueryInterface
+ {
+ CustomQueryInterfaceResult GetInterface([In]ref Guid iid, out IntPtr ppv);
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/InAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/InAttribute.cs
new file mode 100644
index 000000000..f5e6ea936
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/InAttribute.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.
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public sealed class InAttribute : Attribute
+ {
+ public InAttribute()
+ {
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/InterfaceTypeAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/InterfaceTypeAttribute.cs
new file mode 100644
index 000000000..54d023401
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/InterfaceTypeAttribute.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Interface, Inherited = false)]
+ 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; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/InteropEventProvider.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/InteropEventProvider.cs
new file mode 100644
index 000000000..391206004
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/InteropEventProvider.cs
@@ -0,0 +1,607 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//
+// InteropEventProvider.cs
+//
+//
+// Managed event source for FXCore.
+// This will produce an XML file, where each event is pretty-printed with all its arguments nicely parsed.
+//
+// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+using System;
+using System.Security;
+using System.Diagnostics.Tracing;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>Provides an event source for tracing Interop information.</summary>
+ [EventSource(Guid = "C4AC552A-E1EB-4FA2-A651-B200EFD7AA91", Name = "System.Runtime.InteropServices.InteropEventProvider")]
+ internal sealed class InteropEventProvider : EventSource
+ {
+ // Defines the singleton instance for the Interop Event ETW provider
+ public static readonly InteropEventProvider Log = new InteropEventProvider();
+
+ internal new static bool IsEnabled()
+ {
+ // The InteropEventProvider class constructor should create an instance of InteropEventProvider and assign
+ // it to the Log field so Log should never be null here. However the EventSource performs some P/Invoke
+ // interop and creating a System.Type object which happens while running the EventSource ctor can perform
+ // WinRT interop so it is possible that we end up calling IsEnabled before the InteropEventProvider class
+ // constructor has completed so we must check that Log is not null.
+ return Log != null && ((EventSource)Log).IsEnabled();
+ }
+
+ // The InteropEventSource GUID is {C4AC552A-E1EB-4FA2-A651-B200EFD7AA91}
+ private InteropEventProvider() { }
+
+ /// <summary>Keyword definitions.</summary>
+ public static class Keywords
+ {
+ /// <summary>Interop keyword enable or disable the whole interop log events.</summary>
+ public const EventKeywords Interop = (EventKeywords)0x0001; // This is bit 0.
+ }
+
+ //-----------------------------------------------------------------------------------
+ //
+ // Interop Event IDs (must be unique)
+ //
+
+ #region RCWProvider
+ #region TaskID
+ /// <summary>A new RCW was created. Details at TaskRCWCreation.</summary>
+ private const int TASKRCWCREATION_ID = 10;
+ /// <summary>A RCW was finalized. Details at TaskRCWFinalization.</summary>
+ private const int TASKRCWFINALIZATION_ID = 11;
+ /// <summary>The RCW reference counter was incremented. Details at TaskRCWRefCountInc.</summary>
+ private const int TASKRCWREFCOUNTINC_ID = 12;
+ /// <summary>The RCW reference counter was decremented. Details at TaskRCWRefCountDec.</summary>
+ private const int TASKRCWREFCOUNTDEC_ID = 13;
+ /// <summary>The query interface failure. Details at TaskRCWQueryInterfaceFailure.</summary>
+ private const int TASKRCWQUERYINTERFACEFAILURE_ID = 14;
+ #endregion TaskID
+ #region TaskRCWCreation
+ /// <summary>
+ /// Fired when a new RCW was created.
+ /// </summary>
+ /// <scenarios>
+ /// - Pair with RCW finalization to understand RCW lifetime and analyze leaks
+ /// - Reference with other RCW events to understand basic properties of RCW (without using tool to inspect RCWs at runtime)
+ /// - Understanding why weakly typed RCW are created or strongly-typed RCW are created
+ /// </scenarios>
+ /// <param name="comObject">Base address that unique identify the RCW.</param>
+ /// <param name="typeRawValue">RCW type identification.</param>
+ /// <param name="runtimeClassName">RCW runtime class name.</param>
+ /// <param name="context">RCW context.</param>
+ /// <param name="flags">RCW control flags.</param>
+ [SecuritySafeCritical]
+ [Event(TASKRCWCREATION_ID, Message = "New RCW created", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskRCWCreation(long objectID, long typeRawValue, string runtimeClassName, long context, long flags)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[5];
+
+ int runtimeClassNameLength = (runtimeClassName.Length + 1) * 2;
+ fixed (char* StringAux = runtimeClassName)
+ {
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(long);
+ eventPayload[1].DataPointer = ((IntPtr)(&typeRawValue));
+ eventPayload[2].Size = runtimeClassNameLength;
+ eventPayload[2].DataPointer = ((IntPtr)(StringAux));
+ eventPayload[3].Size = sizeof(long);
+ eventPayload[3].DataPointer = ((IntPtr)(&context));
+ eventPayload[4].Size = sizeof(long);
+ eventPayload[4].DataPointer = ((IntPtr)(&flags));
+
+ WriteEventCore(TASKRCWCREATION_ID, 5, eventPayload);
+ }
+ }
+ }
+ }
+ #endregion TaskRCWCreation
+ #region TaskRCWRefCountInc
+ /// <summary>
+ /// Fired when a reference counter is incremented in RCW.
+ /// </summary>
+ /// <scenarios>
+ /// - Diagnosing Marshal.ReleaseCOmObject/FInalReleaseComObject errors
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the RCW.</param>
+ /// <param name="refCount">New reference counter value.</param>
+ [SecuritySafeCritical]
+ [Event(TASKRCWREFCOUNTINC_ID, Message = "RCW refCount incremented", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskRCWRefCountInc(long objectID, int refCount)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[2];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(int);
+ eventPayload[1].DataPointer = ((IntPtr)(&refCount));
+
+ WriteEventCore(TASKRCWREFCOUNTINC_ID, 2, eventPayload);
+ }
+ }
+ }
+ #endregion TaskRCWRefCountInc
+ #region TaskRCWRefCountDec
+ /// <summary>
+ /// Fired when a reference counter is decremented in RCW.
+ /// </summary>
+ /// <scenarios>
+ /// - Diagnosing Marshal.ReleaseCOmObject/FInalReleaseComObject errors
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the RCW.</param>
+ /// <param name="refCount">New reference counter value.</param>
+ [SecuritySafeCritical]
+ [Event(TASKRCWREFCOUNTDEC_ID, Message = "RCW refCount decremented", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskRCWRefCountDec(long objectID, int refCount)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[2];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(int);
+ eventPayload[1].DataPointer = ((IntPtr)(&refCount));
+
+ WriteEventCore(TASKRCWREFCOUNTDEC_ID, 2, eventPayload);
+ }
+ }
+ }
+ #endregion TaskRCWRefCountDec
+ #region TaskRCWFinalization
+ /// <summary>
+ /// Fired when a new RCW was finalized.
+ /// </summary>
+ /// <scenarios>
+ /// - Pair with RCW finalization to understand RCW lifetime and analyze leaks
+ /// - See if certain COM objects are finalized or not
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the RCW.</param>
+ /// <param name="refCount">RCW reference counter.</param>
+ [SecuritySafeCritical]
+ [Event(TASKRCWFINALIZATION_ID, Message = "RCW Finalized", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskRCWFinalization(long objectID, int refCount)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[2];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(int);
+ eventPayload[1].DataPointer = ((IntPtr)(&refCount));
+
+ WriteEventCore(TASKRCWFINALIZATION_ID, 2, eventPayload);
+ }
+ }
+ }
+ #endregion TaskRCWFinalization
+ #region TaskRCWQueryInterfaceFailure
+ /// <summary>
+ /// Fired when a RCW Interface address is queried and failure.
+ /// </summary>
+ /// <scenarios>
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the RCW.</param>
+ /// <param name="context">RCW context.</param>
+ /// <param name="interfaceIId">Queried interface IID.</param>
+ /// <param name="reason">Failure reason.</param>
+ /// <remarks>Not used</remarks>
+ [SecuritySafeCritical]
+ [Event(TASKRCWQUERYINTERFACEFAILURE_ID, Message = "RCW Queried Interface Failure", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskRCWQueryInterfaceFailure(long objectID, long context, Guid interfaceIId, int reason)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[4];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(long);
+ eventPayload[1].DataPointer = ((IntPtr)(&context));
+ eventPayload[2].Size = sizeof(Guid);
+ eventPayload[2].DataPointer = ((IntPtr)(&interfaceIId));
+ eventPayload[3].Size = sizeof(int);
+ eventPayload[3].DataPointer = ((IntPtr)(&reason));
+
+ WriteEventCore(TASKRCWQUERYINTERFACEFAILURE_ID, 4, eventPayload);
+ }
+ }
+ }
+ #endregion TaskRCWQueryInterfaceFailure
+ #endregion RCWProvider
+
+ #region CCWProvider
+ #region TaskID
+ /// <summary>A new CCW was created. Details at TaskCCWCreation. Details at TaskCCWCreation.</summary>
+ private const int TASKCCWCREATION_ID = 20;
+ /// <summary>A CCW was finalized. Details at TaskCCWFinalization. Details at TaskCCWFinalization.</summary>
+ private const int TASKCCWFINALIZATION_ID = 21;
+ /// <summary>The CCW reference counter was incremented. Details at TaskCCWRefCountInc.</summary>
+ private const int TASKCCWREFCOUNTINC_ID = 22;
+ /// <summary>The CCW reference counter was decremented. Details at TaskCCWRefCountDec.</summary>
+ private const int TASKCCWREFCOUNTDEC_ID = 23;
+ /// <summary>The Runtime class name was queried. Details at TaskCCWQueryRuntimeClassName.</summary>
+ private const int TASKCCWQUERYRUNTIMECLASSNAME_ID = 24;
+ /// <summary>An interface was queried whit error. Details at TaskCCWQueryInterfaceFailure.</summary>
+ private const int TASKCCWQUERYINTERFACEFAILURE_ID = 30;
+ /// <summary>Resolve was queried with error. Details at TaskCCWResolveFailure.</summary>
+ private const int TASKCCWRESOLVEFAILURE_ID = 33;
+ #endregion TaskID
+ #region TaskCCWCreation
+ /// <summary>
+ /// Fired when a new CCW was created.
+ /// </summary>
+ /// <scenarios>
+ /// - Understand lifetime of CCWs
+ /// - Reference with other CCW events
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the CCW.</param>
+ /// <param name="targetObjectID">Base address that unique identify the target object in CCW.</param>
+ /// <param name="targetObjectIDType">Raw value for the type of the target Object.</param>
+ [SecuritySafeCritical]
+ [Event(TASKCCWCREATION_ID, Message = "New CCW created", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskCCWCreation(long objectID, long targetObjectID, long targetObjectIDType)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[3];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(long);
+ eventPayload[1].DataPointer = ((IntPtr)(&targetObjectID));
+ eventPayload[2].Size = sizeof(long);
+ eventPayload[2].DataPointer = ((IntPtr)(&targetObjectIDType));
+
+ WriteEventCore(TASKCCWCREATION_ID, 3, eventPayload);
+ }
+ }
+ }
+ #endregion TaskCCWCreation
+ #region TaskCCWFinalization
+ /// <summary>
+ /// Fired when a new CCW was finalized.
+ /// </summary>
+ /// <scenarios>
+ /// - Understand lifetime of CCWs and help track addref/release problems.
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the CCW.</param>
+ /// <param name="refCount">The reference counter value at the ending time.</param>
+ [SecuritySafeCritical]
+ [Event(TASKCCWFINALIZATION_ID, Message = "CCW Finalized", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskCCWFinalization(long objectID, long refCount)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[2];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(long);
+ eventPayload[1].DataPointer = ((IntPtr)(&refCount));
+
+ WriteEventCore(TASKCCWFINALIZATION_ID, 2, eventPayload);
+ }
+ }
+ }
+ #endregion TaskCCWFinalization
+ #region TaskCCWRefCountInc
+ /// <summary>
+ /// Fired when a reference counter is incremented in CCW.
+ /// </summary>
+ /// <scenarios>
+ /// - Tracking addref/release problems
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the CCW.</param>
+ /// <param name="refCount">New reference counter value.</param>
+ [SecuritySafeCritical]
+ [Event(TASKCCWREFCOUNTINC_ID, Message = "CCW refCount incremented", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskCCWRefCountInc(long objectID, long refCount)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[2];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(long);
+ eventPayload[1].DataPointer = ((IntPtr)(&refCount));
+
+ WriteEventCore(TASKCCWREFCOUNTINC_ID, 2, eventPayload);
+ }
+ }
+ }
+ #endregion TaskCCWRefCountInc
+ #region TaskCCWRefCountDec
+ /// <summary>
+ /// Fired when a reference counter is decremented in CCW.
+ /// </summary>
+ /// <scenarios>
+ /// - Tracking addref/release problems
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the CCW.</param>
+ /// <param name="refCount">New reference counter value.</param>
+ [SecuritySafeCritical]
+ [Event(TASKCCWREFCOUNTDEC_ID, Message = "CCW refCount decremented", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskCCWRefCountDec(long objectID, long refCount)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[2];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(long);
+ eventPayload[1].DataPointer = ((IntPtr)(&refCount));
+
+ WriteEventCore(TASKCCWREFCOUNTDEC_ID, 2, eventPayload);
+ }
+ }
+ }
+ #endregion TaskCCWRefCountDec
+ #region TaskCCWQueryRuntimeClassName
+ /// <summary>
+ /// Fired when a runtime class name was queried.
+ /// </summary>
+ /// <scenarios>
+ /// - Diagnosing bugs in JavaScript/.NET interaction, such as why JavaSCript refuse to call a function on a managed WinMD type
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the CCW.</param>
+ /// <param name="runtimeClassName">Required runtime class name.</param>
+ [SecuritySafeCritical]
+ [Event(TASKCCWQUERYRUNTIMECLASSNAME_ID, Message = "CCW runtime class name required", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskCCWQueryRuntimeClassName(long objectID, string runtimeClassName)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[2];
+
+ int runtimeClassNameLength = (runtimeClassName.Length + 1) * 2;
+ fixed (char* StringAux = runtimeClassName)
+ {
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = runtimeClassNameLength;
+ eventPayload[1].DataPointer = ((IntPtr)(StringAux));
+
+ WriteEventCore(TASKCCWQUERYRUNTIMECLASSNAME_ID, 2, eventPayload);
+ }
+ }
+ }
+ }
+ #endregion TaskCCWQueryRuntimeClassName
+ #region TaskCCWQueryInterfaceFailure
+ /// <summary>
+ /// Fired when a CCW Interface address is queried and for any reason it was rejected.
+ /// </summary>
+ /// <scenarios>
+ /// - Diagnosing interop bugs where Qis are rejected for no apparent reason and causing Jupiter to fail in strange ways.
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the CCW.</param>
+ /// <param name="interfaceIId">Guid of the queried interface.</param>
+ [SecuritySafeCritical]
+ [Event(TASKCCWQUERYINTERFACEFAILURE_ID, Message = "CCW queried interface failure", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskCCWQueryInterfaceFailure(long objectID, Guid interfaceIId)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[2];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(Guid);
+ eventPayload[1].DataPointer = ((IntPtr)(&interfaceIId));
+
+ WriteEventCore(TASKCCWQUERYINTERFACEFAILURE_ID, 2, eventPayload);
+ }
+ }
+ }
+ #endregion TaskCCWQueryInterfaceFailure
+ #region TaskCCWResolveFailure
+ /// <summary>
+ /// Fired when a CCW interface resolve is queried and for any reason it was rejected.
+ /// </summary>
+ /// <scenarios>
+ /// - Diagnosing interop bugs where Resolves are rejected for no apparent reason and causing to fail.
+ /// </scenarios>
+ /// <param name="objectID">Base address that unique identify the CCW.</param>
+ /// <param name="interfaceAddress">Address of the interface that must be resolved</param>
+ /// <param name="interfaceIId">Guid of the queried interface.</param>
+ /// <param name="rejectedReason">Rejected reason.</param>
+ [SecuritySafeCritical]
+ [Event(TASKCCWRESOLVEFAILURE_ID, Message = "CCW resolve failure", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskCCWResolveFailure(long objectID, long interfaceAddress, Guid interfaceIId, int rejectedReason)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[4];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&objectID));
+ eventPayload[1].Size = sizeof(long);
+ eventPayload[1].DataPointer = ((IntPtr)(&interfaceAddress));
+ eventPayload[2].Size = sizeof(Guid);
+ eventPayload[2].DataPointer = ((IntPtr)(&interfaceIId));
+ eventPayload[3].Size = sizeof(int);
+ eventPayload[3].DataPointer = ((IntPtr)(&rejectedReason));
+
+ WriteEventCore(TASKCCWRESOLVEFAILURE_ID, 4, eventPayload);
+ }
+ }
+ }
+ #endregion TaskCCWResolveFailure
+ #endregion CCWProvider
+
+ #region JupiterProvider
+ #region TaskID
+ /// <summary>Jupter Garbage Collector was invoked via Callback. Details at TaskJupiterGarbageCollect.</summary>
+ private const int TASKJUPITERGARBAGECOLLECT_ID = 40;
+ /// <summary>Jupiter disconnect RCWs in current apartment. Details at TaskJupiterDisconnectRCWsInCurrentApartment.</summary>
+ private const int TASKJUPITERDISCONNECTERCWSINCURRENTAPARTMENT_ID = 41;
+ /// <summary>Jupiter add memory pressure callback. Details at TaskJupiterAddMemoryPressure.</summary>
+ private const int TASKJUPITERADDMEMORYPRESSURE_ID = 42;
+ /// <summary>Jupiter renove memory pressure callback. Details at TaskJupiterRemoveMemoryPressure.</summary>
+ private const int TASKJUPITERREMOVEMEMORYPRESSURE_ID = 43;
+ /// <summary>Jupiter create managed reference callback. Details at TaskJupiterCreateManagedReference.</summary>
+ private const int TASKJUPITERCREATEMANAGEDREFERENCE_ID = 44;
+ #endregion TaskID
+ #region TaskJupiterGarbageCollect
+ /// <summary>
+ /// Fired when Jupiter garbage collector callback is called.
+ /// </summary>
+ /// <scenarios>
+ /// - Monitoring the frequency of GarbageCollect is being triggered by Jupiter
+ /// </scenarios>
+ [SecuritySafeCritical]
+ [Event(TASKJUPITERGARBAGECOLLECT_ID, Message = "Garbage Collect", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskJupiterGarbageCollect()
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ WriteEventCore(TASKJUPITERGARBAGECOLLECT_ID, 0, null);
+ }
+ }
+ }
+ #endregion TaskJupiterGarbageCollect
+ #region TaskJupiterDisconnectRCWsInCurrentApartment
+ /// <summary>
+ /// Fired when Jupiter disconnect RCWs in current apartment.
+ /// </summary>
+ /// <scenarios>
+ /// - Monitoring the frequency of wait for pending finalizer callback is being triggered by Jupiter
+ /// </scenarios>
+ [SecuritySafeCritical]
+ [Event(TASKJUPITERDISCONNECTERCWSINCURRENTAPARTMENT_ID, Message = "Jupiter disconnect RCWs in current apartment", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskJupiterDisconnectRCWsInCurrentApartment()
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ WriteEventCore(TASKJUPITERDISCONNECTERCWSINCURRENTAPARTMENT_ID, 0, null);
+ }
+ }
+ }
+ #endregion TaskJupiterDisconnectRCWsInCurrentApartment
+ #region TaskJupiterAddMemoryPressure
+ /// <summary>
+ /// Fired when a Jupiter add memory pressure callback is called.
+ /// </summary>
+ /// <scenarios>
+ /// - Monitoring memory pressure added by Jupiter
+ /// </scenarios>
+ /// <param name="memorySize">Number of bytes in the added memory.</param>
+ [SecuritySafeCritical]
+ [Event(TASKJUPITERADDMEMORYPRESSURE_ID, Message = "Jupiter add memory pressure", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskJupiterAddMemoryPressure(long memorySize)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[1];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&memorySize));
+
+ WriteEventCore(TASKJUPITERADDMEMORYPRESSURE_ID, 1, eventPayload);
+ }
+ }
+ }
+ #endregion TaskJupiterAddMemoryPressure
+ #region TaskJupiterRemoveMemoryPressure
+ /// <summary>
+ /// Fired when a Jupiter Remove memory pressure callback is called.
+ /// </summary>
+ /// <scenarios>
+ /// - Monitoring memory pressure Removeed by Jupiter
+ /// </scenarios>
+ /// <param name="memorySize">Number of bytes in the memory removed.</param>
+ [SecuritySafeCritical]
+ [Event(TASKJUPITERREMOVEMEMORYPRESSURE_ID, Message = "Jupiter Remove memory pressure", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskJupiterRemoveMemoryPressure(long memorySize)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[1];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&memorySize));
+
+ WriteEventCore(TASKJUPITERREMOVEMEMORYPRESSURE_ID, 1, eventPayload);
+ }
+ }
+ }
+ #endregion TaskJupiterRemoveMemoryPressure
+ #region TaskJupiterCreateManagedReference
+ /// <summary>
+ /// Fired when a new managed reference is created in Jupiter.
+ /// </summary>
+ /// <scenarios>
+ /// - Monitoring the frequency of managed 'proxies' being created/used.
+ /// </scenarios>
+ /// <param name="IUnknown">Base address that unique identify the Jupiter.</param>
+ /// <param name="objectType">Jupiter type.</param>
+ [SecuritySafeCritical]
+ [Event(TASKJUPITERCREATEMANAGEDREFERENCE_ID, Message = "Jupiter create managed reference", Level = EventLevel.Verbose, Keywords = Keywords.Interop)]
+ public void TaskJupiterCreateManagedReference(long IUnknown, long objectType)
+ {
+ if (IsEnabled(EventLevel.Verbose, Keywords.Interop))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[2];
+
+ eventPayload[0].Size = sizeof(long);
+ eventPayload[0].DataPointer = ((IntPtr)(&IUnknown));
+ eventPayload[1].Size = sizeof(long);
+ eventPayload[1].DataPointer = ((IntPtr)(&objectType));
+
+ WriteEventCore(TASKJUPITERCREATEMANAGEDREFERENCE_ID, 2, eventPayload);
+ }
+ }
+ }
+ #endregion TaskJupiterCreateManagedReference
+ #endregion JupiterProvider
+
+ } //Class InteropEventProvider
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/InvalidComObjectException.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/InvalidComObjectException.cs
new file mode 100644
index 000000000..286c9f344
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/InvalidComObjectException.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.
+
+/*=============================================================================
+**
+** Class: InvalidComObjectException
+**
+** 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.
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public class InvalidComObjectException : Exception
+ {
+ public InvalidComObjectException()
+ : base(SR.Arg_InvalidComObjectException)
+ {
+ HResult = __HResults.COR_E_INVALIDCOMOBJECT;
+ }
+
+ public InvalidComObjectException(String message)
+ : base(message)
+ {
+ HResult = __HResults.COR_E_INVALIDCOMOBJECT;
+ }
+
+ public InvalidComObjectException(String message, Exception inner)
+ : base(message, inner)
+ {
+ HResult = __HResults.COR_E_INVALIDCOMOBJECT;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs
new file mode 100644
index 000000000..80664c20c
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.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.
+
+//
+
+//
+
+/*=============================================================================
+**
+** Class: InvalidOleVariantTypeException
+**
+** Purpose: The type of an OLE variant that was passed into the runtime is
+** invalid.
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public class InvalidOleVariantTypeException : Exception
+ {
+ public InvalidOleVariantTypeException()
+ : base(SR.Arg_InvalidOleVariantTypeException)
+ {
+ HResult = __HResults.COR_E_INVALIDOLEVARIANTTYPE;
+ }
+
+ public InvalidOleVariantTypeException(String message)
+ : base(message)
+ {
+ HResult = __HResults.COR_E_INVALIDOLEVARIANTTYPE;
+ }
+
+ public InvalidOleVariantTypeException(String message, Exception inner)
+ : base(message, inner)
+ {
+ HResult = __HResults.COR_E_INVALIDOLEVARIANTTYPE;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/LCIDConversionAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/LCIDConversionAttribute.cs
new file mode 100644
index 000000000..7cd146af3
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/LCIDConversionAttribute.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.
+
+//
+
+//
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Method, Inherited = false)]
+ internal sealed class LCIDConversionAttribute : Attribute
+ {
+ internal int _val;
+ public LCIDConversionAttribute(int lcid)
+ {
+ _val = lcid;
+ }
+ public int Value { get { return _val; } }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs
new file mode 100644
index 000000000..fef1344a7
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs
@@ -0,0 +1,1614 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+//
+// This file provides an implementation of the pieces of the Marshal class which are required by the Interop
+// API contract but are not provided by the version of Marshal which is part of the Redhawk test library.
+// This partial class is combined with the version from the Redhawk test library, in order to provide the
+// Marshal implementation for System.Private.CoreLib.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+using System.Text;
+using System.Threading;
+using System.Reflection;
+
+#if ENABLE_WINRT
+using System.Runtime.InteropServices.ComTypes;
+#endif //ENABLE_WINRT
+
+namespace System.Runtime.InteropServices
+{
+ public static partial class Marshal
+ {
+
+
+ private const long HIWORDMASK = unchecked((long)0xffffffffffff0000L);
+
+ // 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)
+ {
+ long lPtr = (long)ptr;
+ return 0 == (lPtr & HIWORDMASK);
+ }
+
+ private static bool IsNotWin32Atom(IntPtr ptr)
+ {
+ long lPtr = (long)ptr;
+ return 0 != (lPtr & HIWORDMASK);
+ }
+
+ //====================================================================
+ // 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();
+
+ //====================================================================
+ // Helper method to retrieve the system's maximum DBCS character size.
+ //====================================================================
+ private static unsafe int GetSystemMaxDBCSCharSize()
+ {
+ ExternalInterop.CPINFO cpInfo;
+ if (ExternalInterop.GetCPInfo(ExternalInterop.Constants.CP_ACP, &cpInfo) != 0)
+ {
+ return cpInfo.MaxCharSize;
+ }
+ else
+ {
+ return 2;
+ }
+ }
+
+ public unsafe static String PtrToStringAnsi(IntPtr ptr)
+ {
+ if (IntPtr.Zero == ptr)
+ {
+ return null;
+ }
+ else if (IsWin32Atom(ptr))
+ {
+ return null;
+ }
+ else
+ {
+ int nb = lstrlenA(ptr);
+
+ if (nb == 0)
+ {
+ return string.Empty;
+ }
+ else
+ {
+ return ConvertToUnicode(ptr, nb);
+ }
+ }
+ }
+
+ public unsafe static String PtrToStringAnsi(IntPtr ptr, int len)
+ {
+ if (ptr == IntPtr.Zero)
+ throw new ArgumentNullException("ptr");
+ if (len < 0)
+ throw new ArgumentException("len");
+
+ return ConvertToUnicode(ptr, len);
+ }
+
+ public unsafe 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);
+ }
+
+ public unsafe static String PtrToStringUni(IntPtr ptr)
+ {
+ if (IntPtr.Zero == ptr)
+ {
+ return null;
+ }
+ else if (IsWin32Atom(ptr))
+ {
+ return null;
+ }
+ else
+ {
+ return new String((char*)ptr);
+ }
+ }
+
+ //====================================================================
+ // SizeOf()
+ //====================================================================
+
+ /// <summary>
+ /// Returns the size of an instance of a value type.
+ /// </summary>
+ public static int SizeOf<T>()
+ {
+ return SizeOf(typeof(T));
+ }
+
+ public static int SizeOf<T>(T structure)
+ {
+ return SizeOf<T>();
+ }
+
+ 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);
+ }
+
+ [Pure]
+ public static int SizeOf(Type t)
+ {
+ if (t == null)
+ throw new ArgumentNullException("t");
+ if (t.TypeHandle.IsGenericType())
+ throw new ArgumentException(SR.Argument_NeedNonGenericType, "t");
+ Contract.EndContractBlock();
+
+ return SizeOfHelper(t, true);
+ }
+
+ private static int SizeOfHelper(Type t, bool throwIfNotMarshalable)
+ {
+ RuntimeTypeHandle typeHandle = t.TypeHandle;
+
+ McgStructMarshalData structMarshalData;
+ if (McgModuleManager.TryGetStructMarshalData(typeHandle, out structMarshalData))
+ {
+ return structMarshalData.UnsafeStructType.GetValueTypeSize();
+ }
+
+ if (!typeHandle.IsBlittable() && !typeHandle.IsValueType())
+ {
+ throw new MissingInteropDataException(SR.StructMarshalling_MissingInteropData, t);
+ }
+ else
+ {
+ return typeHandle.GetValueTypeSize();
+ }
+ }
+
+ //====================================================================
+ // OffsetOf()
+ //====================================================================
+ public static IntPtr OffsetOf(Type t, String fieldName)
+ {
+ if (t == null)
+ throw new ArgumentNullException("t");
+
+ if (String.IsNullOrEmpty(fieldName))
+ throw new ArgumentNullException("fieldName");
+
+ if (t.TypeHandle.IsGenericType())
+ throw new ArgumentException(SR.Argument_NeedNonGenericType, "t");
+
+ Contract.EndContractBlock();
+
+ return OffsetOfHelper(t, fieldName);
+ }
+
+ private static IntPtr OffsetOfHelper(Type t, String fieldName)
+ {
+ bool structExists;
+ uint offset;
+ if (McgModuleManager.TryGetStructFieldOffset(t.TypeHandle, fieldName, out structExists, out offset))
+ {
+ return new IntPtr(offset);
+ }
+
+ // if we can find the struct but couldn't find its field, throw Argument Exception
+ if (structExists)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_OffsetOfFieldNotFound, t.TypeHandle.GetDisplayName()), "fieldName");
+ }
+ else
+ {
+ throw new MissingInteropDataException(SR.StructMarshalling_MissingInteropData, t);
+ }
+ }
+
+ public static IntPtr OffsetOf<T>(String fieldName)
+ {
+ return OffsetOf(typeof(T), fieldName);
+ }
+
+ //====================================================================
+ // Copy blocks from CLR arrays to native memory.
+ //====================================================================
+ public static void Copy(int[] source, int startIndex, IntPtr destination, int length)
+ {
+ CopyToNative(source, startIndex, destination, length);
+ }
+
+ public static void Copy(char[] source, int startIndex, IntPtr destination, int length)
+ {
+ CopyToNative(source, startIndex, destination, length);
+ }
+
+ public static void Copy(short[] source, int startIndex, IntPtr destination, int length)
+ {
+ CopyToNative(source, startIndex, destination, length);
+ }
+
+ public static void Copy(long[] source, int startIndex, IntPtr destination, int length)
+ {
+ CopyToNative(source, startIndex, destination, length);
+ }
+
+ public static void Copy(float[] source, int startIndex, IntPtr destination, int length)
+ {
+ CopyToNative(source, startIndex, destination, length);
+ }
+
+ public static void Copy(double[] source, int startIndex, IntPtr destination, int length)
+ {
+ CopyToNative(source, startIndex, destination, length);
+ }
+
+ public static void Copy(byte[] source, int startIndex, IntPtr destination, int length)
+ {
+ CopyToNative(source, startIndex, destination, length);
+ }
+
+ public static void Copy(IntPtr[] source, int startIndex, IntPtr destination, int length)
+ {
+ CopyToNative(source, startIndex, destination, length);
+ }
+
+ private static void CopyToNative(Array source, int startIndex, IntPtr destination, int length)
+ {
+ InteropExtensions.CopyToNative(source, startIndex, destination, length);
+ }
+
+ //====================================================================
+ // Copy blocks from native memory to CLR arrays
+ //====================================================================
+ public static void Copy(IntPtr source, int[] destination, int startIndex, int length)
+ {
+ CopyToManaged(source, destination, startIndex, length);
+ }
+
+ public static void Copy(IntPtr source, char[] destination, int startIndex, int length)
+ {
+ CopyToManaged(source, destination, startIndex, length);
+ }
+
+ public static void Copy(IntPtr source, short[] destination, int startIndex, int length)
+ {
+ CopyToManaged(source, destination, startIndex, length);
+ }
+
+ public static void Copy(IntPtr source, long[] destination, int startIndex, int length)
+ {
+ CopyToManaged(source, destination, startIndex, length);
+ }
+
+ public static void Copy(IntPtr source, float[] destination, int startIndex, int length)
+ {
+ CopyToManaged(source, destination, startIndex, length);
+ }
+
+ public static void Copy(IntPtr source, double[] destination, int startIndex, int length)
+ {
+ CopyToManaged(source, destination, startIndex, length);
+ }
+
+ public static void Copy(IntPtr source, byte[] destination, int startIndex, int length)
+ {
+ CopyToManaged(source, destination, startIndex, length);
+ }
+
+ public static void Copy(IntPtr source, IntPtr[] destination, int startIndex, int length)
+ {
+ CopyToManaged(source, destination, startIndex, length);
+ }
+
+ private static void CopyToManaged(IntPtr source, Array destination, int startIndex, int length)
+ {
+ InteropExtensions.CopyToManaged(source, destination, startIndex, length);
+ }
+
+
+ //====================================================================
+ // Read from memory
+ //====================================================================
+
+
+ public static unsafe byte ReadByte(IntPtr ptr, int ofs)
+ {
+ byte* addr = (byte*)ptr + ofs;
+ return *addr;
+ }
+
+ public static byte ReadByte(IntPtr ptr)
+ {
+ return ReadByte(ptr, 0);
+ }
+
+ public static unsafe short ReadInt16(IntPtr ptr, int ofs)
+ {
+ 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;
+ }
+ }
+
+ public static short ReadInt16(IntPtr ptr)
+ {
+ return ReadInt16(ptr, 0);
+ }
+
+ public static unsafe int ReadInt32(IntPtr ptr, int ofs)
+ {
+ 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;
+ }
+ }
+
+ public static int ReadInt32(IntPtr ptr)
+ {
+ return ReadInt32(ptr, 0);
+ }
+
+ 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
+ }
+
+ public static IntPtr ReadIntPtr(IntPtr ptr, int ofs)
+ {
+#if WIN32
+ return (IntPtr)ReadInt32(ptr, ofs);
+#else
+ return (IntPtr)ReadInt64(ptr, ofs);
+#endif
+ }
+
+ public static IntPtr ReadIntPtr(IntPtr ptr)
+ {
+#if WIN32
+ return (IntPtr)ReadInt32(ptr, 0);
+#else
+ return (IntPtr)ReadInt64(ptr, 0);
+#endif
+ }
+
+ public static unsafe long ReadInt64(IntPtr ptr, int ofs)
+ {
+ 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;
+ }
+ }
+
+ public static long ReadInt64(IntPtr ptr)
+ {
+ return ReadInt64(ptr, 0);
+ }
+
+ //====================================================================
+ // Write to memory
+ //====================================================================
+ public static unsafe void WriteByte(IntPtr ptr, int ofs, byte val)
+ {
+ byte* addr = (byte*)ptr + ofs;
+ *addr = val;
+ }
+
+ public static void WriteByte(IntPtr ptr, byte val)
+ {
+ WriteByte(ptr, 0, val);
+ }
+
+ public static unsafe void WriteInt16(IntPtr ptr, int ofs, short val)
+ {
+ 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];
+ }
+ }
+
+ public static void WriteInt16(IntPtr ptr, short val)
+ {
+ WriteInt16(ptr, 0, val);
+ }
+
+ public static void WriteInt16(IntPtr ptr, int ofs, char val)
+ {
+ WriteInt16(ptr, ofs, (short)val);
+ }
+
+ public static void WriteInt16([In, Out]Object ptr, int ofs, char val)
+ {
+ WriteInt16(ptr, ofs, (short)val);
+ }
+
+ public static void WriteInt16(IntPtr ptr, char val)
+ {
+ WriteInt16(ptr, 0, (short)val);
+ }
+
+ public static unsafe void WriteInt32(IntPtr ptr, int ofs, int val)
+ {
+ 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];
+ }
+ }
+
+ public static void WriteInt32(IntPtr ptr, int val)
+ {
+ WriteInt32(ptr, 0, val);
+ }
+
+ public static void WriteIntPtr(IntPtr ptr, int ofs, IntPtr val)
+ {
+#if WIN32
+ WriteInt32(ptr, ofs, (int)val);
+#else
+ WriteInt64(ptr, ofs, (long)val);
+#endif
+ }
+
+ 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
+ }
+
+ public static void WriteIntPtr(IntPtr ptr, IntPtr val)
+ {
+#if WIN32
+ WriteInt32(ptr, 0, (int)val);
+#else
+ WriteInt64(ptr, 0, (long)val);
+#endif
+ }
+
+ public static unsafe void WriteInt64(IntPtr ptr, int ofs, long val)
+ {
+ 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];
+ }
+ }
+
+ public static void WriteInt64(IntPtr ptr, long val)
+ {
+ WriteInt64(ptr, 0, val);
+ }
+
+ //====================================================================
+ // GetHRForLastWin32Error
+ //====================================================================
+ public static int GetHRForLastWin32Error()
+ {
+ int dwLastError = GetLastWin32Error();
+ if ((dwLastError & 0x80000000) == 0x80000000)
+ {
+ return dwLastError;
+ }
+ else
+ {
+ return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
+ }
+ }
+
+ public static Exception GetExceptionForHR(int errorCode, IntPtr errorInfo)
+ {
+#if ENABLE_WINRT
+ if (errorInfo != new IntPtr(-1))
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ return ExceptionHelpers.GetMappingExceptionForHR(
+ errorCode,
+ message: null,
+ createCOMException: false,
+ hasErrorInfo: false);
+#else
+ throw new PlatformNotSupportedException();
+#endif // ENABLE_WINRT
+ }
+
+ //====================================================================
+ // Throws a CLR exception based on the HRESULT.
+ //====================================================================
+ public static void ThrowExceptionForHR(int errorCode)
+ {
+ ThrowExceptionForHRInternal(errorCode, IntPtr.Zero);
+ }
+
+ public static void ThrowExceptionForHR(int errorCode, IntPtr errorInfo)
+ {
+ ThrowExceptionForHRInternal(errorCode, errorInfo);
+ }
+
+ private static void ThrowExceptionForHRInternal(int errorCode, IntPtr errorInfo)
+ {
+ if (errorCode < 0)
+ {
+ throw GetExceptionForHR(errorCode, errorInfo);
+ }
+ }
+
+ //====================================================================
+ // Memory allocation and deallocation.
+ //====================================================================
+ public static IntPtr AllocHGlobal(IntPtr cb)
+ {
+ IntPtr pNewMem = ExternalInterop.MemAlloc(cb);
+ if (pNewMem == IntPtr.Zero)
+ {
+ throw new OutOfMemoryException();
+ }
+ return pNewMem;
+ }
+
+ public static IntPtr AllocHGlobal(int cb)
+ {
+ return AllocHGlobal((IntPtr)cb);
+ }
+
+ public static void FreeHGlobal(IntPtr hglobal)
+ {
+ if (IsNotWin32Atom(hglobal))
+ {
+ ExternalInterop.MemFree(hglobal);
+ }
+ }
+
+ public unsafe static IntPtr ReAllocHGlobal(IntPtr pv, IntPtr cb)
+ {
+ IntPtr pNewMem = ExternalInterop.MemReAlloc(pv, cb);
+ if (pNewMem == IntPtr.Zero)
+ {
+ throw new OutOfMemoryException();
+ }
+ return pNewMem;
+ }
+
+ private unsafe static void ConvertToAnsi(string source, IntPtr pbNativeBuffer, int cbNativeBuffer)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert(pbNativeBuffer != IntPtr.Zero);
+ Contract.Assert(cbNativeBuffer >= (source.Length + 1) * SystemMaxDBCSCharSize, "Insufficient buffer length passed to ConvertToAnsi");
+
+ fixed (char* pch = source)
+ {
+ int convertedBytes =
+ ExternalInterop.ConvertWideCharToMultiByte(pch, source.Length, pbNativeBuffer, cbNativeBuffer);
+ ((byte*)pbNativeBuffer)[convertedBytes] = 0;
+ }
+ }
+
+ private unsafe static string ConvertToUnicode(IntPtr sourceBuffer, int cbSourceBuffer)
+ {
+ if (IsWin32Atom(sourceBuffer))
+ {
+ throw new ArgumentException(SR.Arg_MustBeStringPtrNotAtom);
+ }
+
+ if (sourceBuffer == IntPtr.Zero || cbSourceBuffer == 0)
+ {
+ return String.Empty;
+ }
+ // MB_PRECOMPOSED is the default.
+ int charsRequired = ExternalInterop.GetCharCount(sourceBuffer, cbSourceBuffer);
+
+ if (charsRequired == 0)
+ {
+ throw new ArgumentException(SR.Arg_InvalidANSIString);
+ }
+
+ char[] wideChars = new char[charsRequired + 1];
+ fixed (char* pWideChars = wideChars)
+ {
+ int converted = ExternalInterop.ConvertMultiByteToWideChar(sourceBuffer,
+ cbSourceBuffer,
+ new IntPtr(pWideChars),
+ wideChars.Length);
+ if (converted == 0)
+ {
+ throw new ArgumentException(SR.Arg_InvalidANSIString);
+ }
+
+ wideChars[converted] = '\0';
+ return new String(pWideChars);
+ }
+ }
+
+ private static unsafe int lstrlenA(IntPtr sz)
+ {
+ Contract.Requires(sz != IntPtr.Zero);
+
+ byte* pb = (byte*)sz;
+ byte* start = pb;
+ while (*pb != 0)
+ {
+ ++pb;
+ }
+
+ return (int)(pb - start);
+ }
+
+ private static unsafe int lstrlenW(IntPtr wsz)
+ {
+ Contract.Requires(wsz != IntPtr.Zero);
+
+ char* pc = (char*)wsz;
+ char* start = pc;
+ while (*pc != 0)
+ {
+ ++pc;
+ }
+
+ return (int)(pc - start);
+ }
+
+ // Zero out the buffer pointed to by ptr, making sure that the compiler cannot
+ // replace the zeroing with a nop
+ private static unsafe void SecureZeroMemory(IntPtr ptr, int bytes)
+ {
+ Contract.Assert(ptr != IntPtr.Zero);
+ Contract.Assert(bytes >= 0);
+
+ byte* pBuffer = (byte*)ptr;
+ for (int i = 0; i < bytes; ++i)
+ {
+ Volatile.Write(ref pBuffer[i], 0);
+ }
+ }
+
+ //====================================================================
+ // String convertions.
+ //====================================================================
+ public unsafe 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");
+
+ IntPtr hglobal = ExternalInterop.MemAlloc(new IntPtr(nb));
+ if (hglobal == IntPtr.Zero)
+ {
+ throw new OutOfMemoryException();
+ }
+ else
+ {
+ ConvertToAnsi(s, hglobal, nb);
+ return hglobal;
+ }
+ }
+ }
+
+ public unsafe 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");
+
+ IntPtr hglobal = ExternalInterop.MemAlloc(new UIntPtr((uint)nb));
+
+ if (hglobal == IntPtr.Zero)
+ {
+ throw new OutOfMemoryException();
+ }
+ else
+ {
+ fixed (char* firstChar = s)
+ {
+ InteropExtensions.Memcpy(hglobal, new IntPtr(firstChar), nb);
+ }
+ return hglobal;
+ }
+ }
+ }
+
+ //====================================================================
+ // return the IUnknown* for an Object if the current context
+ // is the one where the RCW was first seen. Will return null
+ // otherwise.
+ //====================================================================
+ public static IntPtr /* IUnknown* */ GetIUnknownForObject(Object o)
+ {
+ if (o == null)
+ {
+ throw new ArgumentNullException("o");
+ }
+ return MarshalAdapter.GetIUnknownForObject(o);
+ }
+
+ //====================================================================
+ // return an Object for IUnknown
+ //====================================================================
+ public static Object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk)
+ {
+ if (pUnk == default(IntPtr))
+ {
+ throw new ArgumentNullException("pUnk");
+ }
+ return MarshalAdapter.GetObjectForIUnknown(pUnk);
+ }
+
+ //====================================================================
+ // check if the object is classic COM component
+ //====================================================================
+ public static bool IsComObject(Object o)
+ {
+ if (o == null)
+ throw new ArgumentNullException("o", SR.Arg_InvalidHandle);
+
+ return McgComHelpers.IsComObject(o);
+ }
+
+ public static unsafe IntPtr AllocCoTaskMem(int cb)
+ {
+ IntPtr pNewMem = new IntPtr(ExternalInterop.CoTaskMemAlloc(new IntPtr(cb)));
+ if (pNewMem == IntPtr.Zero)
+ {
+ throw new OutOfMemoryException();
+ }
+ return pNewMem;
+ }
+
+ public unsafe 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 = new IntPtr( ExternalInterop.CoTaskMemAlloc(new IntPtr(nb)));
+
+ if (hglobal == IntPtr.Zero)
+ {
+ throw new OutOfMemoryException();
+ }
+ else
+ {
+ fixed (char* firstChar = s)
+ {
+ InteropExtensions.Memcpy(hglobal, new IntPtr(firstChar), nb);
+ }
+ return hglobal;
+ }
+ }
+ }
+
+ public unsafe 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 = new IntPtr(ExternalInterop.CoTaskMemAlloc(new IntPtr(nb)));
+
+ if (hglobal == IntPtr.Zero)
+ {
+ throw new OutOfMemoryException();
+ }
+ else
+ {
+ ConvertToAnsi(s, hglobal, nb);
+ return hglobal;
+ }
+ }
+ }
+
+ public static unsafe void FreeCoTaskMem(IntPtr ptr)
+ {
+ if (IsNotWin32Atom(ptr))
+ {
+ ExternalInterop.CoTaskMemFree((void*)ptr);
+ }
+ }
+
+ //====================================================================
+ // release the COM component and if the reference hits 0 zombie this object
+ // further usage of this Object might throw an exception
+ //====================================================================
+ public static int ReleaseComObject(Object o)
+ {
+ if (o == null)
+ throw new ArgumentNullException("o");
+
+ __ComObject co = null;
+
+ // Make sure the obj is an __ComObject.
+ try
+ {
+ co = (__ComObject)o;
+ }
+ catch (InvalidCastException)
+ {
+ throw new ArgumentException(SR.Argument_ObjNotComObject, "o");
+ }
+
+ return McgMarshal.Release(co);
+ }
+
+ //====================================================================
+ // release the COM component and zombie this object
+ // further usage of this Object might throw an exception
+ //====================================================================
+ 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(SR.Argument_ObjNotComObject, "o");
+ }
+
+ co.FinalReleaseSelf();
+
+ return 0;
+ }
+
+ //====================================================================
+ // IUnknown Helpers
+ //====================================================================
+
+ public static int /* HRESULT */ QueryInterface(IntPtr /* IUnknown */ pUnk, ref Guid iid, out IntPtr ppv)
+ {
+ if (pUnk == IntPtr.Zero)
+ throw new ArgumentNullException("pUnk");
+
+ return McgMarshal.ComQueryInterfaceWithHR(pUnk, ref iid, out ppv);
+ }
+
+ public static int /* ULONG */ AddRef(IntPtr /* IUnknown */ pUnk)
+ {
+ if (pUnk == IntPtr.Zero)
+ throw new ArgumentNullException("pUnk");
+
+ return McgMarshal.ComAddRef(pUnk);
+ }
+
+ public static int /* ULONG */ Release(IntPtr /* IUnknown */ pUnk)
+ {
+ if (pUnk == IntPtr.Zero)
+ throw new ArgumentNullException("pUnk");
+
+ // This is documented to have "undefined behavior" when the ref count is already zero, so
+ // let's not AV if we can help it
+ return McgMarshal.ComSafeRelease(pUnk);
+ }
+
+ public static IntPtr ReAllocCoTaskMem(IntPtr pv, int cb)
+ {
+ IntPtr pNewMem = ExternalInterop.CoTaskMemRealloc(pv, new IntPtr(cb));
+ if (pNewMem == IntPtr.Zero && cb != 0)
+ {
+ throw new OutOfMemoryException();
+ }
+
+ return pNewMem;
+ }
+
+ //====================================================================
+ // BSTR allocation and dealocation.
+ //====================================================================
+ public static void FreeBSTR(IntPtr ptr)
+ {
+ if (IsNotWin32Atom(ptr))
+ {
+ ExternalInterop.SysFreeString(ptr);
+ }
+ }
+
+ public static unsafe IntPtr StringToBSTR(String s)
+ {
+ if (s == null)
+ return IntPtr.Zero;
+
+ // Overflow checking
+ if (s.Length + 1 < s.Length)
+ throw new ArgumentOutOfRangeException("s");
+
+ fixed (char* pch = s)
+ {
+ IntPtr bstr = new IntPtr( ExternalInterop.SysAllocStringLen(pch, (uint)s.Length));
+ if (bstr == IntPtr.Zero)
+ throw new OutOfMemoryException();
+
+ return bstr;
+ }
+ }
+
+ public static String PtrToStringBSTR(IntPtr ptr)
+ {
+ return PtrToStringUni(ptr, (int)ExternalInterop.SysStringLen(ptr));
+ }
+
+ public static void ZeroFreeBSTR(IntPtr s)
+ {
+ SecureZeroMemory(s, (int)ExternalInterop.SysStringLen(s) * 2);
+ FreeBSTR(s);
+ }
+
+ public static void ZeroFreeCoTaskMemAnsi(IntPtr s)
+ {
+ SecureZeroMemory(s, lstrlenA(s));
+ FreeCoTaskMem(s);
+ }
+
+ public static void ZeroFreeCoTaskMemUnicode(IntPtr s)
+ {
+ SecureZeroMemory(s, lstrlenW(s));
+ FreeCoTaskMem(s);
+ }
+
+ public static void ZeroFreeGlobalAllocAnsi(IntPtr s)
+ {
+ SecureZeroMemory(s, lstrlenA(s));
+ FreeHGlobal(s);
+ }
+
+ public static void ZeroFreeGlobalAllocUnicode(IntPtr s)
+ {
+ SecureZeroMemory(s, lstrlenW(s));
+ FreeHGlobal(s);
+ }
+
+ /// <summary>
+ /// Returns the unmanaged function pointer for this delegate
+ /// </summary>
+ public static IntPtr GetFunctionPointerForDelegate(Delegate d)
+ {
+ if (d == null)
+ throw new ArgumentNullException("d");
+
+ return McgModuleManager.GetStubForPInvokeDelegate(d);
+ }
+
+ public static IntPtr GetFunctionPointerForDelegate<TDelegate>(TDelegate d)
+ {
+ return GetFunctionPointerForDelegate((Delegate)(object)d);
+ }
+
+ //====================================================================
+ // Marshals data from a native memory block to a preallocated structure class.
+ //====================================================================
+
+ private static unsafe void PtrToStructureHelper(IntPtr ptr, Object structure)
+ {
+ RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;
+ McgStructMarshalData structMarshalData;
+
+ // Boxed struct start at offset 1 (EEType* at offset 0) while class start at offset 0
+ int offset = structureTypeHandle.IsValueType() ? 1 : 0;
+
+ if (structureTypeHandle.IsBlittable() && structureTypeHandle.IsValueType())
+ {
+ int structSize = Marshal.SizeOf(structure);
+ InteropExtensions.PinObjectAndCall(structure,
+ unboxedStructPtr =>
+ {
+ InteropExtensions.Memcpy(
+ (IntPtr)((IntPtr*)unboxedStructPtr + offset), // safe (need to adjust offset as it could be class)
+ ptr, // unsafe (no need to adjust as it is always struct)
+ structSize
+ );
+ });
+ return;
+ }
+
+ if (McgModuleManager.TryGetStructMarshalData(structureTypeHandle, out structMarshalData))
+ {
+ InteropExtensions.PinObjectAndCall(structure,
+ unboxedStructPtr =>
+ {
+ CalliIntrinsics.Call<int>(
+ structMarshalData.UnmarshalStub,
+ (void*)ptr, // unsafe (no need to adjust as it is always struct)
+ ((void*)((IntPtr*)unboxedStructPtr + offset)) // safe (need to adjust offset as it could be class)
+ );
+ });
+ return;
+ }
+
+ throw new MissingInteropDataException(SR.StructMarshalling_MissingInteropData, structure.GetType());
+ }
+
+ //====================================================================
+ // Creates a new instance of "structuretype" and marshals data from a
+ // native memory block to it.
+ //====================================================================
+ [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ public static Object PtrToStructure(IntPtr ptr, Type structureType)
+ {
+ // Boxing the struct here is important to ensure that the original copy is written to,
+ // not the autoboxed copy
+
+ if (ptr == IntPtr.Zero)
+ throw new ArgumentNullException("ptr");
+
+ if (structureType == null)
+ throw new ArgumentNullException("structureType");
+
+ Object boxedStruct = InteropExtensions.RuntimeNewObject(structureType.TypeHandle);
+ PtrToStructureHelper(ptr, boxedStruct);
+ return boxedStruct;
+ }
+
+ public static T PtrToStructure<T>(IntPtr ptr)
+ {
+ return (T)PtrToStructure(ptr, typeof(T));
+ }
+
+ public static void PtrToStructure(IntPtr ptr, Object structure)
+ {
+ if (ptr == IntPtr.Zero)
+ throw new ArgumentNullException("ptr");
+
+ if (structure == null)
+ throw new ArgumentNullException("structure");
+
+ RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;
+ if (structureTypeHandle.IsValueType())
+ {
+ throw new ArgumentException();
+ }
+
+ PtrToStructureHelper(ptr, structure);
+ }
+
+ public static void PtrToStructure<T>(IntPtr ptr, T structure)
+ {
+ PtrToStructure(ptr, (object)structure);
+ }
+
+ //====================================================================
+ // 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.
+ //====================================================================
+ public static unsafe void StructureToPtr(Object structure, IntPtr ptr, bool fDeleteOld)
+ {
+ if (structure == null)
+ throw new ArgumentNullException("structure");
+
+ if (ptr == IntPtr.Zero)
+ throw new ArgumentNullException("ptr");
+
+ if (fDeleteOld)
+ {
+ DestroyStructure(ptr, structure.GetType());
+ }
+
+ RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;
+ McgStructMarshalData structMarshalData;
+
+ // Boxed struct start at offset 1 (EEType* at offset 0) while class start at offset 0
+ int offset = structureTypeHandle.IsValueType() ? 1 : 0;
+
+ if (structureTypeHandle.IsBlittable())
+ {
+ int structSize = Marshal.SizeOf(structure);
+ InteropExtensions.PinObjectAndCall(structure,
+ unboxedStructPtr =>
+ {
+ InteropExtensions.Memcpy(
+ ptr, // unsafe (no need to adjust as it is always struct)
+ (IntPtr)((IntPtr*)unboxedStructPtr + offset), // safe (need to adjust offset as it could be class)
+ structSize
+ );
+ });
+ return;
+ }
+
+ if (McgModuleManager.TryGetStructMarshalData(structureTypeHandle, out structMarshalData))
+ {
+ InteropExtensions.PinObjectAndCall(structure,
+ unboxedStructPtr =>
+ {
+ CalliIntrinsics.Call<int>(
+ structMarshalData.MarshalStub,
+ ((void*)((IntPtr*)unboxedStructPtr + offset)), // safe (need to adjust offset as it could be class)
+ (void*)ptr // unsafe (no need to adjust as it is always struct)
+ );
+ });
+ return;
+ }
+
+ throw new MissingInteropDataException(SR.StructMarshalling_MissingInteropData, structure.GetType());
+ }
+
+ public static void StructureToPtr<T>(T structure, IntPtr ptr, bool fDeleteOld)
+ {
+ StructureToPtr((object)structure, ptr, fDeleteOld);
+ }
+
+ //====================================================================
+ // DestroyStructure()
+ //
+ //====================================================================
+ public static void DestroyStructure(IntPtr ptr, Type structuretype)
+ {
+ if (ptr == IntPtr.Zero)
+ throw new ArgumentNullException("ptr");
+
+ if (structuretype == null)
+ throw new ArgumentNullException("structuretype");
+
+ RuntimeTypeHandle structureTypeHandle = structuretype.TypeHandle;
+
+ if (structureTypeHandle.IsGenericType())
+ throw new ArgumentException(SR.Argument_NeedNonGenericType, "t");
+
+ if (structureTypeHandle.IsEnum() ||
+ structureTypeHandle.IsInterface() ||
+ InteropExtensions.AreTypesAssignable(typeof(Delegate).TypeHandle, structureTypeHandle))
+ {
+ throw new ArgumentException(SR.Argument_MustHaveLayoutOrBeBlittable, structureTypeHandle.GetDisplayName());
+ }
+
+ Contract.EndContractBlock();
+
+ DestroyStructureHelper(ptr, structuretype);
+ }
+
+ private static unsafe void DestroyStructureHelper(IntPtr ptr, Type structuretype)
+ {
+ RuntimeTypeHandle structureTypeHandle = structuretype.TypeHandle;
+
+ // Boxed struct start at offset 1 (EEType* at offset 0) while class start at offset 0
+ int offset = structureTypeHandle.IsValueType() ? 1 : 0;
+
+ if (structureTypeHandle.IsBlittable())
+ {
+ // ok to call with blittable structure, but no work to do in this case.
+ return;
+ }
+
+ McgStructMarshalData structMarshalData;
+ if (McgModuleManager.TryGetStructMarshalData(structureTypeHandle, out structMarshalData))
+ {
+ if (structMarshalData.HasInvalidLayout)
+ throw new ArgumentException(SR.Argument_MustHaveLayoutOrBeBlittable, structureTypeHandle.GetDisplayName());
+
+ // DestroyStructureStub == IntPtr.Zero means its fields don't need to be destroied
+ if (structMarshalData.DestroyStructureStub != IntPtr.Zero)
+ {
+ CalliIntrinsics.Call<int>(
+ structMarshalData.DestroyStructureStub,
+ (void*)ptr // unsafe (no need to adjust as it is always struct)
+ );
+ }
+
+ return;
+ }
+
+ // Didn't find struct marshal data
+ throw new MissingInteropDataException(SR.StructMarshalling_MissingInteropData, structuretype);
+ }
+
+ public static void DestroyStructure<T>(IntPtr ptr)
+ {
+ DestroyStructure(ptr, typeof(T));
+ }
+
+ public static IntPtr GetComInterfaceForObject<T, TInterface>(T o)
+ {
+ return GetComInterfaceForObject(o, typeof(TInterface));
+ }
+
+ public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type T)
+ {
+ return MarshalAdapter.GetComInterfaceForObject(o, T);
+ }
+
+ public static TDelegate GetDelegateForFunctionPointer<TDelegate>(IntPtr ptr)
+ {
+ return (TDelegate)(object)GetDelegateForFunctionPointer(ptr, typeof(TDelegate));
+ }
+
+ 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.TypeHandle.IsGenericType())
+ throw new ArgumentException(SR.Argument_NeedNonGenericType, "t");
+
+ bool isDelegateType = InteropExtensions.AreTypesAssignable(t.TypeHandle, typeof(MulticastDelegate).TypeHandle) ||
+ InteropExtensions.AreTypesAssignable(t.TypeHandle, typeof(Delegate).TypeHandle);
+
+ if (!isDelegateType)
+ throw new ArgumentException(SR.Arg_MustBeDelegateType, "t");
+
+ return MarshalAdapter.GetDelegateForFunctionPointer(ptr, t);
+ }
+
+ //====================================================================
+ // GetNativeVariantForObject()
+ //
+ //====================================================================
+ public static void GetNativeVariantForObject<T>(T obj, IntPtr pDstNativeVariant)
+ {
+ GetNativeVariantForObject((object)obj, pDstNativeVariant);
+ }
+
+ public static unsafe void GetNativeVariantForObject(Object obj, /* VARIANT * */ IntPtr pDstNativeVariant)
+ {
+ // Obsolete
+ if (pDstNativeVariant == IntPtr.Zero)
+ throw new ArgumentNullException("pSrcNativeVariant");
+
+ if (obj != null && obj.GetType().TypeHandle.IsGenericType())
+ throw new ArgumentException(SR.Argument_NeedNonGenericObject, "obj");
+
+ Contract.EndContractBlock();
+
+ Variant* pVariant = (Variant*)pDstNativeVariant;
+ *pVariant = new Variant(obj);
+ }
+
+ //====================================================================
+ // GetObjectForNativeVariant()
+ //
+ //====================================================================
+ public static unsafe T GetObjectForNativeVariant<T>(IntPtr pSrcNativeVariant)
+ {
+ return (T)GetObjectForNativeVariant(pSrcNativeVariant);
+ }
+
+ public static unsafe Object GetObjectForNativeVariant(/* VARIANT * */ IntPtr pSrcNativeVariant)
+ {
+ // Obsolete
+ if (pSrcNativeVariant == IntPtr.Zero)
+ throw new ArgumentNullException("pSrcNativeVariant");
+ Contract.EndContractBlock();
+
+ Variant* pNativeVar = (Variant*)pSrcNativeVariant;
+ return pNativeVar->ToObject();
+ }
+
+ //====================================================================
+ // GetObjectsForNativeVariants()
+ //
+ //====================================================================
+ public static unsafe Object[] GetObjectsForNativeVariants(IntPtr aSrcNativeVariant, int cVars)
+ {
+ // Obsolete
+ if (aSrcNativeVariant == IntPtr.Zero)
+ throw new ArgumentNullException("aSrcNativeVariant");
+
+ if (cVars < 0)
+ throw new ArgumentOutOfRangeException("cVars", SR.ArgumentOutOfRange_NeedNonNegNum);
+ Contract.EndContractBlock();
+
+ Object[] obj = new Object[cVars];
+ IntPtr aNativeVar = aSrcNativeVariant;
+ for (int i = 0; i < cVars; i++)
+ {
+ obj[i] = GetObjectForNativeVariant(aNativeVar);
+ aNativeVar = aNativeVar + sizeof(Variant);
+ }
+
+ return obj;
+ }
+
+ 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;
+ }
+
+ //====================================================================
+ // 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 !
+ //====================================================================
+ public static IntPtr UnsafeAddrOfPinnedArrayElement(Array arr, int index)
+ {
+ if (arr == null)
+ throw new ArgumentNullException("arr");
+
+ if (index < 0 || index >= arr.Length)
+ throw new ArgumentOutOfRangeException("index");
+ Contract.EndContractBlock();
+
+ int offset = checked(index * arr.GetElementSize());
+
+ return arr.GetAddrOfPinnedArrayFromEETypeField() + offset;
+ }
+
+ public static IntPtr UnsafeAddrOfPinnedArrayElement<T>(T[] arr, int index)
+ {
+ return UnsafeAddrOfPinnedArrayElement((Array)arr, index);
+ }
+
+#if ENABLE_WINRT
+ public static Type GetTypeFromCLSID(Guid clsid)
+ {
+ // @TODO - if this is something we recognize, create a strongly-typed RCW
+ // Otherwise, create a weakly typed RCW
+ throw new PlatformNotSupportedException();
+ }
+
+ //====================================================================
+ // 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.
+ //====================================================================
+ public static Object GetUniqueObjectForIUnknown(IntPtr unknown)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static bool AreComObjectsAvailableForCleanup()
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static IntPtr CreateAggregatedObject(IntPtr pOuter, Object o)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static IntPtr CreateAggregatedObject<T>(IntPtr pOuter, T o)
+ {
+ return CreateAggregatedObject(pOuter, (object)o);
+ }
+
+ public static Object CreateWrapperOfType(Object o, Type t)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static TWrapper CreateWrapperOfType<T, TWrapper>(T o)
+ {
+ return (TWrapper)CreateWrapperOfType(o, typeof(TWrapper));
+ }
+
+ public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type T, CustomQueryInterfaceMode mode)
+ {
+ // Obsolete
+ throw new PlatformNotSupportedException();
+ }
+
+ public static int GetExceptionCode()
+ {
+ // Obsolete
+ throw new PlatformNotSupportedException();
+ }
+
+ /// <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>
+ public static int GetStartComSlot(Type t)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ //====================================================================
+ // Given a managed object that wraps an ITypeInfo, return its name
+ //====================================================================
+ public static String GetTypeInfoName(ITypeInfo typeInfo)
+ {
+ throw new PlatformNotSupportedException();
+ }
+#endif //ENABLE_WINRT
+
+ public static byte ReadByte(Object ptr, int ofs)
+ {
+ // Obsolete
+ throw new PlatformNotSupportedException();
+ }
+
+ public static short ReadInt16(Object ptr, int ofs)
+ {
+ // Obsolete
+ throw new PlatformNotSupportedException();
+ }
+
+ public static int ReadInt32(Object ptr, int ofs)
+ {
+ // Obsolete
+ throw new PlatformNotSupportedException();
+ }
+
+ public static long ReadInt64(Object ptr, int ofs)
+ {
+ // Obsolete
+ throw new PlatformNotSupportedException();
+ }
+
+ public static void WriteByte(Object ptr, int ofs, byte val)
+ {
+ // Obsolete
+ throw new PlatformNotSupportedException();
+ }
+
+ public static void WriteInt16(Object ptr, int ofs, short val)
+ {
+ // Obsolete
+ throw new PlatformNotSupportedException();
+ }
+
+ public static void WriteInt32(Object ptr, int ofs, int val)
+ {
+ // Obsolete
+ throw new PlatformNotSupportedException();
+ }
+
+ public static void WriteInt64(Object ptr, int ofs, long val)
+ {
+ // Obsolete
+ throw new PlatformNotSupportedException();
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAdapter.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAdapter.cs
new file mode 100644
index 000000000..4790c41a7
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAdapter.cs
@@ -0,0 +1,95 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+//
+// This file provides an implementation of the pieces of the Marshal class which are required by the Interop
+// API contract but are not provided by the version of Marshal which is part of the Redhawk test library.
+// This partial class is combined with the version from the Redhawk test library, in order to provide the
+// Marshal implementation for System.Private.CoreLib.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Runtime.Versioning;
+using System.Text;
+using System.Threading;
+using System.Reflection;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Interface to expose MCG marshalling APIs to coreclr,the marshalredirect transform
+ /// redirect the public marshalling API calls in user code to MarshalAdapter functions.
+ /// This gives us an oppurtunity to intercept user's public marshal API call to see
+ /// if the requested operation is MCG aware.
+ /// </summary>
+ public static partial class MarshalAdapter
+ {
+#pragma warning disable 618 // error CS0618: '%' is obsolete:
+ //====================================================================
+ // return the IUnknown* for an Object if the current context
+ // is the one where the RCW was first seen. Will return null
+ // otherwise.
+ //====================================================================
+ public static IntPtr /* IUnknown* */ GetIUnknownForObject(Object o)
+ {
+ return MarshalImpl.GetIUnknownForObject(o);
+ }
+
+ //====================================================================
+ // return an Object for IUnknown
+ //====================================================================
+ public static Object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk)
+ {
+ object obj = MarshalImpl.GetObjectForIUnknown(pUnk);
+#if CORECLR
+ if (obj == null)
+ {
+ return Marshal.GetObjectForIUnknown(pUnk);
+ }
+#endif
+ return obj;
+ }
+
+ public static IntPtr GetComInterfaceForObject<T, TInterface>(T o)
+ {
+ return GetComInterfaceForObject(o, typeof(TInterface));
+ }
+
+ public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type T)
+ {
+ IntPtr ptr = MarshalImpl.GetComInterfaceForObject(o, T);
+#if CORECLR
+ if (ptr == default(IntPtr))
+ {
+ return Marshal.GetComInterfaceForObject(o, T);
+ }
+#endif
+ return ptr;
+ }
+
+ public static TDelegate GetDelegateForFunctionPointer<TDelegate>(IntPtr ptr)
+ {
+ return (TDelegate)(object)GetDelegateForFunctionPointer(ptr, typeof(TDelegate));
+ }
+
+ //====================================================================
+ // Checks if "t" is MCG generated , if not fallback to public API
+ //====================================================================
+ public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t)
+ {
+ Delegate dlg = MarshalImpl.GetDelegateForFunctionPointer(ptr, t);
+#if CORECLR
+ if (dlg == null) // fall back to public marshal API
+ {
+ return Marshal.GetDelegateForFunctionPointer(ptr, t);
+ }
+#endif
+ return dlg;
+ }
+ }
+#pragma warning restore 618
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAsAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAsAttribute.cs
new file mode 100644
index 000000000..fa17080da
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAsAttribute.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;
+
+namespace System.Runtime.InteropServices
+{
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.ReturnValue, Inherited = false)]
+ public unsafe sealed class MarshalAsAttribute : Attribute
+ {
+ 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
+ public String MarshalType; // Name of marshaler class
+ public Type MarshalTypeRef; // Type of marshaler class
+ public String MarshalCookie; // cookie to pass to marshaler
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalDirectiveException.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalDirectiveException.cs
new file mode 100644
index 000000000..7e6f35712
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalDirectiveException.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.
+
+/*=============================================================================
+**
+** Class: MarshalDirectiveException
+**
+** 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.
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public class MarshalDirectiveException : Exception
+ {
+ public MarshalDirectiveException()
+ : base(SR.Arg_MarshalDirectiveException)
+ {
+ HResult = __HResults.COR_E_MARSHALDIRECTIVE;
+ }
+
+ public MarshalDirectiveException(String message)
+ : base(message)
+ {
+ HResult = __HResults.COR_E_MARSHALDIRECTIVE;
+ }
+
+ public MarshalDirectiveException(String message, Exception inner)
+ : base(message, inner)
+ {
+ HResult = __HResults.COR_E_MARSHALDIRECTIVE;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalImpl.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalImpl.cs
new file mode 100644
index 000000000..b3f8fd257
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalImpl.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.
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices
+{
+ internal static partial class MarshalImpl
+ {
+ public static IntPtr /* IUnknown* */ GetIUnknownForObject(Object o)
+ {
+ return McgMarshal.ObjectToComInterface(o, McgModuleManager.IUnknown);
+ }
+
+ public static Object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk)
+ {
+ return McgMarshal.ComInterfaceToObject(pUnk, McgModuleManager.IUnknown);
+ }
+
+ public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t)
+ {
+ return McgModuleManager.GetPInvokeDelegateForStub(ptr, t.TypeHandle);
+ }
+ public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type t)
+ {
+ if (o == null)
+ throw new ArgumentNullException("o");
+
+ if (t == null)
+ throw new ArgumentNullException("type");
+
+ RuntimeTypeHandle interfaceTypeHandle = t.TypeHandle;
+ McgTypeInfo secondTypeInfo;
+ McgTypeInfo mcgTypeInfo = McgModuleManager.GetTypeInfoFromTypeHandle(interfaceTypeHandle, out secondTypeInfo);
+ if (mcgTypeInfo.IsNull)
+ {
+#if CORECLR
+ return default(IntPtr);
+#else
+ throw new MissingInteropDataException(SR.ComTypeMarshalling_MissingInteropData, t);
+#endif
+ }
+ return McgMarshal.ObjectToComInterface(o, mcgTypeInfo);
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/MissingInteropDataException.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/MissingInteropDataException.cs
new file mode 100644
index 000000000..ab6a893ec
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/MissingInteropDataException.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.
+
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Thrown when a manual marshalling method is called, but the type was not found
+ /// by static analysis or in the rd.xml file.
+ /// </summary>
+ class MissingInteropDataException : Exception
+ {
+ public Type MissingType { get; private set; }
+
+ public MissingInteropDataException(string message) : base(message) { }
+#if ENABLE_WINRT
+ public MissingInteropDataException(string resourceFormat, Type pertainantType)
+ : base(SR.Format(resourceFormat,
+ Internal.Reflection.Execution.PayForPlayExperience.MissingMetadataExceptionCreator.ComputeUsefulPertainantIfPossible(pertainantType)))
+ {
+ MissingType = pertainantType;
+ }
+#else
+ public MissingInteropDataException(string resourceFormat, Type pertainantType)
+ {
+ MissingType = pertainantType;
+ }
+#endif //ENABLE_WINRT
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/OptionalAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/OptionalAttribute.cs
new file mode 100644
index 000000000..6f83094cd
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/OptionalAttribute.cs
@@ -0,0 +1,12 @@
+// 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
+{
+ [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+ public sealed class OptionalAttribute : Attribute
+ {
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/PreserveSigAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/PreserveSigAttribute.cs
new file mode 100644
index 000000000..23793e42c
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/PreserveSigAttribute.cs
@@ -0,0 +1,12 @@
+// 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
+{
+ [AttributeUsage(AttributeTargets.Method, Inherited = false)]
+ public sealed class PreserveSigAttribute : Attribute
+ {
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/SEHException.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/SEHException.cs
new file mode 100644
index 000000000..4c0fe9e9e
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/SEHException.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.
+
+/*=============================================================================
+**
+** Class: SEHException
+**
+**
+** Purpose: Exception class for all Structured Exception Handling code.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public class SEHException : Exception
+ {
+ public SEHException()
+ : base()
+ {
+ HResult = __HResults.E_FAIL;
+ }
+
+ public SEHException(String message)
+ : base(message)
+ {
+ HResult = __HResults.E_FAIL;
+ }
+
+ public SEHException(String message, Exception inner)
+ : base(message, inner)
+ {
+ HResult = __HResults.E_FAIL;
+ }
+
+ // 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/System.Private.Interop/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs
new file mode 100644
index 000000000..9c916fc46
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.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.
+
+/*=============================================================================
+**
+** Class: SafeArrayRankMismatchException
+**
+** Purpose: This exception is thrown when the runtime rank of a safe array
+** is different than the array rank specified in the metadata.
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public class SafeArrayRankMismatchException : Exception
+ {
+ public SafeArrayRankMismatchException()
+ : base(SR.Arg_SafeArrayRankMismatchException)
+ {
+ HResult = __HResults.COR_E_SAFEARRAYRANKMISMATCH;
+ }
+
+ public SafeArrayRankMismatchException(String message)
+ : base(message)
+ {
+ HResult = __HResults.COR_E_SAFEARRAYRANKMISMATCH;
+ }
+
+ public SafeArrayRankMismatchException(String message, Exception inner)
+ : base(message, inner)
+ {
+ HResult = __HResults.COR_E_SAFEARRAYRANKMISMATCH;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs
new file mode 100644
index 000000000..9e8e66115
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.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.
+
+/*=============================================================================
+**
+** Class: SafeArrayTypeMismatchException
+**
+** Purpose: This exception is thrown when the runtime type of an array
+** is different than the safe array sub type specified in the
+** metadata.
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ public class SafeArrayTypeMismatchException : Exception
+ {
+ public SafeArrayTypeMismatchException()
+ : base(SR.Arg_SafeArrayTypeMismatchException)
+ {
+ HResult = __HResults.COR_E_SAFEARRAYTYPEMISMATCH;
+ }
+
+ public SafeArrayTypeMismatchException(String message)
+ : base(message)
+ {
+ HResult = __HResults.COR_E_SAFEARRAYTYPEMISMATCH;
+ }
+
+ public SafeArrayTypeMismatchException(String message, Exception inner)
+ : base(message, inner)
+ {
+ HResult = __HResults.COR_E_SAFEARRAYTYPEMISMATCH;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/SafeBuffer.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/SafeBuffer.cs
new file mode 100644
index 000000000..2d147de53
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/SafeBuffer.cs
@@ -0,0 +1,464 @@
+// 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 races 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.
+
+using System;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+
+namespace System.Runtime.InteropServices
+{
+ public abstract unsafe class SafeBuffer : SafeHandle
+ {
+ // 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(IntPtr.Zero, ownsHandle)
+ {
+ _numBytes = Uninitialized;
+ }
+
+ // On the desktop CLR, SafeBuffer has access to the internal handle field since they're both in
+ // mscorlib. For this refactoring, we'll keep the name the same to minimize deltas, but shim
+ // through to DangerousGetHandle
+ private new IntPtr handle
+ {
+ get { return DangerousGetHandle(); }
+ }
+
+ public override bool IsInvalid
+ {
+ get { return DangerousGetHandle() == IntPtr.Zero || DangerousGetHandle() == new IntPtr(-1); }
+ }
+
+ /// <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", SR.ArgumentOutOfRange_NeedNonNegNum);
+ if (IntPtr.Size == 4 && numBytes > UInt32.MaxValue)
+ throw new ArgumentOutOfRangeException("numBytes", SR.ArgumentOutOfRange_AddressSpace);
+ Contract.EndContractBlock();
+
+ if (numBytes >= (ulong)Uninitialized)
+ throw new ArgumentOutOfRangeException("numBytes", SR.ArgumentOutOfRange_UIntPtrMaxMinusOne);
+
+ _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", SR.ArgumentOutOfRange_NeedNonNegNum);
+ if (sizeOfEachElement < 0)
+ throw new ArgumentOutOfRangeException("sizeOfEachElement", SR.ArgumentOutOfRange_NeedNonNegNum);
+
+ if (IntPtr.Size == 4 && numElements * sizeOfEachElement > UInt32.MaxValue)
+ throw new ArgumentOutOfRangeException("numBytes", SR.ArgumentOutOfRange_AddressSpace);
+ Contract.EndContractBlock();
+
+ if (numElements * sizeOfEachElement >= (ulong)Uninitialized)
+ throw new ArgumentOutOfRangeException("numElements", SR.ArgumentOutOfRange_UIntPtrMaxMinusOne);
+
+ _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, 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)]
+ public void AcquirePointer(ref byte* pointer)
+ {
+ if (_numBytes == Uninitialized)
+ throw NotInitialized();
+
+ pointer = null;
+ try
+ {
+ }
+ finally
+ {
+ bool junk = false;
+ DangerousAddRef(ref junk);
+ pointer = (byte*)handle;
+ }
+ }
+
+ 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)]
+ public T Read<T>(ulong byteOffset) where T : struct
+ {
+ if (_numBytes == Uninitialized)
+ throw NotInitialized();
+
+ uint sizeofT = SizeOfType<T>();
+ byte* ptr = (byte*)handle + byteOffset;
+ SpaceCheck(ptr, sizeofT);
+
+ // return *(T*) (_ptr + byteOffset);
+ T value;
+ bool mustCallRelease = false;
+ try
+ {
+ DangerousAddRef(ref mustCallRelease);
+
+ GenericPtrToStructure<T>(ptr, out value, sizeofT);
+ }
+ finally
+ {
+ if (mustCallRelease)
+ DangerousRelease();
+ }
+ return value;
+ }
+
+ [CLSCompliant(false)]
+ public void ReadArray<T>(ulong byteOffset, T[] array, int index, int count)
+ where T : struct
+ {
+ if (array == null)
+ throw new ArgumentNullException("array", SR.ArgumentNull_Buffer);
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_NeedNonNegNum);
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum);
+ if (array.Length - index < count)
+ throw new ArgumentException(SR.Argument_InvalidOffLength);
+ Contract.EndContractBlock();
+
+ if (_numBytes == Uninitialized)
+ throw NotInitialized();
+
+ uint sizeofT = SizeOfType<T>();
+ uint alignedSizeofT = AlignedSizeOf<T>();
+ byte* ptr = (byte*)handle + byteOffset;
+ SpaceCheck(ptr, checked((ulong)(alignedSizeofT * count)));
+
+ bool mustCallRelease = false;
+ 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)]
+ public void Write<T>(ulong byteOffset, T value) where T : struct
+ {
+ if (_numBytes == Uninitialized)
+ throw NotInitialized();
+
+ uint sizeofT = SizeOfType<T>();
+ byte* ptr = (byte*)handle + byteOffset;
+ SpaceCheck(ptr, sizeofT);
+
+ // *((T*) (_ptr + byteOffset)) = value;
+ bool mustCallRelease = false;
+ try
+ {
+ DangerousAddRef(ref mustCallRelease);
+ GenericStructureToPtr(ref value, ptr, sizeofT);
+ }
+ finally
+ {
+ if (mustCallRelease)
+ DangerousRelease();
+ }
+ }
+
+ [CLSCompliant(false)]
+ public void WriteArray<T>(ulong byteOffset, T[] array, int index, int count)
+ where T : struct
+ {
+ if (array == null)
+ throw new ArgumentNullException("array", SR.ArgumentNull_Buffer);
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_NeedNonNegNum);
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum);
+ if (array.Length - index < count)
+ throw new ArgumentException(SR.Argument_InvalidOffLength);
+ Contract.EndContractBlock();
+
+ if (_numBytes == Uninitialized)
+ throw NotInitialized();
+
+ uint sizeofT = SizeOfType<T>();
+ uint alignedSizeofT = AlignedSizeOf<T>();
+ byte* ptr = (byte*)handle + byteOffset;
+ SpaceCheck(ptr, checked((ulong)(alignedSizeofT * count)));
+
+ bool mustCallRelease = false;
+ 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
+ {
+ get
+ {
+ if (_numBytes == Uninitialized)
+ throw NotInitialized();
+
+ return (ulong)_numBytes;
+ }
+ }
+
+ /* No indexer. The perf would be misleadingly bad. People should use
+ * AcquirePointer and ReleasePointer instead. */
+
+ private void SpaceCheck(byte* ptr, ulong sizeInBytes)
+ {
+ if ((ulong)_numBytes < sizeInBytes)
+ NotEnoughRoom();
+ if ((ulong)(ptr - (byte*)handle) > ((ulong)_numBytes) - sizeInBytes)
+ NotEnoughRoom();
+ }
+
+ private static void NotEnoughRoom()
+ {
+ throw new ArgumentException(SR.Arg_BufferTooSmall);
+ }
+
+ private static InvalidOperationException NotInitialized()
+ {
+ Contract.Assert(false, "Uninitialized SafeBuffer! Someone needs to call Initialize before using this instance!");
+ return new InvalidOperationException(SR.InvalidOperation_MustCallInitialize);
+ }
+
+ internal static void GenericPtrToStructure<T>(byte* ptr, out T structure, uint sizeofT) where T : struct
+ {
+ RuntimeTypeHandle structureTypeHandle = typeof(T).TypeHandle;
+ if (!structureTypeHandle.IsBlittable())
+ throw new ArgumentException(SR.Argument_NeedStructWithNoRefs);
+
+ Object boxedStruct = new T();
+ InteropExtensions.PinObjectAndCall(boxedStruct,
+ unboxedStructPtr =>
+ {
+ InteropExtensions.Memcpy(
+ (IntPtr)((IntPtr*)unboxedStructPtr + 1), // safe (need to adjust offset as boxed structure start at offset 1)
+ (IntPtr)ptr, // unsafe (no need to adjust as it is always struct)
+ (int)sizeofT
+ );
+ });
+
+ structure = (T)boxedStruct;
+ }
+
+ internal static void GenericStructureToPtr<T>(ref T structure, byte* ptr, uint sizeofT) where T : struct
+ {
+ RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;
+ if (!structureTypeHandle.IsBlittable())
+ throw new ArgumentException(SR.Argument_NeedStructWithNoRefs);
+
+ InteropExtensions.PinObjectAndCall((Object)structure,
+ unboxedStructPtr =>
+ {
+ InteropExtensions.Memcpy(
+ (IntPtr)ptr, // unsafe (no need to adjust as it is always struct)
+ (IntPtr)((IntPtr*)unboxedStructPtr + 1), // safe (need to adjust offset as boxed structure start at offset 1)
+ (int)sizeofT
+ );
+ });
+ }
+
+ #region "SizeOf Helpers"
+ /// <summary>
+ /// Returns the aligned size of an instance of a value type.
+ /// </summary>
+ private static uint AlignedSizeOf<T>() where T : struct
+ {
+ uint size = SizeOfType<T>();
+ if (size == 1 || size == 2)
+ {
+ return size;
+ }
+ if (IntPtr.Size == 8 && size == 4)
+ {
+ return size;
+ }
+
+ return (uint)(((size + 3) & (~3)));
+ }
+
+ private static uint SizeOfType<T>() where T : struct
+ {
+ return (uint)SizeOf(typeof(T));
+ }
+
+ [Pure]
+ private static int SizeOf(Type t)
+ {
+ Debug.Assert(t != null, "t");
+
+ if (t.TypeHandle.IsGenericType())
+ throw new ArgumentException(SR.Argument_NeedNonGenericType, "t");
+
+ RuntimeTypeHandle typeHandle = t.TypeHandle;
+ if (!(typeHandle.IsBlittable() && typeHandle.IsValueType()))
+ throw new ArgumentException(SR.Argument_NeedStructWithNoRefs);
+
+ return typeHandle.GetValueTypeSize();
+ }
+ #endregion
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/TypeIdentifierAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/TypeIdentifierAttribute.cs
new file mode 100644
index 000000000..a7a51d303
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/TypeIdentifierAttribute.cs
@@ -0,0 +1,24 @@
+// 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
+{
+ [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Struct | AttributeTargets.Delegate, AllowMultiple = false, Inherited = 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_;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/UnknownWrapper.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/UnknownWrapper.cs
new file mode 100644
index 000000000..87cbc151b
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/UnknownWrapper.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.
+
+/*=============================================================================
+**
+** Class: UnknownWrapper.
+**
+**
+** Purpose: Wrapper that is converted to a variant with VT_UNKNOWN.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ 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/System.Private.Interop/src/System/Runtime/InteropServices/UnmanagedType.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/UnmanagedType.cs
new file mode 100644
index 000000000..f0367ff97
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/UnmanagedType.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ 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,
+ IInspectable = 0x2e,
+ HString = 0x2f, // Windows Runtime HSTRING
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/VarEnum.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/VarEnum.cs
new file mode 100644
index 000000000..345df0e69
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/VarEnum.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.
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ 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
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/Variant.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/Variant.cs
new file mode 100644
index 000000000..2f3bdbbee
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/Variant.cs
@@ -0,0 +1,500 @@
+// 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;
+
+namespace System.Runtime.InteropServices
+{
+ /// <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]
+ public struct Variant
+ {
+ // 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.Explicit)]
+ private struct TypeUnion
+ {
+ [FieldOffset(0)]
+ internal ushort _vt;
+ [FieldOffset(2)]
+ internal ushort _wReserved1;
+ [FieldOffset(4)]
+ internal ushort _wReserved2;
+ [FieldOffset(6)]
+ internal ushort _wReserved3;
+ [FieldOffset(8)]
+ internal UnionTypes _unionTypes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct Record
+ {
+ private IntPtr _record;
+ private IntPtr _recordInfo;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ private struct UnionTypes
+ {
+ [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;
+ [FieldOffset(0)]
+ internal IntPtr _bstr;
+ [FieldOffset(0)]
+ internal IntPtr _unknown;
+ [FieldOffset(0)]
+ internal IntPtr _dispatch;
+ [FieldOffset(0)]
+ internal IntPtr _pvarVal;
+ [FieldOffset(0)]
+ internal IntPtr _byref;
+ [FieldOffset(0)]
+ internal Record _record;
+ }
+#pragma warning disable 618 // error CS0618: 'VarEnum' is obsolete:
+ public Variant(object value)
+ {
+ this = new Variant();
+
+ if (value == null) this.VariantType = VarEnum.VT_EMPTY;
+ else if (value is sbyte) this.AsI1 = (sbyte)value;
+ else if (value is byte) this.AsUi1 = (byte)value;
+ else if (value is short) this.AsI2 = (short)value;
+ else if (value is ushort) this.AsUi2 = (ushort)value;
+ else if (value is char)
+ {
+ char unboxedChar = (char)value;
+ this.AsUi2 = (ushort)unboxedChar;
+ }
+ else if (value is int) this.AsI4 = (int)value;
+ else if (value is uint) this.AsUi4 = (uint)value;
+ else if (value is long) this.AsI8 = (long)value;
+ else if (value is ulong) this.AsUi8 = (ulong)value;
+ else if (value is bool) this.AsBool = (bool)value;
+ else if (value is decimal) this.AsDecimal = (decimal)value;
+ else if (value is double) this.AsR8 = (double)value;
+ else if (value is float) this.AsR4 = (float)value;
+ else if (value is string) this.AsBstr = (string)value;
+ else if (value is Array || value is SafeHandle || value is CriticalHandle || value is VariantWrapper)
+ {
+ throw new ArgumentException(SR.Format(SR.Arg_VariantTypeNotSupported, value.GetTypeHandle().GetDisplayName()));
+ }
+ else
+ {
+ this.AsUnknown = value;
+ }
+ }
+
+ /// <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_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_R4: return AsR4;
+ case VarEnum.VT_R8: return AsR8;
+ case VarEnum.VT_DECIMAL: return AsDecimal;
+ case VarEnum.VT_BSTR: return AsBstr;
+ case VarEnum.VT_UNKNOWN: return AsUnknown;
+ default:
+ throw new ArgumentException(SR.Format(SR.Arg_VariantTypeNotSupported, VariantType));
+ }
+ }
+
+ /// <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)
+ {
+ ExternalInterop.VariantClear((IntPtr)pThis);
+ }
+ }
+ Debug.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;
+ }
+ }
+
+
+ // VT_I1
+ internal SByte AsI1
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_I1, "variant");
+ return _typeUnion._unionTypes._i1;
+ }
+ set
+ {
+ Debug.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
+ internal Int16 AsI2
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_I2, "variant");
+ return _typeUnion._unionTypes._i2;
+ }
+ set
+ {
+ Debug.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
+ internal Int32 AsI4
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_I4, "variant");
+ return _typeUnion._unionTypes._i4;
+ }
+ set
+ {
+ Debug.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
+ internal Int64 AsI8
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_I8, "variant");
+ return _typeUnion._unionTypes._i8;
+ }
+ set
+ {
+ Debug.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
+ internal Byte AsUi1
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_UI1, "variant");
+ return _typeUnion._unionTypes._ui1;
+ }
+ set
+ {
+ Debug.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
+ internal UInt16 AsUi2
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_UI2, "variant");
+ return _typeUnion._unionTypes._ui2;
+ }
+ set
+ {
+ Debug.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
+ internal UInt32 AsUi4
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_UI4, "variant");
+ return _typeUnion._unionTypes._ui4;
+ }
+ set
+ {
+ Debug.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
+ internal UInt64 AsUi8
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_UI8, "variant");
+ return _typeUnion._unionTypes._ui8;
+ }
+ set
+ {
+ Debug.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
+ internal Int32 AsInt
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_INT, "variant");
+ return _typeUnion._unionTypes._int;
+ }
+ set
+ {
+ Debug.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
+ internal UInt32 AsUint
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_UINT, "variant");
+ return _typeUnion._unionTypes._uint;
+ }
+ set
+ {
+ Debug.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
+ internal bool AsBool
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_BOOL, "variant");
+ return _typeUnion._unionTypes._bool != 0;
+ }
+ set
+ {
+ Debug.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_R4
+ internal Single AsR4
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_R4, "variant");
+ return _typeUnion._unionTypes._r4;
+ }
+ set
+ {
+ Debug.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
+ internal Double AsR8
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_R8, "variant");
+ return _typeUnion._unionTypes._r8;
+ }
+ set
+ {
+ Debug.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
+ internal Decimal AsDecimal
+ {
+ get
+ {
+ Debug.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
+ {
+ Debug.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_BSTR
+ internal String AsBstr
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_BSTR, "variant");
+ return (string)Marshal.PtrToStringBSTR(this._typeUnion._unionTypes._bstr);
+ }
+ set
+ {
+ Debug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
+ VariantType = VarEnum.VT_BSTR;
+ if (value == null)
+ _typeUnion._unionTypes._bstr = IntPtr.Zero;
+ else
+ _typeUnion._unionTypes._bstr = Marshal.StringToBSTR(value);
+ }
+ }
+
+ // VT_UNKNOWN
+ internal Object AsUnknown
+ {
+ get
+ {
+ Debug.Assert(VariantType == VarEnum.VT_UNKNOWN, "variant");
+ if (_typeUnion._unionTypes._unknown == IntPtr.Zero)
+ return null;
+ return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._unknown);
+ }
+ set
+ {
+ Debug.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);
+ }
+ }
+ }
+#pragma warning restore 618
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/VariantWrapper.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/VariantWrapper.cs
new file mode 100644
index 000000000..aa08a968d
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/VariantWrapper.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.
+
+//
+
+//
+
+/*=============================================================================
+**
+** Class: VariantWrapper.
+**
+**
+** Purpose: Wrapper that is converted to a variant with VT_BYREF | VT_VARIANT.
+**
+**
+=============================================================================*/
+
+using System;
+
+namespace System.Runtime.InteropServices
+{
+ 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/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/CustomPropertyImpl.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/CustomPropertyImpl.cs
new file mode 100644
index 000000000..e8db493c9
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/CustomPropertyImpl.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.
+
+//
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using System.Security;
+using Windows.UI.Xaml.Data;
+
+namespace System.Runtime.InteropServices.WindowsRuntime
+{
+ //
+ // ICustomProperty implementation - basically a wrapper of PropertyInfo
+ //
+ // MCG emits references to this internal type into generated interop code, so we apply the [DependencyReductionRoot]
+ // attribute to it so that it survives initial tree shaking.
+ [System.Runtime.CompilerServices.DependencyReductionRootAttribute]
+ internal sealed class CustomPropertyImpl : ICustomProperty
+ {
+ private PropertyInfo m_property;
+
+ /// <summary>
+ /// True if the property is a collection indexer that may not have metadata
+ /// </summary>
+ private bool m_isIndexerWithoutMetadata;
+
+ /// <summary>
+ /// Type that contains an indexer that doesn't have metadata
+ /// </summary>
+ private Type m_indexerContainingType;
+
+ //
+ // Constructor
+ //
+ public CustomPropertyImpl(PropertyInfo propertyInfo, bool isIndexerWithoutMetadata = false, Type indexerContainingType = null)
+ {
+ m_property = propertyInfo;
+ m_isIndexerWithoutMetadata = isIndexerWithoutMetadata;
+ m_indexerContainingType = indexerContainingType;
+ }
+
+ //
+ // ICustomProperty interface implementation
+ //
+
+ public string Name
+ {
+ get
+ {
+ if (m_isIndexerWithoutMetadata)
+ {
+ return "Item";
+ }
+
+ return m_property.Name;
+ }
+ }
+
+ public bool CanRead
+ {
+ get
+ {
+ return m_isIndexerWithoutMetadata || (m_property.GetMethod != null && m_property.GetMethod.IsPublic);
+ }
+ }
+
+ public bool CanWrite
+ {
+ get
+ {
+ return m_isIndexerWithoutMetadata || (m_property.SetMethod != null && m_property.SetMethod.IsPublic);
+ }
+ }
+
+ /// <summary>
+ /// Verify caller has access to the getter/setter property
+ /// </summary>
+ private void CheckAccess(bool getValue)
+ {
+ if (m_isIndexerWithoutMetadata)
+ {
+ return;
+ }
+
+ MethodInfo accessor = getValue ? m_property.GetMethod : m_property.SetMethod;
+
+ if (accessor == null)
+ throw new ArgumentException(getValue ? SR.Arg_GetMethNotFnd : SR.Arg_SetMethNotFnd);
+
+ if (!accessor.IsPublic)
+ {
+ Exception ex = new MemberAccessException(
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.Arg_MethodAccessException_WithMethodName,
+ accessor.ToString(),
+ accessor.DeclaringType.FullName)
+ );
+
+ // We need to make sure it has the same HR that we were returning in desktop
+ InteropExtensions.SetExceptionErrorCode(ex, __HResults.COR_E_METHODACCESS);
+ throw ex;
+ }
+ }
+
+ internal static void LogDataBindingError(string propertyName, Exception ex)
+ {
+ string message = SR.Format(SR.CustomPropertyProvider_DataBindingError, propertyName, ex.Message);
+
+ // Don't call Debug.WriteLine, since it only does anything in DEBUG builds. Instead, we call OutputDebugString directly.
+ ExternalInterop.OutputDebugString(message);
+ }
+
+ public object GetValue(object target)
+ {
+ CheckAccess(getValue: true);
+
+ if (m_isIndexerWithoutMetadata)
+ {
+ throw new TargetParameterCountException();
+ }
+
+ try
+ {
+ return m_property.GetValue(UnwrapTarget(target));
+ }
+ catch (MemberAccessException ex)
+ {
+ LogDataBindingError(Name, ex);
+ throw;
+ }
+ }
+
+ public void SetValue(object target, object value)
+ {
+ CheckAccess(getValue: false);
+
+ if (m_isIndexerWithoutMetadata)
+ {
+ throw new TargetParameterCountException();
+ }
+
+ try
+ {
+ m_property.SetValue(UnwrapTarget(target), value);
+ }
+ catch (MemberAccessException ex)
+ {
+ LogDataBindingError(Name, ex);
+ throw;
+ }
+ }
+
+ public Type Type
+ {
+ get
+ {
+ if (m_isIndexerWithoutMetadata)
+ {
+ // The following calls look like reflection, but don't require metadata,
+ // so they work on all types.
+ Type indexType = null;
+ TypeInfo containingTypeInfo = m_indexerContainingType.GetTypeInfo();
+ foreach (Type itf in containingTypeInfo.ImplementedInterfaces)
+ {
+ if (!itf.IsConstructedGenericType)
+ {
+ continue;
+ }
+
+ Type genericItf = itf.GetGenericTypeDefinition();
+ if (genericItf.Equals(typeof(IList<>)))
+ {
+ Type listArg = itf.GenericTypeArguments[0];
+ if (indexType != null && !indexType.Equals(listArg))
+ {
+ throw new MissingMetadataException();
+ }
+ indexType = listArg;
+ }
+ else if (genericItf.Equals(typeof(IDictionary<,>)))
+ {
+ Type dictionaryArg = itf.GenericTypeArguments[1];
+ if (indexType != null && !indexType.Equals(dictionaryArg))
+ {
+ throw new MissingMetadataException();
+ }
+ indexType = dictionaryArg;
+ }
+ }
+
+ if (indexType == null)
+ {
+ throw new MissingMetadataException();
+ }
+ return indexType;
+ }
+
+ return m_property.PropertyType;
+ }
+ }
+
+ // 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 GetIndexedValue(object target, object index)
+ {
+ CheckAccess(getValue: true);
+ object unwrappedTarget = UnwrapTarget(target);
+
+ // We might not have metadata for the accessor, but we can try some common collections
+ if (m_isIndexerWithoutMetadata)
+ {
+ IDictionary dictionary = unwrappedTarget as IDictionary;
+ if (dictionary != null)
+ {
+ return dictionary[index];
+ }
+ IList list = unwrappedTarget as IList;
+ if (list != null)
+ {
+ if (index is int)
+ {
+ return list[(int)index];
+ }
+ }
+ }
+
+ try
+ {
+ return m_property.GetValue(unwrappedTarget, new object[] { index });
+ }
+ catch (MemberAccessException ex)
+ {
+ LogDataBindingError(Name, ex);
+ throw;
+ }
+ }
+
+ // 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 SetIndexedValue(object target, object value, object index)
+ {
+ CheckAccess(getValue: false);
+ object unwrappedTarget = UnwrapTarget(target);
+
+ // We might not have metadata for the accessor, but we can try some common collections
+ IDictionary dictionary = unwrappedTarget as IDictionary;
+ if (dictionary != null)
+ {
+ dictionary[index] = value;
+ }
+ IList list = unwrappedTarget as IList;
+ if (list != null)
+ {
+ if (index is int)
+ {
+ list[(int)index] = value;
+ }
+ }
+
+ try
+ {
+ m_property.SetValue(unwrappedTarget, value, new object[] { index });
+ }
+ catch (MemberAccessException ex)
+ {
+ LogDataBindingError(Name, ex);
+ throw;
+ }
+ }
+
+ public static object UnwrapTarget(object target)
+ {
+ //
+ // If target is a managed wrapper, we should unwrap it and use its target for data binding
+ // For example, you don't want to data bind against a KeyValuePairImpl<K, V> - you want the real
+ // KeyValuePair<K, V>
+ //
+ object newTarget = McgComHelpers.UnboxManagedWrapperIfBoxed(target);
+ if (newTarget != target)
+ return newTarget;
+
+ if (target is __ComObject)
+ {
+ object winrtUnboxed = McgModuleManager.UnboxIfBoxed(target);
+ if (winrtUnboxed != null)
+ return winrtUnboxed;
+ }
+
+ return target;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/DefaultInterfaceAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/DefaultInterfaceAttribute.cs
new file mode 100644
index 000000000..2fdc626c8
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/DefaultInterfaceAttribute.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.
+
+//
+
+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; }
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs
new file mode 100644
index 000000000..7ec084486
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs
@@ -0,0 +1,295 @@
+// 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.CompilerServices;
+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(unchecked((long)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;
+ }
+ }
+
+ public static partial class EventRegistrationHelpers
+ {
+ /// <summary>
+ /// A helper method that exposed in our System.Private.MCG
+ /// contract assembly to access the internal ExtractHandler method
+ /// There are other options such as
+ /// 1) define another EventRegistrationTokenTable.Extracthandler in
+ /// System.Private.MCG assembly. Unfortunately this doesn't work because
+ /// compiler sees two EventRegistrationTokenTable classes in two contracts
+ /// 2) make a Extracthandler an extention method. This requires having a "using" statement for the
+ /// extension methods and doesn't make things easier to understand
+ /// </summary>
+ public static T ExtractHandler<T>(System.Runtime.InteropServices.WindowsRuntime.EventRegistrationTokenTable<T> table, System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken token) where T : class
+ {
+ return table.ExtractHandler(token);
+ }
+
+ /// <summary>
+ /// Given a key, locate the corresponding value in the ConditionalWeakTable according to value
+ /// equality. Will create a new value if the key is not found.
+ /// <summary>
+ public static TValue GetValueFromEquivalentKey<TKey, TValue>(ConditionalWeakTable<TKey, TValue> table, TKey key, ConditionalWeakTable<TKey, TValue>.CreateValueCallback callback)
+ where TKey : class
+ where TValue : class
+ {
+ TValue value;
+ TKey foundKey = table.FindEquivalentKeyUnsafe(key, out value);
+ if (foundKey == default(TKey))
+ {
+ value = callback(key);
+ table.Add(key, value);
+ }
+
+ return value;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IActivationFactory.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IActivationFactory.cs
new file mode 100644
index 000000000..db3073faa
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IActivationFactory.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.Runtime.InteropServices;
+
+namespace System.Runtime.InteropServices.WindowsRuntime
+{
+ [ComImport]
+ [Guid("00000035-0000-0000-C000-000000000046")]
+ [WindowsRuntimeImport]
+ public interface IActivationFactory
+ {
+ object ActivateInstance();
+ }
+
+ /// <summary>
+ /// This one is used by MCG as anchor type for the real IActivationFactory interface
+ /// </summary>
+ [Guid("00000035-0000-0000-C000-000000000046")]
+ public interface IActivationFactoryInternal
+ {
+ /// <summary>
+ /// Creates an new instance
+ /// </summary>
+ /// <returns>The IInspectable of the created object</returns>
+ IntPtr ActivateInstance();
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/InterfaceImplementedInVersionAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/InterfaceImplementedInVersionAttribute.cs
new file mode 100644
index 000000000..cda26e7d9
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/InterfaceImplementedInVersionAttribute.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;
+
+namespace System.Runtime.InteropServices.WindowsRuntime
+{
+ // 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;
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReadOnlyArrayAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReadOnlyArrayAttribute.cs
new file mode 100644
index 000000000..7153fbebb
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReadOnlyArrayAttribute.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.
+
+//
+
+using System;
+
+namespace System.Runtime.InteropServices.WindowsRuntime
+{
+ // Applies to read-only array parameters
+ [AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
+ public sealed class ReadOnlyArrayAttribute : Attribute
+ {
+ public ReadOnlyArrayAttribute() { }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReturnValueNameAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReturnValueNameAttribute.cs
new file mode 100644
index 000000000..6514ad9c8
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReturnValueNameAttribute.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.
+
+//
+
+using System;
+
+namespace System.Runtime.InteropServices.WindowsRuntime
+{
+ // 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/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeImportAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeImportAttribute.cs
new file mode 100644
index 000000000..3189c5631
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeImportAttribute.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.
+
+//
+
+using System;
+
+namespace System.Runtime.InteropServices.WindowsRuntime
+{
+ // 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)]
+ internal sealed class WindowsRuntimeImportAttribute : Attribute
+ {
+ public WindowsRuntimeImportAttribute()
+ { }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/WriteOnlyArrayAttribute.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/WriteOnlyArrayAttribute.cs
new file mode 100644
index 000000000..4ffd4396a
--- /dev/null
+++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/WriteOnlyArrayAttribute.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.
+
+//
+
+using System;
+
+namespace System.Runtime.InteropServices.WindowsRuntime
+{
+ // Applies to write-only array parameters
+ [AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
+ public sealed class WriteOnlyArrayAttribute : Attribute
+ {
+ public WriteOnlyArrayAttribute() { }
+ }
+}
diff --git a/src/System.Private.Interop/src/System/__HResults.cs b/src/System.Private.Interop/src/System/__HResults.cs
new file mode 100644
index 000000000..6e7f8b78b
--- /dev/null
+++ b/src/System.Private.Interop/src/System/__HResults.cs
@@ -0,0 +1,233 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+//=============================================================================
+//
+//
+// Purpose: Define HResult constants. Every exception has one of these.
+//
+//
+//===========================================================================*/
+
+using System;
+
+namespace System
+{
+ // Note: FACILITY_URT is defined as 0x13 (0x8013xxxx). Within that
+ // range, 0x1yyy is for Runtime errors (used for Security, Metadata, etc).
+ // In that subrange, 0x15zz and 0x16zz have been allocated for classlib-type
+ // HResults. Also note that some of our HResults have to map to certain
+ // COM HR's, etc.
+
+ // Another arbitrary decision... Feel free to change this, as long as you
+ // renumber the HResults yourself (and update rexcep.h).
+ // Reflection will use 0x1600 -> 0x161f. IO will use 0x1620 -> 0x163f.
+ // Security will use 0x1640 -> 0x165f
+
+ // There are __HResults files in the IO, Remoting, Reflection &
+ // Security/Util directories as well, so choose your HResults carefully.
+ internal static class __HResults
+ {
+ internal const int APPMODEL_ERROR_NO_PACKAGE = unchecked((int)0x80073D54);
+ internal const int CLDB_E_FILE_CORRUPT = unchecked((int)0x8013110e);
+ internal const int CLDB_E_FILE_OLDVER = unchecked((int)0x80131107);
+ internal const int CLDB_E_INDEX_NOTFOUND = unchecked((int)0x80131124);
+ internal const int CLR_E_BIND_ASSEMBLY_NOT_FOUND = unchecked((int)0x80132004);
+ internal const int CLR_E_BIND_ASSEMBLY_PUBLIC_KEY_MISMATCH = unchecked((int)0x80132001);
+ internal const int CLR_E_BIND_ASSEMBLY_VERSION_TOO_LOW = unchecked((int)0x80132000);
+ internal const int CLR_E_BIND_TYPE_NOT_FOUND = unchecked((int)0x80132005);
+ internal const int CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT = unchecked((int)0x80132003);
+ internal const int COR_E_ABANDONEDMUTEX = unchecked((int)0x8013152D);
+ internal const int COR_E_AMBIGUOUSMATCH = unchecked((int)0x8000211D);
+ internal const int COR_E_APPDOMAINUNLOADED = unchecked((int)0x80131014);
+ internal const int COR_E_APPLICATION = unchecked((int)0x80131600);
+ internal const int COR_E_ARGUMENT = unchecked((int)0x80070057);
+ internal const int COR_E_ARGUMENTOUTOFRANGE = unchecked((int)0x80131502);
+ internal const int COR_E_ARITHMETIC = unchecked((int)0x80070216);
+ internal const int COR_E_ARRAYTYPEMISMATCH = unchecked((int)0x80131503);
+ internal const int COR_E_ASSEMBLYEXPECTED = unchecked((int)0x80131018);
+ internal const int COR_E_BADIMAGEFORMAT = unchecked((int)0x8007000B);
+ internal const int COR_E_CANNOTUNLOADAPPDOMAIN = unchecked((int)0x80131015);
+ internal const int COR_E_CODECONTRACTFAILED = unchecked((int)0x80131542);
+ internal const int COR_E_CONTEXTMARSHAL = unchecked((int)0x80131504);
+ internal const int COR_E_CUSTOMATTRIBUTEFORMAT = unchecked((int)0x80131605);
+ internal const int COR_E_DATAMISALIGNED = unchecked((int)0x80131541);
+ internal const int COR_E_DIVIDEBYZERO = unchecked((int)0x80020012); // DISP_E_DIVBYZERO
+ internal const int COR_E_DLLNOTFOUND = unchecked((int)0x80131524);
+ internal const int COR_E_DUPLICATEWAITOBJECT = unchecked((int)0x80131529);
+ internal const int COR_E_ENTRYPOINTNOTFOUND = unchecked((int)0x80131523);
+ internal const int COR_E_EXCEPTION = unchecked((int)0x80131500);
+ internal const int COR_E_EXECUTIONENGINE = unchecked((int)0x80131506);
+ internal const int COR_E_FIELDACCESS = unchecked((int)0x80131507);
+ internal const int COR_E_FIXUPSINEXE = unchecked((int)0x80131019);
+ internal const int COR_E_FORMAT = unchecked((int)0x80131537);
+ internal const int COR_E_INDEXOUTOFRANGE = unchecked((int)0x80131508);
+ internal const int COR_E_INSUFFICIENTEXECUTIONSTACK = unchecked((int)0x80131578);
+ internal const int COR_E_INVALIDCAST = unchecked((int)0x80004002);
+ internal const int COR_E_INVALIDCOMOBJECT = unchecked((int)0x80131527);
+ internal const int COR_E_INVALIDFILTERCRITERIA = unchecked((int)0x80131601);
+ internal const int COR_E_INVALIDOLEVARIANTTYPE = unchecked((int)0x80131531);
+ internal const int COR_E_INVALIDOPERATION = unchecked((int)0x80131509);
+ internal const int COR_E_INVALIDPROGRAM = unchecked((int)0x8013153a);
+ internal const int COR_E_KEYNOTFOUND = unchecked((int)0x80131577);
+ internal const int COR_E_LOADING_REFERENCE_ASSEMBLY = unchecked((int)0x80131058);
+ internal const int COR_E_MARSHALDIRECTIVE = unchecked((int)0x80131535);
+ internal const int COR_E_MEMBERACCESS = unchecked((int)0x8013151A);
+ internal const int COR_E_METHODACCESS = unchecked((int)0x80131510);
+ internal const int COR_E_MISSINGFIELD = unchecked((int)0x80131511);
+ internal const int COR_E_MISSINGMANIFESTRESOURCE = unchecked((int)0x80131532);
+ internal const int COR_E_MISSINGMEMBER = unchecked((int)0x80131512);
+ internal const int COR_E_MISSINGMETHOD = unchecked((int)0x80131513);
+ internal const int COR_E_MISSINGSATELLITEASSEMBLY = unchecked((int)0x80131536);
+ internal const int COR_E_MODULE_HASH_CHECK_FAILED = unchecked((int)0x80131039);
+ internal const int COR_E_MULTICASTNOTSUPPORTED = unchecked((int)0x80131514);
+ internal const int COR_E_NEWER_RUNTIME = unchecked((int)0x8013101b);
+ internal const int COR_E_NOTFINITENUMBER = unchecked((int)0x80131528);
+ internal const int COR_E_NOTSUPPORTED = unchecked((int)0x80131515);
+ internal const int COR_E_NULLREFERENCE = unchecked((int)0x80004003);
+ internal const int COR_E_OBJECTDISPOSED = unchecked((int)0x80131622);
+ internal const int COR_E_OPERATIONCANCELED = unchecked((int)0x8013153B);
+ internal const int COR_E_OUTOFMEMORY = unchecked((int)0x8007000E);
+ internal const int COR_E_OVERFLOW = unchecked((int)0x80131516);
+ internal const int COR_E_PLATFORMNOTSUPPORTED = unchecked((int)0x80131539);
+ internal const int COR_E_RANK = unchecked((int)0x80131517);
+ internal const int COR_E_REFLECTIONTYPELOAD = unchecked((int)0x80131602);
+ internal const int COR_E_REMOTING = unchecked((int)0x8013150b);
+ internal const int COR_E_RUNTIMEWRAPPED = unchecked((int)0x8013153e);
+ internal const int COR_E_SAFEARRAYRANKMISMATCH = unchecked((int)0x80131538);
+ internal const int COR_E_SAFEARRAYTYPEMISMATCH = unchecked((int)0x80131533);
+ internal const int COR_E_SECURITY = unchecked((int)0x8013150A);
+ internal const int COR_E_SERIALIZATION = unchecked((int)0x8013150C);
+ internal const int COR_E_SERVER = unchecked((int)0x8013150e);
+ internal const int COR_E_STACKOVERFLOW = unchecked((int)0x800703E9);
+ internal const int COR_E_SYNCHRONIZATIONLOCK = unchecked((int)0x80131518);
+ internal const int COR_E_SYSTEM = unchecked((int)0x80131501);
+ internal const int COR_E_TARGET = unchecked((int)0x80131603);
+ internal const int COR_E_TARGETINVOCATION = unchecked((int)0x80131604);
+ internal const int COR_E_TARGETPARAMCOUNT = unchecked((int)0x8002000e);
+ internal const int COR_E_THREADABORTED = unchecked((int)0x80131530);
+ internal const int COR_E_THREADINTERRUPTED = unchecked((int)0x80131519);
+ internal const int COR_E_THREADSTART = unchecked((int)0x80131525);
+ internal const int COR_E_THREADSTATE = unchecked((int)0x80131520);
+ internal const int COR_E_TIMEOUT = unchecked((int)0x80131505);
+ internal const int COR_E_TYPEACCESS = unchecked((int)0x80131543);
+ internal const int COR_E_TYPEINITIALIZATION = unchecked((int)0x80131534);
+ internal const int COR_E_TYPELOAD = unchecked((int)0x80131522);
+ internal const int COR_E_TYPEUNLOADED = unchecked((int)0x80131013);
+ internal const int COR_E_UNAUTHORIZEDACCESS = unchecked((int)0x80070005);
+ internal const int COR_E_VERIFICATION = unchecked((int)0x8013150D);
+ internal const int COR_E_WAITHANDLECANNOTBEOPENED = unchecked((int)0x8013152C);
+ internal const int CORSEC_E_CRYPTO = unchecked((int)0x80131430);
+ internal const int CORSEC_E_CRYPTO_UNEX_OPER = unchecked((int)0x80131431);
+ internal const int CORSEC_E_INVALID_IMAGE_FORMAT = unchecked((int)0x8013141d);
+ internal const int CORSEC_E_INVALID_PUBLICKEY = unchecked((int)0x8013141e);
+ internal const int CORSEC_E_INVALID_STRONGNAME = unchecked((int)0x8013141a);
+ internal const int CORSEC_E_MIN_GRANT_FAIL = unchecked((int)0x80131417);
+ internal const int CORSEC_E_MISSING_STRONGNAME = unchecked((int)0x8013141b);
+ internal const int CORSEC_E_NO_EXEC_PERM = unchecked((int)0x80131418);
+ internal const int CORSEC_E_POLICY_EXCEPTION = unchecked((int)0x80131416);
+ internal const int CORSEC_E_SIGNATURE_MISMATCH = unchecked((int)0x80131420);
+ internal const int CORSEC_E_XMLSYNTAX = unchecked((int)0x80131419);
+ internal const int CTL_E_DEVICEIOERROR = unchecked((int)0x800A0039);
+ internal const int CTL_E_DIVISIONBYZERO = unchecked((int)0x800A000B);
+ internal const int CTL_E_FILENOTFOUND = unchecked((int)0x800A0035);
+ internal const int CTL_E_OUTOFMEMORY = unchecked((int)0x800A0007);
+ internal const int CTL_E_OUTOFSTACKSPACE = unchecked((int)0x800A001C);
+ internal const int CTL_E_OVERFLOW = unchecked((int)0x800A0006);
+ internal const int CTL_E_PATHFILEACCESSERROR = unchecked((int)0x800A004B);
+ internal const int CTL_E_PATHNOTFOUND = unchecked((int)0x800A004C);
+ internal const int CTL_E_PERMISSIONDENIED = unchecked((int)0x800A0046);
+ internal const int E_ELEMENTNOTAVAILABLE = unchecked((int)0x802B001F);
+ internal const int E_ELEMENTNOTENABLED = unchecked((int)0x802B001E);
+ internal const int E_FAIL = unchecked((int)0x80004005);
+ internal const int E_ILLEGAL_DELEGATE_ASSIGNMENT = unchecked((int)0x80000018);
+ internal const int E_ILLEGAL_METHOD_CALL = unchecked((int)0x8000000E);
+ internal const int E_ILLEGAL_STATE_CHANGE = unchecked((int)0x8000000D);
+ internal const int E_LAYOUTCYCLE = unchecked((int)0x802B0014);
+ internal const int E_NOTIMPL = unchecked((int)0x80004001);
+ internal const int E_OUTOFMEMORY = unchecked((int)0x8007000E);
+ internal const int E_POINTER = unchecked((int)0x80004003L);
+ internal const int E_XAMLPARSEFAILED = unchecked((int)0x802B000A);
+ internal const int ERROR_BAD_EXE_FORMAT = unchecked((int)0x800700C1);
+ internal const int ERROR_BAD_NET_NAME = unchecked((int)0x80070043);
+ internal const int ERROR_BAD_NETPATH = unchecked((int)0x80070035);
+ internal const int ERROR_DISK_CORRUPT = unchecked((int)0x80070571);
+ internal const int ERROR_DLL_INIT_FAILED = unchecked((int)0x8007045A);
+ internal const int ERROR_DLL_NOT_FOUND = unchecked((int)0x80070485);
+ internal const int ERROR_EXE_MARKED_INVALID = unchecked((int)0x800700C0);
+ internal const int ERROR_FILE_CORRUPT = unchecked((int)0x80070570);
+ internal const int ERROR_FILE_INVALID = unchecked((int)0x800703EE);
+ internal const int ERROR_FILE_NOT_FOUND = unchecked((int)0x80070002);
+ internal const int ERROR_INVALID_DLL = unchecked((int)0x80070482);
+ internal const int ERROR_INVALID_NAME = unchecked((int)0x8007007B);
+ internal const int ERROR_INVALID_ORDINAL = unchecked((int)0x800700B6);
+ internal const int ERROR_INVALID_PARAMETER = unchecked((int)0x80070057);
+ internal const int ERROR_LOCK_VIOLATION = unchecked((int)0x80070021);
+ internal const int ERROR_MOD_NOT_FOUND = unchecked((int)0x8007007E);
+ internal const int ERROR_NO_UNICODE_TRANSLATION = unchecked((int)0x80070459);
+ internal const int ERROR_NOACCESS = unchecked((int)0x800703E6);
+ internal const int ERROR_NOT_READY = unchecked((int)0x80070015);
+ internal const int ERROR_OPEN_FAILED = unchecked((int)0x8007006E);
+ internal const int ERROR_PATH_NOT_FOUND = unchecked((int)0x80070003);
+ internal const int ERROR_SHARING_VIOLATION = unchecked((int)0x80070020);
+ internal const int ERROR_TOO_MANY_OPEN_FILES = unchecked((int)0x80070004);
+ internal const int ERROR_UNRECOGNIZED_VOLUME = unchecked((int)0x800703ED);
+ internal const int ERROR_WRONG_TARGET_NAME = unchecked((int)0x80070574);
+ internal const int FUSION_E_ASM_MODULE_MISSING = unchecked((int)0x80131042);
+ internal const int FUSION_E_CACHEFILE_FAILED = unchecked((int)0x80131052);
+ internal const int FUSION_E_CODE_DOWNLOAD_DISABLED = unchecked((int)0x80131048);
+ internal const int FUSION_E_HOST_GAC_ASM_MISMATCH = unchecked((int)0x80131050);
+ internal const int FUSION_E_INVALID_NAME = unchecked((int)0x80131047);
+ internal const int FUSION_E_INVALID_PRIVATE_ASM_LOCATION = unchecked((int)0x80131041);
+ internal const int FUSION_E_LOADFROM_BLOCKED = unchecked((int)0x80131051);
+ internal const int FUSION_E_PRIVATE_ASM_DISALLOWED = unchecked((int)0x80131044);
+ internal const int FUSION_E_REF_DEF_MISMATCH = unchecked((int)0x80131040);
+ internal const int FUSION_E_SIGNATURE_CHECK_FAILED = unchecked((int)0x80131045);
+ internal const int INET_E_CANNOT_CONNECT = unchecked((int)0x800C0004);
+ internal const int INET_E_CONNECTION_TIMEOUT = unchecked((int)0x800C000B);
+ internal const int INET_E_DATA_NOT_AVAILABLE = unchecked((int)0x800C0007);
+ internal const int INET_E_DOWNLOAD_FAILURE = unchecked((int)0x800C0008);
+ internal const int INET_E_OBJECT_NOT_FOUND = unchecked((int)0x800C0006);
+ internal const int INET_E_RESOURCE_NOT_FOUND = unchecked((int)0x800C0005);
+ internal const int INET_E_UNKNOWN_PROTOCOL = unchecked((int)0x800C000D);
+ internal const int ISS_E_ALLOC_TOO_LARGE = unchecked((int)0x80131484);
+ internal const int ISS_E_BLOCK_SIZE_TOO_SMALL = unchecked((int)0x80131483);
+ internal const int ISS_E_CALLER = unchecked((int)0x801314A1);
+ internal const int ISS_E_CORRUPTED_STORE_FILE = unchecked((int)0x80131480);
+ internal const int ISS_E_CREATE_DIR = unchecked((int)0x80131468);
+ internal const int ISS_E_CREATE_MUTEX = unchecked((int)0x80131464);
+ internal const int ISS_E_DEPRECATE = unchecked((int)0x801314A0);
+ internal const int ISS_E_FILE_NOT_MAPPED = unchecked((int)0x80131482);
+ internal const int ISS_E_FILE_WRITE = unchecked((int)0x80131466);
+ internal const int ISS_E_GET_FILE_SIZE = unchecked((int)0x80131463);
+ internal const int ISS_E_ISOSTORE = unchecked((int)0x80131450);
+ internal const int ISS_E_LOCK_FAILED = unchecked((int)0x80131465);
+ internal const int ISS_E_MACHINE = unchecked((int)0x801314A3);
+ internal const int ISS_E_MACHINE_DACL = unchecked((int)0x801314A4);
+ internal const int ISS_E_MAP_VIEW_OF_FILE = unchecked((int)0x80131462);
+ internal const int ISS_E_OPEN_FILE_MAPPING = unchecked((int)0x80131461);
+ internal const int ISS_E_OPEN_STORE_FILE = unchecked((int)0x80131460);
+ internal const int ISS_E_PATH_LENGTH = unchecked((int)0x801314A2);
+ internal const int ISS_E_SET_FILE_POINTER = unchecked((int)0x80131467);
+ internal const int ISS_E_STORE_NOT_OPEN = unchecked((int)0x80131469);
+ internal const int ISS_E_STORE_VERSION = unchecked((int)0x80131481);
+ internal const int ISS_E_TABLE_ROW_NOT_FOUND = unchecked((int)0x80131486);
+ internal const int ISS_E_USAGE_WILL_EXCEED_QUOTA = unchecked((int)0x80131485);
+ internal const int META_E_BAD_SIGNATURE = unchecked((int)0x80131192);
+ internal const int META_E_CA_FRIENDS_SN_REQUIRED = unchecked((int)0x801311e6);
+ internal const int MSEE_E_ASSEMBLYLOADINPROGRESS = unchecked((int)0x80131016);
+ internal const int RO_E_CLOSED = unchecked((int)0x80000013);
+ internal const int E_BOUNDS = unchecked((int)0x8000000B);
+ internal const int RO_E_METADATA_NAME_NOT_FOUND = unchecked((int)0x8000000F);
+ internal const int SECURITY_E_INCOMPATIBLE_EVIDENCE = unchecked((int)0x80131403);
+ internal const int SECURITY_E_INCOMPATIBLE_SHARE = unchecked((int)0x80131401);
+ internal const int SECURITY_E_UNVERIFIABLE = unchecked((int)0x80131402);
+ internal const int STG_E_PATHNOTFOUND = unchecked((int)0x80030003);
+ public const int COR_E_DIRECTORYNOTFOUND = unchecked((int)0x80070003);
+ public const int COR_E_ENDOFSTREAM = unchecked((int)0x80070026); // OS defined
+ public const int COR_E_FILELOAD = unchecked((int)0x80131621);
+ public const int COR_E_FILENOTFOUND = unchecked((int)0x80070002);
+ public const int COR_E_IO = unchecked((int)0x80131620);
+ public const int COR_E_PATHTOOLONG = unchecked((int)0x800700CE);
+ }
+}
diff --git a/src/System.Private.Interop/src/WinRT/ExceptionHelpers.cs b/src/System.Private.Interop/src/WinRT/ExceptionHelpers.cs
new file mode 100644
index 000000000..420492ca6
--- /dev/null
+++ b/src/System.Private.Interop/src/WinRT/ExceptionHelpers.cs
@@ -0,0 +1,954 @@
+// 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.CompilerServices;
+using System.Diagnostics.Contracts;
+using Internal.Runtime.Augments;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// This class has all the helpers which are needed to provide the Exception support for WinRT and ClassicCOM
+ /// </summary>
+ public unsafe static partial class ExceptionHelpers
+ {
+ /// <summary>
+ /// This class is a helper class to call into IRestrictedErrorInfo methods.
+ /// </summary>
+ private static class RestrictedErrorInfoHelper
+ {
+ internal static bool GetErrorDetails(System.IntPtr pRestrictedErrorInfo, out string errMsg, out int hr, out string resErrMsg, out string errCapSid)
+ {
+ Contract.Assert(pRestrictedErrorInfo != IntPtr.Zero);
+ IntPtr pErrDes, pResErrDes, pErrCapSid;
+
+ pErrDes = pResErrDes = pErrCapSid = IntPtr.Zero;
+ int result;
+ try
+ {
+ // Get the errorDetails associated with the restrictedErrorInfo.
+ __com_IRestrictedErrorInfo* pComRestrictedErrorInfo = (__com_IRestrictedErrorInfo*)pRestrictedErrorInfo;
+ result = CalliIntrinsics.StdCall<int>(
+ pComRestrictedErrorInfo->pVtable->pfnGetErrorDetails,
+ pRestrictedErrorInfo,
+ out pErrDes,
+ out hr,
+ out pResErrDes,
+ out pErrCapSid);
+
+ if (result >= 0)
+ {
+ // RestrictedErrorInfo details can be used since the pRestrictedErrorInfo has the same hr value as the hr returned by the native code.
+ errMsg = Interop.COM.ConvertBSTRToString(pErrDes);
+ resErrMsg = Interop.COM.ConvertBSTRToString(pResErrDes);
+ errCapSid = Interop.COM.ConvertBSTRToString(pErrCapSid);
+ }
+ else
+ {
+ errMsg = resErrMsg = errCapSid = null;
+ hr = 0;
+ }
+ }
+ finally
+ {
+ if (pErrDes != IntPtr.Zero)
+ ExternalInterop.SysFreeString(pErrDes);
+ if (pResErrDes != IntPtr.Zero)
+ ExternalInterop.SysFreeString(pResErrDes);
+ if (pErrCapSid != IntPtr.Zero)
+ ExternalInterop.SysFreeString(pErrCapSid);
+ }
+
+ return result >= 0;
+ }
+
+ internal static void GetReference(System.IntPtr pRestrictedErrorInfo, out string errReference)
+ {
+ Contract.Assert(pRestrictedErrorInfo != IntPtr.Zero);
+ IntPtr pReference = IntPtr.Zero;
+ errReference = null;
+
+ try
+ {
+ __com_IRestrictedErrorInfo* pComRestrictedErrorInfo = (__com_IRestrictedErrorInfo*)pRestrictedErrorInfo;
+ int result = CalliIntrinsics.StdCall<int>(pComRestrictedErrorInfo->pVtable->pfnGetReference, pRestrictedErrorInfo, out pReference);
+ if (result >= 0)
+ {
+ errReference = Interop.COM.ConvertBSTRToString(pReference);
+ }
+ else
+ {
+ errReference = null;
+ }
+ }
+ finally
+ {
+ if (pReference != IntPtr.Zero)
+ ExternalInterop.SysFreeString(pReference);
+ }
+ }
+ }
+
+ /// <summary>
+ /// The method calls RoOriginateLanguageException. The method has all the logic in try, catch block to ensure that none of the exception helpers
+ /// throw exception themselves.
+ /// </summary>
+ /// <param name="ex"></param>
+ /// <returns></returns>
+ private static bool OriginateLanguageException(Exception ex)
+ {
+ IntPtr pUnk = IntPtr.Zero;
+ HSTRING errorMsg = default(HSTRING);
+ try
+ {
+ pUnk = McgMarshal.ObjectToComInterface(ex, McgModuleManager.IUnknown);
+ if (pUnk != IntPtr.Zero)
+ {
+ RuntimeAugments.GenerateExceptionInformationForDump(ex, pUnk);
+
+ errorMsg = McgMarshal.StringToHString(ex.Message);
+
+ return ExternalInterop.RoOriginateLanguageException(ex.HResult, errorMsg, pUnk) >= 0;
+ }
+ }
+ catch (Exception)
+ {
+ // We can't do anything here and hence simply swallow the exception
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pUnk);
+ if (errorMsg.handle != IntPtr.Zero)
+ {
+ ExternalInterop.WindowsDeleteString(errorMsg.handle.ToPointer());
+ }
+ }
+ return false;
+ }
+
+#pragma warning disable 649, 169 // Field 'blah' is never assigned to/Field 'blah' is never used
+
+ // Lets create vTables for these interfaces.
+ private unsafe struct __com_ILanguageExceptionErrorInfo
+ {
+ internal __vtable_ILanguageExceptionErrorInfo* pVtable;
+ }
+
+ private unsafe struct __vtable_ILanguageExceptionErrorInfo
+ {
+ private IntPtr pfnQueryInterface;
+ private IntPtr pfnAddRef;
+ private IntPtr pfnRelease;
+ internal System.IntPtr pfnGetLanguageException;
+ }
+
+ private unsafe struct __com_IRestrictedErrorInfo
+ {
+ internal __vtable_IRestrictedErrorInfo* pVtable;
+ }
+
+ private unsafe struct __vtable_IRestrictedErrorInfo
+ {
+ private IntPtr pfnQueryInterface;
+ private IntPtr pfnAddRef;
+ private IntPtr pfnRelease;
+ internal System.IntPtr pfnGetErrorDetails;
+ internal System.IntPtr pfnGetReference;
+ }
+
+#pragma warning restore 649, 169
+
+ /// <summary>
+ /// This method gets the mapping hr for the exception. and also does the right thing to propogate the hr correctly to the native layer.
+ ///
+ /// We check if the exception is a pure managed exception or an exception created from an hr that entered the system from native.
+ /// a. If it is a pure managed exception we create an IUnknown ptr from the exception and RoOriginateLanguageException on it.
+ /// This helps us to preserve our managed exception and throw the same exception in case this exception roundtrips and hence preserve the call stack.
+ /// Since the API RoOriginateLanguageException is available only on windows blue, we can't do the same in win8. In desktop CLR we use the non-modern SDK API
+ /// GetErroInfo\SetErrorInfo combination to preserve managed exception but unfortunately we can't do this in .NET Native and hence we only our able to preserve the exception message and
+ /// type and end up getting a rough stacktrace PS - Even this behavior in win8 is possible only in debug mode as RoSetErrorReportingFlags is set to UseSetErrorInfo only in debug mode.
+ ///
+ /// b. In case the exception is created due to an hr that entered managed world via native call, we will have restrictederrorInfo associated with it. In this case
+ /// we do not RoOriginateLanguageException\RoOriginateError and rather preserve the exception stack trace by simply calling the SetRestrictedErrorInfo.
+ ///
+ /// c. PS - Due to the use of modern SDK we have no way to round trip exceptions in classicCOM scenarios any more.
+ /// This is because we can't use SetErrorInfo\GetErrorInfo APIs at all. Unfortunately we have no workaround for this even in windowsBlue!
+ /// With the use of IRestrictedErrorInfo has some disadvantages as we lose other info available with IErrorInfo in terms of HelpFile etc.
+ ///
+ /// d. This class puts all the logic in try, catch block to ensure that none of the exception helpers.
+ /// throw exception themselves.
+ /// </summary>
+ /// <param name="ex"></param>
+ /// <param name="isWinRTScenario"></param>
+ /// <returns></returns>
+ internal static int GetHRForExceptionWithErrorPropogationNoThrow(Exception ex, bool isWinRTScenario)
+ {
+ int hr = ex.HResult;
+
+ if (hr == Interop.COM.COR_E_OBJECTDISPOSED && isWinRTScenario)
+ {
+ // Since ObjectDisposedException is projected to RO_E_CLOSED in WINRT we make sure to use the correct hr while updating the CRuntimeError object of Windows.
+ hr = Interop.COM.RO_E_CLOSED;
+ }
+
+ try
+ {
+ // Check whether the exception has an associated RestrictedErrorInfo associated with it.
+ if (isWinRTScenario)
+ {
+ IntPtr pRestrictedErrorInfo;
+ object restrictedErrorInfo;
+ if (InteropExtensions.TryGetRestrictedErrorObject(ex, out restrictedErrorInfo) && restrictedErrorInfo != null)
+ {
+ // We have the restricted errorInfo associated with this object and hence this exception was created by an hr entering managed through native.
+ pRestrictedErrorInfo = McgMarshal.ObjectToComInterface(restrictedErrorInfo, McgModuleManager.IRestrictedErrorInfo);
+ if (pRestrictedErrorInfo != IntPtr.Zero)
+ {
+ // We simply call SetRestrictedErrorInfo since we do not want to originate the exception again.
+ ExternalInterop.SetRestrictedErrorInfo(pRestrictedErrorInfo);
+ McgMarshal.ComSafeRelease(pRestrictedErrorInfo);
+ }
+ }
+ else
+ {
+ // we are in windows blue and hence we can preserve our exception so that we can reuse this exception in case it comes back and provide richer exception support.
+ OriginateLanguageException(ex);
+ }
+ }
+ else
+ {
+ // We are either pre WinBlue or in classicCOM scenario and hence we can only RoOriginateError at this point.
+ // Desktop CLR uses SetErrorInfo and preserves the exception object which helps us give the same support as winBlue.
+ // Since .NET Native can only use modern SDK we have a compatibility break here by only preserving the restrictederrorMsg and exception type but the stack trace will be incorrect.
+
+ // Also RoOriginateError works only under the debugger since RoSetErrorReportingFlags is set to RO_ERROR_REPORTING_USESETERRORINFO.
+ // If we are not under the debugger we can't set this API since it is not part of the modernSDK and hence this will not work
+ // and will result in different behavior than the desktop.
+ HSTRING errorMsg = McgMarshal.StringToHString(ex.Message);
+ ExternalInterop.RoOriginateError(ex.HResult, errorMsg);
+ ExternalInterop.WindowsDeleteString(errorMsg.handle.ToPointer());
+ }
+ }
+ catch (Exception)
+ {
+ // We can't throw an exception here and hence simply swallow it.
+ }
+
+ return hr;
+ }
+
+ /// <summary>
+ /// This does a mapping from hr to the exception and also takes care of making default exception in case of classic COM as COMException.
+ /// and in winrt and marshal APIs as Exception.
+ /// </summary>
+ /// <param name="errorCode"></param>
+ /// <param name="message"></param>
+ /// <param name="createCOMException"></param>
+ /// <returns></returns>
+ internal static Exception GetMappingExceptionForHR(int errorCode, string message, bool createCOMException, bool hasErrorInfo)
+ {
+ if (errorCode >= 0)
+ {
+ return null;
+ }
+
+ Exception exception = null;
+
+ bool shouldDisplayHR = false;
+
+ switch (errorCode)
+ {
+ case __HResults.COR_E_NOTFINITENUMBER: // NotFiniteNumberException
+ case __HResults.COR_E_ARITHMETIC:
+ exception = new ArithmeticException();
+ break;
+ case __HResults.COR_E_ARGUMENT:
+ case unchecked((int)0x800A01C1):
+ case unchecked((int)0x800A01C2):
+ case __HResults.CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT:
+ exception = new ArgumentException();
+
+ if (errorCode != __HResults.COR_E_ARGUMENT)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.E_BOUNDS:
+ case __HResults.COR_E_ARGUMENTOUTOFRANGE:
+ case __HResults.ERROR_NO_UNICODE_TRANSLATION:
+ exception = new ArgumentOutOfRangeException();
+
+ if (errorCode != __HResults.COR_E_ARGUMENTOUTOFRANGE)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_ARRAYTYPEMISMATCH:
+ exception = new ArrayTypeMismatchException();
+ break;
+ case __HResults.COR_E_BADIMAGEFORMAT:
+ case __HResults.CLDB_E_FILE_OLDVER:
+ case __HResults.CLDB_E_INDEX_NOTFOUND:
+ case __HResults.CLDB_E_FILE_CORRUPT:
+ case __HResults.COR_E_NEWER_RUNTIME:
+ case __HResults.COR_E_ASSEMBLYEXPECTED:
+ case __HResults.ERROR_BAD_EXE_FORMAT:
+ case __HResults.ERROR_EXE_MARKED_INVALID:
+ case __HResults.CORSEC_E_INVALID_IMAGE_FORMAT:
+ case __HResults.ERROR_NOACCESS:
+ case __HResults.ERROR_INVALID_ORDINAL:
+ case __HResults.ERROR_INVALID_DLL:
+ case __HResults.ERROR_FILE_CORRUPT:
+ case __HResults.COR_E_LOADING_REFERENCE_ASSEMBLY:
+ case __HResults.META_E_BAD_SIGNATURE:
+ exception = new BadImageFormatException();
+
+ // Always show HR for BadImageFormatException
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_CUSTOMATTRIBUTEFORMAT:
+ exception = new FormatException();
+ break; // CustomAttributeFormatException
+ case __HResults.COR_E_DATAMISALIGNED:
+ exception = InteropExtensions.CreateDataMisalignedException(message); // TODO: Do we need to add msg here?
+ break;
+ case __HResults.COR_E_DIVIDEBYZERO:
+ case __HResults.CTL_E_DIVISIONBYZERO:
+ exception = new DivideByZeroException();
+
+ if (errorCode != __HResults.COR_E_DIVIDEBYZERO)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_DLLNOTFOUND:
+#if ENABLE_WINRT
+ exception = new DllNotFoundException();
+#endif
+ break;
+ case __HResults.COR_E_DUPLICATEWAITOBJECT:
+ exception = new ArgumentException();
+ break; // DuplicateWaitObjectException
+ case __HResults.COR_E_ENDOFSTREAM:
+ case unchecked((int)0x800A003E):
+ exception = new System.IO.EndOfStreamException();
+
+ if (errorCode != __HResults.COR_E_ENDOFSTREAM)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_TYPEACCESS: // TypeAccessException
+ case __HResults.COR_E_ENTRYPOINTNOTFOUND:
+ exception = new TypeLoadException();
+
+ break; // EntryPointNotFoundException
+ case __HResults.COR_E_EXCEPTION:
+ exception = new Exception();
+ break;
+ case __HResults.COR_E_DIRECTORYNOTFOUND:
+ case __HResults.STG_E_PATHNOTFOUND:
+ case __HResults.CTL_E_PATHNOTFOUND:
+ exception = new System.IO.DirectoryNotFoundException();
+
+ if (errorCode != __HResults.COR_E_DIRECTORYNOTFOUND)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_FILELOAD:
+ case __HResults.FUSION_E_INVALID_PRIVATE_ASM_LOCATION:
+ case __HResults.FUSION_E_SIGNATURE_CHECK_FAILED:
+ case __HResults.FUSION_E_LOADFROM_BLOCKED:
+ case __HResults.FUSION_E_CACHEFILE_FAILED:
+ case __HResults.FUSION_E_ASM_MODULE_MISSING:
+ case __HResults.FUSION_E_INVALID_NAME:
+ case __HResults.FUSION_E_PRIVATE_ASM_DISALLOWED:
+ case __HResults.FUSION_E_HOST_GAC_ASM_MISMATCH:
+ case __HResults.COR_E_MODULE_HASH_CHECK_FAILED:
+ case __HResults.FUSION_E_REF_DEF_MISMATCH:
+ case __HResults.SECURITY_E_INCOMPATIBLE_SHARE:
+ case __HResults.SECURITY_E_INCOMPATIBLE_EVIDENCE:
+ case __HResults.SECURITY_E_UNVERIFIABLE:
+ case __HResults.COR_E_FIXUPSINEXE:
+ case __HResults.ERROR_TOO_MANY_OPEN_FILES:
+ case __HResults.ERROR_SHARING_VIOLATION:
+ case __HResults.ERROR_LOCK_VIOLATION:
+ case __HResults.ERROR_OPEN_FAILED:
+ case __HResults.ERROR_DISK_CORRUPT:
+ case __HResults.ERROR_UNRECOGNIZED_VOLUME:
+ case __HResults.ERROR_DLL_INIT_FAILED:
+ case __HResults.FUSION_E_CODE_DOWNLOAD_DISABLED:
+ case __HResults.CORSEC_E_MISSING_STRONGNAME:
+ case __HResults.MSEE_E_ASSEMBLYLOADINPROGRESS:
+ case __HResults.ERROR_FILE_INVALID:
+ exception = new System.IO.FileLoadException();
+
+ shouldDisplayHR = true;
+ break;
+ case __HResults.COR_E_PATHTOOLONG:
+ exception = new System.IO.PathTooLongException();
+ break;
+ case __HResults.COR_E_IO:
+ case __HResults.CTL_E_DEVICEIOERROR:
+ case unchecked((int)0x800A793C):
+ case unchecked((int)0x800A793D):
+ exception = new System.IO.IOException();
+
+ if (errorCode != __HResults.COR_E_IO)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.ERROR_FILE_NOT_FOUND:
+ case __HResults.ERROR_MOD_NOT_FOUND:
+ case __HResults.ERROR_INVALID_NAME:
+ case __HResults.CTL_E_FILENOTFOUND:
+ case __HResults.ERROR_BAD_NET_NAME:
+ case __HResults.ERROR_BAD_NETPATH:
+ case __HResults.ERROR_NOT_READY:
+ case __HResults.ERROR_WRONG_TARGET_NAME:
+ case __HResults.INET_E_UNKNOWN_PROTOCOL:
+ case __HResults.INET_E_CONNECTION_TIMEOUT:
+ case __HResults.INET_E_CANNOT_CONNECT:
+ case __HResults.INET_E_RESOURCE_NOT_FOUND:
+ case __HResults.INET_E_OBJECT_NOT_FOUND:
+ case __HResults.INET_E_DOWNLOAD_FAILURE:
+ case __HResults.INET_E_DATA_NOT_AVAILABLE:
+ case __HResults.ERROR_DLL_NOT_FOUND:
+ case __HResults.CLR_E_BIND_ASSEMBLY_VERSION_TOO_LOW:
+ case __HResults.CLR_E_BIND_ASSEMBLY_PUBLIC_KEY_MISMATCH:
+ case __HResults.CLR_E_BIND_ASSEMBLY_NOT_FOUND:
+ exception = new System.IO.FileNotFoundException();
+
+ shouldDisplayHR = true;
+ break;
+ case __HResults.COR_E_FORMAT:
+ exception = new FormatException();
+ break;
+ case __HResults.COR_E_INDEXOUTOFRANGE:
+ case unchecked((int)0x800a0009):
+ exception = new IndexOutOfRangeException();
+
+ if (errorCode != __HResults.COR_E_INDEXOUTOFRANGE)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_INVALIDCAST:
+ exception = new InvalidCastException();
+ break;
+ case __HResults.COR_E_INVALIDCOMOBJECT:
+ exception = new InvalidComObjectException();
+ break;
+ case __HResults.COR_E_INVALIDOLEVARIANTTYPE:
+ exception = new InvalidOleVariantTypeException();
+ break;
+ case __HResults.COR_E_INVALIDOPERATION:
+ case __HResults.E_ILLEGAL_STATE_CHANGE:
+ case __HResults.E_ILLEGAL_METHOD_CALL:
+ case __HResults.E_ILLEGAL_DELEGATE_ASSIGNMENT:
+ case __HResults.APPMODEL_ERROR_NO_PACKAGE:
+ exception = new InvalidOperationException();
+
+ if (errorCode != __HResults.COR_E_INVALIDOPERATION)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_MARSHALDIRECTIVE:
+ exception = new MarshalDirectiveException();
+ break;
+ case __HResults.COR_E_METHODACCESS: // MethodAccessException
+ case __HResults.META_E_CA_FRIENDS_SN_REQUIRED: // MethodAccessException
+ case __HResults.COR_E_FIELDACCESS:
+ case __HResults.COR_E_MEMBERACCESS:
+ exception = new MemberAccessException();
+
+ if (errorCode != __HResults.COR_E_METHODACCESS)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_MISSINGFIELD: // MissingFieldException
+ case __HResults.COR_E_MISSINGMETHOD: // MissingMethodException
+ case __HResults.COR_E_MISSINGMEMBER:
+ case unchecked((int)0x800A01CD):
+ exception = new MissingMemberException();
+ break;
+ case __HResults.COR_E_MISSINGMANIFESTRESOURCE:
+ exception = new System.Resources.MissingManifestResourceException();
+ break;
+ case __HResults.COR_E_NOTSUPPORTED:
+ case unchecked((int)0x800A01B6):
+ case unchecked((int)0x800A01BD):
+ case unchecked((int)0x800A01CA):
+ case unchecked((int)0x800A01CB):
+ exception = new NotSupportedException();
+
+ if (errorCode != __HResults.COR_E_NOTSUPPORTED)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_NULLREFERENCE:
+ exception = new NullReferenceException();
+ break;
+ case __HResults.COR_E_OBJECTDISPOSED:
+ case __HResults.RO_E_CLOSED:
+ // No default constructor
+ exception = new ObjectDisposedException(String.Empty);
+ break;
+ case __HResults.COR_E_OPERATIONCANCELED:
+#if ENABLE_WINRT
+ exception = new OperationCanceledException();
+#endif
+ break;
+ case __HResults.COR_E_OVERFLOW:
+ case __HResults.CTL_E_OVERFLOW:
+ exception = new OverflowException();
+ break;
+ case __HResults.COR_E_PLATFORMNOTSUPPORTED:
+ exception = new PlatformNotSupportedException(message);
+ break;
+ case __HResults.COR_E_RANK:
+ exception = new RankException();
+ break;
+ case __HResults.COR_E_REFLECTIONTYPELOAD:
+#if ENABLE_WINRT
+ exception = new System.Reflection.ReflectionTypeLoadException(null, null);
+#endif
+ break;
+ case __HResults.COR_E_SECURITY:
+ case __HResults.CORSEC_E_INVALID_STRONGNAME:
+ case __HResults.CTL_E_PERMISSIONDENIED:
+ case unchecked((int)0x800A01A3):
+ case __HResults.CORSEC_E_INVALID_PUBLICKEY:
+ case __HResults.CORSEC_E_SIGNATURE_MISMATCH:
+ exception = new System.Security.SecurityException();
+ break;
+ case __HResults.COR_E_SAFEARRAYRANKMISMATCH:
+ exception = new SafeArrayRankMismatchException();
+ break;
+ case __HResults.COR_E_SAFEARRAYTYPEMISMATCH:
+ exception = new SafeArrayTypeMismatchException();
+ break;
+ case __HResults.COR_E_SERIALIZATION:
+ exception = ConstructExceptionUsingReflection(
+ "System.Runtime.Serialization.SerializationException, System.Runtime.Serialization.Primitives, Version=4.0.0.0",
+ message);
+ break;
+ case __HResults.COR_E_SYNCHRONIZATIONLOCK:
+ exception = new System.Threading.SynchronizationLockException();
+ break;
+ case __HResults.COR_E_TARGETINVOCATION:
+ exception = new System.Reflection.TargetInvocationException(null);
+ break;
+ case __HResults.COR_E_TARGETPARAMCOUNT:
+ exception = new System.Reflection.TargetParameterCountException();
+ break;
+ case __HResults.COR_E_TYPEINITIALIZATION:
+ exception = InteropExtensions.CreateTypeInitializationException(message);
+ break;
+ case __HResults.COR_E_TYPELOAD:
+ case __HResults.RO_E_METADATA_NAME_NOT_FOUND:
+ case __HResults.CLR_E_BIND_TYPE_NOT_FOUND:
+ exception = new TypeLoadException();
+
+ if (errorCode != __HResults.COR_E_TYPELOAD)
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_UNAUTHORIZEDACCESS:
+ case __HResults.CTL_E_PATHFILEACCESSERROR:
+ case unchecked((int)0x800A014F):
+ exception = new UnauthorizedAccessException();
+
+ shouldDisplayHR = true;
+
+ break;
+ case __HResults.COR_E_VERIFICATION:
+ exception = new System.Security.VerificationException();
+ break;
+ case __HResults.E_NOTIMPL:
+ exception = new NotImplementedException();
+ break;
+ case __HResults.E_OUTOFMEMORY:
+ case __HResults.CTL_E_OUTOFMEMORY:
+ case unchecked((int)0x800A7919):
+ exception = new OutOfMemoryException();
+
+ if (errorCode != __HResults.E_OUTOFMEMORY)
+ shouldDisplayHR = true;
+
+ break;
+#if ENABLE_WINRT
+ case __HResults.E_XAMLPARSEFAILED:
+ exception = new Windows.UI.Xaml.Markup.XamlParseException();
+ break;
+ case __HResults.E_ELEMENTNOTAVAILABLE:
+ exception = new Windows.UI.Xaml.Automation.ElementNotAvailableException();
+ break;
+ case __HResults.E_ELEMENTNOTENABLED:
+ exception = new Windows.UI.Xaml.Automation.ElementNotEnabledException();
+ break;
+ case __HResults.E_LAYOUTCYCLE:
+ exception = new Windows.UI.Xaml.LayoutCycleException();
+ break;
+#endif // ENABLE_WINRT
+ case __HResults.COR_E_AMBIGUOUSMATCH: // AmbiguousMatchException
+ case __HResults.COR_E_APPLICATION: // ApplicationException
+ case __HResults.COR_E_APPDOMAINUNLOADED: // AppDomainUnloadedException
+ case __HResults.COR_E_CANNOTUNLOADAPPDOMAIN: // CannotUnloadAppDomainException
+ case __HResults.COR_E_CODECONTRACTFAILED: // ContractException
+ case __HResults.COR_E_CONTEXTMARSHAL: // ContextMarshalException
+ case __HResults.CORSEC_E_CRYPTO: // CryptographicException
+ case __HResults.CORSEC_E_CRYPTO_UNEX_OPER: // CryptographicUnexpectedOperationException
+ case __HResults.COR_E_EXECUTIONENGINE: // ExecutionEngineException
+ case __HResults.COR_E_INSUFFICIENTEXECUTIONSTACK: // InsufficientExecutionStackException
+ case __HResults.COR_E_INVALIDFILTERCRITERIA: // InvalidFilterCriteriaException
+ case __HResults.COR_E_INVALIDPROGRAM: // InvalidProgramException
+ case __HResults.COR_E_MULTICASTNOTSUPPORTED: // MulticastNotSupportedException
+ case __HResults.COR_E_REMOTING: // RemotingException
+ case __HResults.COR_E_RUNTIMEWRAPPED: // RuntimeWrappedException
+ case __HResults.COR_E_SERVER: // ServerException
+ case __HResults.COR_E_STACKOVERFLOW: // StackOverflowException
+ case __HResults.CTL_E_OUTOFSTACKSPACE: // StackOverflowException
+ case __HResults.COR_E_SYSTEM: // SystemException
+ case __HResults.COR_E_TARGET: // TargetException
+ case __HResults.COR_E_THREADABORTED: // TargetException
+ case __HResults.COR_E_THREADINTERRUPTED: // ThreadInterruptedException
+ case __HResults.COR_E_THREADSTATE: // ThreadStateException
+ case __HResults.COR_E_THREADSTART: // ThreadStartException
+ case __HResults.COR_E_TYPEUNLOADED: // TypeUnloadedException
+ case __HResults.CORSEC_E_POLICY_EXCEPTION: // PolicyException
+ case __HResults.CORSEC_E_NO_EXEC_PERM: // PolicyException
+ case __HResults.CORSEC_E_MIN_GRANT_FAIL: // PolicyException
+ case __HResults.CORSEC_E_XMLSYNTAX: // XmlSyntaxException
+ case __HResults.ISS_E_ALLOC_TOO_LARGE: // IsolatedStorageException
+ case __HResults.ISS_E_BLOCK_SIZE_TOO_SMALL: // IsolatedStorageException
+ case __HResults.ISS_E_CALLER: // IsolatedStorageException
+ case __HResults.ISS_E_CORRUPTED_STORE_FILE: // IsolatedStorageException
+ case __HResults.ISS_E_CREATE_DIR: // IsolatedStorageException
+ case __HResults.ISS_E_CREATE_MUTEX: // IsolatedStorageException
+ case __HResults.ISS_E_DEPRECATE: // IsolatedStorageException
+ case __HResults.ISS_E_FILE_NOT_MAPPED: // IsolatedStorageException
+ case __HResults.ISS_E_FILE_WRITE: // IsolatedStorageException
+ case __HResults.ISS_E_GET_FILE_SIZE: // IsolatedStorageException
+ case __HResults.ISS_E_ISOSTORE: // IsolatedStorageException
+ case __HResults.ISS_E_LOCK_FAILED: // IsolatedStorageException
+ case __HResults.ISS_E_MACHINE: // IsolatedStorageException
+ case __HResults.ISS_E_MACHINE_DACL: // IsolatedStorageException
+ case __HResults.ISS_E_MAP_VIEW_OF_FILE: // IsolatedStorageException
+ case __HResults.ISS_E_OPEN_FILE_MAPPING: // IsolatedStorageException
+ case __HResults.ISS_E_OPEN_STORE_FILE: // IsolatedStorageException
+ case __HResults.ISS_E_PATH_LENGTH: // IsolatedStorageException
+ case __HResults.ISS_E_SET_FILE_POINTER: // IsolatedStorageException
+ case __HResults.ISS_E_STORE_NOT_OPEN: // IsolatedStorageException
+ case __HResults.ISS_E_STORE_VERSION: // IsolatedStorageException
+ case __HResults.ISS_E_TABLE_ROW_NOT_FOUND: // IsolatedStorageException
+ case __HResults.ISS_E_USAGE_WILL_EXCEED_QUOTA: // IsolatedStorageException
+ case __HResults.E_FAIL:
+ default:
+ break;
+ }
+
+ if (exception == null)
+ {
+ if (createCOMException)
+ {
+ exception = new COMException();
+ if (errorCode != __HResults.E_FAIL)
+ shouldDisplayHR = true;
+ }
+ else
+ {
+ exception = new Exception();
+ if (errorCode != __HResults.COR_E_EXCEPTION)
+ shouldDisplayHR = true;
+ }
+ }
+
+ bool shouldConstructMessage = false;
+ if (hasErrorInfo)
+ {
+ // If there is a IErrorInfo/IRestrictedErrorInfo, only construct a new error message if
+ // the message is not available and do not use the shouldDisplayHR setting
+ if (message == null)
+ shouldConstructMessage = true;
+ }
+ else
+ {
+ // If there is no IErrorInfo, use the shouldDisplayHR setting from the big switch/case above
+ shouldConstructMessage = shouldDisplayHR;
+ }
+
+ if (shouldConstructMessage)
+ {
+ //
+ // Append the HR into error message, just in case the app wants to look at the HR in
+ // message to determine behavior. We didn't expose HResult property until v4.5 and
+ // GetHRFromException has side effects so probably Message was their only choice.
+ // This behavior is probably not exactly the same as in desktop but it is fine to append
+ // more message at the end. In any case, having the HR in the error message are helpful
+ // to developers.
+ // This makes sure:
+ // 1. We always have a HR 0xNNNNNNNN in the message
+ // 2. Put in a nice "Exception thrown from HRESULT" message if we can
+ // 3. Wrap it in () if there is an existing message
+ //
+
+ // TODO: Add Symbolic Name into Messaage, convert 0x80020006 to DISP_E_UNKNOWNNAME
+ string hrMessage = String.Format("{0} 0x{1:X}", SR.Excep_FromHResult, errorCode);
+
+ message = ExternalInterop.GetMessage(errorCode);
+
+ // Always make sure we have at least the HRESULT part in retail build or when the message
+ // is empty.
+ if (message == null)
+ message = hrMessage;
+ else
+ message = message + " (" + hrMessage + ")";
+ }
+
+ if (message != null)
+ {
+ // Set message explicitly rather than calling constructor because certain ctors would append a
+ // prefix to the message and that is not what we want
+ InteropExtensions.SetExceptionMessage(exception, message);
+ }
+
+ InteropExtensions.SetExceptionErrorCode(exception, errorCode);
+
+ return exception;
+ }
+
+ /// <summary>
+ /// Construct exception dynamically using reflection.
+ /// </summary>
+ /// <param name="exceptionTypeName">Assembly-qualified exception type name</param>
+ /// <param name="message">Message to use for exception creation (null = use parameterless constructor)</param>
+ static Exception ConstructExceptionUsingReflection(string exceptionTypeName, string message)
+ {
+ Exception result = null;
+
+ try
+ {
+ Type exceptionType = Type.GetType(exceptionTypeName);
+
+ if (exceptionType != null)
+ {
+ if (message == null)
+ {
+ result = (Exception)Activator.CreateInstance(exceptionType);
+ }
+ else
+ {
+ result = (Exception)Activator.CreateInstance(exceptionType, message);
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // Ignore exceptions during exception construction - a default exception will be returned
+ }
+ return result;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ static bool TryGetRestrictedErrorInfo(out IntPtr pRestrictedErrorInfo)
+ {
+ return ExternalInterop.GetRestrictedErrorInfo(out pRestrictedErrorInfo) >= 0 && pRestrictedErrorInfo != IntPtr.Zero;
+ }
+
+ /// <summary>
+ /// This method returns a new Exception object given the HR value.
+ ///
+ /// 1. We check whether we have our own LanguageException associated with this hr. If so we simply use it since it helps preserve the stacktrace, message and type.
+ /// This is done using GetLanguageException API on ILanguageExceptionErrorInfo from IRestrictedErrorInfo. Since ILanguageExceptionErrorInfo is available only on Windows Blue
+ /// we can only do this WindowsBlue and above. In desktop CLR we could use GetErroInfo and check whether we have our IErroInfo and retrieve our own exception.
+ /// For Win8 in .NET Native we simply create the exception using the RestrictedErrorInfo and hence only able to give the exception with restrictedErrorMsg.
+ /// 2. In case we do not have the languageException we simply check RestrictedErrorInfo for errorMsg and create an exception using
+ /// <errorMsg>\r\n<restrictedErrorMsg>. This is done for only windows blue. To be backward compatible we only use errorMsg for creating exception in win8.
+ /// 3. PS - This class puts all the logic in try, catch block to ensure that none of the exception helpers
+ /// throw exception themselves.
+ /// </summary>
+ /// <param name="hr"></param>
+ /// <param name="isWinRTScenario"></param>
+ internal static Exception GetExceptionForHRInternalNoThrow(int hr, bool isWinRTScenario, bool isClassicCOM)
+ {
+ Exception ex;
+ IntPtr pRestrictedErrorInfo = IntPtr.Zero;
+
+ try
+ {
+ if (TryGetRestrictedErrorInfo(out pRestrictedErrorInfo))
+ {
+ // This is to check whether we need to give post win8 behavior or not.
+ if (isWinRTScenario)
+ {
+ // Check whether the given IRestrictedErrorInfo object supports ILanguageExceptionErrorInfo
+ IntPtr pLanguageExceptionErrorInfo = McgMarshal.ComQueryInterfaceNoThrow(pRestrictedErrorInfo, ref Interop.COM.IID_ILanguageExceptionErrorInfo);
+ if (pLanguageExceptionErrorInfo != IntPtr.Zero)
+ {
+ // We have an LanguageExceptionErrorInfo.
+ IntPtr pUnk;
+ __com_ILanguageExceptionErrorInfo* pComLanguageExceptionErrorInfo = (__com_ILanguageExceptionErrorInfo*)pLanguageExceptionErrorInfo;
+ int result = CalliIntrinsics.StdCall<int>(pComLanguageExceptionErrorInfo->pVtable->pfnGetLanguageException, pLanguageExceptionErrorInfo, out pUnk);
+ McgMarshal.ComSafeRelease(pLanguageExceptionErrorInfo);
+
+ if (result >= 0 && pUnk != IntPtr.Zero)
+ {
+ try
+ {
+ // Check whether the given pUnk is a managed exception.
+ ComCallableObject ccw;
+ if (ComCallableObject.TryGetCCW(pUnk, out ccw))
+ {
+ return ccw.TargetObject as Exception;
+ }
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pUnk);
+ }
+ }
+ }
+ }
+ String message = null, errorInfoReference = null;
+ string errMsg, errCapSid, resErrMsg;
+ int errHr;
+ object restrictedErrorInfo = null;
+
+ bool hasErrorInfo = false;
+ if (RestrictedErrorInfoHelper.GetErrorDetails(pRestrictedErrorInfo, out errMsg, out errHr, out resErrMsg, out errCapSid) && errHr == hr)
+ {
+ // RestrictedErrorInfo details can be used since the pRestrictedErrorInfo has the same hr value as the hr returned by the native code.
+ // We are in windows blue or above and hence the exceptionMsg is errMsg + "\r\n" + resErrMsg
+ message = String.IsNullOrEmpty(resErrMsg) ? errMsg : errMsg + "\r\n" + resErrMsg;
+ RestrictedErrorInfoHelper.GetReference(pRestrictedErrorInfo, out errorInfoReference);
+ restrictedErrorInfo = McgMarshal.ComInterfaceToObject(pRestrictedErrorInfo, McgModuleManager.IRestrictedErrorInfo);
+
+ hasErrorInfo = true;
+ }
+
+ if (hr == Interop.COM.RO_E_CLOSED && isWinRTScenario)
+ hr = Interop.COM.COR_E_OBJECTDISPOSED;
+
+ // Now we simply need to set the description and the resDescription by adding an internal method.
+ ex = GetMappingExceptionForHR(hr, message, isClassicCOM, hasErrorInfo);
+
+ if (restrictedErrorInfo != null)
+ {
+ InteropExtensions.AddExceptionDataForRestrictedErrorInfo(ex, resErrMsg, errorInfoReference, errCapSid, restrictedErrorInfo);
+ }
+
+ return ex;
+ }
+ }
+ catch (Exception)
+ {
+ // We can't do any thing here and hence we swallow the exception and get the corresponding hr.
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pRestrictedErrorInfo);
+ }
+
+ // We could not find any restrictedErrorInfo associated with this object and hence we simply use the hr to create the exception.
+ return GetMappingExceptionForHR(hr, null, isClassicCOM, hasErrorInfo: false);
+ }
+
+ internal static bool ReportUnhandledError(Exception e)
+ {
+ System.IntPtr pRestrictedErrorInfo = IntPtr.Zero;
+
+ if (e != null)
+ {
+ try
+ {
+#if ENABLE_WINRT
+ // Only report to the WinRT global exception handler in modern apps
+ WinRTInteropCallbacks callbacks = WinRTInterop.Callbacks;
+ if (callbacks == null || !callbacks.IsAppxModel())
+ {
+ return false;
+ }
+
+ // Get the IUnknown 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.
+ if (OriginateLanguageException(e) && TryGetRestrictedErrorInfo(out pRestrictedErrorInfo))
+ {
+ return ExternalInterop.RoReportUnhandledError(pRestrictedErrorInfo) >= 0;
+ }
+#else
+ return false;
+#endif // ENABLE_WINRT
+ }
+ catch (Exception)
+ {
+ // We can't give an exception in this code, so we simply swallow the exception here.
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pRestrictedErrorInfo);
+ }
+ }
+ // If we have got here, then some step of the pInvoke failed, which means the GEH was not invoked
+ return false;
+ }
+
+ internal static Exception AttachRestrictedErrorInfo(Exception e)
+ {
+ // If there is no exception, then the restricted error info doesn't apply to it
+ if (e != null)
+ {
+ System.IntPtr pRestrictedErrorInfo = IntPtr.Zero;
+
+ try
+ {
+ // Get the restricted error info for this thread and see if it may correlate to the current
+ // exception object. Note that in general the thread's IRestrictedErrorInfo is not meant for
+ // exceptions that are marshaled Windows.Foundation.HResults and instead are intended for
+ // HRESULT ABI return values. However, in many cases async APIs will set the thread's restricted
+ // error info as a convention in order to provide extended debugging information for the ErrorCode
+ // property.
+ if (TryGetRestrictedErrorInfo(out pRestrictedErrorInfo))
+ {
+ string description;
+ string restrictedDescription;
+ string capabilitySid;
+ int restrictedErrorInfoHResult;
+ if (RestrictedErrorInfoHelper.GetErrorDetails(
+ pRestrictedErrorInfo,
+ out description,
+ out restrictedErrorInfoHResult,
+ out restrictedDescription,
+ out capabilitySid) && (e.HResult == restrictedErrorInfoHResult))
+ {
+ // Since this is a special case where by convention there may be a correlation, there is not a
+ // guarantee that the restricted error info does belong to the async error code. In order to
+ // reduce the risk that we associate incorrect information with the exception object, we need
+ // to apply a heuristic where we attempt to match the current exception's HRESULT with the
+ // HRESULT the IRestrictedErrorInfo belongs to. If it is a match we will assume association
+ // for the IAsyncInfo case.
+ string errorReference;
+ RestrictedErrorInfoHelper.GetReference(pRestrictedErrorInfo, out errorReference);
+ object restrictedErrorInfo = McgMarshal.ComInterfaceToObject(pRestrictedErrorInfo, McgModuleManager.IRestrictedErrorInfo);
+ InteropExtensions.AddExceptionDataForRestrictedErrorInfo(
+ e,
+ restrictedDescription,
+ errorReference,
+ capabilitySid,
+ restrictedErrorInfo);
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // If we can't get the restricted error info, then proceed as if it isn't associated with this
+ // error.
+ }
+ finally
+ {
+ McgMarshal.ComSafeRelease(pRestrictedErrorInfo);
+ }
+ }
+ return e;
+ }
+ }
+}
diff --git a/src/System.Private.Interop/src/WinRT/Interop.WinRT.cs b/src/System.Private.Interop/src/WinRT/Interop.WinRT.cs
new file mode 100644
index 000000000..523e64f91
--- /dev/null
+++ b/src/System.Private.Interop/src/WinRT/Interop.WinRT.cs
@@ -0,0 +1,94 @@
+// 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.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+
+partial class Interop
+{
+
+ internal unsafe partial class WinRT
+ {
+ // Converts a ASCII (code<0x7f) string to byte array
+ internal static byte[] AsciiStringToByteArray(string ascii)
+ {
+ byte[] ret = new byte[ascii.Length + 1];
+ int index;
+
+ for (index = 0; index < ascii.Length; index++)
+ {
+ ret[index] = (byte)ascii[index];
+ }
+
+ ret[index] = 0;
+
+ return ret;
+ }
+
+ static internal unsafe void RoGetActivationFactory(string className, ref Guid iid, out IntPtr ppv)
+ {
+ fixed (char* unsafe_className = className)
+ {
+ void* hstring_typeName = null;
+
+ HSTRING_HEADER hstringHeader;
+ int hr =
+ WindowsCreateStringReference(
+ unsafe_className, (uint)className.Length, &hstringHeader, &hstring_typeName);
+
+ if (hr < 0)
+ throw Marshal.GetExceptionForHR(hr);
+
+ fixed (Guid* unsafe_iid = &iid)
+ {
+ fixed (void* unsafe_ppv = &ppv)
+ {
+ hr = ExternalInterop.RoGetActivationFactory(
+ hstring_typeName,
+ unsafe_iid,
+ unsafe_ppv);
+
+ if (hr < 0)
+ throw Marshal.GetExceptionForHR(hr);
+ }
+ }
+ }
+ }
+
+ [DllImport(Interop.CORE_WINRT_STRING)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ static internal extern unsafe int WindowsCreateString(char* sourceString, uint length, void* hstring);
+
+ [DllImport(Interop.CORE_WINRT_STRING)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ static internal extern unsafe int WindowsCreateStringReference(
+ char* sourceString, uint length, HSTRING_HEADER* phstringHeader, void* hstring);
+
+ [DllImport(Interop.CORE_WINRT_ERROR, PreserveSig = true)]
+ [McgGeneratedNativeCallCodeAttribute]
+ public static extern int GetRestrictedErrorInfo(out System.IntPtr pRestrictedErrorInfo);
+
+ [DllImport(Interop.CORE_WINRT_ERROR, PreserveSig = true)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern int RoOriginateError(int hr, HSTRING hstring);
+
+ [DllImport(Interop.CORE_WINRT_ERROR, PreserveSig = true)]
+ [McgGeneratedNativeCallCodeAttribute]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static extern int SetRestrictedErrorInfo(System.IntPtr pRestrictedErrorInfo);
+
+ [DllImport(Interop.CORE_WINRT_ERROR1, PreserveSig = true)]
+ [McgGeneratedNativeCallCodeAttribute]
+ static internal extern int RoOriginateLanguageException(int hr, HSTRING message, IntPtr pLanguageException);
+
+ [DllImport(Interop.CORE_WINRT_ERROR1, PreserveSig = true)]
+ [McgGeneratedNativeCallCodeAttribute]
+ internal static extern int RoReportUnhandledError(IntPtr pRestrictedErrorInfo);
+ }
+
+}