diff --git a/src/libraries/Common/src/System/IO/Win32Marshal.cs b/src/libraries/Common/src/System/IO/Win32Marshal.cs
index 2bb328411d993c..cbc75603c428b6 100644
--- a/src/libraries/Common/src/System/IO/Win32Marshal.cs
+++ b/src/libraries/Common/src/System/IO/Win32Marshal.cs
@@ -58,10 +58,22 @@ internal static Exception GetExceptionForWin32Error(int errorCode, string? path
return new OperationCanceledException();
case Interop.Errors.ERROR_INVALID_PARAMETER:
default:
+ string msg = string.IsNullOrEmpty(path)
+ ? GetPInvokeErrorMessage(errorCode)
+ : $"{GetPInvokeErrorMessage(errorCode)} : '{path}'";
return new IOException(
- string.IsNullOrEmpty(path) ? GetMessage(errorCode) : $"{GetMessage(errorCode)} : '{path}'",
+ msg,
MakeHRFromErrorCode(errorCode));
}
+
+ static string GetPInvokeErrorMessage(int errorCode)
+ {
+#if NET7_0_OR_GREATER
+ return Marshal.GetPInvokeErrorMessage(errorCode);
+#else
+ return Interop.Kernel32.GetMessage(errorCode);
+#endif
+ }
}
///
@@ -90,10 +102,5 @@ internal static int TryMakeWin32ErrorCodeFromHR(int hr)
return hr;
}
-
- ///
- /// Returns a string message for the specified Win32 error code.
- ///
- internal static string GetMessage(int errorCode) => Interop.Kernel32.GetMessage(errorCode);
}
}
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs
index 84fc7fb2b54eb3..a8ab0cf8a97391 100644
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs
@@ -203,7 +203,7 @@ private string GetMainWindowTitle()
#if DEBUG
// We never used to throw here, want to surface possible mistakes on our part
int error = Marshal.GetLastWin32Error();
- Debug.Assert(error == 0, $"Failed GetWindowTextLengthW(): { new Win32Exception(error).Message }");
+ Debug.Assert(error == 0, $"Failed GetWindowTextLengthW(): { Marshal.GetPInvokeErrorMessage(error) }");
#endif
return string.Empty;
}
@@ -222,7 +222,7 @@ private string GetMainWindowTitle()
{
// We never used to throw here, want to surface possible mistakes on our part
int error = Marshal.GetLastWin32Error();
- Debug.Assert(error == 0, $"Failed GetWindowTextW(): { new Win32Exception(error).Message }");
+ Debug.Assert(error == 0, $"Failed GetWindowTextW(): { Marshal.GetPInvokeErrorMessage(error) }");
}
#endif
return title.Slice(0, length).ToString();
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 6a4a0e062698cd..a079ceb5f11ab7 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -1881,7 +1881,6 @@
-
@@ -2176,7 +2175,6 @@
-
diff --git a/src/libraries/System.Private.CoreLib/src/System/ComponentModel/Win32Exception.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/ComponentModel/Win32Exception.Unix.cs
deleted file mode 100644
index 4caf3bf65e82c6..00000000000000
--- a/src/libraries/System.Private.CoreLib/src/System/ComponentModel/Win32Exception.Unix.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace System.ComponentModel
-{
- public partial class Win32Exception
- {
- private static string GetErrorMessage(int error) => Interop.Sys.StrError(error);
- }
-}
diff --git a/src/libraries/System.Private.CoreLib/src/System/ComponentModel/Win32Exception.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/ComponentModel/Win32Exception.Windows.cs
deleted file mode 100644
index 58a47b061b2c60..00000000000000
--- a/src/libraries/System.Private.CoreLib/src/System/ComponentModel/Win32Exception.Windows.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace System.ComponentModel
-{
- public partial class Win32Exception
- {
- private static string GetErrorMessage(int error) => Interop.Kernel32.GetMessage(error);
- }
-}
diff --git a/src/libraries/System.Private.CoreLib/src/System/ComponentModel/Win32Exception.cs b/src/libraries/System.Private.CoreLib/src/System/ComponentModel/Win32Exception.cs
index 0fde7ca4f87b3e..dfc7955362fc01 100644
--- a/src/libraries/System.Private.CoreLib/src/System/ComponentModel/Win32Exception.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/ComponentModel/Win32Exception.cs
@@ -13,7 +13,7 @@ namespace System.ComponentModel
///
[Serializable]
[System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- public partial class Win32Exception : ExternalException, ISerializable
+ public class Win32Exception : ExternalException, ISerializable
{
private const int E_FAIL = unchecked((int)0x80004005);
@@ -28,7 +28,7 @@ public Win32Exception() : this(Marshal.GetLastPInvokeError())
///
/// Initializes a new instance of the class with the specified error.
///
- public Win32Exception(int error) : this(error, GetErrorMessage(error))
+ public Win32Exception(int error) : this(error, Marshal.GetPInvokeErrorMessage(error))
{
}
///
diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Variables.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Variables.Windows.cs
index 4531aa133b7eae..a9431b299777c0 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Environment.Variables.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Variables.Windows.cs
@@ -48,10 +48,10 @@ private static void SetEnvironmentVariableCore(string variable, string? value)
case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY:
case Interop.Errors.ERROR_NO_SYSTEM_RESOURCES:
- throw new OutOfMemoryException(Interop.Kernel32.GetMessage(errorCode));
+ throw new OutOfMemoryException(Marshal.GetPInvokeErrorMessage(errorCode));
default:
- throw new ArgumentException(Interop.Kernel32.GetMessage(errorCode));
+ throw new ArgumentException(Marshal.GetPInvokeErrorMessage(errorCode));
}
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Win32.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Win32.cs
index 032f4b16ad3b6d..eb9b0adaab5250 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Environment.Win32.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Win32.cs
@@ -191,7 +191,7 @@ public static string UserDomainName
// The docs don't call this out clearly, but experimenting shows that the error returned is the following.
if (error != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
{
- throw new InvalidOperationException(Win32Marshal.GetMessage(error));
+ throw new InvalidOperationException(Marshal.GetPInvokeErrorMessage(error));
}
domainBuilder.EnsureCapacity((int)length);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Unix.cs
index 8a02bd29654f5e..a3c7bb4f4349bf 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Unix.cs
@@ -195,5 +195,15 @@ public static void SetLastSystemError(int error)
{
Interop.Sys.SetErrNo(error);
}
+
+ ///
+ /// Gets the system error message for the supplied error code.
+ ///
+ /// The error code.
+ /// The error message associated with .
+ public static string GetPInvokeErrorMessage(int error)
+ {
+ return Interop.Sys.StrError(error);
+ }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Windows.cs
index 1ea992b0a7f2e8..146e2011bf28c0 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Windows.cs
@@ -256,5 +256,15 @@ public static void SetLastSystemError(int error)
{
Interop.Kernel32.SetLastError(error);
}
+
+ ///
+ /// Gets the system error message for the supplied error code.
+ ///
+ /// The error code.
+ /// The error message associated with .
+ public static string GetPInvokeErrorMessage(int error)
+ {
+ return Interop.Kernel32.GetMessage(error);
+ }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs
index ed30d503147fe4..6d5a7050577f16 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs
@@ -1296,5 +1296,14 @@ public static int GetLastWin32Error()
{
return GetLastPInvokeError();
}
+
+ ///
+ /// Gets the system error message for the last PInvoke error code.
+ ///
+ /// The error message associated with the last PInvoke error code.
+ public static string GetLastPInvokeErrorMessage()
+ {
+ return GetPInvokeErrorMessage(GetLastPInvokeError());
+ }
}
}
diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs
index ba4ccb2687d385..5f3fa859c43e49 100644
--- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs
+++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs
@@ -586,6 +586,8 @@ public static void FreeHGlobal(System.IntPtr hglobal) { }
public static int GetLastPInvokeError() { throw null; }
public static int GetLastSystemError() { throw null; }
public static int GetLastWin32Error() { throw null; }
+ public static string GetLastPInvokeErrorMessage() { throw null; }
+ public static string GetPInvokeErrorMessage(int error) { throw null; }
[System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public static void GetNativeVariantForObject(object? obj, System.IntPtr pDstNativeVariant) { }
diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System.Runtime.InteropServices.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System.Runtime.InteropServices.Tests.csproj
index 5216e69b0d12ed..d39b569ec036f5 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System.Runtime.InteropServices.Tests.csproj
+++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System.Runtime.InteropServices.Tests.csproj
@@ -99,6 +99,7 @@
+
diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/Marshal/PInvokeErrorMessageTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/Marshal/PInvokeErrorMessageTests.cs
new file mode 100644
index 00000000000000..3ba0a261a667d4
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/Marshal/PInvokeErrorMessageTests.cs
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.ComponentModel;
+using Xunit;
+
+namespace System.Runtime.InteropServices.Tests
+{
+ public class PInvokeErrorMessageTests
+ {
+ public static IEnumerable