diff --git a/nuget/Microsoft.Windows.CsWinRT.Authoring.targets b/nuget/Microsoft.Windows.CsWinRT.Authoring.targets
index 33287c367..7d4ad4bd1 100644
--- a/nuget/Microsoft.Windows.CsWinRT.Authoring.targets
+++ b/nuget/Microsoft.Windows.CsWinRT.Authoring.targets
@@ -42,7 +42,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<_CsWinRTRuntimeCopyLocalItemsFromNuGetPackage Include="@(RuntimeCopyLocalItems->HasMetadata('NuGetPackageVersion'))" />
<_CsWinRTDetectedPackages Include="%(_CsWinRTRuntimeCopyLocalItemsFromNuGetPackage.NuGetPackageId)\%(_CsWinRTRuntimeCopyLocalItemsFromNuGetPackage.NuGetPackageVersion)" Condition="@(_CsWinRTRuntimeCopyLocalItemsFromNuGetPackage->Count()) > 0" />
<_CsWinRTDetectedDistinctPackages Include="@(_CsWinRTDetectedPackages->Distinct())" />
-
+
diff --git a/nuget/Microsoft.Windows.CsWinRT.Embedded.targets b/nuget/Microsoft.Windows.CsWinRT.Embedded.targets
index ff38fa69c..5fdac7141 100644
--- a/nuget/Microsoft.Windows.CsWinRT.Embedded.targets
+++ b/nuget/Microsoft.Windows.CsWinRT.Embedded.targets
@@ -69,7 +69,8 @@ Copyright (C) Microsoft Corporation. All rights reserved.
-
+
+
diff --git a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs
index d23359634..11d952e61 100644
--- a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs
+++ b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs
@@ -365,7 +365,7 @@ private static string ToFullyQualifiedString(ISymbol symbol)
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
- miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes);
+ miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes | SymbolDisplayMiscellaneousOptions.ExpandNullable);
var qualifiedString = symbol.ToDisplayString(symbolDisplayString);
return qualifiedString.StartsWith("global::") ? qualifiedString[8..] : qualifiedString;
@@ -410,7 +410,8 @@ private static string ToVtableLookupString(ISymbol symbol, List genericA
var arity = symbol is INamedTypeSymbol namedType && namedType.Arity > 0 ? "`" + namedType.Arity : "";
var symbolDisplayString = new SymbolDisplayFormat(
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted,
- typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);
+ typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
+ miscellaneousOptions: SymbolDisplayMiscellaneousOptions.ExpandNullable);
return symbol.ToDisplayString(symbolDisplayString) + arity;
}
else
@@ -640,9 +641,12 @@ void AddGenericInterfaceInstantiation(INamedTypeSymbol iface)
List genericParameters = new();
foreach (var genericParameter in iface.TypeArguments)
{
+ var isNullable = genericParameter.IsValueType && genericParameter.NullableAnnotation.HasFlag(NullableAnnotation.Annotated);
+
// Handle initialization of nested generics as they may not be
// initialized already.
- if (genericParameter is INamedTypeSymbol genericParameterIface &&
+ if (!isNullable &&
+ genericParameter is INamedTypeSymbol genericParameterIface &&
genericParameterIface.IsGenericType)
{
AddGenericInterfaceInstantiation(genericParameterIface);
@@ -651,7 +655,7 @@ void AddGenericInterfaceInstantiation(INamedTypeSymbol iface)
genericParameters.Add(new GenericParameter(
ToFullyQualifiedString(genericParameter),
GeneratorHelper.GetAbiType(genericParameter, mapper),
- genericParameter.TypeKind));
+ isNullable ? TypeKind.Interface : genericParameter.TypeKind));
}
genericInterfacesToAddToVtable.Add(new GenericInterface(
diff --git a/src/Authoring/WinRT.SourceGenerator/Helper.cs b/src/Authoring/WinRT.SourceGenerator/Helper.cs
index 2d749d017..00d9195b7 100644
--- a/src/Authoring/WinRT.SourceGenerator/Helper.cs
+++ b/src/Authoring/WinRT.SourceGenerator/Helper.cs
@@ -708,7 +708,7 @@ public static string GetAbiType(ITypeSymbol type, TypeMapper mapper)
return "ABI.System.Exception";
}
- if (type.IsValueType)
+ if (type.IsValueType && !type.NullableAnnotation.HasFlag(NullableAnnotation.Annotated))
{
string customTypeMapKey = string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName);
if (mapper.HasMappingForType(customTypeMapKey))
@@ -912,8 +912,8 @@ public static string GetCreateMarshaler(GenericParameter genericParameter, strin
public static string GetCreateMarshaler(string type, string abiType, TypeKind kind, string arg)
{
- if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType) ||
- type == "bool" ||
+ if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType) ||
+ type == "bool" ||
type == "char")
{
return "";
@@ -923,6 +923,11 @@ public static string GetCreateMarshaler(string type, string abiType, TypeKind ki
// TODO: Consider switching to pinning
return $$"""__{{arg}} = MarshalString.CreateMarshaler({{arg}});""";
}
+ else if (kind == TypeKind.Struct)
+ {
+ string marshalerClass = GetMarshalerClass(type, abiType, kind, false);
+ return $$"""__{{arg}} = {{marshalerClass}}.CreateMarshaler({{arg}});""";
+ }
else
{
string marshalerClass = GetMarshalerClass(type, abiType, kind, false);
@@ -1001,6 +1006,10 @@ public static string GetMarshalerDeclaration(string type, string abiType, TypeKi
{
return "";
}
+ else if (kind == TypeKind.Struct)
+ {
+ return $"{GetAbiMarshalerType(type, abiType, kind, false)}.Marshaler __{arg} = default;";
+ }
else
{
return $"{GetAbiMarshalerType(type, abiType, kind, false)} __{arg} = default;";
diff --git a/src/Tests/FunctionalTests/Async/Program.cs b/src/Tests/FunctionalTests/Async/Program.cs
index 99288b4fb..3aec25171 100644
--- a/src/Tests/FunctionalTests/Async/Program.cs
+++ b/src/Tests/FunctionalTests/Async/Program.cs
@@ -5,6 +5,7 @@
using TestComponentCSharp;
using Windows.Foundation;
using Windows.Storage.Streams;
+using Windows.Web.Http;
using WinRT;
var instance = new Class();
@@ -119,6 +120,20 @@
return 113;
}
+bool progressCalledWithExpectedResults = false;
+var asyncProgressHandler = new AsyncActionProgressHandler((info, progress) =>
+{
+ if (progress.BytesReceived == 3 && progress.TotalBytesToReceive == 4)
+ {
+ progressCalledWithExpectedResults = true;
+ }
+});
+Class.UnboxAndCallProgressHandler(asyncProgressHandler);
+if (!progressCalledWithExpectedResults)
+{
+ return 114;
+}
+
return 100;
static async Task InvokeAddAsync(Class instance, int lhs, int rhs)
diff --git a/src/Tests/FunctionalTests/CCW/Program.cs b/src/Tests/FunctionalTests/CCW/Program.cs
index 8d709df53..ed118594f 100644
--- a/src/Tests/FunctionalTests/CCW/Program.cs
+++ b/src/Tests/FunctionalTests/CCW/Program.cs
@@ -8,6 +8,8 @@
using System.Windows.Input;
using System.Runtime.InteropServices;
using System.Collections.Specialized;
+using Windows.Foundation;
+using Windows.Web.Http;
var managedProperties = new ManagedProperties(42);
var instance = new Class();
@@ -178,6 +180,15 @@
var notifyCollectionChangedActionList = new List();
instance.BindableIterableProperty = notifyCollectionChangedActionList;
+var nullableDoubleList = new List();
+instance.BindableIterableProperty = nullableDoubleList;
+
+var nullableDoubleList2 = new List>();
+instance.BindableIterableProperty = nullableDoubleList2;
+
+var nullableHandleList = new List();
+instance.BindableIterableProperty = nullableHandleList;
+
var customCommand = new CustomCommand() as ICommand;
ccw = MarshalInspectable