CA1404: chamar GetLastError logo depois de P/InvokeCA1404: Call GetLastError immediately after P/Invoke

NomeDoTipoTypeName CallGetLastErrorImmediatelyAfterPInvokeCallGetLastErrorImmediatelyAfterPInvoke
CheckIdCheckId CA1404CA1404
CategoriaCategory Microsoft.InteroperabilityMicrosoft.Interoperability
Alteração SignificativaBreaking Change Não são significativasNon-breaking

CausaCause

É feita uma chamada para o System.Runtime.InteropServices.Marshal.GetLastWin32Error método ou o equivalente Win32 GetLastError função e a chamada que vem imediatamente antes, não seja uma plataforma de invocação de método.A call is made to the System.Runtime.InteropServices.Marshal.GetLastWin32Error method or the equivalent Win32 GetLastError function, and the call that comes immediately before is not to a platform invoke method.

Descrição da regraRule description

Uma plataforma de chamar código não gerenciado do método acessos e é definido usando o Declare palavra-chave na Visual BasicVisual Basic ou o System.Runtime.InteropServices.DllImportAttribute atributo.A platform invoke method accesses unmanaged code and is defined by using the Declare keyword in Visual BasicVisual Basic or the System.Runtime.InteropServices.DllImportAttribute attribute. Em geral, em caso de falha, funções não gerenciadas chamam Win32 SetLastError função para definir um código de erro que está associado com a falha.Generally, upon failure, unmanaged functions call the Win32 SetLastError function to set an error code that is associated with the failure. O chamador da função com falha chamadas Win32 GetLastError função para recuperar o código de erro e determinar a causa da falha.The caller of the failed function calls the Win32 GetLastError function to retrieve the error code and determine the cause of the failure. O código de erro é mantido em uma base por thread e é substituído pela próxima chamada para SetLastError.The error code is maintained on a per-thread basis and is overwritten by the next call to SetLastError. Depois que uma chamada para uma plataforma com falha invocar o método, o código gerenciado pode recuperar o código de erro chamando o GetLastWin32Error método.After a call to a failed platform invoke method, managed code can retrieve the error code by calling the GetLastWin32Error method. Como o código de erro pode ser substituído por chamadas internas de outros métodos de biblioteca de classe gerenciada, o GetLastError ou GetLastWin32Error método deve ser chamado imediatamente após a chamada de método de invocação de plataforma.Because the error code can be overwritten by internal calls from other managed class library methods, the GetLastError or GetLastWin32Error method should be called immediately after the platform invoke method call.

A regra ignora chamadas para os seguintes membros gerenciados quando eles ocorrem entre a chamada para a plataforma de invocação de método e a chamada para GetLastWin32Error.The rule ignores calls to the following managed members when they occur between the call to the platform invoke method and the call to GetLastWin32Error. Esses membros não alteram o erro de código e são úteis para determinar o sucesso de alguma plataforma invocam chamadas de método.These members do not change the error code and are useful for determining the success of some platform invoke method calls.

Como corrigir violaçõesHow to fix violations

Para corrigir uma violação dessa regra, mova a chamada para GetLastWin32Error para que fique imediatamente após a chamada para a plataforma de invocação de método.To fix a violation of this rule, move the call to GetLastWin32Error so that it immediately follows the call to the platform invoke method.

Quando suprimir avisosWhen to suppress warnings

É seguro suprimir um aviso nessa regra, se o código entre a plataforma de invocar a chamada de método e o GetLastWin32Error chamada de método não pode implicitamente ou explicitamente fazem com que o código de erro alterar.It is safe to suppress a warning from this rule if the code between the platform invoke method call and the GetLastWin32Error method call cannot explicitly or implicitly cause the error code to change.

ExemploExample

O exemplo a seguir mostra um método que viola a regra e um método que satisfaz a regra.The following example shows a method that violates the rule and a method that satisfies the rule.

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

CA1060: mover P/Invokes para a classe NativeMethodsCA1060: Move P/Invokes to NativeMethods class

CA1400: os pontos de entrada de P-Invoke devem existirCA1400: P/Invoke entry points should exist

CA1401: os P/Invokes não devem estar visíveisCA1401: P/Invokes should not be visible

CA2101: especificar marshaling para argumentos de cadeia de caracteres P/InvokeCA2101: Specify marshaling for P/Invoke string arguments

CA2205: usar equivalentes gerenciados da API do Win32CA2205: Use managed equivalents of Win32 API