Skip to content
70 changes: 70 additions & 0 deletions include/wil/cppwinrt_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,48 @@ namespace wil::details
#endif // __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS
/// @endcond

#if defined(WINRT_Windows_Foundation_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_HELPERS)
#define __WIL_CPPWINRT_WINDOWS_FOUNDATION_HELPERS
namespace Windows::Foundation
Comment thread
dunhor marked this conversation as resolved.
{
/// @cond
struct IMemoryBufferByteAccess;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
struct IMemoryBufferByteAccess;
struct IMemoryBufferByteAccess;

To make clang-format happy

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, too many instances to do this manually...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I on a fork?

One thing I'd really like to do if I ever got the time to do it is to add a pipeline/action/something that I can run that will run clang format & commit the result, either as a separate command (e.g. /azp format) or just part of the pipeline by default.

/// @endcond
}

namespace wil
{
//! Returns a view into the underlying bytes of a memory buffer
//! provided in the form of an IMemoryBufferReference.
//! The caller is responsible for ensuring that the memory buffer's
//! lifetime encompasses the lifetime of the returned view.
//! By default, returns an array_view<uint8_t>, but you can provide an alternate
//! type such as to_array_view<double>.
//! You must include memorybuffer.h in order to use this overload of to_array_view.
Comment thread
oldnewthing marked this conversation as resolved.
template<typename T = uint8_t, int V = 0>
Comment thread
oldnewthing marked this conversation as resolved.
Outdated
winrt::array_view<T> to_array_view(winrt::Windows::Foundation::IMemoryBufferReference const& reference)
{
uint8_t* data;
uint32_t capacity;
winrt::check_hresult(reference.as<std::enable_if_t<!V, ::Windows::Foundation::IMemoryBufferByteAccess>>()->GetBuffer(&data, &capacity));
Comment thread
oldnewthing marked this conversation as resolved.
Outdated
return { reinterpret_cast<T*>(data), static_cast<uint32_t>(capacity / sizeof(T)) };
}

//! Returns a view into the underlying bytes of a memory buffer
//! provided in the form of an IMemoryBuffer.
//! The caller is responsible for ensuring that the memory buffer's
//! lifetime encompasses the lifetime of the returned view.
//! By default, returns an array_view<uint8_t>, but you can provide an alternate
//! type such as to_array_view<double>.
//! You must include memorybuffer.h in order to use this overload of to_array_view.
template<typename T = uint8_t, int V = 0>
winrt::array_view<T> to_array_view(winrt::Windows::Foundation::IMemoryBuffer const& buffer)
{
return to_array_view<T, V>(buffer.CreateReference());
}
}
#endif

#if defined(WINRT_Windows_Foundation_Collections_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS)
#define __WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS
namespace wil
Expand Down Expand Up @@ -314,6 +356,34 @@ namespace wil
}
#endif

#if defined(WINRT_Windows_Storage_Streams_H) && !defined(__WIL_CPPWINRT_WINDOWS_STORAGE_STREAMS_HELPERS)
#define __WIL_CPPWINRT_WINDOWS_STORAGE_STREAMS_HELPERS
namespace wil
{
//! Returns a view into the underlying bytes of an IBuffer up to its Length.
//! The caller is responsible for ensuring that the IBuffer's
//! lifetime encompasses the lifetime of the returned view.
//! By default, returns an array_view<uint8_t>, but you can provide an alternate
//! type such as to_array_view<double>.
template<typename T = uint8_t>
winrt::array_view<T> to_array_view(winrt::Windows::Storage::Streams::IBuffer const& buffer)
{
return { reinterpret_cast<T*>(buffer.data()), static_cast<uint32_t>(buffer.Length() / sizeof(T)) };
}

//! Returns a view into the underlying bytes of an IBuffer up to its Capacity.
//! The caller is responsible for ensuring that the IBuffer's
//! lifetime encompasses the lifetime of the returned view.
//! By default, returns an array_view<uint8_t>, but you can provide an alternate
//! type such as to_array_view<double>.
template<typename T = uint8_t>
winrt::array_view<T> to_array_view_for_capacity(winrt::Windows::Storage::Streams::IBuffer const& buffer)
{
return { reinterpret_cast<T*>(buffer.data()), static_cast<uint32_t>(buffer.Capacity() / sizeof(T)) };
}
}
#endif

#if defined(WINRT_Windows_UI_H) && defined(_WINDOWS_UI_INTEROP_H_) && !defined(__WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS)
#define __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS
#if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX)
Expand Down
38 changes: 38 additions & 0 deletions tests/CppWinRTTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
#include <winrt/Windows.ApplicationModel.Activation.h>
#include <wil/cppwinrt_helpers.h>
#include <winrt/Windows.System.h>
#include <winrt/Windows.Storage.Streams.h>
#include <wil/cppwinrt_helpers.h> // Verify can include a second time to unlock more features
#include <memorybuffer.h>

using namespace winrt::Windows::ApplicationModel::Activation;

Expand Down Expand Up @@ -182,6 +184,42 @@ TEST_CASE("CppWinRTTests::VectorToVector", "[cppwinrt]")
winrt::uninit_apartment();
}

TEST_CASE("CppWinRTTests::BufferToArrayView", "[cppwinrt]")
{
// Create a buffer of capacity 8 and length 4.
auto buffer = winrt::Windows::Storage::Streams::Buffer(8);
buffer.Length(4);
// Get a Capacity-based int view and set the ints to 256 and 512.
{
auto view = wil::to_array_view_for_capacity<int32_t>(buffer);
REQUIRE(view.size() == 2);
view[0] = 256;
Comment thread
oldnewthing marked this conversation as resolved.
Outdated
view[1] = 512;
}
// Get a Length-based byte view and confirm that the four bytes are { 0, 1, 0, 0 }.
// (Assumes little-endian system.)
{
auto view = wil::to_array_view(buffer);
REQUIRE(view.size() == 4);
REQUIRE(view == winrt::array_view(std::array<uint8_t, 4>{ 0, 1, 0, 0 }));
}
// Create an IMemoryBuffer around the Buffer.
auto mbuffer = winrt::Windows::Storage::Streams::Buffer::CreateMemoryBufferOverIBuffer(buffer);
// Verify that the buffer is the 2 ints 256 and 512.
{
auto view = wil::to_array_view<int>(mbuffer);
REQUIRE(view.size() == 2);
REQUIRE(view == winrt::array_view(std::array{ 256, 512 }));
}
// Verify that the buffer reference is the 8 bytes { 0, 1, 0, 0, 0, 2, 0, 0 }.
// (Assumes little-endian system.)
{
auto view = wil::to_array_view(mbuffer.CreateReference());
REQUIRE(view.size() == 8);
REQUIRE(view == winrt::array_view(std::array<uint8_t, 8>{ 0, 1, 0, 0, 0, 2, 0, 0 }));
}
}

TEST_CASE("CppWinRTTests::WilToCppWinRTExceptionTranslationTest", "[cppwinrt]")
{
auto test = [](HRESULT hr)
Expand Down