/* File sdowrap.cpp Implements a wrapper for the sdo server class based on weijiang's rasuser.dll code. Paul Mayfield, 6/8/98 */ #include #include #include #include #include #include "sdoias.h" #include "sdolib.h" #include "sdowrap.h" #include "hashtab.h" // // Structure defines data returned as a profile // typedef struct _SDO_PROFILE { ISdo * pSdo; // sdo of profile ISdoCollection * pCollection; // attributes ISdoDictionaryOld * pDictionary; // associated dictionary ISdoServiceControl * pServiceControl; // associated ias service HANDLE hMap; // attribute map } SDO_PROFILE; // // Structure maps sdo object to an id // typedef struct _SDO_TO_ID { ISdo * pSdo; ULONG ulId; } SDO_TO_ID; // // Size of hash tables we'll use // #define SDO_HASH_SIZE 13 // // External function prototypes // extern "C" { DWORD SdoTraceEx (DWORD dwErr, LPSTR pszTrace, ...); PVOID SdoAlloc ( IN DWORD dwSize, IN BOOL bZero); VOID SdoFree ( IN PVOID pvData); } HRESULT SdoCollectionGetNext( IEnumVARIANT* pEnum, ISdo** ppSdo); ULONG SdoHashId ( IN HANDLE hId); int SdoCompIds ( IN HANDLE hId, IN HANDLE hSdoNode); VOID SdoCleanupElement ( IN HANDLE hSdoNode); DWORD SdoCreateIdMap( IN ISdoCollection * pCollection, OUT PHANDLE phMap); HRESULT SdoProfileSetAttribute( IN SDO_PROFILE* pProf, IN VARIANT* pVar, IN ULONG ulId); // // Strings // static const WCHAR pszIasService[] = L"IAS"; static const WCHAR pszRemoteAccessService[] = L"RemoteAccess"; // // Macros // #define SDO_RELEASE(_x) {if (_x) ((_x)->Release());} // // Define a class to act as a wrapper for sdo // server functionality. // class SdoMachine { public: // Construction/destruction // SdoMachine(); SdoMachine(BOOL bLocal); ~SdoMachine(); // Server connection // HRESULT Attach( BSTR pszMachine); // Get the machine sdo // ISdoMachine * GetMachine(); // Get the dictionary sdo // ISdoDictionaryOld * GetDictionary(); // Returns the ias service object IUnknown * GetIasService(); IUnknown * GetRemoteAccessService(); // Obtain user objects HRESULT GetUserSdo( BSTR bstrUserName, ISdo** ppUserSdo); // Obtain profiles HRESULT GetDefaultProfile( ISdo ** ppProfileSdo); protected: // Returns the datastore that should be // used for this machine IASDATASTORE GetDataStore(); // Protected data ISdoMachine * m_pMachine; BOOL m_bDataStoreInitailzed; BOOL m_bLocal; IASDATASTORE m_IasDataStore; }; // // Construct a server // SdoMachine::SdoMachine() { m_pMachine = NULL; m_bDataStoreInitailzed = FALSE; m_bLocal = TRUE; m_IasDataStore = DATA_STORE_LOCAL; } // // Construct a server // SdoMachine::SdoMachine(BOOL bLocal) { m_pMachine = NULL; m_bDataStoreInitailzed = FALSE; m_bLocal = bLocal; m_IasDataStore = (bLocal) ? DATA_STORE_LOCAL : DATA_STORE_DIRECTORY; } // // Cleanup a server // SdoMachine::~SdoMachine() { if (m_pMachine) m_pMachine->Release(); } // // Attach to an SdoServer // HRESULT SdoMachine::Attach( IN BSTR pszMachine) { HRESULT hr = S_OK; VARIANT var; VariantInit(&var); do { // CoCreate the instance hr = CoCreateInstance( CLSID_SdoMachine, NULL, CLSCTX_INPROC_SERVER, IID_ISdoMachine, (void**)&m_pMachine); if (FAILED (hr)) { SdoTraceEx(0, "CoCreateInstance SdoMachine failed %x\n", hr); break; } // Connect hr = m_pMachine->Attach(pszMachine); if (FAILED (hr)) { SdoTraceEx(0, "SdoMachine::Attach failed %x\n", hr); break; } } while (FALSE); // Cleanup { VariantClear(&var); if ((FAILED(hr)) && (m_pMachine != NULL)) { m_pMachine->Release(); m_pMachine = NULL; } } return hr; } // // Returns the machine sdo for this machine // ISdoMachine* SdoMachine::GetMachine() { return m_pMachine; } // // Returns dictionary associated with this machine // ISdoDictionaryOld * SdoMachine::GetDictionary() { ISdoDictionaryOld * pRet = NULL; IUnknown * pUnk = NULL; HRESULT hr; do { hr = m_pMachine->GetDictionarySDO(&pUnk); if (FAILED (hr)) { SetLastError(hr); break; } hr = pUnk->QueryInterface(IID_ISdoDictionaryOld, (VOID**)&pRet); if (FAILED (hr)) { SetLastError(hr); break; } pRet->AddRef(); } while (FALSE); // Cleanup { SDO_RELEASE(pUnk); SDO_RELEASE(pRet); } return pRet; } IUnknown * SdoMachine::GetIasService() { IUnknown * pRet = NULL; HRESULT hr = S_OK; BSTR bstrService = SysAllocString(pszIasService); do { if (bstrService == NULL) { break; } hr = m_pMachine->GetServiceSDO( GetDataStore(), bstrService, &pRet); if (FAILED (hr)) { SetLastError(hr); break; } } while (FALSE); // Cleanup { if (FAILED (hr)) { SDO_RELEASE(pRet); } if (bstrService) { SysFreeString(bstrService); } } return pRet; } IUnknown * SdoMachine::GetRemoteAccessService() { IUnknown * pRet = NULL; HRESULT hr = S_OK; BSTR bstrService = SysAllocString(pszRemoteAccessService); do { if (bstrService == NULL) { break; } hr = m_pMachine->GetServiceSDO( GetDataStore(), bstrService, &pRet); if (FAILED (hr)) { SetLastError(hr); break; } } while (FALSE); // Cleanup { if (FAILED (hr)) { SDO_RELEASE(pRet); } if (bstrService) { SysFreeString(bstrService); } } return pRet; } // // Get a reference to the given user from the // sdo server // HRESULT SdoMachine::GetUserSdo( IN BSTR bstrUserName, OUT ISdo** ppUserSdo) { HRESULT hr = S_OK; IUnknown* pUnkn = NULL; // Validate parameters if(!ppUserSdo) { return E_INVALIDARG; } if (! m_pMachine) { return E_POINTER; } do { // Get the user from the machine hr = m_pMachine->GetUserSDO(GetDataStore(), bstrUserName, &pUnkn); if (FAILED (hr)) { SdoTraceEx (0,"GetUserSdo failed %x\n", hr); break; } // Get the required interface hr = pUnkn->QueryInterface(IID_ISdo, (void**)ppUserSdo); if (FAILED (hr)) { SdoTraceEx (0,"User has no SDO interface %x\n", hr); break; } } while (FALSE); // Cleanup { if (pUnkn) pUnkn->Release(); } return hr; } // // Obtains default profile from the sdo // HRESULT SdoMachine::GetDefaultProfile( ISdo ** ppProfileSdo) { IDispatch* pDisp = NULL; IEnumVARIANT* pEnum = NULL; ISdo * pSdo = NULL; IUnknown * pUnkn = NULL; IUnknown *pUnknEnum = NULL; ISdoCollection * pCollection = NULL; BSTR bstrService = NULL; VARIANT var; HRESULT hr = S_OK; INT iCmp; // Make sure we're ready to go if(! ppProfileSdo) return E_INVALIDARG; if (! m_pMachine) return E_FAIL; VariantInit(&var); do { // Initialize the service name bstrService = SysAllocString(pszIasService); if (bstrService == NULL) { SdoTraceEx (0, "GetProfile: unable to alloc service name\n"); hr = E_OUTOFMEMORY; break; } // Get the service SDO pUnkn = GetRemoteAccessService(); if (pUnkn == NULL) { hr = GetLastError(); break; } // Get an SDO reference to the service object hr = pUnkn->QueryInterface(IID_ISdo, (VOID**)&pSdo); if (FAILED (hr)) { SdoTraceEx (0,"GetProfile: no service sdo %x\n", hr); break; } // Get the profiles collection for the service hr = pSdo->GetProperty( PROPERTY_IAS_PROFILES_COLLECTION, &var); if (FAILED (hr)) { SdoTraceEx (0,"GetProfile: no profiles collection %x\n", hr); break; } // We're done with the service sdo pSdo->Release(); pSdo = NULL; // Get the collection interface to the profiles collection hr = (V_DISPATCH(&var))->QueryInterface( IID_ISdoCollection, (VOID**)&pCollection); if (FAILED (hr)) { SdoTraceEx (0,"GetProfile: collec interface %x\n", hr); break; } // Get an enumerator for the profiles collection hr = pCollection->get__NewEnum(&pUnknEnum); if (FAILED (hr)) { SdoTraceEx (0,"GetProfile: no collec enumerator %x\n", hr); break; } // Get the variant enumerator interface of the profiles collection hr = pUnknEnum->QueryInterface( IID_IEnumVARIANT, (VOID**)&pEnum); // Get the first profile pEnum->Reset(); hr = SdoCollectionGetNext(pEnum, &pSdo); if (hr != S_OK) { SdoTraceEx (0,"GetProfile: no profile %x\n", hr); hr = DISP_E_MEMBERNOTFOUND; break; } // Make sure there is only one profile // { ISdo* pSdo2 = NULL; HRESULT hr2 = S_OK; hr2 = SdoCollectionGetNext(pEnum, &pSdo2); SDO_RELEASE(pSdo2); if (hr2 == S_OK) { SdoTraceEx(0, "GetProfile: multiple found, returning error\n"); hr = DISP_E_MEMBERNOTFOUND; break; } } // Done *ppProfileSdo = pSdo; pSdo = NULL; } while (FALSE); // Cleanup { SDO_RELEASE (pDisp); SDO_RELEASE (pSdo); SDO_RELEASE (pEnum); SDO_RELEASE (pUnkn); SDO_RELEASE (pUnknEnum); SDO_RELEASE (pCollection); VariantClear(&var); if (bstrService) SysFreeString(bstrService); } return hr; } // // Get the data store for this machine // IASDATASTORE SdoMachine::GetDataStore() { VARIANT_BOOL vbDirectory = VARIANT_FALSE; HRESULT hr; if (! m_bDataStoreInitailzed) { do { // Determine whether a local verses directory user should // be loaded. hr = m_pMachine->IsDirectoryAvailable(&vbDirectory); if (FAILED (hr)) { SdoTraceEx (0,"IsDirectoryAvailable failed %x\n", hr); break; } // If the user wants a local user, it's always ok to // attempt to get it. if (m_bLocal) { m_IasDataStore = DATA_STORE_LOCAL; } // Otherwise, a directory user is being requested else { // Directory is available, go to the ds if (vbDirectory == VARIANT_TRUE) { m_IasDataStore = DATA_STORE_DIRECTORY; } // Directory's not available, exit with error else if (vbDirectory == VARIANT_FALSE) { m_IasDataStore = DATA_STORE_LOCAL; SdoTraceEx(0, "GetUserSdo: DS user but no DS %x\n", hr); break; } } } while (FALSE); // Remember that we've already calculated the data store m_bDataStoreInitailzed = TRUE; } return m_IasDataStore; } // // Opens an sdo server and connects to it. // HRESULT WINAPI SdoWrapOpenServer( IN BSTR pszMachine, IN BOOL bLocal, OUT HANDLE* phSdoSrv) { HRESULT hr; if(! phSdoSrv) return E_INVALIDARG; *phSdoSrv = NULL; // Build the machine wrapper for the given // machine SdoMachine* pSdoSrv = new SdoMachine(bLocal); if(! pSdoSrv) return E_OUTOFMEMORY; // Attach the wrapper to the desired macine hr = pSdoSrv->Attach( pszMachine); if(S_OK == hr) *phSdoSrv = (HANDLE)pSdoSrv; else delete pSdoSrv; return hr; } // // Closes out an open sdo server object // HRESULT WINAPI SdoWrapCloseServer( IN HANDLE hSdoSrv) { SdoMachine* pSdoSrv; pSdoSrv = (SdoMachine*)hSdoSrv; if (pSdoSrv) delete pSdoSrv; return S_OK; } // // Get a reference to a user in the sdo object // // returns S_OK, or error message from SDO // HRESULT WINAPI SdoWrapOpenUser( IN HANDLE hSdoSrv, IN BSTR pszUser, OUT HANDLE* phSdoObj) { SdoMachine* pSdoSrv = (SdoMachine*)hSdoSrv; HRESULT hr = S_OK; ISdo* pSdo = NULL; if(!hSdoSrv || !phSdoObj) return E_INVALIDARG; // Get the user object hr = pSdoSrv->GetUserSdo(pszUser, &pSdo); if(! FAILED(hr)) { *phSdoObj = (HANDLE)pSdo; } return hr; } // // Retrieves the default profile object // HRESULT WINAPI SdoWrapOpenDefaultProfile ( IN HANDLE hSdoSrv, OUT PHANDLE phProfile) { SdoMachine* pMachine = (SdoMachine*)hSdoSrv; HRESULT hr = S_OK; ISdo* pSdo = NULL; ISdoCollection * pCollection = NULL; ISdoDictionaryOld * pDictionary = NULL; IUnknown * pUnkn = NULL; ISdoServiceControl * pServiceControl = NULL; HANDLE hMap = NULL; SDO_PROFILE * pProf = NULL; VARIANT var; // Validate parameters if ((pMachine == NULL) || (phProfile == NULL)) { return E_INVALIDARG; } VariantInit(&var); do { // Initialize a structure to hold the profile pProf = (SDO_PROFILE*) SdoAlloc(sizeof(SDO_PROFILE), TRUE); if (pProf == NULL) { hr = ERROR_NOT_ENOUGH_MEMORY; break; } // Get the sdo reference to the default profile // from the server hr = pMachine->GetDefaultProfile(&pSdo); if (FAILED (hr)) { break; } if (pSdo == NULL) { hr = E_FAIL; break; } // Get the collection of attributes hr = pSdo->GetProperty( PROPERTY_PROFILE_ATTRIBUTES_COLLECTION, &var); if (FAILED (hr)) { break; } // Get a reference to the IsdoCollection hr = V_DISPATCH(&var)->QueryInterface( IID_ISdoCollection, (VOID**)&pCollection); if (FAILED (hr)) { break; } // Load the attributes for the profile hr = SdoCreateIdMap(pCollection, &hMap); if (hr != NO_ERROR) { break; } // Get the dictionary for the profile pDictionary = pMachine->GetDictionary(); if (pDictionary == NULL) { hr = GetLastError(); break; } // Get the service for the profile pUnkn = pMachine->GetRemoteAccessService(); if (pUnkn == NULL) { hr = GetLastError(); break; } // If this call fails, pServiceControl // will be silently NULL which is what // we want (it's not required). pUnkn->QueryInterface( IID_ISdoServiceControl, (VOID**)&pServiceControl); // Initialize the sdo control block. pProf->pSdo = pSdo; pProf->pCollection = pCollection; pProf->pDictionary = pDictionary; pProf->pServiceControl = pServiceControl; pProf->hMap = hMap; *phProfile = (HANDLE)pProf; } while (FALSE); // Cleanup { if (FAILED (hr)) { HashTabCleanup(hMap); SDO_RELEASE(pSdo); SDO_RELEASE(pCollection); SDO_RELEASE(pDictionary); SDO_RELEASE(pServiceControl); SdoFree(pProf); } SDO_RELEASE(pUnkn); VariantClear(&var); } return hr; } // // Closes an open sdo object // HRESULT WINAPI SdoWrapClose( IN HANDLE hSdoObj) { ISdo* pSdo = (ISdo*)hSdoObj; if (pSdo) pSdo->Release(); return S_OK; } // // Closes an open sdo profile // HRESULT WINAPI SdoWrapCloseProfile( IN HANDLE hProfile) { SDO_PROFILE* pProf = (SDO_PROFILE*)hProfile; if (pProf) { // Cleanup the hashtab of values if (pProf->hMap) { HashTabCleanup(pProf->hMap); } SDO_RELEASE(pProf->pSdo); SDO_RELEASE(pProf->pCollection); SDO_RELEASE(pProf->pDictionary); SDO_RELEASE(pProf->pServiceControl); SdoFree(pProf); } return S_OK; } // // Commits an sdo object // // bCommitChanges -- TRUE, all changes are saved, // FALSE restore to previous commit // returns S_OK or error message from SDO // HRESULT WINAPI SdoWrapCommit( IN HANDLE hSdoObj, IN BOOL bCommitChanges) { ISdo* pSdo = (ISdo*)hSdoObj; if (! bCommitChanges) return pSdo->Restore(); return pSdo->Apply(); } // // Get's an sdo attribute // // when attribute is absent, // V_VT(pVar) = VT_ERROR; // V_ERROR(pVar) = DISP_E_PARAMNOTFOUND; // // returns S_OK or error message from SDO // HRESULT WINAPI SdoWrapGetAttr( IN HANDLE hSdoObj, IN ULONG ulPropId, OUT VARIANT* pVar) { ISdo* pSdo = (ISdo*)hSdoObj; return pSdo->GetProperty(ulPropId, pVar); } // // Puts an sdo attribute // // returns S_OK or error message from SDO // HRESULT WINAPI SdoWrapPutAttr( IN HANDLE hSdoObj, IN ULONG ulPropId, OUT VARIANT* pVar) { ISdo* pSdo = (ISdo*)hSdoObj; return pSdo->PutProperty(ulPropId, pVar); } // // Remove an attribute // // returns S_OK or error message from SDO // HRESULT WINAPI SdoWrapRemoveAttr( IN HANDLE hSdoObj, IN ULONG ulPropId) { ISdo* pSdo = (ISdo*)hSdoObj; VARIANT var; VariantInit(&var); V_VT(&var) = VT_EMPTY; return pSdo->PutProperty(ulPropId, &var); } // // Reads in the set of profile values that we're interested // in. // HRESULT SdoWrapGetProfileValues( IN HANDLE hProfile, OUT VARIANT* pvarEp, OUT VARIANT* pvarEt, OUT VARIANT* pvarAt) { SDO_TO_ID * pNode = NULL; SDO_PROFILE * pProf = (SDO_PROFILE*)hProfile; // Validate if (pProf == NULL) { return E_INVALIDARG; } // Initialize V_VT(pvarEp) = VT_EMPTY; V_VT(pvarEt) = VT_EMPTY; V_VT(pvarAt) = VT_EMPTY; // Read in the enc policy pNode = NULL; HashTabFind( pProf->hMap, (HANDLE)RAS_ATTRIBUTE_ENCRYPTION_POLICY, (HANDLE*)&pNode); if (pNode) { pNode->pSdo->GetProperty(PROPERTY_ATTRIBUTE_VALUE, pvarEp); } // Read in the enc type pNode = NULL; HashTabFind( pProf->hMap, (HANDLE)RAS_ATTRIBUTE_ENCRYPTION_TYPE, (HANDLE*)&pNode); if (pNode) { pNode->pSdo->GetProperty(PROPERTY_ATTRIBUTE_VALUE, pvarEt); } // Read in the auth type pNode = NULL; HashTabFind( pProf->hMap, (HANDLE)IAS_ATTRIBUTE_NP_AUTHENTICATION_TYPE, (HANDLE*)&pNode); if (pNode) { pNode->pSdo->GetProperty(PROPERTY_ATTRIBUTE_VALUE, pvarAt); } return S_OK; } // // Writes out the set of profile values that we're interested // in. // HRESULT SdoWrapSetProfileValues( IN HANDLE hProfile, IN VARIANT* pvarEp OPTIONAL, IN VARIANT* pvarEt OPTIONAL, IN VARIANT* pvarAt OPTIONAL) { SDO_PROFILE * pProf = (SDO_PROFILE*)hProfile; HRESULT hr = S_OK; // Validate if (pProf == NULL) { return E_INVALIDARG; } do { // Write out the values if (pvarEp) { hr = SdoProfileSetAttribute( pProf, pvarEp, RAS_ATTRIBUTE_ENCRYPTION_POLICY); if (FAILED (hr)) { break; } } if (pvarEt) { hr = SdoProfileSetAttribute( pProf, pvarEt, RAS_ATTRIBUTE_ENCRYPTION_TYPE); if (FAILED (hr)) { break; } } if (pvarAt) { hr = SdoProfileSetAttribute( pProf, pvarAt, IAS_ATTRIBUTE_NP_AUTHENTICATION_TYPE); if (FAILED (hr)) { break; } } // Commit the values hr = pProf->pSdo->Apply(); if (FAILED (hr)) { break; } // Tell the service to restart so it reads in the // new profile values we've set. if (pProf->pServiceControl) { hr = pProf->pServiceControl->ResetService(); SdoTraceEx(0, "ResetService returned: %x!\n", hr); hr = S_OK; //if (FAILED (hr)) //{ // break; //} } else { SdoTraceEx(0, "NO SERVICE CONTROL INTERFACE!\n"); } } while (FALSE); // Cleanup { } return hr; } // // Retrieves the next item from a collection // HRESULT SdoCollectionGetNext( IEnumVARIANT* pEnum, ISdo** ppSdo) { HRESULT hr; DWORD dwRetrieved = 1; VARIANT var; // Get the next value VariantInit(&var); hr = pEnum->Next(1, &var, &dwRetrieved); if ( S_OK == hr ) { hr = V_DISPATCH(&var)->QueryInterface( IID_ISdo, (void**)ppSdo); } VariantClear(&var); return hr; } // // Hash table functions that take advantage of // SDO_TO_ID structures // ULONG SdoHashId (HANDLE hId) { ULONG ulId = PtrToUlong(hId); return (ulId % SDO_HASH_SIZE); } // // Compare two ids // int SdoCompIds (HANDLE hId, HANDLE hSdoNode) { ULONG ulId = PtrToUlong(hId); SDO_TO_ID * pSdoNode = (SDO_TO_ID*)hSdoNode; if (ulId == pSdoNode->ulId) { return 0; } else if (ulId > pSdoNode->ulId) { return 1; } return -1; } // // Cleanup data in the hash table // VOID SdoCleanupElement (HANDLE hSdoNode) { SDO_TO_ID * pSdoNode = (SDO_TO_ID*)hSdoNode; if (pSdoNode) { SDO_RELEASE(pSdoNode->pSdo); delete pSdoNode; } } // // Creates an attribute to id map given a collection // DWORD SdoCreateIdMap( IN ISdoCollection * pCollection, OUT PHANDLE phMap) { HRESULT hr; SDO_TO_ID * pMapNode = NULL; VARIANT var, *pVar = NULL; ULONG ulCount; IUnknown * pUnk = NULL; IEnumVARIANT * pEnum = NULL; DWORD i; do { // Get the count to see if there are any attributes hr = pCollection->get_Count((long*)&ulCount); if (FAILED (hr)) { break; } if (ulCount == 0) { hr = S_OK; break; } // Create the map hr = HashTabCreate( SDO_HASH_SIZE, SdoHashId, SdoCompIds, NULL, NULL, SdoCleanupElement, phMap); if (hr != NO_ERROR) { break; } // Get an attribute enumerator hr = pCollection->get__NewEnum(&pUnk); if (FAILED (hr)) { break; } // Get the enum variant interface for the enumerator hr = pUnk->QueryInterface(IID_IEnumVARIANT, (void**)&pEnum); if (FAILED (hr)) { break; } // Create a buffer large enough to hold the result // of the enumeration. pVar = new VARIANT[ulCount]; if(!pVar) { return E_OUTOFMEMORY; } // Initialize the buffer for(i = 0; i < ulCount; i++) { VariantInit(pVar + i); } // Enumerate hr = pEnum->Reset(); if (FAILED (hr)) { return hr; } hr = pEnum->Next(ulCount, pVar, &ulCount); if (FAILED (hr)) { return hr; } // Fill in the map for(i = 0; i < ulCount; i++) { VariantInit(&var); // Initialize the node in the map pMapNode = new SDO_TO_ID; if (! pMapNode) { hr = E_OUTOFMEMORY; break; } // Get the current attribute hr = V_DISPATCH(pVar + i)->QueryInterface( IID_ISdo, (void**)&(pMapNode->pSdo)); if (FAILED (hr)) { delete pMapNode; continue; } // Get it's id hr = pMapNode->pSdo->GetProperty( PROPERTY_ATTRIBUTE_ID, &var); if (FAILED (hr)) { delete pMapNode; continue; } // Map it pMapNode->ulId = V_I4(&var); HashTabInsert ( *phMap, (HANDLE)UlongToPtr(pMapNode->ulId), (HANDLE)pMapNode); VariantClear(&var); } } while (FALSE); // Cleanup { if (pVar) { for(i = 0; i < ulCount; i++) { VariantClear(pVar + i); } delete[] pVar; } SDO_RELEASE(pUnk); SDO_RELEASE(pEnum); } return hr; } // // Sets a value in an attribute collection, adding it // to the collection as needed. // HRESULT SdoProfileSetAttribute( IN SDO_PROFILE* pProf, IN VARIANT* pVar, IN ULONG ulPropId) { SDO_TO_ID * pNode = NULL; ISdo * pSdo = NULL; IDispatch * pDispatch = NULL; HRESULT hr = S_OK; do { // Search for the given attribute in the // table. pNode = NULL; HashTabFind( pProf->hMap, (HANDLE)UlongToPtr(ulPropId), (HANDLE*)&pNode); // If attribute is found, then we have the sdo interface // we need if (pNode) { pSdo = pNode->pSdo; } // Otherwise, we need to add the value to the collection else { // Create the attribute using the dictionary hr = pProf->pDictionary->CreateAttribute( (ATTRIBUTEID)ulPropId, &pDispatch); if (FAILED (hr)) { break; } // Add to the collection hr = pProf->pCollection->Add(NULL, &pDispatch); if (FAILED (hr)) { break; } // Get the sdo interface hr = pDispatch->QueryInterface(IID_ISdo, (VOID**)&pSdo); if (FAILED(hr)) { break; } // Update the hash table pNode = new SDO_TO_ID; if (!pNode) { hr = E_OUTOFMEMORY; break; } // Add ref so we can track the sdo in the hash table pSdo->AddRef(); pNode->ulId = ulPropId; pNode->pSdo = pSdo; HashTabInsert (pProf->hMap, (HANDLE)UlongToPtr(ulPropId), (HANDLE)pNode); } // Set the attribute pSdo->PutProperty(PROPERTY_ATTRIBUTE_VALUE, pVar); if (FAILED (hr)) { break; } } while (FALSE); // Cleanup { SDO_RELEASE(pDispatch); } return hr; }