//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1996 - 1999
//
//  File:       aceedit.cpp
//
//  This file contains the implementation for the advanced ACE editor
//  page.
//
//--------------------------------------------------------------------------

#include "aclpriv.h"
#include "sddl.h"       // ConvertSidToStringSid

#define PWM_SELECT_PAGE             (WM_APP - 1)

//
//  Context Help IDs.
//
const static DWORD aAcePermHelpIDs[] =
{
    IDC_ACEE_INHERITWARNING,        IDH_NOHELP,
    IDC_ACEE_NAME_STATIC,           IDH_ACEE_PERM_NAME,
    IDC_ACEE_NAME,                  IDH_ACEE_PERM_NAME,
    IDC_ACEE_NAMEBUTTON,            IDH_ACEE_PERM_NAMEBUTTON,
    IDC_ACEE_APPLYONTO_STATIC,      IDH_ACEE_PERM_INHERITTYPE,
    IDC_ACEE_INHERITTYPE,           IDH_ACEE_PERM_INHERITTYPE,
    IDC_ACEE_ACCESS,                IDH_ACEE_PERM_LIST,
    IDC_ACEE_ALLOW,                 IDH_ACEE_PERM_LIST,
    IDC_ACEE_DENY,                  IDH_ACEE_PERM_LIST,
    IDC_ACEE_LIST,                  IDH_ACEE_PERM_LIST,
    IDC_ACEE_INHERITIMMEDIATE,      IDH_ACEE_PERM_INHERITIMMEDIATE,
    IDC_ACEE_CLEAR,                 IDH_ACEE_PERM_CLEAR,
    0, 0
};
const static DWORD aAceAuditHelpIDs[] =
{
    IDC_ACEE_INHERITWARNING,        IDH_NOHELP,
    IDC_ACEE_NAME_STATIC,           IDH_ACEE_AUDIT_NAME,
    IDC_ACEE_NAME,                  IDH_ACEE_AUDIT_NAME,
    IDC_ACEE_NAMEBUTTON,            IDH_ACEE_AUDIT_NAMEBUTTON,
    IDC_ACEE_APPLYONTO_STATIC,      IDH_ACEE_AUDIT_INHERITTYPE,
    IDC_ACEE_INHERITTYPE,           IDH_ACEE_AUDIT_INHERITTYPE,
    IDC_ACEE_ACCESS,                IDH_ACEE_AUDIT_LIST,
    IDC_ACEE_ALLOW,                 IDH_ACEE_AUDIT_LIST,
    IDC_ACEE_DENY,                  IDH_ACEE_AUDIT_LIST,
    IDC_ACEE_LIST,                  IDH_ACEE_AUDIT_LIST,
    IDC_ACEE_INHERITIMMEDIATE,      IDH_ACEE_AUDIT_INHERITIMMEDIATE,
    IDC_ACEE_CLEAR,                 IDH_ACEE_AUDIT_CLEAR,
    0, 0
};


class CACEPage : public CSecurityPage
{
private:
    PACE            m_pAce;
    HDPA           *m_phEntries;
    PSID            m_pSid;
    DWORD           m_siFlags;
    DWORD          *m_pdwResult;
    GUID            m_guidInheritType;
    BOOL            m_fInheritImmediateEnabled;
    BOOL            m_fPreviousImmediateSetting;
    BOOL            m_fReadOnly;
    BOOL            m_fPageDirty;
    SI_INHERIT_TYPE m_siInheritUnknown;
	CACEPage		*m_pOtherPage;
	HWND			m_hwnd;

public:
    CACEPage(LPSECURITYINFO psi,
             SI_PAGE_TYPE siType,
             PACE pAce,
             BOOL bReadOnly,
             DWORD dwFlags,
             DWORD *pdwResult,
             HDPA *phEntries);
    virtual ~CACEPage();

private:
    virtual BOOL DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

    // Prevent propsheet callbacks from reaching the object that invoked us
    virtual UINT PSPageCallback(HWND, UINT, LPPROPSHEETPAGE) { return 1; }

    void EmptyCheckList(HWND hwndList);
    LONG CheckPermBoxes(HWND hwndList, PACE pAce, DWORD dwState);
    LONG InitCheckList(HWND hDlg, PACE pAce);
    LONG ReInitCheckList(HWND hDlg, HDPA hEntries);
	VOID DisplayNoControlMessage(HWND hDlg, BOOL bDisplay);
    void HideInheritedAceWarning(HWND hDlg);
    void InitDlg(HWND hDlg);
    BOOL OnChangeName(HWND hDlg);
    BOOL OnClearAll(HWND hDlg);
    void HandleSelChange(HWND hDlg, HWND hWnd);
    LONG OnApply(HWND hDlg, BOOL bClose);
	HWND m_hwndNoPerm;
	BOOL IsAclBloated(HWND hDlg);
	HDPA GetAceList(HWND hDlg);
};
typedef class CACEPage *LPACEPAGE;

CACEPage::CACEPage(LPSECURITYINFO psi,
                   SI_PAGE_TYPE siType,
                   PACE pAce,
                   BOOL bReadOnly,
                   DWORD dwFlags,
                   DWORD *pdwResult,
                   HDPA *phEntries)
: CSecurityPage(psi, siType), m_pAce(pAce), m_fReadOnly(bReadOnly),
    m_siFlags(dwFlags), m_pdwResult(pdwResult), m_phEntries(phEntries),
	m_hwndNoPerm(NULL),m_pOtherPage(NULL)
{
    if (m_pdwResult)
        *m_pdwResult = 0;
}

CACEPage::~CACEPage()
{
    if (m_pSid)
        LocalFree(m_pSid);
	if(m_hwndNoPerm)
		DestroyWindow(m_hwndNoPerm);
}


void
CACEPage::EmptyCheckList(HWND hwndList)
{
    SendMessage(hwndList, CLM_RESETCONTENT, 0, 0);
}


LONG
CACEPage::CheckPermBoxes(HWND hwndList, PACE pAce, DWORD dwState)
{
    LONG nLastChecked = -1;
    UINT cItems;
    BOOL bColumnAllow = FALSE;
    BOOL bColumnDeny = FALSE;

    //
    // Check all boxes that correspond to a particular ACE
    //

    if (hwndList == NULL || pAce == NULL)
        return -1;

    if (pAce->AceFlags & INHERITED_ACE)
        dwState |= CLST_DISABLED;

    if (m_siPageType == SI_PAGE_ADVPERM)
    {
        // Only check one column (either allow or deny)

        if (IsEqualACEType(pAce->AceType, ACCESS_ALLOWED_ACE_TYPE))
            bColumnAllow = TRUE;        // Access allowed
        else if (IsEqualACEType(pAce->AceType, ACCESS_DENIED_ACE_TYPE))
            bColumnDeny = TRUE;         // Access denied
        else
            return -1;  // Bogus ACE
    }
    else if (m_siPageType == SI_PAGE_AUDIT)
    {
        // Either or both columns can be checked for audits

        if (pAce->AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG)
            bColumnAllow = TRUE;        // Audit successful access

        if (pAce->AceFlags & FAILED_ACCESS_ACE_FLAG)
            bColumnDeny = TRUE;         // Audit failed access
    }
    else
        return -1;

    cItems = (UINT)SendMessage(hwndList, CLM_GETITEMCOUNT, 0, 0);

    while (cItems > 0)
    {
        PSI_ACCESS pAccess;

        --cItems;
        pAccess = (PSI_ACCESS)SendMessage(hwndList, CLM_GETITEMDATA, cItems, 0);

        //
        // The below expression tests to see if this access mask enables
        // this access "rights" line.  It could have more bits enabled, but
        // as long as it has all of the ones from the pAccess->mask then
        // it effectively has that option enabled.
        //

        if (pAccess &&
            AllFlagsOn(pAce->Mask, pAccess->mask) &&
            (!(pAce->Flags & ACE_OBJECT_TYPE_PRESENT) ||
             IsSameGUID(pAccess->pguid, &pAce->ObjectType)))
        {
            WPARAM wItem;

            nLastChecked = cItems;


            if (bColumnAllow)
            {
                wItem = MAKELONG((WORD)cItems, COLUMN_ALLOW);
                SendMessage(hwndList,
                            CLM_SETSTATE,
                            wItem,
                            (LPARAM)dwState);
            }

            if (bColumnDeny)
            {
                wItem = MAKELONG((WORD)cItems, COLUMN_DENY);
                SendMessage(hwndList,
                            CLM_SETSTATE,
                            wItem,
                            (LPARAM)dwState);
            }
        }
    }

    return nLastChecked;
}


LONG
CACEPage::InitCheckList(HWND hDlg, PACE pAce)
{
    LONG nTopItemChecked;
    HDPA hList = NULL;

    TraceEnter(TRACE_ACEEDIT, "CACEPage::InitCheckList");
    TraceAssert(hDlg != NULL);

    if (m_siPageType == SI_PAGE_AUDIT)
        SendDlgItemMessage(hDlg, IDC_ACEE_LIST, CLM_SETCOLUMNWIDTH, 0, 40);

    hList = DPA_Create(1);
    if (hList && pAce)
        DPA_AppendPtr(hList, pAce->Copy());

    nTopItemChecked = ReInitCheckList(hDlg, hList);

    if (hList)
        DestroyDPA(hList);

    TraceLeaveValue(nTopItemChecked);
}


LONG
CACEPage::ReInitCheckList(HWND hDlg, HDPA hEntries)
{
    LONG nTopItemChecked = -1;
    HWND hwndList;
    DWORD dwFlags;
    HRESULT hr;
    HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));

    TraceEnter(TRACE_ACEEDIT, "CACEPage::ReInitCheckList");
    TraceAssert(hDlg != NULL);

    hwndList = GetDlgItem(hDlg, IDC_ACEE_LIST);

    EmptyCheckList(hwndList);

    dwFlags = SI_ADVANCED;

    if (m_siPageType == SI_PAGE_AUDIT)
        dwFlags |= SI_EDIT_AUDITS;

    if (m_siFlags == SI_ACCESS_PROPERTY)
        dwFlags |= SI_EDIT_PROPERTIES;

    //
    // Enumerate the permissions and add to the checklist
    //
    hr = _InitCheckList(hwndList,
                        m_psi,
                        &m_guidInheritType,
                        dwFlags,
                        m_siObjectInfo.hInstance,
                        m_siFlags,
                        NULL);
    if (SUCCEEDED(hr))
    {
        UINT cItems = (UINT)SendMessage(hwndList, CLM_GETITEMCOUNT, 0, 0);
		
		//
		//On object page display the message if number
		//cItems is zero.
		//
		if(m_siFlags == SI_ACCESS_SPECIFIC)
			DisplayNoControlMessage(hDlg, !cItems);

        ULONG cAces = 0;
        
        if (hEntries)
            cAces = DPA_GetPtrCount(hEntries);

        //
        // Check the appropriate boxes
        //
        nTopItemChecked = MAXLONG;
        while (cAces > 0)
        {
            PACE_HEADER pAceHeader;

            --cAces;
            pAceHeader = (PACE_HEADER)DPA_FastGetPtr(hEntries, cAces);
            if (pAceHeader)
            {
                CAce Ace(pAceHeader);
                LONG nTop = CheckPermBoxes(hwndList, &Ace, CLST_CHECKED);
                if (-1 != nTop)
                    nTopItemChecked = min(nTopItemChecked, nTop);
            }
        }
        if (MAXLONG == nTopItemChecked)
            nTopItemChecked = -1;

        // Make sure the top item checked is scrolled into view.
        // (-1 scrolls to the top, same as 0.)
        SendMessage(hwndList, CLM_ENSUREVISIBLE, nTopItemChecked, 0);

        // Disable all of the boxes if we're in read-only mode
        if (m_fReadOnly)
            SendMessage(hwndList, WM_ENABLE, FALSE, 0);
    }

    SetCursor(hcur);
    TraceLeaveValue(nTopItemChecked);
}

VOID CACEPage::DisplayNoControlMessage(HWND hDlg, BOOL bDisplay)
{
	RECT rc;
	if(bDisplay)
	{
		ShowWindow(m_hwndNoPerm, SW_SHOW);
	}
	else
	{
		ShowWindow(m_hwndNoPerm, SW_HIDE);
	}
}

void CACEPage::HideInheritedAceWarning(HWND hDlg)
// Hides the message informing the user that the current ACE is inherited from
// the parent. Also moves and resizes controls as appropriate.
{
    // Array of control IDs to move up
    static UINT rgMoveControls[] =
    {
        IDC_ACEE_NAME_STATIC,
        IDC_ACEE_NAME,
        IDC_ACEE_NAMEBUTTON,
        IDC_ACEE_APPLYONTO_STATIC,
        IDC_ACEE_INHERITTYPE,
        IDC_ACEE_ACCESS,
        IDC_ACEE_ALLOW,
        IDC_ACEE_DENY,
    };

    // Get the message window dimensions
    HWND hwndControl = GetDlgItem(hDlg, IDC_ACEE_INHERITWARNING);
    RECT rect;
    GetWindowRect(hwndControl, &rect);

    // We need to move controls up this amount:
    int nMoveUpAmount = rect.bottom - rect.top;

    // Rather than hide the message window, destroy it altogether so WinHelp
    // doesn't confuse it with the "Name:" static during WM_CONTEXTMENU.
    DestroyWindow(hwndControl);

    // Move each of the controls we need to move up
    for (int nControl = 0; nControl < ARRAYSIZE(rgMoveControls); nControl++)
    {
        hwndControl = GetDlgItem(hDlg, rgMoveControls[nControl]);
        GetWindowRect(hwndControl, &rect);
        MapWindowPoints(NULL, hDlg, (LPPOINT)&rect, 2);
        SetWindowPos(hwndControl,
                     NULL,
                     rect.left,
                     rect.top - nMoveUpAmount,
                     0,
                     0,
                     SWP_NOSIZE | SWP_NOZORDER);
    }

    // Finally, we need to resize the list control, including adjusting its height
    hwndControl = GetDlgItem(hDlg, IDC_ACEE_LIST);
    GetWindowRect(hwndControl, &rect);
    MapWindowPoints(NULL, hDlg, (LPPOINT)&rect, 2);
    SetWindowPos(hwndControl,
                 NULL,
                 rect.left,
                 rect.top - nMoveUpAmount,
                 rect.right - rect.left,
                 rect.bottom - (rect.top - nMoveUpAmount),
                 SWP_NOZORDER);
}


//
// Default "Apply onto" strings for when GetInheritTypes
// fails or we don't find a matching inherit type.
//
// If desirable, different strings can be created for
// CONTAINER_INHERIT_ACE vs OBJECT_INHERIT_ACE.
//
static const UINT s_aInheritTypes[] =
{
    IDS_THIS_OBJECT_ONLY,           // 0 = <no inheritance>
    IDS_THIS_OBJECT_AND_SUBOBJECTS, // 1 = OBJECT_INHERIT_ACE
    IDS_THIS_OBJECT_AND_SUBOBJECTS, // 2 = CONTAINER_INHERIT_ACE
    IDS_THIS_OBJECT_AND_SUBOBJECTS, // 3 = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE
};

// These are used when INHERIT_ONLY_ACE is present
static const UINT s_aInheritOnlyTypes[] =
{
    IDS_INVALID_INHERIT,            // 0 = <invalid>
    IDS_SUBOBJECTS_ONLY,            // 1 = OBJECT_INHERIT_ACE
    IDS_SUBOBJECTS_ONLY,            // 2 = CONTAINER_INHERIT_ACE
    IDS_SUBOBJECTS_ONLY,            // 3 = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE
};


static int
_AddInheritType(HWND hInheritType,
                PSI_INHERIT_TYPE psiInheritType,
                HINSTANCE hInstance)
{
    UINT iIndex;
    TCHAR szName[MAX_PATH];
    LPCTSTR pszName = psiInheritType->pszName;

    if (IS_INTRESOURCE(pszName))
    {
        if (LoadString(hInstance,
                       (ULONG)((ULONG_PTR)pszName),
                       szName,
                       ARRAYSIZE(szName)) == 0)
        {
            LoadString(::hModule,
                       IDS_UNKNOWN,
                       szName,
                       ARRAYSIZE(szName));
        }
        pszName = szName;
    }

    iIndex = (UINT)SendMessage(hInheritType, CB_ADDSTRING, 0, (LPARAM)pszName);

    if (CB_ERR != iIndex)
        SendMessage(hInheritType, CB_SETITEMDATA, iIndex, (LPARAM)psiInheritType);

    return iIndex;
}

void
CACEPage::InitDlg(HWND hDlg)
{
#define X_COR 7
#define Y_COR 7
    UCHAR   AceFlags = 0;
    PSID    pSid = NULL;
    LPCTSTR pszName = NULL;
    LPTSTR  pszNameT = NULL;
    HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
    HRESULT hr;

    TraceEnter(TRACE_ACEEDIT, "CACEPage::InitDlg");

	//
	//Store the hDlg
	//

	m_hwnd = hDlg;
	if(m_siFlags == SI_ACCESS_SPECIFIC)
	{
		//
		//Create a label to show message when no generic 
		//permissions exist for the object
		//

		WCHAR szName[1024];
		LoadString(::hModule, IDS_NO_OBJECT_PERM, szName, ARRAYSIZE(szName));

		RECT rc;
		GetWindowRect(GetDlgItem(hDlg,IDC_ACEE_LIST),&rc);
		// Create a new label control
		m_hwndNoPerm = CreateWindowEx(0,
									  TEXT("STATIC"),
									  szName,
									  WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP | SS_NOPREFIX,
									  X_COR,
									  Y_COR,
									  rc.right - rc.left - 2*X_COR,
									  rc.bottom - rc.top - 2*Y_COR,
									  GetDlgItem(hDlg,IDC_ACEE_LIST),
									  (HMENU)IntToPtr(0xffff),
									  ::hModule,
									  NULL);
		// Set the font
		SendMessage(m_hwndNoPerm,
					WM_SETFONT,
					SendMessage(hDlg, WM_GETFONT, 0, 0),
					0);
	}


    if (m_pAce)
    {
        AceFlags = m_pAce->AceFlags;
        m_guidInheritType = m_pAce->InheritedObjectType;
        pSid = m_pAce->psid;
        pszName = m_pAce->LookupName(m_siObjectInfo.pszServerName, m_psi2);
    }
    else
    {
        if (m_siObjectInfo.dwFlags & SI_CONTAINER)
            AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;

        pSid = QuerySystemSid(UI_SID_World);
    }

    // Make sure the AceFlags are valid
    ACCESS_MASK Mask = 0;
    m_psi->MapGeneric(&m_guidInheritType, &AceFlags, &Mask);

    // Hide the inherit warning and adjust other control positions
    if (!(AceFlags & INHERITED_ACE))
        HideInheritedAceWarning(hDlg);

    // Make a copy of the sid and get the name
    if (pSid)
    {
        PUSER_LIST pUserList = NULL;

        m_pSid = LocalAllocSid(pSid);

        if (pszName == NULL)
        {
            // This should only happen when m_pAce is NULL and we're
            // using UI_SID_World
            if (LookupSid(pSid, m_siObjectInfo.pszServerName, m_psi2, &pUserList))
            {
                TraceAssert(NULL != pUserList);
                TraceAssert(1 == pUserList->cUsers);

                if (BuildUserDisplayName(&pszNameT,
                                         pUserList->rgUsers[0].pszName,
                                         pUserList->rgUsers[0].pszLogonName)
                    || ConvertSidToStringSid(pSid, &pszNameT))
                {
                    pszName = pszNameT;
                }
            }
        }

        SetDlgItemText(hDlg, IDC_ACEE_NAME, pszName);

        if (NULL != pUserList)
            LocalFree(pUserList);
    }

    // Get the list of permissions and initialize the check boxes
    LONG nTopChecked = InitCheckList(hDlg, m_pAce);

    if (-1 == nTopChecked &&
        m_pAce &&
        m_pAce->Mask &&
        (m_siObjectInfo.dwFlags & SI_EDIT_PROPERTIES) &&
        m_siFlags != SI_ACCESS_PROPERTY)
    {
        // Must be a property ACE, switch to the Properties page
        PostMessage(hDlg, PWM_SELECT_PAGE, 1, 0);
    }

    HWND hInheritType = GetDlgItem(hDlg, IDC_ACEE_INHERITTYPE);
    HWND hInheritImmed = GetDlgItem(hDlg, IDC_ACEE_INHERITIMMEDIATE);

    if (m_siObjectInfo.dwFlags & SI_NO_TREE_APPLY)
    {
        ShowWindow(hInheritImmed, SW_HIDE);
        EnableWindow(hInheritImmed, FALSE);
    }

    //
    // Get inherit types from callback
    //
    ULONG cItems = 0;
    PSI_INHERIT_TYPE psiInheritType = NULL;

    hr = m_psi->GetInheritTypes(&psiInheritType, &cItems);
    if (SUCCEEDED(hr))
    {
        // Check these inherit bits for a match
        DWORD dwInheritMask = INHERIT_ONLY_ACE | ACE_INHERIT_ALL;

        // Don't check INHERIT_ONLY_ACE if the ACE inherit type
        // matches the current object
        if ((m_siObjectInfo.dwFlags & SI_OBJECT_GUID) &&
            IsSameGUID(&m_siObjectInfo.guidObjectType, &m_guidInheritType))
        {
            dwInheritMask &= ~INHERIT_ONLY_ACE;
        }

        //
        // Add inherit types to combobox
        //
        for ( ; cItems > 0; cItems--, psiInheritType++)
        {
            UINT iIndex = _AddInheritType(hInheritType,
                                          psiInheritType,
                                          m_siObjectInfo.hInstance);

            // See if this entry matches the incoming ACE
            if ((psiInheritType->dwFlags & dwInheritMask) == (ULONG)(AceFlags & dwInheritMask)
                && IsSameGUID(&m_guidInheritType, psiInheritType->pguid))
            {
                // Got a match, select this entry
                SendMessage(hInheritType, CB_SETCURSEL, iIndex, 0);
            }
        }
    }

    //
    // If GetInheritTypes failed, or we failed to find a match,
    // pick a default string and build an appropriate inherit type.
    //
    if (FAILED(hr) || CB_ERR == SendMessage(hInheritType, CB_GETCURSEL, 0, 0))
    {
        // Pick a default string
        UINT ids = IDS_SPECIAL;
        if (IsNullGUID(&m_guidInheritType))
        {
            if (AceFlags & INHERIT_ONLY_ACE)
                ids = s_aInheritOnlyTypes[AceFlags & ACE_INHERIT_ALL];
            else
                ids = s_aInheritTypes[AceFlags & ACE_INHERIT_ALL];
        }

        // Fill in m_siInheritUnknown with the pertinent info
        m_siInheritUnknown.pguid   = &m_guidInheritType;
        m_siInheritUnknown.dwFlags = AceFlags & (INHERIT_ONLY_ACE | ACE_INHERIT_ALL);
        m_siInheritUnknown.pszName = MAKEINTRESOURCE(ids);

        // Insert and select it
        UINT iIndex = _AddInheritType(hInheritType,
                                      &m_siInheritUnknown,
                                      ::hModule);
        SendMessage(hInheritType, CB_SETCURSEL, iIndex, 0);

        if (FAILED(hr))
        {
            // GetInheritTypes failed, which means the only entry is the
            // default one we just added.  Disable the combo.
            EnableWindow(hInheritType, FALSE);
        }
    }


    //
    // Select the options which match the incoming ace
    //

    if (!(AceFlags & (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)))
    {
        SendMessage(hInheritImmed, BM_SETCHECK, BST_UNCHECKED, 0);
        EnableWindow(hInheritImmed, FALSE);
        m_fInheritImmediateEnabled = FALSE;
        m_fPreviousImmediateSetting = BST_UNCHECKED;
    }
    else
    {
        SendMessage(hInheritImmed,
                    BM_SETCHECK,
                    (AceFlags & NO_PROPAGATE_INHERIT_ACE) ? BST_CHECKED : BST_UNCHECKED,
                    0);
        m_fInheritImmediateEnabled = TRUE;
    }

    if (!(m_siObjectInfo.dwFlags & SI_CONTAINER) || m_fReadOnly || (AceFlags & INHERITED_ACE))
    {
        // Disable all inheritance
        EnableWindow(hInheritType, FALSE);
        EnableWindow(hInheritImmed, FALSE);
    }

    if (m_fReadOnly || (AceFlags & INHERITED_ACE))
    {
        // Disable the "change name" and "clear all" buttons
        EnableWindow(GetDlgItem(hDlg, IDC_ACEE_NAMEBUTTON), FALSE);
        EnableWindow(GetDlgItem(hDlg, IDC_ACEE_CLEAR), FALSE);
    }

	PropSheet_QuerySiblings(GetParent(hDlg),0,(LPARAM)this);

    LocalFreeString(&pszNameT);
    SetCursor(hcur);

    TraceLeaveVoid();
}

BOOL
CACEPage::OnChangeName(HWND hDlg)
{
    PUSER_LIST pUserList = NULL;
    BOOL bResult = FALSE;

    TraceEnter(TRACE_ACEEDIT, "CACEPage::OnChangeName");

    if (S_OK == GetUserGroup(hDlg, FALSE, &pUserList))
    {
        TraceAssert(NULL != pUserList);
        TraceAssert(1 == pUserList->cUsers);

        // Free up previous sid
        if (m_pSid)
            LocalFree(m_pSid);

        // Copy the new sid
        m_pSid = LocalAllocSid(pUserList->rgUsers[0].pSid);
        if (m_pSid)
        {
            SetDlgItemText(hDlg, IDC_ACEE_NAME, pUserList->rgUsers[0].pszName);
            bResult = TRUE;
        }
        LocalFree(pUserList);
    }

    TraceLeaveValue(bResult);
}

BOOL
CACEPage::OnClearAll(HWND hDlg)
{
    HWND hwndList;
    ULONG cPermissions;

    TraceEnter(TRACE_ACEEDIT, "CACEPage::OnClearAll");
    TraceAssert(!m_fReadOnly);

    hwndList = GetDlgItem(hDlg, IDC_ACEE_LIST);
    cPermissions = (ULONG)SendMessage(hwndList, CLM_GETITEMCOUNT, 0, 0);

    while (cPermissions != 0)
    {
        WORD wCol = COLUMN_ALLOW;

        cPermissions--;

        while (wCol == COLUMN_ALLOW || wCol == COLUMN_DENY)
        {
            WPARAM wItem = MAKELONG((WORD)cPermissions, wCol);

            if (!(CLST_DISABLED & SendMessage(hwndList, CLM_GETSTATE, wItem, 0)))
                SendMessage(hwndList, CLM_SETSTATE, wItem, CLST_UNCHECKED);

            wCol++;
        }
    }

    TraceLeaveValue(TRUE);
}

void
CACEPage::HandleSelChange(HWND hDlg, HWND hWnd) // inherit type change
{
    PSI_INHERIT_TYPE psiInheritType;
    BOOL fEnableInheritImmediate = FALSE;
    const GUID *pguidInheritType = &GUID_NULL;

    TraceEnter(TRACE_ACEEDIT, "CACEPage::HandleSelChange");

    psiInheritType = (PSI_INHERIT_TYPE)SendMessage(hWnd,
                                                   CB_GETITEMDATA,
                                                   SendMessage(hWnd, CB_GETCURSEL, 0, 0),
                                                   0);

    if (psiInheritType != (PSI_INHERIT_TYPE)CB_ERR && psiInheritType != NULL)
    {
        if (psiInheritType->dwFlags & (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE))
            fEnableInheritImmediate = TRUE;
        if( psiInheritType->pguid )
            pguidInheritType = psiInheritType->pguid;
    }

    if (fEnableInheritImmediate != m_fInheritImmediateEnabled)
    {
        HWND hInheritImmediate = GetDlgItem(hDlg, IDC_ACEE_INHERITIMMEDIATE);

        if (fEnableInheritImmediate)
        {
            SendMessage(hInheritImmediate, BM_SETCHECK, m_fPreviousImmediateSetting, 0);
        }
        else
        {
            m_fPreviousImmediateSetting = (BOOL)SendMessage(hInheritImmediate,
                                                            BM_GETCHECK,
                                                            0,
                                                            0);
            SendMessage(hInheritImmediate, BM_SETCHECK, BST_UNCHECKED, 0);
        }

        EnableWindow(hInheritImmediate, fEnableInheritImmediate);
        m_fInheritImmediateEnabled = fEnableInheritImmediate;
    }

    // If the inherit type GUID has changed, reinitialize the checklist.
    if (!IsSameGUID(pguidInheritType, &m_guidInheritType))
    {
        HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
        HDPA hNewEntries = DPA_Create(4);

        if (hNewEntries)
        {
            GetAcesFromCheckList(GetDlgItem(hDlg, IDC_ACEE_LIST),
                                 m_pSid,
                                 m_siPageType == SI_PAGE_ADVPERM,
                                 TRUE,
                                 0,         // don't care about flags
                                 NULL,      // or inherit type here
                                 hNewEntries);

            // Save new inherit type and reset the checklist
            m_guidInheritType = *pguidInheritType; 
            ReInitCheckList(hDlg, hNewEntries);
            DestroyDPA(hNewEntries);
        }

        SetCursor(hcur);
    }

    TraceLeaveVoid();
}

void
HandleListClick(PNM_CHECKLIST pnmc, 
                SI_PAGE_TYPE siType, 
                BOOL bInheritFlags, 
                HDSA *phAllowUncheckedAccess, 
                HDSA *phDenyUncheckedAccess, 
                BOOL bCustomPresent)
{
    HWND            hChkList;
    UINT            iRow;
    WORD            wCol;
    PSI_ACCESS      pAccess;
    DWORD           dwState;
    BOOL            bNullGuid;
    UINT            iRowCompare;
    PSI_ACCESS      pAccessCompare;

    TraceEnter(TRACE_MISC, "HandleListClick");
    TraceAssert(pnmc != NULL);

    hChkList = pnmc->hdr.hwndFrom;
    iRow    = pnmc->iItem;
    wCol    = (WORD)pnmc->iSubItem;       // 1 = Allow, 2 = Deny
    pAccess = (PSI_ACCESS)pnmc->dwItemData;
    dwState = pnmc->dwState;

    if (pAccess == NULL)
        TraceLeaveVoid();

    if( phAllowUncheckedAccess )
    {
        *phAllowUncheckedAccess = DSA_Create(SIZEOF(PSI_ACCESS), 4);
        if (*phAllowUncheckedAccess == NULL)
        {
            TraceMsg("DSA_Create failed");
            TraceLeaveVoid();
        }
    }
    if( phDenyUncheckedAccess )
    {
        *phDenyUncheckedAccess = DSA_Create(SIZEOF(PSI_ACCESS), 4);
        if (*phDenyUncheckedAccess == NULL)
        {
            TraceMsg("DSA_Create failed");
            TraceLeaveVoid();
        }
    }


    bNullGuid = IsNullGUID(pAccess->pguid);

    iRowCompare = (UINT)SendMessage(hChkList, CLM_GETITEMCOUNT, 0, 0);

    //Custom checkbox is handled Separately
    if( bCustomPresent )
        --iRowCompare;

    while (iRowCompare != 0)
    {
        WPARAM wItem;
        DWORD  dwStateCompareOriginal;
        DWORD  dwStateCompare;
        WORD   wColCompare;
        BOOL   bSameGuid;
        BOOL   bNullGuidCompare;

        --iRowCompare;
        pAccessCompare = (PSI_ACCESS)SendMessage(hChkList, CLM_GETITEMDATA, iRowCompare, 0);

        if (!pAccessCompare)
            continue;

        bSameGuid = IsSameGUID(pAccessCompare->pguid, pAccess->pguid);
        bNullGuidCompare = IsNullGUID(pAccessCompare->pguid);

        // If the GUIDs are incompatible, then we can't do anything
        if (!(bSameGuid || bNullGuid || bNullGuidCompare))
            continue;

        //
        // Yukky, complicated mechanism to determine whether to
        // turn on or off the allow or deny check marks.
        //
        // REVIEW: This algorithm of changing check marks based on other
        // checkmarks handles a lot of cases, but it doesn't handle a
        // two good ones.
        //
        // (1) If you have a right which implies other rights and you turn,
        // it off, then maybe we should turn off all of the implied ones
        // too. For example, you turn off change (which is the combination
        // of read and write) maybe we should turn off both read and write.
        //
        // (2) If you turn on all of the component rights of one which
        // implies them all, then we should turn on that one (because
        // it implies them all).
        //
#ifdef NO_RADIOBUTTON_BEHAVIOR
        wColCompare = wCol;
#else
        for (wColCompare = COLUMN_ALLOW; wColCompare <= COLUMN_DENY; wColCompare++)
#endif
        {
            wItem = MAKELONG((WORD)iRowCompare, wColCompare);
            dwStateCompareOriginal = (DWORD)SendMessage(hChkList, CLM_GETSTATE, wItem, 0);

            //
            // If the other box is disabled, then it represents an
            // inherited right so don't do anything with it.
            //
            // nb: Depending on NO_RADIOBUTTON_BEHAVIOR, this may continue to the
            // for(wColCompare) loop or the while(iRowCompare) loop as appropriate
            //
            if (dwStateCompareOriginal & CLST_DISABLED)
                continue;

            dwStateCompare = dwStateCompareOriginal;

            if (dwState & CLST_CHECKED)
            {
                if (wCol == wColCompare)
                {
                    //
                    // If this right implies some other right,
                    // then turn it on too.
                    //
                    if ((bSameGuid || bNullGuid) && AllFlagsOn(pAccess->mask, pAccessCompare->mask))
                    {
                        if (!bInheritFlags ||
                            AllFlagsOn(pAccess->dwFlags & ACE_INHERIT_ALL, pAccessCompare->dwFlags & ACE_INHERIT_ALL))
                        {
                            dwStateCompare |= CLST_CHECKED;
                        }
                    }
                }
                else
                {
#ifndef NO_RADIOBUTTON_BEHAVIOR
                    //
                    // If this right implies or is implied by some other
                    // right in the other column, then turn it off.
                    //
                    if ( (siType == SI_PAGE_PERM || siType == SI_PAGE_ADVPERM) &&
                         (((bSameGuid || bNullGuid) && AllFlagsOn(pAccess->mask, pAccessCompare->mask)) ||
                          ((bSameGuid || bNullGuidCompare) && AllFlagsOn(pAccessCompare->mask, pAccess->mask))) )
                    {
                        if (!bInheritFlags ||
                            (AllFlagsOn(pAccessCompare->dwFlags & ACE_INHERIT_ALL, pAccess->dwFlags & ACE_INHERIT_ALL) ||
                             AllFlagsOn(pAccess->dwFlags & ACE_INHERIT_ALL, pAccessCompare->dwFlags & ACE_INHERIT_ALL)) )
                        {
                            dwStateCompare &= ~(CLST_CHECKED);
                        }
                    }
#endif
                }
            }
            else
            {
                if (wCol == wColCompare)
                {
                    //
                    // If this right is implied by some other right, then
                    // turn it off too.
                    //
                    if ((bSameGuid || bNullGuidCompare) && AllFlagsOn(pAccessCompare->mask, pAccess->mask))
                    {
                        if (!bInheritFlags ||
                            AllFlagsOn(pAccessCompare->dwFlags & ACE_INHERIT_ALL, pAccess->dwFlags & ACE_INHERIT_ALL))
                        {
                            dwStateCompare &= ~(CLST_CHECKED);
                        }
                    }
                }
            }

            if (dwStateCompareOriginal != dwStateCompare)
            {
                SendMessage(hChkList, CLM_SETSTATE, wItem, (LPARAM)dwStateCompare);
                //If a checkbox was intially checked and and now unchecked, add to 
                //h[Allow|Deny]UncheckedAccess.
                if( dwStateCompareOriginal & CLST_CHECKED && !(dwStateCompare & CLST_CHECKED) )
                {
                    if( phDenyUncheckedAccess && ( wColCompare == COLUMN_DENY ) )
                        DSA_AppendItem(*phDenyUncheckedAccess, &pAccessCompare);
                    if( phAllowUncheckedAccess && ( wColCompare == COLUMN_ALLOW ) )
                        DSA_AppendItem(*phAllowUncheckedAccess, &pAccessCompare);
                }

            }
        }
    }

    TraceLeaveVoid();
}


UINT
GetAcesFromCheckList(HWND hChkList,
                     PSID pSid,                 // All aces get this SID
                     BOOL fPerm,                // Create ACCESS or AUDIT aces?
                     BOOL fAceFlagsProvided,    // Use uAceFlagsAll instead of pAccess->dwFlags
                     UCHAR uAceFlagsAll,        // All aces get these flags
                     const GUID *pInheritGUID,  // All aces get this inherit GUID
                     HDPA hEntries)             // Store new aces here
{
    UINT cCheckRows;
    UINT iCheckRow;
    UINT cbSidSize;
    UINT iCount;
    BOOL bInheritTypePresent = FALSE;

    TraceEnter(TRACE_MISC, "GetAcesFromCheckList");
    TraceAssert(hChkList != NULL);
    TraceAssert(pSid != NULL);
    TraceAssert(hEntries != NULL);

    cbSidSize = GetLengthSid(pSid);

    if (pInheritGUID == NULL)
        pInheritGUID = &GUID_NULL;
    else if (!IsNullGUID(pInheritGUID))
        bInheritTypePresent = TRUE;

    //
    // First clear out the old HDPA
    //
    iCount = DPA_GetPtrCount(hEntries);
    while (iCount != 0)
    {
        --iCount;
        LocalFree(DPA_FastGetPtr(hEntries, iCount));
        DPA_DeletePtr(hEntries, iCount);
    }

    cCheckRows = (UINT)SendMessage(hChkList, CLM_GETITEMCOUNT, 0, 0);
    for (iCheckRow = 0; iCheckRow < cCheckRows; iCheckRow++)
    {
        PSI_ACCESS pAccess;
        DWORD dwObjectFlagsNew;
        WORD wCol;
        UCHAR uAceFlagsNew;

        pAccess = (PSI_ACCESS)SendMessage(hChkList, CLM_GETITEMDATA, iCheckRow, 0);

        uAceFlagsNew = (UCHAR)(fAceFlagsProvided ? uAceFlagsAll : pAccess->dwFlags);

        dwObjectFlagsNew = 0;
        if (!IsNullGUID(pAccess->pguid))
            dwObjectFlagsNew |= ACE_OBJECT_TYPE_PRESENT;

        if (bInheritTypePresent)
            dwObjectFlagsNew |= ACE_INHERITED_OBJECT_TYPE_PRESENT;

        wCol = COLUMN_ALLOW;
        while (wCol == COLUMN_ALLOW || wCol == COLUMN_DENY)
        {
            WPARAM        wItem;
            DWORD         dwState;

            wItem = MAKELONG((WORD)iCheckRow, wCol);
            dwState = (DWORD)SendMessage(hChkList, CLM_GETSTATE, wItem, 0);

            if ((dwState & CLST_CHECKED) && !(dwState & CLST_DISABLED))
            {
                //
                // Ok, time to make an ACE for this check mark, see if we
                // can merge it into an already existing ACE, or whether we
                // we need to create a new entry
                //
                UCHAR uAceTypeNew;
                DWORD dwMaskNew = pAccess->mask;
                UINT cbSize = SIZEOF(KNOWN_ACE);

                if (fPerm)
                {
                    if (wCol == COLUMN_ALLOW)
                        uAceTypeNew = ACCESS_ALLOWED_ACE_TYPE;
                    else
                        uAceTypeNew = ACCESS_DENIED_ACE_TYPE;
                }
                else
                {
                    uAceTypeNew = SYSTEM_AUDIT_ACE_TYPE;
                    uAceFlagsNew &= ~(SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG);

                    if (wCol == COLUMN_ALLOW)
                        uAceFlagsNew |= SUCCESSFUL_ACCESS_ACE_FLAG;
                    else
                        uAceFlagsNew |= FAILED_ACCESS_ACE_FLAG;
                }

                if (dwObjectFlagsNew != 0)
                {
                    uAceTypeNew += (ACCESS_ALLOWED_OBJECT_ACE_TYPE - ACCESS_ALLOWED_ACE_TYPE);
                    cbSize = SIZEOF(KNOWN_OBJECT_ACE);

                    if (dwObjectFlagsNew & ACE_OBJECT_TYPE_PRESENT)
                        cbSize += SIZEOF(GUID);

                    if (dwObjectFlagsNew & ACE_INHERITED_OBJECT_TYPE_PRESENT)
                        cbSize += SIZEOF(GUID);
                }

                cbSize += cbSidSize - SIZEOF(ULONG);

                //
                // See if it exists
                //
                iCount = DPA_GetPtrCount(hEntries);
                while(iCount != 0)
                {
                    PACE_HEADER pAce;
                    BOOL bObjectTypePresent = FALSE;
                    const GUID *pObjectType = NULL;

                    --iCount;
                    pAce = (PACE_HEADER)DPA_FastGetPtr(hEntries, iCount);

                    if (IsObjectAceType(pAce))
                        pObjectType = RtlObjectAceObjectType(pAce);

                    if (!pObjectType)
                        pObjectType = &GUID_NULL;
                    else
                        bObjectTypePresent = TRUE;

                    //
                    // Test the new ACE against each existing ACE to see if
                    // we can combine them.
                    //
                    if (IsEqualACEType(pAce->AceType, uAceTypeNew))
                    {
                        DWORD dwMergeFlags = 0;
                        DWORD dwMergeStatus;
                        DWORD dwMergeResult;

                        if (dwObjectFlagsNew & ACE_OBJECT_TYPE_PRESENT)
                            dwMergeFlags |= MF_OBJECT_TYPE_1_PRESENT;

                        if (bObjectTypePresent)
                            dwMergeFlags |= MF_OBJECT_TYPE_2_PRESENT;

                        if (!(dwMergeFlags & (MF_OBJECT_TYPE_1_PRESENT | MF_OBJECT_TYPE_2_PRESENT)))
                        {
                            // Neither are present, so they are the same
                            dwMergeFlags |= MF_OBJECT_TYPE_EQUAL;
                        }
                        else if (IsSameGUID(pAccess->pguid, pObjectType))
                            dwMergeFlags |= MF_OBJECT_TYPE_EQUAL;

                        if (!fPerm)
                            dwMergeFlags |= MF_AUDIT_ACE_TYPE;

                        dwMergeStatus = MergeAceHelper(uAceFlagsNew,
                                                       dwMaskNew,
                                                       pAce->AceFlags,
                                                       ((PKNOWN_ACE)pAce)->Mask,
                                                       dwMergeFlags,
                                                       &dwMergeResult);

                        if (dwMergeStatus == MERGE_MODIFIED_FLAGS)
                        {
                            uAceFlagsNew = (UCHAR)dwMergeResult;
                            dwMergeStatus = MERGE_OK_1;
                        }
                        else if (dwMergeStatus == MERGE_MODIFIED_MASK)
                        {
                            dwMaskNew = dwMergeResult;
                            dwMergeStatus = MERGE_OK_1;
                        }

                        if (dwMergeStatus == MERGE_OK_1)
                        {
                            //
                            // The new ACE implies the existing ACE, so
                            // the existing one can be removed.
                            //
                            LocalFree(pAce);
                            DPA_DeletePtr(hEntries, iCount);
                            //
                            // Keep looking.  Maybe we can remove some more entries
                            // before adding the new one.
                            //
                        }
                        else if (dwMergeStatus == MERGE_OK_2)
                        {
                            iCount = 1;     // non-zero for match found
                            break;
                        }
                    }
                }

                //
                // Otherwise, add it
                //
                if (iCount == 0)
                {
                    PACE_HEADER pAce = (PACE_HEADER)LocalAlloc(LPTR, cbSize);

                    if (pAce)
                    {
                        PSID pSidT;

                        pAce->AceType  = uAceTypeNew;
                        pAce->AceFlags = uAceFlagsNew;
                        pAce->AceSize  = (USHORT)cbSize;
                        ((PKNOWN_ACE)pAce)->Mask = dwMaskNew;
                        pSidT = &((PKNOWN_ACE)pAce)->SidStart;

                        if (dwObjectFlagsNew != 0)
                        {
                            GUID *pGuid;

                            ((PKNOWN_OBJECT_ACE)pAce)->Flags = dwObjectFlagsNew;

                            pGuid = RtlObjectAceObjectType(pAce);
                            if (pGuid)
                            {
                                if (pAccess->pguid)
                                    *pGuid = *pAccess->pguid;
                                else
                                    *pGuid = GUID_NULL;
                            }

                            pGuid = RtlObjectAceInheritedObjectType(pAce);
                            if (pGuid)
                                *pGuid = *pInheritGUID;

                            pSidT = RtlObjectAceSid(pAce);
                        }

                        CopyMemory(pSidT, pSid, cbSidSize);
                        DPA_AppendPtr(hEntries, pAce);
                    }
                }
            }

            wCol++;
        }
    }

    iCount = DPA_GetPtrCount(hEntries);
    TraceLeaveValue(iCount);
}

LONG
CACEPage::OnApply(HWND hDlg, BOOL /*bClose*/)
{
    const GUID *pInheritGUID;
    UCHAR uAceFlagsNew = 0;
    HDPA hEntries;
	BOOL bAclBloated = FALSE;
	//
	//If this page is property page and user has not clicked on
	//the object page, aclbloat must be checked from this page
	//only.
	//
	if((m_siFlags == SI_ACCESS_PROPERTY) && !m_pOtherPage)
		bAclBloated = IsAclBloated(hDlg);

	if(m_siFlags != SI_ACCESS_PROPERTY)
		bAclBloated = IsAclBloated(hDlg);
	
	if(bAclBloated)
		return PSNRET_INVALID_NOCHANGEPAGE;
    
	if (!m_fPageDirty)
        return PSNRET_NOERROR;

    TraceEnter(TRACE_ACEEDIT, "CACEPage::Apply");


	
    //
    // Determine inheritance for containers
    //
    pInheritGUID = &GUID_NULL;
    if ((m_siObjectInfo.dwFlags & SI_CONTAINER) != 0)
    {
        PSI_INHERIT_TYPE psiInheritType = NULL;
        HWND hInheritType = GetDlgItem( hDlg, IDC_ACEE_INHERITTYPE);

        int iSel = (int)SendMessage(hInheritType, CB_GETCURSEL, 0,0);

        if (iSel != CB_ERR)
        {
            psiInheritType = (PSI_INHERIT_TYPE)SendMessage(hInheritType,
                                                           CB_GETITEMDATA,
                                                           iSel,
                                                           0);
        }

        if (psiInheritType != (PSI_INHERIT_TYPE)CB_ERR && psiInheritType != NULL)
        {
            pInheritGUID = psiInheritType->pguid;
            uAceFlagsNew = (UCHAR)(psiInheritType->dwFlags & VALID_INHERIT_FLAGS);
        }
        else if (m_pAce)
        {
            uAceFlagsNew = m_pAce->AceFlags;
        }

        if (m_fInheritImmediateEnabled)
        {
            if (IsDlgButtonChecked(hDlg, IDC_ACEE_INHERITIMMEDIATE) == BST_CHECKED)
                uAceFlagsNew |= NO_PROPAGATE_INHERIT_ACE;
            else
                uAceFlagsNew &= ~NO_PROPAGATE_INHERIT_ACE;
        }
    }

    if (m_phEntries != NULL)
    {
        if (*m_phEntries == NULL)
            *m_phEntries = DPA_Create(4);

        GetAcesFromCheckList(GetDlgItem(hDlg, IDC_ACEE_LIST),
                             m_pSid,
                             m_siPageType == SI_PAGE_ADVPERM,
                             TRUE,
                             uAceFlagsNew,
                             pInheritGUID,
                             *m_phEntries);
    }

    if (m_pdwResult)
        *m_pdwResult |= (m_siFlags == SI_ACCESS_PROPERTY ? EAE_NEW_PROPERTY_ACE : EAE_NEW_OBJECT_ACE);
    m_fPageDirty = FALSE;

    TraceLeaveValue(PSNRET_NOERROR);
}

BOOL
CACEPage::IsAclBloated(HWND hDlg)
{
    TraceEnter(TRACE_MISC, "CACEPage::ShowAclBloat");
    
	HDPA hEntries = NULL;
	HDPA hPropEntries = NULL;
	
	BOOL bReturn = FALSE;

	hEntries = GetAceList(hDlg);

	if(m_pOtherPage)
	{
		hPropEntries = m_pOtherPage->GetAceList(m_pOtherPage->m_hwnd);
	}

	CACLBloat bloat(m_psi,
					m_psi2,
					m_siPageType,
					&m_siObjectInfo,
					hEntries,
					hPropEntries);	
	if(bloat.IsAclBloated())
		bReturn = bloat.DoModalDialog(hDlg);

	if(hEntries)
		DestroyDPA(hEntries);

	if(hPropEntries)
		DestroyDPA(hPropEntries);

	return bReturn;
}


HDPA
CACEPage::GetAceList(HWND hDlg)
{
	TraceEnter(TRACE_ACEEDIT, "CACEPage::GetAceList");
    
	if (!m_fPageDirty)
		return NULL;
    //
    // Determine inheritance for containers
    //
    const GUID *pInheritGUID = &GUID_NULL;
	UCHAR uAceFlagsNew = 0;
	HDPA hEntries = NULL;

    if ((m_siObjectInfo.dwFlags & SI_CONTAINER) != 0)
    {
        PSI_INHERIT_TYPE psiInheritType = NULL;
        HWND hInheritType = GetDlgItem( hDlg, IDC_ACEE_INHERITTYPE);

        int iSel = (int)SendMessage(hInheritType, CB_GETCURSEL, 0,0);

        if (iSel != CB_ERR)
        {
            psiInheritType = (PSI_INHERIT_TYPE)SendMessage(hInheritType,
                                                           CB_GETITEMDATA,
                                                           iSel,
                                                           0);
        }

        if (psiInheritType != (PSI_INHERIT_TYPE)CB_ERR && psiInheritType != NULL)
        {
            pInheritGUID = psiInheritType->pguid;
            uAceFlagsNew = (UCHAR)(psiInheritType->dwFlags & VALID_INHERIT_FLAGS);
        }
        else if (m_pAce)
        {
            uAceFlagsNew = m_pAce->AceFlags;
        }

        if (m_fInheritImmediateEnabled)
        {
            if (IsDlgButtonChecked(hDlg, IDC_ACEE_INHERITIMMEDIATE) == BST_CHECKED)
                uAceFlagsNew |= NO_PROPAGATE_INHERIT_ACE;
            else
                uAceFlagsNew &= ~NO_PROPAGATE_INHERIT_ACE;
        }
    }

	hEntries = DPA_Create(4);

	if(hEntries)
	{
		GetAcesFromCheckList(GetDlgItem(hDlg, IDC_ACEE_LIST),
							 m_pSid,
							 m_siPageType == SI_PAGE_ADVPERM,
							 TRUE,
							 uAceFlagsNew,
							 pInheritGUID,
							 hEntries);
	}
	return hEntries;
}



BOOL
CACEPage::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_INITDIALOG:
        InitDlg(hDlg);
        break;

    case WM_DESTROY:
        EmptyCheckList(GetDlgItem(hDlg, IDC_ACEE_LIST));
        break;

    case PWM_SELECT_PAGE:
        PropSheet_SetCurSel(GetParent(hDlg), lParam, wParam);
        break;

    case WM_COMMAND:
        switch (GET_WM_COMMAND_ID(wParam, lParam))
        {
        case IDC_ACEE_NAMEBUTTON:
            if (OnChangeName(hDlg))
            {
                PropSheet_Changed(GetParent(hDlg), hDlg);
                m_fPageDirty = TRUE;
            }
            break;

        case IDC_ACEE_INHERITTYPE:
            if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
            {
                HandleSelChange(hDlg, (HWND)lParam);
                PropSheet_Changed(GetParent(hDlg), hDlg);
                m_fPageDirty = TRUE;
            }
            break;

        case IDC_ACEE_INHERITIMMEDIATE:
            if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
            {
                PropSheet_Changed(GetParent(hDlg), hDlg);
                m_fPageDirty = TRUE;
            }
            break;

        case IDC_ACEE_CLEAR:
            if (OnClearAll(hDlg))
            {
                PropSheet_Changed(GetParent(hDlg), hDlg);
                m_fPageDirty = TRUE;
            }
            break;

        default:
            return FALSE;
        }
        break;

    case WM_NOTIFY:
        switch (((NMHDR *)lParam)->code)
        {
        case CLN_CLICK:
            if (lParam)
            {
                HandleListClick((PNM_CHECKLIST)lParam, m_siPageType, FALSE);
                PropSheet_Changed(GetParent(hDlg), hDlg);
                m_fPageDirty = TRUE;
            }
            break;

        case CLN_GETCOLUMNDESC:
            {
                PNM_CHECKLIST pnmc = (PNM_CHECKLIST)lParam;
                GetDlgItemText(hDlg,
                               IDC_ACEE_ALLOW - 1 + pnmc->iSubItem,
                               pnmc->pszText,
                               pnmc->cchTextMax);
            }
            break;

        case PSN_APPLY:
            SetWindowLongPtr(hDlg,
                             DWLP_MSGRESULT,
                             OnApply(hDlg, (BOOL)(((LPPSHNOTIFY)lParam)->lParam)));
            break;


        }
        break;

	case PSM_QUERYSIBLINGS: 
		{
			BOOL bSendQuery = !m_pOtherPage;
			if(this != (CACEPage*)lParam)
				m_pOtherPage = (CACEPage*)lParam;

			if(bSendQuery)
				PostMessage(GetParent(hDlg),PSM_QUERYSIBLINGS,0,(LPARAM)this);
		}

		break;


    case WM_HELP:
        if (IsWindowEnabled(hDlg))
        {
            const DWORD *pdwHelpIDs = aAcePermHelpIDs;

            if (m_siPageType == SI_PAGE_AUDIT)
                pdwHelpIDs = aAceAuditHelpIDs;

            WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
                    c_szAcluiHelpFile,
                    HELP_WM_HELP,
                    (DWORD_PTR)pdwHelpIDs);
        }
        break;

    case WM_CONTEXTMENU:
        if (IsWindowEnabled(hDlg))
        {
            HWND hwnd = (HWND)wParam;
            const DWORD *pdwHelpIDs = aAcePermHelpIDs;

            if (m_siPageType == SI_PAGE_AUDIT)
                pdwHelpIDs = aAceAuditHelpIDs;

            //
            // Some of the checkboxes may be scrolled out of view, but
            // they are still detected by WinHelp, so we jump through
            // a few extra hoops here.
            //
            if (hwnd == hDlg)
            {
                POINT pt;
                pt.x = GET_X_LPARAM(lParam);
                pt.y = GET_Y_LPARAM(lParam);

                ScreenToClient(hDlg, &pt);
                hwnd = ChildWindowFromPoint(hDlg, pt);
                if (hDlg == hwnd)
                    break;
            }

            //
            // WinHelp looks for child windows, but we don't have help id's
            // for the permission checkboxes.  If the request is for the
            // checklist window, fake out WinHelp by referring to one of
            // the static labels just above the list.
            //
            if (GetDlgCtrlID(hwnd) == IDC_ACEE_LIST)
                hwnd = GetWindow((HWND)wParam, GW_HWNDPREV);    // Static label "Deny"

            WinHelp(hwnd,
                    c_szAcluiHelpFile,
                    HELP_CONTEXTMENU,
                    (DWORD_PTR)pdwHelpIDs);
        }
        break;

    default:
        return FALSE;
    }

    return TRUE;
}

HPROPSHEETPAGE
CreateACEPage(LPSECURITYINFO psi,
              SI_PAGE_TYPE siType,
              PACE pAce,
              BOOL bReadOnly,
              DWORD dwFlags,
              DWORD *pdwResult,
              HDPA *phEntries)
{
    HPROPSHEETPAGE hPage = NULL;
    LPCTSTR pszTitle = NULL;
    LPACEPAGE pPage;

    TraceEnter(TRACE_ACEEDIT, "CreateACEPage");
    TraceAssert(psi != NULL);
    TraceAssert(phEntries != NULL);

    pPage = new CACEPage(psi,
                         siType,
                         pAce,
                         bReadOnly,
                         dwFlags,
                         pdwResult,
                         phEntries);
    if (pPage)
    {
        int iDlgTemplate = IDD_ACEENTRY_PERM_PAGE;

        if (siType == SI_PAGE_AUDIT)
            iDlgTemplate = IDD_ACEENTRY_AUDIT_PAGE;

        if (dwFlags == SI_ACCESS_PROPERTY)
            pszTitle = MAKEINTRESOURCE(IDS_ACEE_PROPERTY_TITLE);

        hPage = pPage->CreatePropSheetPage(MAKEINTRESOURCE(iDlgTemplate), pszTitle);
    }

    TraceLeaveValue(hPage);
}

BOOL
EditACEEntry(HWND hwndOwner,
             LPSECURITYINFO psi,
             PACE pAce,
             SI_PAGE_TYPE siType,
             LPCTSTR pszObjectName,
             BOOL bReadOnly,
             DWORD *pdwResult,
             HDPA *phEntries,
             HDPA *phPropertyEntries,
             UINT nStartPage)
{
    HPROPSHEETPAGE hPage[2];
    UINT cPages = 0;
    BOOL bResult = FALSE;

    TraceEnter(TRACE_ACEEDIT, "EditACEEntry");
    TraceAssert(psi != NULL);

    if (phEntries)
    {
        hPage[cPages] = CreateACEPage(psi,
                                      siType,
                                      pAce,
                                      bReadOnly,
                                      SI_ACCESS_SPECIFIC,
                                      pdwResult,
                                      phEntries);
        if (hPage[cPages])
            cPages++;
    }

    if (phPropertyEntries)
    {
        hPage[cPages] = CreateACEPage(psi,
                                      siType,
                                      pAce,
                                      bReadOnly,
                                      SI_ACCESS_PROPERTY,
                                      pdwResult,
                                      phPropertyEntries);
        if (hPage[cPages])
            cPages++;
    }

    if (cPages)
    {
        // Build dialog title string
        LPTSTR pszCaption = NULL;
        FormatStringID(&pszCaption,
                       ::hModule,
                       siType == SI_PAGE_AUDIT ? IDS_ACEE_AUDIT_TITLE : IDS_ACEE_PERM_TITLE,
                       pszObjectName);

        PROPSHEETHEADER psh;
        psh.dwSize = SIZEOF(psh);
        psh.dwFlags = PSH_DEFAULT | PSH_NOAPPLYNOW;
        psh.hwndParent = hwndOwner;
        psh.hInstance = ::hModule;
        psh.pszCaption = pszCaption;
        psh.nPages = cPages;
        psh.nStartPage = 0;
        psh.phpage = &hPage[0];

        if (nStartPage < cPages)
            psh.nStartPage = nStartPage;

        bResult = (PropertySheet(&psh) == IDOK);

        LocalFreeString(&pszCaption);
    }

    TraceLeaveValue(bResult);
}