inline void LogFailure()

in include/wil/result_macros.h [3463:3593]


        inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, const ResultStatus& resultPair, _In_opt_ PCWSTR message,
            bool fWantDebugString, _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars,
            _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars,
            _Out_ FailureInfo *failure) WI_NOEXCEPT
        {
            debugString[0] = L'\0';
            callContextString[0] = L'\0';

            static long volatile s_failureId = 0;

            failure->hr = resultPair.hr;
            failure->status = resultPair.status;

            int failureCount = 0;
            switch (type)
            {
            case FailureType::Exception:
                failureCount = RecordException(failure->hr);
                break;
            case FailureType::Return:
                failureCount = RecordReturn(failure->hr);
                break;
            case FailureType::Log:
                if (SUCCEEDED(failure->hr))
                {
                    // If you hit this assert (or are reviewing this failure telemetry), then most likely you are trying to log success
                    // using one of the WIL macros.  Example:
                    //      LOG_HR(S_OK);
                    // Instead, use one of the forms that conditionally logs based upon the error condition:
                    //      LOG_IF_FAILED(hr);

                    WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected.  Do not LOG_XXX success.");
                    failure->hr = __HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE);
                    failure->status = wil::details::HrToNtStatus(failure->hr);
                }
                failureCount = RecordLog(failure->hr);
                break;
            case FailureType::FailFast:
                failureCount = RecordFailFast(failure->hr);
                break;
            };

            failure->type = type;
            failure->flags = FailureFlags::None;
            WI_SetFlagIf(failure->flags, FailureFlags::NtStatus, resultPair.isNtStatus);
            failure->failureId = ::InterlockedIncrementNoFence(&s_failureId);
            failure->pszMessage = ((message != nullptr) && (message[0] != L'\0')) ? message : nullptr;
            failure->threadId = ::GetCurrentThreadId();
            failure->pszFile = fileName;
            failure->uLineNumber = lineNumber;
            failure->cFailureCount = failureCount;
            failure->pszCode = code;
            failure->pszFunction = functionName;
            failure->returnAddress = returnAddress;
            failure->callerReturnAddress = callerReturnAddress;
            failure->pszCallContext = nullptr;
            ::ZeroMemory(&failure->callContextCurrent, sizeof(failure->callContextCurrent));
            ::ZeroMemory(&failure->callContextOriginating, sizeof(failure->callContextOriginating));
            failure->pszModule = (g_pfnGetModuleName != nullptr) ? g_pfnGetModuleName() : nullptr;

            // Completes filling out failure, notifies thread-based callbacks and the telemetry callback
            if (details::g_pfnGetContextAndNotifyFailure)
            {
                details::g_pfnGetContextAndNotifyFailure(failure, callContextString, callContextStringSizeChars);
            }

            // Allow hooks to inspect the failure before acting upon it
            if (details::g_pfnLoggingCallback)
            {
                details::g_pfnLoggingCallback(*failure);
            }

            // If the hook is enabled then it will be given the opportunity to call RoOriginateError to greatly improve the diagnostic experience
            // for uncaught exceptions.  In cases where we will be throwing a C++/CX Platform::Exception we should avoid originating because the
            // CX runtime will be doing that for us.  fWantDebugString is only set to true when the caller will be throwing a Platform::Exception.
            if (details::g_pfnOriginateCallback && !fWantDebugString)
            {
                details::g_pfnOriginateCallback(*failure);
            }

            if (SUCCEEDED(failure->hr))
            {
                // Caller bug: Leaking a success code into a failure-only function
                FAIL_FAST_IMMEDIATE_IF(type != FailureType::FailFast);
                failure->hr = E_UNEXPECTED;
                failure->status = wil::details::HrToNtStatus(failure->hr);
            }

            bool const fUseOutputDebugString = IsDebuggerPresent() && g_fResultOutputDebugString;

            // We need to generate the logging message if:
            // * We're logging to OutputDebugString
            // * OR the caller asked us to (generally for attaching to a C++/CX exception)
            if (fWantDebugString || fUseOutputDebugString)
            {
                // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the console
                // or the platform exception object if the caller desires it.
                if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet)
                {
                    g_pfnResultLoggingCallback(failure, debugString, debugStringSizeChars);
                }

                // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still want
                // it for OutputDebugString or exception message, then generate the default string.
                if (debugString[0] == L'\0')
                {
                    GetFailureLogString(debugString, debugStringSizeChars, *failure);
                }

                if (fUseOutputDebugString)
                {
                    ::OutputDebugStringW(debugString);
                }
            }
            else
            {
                // [deprecated behavior]
                // This callback was at one point *always* called for all failures, so we continue to call it for failures even when we don't
                // need to generate the debug string information (when the callback was supplied directly).  We can avoid this if the caller
                // used the explicit function (through g_resultMessageCallbackSet)
                if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet)
                {
                    g_pfnResultLoggingCallback(failure, nullptr, 0);
                }
            }

            if (g_fBreakOnFailure && (g_pfnDebugBreak != nullptr))
            {
                g_pfnDebugBreak();
            }
        }