紧接在 P/Invoke 之后调用 GetLastError
更新:2007 年 11 月
TypeName |
CallGetLastErrorImmediatelyAfterPInvoke |
CheckId |
CA1404 |
类别 |
Microsoft.Interoperability |
是否重大更改 |
否 |
原因
调用了 Marshal.GetLastWin32Error 方法或等效的 Win32 GetLastError 函数,并且紧邻的前一个调用不是对平台调用方法的调用。
规则说明
平台调用方法访问非托管代码,并且使用 Visual Basic 中的 Declare 关键字或 System.Runtime.InteropServices.DllImportAttribute 属性进行定义。发生失败时,非托管函数通常会调用 Win32 SetLastError 函数,以便设置与失败关联的错误代码。发生失败的函数的调用方调用 Win32 GetLastError 函数,以检索错误代码并确定失败的原因。错误代码按线程维护,并且被对 SetLastError 的下一次调用覆盖。调用失败的平台调用方法后,托管代码可以通过调用 GetLastWin32Error 方法检索错误代码。因为错误代码可以被其他托管类库方法的内部调用覆盖,所以在调用平台调用方法后应立即调用 GetLastError 或 GetLastWin32Error 方法。
当在对平台调用方法的调用和对 GetLastWin32Error 的调用之间出现以下托管成员时,该规则将忽略对它们的调用。这些成员不更改错误代码,这对于确定某些对平台调用方法的调用是否成功非常有用。
如何修复冲突
要修复与该规则的冲突,请移动对 GetLastWin32Error 的调用,使它紧跟在对平台调用方法的调用之后。
何时禁止显示警告
如果平台调用方法调用和 GetLastWin32Error 方法调用之间的代码不能显式或隐式地更改错误代码,则可以安全地禁止显示此规则发出的警告。
示例
下面的示例演示一个与该规则冲突的方法和一个满足该规则的方法。
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);
}
}
}
}