Sdílet prostřednictvím


CA1404: Volání GetLastError ihned po vyvolání/P

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 System.Runtime.InteropServices.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řesunout P/Invokes třídy NativeMethods

CA1400: Vstupní body P/Invoke by existovat.

CA1401: P/Invokes by neměl být viditelný

CA2101: Zadejte zařazování pro řetězcové argumenty P/Invoke.

CA2205: Ekvivalenty použití spravovaných rozhraní Win32 API