mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1156 lines
35 KiB
1156 lines
35 KiB
// DSColumn.cpp : Implementation of ds column routines and classes
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1999
|
|
//
|
|
// File: DSColumn.cpp
|
|
//
|
|
// Contents: DS Column routines, classes, and static data
|
|
//
|
|
// History: 12-Mar-99 JeffJon Created
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "DSColumn.h"
|
|
#include "dscookie.h"
|
|
#include "dscmn.h" // CrackName()
|
|
#include "dsutil.h"
|
|
|
|
BOOL ColumnExtractStringValue(
|
|
OUT CString& strref,
|
|
IN CDSCookie*,
|
|
IN PADS_SEARCH_COLUMN pColumn,
|
|
IN DWORD iValue)
|
|
{
|
|
if (pColumn == NULL || pColumn->dwNumValues <= iValue)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (pColumn->dwADsType)
|
|
{
|
|
case ADSTYPE_CASE_IGNORE_STRING:
|
|
strref = (LPCWSTR)pColumn->pADsValues[iValue].CaseIgnoreString;
|
|
break;
|
|
case ADSTYPE_DN_STRING:
|
|
strref = (LPCWSTR)pColumn->pADsValues[iValue].DNString;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL ColumnExtractString(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN pColumn)
|
|
{
|
|
return ColumnExtractStringValue( strref, pCookie, pColumn, 0 );
|
|
}
|
|
|
|
BOOL ColumnExtractElementFromDN(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN pColumn,
|
|
long lElement,
|
|
IN DWORD iValue = 0);
|
|
|
|
BOOL ColumnExtractElementFromDN(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN pColumn,
|
|
long lElement,
|
|
IN DWORD iValue)
|
|
{
|
|
if (pColumn == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL fRetval = FALSE;
|
|
CString str;
|
|
CComBSTR bstr;
|
|
HRESULT hr = S_OK;
|
|
do { // false loop
|
|
if ( !ColumnExtractStringValue( str, pCookie, pColumn, iValue ) || str.IsEmpty() )
|
|
{
|
|
strref.Empty();
|
|
fRetval = TRUE;
|
|
break;
|
|
}
|
|
CPathCracker pathCracker;
|
|
hr = pathCracker.Set(const_cast<BSTR>((LPCTSTR)str), ADS_SETTYPE_DN);
|
|
if ( FAILED(hr) )
|
|
break;
|
|
// no need to reset this
|
|
hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
|
|
if ( FAILED(hr) )
|
|
break;
|
|
hr = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF);
|
|
if ( FAILED(hr) )
|
|
break;
|
|
hr = pathCracker.GetElement(lElement, &bstr);
|
|
strref = bstr;
|
|
fRetval = TRUE;
|
|
} while (FALSE); // false loop
|
|
|
|
return fRetval;
|
|
}
|
|
|
|
BOOL ColumnExtractLeafFromDN(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN pColumn)
|
|
{
|
|
return ColumnExtractElementFromDN( strref, pCookie, pColumn, 0 );
|
|
}
|
|
|
|
BOOL ColumnExtractParentFromDN(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN pColumn)
|
|
{
|
|
return ColumnExtractElementFromDN( strref, pCookie, pColumn, 1 );
|
|
}
|
|
|
|
BOOL ColumnExtractGreatGrandparentFromDN(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN pColumn)
|
|
{
|
|
return ColumnExtractElementFromDN( strref, pCookie, pColumn, 3 );
|
|
}
|
|
|
|
BOOL ColumnExtractConnectionDisplayName(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN pColumn)
|
|
{
|
|
if (pColumn == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ADS_INTEGER adsint = 0;
|
|
switch (pColumn->dwADsType)
|
|
{
|
|
case ADSTYPE_INTEGER:
|
|
adsint = pColumn->pADsValues->Integer;
|
|
break;
|
|
default:
|
|
// no value, let it stay 0
|
|
break;
|
|
}
|
|
if (NTDSCONN_OPT_IS_GENERATED & adsint) {
|
|
strref.LoadString (IDS_CONNECTION_KCC_GENERATED);
|
|
} else {
|
|
strref = pCookie->GetName();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL ColumnExtractAttribute(
|
|
OUT CString& strref,
|
|
IN CDSCookie*,
|
|
IN PADS_SEARCH_COLUMN pColumn)
|
|
{
|
|
if (pColumn == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (pColumn->dwADsType)
|
|
{
|
|
case ADSTYPE_DN_STRING :
|
|
strref = pColumn->pADsValues->DNString;
|
|
break;
|
|
|
|
case ADSTYPE_CASE_EXACT_STRING :
|
|
strref = pColumn->pADsValues->CaseExactString;
|
|
break;
|
|
|
|
case ADSTYPE_CASE_IGNORE_STRING:
|
|
strref = pColumn->pADsValues->CaseIgnoreString;
|
|
break;
|
|
|
|
case ADSTYPE_PRINTABLE_STRING :
|
|
strref = pColumn->pADsValues->PrintableString;
|
|
break;
|
|
|
|
case ADSTYPE_NUMERIC_STRING :
|
|
strref = pColumn->pADsValues->NumericString;
|
|
break;
|
|
|
|
case ADSTYPE_OBJECT_CLASS :
|
|
strref = pColumn->pADsValues->ClassName;
|
|
break;
|
|
|
|
case ADSTYPE_BOOLEAN :
|
|
strref = ((DWORD)pColumn->pADsValues->Boolean) ? L"TRUE" : L"FALSE";
|
|
break;
|
|
|
|
case ADSTYPE_INTEGER :
|
|
strref.Format(L"%d", (DWORD) pColumn->pADsValues->Integer);
|
|
break;
|
|
|
|
case ADSTYPE_OCTET_STRING :
|
|
{
|
|
CString sOctet = L"";
|
|
|
|
BYTE b;
|
|
for ( DWORD idx=0; idx<pColumn->pADsValues->OctetString.dwLength; idx++)
|
|
{
|
|
b = ((BYTE *)pColumn->pADsValues->OctetString.lpValue)[idx];
|
|
sOctet.Format(L"0x%02x ", b);
|
|
strref += sOctet;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_UTC_TIME:
|
|
{
|
|
PTSTR ptszDate = NULL;
|
|
int cchDate = 0;
|
|
SYSTEMTIME st = {0};
|
|
|
|
if (!SystemTimeToTzSpecificLocalTime(NULL, &pColumn->pADsValues->UTCTime, &st))
|
|
{
|
|
strref = L"";
|
|
return TRUE;
|
|
}
|
|
cchDate = GetDateFormat(LOCALE_USER_DEFAULT, 0 ,
|
|
&st, NULL,
|
|
ptszDate, 0);
|
|
ptszDate = (PTSTR)malloc(sizeof(TCHAR) * cchDate);
|
|
if (GetDateFormat(LOCALE_USER_DEFAULT, 0,
|
|
&st, NULL,
|
|
ptszDate, cchDate))
|
|
{
|
|
strref = ptszDate;
|
|
}
|
|
else
|
|
{
|
|
strref = L"";
|
|
}
|
|
free(ptszDate);
|
|
|
|
PTSTR ptszTime = NULL;
|
|
|
|
cchDate = GetTimeFormat(LOCALE_USER_DEFAULT, 0 ,
|
|
&st, NULL,
|
|
ptszTime, 0);
|
|
ptszTime = (PTSTR)malloc(sizeof(TCHAR) * cchDate);
|
|
if (ptszTime != NULL)
|
|
{
|
|
if (GetTimeFormat(LOCALE_USER_DEFAULT, 0,
|
|
&st, NULL,
|
|
ptszTime, cchDate))
|
|
{
|
|
strref += _T(" ") + CString(ptszTime);
|
|
}
|
|
else
|
|
{
|
|
strref += _T("");
|
|
}
|
|
free(ptszTime);
|
|
}
|
|
else
|
|
{
|
|
strref = _T("");
|
|
}
|
|
}
|
|
break;
|
|
|
|
default :
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL _ColumnCrackDN(
|
|
OUT CString& strref,
|
|
IN LPCTSTR lpcszDN,
|
|
IN CRACK_NAME_OPR RequestedOpr)
|
|
{
|
|
PWSTR pwzName = NULL;
|
|
HRESULT hr = CrackName(const_cast<PTSTR>(lpcszDN),
|
|
&pwzName,
|
|
RequestedOpr,
|
|
NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (GET_OBJ_CAN_NAME_EX == RequestedOpr)
|
|
{
|
|
LPTSTR ptzCanName = wcschr( pwzName, _T('\n') );
|
|
if (NULL != ptzCanName)
|
|
strref = ptzCanName+1;
|
|
else
|
|
strref.Empty();
|
|
}
|
|
else
|
|
{
|
|
strref = pwzName;
|
|
}
|
|
LocalFreeStringW(&pwzName);
|
|
}
|
|
else
|
|
{
|
|
strref.Empty();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL ColumnExtractNameFromSID(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN)
|
|
{
|
|
return _ColumnCrackDN( strref, pCookie->GetPath(), GET_OBJ_CAN_NAME );
|
|
}
|
|
|
|
BOOL ColumnExtractCanonicalNameFromDN(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN pColumn)
|
|
{
|
|
if (pColumn == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CString str;
|
|
if ( !ColumnExtractString( str, pCookie, pColumn ) || str.IsEmpty() )
|
|
{
|
|
strref.Empty();
|
|
return TRUE;
|
|
}
|
|
|
|
return _ColumnCrackDN( strref, str, GET_OBJ_CAN_NAME_EX );
|
|
}
|
|
|
|
BOOL ColumnExtractDomainFromDN(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN pColumn)
|
|
{
|
|
if (pColumn == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CString str;
|
|
if ( !ColumnExtractString( str, pCookie, pColumn ) || str.IsEmpty() )
|
|
{
|
|
strref.Empty();
|
|
return TRUE;
|
|
}
|
|
|
|
return _ColumnCrackDN( strref, str, GET_DNS_DOMAIN_NAME );
|
|
}
|
|
|
|
int _cdecl _qsort_CompareColumns(const void * elem1, const void * elem2)
|
|
{
|
|
PADSVALUE p1 = (PADSVALUE)elem1;
|
|
PADSVALUE p2 = (PADSVALUE)elem2;
|
|
if (!p1 || !p2 || !p1->DNString || !p2->DNString)
|
|
return 0;
|
|
return wcscmp( p1->DNString, p2->DNString );
|
|
}
|
|
|
|
BOOL ColumnExtractLeafList(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN pColumn)
|
|
{
|
|
if (pColumn == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// alphabetical order
|
|
qsort( pColumn->pADsValues,
|
|
pColumn->dwNumValues,
|
|
sizeof(ADSVALUE),
|
|
_qsort_CompareColumns );
|
|
|
|
CString strSeparator;
|
|
strSeparator.LoadString(IDS_SEPARATOR);
|
|
for (DWORD iValue = 0; iValue < pColumn->dwNumValues; iValue++)
|
|
{
|
|
CString strTransport;
|
|
if ( !ColumnExtractElementFromDN(
|
|
strTransport, pCookie, pColumn, 0, iValue) )
|
|
return FALSE;
|
|
if (0 < iValue)
|
|
strref += strSeparator;
|
|
strref += strTransport;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL _ColumnCrackFRS(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN CRACK_NAME_OPR RequestedOpr)
|
|
{
|
|
CDSCookieInfoConnection* pExtraInfo = NULL;
|
|
if ( NULL == pCookie
|
|
|| _wcsicmp( pCookie->GetClass(), L"nTDSConnection" )
|
|
|| NULL == (pExtraInfo = (CDSCookieInfoConnection*)pCookie->GetExtraInfo())
|
|
|| pExtraInfo->GetClass() != CDSCookieInfoBase::connection
|
|
|| pExtraInfo->m_strFRSComputerReference.IsEmpty()
|
|
)
|
|
{
|
|
strref.Empty();
|
|
return TRUE;
|
|
}
|
|
|
|
return _ColumnCrackDN( strref, pExtraInfo->m_strFRSComputerReference, RequestedOpr );
|
|
}
|
|
|
|
BOOL ColumnExtractFRSComputer(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN)
|
|
{
|
|
return _ColumnCrackFRS( strref, pCookie, GET_OBJ_CAN_NAME_EX );
|
|
}
|
|
|
|
BOOL ColumnExtractFRSDomain(
|
|
OUT CString& strref,
|
|
IN CDSCookie* pCookie,
|
|
IN PADS_SEARCH_COLUMN)
|
|
{
|
|
return _ColumnCrackFRS( strref, pCookie, GET_DNS_DOMAIN_NAME );
|
|
}
|
|
|
|
ATTRIBUTE_COLUMN colName = { ATTR_COLTYPE_NAME,
|
|
IDS_COLUMN_NAME, //column header
|
|
100, //col. width
|
|
NULL, //ldap attr. name
|
|
NULL }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colClass= { ATTR_COLTYPE_CLASS,
|
|
IDS_COLUMN_TYPE, //column header
|
|
100, //col. width
|
|
NULL, //ldap attr. name
|
|
NULL }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colDesc = { ATTR_COLTYPE_DESC,
|
|
IDS_COLUMN_DESCRIPTION, //column header
|
|
150, //col. width
|
|
NULL, //ldap attr. name
|
|
NULL }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colSite = { ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_SITE, //column header
|
|
100, //col. width
|
|
L"siteObject", //ldap attr. name
|
|
ColumnExtractLeafFromDN }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colLocation = { ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_LOCATION, //column header
|
|
150, //col. width
|
|
L"location", //ldap attr. name
|
|
NULL }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colDomain = { ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_DOMAIN, //column header
|
|
150, //col. width
|
|
L"serverReference", //ldap attr. name
|
|
ColumnExtractDomainFromDN }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colBridgehead = { ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_BRIDGEHEAD, //column header
|
|
150, //col. width
|
|
L"bridgeheadTransportList", //ldap attr. name
|
|
ColumnExtractLeafList }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colReplicaComputer = { ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_COMPUTER, //column header
|
|
100, //col. width
|
|
L"fRSComputerReference", //ldap attr. name
|
|
ColumnExtractCanonicalNameFromDN }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colReplicaDomain = { ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_DOMAIN, //column header
|
|
150, //col. width
|
|
L"fRSComputerReference", //ldap attr. name
|
|
ColumnExtractDomainFromDN }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colFromFRSComputer = { ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_FROM_COMPUTER, //column header
|
|
100, //col. width
|
|
L"fromServer", //ldap attr. name
|
|
ColumnExtractFRSComputer }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colFromFRSDomain = { ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_FROM_DOMAIN, //column header
|
|
150, //col. width
|
|
L"fromServer", //ldap attr. name
|
|
ColumnExtractFRSDomain }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colConnectionName={ ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_NAME, //column header
|
|
150, //col. width
|
|
L"options", //ldap attr. name
|
|
ColumnExtractConnectionDisplayName}; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colFromServer={ ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_FROM_SERVER, //column header
|
|
100, //col. width
|
|
L"fromServer", //ldap attr. name
|
|
ColumnExtractParentFromDN }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colFromSite={ ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_FROM_SITE, //column header
|
|
100, //col. width
|
|
L"fromServer", //ldap attr. name
|
|
ColumnExtractGreatGrandparentFromDN }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colCost = { ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_COST, //column header
|
|
75, //col. width
|
|
L"cost", //ldap attr. name
|
|
ColumnExtractAttribute }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colReplInterval = { ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_REPLINTERVAL, //column header
|
|
150, //col. width
|
|
L"replInterval", //ldap attr. name
|
|
ColumnExtractAttribute }; //extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colNameFromSID={ ATTR_COLTYPE_SPECIAL,
|
|
IDS_COLUMN_READABLE_NAME, // column header
|
|
100, // column width
|
|
L"container",
|
|
ColumnExtractNameFromSID }; // extract fn()
|
|
|
|
ATTRIBUTE_COLUMN colGenericSpecial={ ATTR_COLTYPE_SPECIAL,
|
|
0, // resource id 0 means load it from the special column array
|
|
50,
|
|
NULL,
|
|
ColumnExtractAttribute };
|
|
|
|
ATTRIBUTE_COLUMN colModifiedTime={ ATTR_COLTYPE_MODIFIED_TIME,
|
|
0,
|
|
50,
|
|
NULL,
|
|
ColumnExtractAttribute };
|
|
|
|
SPECIAL_COLUMN g_specialCols[] =
|
|
{
|
|
{ IDS_COLUMN_BUSINESS_PHONE, L"telephoneNumber", 100 },
|
|
{ IDS_COLUMN_CITY, L"l", 150 },
|
|
{ IDS_COLUMN_COMPANY, L"company", 150 },
|
|
{ IDS_COLUMN_COUNTRY, L"c", AUTO_WIDTH }, // Default to the width of the header string
|
|
{ IDS_COLUMN_DEPARTMENT, L"department", 150 },
|
|
{ IDS_COLUMN_DISPLAY_NAME, L"displayName", 100 },
|
|
{ IDS_COLUMN_SAM_ACCOUNT_NAME, L"sAMAccountName", 120 },
|
|
{ IDS_COLUMN_MAIL, L"mail", 100 },
|
|
{ IDS_COLUMN_ALIAS_NAME, L"mailNickname", 175 },
|
|
{ IDS_COLUMN_HOME_MDB, L"homeMDB", 100 },
|
|
{ IDS_COLUMN_FIRST_NAME, L"givenName", 100 },
|
|
{ IDS_COLUMN_IMHOMEURL, L"msExchIMPhysicalURL", 170 },
|
|
{ IDS_COLUMN_IMURL, L"msExchIMMetaPhysicalURL", 140 },
|
|
{ IDS_COLUMN_LAST_NAME, L"sn", 100 },
|
|
{ IDS_COLUMN_MODIFIED, L"whenChanged", 130 },
|
|
{ IDS_COLUMN_OFFICE, L"physicalDeliveryOfficeName", 100 },
|
|
{ IDS_COLUMN_STATE, L"st", 100 },
|
|
{ IDS_COLUMN_TARGET_ADDRESS , L"targetAddress", 100 },
|
|
{ IDS_COLUMN_TITLE, L"title", 100 },
|
|
{ IDS_COLUMN_UPN, L"userPrincipalName", 200 },
|
|
{ IDS_COLUMN_TEXTENCODEORADDRESS, L"textEncodedORAddress", 130 },
|
|
{ IDS_COLUMN_ZIP_CODE, L"postalCode", 100 }
|
|
};
|
|
|
|
PATTRIBUTE_COLUMN colsSubnetContainer[6] = { &colName, &colSite, &colLocation, &colClass, &colDesc, NULL };
|
|
PATTRIBUTE_COLUMN colsSitesContainer[5] = { &colName, &colLocation, &colClass, &colDesc, NULL };
|
|
PATTRIBUTE_COLUMN colsServersContainer[6] = { &colName, &colDomain, &colBridgehead, &colClass, &colDesc, NULL };
|
|
PATTRIBUTE_COLUMN colsNTDSDSA[6] = { &colConnectionName, &colFromServer, &colFromSite, &colClass, &colDesc, NULL };
|
|
PATTRIBUTE_COLUMN colsInterSiteTransport[6] = { &colName, &colClass, &colDesc, &colCost, &colReplInterval, NULL };
|
|
PATTRIBUTE_COLUMN colsFRSReplicaSet[6] = { &colName, &colReplicaComputer, &colReplicaDomain, &colClass, &colDesc, NULL };
|
|
PATTRIBUTE_COLUMN colsFRSMember[6] = { &colConnectionName, &colFromFRSComputer, &colFromFRSDomain, &colClass, &colDesc, NULL };
|
|
PATTRIBUTE_COLUMN colsFSP[5] = { &colName, &colClass, &colDesc, &colNameFromSID, NULL };
|
|
|
|
PATTRIBUTE_COLUMN colsDefault[4] = { &colName, &colClass, &colDesc, NULL };
|
|
|
|
// currently, any additional columns must be of string type
|
|
COLUMNS_FOR_CLASS g_colarray[] = {
|
|
{ _T("subnetContainer"), _T("subnetContainer"), 5, colsSubnetContainer },
|
|
{ _T("sitesContainer"), _T("sitesContainer"), 4, colsSitesContainer},
|
|
{ _T("serversContainer"), _T("serversContainer"), 5, colsServersContainer},
|
|
{ _T("nTDSDSA"), _T("nTDSDSA"), 5, colsNTDSDSA },
|
|
{ _T("interSiteTransport"), _T("interSiteTransport"), 5, colsInterSiteTransport},
|
|
{ _T("nTFRSReplicaSet"), _T("nTFRSReplicaSet"), 5, colsFRSReplicaSet },
|
|
{ _T("nTFRSMember"), _T("nTFRSMember"), 5, colsFRSMember },
|
|
{ _T("ForeignSecurityPrincipals"), _T("ForeignSecurityPrincipals"), 4, colsFSP },
|
|
{ NULL, DEFAULT_COLUMN_SET, 3, colsDefault } // empty one at the end; must be here
|
|
};
|
|
|
|
/*
|
|
COLUMNS_FOR_CLASS* GetColumnsForClass( LPCTSTR i_pcszLdapClassName )
|
|
{
|
|
if (NULL == i_pcszLdapClassName)
|
|
i_pcszLdapClassName = L"";
|
|
COLUMNS_FOR_CLASS* pColsForClass;
|
|
for (pColsForClass = g_colarray; NULL != pColsForClass->pcszLdapClassName; pColsForClass++) {
|
|
if ( 0 == _wcsicmp(i_pcszLdapClassName, pColsForClass->pcszLdapClassName) ) {
|
|
break;
|
|
}
|
|
}
|
|
ASSERT( NULL != pColsForClass );
|
|
return pColsForClass;
|
|
}
|
|
*/
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// CDSColumnSet
|
|
|
|
CDSColumnSet* CDSColumnSet::CreateColumnSet(PCOLUMNS_FOR_CLASS pColsForClass, SnapinType snapinType)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// Using the class name as both the column id and the class name for the column set
|
|
CDSColumnSet* pNewColumnSet = new CDSColumnSet(pColsForClass->pcszColumnID, pColsForClass->pcszLdapClassName);
|
|
if (!pNewColumnSet)
|
|
{
|
|
TRACE(L"Unable to allocate memory for new column set\n");
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
UINT nUserColCount = 0;
|
|
for (int idx = 0; idx < pColsForClass->nColumns; idx ++)
|
|
{
|
|
CString cstrHeader;
|
|
CDSColumn* pNewColumn;
|
|
|
|
if (pColsForClass->apColumns[idx]->resid == 0)
|
|
{
|
|
// Don't add the exchange special columns in DSSite
|
|
if (snapinType == SNAPINTYPE_SITE)
|
|
continue;
|
|
|
|
cstrHeader.LoadString(g_specialCols[nUserColCount].resid);
|
|
pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
|
|
LVCFMT_LEFT,
|
|
g_specialCols[nUserColCount].iColumnWidth,
|
|
idx,
|
|
FALSE,
|
|
g_specialCols[nUserColCount].ptszAttribute,
|
|
pColsForClass->apColumns[idx]->coltype,
|
|
pColsForClass->apColumns[idx]->pfnExtract);
|
|
nUserColCount++;
|
|
}
|
|
else
|
|
{
|
|
cstrHeader.LoadString(pColsForClass->apColumns[idx]->resid);
|
|
pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
|
|
LVCFMT_LEFT,
|
|
pColsForClass->apColumns[idx]->iColumnWidth,
|
|
idx,
|
|
TRUE,
|
|
pColsForClass->apColumns[idx]->pcszAttribute,
|
|
pColsForClass->apColumns[idx]->coltype,
|
|
pColsForClass->apColumns[idx]->pfnExtract);
|
|
}
|
|
ASSERT(pNewColumn);
|
|
if (pNewColumn)
|
|
{
|
|
pNewColumnSet->AddColumn(pNewColumn);
|
|
}
|
|
}
|
|
return pNewColumnSet;
|
|
}
|
|
|
|
|
|
CDSColumnSet* CDSColumnSet::CreateColumnSetFromString(LPCWSTR lpszClassName, SnapinType snapinType)
|
|
{
|
|
COLUMNS_FOR_CLASS* pColsForClass;
|
|
for (pColsForClass = g_colarray; pColsForClass->pcszLdapClassName != NULL; pColsForClass++)
|
|
{
|
|
if (lpszClassName != NULL && pColsForClass->pcszLdapClassName != NULL)
|
|
{
|
|
if (wcscmp(pColsForClass->pcszLdapClassName, lpszClassName) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return CDSColumnSet::CreateColumnSet(pColsForClass, snapinType);
|
|
}
|
|
|
|
CDSColumnSet* CDSColumnSet::CreateDescriptionColumnSet()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
CString szNameHeader;
|
|
VERIFY(szNameHeader.LoadString(IDS_COLUMN_NAME));
|
|
CColumn* pNameColumn = new CColumn(szNameHeader,
|
|
LVCFMT_LEFT,
|
|
100,
|
|
0,
|
|
TRUE);
|
|
|
|
if (pNameColumn == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
CString szDescriptionHeader;
|
|
VERIFY(szDescriptionHeader.LoadString(IDS_COLUMN_DESCRIPTION));
|
|
CColumn* pDescColumn = new CColumn(szDescriptionHeader,
|
|
LVCFMT_LEFT,
|
|
150,
|
|
1,
|
|
TRUE);
|
|
if (pDescColumn == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
CDSColumnSet* pDSColumnSet = new CDSColumnSet(L"***---Description Set---***", NULL);
|
|
if (pDSColumnSet == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
pDSColumnSet->AddColumn(pNameColumn);
|
|
pDSColumnSet->AddColumn(pDescColumn);
|
|
return pDSColumnSet;
|
|
}
|
|
|
|
CDSColumnSet* CDSColumnSet::CreateColumnSetFromDisplaySpecifiers(PCWSTR pszClassName, SnapinType snapinType, MyBasePathsInfo* pBasePathsInfo)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
HRESULT hr = S_OK;
|
|
CDSColumnSet* pNewColumnSet = NULL;
|
|
BOOL bDefaultHardcodedSet = FALSE;
|
|
|
|
//
|
|
// Using the class name as both the column id and the class name for the column set
|
|
//
|
|
pNewColumnSet = new CDSColumnSet(pszClassName, pszClassName);
|
|
if (pNewColumnSet != NULL)
|
|
{
|
|
//
|
|
// Start with the hardcoded columns
|
|
//
|
|
COLUMNS_FOR_CLASS* pColsForClass;
|
|
for (pColsForClass = g_colarray; pColsForClass->pcszLdapClassName != NULL; pColsForClass++)
|
|
{
|
|
if (pszClassName != NULL && pColsForClass->pcszLdapClassName != NULL)
|
|
{
|
|
if (wcscmp(pColsForClass->pcszLdapClassName, pszClassName) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pColsForClass != NULL)
|
|
{
|
|
if (wcscmp(pColsForClass->pcszColumnID, DEFAULT_COLUMN_SET) == 0)
|
|
{
|
|
bDefaultHardcodedSet = TRUE;
|
|
}
|
|
|
|
UINT nUserColCount = 0;
|
|
for (int idx = 0; idx < pColsForClass->nColumns; idx ++)
|
|
{
|
|
CString cstrHeader;
|
|
CDSColumn* pNewColumn;
|
|
|
|
if (pColsForClass->apColumns[idx]->resid == 0)
|
|
{
|
|
// Don't add the exchange special columns in DSSite
|
|
if (snapinType == SNAPINTYPE_SITE)
|
|
continue;
|
|
|
|
cstrHeader.LoadString(g_specialCols[nUserColCount].resid);
|
|
pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
|
|
LVCFMT_LEFT,
|
|
g_specialCols[nUserColCount].iColumnWidth,
|
|
idx,
|
|
FALSE,
|
|
g_specialCols[nUserColCount].ptszAttribute,
|
|
pColsForClass->apColumns[idx]->coltype,
|
|
pColsForClass->apColumns[idx]->pfnExtract);
|
|
nUserColCount++;
|
|
}
|
|
else
|
|
{
|
|
cstrHeader.LoadString(pColsForClass->apColumns[idx]->resid);
|
|
pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
|
|
LVCFMT_LEFT,
|
|
pColsForClass->apColumns[idx]->iColumnWidth,
|
|
idx,
|
|
TRUE,
|
|
pColsForClass->apColumns[idx]->pcszAttribute,
|
|
pColsForClass->apColumns[idx]->coltype,
|
|
pColsForClass->apColumns[idx]->pfnExtract);
|
|
}
|
|
pNewColumnSet->AddColumn(pNewColumn);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now add the DS extraColumns
|
|
//
|
|
CStringList strListColumns;
|
|
hr = GetDisplaySpecifierProperty(pszClassName, L"extraColumns", pBasePathsInfo, strListColumns);
|
|
if (FAILED(hr))
|
|
{
|
|
hr = GetDisplaySpecifierProperty(pszClassName, L"extraColumns", pBasePathsInfo, strListColumns, true);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
UINT nColCount = static_cast<UINT>(pNewColumnSet->GetCount());
|
|
POSITION pos = strListColumns.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CDSColumn* pNewColumn = NULL;
|
|
|
|
CString szExtraColumn = strListColumns.GetNext(pos);
|
|
if (!szExtraColumn.IsEmpty())
|
|
{
|
|
//
|
|
// Parse the 5-tuple to get the elements to make the column
|
|
//
|
|
CString szAttributeName;
|
|
CString szColHeader;
|
|
BOOL bVisible = TRUE;
|
|
int iColumnWidth = 0;
|
|
GUID guidCallbackInterface; // unused. Reserved for future callback interface
|
|
|
|
PWSTR pszTemp = new WCHAR[szExtraColumn.GetLength() + 1];
|
|
if (pszTemp != NULL)
|
|
{
|
|
wcscpy(pszTemp, (LPCWSTR)szExtraColumn);
|
|
|
|
PWSTR pszVisible = NULL;
|
|
PWSTR pszColumnWidth = NULL;
|
|
PWSTR pszGuidCallback = NULL;
|
|
|
|
PWSTR pszNextTuple = pszTemp;
|
|
|
|
|
|
pszNextTuple = wcstok(pszTemp, L",");
|
|
if (pszNextTuple != NULL)
|
|
{
|
|
szAttributeName = pszNextTuple;
|
|
}
|
|
|
|
pszNextTuple = wcstok(NULL, L",");
|
|
if (pszNextTuple != NULL)
|
|
{
|
|
szColHeader = pszNextTuple;
|
|
}
|
|
|
|
pszNextTuple = wcstok(NULL, L",");
|
|
if (pszNextTuple != NULL)
|
|
{
|
|
pszVisible = pszNextTuple;
|
|
int i = _wtoi(pszVisible);
|
|
if (i == 0)
|
|
{
|
|
bVisible = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bVisible = TRUE;
|
|
}
|
|
}
|
|
|
|
pszNextTuple = wcstok(NULL, L",");
|
|
if (pszNextTuple != NULL)
|
|
{
|
|
pszColumnWidth = pszNextTuple;
|
|
iColumnWidth = _wtoi(pszColumnWidth);
|
|
}
|
|
|
|
pszNextTuple = wcstok(NULL, L",");
|
|
if (pszNextTuple != NULL)
|
|
{
|
|
pszGuidCallback = pszNextTuple;
|
|
HRESULT hr2 = ::CLSIDFromString(pszGuidCallback, &guidCallbackInterface);
|
|
if (FAILED(hr2))
|
|
{
|
|
memset(&guidCallbackInterface, 0, sizeof(GUID));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create the column with the retrieved data
|
|
//
|
|
pNewColumn = new CDSColumn((PCWSTR)szColHeader,
|
|
LVCFMT_LEFT,
|
|
iColumnWidth,
|
|
nColCount++,
|
|
bVisible,
|
|
(PCWSTR)szAttributeName,
|
|
ATTR_COLTYPE_SPECIAL,
|
|
ColumnExtractAttribute); // this will be changed to the interface when that is implemented
|
|
}
|
|
|
|
delete[] pszTemp;
|
|
|
|
}
|
|
if (pNewColumn != NULL)
|
|
{
|
|
pNewColumnSet->AddColumn(pNewColumn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we failed to retrieve columns from the display specifier
|
|
// and we hit the default hardcoded set but we were not asking
|
|
// for the default hardcoded set and the snapin isn't the sites snapin
|
|
// Then we delete the column set and we will pickup the actual default
|
|
// column set since we are returning NULL
|
|
//
|
|
if (FAILED(hr) &&
|
|
bDefaultHardcodedSet &&
|
|
_wcsicmp(pszClassName, DEFAULT_COLUMN_SET) != 0 &&
|
|
snapinType != SNAPINTYPE_SITE)
|
|
{
|
|
delete pNewColumnSet;
|
|
pNewColumnSet = NULL;
|
|
}
|
|
return pNewColumnSet;
|
|
}
|
|
|
|
HRESULT CColumnSet::Save(IStream* pStm)
|
|
{
|
|
// save the column set ID
|
|
HRESULT hr = SaveStringHelper(GetColumnID(), pStm);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// save the # of visible columns and
|
|
// the indexes of the visible columns
|
|
// NOTICE: we use MMC's MMC_VISIBLE_COLUMNS format to be consitent
|
|
// and to be able to read back easily
|
|
|
|
INT nTotalCols = GetNumCols();
|
|
|
|
// allocate a bit more than needed (i.e. total # of columns)
|
|
MMC_VISIBLE_COLUMNS* pVisibleColumns =
|
|
(MMC_VISIBLE_COLUMNS*)new BYTE[sizeof(MMC_VISIBLE_COLUMNS) + (sizeof(INT)*(nTotalCols-1))];
|
|
|
|
if (!pVisibleColumns)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
pVisibleColumns->nVisibleColumns = 0;
|
|
int iIndex = 0;
|
|
for (POSITION pos = GetHeadPosition(); (pos != NULL); )
|
|
{
|
|
CColumn* pCol = GetNext(pos);
|
|
if (pCol->IsVisible())
|
|
{
|
|
pVisibleColumns->rgVisibleCols[pVisibleColumns->nVisibleColumns] = iIndex;
|
|
(pVisibleColumns->nVisibleColumns)++;
|
|
}
|
|
iIndex++;
|
|
}
|
|
|
|
// save the right length of the struct
|
|
ULONG nByteCount = sizeof(MMC_VISIBLE_COLUMNS) + (sizeof(INT)*(pVisibleColumns->nVisibleColumns-1));
|
|
ULONG nBytesWritten;
|
|
hr = pStm->Write((void*)pVisibleColumns, nByteCount, &nBytesWritten);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (nBytesWritten < nByteCount)
|
|
{
|
|
hr = STG_E_CANTSAVE;
|
|
}
|
|
}
|
|
|
|
delete[] pVisibleColumns;
|
|
pVisibleColumns = 0;
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CColumnSet::Load(IStream* pStm)
|
|
{
|
|
// NOTICE: we already loaded the column set ID and
|
|
// got a columns set that matches this
|
|
|
|
// read the # of visible columns
|
|
DWORD dwColCount = 0;
|
|
INT nCountMax = GetNumCols();
|
|
HRESULT hr = LoadDWordHelper(pStm, &dwColCount);
|
|
if (FAILED(hr) || ((INT)dwColCount > nCountMax))
|
|
return E_FAIL;
|
|
|
|
// allocate some space for the array past the struct
|
|
MMC_VISIBLE_COLUMNS* pVisibleColumns =
|
|
(MMC_VISIBLE_COLUMNS*)new BYTE[sizeof(MMC_VISIBLE_COLUMNS) + (sizeof(INT)*(dwColCount-1))];
|
|
if (!pVisibleColumns)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
pVisibleColumns->nVisibleColumns = (INT)dwColCount;
|
|
|
|
// load the array of indexes of visible columns
|
|
ULONG nBytesRead;
|
|
|
|
ULONG nByteCount = sizeof(DWORD)*dwColCount;
|
|
INT* pArr = pVisibleColumns->rgVisibleCols;
|
|
hr = pStm->Read(pArr, nByteCount, &nBytesRead);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (nBytesRead < nByteCount)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
// update columns
|
|
AddVisibleColumns(pVisibleColumns);
|
|
}
|
|
}
|
|
delete[] pVisibleColumns;
|
|
pVisibleColumns = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
// CColumnSetList
|
|
|
|
void CColumnSetList::Initialize(SnapinType snapinType,
|
|
MyBasePathsInfo* pBasePathsInfo)
|
|
{
|
|
m_pBasePathsInfo = pBasePathsInfo;
|
|
m_snapinType = snapinType;
|
|
}
|
|
|
|
//
|
|
// Find the column set given a column set ID
|
|
//
|
|
CColumnSet* CColumnSetList::FindColumnSet(LPCWSTR lpszColumnID)
|
|
{
|
|
POSITION pos = GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CColumnSet* pTempSet = GetNext(pos);
|
|
ASSERT(pTempSet != NULL);
|
|
|
|
LPCWSTR lpszTempNodeID = pTempSet->GetColumnID();
|
|
|
|
if (wcscmp(lpszTempNodeID, lpszColumnID) == 0)
|
|
{
|
|
return pTempSet;
|
|
}
|
|
}
|
|
CColumnSet* pNewColSet = CDSColumnSet::CreateColumnSetFromDisplaySpecifiers(lpszColumnID,
|
|
m_snapinType,
|
|
m_pBasePathsInfo);
|
|
if (pNewColSet != NULL)
|
|
{
|
|
AddTail(pNewColSet);
|
|
return pNewColSet;
|
|
}
|
|
return GetDefaultColumnSet();
|
|
}
|
|
|
|
CColumnSet* CColumnSetList::GetDefaultColumnSet()
|
|
{
|
|
if (m_pDefaultColumnSet == NULL)
|
|
{
|
|
m_pDefaultColumnSet = CDSColumnSet::CreateColumnSetFromDisplaySpecifiers(DEFAULT_COLUMN_SET,
|
|
m_snapinType,
|
|
m_pBasePathsInfo);
|
|
}
|
|
return m_pDefaultColumnSet;
|
|
}
|
|
|
|
HRESULT CColumnSetList::Save(IStream* pStm)
|
|
{
|
|
// save # of items in the list
|
|
DWORD dwCount = (DWORD)GetCount(); // list count plus default column set
|
|
if (m_pDefaultColumnSet)
|
|
{
|
|
dwCount++;
|
|
}
|
|
|
|
HRESULT hr = SaveDWordHelper(pStm, dwCount);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
|
|
// save columnset list
|
|
for (POSITION pos = GetHeadPosition(); pos != NULL; )
|
|
{
|
|
CColumnSet* pTempSet = GetNext(pos);
|
|
|
|
if (pTempSet == NULL)
|
|
{
|
|
ASSERT(pTempSet != NULL);
|
|
continue;
|
|
}
|
|
|
|
hr = pTempSet->Save(pStm);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
// save default column set
|
|
if (m_pDefaultColumnSet != NULL)
|
|
{
|
|
hr = m_pDefaultColumnSet->Save(pStm);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CColumnSetList::Load(IStream* pStm)
|
|
{
|
|
// load # of items in the list
|
|
DWORD dwLoadCount;
|
|
HRESULT hr = LoadDWordHelper(pStm, &dwLoadCount);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// load column list
|
|
CString szColumnID;
|
|
for (DWORD iColSet = 0; iColSet< dwLoadCount; iColSet++)
|
|
{
|
|
// load the string with the name of the column set
|
|
hr = LoadStringHelper(szColumnID, pStm);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
ASSERT(!szColumnID.IsEmpty());
|
|
CColumnSet* pColumnSet = FindColumnSet(szColumnID);
|
|
if (pColumnSet != NULL)
|
|
{
|
|
hr = pColumnSet->Load(pStm);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|