Skip to content

Commit

Permalink
Merge pull request #552 from microsoft/fix372
Browse files Browse the repository at this point in the history
Add SizeParamIndex or CountConst as required to extern methods
  • Loading branch information
AArnott committed May 17, 2022
2 parents c57036a + 109b566 commit 6f1877f
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 148 deletions.
2 changes: 1 addition & 1 deletion src/Microsoft.Windows.CsWin32/ArrayTypeHandleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs
TypeSyntaxAndMarshaling element = this.ElementType.ToTypeSyntax(inputs, customAttributes);
ArrayTypeSyntax arrayType = ArrayType(element.Type, SingletonList(ArrayRankSpecifier().AddSizes(this.Shape.Sizes.Select(size => LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(size))).ToArray<ExpressionSyntax>())));
MarshalAsAttribute? marshalAs = element.MarshalAsAttribute is object ? new MarshalAsAttribute(UnmanagedType.LPArray) { ArraySubType = element.MarshalAsAttribute.Value } : null;
return new TypeSyntaxAndMarshaling(arrayType, marshalAs);
return new TypeSyntaxAndMarshaling(arrayType, marshalAs, element.NativeArrayInfo);
}
}
163 changes: 40 additions & 123 deletions src/Microsoft.Windows.CsWin32/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1171,15 +1171,21 @@ IEnumerable<MemberDeclarationSyntax> GroupMembersByNamespace(IEnumerable<MemberD
internal static ImmutableDictionary<string, string> GetBannedAPIs(GeneratorOptions options) => options.AllowMarshaling ? BannedAPIsWithMarshaling : BannedAPIsWithoutMarshaling;

[return: NotNullIfNotNull("marshalAs")]
internal static AttributeSyntax? MarshalAs(MarshalAsAttribute? marshalAs)
internal static AttributeSyntax? MarshalAs(MarshalAsAttribute? marshalAs, NativeArrayInfo? nativeArrayInfo)
{
if (marshalAs is null)
{
return null;
}

// TODO: fill in more properties to match the original
return MarshalAs(marshalAs.Value, marshalAs.ArraySubType, marshalAs.MarshalCookie, marshalAs.MarshalType, marshalAs.SizeConst > 0 ? LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(marshalAs.SizeConst)) : null);
return MarshalAs(
marshalAs.Value,
marshalAs.ArraySubType,
marshalAs.MarshalCookie,
marshalAs.MarshalType,
nativeArrayInfo?.CountConst.HasValue is true ? LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(nativeArrayInfo.Value.CountConst.Value)) : null,
nativeArrayInfo?.CountParamIndex.HasValue is true ? LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(nativeArrayInfo.Value.CountParamIndex.Value)) : null);
}

internal static TypeSyntax MakeSpanOfT(TypeSyntax typeArgument) => GenericName("Span").AddTypeArgumentListArguments(typeArgument);
Expand Down Expand Up @@ -1797,14 +1803,14 @@ internal void GetBaseTypeInfo(TypeDefinition typeDef, out StringHandle baseTypeN
return specialDeclaration;
}

internal CustomAttribute? FindNativeArrayInfoAttribute(CustomAttributeHandleCollection customAttributeHandles)
internal NativeArrayInfo? FindNativeArrayInfoAttribute(CustomAttributeHandleCollection customAttributeHandles)
{
foreach (CustomAttributeHandle handle in customAttributeHandles)
{
CustomAttribute att = this.Reader.GetCustomAttribute(handle);
if (this.IsAttribute(att, InteropDecorationNamespace, NativeArrayInfoAttribute))
{
return att;
return DecodeNativeArrayInfoAttribute(att);
}
}

Expand Down Expand Up @@ -2095,7 +2101,7 @@ private static AttributeSyntax UnmanagedFunctionPointer(CallingConvention callin
IdentifierName(Enum.GetName(typeof(CallingConvention), callingConvention)!))));
}

private static AttributeSyntax MarshalAs(UnmanagedType unmanagedType, UnmanagedType? arraySubType = null, string? marshalCookie = null, string? marshalType = null, ExpressionSyntax? sizeConst = null)
private static AttributeSyntax MarshalAs(UnmanagedType unmanagedType, UnmanagedType? arraySubType = null, string? marshalCookie = null, string? marshalType = null, ExpressionSyntax? sizeConst = null, ExpressionSyntax? sizeParamIndex = null)
{
AttributeSyntax? marshalAs =
Attribute(IdentifierName("MarshalAs"))
Expand All @@ -2122,6 +2128,12 @@ private static AttributeSyntax MarshalAs(UnmanagedType unmanagedType, UnmanagedT
AttributeArgument(sizeConst).WithNameEquals(NameEquals(nameof(MarshalAsAttribute.SizeConst))));
}

if (sizeParamIndex is object)
{
marshalAs = marshalAs.AddArgumentListArguments(
AttributeArgument(sizeParamIndex).WithNameEquals(NameEquals(nameof(MarshalAsAttribute.SizeParamIndex))));
}

if (!string.IsNullOrEmpty(marshalCookie))
{
marshalAs = marshalAs.AddArgumentListArguments(
Expand Down Expand Up @@ -2286,6 +2298,16 @@ private static bool TrySplitPossiblyQualifiedName(string possiblyQualifiedName,
return @namespace is object;
}

private static NativeArrayInfo DecodeNativeArrayInfoAttribute(CustomAttribute nativeArrayInfoAttribute)
{
CustomAttributeValue<TypeSyntax> args = nativeArrayInfoAttribute.DecodeValue(CustomAttributeTypeProvider.Instance);
return new NativeArrayInfo
{
CountConst = (int?)args.NamedArguments.FirstOrDefault(a => a.Name == "CountConst").Value,
CountParamIndex = (short?)args.NamedArguments.FirstOrDefault(a => a.Name == "CountParamIndex").Value,
};
}

private T AddApiDocumentation<T>(string api, T memberDeclaration)
where T : MemberDeclarationSyntax
{
Expand Down Expand Up @@ -3248,8 +3270,9 @@ private TypeDeclarationSyntax DeclareInterfaceAsStruct(TypeDefinition typeDef, S
MethodSignature<TypeHandleInfo> signature = methodDefinition.DecodeSignature(SignatureHandleProvider.Instance, null);

CustomAttributeHandleCollection? returnTypeAttributes = this.GetReturnTypeCustomAttributes(methodDefinition);
(TypeSyntax returnType, MarshalAsAttribute? marshalAs) = signature.ReturnType.ToTypeSyntax(typeSettings, returnTypeAttributes);
AttributeSyntax? returnsAttribute = MarshalAs(marshalAs);
TypeSyntaxAndMarshaling returnTypeDetails = signature.ReturnType.ToTypeSyntax(typeSettings, returnTypeAttributes);
TypeSyntax returnType = returnTypeDetails.Type;
AttributeSyntax? returnsAttribute = MarshalAs(returnTypeDetails.MarshalAsAttribute, returnTypeDetails.NativeArrayInfo);

bool preserveSig = returnType is not QualifiedNameSyntax { Right: { Identifier: { ValueText: "HRESULT" } } }
|| (methodDefinition.ImplAttributes & MethodImplAttributes.PreserveSig) == MethodImplAttributes.PreserveSig
Expand Down Expand Up @@ -4293,11 +4316,10 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
CustomAttribute att = this.Reader.GetCustomAttribute(attHandle);
if (this.IsAttribute(att, InteropDecorationNamespace, NativeArrayInfoAttribute))
{
CustomAttributeValue<TypeSyntax> args = att.DecodeValue(CustomAttributeTypeProvider.Instance);
isArray = true;
sizeParamIndex = (short?)args.NamedArguments.FirstOrDefault(a => a.Name == "CountParamIndex").Value;
sizeConst = (int?)args.NamedArguments.FirstOrDefault(a => a.Name == "CountConst").Value;

NativeArrayInfo nativeArrayInfo = DecodeNativeArrayInfoAttribute(att);
sizeParamIndex = nativeArrayInfo.CountParamIndex;
sizeConst = nativeArrayInfo.CountConst;
break;
}
}
Expand Down Expand Up @@ -5403,118 +5425,6 @@ private bool IsManagedType(TypeDefinitionHandle typeDefinitionHandle)
return unmgdType;
}

private MarshalAsAttribute ToMarshalAsAttribute(BlobHandle blobHandle)
{
BlobReader br = this.Reader.GetBlobReader(blobHandle);
var unmgdType = (UnmanagedType)br.ReadByte();
var ma = new MarshalAsAttribute(unmgdType);
switch (unmgdType)
{
case UnmanagedType.Interface:
case UnmanagedType.IUnknown:
case UnmanagedType.IDispatch:
if (br.RemainingBytes == 0)
{
break;
}

ma.IidParameterIndex = br.ReadCompressedInteger();
break;

case UnmanagedType.ByValArray:
if (br.RemainingBytes == 0)
{
break;
}

ma.SizeConst = br.ReadCompressedInteger();

if (br.RemainingBytes == 0)
{
break;
}

ma.ArraySubType = (UnmanagedType)br.ReadCompressedInteger();

break;

case UnmanagedType.SafeArray:
if (br.RemainingBytes == 0)
{
break;
}

ma.SafeArraySubType = (VarEnum)br.ReadCompressedInteger();

if (br.RemainingBytes == 0)
{
break;
}
////string udtName = br.ReadSerializedString();
////ma.SafeArrayUserDefinedSubType = Helpers.LoadTypeFromAssemblyQualifiedName(udtName, module.GetRoAssembly(), ignoreCase: false, throwOnError: false);
break;

case UnmanagedType.LPArray:
if (br.RemainingBytes == 0)
{
break;
}

ma.ArraySubType = (UnmanagedType)br.ReadCompressedInteger();

if (br.RemainingBytes == 0)
{
break;
}

ma.SizeParamIndex = (short)br.ReadCompressedInteger();

if (br.RemainingBytes == 0)
{
break;
}

ma.SizeConst = br.ReadCompressedInteger();
break;

case UnmanagedType.CustomMarshaler:
if (br.RemainingBytes == 0)
{
break;
}

br.ReadSerializedString(); // Skip the typelib guid.

if (br.RemainingBytes == 0)
{
break;
}

br.ReadSerializedString(); // Skip name of native type.

if (br.RemainingBytes == 0)
{
break;
}

ma.MarshalType = br.ReadSerializedString();
////ma.MarshalTypeRef = Helpers.LoadTypeFromAssemblyQualifiedName(ma.MarshalType, module.GetRoAssembly(), ignoreCase: false, throwOnError: false);

if (br.RemainingBytes == 0)
{
break;
}

ma.MarshalCookie = br.ReadSerializedString();
break;

default:
break;
}

return ma;
}

private ExpressionSyntax ToExpressionSyntax(Constant constant)
{
BlobReader blobReader = this.Reader.GetBlobReader(constant.Value);
Expand Down Expand Up @@ -5579,6 +5489,13 @@ private IEnumerable<NamespaceMetadata> GetNamespacesToSearch(string? @namespace)
}
}

internal struct NativeArrayInfo
{
internal short? CountParamIndex { get; init; }

internal int? CountConst { get; init; }
}

private class GeneratedCode
{
private readonly GeneratedCode? parent;
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.Windows.CsWin32/HandleTypeHandleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs
}
else if (TryMarshalAsObject(inputs, simpleName, out MarshalAsAttribute? marshalAs))
{
return new TypeSyntaxAndMarshaling(PredefinedType(Token(SyntaxKind.ObjectKeyword)), marshalAs);
return new TypeSyntaxAndMarshaling(PredefinedType(Token(SyntaxKind.ObjectKeyword)), marshalAs, null);
}
else if (!inputs.AllowMarshaling && this.IsDelegate(inputs, out TypeDefinition delegateDefinition) && inputs.Generator is object && !Generator.IsUntypedDelegate(this.reader, delegateDefinition))
{
Expand Down Expand Up @@ -125,7 +125,7 @@ internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs
marshalCookie = marshalCookie.Substring(Generator.GlobalNamespacePrefix.Length);
}

return new TypeSyntaxAndMarshaling(syntax, new MarshalAsAttribute(UnmanagedType.CustomMarshaler) { MarshalCookie = marshalCookie, MarshalType = Generator.WinRTCustomMarshalerFullName });
return new TypeSyntaxAndMarshaling(syntax, new MarshalAsAttribute(UnmanagedType.CustomMarshaler) { MarshalCookie = marshalCookie, MarshalType = Generator.WinRTCustomMarshalerFullName }, null);
}
}
}
Expand Down
27 changes: 16 additions & 11 deletions src/Microsoft.Windows.CsWin32/PointerTypeHandleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,28 @@ internal record PointerTypeHandleInfo(TypeHandleInfo ElementType) : TypeHandleIn

internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, CustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes)
{
(CodeAnalysis.CSharp.Syntax.TypeSyntax elementSyntax, MarshalAsAttribute? marshalAs) = this.ElementType.ToTypeSyntax(inputs, customAttributes);
if (marshalAs is object || inputs.Generator?.IsManagedType(this.ElementType) is true)
TypeSyntaxAndMarshaling elementTypeDetails = this.ElementType.ToTypeSyntax(inputs, customAttributes);
if (elementTypeDetails.MarshalAsAttribute is object || inputs.Generator?.IsManagedType(this.ElementType) is true)
{
bool xIn = (parameterAttributes & ParameterAttributes.In) == ParameterAttributes.In;
bool xOut = (parameterAttributes & ParameterAttributes.Out) == ParameterAttributes.Out;

// A pointer to a marshaled object is not allowed.
if (customAttributes.HasValue && inputs.Generator?.FindNativeArrayInfoAttribute(customAttributes.Value) is object)
if (customAttributes.HasValue && inputs.Generator?.FindNativeArrayInfoAttribute(customAttributes.Value) is { } nativeArrayInfo)
{
// But this pointer represents an array, so type as an array.
return new TypeSyntaxAndMarshaling(
ArrayType(elementSyntax).AddRankSpecifiers(ArrayRankSpecifier()),
marshalAs is object ? new MarshalAsAttribute(UnmanagedType.LPArray) { ArraySubType = marshalAs.Value } : new MarshalAsAttribute(UnmanagedType.LPArray));
MarshalAsAttribute marshalAsAttribute = new MarshalAsAttribute(UnmanagedType.LPArray);
if (elementTypeDetails.MarshalAsAttribute is object)
{
marshalAsAttribute.ArraySubType = elementTypeDetails.MarshalAsAttribute.Value;
}

return new TypeSyntaxAndMarshaling(ArrayType(elementTypeDetails.Type).AddRankSpecifiers(ArrayRankSpecifier()), marshalAsAttribute, nativeArrayInfo);
}
else if (xIn || xOut)
{
// But we can use a modifier to emulate a pointer and thereby enable marshaling.
return new TypeSyntaxAndMarshaling(elementSyntax, marshalAs)
return new TypeSyntaxAndMarshaling(elementTypeDetails.Type, elementTypeDetails.MarshalAsAttribute, elementTypeDetails.NativeArrayInfo)
{
ParameterModifier = Token(
xIn && xOut ? SyntaxKind.RefKeyword :
Expand All @@ -51,17 +55,18 @@ internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs
// We can replace a pointer to a struct with a managed equivalent by changing the pointer to an array.
// We only want to enter this branch for struct fields, since method parameters can use in/out/ref modifiers.
return new TypeSyntaxAndMarshaling(
ArrayType(elementSyntax).AddRankSpecifiers(ArrayRankSpecifier()),
marshalAs is object ? new MarshalAsAttribute(UnmanagedType.LPArray) { ArraySubType = marshalAs.Value } : null);
ArrayType(elementTypeDetails.Type).AddRankSpecifiers(ArrayRankSpecifier()),
elementTypeDetails.MarshalAsAttribute is object ? new MarshalAsAttribute(UnmanagedType.LPArray) { ArraySubType = elementTypeDetails.MarshalAsAttribute.Value } : null,
elementTypeDetails.NativeArrayInfo);
}
}
else if (inputs.AllowMarshaling && inputs.Generator is object
&& customAttributes?.Any(ah => MetadataUtilities.IsAttribute(inputs.Generator.Reader, inputs.Generator!.Reader.GetCustomAttribute(ah), Generator.InteropDecorationNamespace, "ComOutPtrAttribute")) is true)
{
return new TypeSyntaxAndMarshaling(PredefinedType(Token(SyntaxKind.ObjectKeyword)), new MarshalAsAttribute(UnmanagedType.IUnknown));
return new TypeSyntaxAndMarshaling(PredefinedType(Token(SyntaxKind.ObjectKeyword)), new MarshalAsAttribute(UnmanagedType.IUnknown), null);
}

return new TypeSyntaxAndMarshaling(PointerType(elementSyntax));
return new TypeSyntaxAndMarshaling(PointerType(elementTypeDetails.Type));
}

private bool TryGetElementTypeDefinition(Generator generator, out TypeDefinition typeDef)
Expand Down
Loading

0 comments on commit 6f1877f

Please sign in to comment.