You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1668 lines
43 KiB
1668 lines
43 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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);
|
|
|
|
CStr remaining = cstrCanonicalNameEx.Right(cstrCanonicalNameEx.GetLength() - nCR - 1);
|
|
|
|
// Remove any escaping from the name
|
|
//
|
|
int nBackSlash;
|
|
|
|
while ((nBackSlash = remaining.Find(TEXT('\\'))) != -1)
|
|
{
|
|
CStr cstrTemp = remaining.Left(nBackSlash);
|
|
if (remaining.GetAt(nBackSlash + 1) == TEXT('\\'))
|
|
{
|
|
cstrTemp += remaining.GetAt(nBackSlash + 1);
|
|
++nBackSlash;
|
|
}
|
|
|
|
cstrName += cstrTemp;
|
|
|
|
int count = remaining.GetLength() - nBackSlash - 1;
|
|
if (count > 0)
|
|
{
|
|
remaining = remaining.Right(remaining.GetLength() - nBackSlash - 1);
|
|
}
|
|
else
|
|
{
|
|
// the last character must have been a backslash so just break so
|
|
// that we don't have an infinite loop
|
|
|
|
remaining = L"";
|
|
break;
|
|
}
|
|
|
|
}
|
|
cstrName += remaining;
|
|
}
|
|
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.
|
|
//
|
|
// History: 2002/07/05-ArtM Rewrote to fix NTRAID#NTBUG9-655550 and remove memory leaks.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
CDsObjList::GetCurListItems(int ** ppIndex, PTSTR ** ppptzName, PVOID ** pppData, int* pNumSelected)
|
|
{
|
|
int iStartPoint = -1;
|
|
int i = -1;
|
|
UINT nSelected = ListView_GetSelectedCount(m_hList);
|
|
HRESULT hr = S_OK;
|
|
BOOL fRetrievedItems = TRUE;
|
|
|
|
if (ppIndex)
|
|
{
|
|
*ppIndex = new int[nSelected];
|
|
CHECK_NULL(*ppIndex, hr = E_OUTOFMEMORY);
|
|
}
|
|
if (ppptzName)
|
|
{
|
|
*ppptzName = new PTSTR[nSelected];
|
|
CHECK_NULL(*ppptzName, hr = E_OUTOFMEMORY);
|
|
}
|
|
if (pppData)
|
|
{
|
|
*pppData = new PVOID[nSelected];
|
|
CHECK_NULL(*pppData, hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
for (UINT idx = 0; SUCCEEDED(hr) && idx < nSelected; idx++)
|
|
{
|
|
i = ListView_GetNextItem(m_hList, iStartPoint, LVNI_SELECTED);
|
|
|
|
if (i < 0)
|
|
{
|
|
dspDebugOut((DEB_ITRACE, "DsProp: no list selection.\n"));
|
|
fRetrievedItems = FALSE;
|
|
break;
|
|
}
|
|
|
|
hr = GetItem(
|
|
i,
|
|
(ppptzName != NULL) ? &((*ppptzName)[idx]) : NULL,
|
|
(pppData != NULL) ? &((*pppData)[idx]) : NULL );
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
dspAssert(FALSE);
|
|
fRetrievedItems = FALSE;
|
|
break;
|
|
}
|
|
|
|
iStartPoint = i;
|
|
if (ppIndex)
|
|
{
|
|
(*ppIndex)[idx] = i;
|
|
}
|
|
}
|
|
|
|
if (pNumSelected != NULL && fRetrievedItems && SUCCEEDED(hr))
|
|
{
|
|
*pNumSelected = nSelected;
|
|
}
|
|
|
|
// Clean up any memory allocated if retrieval failed.
|
|
if (FAILED(hr) || !fRetrievedItems)
|
|
{
|
|
dspAssert(FALSE);
|
|
if (ppIndex != NULL)
|
|
{
|
|
delete[] *ppIndex;
|
|
*ppIndex = 0;
|
|
}
|
|
if (ppptzName != NULL)
|
|
{
|
|
delete[] *ppptzName;
|
|
*ppptzName = 0;
|
|
}
|
|
if (pppData != NULL)
|
|
{
|
|
delete[] *pppData;
|
|
*pppData = 0;
|
|
}
|
|
}
|
|
|
|
return fRetrievedItems;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
CStrW filterEscapedValue;
|
|
GetFilterEscapedValue(pItem->m_pwzDN, filterEscapedValue);
|
|
|
|
csClause.Format(wzSearchFormat, g_wzDN, (LPCWSTR)filterEscapedValue);
|
|
|
|
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);
|
|
if (!pwzClass)
|
|
{
|
|
return iIcon;
|
|
}
|
|
|
|
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;
|
|
}
|