/****************************************************************** GetCurrentFirewallProfile - get the active firewall profile as an INetFwProfile, which owns the lists of exceptions we're updating. ********************************************************************/ static HRESULT GetCurrentFirewallProfile( __in BOOL fIgnoreFailures, __out INetFwProfile** ppfwProfile ) { HRESULT hr = S_OK; INetFwMgr* pfwMgr = NULL; INetFwPolicy* pfwPolicy = NULL; INetFwProfile* pfwProfile = NULL; *ppfwProfile = NULL; do { ReleaseNullObject(pfwPolicy); ReleaseNullObject(pfwMgr); ReleaseNullObject(pfwProfile); if (SUCCEEDED(hr = ::CoCreateInstance(__uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&pfwMgr)) && SUCCEEDED(hr = pfwMgr->get_LocalPolicy(&pfwPolicy)) && SUCCEEDED(hr = pfwPolicy->get_CurrentProfile(&pfwProfile))) { break; } else if (fIgnoreFailures) { ExitFunction1(hr = S_FALSE); } else { WcaLog(LOGMSG_STANDARD, "Failed to connect to Windows Firewall"); UINT er = WcaErrorMessage(msierrFirewallCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: // exit with the current HRESULT ExitFunction(); case IDRETRY: // clean up and retry the loop hr = S_FALSE; break; case IDIGNORE: // pass S_FALSE back to the caller, who knows how to ignore the failure ExitFunction1(hr = S_FALSE); default: // No UI, so default is to fail. ExitFunction(); } } } while (S_FALSE == hr); *ppfwProfile = pfwProfile; pfwProfile = NULL; LExit: ReleaseObject(pfwPolicy); ReleaseObject(pfwMgr); ReleaseObject(pfwProfile); return hr; }
HRESULT CpiPartitionsVerifyInstall( CPI_PARTITION_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogCollection* piPartColl = NULL; ICatalogObject* piPartObj = NULL; for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // referenced locaters or partitions that are being installed if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))) continue; // if the partition is referensed and is not a locater, it must be installed if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction)) MessageExitOnFailure(hr = E_FAIL, msierrComPlusPartitionDependency, "A partition is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey); // get partitions collection if (!piPartColl) { hr = CpiGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); } // partition is supposed to exist if (!pItm->fHasComponent || CpiIsInstalled(pItm->isInstalled)) { // get collection object for partition hr = CpiFindCollectionObject(piPartColl, pItm->wzID, *pItm->wzID ? NULL : pItm->wzName, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); // if the partition was found if (S_OK == hr) { // if we don't have an id, copy id from object if (!*pItm->wzID) { hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } } // if the partition was not found else { // if the application is a locater, this is an error if (!pItm->fHasComponent) MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusPartitionNotFound, "A partition required by this installation was not found, key: %S", pItm->wzKey); // create a new id if one is missing if (!*pItm->wzID) { hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to create id"); } } } // partition is supposed to be created else { // check for conflicts do { if (*pItm->wzID) { // find partitions with conflicting id hr = CpiFindCollectionObject(piPartColl, pItm->wzID, NULL, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); if (S_FALSE == hr) { // find partitions with conflicting name hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); if (S_OK == hr) // "A partition with a conflictiong name exists. retry cancel" er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0); else break; // no conflicting entry found, break loop } else // "A partition with a conflicting id exists. abort retry ignore" er = WcaErrorMessage(msierrComPlusPartitionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); } else { // find partitions with conflicting name hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); if (S_OK == hr) // "A partition with a conflictiong name exists. abort retry ignore" er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); else break; // no conflicting entry found, break loop } switch (er) { case IDCANCEL: case IDABORT: ExitOnFailure(hr = E_FAIL, "A partition with a conflictiong name or id exists, key: %S", pItm->wzKey); break; case IDRETRY: break; case IDIGNORE: default: // if we don't have an id, copy id from object if (!*pItm->wzID) { hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } hr = S_FALSE; // indicate that this is not a conflict } } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts // create a new id if one is missing if (!*pItm->wzID) { hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to create id"); } } // clean up ReleaseNullObject(piPartObj); } hr = S_OK; LExit: // clean up ReleaseObject(piPartColl); ReleaseObject(piPartObj); return hr; }
static HRESULT RemoveUsersInApplicationRole( CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogCollection* piUsrInRoleColl = NULL; PSID pSid = NULL; long lChanges = 0; // log WcaLog(LOGMSG_VERBOSE, "Removing user from application role, key: %S", pAttrs->pwzKey); // get users in role collection hr = CpiGetUsersInRoleCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzRoleName, &piUsrInRoleColl); ExitOnFailure(hr, "Failed to get users in role collection"); if (S_FALSE == hr) { // users in role collection not found WcaLog(LOGMSG_VERBOSE, "Unable to retrieve users in role collection, nothing to delete, key: %S", pAttrs->pwzKey); ExitFunction1(hr = S_OK); } // get SID for account do { er = ERROR_SUCCESS; hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid); if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK)) { WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount); er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitFunction(); // exit with error code from CpiAccountNameToSid() case IDRETRY: break; case IDIGNORE: default: ExitFunction1(hr = S_OK); } } else ExitOnFailure(hr, "Failed to get SID for account"); } while (IDRETRY == er); // remove hr = CpiRemoveUserCollectionObject(piUsrInRoleColl, pSid); if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr) { WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr); hr = S_FALSE; } else ExitOnFailure(hr, "Failed to remove user"); if (S_FALSE == hr) { // role not found WcaLog(LOGMSG_VERBOSE, "User not found for application role, nothing to delete, key: %S", pAttrs->pwzKey); ExitFunction1(hr = S_OK); } // save changes hr = piUsrInRoleColl->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(piUsrInRoleColl); if (pSid) ::HeapFree(::GetProcessHeap(), 0, pSid); return hr; }
static HRESULT CreateUsersInApplicationRole( CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogCollection* piUsrInRoleColl = NULL; ICatalogObject* piUsrInRoleObj = NULL; PSID pSid = NULL; long lChanges = 0; // log WcaLog(LOGMSG_VERBOSE, "Adding user to application role, key: %S", pAttrs->pwzKey); // get users in role collection hr = CpiGetUsersInRoleCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzRoleName, &piUsrInRoleColl); if (S_FALSE == hr) hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); ExitOnFailure(hr, "Failed to get users in role collection"); // get SID for account do { er = ERROR_SUCCESS; hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid); if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK)) { WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount); er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitFunction(); // exit with error code from CpiAccountNameToSid() case IDRETRY: break; case IDIGNORE: default: ExitFunction1(hr = S_OK); } } else ExitOnFailure(hr, "Failed to get SID for account"); } while (IDRETRY == er); // find any existing entry hr = CpiFindUserCollectionObject(piUsrInRoleColl, pSid, NULL); if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr) WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr); else ExitOnFailure(hr, "Failed to find user in application role"); if (S_OK == hr) { WcaLog(LOGMSG_VERBOSE, "User already assigned to application role, key: %S", pAttrs->pwzKey); ExitFunction(); // exit with hr = S_OK } // convert SID back to account name hr = CpiSidToAccountName(pSid, &pAttrs->pwzAccount); ExitOnFailure(hr, "Failed to convert SID to account name"); // add user hr = CpiAddCollectionObject(piUsrInRoleColl, &piUsrInRoleObj); ExitOnFailure(hr, "Failed to add user in role to collection"); hr = CpiPutCollectionObjectValue(piUsrInRoleObj, L"User", pAttrs->pwzAccount); ExitOnFailure(hr, "Failed to set role name property"); // save changes hr = piUsrInRoleColl->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(piUsrInRoleColl); ReleaseObject(piUsrInRoleObj); if (pSid) ::HeapFree(::GetProcessHeap(), 0, pSid); return hr; }
static HRESULT CreatePartitionUser( CPI_PARTITION_USER_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogCollection* piUserColl = NULL; ICatalogObject* piUserObj = NULL; PSID pSid = NULL; long lChanges = 0; // log WcaLog(LOGMSG_VERBOSE, "Setting default partition for user, key: %S", pAttrs->pwzKey); // get partition users collection hr = CpiGetPartitionUsersCollection(&piUserColl); ExitOnFailure(hr, "Failed to get partition users collection"); // get SID for account do { er = ERROR_SUCCESS; hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid); if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK)) { WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount); er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitFunction(); // exit with error code from CpiAccountNameToSid() case IDRETRY: break; case IDIGNORE: default: ExitFunction1(hr = S_OK); } } else ExitOnFailure(hr, "Failed to get SID for account"); } while (IDRETRY == er); // remove any existing entry hr = CpiRemoveUserCollectionObject(piUserColl, pSid); if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr) { WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr); hr = S_FALSE; } else ExitOnFailure(hr, "Failed to remove user"); if (S_OK == hr) WcaLog(LOGMSG_VERBOSE, "Existing default partition for user was removed, key: %S", pAttrs->pwzKey); // add partition user hr = CpiAddCollectionObject(piUserColl, &piUserObj); ExitOnFailure(hr, "Failed to add partition to collection"); hr = CpiPutCollectionObjectValue(piUserObj, L"AccountName", pAttrs->pwzAccount); ExitOnFailure(hr, "Failed to set account name property"); hr = CpiPutCollectionObjectValue(piUserObj, L"DefaultPartitionID", pAttrs->pwzPartID); ExitOnFailure(hr, "Failed to set default partition id property"); // save changes hr = piUserColl->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(piUserColl); ReleaseObject(piUserObj); if (pSid) ::HeapFree(::GetProcessHeap(), 0, pSid); return hr; }
HRESULT CpiApplicationRolesVerifyInstall( CPI_APPLICATION_ROLE_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogObject* piRoleObj = NULL; for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // referenced locaters or roles that are being installed if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))) continue; // if the role is referensed and is not a locater, it must be installed if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction)) MessageExitOnFailure1(hr = E_FAIL, msierrComPlusApplicationRoleDependency, "An application role is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey); // role is a locater if (!pItm->fHasComponent) { // get collection object for role hr = FindObjectForApplicationRole(pItm, &piRoleObj); ExitOnFailure(hr, "Failed to find collection object for role"); // if the role was not found if (S_FALSE == hr) MessageExitOnFailure1(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusApplicationRoleNotFound, "An application role required by this installation was not found, key: %S", pItm->wzKey); } // role is supposed to be created else if (!CpiIsInstalled(pItm->isInstalled)) { do { // find roles with conflicting name or id hr = FindObjectForApplicationRole(pItm, NULL); ExitOnFailure(hr, "Failed to find collection object for role"); if (S_OK == hr) { er = WcaErrorMessage(msierrComPlusApplicationRoleConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitOnFailure1(hr = E_FAIL, "An application with a conflictiong name exists, key: %S", pItm->wzKey); break; case IDRETRY: break; case IDIGNORE: default: hr = S_FALSE; // indicate that this is not a conflict } } } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts } // clean up ReleaseNullObject(piRoleObj); } hr = S_OK; LExit: // clean up ReleaseObject(piRoleObj); return hr; }
/****************************************************************** ExecXmlConfig - entry point for XmlConfig Custom Action *******************************************************************/ extern "C" UINT __stdcall ExecXmlConfig( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ExecXmlConfig"); HRESULT hr = S_OK; HRESULT hrOpenFailure = S_OK; UINT er = ERROR_SUCCESS; BOOL fIsWow64Process = FALSE; BOOL fIsFSRedirectDisabled = FALSE; BOOL fPreserveDate = FALSE; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzData = NULL; LPWSTR pwzFile = NULL; LPWSTR pwzElementPath = NULL; LPWSTR pwzVerifyPath = NULL; LPWSTR pwzName = NULL; LPWSTR pwzValue = NULL; LPWSTR pwz = NULL; int cAdditionalChanges = 0; IXMLDOMDocument* pixd = NULL; IXMLDOMNode* pixn = NULL; IXMLDOMNode* pixnVerify = NULL; IXMLDOMNode* pixnNewNode = NULL; IXMLDOMNode* pixnRemovedChild = NULL; IXMLDOMDocument* pixdNew = NULL; IXMLDOMElement* pixeNew = NULL; FILETIME ft; int id = IDRETRY; eXmlAction xa; eXmlPreserveDate xd; // initialize hr = WcaInitialize(hInstall, "ExecXmlConfig"); ExitOnFailure(hr, "failed to initialize"); hr = XmlInitialize(); ExitOnFailure(hr, "failed to initialize xml utilities"); hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); ExitOnFailure(hr, "failed to process CustomActionData"); // Initialize the Wow64 API - store the result in fWow64APIPresent // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases WcaInitializeWow64(); fIsWow64Process = WcaIsWow64Process(); if (xaOpenFile != xa && xaOpenFilex64 != xa) { ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data"); } // loop through all the passed in data while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzFile); ExitOnFailure(hr, "failed to read file name from custom action data"); // Default to not preserve date, preserve it if any modifications require us to fPreserveDate = FALSE; // Open the file ReleaseNullObject(pixd); if (xaOpenFilex64 == xa) { if (!fIsWow64Process) { hr = E_NOTIMPL; ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW."); } hr = WcaDisableWow64FSRedirection(); ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); fIsFSRedirectDisabled = TRUE; } hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd); if (FAILED(hr)) { // Ignore the return code for now. If they try to add something, we'll fail the install. If all they do is remove stuff then it doesn't matter. hrOpenFailure = hr; hr = S_OK; } else { hrOpenFailure = S_OK; } WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile); while (pwz && *pwz) { // If we skip past an element that has additional changes we need to strip them off the stream before // moving on to the next element. Do that now and then restart the outer loop. if (cAdditionalChanges > 0) { while (cAdditionalChanges > 0) { hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); cAdditionalChanges--; } continue; } hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); ExitOnFailure(hr, "failed to process CustomActionData"); // Break if we need to move on to a different file if (xaOpenFile == xa || xaOpenFilex64 == xa) { break; } hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd); ExitOnFailure(hr, "failed to process CustomActionData"); if (xdPreserve == xd) { fPreserveDate = TRUE; } // Get path, name, and value to be written hr = WcaReadStringFromCaData(&pwz, &pwzElementPath); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzVerifyPath); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, &cAdditionalChanges); ExitOnFailure(hr, "failed to process CustomActionData"); // If we failed to open the file and we're adding something to the file, we've got a problem. Otherwise, just continue on since the file's already gone. if (FAILED(hrOpenFailure)) { if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) { MessageExitOnFailure1(hr = hrOpenFailure, msierrXmlConfigFailedOpen, "failed to load XML file: %ls", pwzFile); } else { continue; } } // Select the node we're about to modify ReleaseNullObject(pixn); hr = XmlSelectSingleNode(pixd, pwzElementPath, &pixn); // If we failed to find the node that we are going to add to, we've got a problem. Otherwise, just continue since the node's already gone. if (S_FALSE == hr) { if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) { hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND); } else { hr = S_OK; continue; } } MessageExitOnFailure2(hr, msierrXmlConfigFailedSelect, "failed to find node: %ls in XML file: %ls", pwzElementPath, pwzFile); // Make the modification switch (xa) { case xaWriteValue: if (pwzName && *pwzName) { // We're setting an attribute hr = XmlSetAttribute(pixn, pwzName, pwzValue); ExitOnFailure2(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); } else { // We're setting the text of the node hr = XmlSetText(pixn, pwzValue); ExitOnFailure2(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzElementPath); } break; case xaWriteDocument: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { // We found the verify path which means we have no further work to do continue; } ExitOnFailure1(hr, "failed to query verify path: %ls", pwzVerifyPath); } hr = XmlLoadDocumentEx(pwzValue, XML_LOAD_PRESERVE_WHITESPACE, &pixdNew); ExitOnFailure(hr, "Failed to load value as document."); hr = pixdNew->get_documentElement(&pixeNew); ExitOnFailure(hr, "Failed to get document element."); hr = pixn->appendChild(pixeNew, NULL); ExitOnFailure(hr, "Failed to append document element on to parent element."); ReleaseNullObject(pixeNew); ReleaseNullObject(pixdNew); break; case xaCreateElement: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { // We found the verify path which means we have no further work to do continue; } ExitOnFailure1(hr, "failed to query verify path: %ls", pwzVerifyPath); } hr = XmlCreateChild(pixn, pwzName, &pixnNewNode); ExitOnFailure1(hr, "failed to create child element: %ls", pwzName); if (pwzValue && *pwzValue) { hr = XmlSetText(pixnNewNode, pwzValue); ExitOnFailure2(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName); } while (cAdditionalChanges > 0) { hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); // Set the additional attribute hr = XmlSetAttribute(pixnNewNode, pwzName, pwzValue); ExitOnFailure2(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); cAdditionalChanges--; } ReleaseNullObject(pixnNewNode); break; case xaDeleteValue: if (pwzName && *pwzName) { // Delete the attribute hr = XmlRemoveAttribute(pixn, pwzName); ExitOnFailure1(hr, "failed to remove attribute: %ls", pwzName); } else { // Clear the text value for the node hr = XmlSetText(pixn, L""); ExitOnFailure(hr, "failed to clear text value"); } break; case xaDeleteElement: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { hr = pixn->removeChild(pixnVerify, &pixnRemovedChild); ExitOnFailure(hr, "failed to remove created child element"); ReleaseNullObject(pixnRemovedChild); } else { WcaLog(LOGMSG_VERBOSE, "Failed to select path %ls for deleting. Skipping...", pwzVerifyPath); hr = S_OK; } } else { // TODO: This requires a VerifyPath to delete an element. Should we support not having one? WcaLog(LOGMSG_VERBOSE, "No VerifyPath specified for delete element of ID: %ls", pwzElementPath); } break; default: ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data"); break; } } // Now that we've made all of the changes to this file, save it and move on to the next if (S_OK == hrOpenFailure) { if (fPreserveDate) { hr = FileGetTime(pwzFile, NULL, NULL, &ft); ExitOnFailure1(hr, "failed to get modified time of file : %ls", pwzFile); } int iSaveAttempt = 0; do { hr = XmlSaveDocument(pixd, pwzFile); if (FAILED(hr)) { id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile); switch (id) { case IDABORT: ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); case IDRETRY: hr = S_FALSE; // hit me, baby, one more time break; case IDIGNORE: hr = S_OK; // pretend everything is okay and bail break; case 0: // No UI case, MsiProcessMessage returns 0 if (STIERR_SHARING_VIOLATION == hr) { // Only in case of sharing violation do we retry 30 times, once a second. if (iSaveAttempt < 30) { hr = S_FALSE; ++iSaveAttempt; WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt); Sleep(1000); } else { ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); } } break; default: // Unknown error ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); } } } while (S_FALSE == hr); if (fPreserveDate) { hr = FileSetTime(pwzFile, NULL, NULL, &ft); ExitOnFailure1(hr, "failed to set modified time of file : %ls", pwzFile); } if (fIsFSRedirectDisabled) { fIsFSRedirectDisabled = FALSE; WcaRevertWow64FSRedirection(); } } } LExit: // Make sure we revert FS Redirection if necessary before exiting if (fIsFSRedirectDisabled) { fIsFSRedirectDisabled = FALSE; WcaRevertWow64FSRedirection(); } WcaFinalizeWow64(); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); ReleaseStr(pwzFile); ReleaseStr(pwzElementPath); ReleaseStr(pwzVerifyPath); ReleaseStr(pwzName); ReleaseStr(pwzValue); ReleaseObject(pixeNew); ReleaseObject(pixdNew); ReleaseObject(pixn); ReleaseObject(pixd); ReleaseObject(pixnNewNode); ReleaseObject(pixnRemovedChild); XmlUninitialize(); if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
HRESULT CpiSubscriptionsVerifyInstall( CPI_SUBSCRIPTION_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogObject* piSubsObj = NULL; for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // subscriptions that are being installed if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) continue; // subscription is supposed to exist if (CpiIsInstalled(pItm->isInstalled)) { // if we don't have an id if (!*pItm->wzID) { // find subscriptions with conflicting name hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj); ExitOnFailure(hr, "Failed to find collection object for subscription"); // if the subscription was found if (S_OK == hr) { // get id from subscription object hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } // if the subscription was not found else { // create a new id hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to create id"); } } } // subscription is supposed to be created else { // check for conflicts do { if (*pItm->wzID) { // find subscriptions with conflicting id hr = FindObjectForSubscription(pItm, TRUE, FALSE, &piSubsObj); ExitOnFailure(hr, "Failed to find collection object for subscription"); if (S_FALSE == hr) { // find subscriptions with conflicting name hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj); ExitOnFailure(hr, "Failed to find collection object for subscription"); if (S_OK == hr) // "A subscription with a conflictiong name exists. retry cancel" er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0); else break; // no conflicting entry found, break loop } else // "A subscription with a conflicting id exists. abort retry ignore" er = WcaErrorMessage(msierrComPlusSubscriptionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); } else { // find subscriptions with conflicting name hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj); ExitOnFailure(hr, "Failed to find collection object for subscription"); if (S_OK == hr) // "A subscription with a conflictiong name exists. abort retry ignore" er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); else break; // no conflicting entry found, break loop } switch (er) { case IDCANCEL: case IDABORT: ExitOnFailure1(hr = E_FAIL, "A subscription with a conflictiong name or id exists, key: %S", pItm->wzKey); break; case IDRETRY: break; case IDIGNORE: default: // if we don't have an id, copy id from object if (!*pItm->wzID) { hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } hr = S_FALSE; // indicate that this is not a conflict } } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts // create a new id if one is missing if (!*pItm->wzID) { hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to create id"); } } // clean up ReleaseNullObject(piSubsObj); } hr = S_OK; LExit: // clean up ReleaseObject(piSubsObj); return hr; }
/******************************************************************** MessageQueuingInstall - CUSTOM ACTION ENTRY POINT for installing MSMQ message queues ********************************************************************/ extern "C" UINT __stdcall MessageQueuingInstall(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; MQI_MESSAGE_QUEUE_LIST lstMessageQueues; MQI_MESSAGE_QUEUE_PERMISSION_LIST lstMessageQueuePermissions; int iCost = 0; LPWSTR pwzRollbackActionData = NULL; LPWSTR pwzExecuteActionData = NULL; ::ZeroMemory(&lstMessageQueues, sizeof(lstMessageQueues)); ::ZeroMemory(&lstMessageQueuePermissions, sizeof(lstMessageQueuePermissions)); // initialize hr = WcaInitialize(hInstall, "MessageQueuingInstall"); ExitOnFailure(hr, "Failed to initialize"); do { hr = MqiInitialize(); if (S_FALSE == hr) { WcaLog(LOGMSG_STANDARD, "Failed to load mqrt.dll."); er = WcaErrorMessage(msierrMsmqCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitFunction1(hr = E_FAIL); // bail with error case IDRETRY: break; // retry case IDIGNORE: __fallthrough; default: ExitFunction1(hr = S_OK); // pretend everything is okay and bail } } ExitOnFailure(hr, "Failed to initialize MSMQ."); } while (S_FALSE == hr); // read message queues hr = MqiMessageQueueRead(&lstMessageQueues); ExitOnFailure(hr, "Failed to read MessageQueue table"); // read message queue permissions hr = MqiMessageQueuePermissionRead(&lstMessageQueues, &lstMessageQueuePermissions); ExitOnFailure(hr, "Failed to read message queue permissions"); // verify message queue elementes hr = MqiMessageQueueVerify(&lstMessageQueues); ExitOnFailure(hr, "Failed to verify message queue elements."); if (lstMessageQueues.iInstallCount || lstMessageQueuePermissions.iInstallCount) { // schedule rollback action hr = MqiMessageQueuePermissionInstall(&lstMessageQueuePermissions, &pwzRollbackActionData); ExitOnFailure(hr, "Failed to add message queue permissions to rollback action data"); hr = MqiMessageQueueInstall(&lstMessageQueues, TRUE, &pwzRollbackActionData); ExitOnFailure(hr, "Failed to add message queues to rollback action data"); hr = WcaDoDeferredAction(L"MessageQueuingRollbackInstall", pwzRollbackActionData, 0); ExitOnFailure(hr, "Failed to schedule MessageQueuingRollbackInstall"); // schedule execute action hr = MqiMessageQueueInstall(&lstMessageQueues, FALSE, &pwzExecuteActionData); ExitOnFailure(hr, "Failed to add message queues to execute action data"); iCost += lstMessageQueues.iInstallCount * COST_MESSAGE_QUEUE_CREATE; hr = MqiMessageQueuePermissionInstall(&lstMessageQueuePermissions, &pwzExecuteActionData); ExitOnFailure(hr, "Failed to add message queue permissions to execute action data"); iCost += lstMessageQueues.iInstallCount * COST_MESSAGE_QUEUE_PERMISSION_ADD; hr = WcaDoDeferredAction(L"MessageQueuingExecuteInstall", pwzExecuteActionData, iCost); ExitOnFailure(hr, "Failed to schedule MessageQueuingExecuteInstall"); } hr = S_OK; LExit: // clean up MqiMessageQueueFreeList(&lstMessageQueues); MqiMessageQueuePermissionFreeList(&lstMessageQueuePermissions); ReleaseStr(pwzRollbackActionData); ReleaseStr(pwzExecuteActionData); // uninitialize MqiUninitialize(); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/******************************************************************** ConfigureIIsExec - custom action for installing IIs settings - table data will be wrapped and passed in from immediate CA ReadIIsTables ********************************************************************/ extern "C" UINT __stdcall ConfigureIIsExec( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ConfigureIIsExec here"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; BOOL fInitializedCom = FALSE; IMSAdminBase* piMetabase = NULL; SCA_WEB* pswList = NULL; SCA_WEBDIR* pswdList = NULL; SCA_VDIR* psvdList = NULL; SCA_FILTER* psfList = NULL; SCA_APPPOOL *psapList = NULL; SCA_MIMEMAP* psmmList = NULL; SCA_HTTP_HEADER* pshhList = NULL; SCA_PROPERTY *pspList = NULL; SCA_WEBSVCEXT* psWseList = NULL; SCA_WEB_ERROR* psweList = NULL; LPWSTR pwzScriptKey = NULL; LPWSTR pwzCustomActionData = NULL; WCA_WRAPQUERY_HANDLE hUserQuery = NULL; WCA_WRAPQUERY_HANDLE hWebBaseQuery = NULL; WCA_WRAPQUERY_HANDLE hWebDirPropQuery = NULL; WCA_WRAPQUERY_HANDLE hSslCertQuery = NULL; WCA_WRAPQUERY_HANDLE hWebLogQuery = NULL; WCA_WRAPQUERY_HANDLE hWebAppQuery = NULL; WCA_WRAPQUERY_HANDLE hWebAppExtQuery = NULL; // initialize hr = WcaInitialize(hInstall, "ConfigureIIsExec"); ExitOnFailure(hr, "Failed to initialize"); hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); // Get the CaScript key hr = WcaReadStringFromCaData(&pwzCustomActionData, &pwzScriptKey); ExitOnFailure(hr, "Failed to get CaScript key from custom action data"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to initialize COM"); fInitializedCom = TRUE; // if IIS was uninstalled (thus no IID_IMSAdminBase) allow the // user to still uninstall this package by clicking "Ignore" do { hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void**)&piMetabase); if (FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "failed to get IID_IMSAdminBase Object"); er = WcaErrorMessage(msierrIISCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitFunction(); // bail with the error result from the CoCreate to kick off a rollback case IDRETRY: hr = S_FALSE; // hit me, baby, one more time break; case IDIGNORE: __fallthrough; default: WcaLog(LOGMSG_STANDARD, "ignoring absent IIS"); // We need to write the empty script to communicate to other deferred CA that there is noting to do. hr = ScaWriteConfigurationScript(pwzScriptKey); ExitOnFailure(hr, "failed to schedule metabase configuration"); ExitFunction1(hr = S_OK); // pretend everything is okay break; } } } while (S_FALSE == hr); // read the msi tables hr = WcaBeginUnwrapQuery(&hUserQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap user query"); hr = ScaWebSvcExtRead(&psWseList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebSvcExt, "failed while processing WebServiceExtensions"); hr = ScaAppPoolRead(&psapList, hUserQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadAppPool, "failed while processing WebAppPools"); // MimeMap, Error and HttpHeader need to be read before the virtual directory and web read hr = ScaMimeMapRead(&psmmList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadMimeMap, "failed while processing MimeMaps"); hr = ScaHttpHeaderRead(&pshhList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadHttpHeader, "failed while processing HttpHeaders"); hr = ScaWebErrorRead(&psweList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebError, "failed while processing WebErrors"); hr = WcaBeginUnwrapQuery(&hWebDirPropQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web dir properties query"); hr = WcaBeginUnwrapQuery(&hSslCertQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap ssl certificate query"); hr = WcaBeginUnwrapQuery(&hWebLogQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web log query"); hr = WcaBeginUnwrapQuery(&hWebAppQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web application query"); hr = WcaBeginUnwrapQuery(&hWebAppExtQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web application extension query"); hr = ScaWebsRead(piMetabase, &psmmList, &pswList, &pshhList, &psweList, hUserQuery, hWebDirPropQuery, hSslCertQuery, hWebLogQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebSite, "failed while processing WebSites"); hr = WcaBeginUnwrapQuery(&hWebBaseQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web base query"); hr = ScaWebDirsRead(piMetabase, pswList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData, &pswdList); MessageExitOnFailure(hr, msierrIISFailedReadWebDirs, "failed while processing WebDirs"); hr = ScaVirtualDirsRead(piMetabase, pswList, &psvdList, &psmmList, &pshhList, &psweList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadVDirs, "failed while processing WebVirtualDirs"); hr = ScaFiltersRead(piMetabase, pswList, hWebBaseQuery, &psfList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadFilters, "failed while processing WebFilters"); hr = ScaPropertyRead(&pspList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadProp, "failed while processing WebProperties"); // do uninstall actions (order is important!) hr = ScaPropertyUninstall(piMetabase, pspList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallProp, "failed to uninstall IIS properties"); hr = ScaFiltersUninstall(piMetabase, psfList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallFilters, "failed to schedule uninstall of filters"); hr = ScaVirtualDirsUninstall(piMetabase, psvdList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallVDirs, "failed to schedule uninstall of virtual directories"); hr = ScaWebDirsUninstall(piMetabase, pswdList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebDirs, "failed to schedule uninstall of web directories"); hr = ScaWebsUninstall(piMetabase, pswList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebs, "failed to schedule uninstall of webs"); hr = ScaAppPoolUninstall(piMetabase, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallAppPool, "failed to schedule uninstall of AppPools"); // do install actions (order is important!) // ScaWebSvcExtCommit contains both uninstall and install actions. hr = ScaWebSvcExtCommit(piMetabase, psWseList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebSvcExt, "failed to schedule install/uninstall of WebSvcExt"); hr = ScaAppPoolInstall(piMetabase, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallAppPool, "failed to schedule install of AppPools"); hr = ScaWebsInstall(piMetabase, pswList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebs, "failed to schedule install of webs"); hr = ScaWebDirsInstall(piMetabase, pswdList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebDirs, "failed to schedule install of web directories"); hr = ScaVirtualDirsInstall(piMetabase, psvdList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallVDirs, "failed to schedule install of virtual directories"); hr = ScaFiltersInstall(piMetabase, psfList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallFilters, "failed to schedule install of filters"); hr = ScaPropertyInstall(piMetabase, pspList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallProp, "failed to schedule install of properties"); hr = ScaWriteConfigurationScript(pwzScriptKey); ExitOnFailure(hr, "failed to schedule metabase configuration"); LExit: ReleaseStr(pwzScriptKey); ReleaseStr(pwzCustomActionData); WcaFinishUnwrapQuery(hUserQuery); WcaFinishUnwrapQuery(hWebBaseQuery); WcaFinishUnwrapQuery(hWebDirPropQuery); WcaFinishUnwrapQuery(hSslCertQuery); WcaFinishUnwrapQuery(hWebLogQuery); WcaFinishUnwrapQuery(hWebAppQuery); WcaFinishUnwrapQuery(hWebAppExtQuery); if (psWseList) { ScaWebSvcExtFreeList(psWseList); } if (psfList) { ScaFiltersFreeList(psfList); } if (psvdList) { ScaVirtualDirsFreeList(psvdList); } if (pswdList) { ScaWebDirsFreeList(pswdList); } if (pswList) { ScaWebsFreeList(pswList); } if (psmmList) { ScaMimeMapCheckList(psmmList); ScaMimeMapFreeList(psmmList); } if (pshhList) { ScaHttpHeaderCheckList(pshhList); ScaHttpHeaderFreeList(pshhList); } if (psweList) { ScaWebErrorCheckList(psweList); ScaWebErrorFreeList(psweList); } ReleaseObject(piMetabase); if (fInitializedCom) { ::CoUninitialize(); } er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/******************************************************************** ConfigureComPlusInstall - CUSTOM ACTION ENTRY POINT for installing COM+ components ********************************************************************/ extern "C" UINT __stdcall ConfigureComPlusInstall(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; BOOL fInitializedCom = FALSE; ICOMAdminCatalog* piCatalog = NULL; CPI_PARTITION_LIST partList; CPI_PARTITION_ROLE_LIST partRoleList; CPI_USER_IN_PARTITION_ROLE_LIST usrInPartRoleList; CPI_PARTITION_USER_LIST partUsrList; CPI_APPLICATION_LIST appList; CPI_APPLICATION_ROLE_LIST appRoleList; CPI_USER_IN_APPLICATION_ROLE_LIST usrInAppRoleList; CPI_ASSEMBLY_LIST asmList; CPI_SUBSCRIPTION_LIST subList; LPWSTR pwzRollbackFileName = NULL; LPWSTR pwzActionData = NULL; LPWSTR pwzRollbackActionData = NULL; LPWSTR pwzCommitActionData = NULL; int iVersionNT = 0; int iProgress = 0; int iCommitProgress = 0; ::ZeroMemory(&partList, sizeof(CPI_PARTITION_LIST)); ::ZeroMemory(&partRoleList, sizeof(CPI_PARTITION_ROLE_LIST)); ::ZeroMemory(&usrInPartRoleList, sizeof(CPI_USER_IN_PARTITION_ROLE_LIST)); ::ZeroMemory(&partUsrList, sizeof(CPI_PARTITION_USER_LIST)); ::ZeroMemory(&appList, sizeof(CPI_APPLICATION_LIST)); ::ZeroMemory(&appRoleList, sizeof(CPI_APPLICATION_ROLE_LIST)); ::ZeroMemory(&usrInAppRoleList, sizeof(CPI_USER_IN_APPLICATION_ROLE_LIST)); ::ZeroMemory(&asmList, sizeof(CPI_ASSEMBLY_LIST)); ::ZeroMemory(&subList, sizeof(CPI_SUBSCRIPTION_LIST)); // initialize hr = WcaInitialize(hInstall, "ConfigureComPlusInstall"); ExitOnFailure(hr, "Failed to initialize"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; CpiInitialize(); // check for the prerequsite tables if (!CpiTableExists(cptComPlusPartition) && !CpiTableExists(cptComPlusApplication) && !CpiTableExists(cptComPlusAssembly)) { WcaLog(LOGMSG_VERBOSE, "skipping install COM+ CustomAction, no ComPlusPartition, ComPlusApplication or ComPlusAssembly table present"); ExitFunction1(hr = S_FALSE); } // make sure we can access the COM+ admin catalog do { hr = CpiGetAdminCatalog(&piCatalog); if (FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "Failed to get COM+ admin catalog"); er = WcaErrorMessage(msierrComPlusCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitFunction(); // exit with hr from CpiGetAdminCatalog() to kick off a rollback case IDRETRY: hr = S_FALSE; break; case IDIGNORE: default: ExitFunction1(hr = S_OK); // pretend everything is okay and bail } } } while (S_FALSE == hr); // get NT version hr = WcaGetIntProperty(L"VersionNT", &iVersionNT); ExitOnFailure(hr, "Failed to get VersionNT property"); // read elements if (502 <= iVersionNT && CpiTableExists(cptComPlusPartition)) { hr = CpiPartitionsRead(&partList); MessageExitOnFailure(hr, msierrComPlusPartitionReadFailed, "Failed to read ComPlusPartitions table"); } if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionRole)) { hr = CpiPartitionRolesRead(&partList, &partRoleList); MessageExitOnFailure(hr, msierrComPlusPartitionRoleReadFailed, "Failed to read ComPlusPartitionRole table"); } if (502 <= iVersionNT && (CpiTableExists(cptComPlusUserInPartitionRole) || CpiTableExists(cptComPlusGroupInPartitionRole))) { hr = CpiUsersInPartitionRolesRead(&partRoleList, &usrInPartRoleList); MessageExitOnFailure(hr, msierrComPlusUserInPartitionRoleReadFailed, "Failed to read ComPlusUserInPartitionRole table"); } if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionUser)) { hr = CpiPartitionUsersRead(&partList, &partUsrList); MessageExitOnFailure(hr, msierrComPlusPartitionUserReadFailed, "Failed to read ComPlusPartitionUser table"); } if (CpiTableExists(cptComPlusApplication)) { hr = CpiApplicationsRead(&partList, &appList); MessageExitOnFailure(hr, msierrComPlusApplicationReadFailed, "Failed to read ComPlusApplication table"); } if (CpiTableExists(cptComPlusApplicationRole)) { hr = CpiApplicationRolesRead(&appList, &appRoleList); MessageExitOnFailure(hr, msierrComPlusApplicationRoleReadFailed, "Failed to read ComPlusApplicationRole table"); } if (CpiTableExists(cptComPlusUserInApplicationRole) || CpiTableExists(cptComPlusGroupInApplicationRole)) { hr = CpiUsersInApplicationRolesRead(&appRoleList, &usrInAppRoleList); MessageExitOnFailure(hr, msierrComPlusUserInApplicationRoleReadFailed, "Failed to read ComPlusUserInApplicationRole table"); } if (CpiTableExists(cptComPlusAssembly)) { hr = CpiAssembliesRead(&appList, &appRoleList, &asmList); MessageExitOnFailure(hr, msierrComPlusAssembliesReadFailed, "Failed to read ComPlusAssembly table"); } if (CpiTableExists(cptComPlusSubscription)) { hr = CpiSubscriptionsRead(&asmList, &subList); MessageExitOnFailure(hr, msierrComPlusSubscriptionReadFailed, "Failed to read ComPlusSubscription table"); } // verify elements hr = CpiPartitionsVerifyInstall(&partList); ExitOnFailure(hr, "Failed to verify partitions"); hr = CpiApplicationsVerifyInstall(&appList); ExitOnFailure(hr, "Failed to verify applications"); hr = CpiApplicationRolesVerifyInstall(&appRoleList); ExitOnFailure(hr, "Failed to verify application roles"); hr = CpiAssembliesVerifyInstall(&asmList); ExitOnFailure(hr, "Failed to verify assemblies"); if (subList.iInstallCount) { hr = CpiSubscriptionsVerifyInstall(&subList); ExitOnFailure(hr, "Failed to verify subscriptions"); } // schedule if (partList.iInstallCount || appList.iInstallCount || usrInAppRoleList.iInstallCount || appRoleList.iInstallCount || asmList.iInstallCount || asmList.iRoleInstallCount || subList.iInstallCount) { // create rollback file name hr = CpiGetTempFileName(&pwzRollbackFileName); ExitOnFailure(hr, "Failed to get rollback file name"); // schedule rollback prepare custom action hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLPREPARE, pwzRollbackFileName, 0); ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallPrepare"); // schedule prepare custom action hr = WcaDoDeferredAction(CP_COMPLUSINSTALLPREPARE, pwzRollbackFileName, 0); ExitOnFailure(hr, "Failed to schedule ComPlusInstallPrepare"); // schedule rollback custom action hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzRollbackActionData); ExitOnFailure(hr, "Failed to add rollback file name to rollback custom action data"); hr = CpiSubscriptionsInstall(&subList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install subscriptions"); hr = CpiRoleAssignmentsInstall(&asmList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiAssembliesInstall(&asmList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiUsersInApplicationRolesInstall(&usrInAppRoleList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install users in application roles"); hr = CpiApplicationRolesInstall(&appRoleList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install application roles"); hr = CpiApplicationsInstall(&appList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install applications"); hr = CpiPartitionUsersInstall(&partUsrList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install partition users"); hr = CpiUsersInPartitionRolesInstall(&usrInPartRoleList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install users in partition roles"); hr = CpiPartitionsInstall(&partList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install partitions"); hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLEXECUTE, pwzRollbackActionData, 0); ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallExecute"); // schedule install custom action hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzActionData); ExitOnFailure(hr, "Failed to add rollback file name to custom action data"); hr = CpiPartitionsInstall(&partList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install partitions"); hr = CpiUsersInPartitionRolesInstall(&usrInPartRoleList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install users in partition roles"); hr = CpiPartitionUsersInstall(&partUsrList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install partition users"); hr = CpiApplicationsInstall(&appList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install applications"); hr = CpiApplicationRolesInstall(&appRoleList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install application roles"); hr = CpiUsersInApplicationRolesInstall(&usrInAppRoleList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install users in application roles"); hr = CpiAssembliesInstall(&asmList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiRoleAssignmentsInstall(&asmList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiSubscriptionsInstall(&subList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install subscriptions"); hr = WcaDoDeferredAction(CP_COMPLUSINSTALLEXECUTE, pwzActionData, iProgress); ExitOnFailure(hr, "Failed to schedule ComPlusInstallExecute"); // schedule install commit custom action hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzCommitActionData); ExitOnFailure(hr, "Failed to add rollback file name to commit custom action data"); hr = CpiAssembliesInstall(&asmList, rmCommit, &pwzCommitActionData, &iCommitProgress); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiRoleAssignmentsInstall(&asmList, rmCommit, &pwzCommitActionData, &iCommitProgress); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiSubscriptionsInstall(&subList, rmCommit, &pwzCommitActionData, &iCommitProgress); ExitOnFailure(hr, "Failed to install subscriptions"); hr = WcaDoDeferredAction(CP_COMPLUSINSTALLEXECUTECOMMIT, pwzCommitActionData, iCommitProgress); ExitOnFailure(hr, "Failed to schedule ComPlusInstallExecuteCommit"); // schedule commit custom action hr = WcaDoDeferredAction(CP_COMPLUSINSTALLCOMMIT, pwzRollbackFileName, 0); ExitOnFailure(hr, "Failed to schedule ComPlusInstallCommit"); } hr = S_OK; LExit: // clean up ReleaseObject(piCatalog); ReleaseStr(pwzRollbackFileName); ReleaseStr(pwzActionData); ReleaseStr(pwzRollbackActionData); ReleaseStr(pwzCommitActionData); CpiPartitionListFree(&partList); CpiPartitionRoleListFree(&partRoleList); CpiUserInPartitionRoleListFree(&usrInPartRoleList); CpiPartitionUserListFree(&partUsrList); CpiApplicationListFree(&appList); CpiApplicationRoleListFree(&appRoleList); CpiUserInApplicationRoleListFree(&usrInAppRoleList); CpiAssemblyListFree(&asmList); CpiSubscriptionListFree(&subList); // unitialize CpiFinalize(); if (fInitializedCom) ::CoUninitialize(); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }