//--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1997 // // File: cgenobj.cxx // // Contents: Microsoft ADs IIS Provider Generic Object // // // History: 28-Feb-97 SophiaC Created. // //---------------------------------------------------------------------------- #include "iis.hxx" #pragma hdrstop // Class CIISGenObject DEFINE_IDispatch_ExtMgr_Implementation(CIISGenObject) DEFINE_IADs_Implementation(CIISGenObject) CIISGenObject::CIISGenObject(): _pExtMgr(NULL), _pPropertyCache(NULL), _pszServerName(NULL), _pszMetaBasePath(NULL), _pAdminBase(NULL), _pSchema(NULL) { VariantInit(&_vFilter); ENLIST_TRACKING(CIISGenObject); } HRESULT CIISGenObject::CreateGenericObject( BSTR bstrADsPath, BSTR ClassName, CCredentials& Credentials, DWORD dwObjectState, REFIID riid, void **ppvObj ) { HRESULT hr = S_OK; LPWSTR pszADsParent = NULL; WCHAR szCommonName[MAX_PATH+MAX_PROVIDER_TOKEN_LENGTH]; pszADsParent = AllocADsStr((LPWSTR)bstrADsPath); if (!pszADsParent) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } *pszADsParent = L'\0'; // // Determine the parent and rdn name // hr = BuildADsParentPath( bstrADsPath, pszADsParent, szCommonName ); // // call the helper function // hr = CIISGenObject::CreateGenericObject( pszADsParent, szCommonName, ClassName, Credentials, dwObjectState, riid, ppvObj ); error: if (pszADsParent) { FreeADsStr(pszADsParent); } RRETURN(hr); } HRESULT CIISGenObject::CreateGenericObject( BSTR Parent, BSTR CommonName, BSTR ClassName, CCredentials& Credentials, DWORD dwObjectState, REFIID riid, void **ppvObj ) { CIISGenObject FAR * pGenObject = NULL; CADsExtMgr FAR * pExtensionMgr = NULL; HRESULT hr = S_OK; LPWSTR pszClassName = ClassName; hr = AllocateGenObject(ClassName, Credentials, &pGenObject); BAIL_ON_FAILURE(hr); hr = pGenObject->InitializeCoreObject( Parent, CommonName, ClassName, L"", CLSID_IISGenObject, dwObjectState ); BAIL_ON_FAILURE(hr); hr = pGenObject->CacheMetaDataPath(); BAIL_ON_FAILURE(hr); hr = pGenObject->_pPropertyCache->InitializePropertyCache( pGenObject->_pszServerName ); BAIL_ON_FAILURE(hr); // // To maintain compatibility with IIS4 we want to fail when // creating a new object if the metabase path already exists. // if( ADS_OBJECT_UNBOUND == pGenObject->_dwObjectState ) { hr = ::MetaBaseDetectKey( pGenObject->_pAdminBase, pGenObject->_pszMetaBasePath ); if( SUCCEEDED(hr) ) { hr = HRESULT_FROM_WIN32( ERROR_ALREADY_EXISTS ); } else if( ERROR_PATH_NOT_FOUND == HRESULT_CODE(hr) ) { hr = S_OK; } BAIL_ON_FAILURE(hr); } if ( !_wcsicmp(ClassName, L"IIsFtpServer") || !_wcsicmp(ClassName, L"IIsWebServer") || !_wcsicmp(ClassName, L"IIsNntpServer") || !_wcsicmp(ClassName, L"IIsSmtpServer") || !_wcsicmp(ClassName, L"IIsPop3Server") || !_wcsicmp(ClassName, L"IIsImapServer") ) { pszClassName = L"IIsServer"; } else if ( !_wcsicmp(ClassName, L"IIsWebDirectory") || !_wcsicmp(ClassName, L"IIsWebVirtualDir")) { pszClassName = L"IIsApp"; } hr = ADSILoadExtensionManager( pszClassName, (IADs *)pGenObject, Credentials, pGenObject->_pDispMgr, &pExtensionMgr ); BAIL_ON_FAILURE(hr); pGenObject->_pExtMgr = pExtensionMgr; hr = pGenObject->QueryInterface(riid, ppvObj); BAIL_ON_FAILURE(hr); pGenObject->Release(); RRETURN(hr); error: delete pGenObject; RRETURN(hr); } CIISGenObject::~CIISGenObject( ) { delete _pExtMgr; VariantClear(&_vFilter); delete _pDispMgr; delete _pPropertyCache; if (_pszServerName) { FreeADsStr(_pszServerName); } if (_pszMetaBasePath){ FreeADsStr(_pszMetaBasePath); } } STDMETHODIMP CIISGenObject::QueryInterface(REFIID iid, LPVOID FAR* ppv) { if (ppv == NULL) { RRETURN(E_POINTER); } if (IsEqualIID(iid, IID_IUnknown)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_IADsContainer)) { *ppv = (IADsContainer FAR *) this; } else if (IsEqualIID(iid, IID_IADs)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_IISBaseObject)) { *ppv = (IISBaseObject FAR *) this; } else if (IsEqualIID(iid, IID_IDispatch)) { *ppv = (IADs FAR *) this; } else if (_pExtMgr) { RRETURN(_pExtMgr->QueryInterface(iid,ppv)); } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return NOERROR; } HRESULT CIISGenObject::SetInfo() { HRESULT hr = S_OK; COSERVERINFO csiName; COSERVERINFO *pcsiParam = &csiName; IClassFactory * pcsfFactory = NULL; IIISApplicationAdmin * pAppAdmin = NULL; if (GetObjectState() == ADS_OBJECT_UNBOUND) { // Check to see if we're creating an IIsApplicationPool // If so, use the IISApplicationAdmin interface if ( !_wcsicmp(_ADsClass, L"IIsApplicationPool")) { memset(pcsiParam, 0, sizeof(COSERVERINFO)); // // special case to handle "localhost" to work-around ole32 bug // if (_pszServerName == NULL || _wcsicmp(_pszServerName,L"localhost") == 0) { pcsiParam->pwszName = NULL; } else { pcsiParam->pwszName = _pszServerName; } hr = CoGetClassObject( CLSID_WamAdmin, CLSCTX_SERVER, pcsiParam, IID_IClassFactory, (void**) &pcsfFactory ); BAIL_ON_FAILURE(hr); hr = pcsfFactory->CreateInstance( NULL, IID_IIISApplicationAdmin, (void **) &pAppAdmin ); BAIL_ON_FAILURE(hr); hr = pAppAdmin->CreateApplicationPool( _Name ); // Don't BAIL_ON_FAILURE here! Check the HR below first... } // Otherwise do the creation the old fashioned way else { hr = IISCreateObject(); } // // Since methods that we aggregate like IIsApp::AppCreate may // persist our path in the metabase we don't want to fail just // because the path exists. This is done to maintain backward // compatibility with IIS4. // if( ERROR_ALREADY_EXISTS != HRESULT_CODE(hr) ) { BAIL_ON_FAILURE(hr); } // // If the create succeded, set the object type to bound // SetObjectState(ADS_OBJECT_BOUND); } hr = IISSetObject(); BAIL_ON_FAILURE(hr); error: if (pcsfFactory) { pcsfFactory->Release(); } if (pAppAdmin) { pAppAdmin->Release(); } RRETURN(hr); } HRESULT CIISGenObject::IISSetObject() { HRESULT hr = S_OK; METADATA_HANDLE hObjHandle = NULL; PMETADATA_RECORD pMetaDataArray = NULL; DWORD dwMDNumDataEntries = 0; // // Add SetObject functionality : sophiac // if (GetObjectState() == ADS_OBJECT_UNBOUND) { hr = E_ADS_OBJECT_UNBOUND; BAIL_ON_FAILURE(hr); } hr = OpenAdminBaseKey( _pszServerName, (LPWSTR) _pszMetaBasePath, METADATA_PERMISSION_WRITE, &_pAdminBase, &hObjHandle ); BAIL_ON_FAILURE(hr); hr = _pPropertyCache->IISMarshallProperties( &pMetaDataArray, &dwMDNumDataEntries ); BAIL_ON_FAILURE(hr); hr = MetaBaseSetAllData( _pAdminBase, hObjHandle, L"", (PMETADATA_RECORD)pMetaDataArray, dwMDNumDataEntries ); BAIL_ON_FAILURE(hr); error: if (pMetaDataArray) { FreeMetaDataRecordArray(pMetaDataArray, dwMDNumDataEntries); } if (_pAdminBase && hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); } RRETURN(hr); } HRESULT CIISGenObject::IISCreateObject() { HRESULT hr = S_OK; METADATA_HANDLE hObjHandle = NULL; METADATA_RECORD mdrData; WCHAR DataBuf[MAX_PATH]; // // Add CreateObject functionality : sophiac // hr = OpenAdminBaseKey( _pszServerName, L"", METADATA_PERMISSION_WRITE, &_pAdminBase, &hObjHandle ); BAIL_ON_FAILURE(hr); // // Pass in full path // hr = MetaBaseCreateObject( _pAdminBase, hObjHandle, _pszMetaBasePath ); if( ERROR_ALREADY_EXISTS != HRESULT_CODE(hr) ) { BAIL_ON_FAILURE(hr); } // // Set KeyType // wcscpy((LPWSTR)DataBuf, _ADsClass); mdrData.dwMDIdentifier = MD_KEY_TYPE; mdrData.dwMDDataType = STRING_METADATA; mdrData.dwMDUserType = IIS_MD_UT_SERVER; mdrData.dwMDAttributes = METADATA_NO_ATTRIBUTES; mdrData.dwMDDataLen = (wcslen(DataBuf)+1)*2; mdrData.pbMDData = (PBYTE)DataBuf; hr = _pAdminBase->SetData( hObjHandle, _pszMetaBasePath, &mdrData); BAIL_ON_FAILURE(hr); error: if (_pAdminBase && hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); } RRETURN(hr); } HRESULT CIISGenObject::GetInfo() { _pPropertyCache->flushpropcache(); RRETURN(GetInfo(TRUE)); } HRESULT CIISGenObject::GetInfo( BOOL fExplicit ) { HRESULT hr = S_OK; METADATA_HANDLE hObjHandle = NULL; DWORD dwMDAttributes = METADATA_INHERIT; DWORD dwMDUserType = ALL_METADATA; DWORD dwMDDataType = ALL_METADATA; DWORD dwMDNumDataEntries; DWORD dwMDDataSetNumber; LPBYTE pBuffer = NULL; if (GetObjectState() == ADS_OBJECT_UNBOUND) { hr = E_ADS_OBJECT_UNBOUND; BAIL_ON_FAILURE(hr); } hr = OpenAdminBaseKey( _pszServerName, _pszMetaBasePath, METADATA_PERMISSION_READ, &_pAdminBase, &hObjHandle ); BAIL_ON_FAILURE(hr); hr = MetaBaseGetAllData( _pAdminBase, hObjHandle, L"", dwMDAttributes, dwMDUserType, dwMDDataType, &dwMDNumDataEntries, &dwMDDataSetNumber, (LPBYTE *)&pBuffer ); BAIL_ON_FAILURE(hr); hr = _pPropertyCache->IISUnMarshallProperties( pBuffer, pBuffer, dwMDNumDataEntries, fExplicit ); BAIL_ON_FAILURE(hr); error: if (pBuffer) { FreeADsMem(pBuffer); } if (_pAdminBase && hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); } RRETURN(hr); } /* IADsContainer methods */ STDMETHODIMP CIISGenObject::get_Count(long FAR* retval) { RRETURN(E_NOTIMPL); } STDMETHODIMP CIISGenObject::get_Filter(THIS_ VARIANT FAR* pVar) { RRETURN(E_NOTIMPL); } STDMETHODIMP CIISGenObject::put_Filter(THIS_ VARIANT Var) { RRETURN(E_NOTIMPL); } STDMETHODIMP CIISGenObject::put_Hints(THIS_ VARIANT Var) { RRETURN( E_NOTIMPL); } STDMETHODIMP CIISGenObject::get_Hints(THIS_ VARIANT FAR* pVar) { RRETURN(E_NOTIMPL); } STDMETHODIMP CIISGenObject::GetObject( BSTR ClassName, BSTR RelativeName, IDispatch * FAR* ppObject ) { HRESULT hr = S_OK; hr = ::RelativeGetObject( _ADsPath, ClassName, RelativeName, _Credentials, ppObject, FALSE ); RRETURN(hr); } STDMETHODIMP CIISGenObject::get__NewEnum( THIS_ IUnknown * FAR* retval ) { HRESULT hr; IUnknown FAR* punkEnum=NULL; IEnumVARIANT * penum = NULL; *retval = NULL; hr = CIISGenObjectEnum::Create( (CIISGenObjectEnum **)&penum, _ADsPath, _vFilter, _Credentials ); BAIL_ON_FAILURE(hr); hr = penum->QueryInterface( IID_IUnknown, (VOID FAR* FAR*)retval ); BAIL_ON_FAILURE(hr); if (penum) { penum->Release(); } RRETURN(NOERROR); error: if (penum) { delete penum; } RRETURN(hr); } inline HRESULT ValidateRelativePath( IN LPCWSTR wszRelativePath ) /*++ Routine Description: Determine if a relative path is valid. This is really just to check assumptions that are made about the relative path. It doesn't do much now, but might be expanded and moved to a common location if necessary. Arguments: IN wszRelativePath : a relative ads path Return Value: E_ADS_BAD_PATHNAME if the path is not valid --*/ { HRESULT hr = E_ADS_BAD_PATHNAME; if( wszRelativePath && *wszRelativePath != L'/' ) { hr = S_OK; } RRETURN(hr); } STDMETHODIMP CIISGenObject::Create( THIS_ BSTR ClassName, BSTR RelativeName, IDispatch * FAR* ppObject ) { HRESULT hr = S_OK; IADs * pADs = NULL; BOOL bRelativeNameExtended = FALSE; LPWSTR pwszParentClass = NULL; LPWSTR pwszParentADsPath = NULL; LPWSTR pwszRelativeName = NULL; DWORD i = 0; // // Validate if this class really exists in the schema // and validate that this object can be created in this // container // hr = _pSchema->ValidateClassName(ClassName); BAIL_ON_FAILURE(hr); // // Handle case where RelativeName may be an extended path, // such as foo/bar/baz. // hr = ValidateRelativePath( RelativeName ); BAIL_ON_FAILURE(hr); bRelativeNameExtended = ( wcschr( RelativeName, L'/' ) != NULL ); if( bRelativeNameExtended ) { pwszRelativeName = wcsrchr( RelativeName, L'/' ) + 1; hr = ResolveExtendedChildPath( RelativeName, &pwszParentADsPath, &pwszParentClass ); BAIL_ON_FAILURE(hr); } else { pwszParentClass = _ADsClass; pwszParentADsPath = _ADsPath; pwszRelativeName = RelativeName; } // // validate name --> can't have ',' in the name // while (RelativeName[i] != L'\0' && RelativeName[i] != L',') i++; if (RelativeName[i] != L'\0' || i >= METADATA_MAX_NAME_LEN) { hr = E_ADS_BAD_PARAMETER; BAIL_ON_FAILURE(hr); } hr = _pSchema->ValidateContainedClassName(pwszParentClass, ClassName); BAIL_ON_FAILURE(hr); hr = CIISGenObject::CreateGenericObject( pwszParentADsPath, pwszRelativeName, ClassName, _Credentials, ADS_OBJECT_UNBOUND, IID_IADs, (void **)&pADs ); BAIL_ON_FAILURE(hr); hr = pADs->QueryInterface( IID_IDispatch, (void **)ppObject ); BAIL_ON_FAILURE(hr); error: if (pADs) { pADs->Release(); } if( bRelativeNameExtended ) { ADsFreeString( pwszParentClass ); ADsFreeString( pwszParentADsPath ); } RRETURN(hr); } STDMETHODIMP CIISGenObject::Delete( THIS_ BSTR bstrClassName, BSTR bstrRelativeName ) { HRESULT hr = S_OK; METADATA_HANDLE hObjHandle = NULL; COSERVERINFO csiName; COSERVERINFO *pcsiParam = &csiName; IClassFactory * pcsfFactory = NULL; IIISApplicationAdmin * pAppAdmin = NULL; // // Get Server and Path name // hr = CacheMetaDataPath(); BAIL_ON_FAILURE(hr); // Check to see if we're deleting an IIsApplicationPool // If so, use the IISApplicationAdmin interface if ( !_wcsicmp(bstrClassName, L"IIsApplicationPool")) { memset(pcsiParam, 0, sizeof(COSERVERINFO)); // // special case to handle "localhost" to work-around ole32 bug // if (_pszServerName == NULL || _wcsicmp(_pszServerName,L"localhost") == 0) { pcsiParam->pwszName = NULL; } else { pcsiParam->pwszName = _pszServerName; } hr = CoGetClassObject( CLSID_WamAdmin, CLSCTX_SERVER, pcsiParam, IID_IClassFactory, (void**) &pcsfFactory ); BAIL_ON_FAILURE(hr); hr = pcsfFactory->CreateInstance( NULL, IID_IIISApplicationAdmin, (void **) &pAppAdmin ); BAIL_ON_FAILURE(hr); hr = pAppAdmin->DeleteApplicationPool( bstrRelativeName ); BAIL_ON_FAILURE(hr); } // Otherwise do the delete the old fashioned way else { hr = OpenAdminBaseKey( _pszServerName, _pszMetaBasePath, METADATA_PERMISSION_WRITE, &_pAdminBase, &hObjHandle ); BAIL_ON_FAILURE(hr); // // Pass in full path // hr = MetaBaseDeleteObject( _pAdminBase, hObjHandle, (LPWSTR)bstrRelativeName ); BAIL_ON_FAILURE(hr); } error: if (pcsfFactory) { pcsfFactory->Release(); } if (pAppAdmin) { pAppAdmin->Release(); } if (_pAdminBase && hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); } RRETURN(hr); } STDMETHODIMP CIISGenObject::CopyHere( THIS_ BSTR SourceName, BSTR NewName, IDispatch * FAR* ppObject ) { HRESULT hr = S_OK; IUnknown *pUnk = NULL; METADATA_HANDLE hObjHandle = NULL; LPWSTR pszIISPathName = NULL; IADs *pADs = NULL; BSTR bstrClassName = NULL; LPWSTR pszPath = NULL; IWamAdmin2 *pWamAdmin = NULL; LPWSTR pszIISNewName = NULL; hr = InitWamAdmin(_pszServerName, &pWamAdmin); BAIL_ON_FAILURE(hr); // // open common path node // hr = BuildIISPathFromADsPath( _ADsPath, &pszIISPathName ); BAIL_ON_FAILURE(hr); hr = OpenAdminBaseKey( _pszServerName, pszIISPathName, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, &_pAdminBase, &hObjHandle ); BAIL_ON_FAILURE(hr); // // Do Copy operation // hr = MetaBaseCopyObject( _pAdminBase, hObjHandle, (LPWSTR)SourceName, hObjHandle, (LPWSTR)NewName ); BAIL_ON_FAILURE(hr); if (hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); hObjHandle = NULL; } if (pszIISPathName) { DWORD dwLen; dwLen = wcslen(pszIISPathName) + wcslen(NewName) + 2; pszIISNewName = (LPWSTR)AllocADsMem(dwLen*sizeof(WCHAR)); if (!pszIISNewName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } wcscpy(pszIISNewName, pszIISPathName); if (NewName) { wcscat(pszIISNewName, L"/"); wcscat(pszIISNewName, (LPWSTR)NewName); } } hr = pWamAdmin->AppRecover((LPWSTR) pszIISNewName, TRUE); BAIL_ON_FAILURE(hr); hr = get_CoreADsClass(&bstrClassName); BAIL_ON_FAILURE(hr); hr = CIISGenObject::CreateGenericObject( _ADsPath, NewName, bstrClassName, _Credentials, ADS_OBJECT_BOUND, IID_IADs, (void **)&pADs ); BAIL_ON_FAILURE(hr); pszPath = ((CIISGenObject*)pADs)->ReturnMetaDataPath(); hr = pADs->QueryInterface( IID_IDispatch, (void **)ppObject ); BAIL_ON_FAILURE(hr); error: if (_pAdminBase) { if (hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); } } if (pWamAdmin) { UninitWamAdmin(pWamAdmin); } if (bstrClassName) { ADsFreeString(bstrClassName); } if (pszIISPathName) { FreeADsStr(pszIISPathName); } if (pszIISNewName) { FreeADsMem(pszIISNewName); } if (pADs){ pADs->Release(); } RRETURN(hr); } STDMETHODIMP CIISGenObject::MoveHere( THIS_ BSTR SourceName, BSTR NewName, IDispatch * FAR* ppObject ) { HRESULT hr = S_OK; IUnknown *pUnk = NULL; METADATA_HANDLE hObjHandle = NULL; LPWSTR pszIISPathName = NULL; IADs *pADs = NULL; BSTR bstrClassName = NULL; LPWSTR pszPath = NULL; IWamAdmin2 *pWamAdmin = NULL; LPWSTR pszIISOldName = NULL; LPWSTR pszIISNewName = NULL; hr = InitWamAdmin(_pszServerName, &pWamAdmin); BAIL_ON_FAILURE(hr); // // open common path node // hr = BuildIISPathFromADsPath( _ADsPath, &pszIISPathName ); BAIL_ON_FAILURE(hr); if (pszIISPathName) { DWORD dwLen; dwLen = wcslen(pszIISPathName) + wcslen(SourceName) + 2; pszIISOldName = (LPWSTR)AllocADsMem(dwLen*sizeof(WCHAR)); if (!pszIISOldName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } wcscpy(pszIISOldName, pszIISPathName); if (NewName) { wcscat(pszIISOldName, L"/"); wcscat(pszIISOldName, (LPWSTR)SourceName); } } hr = pWamAdmin->AppDeleteRecoverable((LPWSTR) pszIISOldName, TRUE); BAIL_ON_FAILURE(hr); hr = OpenAdminBaseKey( _pszServerName, pszIISPathName, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, &_pAdminBase, &hObjHandle ); BAIL_ON_FAILURE(hr); // // Do Move operation // hr = MetaBaseMoveObject( _pAdminBase, hObjHandle, (LPWSTR)SourceName, hObjHandle, (LPWSTR)NewName ); BAIL_ON_FAILURE(hr); if (hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); hObjHandle = NULL; } if (pszIISPathName) { DWORD dwLen; dwLen = wcslen(pszIISPathName) + wcslen(NewName) + 2; pszIISNewName = (LPWSTR)AllocADsMem(dwLen*sizeof(WCHAR)); if (!pszIISNewName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } wcscpy(pszIISNewName, pszIISPathName); if (NewName) { wcscat(pszIISNewName, L"/"); wcscat(pszIISNewName, (LPWSTR)NewName); } } hr = pWamAdmin->AppRecover((LPWSTR) pszIISNewName, TRUE); BAIL_ON_FAILURE(hr); hr = get_CoreADsClass(&bstrClassName); BAIL_ON_FAILURE(hr); hr = CIISGenObject::CreateGenericObject( _ADsPath, NewName, bstrClassName, _Credentials, ADS_OBJECT_BOUND, IID_IADs, (void **)&pADs ); BAIL_ON_FAILURE(hr); pszPath = ((CIISGenObject*)pADs)->ReturnMetaDataPath(); hr = pADs->QueryInterface( IID_IDispatch, (void **)ppObject ); BAIL_ON_FAILURE(hr); error: if (_pAdminBase) { if (hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); } } if (pWamAdmin) { UninitWamAdmin(pWamAdmin); } if (bstrClassName) { ADsFreeString(bstrClassName); } if (pszIISPathName) { FreeADsStr(pszIISPathName); } if (pszIISOldName) { FreeADsMem(pszIISOldName); } if (pszIISNewName) { FreeADsMem(pszIISNewName); } if (pADs){ pADs->Release(); } RRETURN(hr); } HRESULT CIISGenObject::AllocateGenObject( LPWSTR pszClassName, CCredentials& Credentials, CIISGenObject ** ppGenObject ) { CIISGenObject FAR * pGenObject = NULL; CAggregatorDispMgr FAR * pDispMgr = NULL; CPropertyCache FAR * pPropertyCache = NULL; HRESULT hr = S_OK; pGenObject = new CIISGenObject(); if (pGenObject == NULL) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr); pDispMgr = new CAggregatorDispMgr; if (pDispMgr == NULL) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr); hr = pDispMgr->LoadTypeInfoEntry( LIBID_ADs, IID_IADs, (IADs *)pGenObject, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); hr = pDispMgr->LoadTypeInfoEntry(LIBID_ADs, IID_IADsContainer, (IADsContainer *)pGenObject, DISPID_NEWENUM ); BAIL_ON_FAILURE(hr); hr = pDispMgr->LoadTypeInfoEntry( LIBID_IISOle, IID_IISBaseObject, (IISBaseObject *)pGenObject, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); hr = CPropertyCache::createpropertycache( (CCoreADsObject FAR *)pGenObject, &pPropertyCache ); BAIL_ON_FAILURE(hr); pDispMgr->RegisterPropertyCache((IPropertyCache*)pPropertyCache); pGenObject->_Credentials = Credentials; pGenObject->_pPropertyCache = pPropertyCache; pGenObject->_pDispMgr = pDispMgr; *ppGenObject = pGenObject; RRETURN(hr); error: delete pDispMgr; RRETURN(hr); } /* INTRINSA suppress=null_pointers, uninitialized */ STDMETHODIMP CIISGenObject::Get( THIS_ BSTR bstrName, VARIANT FAR* pvProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId; DWORD dwSyntax; DWORD dwNumValues = 0; LPIISOBJECT pIISSrcObjects = NULL; WCHAR wchName[MAX_PATH]; BSTR bstrClassName = NULL; // // check if property is a supported property // hr = get_CoreADsClass(&bstrClassName); BAIL_ON_FAILURE(hr); hr = _pSchema->ValidateProperty(bstrClassName, bstrName); BAIL_ON_FAILURE(hr); // // lookup ADSI IIS syntax Id // hr = _pSchema->LookupSyntaxID(bstrName, &dwSyntax); BAIL_ON_FAILURE(hr); // // check if property is BITMASK type; // if BITMASK type, get corresponding DWORD flag property // // check if property is RAW BINARY type; // if RAW BINARY type, get corresponding NTACL flag property // if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY) { hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName); BAIL_ON_FAILURE(hr); } // // retrieve data object from cache; if one exists // if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY) { hr = _pPropertyCache->getproperty( wchName, &dwSyntaxId, &dwNumValues, &pIISSrcObjects ); } else { hr = _pPropertyCache->getproperty( bstrName, &dwSyntaxId, &dwNumValues, &pIISSrcObjects ); } BAIL_ON_FAILURE(hr); // // reset it to its syntax id if BITMASK type // pIISSrcObjects->IISType = dwSyntax; // // translate the IIS objects to variants // // // always return an array for multisz type // if (dwNumValues == 1 && dwSyntax != IIS_SYNTAX_ID_MULTISZ && dwSyntax != IIS_SYNTAX_ID_MIMEMAP ) { hr = IISTypeToVarTypeCopy( _pSchema, bstrName, pIISSrcObjects, pvProp, FALSE ); }else { hr = IISTypeToVarTypeCopyConstruct( _pSchema, bstrName, pIISSrcObjects, dwNumValues, pvProp, FALSE ); } BAIL_ON_FAILURE(hr); error: if (bstrClassName) { ADsFreeString(bstrClassName); } if (pIISSrcObjects) { IISTypeFreeIISObjects( pIISSrcObjects, dwNumValues ); } RRETURN(hr); } STDMETHODIMP CIISGenObject::Put( THIS_ BSTR bstrName, VARIANT vProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId = 0; DWORD dwIndex = 0; LPIISOBJECT pIISDestObjects = NULL; DWORD dwNumValues = 0; VARIANT * pVarArray = NULL; VARIANT * pvProp = NULL; VARIANT vVar; WCHAR wchName[MAX_PATH]; BSTR bstrClassName = NULL; // // check if property is a supported property // hr = get_CoreADsClass(&bstrClassName); BAIL_ON_FAILURE(hr); hr = _pSchema->ValidateProperty(bstrClassName, bstrName); BAIL_ON_FAILURE(hr); // // lookup its syntax ID // hr = _pSchema->LookupSyntaxID( bstrName, &dwSyntaxId); BAIL_ON_FAILURE(hr); // // Issue: How do we handle multi-valued support // VariantInit(&vVar); VariantCopyInd(&vVar, &vProp); if ((V_VT(&vVar) & VT_VARIANT) && V_ISARRAY(&vVar)) { hr = ConvertArrayToVariantArray( vVar, &pVarArray, &dwNumValues ); BAIL_ON_FAILURE(hr); pvProp = pVarArray; } else { dwNumValues = 1; pvProp = &vVar; } // // check if the variant maps to the syntax of this property // hr = VarTypeToIISTypeCopyConstruct( dwSyntaxId, pvProp, dwNumValues, &pIISDestObjects, FALSE ); BAIL_ON_FAILURE(hr); // // check if property is BITMASK type; // if BITMASK type, get corresponding DWORD flag property // if (dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK) { VARIANT vGetProp; DWORD dwMask; DWORD dwFlagValue; hr = _pSchema->LookupBitMask(bstrName, &dwMask); BAIL_ON_FAILURE(hr); // // get its corresponding DWORD flag value // hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName); BAIL_ON_FAILURE(hr); VariantInit(&vGetProp); hr = Get(wchName, &vGetProp); BAIL_ON_FAILURE(hr); dwFlagValue = V_I4(&vGetProp); if (pIISDestObjects->IISValue.value_1.dwDWORD) { dwFlagValue |= dwMask; } else { dwFlagValue &= ~dwMask; } pIISDestObjects->IISValue.value_1.dwDWORD = dwFlagValue; pIISDestObjects->IISType = IIS_SYNTAX_ID_DWORD; bstrName = wchName; } if (dwSyntaxId == IIS_SYNTAX_ID_BINARY) { hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName); BAIL_ON_FAILURE(hr); bstrName = wchName; } // // Find this property in the cache // hr = _pPropertyCache->findproperty( bstrName, &dwIndex ); // // If this property does not exist in the // cache, add this property into the cache. // if (FAILED(hr)) { hr = _pPropertyCache->addproperty( bstrName, dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ? IIS_SYNTAX_ID_DWORD : dwSyntaxId, dwNumValues, pIISDestObjects ); // // If the operation fails for some reason // move on to the next property // BAIL_ON_FAILURE(hr); } // // Now update the property in the cache // hr = _pPropertyCache->putproperty( bstrName, CACHE_PROPERTY_MODIFIED, dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ? IIS_SYNTAX_ID_DWORD : dwSyntaxId, dwNumValues, pIISDestObjects ); BAIL_ON_FAILURE(hr); error: if (pIISDestObjects) { IISTypeFreeIISObjects( pIISDestObjects, dwNumValues ); } if (bstrClassName) { ADsFreeString(bstrClassName); } if (pVarArray) { DWORD i = 0; for (i = 0; i < dwNumValues; i++) { VariantClear(pVarArray + i); } FreeADsMem(pVarArray); } VariantClear(&vVar); RRETURN(hr); } STDMETHODIMP CIISGenObject::PutEx( THIS_ long lnControlCode, BSTR bstrName, VARIANT vProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId = 0; DWORD dwIndex = 0; LPIISOBJECT pIISDestObjects = NULL; DWORD dwNumValues = 0; DWORD dwFlags = 0; VARIANT * pVarArray = NULL; VARIANT * pvProp = NULL; VARIANT vVar; WCHAR wchName[MAX_PATH]; BSTR bstrClassName = NULL; METADATA_HANDLE hObjHandle = NULL; // // check if property is a supported property // hr = get_CoreADsClass(&bstrClassName); BAIL_ON_FAILURE(hr); hr = _pSchema->ValidateProperty(bstrClassName, bstrName); BAIL_ON_FAILURE(hr); // // lookup its syntax Id // hr = _pSchema->LookupSyntaxID( bstrName, &dwSyntaxId); BAIL_ON_FAILURE(hr); switch (lnControlCode) { case ADS_PROPERTY_CLEAR: dwFlags = CACHE_PROPERTY_CLEARED; pIISDestObjects = NULL; dwNumValues = 0; break; case ADS_PROPERTY_UPDATE: dwFlags = CACHE_PROPERTY_MODIFIED; // // Now begin the rest of the processing // VariantInit(&vVar); VariantCopyInd(&vVar, &vProp); if ((V_VT(&vVar) & VT_VARIANT) && V_ISARRAY(&vVar)) { hr = ConvertArrayToVariantArray( vVar, &pVarArray, &dwNumValues ); BAIL_ON_FAILURE(hr); pvProp = pVarArray; } else { hr = E_FAIL; BAIL_ON_FAILURE(hr); } VariantClear(&vVar); // // check if the variant maps to the syntax of this property // hr = VarTypeToIISTypeCopyConstruct( dwSyntaxId, pvProp, dwNumValues, &pIISDestObjects, TRUE ); BAIL_ON_FAILURE(hr); break; default: RRETURN(hr = E_ADS_BAD_PARAMETER); } // // check if property is BITMASK type; // if BITMASK type, get corresponding DWORD flag property // if (dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK) { VARIANT vGetProp; DWORD dwMask; DWORD dwFlagValue; hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName); BAIL_ON_FAILURE(hr); if (dwFlags != CACHE_PROPERTY_CLEARED) { hr = _pSchema->LookupBitMask(bstrName, &dwMask); BAIL_ON_FAILURE(hr); // // get its corresponding DWORD flag value // VariantInit(&vGetProp); hr = Get(wchName, &vGetProp); BAIL_ON_FAILURE(hr); dwFlagValue = V_I4(&vGetProp); if (pIISDestObjects->IISValue.value_1.dwDWORD) { dwFlagValue |= dwMask; } else { dwFlagValue &= ~dwMask; } pIISDestObjects->IISValue.value_1.dwDWORD = dwFlagValue; pIISDestObjects->IISType = IIS_SYNTAX_ID_DWORD; } bstrName = wchName; } if (dwSyntaxId == IIS_SYNTAX_ID_BINARY) { hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName); BAIL_ON_FAILURE(hr); bstrName = wchName; } // // Find this property in the cache // hr = _pPropertyCache->findproperty( bstrName, &dwIndex ); // // If this property does not exist in the // cache, add this property into the cache. // if (FAILED(hr)) { hr = _pPropertyCache->addproperty( bstrName, dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ? IIS_SYNTAX_ID_DWORD : dwSyntaxId, dwNumValues, pIISDestObjects ); // // If the operation fails for some reason // move on to the next property // BAIL_ON_FAILURE(hr); } // // Now update the property in the cache // hr = _pPropertyCache->putproperty( bstrName, dwFlags, dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ? IIS_SYNTAX_ID_DWORD : dwSyntaxId, dwNumValues, pIISDestObjects ); BAIL_ON_FAILURE(hr); if (dwFlags == CACHE_PROPERTY_CLEARED) { DWORD dwMetaId; hr = _pSchema->LookupMetaID(bstrName, &dwMetaId); BAIL_ON_FAILURE(hr); hr = OpenAdminBaseKey( _pszServerName, _pszMetaBasePath, METADATA_PERMISSION_WRITE, &_pAdminBase, &hObjHandle ); BAIL_ON_FAILURE(hr); hr = _pAdminBase->DeleteData( hObjHandle, (LPWSTR)L"", dwMetaId, ALL_METADATA ); if (hr == MD_ERROR_DATA_NOT_FOUND) { hr = S_OK; } } error: if (_pAdminBase && hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); } if (bstrClassName) { ADsFreeString(bstrClassName); } if (pIISDestObjects) { IISTypeFreeIISObjects( pIISDestObjects, dwNumValues ); } if (pVarArray) { DWORD i = 0; for (i = 0; i < dwNumValues; i++) { VariantClear(pVarArray + i); } FreeADsMem(pVarArray); } RRETURN(hr); } /* INTRINSA suppress=null_pointers, uninitialized */ STDMETHODIMP CIISGenObject::GetEx( THIS_ BSTR bstrName, VARIANT FAR* pvProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId; DWORD dwSyntax; DWORD dwNumValues = 0; LPIISOBJECT pIISSrcObjects = NULL; WCHAR wchName[MAX_PATH]; BSTR bstrClassName = NULL; // // check if property is a supported property // hr = get_CoreADsClass(&bstrClassName); BAIL_ON_FAILURE(hr); hr = _pSchema->ValidateProperty(bstrClassName, bstrName); BAIL_ON_FAILURE(hr); // // lookup its syntax Id // hr = _pSchema->LookupSyntaxID(bstrName, &dwSyntax); BAIL_ON_FAILURE(hr); // // check if property is BITMASK type; // if BITMASK type, get corresponding DWORD flag property // // check if property is RAW BINARY type; // if RAW BINARY type, get corresponding NTACL flag property // if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY) { hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName); BAIL_ON_FAILURE(hr); } // // retrieve data object from cache; if one exists // if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY) { hr = _pPropertyCache->getproperty( wchName, &dwSyntaxId, &dwNumValues, &pIISSrcObjects ); } else { hr = _pPropertyCache->getproperty( bstrName, &dwSyntaxId, &dwNumValues, &pIISSrcObjects ); } BAIL_ON_FAILURE(hr); // // reset it to its syntax id if BITMASK type // pIISSrcObjects->IISType = dwSyntax; // // translate the IIS objects to variants // hr = IISTypeToVarTypeCopyConstruct( _pSchema, bstrName, pIISSrcObjects, dwNumValues, pvProp, TRUE ); BAIL_ON_FAILURE(hr); error: if (bstrClassName) { ADsFreeString(bstrClassName); } if (pIISSrcObjects) { IISTypeFreeIISObjects( pIISSrcObjects, dwNumValues ); } RRETURN(hr); } HRESULT CIISGenObject::CacheMetaDataPath() { HRESULT hr = E_FAIL; OBJECTINFO ObjectInfo; POBJECTINFO pObjectInfo = &ObjectInfo; CLexer Lexer(_ADsPath); LPWSTR pszIISPathName = NULL; memset(pObjectInfo, 0, sizeof(OBJECTINFO)); hr = ADsObject(&Lexer, pObjectInfo); BAIL_ON_FAILURE(hr); _pszServerName = AllocADsStr(pObjectInfo->TreeName); if (!_pszServerName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } hr = InitServerInfo(_pszServerName, &_pAdminBase, &_pSchema); BAIL_ON_FAILURE(hr); pszIISPathName = AllocADsStr(_ADsPath); if (!pszIISPathName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } *pszIISPathName = L'\0'; hr = BuildIISPathFromADsPath( pObjectInfo, pszIISPathName ); BAIL_ON_FAILURE(hr); _pszMetaBasePath = AllocADsStr(pszIISPathName); if (!_pszMetaBasePath) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } error: if (pszIISPathName) { FreeADsStr(pszIISPathName); } FreeObjectInfo(pObjectInfo); RRETURN(hr); } STDMETHODIMP CIISGenObject::GetDataPaths( THIS_ BSTR bstrName, THIS_ LONG lnAttribute, VARIANT FAR* pvProp ) { HRESULT hr = S_OK; DWORD dwMetaId; DWORD dwAttribute; DWORD dwTemp; METADATA_HANDLE hObjHandle = NULL; LPBYTE pBuffer = NULL; // // check if property is a supported property // hr = _pSchema->LookupMetaID(bstrName, &dwMetaId); BAIL_ON_FAILURE(hr); hr = _pSchema->LookupMDFlags(dwMetaId, &dwAttribute, &dwTemp); BAIL_ON_FAILURE(hr); switch (lnAttribute) { case IIS_ANY_PROPERTY: break; case IIS_INHERITABLE_ONLY: if ((METADATA_INHERIT & dwAttribute) != METADATA_INHERIT) { RRETURN(hr = MD_ERROR_DATA_NOT_FOUND); } break; default : RRETURN(hr = E_ADS_BAD_PARAMETER); } // // Get Server and Path name // hr = CacheMetaDataPath(); BAIL_ON_FAILURE(hr); hr = OpenAdminBaseKey( _pszServerName, _pszMetaBasePath, METADATA_PERMISSION_READ, &_pAdminBase, &hObjHandle ); BAIL_ON_FAILURE(hr); hr = MetaBaseGetDataPaths(_pAdminBase, hObjHandle, dwMetaId, (LPBYTE *)&pBuffer ); BAIL_ON_FAILURE(hr); hr = MakeVariantFromPathArray( (LPWSTR)_ADsPath, (LPWSTR)pBuffer, pvProp); BAIL_ON_FAILURE(hr); error: if (pBuffer) { FreeADsMem(pBuffer); } if (_pAdminBase && hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); } RRETURN(hr); } STDMETHODIMP CIISGenObject::GetPropertyAttribObj( THIS_ BSTR bstrName, IDispatch * FAR* ppObject ) { HRESULT hr = S_OK; DWORD dwMetaId; DWORD i = 0; PROPERTYINFO *pPropertyInfo = NULL; IISPropertyAttribute * pPropAttrib = NULL; WCHAR wchName[MAX_PATH]; METADATA_HANDLE hObjHandle = NULL; DWORD dwBufferSize = 0; METADATA_RECORD mdrMDData; LPBYTE pBuffer = NULL; VARIANT vVar; VariantInit(&vVar); *ppObject = NULL; // // if passed in bstrName is a meta id, then convert it to property name // if (wcslen(bstrName) >= MAX_PATH) bstrName[MAX_PATH - 1] = L'\0'; wcscpy((LPWSTR)wchName, bstrName); while (wchName[i] != L'\0' && wchName[i] >= L'0' && wchName[i] <= L'9') { i++; } if (i == wcslen((LPWSTR)wchName)) { dwMetaId = _wtoi((LPWSTR)wchName); hr = _pSchema->ConvertID_To_PropName(dwMetaId, (LPWSTR)wchName); BAIL_ON_FAILURE(hr); } else { // // check if property is a supported property // hr = _pSchema->LookupMetaID(bstrName, &dwMetaId); BAIL_ON_FAILURE(hr); } hr = OpenAdminBaseKey( _pszServerName, _pszMetaBasePath, METADATA_PERMISSION_READ, &_pAdminBase, &hObjHandle ); BAIL_ON_FAILURE(hr); MD_SET_DATA_RECORD(&mdrMDData, dwMetaId, METADATA_INHERIT | METADATA_ISINHERITED, ALL_METADATA, ALL_METADATA, dwBufferSize, pBuffer); hr = _pAdminBase->GetData( hObjHandle, L"", &mdrMDData, &dwBufferSize ); pBuffer = (LPBYTE) AllocADsMem(dwBufferSize); mdrMDData.pbMDData = pBuffer; mdrMDData.dwMDDataLen = dwBufferSize; hr = _pAdminBase->GetData( hObjHandle, L"", &mdrMDData, &dwBufferSize ); BAIL_ON_FAILURE(hr); // // get default value // pPropertyInfo = _pSchema->GetPropertyInfo(wchName); ASSERT(pPropertyInfo != NULL); if (pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_DWORD || pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_MIMEMAP || pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_IPSECLIST || pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_BINARY || pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_NTACL) { vVar.vt = VT_I4; vVar.lVal = pPropertyInfo->dwDefault; } else if (pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_BOOL || pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK) { vVar.vt = VT_BOOL; vVar.boolVal = pPropertyInfo->dwDefault ? VARIANT_TRUE : VARIANT_FALSE; } else if (pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_MULTISZ) { LPWSTR pszStr = pPropertyInfo->szDefault; hr = MakeVariantFromStringArray(NULL, pszStr, &vVar); BAIL_ON_FAILURE(hr); } else { vVar.vt = VT_BSTR; hr = ADsAllocString( pPropertyInfo->szDefault, &(vVar.bstrVal)); BAIL_ON_FAILURE(hr); } hr = CPropertyAttribute::CreatePropertyAttribute( IID_IISPropertyAttribute, (VOID**)&pPropAttrib ); BAIL_ON_FAILURE(hr); hr = ((CPropertyAttribute*)pPropAttrib)->InitFromRawData( (LPWSTR) wchName, dwMetaId, mdrMDData.dwMDUserType, // usertype mdrMDData.dwMDAttributes, // attributes &vVar ); BAIL_ON_FAILURE(hr); *ppObject = (IDispatch*)pPropAttrib; error: if (pBuffer) { FreeADsMem(pBuffer); } if (hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); } RRETURN(hr); } HRESULT CIISGenObject::ResolveExtendedChildPath( IN BSTR RelativeChildPath, OUT BSTR *pParentPath, OUT BSTR *pParentClass ) /*++ Routine Description: Helper method called from CIISGenObject::Create() finds the metabase key that is most proximate to RelativeChildPath and returns the ADS class for this key along with adjusted path for the parent. Arguments: IN RelativeChildPath : An extended subpath, such as foo/bar OUT pParentPath : Allocated with ADsAllocString OUT pParentClass : Allocated with ADsAllocString Return Value: S_OK S_FALSE : No path found in the metabase --*/ { ADsAssert( RelativeChildPath ); ADsAssert( pParentPath ); ADsAssert( pParentClass ); *pParentPath = NULL; *pParentClass = NULL; HRESULT hr = S_OK; DWORD cbBuffSize; LPWSTR pwszPathBuffer = NULL; DWORD dwLen; BOOL bFound; WCHAR *pch = NULL; WCHAR wszParentClassBuffer[MAX_PATH]; // // Build buffer to hold the metabase and ads paths // cbBuffSize = (wcslen(_ADsPath) + wcslen(RelativeChildPath) + 2) * sizeof(WCHAR); pwszPathBuffer = (LPWSTR)AllocADsMem( cbBuffSize ); if( !pwszPathBuffer ) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } ZeroMemory( pwszPathBuffer, cbBuffSize ); // // Build the metabase path for the child // wcscpy( pwszPathBuffer, _pszMetaBasePath ); dwLen = wcslen( pwszPathBuffer ); ADsAssert( dwLen ); if( pwszPathBuffer[dwLen - 1] != L'/' ) { pwszPathBuffer[dwLen] = L'/'; } wcscat( pwszPathBuffer, RelativeChildPath ); // // Look for the closest path in the metabase to our child // bFound = FALSE; pch = wcsrchr( pwszPathBuffer, L'/' ); if (pch != NULL) *pch = 0; while( !bFound && 0 != wcscmp( pwszPathBuffer, _pszMetaBasePath ) ) { hr = MetaBaseDetectKey( _pAdminBase, pwszPathBuffer ); if( SUCCEEDED(hr) ) { bFound = TRUE; } else if( ERROR_PATH_NOT_FOUND == HRESULT_CODE(hr) ) { // Continue up the path buffer pch = wcsrchr( pwszPathBuffer, L'/' ); if (pch != NULL) *pch = 0; hr = S_FALSE; } else { BAIL_ON_FAILURE( hr ); } } // // Get pParentClass // if( bFound ) { // Get the key type from the node hr = MetaBaseGetADsClass( _pAdminBase, pwszPathBuffer, _pSchema, wszParentClassBuffer, MAX_PATH ); BAIL_ON_FAILURE( hr ); } else { // Use our own key type wcscpy( wszParentClassBuffer, _ADsClass ); } hr = ADsAllocString( wszParentClassBuffer, pParentClass ); BAIL_ON_FAILURE( hr ); // // Get pParentPath // wcscpy( pwszPathBuffer, _ADsPath ); wcscat( pwszPathBuffer, L"/" ); wcscat( pwszPathBuffer, RelativeChildPath ); pch = wcsrchr( pwszPathBuffer, L'/' ); if (pch != NULL) *pch = 0; hr = ADsAllocString( pwszPathBuffer, pParentPath ); BAIL_ON_FAILURE( hr ); error: if( pwszPathBuffer ) { FreeADsMem( pwszPathBuffer ); } RRETURN( hr ); }