/*++ Copyright (c) 2000 Microsoft Corporation Module Name: pusher.cpp Abstract: This file contains the implementation of the CPusher class. This class contains the logic for pushing schema to the repository. Author: Mohit Srivastava 28-Nov-00 Revision History: --*/ #include "iisprov.h" #include "pusher.h" #include "MultiSzData.h" #include "schema.h" extern CDynSchema* g_pDynSch; // Initialized to NULL in schemadynamic.cpp HRESULT CPusher::RepositoryInSync( const CSchemaExtensions* i_pCatalog, bool* io_pbInSync) { DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(io_pbInSync != NULL); DBG_ASSERT(i_pCatalog != NULL); HRESULT hr = WBEM_S_NO_ERROR; CComBSTR sbstrTemp; CComVariant svtTimeStamp; CComPtr spObjIIsComputer; sbstrTemp = WMI_CLASS_DATA::s_Computer.pszClassName; if(sbstrTemp.m_str == NULL) { return WBEM_E_OUT_OF_MEMORY; } hr = m_pNamespace->GetObject(sbstrTemp, 0, m_pCtx, &spObjIIsComputer, NULL); if(FAILED(hr)) { return hr; } // // Try to get timestamp from repository // hr = CUtils::GetQualifiers(spObjIIsComputer, &g_wszCq_SchemaTS, &svtTimeStamp, 1); if(FAILED(hr) || svtTimeStamp.vt != VT_BSTR) { *io_pbInSync = false; return WBEM_S_NO_ERROR; } // // Get timestamp of mbschema.xml // FILETIME FileTime; hr = i_pCatalog->GetMbSchemaTimeStamp(&FileTime); if(FAILED(hr)) { return hr; } // // Finally, compare the timestamps // WCHAR wszFileTime[30]; CUtils::FileTimeToWchar(&FileTime, wszFileTime); if(_wcsicmp(wszFileTime, svtTimeStamp.bstrVal) == 0) { *io_pbInSync = true; } else { *io_pbInSync = false; } return hr; } HRESULT CPusher::SetTimeStamp( const CSchemaExtensions* i_pCatalog) { DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pCatalog != NULL); HRESULT hr = WBEM_S_NO_ERROR; CComBSTR sbstrTemp; CComVariant svtTimeStamp; CComPtr spObjIIsComputer; sbstrTemp = WMI_CLASS_DATA::s_Computer.pszClassName; if(sbstrTemp.m_str == NULL) { return WBEM_E_OUT_OF_MEMORY; } hr = m_pNamespace->GetObject(sbstrTemp, 0, m_pCtx, &spObjIIsComputer, NULL); if(FAILED(hr)) { return hr; } // // Get timestamp of mbschema.xml // FILETIME FileTime; hr = i_pCatalog->GetMbSchemaTimeStamp(&FileTime); if(FAILED(hr)) { return hr; } WCHAR wszFileTime[30]; CUtils::FileTimeToWchar(&FileTime, wszFileTime); // // Finally, Set the timestamp in the repository // svtTimeStamp = wszFileTime; if(svtTimeStamp.vt != VT_BSTR || svtTimeStamp.bstrVal == NULL) { return WBEM_E_OUT_OF_MEMORY; } hr = CUtils::SetQualifiers( spObjIIsComputer, &g_wszCq_SchemaTS, &svtTimeStamp, 1, 0); if(FAILED(hr)) { return hr; } // // Finally, put the class // hr = m_pNamespace->PutClass(spObjIIsComputer, WBEM_FLAG_OWNER_UPDATE, m_pCtx, NULL); if(FAILED(hr)) { return hr; } return hr; } HRESULT CPusher::Initialize(CWbemServices* i_pNamespace, IWbemContext* i_pCtx) /*++ Synopsis: Only call once. Arguments: [i_pNamespace] - [i_pCtx] - Return Value: --*/ { DBG_ASSERT(i_pNamespace != NULL); DBG_ASSERT(i_pCtx != NULL); DBG_ASSERT(m_bInitCalled == false); DBG_ASSERT(m_bInitSuccessful == false); HRESULT hr = WBEM_S_NO_ERROR; CComBSTR bstrTemp; m_bInitCalled = true; m_pCtx = i_pCtx; m_pNamespace = i_pNamespace; m_awszClassQualNames[1] = g_wszCq_Dynamic; m_avtClassQualValues[1] = (bool)true; m_awszClassQualNames[0] = g_wszCq_Provider; m_avtClassQualValues[0] = g_wszCqv_Provider;; if(m_avtClassQualValues[0].bstrVal == NULL) { hr = WBEM_E_OUT_OF_MEMORY; DBGPRINTF((DBG_CONTEXT, "CPusher::Initialize failed, hr=0x%x\n", hr)); goto exit; } // // Get pointers to most commonly used base classes // bstrTemp = g_wszExtElementParent; if(bstrTemp.m_str == NULL) { hr = WBEM_E_OUT_OF_MEMORY; DBGPRINTF((DBG_CONTEXT, "CPusher::Initialize failed, hr=0x%x\n", hr)); goto exit; } hr = m_pNamespace->GetObject(bstrTemp, 0, m_pCtx, &m_spBaseElementObject, NULL); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::Initialize failed, hr=0x%x\n", hr)); goto exit; } bstrTemp = g_wszExtSettingParent; if(bstrTemp.m_str == NULL) { hr = WBEM_E_OUT_OF_MEMORY; DBGPRINTF((DBG_CONTEXT, "CPusher::Initialize failed, hr=0x%x\n", hr)); goto exit; } hr = m_pNamespace->GetObject(bstrTemp, 0, m_pCtx, &m_spBaseSettingObject, NULL); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::Initialize failed, hr=0x%x\n", hr)); goto exit; } bstrTemp = g_wszExtElementSettingAssocParent; if(bstrTemp.m_str == NULL) { hr = WBEM_E_OUT_OF_MEMORY; DBGPRINTF((DBG_CONTEXT, "CPusher::Initialize failed, hr=0x%x\n", hr)); goto exit; } hr = m_pNamespace->GetObject(bstrTemp, 0, m_pCtx, &m_spBaseElementSettingObject, NULL); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::Initialize failed, hr=0x%x\n", hr)); goto exit; } bstrTemp = g_wszExtGroupPartAssocParent; if(bstrTemp.m_str == NULL) { hr = WBEM_E_OUT_OF_MEMORY; DBGPRINTF((DBG_CONTEXT, "CPusher::Initialize failed, hr=0x%x\n", hr)); goto exit; } hr = m_pNamespace->GetObject(bstrTemp, 0, m_pCtx, &m_spBaseGroupPartObject, NULL); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::Initialize failed, hr=0x%x\n", hr)); goto exit; } exit: if(SUCCEEDED(hr)) { m_bInitSuccessful = true; } return hr; } CPusher::~CPusher() { } HRESULT CPusher::Push( const CSchemaExtensions* i_pCatalog, CHashTable* i_phashClasses, CHashTable* i_phashAssocs) { DBG_ASSERT(i_pCatalog != NULL); DBG_ASSERT(i_phashClasses != NULL); DBG_ASSERT(i_phashAssocs != NULL); DBG_ASSERT(m_bInitSuccessful == true); HRESULT hr = WBEM_S_NO_ERROR; bool bInSync= false; hr = RepositoryInSync(i_pCatalog, &bInSync); if(FAILED(hr)) { return hr; } if(!bInSync) { hr = PushClasses(i_phashClasses); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::Push failed, hr=0x%x\n", hr)); return hr; } hr = PushAssocs(i_phashAssocs); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::Push failed, hr=0x%x\n", hr)); return hr; } hr = SetTimeStamp(i_pCatalog); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::Push failed, hr=0x%x\n", hr)); return hr; } } return hr; } HRESULT CPusher::PushClasses( CHashTable* i_phashTable) /*++ Synopsis: Public function to push classes to repository. 1) Precondition: All USER_DEFINED_TO_REPOSITORY classes are not in repository. 2) Pushes all USER_DEFINED_TO_REPOSITORY classes to repository. 3) Deletes and recreates SHIPPED_TO_MOF, SHIPPED_NOT_TO_MOF, and EXTENDED classes if necessary. Arguments: [i_phashTable] - Return Value: --*/ { DBG_ASSERT(i_phashTable != NULL); DBG_ASSERT(m_pNamespace != NULL); DBG_ASSERT(m_bInitSuccessful == true); HRESULT hr = WBEM_S_NO_ERROR; CComPtr spObject = NULL; CComPtr spChildObject = NULL; // // Vars needed for iteration // CHashTable::Record* pRec = NULL; CHashTable::iterator iter; CHashTable::iterator iterEnd; CComVariant v; // // DeleteChildren of extended base classes // LPWSTR awszBaseClasses[] = { g_wszExtElementParent, g_wszExtSettingParent, NULL }; for(ULONG idx = 0; awszBaseClasses[idx] != NULL; idx++) { hr = DeleteChildren(awszBaseClasses[idx]); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushClasses failed, hr=0x%x\n", hr)); goto exit; } } // // Walk thru the hashtable of classes // bool bPutNeeded; iterEnd = i_phashTable->end(); for(iter = i_phashTable->begin(); iter != iterEnd; ++iter) { pRec = iter.Record(); DBG_ASSERT(pRec != NULL); // // Deletes SHIPPED_TO_MOF, SHIPPED_NOT_TO_MOF, EXTENDED classes if necessary. // hr = PrepareForPutClass(pRec->m_data, &bPutNeeded); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushClasses failed, hr=0x%x\n", hr)); goto exit; } if(bPutNeeded) { hr = GetObject(pRec->m_data->pszParentClass, &spObject); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushClasses failed, hr=0x%x\n", hr)); goto exit; } hr = spObject->SpawnDerivedClass(0, &spChildObject); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushClasses failed, hr=0x%x\n", hr)); goto exit; } spObject = NULL; // // Push class qualifiers and special __CLASS property. // hr = SetClassInfo( spChildObject, pRec->m_wszKey, pRec->m_data->dwExtended); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushClasses failed, hr=0x%x\n", hr)); goto exit; } // // Name property and corresponding qualifier // Base class may contain Name. Handle this case // bool bPutNameProperty = true; for(ULONG j = 0; g_awszParentClassWithNamePK[j] != NULL; j++) { // // Deliberate == // if(g_awszParentClassWithNamePK[j] == pRec->m_data->pszParentClass) { bPutNameProperty = false; } } if( bPutNameProperty ) { hr = spChildObject->Put(g_wszProp_Name, 0, NULL, CIM_STRING); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushClasses failed, hr=0x%x\n", hr)); goto exit; } v = (bool)true; hr = CUtils::SetPropertyQualifiers( spChildObject, g_wszProp_Name, // Property name &g_wszPq_Key, // Array of qual names &v, // Array of qual values 1 // Nr of quals ); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushClasses failed, hr=0x%x\n", hr)); goto exit; } } // // All other properties // hr = SetProperties(pRec->m_data, spChildObject); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushClasses failed, hr=0x%x\n", hr)); goto exit; } // // Any methods // hr = SetMethods(pRec->m_data, spChildObject); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushClasses failed, hr=0x%x\n", hr)); goto exit; } // // Finally, put the class // hr = m_pNamespace->PutClass(spChildObject, WBEM_FLAG_OWNER_UPDATE, m_pCtx, NULL); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushClasses failed, hr=0x%x\n", hr)); goto exit; } spChildObject = NULL; } } exit: return hr; } HRESULT CPusher::PushAssocs( CHashTable* i_phashTable) /*++ Synopsis: Public function to push assocs to repository. - Precondition: All USER_DEFINED_TO_REPOSITORY assocs are not in repository. - Pushes all USER_DEFINED_TO_REPOSITORY assocs to repository. Arguments: [i_phashTable] - Return Value: --*/ { DBG_ASSERT(i_phashTable != NULL); DBG_ASSERT(m_pNamespace != NULL); DBG_ASSERT(m_bInitSuccessful == true); HRESULT hr = WBEM_S_NO_ERROR; CComPtr spObject = NULL; CComPtr spChildObject = NULL; // // Vars needed for iteration // CHashTable::Record* pRec = NULL; CHashTable::iterator iter; CHashTable::iterator iterEnd; // // DeleteChildren of extended base classes // LPWSTR awszBaseClasses[] = { g_wszExtElementSettingAssocParent, g_wszExtGroupPartAssocParent, NULL }; for(ULONG idx = 0; awszBaseClasses[idx] != NULL; idx++) { hr = DeleteChildren(awszBaseClasses[idx]); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushAssocs failed, hr=0x%x\n", hr)); goto exit; } } // // Walk thru the hashtable of assocs // for(iter = i_phashTable->begin(), iterEnd = i_phashTable->end(); iter != iterEnd; ++iter) { pRec = iter.Record(); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushAssocs failed, hr=0x%x\n", hr)); goto exit; } if(pRec->m_data->dwExtended == USER_DEFINED_TO_REPOSITORY) { hr = GetObject(pRec->m_data->pszParentClass, &spObject); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushAssocs failed, hr=0x%x\n", hr)); goto exit; } hr = spObject->SpawnDerivedClass(0, &spChildObject); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushAssocs failed, hr=0x%x\n", hr)); goto exit; } spObject = NULL; // // Push class qualifiers and special __CLASS property. // hr = SetClassInfo( spChildObject, pRec->m_wszKey, pRec->m_data->dwExtended); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushAssocs failed, hr=0x%x\n", hr)); goto exit; } // // Push the two ref properties of the association. // hr = SetAssociationComponent( spChildObject, pRec->m_data->pType->pszLeft, pRec->m_data->pcLeft->pszClassName); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushAssocs failed, hr=0x%x\n", hr)); goto exit; } hr = SetAssociationComponent( spChildObject, pRec->m_data->pType->pszRight, pRec->m_data->pcRight->pszClassName); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::PushAssocs failed, hr=0x%x\n", hr)); goto exit; } hr = m_pNamespace->PutClass( spChildObject, WBEM_FLAG_OWNER_UPDATE | WBEM_FLAG_CREATE_ONLY, m_pCtx, NULL); if(FAILED(hr)) { if(hr == WBEM_E_ALREADY_EXISTS) { hr = WBEM_S_NO_ERROR; } else { DBGPRINTF((DBG_CONTEXT, "CPusher::PushAssocs failed, hr=0x%x\n", hr)); goto exit; } } spChildObject = NULL; } } exit: return hr; } HRESULT CPusher::PrepareForPutClass( const WMI_CLASS* i_pClass, bool* io_pbPutNeeded) /*++ Synopsis: Deletes and recreates SHIPPED_TO_MOF, SHIPPED_NOT_TO_MOF, and EXTENDED classes if necessary. Sets io_pbPutNeeded accordingly. Arguments: [i_pClass] - Return Value: --*/ { DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pClass != NULL); DBG_ASSERT(io_pbPutNeeded != NULL); HRESULT hr = WBEM_S_NO_ERROR; CComPtr spObj; CComBSTR bstrClass = i_pClass->pszClassName; if(bstrClass.m_str == NULL) { return WBEM_E_OUT_OF_MEMORY; } bool bExtendedQual = false; bool bPutNeeded = false; HRESULT hrGetObject = m_pNamespace->GetObject( bstrClass, WBEM_FLAG_RETURN_WBEM_COMPLETE, m_pCtx, &spObj, NULL); if( hrGetObject != WBEM_E_INVALID_CLASS && hrGetObject != WBEM_E_NOT_FOUND) { hr = hrGetObject; } if(FAILED(hr)) { return hr; } // // Determine if the [extended] qualifier is set. // if(SUCCEEDED(hrGetObject)) { VARIANT vtExtended; VariantInit(&vtExtended); HRESULT hrGetQuals = CUtils::GetQualifiers(spObj, &g_wszCq_Extended, &vtExtended, 1); if(FAILED(hrGetQuals)) { bExtendedQual = false; } else if(vtExtended.vt == VT_BOOL) { bExtendedQual = vtExtended.boolVal ? true : false; } } // // Pretty much, don't do a Put class if both the catalog and repository // versions are shipped. This is an optimization for the normal case. // switch(i_pClass->dwExtended) { case EXTENDED: if( hrGetObject != WBEM_E_INVALID_CLASS && hrGetObject != WBEM_E_NOT_FOUND) { hr = m_pNamespace->DeleteClass( bstrClass, WBEM_FLAG_OWNER_UPDATE, m_pCtx, NULL); if(FAILED(hr)) { return hr; } } bPutNeeded = true; break; case USER_DEFINED_NOT_TO_REPOSITORY: bPutNeeded = false; break; case USER_DEFINED_TO_REPOSITORY: if( hrGetObject != WBEM_E_INVALID_CLASS && hrGetObject != WBEM_E_NOT_FOUND) { // // There is already a class in the repository with the same name // as this user-defined class. // TODO: Log an error. // bPutNeeded = false; } else { bPutNeeded = true; } break; case SHIPPED_TO_MOF: case SHIPPED_NOT_TO_MOF: if(bExtendedQual) { if( hrGetObject != WBEM_E_INVALID_CLASS && hrGetObject != WBEM_E_NOT_FOUND) { hr = m_pNamespace->DeleteClass( bstrClass, WBEM_FLAG_OWNER_UPDATE, m_pCtx, NULL); if(FAILED(hr)) { return hr; } } bPutNeeded = true; } else { bPutNeeded = (hrGetObject == WBEM_E_INVALID_CLASS || hrGetObject == WBEM_E_NOT_FOUND) ? true : false; } break; default: DBG_ASSERT(false && "Unknown i_pClass->dwExtended"); break; } *io_pbPutNeeded = bPutNeeded; return hr; } HRESULT CPusher::SetClassInfo( IWbemClassObject* i_pObj, LPCWSTR i_wszClassName, ULONG i_iShipped) /*++ Synopsis: Sets class qualifiers and special __CLASS property on i_pObj Arguments: [i_pObj] - The class or association [i_wszClassName] - Will be value of __CLASS property [i_iShipped] - Determines if we set g_wszCq_Extended qualifier Return Value: --*/ { DBG_ASSERT(i_pObj != NULL); DBG_ASSERT(i_wszClassName != NULL); DBG_ASSERT(m_bInitSuccessful == true); HRESULT hr; CComVariant v; // // Class qualifiers (propagated to instance) // hr = CUtils::SetQualifiers( i_pObj, m_awszClassQualNames, m_avtClassQualValues, 2, WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE); if(FAILED(hr)) { goto exit; } // // Another class qualifier (not propagated to instance) // if(i_iShipped == EXTENDED) { v = (bool)true; hr = CUtils::SetQualifiers( i_pObj, &g_wszCq_Extended, &v, 1, 0); if(FAILED(hr)) { goto exit; } } // // Special __CLASS property // v = i_wszClassName; if(v.bstrVal == NULL) { hr = WBEM_E_OUT_OF_MEMORY; goto exit; } hr = i_pObj->Put(g_wszProp_Class, 0, &v, 0); if(FAILED(hr)) { goto exit; } exit: return hr; } HRESULT CPusher::SetMethods( const WMI_CLASS* i_pElement, IWbemClassObject* i_pObject) const /*++ Synopsis: Called by PushClasses. Sets the methods in i_pObject using i_pElement Arguments: [i_pElement] - [i_pObject] - Return Value: --*/ { DBG_ASSERT(i_pElement != NULL); DBG_ASSERT(i_pObject != NULL); DBG_ASSERT(m_bInitSuccessful == true); HRESULT hr = WBEM_S_NO_ERROR; if(i_pElement->ppMethod == NULL) { return WBEM_S_NO_ERROR; } CComPtr spParamsIn; CComPtr spParamsOut; // // Run thru all the methods // WMI_METHOD* pMethCurrent = NULL; for(ULONG i = 0; i_pElement->ppMethod[i] != NULL; i++) { pMethCurrent = i_pElement->ppMethod[i]; spParamsIn = NULL; spParamsOut = NULL; if(pMethCurrent->ppParams != NULL) { WMI_METHOD_PARAM* pParamCur = NULL; // // The index to indicate to WMI the order of the parameters // wszId is the qualifier name. svtId is a variant so we can give to WMI. // static LPCWSTR wszId = L"ID"; static LPCWSTR wszOpt = L"OPTIONAL"; CComVariant svtId = (int)0; CComVariant svtOpt = (bool)true; // // Run thru all the parameters // for(ULONG j = 0; pMethCurrent->ppParams[j] != NULL; j++) { // // This will just hold spParamsIn and spParamsOut so we // don't need to duplicate the code. // IWbemClassObject* apParamInOut[] = { NULL, NULL }; // // Create the WMI instance for the in and/or out params as needed. // pParamCur = pMethCurrent->ppParams[j]; if( pParamCur->iInOut == PARAM_IN || pParamCur->iInOut == PARAM_INOUT ) { if(spParamsIn == NULL) { hr = m_pNamespace->GetObject(L"__Parameters", 0, m_pCtx, &spParamsIn, NULL); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::SetMethods failed, hr=0x%x\n", hr)); goto exit; } } apParamInOut[0] = spParamsIn; } if( pParamCur->iInOut == PARAM_OUT || pParamCur->iInOut == PARAM_INOUT ) { if(spParamsOut == NULL) { hr = m_pNamespace->GetObject(L"__Parameters", 0, m_pCtx, &spParamsOut, NULL); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::SetMethods failed, hr=0x%x\n", hr)); goto exit; } } apParamInOut[1] = spParamsOut; } // // Finally set them. First ins then outs. // for(ULONG k = 0; k < 2; k++) { if(apParamInOut[k] == NULL) { continue; } hr = apParamInOut[k]->Put( pParamCur->pszParamName, 0, NULL, pParamCur->type); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::SetMethods failed, hr=0x%x\n", hr)); goto exit; } hr = CUtils::SetPropertyQualifiers( apParamInOut[k], pParamCur->pszParamName, &wszId, &svtId, 1); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::SetMethods failed, hr=0x%x\n", hr)); goto exit; } } // set Optional qualifier on CreateNewSite param ServerId if (pMethCurrent == &(WMI_METHOD_DATA::s_ServiceCreateNewServer) && pParamCur == &(WMI_METHOD_PARAM_DATA::s_ServerId)) { DBG_ASSERT(apParamInOut[0] != NULL); hr = CUtils::SetPropertyQualifiers( apParamInOut[0], pParamCur->pszParamName, &wszOpt, &svtOpt, 1); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::SetMethods failed, hr=0x%x\n", hr)); goto exit; } } if(apParamInOut[0] || apParamInOut[1]) { svtId.lVal++; } } } // // Special: Return Value // if(pMethCurrent->typeRetVal) { if(spParamsOut == NULL) { hr = m_pNamespace->GetObject(L"__Parameters", 0, m_pCtx, &spParamsOut, NULL); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::SetMethods failed, hr=0x%x\n", hr)); goto exit; } } hr = spParamsOut->Put( L"ReturnValue", 0, NULL, pMethCurrent->typeRetVal); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "%s failed, hr=0x%x\n", __FUNCTION__, hr)); goto exit; } } // // Put the method. // hr = i_pObject->PutMethod( pMethCurrent->pszMethodName, 0, spParamsIn, spParamsOut); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::SetMethods failed, hr=0x%x\n", hr)); goto exit; } // Set the qualifiers on the method LPCWSTR aQuals[2] = { g_wszMq_Implemented, g_wszMq_Bypass_Getobject }; VARIANT vTrue; vTrue.boolVal = VARIANT_TRUE; vTrue.vt = VT_BOOL; VARIANT aVariants[2]; aVariants[0] = vTrue; aVariants[1] = vTrue; hr = CUtils::SetMethodQualifiers( i_pObject, pMethCurrent->pszMethodName, aQuals, aVariants, 2); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::SetMethods failed, hr=0x%x\n", hr)); goto exit; } /*if(pMethCurrent->pszDescription) { VARIANT vDesc; vDesc.bstrVal = pMethCurrent->pszDescription; vDesc.vt = VT_BSTR; hr = CUtils::SetMethodQualifiers( i_pObject, pMethCurrent->pszMethodName, &g_wszMq_Description, &vDesc, 1); if(FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "CPusher::SetMethods failed, hr=0x%x\n", hr)); goto exit; } }*/ } exit: return hr; } HRESULT CPusher::SetProperties( const WMI_CLASS* i_pElement, IWbemClassObject* i_pObject) const /*++ Synopsis: Called by PushClasses. Sets the properties in i_pObject using i_pElement Arguments: [i_pElement] - [i_pObject] - Return Value: --*/ { DBG_ASSERT(i_pElement != NULL); DBG_ASSERT(i_pObject != NULL); DBG_ASSERT(m_bInitSuccessful == true); HRESULT hr = WBEM_S_NO_ERROR; METABASE_PROPERTY* pPropCurrent = NULL; TFormattedMultiSz* pFormattedMultiSz = NULL; CIMTYPE typeProp; CComPtr spQualSet; VARIANT v; VariantInit(&v); if(i_pElement->ppmbp == NULL) { return hr; } for(ULONG i = 0; i_pElement->ppmbp[i] != NULL; i++) { pPropCurrent = i_pElement->ppmbp[i]; pFormattedMultiSz = NULL; switch(pPropCurrent->dwMDDataType) { case DWORD_METADATA: if(pPropCurrent->dwMDMask != 0) { typeProp = CIM_BOOLEAN; } else { typeProp = CIM_SINT32; } break; case STRING_METADATA: case EXPANDSZ_METADATA: typeProp = CIM_STRING; break; case MULTISZ_METADATA: typeProp = VT_ARRAY | CIM_STRING; pFormattedMultiSz = TFormattedMultiSzData::Find(pPropCurrent->dwMDIdentifier); if(pFormattedMultiSz) { typeProp = VT_ARRAY | CIM_OBJECT; } break; case BINARY_METADATA: typeProp = VT_ARRAY | CIM_UINT8; break; default: // // Non fatal if we cannot recognize type // continue; } hr = i_pObject->Put(pPropCurrent->pszPropName, 0, NULL, typeProp); if(FAILED(hr)) { goto exit; } // // qualifiers // hr = i_pObject->GetPropertyQualifierSet(pPropCurrent->pszPropName, &spQualSet); if(FAILED(hr)) { goto exit; } // // qualifier for read-only // V_VT(&v) = VT_BOOL; V_BOOL(&v) = (pPropCurrent->fReadOnly) ? VARIANT_FALSE : VARIANT_TRUE; hr = spQualSet->Put(g_wszPq_Write, &v, 0); if(FAILED(hr)) { goto exit; } V_BOOL(&v) = VARIANT_TRUE; hr = spQualSet->Put(g_wszPq_Read, &v, 0); if(FAILED(hr)) { goto exit; } VariantClear(&v); // // CIMType qualifier // if(pFormattedMultiSz) { DBG_ASSERT(typeProp == (VT_ARRAY | CIM_OBJECT)); CComBSTR sbstrValue = L"object:"; if(sbstrValue.m_str == NULL) { hr = WBEM_E_OUT_OF_MEMORY; goto exit; } sbstrValue += pFormattedMultiSz->wszWmiClassName; if(sbstrValue.m_str == NULL) { hr = WBEM_E_OUT_OF_MEMORY; goto exit; } // // Deliberately not smart variant. We will let sbstrValue do deconstruction. // VARIANT vValue; vValue.vt = VT_BSTR; vValue.bstrVal = sbstrValue; hr = spQualSet->Put(g_wszPq_CimType, &vValue, 0); if(FAILED(hr)) { goto exit; } } spQualSet = NULL; } exit: VariantClear(&v); return hr; } HRESULT CPusher::SetAssociationComponent( IWbemClassObject* i_pObject, LPCWSTR i_wszComp, LPCWSTR i_wszClass) const /*++ Synopsis: Called by PushAssocs Sets a ref property of an association, i_pObj, using i_wszComp and i_wszClass Arguments: [i_pObject] - the association [i_wszComp] - property name (Eg. Group, Part) [i_wszClass] - the class we are "ref"fing to. Return Value: --*/ { DBG_ASSERT(i_pObject != NULL); DBG_ASSERT(i_wszComp != NULL); DBG_ASSERT(i_wszClass != NULL); DBG_ASSERT(m_bInitSuccessful == true); HRESULT hr = WBEM_S_NO_ERROR; CComPtr spQualSet; VARIANT v; VariantInit(&v); // // Store "Ref:[class name]" in a bstr. // ULONG cchClass = wcslen(i_wszClass); CComBSTR sbstrClass(4 + cchClass); if(sbstrClass.m_str == NULL) { hr = WBEM_E_OUT_OF_MEMORY; goto exit; } memcpy(sbstrClass.m_str , L"Ref:", sizeof(WCHAR)*4); memcpy(sbstrClass.m_str + 4, i_wszClass, sizeof(WCHAR)*(cchClass+1)); // // Put the property (Eg. Group, Part, etc.) // hr = i_pObject->Put(i_wszComp, 0, NULL, CIM_REFERENCE); if(FAILED(hr)) { goto exit; } // // Set Qualifiers on the property // hr = i_pObject->GetPropertyQualifierSet(i_wszComp, &spQualSet); if(FAILED(hr)) { goto exit; } V_VT(&v) = VT_BOOL; V_BOOL(&v) = VARIANT_TRUE; hr = spQualSet->Put(g_wszPq_Key, &v, 0); if(FAILED(hr)) { goto exit; } V_VT(&v) = VT_BSTR; V_BSTR(&v) = sbstrClass.m_str; if(V_BSTR(&v) == NULL) { V_VT(&v) = VT_EMPTY; hr = WBEM_E_OUT_OF_MEMORY; goto exit; } hr = spQualSet->Put(g_wszPq_CimType, &v, 0); V_VT(&v) = VT_EMPTY; V_BSTR(&v) = NULL; if(FAILED(hr)) { goto exit; } exit: return hr; } bool CPusher::NeedToDeleteAssoc( IWbemClassObject* i_pObj) const /*++ Synopsis: Sees if the association i_pObj is already in hashtable. If it is, no point in deleting i_pObj from repository only to recreate it later. Arguments: [i_pObj] - An IWbemClassObject representation of an assoc Return Value: true if i_pObj not in hashtable false otherwise --*/ { DBG_ASSERT(i_pObj != NULL); DBG_ASSERT(g_pDynSch != NULL); DBG_ASSERT(m_bInitSuccessful == true); HRESULT hr = WBEM_S_NO_ERROR; bool bMatch = false; CComVariant vt; LPWSTR wsz; CComPtr spQualSet; CHashTable* pHash = g_pDynSch->GetHashAssociations(); WMI_ASSOCIATION* pAssoc; DBG_ASSERT(pHash != NULL); // // Compare the association names // hr = i_pObj->Get(g_wszProp_Class, 0, &vt, NULL, NULL); if(FAILED(hr) || vt.vt != VT_BSTR) { goto exit; } hr = pHash->Wmi_GetByKey(vt.bstrVal, &pAssoc); if(FAILED(hr)) { goto exit; } vt.Clear(); // // This is the only case we care about // if(pAssoc->dwExtended != USER_DEFINED_TO_REPOSITORY) { goto exit; } // // Compare the left association component // hr = i_pObj->GetPropertyQualifierSet( pAssoc->pType->pszLeft, &spQualSet); if(FAILED(hr)) { goto exit; } spQualSet->Get(g_wszPq_CimType, 0, &vt, NULL); spQualSet = NULL; if(FAILED(hr) || vt.vt != VT_BSTR) { goto exit; } if( (wsz = wcschr(vt.bstrVal, L':')) == NULL ) { goto exit; } wsz++; if(_wcsicmp(wsz, pAssoc->pcLeft->pszClassName) != 0) { goto exit; } vt.Clear(); // // Compare the right association component // hr = i_pObj->GetPropertyQualifierSet( pAssoc->pType->pszRight, &spQualSet); if(FAILED(hr)) { goto exit; } spQualSet->Get(g_wszPq_CimType, 0, &vt, NULL); spQualSet = NULL; if(FAILED(hr) || vt.vt != VT_BSTR) { goto exit; } if( (wsz = wcschr(vt.bstrVal, L':')) == NULL ) { goto exit; } wsz++; if(_wcsicmp(wsz, pAssoc->pcRight->pszClassName) != 0) { goto exit; } vt.Clear(); bMatch = true; pAssoc->dwExtended = USER_DEFINED_NOT_TO_REPOSITORY; exit: return !bMatch; } HRESULT CPusher::DeleteChildren(LPCWSTR i_wszExtSuperClass) { DBG_ASSERT(i_wszExtSuperClass != NULL); DBG_ASSERT(m_bInitSuccessful == true); // // Only can be called from inside Initialize // DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); IEnumWbemClassObject*pEnum = NULL; HRESULT hr = WBEM_S_NO_ERROR; IWbemClassObject* apObj[10] = {0}; ULONG nrObj = 0; ULONG i = 0; VARIANT v; VariantInit(&v); CComBSTR bstrExtSuperClass = i_wszExtSuperClass; if(bstrExtSuperClass.m_str == NULL) { hr = WBEM_E_OUT_OF_MEMORY; goto exit; } hr = m_pNamespace->CreateClassEnum( bstrExtSuperClass, WBEM_FLAG_FORWARD_ONLY, m_pCtx, &pEnum); if(FAILED(hr)) { goto exit; } hr = pEnum->Next(WBEM_INFINITE, 10, apObj, &nrObj); while(SUCCEEDED(hr) && nrObj > 0) { for(i = 0; i < nrObj; i++) { bool bDelete; if( i_wszExtSuperClass == g_wszExtElementSettingAssocParent || i_wszExtSuperClass == g_wszExtGroupPartAssocParent) { bDelete = NeedToDeleteAssoc(apObj[i]); } else { bDelete = true; } if(bDelete) { hr = apObj[i]->Get(g_wszProp_Class, 0, &v, NULL, NULL); if(FAILED(hr)) { goto exit; } hr = m_pNamespace->DeleteClass(v.bstrVal, WBEM_FLAG_OWNER_UPDATE, m_pCtx, NULL); if(FAILED(hr)) { goto exit; } VariantClear(&v); } apObj[i]->Release(); apObj[i] = NULL; } hr = pEnum->Next(WBEM_INFINITE, 10, apObj, &nrObj); } if(FAILED(hr)) { goto exit; } exit: if(pEnum) { pEnum->Release(); pEnum = NULL; } VariantClear(&v); for(i = 0; i < 10; i++) { if(apObj[i]) { apObj[i]->Release(); } } return hr; } HRESULT CPusher::GetObject( LPCWSTR i_wszClass, IWbemClassObject** o_ppObj) { DBG_ASSERT(o_ppObj != NULL); DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); HRESULT hr = WBEM_S_NO_ERROR; IWbemClassObject* pObject; if(i_wszClass == g_wszExtElementParent) { *o_ppObj = m_spBaseElementObject; (*o_ppObj)->AddRef(); } else if(i_wszClass == g_wszExtSettingParent) { *o_ppObj = m_spBaseSettingObject; (*o_ppObj)->AddRef(); } else if(i_wszClass == g_wszExtElementSettingAssocParent) { *o_ppObj = m_spBaseElementSettingObject; (*o_ppObj)->AddRef(); } else if(i_wszClass == g_wszExtGroupPartAssocParent) { *o_ppObj = m_spBaseGroupPartObject; (*o_ppObj)->AddRef(); } else { const CComBSTR sbstrClass = i_wszClass; if(sbstrClass.m_str == NULL) { hr = WBEM_E_OUT_OF_MEMORY; goto exit; } hr = m_pNamespace->GetObject(sbstrClass, 0, m_pCtx, &pObject, NULL); if(FAILED(hr)) { goto exit; } *o_ppObj = pObject; } exit: return hr; }