diff --git a/include/wil/cppwinrt_helpers.h b/include/wil/cppwinrt_helpers.h index d3c09341..78930f52 100644 --- a/include/wil/cppwinrt_helpers.h +++ b/include/wil/cppwinrt_helpers.h @@ -226,6 +226,51 @@ struct dispatcher_traits #endif // __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS /// @endcond +#if defined(WINRT_Windows_Foundation_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_BUFFER_HELPERS) ||\ + defined(WIL_DOXYGEN) +/// @cond +#define __WIL_CPPWINRT_WINDOWS_FOUNDATION_BUFFER_HELPERS +namespace Windows::Foundation +{ + struct IMemoryBufferByteAccess; +} +/// @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, but you can provide an alternate + //! type such as to_array_view. + //! You must include memorybuffer.h in order to use this overload of to_array_view. + template + winrt::array_view to_array_view(winrt::Windows::Foundation::IMemoryBufferReference const& reference) + { + uint8_t* data; + uint32_t capacity; + // Make IMemoryBufferByteAccess a dependent type so we can talk about it even if hasn't been included. + using IMemoryBufferByteAccess = std::enable_if_t, ::Windows::Foundation::IMemoryBufferByteAccess>; + winrt::check_hresult(reference.as()->GetBuffer(&data, &capacity)); + return { reinterpret_cast(data), static_cast(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, but you can provide an alternate + //! type such as to_array_view. + //! You must include memorybuffer.h in order to use this overload of to_array_view. + template + winrt::array_view to_array_view(winrt::Windows::Foundation::IMemoryBuffer const& buffer) + { + return to_array_view(buffer.CreateReference()); + } +} +#endif + #if (defined(WINRT_Windows_Foundation_Collections_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS)) || \ defined(WIL_DOXYGEN) /// @cond @@ -352,6 +397,37 @@ auto to_vector(TSrc const& src) } // namespace wil #endif +#if defined(WINRT_Windows_Storage_Streams_H) && !defined(__WIL_CPPWINRT_WINDOWS_STORAGE_STREAMS_HELPERS) ||\ + defined(WIL_DOXYGEN) +/// @cond +#define __WIL_CPPWINRT_WINDOWS_STORAGE_STREAMS_HELPERS +/// @endcond +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, but you can provide an alternate + //! type such as to_array_view. + template + winrt::array_view to_array_view(winrt::Windows::Storage::Streams::IBuffer const& buffer) + { + return { reinterpret_cast(buffer.data()), static_cast(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, but you can provide an alternate + //! type such as to_array_view. + template + winrt::array_view to_array_view_for_capacity(winrt::Windows::Storage::Streams::IBuffer const& buffer) + { + return { reinterpret_cast(buffer.data()), static_cast(buffer.Capacity() / sizeof(T)) }; + } +} +#endif + #if (defined(WINRT_Windows_UI_H) && defined(_WINDOWS_UI_INTEROP_H_) && !defined(__WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS)) || \ defined(WIL_DOXYGEN) /// @cond diff --git a/tests/CppWinRTTests.cpp b/tests/CppWinRTTests.cpp index 90b226d1..863fd5e0 100644 --- a/tests/CppWinRTTests.cpp +++ b/tests/CppWinRTTests.cpp @@ -10,8 +10,10 @@ #include #include #include +#include #include // Verify can include a second time to unlock more features #include +#include using namespace winrt::Windows::ApplicationModel::Activation; @@ -206,6 +208,44 @@ TEST_CASE("CppWinRTTests::VectorToVector", "[cppwinrt]") winrt::uninit_apartment(); } +TEST_CASE("CppWinRTTests::BufferToArrayView", "[cppwinrt]") +{ + std::array testData = { 314159265, 27182818 }; + auto testDataByteStart = reinterpret_cast(testData.data()); + + // Create a buffer with capacity for our testData, length for one of the int32_t's. + auto buffer = winrt::Windows::Storage::Streams::Buffer(sizeof(testData)); + buffer.Length(sizeof(int32_t)); + + // Get a Capacity-based int view and set the test data. + { + auto view = wil::to_array_view_for_capacity(buffer); + REQUIRE(view.size() == testData.size()); + std::copy(view.begin(), view.end(), testData.begin()); + } + // Get a Length-based byte view and confirm that the four bytes match the first four + // bytes of our test data. + { + auto view = wil::to_array_view(buffer); + REQUIRE(view.size() == sizeof(int32_t)); + REQUIRE(view == winrt::array_view(testDataByteStart, sizeof(int32_t))); + } + // Create an IMemoryBuffer around the Buffer. This uses the Buffer's Capacity as the MemoryBuffer size. + auto mbuffer = winrt::Windows::Storage::Streams::Buffer::CreateMemoryBufferOverIBuffer(buffer); + // Verify that the buffer is the test data as int32_t. + { + auto view = wil::to_array_view(mbuffer); + REQUIRE(view.size() == testData.size()); + REQUIRE(view == winrt::array_view(testData)); + } + // Verify that the buffer reference gives us the test data as uint8_t. + { + auto view = wil::to_array_view(mbuffer.CreateReference()); + REQUIRE(view.size() == sizeof(testData)); + REQUIRE(view == winrt::array_view(testDataByteStart, sizeof(testData))); + } +} + TEST_CASE("CppWinRTTests::WilToCppWinRTExceptionTranslationTest", "[cppwinrt]") { auto test = [](HRESULT hr) {