diff --git a/include/wil/cppwinrt_helpers.h b/include/wil/cppwinrt_helpers.h index c46a73e0d..67117247c 100644 --- a/include/wil/cppwinrt_helpers.h +++ b/include/wil/cppwinrt_helpers.h @@ -212,6 +212,50 @@ 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 +{ + /// @cond + 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) #define __WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS namespace wil @@ -314,6 +358,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, 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) #define __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS #if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX) diff --git a/tests/CppWinRTTests.cpp b/tests/CppWinRTTests.cpp index 210ad8586..fc7368104 100644 --- a/tests/CppWinRTTests.cpp +++ b/tests/CppWinRTTests.cpp @@ -9,7 +9,9 @@ #include #include #include +#include #include // Verify can include a second time to unlock more features +#include using namespace winrt::Windows::ApplicationModel::Activation; @@ -182,6 +184,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)