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.
 
 
 
 
 
 

513 lines
12 KiB

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1998, Microsoft Corp. All rights reserved.
//
// FILE
//
// dsobject.cpp
//
// SYNOPSIS
//
// This file defines the class DSObject.
//
// MODIFICATION HISTORY
//
// 02/20/1998 Original version.
// 06/09/1998 Refresh property cache before enumerating dirty objects.
// 02/11/1999 Keep downlevel parameters in sync.
// 03/16/1999 Return error if downlevel update fails.
//
///////////////////////////////////////////////////////////////////////////////
#include <ias.h>
#include <iasutil.h>
#include <dsenum.h>
#include <dsobject.h>
#include <vector>
WCHAR USER_PARAMETERS_NAME[] = L"UserParameters";
// Smart pointer for an IADsPropertyEntryPtr.
_COM_SMARTPTR_TYPEDEF(IADsPropertyEntry, __uuidof(IADsPropertyEntry));
//////////
// Prefix added to all RDN's.
//////////
_bstr_t DSObject::thePrefix(L"CN=");
//////////
// The name of the 'name' property.
//////////
_bstr_t DSObject::theNameProperty(L"name");
_bstr_t DSObject::theUserParametersProperty(USER_PARAMETERS_NAME);
DSObject::DSObject(IUnknown* subject)
: oldParms(NULL)
{
_Module.Lock();
// All subjects must support IADs && IDirectoryObject.
_com_util::CheckError(subject->QueryInterface(
__uuidof(IADs),
(PVOID*)&leaf
));
_com_util::CheckError(Restore());
}
DSObject::~DSObject() throw ()
{
SysFreeString(oldParms);
_Module.Unlock();
}
//////////
// IUnknown implementation is copied from CComObject<>.
//////////
STDMETHODIMP_(ULONG) DSObject::AddRef()
{
return InternalAddRef();
}
STDMETHODIMP_(ULONG) DSObject::Release()
{
ULONG l = InternalRelease();
if (l == 0) { delete this; }
return l;
}
STDMETHODIMP DSObject::QueryInterface(REFIID iid, void ** ppvObject)
{
return _InternalQueryInterface(iid, ppvObject);
}
STDMETHODIMP DSObject::get_Name(BSTR* pVal)
{
if (pVal == NULL) { return E_OUTOFMEMORY; }
VARIANT v;
RETURN_ERROR(leaf->Get(theNameProperty, &v));
// We should have gotten back a non-null BSTR.
if (V_VT(&v) != VT_BSTR || V_BSTR(&v) == NULL) { return E_FAIL; }
*pVal = V_BSTR(&v);
return S_OK;
}
STDMETHODIMP DSObject::get_Class(BSTR* pVal)
{
return leaf->get_Class(pVal);
}
STDMETHODIMP DSObject::get_GUID(BSTR* pVal)
{
return leaf->get_GUID(pVal);
}
STDMETHODIMP DSObject::get_Container(IDataStoreContainer** pVal)
{
return E_NOTIMPL;
}
STDMETHODIMP DSObject::GetValue(BSTR bstrName, VARIANT* pVal)
{
return leaf->Get(bstrName, pVal);
}
STDMETHODIMP DSObject::GetValueEx(BSTR bstrName, VARIANT* pVal)
{
return leaf->GetEx(bstrName, pVal);
}
STDMETHODIMP DSObject::PutValue(BSTR bstrName, VARIANT* pVal)
{
if (pVal == NULL) { return E_INVALIDARG; }
// Flag the object as dirty.
dirty = TRUE;
// Synch up the downlevel parameters.
downlevel.PutValue(bstrName, pVal);
if ( VT_EMPTY == V_VT(pVal) )
{
return leaf->PutEx(ADS_PROPERTY_CLEAR, bstrName, *pVal);
}
else if ( VT_ARRAY == (V_VT(pVal) & VT_ARRAY) )
{
return leaf->PutEx(ADS_PROPERTY_UPDATE, bstrName, *pVal);
}
else
{
return leaf->Put(bstrName, *pVal);
}
}
STDMETHODIMP DSObject::Update()
{
// Update the UserParameters.
PWSTR newParms;
HRESULT hr = downlevel.Update(oldParms, &newParms);
if (FAILED(hr)) { return hr; }
// Convert to a VARIANT.
VARIANT value;
VariantInit(&value);
V_VT(&value) = VT_BSTR;
V_BSTR(&value) = SysAllocString(newParms);
// Set the UserParameters property.
leaf->Put(theUserParametersProperty, value);
// Clean-up.
VariantClear(&value);
LocalFree(newParms);
return leaf->SetInfo();
}
STDMETHODIMP DSObject::Restore()
{
// Free the old UserParameters.
if (oldParms)
{
SysFreeString(oldParms);
oldParms = NULL;
}
dirty = FALSE;
HRESULT hr = leaf->GetInfo();
if (SUCCEEDED(hr))
{
// Read the UserParameters property.
VARIANT value;
if (leaf->Get(theUserParametersProperty, &value) == S_OK)
{
if (V_VT(&value) == VT_BSTR)
{
oldParms = V_BSTR(&value);
}
else
{
// This should never happen.
VariantClear(&value);
}
}
}
else if (hr == E_ADS_OBJECT_UNBOUND)
{
hr = S_OK;
}
return hr;
}
STDMETHODIMP DSObject::Item(BSTR bstrName, IDataStoreProperty** pVal)
{
if (bstrName == NULL || pVal == NULL) { return E_INVALIDARG; }
*pVal = NULL;
// Get the value for this item.
_variant_t value;
RETURN_ERROR(leaf->Get(bstrName, &value));
try
{
// Create a new property object.
(*pVal = new MyProperty(bstrName, value, this))->AddRef();
}
CATCH_AND_RETURN()
return S_OK;
}
STDMETHODIMP DSObject::get_PropertyCount(long* pVal)
{
if (pVal == NULL) { return E_INVALIDARG; }
if (dirty)
{
RETURN_ERROR(Restore());
}
MyProperties properties(leaf);
if (!properties)
{
// Some ADSI providers may not implement IADsPropertyList.
*pVal = 0;
return E_NOTIMPL;
}
return properties->get_PropertyCount(pVal);
}
STDMETHODIMP DSObject::get_NewPropertyEnum(IUnknown** pVal)
{
if (pVal == NULL) { return E_INVALIDARG; }
*pVal = NULL;
if (dirty)
{
RETURN_ERROR(Restore());
}
MyProperties properties(leaf);
// Some ADSI providers may not implement IADsPropertyList.
if (!properties) { return E_NOTIMPL; }
// Reset the list in case this isn't the first time we've enumerated it.
properties->Reset();
try
{
using _com_util::CheckError;
// How many properties are there?
long count;
CheckError(properties->get_PropertyCount(&count));
// Create a temporary array of items.
std::vector<_variant_t> items;
items.reserve(count);
//////////
// Load all the properties into the temporary array.
//////////
while (count--)
{
// Get the next item in the list.
_variant_t item;
CheckError(properties->Next(&item));
// Convert it to a Property Entry.
IADsPropertyEntryPtr entry(item);
// Get the property name.
BSTR bstrName;
CheckError(entry->get_Name(&bstrName));
_bstr_t name(bstrName, false);
// Get the property value.
_variant_t value;
HRESULT hr = leaf->Get(name, &value);
if (FAILED(hr))
{
if (hr == E_ADS_CANT_CONVERT_DATATYPE)
{
// This must be one of those nasty NTDS attributes that has
// no VARIANT representation.
continue;
}
_com_issue_error(hr);
}
// Create the property object and add it to the vector.
items.push_back(new MyProperty(name, value, this));
}
//////////
// Create and initialize an enumerator for the items.
//////////
CComPtr<EnumVARIANT> newEnum(new CComObject<EnumVARIANT>);
_com_util::CheckError(newEnum->Init(items.begin(),
items.end(),
NULL,
AtlFlagCopy));
// Return it to the caller.
(*pVal = newEnum)->AddRef();
}
CATCH_AND_RETURN()
return S_OK;
}
STDMETHODIMP DSObject::Item(BSTR bstrName, IDataStoreObject** ppObject)
{
if (ppObject == NULL) { return E_INVALIDARG; }
try
{
// Get the ADSI object.
CComPtr<IDispatch> disp;
_com_util::CheckError(node->GetObject(NULL,
thePrefix + bstrName,
&disp));
// Convert to a DSObject.
*ppObject = spawn(disp);
}
CATCH_AND_RETURN()
return S_OK;
}
STDMETHODIMP DSObject::Create(BSTR bstrClass,
BSTR bstrName,
IDataStoreObject** ppObject)
{
if (ppObject == NULL) { return E_INVALIDARG; }
try
{
// Create the ADSI object.
CComPtr<IDispatch> disp;
_com_util::CheckError(node->Create(bstrClass,
thePrefix + bstrName,
&disp));
// Convert to a DSObject.
*ppObject = spawn(disp);
}
CATCH_AND_RETURN()
return S_OK;
}
STDMETHODIMP DSObject::MoveHere(IDataStoreObject* pObject,
BSTR bstrNewName)
{
if (pObject == NULL) { return E_INVALIDARG; }
try
{
using _com_util::CheckError;
// Downcast to a DSObject.
DSObject* obj = DSObject::narrow(pObject);
// Get the absolute path of the object being moved.
CComBSTR path;
CheckError(obj->leaf->get_ADsPath(&path));
// Is the object being renamed?
_bstr_t newName(bstrNewName ? thePrefix + bstrNewName : _bstr_t());
// Move it to this container.
CComPtr<IDispatch> disp;
CheckError(node->MoveHere(path, newName, &disp));
//////////
// Set the leaf to the new object.
//////////
CComPtr<IADs> ads;
CheckError(disp->QueryInterface(__uuidof(IADs), (PVOID*)&ads));
obj->leaf.Release();
obj->leaf = ads;
}
CATCH_AND_RETURN()
return S_OK;
}
STDMETHODIMP DSObject::Remove(BSTR bstrClass, BSTR bstrName)
{
if (bstrClass == NULL) { return E_INVALIDARG; }
try
{
_com_util::CheckError(node->Delete(bstrClass, thePrefix + bstrName));
}
CATCH_AND_RETURN()
return S_OK;
}
STDMETHODIMP DSObject::get_ChildCount(long *pVal)
{
return node->get_Count(pVal);
}
STDMETHODIMP DSObject::get_NewChildEnum(IUnknown** pVal)
{
if (pVal == NULL) { return E_INVALIDARG; }
*pVal = NULL;
try
{
// Get the ADSI enumerator.
CComPtr<IUnknown> unk;
_com_util::CheckError(node->get__NewEnum(&unk));
// Convert to an IEnumVARIANT.
CComPtr<IEnumVARIANT> enumVariant;
_com_util::CheckError(unk->QueryInterface(__uuidof(IEnumVARIANT),
(PVOID*)&enumVariant));
// Construct our wrapper around the real enumerator.
(*pVal = new DSEnumerator(this, enumVariant))->AddRef();
}
CATCH_AND_RETURN()
return S_OK;
}
IDataStoreObject* DSObject::spawn(IUnknown* subject)
{
DSObject* child = new DSObject(subject);
child->InternalAddRef();
return child;
}
DSObject* DSObject::narrow(IUnknown* p)
{
DSObject* object;
using _com_util::CheckError;
CheckError(p->QueryInterface(__uuidof(DSObject), (PVOID*)&object));
// We can get away with InternalRelease since the caller must still
// have a reference to this object.
object->InternalRelease();
return object;
}
HRESULT WINAPI DSObject::getContainer(void* pv, REFIID, LPVOID* ppv, DWORD_PTR)
{
DSObject* obj = (DSObject*)pv;
// If we don't have a node pointer, try to get one.
if (obj->node == NULL)
{
obj->leaf->QueryInterface(__uuidof(IADsContainer), (PVOID*)&obj->node);
}
// If node is not NULL, then we are a container.
if (obj->node != NULL)
{
*ppv = (IDataStoreContainer*)obj;
obj->AddRef();
return S_OK;
}
*ppv = NULL;
return E_NOINTERFACE;
}