Skip to content
Jon Wiswall edited this page Jun 12, 2019 · 1 revision

WIL RPC helpers help you call RPC methods safely, such as converting structured exceptions to HRESULT.

Usage

The RPC helpers can be used by including the correct header file:

#include <wil/rpc_helpers.h>

Definitions

  • RPC methods are those defined in the Microsoft RPC Windows API itself, such as RpcExceptionFilter.
  • Interface methods are those defined in IDL by an application or service.

Invoke helpers

Failures encountered by the Microsoft RPC infrastructure on Windows (such as server crashes, authentication errors, client parameter issues, etc.) are emitted by raising a structured exception from within the RPC machinery. These helpers wrap an invocation of the target interface method in a RpcTryExcept, RpcTryCatch, and RpcEndExcept sequence. Structured exceptions from RPC are mapped to HRESULT and returned. Return values of interface methods are returned directly to the caller.

RPC allows interface methods that return void. For the purposes of these invocation helpers a successful call is mapped to returning S_OK.

MSVC has historically not allowed mixing of structured exceptions and C++ exceptions in a single method, which also meant no method with a structured exception handler could define objects with destructors.

The following methods refer to an RPC IDL definition similar to the following:

[uuid(...), version(1.0)]
interface kittens
{
    HRESULT GetKittenState(
        [in] handle_t binding,
        [in, string] PCWSTR name,
        [out, retval] KittenState** state);

    GUID GetKittenId(
        [in] handle_t binding,
        [in, string] PCWSTR name);

    void PetKitten(
        [in] handle_t binding,
        [in, string] PCWSTR name);
}

wil::invoke_rpc_nothrow

The invoke_rpc_nothrow function expects a parameter-list compatible with wistd::invoke and having a result type of either HRESULT or void.

RPC exceptions are caught, converted to an equivalent HRESULT, and returned to the caller.

Results of interface methods are returned to the caller.

template<typename... TCall>
HRESULT invoke_rpc_nothrow(TCall&&... call) WI_NOEXCEPT;

Example usage:

// Call interface method that returns an HRESULT
wil::unique_rpc_binding binding = // typically gotten elsewhere;
wil::unique_midl_ptr<KittenState> state;
HRESULT hr = wil::invoke_rpc_nothrow(GetKittenState, binding.get(), L"fluffy", state.put());
RETURN_IF_FAILED(hr);

// Call interface method that returns void, log and ignore problems
LOG_IF_FAILED(wil::invoke_rpc_nothrow(PetKitten, binding.get(), L"fluffy"));

wil::invoke_rpc

Similar to wil::invoke_rpc_nothrow, this method invokes the RPC call but translates errors (either in RPC or returned by the interface method) to a C++ exception.

template<typename... TCall>
void invoke_rpc(TCall&&... call);

Example usage:

// Call interface method that returns an HRESULT
wil::unique_rpc_binding binding = // typically gotten elsewhere;
wil::unique_midl_ptr<KittenState> state;
wil::invoke_rpc(GetKittenState, binding.get(), L"fluffy", state.put());

// Call interface method that returns void, log and ignore problems
wil::invoke_rpc(PetKitten, binding.get(), L"fluffy"));

wil::invoke_rpc_result_nothrow

Interface methods can return results other than HRESULT, such as GUID or DWORD or other types understood by MIDL-RPC. Calling wil::invoke_rpc_result_nothrow seperates this result value from the RPC infrastructure results. RPC errors are emitted as the HRESULT return value of this method.

template<typename TResult, typename... TCall>
HRESULT invoke_rpc_result_nothrow(TResult& result, TCall&&... call) WI_NOEXCEPT;

Example:

GUID id{};
wil::unique_rpc_binding binding = // typically gotten elsewhere;
HRESULT hr = wil::invoke_rpc_result_nothrow(id, GetKittenId, binding.get(), L"fluffy");
RETURN_IF_FAILED(hr);
// ... consume 'id'

Template parameters

  • TResult The return type of the interface method. This value is assigned-to when the interface method returns without generating an exception.

wil::invoke_rpc_result

This method wraps wil::invoke_rpc_result_nothrow and translates its HRESULTs to exceptions. The returned value of the interface method is preserved and returned to the caller directly.

template<typename... TCall>
auto invoke_rpc_result(TCall&&... call);

Example:

wil::unique_rpc_binding binding = // typically gotten elsewhere;
const GUID id = wil::invoke_rpc_result(GetKittenId, binding.get(), L"fluffy");
// ... consume 'id'