Skip to content

Commit 8db2cfe

Browse files
committed
Migrate Windows interop to CsWin32 source-generated P/Invoke
Replace hand-written [DllImport] declarations and COM [ComImport] interfaces with CsWin32 source-generated interop. This enables Native AOT scenarios where built-in COM marshalling and System.Runtime.InteropServices marshalling infrastructure do not exist. The approach follows patterns established in WinForms, WPF, and the dotnet/sdk repository. CsWin32 is configured in Microsoft.Build.Framework with allowMarshaling: false and useSafeHandles: false, producing raw pointer signatures that are AOT-compatible. Other projects consume generated types via InternalsVisibleTo. Key changes: Infrastructure: - Add FEATURE_WINDOWSINTEROP compile-time gate in Directory.BeforeCommon.targets, disabled for source-only builds - Add CsWin32 (Microsoft.Windows.CsWin32) and PolySharp package references to Framework.csproj - Add NativeMethods.txt and NativeMethods.json for CsWin32 configuration - Add .editorconfig suppression for CS3019 in Windows/ folders - Add cswin32-interop skill document for agent guidance New utility types: - BufferScope<T>: ref struct for stack-allocated buffers with ArrayPool fallback, replacing manual ArrayPool rent/return and stackalloc patterns throughout interop code - TypeInfo<T>: cached RuntimeHelpers.IsReferenceOrContainsReferences polyfill for net472 - ComScope<T>: COM pointer lifetime management (using-disposable) - ComClassFactory: AOT-compatible COM activation without Activator.CreateInstance - IID: generic IID lookup via IComIID interface - VARIANT, BSTR, HRESULT, FILETIME extensions: CsWin32 partial type augmentations for safe usage patterns NativeMethods.cs cleanup: - Delete ~130 hand-written constants, enums, structs, and [DllImport] declarations replaced by CsWin32 typed equivalents - Replace MemoryStatus class with MEMORYSTATUSEX struct via TryGetMemoryStatus - Replace GetCurrentDirectory/GetFullPath/GetShortPathName/ GetLongPathName with BufferScope-based implementations - Replace StreamHandleType enum with bool useStandardError parameter - Delete DirectoryExists/FileExists/FileOrDirectoryExists wrappers; callers use PInvoke.GetFileAttributes directly - Delete HResultSucceeded/HResultFailed; callers use HRESULT.Failed - Add [UnsupportedOSPlatformGuard("windows")] to IsUnixLike - Version all [SupportedOSPlatform] attributes to "windows6.1" COM interop modernization: - Replace [ComImport] WMI interfaces (IWbemLocator, IWbemServices, IEnumWbemClassObject, IWbemClassObject) with struct-based COM using delegate* unmanaged[Stdcall] vtables - Add IDebugClient4-based command line retrieval as alternative to WMI (CommandLineSource.DebugEngine) - Move IFixedTypeInfo from NativeMethods.cs to its own file in Tasks Platform guard pattern: - Apply dual-guard pattern: #if FEATURE_WINDOWSINTEROP wraps runtime IsWindows checks, eliminating dead code in source builds - Use IsUnixLike (positive guard) instead of !IsWindows for CA1416 platform compatibility analysis - Files excluded at project level via <Compile Remove> when FeatureWindowsInterop is off (WindowsFileSystem, Windows/ folder, WMI structs) Behavioral changes: - Unzip.cs: !IsWindows → IsUnixLike for correct CA1416 analysis - ProcessExtensions: ArrayPool<T> replaced with BufferScope<T> - AssemblyInformation/GlobalAssemblyCache: remove dead non-Windows code paths in net472-only (#if !FEATURE_ASSEMBLYLOADCONTEXT) blocks, which only run on Windows Some related changes are also in dotnet#13426.
1 parent 97e3065 commit 8db2cfe

51 files changed

Lines changed: 3197 additions & 1463 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,3 +457,12 @@ dotnet_diagnostic.xUnit1031.severity = none
457457
# The latter brings incosistency in the codebase and some times in one test case.
458458
# So we are disabling this rule with respect to the above mentioned reasons.
459459
dotnet_diagnostic.xUnit2013.severity = none
460+
461+
# Attributes needed for interop are not CLS-compliant, which produces CS3016 warnings. Disabling here doesn't
462+
# actually work, but when we apply the [CLSCompliant(false)] attribute to the partial declarations of the generated
463+
# types it then fires CS3019 warnings about it not making sense on internal types. We disable these warnings for
464+
# anything in the CsWin32 subfolders. Other options are to disable CS3016 entirely in the project, but that would
465+
# suppress the warning for all code, not just the interop code. Hopefully https://github.com/dotnet/roslyn/issues/68526
466+
# is addressed so we can remove all of this complication.
467+
[{**/Windows/**/*.cs}]
468+
dotnet_diagnostic.CS3019.severity = none

.github/skills/cswin32-interop/SKILL.md

Lines changed: 451 additions & 0 deletions
Large diffs are not rendered by default.

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ Instructions for GitHub Copilot and other AI coding agents working with the MSBu
1515

1616
### Technology Stack
1717
- .NET 10.0 and .NET Framework 4.7.2
18-
- C# 13 features (especially collection expressions)
18+
- C# 14 features (especially collection expressions)
1919
- xUnit with Shouldly for testing
2020
- Multi-platform support (Windows, Linux, macOS)
2121

2222
## General
2323

2424
* Performance is the top priority - minimize allocations, avoid LINQ in hot paths, use efficient algorithms.
25-
* Always use the latest C# features, currently C# 13, especially collection expressions (`[]` over `new Type[]`).
25+
* Always use the latest C# features, currently C# 14, especially collection expressions (`[]` over `new Type[]`).
2626
* Match the style of surrounding code when making edits, but modernize aggressively for substantial changes.
2727

2828
## Code Review Instructions

eng/dependabot/Directory.Packages.props

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@
6363
<PackageVersion Update="Verify.XunitV3" Condition="'$(VerifyXunitV3Version)' != ''" Version="$(VerifyXunitV3Version)" />
6464
</ItemGroup>
6565

66+
<!-- CsWin32 source generator for Windows interop (dev-time only) -->
67+
<ItemGroup>
68+
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.3.183" />
69+
<PackageVersion Update="Microsoft.Windows.CsWin32" Condition="'$(MicrosoftWindowsCsWin32Version)' != ''" Version="$(MicrosoftWindowsCsWin32Version)" />
70+
71+
<PackageVersion Include="PolySharp" Version="1.15.0" />
72+
<PackageVersion Update="PolySharp" Condition="'$(PolySharpVersion)' != ''" Version="$(PolySharpVersion)" />
73+
</ItemGroup>
74+
6675
<!-- Roslyn analyzer authoring packages (used by ThreadSafeTaskAnalyzer) -->
6776
<ItemGroup>
6877
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />

src/Build.UnitTests/BackEnd/TargetUpToDateChecker_Tests.cs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
using Microsoft.Build.Shared;
1616
using Microsoft.Win32.SafeHandles;
1717
using Xunit;
18+
#if FEATURE_WINDOWSINTEROP
19+
using Windows.Win32.Storage.FileSystem;
20+
#endif
1821

1922
#nullable disable
2023

@@ -960,7 +963,7 @@ private void IsAnyOutOfDateTestHelper(
960963

961964
[Fact(Skip = "Creating a symlink on Windows requires elevation.")]
962965
[SkipOnPlatform(TestPlatforms.AnyUnix, "Windows-specific test")]
963-
[SupportedOSPlatform("windows")]
966+
[SupportedOSPlatform("windows6.1")]
964967
public void NewSymlinkOldDestinationIsUpToDate()
965968
{
966969
SimpleSymlinkInputCheck(symlinkWriteTime: New,
@@ -971,7 +974,7 @@ public void NewSymlinkOldDestinationIsUpToDate()
971974

972975
[Fact(Skip = "Creating a symlink on Windows requires elevation.")]
973976
[SkipOnPlatform(TestPlatforms.AnyUnix, "Windows-specific test")]
974-
[SupportedOSPlatform("windows")]
977+
[SupportedOSPlatform("windows6.1")]
975978
public void OldSymlinkOldDestinationIsUpToDate()
976979
{
977980
SimpleSymlinkInputCheck(symlinkWriteTime: Old,
@@ -982,7 +985,7 @@ public void OldSymlinkOldDestinationIsUpToDate()
982985

983986
[Fact(Skip = "Creating a symlink on Windows requires elevation.")]
984987
[SkipOnPlatform(TestPlatforms.AnyUnix, "Windows-specific test")]
985-
[SupportedOSPlatform("windows")]
988+
[SupportedOSPlatform("windows6.1")]
986989
public void OldSymlinkNewDestinationIsNotUpToDate()
987990
{
988991
SimpleSymlinkInputCheck(symlinkWriteTime: Old,
@@ -993,7 +996,7 @@ public void OldSymlinkNewDestinationIsNotUpToDate()
993996

994997
[Fact(Skip = "Creating a symlink on Windows requires elevation.")]
995998
[SkipOnPlatform(TestPlatforms.AnyUnix, "Windows-specific test")]
996-
[SupportedOSPlatform("windows")]
999+
[SupportedOSPlatform("windows6.1")]
9971000
public void NewSymlinkNewDestinationIsNotUpToDate()
9981001
{
9991002
SimpleSymlinkInputCheck(symlinkWriteTime: Middle,
@@ -1004,15 +1007,26 @@ public void NewSymlinkNewDestinationIsNotUpToDate()
10041007

10051008
[DllImport("kernel32.dll")]
10061009
[return: MarshalAs(UnmanagedType.Bool)]
1007-
[SupportedOSPlatform("windows")]
1010+
[SupportedOSPlatform("windows6.1")]
10081011
private static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, UInt32 dwFlags);
10091012

10101013
[DllImport("kernel32.dll", SetLastError = true)]
1011-
[SupportedOSPlatform("windows")]
1014+
[SupportedOSPlatform("windows6.1")]
10121015
private static extern bool SetFileTime(SafeFileHandle hFile, ref long creationTime,
10131016
ref long lastAccessTime, ref long lastWriteTime);
10141017

1015-
[SupportedOSPlatform("windows")]
1018+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CreateFileW")]
1019+
[SupportedOSPlatform("windows6.1")]
1020+
private static extern SafeFileHandle CreateFileForSymlink(
1021+
string lpFileName,
1022+
uint dwDesiredAccess,
1023+
uint dwShareMode,
1024+
IntPtr lpSecurityAttributes,
1025+
uint dwCreationDisposition,
1026+
uint dwFlagsAndAttributes,
1027+
IntPtr hTemplateFile);
1028+
1029+
[SupportedOSPlatform("windows6.1")]
10161030
private void SimpleSymlinkInputCheck(DateTime symlinkWriteTime, DateTime targetWriteTime,
10171031
DateTime outputWriteTime, bool expectedOutOfDate)
10181032
{
@@ -1038,11 +1052,13 @@ private void SimpleSymlinkInputCheck(DateTime symlinkWriteTime, DateTime targetW
10381052

10391053
// File.SetLastWriteTime on the symlink sets the target write time,
10401054
// so set the symlink's write time the hard way
1041-
using (SafeFileHandle handle =
1042-
NativeMethodsShared.CreateFile(
1043-
inputSymlink, NativeMethodsShared.GENERIC_READ | 0x100 /* FILE_WRITE_ATTRIBUTES */,
1044-
NativeMethodsShared.FILE_SHARE_READ, IntPtr.Zero, NativeMethodsShared.OPEN_EXISTING,
1045-
NativeMethodsShared.FILE_ATTRIBUTE_NORMAL | NativeMethodsShared.FILE_FLAG_OPEN_REPARSE_POINT,
1055+
using (SafeFileHandle handle = CreateFileForSymlink(
1056+
inputSymlink,
1057+
(uint)FILE_ACCESS_RIGHTS.FILE_GENERIC_READ | 0x100 /* FILE_WRITE_ATTRIBUTES */,
1058+
(uint)FILE_SHARE_MODE.FILE_SHARE_READ,
1059+
IntPtr.Zero,
1060+
(uint)FILE_CREATION_DISPOSITION.OPEN_EXISTING,
1061+
(uint)(FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL | FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_OPEN_REPARSE_POINT),
10461062
IntPtr.Zero))
10471063
{
10481064
if (handle.IsInvalid)

src/Build.UnitTests/ConsoleLogger_Tests.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
using Shouldly;
1919
using Xunit;
2020
using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem;
21+
#if FEATURE_WINDOWSINTEROP
22+
using Windows.Win32;
23+
using Windows.Win32.Foundation;
24+
using Windows.Win32.Storage.FileSystem;
25+
using Windows.Win32.System.Console;
26+
#endif
2127

2228
#nullable disable
2329

@@ -1959,18 +1965,16 @@ public void TestPrintTargetNamePerMessage()
19591965
/// Check to see what kind of device we are outputting the log to, is it a character device, a file, or something else
19601966
/// this can be used by loggers to modify their outputs based on the device they are writing to
19611967
/// </summary>
1962-
[SupportedOSPlatform("windows")]
1968+
[SupportedOSPlatform("windows6.1")]
19631969
internal bool IsRunningWithCharacterFileType()
19641970
{
19651971
// Get the std out handle
1966-
IntPtr stdHandle = NativeMethodsShared.GetStdHandle(NativeMethodsShared.STD_OUTPUT_HANDLE);
1972+
HANDLE stdHandle = PInvoke.GetStdHandle(STD_HANDLE.STD_OUTPUT_HANDLE);
19671973

1968-
if (stdHandle != Microsoft.Build.BackEnd.NativeMethods.InvalidHandle)
1974+
if (stdHandle != HANDLE.INVALID_HANDLE_VALUE)
19691975
{
1970-
uint fileType = NativeMethodsShared.GetFileType(stdHandle);
1971-
19721976
// The std out is a char type(LPT or Console)
1973-
return fileType == NativeMethodsShared.FILE_TYPE_CHAR;
1977+
return PInvoke.GetFileType(stdHandle) == FILE_TYPE.FILE_TYPE_CHAR;
19741978
}
19751979
else
19761980
{

src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
using Microsoft.Build.Shared.Debugging;
1717
using Microsoft.Build.TelemetryInfra;
1818
using Microsoft.NET.StringTools;
19+
#if FEATURE_WINDOWSINTEROP
20+
using Windows.Win32.System.SystemInformation;
21+
#endif
1922
using BuildAbortedException = Microsoft.Build.Exceptions.BuildAbortedException;
2023

2124
#nullable disable
@@ -885,6 +888,7 @@ private void EvaluateRequestStates()
885888
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.GC.Collect", Justification = "We're trying to get rid of memory because we're running low, so we need to collect NOW in order to free it up ASAP")]
886889
private void CheckMemoryUsage()
887890
{
891+
#if FEATURE_WINDOWSINTEROP
888892
if (!NativeMethodsShared.IsWindows || BuildEnvironmentHelper.Instance.RunningInVisualStudio)
889893
{
890894
// Since this causes synchronous I/O and a stop-the-world GC, it can be very expensive. If
@@ -901,18 +905,17 @@ private void CheckMemoryUsage()
901905
// Jeffrey Richter suggests that when the memory load in the system exceeds 80% it is a good
902906
// idea to start finding ways to unload unnecessary data to prevent memory starvation. We use this metric in
903907
// our calculations below.
904-
NativeMethodsShared.MemoryStatus memoryStatus = NativeMethodsShared.GetMemoryStatus();
905-
if (memoryStatus != null)
908+
if (NativeMethodsShared.TryGetMemoryStatus(out MEMORYSTATUSEX memoryStatus))
906909
{
907910
try
908911
{
909912
// The minimum limit must be no more than 80% of the virtual memory limit to reduce the chances of a single unfortunately
910913
// large project resulting in allocations which exceed available VM space between calls to this function. This situation
911914
// is more likely on 32-bit machines where VM space is only 2 gigs.
912-
ulong memoryUseLimit = Convert.ToUInt64(memoryStatus.TotalVirtual * 0.8);
915+
ulong memoryUseLimit = Convert.ToUInt64(memoryStatus.ullTotalVirtual * 0.8);
913916

914917
// See how much memory we are using and compart that to our limit.
915-
ulong memoryInUse = memoryStatus.TotalVirtual - memoryStatus.AvailableVirtual;
918+
ulong memoryInUse = memoryStatus.ullTotalVirtual - memoryStatus.ullAvailVirtual;
916919
while ((memoryInUse > memoryUseLimit) || _debugForceCaching)
917920
{
918921
TraceEngine(
@@ -936,8 +939,13 @@ private void CheckMemoryUsage()
936939
break;
937940
}
938941

939-
memoryStatus = NativeMethodsShared.GetMemoryStatus();
940-
memoryInUse = memoryStatus.TotalVirtual - memoryStatus.AvailableVirtual;
942+
if (!NativeMethodsShared.TryGetMemoryStatus(out memoryStatus))
943+
{
944+
TraceEngine("Failed to get memory status.");
945+
break;
946+
}
947+
948+
memoryInUse = memoryStatus.ullTotalVirtual - memoryStatus.ullAvailVirtual;
941949
TraceEngine("Memory usage now at {0}", memoryInUse);
942950
}
943951
}
@@ -949,6 +957,7 @@ private void CheckMemoryUsage()
949957
throw new BuildAbortedException(e.Message, e);
950958
}
951959
}
960+
#endif
952961
}
953962

954963
/// <summary>

src/Build/BackEnd/Components/Communications/NodeLauncher.cs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
using Microsoft.Build.Shared;
2020
using Microsoft.Build.Shared.FileSystem;
2121
using BackendNativeMethods = Microsoft.Build.BackEnd.NativeMethods;
22+
#if FEATURE_WINDOWSINTEROP
23+
using Windows.Win32;
24+
using Windows.Win32.Foundation;
25+
#endif
2226

2327
#nullable disable
2428

@@ -62,9 +66,14 @@ private Process StartInternal(NodeLaunchData nodeLaunchData)
6266

6367
CommunicationsUtilities.Trace("Launching node from {0}", nodeLaunchData.MSBuildLocation);
6468

69+
#if FEATURE_WINDOWSINTEROP
6570
return NativeMethodsShared.IsWindows
6671
? StartProcessWindows(nodeLaunchData, exeName, creationFlags, redirectStreams, isNativeAppHost)
67-
: StartProcessUnix(nodeLaunchData, exeName, creationFlags, redirectStreams, isNativeAppHost);
72+
:
73+
#endif
74+
NativeMethodsShared.IsUnixLike
75+
? StartProcessUnix(nodeLaunchData, exeName, creationFlags, redirectStreams, isNativeAppHost)
76+
: throw new PlatformNotSupportedException();
6877

6978
static void ValidateMSBuildLocation(string msbuildLocation)
7079
{
@@ -156,7 +165,8 @@ private Process StartProcessUnix(NodeLaunchData nodeLaunchData, string exeName,
156165
}
157166
}
158167

159-
[SupportedOSPlatform("windows")]
168+
#if FEATURE_WINDOWSINTEROP
169+
[SupportedOSPlatform("windows6.1")]
160170
private static Process StartProcessWindows(NodeLaunchData nodeLaunchData, string exeName, uint creationFlags, bool redirectStreams, bool isNativeAppHost)
161171
{
162172
// Repeat the executable name as the first token of the command line because the command line
@@ -227,19 +237,22 @@ private static Process StartProcessWindows(NodeLaunchData nodeLaunchData, string
227237

228238
static void CloseProcessHandles(BackendNativeMethods.PROCESS_INFORMATION processInfo)
229239
{
230-
if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != NativeMethods.InvalidHandle)
240+
#pragma warning disable CA1416 // static local functions don't inherit [SupportedOSPlatform] (analyzer limitation)
241+
if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != new IntPtr(-1))
231242
{
232-
NativeMethodsShared.CloseHandle(processInfo.hProcess);
243+
PInvoke.CloseHandle((HANDLE)processInfo.hProcess);
233244
}
234245

235-
if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != NativeMethods.InvalidHandle)
246+
if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != new IntPtr(-1))
236247
{
237-
NativeMethodsShared.CloseHandle(processInfo.hThread);
248+
PInvoke.CloseHandle((HANDLE)processInfo.hThread);
238249
}
250+
#pragma warning restore CA1416
239251
}
240252
}
253+
#endif
241254

242-
[SupportedOSPlatform("windows")]
255+
[SupportedOSPlatform("windows6.1")]
243256
private static BackendNativeMethods.STARTUP_INFO CreateStartupInfo(bool redirectStreams)
244257
{
245258
var startInfo = new BackendNativeMethods.STARTUP_INFO

src/Build/Logging/InProcessConsoleConfiguration.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33

44
#nullable disable
55
using System;
6+
#if FEATURE_WINDOWSINTEROP
67
using System.Diagnostics;
8+
using Windows.Win32;
9+
using Windows.Win32.Foundation;
10+
using Windows.Win32.Storage.FileSystem;
11+
using Windows.Win32.System.Console;
12+
#endif
713

814
namespace Microsoft.Build.BackEnd.Logging;
915

@@ -24,14 +30,15 @@ public bool AcceptAnsiColorCodes
2430
get
2531
{
2632
bool acceptAnsiColorCodes = false;
33+
#if FEATURE_WINDOWSINTEROP
2734
if (NativeMethodsShared.IsWindows && !Console.IsOutputRedirected)
2835
{
2936
try
3037
{
31-
IntPtr stdOut = NativeMethodsShared.GetStdHandle(NativeMethodsShared.STD_OUTPUT_HANDLE);
32-
if (NativeMethodsShared.GetConsoleMode(stdOut, out uint consoleMode))
38+
HANDLE stdOut = PInvoke.GetStdHandle(STD_HANDLE.STD_OUTPUT_HANDLE);
39+
if (PInvoke.GetConsoleMode(stdOut, out CONSOLE_MODE consoleMode))
3340
{
34-
acceptAnsiColorCodes = (consoleMode & NativeMethodsShared.ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0;
41+
acceptAnsiColorCodes = consoleMode.HasFlag(CONSOLE_MODE.ENABLE_VIRTUAL_TERMINAL_PROCESSING);
3542
}
3643
}
3744
catch (Exception ex)
@@ -40,6 +47,7 @@ public bool AcceptAnsiColorCodes
4047
}
4148
}
4249
else
50+
#endif
4351
{
4452
// On posix OSes we expect console always supports VT100 coloring unless it is redirected
4553
acceptAnsiColorCodes = !Console.IsOutputRedirected;
@@ -75,20 +83,19 @@ public bool OutputIsScreen
7583
{
7684
bool isScreen = false;
7785

86+
#if FEATURE_WINDOWSINTEROP
7887
if (NativeMethodsShared.IsWindows)
7988
{
8089
// Get the std out handle
81-
IntPtr stdHandle = NativeMethodsShared.GetStdHandle(NativeMethodsShared.STD_OUTPUT_HANDLE);
90+
HANDLE stdHandle = PInvoke.GetStdHandle(STD_HANDLE.STD_OUTPUT_HANDLE);
8291

83-
if (stdHandle != NativeMethods.InvalidHandle)
92+
if (stdHandle != HANDLE.INVALID_HANDLE_VALUE)
8493
{
85-
uint fileType = NativeMethodsShared.GetFileType(stdHandle);
86-
87-
// The std out is a char type(LPT or Console)
88-
isScreen = fileType == NativeMethodsShared.FILE_TYPE_CHAR;
94+
isScreen = PInvoke.GetFileType(stdHandle) == FILE_TYPE.FILE_TYPE_CHAR;
8995
}
9096
}
9197
else
98+
#endif
9299
{
93100
isScreen = !Console.IsOutputRedirected;
94101
}

src/Build/Logging/SimpleErrorLogger.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public sealed class SimpleErrorLogger : INodeLogger
2424
private readonly uint? originalConsoleMode;
2525
public SimpleErrorLogger()
2626
{
27-
(acceptAnsiColorCodes, _, originalConsoleMode) = NativeMethods.QueryIsScreenAndTryEnableAnsiColorCodes(NativeMethods.StreamHandleType.StdErr);
27+
(acceptAnsiColorCodes, _, originalConsoleMode) = NativeMethods.QueryIsScreenAndTryEnableAnsiColorCodes(useStandardError: true);
2828
}
2929

3030
public bool HasLoggedErrors { get; private set; } = false;
@@ -85,7 +85,7 @@ public void Initialize(IEventSource eventSource)
8585

8686
public void Shutdown()
8787
{
88-
NativeMethods.RestoreConsoleMode(originalConsoleMode, NativeMethods.StreamHandleType.StdErr);
88+
NativeMethods.RestoreConsoleMode(originalConsoleMode, useStandardError: true);
8989
}
9090
}
9191
}

0 commit comments

Comments
 (0)