1249 lines
37 KiB
C++
1249 lines
37 KiB
C++
// WbemProv.cpp : Implementation of CAdreplpvApp and DLL registration.
|
|
|
|
#include "stdafx.h"
|
|
#include "dbg.cpp"
|
|
//#include "adreplpv.h"
|
|
#include "Wbem.h"
|
|
#include <lmcons.h>
|
|
#include <lmapibuf.h>
|
|
#include <adshlp.h>
|
|
|
|
#define INITGUID
|
|
#include <initguid.h>
|
|
DEFINE_GUID(CLSID_ADReplProvider,0x96FA95C4,0x0AF3,0x4EF9,0xA1,0xEB,0xC8,0x15,0x13,0x22,0x15,0x7B);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
// CODEWORK should only have one definition of classname and GUID
|
|
#define CLASSNAME_STRING_STATUS L"Microsoft_ADReplStatus"
|
|
#define CLASSNAME_STRING_DC L"Microsoft_ADReplDomainController"
|
|
|
|
CProvider::CProvider()
|
|
{
|
|
}
|
|
|
|
CProvider::~CProvider()
|
|
{
|
|
}
|
|
|
|
|
|
// IWbemProviderInit
|
|
|
|
STDMETHODIMP CProvider::Initialize(
|
|
IN LPWSTR pszUser,
|
|
IN LONG lFlags,
|
|
IN LPWSTR pszNamespace,
|
|
IN LPWSTR pszLocale,
|
|
IN IWbemServices *pNamespace,
|
|
IN IWbemContext *pCtx,
|
|
IN IWbemProviderInitSink *pInitSink
|
|
)
|
|
{
|
|
WBEM_VALIDATE_INTF_PTR( pNamespace );
|
|
WBEM_VALIDATE_INTF_PTR( pCtx );
|
|
WBEM_VALIDATE_INTF_PTR( pInitSink );
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
do
|
|
{
|
|
m_sipNamespace = pNamespace;
|
|
|
|
CComBSTR sbstrObjectName = CLASSNAME_STRING_STATUS; // is this necessary?
|
|
hr = m_sipNamespace->GetObject( sbstrObjectName,
|
|
WBEM_FLAG_RETURN_WBEM_COMPLETE,
|
|
pCtx,
|
|
&m_sipClassDefStatus,
|
|
NULL );
|
|
BREAK_ON_FAIL;
|
|
|
|
sbstrObjectName = CLASSNAME_STRING_DC;
|
|
hr = m_sipNamespace->GetObject( sbstrObjectName,
|
|
WBEM_FLAG_RETURN_WBEM_COMPLETE,
|
|
pCtx,
|
|
&m_sipClassDefDC,
|
|
NULL );
|
|
BREAK_ON_FAIL;
|
|
|
|
// Let CIMOM know you are initialized
|
|
// return value and SetStatus param should be consistent, so ignore
|
|
// the return value from SetStatus itself (in retail builds)
|
|
HRESULT hr2 = pInitSink->SetStatus( WBEM_S_INITIALIZED, 0 );
|
|
ASSERT( !FAILED(hr2) );
|
|
|
|
} while (false);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// IWbemServices
|
|
|
|
// BUGBUG should this ever indicate more than one?
|
|
STDMETHODIMP CProvider::GetObjectAsync(
|
|
IN const BSTR bstrObjectPath,
|
|
IN long lFlags,
|
|
IN IWbemContext *pCtx,
|
|
IN IWbemObjectSink *pResponseHandler)
|
|
{
|
|
WBEM_VALIDATE_IN_STRING_PTR( bstrObjectPath );
|
|
// CODEWORK check lFlags?
|
|
WBEM_VALIDATE_INTF_PTR( pCtx );
|
|
WBEM_VALIDATE_INTF_PTR( pResponseHandler );
|
|
|
|
static LPCWSTR ROOTSTR_STATUS = L"Microsoft_ADReplStatus.CompositeName=\"";
|
|
static LPCWSTR ROOTSTR_DC = L"Microsoft_ADReplDomainController.SiteName=\"";
|
|
|
|
int rootlen = lstrlen(ROOTSTR_STATUS);
|
|
if ( lstrlen(bstrObjectPath) > rootlen
|
|
&& 0 == _tcsnicmp(bstrObjectPath, ROOTSTR_STATUS, rootlen)
|
|
)
|
|
{
|
|
// remove prefix
|
|
CComBSTR sbstrFilterValue = (BSTR)bstrObjectPath + rootlen;
|
|
// remove trailing doublequote
|
|
sbstrFilterValue[lstrlen(sbstrFilterValue)-1] = L'\0';
|
|
|
|
return _EnumAndIndicateStatus( CLASS_STATUS,
|
|
pCtx,
|
|
pResponseHandler,
|
|
sbstrFilterValue );
|
|
}
|
|
|
|
rootlen = lstrlen(ROOTSTR_DC);
|
|
if ( lstrlen(bstrObjectPath) > rootlen
|
|
&& 0 == _tcsnicmp(bstrObjectPath, ROOTSTR_DC, rootlen)
|
|
)
|
|
{
|
|
// remove prefix
|
|
CComBSTR sbstrFilterValue = (BSTR)bstrObjectPath + rootlen;
|
|
// remove trailing doublequote
|
|
sbstrFilterValue[lstrlen(sbstrFilterValue)-1] = L'\0';
|
|
|
|
return _EnumAndIndicateDC( pCtx,
|
|
pResponseHandler,
|
|
sbstrFilterValue );
|
|
}
|
|
|
|
ASSERT(false);
|
|
return WBEM_E_INVALID_OBJECT_PATH;
|
|
}
|
|
|
|
STDMETHODIMP CProvider::CreateInstanceEnumAsync(
|
|
IN const BSTR bstrClass,
|
|
IN long lFlags,
|
|
IN IWbemContext *pCtx,
|
|
IN IWbemObjectSink *pResponseHandler)
|
|
{
|
|
WBEM_VALIDATE_IN_STRING_PTR( bstrClass );
|
|
// CODEWORK check lFlags?
|
|
WBEM_VALIDATE_INTF_PTR( pCtx );
|
|
WBEM_VALIDATE_INTF_PTR( pResponseHandler );
|
|
|
|
if ( 0 == lstrcmp( bstrClass, CLASSNAME_STRING_STATUS ) )
|
|
return _EnumAndIndicateStatus( CLASS_STATUS, pCtx, pResponseHandler );
|
|
else if ( 0 == lstrcmp( bstrClass, CLASSNAME_STRING_DC ) )
|
|
return _EnumAndIndicateDC( pCtx, pResponseHandler );
|
|
return WBEM_E_INVALID_OBJECT_PATH;
|
|
|
|
}
|
|
|
|
HRESULT CProvider::_EnumAndIndicateStatus(
|
|
IN ProviderClass provclass, // BUGBUG don't need this parameter
|
|
IN IWbemContext *pCtx,
|
|
IN IWbemObjectSink *pResponseHandler,
|
|
IN const BSTR bstrFilterValue )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
DSROLE_PRIMARY_DOMAIN_INFO_BASIC* pdomaininfo = NULL;
|
|
HANDLE hDS = NULL;
|
|
bool fImpersonating = false;
|
|
|
|
do
|
|
{
|
|
hr = CoImpersonateClient();
|
|
BREAK_ON_FAIL;
|
|
fImpersonating = true;
|
|
|
|
// Check whether this is a DC
|
|
hr = HRESULT_FROM_WIN32(DsRoleGetPrimaryDomainInformation(
|
|
NULL, // lpServer = local machine
|
|
DsRolePrimaryDomainInfoBasic, // InfoLevel
|
|
(PBYTE*)&pdomaininfo // pBuffer
|
|
));
|
|
BREAK_ON_FAIL;
|
|
ASSERT( NULL != pdomaininfo );
|
|
bool fIsDC = true;
|
|
switch (pdomaininfo->MachineRole)
|
|
{
|
|
case DsRole_RoleBackupDomainController:
|
|
case DsRole_RolePrimaryDomainController:
|
|
break;
|
|
default:
|
|
fIsDC = false;
|
|
break;
|
|
}
|
|
if ( !fIsDC )
|
|
{
|
|
// this is not a DC, return no connections
|
|
break;
|
|
}
|
|
|
|
TCHAR achComputerName[MAX_PATH];
|
|
DWORD dwSize = sizeof(achComputerName)/sizeof(TCHAR);
|
|
if ( !GetComputerNameEx(
|
|
ComputerNameDnsFullyQualified,
|
|
achComputerName,
|
|
&dwSize ))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = HRESULT_FROM_WIN32(DsBind(
|
|
achComputerName, // DomainControllerName
|
|
NULL, // DnsDomainName
|
|
&hDS // phDS
|
|
));
|
|
// RPC_S_UUID_NO_ADDRESS means this is not a DC
|
|
BREAK_ON_FAIL;
|
|
ASSERT( NULL != hDS );
|
|
|
|
switch (provclass)
|
|
{
|
|
case CLASS_DC:
|
|
ASSERT(false);
|
|
break;
|
|
case CLASS_STATUS:
|
|
hr = _EnumAndIndicateWorker( provclass,
|
|
hDS,
|
|
pCtx,
|
|
pResponseHandler,
|
|
bstrFilterValue );
|
|
break;
|
|
default:
|
|
ASSERT(false);
|
|
}
|
|
|
|
} while (false);
|
|
|
|
if (fImpersonating)
|
|
{
|
|
// CODEWORK do we want to keep impersonating and reverting?
|
|
HRESULT hr2 = CoRevertToSelf();
|
|
ASSERT( !FAILED(hr2) );
|
|
}
|
|
|
|
if (NULL != hDS)
|
|
{
|
|
(void) DsUnBind( &hDS );
|
|
}
|
|
if (NULL != pdomaininfo)
|
|
{
|
|
DsRoleFreeMemory( pdomaininfo );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
HRESULT CProvider::_EnumAndIndicateDCWorker(
|
|
IN HANDLE hDS,
|
|
IN IWbemContext *pCtx,
|
|
IN IWbemObjectSink *pResponseHandler,
|
|
IN const BSTR bstrFilterValue )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
DS_DOMAIN_TRUSTS* ptrusts = NULL;
|
|
ULONG ctrusts = 0;
|
|
|
|
do
|
|
{
|
|
hr = HRESULT_FROM_WIN32(DsEnumerateDomainTrustsW(
|
|
NULL, // ServerName
|
|
DS_DOMAIN_IN_FOREST, // Flags,
|
|
&ptrusts, // Domains,
|
|
&ctrusts // DomainCount
|
|
));
|
|
|
|
BREAK_ON_FAIL;
|
|
if (0 == ctrusts)
|
|
break;
|
|
if ( BAD_IN_MULTISTRUCT_PTR(ptrusts,ctrusts) )
|
|
{
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
for (ULONG i = 0; i < ctrusts; i++)
|
|
{
|
|
if ( BAD_IN_STRING_PTR(ptrusts[i].DnsDomainName) )
|
|
{
|
|
// skip this one
|
|
break;
|
|
}
|
|
hr = _EnumAndIndicateWorker( CLASS_DC,
|
|
hDS,
|
|
pCtx,
|
|
pResponseHandler,
|
|
bstrFilterValue,
|
|
ptrusts[i].DnsDomainName );
|
|
BREAK_ON_FAIL;
|
|
}
|
|
|
|
} while (false);
|
|
|
|
if ( NULL != ptrusts )
|
|
{
|
|
(void) NetApiBufferFree( ptrusts );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
*/
|
|
|
|
HRESULT CProvider::_EnumAndIndicateWorker(
|
|
IN ProviderClass provclass, // BUGBUG parameter not needed
|
|
IN HANDLE hDS,
|
|
IN IWbemContext *pCtx,
|
|
IN IWbemObjectSink *pResponseHandler,
|
|
IN const BSTR bstrFilterValue,
|
|
IN const BSTR bstrDnsDomainName )
|
|
{
|
|
WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL(bstrFilterValue);
|
|
WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL(bstrDnsDomainName);
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
DS_REPL_NEIGHBORS* pneighborsstruct = NULL;
|
|
DS_DOMAIN_CONTROLLER_INFO_1 * pDCs = NULL; // BUGBUG not needed
|
|
ULONG cDCs = 0;
|
|
DWORD cIndicateItems = 0;
|
|
IWbemClassObject** paIndicateItems = NULL;
|
|
|
|
do
|
|
{
|
|
switch (provclass)
|
|
{
|
|
case CLASS_STATUS:
|
|
hr = _BuildListStatus( hDS, &pneighborsstruct );
|
|
break;
|
|
/*
|
|
case CLASS_DC:
|
|
hr = _BuildListDC( hDS, bstrDnsDomainName, &pDCs, &cDCs );
|
|
break;
|
|
*/
|
|
default:
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
BREAK_ON_FAIL;
|
|
|
|
switch (provclass)
|
|
{
|
|
case CLASS_STATUS:
|
|
hr = _BuildIndicateArrayStatus( pneighborsstruct,
|
|
bstrFilterValue,
|
|
&paIndicateItems,
|
|
&cIndicateItems );
|
|
break;
|
|
/*
|
|
case CLASS_DC:
|
|
hr = _BuildIndicateArrayDC( pDCs,
|
|
cDCs,
|
|
bstrFilterValue,
|
|
&paIndicateItems,
|
|
&cIndicateItems );
|
|
break;
|
|
*/
|
|
default:
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Send the objects to the caller
|
|
//
|
|
// [In] param, no need to addref.
|
|
if (cIndicateItems > 0)
|
|
{
|
|
hr = pResponseHandler->Indicate( cIndicateItems, paIndicateItems );
|
|
BREAK_ON_FAIL;
|
|
}
|
|
|
|
// Let CIMOM know you are finished
|
|
// return value and SetStatus param should be consistent, so ignore
|
|
// the return value from SetStatus itself (in retail builds)
|
|
HRESULT hr2 = pResponseHandler->SetStatus( WBEM_STATUS_COMPLETE, hr,
|
|
NULL, NULL );
|
|
ASSERT( !FAILED(hr2) );
|
|
|
|
} while (false);
|
|
|
|
_ReleaseIndicateArray( paIndicateItems, cIndicateItems );
|
|
|
|
if ( NULL != pneighborsstruct )
|
|
{
|
|
(void) DsReplicaFreeInfo( DS_REPL_INFO_NEIGHBORS, pneighborsstruct );
|
|
}
|
|
if ( NULL != pDCs )
|
|
{
|
|
(void) NetApiBufferFree( pDCs );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
// does not validate resultant structs coming from API
|
|
HRESULT CProvider::_BuildConnectionList(
|
|
IN ProviderClass provclass,
|
|
OUT void** ppitems )
|
|
{
|
|
WBEM_VALIDATE_OUT_PTRPTR( ppitems );
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
bool fImpersonating = false;
|
|
|
|
do {
|
|
|
|
hr = CoImpersonateClient();
|
|
BREAK_ON_FAIL;
|
|
fImpersonating = true;
|
|
|
|
switch (provclass)
|
|
{
|
|
case CLASS_STATUS:
|
|
hr = _BuildListStatus( ppitems );
|
|
break;
|
|
case CLASS_DC:
|
|
hr = _BuildListDC( ppitems );
|
|
break;
|
|
default:
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
} while (false);
|
|
|
|
if (fImpersonating)
|
|
{
|
|
HRESULT hr2 = CoRevertToSelf();
|
|
ASSERT( !FAILED(hr2) );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
*/
|
|
|
|
// does not validate resultant structs coming from API
|
|
HRESULT CProvider::_BuildListStatus(
|
|
IN HANDLE hDS,
|
|
OUT DS_REPL_NEIGHBORS** ppneighborsstruct )
|
|
{
|
|
WBEM_VALIDATE_OUT_STRUCT_PTR(ppneighborsstruct);
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
do {
|
|
hr = HRESULT_FROM_WIN32(DsReplicaGetInfo(
|
|
hDS, // hDS
|
|
DS_REPL_INFO_NEIGHBORS, // InfoType
|
|
NULL, // pszObject
|
|
NULL, // puuidForSourceDsaObjGuid,
|
|
(void**)ppneighborsstruct // ppinfo
|
|
));
|
|
BREAK_ON_FAIL;
|
|
|
|
if ( BAD_IN_STRUCT_PTR(*ppneighborsstruct) )
|
|
{
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
} while (false);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CProvider::_EnumAndIndicateDC(
|
|
IN IWbemContext *pCtx,
|
|
IN IWbemObjectSink *pResponseHandler,
|
|
IN const BSTR bstrFilterValue
|
|
)
|
|
{
|
|
WBEM_VALIDATE_INTF_PTR( pCtx );
|
|
WBEM_VALIDATE_INTF_PTR( pResponseHandler );
|
|
WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL( bstrFilterValue );
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
CComPtr<IADs> spIADsRootDSE;
|
|
CComVariant svarSchema;
|
|
CComPtr<IADsPathname> spIADsPathname;
|
|
CComPtr<IDirectorySearch> spIADsSearch;
|
|
CComPtr<IADsPathname> spPathCracker;
|
|
|
|
do {
|
|
|
|
//
|
|
// Enumerate all nTDSDSA objects
|
|
//
|
|
|
|
hr = ADsOpenObject( L"LDAP://RootDSE",
|
|
NULL, NULL, ADS_SECURE_AUTHENTICATION,
|
|
IID_IADs, OUT (void **)&spIADsRootDSE);
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = spIADsRootDSE->Get(L"configurationNamingContext", &svarSchema);
|
|
BREAK_ON_FAIL;
|
|
ASSERT( VT_BSTR == svarSchema.vt );
|
|
|
|
hr = spIADsPathname.CoCreateInstance( CLSID_Pathname );
|
|
BREAK_ON_FAIL;
|
|
ASSERT( !!spIADsPathname );
|
|
|
|
CComBSTR sbstr = L"LDAP://CN=Sites,";
|
|
sbstr += svarSchema.bstrVal;
|
|
|
|
hr = ADsOpenObject( sbstr,
|
|
NULL, NULL, ADS_SECURE_AUTHENTICATION,
|
|
IID_IDirectorySearch, (void **)&spIADsSearch);
|
|
BREAK_ON_FAIL;
|
|
|
|
ADS_SEARCHPREF_INFO aSearchPref[4];
|
|
aSearchPref[0].dwSearchPref = ADS_SEARCHPREF_CHASE_REFERRALS;
|
|
aSearchPref[0].vValue.dwType = ADSTYPE_INTEGER;
|
|
aSearchPref[0].vValue.Integer = ADS_CHASE_REFERRALS_EXTERNAL;
|
|
aSearchPref[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
|
|
aSearchPref[1].vValue.dwType = ADSTYPE_INTEGER;
|
|
aSearchPref[1].vValue.Integer = 50;
|
|
aSearchPref[2].dwSearchPref = ADS_SEARCHPREF_CACHE_RESULTS;
|
|
aSearchPref[2].vValue.dwType = ADSTYPE_BOOLEAN;
|
|
aSearchPref[2].vValue.Integer = FALSE;
|
|
aSearchPref[3].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
|
|
aSearchPref[3].vValue.dwType = ADSTYPE_INTEGER;
|
|
aSearchPref[3].vValue.Integer = ADS_SCOPE_SUBTREE;
|
|
|
|
hr = spIADsSearch->SetSearchPreference (aSearchPref, 4);
|
|
BREAK_ON_FAIL;
|
|
|
|
CComBSTR sbstr1 = L"objectGUID";
|
|
CComBSTR sbstr2 = L"distinguishedName";
|
|
LPWSTR apAttributeNames[2] = {sbstr1,sbstr2};
|
|
ADS_SEARCH_HANDLE hSearch = NULL;
|
|
hr = spIADsSearch->ExecuteSearch( L"(objectclass=nTDSDSA)",
|
|
apAttributeNames, // CODEWORK must use BSTRs?
|
|
2,
|
|
&hSearch );
|
|
BREAK_ON_FAIL;
|
|
|
|
//
|
|
// Prepare a path cracker object
|
|
//
|
|
hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IADsPathname, (PVOID *)&spPathCracker);
|
|
BREAK_ON_FAIL;
|
|
ASSERT( !!spPathCracker );
|
|
hr = spPathCracker->SetDisplayType( ADS_DISPLAY_VALUE_ONLY );
|
|
BREAK_ON_FAIL;
|
|
|
|
while ( S_OK == (hr = spIADsSearch->GetNextRow ( hSearch )) )
|
|
{
|
|
CComPtr<IWbemClassObject> spIndicateItem;
|
|
hr = m_sipClassDefDC->SpawnInstance( 0, &spIndicateItem );
|
|
BREAK_ON_FAIL;
|
|
IWbemClassObject* pIndicateItem = spIndicateItem;
|
|
ASSERT( NULL != pIndicateItem );
|
|
|
|
hr = _PutAttributesDC( pIndicateItem,
|
|
spPathCracker,
|
|
bstrFilterValue,
|
|
spIADsSearch,
|
|
hSearch );
|
|
if (S_FALSE == hr)
|
|
continue;
|
|
BREAK_ON_FAIL;
|
|
|
|
//
|
|
// Send the object to the caller
|
|
//
|
|
// [In] param, no need to addref.
|
|
|
|
// ATL asserts on CComPtr<>::operator& if contents not NULL
|
|
hr = pResponseHandler->Indicate( 1, &pIndicateItem );
|
|
BREAK_ON_FAIL;
|
|
|
|
// Let CIMOM know you are finished
|
|
// return value and SetStatus param should be consistent,
|
|
// so ignore the return value from SetStatus itself
|
|
// (in retail builds)
|
|
HRESULT hr2 = pResponseHandler->SetStatus(
|
|
WBEM_STATUS_COMPLETE, hr, NULL, NULL );
|
|
ASSERT( !FAILED(hr2) );
|
|
}
|
|
|
|
} while (false);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
HRESULT CProvider::_BuildListDC(
|
|
IN HANDLE hDS,
|
|
IN const BSTR bstrDnsDomainName,
|
|
OUT DS_DOMAIN_CONTROLLER_INFO_1** ppDCs,
|
|
OUT ULONG* pcDCs )
|
|
{
|
|
WBEM_VALIDATE_OUT_STRUCT_PTR(ppDCs);
|
|
WBEM_VALIDATE_OUT_STRUCT_PTR(pcDCs);
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
do {
|
|
hr = HRESULT_FROM_WIN32(DsGetDomainControllerInfo(
|
|
hDS, // hDS
|
|
bstrDnsDomainName, // DomainName
|
|
1, // InfoLevel
|
|
pcDCs, // pcOut,
|
|
(void**)ppDCs // ppInfo
|
|
));
|
|
BREAK_ON_FAIL;
|
|
|
|
if ( BAD_IN_MULTISTRUCT_PTR(*ppDCs,*pcDCs) )
|
|
{
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
} while (false);
|
|
|
|
return hr;
|
|
}
|
|
*/
|
|
|
|
HRESULT _PutUUIDAttribute(
|
|
IWbemClassObject* ipNewInst,
|
|
LPCTSTR pcszAttributeName,
|
|
UUID& refuuid)
|
|
{
|
|
CComVariant svar;
|
|
OLECHAR ach[MAX_PATH];
|
|
::ZeroMemory( ach, sizeof(ach) );
|
|
if ( 0 >= StringFromGUID2( refuuid, ach, MAX_PATH ) )
|
|
{
|
|
ASSERT(false);
|
|
}
|
|
svar = ach;
|
|
return ipNewInst->Put( pcszAttributeName, 0, &svar, 0 );
|
|
}
|
|
|
|
|
|
HRESULT _PutLONGLONGAttribute(
|
|
IWbemClassObject* ipNewInst,
|
|
LPCTSTR pcszAttributeName,
|
|
LONGLONG longlong)
|
|
{
|
|
CComVariant svar;
|
|
OLECHAR ach[MAX_PATH];
|
|
::ZeroMemory( ach, sizeof(ach) );
|
|
_ui64tot( longlong, ach, 10 );
|
|
svar = ach;
|
|
return ipNewInst->Put( pcszAttributeName, 0, &svar, 0 );
|
|
}
|
|
|
|
|
|
HRESULT _PutFILETIMEAttribute(
|
|
IWbemClassObject* ipNewInst,
|
|
LPCTSTR pcszAttributeName,
|
|
FILETIME& reffiletime)
|
|
{
|
|
SYSTEMTIME systime;
|
|
::ZeroMemory( &systime, sizeof(SYSTEMTIME) );
|
|
if ( !FileTimeToSystemTime( &reffiletime, &systime ) )
|
|
{
|
|
ASSERT(false);
|
|
return HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
CComVariant svar;
|
|
OLECHAR ach[MAX_PATH];
|
|
::ZeroMemory( ach, sizeof(ach) );
|
|
swprintf( ach, L"%04u%02u%02u%02u%02u%02u.%06u+000",
|
|
systime.wYear,
|
|
systime.wMonth,
|
|
systime.wDay,
|
|
systime.wHour,
|
|
systime.wMinute,
|
|
systime.wSecond,
|
|
systime.wMilliseconds
|
|
);
|
|
svar = ach;
|
|
return ipNewInst->Put( pcszAttributeName, 0, &svar, 0 );
|
|
}
|
|
|
|
|
|
HRESULT _PutBooleanAttributes(
|
|
IWbemClassObject* ipNewInst,
|
|
UINT cNumAttributes,
|
|
LPCTSTR* aAttributeNames,
|
|
DWORD* aBitmasks,
|
|
DWORD dwValue)
|
|
{
|
|
WBEM_VALIDATE_READ_PTR( aAttributeNames, cNumAttributes*sizeof(LPCTSTR) );
|
|
WBEM_VALIDATE_READ_PTR( aBitmasks, cNumAttributes*sizeof(DWORD) );
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
CComVariant svar = true;
|
|
for (UINT i = 0; i < cNumAttributes; i++)
|
|
{
|
|
WBEM_VALIDATE_IN_STRING_PTR( aAttributeNames[i] );
|
|
if (dwValue & aBitmasks[i])
|
|
{
|
|
hr = ipNewInst->Put( aAttributeNames[i], 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT _ExtractDomainName(
|
|
LPCTSTR pszNamingContext,
|
|
BSTR* pbstrDomainName )
|
|
{
|
|
WBEM_VALIDATE_IN_STRING_PTR( pszNamingContext );
|
|
WBEM_VALIDATE_OUT_PTRPTR( pbstrDomainName );
|
|
|
|
PDS_NAME_RESULTW pDsNameResult = NULL;
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
do {
|
|
DWORD dwErr = DsCrackNamesW(
|
|
(HANDLE)-1,
|
|
DS_NAME_FLAG_SYNTACTICAL_ONLY,
|
|
DS_FQDN_1779_NAME,
|
|
DS_CANONICAL_NAME,
|
|
1,
|
|
&pszNamingContext,
|
|
&pDsNameResult);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
hr = HRESULT_FROM_WIN32( dwErr );
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
if ( BAD_IN_STRUCT_PTR(pDsNameResult)
|
|
|| 1 != pDsNameResult->cItems
|
|
|| DS_NAME_NO_ERROR != pDsNameResult->rItems->status
|
|
|| BAD_IN_STRUCT_PTR(pDsNameResult->rItems)
|
|
|| BAD_IN_STRING_PTR(pDsNameResult->rItems->pDomain)
|
|
)
|
|
{
|
|
hr = E_FAIL;
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
*pbstrDomainName = ::SysAllocString(pDsNameResult->rItems->pDomain);
|
|
if (NULL == *pbstrDomainName)
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
|
|
} while (false);
|
|
|
|
if (pDsNameResult)
|
|
{
|
|
DsFreeNameResultW(pDsNameResult);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// if this returns S_FALSE, skip this connection but do not consider this an error
|
|
HRESULT CProvider::_PutAttributesStatus(
|
|
IWbemClassObject** pipNewInst,
|
|
const BSTR bstrFilterValue,
|
|
DS_REPL_NEIGHBOR* pneighbor)
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
if ( BAD_IN_STRING_PTR(pneighbor->pszNamingContext)
|
|
|| BAD_IN_STRING_PTR(pneighbor->pszSourceDsaDN)
|
|
|| BAD_IN_STRING_PTR_OPTIONAL(pneighbor->pszSourceDsaAddress)
|
|
|| BAD_IN_STRING_PTR_OPTIONAL(pneighbor->pszAsyncIntersiteTransportDN)
|
|
)
|
|
{
|
|
ASSERT(false);
|
|
return S_FALSE;
|
|
}
|
|
|
|
CComPtr<IADsPathname> spPathCracker;
|
|
CComBSTR sbstrReplicatedDomain, // DNS name of replicated domain
|
|
sbstrSourceServer, // CN= name of source server
|
|
sbstrSourceSite, // name of site containing source server
|
|
sbstrCompositeName; // composite name for WMI
|
|
|
|
do {
|
|
hr = _ExtractDomainName( pneighbor->pszNamingContext, &sbstrReplicatedDomain );
|
|
BREAK_ON_FAIL;
|
|
|
|
boolean bIsConfigNC = (0 == wcsnicmp(pneighbor->pszNamingContext,
|
|
L"CN=Configuration,",
|
|
17));
|
|
boolean bIsSchemaNC = (0 == wcsnicmp(pneighbor->pszNamingContext,
|
|
L"CN=Schema,",
|
|
10));
|
|
boolean bIsDeleted = (NULL != wcsstr(pneighbor->pszSourceDsaAddress, L"\nDEL:"));
|
|
|
|
// retrieve source server name and site name
|
|
hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IADsPathname, (PVOID *)&spPathCracker);
|
|
BREAK_ON_FAIL;
|
|
ASSERT( !!spPathCracker );
|
|
hr = spPathCracker->Set( pneighbor->pszSourceDsaDN, ADS_SETTYPE_DN );
|
|
BREAK_ON_FAIL;
|
|
hr = spPathCracker->SetDisplayType( ADS_DISPLAY_VALUE_ONLY );
|
|
BREAK_ON_FAIL;
|
|
hr = spPathCracker->GetElement( 1L, &sbstrSourceServer );
|
|
BREAK_ON_FAIL;
|
|
hr = spPathCracker->GetElement( 3L, &sbstrSourceSite );
|
|
BREAK_ON_FAIL;
|
|
|
|
// Build the composite name
|
|
sbstrCompositeName = sbstrSourceSite;
|
|
sbstrCompositeName += L"\\";
|
|
sbstrCompositeName += sbstrSourceServer;
|
|
sbstrCompositeName += L";";
|
|
sbstrCompositeName += sbstrReplicatedDomain;
|
|
if (bIsConfigNC)
|
|
sbstrCompositeName += L",Configuration";
|
|
else if (bIsSchemaNC)
|
|
sbstrCompositeName += L",Schema";
|
|
else
|
|
sbstrCompositeName += L",Domain";
|
|
|
|
// Test the composite name against the filter
|
|
if ( NULL != bstrFilterValue
|
|
&& !lstrcmpi(sbstrCompositeName, bstrFilterValue)
|
|
)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create a new instance of the data object
|
|
//
|
|
hr = m_sipClassDefStatus->SpawnInstance( 0, pipNewInst );
|
|
BREAK_ON_FAIL;
|
|
IWbemClassObject* ipNewInst = *pipNewInst;
|
|
if (NULL == ipNewInst)
|
|
{
|
|
ASSERT(false);
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
CComVariant svar;
|
|
|
|
svar = sbstrCompositeName;
|
|
hr = ipNewInst->Put( L"CompositeName", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = pneighbor->pszNamingContext;
|
|
hr = ipNewInst->Put( L"NamingContext", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = pneighbor->pszSourceDsaDN;
|
|
hr = ipNewInst->Put( L"SourceDsaDN", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = pneighbor->pszSourceDsaAddress;
|
|
hr = ipNewInst->Put( L"SourceDsaAddress", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = pneighbor->pszAsyncIntersiteTransportDN;
|
|
hr = ipNewInst->Put( L"AsyncIntersiteTransportDN", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = (long)pneighbor->dwReplicaFlags;
|
|
hr = ipNewInst->Put( L"ReplicaFlags", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
if (bIsConfigNC)
|
|
{
|
|
svar = TRUE;
|
|
hr = ipNewInst->Put( L"IsConfigurationNamingContext", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
}
|
|
|
|
if (bIsSchemaNC)
|
|
{
|
|
svar = TRUE;
|
|
hr = ipNewInst->Put( L"IsSchemaNamingContext", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
}
|
|
|
|
if (bIsDeleted)
|
|
{
|
|
svar = TRUE;
|
|
hr = ipNewInst->Put( L"IsDeletedSourceDsa", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
}
|
|
svar = sbstrSourceSite;
|
|
hr = ipNewInst->Put( L"SourceDsaSite", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = sbstrSourceServer;
|
|
hr = ipNewInst->Put( L"SourceDsaCN", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = sbstrReplicatedDomain;
|
|
hr = ipNewInst->Put( L"Domain", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
LPCTSTR aBooleanAttrNames[12] = {
|
|
TEXT("Writeable"),
|
|
TEXT("SyncOnStartup"),
|
|
TEXT("DoScheduledSyncs"),
|
|
TEXT("UseAsyncIntersiteTransport"),
|
|
TEXT("TwoWaySync"),
|
|
TEXT("FullSyncInProgress"),
|
|
TEXT("FullSyncNextPacket"),
|
|
TEXT("NeverSynced"),
|
|
TEXT("IgnoreChangeNotifications"),
|
|
TEXT("DisableScheduledSync"),
|
|
TEXT("CompressChanges"),
|
|
TEXT("NoChangeNotifications")
|
|
};
|
|
|
|
DWORD aBitmasks[12] = {
|
|
DS_REPL_NBR_WRITEABLE,
|
|
DS_REPL_NBR_SYNC_ON_STARTUP,
|
|
DS_REPL_NBR_DO_SCHEDULED_SYNCS,
|
|
DS_REPL_NBR_USE_ASYNC_INTERSITE_TRANSPORT,
|
|
DS_REPL_NBR_TWO_WAY_SYNC,
|
|
DS_REPL_NBR_FULL_SYNC_IN_PROGRESS,
|
|
DS_REPL_NBR_FULL_SYNC_NEXT_PACKET,
|
|
DS_REPL_NBR_NEVER_SYNCED,
|
|
DS_REPL_NBR_IGNORE_CHANGE_NOTIFICATIONS,
|
|
DS_REPL_NBR_DISABLE_SCHEDULED_SYNC,
|
|
DS_REPL_NBR_COMPRESS_CHANGES,
|
|
DS_REPL_NBR_NO_CHANGE_NOTIFICATIONS
|
|
};
|
|
|
|
hr = _PutBooleanAttributes( ipNewInst,
|
|
12,
|
|
aBooleanAttrNames,
|
|
aBitmasks,
|
|
pneighbor->dwReplicaFlags );
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = _PutUUIDAttribute( ipNewInst,
|
|
L"NamingContextObjGuid",
|
|
pneighbor->uuidNamingContextObjGuid );
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = _PutUUIDAttribute( ipNewInst,
|
|
L"SourceDsaObjGuid",
|
|
pneighbor->uuidSourceDsaObjGuid );
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = _PutUUIDAttribute( ipNewInst,
|
|
L"SourceDsaInvocationID",
|
|
pneighbor->uuidSourceDsaInvocationID );
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = _PutUUIDAttribute( ipNewInst,
|
|
L"AsyncIntersiteTransportObjGuid",
|
|
pneighbor->uuidAsyncIntersiteTransportObjGuid );
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = _PutLONGLONGAttribute( ipNewInst,
|
|
L"LastObjChangeSynced",
|
|
pneighbor->usnLastObjChangeSynced);
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = _PutLONGLONGAttribute( ipNewInst,
|
|
L"AttributeFilter",
|
|
pneighbor->usnAttributeFilter);
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = _PutFILETIMEAttribute( ipNewInst,
|
|
L"LastSyncSuccess",
|
|
pneighbor->ftimeLastSyncSuccess);
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = _PutFILETIMEAttribute( ipNewInst,
|
|
L"LastSyncAttempt",
|
|
pneighbor->ftimeLastSyncAttempt);
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = (long)pneighbor->dwLastSyncResult;
|
|
hr = ipNewInst->Put( L"LastSyncResult", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = (long)pneighbor->cNumConsecutiveSyncFailures;
|
|
hr = ipNewInst->Put( L"NumConsecutiveSyncFailures", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = (long)((bIsDeleted) ? 0L : pneighbor->cNumConsecutiveSyncFailures);
|
|
hr = ipNewInst->Put( L"ModifiedNumConsecutiveSyncFailures", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
} while (false);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// if this returns S_FALSE, skip this connection but do not consider this an error
|
|
// note, this version does not create or release the instance
|
|
HRESULT CProvider::_PutAttributesDC(
|
|
IN IWbemClassObject* pIndicateItem,
|
|
IN IADsPathname* pPathCracker,
|
|
IN const BSTR bstrFilterValue,
|
|
IN IDirectorySearch* pIADsSearch,
|
|
IN ADS_SEARCH_HANDLE hSearch)
|
|
{
|
|
WBEM_VALIDATE_INTF_PTR( pIndicateItem );
|
|
WBEM_VALIDATE_INTF_PTR( pPathCracker );
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
ADS_SEARCH_COLUMN adscolDN, adscolGUID;
|
|
boolean fFreeColumnDN = false, fFreeColumnGUID = false;
|
|
CComVariant svar;
|
|
CComBSTR sbstrServerCN, sbstrSite;
|
|
|
|
do {
|
|
hr = pIADsSearch->GetColumn( hSearch, L"distinguishedName", &adscolDN );
|
|
BREAK_ON_FAIL;
|
|
fFreeColumnDN = true;
|
|
if ( ADSTYPE_DN_STRING != adscolDN.dwADsType
|
|
|| 1 != adscolDN.dwNumValues
|
|
|| BAD_IN_STRUCT_PTR(adscolDN.pADsValues)
|
|
|| BAD_IN_STRING_PTR(adscolDN.pADsValues[0].DNString)
|
|
)
|
|
{
|
|
// skip this one
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
hr = pIADsSearch->GetColumn( hSearch, L"objectGUID", &adscolGUID );
|
|
BREAK_ON_FAIL;
|
|
fFreeColumnGUID = true;
|
|
if ( ADSTYPE_OCTET_STRING != adscolGUID.dwADsType
|
|
|| 1 != adscolGUID.dwNumValues
|
|
|| BAD_IN_STRUCT_PTR(adscolGUID.pADsValues)
|
|
|| 0 == adscolGUID.pADsValues[0].OctetString.dwLength
|
|
|| BAD_IN_READ_PTR(adscolGUID.pADsValues[0].OctetString.lpValue,
|
|
adscolGUID.pADsValues[0].OctetString.dwLength)
|
|
)
|
|
{
|
|
// skip this one
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
hr = pPathCracker->Set( adscolDN.pADsValues[0].DNString, ADS_SETTYPE_DN );
|
|
BREAK_ON_FAIL;
|
|
hr = pPathCracker->GetElement( 1L, &sbstrServerCN );
|
|
BREAK_ON_FAIL;
|
|
hr = pPathCracker->GetElement( 3L, &sbstrSite );
|
|
BREAK_ON_FAIL;
|
|
|
|
// Test the site name against the filter
|
|
if ( NULL != bstrFilterValue
|
|
&& !lstrcmpi(sbstrSite, bstrFilterValue)
|
|
)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
svar = adscolDN.pADsValues[0].DNString;
|
|
hr = pIndicateItem->Put( L"DistinguishedName", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = sbstrServerCN;
|
|
hr = pIndicateItem->Put( L"CommonName", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
svar = sbstrSite;
|
|
hr = pIndicateItem->Put( L"SiteName", 0, &svar, 0 );
|
|
BREAK_ON_FAIL;
|
|
|
|
hr = _PutUUIDAttribute( pIndicateItem,
|
|
L"ObjectGUID",
|
|
(GUID&)adscolGUID.pADsValues[0].OctetString.lpValue );
|
|
BREAK_ON_FAIL;
|
|
|
|
} while (false);
|
|
|
|
if (fFreeColumnDN)
|
|
{
|
|
HRESULT hr2 = pIADsSearch->FreeColumn( &adscolDN );
|
|
ASSERT( SUCCEEDED(hr2) );
|
|
}
|
|
if (fFreeColumnGUID)
|
|
{
|
|
HRESULT hr2 = pIADsSearch->FreeColumn( &adscolGUID );
|
|
ASSERT( SUCCEEDED(hr2) );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CProvider::_BuildIndicateArrayStatus(
|
|
IN DS_REPL_NEIGHBORS* pneighborstruct,
|
|
IN const BSTR bstrFilterValue,
|
|
OUT IWbemClassObject*** ppaIndicateItems,
|
|
OUT DWORD* pcIndicateItems)
|
|
{
|
|
WBEM_VALIDATE_IN_STRUCT_PTR( pneighborstruct );
|
|
WBEM_VALIDATE_IN_MULTISTRUCT_PTR( pneighborstruct->rgNeighbor,
|
|
pneighborstruct->cNumNeighbors );
|
|
WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL( bstrFilterValue );
|
|
WBEM_VALIDATE_OUT_PTRPTR( ppaIndicateItems );
|
|
WBEM_VALIDATE_OUT_STRUCT_PTR( pcIndicateItems );
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
DS_REPL_NEIGHBOR* pneighbors = pneighborstruct->rgNeighbor;
|
|
DWORD cneighbors = pneighborstruct->cNumNeighbors;
|
|
if (0 == cneighbors)
|
|
return WBEM_S_NO_ERROR;
|
|
|
|
IWbemClassObject** paIndicateItems = NULL;
|
|
DWORD cIndicateItems = 0;
|
|
|
|
*ppaIndicateItems = NULL;
|
|
*pcIndicateItems = 0;
|
|
|
|
do
|
|
{
|
|
paIndicateItems = new IWbemClassObject*[cneighbors];
|
|
if (NULL == paIndicateItems)
|
|
{
|
|
ASSERT(false);
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
::ZeroMemory( paIndicateItems, cneighbors * sizeof(IWbemClassObject*) );
|
|
for (DWORD i = 0; i < cneighbors; i++)
|
|
{
|
|
DS_REPL_NEIGHBOR* pneighbor = &(pneighbors[i]);
|
|
|
|
hr = _PutAttributesStatus( &paIndicateItems[cIndicateItems],
|
|
bstrFilterValue,
|
|
pneighbor );
|
|
if (S_FALSE == hr)
|
|
continue;
|
|
cIndicateItems++;
|
|
BREAK_ON_FAIL;
|
|
}
|
|
|
|
} while (false);
|
|
|
|
if (!FAILED(hr))
|
|
{
|
|
*ppaIndicateItems = paIndicateItems;
|
|
*pcIndicateItems = cIndicateItems;
|
|
}
|
|
else
|
|
{
|
|
_ReleaseIndicateArray( paIndicateItems, cneighbors );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
HRESULT CProvider::_BuildIndicateArrayDC(
|
|
IN DS_DOMAIN_CONTROLLER_INFO_1* pDCs,
|
|
IN ULONG cDCs,
|
|
IN const BSTR bstrFilterValue,
|
|
OUT IWbemClassObject*** ppaIndicateItems,
|
|
OUT DWORD* pcIndicateItems)
|
|
{
|
|
WBEM_VALIDATE_IN_MULTISTRUCT_PTR( pDCs, cDCs );
|
|
WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL( bstrFilterValue );
|
|
WBEM_VALIDATE_OUT_PTRPTR( ppaIndicateItems );
|
|
WBEM_VALIDATE_OUT_STRUCT_PTR( pcIndicateItems );
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
if (0 == cDCs)
|
|
return WBEM_S_NO_ERROR;
|
|
|
|
IWbemClassObject** paIndicateItems = NULL;
|
|
DWORD cIndicateItems = 0;
|
|
|
|
*ppaIndicateItems = NULL;
|
|
*pcIndicateItems = 0;
|
|
|
|
do
|
|
{
|
|
paIndicateItems = new IWbemClassObject*[cDCs];
|
|
if (NULL == paIndicateItems)
|
|
{
|
|
ASSERT(false);
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
::ZeroMemory( paIndicateItems, cDCs * sizeof(IWbemClassObject*) );
|
|
for (DWORD i = 0; i < cDCs; i++)
|
|
{
|
|
DS_DOMAIN_CONTROLLER_INFO_1* pDC = &(pDCs[i]);
|
|
|
|
hr = _PutAttributesDC( &paIndicateItems[cIndicateItems],
|
|
bstrFilterValue,
|
|
pDC );
|
|
if (S_FALSE == hr)
|
|
continue;
|
|
cIndicateItems++;
|
|
BREAK_ON_FAIL;
|
|
}
|
|
|
|
} while (false);
|
|
|
|
if (!FAILED(hr))
|
|
{
|
|
*ppaIndicateItems = paIndicateItems;
|
|
*pcIndicateItems = cIndicateItems;
|
|
}
|
|
else
|
|
{
|
|
_ReleaseIndicateArray( paIndicateItems, cDCs );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
*/
|
|
|
|
void CProvider::_ReleaseIndicateArray(
|
|
IWbemClassObject** paIndicateItems,
|
|
DWORD cIndicateItems,
|
|
bool fReleaseArray)
|
|
{
|
|
if (paIndicateItems != NULL)
|
|
{
|
|
for (DWORD i = 0; i < cIndicateItems; i++)
|
|
{
|
|
if (NULL != paIndicateItems[i])
|
|
paIndicateItems[i]->Release();
|
|
}
|
|
if (fReleaseArray)
|
|
{
|
|
delete[] paIndicateItems;
|
|
}
|
|
else
|
|
{
|
|
::ZeroMemory( *paIndicateItems,
|
|
cIndicateItems * sizeof(IWbemClassObject*) );
|
|
|
|
}
|
|
}
|
|
}
|