dolphin/Externals/WIL/tests/FakeWinRTTypes.h

401 lines
8.5 KiB
C++

#pragma once
#include <wil/resource.h>
#include <windows.foundation.h>
#include <wrl/implements.h>
#include <wrl/wrappers/corewrappers.h>
template <typename T>
struct WinRTStorage
{
T value = {};
HRESULT CopyTo(T* result)
{
*result = value;
return S_OK;
}
HRESULT Set(T val)
{
value = val;
return S_OK;
}
static void Destroy(T&)
{
}
void Reset()
{
}
bool Equals(T val)
{
// NOTE: Padding can through this off, but this isn't intended to be a robust solution...
return memcmp(&value, &val, sizeof(T)) == 0;
}
};
template <>
struct WinRTStorage<HSTRING>
{
Microsoft::WRL::Wrappers::HString value;
HRESULT CopyTo(HSTRING* result) const
{
return value.CopyTo(result);
}
HRESULT Set(HSTRING val)
{
return value.Set(val);
}
static void Destroy(HSTRING& val)
{
::WindowsDeleteString(val);
val = nullptr;
}
void Reset()
{
value = {};
}
bool Equals(HSTRING val) const
{
return value == val;
}
};
template <typename T>
struct WinRTStorage<T*>
{
Microsoft::WRL::ComPtr<T> value;
HRESULT CopyTo(T** result)
{
*result = Microsoft::WRL::ComPtr<T>(value).Detach();
return S_OK;
}
HRESULT Set(T* val)
{
value = val;
return S_OK;
}
static void Destroy(T*& val)
{
val->Release();
val = nullptr;
}
void Reset()
{
value.Reset();
}
bool Equals(T* val)
{
return value.Get() == val;
}
};
// Very minimal IAsyncOperation implementation that gives calling tests control over when it completes
template <typename Logical, typename Abi = Logical>
struct FakeAsyncOperation : Microsoft::WRL::RuntimeClass<
ABI::Windows::Foundation::IAsyncInfo,
ABI::Windows::Foundation::IAsyncOperation<Logical>>
{
using Handler = ABI::Windows::Foundation::IAsyncOperationCompletedHandler<Logical>;
// IAsyncInfo
IFACEMETHODIMP get_Id(unsigned int*) override
{
return E_NOTIMPL;
}
IFACEMETHODIMP get_Status(AsyncStatus* status) override
{
auto lock = m_lock.lock_shared();
*status = m_status;
return S_OK;
}
IFACEMETHODIMP get_ErrorCode(HRESULT* errorCode) override
{
auto lock = m_lock.lock_shared();
*errorCode = m_result;
return S_OK;
}
IFACEMETHODIMP Cancel() override
{
return E_NOTIMPL;
}
IFACEMETHODIMP Close() override
{
return E_NOTIMPL;
}
// IAsyncOperation
IFACEMETHODIMP put_Completed(Handler* handler) override
{
bool invoke = false;
{
auto lock = m_lock.lock_exclusive();
if (m_handler)
{
return E_FAIL;
}
m_handler = handler;
invoke = m_status != ABI::Windows::Foundation::AsyncStatus::Started;
}
if (invoke)
{
handler->Invoke(this, m_status);
}
return S_OK;
}
IFACEMETHODIMP get_Completed(Handler** handler) override
{
auto lock = m_lock.lock_shared();
*handler = Microsoft::WRL::ComPtr<Handler>(m_handler).Detach();
return S_OK;
}
IFACEMETHODIMP GetResults(Abi* results) override
{
return m_storage.CopyTo(results);
}
// Test functions
void Complete(HRESULT hr, Abi result)
{
using namespace ABI::Windows::Foundation;
Handler* handler = nullptr;
{
auto lock = m_lock.lock_exclusive();
if (m_status == AsyncStatus::Started)
{
m_result = hr;
m_storage.Set(result);
m_status = SUCCEEDED(hr) ? AsyncStatus::Completed : AsyncStatus::Error;
handler = m_handler.Get();
}
}
if (handler)
{
handler->Invoke(this, m_status);
}
}
private:
wil::srwlock m_lock;
Microsoft::WRL::ComPtr<Handler> m_handler;
ABI::Windows::Foundation::AsyncStatus m_status = ABI::Windows::Foundation::AsyncStatus::Started;
HRESULT m_result = S_OK;
WinRTStorage<Abi> m_storage;
};
template <typename Logical, typename Abi = Logical, size_t MaxSize = 250>
struct FakeVector : Microsoft::WRL::RuntimeClass<
ABI::Windows::Foundation::Collections::IVector<Logical>,
ABI::Windows::Foundation::Collections::IVectorView<Logical>>
{
// IVector
IFACEMETHODIMP GetAt(unsigned index, Abi* item) override
{
if (index >= m_size)
{
return E_BOUNDS;
}
return m_data[index].CopyTo(item);
}
IFACEMETHODIMP get_Size(unsigned* size) override
{
*size = static_cast<unsigned>(m_size);
return S_OK;
}
IFACEMETHODIMP GetView(ABI::Windows::Foundation::Collections::IVectorView<Logical>** view) override
{
this->AddRef();
*view = this;
return S_OK;
}
IFACEMETHODIMP IndexOf(Abi value, unsigned* index, boolean* found) override
{
for (size_t i = 0; i < m_size; ++i)
{
if (m_data[i].Equals(value))
{
*index = static_cast<unsigned>(i);
*found = true;
return S_OK;
}
}
*index = 0;
*found = false;
return S_OK;
}
IFACEMETHODIMP SetAt(unsigned index, Abi item) override
{
if (index >= m_size)
{
return E_BOUNDS;
}
return m_data[index].Set(item);
}
IFACEMETHODIMP InsertAt(unsigned index, Abi item) override
{
// Insert at the end and swap it into place
if (index > m_size)
{
return E_BOUNDS;
}
auto hr = Append(item);
if (SUCCEEDED(hr))
{
for (size_t i = m_size - 1; i > index; --i)
{
wistd::swap_wil(m_data[i], m_data[i - 1]);
}
}
return hr;
}
IFACEMETHODIMP RemoveAt(unsigned index) override
{
if (index >= m_size)
{
return E_BOUNDS;
}
for (size_t i = index + 1; i < m_size; ++i)
{
wistd::swap_wil(m_data[i], m_data[i - 1]);
}
m_data[--m_size].Reset();
return S_OK;
}
IFACEMETHODIMP Append(Abi item) override
{
if (m_size > MaxSize)
{
return E_OUTOFMEMORY;
}
auto hr = m_data[m_size].Set(item);
if (SUCCEEDED(hr))
{
++m_size;
}
return hr;
}
IFACEMETHODIMP RemoveAtEnd() override
{
if (m_size == 0)
{
return E_BOUNDS;
}
m_data[--m_size].Reset();
return S_OK;
}
IFACEMETHODIMP Clear() override
{
for (size_t i = 0; i < m_size; ++i)
{
m_data[i].Reset();
}
m_size = 0;
return S_OK;
}
IFACEMETHODIMP GetMany(unsigned startIndex, unsigned capacity, Abi* value, unsigned* actual) override
{
*actual = 0;
if (startIndex >= m_size)
{
return S_OK;
}
auto count = m_size - startIndex;
count = (count > capacity) ? capacity : count;
HRESULT hr = S_OK;
unsigned i;
for (i = 0; (i < count) && SUCCEEDED(hr); ++i)
{
hr = m_data[startIndex + i].CopyTo(value + i);
}
if (SUCCEEDED(hr))
{
*actual = static_cast<unsigned>(count);
}
else
{
while (i--)
{
WinRTStorage<Abi>::Destroy(value[i]);
}
}
return hr;
}
IFACEMETHODIMP ReplaceAll(unsigned count, Abi* value) override
{
if (count > MaxSize)
{
return E_OUTOFMEMORY;
}
Clear();
HRESULT hr = S_OK;
for (size_t i = 0; (i < count) && SUCCEEDED(hr); ++i)
{
hr = m_data[i].Set(value[i]);
}
if (FAILED(hr))
{
Clear();
}
return hr;
}
private:
size_t m_size = 0;
WinRTStorage<Abi> m_data[MaxSize];
};