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

458 lines
9.9 KiB
C++

/******Module*Header**\
* Module Name: ctngen.cpp
*
* Implementation of the IThumbnailExtractor interface
*
* Created: 14-Nov-1997
* Author: Ori Gershony [orig]
*
* Copyright (c) 1996 Microsoft Corporation
\****/
#include "objbase.h"
#include "stdafx.h"
#include "tnail.h"
#include "ctngen.h"
extern CHAR THUMBNAIL_CLIPDATA[];
// Ntfs Flat File objects do not respond to QI for IID_IStorage any more.
// If you really need an IStorage* and you are a system component then
// you can use IID_IFlatStorage. (IFlatStorage does not marshal)
EXTERN_C const IID IID_IFlatStorage = { /* b29d6138-b92f-11d1-83ee-00c04fc2c6d4 */
0xb29d6138,
0xb92f,
0x11d1,
{0x83, 0xee, 0x00, 0xc0, 0x4f, 0xc2, 0xc6, 0xd4}
};
// Global critical section to make code single threaded.
// Actually the code doesn't look to bad, but we are calling the JPG library
// and I know nothing about that. Perhaps with alot more thought, study and
// investigation this code could be shown to be thread safe.
CRITICAL_SECTION g_csTNGEN;
/******Public*Routine******\
* CThumbnailFCNContainer::CThumbnailFCNContainer
*
* Constructor for CThumbnailFCNContainer
*
* Arguments:
*
* Return Value:
*
* none
*
* History:
*
* 14-Nov-1997 -by- Ori Gershony [orig]
*
\****/
CThumbnailFCNContainer::CThumbnailFCNContainer(VOID)
{
TN_Initialize();
}
/******Public*Routine******\
* CThumbnailFCNContainer::~CThumbnailFCNContainer
*
* Destructor for CThumbnailFCNContainer
*
* Arguments:
*
* Return Value:
*
* none
*
* History:
*
* 14-Nov-1997 -by- Ori Gershony [orig]
*
\****/
CThumbnailFCNContainer::~CThumbnailFCNContainer(VOID)
{
TN_Uninitialize();
}
/******Public*Routine******\
* CThumbnailFCNContainer::OnFileUpdated
*
* This method notifies us that the file indicated by pStg has been
* modified and therefore we should generate a new thumbnail for it.
*
* Arguments:
*
* pStg -- A pointer to a storage of the file which was modified
*
* Return Value:
*
* NOERROR upon success, or appropriate error code
*
* History:
*
* 14-Nov-1997 -by- Ori Gershony [orig]
*
\****/
STDMETHODIMP
CThumbnailFCNContainer::OnFileUpdated(
IStorage *pStg
)
{
HRESULT retVal;
IStream *pInputStream;
IPropertySetStorage *pPropSetStg=NULL;
// A little bit of validation won't hurt, and can protect us against
// bad callers
if (pStg == NULL)
{
return E_INVALIDARG;
}
EnterCriticalSection ( &g_csTNGEN );
// Get the PropertySetStorage Interface. This also serves as the
// stablizing reference.
retVal = pStg->QueryInterface( IID_IPropertySetStorage,
(PVOID*)&pPropSetStg );
// if (FAILED(retVal))
// {
// return retVal;
// }
// else
// {
// VOID* pvData;
// DWORD cbSize;
// retVal = ReadThumbnail(&pvData, &cbSize, pPropSetStg );
// if (SUCCEEDED(retVal))
// {
// CoTaskMemFree( pvData );
// }
// else
// {
// pPropSetStg->Release();
// return S_OK;
// }
// }
// First open the stream containing image data
retVal = pStg->OpenStream(L"CONTENTS",
NULL,
STGM_READ | STGM_SHARE_EXCLUSIVE | STGM_DIRECT,
0,
&pInputStream);
if (SUCCEEDED(retVal))
{
VOID *pBuffer = (VOID *) LocalAlloc (0, JPEG_BUFFER_SIZE);
if (pBuffer)
{
ULONG ulBufferSize;
FILETIME filetime = { 0 };
retVal = TN_GenerateCompressedThumbnail(pInputStream,
(CHAR *) pBuffer,
&ulBufferSize,
filetime);
pInputStream->Release();
if (SUCCEEDED(retVal))
{
retVal = WriteThumbnail(pBuffer, ulBufferSize, pPropSetStg, FALSE);
}
LocalFree(pBuffer);
}
else
{
// Release pInputStream if memory allocation fails. We can't use a common
// code path for both because WriteThumbnail requires the stream to have already
// been released.
pInputStream->Release();
}
}
pPropSetStg->Release();
LeaveCriticalSection ( &g_csTNGEN );
return retVal;
}
/******Public*Routine******\
* CThumbnailFCNContainer::ExtractThumbnail
*
* Returns a bitmap of the thumbnail for the storage pointed to by pStg
* Note: The caller is responsible for freeing the bitmap pointed to by
* phOutputBitmap by calling DeleteObject!
*
* Arguments:
* pStg -- The storage containing the thumbnail
* ulLength -- The requested length
* ulWidth -- The requested width
* pulOutputLength -- will hold the actual output length
* pulOutputWidth -- will hold the actual output width
* phOutputBitmap -- A pointer that will point to the bitmap containing
* the thumbnail. This will be released by the caller!
*
* Return Value:
*
* NOERROR upon success, or appropriate error code
*
* History:
*
* 14-Nov-1997 -by- Ori Gershony [orig]
*
\****/
STDMETHODIMP
CThumbnailFCNContainer::ExtractThumbnail(
IStorage *pStg,
ULONG ulLength,
ULONG ulHeight,
ULONG *pulOutputLength,
ULONG *pulOutputHeight,
HBITMAP *phOutputBitmap
)
{
HRESULT retVal;
// A little bit of validation won't hurt, and can protect us against
// bad callers
if (pStg == NULL)
{
return E_INVALIDARG;
}
EnterCriticalSection ( &g_csTNGEN );
retVal = SuppressTimestampChanges(pStg);
if (SUCCEEDED(retVal))
{
retVal = ExtractThumbnailHelper(pStg,
ulLength,
ulHeight,
pulOutputLength,
pulOutputHeight,
phOutputBitmap);
}
// If no thumbnail was extracted then generate a thumbnail
// and try again.
if (FAILED(retVal))
{
retVal = OnFileUpdated(pStg);
if (SUCCEEDED(retVal))
{
// Try again--now thumbnail should be there
retVal = ExtractThumbnailHelper(pStg,
ulLength,
ulHeight,
pulOutputLength,
pulOutputHeight,
phOutputBitmap);
}
}
LeaveCriticalSection ( &g_csTNGEN );
return retVal;
}
/******Public*Routine******\
* CThumbnailFCNContainer::ExtractThumbnailHelper
*
* Returns a bitmap of the thumbnail for the storage pointed to by pStg
* Note: The caller is responsible for freeing the bitmap pointed to by
* phOutputBitmap by calling DeleteObject!
*
* Arguments:
* pStg -- The storage containing the thumbnail
* ulLength -- The requested length
* ulWidth -- The requested width
* pulOutputLength -- will hold the actual output length
* pulOutputWidth -- will hold the actual output width
* phOutputBitmap -- A pointer that will point to the bitmap containing
* the thumbnail. This will be released by the caller!
*
* Return Value:
*
* NOERROR upon success, or appropriate error code
*
* History:
*
* 14-Nov-1997 -by- Ori Gershony [orig]
*
\****/
STDMETHODIMP
CThumbnailFCNContainer::ExtractThumbnailHelper(
IStorage *pStg,
ULONG ulLength,
ULONG ulHeight,
ULONG *pulOutputLength,
ULONG *pulOutputHeight,
HBITMAP *phOutputBitmap
)
{
HRESULT retVal;
IPropertySetStorage *pPropSetStg;
// Read the thumbnail
VOID *pBuffer=NULL;
ULONG ulBufferSize=0;
retVal = pStg->QueryInterface( IID_IPropertySetStorage,
(PVOID*) & pPropSetStg );
if (SUCCEEDED(retVal))
{
retVal = ReadThumbnail(&pBuffer, &ulBufferSize, pPropSetStg);
if (SUCCEEDED(retVal))
{
retVal = TN_GenerateThumbnailImage(
(CHAR *) pBuffer,
ulLength,
ulHeight,
pulOutputLength,
pulOutputHeight,
phOutputBitmap);
CoTaskMemFree(pBuffer);
}
pPropSetStg->Release();
}
return retVal;
}
/******Public*Routine******\
* CThumbnailFCNContainer::GetTimeStamp
*
* This method obtains the timestamp for the last modification of the CONTENTS
* stream of pStg
*
*
* Arguments:
*
* pStg -- A pointer to a storage of the file
* pFileTime -- A pointer to a variable which will receive the timestamp
*
* Return Value:
*
* NOERROR upon success, or appropriate error code
*
* History:
*
* 30-Dec-1997 -by- Ori Gershony [orig]
*
\****/
STDMETHODIMP
CThumbnailFCNContainer::GetTimeStamp(
IPropertySetStorage *pPropSetStg,
FILETIME *pFiletime
)
{
// Obtain the timestamp
HRESULT retVal;
IStorage *pStg=NULL;
STATSTG statstg;
retVal = pPropSetStg->QueryInterface( IID_IFlatStorage, (PVOID*) & pStg );
if(SUCCEEDED(retVal))
{
retVal = pStg->Stat(&statstg, STATFLAG_NONAME);
if (SUCCEEDED(retVal))
{
*pFiletime = statstg.mtime;
}
pStg->Release();
}
return retVal;
}
/******Public*Routine******\
* CThumbnailFCNContainer::SuppressTimestampChanges
*
* This method suppresses timestamp notifications for a storage
*
*
* Arguments:
*
* punkStorage -- A pointer to a storage of the file
*
* Return Value:
*
* NOERROR upon success, or appropriate error code
*
* History:
*
* 30-Dec-1997 -by- Ori Gershony [orig]
*
\****/
STDMETHODIMP
CThumbnailFCNContainer::SuppressTimestampChanges(
IUnknown *punkStorage
)
{
HRESULT retVal;
// Supress file time modification
ITimeAndNoticeControl *pITimeAndNoticeControl;
retVal = punkStorage->QueryInterface(IID_ITimeAndNoticeControl,
(VOID **) &pITimeAndNoticeControl);
if (SUCCEEDED(retVal))
{
retVal = pITimeAndNoticeControl->SuppressChanges(1,0);
if (FAILED(retVal))
retVal = pITimeAndNoticeControl->SuppressChanges(0,0);
pITimeAndNoticeControl->Release();
}
return retVal;
}