CA1404: Chamar GetLastError imediatamente após P/Invoke.

TypeName

CallGetLastErrorImmediatelyAfterPInvoke

CheckId

CA1404

<strong>Categoria</strong>

Microsoft.Interoperability

Alteração significativa

Não-separável

Causa

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

Descrição da regra

Uma plataforma chamar código não gerenciado do método acessos e é definida usando o Declare palavra-chave em Visual Basic ou System.Runtime.InteropServices.DllImportAttribute atributo. Geralmente, em caso de falha, funções não gerenciadas chamam Win32 SetLastError função para definir um código de erro está associado à falha. O chamador da função falha chama o Win32 GetLastError função para recuperar o código de erro e determinar a causa da falha. O código de erro é mantido em uma base por segmento e é substituído pela próxima chamada para SetLastError. Após uma chamada para uma plataforma com falha chamar o método, o código gerenciado pode recuperar o código de erro chamando o GetLastWin32Error método. 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 o invocação de plataforma chamada de método.

A regra ignora chamadas para os seguintes membros gerenciados quando elas ocorrem entre a chamada para a plataforma chamar o método e a chamada para GetLastWin32Error. Esses membros não alteram o erro e são úteis para determinar o sucesso de alguns plataforma chamar chamadas de método.

Como corrigir violações

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

Quando suprimir avisos

É seguro eliminar um aviso esta regra se o código entre a plataforma chamar chamadas de método e a GetLastWin32Error chamada de método não pode explicitamente ou implicitamente, fazer com que o código de erro ao alterar.

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 NativeMethods classe

CA1400: Os pontos de entrada de P/Invoke devem existir.

CA1401: P/Invokes não deverá ser visível

CA2101: Especifique o empacotamento para argumentos de seqüência de caracteres de P/Invoke.

CA2205: Use o gerenciado equivalentes da API do Win32