Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

561 lines
14 KiB

// PPPBag.cpp : Implementation of CPropertyPagePropertyBag
#include "stdafx.h"
#include "WizChain.h"
#include "PPPBag.h"
#include "PropItem.h"
/////////////////////////////////////////////////////////////////////////////
// CPropertyPagePropertyBag
STDMETHODIMP CPropertyPagePropertyBag::GetProperty( BSTR szGUID, VARIANT* pvar, PPPBAG_TYPE* pdwFlags, BOOL* pbIsOwner )
{
if ( !szGUID || !pvar || !pdwFlags || !pbIsOwner ) return E_POINTER;
CLSID clsid;
HRESULT hr = S_OK;
RPC_STATUS rpcs = UuidFromString( (LPOLESTR)szGUID, &clsid );
if( RPC_S_OK != rpcs )
{
return HRESULT_FROM_WIN32(rpcs);
}
VariantInit( pvar );
*pdwFlags = PPPBAG_TYPE_UNINITIALIZED;
// no need to make sure szGUID is a valid guid
// since it won't be in the map
std::map<BSTR, CBagEntry*, CBSTR_Less>::iterator mapiter;
mapiter = m_map.find( szGUID );
if( mapiter != m_map.end() )
{
CBagEntry * pBE = mapiter->second;
if( pBE )
{
if( SUCCEEDED(VariantCopy( pvar, pBE->GetVariant() )) )
{
*pdwFlags = pBE->GetFlags( );
*pbIsOwner = (pBE->GetOwner( ) == m_dwOwner);
return S_OK;
}
else
{
return E_FAIL;
}
}
}
return E_INVALIDARG;
}
// a couple of helper functions
HRESULT HelperDelete(std::map<BSTR, CBagEntry*, CBSTR_Less>& map, BSTR szGUID, DWORD dwOwner );
HRESULT HelperAdd (std::map<BSTR, CBagEntry*, CBSTR_Less>& map, BSTR szGUID, CBagEntry* pBE);
STDMETHODIMP CPropertyPagePropertyBag::SetProperty( BSTR szGUID, VARIANT* pvar, PPPBAG_TYPE dwFlags )
{
// validate parameters
if( !szGUID || !pvar ) return E_POINTER;
CLSID clsid;
RPC_STATUS rpcs = UuidFromString( (LPOLESTR)szGUID, &clsid );
if( RPC_S_OK != rpcs )
{
return HRESULT_FROM_WIN32(rpcs);
}
switch( dwFlags )
{
case PPPBAG_TYPE_READWRITE:
case PPPBAG_TYPE_READONLY:
case PPPBAG_TYPE_ADDITIVE:
case PPPBAG_TYPE_DELETION:
{
break;
}
default:
{
return E_INVALIDARG;
}
}
if( m_bReadOnly != FALSE )
{
return E_UNEXPECTED;
}
switch( dwFlags )
{
case PPPBAG_TYPE_DELETION:
{
return HelperDelete( m_map, szGUID, m_dwOwner );
}
case PPPBAG_TYPE_READWRITE:
{
// anyone can write to one of these
HelperDelete( m_map, szGUID, m_dwOwner );
CBagEntry* pBagEntry = new CBagEntry( pvar, dwFlags, m_dwOwner );
if( !pBagEntry ) return E_OUTOFMEMORY;
return HelperAdd( m_map, szGUID, pBagEntry );
}
case PPPBAG_TYPE_READONLY:
{
// only allow owner to write to this kind of entry
HRESULT hr = HelperDelete( m_map, szGUID, m_dwOwner );
if( hr == S_OK )
{
CBagEntry* pBagEntry = new CBagEntry( pvar, dwFlags, m_dwOwner );
if( !pBagEntry ) return E_OUTOFMEMORY;
hr = HelperAdd( m_map, szGUID, pBagEntry );
}
return hr;
}
case PPPBAG_TYPE_ADDITIVE:
{
// TODO: add code so that additive properties work correctly
return E_NOTIMPL;
}
}
return S_OK;
}
HRESULT HelperDelete( std::map<BSTR, CBagEntry*, CBSTR_Less> & map, BSTR szGUID, DWORD dwOwner )
{
std::map<BSTR, CBagEntry*, CBSTR_Less>::iterator mapiter;
mapiter = map.find( szGUID );
if( mapiter != map.end( ) )
{
CBagEntry * pBE = mapiter->second;
if( pBE )
{
if( pBE->GetFlags( ) == PPPBAG_TYPE_READONLY )
{
if( pBE->GetOwner( ) != dwOwner ) // component's trying to delete
{
return E_UNEXPECTED; // an entry that doesn't belong to it
}
}
}
SysFreeString( mapiter->first );
delete mapiter->second;
map.erase( mapiter );
}
return S_OK;
}
HRESULT HelperAdd( std::map<BSTR, CBagEntry*, CBSTR_Less>& map, BSTR szGUID, CBagEntry* pBE )
{
std::map<BSTR, CBagEntry*, CBSTR_Less>::iterator mapiter = map.find( szGUID );
if( mapiter != map.end() )
{
assert( 0 && "this should have been deleted by now!" );
SysFreeString( mapiter->first );
delete mapiter->second;
map.erase( mapiter );
}
BSTR bstr = SysAllocString( (LPOLESTR)szGUID );
if( !bstr )
{
return E_OUTOFMEMORY;
}
map[bstr] = pBE;
return S_OK;
}
HRESULT CPropertyPagePropertyBag::Enumerate( long index, BSTR* pbstr, VARIANT* pvar, PPPBAG_TYPE* pdwFlags, BOOL* pbIsOwner, BOOL* pbInRange )
{
if( !pbstr || !pvar|| !pdwFlags || !pbIsOwner || !pbInRange ) return E_POINTER;
if( index >= 0 )
{
long i = 0;
std::map<BSTR, CBagEntry *, CBSTR_Less>::iterator mapiter = m_map.begin( );
while( mapiter != m_map.end() )
{
if( i == index )
{
*pbstr = SysAllocString( mapiter->first );
CBagEntry* pBE = mapiter->second;
assert( pBE != NULL );
if( SUCCEEDED(VariantCopy( pvar, pBE->GetVariant() )) )
{
*pdwFlags = pBE->GetFlags();
*pbIsOwner = (pBE->GetOwner() == m_dwOwner);
*pbInRange = TRUE;
return S_OK;
}
return E_FAIL;
}
mapiter++;
i++;
}
}
// out of range
*pdwFlags = PPPBAG_TYPE_UNINITIALIZED;
*pbInRange = FALSE;
return S_FALSE;
}
// helper
IDispatch* CreateItem( BSTR bstrGuid, VARIANT* var, PPPBAG_TYPE dwFlags )
{
// create the item and initialize it
CComObject<CPropertyItem>* pPI = NULL;
CComObject<CPropertyItem>::CreateInstance( &pPI );
if( !pPI ) return NULL;
pPI->Initialize( bstrGuid, var, dwFlags ); // Initialize the Property Item
// return back an IDispatch *
IDispatch* pDisp = NULL;
pPI->AddRef( );
pPI->QueryInterface( IID_IDispatch, (void**)&pDisp ); // can't fail
pPI->Release( );
assert( pDisp != NULL );
return pDisp;
}
class CEnumVariant : public IEnumVARIANT
{
private:
ULONG m_refs;
ULONG m_index;
CPropertyPagePropertyBag* m_pPPPBag; // addref'd !
CEnumVariant( CPropertyPagePropertyBag* pPPPBag )
{
assert( pPPPBag != NULL );
m_refs = 0;
m_index = 0;
m_pPPPBag = pPPPBag;
m_pPPPBag->AddRef();
}
~CEnumVariant ()
{
m_pPPPBag->Release();
}
public:
static IEnumVARIANT* CreateInstance( CPropertyPagePropertyBag* pPPPBag )
{
assert( pPPPBag != NULL );
CEnumVariant* pCEV = new CEnumVariant( pPPPBag );
if( !pCEV )
{
return NULL;
}
IEnumVARIANT* pIEV = NULL;
pCEV->AddRef( );
pCEV->QueryInterface( IID_IEnumVARIANT, (void**)&pIEV );
pCEV->Release( );
return pIEV;
}
// IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void** ppvObject )
{
HRESULT hr = S_OK;
if ((riid == IID_IUnknown) ||
(riid == IID_IEnumVARIANT) )
{
AddRef();
*ppvObject = (void*)this;
}
else
{
hr = E_NOINTERFACE;
}
return hr;
}
virtual ULONG STDMETHODCALLTYPE AddRef( )
{
InterlockedIncrement( (PLONG)&m_refs );
return m_refs;
}
virtual ULONG STDMETHODCALLTYPE Release( )
{
InterlockedDecrement( (PLONG)&m_refs );
ULONG l = m_refs;
if( m_refs == 0 )
{
delete this;
}
return l;
}
// IEnumVARIANT
virtual HRESULT STDMETHODCALLTYPE Next( /*[in]*/ ULONG celt, /*[out, size_is(celt), length_is(*pCeltFetched)]*/ VARIANT* rgVar, /*[out]*/ ULONG* pCeltFetched )
{
// clear stuff being passed in (just in case)
if( pCeltFetched )
{
*pCeltFetched = 0;
}
for( ULONG i = 0; i < celt; i++ )
{
VariantInit( &rgVar[i] );
}
// get the next celt elements
for( i = 0; i < celt; i++ )
{
BSTR bstr = NULL;
VARIANT var;
VariantInit( &var );
PPPBAG_TYPE dwFlags = PPPBAG_TYPE_UNINITIALIZED;
BOOL bIsOwner = FALSE;
BOOL bInRange = FALSE;
m_pPPPBag->Enumerate( (long)m_index++, &bstr, &var, &dwFlags, &bIsOwner, &bInRange );
if( bInRange == FALSE )
{
break;
}
IDispatch* pDisp = CreateItem( bstr, &var, dwFlags );
VariantClear( &var );
if( pDisp == NULL )
{
return E_OUTOFMEMORY;
}
rgVar[i].vt = VT_DISPATCH;
rgVar[i].pdispVal = pDisp;
}
// fill out how many we're returning
if( pCeltFetched )
{
*pCeltFetched = i;
}
return ( (i < celt) ? S_FALSE : S_OK);
}
virtual HRESULT STDMETHODCALLTYPE Skip( /*[in]*/ ULONG celt )
{
long count;
m_pPPPBag->get_Count( &count );
if( (celt + m_index) > (ULONG)count )
{
return S_FALSE;
}
m_index += celt;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE Reset( )
{
m_index = 0;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE Clone( /*[out]*/ IEnumVARIANT** ppEnum )
{
if( !(*ppEnum = CreateInstance( m_pPPPBag )) )
{
return E_OUTOFMEMORY;
}
return S_OK;
}
};
// CPropertyCollection
STDMETHODIMP CPropertyPagePropertyBag::get__NewEnum( IUnknown** pVal )
{
if( !pVal ) return E_POINTER;
IEnumVARIANT* pEV = CEnumVariant::CreateInstance( this );
if( !pEV ) return E_OUTOFMEMORY;
HRESULT hr = pEV->QueryInterface( IID_IUnknown, (void**)pVal );
pEV->Release();
return hr;
}
STDMETHODIMP CPropertyPagePropertyBag::get_Item( VARIANT* pVar, IDispatch** pVal )
{
// handle both:
// objFoo.Item(1), and
// objFoo.Item("string");
// validate parameters
if( !pVar || !pVal ) return E_POINTER;
*pVal = NULL;
if( V_VT(pVar) == VT_BSTR )
{
BSTR bstrGuid = V_BSTR(pVar);
CLSID clsid;
HRESULT hr = S_OK;
RPC_STATUS rpcs = UuidFromString( (LPOLESTR)bstrGuid, &clsid );
if( RPC_S_OK != rpcs )
{
return HRESULT_FROM_WIN32(rpcs);
}
std::map<BSTR, CBagEntry*, CBSTR_Less>::iterator mapiter;
mapiter = m_map.find( bstrGuid );
if( mapiter != m_map.end() )
{
CBagEntry* pBE = mapiter->second;
if( pBE )
{
if( !(*pVal = CreateItem( bstrGuid, pBE->GetVariant(), pBE->GetFlags() )) )
{
return E_OUTOFMEMORY;
}
return S_OK;
}
}
}
else if ( (V_VT(pVar) == VT_I2) || (V_VT(pVar) == VT_I4) )
{
long index;
if( V_VT(pVar) == VT_I4 )
{
index = V_I4(pVar);
}
else
{
index = V_I2(pVar);
}
BSTR bstr = NULL;
VARIANT var;
VariantInit (&var);
PPPBAG_TYPE dwFlags = PPPBAG_TYPE_UNINITIALIZED;
BOOL bIsOwner = FALSE;
BOOL bInRange = FALSE;
HRESULT hr = Enumerate( index, &bstr, &var, &dwFlags, &bIsOwner, &bInRange );
if( SUCCEEDED(hr) && (bInRange == TRUE) )
{
if( !(*pVal = CreateItem( bstr, &var, dwFlags )) )
{
hr = E_OUTOFMEMORY;
}
}
VariantClear ( &var );
SysFreeString( bstr );
return hr;
}
else
{
return E_UNEXPECTED; // not a valid variant type
}
return S_FALSE;
}
STDMETHODIMP CPropertyPagePropertyBag::get_Count( long *pVal )
{
if( !pVal ) return E_POINTER;
// TODO: figure out how to use map.count method
long i = 0;
std::map<BSTR, CBagEntry*, CBSTR_Less>::iterator mapiter = m_map.begin();
while( mapiter != m_map.end() )
{
mapiter++;
i++;
}
*pVal = i;
return S_OK;
}
STDMETHODIMP CPropertyPagePropertyBag::Add(BSTR bstrGuid, VARIANT *varValue, long iFlags, IPropertyItem **ppItem)
{
// validate parameters
if( !bstrGuid || !varValue || !ppItem ) return E_POINTER;
*ppItem = NULL;
HRESULT hr = SetProperty( bstrGuid, varValue, (PPPBAG_TYPE)iFlags );
if( hr == S_OK )
{
IDispatch* pDisp = CreateItem( bstrGuid, varValue, (PPPBAG_TYPE)iFlags );
if( !pDisp )
{
hr = E_OUTOFMEMORY;
}
else
{
hr = pDisp->QueryInterface( IID_IPropertyItem, (void**)ppItem );
pDisp->Release();
}
}
return hr;
}
STDMETHODIMP CPropertyPagePropertyBag::Remove( BSTR bstrGuid )
{
if( !bstrGuid ) return E_POINTER;
CLSID clsid;
RPC_STATUS rpcs = UuidFromString( (LPOLESTR)bstrGuid, &clsid );
if( RPC_S_OK != rpcs )
{
return HRESULT_FROM_WIN32(rpcs);
}
return HelperDelete( m_map, bstrGuid, m_dwOwner );
}