windows-nt/Source/XPSP1/NT/net/ias/mmc/nap/ntgroups.cpp
2020-09-26 16:20:57 +08:00

1597 lines
35 KiB
C++

//////////////////////////////////////////////////////////////////////////////
/*++
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 <objsel.h>
#include "NTGroups.h"
//
// where we can find declarations needed in this file:
//
#include <vector>
#include <utility> // For "pair"
#include <atltmp.h>
#include <initguid.h>
#include <activeds.h>
#include <lmcons.h>
#include <objsel.h>
#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 Pointer>
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<CDisplayGroupsDialog, FALSE> 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<PBYTE>
{
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<IDsObjectPicker> 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<IDataObject> 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;
}