CA1404: Należy wywołać GetLastError natychmiast po P/Invoke
TypeName |
CallGetLastErrorImmediatelyAfterPInvoke |
CheckId |
CA1404 |
Kategoria |
Microsoft.Interoperability |
Zmiana kluczowa |
Niekluczowa |
Przyczyna
Wywołano metodę Marshal.GetLastWin32Error lub równoważną funkcję Win32 GetLastError, a wywołanie, które zostało wykonane bezpośrednio wcześniej, nie jest metodą wywołania platformy.
Opis reguły
Metoda wywołania platformy uzyskuje dostęp do kodu niezarządzanego i jest zdefiniowana za pomocą słowa kluczowego Declare w Visual Basic lub atrybutu DllImportAttribute.Ogólnie, w przypadku awarii, funkcje niezarządzane wywołują funkcję Win32 SetLastError, aby ustawić kod błędu, który jest skojarzony z awarią.Wywołujący funkcję, która nie powiodła się, wywołuje funkcję Win32 GetLastError, aby pobrać kod błędu i ustalić przyczynę błędu.Kod błędu jest utrzymywany na zasadzie jeden dla wątku i jest zastępowany przez następne wywołanie SetLastError.Po wywołaniu metody wywołania platformy, która nie powiodła się, kod zarządzany może pobrać kod błędu, wywołując metodę GetLastWin32Error.Ponieważ kod błędu może zostać zastąpiony przez wewnętrzne wywołania z innych metod biblioteki klas zarządzanych, metoda GetLastError lub GetLastWin32Error powinna zostać wywołana natychmiast po wywołaniu metody wywołania platformy.
Reguła ignoruje wywołania następujących zarządzanych elementów członkowskich, gdy występują między wywołaniem metody wywołania platformy, a wywołaniem GetLastWin32Error.Te elementy członkowskie te nie zmieniają kodu błędu i są przydatne do określania powodzenia niektórych wywołań metody wywołania platformy.
Jak naprawić naruszenia
Aby naprawić naruszenie tej reguły, przenieś wywołanie GetLastWin32Error, tak aby następowało natychmiast po wywołaniu metody wywołania platformy.
Kiedy pominąć ostrzeżenia
Można bezpiecznie pominąć ostrzeżenie dotyczące tej reguły, jeżeli kod między wywołaniem metody wywołania platformy, a wywołaniem metody GetLastWin32Error nie może jawnie lub niejawnie spowodować zmiany kodu błędu.
Przykład
Poniższy przykład pokazuje metodę, która narusza regułę oraz metodę, która spełnia regułę.
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);
}
}
}
}
Powiązane reguły
CA1060: Przenieś P/Invokes do klasy NativeMethods
CA1400: Powinny istnieć punkty wejścia P/Invoke
CA1401: P/Invokes nie powinny być widoczne
CA2101: Należy określić operacje organizacyjne dla argumentów typu string P/Invoke
CA2205: Użyj zarządzanych odpowiedników interfejsu API Win32