Skip to content

Commit

Permalink
Implement logic for 'CsWinRTEnableManifestFreeActivation'
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergio0694 committed Dec 14, 2024
1 parent cff8baa commit 0c1656c
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 20 deletions.
91 changes: 72 additions & 19 deletions src/WinRT.Runtime/ActivationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using WinRT.Interop;
Expand Down Expand Up @@ -227,26 +228,9 @@ public static IObjectReference Get(string typeName)
return factory;
}

var moduleName = typeName;
while (true)
{
var lastSegment = moduleName.LastIndexOf(".", StringComparison.Ordinal);
if (lastSegment <= 0)
{
Marshal.ThrowExceptionForHR(hr);
}
moduleName = moduleName.Remove(lastSegment);
ThrowIfClassNotRegisteredAndManifestFreeActivationDisabled(typeName, hr);

DllModule module = null;
if (DllModule.TryLoad(moduleName + ".dll", out module))
{
(factory, hr) = module.GetActivationFactory(typeName);
if (factory != null)
{
return factory;
}
}
}
return ManifestFreeGet(typeName, hr);
}

#if NET
Expand Down Expand Up @@ -276,15 +260,27 @@ public static ObjectReference<I> Get<I>(string typeName, Guid iid)
{
return factory;
}

ThrowIfClassNotRegisteredAndManifestFreeActivationDisabled(typeName, hr);

return ManifestFreeGet(typeName, iid, hr);
#else
ObjectReference<I> factory;
(factory, hr) = WinRTModule.GetActivationFactory<I>(typeName, iid);
if (factory != null)
{
return factory;
}

ThrowIfClassNotRegisteredAndManifestFreeActivationDisabled(typeName, hr);

return ManifestFreeGet<I>(typeName, iid, hr);
#endif
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static IObjectReference ManifestFreeGet(string typeName, int hr)
{
var moduleName = typeName;
while (true)
{
Expand All @@ -297,6 +293,34 @@ public static ObjectReference<I> Get<I>(string typeName, Guid iid)

DllModule module = null;
if (DllModule.TryLoad(moduleName + ".dll", out module))
{
(ObjectReference<IUnknownVftbl> factory, hr) = module.GetActivationFactory(typeName);
if (factory != null)
{
return factory;
}
}
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
#if NET
private static IObjectReference ManifestFreeGet(string typeName, Guid iid, int hr)
#else
private static ObjectReference<I> ManifestFreeGet<I>(string typeName, Guid iid, int hr)
#endif
{
var moduleName = typeName;
while (true)
{
var lastSegment = moduleName.LastIndexOf(".", StringComparison.Ordinal);
if (lastSegment <= 0)
{
Marshal.ThrowExceptionForHR(hr);
}
moduleName = moduleName.Remove(lastSegment);

if (DllModule.TryLoad(moduleName + ".dll", out DllModule module))
{
ObjectReference<IUnknownVftbl> activationFactory;
(activationFactory, hr) = module.GetActivationFactory(typeName);
Expand All @@ -315,6 +339,35 @@ public static ObjectReference<I> Get<I>(string typeName, Guid iid)
}
}

private static void ThrowIfClassNotRegisteredAndManifestFreeActivationDisabled(string typeName, int hr)
{
// If manifest free activation is enabled, we never throw here.
// Callers will always try the fallback path if we didn't succeed.
if (FeatureSwitches.EnableManifestFreeActivation)
{
return;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static Exception GetException(string typeName, int hr)
{
Exception exception = Marshal.GetExceptionForHR(hr);

if (hr == ExceptionHelpers.REGDB_E_CLASSNOTREG)
{
throw new NotSupportedException(
$"Failed to activate type with runtime class name '{typeName}' with 'RoGetActivationFactory' (it returned 0x80040154, ie. 'REGDB_E_CLASSNOTREG'). Make sure to add the activatable class id for the type " +
"to the APPX manifest, or enable the manifest free activation fallback path by disabling the 'CsWinRTEnableManifestFreeActivation' property (note: the fallback path incurs a performance hit).", exception);
}

return exception;
}

// Explicit throw so the JIT can see it and correctly optimize for always throwing paths.
// The exception instantiation is in a separate method so that codegen remains separate.
throw GetException(typeName, hr);
}

#if NET
private static IObjectReference GetFromActivationHandler(string typeName, Guid iid)
{
Expand Down
1 change: 1 addition & 0 deletions src/WinRT.Runtime/ExceptionHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ static unsafe class ExceptionHelpers
private const int ERROR_BAD_FORMAT = unchecked((int)0x8007000b);
private const int ERROR_CANCELLED = unchecked((int)0x800704c7);
private const int ERROR_TIMEOUT = unchecked((int)0x800705b4);
internal const int REGDB_E_CLASSNOTREG = unchecked((int)0x80040154);

private static delegate* unmanaged[Stdcall]<IntPtr*, int> getRestrictedErrorInfo;
private static delegate* unmanaged[Stdcall]<IntPtr, int> setRestrictedErrorInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,6 @@ private static unsafe int Do_Abi_GetCustomProperty_0(IntPtr thisPtr, IntPtr name
{
throw new NotSupportedException(
$"ICustomProperty support used by XAML binding for type '{target.GetType()}' (property '{_name}') requires the type to marked with 'WinRT.GeneratedBindableCustomPropertyAttribute'. " +

$"If this is a built-in type or a type that can't be marked, a wrapper type should be used around it that is marked to enable this support.");
}

Expand Down

0 comments on commit 0c1656c

Please sign in to comment.