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

644 lines
16 KiB
C++

//----------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: cumicurs.cxx
//
// Contents: Contains the UMI cursor object implementation
//
// History: 03-16-00 SivaramR Created.
//
//----------------------------------------------------------------------------
#include "winnt.hxx"
//----------------------------------------------------------------------------
// Function: CreateCursor
//
// Synopsis: Creates a cursor object. Called by IUmiContainer::CreateEnum().
//
// Arguments:
//
// pCredentials Credentials of the UMI object creating the cursor
// pCont Pointer to container on which CreateEnum was called
// iid Interface requested. Only interface supported is IUmiCursor.
// ppInterface Returns pointer to interface requested
//
// Returns: S_OK on success. Error code otherwise.
//
// Modifies: *ppInterface to return a pointer to the interface requested
//
//----------------------------------------------------------------------------
HRESULT CUmiCursor::CreateCursor(
CWinNTCredentials *pCredentials,
IUnknown *pCont,
REFIID iid,
LPVOID *ppInterface
)
{
CUmiCursor *pCursor = NULL;
HRESULT hr = S_OK;
ADsAssert(ppInterface != NULL);
ADsAssert(pCont != NULL);
pCursor = new CUmiCursor();
if(NULL == pCursor)
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
// initialize cursor object
hr = pCursor->FInit(pCont, pCredentials);
BAIL_ON_FAILURE(hr);
hr = pCursor->QueryInterface(iid, ppInterface);
BAIL_ON_FAILURE(hr);
pCursor->Release();
RRETURN(S_OK);
error:
if(pCursor != NULL)
delete pCursor;
RRETURN(hr);
}
//----------------------------------------------------------------------------
// Function: CUmiCursor
//
// Synopsis: Constructor. Initializes all member variables
//
// Arguments:
//
// None
//
// Returns: Nothing.
//
// Modifies: Nothing.
//
//----------------------------------------------------------------------------
CUmiCursor::CUmiCursor(void)
{
m_pIUmiPropList = NULL;
m_ulErrorStatus = 0;
m_pUnkInner = NULL;
m_pIID = NULL;
m_pEnumerator = NULL;
}
//----------------------------------------------------------------------------
// Function: ~CUmiCursor
//
// Synopsis: Destructor. Frees member variables
//
// Arguments:
//
// None
//
// Returns: Nothing.
//
// Modifies: Nothing.
//
//----------------------------------------------------------------------------
CUmiCursor::~CUmiCursor(void)
{
if(m_pIUmiPropList != NULL)
m_pIUmiPropList->Release();
if(m_pUnkInner != NULL)
m_pUnkInner->Release();
if(m_pIID != NULL)
FreeADsMem(m_pIID);
if(m_pEnumerator != NULL)
m_pEnumerator->Release();
}
//----------------------------------------------------------------------------
// Function: FInit
//
// Synopsis: Initializes cursor object.
//
// Arguments:
//
// pCont Pointer to UMI container that created this cursor.
// pCredentials Credentials of UMI object creating the cursor
//
// Returns: S_OK on success. Error code otherwise.
//
// Modifies: Nothing.
//
//----------------------------------------------------------------------------
HRESULT CUmiCursor::FInit(
IUnknown *pCont,
CWinNTCredentials *pCredentials
)
{
HRESULT hr = S_OK;
CUmiPropList *pPropList = NULL;
ADsAssert(pCont != NULL);
pPropList = new CUmiPropList(CursorClass, g_dwCursorTableSize);
if(NULL == pPropList)
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
hr = pPropList->FInit(NULL, NULL);
BAIL_ON_FAILURE(hr);
hr = pPropList->QueryInterface(
IID_IUmiPropList,
(void **) &m_pIUmiPropList
);
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.
pPropList->Release();
m_pUnkInner = pCont;
pCont->AddRef();
m_pCreds = pCredentials;
RRETURN(S_OK);
error:
if(m_pIUmiPropList != NULL) {
m_pIUmiPropList->Release();
m_pIUmiPropList = NULL;
}
if(pPropList != NULL)
delete pPropList;
RRETURN(hr);
}
//----------------------------------------------------------------------------
// Function: QueryInterface
//
// Synopsis: Queries cursor object for supported interfaces. Only
// IUmiCursor is supported.
//
// 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 CUmiCursor::QueryInterface(
REFIID iid,
LPVOID *ppInterface
)
{
if(NULL == ppInterface)
RRETURN(E_INVALIDARG);
*ppInterface = NULL;
if(IsEqualIID(iid, IID_IUnknown))
*ppInterface = (IUmiCursor *) this;
else if(IsEqualIID(iid, IID_IUmiCursor))
*ppInterface = (IUmiCursor *) this;
else if(IsEqualIID(iid, IID_IUmiBaseObject))
*ppInterface = (IUmiBaseObject *) this;
else if(IsEqualIID(iid, IID_IUmiPropList))
*ppInterface = (IUmiPropList *) this;
else
RRETURN(E_NOINTERFACE);
AddRef();
RRETURN(S_OK);
}
//----------------------------------------------------------------------------
// 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.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiCursor::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: 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
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiCursor::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_pIUmiPropList != NULL);
hr = m_pIUmiPropList->QueryInterface(IID_IUmiPropList, (void **)pPropList);
error:
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: SetLastStatus
//
// Synopsis: Sets the status of the last operation.
//
// Arguments:
//
// ulStatus Status to be set
//
// Returns: Nothing
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
void CUmiCursor::SetLastStatus(ULONG ulStatus)
{
m_ulErrorStatus = ulStatus;
return;
}
//----------------------------------------------------------------------------
// Function: SetIID
//
// Synopsis: Sets the interface to be requested off each item returned by
// the enumerator. Default is IID_IUmiObject.
//
// Arguments:
//
// riid IID of interface to request
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: Nothing.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiCursor::SetIID(
REFIID riid
)
{
SetLastStatus(0);
if(NULL == m_pIID)
{
m_pIID = (IID *) AllocADsMem(sizeof(IID));
if(NULL == m_pIID) {
SetLastStatus(UMI_E_OUT_OF_MEMORY);
RRETURN(UMI_E_OUT_OF_MEMORY);
}
}
memcpy(m_pIID, &riid, sizeof(IID));
RRETURN(UMI_S_NO_ERROR);
}
//----------------------------------------------------------------------------
// Function: Reset
//
// Synopsis: Resets the enumerator to start from the beginning
//
// Arguments:
//
// None
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: Nothing.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiCursor::Reset(void)
{
HRESULT hr = UMI_S_NO_ERROR;
SetLastStatus(0);
// WinNT doesn't support Reset(). Keep the code below in case WinNT
// Reset() gets implemented in the future.
BAIL_ON_FAILURE(hr = UMI_E_NOTIMPL);
// it is possible that m_pEnumerator may be NULL here if the user
// called Reset before calling Next()
if(NULL == m_pEnumerator)
RRETURN(UMI_S_NO_ERROR);
hr = m_pEnumerator->Reset();
BAIL_ON_FAILURE(hr);
RRETURN(UMI_S_NO_ERROR);
error:
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: GetFilter
//
// Synopsis: Gets the filter from the interface property cache. If the
// interface property was not set, an emty variant is returned.
//
// Arguments:
//
// pvFilter Returns variant containing the filter
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pvFilter to return the filter.
//
//----------------------------------------------------------------------------
HRESULT CUmiCursor::GetFilter(VARIANT *pvFilter)
{
HRESULT hr = UMI_S_NO_ERROR;
UMI_PROPERTY_VALUES *pUmiProp = NULL;
LPWSTR *ppszFilters = NULL;
DWORD dwNumFilters = 0;
ADsAssert(pvFilter != NULL);
VariantInit(pvFilter);
hr = m_pIUmiPropList->Get(
TEXT(CURSOR_INTF_PROP_FILTER),
0,
&pUmiProp
);
if(UMI_E_PROPERTY_NOT_FOUND == hr)
// interface property was not set. Return empty variant.
RRETURN(UMI_S_NO_ERROR);
// check if there was some other error on Get()
BAIL_ON_FAILURE(hr);
ADsAssert(UMI_TYPE_LPWSTR == pUmiProp->pPropArray->uType);
ADsAssert(pUmiProp->pPropArray->pUmiValue != NULL);
ppszFilters = pUmiProp->pPropArray->pUmiValue->pszStrValue;
dwNumFilters = pUmiProp->pPropArray->uCount;
hr = ADsBuildVarArrayStr(ppszFilters, dwNumFilters, pvFilter);
BAIL_ON_FAILURE(hr);
error:
if(pUmiProp != NULL)
m_pIUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
RRETURN(hr);
}
//----------------------------------------------------------------------------
// Function: Next
//
// Synopsis: Returns the next item(s) in the enumeration sequence.
//
// Arguments:
//
// uNumRequested Number of items requested
// pNumReturned Returns actual number of objects returned
// ppObjects Array of interface pointers of size *pNumReturned
//
// None
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pNumReturned to return the number of objects returned
// *ppObjects to return the interface pointers
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiCursor::Next(
ULONG uNumRequested,
ULONG *puNumReturned,
LPVOID *ppObjects
)
{
HRESULT hr = UMI_S_NO_ERROR;
VARIANT vFilter, *pvResults = NULL;
ULONG ulIndex = 0, uNumReturned = 0, uNumResults = 0;
IDispatch *pDisp = NULL;
IUnknown **pUnkArr = NULL, *pTmpUnk = NULL;
IADsContainer *pIADsContainer = NULL;
SetLastStatus(0);
if( (NULL == puNumReturned) || (NULL == ppObjects) )
BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
*puNumReturned = 0;
*ppObjects = NULL;
VariantInit(&vFilter);
if(NULL == m_pEnumerator) {
// first call to Next()
ADsAssert(m_pUnkInner != NULL);
hr = m_pUnkInner->QueryInterface(
IID_IADsContainer,
(void **) &pIADsContainer
);
BAIL_ON_FAILURE(hr);
// check if the user set a filter on the cursor
hr = GetFilter(&vFilter);
BAIL_ON_FAILURE(hr);
hr = pIADsContainer->put_Filter(vFilter);
BAIL_ON_FAILURE(hr);
m_pCreds->SetUmiFlag();
hr = pIADsContainer->get__NewEnum((IUnknown **) &m_pEnumerator);
m_pCreds->ResetUmiFlag();
BAIL_ON_FAILURE(hr);
}
// allocate memory for variants to return objects
pvResults = (VARIANT *) AllocADsMem(uNumRequested * sizeof(VARIANT));
if(NULL == pvResults)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
hr = m_pEnumerator->Next(
uNumRequested,
pvResults,
&uNumReturned
);
BAIL_ON_FAILURE(hr);
// allocate memory for array of interface pointers to return
pUnkArr = (IUnknown **) AllocADsMem(uNumReturned * sizeof(IUnknown *));
if(NULL == pUnkArr)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
// convert the V_DISPATCH variants to the requested interface properties
for(ulIndex = 0; ulIndex < uNumReturned; ulIndex++) {
pDisp = V_DISPATCH(&pvResults[ulIndex]);
ADsAssert(pDisp != NULL);
if(m_pIID != NULL)
hr = pDisp->QueryInterface(*m_pIID, (void **) &pTmpUnk);
else
hr = pDisp->QueryInterface(IID_IUmiObject, (void **) &pTmpUnk);
if(FAILED(hr))
continue;
pUnkArr[uNumResults] = pTmpUnk;
uNumResults++;
}
*puNumReturned = uNumResults;
if(uNumResults > 0)
*ppObjects = pUnkArr;
else
FreeADsMem(pUnkArr);
error:
VariantClear(&vFilter);
if(pvResults != NULL) {
for(ulIndex = 0; ulIndex < uNumReturned; ulIndex++)
VariantClear(&pvResults[ulIndex]);
FreeADsMem(pvResults);
}
if(pIADsContainer != NULL)
pIADsContainer->Release();
if(FAILED(hr))
SetLastStatus(hr);
RRETURN(MapHrToUmiError(hr));
}
//----------------------------------------------------------------------------
// Function: Count
//
// Synopsis: Counts the number of results returned by the enumerator.
// Not implemented currently.
//
// Arguments:
//
// None
//
// Returns: UMI_E_NOTIMPL for now.
//
// Modifies: Nothing.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiCursor::Count(
ULONG *puNumObjects
)
{
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}
//----------------------------------------------------------------------------
// Function: Previous
//
// Synopsis: Returnss the previous object returned by the enumerator.
// Not implemented currently.
//
// Arguments:
//
// None
//
// Returns: UMI_E_NOTIMPL for now.
//
// Modifies: Nothing.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiCursor::Previous(
ULONG uFlags,
LPVOID *pObj
)
{
SetLastStatus(UMI_E_NOTIMPL);
RRETURN(UMI_E_NOTIMPL);
}