summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dlls/mscorrc/mscorrc.rc1
-rw-r--r--src/dlls/mscorrc/resource.h1
-rw-r--r--src/vm/ecall.cpp12
-rw-r--r--src/vm/interoputil.cpp97
-rw-r--r--src/vm/interoputil.h16
-rw-r--r--src/vm/methodtable.cpp4
-rw-r--r--src/vm/methodtable.h24
-rw-r--r--src/vm/methodtablebuilder.cpp26
-rw-r--r--src/vm/methodtablebuilder.h3
-rw-r--r--src/vm/runtimehandles.cpp12
-rw-r--r--tests/src/Interop/CMakeLists.txt1
-rw-r--r--tests/src/Interop/ClassicCOM/CMakeLists.txt13
-rw-r--r--tests/src/Interop/ClassicCOM/COMLib.cs34
-rw-r--r--tests/src/Interop/ClassicCOM/COMLib.csproj32
-rw-r--r--tests/src/Interop/ClassicCOM/COMLib2.cs34
-rw-r--r--tests/src/Interop/ClassicCOM/COMLib2.csproj32
-rw-r--r--tests/src/Interop/ClassicCOM/ClassicCOMNative.cpp28
-rw-r--r--tests/src/Interop/ClassicCOM/ClassicCOMUnitTest.cs245
-rw-r--r--tests/src/Interop/ClassicCOM/ClassicCOMUnitTest.csproj47
19 files changed, 555 insertions, 107 deletions
diff --git a/src/dlls/mscorrc/mscorrc.rc b/src/dlls/mscorrc/mscorrc.rc
index 00a068c9b1..61f5c9af1b 100644
--- a/src/dlls/mscorrc/mscorrc.rc
+++ b/src/dlls/mscorrc/mscorrc.rc
@@ -2065,6 +2065,7 @@ BEGIN
IDS_EE_BADMARSHAL_TYPE_ASANYA "Marshalling arbitrary types is not supported"
IDS_EE_BADMARSHAL_TYPE_IDISPATCH "Marshalling as IDispatch is not supported"
IDS_EE_ERROR_IDISPATCH "IDispatch and IDispatchEx are not supported"
+ IDS_EE_ERROR_COM "COM is not supported"
END
STRINGTABLE DISCARDABLE
diff --git a/src/dlls/mscorrc/resource.h b/src/dlls/mscorrc/resource.h
index 0fbbf1ce1a..b8e1b2b2a9 100644
--- a/src/dlls/mscorrc/resource.h
+++ b/src/dlls/mscorrc/resource.h
@@ -897,3 +897,4 @@
#define IDS_EE_NDIRECT_LOADLIB_LINUX 0x263e
#define IDS_EE_NDIRECT_LOADLIB_MAC 0x263f
#define IDS_EE_NDIRECT_GETPROCADDRESS_UNIX 0x2640
+#define IDS_EE_ERROR_COM 0x2641
diff --git a/src/vm/ecall.cpp b/src/vm/ecall.cpp
index dacec45787..3812ff1030 100644
--- a/src/vm/ecall.cpp
+++ b/src/vm/ecall.cpp
@@ -320,10 +320,14 @@ PCODE ECall::GetFCallImpl(MethodDesc * pMD, BOOL * pfSharedOrDynamicFCallImpl /*
return GetFCallImpl(MscorlibBinder::GetMethod(METHOD__DELEGATE__CONSTRUCT_DELEGATE));
}
-#ifdef FEATURE_COMINTEROP
// COM imported classes have special constructors
- if (pMT->IsComObjectType() && pMT != g_pBaseCOMObject && pMT != g_pBaseRuntimeClass)
+ if (pMT->IsComObjectType()
+#ifdef FEATURE_COMINTEROP
+ && pMT != g_pBaseCOMObject && pMT != g_pBaseRuntimeClass
+#endif // FEATURE_COMINTEROP
+ )
{
+#ifdef FEATURE_COMINTEROP
if (pfSharedOrDynamicFCallImpl)
*pfSharedOrDynamicFCallImpl = TRUE;
@@ -333,8 +337,10 @@ PCODE ECall::GetFCallImpl(MethodDesc * pMD, BOOL * pfSharedOrDynamicFCallImpl /*
// FCComCtor does not need to be in the fcall hashtable since it does not erect frame.
return GetEEFuncEntryPoint(FCComCtor);
- }
+#else
+ COMPlusThrow(kPlatformNotSupportedException, IDS_EE_ERROR_COM);
#endif // FEATURE_COMINTEROP
+ }
if (!pMD->GetModule()->IsSystem())
COMPlusThrow(kSecurityException, BFA_ECALLS_MUST_BE_IN_SYS_MOD);
diff --git a/src/vm/interoputil.cpp b/src/vm/interoputil.cpp
index d48163c075..630706bfc7 100644
--- a/src/vm/interoputil.cpp
+++ b/src/vm/interoputil.cpp
@@ -999,6 +999,7 @@ void GetCultureInfoForLCID(LCID lcid, OBJECTREF *pCultureObj)
COMPlusThrow(kNotSupportedException);
#endif
}
+
#endif // CROSSGEN_COMPILE
//---------------------------------------------------------------------------
@@ -1618,6 +1619,55 @@ BOOL CanCastComObject(OBJECTREF obj, MethodTable * pTargetMT)
}
}
+// Returns TRUE iff the argument represents the "__ComObject" type or
+// any type derived from it (i.e. typelib-imported RCWs).
+BOOL IsComWrapperClass(TypeHandle type)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ MethodTable* pMT = type.GetMethodTable();
+ if (pMT == NULL)
+ return FALSE;
+
+ return pMT->IsComObjectType();
+}
+
+// Returns TRUE iff the argument represents the "__ComObject" type.
+BOOL IsComObjectClass(TypeHandle type)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+#ifdef FEATURE_COMINTEROP
+ if (!type.IsTypeDesc())
+ {
+ MethodTable *pMT = type.AsMethodTable();
+
+ if (pMT->IsComObjectType())
+ {
+ // May be __ComObject or typed RCW. __ComObject must have already been loaded
+ // if we see an MT marked like this so calling the *NoInit method is sufficient.
+
+ return pMT == g_pBaseCOMObject;
+ }
+ }
+#endif
+
+ return FALSE;
+}
+
VOID
ReadBestFitCustomAttribute(MethodDesc* pMD, BOOL* BestFit, BOOL* ThrowOnUnmappableChar)
{
@@ -6204,53 +6254,6 @@ MethodTable *WinRTDelegateRedirector::GetWinRTTypeForRedirectedDelegateIndex(Win
}
}
-// Returns TRUE iff the argument represents the "__ComObject" type or
-// any type derived from it (i.e. typelib-imported RCWs).
-BOOL IsComWrapperClass(TypeHandle type)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- MethodTable* pMT = type.GetMethodTable();
- if (pMT == NULL)
- return FALSE;
-
- return pMT->IsComObjectType();
-}
-
-// Returns TRUE iff the argument represents the "__ComObject" type.
-BOOL IsComObjectClass(TypeHandle type)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- if (!type.IsTypeDesc())
- {
- MethodTable *pMT = type.AsMethodTable();
-
- if (pMT->IsComObjectType())
- {
- // May be __ComObject or typed RCW. __ComObject must have already been loaded
- // if we see an MT marked like this so calling the *NoInit method is sufficient.
- return (pMT == g_pBaseCOMObject);
- }
- }
-
- return FALSE;
-}
-
-
#ifndef CROSSGEN_COMPILE
#ifdef _DEBUG
diff --git a/src/vm/interoputil.h b/src/vm/interoputil.h
index 6762c80f92..a6896248c6 100644
--- a/src/vm/interoputil.h
+++ b/src/vm/interoputil.h
@@ -106,6 +106,13 @@ ULONG SafeReleasePreemp(IUnknown* pUnk, RCW* pRCW = NULL);
// Determines if a COM object can be cast to the specified type.
BOOL CanCastComObject(OBJECTREF obj, MethodTable * pTargetMT);
+// includes Types which hold a "ComObject" class
+// and types which are imported through typelib
+BOOL IsComWrapperClass(TypeHandle type);
+
+// includes Type which hold a "__ComObject" class
+BOOL IsComObjectClass(TypeHandle type);
+
//---------------------------------------------------------
// Read the BestFit custom attribute info from
// both assembly level and interface level
@@ -491,14 +498,6 @@ public:
static void ComputeGuidForGenericType(MethodTable *pMT, GUID *pGuid);
}; // class WinRTGuidGenerator
-
-// includes Types which hold a "ComObject" class
-// and types which are imported through typelib
-BOOL IsComWrapperClass(TypeHandle type);
-
-// includes Type which hold a "__ComObject" class
-BOOL IsComObjectClass(TypeHandle type);
-
IUnknown* MarshalObjectToInterface(OBJECTREF* ppObject, MethodTable* pItfMT, MethodTable* pClassMT, DWORD dwFlags);
void UnmarshalObjectFromInterface(OBJECTREF *ppObjectDest, IUnknown **ppUnkSrc, MethodTable *pItfMT, MethodTable *pClassMT, DWORD dwFlags);
@@ -508,7 +507,6 @@ class ICOMInterfaceMarshalerCallback;
void GetNativeWinRTFactoryObject(MethodTable *pMT, Thread *pThread, MethodTable *pFactoryIntfMT, BOOL bNeedUniqueRCW, ICOMInterfaceMarshalerCallback *pCallback, OBJECTREF *prefFactory);
#else // FEATURE_COMINTEROP
-
inline HRESULT EnsureComStartedNoThrow()
{
LIMITED_METHOD_CONTRACT;
diff --git a/src/vm/methodtable.cpp b/src/vm/methodtable.cpp
index 710a81abf4..67656235ef 100644
--- a/src/vm/methodtable.cpp
+++ b/src/vm/methodtable.cpp
@@ -602,8 +602,6 @@ void MethodTable::SetIsRestored()
#endif
}
-#ifdef FEATURE_COMINTEROP
-
//==========================================================================================
// mark as COM object type (System.__ComObject and types deriving from it)
void MethodTable::SetComObjectType()
@@ -612,8 +610,6 @@ void MethodTable::SetComObjectType()
SetFlag(enum_flag_ComObject);
}
-#endif // FEATURE_COMINTEROP
-
#if defined(FEATURE_TYPEEQUIVALENCE)
void MethodTable::SetHasTypeEquivalence()
{
diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h
index 7bc2a83c54..e88fe16644 100644
--- a/src/vm/methodtable.h
+++ b/src/vm/methodtable.h
@@ -882,9 +882,6 @@ public:
BOOL IsExtensibleRCW();
- // mark the class type as COM object class
- void SetComObjectType();
-
#if defined(FEATURE_TYPEEQUIVALENCE)
// mark the type as opted into type equivalence
void SetHasTypeEquivalence();
@@ -894,12 +891,6 @@ public:
// the hierarchy
MethodTable* GetComPlusParentMethodTable();
- // class is a com object class
- BOOL IsComObjectType()
- {
- LIMITED_METHOD_DAC_CONTRACT;
- return GetFlag(enum_flag_ComObject);
- }
// class is a WinRT object class (is itself or derives from a ProjectedFromWinRT class)
BOOL IsWinRTObjectType();
@@ -943,11 +934,6 @@ public:
InteropMethodTableData *GetComInteropData();
#else // !FEATURE_COMINTEROP
- BOOL IsComObjectType()
- {
- SUPPORTS_DAC;
- return FALSE;
- }
BOOL IsWinRTObjectType()
{
LIMITED_METHOD_CONTRACT;
@@ -955,6 +941,16 @@ public:
}
#endif // !FEATURE_COMINTEROP
+ // class is a com object class
+ BOOL IsComObjectType()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_ComObject);
+ }
+
+ // mark the class type as COM object class
+ void SetComObjectType();
+
#ifdef FEATURE_ICASTABLE
void SetICastable();
#endif
diff --git a/src/vm/methodtablebuilder.cpp b/src/vm/methodtablebuilder.cpp
index 6464e5849e..c57677b316 100644
--- a/src/vm/methodtablebuilder.cpp
+++ b/src/vm/methodtablebuilder.cpp
@@ -1536,12 +1536,11 @@ MethodTableBuilder::BuildMethodTableThrowing(
}
}
-#ifdef FEATURE_COMINTEROP
-
// Com Import classes are special. These types must derive from System.Object,
// and we then substitute the parent with System._ComObject.
if (IsComImport() && !IsEnum() && !IsInterface() && !IsValueClass() && !IsDelegate())
{
+#ifdef FEATURE_COMINTEROP
// ComImport classes must either extend from Object or be a WinRT class
// that extends from another WinRT class (and so form a chain of WinRT classes
// that ultimately extend from object).
@@ -1579,11 +1578,12 @@ MethodTableBuilder::BuildMethodTableThrowing(
bmtInternal->pType->SetParentType(CreateTypeChain(pCOMMT, Substitution()));
bmtInternal->pParentMT = pCOMMT;
}
-
+#endif
// if the current class is imported
bmtProp->fIsComObjectType = true;
}
+#ifdef FEATURE_COMINTEROP
if (GetHalfBakedClass()->IsProjectedFromWinRT() && IsValueClass() && !IsEnum())
{
// WinRT structures must have sequential layout
@@ -2865,12 +2865,10 @@ MethodTableBuilder::EnumerateClassMethods()
// RVA : 0
if (dwMethodRVA != 0)
{
-#ifdef FEATURE_COMINTEROP
if(fIsClassComImport)
{
BuildMethodTableThrowException(BFA_METHOD_WITH_NONZERO_RVA);
}
-#endif // FEATURE_COMINTEROP
if(IsMdAbstract(dwMemberAttrs))
{
BuildMethodTableThrowException(BFA_ABSTRACT_METHOD_WITH_RVA);
@@ -3066,14 +3064,12 @@ MethodTableBuilder::EnumerateClassMethods()
// The attribute is not present
if (hr == S_FALSE)
{
+#ifdef FEATURE_COMINTEROP
if (fIsClassComImport
-#ifdef FEATURE_COMINTEROP
|| GetHalfBakedClass()->IsProjectedFromWinRT()
|| bmtProp->fComEventItfType
-#endif //FEATURE_COMINTEROP
)
{
-#ifdef FEATURE_COMINTEROP
// ComImport classes have methods which are just used
// for implementing all interfaces the class supports
type = METHOD_TYPE_COMINTEROP;
@@ -3090,13 +3086,10 @@ MethodTableBuilder::EnumerateClassMethods()
type = METHOD_TYPE_FCALL;
}
}
-#else
- //If we don't support com interop, refuse to load interop methods. Otherwise we fail to
- //jit calls to them since the constuctor has no intrinsic ID.
- BuildMethodTableThrowException(hr, IDS_CLASSLOAD_GENERAL, tok);
-#endif // FEATURE_COMINTEROP
}
- else if (dwMethodRVA == 0)
+ else
+#endif //FEATURE_COMINTEROP
+ if (dwMethodRVA == 0)
{
type = METHOD_TYPE_FCALL;
}
@@ -10322,16 +10315,17 @@ MethodTableBuilder::SetupMethodTable2(
GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes);
-#ifdef FEATURE_COMINTEROP
if (bmtProp->fIsComObjectType)
{ // Propagate the com specific info
pMT->SetComObjectType();
-
+#ifdef FEATURE_COMINTEROP
// COM objects need an optional field on the EEClass, so ensure this class instance has allocated
// the optional field descriptor.
EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
+#endif // FEATURE_COMINTEROP
}
+#ifdef FEATURE_COMINTEROP
if (pMT->GetAssembly()->IsManagedWinMD())
{
// We need to mark classes that are implementations of managed WinRT runtime classes with
diff --git a/src/vm/methodtablebuilder.h b/src/vm/methodtablebuilder.h
index e64b72bb9d..3e267a2b23 100644
--- a/src/vm/methodtablebuilder.h
+++ b/src/vm/methodtablebuilder.h
@@ -1316,10 +1316,9 @@ private:
bool fNoSanityChecks;
bool fSparse; // Set to true if a sparse interface is being used.
-#ifdef FEATURE_COMINTEROP
// Com Interop, ComWrapper classes extend from ComObject
bool fIsComObjectType; // whether this class is an instance of ComObject class
-
+#ifdef FEATURE_COMINTEROP
bool fIsMngStandardItf; // Set to true if the interface is a manages standard interface.
bool fComEventItfType; // Set to true if the class is a special COM event interface.
bool fIsRedirectedInterface; // Set to true if the class is an interface redirected for WinRT
diff --git a/src/vm/runtimehandles.cpp b/src/vm/runtimehandles.cpp
index 723222e55b..de9505ae91 100644
--- a/src/vm/runtimehandles.cpp
+++ b/src/vm/runtimehandles.cpp
@@ -1012,7 +1012,6 @@ RuntimeTypeHandle::IsVisible(
} // RuntimeTypeHandle::IsVisible
FCIMPL2(FC_BOOL_RET, RuntimeTypeHandle::IsComObject, ReflectClassBaseObject *pTypeUNSAFE, CLR_BOOL isGenericCOM) {
-#ifdef FEATURE_COMINTEROP
CONTRACTL {
FCALL_CHECK;
}
@@ -1037,17 +1036,6 @@ FCIMPL2(FC_BOOL_RET, RuntimeTypeHandle::IsComObject, ReflectClassBaseObject *pTy
HELPER_METHOD_FRAME_END();
FC_RETURN_BOOL(ret);
-#else
- CONTRACTL {
- DISABLED(NOTHROW);
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pTypeUNSAFE));
- }
- CONTRACTL_END;
- FCUnique(0x37);
- FC_RETURN_BOOL(FALSE);
-#endif
}
FCIMPLEND
diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt
index fc6ee5d2e6..9c217063f2 100644
--- a/tests/src/Interop/CMakeLists.txt
+++ b/tests/src/Interop/CMakeLists.txt
@@ -26,3 +26,4 @@ add_subdirectory(StringMarshalling/UTF8)
add_subdirectory(MarshalAPI/FunctionPointer)
add_subdirectory(MarshalAPI/IUnknown)
add_subdirectory(SizeConst)
+add_subdirectory(ClassicCOM) \ No newline at end of file
diff --git a/tests/src/Interop/ClassicCOM/CMakeLists.txt b/tests/src/Interop/ClassicCOM/CMakeLists.txt
new file mode 100644
index 0000000000..d3416dd584
--- /dev/null
+++ b/tests/src/Interop/ClassicCOM/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required (VERSION 2.6)
+project (ClassicCOMNative)
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES ClassicCOMNative.cpp)
+
+# add the executable
+add_library (ClassicCOMNative SHARED ${SOURCES})
+target_link_libraries(ClassicCOMNative ${LINK_LIBRARIES_ADDITIONAL})
+
+# add the install targets
+install (TARGETS ClassicCOMNative DESTINATION bin)
+
+
diff --git a/tests/src/Interop/ClassicCOM/COMLib.cs b/tests/src/Interop/ClassicCOM/COMLib.cs
new file mode 100644
index 0000000000..fba866c567
--- /dev/null
+++ b/tests/src/Interop/ClassicCOM/COMLib.cs
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Text;
+using System.Security;
+using System.Runtime.InteropServices;
+
+public class COMLib
+{
+ [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();
+ }
+
+ [ComImport]
+ [Guid("78A51822-51F4-11D0-8F20-00805F2CD064")]
+ public class ProcessDebugManager
+ {
+ }
+}
diff --git a/tests/src/Interop/ClassicCOM/COMLib.csproj b/tests/src/Interop/ClassicCOM/COMLib.csproj
new file mode 100644
index 0000000000..1f289d6729
--- /dev/null
+++ b/tests/src/Interop/ClassicCOM/COMLib.csproj
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>COMLib</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{5FEE5C46-8DD9-49FA-BDC1-AF22867A0704}</ProjectGuid>
+ <OutputType>library</OutputType>
+ <ProjectTypeGuids>{CDC3DF7E-04B4-4464-9A02-7E2B0FAB586A};{68EC03EE-C9EE-47FD-AA08-A954EB2D9816}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="COMLib.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/ClassicCOM/COMLib2.cs b/tests/src/Interop/ClassicCOM/COMLib2.cs
new file mode 100644
index 0000000000..8f0ec78c4d
--- /dev/null
+++ b/tests/src/Interop/ClassicCOM/COMLib2.cs
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Text;
+using System.Security;
+using System.Runtime.InteropServices;
+
+namespace COMLib2
+{
+ [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();
+ }
+
+ [ComImport]
+ [Guid("09799AFB-AD67-11d1-ABCD-00C04FC30936")]
+ public class ContextMenu
+ {
+ }
+}
diff --git a/tests/src/Interop/ClassicCOM/COMLib2.csproj b/tests/src/Interop/ClassicCOM/COMLib2.csproj
new file mode 100644
index 0000000000..601b94ecf9
--- /dev/null
+++ b/tests/src/Interop/ClassicCOM/COMLib2.csproj
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>COMLib2</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{C04AB564-CC61-499D-9F4C-AA1A9FDE42C9}</ProjectGuid>
+ <OutputType>library</OutputType>
+ <ProjectTypeGuids>{4948E98A-ECFC-4988-851E-68E1ADD2DD5A};{B850CC46-E8FB-4569-A28D-423F81E8A861}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="COMLib2.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/ClassicCOM/ClassicCOMNative.cpp b/tests/src/Interop/ClassicCOM/ClassicCOMNative.cpp
new file mode 100644
index 0000000000..962313c229
--- /dev/null
+++ b/tests/src/Interop/ClassicCOM/ClassicCOMNative.cpp
@@ -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.
+//
+
+#include <xplatform.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C" DLL_EXPORT void PassObjectToNative(void * ptr)
+{
+ // TODO: Add check
+}
+
+extern "C" DLL_EXPORT void PassObjectArrayToNative(void ** pptr)
+{
+ // TODO: Add check
+}
+
+extern "C" DLL_EXPORT void GetObjectFromNative(void ** pptr)
+{
+ *pptr = NULL;
+ // TODO: Add check
+}
+
+extern "C" DLL_EXPORT void GetObjectFromNativeAsRef(void ** pptr)
+{
+ // TODO: Add check
+} \ No newline at end of file
diff --git a/tests/src/Interop/ClassicCOM/ClassicCOMUnitTest.cs b/tests/src/Interop/ClassicCOM/ClassicCOMUnitTest.cs
new file mode 100644
index 0000000000..23bac89fbb
--- /dev/null
+++ b/tests/src/Interop/ClassicCOM/ClassicCOMUnitTest.cs
@@ -0,0 +1,245 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// Adding tests for Classic COM code coverage
+//
+
+using System;
+using System.Text;
+using System.Security;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using TestLibrary;
+
+public class ClassicCOMUnitTest
+{
+ /// <summary>
+ /// Try to reflect load ComImport Types by enumerate
+ /// </summary>
+ /// <returns></returns>
+ static bool RelectionLoad()
+ {
+ try
+ {
+ Console.WriteLine("Scenario: RelectionLoad");
+ var asm = Assembly.LoadFrom("COMLib.dll");
+ foreach (Type t in asm.GetTypes())
+ {
+ Console.WriteLine(t.Name);
+ }
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Caught unexpected exception: " + e);
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Try to test Type.IsCOMObject
+ /// </summary>
+ /// <returns></returns>
+ static bool TypeIsComObject()
+ {
+ try
+ {
+ Console.WriteLine("Scenario: TypeIsComObject");
+ Type classType = typeof(COMLib2.ContextMenu);
+ if (!classType.IsCOMObject)
+ {
+ Console.WriteLine("ComImport Class's IsCOMObject should return true");
+ return false;
+ }
+
+ Type interfaceType = typeof(COMLib2.IEnumVARIANT);
+ if (interfaceType.IsCOMObject)
+ {
+ Console.WriteLine("ComImport interface's IsCOMObject should return false");
+ return false;
+ }
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Caught unexpected exception: " + e);
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Try to create COM instance
+ /// </summary>
+ /// <returns></returns>
+ static bool AcivateCOMType()
+ {
+ try
+ {
+ Console.WriteLine("Scenario: AcivateCOMType");
+ COMLib2.ContextMenu contextMenu = (COMLib2.ContextMenu)Activator.CreateInstance(typeof(COMLib2.ContextMenu));
+
+ // Linux should throw PlatformNotSupportedException
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return false;
+ }
+
+ if (contextMenu == null)
+ {
+ Console.WriteLine("AcivateCOMType failed");
+ return false;
+ }
+
+ return true;
+ }
+ catch (System.Reflection.TargetInvocationException e)
+ {
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && e.InnerException is PlatformNotSupportedException)
+ {
+ return true;
+ }
+
+ Console.WriteLine("Caught unexpected PlatformNotSupportedException: " + e);
+ return false;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Caught unexpected exception: " + e);
+ return false;
+ }
+ }
+
+ [DllImport("ClassicCOMNative.dll")]
+ extern static void PassObjectToNative([In, MarshalAs( UnmanagedType.Interface)] object o);
+
+ [DllImport("ClassicCOMNative.dll")]
+ extern static void PassObjectArrayToNative([In,Out] object[] o);
+
+ [DllImport("ClassicCOMNative.dll")]
+ extern static void GetObjectFromNative(out object o);
+
+ [DllImport("ClassicCOMNative.dll")]
+ extern static void GetObjectFromNativeAsRef(ref object o);
+
+ /// <summary>
+ /// Try to Marshal COM Type across managed-native boundary
+ /// </summary>
+ /// <returns></returns>
+ static bool MarshalCOMType()
+ {
+ Console.WriteLine("Scenario: MarshalCOMType");
+ try
+ {
+ object o = new object();
+ PassObjectToNative(o);
+ }
+ catch (System.Runtime.InteropServices.MarshalDirectiveException e)
+ {
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return true;
+ }
+ Console.WriteLine("Caught unexpected MarshalDirectiveException: " + e);
+ return false;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Caught unexpected exception in PassObjectToNative: " + e);
+ return false;
+ }
+
+ try
+ {
+ object [] oa = new object[2];
+ PassObjectArrayToNative(oa);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Caught unexpected exception in GetObjectFromNative: " + e);
+ return false;
+ }
+
+
+ try
+ {
+ object o;
+ GetObjectFromNative(out o);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Caught unexpected exception in GetObjectFromNative: " + e);
+ return false;
+ }
+
+ try
+ {
+ object o = new object();
+ GetObjectFromNativeAsRef(ref o);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Caught unexpected exception in GetObjectFromNativeAsRef: " + e);
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Try to call Marshal API for COM Types
+ /// </summary>
+ /// <returns></returns>
+ static bool MarshalAPI()
+ {
+ Console.WriteLine("Scenario: MarshalAPI");
+ // MarshalAPI
+ if (Marshal.AreComObjectsAvailableForCleanup())
+ {
+ Console.WriteLine("AreComObjectsAvailableForCleanup should return false");
+ return false;
+ }
+ return true;
+ }
+
+ [System.Security.SecuritySafeCritical]
+ static int Main()
+ {
+ int failures = 0;
+ if (!RelectionLoad())
+ {
+ Console.WriteLine("RelectionLoad Failed");
+ failures++;
+ }
+
+ if (!TypeIsComObject())
+ {
+ Console.WriteLine("TypeIsComObject Failed");
+ failures++;
+ }
+
+ if (!AcivateCOMType())
+ {
+ Console.WriteLine("AcivateCOMType Failed");
+ failures++;
+ }
+
+ if (!MarshalCOMType())
+ {
+ Console.WriteLine("MarshalCOMType Failed");
+ failures++;
+ }
+
+ if (!MarshalAPI())
+ {
+ Console.WriteLine("MarshalAPI Failed");
+ failures++;
+ }
+
+ return failures > 0 ? 101 : 100;
+ }
+}
diff --git a/tests/src/Interop/ClassicCOM/ClassicCOMUnitTest.csproj b/tests/src/Interop/ClassicCOM/ClassicCOMUnitTest.csproj
new file mode 100644
index 0000000000..673e216fe9
--- /dev/null
+++ b/tests/src/Interop/ClassicCOM/ClassicCOMUnitTest.csproj
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>ClassicCOMUnitTest</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{85C57688-DA98-4DE3-AC9B-526E4747434C}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{209912F9-0DA1-4184-9CC1-8D583BAF4A28};{87799F5D-CEBD-499D-BDBA-B2C6105CD766}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="ClassicCOMUnitTest.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj">
+ <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project>
+ <Name>CoreCLRTestLibrary</Name>
+ </ProjectReference>
+ <ProjectReference Include="COMLib.csproj">
+ <Project>{5FEE5C46-8DD9-49FA-BDC1-AF22867A0704}</Project>
+ <Name>COMLib</Name>
+ </ProjectReference>
+ <ProjectReference Include="COMLib2.csproj">
+ <Project>{C04AB564-CC61-499D-9F4C-AA1A9FDE42C9}</Project>
+ <Name>COMLib</Name>
+ </ProjectReference>
+ <ProjectReference Include="CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>