xref: /AOO41X/main/shell/source/win32/shlxthandler/thumbviewer/thumbviewer.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_shell.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include "internal/global.hxx"
32*cdf0e10cSrcweir 
33*cdf0e10cSrcweir #ifndef INFOTIPS_HXX_INCLUDED
34*cdf0e10cSrcweir #include "internal/thumbviewer.hxx"
35*cdf0e10cSrcweir #endif
36*cdf0e10cSrcweir #include "internal/shlxthdl.hxx"
37*cdf0e10cSrcweir #include "internal/registry.hxx"
38*cdf0e10cSrcweir #include "internal/fileextensions.hxx"
39*cdf0e10cSrcweir #include "internal/config.hxx"
40*cdf0e10cSrcweir #include "internal/zipfile.hxx"
41*cdf0e10cSrcweir #include "internal/utilities.hxx"
42*cdf0e10cSrcweir 
43*cdf0e10cSrcweir #include "internal/resource.h"
44*cdf0e10cSrcweir 
45*cdf0e10cSrcweir #include <stdio.h>
46*cdf0e10cSrcweir #include <utility>
47*cdf0e10cSrcweir #include <stdlib.h>
48*cdf0e10cSrcweir 
49*cdf0e10cSrcweir #if defined _MSC_VER
50*cdf0e10cSrcweir #pragma warning(push, 1)
51*cdf0e10cSrcweir #endif
52*cdf0e10cSrcweir #include <shellapi.h>
53*cdf0e10cSrcweir #if defined _MSC_VER
54*cdf0e10cSrcweir #pragma warning(pop)
55*cdf0e10cSrcweir #endif
56*cdf0e10cSrcweir #include <memory>
57*cdf0e10cSrcweir 
58*cdf0e10cSrcweir extern HINSTANCE g_hModule;
59*cdf0e10cSrcweir 
60*cdf0e10cSrcweir namespace internal
61*cdf0e10cSrcweir {
62*cdf0e10cSrcweir     /* The signet.png used for thumbnails of signed documents
63*cdf0e10cSrcweir        is contained as resource in this module, the resource
64*cdf0e10cSrcweir        id is 2000 */
65*cdf0e10cSrcweir     void LoadSignetImageFromResource(ZipFile::ZipContentBuffer_t& buffer)
66*cdf0e10cSrcweir     {
67*cdf0e10cSrcweir         HRSRC hrc = FindResource(g_hModule, TEXT("#2000"), RT_RCDATA);
68*cdf0e10cSrcweir         DWORD size = SizeofResource(g_hModule, hrc);
69*cdf0e10cSrcweir         HGLOBAL hglob = LoadResource(g_hModule, hrc);
70*cdf0e10cSrcweir         char* data = reinterpret_cast<char*>(LockResource(hglob));
71*cdf0e10cSrcweir         buffer = ZipFile::ZipContentBuffer_t(data, data + size);
72*cdf0e10cSrcweir     }
73*cdf0e10cSrcweir 
74*cdf0e10cSrcweir     bool IsSignedDocument(const ZipFile* zipfile)
75*cdf0e10cSrcweir     {
76*cdf0e10cSrcweir         return zipfile->HasContent("META-INF/documentsignatures.xml");
77*cdf0e10cSrcweir     }
78*cdf0e10cSrcweir 
79*cdf0e10cSrcweir     bool IsWindowsXP()
80*cdf0e10cSrcweir     {
81*cdf0e10cSrcweir         OSVERSIONINFO osvi;
82*cdf0e10cSrcweir         ZeroMemory(&osvi, sizeof(osvi));
83*cdf0e10cSrcweir         osvi.dwOSVersionInfoSize = sizeof(osvi);
84*cdf0e10cSrcweir         GetVersionEx(&osvi);
85*cdf0e10cSrcweir 
86*cdf0e10cSrcweir         return ((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
87*cdf0e10cSrcweir                 ((osvi.dwMajorVersion >= 5) && (osvi.dwMinorVersion >= 1)));
88*cdf0e10cSrcweir     }
89*cdf0e10cSrcweir 
90*cdf0e10cSrcweir     /* Calculate where to position the signet image.
91*cdf0e10cSrcweir        On Windows ME we need to shift the signet a
92*cdf0e10cSrcweir        little bit to the left because Windows ME
93*cdf0e10cSrcweir        puts an overlay icon to the lower right
94*cdf0e10cSrcweir        corner of a thumbnail image so that our signet
95*cdf0e10cSrcweir        we be hidden. */
96*cdf0e10cSrcweir     Gdiplus::Point CalcSignetPosition(
97*cdf0e10cSrcweir         const Gdiplus::Rect& canvas, const Gdiplus::Rect& thumbnail_border, const Gdiplus::Rect& signet)
98*cdf0e10cSrcweir     {
99*cdf0e10cSrcweir         int x = 0;
100*cdf0e10cSrcweir         int y = 0;
101*cdf0e10cSrcweir         int hoffset = canvas.GetRight() - thumbnail_border.GetRight();
102*cdf0e10cSrcweir         int voffset = canvas.GetBottom() - thumbnail_border.GetBottom();
103*cdf0e10cSrcweir 
104*cdf0e10cSrcweir         if (hoffset > voffset)
105*cdf0e10cSrcweir         {
106*cdf0e10cSrcweir             x = thumbnail_border.GetRight() - signet.GetRight() + min(signet.GetRight() / 2, hoffset);
107*cdf0e10cSrcweir             y = thumbnail_border.GetBottom() - signet.GetBottom();
108*cdf0e10cSrcweir         }
109*cdf0e10cSrcweir         else
110*cdf0e10cSrcweir         {
111*cdf0e10cSrcweir             x = thumbnail_border.GetRight() - signet.GetRight();
112*cdf0e10cSrcweir             y = thumbnail_border.GetBottom() - signet.GetBottom() + min(signet.GetBottom() / 2, voffset);
113*cdf0e10cSrcweir         }
114*cdf0e10cSrcweir 
115*cdf0e10cSrcweir         if (!IsWindowsXP())
116*cdf0e10cSrcweir             x -= 15;
117*cdf0e10cSrcweir 
118*cdf0e10cSrcweir         return Gdiplus::Point(x,y);
119*cdf0e10cSrcweir     }
120*cdf0e10cSrcweir }
121*cdf0e10cSrcweir 
122*cdf0e10cSrcweir class StreamOnZipBuffer : public IStream
123*cdf0e10cSrcweir {
124*cdf0e10cSrcweir public:
125*cdf0e10cSrcweir     StreamOnZipBuffer(const ZipFile::ZipContentBuffer_t& zip_buffer);
126*cdf0e10cSrcweir 
127*cdf0e10cSrcweir     // IUnknown
128*cdf0e10cSrcweir     virtual ULONG STDMETHODCALLTYPE AddRef();
129*cdf0e10cSrcweir     virtual ULONG STDMETHODCALLTYPE Release( void);
130*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject);
131*cdf0e10cSrcweir 
132*cdf0e10cSrcweir     // IStream
133*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead);
134*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE Write(void const *pv, ULONG cb, ULONG *pcbWritten);
135*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition);
136*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize);
137*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten);
138*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags);
139*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE Revert(void);
140*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType);
141*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType);
142*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag);
143*cdf0e10cSrcweir     virtual HRESULT STDMETHODCALLTYPE Clone(IStream **ppstm);
144*cdf0e10cSrcweir 
145*cdf0e10cSrcweir private:
146*cdf0e10cSrcweir     LONG ref_count_;
147*cdf0e10cSrcweir     const ZipFile::ZipContentBuffer_t& ref_zip_buffer_;
148*cdf0e10cSrcweir     size_t pos_;
149*cdf0e10cSrcweir };
150*cdf0e10cSrcweir 
151*cdf0e10cSrcweir StreamOnZipBuffer::StreamOnZipBuffer(const ZipFile::ZipContentBuffer_t& zip_buffer) :
152*cdf0e10cSrcweir     ref_count_(1),
153*cdf0e10cSrcweir     ref_zip_buffer_(zip_buffer),
154*cdf0e10cSrcweir     pos_(0)
155*cdf0e10cSrcweir {
156*cdf0e10cSrcweir }
157*cdf0e10cSrcweir 
158*cdf0e10cSrcweir // IUnknown methods
159*cdf0e10cSrcweir 
160*cdf0e10cSrcweir ULONG STDMETHODCALLTYPE StreamOnZipBuffer::AddRef(void)
161*cdf0e10cSrcweir {
162*cdf0e10cSrcweir     return InterlockedIncrement(&ref_count_);
163*cdf0e10cSrcweir }
164*cdf0e10cSrcweir 
165*cdf0e10cSrcweir ULONG STDMETHODCALLTYPE StreamOnZipBuffer::Release( void)
166*cdf0e10cSrcweir {
167*cdf0e10cSrcweir     long refcnt = InterlockedDecrement(&ref_count_);
168*cdf0e10cSrcweir 
169*cdf0e10cSrcweir     if (0 == ref_count_)
170*cdf0e10cSrcweir         delete this;
171*cdf0e10cSrcweir 
172*cdf0e10cSrcweir     return refcnt;
173*cdf0e10cSrcweir }
174*cdf0e10cSrcweir 
175*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
176*cdf0e10cSrcweir {
177*cdf0e10cSrcweir     *ppvObject = 0;
178*cdf0e10cSrcweir     IUnknown* pUnk = 0;
179*cdf0e10cSrcweir 
180*cdf0e10cSrcweir     if ((IID_IUnknown == riid) || (IID_IStream == riid))
181*cdf0e10cSrcweir     {
182*cdf0e10cSrcweir         pUnk = static_cast<IStream*>(this);
183*cdf0e10cSrcweir         pUnk->AddRef();
184*cdf0e10cSrcweir         *ppvObject = pUnk;
185*cdf0e10cSrcweir         return S_OK;
186*cdf0e10cSrcweir     }
187*cdf0e10cSrcweir     return E_NOINTERFACE;
188*cdf0e10cSrcweir }
189*cdf0e10cSrcweir 
190*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Read(void *pv, ULONG cb, ULONG *pcbRead)
191*cdf0e10cSrcweir {
192*cdf0e10cSrcweir     if (pv == NULL)
193*cdf0e10cSrcweir         return STG_E_INVALIDPOINTER;
194*cdf0e10cSrcweir 
195*cdf0e10cSrcweir     size_t size = ref_zip_buffer_.size();
196*cdf0e10cSrcweir 
197*cdf0e10cSrcweir     if (pos_ > size)
198*cdf0e10cSrcweir         return S_FALSE;
199*cdf0e10cSrcweir 
200*cdf0e10cSrcweir     char* p = reinterpret_cast<char*>(pv);
201*cdf0e10cSrcweir     ULONG read = 0;
202*cdf0e10cSrcweir 
203*cdf0e10cSrcweir     for ( ;(pos_ < size) && (cb > 0); pos_++, cb--, read++)
204*cdf0e10cSrcweir         *p++ = ref_zip_buffer_[pos_];
205*cdf0e10cSrcweir 
206*cdf0e10cSrcweir     if (pcbRead)
207*cdf0e10cSrcweir         *pcbRead = read;
208*cdf0e10cSrcweir 
209*cdf0e10cSrcweir     return S_OK;
210*cdf0e10cSrcweir }
211*cdf0e10cSrcweir 
212*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *)
213*cdf0e10cSrcweir {
214*cdf0e10cSrcweir     __int64 size = (__int64) ref_zip_buffer_.size();
215*cdf0e10cSrcweir     __int64 p = 0;
216*cdf0e10cSrcweir 
217*cdf0e10cSrcweir     switch (dwOrigin)
218*cdf0e10cSrcweir     {
219*cdf0e10cSrcweir         case STREAM_SEEK_SET:
220*cdf0e10cSrcweir             break;
221*cdf0e10cSrcweir         case STREAM_SEEK_CUR:
222*cdf0e10cSrcweir             p = (__int64) pos_;
223*cdf0e10cSrcweir             break;
224*cdf0e10cSrcweir         case STREAM_SEEK_END:
225*cdf0e10cSrcweir             p = size - 1;
226*cdf0e10cSrcweir             break;
227*cdf0e10cSrcweir    }
228*cdf0e10cSrcweir 
229*cdf0e10cSrcweir    HRESULT hr = STG_E_INVALIDFUNCTION;
230*cdf0e10cSrcweir 
231*cdf0e10cSrcweir    p += dlibMove.QuadPart;
232*cdf0e10cSrcweir 
233*cdf0e10cSrcweir    if ( ( p >= 0 ) && (p < size) )
234*cdf0e10cSrcweir    {
235*cdf0e10cSrcweir         pos_ = (size_t) p;
236*cdf0e10cSrcweir         hr = S_OK;
237*cdf0e10cSrcweir    }
238*cdf0e10cSrcweir    return hr;
239*cdf0e10cSrcweir }
240*cdf0e10cSrcweir 
241*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
242*cdf0e10cSrcweir {
243*cdf0e10cSrcweir     if (pstatstg == NULL)
244*cdf0e10cSrcweir         return STG_E_INVALIDPOINTER;
245*cdf0e10cSrcweir 
246*cdf0e10cSrcweir     ZeroMemory(pstatstg, sizeof(STATSTG));
247*cdf0e10cSrcweir 
248*cdf0e10cSrcweir     if (grfStatFlag == STATFLAG_DEFAULT)
249*cdf0e10cSrcweir     {
250*cdf0e10cSrcweir         size_t sz = 4 * sizeof(wchar_t);
251*cdf0e10cSrcweir         wchar_t* name = reinterpret_cast<wchar_t*>(CoTaskMemAlloc(sz));
252*cdf0e10cSrcweir         ZeroMemory(name, sz);
253*cdf0e10cSrcweir         memcpy(name, L"png", 3 * sizeof(wchar_t));
254*cdf0e10cSrcweir         pstatstg->pwcsName = name;
255*cdf0e10cSrcweir     }
256*cdf0e10cSrcweir 
257*cdf0e10cSrcweir     pstatstg->type = STGTY_LOCKBYTES;
258*cdf0e10cSrcweir 
259*cdf0e10cSrcweir     ULARGE_INTEGER uli;
260*cdf0e10cSrcweir     uli.LowPart = ref_zip_buffer_.size();
261*cdf0e10cSrcweir     uli.HighPart = 0;
262*cdf0e10cSrcweir 
263*cdf0e10cSrcweir     pstatstg->cbSize = uli;
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir     return S_OK;
266*cdf0e10cSrcweir }
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Write(void const *, ULONG, ULONG *)
269*cdf0e10cSrcweir { return E_NOTIMPL; }
270*cdf0e10cSrcweir 
271*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::SetSize(ULARGE_INTEGER)
272*cdf0e10cSrcweir { return E_NOTIMPL; }
273*cdf0e10cSrcweir 
274*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::CopyTo(IStream *, ULARGE_INTEGER, ULARGE_INTEGER *, ULARGE_INTEGER *)
275*cdf0e10cSrcweir { return E_NOTIMPL; }
276*cdf0e10cSrcweir 
277*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Commit(DWORD)
278*cdf0e10cSrcweir { return E_NOTIMPL; }
279*cdf0e10cSrcweir 
280*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Revert(void)
281*cdf0e10cSrcweir { return E_NOTIMPL; }
282*cdf0e10cSrcweir 
283*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD)
284*cdf0e10cSrcweir { return E_NOTIMPL; }
285*cdf0e10cSrcweir 
286*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD)
287*cdf0e10cSrcweir { return E_NOTIMPL; }
288*cdf0e10cSrcweir 
289*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Clone(IStream **)
290*cdf0e10cSrcweir {  return E_NOTIMPL; }
291*cdf0e10cSrcweir 
292*cdf0e10cSrcweir 
293*cdf0e10cSrcweir //#########################################
294*cdf0e10cSrcweir 
295*cdf0e10cSrcweir 
296*cdf0e10cSrcweir CThumbviewer::CThumbviewer(long RefCnt) :
297*cdf0e10cSrcweir     ref_count_(RefCnt)
298*cdf0e10cSrcweir {
299*cdf0e10cSrcweir     InterlockedIncrement(&g_DllRefCnt);
300*cdf0e10cSrcweir 
301*cdf0e10cSrcweir     thumbnail_size_.cx = 0;
302*cdf0e10cSrcweir     thumbnail_size_.cy = 0;
303*cdf0e10cSrcweir 
304*cdf0e10cSrcweir     Gdiplus::GdiplusStartupInput gdiplusStartupInput;
305*cdf0e10cSrcweir     Gdiplus::GdiplusStartup(&gdiplus_token_, &gdiplusStartupInput, NULL);
306*cdf0e10cSrcweir 
307*cdf0e10cSrcweir     ZipFile::ZipContentBuffer_t img_data;
308*cdf0e10cSrcweir     internal::LoadSignetImageFromResource(img_data);
309*cdf0e10cSrcweir     IStream* stream = new StreamOnZipBuffer(img_data);
310*cdf0e10cSrcweir     signet_ = new Gdiplus::Bitmap(stream, TRUE);
311*cdf0e10cSrcweir     stream->Release();
312*cdf0e10cSrcweir }
313*cdf0e10cSrcweir 
314*cdf0e10cSrcweir CThumbviewer::~CThumbviewer()
315*cdf0e10cSrcweir {
316*cdf0e10cSrcweir     delete signet_;
317*cdf0e10cSrcweir     Gdiplus::GdiplusShutdown(gdiplus_token_);
318*cdf0e10cSrcweir     InterlockedDecrement(&g_DllRefCnt);
319*cdf0e10cSrcweir }
320*cdf0e10cSrcweir 
321*cdf0e10cSrcweir // IUnknown methods
322*cdf0e10cSrcweir 
323*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE CThumbviewer::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
324*cdf0e10cSrcweir {
325*cdf0e10cSrcweir     *ppvObject = 0;
326*cdf0e10cSrcweir     IUnknown* pUnk = 0;
327*cdf0e10cSrcweir 
328*cdf0e10cSrcweir     if ((IID_IUnknown == riid) || (IID_IPersistFile == riid))
329*cdf0e10cSrcweir     {
330*cdf0e10cSrcweir         pUnk = static_cast<IPersistFile*>(this);
331*cdf0e10cSrcweir         pUnk->AddRef();
332*cdf0e10cSrcweir         *ppvObject = pUnk;
333*cdf0e10cSrcweir         return S_OK;
334*cdf0e10cSrcweir     }
335*cdf0e10cSrcweir     else if (IID_IExtractImage == riid)
336*cdf0e10cSrcweir     {
337*cdf0e10cSrcweir         pUnk = static_cast<IExtractImage*>(this);
338*cdf0e10cSrcweir         pUnk->AddRef();
339*cdf0e10cSrcweir         *ppvObject = pUnk;
340*cdf0e10cSrcweir         return S_OK;
341*cdf0e10cSrcweir     }
342*cdf0e10cSrcweir     return E_NOINTERFACE;
343*cdf0e10cSrcweir }
344*cdf0e10cSrcweir 
345*cdf0e10cSrcweir ULONG STDMETHODCALLTYPE CThumbviewer::AddRef(void)
346*cdf0e10cSrcweir {
347*cdf0e10cSrcweir     return InterlockedIncrement(&ref_count_);
348*cdf0e10cSrcweir }
349*cdf0e10cSrcweir 
350*cdf0e10cSrcweir ULONG STDMETHODCALLTYPE CThumbviewer::Release( void)
351*cdf0e10cSrcweir {
352*cdf0e10cSrcweir     long refcnt = InterlockedDecrement(&ref_count_);
353*cdf0e10cSrcweir 
354*cdf0e10cSrcweir     if (0 == ref_count_)
355*cdf0e10cSrcweir         delete this;
356*cdf0e10cSrcweir 
357*cdf0e10cSrcweir     return refcnt;
358*cdf0e10cSrcweir }
359*cdf0e10cSrcweir 
360*cdf0e10cSrcweir // IExtractImage2 methods
361*cdf0e10cSrcweir 
362*cdf0e10cSrcweir const std::string THUMBNAIL_CONTENT = "Thumbnails/thumbnail.png";
363*cdf0e10cSrcweir 
364*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE CThumbviewer::Extract(HBITMAP *phBmpImage)
365*cdf0e10cSrcweir {
366*cdf0e10cSrcweir     HRESULT hr = E_FAIL;
367*cdf0e10cSrcweir 
368*cdf0e10cSrcweir     try
369*cdf0e10cSrcweir     {
370*cdf0e10cSrcweir         std::wstring fname = getShortPathName( filename_ );
371*cdf0e10cSrcweir         std::auto_ptr<ZipFile> zipfile( new ZipFile( WStringToString( fname ) ) );
372*cdf0e10cSrcweir 
373*cdf0e10cSrcweir         if (zipfile->HasContent(THUMBNAIL_CONTENT))
374*cdf0e10cSrcweir         {
375*cdf0e10cSrcweir             ZipFile::ZipContentBuffer_t thumbnail;
376*cdf0e10cSrcweir             zipfile->GetUncompressedContent(THUMBNAIL_CONTENT, thumbnail);
377*cdf0e10cSrcweir             IStream* stream = new StreamOnZipBuffer(thumbnail);
378*cdf0e10cSrcweir 
379*cdf0e10cSrcweir             Gdiplus::Bitmap thumbnail_png(stream, TRUE);
380*cdf0e10cSrcweir 
381*cdf0e10cSrcweir             if ((thumbnail_png.GetHeight() == 0) || (thumbnail_png.GetWidth() == 0))
382*cdf0e10cSrcweir             {
383*cdf0e10cSrcweir                 stream->Release();
384*cdf0e10cSrcweir                 return E_FAIL;
385*cdf0e10cSrcweir             }
386*cdf0e10cSrcweir 
387*cdf0e10cSrcweir     		HWND hwnd = GetDesktopWindow();
388*cdf0e10cSrcweir     		HDC hdc = GetDC(hwnd);
389*cdf0e10cSrcweir             HDC memDC = CreateCompatibleDC(hdc);
390*cdf0e10cSrcweir 
391*cdf0e10cSrcweir             if (memDC)
392*cdf0e10cSrcweir             {
393*cdf0e10cSrcweir                 UINT offset = 3; // reserve a little border space
394*cdf0e10cSrcweir 
395*cdf0e10cSrcweir                 Gdiplus::Rect canvas(0, 0, thumbnail_size_.cx, thumbnail_size_.cy);
396*cdf0e10cSrcweir                 Gdiplus::Rect canvas_thumbnail(offset, offset, thumbnail_size_.cx - 2 * offset, thumbnail_size_.cy - 2 * offset);
397*cdf0e10cSrcweir 
398*cdf0e10cSrcweir                 Gdiplus::Rect scaledRect = CalcScaledAspectRatio(
399*cdf0e10cSrcweir                     Gdiplus::Rect(0, 0, thumbnail_png.GetWidth(), thumbnail_png.GetHeight()), canvas_thumbnail);
400*cdf0e10cSrcweir 
401*cdf0e10cSrcweir                 struct {
402*cdf0e10cSrcweir                     BITMAPINFOHEADER bi;
403*cdf0e10cSrcweir                     DWORD ct[256];
404*cdf0e10cSrcweir                 } dib;
405*cdf0e10cSrcweir 
406*cdf0e10cSrcweir                 ZeroMemory(&dib, sizeof(dib));
407*cdf0e10cSrcweir 
408*cdf0e10cSrcweir                 dib.bi.biSize = sizeof(BITMAPINFOHEADER);
409*cdf0e10cSrcweir                 dib.bi.biWidth = thumbnail_size_.cx;
410*cdf0e10cSrcweir                 dib.bi.biHeight = thumbnail_size_.cy;
411*cdf0e10cSrcweir                 dib.bi.biPlanes = 1;
412*cdf0e10cSrcweir                 dib.bi.biBitCount = static_cast<WORD>(color_depth_);
413*cdf0e10cSrcweir                 dib.bi.biCompression = BI_RGB;
414*cdf0e10cSrcweir 
415*cdf0e10cSrcweir                 LPVOID lpBits;
416*cdf0e10cSrcweir                 HBITMAP hMemBmp = CreateDIBSection(memDC, (LPBITMAPINFO)&dib, DIB_RGB_COLORS, &lpBits, NULL, 0);
417*cdf0e10cSrcweir                 HGDIOBJ hOldObj = SelectObject(memDC, hMemBmp);
418*cdf0e10cSrcweir 
419*cdf0e10cSrcweir                 Gdiplus::Graphics graphics(memDC);
420*cdf0e10cSrcweir                 Gdiplus::Pen blackPen(Gdiplus::Color(255, 0, 0, 0), 1);
421*cdf0e10cSrcweir 
422*cdf0e10cSrcweir                 Gdiplus::SolidBrush whiteBrush(Gdiplus::Color(255, 255, 255, 255));
423*cdf0e10cSrcweir                 graphics.FillRectangle(&whiteBrush, canvas);
424*cdf0e10cSrcweir 
425*cdf0e10cSrcweir                 scaledRect.X = (canvas.Width - scaledRect.Width) / 2;
426*cdf0e10cSrcweir                 scaledRect.Y = (canvas.Height - scaledRect.Height) / 2;
427*cdf0e10cSrcweir 
428*cdf0e10cSrcweir                 Gdiplus::Rect border_rect(scaledRect.X, scaledRect.Y, scaledRect.Width, scaledRect.Height);
429*cdf0e10cSrcweir                 graphics.DrawRectangle(&blackPen, border_rect);
430*cdf0e10cSrcweir 
431*cdf0e10cSrcweir                 scaledRect.X += 1;
432*cdf0e10cSrcweir                 scaledRect.Y += 1;
433*cdf0e10cSrcweir                 scaledRect.Width -= 1;
434*cdf0e10cSrcweir                 scaledRect.Height -= 1;
435*cdf0e10cSrcweir 
436*cdf0e10cSrcweir                 graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);
437*cdf0e10cSrcweir                 Gdiplus::Status stat = graphics.DrawImage(
438*cdf0e10cSrcweir                     &thumbnail_png, scaledRect, 0 , 0,
439*cdf0e10cSrcweir                     thumbnail_png.GetWidth(), thumbnail_png.GetHeight(), Gdiplus::UnitPixel);
440*cdf0e10cSrcweir 
441*cdf0e10cSrcweir                 /* Add a signet sign to the thumbnail of signed documents */
442*cdf0e10cSrcweir                 if (internal::IsSignedDocument(zipfile.get()))
443*cdf0e10cSrcweir                 {
444*cdf0e10cSrcweir                     double SCALING_FACTOR = 0.6;
445*cdf0e10cSrcweir                     Gdiplus::Rect signet_scaled(
446*cdf0e10cSrcweir                         0, 0, static_cast<INT>(signet_->GetWidth() * SCALING_FACTOR), static_cast<INT>(signet_->GetHeight() * SCALING_FACTOR));
447*cdf0e10cSrcweir                     Gdiplus::Point pos_signet = internal::CalcSignetPosition(canvas_thumbnail, border_rect, signet_scaled);
448*cdf0e10cSrcweir                     Gdiplus::Rect dest(pos_signet.X, pos_signet.Y, signet_scaled.GetRight(), signet_scaled.GetBottom());
449*cdf0e10cSrcweir 
450*cdf0e10cSrcweir                     stat = graphics.DrawImage(
451*cdf0e10cSrcweir                         signet_, dest,
452*cdf0e10cSrcweir                         0, 0, signet_->GetWidth(), signet_->GetHeight(),
453*cdf0e10cSrcweir                         Gdiplus::UnitPixel);
454*cdf0e10cSrcweir                 }
455*cdf0e10cSrcweir 
456*cdf0e10cSrcweir                 if (stat == Gdiplus::Ok)
457*cdf0e10cSrcweir                 {
458*cdf0e10cSrcweir                     *phBmpImage = hMemBmp;
459*cdf0e10cSrcweir                     hr = NOERROR;
460*cdf0e10cSrcweir                 }
461*cdf0e10cSrcweir 
462*cdf0e10cSrcweir                 SelectObject(memDC, hOldObj);
463*cdf0e10cSrcweir                 DeleteDC(memDC);
464*cdf0e10cSrcweir             }
465*cdf0e10cSrcweir 
466*cdf0e10cSrcweir             ReleaseDC(hwnd, hdc);
467*cdf0e10cSrcweir             stream->Release();
468*cdf0e10cSrcweir         }
469*cdf0e10cSrcweir     }
470*cdf0e10cSrcweir     catch(std::exception&)
471*cdf0e10cSrcweir     {
472*cdf0e10cSrcweir         OutputDebugStringFormat( "CThumbviewer Extract ERROR!\n" );
473*cdf0e10cSrcweir         hr = E_FAIL;
474*cdf0e10cSrcweir     }
475*cdf0e10cSrcweir     return hr;
476*cdf0e10cSrcweir }
477*cdf0e10cSrcweir 
478*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE CThumbviewer::GetLocation(
479*cdf0e10cSrcweir     LPWSTR pszPathBuffer, DWORD cchMax, DWORD *pdwPriority, const SIZE *prgSize, DWORD dwRecClrDepth, DWORD *pdwFlags)
480*cdf0e10cSrcweir {
481*cdf0e10cSrcweir     if ((prgSize == NULL) || (pdwFlags == NULL) || ((*pdwFlags & IEIFLAG_ASYNC) && (pdwPriority == NULL)))
482*cdf0e10cSrcweir         return E_INVALIDARG;
483*cdf0e10cSrcweir 
484*cdf0e10cSrcweir     thumbnail_size_ = *prgSize;
485*cdf0e10cSrcweir     color_depth_ = dwRecClrDepth;
486*cdf0e10cSrcweir 
487*cdf0e10cSrcweir     *pdwFlags = IEIFLAG_CACHE; // we don't cache the image
488*cdf0e10cSrcweir 
489*cdf0e10cSrcweir     wcsncpy(pszPathBuffer, filename_.c_str(), cchMax);
490*cdf0e10cSrcweir 
491*cdf0e10cSrcweir     return NOERROR;
492*cdf0e10cSrcweir }
493*cdf0e10cSrcweir 
494*cdf0e10cSrcweir // IPersist methods
495*cdf0e10cSrcweir 
496*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE CThumbviewer::GetClassID(CLSID* pClassID)
497*cdf0e10cSrcweir {
498*cdf0e10cSrcweir     pClassID = const_cast<CLSID*>(&CLSID_THUMBVIEWER_HANDLER);
499*cdf0e10cSrcweir     return S_OK;
500*cdf0e10cSrcweir }
501*cdf0e10cSrcweir 
502*cdf0e10cSrcweir // IPersistFile methods
503*cdf0e10cSrcweir 
504*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE CThumbviewer::Load(LPCOLESTR pszFileName, DWORD)
505*cdf0e10cSrcweir {
506*cdf0e10cSrcweir     filename_ = pszFileName;
507*cdf0e10cSrcweir     return S_OK;
508*cdf0e10cSrcweir }
509*cdf0e10cSrcweir 
510*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE CThumbviewer::IsDirty()
511*cdf0e10cSrcweir { return E_NOTIMPL; }
512*cdf0e10cSrcweir 
513*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE CThumbviewer::Save(LPCOLESTR, BOOL)
514*cdf0e10cSrcweir { return E_NOTIMPL; }
515*cdf0e10cSrcweir 
516*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE CThumbviewer::SaveCompleted(LPCOLESTR)
517*cdf0e10cSrcweir { return E_NOTIMPL; }
518*cdf0e10cSrcweir 
519*cdf0e10cSrcweir HRESULT STDMETHODCALLTYPE CThumbviewer::GetCurFile(LPOLESTR __RPC_FAR*)
520*cdf0e10cSrcweir { return E_NOTIMPL; }
521*cdf0e10cSrcweir 
522*cdf0e10cSrcweir 
523*cdf0e10cSrcweir Gdiplus::Rect CThumbviewer::CalcScaledAspectRatio(Gdiplus::Rect src, Gdiplus::Rect dest)
524*cdf0e10cSrcweir {
525*cdf0e10cSrcweir     Gdiplus::Rect result;
526*cdf0e10cSrcweir     if (src.Width >= src.Height)
527*cdf0e10cSrcweir         result = Gdiplus::Rect(0, 0, dest.Width, src.Height * dest.Width / src.Width);
528*cdf0e10cSrcweir     else
529*cdf0e10cSrcweir         result = Gdiplus::Rect(0, 0, src.Width * dest.Height / src.Height, dest.Height);
530*cdf0e10cSrcweir 
531*cdf0e10cSrcweir     return result;
532*cdf0e10cSrcweir }
533*cdf0e10cSrcweir 
534