////////////////////////////////////////////////////////////////////////////// /*++ Copyright (C) Microsoft Corporation, 1998 - 2001 Module Name: NTGroups.cpp Abstract: Implementation file for the CIASGroupsAttributeEditor class. Revision History: mmaguire 08/10/98 - added new intermediate dialog for picking groups using some of byao's original implementation --*/ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // BEGIN INCLUDES // // standard includes: // #include "Precompiled.h" // // where we can find declaration for main class in this file: // #include #include "NTGroups.h" // // where we can find declarations needed in this file: // #include #include // For "pair" #include #include #include #include #include #include "textsid.h" #include "dialog.h" #include "dsrole.h" // // END INCLUDES ////////////////////////////////////////////////////////////////////////////// //#define OLD_OBJECT_PICKER // Small wrapper class for a BYTE pointer to avoid memory leaks. template class SmartPointer { public: SmartPointer() { m_Pointer = NULL; } operator Pointer() { return( m_Pointer ); } Pointer * operator&() { return( & m_Pointer ); } virtual ~SmartPointer() { // Override as necessary. }; protected: Pointer m_Pointer; }; ///////////////////////////////////////////////////////////////////////////// // Declarations needed in this file: PWSTR g_wzObjectSID = _T("objectSid"); // Group list delimiter: #define DELIMITER L";" // Utility functions: static HRESULT ConvertSidToTextualRepresentation( PSID pSid, CComBSTR &bstrTextualSid ); static HRESULT ConvertSidToHumanReadable( PSID pSid, CComBSTR &bstrHumanReadable, LPCTSTR lpSystemName = NULL ); // We needed this because the standard macro doesn't return the value from SNDMSG and // sometimes we need to know whether the operation succeeded or failed. static inline LRESULT CustomListView_SetItemState( HWND hwndLV, int i, UINT data, UINT mask) { LV_ITEM _ms_lvi; _ms_lvi.stateMask = mask; _ms_lvi.state = data; return SNDMSG((hwndLV), LVM_SETITEMSTATE, (WPARAM)i, (LPARAM)(LV_ITEM FAR *)&_ms_lvi); } ///////////////////////////////////////////////////////////////////////////// // CDisplayGroupsDialog class CDisplayGroupsDialog; typedef CIASDialog DISPLAY_GROUPS_FALSE; class CDisplayGroupsDialog : public DISPLAY_GROUPS_FALSE { public: CDisplayGroupsDialog( GroupList *pGroups ); ~CDisplayGroupsDialog(); enum { IDD = IDD_DIALOG_DISPLAY_GROUPS }; BEGIN_MSG_MAP(CDisplayGroupsDialog) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_ID_HANDLER(IDC_BUTTON_ADD_GROUP, OnAdd) COMMAND_ID_HANDLER(IDC_BUTTON_REMOVE_GROUP, OnRemove) COMMAND_ID_HANDLER(IDOK, OnOK) COMMAND_ID_HANDLER(IDCANCEL, OnCancel) NOTIFY_CODE_HANDLER(LVN_ITEMCHANGED, OnListViewItemChanged) // NOTIFY_CODE_HANDLER(NM_DBLCLK, OnListViewDbclk) CHAIN_MSG_MAP(DISPLAY_GROUPS_FALSE) END_MSG_MAP() LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnRemove(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); LRESULT OnAdd(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); LRESULT OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); LRESULT OnCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); LRESULT OnListViewItemChanged(int idCtrl, LPNMHDR pnmh, BOOL& bHandled); LRESULT OnListViewDbclk(int idCtrl, LPNMHDR pnmh, BOOL& bHandled); protected: BOOL PopulateGroupList( int iStartIndex ); private: HWND m_hWndGroupList; GroupList * m_pGroups; }; ////////////////////////////////////////////////////////////////////////////// /*++ CIASGroupsAttributeEditor::Edit IIASAttributeEditor implementation. --*/ ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CIASGroupsAttributeEditor::Edit(IIASAttributeInfo * pIASAttributeInfo, /*[in]*/ VARIANT *pAttributeValue, /*[in, out]*/ BSTR *pReserved ) { TRACE_FUNCTION("CIASGroupsAttributeEditor::Edit"); HRESULT hr = S_OK; try // new could throw as could DoModal { WCHAR * pszMachineName = NULL; // Check for preconditions. // We will ignore the pIASAttributeInfo interface pointer -- it is not // needed for this attribute editor. if( ! pAttributeValue ) { return E_INVALIDARG; } if( V_VT(pAttributeValue ) != VT_BSTR ) { return E_INVALIDARG; } GroupList Groups; // We need to pass the machine name in somehow, so we use the // otherwise unused pReserved BSTR *. if( pReserved ) { Groups.m_bstrServerName = *pReserved; } Groups.PopulateGroupsFromVariant( pAttributeValue ); // ISSUE: Need to get szServerAddress in here somehow -- could use reserved. CDisplayGroupsDialog * pDisplayGroupsDialog = new CDisplayGroupsDialog( &Groups ); _ASSERTE( pDisplayGroupsDialog ); int iResult = pDisplayGroupsDialog->DoModal(); if( IDOK == iResult ) { // Clear out the old value of the variant. VariantClear(pAttributeValue); Groups.PopulateVariantFromGroups( pAttributeValue ); hr = S_OK; } else { hr = S_FALSE; } } catch(...) { return E_FAIL; } return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ CIASGroupsAttributeEditor::GetDisplayInfo IIASAttributeEditor implementation. --*/ ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CIASGroupsAttributeEditor::GetDisplayInfo(IIASAttributeInfo * pIASAttributeInfo, /*[in]*/ VARIANT *pAttributeValue, BSTR * pServerName, BSTR * pValueAsString, /*[in, out]*/ BSTR *pReserved ) { TRACE_FUNCTION("CIASGroupsAttributeEditor::GetDisplayInfo"); HRESULT hr = S_OK; // Check for preconditions. // We will ignore the pIASAttributeInfo interface pointer -- it is not // needed for this attribute editor. // We will also ignore the pVendorName BSTR pointer -- this doesn't // make sense for this attribute editor. if( ! pAttributeValue ) { return E_INVALIDARG; } if( V_VT(pAttributeValue ) != VT_BSTR ) { return E_INVALIDARG; } if( ! pValueAsString ) { return E_INVALIDARG; } try { GroupList Groups; // We need to pass the machine name in somehow, so we use the // otherwise unused pReserved BSTR *. if( pReserved ) { Groups.m_bstrServerName = *pReserved; } hr = Groups.PopulateGroupsFromVariant( pAttributeValue ); if( FAILED( hr ) ) { return hr; } CComBSTR bstrDisplay; GroupList::iterator thePair = Groups.begin(); while( thePair != Groups.end() ) { bstrDisplay += thePair->second; thePair++; if( thePair != Groups.end() ) { bstrDisplay += DELIMITER; } } *pValueAsString = bstrDisplay.Copy(); } catch(...) { return E_FAIL; } return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ ConvertSidToTextualRepresentation Converts a SID to a BSTR representation. e.g. "S-1-5-32-544" --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT ConvertSidToTextualRepresentation( PSID pSid, CComBSTR &bstrTextualSid ) { HRESULT hr = S_OK; // convert the SID value to texual format WCHAR text[1024]; DWORD cbText = sizeof(text)/sizeof(WCHAR); if( NO_ERROR == IASSidToTextW(pSid, text, &cbText) ) { bstrTextualSid = text; } else { return E_FAIL; } return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ ConvertSidToTextualRepresentation Converts a SID to a humanBSTR representation. e.g. "ias-domain\Users" --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT ConvertSidToHumanReadable( PSID pSid, CComBSTR &bstrHumanReadable, LPCTSTR lpSystemName ) { HRESULT hr = S_OK; // Find the group name for this sid. WCHAR wzUserName[MAX_PATH+1]; WCHAR wzDomainName[MAX_PATH+1]; DWORD dwUserNameLen, dwDomainNameLen; SID_NAME_USE sidUser = SidTypeGroup; ATLTRACE(_T("looking up the account name from the SID value\n")); dwUserNameLen = sizeof(wzUserName); dwDomainNameLen = sizeof(wzDomainName); if (LookupAccountSid( lpSystemName, pSid, wzUserName, &dwUserNameLen, wzDomainName, &dwDomainNameLen, &sidUser ) ) { bstrHumanReadable = wzDomainName; bstrHumanReadable += L"\\"; bstrHumanReadable += wzUserName; } else { #ifdef DEBUG DWORD dwError = GetLastError(); ATLTRACE(_T("Error: %ld\n"), dwError); #endif // DEBUG return E_FAIL; } return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ GroupList::PopulateGroupsFromVariant Takes a pointer to a variant and populates a GroupList with that data. --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT GroupList::PopulateGroupsFromVariant( VARIANT * pvarGroups ) { TRACE_FUNCTION("GroupList::PopulateGroupsFromVariant"); // Check for preconditions. _ASSERTE( V_VT(pvarGroups) == VT_BSTR ); HRESULT hr = S_OK; // First, make a local copy. // ISSUE: Make sure this copies. CComBSTR bstrGroups = V_BSTR(pvarGroups); WCHAR *pwzGroupText = bstrGroups; // Each group should be separated by a comma or semicolon. PWSTR pwzToken = wcstok(pwzGroupText, DELIMITER); while (pwzToken) { PSID pSid = NULL; try { CComBSTR bstrGroupTextualSid = pwzToken; CComBSTR bstrGroupName; if( NO_ERROR != IASSidFromTextW( pwzToken, &pSid ) ) { // Try the next one. throw E_FAIL; } if( FAILED( ConvertSidToHumanReadable( pSid, bstrGroupName, m_bstrServerName ) ) ) { // Try the next one. throw E_FAIL; } GROUPPAIR thePair = std::make_pair( bstrGroupTextualSid, bstrGroupName ); push_back( thePair ); FreeSid( pSid ); pwzToken = wcstok(NULL, DELIMITER); } catch(...) { if( pSid ) { FreeSid( pSid ); } pwzToken = wcstok(NULL, DELIMITER); } } return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ GroupList::PopulateVariantFromGroups Takes a pointer to a variant and populates the variant with data from a GroupList. --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT GroupList::PopulateVariantFromGroups( VARIANT * pAttributeValue ) { TRACE_FUNCTION("GroupList::PopulateVariantFromGroups"); HRESULT hr = S_OK; CComBSTR bstrGroupsString; GroupList::iterator thePair = begin(); while( thePair != end() ) { bstrGroupsString += thePair->first; thePair++; if( thePair != end() ) { bstrGroupsString += DELIMITER; } } V_VT(pAttributeValue) = VT_BSTR; V_BSTR( pAttributeValue ) = bstrGroupsString.Copy(); return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ GroupList::AddPairToGroups Adds a pair to a GroupList if a pair with the same SID isn't already in the list. Note: Does nothing and return S_FALSE if Pair already in groups list. --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT GroupList::AddPairToGroups( GROUPPAIR &thePair ) { TRACE_FUNCTION("GroupList::AddPairToGroups"); HRESULT hr = S_OK; try { // First, check to see if the pair is already in the group. GroupList::iterator theIterator; for( theIterator = begin(); theIterator != end(); ++theIterator ) { if( 0 == wcscmp( theIterator->first, thePair.first ) ) { return S_FALSE; } } push_back( thePair ); } catch(...) { return E_FAIL; } return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ GroupList::AddSelectionSidsToGroup #ifndef OLD_OBJECT_PICKER Takes a PDS_SELECTION_LIST pointer and adds all groups it points to to a GroupList. #else // OLD_OBJECT_PICKER Takes a PDSSELECTIONLIST pointer and adds all groups it points to to a GroupList. #endif // OLD_OBJECT_PICKER Returns S_OK if it adds any new groups. Returns S_FALSE and does not add entries if they are already in the GroupList. E_FAIL on error. --*/ ////////////////////////////////////////////////////////////////////////////// #ifndef OLD_OBJECT_PICKER HRESULT GroupList::AddSelectionSidsToGroup( PDS_SELECTION_LIST pDsSelList ) #else // OLD_OBJECT_PICKER HRESULT GroupList::AddSelectionSidsToGroup( PDSSELECTIONLIST pDsSelList ) #endif // OLD_OBJECT_PICKER { TRACE_FUNCTION("GroupList::AddSelectionSidsToGroup"); HRESULT hr = S_OK; ULONG i; #ifndef OLD_OBJECT_PICKER PDS_SELECTION pCur = &pDsSelList->aDsSelection[0]; #else // OLD_OBJECT_PICKER PDSSELECTION pCur = &pDsSelList->aDsSelection[0]; #endif // OLD_OBJECT_PICKER BOOL bAtLeastOneAdded = FALSE; // // now let's get the sid value for each selection! // pCur = &pDsSelList->aDsSelection[0]; for (i = 0; i < pDsSelList->cItems; ++i, ++pCur) { #ifndef OLD_OBJECT_PICKER if (V_VT(&pCur->pvarFetchedAttributes[0]) == (VT_ARRAY|VT_UI1)) #else // OLD_OBJECT_PICKER if (V_VT(&pCur->pvarOtherAttributes[0]) == (VT_ARRAY|VT_UI1)) #endif // OLD_OBJECT_PICKER { // succeeded: we got the SID value back! PSID pSid = NULL; #ifndef OLD_OBJECT_PICKER hr = SafeArrayAccessData(V_ARRAY(&pCur->pvarFetchedAttributes[0]), &pSid); #else // OLD_OBJECT_PICKER hr = SafeArrayAccessData(V_ARRAY(&pCur->pvarOtherAttributes[0]), &pSid); #endif // OLD_OBJECT_PICKER if ( SUCCEEDED(hr) && pSid ) { CComBSTR bstrTextualSid; CComBSTR bstrHumanReadable; hr = ConvertSidToTextualRepresentation( pSid, bstrTextualSid ); if( FAILED( hr ) ) { // If we can't get the textual representation of the SID, // then we're hosed for this group -- we'll have nothing // to save it away as. continue; } hr = ConvertSidToHumanReadable( pSid, bstrHumanReadable, m_bstrServerName ); if( FAILED( hr ) ) { // For some reason, we couldn't look up a group name. // Use the textual SID to display this group. bstrHumanReadable = bstrTextualSid; } GROUPPAIR thePair = std::make_pair( bstrTextualSid, bstrHumanReadable ); hr = AddPairToGroups( thePair ); if( S_OK == hr ) { bAtLeastOneAdded = TRUE; } } #ifndef OLD_OBJECT_PICKER SafeArrayUnaccessData(V_ARRAY(&pCur->pvarFetchedAttributes[0])); #else // OLD_OBJECT_PICKER SafeArrayUnaccessData(V_ARRAY(&pCur->pvarOtherAttributes[0])); #endif // OLD_OBJECT_PICKER } else { // we couldn't get the sid value hr = E_FAIL; } } // for // We don't seem to have encountered any errors. // Decide on return value based on whether we added any new // groups to the list that weren't already there. if( bAtLeastOneAdded ) { return S_OK; } else { return S_FALSE; } } // Small wrapper class for a DsRole BYTE pointer to avoid memory leaks. class MyDsRoleBytePointer : public SmartPointer { public: // We override the destructor to do DsRole specific release. ~MyDsRoleBytePointer() { if( m_Pointer ) { DsRoleFreeMemory( m_Pointer ); } } }; //+--------------------------------------------------------------------------- // // Function: GroupList::PickNtGroups // // Synopsis: pop up the objectPicker UI and choose a set of NT groups // // Arguments: // [in] HWND hWndParent: parent window; // [in] LPTSTR pszServerAddress:the machine name // // // Returns: S_OK if added new groups. // S_FALSE if no new groups in selection. // Error value on fail. // // History: Created Header byao 2/15/98 12:09:53 AM // Modified byao 3/11/98 to get domain/group names as well // Modified mmaguire 08/12/98 made method of GroupList class // //+--------------------------------------------------------------------------- HRESULT GroupList::PickNtGroups( HWND hWndParent ) { #ifndef OLD_OBJECT_PICKER HRESULT hr; CComPtr spDsObjectPicker; hr = CoCreateInstance( CLSID_DsObjectPicker , NULL , CLSCTX_INPROC_SERVER , IID_IDsObjectPicker , (void **) &spDsObjectPicker ); if( FAILED( hr ) ) { return hr; } // Check to see if we are a DC -- we will use DsRoleGetPrimaryDomainInformation LPWSTR szServer = NULL; if ( m_bstrServerName && _tcslen(m_bstrServerName) ) { // use machine name for remote machine szServer = m_bstrServerName; } MyDsRoleBytePointer dsInfo; if( ERROR_SUCCESS != DsRoleGetPrimaryDomainInformation( szServer, DsRolePrimaryDomainInfoBasic, &dsInfo ) ) { return E_FAIL; } PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pInfo = (PDSROLE_PRIMARY_DOMAIN_INFO_BASIC) (PBYTE) dsInfo; if( ! pInfo ) { return E_FAIL; } BOOL bNotDc; if( pInfo->MachineRole == DsRole_RoleBackupDomainController || pInfo->MachineRole == DsRole_RolePrimaryDomainController ) { bNotDc = FALSE; } else { bNotDc = TRUE; } // At the most, we need only three scopes (we may use less). DSOP_SCOPE_INIT_INFO aScopes[3]; ZeroMemory( aScopes, sizeof(aScopes) ); int iScopeCount = 0; // We need to add this first, DSOP_SCOPE_TYPE_TARGET_COMPUTER type // scope only if we are not on the DC. if( bNotDc ) { // Include a scope for the target computer's scope. aScopes[iScopeCount].cbSize = sizeof( DSOP_SCOPE_INIT_INFO ); aScopes[iScopeCount].flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER; // Set what filters to apply for this scope. aScopes[iScopeCount].FilterFlags.flDownlevel= DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS | DSOP_DOWNLEVEL_FILTER_EXCLUDE_BUILTIN_GROUPS ; } // Move on to next scope. ++iScopeCount; // Set the downlevel scopes aScopes[iScopeCount].cbSize = sizeof( DSOP_SCOPE_INIT_INFO ); aScopes[iScopeCount].flType = DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN | DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN ; // Set what filters to apply for this scope. aScopes[iScopeCount].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS | DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS | DSOP_DOWNLEVEL_FILTER_EXCLUDE_BUILTIN_GROUPS ; // Move on to next scope. ++iScopeCount; // For all other scopes, use same as target computer but exclude BUILTIN_GROUPS aScopes[iScopeCount].cbSize = sizeof( DSOP_SCOPE_INIT_INFO ); aScopes[iScopeCount].flType = DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN | DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN ; // Set what filters to apply for this scope. aScopes[iScopeCount].FilterFlags.Uplevel.flBothModes = 0 /* BUG 263302 -- not to show domain local groups | DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE ~ BUG */ | DSOP_FILTER_GLOBAL_GROUPS_SE ; aScopes[iScopeCount].FilterFlags.Uplevel.flNativeModeOnly = DSOP_FILTER_UNIVERSAL_GROUPS_SE; // Now fill up the correct structures and call Initialize. DSOP_INIT_INFO InitInfo; ZeroMemory( &InitInfo, sizeof(InitInfo) ); InitInfo.cbSize = sizeof( InitInfo ); InitInfo.cDsScopeInfos = iScopeCount + 1; InitInfo.aDsScopeInfos = aScopes; InitInfo.flOptions = DSOP_FLAG_MULTISELECT; // Requested attributes: InitInfo.cAttributesToFetch = 1; // We only need the SID value. LPTSTR pSidAttr = g_wzObjectSID; LPCTSTR aptzRequestedAttributes[1]; aptzRequestedAttributes[0] = pSidAttr; InitInfo.apwzAttributeNames = (const WCHAR **)aptzRequestedAttributes; if ( m_bstrServerName && _tcslen(m_bstrServerName) ) { // use machine name for remote machine InitInfo.pwzTargetComputer = m_bstrServerName; } else { // or use NULL for local machine InitInfo.pwzTargetComputer = NULL; } hr = spDsObjectPicker->Initialize(&InitInfo); if( FAILED( hr ) ) { return hr; } CComPtr spDataObject; hr = spDsObjectPicker->InvokeDialog( hWndParent, &spDataObject ); if( FAILED( hr ) || hr == S_FALSE ) { // When user selected "Cancel", ObjectPicker will return S_FALSE. return hr; } STGMEDIUM stgmedium = { TYMED_HGLOBAL , NULL }; UINT cf = RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST); if( 0 == cf ) { return E_FAIL; } FORMATETC formatetc = { (CLIPFORMAT)cf , NULL , DVASPECT_CONTENT , -1 , TYMED_HGLOBAL }; hr = spDataObject->GetData( &formatetc, &stgmedium ); if( FAILED( hr ) ) { return hr; } PDS_SELECTION_LIST pDsSelList = (PDS_SELECTION_LIST) GlobalLock( stgmedium.hGlobal ); if( ! pDsSelList ) { return E_FAIL; } hr = AddSelectionSidsToGroup( pDsSelList ); GlobalUnlock( stgmedium.hGlobal ); ReleaseStgMedium( &stgmedium ); #else // OLD_OBJECT_PICKER HRESULT hr; BOOL fBadArg = FALSE; ULONG flDsObjectPicker = 0; ULONG flUserGroupObjectPicker = 0; ULONG flComputerObjectPicker = 0; ULONG flInitialScope = DSOP_SCOPE_SPECIFIED_MACHINE; flDsObjectPicker = flInitialScope | DSOP_SCOPE_DIRECTORY | DSOP_SCOPE_DOMAIN_TREE | DSOP_SCOPE_EXTERNAL_TRUSTED_DOMAINS ; flUserGroupObjectPicker = UGOP_GLOBAL_GROUPS | UGOP_ACCOUNT_GROUPS_SE | UGOP_UNIVERSAL_GROUPS_SE | UGOP_RESOURCE_GROUPS_SE | UGOP_LOCAL_GROUPS ; // // Call the API // PDSSELECTIONLIST pDsSelList = NULL; GETUSERGROUPSELECTIONINFO ugsi; ZeroMemory(&ugsi, sizeof ugsi); ugsi.cbSize = sizeof(GETUSERGROUPSELECTIONINFO); ugsi.hwndParent = hWndParent; // parent window if ( m_bstrServerName && _tcslen(m_bstrServerName) ) { // use machine name for remote machine ugsi.ptzComputerName= m_bstrServerName; } else { // or use NULL for local machine ugsi.ptzComputerName= NULL; } ugsi.ptzDomainName = NULL; ugsi.flObjectPicker = OP_MULTISELECT; ugsi.flDsObjectPicker = flDsObjectPicker; ugsi.flStartingScope = flInitialScope; ugsi.flUserGroupObjectPickerSpecifiedDomain = flUserGroupObjectPicker; ugsi.flUserGroupObjectPickerOtherDomains = flUserGroupObjectPicker; ugsi.ppDsSelList = &pDsSelList; // requested attributes: LPTSTR pSidAttr = g_wzObjectSID; LPCTSTR aptzRequestedAttributes[1]; aptzRequestedAttributes[0] = pSidAttr; ugsi.cRequestedAttributes = 1; // we only need the SID value ugsi.aptzRequestedAttributes = (const WCHAR **)aptzRequestedAttributes; hr = GetUserGroupSelection(&ugsi); if (SUCCEEDED(hr) && hr != S_FALSE ) { // when user selected "Cancel", ObjectPicker will return S_FALSE // get selected SIDs hr = AddSelectionSidsToGroup( pDsSelList ); } if (pDsSelList) { FreeDsSelectionList(pDsSelList); } #endif // OLD_OBJECT_PICKER return hr; } ///////////////////////////////////////////////////////////////////////////// // CDisplayGroupsDialog ////////////////////////////////////////////////////////////////////////////// /*++ CDisplayGroupsDialog::CDisplayGroupsDialog Constructor --*/ ////////////////////////////////////////////////////////////////////////////// CDisplayGroupsDialog::CDisplayGroupsDialog( GroupList *pGroups ) { TRACE_FUNCTION("CDisplayGroupsDialog::CDisplayGroupsDialog"); m_pGroups = pGroups; } ////////////////////////////////////////////////////////////////////////////// /*++ CDisplayGroupsDialog::~CDisplayGroupsDialog Destructor --*/ ////////////////////////////////////////////////////////////////////////////// CDisplayGroupsDialog::~CDisplayGroupsDialog() { } ////////////////////////////////////////////////////////////////////////////// /*++ CDisplayGroupsDialog::OnInitDialog --*/ ////////////////////////////////////////////////////////////////////////////// LRESULT CDisplayGroupsDialog::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { TRACE_FUNCTION("CDisplayGroupsDialog::OnInitDialog"); m_hWndGroupList = GetDlgItem(IDC_LIST_GROUPS); // // first, set the list box to 2 columns // LVCOLUMN lvc; int iCol; WCHAR achColumnHeader[256]; HINSTANCE hInst; // initialize the LVCOLUMN structure lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT; lvc.cx = 300; lvc.pszText = achColumnHeader; // first column header: name hInst = _Module.GetModuleInstance(); ::LoadStringW(hInst, IDS_DISPLAY_GROUPS_FIRSTCOLUMN, achColumnHeader, sizeof(achColumnHeader)/sizeof(achColumnHeader[0])); lvc.iSubItem = 0; ListView_InsertColumn(m_hWndGroupList, 0, &lvc); // // populate the list control with data // if ( ! PopulateGroupList( 0 ) ) { ErrorTrace(ERROR_NAPMMC_SELATTRDLG, "PopulateRuleAttrs() failed"); return 0; } // Set some items based on whether the list is empty or not. if( m_pGroups->size() ) { // Select the first item. ListView_SetItemState(m_hWndGroupList, 0, LVIS_SELECTED, LVIS_SELECTED); } else { // The list is empty -- disable the OK button. ::EnableWindow(GetDlgItem(IDOK), FALSE); // Make sure the Remove button is not enabled initially. ::EnableWindow(GetDlgItem(IDC_BUTTON_REMOVE_GROUP), FALSE); } #ifdef DEBUG m_pGroups->DebugPrintGroups(); #endif // DEBUG // Set the listview control so that double-click anywhere in row selects. ListView_SetExtendedListViewStyleEx(m_hWndGroupList, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); return 1; // Let the system set the focus } //+--------------------------------------------------------------------------- // // Function: OnListViewDbclk // // Class: CDisplayGroupsDialog // // Synopsis: handle the case where the user has changed a selection // enable/disable OK, CANCEL button accordingly // // Arguments: int idCtrl - ID of the list control // LPNMHDR pnmh - notification message // BOOL& bHandled - handled or not? // // Returns: LRESULT - // // History: Created Header byao 2/19/98 11:15:30 PM // modified mmaguire 08/12/98 for use in Group List dialog // //+--------------------------------------------------------------------------- //LRESULT CDisplayGroupsDialog::OnListViewDbclk(int idCtrl, // LPNMHDR pnmh, // BOOL& bHandled) //{ // TRACE_FUNCTION("CDisplayGroupsDialog::OnListViewDbclk"); // // return OnAdd(idCtrl, IDC_BUTTON_ADD_CONDITION, m_hWndGroupList, bHandled); // the same as ok; //} ////////////////////////////////////////////////////////////////////////////// /*++ CDisplayGroupsDialog::OnAdd --*/ ////////////////////////////////////////////////////////////////////////////// LRESULT CDisplayGroupsDialog::OnAdd(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { TRACE_FUNCTION("CDisplayGroupsDialog::OnAdd"); HRESULT hr; #ifdef DEBUG m_pGroups->DebugPrintGroups(); #endif // DEBUG // Store the previous size of the list. int iSize = m_pGroups->size(); // // NTGroups Picker // hr = m_pGroups->PickNtGroups( m_hWnd ); #ifdef DEBUG m_pGroups->DebugPrintGroups(); #endif // DEBUG // // PickNtGroups will return S_FALSE when user cancelled out of the dialog. // if ( SUCCEEDED(hr) && hr != S_FALSE ) { // Add the new groups to the display's list. PopulateGroupList( iSize ); // Make sure the OK button is enabled. ::EnableWindow(GetDlgItem(IDOK), TRUE); } else { ErrorTrace(ERROR_NAPMMC_NTGCONDITION, "NTGroup picker failed, err = %x", hr); if ( hr == E_NOTIMPL ) { // we return this error whether the SID value can't be retrieved ShowErrorDialog( m_hWnd, IDS_ERROR_OBJECT_PICKER_NO_SIDS, NULL, hr ); } else if ( hr != S_FALSE ) { ShowErrorDialog( m_hWnd, IDS_ERROR_OBJECT_PICKER, NULL, hr ); } } // ISSUE: This function wants an LRESULT, not and HRESULT // -- not sure of importance of return code here. return S_OK; } ////////////////////////////////////////////////////////////////////////////// /*++ CDisplayGroupsDialog::OnRemove --*/ ////////////////////////////////////////////////////////////////////////////// LRESULT CDisplayGroupsDialog::OnRemove(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { TRACE_FUNCTION("CDisplayGroupsDialog::OnRemove"); #ifdef DEBUG m_pGroups->DebugPrintGroups(); #endif // DEBUG // // Has the user chosen any condition type yet? // LVITEM lvi; // Find out what's selected. // MAM: This is not what we want here: int iIndex = ListView_GetSelectionMark(m_hWndGroupList); int iSelected = ListView_GetNextItem(m_hWndGroupList, -1, LVNI_SELECTED); DebugTrace(DEBUG_NAPMMC_SELATTRDLG, "Selected item: %d", iSelected ); if( -1 != iSelected ) { // The index inside the attribute list is stored as the lParam of this item. m_pGroups->erase( m_pGroups->begin() + iSelected ); ListView_DeleteItem(m_hWndGroupList, iSelected ); // The user may have removed all of the groups, leaving an // empty listnd out if the user should be able to click OK. if( ! m_pGroups->size() ) { // Yes, disable the ok button. ::EnableWindow(GetDlgItem(IDOK), FALSE); } // Try to make sure that the same position remains selected. if( ! CustomListView_SetItemState(m_hWndGroupList, iSelected, LVIS_SELECTED, LVIS_SELECTED) ) { // We failed to select the same position, probably because we just // deleted the last element. Try to select the position before it. ListView_SetItemState(m_hWndGroupList, iSelected -1, LVIS_SELECTED, LVIS_SELECTED); } } #ifdef DEBUG m_pGroups->DebugPrintGroups(); #endif // DEBUG return 0; } ////////////////////////////////////////////////////////////////////////////// /*++ CDisplayGroupsDialog::OnOK --*/ ////////////////////////////////////////////////////////////////////////////// LRESULT CDisplayGroupsDialog::OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { TRACE_FUNCTION("CDisplayGroupsDialog::OnOK"); EndDialog(TRUE); return 0; } ////////////////////////////////////////////////////////////////////////////// /*++ CDisplayGroupsDialog::OnCancel --*/ ////////////////////////////////////////////////////////////////////////////// LRESULT CDisplayGroupsDialog::OnCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { TRACE_FUNCTION("+NAPMMC+:# CDisplayGroupsDialog::OnCancel\n"); // FALSE will be the return value of the DoModal call on this dialog. EndDialog(FALSE); return 0; } ////////////////////////////////////////////////////////////////////////////// /*++ CDisplayGroupsDialog::PopulateGroupList --*/ ////////////////////////////////////////////////////////////////////////////// BOOL CDisplayGroupsDialog::PopulateGroupList( int iStartIndex ) { TRACE_FUNCTION("CDisplayGroupsDialog::PopulateCondAttrs"); int iIndex; WCHAR wzText[MAX_PATH]; WCHAR * pszNextGroup; LVITEM lvi; lvi.mask = LVIF_TEXT | LVIF_STATE; lvi.state = 0; lvi.stateMask = 0; lvi.iSubItem = 0; lvi.iItem = iStartIndex; GroupList::iterator thePair; for( thePair = m_pGroups->begin() + iStartIndex ; thePair != m_pGroups->end(); ++thePair ) { lvi.pszText = thePair->second; ListView_InsertItem(m_hWndGroupList, &lvi); // ListView_SetItemText(m_hWndGroupList, iIndex, 1, L"@Not yet implemented"); ++lvi.iItem; } return TRUE; } ////////////////////////////////////////////////////////////////////////////// /*++ CDisplayGroupsDialog::OnListViewItemChanged We enable or disable the Remove button depending on whether an item is selected. --*/ ////////////////////////////////////////////////////////////////////////////// LRESULT CDisplayGroupsDialog::OnListViewItemChanged(int idCtrl, LPNMHDR pnmh, BOOL& bHandled) { TRACE_FUNCTION("CDisplayGroupsDialog::OnListViewItemChanged"); // Find out what's selected. int iSelected = ListView_GetNextItem(m_hWndGroupList, -1, LVNI_SELECTED); if (-1 == iSelected ) { if( ::GetFocus() == GetDlgItem(IDC_BUTTON_REMOVE_GROUP)) ::SetFocus(GetDlgItem(IDC_BUTTON_ADD_GROUP)); // The user selected nothing, let's disable the remove button. ::EnableWindow(GetDlgItem(IDC_BUTTON_REMOVE_GROUP), FALSE); } else { // Yes, enable the remove button. ::EnableWindow(GetDlgItem(IDC_BUTTON_REMOVE_GROUP), TRUE); } bHandled = FALSE; return 0; } #ifdef DEBUG HRESULT GroupList::DebugPrintGroups() { TRACE_FUNCTION("GroupList::DebugPrintGroups"); DebugTrace(DEBUG_NAPMMC_SELATTRDLG, "Begin GroupList dump" ); GroupList::iterator thePair; for( thePair = begin(); thePair != end(); ++thePair ) { thePair->second; DebugTrace(DEBUG_NAPMMC_SELATTRDLG, "Group: %ws %ws", thePair->first, thePair->second ); } DebugTrace(DEBUG_NAPMMC_SELATTRDLG, "End GroupList dump" ); return S_OK; } #endif // DEBUG ////////////////////////////////////////////////////////////////////////////// /*++ NTGroup_ListView::AddMoreGroups --*/ ////////////////////////////////////////////////////////////////////////////// DWORD NTGroup_ListView::AddMoreGroups() { if ( m_hListView == NULL ) return 0; // Store the previous size of the list. int iSize = GroupList::size(); // // NTGroups Picker // HRESULT hr = GroupList::PickNtGroups( m_hParent ); // // PickNtGroups will return S_FALSE when user cancelled out of the dialog. // if ( SUCCEEDED(hr) && hr != S_FALSE ) { // Add the new groups to the display's list. PopulateGroupList( iSize ); } else { if ( hr == E_NOTIMPL ) { // we return this error whether the SID value can't be retrieved ShowErrorDialog( m_hParent, IDS_ERROR_OBJECT_PICKER_NO_SIDS, NULL, hr ); } else if ( hr != S_FALSE ) { ShowErrorDialog( m_hParent, IDS_ERROR_OBJECT_PICKER, NULL, hr ); } } // ISSUE: This function wants an LRESULT, not and HRESULT // -- not sure of importance of return code here. return S_OK; } ////////////////////////////////////////////////////////////////////////////// /*++ NTGroup_ListView::RemoveSelectedGroups --*/ ////////////////////////////////////////////////////////////////////////////// DWORD NTGroup_ListView::RemoveSelectedGroups() { if ( m_hListView == NULL) return 0; // // Has the user chosen any condition type yet? // LVITEM lvi; // Find out what's selected. int iSelected = ListView_GetNextItem(m_hListView, -1, LVNI_SELECTED); if( -1 != iSelected ) { // The index inside the attribute list is stored as the lParam of this item. GroupList::erase( GroupList::begin() + iSelected ); ListView_DeleteItem(m_hListView, iSelected ); // Try to make sure that the same position remains selected. if( ! CustomListView_SetItemState(m_hListView, iSelected, LVIS_SELECTED, LVIS_SELECTED) ) { // We failed to select the same position, probably because we just // deleted the last element. Try to select the position before it. ListView_SetItemState(m_hListView, iSelected -1, LVIS_SELECTED, LVIS_SELECTED); } } return (iSelected != -1 ? 1 : 0); } ////////////////////////////////////////////////////////////////////////////// /*++ NTGroup_ListView::PopulateGroupList --*/ ////////////////////////////////////////////////////////////////////////////// BOOL NTGroup_ListView::PopulateGroupList( int iStartIndex ) { if ( m_hListView == NULL) return 0; int iIndex; WCHAR wzText[MAX_PATH]; WCHAR * pszNextGroup; LVITEM lvi; lvi.mask = LVIF_TEXT | LVIF_STATE; lvi.state = 0; lvi.stateMask = 0; lvi.iSubItem = 0; lvi.iItem = iStartIndex; GroupList::iterator thePair; for( thePair = GroupList::begin() + iStartIndex ; thePair != GroupList::end(); ++thePair ) { lvi.pszText = thePair->second; ListView_InsertItem(m_hListView, &lvi); ++lvi.iItem; } return TRUE; }