Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,12 @@ public BasicClassFactory(Guid clsid, Type classType)
_classType = classType;
}

public static void ValidateInterfaceRequest(Type classType, ref Guid riid, object? outer)
public static Type GetValidatedInterfaceType(Type classType, ref Guid riid, object? outer)
{
Debug.Assert(classType != null);
if (riid == Marshal.IID_IUnknown)
{
return;
return typeof(object);
}

// Aggregation can only be done when requesting IUnknown.
Expand All @@ -251,23 +251,40 @@ public static void ValidateInterfaceRequest(Type classType, ref Guid riid, objec
throw new COMException(string.Empty, CLASS_E_NOAGGREGATION);
}

bool found = false;

// Verify the class implements the desired interface
foreach (Type i in classType.GetInterfaces())
{
if (i.GUID == riid)
{
found = true;
break;
return i;
}
}

if (!found)
// E_NOINTERFACE
throw new InvalidCastException();
}

public static void ValidateObjectIsMarshallableAsInterface(object obj, Type interfaceType)
{
// If the requested "interface type" is type object then return
// because type object is always marshallable.
if (interfaceType == typeof(object))
{
// E_NOINTERFACE
throw new InvalidCastException();
return;
}

Debug.Assert(interfaceType.IsInterface);

// The intent of this call is to validate the interface can be
// marshalled to native code. An exception will be thrown if the
// type is unable to be marshalled to native code.
// Scenarios where this is relevant:
// - Interfaces that use Generics
// - Interfaces that define implementation
IntPtr ptr = Marshal.GetComInterfaceForObject(obj, interfaceType, CustomQueryInterfaceMode.Ignore);

// Decrement the above 'Marshal.GetComInterfaceForObject()'
Marshal.Release(ptr);
}

public static object CreateAggregatedObject(object pUnkOuter, object comObject)
Expand All @@ -283,7 +300,7 @@ public static object CreateAggregatedObject(object pUnkOuter, object comObject)
finally
{
// Decrement the above 'Marshal.GetIUnknownForObject()'
Marshal.ReleaseComObject(pUnkOuter);
Marshal.Release(outerPtr);
}
}

Expand All @@ -292,13 +309,15 @@ public void CreateInstance(
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out object? ppvObject)
{
BasicClassFactory.ValidateInterfaceRequest(_classType, ref riid, pUnkOuter);
Type interfaceType = BasicClassFactory.GetValidatedInterfaceType(_classType, ref riid, pUnkOuter);

ppvObject = Activator.CreateInstance(_classType)!;
if (pUnkOuter != null)
{
ppvObject = BasicClassFactory.CreateAggregatedObject(pUnkOuter, ppvObject);
}

BasicClassFactory.ValidateObjectIsMarshallableAsInterface(ppvObject, interfaceType);
}

public void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock)
Expand Down Expand Up @@ -369,13 +388,15 @@ private void CreateInstanceInner(
bool isDesignTime,
out object ppvObject)
{
BasicClassFactory.ValidateInterfaceRequest(_classType, ref riid, pUnkOuter);
Type interfaceType = BasicClassFactory.GetValidatedInterfaceType(_classType, ref riid, pUnkOuter);

ppvObject = _licenseProxy.AllocateAndValidateLicense(_classType, key, isDesignTime);
if (pUnkOuter != null)
{
ppvObject = BasicClassFactory.CreateAggregatedObject(pUnkOuter, ppvObject);
}

BasicClassFactory.ValidateObjectIsMarshallableAsInterface(ppvObject, interfaceType);
}
}
}
Expand Down Expand Up @@ -567,12 +588,12 @@ public void GetCurrentContextInfo(RuntimeTypeHandle rth, out bool isDesignTime,

// Types are as follows:
// Type, out bool, out string -> LicenseContext
var parameters = new object[] { targetRcwTypeMaybe, /* out */ null!, /* out */ null! };
var parameters = new object?[] { targetRcwTypeMaybe, /* out */ null, /* out */ null };
_licContext = _getCurrentContextInfo.Invoke(null, BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameters, culture: null);

_targetRcwType = targetRcwTypeMaybe;
isDesignTime = (bool)parameters[1];
bstrKey = Marshal.StringToBSTR((string?)parameters[2]);
isDesignTime = (bool)parameters[1]!;
bstrKey = Marshal.StringToBSTR((string)parameters[2]!);
}

// The CLR invokes this when instantiating a licensed COM
Expand Down
3 changes: 2 additions & 1 deletion src/dlls/mscorrc/mscorrc.rc
Original file line number Diff line number Diff line change
Expand Up @@ -913,8 +913,9 @@ BEGIN

IDS_EE_COM_INVISIBLE_PARENT "Type '%1' has a ComVisible(false) parent '%2' in its hierarchy, therefore QueryInterface calls for IDispatch or class interfaces are disallowed."

IDS_EE_COMIMPORT_METHOD_NO_INTERFACE "Method '%1' in ComImport class '%2' must implement an interface method."
IDS_EE_ATTEMPT_TO_CREATE_GENERIC_CCW "Generic types cannot be marshaled to COM interface pointers."
IDS_EE_ATTEMPT_TO_CREATE_NON_ABSTRACT_CCW "Types with non-abstract methods cannot be marshaled to COM interface pointers."
IDS_EE_COMIMPORT_METHOD_NO_INTERFACE "Method '%1' in ComImport class '%2' must implement an interface method."

IDS_CLASSLOAD_BAD_METHOD_COUNT "Metadata method count does not match method enumeration length for type '%1' from assembly '%2'."
IDS_CLASSLOAD_BAD_FIELD_COUNT "Metadata field count does not match field enumeration length for type '%1' from assembly '%2'."
Expand Down
2 changes: 1 addition & 1 deletion src/dlls/mscorrc/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@

#define IDS_EE_PROFILING_FAILURE 0x1aa8
#define IDS_EE_ATTEMPT_TO_CREATE_GENERIC_CCW 0x1aa9

#define IDS_EE_ATTEMPT_TO_CREATE_NON_ABSTRACT_CCW 0x1aaa
#define IDS_EE_COMIMPORT_METHOD_NO_INTERFACE 0x1aab
#define IDS_EE_OUT_OF_MEMORY_WITHIN_RANGE 0x1aac
#define IDS_EE_ARRAY_DIMENSIONS_EXCEEDED 0x1aad
Expand Down
14 changes: 13 additions & 1 deletion src/vm/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,11 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW!
LIMITED_METHOD_CONTRACT;
m_VMFlags |= (DWORD) VMFLAG_FIXED_ADDRESS_VT_STATICS;
}
void SetHasOnlyAbstractMethods()
{
LIMITED_METHOD_CONTRACT;
m_VMFlags |= (DWORD) VMFLAG_ONLY_ABSTRACT_METHODS;
}
#ifdef FEATURE_COMINTEROP
void SetSparseForCOMInterop()
{
Expand Down Expand Up @@ -1445,6 +1450,13 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW!
LIMITED_METHOD_CONTRACT;
return m_VMFlags & VMFLAG_FIXED_ADDRESS_VT_STATICS;
}

BOOL HasOnlyAbstractMethods()
{
LIMITED_METHOD_CONTRACT;
return m_VMFlags & VMFLAG_ONLY_ABSTRACT_METHODS;
}

#ifdef FEATURE_COMINTEROP
BOOL IsSparseForCOMInterop()
{
Expand Down Expand Up @@ -1874,7 +1886,7 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW!
// unused = 0x00080000,
VMFLAG_CONTAINS_STACK_PTR = 0x00100000,
VMFLAG_PREFER_ALIGN8 = 0x00200000, // Would like to have 8-byte alignment
// unused = 0x00400000,
VMFLAG_ONLY_ABSTRACT_METHODS = 0x00400000, // Type only contains abstract methods

#ifdef FEATURE_COMINTEROP
VMFLAG_SPARSE_FOR_COMINTEROP = 0x00800000,
Expand Down
Loading