CA1404: Call GetLastError immediately after P/Invoke
A call is made to the Marshal.GetLastWin32Error method or the equivalent Win32 GetLastError function, and the call that comes immediately before is not to a platform invoke method.
A platform invoke method accesses unmanaged code and is defined by using the Declare keyword in Visual Basic or the System.Runtime.InteropServices.DllImportAttribute attribute. Generally, upon failure, unmanaged functions call the Win32 SetLastError function to set an error code that is associated with the failure. The caller of the failed function calls the Win32 GetLastError function to retrieve the error code and determine the cause of the failure. The error code is maintained on a per-thread basis and is overwritten by the next call to SetLastError. After a call to a failed platform invoke method, managed code can retrieve the error code by calling the GetLastWin32Error method. Because the error code can be overwritten by internal calls from other managed class library methods, the GetLastError or GetLastWin32Error method should be called immediately after the platform invoke method call.
The rule ignores calls to the following managed members when they occur between the call to the platform invoke method and the call to GetLastWin32Error. These members do not change the error code and are useful for determining the success of some platform invoke method calls.
To fix a violation of this rule, move the call to GetLastWin32Error so that it immediately follows the call to the platform invoke method.
It is safe to suppress a warning from this rule if the code between the platform invoke method call and the GetLastWin32Error method call cannot explicitly or implicitly cause the error code to change.
The following example shows a method that violates the rule and a method that satisfies the rule.
Imports System Imports System.Runtime.InteropServices Imports System.Text Namespace InteroperabilityLibrary Class NativeMethods Private Sub New() End Sub ' Violates rule UseManagedEquivalentsOfWin32Api. Friend Declare Auto Function _ ExpandEnvironmentStrings Lib "kernel32.dll" _ (lpSrc As String, lpDst As StringBuilder, nSize As Integer) _ As Integer End Class Public Class UseNativeMethod Dim environmentVariable As String = "%TEMP%" Dim expandedVariable As StringBuilder Sub ViolateRule() expandedVariable = New StringBuilder(100) If NativeMethods.ExpandEnvironmentStrings( _ environmentVariable, _ expandedVariable, _ expandedVariable.Capacity) = 0 ' Violates rule CallGetLastErrorImmediatelyAfterPInvoke. Console.Error.WriteLine(Marshal.GetLastWin32Error()) Else Console.WriteLine(expandedVariable) End If End Sub Sub SatisfyRule() expandedVariable = New StringBuilder(100) If NativeMethods.ExpandEnvironmentStrings( _ environmentVariable, _ expandedVariable, _ expandedVariable.Capacity) = 0 ' Satisfies rule CallGetLastErrorImmediatelyAfterPInvoke. Dim lastError As Integer = Marshal.GetLastWin32Error() Console.Error.WriteLine(lastError) Else Console.WriteLine(expandedVariable) End If End Sub End Class End Namespace