windows-nt/Source/XPSP1/NT/ds/adsi/winnt/cumiobj.cxx
2020-09-26 16:20:57 +08:00

2577 lines
69 KiB
C++

//----------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: cumiobj.cxx
//
// Contents: Contains the implementation of IUmiObject. The methods are
// encapsulated in one object. This object holds a pointer to
// the inner unknown of the corresponding WinNT object.
// The methods of IUmiContainer are also implemented on this
// same object, but will only be used if the underlying WinNT
// object is a container.
//
// History: 03-06-00 SivaramR Created.
//
//----------------------------------------------------------------------------
#include "winnt.hxx"
//----------------------------------------------------------------------------
// Function: CUmiObject
//
// Synopsis: Constructor. Initializes member variable.
//
// Arguments: None
//
// Returns: Nothing
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
CUmiObject::CUmiObject(void)
{
m_pIntfProps = NULL;
m_pObjProps = NULL;
m_pUnkInner = NULL;
m_pIADs = NULL;
m_pIADsContainer = NULL;
m_ulErrorStatus = 0;
m_pCoreObj = NULL;
m_pExtMgr = NULL;
m_fOuterUnkSet = FALSE;
m_pPropCache = NULL;
m_fRefreshDone = FALSE;
}
//----------------------------------------------------------------------------
// Function: ~CUmiObject
//
// Synopsis: Destructor. Frees member variables.
//
// Arguments: None
//
// Returns: Nothing
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
CUmiObject::~CUmiObject(void)
{
if(m_pIntfProps != NULL)
m_pIntfProps->Release();
if(m_pObjProps != NULL)
delete m_pObjProps;
if(m_pUnkInner != NULL)
m_pUnkInner->Release();
//
// m_pIADs and m_pIADsContainer may now delegate to an outer unknown if
// if the ADSI object has been aggregated in GetObjectByCLSID
// subsequent to creation. Hence, we should not call Release() on either
// of these pointers. Instead, call Release() on m_pUnkInner since this
// is guaranteed to be a pointer to the non-delegating IUnknown.
//
if(m_pIADsContainer != NULL)
m_pUnkInner->Release();
if(m_pIADs != NULL)
m_pUnkInner->Release();
if(m_pPropCache != NULL)
delete m_pPropCache;
}
//----------------------------------------------------------------------------
// Function: FInit
//
// Synopsis: Initializes UMI object.
//
// Arguments:
//
// Credentials Credentials stored in the underlying WinNT object
// pSchema Pointer to schema for this object
// dwSchemaSize Size of schema array
// pPropCache Pointer to property cache for this object
// pUnkInner Pointer to inner unknown of underlying WinNT object
// pExtMgr Pointer to extension manager of underlying WinNT object
// pCoreObj Pointer to the core object of underlying WinNT object
// pClassInfo Pointer to class information if this object is a class object.
// NULL otherwise.
//
// Returns: S_OK on success. Error code otherwise.
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
HRESULT CUmiObject::FInit(
CWinNTCredentials& Credentials,
PPROPERTYINFO pSchema,
DWORD dwSchemaSize,
CPropertyCache *pPropertyCache,
IUnknown *pUnkInner,
CADsExtMgr *pExtMgr,
CCoreADsObject *pCoreObj,
CLASSINFO *pClassInfo
)
{
HRESULT hr = S_OK;
CUmiPropList *pIntfProps = NULL;
ADsAssert(pCoreObj != NULL); // extension manager may be NULL for some
// WinNT objects
if(pPropertyCache != NULL) {
// some WinNT objects don't have a property cache associated with them.
// Namespace and schema objects are examples. For these, we might
// create a proeprty cache in the 'else' clause below. Otherwise, we
// return UMI_E_NOTIMPL from IUmiPropList methods since m_pObjProps will be
// NULL for these objects.
ADsAssert( (pSchema != NULL) && (dwSchemaSize > 0) &&
(pUnkInner != NULL) );
// Initialize property list for object properties
m_pObjProps = new CUmiPropList(pSchema, dwSchemaSize);
if(NULL == m_pObjProps)
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
hr = m_pObjProps->FInit(pPropertyCache, NULL);
BAIL_ON_FAILURE(hr);
}
else if(pSchema != NULL) {
// Property, class, schema and syntax objects do not have a cache
// associated with them. But, they support a number of properties through
// IDispatch. We want to expose these through UMI. So create a property
// cache and populate it with these read-only properties. Thus,
// m_pObjProps will be NULL only for namespace objects.
ADsAssert( (pUnkInner != NULL) && (dwSchemaSize > 0) );
hr = CreateObjectProperties(
pSchema,
dwSchemaSize,
pUnkInner,
pCoreObj
);
BAIL_ON_FAILURE(hr);
}
// Initialize property list for interface properties
pIntfProps = new CUmiPropList(ObjClass, g_dwObjClassSize);
if(NULL == pIntfProps)
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
hr = pIntfProps->FInit(NULL, g_UmiObjUnImplProps);
BAIL_ON_FAILURE(hr);
hr = pIntfProps->QueryInterface(
IID_IUmiPropList,
(void **) &m_pIntfProps
);
BAIL_ON_FAILURE(hr);
// DECLARE_STD_REFCOUNTING initializes the refcount to 1. Call Release()
// on the created object, so that releasing the interface pointer will
// free the object.
pIntfProps->Release();
m_pUnkInner = pUnkInner;
// Get pointers to IADs and IADsContainer interfaces on WinNT object
hr = m_pUnkInner->QueryInterface(
IID_IADsContainer,
(void **) &m_pIADsContainer
);
if(FAILED(hr))
m_pIADsContainer = NULL;
hr = m_pUnkInner->QueryInterface(
IID_IADs,
(void **) &m_pIADs
);
if(FAILED(hr))
m_pIADs = NULL;
else {
hr = pIntfProps->SetStandardProperties(m_pIADs, pCoreObj);
BAIL_ON_FAILURE(hr);
}
pIntfProps->SetClassInfo(pClassInfo);
// set the property count in the interface property cache
hr = pIntfProps->SetPropertyCount(dwSchemaSize);
BAIL_ON_FAILURE(hr);
m_pExtMgr = pExtMgr;
m_pCoreObj = pCoreObj;
m_pCreds = &Credentials;
RRETURN(S_OK);
error:
if(m_pObjProps != NULL)
delete m_pObjProps;
if(m_pIntfProps != NULL)
m_pIntfProps->Release();
else if(pIntfProps != NULL)
delete pIntfProps;
if(m_pIADsContainer != NULL)
m_pIADsContainer->Release();
if(m_pIADs != NULL)
m_pIADs->Release();
// make sure destructor doesn't free these again
m_pObjProps = NULL;
m_pIntfProps = NULL;
m_pIADsContainer = NULL;
m_pIADs = NULL;
m_pUnkInner = NULL;
RRETURN(hr);
}
//----------------------------------------------------------------------------
// Function: CreateObjectProperties
//
// Synopsis: Creates a property cache and populates it with the properties
// supported on the WinNT object's IDispatch interface. This is
// used to expose properties on property, class and syntax objects
// through UMI.
//
// Arguments:
//
// pSchema Pointer to schema for this object
// dwSchemaSize Size of schema array
// pUnkInner Pointer to inner unknown of underlying WinNT object
// pCoreObj Pointer to the core object of the WinNT object
//
// Returns: S_OK on success. Error code otherwise.
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
HRESULT CUmiObject::CreateObjectProperties(
PPROPERTYINFO pSchema,
DWORD dwSchemaSize,
IUnknown *pUnkInner,
CCoreADsObject *pCoreObj
)
{
HRESULT hr = S_OK;
IDispatch *pDispatch = NULL;
DWORD dwIndex = 0;
DISPID DispId;
DISPPARAMS DispParams = {NULL, NULL, 0, 0};
VARIANT var;
CPropertyCache *pPropCache = NULL;
ADsAssert( (pSchema != NULL) && (dwSchemaSize > 0) &&
(pUnkInner != NULL) && (pCoreObj != NULL) );
hr = CPropertyCache::createpropertycache(
pSchema,
dwSchemaSize,
pCoreObj,
&pPropCache);
BAIL_ON_FAILURE(hr);
hr = pUnkInner->QueryInterface(
IID_IDispatch,
(void **) &pDispatch
);
BAIL_ON_FAILURE(hr);
for(dwIndex = 0; dwIndex < dwSchemaSize; dwIndex++) {
hr = pDispatch->GetIDsOfNames(
IID_NULL,
&pSchema[dwIndex].szPropertyName,
1,
LOCALE_SYSTEM_DEFAULT,
&DispId
);
BAIL_ON_FAILURE(hr);
hr = pDispatch->Invoke(
DispId,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET,
&DispParams,
&var,
NULL,
NULL
);
BAIL_ON_FAILURE(hr);
hr = GenericPutPropertyManager(
pPropCache,
pSchema,
dwSchemaSize,
pSchema[dwIndex].szPropertyName,
var,
FALSE
);
VariantClear(&var);
// If there is a multivalued ADSI interface property that has no values
// (such as MandatoryProperties/Containment on a schema object), the
// call to Invoke above returns a variant which has a safearray with
// 0 elements in it. The call to GenericPutPropertyManager will fail
// with E_ADS_BAD_PARAMETER in this case. In this case, don't store
// anything in the property cache for this property. Trying to fetch
// it later will return UMI_E_NOT_FOUND.
if(hr != E_ADS_BAD_PARAMETER)
BAIL_ON_FAILURE(hr);
}
// Mark all properties as "not modified", since the client really hasn't
// updated the cache, though we have.
pPropCache->ClearModifiedFlags();
// Initialize property list for object properties
m_pObjProps = new CUmiPropList(pSchema, dwSchemaSize);
if(NULL == m_pObjProps)
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
hr = m_pObjProps->FInit(pPropCache, NULL);
BAIL_ON_FAILURE(hr);
m_pPropCache = pPropCache;
pDispatch->Release();
RRETURN(S_OK);
error:
if(pPropCache != NULL)
delete pPropCache;
if(pDispatch != NULL)
pDispatch->Release();
if(m_pObjProps != NULL) {
delete m_pObjProps;
m_pObjProps = NULL;
}
RRETURN(hr);
}
//----------------------------------------------------------------------------
// Function: QueryInterface
//
// Synopsis: Implements QI for the UMI object.
//
// Arguments
//
// iid interface requested
// ppInterface Returns pointer to interface requested. NULL if interface
// is not supported.
//
// Returns: S_OK on success. Error code otherwise.
//
// Modifies: *ppInterface to return interface pointer
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::QueryInterface(
REFIID iid,
LPVOID *ppInterface
)
{
HRESULT hr = S_OK;
IUnknown *pTmpIntfPtr = NULL;
if(NULL == ppInterface)
RRETURN(E_INVALIDARG);
*ppInterface = NULL;
if(IsEqualIID(iid, IID_IUnknown))
*ppInterface = (IUmiObject *) this;
else if(IsEqualIID(iid, IID_IUmiObject))
*ppInterface = (IUmiObject *) this;
else if(IsEqualIID(iid, IID_IUmiContainer)) {
// check if underlying WinNT object is a container
if(m_pIADsContainer != NULL)
*ppInterface = (IUmiContainer *) this;
else
RRETURN(E_NOINTERFACE);
}
else if(IsEqualIID(iid, IID_IUmiBaseObject))
*ppInterface = (IUmiBaseObject *) this;
else if(IsEqualIID(iid, IID_IUmiPropList))
*ppInterface = (IUmiPropList *) this;
else if(IsEqualIID(iid, IID_IUmiCustomInterfaceFactory))
*ppInterface = (IUmiCustomInterfaceFactory *) this;
else if(IsEqualIID(iid, IID_IUmiADSIPrivate))
*ppInterface = (IUmiADSIPrivate *) this;
else
RRETURN(E_NOINTERFACE);
AddRef();
RRETURN(S_OK);
}
//----------------------------------------------------------------------------
// Function: Clone
//
// Synopsis: Implements IUmiObject::Clone. Creates a new uncommitted object
// and copies over all properties from the source to destination.
// The source may be Refresh()ed if necessary.
//
// Arguments
//
// uFlags Flags for Clone(). Must be 0 for now.
// riid Interface ID requested on the cloned object
// pCopy Returns interface pointer requested
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pCopy to return the interface requested.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::Clone(
ULONG uFlags,
REFIID riid,
LPVOID *pCopy
)
{
HRESULT hr = UMI_S_NO_ERROR;
BSTR bstrADsPath = NULL, bstrParent = NULL;
BSTR bstrClass = NULL, bstrName = NULL;
IUnknown *pUnknown = NULL, *pUnkParent = NULL;
IDispatch *pDispatch = NULL;
IADsContainer *pIADsCont = NULL;
IUmiObject *pUmiObj = NULL;
IUmiADSIPrivate *pUmiPrivate = NULL;
SetLastStatus(0);
if(uFlags != 0)
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
if(NULL == pCopy)
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if( (NULL == m_pCoreObj) || (NULL == m_pIADs) )
// shouldn't happen, but just being paranoid
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
*pCopy = NULL;
if(ADS_OBJECT_BOUND == m_pCoreObj->GetObjectState()) {
// object exists on server
if(FALSE == m_fRefreshDone) {
hr = m_pCoreObj->ImplicitGetInfo();
BAIL_ON_FAILURE(hr);
}
hr = m_pIADs->get_ADsPath(&bstrADsPath);
BAIL_ON_FAILURE(hr);
m_pCreds->SetUmiFlag();
hr = GetObject(
bstrADsPath,
(LPVOID *) &pUnknown,
*m_pCreds
);
m_pCreds->ResetUmiFlag();
BAIL_ON_FAILURE(hr);
hr = pUnknown->QueryInterface(IID_IUmiObject, (LPVOID *) &pUmiObj);
BAIL_ON_FAILURE(hr);
}
else if(ADS_OBJECT_UNBOUND == m_pCoreObj->GetObjectState()) {
// object not yet committed to server. We don't have to refresh the
// cache since the object is not yet committed. Get the parent container
// and call Create() on it.
hr = m_pIADs->get_Parent(&bstrParent);
BAIL_ON_FAILURE(hr);
m_pCreds->SetUmiFlag();
hr = GetObject(
bstrParent,
(LPVOID *) &pUnkParent,
*m_pCreds
);
m_pCreds->ResetUmiFlag();
BAIL_ON_FAILURE(hr);
hr = pUnkParent->QueryInterface(
IID_IUmiADSIPrivate,
(LPVOID *) &pUmiPrivate
);
BAIL_ON_FAILURE(hr);
hr = pUmiPrivate->GetContainer((void **) &pIADsCont);
BAIL_ON_FAILURE(hr);
ADsAssert(pIADsCont != NULL);
// get the class and name of this object
hr = m_pIADs->get_Class(&bstrClass);
BAIL_ON_FAILURE(hr);
hr = m_pIADs->get_Name(&bstrName);
BAIL_ON_FAILURE(hr);
pUmiPrivate->SetUmiFlag();
// now Create() the cloned object
hr = pIADsCont->Create(
bstrClass,
bstrName,
&pDispatch
);
pUmiPrivate->ResetUmiFlag();
BAIL_ON_FAILURE(hr);
hr = pDispatch->QueryInterface(IID_IUmiObject, (LPVOID *) &pUmiObj);
BAIL_ON_FAILURE(hr);
}
else // unknown state, shouldn't happen.
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
// copy over the attributes in the property cache
hr = CopyPropCache(pUmiObj, (IUmiObject *) this);
BAIL_ON_FAILURE(hr);
hr = pUmiObj->QueryInterface(riid, pCopy);
BAIL_ON_FAILURE(hr);
error:
if(bstrADsPath != NULL)
SysFreeString(bstrADsPath);
if(bstrParent != NULL)
SysFreeString(bstrParent);
if(bstrClass != NULL)
SysFreeString(bstrClass);
if(bstrName != NULL)
SysFreeString(bstrName);
if(pUnknown != NULL)
pUnknown->Release();
if(pUnkParent != NULL)
pUnkParent->Release();
if(pDispatch != NULL)
pDispatch->Release();
if(pIADsCont != NULL)
pIADsCont->Release();
if(pUmiObj != NULL)
pUmiObj->Release();
if(pUmiPrivate != NULL)
pUmiPrivate->Release();
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: CopyPropCache
//
// Synopsis: Copies the cache of one IUmiObject to another IUmiObject.
//
// Arguments
//
// pDest IUmiObject interface pointer of destination
// pSrc IUmiObject interface pointer of source
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
HRESULT CUmiObject::CopyPropCache(
IUmiObject *pDest,
IUmiObject *pSrc
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulIndex = 0, ulPutFlag = 0;
LPWSTR pszPropName = NULL;
UMI_PROPERTY_VALUES *pUmiPropNames = NULL, *pUmiProp = NULL;
ADsAssert( (pDest != NULL) && (pSrc != NULL) );
// get the names of the properties in cache.
hr = pSrc->GetProps(
NULL,
0,
UMI_FLAG_GETPROPS_NAMES,
&pUmiPropNames
);
BAIL_ON_FAILURE(hr);
// copy over each property
for(ulIndex = 0; ulIndex < pUmiPropNames->uCount; ulIndex++) {
pszPropName = pUmiPropNames->pPropArray[ulIndex].pszPropertyName;
if(NULL == pszPropName)
// shouldn't happen, just being paranoid.
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
hr = pSrc->Get(
pszPropName,
UMI_FLAG_PROVIDER_CACHE,
&pUmiProp
);
BAIL_ON_FAILURE(hr);
// if the property was updated in cache, we need to mark it as updated
// in the destination object's cache also. Otherwise, mark the
// property as clean in the destination object's cache.
if(UMI_OPERATION_UPDATE == pUmiProp->pPropArray->uOperationType)
ulPutFlag = 0;
else
ulPutFlag = UMI_INTERNAL_FLAG_MARK_AS_CLEAN;
pUmiProp->pPropArray->uOperationType = UMI_OPERATION_UPDATE;
hr = pDest->Put(
pszPropName,
ulPutFlag,
pUmiProp
);
BAIL_ON_FAILURE(hr);
pSrc->FreeMemory(0, pUmiProp);
pUmiProp = NULL;
}
pSrc->FreeMemory(0, pUmiPropNames);
error:
if(FAILED(hr)) {
if(pUmiProp != NULL)
pSrc->FreeMemory(0, pUmiProp);
if(pUmiPropNames != NULL)
pSrc->FreeMemory(0, pUmiPropNames);
}
RRETURN(hr);
}
//----------------------------------------------------------------------------
// Function: Refresh
//
// Synopsis: Implements IUmiObject::Refresh. Calls GetInfo on WinNT
// object to refresh the cache. GetInfoEx is implemented by
// just calling GetInfo in the WinNT provider.
//
// Arguments
//
// uFlags Flags for Refresh. Must be 0 for now.
// uNameCount Number of attributes to refresh
// pszNames Names of attributes to refresh
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
HRESULT CUmiObject::Refresh(
ULONG uFlags,
ULONG uNameCount,
LPWSTR *pszNames
)
{
ULONG i = 0;
HRESULT hr = UMI_S_NO_ERROR;
SetLastStatus(0);
if( (uFlags != UMI_FLAG_REFRESH_ALL) &&
(uFlags != UMI_FLAG_REFRESH_PARTIAL) )
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
if( ((NULL == pszNames) && (uNameCount != 0)) ||
((pszNames != NULL) && (0 == uNameCount)) )
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
// ensure all attributes are valid
for(i = 0; i < uNameCount; i++)
if(NULL == pszNames[i])
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if(UMI_FLAG_REFRESH_PARTIAL == uFlags) {
// do an implicit GetInfo on the WinNT object
if(NULL == m_pCoreObj)
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
if(uNameCount != 0) {
// can't specify UMI_FLAG_REFRESH_PARTIAL and attribute names
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
}
hr = m_pCoreObj->ImplicitGetInfo();
BAIL_ON_FAILURE(hr);
}
else {
if(NULL == m_pIADs)
// shouldn't happen, but just being paranoid
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
hr = m_pIADs->GetInfo();
BAIL_ON_FAILURE(hr);
}
m_fRefreshDone = TRUE;
error:
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: Commit
//
// Synopsis: Implements IUmiObject::Commit. Calls SetInfo on WinNT
// object to commit changes made to the cache.
//
// Arguments
//
// uFlags Flags for Refresh.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
HRESULT CUmiObject::Commit(ULONG uFlags)
{
HRESULT hr = UMI_S_NO_ERROR;
SetLastStatus(0);
// CIMOM always calls with UMI_DONT_COMMIT_SECURITY_DESCRIPTOR set. Ignore
// this flag as it is not meaningful on WinNT.
if( (uFlags != 0) && (uFlags != UMI_DONT_COMMIT_SECURITY_DESCRIPTOR) )
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
if(NULL == m_pIADs)
// shouldn't happen, but just being paranoid
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
hr = m_pIADs->SetInfo();
BAIL_ON_FAILURE(hr);
error:
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// IUmiPropList methods
//
// These are implemented by invoking the corresponding method in the
// CUmiPropList object that implements object properties. For a description
// of these methods, refer to cumiprop.cxx
//
//----------------------------------------------------------------------------
HRESULT CUmiObject::Put(
LPCWSTR pszName,
ULONG uFlags,
UMI_PROPERTY_VALUES *pProp
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulStatus = 0;
IID iid;
SetLastStatus(0);
if(NULL == m_pObjProps) {
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
hr = m_pObjProps->Put(
pszName,
uFlags,
pProp
);
if(FAILED(hr)) {
m_pObjProps->GetLastStatus( // ignore error return
0,
&ulStatus,
iid,
NULL
);
SetLastStatus(ulStatus);
}
RRETURN(MapHrToUmiError(hr));
}
HRESULT CUmiObject::Get(
LPCWSTR pszName,
ULONG uFlags,
UMI_PROPERTY_VALUES **ppProp
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulStatus = 0;
IID iid;
SetLastStatus(0);
if(NULL == m_pObjProps) {
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
hr = m_pObjProps->Get(
pszName,
uFlags,
ppProp
);
if(FAILED(hr)) {
m_pObjProps->GetLastStatus( // ignore error return
0,
&ulStatus,
iid,
NULL
);
SetLastStatus(ulStatus);
}
RRETURN(MapHrToUmiError(hr));
}
HRESULT CUmiObject::GetAs(
LPCWSTR pszName,
ULONG uFlags,
ULONG uCoercionType,
UMI_PROPERTY_VALUES **ppProp
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulStatus = 0;
IID iid;
SetLastStatus(0);
if(NULL == m_pObjProps) {
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
hr = m_pObjProps->GetAs(
pszName,
uFlags,
uCoercionType,
ppProp
);
if(FAILED(hr)) {
m_pObjProps->GetLastStatus( // ignore error return
0,
&ulStatus,
iid,
NULL
);
SetLastStatus(ulStatus);
}
RRETURN(MapHrToUmiError(hr));
}
HRESULT CUmiObject::FreeMemory(
ULONG uReserved,
LPVOID pMem
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulStatus = 0;
IID iid;
SetLastStatus(0);
if(NULL == m_pObjProps) {
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
hr = m_pObjProps->FreeMemory(
uReserved,
pMem
);
if(FAILED(hr)) {
m_pObjProps->GetLastStatus( // ignore error return
0,
&ulStatus,
iid,
NULL
);
SetLastStatus(ulStatus);
}
RRETURN(MapHrToUmiError(hr));
}
HRESULT CUmiObject::GetAt(
LPCWSTR pszName,
ULONG uFlags,
ULONG uBufferLength,
LPVOID pExistingMem
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulStatus = 0;
IID iid;
SetLastStatus(0);
if(NULL == m_pObjProps) {
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
hr = m_pObjProps->GetAt(
pszName,
uFlags,
uBufferLength,
pExistingMem
);
if(FAILED(hr)) {
m_pObjProps->GetLastStatus( // ignore error return
0,
&ulStatus,
iid,
NULL
);
SetLastStatus(ulStatus);
}
RRETURN(MapHrToUmiError(hr));
}
HRESULT CUmiObject::GetProps(
LPCWSTR *pszNames,
ULONG uNameCount,
ULONG uFlags,
UMI_PROPERTY_VALUES **pProps
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulStatus = 0;
IID iid;
SetLastStatus(0);
if(NULL == m_pObjProps) {
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
hr = m_pObjProps->GetProps(
pszNames,
uNameCount,
uFlags,
pProps
);
if(FAILED(hr)) {
m_pObjProps->GetLastStatus( // ignore error return
0,
&ulStatus,
iid,
NULL
);
SetLastStatus(ulStatus);
}
RRETURN(MapHrToUmiError(hr));
}
HRESULT CUmiObject::PutProps(
LPCWSTR *pszNames,
ULONG uNameCount,
ULONG uFlags,
UMI_PROPERTY_VALUES *pProps
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulStatus = 0;
IID iid;
SetLastStatus(0);
if(NULL == m_pObjProps) {
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
hr = m_pObjProps->PutProps(
pszNames,
uNameCount,
uFlags,
pProps
);
if(FAILED(hr)) {
m_pObjProps->GetLastStatus( // ignore error return
0,
&ulStatus,
iid,
NULL
);
SetLastStatus(ulStatus);
}
RRETURN(MapHrToUmiError(hr));
}
HRESULT CUmiObject::PutFrom(
LPCWSTR pszName,
ULONG uFlags,
ULONG uBufferLength,
LPVOID pExistingMem
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulStatus = 0;
IID iid;
SetLastStatus(0);
if(NULL == m_pObjProps) {
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
hr = m_pObjProps->PutFrom(
pszName,
uFlags,
uBufferLength,
pExistingMem
);
if(FAILED(hr)) {
m_pObjProps->GetLastStatus( // ignore error return
0,
&ulStatus,
iid,
NULL
);
SetLastStatus(ulStatus);
}
RRETURN(MapHrToUmiError(hr));
}
HRESULT CUmiObject::Delete(
LPCWSTR pszName,
ULONG uFlags
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulStatus = 0;
IID iid;
SetLastStatus(0);
if(NULL == m_pObjProps) {
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
hr = m_pObjProps->Delete(
pszName,
uFlags
);
if(FAILED(hr)) {
m_pObjProps->GetLastStatus( // ignore error return
0,
&ulStatus,
iid,
NULL
);
SetLastStatus(ulStatus);
}
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: GetLastStatus
//
// Synopsis: Returns status or error code from the last operation. Currently
// only numeric status is returned i.e, no error objects are
// returned. Implements IUmiBaseObject::GetLastStatus().
//
// Arguments:
//
// uFlags Reserved. Must be 0 for now.
// puSpecificStatus Returns status code
// riid IID requested. Ignored currently.
// pStatusObj Returns interface requested. Always returns NULL currently.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *puSpecificStatus to return status code.
//
//----------------------------------------------------------------------------
HRESULT CUmiObject::GetLastStatus(
ULONG uFlags,
ULONG *puSpecificStatus,
REFIID riid,
LPVOID *pStatusObj
)
{
if(pStatusObj != NULL)
*pStatusObj = NULL;
if(puSpecificStatus != NULL)
*puSpecificStatus = 0;
if(uFlags != 0)
RRETURN(UMI_E_INVALID_FLAGS);
if(NULL == puSpecificStatus)
RRETURN(UMI_E_INVALIDARG);
*puSpecificStatus = m_ulErrorStatus;
RRETURN(UMI_S_NO_ERROR);
}
//----------------------------------------------------------------------------
// Function: SetLastStatus
//
// Synopsis: Sets the status of the last operation.
//
// Arguments:
//
// ulStatus Status to be set
//
// Returns: Nothing
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
void CUmiObject::SetLastStatus(ULONG ulStatus)
{
m_ulErrorStatus = ulStatus;
return;
}
//----------------------------------------------------------------------------
// Function: GetInterfacePropList
//
// Synopsis: Returns a pointer to the interface property list implementation
// for the connection object. Implements
// IUmiBaseObject::GetInterfacePropList().
//
// Arguments:
//
// uFlags Reserved. Must be 0 for now.
// pPropList Returns pointer to IUmiPropertyList interface
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pPropList to return interface pointer
//
//----------------------------------------------------------------------------
HRESULT CUmiObject::GetInterfacePropList(
ULONG uFlags,
IUmiPropList **pPropList
)
{
HRESULT hr = UMI_S_NO_ERROR;
SetLastStatus(0);
if(uFlags != 0)
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
if(NULL == pPropList)
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
ADsAssert(m_pIntfProps != NULL);
hr = m_pIntfProps->QueryInterface(IID_IUmiPropList, (void **) pPropList);
error:
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: IsRelativePath
//
// Synopsis: Checks if a path is relative or absolute
//
// Arguments:
//
// pURL IUmiURL interface containing the path
//
// Returns: TRUE if the path is relative, FALSE otherwise
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
BOOL CUmiObject::IsRelativePath(IUmiURL *pURL)
{
HRESULT hr = S_OK;
ULONGLONG PathType = 0;
ADsAssert(pURL != NULL);
hr = pURL->GetPathInfo(
0,
&PathType
);
BAIL_ON_FAILURE(hr);
if(PathType & UMIPATH_INFO_RELATIVE_PATH)
RRETURN(TRUE);
else
RRETURN(FALSE);
error:
RRETURN(FALSE);
}
//----------------------------------------------------------------------------
// Function: GetClassAndPath
//
// Synopsis: Obtains the class name and path from a relative UMI path.
// The class name and value are mandatory. The key is optional.
//
// Arguments:
//
// pszPath String containing the path
// ppszClass Returns string containing the class name
// ppszPath Returns string containing the path
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *ppszClass and *ppszPath
//
//----------------------------------------------------------------------------
HRESULT CUmiObject::GetClassAndPath(
LPWSTR pszPath,
LPWSTR *ppszClass,
LPWSTR *ppszPath
)
{
HRESULT hr = UMI_S_NO_ERROR;
WCHAR *pSeparator = NULL, *pValSeparator = NULL;
ADsAssert( (pszPath != NULL) && (ppszClass != NULL) &&
(ppszPath != NULL) );
*ppszClass = NULL;
*ppszPath = NULL;
// look for the '=' in the relative path
if(NULL == (pValSeparator = wcschr(pszPath, VALUE_SEPARATOR)))
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
*pValSeparator = L'\0';
*ppszPath = AllocADsStr(pValSeparator+1);
if(NULL == *ppszPath)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
if(NULL == (pSeparator = wcschr(pszPath, CLASS_SEPARATOR))) {
// path does not have a key in it
*ppszClass = AllocADsStr(pszPath);
if(NULL == *ppszClass)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
}
else {
// path has a key. Make sure it is "Name".
*pSeparator = L'\0';
if(_wcsicmp(pSeparator+1, WINNT_KEY_NAME))
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
*ppszClass = AllocADsStr(pszPath);
if(NULL == *ppszClass)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
}
RRETURN(UMI_S_NO_ERROR);
error:
if(*ppszPath != NULL)
FreeADsStr(*ppszPath);
if(*ppszClass != NULL)
FreeADsStr(*ppszClass);
*ppszPath = *ppszClass = NULL;
RRETURN(hr);
}
//----------------------------------------------------------------------------
// Function: Open
//
// Synopsis: Opens the object specified by a URL. URL has to be a relative
// UMI path. Implements IUmiContainer::Open().
//
// Arguments:
//
// pURL Pointer to an IUmiURL interface
// uFlags Reserved. Must be 0 for now.
// TargetIID Interface requested
// ppInterface Returns pointer to interface requested
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *ppInterface to return interface pointer
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::Open(
IUmiURL *pURL,
ULONG uFlags,
REFIID TargetIID,
LPVOID *ppInterface
)
{
BOOL fIsRelPath = FALSE;
HRESULT hr = UMI_S_NO_ERROR;
WCHAR pszUrl[MAX_URL+1];
WCHAR *pszLongUrl = pszUrl;
ULONG ulUrlLen = MAX_URL;
WCHAR *pszClass = NULL, *pszPath = NULL;
IDispatch *pIDispatch = NULL;
SetLastStatus(0);
if(uFlags != 0)
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
if( (NULL == pURL) || (NULL == ppInterface) )
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if(NULL == m_pIADsContainer)
// shouldn't happen, but just in case...
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
// Get the path from the URL
hr = pURL->Get(0, &ulUrlLen, pszUrl);
if(WBEM_E_BUFFER_TOO_SMALL == hr) {
// need to allocate more memory for URL
pszLongUrl = (WCHAR *) AllocADsMem(ulUrlLen * sizeof(WCHAR));
if(NULL == pszLongUrl)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
hr = pURL->Get(0, &ulUrlLen, pszLongUrl);
}
BAIL_ON_FAILURE(hr);
// Check if the path is relative or absolute
fIsRelPath = IsRelativePath(pURL);
if(TRUE == fIsRelPath) {
// check if the caller specified the class as part of the path
hr = GetClassAndPath(pszLongUrl, &pszClass, &pszPath);
BAIL_ON_FAILURE(hr);
m_pCreds->SetUmiFlag();
hr = m_pIADsContainer->GetObject(
pszClass,
pszPath,
&pIDispatch
);
m_pCreds->ResetUmiFlag();
BAIL_ON_FAILURE(hr);
hr = pIDispatch->QueryInterface(
TargetIID,
ppInterface
);
BAIL_ON_FAILURE(hr);
} // if(TRUE == fIsRelPath
else {
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
}
error:
if(pIDispatch != NULL)
pIDispatch->Release();
if(pszClass != NULL)
FreeADsMem(pszClass);
if(pszPath != NULL)
FreeADsMem(pszPath);
if(pszLongUrl != pszUrl)
FreeADsMem(pszLongUrl);
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: PutObject
//
// Synopsis: Commits an object into the container. Not implemented currently.
// Implements IUmiContainer::Put().
//
// Arguments:
//
// uFlags Reserved. Must be 0 for now.
// TargetIID IID of nterface pointer sent in
// pInterface Interface pointer sent in
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *ppInterface to return interface pointer
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::PutObject(
ULONG uFlags,
REFIID TargetIID,
LPVOID pInterface
)
{
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
//----------------------------------------------------------------------------
// Function: DeleteObject
//
// Synopsis: Deletes the object specified by the relative UMI path.
// Implements IUmiContainer::Delete().
//
// Arguments:
//
// pURL Pointer to an IUmiURL interface
// uFlags Reserved. Must be 0 for now.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::DeleteObject(
IUmiURL *pURL,
ULONG uFlags
)
{
ULONG ulUrlLen = MAX_URL;
WCHAR pszUrl[MAX_URL+1], *pszClass = NULL, *pszPath = NULL;
WCHAR *pszLongUrl = pszUrl;
BOOL fIsRelPath = FALSE;
HRESULT hr = UMI_S_NO_ERROR;
SetLastStatus(0);
if(uFlags != 0)
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
if(NULL == pURL)
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if(NULL == m_pIADsContainer)
// shouldn't happen, but just in case...
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
// Get the path from the URL
hr = pURL->Get(0, &ulUrlLen, pszUrl);
if(WBEM_E_BUFFER_TOO_SMALL == hr) {
// need to allocate more memory for URL
pszLongUrl = (WCHAR *) AllocADsMem(ulUrlLen * sizeof(WCHAR));
if(NULL == pszLongUrl)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
hr = pURL->Get(0, &ulUrlLen, pszLongUrl);
}
BAIL_ON_FAILURE(hr);
// Check if the path is relative or absolute
fIsRelPath = IsRelativePath(pURL);
if(TRUE == fIsRelPath) {
// check if the caller specified the class as part of the path
hr = GetClassAndPath(pszLongUrl, &pszClass, &pszPath);
BAIL_ON_FAILURE(hr);
m_pCreds->SetUmiFlag();
hr = m_pIADsContainer->Delete(
pszClass,
pszPath
);
m_pCreds->ResetUmiFlag();
BAIL_ON_FAILURE(hr);
} // if(TRUE == fIsRelPath
else {
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
}
error:
if(pszClass != NULL)
FreeADsMem(pszClass);
if(pszPath != NULL)
FreeADsMem(pszPath);
if(pszLongUrl != pszUrl)
FreeADsMem(pszLongUrl);
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: Create
//
// Synopsis: Creates the object specified by the relative UMI path.
// Implements IUmiContainer::Create().
//
// Arguments:
//
// pURL Pointer to an IUmiURL interface
// uFlags Reserved. Must be 0 for now.
// ppNewObj Returns pointer to IUmiObject interface on new object
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pNewObject to return the IUmiObject interface
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::Create(
IUmiURL *pURL,
ULONG uFlags,
IUmiObject **ppNewObj
)
{
ULONG ulUrlLen = MAX_URL;
WCHAR pszUrl[MAX_URL+1], *pszClass = NULL, *pszPath = NULL;
WCHAR *pszLongUrl = pszUrl;
BOOL fIsRelPath = FALSE;
HRESULT hr = UMI_S_NO_ERROR;
IDispatch *pIDispatch = NULL;
SetLastStatus(0);
if(uFlags != 0)
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
if( (NULL == pURL) || (NULL == ppNewObj) )
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if(NULL == m_pIADsContainer)
// shouldn't happen, but just in case...
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
// Get the path from the URL
hr = pURL->Get(0, &ulUrlLen, pszUrl);
if(WBEM_E_BUFFER_TOO_SMALL == hr) {
// need to allocate more memory for URL
pszLongUrl = (WCHAR *) AllocADsMem(ulUrlLen * sizeof(WCHAR));
if(NULL == pszLongUrl)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
hr = pURL->Get(0, &ulUrlLen, pszLongUrl);
}
BAIL_ON_FAILURE(hr);
// Check if the path is relative or absolute
fIsRelPath = IsRelativePath(pURL);
if(TRUE == fIsRelPath) {
// check if the caller specified the class as part of the path
hr = GetClassAndPath(pszLongUrl, &pszClass, &pszPath);
BAIL_ON_FAILURE(hr);
m_pCreds->SetUmiFlag();
hr = m_pIADsContainer->Create(
pszClass,
pszPath,
&pIDispatch
);
m_pCreds->ResetUmiFlag();
BAIL_ON_FAILURE(hr);
hr = pIDispatch->QueryInterface(
IID_IUmiObject,
(void **) ppNewObj
);
BAIL_ON_FAILURE(hr);
} // if(TRUE == fIsRelPath
else {
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
}
error:
if(pIDispatch != NULL)
pIDispatch->Release();
if(pszClass != NULL)
FreeADsMem(pszClass);
if(pszPath != NULL)
FreeADsMem(pszPath);
if(pszLongUrl != pszUrl)
FreeADsMem(pszLongUrl);
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: Move
//
// Synopsis: Moves a specified object into the container. Implements
// IUmiContainer::Move().
//
// Arguments:
//
// uFlags Reserved. Must be 0 for now.
// pOldURL URL of the object to be moved
// pNewURL New URL of the object within the container. If NULL, the new
// name will be the same as the old one.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::Move(
ULONG uFlags,
IUmiURL *pOldURL,
IUmiURL *pNewURL
)
{
ULONG ulUrlLen = MAX_URL;
WCHAR pszNewUrl[MAX_URL+1], pszOldUrl[MAX_URL+1];
WCHAR *pszLongNewUrl = pszNewUrl, *pszLongOldUrl = pszOldUrl;
WCHAR *pszDstPath = NULL, *pszTmpStr = NULL;
WCHAR *pszClass = NULL;
BOOL fIsRelPath = FALSE;
IDispatch *pIDispatch = NULL;
HRESULT hr = UMI_S_NO_ERROR;
ULONGLONG PathType = 0;
WCHAR *pSeparator = NULL;
DWORD dwNumComponents = 0, dwIndex = 0;
LPWSTR *ppszClasses = NULL;
SetLastStatus(0);
if(uFlags != 0)
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
if(NULL == pOldURL)
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if(NULL == m_pIADsContainer)
// shouldn't happen, but just in case...
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
// Get the path from the URL
if(pNewURL != NULL) {
hr = pNewURL->Get(0, &ulUrlLen, pszNewUrl);
if(WBEM_E_BUFFER_TOO_SMALL == hr) {
// need to allocate more memory for URL
pszLongNewUrl = (WCHAR *) AllocADsMem(ulUrlLen * sizeof(WCHAR));
if(NULL == pszLongNewUrl)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
hr = pNewURL->Get(0, &ulUrlLen, pszLongNewUrl);
}
BAIL_ON_FAILURE(hr);
// Check if the path is relative or absolute
fIsRelPath = IsRelativePath(pNewURL);
}
else {
fIsRelPath = TRUE;
pszDstPath = NULL;
}
// check if old path is native or UMI path
hr = pOldURL->GetPathInfo(0, &PathType);
BAIL_ON_FAILURE(hr);
if(PathType & UMIPATH_INFO_NATIVE_STRING) {
// Get the native path from the URL
ulUrlLen = MAX_URL;
hr = pOldURL->Get(0, &ulUrlLen, pszOldUrl);
if(WBEM_E_BUFFER_TOO_SMALL == hr) {
// need to allocate more memory for URL
pszLongOldUrl = (WCHAR *) AllocADsMem(ulUrlLen * sizeof(WCHAR));
if(NULL == pszLongOldUrl)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
hr = pOldURL->Get(0, &ulUrlLen, pszLongOldUrl);
}
BAIL_ON_FAILURE(hr);
}
else {
// assume UMI path if not native
hr = UmiToWinNTPath(
pOldURL,
&pszLongOldUrl,
&dwNumComponents,
&ppszClasses
);
BAIL_ON_FAILURE(hr);
// check to ensure that the UMI path had the expected object classes
hr = CheckClasses(dwNumComponents, ppszClasses);
BAIL_ON_FAILURE(hr);
}
if(TRUE == fIsRelPath) {
if(pNewURL != NULL) {
hr = GetClassAndPath(pszLongNewUrl, &pszClass, &pszDstPath);
BAIL_ON_FAILURE(hr);
// Make sure that if the old path had a class specified in the path,
// then the new path also if of the same class
if(NULL == (pSeparator = wcschr(pszLongOldUrl,
NATIVE_CLASS_SEPARATOR))) {
// no class specified in the old path. Must have been a native path.
// Append class to old path.
pszTmpStr = (WCHAR *) AllocADsMem(
(wcslen(pszLongOldUrl)+MAX_CLASS) *
sizeof(WCHAR) );
if(NULL == pszTmpStr)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
wcscpy(pszTmpStr, pszLongOldUrl);
wcscat(pszTmpStr, L",");
wcscat(pszTmpStr, pszClass);
if(pszLongOldUrl != pszOldUrl)
FreeADsMem(pszLongOldUrl);
pszLongOldUrl = pszTmpStr;
}
else {
// old path already had a class in it
if(_wcsicmp(pSeparator+1, pszClass))
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
}
} // if(pNewUrl != NULL)
m_pCreds->SetUmiFlag();
hr = m_pIADsContainer->MoveHere(
pszLongOldUrl,
pszDstPath,
&pIDispatch
);
m_pCreds->ResetUmiFlag();
BAIL_ON_FAILURE(hr);
} // if(TRUE == fIsRelPath)
else {
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
}
error:
if(pIDispatch != NULL)
pIDispatch->Release();
if(pszLongOldUrl != pszOldUrl)
FreeADsMem(pszLongOldUrl);
if(pszLongNewUrl != pszNewUrl)
FreeADsMem(pszLongNewUrl);
if(pszClass != NULL)
FreeADsStr(pszClass);
if(pszDstPath != NULL)
FreeADsStr(pszDstPath);
if(ppszClasses != NULL) {
for(dwIndex = 0; dwIndex < dwNumComponents; dwIndex++) {
if(ppszClasses[dwIndex] != NULL)
FreeADsStr(ppszClasses[dwIndex]);
}
FreeADsMem(ppszClasses);
}
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: CreateEnum
//
// Synopsis: Creates an enumerator within a container. The enumerator is
// a IUmiCursor interface pointer. The caller can optionally set
// a filter on the cursor and then enumerate the contents of the
// container. The actual enumeration of the container does
// not happen in this function. It is deferred to the point
// when the cursor is used to enumerate the results.
//
// Arguments:
//
// pszEnumContext Not used. Must be NULL.
// uFlags Reserved. Must be 0 for now.
// TargetIID Interface requested. Has to be IUmiCursor.
// ppInterface Returns the IUmiCursor interface pointer
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *ppInterface to return the IUmiCursor interface
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::CreateEnum(
IUmiURL *pszEnumContext,
ULONG uFlags,
REFIID TargetIID,
LPVOID *ppInterface
)
{
HRESULT hr = UMI_S_NO_ERROR;
IUnknown *pEnumerator = NULL;
SetLastStatus(0);
if(uFlags != 0)
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
if( (pszEnumContext != NULL) || (NULL == ppInterface) )
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if(!IsEqualIID(IID_IUmiCursor, TargetIID))
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
*ppInterface = NULL;
if(NULL == m_pIADsContainer)
// shouldn't happen, but just in case...
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
hr = CUmiCursor::CreateCursor(m_pCreds, m_pUnkInner, TargetIID,
ppInterface);
BAIL_ON_FAILURE(hr);
error:
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: ExecQuery
//
// Synopsis: Executes a query in a container. Not implemented on WinNT.
// Implements IUmiContainer::ExecQuery().
//
// Arguments:
//
// pQuery IUmiQuery interface containing the query
// uFlags Reserved. Must be 0 for now.
// TargetIID Interface requested
// ppInterface Returns pointer to interface requested
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *ppInterface to return interface pointer
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::ExecQuery(
IUmiQuery *pQuery,
ULONG uFlags,
REFIID TargetIID,
LPVOID *ppInterface
)
{
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
//----------------------------------------------------------------------------
// Function: GetCLSIDForIID
//
// Synopsis: Returns the CLSID corresponding to a given interface IID. If
// the interface is one of the interfaces implemented by the
// underlying WinNT object, then CLSID_WinNTObject is returned.
// If the IID is one of the interfaces implemented by an
// extension object, then the extension's CLSID is returned.
// Implements IUmiCustomInterfaceFactory::GetCLSIDForIID.
//
// Arguments:
//
// riid Interface ID for which we want to find the CLSID
// lFlags Reserved. Must be 0.
// pCLSID Returns the CLSID corresponding to the IID.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pCLSID to return CLSID.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::GetCLSIDForIID(
REFIID riid,
long lFlags,
CLSID *pCLSID
)
{
HRESULT hr = S_OK;
IUnknown *pUnknown = NULL;
SetLastStatus(0);
if( (lFlags != 0) || (NULL == pCLSID) )
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if(m_pExtMgr != NULL) {
// check if there is any extension which supports this IID
hr = m_pExtMgr->GetCLSIDForIID(
riid,
lFlags,
pCLSID
);
if(SUCCEEDED(hr))
RRETURN(UMI_S_NO_ERROR);
}
// check if the underlying WinNT object supports this IID
hr = m_pUnkInner->QueryInterface(riid, (void **) &pUnknown);
if(SUCCEEDED(hr)) {
pUnknown->Release();
memcpy(pCLSID, &CLSID_WinNTObject, sizeof(GUID));
RRETURN(UMI_S_NO_ERROR);
}
error:
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: GetObjectByCLSID
//
// Synopsis: Returns a pointer to a requested interface on the object
// specified by a CLSID. The object specified by the CLSID is
// aggregated by the specified outer unknown. The interface
// returned is a non-delegating interface on the object.
// Implements IUmiCustomInterfaceFactory::GetObjectByCLSID.
//
// Arguments:
//
// clsid CLSID of object on which interface should be obtained
// pUnkOuter Aggregating outer unknown.
// dwClsContext Context for running executable code.
// riid Interface requested. Has to be IID_IUnknown.
// lFlags Reserved. Must be 0.
// ppInterface Returns requested interface
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *ppInterface to return requested interface
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::GetObjectByCLSID(
CLSID clsid,
IUnknown *pUnkOuter,
DWORD dwClsContext,
REFIID riid,
long lFlags,
void **ppInterface
)
{
HRESULT hr = S_OK;
IUnknown *pCurOuterUnk = NULL;
SetLastStatus(0);
if( (lFlags != 0) || (NULL == pUnkOuter) || (NULL == ppInterface) ||
(dwClsContext != CLSCTX_INPROC_SERVER) )
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
// ensure outer unknown specified is same as what is on the WinNT object
if(TRUE == m_fOuterUnkSet) {
pCurOuterUnk = m_pCoreObj->GetOuterUnknown();
if(pCurOuterUnk != pUnkOuter)
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
}
// Interface requested has to be IID_IUnknown if there is an outer unknown
if (!IsEqualIID(riid, IID_IUnknown))
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if(!IsEqualCLSID(clsid, CLSID_WinNTObject)) {
// has to be a CLSID of an extension object
if(m_pExtMgr != NULL) {
hr = m_pExtMgr->GetObjectByCLSID(
clsid,
pUnkOuter,
riid,
ppInterface
);
BAIL_ON_FAILURE(hr);
// successfully got the interface
m_pCoreObj->SetOuterUnknown(pUnkOuter);
m_fOuterUnkSet = TRUE;
RRETURN(UMI_S_NO_ERROR);
}
else
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG); // bad CLSID
}
// CLSID == CLSID_WinNTObject. This has to be an interface on the
// underlying WinNT object.
m_pCoreObj->SetOuterUnknown(pUnkOuter);
m_fOuterUnkSet = TRUE;
*ppInterface = m_pUnkInner;
m_pUnkInner->AddRef();
RRETURN(UMI_S_NO_ERROR);
error:
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: GetCLSIDForNames
//
// Synopsis: Returns the CLSID of the object that supports a specified
// method/property. Also returns DISPIDs for the property/method.
// Implements IUmiCustomInterfaceFactory::GetCLSIDForNames.
//
// Arguments:
//
// rgszNames Names to be mapped
// cNames Number of names to be mapped
// lcid Locale in which to interpret the names
// rgDispId Returns DISPID
// lFlags Reserved. Must be 0.
// pCLSID Returns CLSID of object which supports this property/method.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pCLSID to return the CLSID.
// *rgDispId to return the DISPIDs.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::GetCLSIDForNames(
LPOLESTR *rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgDispId,
long lFlags,
CLSID *pCLSID
)
{
HRESULT hr = S_OK;
IDispatch *pDispatch = NULL;
SetLastStatus(0);
if( (lFlags != 0) || (NULL == pCLSID) )
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if(0 == cNames)
RRETURN(UMI_S_NO_ERROR);
if( (NULL == rgszNames) || (NULL == rgDispId) )
RRETURN(UMI_S_NO_ERROR);
if(m_pExtMgr != NULL) {
// check if there is any extension which supports this IID
hr = m_pExtMgr->GetCLSIDForNames(
rgszNames,
cNames,
lcid,
rgDispId,
lFlags,
pCLSID
);
if(SUCCEEDED(hr))
// successfully got the CLSID and DISPIDs
RRETURN(UMI_S_NO_ERROR);
}
// check if the underlying WinNT object supports this name
hr = m_pUnkInner->QueryInterface(IID_IDispatch, (void **) &pDispatch);
if(FAILED(hr))
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
hr = pDispatch->GetIDsOfNames(
IID_NULL,
rgszNames,
cNames,
lcid,
rgDispId
);
if(SUCCEEDED(hr)) {
pDispatch->Release();
memcpy(pCLSID, &CLSID_WinNTObject, sizeof(GUID));
RRETURN(UMI_S_NO_ERROR);
}
error:
if(pDispatch != NULL)
pDispatch->Release();
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: GetContainer
//
// Synopsis: Returns a pointer to the IADsContainer interface of the
// underlying WinNT object. Used as a backdoor to get access to
// the WinNT object from a UMI object. Implements
// IUmiADSIPrivate::GetContainer().
//
// Arguments:
//
// ppContainer Returns pointer to IADsContainer interface on WinNT object
//
// Returns: S_OK on success. Error code otherwise.
//
// Modifies: *ppContainer to return the IADsContainer interface pointer.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::GetContainer(void **ppContainer)
{
if(NULL == ppContainer)
RRETURN(UMI_E_INVALIDARG);
*ppContainer = (void *) m_pIADsContainer;
if(m_pIADsContainer != NULL)
m_pIADsContainer->AddRef();
RRETURN(S_OK);
}
//----------------------------------------------------------------------------
// Function: CopyTo
//
// Synopsis: Creates an uncommitted copy of an object at the location
// specified by a URL. This is the same as Clone except that
// the new object has a different path than the old one. If the
// cache is dirty in teh source object, then the destination will
// also end up with a dirty cache.
//
// Update: This method will not be supported for now.
//
// Arguments:
//
// uFlags Flags for CopyTo. Must be 0 for now.
// pURL Destination path (native or UMI)
// riid Interface requested from new object
// pCopy Returns interface requested
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pCopy to return requested interface pointer
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::CopyTo(
ULONG uFlags,
IUmiURL *pURL,
REFIID riid,
LPVOID *pCopy
)
{
HRESULT hr = UMI_S_NO_ERROR;
ULONGLONG PathType = 0;
WCHAR pszUrl[MAX_URL+1];
WCHAR *pszLongUrl = pszUrl;
ULONG ulUrlLen = MAX_URL;
LPWSTR RelName = NULL;
BSTR bstrClass = NULL;
IUnknown *pUnkParent = NULL;
IADsContainer *pIADsCont = NULL;
IDispatch *pDispatch = NULL;
IUmiObject *pUmiObj = NULL;
IUmiADSIPrivate *pUmiPrivate = NULL;
OBJECTINFO ObjectInfo;
POBJECTINFO pObjectInfo = NULL;
CLexer Lexer(NULL);
DWORD dwNumComponents = 0, dwIndex = 0, dwCoreIndex = 0;
LPWSTR *ppszClasses = NULL;
CCoreADsObject *pCoreObj = NULL;
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
SetLastStatus(0);
if(uFlags != 0)
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
if( (NULL == pCopy) || (NULL == pURL) )
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
if( (NULL == m_pCoreObj) || (NULL == m_pIADs) )
// shouldn't happen, but just being paranoid
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
*pCopy = NULL;
// check if this is a native path or UMI path
hr = pURL->GetPathInfo(0, &PathType);
BAIL_ON_FAILURE(hr);
if(PathType & UMIPATH_INFO_NATIVE_STRING) {
// Get the native path from the URL
hr = pURL->Get(0, &ulUrlLen, pszUrl);
if(WBEM_E_BUFFER_TOO_SMALL == hr) {
// need to allocate more memory for URL
pszLongUrl = (WCHAR *) AllocADsMem(ulUrlLen * sizeof(WCHAR));
if(NULL == pszLongUrl)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
hr = pURL->Get(0, &ulUrlLen, pszLongUrl);
}
BAIL_ON_FAILURE(hr);
}
else {
// assume UMI path if not native
hr = UmiToWinNTPath(
pURL,
&pszLongUrl,
&dwNumComponents,
&ppszClasses
);
BAIL_ON_FAILURE(hr);
}
// get the native path of the parent and the relative name of new object
Lexer.SetBuffer(pszLongUrl);
pObjectInfo = &ObjectInfo;
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
hr = Object(&Lexer, pObjectInfo);
if(FAILED(hr)) {
pObjectInfo = NULL; // so we don't attempt to free object info later
goto error;
}
hr = BuildParent(pObjectInfo, pszLongUrl);
BAIL_ON_FAILURE(hr);
if(pObjectInfo->NumComponents != 0)
RelName =
pObjectInfo->DisplayComponentArray[pObjectInfo->NumComponents - 1];
else
// can't have a parent for such a path
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
// Decrement number of components since we are dealing with the parent
dwNumComponents--;
hr = GetObject(
pszLongUrl,
(LPVOID *) &pUnkParent,
*m_pCreds
);
BAIL_ON_FAILURE(hr);
hr = pUnkParent->QueryInterface(
IID_IUmiADSIPrivate,
(LPVOID *) &pUmiPrivate
);
BAIL_ON_FAILURE(hr);
hr = pUmiPrivate->GetCoreObject((void **) &pCoreObj);
BAIL_ON_FAILURE(hr);
// walk the list of classes in reverse order. Reason for reverse order
// is that the WinNT provider may tack on an additional component to
// the ADsPath stored in the core object. For example,
// Open("WinNT://ntdsdc1") would return an ADsPath of
// "WinNT://ntdev/ntdsdc1".
if(dwNumComponents > 0) {
dwCoreIndex = pCoreObj->_dwNumComponents - 1;
for(dwIndex = dwNumComponents - 1; ((long) dwIndex) >= 0; dwIndex--) {
if( _wcsicmp(
ppszClasses[dwIndex],
pCoreObj->_CompClasses[dwCoreIndex]) ) {
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
}
dwCoreIndex--;
}
}
hr = pUmiPrivate->GetContainer((void **) &pIADsCont);
BAIL_ON_FAILURE(hr);
if(NULL == pIADsCont)
// parent object is not a container
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
// get the class of this object
hr = m_pIADs->get_Class(&bstrClass);
BAIL_ON_FAILURE(hr);
// make sure that the destination path mentioned the same class
if(_wcsicmp(bstrClass, ppszClasses[dwNumComponents]))
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
// now Create() the new object
hr = pIADsCont->Create(
bstrClass,
RelName,
&pDispatch
);
if(E_NOTIMPL == hr) // parent is namespace object
hr = UMI_E_FAIL;
BAIL_ON_FAILURE(hr);
hr = pDispatch->QueryInterface(IID_IUmiObject, (LPVOID *) &pUmiObj);
BAIL_ON_FAILURE(hr);
// if the source object is bound, refresh it if required
if(ADS_OBJECT_BOUND == m_pCoreObj->GetObjectState()) {
// object exists on server
if(FALSE == m_fRefreshDone) {
hr = m_pCoreObj->ImplicitGetInfo();
BAIL_ON_FAILURE(hr);
}
}
// copy over the attributes in the property cache
hr = CopyPropCache(pUmiObj, (IUmiObject *) this);
BAIL_ON_FAILURE(hr);
hr = pUmiObj->QueryInterface(riid, pCopy);
BAIL_ON_FAILURE(hr);
error:
if( (pszLongUrl != NULL) && (pszLongUrl != pszUrl) )
FreeADsMem(pszLongUrl);
if(bstrClass != NULL)
SysFreeString(bstrClass);
if(pUnkParent != NULL)
pUnkParent->Release();
if(pIADsCont != NULL)
pIADsCont->Release();
if(pUmiObj != NULL)
pUmiObj->Release();
if(pUmiPrivate != NULL)
pUmiPrivate->Release();
if(pDispatch != NULL)
pDispatch->Release();
if(pObjectInfo != NULL)
FreeObjectInfo(&ObjectInfo, TRUE);
if(ppszClasses != NULL) {
for(dwIndex = 0; dwIndex < dwNumComponents; dwIndex++) {
if(ppszClasses[dwIndex] != NULL)
FreeADsStr(ppszClasses[dwIndex]);
}
FreeADsMem(ppszClasses);
}
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: GetCoreObject
//
// Synopsis: Returns a pointer to the core object of the
// underlying WinNT object. Used as a backdoor to get access to
// the WinNT core object from a UMI object. Implements
// IUmiADSIPrivate::GetCoreObject().
//
// Arguments:
//
// ppCoreObj Returns pointer to core object of WinNT object
//
// Returns: S_OK on success. Error code otherwise.
//
// Modifies: *ppCoreObj to return the core object pointer.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiObject::GetCoreObject(void **ppCoreObj)
{
if(NULL == ppCoreObj)
RRETURN(UMI_E_INVALIDARG);
*ppCoreObj = NULL;
if(NULL == m_pCoreObj)
// shouldn't happen. Just being paranoid.
RRETURN(UMI_E_FAIL);
*ppCoreObj = (void *) m_pCoreObj;
RRETURN(S_OK);
}
//----------------------------------------------------------------------------
// Function: CheckClasses
//
// Synopsis: Checks that the classes specified in the UMI path passed to
// Move are valid. Need a separate function for this because UMI
// doesn't actually retrieve the object that is to be moved - it
// is handled internally within ADSI. So, we need to check the
// classes before calling into ADSI. We make use of the fact that
// the WinNT provider only supports moving user and group objects.
//
// Arguments:
//
// dwNumComponents Number of components in the UMI path
// ppszClasses Class of each component
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
HRESULT CUmiObject::CheckClasses(
DWORD dwNumComponents,
LPWSTR *ppszClasses
)
{
if(NULL == ppszClasses)
RRETURN(UMI_E_INVALIDARG);
if( (dwNumComponents != 2) && (dwNumComponents != 3) )
RRETURN(UMI_E_INVALIDARG);
// can only move users or groups
if( _wcsicmp(ppszClasses[dwNumComponents - 1], USER_CLASS_NAME) &&
_wcsicmp(ppszClasses[dwNumComponents - 1], GROUP_CLASS_NAME) )
RRETURN(UMI_E_INVALIDARG);
if(2 == dwNumComponents) {
if( _wcsicmp(ppszClasses[0], DOMAIN_CLASS_NAME) &&
_wcsicmp(ppszClasses[0], COMPUTER_CLASS_NAME) )
RRETURN(UMI_E_INVALIDARG);
}
if(3 == dwNumComponents) {
if( _wcsicmp(ppszClasses[0], DOMAIN_CLASS_NAME) ||
_wcsicmp(ppszClasses[1], COMPUTER_CLASS_NAME) )
RRETURN(UMI_E_INVALIDARG);
}
RRETURN(S_OK);
}