Skip to content

Commit f3414d6

Browse files
committed
Replace shared Interop.FormatMessage.cs with non-shared one
1 parent 5c521c8 commit f3414d6

20 files changed

Lines changed: 48 additions & 160 deletions

File tree

src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.FormatMessage.cs

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6-
using System.Text;
76
using System.Runtime.InteropServices;
87

98
internal partial class Interop
@@ -14,17 +13,19 @@ internal partial class Kernel32
1413
private const int FORMAT_MESSAGE_FROM_HMODULE = 0x00000800;
1514
private const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
1615
private const int FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000;
17-
18-
16+
1917
private const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
18+
private const int InitialBufferSize = 256; // small enough to be on stack, and large enough for most error messages
19+
private const int BufferSizeIncreaseFactor = 4;
20+
private const int MaxAllowedBufferSize = 65 * 1024;
2021

2122
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "FormatMessageW", SetLastError = true, BestFitMapping = true)]
22-
private static extern int FormatMessage(
23+
private static extern unsafe int FormatMessage(
2324
int dwFlags,
2425
IntPtr lpSource,
2526
uint dwMessageId,
2627
int dwLanguageId,
27-
[Out] StringBuilder lpBuffer,
28+
char* lpBuffer,
2829
int nSize,
2930
IntPtr[] arguments);
3031

@@ -38,50 +39,54 @@ internal static string GetMessage(int errorCode)
3839

3940
internal static string GetMessage(IntPtr moduleHandle, int errorCode)
4041
{
41-
var sb = new StringBuilder(InitialBufferSize);
42+
Span<char> buffer = stackalloc char[InitialBufferSize];
4243
do
4344
{
44-
string errorMsg;
45-
if (TryGetErrorMessage(moduleHandle, errorCode, sb, out errorMsg))
45+
if (TryGetErrorMessage(moduleHandle, errorCode, buffer, out string errorMsg))
4646
{
4747
return errorMsg;
4848
}
49-
else
50-
{
51-
// increase the capacity of the StringBuilder.
52-
sb.Capacity *= BufferSizeIncreaseFactor;
53-
}
49+
50+
// Increase the capacity of the buffer.
51+
buffer = new char[buffer.Length * BufferSizeIncreaseFactor];
5452
}
55-
while (sb.Capacity < MaxAllowedBufferSize);
53+
while (buffer.Length < MaxAllowedBufferSize);
5654

5755
// If you come here then a size as large as 65K is also not sufficient and so we give the generic errorMsg.
5856
return string.Format("Unknown error (0x{0:x})", errorCode);
5957
}
6058

61-
private static bool TryGetErrorMessage(IntPtr moduleHandle, int errorCode, StringBuilder sb, out string errorMsg)
59+
private static bool TryGetErrorMessage(IntPtr moduleHandle, int errorCode, Span<char> buffer, out string errorMsg)
6260
{
63-
errorMsg = "";
64-
6561
int flags = FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY;
6662
if (moduleHandle != IntPtr.Zero)
6763
{
6864
flags |= FORMAT_MESSAGE_FROM_HMODULE;
6965
}
7066

71-
int result = FormatMessage(flags, moduleHandle, (uint)errorCode, 0, sb, sb.Capacity, null);
67+
int result;
68+
unsafe
69+
{
70+
fixed (char* bufferPtr = &MemoryMarshal.GetReference(buffer))
71+
{
72+
result = FormatMessage(flags, moduleHandle, unchecked((uint)errorCode), 0, bufferPtr, buffer.Length, null);
73+
}
74+
}
75+
7276
if (result != 0)
7377
{
74-
int i = sb.Length;
78+
int i = result;
7579
while (i > 0)
7680
{
77-
char ch = sb[i - 1];
81+
char ch = buffer[i - 1];
7882
if (ch > 32 && ch != '.') break;
7983
i--;
8084
}
81-
errorMsg = sb.ToString(0, i);
85+
errorMsg = buffer.Slice(0, i).ToString();
8286
}
8387
else if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
8488
{
89+
errorMsg = "";
8590
return false;
8691
}
8792
else
@@ -105,8 +110,5 @@ private static bool TryGetErrorMessage(IntPtr moduleHandle, int errorCode, Strin
105110
//
106111
// As a result we use the following approach.
107112
// We initially call the API with a buffer size of 256 and then gradually increase the size in case of failure until we reach the maximum allowed limit of 65K.
108-
private const int InitialBufferSize = 256;
109-
private const int BufferSizeIncreaseFactor = 4;
110-
private const int MaxAllowedBufferSize = 65 * 1024;
111113
}
112114
}

src/Common/src/Interop/Windows/kernel32/Interop.FormatMessage.cs

Lines changed: 0 additions & 114 deletions
This file was deleted.

src/Common/tests/Common.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108
<Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
109109
</Compile>
110110
<Compile Include="Tests\System\IO\PathInternal.Windows.Tests.cs" />
111-
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs">
111+
<Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.FormatMessage.cs">
112112
<Link>Common\Interop\Windows\kernel32\Interop.FormatMessage.cs</Link>
113113
</Compile>
114114
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">

src/Microsoft.Win32.Primitives/src/Microsoft.Win32.Primitives.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
2222
<Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
2323
</Compile>
24-
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs">
24+
<Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.FormatMessage.cs">
2525
<Link>Common\Interop\Windows\Interop.FormatMessage.cs</Link>
2626
</Compile>
2727
<Compile Include="System\ComponentModel\Win32Exception.Windows.cs" />

src/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">
5252
<Link>Common\Interop\Windows\Interop.Errors.cs</Link>
5353
</Compile>
54-
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs">
54+
<Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.FormatMessage.cs">
5555
<Link>Common\Interop\Windows\Interop.FormatMessage.cs</Link>
5656
</Compile>
5757
<Compile Include="$(CommonPath)\Interop\Windows\advapi32\Interop.RegCloseKey.cs">
@@ -122,4 +122,4 @@
122122
<Reference Include="System.Security.Principal.Windows" />
123123
</ItemGroup>
124124
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
125-
</Project>
125+
</Project>

src/System.Console/src/System.Console.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.Beep.cs">
5757
<Link>Common\Interop\Windows\Interop.Beep.cs</Link>
5858
</Compile>
59-
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs">
59+
<Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.FormatMessage.cs">
6060
<Link>Common\Interop\Windows\Interop.FormatMessage.cs</Link>
6161
</Compile>
6262
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.ConsoleCursorInfo.cs">

src/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">
5858
<Link>Common\Interop\Windows\Interop.Errors.cs</Link>
5959
</Compile>
60-
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs">
60+
<Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.FormatMessage.cs">
6161
<Link>Common\Interop\Windows\Interop.FormatMessage.cs</Link>
6262
</Compile>
6363
<Compile Include="$(CommonPath)\CoreLib\System\IO\Win32Marshal.cs">

src/System.IO.FileSystem/src/System.IO.FileSystem.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">
7070
<Link>Common\Interop\Windows\Interop.Errors.cs</Link>
7171
</Compile>
72-
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs">
72+
<Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.FormatMessage.cs">
7373
<Link>Common\Interop\Windows\Interop.FormatMessage.cs</Link>
7474
</Compile>
7575
<Compile Include="$(CommonPath)\System\HResults.cs">

src/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">
7070
<Link>Common\Interop\Windows\Interop.Errors.cs</Link>
7171
</Compile>
72-
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs">
72+
<Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.FormatMessage.cs">
7373
<Link>Common\Interop\Windows\Interop.FormatMessage.cs</Link>
7474
</Compile>
7575
<Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.FileAttributes.cs">

src/System.IO.Pipes/src/System.IO.Pipes.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">
4646
<Link>Common\Interop\Windows\Interop.Errors.cs</Link>
4747
</Compile>
48-
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs">
48+
<Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.FormatMessage.cs">
4949
<Link>Common\Interop\Windows\Interop.FormatMessage.cs</Link>
5050
</Compile>
5151
<Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.SecurityOptions.cs">

0 commit comments

Comments
 (0)