// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. #include "precomp.h" // private structs struct CPI_APPLICATION_ATTRIBUTES { int iActionType; int iActionCost; LPWSTR pwzKey; LPWSTR pwzID; LPWSTR pwzName; LPWSTR pwzPartID; CPI_PROPERTY* pPropList; }; // prototypes for private helper functions static HRESULT ReadApplicationAttributes( LPWSTR* ppwzData, CPI_APPLICATION_ATTRIBUTES* pAttrs ); static void FreeApplicationAttributes( CPI_APPLICATION_ATTRIBUTES* pAttrs ); static HRESULT CreateApplication( CPI_APPLICATION_ATTRIBUTES* pAttrs ); static HRESULT RemoveApplication( CPI_APPLICATION_ATTRIBUTES* pAttrs ); // function definitions HRESULT CpiConfigureApplications( LPWSTR* ppwzData, HANDLE hRollbackFile ) { HRESULT hr = S_OK; CPI_APPLICATION_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // read action text hr = CpiActionStartMessage(ppwzData, FALSE); ExitOnFailure(hr, "Failed to send action start message"); // get count int iCnt = 0; hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); // write count to rollback file hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); ExitOnFailure(hr, "Failed to write count to rollback file"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadApplicationAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // progress message hr = CpiActionDataMessage(1, attrs.pwzName); ExitOnFailure(hr, "Failed to send progress messages"); if (S_FALSE == hr) ExitFunction(); // write key to rollback file hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); ExitOnFailure(hr, "Failed to write key to rollback file"); // action switch (attrs.iActionType) { case atCreate: hr = CreateApplication(&attrs); ExitOnFailure(hr, "Failed to create application, key: %S", attrs.pwzKey); break; case atRemove: hr = RemoveApplication(&attrs); ExitOnFailure(hr, "Failed to remove application, key: %S", attrs.pwzKey); break; } // write completion status to rollback file hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); ExitOnFailure(hr, "Failed to write completion status to rollback file"); // progress hr = WcaProgressMessage(attrs.iActionCost, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreeApplicationAttributes(&attrs); return hr; } HRESULT CpiRollbackConfigureApplications( LPWSTR* ppwzData, CPI_ROLLBACK_DATA* pRollbackDataList ) { HRESULT hr = S_OK; int iRollbackStatus; CPI_APPLICATION_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // read action text hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); ExitOnFailure(hr, "Failed to send action start message"); // get count int iCnt = 0; hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadApplicationAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // rollback status hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); if (S_FALSE == hr) continue; // not found, nothing to rollback // progress message hr = CpiActionDataMessage(1, attrs.pwzName); ExitOnFailure(hr, "Failed to send progress messages"); if (S_FALSE == hr) ExitFunction(); // action switch (attrs.iActionType) { case atCreate: hr = CreateApplication(&attrs); if (FAILED(hr)) WcaLog(LOGMSG_STANDARD, "Failed to create application, hr: 0x%x, key: %S", hr, attrs.pwzKey); break; case atRemove: hr = RemoveApplication(&attrs); if (FAILED(hr)) WcaLog(LOGMSG_STANDARD, "Failed to remove application, hr: 0x%x, key: %S", hr, attrs.pwzKey); break; } // check rollback status if (0 == iRollbackStatus) continue; // operation did not complete, skip progress // progress hr = WcaProgressMessage(attrs.iActionCost, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreeApplicationAttributes(&attrs); return hr; } // helper function definitions static HRESULT ReadApplicationAttributes( LPWSTR* ppwzData, CPI_APPLICATION_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); ExitOnFailure(hr, "Failed to read action type"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); ExitOnFailure(hr, "Failed to read action cost"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); ExitOnFailure(hr, "Failed to read key"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzID); ExitOnFailure(hr, "Failed to read id"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName); ExitOnFailure(hr, "Failed to read name"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); ExitOnFailure(hr, "Failed to read partition id"); hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList); ExitOnFailure(hr, "Failed to read properties"); hr = S_OK; LExit: return hr; } static void FreeApplicationAttributes( CPI_APPLICATION_ATTRIBUTES* pAttrs ) { ReleaseStr(pAttrs->pwzKey); ReleaseStr(pAttrs->pwzID); ReleaseStr(pAttrs->pwzName); ReleaseStr(pAttrs->pwzPartID); if (pAttrs->pPropList) CpiFreePropertyList(pAttrs->pPropList); } static HRESULT CreateApplication( CPI_APPLICATION_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; ICatalogCollection* piAppColl = NULL; ICatalogObject* piAppObj = NULL; long lChanges = 0; // log WcaLog(LOGMSG_VERBOSE, "Creating application, key: %S", pAttrs->pwzKey); // get applications collection hr = CpiExecGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl); if (S_FALSE == hr) hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); ExitOnFailure(hr, "Failed to get applications collection"); // check if application exists hr = CpiFindCollectionObjectByStringKey(piAppColl, pAttrs->pwzID, &piAppObj); ExitOnFailure(hr, "Failed to find application"); if (S_FALSE == hr) { // create application hr = CpiAddCollectionObject(piAppColl, &piAppObj); ExitOnFailure(hr, "Failed to add application to collection"); hr = CpiPutCollectionObjectValue(piAppObj, L"ID", pAttrs->pwzID); ExitOnFailure(hr, "Failed to set application id property"); hr = CpiPutCollectionObjectValue(piAppObj, L"Name", pAttrs->pwzName); ExitOnFailure(hr, "Failed to set application name property"); // save changes hr = piAppColl->SaveChanges(&lChanges); if (COMADMIN_E_OBJECTERRORS == hr) CpiLogCatalogErrorInfo(); ExitOnFailure(hr, "Failed to add application"); } // properties hr = CpiPutCollectionObjectValues(piAppObj, pAttrs->pPropList); ExitOnFailure(hr, "Failed to write properties"); // save changes hr = piAppColl->SaveChanges(&lChanges); if (COMADMIN_E_OBJECTERRORS == hr) CpiLogCatalogErrorInfo(); ExitOnFailure(hr, "Failed to save changes"); // log WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); hr = S_OK; LExit: // clean up ReleaseObject(piAppColl); ReleaseObject(piAppObj); return hr; } static HRESULT RemoveApplication( CPI_APPLICATION_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; ICatalogCollection* piAppColl = NULL; long lChanges = 0; // log WcaLog(LOGMSG_VERBOSE, "Removing application, key: %S", pAttrs->pwzKey); // get applications collection hr = CpiExecGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl); ExitOnFailure(hr, "Failed to get applications collection"); if (S_FALSE == hr) { // applications collection not found WcaLog(LOGMSG_VERBOSE, "Unable to retrieve applications collection, nothing to delete, key: %S", pAttrs->pwzKey); ExitFunction1(hr = S_OK); } // remove hr = CpiRemoveCollectionObject(piAppColl, pAttrs->pwzID, NULL, TRUE); ExitOnFailure(hr, "Failed to remove application"); if (S_FALSE == hr) { // application not found WcaLog(LOGMSG_VERBOSE, "Application not found, nothing to delete, key: %S", pAttrs->pwzKey); ExitFunction1(hr = S_OK); } // save changes hr = piAppColl->SaveChanges(&lChanges); if (COMADMIN_E_OBJECTERRORS == hr) CpiLogCatalogErrorInfo(); ExitOnFailure(hr, "Failed to save changes"); // log WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); hr = S_OK; LExit: // clean up ReleaseObject(piAppColl); return hr; }