CA1404: P/Invoke の直後に GetLastError を呼び出します
Item | [値] |
---|---|
規則 ID | CA1404 |
カテゴリ | Microsoft.Interoperability |
互換性に影響する変更点 | なし |
原因
System.Runtime.InteropServices.Marshal.GetLastWin32Error メソッドまたは同等の Win32 GetLastError
関数が呼び出されました。その直前に、プラットフォーム呼び出しメソッドが呼び出されていません。
規則の説明
プラットフォーム呼び出しメソッドは、アンマネージド コードにアクセスし、Visual Basic の Declare
キーワードまたは System.Runtime.InteropServices.DllImportAttribute を使って定義されます。 一般に、エラーが発生した場合、アンマネージ関数では Win32 SetLastError
関数を呼び出して、エラーに関連付けられているエラー コードを設定します。 失敗した関数の呼び出し元では、Win32 GetLastError
関数を呼び出してエラー コードを取得し、エラーの原因を特定します。 エラー コードはスレッド単位で管理され、SetLastError
の次の呼び出しによって上書きされます。 失敗したプラットフォーム呼び出しメソッドの呼び出しの後、マネージド コードでは GetLastWin32Error メソッドを呼び出してエラー コードを取得できます。 エラー コードは他のマネージド クラス ライブラリ メソッドからの内部呼び出しによって上書きされる可能性があるため、GetLastError
または GetLastWin32Error メソッドは、プラットフォーム呼び出しメソッドの呼び出しの直後に呼び出す必要があります。
この規則では、プラットフォーム呼び出しメソッドの呼び出しと GetLastWin32Error の呼び出しの間に次のマネージド メンバーへの呼び出しが発生した場合に、その呼び出しが無視されます。 これらのメンバーではエラー コードが変更されず、一部のプラットフォーム呼び出しメソッドの呼び出しが成功したかどうかを判断するのに役立ちます。
違反の修正方法
この規則の違反を修正するには、プラットフォーム呼び出しメソッドの呼び出しの直後になるように GetLastWin32Error の呼び出しを移動します。
どのようなときに警告を抑制するか
プラットフォーム呼び出しメソッドの呼び出しと GetLastWin32Error メソッドの呼び出しの間のコードで明示的にまたは暗黙的にエラー コードを変更することができない場合は、この規則による警告を抑制しても問題ありません。
例
次に示すのは、規則に違反するメソッドと、規則を満たすメソッドの例です。
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/Invoke を NativeMethods クラスに移動します
CA1400: P/Invoke エントリ ポイントは存在しなければなりません
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示