diff --git a/global.json b/global.json index f8dd2c72..74940df1 100644 --- a/global.json +++ b/global.json @@ -5,6 +5,7 @@ "allowPrerelease": false }, "msbuild-sdks": { - "Microsoft.Build.NoTargets": "3.7.56" + "Microsoft.Build.NoTargets": "3.7.56", + "Microsoft.Windows.WinmdGenerator": "0.63.31-preview" } } diff --git a/src/Microsoft.Windows.CsWin32/ArrayTypeHandleInfo.cs b/src/Microsoft.Windows.CsWin32/ArrayTypeHandleInfo.cs index a42d1950..8d063542 100644 --- a/src/Microsoft.Windows.CsWin32/ArrayTypeHandleInfo.cs +++ b/src/Microsoft.Windows.CsWin32/ArrayTypeHandleInfo.cs @@ -7,7 +7,7 @@ internal record ArrayTypeHandleInfo(TypeHandleInfo ElementType, ArrayShape Shape { public override string ToString() => this.ToTypeSyntaxForDisplay().ToString(); - internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, CustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes) + internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, QualifiedCustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes) { TypeSyntaxAndMarshaling element = this.ElementType.ToTypeSyntax(inputs, forElement, customAttributes); if (inputs.AllowMarshaling || inputs.IsField) diff --git a/src/Microsoft.Windows.CsWin32/Generator.Com.cs b/src/Microsoft.Windows.CsWin32/Generator.Com.cs index b85c5185..56301a7d 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.Com.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.Com.cs @@ -51,18 +51,18 @@ private static Guid DecodeGuidFromAttribute(CustomAttribute guidAttribute) { TypeDefinition typeDef = this.Reader.GetTypeDefinition(typeDefHandle); var baseTypes = ImmutableStack.Create(); - (Generator Generator, InterfaceImplementationHandle Handle) baseTypeHandle = (this, typeDef.GetInterfaceImplementations().SingleOrDefault()); - while (!baseTypeHandle.Handle.IsNil) + (Generator Generator, InterfaceImplementationHandle Handle) baseInterfaceImplHandle = (this, typeDef.GetInterfaceImplementations().SingleOrDefault()); + while (!baseInterfaceImplHandle.Handle.IsNil) { - InterfaceImplementation baseTypeImpl = baseTypeHandle.Generator.Reader.GetInterfaceImplementation(baseTypeHandle.Handle); - if (!baseTypeHandle.Generator.TryGetTypeDefHandle((TypeReferenceHandle)baseTypeImpl.Interface, out QualifiedTypeDefinitionHandle baseTypeDefHandle)) + InterfaceImplementation baseTypeImpl = baseInterfaceImplHandle.Generator.Reader.GetInterfaceImplementation(baseInterfaceImplHandle.Handle); + if (!baseInterfaceImplHandle.Generator.TryGetTypeDefHandle((TypeReferenceHandle)baseTypeImpl.Interface, out QualifiedTypeDefinitionHandle baseTypeDefHandle)) { throw new GenerationFailedException("Failed to find base type."); } baseTypes = baseTypes.Push(baseTypeDefHandle); TypeDefinition baseType = baseTypeDefHandle.Reader.GetTypeDefinition(baseTypeDefHandle.DefinitionHandle); - baseTypeHandle = (baseTypeHandle.Generator, baseType.GetInterfaceImplementations().SingleOrDefault()); + baseInterfaceImplHandle = (baseTypeDefHandle.Generator, baseType.GetInterfaceImplementations().SingleOrDefault()); } if (this.IsNonCOMInterface(typeDef)) @@ -112,7 +112,7 @@ private TypeDeclarationSyntax DeclareInterfaceAsStruct(TypeDefinitionHandle type BlockSyntax populateVTableBody = Block(); IdentifierNameSyntax objectLocal = IdentifierName("__object"); IdentifierNameSyntax hrLocal = IdentifierName("__hr"); - StatementSyntax returnSOK = ReturnStatement(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, HresultTypeSyntax, IdentifierName("S_OK"))); + StatementSyntax returnSOK = ReturnStatement(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, this.HresultTypeSyntax, IdentifierName("S_OK"))); this.MainGenerator.RequestInteropType("Windows.Win32.Foundation", "HRESULT", context); @@ -143,10 +143,10 @@ private TypeDeclarationSyntax DeclareInterfaceAsStruct(TypeDefinitionHandle type declaredProperties.UnionWith( from method in allMethods group method by method.Generator into methodsByMetadata - let methodDefs = methodsByMetadata.Select(qh => qh.Reader.GetMethodDefinition(qh.MethodHandle)) + let methodDefs = methodsByMetadata.Select(qh => qh.Resolve()) from property in methodsByMetadata.Key.GetDeclarableProperties(methodDefs, originalIfaceName, allowNonConsecutiveAccessors: true, context) select property); - ISet? ifaceDeclaredProperties = ccwThisParameter is not null ? this.GetDeclarableProperties(allMethods.Select(qh => qh.Reader.GetMethodDefinition(qh.MethodHandle)), originalIfaceName, allowNonConsecutiveAccessors: false, context) : null; + ISet? ifaceDeclaredProperties = ccwThisParameter is not null ? this.GetDeclarableProperties(allMethods.Select(qh => qh.Resolve()), originalIfaceName, allowNonConsecutiveAccessors: false, context) : null; foreach (QualifiedMethodDefinitionHandle methodDefHandle in allMethods) { @@ -156,12 +156,12 @@ from property in methodsByMetadata.Key.GetDeclarableProperties(methodDefs, origi IdentifierNameSyntax innerMethodName = IdentifierName($"{methodName}_{methodCounter}"); LiteralExpressionSyntax methodOffset = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(methodCounter - 1)); - MethodSignature signature = methodDefinition.Method.DecodeSignature(SignatureHandleProvider.Instance, null); - CustomAttributeHandleCollection? returnTypeAttributes = methodDefinition.Generator.GetReturnTypeCustomAttributes(methodDefinition.Method); + MethodSignature signature = methodDefinition.Method.DecodeSignature(this.SignatureHandleProvider, null); + QualifiedCustomAttributeHandleCollection? returnTypeAttributes = methodDefinition.GetReturnTypeCustomAttributes(); TypeSyntax returnType = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.InterfaceAsStructMember, returnTypeAttributes).Type; TypeSyntax returnTypePreserveSig = returnType; - ParameterListSyntax parameterList = methodDefinition.Generator.CreateParameterList(methodDefinition.Method, signature, typeSettings with { Generator = methodDefinition.Generator }, GeneratingElement.InterfaceAsStructMember); + ParameterListSyntax parameterList = methodDefinition.Generator.CreateParameterList(methodDefinition.Method, signature, typeSettings, GeneratingElement.InterfaceAsStructMember); ParameterListSyntax parameterListPreserveSig = parameterList; // preserve a copy that has no mutations. bool requiresMarshaling = parameterList.Parameters.Any(p => p.AttributeLists.SelectMany(al => al.Attributes).Any(a => a.Name is IdentifierNameSyntax { Identifier.ValueText: "MarshalAs" }) || p.Modifiers.Any(SyntaxKind.RefKeyword) || p.Modifiers.Any(SyntaxKind.OutKeyword) || p.Modifiers.Any(SyntaxKind.InKeyword)); FunctionPointerParameterListSyntax funcPtrParameters = FunctionPointerParameterList() @@ -196,7 +196,7 @@ from property in methodsByMetadata.Key.GetDeclarableProperties(methodDefs, origi // We can declare this method as a property accessor if it represents a property. // We must also confirm that the property type is the same in both cases, because sometimes they aren't (e.g. IUIAutomationProxyFactoryEntry.ClassName). - if (methodDefinition.Generator.TryGetPropertyAccessorInfo(methodDefinition.Method, originalIfaceName, context, out IdentifierNameSyntax? propertyName, out SyntaxKind? accessorKind, out TypeSyntax? propertyType) && + if (methodDefinition.Generator.TryGetPropertyAccessorInfo(methodDefinition, originalIfaceName, context, out IdentifierNameSyntax? propertyName, out SyntaxKind? accessorKind, out TypeSyntax? propertyType) && declaredProperties.Contains(propertyName.Identifier.ValueText)) { StatementSyntax ThrowOnHRFailure(ExpressionSyntax hrExpression) => ExpressionStatement(InvocationExpression( @@ -337,12 +337,13 @@ StatementSyntax InvokeVtblAndThrow() => ExpressionStatement(InvocationExpression propertyOrMethod = methodDeclaration; - members.AddRange(methodDefinition.Generator.DeclareFriendlyOverloads(methodDefinition.Method, methodDeclaration, IdentifierName(ifaceName.Identifier.ValueText), FriendlyOverloadOf.StructMethod, helperMethodsInStruct)); + bool avoidWinmdRootAlias = this != methodDefinition.Generator; + members.AddRange(methodDefinition.Generator.DeclareFriendlyOverloads(methodDefinition.Method, methodDeclaration, IdentifierName(ifaceName.Identifier.ValueText), FriendlyOverloadOf.StructMethod, helperMethodsInStruct, avoidWinmdRootAlias)); } if (ccwThisParameter is not null && !ccwMethodsToSkip.Contains(methodDefHandle)) { - if (this.TryGetPropertyAccessorInfo(methodDefinition.Method, originalIfaceName, context, out propertyName, out accessorKind, out propertyType) && + if (this.TryGetPropertyAccessorInfo(methodDefinition, originalIfaceName, context, out propertyName, out accessorKind, out propertyType) && ifaceDeclaredProperties!.Contains(propertyName.Identifier.ValueText)) { switch (accessorKind) @@ -412,10 +413,10 @@ void AddCcwThunk(params StatementSyntax[] thunkInvokeAndReturn) bool hrReturnType = returnTypePreserveSig is QualifiedNameSyntax { Right.Identifier.ValueText: "HRESULT" }; //// HRESULT hr = ComHelpers.UnwrapCCW(@this, out Interface? @object); - LocalDeclarationStatementSyntax hrDecl = LocalDeclarationStatement(VariableDeclaration(HresultTypeSyntax).AddVariables( + LocalDeclarationStatementSyntax hrDecl = LocalDeclarationStatement(VariableDeclaration(this.HresultTypeSyntax).AddVariables( VariableDeclarator(hrLocal.Identifier).WithInitializer(EqualsValueClause( InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName("ComHelpers"), IdentifierName("UnwrapCCW")), + MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, QualifiedName(this.Win32NamespacePrefix, IdentifierName("ComHelpers")), IdentifierName("UnwrapCCW")), ArgumentList().AddArguments( Argument(pThisParameterName), Argument(DeclarationExpression(NestedCOMInterfaceName.WithTrailingTrivia(Space), SingleVariableDesignation(objectLocal.Identifier))).WithRefKindKeyword(Token(SyntaxKind.OutKeyword)))))))); @@ -433,7 +434,7 @@ void AddCcwThunk(params StatementSyntax[] thunkInvokeAndReturn) if (hrReturnType) { //// return (HRESULT)ex.HResult; - catchBlock = catchBlock.AddStatements(ReturnStatement(CastExpression(HresultTypeSyntax, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, exLocal, IdentifierName(nameof(Exception.HResult)))))); + catchBlock = catchBlock.AddStatements(ReturnStatement(CastExpression(this.HresultTypeSyntax, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, exLocal, IdentifierName(nameof(Exception.HResult)))))); } else { @@ -573,7 +574,7 @@ static ExpressionSyntax ThisPointer(PointerTypeSyntax? typedPointer = null) TypeSyntaxSettings typeSettings = this.comSignatureTypeSettings; // It is imperative that we generate methods for all base interfaces as well, ahead of any implemented by *this* interface. - var allMethods = new List(); + var allMethods = new List(); bool foundIUnknown = false; bool foundIDispatch = false; bool foundIInspectable = false; @@ -582,30 +583,30 @@ static ExpressionSyntax ThisPointer(PointerTypeSyntax? typedPointer = null) { QualifiedTypeDefinitionHandle baseTypeHandle = baseTypes.Peek(); baseTypes = baseTypes.Pop(); - TypeDefinition baseType = baseTypeHandle.Reader.GetTypeDefinition(baseTypeHandle.DefinitionHandle); + QualifiedTypeDefinition baseType = baseTypeHandle.Resolve(); if (!foundIUnknown) { - if (!baseTypeHandle.Reader.StringComparer.Equals(baseType.Name, "IUnknown")) + if (!baseTypeHandle.Reader.StringComparer.Equals(baseType.Definition.Name, "IUnknown")) { - throw new NotSupportedException("Unsupported base COM interface type: " + baseTypeHandle.Reader.GetString(baseType.Name)); + throw new NotSupportedException("Unsupported base COM interface type: " + baseTypeHandle.Reader.GetString(baseType.Definition.Name)); } foundIUnknown = true; } else { - if (baseTypeHandle.Reader.StringComparer.Equals(baseType.Name, "IDispatch")) + if (baseTypeHandle.Reader.StringComparer.Equals(baseType.Definition.Name, "IDispatch")) { foundIDispatch = true; } - else if (baseTypeHandle.Reader.StringComparer.Equals(baseType.Name, "IInspectable")) + else if (baseTypeHandle.Reader.StringComparer.Equals(baseType.Definition.Name, "IInspectable")) { foundIInspectable = true; } else { baseTypeHandle.Generator.RequestInteropType(baseTypeHandle.DefinitionHandle, context); - TypeSyntax baseTypeSyntax = new HandleTypeHandleInfo(baseTypeHandle.Reader, baseTypeHandle.DefinitionHandle).ToTypeSyntax(this.comSignatureTypeSettings, GeneratingElement.InterfaceMember, null).Type; + TypeSyntax baseTypeSyntax = new HandleTypeHandleInfo(baseTypeHandle.Generator, baseTypeHandle.Reader, baseTypeHandle.DefinitionHandle).ToTypeSyntax(this.comSignatureTypeSettings, GeneratingElement.InterfaceMember, null).Type; if (interfaceAsSubtype) { baseTypeSyntax = QualifiedName( @@ -614,13 +615,13 @@ static ExpressionSyntax ThisPointer(PointerTypeSyntax? typedPointer = null) } baseTypeSyntaxList.Add(SimpleBaseType(baseTypeSyntax)); - allMethods.AddRange(baseType.GetMethods()); + allMethods.AddRange(baseType.Definition.GetMethods().Select(methodHandle => new QualifiedMethodDefinitionHandle(baseType.Generator, methodHandle))); } } } int inheritedMethods = allMethods.Count; - allMethods.AddRange(typeDef.GetMethods()); + allMethods.AddRange(typeDef.GetMethods().Select(methodHandle => new QualifiedMethodDefinitionHandle(this, methodHandle))); AttributeSyntax ifaceType = InterfaceType( foundIInspectable ? ComInterfaceType.InterfaceIsIInspectable : @@ -630,12 +631,12 @@ static ExpressionSyntax ThisPointer(PointerTypeSyntax? typedPointer = null) var members = new List(); var friendlyOverloads = new List(); - ISet declaredProperties = this.GetDeclarableProperties(allMethods.Select(this.Reader.GetMethodDefinition), actualIfaceName, allowNonConsecutiveAccessors: false, context); + ISet declaredProperties = this.GetDeclarableProperties(allMethods.Select(method => method.Resolve()), actualIfaceName, allowNonConsecutiveAccessors: false, context); - foreach (MethodDefinitionHandle methodDefHandle in allMethods) + foreach (QualifiedMethodDefinitionHandle methodDefHandle in allMethods) { - MethodDefinition methodDefinition = this.Reader.GetMethodDefinition(methodDefHandle); - string methodName = this.Reader.GetString(methodDefinition.Name); + QualifiedMethodDefinition methodDefinition = methodDefHandle.Resolve(); + string methodName = methodDefinition.Reader.GetString(methodDefinition.Method.Name); inheritedMethods--; try { @@ -646,7 +647,7 @@ static ExpressionSyntax ThisPointer(PointerTypeSyntax? typedPointer = null) // Even if it could be represented as a property accessor, we cannot do so if a property by the same name was already declared in anything other than the previous row. // Adding an accessor to a property later than the very next row would screw up the virtual method table ordering. // We must also confirm that the property type is the same in both cases, because sometimes they aren't (e.g. IUIAutomationProxyFactoryEntry.ClassName). - if (this.TryGetPropertyAccessorInfo(methodDefinition, actualIfaceName, context, out IdentifierNameSyntax? propertyName, out SyntaxKind? accessorKind, out TypeSyntax? propertyType) && declaredProperties.Contains(propertyName.Identifier.ValueText)) + if (methodDefinition.Generator.TryGetPropertyAccessorInfo(methodDefinition, actualIfaceName, context, out IdentifierNameSyntax? propertyName, out SyntaxKind? accessorKind, out TypeSyntax? propertyType) && declaredProperties.Contains(propertyName.Identifier.ValueText)) { AccessorDeclarationSyntax accessor = AccessorDeclaration(accessorKind.Value).WithSemicolonToken(Semicolon); @@ -672,16 +673,16 @@ static ExpressionSyntax ThisPointer(PointerTypeSyntax? typedPointer = null) } else { - MethodSignature signature = methodDefinition.DecodeSignature(SignatureHandleProvider.Instance, null); + MethodSignature signature = methodDefinition.Method.DecodeSignature(this.SignatureHandleProvider, null); - CustomAttributeHandleCollection? returnTypeAttributes = this.GetReturnTypeCustomAttributes(methodDefinition); - TypeSyntaxAndMarshaling returnTypeDetails = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.InterfaceMember, returnTypeAttributes); + CustomAttributeHandleCollection? returnTypeAttributes = methodDefinition.Generator.GetReturnTypeCustomAttributes(methodDefinition.Method); + TypeSyntaxAndMarshaling returnTypeDetails = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.InterfaceMember, returnTypeAttributes?.QualifyWith(methodDefinition.Generator)); TypeSyntax returnType = returnTypeDetails.Type; AttributeSyntax? returnsAttribute = MarshalAs(returnTypeDetails.MarshalAsAttribute, returnTypeDetails.NativeArrayInfo); - ParameterListSyntax? parameterList = this.CreateParameterList(methodDefinition, signature, this.comSignatureTypeSettings, GeneratingElement.InterfaceMember); + ParameterListSyntax? parameterList = methodDefinition.Generator.CreateParameterList(methodDefinition.Method, signature, this.comSignatureTypeSettings, GeneratingElement.InterfaceMember); - bool preserveSig = interfaceAsSubtype || this.UsePreserveSigForComMethod(methodDefinition, signature, actualIfaceName, methodName); + bool preserveSig = interfaceAsSubtype || this.UsePreserveSigForComMethod(methodDefinition.Method, signature, actualIfaceName, methodName); if (!preserveSig) { ParameterSyntax? lastParameter = parameterList.Parameters.Count > 0 ? parameterList.Parameters[parameterList.Parameters.Count - 1] : null; @@ -732,9 +733,10 @@ static ExpressionSyntax ThisPointer(PointerTypeSyntax? typedPointer = null) if (methodDeclaration is not null) { + bool avoidWinmdRootAlias = this != methodDefinition.Generator; NameSyntax declaringTypeName = HandleTypeHandleInfo.GetNestingQualifiedName(this, this.Reader, typeDef, hasUnmanagedSuffix: false, isInterfaceNestedInStruct: interfaceAsSubtype); friendlyOverloads.AddRange( - this.DeclareFriendlyOverloads(methodDefinition, methodDeclaration, declaringTypeName, FriendlyOverloadOf.InterfaceMethod, this.injectedPInvokeHelperMethodsToFriendlyOverloadsExtensions)); + methodDefinition.Generator.DeclareFriendlyOverloads(methodDefinition.Method, methodDeclaration, declaringTypeName, FriendlyOverloadOf.InterfaceMethod, this.injectedPInvokeHelperMethodsToFriendlyOverloadsExtensions, avoidWinmdRootAlias)); } } catch (Exception ex) @@ -801,7 +803,7 @@ private unsafe (IReadOnlyList Members, IReadOnlyList GetDeclarableProperties(IEnumerable methods, string ifaceName, bool allowNonConsecutiveAccessors, Context context) + private ISet GetDeclarableProperties(IEnumerable methods, string ifaceName, bool allowNonConsecutiveAccessors, Context context) { Dictionary goodProperties = new(StringComparer.Ordinal); HashSet badProperties = new(StringComparer.Ordinal); int rowIndex = -1; - foreach (MethodDefinition methodDefinition in methods) + foreach (QualifiedMethodDefinition methodDefinition in methods) { rowIndex++; - if (this.TryGetPropertyAccessorInfo(methodDefinition, ifaceName, context, out IdentifierNameSyntax? propertyName, out SyntaxKind? accessorKind, out TypeSyntax? propertyType)) + if (methodDefinition.Generator.TryGetPropertyAccessorInfo(methodDefinition, ifaceName, context, out IdentifierNameSyntax? propertyName, out SyntaxKind? accessorKind, out TypeSyntax? propertyType)) { if (badProperties.Contains(propertyName.Identifier.ValueText)) { @@ -931,11 +933,12 @@ void ReportBadProperty() return goodProperties.Count == 0 ? ImmutableHashSet.Empty : new HashSet(goodProperties.Keys, StringComparer.Ordinal); } - private bool TryGetPropertyAccessorInfo(MethodDefinition methodDefinition, string ifaceName, Context context, [NotNullWhen(true)] out IdentifierNameSyntax? propertyName, [NotNullWhen(true)] out SyntaxKind? accessorKind, [NotNullWhen(true)] out TypeSyntax? propertyType) + private bool TryGetPropertyAccessorInfo(QualifiedMethodDefinition qmd, string ifaceName, Context context, [NotNullWhen(true)] out IdentifierNameSyntax? propertyName, [NotNullWhen(true)] out SyntaxKind? accessorKind, [NotNullWhen(true)] out TypeSyntax? propertyType) { propertyName = null; accessorKind = null; propertyType = null; + MethodDefinition methodDefinition = qmd.Method; TypeSyntaxSettings syntaxSettings = context.Filter(this.comSignatureTypeSettings); if ((methodDefinition.Attributes & MethodAttributes.SpecialName) != MethodAttributes.SpecialName) @@ -952,7 +955,7 @@ private bool TryGetPropertyAccessorInfo(MethodDefinition methodDefinition, strin return false; } - MethodSignature signature = methodDefinition.DecodeSignature(SignatureHandleProvider.Instance, null); + MethodSignature signature = methodDefinition.DecodeSignature(this.SignatureHandleProvider, null); string methodName = this.Reader.GetString(methodDefinition.Name); if (this.UsePreserveSigForComMethod(methodDefinition, signature, ifaceName, methodName)) { @@ -979,9 +982,9 @@ private bool TryGetPropertyAccessorInfo(MethodDefinition methodDefinition, strin return false; } - Parameter propertyTypeParameter = this.Reader.GetParameter(parameters.Skip(1).Single()); + Parameter propertyTypeParameter = qmd.Reader.GetParameter(parameters.Skip(1).Single()); TypeHandleInfo propertyTypeInfo = signature.ParameterTypes[0]; - propertyType = propertyTypeInfo.ToTypeSyntax(syntaxSettings, GeneratingElement.Property, propertyTypeParameter.GetCustomAttributes(), propertyTypeParameter.Attributes).Type; + propertyType = propertyTypeInfo.ToTypeSyntax(syntaxSettings, GeneratingElement.Property, propertyTypeParameter.GetCustomAttributes().QualifyWith(qmd.Generator), propertyTypeParameter.Attributes).Type; if (isGetter) { diff --git a/src/Microsoft.Windows.CsWin32/Generator.Constant.cs b/src/Microsoft.Windows.CsWin32/Generator.Constant.cs index e1df607f..61e7e060 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.Constant.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.Constant.cs @@ -139,7 +139,7 @@ internal void RequestConstant(FieldDefinitionHandle fieldDefHandle) FieldDefinition fieldDef = this.Reader.GetFieldDefinition(fieldDefHandle); FieldDeclarationSyntax constantDeclaration = this.DeclareConstant(fieldDef); - TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null) with { IsConstantField = true }; + TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(this.SignatureHandleProvider, null) with { IsConstantField = true }; TypeDefinitionHandle? fieldType = null; if (fieldTypeInfo is HandleTypeHandleInfo handleInfo && this.IsTypeDefStruct(handleInfo) && handleInfo.Handle.Kind == HandleKind.TypeReference) { @@ -213,7 +213,7 @@ ReadOnlyMemory TrimCurlyBraces(ReadOnlyMemory arg) MethodDefinition methodDef = this.Reader.GetMethodDefinition(methodDefHandle); if (this.Reader.StringComparer.Equals(methodDef.Name, ".ctor") && methodDef.GetParameters().Count == args.Count) { - MethodSignature ctorSignature = methodDef.DecodeSignature(SignatureHandleProvider.Instance, null); + MethodSignature ctorSignature = methodDef.DecodeSignature(this.SignatureHandleProvider, null); var argExpressions = new ArgumentSyntax[args.Count]; for (int i = 0; i < args.Count; i++) @@ -245,7 +245,7 @@ ReadOnlyMemory TrimCurlyBraces(ReadOnlyMemory arg) { FieldDefinition fieldDef = this.Reader.GetFieldDefinition(fieldDefHandle); string fieldName = this.Reader.GetString(fieldDef.Name); - TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null) with { IsConstantField = true }; + TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(this.SignatureHandleProvider, null) with { IsConstantField = true }; fieldAssignmentExpressions[i] = AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentifierName(fieldName), @@ -354,9 +354,9 @@ private FieldDeclarationSyntax DeclareConstant(FieldDefinition fieldDef) string name = this.Reader.GetString(fieldDef.Name); try { - TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null) with { IsConstantField = true }; + TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(this.SignatureHandleProvider, null) with { IsConstantField = true }; CustomAttributeHandleCollection customAttributes = fieldDef.GetCustomAttributes(); - TypeSyntaxAndMarshaling fieldType = fieldTypeInfo.ToTypeSyntax(this.fieldTypeSettings, GeneratingElement.Constant, customAttributes); + TypeSyntaxAndMarshaling fieldType = fieldTypeInfo.ToTypeSyntax(this.fieldTypeSettings, GeneratingElement.Constant, customAttributes.QualifyWith(this)); bool requiresUnsafe = false; ExpressionSyntax value = fieldDef.GetDefaultValue() is { IsNil: false } constantHandle ? ToExpressionSyntax(this.Reader, constantHandle) : diff --git a/src/Microsoft.Windows.CsWin32/Generator.Delegate.cs b/src/Microsoft.Windows.CsWin32/Generator.Delegate.cs index 7600aba5..3cb8d5b0 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.Delegate.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.Delegate.cs @@ -54,7 +54,7 @@ private DelegateDeclarationSyntax DeclareDelegate(TypeDefinition typeDef) } this.GetSignatureForDelegate(typeDef, out MethodDefinition invokeMethodDef, out MethodSignature signature, out CustomAttributeHandleCollection? returnTypeAttributes); - TypeSyntaxAndMarshaling returnValue = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.Delegate, returnTypeAttributes); + TypeSyntaxAndMarshaling returnValue = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.Delegate, returnTypeAttributes?.QualifyWith(this)); DelegateDeclarationSyntax result = DelegateDeclaration(returnValue.Type, Identifier(name)) .WithParameterList(FixTrivia(this.CreateParameterList(invokeMethodDef, signature, typeSettings, GeneratingElement.Delegate))) @@ -113,7 +113,7 @@ private MemberDeclarationSyntax DeclareUntypedDelegate(TypeDefinition typeDef) private void GetSignatureForDelegate(TypeDefinition typeDef, out MethodDefinition invokeMethodDef, out MethodSignature signature, out CustomAttributeHandleCollection? returnTypeAttributes) { invokeMethodDef = typeDef.GetMethods().Select(this.Reader.GetMethodDefinition).Single(def => this.Reader.StringComparer.Equals(def.Name, "Invoke")); - signature = invokeMethodDef.DecodeSignature(SignatureHandleProvider.Instance, null); + signature = invokeMethodDef.DecodeSignature(this.SignatureHandleProvider, null); returnTypeAttributes = this.GetReturnTypeCustomAttributes(invokeMethodDef); } @@ -149,6 +149,6 @@ private FunctionPointerParameterSyntax TranslateDelegateToFunctionPointer(TypeHa return FunctionPointerParameter(delegateTypeDef.Generator.FunctionPointer(delegateTypeDef.Definition)); } - return FunctionPointerParameter(parameterTypeInfo.ToTypeSyntax(this.functionPointerTypeSettings, GeneratingElement.FunctionPointer, customAttributeHandles).GetUnmarshaledType()); + return FunctionPointerParameter(parameterTypeInfo.ToTypeSyntax(this.functionPointerTypeSettings, GeneratingElement.FunctionPointer, customAttributeHandles?.QualifyWith(this)).GetUnmarshaledType()); } } diff --git a/src/Microsoft.Windows.CsWin32/Generator.Enum.cs b/src/Microsoft.Windows.CsWin32/Generator.Enum.cs index 456a18e8..18f9bcd6 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.Enum.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.Enum.cs @@ -65,7 +65,7 @@ void AddEnumValue(FieldDefinitionHandle fieldDefHandle) ConstantHandle valueHandle = fieldDef.GetDefaultValue(); if (valueHandle.IsNil) { - enumBaseType = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null).ToTypeSyntax(this.enumTypeSettings, GeneratingElement.EnumValue, null).Type; + enumBaseType = fieldDef.DecodeSignature(this.SignatureHandleProvider, null).ToTypeSyntax(this.enumTypeSettings, GeneratingElement.EnumValue, null).Type; return; } diff --git a/src/Microsoft.Windows.CsWin32/Generator.Extern.cs b/src/Microsoft.Windows.CsWin32/Generator.Extern.cs index 3d51cc64..62a9b36b 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.Extern.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.Extern.cs @@ -184,11 +184,11 @@ private void DeclareExternMethod(MethodDefinitionHandle methodDefinitionHandle) // If this method releases a handle, recreate the method signature such that we take the struct rather than the SafeHandle as a parameter. TypeSyntaxSettings typeSettings = this.MetadataIndex.ReleaseMethods.Contains(entrypoint ?? methodName) ? this.externReleaseSignatureTypeSettings : this.externSignatureTypeSettings; - MethodSignature signature = methodDefinition.DecodeSignature(SignatureHandleProvider.Instance, null); + MethodSignature signature = methodDefinition.DecodeSignature(this.SignatureHandleProvider, null); bool requiresUnicodeCharSet = signature.ParameterTypes.Any(p => p is PrimitiveTypeHandleInfo { PrimitiveTypeCode: PrimitiveTypeCode.Char }); CustomAttributeHandleCollection? returnTypeAttributes = this.GetReturnTypeCustomAttributes(methodDefinition); - TypeSyntaxAndMarshaling returnType = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.ExternMethod, returnTypeAttributes, ParameterAttributes.Out); + TypeSyntaxAndMarshaling returnType = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.ExternMethod, returnTypeAttributes?.QualifyWith(this), ParameterAttributes.Out); // Search for any enum substitutions. TypeSyntax? returnTypeEnumName = this.FindAssociatedEnum(returnTypeAttributes); @@ -355,7 +355,7 @@ static SyntaxToken RefInOutKeyword(ParameterSyntax p) => // Add documentation if we can find it. exposedMethod = this.AddApiDocumentation(entrypoint ?? methodName, exposedMethod); - this.volatileCode.AddMemberToModule(moduleName, this.DeclareFriendlyOverloads(methodDefinition, exposedMethod, this.methodsAndConstantsClassName, FriendlyOverloadOf.ExternMethod, this.injectedPInvokeHelperMethods)); + this.volatileCode.AddMemberToModule(moduleName, this.DeclareFriendlyOverloads(methodDefinition, exposedMethod, this.methodsAndConstantsClassName, FriendlyOverloadOf.ExternMethod, this.injectedPInvokeHelperMethods, avoidWinmdRootAlias: false)); this.volatileCode.AddMemberToModule(moduleName, exposedMethod); } catch (Exception ex) diff --git a/src/Microsoft.Windows.CsWin32/Generator.FriendlyOverloads.cs b/src/Microsoft.Windows.CsWin32/Generator.FriendlyOverloads.cs index a01a58da..718dba24 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.FriendlyOverloads.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.FriendlyOverloads.cs @@ -14,7 +14,7 @@ private enum FriendlyOverloadOf InterfaceMethod, } - private IEnumerable DeclareFriendlyOverloads(MethodDefinition methodDefinition, MethodDeclarationSyntax externMethodDeclaration, NameSyntax declaringTypeName, FriendlyOverloadOf overloadOf, HashSet helperMethodsAdded) + private IEnumerable DeclareFriendlyOverloads(MethodDefinition methodDefinition, MethodDeclarationSyntax externMethodDeclaration, NameSyntax declaringTypeName, FriendlyOverloadOf overloadOf, HashSet helperMethodsAdded, bool avoidWinmdRootAlias) { if (!this.options.FriendlyOverloads.Enabled) { @@ -59,7 +59,12 @@ private IEnumerable DeclareFriendlyOverloads(MethodDefi _ => throw new NotSupportedException(overloadOf.ToString()), }; - MethodSignature originalSignature = methodDefinition.DecodeSignature(SignatureHandleProvider.Instance, null); + if (avoidWinmdRootAlias) + { + parameterTypeSyntaxSettings = parameterTypeSyntaxSettings with { AvoidWinmdRootAlias = true }; + } + + MethodSignature originalSignature = methodDefinition.DecodeSignature(this.SignatureHandleProvider, null); CustomAttributeHandleCollection? returnTypeAttributes = null; var parameters = externMethodDeclaration.ParameterList.Parameters.Select(StripAttributes).ToList(); var lengthParamUsedBy = new Dictionary(); @@ -105,7 +110,7 @@ private IEnumerable DeclareFriendlyOverloads(MethodDefi TypeHandleInfo parameterTypeInfo = originalSignature.ParameterTypes[param.SequenceNumber - 1]; bool isManagedParameterType = this.IsManagedType(parameterTypeInfo); - bool mustRemainAsPointer = parameterTypeInfo is PointerTypeHandleInfo { ElementType: HandleTypeHandleInfo pointedElement } && this.IsStructWithFlexibleArray(pointedElement); + bool mustRemainAsPointer = parameterTypeInfo is PointerTypeHandleInfo { ElementType: HandleTypeHandleInfo pointedElement } && pointedElement.Generator.IsStructWithFlexibleArray(pointedElement); IdentifierNameSyntax origName = IdentifierName(externParam.Identifier.ValueText); @@ -146,7 +151,7 @@ private IEnumerable DeclareFriendlyOverloads(MethodDefi bool hasOut = externParam.Modifiers.Any(SyntaxKind.OutKeyword); arguments[param.SequenceNumber - 1] = arguments[param.SequenceNumber - 1].WithRefKindKeyword(TokenWithSpace(hasOut ? SyntaxKind.OutKeyword : SyntaxKind.RefKeyword)); } - else if (isOut && !isIn && !isReleaseMethod && parameterTypeInfo is PointerTypeHandleInfo { ElementType: HandleTypeHandleInfo pointedElementInfo } && this.TryGetHandleReleaseMethod(pointedElementInfo.Handle, paramAttributes, out string? outReleaseMethod) && !this.Reader.StringComparer.Equals(methodDefinition.Name, outReleaseMethod)) + else if (isOut && !isIn && !isReleaseMethod && parameterTypeInfo is PointerTypeHandleInfo { ElementType: HandleTypeHandleInfo pointedElementInfo } && pointedElementInfo.Generator.TryGetHandleReleaseMethod(pointedElementInfo.Handle, paramAttributes, out string? outReleaseMethod) && !this.Reader.StringComparer.Equals(methodDefinition.Name, outReleaseMethod)) { if (this.RequestSafeHandle(outReleaseMethod) is TypeSyntax safeHandleType) { @@ -668,7 +673,7 @@ bool TryHandleCountParam(TypeSyntax elementType, bool nullableSource) } TypeSyntax? returnSafeHandleType = originalSignature.ReturnType is HandleTypeHandleInfo returnTypeHandleInfo - && this.TryGetHandleReleaseMethod(returnTypeHandleInfo.Handle, returnTypeAttributes, out string? returnReleaseMethod) + && returnTypeHandleInfo.Generator.TryGetHandleReleaseMethod(returnTypeHandleInfo.Handle, returnTypeAttributes, out string? returnReleaseMethod) ? this.RequestSafeHandle(returnReleaseMethod) : null; SyntaxToken friendlyMethodName = externMethodDeclaration.Identifier; @@ -794,7 +799,7 @@ bool TryHandleCountParam(TypeSyntax elementType, bool nullableSource) // If we're using C# 13 or later, consider adding the overload resolution attribute if it would likely resolve ambiguities. if (this.LanguageVersion >= (LanguageVersion)1300 && parameters.Count == externMethodDeclaration.ParameterList.Parameters.Count) { - this.DeclareOverloadResolutionPriorityAttributeIfNecessary(); + this.volatileCode.GenerationTransaction(() => this.DeclareOverloadResolutionPriorityAttributeIfNecessary()); friendlyDeclaration = friendlyDeclaration.AddAttributeLists(AttributeList().AddAttributes(OverloadResolutionPriorityAttribute(1))); } diff --git a/src/Microsoft.Windows.CsWin32/Generator.Handle.cs b/src/Microsoft.Windows.CsWin32/Generator.Handle.cs index aa1d628e..96045b82 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.Handle.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.Handle.cs @@ -36,9 +36,9 @@ public partial class Generator string releaseMethodModule = this.GetNormalizedModuleName(releaseMethodDef.GetImport()); IdentifierNameSyntax? safeHandleTypeIdentifier = IdentifierName(safeHandleClassName); - safeHandleType = safeHandleTypeIdentifier; + safeHandleType = QualifiedName(ParseName($"global::{this.Namespace}"), safeHandleTypeIdentifier); - MethodSignature releaseMethodSignature = releaseMethodDef.DecodeSignature(SignatureHandleProvider.Instance, null); + MethodSignature releaseMethodSignature = releaseMethodDef.DecodeSignature(this.SignatureHandleProvider, null); TypeHandleInfo releaseMethodParameterTypeHandleInfo = releaseMethodSignature.ParameterTypes[0]; TypeSyntaxAndMarshaling releaseMethodParameterType = releaseMethodParameterTypeHandleInfo.ToTypeSyntax(this.externSignatureTypeSettings, GeneratingElement.HelperClassMember, default); @@ -60,7 +60,10 @@ public partial class Generator safeHandleType = null; } - this.volatileCode.AddSafeHandleNameForReleaseMethod(releaseMethod, safeHandleType); + this.volatileCode.GenerationTransaction(delegate + { + this.volatileCode.AddSafeHandleNameForReleaseMethod(releaseMethod, safeHandleType); + }); if (safeHandleType is null) { @@ -72,7 +75,10 @@ public partial class Generator return safeHandleType; } - this.RequestExternMethod(releaseMethodHandle.Value); + this.volatileCode.GenerationTransaction(delegate + { + this.RequestExternMethod(releaseMethodHandle.Value); + }); // Collect all the known invalid values for this handle. // If no invalid values are given (e.g. BSTR), we'll just assume 0 is invalid. @@ -80,7 +86,7 @@ public partial class Generator IntPtr preferredInvalidValue = GetPreferredInvalidHandleValue(invalidHandleValues, new IntPtr(-1)); CustomAttributeHandleCollection? atts = this.GetReturnTypeCustomAttributes(releaseMethodDef); - TypeSyntaxAndMarshaling releaseMethodReturnType = releaseMethodSignature.ReturnType.ToTypeSyntax(this.externSignatureTypeSettings, GeneratingElement.HelperClassMember, atts); + TypeSyntaxAndMarshaling releaseMethodReturnType = releaseMethodSignature.ReturnType.ToTypeSyntax(this.externSignatureTypeSettings, GeneratingElement.HelperClassMember, atts?.QualifyWith(this)); this.TryGetRenamedMethod(releaseMethod, out string? renamedReleaseMethod); @@ -257,7 +263,11 @@ public partial class Generator /// ")); - this.volatileCode.AddSafeHandleType(safeHandleDeclaration); + this.volatileCode.GenerationTransaction(delegate + { + this.volatileCode.AddSafeHandleType(safeHandleDeclaration); + }); + return safeHandleType; } catch (Exception ex) diff --git a/src/Microsoft.Windows.CsWin32/Generator.InlineArrays.cs b/src/Microsoft.Windows.CsWin32/Generator.InlineArrays.cs index 5038c780..16f64803 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.InlineArrays.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.InlineArrays.cs @@ -731,7 +731,7 @@ StatementSyntax ClearSlice(ExpressionSyntax span) => } else { - qualifiedElementType = fieldTypeHandleInfo.ToTypeSyntax(this.extensionMethodSignatureTypeSettings, GeneratingElement.Other, customAttributes).Type switch + qualifiedElementType = fieldTypeHandleInfo.ToTypeSyntax(this.extensionMethodSignatureTypeSettings, GeneratingElement.Other, customAttributes.QualifyWith(this)).Type switch { ArrayTypeSyntax at => at.ElementType, PointerTypeSyntax ptrType => ptrType.ElementType, diff --git a/src/Microsoft.Windows.CsWin32/Generator.Invariants.cs b/src/Microsoft.Windows.CsWin32/Generator.Invariants.cs index a96a6908..61e5b685 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.Invariants.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.Invariants.cs @@ -312,8 +312,6 @@ public partial class Generator AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(ThisAssembly.AssemblyName))), AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(ThisAssembly.AssemblyInformationalVersion))))); - private static readonly TypeSyntax HresultTypeSyntax = QualifiedName(QualifiedName(IdentifierName(GlobalWinmdRootNamespaceAlias), IdentifierName("Foundation")), IdentifierName("HRESULT")); - /// /// Gets the set of macros that can be generated. /// @@ -340,4 +338,16 @@ public partial class Generator .Add("IUnknown", "This COM interface is implicit in the runtime. Interfaces that derive from it should apply the [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] attribute instead.") .Add("IDispatch", "This COM interface is implicit in the runtime. Interfaces that derive from it should apply the [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] attribute instead.") .Add("VARIANT", "Use `object` instead of VARIANT when in COM interface mode. VARIANT can only be emitted when emitting COM interfaces as structs."); + + private string Win32NamespacePrefixString => this.IsWin32Sdk ? GlobalWinmdRootNamespaceAlias : "global::Windows.Win32"; + + private IdentifierNameSyntax Win32NamespacePrefix => IdentifierName(this.Win32NamespacePrefixString); + + private TypeSyntax HresultTypeSyntax + { + get + { + return QualifiedName(QualifiedName(this.Win32NamespacePrefix, IdentifierName("Foundation")), IdentifierName("HRESULT")); + } + } } diff --git a/src/Microsoft.Windows.CsWin32/Generator.MetadataHelpers.cs b/src/Microsoft.Windows.CsWin32/Generator.MetadataHelpers.cs index a993188e..a7992342 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.MetadataHelpers.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.MetadataHelpers.cs @@ -148,14 +148,14 @@ internal bool IsInterface(HandleTypeHandleInfo typeInfo) if (typeInfo.Handle.Kind == HandleKind.TypeReference) { var trh = (TypeReferenceHandle)typeInfo.Handle; - this.TryGetTypeDefHandle(trh, out tdh); + typeInfo.Generator.TryGetTypeDefHandle(trh, out tdh); } else if (typeInfo.Handle.Kind == HandleKind.TypeDefinition) { tdh = (TypeDefinitionHandle)typeInfo.Handle; } - return !tdh.IsNil && (this.Reader.GetTypeDefinition(tdh).Attributes & TypeAttributes.Interface) == TypeAttributes.Interface; + return !tdh.IsNil && (typeInfo.Reader.GetTypeDefinition(tdh).Attributes & TypeAttributes.Interface) == TypeAttributes.Interface; } internal bool IsInterface(TypeHandleInfo handleInfo) @@ -187,7 +187,7 @@ internal bool IsInterface(TypeReferenceHandle typeRefHandle) internal bool IsStructWithFlexibleArray(HandleTypeHandleInfo typeInfo) { - return this.TryGetTypeDefHandle(typeInfo.Handle, out QualifiedTypeDefinitionHandle typeHandle) + return typeInfo.Generator.TryGetTypeDefHandle(typeInfo.Handle, out QualifiedTypeDefinitionHandle typeHandle) && typeHandle.Generator.IsStructWithFlexibleArray(typeHandle.DefinitionHandle); } @@ -220,20 +220,20 @@ internal bool IsManagedType(TypeHandleInfo typeHandleInfo) { return false; } - else if (elementType is HandleTypeHandleInfo { Handle: { Kind: HandleKind.TypeDefinition } typeDefHandle }) + else if (elementType is HandleTypeHandleInfo { Handle: { Kind: HandleKind.TypeDefinition } typeDefHandle } handleTypeDef) { - return this.IsManagedType((TypeDefinitionHandle)typeDefHandle); + return handleTypeDef.Generator.IsManagedType((TypeDefinitionHandle)typeDefHandle); } else if (elementType is HandleTypeHandleInfo { Handle: { Kind: HandleKind.TypeReference } typeRefHandle } handleElement) { var trh = (TypeReferenceHandle)typeRefHandle; - if (this.TryGetTypeDefHandle(trh, out QualifiedTypeDefinitionHandle qtdr)) + if (handleElement.Generator.TryGetTypeDefHandle(trh, out QualifiedTypeDefinitionHandle qtdr)) { return qtdr.Generator.IsManagedType(qtdr.DefinitionHandle); } // If the type comes from an external assembly, assume that structs are blittable and anything else is not. - TypeReference tr = this.Reader.GetTypeReference(trh); + TypeReference tr = handleElement.Reader.GetTypeReference(trh); if (tr.ResolutionScope.Kind == HandleKind.AssemblyReference && handleElement.RawTypeKind is byte kind) { // Structs set 0x1, classes set 0x2. @@ -244,6 +244,24 @@ internal bool IsManagedType(TypeHandleInfo typeHandleInfo) throw new GenerationFailedException("Unrecognized type: " + elementType.GetType().Name); } + internal CustomAttributeHandleCollection? GetReturnTypeCustomAttributes(MethodDefinition methodDefinition) + { + CustomAttributeHandleCollection? returnTypeAttributes = null; + foreach (ParameterHandle parameterHandle in methodDefinition.GetParameters()) + { + Parameter parameter = this.Reader.GetParameter(parameterHandle); + if (parameter.Name.IsNil) + { + returnTypeAttributes = parameter.GetCustomAttributes(); + } + + // What we're looking for would always be the first element in the collection. + break; + } + + return returnTypeAttributes; + } + private static bool IsWideFunction(string methodName) { if (methodName.Length > 1 && methodName.EndsWith("W", StringComparison.Ordinal) && char.IsLower(methodName[methodName.Length - 2])) @@ -398,7 +416,7 @@ private bool IsManagedType(TypeDefinitionHandle typeDefinitionHandle) FieldDefinition fieldDef = this.Reader.GetFieldDefinition(fieldHandle); try { - TypeHandleInfo fieldType = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null); + TypeHandleInfo fieldType = fieldDef.DecodeSignature(this.SignatureHandleProvider, null); TypeHandleInfo elementType = fieldType; while (elementType is ITypeHandleContainer container) { @@ -484,9 +502,13 @@ private bool IsManagedType(TypeDefinitionHandle typeDefinitionHandle) throw new NotSupportedException(); } + catch (GenerationFailedException) + { + throw; + } catch (Exception ex) { - throw new GenerationFailedException($"Unable to determine if {new HandleTypeHandleInfo(this.Reader, typeDefinitionHandle).ToTypeSyntax(this.errorMessageTypeSettings, GeneratingElement.Other, null)} is a managed type.", ex); + throw new GenerationFailedException($"Unable to determine if {new HandleTypeHandleInfo(this, this.Reader, typeDefinitionHandle).ToTypeSyntax(this.errorMessageTypeSettings, GeneratingElement.Other, null)} is a managed type.", ex); } } } @@ -507,24 +529,6 @@ private bool IsManagedType(TypeDefinitionHandle typeDefinitionHandle) private bool HasObsoleteAttribute(CustomAttributeHandleCollection attributes) => this.FindAttribute(attributes, nameof(System), nameof(ObsoleteAttribute)).HasValue; - private CustomAttributeHandleCollection? GetReturnTypeCustomAttributes(MethodDefinition methodDefinition) - { - CustomAttributeHandleCollection? returnTypeAttributes = null; - foreach (ParameterHandle parameterHandle in methodDefinition.GetParameters()) - { - Parameter parameter = this.Reader.GetParameter(parameterHandle); - if (parameter.Name.IsNil) - { - returnTypeAttributes = parameter.GetCustomAttributes(); - } - - // What we're looking for would always be the first element in the collection. - break; - } - - return returnTypeAttributes; - } - private bool IsUntypedDelegate(TypeDefinition typeDef) => IsUntypedDelegate(this.Reader, typeDef); private bool IsTypeDefStruct(TypeDefinition typeDef) => this.FindInteropDecorativeAttribute(typeDef.GetCustomAttributes(), NativeTypedefAttribute).HasValue || this.FindInteropDecorativeAttribute(typeDef.GetCustomAttributes(), MetadataTypedefAttribute).HasValue; diff --git a/src/Microsoft.Windows.CsWin32/Generator.Struct.cs b/src/Microsoft.Windows.CsWin32/Generator.Struct.cs index 966c4218..ee16615f 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.Struct.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.Struct.cs @@ -85,8 +85,8 @@ private StructDeclarationSyntax DeclareStruct(TypeDefinitionHandle typeDefHandle } else if (fieldDefHandle == flexibleArrayFieldHandle) { - CustomAttributeHandleCollection fieldAttributes = fieldDef.GetCustomAttributes(); - var fieldTypeInfo = (ArrayTypeHandleInfo)fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null); + QualifiedCustomAttributeHandleCollection fieldAttributes = fieldDef.GetCustomAttributes().QualifyWith(this); + var fieldTypeInfo = (ArrayTypeHandleInfo)fieldDef.DecodeSignature(this.SignatureHandleProvider, null); TypeSyntax fieldType = fieldTypeInfo.ElementType.ToTypeSyntax(typeSettings, GeneratingElement.StructMember, fieldAttributes).Type; if (fieldType is PointerTypeSyntax or FunctionPointerTypeSyntax) @@ -129,7 +129,7 @@ private StructDeclarationSyntax DeclareStruct(TypeDefinitionHandle typeDefHandle else { CustomAttributeHandleCollection fieldAttributes = fieldDef.GetCustomAttributes(); - TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null); + TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(this.SignatureHandleProvider, null); hasUtf16CharField |= fieldTypeInfo is PrimitiveTypeHandleInfo { PrimitiveTypeCode: PrimitiveTypeCode.Char }; TypeSyntaxSettings thisFieldTypeSettings = typeSettings; @@ -152,7 +152,7 @@ private StructDeclarationSyntax DeclareStruct(TypeDefinitionHandle typeDefHandle } } - TypeSyntaxAndMarshaling fieldTypeSyntax = fieldTypeInfo.ToTypeSyntax(thisFieldTypeSettings, GeneratingElement.StructMember, fieldAttributes); + TypeSyntaxAndMarshaling fieldTypeSyntax = fieldTypeInfo.ToTypeSyntax(thisFieldTypeSettings, GeneratingElement.StructMember, fieldAttributes.QualifyWith(this)); (TypeSyntax FieldType, SyntaxList AdditionalMembers, AttributeSyntax? MarshalAsAttribute) fieldInfo = this.ReinterpretFieldType(fieldDef, fieldTypeSyntax.Type, fieldAttributes, context); additionalMembers = additionalMembers.AddRange(fieldInfo.AdditionalMembers); @@ -215,7 +215,7 @@ private StructDeclarationSyntax DeclareStruct(TypeDefinitionHandle typeDefHandle foreach (CustomAttribute bitfieldAttribute in MetadataUtilities.FindAttributes(this.Reader, fieldDef.GetCustomAttributes(), InteropDecorationNamespace, NativeBitfieldAttribute)) { - var fieldTypeInfo = (PrimitiveTypeHandleInfo)fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null); + var fieldTypeInfo = (PrimitiveTypeHandleInfo)fieldDef.DecodeSignature(this.SignatureHandleProvider, null); CustomAttributeValue decodedAttribute = bitfieldAttribute.DecodeValue(CustomAttributeTypeProvider.Instance); (int? fieldBitLength, bool signed) = fieldTypeInfo.PrimitiveTypeCode switch @@ -514,7 +514,7 @@ private MethodDeclarationSyntax DeclareSizeOfMethod(TypeSyntax structType, TypeS private (TypeSyntax FieldType, SyntaxList AdditionalMembers, AttributeSyntax? MarshalAsAttribute) ReinterpretFieldType(FieldDefinition fieldDef, TypeSyntax originalType, CustomAttributeHandleCollection customAttributes, Context context) { TypeSyntaxSettings typeSettings = context.Filter(this.fieldTypeSettings); - TypeHandleInfo fieldTypeHandleInfo = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null); + TypeHandleInfo fieldTypeHandleInfo = fieldDef.DecodeSignature(this.SignatureHandleProvider, null); AttributeSyntax? marshalAs = null; // If the field is a fixed length array, we have to work some code gen magic since C# does not allow those. diff --git a/src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs b/src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs index d827e344..5ab1a2a4 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs @@ -29,7 +29,7 @@ bool Resolve(TypeDefinitionHandle tdh, [NotNullWhen(true)] out TypeHandleInfo? f foreach (FieldDefinitionHandle fdh in td.GetFields()) { FieldDefinition fd = this.Reader.GetFieldDefinition(fdh); - fieldType = fd.DecodeSignature(SignatureHandleProvider.Instance, null); + fieldType = fd.DecodeSignature(this.SignatureHandleProvider, null); return true; } @@ -98,8 +98,8 @@ private StructDeclarationSyntax DeclareTypeDefStruct(TypeDefinition typeDef, Typ IdentifierNameSyntax fieldIdentifierName = SafeIdentifierName(fieldName); VariableDeclaratorSyntax fieldDeclarator = VariableDeclarator(fieldIdentifierName.Identifier); CustomAttributeHandleCollection fieldAttributes = fieldDef.GetCustomAttributes(); - TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null); - TypeSyntaxAndMarshaling fieldType = fieldTypeInfo.ToTypeSyntax(typeSettings, GeneratingElement.Field, fieldAttributes); + TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(this.SignatureHandleProvider, null); + TypeSyntaxAndMarshaling fieldType = fieldTypeInfo.ToTypeSyntax(typeSettings, GeneratingElement.Field, fieldAttributes.QualifyWith(this)); (TypeSyntax FieldType, SyntaxList AdditionalMembers, AttributeSyntax? _) fieldInfo = this.ReinterpretFieldType(fieldDef, fieldType.Type, fieldAttributes, this.DefaultContext); SyntaxList members = List(); diff --git a/src/Microsoft.Windows.CsWin32/Generator.cs b/src/Microsoft.Windows.CsWin32/Generator.cs index f67cdfc4..a00dec7f 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.cs @@ -86,6 +86,7 @@ public Generator(string metadataLibraryPath, Docs? docs, IEnumerable add } MetadataFile metadataFile = MetadataCache.Default.GetMetadataFile(metadataLibraryPath); + this.SignatureHandleProvider = new(this); this.MetadataIndex = metadataFile.GetMetadataIndex(compilation?.Options.Platform); this.metadataReader = metadataFile.GetMetadataReader(); @@ -286,6 +287,8 @@ internal Generator MainGenerator internal MetadataIndex MetadataIndex { get; } + internal SignatureHandleProvider SignatureHandleProvider { get; } + internal MetadataReader Reader => this.metadataReader.Value; internal LanguageVersion LanguageVersion => this.parseOptions?.LanguageVersion ?? LanguageVersion.CSharp9; @@ -923,7 +926,10 @@ internal void RequestComHelpers(Context context) } else if (this.SuperGenerator is not null && this.SuperGenerator.TryGetGenerator("Windows.Win32", out Generator? generator)) { - generator.RequestComHelpers(context); + generator.volatileCode.GenerationTransaction(delegate + { + generator.RequestComHelpers(context); + }); } } @@ -966,46 +972,49 @@ internal void RequestInteropType(string @namespace, string name, Context context internal void RequestInteropType(TypeDefinitionHandle typeDefHandle, Context context) { - TypeDefinition typeDef = this.Reader.GetTypeDefinition(typeDefHandle); - if (typeDef.GetDeclaringType() is { IsNil: false } nestingParentHandle) - { - // We should only generate this type into its parent type. - this.RequestInteropType(nestingParentHandle, context); - return; - } - - string ns = this.Reader.GetString(typeDef.Namespace); - if (!this.IsCompatibleWithPlatform(typeDef.GetCustomAttributes())) + this.volatileCode.GenerationTransaction(delegate { - // We've been asked for an interop type that does not apply. This happens because the metadata - // may use a TypeReferenceHandle or TypeDefinitionHandle to just one of many arch-specific definitions of this type. - // Try to find the appropriate definition for our target architecture. - string name = this.Reader.GetString(typeDef.Name); - NamespaceMetadata namespaceMetadata = this.MetadataIndex.MetadataByNamespace[ns]; - if (!namespaceMetadata.Types.TryGetValue(name, out typeDefHandle) && namespaceMetadata.TypesForOtherPlatform.Contains(name)) + TypeDefinition typeDef = this.Reader.GetTypeDefinition(typeDefHandle); + if (typeDef.GetDeclaringType() is { IsNil: false } nestingParentHandle) { - throw new PlatformIncompatibleException($"Request for type ({ns}.{name}) that is not available given the target platform."); + // We should only generate this type into its parent type. + this.RequestInteropType(nestingParentHandle, context); + return; } - } - bool hasUnmanagedName = this.HasUnmanagedSuffix(this.Reader, typeDef.Name, context.AllowMarshaling, this.IsManagedType(typeDefHandle)); - this.volatileCode.GenerateType(typeDefHandle, hasUnmanagedName, delegate - { - if (this.RequestInteropTypeHelper(typeDefHandle, context) is MemberDeclarationSyntax typeDeclaration) + string ns = this.Reader.GetString(typeDef.Namespace); + if (!this.IsCompatibleWithPlatform(typeDef.GetCustomAttributes())) { - if (!this.TryStripCommonNamespace(ns, out string? shortNamespace)) + // We've been asked for an interop type that does not apply. This happens because the metadata + // may use a TypeReferenceHandle or TypeDefinitionHandle to just one of many arch-specific definitions of this type. + // Try to find the appropriate definition for our target architecture. + string name = this.Reader.GetString(typeDef.Name); + NamespaceMetadata namespaceMetadata = this.MetadataIndex.MetadataByNamespace[ns]; + if (!namespaceMetadata.Types.TryGetValue(name, out typeDefHandle) && namespaceMetadata.TypesForOtherPlatform.Contains(name)) { - throw new GenerationFailedException("Unexpected namespace: " + ns); + throw new PlatformIncompatibleException($"Request for type ({ns}.{name}) that is not available given the target platform."); } + } - if (shortNamespace.Length > 0) + bool hasUnmanagedName = this.HasUnmanagedSuffix(this.Reader, typeDef.Name, context.AllowMarshaling, this.IsManagedType(typeDefHandle)); + this.volatileCode.GenerateType(typeDefHandle, hasUnmanagedName, delegate + { + if (this.RequestInteropTypeHelper(typeDefHandle, context) is MemberDeclarationSyntax typeDeclaration) { - typeDeclaration = typeDeclaration.WithAdditionalAnnotations( - new SyntaxAnnotation(NamespaceContainerAnnotation, shortNamespace)); - } + if (!this.TryStripCommonNamespace(ns, out string? shortNamespace)) + { + throw new GenerationFailedException("Unexpected namespace: " + ns); + } - this.volatileCode.AddInteropType(typeDefHandle, hasUnmanagedName, typeDeclaration); - } + if (shortNamespace.Length > 0) + { + typeDeclaration = typeDeclaration.WithAdditionalAnnotations( + new SyntaxAnnotation(NamespaceContainerAnnotation, shortNamespace)); + } + + this.volatileCode.AddInteropType(typeDefHandle, hasUnmanagedName, typeDeclaration); + } + }); }); } @@ -1161,6 +1170,20 @@ internal void GetBaseTypeInfo(TypeDefinition typeDef, out StringHandle baseTypeN internal string GetMangledIdentifier(string normalIdentifier, bool allowMarshaling, bool isManagedType) => this.HasUnmanagedSuffix(normalIdentifier, allowMarshaling, isManagedType) ? normalIdentifier + UnmanagedInteropSuffix : normalIdentifier; + internal Generator GetGeneratorFromReader(MetadataReader reader) + { + if (this.SuperGenerator is object) + { + return this.SuperGenerator.GetGeneratorFromReader(reader); + } + else if (reader == this.Reader) + { + return this; + } + + throw new InvalidOperationException("Encountered a reader not associated with an active generator"); + } + /// /// Disposes of managed and unmanaged resources. /// @@ -1469,7 +1492,7 @@ private ParameterSyntax CreateParameter(TypeHandleInfo parameterInfo, Parameter // TODO: // * Notice [Out][RAIIFree] handle producing parameters. Can we make these provide SafeHandle's? bool isReturnOrOutParam = parameter.SequenceNumber == 0 || (parameter.Attributes & ParameterAttributes.Out) == ParameterAttributes.Out; - TypeSyntaxAndMarshaling parameterTypeSyntax = parameterInfo.ToTypeSyntax(typeSettings, forElement, parameter.GetCustomAttributes(), parameter.Attributes); + TypeSyntaxAndMarshaling parameterTypeSyntax = parameterInfo.ToTypeSyntax(typeSettings, forElement, parameter.GetCustomAttributes().QualifyWith(this), parameter.Attributes); // Determine the custom attributes to apply. AttributeListSyntax? attributes = AttributeList(); diff --git a/src/Microsoft.Windows.CsWin32/HandleTypeHandleInfo.cs b/src/Microsoft.Windows.CsWin32/HandleTypeHandleInfo.cs index 732e345f..53b6f8b2 100644 --- a/src/Microsoft.Windows.CsWin32/HandleTypeHandleInfo.cs +++ b/src/Microsoft.Windows.CsWin32/HandleTypeHandleInfo.cs @@ -6,14 +6,16 @@ namespace Microsoft.Windows.CsWin32; internal record HandleTypeHandleInfo : TypeHandleInfo { private readonly MetadataReader reader; + private readonly Generator generator; // We just want to see that the identifier starts with I, followed by another upper case letter, // followed by a lower case letter. All the WinRT interfaces will match this, and none of the WinRT // objects will match it private static readonly System.Text.RegularExpressions.Regex InterfaceNameMatcher = new System.Text.RegularExpressions.Regex("^I[A-Z][a-z]"); - internal HandleTypeHandleInfo(MetadataReader reader, EntityHandle handle, byte? rawTypeKind = null) + internal HandleTypeHandleInfo(Generator generator, MetadataReader reader, EntityHandle handle, byte? rawTypeKind = null) { + this.generator = generator; this.reader = reader; this.Handle = handle; this.RawTypeKind = rawTypeKind; @@ -21,6 +23,10 @@ internal HandleTypeHandleInfo(MetadataReader reader, EntityHandle handle, byte? internal EntityHandle Handle { get; } + internal MetadataReader Reader => this.reader; + + internal Generator Generator => this.generator; + internal byte? RawTypeKind { get; } public override string ToString() => this.ToTypeSyntaxForDisplay().ToString(); @@ -70,12 +76,13 @@ internal bool IsType(string leafName) } } - internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, CustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes = default) + internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, QualifiedCustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes = default) { NameSyntax? nameSyntax; bool isInterface; bool isNonCOMConformingInterface; - bool isManagedType = inputs.Generator?.IsManagedType(this) ?? false; + + bool isManagedType = this.generator.IsManagedType(this); QualifiedTypeDefinitionHandle? qtdh = default; switch (this.Handle.Kind) { @@ -85,23 +92,20 @@ internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs string simpleNameSuffix = hasUnmanagedSuffix ? Generator.UnmanagedInteropSuffix : string.Empty; nameSyntax = inputs.QualifyNames ? GetNestingQualifiedName(inputs.Generator, this.reader, td, hasUnmanagedSuffix, isInterfaceNestedInStruct: false) : IdentifierName(this.reader.GetString(td.Name) + simpleNameSuffix); isInterface = (td.Attributes & TypeAttributes.Interface) == TypeAttributes.Interface; - isNonCOMConformingInterface = isInterface && inputs.Generator?.IsNonCOMInterface(td) is true; - qtdh = inputs.Generator is not null ? new QualifiedTypeDefinitionHandle(inputs.Generator, (TypeDefinitionHandle)this.Handle) : default; + isNonCOMConformingInterface = isInterface && this.generator.IsNonCOMInterface(td) is true; + qtdh = new QualifiedTypeDefinitionHandle(this.generator, (TypeDefinitionHandle)this.Handle); break; case HandleKind.TypeReference: var trh = (TypeReferenceHandle)this.Handle; TypeReference tr = this.reader.GetTypeReference(trh); - hasUnmanagedSuffix = inputs.Generator?.HasUnmanagedSuffix(this.reader, tr.Name, inputs.AllowMarshaling, isManagedType) ?? false; + hasUnmanagedSuffix = inputs.Generator?.HasUnmanagedSuffix(this.Reader, tr.Name, inputs.AllowMarshaling, isManagedType) ?? false; simpleNameSuffix = hasUnmanagedSuffix ? Generator.UnmanagedInteropSuffix : string.Empty; nameSyntax = inputs.QualifyNames ? GetNestingQualifiedName(inputs, this.reader, tr, hasUnmanagedSuffix) : IdentifierName(this.reader.GetString(tr.Name) + simpleNameSuffix); - isInterface = inputs.Generator?.IsInterface(trh) is true; - isNonCOMConformingInterface = isInterface && inputs.Generator?.IsNonCOMInterface(trh) is true; - if (inputs.Generator is not null) + isInterface = this.generator.IsInterface(trh) is true; + isNonCOMConformingInterface = isInterface && this.generator.IsNonCOMInterface(trh) is true; + if (this.generator.TryGetTypeDefHandle(this.Handle, out QualifiedTypeDefinitionHandle qtdhTmp)) { - if (inputs.Generator.TryGetTypeDefHandle(this.Handle, out QualifiedTypeDefinitionHandle qtdhTmp)) - { - qtdh = qtdhTmp; - } + qtdh = qtdhTmp; } break; @@ -131,8 +135,8 @@ internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs if (simpleName is "PWSTR" or "PSTR") { - bool isConst = this.IsConstantField || MetadataUtilities.FindAttribute(this.reader, customAttributes, Generator.InteropDecorationNamespace, "ConstAttribute").HasValue; - bool isEmptyStringTerminatedList = MetadataUtilities.FindAttribute(this.reader, customAttributes, Generator.InteropDecorationNamespace, "NullNullTerminatedAttribute").HasValue; + bool isConst = this.IsConstantField || ((customAttributes is object) && MetadataUtilities.FindAttribute(customAttributes.Value.Reader, customAttributes.Value.Collection, Generator.InteropDecorationNamespace, "ConstAttribute").HasValue); + bool isEmptyStringTerminatedList = (customAttributes is object) && MetadataUtilities.FindAttribute(customAttributes.Value.Reader, customAttributes.Value.Collection, Generator.InteropDecorationNamespace, "NullNullTerminatedAttribute").HasValue; string constChar = isConst ? "C" : string.Empty; string listChars = isEmptyStringTerminatedList ? "ZZ" : string.Empty; string nameEnding = simpleName.Substring(1); @@ -146,7 +150,7 @@ internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs } else { - this.RequestTypeGeneration(inputs.Generator, this.GetContext(inputs)); + this.RequestTypeGeneration(this.GetContext(inputs)); } } else @@ -164,7 +168,7 @@ internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs } else { - this.RequestTypeGeneration(inputs.Generator, this.GetContext(inputs)); + this.RequestTypeGeneration(this.GetContext(inputs)); } if (isDelegate) @@ -207,7 +211,7 @@ internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs internal override bool? IsValueType(TypeSyntaxSettings inputs) { - Generator generator = inputs.Generator ?? throw new ArgumentException("Generator required."); + Generator generator = this.generator; TypeDefinitionHandle typeDefHandle = default; switch (this.Handle.Kind) { @@ -301,12 +305,12 @@ private static NameSyntax GetNestingQualifiedName(TypeSyntaxSettings inputs, Met private bool IsDelegate(TypeSyntaxSettings inputs, out QualifiedTypeDefinition delegateTypeDef) { TypeDefinitionHandle tdh = default; - Generator? generator = inputs.Generator; + Generator generator = this.generator; switch (this.Handle.Kind) { - case HandleKind.TypeReference when inputs.Generator is not null: + case HandleKind.TypeReference when generator is not null: var trHandle = (TypeReferenceHandle)this.Handle; - if (inputs.Generator.TryGetTypeDefHandle(trHandle, out QualifiedTypeDefinitionHandle qtdh)) + if (generator.TryGetTypeDefHandle(trHandle, out QualifiedTypeDefinitionHandle qtdh)) { tdh = qtdh.DefinitionHandle; generator = qtdh.Generator; @@ -339,15 +343,15 @@ private bool IsDelegate(TypeSyntaxSettings inputs, out QualifiedTypeDefinition d return false; } - private void RequestTypeGeneration(Generator? generator, Generator.Context context) + private void RequestTypeGeneration(Generator.Context context) { if (this.Handle.Kind == HandleKind.TypeDefinition) { - generator?.RequestInteropType((TypeDefinitionHandle)this.Handle, context); + this.generator.RequestInteropType((TypeDefinitionHandle)this.Handle, context); } else if (this.Handle.Kind == HandleKind.TypeReference) { - generator?.RequestInteropType((TypeReferenceHandle)this.Handle, context); + this.generator.RequestInteropType((TypeReferenceHandle)this.Handle, context); } } } diff --git a/src/Microsoft.Windows.CsWin32/MetadataIndex.cs b/src/Microsoft.Windows.CsWin32/MetadataIndex.cs index 39db44c1..1297c928 100644 --- a/src/Microsoft.Windows.CsWin32/MetadataIndex.cs +++ b/src/Microsoft.Windows.CsWin32/MetadataIndex.cs @@ -155,7 +155,7 @@ void PopulateNamespace(NamespaceDefinition ns, string? parentNamespace) fieldEnum.MoveNext(); FieldDefinitionHandle fieldHandle = fieldEnum.Current; FieldDefinition fieldDef = mr.GetFieldDefinition(fieldHandle); - if (fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null) is PrimitiveTypeHandleInfo { PrimitiveTypeCode: PrimitiveTypeCode.IntPtr or PrimitiveTypeCode.UIntPtr }) + if (fieldDef.DecodeSignature(PrimitiveSignatureHandleProvider.Instance, null) is PrimitiveTypeHandleInfo { PrimitiveTypeCode: PrimitiveTypeCode.IntPtr or PrimitiveTypeCode.UIntPtr }) { this.handleTypeStructsWithIntPtrSizeFields.Add(typeName); } diff --git a/src/Microsoft.Windows.CsWin32/MetadataQualifiedTokens.cs b/src/Microsoft.Windows.CsWin32/MetadataQualifiedTokens.cs index 3047303d..0f550ba2 100644 --- a/src/Microsoft.Windows.CsWin32/MetadataQualifiedTokens.cs +++ b/src/Microsoft.Windows.CsWin32/MetadataQualifiedTokens.cs @@ -37,4 +37,68 @@ internal record struct QualifiedMethodDefinitionHandle(Generator Generator, Meth internal record struct QualifiedMethodDefinition(Generator Generator, MethodDefinition Method) { internal MetadataReader Reader => this.Generator.Reader; + + internal StringHandle Name => this.Method.Name; + + internal QualifiedCustomAttributeHandleCollection? GetReturnTypeCustomAttributes() => this.Generator.GetReturnTypeCustomAttributes(this.Method)?.QualifyWith(this.Generator); + + internal IEnumerable GetParameters() + { + foreach (ParameterHandle parameterHandle in this.Method.GetParameters()) + { + yield return new QualifiedParameterHandle(this.Generator, parameterHandle); + } + } + + internal QualifiedCustomAttributeHandleCollection GetCustomAttributes() => this.Method.GetCustomAttributes().QualifyWith(this.Generator); +} + +internal record struct QualifiedCustomAttributeHandle(Generator Generator, CustomAttributeHandle CustomAttributeHandle) +{ + internal MetadataReader Reader => this.Generator.Reader; + + internal QualifiedCustomAttribute Resolve() => new(this.Generator, this.Generator.Reader.GetCustomAttribute(this.CustomAttributeHandle)); +} + +internal record struct QualifiedParameterHandle(Generator Generator, ParameterHandle ParameterHandle) +{ + internal MetadataReader Reader => this.Generator.Reader; + + internal QualifiedParameter Resolve() => new(this.Generator, this.Generator.Reader.GetParameter(this.ParameterHandle)); +} + +internal record struct QualifiedParameter(Generator Generator, Parameter Parameter) +{ + internal MetadataReader Reader => this.Generator.Reader; +} + +internal record struct QualifiedCustomAttributeHandleCollection(Generator Generator, CustomAttributeHandleCollection Collection) : IEnumerable +{ + internal MetadataReader Reader => this.Generator.Reader; + + public IEnumerator GetEnumerator() + { + foreach (CustomAttributeHandle handle in this.Collection) + { + yield return new QualifiedCustomAttributeHandle(this.Generator, handle); + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => this.GetEnumerator(); +} + +internal record struct QualifiedCustomAttribute(Generator Generator, CustomAttribute Attribute) +{ + internal MetadataReader Reader => this.Generator.Reader; +} + +internal static class QualifiedExtensions +{ + internal static QualifiedMethodDefinition QualifyWith(this MethodDefinition method, Generator generator) => new(generator, method); + + internal static QualifiedParameter QualifyWith(this Parameter parameter, Generator generator) => new(generator, parameter); + + internal static QualifiedParameterHandle QualifyWith(this ParameterHandle parameterHandle, Generator generator) => new(generator, parameterHandle); + + internal static QualifiedCustomAttributeHandleCollection QualifyWith(this CustomAttributeHandleCollection collection, Generator generator) => new(generator, collection); } diff --git a/src/Microsoft.Windows.CsWin32/PointerTypeHandleInfo.cs b/src/Microsoft.Windows.CsWin32/PointerTypeHandleInfo.cs index b49266f4..19a52c6a 100644 --- a/src/Microsoft.Windows.CsWin32/PointerTypeHandleInfo.cs +++ b/src/Microsoft.Windows.CsWin32/PointerTypeHandleInfo.cs @@ -7,9 +7,9 @@ internal record PointerTypeHandleInfo(TypeHandleInfo ElementType) : TypeHandleIn { public override string ToString() => this.ToTypeSyntaxForDisplay().ToString(); - internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, CustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes = default) + internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, QualifiedCustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes = default) { - Generator.NativeArrayInfo? nativeArrayInfo = customAttributes.HasValue ? inputs.Generator?.FindNativeArrayInfoAttribute(customAttributes.Value) : null; + Generator.NativeArrayInfo? nativeArrayInfo = customAttributes.HasValue ? customAttributes.Value.Generator.FindNativeArrayInfoAttribute(customAttributes.Value.Collection) : null; // We can't marshal a pointer exposed as a field, unless it's a pointer to an array. if (inputs.AllowMarshaling && inputs.IsField && (customAttributes is null || nativeArrayInfo is null)) @@ -19,7 +19,7 @@ internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs bool xOptional = (parameterAttributes & ParameterAttributes.Optional) == ParameterAttributes.Optional; bool mustUsePointers = xOptional && forElement == Generator.GeneratingElement.InterfaceMember && nativeArrayInfo is null; - mustUsePointers |= this.ElementType is HandleTypeHandleInfo handleElementType && inputs.Generator?.IsStructWithFlexibleArray(handleElementType) is true; + mustUsePointers |= this.ElementType is HandleTypeHandleInfo handleElementType && handleElementType.Generator.IsStructWithFlexibleArray(handleElementType) is true; if (mustUsePointers) { // Disable marshaling because pointers to optional parameters cannot be passed by reference when used as parameters of a COM interface method. @@ -56,7 +56,7 @@ inputs with { if (elementTypeDetails.Type is PredefinedTypeSyntax { Keyword: { RawKind: (int)SyntaxKind.ObjectKeyword } } && inputs.Generator is not null && inputs.Generator.Options.ComInterop.UseIntPtrForComOutPointers) { - bool isComOutPtr = inputs.Generator.FindInteropDecorativeAttribute(customAttributes, "ComOutPtrAttribute").HasValue; + bool isComOutPtr = customAttributes?.Generator.FindInteropDecorativeAttribute(customAttributes.Value.Collection, "ComOutPtrAttribute").HasValue ?? false; return new TypeSyntaxAndMarshaling(IdentifierName(nameof(IntPtr))) { ParameterModifier = Token(SyntaxKind.OutKeyword), @@ -88,7 +88,7 @@ inputs with elementTypeDetails.NativeArrayInfo); } } - else if (inputs.AllowMarshaling && inputs.Generator?.FindInteropDecorativeAttribute(customAttributes, "ComOutPtrAttribute") is not null) + else if (inputs.AllowMarshaling && customAttributes is object && customAttributes.Value.Generator.FindInteropDecorativeAttribute(customAttributes.Value.Collection, "ComOutPtrAttribute") is not null) { return new TypeSyntaxAndMarshaling(PredefinedType(Token(SyntaxKind.ObjectKeyword)), new MarshalAsAttribute(UnmanagedType.IUnknown), null); } diff --git a/src/Microsoft.Windows.CsWin32/PrimitiveSignatureHandleProvider.cs b/src/Microsoft.Windows.CsWin32/PrimitiveSignatureHandleProvider.cs new file mode 100644 index 00000000..579d7e72 --- /dev/null +++ b/src/Microsoft.Windows.CsWin32/PrimitiveSignatureHandleProvider.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Windows.CsWin32; + +// Like SignatureHandleProvider, but has no generator so can't bind complex types to a Generator. +internal class PrimitiveSignatureHandleProvider : ISignatureTypeProvider +{ + internal static readonly PrimitiveSignatureHandleProvider Instance = new(); + + internal PrimitiveSignatureHandleProvider() + { + } + + internal interface IGenericContext + { + } + + public TypeHandleInfo GetArrayType(TypeHandleInfo elementType, ArrayShape shape) => new ArrayTypeHandleInfo(elementType, shape); + + public TypeHandleInfo GetPointerType(TypeHandleInfo elementType) => new PointerTypeHandleInfo(elementType); + + public TypeHandleInfo GetPrimitiveType(PrimitiveTypeCode typeCode) => new PrimitiveTypeHandleInfo(typeCode); + + public TypeHandleInfo GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) => throw new NotImplementedException(); + + public TypeHandleInfo GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) => throw new NotImplementedException(); + + /// + public TypeHandleInfo GetSZArrayType(TypeHandleInfo elementType) => throw new NotImplementedException(); + + /// + public TypeHandleInfo GetTypeFromSpecification(MetadataReader reader, IGenericContext? genericContext, TypeSpecificationHandle handle, byte rawTypeKind) => throw new NotImplementedException(); + + /// + public TypeHandleInfo GetByReferenceType(TypeHandleInfo elementType) => throw new NotImplementedException(); + + /// + public TypeHandleInfo GetFunctionPointerType(MethodSignature signature) => throw new NotImplementedException(); + + /// + public TypeHandleInfo GetGenericInstantiation(TypeHandleInfo genericType, ImmutableArray typeArguments) => throw new NotImplementedException(); + + /// + public TypeHandleInfo GetGenericMethodParameter(IGenericContext? genericContext, int index) => throw new NotImplementedException(); + + /// + public TypeHandleInfo GetGenericTypeParameter(IGenericContext? genericContext, int index) => throw new NotImplementedException(); + + /// + public TypeHandleInfo GetModifiedType(TypeHandleInfo modifier, TypeHandleInfo unmodifiedType, bool isRequired) => throw new NotImplementedException(); + + /// + public TypeHandleInfo GetPinnedType(TypeHandleInfo elementType) => throw new NotImplementedException(); +} diff --git a/src/Microsoft.Windows.CsWin32/PrimitiveTypeHandleInfo.cs b/src/Microsoft.Windows.CsWin32/PrimitiveTypeHandleInfo.cs index 13fba407..bc68cf17 100644 --- a/src/Microsoft.Windows.CsWin32/PrimitiveTypeHandleInfo.cs +++ b/src/Microsoft.Windows.CsWin32/PrimitiveTypeHandleInfo.cs @@ -7,14 +7,14 @@ internal record PrimitiveTypeHandleInfo(PrimitiveTypeCode PrimitiveTypeCode) : T { public override string ToString() => this.ToTypeSyntaxForDisplay().ToString(); - internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, CustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes) + internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, QualifiedCustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes) { // We want to expose the enum type when there is one, but doing it *properly* requires marshaling to the underlying type. // The length of the enum may differ from the length of the primitive type, which means we can't just use the enum type directly. // Even if the lengths match, if the enum's underlying base type conflicts with the primitive's signed type (e.g. int != uint), // certain CPU architectures can fail as well. // So we just have to use the primitive type when marshaling is not allowed. - if (inputs.AllowMarshaling && inputs.Generator?.FindAssociatedEnum(customAttributes) is NameSyntax enumTypeName && inputs.Generator.TryGenerateType(enumTypeName.ToString(), out IReadOnlyCollection preciseMatch)) + if (inputs.AllowMarshaling && customAttributes?.Generator.FindAssociatedEnum(customAttributes.Value.Collection) is NameSyntax enumTypeName && inputs.Generator!.TryGenerateType(enumTypeName.ToString(), out IReadOnlyCollection preciseMatch)) { // Use the qualified name. enumTypeName = ParseName(Generator.ReplaceCommonNamespaceWithAlias(inputs.Generator, preciseMatch.First())); diff --git a/src/Microsoft.Windows.CsWin32/SignatureHandleProvider.cs b/src/Microsoft.Windows.CsWin32/SignatureHandleProvider.cs index fa3c2be3..5b85395d 100644 --- a/src/Microsoft.Windows.CsWin32/SignatureHandleProvider.cs +++ b/src/Microsoft.Windows.CsWin32/SignatureHandleProvider.cs @@ -5,10 +5,11 @@ namespace Microsoft.Windows.CsWin32; internal class SignatureHandleProvider : ISignatureTypeProvider { - internal static readonly SignatureHandleProvider Instance = new SignatureHandleProvider(); + private readonly Generator generator; - private SignatureHandleProvider() + internal SignatureHandleProvider(Generator generator) { + this.generator = generator; } internal interface IGenericContext @@ -21,9 +22,9 @@ internal interface IGenericContext public TypeHandleInfo GetPrimitiveType(PrimitiveTypeCode typeCode) => new PrimitiveTypeHandleInfo(typeCode); - public TypeHandleInfo GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) => new HandleTypeHandleInfo(reader, handle, rawTypeKind); + public TypeHandleInfo GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) => new HandleTypeHandleInfo(this.generator.GetGeneratorFromReader(reader), reader, handle, rawTypeKind); - public TypeHandleInfo GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) => new HandleTypeHandleInfo(reader, handle, rawTypeKind); + public TypeHandleInfo GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) => new HandleTypeHandleInfo(this.generator.GetGeneratorFromReader(reader), reader, handle, rawTypeKind); /// public TypeHandleInfo GetSZArrayType(TypeHandleInfo elementType) => throw new NotImplementedException(); diff --git a/src/Microsoft.Windows.CsWin32/SuperGenerator.cs b/src/Microsoft.Windows.CsWin32/SuperGenerator.cs index b184c4f7..c22f7e12 100644 --- a/src/Microsoft.Windows.CsWin32/SuperGenerator.cs +++ b/src/Microsoft.Windows.CsWin32/SuperGenerator.cs @@ -250,6 +250,11 @@ internal bool TryGetGenerator(string winmdName, [NotNullWhen(true)] out Generato return this.Generators.TryGetValue(winmdName, out targetGenerator); } + internal Generator GetGeneratorFromReader(MetadataReader reader) + { + return this.Generators.FirstOrDefault(kv => kv.Value.Reader == reader).Value ?? throw new InvalidOperationException("No generator found for the specified reader."); + } + internal bool TryGetTypeDefinitionHandle(QualifiedTypeReferenceHandle typeRefHandle, out QualifiedTypeDefinitionHandle typeDefHandle) { if (typeRefHandle.Generator.TryGetTypeDefHandle(typeRefHandle.ReferenceHandle, out TypeDefinitionHandle localHandle)) diff --git a/src/Microsoft.Windows.CsWin32/TypeHandleInfo.cs b/src/Microsoft.Windows.CsWin32/TypeHandleInfo.cs index 44c8c53e..50bdc2c9 100644 --- a/src/Microsoft.Windows.CsWin32/TypeHandleInfo.cs +++ b/src/Microsoft.Windows.CsWin32/TypeHandleInfo.cs @@ -9,7 +9,7 @@ internal abstract record TypeHandleInfo internal bool IsConstantField { get; init; } - internal abstract TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, CustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes = default); + internal abstract TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, QualifiedCustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes = default); internal abstract bool? IsValueType(TypeSyntaxSettings inputs); diff --git a/test/CustomIInspectable/.gitignore b/test/CustomIInspectable/.gitignore new file mode 100644 index 00000000..376677dc --- /dev/null +++ b/test/CustomIInspectable/.gitignore @@ -0,0 +1 @@ +*.winmd diff --git a/test/CustomIInspectable/CustomIInspectable.csproj b/test/CustomIInspectable/CustomIInspectable.csproj new file mode 100644 index 00000000..d3988a9d --- /dev/null +++ b/test/CustomIInspectable/CustomIInspectable.csproj @@ -0,0 +1,45 @@ + + + + + false + + + netstandard2.0 + false + false + + CustomIInspectable.winmd + 255.255.255.255 + 10.0.19041.0 + true + + + + + + + + + $(AdditionalIncludes);$(Pkg_MicrosoftWindowsSDKCPP)\c\Include\10.0.22621.0\shared + $(AdditionalIncludes);$(CompiledHeadersDir) + + + + + + + + + + + + + + @(TraverseFiles) + CustomIInspectable + + + + + diff --git a/test/CustomIInspectable/CustomIInspectable.idl b/test/CustomIInspectable/CustomIInspectable.idl new file mode 100644 index 00000000..d24efa05 --- /dev/null +++ b/test/CustomIInspectable/CustomIInspectable.idl @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +import "objidl.idl"; +import "inspectable.idl"; + +cpp_quote("#ifdef __cplusplus") +cpp_quote("namespace TestApis {") +cpp_quote("#endif // __cplusplus") + +[local, object, uuid(03861681-b74a-4581-8648-2a2cee7d8a8a)] +interface ITestDerivedFromInspectable : IInspectable +{ + [annotation("_Pre_satisfies_(*pHandleToAttach != nullptr) " + "_Post_satisfies_(*pHandleToAttach == nullptr) " + "_On_failure_(_Unchanged_(*pHandleToAttach))")] + HRESULT CreateAndAttachHandle( + [in, annotation("_Inout_")] HANDLE* pHandleToAttach, + [in] REFIID iid, + [out, iid_is(iid), annotation("_COM_Outptr_")] void** ppv); + + HRESULT CreateWithDuplicatedHandle( + [in, annotation("_In_")] HANDLE handleToDuplicate, + [in] REFIID iid, + [out, iid_is(iid), annotation("_COM_Outptr_")] void** ppv); +}; + +cpp_quote("#ifdef __cplusplus") +cpp_quote("} ") +cpp_quote("#endif // __cplusplus") + diff --git a/test/CustomIInspectable/Directory.Build.props b/test/CustomIInspectable/Directory.Build.props new file mode 100644 index 00000000..eb0ea2d3 --- /dev/null +++ b/test/CustomIInspectable/Directory.Build.props @@ -0,0 +1,5 @@ + + + + + diff --git a/test/CustomIInspectable/Directory.Build.targets b/test/CustomIInspectable/Directory.Build.targets new file mode 100644 index 00000000..eb0ea2d3 --- /dev/null +++ b/test/CustomIInspectable/Directory.Build.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/test/CustomIInspectable/Directory.Packages.props b/test/CustomIInspectable/Directory.Packages.props new file mode 100644 index 00000000..07811bb8 --- /dev/null +++ b/test/CustomIInspectable/Directory.Packages.props @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/CustomIInspectable/main.cpp b/test/CustomIInspectable/main.cpp new file mode 100644 index 00000000..0cf064b7 --- /dev/null +++ b/test/CustomIInspectable/main.cpp @@ -0,0 +1 @@ +#include diff --git a/test/CustomIInspectable/readme.md b/test/CustomIInspectable/readme.md new file mode 100644 index 00000000..2e991965 --- /dev/null +++ b/test/CustomIInspectable/readme.md @@ -0,0 +1,12 @@ +# CustomIInspectable + +This was built following https://withinrafael.com/2023/01/18/generating-metadata-for-the-windows-crate + +## To build + +``` +dotnet restore +dotnet msbuild +``` + +It's important to use `dotnet msbuild` because WinMDGenerator is net8-targeting msbuild tasks which can only function inside dotnet msbuild and do not work in "dotnet build" or "msbuild". diff --git a/test/Microsoft.Windows.CsWin32.Tests/ExternalMetadata/CustomIInspectable.winmd b/test/Microsoft.Windows.CsWin32.Tests/ExternalMetadata/CustomIInspectable.winmd new file mode 100644 index 00000000..2a4c8891 Binary files /dev/null and b/test/Microsoft.Windows.CsWin32.Tests/ExternalMetadata/CustomIInspectable.winmd differ diff --git a/test/Microsoft.Windows.CsWin32.Tests/ExternalMetadata/NOTICE.md b/test/Microsoft.Windows.CsWin32.Tests/ExternalMetadata/NOTICE.md index 5d20d7df..795679c5 100644 --- a/test/Microsoft.Windows.CsWin32.Tests/ExternalMetadata/NOTICE.md +++ b/test/Microsoft.Windows.CsWin32.Tests/ExternalMetadata/NOTICE.md @@ -3,3 +3,4 @@ This folder contains winmd files obtained from other sources which we use for te Metadata | Source --|-- ServiceFabric.winmd | [youyuanwu/fabric-metadata](https://github.com/youyuanwu/fabric-metadata/raw/a1bcca6ad6f6a772c9e5ff4bdba80ae5e5f24cfc/.windows/winmd/ServiceFabric.winmd) +CustomIInspectable.winmd | Generated using WinMDGenerator toolchain. Project in the subdirectory [CustomIInspectable](../../CustomIInspectable) with build instructions in [readme.md](../../CustomIInspectable/readme.md). diff --git a/test/Microsoft.Windows.CsWin32.Tests/FriendlyOverloadTests.cs b/test/Microsoft.Windows.CsWin32.Tests/FriendlyOverloadTests.cs index d108dc2d..83e961d7 100644 --- a/test/Microsoft.Windows.CsWin32.Tests/FriendlyOverloadTests.cs +++ b/test/Microsoft.Windows.CsWin32.Tests/FriendlyOverloadTests.cs @@ -34,7 +34,7 @@ public void SpecializedRAIIFree_ReturnValue() this.GenerateApi(Method); MethodDeclarationSyntax method = Assert.Single(this.FindGeneratedMethod(Method), m => !IsOrContainsExternMethod(m)); - Assert.Equal("ReleaseActCtxSafeHandle", Assert.IsType(method.ReturnType).Identifier.ValueText); + Assert.Equal("ReleaseActCtxSafeHandle", Assert.IsType(method.ReturnType).Right.Identifier.ValueText); } [Fact] @@ -44,7 +44,7 @@ public void SpecializedRAIIFree_OutParameter() this.GenerateApi(Method); MethodDeclarationSyntax method = Assert.Single(this.FindGeneratedMethod(Method), m => !IsOrContainsExternMethod(m)); - Assert.Equal("DsGetDcCloseWSafeHandle", Assert.IsType(method.ParameterList.Parameters.Last().Type).Identifier.ValueText); + Assert.Equal("DsGetDcCloseWSafeHandle", Assert.IsType(method.ParameterList.Parameters.Last().Type).Right.Identifier.ValueText); } [Fact] diff --git a/test/Microsoft.Windows.CsWin32.Tests/GeneratorTestBase.cs b/test/Microsoft.Windows.CsWin32.Tests/GeneratorTestBase.cs index 57247407..2f28819f 100644 --- a/test/Microsoft.Windows.CsWin32.Tests/GeneratorTestBase.cs +++ b/test/Microsoft.Windows.CsWin32.Tests/GeneratorTestBase.cs @@ -13,6 +13,7 @@ public abstract class GeneratorTestBase : IDisposable, IAsyncLifetime protected static readonly string[] DefaultMetadataPaths = new[] { MetadataPath, WdkMetadataPath }; ////protected static readonly string DiaMetadataPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location!)!, "Microsoft.Dia.winmd"); protected static readonly string ServiceFabricMetadataPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location!)!, "ExternalMetadata", "ServiceFabric.winmd"); + protected static readonly string CustomIInspectableMetadataPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location!)!, "ExternalMetadata", "CustomIInspectable.winmd"); protected static readonly string ApiDocsPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location!)!, "apidocs.msgpack"); protected readonly ITestOutputHelper logger; diff --git a/test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs b/test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs index 62296af0..8a780ecf 100644 --- a/test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs +++ b/test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs @@ -688,7 +688,7 @@ public void GetLastErrorGenerationThrowsWhenExplicitlyCalled() Assert.Throws(() => this.generator.TryGenerate("GetLastError", CancellationToken.None)); } - [Fact(Skip = "https://github.com/microsoft/win32metadata/issues/129")] + [Fact] public void DeleteObject_TakesTypeDefStruct() { this.generator = this.CreateGenerator(); @@ -697,7 +697,7 @@ public void DeleteObject_TakesTypeDefStruct() this.AssertNoDiagnostics(); MethodDeclarationSyntax? deleteObjectMethod = this.FindGeneratedMethod("DeleteObject").FirstOrDefault(); Assert.NotNull(deleteObjectMethod); - Assert.Equal("HGDIOBJ", Assert.IsType(deleteObjectMethod!.ParameterList.Parameters[0].Type).Identifier.ValueText); + Assert.Equal("HGDIOBJ", Assert.IsType(deleteObjectMethod!.ParameterList.Parameters[0].Type).Right.Identifier.ValueText); } [Theory] diff --git a/test/Microsoft.Windows.CsWin32.Tests/HandleTests.cs b/test/Microsoft.Windows.CsWin32.Tests/HandleTests.cs index bf1d2948..bda7548a 100644 --- a/test/Microsoft.Windows.CsWin32.Tests/HandleTests.cs +++ b/test/Microsoft.Windows.CsWin32.Tests/HandleTests.cs @@ -86,7 +86,7 @@ public void MSIHANDLE_BecomesSafeHandle() Assert.Contains( this.FindGeneratedMethod("MsiGetLastErrorRecord_SafeHandle"), - method => method!.ReturnType?.ToString() == "MsiCloseHandleSafeHandle"); + method => method!.ReturnType?.ToString() == "global::Windows.Win32.MsiCloseHandleSafeHandle"); MethodDeclarationSyntax releaseMethod = this.FindGeneratedMethod("MsiCloseHandle").Single(); Assert.Equal("MSIHANDLE", Assert.IsType(releaseMethod!.ParameterList.Parameters[0].Type).Right.Identifier.ValueText); diff --git a/test/Microsoft.Windows.CsWin32.Tests/MultiMetadataTests.cs b/test/Microsoft.Windows.CsWin32.Tests/MultiMetadataTests.cs index 349d7440..8f05869d 100644 --- a/test/Microsoft.Windows.CsWin32.Tests/MultiMetadataTests.cs +++ b/test/Microsoft.Windows.CsWin32.Tests/MultiMetadataTests.cs @@ -11,9 +11,24 @@ public MultiMetadataTests(ITestOutputHelper logger) [Theory, PairwiseData] public void BasicServiceFabric(bool allowMarshaling) { - this.generator = this.CreateSuperGenerator(DefaultMetadataPaths.Concat(new[] { ServiceFabricMetadataPath }).ToArray(), DefaultTestGeneratorOptions with { AllowMarshaling = allowMarshaling }); - Assert.True(this.generator.TryGenerate("IFabricStringResult", CancellationToken.None)); - this.CollectGeneratedCode(this.generator); - this.AssertNoDiagnostics(); + this.generator = this.CreateSuperGenerator([.. DefaultMetadataPaths, ServiceFabricMetadataPath], DefaultTestGeneratorOptions with { AllowMarshaling = allowMarshaling }); + this.GenerateApi("IFabricStringResult"); + } + + [Theory, CombinatorialData] + public void CrossWinMD_IInspectable( + [CombinatorialValues([false, true])] bool allowMarshaling, + [CombinatorialValues([null, "TestPInvoke"])] string pinvokeClassName, + [CombinatorialValues(["net472", "net8.0"])] string tfm) + { + this.compilation = this.starterCompilations[tfm]; + GeneratorOptions options = DefaultTestGeneratorOptions with { AllowMarshaling = allowMarshaling }; + if (pinvokeClassName is not null) + { + options = options with { ClassName = pinvokeClassName }; + } + + this.generator = this.CreateSuperGenerator([.. DefaultMetadataPaths, CustomIInspectableMetadataPath], options); + this.GenerateApi("ITestDerivedFromInspectable"); } }