Skip to content

Commit dd815b2

Browse files
authored
Merge pull request #1052 from microsoft/fix1051
Add implicit conversions between `bool` and `VARIANT_BOOL`
2 parents 33ecc79 + f9e49cc commit dd815b2

File tree

5 files changed

+120
-2
lines changed

5 files changed

+120
-2
lines changed

src/Microsoft.Windows.CsWin32/Generator.GeneratedCode.cs

+21-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ private class GeneratedCode
3434
/// </summary>
3535
private readonly Dictionary<MethodDefinitionHandle, Exception?> methodsGenerating = new();
3636

37+
/// <summary>
38+
/// The constants that are or have been generated.
39+
/// </summary>
40+
private readonly Dictionary<FieldDefinitionHandle, Exception?> constantsGenerating = new();
41+
3742
/// <summary>
3843
/// A collection of the names of special types we are or have generated.
3944
/// </summary>
@@ -303,12 +308,26 @@ internal void GenerateConstant(FieldDefinitionHandle fieldDefinitionHandle, Acti
303308
{
304309
this.ThrowIfNotGenerating();
305310

306-
if (this.fieldsToSyntax.ContainsKey(fieldDefinitionHandle) || this.parent?.fieldsToSyntax.ContainsKey(fieldDefinitionHandle) is true)
311+
if (this.constantsGenerating.TryGetValue(fieldDefinitionHandle, out Exception? failure) || this.parent?.constantsGenerating.TryGetValue(fieldDefinitionHandle, out failure) is true)
307312
{
313+
if (failure is object)
314+
{
315+
throw new GenerationFailedException("This constant already failed in generation previously.", failure);
316+
}
317+
308318
return;
309319
}
310320

311-
generator();
321+
this.constantsGenerating.Add(fieldDefinitionHandle, null);
322+
try
323+
{
324+
generator();
325+
}
326+
catch (Exception ex)
327+
{
328+
this.constantsGenerating[fieldDefinitionHandle] = ex;
329+
throw;
330+
}
312331
}
313332

314333
internal void GenerateMacro(string macroName, Action generator)

src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs

+5
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ private StructDeclarationSyntax DeclareTypeDefStruct(TypeDefinition typeDef, Typ
200200
members = AddOrReplaceMembers(members, this.ExtractMembersFromTemplate(name.Identifier.ValueText));
201201
this.TryGenerateType("Windows.Win32.Foundation.PC" + name.Identifier.ValueText.Substring(1)); // the template references its constant version
202202
break;
203+
case "VARIANT_BOOL":
204+
members = AddOrReplaceMembers(members, this.ExtractMembersFromTemplate(name.Identifier.ValueText));
205+
this.TryGenerateConstant("VARIANT_TRUE", out _); // the template references its constant version
206+
this.TryGenerateConstant("VARIANT_FALSE", out _); // the template references its constant version
207+
break;
203208
case "BSTR":
204209
case "HRESULT":
205210
case "NTSTATUS":
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
partial struct VARIANT_BOOL
2+
{
3+
internal VARIANT_BOOL(bool value) => this.Value = value ? VARIANT_TRUE : VARIANT_FALSE;
4+
public static implicit operator bool(VARIANT_BOOL value) => value != VARIANT_FALSE;
5+
public static implicit operator VARIANT_BOOL(bool value) => value ? VARIANT_TRUE : VARIANT_FALSE;
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Windows.Win32.Foundation;
5+
6+
public class VARIANT_BOOLTests
7+
{
8+
[Fact]
9+
public void Ctor_bool()
10+
{
11+
VARIANT_BOOL b = true;
12+
bool b2 = b;
13+
Assert.True(b);
14+
Assert.True(b2);
15+
16+
Assert.False(default(VARIANT_BOOL));
17+
}
18+
19+
[Fact]
20+
public void Ctor_int()
21+
{
22+
Assert.Equal(2, new VARIANT_BOOL(2).Value);
23+
}
24+
25+
[Fact]
26+
public void ExplicitCast()
27+
{
28+
Assert.Equal(2, ((VARIANT_BOOL)2).Value);
29+
}
30+
31+
[Theory]
32+
[InlineData(3)]
33+
[InlineData(-1)]
34+
[InlineData(0)]
35+
[InlineData(1)]
36+
[InlineData(0xfff)]
37+
public void LossyConversionFromBOOLtoBool(short ordinal)
38+
{
39+
VARIANT_BOOL nativeBool = new VARIANT_BOOL(ordinal);
40+
bool managedBool = nativeBool;
41+
Assert.Equal(ordinal != 0, managedBool);
42+
BOOLEAN roundtrippedNativeBool = managedBool;
43+
Assert.Equal(managedBool ? 1 : 0, roundtrippedNativeBool);
44+
}
45+
46+
[Fact]
47+
public void BOOLEqualsComparesExactValue()
48+
{
49+
VARIANT_BOOL b1 = new VARIANT_BOOL(1);
50+
VARIANT_BOOL b2 = new VARIANT_BOOL(2);
51+
Assert.Equal(b1, b1);
52+
Assert.NotEqual(b1, b2);
53+
}
54+
55+
[Fact]
56+
public void BOOL_OverridesEqualityOperator()
57+
{
58+
var @true = new VARIANT_BOOL(true);
59+
var @false = new VARIANT_BOOL(false);
60+
Assert.True(@true == new VARIANT_BOOL(true));
61+
Assert.False(@true != new VARIANT_BOOL(true));
62+
Assert.True(@true != @false);
63+
Assert.False(@true == @false);
64+
65+
var two = new VARIANT_BOOL(2);
66+
Assert.False(two == @true);
67+
Assert.True(two != @true);
68+
}
69+
70+
[Fact]
71+
public void LogicalOperators_And()
72+
{
73+
VARIANT_BOOL @true = true, @false = false;
74+
Assert.False(@false && @false);
75+
Assert.False(@true && @false);
76+
Assert.True(@true && @true);
77+
}
78+
79+
[Fact]
80+
public void LogicalOperators_Or()
81+
{
82+
VARIANT_BOOL @true = true, @false = false;
83+
Assert.True(@true || @false);
84+
Assert.False(@false || @false);
85+
Assert.True(@true || @true);
86+
}
87+
}

test/Microsoft.Windows.CsWin32.Tests/StructTests.cs

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ public void SpecialStruct_ByRequest(string structName)
173173
[CombinatorialData]
174174
public void InterestingStructs(
175175
[CombinatorialValues(
176+
"VARIANT_BOOL", // has a custom conversion to bool and relies on other members being generated
176177
"DRIVER_OBJECT", // has an inline array of delegates
177178
"DEVICE_RELATIONS", // ends with an inline "flexible" array
178179
"D3DHAL_CONTEXTCREATEDATA", // contains a field that is a pointer to a struct that is normally managed

0 commit comments

Comments
 (0)