Skip to content
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
24 changes: 9 additions & 15 deletions src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1351,26 +1351,20 @@ internal static void DestroyCleanupList(ref CleanupWorkListElement? pCleanupWork

internal static Exception GetHRExceptionObject(int hr)
{
Exception? ex = null;
GetHRExceptionObject(hr, ObjectHandleOnStack.Create(ref ex));
ex!.InternalPreserveStackTrace();
return ex!;
Exception ex = Marshal.GetExceptionForHR(hr)!;
ex.InternalPreserveStackTrace();
return ex;
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "StubHelpers_GetHRExceptionObject")]
private static partial void GetHRExceptionObject(int hr, ObjectHandleOnStack throwable);

#if FEATURE_COMINTEROP
internal static Exception GetCOMHRExceptionObject(int hr, IntPtr pCPCMD, object pThis)
internal static Exception GetCOMHRExceptionObject(int hr, IntPtr pCPCMD, IntPtr pUnk)
{
Exception? ex = null;
GetCOMHRExceptionObject(hr, pCPCMD, ObjectHandleOnStack.Create(ref pThis), ObjectHandleOnStack.Create(ref ex));
ex!.InternalPreserveStackTrace();
return ex!;
RuntimeMethodHandle handle = RuntimeMethodHandle.FromIntPtr(pCPCMD);
RuntimeType declaringType = RuntimeMethodHandle.GetDeclaringType(handle.GetMethodInfo());
Exception ex = Marshal.GetExceptionForHR(hr, declaringType.GUID, pUnk)!;
ex.InternalPreserveStackTrace();
return ex;
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "StubHelpers_GetCOMHRExceptionObject")]
private static partial void GetCOMHRExceptionObject(int hr, IntPtr pCPCMD, ObjectHandleOnStack pThis, ObjectHandleOnStack throwable);
#endif // FEATURE_COMINTEROP

[ThreadStatic]
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -1039,7 +1039,7 @@ DEFINE_METHOD(BUFFER, MEMCOPYGC, BulkMoveWithWriteBar
DEFINE_CLASS(STUBHELPERS, StubHelpers, StubHelpers)
DEFINE_METHOD(STUBHELPERS, GET_DELEGATE_TARGET, GetDelegateTarget, SM_Delegate_RetIntPtr)
#ifdef FEATURE_COMINTEROP
DEFINE_METHOD(STUBHELPERS, GET_COM_HR_EXCEPTION_OBJECT, GetCOMHRExceptionObject, SM_Int_IntPtr_Obj_RetException)
DEFINE_METHOD(STUBHELPERS, GET_COM_HR_EXCEPTION_OBJECT, GetCOMHRExceptionObject, SM_Int_IntPtr_IntPtr_RetException)
DEFINE_METHOD(STUBHELPERS, GET_COM_IP_FROM_RCW, GetCOMIPFromRCW, SM_Obj_IntPtr_RefIntPtr_RefBool_RetIntPtr)
#endif // FEATURE_COMINTEROP
DEFINE_METHOD(STUBHELPERS, SET_LAST_ERROR, SetLastError, SM_RetVoid)
Expand Down
13 changes: 4 additions & 9 deletions src/coreclr/vm/dllimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,14 +736,9 @@ class ILStubState : public StubState
#ifdef FEATURE_COMINTEROP
if (SF_IsForwardCOMStub(m_dwStubFlags))
{
// Make sure that the RCW stays alive for the duration of the call. Note that if we do HRESULT
// swapping, we'll pass 'this' to GetCOMHRExceptionObject after returning from the target so
// GC.KeepAlive is not necessary.
if (!SF_IsHRESULTSwapping(m_dwStubFlags))
{
m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
pcsDispatch->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
}
// Make sure that the RCW stays alive for the duration of the call.
m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
pcsDispatch->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
}
#endif // FEATURE_COMINTEROP

Expand All @@ -761,7 +756,7 @@ class ILStubState : public StubState
if (SF_IsCOMStub(m_dwStubFlags))
{
m_slIL.EmitLoadStubContext(pcsDispatch, m_dwStubFlags);
m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
pcsDispatch->EmitLDLOC(m_slIL.GetTargetInterfacePointerLocalNum());

pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_COM_HR_EXCEPTION_OBJECT, 3, 1);
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/metasig.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@


// static methods:
DEFINE_METASIG_T(SM(Int_IntPtr_Obj_RetException, i I j, C(EXCEPTION)))
DEFINE_METASIG_T(SM(Int_IntPtr_IntPtr_RetException, i I I, C(EXCEPTION)))
DEFINE_METASIG_T(SM(Type_CharPtr_RuntimeAssembly_Bool_Bool_IntPtr_RetRuntimeType, P(u) C(ASSEMBLY) F F I, C(CLASS)))
DEFINE_METASIG_T(SM(Type_RetIntPtr, C(TYPE), I))
DEFINE_METASIG(SM(RefIntPtr_IntPtr_IntPtr_Int_RetObj, r(I) I I i, j))
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/vm/qcallentrypoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,9 +518,7 @@ static const Entry s_QCall[] =
DllImportEntry(StubHelpers_ProfilerBeginTransitionCallback)
DllImportEntry(StubHelpers_ProfilerEndTransitionCallback)
#endif
DllImportEntry(StubHelpers_GetHRExceptionObject)
#if defined(FEATURE_COMINTEROP)
DllImportEntry(StubHelpers_GetCOMHRExceptionObject)
DllImportEntry(StubHelpers_GetCOMIPFromRCWSlow)
DllImportEntry(ObjectMarshaler_ConvertToNative)
DllImportEntry(ObjectMarshaler_ConvertToManaged)
Expand Down
75 changes: 0 additions & 75 deletions src/coreclr/vm/stubhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,81 +543,6 @@ extern "C" void QCALLTYPE StubHelpers_ProfilerEndTransitionCallback(MethodDesc*
}
#endif // PROFILING_SUPPORTED

extern "C" void QCALLTYPE StubHelpers_GetHRExceptionObject(HRESULT hr, QCall::ObjectHandleOnStack result)
{
QCALL_CONTRACT;

BEGIN_QCALL;

GCX_COOP();

OBJECTREF oThrowable = NULL;
GCPROTECT_BEGIN(oThrowable);

// GetExceptionForHR uses equivalant logic as COMPlusThrowHR
GetExceptionForHR(hr, &oThrowable);
result.Set(oThrowable);

GCPROTECT_END();

END_QCALL;
}

#ifdef FEATURE_COMINTEROP
extern "C" void QCALLTYPE StubHelpers_GetCOMHRExceptionObject(
HRESULT hr,
MethodDesc* pMD,
QCall::ObjectHandleOnStack pThis,
QCall::ObjectHandleOnStack result)
{
QCALL_CONTRACT;

BEGIN_QCALL;

GCX_COOP();

struct
{
OBJECTREF oThrowable;
OBJECTREF oref;
} gc;
gc.oThrowable = NULL;
gc.oref = NULL;
GCPROTECT_BEGIN(gc);

IErrorInfo* pErrorInfo = NULL;
if (pMD != NULL)
{
// Retrieve the interface method table.
MethodTable* pItfMT = CLRToCOMCallInfo::FromMethodDesc(pMD)->m_pInterfaceMT;

// get 'this'
gc.oref = ObjectToOBJECTREF(pThis.Get());

// Get IUnknown pointer for this interface on this object
IUnknown* pUnk = ComObject::GetComIPFromRCW(&gc.oref, pItfMT);
if (pUnk != NULL)
{
// Check to see if the component supports error information for this interface.
IID ItfIID;
pItfMT->GetGuid(&ItfIID, TRUE);
pErrorInfo = GetSupportedErrorInfo(pUnk, ItfIID);

DWORD cbRef = SafeRelease(pUnk);
LogInteropRelease(pUnk, cbRef, "IUnk to QI for ISupportsErrorInfo");
}
}

// GetExceptionForHR will handle lifetime of IErrorInfo.
GetExceptionForHR(hr, pErrorInfo, &gc.oThrowable);
result.Set(gc.oThrowable);

GCPROTECT_END();

END_QCALL;
}
#endif // FEATURE_COMINTEROP

extern "C" void QCALLTYPE StubHelpers_MarshalToManagedVaList(va_list va, VARARGS* pArgIterator)
{
QCALL_CONTRACT;
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/vm/stubhelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ extern "C" void* QCALLTYPE StubHelpers_ProfilerBeginTransitionCallback(MethodDes
extern "C" void QCALLTYPE StubHelpers_ProfilerEndTransitionCallback(MethodDesc* pTargetMD);
#endif

extern "C" void QCALLTYPE StubHelpers_GetHRExceptionObject(HRESULT hr, QCall::ObjectHandleOnStack result);

#ifdef FEATURE_COMINTEROP
extern "C" void QCALLTYPE StubHelpers_GetCOMHRExceptionObject(HRESULT hr, MethodDesc *pMD, QCall::ObjectHandleOnStack pThis, QCall::ObjectHandleOnStack result);

extern "C" IUnknown* QCALLTYPE StubHelpers_GetCOMIPFromRCWSlow(QCall::ObjectHandleOnStack pSrc, MethodDesc* pMD, void** ppTarget);

extern "C" void QCALLTYPE ObjectMarshaler_ConvertToNative(QCall::ObjectHandleOnStack pSrcUNSAFE, VARIANT* pDest);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class OleAut32
{
[LibraryImport(Libraries.OleAut32)]
internal static partial int GetErrorInfo(uint dwReserved, out IntPtr ppErrorInfo);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2156,6 +2156,9 @@
<Compile Include="$(CommonPath)Interop\Windows\Ole32\Interop.PropVariantClear.cs">
<Link>Common\Interop\Windows\Ole32\Interop.PropVariantClear.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\OleAut32\Interop.GetErrorInfo.cs">
<Link>Common\Interop\Windows\OleAut32\Interop.GetErrorInfo.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Secur32\Interop.GetUserNameExW.cs">
<Link>Common\Interop\Windows\Secur32\Interop.GetUserNameExW.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,63 @@ public static IntPtr GetHINSTANCE(Module m)
return GetExceptionForHRInternal(errorCode, errorInfo);
}

public static Exception? GetExceptionForHR(int errorCode, in Guid iid, IntPtr pUnk)
{
if (errorCode >= 0)
{
return null;
}

return GetExceptionForHRInternal(errorCode, in iid, pUnk);
}

private static unsafe Exception? GetExceptionForHRInternal(int errorCode, in Guid iid, IntPtr pUnk)
{
const IntPtr NoErrorInfo = -1; // Use -1 to indicate no error info available

// Normally, we would check if the interface supports IErrorInfo first. However,
// built-in COM calls GetErrorInfo first to clear the error info, so we follow
// that pattern here.
IntPtr errorInfo = NoErrorInfo;

#if TARGET_WINDOWS
Interop.OleAut32.GetErrorInfo(0, out errorInfo);
if (errorInfo == IntPtr.Zero)
{
errorInfo = NoErrorInfo;
}

// If there is error info and we have a pointer to the interface,
// we check if it supports ISupportErrorInfo.
if (errorInfo != NoErrorInfo && pUnk != IntPtr.Zero)
{
Guid IID_ISupportErrorInfo = new(0xDF0B3D60, 0x548F, 0x101B, 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19);
int hr = QueryInterface(pUnk, in IID_ISupportErrorInfo, out IntPtr supportErrorInfo);
if (hr == 0)
{
// Check if the target interface is supported.
// ISupportErrorInfo.InterfaceSupportsErrorInfo slot
fixed (Guid* piid = &iid)
{
hr = ((delegate* unmanaged[MemberFunction]<IntPtr, Guid*, int>)(*(*(void***)supportErrorInfo + 3)))(supportErrorInfo, piid);
}
Release(supportErrorInfo);
}

// If ISupportErrorInfo isn't supported or the target interface doesn't support IErrorInfo,
// release the error info and mark it as NoErrorInfo to avoid querying for IErrorInfo again.
if (hr != 0)
{
Release(errorInfo);
errorInfo = NoErrorInfo;
}
}
#endif

// If the error info is valid, its lifetime will be handled by GetExceptionForHRInternal().
return GetExceptionForHRInternal(errorCode, errorInfo);
}

#if !CORECLR
#pragma warning disable IDE0060
private static Exception? GetExceptionForHRInternal(int errorCode, IntPtr errorInfo)
Expand Down Expand Up @@ -865,6 +922,14 @@ public static void ThrowExceptionForHR(int errorCode, IntPtr errorInfo)
}
}

public static void ThrowExceptionForHR(int errorCode, in Guid iid, IntPtr pUnk)
{
if (errorCode < 0)
{
throw GetExceptionForHR(errorCode, in iid, pUnk)!;
}
}

public static IntPtr SecureStringToBSTR(SecureString s)
{
if (s is null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
return new ComMethodContext(
data.Method,
data.OwningInterface,
CalculateStubInformation(data.Method.MethodInfo.Syntax, symbolMap[data.Method.MethodInfo], data.Method.Index, env, data.OwningInterface.Info.Type, ct));
CalculateStubInformation(data.Method.MethodInfo.Syntax, symbolMap[data.Method.MethodInfo], data.Method.Index, env, data.OwningInterface.Info, ct));
}).WithTrackingName(StepNames.CalculateStubInformation);

var interfaceAndMethodsContexts = comMethodContexts
Expand Down Expand Up @@ -256,7 +256,7 @@ private static bool IsHResultLikeType(ManagedTypeInfo type)
|| typeName.Equals("hresult", StringComparison.OrdinalIgnoreCase);
}

private static IncrementalMethodStubGenerationContext CalculateStubInformation(MethodDeclarationSyntax syntax, IMethodSymbol symbol, int index, StubEnvironment environment, ManagedTypeInfo owningInterface, CancellationToken ct)
private static IncrementalMethodStubGenerationContext CalculateStubInformation(MethodDeclarationSyntax syntax, IMethodSymbol symbol, int index, StubEnvironment environment, ComInterfaceInfo owningInterfaceInfo, CancellationToken ct)
{
ct.ThrowIfCancellationRequested();
INamedTypeSymbol? lcidConversionAttrType = environment.LcidConversionAttrType;
Expand Down Expand Up @@ -349,7 +349,7 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M
// Add the HRESULT return value in the native signature.
// This element does not have any influence on the managed signature, so don't assign a managed index.
ElementTypeInformation = returnSwappedSignatureElements.Add(
new TypePositionInfo(SpecialTypeInfo.Int32, new ManagedHResultExceptionMarshallingInfo())
new TypePositionInfo(SpecialTypeInfo.Int32, new ManagedHResultExceptionMarshallingInfo(owningInterfaceInfo.InterfaceId))
{
NativeIndex = TypePositionInfo.ReturnIndex
})
Expand Down Expand Up @@ -425,7 +425,7 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M
virtualMethodIndexData,
exceptionMarshallingInfo,
environment.EnvironmentFlags,
owningInterface,
owningInterfaceInfo.Type,
declaringType,
generatorDiagnostics.Diagnostics.ToSequenceEqualImmutableArray(),
ComInterfaceDispatchMarshallingInfo.Instance);
Expand Down Expand Up @@ -826,7 +826,7 @@ private static ClassDeclarationSyntax GenerateInterfaceInformation(ComInterfaceI
EqualsValueClause(
ImplicitObjectCreationExpression()
.AddArgumentListArguments(
Argument(CreateEmbeddedDataBlobCreationStatement(context.InterfaceId.ToByteArray())))))
Argument(ComInterfaceGeneratorHelpers.CreateEmbeddedDataBlobCreationStatement(context.InterfaceId.ToByteArray())))))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));

if (context.Options.HasFlag(ComInterfaceOptions.ManagedObjectWrapper))
Expand Down Expand Up @@ -858,20 +858,6 @@ private static ClassDeclarationSyntax GenerateInterfaceInformation(ComInterfaceI
.AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
.WithExpressionBody(ArrowExpressionClause(LiteralExpression(SyntaxKind.NullLiteralExpression)))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));


static ExpressionSyntax CreateEmbeddedDataBlobCreationStatement(ReadOnlySpan<byte> bytes)
{
var literals = new CollectionElementSyntax[bytes.Length];

for (int i = 0; i < bytes.Length; i++)
{
literals[i] = ExpressionElement(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(bytes[i])));
}

// [ <byte literals> ]
return CollectionExpression(SeparatedList(literals));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace Microsoft.Interop
{
Expand Down Expand Up @@ -32,5 +35,18 @@ public static IMarshallingGeneratorResolver GetGeneratorResolver(EnvironmentFlag
(false, MarshalDirection.UnmanagedToManaged) => s_unmanagedToManagedEnabledMarshallingGeneratorResolver,
_ => throw new UnreachableException(),
};

public static ExpressionSyntax CreateEmbeddedDataBlobCreationStatement(ReadOnlySpan<byte> bytes)
{
var literals = new CollectionElementSyntax[bytes.Length];

for (int i = 0; i < bytes.Length; i++)
{
literals[i] = ExpressionElement(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(bytes[i])));
}

// [ <byte literals> ]
return CollectionExpression(SeparatedList(literals));
}
}
}
Loading
Loading