Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Give HWND an IntPtr field type #588

Merged
merged 1 commit into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 32 additions & 18 deletions src/Microsoft.Windows.CsWin32/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3121,7 +3121,7 @@ private FieldDeclarationSyntax DeclareConstant(FieldDefinition fieldDef)
bool requiresUnsafe = false;
if (fieldType.Type is not PredefinedTypeSyntax && value is not ObjectCreationExpressionSyntax)
{
if (fieldTypeInfo is HandleTypeHandleInfo handleFieldTypeInfo && this.TryGetHandleReleaseMethod(handleFieldTypeInfo.Handle, out _))
if (fieldTypeInfo is HandleTypeHandleInfo handleFieldTypeInfo && this.IsHandle(handleFieldTypeInfo.Handle, out _))
{
// Cast to IntPtr first, then the actual handle struct.
value = CastExpression(fieldType.Type, CastExpression(IntPtrTypeSyntax, ParenthesizedExpression(value)));
Expand Down Expand Up @@ -3757,30 +3757,44 @@ private ClassDeclarationSyntax DeclareCocreatableClass(TypeDefinition typeDef)
return result;
}

private bool IsHandle(EntityHandle typeDefOrRefHandle, out string? releaseMethodName)
{
switch (typeDefOrRefHandle.Kind)
{
case HandleKind.TypeReference when this.TryGetTypeDefHandle((TypeReferenceHandle)typeDefOrRefHandle, out TypeDefinitionHandle typeDefHandle):
return this.IsHandle(typeDefHandle, out releaseMethodName);
case HandleKind.TypeDefinition:
return this.IsHandle((TypeDefinitionHandle)typeDefOrRefHandle, out releaseMethodName);
}

releaseMethodName = null;
return false;
}

private bool IsHandle(TypeDefinitionHandle typeDefHandle, out string? releaseMethodName)
{
if (this.MetadataIndex.HandleTypeReleaseMethod.TryGetValue(typeDefHandle, out releaseMethodName))
{
return true;
}

// Special case handles that do not carry RAIIFree attributes.
releaseMethodName = null;
TypeDefinition typeDef = this.Reader.GetTypeDefinition(typeDefHandle);
return this.Reader.StringComparer.Equals(typeDef.Name, "HGDIOBJ")
|| this.Reader.StringComparer.Equals(typeDef.Name, "HWND");
}

/// <summary>
/// Creates a struct that emulates a typedef in the C language headers.
/// </summary>
private StructDeclarationSyntax DeclareTypeDefStruct(TypeDefinition typeDef, TypeDefinitionHandle typeDefHandle)
{
IdentifierNameSyntax name = IdentifierName(this.Reader.GetString(typeDef.Name));
bool isHandle = name.Identifier.ValueText == "HGDIOBJ";
foreach (CustomAttributeHandle attHandle in typeDef.GetCustomAttributes())
bool isHandle = this.IsHandle(typeDefHandle, out string? freeMethodName);
if (freeMethodName is not null)
{
CustomAttribute att = this.Reader.GetCustomAttribute(attHandle);

// If this struct represents a handle, generate the SafeHandle-equivalent.
if (this.IsAttribute(att, InteropDecorationNamespace, RAIIFreeAttribute))
{
CustomAttributeValue<TypeSyntax> args = att.DecodeValue(CustomAttributeTypeProvider.Instance);
if (args.FixedArguments[0].Value is string freeMethodName)
{
////this.GenerateSafeHandle(freeMethodName);
this.TryGenerateExternMethod(freeMethodName, out _);
isHandle = true;
}

break;
}
this.TryGenerateExternMethod(freeMethodName, out _);
}

TypeSyntaxSettings typeSettings = isHandle ? this.fieldOfHandleTypeDefTypeSettings : this.fieldTypeSettings;
Expand Down
35 changes: 27 additions & 8 deletions test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,21 @@ public void HandleStructsHaveIsNullProperty(string handleName)
this.AssertGeneratedMember(handleName, "IsNull", "internal bool IsNull => Value == default;");
}

[Theory]
[InlineData("HANDLE")]
[InlineData("HGDIOBJ")]
[InlineData("HWND")]
public void HandleTypeDefsUseIntPtrAsFieldType(string handleType)
{
this.generator = this.CreateGenerator();
Assert.True(this.generator.TryGenerate(handleType, CancellationToken.None));
this.CollectGeneratedCode(this.generator);
this.AssertNoDiagnostics();
StructDeclarationSyntax hwnd = Assert.IsType<StructDeclarationSyntax>(this.FindGeneratedType(handleType).Single());
FieldDeclarationSyntax field = hwnd.Members.OfType<FieldDeclarationSyntax>().Single();
Assert.Equal(nameof(IntPtr), Assert.IsType<IdentifierNameSyntax>(field.Declaration.Type).Identifier.ValueText);
}

[Fact]
public void NamespaceHandleGetsNoSafeHandle()
{
Expand Down Expand Up @@ -1927,10 +1942,12 @@ namespace Foundation
internal readonly partial struct HWND
: IEquatable<HWND>
{
internal readonly nint Value;
internal HWND(nint value) => this.Value = value;
public static implicit operator nint(HWND value) => value.Value;
public static explicit operator HWND(nint value) => new HWND(value);
internal readonly IntPtr Value;
internal HWND(IntPtr value) => this.Value = value;

internal bool IsNull => Value == default;
public static implicit operator IntPtr(HWND value) => value.Value;
public static explicit operator HWND(IntPtr value) => new HWND(value);
public static bool operator ==(HWND left, HWND right) => left.Value == right.Value;
public static bool operator !=(HWND left, HWND right) => !(left == right);

Expand Down Expand Up @@ -2073,10 +2090,12 @@ namespace Foundation
internal readonly partial struct HWND
: IEquatable<HWND>
{
internal readonly nint Value;
internal HWND(nint value) => this.Value = value;
public static implicit operator nint(HWND value) => value.Value;
public static explicit operator HWND(nint value) => new HWND(value);
internal readonly IntPtr Value;
internal HWND(IntPtr value) => this.Value = value;

internal bool IsNull => Value == default;
public static implicit operator IntPtr(HWND value) => value.Value;
public static explicit operator HWND(IntPtr value) => new HWND(value);
public static bool operator ==(HWND left, HWND right) => left.Value == right.Value;
public static bool operator !=(HWND left, HWND right) => !(left == right);

Expand Down