Partilhar via


CA1404: chamar GetLastError logo depois de P/Invoke

TypeName

CallGetLastErrorImmediatelyAfterPInvoke

CheckId

CA1404

Categoria

Microsoft.Interoperability

Alteração Significativa

Sem quebra

Causa

For feita uma chamada para o método de Marshal.GetLastWin32Error ou função do Win32 GetLastError de equivalente, e a chamada de que vem antes não é a um método de invocação de plataforma.

Descrição da Regra

Um método de invocação de plataforma acessa o código não gerenciado e é definido com a palavra-chave de Declare em Visual Basic ou no atributo de DllImportAttribute .Em geral, na falha, funções não gerenciado chamam a função do Win32 SetLastError para definir um código de erro que é associado à falha.O chamador de chamadas de funções que falharam a função do Win32 GetLastError para recuperar o código de erro e para determinar a causa da falha.O código de erro é mantido em uma base por thread e substituído pela próxima chamada para SetLastError.Depois que uma chamada para um método malsucedida da invocação de plataforma, código gerenciado pode recuperar o código de erro chamando o método de GetLastWin32Error .Como o código de erro pode ser substituído por chamadas internos de outros métodos gerenciados da biblioteca de classe, o método de GetLastError ou de GetLastWin32Error deve ser chamado imediatamente depois da chamada do método de invocação de plataforma.

A regra ignora chamadas aos seguintes membros gerenciados quando ocorrem entre a chamada para o método de invocação de plataforma e chame para GetLastWin32Error.Esses membros não alteram o código de erro e são úteis para determinar o êxito de algumas chamadas do método de invocação de plataforma.

Como Corrigir Violações

Para corrigir uma violação desta regra, mova a chamada a GetLastWin32Error de modo que segue imediatamente a chamada para o método de invocação de plataforma.

Quando Suprimir Alertas

É seguro suprimir um aviso dessa regra se o código na chamada do método de invocação de preparo e a chamada do método de GetLastWin32Error não pode explicitamente ou implicitamente fazer com que o código de erro à alteração.

Exemplo

O exemplo a seguir mostra um método que viola a regra e um método que satisfaça a regra.

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

Regras Relacionadas

CA1060: mover P/Invokes para a classe NativeMethods

CA1400: os pontos de entrada P/Invoke devem existir

CA1401: P/Invokes não deve estar visível

CA2101: especificar marshaling para argumentos da cadeia de caracteres P/Invoke

CA2205: usar equivalentes gerenciados da API do Win32