HRESULT WaitForCompletion()

in include/wil/winrt.h [1405:1481]


    HRESULT WaitForCompletion(_In_ TIOperation operation, COWAIT_FLAGS flags, DWORD timeoutValue, _Out_opt_ bool* timedOut) WI_NOEXCEPT
    {
        typedef wistd::remove_pointer_t<decltype(GetAsyncDelegateType(operation))> TIDelegate;

        class CompletionDelegate : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::Delegate>,
            TIDelegate, Microsoft::WRL::FtmBase>
        {
        public:
            HRESULT RuntimeClassInitialize()
            {
                RETURN_HR(m_completedEventHandle.create());
            }

            HRESULT STDMETHODCALLTYPE Invoke(_In_ TIOperation, ABI::Windows::Foundation::AsyncStatus status) override
            {
                m_status = status;
                m_completedEventHandle.SetEvent();
                return S_OK;
            }

            HANDLE GetEvent() const
            {
                return m_completedEventHandle.get();
            }

            ABI::Windows::Foundation::AsyncStatus GetStatus() const
            {
                return m_status;
            }

        private:
            volatile ABI::Windows::Foundation::AsyncStatus m_status = ABI::Windows::Foundation::AsyncStatus::Started;
            wil::unique_event_nothrow m_completedEventHandle;
        };

        WI_ASSERT(timedOut || (timeoutValue == INFINITE));
        assign_to_opt_param(timedOut, false);

        Microsoft::WRL::ComPtr<CompletionDelegate> completedDelegate;
        RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CompletionDelegate>(&completedDelegate));
        RETURN_IF_FAILED(operation->put_Completed(completedDelegate.Get()));

        HANDLE handles[] = { completedDelegate->GetEvent() };
        DWORD dwHandleIndex;
        HRESULT hr = CoWaitForMultipleHandles(flags, timeoutValue, ARRAYSIZE(handles), handles, &dwHandleIndex);

        // If the caller is listening for timedOut, and we actually timed out, set the bool and return S_OK. Otherwise, fail.
        if (timedOut && (hr == RPC_S_CALLPENDING))
        {
            *timedOut = true;
            return S_OK;
        }
        RETURN_IF_FAILED(hr);

        if (completedDelegate->GetStatus() != ABI::Windows::Foundation::AsyncStatus::Completed)
        {
            // QI to the IAsyncInfo interface.  While all operations implement this, it is
            // possible that the stub has disconnected, causing the QI to fail.
            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
            hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo));
            if (SUCCEEDED(hr))
            {
                // Save the error code result in a temporary variable to allow us
                // to also retrieve the result of the COM call.  If the stub has
                // disconnected, this call may fail.
                HRESULT errorCode = E_UNEXPECTED;
                hr = asyncInfo->get_ErrorCode(&errorCode);
                if (SUCCEEDED(hr))
                {
                    // Return the operations error code to the caller.
                    hr = errorCode;
                }
            }
            return hr; // leave it to the caller to log failures.
        }
        return S_OK;
    }