Udostępnij za pośrednictwem


CA1404: Należy wywołać GetLastError natychmiast po P/Invoke

TypeName

CallGetLastErrorImmediatelyAfterPInvoke

CheckId

CA1404

Kategoria

Microsoft.Interoperability

Zmiana kluczowa

Niekluczowa

Przyczyna

Wywołano metodę Marshal.GetLastWin32Error lub równoważną funkcję Win32 GetLastError, a wywołanie, które zostało wykonane bezpośrednio wcześniej, nie jest metodą wywołania platformy.

Opis reguły

Metoda wywołania platformy uzyskuje dostęp do kodu niezarządzanego i jest zdefiniowana za pomocą słowa kluczowego Declare w Visual Basic lub atrybutu DllImportAttribute.Ogólnie, w przypadku awarii, funkcje niezarządzane wywołują funkcję Win32 SetLastError, aby ustawić kod błędu, który jest skojarzony z awarią.Wywołujący funkcję, która nie powiodła się, wywołuje funkcję Win32 GetLastError, aby pobrać kod błędu i ustalić przyczynę błędu.Kod błędu jest utrzymywany na zasadzie jeden dla wątku i jest zastępowany przez następne wywołanie SetLastError.Po wywołaniu metody wywołania platformy, która nie powiodła się, kod zarządzany może pobrać kod błędu, wywołując metodę GetLastWin32Error.Ponieważ kod błędu może zostać zastąpiony przez wewnętrzne wywołania z innych metod biblioteki klas zarządzanych, metoda GetLastError lub GetLastWin32Error powinna zostać wywołana natychmiast po wywołaniu metody wywołania platformy.

Reguła ignoruje wywołania następujących zarządzanych elementów członkowskich, gdy występują między wywołaniem metody wywołania platformy, a wywołaniem GetLastWin32Error.Te elementy członkowskie te nie zmieniają kodu błędu i są przydatne do określania powodzenia niektórych wywołań metody wywołania platformy.

Jak naprawić naruszenia

Aby naprawić naruszenie tej reguły, przenieś wywołanie GetLastWin32Error, tak aby następowało natychmiast po wywołaniu metody wywołania platformy.

Kiedy pominąć ostrzeżenia

Można bezpiecznie pominąć ostrzeżenie dotyczące tej reguły, jeżeli kod między wywołaniem metody wywołania platformy, a wywołaniem metody GetLastWin32Error nie może jawnie lub niejawnie spowodować zmiany kodu błędu.

Przykład

Poniższy przykład pokazuje metodę, która narusza regułę oraz metodę, która spełnia regułę.

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

Powiązane reguły

CA1060: Przenieś P/Invokes do klasy NativeMethods

CA1400: Powinny istnieć punkty wejścia P/Invoke

CA1401: P/Invokes nie powinny być widoczne

CA2101: Należy określić operacje organizacyjne dla argumentów typu string P/Invoke

CA2205: Użyj zarządzanych odpowiedników interfejsu API Win32