CA1404: Volání GetLastError ihned po vyvolání/P
TypeName |
CallGetLastErrorImmediatelyAfterPInvoke |
CheckId |
CA1404 |
Kategorie |
Microsoft.interoperability |
Narušující změna |
Nenarušující |
Příčina
Je provedeno volání metody Marshal.GetLastWin32Error nebo ekvivalentní funkce GetLastError rozhraní Win32 a volání bezprostředně před tím není metoda vyvolání platformy.
Popis pravidla
Metoda vyvolání platformy přistupuje k nespravovanému kódu a je definována pomocí klíčového slova Declare v jazyce Visual Basic nebo pomocí atributu System.Runtime.InteropServices.DllImportAttribute.Obecně po selhání nespravovaná funkce volá funkci SetLastError rozhraní Win32, aby nastavila chybový kód přidružený k selhání.Volající nezdařené funkce zavolá funkci GetLastError rozhraní Win32 k načtení kódu chyby a určení příčiny chyby.Kód chyby je udržován na základě vlákna a je přepsán dalším voláním funkce SetLastError.Po volání nezdařené metody vyvolání platformy, spravovaný kód můžete načíst kód chyby zavoláním metody GetLastWin32Error.Protože kód chyby může být přepsán vnitřním voláním z jiných metod spravované knihovny třídy, metody GetLastError nebo GetLastWin32Error by měly být volány ihned po volání metody vyvolání platformy.
Pravidlo ignoruje volání následujících spravovaných členů, pokud nastanou mezi voláním metody vyvolání platformy a voláním metody GetLastWin32Error.Tyto členy nemění kód chyby a jsou užitečné pro určení úspěchu některých volání metod vyvolání platformy.
Jak vyřešit porušení
Chcete-li opravit porušení tohoto pravidla, přesuňte volání metody GetLastWin32Error tak, aby následovalo ihned po volání metody vyvolání platformy.
Kdy potlačit upozornění
Potlačení upozornění tohoto pravidla je bezpečné, pokud kód mezi voláním metody vyvolání platformy a voláním metody GetLastWin32Error nemůže explicitně nebo implicitně způsobit změnu kódu chyby.
Příklad
Následující příklad ukazuje metodu, která porušuje toto pravidlo a metody, které tomuto pravidlu vyhovují.
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);
}
}
}
}
Související pravidla
CA1060: Přesunout P/Invokes třídy NativeMethods
CA1400: Vstupní body P/Invoke by existovat.
CA1401: P/Invokes by neměl být viditelný
CA2101: Zadejte zařazování pro řetězcové argumenty P/Invoke.