windows-nt/Source/XPSP1/NT/shell/osshell/dskquota/control/user.cpp
2020-09-26 16:20:57 +08:00

2042 lines
58 KiB
C++

///////////////////////////////////////////////////////////////////////////////
/* File: user.cpp
Description: Contains member function definitions for class DiskQuotaUser.
The DiskQuotaUser object represents a user's record in a volume's
quota information file. The holder of a user object's IDiskQuotaUser
interface can query and modify information for that user as security
privileges permit. A user object is obtained through a UserEnumerator
object (IEnumDiskQuotaUsers) which is itself obtained through
IDiskQuotaControl::CreateEnumUsers().
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
05/22/96 Initial creation. BrianAu
08/20/96 Added m_dwID member to DiskQuotaUser. BrianAu
09/05/96 Added exception handling. BrianAu
03/18/98 Replaced "domain", "name" and "full name" with BrianAu
"container", "logon name" and "display name" to
better match the actual contents. This was in
reponse to making the quota UI DS-aware. The
"logon name" is now a unique key as it contains
both account name and domain-like information.
i.e. "REDMOND\brianau" or "brianau@microsoft.com".
*/
///////////////////////////////////////////////////////////////////////////////
#include "pch.h" // PCH
#pragma hdrstop
#include <comutil.h>
#include "user.h"
#include "resource.h" // For IDS_NO_LIMIT.
//
// Verify that build is UNICODE.
//
#if !defined(UNICODE)
# error This module must be compiled UNICODE.
#endif
//
// Only one of these for all users. (static member).
//
LONG DiskQuotaUser::m_cUsersAlive = 0; // Cnt of users alive now.
ULONG DiskQuotaUser::m_ulNextUniqueId = 0;
HANDLE DiskQuotaUser::m_hMutex = NULL;
DWORD DiskQuotaUser::m_dwMutexWaitTimeout = 5000; // 5 seconds.
CArray<CString> DiskQuotaUser::m_ContainerNameCache;
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::DiskQuotaUser
Description: Constructor.
Arguments:
pFSObject - Pointer to "file system" object. It is through this pointer
that the object accesses the ntioapi functions. Caller must call
AddRef() for this pointer prior to calling Initialize().
Returns: Nothing.
Exceptions: OutOfMemory.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
05/22/96 Initial creation. BrianAu
09/05/96 Added domain name string. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
DiskQuotaUser::DiskQuotaUser(
FSObject *pFSObject
) : m_cRef(0),
m_ulUniqueId(InterlockedIncrement((LONG *)&m_ulNextUniqueId)),
m_pSid(NULL),
m_pszLogonName(NULL),
m_pszDisplayName(NULL),
m_pFSObject(pFSObject),
m_bNeedCacheUpdate(TRUE), // Data cache, not domain name cache.
m_iContainerName(-1),
m_dwAccountStatus(DISKQUOTA_USER_ACCOUNT_UNRESOLVED)
{
DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUser::DiskQuotaUser")));
DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
DBGASSERT((NULL != m_pFSObject));
m_llQuotaUsed = 0;
m_llQuotaThreshold = 0;
m_llQuotaLimit = 0;
//
// Initialize the domain name cache and class-wide locking mutex.
// These members are static so we only do it once.
//
InterlockedIncrement(&m_cUsersAlive);
if (NULL == DiskQuotaUser::m_hMutex)
{
DiskQuotaUser::m_hMutex = CreateMutex(NULL, FALSE, NULL);
m_ContainerNameCache.SetSize(25);
m_ContainerNameCache.SetGrow(25);
}
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::~DiskQuotaUser
Description: Destructor
Arguments: None.
Returns: Nothing.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
05/22/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
DiskQuotaUser::~DiskQuotaUser(
VOID
)
{
DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUser::~DiskQuotaUser")));
DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
Destroy();
if (InterlockedDecrement(&m_cUsersAlive) == 0)
{
//
// If active user count is 0, destroy the domain name cache and
// class-wide mutex.
//
DestroyContainerNameCache();
if (NULL != DiskQuotaUser::m_hMutex)
{
CloseHandle(DiskQuotaUser::m_hMutex);
DiskQuotaUser::m_hMutex = NULL;
}
}
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::QueryInterface
Description: Returns an interface pointer to the object's IUnknown or
IDiskQuotaUser interface. Only IID_IUnknown and
IID_IDiskQuotaUser are recognized. The object referenced by the
returned interface pointer is uninitialized. The recipient of the
pointer must call Initialize() before the object is usable.
Arguments:
riid - Reference to requested interface ID.
ppvOut - Address of interface pointer variable to accept interface ptr.
Returns:
NOERROR - Success.
E_NOINTERFACE - Requested interface not supported.
E_INVALIDARG - ppvOut argument was NULL.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
05/22/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
DiskQuotaUser::QueryInterface(
REFIID riid,
LPVOID *ppvOut
)
{
DBGTRACE((DM_USER, DL_MID, TEXT("DiskQuotaUser::QueryInterface")));
DBGPRINTIID(DM_USER, DL_MID, riid);
HRESULT hResult = E_NOINTERFACE;
if (NULL == ppvOut)
return E_INVALIDARG;
try
{
*ppvOut = NULL;
if (IID_IUnknown == riid ||
IID_IDiskQuotaUser == riid)
{
*ppvOut = static_cast<IDiskQuotaUser *>(this);
}
else if (IID_IDispatch == riid ||
IID_DIDiskQuotaUser == riid)
{
//
// Create a disk quota user "dispatch" object to handle all of
// the automation duties. This object takes a pointer to the real
// user object so that it can call the real object to do the real
// work. The reason we use a special "dispatch" object is so that
// we can maintain identical names for dispatch and vtable methods
// that perform the same function. Otherwise, if the DiskQuotaUser
// object implements both IDiskQuotaUser and DIDiskQuotaUser methods,
// we could not have two methods named Invalidate (one for vtable
// and one for dispatch.
//
DiskQuotaUserDisp *pUserDisp = new DiskQuotaUserDisp(static_cast<PDISKQUOTA_USER>(this));
*ppvOut = static_cast<DIDiskQuotaUser *>(pUserDisp);
}
if (NULL != *ppvOut)
{
((LPUNKNOWN)*ppvOut)->AddRef();
hResult = NOERROR;
}
}
catch(CAllocException& e)
{
*ppvOut = NULL;
hResult = E_OUTOFMEMORY;
}
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::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)
DiskQuotaUser::AddRef(
VOID
)
{
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUser::AddRef")));
DBGPRINT((DM_USER, DL_LOW, TEXT("\t0x%08X %d -> %d"),
this, m_cRef, m_cRef + 1));
ULONG ulReturn = m_cRef + 1;
InterlockedIncrement(&m_cRef);
return ulReturn;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::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)
DiskQuotaUser::Release(
VOID
)
{
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUser::Release")));
DBGPRINT((DM_USER, DL_LOW, TEXT("\t0x%08X %d -> %d"),
this, m_cRef, m_cRef - 1));
ULONG ulReturn = m_cRef - 1;
if (InterlockedDecrement(&m_cRef) == 0)
{
delete this;
ulReturn = 0;
}
return ulReturn;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::Initialize
Description: Initializes a new DiskQuotaUser object from a quota information
record read from a volume's quota information file.
Arguments:
pfqi [optional] - Pointer to a record of type FILE_QUOTA_INFORMATION. If
not NULL, the data from this record is used to initialize the new user
object.
Returns:
NOERROR - Success.
E_UNEXPECTED - SID buffer too small (shouldn't happen).
ERROR_INVALID_SID (hr) - SID in quota information is invalid.
ERROR_ACCESS_DENIED (hr) - Need READ access to quota device.
Exceptions: OutOfMemory.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
05/22/96 Initial creation. BrianAu
08/11/96 Added access control. BrianAu
09/05/96 Added exception handling. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
DiskQuotaUser::Initialize(
PFILE_QUOTA_INFORMATION pfqi
)
{
HRESULT hResult = NOERROR;
DBGASSERT((NULL != m_pFSObject));
//
// Need READ access to create a user object.
//
if (m_pFSObject->GrantedAccess(GENERIC_READ))
{
if (NULL != pfqi) // pfqi is optional.
{
if (0 < pfqi->SidLength && IsValidSid(&pfqi->Sid))
{
//
// Allocate space for SID structure.
//
m_pSid = (PSID) new BYTE[pfqi->SidLength];
//
// Copy SID structure to object.
//
if (CopySid(pfqi->SidLength, m_pSid, &pfqi->Sid))
{
//
// Initialize user's quota data values.
// If error copying SID, don't bother with these.
//
m_llQuotaUsed = pfqi->QuotaUsed.QuadPart;
m_llQuotaThreshold = pfqi->QuotaThreshold.QuadPart;
m_llQuotaLimit = pfqi->QuotaLimit.QuadPart;
}
else
{
//
// The only reason CopySid can fail is
// STATUS_BUFFER_TOO_SMALL. Since we allocated the buffer
// above, this should never fail.
//
DBGASSERT((FALSE));
hResult = E_UNEXPECTED; // Error copying SID.
}
}
else
{
DBGERROR((TEXT("DiskQuotaUser::Initialize - Invalid SID or Bad Sid Length (%d)"), pfqi->SidLength));
hResult = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
}
}
}
else
hResult = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::Destroy
Description: Destroys a user object by deleting its SID buffer and releasing
its FSObject pointer.
Arguments: None.
Returns: Nothing.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
05/22/96 Initial creation. BrianAu
09/05/96 Added domain name string. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID DiskQuotaUser::Destroy(
VOID
)
{
//
// Delete the SID buffer.
//
delete [] m_pSid;
m_pSid = NULL;
//
// Delete the logon name buffer.
//
delete[] m_pszLogonName;
m_pszLogonName = NULL;
//
// Delete the display name buffer.
//
delete[] m_pszDisplayName;
m_pszDisplayName = NULL;
if (NULL != m_pFSObject)
{
//
// Release hold on File System object.
//
m_pFSObject->Release();
m_pFSObject = NULL;
}
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::DestroyContainerNameCache
Description: Destroys the container name cache. Should only be called
when there are not more active user objects. The container name cache
is a static member of DiskQuotaUser.
Arguments: None.
Returns: Nothing.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
09/06/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID
DiskQuotaUser::DestroyContainerNameCache(
VOID
)
{
//
// Remove all container name strings from the cache. No need to lock
// the cache object before clearing it. It will handle the locking
// and unlocking.
//
m_ContainerNameCache.Clear();
}
//
// Return user object's unique ID.
//
STDMETHODIMP
DiskQuotaUser::GetID(
ULONG *pulID
)
{
*pulID = m_ulUniqueId;
return NOERROR;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::GetAccountStatus
Description: Retrieves the account name resolution status for the
user object.
Arguments:
pdwAccountStatus - Address of variable to recieve status. The following
values (see dskquota.h) can be returned in this variable:
DISKQUOTA_USER_ACCOUNT_RESOLVED
DISKQUOTA_USER_ACCOUNT_UNAVAILABLE
DISKQUOTA_USER_ACCOUNT_DELETED
DISKQUOTA_USER_ACCOUNT_INVALID
DISKQUOTA_USER_ACCOUNT_UNKNOWN
DISKQUOTA_USER_ACCOUNT_UNRESOLVED
Returns:
NOERROR - Success.
E_INVALIDARG - pdwAccountStatus arg is NULL.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
06/11/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
DiskQuotaUser::GetAccountStatus(
LPDWORD pdwAccountStatus
)
{
if (NULL == pdwAccountStatus)
return E_INVALIDARG;
*pdwAccountStatus = m_dwAccountStatus;
return NOERROR;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::SetName
Description: Sets the account names of the user object.
It is intended that the SidNameResolver object will call this member
when it has resolved a user's SID into an account name. This function
is not included in IDiskQuotaUser. Therefore, it is not for public
consumption.
Arguments:
pszContainer - Address of buffer containing container name string.
pszLogonName - Address of buffer containing user's logon name string.
pszDisplayName - Address of buffer containing user's display name string.
Returns:
NOERROR - Success.
E_INVALIDARG - pszName or pszDomain arg is NULL.
E_OUTOFMEMORY - Insufficient memory.
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
06/11/96 Initial creation. BrianAu
09/05/96 Added domain name string. BrianAu
09/22/96 Added full name string. BrianAu
12/10/96 Added class-scope user lock. BrianAu
05/18/97 Removed access token. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
DiskQuotaUser::SetName(
LPCWSTR pszContainer,
LPCWSTR pszLogonName,
LPCWSTR pszDisplayName
)
{
HRESULT hResult = NOERROR;
if (NULL == pszContainer || NULL == pszLogonName || NULL == pszDisplayName)
return E_INVALIDARG;
if (!DiskQuotaUser::Lock())
{
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
}
else
{
//
// Delete existing name buffer.
//
delete[] m_pszLogonName;
m_pszLogonName = NULL;
delete[] m_pszDisplayName;
m_pszDisplayName = NULL;
try
{
//
// Save name and full name in user object.
// Cache container string in container name cache and
// save cache index in user object.
//
INT index = -1;
m_pszLogonName = StringDup(pszLogonName);
m_pszDisplayName = StringDup(pszDisplayName);
CacheContainerName(pszContainer, &m_iContainerName);
}
catch(CAllocException& e)
{
hResult = E_OUTOFMEMORY;
}
DiskQuotaUser::ReleaseLock();
}
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::GetName
Description: Retrieves the domain and account names from the user object.
It is intended that the client of the user object will register
a callback (event sink) with a DiskQuotaControl object. When the
resolver has resolved the SID to an account name, the resolver will
set the user object's name string and the client will be notified.
The client then calls this method to get the user's name.
Arguments:
pszContainerBuffer - Address of destination buffer for container name string.
cchContainerBuffer - Size of container destination buffer in characters.
pszLogonNameBuffer - Address of destination buffer for logon name string.
cchLogonNameBuffer - Size of logon name destination buffer in characters.
pszDisplayNameBuffer - Address of destination buffer for display name string.
cchDisplayNameBuffer - Size of display name destination buffer in characters.
Returns:
NOERROR - Success.
ERROR_LOCK_FAILED (hr) - Failed to lock user object.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
06/11/96 Initial creation. BrianAu
09/05/96 Added domain name string. BrianAu
09/22/96 Added full name string. BrianAu
12/10/96 Added class-scope user lock. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
DiskQuotaUser::GetName(
LPWSTR pszContainerBuffer,
DWORD cchContainerBuffer,
LPWSTR pszLogonNameBuffer,
DWORD cchLogonNameBuffer,
LPWSTR pszDisplayNameBuffer,
DWORD cchDisplayNameBuffer
)
{
HRESULT hResult = NOERROR;
if (!DiskQuotaUser::Lock())
{
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
}
else
{
if (NULL != pszContainerBuffer)
{
if (-1 != m_iContainerName)
{
GetCachedContainerName(m_iContainerName,
pszContainerBuffer,
cchContainerBuffer);
}
else
lstrcpyn(pszContainerBuffer, TEXT(""), cchContainerBuffer);
}
if (NULL != pszLogonNameBuffer)
{
lstrcpyn(pszLogonNameBuffer,
(NULL != m_pszLogonName) ? m_pszLogonName : TEXT(""),
cchLogonNameBuffer);
}
if (NULL != pszDisplayNameBuffer)
{
lstrcpyn(pszDisplayNameBuffer,
(NULL != m_pszDisplayName) ? m_pszDisplayName : TEXT(""),
cchDisplayNameBuffer);
}
DiskQuotaUser::ReleaseLock();
}
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::GetSidLength
Description: Retrieves the length of the user's SID in bytes.
Arguments:
pcbSid - Address of DWORD to accept SID length value.
Returns:
NOERROR - Success.
E_INVALIDARG - pcbSid argument is NULL.
ERROR_INVALID_SID (hr) - Invalid SID.
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
05/22/96 Initial creation. BrianAu
12/10/96 Added class-scope user lock. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
DiskQuotaUser::GetSidLength(
LPDWORD pcbSid
)
{
HRESULT hResult = NOERROR;
if (NULL == pcbSid)
return E_INVALIDARG;
if (!DiskQuotaUser::Lock())
{
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
}
else
{
if (NULL != m_pSid && IsValidSid(m_pSid))
{
*pcbSid = GetLengthSid(m_pSid);
}
else
hResult = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
DiskQuotaUser::ReleaseLock();
}
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::GetSid
Description: Retrieves the user's SID to a caller-provided buffer.
The caller should call GetSidLength() to obtain the required buffer
size before calling GetSid().
Arguments:
pSid - Address of destination buffer for SID. This argument type must
be PBYTE to work with the MIDL compiler. Since PSID is really just
LPVOID and since MIDL doesn't like pointers to void, we have to
use something other than PSID.
cbSidBuf - Size of destination buffer in bytes.
Returns:
NOERROR - Success.
E_INVALIDARG - pSID is NULL.
ERROR_INVALID_SID (hr) - User's SID is invalid.
ERROR_INSUFFICIENT_BUFFER (hr) - Insufficient dest buffer size.
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
05/22/96 Initial creation. BrianAu
12/10/96 Added class-scope user lock. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
DiskQuotaUser::GetSid(
PBYTE pSid,
DWORD cbSidBuf
)
{
HRESULT hResult = NOERROR;
if (NULL == pSid)
return E_INVALIDARG;
if (!DiskQuotaUser::Lock())
{
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
}
else
{
if (NULL != m_pSid && IsValidSid(m_pSid))
{
if (!CopySid(cbSidBuf, (PSID)pSid, m_pSid))
{
//
// The only reason CopySid can fail is STATUS_BUFFER_TOO_SMALL.
// Force status code to INSUFFICIENT_BUFFER.
//
DBGERROR((TEXT("ERROR in DiskQuotaUser::GetSid. CopySid() failed. Result = 0x%08X."),
GetLastError()));
hResult = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
}
else
{
DBGERROR((TEXT("ERROR in DiskQuotaUser::GetSid. Invalid SID.")));
hResult = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
}
DiskQuotaUser::ReleaseLock();
}
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::RefreshCachedInfo
Description: Refreshes a user object's cached quota information from the
volume's quota information file.
Arguments: None.
Returns:
NOERROR - Success.
ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
E_FAIL - Unexpected NTIOAPI error.
This function can propagate errors from the NTIOAPI system. A few
known ones are mapped to HResults in fsobject.cpp (see HResultFromNtStatus).
All others are mapped to E_FAIL.
Exceptions: OutOfMemory.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
06/05/96 Initial creation. BrianAu
09/05/96 Added exception handling. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
DiskQuotaUser::RefreshCachedInfo(
VOID
)
{
HRESULT hResult = NOERROR;
DWORD cbBuffer = FILE_QUOTA_INFORMATION_MAX_LEN;
PSIDLIST pSidList = NULL;
DWORD cbSidList = 0;
PSID pSids[] = { m_pSid, NULL };
PBYTE pbBuffer = NULL;
try
{
pbBuffer = new BYTE[cbBuffer];
//
// This can throw OutOfMemory.
//
hResult = CreateSidList(pSids, 0, &pSidList, &cbSidList);
if (SUCCEEDED(hResult))
{
hResult = m_pFSObject->QueryUserQuotaInformation(
pbBuffer, // Buffer to receive data.
cbBuffer, // Buffer size in bytes.
TRUE, // Single entry requested.
pSidList, // Sid.
cbSidList, // Length of Sid.
NULL, // Starting Sid
TRUE); // Start search at first user.
if (SUCCEEDED(hResult) || ERROR_NO_MORE_ITEMS == HRESULT_CODE(hResult))
{
PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)pbBuffer;
m_llQuotaUsed = pfqi->QuotaUsed.QuadPart;
m_llQuotaThreshold = pfqi->QuotaThreshold.QuadPart;
m_llQuotaLimit = pfqi->QuotaLimit.QuadPart;
m_bNeedCacheUpdate = FALSE;
//
// Don't return ERROR_NO_MORE_ITEMS to caller.
// They won't care.
//
hResult = NOERROR;
}
delete[] pSidList;
}
delete[] pbBuffer;
}
catch(CAllocException& e)
{
hResult = E_OUTOFMEMORY;
delete[] pbBuffer;
delete[] pSidList;
}
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::WriteCachedInfo
Description: Writes quota information cached in a user object to the
volume's quota information file.
Arguments: None.
Returns:
NOERROR - Success.
ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
E_FAIL - Some other NTIOAPI error.
E_UNEXPECTED - CopySid failed.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
07/31/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
DiskQuotaUser::WriteCachedInfo(
VOID
)
{
HRESULT hResult = NOERROR;
BYTE Buffer[FILE_QUOTA_INFORMATION_MAX_LEN];
PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)Buffer;
pfqi->NextEntryOffset = 0;
pfqi->SidLength = GetLengthSid(m_pSid);
pfqi->QuotaUsed.QuadPart = m_llQuotaUsed;
pfqi->QuotaLimit.QuadPart = m_llQuotaLimit;
pfqi->QuotaThreshold.QuadPart = m_llQuotaThreshold;
if (CopySid(pfqi->SidLength, &(pfqi->Sid), m_pSid))
hResult = m_pFSObject->SetUserQuotaInformation(pfqi, sizeof(Buffer));
else
hResult = E_UNEXPECTED;
if (FAILED(hResult))
{
//
// Something failed.
// Invalidate cached information so next request reads from disk.
//
Invalidate();
}
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::GetQuotaInformation
Description: Retrieves a user's quota limit, threshold and used quota
values in a single method. Since the user interface is marshaled
across thread boundaries, this can be a big performance improvement
if you want all three values.
Arguments:
pbInfo - Address of destination buffer. Should be sized for structure
DISKQUOTA_USER_INFORMATION.
cbInfo - Number of bytes in destination buffer. Should be
sizeof(DISKQUOTA_USER_INFORMATION).
Returns:
NOERROR - Success.
E_INVALIDARG - pbInfo argument is NULL.
E_OUTOFMEMORY - Insufficient memory.
ERROR_INSUFFICIENT_BUFFER (hr) - Destination buffer is too small.
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
07/31/96 Initial creation. BrianAu
12/10/96 Added class-scope user lock. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
DiskQuotaUser::GetQuotaInformation(
LPVOID pbInfo,
DWORD cbInfo
)
{
HRESULT hResult = NOERROR;
if (NULL == pbInfo)
return E_INVALIDARG;
try
{
if (cbInfo < sizeof(DISKQUOTA_USER_INFORMATION))
{
hResult = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
else
{
if (!DiskQuotaUser::Lock())
{
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
}
else
{
//
// Refresh cached info from disk if needed.
// Can throw OutOfMemory.
//
if (m_bNeedCacheUpdate)
hResult = RefreshCachedInfo();
if (SUCCEEDED(hResult))
{
PDISKQUOTA_USER_INFORMATION pui = (PDISKQUOTA_USER_INFORMATION)pbInfo;
pui->QuotaUsed = m_llQuotaUsed;
pui->QuotaThreshold = m_llQuotaThreshold;
pui->QuotaLimit = m_llQuotaLimit;
}
DiskQuotaUser::ReleaseLock();
}
}
}
catch(CAllocException& e)
{
hResult = E_OUTOFMEMORY;
}
return hResult;
}
STDMETHODIMP
DiskQuotaUser::GetQuotaUsedText(
LPWSTR pszText,
DWORD cchText
)
{
if (NULL == pszText)
return E_INVALIDARG;
LONGLONG llValue;
HRESULT hr = GetQuotaUsed(&llValue);
if (SUCCEEDED(hr))
{
if (NOLIMIT == llValue)
{
LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
}
else
{
XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
}
}
return hr;
}
STDMETHODIMP
DiskQuotaUser::GetQuotaThresholdText(
LPWSTR pszText,
DWORD cchText
)
{
if (NULL == pszText)
return E_INVALIDARG;
LONGLONG llValue;
HRESULT hr = GetQuotaThreshold(&llValue);
if (SUCCEEDED(hr))
{
if (NOLIMIT == llValue)
{
LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
}
else
{
XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
}
}
return hr;
}
STDMETHODIMP
DiskQuotaUser::GetQuotaLimitText(
LPWSTR pszText,
DWORD cchText
)
{
if (NULL == pszText)
return E_INVALIDARG;
LONGLONG llValue;
HRESULT hr = GetQuotaLimit(&llValue);
if (SUCCEEDED(hr))
{
if (NOLIMIT == llValue)
{
LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
}
else
{
XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
}
}
return hr;
}
STDMETHODIMP
DiskQuotaUser::SetQuotaThreshold(
LONGLONG llThreshold,
BOOL bWriteThrough
)
{
if (MARK4DEL > llThreshold)
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
return SetLargeIntegerQuotaItem(&m_llQuotaThreshold,
llThreshold,
bWriteThrough);
}
STDMETHODIMP
DiskQuotaUser::SetQuotaLimit(
LONGLONG llLimit,
BOOL bWriteThrough
)
{
if (MARK4DEL > llLimit)
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
return SetLargeIntegerQuotaItem(&m_llQuotaLimit,
llLimit,
bWriteThrough);
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::GetLargeIntegerQuotaItem
Description: Retrieves a single quota information item (used, limit,
threshold) for the user. If the cached data is invalid, fresh data is
read in from disk.
Arguments:
pllItem - Address of cached member item.
pllValueOut - Address of LONGLONG to receive item's value.
Returns:
NOERROR - Success.
E_INVALIDARG - Either pdwLowPart or pdwHighPart arg was NULL.
E_OUTOFMEMORY - Insufficient memory.
E_UNEXPECTED - Unexpected exception.
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
06/05/96 Initial creation. BrianAu
12/10/96 Added class-scope user lock. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
DiskQuotaUser::GetLargeIntegerQuotaItem(
PLONGLONG pllItem,
PLONGLONG pllValueOut
)
{
HRESULT hResult = NOERROR;
DBGASSERT((NULL != pllItem));
if (NULL == pllItem || NULL == pllValueOut)
return E_INVALIDARG;
if (!DiskQuotaUser::Lock())
{
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
}
else
{
if (m_bNeedCacheUpdate)
try
{
hResult = RefreshCachedInfo();
}
catch(CAllocException& e)
{
hResult = E_OUTOFMEMORY;
}
if (SUCCEEDED(hResult))
{
*pllValueOut = *pllItem;
}
DiskQuotaUser::ReleaseLock();
}
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::SetLargeIntegerQuotaItem
Description: Sets the quota information for a given quota item (limit or
threshold). If the bWriteThrough argument is TRUE, the information is
also written through to the volume's quota file. Otherwise, it is
just cached in the user object.
Arguments:
pllItem - Address of cached member item.
llValue - LONGLONG value to assign to member item.
bWriteThrough - TRUE = Write data through to disk.
FALSE = Only cache data in user object.
Returns:
NOERROR - Success.
ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
E_FAIL - Some other NTIOAPI error.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/06/96 Initial creation. BrianAu
12/10/96 Added class-scope user lock. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
DiskQuotaUser::SetLargeIntegerQuotaItem(
PLONGLONG pllItem,
LONGLONG llValue,
BOOL bWriteThrough)
{
DBGASSERT((NULL != pllItem));
HRESULT hResult = NOERROR;
if (!DiskQuotaUser::Lock())
{
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
}
else
{
*pllItem = llValue;
if (bWriteThrough)
hResult = WriteCachedInfo();
DiskQuotaUser::ReleaseLock();
}
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::CacheContainerName
Description: Class DiskQuotaUser maintains a static member that is
a cache of account container names. It is likely that there will be
few distinct container names in use on a volume. Therefore, there's
no need to store a container name for each user object. We cache the
names and store only an index into the cache in each user object.
This method adds a name to the cache and returns the index of the
name in the cache. If the name already exists in the cache,
it is not added.
Arguments:
pszContainer - Address of container name string to add to cache.
pCacheIndex [optional] - Address of integer variable to receive the
cache index of the container name string. May be NULL.
Returns:
S_OK - Success.
S_FALSE - Name already in cache.
E_FAIL - No cache object.
Exceptions: OutOfMemory.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
09/05/09 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
DiskQuotaUser::CacheContainerName(
LPCTSTR pszContainer,
INT *pCacheIndex
)
{
DBGASSERT((NULL != pszContainer));
HRESULT hResult = S_OK;
INT iCacheIndex = -1;
UINT cItems = 0;
m_ContainerNameCache.Lock();
cItems = m_ContainerNameCache.Count();
for (UINT i = 0; i < cItems; i++)
{
//
// See if the name is already in the cache.
//
if (0 == m_ContainerNameCache[i].Compare(pszContainer))
{
iCacheIndex = i;
hResult = S_FALSE; // Already cached.
break;
}
}
if (S_OK == hResult)
{
//
// Not in the cache. Add it.
//
try
{
m_ContainerNameCache.Append(CString(pszContainer));
iCacheIndex = m_ContainerNameCache.UpperBound();
}
catch(CAllocException& e)
{
hResult = E_OUTOFMEMORY;
}
}
m_ContainerNameCache.ReleaseLock();
if (NULL != pCacheIndex)
*pCacheIndex = iCacheIndex;
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::GetCachedContainerName
Description: Retrieves an account container name string from the
container name cache.
Arguments:
iCacheIndex - User's index in domain name cache.
pszContainer - Destination buffer to receive container name string.
cchContainer - Number of characters in destination buffer.
Returns:
NOERROR - Success.
E_UNEXPECTED - No name at index iCacheIndex. Returns "" as name.
E_FAIL - No domain name cache object.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
09/05/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
DiskQuotaUser::GetCachedContainerName(
INT iCacheIndex,
LPTSTR pszContainer,
UINT cchContainer
)
{
DBGASSERT((NULL != pszContainer));
DBGASSERT((-1 != iCacheIndex));
HRESULT hResult = NOERROR;
m_ContainerNameCache.Lock();
DBGASSERT((iCacheIndex < m_ContainerNameCache.Count()));
lstrcpyn(pszContainer, m_ContainerNameCache[iCacheIndex], cchContainer);
m_ContainerNameCache.ReleaseLock();
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::Lock
Description: Call this to obtain an exclusive lock to the user object.
In actuality, there is only one lock for all user objects so you're
really getting an exclusive lock to all users. Since there can be
a high number of users, it was decided to use a single class-wide
lock instead of a unique lock for each user object.
Arguments: None.
Returns:
TRUE = Obtained exclusive lock.
FALSE = Couldn't get a lock. Either mutex hasn't been created or
the mutex wait timeout expired, or the wait operation failed.
Either way, we couldn't get the lock.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
12/10/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
DiskQuotaUser::Lock(
VOID
)
{
BOOL bResult = FALSE;
if (NULL != DiskQuotaUser::m_hMutex)
{
DWORD dwWaitResult = WaitForSingleObject(DiskQuotaUser::m_hMutex,
DiskQuotaUser::m_dwMutexWaitTimeout);
bResult = (WAIT_OBJECT_0 == dwWaitResult);
}
return bResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::ReleaseLock
Description: Call this to release a lock obtained with DiskQuotaUser::Lock.
Arguments: None.
Returns: Nothing.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
12/10/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID
DiskQuotaUser::ReleaseLock(
VOID
)
{
if (NULL != DiskQuotaUser::m_hMutex)
{
ReleaseMutex(DiskQuotaUser::m_hMutex);
}
}
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::SetAccountStatus
Description: Stores the status of the user's account in the user object.
User accounts may be "unresolved", "unavailable", "resolved",
"deleted", "invalid" or "unknown".
These states correspond to the values obtained
through LookupAccountSid.
Arguments:
dwStatus - DISKQUOTA_USER_ACCOUNT_UNRESOLVED
DISKQUOTA_USER_ACCOUNT_UNAVAILABLE
DISKQUOTA_USER_ACCOUNT_RESOLVED
DISKQUOTA_USER_ACCOUNT_DELETED
DISKQUOTA_USER_ACCOUNT_UNKNOWN
DISKQUOTA_USER_ACCOUNT_INVALID
Returns: Nothing.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
05/18/97 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID
DiskQuotaUser::SetAccountStatus(
DWORD dwStatus
)
{
DBGASSERT((DISKQUOTA_USER_ACCOUNT_UNRESOLVED == dwStatus ||
DISKQUOTA_USER_ACCOUNT_UNAVAILABLE == dwStatus ||
DISKQUOTA_USER_ACCOUNT_RESOLVED == dwStatus ||
DISKQUOTA_USER_ACCOUNT_DELETED == dwStatus ||
DISKQUOTA_USER_ACCOUNT_INVALID == dwStatus ||
DISKQUOTA_USER_ACCOUNT_UNKNOWN == dwStatus));
m_dwAccountStatus = dwStatus;
}
//
// The following functions implement the DiskQuotaUser "dispatch" object that
// is created to handle OLE automation duties for the DiskQuotaUser object.
// The functions are all fairly basic and require little explanation.
// Therefore, I'll spare you the function headers. In most cases,
// the property and method functions call directly through to their
// corresponding functions in class DiskQuotaUser.
//
DiskQuotaUserDisp::DiskQuotaUserDisp(
PDISKQUOTA_USER pUser
) : m_cRef(0),
m_pUser(pUser)
{
DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserDisp::DiskQuotaUserDisp")));
DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
if (NULL != m_pUser)
{
m_pUser->AddRef();
}
m_Dispatch.Initialize(static_cast<IDispatch *>(this),
LIBID_DiskQuotaTypeLibrary,
IID_DIDiskQuotaUser,
L"DSKQUOTA.DLL");
}
DiskQuotaUserDisp::~DiskQuotaUserDisp(
VOID
)
{
DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserDisp::~DiskQuotaUserDisp")));
DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
if (NULL != m_pUser)
{
m_pUser->Release();
}
}
STDMETHODIMP
DiskQuotaUserDisp::QueryInterface(
REFIID riid,
LPVOID *ppvOut
)
{
DBGTRACE((DM_USER, DL_MID, TEXT("DiskQuotaUserDisp::QueryInterface")));
DBGPRINTIID(DM_USER, DL_MID, riid);
HRESULT hResult = E_NOINTERFACE;
if (NULL == ppvOut)
return E_INVALIDARG;
*ppvOut = NULL;
if (IID_IUnknown == riid)
{
*ppvOut = this;
}
else if (IID_IDispatch == riid)
{
*ppvOut = static_cast<IDispatch *>(this);
}
else if (IID_DIDiskQuotaUser == riid)
{
*ppvOut = static_cast<DIDiskQuotaUser *>(this);
}
else if (IID_IDiskQuotaUser == riid)
{
//
// Return the quota user's vtable interface.
// This allows code to "typecast" (COM-style) between
// the dispatch interface and vtable interface.
//
return m_pUser->QueryInterface(riid, ppvOut);
}
if (NULL != *ppvOut)
{
((LPUNKNOWN)*ppvOut)->AddRef();
hResult = NOERROR;
}
return hResult;
}
STDMETHODIMP_(ULONG)
DiskQuotaUserDisp::AddRef(
VOID
)
{
ULONG ulReturn = m_cRef + 1;
DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserDisp::AddRef, 0x%08X %d -> %d"),
this, ulReturn - 1, ulReturn));
InterlockedIncrement(&m_cRef);
return ulReturn;
}
STDMETHODIMP_(ULONG)
DiskQuotaUserDisp::Release(
VOID
)
{
ULONG ulReturn = m_cRef - 1;
DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserDisp::Release, 0x%08X %d -> %d"),
this, ulReturn + 1, ulReturn));
if (InterlockedDecrement(&m_cRef) == 0)
{
delete this;
ulReturn = 0;
}
return ulReturn;
}
//
// IDispatch::GetIDsOfNames
//
STDMETHODIMP
DiskQuotaUserDisp::GetIDsOfNames(
REFIID riid,
OLECHAR **rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgDispId
)
{
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::GetIDsOfNames")));
//
// Let our dispatch object handle this.
//
return m_Dispatch.GetIDsOfNames(riid,
rgszNames,
cNames,
lcid,
rgDispId);
}
//
// IDispatch::GetTypeInfo
//
STDMETHODIMP
DiskQuotaUserDisp::GetTypeInfo(
UINT iTInfo,
LCID lcid,
ITypeInfo **ppTypeInfo
)
{
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::GetTypeInfo")));
//
// Let our dispatch object handle this.
//
return m_Dispatch.GetTypeInfo(iTInfo, lcid, ppTypeInfo);
}
//
// IDispatch::GetTypeInfoCount
//
STDMETHODIMP
DiskQuotaUserDisp::GetTypeInfoCount(
UINT *pctinfo
)
{
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::GetTypeInfoCount")));
//
// Let our dispatch object handle this.
//
return m_Dispatch.GetTypeInfoCount(pctinfo);
}
//
// IDispatch::Invoke
//
STDMETHODIMP
DiskQuotaUserDisp::Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
UINT *puArgErr
)
{
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::Invoke")));
DBGPRINT((DM_USER, DL_LOW, TEXT("DispId = %d"), dispIdMember));
DBGPRINTIID(DM_USER, DL_LOW, riid);
//
// Let our dispatch object handle this.
//
return m_Dispatch.Invoke(dispIdMember,
riid,
lcid,
wFlags,
pDispParams,
pVarResult,
pExcepInfo,
puArgErr);
}
//
// Return user object's unique ID.
//
STDMETHODIMP
DiskQuotaUserDisp::get_ID(
long *pID
)
{
return m_pUser->GetID((ULONG *)pID);
}
STDMETHODIMP
DiskQuotaUserDisp::get_AccountContainerName(
BSTR *pContainerName
)
{
TCHAR szName[MAX_DOMAIN] = { TEXT('\0') };
HRESULT hr = m_pUser->GetName(szName, ARRAYSIZE(szName),
NULL, 0,
NULL, 0);
if (SUCCEEDED(hr))
{
*pContainerName = SysAllocString(szName);
if (NULL == *pContainerName)
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
STDMETHODIMP
DiskQuotaUserDisp::get_LogonName(
BSTR *pLogonName
)
{
TCHAR szName[MAX_USERNAME] = { TEXT('\0') };
HRESULT hr = m_pUser->GetName(NULL, 0,
szName, ARRAYSIZE(szName),
NULL, 0);
if (SUCCEEDED(hr))
{
*pLogonName = SysAllocString(szName);
if (NULL == *pLogonName)
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
STDMETHODIMP
DiskQuotaUserDisp::get_DisplayName(
BSTR *pDisplayName
)
{
TCHAR szName[MAX_FULL_USERNAME] = { TEXT('\0') };
HRESULT hr = m_pUser->GetName(NULL, 0,
NULL, 0,
szName, ARRAYSIZE(szName));
if (SUCCEEDED(hr))
{
*pDisplayName = SysAllocString(szName);
if (NULL == *pDisplayName)
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
STDMETHODIMP
DiskQuotaUserDisp::get_QuotaThreshold(
double *pThreshold
)
{
LONGLONG llValue;
HRESULT hr = m_pUser->GetQuotaThreshold(&llValue);
if (SUCCEEDED(hr))
*pThreshold = (double)llValue;
return hr;
}
STDMETHODIMP
DiskQuotaUserDisp::put_QuotaThreshold(
double Threshold
)
{
if (MAXLONGLONG < Threshold)
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
return m_pUser->SetQuotaThreshold((LONGLONG)Threshold, TRUE);
}
STDMETHODIMP
DiskQuotaUserDisp::get_QuotaThresholdText(
BSTR *pThresholdText
)
{
TCHAR szValue[40];
HRESULT hr = m_pUser->GetQuotaThresholdText(szValue, ARRAYSIZE(szValue));
if (SUCCEEDED(hr))
{
*pThresholdText = SysAllocString(szValue);
if (NULL == *pThresholdText)
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
STDMETHODIMP
DiskQuotaUserDisp::get_QuotaLimit(
double *pQuotaLimit
)
{
LONGLONG llValue;
HRESULT hr = m_pUser->GetQuotaLimit(&llValue);
if (SUCCEEDED(hr))
*pQuotaLimit = (double)llValue;
return hr;
}
STDMETHODIMP
DiskQuotaUserDisp::put_QuotaLimit(
double Limit
)
{
if (MAXLONGLONG < Limit)
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
return m_pUser->SetQuotaLimit((LONGLONG)Limit, TRUE);
}
STDMETHODIMP
DiskQuotaUserDisp::get_QuotaLimitText(
BSTR *pLimitText
)
{
TCHAR szValue[40];
HRESULT hr = m_pUser->GetQuotaLimitText(szValue, ARRAYSIZE(szValue));
if (SUCCEEDED(hr))
{
*pLimitText = SysAllocString(szValue);
if (NULL == *pLimitText)
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
STDMETHODIMP
DiskQuotaUserDisp::get_QuotaUsed(
double *pUsed
)
{
LONGLONG llValue;
HRESULT hr = m_pUser->GetQuotaUsed(&llValue);
if (SUCCEEDED(hr))
*pUsed = (double)llValue;
return hr;
}
STDMETHODIMP
DiskQuotaUserDisp::get_QuotaUsedText(
BSTR *pUsedText
)
{
TCHAR szValue[40];
HRESULT hr = m_pUser->GetQuotaUsedText(szValue, ARRAYSIZE(szValue));
if (SUCCEEDED(hr))
{
*pUsedText = SysAllocString(szValue);
if (NULL == *pUsedText)
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
STDMETHODIMP
DiskQuotaUserDisp::get_AccountStatus(
AccountStatusConstants *pStatus
)
{
DWORD dwStatus;
HRESULT hr = m_pUser->GetAccountStatus(&dwStatus);
if (SUCCEEDED(hr))
{
*pStatus = (AccountStatusConstants)dwStatus;
}
return hr;
}
//
// Methods.
//
STDMETHODIMP
DiskQuotaUserDisp::Invalidate(
void
)
{
return m_pUser->Invalidate();
}
#ifdef NEVER
// ----------------------------------------------------------------------------
// OBSOLETE CODE
// ----------------------------------------------------------------------------
//
// I originally provided the GetSidString code in the IDiskQuotaUser interface.
// It was useful during development but I decided that it would be
// relatively useless to most users of the interface. If they want to
// format the SID as a string, they can learn about it on MSDN. That's
// where I got the original code (See in dskquota\common\utils.cpp).
// I've left it here in case a need is ever identified.
//
// [brianau - 08/05/97]
//
///////////////////////////////////////////////////////////////////////////////
/* Function: DiskQuotaUser::GetSidString
Description: Retrieves the account SID from the user object in character
format.
Arguments:
pszBuffer - Address of destination buffer for account SID string.
cchBuffer - Size of destination buffer in characters.
Returns:
NOERROR - Success.
E_INVALIDARG - pszBuffer arg is NULL.
ERROR_INSUFFICIENT_BUFFER (hr) - Caller's buffer is too small.
ERROR_LOCK_FAILED (hr) - Failed to lock user object.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
07/23/96 Initial creation. BrianAu
12/10/96 Added class-scope user lock. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
DiskQuotaUser::GetSidString(
LPWSTR pszBuffer,
DWORD cchBuffer
)
{
HRESULT hResult = NOERROR;
if (NULL == pszBuffer)
return E_INVALIDARG;
if (!DiskQuotaUser::Lock())
{
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
}
else
{
DWORD cchSid = cchBuffer;
if (!SidToString(m_pSid, pszBuffer, &cchSid))
hResult = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
DiskQuotaUser::ReleaseLock();
}
return hResult;
}
#endif // NEVER