diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/inc/thumbviewer.hxx | 77 | ||||
-rw-r--r-- | shell/qa/zip/testzipimpl.cxx | 37 | ||||
-rw-r--r-- | shell/source/win32/shlxthandler/classfactory.cxx | 2 | ||||
-rw-r--r-- | shell/source/win32/shlxthandler/thumbviewer/thumbviewer.cxx | 233 |
4 files changed, 162 insertions, 187 deletions
diff --git a/shell/inc/thumbviewer.hxx b/shell/inc/thumbviewer.hxx index 23310691e0b7..57ef8e5a8bbd 100644 --- a/shell/inc/thumbviewer.hxx +++ b/shell/inc/thumbviewer.hxx @@ -17,83 +17,10 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#ifndef INCLUDED_SHELL_INC_INTERNAL_THUMBVIEWER_HXX -#define INCLUDED_SHELL_INC_INTERNAL_THUMBVIEWER_HXX +#pragma once -#include <objidl.h> #include <shlobj.h> -#ifndef DONT_HAVE_GDIPLUS -#include <gdiplus.h> -#endif -#include <string> -class CThumbviewer : public IPersistFile, public IExtractImage -{ -public: - CThumbviewer(LONG RefCnt = 1); - virtual ~CThumbviewer(); - - - // IUnknown methods - - - virtual HRESULT STDMETHODCALLTYPE QueryInterface( - REFIID riid, - void __RPC_FAR *__RPC_FAR *ppvObject) override; - - virtual ULONG STDMETHODCALLTYPE AddRef() override; - - virtual ULONG STDMETHODCALLTYPE Release() override; - - - // IExtractImage methods - - - virtual HRESULT STDMETHODCALLTYPE Extract(HBITMAP *phBmpImage) override; - - virtual HRESULT STDMETHODCALLTYPE GetLocation( - LPWSTR pszPathBuffer, - DWORD cchMax, - DWORD *pdwPriority, - const SIZE *prgSize, - DWORD dwRecClrDepth, - DWORD *pdwFlags) override; - - - // IPersist methods - - - virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID* pClassID) override; - - - // IPersistFile methods - - - virtual HRESULT STDMETHODCALLTYPE IsDirty() override; - - virtual HRESULT STDMETHODCALLTYPE Load( - /* [in] */ LPCOLESTR pszFileName, - /* [in] */ DWORD dwMode) override; - - virtual HRESULT STDMETHODCALLTYPE Save( - /* [unique][in] */ LPCOLESTR pszFileName, - /* [in] */ BOOL fRemember) override; - - virtual HRESULT STDMETHODCALLTYPE SaveCompleted( - /* [unique][in] */ LPCOLESTR pszFileName) override; - - virtual HRESULT STDMETHODCALLTYPE GetCurFile( - /* [out] */ LPOLESTR __RPC_FAR *ppszFileName) override; - -private: - LONG ref_count_; - std::wstring filename_; - SIZE thumbnail_size_; - DWORD color_depth_; - ULONG_PTR gdiplus_token_; - Gdiplus::Bitmap* signet_; -}; - -#endif +IExtractImage* CreateThumbviewer(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/qa/zip/testzipimpl.cxx b/shell/qa/zip/testzipimpl.cxx index e39408f98496..572782f722c4 100644 --- a/shell/qa/zip/testzipimpl.cxx +++ b/shell/qa/zip/testzipimpl.cxx @@ -20,26 +20,25 @@ #include "testzipimpl.hxx" TestZipImpl::TestZipImpl(StreamInterface* stream) - : zipFile(ZipFile(stream)) - , expectedContents() + : zipFile{ stream } + , expectedContents{ "mimetype", + "Configurations2/statusbar/", + "Configurations2/accelerator/current.xml", + "Configurations2/floater/", + "Configurations2/popupmenu/", + "Configurations2/progressbar/", + "Configurations2/toolpanel/", + "Configurations2/menubar/", + "Configurations2/toolbar/", + "Configurations2/images/Bitmaps/", + "content.xml", + "manifest.rdf", + "styles.xml", + "meta.xml", + "Thumbnails/thumbnail.png", + "settings.xml", + "META-INF/manifest.xml" } { - expectedContents.push_back("mimetype"); - expectedContents.push_back("Configurations2/statusbar/"); - expectedContents.push_back("Configurations2/accelerator/current.xml"); - expectedContents.push_back("Configurations2/floater/"); - expectedContents.push_back("Configurations2/popupmenu/"); - expectedContents.push_back("Configurations2/progressbar/"); - expectedContents.push_back("Configurations2/toolpanel/"); - expectedContents.push_back("Configurations2/menubar/"); - expectedContents.push_back("Configurations2/toolbar/"); - expectedContents.push_back("Configurations2/images/Bitmaps/"); - expectedContents.push_back("content.xml"); - expectedContents.push_back("manifest.rdf"); - expectedContents.push_back("styles.xml"); - expectedContents.push_back("meta.xml"); - expectedContents.push_back("Thumbnails/thumbnail.png"); - expectedContents.push_back("settings.xml"); - expectedContents.push_back("META-INF/manifest.xml"); sort(expectedContents.begin(), expectedContents.end()); } diff --git a/shell/source/win32/shlxthandler/classfactory.cxx b/shell/source/win32/shlxthandler/classfactory.cxx index 95da69252089..ff0f2b406d4e 100644 --- a/shell/source/win32/shlxthandler/classfactory.cxx +++ b/shell/source/win32/shlxthandler/classfactory.cxx @@ -102,7 +102,7 @@ HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance( pUnk = new CColumnInfo(); else if (CLSID_THUMBVIEWER_HANDLER == m_Clsid) - pUnk = static_cast<IExtractImage*>(new CThumbviewer()); + pUnk = CreateThumbviewer(); if (nullptr == pUnk) { diff --git a/shell/source/win32/shlxthandler/thumbviewer/thumbviewer.cxx b/shell/source/win32/shlxthandler/thumbviewer/thumbviewer.cxx index 657664ff5866..750b5a36f7b1 100644 --- a/shell/source/win32/shlxthandler/thumbviewer/thumbviewer.cxx +++ b/shell/source/win32/shlxthandler/thumbviewer/thumbviewer.cxx @@ -17,9 +17,6 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#ifndef DONT_HAVE_GDIPLUS - - #include <global.hxx> #include <thumbviewer.hxx> @@ -37,26 +34,32 @@ #include <stdlib.h> #include <shellapi.h> +#include <objidl.h> +#include <shlobj.h> +#include <gdiplus.h> +#include <algorithm> +#include <atomic> #include <memory> +#include <string> -namespace internal +namespace { /* The signet.png used for thumbnails of signed documents is contained as resource in this module, the resource id is 2000 */ - static void LoadSignetImageFromResource(ZipFile::ZipContentBuffer_t& buffer) + static ZipFile::ZipContentBuffer_t LoadSignetImageFromResource() { HRSRC hrc = FindResourceW(g_hModule, L"#2000", reinterpret_cast<LPWSTR>(RT_RCDATA)); DWORD size = SizeofResource(g_hModule, hrc); HGLOBAL hglob = LoadResource(g_hModule, hrc); char* data = static_cast<char*>(LockResource(hglob)); - buffer = ZipFile::ZipContentBuffer_t(data, data + size); + return ZipFile::ZipContentBuffer_t(data, data + size); } - static bool IsSignedDocument(const ZipFile* zipfile) + static bool IsSignedDocument(const ZipFile& zipfile) { - return zipfile->HasContent("META-INF/documentsignatures.xml"); + return zipfile.HasContent("META-INF/documentsignatures.xml"); } static Gdiplus::Point CalcSignetPosition( @@ -80,9 +83,6 @@ namespace internal return Gdiplus::Point(x,y); } -} - -namespace { Gdiplus::Rect CalcScaledAspectRatio(const Gdiplus::Rect& src, const Gdiplus::Rect& dest) { @@ -98,7 +98,18 @@ Gdiplus::Rect CalcScaledAspectRatio(const Gdiplus::Rect& src, const Gdiplus::Rec class StreamOnZipBuffer final : public IStream { public: - explicit StreamOnZipBuffer(const ZipFile::ZipContentBuffer_t& zip_buffer); + struct SmartPtr + { + ~SmartPtr() { p->Release(); } + operator IStream*() { return p; } + + IStream* p; + }; + + static SmartPtr Create(ZipFile::ZipContentBuffer_t&& zip_buffer) + { + return { new StreamOnZipBuffer(std::move(zip_buffer)) }; + } // IUnknown virtual ULONG STDMETHODCALLTYPE AddRef() override; @@ -119,32 +130,28 @@ public: virtual HRESULT STDMETHODCALLTYPE Clone(IStream **ppstm) override; private: - LONG ref_count_; - const ZipFile::ZipContentBuffer_t& ref_zip_buffer_; - size_t pos_; -}; - -} + explicit StreamOnZipBuffer(ZipFile::ZipContentBuffer_t&& zip_buffer) + : zip_buffer_(std::move(zip_buffer)) + { + } -StreamOnZipBuffer::StreamOnZipBuffer(const ZipFile::ZipContentBuffer_t& zip_buffer) : - ref_count_(1), - ref_zip_buffer_(zip_buffer), - pos_(0) -{ -} + std::atomic<ULONG> ref_count_ = 1; + const ZipFile::ZipContentBuffer_t zip_buffer_; + size_t pos_ = 0; +}; // IUnknown methods ULONG STDMETHODCALLTYPE StreamOnZipBuffer::AddRef() { - return InterlockedIncrement(&ref_count_); + return ++ref_count_; } ULONG STDMETHODCALLTYPE StreamOnZipBuffer::Release() { - LONG refcnt = InterlockedDecrement(&ref_count_); + const ULONG refcnt = --ref_count_; - if (0 == ref_count_) + if (0 == refcnt) delete this; return refcnt; @@ -153,13 +160,11 @@ ULONG STDMETHODCALLTYPE StreamOnZipBuffer::Release() HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) { *ppvObject = nullptr; - IUnknown* pUnk = nullptr; if ((IID_IUnknown == riid) || (IID_IStream == riid)) { - pUnk = this; - pUnk->AddRef(); - *ppvObject = pUnk; + *ppvObject = this; + AddRef(); return S_OK; } return E_NOINTERFACE; @@ -170,75 +175,78 @@ HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Read(void *pv, ULONG cb, ULONG *pcb if (pv == nullptr) return STG_E_INVALIDPOINTER; - size_t size = ref_zip_buffer_.size(); - - if (pos_ > size) - return S_FALSE; - char* p = static_cast<char*>(pv); - ULONG read = 0; - - for ( ;(pos_ < size) && (cb > 0); pos_++, cb--, read++) - *p++ = ref_zip_buffer_[pos_]; + const size_t available = pos_ < zip_buffer_.size() ? zip_buffer_.size() - pos_ : 0; + const ULONG read = min(available, cb); + if (read > 0) + { + std::copy_n(zip_buffer_.data() + pos_, read, p); + pos_ += read; + } if (pcbRead) *pcbRead = read; - return S_OK; + return read == cb ? S_OK : S_FALSE; } -HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *) +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, + ULARGE_INTEGER* plibNewPosition) { - __int64 size = static_cast<__int64>(ref_zip_buffer_.size()); - __int64 p = 0; + const __int64 size = zip_buffer_.size(); + __int64 p; switch (dwOrigin) { case STREAM_SEEK_SET: + p = 0; break; case STREAM_SEEK_CUR: - p = static_cast<__int64>(pos_); + p = pos_; break; case STREAM_SEEK_END: - p = size - 1; + p = size; break; + default: + return STG_E_INVALIDFUNCTION; } - HRESULT hr = STG_E_INVALIDFUNCTION; - p += dlibMove.QuadPart; + if (p < 0) + return STG_E_INVALIDFUNCTION; - if ( ( p >= 0 ) && (p < size) ) - { - pos_ = static_cast<size_t>(p); - hr = S_OK; - } - return hr; + if (p > size) + p = size; + + pos_ = p; + if (plibNewPosition) + *plibNewPosition = { .QuadPart = pos_ }; + return S_OK; } HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Stat(STATSTG *pstatstg, DWORD grfStatFlag) { if (pstatstg == nullptr) return STG_E_INVALIDPOINTER; + if (grfStatFlag != STATFLAG_DEFAULT && grfStatFlag != STATFLAG_NONAME) + return STG_E_INVALIDFLAG; ZeroMemory(pstatstg, sizeof(STATSTG)); - if (grfStatFlag == STATFLAG_DEFAULT) + if (grfStatFlag != STATFLAG_NONAME) { size_t sz = 4 * sizeof(wchar_t); wchar_t* name = static_cast<wchar_t*>(CoTaskMemAlloc(sz)); - ZeroMemory(name, sz); - memcpy(name, L"png", 3 * sizeof(wchar_t)); + if (!name) + return STG_E_INSUFFICIENTMEMORY; + wcscpy(name, L"png"); pstatstg->pwcsName = name; } pstatstg->type = STGTY_LOCKBYTES; - ULARGE_INTEGER uli; - uli.LowPart = static_cast<DWORD>(ref_zip_buffer_.size()); - uli.HighPart = 0; - - pstatstg->cbSize = uli; + static_assert(std::is_integral_v<decltype(pstatstg->cbSize.QuadPart)>); + pstatstg->cbSize = { .QuadPart = zip_buffer_.size() }; return S_OK; } @@ -267,23 +275,69 @@ HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::UnlockRegion(ULARGE_INTEGER, ULARGE HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Clone(IStream **) { return E_NOTIMPL; } +class CThumbviewer : public IPersistFile, public IExtractImage +{ +public: + CThumbviewer(); + virtual ~CThumbviewer(); + + // IUnknown methods + + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, + void __RPC_FAR* __RPC_FAR* ppvObject) override; + + virtual ULONG STDMETHODCALLTYPE AddRef() override; + + virtual ULONG STDMETHODCALLTYPE Release() override; + + // IExtractImage methods + + virtual HRESULT STDMETHODCALLTYPE Extract(HBITMAP* phBmpImage) override; -CThumbviewer::CThumbviewer(LONG RefCnt) : - ref_count_(RefCnt) + virtual HRESULT STDMETHODCALLTYPE GetLocation(LPWSTR pszPathBuffer, DWORD cchMax, + DWORD* pdwPriority, const SIZE* prgSize, + DWORD dwRecClrDepth, DWORD* pdwFlags) override; + + // IPersist methods + + virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID* pClassID) override; + + // IPersistFile methods + + virtual HRESULT STDMETHODCALLTYPE IsDirty() override; + + virtual HRESULT STDMETHODCALLTYPE Load( + /* [in] */ LPCOLESTR pszFileName, + /* [in] */ DWORD dwMode) override; + + virtual HRESULT STDMETHODCALLTYPE Save( + /* [unique][in] */ LPCOLESTR pszFileName, + /* [in] */ BOOL fRemember) override; + + virtual HRESULT STDMETHODCALLTYPE SaveCompleted( + /* [unique][in] */ LPCOLESTR pszFileName) override; + + virtual HRESULT STDMETHODCALLTYPE GetCurFile( + /* [out] */ LPOLESTR __RPC_FAR* ppszFileName) override; + +private: + std::atomic<ULONG> ref_count_ = 1; + DWORD color_depth_ = 0; + std::wstring filename_; + SIZE thumbnail_size_ = { .cx = 0, .cy = 0 }; + ULONG_PTR gdiplus_token_; + Gdiplus::Bitmap* signet_; +}; + +CThumbviewer::CThumbviewer() { InterlockedIncrement(&g_DllRefCnt); - thumbnail_size_.cx = 0; - thumbnail_size_.cy = 0; - Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&gdiplus_token_, &gdiplusStartupInput, nullptr); - ZipFile::ZipContentBuffer_t img_data; - internal::LoadSignetImageFromResource(img_data); - IStream* stream = new StreamOnZipBuffer(img_data); - signet_ = new Gdiplus::Bitmap(stream, TRUE); - stream->Release(); + signet_ = new Gdiplus::Bitmap( + StreamOnZipBuffer::Create(LoadSignetImageFromResource()), TRUE); } CThumbviewer::~CThumbviewer() @@ -298,20 +352,17 @@ CThumbviewer::~CThumbviewer() HRESULT STDMETHODCALLTYPE CThumbviewer::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) { *ppvObject = nullptr; - IUnknown* pUnk = nullptr; if ((IID_IUnknown == riid) || (IID_IPersistFile == riid)) { - pUnk = static_cast<IPersistFile*>(this); - pUnk->AddRef(); - *ppvObject = pUnk; + *ppvObject = static_cast<IPersistFile*>(this); + AddRef(); return S_OK; } else if (IID_IExtractImage == riid) { - pUnk = static_cast<IExtractImage*>(this); - pUnk->AddRef(); - *ppvObject = pUnk; + *ppvObject = static_cast<IExtractImage*>(this); + AddRef(); return S_OK; } return E_NOINTERFACE; @@ -319,14 +370,14 @@ HRESULT STDMETHODCALLTYPE CThumbviewer::QueryInterface(REFIID riid, void __RPC_F ULONG STDMETHODCALLTYPE CThumbviewer::AddRef() { - return InterlockedIncrement(&ref_count_); + return ++ref_count_; } ULONG STDMETHODCALLTYPE CThumbviewer::Release() { - LONG refcnt = InterlockedDecrement(&ref_count_); + const ULONG refcnt = --ref_count_; - if (0 == ref_count_) + if (0 == refcnt) delete this; return refcnt; @@ -343,19 +394,17 @@ HRESULT STDMETHODCALLTYPE CThumbviewer::Extract(HBITMAP *phBmpImage) try { std::wstring fname = getShortPathName( filename_ ); - std::unique_ptr<ZipFile> zipfile( new ZipFile( fname ) ); + ZipFile zipfile(fname); - if (zipfile->HasContent(THUMBNAIL_CONTENT)) + if (zipfile.HasContent(THUMBNAIL_CONTENT)) { ZipFile::ZipContentBuffer_t thumbnail; - zipfile->GetUncompressedContent(THUMBNAIL_CONTENT, thumbnail); - IStream* stream = new StreamOnZipBuffer(thumbnail); + zipfile.GetUncompressedContent(THUMBNAIL_CONTENT, thumbnail); - Gdiplus::Bitmap thumbnail_png(stream, TRUE); + Gdiplus::Bitmap thumbnail_png(StreamOnZipBuffer::Create(std::move(thumbnail)), TRUE); if ((thumbnail_png.GetHeight() == 0) || (thumbnail_png.GetWidth() == 0)) { - stream->Release(); return E_FAIL; } @@ -414,12 +463,12 @@ HRESULT STDMETHODCALLTYPE CThumbviewer::Extract(HBITMAP *phBmpImage) thumbnail_png.GetWidth(), thumbnail_png.GetHeight(), Gdiplus::UnitPixel); /* Add a signet sign to the thumbnail of signed documents */ - if (internal::IsSignedDocument(zipfile.get())) + if (IsSignedDocument(zipfile)) { double SCALING_FACTOR = 0.6; Gdiplus::Rect signet_scaled( 0, 0, static_cast<INT>(signet_->GetWidth() * SCALING_FACTOR), static_cast<INT>(signet_->GetHeight() * SCALING_FACTOR)); - Gdiplus::Point pos_signet = internal::CalcSignetPosition(canvas_thumbnail, border_rect, signet_scaled); + Gdiplus::Point pos_signet = CalcSignetPosition(canvas_thumbnail, border_rect, signet_scaled); Gdiplus::Rect dest(pos_signet.X, pos_signet.Y, signet_scaled.GetRight(), signet_scaled.GetBottom()); stat = graphics.DrawImage( @@ -439,7 +488,6 @@ HRESULT STDMETHODCALLTYPE CThumbviewer::Extract(HBITMAP *phBmpImage) } ReleaseDC(hwnd, hdc); - stream->Release(); } } catch(std::exception&) @@ -494,7 +542,8 @@ HRESULT STDMETHODCALLTYPE CThumbviewer::SaveCompleted(LPCOLESTR) HRESULT STDMETHODCALLTYPE CThumbviewer::GetCurFile(LPOLESTR __RPC_FAR*) { return E_NOTIMPL; } +} // namespace -#endif // DONT_HAVE_GDIPLUS +IExtractImage* CreateThumbviewer() { return new CThumbviewer; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |