Initial QSfera import
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// global compilation flag configuring windows sdk headers
|
||||
// preventing inclusion of min and max macros clashing with <limits>
|
||||
#define NOMINMAX 1
|
||||
|
||||
// override byte to prevent clashes with <cstddef>
|
||||
#define byte win_byte_override
|
||||
|
||||
#include <Windows.h> // gdi plus requires Windows.h
|
||||
// ...includes for other windows header that may use byte...
|
||||
|
||||
// Define min max macros required by GDI+ headers.
|
||||
#ifndef max
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#else
|
||||
#error max macro is already defined
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#else
|
||||
#error min macro is already defined
|
||||
#endif
|
||||
|
||||
#include <gdiplus.h>
|
||||
|
||||
// Undefine min max macros so they won't collide with <limits> header content.
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
// Undefine byte macros so it won't collide with <cstddef> header content.
|
||||
#undef byte
|
||||
|
||||
#include "thumbnailprovider.h"
|
||||
#include <QSize>
|
||||
#include <shlwapi.h>
|
||||
#include <vector>
|
||||
|
||||
extern long dllObjectsCount;
|
||||
|
||||
namespace VfsShellExtensions {
|
||||
|
||||
std::pair<HBITMAP, WTS_ALPHATYPE> hBitmapAndAlphaTypeFromData(const QByteArray &thumbnailData)
|
||||
{
|
||||
if (thumbnailData.isEmpty()) {
|
||||
return {NULL, WTSAT_UNKNOWN};
|
||||
}
|
||||
|
||||
Gdiplus::Bitmap *gdiPlusBitmap = nullptr;
|
||||
ULONG_PTR gdiPlusToken;
|
||||
Gdiplus::GdiplusStartupInput gdiPlusStartupInput;
|
||||
if (Gdiplus::GdiplusStartup(&gdiPlusToken, &gdiPlusStartupInput, nullptr) != Gdiplus::Status::Ok) {
|
||||
return {NULL, WTSAT_UNKNOWN};
|
||||
}
|
||||
|
||||
const auto handleFailure = [gdiPlusToken]() -> std::pair<HBITMAP, WTS_ALPHATYPE> {
|
||||
Gdiplus::GdiplusShutdown(gdiPlusToken);
|
||||
return {NULL, WTSAT_UNKNOWN};
|
||||
};
|
||||
|
||||
const std::vector<unsigned char> bitmapData(thumbnailData.begin(), thumbnailData.end());
|
||||
auto const stream{::SHCreateMemStream(&bitmapData[0], static_cast<UINT>(bitmapData.size()))};
|
||||
|
||||
if (!stream) {
|
||||
return handleFailure();
|
||||
}
|
||||
gdiPlusBitmap = Gdiplus::Bitmap::FromStream(stream);
|
||||
|
||||
auto hasAlpha = false;
|
||||
HBITMAP hBitmap = NULL;
|
||||
if (gdiPlusBitmap) {
|
||||
hasAlpha = Gdiplus::IsAlphaPixelFormat(gdiPlusBitmap->GetPixelFormat());
|
||||
if (gdiPlusBitmap->GetHBITMAP(Gdiplus::Color(0, 0, 0), &hBitmap) != Gdiplus::Status::Ok) {
|
||||
return handleFailure();
|
||||
}
|
||||
}
|
||||
|
||||
Gdiplus::GdiplusShutdown(gdiPlusToken);
|
||||
|
||||
return {hBitmap, hasAlpha ? WTSAT_ARGB : WTSAT_RGB};
|
||||
}
|
||||
|
||||
ThumbnailProvider::ThumbnailProvider()
|
||||
: _referenceCount(1)
|
||||
{
|
||||
InterlockedIncrement(&dllObjectsCount);
|
||||
}
|
||||
|
||||
ThumbnailProvider::~ThumbnailProvider()
|
||||
{
|
||||
InterlockedDecrement(&dllObjectsCount);
|
||||
}
|
||||
IFACEMETHODIMP ThumbnailProvider::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(ThumbnailProvider, IInitializeWithItem),
|
||||
QITABENT(ThumbnailProvider, IThumbnailProvider),
|
||||
{0},
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) ThumbnailProvider::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&_referenceCount);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) ThumbnailProvider::Release()
|
||||
{
|
||||
const auto refCount = InterlockedDecrement(&_referenceCount);
|
||||
if (refCount == 0) {
|
||||
delete this;
|
||||
}
|
||||
return refCount;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ThumbnailProvider::Initialize(_In_ IShellItem *item, _In_ DWORD mode)
|
||||
{
|
||||
HRESULT hresult = item->QueryInterface(__uuidof(_shellItem), reinterpret_cast<void **>(&_shellItem));
|
||||
if (FAILED(hresult)) {
|
||||
return hresult;
|
||||
}
|
||||
|
||||
LPWSTR pszName = NULL;
|
||||
hresult = _shellItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName);
|
||||
if (FAILED(hresult)) {
|
||||
return hresult;
|
||||
}
|
||||
|
||||
_shellItemPath = QString::fromWCharArray(pszName);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ThumbnailProvider::GetThumbnail(_In_ UINT cx, _Out_ HBITMAP *bitmap, _Out_ WTS_ALPHATYPE *alphaType)
|
||||
{
|
||||
*bitmap = nullptr;
|
||||
*alphaType = WTSAT_UNKNOWN;
|
||||
|
||||
const auto thumbnailDataReceived = _thumbnailProviderIpc.fetchThumbnailForFile(_shellItemPath, QSize(cx, cx));
|
||||
|
||||
if (thumbnailDataReceived.isEmpty()) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
const auto bitmapAndAlphaType = hBitmapAndAlphaTypeFromData(thumbnailDataReceived);
|
||||
if (!bitmapAndAlphaType.first) {
|
||||
return E_FAIL;
|
||||
}
|
||||
*bitmap = bitmapAndAlphaType.first;
|
||||
*alphaType = bitmapAndAlphaType.second;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user