//+---------------------------------------------------------------------------- // // 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((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((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((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 // 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((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((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 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(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(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; }