2939 lines
84 KiB
C++
2939 lines
84 KiB
C++
// --------------------------------------------------------------------------------
|
|
// IPropObj.cpp
|
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
|
// Steven J. Bailey
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "ipropobj.h"
|
|
#include "propcryp.h"
|
|
#include "pstore.h"
|
|
#include "dllmain.h"
|
|
#include "qstrcmpi.h"
|
|
#include "demand.h"
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Prototypes
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT PropUtil_HrValidatePropInfo(LPPROPINFO prgPropInfo, ULONG cProperties);
|
|
BOOL PropUtil_FIsValidPropTagType(DWORD dwPropTag);
|
|
HRESULT PropUtil_HrDupPropInfoArray(LPCPROPINFO prgPropInfoSrc, ULONG cPropsSrc, LPPSETINFO pPsetInfo);
|
|
VOID PropUtil_FreePropValueArrayItems(LPPROPVALUE prgPropValue, ULONG cProperties);
|
|
VOID PropUtil_FreeVariant(DWORD dwPropTag, LPXVARIANT pVariant, DWORD cbValue);
|
|
VOID PropUtil_FreePropInfoArrayItems(LPPROPINFO prgPropInfo, ULONG cProperties);
|
|
HRESULT PropUtil_HrCopyVariant(DWORD dwPropTag, LPCXVARIANT pVariantSrc, DWORD cbSrc, LPXVARIANT pVariantDest, DWORD *pcbDest);
|
|
HRESULT PropUtil_HrBinaryFromVariant(DWORD dwPropTag, LPXVARIANT pVariant, DWORD cbValue, LPBYTE pb, DWORD *pcb);
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// HrCreatePropertyContainer
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT HrCreatePropertyContainer(CPropertySet *pPropertySet, CPropertyContainer **ppPropertyContainer)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CPropertyContainer *pPropertyContainer=NULL;
|
|
|
|
// check params
|
|
Assert(pPropertySet != NULL);
|
|
Assert(ppPropertyContainer != NULL);
|
|
|
|
// Create Container
|
|
pPropertyContainer = new CPropertyContainer();
|
|
if (NULL == pPropertyContainer)
|
|
{
|
|
hr = TRAPHR(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
// Init
|
|
CHECKHR(hr = pPropertyContainer->HrInit(pPropertySet));
|
|
|
|
// Set Container
|
|
*ppPropertyContainer = pPropertyContainer;
|
|
|
|
exit:
|
|
// Failed
|
|
if (FAILED(hr))
|
|
{
|
|
SafeRelease(pPropertyContainer);
|
|
*ppPropertyContainer = NULL;
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::CPropertyContainer
|
|
// -----------------------------------------------------------------------------
|
|
CPropertyContainer::CPropertyContainer(void)
|
|
{
|
|
m_cRef = 1;
|
|
m_pPropertySet = NULL;
|
|
m_prgPropValue = 0;
|
|
m_cDirtyProps = 0;
|
|
m_cProperties = 0;
|
|
m_fLoading = FALSE;
|
|
m_pPropCrypt = NULL;
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::~CPropertyContainer
|
|
// -----------------------------------------------------------------------------
|
|
CPropertyContainer::~CPropertyContainer()
|
|
{
|
|
Assert(m_cRef == 0);
|
|
ResetContainer();
|
|
SafeMemFree(m_prgPropValue);
|
|
SafeRelease(m_pPropertySet);
|
|
SafeRelease(m_pPropCrypt);
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::QueryInterface
|
|
// -----------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertyContainer::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Bad param
|
|
if (ppv == NULL)
|
|
{
|
|
hr = TRAPHR(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
// Init
|
|
*ppv=NULL;
|
|
|
|
// IID_IUnknown
|
|
if (IID_IUnknown == riid)
|
|
(IUnknown *)this;
|
|
|
|
// IID_IPropertyContainer
|
|
else if (IID_IPropertyContainer == riid)
|
|
(IPropertyContainer *)this;
|
|
|
|
// If not null, addref it and return
|
|
if (NULL!=*ppv)
|
|
{
|
|
((LPUNKNOWN)*ppv)->AddRef();
|
|
goto exit;
|
|
}
|
|
|
|
// No Interface
|
|
hr = TRAPHR(E_NOINTERFACE);
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::AddRef
|
|
// -----------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CPropertyContainer::AddRef(VOID)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::Release
|
|
// -----------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CPropertyContainer::Release(VOID)
|
|
{
|
|
if (--m_cRef == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_cRef;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::ResetContainer
|
|
// -----------------------------------------------------------------------------
|
|
VOID CPropertyContainer::ResetContainer(VOID)
|
|
{
|
|
// I hope we don't have any dirty properties
|
|
#ifdef DEBUG
|
|
if (m_cDirtyProps)
|
|
DebugTrace("CPropertyContainer::ResetContainer - %d Dirty Properties.\n", m_cDirtyProps);
|
|
#endif
|
|
|
|
// Crit Sect
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Free prop data
|
|
if (m_prgPropValue)
|
|
{
|
|
Assert(m_cProperties);
|
|
PropUtil_FreePropValueArrayItems(m_prgPropValue, m_cProperties);
|
|
}
|
|
|
|
// Reset variables
|
|
m_cDirtyProps = 0;
|
|
|
|
// Leave Crit Sect
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrEnumProps
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrEnumProps(CEnumProps **ppEnumProps)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Check Params
|
|
Assert(ppEnumProps != NULL);
|
|
|
|
// Allocate memory for object
|
|
*ppEnumProps = new CEnumProps(this);
|
|
if (*ppEnumProps == NULL)
|
|
{
|
|
hr = TRAPHR(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrInit
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrInit(CPropertySet *pPropertySet)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Leave Crit Sect
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Bad Parameter
|
|
Assert(pPropertySet != NULL);
|
|
|
|
// Save the property set
|
|
m_pPropertySet = pPropertySet;
|
|
m_pPropertySet->AddRef();
|
|
|
|
// Do we have the property data array yet ?
|
|
Assert(m_prgPropValue == NULL);
|
|
Assert(m_cProperties == 0);
|
|
CHECKHR(hr = m_pPropertySet->HrGetPropValueArray(&m_prgPropValue, &m_cProperties));
|
|
AssertReadWritePtr(m_prgPropValue, sizeof(PROPVALUE) * m_cProperties);
|
|
|
|
exit:
|
|
// Leave Crit Sect
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrEncryptProp
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrEncryptProp(LPBYTE pbClientData, DWORD cbClientData,
|
|
LPBYTE *ppbPropData, DWORD *pcbPropData)
|
|
{
|
|
HRESULT hr;
|
|
BLOB blobClient;
|
|
BLOB blobProp;
|
|
|
|
// Create Encoder?
|
|
if (NULL == m_pPropCrypt)
|
|
CHECKHR(hr = HrCreatePropCrypt(&m_pPropCrypt));
|
|
|
|
blobClient.pBlobData= pbClientData;
|
|
blobClient.cbSize = cbClientData;
|
|
blobProp.pBlobData = *ppbPropData;
|
|
blobProp.cbSize = *pcbPropData;
|
|
|
|
if (pbClientData)
|
|
{
|
|
// Client has data to save
|
|
|
|
if (!*ppbPropData)
|
|
{
|
|
LPSTR szName;
|
|
ULONG dexAcct;
|
|
|
|
// Build the seed name if possible
|
|
if SUCCEEDED(m_pPropertySet->HrIndexFromPropTag(AP_ACCOUNT_NAME, &dexAcct) &&
|
|
(TYPE_STRING == PROPTAG_TYPE(m_prgPropValue[dexAcct].dwPropTag)))
|
|
{
|
|
szName = (LPSTR)m_prgPropValue[dexAcct].pbValue;
|
|
}
|
|
else
|
|
{
|
|
szName = NULL;
|
|
}
|
|
|
|
hr = m_pPropCrypt->HrEncodeNewProp(szName, &blobClient, &blobProp);
|
|
}
|
|
else
|
|
{
|
|
hr = m_pPropCrypt->HrEncode(&blobClient, &blobProp);
|
|
}
|
|
|
|
// We need to (possibly) update this, regardless. HrEncode
|
|
// can change the data if PST is not installed
|
|
*ppbPropData = blobProp.pBlobData;
|
|
*pcbPropData = blobProp.cbSize;
|
|
}
|
|
else if (*ppbPropData)
|
|
{
|
|
// If we had a property, the client has no data so hose it.
|
|
|
|
DOUTL(DOUTL_CPROP, "EncryptedProp: attempting to delete.");
|
|
hr = m_pPropCrypt->HrDelete(&blobProp);
|
|
if (SUCCEEDED(hr) || PST_E_ITEM_NO_EXISTS == hr)
|
|
{
|
|
DOUTL(DOUTL_CPROP, "EncryptedProp: deleted.");
|
|
hr = S_PasswordDeleted;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
DOUTL(DOUTL_CPROP, "EncryptedProp: noop in EncodeProp. no handle, no data.");
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrDecryptProp
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrDecryptProp(BLOB *pIn, BLOB *pOut)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
|
|
Assert(pIn && pOut);
|
|
|
|
pOut->pBlobData = NULL;
|
|
|
|
// Create Encryptor ?
|
|
if (m_pPropCrypt == NULL)
|
|
CHECKHR(hr = HrCreatePropCrypt(&m_pPropCrypt));
|
|
|
|
// Decode it
|
|
hr = m_pPropCrypt->HrDecode(pIn, pOut);
|
|
#ifdef DEBUG
|
|
if (FAILED(hr))
|
|
{
|
|
Assert(!pOut->pBlobData);
|
|
}
|
|
#endif
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::SetOriginalPropsToDirty
|
|
// -----------------------------------------------------------------------------
|
|
VOID CPropertyContainer::SetOriginalPropsToDirty(VOID)
|
|
{
|
|
PROPVALUE *pProp;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Loop through properties
|
|
pProp = m_prgPropValue;
|
|
for (ULONG i=0; i<m_cProperties; i++)
|
|
{
|
|
// If property was set during load and its not already dirty
|
|
if ((pProp->dwValueFlags & PV_SetOnLoad) && !(pProp->dwValueFlags & PV_WriteDirty))
|
|
{
|
|
m_cDirtyProps++;
|
|
pProp->dwValueFlags |= PV_WriteDirty;
|
|
Assert(m_cDirtyProps <= m_cProperties);
|
|
}
|
|
|
|
pProp++;
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::FIsBeingLoaded
|
|
// -----------------------------------------------------------------------------
|
|
BOOL CPropertyContainer::FIsBeingLoaded(VOID)
|
|
{
|
|
return m_fLoading;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::EnterLoadContainer
|
|
// -----------------------------------------------------------------------------
|
|
VOID CPropertyContainer::EnterLoadContainer(VOID)
|
|
{
|
|
Assert(m_fLoading == FALSE);
|
|
m_fLoading = TRUE;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::LeaveLoadContainer
|
|
// -----------------------------------------------------------------------------
|
|
VOID CPropertyContainer::LeaveLoadContainer(VOID)
|
|
{
|
|
Assert(m_fLoading == TRUE);
|
|
m_fLoading = FALSE;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::FIsDirty
|
|
// -----------------------------------------------------------------------------
|
|
BOOL CPropertyContainer::FIsDirty(VOID)
|
|
{
|
|
return m_cDirtyProps ? TRUE : FALSE;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrIsPropDirty
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrIsPropDirty(DWORD dwPropTag, BOOL *pfDirty)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
|
|
Assert(pfDirty != NULL);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Bad Parameter
|
|
Assert(m_pPropertySet != NULL);
|
|
Assert(m_prgPropValue != NULL);
|
|
Assert(dwPropTag != 0);
|
|
|
|
// Get Propety Index
|
|
CHECKHR(hr = m_pPropertySet->HrIndexFromPropTag(dwPropTag, &i));
|
|
|
|
// check proptags
|
|
Assert(dwPropTag == m_prgPropValue[i].dwPropTag);
|
|
|
|
// If property has not be set, get its default from the property set
|
|
*pfDirty = (m_prgPropValue[i].dwValueFlags & PV_WriteDirty);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrSetAllPropsDirty
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrSetAllPropsDirty(BOOL fDirty)
|
|
{
|
|
// Locals
|
|
PROPVALUE *pProp;
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Verify container
|
|
Assert(m_pPropertySet != NULL);
|
|
Assert(m_prgPropValue != NULL);
|
|
|
|
// Assume no dirty props
|
|
m_cDirtyProps = fDirty ? m_cDirtyProps : 0;
|
|
|
|
// Loop throug properties
|
|
pProp = m_prgPropValue;
|
|
if (fDirty)
|
|
{
|
|
for (i=0; i<m_cProperties; i++)
|
|
{
|
|
pProp->dwValueFlags |= PV_WriteDirty;
|
|
pProp++;
|
|
}
|
|
}
|
|
|
|
// Remove write dirty flags
|
|
else
|
|
{
|
|
for (i=0; i<m_cProperties; i++)
|
|
{
|
|
pProp->dwValueFlags &= ~(pProp->dwValueFlags & PV_WriteDirty);
|
|
pProp++;
|
|
}
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrSetPropDirty
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrSetPropDirty(DWORD dwPropTag, BOOL fDirty)
|
|
{
|
|
// Locals
|
|
PROPVALUE *pProp;
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Verify container
|
|
Assert(m_pPropertySet != NULL);
|
|
Assert(m_prgPropValue != NULL);
|
|
Assert(dwPropTag != 0);
|
|
|
|
// Get Propety Index
|
|
CHECKHR(hr = m_pPropertySet->HrIndexFromPropTag(dwPropTag, &i));
|
|
|
|
// check proptags
|
|
Assert(dwPropTag == m_prgPropValue[i].dwPropTag);
|
|
|
|
pProp = &m_prgPropValue[i];
|
|
|
|
// Decrement dirty ?
|
|
if ((pProp->dwValueFlags & PV_WriteDirty) && !fDirty)
|
|
{
|
|
Assert(m_cDirtyProps > 0);
|
|
m_cDirtyProps--;
|
|
}
|
|
|
|
// Otherwise, increment dirty
|
|
else if (!(pProp->dwValueFlags & PV_WriteDirty) && fDirty)
|
|
{
|
|
m_cDirtyProps++;
|
|
Assert(m_cDirtyProps <= m_cProperties);
|
|
}
|
|
|
|
// Clear dirty flag
|
|
if (fDirty)
|
|
pProp->dwValueFlags |= PV_WriteDirty;
|
|
else
|
|
pProp->dwValueFlags &= ~(pProp->dwValueFlags & PV_WriteDirty);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrGetPropInfo
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrGetPropInfo(DWORD dwPropTag, LPPROPINFO pPropInfo)
|
|
{
|
|
// No property set
|
|
Assert(m_pPropertySet != NULL);
|
|
Assert(pPropInfo != NULL);
|
|
|
|
// Go through the property set
|
|
return m_pPropertySet->HrGetPropInfo(dwPropTag, pPropInfo);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrGetPropInfo
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrGetPropInfo(LPTSTR pszName, LPPROPINFO pPropInfo)
|
|
{
|
|
// No property set
|
|
Assert(m_pPropertySet != NULL);
|
|
Assert(pPropInfo != NULL);
|
|
Assert(pszName != NULL);
|
|
|
|
// Go through the property set
|
|
return m_pPropertySet->HrGetPropInfo(pszName, pPropInfo);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::GetPropDw
|
|
// -----------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertyContainer::GetPropDw(DWORD dwPropTag, DWORD *pdw)
|
|
{
|
|
ULONG cb = sizeof(DWORD);
|
|
return GetProp(dwPropTag, (LPBYTE)pdw, &cb);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::GetPropSz
|
|
// -----------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertyContainer::GetPropSz(DWORD dwPropTag, LPSTR psz, ULONG cchMax)
|
|
{
|
|
return GetProp(dwPropTag, (LPBYTE)psz, &cchMax);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrGetProp (BYTE)
|
|
// -----------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertyContainer::GetProp(DWORD dwPropTag, LPBYTE pb, ULONG *pcb)
|
|
{
|
|
// Locals
|
|
PROPVALUE *pProp;
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
PROPINFO rPropInfo;
|
|
PROPTYPE PropType;
|
|
DWORD cbStream;
|
|
LPBYTE pbDefault=NULL;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Check params
|
|
Assert(pcb);
|
|
Assert(m_pPropertySet && m_prgPropValue && dwPropTag);
|
|
|
|
// Get Propety Index
|
|
CHECKHR(hr = m_pPropertySet->HrIndexFromPropTag(dwPropTag, &i));
|
|
|
|
// check proptags
|
|
Assert(dwPropTag == m_prgPropValue[i].dwPropTag);
|
|
|
|
pProp = &m_prgPropValue[i];
|
|
|
|
// If property has not be set, get its default from the property set
|
|
if (!(pProp->dwValueFlags & PV_ValueSet))
|
|
{
|
|
// Locals
|
|
BYTE rgbDefault[512];
|
|
LPBYTE pb=NULL;
|
|
ULONG cb;
|
|
|
|
// Should not every be dirty at this point
|
|
Assert(!(pProp->dwValueFlags & PV_WriteDirty));
|
|
|
|
// If no default, then bail out
|
|
if (!(pProp->dwPropFlags & PF_DEFAULT))
|
|
{
|
|
hr = E_NoPropData;
|
|
goto exit;
|
|
}
|
|
|
|
// Get propinfo item
|
|
CHECKHR(hr = m_pPropertySet->HrGetPropInfo(dwPropTag, &rPropInfo));
|
|
|
|
// Do we need to allocate a local buffer
|
|
if (rPropInfo.Default.cbValue > sizeof (rgbDefault))
|
|
{
|
|
// Allocate memory
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pbDefault, rPropInfo.Default.cbValue));
|
|
|
|
// Set local default buff
|
|
pb = pbDefault;
|
|
cb = rPropInfo.Default.cbValue;
|
|
}
|
|
|
|
// Cool, I can use a local buffer and not allocate memory
|
|
else
|
|
{
|
|
pb = rgbDefault;
|
|
cb = sizeof(rgbDefault);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
ULONG cDirty;
|
|
cDirty = m_cDirtyProps;
|
|
#endif
|
|
|
|
// Get the size of the default value
|
|
CHECKHR(hr = PropUtil_HrBinaryFromVariant(rPropInfo.dwPropTag, &rPropInfo.Default.Variant,
|
|
rPropInfo.Default.cbValue, pb, &cb));
|
|
|
|
// Set the property
|
|
CHECKHR(hr = SetProp(dwPropTag, pb, cb));
|
|
|
|
// This does not cause the propety to be dirty
|
|
pProp->dwValueFlags &= ~(pProp->dwValueFlags & PV_WriteDirty);
|
|
|
|
// Decrement dirty props since I don't really consider this dirty since it is only using the default value
|
|
Assert(m_cDirtyProps > 0);
|
|
m_cDirtyProps--;
|
|
|
|
// Using Default
|
|
pProp->dwValueFlags |= PV_UsingDefault;
|
|
|
|
// The number of dirty properties should not have increased
|
|
Assert(cDirty == m_cDirtyProps);
|
|
}
|
|
|
|
// Get Prop Type
|
|
AssertSz(pProp->dwValueFlags & PV_ValueSet, "Fetching Uninitialized properties from container");
|
|
|
|
// Get Property Type
|
|
PropType = PROPTAG_TYPE(dwPropTag);
|
|
|
|
#ifdef DEBUG
|
|
if (pProp->pbValue == NULL)
|
|
Assert(pProp->cbValue == 0);
|
|
if (pProp->cbValue == 0)
|
|
Assert(pProp->pbValue == NULL);
|
|
#endif
|
|
|
|
if (pProp->pbValue == NULL || pProp->cbValue == 0)
|
|
{
|
|
if (pProp->dwPropFlags & PF_ENCRYPTED)
|
|
{
|
|
// if the acct settings haven't been committed yet, then pbValue and cbValue are NULL
|
|
// for new accts, but the value is actually set, so let's give it a chance to handle
|
|
// that case
|
|
hr = GetEncryptedProp(pProp, pb, pcb);
|
|
}
|
|
else
|
|
{
|
|
hr = E_NoPropData;
|
|
}
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (pProp->dwPropFlags & PF_ENCRYPTED)
|
|
GetEncryptedProp(pProp, pb, pcb);
|
|
else
|
|
{
|
|
// Just want the size ?
|
|
if (pb == NULL)
|
|
{
|
|
*pcb = pProp->cbValue;
|
|
goto exit;
|
|
}
|
|
|
|
// Is it big enough
|
|
if (pProp->cbValue > *pcb)
|
|
{
|
|
Assert(FALSE);
|
|
hr = TRAPHR(E_BufferTooSmall);
|
|
goto exit;
|
|
}
|
|
|
|
// Check Buffer
|
|
AssertWritePtr(pb, pProp->cbValue);
|
|
|
|
// Set outbound size
|
|
*pcb = pProp->cbValue;
|
|
|
|
// Copy Data from stream
|
|
if (TYPE_STREAM == PropType)
|
|
{
|
|
Assert(pProp->Variant.Lpstream);
|
|
CHECKHR(hr = HrCopyStreamToByte(pProp->Variant.Lpstream, pb, &cbStream));
|
|
Assert(cbStream == *pcb);
|
|
}
|
|
|
|
// Otherwise, simple copy
|
|
else
|
|
{
|
|
AssertReadPtr(pProp->pbValue, pProp->cbValue);
|
|
CopyMemory(pb, pProp->pbValue, pProp->cbValue);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pbDefault);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::GetEncryptedProp
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::GetEncryptedProp(PROPVALUE *ppv, LPBYTE pb, ULONG *pcb)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BLOB blobCleartext;
|
|
BLOB blobName;
|
|
BYTE *pbData = NULL;
|
|
ULONG cbData;
|
|
|
|
Assert(ppv != NULL);
|
|
|
|
if (TYPE_PASS != PROPTAG_TYPE(ppv->dwPropTag))
|
|
return E_FAIL;
|
|
|
|
if (!!(ppv->dwValueFlags & PV_WriteDirty))
|
|
{
|
|
Assert(ppv->Variant.pPass != NULL);
|
|
|
|
cbData = ppv->Variant.pPass->blobPassword.cbSize;
|
|
|
|
if (pb == NULL)
|
|
{
|
|
*pcb = cbData;
|
|
return(S_OK);
|
|
}
|
|
|
|
// Is it big enough
|
|
if (cbData > *pcb)
|
|
{
|
|
Assert(FALSE);
|
|
return(E_BufferTooSmall);
|
|
}
|
|
|
|
if (cbData > 0)
|
|
CopyMemory(pb, ppv->Variant.pPass->blobPassword.pBlobData, cbData);
|
|
else if (*pcb > 0)
|
|
*pb = 0;
|
|
*pcb = cbData;
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
Assert(ppv->pbValue != NULL);
|
|
|
|
blobName.pBlobData = ppv->pbValue;
|
|
blobName.cbSize = ppv->cbValue;
|
|
if (FAILED(HrDecryptProp(&blobName, &blobCleartext)))
|
|
{
|
|
hr = E_NoPropData;
|
|
goto exit;
|
|
}
|
|
|
|
// Just want the size ?
|
|
if (pb == NULL)
|
|
{
|
|
*pcb = blobCleartext.cbSize;
|
|
goto exit;
|
|
}
|
|
|
|
// Is it big enough
|
|
if (blobCleartext.cbSize > *pcb)
|
|
{
|
|
Assert(FALSE);
|
|
hr = TRAPHR(E_BufferTooSmall);
|
|
goto exit;
|
|
}
|
|
|
|
// Check Buffer
|
|
AssertWritePtr(pb, blobCleartext.cbSize);
|
|
|
|
// Set outbound size
|
|
*pcb = blobCleartext.cbSize;
|
|
|
|
if (blobCleartext.pBlobData)
|
|
{
|
|
Assert(blobCleartext.cbSize);
|
|
DOUTL(DOUTL_CPROP, "EncryptedProp: requested (tag: %lx)", ppv->dwPropTag);
|
|
// change the dout level to be a little random so I don't spew peoples passwords as easily
|
|
DOUTL(DOUTL_CPROP|2048, "EncryptedProp: data is \"%s\"", (LPSTR)blobCleartext.pBlobData);
|
|
AssertReadPtr(blobCleartext.pBlobData, blobCleartext.cbSize);
|
|
CopyMemory(pb, blobCleartext.pBlobData, blobCleartext.cbSize);
|
|
}
|
|
#ifdef DEBUG
|
|
else
|
|
{
|
|
DOUTL(DOUTL_CPROP, "EncryptedProp: requested (tag: %lx) -- NULL (hr = %lx)", ppv->dwPropTag, hr);
|
|
}
|
|
#endif
|
|
|
|
exit:
|
|
if (blobCleartext.pBlobData)
|
|
CoTaskMemFree(blobCleartext.pBlobData);
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::SetProp (DWORD)
|
|
// -----------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertyContainer::SetPropDw(DWORD dwPropTag, DWORD dw)
|
|
{
|
|
return SetProp(dwPropTag, (LPBYTE)&dw, sizeof(DWORD));
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::SetPropSz (SBCS/DBCS)
|
|
// -----------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertyContainer::SetPropSz(DWORD dwPropTag, LPSTR psz)
|
|
{
|
|
return SetProp(dwPropTag, (LPBYTE)psz, lstrlen(psz)+1);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::SetProp (BYTE)
|
|
// -----------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertyContainer::SetProp(DWORD dwPropTag, LPBYTE pb, ULONG cb)
|
|
{
|
|
// Locals
|
|
PROPVALUE *pProp;
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
PROPTYPE PropType;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// check params
|
|
Assert(m_pPropertySet && m_prgPropValue && dwPropTag);
|
|
|
|
#ifdef ATHENA_RTM_RELEASE
|
|
#error This migration code should be removed (t-erikne)
|
|
#else
|
|
if (dwPropTag == PROPTAG(TYPE_STRING, AP_FIRST+102) || // old IMAP pass
|
|
dwPropTag == PROPTAG(TYPE_STRING, AP_FIRST+202) || // old LDAP pass
|
|
dwPropTag == PROPTAG(TYPE_STRING, AP_FIRST+302) || // old NNTP pass
|
|
dwPropTag == PROPTAG(TYPE_STRING, AP_FIRST+402) || // old POP3 pass
|
|
dwPropTag == PROPTAG(TYPE_STRING, AP_FIRST+502)) // old SMTP pass
|
|
{
|
|
dwPropTag = PROPTAG(TYPE_PASS, PROPTAG_ID(dwPropTag));
|
|
}
|
|
#endif
|
|
|
|
// Get Propety Index
|
|
CHECKHR(hr = m_pPropertySet->HrIndexFromPropTag(dwPropTag, &i));
|
|
|
|
// check proptags
|
|
Assert(dwPropTag == m_prgPropValue[i].dwPropTag);
|
|
PropType = PROPTAG_TYPE(dwPropTag);
|
|
pProp = &m_prgPropValue[i];
|
|
|
|
// DEBUG validate string null terminated
|
|
#ifdef DEBUG
|
|
if (pb && (PropType == TYPE_STRING || PropType == TYPE_WSTRING))
|
|
AssertSz(pb[cb-1] == '\0', "String is not null terminated - I suspect a Page Fault is eminent.");
|
|
#endif
|
|
|
|
// Validate data minmax
|
|
CHECKHR(hr = HrValidateSetProp(PropType, pProp, pb, cb, &pProp->rMinMax));
|
|
|
|
//N too many special cases.. own fn?
|
|
//N besides, doesn't this make things out of sync in failure cases?
|
|
if (TYPE_PASS != PropType)
|
|
// Assume data is not set
|
|
pProp->cbValue = 0;
|
|
|
|
// Handle data type
|
|
switch(PropType)
|
|
{
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BOOL:
|
|
pProp->pbValue = (LPBYTE)&pProp->Variant.Bool;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_FLAGS:
|
|
pProp->pbValue = (LPBYTE)&pProp->Variant.Flags;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_DWORD:
|
|
pProp->pbValue = (LPBYTE)&pProp->Variant.Dword;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_LONG:
|
|
pProp->pbValue = (LPBYTE)&pProp->Variant.Long;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_WORD:
|
|
pProp->pbValue = (LPBYTE)&pProp->Variant.Word;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_SHORT:
|
|
pProp->pbValue = (LPBYTE)&pProp->Variant.Short;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BYTE:
|
|
pProp->pbValue = (LPBYTE)&pProp->Variant.Byte;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_CHAR:
|
|
pProp->pbValue = (LPBYTE)&pProp->Variant.Char;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_FILETIME:
|
|
pProp->pbValue = (LPBYTE)&pProp->Variant.Filetime;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_ULARGEINTEGER:
|
|
pProp->pbValue = (LPBYTE)&pProp->Variant.uhVal;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_STRING:
|
|
CHECKHR(hr = HrGrowDynamicProperty(cb, &pProp->cbAllocated, (LPBYTE *)&pProp->Variant.Lpstring, sizeof(BYTE)));
|
|
pProp->pbValue = (LPBYTE)pProp->Variant.Lpstring;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_WSTRING:
|
|
CHECKHR(hr = HrGrowDynamicProperty(cb, &pProp->cbAllocated, (LPBYTE *)&pProp->Variant.Lpwstring, sizeof(WCHAR)));
|
|
pProp->pbValue = (LPBYTE)pProp->Variant.Lpwstring;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BINARY:
|
|
CHECKHR(hr = HrGrowDynamicProperty(cb, &pProp->cbAllocated, (LPBYTE *)&pProp->Variant.Lpbyte, sizeof(BYTE)));
|
|
pProp->pbValue = (LPBYTE)pProp->Variant.Lpbyte;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_STREAM:
|
|
SafeRelease(pProp->Variant.Lpstream);
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_PASS:
|
|
if (!pProp->Variant.pPass)
|
|
{
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pProp->Variant.pPass, sizeof(PROPPASS)));
|
|
ZeroMemory(pProp->Variant.pPass, sizeof(PROPPASS));
|
|
DOUTL(DOUTL_CPROP, "EncryptedProp: created (tag: %lx) -- %lx", dwPropTag, pProp->Variant.pPass);
|
|
}
|
|
|
|
// if this case changes, look at the special casing for TYPE_PASS done below
|
|
if (FIsBeingLoaded())
|
|
{
|
|
// if this set is done during a load, the caller must be setting
|
|
// the registry -- that's all he has
|
|
|
|
CHECKHR(hr = HrGrowDynamicProperty(cb, &pProp->cbAllocated,
|
|
&pProp->Variant.pPass->pbRegData, sizeof(BYTE)));
|
|
pProp->pbValue = pProp->Variant.pPass->pbRegData;
|
|
DOUTL(DOUTL_CPROP, "EncryptedProp: regdata set (tag: %lx) (%d bytes, %c%c%c)", dwPropTag, cb,
|
|
LPWSTR(pb)[2], LPWSTR(pb)[3], LPWSTR(pb)[4]);
|
|
|
|
}
|
|
else
|
|
{
|
|
// the data incoming is the password -- that's all he knows about
|
|
|
|
if (pb && cb)
|
|
{
|
|
CHECKHR(hr = HrRealloc((LPVOID *)&pProp->Variant.pPass->blobPassword.pBlobData, cb));
|
|
AssertWritePtr(pProp->Variant.pPass->blobPassword.pBlobData, cb);
|
|
CopyMemory(pProp->Variant.pPass->blobPassword.pBlobData, pb, cb);
|
|
}
|
|
else
|
|
{
|
|
// why doesn't our realloc take 0 for a size?!?!!
|
|
SafeMemFree(pProp->Variant.pPass->blobPassword.pBlobData);
|
|
}
|
|
pProp->Variant.pPass->blobPassword.cbSize = cb;
|
|
DOUTL(DOUTL_CPROP, "EncryptedProp: value set (tag: %lx) (%d bytes)", dwPropTag, cb);
|
|
}
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
default:
|
|
AssertSz(FALSE, "Hmmm, bad property type, this should have failed earlier.");
|
|
hr = TRAPHR(E_BadPropType);
|
|
goto exit;
|
|
}
|
|
|
|
// Property Set
|
|
pProp->dwValueFlags |= PV_ValueSet;
|
|
|
|
// Not using default
|
|
pProp->dwValueFlags &= ~PV_UsingDefault;
|
|
|
|
if (TYPE_PASS != PropType || FIsBeingLoaded())
|
|
{
|
|
// Set data size
|
|
pProp->cbValue = cb;
|
|
|
|
// Copy Data from stream
|
|
if (pb)
|
|
{
|
|
if (TYPE_STREAM == PropType)
|
|
{
|
|
CHECKHR(hr = HrByteToStream(&pProp->Variant.Lpstream, pb, cb));
|
|
}
|
|
|
|
// Otherwise, just copy
|
|
else
|
|
{
|
|
AssertWritePtr(pProp->pbValue, cb);
|
|
CopyMemory(pProp->pbValue, pb, cb);
|
|
}
|
|
}
|
|
else
|
|
pProp->pbValue = NULL;
|
|
}
|
|
|
|
if (FIsBeingLoaded())
|
|
// If loading container, set the flag
|
|
pProp->dwValueFlags |= PV_SetOnLoad;
|
|
|
|
// Otherwise, Its dirty
|
|
else if (!(pProp->dwValueFlags & PV_WriteDirty))
|
|
{
|
|
pProp->dwValueFlags |= PV_WriteDirty;
|
|
m_cDirtyProps++;
|
|
Assert(m_cDirtyProps <= m_cProperties);
|
|
}
|
|
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertyContainer::HrGrowDynamicProperty
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrGrowDynamicProperty(DWORD cbNewSize, DWORD *pcbAllocated, LPBYTE *ppbData, DWORD dwUnitSize)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cb;
|
|
|
|
// Check Params
|
|
Assert(pcbAllocated && ppbData);
|
|
|
|
// Do we need to re allocate ?
|
|
if (cbNewSize > *pcbAllocated)
|
|
{
|
|
// Grow the buffer
|
|
|
|
//N what about the following alloc code:
|
|
// if (*pcbAllocated)
|
|
// *pcbAllocated = (cbNewSize + 256);
|
|
// else
|
|
// *pcbAllocated = cbNewSize;
|
|
// it would work better for passwords, I think
|
|
|
|
*pcbAllocated = (cbNewSize + 256);
|
|
|
|
// Compute number of bytes to allocate
|
|
cb = (*pcbAllocated) * dwUnitSize;
|
|
|
|
// Allocate some memory
|
|
CHECKHR(hr = HrRealloc((LPVOID *)ppbData, cb));
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::CPropertySet
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertyContainer::HrValidateSetProp(PROPTYPE PropType, LPPROPVALUE pPropValue, LPBYTE pb, ULONG cb, LPMINMAX pMinMax)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
XVARIANT Variant;
|
|
|
|
// Check Params
|
|
Assert(pPropValue && pMinMax);
|
|
|
|
// Validate min max
|
|
#ifdef DEBUG
|
|
if (pPropValue->dwPropFlags & PF_MINMAX)
|
|
Assert(pMinMax->dwMin < pMinMax->dwMax);
|
|
#endif
|
|
|
|
if (pb == NULL && cb == 0)
|
|
return(S_OK);
|
|
|
|
//N this array of Copymemories is not needed
|
|
//N with some casts and memcmps, the same end
|
|
//N could be achieved.
|
|
|
|
// Handle data type
|
|
switch(PropType)
|
|
{
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BOOL:
|
|
Assert(pb && cb);
|
|
if (cb != sizeof(DWORD))
|
|
{
|
|
hr = TRAPHR(E_BufferSizeMismatch);
|
|
goto exit;
|
|
}
|
|
Assert(!(pPropValue->dwPropFlags & PF_MINMAX));
|
|
CopyMemory(&Variant.Bool, pb, cb);
|
|
if (Variant.Bool != 0 && Variant.Bool != 1)
|
|
hr = TRAPHR(E_InvalidBooleanValue);
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_FLAGS:
|
|
Assert(pb && cb);
|
|
if (cb != sizeof(DWORD))
|
|
{
|
|
hr = TRAPHR(E_BufferSizeMismatch);
|
|
goto exit;
|
|
}
|
|
if (pPropValue->dwPropFlags & PF_MINMAX)
|
|
{
|
|
CopyMemory(&Variant.Flags, pb, cb);
|
|
if (Variant.Flags < (DWORD)pMinMax->dwMin || Variant.Flags > (DWORD)pMinMax->dwMax)
|
|
hr = TRAPHR(E_InvalidMinMaxValue);
|
|
}
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_DWORD:
|
|
Assert(pb && cb);
|
|
if (cb != sizeof(DWORD))
|
|
{
|
|
hr = TRAPHR(E_BufferSizeMismatch);
|
|
goto exit;
|
|
}
|
|
if (pPropValue->dwPropFlags & PF_MINMAX)
|
|
{
|
|
CopyMemory(&Variant.Dword, pb, cb);
|
|
if (Variant.Dword < (DWORD)pMinMax->dwMin || Variant.Dword > (DWORD)pMinMax->dwMax)
|
|
hr = TRAPHR(E_InvalidMinMaxValue);
|
|
}
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_LONG:
|
|
Assert(pb && cb);
|
|
if (cb != sizeof(LONG))
|
|
{
|
|
hr = TRAPHR(E_BufferSizeMismatch);
|
|
goto exit;
|
|
}
|
|
if (pPropValue->dwPropFlags & PF_MINMAX)
|
|
{
|
|
CopyMemory(&Variant.Long, pb, cb);
|
|
if (Variant.Long < (LONG)pMinMax->dwMin || Variant.Long > (LONG)pMinMax->dwMax)
|
|
hr = TRAPHR(E_InvalidMinMaxValue);
|
|
}
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_WORD:
|
|
Assert(pb && cb);
|
|
if (cb != sizeof(WORD))
|
|
{
|
|
hr = TRAPHR(E_BufferSizeMismatch);
|
|
goto exit;
|
|
}
|
|
if (pPropValue->dwPropFlags & PF_MINMAX)
|
|
{
|
|
CopyMemory(&Variant.Word, pb, cb);
|
|
if (Variant.Word < (WORD)pMinMax->dwMin || Variant.Word > (WORD)pMinMax->dwMax)
|
|
hr = TRAPHR(E_InvalidMinMaxValue);
|
|
}
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_SHORT:
|
|
Assert(pb && cb);
|
|
if (cb != sizeof(SHORT))
|
|
{
|
|
hr = TRAPHR(E_BufferSizeMismatch);
|
|
goto exit;
|
|
}
|
|
if (pPropValue->dwPropFlags & PF_MINMAX)
|
|
{
|
|
CopyMemory(&Variant.Short, pb, cb);
|
|
if (Variant.Short < (SHORT)pMinMax->dwMin || Variant.Short > (SHORT)pMinMax->dwMax)
|
|
hr = TRAPHR(E_InvalidMinMaxValue);
|
|
}
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BYTE:
|
|
Assert(pb && cb);
|
|
if (cb != sizeof(BYTE))
|
|
{
|
|
hr = TRAPHR(E_BufferSizeMismatch);
|
|
goto exit;
|
|
}
|
|
if (pPropValue->dwPropFlags & PF_MINMAX)
|
|
{
|
|
CopyMemory(&Variant.Byte, pb, cb);
|
|
if (Variant.Byte < (BYTE)pMinMax->dwMin || Variant.Byte > (BYTE)pMinMax->dwMax)
|
|
hr = TRAPHR(E_InvalidMinMaxValue);
|
|
}
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_CHAR:
|
|
Assert(pb && cb);
|
|
if (cb != sizeof(CHAR))
|
|
{
|
|
hr = TRAPHR(E_BufferSizeMismatch);
|
|
goto exit;
|
|
}
|
|
if (pPropValue->dwPropFlags & PF_MINMAX)
|
|
{
|
|
CopyMemory(&Variant.Char, pb, cb);
|
|
if (Variant.Char < (CHAR)pMinMax->dwMin || Variant.Char > (CHAR)pMinMax->dwMax)
|
|
hr = TRAPHR(E_InvalidMinMaxValue);
|
|
}
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_STRING:
|
|
case TYPE_WSTRING:
|
|
if (cb)
|
|
cb--;
|
|
|
|
case TYPE_BINARY:
|
|
case TYPE_PASS:
|
|
if (pPropValue->dwPropFlags & PF_MINMAX)
|
|
{
|
|
if (cb < pMinMax->dwMin || cb > pMinMax->dwMax)
|
|
hr = TRAPHR(E_InvalidMinMaxValue);
|
|
}
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_FILETIME:
|
|
case TYPE_STREAM:
|
|
case TYPE_ULARGEINTEGER:
|
|
Assert(!(pPropValue->dwPropFlags & PF_MINMAX));
|
|
break;
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
default:
|
|
AssertSz(FALSE, "Hmmm, bad property type, this should have failed earlier.");
|
|
hr = TRAPHR(E_BadPropType);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CPropertyContainer::PersistEncryptedProp(DWORD dwPropTag, BOOL *pfPasswChanged)
|
|
{
|
|
ULONG dex;
|
|
HRESULT hr;
|
|
|
|
if (TYPE_PASS != PROPTAG_TYPE(dwPropTag))
|
|
return E_FAIL;
|
|
|
|
DOUTL(DOUTL_CPROP, "EncryptedProp: persisted...");
|
|
CHECKHR(hr = m_pPropertySet->HrIndexFromPropTag(dwPropTag, &dex));
|
|
|
|
// better have a property by the time we get here
|
|
Assert(m_prgPropValue[dex].Variant.pPass);
|
|
|
|
Assert(pfPasswChanged);
|
|
|
|
// [shaheedp] QFE for OUTLOOK. Refer to Bug# 82393 in IE database.
|
|
// This is originally a hack we put in for Bug# 66724. For bug# 88393, we are just
|
|
// refining the hack. Refer to the mail attached to the bug# 82393.
|
|
if ((m_prgPropValue[dex].Variant.pPass->blobPassword.pBlobData) && (*m_prgPropValue[dex].Variant.pPass->blobPassword.pBlobData))
|
|
*pfPasswChanged = TRUE;
|
|
|
|
hr = HrEncryptProp(
|
|
m_prgPropValue[dex].Variant.pPass->blobPassword.pBlobData,
|
|
m_prgPropValue[dex].Variant.pPass->blobPassword.cbSize,
|
|
&m_prgPropValue[dex].Variant.pPass->pbRegData,
|
|
&m_prgPropValue[dex].cbValue);
|
|
m_prgPropValue[dex].pbValue = m_prgPropValue[dex].Variant.pPass->pbRegData;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::CPropertySet
|
|
// -----------------------------------------------------------------------------
|
|
CPropertySet::CPropertySet()
|
|
{
|
|
m_cRef = 1;
|
|
m_cProperties = 0;
|
|
m_ulPropIdMin = 0;
|
|
m_ulPropIdMax = 0;
|
|
m_fInit = FALSE;
|
|
m_prgPropInfo = NULL;
|
|
m_prgPropValue = NULL;
|
|
m_rgpInfo = NULL;
|
|
m_cpInfo = 0;
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::~CPropertySet
|
|
// -----------------------------------------------------------------------------
|
|
CPropertySet::~CPropertySet()
|
|
{
|
|
Assert(m_cRef == 0);
|
|
ResetPropertySet();
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::AddRef
|
|
// -----------------------------------------------------------------------------
|
|
ULONG CPropertySet::AddRef(VOID)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::Release
|
|
// -----------------------------------------------------------------------------
|
|
ULONG CPropertySet::Release(VOID)
|
|
{
|
|
if (--m_cRef == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_cRef;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::ResetPropertySet
|
|
// -----------------------------------------------------------------------------
|
|
VOID CPropertySet::ResetPropertySet(VOID)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Free prgPropValue array
|
|
if (m_prgPropValue)
|
|
{
|
|
PropUtil_FreePropValueArrayItems(m_prgPropValue, m_cProperties);
|
|
SafeMemFree(m_prgPropValue);
|
|
}
|
|
|
|
// Free prgPropInfo array
|
|
if (m_prgPropInfo)
|
|
{
|
|
PropUtil_FreePropInfoArrayItems(m_prgPropInfo, m_cProperties);
|
|
SafeMemFree(m_prgPropInfo);
|
|
}
|
|
|
|
if (m_rgpInfo != NULL)
|
|
{
|
|
MemFree(m_rgpInfo);
|
|
m_rgpInfo = NULL;
|
|
}
|
|
|
|
// Reset the rest of the properset information
|
|
m_cProperties = 0;
|
|
m_ulPropIdMin = 0;
|
|
m_ulPropIdMax = 0;
|
|
m_cpInfo = 0;
|
|
m_fInit = FALSE;
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::HrInit
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertySet::HrInit(LPCPROPINFO prgPropInfo, ULONG cProperties)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
PSETINFO rPsetInfo;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Check Params
|
|
Assert(prgPropInfo && cProperties);
|
|
AssertReadPtr(prgPropInfo, sizeof(PROPINFO) * cProperties);
|
|
|
|
// free current data
|
|
ResetPropertySet();
|
|
|
|
// Duplicate and sort the propinfo array
|
|
CHECKHR(hr = PropUtil_HrDupPropInfoArray(prgPropInfo, cProperties, &rPsetInfo));
|
|
|
|
// Copy PsetInfo Items
|
|
m_prgPropInfo = rPsetInfo.prgPropInfo;
|
|
m_cProperties = rPsetInfo.cProperties;
|
|
m_ulPropIdMin = rPsetInfo.ulPropIdMin;
|
|
m_ulPropIdMax = rPsetInfo.ulPropIdMax;
|
|
|
|
m_rgpInfo = rPsetInfo.rgpInfo;
|
|
m_cpInfo = rPsetInfo.cpInfo;
|
|
|
|
// Lets validate prgPropInfo
|
|
CHECKHR(hr = PropUtil_HrValidatePropInfo(m_prgPropInfo, m_cProperties));
|
|
|
|
// We are ready to go
|
|
m_fInit = TRUE;
|
|
|
|
exit:
|
|
// If failed, reset state
|
|
if (FAILED(hr))
|
|
{
|
|
ResetPropertySet();
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::HrGetPropInfo
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertySet::HrGetPropInfo(LPTSTR pszName, LPPROPINFO pPropInfo)
|
|
{
|
|
// Locals
|
|
int cmp, left, right, x;
|
|
PROPINFO *pInfo;
|
|
HRESULT hr=S_OK;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Check Params
|
|
Assert(pszName && m_fInit);
|
|
AssertReadWritePtr(m_prgPropInfo, sizeof(PROPINFO) * m_cProperties);
|
|
AssertWritePtr(pPropInfo, sizeof(PROPINFO));
|
|
|
|
left = 0;
|
|
right = m_cpInfo - 1;
|
|
do
|
|
{
|
|
x = (left + right) / 2;
|
|
pInfo = m_rgpInfo[x];
|
|
cmp = OEMstrcmpi(pszName, pInfo->pszName);
|
|
if (cmp == 0)
|
|
{
|
|
CopyMemory(pPropInfo, pInfo, sizeof(PROPINFO));
|
|
goto exit;
|
|
}
|
|
else if (cmp < 0)
|
|
right = x - 1;
|
|
else
|
|
left = x + 1;
|
|
}
|
|
while (right >= left);
|
|
|
|
// If we make here, we failed
|
|
hr = TRAPHR(E_PropNotFound);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::HrGetPropInfo
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertySet::HrGetPropInfo(DWORD dwPropTag, LPPROPINFO pPropInfo)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
ULONG i;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Check Params
|
|
Assert(dwPropTag && m_fInit);
|
|
AssertReadWritePtr(m_prgPropInfo, sizeof(PROPINFO) * m_cProperties);
|
|
AssertWritePtr(pPropInfo, sizeof(PROPINFO));
|
|
|
|
// Compute array index based on proptag
|
|
CHECKHR(hr = HrIndexFromPropTag(dwPropTag, &i));
|
|
|
|
// Index into propinfo array
|
|
CopyMemory(pPropInfo, &m_prgPropInfo[i], sizeof(PROPINFO));
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::HrGetPropValueArray
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertySet::HrGetPropValueArray(LPPROPVALUE *pprgPropValue, ULONG *pcProperties)
|
|
{
|
|
// Locals
|
|
LPPROPINFO pInfo;
|
|
PROPVALUE *pValue;
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Check Params
|
|
Assert(pprgPropValue && pcProperties && m_fInit);
|
|
|
|
// Set number of properties
|
|
*pcProperties = m_cProperties;
|
|
*pprgPropValue = NULL;
|
|
|
|
// Have I created my private cached prop data array
|
|
if (m_prgPropValue == NULL)
|
|
{
|
|
// Allocate it
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&m_prgPropValue, sizeof(PROPVALUE) * m_cProperties));
|
|
|
|
// Zeroinit
|
|
ZeroMemory(m_prgPropValue, sizeof(PROPVALUE) * m_cProperties);
|
|
|
|
// Set Prop Tags
|
|
AssertReadPtr(m_prgPropInfo, m_cProperties * sizeof(PROPINFO));
|
|
|
|
pInfo = m_prgPropInfo;
|
|
pValue = m_prgPropValue;
|
|
for (i=0; i<m_cProperties; i++)
|
|
{
|
|
// Zero property tags are ok but undesireable
|
|
if (pInfo->dwPropTag != 0)
|
|
{
|
|
// Property Tag
|
|
if (FIsValidPropTag(pInfo->dwPropTag))
|
|
{
|
|
pValue->dwPropTag = pInfo->dwPropTag;
|
|
pValue->dwPropFlags = pInfo->dwFlags;
|
|
CopyMemory(&pValue->rMinMax, &pInfo->rMinMax, sizeof(MINMAX));
|
|
}
|
|
}
|
|
|
|
pInfo++;
|
|
pValue++;
|
|
}
|
|
}
|
|
|
|
// Allocate outbound propdata array
|
|
CHECKHR(hr = HrAlloc((LPVOID *)pprgPropValue, sizeof(PROPVALUE) * m_cProperties));
|
|
|
|
// Lets valid some memory
|
|
Assert(m_prgPropValue);
|
|
AssertReadPtr(m_prgPropValue, m_cProperties * sizeof(PROPVALUE));
|
|
AssertReadWritePtr(*pprgPropValue, m_cProperties * sizeof(PROPVALUE));
|
|
|
|
// Copy Cached Prop Data Array
|
|
CopyMemory(*pprgPropValue, m_prgPropValue, sizeof(PROPVALUE) * m_cProperties);
|
|
|
|
exit:
|
|
// If we fail, free stuff and return
|
|
if (FAILED(hr))
|
|
{
|
|
SafeMemFree((*pprgPropValue));
|
|
*pcProperties = 0;
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::FIsValidPropTag
|
|
// -----------------------------------------------------------------------------
|
|
BOOL CPropertySet::FIsValidPropTag(DWORD dwPropTag)
|
|
{
|
|
// Locals
|
|
DWORD dwPropId = PROPTAG_ID(dwPropTag);
|
|
|
|
// If proptag is zero
|
|
if (dwPropTag == 0)
|
|
return FALSE;
|
|
|
|
// Make sure prop id is in our range
|
|
if (dwPropId < m_ulPropIdMin || dwPropId > m_ulPropIdMax)
|
|
return FALSE;
|
|
|
|
// Done
|
|
return PropUtil_FIsValidPropTagType(dwPropTag);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySet::HrIndexFromPropTag
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CPropertySet::HrIndexFromPropTag(DWORD dwPropTag, ULONG *pi)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Check Params
|
|
Assert(pi && dwPropTag);
|
|
|
|
// Valid Prop Tag ?
|
|
if (!FIsValidPropTag(dwPropTag))
|
|
{
|
|
AssertSz(FALSE, "Invalid dwPropTag in CPropertyContainer::HrGetProp");
|
|
hr = TRAPHR(E_InvalidPropTag);
|
|
goto exit;
|
|
}
|
|
|
|
// Set index
|
|
Assert(m_ulPropIdMin > 0 && PROPTAG_ID(dwPropTag) >= m_ulPropIdMin);
|
|
*pi = PROPTAG_ID(dwPropTag) - m_ulPropIdMin;
|
|
Assert(*pi < m_cProperties);
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CEnumProps::CEnumProps
|
|
// -----------------------------------------------------------------------------
|
|
CEnumProps::CEnumProps(CPropertyContainer *pPropertyContainer)
|
|
{
|
|
Assert(pPropertyContainer);
|
|
m_cRef = 1;
|
|
m_iProperty = -1;
|
|
m_pPropertyContainer = pPropertyContainer;
|
|
if (m_pPropertyContainer)
|
|
m_pPropertyContainer->AddRef();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CEnumProps::~CEnumProps
|
|
// -----------------------------------------------------------------------------
|
|
CEnumProps::~CEnumProps()
|
|
{
|
|
SafeRelease(m_pPropertyContainer);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CEnumProps::AddRef
|
|
// -----------------------------------------------------------------------------
|
|
ULONG CEnumProps::AddRef(VOID)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CEnumProps::Release
|
|
// -----------------------------------------------------------------------------
|
|
ULONG CEnumProps::Release(VOID)
|
|
{
|
|
if (--m_cRef == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_cRef;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CEnumProps::~CEnumProps
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CEnumProps::HrGetCount(ULONG *pcItems)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Use Critical Section of AddRef'ed CPropertyContainer
|
|
EnterCriticalSection(&m_pPropertyContainer->m_cs);
|
|
|
|
// Bad Parameter
|
|
if (pcItems == NULL || m_pPropertyContainer == NULL)
|
|
{
|
|
Assert(FALSE);
|
|
hr = TRAPHR(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
// Return number of properties
|
|
*pcItems = m_pPropertyContainer->m_cProperties;
|
|
|
|
exit:
|
|
// Use Critical Section of AddRef'ed CPropertyContainer
|
|
LeaveCriticalSection(&m_pPropertyContainer->m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CEnumProps::HrGetNext
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CEnumProps::HrGetNext(LPPROPVALUE pPropValue, LPPROPINFO pPropInfo)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Bad Parameter
|
|
if (m_pPropertyContainer == NULL)
|
|
{
|
|
Assert(FALSE);
|
|
hr = TRAPHR(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
// Use Critical Section of AddRef'ed CPropertyContainer
|
|
EnterCriticalSection(&m_pPropertyContainer->m_cs);
|
|
|
|
// We've got to skip empty propvalues
|
|
do
|
|
{
|
|
// Have we reached the end ?
|
|
//N + not needed if just do > ?
|
|
if (m_iProperty + 1 >= (LONG)m_pPropertyContainer->m_cProperties)
|
|
{
|
|
hr = E_EnumFinished;
|
|
goto exit;
|
|
}
|
|
|
|
// Increment m_iProperty
|
|
m_iProperty++;
|
|
|
|
} while(m_pPropertyContainer->m_prgPropValue[m_iProperty].dwPropTag == 0);
|
|
|
|
// Copy propdata
|
|
if (pPropValue)
|
|
CopyMemory(pPropValue, &m_pPropertyContainer->m_prgPropValue[m_iProperty], sizeof(PROPVALUE));
|
|
|
|
// propert info
|
|
if (pPropInfo)
|
|
{
|
|
// Get the property info from the property set
|
|
CHECKHR(hr = m_pPropertyContainer->m_pPropertySet->HrGetPropInfo(pPropValue->dwPropTag, pPropInfo));
|
|
}
|
|
|
|
exit:
|
|
// Use Critical Section of AddRef'ed CPropertyContainer
|
|
LeaveCriticalSection(&m_pPropertyContainer->m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CEnumProps::HrGetCurrent
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CEnumProps::HrGetCurrent(LPPROPVALUE pPropValue, LPPROPINFO pPropInfo)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Bad Parameter
|
|
if (m_pPropertyContainer == NULL)
|
|
{
|
|
Assert(FALSE);
|
|
hr = TRAPHR(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
// Use Critical Section of AddRef'ed CPropertyContainer
|
|
EnterCriticalSection(&m_pPropertyContainer->m_cs);
|
|
|
|
//N see other comment
|
|
if (m_iProperty + 1 >= (LONG)m_pPropertyContainer->m_cProperties)
|
|
{
|
|
hr = E_EnumFinished;
|
|
goto exit;
|
|
}
|
|
|
|
// Copy propdata
|
|
if (pPropValue)
|
|
CopyMemory(pPropValue, &m_pPropertyContainer->m_prgPropValue[m_iProperty], sizeof(PROPVALUE));
|
|
|
|
// propert info
|
|
if (pPropInfo)
|
|
{
|
|
// Get the property info from the property set
|
|
CHECKHR(hr = m_pPropertyContainer->m_pPropertySet->HrGetPropInfo(pPropValue->dwPropTag, pPropInfo));
|
|
}
|
|
|
|
exit:
|
|
// Use Critical Section of AddRef'ed CPropertyContainer
|
|
LeaveCriticalSection(&m_pPropertyContainer->m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CEnumProps::Reset
|
|
// -----------------------------------------------------------------------------
|
|
VOID CEnumProps::Reset(VOID)
|
|
{
|
|
m_iProperty = -1;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_FIsValidPropTagType
|
|
// -----------------------------------------------------------------------------
|
|
BOOL PropUtil_FIsValidPropTagType(DWORD dwPropTag)
|
|
{
|
|
// Locals
|
|
PROPTYPE PropType = PROPTAG_TYPE(dwPropTag);
|
|
|
|
// Zero proptag
|
|
if (dwPropTag == 0)
|
|
return FALSE;
|
|
|
|
// Check Data Type
|
|
if (PropType <= TYPE_ERROR || PropType >= TYPE_LAST)
|
|
{
|
|
AssertSz(FALSE, "Invalid property data type.");
|
|
return FALSE;
|
|
}
|
|
|
|
// Done
|
|
return TRUE;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_FreePropValueArrayItems
|
|
// -----------------------------------------------------------------------------
|
|
VOID PropUtil_FreePropValueArrayItems(LPPROPVALUE prgPropValue, ULONG cProperties)
|
|
{
|
|
// No array
|
|
Assert(prgPropValue);
|
|
|
|
// Validate memory
|
|
AssertReadWritePtr(prgPropValue, sizeof(PROPVALUE) * cProperties);
|
|
|
|
// Loop
|
|
for (register ULONG i=0; i<cProperties; i++)
|
|
{
|
|
// No proptag, noop
|
|
if (prgPropValue->dwPropTag != 0)
|
|
{
|
|
// Free variant value
|
|
PropUtil_FreeVariant(prgPropValue->dwPropTag, &prgPropValue->Variant, prgPropValue->cbValue);
|
|
|
|
// Zeroinit
|
|
prgPropValue->dwValueFlags = 0;
|
|
prgPropValue->cbAllocated = 0;
|
|
prgPropValue->cbValue = 0;
|
|
prgPropValue->pbValue = NULL;
|
|
}
|
|
|
|
prgPropValue++;
|
|
}
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_FreeVariant
|
|
// -----------------------------------------------------------------------------
|
|
VOID PropUtil_FreeVariant(DWORD dwPropTag, LPXVARIANT pVariant, DWORD cbValue)
|
|
{
|
|
// Locals
|
|
PROPTYPE PropType = PROPTAG_TYPE(dwPropTag);
|
|
|
|
// Check Params
|
|
Assert(pVariant && dwPropTag);
|
|
Assert(PropUtil_FIsValidPropTagType(dwPropTag));
|
|
|
|
if (pVariant->Dword != NULL)
|
|
{
|
|
// Release Stream
|
|
if (TYPE_STREAM == PropType)
|
|
{
|
|
if (pVariant->Lpstream)
|
|
{
|
|
AssertReadPtr(pVariant->Lpstream, sizeof(LPSTREAM));
|
|
pVariant->Lpstream->Release();
|
|
}
|
|
}
|
|
|
|
// String
|
|
else if (TYPE_STRING == PropType)
|
|
{
|
|
if (pVariant->Lpstring)
|
|
{
|
|
AssertReadWritePtr(pVariant->Lpstring, cbValue);
|
|
MemFree(pVariant->Lpstring);
|
|
}
|
|
}
|
|
|
|
// Wide-String
|
|
else if (TYPE_WSTRING == PropType)
|
|
{
|
|
if (pVariant->Lpwstring)
|
|
{
|
|
AssertReadWritePtr(pVariant->Lpwstring, cbValue);
|
|
MemFree(pVariant->Lpwstring);
|
|
}
|
|
}
|
|
|
|
// Binary
|
|
else if (TYPE_BINARY == PropType)
|
|
{
|
|
if (pVariant->Lpbyte)
|
|
{
|
|
AssertReadWritePtr(pVariant->Lpbyte, cbValue);
|
|
MemFree(pVariant->Lpbyte);
|
|
}
|
|
}
|
|
|
|
// Password
|
|
else if (TYPE_PASS == PropType)
|
|
{
|
|
if (pVariant->pPass)
|
|
{
|
|
DOUTL(DOUTL_CPROP, "EncryptedProp: varient freed -- %lx", pVariant->pPass);
|
|
AssertReadWritePtr(pVariant->pPass, sizeof(PROPPASS));
|
|
if (pVariant->pPass->pbRegData)
|
|
{
|
|
AssertReadWritePtr(pVariant->pPass->pbRegData, cbValue);
|
|
MemFree(pVariant->pPass->pbRegData);
|
|
}
|
|
if (pVariant->pPass->blobPassword.pBlobData)
|
|
{
|
|
AssertReadWritePtr(pVariant->pPass->blobPassword.pBlobData,
|
|
pVariant->pPass->blobPassword.cbSize);
|
|
MemFree(pVariant->pPass->blobPassword.pBlobData);
|
|
}
|
|
MemFree(pVariant->pPass);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset data items so it can be re-used
|
|
ZeroMemory(pVariant, sizeof(XVARIANT));
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_FreePropInfoArrayItems
|
|
// -----------------------------------------------------------------------------
|
|
VOID PropUtil_FreePropInfoArrayItems(LPPROPINFO prgPropInfo, ULONG cProperties)
|
|
{
|
|
// Locals
|
|
LPPROPINFO pInfo;
|
|
ULONG i;
|
|
|
|
// Nothing to free ?
|
|
if (prgPropInfo == NULL || cProperties == 0)
|
|
return;
|
|
|
|
// Check Params
|
|
AssertReadWritePtr(prgPropInfo, sizeof(PROPINFO) * cProperties);
|
|
|
|
// Loop
|
|
pInfo = prgPropInfo;
|
|
for (i=0; i<cProperties; i++)
|
|
{
|
|
// No prop
|
|
if (pInfo->dwPropTag != 0)
|
|
{
|
|
// Free property name
|
|
SafeMemFree(pInfo->pszName);
|
|
|
|
// Free default value
|
|
PropUtil_FreeVariant(pInfo->dwPropTag, &pInfo->Default.Variant, pInfo->Default.cbValue);
|
|
}
|
|
|
|
pInfo++;
|
|
}
|
|
|
|
// Zero it
|
|
ZeroMemory(prgPropInfo, sizeof(PROPINFO) * cProperties);
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
void qsort(PROPINFO **ppInfo, long left, long right)
|
|
{
|
|
long i, j;
|
|
PROPINFO *pT, *k;
|
|
|
|
i = left;
|
|
j = right;
|
|
k = ppInfo[(left + right) / 2];
|
|
|
|
do
|
|
{
|
|
while (OEMstrcmpi(ppInfo[i]->pszName, k->pszName) < 0 && i < right)
|
|
i++;
|
|
while (OEMstrcmpi(ppInfo[j]->pszName, k->pszName) > 0 && j > left)
|
|
j--;
|
|
|
|
if (i <= j)
|
|
{
|
|
pT = ppInfo[i];
|
|
ppInfo[i] = ppInfo[j];
|
|
ppInfo[j] = pT;
|
|
i++; j--;
|
|
}
|
|
}
|
|
while (i <= j);
|
|
|
|
if (left < j)
|
|
qsort(ppInfo, left, j);
|
|
if (i < right)
|
|
qsort(ppInfo, i, right);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_HrDupPropInfoArray
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT PropUtil_HrDupPropInfoArray(LPCPROPINFO prgPropInfoSrc, ULONG cPropsSrc, LPPSETINFO pPsetInfo)
|
|
{
|
|
// Locals
|
|
LPCPROPINFO pInfo;
|
|
LPPROPINFO pSet, *ppInfo;
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
ULONG ulPropId,
|
|
nIndex;
|
|
|
|
// Check Param
|
|
Assert(cPropsSrc > 0);
|
|
Assert(prgPropInfoSrc != NULL);
|
|
Assert(pPsetInfo != NULL);
|
|
AssertReadPtr(prgPropInfoSrc, sizeof(PROPINFO) * cPropsSrc);
|
|
|
|
// Init
|
|
ZeroMemory(pPsetInfo, sizeof(PSETINFO));
|
|
|
|
// Lets find the min and max property ids
|
|
pPsetInfo->ulPropIdMin = 0xffffffff;
|
|
|
|
pInfo = prgPropInfoSrc;
|
|
for(i=0; i<cPropsSrc; i++)
|
|
{
|
|
ulPropId = PROPTAG_ID(pInfo->dwPropTag);
|
|
if (ulPropId > pPsetInfo->ulPropIdMax)
|
|
pPsetInfo->ulPropIdMax = ulPropId;
|
|
if (ulPropId < pPsetInfo->ulPropIdMin)
|
|
pPsetInfo->ulPropIdMin = ulPropId;
|
|
pInfo++;
|
|
}
|
|
|
|
Assert(pPsetInfo->ulPropIdMin <= pPsetInfo->ulPropIdMax);
|
|
Assert((pPsetInfo->ulPropIdMax - pPsetInfo->ulPropIdMin) + 1 >= cPropsSrc);
|
|
|
|
// Compute real number of properties
|
|
pPsetInfo->cProperties = (pPsetInfo->ulPropIdMax - pPsetInfo->ulPropIdMin) + 1;
|
|
|
|
// Allocate Dest
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pPsetInfo->prgPropInfo, sizeof(PROPINFO) * pPsetInfo->cProperties));
|
|
|
|
// Zero init
|
|
ZeroMemory(pPsetInfo->prgPropInfo, sizeof(PROPINFO) * pPsetInfo->cProperties);
|
|
|
|
CHECKHR(hr = HrAlloc((void **)&pPsetInfo->rgpInfo, sizeof(PROPINFO *) * cPropsSrc));
|
|
pPsetInfo->cpInfo = cPropsSrc;
|
|
|
|
// Loop through src propinfo
|
|
pInfo = prgPropInfoSrc;
|
|
ppInfo = pPsetInfo->rgpInfo;
|
|
for(i=0; i<cPropsSrc; i++)
|
|
{
|
|
// Only if valid proptag
|
|
Assert(PropUtil_FIsValidPropTagType(pInfo->dwPropTag));
|
|
|
|
// Compute index into dest array in which the proptag should be
|
|
nIndex = PROPTAG_ID(pInfo->dwPropTag) - pPsetInfo->ulPropIdMin;
|
|
pSet = &pPsetInfo->prgPropInfo[nIndex];
|
|
|
|
*ppInfo = pSet;
|
|
|
|
// Duplicate ?
|
|
Assert(pSet->dwPropTag == 0);
|
|
|
|
// PropTag
|
|
pSet->dwPropTag = pInfo->dwPropTag;
|
|
|
|
// Flags
|
|
pSet->dwFlags = pInfo->dwFlags;
|
|
|
|
// Property Name
|
|
pSet->pszName = PszDupA(pInfo->pszName);
|
|
|
|
// Default Value
|
|
if (pSet->dwFlags & PF_DEFAULT)
|
|
{
|
|
// Copy Default Value
|
|
CHECKHR(hr = PropUtil_HrCopyVariant(pInfo->dwPropTag,
|
|
&pInfo->Default.Variant,
|
|
pInfo->Default.cbValue,
|
|
&pSet->Default.Variant,
|
|
&pSet->Default.cbValue));
|
|
}
|
|
|
|
// Copy minmax info
|
|
CopyMemory(&pSet->rMinMax, &pInfo->rMinMax, sizeof(MINMAX));
|
|
|
|
// Validate minmax
|
|
//N should add code to make sure minmax struct is zeros if !PF_MINMAX, saves
|
|
//N confusion should that ever get copied
|
|
Assert(!!(pSet->dwFlags & PF_MINMAX) || (pSet->rMinMax.dwMax >= pSet->rMinMax.dwMin));
|
|
|
|
pInfo++;
|
|
ppInfo++;
|
|
}
|
|
|
|
qsort(pPsetInfo->rgpInfo, 0, pPsetInfo->cpInfo - 1);
|
|
|
|
exit:
|
|
// If failed, free stuff
|
|
if (FAILED(hr))
|
|
{
|
|
PropUtil_FreePropInfoArrayItems(pPsetInfo->prgPropInfo, pPsetInfo->cProperties);
|
|
SafeMemFree(pPsetInfo->prgPropInfo);
|
|
SafeMemFree(pPsetInfo->rgpInfo);
|
|
ZeroMemory(pPsetInfo, sizeof(PSETINFO));
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_HrBinaryFromVariant
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT PropUtil_HrBinaryFromVariant(DWORD dwPropTag, LPXVARIANT pVariant, DWORD cbValue, LPBYTE pb, DWORD *pcb)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
PROPTYPE PropType = PROPTAG_TYPE(dwPropTag);
|
|
DWORD cbStream;
|
|
LPBYTE pbValue=NULL;
|
|
|
|
// Validate Parameters
|
|
if (pVariant == NULL || pb == NULL || pcb == NULL || dwPropTag == 0)
|
|
{
|
|
hr = TRAPHR(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
// Handle data type
|
|
switch(PropType)
|
|
{
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BOOL:
|
|
Assert(cbValue == sizeof(DWORD));
|
|
pbValue = (LPBYTE)&pVariant->Bool;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_FLAGS:
|
|
Assert(cbValue == sizeof(DWORD));
|
|
pbValue = (LPBYTE)&pVariant->Flags;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_DWORD:
|
|
Assert(cbValue == sizeof(DWORD));
|
|
pbValue = (LPBYTE)&pVariant->Dword;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_LONG:
|
|
Assert(cbValue == sizeof(LONG));
|
|
pbValue = (LPBYTE)&pVariant->Long;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_WORD:
|
|
Assert(cbValue == sizeof(WORD));
|
|
pbValue = (LPBYTE)&pVariant->Word;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_SHORT:
|
|
Assert(cbValue == sizeof(SHORT));
|
|
pbValue = (LPBYTE)&pVariant->Short;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BYTE:
|
|
Assert(cbValue == sizeof(BYTE));
|
|
pbValue = (LPBYTE)&pVariant->Byte;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_CHAR:
|
|
Assert(cbValue == sizeof(CHAR));
|
|
pbValue = (LPBYTE)&pVariant->Char;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_FILETIME:
|
|
Assert(cbValue == sizeof(FILETIME));
|
|
pbValue = (LPBYTE)&pVariant->Filetime;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_ULARGEINTEGER:
|
|
Assert(cbValue == sizeof(ULARGE_INTEGER));
|
|
pbValue = (LPBYTE)&pVariant->uhVal;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_STRING:
|
|
Assert(cbValue == (DWORD)lstrlen(pVariant->Lpstring)+1);
|
|
pbValue = (LPBYTE)pVariant->Lpstring;
|
|
AssertSz(pbValue[cbValue-sizeof(char)] == '\0',
|
|
"String is not null terminated - I suspect a Page Fault is eminent.");
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_WSTRING:
|
|
Assert(cbValue == (DWORD)(lstrlenW(pVariant->Lpwstring)+1) * sizeof(WCHAR));
|
|
pbValue = (LPBYTE)pVariant->Lpwstring;
|
|
Assert(2 == sizeof(WCHAR)); // Next assert depends on this
|
|
AssertSz(pbValue[cbValue-1] == '\0' && pbValue[cbValue-2] == '\0',
|
|
"WString is not null terminated - I suspect a Page Fault is eminent.");
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BINARY:
|
|
pbValue = pVariant->Lpbyte;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_PASS:
|
|
pbValue = (pVariant->pPass) ? pVariant->pPass->pbRegData : NULL;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_STREAM:
|
|
if (pVariant->Lpstream)
|
|
HrGetStreamSize(pVariant->Lpstream, &cbValue);
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
default:
|
|
AssertSz(FALSE, "Hmmm, bad property type, this should have failed earlier.");
|
|
hr = TRAPHR(E_BadPropType);
|
|
goto exit;
|
|
}
|
|
|
|
// No Data ?
|
|
if (cbValue == 0 || pbValue == NULL)
|
|
{
|
|
*pcb = cbValue;
|
|
goto exit;
|
|
}
|
|
|
|
// Is it big enough
|
|
if (cbValue > *pcb)
|
|
{
|
|
hr = TRAPHR(E_BufferTooSmall);
|
|
goto exit;
|
|
}
|
|
|
|
// Check Buffer
|
|
AssertWritePtr(pb, cbValue);
|
|
|
|
// Set outbound size
|
|
*pcb = cbValue;
|
|
|
|
// Copy Data from stream
|
|
if (TYPE_STREAM == PropType)
|
|
{
|
|
Assert(pVariant->Lpstream);
|
|
CHECKHR(hr = HrCopyStreamToByte(pVariant->Lpstream, pb, &cbStream));
|
|
Assert(cbStream == *pcb);
|
|
}
|
|
|
|
// Otherwise, simple copy
|
|
else
|
|
{
|
|
AssertReadPtr(pbValue, cbValue);
|
|
CopyMemory(pb, pbValue, cbValue);
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_HrCopyVariant
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT PropUtil_HrCopyVariant(DWORD dwPropTag, LPCXVARIANT pVariantSrc, DWORD cbSrc, LPXVARIANT pVariantDest, DWORD *pcbDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
PROPTYPE PropType = PROPTAG_TYPE(dwPropTag);
|
|
|
|
// Validate Parameters
|
|
if (pVariantSrc == NULL || pVariantDest == NULL || pcbDest == NULL || dwPropTag == 0)
|
|
{
|
|
hr = TRAPHR(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
// Handle data type
|
|
switch(PropType)
|
|
{
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BOOL:
|
|
*pcbDest = sizeof(DWORD);
|
|
pVariantDest->Bool = pVariantSrc->Bool;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_FLAGS:
|
|
*pcbDest = sizeof(DWORD);
|
|
pVariantDest->Flags = pVariantSrc->Flags;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_DWORD:
|
|
*pcbDest = sizeof(DWORD);
|
|
pVariantDest->Dword = pVariantSrc->Dword;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_LONG:
|
|
*pcbDest = sizeof(LONG);
|
|
pVariantDest->Long = pVariantSrc->Long;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_WORD:
|
|
*pcbDest = sizeof(WORD);
|
|
pVariantDest->Word = pVariantSrc->Word;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_SHORT:
|
|
*pcbDest = sizeof(SHORT);
|
|
pVariantDest->Short = pVariantSrc->Short;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BYTE:
|
|
*pcbDest = sizeof(BYTE);
|
|
pVariantDest->Byte = pVariantSrc->Byte;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_CHAR:
|
|
*pcbDest = sizeof(CHAR);
|
|
pVariantDest->Char = pVariantSrc->Char;
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_FILETIME:
|
|
Assert(cbSrc == sizeof(FILETIME));
|
|
*pcbDest = sizeof(FILETIME);
|
|
CopyMemory(&pVariantDest->Filetime, &pVariantSrc->Filetime, sizeof(FILETIME));
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_ULARGEINTEGER:
|
|
Assert(cbSrc == sizeof(ULARGE_INTEGER));
|
|
*pcbDest = sizeof(ULARGE_INTEGER);
|
|
CopyMemory(&pVariantDest->uhVal, &pVariantSrc->uhVal, sizeof(ULARGE_INTEGER));
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_STRING:
|
|
{
|
|
LPSTR pszSrc;
|
|
char sz[512];
|
|
|
|
// Check if this is actually a string resource ID
|
|
if (0 == HIWORD(pVariantSrc->Lpstring))
|
|
{
|
|
// Load the default from the string resource table
|
|
cbSrc = LoadString(g_hInstRes, LOWORD(pVariantSrc->Lpstring),
|
|
sz, sizeof(sz)) + 1; // Add 1 to cbSrc to null-term
|
|
if (1 == cbSrc) // LoadString returns 0 on failure, + 1 == 1
|
|
{
|
|
// Rather than prevent OE from starting, just substitute blank string
|
|
AssertSz(FALSE, "Could not load string resource default value");
|
|
sz[0] = '\0';
|
|
}
|
|
pszSrc = sz;
|
|
}
|
|
else
|
|
{
|
|
Assert(cbSrc);
|
|
AssertReadPtr(pVariantSrc->Lpstring, cbSrc);
|
|
pszSrc = pVariantSrc->Lpstring;
|
|
}
|
|
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pVariantDest->Lpstring, cbSrc));
|
|
AssertWritePtr(pVariantDest->Lpstring, cbSrc);
|
|
*pcbDest = cbSrc;
|
|
CopyMemory(pVariantDest->Lpstring, pszSrc, cbSrc);
|
|
Assert(pVariantDest->Lpstring[cbSrc-1] == '\0');
|
|
|
|
} // case TYPE_STRING
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_WSTRING:
|
|
Assert(cbSrc);
|
|
AssertReadPtr(pVariantSrc->Lpwstring, cbSrc);
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pVariantDest->Lpwstring, cbSrc));
|
|
AssertWritePtr(pVariantDest->Lpwstring, cbSrc);
|
|
*pcbDest = cbSrc;
|
|
CopyMemory(pVariantDest->Lpwstring, pVariantSrc->Lpwstring, cbSrc);
|
|
Assert(2 == sizeof(WCHAR));
|
|
Assert(pVariantDest->Lpwstring[cbSrc-1] == '\0' &&
|
|
pVariantDest->Lpwstring[cbSrc-2] == '\0');
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_BINARY:
|
|
Assert(cbSrc);
|
|
AssertReadPtr(pVariantSrc->Lpbyte, cbSrc);
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pVariantDest->Lpbyte, cbSrc));
|
|
AssertWritePtr(pVariantDest->Lpbyte, cbSrc);
|
|
*pcbDest = cbSrc;
|
|
CopyMemory(pVariantDest->Lpbyte, pVariantSrc->Lpbyte, cbSrc);
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_PASS:
|
|
Assert(cbSrc);
|
|
if (pVariantSrc->pPass)
|
|
{
|
|
AssertReadPtr(pVariantSrc->pPass->pbRegData, cbSrc);
|
|
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pVariantDest->pPass, sizeof(PROPPASS)));
|
|
ZeroMemory(pVariantDest->pPass, sizeof(PROPPASS));
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pVariantDest->pPass->pbRegData, cbSrc));
|
|
|
|
AssertWritePtr(pVariantDest->pPass->pbRegData, cbSrc);
|
|
*pcbDest = cbSrc;
|
|
CopyMemory(pVariantDest->pPass->pbRegData, pVariantSrc->pPass->pbRegData, cbSrc);
|
|
}
|
|
else
|
|
{
|
|
*pcbDest = 0;
|
|
}
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
case TYPE_STREAM:
|
|
pVariantDest->Lpstream = pVariantSrc->Lpstream;
|
|
if (pVariantDest->Lpstream)
|
|
pVariantDest->Lpstream->AddRef();
|
|
break;
|
|
|
|
// ----------------------------------------------------------------
|
|
default:
|
|
AssertSz(FALSE, "Hmmm, bad property type, this should have failed earlier.");
|
|
hr = TRAPHR(E_BadPropType);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_FRegCompatDataTypes
|
|
// -----------------------------------------------------------------------------
|
|
BOOL PropUtil_FRegCompatDataTypes(DWORD dwPropTag, DWORD dwRegType)
|
|
{
|
|
// Locals
|
|
BOOL fResult=FALSE;
|
|
|
|
// Check Params
|
|
Assert(dwPropTag);
|
|
|
|
// Map Property Type to registry type
|
|
switch(PROPTAG_TYPE(dwPropTag))
|
|
{
|
|
case TYPE_BOOL:
|
|
case TYPE_DWORD:
|
|
case TYPE_LONG:
|
|
case TYPE_WORD:
|
|
case TYPE_SHORT:
|
|
case TYPE_FLAGS:
|
|
if (dwRegType == REG_DWORD)
|
|
fResult = TRUE;
|
|
break;
|
|
|
|
case TYPE_CHAR:
|
|
case TYPE_BINARY:
|
|
case TYPE_BYTE:
|
|
case TYPE_FILETIME:
|
|
case TYPE_PASS:
|
|
case TYPE_ULARGEINTEGER:
|
|
if (dwRegType == REG_BINARY)
|
|
fResult = TRUE;
|
|
break;
|
|
|
|
case TYPE_STRING:
|
|
case TYPE_WSTRING:
|
|
if (dwRegType == REG_SZ || dwRegType == REG_BINARY || dwRegType == REG_EXPAND_SZ)
|
|
fResult = TRUE;
|
|
break;
|
|
|
|
default:
|
|
AssertSz(FALSE, "Property type is not supported by the registry.");
|
|
TRAPHR(E_FAIL);
|
|
break;
|
|
}
|
|
|
|
// Done
|
|
return fResult;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_HrRegTypeFromPropTag
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT PropUtil_HrRegTypeFromPropTag(DWORD dwPropTag, DWORD *pdwRegType)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
PROPTYPE PropType = PROPTAG_TYPE(dwPropTag);
|
|
|
|
// Check Params
|
|
Assert(dwPropTag && pdwRegType);
|
|
|
|
// Map Property Type to registry type
|
|
switch(PROPTAG_TYPE(PropType))
|
|
{
|
|
case TYPE_BOOL:
|
|
case TYPE_DWORD:
|
|
case TYPE_LONG:
|
|
case TYPE_WORD:
|
|
case TYPE_SHORT:
|
|
case TYPE_FLAGS:
|
|
*pdwRegType = REG_DWORD;
|
|
break;
|
|
|
|
case TYPE_CHAR:
|
|
case TYPE_BINARY:
|
|
case TYPE_BYTE:
|
|
case TYPE_FILETIME:
|
|
case TYPE_PASS:
|
|
case TYPE_ULARGEINTEGER:
|
|
*pdwRegType = REG_BINARY;
|
|
break;
|
|
|
|
case TYPE_STRING:
|
|
case TYPE_WSTRING:
|
|
*pdwRegType = REG_SZ;
|
|
break;
|
|
|
|
default:
|
|
AssertSz(FALSE, "Property type is not supported by the registry.");
|
|
hr = TRAPHR(E_FAIL);
|
|
*pdwRegType = 0;
|
|
break;
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_HrValidatePropInfo
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT PropUtil_HrValidatePropInfo(LPPROPINFO prgPropInfo, ULONG cProperties)
|
|
{
|
|
#ifdef DEBUG
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
|
|
// Check Params
|
|
Assert(prgPropInfo);
|
|
AssertReadPtr(prgPropInfo, cProperties * sizeof(PROPINFO));
|
|
|
|
// Loop through the propinfo array
|
|
for (i=0; i<cProperties; i++)
|
|
{
|
|
// Empty proptags are okay, but undesireable
|
|
if (prgPropInfo[i].dwPropTag == 0)
|
|
continue;
|
|
|
|
// This should never happen
|
|
if (PROPTAG_ID(prgPropInfo[i].dwPropTag) > MAX_PROPID)
|
|
{
|
|
AssertSz(FALSE, "Property Tag Id is somehow greater than the MAX_PROPID.");
|
|
hr = TRAPHR(E_InvalidPropertySet);
|
|
goto exit;
|
|
}
|
|
|
|
// Validate Property data type
|
|
if (PropUtil_FIsValidPropTagType(PROPTAG_TYPE(prgPropInfo[i].dwPropTag)) == FALSE)
|
|
{
|
|
AssertSz(FALSE, "Invalid Property Type.");
|
|
hr = TRAPHR(E_InvalidPropertySet);
|
|
goto exit;
|
|
}
|
|
|
|
// Propids should be in ascending order
|
|
if (i > 0)
|
|
{
|
|
if (PROPTAG_ID(prgPropInfo[i].dwPropTag) <= PROPTAG_ID(prgPropInfo[i-1].dwPropTag))
|
|
{
|
|
AssertSz(FALSE, "Property Tag Ids are not in ascending order.");
|
|
hr = TRAPHR(E_InvalidPropertySet);
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
#else
|
|
return(S_OK);
|
|
#endif // DEBUG
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_HrPersistContainerToRegistry
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT PropUtil_HrPersistContainerToRegistry(HKEY hkeyReg, CPropertyContainer *pPropertyContainer, BOOL *pfPasswChanged)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CEnumProps *pEnumProps=NULL;
|
|
PROPVALUE rPropValue;
|
|
PROPINFO rPropInfo;
|
|
DWORD dwType;
|
|
|
|
// Check Parameters
|
|
if (hkeyReg == NULL || pPropertyContainer == NULL)
|
|
{
|
|
hr = TRAPHR(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
*pfPasswChanged = FALSE;
|
|
// Enumerate CPropertyContainer
|
|
CHECKHR(hr = pPropertyContainer->HrEnumProps(&pEnumProps));
|
|
|
|
// Loop through all properties
|
|
while(SUCCEEDED(pEnumProps->HrGetNext(&rPropValue, &rPropInfo)))
|
|
{
|
|
// Not Dirty
|
|
if (!(rPropValue.dwValueFlags & PV_WriteDirty))
|
|
continue;
|
|
|
|
// In addition to having the registry value set, encrypted properties need
|
|
// other info to be persisted on commit.
|
|
// needs to happen before we continue the loop, even on delete, since this
|
|
// function call will cause that to happen
|
|
|
|
// [BUGBUG]. We should test for the proptag being equal to password prop.
|
|
// This will cause a problem if we add another property that needs to be encrypted.
|
|
if (rPropValue.dwPropFlags & PF_ENCRYPTED)
|
|
{
|
|
hr = pPropertyContainer->PersistEncryptedProp(rPropValue.dwPropTag, pfPasswChanged);
|
|
if (S_PasswordDeleted == hr || FAILED(hr))
|
|
{
|
|
rPropInfo.dwFlags |= PF_NOPERSIST;
|
|
if (hr != S_PasswordDeleted)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
else // succeeded and not password deleted
|
|
{
|
|
// [shaheedp] QFE for OUTLOOK. Refer to Bug# 82393 in IE database.
|
|
// This is originally a hack we put in for Bug# 66724. For bug# 88393, we are just
|
|
// refining the hack. Refer to the mail attached to the bug# 82393.
|
|
|
|
//*fPasswChanged = TRUE;
|
|
|
|
// reload
|
|
CHECKHR(hr = pEnumProps->HrGetCurrent(&rPropValue, &rPropInfo));
|
|
}
|
|
}
|
|
|
|
// Not persist, or no data ?
|
|
if (rPropInfo.dwFlags & PF_NOPERSIST || rPropValue.cbValue == 0 || rPropValue.pbValue == NULL)
|
|
{
|
|
// Make sure the value is not in the registry
|
|
if (rPropInfo.pszName)
|
|
RegDeleteValue(hkeyReg, rPropInfo.pszName);
|
|
|
|
// Its not dirty
|
|
pPropertyContainer->HrSetPropDirty(rPropValue.dwPropTag, FALSE);
|
|
continue;
|
|
}
|
|
|
|
// The value should have been set
|
|
Assert(rPropInfo.pszName && (rPropValue.dwValueFlags & PV_ValueSet));
|
|
|
|
// Get property reg data type
|
|
if (FAILED(PropUtil_HrRegTypeFromPropTag(rPropValue.dwPropTag, &dwType)))
|
|
{
|
|
AssertSz(FALSE, "We've got problems, my 24 inch pythons are shrinking.");
|
|
continue;
|
|
}
|
|
|
|
// Set value into the registry
|
|
AssertReadPtr(rPropValue.pbValue, rPropValue.cbValue);
|
|
if (RegSetValueEx(hkeyReg, rPropInfo.pszName, 0, dwType, rPropValue.pbValue, rPropValue.cbValue) != ERROR_SUCCESS)
|
|
{
|
|
hr = TRAPHR(E_RegSetValueFailed);
|
|
goto exit;
|
|
}
|
|
|
|
// Not dirty
|
|
CHECKHR(hr = pPropertyContainer->HrSetPropDirty(rPropValue.dwPropTag, FALSE));
|
|
}
|
|
|
|
// Better not have any dirty properties
|
|
Assert(pPropertyContainer->FIsDirty() == FALSE);
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pEnumProps);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// PropUtil_HrLoadContainerFromRegistry
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT PropUtil_HrLoadContainerFromRegistry(HKEY hkeyReg, CPropertyContainer *pPropertyContainer)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD i=0,
|
|
cbValueName=0,
|
|
dwType,
|
|
cbData=0,
|
|
cbValueNameMax=0,
|
|
cbDataMax=0;
|
|
LONG lResult;
|
|
LPTSTR pszValueName=NULL;
|
|
LPBYTE pbDataT, pbData=NULL;
|
|
PROPINFO rPropInfo;
|
|
|
|
// Check Parameters
|
|
Assert(hkeyReg != NULL);
|
|
Assert(pPropertyContainer != NULL);
|
|
|
|
// Should be in the load state
|
|
Assert(pPropertyContainer->FIsBeingLoaded());
|
|
|
|
// Reset the container in case we are re-opening an account
|
|
//N this is a waste if we are not... can we tell?
|
|
//pPropertyContainer->ResetContainer();
|
|
|
|
// Lets get max value name length and the max value data length
|
|
if (RegQueryInfoKey (hkeyReg, NULL, NULL, 0, NULL, NULL, NULL, NULL,
|
|
&cbValueNameMax, &cbDataMax, NULL, NULL) != ERROR_SUCCESS)
|
|
{
|
|
hr = TRAPHR(E_RegQueryInfoKeyFailed);
|
|
goto exit;
|
|
}
|
|
|
|
// Add One to length
|
|
cbValueNameMax++;
|
|
|
|
// Allocate local buffer for value names
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pszValueName, cbValueNameMax));
|
|
|
|
// Allocate local buffer for value data
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pbData, cbDataMax));
|
|
|
|
// Enumerate through values in the account
|
|
for(i=0;;i++)
|
|
{
|
|
// Get the value name and data
|
|
cbValueName = cbValueNameMax;
|
|
cbData = cbDataMax;
|
|
lResult = RegEnumValue(hkeyReg, i, pszValueName, &cbValueName, 0, &dwType, pbData, &cbData);
|
|
|
|
// Done ?
|
|
if (lResult == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
|
|
// Error
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
AssertSz(FALSE, "Why did RegEnumValue fail, I may be skipping values.");
|
|
continue;
|
|
}
|
|
|
|
// Find property based on name
|
|
if (FAILED(pPropertyContainer->HrGetPropInfo(pszValueName, &rPropInfo)))
|
|
continue;
|
|
|
|
// Compatible Data Types ?
|
|
if (!PropUtil_FRegCompatDataTypes(rPropInfo.dwPropTag, dwType))
|
|
{
|
|
AssertSz(FALSE, "Registry data type is not compatible with the associated property.");
|
|
continue;
|
|
}
|
|
|
|
if (dwType == REG_EXPAND_SZ)
|
|
{
|
|
DWORD cchNewLen;
|
|
hr = HrAlloc((LPVOID *)&pbDataT, cbData * sizeof(TCHAR));
|
|
IF_FAILEXIT(hr);
|
|
cchNewLen = ExpandEnvironmentStrings((TCHAR *)pbData, (TCHAR *)pbDataT, cbData);
|
|
if (cchNewLen > cbData)
|
|
{
|
|
// Not enough room for the expanded string, allocate more memory
|
|
MemFree(pbDataT);
|
|
hr = HrAlloc((LPVOID *)&pbDataT, cchNewLen * sizeof(TCHAR));
|
|
IF_FAILEXIT(hr);
|
|
|
|
cbData = ExpandEnvironmentStrings((TCHAR *)pbData, (TCHAR *)pbDataT, cchNewLen);
|
|
|
|
if ((0 == cbData ) || (cbData > cchNewLen))
|
|
{
|
|
AssertSz(0, "We gave ExpandEnvironmentStrings more mem, and it still failed!");
|
|
TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
cbData = (lstrlen((TCHAR *)pbDataT) + 1) * sizeof(TCHAR);
|
|
CopyMemory(pbData, pbDataT, cbData);
|
|
MemFree(pbDataT);
|
|
}
|
|
|
|
CHECKHR(hr = pPropertyContainer->SetProp(rPropInfo.dwPropTag, pbData, cbData));
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
if (pszValueName)
|
|
MemFree(pszValueName);
|
|
if (pbData)
|
|
MemFree(pbData);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|