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