CA1404: Llame a GetLastError inmediatamente después de P/InvokeCA1404: Call GetLastError immediately after P/Invoke

TypeNameTypeName CallGetLastErrorImmediatelyAfterPInvokeCallGetLastErrorImmediatelyAfterPInvoke
Identificador de comprobaciónCheckId CA1404CA1404
CategoríaCategory Microsoft.InteroperabilityMicrosoft.Interoperability
Cambio problemáticoBreaking Change Poco problemáticoNon-breaking

MotivoCause

Se realiza una llamada a la System.Runtime.InteropServices.Marshal.GetLastWin32Error método o el equivalente de Win32 GetLastError función y la llamada que se incluye inmediatamente anterior no es una plataforma de invocación de método.A call is made to the System.Runtime.InteropServices.Marshal.GetLastWin32Error method or the equivalent Win32 GetLastError function, and the call that comes immediately before is not to a platform invoke method.

Descripción de la reglaRule Description

Una plataforma de invocación de método tiene acceso al código no administrado y se define utilizando la Declare palabra clave en Visual BasicVisual Basic o System.Runtime.InteropServices.DllImportAttribute atributo.A platform invoke method accesses unmanaged code and is defined by using the Declare keyword in Visual BasicVisual Basic or the System.Runtime.InteropServices.DllImportAttribute attribute. Por lo general, en caso de error, las funciones no administradas llamadas Win32 SetLastError función para establecer un código de error que está asociado con el error.Generally, upon failure, unmanaged functions call the Win32 SetLastError function to set an error code that is associated with the failure. El llamador de la función con errores llama Win32 GetLastError función para recuperar el código de error y determinar la causa del error.The caller of the failed function calls the Win32 GetLastError function to retrieve the error code and determine the cause of the failure. El código de error se mantiene por subproceso y se sobrescribe con la siguiente llamada a SetLastError.The error code is maintained on a per-thread basis and is overwritten by the next call to SetLastError. Después de una llamada a una plataforma de error al invocar el método, el código administrado puede recuperar el código de error mediante una llamada a la GetLastWin32Error método.After a call to a failed platform invoke method, managed code can retrieve the error code by calling the GetLastWin32Error method. Ya que el código de error puede sobrescribirse mediante llamadas internas desde otros métodos de la biblioteca de clase administrada, el GetLastError o GetLastWin32Error debe llamarse al método inmediatamente después de llamada al método de invocación de plataforma.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.

La regla omite las llamadas a los siguientes miembros administrados cuando se producen entre la llamada a la plataforma de invocación de método y la llamada a GetLastWin32Error.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. Estos miembros no cambian el error llamadas de método de invocación de código y son útiles para determinar el éxito de algunas plataformas.These members do not change the error code and are useful for determining the success of some platform invoke method calls.

Cómo corregir infraccionesHow to Fix Violations

Para corregir una infracción de esta regla, mueva la llamada a GetLastWin32Error por lo que sigue inmediatamente a la llamada a la plataforma de invocación de método.To fix a violation of this rule, move the call to GetLastWin32Error so that it immediately follows the call to the platform invoke method.

Cuándo suprimir advertenciasWhen to Suppress Warnings

Es seguro suprimir una advertencia de esta regla si el código entre la plataforma de invocar la llamada al método y el GetLastWin32Error llamada al método no puede hacer explícitamente o implícitamente cambiar el código de error.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.

EjemploExample

En el ejemplo siguiente se muestra un método que infringe la regla y un método que cumple la regla.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
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace InteroperabilityLibrary
{
   internal class NativeMethods
   {
      private NativeMethods() {}

      // Violates rule UseManagedEquivalentsOfWin32Api.
      [DllImport("kernel32.dll", CharSet = CharSet.Auto, 
          SetLastError = true)]
      internal static extern int ExpandEnvironmentStrings(
         string lpSrc, StringBuilder lpDst, int nSize);
   }

   public class UseNativeMethod
   {
      string environmentVariable = "%TEMP%";
      StringBuilder expandedVariable;

      public void 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);
         }
      }

      public void SatisfyRule()
      {
         expandedVariable = new StringBuilder(100);

         if(NativeMethods.ExpandEnvironmentStrings(
            environmentVariable, 
            expandedVariable, 
            expandedVariable.Capacity) == 0)
         {
            // Satisfies rule CallGetLastErrorImmediatelyAfterPInvoke.
            int lastError = Marshal.GetLastWin32Error();
            Console.Error.WriteLine(lastError);
         }
         else
         {
            Console.WriteLine(expandedVariable);
         }
      }
   }
}

CA1060: Mueva P/Invokes a la clase NativeMethodsCA1060: Move P/Invokes to NativeMethods class

CA1400: Deben existir puntos de entrada P/InvokeCA1400: P/Invoke entry points should exist

CA1401: P/Invoke no deben estar visibleCA1401: P/Invokes should not be visible

CA2101: Especifique cálculo de referencias para argumentos de cadena P/InvokeCA2101: Specify marshaling for P/Invoke string arguments

CA2205: Utilizar equivalentes administrados de la API Win32CA2205: Use managed equivalents of Win32 API