共用方式為


CA1404:必須在 P/Invoke 之後立即呼叫 GetLastError

型別名稱

CallGetLastErrorImmediatelyAfterPInvoke

CheckId

CA1404

分類

Microsoft.Interoperability

中斷變更

中斷

原因

會對 Marshal.GetLastWin32Error 方法或對等 Win32 GetLastError 函式進行呼叫,而且緊接在前的呼叫並不是平台叫用方法。

規則描述

平台叫用方法會存取 Unmanaged 程式碼,而且是使用 Visual Basic 中之 Declare 關鍵字或 DllImportAttribute 屬性所定義的。一般而言,失敗時,Unmanaged 函式會呼叫 Win32 SetLastError 函式,以設定與失敗相關聯的錯誤碼。失敗函式的呼叫端會呼叫 Win32 GetLastError 函式,以擷取錯誤碼並判斷失敗的原因。錯誤碼是根據每個執行緒進行維護,而且會在下次呼叫 SetLastError 時遭到覆寫。在呼叫失敗的平台叫用方法之後,Managed 程式碼可以呼叫 GetLastWin32Error 方法擷取錯誤碼。因為來自其他 Managed 類別庫 (Class Library) 方法的內部呼叫可以覆寫錯誤碼,所以在平台叫用方法呼叫之後,應該立即呼叫 GetLastError 或 GetLastWin32Error 方法。

當下列 Managed 成員發生在呼叫平台叫用方法及呼叫 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);
         }
      }
   }
}

相關規則

CA1060:將 P/Invokes 移到 NativeMethods 類別

CA1400:P/Invoke 進入點應該要存在

CA1401:P/Invokes 不應該為可見的

CA2101:必須指定 P/Invoke 字串引數的封送處理

CA2205:必須使用 Win32 API 的 Managed 對應項