// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
namespace Microsoft.Build.Shared.FileSystem
{
///
/// A possibly-recoverable exception wrapping a failed native call. The captures the
/// associated recent error code (). The
/// accounts for the native code as well as a human readable portion.
///
///
/// This is much like , but the message field contains the caller-provided part in addition
/// to the system-provided message (rather than replacing the system provided message).
///
[SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors",
Justification = "We don't need exceptions to cross AppDomain boundaries.")]
[Serializable]
internal sealed class NativeWin32Exception : Win32Exception
{
///
/// Creates an exception representing a native failure (with a corresponding Win32 error code).
/// The exception's includes the error code, a system-provided message describing it,
/// and the provided application-specific message prefix (e.g. "Unable to open log file").
///
public NativeWin32Exception(int nativeErrorCode, [Localizable(false)] string messagePrefix)
: base(nativeErrorCode, GetFormattedMessageForNativeErrorCode(nativeErrorCode, messagePrefix))
{
// Win32Exception does not initialize HResult but many others like IOException do.
// In order to have a uniform error checking, initialize HResult using something similar to HRESULT_FROM_WIN32
HResult = HResultFromWin32(nativeErrorCode);
}
///
/// Creates an exception representing a native failure (with a corresponding Win32 error code).
/// The exception's includes the error code and a system-provided message describing it.
///
public NativeWin32Exception(int nativeErrorCode)
: this(nativeErrorCode, null)
{
}
///
/// Returns a human readable error string for a native error code, like Native: Can't access the log file (0x5: Access is denied).
/// The message prefix (e.g. "Can't access the log file") is optional.
///
public static string GetFormattedMessageForNativeErrorCode(int nativeErrorCode, [Localizable(false)] string messagePrefix = null)
{
string systemMessage = new Win32Exception(nativeErrorCode).Message;
if (!string.IsNullOrEmpty(messagePrefix))
{
return string.Format(CultureInfo.InvariantCulture, "Native: {0} (0x{1:X}: {2})", messagePrefix, nativeErrorCode, systemMessage);
}
else
{
return string.Format(CultureInfo.InvariantCulture, "Native: 0x{0:X}: {1}", nativeErrorCode, systemMessage);
}
}
///
/// Converts a Win32 error code to HResult
///
public static int HResultFromWin32(int nativeErrorCode)
{
if (nativeErrorCode < 0 || nativeErrorCode > 0xFFFF)
{
return nativeErrorCode;
}
return unchecked((int)0x80070000) | nativeErrorCode;
}
}
}