|
|
//----------------------------------------------------------------------------
//
// 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); }
|