933 lines
24 KiB
C++
933 lines
24 KiB
C++
//+------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1994 - 1998.
|
|
//
|
|
// File: tnupdr.cxx
|
|
//
|
|
//+------------------------------------------------------------------
|
|
|
|
#include "pch.cxx"
|
|
|
|
#include <filtntfy.h>
|
|
#include "tnupdr.hxx"
|
|
|
|
|
|
EXTERN_C const IID IID_IFlatStorage; /* b29d6138-b92f-11d1-83ee-00c04fc2c6d4 */
|
|
|
|
DECLARE_INFOLEVEL(updr)
|
|
|
|
#define DEB_INFO DEB_USER1
|
|
#define DEB_REGINFO DEB_USER2
|
|
|
|
|
|
#define MIME_TYPES_ROOT L"software\\classes\\Mime\\Database\\Content Type"
|
|
|
|
#define IMAGE_PREFIX L"image/"
|
|
#define IMAGE_PREFIX_LEN 6
|
|
|
|
extern "C" CLSID CLSID_ThumbnailFCNHandler;
|
|
extern "C" CLSID CLSID_ThumbnailUpdater;
|
|
|
|
class CThumbnailCF : public IClassFactory
|
|
{
|
|
public:
|
|
// Constructor
|
|
CThumbnailCF(): _cRefs(1) { }
|
|
|
|
// IUnknown methods
|
|
STDMETHOD (QueryInterface) (REFIID riid, void **ppv);
|
|
STDMETHOD_(ULONG,AddRef) (void);
|
|
STDMETHOD_(ULONG,Release) (void);
|
|
|
|
// IClassFactory methods
|
|
STDMETHOD (CreateInstance)(IUnknown *pUnkOuter, REFIID riid, void **ppv);
|
|
STDMETHOD (LockServer) (BOOL fLock) { return S_OK; }
|
|
|
|
private:
|
|
ULONG _cRefs; // CF reference count
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// Funtion to create a Class Factory Object.
|
|
// This is in form DoATClassCreate() wants.
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
HRESULT GetCThumbnailCF(REFCLSID clsid, REFIID iid, void **ppv)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
CThumbnailCF *pCF=NULL;
|
|
|
|
*ppv = 0;
|
|
|
|
if( ! IsEqualCLSID(clsid, CLSID_ThumbnailUpdater))
|
|
return CLASS_E_CLASSNOTAVAILABLE;
|
|
|
|
pCF = new CThumbnailCF();
|
|
|
|
if( NULL == pCF )
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
hr = pCF->QueryInterface(iid, ppv);
|
|
pCF->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// Hook from the DllgetClassObject routine.
|
|
// This is special because it must start in an Apartment.
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CThumbnail_ApartmentDllGetClassObject(
|
|
REFCLSID clsid,
|
|
REFIID iid,
|
|
void **ppv)
|
|
{
|
|
HRESULT hr;
|
|
|
|
updrDebug((DEB_ITRACE,
|
|
"ApartmentDllGetClassObject(%I,%I,%x)\n",
|
|
&clsid, &iid, ppv));
|
|
|
|
if(IsEqualCLSID(clsid, CLSID_ThumbnailUpdater))
|
|
{
|
|
COleTls tls;
|
|
|
|
if ( (tls->dwFlags & OLETLS_INNEUTRALAPT)
|
|
|| !(tls->dwFlags & OLETLS_APARTMENTTHREADED))
|
|
{
|
|
//We need to switch to a single-threaded apartment.
|
|
hr = DoATClassCreate(GetCThumbnailCF, clsid, iid, (IUnknown **)ppv);
|
|
}
|
|
else
|
|
{
|
|
//This thread is in a single-threaded apartment.
|
|
hr = GetCThumbnailCF(clsid, iid, ppv);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = CLASS_E_CLASSNOTAVAILABLE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CThumbnailCF::AddRef, public
|
|
//
|
|
// Synopsis: Adds a reference to an interface
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CThumbnailCF::AddRef(void)
|
|
{
|
|
return InterlockedIncrement((LONG *)&_cRefs);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CThumbnailCF::Release, public
|
|
//
|
|
// Synopsis: Adds a reference to an interface
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CThumbnailCF::Release(void)
|
|
{
|
|
ULONG cRefs = (ULONG) InterlockedDecrement((LONG *)&_cRefs);
|
|
if (cRefs == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return cRefs;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CThumbnailCF::QueryInterface, public
|
|
//
|
|
// Synopsis: Returns a pointer to the requested interface.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CThumbnailCF::QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if (IsEqualIID(riid, IID_IClassFactory) ||
|
|
IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
*ppv = (IClassFactory *) this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// OLE32 Internal ClassFactory Entry Point
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CThumbnailCF_CreateInstance(
|
|
IUnknown *pUnkOuter,
|
|
REFIID riid,
|
|
void** ppv)
|
|
{
|
|
HRESULT hr;
|
|
CTNUpdater * pact;
|
|
|
|
updrDebug(( DEB_IWARN, "Thumbnailer: CreateInstance called\n" ));
|
|
|
|
if(NULL != pUnkOuter)
|
|
{
|
|
return CLASS_E_NOAGGREGATION;
|
|
}
|
|
|
|
pact = new CTNUpdater;
|
|
|
|
if(NULL == pact)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if(!pact->ObjectInit())
|
|
{
|
|
pact->Release();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pact->QueryInterface(riid, ppv);
|
|
pact->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
// Member: CThumbnailCF::CreateInstance, public
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CThumbnailCF::CreateInstance(IUnknown *pUnkOuter,
|
|
REFIID riid,
|
|
void **ppv)
|
|
{
|
|
return CThumbnailCF_CreateInstance( pUnkOuter, riid, ppv );
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// CTNUpdater Class
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
//---------------------------------------------------------
|
|
// C++ Methods: Constructor
|
|
//---------------------------------------------------------
|
|
CTNUpdater::CTNUpdater(void)
|
|
{
|
|
m_cRef = 1;
|
|
m_pITE = NULL;
|
|
m_hEvRegNotify = NULL;
|
|
m_hkeyMime = NULL;
|
|
m_ppwszExtensions = NULL;
|
|
m_pTempList = NULL;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
// C++ Methods: Destructor
|
|
//---------------------------------------------------------
|
|
CTNUpdater::~CTNUpdater(void)
|
|
{
|
|
if( NULL != m_pTempList )
|
|
FreeTempExtensionList();
|
|
|
|
if( NULL != m_pITE )
|
|
m_pITE->Release();
|
|
|
|
if( NULL != m_hkeyMime )
|
|
CloseHandle( m_hkeyMime );
|
|
|
|
if( NULL != m_hEvRegNotify )
|
|
CloseHandle( m_hEvRegNotify );
|
|
|
|
if( NULL != m_ppwszExtensions )
|
|
CoTaskMemFree( m_ppwszExtensions );
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// non-interface Init routine
|
|
//---------------------------------------------------------
|
|
BOOL
|
|
CTNUpdater::ObjectInit()
|
|
{
|
|
HRESULT sc;
|
|
DWORD status;
|
|
|
|
//
|
|
// Create the event for waiting on registry changes.
|
|
//
|
|
status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
MIME_TYPES_ROOT,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&m_hkeyMime );
|
|
|
|
if( ERROR_SUCCESS != status )
|
|
updrErr( EH_Err, LAST_SCODE );
|
|
|
|
m_hEvRegNotify = CreateEvent( NULL,
|
|
TRUE, // Manual Reset
|
|
FALSE, // Init signaled
|
|
NULL );
|
|
|
|
if( NULL == m_hEvRegNotify )
|
|
updrErr( EH_Err, LAST_SCODE );
|
|
|
|
updrChk( GetImageFileExtensions() );
|
|
|
|
return TRUE;
|
|
EH_Err:
|
|
return FALSE;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// IUnknown::AddRef
|
|
//---------------------------------------------------------
|
|
ULONG
|
|
CTNUpdater::AddRef()
|
|
{
|
|
return InterlockedIncrement((LONG*)&m_cRef);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// IUnknown::Release
|
|
//---------------------------------------------------------
|
|
ULONG
|
|
CTNUpdater::Release()
|
|
{
|
|
LONG cRef;
|
|
|
|
cRef = InterlockedDecrement((LONG*)&m_cRef);
|
|
|
|
// ASSERT(cRef >= 0);
|
|
|
|
if(cRef <= 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// IUnknown::QueryInterface
|
|
//---------------------------------------------------------
|
|
HRESULT
|
|
CTNUpdater::QueryInterface(
|
|
REFIID iid,
|
|
void **ppv)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
IUnknown *pUnk=NULL;
|
|
|
|
if(IsEqualIID(IID_IUnknown, iid))
|
|
{
|
|
pUnk = (IFilterStatus*)this;
|
|
}
|
|
else if(IsEqualIID(IID_IFilterStatus, iid))
|
|
{
|
|
pUnk = (IFilterStatus*)this;
|
|
}
|
|
else if(IsEqualIID(IID_IOplockStorage, iid))
|
|
{
|
|
pUnk = (IOplockStorage*)this;
|
|
}
|
|
else
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
pUnk->AddRef();
|
|
*ppv = pUnk;
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// IFilterStatus::Initialize
|
|
//---------------------------------------------------------
|
|
HRESULT
|
|
CTNUpdater::Initialize(
|
|
const WCHAR *pwszCatalogName,
|
|
const WCHAR *pwszCatalogPath)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// IFilterStatus::FilterLoad
|
|
//---------------------------------------------------------
|
|
HRESULT
|
|
CTNUpdater::FilterLoad(
|
|
const WCHAR *pwszPath,
|
|
SCODE scFilterStatus)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
//---------------------------------------------
|
|
// Test routine
|
|
//----------------------------------------
|
|
|
|
HRESULT
|
|
test_junk(IStorage *pstg)
|
|
{
|
|
HRESULT sc=S_OK;
|
|
IPropertySetStorage *ppss = NULL;
|
|
IPropertyStorage *pps = NULL;
|
|
PROPSPEC propSpec[1];
|
|
PROPVARIANT propVar[1];
|
|
|
|
|
|
updrChk( pstg->QueryInterface( IID_IPropertySetStorage, (void**)&ppss ) );
|
|
|
|
updrChk( ppss->Open( FMTID_SummaryInformation,
|
|
STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
|
|
&pps ) );
|
|
|
|
propSpec[0].ulKind = PRSPEC_PROPID;
|
|
propSpec[0].propid = PIDSI_THUMBNAIL;
|
|
|
|
updrChk( pps->ReadMultiple(1, propSpec, propVar) );
|
|
|
|
EH_Err:
|
|
// FreePropVariantArray(1, propVar);
|
|
if( NULL != ppss )
|
|
ppss->Release();
|
|
if( NULL != pps )
|
|
pps->Release();
|
|
return sc;
|
|
} */
|
|
|
|
//---------------------------------------------------------
|
|
// IFilterStatus::PreFilter
|
|
//
|
|
// This routine ALWAYS SUCCEEDS, unless we want to defer processing
|
|
// to a later time.
|
|
// If it returns any failure, CI will defer filtering the file
|
|
// and will submit it again later.
|
|
//---------------------------------------------------------
|
|
HRESULT
|
|
CTNUpdater::PreFilter(
|
|
WCHAR const * pwszPath)
|
|
{
|
|
HRESULT sc=S_OK;
|
|
IStorage *pstg=NULL;
|
|
IThumbnailExtractor *pITE=NULL;
|
|
ITimeAndNoticeControl *pITNC=NULL;
|
|
ULONG cStorageFinalReferences=0;
|
|
|
|
updrDebug(( DEB_INFO | DEB_TRACE,
|
|
"PreFilter(\"%ws\")\n", pwszPath ));
|
|
|
|
// Optimize, don't spend time on files that we don't expect to be
|
|
// Images. If it does not have a valid extension then we are done.
|
|
//
|
|
if( ! HasAnImageFileExtension(pwszPath) )
|
|
return S_FALSE;
|
|
|
|
// Open an Oplock'ed Storage. (w/ SuppressChanges turned on)
|
|
//
|
|
updrChk( OpenStorageEx(pwszPath,
|
|
STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
|
|
STGFMT_FILE,
|
|
0,
|
|
IID_IFlatStorage,
|
|
(void**)&pstg) );
|
|
|
|
if( NULL == m_pITE )
|
|
{
|
|
updrChk( CoCreateInstance(CLSID_ThumbnailFCNHandler,
|
|
NULL, // pUnkOuter
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IThumbnailExtractor,
|
|
(void**)&pITE) );
|
|
m_pITE = pITE;
|
|
pITE = NULL;
|
|
}
|
|
|
|
updrChk( m_pITE->OnFileUpdated(pstg) );
|
|
|
|
|
|
EH_Err:
|
|
if(NULL != pITNC)
|
|
pITNC->Release();
|
|
|
|
if(NULL != pITE)
|
|
pITE->Release();
|
|
|
|
if(NULL != pstg)
|
|
cStorageFinalReferences = pstg->Release();
|
|
|
|
updrAssert( 0 == cStorageFinalReferences );
|
|
updrDebug(( DEB_TRACE, "PreFilter() returned %x\n", sc ));
|
|
|
|
switch( sc )
|
|
{
|
|
case STG_E_SHAREVIOLATION: // Someone else has it open when we started.
|
|
case STG_E_LOCKVIOLATION:
|
|
|
|
case STG_E_REVERTED: // Someone else opened if after we started.
|
|
break;
|
|
|
|
// All other problems are likely permanent so don't error.
|
|
// all errors tell CI to re-try the file.
|
|
default:
|
|
if( FAILED( sc ) )
|
|
sc = S_FALSE;
|
|
else
|
|
sc = S_OK;
|
|
break;
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// IFilterStatus::PostFilter
|
|
//---------------------------------------------------------
|
|
HRESULT
|
|
CTNUpdater::PostFilter(
|
|
WCHAR const * pwszPath,
|
|
HRESULT hrStatus)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
// IOplockStorage::CreateStorageEx
|
|
//---------------------------------------------------------
|
|
HRESULT
|
|
CTNUpdater::CreateStorageEx(
|
|
LPCWSTR pwcsName,
|
|
DWORD grfMode,
|
|
DWORD stgfmt,
|
|
DWORD grfAttrs,
|
|
REFIID riid,
|
|
void ** ppstgOpen)
|
|
{
|
|
return STG_E_INVALIDPARAMETER;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// IOplockStorage::OpenStorageEx
|
|
//---------------------------------------------------------
|
|
HRESULT
|
|
CTNUpdater::OpenStorageEx(
|
|
LPCWSTR pwcsName,
|
|
DWORD grfMode,
|
|
DWORD stgfmt,
|
|
DWORD grfAttrs,
|
|
REFIID riid,
|
|
void ** ppstgOpen)
|
|
{
|
|
HRESULT sc=S_OK;
|
|
IStorage *pstg=NULL;
|
|
|
|
if(0 != (grfMode & STGM_OPLOCKS_DONT_WORK))
|
|
return STG_E_INVALIDFLAG;
|
|
|
|
if( STGFMT_NATIVE == stgfmt
|
|
|| STGFMT_DOCFILE == stgfmt
|
|
|| STGFMT_STORAGE == stgfmt)
|
|
{
|
|
updrErr(EH_Err, STG_E_INVALIDPARAMETER);
|
|
}
|
|
|
|
|
|
if( STGFMT_ANY == stgfmt )
|
|
updrErr(EH_Err, STG_E_INVALIDPARAMETER);
|
|
|
|
if( STGFMT_FILE == stgfmt )
|
|
{
|
|
updrChk( NFFOpen( pwcsName, // PathName
|
|
grfMode, // Storage Mode
|
|
// Special NFF flags
|
|
NFFOPEN_OPLOCK | NFFOPEN_SUPPRESS_CHANGES,
|
|
FALSE, // Create API?
|
|
riid, // Interface ID
|
|
(void**)&pstg ) ); // [out] interface pointer
|
|
|
|
}
|
|
|
|
*ppstgOpen = pstg;
|
|
pstg = NULL;
|
|
sc = S_OK;
|
|
|
|
EH_Err:
|
|
|
|
RELEASE_INTERFACE( pstg );
|
|
|
|
return(sc);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
// HasAnImageFileExtention, private method.
|
|
//---------------------------------------------------------
|
|
BOOL
|
|
CTNUpdater::HasAnImageFileExtension(
|
|
WCHAR const * pwszPath)
|
|
{
|
|
LPCWSTR pwszDot;
|
|
LPWSTR* ppwszExt;
|
|
HRESULT sc=S_OK;
|
|
|
|
if(NULL == pwszPath)
|
|
return FALSE;
|
|
|
|
//
|
|
// Scan forward through the string looking for the last dot that
|
|
// was not followed by a WHACK or a SPACE.
|
|
//
|
|
for (pwszDot = NULL; *pwszPath; pwszPath++)
|
|
{
|
|
switch (*pwszPath) {
|
|
case L'.':
|
|
pwszDot = pwszPath; // remember the last dot
|
|
break;
|
|
case L'\\':
|
|
case L' ': // extensions can't have spaces
|
|
pwszDot = NULL; // forget last dot, it was in a directory
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If there is no extension fail.
|
|
//
|
|
if(NULL == pwszDot)
|
|
return FALSE;
|
|
|
|
// If the registry change event is signaled then read a new list.
|
|
//
|
|
if( WAIT_OBJECT_0 == WaitForSingleObject( m_hEvRegNotify, 0 ) )
|
|
updrChk( GetImageFileExtensions() );
|
|
|
|
for( ppwszExt=m_ppwszExtensions; NULL!=*ppwszExt; ++ppwszExt)
|
|
{
|
|
// Do a case insensitive compare for a known extension.
|
|
if( 0 == _wcsicmp( pwszDot, *ppwszExt ) )
|
|
return TRUE;
|
|
}
|
|
EH_Err:
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CTNUpdater::GetImageFileExtensions()
|
|
{
|
|
DWORD idx, ckeys;
|
|
LPWSTR pwszKeyName = NULL;
|
|
LPWSTR pwszExtension;
|
|
ULONG ccName, ccMaxNameLength;
|
|
DWORD status;
|
|
HRESULT sc;
|
|
FILETIME ftLastTime;
|
|
|
|
int cszTotalStrs=0; // Count of Extension Strings
|
|
int ccTotalChars=0; // Count of total Extension characters w/ NULLs
|
|
int cbTotalSize=0; // Total memory to allocate.
|
|
|
|
TEMPEXTLIST* pExt=NULL; // Src Pointer to the current Extension.
|
|
LPWSTR* ppwszPtr=NULL; // Des Pointer into string pointer table.
|
|
WCHAR* pwszBuf=NULL; // Des Pointer into character buffer table.
|
|
LPWSTR* ppwszTable=NULL;
|
|
|
|
if( NULL != m_ppwszExtensions )
|
|
{
|
|
CoTaskMemFree( m_ppwszExtensions );
|
|
m_ppwszExtensions = NULL;
|
|
}
|
|
|
|
//
|
|
// Ask for notification if this part of the registry changes.
|
|
// Set the notify before reading, that way if a change is made while
|
|
// we are reading and we miss it, we will pick it up on the next round.
|
|
//
|
|
status = RegNotifyChangeKeyValue( m_hkeyMime,
|
|
TRUE, // watch subtree
|
|
REG_NOTIFY_CHANGE_LAST_SET
|
|
|REG_NOTIFY_CHANGE_NAME,
|
|
m_hEvRegNotify,
|
|
TRUE );
|
|
if( ERROR_SUCCESS != status )
|
|
{
|
|
updrDebug(( DEB_ERROR,
|
|
"Can't set RegNotifyChangeKeyValue() %x\n",
|
|
GetLastError() ));
|
|
}
|
|
|
|
//
|
|
// Get the size of the maximum entry.
|
|
// Then allocate the buffer for the key name.
|
|
//
|
|
status = RegQueryInfoKey( m_hkeyMime,
|
|
NULL, NULL, NULL,
|
|
&ckeys,
|
|
&ccMaxNameLength,
|
|
NULL, NULL, NULL,
|
|
NULL, NULL, NULL );
|
|
if(ERROR_SUCCESS != status)
|
|
updrErr( EH_Err, LAST_SCODE );
|
|
|
|
ccMaxNameLength += 1; // Add one for the NULL
|
|
updrMem( pwszKeyName = new WCHAR[ ccMaxNameLength * sizeof(WCHAR)] );
|
|
|
|
//
|
|
// Enumerate through all the format types, looking for
|
|
// the image types. (they start with "image/")
|
|
//
|
|
for(idx=0; idx<ckeys; idx++)
|
|
{
|
|
ccName = ccMaxNameLength;
|
|
|
|
status = RegEnumKeyEx( m_hkeyMime,
|
|
idx,
|
|
pwszKeyName,
|
|
&ccName,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&ftLastTime );
|
|
|
|
if(ERROR_SUCCESS != status)
|
|
{
|
|
updrDebug(( DEB_REGINFO,
|
|
"Enum of Mime Image types failed %x)\n",
|
|
status));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If it is an image format then get the value of the
|
|
// "Extension" subkey (if any).
|
|
//
|
|
if( 0 == _wcsnicmp( pwszKeyName, IMAGE_PREFIX, IMAGE_PREFIX_LEN ) )
|
|
{
|
|
//
|
|
// The extension string is allocated by "GetAFileNameExtension()"
|
|
// and given away to "AddToTempExtensionList()".
|
|
//
|
|
sc = GetAFileNameExtension( pwszKeyName,
|
|
&pwszExtension );
|
|
|
|
if(!FAILED(sc))
|
|
{
|
|
AddToTempExtensionList( pwszExtension );
|
|
pwszExtension = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Build a table of extensions from the temporary linked list.
|
|
//
|
|
|
|
// Count the size.
|
|
//
|
|
for(pExt=m_pTempList; pExt!=NULL; pExt=pExt->pNext)
|
|
{
|
|
cszTotalStrs += 1;
|
|
ccTotalChars += wcslen(pExt->pwszExtension) + 1;
|
|
}
|
|
|
|
// Allocate the memory
|
|
//
|
|
cbTotalSize = (cszTotalStrs+1) * sizeof (WCHAR*);
|
|
cbTotalSize += ccTotalChars * sizeof(WCHAR*);
|
|
ppwszTable = (LPWSTR*) CoTaskMemAlloc( cbTotalSize );
|
|
|
|
// Set the pointers to the start of the pointer table and
|
|
// the start of the character buffer space.
|
|
//
|
|
ppwszPtr = ppwszTable;
|
|
pwszBuf = (WCHAR*) (ppwszTable + cszTotalStrs+1);
|
|
|
|
for(pExt=m_pTempList; pExt!=NULL; pExt=pExt->pNext)
|
|
{
|
|
// Copy the string into the buffer space.
|
|
//
|
|
wcscpy(pwszBuf, pExt->pwszExtension);
|
|
|
|
// Record the enrty to point at it.
|
|
//
|
|
*ppwszPtr = pwszBuf;
|
|
|
|
// Advance the pointers.
|
|
//
|
|
ppwszPtr += 1; // Advance one string pointer.
|
|
pwszBuf += wcslen(pwszBuf) +1; // Advance one string.
|
|
}
|
|
|
|
// Place a NULL in the last entry, to terminate the list.
|
|
//
|
|
*ppwszPtr = NULL;
|
|
|
|
FreeTempExtensionList();
|
|
|
|
// Success. Copy results out.
|
|
//
|
|
m_ppwszExtensions = ppwszTable;
|
|
ppwszTable = NULL;
|
|
|
|
EH_Err:
|
|
if( NULL != ppwszTable )
|
|
CoTaskMemFree( ppwszTable );
|
|
|
|
if( NULL != pwszKeyName )
|
|
delete[] pwszKeyName;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Search the existing list for an identical extension. If you don't find
|
|
// one, then push a new one onto the front of the list.
|
|
// The string is given to us. If we don't want it, then delete it.
|
|
//
|
|
HRESULT
|
|
CTNUpdater::AddToTempExtensionList(
|
|
WCHAR* pwszExtension)
|
|
{
|
|
TEMPEXTLIST* pExt;
|
|
|
|
for(pExt=m_pTempList; pExt!=NULL; pExt=pExt->pNext)
|
|
{
|
|
if( 0 == _wcsicmp(pwszExtension, pExt->pwszExtension) )
|
|
break;
|
|
}
|
|
|
|
if(NULL == pExt)
|
|
{ // If we didn't find it, save it on the list.
|
|
pExt = new TEMPEXTLIST;
|
|
pExt->pwszExtension = pwszExtension;
|
|
pExt->pNext = m_pTempList;
|
|
m_pTempList = pExt;
|
|
}
|
|
else
|
|
{ // If we already have one, then delete this string.
|
|
CoTaskMemFree(pwszExtension);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CTNUpdater::FreeTempExtensionList()
|
|
{
|
|
TEMPEXTLIST* pExt;
|
|
TEMPEXTLIST* pExtNext;
|
|
|
|
pExt=m_pTempList;
|
|
|
|
while(NULL != pExt)
|
|
{
|
|
pExtNext = pExt->pNext;
|
|
CoTaskMemFree( pExt->pwszExtension );
|
|
delete pExt;
|
|
pExt = pExtNext;
|
|
}
|
|
m_pTempList = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CTNUpdater::GetAFileNameExtension(
|
|
WCHAR* pwszKeyName,
|
|
WCHAR** ppwszExtension)
|
|
{
|
|
DWORD status, dwType;
|
|
HKEY hkeyImageFormat=NULL;
|
|
DWORD cbExtBuf=0;
|
|
HRESULT sc=S_OK;
|
|
WCHAR *pwszExt=NULL;
|
|
|
|
status = RegOpenKeyEx( m_hkeyMime,
|
|
pwszKeyName,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hkeyImageFormat );
|
|
|
|
if(ERROR_SUCCESS != status)
|
|
{
|
|
updrDebug(( DEB_ERROR,
|
|
"Error, could not open image format key '%ws' err=%d\n",
|
|
pwszKeyName, status ));
|
|
updrErr( EH_Err, LAST_SCODE );
|
|
}
|
|
|
|
// Get the Size of the extension string.
|
|
//
|
|
status = RegQueryValueEx( hkeyImageFormat,
|
|
L"Extension",
|
|
0,
|
|
&dwType,
|
|
NULL,
|
|
&cbExtBuf );
|
|
|
|
if(ERROR_SUCCESS != status)
|
|
{
|
|
if(ERROR_FILE_NOT_FOUND != status)
|
|
{
|
|
updrDebug(( DEB_REGINFO,
|
|
"Error, reading Extension for '%ws' err=%d\n",
|
|
pwszKeyName, status ));
|
|
}
|
|
sc = E_FAIL;
|
|
goto EH_Err;
|
|
}
|
|
|
|
if(REG_SZ != dwType)
|
|
{
|
|
updrDebug(( DEB_REGINFO,
|
|
"Error, Extension for '%ws' not REG_SZ type.\n",
|
|
pwszKeyName ));
|
|
sc = E_FAIL;
|
|
goto EH_Err;
|
|
}
|
|
|
|
|
|
// Allocate the buffer and read the extension string.
|
|
//
|
|
updrMem( pwszExt = (WCHAR*)CoTaskMemAlloc(cbExtBuf) );
|
|
|
|
status = RegQueryValueEx( hkeyImageFormat,
|
|
L"Extension",
|
|
0,
|
|
&dwType,
|
|
(BYTE*)pwszExt,
|
|
&cbExtBuf );
|
|
|
|
if(ERROR_SUCCESS != status)
|
|
updrErr( EH_Err, LAST_SCODE );
|
|
|
|
*ppwszExtension = pwszExt;
|
|
pwszExt = NULL;
|
|
|
|
EH_Err:
|
|
if(NULL != pwszExt)
|
|
CoTaskMemFree(pwszExt);
|
|
|
|
if( NULL != hkeyImageFormat )
|
|
RegCloseKey(hkeyImageFormat);
|
|
|
|
return sc;
|
|
}
|