Skip to content

Commit

Permalink
Add remarks to last error Marshal APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
elinor-fung committed Oct 29, 2021
1 parent f532ec7 commit e7a7126
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//<snippet1>
using System;
using System.Runtime.InteropServices;

// These functions specify SetLastError=true to propagate the last error from the p/invoke
// such that it can be retrieved using Marshal.GetLastPInvokeError().
internal static class Kernel32
{
[DllImport(nameof(Kernel32), ExactSpelling = true, SetLastError = true)]
internal static extern bool SetCurrentDirectoryW([MarshalAs(UnmanagedType.LPWStr)] string path);
}

internal static class libc
{
[DllImport(nameof(libc), SetLastError = true)]
internal static extern int chdir([MarshalAs(UnmanagedType.LPUTF8Str)] string path);
}

class Program
{
public static void Main(string[] args)
{
// Call p/invoke with valid arguments.
CallPInvoke(AppContext.BaseDirectory);

// Call p/invoke with invalid arguments.
CallPInvoke(string.Empty);
}

private static void CallPInvoke(string path)
{
if (OperatingSystem.IsWindows())
{
Console.WriteLine($"Calling SetCurrentDirectoryW with path '{path}'");
Kernel32.SetCurrentDirectoryW(path);
}
else
{
Console.WriteLine($"Calling chdir with path '{path}'");
libc.chdir(path);
}

// Get the last p/invoke error and display it.
int error = Marshal.GetLastPInvokeError();
Console.WriteLine($"Last p/invoke error: {error}");
}
}
//</snippet1>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

</Project>
9 changes: 5 additions & 4 deletions xml/System.Runtime.InteropServices/DllImportAttribute.xml
Original file line number Diff line number Diff line change
Expand Up @@ -557,15 +557,16 @@
<ReturnType>System.Boolean</ReturnType>
</ReturnValue>
<Docs>
<summary>Indicates whether the callee calls the <see langword="SetLastError" /> Windows API function before returning from the attributed method.</summary>
<summary>Indicates whether the callee sets an error (<see langword="SetLastError" /> on Windows or `errno` on other platforms) before returning from the attributed method.</summary>
<remarks>
<format type="text/markdown"><![CDATA[
## Remarks
`true` to indicate that the callee will call `SetLastError`; otherwise, `false`. The default is `false`.
The runtime marshaler calls `GetLastError` and caches the value returned to prevent it from being overwritten by other API calls. You can retrieve the error code by calling <xref:System.Runtime.InteropServices.Marshal.GetLastWin32Error%2A>.
`true` to indicate that the callee will set an error via `SetLastError` on Windows or `errno` on other platforms; otherwise, `false`. The default is `false`.
The runtime marshaler calls `GetLastError` or `errno` and caches the value returned to prevent it from being overwritten by other API calls.
You can retrieve the error code by calling <xref:System.Runtime.InteropServices.Marshal.GetLastWin32Error%2A> on .NET 6.0 and above
or <xref:System.Runtime.InteropServices.Marshal.GetLastWin32Error%2A> on .NET 5.0 and below or .NET Framework.
## Examples
Expand Down
47 changes: 34 additions & 13 deletions xml/System.Runtime.InteropServices/Marshal.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4362,15 +4362,26 @@
</ReturnValue>
<Parameters />
<Docs>
<summary>Get the last platform invoke error on the current thread</summary>
<returns>The last platform invoke error</returns>
<summary>Get the last platform invoke error on the current thread.</summary>
<returns>The last platform invoke error.</returns>
<remarks>
<format type="text/markdown"><![CDATA[

## Remarks

The last platform invoke error corresponds to the error set by either the most recent platform
invoke that was configured to set the last error or a call to <xref:System.Runtime.InteropServices.Marshal.SetLastPInvokeError(System.Int32)>.
The last platform invoke error corresponds to the error set either by the most recent platform invoke that was
configured with <xref:System.Runtime.InteropServices.DllImportAttribute.SetLastError?displayProperty=nameWithType>
set to `true` or by a call to <xref:System.Runtime.InteropServices.Marshal.SetLastPInvokeError(System.Int32)>.

This method will only return errors set via the mentioned scenarios. To get the last system error independent of
platform invoke usage, use <xref:System.Runtime.InteropServices.Marshal.GetLastSystemError%2A>.

## Examples

The following example defines a p/invoke with <xref:System.Runtime.InteropServices.DllImportAttribute.SetLastError?displayProperty=nameWithType>
set to `true` and demonstrates using <xref:System.Runtime.InteropServices.Marshal.GetLastPInvokeError%2A> to get the last p/invoke error.

:::code language="csharp" source="~/samples/snippets/csharp/System.Runtime.InteropServices/Marshal/GetLastPInvokeError.cs" id="Snippet1":::

]]></format>
</remarks>
Expand Down Expand Up @@ -4399,14 +4410,14 @@ The last platform invoke error corresponds to the error set by either the most r
</ReturnValue>
<Parameters />
<Docs>
<summary>Get the last system error on the current thread</summary>
<returns>The last system error</returns>
<summary>Get the last system error on the current thread.</summary>
<returns>The last system error.</returns>
<remarks>
<format type="text/markdown"><![CDATA[

## Remarks

The error is that for the current operating system (e.g. errno on Unix, GetLastError on Windows)
The system error is based on the current operating system &mdash that is, `errno` on non-Windows and <see href="/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror">GetLastError</see> on Windows.

]]></format>
</remarks>
Expand Down Expand Up @@ -4473,6 +4484,8 @@ You can use this method to obtain error codes only if you apply the <xref:System

There is a difference in the behavior of the `GetLastWin32Error` method on .NET Core and .NET Framework when <xref:System.Runtime.InteropServices.DllImportAttribute.SetLastError?displayProperty=nameWithType> is `true`. On .NET Framework, the `GetLastWin32Error` method can retain error information from one P/Invoke call to the next. On .NET Core, error information is cleared before P/Invoke call, and the `GetLastWin32Error` represents only error information from the last method call.

On .NET 6.0 and above, this method is functionally equivalent to <xref:System.Runtime.InteropServices.Marshal.GetLastPInvokeError%2A>, which is named to better reflect the intent of the API and its cross-platform nature. <xref:System.Runtime.InteropServices.Marshal.GetLastPInvokeError%2A> should be preferred over <xref:System.Runtime.InteropServices.Marshal.GetLastWin32Error%2A>.

## Examples
The following example calls the `GetLastWin32Error` method. The example first demonstrates calling the method with no error present and then demonstrates calling the method with an error present.

Expand Down Expand Up @@ -9692,9 +9705,17 @@ There is a difference in the behavior of the `GetLastWin32Error` method on .NET
<Parameter Name="error" Type="System.Int32" Index="0" FrameworkAlternate="net-6.0" />
</Parameters>
<Docs>
<param name="error">Error to set</param>
<summary>Set the last platform invoke error on the current thread</summary>
<remarks>To be added.</remarks>
<param name="error">Error to set.</param>
<summary>Set the last platform invoke error on the current thread.</summary>
<remarks>
<format type="text/markdown"><![CDATA[

## Remarks

The last platform invoke error is stored per-thread and can be retrieved using <xref:System.Runtime.InteropServices.Marshal.GetLastPInvokeError(System.Int32)>.

]]></format>
</remarks>
</Docs>
</Member>
<Member MemberName="SetLastSystemError">
Expand Down Expand Up @@ -9722,14 +9743,14 @@ There is a difference in the behavior of the `GetLastWin32Error` method on .NET
<Parameter Name="error" Type="System.Int32" Index="0" FrameworkAlternate="net-6.0" />
</Parameters>
<Docs>
<param name="error">Error to set</param>
<summary>Set the last system error on the current thread</summary>
<param name="error">Error to set.</param>
<summary>Set the last system error on the current thread.</summary>
<remarks>
<format type="text/markdown"><![CDATA[

## Remarks

The error is that for the current operating system (e.g. errno on Unix, SetLastError on Windows)
The system error is based on the current operating system &mdash; that is, `errno` on Unix and <see href="/windows/win32/api/errhandlingapi/nf-errhandlingapi-setlasterror">SetLastError</see> on Windows.

]]></format>
</remarks>
Expand Down

0 comments on commit e7a7126

Please sign in to comment.