static HRESULT AddPartitionToActionData( CPI_PARTITION* pItm, int iActionType, int iActionCost, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; // add action information to custom action data hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData); ExitOnFailure(hr, "Failed to add action type to custom action data"); hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData); ExitOnFailure(hr, "Failed to add action cost to custom action data"); // add partition information to custom action data hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData); ExitOnFailure(hr, "Failed to add partition key to custom action data"); hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData); ExitOnFailure(hr, "Failed to add partition id to custom action data"); hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData); ExitOnFailure(hr, "Failed to add partition name to custom action data"); // add properties to custom action data hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData); ExitOnFailure(hr, "Failed to add properties to custom action data"); hr = S_OK; LExit: return hr; }
HRESULT CpiAddPropertiesToActionData( int iPropCount, CPI_PROPERTY* pPropList, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; hr = WcaWriteIntegerToCaData(iPropCount, ppwzActionData); ExitOnFailure(hr, "Failed to add count to custom action data"); if (iPropCount) // count might be 0 event thought there are elements in the list { for (CPI_PROPERTY* pProp = pPropList; pProp; pProp = pProp->pNext) { hr = WcaWriteStringToCaData(pProp->wzName, ppwzActionData); ExitOnFailure(hr, "Failed to add property name to custom action data, name: %S", pProp->wzName); hr = WcaWriteStringToCaData(pProp->pwzValue, ppwzActionData); ExitOnFailure(hr, "Failed to add property value to custom action data, name: %S", pProp->wzName); } } hr = S_OK; LExit: return hr; }
static HRESULT AddPartitionUserToActionData( CPI_PARTITION_USER* pItm, int iActionType, int iActionCost, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; // add action information to custom action data hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData); ExitOnFailure(hr, "Failed to add action type to custom action data"); hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData); ExitOnFailure(hr, "Failed to add action cost to custom action data"); // add partition user information to custom action data hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData); ExitOnFailure(hr, "Failed to add partition user key to custom action data"); hr = WcaWriteStringToCaData(pItm->pwzAccount, ppwzActionData); ExitOnFailure(hr, "Failed to add user account to custom action data"); // add partition information to custom action data hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pPartition->wzID : L"", ppwzActionData); ExitOnFailure(hr, "Failed to add partition id to custom action data"); hr = S_OK; LExit: return hr; }
static HRESULT AddMessageQueueToActionData( MQI_MESSAGE_QUEUE* pItm, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; // add message queue information to custom action data hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData); ExitOnFailure(hr, "Failed to add key to custom action data"); hr = WcaWriteIntegerToCaData(pItm->iBasePriority, ppwzActionData); ExitOnFailure(hr, "Failed to add base priority to custom action data"); hr = WcaWriteIntegerToCaData(pItm->iJournalQuota, ppwzActionData); ExitOnFailure(hr, "Failed to add journal quota to custom action data"); hr = WcaWriteStringToCaData(pItm->wzLabel, ppwzActionData); ExitOnFailure(hr, "Failed to add label to custom action data"); hr = WcaWriteStringToCaData(pItm->wzMulticastAddress, ppwzActionData); ExitOnFailure(hr, "Failed to add multicast address to custom action data"); hr = WcaWriteStringToCaData(pItm->wzPathName, ppwzActionData); ExitOnFailure(hr, "Failed to add path name to custom action data"); hr = WcaWriteIntegerToCaData(pItm->iPrivLevel, ppwzActionData); ExitOnFailure(hr, "Failed to add privacy level to custom action data"); hr = WcaWriteIntegerToCaData(pItm->iQuota, ppwzActionData); ExitOnFailure(hr, "Failed to add quota to custom action data"); hr = WcaWriteStringToCaData(pItm->wzServiceTypeGuid, ppwzActionData); ExitOnFailure(hr, "Failed to add service type guid to custom action data"); hr = WcaWriteIntegerToCaData(pItm->iAttributes, ppwzActionData); ExitOnFailure(hr, "Failed to add attributes to custom action data"); hr = S_OK; LExit: return hr; }
static HRESULT AddUserInPartitionRoleToActionData( CPI_USER_IN_PARTITION_ROLE* pItm, int iActionType, int iActionCost, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; // add action information to custom action data hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData); ExitOnFailure(hr, "Failed to add action type to custom action data"); hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData); ExitOnFailure(hr, "Failed to add action cost to custom action data"); // add application role information to custom action data hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData); ExitOnFailure(hr, "Failed to add key to custom action data"); hr = WcaWriteStringToCaData(pItm->pPartitionRole->wzName, ppwzActionData); ExitOnFailure(hr, "Failed to add role name to custom action data"); hr = WcaWriteStringToCaData(pItm->pwzAccount, ppwzActionData); ExitOnFailure(hr, "Failed to add user account to custom action data"); // add partition information to custom action data hr = WcaWriteStringToCaData(pItm->pPartitionRole->pPartition->wzID, ppwzActionData); ExitOnFailure(hr, "Failed to add partition id to custom action data"); hr = S_OK; LExit: return hr; }
static HRESULT BeginChangeFile( __in LPCWSTR pwzFile, __in int iCompAttributes, __inout LPWSTR* ppwzCustomActionData ) { Assert(pwzFile && *pwzFile && ppwzCustomActionData); HRESULT hr = S_OK; BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit; LPBYTE pbData = NULL; DWORD cbData = 0; LPWSTR pwzRollbackCustomActionData = NULL; if (fIs64Bit) { hr = WcaWriteIntegerToCaData((int)xaOpenFilex64, ppwzCustomActionData); ExitOnFailure(hr, "failed to write 64-bit file indicator to custom action data"); } else { hr = WcaWriteIntegerToCaData((int)xaOpenFile, ppwzCustomActionData); ExitOnFailure(hr, "failed to write file indicator to custom action data"); } hr = WcaWriteStringToCaData(pwzFile, ppwzCustomActionData); ExitOnFailure1(hr, "failed to write file to custom action data: %ls", pwzFile); // If the file already exits, then we have to put it back the way it was on failure if (FileExistsEx(pwzFile, NULL)) { hr = FileRead(&pbData, &cbData, pwzFile); ExitOnFailure1(hr, "failed to read file: %ls", pwzFile); // Set up the rollback for this file hr = WcaWriteIntegerToCaData((int)fIs64Bit, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to write component bitness to rollback custom action data"); hr = WcaWriteStringToCaData(pwzFile, &pwzRollbackCustomActionData); ExitOnFailure1(hr, "failed to write file name to rollback custom action data: %ls", pwzFile); hr = WcaWriteStreamToCaData(pbData, cbData, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to write file contents to rollback custom action data."); hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"ExecXmlConfigRollback"), pwzRollbackCustomActionData, COST_XMLFILE); ExitOnFailure1(hr, "failed to schedule ExecXmlConfigRollback for file: %ls", pwzFile); ReleaseStr(pwzRollbackCustomActionData); } LExit: ReleaseMem(pbData); return hr; }
static HRESULT WriteGroupInfo( __in SCA_GROUP* psgList, __in LPWSTR *ppwzActionData ) { HRESULT hr = S_OK; for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext) { hr = WcaWriteStringToCaData(psg->wzName, ppwzActionData); ExitOnFailure1(hr, "failed to add group name to custom action data: %ls", psg->wzName); hr = WcaWriteStringToCaData(psg->wzDomain, ppwzActionData); ExitOnFailure1(hr, "failed to add group domain to custom action data: %ls", psg->wzDomain); } LExit: return hr; }
static HRESULT AddSubscriptionToActionData( CPI_SUBSCRIPTION* pItm, int iActionType, int iActionCost, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; // add action information to custom action data hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData); ExitOnFailure(hr, "Failed to add action type to custom action data"); hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData); ExitOnFailure(hr, "Failed to add action cost to custom action data"); // add application role information to custom action data hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData); ExitOnFailure(hr, "Failed to add subscription key to custom action data"); hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData); ExitOnFailure(hr, "Failed to add subscription id to custom action data"); hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData); ExitOnFailure(hr, "Failed to add subscription name to custom action data"); hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->wzEventCLSID : L"", ppwzActionData); ExitOnFailure(hr, "Failed to add assembly tlb path to custom action data"); hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->wzPublisherID : L"", ppwzActionData); ExitOnFailure(hr, "Failed to add assembly proxy-stub dll path to custom action data"); // add component information to custom action data hr = WcaWriteStringToCaData(pItm->pComponent->wzCLSID, ppwzActionData); ExitOnFailure(hr, "Failed to add application id to custom action data"); // add application information to custom action data hr = WcaWriteStringToCaData(pItm->pAssembly->pApplication->wzID, ppwzActionData); ExitOnFailure(hr, "Failed to add application id to custom action data"); // add partition information to custom action data LPCWSTR pwzPartID = pItm->pAssembly->pApplication->pPartition ? pItm->pAssembly->pApplication->pPartition->wzID : L""; hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData); ExitOnFailure(hr, "Failed to add partition id to custom action data"); // add properties to custom action data hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData); ExitOnFailure(hr, "Failed to add properties to custom action data"); hr = S_OK; LExit: return hr; }
// Behaves like WriteGroupInfo, but it filters out groups the user is currently a member of, // because we don't want to rollback those static HRESULT WriteGroupRollbackInfo( __in LPCWSTR pwzName, __in LPCWSTR pwzDomain, __in SCA_GROUP* psgList, __in LPWSTR *ppwzActionData ) { HRESULT hr = S_OK; BOOL fIsMember = FALSE; for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext) { hr = UserCheckIsMember(pwzName, pwzDomain, psg->wzName, psg->wzDomain, &fIsMember); if (FAILED(hr)) { WcaLog(LOGMSG_VERBOSE, "Failed to check if user: %ls (domain: %ls) is member of a group while collecting rollback information (error code 0x%x) - continuing", pwzName, pwzDomain, hr); hr = S_OK; continue; } // If the user is currently a member, we don't want to undo that on rollback, so skip adding // this group record to the list of groups to rollback if (fIsMember) { continue; } hr = WcaWriteStringToCaData(psg->wzName, ppwzActionData); ExitOnFailure1(hr, "failed to add group name to custom action data: %ls", psg->wzName); hr = WcaWriteStringToCaData(psg->wzDomain, ppwzActionData); ExitOnFailure1(hr, "failed to add group domain to custom action data: %ls", psg->wzDomain); } LExit: return hr; }
static HRESULT AddMessageQueuePermissionToActionData( MQI_MESSAGE_QUEUE_PERMISSION* pItm, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; // add message queue information to custom action data hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData); ExitOnFailure(hr, "Failed to add key to custom action data"); hr = WcaWriteStringToCaData(pItm->pMessageQueue->wzPathName, ppwzActionData); ExitOnFailure(hr, "Failed to add path name to custom action data"); hr = WcaWriteStringToCaData(pItm->wzDomain, ppwzActionData); ExitOnFailure(hr, "Failed to add domain to custom action data"); hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData); ExitOnFailure(hr, "Failed to add name to custom action data"); hr = WcaWriteIntegerToCaData(pItm->iPermissions, ppwzActionData); ExitOnFailure(hr, "Failed to add permissions to custom action data"); hr = S_OK; LExit: return hr; }
static HRESULT WriteChangeData( __in XML_CONFIG_CHANGE* pxfc, __in eXmlAction action, __inout LPWSTR* ppwzCustomActionData ) { Assert(pxfc && ppwzCustomActionData); HRESULT hr = S_OK; XML_CONFIG_CHANGE* pxfcAdditionalChanges = NULL; hr = WcaWriteStringToCaData(pxfc->pwzElementPath, ppwzCustomActionData); ExitOnFailure1(hr, "failed to write ElementPath to custom action data: %ls", pxfc->pwzElementPath); hr = WcaWriteStringToCaData(pxfc->pwzVerifyPath, ppwzCustomActionData); ExitOnFailure1(hr, "failed to write VerifyPath to custom action data: %ls", pxfc->pwzVerifyPath); hr = WcaWriteStringToCaData(pxfc->wzName, ppwzCustomActionData); ExitOnFailure1(hr, "failed to write Name to custom action data: %ls", pxfc->wzName); hr = WcaWriteStringToCaData(pxfc->pwzValue, ppwzCustomActionData); ExitOnFailure1(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue); if (pxfc->iXmlFlags & XMLCONFIG_CREATE && pxfc->iXmlFlags & XMLCONFIG_ELEMENT && xaCreateElement == action && pxfc->pxfcAdditionalChanges) { hr = WcaWriteIntegerToCaData(pxfc->cAdditionalChanges, ppwzCustomActionData); ExitOnFailure(hr, "failed to write additional changes value to custom action data"); pxfcAdditionalChanges = pxfc->pxfcAdditionalChanges; while (pxfcAdditionalChanges) { Assert((0 == lstrcmpW(pxfcAdditionalChanges->wzComponent, pxfc->wzComponent)) && 0 == pxfcAdditionalChanges->iXmlFlags && (0 == lstrcmpW(pxfcAdditionalChanges->wzFile, pxfc->wzFile))); hr = WcaWriteStringToCaData(pxfcAdditionalChanges->wzName, ppwzCustomActionData); ExitOnFailure1(hr, "failed to write Name to custom action data: %ls", pxfc->wzName); hr = WcaWriteStringToCaData(pxfcAdditionalChanges->pwzValue, ppwzCustomActionData); ExitOnFailure1(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue); pxfcAdditionalChanges = pxfcAdditionalChanges->pxfcNext; } } else { hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData); ExitOnFailure(hr, "failed to write additional changes value to custom action data"); } LExit: return hr; }
HRESULT SchedDropDatabase( __in LPCWSTR wzKey, __in LPCWSTR wzServer, __in LPCWSTR wzInstance, __in LPCWSTR wzDatabase, __in int iAttributes, __in BOOL fIntegratedAuth, __in LPCWSTR wzUser, __in LPCWSTR wzPassword ) { HRESULT hr = S_OK; WCHAR* pwzCustomActionData = NULL; hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData); ExitOnFailure(hr, "failed to add DBKey to CustomActionData"); hr = WcaWriteStringToCaData(wzServer, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add server name to CustomActionData"); hr = WcaWriteStringToCaData(wzInstance, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add server instance to CustomActionData"); hr = WcaWriteStringToCaData(wzDatabase, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add database name to CustomActionData"); hr = WcaWriteIntegerToCaData(iAttributes, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add server name to CustomActionData"); hr = WcaWriteStringToCaData(fIntegratedAuth ? L"1" : L"0", &pwzCustomActionData); ExitOnFailure(hr, "Failed to add server name to CustomActionData"); hr = WcaWriteStringToCaData(wzUser, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add server user to CustomActionData"); hr = WcaWriteStringToCaData(wzPassword, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add user password to CustomActionData"); hr = WcaDoDeferredAction(L"DropDatabase", pwzCustomActionData, COST_SQL_DROPDB); ExitOnFailure(hr, "Failed to schedule DropDatabase action"); LExit: ReleaseStr(pwzCustomActionData); return hr; }
HRESULT CpiAddActionTextToActionData( LPCWSTR pwzAction, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; PMSIHANDLE hView, hRecKey, hRec; LPWSTR pwzDescription = NULL; LPWSTR pwzTemplate = NULL; if (S_OK == WcaTableExists(L"ActionText")) { // create parameter record hRecKey = ::MsiCreateRecord(1); ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); hr = WcaSetRecordString(hRecKey, 1, pwzAction); ExitOnFailure(hr, "Failed to set record string"); // open view hr = WcaOpenView(vcsActionTextQuery, &hView); ExitOnFailure(hr, "Failed to open view on ActionText table"); hr = WcaExecuteView(hView, hRecKey); ExitOnFailure(hr, "Failed to execute view on ActionText table"); // fetch record hr = WcaFetchSingleRecord(hView, &hRec); if (S_FALSE != hr) { ExitOnFailure(hr, "Failed to fetch action text record"); // get description hr = WcaGetRecordString(hRec, atqDescription, &pwzDescription); ExitOnFailure(hr, "Failed to get description"); // get template hr = WcaGetRecordString(hRec, atqTemplate, &pwzTemplate); ExitOnFailure(hr, "Failed to get template"); } } // add action name to action data hr = WcaWriteStringToCaData(pwzAction, ppwzActionData); ExitOnFailure(hr, "Failed to add action name to custom action data"); // add description to action data hr = WcaWriteStringToCaData(pwzDescription ? pwzDescription : L"", ppwzActionData); ExitOnFailure(hr, "Failed to add description to custom action data"); // add template to action data hr = WcaWriteStringToCaData(pwzTemplate ? pwzTemplate : L"", ppwzActionData); ExitOnFailure(hr, "Failed to add template to custom action data"); hr = S_OK; LExit: // clean up ReleaseStr(pwzDescription); ReleaseStr(pwzTemplate); return hr; }
static HRESULT SchedCreateDatabase( __in SCA_DB* psd ) { HRESULT hr = S_OK; WCHAR* pwzCustomActionData = NULL; hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData); ExitOnFailure(hr, "failed to add DBKey to CustomActionData"); hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add server name to CustomActionData"); hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add server instance to CustomActionData"); hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add database name to CustomActionData"); hr = WcaWriteIntegerToCaData(psd->iAttributes, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add Sql attributes to CustomActionData"); hr = WcaWriteStringToCaData(psd->fUseIntegratedAuth ? L"1" : L"0", &pwzCustomActionData); ExitOnFailure(hr, "Failed to add if integrated connection to CustomActionData"); hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add server user to CustomActionData"); hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add user password to CustomActionData"); // Check to see if the database exists, if it does not then schedule a rollback // so we clean up after ourselves if the creation of the database fails or is // aborted. It is interesting to note that we can do this check here because the // deferred CustomActions are Impersonated. That means this scheduling action and // the execution actions all run with the same user context, so it is safe to // to do the check. hr = SqlDatabaseExists(psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword, NULL); if (S_FALSE == hr) { hr = WcaDoDeferredAction(L"RollbackCreateDatabase", pwzCustomActionData, COST_SQL_CREATEDB); ExitOnFailure(hr, "Failed to schedule RollbackCreateDatabase action"); } // database filespec if (psd->fHasDbSpec) { hr = WcaWriteStringToCaData(L"1", &pwzCustomActionData); ExitOnFailure(hr, "failed to specify that do have db.filespec to CustomActionData"); hr = WcaWriteStringToCaData(psd->sfDb.wzName, &pwzCustomActionData); ExitOnFailure(hr, "failed to add FileSpec.Name to CustomActionData"); hr = WcaWriteStringToCaData(psd->sfDb.wzFilename, &pwzCustomActionData); ExitOnFailure(hr, "failed to add FileSpec.Filename to CustomActionData"); hr = WcaWriteStringToCaData(psd->sfDb.wzSize, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add FileSpec.Size to CustomActionData"); hr = WcaWriteStringToCaData(psd->sfDb.wzMaxSize, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add FileSpec.MaxSize to CustomActionData"); hr = WcaWriteStringToCaData(psd->sfDb.wzGrow, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add FileSpec.GrowthSize to CustomActionData"); } else { hr = WcaWriteStringToCaData(L"0", &pwzCustomActionData); ExitOnFailure(hr, "failed to specify that do not have db.filespec to CustomActionData"); } // log filespec if (psd->fHasLogSpec) { hr = WcaWriteStringToCaData(L"1", &pwzCustomActionData); ExitOnFailure(hr, "failed to specify that do have log.filespec to CustomActionData"); hr = WcaWriteStringToCaData(psd->sfLog.wzName, &pwzCustomActionData); ExitOnFailure(hr, "failed to add FileSpec.Name to CustomActionData"); hr = WcaWriteStringToCaData(psd->sfLog.wzFilename, &pwzCustomActionData); ExitOnFailure(hr, "failed to add FileSpec.Filename to CustomActionData"); hr = WcaWriteStringToCaData(psd->sfLog.wzSize, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add FileSpec.Size to CustomActionData"); hr = WcaWriteStringToCaData(psd->sfLog.wzMaxSize, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add FileSpec.MaxSize to CustomActionData"); hr = WcaWriteStringToCaData(psd->sfLog.wzGrow, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add FileSpec.GrowthSize to CustomActionData"); } else { hr = WcaWriteStringToCaData(L"0", &pwzCustomActionData); ExitOnFailure(hr, "failed to specify that do not have log.filespec to CustomActionData"); } // schedule the CreateDatabase action hr = WcaDoDeferredAction(L"CreateDatabase", pwzCustomActionData, COST_SQL_CREATEDB); ExitOnFailure(hr, "Failed to schedule CreateDatabase action"); LExit: ReleaseStr(pwzCustomActionData); return hr; }
/****************************************************************** SchedNetFx - entry point for NetFx Custom Action ********************************************************************/ extern "C" UINT __stdcall SchedNetFx( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedNetFx"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzInstallCustomActionData = NULL; LPWSTR pwzUninstallCustomActionData = NULL; UINT uiCost = 0; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; PMSIHANDLE hViewGac = NULL; PMSIHANDLE hRecGac = NULL; LPWSTR pwzId = NULL; LPWSTR pwzData = NULL; LPWSTR pwzTemp = NULL; LPWSTR pwzFile = NULL; int iPriority = 0; int iAssemblyCost = 0; int iAttributes = 0; LPWSTR pwzFileApp = NULL; LPWSTR pwzDirAppBase = NULL; LPWSTR pwzComponent = NULL; INSTALLSTATE isInstalled; INSTALLSTATE isAction; LPWSTR pwz32Ngen = NULL; LPWSTR pwz64Ngen = NULL; BOOL f32NgenExeExists = FALSE; BOOL f64NgenExeExists = FALSE; BOOL fNeedInstallUpdate32 = FALSE; BOOL fNeedUninstallUpdate32 = FALSE; BOOL fNeedInstallUpdate64 = FALSE; BOOL fNeedUninstallUpdate64 = FALSE; // initialize hr = WcaInitialize(hInstall, "SchedNetFx"); ExitOnFailure(hr, "failed to initialize"); hr = GetNgenPath(&pwz32Ngen, FALSE); f32NgenExeExists = SUCCEEDED(hr); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) { hr = ERROR_SUCCESS; WcaLog(LOGMSG_STANDARD, "Failed to find 32bit ngen. No actions will be scheduled to create native images for 32bit."); } ExitOnFailure(hr, "failed to get 32bit ngen.exe path"); hr = GetNgenPath(&pwz64Ngen, TRUE); f64NgenExeExists = SUCCEEDED(hr); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) { hr = ERROR_SUCCESS; WcaLog(LOGMSG_STANDARD, "Failed to find 64bit ngen. No actions will be scheduled to create native images for 64bit."); } ExitOnFailure(hr, "failed to get 64bit ngen.exe path"); // loop through all the NetFx records hr = WcaOpenExecuteView(vcsNgenQuery, &hView); ExitOnFailure(hr, "failed to open view on NetFxNativeImage table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // Get Id hr = WcaGetRecordString(hRec, ngqId, &pwzId); ExitOnFailure(hr, "failed to get NetFxNativeImage.NetFxNativeImage"); // Get File hr = WcaGetRecordString(hRec, ngqFile, &pwzData); ExitOnFailure1(hr, "failed to get NetFxNativeImage.File_ for record: %ls", pwzId); hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedFile, pwzData); ExitOnFailure1(hr, "failed to format file string for file: %ls", pwzData); hr = WcaGetFormattedString(pwzTemp, &pwzFile); ExitOnFailure1(hr, "failed to get formatted string for file: %ls", pwzData); // Get Priority hr = WcaGetRecordInteger(hRec, ngqPriority, &iPriority); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Priority for record: %ls", pwzId); if (0 == iPriority) iAssemblyCost = COST_NGEN_BLOCKING; else iAssemblyCost = COST_NGEN_NONBLOCKING; // Get Attributes hr = WcaGetRecordInteger(hRec, ngqAttributes, &iAttributes); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Attributes for record: %ls", pwzId); // Get File_Application or leave pwzFileApp NULL. hr = WcaGetRecordFormattedString(hRec, ngqFileApp, &pwzData); ExitOnFailure1(hr, "failed to get NetFxNativeImage.File_Application for record: %ls", pwzId); // Check if the value resolves to a valid file ID. if (S_OK == FileIdExists(pwzData)) { // Resolve the file ID to a path. hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedFile, pwzData); ExitOnFailure1(hr, "failed to format file application string for file: %ls", pwzData); hr = WcaGetFormattedString(pwzTemp, &pwzFileApp); ExitOnFailure1(hr, "failed to get formatted string for file application: %ls", pwzData); } else { // Assume record formatted to a path already. hr = StrAllocString(&pwzFileApp, pwzData, 0); ExitOnFailure1(hr, "failed to allocate string for file path: %ls", pwzData); hr = PathEnsureQuoted(&pwzFileApp, FALSE); ExitOnFailure1(hr, "failed to quote file path: %ls", pwzData); } // Get Directory_ApplicationBase or leave pwzDirAppBase NULL. hr = WcaGetRecordFormattedString(hRec, ngqDirAppBase, &pwzData); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Directory_ApplicationBase for record: %ls", pwzId); if (WcaIsUnicodePropertySet(pwzData)) { // Resolve the directory ID to a path. hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedDirectory, pwzData); ExitOnFailure1(hr, "failed to format directory application base string for property: %ls", pwzData); hr = WcaGetFormattedString(pwzTemp, &pwzDirAppBase); ExitOnFailure1(hr, "failed to get formatted string for directory application base: %ls", pwzData); } else { // Assume record formatted to a path already. hr = StrAllocString(&pwzDirAppBase, pwzData, 0); ExitOnFailure1(hr, "failed to allocate string for directory path: %ls", pwzData); hr = PathEnsureQuoted(&pwzDirAppBase, TRUE); ExitOnFailure1(hr, "failed to quote and backslashify directory: %ls", pwzData); } // Get Component hr = WcaGetRecordString(hRec, ngqComponent, &pwzComponent); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Directory_ApplicationBase for record: %ls", pwzId); er = ::MsiGetComponentStateW(hInstall, pwzComponent, &isInstalled, &isAction); ExitOnWin32Error1(er, hr, "failed to get install state for Component: %ls", pwzComponent); // // Figure out if it's going to be GAC'd. The possibility exists that no assemblies are going to be GAC'd // so we have to check for the MsiAssembly table first. // if (S_OK == WcaTableExists(L"MsiAssembly")) { hr = WcaOpenView(vcsNgenGac, &hViewGac); ExitOnFailure(hr, "failed to open view on File/MsiAssembly table"); hr = WcaExecuteView(hViewGac, hRec); ExitOnFailure(hr, "failed to execute view on File/MsiAssembly table"); hr = WcaFetchSingleRecord(hViewGac, &hRecGac); ExitOnFailure(hr, "failed to fetch File_Assembly from File/MsiAssembly table"); if (S_FALSE != hr) { hr = WcaGetRecordString(hRecGac, nggApplication, &pwzData); ExitOnFailure(hr, "failed to get MsiAssembly.File_Application"); // If it's in the GAC replace the file name with the strong name if (L'\0' == pwzData[0]) { hr = GetStrongName(&pwzFile, pwzComponent); ExitOnFailure1(hr, "failed to get strong name for component: %ls", pwzData); } } } // // Schedule the work // if (!(iAttributes & NGEN_32BIT) && !(iAttributes & NGEN_64BIT)) ExitOnFailure1(hr = E_INVALIDARG, "Neither 32bit nor 64bit is specified for NGEN of file: %ls", pwzFile); if (WcaIsInstalling(isInstalled, isAction) || WcaIsReInstalling(isInstalled, isAction)) { if (iAttributes & NGEN_32BIT && f32NgenExeExists) { // Assemble the install command line hr = CreateInstallCommand(&pwzData, pwz32Ngen, pwzFile, iPriority, iAttributes, pwzFileApp, pwzDirAppBase); ExitOnFailure(hr, "failed to create install command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(iAssemblyCost, &pwzInstallCustomActionData); ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += iAssemblyCost; fNeedInstallUpdate32 = TRUE; } if (iAttributes & NGEN_64BIT && f64NgenExeExists) { // Assemble the install command line hr = CreateInstallCommand(&pwzData, pwz64Ngen, pwzFile, iPriority, iAttributes, pwzFileApp, pwzDirAppBase); ExitOnFailure(hr, "failed to create install command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(iAssemblyCost, &pwzInstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += iAssemblyCost; fNeedInstallUpdate64 = TRUE; } } else if (WcaIsUninstalling(isInstalled, isAction)) { if (iAttributes & NGEN_32BIT && f32NgenExeExists) { hr = StrAllocFormatted(&pwzData, L"%s uninstall %s", pwz32Ngen, pwzFile); ExitOnFailure(hr, "failed to create update 32 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; fNeedUninstallUpdate32 = TRUE; } if (iAttributes & NGEN_64BIT && f64NgenExeExists) { hr = StrAllocFormatted(&pwzData, L"%s uninstall %s", pwz64Ngen, pwzFile); ExitOnFailure(hr, "failed to create update 64 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; fNeedUninstallUpdate64 = TRUE; } } } if (E_NOMOREITEMS == hr) hr = S_OK; ExitOnFailure(hr, "failed while looping through all files to create native images for"); // If we need 32 bit install update if (fNeedInstallUpdate32) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz32Ngen); ExitOnFailure(hr, "failed to create install update 32 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to install custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzInstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to install custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // If we need 32 bit uninstall update if (fNeedUninstallUpdate32) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz32Ngen); ExitOnFailure(hr, "failed to create uninstall update 32 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to uninstall custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to uninstall custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // If we need 64 bit install update if (fNeedInstallUpdate64) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz64Ngen); ExitOnFailure(hr, "failed to create install update 64 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to install custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzInstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to install custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // If we need 64 bit install update if (fNeedUninstallUpdate64) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz64Ngen); ExitOnFailure(hr, "failed to create uninstall update 64 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to uninstall custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to uninstall custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // Add to progress bar if ((pwzInstallCustomActionData && *pwzInstallCustomActionData) || (pwzUninstallCustomActionData && *pwzUninstallCustomActionData)) { hr = WcaProgressMessage(uiCost, TRUE); ExitOnFailure(hr, "failed to extend progress bar for NetFxExecuteNativeImage"); } // Schedule the install custom action if (pwzInstallCustomActionData && *pwzInstallCustomActionData) { hr = WcaSetProperty(L"NetFxExecuteNativeImageInstall", pwzInstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageInstall action"); hr = WcaSetProperty(L"NetFxExecuteNativeImageCommitInstall", pwzInstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageCommitInstall action"); } // Schedule the uninstall custom action if (pwzUninstallCustomActionData && *pwzUninstallCustomActionData) { hr = WcaSetProperty(L"NetFxExecuteNativeImageUninstall", pwzUninstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageUninstall action"); hr = WcaSetProperty(L"NetFxExecuteNativeImageCommitUninstall", pwzUninstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageCommitUninstall action"); } LExit: ReleaseStr(pwzInstallCustomActionData); ReleaseStr(pwzUninstallCustomActionData); ReleaseStr(pwzId); ReleaseStr(pwzData); ReleaseStr(pwzTemp); ReleaseStr(pwzFile); ReleaseStr(pwzFileApp); ReleaseStr(pwzDirAppBase); ReleaseStr(pwzComponent); ReleaseStr(pwz32Ngen); ReleaseStr(pwz64Ngen); if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** SchedSecureObjects - entry point for SchedSecureObjects Custom Action called as Type 1 CustomAction (binary DLL) from Windows Installer in InstallExecuteSequence, to schedule ExecSecureObjects ******************************************************************/ extern "C" UINT __stdcall SchedSecureObjects( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedSecureObjects"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzSecureObject = NULL; LPWSTR pwzData = NULL; LPWSTR pwzTable = NULL; LPWSTR pwzTargetPath = NULL; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; INSTALLSTATE isInstalled; INSTALLSTATE isAction; LPWSTR pwzCustomActionData = NULL; DWORD cObjects = 0; eOBJECTTYPE eType = OT_UNKNOWN; // // initialize // hr = WcaInitialize(hInstall, "SchedSecureObjects"); ExitOnFailure(hr, "failed to initialize"); // anything to do? if (S_OK != WcaTableExists(L"SecureObjects")) { WcaLog(LOGMSG_STANDARD, "SecureObjects table doesn't exist, so there are no objects to secure."); ExitFunction(); } // // loop through all the objects to be secured // hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView); ExitOnFailure(hr, "failed to open view on SecureObjects table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable); ExitOnFailure(hr, "failed to get object table"); eType = EObjectTypeFromString(pwzTable); if (OT_UNKNOWN == eType) { ExitOnFailure1(hr = E_INVALIDARG, "unknown SecureObject.Table: %ls", pwzTable); } int iCompAttributes = 0; hr = WcaGetRecordInteger(hRec, QSO_COMPATTRIBUTES, &iCompAttributes); ExitOnFailure(hr, "failed to get Component attributes for secure object"); BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit; // Only process entries in the SecureObjects table whose components match the bitness of this CA #ifdef _WIN64 if (!fIs64Bit) { continue; } #else if (fIs64Bit) { continue; } #endif // Get the object to secure hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject); ExitOnFailure(hr, "failed to get name of object"); hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath); ExitOnFailure1(hr, "failed to get target path of object '%ls'", pwzSecureObject); hr = WcaGetRecordString(hRec, QSO_COMPONENT, &pwzData); ExitOnFailure(hr, "failed to get Component name for secure object"); // // if we are installing this Component // er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %ls", pwzData); if (WcaIsInstalling(isInstalled, isAction)) { hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); // add the data to the CustomActionData hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzData); ExitOnFailure(hr, "failed to get name of object"); hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordFormattedString(hRec, QSO_DOMAIN, &pwzData); ExitOnFailure(hr, "failed to get domain for user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordFormattedString(hRec, QSO_USER, &pwzData); ExitOnFailure(hr, "failed to get user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSO_PERMISSION, &pwzData); ExitOnFailure(hr, "failed to get permission to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); ++cObjects; } } // if we looped through all records all is well if (E_NOMOREITEMS == hr) hr = S_OK; ExitOnFailure(hr, "failed while looping through all objects to secure"); // // schedule the custom action and add to progress bar // if (pwzCustomActionData && *pwzCustomActionData) { Assert(0 < cObjects); hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"ExecSecureObjects"), pwzCustomActionData, cObjects * COST_SECUREOBJECT); ExitOnFailure(hr, "failed to schedule ExecSecureObjects action"); } LExit: ReleaseStr(pwzSecureObject); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); ReleaseStr(pwzTable); ReleaseStr(pwzTargetPath); if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/****************************************************************** SchedAddinRegistration - entry point for AddinRegistration Custom Action ********************************************************************/ HRESULT SchedAddinRegistration(MSIHANDLE hInstall, BOOL fInstall) { // AssertSz(FALSE, "debug SchedRegisterAddins"); HRESULT hr = S_OK; LPWSTR pwzCustomActionData = NULL; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; LPWSTR pwzData = NULL; LPWSTR pwzTemp = NULL; LPWSTR pwzComponent = NULL; LPWSTR pwzId = NULL; LPWSTR pwzFile = NULL; LPWSTR pwzFriendlyName = NULL; LPWSTR pwzDescription = NULL; int iBitness = 0; int iCommandLineSafe = 1; int iLoadBehavior = 0; LPWSTR pwzAllUsers = NULL; int nAddins = 0; hr = WcaGetProperty(L"ALLUSERS", &pwzAllUsers); ExitOnFailure(hr, "failed to read value of ALLUSERS property"); // loop through all the RegisterAddin records hr = WcaOpenExecuteView(vcsRegisterAddinsQuery, &hView); ExitOnFailure(hr, "failed to open view on AddinRegistration table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { ++nAddins; // Get Id hr = WcaGetRecordString(hRec, arqId, &pwzId); ExitOnFailure(hr, "failed to get AddinRegistration.AddinRegistration"); // Get File hr = WcaGetRecordString(hRec, arqFile, &pwzData); ExitOnFailure1(hr, "failed to get AddinRegistration.File_ for record: %ls", pwzId); hr = StrAllocFormatted(&pwzTemp, L"[#%ls]", pwzData); ExitOnFailure1(hr, "failed to format file string for file: %ls", pwzData); hr = WcaGetFormattedString(pwzTemp, &pwzFile); ExitOnFailure1(hr, "failed to get formatted string for file: %ls", pwzData); // Get name hr = WcaGetRecordFormattedString(hRec, arqName, &pwzFriendlyName); ExitOnFailure1(hr, "failed to get AddinRegistration.Name for record: %ls", pwzId); // Get description hr = WcaGetRecordFormattedString(hRec, arqDescription, &pwzDescription); ExitOnFailure1(hr, "failed to get AddinRegistration.Description for record: %ls", pwzId); // Get description hr = WcaGetRecordInteger(hRec, arqBitness, &iBitness); ExitOnFailure1(hr, "failed to get AddinRegistration.Bitnesss for record: %ls", pwzId); // Get description hr = WcaGetRecordInteger(hRec, arqCommandLineSafe, &iCommandLineSafe); ExitOnFailure1(hr, "failed to get AddinRegistration.CommandLineSafe for record: %ls", pwzId); // Get description hr = WcaGetRecordInteger(hRec, arqLoadBehavior, &iLoadBehavior); ExitOnFailure1(hr, "failed to get AddinRegistration.LoadBehavior for record: %ls", pwzId); // get component and its install/action states hr = WcaGetRecordString(hRec, arqComponent, &pwzComponent); ExitOnFailure(hr, "failed to get addin component id"); // we need to know if the component's being installed, uninstalled, or reinstalled WCA_TODO todo = WcaGetComponentToDo(pwzComponent); // skip this entry if this is the install CA and we are uninstalling the component if (fInstall && WCA_TODO_UNINSTALL == todo) { continue; } // skip this entry if this is an uninstall CA and we are not uninstalling the component if (!fInstall && WCA_TODO_UNINSTALL != todo) { continue; } // write custom action data: operation, instance guid, path, directory hr = WcaWriteIntegerToCaData(todo, &pwzCustomActionData); ExitOnFailure1(hr, "failed to write operation to custom action data for instance id: %ls", pwzId); hr = WcaWriteStringToCaData(pwzId, &pwzCustomActionData); ExitOnFailure1(hr, "failed to write id to custom action data for instance id: %ls", pwzId); hr = WcaWriteStringToCaData(pwzFile, &pwzCustomActionData); ExitOnFailure1(hr, "failed to write custom action data for instance id: %ls", pwzId); hr = WcaWriteStringToCaData(pwzFriendlyName, &pwzCustomActionData); ExitOnFailure1(hr, "failed to write addin name to custom action data for instance id: %ls", pwzId); hr = WcaWriteStringToCaData(pwzDescription, &pwzCustomActionData); ExitOnFailure1(hr, "failed to write addin description to custom action data for instance id: %ls", pwzId); hr = WcaWriteIntegerToCaData(iBitness, &pwzCustomActionData); ExitOnFailure1(hr, "failed to write Bitness to custom action data for instance id: %ls", pwzId); hr = WcaWriteIntegerToCaData(iCommandLineSafe, &pwzCustomActionData); ExitOnFailure1(hr, "failed to write CommandLineSafe to custom action data for instance id: %ls", pwzId); hr = WcaWriteIntegerToCaData(iLoadBehavior, &pwzCustomActionData); ExitOnFailure1(hr, "failed to write LoadBehavior to custom action data for instance id: %ls", pwzId); hr = WcaWriteStringToCaData(pwzAllUsers, &pwzCustomActionData); ExitOnFailure(hr, "failed to write allusers property to custom action data for instance id: %ls", pwzId); } if (E_NOMOREITEMS == hr) hr = S_OK; ExitOnFailure(hr, "failed while looping through all files to create native images for"); // Schedule the install custom action if (pwzCustomActionData && *pwzCustomActionData) { WcaLog(LOGMSG_STANDARD, "Scheduling Addin Registration (%ls)", pwzCustomActionData); hr = WcaDoDeferredAction(L"RollbackAddinRegistration", pwzCustomActionData, nAddins * COST_REGISTER_ADDIN); ExitOnFailure(hr, "Failed to schedule addin registration rollback"); hr = WcaDoDeferredAction(L"ExecAddinRegistration", pwzCustomActionData, nAddins * COST_REGISTER_ADDIN); ExitOnFailure(hr, "Failed to schedule addin registration execution"); } LExit: ReleaseStr(pwzAllUsers); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzId); ReleaseStr(pwzData); ReleaseStr(pwzData); ReleaseStr(pwzTemp); ReleaseStr(pwzComponent); ReleaseStr(pwzFile); ReleaseStr(pwzFriendlyName); ReleaseStr(pwzDescription); return hr; }
/****************************************************************** CaSchedServiceConfig - entry point for CaSchedServiceConfig Custom Action called as Type 1 CustomAction (binary DLL) from Windows Installer in InstallExecuteSequence before CaExecServiceConfig ********************************************************************/ extern "C" UINT __stdcall SchedServiceConfig( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedServiceConfig"); HRESULT hr = S_OK; UINT uiResult = ERROR_SUCCESS; DWORD dwError = 0; LPWSTR pwzData = NULL; int iData = 0; BOOL fExistingService = FALSE; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; INSTALLSTATE isInstalled; INSTALLSTATE isAction; SC_HANDLE hSCM = NULL; SC_HANDLE hService = NULL; LPSERVICE_FAILURE_ACTIONSW psfa; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzRollbackCustomActionData = NULL; DWORD cServices = 0; DWORD dwRestartDelay = 0; WCHAR wzActionName[32] = { 0 }; DWORD dwSizeNeeded = 0; // initialize hr = WcaInitialize(hInstall, "SchedServiceConfig"); ExitOnFailure(hr, "failed to initialize"); //Get a handle to the service control manager hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (hSCM == NULL) ExitOnLastError(hr, "failed to get handle to SCM"); // loop through all the services to be configured hr = WcaOpenExecuteView(wzQUERY_SERVICECONFIG, &hView); ExitOnFailure(hr, "failed to open view on ServiceConfig table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { hr = WcaGetRecordInteger(hRec, QSC_NEWSERVICE, &iData); ExitOnFailure(hr, "failed to get object NewService"); fExistingService = 1 != iData; // Get component name hr = WcaGetRecordString(hRec, QSC_COMPONENT, &pwzData); ExitOnFailure(hr, "failed to get component name"); // check if we are installing this Component hr = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); ExitOnFailure1(hr = HRESULT_FROM_WIN32(hr), "failed to get install state for Component: %S", pwzData); // We want to configure either a service we're installing or one already on the box if (WcaIsInstalling(isInstalled, isAction)) { // Check if we're configuring an existing service if (fExistingService) { // Confirm the service is actually on the box hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData); ExitOnFailure(hr, "failed to get object NewService"); //Get a handle to the service hService = ::OpenServiceW(hSCM, pwzData, SERVICE_QUERY_CONFIG); if (hService == NULL) { dwError = ::GetLastError(); hr = HRESULT_FROM_WIN32(dwError); if (hr == ERROR_SERVICE_DOES_NOT_EXIST) { ExitOnFailure1(hr, "Service \"%s\" does not exist on this system.", pwzData); } else { ExitOnFailure1(hr, "Failed to get handle to the service \"%S\".", pwzData); } } // Get Current Service Config info if(!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, NULL, 0, &dwSizeNeeded) && ERROR_INSUFFICIENT_BUFFER != ::GetLastError()) { ExitOnLastError(hr, "Failed to get current service config info."); } // Alloc space we were told we needed psfa = (LPSERVICE_FAILURE_ACTIONSW) MemAlloc(dwSizeNeeded, TRUE); ExitOnNull(psfa, hr, E_OUTOFMEMORY, "failed to allocate memory for service failure actions."); // Now do the real query if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)psfa, dwSizeNeeded, &dwSizeNeeded)) ExitOnLastError(hr, "failed to Query Service."); // Build up rollback CA data so we can restore service state if necessary hr = WcaWriteStringToCaData(pwzData, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); // If this service struct is empty, fill in defualt values if(psfa->cActions < 3) { hr = WcaWriteStringToCaData(c_wzActionTypeNone, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); hr = WcaWriteStringToCaData(c_wzActionTypeNone, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); hr = WcaWriteStringToCaData(c_wzActionTypeNone, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); } else { // psfa actually had actions defined, so use them // action 1 hr = GetSCActionTypeString(psfa->lpsaActions[0].Type, (LPWSTR)wzActionName, 32); ExitOnFailure(hr, "failed to query SFA object"); if (SC_ACTION_RESTART == psfa->lpsaActions[0].Type) dwRestartDelay = psfa->lpsaActions[0].Delay / 1000; hr = WcaWriteStringToCaData(wzActionName, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); // action 2 hr = GetSCActionTypeString(psfa->lpsaActions[1].Type, (LPWSTR)wzActionName, 32); ExitOnFailure(hr, "failed to query SFA object"); if (SC_ACTION_RESTART == psfa->lpsaActions[1].Type) dwRestartDelay = psfa->lpsaActions[1].Delay / 1000; hr = WcaWriteStringToCaData(wzActionName, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); // action 3 hr = GetSCActionTypeString(psfa->lpsaActions[2].Type, (LPWSTR)wzActionName, 32); ExitOnFailure(hr, "failed to query SFA object"); if (SC_ACTION_RESTART == psfa->lpsaActions[2].Type) dwRestartDelay = psfa->lpsaActions[2].Delay / 1000; hr = WcaWriteStringToCaData(wzActionName, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); } hr = WcaWriteIntegerToCaData(psfa->dwResetPeriod / (24 * 60 * 60), &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaWriteIntegerToCaData(dwRestartDelay, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); // check for value being null if(!psfa->lpCommand) psfa->lpCommand = L""; hr = WcaWriteStringToCaData(psfa->lpCommand, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); // check for value being null if(!psfa->lpRebootMsg) psfa->lpRebootMsg = L""; hr = WcaWriteStringToCaData(psfa->lpRebootMsg, &pwzRollbackCustomActionData); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); // Clear up per-service values if(psfa) MemFree(psfa); } // add the data to the CustomActionData (for install) hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData); ExitOnFailure(hr, "failed to get name of service"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSC_FIRSTFAILUREACTIONTYPE, &pwzData); ExitOnFailure(hr, "failed to get first failure action type"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSC_SECONDFAILUREACTIONTYPE, &pwzData); ExitOnFailure(hr, "failed to get second failure action type"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSC_THIRDFAILUREACTIONTYPE, &pwzData); ExitOnFailure(hr, "failed to get third failure action type"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordInteger(hRec, QSC_RESETPERIODINDAYS, &iData); if (hr == S_FALSE) // deal w/ possible null value iData = 0; ExitOnFailure(hr, "failed to get reset period in days between service restart attempts."); hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordInteger(hRec, QSC_RESTARTSERVICEDELAYINSECONDS, &iData); if (hr == S_FALSE) // deal w/ possible null value iData = 0; ExitOnFailure(hr, "failed to get server restart delay value."); hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSC_PROGRAMCOMMANDLINE, &pwzData); // null value already dealt w/ properly ExitOnFailure(hr, "failed to get command line to run on service failure."); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSC_REBOOTMESSAGE, &pwzData); // null value already dealt w/ properly ExitOnFailure(hr, "failed to get message to send to users when server reboots due to service failure."); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); cServices++; ::CloseServiceHandle(hService); hService = NULL; } } // if we looped through all records all is well if (E_NOMOREITEMS == hr) hr = S_OK; ExitOnFailure(hr, "failed while looping through all objects to secure"); // setup CustomActionData and add to progress bar for download if (pwzRollbackCustomActionData && *pwzRollbackCustomActionData) { Assert(0 < cServices); hr = WcaDoDeferredAction(L"ExecServiceConfigRollback", pwzRollbackCustomActionData, cServices * COST_SERVICECONFIG); ExitOnFailure(hr, "failed to schedule ExecSecureObjects action"); } // schedule the custom action and add to progress bar if (pwzCustomActionData && *pwzCustomActionData) { Assert(0 < cServices); hr = WcaDoDeferredAction(L"ExecServiceConfig", pwzCustomActionData, cServices * COST_SERVICECONFIG); ExitOnFailure(hr, "failed to schedule ExecSecureObjects action"); } LExit: // Clean up handles if (hService != NULL) ::CloseServiceHandle(hService); if (hSCM != NULL) ::CloseServiceHandle(hSCM); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzRollbackCustomActionData); ReleaseStr(pwzData); if (FAILED(hr)) uiResult = ERROR_INSTALL_FAILURE; return WcaFinalize(uiResult); }
/****************************************************************** CaSchedSecureObjects - entry point for CaReadSecureObjects Custom Action called as Type 1 CustomAction (binary DLL) from Windows Installer in InstallExecuteSequence before CaSecureObjects ******************************************************************/ extern "C" UINT __stdcall SchedSecureObjects( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedSecureObjects"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzData = NULL; LPWSTR pwzTable = NULL; LPWSTR pwzTargetPath = NULL; LPWSTR pwzFormattedString = NULL; int iRoot = 0; int iAllUsers = 0; LPWSTR pwzKey = NULL; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; MSIHANDLE hViewObject = NULL; // Don't free this since it's always a copy of either hViewService or hViewCreateFolder PMSIHANDLE hViewService = NULL; PMSIHANDLE hViewCreateFolder = NULL; PMSIHANDLE hViewFile = NULL; PMSIHANDLE hViewRegistry = NULL; PMSIHANDLE hRecObject = NULL; INSTALLSTATE isInstalled; INSTALLSTATE isAction; LPWSTR pwzCustomActionData = NULL; DWORD cchCustomActionData = 0; DWORD cObjects = 0; eOBJECTTYPE eType = OT_UNKNOWN; // // initialize // hr = WcaInitialize(hInstall, "SchedSecureObjects"); ExitOnFailure(hr, "failed to initialize"); // // loop through all the objects to be secured // hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView); ExitOnFailure(hr, "failed to open view on SecureObjects table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { hViewObject = NULL; eType = OT_UNKNOWN; hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable); ExitOnFailure(hr, "failed to get object table"); // ensure we're looking at a known table if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) { eType = OT_SERVICE; } else if (0 == lstrcmpW(L"CreateFolder", pwzTable)) { eType = OT_FOLDER; } else if (0 == lstrcmpW(L"File", pwzTable)) { eType = OT_FILE; } else if (0 == lstrcmpW(L"Registry", pwzTable)) { eType = OT_REGISTRY; } else { ExitOnFailure1(hr = E_INVALIDARG, "unknown SecureObject.Table: %S", pwzTable); } // if we haven't opened a view on the ServiceInstall/CreateFolder table, do that now if (OT_SERVICE == eType) { if (!hViewService) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_SERVICECOMPONENT, &hViewService); ExitOnFailure(hr, "failed to open view on ServiceInstall table"); } hViewObject = hViewService; } else if (OT_FOLDER == eType) { if (!hViewCreateFolder) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_CREATEFOLDERCOMPONENT, &hViewCreateFolder); ExitOnFailure(hr, "failed to open view on CreateFolder table"); } hViewObject = hViewCreateFolder; } else if (OT_FILE== eType) { if (!hViewFile) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_FILECOMPONENT, &hViewFile); ExitOnFailure(hr, "failed to open view on CreateFolder table"); } hViewObject = hViewFile; } else if (OT_REGISTRY== eType) { if (!hViewRegistry) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_REGISTRYCOMPONENT, &hViewRegistry); ExitOnFailure(hr, "failed to open view on CreateFolder table"); } hViewObject = hViewRegistry; } Assert(hViewObject); // execute a view looking for the object's Component_ hr = WcaExecuteView(hViewObject, hRec); ExitOnFailure1(hr, "failed to execute view on %S table", pwzData); hr = WcaFetchSingleRecord(hViewObject, &hRecObject); ExitOnFailure(hr, "failed to fetch Component for secure object"); hr = WcaGetRecordString(hRecObject, QSOC_COMPONENT, &pwzData); ExitOnFailure(hr, "failed to get Component name for secure object"); // // if we are installing this Component // er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %S", pwzData); if (WcaIsInstalling(isInstalled, isAction)) { // add the data to the CustomActionData hr = WcaGetRecordString(hRecObject, QSOC_OBJECTNAME, &pwzData); ExitOnFailure(hr, "failed to get name of object"); if (OT_SERVICE == eType) { hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else if (OT_FOLDER == eType) { hr = WcaGetTargetPath(pwzData, &pwzTargetPath); ExitOnFailure1(hr, "failed to get target path for directory id: %S", pwzData); hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else if (OT_FILE == eType) { hr = StrAllocFormatted(&pwzFormattedString, L"[#%s]", pwzData); ExitOnFailure1(hr, "failed to create formatted string for securing file object: %S", pwzData); hr = WcaGetFormattedString(pwzFormattedString, &pwzTargetPath); ExitOnFailure2(hr, "failed to get file path from formatted string: %S for secure object: %S", pwzFormattedString, pwzData); hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else if (OT_REGISTRY == eType) { hr = WcaGetRecordInteger(hRecObject, QSOC_REGROOT, &iRoot); ExitOnFailure1(hr, "Failed to get reg key root for secure object: %S", pwzData); hr = WcaGetRecordFormattedString(hRecObject, QSOC_REGKEY, &pwzKey); ExitOnFailure1(hr, "Failed to get reg key for secure object: %S", pwzData); // Decode the root value if (-1 == iRoot) { // They didn't specify a root so that means it's either HKCU or HKLM depending on ALLUSERS property hr = WcaGetIntProperty(L"ALLUSERS", &iAllUsers); ExitOnFailure(hr, "failed to get value of ALLUSERS property"); if (1 == iAllUsers) { hr = StrAllocString(&pwzTargetPath, L"MACHINE\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); } else { hr = StrAllocString(&pwzTargetPath, L"CURRENT_USER\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); } } else if (/*msidbRegistryRootClassesRoot*/ 0 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"CLASSES_ROOT\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCR root"); } else if (/*msidbRegistryRootCurrentUser*/ 1 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"CURRENT_USER\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); } else if (/*msidbRegistryRootLocalMachine*/ 2 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"MACHINE\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); } else if (/*msidbRegistryRootUsers*/ 3 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"USERS\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKU root"); } else { ExitOnFailure2(hr = E_UNEXPECTED, "Unknown registry key root specified for secure object: '%S' root: %d", pwzData, iRoot); } hr = StrAllocConcat(&pwzTargetPath, pwzKey, 0); ExitOnFailure2(hr, "Failed to concat key: %S for secure object: %S", pwzKey, pwzData); hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else { AssertSz(FALSE, "How did you get here?"); } hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordFormattedString(hRec, QSO_DOMAIN, &pwzData); ExitOnFailure(hr, "failed to get domain for user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordFormattedString(hRec, QSO_USER, &pwzData); ExitOnFailure(hr, "failed to get user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSO_PERMISSION, &pwzData); ExitOnFailure(hr, "failed to get domain for user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); cObjects++; } } // if we looped through all records all is well if (E_NOMOREITEMS == hr) hr = S_OK; ExitOnFailure(hr, "failed while looping through all objects to secure"); // // schedule the custom action and add to progress bar // if (pwzCustomActionData && *pwzCustomActionData) { Assert(0 < cObjects); hr = WcaDoDeferredAction(L"ExecSecureObjects", pwzCustomActionData, cObjects * COST_SECUREOBJECT); ExitOnFailure(hr, "failed to schedule ExecSecureObjects action"); } LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); ReleaseStr(pwzTable); ReleaseStr(pwzTargetPath); ReleaseStr(pwzFormattedString); ReleaseStr(pwzKey); if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** SchedFirewallExceptions - immediate custom action worker to register and remove firewall exceptions. ********************************************************************/ static UINT SchedFirewallExceptions( __in MSIHANDLE hInstall, WCA_TODO todoSched ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; int cFirewallExceptions = 0; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzName = NULL; LPWSTR pwzRemoteAddresses = NULL; LPWSTR pwzPort = NULL; int iProtocol = 0; int iAttributes = 0; int iProfile = 0; LPWSTR pwzProgram = NULL; LPWSTR pwzComponent = NULL; LPWSTR pwzFormattedFile = NULL; LPWSTR pwzDescription = NULL; // initialize hr = WcaInitialize(hInstall, "SchedFirewallExceptions"); ExitOnFailure(hr, "failed to initialize"); // anything to do? if (S_OK != WcaTableExists(L"WixFirewallException")) { WcaLog(LOGMSG_STANDARD, "WixFirewallException table doesn't exist, so there are no firewall exceptions to configure."); ExitFunction(); } // query and loop through all the firewall exceptions hr = WcaOpenExecuteView(vcsFirewallExceptionQuery, &hView); ExitOnFailure(hr, "failed to open view on WixFirewallException table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { hr = WcaGetRecordFormattedString(hRec, feqName, &pwzName); ExitOnFailure(hr, "failed to get firewall exception name"); hr = WcaGetRecordFormattedString(hRec, feqRemoteAddresses, &pwzRemoteAddresses); ExitOnFailure(hr, "failed to get firewall exception remote addresses"); hr = WcaGetRecordFormattedString(hRec, feqPort, &pwzPort); ExitOnFailure(hr, "failed to get firewall exception port"); hr = WcaGetRecordInteger(hRec, feqProtocol, &iProtocol); ExitOnFailure(hr, "failed to get firewall exception protocol"); hr = WcaGetRecordFormattedString(hRec, feqProgram, &pwzProgram); ExitOnFailure(hr, "failed to get firewall exception program"); hr = WcaGetRecordInteger(hRec, feqAttributes, &iAttributes); ExitOnFailure(hr, "failed to get firewall exception attributes"); hr = WcaGetRecordInteger(hRec, feqProfile, &iProfile); ExitOnFailure(hr, "failed to get firewall exception profile"); hr = WcaGetRecordString(hRec, feqComponent, &pwzComponent); ExitOnFailure(hr, "failed to get firewall exception component"); hr = WcaGetRecordString(hRec, feqDescription, &pwzDescription); ExitOnFailure(hr, "failed to get firewall description"); // figure out what we're doing for this exception, treating reinstall the same as install WCA_TODO todoComponent = WcaGetComponentToDo(pwzComponent); if ((WCA_TODO_REINSTALL == todoComponent ? WCA_TODO_INSTALL : todoComponent) != todoSched) { WcaLog(LOGMSG_STANDARD, "Component '%ls' action state (%d) doesn't match request (%d)", pwzComponent, todoComponent, todoSched); continue; } // action :: name :: profile :: remoteaddresses :: attributes :: target :: {port::protocol | path} ++cFirewallExceptions; hr = WcaWriteIntegerToCaData(todoComponent, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception action to custom action data"); hr = WcaWriteStringToCaData(pwzName, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception name to custom action data"); hr = WcaWriteIntegerToCaData(iProfile, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception profile to custom action data"); hr = WcaWriteStringToCaData(pwzRemoteAddresses, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception remote addresses to custom action data"); hr = WcaWriteIntegerToCaData(iAttributes, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception attributes to custom action data"); if (*pwzProgram) { // If program is defined, we have an application exception. hr = WcaWriteIntegerToCaData(fetApplication, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception target (application) to custom action data"); hr = WcaWriteStringToCaData(pwzProgram, &pwzCustomActionData); ExitOnFailure(hr, "failed to write application path to custom action data"); } else { // we have a port-only exception hr = WcaWriteIntegerToCaData(fetPort, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception target (port) to custom action data"); } hr = WcaWriteStringToCaData(pwzPort, &pwzCustomActionData); ExitOnFailure(hr, "failed to write application path to custom action data"); hr = WcaWriteIntegerToCaData(iProtocol, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception protocol to custom action data"); hr = WcaWriteStringToCaData(pwzDescription, &pwzCustomActionData); ExitOnFailure(hr, "failed to write firewall rule description to custom action data"); } // reaching the end of the list is actually a good thing, not an error if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "failure occured while processing WixFirewallException table"); // schedule ExecFirewallExceptions if there's anything to do if (pwzCustomActionData && *pwzCustomActionData) { WcaLog(LOGMSG_STANDARD, "Scheduling firewall exception (%ls)", pwzCustomActionData); if (WCA_TODO_INSTALL == todoSched) { hr = WcaDoDeferredAction(L"WixRollbackFirewallExceptionsInstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall install exceptions rollback"); hr = WcaDoDeferredAction(L"WixExecFirewallExceptionsInstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall install exceptions execution"); } else { hr = WcaDoDeferredAction(L"WixRollbackFirewallExceptionsUninstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions rollback"); hr = WcaDoDeferredAction(L"WixExecFirewallExceptionsUninstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions execution"); } } else { WcaLog(LOGMSG_STANDARD, "No firewall exceptions scheduled"); } LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzName); ReleaseStr(pwzRemoteAddresses); ReleaseStr(pwzPort); ReleaseStr(pwzProgram); ReleaseStr(pwzComponent); ReleaseStr(pwzDescription); ReleaseStr(pwzFormattedFile); return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er); }
static HRESULT StoreACLRollbackInfo( __in LPWSTR pwzObject, __in LPCWSTR pwzTable ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; PSECURITY_DESCRIPTOR psd = NULL; SECURITY_DESCRIPTOR_CONTROL sdc = {0}; DWORD dwRevision = 0; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzSecurityInfo = NULL; Assert(pwzObject && pwzTable); SE_OBJECT_TYPE objectType = SEObjectTypeFromString(const_cast<LPCWSTR> (pwzTable)); if (SE_UNKNOWN_OBJECT_TYPE != objectType) { er = ::GetNamedSecurityInfoW(pwzObject, objectType, DACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd); if (ERROR_FILE_NOT_FOUND == er || ERROR_PATH_NOT_FOUND == er || ERROR_SERVICE_DOES_NOT_EXIST == HRESULT_CODE(er)) { // If the file, path or service doesn't exist yet, skip rollback without a message hr = HRESULT_FROM_WIN32(er); ExitFunction(); } ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "Unable to schedule rollback for object: %ls", pwzObject); //Need to see if DACL is protected so getting Descriptor information if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) { ExitOnLastError1(hr, "Unable to schedule rollback for object (failed to get security descriptor control): %ls", pwzObject); } // Convert the security information to a string, and write this to the custom action data if (!::ConvertSecurityDescriptorToStringSecurityDescriptorW(psd,SDDL_REVISION_1,DACL_SECURITY_INFORMATION,&pwzSecurityInfo,NULL)) { hr = E_UNEXPECTED; ExitOnFailure1(hr, "Unable to schedule rollback for object (failed to convert security descriptor to a valid security descriptor string): %ls", pwzObject); } hr = WcaWriteStringToCaData(pwzObject, &pwzCustomActionData); ExitOnFailure(hr, "failed to add object data to rollback CustomActionData"); hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData); ExitOnFailure(hr, "failed to add table name to rollback CustomActionData"); hr = WcaWriteStringToCaData(pwzSecurityInfo, &pwzCustomActionData); ExitOnFailure(hr, "failed to add security info data to rollback CustomActionData"); // Write a 1 if DACL is protected, 0 otherwise if (sdc & SE_DACL_PROTECTED) { hr = WcaWriteIntegerToCaData(1,&pwzCustomActionData); ExitOnFailure(hr, "failed to add data to rollbackCustomActionData"); } else { hr = WcaWriteIntegerToCaData(0,&pwzCustomActionData); ExitOnFailure(hr, "failed to add data to rollback CustomActionData"); } hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"ExecSecureObjectsRollback"), pwzCustomActionData, COST_SECUREOBJECT); ExitOnFailure2(hr, "failed to schedule ExecSecureObjectsRollback for item: %ls of type: %ls", pwzObject, pwzTable); ReleaseStr(pwzCustomActionData); pwzCustomActionData = NULL; } else { MessageExitOnFailure1(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable); } LExit: ReleaseStr(pwzCustomActionData); if (psd) { ::LocalFree(psd); } return hr; }
/******************************************************************** ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings ********************************************************************/ extern "C" UINT __stdcall ConfigureIIs( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ConfigureIIs here"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzScriptKey = NULL; LPWSTR pwzBackupId = NULL; LPWSTR pwzCustomActionData = NULL; // CustomActionData for ConfigureIIs custom action // initialize hr = WcaInitialize(hInstall, "ConfigureIIs"); ExitOnFailure(hr, "Failed to initialize"); // check for the prerequsite tables if (S_OK != WcaTableExists(L"IIsWebSite") && S_OK != WcaTableExists(L"IIsFilter") && S_OK != WcaTableExists(L"IIsProperty") && S_OK != WcaTableExists(L"IIsWebServiceExtension") && S_OK != WcaTableExists(L"IIsAppPool")) { WcaLog(LOGMSG_VERBOSE, "skipping IIs CustomAction, no IIsWebSite table, no IIsFilter table, no IIsProperty table, no IIsWebServiceExtension, and no IIsAppPool table"); ExitFunction1(hr = S_FALSE); } // Get a CaScript key hr = WcaCaScriptCreateKey(&pwzScriptKey); ExitOnFailure(hr, "Failed to get encoding key."); // Generate a unique string to be used for this product's transaction // This prevents a name collision when doing a major upgrade hr = WcaGetProperty(L"ProductCode", &pwzBackupId); ExitOnFailure(hr, "failed to get ProductCode"); hr = StrAllocConcat(&pwzBackupId, L"ScaConfigureIIs", 0); ExitOnFailure(hr, "failed to concat ScaConfigureIIs"); // make sure the operations below are wrapped in a "transaction" // use IIS7 transaction logic even if using Iis6 compat because Backup/Restore don't work with metabase compatibility if (MSICONDITION_TRUE == ::MsiEvaluateConditionW(hInstall, IIS7CONDITION)) { hr = ScaIIS7ConfigTransaction(pwzBackupId); MessageExitOnFailure(hr, msierrIISFailedSchedTransaction, "failed to start IIS7 transaction"); } else { hr = ScaMetabaseTransaction(pwzBackupId); MessageExitOnFailure(hr, msierrIISFailedSchedTransaction, "failed to start IIS transaction"); } // Write the CaScript key to the ConfigureIIS custom action data hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add encoding key to CustomActionData."); // Wrap vcsUserDeferredQuery to send to deferred CA if (S_OK == WcaTableExists(L"User")) { hr = WcaWrapQuery(vcsUserDeferredQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap User query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap User empty query"); } // Wrap vcsWebSvcExtQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebServiceExtension")) { hr = WcaWrapQuery(vcsWebSvcExtQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3 | efmcColumn4, 1, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebServiceExtension query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebServiceExtension empty query"); } // Wrap vcsAppPoolQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsAppPool")) { hr = WcaWrapQuery(vcsAppPoolQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn15 | efmcColumn16, 3, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsAppPool query"); hr = WcaWrapQuery(vcsComponentAttrQuery, &pwzCustomActionData, 0, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap Component query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsAppPool empty query"); } // Wrap vcsMimeMapQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsMimeMap")) { hr = WcaWrapQuery(vcsMimeMapQuery, &pwzCustomActionData, efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsMimeMap query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsMimeMap empty query"); } // Wrap vcsHttpHeaderQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsHttpHeader")) { hr = WcaWrapQuery(vcsHttpHeaderQuery, &pwzCustomActionData, efmcColumn1 | efmcColumn4, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsHttpHeader query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsHttpHeader empty query"); } // Wrap vcsWebErrorQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebError")) { hr = WcaWrapQuery(vcsWebErrorQuery, &pwzCustomActionData, efmcColumn5 | efmcColumn6, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebError query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebError empty query"); } // Wrap vcsWebDirPropertiesQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebDirProperties")) { hr = WcaWrapQuery(vcsWebDirPropertiesQuery, &pwzCustomActionData, efmcColumn8 | efmcColumn10 | efmcColumn12 | efmcColumn15, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebDirProperties query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebDirProperties empty query"); } // Wrap vcsSslCertificateQuery to send to deferred CA if (S_OK == WcaTableExists(L"Certificate") && S_OK == WcaTableExists(L"CertificateHash") && S_OK == WcaTableExists(L"IIsWebSiteCertificates")) { hr = WcaWrapQuery(vcsSslCertificateQuery, &pwzCustomActionData, 0, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap SslCertificate query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap SslCertificate empty query"); } // Wrap vcsWebLogQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebLog")) { hr = WcaWrapQuery(vcsWebLogQuery, &pwzCustomActionData, efmcColumn2, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebLog query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebLog empty query"); } // Wrap vcsWebApplicationQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebApplication")) { hr = WcaWrapQuery(vcsWebApplicationQuery, &pwzCustomActionData, efmcColumn1, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebApplication query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebApplication empty query"); } // Wrap vcsWebAppExtensionQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebApplicationExtension")) { hr = WcaWrapQuery(vcsWebAppExtensionQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebApplicationExtension query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebApplicationExtension empty query"); } // Wrap vcsWebQuery, vcsWebAddressQuery, and vcsWebBaseQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebAddress") && S_OK == WcaTableExists(L"IIsWebSite")) { hr = WcaWrapQuery(vcsWebQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn12 | efmcColumn13 | efmcColumn14, 2, 6); ExitOnFailure(hr, "Failed to wrap IIsWebSite query"); hr = WcaWrapQuery(vcsWebAddressQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebAddress query"); hr = WcaWrapQuery(vcsWebBaseQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3 | efmcColumn4 | efmcColumn5 | efmcColumn7, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebBase query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebSite empty query"); hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebAddress empty query"); hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebBase empty query"); } // Wrap vcsWebDirQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebDir")) { hr = WcaWrapQuery(vcsWebDirQuery, &pwzCustomActionData, efmcColumn4, 3, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebDir query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebDir empty query"); } // Wrap vcsVDirQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebVirtualDir")) { hr = WcaWrapQuery(vcsVDirQuery, &pwzCustomActionData, efmcColumn4, 3, 5); ExitOnFailure(hr, "Failed to wrap IIsWebVirtualDir query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebVirtualDir empty query"); } // Wrap vcsFilterQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsFilter")) { hr = WcaWrapQuery(vcsFilterQuery, &pwzCustomActionData, efmcColumn4 | efmcColumn5, 3, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsFilter query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsFilter empty query"); } // Wrap vcsPropertyQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsProperty")) { hr = WcaWrapQuery(vcsPropertyQuery, &pwzCustomActionData, efmcColumn4, 2, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsProperty query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsProperty empty query"); } if (MSICONDITION_TRUE == ::MsiEvaluateConditionW(hInstall, USEIIS7CONDITION)) { // This must remain trace only, CA data may contain password WcaLog(LOGMSG_TRACEONLY, "Custom Action Data for ConfigureIIS7Exec will be: %ls", pwzCustomActionData); hr = WcaDoDeferredAction(L"ConfigureIIs7Exec", pwzCustomActionData, ConfigureIIsCost); ExitOnFailure(hr, "Failed to schedule ConfigureIIs7Exec custom action"); ReleaseNullStr(pwzCustomActionData); // Write the CaScript key to the ConfigureIIS custom action data hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add script key to CustomActionData."); hr = WcaDoDeferredAction(L"WriteIIS7ConfigChanges", pwzCustomActionData, WriteIIS7ConfigChangesCost); ExitOnFailure(hr, "Failed to schedule WriteMetabaseChanges custom action"); } else { // This must remain trace only, CA data may contain password WcaLog(LOGMSG_TRACEONLY, "Custom Action Data for ConfigureIISExec will be: %ls", pwzCustomActionData); hr = WcaDoDeferredAction(L"ConfigureIIsExec", pwzCustomActionData, ConfigureIIsCost); ExitOnFailure(hr, "Failed to schedule ConfigureIISExec custom action"); ReleaseNullStr(pwzCustomActionData); // Write the CaScript key to the ConfigureIIS custom action data hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add script key to CustomActionData."); hr = WcaDoDeferredAction(L"WriteMetabaseChanges", pwzCustomActionData, WriteMetabaseChangesCost); ExitOnFailure(hr, "Failed to schedule WriteMetabaseChanges custom action"); } LExit: ReleaseStr(pwzScriptKey); ReleaseStr(pwzBackupId); ReleaseStr(pwzCustomActionData); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/* **************************************************************** ScaUserExecute - Schedules user account creation or removal based on component state. ******************************************************************/ HRESULT ScaUserExecute( __in SCA_USER *psuList ) { HRESULT hr = S_OK; DWORD er = 0; PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; USER_INFO_0 *pUserInfo = NULL; LPWSTR pwzActionData = NULL; LPWSTR pwzRollbackData = NULL; for (SCA_USER *psu = psuList; psu; psu = psu->psuNext) { USER_EXISTS ueUserExists = USER_EXISTS_INDETERMINATE; // Always put the User Name and Domain plus Attributes on the front of the CustomAction // data. Sometimes we'll add more data. Assert(psu->wzName); hr = WcaWriteStringToCaData(psu->wzName, &pwzActionData); ExitOnFailure1(hr, "Failed to add user name to custom action data: %ls", psu->wzName); hr = WcaWriteStringToCaData(psu->wzDomain, &pwzActionData); ExitOnFailure1(hr, "Failed to add user domain to custom action data: %ls", psu->wzDomain); hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData); ExitOnFailure1(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey); // Check to see if the user already exists since we have to be very careful when adding // and removing users. Note: MSDN says that it is safe to call these APIs from any // user, so we should be safe calling it during immediate mode. er = ::NetApiBufferAllocate(sizeof(USER_INFO_0), reinterpret_cast<LPVOID*>(&pUserInfo)); hr = HRESULT_FROM_WIN32(er); ExitOnFailure1(hr, "Failed to allocate memory to check existence of user: %ls", psu->wzName); LPCWSTR wzDomain = psu->wzDomain; if (wzDomain && *wzDomain) { er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, NULL, &pDomainControllerInfo); if (HRESULT_FROM_WIN32(er) == RPC_S_SERVER_UNAVAILABLE) { // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo); } if (ERROR_SUCCESS == er) { wzDomain = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix } } er = ::NetUserGetInfo(wzDomain, psu->wzName, 0, reinterpret_cast<LPBYTE*>(pUserInfo)); if (NERR_Success == er) { ueUserExists = USER_EXISTS_YES; } else if (NERR_UserNotFound == er) { ueUserExists = USER_EXISTS_NO; } else { ueUserExists = USER_EXISTS_INDETERMINATE; hr = HRESULT_FROM_WIN32(er); WcaLog(LOGMSG_VERBOSE, "Failed to check existence of domain: %ls, user: %ls (error code 0x%x) - continuing", wzDomain, psu->wzName, hr); } if (WcaIsInstalling(psu->isInstalled, psu->isAction)) { // If the user exists, check to see if we are supposed to fail if user the exists before // the install. if (USER_EXISTS_YES == ueUserExists) { // Reinstalls will always fail if we don't remove the check for "fail if exists". if (WcaIsReInstalling(psu->isInstalled, psu->isAction)) { psu->iAttributes &= ~SCAU_FAIL_IF_EXISTS; } if ((SCAU_FAIL_IF_EXISTS & (psu->iAttributes)) && !(SCAU_UPDATE_IF_EXISTS & (psu->iAttributes))) { hr = HRESULT_FROM_WIN32(NERR_UserExists); MessageExitOnFailure1(hr, msierrUSRFailedUserCreateExists, "Failed to create user: %ls because user already exists.", psu->wzName); } } // Rollback only if the user already exists, we couldn't determine if the user exists, or we are going to create the user if ((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists) || !(psu->iAttributes & SCAU_DONT_CREATE_USER)) { INT iRollbackUserAttributes = psu->iAttributes; // If the user already exists, ensure this is accounted for in rollback if (USER_EXISTS_YES == ueUserExists) { iRollbackUserAttributes |= SCAU_DONT_CREATE_USER; } else { iRollbackUserAttributes &= ~SCAU_DONT_CREATE_USER; } hr = WcaWriteStringToCaData(psu->wzName, &pwzRollbackData); ExitOnFailure1(hr, "Failed to add user name to rollback custom action data: %ls", psu->wzName); hr = WcaWriteStringToCaData(psu->wzDomain, &pwzRollbackData); ExitOnFailure1(hr, "Failed to add user domain to rollback custom action data: %ls", psu->wzDomain); hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); ExitOnFailure1(hr, "failed to add user attributes to rollback custom action data for user: %ls", psu->wzKey); // If the user already exists, add relevant group information to rollback data if (USER_EXISTS_YES == ueUserExists || USER_EXISTS_INDETERMINATE == ueUserExists) { hr = WriteGroupRollbackInfo(psu->wzName, psu->wzDomain, psu->psgGroups, &pwzRollbackData); ExitOnFailure(hr, "failed to add group information to rollback custom action data"); } hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"CreateUserRollback"), pwzRollbackData, COST_USER_DELETE); ExitOnFailure(hr, "failed to schedule CreateUserRollback"); } // // Schedule the creation now. // hr = WcaWriteStringToCaData(psu->wzPassword, &pwzActionData); ExitOnFailure1(hr, "failed to add user password to custom action data for user: %ls", psu->wzKey); // Add user's group information to custom action data hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); ExitOnFailure(hr, "failed to add group information to custom action data"); hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"CreateUser"), pwzActionData, COST_USER_ADD); ExitOnFailure(hr, "failed to schedule CreateUser"); } else if (((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists)) && WcaIsUninstalling(psu->isInstalled, psu->isAction) && !(psu->iAttributes & SCAU_DONT_REMOVE_ON_UNINSTALL)) { // Add user's group information - this will ensure the user can be removed from any groups they were added to, if the user isn't be deleted hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); ExitOnFailure(hr, "failed to add group information to custom action data"); // // Schedule the removal because the user exists and we don't have any flags set // that say, don't remove the user on uninstall. // // Note: We can't rollback the removal of a user which is why RemoveUser is a commit // CustomAction. hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"RemoveUser"), pwzActionData, COST_USER_DELETE); ExitOnFailure(hr, "failed to schedule RemoveUser"); } ReleaseNullStr(pwzActionData); ReleaseNullStr(pwzRollbackData); if (pUserInfo) { ::NetApiBufferFree(static_cast<LPVOID>(pUserInfo)); pUserInfo = NULL; } if (pDomainControllerInfo) { ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo)); pDomainControllerInfo = NULL; } } LExit: ReleaseStr(pwzActionData); ReleaseStr(pwzRollbackData); if (pUserInfo) { ::NetApiBufferFree(static_cast<LPVOID>(pUserInfo)); } if (pDomainControllerInfo) { ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo)); } return hr; }
static HRESULT ExecuteStrings( __in SCA_DB* psdList, __in SCA_SQLSTR* psssList, __in BOOL fInstall ) { HRESULT hr = S_FALSE; // assume nothing will be done int iRollback = -1; int iOldRollback = iRollback; LPCWSTR wzOldDb = NULL; UINT uiCost = 0; WCHAR* pwzCustomActionData = NULL; WCHAR wzNumber[64]; // loop through all sql strings for (SCA_SQLSTR* psss = psssList; psss; psss = psss->psssNext) { // if installing this component if ((fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_INSTALL) && WcaIsInstalling(psss->isInstalled, psss->isAction) && !WcaIsReInstalling(psss->isInstalled, psss->isAction)) || (fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_REINSTALL) && WcaIsReInstalling(psss->isInstalled, psss->isAction)) || (!fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_UNINSTALL) && WcaIsUninstalling(psss->isInstalled, psss->isAction))) { // determine if this is a rollback scheduling or normal deferred scheduling if (psss->iAttributes & SCASQL_ROLLBACK) { iRollback = 1; } else { iRollback = 0; } // if we need to create a connection to a new server\database if (!wzOldDb || 0 != lstrcmpW(wzOldDb, psss->wzSqlDb) || iOldRollback != iRollback) { const SCA_DB* psd = ScaDbsFindDatabase(psss->wzSqlDb, psdList); if (!psd) { ExitOnFailure1(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "failed to find data for Database: %ls", psss->wzSqlDb); } if (-1 == iOldRollback) { iOldRollback = iRollback; } Assert(0 == iOldRollback || 1 == iOldRollback); // if there was custom action data before, schedule the action to write it if (pwzCustomActionData && *pwzCustomActionData) { Assert(pwzCustomActionData && *pwzCustomActionData && uiCost); hr = WcaDoDeferredAction(1 == iOldRollback ? L"RollbackExecuteSqlStrings" : L"ExecuteSqlStrings", pwzCustomActionData, uiCost); ExitOnFailure1(hr, "failed to schedule ExecuteSqlStrings action, rollback: %d", iOldRollback); iOldRollback = iRollback; *pwzCustomActionData = L'\0'; uiCost = 0; } Assert(!pwzCustomActionData || (pwzCustomActionData && 0 == *pwzCustomActionData) && 0 == uiCost); hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Server Database String to CustomActionData for Database String: %ls", psd->wzKey); hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Server to CustomActionData for Database String: %ls", psd->wzKey); hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Instance to CustomActionData for Database String: %ls", psd->wzKey); hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Database to CustomActionData for Database String: %ls", psd->wzKey); hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->iAttributes); ExitOnFailure(hr, "Failed to format attributes integer value to string"); hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Attributes to CustomActionData for Database String: %ls", psd->wzKey); hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->fUseIntegratedAuth); ExitOnFailure(hr, "Failed to format UseIntegratedAuth integer value to string"); hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL IntegratedAuth flag to CustomActionData for Database String: %ls", psd->wzKey); hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL UserName to CustomActionData for Database String: %ls", psd->wzKey); hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Password to CustomActionData for Database String: %ls", psd->wzKey); uiCost += COST_SQL_CONNECTDB; wzOldDb = psss->wzSqlDb; } WcaLog(LOGMSG_VERBOSE, "Scheduling SQL string: %ls", psss->pwzSql); hr = WcaWriteStringToCaData(psss->wzKey, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Key to CustomActionData for SQL string: %ls", psss->wzKey); hr = WcaWriteIntegerToCaData(psss->iAttributes, &pwzCustomActionData); ExitOnFailure1(hr, "failed to add attributes to CustomActionData for SQL string: %ls", psss->wzKey); hr = WcaWriteStringToCaData(psss->pwzSql, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to to add SQL Query to CustomActionData for SQL string: %ls", psss->wzKey); uiCost += COST_SQL_STRING; } } if (pwzCustomActionData && *pwzCustomActionData) { Assert(pwzCustomActionData && *pwzCustomActionData && uiCost); hr = WcaDoDeferredAction(1 == iRollback ? L"RollbackExecuteSqlStrings" : L"ExecuteSqlStrings", pwzCustomActionData, uiCost); ExitOnFailure(hr, "Failed to schedule ExecuteSqlStrings action"); *pwzCustomActionData = L'\0'; uiCost = 0; } LExit: ReleaseStr(pwzCustomActionData); return hr; }
/****************************************************************** SchedServiceConfig - entry point for SchedServiceConfig Custom Action called as Type 1 CustomAction (binary DLL) from Windows Installer in InstallExecuteSequence before CaExecServiceConfig ********************************************************************/ extern "C" UINT __stdcall SchedServiceConfig( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug SchedServiceConfig"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzScriptKey = NULL; LPWSTR pwzCustomActionData = NULL; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; LPWSTR pwzData = NULL; int iData = 0; DWORD cServices = 0; // initialize hr = WcaInitialize(hInstall, "SchedServiceConfig"); ExitOnFailure(hr, "Failed to initialize."); // Get the script key for this CustomAction and put it on the front of the // CustomActionData of the install action. hr = WcaCaScriptCreateKey(&pwzScriptKey); ExitOnFailure(hr, "Failed to get encoding key."); hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add encoding key to CustomActionData."); // Loop through all the services to be configured. hr = WcaOpenExecuteView(wzQUERY_SERVICECONFIG, &hView); ExitOnFailure(hr, "Failed to open view on ServiceConfig table."); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; // Get component name to check if we are installing it. If so // then add the table data to the CustomActionData, otherwise // skip it. hr = WcaGetRecordString(hRec, QSC_COMPONENT, &pwzData); ExitOnFailure(hr, "Failed to get component name"); hr = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); ExitOnFailure1(hr = HRESULT_FROM_WIN32(hr), "Failed to get install state for Component: %ls", pwzData); if (WcaIsInstalling(isInstalled, isAction)) { // Add the data to the CustomActionData (for install). hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData); ExitOnFailure(hr, "Failed to get name of service."); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add name to CustomActionData."); hr = WcaGetRecordInteger(hRec, QSC_NEWSERVICE, &iData); ExitOnFailure(hr, "Failed to get ServiceConfig.NewService."); hr = WcaWriteIntegerToCaData(0 != iData, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add NewService data to CustomActionData"); hr = WcaGetRecordString(hRec, QSC_FIRSTFAILUREACTIONTYPE, &pwzData); ExitOnFailure(hr, "failed to get first failure action type"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSC_SECONDFAILUREACTIONTYPE, &pwzData); ExitOnFailure(hr, "failed to get second failure action type"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSC_THIRDFAILUREACTIONTYPE, &pwzData); ExitOnFailure(hr, "failed to get third failure action type"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordInteger(hRec, QSC_RESETPERIODINDAYS, &iData); if (S_FALSE == hr) // deal w/ possible null value { iData = 0; } ExitOnFailure(hr, "failed to get reset period in days between service restart attempts."); hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordInteger(hRec, QSC_RESTARTSERVICEDELAYINSECONDS, &iData); if (S_FALSE == hr) // deal w/ possible null value { iData = 0; } ExitOnFailure(hr, "failed to get server restart delay value."); hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordFormattedString(hRec, QSC_PROGRAMCOMMANDLINE, &pwzData); // null value already dealt w/ properly ExitOnFailure(hr, "failed to get command line to run on service failure."); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSC_REBOOTMESSAGE, &pwzData); // null value already dealt w/ properly ExitOnFailure(hr, "failed to get message to send to users when server reboots due to service failure."); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); ++cServices; } } // if we looped through all records all is well if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "failed while looping through all objects to secure"); // setup CustomActionData and add to progress bar for download if (0 < cServices) { hr = WcaDoDeferredAction(L"RollbackServiceConfig", pwzScriptKey, cServices * COST_SERVICECONFIG); ExitOnFailure(hr, "failed to schedule RollbackServiceConfig action"); hr = WcaDoDeferredAction(L"ExecServiceConfig", pwzCustomActionData, cServices * COST_SERVICECONFIG); ExitOnFailure(hr, "failed to schedule ExecServiceConfig action"); } LExit: ReleaseStr(pwzData); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzScriptKey); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** WixSchedInternetShortcuts - entry point ********************************************************************/ extern "C" UINT __stdcall WixSchedInternetShortcuts( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; UINT uiCost = 0; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; MSIHANDLE hCreateFolderTable = NULL; MSIHANDLE hCreateFolderColumns = NULL; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzComponent = NULL; LPWSTR pwzDirectory = NULL; LPWSTR pwzFilename = NULL; LPWSTR pwzTarget = NULL; LPWSTR pwzShortcutPath = NULL; int iAttr = 0; LPWSTR pwzIconFile = NULL; int iIconIndex = 0; IUniformResourceLocatorW* piURL = NULL; IShellLinkW* piShellLink = NULL; BOOL fInitializedCom = FALSE; hr = WcaInitialize(hInstall, "WixSchedInternetShortcuts"); ExitOnFailure(hr, "failed to initialize WixSchedInternetShortcuts."); // anything to do? if (S_OK != WcaTableExists(L"WixInternetShortcut")) { WcaLog(LOGMSG_STANDARD, "WixInternetShortcut table doesn't exist, so there are no Internet shortcuts to process"); goto LExit; } // check to see if we can create a shortcut - Server Core and others may not have a shell registered. hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to initialize COM"); fInitializedCom = TRUE; hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL); if (S_OK != hr) { WcaLog(LOGMSG_STANDARD, "failed to create an instance of IUniformResourceLocatorW, skipping shortcut creation"); ExitFunction1(hr = S_OK); } hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink); if (S_OK != hr) { WcaLog(LOGMSG_STANDARD, "failed to create an instance of IShellLinkW, skipping shortcut creation"); ExitFunction1(hr = S_OK); } // query and loop through all the shortcuts hr = WcaOpenExecuteView(vcsShortcutsQuery, &hView); ExitOnFailure(hr, "failed to open view on WixInternetShortcut table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // read column values hr = WcaGetRecordString(hRec, esqComponent, &pwzComponent); ExitOnFailure(hr, "failed to get shortcut component"); hr = WcaGetRecordString(hRec, esqDirectory, &pwzDirectory); ExitOnFailure(hr, "failed to get shortcut directory"); hr = WcaGetRecordString(hRec, esqFilename, &pwzFilename); ExitOnFailure(hr, "failed to get shortcut filename"); hr = WcaGetRecordFormattedString(hRec, esqTarget, &pwzTarget); ExitOnFailure(hr, "failed to get shortcut target"); hr = WcaGetRecordInteger(hRec, esqAttributes, &iAttr); ExitOnFailure(hr, "failed to get shortcut attributes"); hr = WcaGetRecordFormattedString(hRec, esqIconFile, &pwzIconFile); ExitOnFailure(hr, "failed to get shortcut icon file"); hr = WcaGetRecordInteger(hRec, esqIconIndex, &iIconIndex); ExitOnFailure(hr, "failed to get shortcut icon index"); // skip processing this WixInternetShortcut row if the component isn't being configured WCA_TODO todo = WcaGetComponentToDo(pwzComponent); if (WCA_TODO_UNKNOWN == todo) { WcaLog(LOGMSG_VERBOSE, "Skipping shortcut for null-action component '%ls'", pwzComponent); continue; } // we need to create the directory where the shortcut is supposed to live; rather // than doing so in our deferred custom action, use the CreateFolder table to have MSI // make (and remove) them on our behalf (including the correct cleanup of parent directories). MSIDBERROR dbError = MSIDBERROR_NOERROR; WcaLog(LOGMSG_STANDARD, "Adding folder '%ls', component '%ls' to the CreateFolder table", pwzDirectory, pwzComponent); hr = WcaAddTempRecord(&hCreateFolderTable, &hCreateFolderColumns, L"CreateFolder", &dbError, 0, 2, pwzDirectory, pwzComponent); if (MSIDBERROR_DUPLICATEKEY == dbError) { WcaLog(LOGMSG_STANDARD, "Folder '%ls' already exists in the CreateFolder table; the above error is harmless", pwzDirectory); hr = S_OK; } ExitOnFailure(hr, "Couldn't add temporary CreateFolder row"); // only if we're installing/reinstalling do we need to schedule the deferred CA // (uninstallation is handled via permanent RemoveFile rows and temporary CreateFolder rows) if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo) { // turn the Directory_ id into a path hr = WcaGetTargetPath(pwzDirectory, &pwzShortcutPath); ExitOnFailure(hr, "failed to allocate string for shortcut directory"); // append the shortcut filename hr = StrAllocConcat(&pwzShortcutPath, pwzFilename, 0); ExitOnFailure(hr, "failed to allocate string for shortcut filename"); // write the shortcut path and target to custom action data for deferred CAs hr = WcaWriteStringToCaData(pwzShortcutPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to write shortcut path to custom action data"); hr = WcaWriteStringToCaData(pwzTarget, &pwzCustomActionData); ExitOnFailure(hr, "failed to write shortcut target to custom action data"); hr = WcaWriteIntegerToCaData(iAttr, &pwzCustomActionData); ExitOnFailure(hr, "failed to write shortcut attributes to custom action data"); hr = WcaWriteStringToCaData(pwzIconFile, &pwzCustomActionData); ExitOnFailure(hr, "failed to write icon file to custom action data"); hr = WcaWriteIntegerToCaData(iIconIndex, &pwzCustomActionData); ExitOnFailure(hr, "failed to write icon index to custom action data"); uiCost += COST_INTERNETSHORTCUT; } } if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "Failure occured while processing WixInternetShortcut table"); // if we have any shortcuts to install if (pwzCustomActionData && *pwzCustomActionData) { // add cost to progress bar hr = WcaProgressMessage(uiCost, TRUE); ExitOnFailure(hr, "failed to extend progress bar for InternetShortcuts"); // provide custom action data to deferred and rollback CAs hr = WcaSetProperty(PLATFORM_DECORATION(L"WixRollbackInternetShortcuts"), pwzCustomActionData); ExitOnFailure(hr, "failed to set WixRollbackInternetShortcuts rollback custom action data"); hr = WcaSetProperty(PLATFORM_DECORATION(L"WixCreateInternetShortcuts"), pwzCustomActionData); ExitOnFailure(hr, "failed to set WixCreateInternetShortcuts custom action data"); } LExit: if (hCreateFolderTable) { ::MsiCloseHandle(hCreateFolderTable); } if (hCreateFolderColumns) { ::MsiCloseHandle(hCreateFolderColumns); } ReleaseStr(pwzCustomActionData); ReleaseStr(pwzComponent); ReleaseStr(pwzDirectory); ReleaseStr(pwzFilename); ReleaseStr(pwzTarget); ReleaseStr(pwzShortcutPath); ReleaseObject(piShellLink); ReleaseObject(piURL); 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); }