Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Reading quota information on an NTFS volume

0.00/5 (No votes)
23 Jun 2005 1  
A class wrapping most of the functionality of the IDiskQuotaControl interface.

Introduction

As I was perusing the MSDN for another unrelated reason, I stumbled across the IDiskQuotaControl interface. While it sounded interesting, my lack of COM experience forced me to press on with my original goal. Several months later I decided to explore the IDiskQuotaControl interface again. What I discovered along the way was very helpful, at least to me.

Raw interface pointers

I started out just including the dskquota.h header file. To make use of the interfaces and properties in this file, I used a code similar to:

IDiskQuotaControl   *pDiskQuotaControl;
IEnumDiskQuotaUsers *pEnumDiskQuotaUsers;
HRESULT             hr;
    
hr = CoCreateInstance(CLSID_DiskQuotaControl,
                      NULL,
                      CLSCTX_INPROC_SERVER,
                      IID_IDiskQuotaControl,
                      (PVOID *) &pDiskQuotaControl);
if (SUCCEEDED(hr))
{
    hr = pDiskQuotaControl->Initialize(_bstr_t("c:\\"), TRUE);
    if (SUCCEEDED(hr))
    {
        hr = pDiskQuotaControl->CreateEnumUsers(NULL, 
                      0, DISKQUOTA_USERNAME_RESOLVE_SYNC,
                      &pEnumDiskQuotaUsers);
        if (SUCCEEDED(hr))
        {
            ...
            pEnumDiskQuotaUsers->Release();
        }
    }

    pDiskQuotaControl->Release();
}

Cool, I thought. I wonder if I could make that CoCreateInstance() call a bit cleaner. At this point I remembered reading about smart pointers from a COM project I worked on several years ago. Looking back at that code as a starting point, I put the necessary changes in place.

Smart pointers

First I imported the disk quota type library contained within dskquota.dll:

#import <dskquota.dll> rename("DiskQuotaTypeLibrary", "DQ")

I renamed the namespace simply because it was so long. Now I was ready to change the raw interface pointers to smart pointers. I started out with something simple:

DQ::DIDiskQuotaControlPtr ptrDiskQuotaControl;

HRESULT hr = 
   ptrDiskQuotaControl.CreateInstance(__uuidof(DQ::DiskQuotaControl));
if (SUCCEEDED(hr))
{
    hr = ptrDiskQuotaControl->Initialize(_bstr_t("c:\\"), TRUE);
    if (NOERROR == hr)
    {
        ...
    }
}

Wow, this works too. I went on and tried to use the CreateEnumUsers() method. That's when things went downhill. First, that method did not exist. Second, the fourth parameter was a IEnumDiskQuotaUsers smart pointer which also did not exist. Now I was really stumped, especially since the MSDN documentation indicated otherwise. I poked at it a while longer before asking for help. I was told that it looks like a type library which only has dispatch interfaces, but that I could still use smart pointers if I wanted. The only changes I'd need were to remove the #import statement, and add my own types using the _COM_SMARTPTR_TYPEDEF() macro:

_COM_SMARTPTR_TYPEDEF(IDiskQuotaControl, IID_IDiskQuotaControl);
_COM_SMARTPTR_TYPEDEF(IEnumDiskQuotaUsers, IID_IEnumDiskQuotaUsers);
_COM_SMARTPTR_TYPEDEF(IDiskQuotaUser, IID_IDiskQuotaUser);

Now I was making some progress! I could create an instance of the IDiskQuotaControl interface, initialize it, and call the CreateEnumUsers() method just like I had when using the raw interface pointers:

IEnumDiskQuotaUsersPtr ptrEnumDQUsers;
hr = ptrDiskQuotaControl->CreateEnumUsers(NULL, 
                                          0,
                                          DISKQUOTA_USERNAME_RESOLVE_SYNC,
                                          &ptrEnumDQUsers);
if (NOERROR == hr)
{
    IDiskQuotaUserPtr ptrDQUser;
    
    hr = ptrEnumDQUsers->Next(1, &ptrDQUser, NULL);
    if (NOERROR == hr)
    {
        ...
    }
}

Just to ensure that I was indeed able to enumerate through each of the registered users, I used:

TCHAR szLogonName[128];
      szDisplayname[128];

while (ptrEnumDQUsers->Next(1, &ptrDQUser, NULL) == NOERROR)
{
    hr = ptrDQUser->GetName(NULL, 
                            0, 
                            szLogonName,
                            sizeof(szLogonName), 
                            szDisplayName,
                            sizeof(szDisplayName));

    if (NOERROR == hr)
        TRACE(_T("Logon name = ]%s[\n"), szLogonName);
}

Yep, it worked! My next goal was to somehow wrap all this up into a useful class or two to hide some of the COM-ness from it.

The CDiskQuotaControl class

This class is a wrapper around most of the IDiskQuotaControl and IEnumDiskQuotaUsers interfaces. Most of the text comes straight from the MSDN.

CDiskQuotaControl Constructs a CDiskQuotaControl object.
Initialize Initializes a new CDiskQuotaControl object by opening the NTFS volume in read-only mode. The return value indicates whether the volume supports NTFS disk quotas and whether the caller has sufficient access rights.
EnumFirstUser Creates an enumerator object for enumerating quota users on the volume, and then retrieves the first user in the enumeration sequence. The user's account information is resolved synchronously.
EnumNextUser Retrieves the next user in the enumeration sequence.
GetDefaultQuotaLimit Retrieves the default quota limit for the volume.
GetDefaultQuotaLimitText Retrieves the default quota limit for the volume. The limit is expressed as a text string, for example "10.5 MB". If the volume has no limit, the string returned is "No Limit." If the buffer is too small, it is truncated to fit the buffer.
GetDefaultQuotaThreshold Retrieves the default quota warning threshold for the volume.
GetDefaultQuotaThresholdText Retrieves the default warning threshold for the volume. This threshold is expressed as a text string, for example "10.5 MB". If the volume does not have a threshold, the string returned is "No Limit." If the buffer is too small, the string is truncated to fit the buffer.
IsStateDisabled Determines if quotas are enabled on the volume.
IsStateTracked Determines if quotas are tracked (i.e., the limit is not enforced) on the volume.
IsStateEnforced Determines if quotas are enforced on the volume.
IsStateIncomplete Determines if the volume's quota information is out of date.
IsStateRebuilding Determines if the volume's quota information is being rebuilt.

HRESULT Initialize( PCTSTR pszVolume )

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_FILE_NOT_FOUND The requested file or object was not found.
ERROR_INITIALIZED The controller object has already been initialized. Multiple initialization is not allowed.
ERROR_INVALID_NAME The requested file path is invalid.
ERROR_NOTSUPPORTED The file system does not support quotas.
ERROR_PATH_NOT_FOUND The requested file path was not found.

Parameters

  • pszVolume

    Specifies the path to the volume's root.

HRESULT EnumFirstUser( CDiskQuotaUser *pDiskQuotaUser )

HRESULT EnumNextUser( CDiskQuotaUser *pDiskQuotaUser ) const

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_NOT_READY The CDiskQuotaControl object is not initialized.
E_INVALIDARG The pDiskQuotaUser parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.
S_FALSE If the first, or next, user in the enumeration sequence was not successfully retrieved.

Parameters

  • pDiskQuotaUser

    Pointer to a CDiskQuotaUser object.

HRESULT GetDefaultQuotaLimit( PLONGLONG pLimit ) const

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_NOT_READY The CDiskQuotaControl object is not initialized.
E_INVALIDARG The pLimit parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • pLimit

    Pointer to the variable to receive the quota limit. If this value is -1, the user has an unlimited quota.

HRESULT GetDefaultQuotaLimitText( CString &strDefaultQuotaText ) const

HRESULT GetDefaultQuotaLimitText( PTSTR pszDefaultQuotaText, const DWORD dwSize ) const

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_NOT_READY The CDiskQuotaControl object is not initialized.
E_INVALIDARG The pszDefaultQuotaText parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • strDefaultQuotaText

    Reference to a CString object that will receive the text string.

  • pszDefaultQuotaText

    Pointer to the buffer to receive the text string.

  • dwSize

    Size of the buffer, in characters.

HRESULT GetDefaultQuotaThreshold( PLONGLONG pThreshold ) const

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_NOT_READY The CDiskQuotaControl object is not initialized.
E_INVALIDARG The pThreshold parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • pThreshold

    Pointer to the variable to receive the default warning threshold value, in bytes.

HRESULT GetDefaultQuotaThresholdText( CString &strDefaultQuotaText ) const

HRESULT GetDefaultQuotaThresholdText( PTSTR pszDefaultQuotaText, const DWORD dwSize ) const

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_NOT_READY The CDiskQuotaControl object is not initialized.
E_INVALIDARG The pszDefaultQuotaText parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • strDefaultQuotaText

    Reference to a CString object that will receive the text string.

  • pszDefaultQuotaText

    Pointer to the buffer to receive the text string.

  • dwSize

    Size of the buffer, in characters.

bool IsStateDisabled( void ) const;

Return value

true, if quotas are disabled on the volume; false otherwise.

bool IsStateTracked( void ) const;

Return value

true, if quotas are enabled on the volume but the limit is not being enforced; false otherwise.

bool IsStateEnforced( void ) const;

Return value

true, if quotas are enabled on the volume and the limit is being enforced; false otherwise.

bool IsStateIncomplete( void ) const;

Return value

true, if the quota's information is out of date; false otherwise.

bool IsStateRebuilding( void ) const;

Return value

true, if the quota's information is being rebuilt; false otherwise.

The CDiskQuotaUser class

This class is a wrapper around most of the IDiskQuotaUser interface. Most of the text comes straight from the MSDN.

CDiskQuotaUser Constructs a CDiskQuotaUser object which represents a single user quota entry in the volume quota information file.
GetName Retrieves the name strings associated with a disk quota user.
GetQuotaThresholdText Retrieves the user's warning threshold for the volume. This threshold is expressed as a text string, for example "10.5 MB". If the user's threshold is unlimited, the string returned is "No Limit." If the destination buffer is too small, the string is truncated to fit the buffer.
GetQuotaThreshold Retrieves the user's warning threshold value on the volume. The threshold is an arbitrary value set by the volume's quota administrator. You can use it to identify users who are approaching their hard quota limit.
GetQuotaLimitText Retrieves the user's quota limit for the volume. This limit is expressed as a text string, for example "10.5 MB". If the user has no quota limit, the string returned is "No Limit." If the destination buffer is too small, the string is truncated to fit the buffer.
GetQuotaLimit Retrieves the user's quota limit value on the volume. The limit is set as the maximum amount of disk space available to the volume user.
GetQuotaUsedText Retrieves the user's quota used value for the volume. This value is expressed as a text string, for example "10.5 MB". If the destination buffer is too small, the string is truncated to fit the buffer.
GetQuotaUsed Retrieves the user's quota used value on the volume. This is the amount of information stored on the volume by the user. Note that this is the amount of uncompressed information. Therefore, the use of NTFS compression does not affect this value.
GetQuotaInformation Retrieves the values for the user's warning threshold, hard quota limit, and quota used.
IsStatusResolved Determines if a user's SID resolved to a user account.
IsStatusUnavailable Determines if a user's account is available. The network DC may not be available.
IsStatusDeleted Determines if a user's account was deleted from the domain.
IsStatusInvalid Determines if a user's account is invalid.
IsStatusUnknown Determines if a user's account is unknown.
IsStatusUnresolved Determines if a user's SID did not resolve to a user account.

HRESULT GetName( CString &strLogonName, CString &strDisplayName ) const;

HRESULT GetName( PTSTR pszLogonName, const DWORD dwSizeLogon, PTSTR pszDisplayName, const DWORD dwSizeDisplay ) const;

Return value

Value Meaning
NOERROR Success.
ERROR_LOCK_FAILED Failure to obtain an exclusive lock.

Parameters

  • strLogonName

    Reference to a CString object that will receive the name the user specified to log on to the computer. The format of the name returned depends on whether directory service information is available.

  • strDisplayName

    Reference to a CString object that will receive the display name for the quota user. If the information is not available, the string returned is empty.

  • pszLogonName

    Pointer to the buffer to receive the name the user specified to log on to the computer. This value can be NULL. The format of the name returned depends on whether directory service information is available.

  • dwSizeLogon

    Size of the logon name buffer, in characters. Ignored if pszLogonName is NULL.

  • pszDisplayName

    Pointer to the buffer to receive the display name for the quota user. This value can be NULL. If the information is not available, the string returned is of zero length.

  • dwSizeDisplay

    Size of the display-name buffer, in characters. Ignored if pszDisplayName is NULL.

HRESULT GetQuotaThresholdText( CString &strQuotaThresholdText ) const;

HRESULT GetQuotaThresholdText( PTSTR pszQuotaThresholdText, const DWORD dwSize ) const;

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_LOCK_FAILED Failure to obtain an exclusive lock.
E_INVALIDARG The pszQuotaThresholdText parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • strQuotaThresholdText

    Reference to a CString object that will receive the text string.

  • pszQuotaThresholdText

    Pointer to the buffer to receive the text string.

  • dwSize

    Size of the destination buffer, in characters.

HRESULT GetQuotaThreshold( PLONGLONG pLimit ) const;

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_LOCK_FAILED Failure to obtain an exclusive lock.
E_INVALIDARG The pLimit parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • pLimit

    Pointer to a variable to receive the warning threshold value.

HRESULT GetQuotaLimitText( CString &strQuotaLimitText ) const;

HRESULT GetQuotaLimitText( PTSTR pszQuotaLimitText, const DWORD dwSize ) const;

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_LOCK_FAILED Failure to obtain an exclusive lock.
E_INVALIDARG The pszQuotaLimitText parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • strQuotaLimitText

    Reference to a CString object that will receive the text string.

  • pszQuotaLimitText

    Pointer to the buffer to receive the text string.

  • dwSize

    Size of the buffer, in characters.

HRESULT GetQuotaLimit( PLONGLONG pLimit ) const;

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_LOCK_FAILED Failure to obtain an exclusive lock.
E_INVALIDARG The pLimit parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • pLimit

    Pointer to the variable to receive the limit value. If this value is -1, the user has an unlimited quota.

HRESULT GetQuotaUsedText( CString &strQuotaUsedText ) const;

HRESULT GetQuotaUsedText( PTSTR pszQuotaUsedText, const DWORD dwSize ) const;

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_LOCK_FAILED Failure to obtain an exclusive lock.
E_INVALIDARG The pszQuotaUsedText parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • strQuotaUsedText

    Reference to a CString object that will receive the text string.

  • pszQuotaUsedText

    Pointer to the buffer to receive the text string.

  • dwSize

    Size of the buffer, in bytes.

HRESULT GetQuotaUsed( PLONGLONG pUsed ) const;

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_LOCK_FAILED Failure to obtain an exclusive lock.
E_INVALIDARG The pUsed parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • pUsed

    Pointer to the variable to receive the quota used value.

HRESULT GetQuotaInformation( PDISKQUOTA_USER_INFORMATION pDQUserInfo, const DWORD dwSize ) const;

Return value

Value Meaning
NOERROR Success.
ERROR_ACCESS_DENIED The caller has insufficient access rights.
ERROR_LOCK_FAILED Failure to obtain an exclusive lock.
E_INVALIDARG The pDQUserInfo parameter is NULL.
E_OUTOFMEMORY Insufficient memory.
E_FAIL An unexpected file system error occurred.
E_UNEXPECTED An unexpected exception occurred.

Parameters

  • pDQUserInfo

    Pointer to a DISKQUOTA_USER_INFORMATION structure to receive the quota information.

  • dwSize

    Size of the quota information structure, in bytes.

bool IsStatusResolved( void ) const;

Return value

true if the user's SID was resolved to a user account; false otherwise.

bool IsStatusUnavailable( void ) const;

Return value

true if the user's account is unavailable (e.g., the domain controller may not be available); false otherwise.

bool IsStatusDeleted( void ) const;

Return value

true if the user's account was deleted; false otherwise.

bool IsStatusInvalid( void ) const;

Return value

true if the user's account is invalid; false otherwise.

bool IsStatusUnknown( void ) const;

Return value

true if the user's account is unknown; false otherwise.

bool IsStatusUnresolved( void ) const;

Return value

true if the user's SID does not resolve to a user account; false otherwise.

Example

CDiskQuotaControl DiskQuotaControl;

HRESULT hr = DiskQuotaControl.Initialize(strVolume);    
if (ERROR_NOT_SUPPORTED == hr)
    TRACE(CString((LPCTSTR) IDS_NOT_SUPPORTED));

if (NOERROR == hr)
{
    if (DiskQuotaControl.IsStateDisabled())
        TRACE(CString((LPCTSTR) IDS_NOT_ENABLED));
    else if (DiskQuotaControl.IsStateTracked())
        TRACE(CString((LPCTSTR) IDS_NOT_TRACKED));
    else if (DiskQuotaControl.IsStateEnforced())
        TRACE(CString((LPCTSTR) IDS_NOT_ENFORCED));
    else if (DiskQuotaControl.IsStateIncomplete())
        TRACE(CString((LPCTSTR) IDS_INCOMPLETE));
    else if (DiskQuotaControl.IsStateRebuilding())
        TRACE(CString((LPCTSTR) IDS_REBUILDING));
    else
        TRACE(CString((LPCTSTR) IDS_UNKNOWN));

    
    DISKQUOTA_USER_INFORMATION  DQUserInfo;
    CString                     strLogonName,
                                strDisplayName,
                                strQuotaThresholdText,
                                strQuotaLimitText,
                                strQuotaUsedText;

    // enumerate through each of the users

    hr = DiskQuotaControl.EnumFirstUser(&DiskQuotaUser);
    while (S_OK == hr)
    {
        // get information about the user's numbers

        DiskQuotaUser.GetName(strLogonName, strDisplayName);
        DiskQuotaUser.GetQuotaThresholdText(strQuotaThresholdText);
        DiskQuotaUser.GetQuotaLimitText(strQuotaLimitText);
        DiskQuotaUser.GetQuotaUsedText(strQuotaUsedText);
        DiskQuotaUser.GetQuotaInformation(&DQUserInfo, 
                       sizeof(DISKQUOTA_USER_INFORMATION));

        // determine if the user is above/below their quota

        if (DQUserInfo.QuotaUsed > DQUserInfo.QuotaLimit && 
                                   DQUserInfo.QuotaLimit >= 0)
            TRACE(CString((LPCTSTR) IDS_ABOVE_LIMIT));
        else if (DQUserInfo.QuotaUsed > DQUserInfo.QuotaThreshold && 
                                      DQUserInfo.QuotaThreshold >= 0)
            TRACE(CString((LPCTSTR) IDS_WARNING));
        else
            TRACE(CString((LPCTSTR) IDS_OK));

        TRACE(strLogonName);

        hr = DiskQuotaControl.EnumNextUser(&DiskQuotaUser);
    }
}

Extras

The code in this section isn't within the scope of this article but I wanted to show it anyway as it was useful for me and hopefully for anyone else who might need it.

I've seen several different varieties of adjusting a control's dimensions or location at runtime. Some examples were painfully long while others were not as bad or were just plain hard to follow. I put a simple function together that I feel is small and easy to understand. This function is called from the dialog's OnSize() method.

In the dialog's OnInitDialog() method, we need to get the initial size of the client area. This is so we have a reference point from which to move. This looks like:

GetClientRect(m_rectOrig);
m_nWidth  = m_rectOrig.Width();
m_nHeight = m_rectOrig.Height();

Notice that m_rectOrig is a member variable rather than just a local variable. It is used in the OnGetMinMaxInfo() method to make sure we don't minimize the dialog too much.

The function to do the sizing and moving of the child controls looks like:

void RepositionChildControl( CWnd *pWnd, const int dx, 
                       const int dy, const UINT uAnchor )
{
    // make sure the dialog exists

    if (NULL != pWnd->m_hWnd)
    {
        CRect   rect;

        pWnd->GetWindowRect(rect);
        ScreenToClient(rect);

        if (uAnchor & resizeVERT)        // 0x0020

            rect.bottom += dy;
        else if (uAnchor & anchorBOTTOM) // 0x0004

            rect.OffsetRect(0, dy);
        
        if (uAnchor & resizeHORZ)        // 0x0010

            rect.right += dx;
        else if (uAnchor & anchorRIGHT)  // 0x0002

            rect.OffsetRect(dx, 0);

        pWnd->MoveWindow(rect);
    }
}

Whenever the dialog is being resized, the OnSize() method is called. Here is where we call RepositionChildControl():

void OnSize(UINT nType, int cx, int cy) 
{
    CDialog::OnSize(nType, cx, cy);
    
    // how much did the dialog grow/shrink by?

    int nWidthOffset  = cx - m_nWidth;
    int nHeightOffset = cy - m_nHeight;

    // this control is anchored at the top and right, 

    // and is sized horizontally

    RepositionChildControl(&m_lblStatus, nWidthOffset, 
      nHeightOffset, anchorTOP | anchorRIGHT | resizeHORZ);
    
    // this control is anchored at the top and left, 

    // and is sized horizontally and vertically

    RepositionChildControl(&m_lcDQInfo,  nWidthOffset, 
      nHeightOffset, anchorTOP | anchorLEFT | resizeBOTH);
    
    // this control is anchored at the top and right

    RepositionChildControl(&m_btnCancel, nWidthOffset, 
                 nHeightOffset, anchorTOP | anchorRIGHT);

    // save dialog's new dimensions

    m_nWidth  = cx;
    m_nHeight = cy;
}

Since this type of movement does cause a little bit of flicker, the interested reader could add each of the controls to a CWnd* array. Then in the dialog's OnEraseBkgnd() method, subtract the rect of each of the controls from the dialog's rect using CDC::ExcludeClipRect().

Summary

These two classes are far from complete. They reflect the "read" methods of each of the interfaces, thus they do not update any quota information. However, they could easily be expanded for such functionality.

Enjoy!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here