Passing parameters into the ABI boundary

With the types in the winrt::param namespace, C++/WinRT simplifies passing parameters into the ABI boundary by providing automatic conversions for common cases. You can see more details, and code examples, in String handling and Standard C++ data types and C++/WinRT.

Important

You shouldn't use the types in the winrt::param namespace yourself. They're for the benefit of the projection.

Many types come in both synchronous and asynchronous versions. C++/WinRT uses the synchronous version when you're passing a parameter to a synchronous method; it uses the asynchronous version when you're passing a parameter to an asynchronous method. The asynchronous version takes extra steps to make it harder for the caller to mutate the collection before the operation has completed. Note, however, that none of the variants protect against the collection being mutated from another thread. Preventing that is your responsibility.

String parameters

winrt::param::hstring simplifies passing parameters to APIs that take HSTRING.

Types that you can pass Notes
{} Passes empty string.
winrt::hstring
std::wstring_view For literals, you can write L"Name"sv. The view must have a null terminator after the end.
std::wstring -
wchar_t const* A null-terminated string.

nullptr is not allowed. Use {} instead.

The compiler knows how to evaluate wcslen on string literals at compile time. So, for literals, L"Name"sv and L"Name" are equivalent.

Note that std::wstring_view objects are not null terminated, but C++/WinRT requires that the character after the end of the string be a null. If you pass a non-null-terminated std::wstring_view, then the process will terminate.

Iterable parameters

winrt::param::iterable<T> and winrt::param::async_iterable<T> simplify passing parameters to APIs that take IIterable<T>.

Windows Runtime collections are already IIterable.

Types that you can pass Sync Async Notes
nullptr Yes Yes You must verify that the underlying method supports nullptr.
IIterable<T> Yes Yes Or anything convertible to it.
std::vector<T> const& Yes No
std::vector<T>&& Yes Yes Contents are moved into the iterator to prevent mutation.
std::initializer_list<T> Yes Yes The async version copies the items.
std::initializer_list<U> Yes No U must be convertible to T.
{ ForwardIt begin, ForwardIt end } Yes No *begin must be convertible to T.

Note that IIterable<U> and std::vector<U> are not permitted, even if U is convertible to T. For std::vector<U>, you can use the double-iterator version (more details below).

In some cases, the object that you have may actually implement the IIterable that you want. For example, the IVectorView<StorageFile> produced by FileOpenPicker.PickMultipleFilesAsync implements IIterable<StorageFile>. But it also implements IIterable<IStorageItem>; you just have to ask for it explicitly.

IVectorView<StorageFile> pickedFiles{ co_await filePicker.PickMultipleFilesAsync() };
requestData.SetStorageItems(storageItems.as<IIterable<IStorageItem>>());

In other cases, you can use the double-iterator version.

std::vector<StorageFile> storageFiles;
requestData.SetStorageItems({ storageFiles.begin(), storageFiles.end() });

The double-iterator works more generally for the case where you have a collection that doesn't fit any of the scenarios above, as long as you can iterate over it and produce things that can be converted to T. We used it above to iterate over a vector of derived types. Here, we use it to iterate over a non-vector of derived types.

std::array<StorageFile, 3> storageFiles;
requestData.SetStorageItems(storageFiles); // This doesn't work.
requestData.SetStorageItems({ storageFiles.begin(), storageFiles.end() }); // But this works.

The implementation of IIterator<T>.GetMany(T[]) is more efficient if the iterator is a RandomAcessIt. Otherwise, it makes several passes over the range.

Types that you can pass Sync Async Notes
nullptr Yes Yes You must verify that the underlying method supports nullptr.
IIterable<IKeyValuePair<K, V>> Yes Yes Or anything convertible to it.
std::map<K, V> const& Yes No
std::map<K, V>&& Yes Yes Contents are moved into the iterator to prevent mutation.
std::unordered_map<K, V> const& Yes No
std::unordered_map<K, V>&& Yes Yes Contents are moved into the iterator to prevent mutation.
std::initializer_list<std::pair<K, V>> Yes Yes Types K and V must match exactly. Keys may not be duplicated. The async version copies the items.
{ ForwardIt begin, ForwardIt end } Yes No begin->first and begin->second must be convertible to K and V, respectively.

Vector view parameters

winrt::param::vector_view<T> and winrt::param::async_vector_view<T> simplify passing parameters to APIs that take IVectorView<T>.

You can use IVector<T>.GetView to get an IVectorView from an IVector.

Types that you can pass Sync Async Notes
nullptr Yes Yes You must verify that the underlying method supports nullptr.
IVectorView<T> Yes Yes Or anything convertible to it.
std::vector<T>const& Yes No
std::vector<T>&& Yes Yes Contents are moved into the view to prevent mutation.
std::initializer_list<T> Yes Yes Type must match exactly. The async version copies the items.
{ ForwardIt begin, ForwardIt end } Yes No *begin must be convertible to T.

The double-iterator version can be used to create vector views out of things that don't fit the requirements for being passed directly. Note, however, that since vectors support random access, we recommend that you pass a RandomAcessIter.

Map view parameters

winrt::param::map_view<T> and winrt::param::async_map_view<T> simplify passing parameters to APIs that take IMapView<T>.

You can use IMap::GetView to get an IMapView from an IMap.

Types that you can pass Sync Async Notes
nullptr Yes Yes You must verify that the underlying method supports nullptr.
IMapView<K, V> Yes Yes Or anything convertible to it.
std::map<K, V> const& Yes No
std::map<K, V>&& Yes Yes Contents are moved into the view to prevent mutation.
std::unordered_map<K, V> const& Yes No
std::unordered_map<K, V>&& Yes Yes Contents are moved into the view to prevent mutation.
std::initializer_list<std::pair<K, V>> Yes Yes Both sync and async versions copy the items. You may not duplicate keys.

Vector parameters

winrt::param::vector<T> simplifies passing parameters to APIs that take IVector<T>.

Types that you can pass Notes
nullptr You must verify that the underlying method supports nullptr.
IVector<T> Or anything convertible to it.
std::vector<T>&& Contents are moved into the parameter to prevent mutation. Results are not moved back.
std::initializer_list<T> Contents are copied into the parameter to prevent mutation.

If the method mutates the vector, then the only way to observe the mutation is to pass an IVector directly. If you pass a std::vector, then the method mutates the copy and not the original.

Map parameters

winrt::param::map<T> simplifies passing parameters to APIs that take IMap<T>.

Types that you can pass Notes
nullptr You must verify that the underlying method supports nullptr.
IMap<T> Or anything convertible to it.
std::map<K, V>&& Contents are moved into the parameter to prevent mutation. Results are not moved back.
std::unordered_map<K, V>&& Contents are moved into the parameter to prevent mutation. Results are not moved back.
std::initializer_list<std::pair<K, V>> Contents are copied into the parameter to prevent mutation.

If the method mutates the map, then the only way to observe the mutation is to pass an IMap directly. If you pass a std::map or std::unordered_map, then the method mutates the copy and not the original.

Array parameters

The winrt::array_view<T> is not in the winrt::param namespace, but it is used for parameters that are C-style arrays—also known as conformant arrays.

Types that you can pass Notes
{} An empty array.
array A conformant array of C (that is, C array[N];), where C is convertible to T, and sizeof(C) == sizeof(T).
std::array<C, N> A C++ std::array of C, where C is convertible to T, and sizeof(C) == sizeof(T).
std::vector<C> A C++ std::vector of C, where C is convertible to T, and sizeof(C) == sizeof(T).
{ T*, T* } A pair of pointers represent the range [begin, end).
std::initializer_list<T>

Also see the blog post The various patterns for passing C-style arrays across the Windows Runtime ABI boundary.