Sdílet prostřednictvím


CA1404: Volejte GetLastError ihned po volání nespravovaného kódu

TypeName

CallGetLastErrorImmediatelyAfterPInvoke

CheckId

CA1404

Kategorie

Microsoft.interoperability

Narušující změna

Nenarušující

Příčina

Je provedeno volání metody Marshal.GetLastWin32Error nebo ekvivalentní funkce GetLastError rozhraní Win32 a volání bezprostředně před tím není metoda vyvolání platformy.

Popis pravidla

Metoda vyvolání platformy přistupuje k nespravovanému kódu a je definována pomocí klíčového slova Declare v jazyce Visual Basic nebo pomocí atributu DllImportAttribute.Obecně po selhání nespravovaná funkce volá funkci SetLastError rozhraní Win32, aby nastavila chybový kód přidružený k selhání.Volající nezdařené funkce zavolá funkci GetLastError rozhraní Win32 k načtení kódu chyby a určení příčiny chyby.Kód chyby je udržován na základě vlákna a je přepsán dalším voláním funkce SetLastError.Po volání nezdařené metody vyvolání platformy, spravovaný kód můžete načíst kód chyby zavoláním metody GetLastWin32Error.Protože kód chyby může být přepsán vnitřním voláním z jiných metod spravované knihovny třídy, metody GetLastError nebo GetLastWin32Error by měly být volány ihned po volání metody vyvolání platformy.

Pravidlo ignoruje volání následujících spravovaných členů, pokud nastanou mezi voláním metody vyvolání platformy a voláním metody GetLastWin32Error.Tyto členy nemění kód chyby a jsou užitečné pro určení úspěchu některých volání metod vyvolání platformy.

Jak vyřešit porušení

Chcete-li opravit porušení tohoto pravidla, přesuňte volání metody GetLastWin32Error tak, aby následovalo ihned po volání metody vyvolání platformy.

Kdy potlačit upozornění

Potlačení upozornění tohoto pravidla je bezpečné, pokud kód mezi voláním metody vyvolání platformy a voláním metody GetLastWin32Error nemůže explicitně nebo implicitně způsobit změnu kódu chyby.

Příklad

Následující příklad ukazuje metodu, která porušuje toto pravidlo a metody, které tomuto pravidlu vyhovují.

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

Související pravidla

CA1060: Přesuňte volání nespravovaných kódů do třídy NativeMethods

CA1400: Vstupní body volání nespravovaného kódu by měly existovat

CA1401: Volání nespravovaných kódů by neměla být viditelná

CA2101: Určete kódování pro argumenty řetězce volání nespravovaného kódu

CA2205: Použijte spravované ekvivalenty rozhraní Win32 API