CA1404 : Appeler GetLastError immédiatement après P/Invoke

Élément Valeur
ID de la règle CA1404
Category Microsoft.Interoperability
Modification avec rupture Sans rupture

Cause

Un appel est effectué à la méthode System.Runtime.InteropServices.Marshal.GetLastWin32Error ou à la fonction Win32 GetLastError équivalente, et l’appel qui vient immédiatement avant n’est pas à une méthode d’appel de code non managé.

Description de la règle

Une méthode d’appel de code non managé accède au code non managé et est définie à l’aide du mot clé Declare dans Visual Basic ou de l’attribut System.Runtime.InteropServices.DllImportAttribute. En règle générale, en cas d’échec, les fonctions non managées appellent la fonction Win32 SetLastError pour définir un code d’erreur associé à l’échec. L’appelant de la fonction ayant échoué appelle la fonction Win32 GetLastError pour récupérer le code d’erreur et déterminer la cause de l’échec. Le code d’erreur est conservé par thread et est remplacé par l’appel suivant à SetLastError. Après un appel à une méthode d’appel de code non managé ayant échoué, le code managé peut récupérer le code d’erreur en appelant la méthode GetLastWin32Error. Étant donné que le code d’erreur peut être remplacé par des appels internes à partir d’autres méthodes de bibliothèque de classes managées, la méthode GetLastError ou GetLastWin32Error doit être appelée immédiatement après l’appel de la méthode d’appel de code non managé.

La règle ignore les appels aux membres managés suivants lorsqu’ils se produisent entre l’appel à la méthode d’appel de code non managé et l’appel à GetLastWin32Error. Ces membres ne modifient pas le code d’erreur et sont utiles pour déterminer la réussite de certains appels de méthode d’appel de code non managé.

Comment corriger les violations

Pour corriger une violation de cette règle, déplacez l’appel à GetLastWin32Error pour qu’il suit immédiatement l’appel à la méthode d’appel de code non managé.

Quand supprimer les avertissements

Il est possible de supprimer un avertissement de cette règle si le code entre l’appel de méthode d’appel de code non managé et l’appel de méthode GetLastWin32Error ne peut pas entraîner explicitement ou implicitement la modification du code d’erreur.

Exemple

L’exemple suivant montre une méthode qui enfreint la règle et une méthode qui est conforme à la règle.

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 : Déplacer les P/Invoke vers une classe NativeMethods

CA1400 : Des points d’entrée P/Invoke doivent exister

CA1401 : Les P/Invoke ne doivent pas être visibles

CA2101 : Spécifier le marshaling pour les arguments de chaîne P/Invoke

CA2205 : Utilisez des équivalents managés de l'API Win32