2577 lines
69 KiB
C++
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);
|
|
}
|