//+---------------------------------------------------------------------------- // // File: ChimeSettings.cpp // // Module: SetChimeSettings.Dll // // Synopsis: Implements the SetChimeSettings and Initialization Task // // Copyright (c) Microsoft Corporation. All rights reserved. // //+---------------------------------------------------------------------------- #include "stdafx.h" #include #include #include #include "SetChimeSettings.h" #include "appliancetask.h" #include "taskctx.h" #include "ChimeSettings.h" #include "appsrvcs.h" #include "..\sasamplemsgdll\sampleresource.h" #include "appliancetask_i.c" #include "appsrvcs_i.c" #include "taskctx_i.c" // // Name and parameters for SetChimeSettings Task // const WCHAR SET_CHIME_SETTINGS_TASK[]=L"SetChimeSettings"; const WCHAR PARAM_CHIME_TYPE[]=L"ChimeType"; const WCHAR PARAM_CHIME_INTERVAL[]=L"ChimeInterval"; // // Alert source information // const WCHAR ALERT_LOG_NAME[]=L"SampleResource.Dll"; const WCHAR ALERT_SOURCE []=L""; // // Registry locations // const WCHAR REGKEY_SA_CHIMESETTINGS[]=L"Software\\Microsoft\\ServerAppliance\\Chime"; const WCHAR REGSTR_VAL_CHIME_RAISEALERT[]=L"RaiseAlert"; const WCHAR REGSTR_VAL_CHIME_TYPE[] =L"ChimeType"; const WCHAR REGSTR_VAL_CHIME_INTERVAL[]=L"ChimeInterval"; // // Name of the Event to signal to notify Chime Service // const WCHAR CHIME_EVENT[]=L"SA_Chime_Change_Event"; // // Various strings used in the program // const WCHAR SZ_METHOD_NAME[]=L"MethodName"; const WCHAR SZ_APPLIANCE_INITIALIZATION_TASK []=L"ApplianceInitializationTask"; //+---------------------------------------------------------------------------- // // Function: CChimeSettings::OnTaskExecute // // Synopsis: This function is the entry point for AppMgr. // // Arguments: pTaskContext - The TaskContext object contains the method name // and parameters as name value pairs // // Returns: HRESULT // //+---------------------------------------------------------------------------- STDMETHODIMP CChimeSettings::OnTaskExecute(IUnknown *pTaskContext) { HRESULT hrRet=E_FAIL; CComPtr pTaskParameters; SET_CHIME_SETTINGS_TASK_TYPE scstChoice; ASSERT(pTaskContext); TRACE(("CChimeSettings::OnTaskExecute")); try { do { if(NULL == pTaskContext) { TRACE("CChimeSettings::OnTaskExecute got NULL pTaskContext"); break; } hrRet = pTaskContext->QueryInterface(IID_ITaskContext, (void **)&pTaskParameters); if(FAILED(hrRet)) { TRACE1("CChimeSettings::OnTaskExecute pTaskContext QI failed for pTaskParameters, %X",hrRet); break; } // Check which Task is being executed and call that method scstChoice = GetMethodName(pTaskParameters); switch (scstChoice) { case SET_CHIME_SETTINGS: hrRet = SetChimeSettings(pTaskParameters); TRACE1(("SetChimeSettings returned %X"), hrRet); break; case RAISE_SET_CHIME_SETTINGS_ALERT: // Alert will be raised on OnTaskComplete hrRet = S_OK; TRACE(("RaiseSetChimeSettingsAlert method called")); break; default: TRACE("GetMethodName() failed to get method name in OnTaskExecute"); hrRet = E_INVALIDARG; break; } } while(false); } catch(...) { TRACE("CChimeSettings::OnTaskExecute caught unknown exception"); hrRet=E_FAIL; } TRACE1("CChimeSettings::OnTaskExecute returning %X", hrRet); return hrRet; } //+---------------------------------------------------------------------------- // // Function: CChimeSettings::OnTaskComplete // // Synopsis: // // Arguments: pTaskContext - The TaskContext object contains the method name // and parameters as name value pairs // // Returns: HRESULT // //+---------------------------------------------------------------------------- STDMETHODIMP CChimeSettings::OnTaskComplete(IUnknown *pTaskContext, LONG lTaskResult) { HRESULT hrRet = E_FAIL; CComPtr pTaskParameters; SET_CHIME_SETTINGS_TASK_TYPE scstChoice; ASSERT(pTaskContext); TRACE(("CChimeSettings::OnTaskComplete")); try { do { if(NULL == pTaskContext) { TRACE("CChimeSettings::OnTaskComplete got NULL pTaskContext"); break; } hrRet = pTaskContext->QueryInterface(IID_ITaskContext, (void **)&pTaskParameters); if (FAILED(hrRet)) { TRACE1("CChimeSettings::OnTaskComplete failed in pTaskContext QI for pTaskParameters, %X", hrRet); break; } // // Check which Task is being executed and call that method // scstChoice = GetMethodName(pTaskParameters); switch (scstChoice) { case SET_CHIME_SETTINGS: if (lTaskResult == SA_TASK_RESULT_COMMIT) { // // Clear any existing SetChimeSettings alert, // do not raise the alert on subsequent boots and // notify the chime service about update to Chime Settings // hrRet = E_FAIL; if ( (TRUE == ClearSetChimeSettingsAlert()) && (TRUE == DoNotRaiseChimeSettingsAlert()) && (TRUE == NotifyChimeService()) ) { TRACE("No rollback in OnTaskComplete"); hrRet = S_OK; } } else { hrRet = RollbackSetChimeSettings(pTaskParameters); TRACE1(("RollbackSetChimeSettings returned %X"), hrRet); } break; case RAISE_SET_CHIME_SETTINGS_ALERT: if (lTaskResult == SA_TASK_RESULT_COMMIT) { if (TRUE == ShouldRaiseChimeSettingsAlert()) { hrRet = RaiseSetChimeSettingsAlert(); if (FAILED(hrRet)) { TRACE1(("RaiseSetChimeSettingsAlert returned %X"), hrRet); } } else { TRACE("No need to raise the ChimeSettings alert"); } } else { // // Do nothing on Commit failure // hrRet = S_OK; } break; default: TRACE("GetMethodName() failed to get method name in OnTaskComplete"); hrRet = E_INVALIDARG; break; } } while(false); } catch(...) { TRACE("CChimeSettings::OnTaskComplete caught unknown exception"); hrRet=E_FAIL; } TRACE1("CChimeSettings::OnTaskComplete returning %X", hrRet); return hrRet; } //+---------------------------------------------------------------------------- // // Function: CChimeSettings::GetMethodName // // Synopsis: // // Arguments: pTaskContext - The TaskContext object contains the method name // and parameters as name value pairs // // Returns: SET_CHIME_SETTINGS_TASK_TYPE // //+---------------------------------------------------------------------------- SET_CHIME_SETTINGS_TASK_TYPE CChimeSettings::GetMethodName(IN ITaskContext *pTaskParameter) { _bstr_t bstrParamName(SZ_METHOD_NAME); HRESULT hrRet; _variant_t varValue; SET_CHIME_SETTINGS_TASK_TYPE scstChoice = NONE_FOUND; ASSERT(pTaskParameter); try { do { hrRet = pTaskParameter->GetParameter(bstrParamName, &varValue); if (FAILED(hrRet)) { TRACE1(("GetParameter failed in CChimeSettings::GetMethodName %X"), hrRet); } if (V_VT(&varValue) != VT_BSTR) { TRACE1(("Non-strint(%X) parameter received in GetParameter in CChimeSettings::GetMethodName"), V_VT(&varValue)); hrRet = E_INVALIDARG; break; } if (lstrcmp(V_BSTR(&varValue), SET_CHIME_SETTINGS_TASK) == 0) { scstChoice = SET_CHIME_SETTINGS; break; } if (lstrcmp(V_BSTR(&varValue), SZ_APPLIANCE_INITIALIZATION_TASK) == 0) { scstChoice = RAISE_SET_CHIME_SETTINGS_ALERT; break; } } while(false); } catch(...) { TRACE("CChimeSettings::GetMethodName caught unknown exception"); hrRet=E_FAIL; } if (FAILED(hrRet)) { scstChoice = NONE_FOUND; } return scstChoice; } //+---------------------------------------------------------------------------- // // Function: CChimeSettings::GetSetChimeSettingsParameters // // Synopsis: Extracts chime settings parameters from task context // // Arguments: pTaskContext - The TaskContext object contains the method name // and parameters as name value pairs // pdwChimeType - ChimeType // pdwChimeInterval - ChimeInterval // // Returns: HRESULT // //+---------------------------------------------------------------------------- STDMETHODIMP CChimeSettings::GetSetChimeSettingsParameters(IN ITaskContext *pTaskContext, OUT DWORD *pdwChimeType, OUT DWORD *pdwChimeInterval) { _bstr_t bstrParamChimeType(PARAM_CHIME_TYPE); _bstr_t bstrParamChimeInterval(PARAM_CHIME_INTERVAL); HRESULT hrRet = S_OK; _variant_t varValue; ASSERT(pTaskContext && pdwChimeType && pdwChimeInterval); // // Retrieve ChimeType from TaskContext // try { do { VariantClear(&varValue); hrRet = pTaskContext->GetParameter(bstrParamChimeType, &varValue); if(FAILED(hrRet)) { TRACE1("CChimeSettings::GetSetChimeSetttingsParameters failed in GetParameters, %X",hrRet); break; } if (V_VT(&varValue) != VT_BSTR) { TRACE2(("Non-String (%X) parameter received for %ws in GetParameter \ in CChimeSettings:GetSetChimeSettingsParameters"), \ V_VT(&varValue), PARAM_CHIME_TYPE); hrRet = E_INVALIDARG; break; } *pdwChimeType = _ttol(V_BSTR(&varValue)); // // Retrieve ChimeInterval from TaskContext // VariantClear(&varValue); hrRet = pTaskContext->GetParameter(bstrParamChimeInterval, &varValue); if(FAILED(hrRet)) { TRACE1("CChimeSettings::GetSetChimeSetttingsParameters failed in GetParameters, %X",hrRet); break; } if (V_VT(&varValue) != VT_BSTR) { TRACE2(("Non-String(%X) parameter received for %ws in GetParameter \ in CChimeSettings::GetSetChimeSettingsParameters"), \ V_VT(&varValue), PARAM_CHIME_INTERVAL); hrRet = E_INVALIDARG; break; } *pdwChimeInterval = _ttol(V_BSTR(&varValue)); TRACE2(("ChimeType = 0x%x, ChimeInterval = %ul"), *pdwChimeType, *pdwChimeInterval); } while(false); } catch(...) { TRACE1("CChimeSettings::GetSetChimeSetttingsParameters exception caught", hrRet); hrRet=E_FAIL; } //VariantClear(&varValue); return hrRet; } //+---------------------------------------------------------------------------- // // Function: CChimeSettings::SetChimeSettings // // Synopsis: Writes chime settings passed in by task context to registry // // Arguments: pTaskContext - The TaskContext object contains the method name // and parameters as name value pairs // // Returns: HRESULT // //+---------------------------------------------------------------------------- STDMETHODIMP CChimeSettings::SetChimeSettings(IN ITaskContext *pTaskContext) { HRESULT hrRet=E_FAIL; DWORD dwChimeType = 0, dwChimeInterval = 0; LONG lResult; DWORD dwDisposition; CRegKey crKey; ASSERT(pTaskContext); try { do { // // Get Chime Type and Interval from the TaskContext object // hrRet = GetSetChimeSettingsParameters(pTaskContext, &dwChimeType, &dwChimeInterval); if (FAILED (hrRet)) { break; } // // Save current values - this will be used to restore the settings // if this task needs to be rolledback // lResult = crKey.Open(HKEY_LOCAL_MACHINE, REGKEY_SA_CHIMESETTINGS, KEY_ALL_ACCESS); if (ERROR_SUCCESS == lResult) { if (ERROR_SUCCESS != crKey.QueryValue(m_dwOldChimeType, REGSTR_VAL_CHIME_TYPE)) { // // Could be due to bad setup - let log it and continue on // TRACE2("QueryValue of %ws failed in SetChimeSettings, %x", REGSTR_VAL_CHIME_TYPE, lResult); } if (ERROR_SUCCESS != crKey.QueryValue(m_dwOldChimeInterval, REGSTR_VAL_CHIME_INTERVAL)) { // // Could be due to bad setup - let log it and continue on // TRACE2("QueryValue of %ws failed in SetChimeSettings, %x", REGSTR_VAL_CHIME_INTERVAL, lResult); } } else { // // If we couldn't open the key, it probably because the key does not // exist. Let's create it // lResult = crKey.Create(HKEY_LOCAL_MACHINE, REGKEY_SA_CHIMESETTINGS, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &dwDisposition); if (ERROR_SUCCESS != lResult) { TRACE1("Create failed in CChimeSettings::SetChimeSettings, %x", lResult); hrRet=HRESULT_FROM_WIN32(lResult); break; } } // // Set the new values // lResult = crKey.SetValue(dwChimeType, REGSTR_VAL_CHIME_TYPE); if (ERROR_SUCCESS != lResult) { TRACE2("SetValue of %ws failed, %x", REGSTR_VAL_CHIME_TYPE, lResult); hrRet=HRESULT_FROM_WIN32(lResult); break; } lResult = crKey.SetValue(dwChimeInterval, REGSTR_VAL_CHIME_INTERVAL); if (ERROR_SUCCESS != lResult) { TRACE2("SetValue of %ws failed, %x", REGSTR_VAL_CHIME_INTERVAL, lResult); hrRet=HRESULT_FROM_WIN32(lResult); break; } hrRet = S_OK; } while(false); } catch(...) { TRACE("CChimeSettings::SetChimeSettings caught unknown exception"); hrRet=E_FAIL; } return hrRet; } //+---------------------------------------------------------------------------- // // Function: CChimeSettings::RoolbackSetChimeSettings // // Synopsis: restore the old chime settings // // Arguments: pTaskContext - The TaskContext object contains the method name // and parameters as name value pairs // // Returns: HRESULT // //+---------------------------------------------------------------------------- STDMETHODIMP CChimeSettings::RollbackSetChimeSettings(IN ITaskContext *pTaskContext) { HRESULT hrRet = S_OK; LONG lResult; CRegKey crKey; ASSERT(pTaskContext); try { do { lResult = crKey.Open(HKEY_LOCAL_MACHINE, REGKEY_SA_CHIMESETTINGS, KEY_WRITE); if (ERROR_SUCCESS != lResult) { TRACE1("CChimeSettings::RollbackSetChimeSettings failed to open Chime regkey, %d",lResult); hrRet=HRESULT_FROM_WIN32(lResult); break; } // // Restore the old values // lResult = crKey.SetValue(m_dwOldChimeType, REGSTR_VAL_CHIME_TYPE); if (ERROR_SUCCESS != lResult) { TRACE2("SetValue of %ws failed, %x", REGSTR_VAL_CHIME_TYPE, lResult); hrRet=HRESULT_FROM_WIN32(lResult); break; } lResult = crKey.SetValue(m_dwOldChimeInterval, REGSTR_VAL_CHIME_INTERVAL); if (ERROR_SUCCESS != lResult) { TRACE2("SetValue of %ws failed, %x", REGSTR_VAL_CHIME_INTERVAL, lResult); hrRet=HRESULT_FROM_WIN32(lResult); break; } } while(false); } catch(...) { TRACE("CChimeSettings::OnTaskComplete caught unknown exception"); hrRet=E_FAIL; } return hrRet; } //+---------------------------------------------------------------------------- // // Function: CChimeSettings::RaiseSetChimeSettingsAlert // // Synopsis: Raises the initial "Chime not set up" alert during appliance initialization // // Arguments: None // // Returns: HRESULT // //+---------------------------------------------------------------------------- STDMETHODIMP CChimeSettings::RaiseSetChimeSettingsAlert(void) { CComPtr pAppSrvcs; DWORD dwAlertType = SA_ALERT_TYPE_ATTENTION; DWORD dwAlertId = SA_SAMPLEAPP_CHIME_NOTSET_ALERT_CAPTION; HRESULT hrRet = E_FAIL; _bstr_t bstrAlertLog(ALERT_LOG_NAME); _bstr_t bstrAlertSource(ALERT_SOURCE); _variant_t varReplacementStrings; _variant_t varRawData; LONG lCookie; TRACE("Entering RaiseSetChimeSettingsAlert"); try { do { hrRet = CoCreateInstance(CLSID_ApplianceServices, NULL, CLSCTX_INPROC_SERVER , IID_IApplianceServices, (void**)&pAppSrvcs); if (FAILED(hrRet)) { ASSERTMSG(FALSE, L"RaiseSetChimeSettingsAlert failed at CoCreateInstance"); TRACE1("RaiseSetChimeSettingsAlert failed at CoCreateInstance, %x", hrRet); break; } ASSERT(pAppSrvcs); // Initialize() is called prior to using other component services. Performs // component initialization operations. hrRet = pAppSrvcs->Initialize(); if (FAILED(hrRet)) { ASSERTMSG(FALSE, L"RaiseSetChimeSettingsAlert failed at pAppSrvcs->Initialize"); TRACE1("RaiseSetChimeSettingsAlert failed at pAppSrvcs->Initialize, %x", hrRet); break; } hrRet = pAppSrvcs->RaiseAlert(dwAlertType, dwAlertId, bstrAlertLog, bstrAlertSource, SA_ALERT_DURATION_ETERNAL, &varReplacementStrings, &varRawData, &lCookie); if (FAILED(hrRet)) { ASSERTMSG(FALSE, TEXT("RaiseSetChimeSettingsAlert failed at pAppSrvcs->RaiseAlert")); TRACE1("RaiseSetChimeSettingsAlert failed at pAppSrvcs->RaiseAlert, %x", hrRet); break; } } while(false); } catch(...) { TRACE("CChimeSettings::RaiseSetChimeSettingsAlert exception caught"); hrRet=E_FAIL; } return hrRet; } //+---------------------------------------------------------------------------- // // Function: CChimeSettings::DoNotRaiseChimeSettingsAlert // // Synopsis: After chime is setup the initial "Chime not set up" alert needs to be disabled. // This function sets the RaiseAlert regkey to 0 to prevent the alert to be raised. // // Arguments: None // // Returns: BOOL // //+---------------------------------------------------------------------------- BOOL CChimeSettings::DoNotRaiseChimeSettingsAlert(void) { LONG lReturnValue; HKEY hKey = NULL; DWORD dwDisposition, dwRaiseChimeSettingsAlert = 0; BOOL bReturnCode = FALSE; TRACE("Entering DoNotRaiseChimeSettingsAlert"); // // Write Settings to registry // do { lReturnValue = RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGKEY_SA_CHIMESETTINGS, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition); if (lReturnValue != ERROR_SUCCESS) { TRACE1("RegCreateKeyEx failed with %X", lReturnValue); break; } // // Set RaiseAlert value to 0 // dwRaiseChimeSettingsAlert = 0; lReturnValue = RegSetValueEx(hKey, REGSTR_VAL_CHIME_RAISEALERT, 0, REG_DWORD, (LPBYTE) &dwRaiseChimeSettingsAlert, sizeof(DWORD)); if (lReturnValue != ERROR_SUCCESS) { TRACE2("RegSetValueEx of %ws failed with %X", REGSTR_VAL_CHIME_RAISEALERT, lReturnValue); break; } else { bReturnCode = TRUE; } } while(false); if (NULL != hKey) { RegCloseKey(hKey); } return bReturnCode; } //+---------------------------------------------------------------------------- // // Function: CChimeSettings::ShouldRaiseChimeSettingsAlert // // Synopsis: Returns TRUE if the alert needs to be raised. Reads RaiseAlert regkey to // determine this. // // Arguments: None // // Returns: BOOL // //+---------------------------------------------------------------------------- BOOL CChimeSettings::ShouldRaiseChimeSettingsAlert(void) { LONG lReturnValue; HKEY hKey = NULL; DWORD dwSize, dwType, dwRaiseChimeSettingsAlert = 0; BOOL bReturnCode = TRUE; TRACE("ShouldRaiseChimeSettingsAlert"); do { // // Open HKLM\Software\Microsoft\ServerAppliance\Chime reg key // lReturnValue = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_SA_CHIMESETTINGS, 0, KEY_READ, &hKey); if (lReturnValue != ERROR_SUCCESS) { TRACE1("RegOpenKeyEx failed with %X", lReturnValue); bReturnCode=FALSE; break; } // // Read the RaiseAlert reg key // dwSize = sizeof(DWORD); lReturnValue = RegQueryValueEx(hKey, REGSTR_VAL_CHIME_RAISEALERT, 0, &dwType, (LPBYTE) &dwRaiseChimeSettingsAlert, &dwSize); if (lReturnValue != ERROR_SUCCESS) { TRACE2("RegQueryValueEx of %ws failed with %X", REGSTR_VAL_CHIME_RAISEALERT, lReturnValue); bReturnCode=FALSE; break; } if (0 == dwRaiseChimeSettingsAlert) { bReturnCode = FALSE; } } while(false); if (NULL != hKey) { RegCloseKey(hKey); } return bReturnCode; } //+---------------------------------------------------------------------------- // // Function: CChimeSettings::ClearSetChimeSettingsAlert // // Synopsis: clears the set chime settings alert // // Arguments: none // // Returns: SET_CHIME_SETTINGS_TASK_TYPE // //+---------------------------------------------------------------------------- BOOL CChimeSettings::ClearSetChimeSettingsAlert(void) { CComPtr pAppSrvcs; HRESULT hrRet = E_FAIL; _bstr_t bstrAlertLog(ALERT_LOG_NAME); BOOL bReturnCode = FALSE; TRACE("ClearSetChimeSettings"); try { do { hrRet = CoCreateInstance(CLSID_ApplianceServices, NULL, CLSCTX_INPROC_SERVER , IID_IApplianceServices, (void**)&pAppSrvcs); if (FAILED(hrRet)) { ASSERTMSG(FALSE, L"ClearSetChimeSettingsAlert failed at CoCreateInstance"); TRACE1("ClearSetChimeSettingsAlert failed at CoCreateInstance, %x", hrRet); break; } ASSERT(pAppSrvcs); hrRet = pAppSrvcs->Initialize(); if (FAILED(hrRet)) { ASSERTMSG(FALSE, L"ClearSetChimeSettingsAlert failed at pAppSrvcs->Initialize"); TRACE1("ClearSetChimeSettingsAlert failed at pAppSrvcs->Initialize, %x", hrRet); break; } // // Clear the Setup Chime Settings alert // hrRet = pAppSrvcs->ClearAlertAll(SA_SAMPLEAPP_CHIME_NOTSET_ALERT_CAPTION, bstrAlertLog); // // DISP_E_MEMBERNOTFOUND means that there were no matching alerts // if ((hrRet != DISP_E_MEMBERNOTFOUND) && (FAILED(hrRet))) { ASSERTMSG(FALSE, TEXT("ClearSetChimeSettingsAlert failed at pAppSrvcs->RaiseAlert")); TRACE1("ClearSetChimeSettingsAlert failed at pAppSrvcs->RaiseAlert, %x", hrRet); } else { bReturnCode = TRUE; } } while(false); } catch(...) { TRACE("CChimeSettings::OnTaskComplete caught unknown exception"); bReturnCode=FALSE; } return bReturnCode; } //+---------------------------------------------------------------------------- // // Function: CChimeSettings::NotifyChimeService // // Synopsis: Signals the event to notify ChimeService about the registry change. // ChimeService waits on the chime configuration change event and // reads the chime settings from registry if this event is set. // // Arguments: None // // Returns: BOOL // //+---------------------------------------------------------------------------- BOOL CChimeSettings::NotifyChimeService(void) { HANDLE hEvent = NULL; BOOL bRet = FALSE; do { // //Open the event to notify the chimeservice //This event should be created by the chime service when it starts. // hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, CHIME_EVENT); if (NULL == hEvent) { TRACE1("OpenEvent failed with %ld", GetLastError()); break; } // //Set the event. ChimeService will wakeup and read the new settings. // if (0 == SetEvent(hEvent)) { TRACE1("SetEvent failed with %ld", GetLastError()); break; } bRet= TRUE; } while(false); if (NULL != hEvent) { CloseHandle(hEvent); } return bRet; }