Skip to content
Draft
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
40 changes: 40 additions & 0 deletions src/WinRT.Runtime2/InteropServices/ComObjectHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

using System;
using System.Runtime.CompilerServices;

namespace WindowsRuntime.InteropServices;

Expand Down Expand Up @@ -82,4 +83,43 @@ public static HRESULT IsFreeThreadedUnsafe(void* thisPtr)

return WellKnownErrorCodes.S_FALSE;
}

/// <summary>
/// Validates the provided marshaling type for a given object.
/// </summary>
/// <param name="thisPtr">The target COM object.</param>
/// <param name="marshalingType">The <see cref="CreateObjectReferenceMarshalingType"/> value available in metadata for the type being marshalled.</param>
/// <remarks>
/// This method will fail-fast if the validation fails.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidateMarshalingType(void* thisPtr, CreateObjectReferenceMarshalingType marshalingType)
{
if (!WindowsRuntimeFeatureSwitches.EnableMarshalingTypeValidation)
{
return;
}

// Move the logic into a non-inlineable method to help the containing one get inlined correctly
[MethodImpl(MethodImplOptions.NoInlining)]
static void PerformValidation(void* thisPtr, CreateObjectReferenceMarshalingType marshalingType)
{
// If no static type information is available, we can avoid the validation overhead
if (marshalingType == CreateObjectReferenceMarshalingType.Unknown)
{
return;
}

HRESULT hresult = IsFreeThreadedUnsafe(thisPtr);

// If the object declared a marshalling type that doesn't match what we can compute at runtime, fail immediately
if ((marshalingType == CreateObjectReferenceMarshalingType.Agile && hresult == WellKnownErrorCodes.S_FALSE) ||
(marshalingType == CreateObjectReferenceMarshalingType.Standard && hresult == WellKnownErrorCodes.S_OK))
{
Environment.FailFast($"The input object ('{(nint)thisPtr:X16}') declared the incorrect marshalling type '{marshalingType}'.");
}
}

PerformValidation(thisPtr, marshalingType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.ComponentModel;

namespace WindowsRuntime.InteropServices;

/// <summary>
/// Specifies the marshaling type to use to marshal a given Windows Runtime object, specifically when creating a <see cref="WindowsRuntimeObjectReference"/> instance.
/// </summary>
/// <seealso href="https://learn.microsoft.com/uwp/api/windows.foundation.metadata.marshalingtype"/>
[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage,
DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId,
UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)]
[EditorBrowsable(EditorBrowsableState.Never)]
public enum CreateObjectReferenceMarshalingType
{
/// <summary>
/// No static type information is available to know in advance the marshaling type for the class.
/// </summary>
Unknown,

/// <summary>
/// The class marshals and unmarshals to the same pointer value on all interfaces.
/// </summary>
Agile = 2,

/// <summary>
/// The class does not implement <see href="https://learn.microsoft.com/windows/win32/api/objidl/nn-objidl-imarshal"><c>IMarshal</c></see> or forwards to
/// <see href="https://learn.microsoft.com/windows/win32/api/combaseapi/nf-combaseapi-cogetstandardmarshal"><c>CoGetStandardMarshal</c></see> on all interfaces.
/// </summary>
Standard = 3
}
Loading
Loading