/////////////////////////////////////////////////////////////////////////////// /* File: enumuser.cpp Description: Contains member function definitions for class DiskQuotaUserEnum. The DiskQuotaUserEnum object is provided to enumerate the users in a volume's quota information file. The caller instantiates an enumerator through IDiskQuotaControl::CreateDiskQuotaUserEnum(). The enumerator's interface IEnumDiskQuotaUsers supports the normal OLE 2 enumeration functions Next(), Skip(), Reset() and Clone(). Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// #include "pch.h" // PCH #pragma hdrstop #include "user.h" #include "userenum.h" // // Verify that build is UNICODE. // #if !defined(UNICODE) # error This module must be compiled UNICODE. #endif /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::DiskQuotaUserEnum Description: Constructor. Arguments: pFSObject - Pointer to an existing "file system" object. It is through this object that the enumerator accesses the ntioapi functions. A pointer to this file system object is also passed on to contained user objects so they may refresh their data when required. pQuotaController - Pointer to an IDiskQuotaControl interface that we'll AddRef(). The control object is who provides the "name changed" notification mechanism. It needs to stay around as long as the enumerator is alive. pSidNameResolver - Pointer to an ISidNameResolver interface that will be used to resolve user SIDs to account names. The resolver object is initially instantiated by the quota controller. Returns: Nothing. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu 08/15/97 Moved pQuotaControl, pSidNameResolver and pFSObject BrianAu arguments from Initialize() to ctor. Needed so that ref counting is correct. */ /////////////////////////////////////////////////////////////////////////////// DiskQuotaUserEnum::DiskQuotaUserEnum( PDISKQUOTA_CONTROL pQuotaController, PSID_NAME_RESOLVER pSidNameResolver, FSObject *pFSObject ) : m_cRef(0), m_pbBuffer(NULL), m_pbCurrent(NULL), m_cbBuffer(0), m_pSidList(NULL), m_cbSidList(0), m_bEOF(FALSE), m_bSingleUser(FALSE), m_bInitialized(FALSE), m_bRestartScan(TRUE), m_fNameResolution(DISKQUOTA_USERNAME_RESOLVE_NONE), m_pFSObject(pFSObject), m_pQuotaController(pQuotaController), m_pSidNameResolver(pSidNameResolver) { DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserEnum::DiskQuotaUserEnum"))); if (NULL != m_pQuotaController) m_pQuotaController->AddRef(); if (NULL != m_pSidNameResolver) m_pSidNameResolver->AddRef(); if (NULL != m_pFSObject) m_pFSObject->AddRef(); InterlockedIncrement(&g_cRefThisDll); } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::~DiskQuotaUserEnum Description: Destructor. Destroys the enumerator's internal buffers and releases any held interface pointers. Arguments: None. Returns: Nothing. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// DiskQuotaUserEnum::~DiskQuotaUserEnum(void) { DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserEnum::~DiskQuotaUserEnum"))); if (NULL != m_pFSObject) m_pFSObject->Release(); // // Order is important here. Release the resolver before the controller. // if (NULL != m_pSidNameResolver) m_pSidNameResolver->Release(); if (NULL != m_pQuotaController) m_pQuotaController->Release(); delete [] m_pbBuffer; delete [] m_pSidList; InterlockedDecrement(&g_cRefThisDll); } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::QueryInterface Description: Obtain pointer to IUnknown or IEnumDiskQuotaUser. Note that referenced object is uninitialized. Recipient of interface pointer must call Initialize() member function before object is usable. Arguments: riid - Reference to requested interface ID. IID_IUnknown and IID_IEnumDiskQuotaUser are recognized. ppvOut - Address of interface pointer variable to accept the returned interface pointer. Returns: NO_ERROR - Success. E_NOINTERFACE - Requested interface not supported. E_INVALIDARG - ppvOut argument is NULL. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP DiskQuotaUserEnum::QueryInterface( REFIID riid, LPVOID *ppvOut ) { HRESULT hResult = E_NOINTERFACE; if (NULL == ppvOut) return E_INVALIDARG; *ppvOut = NULL; if (IID_IUnknown == riid || IID_IEnumDiskQuotaUsers == riid) { // // Interface supported. // *ppvOut = this; ((LPUNKNOWN)*ppvOut)->AddRef(); hResult = NOERROR; } return hResult; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::AddRef Description: Increments object reference count. Arguments: None. Returns: New reference count value. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) DiskQuotaUserEnum::AddRef( VOID ) { ULONG ulReturn = m_cRef + 1; DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserEnum::AddRef, 0x%08X %d -> %d"), this, ulReturn - 1, ulReturn)); InterlockedIncrement(&m_cRef); return ulReturn; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::Release Description: Decrements object reference count. If count drops to 0, object is deleted. Arguments: None. Returns: New reference count value. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) DiskQuotaUserEnum::Release( VOID ) { ULONG ulReturn = m_cRef - 1; DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserEnum::Release, 0x%08X %d -> %d"), this, ulReturn + 1, ulReturn)); if (InterlockedDecrement(&m_cRef) == 0) { delete this; ulReturn = 0; } return ulReturn; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::Initialize Description: Initializes a new enumerator object. This member function is overloaded to provide two implementations. The first accepts explicit arguments for initialization. This member is intended for creating a new unique enumerator through IDiskQuotaControl::CreateEnumUsers. The second implementation merely accepts a reference to an existing EnumUsers object. This member is intended to support the function IEnumDiskQuotaUser::Clone(). Arguments: fNameResolution - Method of SID-to-name resolution. Can be one of the following: DISKQUOTA_USERNAME_RESOLVE_NONE DISKQUOTA_USERNAME_RESOLVE_SYNC DISKQUOTA_USERNAME_RESOLVE_ASYNC cbBuffer [optional] - Size in bytes of the internal buffer used in calls to the NTIOAPI functions. Default is ENUMUSER_BUF_LEN. rgpSids [optional] - Pointer to a list of SID pointers. If provided, only those users with SIDs included in the list are returned. This argument may be NULL in which case ALL users are included. Any element containing a NULL pointer will terminate the list. cpSids [optional] - If pSidList is not NULL, this arg contains the count of entries in rgpSids. If rgpSids is not NULL and this argument contains 0, rgpSids is assumed to contain a terminating NULL pointer entry. UserEnum - Reference to an existing DiskQuotaUserEnum object. The new object opens a connection to the same volume as the object being cloned. The new object maintains a separate buffer for transfer of data from the NTIOAPI system. Returns: NO_ERROR - Success. S_FALSE - Already initialized. E_OUTOFMEMORY - Insufficient memory. ERROR_INVALID_SID (hr) - A SID in rgpSids was invalid. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// HRESULT DiskQuotaUserEnum::Initialize( DWORD fNameResolution, DWORD cbBuffer, PSID *rgpSids, DWORD cpSids ) { HRESULT hResult = NO_ERROR; if (m_bInitialized) { hResult = S_FALSE; } else { try { // // Create an internal buffer for data transfer from the ntioapi. // m_pbBuffer = new BYTE [cbBuffer]; m_cbBuffer = cbBuffer; if (NULL != rgpSids) { // // A list of SID pointers was provided. // Initialize the SID list structure. // Can throw OutOfMemory. // m_bSingleUser = (cpSids == 1); hResult = InitializeSidList(rgpSids, cpSids); } if (SUCCEEDED(hResult)) { // // Must have an independent instance of the controller's file system // object. The NTIOAPI functions maintain an enumeration context // for each open handle. Therefore, each user enumerator must have a // unique file handle to the NTIOAPI object. // I say this because it appears tempting to just keep a copy of the // controller's FSObject pointer and AddRef it. // // This create-n-swap is sort of slimy. We originally got a // ptr to the caller's FSObject in the ctor. However, now we want // to create our own FSObject. Create a copy and release the original. // FSObject *pFsoTemp = m_pFSObject; m_pFSObject = NULL; hResult = FSObject::Create(*pFsoTemp, &m_pFSObject); pFsoTemp->Release(); if (SUCCEEDED(hResult)) { m_fNameResolution = fNameResolution; m_bInitialized = TRUE; } } } catch(CAllocException& e) { hResult = E_OUTOFMEMORY; } } return hResult; } HRESULT DiskQuotaUserEnum::Initialize( const DiskQuotaUserEnum& UserEnum ) { HRESULT hResult = NO_ERROR; try { // // Initialize the new enumerator without a SID list. // If the enumerator being copied has a SID list, we // don't want to re-create a list of SID pointers for Initialize() // so we defer this for InitializeSidList. InitializeSidList // has an overloaded version that accepts a pointer to an existing // SIDLIST structure and merely copies the bytes. // hResult = Initialize(UserEnum.m_fNameResolution, UserEnum.m_cbBuffer, NULL, 0); if (SUCCEEDED(hResult) && NULL != UserEnum.m_pSidList) { m_bSingleUser = UserEnum.m_bSingleUser; hResult = InitializeSidList(UserEnum.m_pSidList, UserEnum.m_cbSidList); } } catch(CAllocException& e) { hResult = E_OUTOFMEMORY; } return hResult; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::InitializeSidList Description: Initializes the m_pSidList member of the enumerator. The method comes in two overloaded forms. The first accepts a pointer to an existing SIDLIST structure and merely creates a new copy. The second form accepts the address of an array of SID pointers and generates a new SIDLIST structure. Arguments: pSidList - Address of an existing SIDLIST structure to be copied. cbSidList - Number of bytes in the SIDLIST structure. rgpSids - Pointer to a list of SID pointers. If provided, only those users with SIDs included in the list are returned. This argument may be NULL in which case ALL users are included. Any element containing a NULL pointer will terminate the list. cpSids - If pSidList is not NULL, this arg contains the count of entries in rgpSids. If rgpSids is not NULL and this argument contains 0, rgpSids is assumed to contain a terminating NULL pointer entry. Returns: NO_ERROR - Success. ERROR_INVALID_SID (hr) - A SID in rgpSids was invalid. Exceptions: OutOfMemory. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 08/13/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// HRESULT DiskQuotaUserEnum::InitializeSidList( PSIDLIST pSidList, DWORD cbSidList ) { HRESULT hResult = NO_ERROR; DBGASSERT((NULL != pSidList)); DBGASSERT((0 < cbSidList)); // // Create a buffer for the SID list copy. // m_pSidList = (PSIDLIST)new BYTE[cbSidList]; // // Copy the enumerator's SID list. // CopyMemory(m_pSidList, pSidList, cbSidList); m_cbSidList = cbSidList; return hResult; } HRESULT DiskQuotaUserEnum::InitializeSidList( PSID *rgpSids, DWORD cpSids ) { HRESULT hResult = NO_ERROR; DBGASSERT((NULL != rgpSids)); DBGASSERT((0 < cpSids)); // // Create a SIDLIST structure from the array of SID pointers. // Can throw OutOfMemory. // hResult = CreateSidList(rgpSids, cpSids, &m_pSidList, &m_cbSidList); if (FAILED(hResult)) { DBGASSERT((NULL == m_pSidList)); DBGASSERT((0 == m_cbSidList)); } return hResult; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::QueryQuotaInformation Description: Provides a simple wrapper around the NTIOAPI function QueryQuotaInformationFile. The function adds value by providing the address and size of the enumerator's data buffer. Note that the QueryQuotaInformationFile interface in NTIOAPI functions as an enumerator itself. Repeated calls enumerate user quota data much the same way the Next() function does in an OLE enumerator interface. Data is returned in a byte buffer as a series of variable-length quota records. Arguments: bReturnSingleEntry [optional] - TRUE if only a single entry is desired. FALSE if multiple records are desired. Default is FALSE. pSidList [optional] - Pointer to a list of SIDs. If provided, the data returned is only for those users included in the SID list. Default is NULL. cbSidList [optional] - If SidList is not NULL, contains length of SidList in bytes. Default is 0. pStartSid [optional] - Pointer to SID in SID list where scan is to start if bRestartScan is TRUE. Default is NULL. bRestartScan [optional] - TRUE = restart enumeration at first user or user pointed to by StartSid in SidList (if provided). FALSE = continue enumeration from current point. Default is FALSE. Returns: NO_ERROR - Success. ERROR_NO_MORE_ITEMS - No more user records. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// HRESULT DiskQuotaUserEnum::QueryQuotaInformation( BOOL bReturnSingleEntry, PVOID pSidList, ULONG cbSidList, PSID pStartSid, BOOL bRestartScan ) { HRESULT hResult = NO_ERROR; if (bRestartScan) { // // Reset EOF flag if restarting enumerator scan. // m_bEOF = FALSE; } if (!m_bEOF) { ZeroMemory(m_pbBuffer, m_cbBuffer); hResult = m_pFSObject->QueryUserQuotaInformation( m_pbBuffer, m_cbBuffer, bReturnSingleEntry, pSidList, cbSidList, pStartSid, bRestartScan); if (ERROR_SUCCESS == HRESULT_CODE(hResult) || ERROR_NO_MORE_ITEMS == HRESULT_CODE(hResult)) { // // The enumeration logic changed between Win2000 and WinXP. // On Win2000, NTFS will return ERROR_NO_MORE_ITEMS on the last // buffer returned that contains data. On WinXP, this error // code is returned on the first buffer that returns NO data. // To handle both cases, we zero out the buffer before reading data // and inspect the SidLength value in the first record to determine // if the buffer contains any data. If the sid length is 0, we // can assume the buffer is empty. // hResult = NO_ERROR; } } else { // // There REALLY are no more entries. // hResult = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); } return hResult; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::CreateUserObject Description: Creates a new DiskQuotaUser object from the quota information retrieved through QueryQuotaInformation. The caller provides a pointer to the start of the desired quota info record to be used for initialization. Arguments: pfqi - Pointer to the quota information record used for initialization. ppOut - Address of interface pointer variable to accept the user object's IDiskQuotaUser interface pointer. Returns: NO_ERROR - Success. E_INVALIDARG - pfqi or ppOut arg is NULL. E_UNEXPECTED - Unexpected error. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu 09/05/96 Added exception handling. BrianAu */ /////////////////////////////////////////////////////////////////////////////// HRESULT DiskQuotaUserEnum::CreateUserObject( PFILE_QUOTA_INFORMATION pfqi, PDISKQUOTA_USER *ppOut ) { HRESULT hResult = NO_ERROR; if (NULL == pfqi || NULL == ppOut) return E_INVALIDARG; // // Create the user object and get the IDiskQuotaUser interface pointer. // This pointer is what is given to the caller. // m_pFSObject->AddRef(); DiskQuotaUser *pUser = new DiskQuotaUser(m_pFSObject); // // Initialize the new user object using the buffered quota data pointed to // by pfqi. // hResult = pUser->Initialize(pfqi); if (SUCCEEDED(hResult)) { hResult = pUser->QueryInterface(IID_IDiskQuotaUser, (LPVOID *)ppOut); } if (FAILED(hResult)) { // // Either Initialize or QueryInterface failed. Delete the object. // delete pUser; pUser = NULL; } return hResult; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::GetNextUser Description: Creates a new user object from the "current" record in the quota information buffer. A pointer to the object's IDiskQuotaUser interface is returned and the "current" record pointer in the quota information buffer is advanced to the next user record. Arguments: ppOut [optional] - Address of interface pointer variable to receive address of user object's IDiskQuotaUserInterface pointer. If this argument is NULL, the new user object is not created. This is useful for skipping items in the enumeration. Returns: NO_ERROR - Success. E_DISKQUOTA_INVALID_SID - User record's SID is invalid. ERROR_NO_MORE_ITEMS - No more users. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// HRESULT DiskQuotaUserEnum::GetNextUser( PDISKQUOTA_USER *ppOut ) { PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)m_pbCurrent; HRESULT hResult = NO_ERROR; // // If m_pbCurrent is NULL, this is the first request for data. // If pfqi->NextEntryOffset is 0, we need to read another buffer of data. // if (NULL == m_pbCurrent) { // // No more user entries in buffer. // Read quota information into m_pbBuffer. // Use SID list if we have one. // hResult = QueryQuotaInformation(m_bSingleUser, // Single user? m_pSidList, // SID list. m_cbSidList, // SID list length. 0, // Start SID, m_bRestartScan); // Restart scan? if (SUCCEEDED(hResult)) { // // New information in buffer. Reset record pointers. // m_pbCurrent = m_pbBuffer; m_bRestartScan = FALSE; pfqi = (PFILE_QUOTA_INFORMATION)m_pbCurrent; } } if (SUCCEEDED(hResult)) { // // We have a valid pointer into the buffer of user quota data. // if (NULL != ppOut) { if (0 != pfqi->SidLength) { // // Caller provided a user interface pointer variable. // Create a new user record. This can throw OutOfMemory. // hResult = CreateUserObject(pfqi, ppOut); } else { m_bEOF = TRUE; hResult = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); } } if (0 != pfqi->NextEntryOffset) m_pbCurrent += pfqi->NextEntryOffset; // Advance to next user. else m_pbCurrent = NULL; // Reset to trigger quota file read. } return hResult; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::Next Description: Retrieve the next cUsers records from the volume's quota information file. If the enumerator was created with a SidList, only those users contained in the SidList are included in the enumeration. Repeated calls to Next() continue to enumerate successive quota users. The Reset() function may be used to reset the enumerator to the start of the enumeration. Arguments: cUsers - Number of elements in paUsers array. pUser - Array of IDiskQuotaUser pointers. Must provide space for cUsers pointers. Upon return, each element of this array contains an interface pointer to a DiskQuotaUser object. pcCreated [optional] - Address of DWORD to accept the count of user object interface pointers returned in pUser. Note that any array locations equal to or beyond the value returned in pcCreated are invalid and set to NULL. Returns: S_OK - Success. Enumerated number of requested users. S_FALSE - End of enumeration encountered. Returning less than cUsers records. E_INVALIDARG - pUser arg is NULL. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// HRESULT DiskQuotaUserEnum::Next( DWORD cUsers, // Number of elements in array. PDISKQUOTA_USER *pUser, // Dest array for quota user interface ptrs. DWORD *pcCreated // Return number created. ) { HRESULT hResult = S_OK; UINT i = 0; // Index into user caller's array. UINT cCreated = 0; if (NULL == pUser) return E_INVALIDARG; if (NULL != pcCreated) *pcCreated = 0; try { IDiskQuotaUser *pNextUser = NULL; // Ptr to new user. // // Enumerate user records until one of the following: // 1. Failure. // 2. No more users. // 3. Enumerated requested count. // while(SUCCEEDED(hResult) && cUsers > 0) { // // Create new user object. This can throw OutOfMemory. // hResult = GetNextUser(&pNextUser); if (SUCCEEDED(hResult)) { // // User records come from the quota file containing only a SID. // We must ask the SidNameResolver to locate the corresponding // account name. If client wants names synchronously, we block // here until account name is found. User object will contain // account name. // If client wants names asynchronously, the user object is handed // off to the resolver for background processing. We continue on. // If the client implemented the IDiskQuotaEvents interface and // called IConnectionPoint::Advise, it will receive a // OnUserNameChange notification when the name is finally resolved. // If user doesn't want user name resolved, don't do either. // This would be the case if the client already has the SID/Name // pair and just wants user objects. // switch(m_fNameResolution) { case DISKQUOTA_USERNAME_RESOLVE_ASYNC: m_pSidNameResolver->FindUserNameAsync(pNextUser); break; case DISKQUOTA_USERNAME_RESOLVE_SYNC: m_pSidNameResolver->FindUserName(pNextUser); break; case DISKQUOTA_USERNAME_RESOLVE_NONE: default: break; } // // Note: Ref count for pUser already incremented in // DiskQuotaUser::QueryInterface. // *pUser = pNextUser; pUser++; cUsers--; cCreated++; } } if (NULL != pcCreated) *pcCreated = cCreated; // If requested, return number of users created. if (cUsers > 0) { // // Less than requested number of users were retrieved. // hResult = S_FALSE; while(cUsers > 0) { // // Set any un-filled array elements to NULL. // *pUser = NULL; pUser++; cUsers--; } } } catch(CAllocException& e) { hResult = E_OUTOFMEMORY; } if (FAILED(hResult)) { // // Release any user objects already created. // for (i = 0; i < cCreated; i++) { PDISKQUOTA_USER pu = *(pUser + i); if (NULL != pu) { pu->Release(); *(pUser + i) = NULL; } } *pcCreated = 0; } return hResult; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::Skip Description: Skips a specified number of users in the user enumeration. Arguments: cUsers - Number of users to skip. Returns: S_OK - Success. Skipped number of requested users. S_FALSE - End of enumeration encountered. Skipped less than cUsers records. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// HRESULT DiskQuotaUserEnum::Skip( DWORD cUsers ) { while(cUsers > 0 && SUCCEEDED(GetNextUser(NULL))) { cUsers--; } return cUsers == 0 ? S_OK : S_FALSE; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::Reset Description: Resets the enumerator object so that the next call to Next() starts enumerating at the beginning of the enumeration. Arguments: None. Returns: Always returns S_OK. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu 02/09/99 Changed so we just reset m_pbCurrent and BrianAu m_bRestartScan. */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP DiskQuotaUserEnum::Reset( VOID ) { m_pbCurrent = NULL; m_bRestartScan = TRUE; return S_OK; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserEnum::Clone Description: Creates a duplicate of the enumerator object and returns a pointer to the new object's IEnumDiskQuotaUser interface. Arguments: ppOut - Address of interface pointer variable to accept the pointer to the new object's IEnumDiskQuotaUser interface. Returns: NO_ERROR - Success. E_OUTOFMEMORY - Insufficient memory to create new enumerator. E_INVALIDARG - ppOut arg was NULL. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/22/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP DiskQuotaUserEnum::Clone( PENUM_DISKQUOTA_USERS *ppOut ) { HRESULT hResult = NO_ERROR; if (NULL == ppOut) return E_INVALIDARG; try { DiskQuotaUserEnum *pUserEnum = new DiskQuotaUserEnum( m_pQuotaController, m_pSidNameResolver, m_pFSObject); hResult = pUserEnum->Initialize(*this); if (SUCCEEDED(hResult)) { hResult = pUserEnum->QueryInterface(IID_IEnumDiskQuotaUsers, (LPVOID *)ppOut); } if (FAILED(hResult)) { // // Either Initialize or QueryInterface failed. // delete pUserEnum; pUserEnum = NULL; } } catch(CAllocException& e) { hResult = E_OUTOFMEMORY; } return hResult; } DiskQuotaUserCollection::DiskQuotaUserCollection( PDISKQUOTA_CONTROL pController, DWORD fNameResolution ) : m_cRef(0), m_pController(pController), m_pEnum(NULL), m_fNameResolution(fNameResolution) { if (NULL != m_pController) { m_pController->AddRef(); } } DiskQuotaUserCollection::~DiskQuotaUserCollection( VOID ) { if (NULL != m_pEnum) { m_pEnum->Release(); } if (NULL != m_pController) { m_pController->Release(); } } HRESULT DiskQuotaUserCollection::Initialize( VOID ) { HRESULT hr = S_FALSE; // Assume already initialized. if (NULL == m_pEnum) { if (NULL == m_pController) { hr = E_UNEXPECTED; } else { hr = m_pController->CreateEnumUsers(NULL, 0, m_fNameResolution, &m_pEnum); } } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserCollection::QueryInterface Description: Obtain pointer to IUnknown or IEnumDiskQuotaUserVARIANTs. Arguments: riid - Reference to requested interface ID. ppvOut - Address of interface pointer variable to accept the returned interface pointer. Returns: NO_ERROR - Success. E_NOINTERFACE - Requested interface not supported. E_INVALIDARG - ppvOut argument is NULL. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 08/22/97 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP DiskQuotaUserCollection::QueryInterface( REFIID riid, LPVOID *ppvOut ) { HRESULT hResult = E_NOINTERFACE; if (NULL == ppvOut) return E_INVALIDARG; *ppvOut = NULL; if (IID_IUnknown == riid || IID_IEnumVARIANT == riid) { // // Interface supported. // *ppvOut = this; ((LPUNKNOWN)*ppvOut)->AddRef(); hResult = NOERROR; } return hResult; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserCollection::AddRef Description: Increments object reference count. Arguments: None. Returns: New reference count value. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 08/22/97 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) DiskQuotaUserCollection::AddRef( VOID ) { ULONG ulReturn = m_cRef + 1; DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserCollection::AddRef, 0x%08X %d -> %d"), this, ulReturn - 1, ulReturn)); InterlockedIncrement(&m_cRef); return ulReturn; } /////////////////////////////////////////////////////////////////////////////// /* Function: DiskQuotaUserCollection::Release Description: Decrements object reference count. If count drops to 0, object is deleted. Arguments: None. Returns: New reference count value. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 08/22/97 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) DiskQuotaUserCollection::Release( VOID ) { ULONG ulReturn = m_cRef - 1; DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserCollection::Release, 0x%08X %d -> %d"), this, ulReturn + 1, ulReturn)); if (InterlockedDecrement(&m_cRef) == 0) { delete this; ulReturn = 0; } return ulReturn; } STDMETHODIMP DiskQuotaUserCollection::Next( DWORD cUsers, VARIANT *rgvar, DWORD *pcUsersFetched ) { HRESULT hr = E_UNEXPECTED; try { if (NULL == pcUsersFetched && 1 < cUsers) { // // If pcUsersFetched is NULL, cUsers must be 1. // hr = E_INVALIDARG; } else { DWORD cEnumerated = 0; PDISKQUOTA_USER *prgUsers = new PDISKQUOTA_USER[cUsers]; if (NULL != prgUsers) { hr = m_pEnum->Next(cUsers, prgUsers, &cEnumerated); if (SUCCEEDED(hr)) { for (INT i = 0; i < (INT)cEnumerated; i++) { VariantInit(&rgvar[i]); IDispatch *pIDisp = NULL; hr = prgUsers[i]->QueryInterface(IID_IDispatch, (LPVOID *)&pIDisp); if (SUCCEEDED(hr)) { V_VT(&rgvar[i]) = VT_DISPATCH; V_DISPATCH(&rgvar[i]) = pIDisp; } prgUsers[i]->Release(); } } delete[] prgUsers; } if (NULL != pcUsersFetched) { *pcUsersFetched = cEnumerated; } } } catch(CAllocException& e) { hr = E_OUTOFMEMORY; } return hr; } STDMETHODIMP DiskQuotaUserCollection::Skip( DWORD cUsers ) { return m_pEnum->Skip(cUsers); } STDMETHODIMP DiskQuotaUserCollection::Reset( void ) { return m_pEnum->Reset(); } STDMETHODIMP DiskQuotaUserCollection::Clone( IEnumVARIANT **ppEnum ) { HRESULT hr = E_FAIL; try { DiskQuotaUserCollection *pEnum = new DiskQuotaUserCollection(m_pController, m_fNameResolution); if (NULL != pEnum) { hr = pEnum->Initialize(); if (SUCCEEDED(hr)) { hr = pEnum->QueryInterface(IID_IEnumVARIANT, (LPVOID *)ppEnum); } else { delete pEnum; } } } catch(CAllocException& me) { hr = E_OUTOFMEMORY; } return hr; }