2020-09-30 17:12:32 +02:00

510 lines
14 KiB
C++

#include "precomp.h"
HRESULT GetMediaManagerThumbnail( IPropertyStorage * pPropStg,
const SIZE * prgSize,
DWORD dwClrDepth,
HPALETTE hpal,
BOOL fOrigSize,
HBITMAP * phBmpThumbnail );
HRESULT GetDocFileThumbnail( IPropertyStorage * pPropStg,
const SIZE * prgSize,
DWORD dwClrDepth,
HPALETTE hpal,
BOOL fOrigSize,
HBITMAP * phBmpThumbnail );
// PACKEDMETA struct for DocFile thumbnails.
typedef struct
{
WORD mm;
WORD xExt;
WORD yExt;
WORD dummy;
} PACKEDMETA;
VOID CalcMetaFileSize( HDC hDC, PACKEDMETA * pMeta, const SIZEL * prgSize, RECT * pRect);
WCHAR const c_szMIC[] = L".MIC";
WCHAR c_szThumbnailProp[] = L"Thumbnail";
CDocFileHandler::CDocFileHandler()
{
m_pszPath = NULL;
}
CDocFileHandler::~CDocFileHandler()
{
if ( m_pszPath )
{
LocalFree( m_pszPath );
}
}
STDMETHODIMP CDocFileHandler::GetLocation ( LPWSTR szFileName,
DWORD cchMax,
DWORD * pdwPriority,
const SIZE * prgSize,
DWORD dwRecClrDepth,
DWORD *pdwFlags )
{
if ( !szFileName || !pdwFlags || ((*pdwFlags & IEIFLAG_ASYNC) && !pdwPriority ) || !prgSize )
{
return E_INVALIDARG;
}
if ( !m_pszPath )
{
return E_UNEXPECTED;
}
m_rgSize = *prgSize;
m_dwRecClrDepth = dwRecClrDepth;
// just copy the current path into the buffer as we do not share thumbnails...
StrCpyNW( szFileName, m_pszPath, cchMax );
HRESULT hr = NOERROR;
if ( *pdwFlags & IEIFLAG_ASYNC )
{
// we support async
hr = E_PENDING;
*pdwPriority = PRIORITY_NORMAL;
}
m_fOrigSize = BOOLIFY(*pdwFlags & IEIFLAG_ORIGSIZE );
// we don't want it cached....
*pdwFlags &= ~IEIFLAG_CACHE;
return hr;
}
STDMETHODIMP CDocFileHandler::Extract ( HBITMAP * phBmpThumbnail)
{
if ( !m_pszPath )
{
return E_UNEXPECTED;
}
if ( !phBmpThumbnail )
{
return E_INVALIDARG;
}
// find the extension.....
LPWSTR pszExt = StrRChrW( m_pszPath, NULL, WCHAR('.'));
if ( !pszExt )
{
return E_UNEXPECTED;
}
LPSTORAGE pStorage = NULL;
HRESULT hr = StgOpenStorage( m_pszPath,
NULL,
STGM_READ | STGM_SHARE_EXCLUSIVE,
NULL,
NULL,
& pStorage );
if ( FAILED( hr ))
{
return hr;
}
LPPROPERTYSETSTORAGE pPropSetStg = NULL;
hr = pStorage->QueryInterface( IID_IPropertySetStorage, (LPVOID *) &pPropSetStg );
if ( FAILED( hr ))
{
pStorage->Release();
return hr;
}
FMTID fmtidPropSet = FMTID_SummaryInformation;
BOOL fMediaManager = FALSE;
// "MIC" Microsoft Image Composer files needs special casing because they use
// the Media Manager internal thumbnail propertyset ... (by what it would be like
// to be standard for once ....)
if ( StrCmpIW( pszExt, c_szMIC ) == 0 )
{
// switch to the Media Manager thumbnail propertyset....
fmtidPropSet = FMTID_CmsThumbnailPropertySet;
fMediaManager = TRUE;
}
LPPROPERTYSTORAGE pPropSet;
hr = pPropSetStg->Open( fmtidPropSet,
STGM_READ | STGM_SHARE_EXCLUSIVE,
&pPropSet );
if ( FAILED( hr ))
{
pStorage->Release();
pPropSetStg->Release();
return hr;
}
HPALETTE hpal = NULL;
if ( m_dwRecClrDepth == 8 )
{
hpal = SHCreateShellPalette( NULL );
}
else if ( m_dwRecClrDepth < 8 )
{
hpal = (HPALETTE) GetStockObject( DEFAULT_PALETTE );
}
if ( fMediaManager )
{
hr = GetMediaManagerThumbnail( pPropSet, &m_rgSize, m_dwRecClrDepth, hpal, m_fOrigSize, phBmpThumbnail );
}
else
{
hr = GetDocFileThumbnail( pPropSet, &m_rgSize, m_dwRecClrDepth, hpal, m_fOrigSize, phBmpThumbnail );
}
if ( hpal )
{
DeletePalette( hpal );
}
pPropSet->Release();
pPropSetStg->Release();
pStorage->Release();
return hr;
}
STDMETHODIMP CDocFileHandler::GetDateStamp ( FILETIME * pftDateStamp )
{
Assert( pftDateStamp );
HANDLE hFind;
WIN32_FIND_DATAW rgData;
hFind = FindFirstFileWrapW( m_pszPath, &rgData );
if ( INVALID_HANDLE_VALUE != hFind )
{
*pftDateStamp = rgData.ftLastWriteTime;
FindClose( hFind );
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP CDocFileHandler::Load(LPCOLESTR pszFileName, DWORD dwMode)
{
// ignore the DWORD dwMode, as we only ever open in read mode....
if ( !pszFileName )
{
return E_INVALIDARG;
}
DWORD dwAttrs = GetFileAttributesWrapW( pszFileName );
if (( dwAttrs != (DWORD) -1) && (dwAttrs & FILE_ATTRIBUTE_OFFLINE ))
{
return E_FAIL;
}
if ( m_pszPath )
{
LocalFree( m_pszPath );
}
UINT cLen = lstrlenW( pszFileName ) + 1;
m_pszPath = (LPWSTR) LocalAlloc( LPTR, cLen * sizeof(WCHAR));
if ( !m_pszPath )
{
return E_OUTOFMEMORY;
}
StrCpyW( m_pszPath, pszFileName );
return NOERROR;
}
HRESULT GetMediaManagerThumbnail( IPropertyStorage * pPropStg,
const SIZE * prgSize,
DWORD dwClrDepth,
HPALETTE hpal,
BOOL fOrigSize,
HBITMAP * phBmpThumbnail )
{
// current version of media manager simply stores the DIB data in a under a
// named property Thumbnail...
PROPSPEC propSpec;
PROPVARIANT pvarResult;
ZeroMemory( &pvarResult, sizeof( pvarResult ));
if ( !pPropStg || !prgSize )
{
return E_INVALIDARG;
}
// read the thumbnail property from the property storage.
propSpec.ulKind = PRSPEC_LPWSTR;
propSpec.lpwstr = c_szThumbnailProp;
HRESULT hr = pPropStg->ReadMultiple( 1, &propSpec, &pvarResult );
if( SUCCEEDED( hr ) )
{
BITMAPINFO * pbi;
LPVOID pBits;
pbi = ( BITMAPINFO * )pvarResult.blob.pBlobData;
pBits = CalcBitsOffsetInDIB( pbi );
hr = E_FAIL;
if ( pbi->bmiHeader.biSize == sizeof( BITMAPINFOHEADER ) )
{
if ( ConvertDIBSECTIONToThumbnail( pbi, pBits, phBmpThumbnail, prgSize, dwClrDepth, hpal, 15, fOrigSize ))
{
hr = NOERROR;
}
}
PropVariantClear( &pvarResult );
}
return hr;
}
HRESULT GetDocFileThumbnail( IPropertyStorage * pPropStg,
const SIZE * prgSize,
DWORD dwClrDepth,
HPALETTE hpal,
BOOL fOrigSize,
HBITMAP * phBmpThumbnail )
{
PROPSPEC propSpec;
PROPVARIANT pvarResult;
HDC hDC = GetDC( GetDesktopWindow( ) );
HBITMAP hBmp = NULL;
HRESULT hr = S_OK;
if ( !pPropStg || !prgSize )
{
return E_INVALIDARG;
}
HDC hMemDC = CreateCompatibleDC( hDC );
if ( hMemDC == NULL )
{
return E_OUTOFMEMORY;
}
// read the thumbnail property from the property storage.
propSpec.ulKind = PRSPEC_PROPID;
propSpec.propid = PIDSI_THUMBNAIL;
hr = pPropStg->ReadMultiple( 1, &propSpec, &pvarResult );
if( SUCCEEDED( hr ) )
{
// make sure we are dealing with a clipboard format. CLIPDATA
if ( ( pvarResult.vt == VT_CF ) && ( pvarResult.pclipdata->ulClipFmt == -1 ) )
{
LPDWORD pdwCF = ( LPDWORD )pvarResult.pclipdata->pClipData;
LPBYTE pStruct = pvarResult.pclipdata->pClipData + sizeof( DWORD );
if ( *pdwCF == CF_METAFILEPICT )
{
SetMapMode( hMemDC, MM_TEXT );
// handle thumbnail that is a metafile.
PACKEDMETA * pMeta = ( PACKEDMETA * )pStruct;
LPBYTE pData = pStruct + sizeof( PACKEDMETA );
HMETAFILE hMF;
RECT rect;
UINT cbSize = pvarResult.pclipdata->cbSize - sizeof( DWORD ) - sizeof( pMeta->mm ) -
sizeof( pMeta->xExt ) - sizeof( pMeta->yExt ) - sizeof( pMeta->dummy );
// save as a metafile.
hMF = SetMetaFileBitsEx( cbSize, pData );
if ( hMF )
{
SIZE rgNewSize;
// use the mapping mode to calc the current size
CalcMetaFileSize( hMemDC, pMeta, prgSize, & rect );
CalculateAspectRatio( prgSize, &rect );
if ( fOrigSize )
{
// use the aspect rect to refigure the size...
rgNewSize.cx = rect.right - rect.left;
rgNewSize.cy = rect.bottom - rect.top;
prgSize = &rgNewSize;
// adjust the rect to be the same as the size (which is the size of the metafile)
rect.right -= rect.left;
rect.bottom -= rect.top;
rect.left = 0;
rect.top = 0;
}
if ( CreateSizedDIBSECTION( prgSize, dwClrDepth, hpal, NULL, &hBmp, NULL, NULL ))
{
HGDIOBJ hOldBmp = SelectObject( hMemDC, hBmp );
HGDIOBJ hBrush = GetStockObject( THUMBNAIL_BACKGROUND_BRUSH );
HGDIOBJ hOldBrush = SelectObject( hMemDC, hBrush );
HGDIOBJ hPen = GetStockObject( THUMBNAIL_BACKGROUND_PEN );
HGDIOBJ hOldPen = SelectObject( hMemDC, hPen );
Rectangle( hMemDC, 0, 0, prgSize->cx, prgSize->cy );
SelectObject( hMemDC, hOldBrush );
SelectObject( hMemDC, hOldPen );
int iXBorder = 0;
int iYBorder = 0;
if ( rect.left == 0 )
{
iXBorder ++;
}
if ( rect.top == 0 )
{
iYBorder ++;
}
SetViewportExtEx( hMemDC, rect.right - rect.left - 2 * iXBorder, rect.bottom - rect.top - 2 * iYBorder, NULL );
SetViewportOrgEx( hMemDC, rect.left + iXBorder, rect.top + iYBorder, NULL );
SetMapMode( hMemDC, pMeta->mm );
// play the metafile.
BOOL bRet = PlayMetaFile( hMemDC, hMF );
if ( bRet )
{
*phBmpThumbnail = hBmp ;
if ( *phBmpThumbnail == NULL )
{
// unable to get thumbnail bitmap.
hr = E_FAIL;
}
}
DeleteMetaFile( hMF );
SelectObject( hMemDC, hOldBmp );
if ( FAILED( hr ) && hBmp )
{
DeleteObject( hBmp );
}
}
else
{
hr = DV_E_CLIPFORMAT;
}
}
}
else if ( *pdwCF == CF_DIB )
{
// handle thumbnail that is a metafile.
BITMAPINFO * pDib = (BITMAPINFO *) pStruct;
if ( pDib->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
{
LPVOID pBits = CalcBitsOffsetInDIB( pDib );
if ( ConvertDIBSECTIONToThumbnail( pDib, pBits, phBmpThumbnail, prgSize, dwClrDepth, hpal, 15, fOrigSize ) == FALSE )
{
hr = DV_E_CLIPFORMAT;
}
}
}
else
{
hr = DV_E_CLIPFORMAT;
}
}
else
{
hr = DV_E_CLIPFORMAT;
}
PropVariantClear( &pvarResult );
}
DeleteDC( hMemDC );
ReleaseDC( GetDesktopWindow( ), hDC );
return hr;
}
VOID CalcMetaFileSize( HDC hDC, PACKEDMETA * prgMeta, const SIZEL * prgSize, RECT * prgRect)
{
Assert( prgMeta && prgRect );
prgRect->left = 0;
prgRect->top = 0;
if ( !prgMeta->xExt || !prgMeta->yExt )
{
// no size, then just use the size rect ...
prgRect->right = prgSize->cx;
prgRect->bottom = prgSize->cy;
}
else
{
// set the mapping mode....
SetMapMode( hDC, prgMeta->mm );
if ( prgMeta->mm == MM_ISOTROPIC || prgMeta->mm == MM_ANISOTROPIC )
{
// we must set the ViewPortExtent and the window extent to get the scaling
SetWindowExtEx( hDC, prgMeta->xExt, prgMeta->yExt, NULL );
SetViewportExtEx( hDC, prgMeta->xExt, prgMeta->yExt, NULL );
}
POINT pt;
pt.x = prgMeta->xExt;
pt.y = prgMeta->yExt;
// convert to pixels....
LPtoDP( hDC, &pt, 1);
prgRect->right = abs( pt.x );
prgRect->bottom = abs( pt.y );
}
}
STDMETHODIMP CDocFileHandler::GetClassID(CLSID * pCLSID )
{
return E_NOTIMPL;
}
STDMETHODIMP CDocFileHandler::IsDirty( )
{
return S_FALSE;
}
STDMETHODIMP CDocFileHandler::Save(LPCOLESTR pszFileName, BOOL fRemember)
{
return E_NOTIMPL;
}
STDMETHODIMP CDocFileHandler::SaveCompleted(LPCOLESTR pszFileName)
{
return E_NOTIMPL;
}
STDMETHODIMP CDocFileHandler::GetCurFile(LPOLESTR * ppszFileName)
{
return E_NOTIMPL;
}