Condividi tramite


CA1404: Chiamare GetLastError immediatamente dopo P/Invoke

Articolo Valore
ID regola CA1404
Category Microsoft.Interoperability
Modifica Nessuna interruzione

Causa

Viene effettuata una chiamata al System.Runtime.InteropServices.Marshal.GetLastWin32Error metodo o alla funzione Win32 GetLastError equivalente e la chiamata immediatamente precedente a un metodo platform invoke.

Descrizione regola

Un metodo platform invoke accede al codice non gestito e viene definito usando la Declare parola chiave in Visual Basic o l'attributo System.Runtime.InteropServices.DllImportAttribute . In genere, in caso di errore, le funzioni non gestite chiamano la funzione Win32 SetLastError per impostare un codice di errore associato all'errore. Il chiamante della funzione non riuscita chiama la funzione Win32 GetLastError per recuperare il codice di errore e determinare la causa dell'errore. Il codice di errore viene mantenuto per ogni thread e viene sovrascritto dalla chiamata successiva a SetLastError. Dopo una chiamata a un metodo platform invoke non riuscito, il codice gestito può recuperare il codice di errore chiamando il GetLastWin32Error metodo . Poiché il codice di errore può essere sovrascritto da chiamate interne da altri metodi della libreria di classi gestite, il GetLastError metodo o GetLastWin32Error deve essere chiamato immediatamente dopo la chiamata al metodo platform invoke.

La regola ignora le chiamate ai membri gestiti seguenti quando si verificano tra la chiamata al metodo platform invoke e la chiamata a GetLastWin32Error. Questi membri non modificano il codice di errore e sono utili per determinare l'esito positivo di alcune chiamate al metodo platform invoke.

Come correggere le violazioni

Per correggere una violazione di questa regola, spostare la chiamata a GetLastWin32Error in modo che segua immediatamente la chiamata al metodo platform invoke.

Quando eliminare gli avvisi

È possibile eliminare un avviso da questa regola se il codice tra la chiamata al metodo platform invoke e la chiamata al GetLastWin32Error metodo non può modificare in modo esplicito o implicito il codice di errore.

Esempio

Nell'esempio seguente viene illustrato un metodo che viola la regola e un metodo che soddisfa la regola.

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: Spostare P/Invoke nella classe NativeMethods

CA1400: I punti di ingresso P/Invoke devono esistere

CA1401: I P/Invoke non devono essere visibili

CA2101: Specificare il marshalling per argomenti di stringa P/Invoke

CA2205: Usare equivalenti gestiti dell'API Win32