mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-10-28 07:44:06 +01:00
Common (Windows): adds a WinRT helper
This commit is contained in:
@@ -1071,6 +1071,7 @@ elseif(WIN32)
|
|||||||
src/common/windows/registry.c
|
src/common/windows/registry.c
|
||||||
src/common/windows/unicode.c
|
src/common/windows/unicode.c
|
||||||
src/common/windows/variant.cpp
|
src/common/windows/variant.cpp
|
||||||
|
src/common/windows/winrt.cpp
|
||||||
src/common/windows/version.c
|
src/common/windows/version.c
|
||||||
src/detection/battery/battery_windows.c
|
src/detection/battery/battery_windows.c
|
||||||
src/detection/bios/bios_windows.c
|
src/detection/bios/bios_windows.c
|
||||||
|
|||||||
@@ -0,0 +1,322 @@
|
|||||||
|
#include "winrt.hpp"
|
||||||
|
|
||||||
|
#if FF_HAVE_WINRT
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
// A COM vtable is a flat array of function pointers: IUnknown's three methods, IInspectable's three,
|
||||||
|
// then the interface's own methods in declaration order. The pair below writes that array by hand
|
||||||
|
// instead of deriving from winrt::impl::abi<...>.
|
||||||
|
//
|
||||||
|
// Deriving is the idiomatic choice, and it would let the compiler check every slot -- but it cannot
|
||||||
|
// be used here. A class with virtual functions makes clang emit the vtable of its abstract base, and
|
||||||
|
// each pure slot of that table refers to libc++abi's __cxa_pure_virtual. fastfetch is linked by the C
|
||||||
|
// compiler and therefore has neither libc++ nor libc++abi, so that reference would be the only
|
||||||
|
// unresolved symbol in the program. A hand-written table has no virtual functions at all, which
|
||||||
|
// keeps this file as free of the C++ runtime as `media_windows.cpp` is.
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using WinrtIterableAbi = winrt::impl::abi<winrt::Windows::Foundation::Collections::IIterable<winrt::hstring>>::type;
|
||||||
|
|
||||||
|
struct FFWinrtHstringIterable;
|
||||||
|
struct FFWinrtHstringIterator;
|
||||||
|
|
||||||
|
struct FFWinrtHstringIterableVtbl {
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* QueryInterface)(FFWinrtHstringIterable* self, GUID const& riid, void** result);
|
||||||
|
std::uint32_t (STDMETHODCALLTYPE* AddRef)(FFWinrtHstringIterable* self);
|
||||||
|
std::uint32_t (STDMETHODCALLTYPE* Release)(FFWinrtHstringIterable* self);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* GetIids)(FFWinrtHstringIterable* self, std::uint32_t* count, GUID** iids);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* GetRuntimeClassName)(FFWinrtHstringIterable* self, void** name);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* GetTrustLevel)(FFWinrtHstringIterable* self, std::int32_t* level);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* First)(FFWinrtHstringIterable* self, void** result);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFWinrtHstringIteratorVtbl {
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* QueryInterface)(FFWinrtHstringIterator* self, GUID const& riid, void** result);
|
||||||
|
std::uint32_t (STDMETHODCALLTYPE* AddRef)(FFWinrtHstringIterator* self);
|
||||||
|
std::uint32_t (STDMETHODCALLTYPE* Release)(FFWinrtHstringIterator* self);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* GetIids)(FFWinrtHstringIterator* self, std::uint32_t* count, GUID** iids);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* GetRuntimeClassName)(FFWinrtHstringIterator* self, void** name);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* GetTrustLevel)(FFWinrtHstringIterator* self, std::int32_t* level);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* get_Current)(FFWinrtHstringIterator* self, HSTRING* value);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* get_HasCurrent)(FFWinrtHstringIterator* self, bool* value);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* MoveNext)(FFWinrtHstringIterator* self, bool* value);
|
||||||
|
std::int32_t (STDMETHODCALLTYPE* GetMany)(FFWinrtHstringIterator* self, std::uint32_t capacity, HSTRING* values, std::uint32_t* actual);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Everything the pair allocates comes from malloc(), because the placement is driven by the C
|
||||||
|
// allocator rather than by `new` (see the note above).
|
||||||
|
struct FFWinrtHstringIterable {
|
||||||
|
const FFWinrtHstringIterableVtbl* lpVtbl;
|
||||||
|
std::uint32_t refCount;
|
||||||
|
FFlist strings; // HSTRING
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFWinrtHstringIterator {
|
||||||
|
const FFWinrtHstringIteratorVtbl* lpVtbl;
|
||||||
|
std::uint32_t refCount;
|
||||||
|
FFWinrtHstringIterable* owner;
|
||||||
|
std::uint32_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// IIterable<HSTRING>
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterable_QueryInterface(FFWinrtHstringIterable* self, GUID const& riid, void** result) {
|
||||||
|
if (!result) {
|
||||||
|
return E_POINTER;
|
||||||
|
}
|
||||||
|
*result = nullptr;
|
||||||
|
|
||||||
|
if (IsEqualGUID(riid, winrt::guid_of<winrt::Windows::Foundation::IUnknown>()) ||
|
||||||
|
IsEqualGUID(riid, winrt::guid_of<winrt::Windows::Foundation::IInspectable>()) ||
|
||||||
|
IsEqualGUID(riid, winrt::guid_of<winrt::Windows::Foundation::Collections::IIterable<winrt::hstring>>())) {
|
||||||
|
*result = self;
|
||||||
|
self->lpVtbl->AddRef(self);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t STDMETHODCALLTYPE ffWinrtHstringIterable_AddRef(FFWinrtHstringIterable* self) {
|
||||||
|
return ++self->refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t STDMETHODCALLTYPE ffWinrtHstringIterable_Release(FFWinrtHstringIterable* self) {
|
||||||
|
std::uint32_t remaining = --self->refCount;
|
||||||
|
if (remaining == 0) {
|
||||||
|
FF_LIST_FOR_EACH(HSTRING, string, self->strings) {
|
||||||
|
WindowsDeleteString(*string);
|
||||||
|
}
|
||||||
|
ffListDestroy(&self->strings);
|
||||||
|
free(self);
|
||||||
|
}
|
||||||
|
return remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterable_GetIids(FFWinrtHstringIterable* self, std::uint32_t* count, GUID** iids) {
|
||||||
|
(void) self;
|
||||||
|
*count = 0;
|
||||||
|
*iids = nullptr;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterable_GetRuntimeClassName(FFWinrtHstringIterable* self, void** name) {
|
||||||
|
(void) self;
|
||||||
|
*name = nullptr;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `level` is the ABI's 32-bit TrustLevel enum; BaseTrust is 0.
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterable_GetTrustLevel(FFWinrtHstringIterable* self, std::int32_t* level) {
|
||||||
|
(void) self;
|
||||||
|
*level = 0;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterable_First(FFWinrtHstringIterable* self, void** result) {
|
||||||
|
if (!result) {
|
||||||
|
return E_POINTER;
|
||||||
|
}
|
||||||
|
*result = nullptr;
|
||||||
|
|
||||||
|
auto* iterator = (FFWinrtHstringIterator*) malloc(sizeof(FFWinrtHstringIterator));
|
||||||
|
if (!iterator) {
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator->lpVtbl = nullptr; // assigned below, once the table is declared
|
||||||
|
iterator->refCount = 1;
|
||||||
|
iterator->owner = self;
|
||||||
|
iterator->index = 0;
|
||||||
|
|
||||||
|
// The iterator outlives the call that created it, so it holds a reference of its own.
|
||||||
|
self->lpVtbl->AddRef(self);
|
||||||
|
|
||||||
|
extern const FFWinrtHstringIteratorVtbl ffWinrtHstringIteratorVtbl;
|
||||||
|
iterator->lpVtbl = &ffWinrtHstringIteratorVtbl;
|
||||||
|
|
||||||
|
*result = iterator;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FFWinrtHstringIterableVtbl ffWinrtHstringIterableVtbl = {
|
||||||
|
ffWinrtHstringIterable_QueryInterface,
|
||||||
|
ffWinrtHstringIterable_AddRef,
|
||||||
|
ffWinrtHstringIterable_Release,
|
||||||
|
ffWinrtHstringIterable_GetIids,
|
||||||
|
ffWinrtHstringIterable_GetRuntimeClassName,
|
||||||
|
ffWinrtHstringIterable_GetTrustLevel,
|
||||||
|
ffWinrtHstringIterable_First,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// IIterator<HSTRING>
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterator_QueryInterface(FFWinrtHstringIterator* self, GUID const& riid, void** result) {
|
||||||
|
if (!result) {
|
||||||
|
return E_POINTER;
|
||||||
|
}
|
||||||
|
*result = nullptr;
|
||||||
|
|
||||||
|
if (IsEqualGUID(riid, winrt::guid_of<winrt::Windows::Foundation::IUnknown>()) ||
|
||||||
|
IsEqualGUID(riid, winrt::guid_of<winrt::Windows::Foundation::IInspectable>()) ||
|
||||||
|
IsEqualGUID(riid, winrt::guid_of<winrt::Windows::Foundation::Collections::IIterator<winrt::hstring>>())) {
|
||||||
|
*result = self;
|
||||||
|
self->lpVtbl->AddRef(self);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t STDMETHODCALLTYPE ffWinrtHstringIterator_AddRef(FFWinrtHstringIterator* self) {
|
||||||
|
return ++self->refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t STDMETHODCALLTYPE ffWinrtHstringIterator_Release(FFWinrtHstringIterator* self) {
|
||||||
|
std::uint32_t remaining = --self->refCount;
|
||||||
|
if (remaining == 0) {
|
||||||
|
self->owner->lpVtbl->Release(self->owner);
|
||||||
|
free(self);
|
||||||
|
}
|
||||||
|
return remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterator_GetIids(FFWinrtHstringIterator* self, std::uint32_t* count, GUID** iids) {
|
||||||
|
(void) self;
|
||||||
|
*count = 0;
|
||||||
|
*iids = nullptr;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterator_GetRuntimeClassName(FFWinrtHstringIterator* self, void** name) {
|
||||||
|
(void) self;
|
||||||
|
*name = nullptr;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterator_GetTrustLevel(FFWinrtHstringIterator* self, std::int32_t* level) {
|
||||||
|
(void) self;
|
||||||
|
*level = 0;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterator_get_Current(FFWinrtHstringIterator* self, HSTRING* value) {
|
||||||
|
if (!value) {
|
||||||
|
return E_POINTER;
|
||||||
|
}
|
||||||
|
*value = nullptr;
|
||||||
|
|
||||||
|
if (self->index >= self->owner->strings.length) {
|
||||||
|
return E_BOUNDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The caller owns what it gets, so hand out a duplicate rather than the stored string.
|
||||||
|
return WindowsDuplicateString(*(HSTRING*) ffListGet(&self->owner->strings, sizeof(HSTRING), self->index), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterator_get_HasCurrent(FFWinrtHstringIterator* self, bool* value) {
|
||||||
|
if (!value) {
|
||||||
|
return E_POINTER;
|
||||||
|
}
|
||||||
|
*value = self->index < self->owner->strings.length;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterator_MoveNext(FFWinrtHstringIterator* self, bool* value) {
|
||||||
|
if (!value) {
|
||||||
|
return E_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->index < self->owner->strings.length) {
|
||||||
|
++self->index;
|
||||||
|
}
|
||||||
|
*value = self->index < self->owner->strings.length;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t STDMETHODCALLTYPE ffWinrtHstringIterator_GetMany(FFWinrtHstringIterator* self, std::uint32_t capacity, HSTRING* values, std::uint32_t* actual) {
|
||||||
|
if (!actual) {
|
||||||
|
return E_POINTER;
|
||||||
|
}
|
||||||
|
*actual = 0;
|
||||||
|
|
||||||
|
if (capacity && !values) {
|
||||||
|
return E_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t available = self->owner->strings.length - self->index;
|
||||||
|
std::uint32_t taken = capacity < available ? capacity : available;
|
||||||
|
|
||||||
|
for (std::uint32_t i = 0; i < taken; ++i) {
|
||||||
|
WindowsDuplicateString(*(HSTRING*) ffListGet(&self->owner->strings, sizeof(HSTRING), self->index + i), &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->index += taken;
|
||||||
|
*actual = taken;
|
||||||
|
|
||||||
|
return taken == capacity ? S_OK : S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FFWinrtHstringIteratorVtbl ffWinrtHstringIteratorVtbl = {
|
||||||
|
ffWinrtHstringIterator_QueryInterface,
|
||||||
|
ffWinrtHstringIterator_AddRef,
|
||||||
|
ffWinrtHstringIterator_Release,
|
||||||
|
ffWinrtHstringIterator_GetIids,
|
||||||
|
ffWinrtHstringIterator_GetRuntimeClassName,
|
||||||
|
ffWinrtHstringIterator_GetTrustLevel,
|
||||||
|
ffWinrtHstringIterator_get_Current,
|
||||||
|
ffWinrtHstringIterator_get_HasCurrent,
|
||||||
|
ffWinrtHstringIterator_MoveNext,
|
||||||
|
ffWinrtHstringIterator_GetMany,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void ffDeleteHstring(HSTRING* value) {
|
||||||
|
if (*value) {
|
||||||
|
WindowsDeleteString(*value);
|
||||||
|
*value = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ffStrbufSetHstring(FFstrbuf* destination, HSTRING value) {
|
||||||
|
uint32_t length = 0;
|
||||||
|
const wchar_t* raw = WindowsGetStringRawBuffer(value, &length);
|
||||||
|
ffStrbufSetNWS(destination, length, raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT ffWinrtCreateHstringIterable(const wchar_t* const* items, uint32_t count, abi_t<winrt::Windows::Foundation::Collections::IIterable<winrt::hstring>>** result) {
|
||||||
|
*result = nullptr;
|
||||||
|
|
||||||
|
if (count > 0 && !items) {
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* iterable = (FFWinrtHstringIterable*) malloc(sizeof(FFWinrtHstringIterable));
|
||||||
|
if (!iterable) {
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterable->lpVtbl = &ffWinrtHstringIterableVtbl;
|
||||||
|
iterable->refCount = 1;
|
||||||
|
ffListInitA(&iterable->strings, sizeof(HSTRING), count > 0 ? count : FF_LIST_DEFAULT_ALLOC);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
HSTRING* slot = (HSTRING*) ffListAdd(&iterable->strings, sizeof(HSTRING));
|
||||||
|
HRESULT hr = WindowsCreateString(items[i], (UINT32) ::wcslen(items[i]), slot);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
iterable->lpVtbl->Release(iterable);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = reinterpret_cast<WinrtIterableAbi*>(iterable);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FF_HAVE_WINRT
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "common/FFlist.h"
|
||||||
|
#include "common/FFstrbuf.h"
|
||||||
|
#include "common/time.h"
|
||||||
|
#include "common/windows/com.h"
|
||||||
|
#include "common/windows/unicode.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FF_HAVE_WINRT
|
||||||
|
|
||||||
|
#include <roapi.h>
|
||||||
|
#include <winstring.h>
|
||||||
|
#include <asyncinfo.h>
|
||||||
|
|
||||||
|
#include <winrt/base.h>
|
||||||
|
#include <winrt/Windows.Foundation.h>
|
||||||
|
#include <winrt/Windows.Foundation.Collections.h>
|
||||||
|
|
||||||
|
using winrt::impl::abi_t;
|
||||||
|
|
||||||
|
// Frees an HSTRING and clears the pointer, so it can be used with [[gnu::cleanup]].
|
||||||
|
void ffDeleteHstring(HSTRING* value);
|
||||||
|
|
||||||
|
// Copies an HSTRING into an FFstrbuf, transcoding from UTF-16 to UTF-8.
|
||||||
|
void ffStrbufSetHstring(FFstrbuf* destination, HSTRING value);
|
||||||
|
|
||||||
|
// Wraps `items` in an IVector<hstring> and hands out its IIterable<hstring> view, which is the
|
||||||
|
// parameter shape the FindAllAsync overloads taking additional properties expect. The caller owns
|
||||||
|
// the result.
|
||||||
|
HRESULT ffWinrtCreateHstringIterable(const wchar_t* const* items, uint32_t count, abi_t<winrt::Windows::Foundation::Collections::IIterable<winrt::hstring>>** result);
|
||||||
|
|
||||||
|
// RoGetActivationFactory() for a WinRT runtime class.
|
||||||
|
//
|
||||||
|
// `Projection` must be the *projection* type -- e.g.
|
||||||
|
// winrt::Windows::Devices.Bluetooth::IBluetoothLEDeviceStatics -- and never abi_t<...>:
|
||||||
|
// winrt::impl::guid_v is only specialized for projection types, and abi_t<T> expands to
|
||||||
|
// impl::abi<T>::type, which is a non-deduced context.
|
||||||
|
template <typename Projection>
|
||||||
|
static inline HRESULT ffGetActivationFactory(const wchar_t* className, abi_t<Projection>** factory) {
|
||||||
|
HSTRING_HEADER header;
|
||||||
|
HSTRING runtimeClass;
|
||||||
|
HRESULT hr = WindowsCreateStringReference(className, (UINT32) ::wcslen(className), &header, &runtimeClass);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RoGetActivationFactory(runtimeClass, winrt::guid_of<Projection>(), reinterpret_cast<void**>(factory));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TargetProjection, typename SourceAbi>
|
||||||
|
static inline HRESULT ffQueryInterface(SourceAbi* source, abi_t<TargetProjection>** target) {
|
||||||
|
return source->QueryInterface(winrt::guid_of<TargetProjection>(), reinterpret_cast<void**>(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spins until `operation` leaves AsyncStatus::Started, then hands its results to `result`.
|
||||||
|
template <typename TOperationAbi, typename TResultAbi>
|
||||||
|
static HRESULT ffWaitForAsyncOperation(TOperationAbi* operation, TResultAbi** result) {
|
||||||
|
FF_AUTO_RELEASE_COM_OBJECT IAsyncInfo* asyncInfo = nullptr;
|
||||||
|
HRESULT hr = ffQueryInterface<IAsyncInfo>(operation, &asyncInfo);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncStatus status = AsyncStatus::Started;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
hr = asyncInfo->get_Status(&status);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
if (status == AsyncStatus::Started) {
|
||||||
|
ffTimeSleep(0);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != AsyncStatus::Completed) {
|
||||||
|
HRESULT errorCode = E_FAIL;
|
||||||
|
asyncInfo->get_ErrorCode(&errorCode);
|
||||||
|
return FAILED(errorCode) ? errorCode : E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return operation->GetResults((void**) result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TResultProjection, typename TOperation>
|
||||||
|
static HRESULT ffRunAndWait(TOperation&& operation, abi_t<TResultProjection>** result) {
|
||||||
|
FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::Foundation::IAsyncOperation<TResultProjection>>* opResult = nullptr;
|
||||||
|
HRESULT hr = operation(reinterpret_cast<void**>(&opResult));
|
||||||
|
if (FAILED(hr) || !opResult) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ffWaitForAsyncOperation(opResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TResultProjection, typename TOperation>
|
||||||
|
static HRESULT ffRunAndWait2(TOperation&& operation, abi_t<TResultProjection>** result) {
|
||||||
|
*result = nullptr;
|
||||||
|
|
||||||
|
FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::Foundation::IAsyncOperationWithProgress<TResultProjection, int32_t>>* opResult = nullptr;
|
||||||
|
HRESULT hr = operation(reinterpret_cast<void**>(&opResult));
|
||||||
|
if (FAILED(hr) || !opResult) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ffWaitForAsyncOperation(opResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FF_HAVE_WINRT
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error Must be included in C++ source file
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -6,10 +6,9 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if FF_HAVE_WINRT
|
#if FF_HAVE_WINRT
|
||||||
#include <roapi.h>
|
#include "common/windows/winrt.hpp"
|
||||||
|
|
||||||
#include <robuffer.h>
|
#include <robuffer.h>
|
||||||
#include <winstring.h>
|
|
||||||
#include <asyncinfo.h>
|
|
||||||
|
|
||||||
#include <shobjidl.h>
|
#include <shobjidl.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
@@ -21,94 +20,6 @@ extern "C" {
|
|||||||
#include <winrt/Windows.Media.Control.h>
|
#include <winrt/Windows.Media.Control.h>
|
||||||
#include <winrt/Windows.Storage.Streams.h>
|
#include <winrt/Windows.Storage.Streams.h>
|
||||||
|
|
||||||
using winrt::impl::abi_t;
|
|
||||||
using winrt::Windows::Foundation::IAsyncOperation;
|
|
||||||
using winrt::Windows::Foundation::IAsyncOperationWithProgress;
|
|
||||||
|
|
||||||
static inline void deleteHstring(HSTRING* pstr) {
|
|
||||||
if (*pstr) {
|
|
||||||
WindowsDeleteString(*pstr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ffStrbufSetHstring(FFstrbuf* destination, HSTRING value) {
|
|
||||||
uint32_t length;
|
|
||||||
const wchar_t* raw = WindowsGetStringRawBuffer(value, &length);
|
|
||||||
ffStrbufSetNWS(destination, length, raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Interface>
|
|
||||||
static inline HRESULT ffGetActivationFactory(const wchar_t* className, REFIID iid, Interface** factory) {
|
|
||||||
HSTRING_HEADER header;
|
|
||||||
HSTRING runtimeClass;
|
|
||||||
HRESULT hr = WindowsCreateStringReference(className, (UINT32)::wcslen(className), &header, &runtimeClass);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RoGetActivationFactory(runtimeClass, iid, reinterpret_cast<void**>(factory));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TargetProjection, typename SourceAbi>
|
|
||||||
static inline HRESULT ffQueryInterface(SourceAbi* source, abi_t<TargetProjection>** target) {
|
|
||||||
return source->QueryInterface(winrt::guid_of<TargetProjection>(), reinterpret_cast<void**>(target));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TOperationAbi, typename TResultAbi>
|
|
||||||
static HRESULT ffWaitForAsyncOperation(TOperationAbi* operation, TResultAbi** result) {
|
|
||||||
FF_AUTO_RELEASE_COM_OBJECT IAsyncInfo* asyncInfo = nullptr;
|
|
||||||
HRESULT hr = ffQueryInterface<IAsyncInfo>(operation, &asyncInfo);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncStatus status = AsyncStatus::Started;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
hr = asyncInfo->get_Status(&status);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
if (status == AsyncStatus::Started) {
|
|
||||||
ffTimeSleep(0);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != AsyncStatus::Completed) {
|
|
||||||
HRESULT errorCode = E_FAIL;
|
|
||||||
asyncInfo->get_ErrorCode(&errorCode);
|
|
||||||
return FAILED(errorCode) ? errorCode : E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return operation->GetResults((void**) result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TResultProjection, typename TOperation>
|
|
||||||
static HRESULT ffRunAndWait(TOperation&& operation, abi_t<TResultProjection>** result) {
|
|
||||||
FF_AUTO_RELEASE_COM_OBJECT abi_t<IAsyncOperation<TResultProjection>>* opResult = nullptr;
|
|
||||||
HRESULT hr = operation(reinterpret_cast<void**>(&opResult));
|
|
||||||
if (FAILED(hr) || !opResult) {
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ffWaitForAsyncOperation(opResult, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TResultProjection, typename TOperation>
|
|
||||||
static HRESULT ffRunAndWait2(TOperation&& operation, abi_t<TResultProjection>** result) {
|
|
||||||
*result = nullptr;
|
|
||||||
|
|
||||||
FF_AUTO_RELEASE_COM_OBJECT abi_t<IAsyncOperationWithProgress<TResultProjection, int32_t>>* opResult = nullptr;
|
|
||||||
HRESULT hr = operation(reinterpret_cast<void**>(&opResult));
|
|
||||||
if (FAILED(hr) || !opResult) {
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ffWaitForAsyncOperation(opResult, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT ffSaveThumbnailToTempPath(
|
static HRESULT ffSaveThumbnailToTempPath(
|
||||||
abi_t<winrt::Windows::Storage::Streams::IRandomAccessStreamReference>* thumbnail,
|
abi_t<winrt::Windows::Storage::Streams::IRandomAccessStreamReference>* thumbnail,
|
||||||
FFstrbuf* destination) {
|
FFstrbuf* destination) {
|
||||||
@@ -138,7 +49,7 @@ static HRESULT ffSaveThumbnailToTempPath(
|
|||||||
}
|
}
|
||||||
|
|
||||||
FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::Storage::Streams::IBufferFactory>* bufferFactory = nullptr;
|
FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::Storage::Streams::IBufferFactory>* bufferFactory = nullptr;
|
||||||
hr = ffGetActivationFactory(L"Windows.Storage.Streams.Buffer", winrt::guid_of<winrt::Windows::Storage::Streams::IBufferFactory>(), &bufferFactory);
|
hr = ffGetActivationFactory<winrt::Windows::Storage::Streams::IBufferFactory>(L"Windows.Storage.Streams.Buffer", &bufferFactory);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
@@ -223,7 +134,7 @@ static HRESULT ffSaveThumbnailToTempPath(
|
|||||||
// are actually packaged -- the caller gates it, see `resolveAppUserModelId`.
|
// are actually packaged -- the caller gates it, see `resolveAppUserModelId`.
|
||||||
static bool resolvePackagedAppUserModelId(const wchar_t* aumid, FFstrbuf* result) {
|
static bool resolvePackagedAppUserModelId(const wchar_t* aumid, FFstrbuf* result) {
|
||||||
FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::ApplicationModel::IAppInfoStatics>* statics = nullptr;
|
FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::ApplicationModel::IAppInfoStatics>* statics = nullptr;
|
||||||
if (FAILED(ffGetActivationFactory(L"Windows.ApplicationModel.AppInfo", winrt::guid_of<winrt::Windows::ApplicationModel::IAppInfoStatics>(), &statics)) || !statics) {
|
if (FAILED(ffGetActivationFactory<winrt::Windows::ApplicationModel::IAppInfoStatics>(L"Windows.ApplicationModel.AppInfo", &statics)) || !statics) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +154,7 @@ static bool resolvePackagedAppUserModelId(const wchar_t* aumid, FFstrbuf* result
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[gnu::cleanup(deleteHstring)]] HSTRING displayName = nullptr;
|
[[gnu::cleanup(ffDeleteHstring)]] HSTRING displayName = nullptr;
|
||||||
if (FAILED(displayInfo->get_DisplayName(reinterpret_cast<void**>(&displayName))) || !displayName) {
|
if (FAILED(displayInfo->get_DisplayName(reinterpret_cast<void**>(&displayName))) || !displayName) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -316,7 +227,7 @@ static const char* getMedia(FFMediaResult* result, bool saveCover) {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManagerStatics>* managerStatics = nullptr;
|
FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManagerStatics>* managerStatics = nullptr;
|
||||||
HRESULT hr = ffGetActivationFactory(L"Windows.Media.Control.GlobalSystemMediaTransportControlsSessionManager", winrt::guid_of<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManagerStatics>(), &managerStatics);
|
HRESULT hr = ffGetActivationFactory<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManagerStatics>(L"Windows.Media.Control.GlobalSystemMediaTransportControlsSessionManager", &managerStatics);
|
||||||
if (FAILED(hr) || !managerStatics) {
|
if (FAILED(hr) || !managerStatics) {
|
||||||
error = "winrt: RoGetActivationFactory(GlobalSystemMediaTransportControlsSessionManager) failed";
|
error = "winrt: RoGetActivationFactory(GlobalSystemMediaTransportControlsSessionManager) failed";
|
||||||
break;
|
break;
|
||||||
@@ -332,7 +243,7 @@ static const char* getMedia(FFMediaResult* result, bool saveCover) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[gnu::cleanup(deleteHstring)]] HSTRING playerId = nullptr;
|
[[gnu::cleanup(ffDeleteHstring)]] HSTRING playerId = nullptr;
|
||||||
|
|
||||||
FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSession>* session = nullptr;
|
FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSession>* session = nullptr;
|
||||||
if (instance.config.general.playerName.length) {
|
if (instance.config.general.playerName.length) {
|
||||||
@@ -367,7 +278,7 @@ static const char* getMedia(FFMediaResult* result, bool saveCover) {
|
|||||||
currentSession = nullptr; // Don't release the session object
|
currentSession = nullptr; // Don't release the session object
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
deleteHstring(&playerId);
|
ffDeleteHstring(&playerId);
|
||||||
ffStrbufClear(&result->playerId);
|
ffStrbufClear(&result->playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,17 +344,17 @@ static const char* getMedia(FFMediaResult* result, bool saveCover) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[gnu::cleanup(deleteHstring)]] HSTRING title = nullptr;
|
[[gnu::cleanup(ffDeleteHstring)]] HSTRING title = nullptr;
|
||||||
if (SUCCEEDED(mediaProps->get_Title(reinterpret_cast<void**>(&title)))) {
|
if (SUCCEEDED(mediaProps->get_Title(reinterpret_cast<void**>(&title)))) {
|
||||||
ffStrbufSetHstring(&result->song, title);
|
ffStrbufSetHstring(&result->song, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[gnu::cleanup(deleteHstring)]] HSTRING artist = nullptr;
|
[[gnu::cleanup(ffDeleteHstring)]] HSTRING artist = nullptr;
|
||||||
if (SUCCEEDED(mediaProps->get_Artist(reinterpret_cast<void**>(&artist)))) {
|
if (SUCCEEDED(mediaProps->get_Artist(reinterpret_cast<void**>(&artist)))) {
|
||||||
ffStrbufSetHstring(&result->artist, artist);
|
ffStrbufSetHstring(&result->artist, artist);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[gnu::cleanup(deleteHstring)]] HSTRING album = nullptr;
|
[[gnu::cleanup(ffDeleteHstring)]] HSTRING album = nullptr;
|
||||||
if (SUCCEEDED(mediaProps->get_AlbumTitle(reinterpret_cast<void**>(&album)))) {
|
if (SUCCEEDED(mediaProps->get_AlbumTitle(reinterpret_cast<void**>(&album)))) {
|
||||||
ffStrbufSetHstring(&result->album, album);
|
ffStrbufSetHstring(&result->album, album);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user