/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: helpers.cxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/


#include "soole.h"

#ifndef _SMPRINTF_H
#include <systools/win32/snprintf.h>
#endif

#define ARRAYSIZE(a)    (sizeof(a)/sizeof(a[0]))

namespace binfilter {
static BOOL GetFileTimes(LPTSTR pszFileName, FILETIME *pft);

/*
 * StarObject_MetafilePictIconFree
 *
 * Purpose:
 *  Deletes the metafile contained in a METAFILEPICT structure and
 *  frees the memory for the structure itself.
 *
 * Parameters:
 *  hMetaPict       HGLOBAL metafilepict structure created in
 *                  OleMetafilePictFromIconAndLabel
 *
 * Return Value:
 *  None
 */

STDAPI_(void) StarObject_MetafilePictIconFree(HGLOBAL hMetaPict)
   {
   LPMETAFILEPICT      pMF;

   if (NULL==hMetaPict)
	  return;

   pMF=(LPMETAFILEPICT)GlobalLock(hMetaPict);

   if (NULL!=pMF)
	  {
	  if (NULL!=pMF->hMF)
		 DeleteMetaFile(pMF->hMF);
	  }

   GlobalUnlock(hMetaPict);
   GlobalFree(hMetaPict);
   return;
   }





/*
 * StarObject_SwitchDisplayAspect
 *
 * Purpose:
 *  Switch the currently cached display aspect between DVASPECT_ICON
 *  and DVASPECT_CONTENT.  When setting up icon aspect, any currently
 *  cached content cache is discarded and any advise connections for
 *  content aspect are broken.
 *
 * Parameters:
 *  pObj            IUnknown * to the object in question
 *  pdwCurAspect    DWORD * containing the current aspect which
 *                  will contain the new aspect on output.
 *  dwNewAspect     DWORD with the aspect to switch to.
 *  hMetaPict       HGLOBAL containing the CF_METAFILEPICT with
 *                  the icon.
 *  fDeleteOld      BOOL indicating if we're to delete the old
 *                  aspect from the cache.
 *  fViewAdvise     BOOL indicating if we're to establish an
 *                  advise with the object for this new aspect.
 *  pSink           IAdviseSink * to the notification sink.
 *  pfMustUpdate    BOOL * in which to return whether or not
 *                  an update from a running server is necessary.
 *
 * Return Value:
 *  HRESULT         NOERROR or an error code in which case the cache
 *                  remains unchanged.
 */

STDAPI StarObject_SwitchDisplayAspect(IUnknown *pObj, LPDWORD pdwCurAspect
	, DWORD dwNewAspect, HGLOBAL hMetaPict, BOOL fDeleteOld
	, BOOL fViewAdvise, IAdviseSink *pSink, BOOL *pfMustUpdate)
	{
	IOleCache      *pCache=NULL;
	FORMATETC       fe;
	STGMEDIUM       stm;
	DWORD           dwAdvf;
	DWORD           dwNewConnection;
	DWORD           dwOldAspect=*pdwCurAspect;
	HRESULT         hr;

	if (pfMustUpdate)
	   *pfMustUpdate=FALSE;

	hr=pObj->QueryInterface(IID_IOleCache, (void **)&pCache);

	if (FAILED(hr))
	   return ResultFromScode(E_FAIL);

	//Establish new cache with the new aspect
	SETFormatEtc(fe, 0, dwNewAspect, NULL, TYMED_NULL, -1);

	/*
	 * If we are using a custom icon for the display aspect then
	 * we won't want to establish notifications with the data
	 * source, that is, we don't want to change the icon.  Otherwise
	 * we link up the given advise sink.
	 */
	if (DVASPECT_ICON==dwNewAspect && NULL!=hMetaPict)
	   dwAdvf=ADVF_NODATA;
	else
	   dwAdvf=ADVF_PRIMEFIRST;

	hr=pCache->Cache(&fe, dwAdvf, &dwNewConnection);

	if (FAILED(hr))
		{
		pCache->Release();
		return hr;
		}

	*pdwCurAspect=dwNewAspect;

	/*
	 * Stuff the custom icon into the cache, or force an update
	 * from the server.
	 */
	if (DVASPECT_ICON==dwNewAspect && NULL!=hMetaPict)
		{
		SETFormatEtc(fe, CF_METAFILEPICT, DVASPECT_ICON, NULL
			, TYMED_MFPICT, -1);

		stm.tymed=TYMED_MFPICT;
		stm.hGlobal=hMetaPict;
		stm.pUnkForRelease=NULL;

		hr=pCache->SetData(&fe, &stm, FALSE);
		}
	else
		{
		if (pfMustUpdate)
		   *pfMustUpdate=TRUE;
		}

	if (fViewAdvise && pSink)
		{
		IViewObject    *pView=NULL;

		hr=pObj->QueryInterface(IID_IViewObject, (void **)&pView);

		if (SUCCEEDED(hr))
			{
			pView->SetAdvise(dwNewAspect, 0, pSink);
			pView->Release();
			}
		}

	/*
	 * Remove existing caches for the old display aspect to cut
	 * down on needless storage overhead.  If you want to switch
	 * frequently between icon and content aspects, then it is
	 * best to actually keep both presentations in the cache.
	 */
	if (fDeleteOld)
		{
		IEnumSTATDATA  *pEnum=NULL;
		STATDATA        sd;

		hr=pCache->EnumCache(&pEnum);

		while(NOERROR==hr)
			{
			hr=pEnum->Next(1, &sd, NULL);

			if (NOERROR==hr)
				{
				//Remove old aspect caches
				if (sd.formatetc.dwAspect==dwOldAspect)
					pCache->Uncache(sd.dwConnection);
				}
			}

		if (NULL!=pEnum)
			pEnum->Release();
		}

	pCache->Release();
	return NOERROR;
	}



/*
 * StarObject_SetIconInCache
 *
 * Purpose:
 *  Stores an iconic presentation metafile in the cache.
 *
 * Parameters:
 *  pObj            IUnknown * of the object.
 *  hMetaPict       HGLOBAL containing the presentation.
 *
 * Return Value:
 *  HRESULT         From IOleCache::SetData.
 */

STDAPI StarObject_SetIconInCache(IUnknown *pObj, HGLOBAL hMetaPict)
	{
	IOleCache      *pCache;
	FORMATETC       fe;
	STGMEDIUM       stm;
	HRESULT         hr;

	if (NULL==hMetaPict)
		return ResultFromScode(E_INVALIDARG);

	if (FAILED(pObj->QueryInterface(IID_IOleCache, (void **)&pCache)))
		return ResultFromScode(E_NOINTERFACE);

	SETFormatEtc(fe, CF_METAFILEPICT, DVASPECT_ICON, NULL
		, TYMED_MFPICT, -1);

	stm.tymed=TYMED_MFPICT;
	stm.hGlobal=hMetaPict;
	stm.pUnkForRelease=NULL;

	hr=pCache->SetData(&fe, &stm, FALSE);
	pCache->Release();

	return hr;
	}





/*
 * StarObject_GetUserTypeOfClass
 *
 * Purpose:
 *  Returns the user type (human readable class name) of the
 *  specified class as stored in the registry.
 *
 * Parameters:
 *  clsID           CLSID in question
 *  iName           UINT index to the name to retrieve, where
 *                  zero is the name found as the value of
 *                  of the CLSID, anything else tries
 *                  AuxUserType\iName.
 *  pszUserType     LPTSTR in which to return the type
 *  cch             UINT length of pszUserType
 *
 * Return Value:
 *  UINT            Number of characters in returned string.
 *                  0 on error.
 */

STDAPI_(UINT) StarObject_GetUserTypeOfClass(REFCLSID clsID, UINT iName
	, LPTSTR pszUserType, UINT cch)
	{
	LPTSTR      pszCLSID;
	LPTSTR      pszProgID;
	TCHAR       szKey[300];
	LONG        dw;
	LONG        lRet;

	if (!pszUserType)
		return 0;

	*pszUserType='\0';

	//Get a string containing the class name
	StarObject_StringFromCLSID(clsID, &pszCLSID);

	if (0==iName)
		sntprintf(szKey, ARRAYSIZE(szKey), TEXT("CLSID\\%s"), pszCLSID);
	else
		{
		sntprintf(szKey, ARRAYSIZE(szKey), TEXT("CLSID\\%s\\AuxUserType\\%u")
			, pszCLSID, iName);
		}

	CoTaskMemFree(pszCLSID);

	dw=cch;
	lRet=RegQueryValue(HKEY_CLASSES_ROOT, szKey, pszUserType, &dw);

	if (ERROR_SUCCESS!=lRet)
		{
		lstrcpyn(pszUserType, TEXT("Unknown"), cch);

		if (CoIsOle1Class(clsID))
			{
			//Try to get ProgID value for OLE 1 class
			StarObject_ProgIDFromCLSID(clsID, &pszProgID);

			dw=cch;
			lRet=RegQueryValue(HKEY_CLASSES_ROOT, pszProgID
				, pszUserType, &dw);

			CoTaskMemFree(pszProgID);

			if (ERROR_SUCCESS!=lRet)
				dw=0;
			}
		}

	return (UINT)dw;
	}





/*
 * StarObject_DoConvert
 *
 * Purpose:
 *  Convert an embedded or linked object to another type, working
 *  in conjunection with OleUIConvert.
 *
 * Parameters:
 *  pIStorage       IStorage * to the object's data.
 *  clsID           CLSID to which we convert the object.
 *
 * Return Value:
 *  HRESULT         The usual.
 */

STDAPI StarObject_DoConvert(IStorage *pIStorage, REFCLSID clsID)
	{
	HRESULT     hr;
	CLSID       clsIDOrg;
	CLIPFORMAT  cfOrg;
	LPTSTR      pszOrg=NULL;
	TCHAR       szNew[256];

	if (FAILED(ReadClassStg(pIStorage, &clsIDOrg)))
		return ResultFromScode(E_FAIL);

	//Read original format/user type
	hr=StarObject_ReadFmtUserTypeStg(pIStorage, &cfOrg, &pszOrg);

	//Get new user type
	if (0==StarObject_GetUserTypeOfClass(clsID, 0, szNew, 256))
		lstrcpyn(szNew, TEXT(""), ARRAYSIZE(szNew));

	//Write new class into the storage
	if (SUCCEEDED(WriteClassStg(pIStorage, clsID)))
		{
		if (SUCCEEDED(StarObject_WriteFmtUserTypeStg(pIStorage, cfOrg
			, szNew)))
			{
			SetConvertStg(pIStorage, TRUE);
			CoTaskMemFree((void *)pszOrg);
			return NOERROR;
			}

		//Failed to write new type, restore the old class
		WriteClassStg(pIStorage, clsIDOrg);
		}

	CoTaskMemFree((void *)pszOrg);
	return ResultFromScode(E_FAIL);
	}




/*
 * StarObject_CopyString
 *
 * Purpose:
 *  Copies a string allocated with CoTaskMemAlloc.
 *
 * Parameters:
 *  pszSrc          LPTSTR to the string to copy.
 *
 * Return Value:
 *  LPTSTR          New string or a NULL.
 */

STDAPI_(LPTSTR) StarObject_CopyString(LPTSTR pszSrc)
	{
	IMalloc    *pIMalloc;
	LPTSTR      pszDst;
	UINT        cch;

	cch=lstrlen(pszSrc);

	if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
		return NULL;

	pszDst=(LPTSTR)pIMalloc->Alloc((cch+1)*sizeof(TCHAR));

	if (NULL!=pszDst)
	   lstrcpyn(pszDst, pszSrc, cch+1);

	pIMalloc->Release();
	return pszDst;
	}




/*
 * StarObject_ObjectDescriptorFromOleObject
 *
 * Purpose:
 *  Fills and returns an OBJECTDESCRIPTOR structure. Information
 *  for the structure is obtained from an IOleObject instance.
 *
 * Parameters:
 *  pObj            IOleObject * from which to retrieve information.
 *  dwAspect        DWORD with the display aspect
 *  ptl             POINTL from upper-left corner of object where
 *                  mouse went down for use with Drag & Drop.
 *  pszl            LPSIZEL (optional) if the object is being scaled in
 *                  its container, then the container should pass the
 *                  extents that it is using to display the object.
 *
 * Return Value:
 *  HBGLOBAL         Handle to OBJECTDESCRIPTOR structure.
 */

STDAPI_(HGLOBAL) StarObject_ObjectDescriptorFromOleObject
	(IOleObject *pObj, DWORD dwAspect, POINTL ptl, LPSIZEL pszl)
	{
	CLSID           clsID;
	LPTSTR          pszName=NULL;
	LPTSTR          pszSrc=NULL;
	BOOL            fLink=FALSE;
	IOleLink       *pLink;
	TCHAR           szName[512];
	DWORD           dwMisc=0;
	HGLOBAL         hMem;
	HRESULT         hr;
   #ifdef WIN32ANSI
   //#ifndef UNICODE
	LPWSTR			pszw;
	char	szTemp[512];
   #endif

	if (SUCCEEDED(pObj->QueryInterface(IID_IOleLink
		, (void **)&pLink)))
		fLink=TRUE;

	if (FAILED(pObj->GetUserClassID(&clsID)))
		clsID=CLSID_NULL;

	//Get user string, expand to "Linked %s" if this is link
   #ifndef WIN32ANSI
   //#ifdef UNICODE
	pObj->GetUserType(USERCLASSTYPE_FULL, &pszName);
   #else
	pObj->GetUserType(USERCLASSTYPE_FULL, &pszw);
	WideCharToMultiByte(CP_ACP, 0, pszw, -1, szTemp
		, sizeof(szTemp), NULL, NULL);
	pszName=szTemp;
   #endif

	if (fLink && NULL!=pszName)
		sntprintf(szName, ARRAYSIZE(szName), TEXT("Linked %s"), pszName);
	else
		lstrcpyn(szName, pszName, ARRAYSIZE(szName));

   #ifndef WIN32ANSI
   //#ifdef UNICODE
	CoTaskMemFree(pszName);
   #else
	CoTaskMemFree(pszw);
   #endif

	/*
	 * Get the source name of this object using either the
	 * link display name (for link) or a moniker display
	 * name.
	 */

	if (fLink)
		{
	   #ifndef WIN32ANSI
	   //#ifdef UNICODE
		hr=pLink->GetSourceDisplayName(&pszSrc);
	   #else
		hr=pLink->GetSourceDisplayName(&pszw);
		WideCharToMultiByte(CP_ACP, 0, pszw, -1, szTemp
			, sizeof(szTemp), NULL, NULL);
		pszSrc=szTemp;
	   #endif
		}
	else
		{
		IMoniker   *pmk;

		hr=pObj->GetMoniker(OLEGETMONIKER_TEMPFORUSER
			, OLEWHICHMK_OBJFULL, &pmk);

		if (SUCCEEDED(hr))
			{
			IBindCtx  *pbc;
			CreateBindCtx(0, &pbc);

		   #ifndef WIN32ANSI
		   //#ifdef UNICODE
			pmk->GetDisplayName(pbc, NULL, &pszSrc);
		   #else
			pmk->GetDisplayName(pbc, NULL, &pszw);
			WideCharToMultiByte(CP_ACP, 0, pszw, -1, szTemp
				, sizeof(szTemp), NULL, NULL);
			pszSrc=szTemp;
		   #endif

			pbc->Release();

			pmk->Release();
			}
		}

	if (fLink)
		pLink->Release();

	//Get MiscStatus bits
	hr=pObj->GetMiscStatus(dwAspect, &dwMisc);

	//Get OBJECTDESCRIPTOR
	hMem=StarObject_AllocObjectDescriptor(clsID, dwAspect, *pszl, ptl
		, dwMisc, szName, pszSrc);

   #ifndef WIN32ANSI
   //#ifdef UNICODE
	CoTaskMemFree(pszSrc);
   #else
	CoTaskMemFree(pszw);
   #endif

	return hMem;
	}





/*
 * StarObject_AllocObjectDescriptor
 *
 * Purpose:
 *  Allocated and fills an OBJECTDESCRIPTOR structure.
 *
 * Parameters:
 *  clsID           CLSID to store.
 *  dwAspect        DWORD with the display aspect
 *  pszl            LPSIZEL (optional) if the object is being scaled in
 *                  its container, then the container should pass the
 *                  extents that it is using to display the object.
 *  ptl             POINTL from upper-left corner of object where
 *                  mouse went down for use with Drag & Drop.
 *  dwMisc          DWORD containing MiscStatus flags
 *  pszName         LPTSTR naming the object to copy
 *  pszSrc          LPTSTR identifying the source of the object.
 *
 * Return Value:
 *  HBGLOBAL         Handle to OBJECTDESCRIPTOR structure.
 */

STDAPI_(HGLOBAL) StarObject_AllocObjectDescriptor(CLSID clsID
	, DWORD dwAspect, SIZEL szl, POINTL ptl, DWORD dwMisc
	, LPTSTR pszName, LPTSTR pszSrc)
	{
	HGLOBAL              hMem=NULL;
	LPOBJECTDESCRIPTOR   pOD;
	DWORD                cb, cbStruct;
	DWORD                cchName, cchSrc;

	cchName=lstrlen(pszName)+1;

	if (NULL!=pszSrc)
		cchSrc=lstrlen(pszSrc)+1;
	else
		{
		cchSrc=cchName;
		pszSrc=pszName;
		}

	/*
	 * Note:  CFSTR_OBJECTDESCRIPTOR is an ANSI structure.
	 * That means strings in it must be ANSI.  OLE will do
	 * internal conversions back to Unicode as necessary,
	 * but we have to put ANSI strings in it ourselves.
	 */
	cbStruct=sizeof(OBJECTDESCRIPTOR);
	cb=cbStruct+(sizeof(WCHAR)*(cchName+cchSrc));   //HACK

	hMem=GlobalAlloc(GHND, cb);

	if (NULL==hMem)
		return NULL;

	pOD=(LPOBJECTDESCRIPTOR)GlobalLock(hMem);

	pOD->cbSize=cb;
	pOD->clsid=clsID;
	pOD->dwDrawAspect=dwAspect;
	pOD->sizel=szl;
	pOD->pointl=ptl;
	pOD->dwStatus=dwMisc;

	if (pszName)
		{
		pOD->dwFullUserTypeName=cbStruct;
	   #ifdef WIN32ANSI
		MultiByteToWideChar(CP_ACP, 0, pszName, -1
			, (LPWSTR)((LPBYTE)pOD+pOD->dwFullUserTypeName), cchName);
	   #else
		lstrcpyn((LPTSTR)((LPBYTE)pOD+pOD->dwFullUserTypeName)
			, pszName, cchName);
	   #endif
		}
	else
		pOD->dwFullUserTypeName=0;  //No string

	if (pszSrc)
		{
		pOD->dwSrcOfCopy=cbStruct+(cchName*sizeof(WCHAR));

	   #ifdef WIN32ANSI
		MultiByteToWideChar(CP_ACP, 0, pszSrc, -1
			, (LPWSTR)((LPBYTE)pOD+pOD->dwSrcOfCopy), cchSrc);
	   #else
		lstrcpyn((LPTSTR)((LPBYTE)pOD+pOD->dwSrcOfCopy), pszSrc, cchSrc);
	   #endif
		}
	else
		pOD->dwSrcOfCopy=0;  //No string

	GlobalUnlock(hMem);
	return hMem;
	}





/*
 * StarObject_CreateStorageOnHGlobal
 *
 * Purpose:
 *  Create a memory based storage object on an memory lockbytes.
 *
 * Parameters:
 *  grfMode --  flags passed to StgCreateDocfileOnILockBytes
 *
 *  NOTE: if hGlobal is NULL, then a new IStorage is created and
 *              STGM_CREATE flag is passed to StgCreateDocfileOnILockBytes.
 *        if hGlobal is non-NULL, then it is assumed that the hGlobal already
 *              has an IStorage inside it and STGM_CONVERT flag is passed
 *              to StgCreateDocfileOnILockBytes.
 *
 * Return Value:
 *  IStorage *      Pointer to the storage we create.
 */

STDAPI_(IStorage *) StarObject_CreateStorageOnHGlobal(DWORD grfMode)
	{
	DWORD           grfCreate=grfMode | STGM_CREATE;
	HRESULT         hr;
	ILockBytes     *pLB=NULL;
	IStorage       *pIStorage=NULL;

	hr=CreateILockBytesOnHGlobal(NULL, TRUE, &pLB);

	if (FAILED(hr))
		return NULL;

	hr=StgCreateDocfileOnILockBytes(pLB, grfCreate, 0, &pIStorage);

	pLB->Release();

	return SUCCEEDED(hr) ? pIStorage : NULL;
	}








/*
 * StarObject_GetLinkSourceData
 *
 * Purpose:
 *  Creates a CFSTR_LINKSOURCE data format, that is, a serialized
 *  moniker in a stream.
 *
 * Parameters:
 *  pmk             IMoniker * of the link.
 *  pClsID          CLSID * to write into the stream.
 *  pFE             FORMATETC * describing the data which
 *                  should have TYMED_ISTREAM in it.
 *  pSTM            STGMEDIUM in which to return the data.
 *                  If this has TYMED_NULL, then this function
 *                  allocates the stream, otherwise it writes
 *                  into the stream in pSTM->pstm.
 */

STDAPI StarObject_GetLinkSourceData(IMoniker *pmk, LPCLSID pClsID
	, LPFORMATETC pFE, LPSTGMEDIUM pSTM)
	{
	LPSTREAM    pIStream = NULL;
	HRESULT     hr;

	pSTM->pUnkForRelease=NULL;

	if (TYMED_NULL==pSTM->tymed)
		{
		if (pFE->tymed & TYMED_ISTREAM)
			{
			hr=CreateStreamOnHGlobal(NULL, TRUE, &pIStream);

			if (FAILED(hr))
				return ResultFromScode(E_OUTOFMEMORY);

			pSTM->pstm=pIStream;
			pSTM->tymed=TYMED_ISTREAM;
			}
		else
			return ResultFromScode(DATA_E_FORMATETC);
		}
	else
		{
		if (TYMED_ISTREAM==pSTM->tymed)
			{
			pSTM->tymed=TYMED_ISTREAM;
			pSTM->pstm=pSTM->pstm;
			}
		else
			return ResultFromScode(DATA_E_FORMATETC);
	   }

	hr=OleSaveToStream(pmk, pSTM->pstm);

	if (FAILED(hr))
		return hr;

	return WriteClassStm(pSTM->pstm, *pClsID);
	}





/*
 * StarObject_RegisterAsRunning
 *
 * Purpose:
 *  Registers a moniker as running in the running object
 *  table, revoking any existing registration.
 *
 * Parameters:
 *  pUnk            IUnknown * of the object.
 *  pmk             IMoniker * naming the object.
 *  dwFlags         DWORD flags to pass to IROT::Register
 *  pdwReg          LPDWORD in which to store the registration key.
 *
 * Return Value:
 *  None
 */

STDAPI_(void) StarObject_RegisterAsRunning(IUnknown *pUnk
	, IMoniker *pmk, DWORD dwFlags, LPDWORD pdwReg)
	{
	IRunningObjectTable    *pROT;
	HRESULT                 hr;
	DWORD                   dwReg=*pdwReg;

	if (NULL==pmk || NULL==pUnk || NULL==pdwReg)
		return;

	dwReg=*pdwReg;

	if (FAILED(GetRunningObjectTable(0, &pROT)))
		return;

	hr=pROT->Register(dwFlags, pUnk, pmk, pdwReg);

	if (MK_S_MONIKERALREADYREGISTERED==GetScode(hr))
		{
		if (0!=dwReg)
			pROT->Revoke(dwReg);
		}

	pROT->Release();
	return;
	}



/*
 * StarObject_RevokeAsRunning
 *
 * Purpose:
 *  Wrapper for IRunningObjectTable::Revoke
 *
 * Parameters:
 *  pdwReg          LPDWORD containing the key on input, zeroed
 *                  on output.
 *
 * Return Value:
 *  None
 */

STDAPI_(void) StarObject_RevokeAsRunning(LPDWORD pdwReg)
	{
	IRunningObjectTable    *pROT;

	if (0==*pdwReg)
		return;

	if (FAILED(GetRunningObjectTable(0, &pROT)))
		return;

	pROT->Revoke(*pdwReg);
	pROT->Release();

	*pdwReg=0;
	return;
	}



/*
 * StarObject_NoteChangeTime
 *
 * Purpose:
 *  Wrapper for IRunningObjectTable::NoteChangeTime
 *
 * Parameters:
 *  dwReg           DWORD identifying the running object to note.
 *  pft             FILETIME * containing the new time.  If NULL,
 *                  then we'll get it from CoFileTimeNow.
 *  pszFile         LPTSTR to a filename.  If pft is NULL, we'll
 *                  retrieve times from this file.
 *
 * Return Value:
 *  None
 */

STDAPI_(void) StarObject_NoteChangeTime(DWORD dwReg, FILETIME *pft
	, LPTSTR pszFile)
	{
	IRunningObjectTable    *pROT;
	FILETIME                ft;

	if (NULL==pft)
		{
		CoFileTimeNow(&ft);
		pft=&ft;
		}

	if (NULL!=pszFile)
		GetFileTimes(pszFile, pft);

	if (FAILED(GetRunningObjectTable(0, &pROT)))
		return;

	pROT->NoteChangeTime(dwReg, pft);
	pROT->Release();
	return;
	}




/*
 * GetFileTimes
 * (Internal)
 *
 * Purpose:
 *  Retrieve the FILETIME structure for a given file.
 */

static BOOL GetFileTimes(LPTSTR pszFileName, FILETIME *pft)
{
	WIN32_FIND_DATA fd;
	HANDLE          hFind;

	hFind=FindFirstFile(pszFileName, &fd);

	if (NULL==hFind || INVALID_HANDLE_VALUE==hFind)
		return FALSE;

	FindClose(hFind);
	*pft=fd.ftLastWriteTime;
	return TRUE;
}
}
