CA1404: GetLastError unmittelbar nach P/Invoke aufrufen

TypeName

CallGetLastErrorImmediatelyAfterPInvoke

CheckId

CA1404

Kategorie (Category)

Microsoft.Interoperability

Unterbrechende Änderung

Nicht unterbrechend

Ursache

Die Marshal.GetLastWin32Error-Methode oder die entsprechende GetLastError-Win32-Funktion wird aufgerufen, und unmittelbar zuvor wird keine Plattformaufrufmethode aufgerufen.

Regelbeschreibung

Eine Plattformaufrufmethode greift auf nicht verwalteten Code zu und wird mit dem Declare-Schlüsselwort in Visual Basic oder dem DllImportAttribute-Attribut definiert.Bei einem Fehler rufen nicht verwaltete Funktionen im Allgemeinen die SetLastError-Win32-Funktion auf, um einen Fehlercode festzulegen, der dem Fehler zugeordnet wird.Der Aufrufer der fehlgeschlagenen Funktion ruft die GetLastError-Win32-Funktion auf, um den Fehlercode abzurufen und die Ursache des Fehlers zu ermitteln.Der Fehlercode wird threadweise verwaltet und durch den nächsten Aufruf von SetLastError überschrieben.Nach einem Aufruf einer fehlgeschlagenen Plattformaufrufmethode kann der Fehlercode durch verwalteten Code abgerufen werden. Dazu wird die GetLastWin32Error-Methode aufgerufen.Da der Fehlercode durch interne Aufrufe überschrieben werden kann, die von anderen verwalteten Klassenbibliotheksmethoden stammen, sollte die GetLastError-Methode oder die GetLastWin32Error-Methode unmittelbar nach dem Aufruf der Plattformaufrufmethode aufgerufen werden.

Die Regel ignoriert Aufrufe der folgenden verwalteten Member, wenn diese zwischen dem Aufruf der Plattformaufrufmethode und dem Aufruf von GetLastWin32Error erfolgen.Diese Member ändern den Fehlercode nicht, und mithilfe dieser Member lässt sich feststellen, ob bestimmte Aufrufe von Plattformaufruftmethoden erfolgreich waren.

Behandeln von Verstößen

Um einen Verstoß gegen diese Regel zu beheben, verschieben Sie den Aufruf in GetLastWin32Error, damit er unmittelbar auf den Aufruf der Plattformaufrufmethode folgt.

Wann sollten Warnungen unterdrückt werden?

Eine Warnung dieser Regel kann gefahrlos unterdrückt werden, wenn der Code zwischen dem Aufruf der Plattformaufrufmethode und dem Aufruf der GetLastWin32Error-Methode keine explizite oder implizite Änderung des Fehlercodes bewirken kann.

Beispiel

Das folgende Beispiel zeigt eine Methode, die gegen die Regel verstößt, und eine Methode, die der Regel entspricht.

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

Verwandte Regeln

CA1060: P/Invokes in NativeMethods-Klasse verschieben

CA1400: Für P/Invoke müssen Einstiegspunkte vorhanden sein

CA1401: P/Invokes dürfen nicht sichtbar sein

CA2101: Marshalling für P/Invoke-Zeichenfolgenargumente festlegen

CA2205: Verwaltete Entsprechungen der Win32 API verwenden