windows-nt/Source/XPSP1/NT/admin/display/proppage/objlist.cxx
2020-09-26 16:20:57 +08:00

1650 lines
41 KiB
C++

//+----------------------------------------------------------------------------
//
// Windows NT Directory Service Property Pages
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: objlist.cxx
//
// Contents: Link-lists of objects and list-view controls displaying objects.
//
// History: 20-Nov-97 EricB created
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "proppage.h"
#include "objlist.h"
CClassIconCache g_ClassIconCache;
//+----------------------------------------------------------------------------
//
// Class: CMemberLinkList
//
// Purpose: Linked list of membership class objects.
//
//-----------------------------------------------------------------------------
CMemberLinkList::~CMemberLinkList(void)
{
CMemberListItem * pItem = m_pListHead, * pNext;
while (pItem)
{
pNext = pItem->Next();
delete pItem;
pItem = pNext;
}
}
//+----------------------------------------------------------------------------
//
// Method: CMemberLinkList::FindItemRemove
//
// Synopsis: Search for an element with a matching DN and, if found, remove
// it from the list and return its pointer. Returns NULL if not
// found.
//
//-----------------------------------------------------------------------------
CMemberListItem *
CMemberLinkList::FindItemRemove(PWSTR pwzDN)
{
CMemberListItem * pItem = m_pListHead;
while (pItem)
{
dspAssert(pItem->m_pwzDN);
if (_wcsicmp(pItem->m_pwzDN, pwzDN) == 0)
{
if (pItem->Prev() == NULL)
{
// this item is the list head.
//
m_pListHead = pItem->Next();
}
pItem->UnLink();
return pItem;
}
pItem = pItem->Next();
}
return NULL;
}
//+----------------------------------------------------------------------------
//
// Method: CMemberLinkList::FindItemRemove
//
// Synopsis: Search for an element with a matching SID and, if found, remove
// it from the list and return its pointer. Returns NULL if not
// found.
//
//-----------------------------------------------------------------------------
CMemberListItem *
CMemberLinkList::FindItemRemove(PSID pSid)
{
CMemberListItem * pItem = m_pListHead;
while (pItem)
{
dspAssert(pItem->m_pwzDN);
if (pItem->m_pSid && EqualSid(pItem->m_pSid, pSid))
{
if (pItem->Prev() == NULL)
{
// this item is the list head.
//
m_pListHead = pItem->Next();
}
pItem->UnLink();
return pItem;
}
pItem = pItem->Next();
}
return NULL;
}
//+----------------------------------------------------------------------------
//
// Method: CMemberLinkList::RemoveFirstItem
//
// Synopsis: Remove the first item from the list.
//
//-----------------------------------------------------------------------------
CMemberListItem *
CMemberLinkList::RemoveFirstItem(void)
{
CMemberListItem * pItem = m_pListHead;
if (pItem)
{
m_pListHead = pItem->Next();
pItem->UnLink();
return pItem;
}
return NULL;
}
//+----------------------------------------------------------------------------
//
// Method: CMemberLinkList::AddItem
//
// Synopsis: Insert an item into the list.
//
//-----------------------------------------------------------------------------
BOOL
CMemberLinkList::AddItem(CMemberListItem * pItem, BOOL fMember)
{
if (!pItem->m_fIsAlreadyMember)
{
return TRUE;
}
CMemberListItem * pItemCopy;
if (m_pListHead == NULL)
{
pItemCopy = pItem->Copy();
CHECK_NULL(pItemCopy, return FALSE);
pItemCopy->m_fIsAlreadyMember = fMember;
m_pListHead = pItemCopy;
}
else
{
CMemberListItem * pCur = m_pListHead;
//
// Make sure the item isn't already in the list.
//
while (pCur)
{
dspAssert(pCur->m_pwzDN);
if (_wcsicmp(pCur->m_pwzDN, pItem->m_pwzDN) == 0)
{
return TRUE;
}
pCur = pCur->Next();
}
pItemCopy = pItem->Copy();
CHECK_NULL(pItemCopy, return FALSE);
pItemCopy->m_fIsAlreadyMember = fMember;
pItemCopy->LinkAfter(m_pListHead);
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Method: CMemberLinkList::GetItemCount
//
// Synopsis: Return the count of elements in the list.
//
//-----------------------------------------------------------------------------
int
CMemberLinkList::GetItemCount(void)
{
int cItem = 0;
CMemberListItem * pItem = m_pListHead;
while (pItem)
{
cItem++;
pItem = pItem->Next();
}
return cItem;
}
//+----------------------------------------------------------------------------
//
// Class: CDsObjList
//
// Purpose: Base class for DS object lists that employ a two column
// list view to show object Name and Folder.
//
//-----------------------------------------------------------------------------
CDsObjList::CDsObjList(HWND hPage, int idList) :
m_hPage(hPage),
m_idList(idList),
m_nCurItem(0),
m_fShowIcons(FALSE),
m_fLimitExceeded(FALSE)
{
}
CDsObjList::~CDsObjList(void)
{
}
//+----------------------------------------------------------------------------
//
// Method: CDsObjList::Init
//
// Synopsis: Initialize the list view, add its columns.
//
//-----------------------------------------------------------------------------
HRESULT
CDsObjList::Init(BOOL fShowIcons)
{
m_fShowIcons = fShowIcons;
m_hList = GetDlgItem(m_hPage, m_idList);
if (m_hList == NULL)
{
return HRESULT_FROM_WIN32(GetLastError());
}
ListView_SetExtendedListViewStyle(m_hList, LVS_EX_FULLROWSELECT);
//
// Set the column headings.
//
PTSTR ptsz;
RECT rect;
GetClientRect(m_hList, &rect);
if (!LoadStringToTchar(IDS_COL_TITLE_OBJNAME, &ptsz))
{
ReportError(GetLastError(), 0, m_hPage);
return HRESULT_FROM_WIN32(GetLastError());
}
LV_COLUMN lvc = {0};
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
lvc.cx = OBJ_LIST_NAME_COL_WIDTH;
lvc.pszText = ptsz;
lvc.iSubItem = IDX_NAME_COL;
ListView_InsertColumn(m_hList, IDX_NAME_COL, &lvc);
delete ptsz;
if (!LoadStringToTchar(IDS_COL_TITLE_OBJFOLDER, &ptsz))
{
ReportError(GetLastError(), 0, m_hPage);
return HRESULT_FROM_WIN32(GetLastError());
}
lvc.cx = rect.right - OBJ_LIST_NAME_COL_WIDTH;
lvc.pszText = ptsz;
lvc.iSubItem = IDX_FOLDER_COL;
ListView_InsertColumn(m_hList, IDX_FOLDER_COL, &lvc);
delete ptsz;
if (m_fShowIcons)
{
// Assign the imagelist to the listview
//
ListView_SetImageList(m_hList,
g_ClassIconCache.GetImageList(),
LVSIL_SMALL);
}
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Method: GetNameParts
//
// Synopsis: The folder path and object name should be separated by a
// newline character. Return a pointer to the name and allocate
// a buffer for the folder part. Return NULL for the folder part
// if a newline is not found. No folder is returned if the input
// pointer pcstrFolder is NULL.
//
//-----------------------------------------------------------------------------
void
GetNameParts(const CStr& cstrCanonicalNameEx, CStr& cstrFolder, CStr & cstrName)
{
int nCR = cstrCanonicalNameEx.Find(TEXT('\n'));
if (-1 != nCR)
{
cstrFolder = cstrCanonicalNameEx.Left(nCR);
cstrName = cstrCanonicalNameEx.Right(cstrCanonicalNameEx.GetLength() - nCR - 1);
// Remove any escaping from the name
//
int nBackSlash;
while ((nBackSlash = cstrName.Find(TEXT('\\'))) != -1)
{
CStr cstrTemp = cstrName.Left(nBackSlash);
int count = cstrName.GetLength() - nBackSlash - 1;
if (count > 0)
{
cstrTemp += cstrName.Right(cstrName.GetLength() - nBackSlash - 1);
}
cstrName = cstrTemp;
}
}
else
{
cstrName = cstrCanonicalNameEx;
cstrFolder.Empty();
}
}
//+----------------------------------------------------------------------------
//
// Method: CDsObjList::InsertIntoList
//
// Synopsis: Insert the item into the listview control.
//
//-----------------------------------------------------------------------------
HRESULT
CDsObjList::InsertIntoList(PTSTR ptzDisplayName, PVOID pData, int iIcon)
{
HRESULT hr = S_OK;
//
// The name and folder should be separated by a new line character.
//
CStr cstrFolder, cstrName;
CStr cstrDisplayName = ptzDisplayName;
GetNameParts(cstrDisplayName, cstrFolder, cstrName);
CHECK_HRESULT(hr, return hr);
LV_ITEM lvi = {0};
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iSubItem = IDX_NAME_COL;
lvi.pszText = const_cast<PTSTR>((LPCTSTR)cstrName);
lvi.lParam = (LPARAM)pData;
lvi.iItem = m_nCurItem;
if (-1 != iIcon)
{
lvi.mask |= LVIF_IMAGE;
// if the limit is exceeded use the default icon.
lvi.iImage = (m_fLimitExceeded) ? 0 : iIcon;
}
int NewIndex = ListView_InsertItem(m_hList, &lvi);
dspAssert(NewIndex != -1);
if (!cstrFolder.IsEmpty())
{
ListView_SetItemText(m_hList, NewIndex, IDX_FOLDER_COL,
const_cast<PTSTR>((LPCTSTR)cstrFolder));
//delete ptzFolder;
}
m_nCurItem++;
return hr;
}
//+----------------------------------------------------------------------------
//
// Method: CDsObjList::GetItem
//
// Synopsis: Returns the name and item data for the indicated item. Any of
// the input pointers can be NULL to skip that parameter.
//
//-----------------------------------------------------------------------------
HRESULT
CDsObjList::GetItem(int index, PTSTR * pptzName, PVOID * ppData)
{
TCHAR tzBuf[256];
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iItem = index;
lvi.iSubItem = IDX_NAME_COL;
lvi.pszText = tzBuf;
lvi.cchTextMax = 256;
if (!ListView_GetItem(m_hList, &lvi))
{
return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
}
if (pptzName)
{
if (lvi.pszText)
{
*pptzName = new TCHAR[_tcslen(lvi.pszText) + 1];
CHECK_NULL_REPORT(*pptzName, m_hPage, return FALSE);
_tcscpy(*pptzName, lvi.pszText);
}
else
{
*pptzName = NULL;
}
}
if (ppData)
{
*ppData = (PVOID)lvi.lParam;
}
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Method: CDsObjList::GetCurListItem
//
// Synopsis: Returns the index, name (in an allocated buffer), and pointer
// to the item data. Any of the input pointers can be NULL to skip
// that parameter.
//
//-----------------------------------------------------------------------------
BOOL
CDsObjList::GetCurListItem(int * pIndex, PTSTR * pptzName, PVOID * ppData)
{
int i = ListView_GetNextItem(m_hList, -1, LVNI_SELECTED);
if (i < 0)
{
dspDebugOut((DEB_ITRACE, "DsProp: no list selection.\n"));
return FALSE;
}
HRESULT hr = GetItem(i, pptzName, ppData);
if (FAILED(hr))
{
dspAssert(FALSE);
return FALSE;
}
if (pIndex)
{
*pIndex = i;
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Method: CDsObjList::GetCurListItems
//
// Synopsis: Returns an array of indexes, names (in an allocated buffers), and pointers
// to the items data. Any of the input pointers can be NULL to skip
// that parameter.
//
//-----------------------------------------------------------------------------
BOOL
CDsObjList::GetCurListItems(int ** ppIndex, PTSTR ** ppptzName, PVOID ** pppData, int* pNumSelected)
{
int iStartPoint = -1;
int i = -1;
UINT nSelected = ListView_GetSelectedCount(m_hList);
if (ppIndex)
{
*ppIndex = new int[nSelected];
}
if (ppptzName)
{
*ppptzName = new PTSTR[nSelected];
}
if (pppData)
{
*pppData = new PVOID[nSelected];
}
for (UINT idx = 0; idx < nSelected; idx++)
{
i = ListView_GetNextItem(m_hList, iStartPoint, LVNI_SELECTED);
if (i < 0)
{
dspDebugOut((DEB_ITRACE, "DsProp: no list selection.\n"));
if (ppIndex)
{
delete[] ppIndex;
*ppIndex = 0;
}
if (ppptzName)
{
delete[] ppptzName;
*ppptzName = 0;
}
if (pppData)
{
delete[] pppData;
*pppData = 0;
}
return FALSE;
}
HRESULT hr;
if (ppptzName == NULL && pppData == NULL)
{
hr = GetItem(i, NULL, NULL);
}
else if (pppData == NULL)
{
hr = GetItem(i, &((*ppptzName)[idx]), NULL);
}
else if (ppptzName == NULL)
{
hr = GetItem(i, NULL, &((*pppData)[idx]));
}
else
{
hr = GetItem(i, &((*ppptzName)[idx]), &((*pppData)[idx]));
}
if (FAILED(hr))
{
dspAssert(FALSE);
if (ppIndex != NULL)
{
delete[] ppIndex;
*ppIndex = 0;
}
if (ppptzName != NULL)
{
delete[] ppptzName;
*ppptzName = 0;
}
if (pppData != NULL)
{
delete[] pppData;
*pppData = 0;
}
return FALSE;
}
iStartPoint = i;
(*ppIndex)[idx] = i;
}
*pNumSelected = nSelected;
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Method: CDsMembershipList::InsertIntoList
//
// Synopsis: Insert the item into the listview control.
//
// Arguments: [pwzPath] - object DN.
// [iIcon] - object icon, -1 means ignore.
// [fAlreadyMember] - already member of group, not a new member in an add/apply-pending state.
// [fPrimary] - member by virtue of primaryGroupID attribute.
// [fIgnoreDups] - don't report error if already in list; used for merging in reverse membership.
// [fDontChkDups] - don't check for duplicates; used for initial listing of direct membership.
//
//-----------------------------------------------------------------------------
HRESULT
CDsMembershipList::InsertIntoList(PWSTR pwzPath, int iIcon, BOOL fAlreadyMember,
BOOL fPrimary, BOOL fIgnoreDups,
BOOL fDontChkDups, ULONG ulScopeType)
{
HRESULT hr = S_OK, hrRet = S_OK;
PWSTR pwzPathCopy = NULL, pwzCanEx = NULL;
PTSTR ptzCanEx = NULL;
CMemberListItem * pListItem = NULL;
BOOL fCanBePrimary = FALSE;
//
// Convert the distinguished name to a more friendly variant for display
// in the list.
//
if (DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN == ulScopeType)
{
if (!UnicodeToTchar(pwzPath, &ptzCanEx))
{
REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
hr = E_OUTOFMEMORY;
goto ErrorCleanup;
}
PTSTR ptzSlash = _tcspbrk(ptzCanEx, TEXT("\\/"));
if (ptzSlash)
{
*ptzSlash = TEXT('\n');
}
}
else
{
hr = CrackName(pwzPath, &pwzCanEx, GET_OBJ_CAN_NAME_EX, m_hPage);
if (DS_NAME_ERROR_NO_MAPPING == HRESULT_CODE(hr))
{
hrRet = MAKE_HRESULT(SEVERITY_ERROR, 0, DS_NAME_ERROR_NO_MAPPING);
hr = S_OK;
}
CHECK_HRESULT(hr, goto ErrorCleanup);
if (!UnicodeToTchar(pwzCanEx, &ptzCanEx))
{
LocalFreeStringW(&pwzCanEx);
REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
hr = E_OUTOFMEMORY;
goto ErrorCleanup;
}
LocalFreeStringW(&pwzCanEx);
}
if (!fDontChkDups)
{
//
// Check to see if the item is already in the list.
//
LV_ITEM lvi;
lvi.mask = LVIF_PARAM;
lvi.iItem = 0;
lvi.iSubItem = IDX_NAME_COL;
while (ListView_GetItem(m_hList, &lvi))
{
pListItem = (CMemberListItem *)lvi.lParam;
dspAssert(pListItem);
if (_wcsicmp(pListItem->m_pwzDN, pwzPath) == 0)
{
if (fIgnoreDups)
{
DO_DEL(ptzCanEx);
return S_OK;
}
CStr cstrName;
CStr cstrCanEx = ptzCanEx;
CStr cstrFolder;
GetNameParts(cstrCanEx, cstrFolder, cstrName);
ErrMsgParam(IDS_GRP_ALREADY_MEMBER,
reinterpret_cast<LPARAM>((LPCTSTR)cstrName), m_hPage);
DO_DEL(ptzCanEx);
return HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
}
lvi.iItem++;
}
}
//
// Put the item into the list.
//
pListItem = new CMemberListItem;
CHECK_NULL_REPORT(pListItem, m_hPage, goto ErrorCleanup);
if (!AllocWStr(pwzPath, &pwzPathCopy))
{
REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
hr = E_OUTOFMEMORY;
goto ErrorCleanup;
}
pListItem->m_ptzName = ptzCanEx;
pListItem->m_pwzDN = pwzPathCopy;
pListItem->m_fIsAlreadyMember = fAlreadyMember;
pListItem->m_fCanBePrimary = fCanBePrimary;
pListItem->m_fIsPrimary = fPrimary;
pListItem->m_ulScopeType = ulScopeType;
hr = CDsObjList::InsertIntoList(ptzCanEx, pListItem, iIcon);
CHECK_HRESULT(hr, goto ErrorCleanup);
return hrRet;
ErrorCleanup:
DO_DEL(pwzPathCopy);
DO_DEL(ptzCanEx);
DO_DEL(pListItem);
return hr;
}
//+----------------------------------------------------------------------------
//
// Method: CDsMembershipList::InsertIntoList
//
// Synopsis: Insert the item into the listview control. This method uses
// the object-SID to identify the new group member which in this
// case is from an external domain.
//
// Arguments: [pSid] - a binary SID.
// [pwzPath] - an object name in WINNT format (domain\name or
// domain/name).
//
//-----------------------------------------------------------------------------
HRESULT
CDsMembershipList::InsertIntoList(PSID pSid, PWSTR pwzPath)
{
HRESULT hr;
PTSTR ptzCanEx, ptzSlash;
CMemberListItem * pListItem = NULL;
if (!UnicodeToTchar(pwzPath, &ptzCanEx))
{
REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
return E_OUTOFMEMORY;
}
ptzSlash = _tcspbrk(ptzCanEx, TEXT("\n"));
if (!ptzSlash)
{
ptzSlash = _tcspbrk(ptzCanEx, TEXT("/\\"));
dspAssert(ptzSlash);
if (ptzSlash)
{
*ptzSlash = TEXT('\n');
}
}
//
// Check to see if the item is already in the list. Use the display name
// (canonical name) rather than the DN since the DN of an existing external
// domain group member will be different from the initial path name (the
// <SID=01050xxx> name).
//
LV_ITEM lvi;
lvi.mask = LVIF_PARAM;
lvi.iItem = 0;
lvi.iSubItem = IDX_NAME_COL;
while (ListView_GetItem(m_hList, &lvi))
{
pListItem = (CMemberListItem *)lvi.lParam;
dspAssert(pListItem);
if (_tcsicmp(pListItem->m_ptzName, ptzCanEx) == 0)
{
CStr cstrName;
CStr cstrCanEx = ptzCanEx;
CStr cstrFolder;
GetNameParts(cstrCanEx, cstrFolder, cstrName);
ErrMsgParam(IDS_GRP_ALREADY_MEMBER,
reinterpret_cast<LPARAM>((LPCTSTR)cstrName), m_hPage);
DO_DEL(ptzCanEx);
return HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
}
lvi.iItem++;
}
//
// Put the item into the list.
//
pListItem = new CMemberListItem;
CHECK_NULL_REPORT(pListItem, m_hPage, return E_OUTOFMEMORY);
PWSTR pwzSidPath;
CStrW strSIDname;
ConvertSidToPath(pSid, strSIDname);
if (!AllocWStr(const_cast<PWSTR>((LPCWSTR)strSIDname), &pwzSidPath))
{
REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
hr = E_OUTOFMEMORY;
goto ErrorCleanup;
}
pListItem->m_ptzName = ptzCanEx;
pListItem->m_pwzDN = pwzSidPath;
pListItem->m_fIsExternal = TRUE;
pListItem->SetSid(pSid);
hr = CDsObjList::InsertIntoList(ptzCanEx, pListItem);
CHECK_HRESULT(hr, goto ErrorCleanup);
return S_OK;
ErrorCleanup:
DO_DEL(pwzSidPath);
DO_DEL(ptzCanEx);
DO_DEL(pListItem);
return hr;
}
//+----------------------------------------------------------------------------
//
// Method: CDsMembershipList::InsertIntoList
//
// Synopsis: Insert the item into the listview control.
//
//-----------------------------------------------------------------------------
HRESULT
CDsMembershipList::InsertIntoList(CMemberListItem * pItem)
{
HRESULT hr = S_OK;
PWSTR pwzCanEx = NULL;
PTSTR ptzCanEx = NULL;
//
// Convert the 1779 name to a more friendly variant for display
// in the list.
//
hr = CrackName(pItem->m_pwzDN, &pwzCanEx, GET_OBJ_CAN_NAME_EX, m_hPage);
CHECK_HRESULT(hr, goto ErrorCleanup);
if (!UnicodeToTchar(pwzCanEx, &ptzCanEx))
{
LocalFreeStringW(&pwzCanEx);
REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
hr = E_OUTOFMEMORY;
goto ErrorCleanup;
}
LocalFreeStringW(&pwzCanEx);
hr = CDsObjList::InsertIntoList(ptzCanEx, pItem);
CHECK_HRESULT(hr, goto ErrorCleanup);
return S_OK;
ErrorCleanup:
DO_DEL(ptzCanEx);
DO_DEL(pItem);
return hr;
}
//+----------------------------------------------------------------------------
//
// Method: CDsObjList::RemoveListItem
//
// Synopsis: Removes the indicated list item.
//
//-----------------------------------------------------------------------------
BOOL
CDsObjList::RemoveListItem(int Index)
{
if (!ListView_DeleteItem(m_hList, Index))
{
REPORT_ERROR(GetLastError(), m_hPage);
return FALSE;
}
m_nCurItem--;
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Method: CDsMembershipList::RemoveListItem
//
// Synopsis: Removes the indicated list item, deleting the item data obj.
//
//-----------------------------------------------------------------------------
BOOL
CDsMembershipList::RemoveListItem(int Index)
{
CMemberListItem * pItem;
LV_ITEM lvi;
lvi.mask = LVIF_PARAM;
lvi.iItem = Index;
lvi.iSubItem = IDX_NAME_COL;
if (!ListView_GetItem(m_hList, &lvi))
{
dspAssert(FALSE);
return FALSE;
}
pItem = (CMemberListItem *)lvi.lParam;
if (pItem)
{
delete pItem;
}
if (!ListView_DeleteItem(m_hList, Index))
{
REPORT_ERROR(GetLastError(), m_hPage);
return FALSE;
}
m_nCurItem--;
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Method: CDsMembershipList::ClearList
//
// Synopsis: Remove all list items, freeing memory.
//
//-----------------------------------------------------------------------------
void
CDsMembershipList::ClearList(void)
{
CMemberListItem * pItem;
LV_ITEM lvi;
lvi.mask = LVIF_PARAM;
lvi.iItem = 0;
lvi.iSubItem = IDX_NAME_COL;
while (ListView_GetItem(m_hList, &lvi))
{
pItem = (CMemberListItem *)lvi.lParam;
if (pItem)
{
delete pItem;
}
lvi.iItem++;
}
ListView_DeleteAllItems(m_hList);
m_nCurItem = 0;
}
//+----------------------------------------------------------------------------
//
// Method: CDsMembershipList::GetIndex
//
// Synopsis: Find the list entry whose DN matches and return the index.
//
// Arguments: [pwzDN] - DN to match, matches only first instance.
// [ulStart] - Index on which to start search.
// [ulEnd] - Search end index. If zero or less than ulStart,
// search to the end of the list.
//
//-----------------------------------------------------------------------------
int
CDsMembershipList::GetIndex(LPCWSTR pwzDN, ULONG ulStart, ULONG ulEnd)
{
int i = ulStart;
CMemberListItem * pItem;
while (TRUE)
{
if (FAILED(GetItem(i, &pItem)))
{
return -1;
}
if (_wcsicmp(pwzDN, pItem->m_pwzDN) == 0)
{
return i;
}
if (ulEnd && (ULONG)i >= ulEnd)
{
return -1;
}
i++;
}
}
//+----------------------------------------------------------------------------
//
// Method: CDsMembershipList::SetMemberIcons
//
// Synopsis: Query the DS for the class and userAccountControl of the list's
// members. Use the returned info to select an icon for each item.
//
//-----------------------------------------------------------------------------
HRESULT
CDsMembershipList::SetMemberIcons(CDsPropPageBase *pPage)
{
HRESULT hr = S_OK;
//
// Just put this here so /W4 doesn't complain when compiling for Win9x
//
pPage;
if (0 == g_ulMemberFilterCount)
{
return S_OK;
}
if ((ULONG)GetCount() > g_ulMemberQueryLimit)
{
m_fLimitExceeded = TRUE;
return S_OK;
}
#if defined (DSADMIN)
CComPtr <IDirectorySearch> spDsSearch;
CSmartWStr cswzCleanObj;
PWSTR pwzDnsDom;
hr = pPage->SkipPrefix(pPage->GetObjPathName(), &cswzCleanObj);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
//
// To bind to a GC, you need to supply the domain name rather than the
// server path because the current DC may not be hosting a GC.
//
hr = CrackName(cswzCleanObj, &pwzDnsDom, GET_DNS_DOMAIN_NAME, pPage->GetHWnd());
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
hr = DSPROP_GetGCSearchOnDomain(pwzDnsDom,
IID_IDirectorySearch,
(PVOID*)&spDsSearch);
LocalFreeStringW(&pwzDnsDom);
if (S_OK != hr)
{
if (S_FALSE == hr ||
HRESULT_FROM_WIN32(ERROR_DS_SERVER_DOWN) == hr)
{
ErrMsg(IDS_WARN_NO_GC_FOUND, pPage->GetHWnd());
}
else if (HRESULT_FROM_WIN32(ERROR_LOGON_FAILURE) == hr)
{
ErrMsg(IDS_WARN_ACCESS_TO_GC_DENIED, pPage->GetHWnd());
}
else
{
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(),;);
}
return hr;
}
CStrW csFilter = L"(|", csClass, csClause;
CMemberListItem * pItem;
ULONG i, ulStart = 0, ulEnd;
ADS_SEARCHPREF_INFO SearchPref;
WCHAR wzSearchFormat[] = L"(%s=%s)";
PWSTR pwzAttrNames[] = {g_wzDN, g_wzObjectClass, g_wzUserAccountControl};
SearchPref.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
SearchPref.vValue.Integer = ADS_SCOPE_SUBTREE;
SearchPref.vValue.dwType = ADSTYPE_INTEGER;
hr = spDsSearch->SetSearchPreference(&SearchPref, 1);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
while (TRUE)
{
ulEnd = ulStart + g_ulMemberFilterCount;
for (i = ulStart; i < ulEnd; i++)
{
if (GetItem(i, &pItem) == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))
{
// End Of List, reset end counter.
//
ulEnd = i;
break;
}
csClause.Format(wzSearchFormat, g_wzDN, pItem->m_pwzDN);
csFilter += csClause;
}
csFilter += L")";
ADS_SEARCH_HANDLE hSrch = NULL;
dspDebugOut((DEB_USER14 | DEB_ITRACE, "About to do the member search.\n"));
hr = spDsSearch->ExecuteSearch((PWSTR)(LPCWSTR)csFilter,
pwzAttrNames, ARRAYLENGTH(pwzAttrNames),
&hSrch);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
dspDebugOut((DEB_USER14 | DEB_ITRACE, "Member search returned.\n"));
hr = spDsSearch->GetNextRow(hSrch);
for (i = ulStart; (i < ulEnd) && (S_OK == hr); i++)
{
ADS_SEARCH_COLUMN Column;
BOOL fDisabled = FALSE;
CStrW csDN;
int iIndex;
//
// Get the object dn.
//
hr = spDsSearch->GetColumn(hSrch, g_wzDN, &Column);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), break);
csDN = Column.pADsValues->CaseIgnoreString;
spDsSearch->FreeColumn(&Column);
//
// Get the object class.
//
hr = spDsSearch->GetColumn(hSrch, g_wzObjectClass, &Column);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), break);
// Krishna sez the most derived class is *always* the last array element...
csClass = Column.pADsValues[Column.dwNumValues - 1].CaseIgnoreString;
spDsSearch->FreeColumn(&Column);
//
// Get the object userAccountControl.
//
hr = spDsSearch->GetColumn(hSrch, g_wzUserAccountControl, &Column);
if (S_OK == hr)
{
fDisabled = (Column.pADsValues->Integer & UF_ACCOUNTDISABLE) != 0;
spDsSearch->FreeColumn(&Column);
}
if ((iIndex = GetIndex(csDN, ulStart, ulEnd)) == -1)
{
dspAssert(FALSE && "list entry not found!");
return E_FAIL;
}
LV_ITEM lvi = {0};
lvi.mask = LVIF_IMAGE;
lvi.iSubItem = IDX_NAME_COL;
lvi.iItem = iIndex;
lvi.iImage = g_ClassIconCache.GetClassIconIndex(csClass, fDisabled);
if (lvi.iImage == -1)
{
lvi.iImage = g_ClassIconCache.AddClassIcon(csClass, fDisabled);
}
ListView_SetItem(m_hList, &lvi);
hr = spDsSearch->GetNextRow(hSrch);
}
dspDebugOut((DEB_USER14 | DEB_ITRACE, "Members updated with icons.\n"));
spDsSearch->CloseSearchHandle(hSrch);
if (ulEnd != (ulStart + g_ulMemberFilterCount))
{
// EOL, stop processing.
//
break;
}
ulStart = ulEnd;
csFilter = L"(|";
}
#endif // defined (DSADMIN)
return hr;
}
//+----------------------------------------------------------------------------
//
// Class: CMemberListItem
//
// Purpose: Item data for the reverse membership list.
//
//-----------------------------------------------------------------------------
//+----------------------------------------------------------------------------
//
// Method: CMemberListItem::Copy
//
// Synopsis: Return a copy of the original element.
//
//-----------------------------------------------------------------------------
CMemberListItem *
CMemberListItem::Copy(void)
{
CMemberListItem * pItem = new CMemberListItem;
CHECK_NULL(pItem, return NULL);
if (this->m_pwzDN)
{
if (!AllocWStr(this->m_pwzDN, &pItem->m_pwzDN))
{
delete pItem;
return NULL;
}
}
if (this->m_ptzName)
{
if (!AllocTStr(this->m_ptzName, &pItem->m_ptzName))
{
delete pItem;
return NULL;
}
}
if (this->m_pSid)
{
if (!pItem->SetSid(this->m_pSid))
{
delete pItem;
return NULL;
}
}
pItem->m_fIsPrimary = this->m_fIsPrimary;
pItem->m_ulScopeType = this->m_ulScopeType;
pItem->m_fSidSet = this->m_fSidSet;
pItem->m_fCanBePrimarySet = this->m_fCanBePrimarySet;
pItem->m_fCanBePrimary = this->m_fCanBePrimary;
pItem->m_fIsAlreadyMember = this->m_fIsAlreadyMember;
pItem->m_fIsExternal = this->m_fIsExternal;
return pItem;
}
//+----------------------------------------------------------------------------
//
// Method: CMemberListItem::SetSid
//
// Synopsis: Copy and store the passed in SID.
//
//-----------------------------------------------------------------------------
BOOL
CMemberListItem::SetSid(PSID pSid)
{
int cb = GetLengthSid(pSid);
dspAssert(cb);
this->m_pSid = new BYTE[cb];
CHECK_NULL(this->m_pSid, return FALSE);
memcpy(this->m_pSid, pSid, cb);
m_fSidSet = TRUE;
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: ConvertSidToPath
//
// Synopsis: Converts the binary SID to a string LDAP path.
//
//-----------------------------------------------------------------------------
void
ConvertSidToPath(PSID pObjSID, CStrW &strSIDname)
{
strSIDname = g_wzSidPathPrefix;
//
// Convert the bytes of the sid to hex chars.
//
PBYTE pbSid = (PBYTE)pObjSID;
ULONG i;
PUCHAR pcSubAuth = NULL;
pcSubAuth = GetSidSubAuthorityCount(pObjSID);
dspAssert(pcSubAuth);
ULONG cbSid = GetSidLengthRequired(*pcSubAuth);
dspAssert(cbSid);
dspAssert(cbSid == (*pcSubAuth - 1) * (sizeof(DWORD)) + sizeof(SID));
for (i = 0; i < cbSid; i++)
{
WCHAR wzCur[3];
wsprintfW(wzCur, L"%02x", *pbSid);
pbSid++;
strSIDname += wzCur;
}
strSIDname += g_wzSidPathSuffix;
}
//+----------------------------------------------------------------------------
//
// Method: CClassIconCache::CClassIconCache
//
//-----------------------------------------------------------------------------
CClassIconCache::CClassIconCache(void) :
m_fInitialized(FALSE),
m_prgcce(NULL),
m_hImageList(NULL)
{
TRACE(CClassIconCache,CClassIconCache);
m_nImageCount = 0;
}
//+----------------------------------------------------------------------------
//
// Method: CClassIconCache::~CClassIconCache
//
//-----------------------------------------------------------------------------
CClassIconCache::~CClassIconCache(void)
{
TRACE(CClassIconCache,~CClassIconCache);
ClearAll();
}
//+----------------------------------------------------------------------------
//
// Method: CClassIconCache::ClearAll
//
//-----------------------------------------------------------------------------
void CClassIconCache::ClearAll(void)
{
if (m_hImageList != NULL)
{
ImageList_RemoveAll(m_hImageList);
ImageList_Destroy(m_hImageList);
m_hImageList = NULL;
}
if (m_prgcce != NULL)
{
delete[] m_prgcce;
m_prgcce = NULL;
m_nImageCount = 0;
}
m_fInitialized = FALSE;
}
//+----------------------------------------------------------------------------
//
// Method: CClassIconCache::GetClassIconIndex
//
//-----------------------------------------------------------------------------
int CClassIconCache::GetClassIconIndex(PCWSTR pwzClass, BOOL fDisabled)
{
int iIcon = -1;
dspAssert(pwzClass);
Initialize();
if (m_prgcce != NULL && m_nImageCount > 0)
{
for (UINT i = 0; i < m_nImageCount; i++)
{
if (_wcsicmp(pwzClass, m_prgcce[i].wzClass) == 0)
{
iIcon = (fDisabled) ? m_prgcce[i].iDisabledIcon : m_prgcce[i].iIcon;
break;
}
}
}
dspDebugOut((DEB_USER14, "CClassIconCache::GetClassIconIndex returning %d\n", iIcon));
return iIcon;
}
//+----------------------------------------------------------------------------
//
// Method: CClassIconCache::AddClassIcon
//
//-----------------------------------------------------------------------------
int CClassIconCache::AddClassIcon(PCWSTR pwzClass, BOOL fDisabled)
{
//
// Retrieves the icon for the class from the DisplaySpecifiers and puts it
// in the image list
//
HICON hIcon = NULL;
HICON hDisabledIcon = NULL;
hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, const_cast<PWSTR>(pwzClass), 16, 16);
if (!hIcon)
{
DBG_OUT("CClassIconCache::AddClassIcon failed in DsGetIcon for normal icon");
return E_OUTOFMEMORY;
}
hDisabledIcon = DsGetIcon(DSGIF_ISDISABLED | DSGIF_GETDEFAULTICON, const_cast<PWSTR>(pwzClass), 16, 16);
if (!hDisabledIcon)
{
DBG_OUT("CClassIconCache::AddClassIcon failed in DsGetIcon for disabled icon");
hDisabledIcon = hIcon;
}
if (m_prgcce != NULL)
{
CLASS_CACHE_ENTRY* pNewList = new CLASS_CACHE_ENTRY[m_nImageCount + 1];
if (pNewList == NULL)
{
return -1;
}
memcpy(pNewList, m_prgcce, sizeof(CLASS_CACHE_ENTRY) * m_nImageCount);
delete[] m_prgcce;
m_prgcce = pNewList;
m_prgcce[m_nImageCount].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
if (hDisabledIcon == hIcon)
{
m_prgcce[m_nImageCount].iDisabledIcon = m_prgcce[m_nImageCount].iIcon;
}
else
{
m_prgcce[m_nImageCount].iDisabledIcon = ImageList_AddIcon(m_hImageList, hDisabledIcon);
}
m_nImageCount++;
}
DestroyIcon(hIcon);
if (hDisabledIcon != hIcon)
{
DestroyIcon(hDisabledIcon);
}
return (fDisabled) ? m_prgcce[m_nImageCount - 1].iDisabledIcon : m_prgcce[m_nImageCount - 1].iIcon;
}
//+----------------------------------------------------------------------------
//
// Method: CClassIconCache::Initialize
//
//-----------------------------------------------------------------------------
HRESULT CClassIconCache::Initialize(void)
{
if (m_fInitialized)
{
return S_OK;
}
if (m_prgcce != NULL)
{
delete[] m_prgcce;
m_prgcce = NULL;
m_nImageCount = 0;
}
m_nImageCount = ICON_CACHE_NUM_CLASSES;
m_prgcce = new CLASS_CACHE_ENTRY[m_nImageCount];
if (m_prgcce == NULL)
{
m_nImageCount = 0;
return -1;
}
memset(m_prgcce, 0, sizeof(CLASS_CACHE_ENTRY) * m_nImageCount);
dspAssert(m_prgcce != NULL);
TRACE(CClassIconCache,Initialize);
m_hImageList = ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 1, 1);
if (NULL == m_hImageList)
{
DBG_OUT("ImageList_Create failed");
return E_OUTOFMEMORY;
}
HICON hIcon;
//
// Default
//
hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MEMBER));
if (!hIcon)
{
DBG_OUT("DsGetIcon failed for member icon");
return E_OUTOFMEMORY;
}
m_prgcce[0].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
wcscpy(m_prgcce[0].wzClass, L"default");
m_prgcce[0].iDisabledIcon = m_prgcce[0].iIcon;
//
// User
//
hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, g_wzUser, 16, 16);
if (!hIcon)
{
DBG_OUT("DsGetIcon failed for user icon");
return E_OUTOFMEMORY;
}
m_prgcce[1].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
DestroyIcon(hIcon);
hIcon = DsGetIcon(DSGIF_ISDISABLED | DSGIF_GETDEFAULTICON, g_wzUser, 16, 16);
if (!hIcon)
{
DBG_OUT("DsGetIcon failed for user disable icon");
return E_OUTOFMEMORY;
}
m_prgcce[1].iDisabledIcon = ImageList_AddIcon(m_hImageList, hIcon);
DestroyIcon(hIcon);
wcscpy(m_prgcce[1].wzClass, g_wzUser);
//
// Computer
//
hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, g_wzComputer, 16, 16);
if (!hIcon)
{
DBG_OUT("DsGetIcon failed for computer icon");
return E_OUTOFMEMORY;
}
m_prgcce[2].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
DestroyIcon(hIcon);
hIcon = DsGetIcon(DSGIF_ISDISABLED | DSGIF_GETDEFAULTICON, g_wzComputer, 16, 16);
if (!hIcon)
{
DBG_OUT("DsGetIcon failed for computer disable icon");
return E_OUTOFMEMORY;
}
m_prgcce[2].iDisabledIcon = ImageList_AddIcon(m_hImageList, hIcon);
DestroyIcon(hIcon);
wcscpy(m_prgcce[2].wzClass, g_wzComputer);
//
// Contact
//
hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, g_wzContact, 16, 16);
if (!hIcon)
{
DBG_OUT("DsGetIcon failed for contact icon");
return E_OUTOFMEMORY;
}
m_prgcce[3].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
DestroyIcon(hIcon);
m_prgcce[3].iDisabledIcon = -1;
wcscpy(m_prgcce[3].wzClass, g_wzContact);
//
// Group
//
hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, g_wzGroup, 16, 16);
if (!hIcon)
{
DBG_OUT("DsGetIcon failed for group icon");
return E_OUTOFMEMORY;
}
m_prgcce[4].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
DestroyIcon(hIcon);
m_prgcce[4].iDisabledIcon = -1;
wcscpy(m_prgcce[4].wzClass, g_wzGroup);
//
// FPO
//
hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, g_wzFPO, 16, 16);
if (!hIcon)
{
DBG_OUT("DsGetIcon failed for fpo icon");
return E_OUTOFMEMORY;
}
m_prgcce[5].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
DestroyIcon(hIcon);
m_prgcce[5].iDisabledIcon = -1;
wcscpy(m_prgcce[5].wzClass, g_wzFPO);
m_fInitialized = TRUE;
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Method: CClassIconCache::GetImageList
//
//-----------------------------------------------------------------------------
HIMAGELIST CClassIconCache::GetImageList(void)
{
if (FAILED(Initialize()))
{
return NULL;
}
return m_hImageList;
}