CA1404: Llame a GetLastError inmediatamente después de P/Invoke

Elemento Valor
RuleId CA1404
Category Microsoft.Interoperability
Cambio importante Poco problemático

Causa

Se hace una llamada al método System.Runtime.InteropServices.Marshal.GetLastWin32Error o a la función GetLastError de Win32 equivalente y la llamada inmediatamente anterior no es a un método de invocación de plataforma.

Descripción de la regla

Un método de invocación de plataforma accede al código no administrado y se define mediante la palabra clave Declare en Visual Basic o el atributo System.Runtime.InteropServices.DllImportAttribute. Por lo general, tras un error, las funciones no administradas llaman a la función SetLastError de Win32 para establecer un código de error asociado al error. El autor de la llamada de la función con errores llama a la función GetLastError de Win32 para recuperar el código de error y determinar la causa del error. El código de error se mantiene por subproceso y se sobrescribe mediante la siguiente llamada a SetLastError. Después de una llamada a un método de invocación de plataforma con errores, el código administrado puede recuperar el código de error llamando al método GetLastWin32Error. Dado que las llamadas internas pueden sobrescribir el código de error desde otros métodos de biblioteca de clases administradas, se debe llamar al método GetLastError o GetLastWin32Error inmediatamente después de la llamada al método de invocación de plataforma.

La regla omite las llamadas a los siguientes miembros administrados cuando se producen entre la llamada al método de invocación de plataforma y la llamada a GetLastWin32Error. Estos miembros no cambian el código de error y son útiles para determinar el éxito de algunas llamadas al método de invocación de plataforma.

Cómo corregir infracciones

Para corregir una infracción de esta regla, mueva la llamada a GetLastWin32Error para que siga inmediatamente la llamada al método de invocación de plataforma.

Cuándo suprimir las advertencias

Es seguro suprimir una advertencia de esta regla si el código entre la llamada al método de invocación de plataforma y la llamada al método GetLastWin32Error no puede hacer que el código de error cambie explícita o implícitamente.

Ejemplo

En el ejemplo siguiente se muestra un método que infringe la regla y un método que la cumple.

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 NativeMethods

CA1400: Deben existir puntos de entrada P/Invoke

CA1401: Los elementos P/Invoke no deben estar visibles

CA2101: Especifique cálculo de referencias para argumentos de cadena P/Invoke

CA2205: Utilizar equivalentes administrados de la API Win32