 
// Copyright (C) Microsoft Corporation. All rights reserved.

#ifndef _ROERROR_H
#define _ROERROR_H


#if defined(_MSC_VER)
#pragma once
#endif

#ifdef _CONTRACT_GEN
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#endif

#include <apiset.h>
#include <apisetcconv.h>
#include <hstring.h>
#include <restrictedErrorInfo.h>
#include <rpc.h>

#include <sdkddkver.h>

#if (NTDDI_VERSION >= NTDDI_WIN8)

/* APISET_NAME: api-ms-win-core-winrt-error-l1 */

#ifndef _APISET_RO_ERROR_VER
#ifdef _APISET_MINCORE_VERSION
#if _APISET_MINCORE_VERSION >= 0x0100
#define _APISET_RO_ERROR_VER 0x0100l
#endif // _APISET_MINCORE_VERSION >= 0x0100
#endif // _APISET_MINCORE_VERSION
#endif // _APISET_RO_ERROR_VER

#pragma region Application Family

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)

#ifdef _OLE32_
#define WINOLEGLOBAL EXTERN_C 
#else
#define WINOLEGLOBAL EXTERN_C DECLSPEC_IMPORT
#endif // _OLE32_

typedef enum {
        RO_ERROR_REPORTING_NONE               = 0x00000000,
        RO_ERROR_REPORTING_SUPPRESSEXCEPTIONS = 0x00000001,
        RO_ERROR_REPORTING_FORCEEXCEPTIONS    = 0x00000002,
        RO_ERROR_REPORTING_USESETERRORINFO    = 0x00000004,
        RO_ERROR_REPORTING_SUPPRESSSETERRORINFO = 0x00000008,
}RO_ERROR_REPORTING_FLAGS;

DEFINE_ENUM_FLAG_OPERATORS(RO_ERROR_REPORTING_FLAGS);

const int MAX_ERROR_MESSAGE_CHARS = 512; //not including the terminating null

STDAPI
RoGetErrorReportingFlags(
    _Out_ UINT32 * pflags
    );


STDAPI
RoSetErrorReportingFlags(
    _In_ UINT32 flags
    );


#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
#pragma endregion

#pragma region Desktop Family

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

STDAPI
RoResolveRestrictedErrorInfoReference(
    _In_ PCWSTR reference,
    _Outptr_ IRestrictedErrorInfo ** ppRestrictedErrorInfo
    );

    
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#pragma endregion

#pragma region Application Family

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)

STDAPI
SetRestrictedErrorInfo(
    _In_ IRestrictedErrorInfo * pRestrictedErrorInfo
    );


STDAPI
GetRestrictedErrorInfo(
    _Outptr_result_maybenull_ IRestrictedErrorInfo ** ppRestrictedErrorInfo
    );


STDAPI_(BOOL)
RoOriginateErrorW(
    _In_ HRESULT error,
    _In_ UINT cchMax,
    _When_(cchMax == 0, _In_reads_or_z_opt_(MAX_ERROR_MESSAGE_CHARS) ) 
             _When_(cchMax > 0 && cchMax < MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(cchMax) )
             _When_(cchMax >= MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(MAX_ERROR_MESSAGE_CHARS) ) PCWSTR message
    );


STDAPI_(BOOL)
RoOriginateError(
    _In_ HRESULT error,
    _In_opt_ HSTRING message
    );


STDAPI_(BOOL)
RoTransformErrorW(
    _In_ HRESULT oldError,
    _In_ HRESULT newError,
    _In_ UINT cchMax,
    _When_(cchMax == 0, _In_reads_or_z_opt_(MAX_ERROR_MESSAGE_CHARS)) 
             _When_(cchMax > 0 && cchMax < MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(cchMax) )
             _When_(cchMax >= MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(MAX_ERROR_MESSAGE_CHARS) ) PCWSTR message
    );


STDAPI_(BOOL)
RoTransformError(
    _In_ HRESULT oldError,
    _In_ HRESULT newError,
    _In_opt_ HSTRING message
    );


STDAPI
RoCaptureErrorContext(
    HRESULT hr
    );


STDAPI_(void)
RoFailFastWithErrorContext(
    HRESULT hrError
    );


#ifdef __cplusplus
namespace Windows
{
    namespace Foundation
    {
        namespace Diagnostics
        {
            typedef enum {
                None               = RO_ERROR_REPORTING_NONE,
                SuppressExceptions = RO_ERROR_REPORTING_SUPPRESSEXCEPTIONS,
                ForceExceptions    = RO_ERROR_REPORTING_FORCEEXCEPTIONS,
                UseSetErrorInfo    = RO_ERROR_REPORTING_USESETERRORINFO,
                SuppressSetErrorInfo = RO_ERROR_REPORTING_SUPPRESSSETERRORINFO,
            } RoErrorReportingFlags;

            DEFINE_ENUM_FLAG_OPERATORS(RoErrorReportingFlags);
            
            inline HRESULT GetErrorReportingFlags(_Out_ UINT32 *pflags)
            {
                return ::RoGetErrorReportingFlags(pflags);
            }
            
            inline HRESULT SetErrorReportingFlags(_In_ UINT32 flags)
            {
                return ::RoSetErrorReportingFlags(flags);
            }

            inline BOOL OriginateError(_In_ HRESULT error, _In_ UINT cchMax,
                _When_(cchMax == 0, _In_reads_or_z_opt_(MAX_ERROR_MESSAGE_CHARS) ) 
                _When_(cchMax > 0 && cchMax < MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(cchMax) )
                _When_(cchMax >= MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(MAX_ERROR_MESSAGE_CHARS) ) 
                 PCWSTR message)
            {
                if (SUCCEEDED(error))
                {
                    return FALSE;
                }

                return ::RoOriginateErrorW(error, cchMax, message);
            }
            
            inline BOOL OriginateError(_In_ HRESULT error, _In_ HSTRING message)
            {
                if (SUCCEEDED(error))
                {
                    return FALSE;
                }

                return ::RoOriginateError(error, message);
            }
            
            inline BOOL TransformError(_In_ HRESULT oldError, _In_ HRESULT newError, _In_ UINT cchMax,
             _When_(cchMax == 0, _In_reads_or_z_opt_(MAX_ERROR_MESSAGE_CHARS)) 
             _When_(cchMax > 0 && cchMax < MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(cchMax) )
             _When_(cchMax >= MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(MAX_ERROR_MESSAGE_CHARS) ) PCWSTR message)
            {
                if ((oldError == newError) ||
                    (SUCCEEDED(oldError) && SUCCEEDED(newError)))
                {
                    return FALSE;
                }

                return ::RoTransformErrorW(oldError, newError, cchMax, message);
            }
            
            inline BOOL TransformError(_In_ HRESULT oldError, _In_ HRESULT newError, _In_ HSTRING message)
            {
                if ((oldError == newError) ||
                    (SUCCEEDED(oldError) && SUCCEEDED(newError)))
                {
                    return FALSE;
                }

                return ::RoTransformError(oldError, newError, message);
            }
        }
    }
}

namespace ABI
{
    namespace Windows
    {
        namespace Foundation
        {
            namespace Diagnostics
            {
                typedef enum {
                    None               = RO_ERROR_REPORTING_NONE,
                    SuppressExceptions = RO_ERROR_REPORTING_SUPPRESSEXCEPTIONS,
                    ForceExceptions    = RO_ERROR_REPORTING_FORCEEXCEPTIONS,
                    UseSetErrorInfo    = RO_ERROR_REPORTING_USESETERRORINFO,
                    SuppressSetErrorInfo = RO_ERROR_REPORTING_SUPPRESSSETERRORINFO,
                } RoErrorReportingFlags;

                DEFINE_ENUM_FLAG_OPERATORS(RoErrorReportingFlags);
            
                inline HRESULT GetErrorReportingFlags(_Out_ UINT32 *pflags)
                {
                    return ::RoGetErrorReportingFlags(pflags);
                }
            
                inline HRESULT SetErrorReportingFlags(_In_ UINT32 flags)
                {
                    return ::RoSetErrorReportingFlags(flags);
                }

                inline BOOL OriginateError(_In_ HRESULT error, _In_ UINT cchMax,
                    _When_(cchMax == 0, _In_reads_or_z_opt_(MAX_ERROR_MESSAGE_CHARS) ) 
                    _When_(cchMax > 0 && cchMax < MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(cchMax) )
                    _When_(cchMax >= MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(MAX_ERROR_MESSAGE_CHARS) )
                    PCWSTR message)
                {
                    return ::RoOriginateErrorW(error, cchMax, message);
                }
            
                inline BOOL OriginateError(_In_ HRESULT error, _In_ HSTRING message)
                {
                    return ::RoOriginateError(error, message);
                }
            
                inline BOOL TransformError(_In_ HRESULT oldError, _In_ HRESULT newError, _In_ UINT cchMax,
                    _When_(cchMax == 0, _In_reads_or_z_opt_(MAX_ERROR_MESSAGE_CHARS)) 
                    _When_(cchMax > 0 && cchMax < MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(cchMax) )
                    _When_(cchMax >= MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(MAX_ERROR_MESSAGE_CHARS) ) PCWSTR message)
                {
                    return ::RoTransformErrorW(oldError, newError, cchMax, message);
                }
            
                inline BOOL TransformError(_In_ HRESULT oldError, _In_ HRESULT newError, _In_ HSTRING message)
                {
                    return ::RoTransformError(oldError, newError, message);
                }
            }
        }
    }
}

#endif  //__cplusplus


//  Exception Codes are 32 bit values laid out as follows:
//
//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
//  +---+-+-+-----------------------+-------------------------------+
//  |Sev|C|R|     Facility          |               Code            |
//  +---+-+-+-----------------------+-------------------------------+
//
//  where
//
//      Sev - is the severity code
//
//          00 - Success
//          01 - Informational
//          10 - Warning
//          11 - Error
//
//      C - is the Customer code flag
//
//      R - is a reserved bit
//
//      Facility - is the facility code
//
//      Code - is the facility's status code

const DWORD EXCEPTION_RO_ORIGINATEERROR = (DWORD)((0x1 << 30) | (FACILITY_WINDOWS << 16) | 0x201);  //0x40080201L
const DWORD EXCEPTION_RO_TRANSFORMERROR = (DWORD)((0x1 << 30) | (FACILITY_WINDOWS << 16) | 0x202);  //0x40080202L

// The various versions of RoOriginateError will raise and catch a structured exception with an 
// exception code of EXCEPTION_RO_ORIGINATEERROR and the following information in the 
// ExceptionInformation array. The characterCount element is the number of characters in the message, 
// not including the NULL terminator.
// ExceptionInformation[0] -- HRESULT error
// ExceptionInformation[1] -- UINT characterCount
// ExceptionInformation[2] -- PCWSTR message
//
// The various versions of RoTransformError will raise and catch a structured exception with an
// exception code of EXCEPTION_RO_TRANSFORMERROR and the following information in the
// ExceptionInformation array. The characterCountelement is the number of characters in the message,
// not including the NULL terminator.
// ExceptionInformation[0] -- HRESULT oldError
// ExceptionInformation[1] -- HRESULT newError
// ExceptionInformation[2] -- UINT characterCount
// ExceptionInformaiton[3] -- PCWSTR message
//
// As documented in MSDN, the ExceptionInformation can be retrieved in the filter expression
// of a frame-based exception handler by calling GetExceptionInformation. A debugger can
// retrieve these values by calling WaitForDebugEvent, keeping in mind that exception records have
// a different binary layout between 32bit and 64bit processes.

#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
#pragma endregion

#endif // #if (NTDDI_VERSION >= NTDDI_WIN8)

#endif /* _ROERROR_H */

