更新: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);
         }
      }
   }
}