From ceb533896f75dc429cd938842645d76e4e0b3255 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 11 Aug 2023 12:40:08 -0600 Subject: [PATCH] Add MAKELONG and related macros Closes #997 --- src/Microsoft.Windows.CsWin32/Generator.cs | 10 +++ .../templates/PInvokeClassMacros.cs | 32 +++++++++ test/GenerationSandbox.Tests/MacroTests.cs | 68 +++++++++++++++++++ .../GenerationSandbox.Tests/NativeMethods.txt | 5 ++ .../GeneratorTests.cs | 23 ------- .../MacrosTests.cs | 33 +++++++++ 6 files changed, 148 insertions(+), 23 deletions(-) create mode 100644 test/GenerationSandbox.Tests/MacroTests.cs create mode 100644 test/Microsoft.Windows.CsWin32.Tests/MacrosTests.cs diff --git a/src/Microsoft.Windows.CsWin32/Generator.cs b/src/Microsoft.Windows.CsWin32/Generator.cs index ce63ce14..34f0108e 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.cs @@ -943,6 +943,16 @@ internal void RequestMacro(MethodDeclarationSyntax macro) this.TryGenerateType(identifierString.Substring(GlobalNamespacePrefix.Length)); } } + + // Generate macro dependencies, if any. + foreach (IdentifierNameSyntax identifier in macro.DescendantNodes().OfType()) + { + string identifierString = identifier.ToString(); + if (Win32SdkMacros.ContainsKey(identifierString)) + { + this.TryGenerateMacro(identifierString, out _); + } + } }); } diff --git a/src/Microsoft.Windows.CsWin32/templates/PInvokeClassMacros.cs b/src/Microsoft.Windows.CsWin32/templates/PInvokeClassMacros.cs index 348a0c47..1cc581aa 100644 --- a/src/Microsoft.Windows.CsWin32/templates/PInvokeClassMacros.cs +++ b/src/Microsoft.Windows.CsWin32/templates/PInvokeClassMacros.cs @@ -12,4 +12,36 @@ internal class PInvokeClassMacros /// Learn more in the documentation for this API. /// internal static global::Windows.Win32.Foundation.HRESULT HRESULT_FROM_WIN32(global::Windows.Win32.Foundation.WIN32_ERROR error) => new(unchecked(error <= 0 ? (int)error : (int)(((uint)error & 0x0000FFFF) | 0x80070000))); + + /// + /// Joins two 16-bit integers into a 32-bit integer. + /// + /// The low word. + /// The high word. + /// A 32-bit unsigned integer. + internal static uint MAKELONG(ushort a, ushort b) => (uint)(a | b << 16); + + /// + /// Constructs a from two 16-bit values. + /// + /// The low word. + /// The high word. + /// The WPARAM value. + internal static global::Windows.Win32.Foundation.WPARAM MAKEWPARAM(ushort l, ushort h) => MAKELONG(l, h); + + /// + /// Constructs a from two 16-bit values. + /// + /// The low word. + /// The high word. + /// The LPARAM value. + internal static global::Windows.Win32.Foundation.LPARAM MAKELPARAM(ushort l, ushort h) => unchecked((nint)MAKELONG(l, h)); + + /// + /// Constructs a from two 16-bit values. + /// + /// The low word. + /// The high word. + /// The LRESULT value. + internal static global::Windows.Win32.Foundation.LRESULT MAKELRESULT(ushort l, ushort h) => unchecked((global::Windows.Win32.Foundation.LRESULT)(nint)MAKELONG(l, h)); } diff --git a/test/GenerationSandbox.Tests/MacroTests.cs b/test/GenerationSandbox.Tests/MacroTests.cs new file mode 100644 index 00000000..00131038 --- /dev/null +++ b/test/GenerationSandbox.Tests/MacroTests.cs @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Windows.Win32.Foundation; +using static Windows.Win32.PInvoke; + +public class MacroTests +{ + [Fact] + public void HRESULT_FROM_WIN32Test() + { + Assert.Equal(HRESULT.S_OK, HRESULT_FROM_WIN32(WIN32_ERROR.NO_ERROR)); + } + + [Fact] + public void MAKELONGTest() + { + Assert.Equal(0x00000000u, MAKELONG(0x0000, 0x0000)); + Assert.Equal(0x00010000u, MAKELONG(0x0000, 0x0001)); + Assert.Equal(0x00000001u, MAKELONG(0x0001, 0x0000)); + Assert.Equal(0x00010002u, MAKELONG(0x0002, 0x0001)); + Assert.Equal(0xFFFF0000u, MAKELONG(0x0000, 0xFFFF)); + Assert.Equal(0x0000FFFFu, MAKELONG(0xFFFF, 0x0000)); + Assert.Equal(0xFFFFFFFFu, MAKELONG(0xFFFF, 0xFFFF)); + } + + [Fact] + public void MAKEWPARAMTest() + { + Assert.Equal(0x00000000u, MAKEWPARAM(0x0000, 0x0000)); + Assert.Equal(0x00010000u, MAKEWPARAM(0x0000, 0x0001)); + Assert.Equal(0x00000001u, MAKEWPARAM(0x0001, 0x0000)); + Assert.Equal(0x00010002u, MAKEWPARAM(0x0002, 0x0001)); + Assert.Equal(0xFFFF0000u, MAKEWPARAM(0x0000, 0xFFFF)); + Assert.Equal(0x0000FFFFu, MAKEWPARAM(0xFFFF, 0x0000)); + Assert.Equal(0xFFFFFFFFu, MAKEWPARAM(0xFFFF, 0xFFFF)); + } + + [Fact] + public void MAKELPARAMTest() + { + unchecked + { + Assert.Equal((LPARAM)(nint)0x00000000, MAKELPARAM(0x0000, 0x0000)); + Assert.Equal((LPARAM)(nint)0x00010000, MAKELPARAM(0x0000, 0x0001)); + Assert.Equal((LPARAM)(nint)0x00000001, MAKELPARAM(0x0001, 0x0000)); + Assert.Equal((LPARAM)(nint)0x00010002, MAKELPARAM(0x0002, 0x0001)); + Assert.Equal((LPARAM)(nint)0xFFFF0000, MAKELPARAM(0x0000, 0xFFFF)); + Assert.Equal((LPARAM)(nint)0x0000FFFF, MAKELPARAM(0xFFFF, 0x0000)); + Assert.Equal((LPARAM)(nint)0xFFFFFFFF, MAKELPARAM(0xFFFF, 0xFFFF)); + } + } + + [Fact] + public void MAKELRESULTTest() + { + unchecked + { + Assert.Equal((LRESULT)(nint)0x00000000, MAKELRESULT(0x0000, 0x0000)); + Assert.Equal((LRESULT)(nint)0x00010000, MAKELRESULT(0x0000, 0x0001)); + Assert.Equal((LRESULT)(nint)0x00000001, MAKELRESULT(0x0001, 0x0000)); + Assert.Equal((LRESULT)(nint)0x00010002, MAKELRESULT(0x0002, 0x0001)); + Assert.Equal((LRESULT)(nint)0xFFFF0000, MAKELRESULT(0x0000, 0xFFFF)); + Assert.Equal((LRESULT)(nint)0x0000FFFF, MAKELRESULT(0xFFFF, 0x0000)); + Assert.Equal((LRESULT)(nint)0xFFFFFFFF, MAKELRESULT(0xFFFF, 0xFFFF)); + } + } +} diff --git a/test/GenerationSandbox.Tests/NativeMethods.txt b/test/GenerationSandbox.Tests/NativeMethods.txt index 165ec8b9..c0356712 100644 --- a/test/GenerationSandbox.Tests/NativeMethods.txt +++ b/test/GenerationSandbox.Tests/NativeMethods.txt @@ -13,6 +13,7 @@ GetTickCount GetWindowText GetWindowTextLength HDC_UserSize +HRESULT_FROM_WIN32 IDirectorySearch IEnumDebugPropertyInfo IPersistFile @@ -21,6 +22,9 @@ IShellWindows KEY_EVENT_RECORD LoadLibrary MainAVIHeader +MAKELPARAM +MAKELRESULT +MAKEWPARAM MAX_PATH NTSTATUS PathParseIconLocation @@ -30,6 +34,7 @@ PZZWSTR RECT RegLoadAppKey RM_PROCESS_INFO +S_OK SHDESCRIPTIONID ShellLink ShellWindowFindWindowOptions diff --git a/test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs b/test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs index c726beaa..6fb09218 100644 --- a/test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs +++ b/test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs @@ -389,29 +389,6 @@ public void ObsoleteAttributePropagated() Assert.Contains(field!.Value.Field.AttributeLists, al => IsAttributePresent(al, "Obsolete")); } - [Theory, PairwiseData] - public void MacroAPIsGenerateWithAppropriateVisibility(bool publicVisibility) - { - this.generator = this.CreateGenerator(DefaultTestGeneratorOptions with { Public = publicVisibility }); - Assert.True(this.generator.TryGenerate("HRESULT_FROM_WIN32", CancellationToken.None)); - this.CollectGeneratedCode(this.generator); - this.AssertNoDiagnostics(); - var method = Assert.Single(this.FindGeneratedMethod("HRESULT_FROM_WIN32")); - - Assert.True(method.Modifiers.Any(publicVisibility ? SyntaxKind.PublicKeyword : SyntaxKind.InternalKeyword)); - } - - [Theory] - [MemberData(nameof(AvailableMacros))] - public void MacroAPIsGenerate(string macro) - { - this.generator = this.CreateGenerator(); - Assert.True(this.generator.TryGenerate(macro, CancellationToken.None)); - this.CollectGeneratedCode(this.generator); - this.AssertNoDiagnostics(); - Assert.Single(this.FindGeneratedMethod(macro)); - } - [Theory] [InlineData("BOOL")] [InlineData("BOOLEAN")] diff --git a/test/Microsoft.Windows.CsWin32.Tests/MacrosTests.cs b/test/Microsoft.Windows.CsWin32.Tests/MacrosTests.cs new file mode 100644 index 00000000..69b91292 --- /dev/null +++ b/test/Microsoft.Windows.CsWin32.Tests/MacrosTests.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +public class MacrosTests : GeneratorTestBase +{ + public MacrosTests(ITestOutputHelper logger) + : base(logger) + { + } + + [Theory, PairwiseData] + public void MacroAPIsGenerateWithAppropriateVisibility(bool publicVisibility) + { + this.generator = this.CreateGenerator(DefaultTestGeneratorOptions with { Public = publicVisibility }); + Assert.True(this.generator.TryGenerate("MAKELONG", CancellationToken.None)); + this.CollectGeneratedCode(this.generator); + this.AssertNoDiagnostics(); + var method = Assert.Single(this.FindGeneratedMethod("MAKELONG")); + + Assert.True(method.Modifiers.Any(publicVisibility ? SyntaxKind.PublicKeyword : SyntaxKind.InternalKeyword)); + } + + [Theory] + [MemberData(nameof(AvailableMacros))] + public void MacroAPIsGenerate(string macro) + { + this.generator = this.CreateGenerator(); + Assert.True(this.generator.TryGenerate(macro, CancellationToken.None)); + this.CollectGeneratedCode(this.generator); + this.AssertNoDiagnostics(); + Assert.Single(this.FindGeneratedMethod(macro)); + } +}