1597 lines
35 KiB
C++
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;
|
||
|
}
|
||
|
|
||
|
|