Skip to content

Commit

Permalink
Switch to the now-built-in Marshal APIs from MarshalEx (#1042)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkoritzinsky authored Apr 30, 2021
1 parent e111609 commit 26dec3e
Show file tree
Hide file tree
Showing 12 changed files with 26 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

<PropertyGroup>
<AssemblyName>Microsoft.Interop.Ancillary</AssemblyName>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<RootNamespace>System.Runtime.InteropServices</RootNamespace>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseCustomRuntimeVersion>false</UseCustomRuntimeVersion>
</PropertyGroup>

</Project>
91 changes: 2 additions & 89 deletions DllImportGenerator/Ancillary.Interop/MarshalEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,97 +7,10 @@ namespace System.Runtime.InteropServices
/// <summary>
/// Marshalling helper methods that will likely live in S.R.IS.Marshal
/// when we integrate our APIs with dotnet/runtime.
/// When referencing this type in a source-generator, make sure to use
/// the TypeNames.MarshalEx method to enable configuration when dogfooding.
/// </summary>
public static class MarshalEx
{
/// <summary>
/// Sets the handle of <paramref name="safeHandle"/> to the specified <paramref name="handle"/>.
/// </summary>
/// <param name="safeHandle"><see cref="SafeHandle"/> instance to update</param>
/// <param name="handle">Pre-existing handle</param>
public static void InitHandle(SafeHandle safeHandle, IntPtr handle)
{
typeof(SafeHandle).GetMethod("SetHandle", BindingFlags.NonPublic | BindingFlags.Instance)!.Invoke(safeHandle, new object[] { handle });
}

/// <summary>
/// Set the last platform invoke error on the thread
/// </summary>
public static void SetLastPInvokeError(int error)
{
MethodInfo? method = typeof(Marshal).GetMethod("SetLastWin32Error", BindingFlags.NonPublic | BindingFlags.Static);
if (method == null)
{
method = typeof(Marshal).GetMethod("SetLastPInvokeError", BindingFlags.Public | BindingFlags.Static);
}

method!.Invoke(null, new object[] { error });
}

/// <summary>
/// Get the last system error on the current thread (errno on Unix, GetLastError on Windows)
/// </summary>
public static unsafe int GetLastSystemError()
{
// Would be internal call that handles getting the last error for the thread using the PAL

if (OperatingSystem.IsWindows())
{
return Kernel32.GetLastError();
}
else if (OperatingSystem.IsMacOS())
{
return *libc.__error();
}
else if (OperatingSystem.IsLinux())
{
return *libc.__errno_location();
}

throw new NotImplementedException();
}

/// <summary>
/// Set the last system error on the current thread (errno on Unix, SetLastError on Windows)
/// </summary>
public static unsafe void SetLastSystemError(int error)
{
// Would be internal call that handles setting the last error for the thread using the PAL

if (OperatingSystem.IsWindows())
{
Kernel32.SetLastError(error);
}
else if (OperatingSystem.IsMacOS())
{
*libc.__error() = error;
}
else if (OperatingSystem.IsLinux())
{
*libc.__errno_location() = error;
}
else
{
throw new NotImplementedException();
}
}

private class Kernel32
{
[DllImport(nameof(Kernel32))]
public static extern void SetLastError(int error);

[DllImport(nameof(Kernel32))]
public static extern int GetLastError();
}

private class libc
{
[DllImport(nameof(libc))]
internal static unsafe extern int* __errno_location();

[DllImport(nameof(libc))]
internal static unsafe extern int* __error();
}
}
}
2 changes: 1 addition & 1 deletion DllImportGenerator/Benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
Expand Down
5 changes: 1 addition & 4 deletions DllImportGenerator/Demo/Demo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>

<!-- Indicate to the compiler to output generated files to disk. Source addded
by the DllImportGenerator can be found in the intermediate directory. -->
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>

<!-- See https://github.com/dotnet/runtime/issues/42745 for why this is needed. -->
<UseAppHost>true</UseAppHost>
<IsPackable>false</IsPackable>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Import Project="$(RepoRoot)DllImportGenerator\DllImportGenerator\Microsoft.Interop.DllImportGenerator.props" />

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>Preview</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public SetLastErrorMarshaller(int i)
public int ToManaged()
{
// Explicity set the last error to something else on unmarshalling
MarshalEx.SetLastPInvokeError(val * 2);
Marshal.SetLastPInvokeError(val * 2);
return val;
}
}
Expand Down Expand Up @@ -54,12 +54,12 @@ public void LastWin32Error_HasExpectedValue(int error)
Assert.Equal(errorString, ret);

// Clear the last error
MarshalEx.SetLastPInvokeError(0);
Marshal.SetLastPInvokeError(0);

NativeExportsNE.SetLastError.SetError(error, shouldSetError: 1);
Assert.Equal(error, Marshal.GetLastWin32Error());

MarshalEx.SetLastPInvokeError(0);
Marshal.SetLastPInvokeError(0);

// Custom marshalling sets the last error on unmarshalling.
// Last error should reflect error from native call, not unmarshalling.
Expand All @@ -71,15 +71,15 @@ public void LastWin32Error_HasExpectedValue(int error)
public void ClearPreviousError()
{
int error = 100;
MarshalEx.SetLastPInvokeError(error);
Marshal.SetLastPInvokeError(error);

// Don't actually set the error in the native call. SetLastError=true should clear any existing error.
string errorString = error.ToString();
string ret = NativeExportsNE.SetLastError.SetError_NonBlittableSignature(error, shouldSetError: false, errorString);
Assert.Equal(0, Marshal.GetLastWin32Error());
Assert.Equal(errorString, ret);

MarshalEx.SetLastPInvokeError(error);
Marshal.SetLastPInvokeError(error);

// Don't actually set the error in the native call. SetLastError=true should clear any existing error.
NativeExportsNE.SetLastError.SetError(error, shouldSetError: 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>Preview</LangVersion>
<Nullable>enable</Nullable>
Expand Down
10 changes: 8 additions & 2 deletions DllImportGenerator/DllImportGenerator.UnitTests/TestUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.CodeAnalysis.Testing;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -71,8 +72,13 @@ public static async Task<Compilation> CreateCompilationWithReferenceAssemblies(s

public static (ReferenceAssemblies, MetadataReference) GetReferenceAssemblies()
{
// TODO: When .NET 5.0 releases, we can simplify this.
var referenceAssemblies = ReferenceAssemblies.Net.Net50;
// TODO: When .NET 6.0 releases, we can simplify this.
var referenceAssemblies = new ReferenceAssemblies(
"net6.0",
new PackageIdentity(
"Microsoft.NETCore.App.Ref",
"6.0.0-preview.5.21226.5"),
Path.Combine("ref", "net6.0"));

// Include the assembly containing the new attribute and all of its references.
// [TODO] Remove once the attribute has been added to the BCL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeCont
StatementSyntax unmarshalStatement = ExpressionStatement(
InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
ParseTypeName(TypeNames.MarshalEx(options)),
ParseTypeName(TypeNames.System_Runtime_InteropServices_Marshal),
IdentifierName("InitHandle")),
ArgumentList(SeparatedList(
new []
Expand Down
6 changes: 3 additions & 3 deletions DllImportGenerator/DllImportGenerator/StubCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ public override (string managed, string native) GetIdentifiers(TypePositionInfo
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
ParseName(TypeNames.MarshalEx(options)),
ParseName(TypeNames.System_Runtime_InteropServices_Marshal),
IdentifierName("SetLastSystemError")),
ArgumentList(SingletonSeparatedList(
Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(SuccessErrorCode)))))));
Expand All @@ -274,7 +274,7 @@ public override (string managed, string native) GetIdentifiers(TypePositionInfo
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
ParseName(TypeNames.MarshalEx(options)),
ParseName(TypeNames.System_Runtime_InteropServices_Marshal),
IdentifierName("GetLastSystemError")))));

invokeStatement = Block(clearLastError, invokeStatement, getLastError);
Expand Down Expand Up @@ -326,7 +326,7 @@ public override (string managed, string native) GetIdentifiers(TypePositionInfo
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
ParseName(TypeNames.MarshalEx(options)),
ParseName(TypeNames.System_Runtime_InteropServices_Marshal),
IdentifierName("SetLastPInvokeError")),
ArgumentList(SingletonSeparatedList(
Argument(IdentifierName(LastErrorIdentifier)))))));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<AssemblyName>Microsoft.Interop.Tests.NativeExports</AssemblyName>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableDynamicLoading>true</EnableDynamicLoading>
<DnneAddGeneratedBinaryToProject>true</DnneAddGeneratedBinaryToProject>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

Expand Down

0 comments on commit 26dec3e

Please sign in to comment.