-
Notifications
You must be signed in to change notification settings - Fork 236
RPC helpers
WIL RPC helpers help you call RPC methods safely,
such as converting structured exceptions to HRESULT
.
The RPC helpers can be used by including the correct header file:
#include <wil/rpc_helpers.h>
-
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.
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);
}
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"));
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"));
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'
-
TResult
The return type of the interface method. This value is assigned-to when the interface method returns without generating an exception.
This method wraps wil::invoke_rpc_result_nothrow
and translates
its HRESULT
s 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'