From: Luqun Lou Date: Tue, 27 Mar 2018 21:20:09 +0000 (-0700) Subject: Enable reflection load ComImport assembly and Type.IsComObjectType (#16943) X-Git-Tag: accepted/tizen/unified/20190422.045933~2473 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d0833f90ed516b08871635a05c1d5657379b8053;p=platform%2Fupstream%2Fcoreclr.git Enable reflection load ComImport assembly and Type.IsComObjectType (#16943) * Enable reflection load ComImport assembly and Type.IsComObjectType * Update Enable reflection load ComImport assembly --- diff --git a/src/dlls/mscorrc/mscorrc.rc b/src/dlls/mscorrc/mscorrc.rc index 00a068c..61f5c9a 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 0fbbf1c..b8e1b2b 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 dacec45..3812ff1 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 d48163c..630706b 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 6762c80..a689624 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 710a81a..6765623 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 7bc2a83..e88fe16 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 6464e58..c57677b 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 e64b72b..3e267a2 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 723222e..de9505a 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 fc6ee5d..9c21706 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 0000000..d3416dd --- /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 0000000..fba866c --- /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 0000000..1f289d6 --- /dev/null +++ b/tests/src/Interop/ClassicCOM/COMLib.csproj @@ -0,0 +1,32 @@ + + + + + Debug + AnyCPU + COMLib + 2.0 + {5FEE5C46-8DD9-49FA-BDC1-AF22867A0704} + library + {CDC3DF7E-04B4-4464-9A02-7E2B0FAB586A};{68EC03EE-C9EE-47FD-AA08-A954EB2D9816} + ..\..\ + $(DefineConstants);STATIC + + + + + + + + + False + + + + + + + + + + diff --git a/tests/src/Interop/ClassicCOM/COMLib2.cs b/tests/src/Interop/ClassicCOM/COMLib2.cs new file mode 100644 index 0000000..8f0ec78 --- /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 0000000..601b94e --- /dev/null +++ b/tests/src/Interop/ClassicCOM/COMLib2.csproj @@ -0,0 +1,32 @@ + + + + + Debug + AnyCPU + COMLib2 + 2.0 + {C04AB564-CC61-499D-9F4C-AA1A9FDE42C9} + library + {4948E98A-ECFC-4988-851E-68E1ADD2DD5A};{B850CC46-E8FB-4569-A28D-423F81E8A861} + ..\..\ + $(DefineConstants);STATIC + + + + + + + + + False + + + + + + + + + + diff --git a/tests/src/Interop/ClassicCOM/ClassicCOMNative.cpp b/tests/src/Interop/ClassicCOM/ClassicCOMNative.cpp new file mode 100644 index 0000000..962313c --- /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 +#include +#include + +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 0000000..23bac89 --- /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 +{ + /// + /// Try to reflect load ComImport Types by enumerate + /// + /// + 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; + } + } + + /// + /// Try to test Type.IsCOMObject + /// + /// + 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; + } + } + + /// + /// Try to create COM instance + /// + /// + 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); + + /// + /// Try to Marshal COM Type across managed-native boundary + /// + /// + 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; + } + + /// + /// Try to call Marshal API for COM Types + /// + /// + 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 0000000..673e216 --- /dev/null +++ b/tests/src/Interop/ClassicCOM/ClassicCOMUnitTest.csproj @@ -0,0 +1,47 @@ + + + + + Debug + AnyCPU + ClassicCOMUnitTest + 2.0 + {85C57688-DA98-4DE3-AC9B-526E4747434C} + Exe + {209912F9-0DA1-4184-9CC1-8D583BAF4A28};{87799F5D-CEBD-499D-BDBA-B2C6105CD766} + ..\..\ + $(DefineConstants);STATIC + + + + + + + + + False + + + + + + + + + + + {c8c0dc74-fac4-45b1-81fe-70c4808366e0} + CoreCLRTestLibrary + + + {5FEE5C46-8DD9-49FA-BDC1-AF22867A0704} + COMLib + + + {C04AB564-CC61-499D-9F4C-AA1A9FDE42C9} + COMLib + + + + +