Skip to content
76 changes: 76 additions & 0 deletions include/wil/cppwinrt_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,51 @@ struct dispatcher_traits<winrt::Microsoft::UI::Dispatching::DispatcherQueue>
#endif // __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS
/// @endcond

#if defined(WINRT_Windows_Foundation_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_BUFFER_HELPERS) ||\
defined(WIL_DOXYGEN)
Comment on lines +229 to +230
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
#if defined(WINRT_Windows_Foundation_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_BUFFER_HELPERS) ||\
defined(WIL_DOXYGEN)
#if defined(WINRT_Windows_Foundation_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_BUFFER_HELPERS) || defined(WIL_DOXYGEN)

To make clang-format happy

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think extra parens will also help.

/// @cond
#define __WIL_CPPWINRT_WINDOWS_FOUNDATION_BUFFER_HELPERS
namespace Windows::Foundation
Comment thread
dunhor marked this conversation as resolved.
{
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>
winrt::array_view<T> 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 <memorybuffer.h> hasn't been included.
using IMemoryBufferByteAccess = std::enable_if_t<std::is_same_v<T, T>, ::Windows::Foundation::IMemoryBufferByteAccess>;
winrt::check_hresult(reference.as<IMemoryBufferByteAccess>()->GetBuffer(&data, &capacity));
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>
winrt::array_view<T> to_array_view(winrt::Windows::Foundation::IMemoryBuffer const& buffer)
{
return to_array_view<T>(buffer.CreateReference());
}
}
#endif

#if (defined(WINRT_Windows_Foundation_Collections_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS)) || \
defined(WIL_DOXYGEN)
/// @cond
Expand Down Expand Up @@ -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<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)) || \
defined(WIL_DOXYGEN)
/// @cond
Expand Down
40 changes: 40 additions & 0 deletions tests/CppWinRTTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#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 <wil/stl.h>
#include <memorybuffer.h>

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

Expand Down Expand Up @@ -206,6 +208,44 @@ TEST_CASE("CppWinRTTests::VectorToVector", "[cppwinrt]")
winrt::uninit_apartment();
}

TEST_CASE("CppWinRTTests::BufferToArrayView", "[cppwinrt]")
{
std::array<int32_t, 2> testData = { 314159265, 27182818 };
Comment thread
dunhor marked this conversation as resolved.
auto testDataByteStart = reinterpret_cast<uint8_t*>(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<int32_t>(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<int32_t>(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) {
Expand Down
Loading