//--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1996 // // File: cschema.cxx // // Contents: Windows NT 3.51 // // // History: 01-09-96 yihsins Created. // //---------------------------------------------------------------------------- #include "winnt.hxx" #pragma hdrstop /******************************************************************/ /* Class CWinNTSchema /******************************************************************/ DEFINE_IDispatch_Delegating_Implementation(CWinNTSchema) DEFINE_IADsExtension_Implementation(CWinNTSchema) DEFINE_IADs_Implementation(CWinNTSchema) CWinNTSchema::CWinNTSchema() { VariantInit( &_vFilter ); ENLIST_TRACKING(CWinNTSchema); } CWinNTSchema::~CWinNTSchema() { VariantClear( &_vFilter ); delete _pDispMgr; } HRESULT CWinNTSchema::CreateSchema( BSTR bstrParent, BSTR bstrName, DWORD dwObjectState, REFIID riid, CWinNTCredentials& Credentials, void **ppvObj ) { CWinNTSchema FAR *pSchema = NULL; HRESULT hr = S_OK; hr = AllocateSchemaObject( &pSchema ); BAIL_ON_FAILURE(hr); hr = pSchema->InitializeCoreObject( bstrParent, bstrName, SCHEMA_CLASS_NAME, NO_SCHEMA, CLSID_WinNTSchema, dwObjectState ); BAIL_ON_FAILURE(hr); pSchema->_Credentials = Credentials; // check if the call is from UMI if(Credentials.GetFlags() & ADS_AUTH_RESERVED) { // // we do not pass riid to InitUmiObject below. This is because UMI object // does not support IDispatch. There are several places in ADSI code where // riid passed into this function is defaulted to IID_IDispatch - // IADsContainer::Create for example. To handle these cases, we always // request IID_IUnknown from the UMI object. Subsequent code within UMI // will QI for the appropriate interface. // if(2 == pSchema->_dwNumComponents) { pSchema->_CompClasses[0] = L"Computer"; pSchema->_CompClasses[1] = L"Schema"; } else BAIL_ON_FAILURE(hr = UMI_E_FAIL); hr = pSchema->InitUmiObject( pSchema->_Credentials, SchemaClass, g_dwSchemaClassTableSize, NULL, (IUnknown *) (INonDelegatingUnknown *) pSchema, NULL, IID_IUnknown, ppvObj ); BAIL_ON_FAILURE(hr); // // UMI object was created and the interface was obtained successfully. // UMI object now has a reference to the inner unknown of IADs, since // the call to Release() below is not going to be made in this case. // RRETURN(hr); } hr = pSchema->QueryInterface( riid, ppvObj ); BAIL_ON_FAILURE(hr); pSchema->Release(); RRETURN(hr); error: delete pSchema; RRETURN_EXP_IF_ERR(hr); } //---------------------------------------------------------------------------- // Function: QueryInterface // // Synopsis: If this object is aggregated within another object, then // all calls will delegate to the outer object. Otherwise, the // non-delegating QI is called // // Arguments: // // iid interface requested // ppInterface Returns pointer to interface requested. NULL if interface // is not supported. // // Returns: S_OK on success. Error code otherwise. // // Modifies: *ppInterface to return interface pointer // //---------------------------------------------------------------------------- STDMETHODIMP CWinNTSchema::QueryInterface( REFIID iid, LPVOID *ppInterface ) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->QueryInterface( iid, ppInterface )); RRETURN(NonDelegatingQueryInterface( iid, ppInterface )); } //---------------------------------------------------------------------------- // Function: AddRef // // Synopsis: IUnknown::AddRef. If this object is aggregated within // another, all calls will delegate to the outer object. // Otherwise, the non-delegating AddRef is called // // Arguments: // // None // // Returns: New reference count // // Modifies: Nothing // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CWinNTSchema::AddRef(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->AddRef()); RRETURN(NonDelegatingAddRef()); } //---------------------------------------------------------------------------- // Function: Release // // Synopsis: IUnknown::Release. If this object is aggregated within // another, all calls will delegate to the outer object. // Otherwise, the non-delegating Release is called // // Arguments: // // None // // Returns: New reference count // // Modifies: Nothing // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CWinNTSchema::Release(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->Release()); RRETURN(NonDelegatingRelease()); } //---------------------------------------------------------------------------- STDMETHODIMP CWinNTSchema::NonDelegatingQueryInterface(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_IDispatch)) { *ppv = (IADs FAR *)this; } else if (IsEqualIID(iid, IID_ISupportErrorInfo)) { *ppv = (ISupportErrorInfo FAR *)this; } else if (IsEqualIID(iid, IID_IADs)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_IADsContainer)) { *ppv = (IADsContainer FAR *) this; } else if( (_pDispatch != NULL) && IsEqualIID(iid, IID_IADsExtension) ) { *ppv = (IADsExtension *) this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return NOERROR; } /* ISupportErrorInfo method */ STDMETHODIMP CWinNTSchema::InterfaceSupportsErrorInfo( THIS_ REFIID riid ) { if (IsEqualIID(riid, IID_IADs) || IsEqualIID(riid, IID_IADsContainer)) { RRETURN(S_OK); } else { RRETURN(S_FALSE); } } /* IADs methods */ STDMETHODIMP CWinNTSchema::SetInfo(THIS) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } STDMETHODIMP CWinNTSchema::GetInfo(THIS) { RRETURN(S_OK); } STDMETHODIMP CWinNTSchema::ImplicitGetInfo(THIS) { RRETURN(S_OK); } /* IADsContainer methods */ STDMETHODIMP CWinNTSchema::get_Count(long FAR* retval) { HRESULT hr; if ( !retval ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); *retval = g_cWinNTClasses + g_cWinNTSyntax; RRETURN(S_OK); } STDMETHODIMP CWinNTSchema::get_Filter(THIS_ VARIANT FAR* pVar) { HRESULT hr; if ( !pVar ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); VariantInit( pVar ); hr = VariantCopy( pVar, &_vFilter ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTSchema::put_Filter(THIS_ VARIANT Var) { HRESULT hr; hr = VariantCopy( &_vFilter, &Var ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTSchema::get_Hints(THIS_ VARIANT FAR* pVar) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } STDMETHODIMP CWinNTSchema::put_Hints(THIS_ VARIANT Var) { RRETURN_EXP_IF_ERR( E_NOTIMPL); } STDMETHODIMP CWinNTSchema::GetObject( THIS_ BSTR ClassName, BSTR RelativeName, IDispatch * FAR* ppObject) { TCHAR szBuffer[MAX_PATH]; DWORD dwLength = 0; HRESULT hr = S_OK; if (!RelativeName || !*RelativeName) { RRETURN_EXP_IF_ERR(E_ADS_UNKNOWN_OBJECT); } // // Make sure we are not going to overflow the string buffer. // +2 for / and \0 // dwLength = wcslen(_ADsPath) + wcslen(RelativeName) + 2; if (dwLength > MAX_PATH) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } wcscpy(szBuffer, _ADsPath); wcscat(szBuffer, L"/"); wcscat(szBuffer, RelativeName); if (ClassName) { // // +1 for the ",". // dwLength += wcslen(ClassName) + 1; if (dwLength > MAX_PATH) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } wcscat(szBuffer,L","); wcscat(szBuffer, ClassName); } hr = ::GetObject(szBuffer, (LPVOID *)ppObject, _Credentials); BAIL_ON_FAILURE(hr); error: RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTSchema::get__NewEnum(THIS_ IUnknown * FAR* retval) { HRESULT hr; IEnumVARIANT *penum = NULL; if ( !retval ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); *retval = NULL; // // Create new enumerator for items currently // in collection and QI for IUnknown // hr = CWinNTSchemaEnum::Create( (CWinNTSchemaEnum **)&penum, _ADsPath, _Name, _vFilter, _Credentials); BAIL_ON_FAILURE(hr); hr = penum->QueryInterface( IID_IUnknown, (VOID FAR* FAR*)retval ); BAIL_ON_FAILURE(hr); if ( penum ) penum->Release(); RRETURN(hr); error: if ( penum ) delete penum; RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTSchema::Create( THIS_ BSTR ClassName, BSTR RelativeName, IDispatch * FAR* ppObject) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } STDMETHODIMP CWinNTSchema::Delete(THIS_ BSTR SourceName, BSTR Type) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } STDMETHODIMP CWinNTSchema::CopyHere(THIS_ BSTR SourceName, BSTR NewName, IDispatch * FAR* ppObject) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } STDMETHODIMP CWinNTSchema::MoveHere(THIS_ BSTR SourceName, BSTR NewName, IDispatch * FAR* ppObject) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } HRESULT CWinNTSchema::AllocateSchemaObject(CWinNTSchema FAR * FAR * ppSchema) { CWinNTSchema FAR *pSchema = NULL; CAggregatorDispMgr FAR *pDispMgr = NULL; HRESULT hr = S_OK; pSchema = new CWinNTSchema(); if ( pSchema == NULL ) hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); pDispMgr = new CAggregatorDispMgr; if ( pDispMgr == NULL ) hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry( pDispMgr, LIBID_ADs, IID_IADs, (IADs *) pSchema, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry( pDispMgr, LIBID_ADs, IID_IADsContainer, (IADsContainer *) pSchema, DISPID_NEWENUM ); BAIL_ON_FAILURE(hr); pSchema->_pDispMgr = pDispMgr; *ppSchema = pSchema; RRETURN(hr); error: delete pDispMgr; delete pSchema; RRETURN_EXP_IF_ERR(hr); } /******************************************************************/ /* Class CWinNTClass /******************************************************************/ DEFINE_IDispatch_Delegating_Implementation(CWinNTClass) DEFINE_IADsExtension_Implementation(CWinNTClass) DEFINE_IADs_Implementation(CWinNTClass) CWinNTClass::CWinNTClass() : _pDispMgr( NULL ), _aPropertyInfo( NULL ), _cPropertyInfo( 0 ), _bstrCLSID( NULL ), _bstrOID( NULL ), _bstrPrimaryInterface( NULL ), _fAbstract( FALSE ), _fContainer( FALSE ), _bstrHelpFileName( NULL ), _lHelpFileContext( 0 ) { VariantInit( &_vMandatoryProperties ); VariantInit( &_vOptionalProperties ); VariantInit( &_vPossSuperiors ); VariantInit( &_vContainment ); VariantInit( &_vFilter ); ENLIST_TRACKING(CWinNTClass); } CWinNTClass::~CWinNTClass() { if ( _bstrCLSID ) { ADsFreeString( _bstrCLSID ); } if ( _bstrOID ) { ADsFreeString( _bstrOID ); } if ( _bstrPrimaryInterface ) { ADsFreeString( _bstrPrimaryInterface ); } if ( _bstrHelpFileName ) { ADsFreeString( _bstrHelpFileName ); } VariantClear( &_vMandatoryProperties ); VariantClear( &_vOptionalProperties ); VariantClear( &_vPossSuperiors ); VariantClear( &_vContainment ); VariantClear( &_vFilter ); delete _pDispMgr; } HRESULT CWinNTClass::CreateClass( BSTR bstrParent, CLASSINFO *pClassInfo, DWORD dwObjectState, REFIID riid, CWinNTCredentials& Credentials, void **ppvObj ) { CWinNTClass FAR *pClass = NULL; HRESULT hr = S_OK; BSTR bstrTmp = NULL; hr = AllocateClassObject( &pClass ); BAIL_ON_FAILURE(hr); pClass->_aPropertyInfo = pClassInfo->aPropertyInfo; pClass->_cPropertyInfo = pClassInfo->cPropertyInfo; pClass->_lHelpFileContext = pClassInfo->lHelpFileContext; pClass->_fContainer = (VARIANT_BOOL)pClassInfo->fContainer; pClass->_fAbstract = (VARIANT_BOOL)pClassInfo->fAbstract; hr = StringFromCLSID( (REFCLSID) *(pClassInfo->pPrimaryInterfaceGUID), &bstrTmp ); BAIL_ON_FAILURE(hr); hr = ADsAllocString( bstrTmp, &pClass->_bstrPrimaryInterface); BAIL_ON_FAILURE(hr); CoTaskMemFree(bstrTmp); bstrTmp = NULL; hr = StringFromCLSID( (REFCLSID) *(pClassInfo->pCLSID), &bstrTmp ); BAIL_ON_FAILURE(hr); hr = ADsAllocString( bstrTmp, &pClass->_bstrCLSID ); BAIL_ON_FAILURE(hr); CoTaskMemFree(bstrTmp); bstrTmp = NULL; hr = ADsAllocString( pClassInfo->bstrOID, &pClass->_bstrOID); BAIL_ON_FAILURE(hr); hr = MakeVariantFromStringList( pClassInfo->bstrMandatoryProperties, &(pClass->_vMandatoryProperties)); BAIL_ON_FAILURE(hr); hr = MakeVariantFromStringList( pClassInfo->bstrOptionalProperties, &(pClass->_vOptionalProperties)); BAIL_ON_FAILURE(hr); hr = MakeVariantFromStringList( pClassInfo->bstrPossSuperiors, &(pClass->_vPossSuperiors)); BAIL_ON_FAILURE(hr); hr = MakeVariantFromStringList( pClassInfo->bstrContainment, &(pClass->_vContainment)); BAIL_ON_FAILURE(hr); hr = ADsAllocString( pClassInfo->bstrHelpFileName, &pClass->_bstrHelpFileName); BAIL_ON_FAILURE(hr); hr = pClass->InitializeCoreObject( bstrParent, pClassInfo->bstrName, CLASS_CLASS_NAME, NO_SCHEMA, CLSID_WinNTClass, dwObjectState ); BAIL_ON_FAILURE(hr); pClass->_Credentials = Credentials; // check if the call is from UMI if(Credentials.GetFlags() & ADS_AUTH_RESERVED) { // // we do not pass riid to InitUmiObject below. This is because UMI object // does not support IDispatch. There are several places in ADSI code where // riid passed into this function is defaulted to IID_IDispatch - // IADsContainer::Create for example. To handle these cases, we always // request IID_IUnknown from the UMI object. Subsequent code within UMI // will QI for the appropriate interface. // if(3 == pClass->_dwNumComponents) { pClass->_CompClasses[0] = L"Computer"; pClass->_CompClasses[1] = L"Schema"; pClass->_CompClasses[2] = L"Class"; } else BAIL_ON_FAILURE(hr = UMI_E_FAIL); hr = pClass->InitUmiObject( pClass->_Credentials, SchClassClass, g_dwSchClassClassTableSize, NULL, (IUnknown *)(INonDelegatingUnknown *) pClass, NULL, IID_IUnknown, ppvObj, pClassInfo ); BAIL_ON_FAILURE(hr); // // UMI object was created and the interface was obtained successfully. // UMI object now has a reference to the inner unknown of IADs, since // the call to Release() below is not going to be made in this case. // RRETURN(hr); } hr = pClass->QueryInterface( riid, ppvObj ); BAIL_ON_FAILURE(hr); pClass->Release(); RRETURN(hr); error: if ( bstrTmp != NULL ) CoTaskMemFree(bstrTmp); delete pClass; RRETURN_EXP_IF_ERR(hr); } // called by implicit GetInfo from property cache STDMETHODIMP CWinNTClass::GetInfo( THIS_ DWORD dwApiLevel, BOOL fExplicit ) { RRETURN(S_OK); } //---------------------------------------------------------------------------- // Function: QueryInterface // // Synopsis: If this object is aggregated within another object, then // all calls will delegate to the outer object. Otherwise, the // non-delegating QI is called // // Arguments: // // iid interface requested // ppInterface Returns pointer to interface requested. NULL if interface // is not supported. // // Returns: S_OK on success. Error code otherwise. // // Modifies: *ppInterface to return interface pointer // //---------------------------------------------------------------------------- STDMETHODIMP CWinNTClass::QueryInterface( REFIID iid, LPVOID *ppInterface ) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->QueryInterface( iid, ppInterface )); RRETURN(NonDelegatingQueryInterface( iid, ppInterface )); } //---------------------------------------------------------------------------- // Function: AddRef // // Synopsis: IUnknown::AddRef. If this object is aggregated within // another, all calls will delegate to the outer object. // Otherwise, the non-delegating AddRef is called // // Arguments: // // None // // Returns: New reference count // // Modifies: Nothing // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CWinNTClass::AddRef(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->AddRef()); RRETURN(NonDelegatingAddRef()); } //---------------------------------------------------------------------------- // Function: Release // // Synopsis: IUnknown::Release. If this object is aggregated within // another, all calls will delegate to the outer object. // Otherwise, the non-delegating Release is called // // Arguments: // // None // // Returns: New reference count // // Modifies: Nothing // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CWinNTClass::Release(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->Release()); RRETURN(NonDelegatingRelease()); } //---------------------------------------------------------------------------- STDMETHODIMP CWinNTClass::NonDelegatingQueryInterface(REFIID iid, LPVOID FAR* ppv) { if (ppv == NULL) { RRETURN(E_POINTER); } if (IsEqualIID(iid, IID_IUnknown)) { *ppv = (IADsClass FAR * ) this; } else if (IsEqualIID(iid, IID_IDispatch)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_ISupportErrorInfo)) { *ppv = (ISupportErrorInfo FAR *)this; } else if (IsEqualIID(iid, IID_IADs)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_IADsClass)) { *ppv = (IADsClass FAR *) this; } else if( (_pDispatch != NULL) && IsEqualIID(iid, IID_IADsExtension) ) { *ppv = (IADsExtension *) this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return NOERROR; } /* ISupportErrorInfo method */ STDMETHODIMP CWinNTClass::InterfaceSupportsErrorInfo( THIS_ REFIID riid ) { if (IsEqualIID(riid, IID_IADs) || IsEqualIID(riid, IID_IADsClass)) { RRETURN(S_OK); } else { RRETURN(S_FALSE); } } /* IADs methods */ STDMETHODIMP CWinNTClass::SetInfo(THIS) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } STDMETHODIMP CWinNTClass::GetInfo(THIS) { RRETURN(S_OK); } STDMETHODIMP CWinNTClass::ImplicitGetInfo(THIS) { RRETURN(S_OK); } /* IADsClass methods */ STDMETHODIMP CWinNTClass::get_PrimaryInterface( THIS_ BSTR FAR *pbstrGUID ) { HRESULT hr; if ( !pbstrGUID ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); hr = ADsAllocString( _bstrPrimaryInterface, pbstrGUID ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTClass::get_CLSID( THIS_ BSTR FAR *pbstrCLSID ) { HRESULT hr; if ( !pbstrCLSID ) RRETURN(E_ADS_BAD_PARAMETER); hr = ADsAllocString( _bstrCLSID, pbstrCLSID ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTClass::put_CLSID( THIS_ BSTR bstrCLSID ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_OID( THIS_ BSTR FAR *pbstrOID ) { HRESULT hr; if ( !pbstrOID ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); hr = ADsAllocString( _bstrOID, pbstrOID ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTClass::put_OID( THIS_ BSTR bstrOID ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_Abstract( THIS_ VARIANT_BOOL FAR *pfAbstract ) { if ( !pfAbstract ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); *pfAbstract = _fAbstract? VARIANT_TRUE : VARIANT_FALSE; RRETURN(S_OK); } STDMETHODIMP CWinNTClass::put_Abstract( THIS_ VARIANT_BOOL fAbstract ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_Auxiliary( THIS_ VARIANT_BOOL FAR *pfAuxiliary) { if ( !pfAuxiliary ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); *pfAuxiliary = VARIANT_FALSE; RRETURN(S_OK); } STDMETHODIMP CWinNTClass::put_Auxiliary( THIS_ VARIANT_BOOL fAuxiliary ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_MandatoryProperties( THIS_ VARIANT FAR *pvMandatoryProperties ) { HRESULT hr; VariantInit( pvMandatoryProperties ); hr = VariantCopy( pvMandatoryProperties, &_vMandatoryProperties ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTClass::put_MandatoryProperties( THIS_ VARIANT vMandatoryProperties ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_DerivedFrom( THIS_ VARIANT FAR *pvDerivedFrom ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::put_DerivedFrom( THIS_ VARIANT vDerivedFrom ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_AuxDerivedFrom( THIS_ VARIANT FAR *pvAuxDerivedFrom ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::put_AuxDerivedFrom( THIS_ VARIANT vAuxDerivedFrom ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_PossibleSuperiors( THIS_ VARIANT FAR *pvPossSuperiors ) { HRESULT hr; VariantInit( pvPossSuperiors ); hr = VariantCopy( pvPossSuperiors, &_vPossSuperiors ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTClass::put_PossibleSuperiors( THIS_ VARIANT vPossSuperiors ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_Containment( THIS_ VARIANT FAR *pvContainment ) { HRESULT hr; VariantInit( pvContainment ); hr = VariantCopy( pvContainment, &_vContainment ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTClass::put_Containment( THIS_ VARIANT vContainment ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_Container( THIS_ VARIANT_BOOL FAR *pfContainer ) { if ( !pfContainer ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); *pfContainer = _fContainer? VARIANT_TRUE : VARIANT_FALSE; RRETURN(S_OK); } STDMETHODIMP CWinNTClass::put_Container( THIS_ VARIANT_BOOL fContainer ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_HelpFileName( THIS_ BSTR FAR *pbstrHelpFileName ) { HRESULT hr; if ( !pbstrHelpFileName ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); hr = ADsAllocString( _bstrHelpFileName, pbstrHelpFileName ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTClass::put_HelpFileName( THIS_ BSTR bstrHelpFile ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::get_HelpFileContext( THIS_ long FAR *plHelpContext ) { if ( !plHelpContext ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); *plHelpContext = _lHelpFileContext; RRETURN(S_OK); } STDMETHODIMP CWinNTClass::put_HelpFileContext( THIS_ long lHelpContext ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTClass::Qualifiers(THIS_ IADsCollection FAR* FAR* ppQualifiers) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } HRESULT CWinNTClass::AllocateClassObject(CWinNTClass FAR * FAR * ppClass) { CWinNTClass FAR *pClass = NULL; CAggregatorDispMgr FAR *pDispMgr = NULL; HRESULT hr = S_OK; pClass = new CWinNTClass(); if ( pClass == NULL ) hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); pDispMgr = new CAggregatorDispMgr; if ( pDispMgr == NULL ) hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry( pDispMgr, LIBID_ADs, IID_IADs, (IADs *) pClass, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry( pDispMgr, LIBID_ADs, IID_IADsClass, (IADsClass *) pClass, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); pClass->_pDispMgr = pDispMgr; *ppClass = pClass; RRETURN(hr); error: delete pDispMgr; delete pClass; RRETURN(hr); } /******************************************************************/ /* Class CWinNTProperty /******************************************************************/ DEFINE_IDispatch_Delegating_Implementation(CWinNTProperty) DEFINE_IADsExtension_Implementation(CWinNTProperty) DEFINE_IADs_Implementation(CWinNTProperty) CWinNTProperty::CWinNTProperty() : _pDispMgr( NULL ), _bstrOID( NULL ), _bstrSyntax( NULL ), _lMaxRange( 0 ), _lMinRange( 0 ), _fMultiValued( FALSE ) { ENLIST_TRACKING(CWinNTProperty); } CWinNTProperty::~CWinNTProperty() { if ( _bstrOID ) { ADsFreeString( _bstrOID ); } if ( _bstrSyntax ) { ADsFreeString( _bstrSyntax ); } delete _pDispMgr; } HRESULT CWinNTProperty::CreateProperty( BSTR bstrParent, PROPERTYINFO *pPropertyInfo, DWORD dwObjectState, REFIID riid, CWinNTCredentials& Credentials, void **ppvObj ) { CWinNTProperty FAR * pProperty = NULL; HRESULT hr = S_OK; hr = AllocatePropertyObject( &pProperty ); BAIL_ON_FAILURE(hr); hr = ADsAllocString( pPropertyInfo->bstrOID, &pProperty->_bstrOID); BAIL_ON_FAILURE(hr); hr = ADsAllocString( pPropertyInfo->bstrSyntax, &pProperty->_bstrSyntax); BAIL_ON_FAILURE(hr); pProperty->_lMaxRange = pPropertyInfo->lMaxRange; pProperty->_lMinRange = pPropertyInfo->lMinRange; pProperty->_fMultiValued = (VARIANT_BOOL)pPropertyInfo->fMultiValued; hr = pProperty->InitializeCoreObject( bstrParent, pPropertyInfo->szPropertyName, PROPERTY_CLASS_NAME, NO_SCHEMA, CLSID_WinNTProperty, dwObjectState ); BAIL_ON_FAILURE(hr); pProperty->_Credentials = Credentials; // check if the call is from UMI if(Credentials.GetFlags() & ADS_AUTH_RESERVED) { // // we do not pass riid to InitUmiObject below. This is because UMI object // does not support IDispatch. There are several places in ADSI code where // riid passed into this function is defaulted to IID_IDispatch - // IADsContainer::Create for example. To handle these cases, we always // request IID_IUnknown from the UMI object. Subsequent code within UMI // will QI for the appropriate interface. // if(3 == pProperty->_dwNumComponents) { pProperty->_CompClasses[0] = L"Computer"; pProperty->_CompClasses[1] = L"Schema"; pProperty->_CompClasses[2] = L"Property"; } else BAIL_ON_FAILURE(hr = UMI_E_FAIL); hr = pProperty->InitUmiObject( pProperty->_Credentials, PropertyClass, g_dwPropertyClassTableSize, NULL, (IUnknown *)(INonDelegatingUnknown *) pProperty, NULL, IID_IUnknown, ppvObj ); BAIL_ON_FAILURE(hr); // // UMI object was created and the interface was obtained successfully. // UMI object now has a reference to the inner unknown of IADs, since // the call to Release() below is not going to be made in this case. // RRETURN(hr); } hr = pProperty->QueryInterface( riid, ppvObj ); BAIL_ON_FAILURE(hr); pProperty->Release(); RRETURN(hr); error: delete pProperty; RRETURN_EXP_IF_ERR(hr); } // called by implicit GetInfo from property cache STDMETHODIMP CWinNTProperty::GetInfo( THIS_ DWORD dwApiLevel, BOOL fExplicit ) { RRETURN(S_OK); } //---------------------------------------------------------------------------- // Function: QueryInterface // // Synopsis: If this object is aggregated within another object, then // all calls will delegate to the outer object. Otherwise, the // non-delegating QI is called // // Arguments: // // iid interface requested // ppInterface Returns pointer to interface requested. NULL if interface // is not supported. // // Returns: S_OK on success. Error code otherwise. // // Modifies: *ppInterface to return interface pointer // //---------------------------------------------------------------------------- STDMETHODIMP CWinNTProperty::QueryInterface( REFIID iid, LPVOID *ppInterface ) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->QueryInterface( iid, ppInterface )); RRETURN(NonDelegatingQueryInterface( iid, ppInterface )); } //---------------------------------------------------------------------------- // Function: AddRef // // Synopsis: IUnknown::AddRef. If this object is aggregated within // another, all calls will delegate to the outer object. // Otherwise, the non-delegating AddRef is called // // Arguments: // // None // // Returns: New reference count // // Modifies: Nothing // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CWinNTProperty::AddRef(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->AddRef()); RRETURN(NonDelegatingAddRef()); } //---------------------------------------------------------------------------- // Function: Release // // Synopsis: IUnknown::Release. If this object is aggregated within // another, all calls will delegate to the outer object. // Otherwise, the non-delegating Release is called // // Arguments: // // None // // Returns: New reference count // // Modifies: Nothing // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CWinNTProperty::Release(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->Release()); RRETURN(NonDelegatingRelease()); } //---------------------------------------------------------------------------- STDMETHODIMP CWinNTProperty::NonDelegatingQueryInterface(REFIID iid, LPVOID FAR* ppv) { if (ppv == NULL) { RRETURN(E_POINTER); } if (IsEqualIID(iid, IID_IUnknown)) { *ppv = (IADsProperty FAR *) this; } else if (IsEqualIID(iid, IID_IDispatch)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_ISupportErrorInfo)) { *ppv = (ISupportErrorInfo FAR *)this; } else if (IsEqualIID(iid, IID_IADs)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_IADsProperty)) { *ppv = (IADsProperty FAR *) this; } else if( (_pDispatch != NULL) && IsEqualIID(iid, IID_IADsExtension) ) { *ppv = (IADsExtension *) this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return NOERROR; } /* ISupportErrorInfo method */ STDMETHODIMP CWinNTProperty::InterfaceSupportsErrorInfo( THIS_ REFIID riid ) { if (IsEqualIID(riid, IID_IADs) || IsEqualIID(riid, IID_IADsProperty)) { RRETURN(S_OK); } else { RRETURN(S_FALSE); } } /* IADs methods */ STDMETHODIMP CWinNTProperty::SetInfo(THIS) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } STDMETHODIMP CWinNTProperty::GetInfo(THIS) { RRETURN(S_OK); } STDMETHODIMP CWinNTProperty::ImplicitGetInfo(THIS) { RRETURN(S_OK); } /* IADsProperty methods */ STDMETHODIMP CWinNTProperty::get_OID( THIS_ BSTR FAR *pbstrOID ) { HRESULT hr; if ( !pbstrOID ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); hr = ADsAllocString( _bstrOID, pbstrOID ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTProperty::put_OID( THIS_ BSTR bstrOID ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTProperty::get_Syntax( THIS_ BSTR FAR *pbstrSyntax ) { HRESULT hr; if ( !pbstrSyntax ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); hr = ADsAllocString( _bstrSyntax, pbstrSyntax ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTProperty::put_Syntax( THIS_ BSTR bstrSyntax ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTProperty::get_MaxRange( THIS_ long FAR *plMaxRange ) { if ( !plMaxRange ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); *plMaxRange = _lMaxRange; RRETURN(S_OK); } STDMETHODIMP CWinNTProperty::put_MaxRange( THIS_ long lMaxRange ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTProperty::get_MinRange( THIS_ long FAR *plMinRange ) { if ( !plMinRange ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); *plMinRange = _lMinRange; RRETURN(S_OK); } STDMETHODIMP CWinNTProperty::put_MinRange( THIS_ long lMinRange ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTProperty::get_MultiValued( THIS_ VARIANT_BOOL FAR *pfMultiValued ) { if ( !pfMultiValued ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); *pfMultiValued = _fMultiValued? VARIANT_TRUE : VARIANT_FALSE; RRETURN(S_OK); } STDMETHODIMP CWinNTProperty::put_MultiValued( THIS_ VARIANT_BOOL fMultiValued ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTProperty::Qualifiers(THIS_ IADsCollection FAR* FAR* ppQualifiers) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } HRESULT CWinNTProperty::AllocatePropertyObject(CWinNTProperty FAR * FAR * ppProperty) { CWinNTProperty FAR *pProperty = NULL; CAggregatorDispMgr FAR *pDispMgr = NULL; HRESULT hr = S_OK; pProperty = new CWinNTProperty(); if ( pProperty == NULL ) hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); pDispMgr = new CAggregatorDispMgr; if ( pDispMgr == NULL ) hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry( pDispMgr, LIBID_ADs, IID_IADs, (IADs *) pProperty, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry( pDispMgr, LIBID_ADs, IID_IADsProperty, (IADsProperty *) pProperty, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); pProperty->_pDispMgr = pDispMgr; *ppProperty = pProperty; RRETURN(hr); error: delete pDispMgr; delete pProperty; RRETURN(hr); } /******************************************************************/ /* Class CWinNTSyntax /******************************************************************/ DEFINE_IDispatch_Delegating_Implementation(CWinNTSyntax) DEFINE_IADsExtension_Implementation(CWinNTSyntax) DEFINE_IADs_Implementation(CWinNTSyntax) CWinNTSyntax::CWinNTSyntax() { ENLIST_TRACKING(CWinNTSyntax); } CWinNTSyntax::~CWinNTSyntax() { delete _pDispMgr; } HRESULT CWinNTSyntax::CreateSyntax( BSTR bstrParent, SYNTAXINFO *pSyntaxInfo, DWORD dwObjectState, REFIID riid, CWinNTCredentials& Credentials, void **ppvObj ) { CWinNTSyntax FAR *pSyntax = NULL; HRESULT hr = S_OK; hr = AllocateSyntaxObject( &pSyntax ); BAIL_ON_FAILURE(hr); hr = pSyntax->InitializeCoreObject( bstrParent, pSyntaxInfo->bstrName, SYNTAX_CLASS_NAME, NO_SCHEMA, CLSID_WinNTSyntax, dwObjectState ); BAIL_ON_FAILURE(hr); pSyntax->_lOleAutoDataType = pSyntaxInfo->lOleAutoDataType; pSyntax->_Credentials = Credentials; // check if the call is from UMI if(Credentials.GetFlags() & ADS_AUTH_RESERVED) { // // we do not pass riid to InitUmiObject below. This is because UMI object // does not support IDispatch. There are several places in ADSI code where // riid passed into this function is defaulted to IID_IDispatch - // IADsContainer::Create for example. To handle these cases, we always // request IID_IUnknown from the UMI object. Subsequent code within UMI // will QI for the appropriate interface. // if(3 == pSyntax->_dwNumComponents) { pSyntax->_CompClasses[0] = L"Computer"; pSyntax->_CompClasses[1] = L"Schema"; pSyntax->_CompClasses[2] = L"Syntax"; } else BAIL_ON_FAILURE(hr = UMI_E_FAIL); hr = pSyntax->InitUmiObject( pSyntax->_Credentials, SyntaxClass, g_dwSyntaxTableSize, NULL, (IUnknown *)(INonDelegatingUnknown *) pSyntax, NULL, IID_IUnknown, ppvObj ); BAIL_ON_FAILURE(hr); // // UMI object was created and the interface was obtained successfully. // UMI object now has a reference to the inner unknown of IADs, since // the call to Release() below is not going to be made in this case. // RRETURN(hr); } hr = pSyntax->QueryInterface( riid, ppvObj ); BAIL_ON_FAILURE(hr); pSyntax->Release(); RRETURN(hr); error: delete pSyntax; RRETURN_EXP_IF_ERR(hr); } // called by implicit GetInfo from property cache STDMETHODIMP CWinNTSyntax::GetInfo( THIS_ DWORD dwApiLevel, BOOL fExplicit ) { RRETURN(S_OK); } //---------------------------------------------------------------------------- // Function: QueryInterface // // Synopsis: If this object is aggregated within another object, then // all calls will delegate to the outer object. Otherwise, the // non-delegating QI is called // // Arguments: // // iid interface requested // ppInterface Returns pointer to interface requested. NULL if interface // is not supported. // // Returns: S_OK on success. Error code otherwise. // // Modifies: *ppInterface to return interface pointer // //---------------------------------------------------------------------------- STDMETHODIMP CWinNTSyntax::QueryInterface( REFIID iid, LPVOID *ppInterface ) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->QueryInterface( iid, ppInterface )); RRETURN(NonDelegatingQueryInterface( iid, ppInterface )); } //---------------------------------------------------------------------------- // Function: AddRef // // Synopsis: IUnknown::AddRef. If this object is aggregated within // another, all calls will delegate to the outer object. // Otherwise, the non-delegating AddRef is called // // Arguments: // // None // // Returns: New reference count // // Modifies: Nothing // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CWinNTSyntax::AddRef(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->AddRef()); RRETURN(NonDelegatingAddRef()); } //---------------------------------------------------------------------------- // Function: Release // // Synopsis: IUnknown::Release. If this object is aggregated within // another, all calls will delegate to the outer object. // Otherwise, the non-delegating Release is called // // Arguments: // // None // // Returns: New reference count // // Modifies: Nothing // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CWinNTSyntax::Release(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->Release()); RRETURN(NonDelegatingRelease()); } //---------------------------------------------------------------------------- STDMETHODIMP CWinNTSyntax::NonDelegatingQueryInterface(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_IDispatch)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_ISupportErrorInfo)) { *ppv = (ISupportErrorInfo FAR *) this; } else if (IsEqualIID(iid, IID_IADs)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_IADsSyntax)) { *ppv = (IADsSyntax FAR *) this; } else if( (_pDispatch != NULL) && IsEqualIID(iid, IID_IADsExtension) ) { *ppv = (IADsExtension *) this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return NOERROR; } /* ISupportErrorInfo method */ STDMETHODIMP CWinNTSyntax::InterfaceSupportsErrorInfo( THIS_ REFIID riid ) { if (IsEqualIID(riid, IID_IADs) || IsEqualIID(riid, IID_IADsSyntax)) { RRETURN(S_OK); } else { RRETURN(S_FALSE); } } /* IADs methods */ STDMETHODIMP CWinNTSyntax::SetInfo(THIS) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } STDMETHODIMP CWinNTSyntax::GetInfo(THIS) { RRETURN(S_OK); } STDMETHODIMP CWinNTSyntax::ImplicitGetInfo(THIS) { RRETURN(S_OK); } HRESULT CWinNTSyntax::AllocateSyntaxObject(CWinNTSyntax FAR * FAR * ppSyntax) { CWinNTSyntax FAR *pSyntax = NULL; CAggregatorDispMgr FAR *pDispMgr = NULL; HRESULT hr = S_OK; pSyntax = new CWinNTSyntax(); if ( pSyntax == NULL ) hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); pDispMgr = new CAggregatorDispMgr; if ( pDispMgr == NULL ) hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry( pDispMgr, LIBID_ADs, IID_IADsSyntax, (IADsSyntax *) pSyntax, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); pSyntax->_pDispMgr = pDispMgr; *ppSyntax = pSyntax; RRETURN(hr); error: delete pDispMgr; delete pSyntax; RRETURN(hr); } STDMETHODIMP CWinNTSyntax::get_OleAutoDataType( THIS_ long FAR *plOleAutoDataType ) { if ( !plOleAutoDataType ) RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); *plOleAutoDataType = _lOleAutoDataType; RRETURN(S_OK); } STDMETHODIMP CWinNTSyntax::put_OleAutoDataType( THIS_ long lOleAutoDataType ) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } /******************************************************************/ /* Misc Helpers /******************************************************************/ HRESULT MakeVariantFromStringList( BSTR bstrList, VARIANT *pvVariant ) { HRESULT hr = S_OK; SAFEARRAY *aList = NULL; SAFEARRAYBOUND aBound; BSTR pszTempList = NULL; if ( bstrList != NULL ) { long i = 0; long nCount = 1; TCHAR c; BSTR pszSrc; hr = ADsAllocString( bstrList, &pszTempList ); BAIL_ON_FAILURE(hr); while ( c = pszTempList[i] ) { if ( c == TEXT(',')) { pszTempList[i] = 0; nCount++; } i++; } aBound.lLbound = 0; aBound.cElements = nCount; aList = SafeArrayCreate( VT_VARIANT, 1, &aBound ); if ( aList == NULL ) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } pszSrc = pszTempList; for ( i = 0; i < nCount; i++ ) { VARIANT v; VariantInit(&v); V_VT(&v) = VT_BSTR; hr = ADsAllocString( pszSrc, &(V_BSTR(&v))); BAIL_ON_FAILURE(hr); hr = SafeArrayPutElement( aList, &i, &v ); VariantClear(&v); BAIL_ON_FAILURE(hr); pszSrc += _tcslen( pszSrc ) + 1; } VariantInit( pvVariant ); V_VT(pvVariant) = VT_ARRAY | VT_VARIANT; V_ARRAY(pvVariant) = aList; ADsFreeString( pszTempList ); pszTempList = NULL; } else { aBound.lLbound = 0; aBound.cElements = 0; aList = SafeArrayCreate( VT_VARIANT, 1, &aBound ); if ( aList == NULL ) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } VariantInit( pvVariant ); V_VT(pvVariant) = VT_ARRAY | VT_VARIANT; V_ARRAY(pvVariant) = aList; } RRETURN(S_OK); error: if ( pszTempList ) ADsFreeString( pszTempList ); if ( aList ) SafeArrayDestroy( aList ); return hr; } STDMETHODIMP CWinNTClass::get_OptionalProperties( THIS_ VARIANT FAR *retval ) { HRESULT hr; VariantInit( retval ); hr = VariantCopy( retval, &_vOptionalProperties ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTClass::put_OptionalProperties( THIS_ VARIANT vOptionalProperties ) { HRESULT hr = E_NOTIMPL; RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTClass::get_NamingProperties( THIS_ VARIANT FAR *retval ) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } STDMETHODIMP CWinNTClass::put_NamingProperties( THIS_ VARIANT vNamingProperties ) { RRETURN_EXP_IF_ERR(E_NOTIMPL); }