Cleanup: clang-format
This commit is contained in:
parent
6c16c2c233
commit
6726e98fe2
Notes:
blender-bot
2023-02-14 07:25:46 +01:00
Referenced by issue #69372, blender 2.8 crashes when zooming out in "Animation -> Graph Editor" window. Referenced by issue #69339, Surface Deform Modifier is Not Binding or Updating Referenced by issue #69346, Undo doesn't work with paint mask selection (texture paint vs. vertex/weightpaint)
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
#include <shlwapi.h>
|
||||
#include <thumbcache.h> // For IThumbnailProvider.
|
||||
#include <thumbcache.h> // For IThumbnailProvider.
|
||||
#include <new>
|
||||
|
||||
#pragma comment(lib, "shlwapi.lib")
|
||||
|
@ -23,298 +23,291 @@
|
|||
// this thumbnail provider implements IInitializeWithStream to enable being hosted
|
||||
// in an isolated process for robustness
|
||||
|
||||
class CBlendThumb : public IInitializeWithStream, public IThumbnailProvider
|
||||
{
|
||||
public:
|
||||
CBlendThumb() : _cRef(1), _pStream(NULL) {}
|
||||
class CBlendThumb : public IInitializeWithStream, public IThumbnailProvider {
|
||||
public:
|
||||
CBlendThumb() : _cRef(1), _pStream(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CBlendThumb()
|
||||
{
|
||||
if (_pStream)
|
||||
{
|
||||
_pStream->Release();
|
||||
}
|
||||
}
|
||||
virtual ~CBlendThumb()
|
||||
{
|
||||
if (_pStream) {
|
||||
_pStream->Release();
|
||||
}
|
||||
}
|
||||
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
static const QITAB qit[] =
|
||||
{
|
||||
QITABENT(CBlendThumb, IInitializeWithStream),
|
||||
QITABENT(CBlendThumb, IThumbnailProvider),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(CBlendThumb, IInitializeWithStream),
|
||||
QITABENT(CBlendThumb, IThumbnailProvider),
|
||||
{0},
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&_cRef);
|
||||
}
|
||||
IFACEMETHODIMP_(ULONG) AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&_cRef);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) Release()
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&_cRef);
|
||||
if (!cRef)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
return cRef;
|
||||
}
|
||||
IFACEMETHODIMP_(ULONG) Release()
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&_cRef);
|
||||
if (!cRef) {
|
||||
delete this;
|
||||
}
|
||||
return cRef;
|
||||
}
|
||||
|
||||
// IInitializeWithStream
|
||||
IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode);
|
||||
// IInitializeWithStream
|
||||
IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode);
|
||||
|
||||
// IThumbnailProvider
|
||||
IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
|
||||
// IThumbnailProvider
|
||||
IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
|
||||
|
||||
private:
|
||||
long _cRef;
|
||||
IStream *_pStream; // provided during initialization.
|
||||
private:
|
||||
long _cRef;
|
||||
IStream *_pStream; // provided during initialization.
|
||||
};
|
||||
|
||||
HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv)
|
||||
{
|
||||
CBlendThumb *pNew = new (std::nothrow) CBlendThumb();
|
||||
HRESULT hr = pNew ? S_OK : E_OUTOFMEMORY;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pNew->QueryInterface(riid, ppv);
|
||||
pNew->Release();
|
||||
}
|
||||
return hr;
|
||||
CBlendThumb *pNew = new (std::nothrow) CBlendThumb();
|
||||
HRESULT hr = pNew ? S_OK : E_OUTOFMEMORY;
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = pNew->QueryInterface(riid, ppv);
|
||||
pNew->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
// IInitializeWithStream
|
||||
IFACEMETHODIMP CBlendThumb::Initialize(IStream *pStream, DWORD)
|
||||
{
|
||||
HRESULT hr = E_UNEXPECTED; // can only be inited once
|
||||
if (_pStream == NULL)
|
||||
{
|
||||
// take a reference to the stream if we have not been inited yet
|
||||
hr = pStream->QueryInterface(&_pStream);
|
||||
}
|
||||
return hr;
|
||||
HRESULT hr = E_UNEXPECTED; // can only be inited once
|
||||
if (_pStream == NULL) {
|
||||
// take a reference to the stream if we have not been inited yet
|
||||
hr = pStream->QueryInterface(&_pStream);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
#include <math.h>
|
||||
#include <zlib.h>
|
||||
#include "Wincodec.h"
|
||||
const unsigned char gzip_magic[3] = { 0x1f, 0x8b, 0x08 };
|
||||
const unsigned char gzip_magic[3] = {0x1f, 0x8b, 0x08};
|
||||
|
||||
// IThumbnailProvider
|
||||
IFACEMETHODIMP CBlendThumb::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha)
|
||||
{
|
||||
ULONG BytesRead;
|
||||
HRESULT hr = S_FALSE;
|
||||
LARGE_INTEGER SeekPos;
|
||||
ULONG BytesRead;
|
||||
HRESULT hr = S_FALSE;
|
||||
LARGE_INTEGER SeekPos;
|
||||
|
||||
// Compressed?
|
||||
unsigned char in_magic[3];
|
||||
_pStream->Read(&in_magic,3,&BytesRead);
|
||||
bool gzipped = true;
|
||||
for ( int i=0; i < 3; i++ )
|
||||
if ( in_magic[i] != gzip_magic[i] )
|
||||
{
|
||||
gzipped = false;
|
||||
break;
|
||||
}
|
||||
// Compressed?
|
||||
unsigned char in_magic[3];
|
||||
_pStream->Read(&in_magic, 3, &BytesRead);
|
||||
bool gzipped = true;
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (in_magic[i] != gzip_magic[i]) {
|
||||
gzipped = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gzipped)
|
||||
{
|
||||
// Zlib inflate
|
||||
z_stream stream;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
if (gzipped) {
|
||||
// Zlib inflate
|
||||
z_stream stream;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
|
||||
// Get compressed file length
|
||||
SeekPos.QuadPart = 0;
|
||||
_pStream->Seek(SeekPos,STREAM_SEEK_END,NULL);
|
||||
// Get compressed file length
|
||||
SeekPos.QuadPart = 0;
|
||||
_pStream->Seek(SeekPos, STREAM_SEEK_END, NULL);
|
||||
|
||||
// Get compressed and uncompressed size
|
||||
uLong source_size;
|
||||
uLongf dest_size;
|
||||
//SeekPos.QuadPart = -4; // last 4 bytes define size of uncompressed file
|
||||
//ULARGE_INTEGER Tell;
|
||||
//_pStream->Seek(SeekPos,STREAM_SEEK_END,&Tell);
|
||||
//source_size = (uLong)Tell.QuadPart + 4; // src
|
||||
//_pStream->Read(&dest_size,4,&BytesRead); // dest
|
||||
dest_size = 1024*70; // thumbnail is currently always inside the first 65KB...if it moves or enlargens this line will have to change or go!
|
||||
source_size = (uLong)max(SeekPos.QuadPart,dest_size); // for safety, assume no compression
|
||||
|
||||
// Input
|
||||
Bytef* src = new Bytef[source_size];
|
||||
stream.next_in = (Bytef*)src;
|
||||
stream.avail_in = (uInt)source_size;
|
||||
|
||||
// Output
|
||||
Bytef* dest = new Bytef[dest_size];
|
||||
stream.next_out = (Bytef*)dest;
|
||||
stream.avail_out = dest_size;
|
||||
// Get compressed and uncompressed size
|
||||
uLong source_size;
|
||||
uLongf dest_size;
|
||||
// SeekPos.QuadPart = -4; // last 4 bytes define size of uncompressed file
|
||||
// ULARGE_INTEGER Tell;
|
||||
//_pStream->Seek(SeekPos,STREAM_SEEK_END,&Tell);
|
||||
// source_size = (uLong)Tell.QuadPart + 4; // src
|
||||
//_pStream->Read(&dest_size,4,&BytesRead); // dest
|
||||
dest_size = 1024 * 70; // thumbnail is currently always inside the first 65KB...if it moves or
|
||||
// enlargens this line will have to change or go!
|
||||
source_size = (uLong)max(SeekPos.QuadPart, dest_size); // for safety, assume no compression
|
||||
|
||||
// IStream to src
|
||||
SeekPos.QuadPart = 0;
|
||||
_pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
|
||||
_pStream->Read(src,source_size,&BytesRead);
|
||||
|
||||
// Do the inflation
|
||||
int err;
|
||||
err = inflateInit2(&stream,16); // 16 means "gzip"...nice!
|
||||
err = inflate(&stream, Z_FINISH);
|
||||
err = inflateEnd(&stream);
|
||||
|
||||
// Replace the IStream, which is read-only
|
||||
_pStream->Release();
|
||||
_pStream = SHCreateMemStream(dest,dest_size);
|
||||
|
||||
delete[] src;
|
||||
delete[] dest;
|
||||
}
|
||||
// Input
|
||||
Bytef *src = new Bytef[source_size];
|
||||
stream.next_in = (Bytef *)src;
|
||||
stream.avail_in = (uInt)source_size;
|
||||
|
||||
// Blender version, early out if sub 2.5
|
||||
SeekPos.QuadPart = 9;
|
||||
_pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
|
||||
char version[4];
|
||||
version[3] = '\0';
|
||||
_pStream->Read(&version,3,&BytesRead);
|
||||
if ( BytesRead != 3)
|
||||
return E_UNEXPECTED;
|
||||
int iVersion = atoi(version);
|
||||
if ( iVersion < 250 )
|
||||
return S_FALSE;
|
||||
|
||||
// 32 or 64 bit blend?
|
||||
SeekPos.QuadPart = 7;
|
||||
_pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
|
||||
// Output
|
||||
Bytef *dest = new Bytef[dest_size];
|
||||
stream.next_out = (Bytef *)dest;
|
||||
stream.avail_out = dest_size;
|
||||
|
||||
char _PointerSize;
|
||||
_pStream->Read(&_PointerSize,1,&BytesRead);
|
||||
// IStream to src
|
||||
SeekPos.QuadPart = 0;
|
||||
_pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
|
||||
_pStream->Read(src, source_size, &BytesRead);
|
||||
|
||||
int PointerSize = _PointerSize == '_' ? 4 : 8;
|
||||
int HeaderSize = 16 + PointerSize;
|
||||
// Do the inflation
|
||||
int err;
|
||||
err = inflateInit2(&stream, 16); // 16 means "gzip"...nice!
|
||||
err = inflate(&stream, Z_FINISH);
|
||||
err = inflateEnd(&stream);
|
||||
|
||||
// Find and read thumbnail ("TEST") block
|
||||
SeekPos.QuadPart = 12;
|
||||
_pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
|
||||
int BlockOffset = 12;
|
||||
while ( _pStream )
|
||||
{
|
||||
// Scan current block
|
||||
char BlockName[5];
|
||||
BlockName[4] = '\0';
|
||||
int BlockSize = 0;
|
||||
// Replace the IStream, which is read-only
|
||||
_pStream->Release();
|
||||
_pStream = SHCreateMemStream(dest, dest_size);
|
||||
|
||||
if (_pStream->Read(BlockName,4,&BytesRead) == S_OK && _pStream->Read((void*)&BlockSize,4,&BytesRead) == S_OK)
|
||||
{
|
||||
if ( strcmp (BlockName,"TEST") != 0 )
|
||||
{
|
||||
SeekPos.QuadPart = BlockOffset += HeaderSize + BlockSize;
|
||||
_pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else break; // eof
|
||||
delete[] src;
|
||||
delete[] dest;
|
||||
}
|
||||
|
||||
// Found the block
|
||||
SeekPos.QuadPart = BlockOffset + HeaderSize;
|
||||
_pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
|
||||
// Blender version, early out if sub 2.5
|
||||
SeekPos.QuadPart = 9;
|
||||
_pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
|
||||
char version[4];
|
||||
version[3] = '\0';
|
||||
_pStream->Read(&version, 3, &BytesRead);
|
||||
if (BytesRead != 3)
|
||||
return E_UNEXPECTED;
|
||||
int iVersion = atoi(version);
|
||||
if (iVersion < 250)
|
||||
return S_FALSE;
|
||||
|
||||
int width, height;
|
||||
_pStream->Read((char*)&width,4,&BytesRead);
|
||||
_pStream->Read((char*)&height,4,&BytesRead);
|
||||
BlockSize -= 8;
|
||||
// 32 or 64 bit blend?
|
||||
SeekPos.QuadPart = 7;
|
||||
_pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
|
||||
|
||||
// Isolate RGBA data
|
||||
char* pRGBA = new char[BlockSize];
|
||||
_pStream->Read(pRGBA,BlockSize,&BytesRead);
|
||||
char _PointerSize;
|
||||
_pStream->Read(&_PointerSize, 1, &BytesRead);
|
||||
|
||||
if (BytesRead != (ULONG)BlockSize)
|
||||
return E_UNEXPECTED;
|
||||
int PointerSize = _PointerSize == '_' ? 4 : 8;
|
||||
int HeaderSize = 16 + PointerSize;
|
||||
|
||||
// Convert to BGRA for Windows
|
||||
for (int i=0; i < BlockSize; i+=4 )
|
||||
{
|
||||
#define RED_BYTE pRGBA[i]
|
||||
#define BLUE_BYTE pRGBA[i+2]
|
||||
// Find and read thumbnail ("TEST") block
|
||||
SeekPos.QuadPart = 12;
|
||||
_pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
|
||||
int BlockOffset = 12;
|
||||
while (_pStream) {
|
||||
// Scan current block
|
||||
char BlockName[5];
|
||||
BlockName[4] = '\0';
|
||||
int BlockSize = 0;
|
||||
|
||||
char red = RED_BYTE;
|
||||
RED_BYTE = BLUE_BYTE;
|
||||
BLUE_BYTE = red;
|
||||
}
|
||||
|
||||
// Flip vertically (Blender stores it upside-down)
|
||||
unsigned int LineSize = width*4;
|
||||
char* FlippedImage = new char[BlockSize];
|
||||
for (int i=0; i<height; i++)
|
||||
{
|
||||
if ( 0 != memcpy_s(&FlippedImage[ (height - i - 1)*LineSize ],LineSize,&pRGBA[ i*LineSize ],LineSize))
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
delete[] pRGBA;
|
||||
pRGBA = FlippedImage;
|
||||
if (_pStream->Read(BlockName, 4, &BytesRead) == S_OK &&
|
||||
_pStream->Read((void *)&BlockSize, 4, &BytesRead) == S_OK) {
|
||||
if (strcmp(BlockName, "TEST") != 0) {
|
||||
SeekPos.QuadPart = BlockOffset += HeaderSize + BlockSize;
|
||||
_pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
break; // eof
|
||||
|
||||
// Create image
|
||||
*phbmp = CreateBitmap(width,height,1,32,pRGBA);
|
||||
if (!*phbmp)
|
||||
return E_FAIL;
|
||||
*pdwAlpha = WTSAT_ARGB; // it's actually BGRA, not sure why this works
|
||||
// Found the block
|
||||
SeekPos.QuadPart = BlockOffset + HeaderSize;
|
||||
_pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
|
||||
|
||||
// Scale down if required
|
||||
if ( (unsigned)width > cx || (unsigned)height > cx )
|
||||
{
|
||||
float scale = 1.0f / (max(width,height) / (float)cx);
|
||||
LONG NewWidth = (LONG)(width *scale);
|
||||
LONG NewHeight = (LONG)(height *scale);
|
||||
int width, height;
|
||||
_pStream->Read((char *)&width, 4, &BytesRead);
|
||||
_pStream->Read((char *)&height, 4, &BytesRead);
|
||||
BlockSize -= 8;
|
||||
|
||||
// Isolate RGBA data
|
||||
char *pRGBA = new char[BlockSize];
|
||||
_pStream->Read(pRGBA, BlockSize, &BytesRead);
|
||||
|
||||
if (BytesRead != (ULONG)BlockSize)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
// Convert to BGRA for Windows
|
||||
for (int i = 0; i < BlockSize; i += 4) {
|
||||
#define RED_BYTE pRGBA[i]
|
||||
#define BLUE_BYTE pRGBA[i + 2]
|
||||
|
||||
char red = RED_BYTE;
|
||||
RED_BYTE = BLUE_BYTE;
|
||||
BLUE_BYTE = red;
|
||||
}
|
||||
|
||||
// Flip vertically (Blender stores it upside-down)
|
||||
unsigned int LineSize = width * 4;
|
||||
char *FlippedImage = new char[BlockSize];
|
||||
for (int i = 0; i < height; i++) {
|
||||
if (0 != memcpy_s(&FlippedImage[(height - i - 1) * LineSize],
|
||||
LineSize,
|
||||
&pRGBA[i * LineSize],
|
||||
LineSize))
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
delete[] pRGBA;
|
||||
pRGBA = FlippedImage;
|
||||
|
||||
// Create image
|
||||
*phbmp = CreateBitmap(width, height, 1, 32, pRGBA);
|
||||
if (!*phbmp)
|
||||
return E_FAIL;
|
||||
*pdwAlpha = WTSAT_ARGB; // it's actually BGRA, not sure why this works
|
||||
|
||||
// Scale down if required
|
||||
if ((unsigned)width > cx || (unsigned)height > cx) {
|
||||
float scale = 1.0f / (max(width, height) / (float)cx);
|
||||
LONG NewWidth = (LONG)(width * scale);
|
||||
LONG NewHeight = (LONG)(height * scale);
|
||||
|
||||
#ifdef _DEBUG
|
||||
#if 0
|
||||
# if 0
|
||||
MessageBox(0,"Attach now","Debugging",MB_OK);
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
IWICImagingFactory *pImgFac;
|
||||
hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImgFac));
|
||||
|
||||
IWICBitmap* WICBmp;
|
||||
hr = pImgFac->CreateBitmapFromHBITMAP(*phbmp,0,WICBitmapUseAlpha,&WICBmp);
|
||||
|
||||
BITMAPINFO bmi = {};
|
||||
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
||||
bmi.bmiHeader.biWidth = NewWidth;
|
||||
bmi.bmiHeader.biHeight = -NewHeight;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
IWICImagingFactory *pImgFac;
|
||||
hr = CoCreateInstance(
|
||||
CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImgFac));
|
||||
|
||||
BYTE *pBits;
|
||||
HBITMAP ResizedHBmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pBits, NULL, 0);
|
||||
hr = ResizedHBmp ? S_OK : E_OUTOFMEMORY;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IWICBitmapScaler* pIScaler;
|
||||
hr = pImgFac->CreateBitmapScaler(&pIScaler);
|
||||
hr = pIScaler->Initialize(WICBmp,NewWidth,NewHeight,WICBitmapInterpolationModeFant);
|
||||
|
||||
WICRect rect = {0, 0, NewWidth, NewHeight};
|
||||
hr = pIScaler->CopyPixels(&rect, NewWidth * 4, NewWidth * NewHeight * 4, pBits);
|
||||
IWICBitmap *WICBmp;
|
||||
hr = pImgFac->CreateBitmapFromHBITMAP(*phbmp, 0, WICBitmapUseAlpha, &WICBmp);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
DeleteObject(*phbmp);
|
||||
*phbmp = ResizedHBmp;
|
||||
}
|
||||
else
|
||||
DeleteObject(ResizedHBmp);
|
||||
BITMAPINFO bmi = {};
|
||||
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
||||
bmi.bmiHeader.biWidth = NewWidth;
|
||||
bmi.bmiHeader.biHeight = -NewHeight;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
pIScaler->Release();
|
||||
}
|
||||
WICBmp->Release();
|
||||
pImgFac->Release();
|
||||
}
|
||||
else
|
||||
hr = S_OK;
|
||||
break;
|
||||
}
|
||||
return hr;
|
||||
BYTE *pBits;
|
||||
HBITMAP ResizedHBmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0);
|
||||
hr = ResizedHBmp ? S_OK : E_OUTOFMEMORY;
|
||||
if (SUCCEEDED(hr)) {
|
||||
IWICBitmapScaler *pIScaler;
|
||||
hr = pImgFac->CreateBitmapScaler(&pIScaler);
|
||||
hr = pIScaler->Initialize(WICBmp, NewWidth, NewHeight, WICBitmapInterpolationModeFant);
|
||||
|
||||
WICRect rect = {0, 0, NewWidth, NewHeight};
|
||||
hr = pIScaler->CopyPixels(&rect, NewWidth * 4, NewWidth * NewHeight * 4, pBits);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
DeleteObject(*phbmp);
|
||||
*phbmp = ResizedHBmp;
|
||||
}
|
||||
else
|
||||
DeleteObject(ResizedHBmp);
|
||||
|
||||
pIScaler->Release();
|
||||
}
|
||||
WICBmp->Release();
|
||||
pImgFac->Release();
|
||||
}
|
||||
else
|
||||
hr = S_OK;
|
||||
break;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -16,29 +16,26 @@
|
|||
|
||||
#include <objbase.h>
|
||||
#include <shlwapi.h>
|
||||
#include <thumbcache.h> // For IThumbnailProvider.
|
||||
#include <shlobj.h> // For SHChangeNotify
|
||||
#include <thumbcache.h> // For IThumbnailProvider.
|
||||
#include <shlobj.h> // For SHChangeNotify
|
||||
#include <new>
|
||||
|
||||
extern HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv);
|
||||
|
||||
#define SZ_CLSID_BLENDTHUMBHANDLER L"{D45F043D-F17F-4e8a-8435-70971D9FA46D}"
|
||||
#define SZ_BLENDTHUMBHANDLER L"Blender Thumbnail Handler"
|
||||
const CLSID CLSID_BlendThumbHandler = { 0xd45f043d, 0xf17f, 0x4e8a, { 0x84, 0x35, 0x70, 0x97, 0x1d, 0x9f, 0xa4, 0x6d } };
|
||||
#define SZ_CLSID_BLENDTHUMBHANDLER L"{D45F043D-F17F-4e8a-8435-70971D9FA46D}"
|
||||
#define SZ_BLENDTHUMBHANDLER L"Blender Thumbnail Handler"
|
||||
const CLSID CLSID_BlendThumbHandler = {
|
||||
0xd45f043d, 0xf17f, 0x4e8a, {0x84, 0x35, 0x70, 0x97, 0x1d, 0x9f, 0xa4, 0x6d}};
|
||||
|
||||
typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject);
|
||||
struct CLASS_OBJECT_INIT
|
||||
{
|
||||
const CLSID *pClsid;
|
||||
PFNCREATEINSTANCE pfnCreate;
|
||||
struct CLASS_OBJECT_INIT {
|
||||
const CLSID *pClsid;
|
||||
PFNCREATEINSTANCE pfnCreate;
|
||||
};
|
||||
|
||||
// add classes supported by this module here
|
||||
const CLASS_OBJECT_INIT c_rgClassObjectInit[] =
|
||||
{
|
||||
{ &CLSID_BlendThumbHandler, CBlendThumb_CreateInstance }
|
||||
};
|
||||
|
||||
const CLASS_OBJECT_INIT c_rgClassObjectInit[] = {
|
||||
{&CLSID_BlendThumbHandler, CBlendThumb_CreateInstance}};
|
||||
|
||||
long g_cRefModule = 0;
|
||||
|
||||
|
@ -48,162 +45,160 @@ HINSTANCE g_hInst = NULL;
|
|||
// Standard DLL functions
|
||||
STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
|
||||
{
|
||||
if (dwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
g_hInst = hInstance;
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
}
|
||||
return TRUE;
|
||||
if (dwReason == DLL_PROCESS_ATTACH) {
|
||||
g_hInst = hInstance;
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
STDAPI DllCanUnloadNow()
|
||||
{
|
||||
// Only allow the DLL to be unloaded after all outstanding references have been released
|
||||
return (g_cRefModule == 0) ? S_OK : S_FALSE;
|
||||
// Only allow the DLL to be unloaded after all outstanding references have been released
|
||||
return (g_cRefModule == 0) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
void DllAddRef()
|
||||
{
|
||||
InterlockedIncrement(&g_cRefModule);
|
||||
InterlockedIncrement(&g_cRefModule);
|
||||
}
|
||||
|
||||
void DllRelease()
|
||||
{
|
||||
InterlockedDecrement(&g_cRefModule);
|
||||
InterlockedDecrement(&g_cRefModule);
|
||||
}
|
||||
|
||||
class CClassFactory : public IClassFactory
|
||||
{
|
||||
public:
|
||||
static HRESULT CreateInstance(REFCLSID clsid, const CLASS_OBJECT_INIT *pClassObjectInits, size_t cClassObjectInits, REFIID riid, void **ppv)
|
||||
{
|
||||
*ppv = NULL;
|
||||
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
|
||||
for (size_t i = 0; i < cClassObjectInits; i++)
|
||||
{
|
||||
if (clsid == *pClassObjectInits[i].pClsid)
|
||||
{
|
||||
IClassFactory *pClassFactory = new (std::nothrow) CClassFactory(pClassObjectInits[i].pfnCreate);
|
||||
hr = pClassFactory ? S_OK : E_OUTOFMEMORY;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pClassFactory->QueryInterface(riid, ppv);
|
||||
pClassFactory->Release();
|
||||
}
|
||||
break; // match found
|
||||
}
|
||||
class CClassFactory : public IClassFactory {
|
||||
public:
|
||||
static HRESULT CreateInstance(REFCLSID clsid,
|
||||
const CLASS_OBJECT_INIT *pClassObjectInits,
|
||||
size_t cClassObjectInits,
|
||||
REFIID riid,
|
||||
void **ppv)
|
||||
{
|
||||
*ppv = NULL;
|
||||
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
|
||||
for (size_t i = 0; i < cClassObjectInits; i++) {
|
||||
if (clsid == *pClassObjectInits[i].pClsid) {
|
||||
IClassFactory *pClassFactory = new (std::nothrow)
|
||||
CClassFactory(pClassObjectInits[i].pfnCreate);
|
||||
hr = pClassFactory ? S_OK : E_OUTOFMEMORY;
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = pClassFactory->QueryInterface(riid, ppv);
|
||||
pClassFactory->Release();
|
||||
}
|
||||
return hr;
|
||||
break; // match found
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
CClassFactory(PFNCREATEINSTANCE pfnCreate) : _cRef(1), _pfnCreate(pfnCreate)
|
||||
{
|
||||
DllAddRef();
|
||||
CClassFactory(PFNCREATEINSTANCE pfnCreate) : _cRef(1), _pfnCreate(pfnCreate)
|
||||
{
|
||||
DllAddRef();
|
||||
}
|
||||
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
static const QITAB qit[] = {QITABENT(CClassFactory, IClassFactory), {0}};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&_cRef);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) Release()
|
||||
{
|
||||
long cRef = InterlockedDecrement(&_cRef);
|
||||
if (cRef == 0) {
|
||||
delete this;
|
||||
}
|
||||
return cRef;
|
||||
}
|
||||
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void ** ppv)
|
||||
{
|
||||
static const QITAB qit[] =
|
||||
{
|
||||
QITABENT(CClassFactory, IClassFactory),
|
||||
{ 0 }
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
// IClassFactory
|
||||
IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
|
||||
{
|
||||
return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP LockServer(BOOL fLock)
|
||||
{
|
||||
if (fLock) {
|
||||
DllAddRef();
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&_cRef);
|
||||
else {
|
||||
DllRelease();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) Release()
|
||||
{
|
||||
long cRef = InterlockedDecrement(&_cRef);
|
||||
if (cRef == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
return cRef;
|
||||
}
|
||||
private:
|
||||
~CClassFactory()
|
||||
{
|
||||
DllRelease();
|
||||
}
|
||||
|
||||
// IClassFactory
|
||||
IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
|
||||
{
|
||||
return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP LockServer(BOOL fLock)
|
||||
{
|
||||
if (fLock)
|
||||
{
|
||||
DllAddRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
DllRelease();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~CClassFactory()
|
||||
{
|
||||
DllRelease();
|
||||
}
|
||||
|
||||
long _cRef;
|
||||
PFNCREATEINSTANCE _pfnCreate;
|
||||
long _cRef;
|
||||
PFNCREATEINSTANCE _pfnCreate;
|
||||
};
|
||||
|
||||
STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
|
||||
{
|
||||
return CClassFactory::CreateInstance(clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
|
||||
return CClassFactory::CreateInstance(
|
||||
clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
|
||||
}
|
||||
|
||||
// A struct to hold the information required for a registry entry
|
||||
|
||||
struct REGISTRY_ENTRY
|
||||
{
|
||||
HKEY hkeyRoot;
|
||||
PCWSTR pszKeyName;
|
||||
PCWSTR pszValueName;
|
||||
DWORD dwValueType;
|
||||
PCWSTR pszData;
|
||||
struct REGISTRY_ENTRY {
|
||||
HKEY hkeyRoot;
|
||||
PCWSTR pszKeyName;
|
||||
PCWSTR pszValueName;
|
||||
DWORD dwValueType;
|
||||
PCWSTR pszData;
|
||||
};
|
||||
|
||||
// Creates a registry key (if needed) and sets the default value of the key
|
||||
|
||||
HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
|
||||
{
|
||||
HKEY hKey;
|
||||
HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot, pRegistryEntry->pszKeyName,
|
||||
0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// All this just to support REG_DWORD...
|
||||
DWORD size;
|
||||
DWORD data;
|
||||
BYTE* lpData = (LPBYTE) pRegistryEntry->pszData;
|
||||
switch (pRegistryEntry->dwValueType)
|
||||
{
|
||||
case REG_SZ:
|
||||
size = ((DWORD) wcslen(pRegistryEntry->pszData) + 1) * sizeof(WCHAR);
|
||||
break;
|
||||
case REG_DWORD:
|
||||
size = sizeof(DWORD);
|
||||
data = (DWORD)pRegistryEntry->pszData;
|
||||
lpData = (BYTE*)&data;
|
||||
break;
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, pRegistryEntry->pszValueName, 0, pRegistryEntry->dwValueType,
|
||||
lpData, size ));
|
||||
RegCloseKey(hKey);
|
||||
HKEY hKey;
|
||||
HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot,
|
||||
pRegistryEntry->pszKeyName,
|
||||
0,
|
||||
NULL,
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
KEY_SET_VALUE,
|
||||
NULL,
|
||||
&hKey,
|
||||
NULL));
|
||||
if (SUCCEEDED(hr)) {
|
||||
// All this just to support REG_DWORD...
|
||||
DWORD size;
|
||||
DWORD data;
|
||||
BYTE *lpData = (LPBYTE)pRegistryEntry->pszData;
|
||||
switch (pRegistryEntry->dwValueType) {
|
||||
case REG_SZ:
|
||||
size = ((DWORD)wcslen(pRegistryEntry->pszData) + 1) * sizeof(WCHAR);
|
||||
break;
|
||||
case REG_DWORD:
|
||||
size = sizeof(DWORD);
|
||||
data = (DWORD)pRegistryEntry->pszData;
|
||||
lpData = (BYTE *)&data;
|
||||
break;
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
return hr;
|
||||
|
||||
hr = HRESULT_FROM_WIN32(RegSetValueExW(
|
||||
hKey, pRegistryEntry->pszValueName, 0, pRegistryEntry->dwValueType, lpData, size));
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -211,39 +206,55 @@ HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
|
|||
//
|
||||
STDAPI DllRegisterServer()
|
||||
{
|
||||
HRESULT hr;
|
||||
HRESULT hr;
|
||||
|
||||
WCHAR szModuleName[MAX_PATH];
|
||||
WCHAR szModuleName[MAX_PATH];
|
||||
|
||||
if (!GetModuleFileNameW(g_hInst, szModuleName, ARRAYSIZE(szModuleName)))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
const REGISTRY_ENTRY rgRegistryEntries[] =
|
||||
{
|
||||
// RootKey KeyName ValueName ValueType Data
|
||||
{HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER, NULL, REG_SZ, SZ_BLENDTHUMBHANDLER},
|
||||
{HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32", NULL, REG_SZ, szModuleName},
|
||||
{HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32", L"ThreadingModel", REG_SZ, L"Apartment"},
|
||||
{HKEY_CURRENT_USER, L"Software\\Classes\\.blend\\", L"Treatment", REG_DWORD, 0}, // doesn't appear to do anything...
|
||||
{HKEY_CURRENT_USER, L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", NULL, REG_SZ, SZ_CLSID_BLENDTHUMBHANDLER},
|
||||
};
|
||||
if (!GetModuleFileNameW(g_hInst, szModuleName, ARRAYSIZE(szModuleName))) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
else {
|
||||
const REGISTRY_ENTRY rgRegistryEntries[] = {
|
||||
// RootKey KeyName ValueName ValueType Data
|
||||
{HKEY_CURRENT_USER,
|
||||
L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
|
||||
NULL,
|
||||
REG_SZ,
|
||||
SZ_BLENDTHUMBHANDLER},
|
||||
{HKEY_CURRENT_USER,
|
||||
L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32",
|
||||
NULL,
|
||||
REG_SZ,
|
||||
szModuleName},
|
||||
{HKEY_CURRENT_USER,
|
||||
L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32",
|
||||
L"ThreadingModel",
|
||||
REG_SZ,
|
||||
L"Apartment"},
|
||||
{HKEY_CURRENT_USER,
|
||||
L"Software\\Classes\\.blend\\",
|
||||
L"Treatment",
|
||||
REG_DWORD,
|
||||
0}, // doesn't appear to do anything...
|
||||
{HKEY_CURRENT_USER,
|
||||
L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}",
|
||||
NULL,
|
||||
REG_SZ,
|
||||
SZ_CLSID_BLENDTHUMBHANDLER},
|
||||
};
|
||||
|
||||
hr = S_OK;
|
||||
for (int i = 0; i < ARRAYSIZE(rgRegistryEntries) && SUCCEEDED(hr); i++)
|
||||
{
|
||||
hr = CreateRegKeyAndSetValue(&rgRegistryEntries[i]);
|
||||
}
|
||||
hr = S_OK;
|
||||
for (int i = 0; i < ARRAYSIZE(rgRegistryEntries) && SUCCEEDED(hr); i++) {
|
||||
hr = CreateRegKeyAndSetValue(&rgRegistryEntries[i]);
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// This tells the shell to invalidate the thumbnail cache. This is important because any .blend files
|
||||
// viewed before registering this handler would otherwise show cached blank thumbnails.
|
||||
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
if (SUCCEEDED(hr)) {
|
||||
// This tells the shell to invalidate the thumbnail cache. This is important because any
|
||||
// .blend files viewed before registering this handler would otherwise show cached blank
|
||||
// thumbnails.
|
||||
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -251,23 +262,19 @@ STDAPI DllRegisterServer()
|
|||
//
|
||||
STDAPI DllUnregisterServer()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
const PCWSTR rgpszKeys[] =
|
||||
{
|
||||
L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
|
||||
L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}"
|
||||
};
|
||||
const PCWSTR rgpszKeys[] = {
|
||||
L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
|
||||
L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}"};
|
||||
|
||||
// Delete the registry entries
|
||||
for (int i = 0; i < ARRAYSIZE(rgpszKeys) && SUCCEEDED(hr); i++)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDeleteTreeW(HKEY_CURRENT_USER, rgpszKeys[i]));
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
||||
{
|
||||
// If the registry entry has already been deleted, say S_OK.
|
||||
hr = S_OK;
|
||||
}
|
||||
// Delete the registry entries
|
||||
for (int i = 0; i < ARRAYSIZE(rgpszKeys) && SUCCEEDED(hr); i++) {
|
||||
hr = HRESULT_FROM_WIN32(RegDeleteTreeW(HKEY_CURRENT_USER, rgpszKeys[i]));
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
|
||||
// If the registry entry has already been deleted, say S_OK.
|
||||
hr = S_OK;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue