5

私のコードに 2 つの CA 警告が表示される理由を理解したいと思います。

CA2000スコープを失う前にオブジェクトを破棄 メソッド 'ImpersonateValidUser(string, string, string, LogOnType, LogOnProvider, ImpersonationLevel)' で、オブジェクトへのすべての参照がスコープ外になる前に、オブジェクト 'tempWindowsIdentity' で System.IDisposable.Dispose を呼び出します。

CA1404 P/Invoke メソッド 'ImpersonateValidUser(string, string, string, LogOnType, LogOnProvider, ImpersonationLevel)' が GetLastWin32Error を呼び出した直後に GetLastError を呼び出しますが、'IDisposable.Dispose()' への直前の呼び出しは P/Invoke ステートメントではありません。GetLastWin32Error への呼び出しを移動して、関連するプラットフォーム呼び出し呼び出しの直後に続くようにします。

以下は単純化されたコード サンプルで、警告が表示される場所に正確にコメントが付けられています。

private static void Impersonate(string userName, string domain, string password, LogOnType logonType, LogOnProvider logonProvider, ImpersonationLevel impersonationLevel)
{
    var token = IntPtr.Zero;
    var tokenDuplicate = IntPtr.Zero;
    if (NativeMethods.RevertToSelf())
    {
        if (NativeMethods.LogonUser(userName, domain, password, (int)logonType, (int)logonProvider, ref token) != 0)
        {
            if (NativeMethods.DuplicateToken(token, (int)impersonationLevel, ref tokenDuplicate) != 0)
            {
                /* CA2000 */ using (var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate))
                {
                    _impersonationContext = tempWindowsIdentity.Impersonate();
                    return;
                }
            }
        }
    }
    /* CA1404 */ var e = Marshal.GetLastWin32Error();
    throw new Win32Exception(e);
}

CA2000 -ステートメントの完了tempWindowsIdentity後にオブジェクトが使用されないusing()ため、この警告が表示されるのはなぜですか?

CA1404 -Marshal.GetLastWin32Error()常にネイティブ メソッドの直後に呼び出されます。状況using()ステートメントが先に呼び出された場合でも、return句が表示Marshal.GetLastWin32Error()され、その後呼び出されないのに、なぜこの警告が表示されるのでしょうか。

4

3 に答える 3

0

usingステートメント内で使い捨てオブジェクトを作成していることを意味するルールの次の部分に違反しているため、CA2000 が発生すると思います。

使い捨てオブジェクトを返すには、オブジェクトが using ブロックの外側の try/finally ブロックで構築されている必要があります。

Marshal.GetLastWin32Error();また、ネイティブ呼び出しの直後に呼び出しを行っていないため、CA1404 が発生します。コードの最初の項目としてMarshal.GetLastWin32Error();各ステートメントを呼び出すようにしてください。if

于 2013-01-22T10:59:18.797 に答える
0

このコードは、これらの CA 警告を修正する必要があります...あまりエレガントではありません...しかし、コード分析は決してエレガントなコードを生成しません。

private static void Impersonate(string userName, string domain, string password, LogOnType logonType, LogOnProvider logonProvider, ImpersonationLevel impersonationLevel)
{
    if (!NativeMethods.RevertToSelf())
        throw new Win32Exception(Marshal.GetLastWin32Error());

    IntPtr token = IntPtr.Zero;

    if (NativeMethods.LogonUser(userName, domain, password, (int)logonType, (int)logonProvider, ref token) == 0)
        throw new Win32Exception(Marshal.GetLastWin32Error());

    IntPtr tokenDuplicate = IntPtr.Zero;

    if (NativeMethods.DuplicateToken(token, (int)impersonationLevel, ref tokenDuplicate) == 0)
        throw new Win32Exception(Marshal.GetLastWin32Error());

WindowsIdentity tempWindowsIdentity;

    try
    {
        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
        _impersonationContext = tempWindowsIdentity.Impersonate();
    }
    finally
    {
        if (tempPort != null)
        {
            tempWindowsIdentity.Dispose();
            tempWindowsIdentity = null;
        }
    }
}

CA1404 に関して言えば、不正な API 呼び出しによって生成されたエラー コードは、すぐにキャッチしないと、他のマネージ クラス ライブラリ メソッドからの内部呼び出しによって上書きされる可能性があります。CA2000 では、アプローチで WindowsIdentity が作成されますが、オブジェクトへのすべての参照がスコープ外になる前にオブジェクトが破棄されません。そうすることで、障害点で例外が発生することを許可しません。

于 2013-01-22T10:54:01.143 に答える
-1

CA1404 は次の方法で解決しました。原因は、「!= 0」が LogonUser() または DuplicateToken() の直後の呼び出しであったことです。

private static void Impersonate(string userName, string domain, string password, LogOnType logonType, LogOnProvider logonProvider, ImpersonationLevel impersonationLevel)
{
    var token = IntPtr.Zero;
    var tokenDuplicate = IntPtr.Zero;
    if (NativeMethods.RevertToSelf())
    {
        var logonUserSuccessful = NativeMethods.LogonUser(userName, domain, password, (int) logonType, (int) logonProvider, ref token);
        var e = Marshal.GetLastWin32Error();  // call before comparison against 0 to avoid CA1404
        if (logonUserSuccessful != 0)
        {
            var duplicateTokenSuccessful = NativeMethods.DuplicateToken(token, (int) impersonationLevel, ref tokenDuplicate);
            e = Marshal.GetLastWin32Error();  // call before comparison against 0 to avoid CA1404
            if (duplicateTokenSuccessful != 0)
            {
                /* CA2000 */
                using (var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate))
                {
                    _impersonationContext = tempWindowsIdentity.Impersonate();
                    return;
                }
            }
        }
    }
    throw new Win32Exception(e);
}
于 2014-11-17T09:41:42.697 に答える