From cbc09b6cd6d0d0b8bf095a88d4d8333616637f71 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Mon, 4 Feb 2019 20:05:54 -0600 Subject: Import code from old v4 repo --- src/ca/cpappexec.cpp | 344 ++++++ src/ca/cpappexec.h | 12 + src/ca/cpapproleexec.cpp | 720 +++++++++++ src/ca/cpapproleexec.h | 20 + src/ca/cpapprolesched.cpp | 843 +++++++++++++ src/ca/cpapprolesched.h | 112 ++ src/ca/cpappsched.cpp | 752 +++++++++++ src/ca/cpappsched.h | 83 ++ src/ca/cpasmexec.cpp | 1888 ++++++++++++++++++++++++++++ src/ca/cpasmexec.h | 20 + src/ca/cpasmsched.cpp | 2135 ++++++++++++++++++++++++++++++++ src/ca/cpasmsched.h | 168 +++ src/ca/cpcost.h | 30 + src/ca/cpexec.cpp | 704 +++++++++++ src/ca/cpexec.def | 11 + src/ca/cppartexec.cpp | 690 +++++++++++ src/ca/cppartexec.h | 20 + src/ca/cppartroleexec.cpp | 397 ++++++ src/ca/cppartroleexec.h | 12 + src/ca/cppartrolesched.cpp | 421 +++++++ src/ca/cppartrolesched.h | 76 ++ src/ca/cppartsched.cpp | 912 ++++++++++++++ src/ca/cppartsched.h | 125 ++ src/ca/cpsched.cpp | 590 +++++++++ src/ca/cpsubsexec.cpp | 411 +++++++ src/ca/cpsubsexec.h | 12 + src/ca/cpsubssched.cpp | 606 +++++++++ src/ca/cpsubssched.h | 62 + src/ca/cputilexec.cpp | 1881 ++++++++++++++++++++++++++++ src/ca/cputilexec.h | 193 +++ src/ca/cputilsched.cpp | 885 +++++++++++++ src/ca/cputilsched.h | 144 +++ src/wixext/ComPlusCompiler.cs | 2188 +++++++++++++++++++++++++++++++++ src/wixext/ComPlusDecompiler.cs | 1843 +++++++++++++++++++++++++++ src/wixext/ComPlusExtensionData.cs | 64 + src/wixext/WixComPlusExtension.csproj | 50 + src/wixext/complus.xsd | 944 ++++++++++++++ src/wixext/messages.xml | 77 ++ src/wixext/tables.xml | 250 ++++ src/wixlib/ComPlusExtension.wixproj | 26 + src/wixlib/ComPlusExtension.wxs | 139 +++ src/wixlib/en-us.wxl | 71 ++ src/wixlib/es-es.wxl | 72 ++ src/wixlib/ja-jp.wxl | 71 ++ 44 files changed, 21074 insertions(+) create mode 100644 src/ca/cpappexec.cpp create mode 100644 src/ca/cpappexec.h create mode 100644 src/ca/cpapproleexec.cpp create mode 100644 src/ca/cpapproleexec.h create mode 100644 src/ca/cpapprolesched.cpp create mode 100644 src/ca/cpapprolesched.h create mode 100644 src/ca/cpappsched.cpp create mode 100644 src/ca/cpappsched.h create mode 100644 src/ca/cpasmexec.cpp create mode 100644 src/ca/cpasmexec.h create mode 100644 src/ca/cpasmsched.cpp create mode 100644 src/ca/cpasmsched.h create mode 100644 src/ca/cpcost.h create mode 100644 src/ca/cpexec.cpp create mode 100644 src/ca/cpexec.def create mode 100644 src/ca/cppartexec.cpp create mode 100644 src/ca/cppartexec.h create mode 100644 src/ca/cppartroleexec.cpp create mode 100644 src/ca/cppartroleexec.h create mode 100644 src/ca/cppartrolesched.cpp create mode 100644 src/ca/cppartrolesched.h create mode 100644 src/ca/cppartsched.cpp create mode 100644 src/ca/cppartsched.h create mode 100644 src/ca/cpsched.cpp create mode 100644 src/ca/cpsubsexec.cpp create mode 100644 src/ca/cpsubsexec.h create mode 100644 src/ca/cpsubssched.cpp create mode 100644 src/ca/cpsubssched.h create mode 100644 src/ca/cputilexec.cpp create mode 100644 src/ca/cputilexec.h create mode 100644 src/ca/cputilsched.cpp create mode 100644 src/ca/cputilsched.h create mode 100644 src/wixext/ComPlusCompiler.cs create mode 100644 src/wixext/ComPlusDecompiler.cs create mode 100644 src/wixext/ComPlusExtensionData.cs create mode 100644 src/wixext/WixComPlusExtension.csproj create mode 100644 src/wixext/complus.xsd create mode 100644 src/wixext/messages.xml create mode 100644 src/wixext/tables.xml create mode 100644 src/wixlib/ComPlusExtension.wixproj create mode 100644 src/wixlib/ComPlusExtension.wxs create mode 100644 src/wixlib/en-us.wxl create mode 100644 src/wixlib/es-es.wxl create mode 100644 src/wixlib/ja-jp.wxl (limited to 'src') diff --git a/src/ca/cpappexec.cpp b/src/ca/cpappexec.cpp new file mode 100644 index 00000000..43d6cd6d --- /dev/null +++ b/src/ca/cpappexec.cpp @@ -0,0 +1,344 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// private structs + +struct CPI_APPLICATION_ATTRIBUTES +{ + int iActionType; + int iActionCost; + LPWSTR pwzKey; + LPWSTR pwzID; + LPWSTR pwzName; + LPWSTR pwzPartID; + CPI_PROPERTY* pPropList; +}; + + +// prototypes for private helper functions + +static HRESULT ReadApplicationAttributes( + LPWSTR* ppwzData, + CPI_APPLICATION_ATTRIBUTES* pAttrs + ); +static void FreeApplicationAttributes( + CPI_APPLICATION_ATTRIBUTES* pAttrs + ); +static HRESULT CreateApplication( + CPI_APPLICATION_ATTRIBUTES* pAttrs + ); +static HRESULT RemoveApplication( + CPI_APPLICATION_ATTRIBUTES* pAttrs + ); + + +// function definitions + +HRESULT CpiConfigureApplications( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ) +{ + HRESULT hr = S_OK; + + CPI_APPLICATION_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, FALSE); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // write count to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); + ExitOnFailure(hr, "Failed to write count to rollback file"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadApplicationAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // write key to rollback file + hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); + ExitOnFailure(hr, "Failed to write key to rollback file"); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreateApplication(&attrs); + ExitOnFailure(hr, "Failed to create application, key: %S", attrs.pwzKey); + break; + case atRemove: + hr = RemoveApplication(&attrs); + ExitOnFailure(hr, "Failed to remove application, key: %S", attrs.pwzKey); + break; + } + + // write completion status to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); + ExitOnFailure(hr, "Failed to write completion status to rollback file"); + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeApplicationAttributes(&attrs); + + return hr; +} + +HRESULT CpiRollbackConfigureApplications( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ) +{ + HRESULT hr = S_OK; + + int iRollbackStatus; + + CPI_APPLICATION_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadApplicationAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // rollback status + hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); + + if (S_FALSE == hr) + continue; // not found, nothing to rollback + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreateApplication(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to create application, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + case atRemove: + hr = RemoveApplication(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to remove application, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + } + + // check rollback status + if (0 == iRollbackStatus) + continue; // operation did not complete, skip progress + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeApplicationAttributes(&attrs); + + return hr; +} + + +// helper function definitions + +static HRESULT ReadApplicationAttributes( + LPWSTR* ppwzData, + CPI_APPLICATION_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); + ExitOnFailure(hr, "Failed to read action type"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); + ExitOnFailure(hr, "Failed to read action cost"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); + ExitOnFailure(hr, "Failed to read key"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzID); + ExitOnFailure(hr, "Failed to read id"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName); + ExitOnFailure(hr, "Failed to read name"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); + ExitOnFailure(hr, "Failed to read partition id"); + hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList); + ExitOnFailure(hr, "Failed to read properties"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreeApplicationAttributes( + CPI_APPLICATION_ATTRIBUTES* pAttrs + ) +{ + ReleaseStr(pAttrs->pwzKey); + ReleaseStr(pAttrs->pwzID); + ReleaseStr(pAttrs->pwzName); + ReleaseStr(pAttrs->pwzPartID); + + if (pAttrs->pPropList) + CpiFreePropertyList(pAttrs->pPropList); +} + +static HRESULT CreateApplication( + CPI_APPLICATION_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piAppColl = NULL; + ICatalogObject* piAppObj = NULL; + + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Creating application, key: %S", pAttrs->pwzKey); + + // get applications collection + hr = CpiGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to get applications collection"); + + // check if application exists + hr = CpiFindCollectionObjectByStringKey(piAppColl, pAttrs->pwzID, &piAppObj); + ExitOnFailure(hr, "Failed to find application"); + + if (S_FALSE == hr) + { + // create application + hr = CpiAddCollectionObject(piAppColl, &piAppObj); + ExitOnFailure(hr, "Failed to add application to collection"); + + hr = CpiPutCollectionObjectValue(piAppObj, L"ID", pAttrs->pwzID); + ExitOnFailure(hr, "Failed to set application id property"); + + hr = CpiPutCollectionObjectValue(piAppObj, L"Name", pAttrs->pwzName); + ExitOnFailure(hr, "Failed to set application name property"); + + // save changes + hr = piAppColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to add application"); + } + + // properties + hr = CpiPutCollectionObjectValues(piAppObj, pAttrs->pPropList); + ExitOnFailure(hr, "Failed to write properties"); + + // save changes + hr = piAppColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piAppColl); + ReleaseObject(piAppObj); + + return hr; +} + +static HRESULT RemoveApplication( + CPI_APPLICATION_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piAppColl = NULL; + + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Removing application, key: %S", pAttrs->pwzKey); + + // get applications collection + hr = CpiGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl); + ExitOnFailure(hr, "Failed to get applications collection"); + + if (S_FALSE == hr) + { + // applications collection not found + WcaLog(LOGMSG_VERBOSE, "Unable to retrieve applications collection, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // remove + hr = CpiRemoveCollectionObject(piAppColl, pAttrs->pwzID, NULL, TRUE); + ExitOnFailure(hr, "Failed to remove application"); + + if (S_FALSE == hr) + { + // application not found + WcaLog(LOGMSG_VERBOSE, "Application not found, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // save changes + hr = piAppColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piAppColl); + + return hr; +} diff --git a/src/ca/cpappexec.h b/src/ca/cpappexec.h new file mode 100644 index 00000000..5003b046 --- /dev/null +++ b/src/ca/cpappexec.h @@ -0,0 +1,12 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +HRESULT CpiConfigureApplications( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ); +HRESULT CpiRollbackConfigureApplications( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ); diff --git a/src/ca/cpapproleexec.cpp b/src/ca/cpapproleexec.cpp new file mode 100644 index 00000000..e3b71e93 --- /dev/null +++ b/src/ca/cpapproleexec.cpp @@ -0,0 +1,720 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// private structs + +struct CPI_APPLICATION_ROLE_ATTRIBUTES +{ + int iActionType; + int iActionCost; + LPWSTR pwzKey; + LPWSTR pwzName; + LPWSTR pwzAppID; + LPWSTR pwzPartID; + CPI_PROPERTY* pPropList; +}; + +struct CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES +{ + int iActionType; + int iActionCost; + LPWSTR pwzKey; + LPWSTR pwzRoleName; + LPWSTR pwzAccount; + LPWSTR pwzAppID; + LPWSTR pwzPartID; +}; + + +// prototypes for private helper functions + +static HRESULT ReadApplicationRoleAttributes( + LPWSTR* ppwzData, + CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ); +static void FreeApplicationRoleAttributes( + CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ); +static HRESULT CreateApplicationRole( + CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ); +static HRESULT RemoveApplicationRole( + CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ); +static HRESULT ReadUsersInApplicationRoleAttributes( + LPWSTR* ppwzData, + CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ); +static void FreeUsersInApplicationRoleAttributes( + CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ); +static HRESULT CreateUsersInApplicationRole( + CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ); +static HRESULT RemoveUsersInApplicationRole( + CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ); + + +// function definitions + +HRESULT CpiConfigureApplicationRoles( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ) +{ + HRESULT hr = S_OK; + + CPI_APPLICATION_ROLE_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, FALSE); + ExitOnFailure(hr, "Failed to send action start message"); + + // ger count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // write count to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); + ExitOnFailure(hr, "Failed to write count to rollback file"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadApplicationRoleAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // write key to rollback file + hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); + ExitOnFailure(hr, "Failed to write key to rollback file"); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreateApplicationRole(&attrs); + ExitOnFailure(hr, "Failed to create application role, key: %S", attrs.pwzKey); + break; + case atRemove: + hr = RemoveApplicationRole(&attrs); + ExitOnFailure(hr, "Failed to remove application role, key: %S", attrs.pwzKey); + break; + } + + // write completion status to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); + ExitOnFailure(hr, "Failed to write completion status to rollback file"); + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeApplicationRoleAttributes(&attrs); + + return hr; +} + +HRESULT CpiRollbackConfigureApplicationRoles( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ) +{ + HRESULT hr = S_OK; + + int iRollbackStatus; + + CPI_APPLICATION_ROLE_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadApplicationRoleAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // rollback status + hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); + + if (S_FALSE == hr) + continue; // not found, nothing to rollback + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreateApplicationRole(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to create application role, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + case atRemove: + hr = RemoveApplicationRole(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to remove application role, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + } + + // check rollback status + if (0 == iRollbackStatus) + continue; // operation did not complete, skip progress + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeApplicationRoleAttributes(&attrs); + + return hr; +} + +HRESULT CpiConfigureUsersInApplicationRoles( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ) +{ + HRESULT hr = S_OK; + + CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, FALSE); + ExitOnFailure(hr, "Failed to send action start message"); + + // ger count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // write count to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); + ExitOnFailure(hr, "Failed to write count to rollback file"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadUsersInApplicationRoleAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzRoleName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // write key to rollback file + hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); + ExitOnFailure(hr, "Failed to write key to rollback file"); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreateUsersInApplicationRole(&attrs); + ExitOnFailure(hr, "Failed to create user in application role, key: %S", attrs.pwzKey); + break; + case atRemove: + hr = RemoveUsersInApplicationRole(&attrs); + ExitOnFailure(hr, "Failed to remove user from application role, key: %S", attrs.pwzKey); + break; + } + + // write completion status to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); + ExitOnFailure(hr, "Failed to write completion status to rollback file"); + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeUsersInApplicationRoleAttributes(&attrs); + + return hr; +} + +HRESULT CpiRollbackConfigureUsersInApplicationRoles( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ) +{ + HRESULT hr = S_OK; + + int iRollbackStatus; + + CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadUsersInApplicationRoleAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // rollback status + hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); + + if (S_FALSE == hr) + continue; // not found, nothing to rollback + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzRoleName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreateUsersInApplicationRole(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to add user to application role, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + case atRemove: + hr = RemoveUsersInApplicationRole(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to remove user from application role, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + } + + // check rollback status + if (0 == iRollbackStatus) + continue; // operation did not complete, skip progress + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeUsersInApplicationRoleAttributes(&attrs); + + return hr; +} + + +// helper function definitions + +static HRESULT ReadApplicationRoleAttributes( + LPWSTR* ppwzData, + CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); + ExitOnFailure(hr, "Failed to read action type"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); + ExitOnFailure(hr, "Failed to read action cost"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); + ExitOnFailure(hr, "Failed to read key"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName); + ExitOnFailure(hr, "Failed to read name"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID); + ExitOnFailure(hr, "Failed to read application id"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); + ExitOnFailure(hr, "Failed to read partition id"); + hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList); + ExitOnFailure(hr, "Failed to read properties"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreeApplicationRoleAttributes( + CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ) +{ + ReleaseStr(pAttrs->pwzKey); + ReleaseStr(pAttrs->pwzName); + ReleaseStr(pAttrs->pwzAppID); + ReleaseStr(pAttrs->pwzPartID); + + if (pAttrs->pPropList) + CpiFreePropertyList(pAttrs->pPropList); +} + +static HRESULT CreateApplicationRole( + CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piRolesColl = NULL; + ICatalogObject* piRoleObj = NULL; + + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Creating application role, key: %S", pAttrs->pwzKey); + + // get roles collection + hr = CpiGetRolesCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, &piRolesColl); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to get roles collection"); + + // check if role exists + hr = CpiFindCollectionObjectByName(piRolesColl, pAttrs->pwzName, &piRoleObj); + ExitOnFailure(hr, "Failed to find role"); + + if (S_FALSE == hr) + { + // create role + hr = CpiAddCollectionObject(piRolesColl, &piRoleObj); + ExitOnFailure(hr, "Failed to add role to collection"); + + hr = CpiPutCollectionObjectValue(piRoleObj, L"Name", pAttrs->pwzName); + ExitOnFailure(hr, "Failed to set role name property"); + } + + // properties + hr = CpiPutCollectionObjectValues(piRoleObj, pAttrs->pPropList); + ExitOnFailure(hr, "Failed to write properties"); + + // save changes + hr = piRolesColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piRolesColl); + ReleaseObject(piRoleObj); + + return hr; +} + +static HRESULT RemoveApplicationRole( + CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piRolesColl = NULL; + + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Removing application role, key: %S", pAttrs->pwzKey); + + // get roles collection + hr = CpiGetRolesCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, &piRolesColl); + ExitOnFailure(hr, "Failed to get roles collection"); + + if (S_FALSE == hr) + { + // roles collection not found + WcaLog(LOGMSG_VERBOSE, "Unable to retrieve roles collection, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // remove + hr = CpiRemoveCollectionObject(piRolesColl, NULL, pAttrs->pwzName, FALSE); + ExitOnFailure(hr, "Failed to remove role"); + + if (S_FALSE == hr) + { + // role not found + WcaLog(LOGMSG_VERBOSE, "Role not found, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // save changes + hr = piRolesColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piRolesColl); + + return hr; +} + +static HRESULT ReadUsersInApplicationRoleAttributes( + LPWSTR* ppwzData, + CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); + ExitOnFailure(hr, "Failed to read action type"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); + ExitOnFailure(hr, "Failed to read action cost"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); + ExitOnFailure(hr, "Failed to read key"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzRoleName); + ExitOnFailure(hr, "Failed to read role name"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount); + ExitOnFailure(hr, "Failed to read account name"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID); + ExitOnFailure(hr, "Failed to read application id"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); + ExitOnFailure(hr, "Failed to read partition id"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreeUsersInApplicationRoleAttributes( + CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ) +{ + ReleaseStr(pAttrs->pwzKey); + ReleaseStr(pAttrs->pwzRoleName); + ReleaseStr(pAttrs->pwzAccount); + ReleaseStr(pAttrs->pwzAppID); + ReleaseStr(pAttrs->pwzPartID); +} + +static HRESULT CreateUsersInApplicationRole( + CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogCollection* piUsrInRoleColl = NULL; + ICatalogObject* piUsrInRoleObj = NULL; + + PSID pSid = NULL; + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Adding user to application role, key: %S", pAttrs->pwzKey); + + // get users in role collection + hr = CpiGetUsersInRoleCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzRoleName, &piUsrInRoleColl); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to get users in role collection"); + + // get SID for account + do { + er = ERROR_SUCCESS; + hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK)) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount); + er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + switch (er) + { + case IDABORT: + ExitFunction(); // exit with error code from CpiAccountNameToSid() + case IDRETRY: + break; + case IDIGNORE: + default: + ExitFunction1(hr = S_OK); + } + } + else + ExitOnFailure(hr, "Failed to get SID for account"); + } while (IDRETRY == er); + + // find any existing entry + hr = CpiFindUserCollectionObject(piUsrInRoleColl, pSid, NULL); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr) + WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr); + else + ExitOnFailure(hr, "Failed to find user in application role"); + + if (S_OK == hr) + { + WcaLog(LOGMSG_VERBOSE, "User already assigned to application role, key: %S", pAttrs->pwzKey); + ExitFunction(); // exit with hr = S_OK + } + + // convert SID back to account name + hr = CpiSidToAccountName(pSid, &pAttrs->pwzAccount); + ExitOnFailure(hr, "Failed to convert SID to account name"); + + // add user + hr = CpiAddCollectionObject(piUsrInRoleColl, &piUsrInRoleObj); + ExitOnFailure(hr, "Failed to add user in role to collection"); + + hr = CpiPutCollectionObjectValue(piUsrInRoleObj, L"User", pAttrs->pwzAccount); + ExitOnFailure(hr, "Failed to set role name property"); + + // save changes + hr = piUsrInRoleColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piUsrInRoleColl); + ReleaseObject(piUsrInRoleObj); + + if (pSid) + ::HeapFree(::GetProcessHeap(), 0, pSid); + + return hr; +} + +static HRESULT RemoveUsersInApplicationRole( + CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogCollection* piUsrInRoleColl = NULL; + + PSID pSid = NULL; + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Removing user from application role, key: %S", pAttrs->pwzKey); + + // get users in role collection + hr = CpiGetUsersInRoleCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzRoleName, &piUsrInRoleColl); + ExitOnFailure(hr, "Failed to get users in role collection"); + + if (S_FALSE == hr) + { + // users in role collection not found + WcaLog(LOGMSG_VERBOSE, "Unable to retrieve users in role collection, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // get SID for account + do { + er = ERROR_SUCCESS; + hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK)) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount); + er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + switch (er) + { + case IDABORT: + ExitFunction(); // exit with error code from CpiAccountNameToSid() + case IDRETRY: + break; + case IDIGNORE: + default: + ExitFunction1(hr = S_OK); + } + } + else + ExitOnFailure(hr, "Failed to get SID for account"); + } while (IDRETRY == er); + + // remove + hr = CpiRemoveUserCollectionObject(piUsrInRoleColl, pSid); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr); + hr = S_FALSE; + } + else + ExitOnFailure(hr, "Failed to remove user"); + + if (S_FALSE == hr) + { + // role not found + WcaLog(LOGMSG_VERBOSE, "User not found for application role, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // save changes + hr = piUsrInRoleColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piUsrInRoleColl); + + if (pSid) + ::HeapFree(::GetProcessHeap(), 0, pSid); + + return hr; +} diff --git a/src/ca/cpapproleexec.h b/src/ca/cpapproleexec.h new file mode 100644 index 00000000..1251cbdb --- /dev/null +++ b/src/ca/cpapproleexec.h @@ -0,0 +1,20 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +HRESULT CpiConfigureApplicationRoles( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ); +HRESULT CpiRollbackConfigureApplicationRoles( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ); +HRESULT CpiConfigureUsersInApplicationRoles( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ); +HRESULT CpiRollbackConfigureUsersInApplicationRoles( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ); diff --git a/src/ca/cpapprolesched.cpp b/src/ca/cpapprolesched.cpp new file mode 100644 index 00000000..a268d156 --- /dev/null +++ b/src/ca/cpapprolesched.cpp @@ -0,0 +1,843 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// sql queries + +LPCWSTR vcsApplicationRoleQuery = + L"SELECT `ApplicationRole`, `Application_`, `Component_`, `Name` FROM `ComPlusApplicationRole`"; +enum eApplicationRoleQuery { arqApplicationRole = 1, arqApplication, arqComponent, arqName }; + +LPCWSTR vcsUserInApplicationRoleQuery = + L"SELECT `UserInApplicationRole`, `ApplicationRole_`, `ComPlusUserInApplicationRole`.`Component_`, `Domain`, `Name` FROM `ComPlusUserInApplicationRole`, `User` WHERE `User_` = `User`"; +LPCWSTR vcsGroupInApplicationRoleQuery = + L"SELECT `GroupInApplicationRole`, `ApplicationRole_`, `ComPlusGroupInApplicationRole`.`Component_`, `Domain`, `Name` FROM `ComPlusGroupInApplicationRole`, `Group` WHERE `Group_` = `Group`"; +enum eTrusteeInApplicationRoleQuery { tiarqUserInApplicationRole = 1, tiarqApplicationRole, tiarqComponent, tiarqDomain, tiarqName }; + +LPCWSTR vcsApplicationRolePropertyQuery = + L"SELECT `Name`, `Value` FROM `ComPlusApplicationRoleProperty` WHERE `ApplicationRole_` = ?"; + + +// property definitions + +CPI_PROPERTY_DEFINITION pdlApplicationRoleProperties[] = +{ + {L"Description", cpptString, 500}, + {NULL, cpptNone, 0} +}; + + +// prototypes for private helper functions + +static HRESULT TrusteesInApplicationRolesRead( + LPCWSTR pwzQuery, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList + ); +static void FreeApplicationRole( + CPI_APPLICATION_ROLE* pItm + ); +static void FreeUserInApplicationRole( + CPI_USER_IN_APPLICATION_ROLE* pItm + ); +//static HRESULT GetUsersCollForApplicationRole( +// CPI_APPLICATION_ROLE* pAppRole, +// ICatalogCollection** ppiUsersColl +// ); +static HRESULT FindObjectForApplicationRole( + CPI_APPLICATION_ROLE* pItm, + ICatalogObject** ppiRoleObj + ); +static HRESULT AddApplicationRoleToActionData( + CPI_APPLICATION_ROLE* pItm, + int iActionType, + int iActionCost, + LPWSTR* ppwzActionData + ); +static HRESULT AddUserInApplicationRoleToActionData( + CPI_USER_IN_APPLICATION_ROLE* pItm, + int iActionType, + int iActionCost, + LPWSTR* ppwzActionData + ); + + +// function definitions + +void CpiApplicationRoleListFree( + CPI_APPLICATION_ROLE_LIST* pList + ) +{ + CPI_APPLICATION_ROLE* pItm = pList->pFirst; + + while (pItm) + { + CPI_APPLICATION_ROLE* pDelete = pItm; + pItm = pItm->pNext; + FreeApplicationRole(pDelete); + } +} + +HRESULT CpiApplicationRolesRead( + CPI_APPLICATION_LIST* pAppList, + CPI_APPLICATION_ROLE_LIST* pAppRoleList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + + CPI_APPLICATION_ROLE* pItm = NULL; + LPWSTR pwzData = NULL; + BOOL fMatchingArchitecture = FALSE; + + // loop through all application roles + hr = WcaOpenExecuteView(vcsApplicationRoleQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on ComPlusApplicationRole table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // get component + hr = WcaGetRecordString(hRec, arqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get component"); + + // check if the component is our processor architecture + if (pwzData && *pwzData) + { + hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); + ExitOnFailure(hr, "Failed to get component architecture."); + + if (!fMatchingArchitecture) + { + continue; // not the same architecture, ignore + } + } + + // create entry + pItm = (CPI_APPLICATION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_APPLICATION_ROLE)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get component install state + if (pwzData && *pwzData) + { + pItm->fHasComponent = TRUE; + + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); + } + + // get key + hr = WcaGetRecordString(hRec, arqApplicationRole, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get application + hr = WcaGetRecordString(hRec, arqApplication, &pwzData); + ExitOnFailure(hr, "Failed to get application"); + + hr = CpiApplicationFindByKey(pAppList, pwzData, &pItm->pApplication); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to find application, key: %S", pwzData); + + // get name + hr = WcaGetRecordFormattedString(hRec, arqName, &pwzData); + ExitOnFailure(hr, "Failed to get name"); + StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); + + // get properties + if (CpiTableExists(cptComPlusApplicationRoleProperty)) + { + hr = CpiPropertiesRead(vcsApplicationRolePropertyQuery, pItm->wzKey, pdlApplicationRoleProperties, &pItm->pProperties, &pItm->iPropertyCount); + ExitOnFailure(hr, "Failed to get properties"); + } + + // set references & increment counters + if (pItm->fHasComponent) + { + if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + { + CpiApplicationAddReferenceInstall(pItm->pApplication); + pAppRoleList->iInstallCount++; + } + if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + { + CpiApplicationAddReferenceUninstall(pItm->pApplication); + pAppRoleList->iUninstallCount++; + } + } + + // add entry + if (pAppRoleList->pFirst) + pItm->pNext = pAppRoleList->pFirst; + pAppRoleList->pFirst = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + FreeApplicationRole(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +HRESULT CpiApplicationRolesVerifyInstall( + CPI_APPLICATION_ROLE_LIST* pList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogObject* piRoleObj = NULL; + + for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // referenced locaters or roles that are being installed + if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))) + continue; + + // if the role is referensed and is not a locater, it must be installed + if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction)) + MessageExitOnFailure(hr = E_FAIL, msierrComPlusApplicationRoleDependency, "An application role is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey); + + // role is a locater + if (!pItm->fHasComponent) + { + // get collection object for role + hr = FindObjectForApplicationRole(pItm, &piRoleObj); + ExitOnFailure(hr, "Failed to find collection object for role"); + + // if the role was not found + if (S_FALSE == hr) + MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusApplicationRoleNotFound, "An application role required by this installation was not found, key: %S", pItm->wzKey); + } + + // role is supposed to be created + else if (!CpiIsInstalled(pItm->isInstalled)) + { + do { + // find roles with conflicting name or id + hr = FindObjectForApplicationRole(pItm, NULL); + ExitOnFailure(hr, "Failed to find collection object for role"); + + if (S_OK == hr) + { + er = WcaErrorMessage(msierrComPlusApplicationRoleConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + switch (er) + { + case IDABORT: + ExitOnFailure(hr = E_FAIL, "An application with a conflictiong name exists, key: %S", pItm->wzKey); + break; + case IDRETRY: + break; + case IDIGNORE: + default: + hr = S_FALSE; // indicate that this is not a conflict + } + } + } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts + } + + // clean up + ReleaseNullObject(piRoleObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piRoleObj); + + return hr; +} + +HRESULT CpiApplicationRolesVerifyUninstall( + CPI_APPLICATION_ROLE_LIST* pList + ) +{ + HRESULT hr = S_OK; + + for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // referenced locaters or roles that are being installed + if (!pItm->fReferencedForUninstall && !(pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction))) + continue; + + // get collection object for role + hr = FindObjectForApplicationRole(pItm, NULL); + ExitOnFailure(hr, "Failed to find collection object for role"); + + // if the role was not found + if (S_FALSE == hr) + { + pItm->fObjectNotFound = TRUE; + if (pItm->fHasComponent) + pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall + } + } + + hr = S_OK; + +LExit: + return hr; +} + +void CpiApplicationRoleAddReferenceInstall( + CPI_APPLICATION_ROLE* pItm + ) +{ + pItm->fReferencedForInstall = TRUE; + CpiApplicationAddReferenceInstall(pItm->pApplication); +} + +void CpiApplicationRoleAddReferenceUninstall( + CPI_APPLICATION_ROLE* pItm + ) +{ + pItm->fReferencedForUninstall = TRUE; + CpiApplicationAddReferenceUninstall(pItm->pApplication); +} + +HRESULT CpiApplicationRolesInstall( + CPI_APPLICATION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"CreateComPlusApplicationRoles", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add count to action data + hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add roles to custom action data + for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // roles that are being installed only + if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + { + if (CpiIsInstalled(pItm->isInstalled)) + iActionType = atNoOp; + else + iActionType = atRemove; + } + else + iActionType = atCreate; + + // add to action data + hr = AddApplicationRoleToActionData(pItm, iActionType, COST_APPLICATION_ROLE_CREATE, ppwzActionData); + ExitOnFailure(hr, "Failed to add application role to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_APPLICATION_ROLE_CREATE * pList->iInstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiApplicationRolesUninstall( + CPI_APPLICATION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"RemoveComPlusApplicationRoles", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add count to action data + hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add roles to custom action data + for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // roles that are being uninstalled only + if (pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + iActionType = atCreate; + else + iActionType = atRemove; + + // add to action data + hr = AddApplicationRoleToActionData(pItm, iActionType, COST_APPLICATION_ROLE_DELETE, ppwzActionData); + ExitOnFailure(hr, "Failed to add application role to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_APPLICATION_ROLE_DELETE * pList->iUninstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiApplicationRoleFindByKey( + CPI_APPLICATION_ROLE_LIST* pList, + LPCWSTR pwzKey, + CPI_APPLICATION_ROLE** ppAppRole + ) +{ + for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + if (0 == lstrcmpW(pItm->wzKey, pwzKey)) + { + *ppAppRole = pItm; + return S_OK; + } + } + + return S_FALSE; +} + +void CpiUserInApplicationRoleListFree( + CPI_USER_IN_APPLICATION_ROLE_LIST* pList + ) +{ + CPI_USER_IN_APPLICATION_ROLE* pItm = pList->pFirst; + + while (pItm) + { + CPI_USER_IN_APPLICATION_ROLE* pDelete = pItm; + pItm = pItm->pNext; + FreeUserInApplicationRole(pDelete); + } +} + +HRESULT CpiUsersInApplicationRolesRead( + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList + ) +{ + HRESULT hr = S_OK; + + // read users in application roles + if (CpiTableExists(cptComPlusUserInApplicationRole)) + { + hr = TrusteesInApplicationRolesRead(vcsUserInApplicationRoleQuery, pAppRoleList, pUsrInAppRoleList); + ExitOnFailure(hr, "Failed to read users in application roles"); + } + + // read groups in application roles + if (CpiTableExists(cptComPlusGroupInApplicationRole)) + { + hr = TrusteesInApplicationRolesRead(vcsGroupInApplicationRoleQuery, pAppRoleList, pUsrInAppRoleList); + ExitOnFailure(hr, "Failed to read groups in application roles"); + } + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiUsersInApplicationRolesInstall( + CPI_USER_IN_APPLICATION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"AddUsersToComPlusApplicationRoles", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add count to action data + hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add roles to custom action data + for (CPI_USER_IN_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // roles that are being installed only + if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + { + if (CpiIsInstalled(pItm->isInstalled)) + iActionType = atNoOp; + else + iActionType = atRemove; + } + else + iActionType = atCreate; + + // add to action data + hr = AddUserInApplicationRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_CREATE, ppwzActionData); + ExitOnFailure(hr, "Failed to add user in application role to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_USER_IN_APPLICATION_ROLE_CREATE * pList->iInstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiUsersInApplicationRolesUninstall( + CPI_USER_IN_APPLICATION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"RemoveUsersFromComPlusAppRoles", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add count to action data + hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add roles to custom action data + for (CPI_USER_IN_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // roles that are being uninstalled only + if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + iActionType = atCreate; + else + iActionType = atRemove; + + // add to action data + hr = AddUserInApplicationRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_DELETE, ppwzActionData); + ExitOnFailure(hr, "Failed to add user in application role to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_USER_IN_APPLICATION_ROLE_DELETE * pList->iUninstallCount; + + hr = S_OK; + +LExit: + return hr; +} + + +// helper function definitions + +static HRESULT TrusteesInApplicationRolesRead( + LPCWSTR pwzQuery, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + + CPI_USER_IN_APPLICATION_ROLE* pItm = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzDomain = NULL; + LPWSTR pwzName = NULL; + BOOL fMatchingArchitecture = FALSE; + + // loop through all application roles + hr = WcaOpenExecuteView(pwzQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // get component + hr = WcaGetRecordString(hRec, tiarqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get component"); + + // check if the component is our processor architecture + hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); + ExitOnFailure(hr, "Failed to get component architecture."); + + if (!fMatchingArchitecture) + { + continue; // not the same architecture, ignore + } + + // create entry + pItm = (CPI_USER_IN_APPLICATION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_USER_IN_APPLICATION_ROLE)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get component install state + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); + + // get key + hr = WcaGetRecordString(hRec, tiarqUserInApplicationRole, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get application role + hr = WcaGetRecordString(hRec, tiarqApplicationRole, &pwzData); + ExitOnFailure(hr, "Failed to get application role"); + + hr = CpiApplicationRoleFindByKey(pAppRoleList, pwzData, &pItm->pApplicationRole); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to find application role, key: %S", pwzData); + + // get user domain + hr = WcaGetRecordFormattedString(hRec, tiarqDomain, &pwzDomain); + ExitOnFailure(hr, "Failed to get domain"); + + // get user name + hr = WcaGetRecordFormattedString(hRec, tiarqName, &pwzName); + ExitOnFailure(hr, "Failed to get name"); + + // build account name + hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount); + ExitOnFailure(hr, "Failed to build account name"); + + // set references & increment counters + if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + { + CpiApplicationRoleAddReferenceInstall(pItm->pApplicationRole); + pUsrInAppRoleList->iInstallCount++; + } + if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + { + CpiApplicationRoleAddReferenceUninstall(pItm->pApplicationRole); + pUsrInAppRoleList->iUninstallCount++; + } + + // add entry + if (pUsrInAppRoleList->pFirst) + pItm->pNext = pUsrInAppRoleList->pFirst; + pUsrInAppRoleList->pFirst = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + FreeUserInApplicationRole(pItm); + + ReleaseStr(pwzData); + ReleaseStr(pwzDomain); + ReleaseStr(pwzName); + + return hr; +} + +static void FreeApplicationRole( + CPI_APPLICATION_ROLE* pItm + ) +{ + if (pItm->pProperties) + CpiPropertiesFreeList(pItm->pProperties); + + ReleaseObject(pItm->piUsersColl); + + ::HeapFree(::GetProcessHeap(), 0, pItm); +} + +static void FreeUserInApplicationRole( + CPI_USER_IN_APPLICATION_ROLE* pItm + ) +{ + ReleaseStr(pItm->pwzAccount); + + ::HeapFree(::GetProcessHeap(), 0, pItm); +} + +//static HRESULT GetUsersCollForApplicationRole( +// CPI_APPLICATION_ROLE* pAppRole, +// ICatalogCollection** ppiUsersColl +// ) +//{ +// HRESULT hr = S_OK; +// +// ICatalogCollection* piRoleColl = NULL; +// ICatalogObject* piRoleObj = NULL; +// +// // if a previous attempt to locate the collection object failed +// if (pAppRole->fObjectNotFound) +// ExitFunction1(hr = S_FALSE); +// +// // get applications collection +// if (!pAppRole->piUsersColl) +// { +// // get collection object for role +// hr = FindObjectForApplicationRole(pAppRole, &piRoleObj); +// ExitOnFailure(hr, "Failed to find collection object for role"); +// +// if (S_FALSE == hr) +// ExitFunction(); // exit with hr = S_FALSE +// +// // get users collection +// hr = CpiGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInRole", &pAppRole->piUsersColl); +// ExitOnFailure(hr, "Failed to get users in role collection"); +// } +// +// // return value +// *ppiUsersColl = pAppRole->piUsersColl; +// (*ppiUsersColl)->AddRef(); +// +// hr = S_OK; +// +//LExit: +// // clean up +// ReleaseObject(piRoleColl); +// ReleaseObject(piRoleObj); +// +// return hr; +//} + +static HRESULT FindObjectForApplicationRole( + CPI_APPLICATION_ROLE* pItm, + ICatalogObject** ppiRoleObj + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piRoleColl = NULL; + + // get roles collection + hr = CpiGetRolesCollForApplication(pItm->pApplication, &piRoleColl); + ExitOnFailure(hr, "Failed to get collection"); + + if (S_FALSE == hr) + ExitFunction(); // exit with hr = S_FALSE + + // find role object + hr = CpiFindCollectionObject(piRoleColl, NULL, pItm->wzName, ppiRoleObj); + ExitOnFailure(hr, "Failed to find object"); + + // exit with hr from CpiFindCollectionObject() + +LExit: + // clean up + ReleaseObject(piRoleColl); + + return hr; +} + +static HRESULT AddApplicationRoleToActionData( + CPI_APPLICATION_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 application role key to custom action data"); + hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData); + ExitOnFailure(hr, "Failed to add application role name to custom action data"); + + // add application information to custom action data + hr = WcaWriteStringToCaData(pItm->pApplication->wzID, ppwzActionData); + ExitOnFailure(hr, "Failed to add application id to custom action data"); + + // add partition information to custom action data + hr = WcaWriteStringToCaData(pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L"", 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; +} + +static HRESULT AddUserInApplicationRoleToActionData( + CPI_USER_IN_APPLICATION_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->pApplicationRole->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 application information to custom action data + CPI_APPLICATION* pApplication = pItm->pApplicationRole->pApplication; + hr = WcaWriteStringToCaData(pApplication->wzID, ppwzActionData); + ExitOnFailure(hr, "Failed to add application id to custom action data"); + + // add partition information to custom action data + hr = WcaWriteStringToCaData(pApplication->pPartition ? pApplication->pPartition->wzID : L"", ppwzActionData); + ExitOnFailure(hr, "Failed to add partition id to custom action data"); + + hr = S_OK; + +LExit: + return hr; +} diff --git a/src/ca/cpapprolesched.h b/src/ca/cpapprolesched.h new file mode 100644 index 00000000..02852eef --- /dev/null +++ b/src/ca/cpapprolesched.h @@ -0,0 +1,112 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +struct CPI_APPLICATION_ROLE +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzName[MAX_DARWIN_COLUMN + 1]; + + int iPropertyCount; + CPI_PROPERTY* pProperties; + + BOOL fHasComponent; + BOOL fReferencedForInstall; + BOOL fReferencedForUninstall; + BOOL fObjectNotFound; + + INSTALLSTATE isInstalled, isAction; + + CPI_APPLICATION* pApplication; + + ICatalogCollection* piUsersColl; + + CPI_APPLICATION_ROLE* pNext; +}; + +struct CPI_APPLICATION_ROLE_LIST +{ + CPI_APPLICATION_ROLE* pFirst; + + int iInstallCount; + int iUninstallCount; +}; + +struct CPI_USER_IN_APPLICATION_ROLE +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + LPWSTR pwzAccount; + + INSTALLSTATE isInstalled, isAction; + + CPI_APPLICATION_ROLE* pApplicationRole; + + CPI_USER_IN_APPLICATION_ROLE* pNext; +}; + +struct CPI_USER_IN_APPLICATION_ROLE_LIST +{ + CPI_USER_IN_APPLICATION_ROLE* pFirst; + + int iInstallCount; + int iUninstallCount; +}; + + +// function prototypes + +void CpiApplicationRoleListFree( + CPI_APPLICATION_ROLE_LIST* pList + ); +HRESULT CpiApplicationRolesRead( + CPI_APPLICATION_LIST* pAppList, + CPI_APPLICATION_ROLE_LIST* pAppRoleList + ); +HRESULT CpiApplicationRolesVerifyInstall( + CPI_APPLICATION_ROLE_LIST* pList + ); +HRESULT CpiApplicationRolesVerifyUninstall( + CPI_APPLICATION_ROLE_LIST* pList + ); +void CpiApplicationRoleAddReferenceInstall( + CPI_APPLICATION_ROLE* pItm + ); +void CpiApplicationRoleAddReferenceUninstall( + CPI_APPLICATION_ROLE* pItm + ); +HRESULT CpiApplicationRolesInstall( + CPI_APPLICATION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiApplicationRolesUninstall( + CPI_APPLICATION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiApplicationRoleFindByKey( + CPI_APPLICATION_ROLE_LIST* pList, + LPCWSTR pwzKey, + CPI_APPLICATION_ROLE** ppAppRole + ); +void CpiUserInApplicationRoleListFree( + CPI_USER_IN_APPLICATION_ROLE_LIST* pList + ); +HRESULT CpiUsersInApplicationRolesRead( + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList + ); +HRESULT CpiUsersInApplicationRolesInstall( + CPI_USER_IN_APPLICATION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiUsersInApplicationRolesUninstall( + CPI_USER_IN_APPLICATION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); diff --git a/src/ca/cpappsched.cpp b/src/ca/cpappsched.cpp new file mode 100644 index 00000000..cec99794 --- /dev/null +++ b/src/ca/cpappsched.cpp @@ -0,0 +1,752 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// sql queries + +LPCWSTR vcsApplicationQuery = + L"SELECT `Application`, `Component_`, `Partition_`, `Id`, `Name` FROM `ComPlusApplication`"; +enum eApplicationQuery { aqApplication = 1, aqComponent, aqPartition, aqID, aqName }; + +LPCWSTR vcsApplicationPropertyQuery = + L"SELECT `Name`, `Value` FROM `ComPlusApplicationProperty` WHERE `Application_` = ?"; + + +// property definitions + +CPI_PROPERTY_DEFINITION pdlApplicationProperties[] = +{ + {L"3GigSupportEnabled", cpptBoolean, 500}, + {L"AccessChecksLevel", cpptInteger, 500}, + {L"Activation", cpptInteger, 500}, + {L"ApplicationAccessChecksEnabled", cpptBoolean, 500}, + {L"ApplicationDirectory", cpptString, 501}, + {L"Authentication", cpptInteger, 500}, + {L"AuthenticationCapability", cpptInteger, 500}, + {L"Changeable", cpptBoolean, 500}, + {L"CommandLine", cpptString, 500}, + {L"ConcurrentApps", cpptInteger, 501}, + {L"CreatedBy", cpptString, 500}, + {L"CRMEnabled", cpptBoolean, 500}, + {L"CRMLogFile", cpptString, 500}, + {L"Deleteable", cpptBoolean, 500}, + {L"Description", cpptString, 500}, + {L"DumpEnabled", cpptBoolean, 501}, + {L"DumpOnException", cpptBoolean, 501}, + {L"DumpOnFailfast", cpptBoolean, 501}, + {L"DumpPath", cpptString, 501}, + {L"EventsEnabled", cpptBoolean, 500}, + {L"Identity", cpptString, 500}, + {L"ImpersonationLevel", cpptInteger, 500}, + {L"IsEnabled", cpptBoolean, 501}, + {L"MaxDumpCount", cpptInteger, 501}, + {L"Password", cpptString, 500}, + {L"QCAuthenticateMsgs", cpptInteger, 501}, + {L"QCListenerMaxThreads", cpptInteger, 501}, + {L"QueueListenerEnabled", cpptBoolean, 500}, + {L"QueuingEnabled", cpptBoolean, 500}, + {L"RecycleActivationLimit", cpptInteger, 501}, + {L"RecycleCallLimit", cpptInteger, 501}, + {L"RecycleExpirationTimeout", cpptInteger, 501}, + {L"RecycleLifetimeLimit", cpptInteger, 501}, + {L"RecycleMemoryLimit", cpptInteger, 501}, + {L"Replicable", cpptBoolean, 501}, + {L"RunForever", cpptBoolean, 500}, + {L"ShutdownAfter", cpptInteger, 500}, + {L"SoapActivated", cpptBoolean, 502}, + {L"SoapBaseUrl", cpptString, 502}, + {L"SoapMailTo", cpptString, 502}, + {L"SoapVRoot", cpptString, 502}, + {L"SRPEnabled", cpptBoolean, 501}, + {L"SRPTrustLevel", cpptInteger, 501}, + {NULL, cpptNone, 0} +}; + + +// prototypes for private helper functions + +static void FreeApplication( + CPI_APPLICATION* pItm + ); +static HRESULT FindObjectForApplication( + CPI_APPLICATION* pItm, + BOOL fFindId, + BOOL fFindName, + ICatalogObject** ppiAppObj + ); +static HRESULT AddApplicationToActionData( + CPI_APPLICATION* pItm, + int iActionType, + int iActionCost, + LPWSTR* ppwzActionData + ); + + +// function definitions + +void CpiApplicationListFree( + CPI_APPLICATION_LIST* pList + ) +{ + CPI_APPLICATION* pItm = pList->pFirst; + + while (pItm) + { + CPI_APPLICATION* pDelete = pItm; + pItm = pItm->pNext; + FreeApplication(pDelete); + } +} + +HRESULT CpiApplicationsRead( + CPI_PARTITION_LIST* pPartList, + CPI_APPLICATION_LIST* pAppList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + int iVersionNT = 0; + + PMSIHANDLE hView, hRec; + + CPI_APPLICATION* pItm = NULL; + LPWSTR pwzData = NULL; + BOOL fMatchingArchitecture = FALSE; + + // get NT version + hr = WcaGetIntProperty(L"VersionNT", &iVersionNT); + ExitOnFailure(hr, "Failed to get VersionNT property"); + + // loop through all applications + hr = WcaOpenExecuteView(vcsApplicationQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on ComPlusApplication table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // get component + hr = WcaGetRecordString(hRec, aqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get component"); + + // check if the component is our processor architecture + if (pwzData && *pwzData) + { + hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); + ExitOnFailure(hr, "Failed to get component architecture."); + + if (!fMatchingArchitecture) + { + continue; // not the same architecture, ignore + } + } + + // create entry + pItm = (CPI_APPLICATION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_APPLICATION)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get component install state + if (pwzData && *pwzData) + { + pItm->fHasComponent = TRUE; + + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); + } + + // get key + hr = WcaGetRecordString(hRec, aqApplication, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get partition + if (502 <= iVersionNT) + { + hr = WcaGetRecordString(hRec, aqPartition, &pwzData); + ExitOnFailure(hr, "Failed to get partition"); + + if (pwzData && *pwzData) + { + hr = CpiPartitionFindByKey(pPartList, pwzData, &pItm->pPartition); + ExitOnFailure(hr, "Failed to find partition, key: %S", pwzData); + } + } + + // get id + hr = WcaGetRecordFormattedString(hRec, aqID, &pwzData); + ExitOnFailure(hr, "Failed to get id"); + + if (pwzData && *pwzData) + { + hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData); + } + + // get name + hr = WcaGetRecordFormattedString(hRec, aqName, &pwzData); + ExitOnFailure(hr, "Failed to get name"); + StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); + + // if application is a locater, either an id or a name must be provided + if (!pItm->fHasComponent && !*pItm->wzID && !*pItm->wzName) + ExitOnFailure(hr = E_FAIL, "An application locater must have either an id or a name associated, key: %S", pItm->wzKey); + + // if application is not a locater, an name must be provided + if (pItm->fHasComponent && !*pItm->wzName) + ExitOnFailure(hr = E_FAIL, "An application must have a name associated, key: %S", pItm->wzKey); + + // get properties + if (CpiTableExists(cptComPlusApplicationProperty) && pItm->fHasComponent) + { + hr = CpiPropertiesRead(vcsApplicationPropertyQuery, pItm->wzKey, pdlApplicationProperties, &pItm->pProperties, &pItm->iPropertyCount); + ExitOnFailure(hr, "Failed to get properties"); + } + + // set references & increment counters + if (pItm->fHasComponent) + { + if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + { + if (pItm->pPartition) + CpiPartitionAddReferenceInstall(pItm->pPartition); + pAppList->iInstallCount++; + } + if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + { + if (pItm->pPartition) + CpiPartitionAddReferenceUninstall(pItm->pPartition); + pAppList->iUninstallCount++; + } + } + + // add entry + if (pAppList->pFirst) + pItm->pNext = pAppList->pFirst; + pAppList->pFirst = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + FreeApplication(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +HRESULT CpiApplicationsVerifyInstall( + CPI_APPLICATION_LIST* pList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogObject* piAppObj = NULL; + + for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // referenced locaters or applications that are being installed + if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))) + continue; + + // if the application is referensed and is not a locater, it must be installed + if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction)) + MessageExitOnFailure(hr = E_FAIL, msierrComPlusApplicationDependency, "An application is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey); + + // application is supposed to exist + if (!pItm->fHasComponent || CpiIsInstalled(pItm->isInstalled)) + { + // get collection object for application + hr = FindObjectForApplication(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piAppObj); + ExitOnFailure(hr, "Failed to find collection object for application"); + + // if the application was found + if (S_OK == hr) + { + // if we don't have an id, copy id from object + if (!*pItm->wzID) + { + hr = CpiGetKeyForObject(piAppObj, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to get id"); + } + } + + // if the application was not found + else + { + // if the application is a locater, this is an error + if (!pItm->fHasComponent) + MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusApplicationNotFound, "An application required by this installation was not found, key: %S", pItm->wzKey); + + // create a new id if one is missing + if (!*pItm->wzID) + { + hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to create id"); + } + } + } + + // application is supposed to be created + else + { + // check for conflicts + do { + if (*pItm->wzID) + { + // find applications with conflicting id + hr = FindObjectForApplication(pItm, TRUE, FALSE, &piAppObj); + ExitOnFailure(hr, "Failed to find collection object for application"); + + if (S_FALSE == hr) + { + // find applications with conflicting name + hr = FindObjectForApplication(pItm, FALSE, TRUE, &piAppObj); + ExitOnFailure(hr, "Failed to find collection object for application"); + + if (S_OK == hr) + // "A application with a conflictiong name exists. retry cancel" + er = WcaErrorMessage(msierrComPlusApplicationNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0); + else + break; // no conflicting entry found, break loop + } + else + // "A application with a conflicting id exists. abort retry ignore" + er = WcaErrorMessage(msierrComPlusApplicationIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + } + else + { + // find applications with conflicting name + hr = FindObjectForApplication(pItm, FALSE, TRUE, &piAppObj); + ExitOnFailure(hr, "Failed to find collection object for application"); + + if (S_OK == hr) + // "A subscription with a conflictiong name exists. abort retry ignore" + er = WcaErrorMessage(msierrComPlusApplicationNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + else + break; // no conflicting entry found, break loop + } + + switch (er) + { + case IDCANCEL: + case IDABORT: + ExitOnFailure(hr = E_FAIL, "An application with a conflictiong name or id exists, key: %S", pItm->wzKey); + break; + case IDRETRY: + break; + case IDIGNORE: + default: + // if we don't have an id, copy id from object + if (!*pItm->wzID) + { + hr = CpiGetKeyForObject(piAppObj, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to get id"); + } + hr = S_FALSE; // indicate that this is not a conflict + } + } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts + + // create a new id if one is missing + if (!*pItm->wzID) + { + hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to create id"); + } + } + + // clean up + ReleaseNullObject(piAppObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piAppObj); + + return hr; +} + +HRESULT CpiApplicationsVerifyUninstall( + CPI_APPLICATION_LIST* pList + ) +{ + HRESULT hr = S_OK; + ICatalogObject* piAppObj = NULL; + + for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // referenced locaters or applications that are being installed + if (!pItm->fReferencedForUninstall && !(pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction))) + continue; + + // get collection object for application + hr = FindObjectForApplication(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piAppObj); + ExitOnFailure(hr, "Failed to find collection object for application"); + + // if the application was found + if (S_OK == hr) + { + // if we don't have an id, copy id from object + if (!*pItm->wzID) + { + hr = CpiGetKeyForObject(piAppObj, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to get id"); + } + } + + // if the application was not found + else + { + pItm->fObjectNotFound = TRUE; + if (pItm->fHasComponent) + pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall + } + + // clean up + ReleaseNullObject(piAppObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piAppObj); + + return hr; +} + +void CpiApplicationAddReferenceInstall( + CPI_APPLICATION* pItm + ) +{ + pItm->fReferencedForInstall = TRUE; + if (pItm->pPartition) + CpiPartitionAddReferenceInstall(pItm->pPartition); +} + +void CpiApplicationAddReferenceUninstall( + CPI_APPLICATION* pItm + ) +{ + pItm->fReferencedForUninstall = TRUE; + if (pItm->pPartition) + CpiPartitionAddReferenceUninstall(pItm->pPartition); +} + +HRESULT CpiApplicationsInstall( + CPI_APPLICATION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"CreateComPlusApplications", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add applicaton count to action data + hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add applications to custom action data + for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // applications that are being installed only + if (!pItm->fHasComponent || !WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + { + if (CpiIsInstalled(pItm->isInstalled)) + iActionType = atNoOp; + else + iActionType = atRemove; + } + else + iActionType = atCreate; + + // add to action data + hr = AddApplicationToActionData(pItm, iActionType, COST_APPLICATION_CREATE, ppwzActionData); + ExitOnFailure(hr, "Failed to add applicaton to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_APPLICATION_CREATE * pList->iInstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiApplicationsUninstall( + CPI_APPLICATION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"RemoveComPlusApplications", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add applicaton count to action data + hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add applications to custom action data + for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // applications that are being uninstalled only + if (!pItm->fHasComponent || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + iActionType = atCreate; + else + iActionType = atRemove; + + // add to action data + hr = AddApplicationToActionData(pItm, iActionType, COST_APPLICATION_DELETE, ppwzActionData); + ExitOnFailure(hr, "Failed to add applicaton to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_APPLICATION_DELETE * pList->iUninstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiApplicationFindByKey( + CPI_APPLICATION_LIST* pList, + LPCWSTR pwzKey, + CPI_APPLICATION** ppApp + ) +{ + for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + if (0 == lstrcmpW(pItm->wzKey, pwzKey)) + { + *ppApp = pItm; + return S_OK; + } + } + + return S_FALSE; +} + +HRESULT CpiGetRolesCollForApplication( + CPI_APPLICATION* pApp, + ICatalogCollection** ppiRolesColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piAppColl = NULL; + ICatalogObject* piAppObj = NULL; + + // if a previous attempt to locate the collection object failed + if (pApp->fObjectNotFound) + ExitFunction1(hr = S_FALSE); + + // get applications collection + if (!pApp->piRolesColl) + { + // get applications collection + if (pApp->pPartition) + hr = CpiGetApplicationsCollForPartition(pApp->pPartition, &piAppColl); + else + hr = CpiGetApplicationsCollection(&piAppColl); + ExitOnFailure(hr, "Failed to get applications collection"); + + if (S_FALSE == hr) + ExitFunction(); // exit with hr = S_FALSE + + // find application object + hr = CpiFindCollectionObject(piAppColl, pApp->wzID, *pApp->wzID ? NULL : pApp->wzName, &piAppObj); + ExitOnFailure(hr, "Failed to find application object"); + + if (S_FALSE == hr) + ExitFunction(); // exit with hr = S_FALSE + + // get roles collection + hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Roles", &pApp->piRolesColl); + ExitOnFailure(hr, "Failed to get roles collection"); + } + + // return value + *ppiRolesColl = pApp->piRolesColl; + (*ppiRolesColl)->AddRef(); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piAppColl); + ReleaseObject(piAppObj); + + return hr; +} + +HRESULT CpiGetComponentsCollForApplication( + CPI_APPLICATION* pApp, + ICatalogCollection** ppiCompsColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piAppColl = NULL; + ICatalogObject* piAppObj = NULL; + + // if a previous attempt to locate the collection object failed + if (pApp->fObjectNotFound) + ExitFunction1(hr = S_FALSE); + + // get applications collection + if (!pApp->piCompsColl) + { + // get applications collection + if (pApp->pPartition) + hr = CpiGetApplicationsCollForPartition(pApp->pPartition, &piAppColl); + else + hr = CpiGetApplicationsCollection(&piAppColl); + ExitOnFailure(hr, "Failed to get applications collection"); + + if (S_FALSE == hr) + ExitFunction(); // exit with hr = S_FALSE + + // find application object + hr = CpiFindCollectionObject(piAppColl, pApp->wzID, *pApp->wzID ? NULL : pApp->wzName, &piAppObj); + ExitOnFailure(hr, "Failed to find application object"); + + if (S_FALSE == hr) + ExitFunction(); // exit with hr = S_FALSE + + // get roles collection + hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Components", &pApp->piCompsColl); + ExitOnFailure(hr, "Failed to get components collection"); + } + + // return value + *ppiCompsColl = pApp->piCompsColl; + (*ppiCompsColl)->AddRef(); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piAppColl); + ReleaseObject(piAppObj); + + return hr; +} + + +// helper function definitions + +static void FreeApplication( + CPI_APPLICATION* pItm + ) +{ + if (pItm->pProperties) + CpiPropertiesFreeList(pItm->pProperties); + + ReleaseObject(pItm->piRolesColl); + ReleaseObject(pItm->piCompsColl); + + ::HeapFree(::GetProcessHeap(), 0, pItm); +} + +static HRESULT FindObjectForApplication( + CPI_APPLICATION* pItm, + BOOL fFindId, + BOOL fFindName, + ICatalogObject** ppiAppObj + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piAppColl = NULL; + + // get applications collection + if (pItm->pPartition) + hr = CpiGetApplicationsCollForPartition(pItm->pPartition, &piAppColl); + else + hr = CpiGetApplicationsCollection(&piAppColl); + ExitOnFailure(hr, "Failed to get applications collection"); + + if (S_FALSE == hr) + ExitFunction(); // exit with hr = S_FALSE + + // find application object + hr = CpiFindCollectionObject(piAppColl, fFindId ? pItm->wzID : NULL, fFindName ? pItm->wzName : NULL, ppiAppObj); + ExitOnFailure(hr, "Failed to find application object"); + + // exit with hr from CpiFindCollectionObject() + +LExit: + // clean up + ReleaseObject(piAppColl); + + return hr; +} + +static HRESULT AddApplicationToActionData( + CPI_APPLICATION* 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 information to custom action data + hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData); + ExitOnFailure(hr, "Failed to add application key to custom action data"); + hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData); + ExitOnFailure(hr, "Failed to add application id to custom action data"); + hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData); + ExitOnFailure(hr, "Failed to add application name to custom action data"); + + // add partition information to custom action data + hr = WcaWriteStringToCaData(pItm->pPartition ? pItm->pPartition->wzID : L"", 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; +} diff --git a/src/ca/cpappsched.h b/src/ca/cpappsched.h new file mode 100644 index 00000000..2cd6a0ee --- /dev/null +++ b/src/ca/cpappsched.h @@ -0,0 +1,83 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +struct CPI_APPLICATION +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzID[CPI_MAX_GUID + 1]; + WCHAR wzName[MAX_DARWIN_COLUMN + 1]; + + int iPropertyCount; + CPI_PROPERTY* pProperties; + + BOOL fHasComponent; + BOOL fReferencedForInstall; + BOOL fReferencedForUninstall; + BOOL fObjectNotFound; + + INSTALLSTATE isInstalled, isAction; + + CPI_PARTITION* pPartition; + + ICatalogCollection* piRolesColl; + ICatalogCollection* piCompsColl; + + CPI_APPLICATION* pNext; +}; + +struct CPI_APPLICATION_LIST +{ + CPI_APPLICATION* pFirst; + + int iInstallCount; + int iUninstallCount; +}; + + +// function prototypes + +void CpiApplicationListFree( + CPI_APPLICATION_LIST* pList + ); +HRESULT CpiApplicationsRead( + CPI_PARTITION_LIST* pPartList, + CPI_APPLICATION_LIST* pAppList + ); +HRESULT CpiApplicationsVerifyInstall( + CPI_APPLICATION_LIST* pList + ); +HRESULT CpiApplicationsVerifyUninstall( + CPI_APPLICATION_LIST* pList + ); +void CpiApplicationAddReferenceInstall( + CPI_APPLICATION* pItm + ); +void CpiApplicationAddReferenceUninstall( + CPI_APPLICATION* pItm + ); +HRESULT CpiApplicationsInstall( + CPI_APPLICATION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiApplicationsUninstall( + CPI_APPLICATION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiApplicationFindByKey( + CPI_APPLICATION_LIST* pList, + LPCWSTR pwzKey, + CPI_APPLICATION** ppApp + ); +HRESULT CpiGetRolesCollForApplication( + CPI_APPLICATION* pApp, + ICatalogCollection** ppiRolesColl + ); +HRESULT CpiGetComponentsCollForApplication( + CPI_APPLICATION* pApp, + ICatalogCollection** ppiCompsColl + ); diff --git a/src/ca/cpasmexec.cpp b/src/ca/cpasmexec.cpp new file mode 100644 index 00000000..339c08e1 --- /dev/null +++ b/src/ca/cpasmexec.cpp @@ -0,0 +1,1888 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// GAC related declarations + +typedef struct _FUSION_INSTALL_REFERENCE_ +{ + DWORD cbSize; + DWORD dwFlags; + GUID guidScheme; + LPCWSTR szIdentifier; + LPCWSTR szNonCannonicalData; +} FUSION_INSTALL_REFERENCE; + +typedef struct _FUSION_INSTALL_REFERENCE_ *LPFUSION_INSTALL_REFERENCE; + +typedef const FUSION_INSTALL_REFERENCE *LPCFUSION_INSTALL_REFERENCE; + +typedef struct _ASSEMBLY_INFO +{ + ULONG cbAssemblyInfo; + DWORD dwAssemblyFlags; + ULARGE_INTEGER uliAssemblySizeInKB; + LPWSTR pszCurrentAssemblyPathBuf; + ULONG cchBuf; +} ASSEMBLY_INFO; + +typedef interface IAssemblyCacheItem IAssemblyCacheItem; + +MIDL_INTERFACE("e707dcde-d1cd-11d2-bab9-00c04f8eceae") +IAssemblyCache : public IUnknown +{ +public: + virtual HRESULT STDMETHODCALLTYPE UninstallAssembly( + /* [in] */ DWORD dwFlags, + /* [in] */ LPCWSTR pszAssemblyName, + /* [in] */ LPCFUSION_INSTALL_REFERENCE pRefData, + /* [optional][out] */ ULONG *pulDisposition) = 0; + + virtual HRESULT STDMETHODCALLTYPE QueryAssemblyInfo( + /* [in] */ DWORD dwFlags, + /* [in] */ LPCWSTR pszAssemblyName, + /* [out][in] */ ASSEMBLY_INFO *pAsmInfo) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateAssemblyCacheItem( + /* [in] */ DWORD dwFlags, + /* [in] */ PVOID pvReserved, + /* [out] */ IAssemblyCacheItem **ppAsmItem, + /* [optional][in] */ LPCWSTR pszAssemblyName) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateAssemblyScavenger( + /* [out] */ IUnknown **ppUnkReserved) = 0; + + virtual HRESULT STDMETHODCALLTYPE InstallAssembly( + /* [in] */ DWORD dwFlags, + /* [in] */ LPCWSTR pszManifestFilePath, + /* [in] */ LPCFUSION_INSTALL_REFERENCE pRefData) = 0; +}; + +typedef HRESULT (__stdcall *LoadLibraryShimFunc)(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll); +typedef HRESULT (__stdcall *CreateAssemblyCacheFunc)(IAssemblyCache **ppAsmCache, DWORD dwReserved); + + +// RegistrationHelper related declarations + +static const GUID CLSID_RegistrationHelper = + { 0x89a86e7b, 0xc229, 0x4008, { 0x9b, 0xaa, 0x2f, 0x5c, 0x84, 0x11, 0xd7, 0xe0 } }; + +enum eInstallationFlags { + ifConfigureComponentsOnly = 16, + ifFindOrCreateTargetApplication = 4, + ifExpectExistingTypeLib = 1 +}; + + +// private constants + +enum eAssemblyAttributes +{ + aaEventClass = (1 << 0), + aaDotNetAssembly = (1 << 1), + aaPathFromGAC = (1 << 2), + aaRunInCommit = (1 << 3) +}; + + +// private structs + +struct CPI_ROLE_ASSIGNMENT +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzRoleName[MAX_DARWIN_COLUMN + 1]; + + CPI_ROLE_ASSIGNMENT* pNext; +}; + +struct CPI_METHOD +{ + WCHAR wzIndex[11 + 1]; + WCHAR wzName[MAX_DARWIN_COLUMN + 1]; + + CPI_PROPERTY* pPropertyList; + CPI_ROLE_ASSIGNMENT* pRoleAssignmentList; + + CPI_METHOD* pNext; +}; + +struct CPI_INTERFACE +{ + WCHAR wzIID[CPI_MAX_GUID + 1]; + + CPI_PROPERTY* pPropertyList; + CPI_ROLE_ASSIGNMENT* pRoleAssignmentList; + CPI_METHOD* pMethodList; + + CPI_INTERFACE* pNext; +}; + +struct CPI_COMPONENT +{ + WCHAR wzCLSID[CPI_MAX_GUID + 1]; + + CPI_PROPERTY* pPropertyList; + CPI_ROLE_ASSIGNMENT* pRoleAssignmentList; + CPI_INTERFACE* pInterfaceList; + + CPI_COMPONENT* pNext; +}; + +struct CPI_ASSEMBLY_ATTRIBUTES +{ + int iActionType; + int iActionCost; + LPWSTR pwzKey; + LPWSTR pwzAssemblyName; + LPWSTR pwzDllPath; + LPWSTR pwzTlbPath; + LPWSTR pwzPSDllPath; + LPWSTR pwzAppID; + LPWSTR pwzPartID; + int iAttributes; + CPI_COMPONENT* pCompList; +}; + +struct CPI_ROLE_ASSIGNMENTS_ATTRIBUTES +{ + int iActionType; + int iActionCost; + LPWSTR pwzKey; + LPWSTR pwzAppID; + LPWSTR pwzPartID; + int iRoleCount; + CPI_COMPONENT* pCompList; +}; + + +// prototypes for private helper functions + +static HRESULT RegisterAssembly( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ); +static HRESULT UnregisterAssembly( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ); +static void InitAssemblyExec(); +static void UninitAssemblyExec(); +static HRESULT GetRegistrationHelper( + IDispatch** ppiRegHlp + ); +static HRESULT GetAssemblyCacheObject( + IAssemblyCache** ppAssemblyCache + ); +static HRESULT GetAssemblyPathFromGAC( + LPCWSTR pwzAssemblyName, + LPWSTR* ppwzAssemblyPath + ); +static HRESULT RegisterDotNetAssembly( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ); +static HRESULT RegisterNativeAssembly( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ); +static HRESULT UnregisterDotNetAssembly( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ); +static HRESULT RemoveComponents( + ICatalogCollection* piCompColl, + CPI_COMPONENT* pCompList + ); +static HRESULT ReadAssemblyAttributes( + LPWSTR* ppwzData, + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ); +static void FreeAssemblyAttributes( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ); +static HRESULT ReadRoleAssignmentsAttributes( + LPWSTR* ppwzData, + CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs + ); +static void FreeRoleAssignmentsAttributes( + CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs + ); +static HRESULT ConfigureComponents( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + CPI_COMPONENT* pCompList, + BOOL fCreate, + BOOL fProgress + ); +static HRESULT ConfigureInterfaces( + ICatalogCollection* piCompColl, + ICatalogObject* piCompObj, + CPI_INTERFACE* pIntfList, + BOOL fCreate + ); +static HRESULT ConfigureMethods( + ICatalogCollection* piIntfColl, + ICatalogObject* piIntfObj, + CPI_METHOD* pMethList, + BOOL fCreate + ); +static HRESULT ConfigureRoleAssignments( + LPCWSTR pwzCollName, + ICatalogCollection* piCompColl, + ICatalogObject* piCompObj, + CPI_ROLE_ASSIGNMENT* pRoleList, + BOOL fCreate + ); +static HRESULT ReadComponentList( + LPWSTR* ppwzData, + CPI_COMPONENT** ppCompList + ); +static HRESULT ReadInterfaceList( + LPWSTR* ppwzData, + CPI_INTERFACE** ppIntfList + ); +static HRESULT ReadMethodList( + LPWSTR* ppwzData, + CPI_METHOD** ppMethList + ); +static HRESULT ReadRoleAssignmentList( + LPWSTR* ppwzData, + CPI_ROLE_ASSIGNMENT** ppRoleList + ); +static void FreeComponentList( + CPI_COMPONENT* pList + ); +static void FreeInterfaceList( + CPI_INTERFACE* pList + ); +static void FreeMethodList( + CPI_METHOD* pList + ); +static void FreeRoleAssignmentList( + CPI_ROLE_ASSIGNMENT* pList + ); + + +// variables + +static IDispatch* gpiRegHlp; +static IAssemblyCache* gpAssemblyCache; +static HMODULE ghMscoree; +static HMODULE ghFusion; + + +// function definitions + +HRESULT CpiConfigureAssemblies( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ) +{ + HRESULT hr = S_OK; + + CPI_ASSEMBLY_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // initialize + InitAssemblyExec(); + + // read action text + hr = CpiActionStartMessage(ppwzData, FALSE); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // write count to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); + ExitOnFailure(hr, "Failed to write count to rollback file"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadAssemblyAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read assembly attributes"); + + // write key to rollback file + hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); + ExitOnFailure(hr, "Failed to write key to rollback file"); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = RegisterAssembly(&attrs); + ExitOnFailure(hr, "Failed to register assembly, key: %S", attrs.pwzKey); + break; + case atRemove: + hr = UnregisterAssembly(&attrs); + ExitOnFailure(hr, "Failed to unregister assembly, key: %S", attrs.pwzKey); + break; + default: + hr = S_OK; + break; + } + + if (S_FALSE == hr) + ExitFunction(); // aborted by user + + // write completion status to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); + ExitOnFailure(hr, "Failed to write completion status to rollback file"); + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeAssemblyAttributes(&attrs); + + // uninitialize + UninitAssemblyExec(); + + return hr; +} + +HRESULT CpiRollbackConfigureAssemblies( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ) +{ + HRESULT hr = S_OK; + + int iRollbackStatus; + + CPI_ASSEMBLY_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // initialize + InitAssemblyExec(); + + // read action text + hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadAssemblyAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read assembly attributes"); + + // rollback status + hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); + + if (S_FALSE == hr) + continue; // not found, nothing to rollback + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = RegisterAssembly(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to register assembly, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + case atRemove: + hr = UnregisterAssembly(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to unregister assembly, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + } + + // check rollback status + if (0 == iRollbackStatus) + continue; // operation did not complete, skip progress + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeAssemblyAttributes(&attrs); + + // uninitialize + UninitAssemblyExec(); + + return hr; +} + +HRESULT CpiConfigureRoleAssignments( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ) +{ + HRESULT hr = S_OK; + + CPI_ROLE_ASSIGNMENTS_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, FALSE); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // write count to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); + ExitOnFailure(hr, "Failed to write count to rollback file"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadRoleAssignmentsAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read role assignments attributes"); + + // write key to rollback file + hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); + ExitOnFailure(hr, "Failed to write key to rollback file"); + + // action + if (atNoOp != attrs.iActionType) + { + hr = ConfigureComponents(attrs.pwzPartID, attrs.pwzAppID, attrs.pCompList, atCreate == attrs.iActionType, TRUE); + ExitOnFailure(hr, "Failed to configure components"); + + if (S_FALSE == hr) + ExitFunction(); // aborted by user + } + + // write completion status to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); + ExitOnFailure(hr, "Failed to write completion status to rollback file"); + + // progress + hr = WcaProgressMessage(attrs.iActionCost * attrs.iRoleCount, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeRoleAssignmentsAttributes(&attrs); + + return hr; +} + +HRESULT CpiRollbackConfigureRoleAssignments( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ) +{ + HRESULT hr = S_OK; + + int iRollbackStatus; + + CPI_ROLE_ASSIGNMENTS_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadRoleAssignmentsAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read role assignments attributes"); + + // rollback status + hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); + + if (S_FALSE == hr) + continue; // not found, nothing to rollback + + // action + if (atNoOp != attrs.iActionType) + { + hr = ConfigureComponents(attrs.pwzPartID, attrs.pwzAppID, attrs.pCompList, atCreate == attrs.iActionType, TRUE); + ExitOnFailure(hr, "Failed to configure components"); + + if (S_FALSE == hr) + ExitFunction(); // aborted by user + } + + // check rollback status + if (0 == iRollbackStatus) + continue; // operation did not complete, skip progress + + // progress + hr = WcaProgressMessage(attrs.iActionCost * attrs.iRoleCount, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeRoleAssignmentsAttributes(&attrs); + + return hr; +} + + +// helper function definitions + +static HRESULT RegisterAssembly( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + // progress message + hr = CpiActionDataMessage(1, (pAttrs->iAttributes & aaPathFromGAC) ? pAttrs->pwzAssemblyName : pAttrs->pwzDllPath); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); // aborted by user + + // log + WcaLog(LOGMSG_VERBOSE, "Registering assembly, key: %S", pAttrs->pwzKey); + + // extract path from GAC + if (pAttrs->iAttributes & aaPathFromGAC) + { + hr = GetAssemblyPathFromGAC(pAttrs->pwzAssemblyName, &pAttrs->pwzDllPath); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to get path for assembly from GAC"); + + // log + WcaLog(LOGMSG_VERBOSE, "Assembly path extracted from GAC, key: %S, path: '%S'", pAttrs->pwzKey, pAttrs->pwzDllPath); + } + + // .net assembly + if (pAttrs->iAttributes & aaDotNetAssembly) + { + hr = RegisterDotNetAssembly(pAttrs); + ExitOnFailure(hr, "Failed to register .NET assembly"); + } + + // native assembly + else + { + hr = RegisterNativeAssembly(pAttrs); + ExitOnFailure(hr, "Failed to register native assembly"); + } + + // configure components + if (pAttrs->pCompList) + { + hr = ConfigureComponents(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pCompList, TRUE, FALSE); + ExitOnFailure(hr, "Failed to configure components"); + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT UnregisterAssembly( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + long lChanges = 0; + + ICatalogCollection* piColl = NULL; + ICatalogObject* piObj = NULL; + + // progress message + hr = CpiActionDataMessage(1, (pAttrs->iAttributes & aaPathFromGAC) ? pAttrs->pwzAssemblyName : pAttrs->pwzDllPath); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); // aborted by user + + // log + WcaLog(LOGMSG_VERBOSE, "Unregistering assembly, key: %S", pAttrs->pwzKey); + + // extract path from GAC + if (pAttrs->iAttributes & aaPathFromGAC) + { + hr = GetAssemblyPathFromGAC(pAttrs->pwzAssemblyName, &pAttrs->pwzDllPath); + ExitOnFailure(hr, "Failed to get path for assembly from GAC"); + + if (S_FALSE == hr) + { + WcaLog(LOGMSG_VERBOSE, "Unable to locate assembly in GAC, assembly will not be unregistered from COM+, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // log + WcaLog(LOGMSG_VERBOSE, "Assembly path extracted from GAC, key: %S, path: '%S'", pAttrs->pwzKey, pAttrs->pwzDllPath); + } + + // .NET assembly + if (pAttrs->iAttributes & aaDotNetAssembly) + { + if (pAttrs->pwzAppID && *pAttrs->pwzAppID) + { + // When unregistering a .net assembly using the RegistrationHelper class, and the application is + // left empty after all components in the assembly are removed, the RegistrationHelper class also + // attempts to remove the application for some reason. However, it does not handle the situation + // when the application has its deleteable property set to false, and will simply fail if this is + // the case. This is the reason we are clearing the deleatable property of the application here. + // + // TODO: handle rollbacks + + // get applications collection + hr = CpiGetApplicationsCollection(pAttrs->pwzPartID, &piColl); + ExitOnFailure(hr, "Failed to get applications collection"); + + if (S_FALSE == hr) + { + // applications collection not found + WcaLog(LOGMSG_VERBOSE, "Unable to retrieve applications collection, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // find application object + hr = CpiFindCollectionObjectByStringKey(piColl, pAttrs->pwzAppID, &piObj); + ExitOnFailure(hr, "Failed to find application object"); + + if (S_FALSE == hr) + { + // application not found + WcaLog(LOGMSG_VERBOSE, "Unable to find application object, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // reset deleteable property + hr = CpiResetObjectProperty(piColl, piObj, L"Deleteable"); + ExitOnFailure(hr, "Failed to reset deleteable property"); + } + + // unregister assembly + hr = UnregisterDotNetAssembly(pAttrs); + ExitOnFailure(hr, "Failed to unregister .NET assembly"); + } + + // native assembly + else + { + // get components collection + hr = CpiGetComponentsCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, &piColl); + ExitOnFailure(hr, "Failed to get components collection"); + + if (S_FALSE == hr) + { + // components collection not found + WcaLog(LOGMSG_VERBOSE, "Unable to retrieve components collection, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // remove components + hr = RemoveComponents(piColl, pAttrs->pCompList); + ExitOnFailure(hr, "Failed to get remove components"); + + // save changes + hr = piColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piColl); + ReleaseObject(piObj); + + return hr; +} + +static void InitAssemblyExec() +{ + gpiRegHlp = NULL; + gpAssemblyCache = NULL; + ghMscoree = NULL; + ghFusion = NULL; +} + +static void UninitAssemblyExec() +{ + ReleaseObject(gpiRegHlp); + ReleaseObject(gpAssemblyCache); + if (ghFusion) + ::FreeLibrary(ghFusion); + if (ghMscoree) + ::FreeLibrary(ghMscoree); +} + +static HRESULT GetRegistrationHelper( + IDispatch** ppiRegHlp + ) +{ + HRESULT hr = S_OK; + + if (!gpiRegHlp) + { + // create registration helper object + hr = ::CoCreateInstance(CLSID_RegistrationHelper, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&gpiRegHlp); + ExitOnFailure(hr, "Failed to create registration helper object"); + } + + gpiRegHlp->AddRef(); + *ppiRegHlp = gpiRegHlp; + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT GetAssemblyCacheObject( + IAssemblyCache** ppAssemblyCache + ) +{ + HRESULT hr = S_OK; + + if (!gpAssemblyCache) + { + // mscoree.dll + if (!ghMscoree) + { + // load mscoree.dll + ghMscoree = ::LoadLibraryW(L"mscoree.dll"); + ExitOnNull(ghMscoree, hr, E_FAIL, "Failed to load mscoree.dll"); + } + + // fusion.dll + if (!ghFusion) + { + // get LoadLibraryShim function address + LoadLibraryShimFunc pfnLoadLibraryShim = (LoadLibraryShimFunc)::GetProcAddress(ghMscoree, "LoadLibraryShim"); + ExitOnNull(pfnLoadLibraryShim, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for LoadLibraryShim() function"); + + // load fusion.dll + hr = pfnLoadLibraryShim(L"fusion.dll", NULL, NULL, &ghFusion); + ExitOnFailure(hr, "Failed to load fusion.dll"); + } + + // get CreateAssemblyCache function address + CreateAssemblyCacheFunc pfnCreateAssemblyCache = (CreateAssemblyCacheFunc)::GetProcAddress(ghFusion, "CreateAssemblyCache"); + ExitOnNull(pfnCreateAssemblyCache, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for CreateAssemblyCache() function"); + + // create AssemblyCache object + hr = pfnCreateAssemblyCache(&gpAssemblyCache, 0); + ExitOnFailure(hr, "Failed to create AssemblyCache object"); + } + + gpAssemblyCache->AddRef(); + *ppAssemblyCache = gpAssemblyCache; + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT GetAssemblyPathFromGAC( + LPCWSTR pwzAssemblyName, + LPWSTR* ppwzAssemblyPath + ) +{ + HRESULT hr = S_OK; + + IAssemblyCache* pAssemblyCache = NULL; + + ASSEMBLY_INFO assemblyInfo; + WCHAR wzPathBuf[MAX_PATH]; + + ::ZeroMemory(&assemblyInfo, sizeof(ASSEMBLY_INFO)); + ::ZeroMemory(wzPathBuf, countof(wzPathBuf)); + + // get AssemblyCache object + hr = GetAssemblyCacheObject(&pAssemblyCache); + ExitOnFailure(hr, "Failed to get AssemblyCache object"); + + // get assembly info + assemblyInfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO); + assemblyInfo.pszCurrentAssemblyPathBuf = wzPathBuf; + assemblyInfo.cchBuf = countof(wzPathBuf); + + hr = pAssemblyCache->QueryAssemblyInfo(0, pwzAssemblyName, &assemblyInfo); + if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) + ExitFunction1(hr = S_FALSE); + ExitOnFailure(hr, "Failed to get assembly info"); + + // copy assembly path + hr = StrAllocString(ppwzAssemblyPath, wzPathBuf, 0); + ExitOnFailure(hr, "Failed to copy assembly path"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(pAssemblyCache); + + return hr; +} + +static HRESULT RegisterDotNetAssembly( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + IDispatch* piRegHlp = NULL; + + DISPID dispid; + BSTR bstrMember = NULL; + + long lInstallationFlags = 0; + + VARIANTARG rgvarg[5]; + DISPPARAMS dispparams; + EXCEPINFO excepInfo; + + BSTR bstrPartName = NULL; + BSTR bstrAppName = NULL; + BSTR bstrDllPath = NULL; + BSTR bstrTlbPath = NULL; + + ::ZeroMemory(rgvarg, sizeof(rgvarg)); + ::ZeroMemory(&dispparams, sizeof(dispparams)); + ::ZeroMemory(&excepInfo, sizeof(excepInfo)); + + bstrMember = ::SysAllocString(L"InstallAssembly_2"); + ExitOnNull(bstrMember, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for method name"); + + // create BSTRs for parameters + if (pAttrs->pwzPartID && *pAttrs->pwzPartID) + { + bstrPartName = ::SysAllocString(pAttrs->pwzPartID); + ExitOnNull(bstrPartName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id"); + } + + if (pAttrs->pwzAppID && *pAttrs->pwzAppID) + { + bstrAppName = ::SysAllocString(pAttrs->pwzAppID); + ExitOnNull(bstrAppName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id"); + } + + bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath); + ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path"); + + if (pAttrs->pwzTlbPath && *pAttrs->pwzTlbPath) + { + bstrTlbPath = ::SysAllocString(pAttrs->pwzTlbPath); + ExitOnNull(bstrTlbPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path"); + } + + // get registration helper object + hr = GetRegistrationHelper(&piRegHlp); + ExitOnFailure(hr, "Failed to get registration helper object"); + + // get dispatch id of InstallAssembly() method + hr = piRegHlp->GetIDsOfNames(IID_NULL, &bstrMember, 1, LOCALE_USER_DEFAULT, &dispid); + ExitOnFailure(hr, "Failed to get dispatch id of InstallAssembly() method"); + + // set installation flags + lInstallationFlags = ifExpectExistingTypeLib; + + if (!bstrAppName) + lInstallationFlags |= ifFindOrCreateTargetApplication; + + // invoke InstallAssembly() method + rgvarg[0].vt = VT_I4; + rgvarg[0].lVal = lInstallationFlags; + rgvarg[1].vt = VT_BYREF|VT_BSTR; + rgvarg[1].pbstrVal = &bstrTlbPath; + rgvarg[2].vt = VT_BSTR; + rgvarg[2].bstrVal = bstrPartName; + rgvarg[3].vt = VT_BYREF|VT_BSTR; + rgvarg[3].pbstrVal = &bstrAppName; + rgvarg[4].vt = VT_BSTR; + rgvarg[4].bstrVal = bstrDllPath; + dispparams.rgvarg = rgvarg; + dispparams.cArgs = 5; + dispparams.cNamedArgs = 0; + + hr = piRegHlp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, &excepInfo, NULL); + if (DISP_E_EXCEPTION == hr) + { + // log exception information + if (!excepInfo.pfnDeferredFillIn || (excepInfo.pfnDeferredFillIn && SUCCEEDED(excepInfo.pfnDeferredFillIn(&excepInfo)))) + { + WcaLog(LOGMSG_STANDARD, "ExceptionInfo: Code='%hu', Source='%S', Description='%S', HelpFile='%S', HelpContext='%u'", + excepInfo.wCode, excepInfo.bstrSource, + excepInfo.bstrDescription ? excepInfo.bstrDescription : L"", + excepInfo.bstrHelpFile ? excepInfo.bstrHelpFile : L"", + excepInfo.dwHelpContext); + } + } + ExitOnFailure(hr, "Failed to invoke RegistrationHelper.InstallAssembly() method"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piRegHlp); + + ReleaseBSTR(bstrMember); + + ReleaseBSTR(excepInfo.bstrSource); + ReleaseBSTR(excepInfo.bstrDescription); + ReleaseBSTR(excepInfo.bstrHelpFile); + + ReleaseBSTR(bstrPartName); + ReleaseBSTR(bstrAppName); + ReleaseBSTR(bstrDllPath); + ReleaseBSTR(bstrTlbPath); + + return hr; +} + +static HRESULT RegisterNativeAssembly( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + ICOMAdminCatalog2* piCatalog2 = NULL; + BSTR bstrGlobPartID = NULL; + + BSTR bstrPartID = NULL; + BSTR bstrAppID = NULL; + BSTR bstrDllPath = NULL; + BSTR bstrTlbPath = NULL; + BSTR bstrPSDllPath = NULL; + + // create BSTRs for parameters + if (pAttrs->pwzPartID && *pAttrs->pwzPartID) + { + bstrPartID = ::SysAllocString(pAttrs->pwzPartID); + ExitOnNull(bstrPartID, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id"); + } + + bstrAppID = ::SysAllocString(pAttrs->pwzAppID); + ExitOnNull(bstrAppID, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id"); + + bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath); + ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path"); + + bstrTlbPath = ::SysAllocString(pAttrs->pwzTlbPath ? pAttrs->pwzTlbPath : L""); + ExitOnNull(bstrTlbPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path"); + + bstrPSDllPath = ::SysAllocString(pAttrs->pwzPSDllPath ? pAttrs->pwzPSDllPath : L""); + ExitOnNull(bstrPSDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path"); + + // get catalog + hr = CpiGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get ICOMAdminCatalog2 interface + hr = piCatalog->QueryInterface(IID_ICOMAdminCatalog2, (void**)&piCatalog2); + + // COM+ 1.5 or later + if (E_NOINTERFACE != hr) + { + ExitOnFailure(hr, "Failed to get IID_ICOMAdminCatalog2 interface"); + + // partition id + if (!bstrPartID) + { + // get global partition id + hr = piCatalog2->get_GlobalPartitionID(&bstrGlobPartID); + ExitOnFailure(hr, "Failed to get global partition id"); + } + + // set current partition + hr = piCatalog2->put_CurrentPartition(bstrPartID ? bstrPartID : bstrGlobPartID); + ExitOnFailure(hr, "Failed to set current partition"); + } + + // COM+ pre 1.5 + else + { + // this version of COM+ does not support partitions, make sure a partition was not specified + if (bstrPartID) + ExitOnFailure(hr = E_FAIL, "Partitions are not supported by this version of COM+"); + } + + // install event classes + if (pAttrs->iAttributes & aaEventClass) + { + hr = piCatalog->InstallEventClass(bstrAppID, bstrDllPath, bstrTlbPath, bstrPSDllPath); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to install event classes"); + } + + // install components + else + { + hr = piCatalog->InstallComponent(bstrAppID, bstrDllPath, bstrTlbPath, bstrPSDllPath); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to install components"); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piCatalog2); + ReleaseBSTR(bstrGlobPartID); + + ReleaseBSTR(bstrPartID); + ReleaseBSTR(bstrAppID); + ReleaseBSTR(bstrDllPath); + ReleaseBSTR(bstrTlbPath); + ReleaseBSTR(bstrPSDllPath); + + return hr; +} + +static HRESULT UnregisterDotNetAssembly( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + IDispatch* piRegHlp = NULL; + + DISPID dispid; + BSTR bstrMember = NULL; + + VARIANTARG rgvarg[3]; + DISPPARAMS dispparams; + EXCEPINFO excepInfo; + + BSTR bstrPartName = NULL; + BSTR bstrAppName = NULL; + BSTR bstrDllPath = NULL; + + ::ZeroMemory(rgvarg, sizeof(rgvarg)); + ::ZeroMemory(&dispparams, sizeof(dispparams)); + ::ZeroMemory(&excepInfo, sizeof(excepInfo)); + + bstrMember = ::SysAllocString(L"UninstallAssembly_2"); + ExitOnNull(bstrMember, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for method name"); + + // create BSTRs for parameters + if (pAttrs->pwzPartID && *pAttrs->pwzPartID) + { + bstrPartName = ::SysAllocString(pAttrs->pwzPartID); + ExitOnNull(bstrPartName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id"); + } + + bstrAppName = ::SysAllocString(pAttrs->pwzAppID); + ExitOnNull(bstrAppName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id"); + + bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath); + ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path"); + + // get registration helper object + hr = GetRegistrationHelper(&piRegHlp); + ExitOnFailure(hr, "Failed to get registration helper object"); + + // get dispatch id of UninstallAssembly() method + hr = piRegHlp->GetIDsOfNames(IID_NULL, &bstrMember, 1, LOCALE_USER_DEFAULT, &dispid); + ExitOnFailure(hr, "Failed to get dispatch id of UninstallAssembly() method"); + + // invoke UninstallAssembly() method + rgvarg[0].vt = VT_BSTR; + rgvarg[0].bstrVal = bstrPartName; + rgvarg[1].vt = VT_BSTR; + rgvarg[1].bstrVal = bstrAppName; + rgvarg[2].vt = VT_BSTR; + rgvarg[2].bstrVal = bstrDllPath; + dispparams.rgvarg = rgvarg; + dispparams.cArgs = 3; + dispparams.cNamedArgs = 0; + + hr = piRegHlp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, &excepInfo, NULL); + if (DISP_E_EXCEPTION == hr) + { + // log exception information + if (!excepInfo.pfnDeferredFillIn || (excepInfo.pfnDeferredFillIn && SUCCEEDED(excepInfo.pfnDeferredFillIn(&excepInfo)))) + { + WcaLog(LOGMSG_STANDARD, "ExceptionInfo: Code='%hu', Source='%S', Description='%S', HelpFile='%S', HelpContext='%u'", + excepInfo.wCode, excepInfo.bstrSource, + excepInfo.bstrDescription ? excepInfo.bstrDescription : L"", + excepInfo.bstrHelpFile ? excepInfo.bstrHelpFile : L"", + excepInfo.dwHelpContext); + } + } + ExitOnFailure(hr, "Failed to invoke RegistrationHelper.UninstallAssembly() method"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piRegHlp); + + ReleaseBSTR(bstrMember); + + ReleaseBSTR(excepInfo.bstrSource); + ReleaseBSTR(excepInfo.bstrDescription); + ReleaseBSTR(excepInfo.bstrHelpFile); + + ReleaseBSTR(bstrPartName); + ReleaseBSTR(bstrAppName); + ReleaseBSTR(bstrDllPath); + + return hr; +} + +static HRESULT RemoveComponents( + ICatalogCollection* piCompColl, + CPI_COMPONENT* pCompList + ) +{ + HRESULT hr = S_OK; + + for (CPI_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext) + { + // remove + hr = CpiRemoveCollectionObject(piCompColl, pItm->wzCLSID, NULL, FALSE); + ExitOnFailure(hr, "Failed to remove component"); + + if (S_FALSE == hr) + WcaLog(LOGMSG_VERBOSE, "Component not found, nothing to delete, key: %S", pItm->wzCLSID); + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT ReadAssemblyAttributes( + LPWSTR* ppwzData, + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + // read attributes + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); + ExitOnFailure(hr, "Failed to read action type"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); + ExitOnFailure(hr, "Failed to read action cost"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); + ExitOnFailure(hr, "Failed to read key"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAssemblyName); + ExitOnFailure(hr, "Failed to read assembly name"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzDllPath); + ExitOnFailure(hr, "Failed to read dll path"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzTlbPath); + ExitOnFailure(hr, "Failed to read tlb path"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPSDllPath); + ExitOnFailure(hr, "Failed to read proxy-stub dll path"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iAttributes); + ExitOnFailure(hr, "Failed to read attributes"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID); + ExitOnFailure(hr, "Failed to read application id"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); + ExitOnFailure(hr, "Failed to read partition id"); + + // free existing component list + if (pAttrs->pCompList) + { + FreeComponentList(pAttrs->pCompList); + pAttrs->pCompList = NULL; + } + + // read components + hr = ReadComponentList(ppwzData, &pAttrs->pCompList); + ExitOnFailure(hr, "Failed to read components"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreeAssemblyAttributes( + CPI_ASSEMBLY_ATTRIBUTES* pAttrs + ) +{ + ReleaseStr(pAttrs->pwzKey); + ReleaseStr(pAttrs->pwzAssemblyName); + ReleaseStr(pAttrs->pwzDllPath); + ReleaseStr(pAttrs->pwzTlbPath); + ReleaseStr(pAttrs->pwzPSDllPath); + ReleaseStr(pAttrs->pwzAppID); + ReleaseStr(pAttrs->pwzPartID); + + if (pAttrs->pCompList) + FreeComponentList(pAttrs->pCompList); +} + +static HRESULT ReadRoleAssignmentsAttributes( + LPWSTR* ppwzData, + CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + // read attributes + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); + ExitOnFailure(hr, "Failed to read action type"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); + ExitOnFailure(hr, "Failed to read action cost"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); + ExitOnFailure(hr, "Failed to read key"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iRoleCount); + ExitOnFailure(hr, "Failed to read role assignments count"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID); + ExitOnFailure(hr, "Failed to read application id"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); + ExitOnFailure(hr, "Failed to read partition id"); + + // free existing component list + if (pAttrs->pCompList) + { + FreeComponentList(pAttrs->pCompList); + pAttrs->pCompList = NULL; + } + + // read components + hr = ReadComponentList(ppwzData, &pAttrs->pCompList); + ExitOnFailure(hr, "Failed to read components"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreeRoleAssignmentsAttributes( + CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs + ) +{ + ReleaseStr(pAttrs->pwzKey); + ReleaseStr(pAttrs->pwzAppID); + ReleaseStr(pAttrs->pwzPartID); + + if (pAttrs->pCompList) + FreeComponentList(pAttrs->pCompList); +} + + +static HRESULT ConfigureComponents( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + CPI_COMPONENT* pCompList, + BOOL fCreate, + BOOL fProgress + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piCompColl = NULL; + ICatalogObject* piCompObj = NULL; + + long lChanges = 0; + + // get components collection + hr = CpiGetComponentsCollection(pwzPartID, pwzAppID, &piCompColl); + if (S_FALSE == hr) + if (fCreate) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + else + ExitFunction1(hr = S_OK); + ExitOnFailure(hr, "Failed to get components collection"); + + // read components + for (CPI_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext) + { + // progress message + if (fProgress) + { + hr = CpiActionDataMessage(1, pItm->wzCLSID); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); // aborted by user + } + + // find component + hr = CpiFindCollectionObjectByStringKey(piCompColl, pItm->wzCLSID, &piCompObj); + if (S_FALSE == hr) + if (fCreate) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + else + continue; + ExitOnFailure(hr, "Failed to find component object"); + + // properties + hr = CpiPutCollectionObjectValues(piCompObj, pItm->pPropertyList); + ExitOnFailure(hr, "Failed to write properties"); + + // read roles + if (pItm->pRoleAssignmentList) + { + hr = ConfigureRoleAssignments(L"RolesForComponent", piCompColl, piCompObj, pItm->pRoleAssignmentList, fCreate); + ExitOnFailure(hr, "Failed to read roles"); + } + + // read interfaces + if (pItm->pInterfaceList) + { + hr = ConfigureInterfaces(piCompColl, piCompObj, pItm->pInterfaceList, fCreate); + ExitOnFailure(hr, "Failed to read interfaces"); + } + + // clean up + ReleaseNullObject(piCompObj); + } + + // save changes + hr = piCompColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCompColl); + ReleaseObject(piCompObj); + + return hr; +} + +static HRESULT ConfigureInterfaces( + ICatalogCollection* piCompColl, + ICatalogObject* piCompObj, + CPI_INTERFACE* pIntfList, + BOOL fCreate + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piIntfColl = NULL; + ICatalogObject* piIntfObj = NULL; + + long lChanges = 0; + + // get interfaces collection + hr = CpiGetInterfacesCollection(piCompColl, piCompObj, &piIntfColl); + if (S_FALSE == hr) + if (fCreate) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + else + ExitFunction1(hr = S_OK); + ExitOnFailure(hr, "Failed to get interfaces collection"); + + // read interfaces + for (CPI_INTERFACE* pItm = pIntfList; pItm; pItm = pItm->pNext) + { + // find interface + hr = CpiFindCollectionObjectByStringKey(piIntfColl, pItm->wzIID, &piIntfObj); + if (S_FALSE == hr) + if (fCreate) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + else + continue; + ExitOnFailure(hr, "Failed to find interface object"); + + // properties + hr = CpiPutCollectionObjectValues(piIntfObj, pItm->pPropertyList); + ExitOnFailure(hr, "Failed to write properties"); + + // read roles + if (pItm->pRoleAssignmentList) + { + hr = ConfigureRoleAssignments(L"RolesForInterface", piIntfColl, piIntfObj, pItm->pRoleAssignmentList, fCreate); + ExitOnFailure(hr, "Failed to read roles"); + } + + // read methods + if (pItm->pMethodList) + { + hr = ConfigureMethods(piIntfColl, piIntfObj, pItm->pMethodList, fCreate); + ExitOnFailure(hr, "Failed to read methods"); + } + + // clean up + ReleaseNullObject(piIntfObj); + } + + // save changes + hr = piIntfColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piIntfColl); + ReleaseObject(piIntfObj); + + return hr; +} + +static HRESULT ConfigureMethods( + ICatalogCollection* piIntfColl, + ICatalogObject* piIntfObj, + CPI_METHOD* pMethList, + BOOL fCreate + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piMethColl = NULL; + ICatalogObject* piMethObj = NULL; + + long lChanges = 0; + + // get methods collection + hr = CpiGetMethodsCollection(piIntfColl, piIntfObj, &piMethColl); + if (S_FALSE == hr) + if (fCreate) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + else + ExitFunction1(hr = S_OK); + ExitOnFailure(hr, "Failed to get methods collection"); + + // read methods + for (CPI_METHOD* pItm = pMethList; pItm; pItm = pItm->pNext) + { + // find method + if (*pItm->wzIndex) + hr = CpiFindCollectionObjectByIntegerKey(piMethColl, _wtol(pItm->wzIndex), &piMethObj); + else + hr = CpiFindCollectionObjectByName(piMethColl, pItm->wzName, &piMethObj); + + if (S_FALSE == hr) + if (fCreate) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + else + continue; + ExitOnFailure(hr, "Failed to find method object"); + + // properties + hr = CpiPutCollectionObjectValues(piMethObj, pItm->pPropertyList); + ExitOnFailure(hr, "Failed to write properties"); + + // read roles + if (pItm->pRoleAssignmentList) + { + hr = ConfigureRoleAssignments(L"RolesForMethod", piMethColl, piMethObj, pItm->pRoleAssignmentList, fCreate); + ExitOnFailure(hr, "Failed to read roles"); + } + + // clean up + ReleaseNullObject(piMethObj); + } + + // save changes + hr = piMethColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piMethColl); + ReleaseObject(piMethObj); + + return hr; +} + +static HRESULT ConfigureRoleAssignments( + LPCWSTR pwzCollName, + ICatalogCollection* piCompColl, + ICatalogObject* piCompObj, + CPI_ROLE_ASSIGNMENT* pRoleList, + BOOL fCreate + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piRoleColl = NULL; + ICatalogObject* piRoleObj = NULL; + + long lChanges = 0; + + // get roles collection + hr = CpiGetCatalogCollection(piCompColl, piCompObj, pwzCollName, &piRoleColl); + if (S_FALSE == hr) + if (fCreate) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + else + ExitFunction1(hr = S_OK); + ExitOnFailure(hr, "Failed to get role assignments collection"); + + // read roles + for (CPI_ROLE_ASSIGNMENT* pItm = pRoleList; pItm; pItm = pItm->pNext) + { + if (fCreate) + { + // find existing role + hr = CpiFindCollectionObjectByName(piRoleColl, pItm->wzRoleName, NULL); + ExitOnFailure(hr, "Failed to find role, key: %S", pItm->wzKey); + + if (S_OK == hr) + continue; // role already exists + + // add object + hr = CpiAddCollectionObject(piRoleColl, &piRoleObj); + ExitOnFailure(hr, "Failed to add role assignment to collection"); + + // role name + hr = CpiPutCollectionObjectValue(piRoleObj, L"Name", pItm->wzRoleName); + ExitOnFailure(hr, "Failed to set role name property, key: %S", pItm->wzKey); + + // clean up + ReleaseNullObject(piRoleObj); + } + else + { + // remove role + hr = CpiRemoveCollectionObject(piRoleColl, NULL, pItm->wzRoleName, FALSE); + ExitOnFailure(hr, "Failed to remove role, key: %S", pItm->wzKey); + } + } + + // save changes + hr = piRoleColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piRoleColl); + ReleaseObject(piRoleObj); + + return hr; +} + +static HRESULT ReadComponentList( + LPWSTR* ppwzData, + CPI_COMPONENT** ppCompList + ) +{ + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + + CPI_COMPONENT* pItm = NULL; + + int iCnt = 0; + + // read count + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // read components + for (int i = 0; i < iCnt; i++) + { + pItm = (CPI_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_COMPONENT)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // read clsid + hr = WcaReadStringFromCaData(ppwzData, &pwzData); + ExitOnFailure(hr, "Failed to read clsid"); + StringCchCopyW(pItm->wzCLSID, countof(pItm->wzCLSID), pwzData); + + // read properties + hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList); + ExitOnFailure(hr, "Failed to read properties"); + + // read role assignments + hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList); + ExitOnFailure(hr, "Failed to read role assignments"); + + // read interfaces + hr = ReadInterfaceList(ppwzData, &pItm->pInterfaceList); + ExitOnFailure(hr, "Failed to read interfaces"); + + // add to list + if (*ppCompList) + pItm->pNext = *ppCompList; + *ppCompList = pItm; + pItm = NULL; + } + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzData); + + if (pItm) + FreeComponentList(pItm); + + return hr; +} + +static HRESULT ReadInterfaceList( + LPWSTR* ppwzData, + CPI_INTERFACE** ppIntfList + ) +{ + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + + CPI_INTERFACE* pItm = NULL; + + int iCnt = 0; + + // read count + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // read interfaces + for (int i = 0; i < iCnt; i++) + { + pItm = (CPI_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_INTERFACE)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // read iid + hr = WcaReadStringFromCaData(ppwzData, &pwzData); + ExitOnFailure(hr, "Failed to read iid"); + StringCchCopyW(pItm->wzIID, countof(pItm->wzIID), pwzData); + + // read properties + hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList); + ExitOnFailure(hr, "Failed to read properties"); + + // read role assignments + hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList); + ExitOnFailure(hr, "Failed to read role assignments"); + + // read methods + hr = ReadMethodList(ppwzData, &pItm->pMethodList); + ExitOnFailure(hr, "Failed to read methods"); + + // add to list + if (*ppIntfList) + pItm->pNext = *ppIntfList; + *ppIntfList = pItm; + pItm = NULL; + } + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzData); + + if (pItm) + FreeInterfaceList(pItm); + + return hr; +} + +static HRESULT ReadMethodList( + LPWSTR* ppwzData, + CPI_METHOD** ppMethList + ) +{ + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + + CPI_METHOD* pItm = NULL; + + int iCnt = 0; + + // read count + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // read methods + for (int i = 0; i < iCnt; i++) + { + pItm = (CPI_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_METHOD)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // read index + hr = WcaReadStringFromCaData(ppwzData, &pwzData); + ExitOnFailure(hr, "Failed to read index"); + StringCchCopyW(pItm->wzIndex, countof(pItm->wzIndex), pwzData); + + // read name + hr = WcaReadStringFromCaData(ppwzData, &pwzData); + ExitOnFailure(hr, "Failed to read name"); + StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); + + // read properties + hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList); + ExitOnFailure(hr, "Failed to read properties"); + + // read role assignments + hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList); + ExitOnFailure(hr, "Failed to read role assignments"); + + // add to list + if (*ppMethList) + pItm->pNext = *ppMethList; + *ppMethList = pItm; + pItm = NULL; + } + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzData); + + if (pItm) + FreeMethodList(pItm); + + return hr; +} + +static HRESULT ReadRoleAssignmentList( + LPWSTR* ppwzData, + CPI_ROLE_ASSIGNMENT** ppRoleList + ) +{ + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + + CPI_ROLE_ASSIGNMENT* pItm = NULL; + + int iCnt = 0; + + // read role count + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read role assignments count"); + + // read roles + for (int i = 0; i < iCnt; i++) + { + pItm = (CPI_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ROLE_ASSIGNMENT)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // read key + hr = WcaReadStringFromCaData(ppwzData, &pwzData); + ExitOnFailure(hr, "Failed to read key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // read role name + hr = WcaReadStringFromCaData(ppwzData, &pwzData); + ExitOnFailure(hr, "Failed to read role name"); + StringCchCopyW(pItm->wzRoleName, countof(pItm->wzRoleName), pwzData); + + // add to list + if (*ppRoleList) + pItm->pNext = *ppRoleList; + *ppRoleList = pItm; + pItm = NULL; + } + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzData); + + if (pItm) + FreeRoleAssignmentList(pItm); + + return hr; +} + +static void FreeComponentList( + CPI_COMPONENT* pList + ) +{ + while (pList) + { + if (pList->pPropertyList) + CpiFreePropertyList(pList->pPropertyList); + if (pList->pRoleAssignmentList) + FreeRoleAssignmentList(pList->pRoleAssignmentList); + if (pList->pInterfaceList) + FreeInterfaceList(pList->pInterfaceList); + + CPI_COMPONENT* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +static void FreeInterfaceList( + CPI_INTERFACE* pList + ) +{ + while (pList) + { + if (pList->pPropertyList) + CpiFreePropertyList(pList->pPropertyList); + if (pList->pRoleAssignmentList) + FreeRoleAssignmentList(pList->pRoleAssignmentList); + if (pList->pMethodList) + FreeMethodList(pList->pMethodList); + + CPI_INTERFACE* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +static void FreeMethodList( + CPI_METHOD* pList + ) +{ + while (pList) + { + if (pList->pPropertyList) + CpiFreePropertyList(pList->pPropertyList); + if (pList->pRoleAssignmentList) + FreeRoleAssignmentList(pList->pRoleAssignmentList); + + CPI_METHOD* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +static void FreeRoleAssignmentList( + CPI_ROLE_ASSIGNMENT* pList + ) +{ + while (pList) + { + CPI_ROLE_ASSIGNMENT* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} diff --git a/src/ca/cpasmexec.h b/src/ca/cpasmexec.h new file mode 100644 index 00000000..56184c01 --- /dev/null +++ b/src/ca/cpasmexec.h @@ -0,0 +1,20 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +HRESULT CpiConfigureAssemblies( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ); +HRESULT CpiRollbackConfigureAssemblies( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ); +HRESULT CpiConfigureRoleAssignments( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ); +HRESULT CpiRollbackConfigureRoleAssignments( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ); diff --git a/src/ca/cpasmsched.cpp b/src/ca/cpasmsched.cpp new file mode 100644 index 00000000..97ecff61 --- /dev/null +++ b/src/ca/cpasmsched.cpp @@ -0,0 +1,2135 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// sql queries + +LPCWSTR vcsMsiAssemblyNameQuery = + L"SELECT `Name`, `Value` FROM `MsiAssemblyName` WHERE `Component_` = ?"; +enum eMsiAssemblyNameQuery { manqName = 1, manqValue }; + +LPCWSTR vcsModuleQuery = + L"SELECT `ModuleID` FROM `ModuleSignature`"; +enum eModuleQuery { mqModule = 1 }; + +LPCWSTR vcsAssemblyQuery = + L"SELECT `Assembly`, `Component_`, `Application_`, `AssemblyName`, `DllPath`, `TlbPath`, `PSDllPath`, `Attributes` FROM `ComPlusAssembly`"; +enum eAssemblyQuery { aqAssembly = 1, aqComponent, aqApplication, aqAssemblyName, aqDllPath, aqTlbPath, aqPSDllPath, aqAttributes }; + +LPCWSTR vcsComponentQuery = + L"SELECT `ComPlusComponent`, `CLSID` FROM `ComPlusComponent` WHERE `Assembly_` = ?"; +enum eComponentQuery { cqComponent = 1, cqCLSID }; + +LPCWSTR vcsComponentPropertyQuery = + L"SELECT `Name`, `Value` FROM `ComPlusComponentProperty` WHERE `ComPlusComponent_` = ?"; + +LPCWSTR vcsInterfaceQuery = + L"SELECT `Interface`, `IID` FROM `ComPlusInterface` WHERE `ComPlusComponent_` = ?"; +enum eInterfaceQuery { iqInterface = 1, iqIID }; + +LPCWSTR vcsInterfacePropertyQuery = + L"SELECT `Name`, `Value` FROM `ComPlusInterfaceProperty` WHERE `Interface_` = ?"; + +LPCWSTR vcsMethodQuery = + L"SELECT `Method`, `Index`, `Name` FROM `ComPlusMethod` WHERE `Interface_` = ?"; +enum eMethodQuery { mqMethod = 1, mqIndex, mqName }; + +LPCWSTR vcsMethodPropertyQuery = + L"SELECT `Name`, `Value` FROM `ComPlusMethodProperty` WHERE `Method_` = ?"; + +LPCWSTR vcsRoleForComponentQuery = + L"SELECT `RoleForComponent`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForComponent` WHERE `ComPlusComponent_` = ?"; +LPCWSTR vcsRoleForInterfaceQuery = + L"SELECT `RoleForInterface`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForInterface` WHERE `Interface_` = ?"; +LPCWSTR vcsRoleForMethodQuery = + L"SELECT `RoleForMethod`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForMethod` WHERE `Method_` = ?"; + +enum eRoleAssignmentQuery { raqKey = 1, raqApplicationRole, raqComponent }; + +LPCWSTR vcsModuleComponentsQuery = + L"SELECT `Component`, `ModuleID` FROM `ModuleComponents`"; +LPCWSTR vcsModuleDependencyQuery = + L"SELECT `ModuleID`, `RequiredID` FROM `ModuleDependency`"; +LPCWSTR vcsAssemblyDependencyQuery = + L"SELECT `Assembly_`, `RequiredAssembly_` FROM `ComPlusAssemblyDependency`"; + +enum eKeyPairQuery { kpqFirstKey = 1, kpqSecondKey }; + + +// private structs + +struct CPI_KEY_PAIR +{ + WCHAR wzFirstKey[MAX_DARWIN_KEY + 1]; + WCHAR wzSecondKey[MAX_DARWIN_KEY + 1]; + + CPI_KEY_PAIR* pNext; +}; + +struct CPI_DEPENDENCY_CHAIN +{ + LPCWSTR pwzKey; + + CPI_DEPENDENCY_CHAIN* pPrev; +}; + +struct CPI_MODULE +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + + CPI_MODULE* pPrev; + CPI_MODULE* pNext; +}; + +struct CPI_MODULE_LIST +{ + CPI_MODULE* pFirst; + CPI_MODULE* pLast; +}; + + +// property definitions + +CPI_PROPERTY_DEFINITION pdlComponentProperties[] = +{ + {L"AllowInprocSubscribers", cpptBoolean, 500}, + {L"ComponentAccessChecksEnabled", cpptBoolean, 500}, + {L"ComponentTransactionTimeout", cpptInteger, 500}, + {L"ComponentTransactionTimeoutEnabled", cpptBoolean, 500}, + {L"COMTIIntrinsics", cpptBoolean, 500}, + {L"ConstructionEnabled", cpptBoolean, 500}, + {L"ConstructorString", cpptString, 500}, + {L"CreationTimeout", cpptInteger, 500}, + {L"Description", cpptString, 500}, + {L"EventTrackingEnabled", cpptBoolean, 500}, + {L"ExceptionClass", cpptString, 500}, + {L"FireInParallel", cpptBoolean, 500}, + {L"IISIntrinsics", cpptBoolean, 500}, + {L"InitializesServerApplication", cpptBoolean, 500}, + {L"IsEnabled", cpptBoolean, 501}, + {L"IsPrivateComponent", cpptBoolean, 501}, + {L"JustInTimeActivation", cpptBoolean, 500}, + {L"LoadBalancingSupported", cpptBoolean, 500}, + {L"MaxPoolSize", cpptInteger, 500}, + {L"MinPoolSize", cpptInteger, 500}, + {L"MultiInterfacePublisherFilterCLSID", cpptString, 500}, + {L"MustRunInClientContext", cpptBoolean, 500}, + {L"MustRunInDefaultContext", cpptBoolean, 501}, + {L"ObjectPoolingEnabled", cpptBoolean, 500}, + {L"PublisherID", cpptString, 500}, + {L"SoapAssemblyName", cpptString, 502}, + {L"SoapTypeName", cpptString, 502}, + {L"Synchronization", cpptInteger, 500}, + {L"Transaction", cpptInteger, 500}, + {L"TxIsolationLevel", cpptInteger, 501}, + {NULL, cpptNone, 0} +}; + +CPI_PROPERTY_DEFINITION pdlInterfaceProperties[] = +{ + {L"Description", cpptString, 500}, + {L"QueuingEnabled", cpptBoolean, 500}, + {NULL, cpptNone, 0} +}; + +CPI_PROPERTY_DEFINITION pdlMethodProperties[] = +{ + {L"AutoComplete", cpptBoolean, 500}, + {L"Description", cpptString, 500}, + {NULL, cpptNone, 0} +}; + + +// prototypes for private helper functions + +static HRESULT GetAssemblyName( + LPCWSTR pwzComponent, + LPWSTR* ppwzAssemblyName + ); +static HRESULT KeyPairsRead( + LPCWSTR pwzQuery, + CPI_KEY_PAIR** ppKeyPairList + ); +static HRESULT ModulesRead( + CPI_MODULE_LIST* pModList + ); +static HRESULT AssembliesRead( + CPI_KEY_PAIR* pModCompList, + CPI_APPLICATION_LIST* pAppList, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ASSEMBLY_LIST* pAsmList + ); +static HRESULT ComponentsRead( + LPCWSTR pwzAsmKey, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ASSEMBLY* pAsm + ); +static HRESULT InterfacesRead( + LPCWSTR pwzCompKey, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ASSEMBLY* pAsm, + CPI_COMPONENT* pComp + ); +static HRESULT MethodsRead( + LPCWSTR pwzIntfKey, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ASSEMBLY* pAsm, + CPI_INTERFACE* pIntf + ); +static HRESULT RoleAssignmentsRead( + LPCWSTR pwzQuery, + LPCWSTR pwzKey, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ROLE_ASSIGNMENT** ppRoleList, + int* piInstallCount, + int* piUninstallCount + ); +static HRESULT TopSortModuleList( + CPI_KEY_PAIR* pDepList, + CPI_MODULE_LIST* pList + ); +static HRESULT SwapDependentModules( + CPI_DEPENDENCY_CHAIN* pdcPrev, + CPI_KEY_PAIR* pDepList, + CPI_MODULE_LIST* pList, + CPI_MODULE* pRoot, + CPI_MODULE* pItm + ); +static HRESULT ModuleFindByKey( + CPI_MODULE* pItm, + LPCWSTR pwzKey, + BOOL fReverse, + CPI_MODULE** ppItm + ); +static void SortAssemblyListByModule( + CPI_MODULE_LIST* pModList, + CPI_ASSEMBLY_LIST* pAsmList + ); +static HRESULT TopSortAssemblyList( + CPI_KEY_PAIR* pDepList, + CPI_ASSEMBLY_LIST* pList + ); +static HRESULT SwapDependentAssemblies( + CPI_DEPENDENCY_CHAIN* pdcPrev, + CPI_KEY_PAIR* pDepList, + CPI_ASSEMBLY_LIST* pList, + CPI_ASSEMBLY* pRoot, + CPI_ASSEMBLY* pItm + ); +static HRESULT AssemblyFindByKey( + CPI_ASSEMBLY* pItm, + LPCWSTR pwzKey, + BOOL fReverse, + CPI_ASSEMBLY** ppItm + ); +static HRESULT AddAssemblyToActionData( + CPI_ASSEMBLY* pItm, + BOOL fInstall, + int iActionType, + int iActionCost, + LPWSTR* ppwzActionData + ); +static HRESULT AddRoleAssignmentsToActionData( + CPI_ASSEMBLY* pItm, + BOOL fInstall, + int iActionType, + int iActionCost, + LPWSTR* ppwzActionData + ); +static HRESULT AddComponentToActionData( + CPI_COMPONENT* pItm, + BOOL fInstall, + BOOL fProps, + BOOL fRoles, + LPWSTR* ppwzActionData + ); +static HRESULT AddInterfaceToActionData( + CPI_INTERFACE* pItm, + BOOL fInstall, + BOOL fProps, + BOOL fRoles, + LPWSTR* ppwzActionData + ); +static HRESULT AddMethodToActionData( + CPI_METHOD* pItm, + BOOL fInstall, + BOOL fProps, + BOOL fRoles, + LPWSTR* ppwzActionData + ); +static HRESULT AddRolesToActionData( + int iRoleInstallCount, + int iRoleUninstallCount, + CPI_ROLE_ASSIGNMENT* pRoleList, + BOOL fInstall, + BOOL fRoles, + LPWSTR* ppwzActionData + ); +static HRESULT KeyPairFindByFirstKey( + CPI_KEY_PAIR* pList, + LPCWSTR pwzKey, + CPI_KEY_PAIR** ppItm + ); +static void AssemblyFree( + CPI_ASSEMBLY* pItm + ); +static void KeyPairsFreeList( + CPI_KEY_PAIR* pList + ); +void ModuleListFree( + CPI_MODULE_LIST* pList + ); +static void ModuleFree( + CPI_MODULE* pItm + ); +static void ComponentsFreeList( + CPI_COMPONENT* pList + ); +static void InterfacesFreeList( + CPI_INTERFACE* pList + ); +static void MethodsFreeList( + CPI_METHOD* pList + ); +static void RoleAssignmentsFreeList( + CPI_ROLE_ASSIGNMENT* pList + ); + + +// function definitions + +void CpiAssemblyListFree( + CPI_ASSEMBLY_LIST* pList + ) +{ + CPI_ASSEMBLY* pItm = pList->pFirst; + + while (pItm) + { + CPI_ASSEMBLY* pDelete = pItm; + pItm = pItm->pNext; + AssemblyFree(pDelete); + } +} + +HRESULT CpiAssembliesRead( + CPI_APPLICATION_LIST* pAppList, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ASSEMBLY_LIST* pAsmList + ) +{ + HRESULT hr = S_OK; + CPI_MODULE_LIST modList; + CPI_KEY_PAIR* pModCompList = NULL; + CPI_KEY_PAIR* pModDepList = NULL; + CPI_KEY_PAIR* pAsmDepList = NULL; + + ::ZeroMemory(&modList, sizeof(CPI_MODULE_LIST)); + + BOOL fModuleSignatureTable = (S_OK == WcaTableExists(L"ModuleSignature")); + BOOL fModuleComponentsTable = (S_OK == WcaTableExists(L"ModuleComponents")); + BOOL fModuleDependencyTable = (S_OK == WcaTableExists(L"ModuleDependency")); + + // read modules + if (fModuleSignatureTable) + { + hr = ModulesRead(&modList); + ExitOnFailure(hr, "Failed to read ModuleSignature table"); + } + + // read module components + if (fModuleComponentsTable) + { + hr = KeyPairsRead(vcsModuleComponentsQuery, &pModCompList); + ExitOnFailure(hr, "Failed to read ModuleComponents table"); + } + + // read module dependencies + if (fModuleDependencyTable) + { + hr = KeyPairsRead(vcsModuleDependencyQuery, &pModDepList); + ExitOnFailure(hr, "Failed to read ModuleDependency table"); + } + + // read assemblies + hr = AssembliesRead(pModCompList, pAppList, pAppRoleList, pAsmList); + ExitOnFailure(hr, "Failed to read ComPlusAssembly table"); + + // read assembly dependencies + if (CpiTableExists(cptComPlusAssemblyDependency)) + { + hr = KeyPairsRead(vcsAssemblyDependencyQuery, &pAsmDepList); + ExitOnFailure(hr, "Failed to read ComPlusAssemblyDependency table"); + } + + // sort modules + if (modList.pFirst && pModDepList) + { + hr = TopSortModuleList(pModDepList, &modList); + ExitOnFailure(hr, "Failed to sort modules"); + } + + // sort assemblies by module + if (pAsmList->pFirst && modList.pFirst && pModDepList) + SortAssemblyListByModule(&modList, pAsmList); + + // sort assemblies by dependency + if (pAsmList->pFirst && pAsmDepList) + { + hr = TopSortAssemblyList(pAsmDepList, pAsmList); + ExitOnFailure(hr, "Failed to sort assemblies"); + } + + hr = S_OK; + +LExit: + // clean up + ModuleListFree(&modList); + if (pModCompList) + KeyPairsFreeList(pModCompList); + if (pModDepList) + KeyPairsFreeList(pModDepList); + if (pAsmDepList) + KeyPairsFreeList(pAsmDepList); + + return hr; +} + +HRESULT CpiAssembliesVerifyInstall( + CPI_ASSEMBLY_LIST* pList + ) +{ + HRESULT hr = S_OK; + + for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // assemblies that are being installed + if (!pItm->fReferencedForInstall && !pItm->iRoleAssignmentsInstallCount && !WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // if the assembly is referensed, it must be installed + if ((pItm->fReferencedForInstall || pItm->iRoleAssignmentsInstallCount) && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction)) + MessageExitOnFailure(hr = E_FAIL, msierrComPlusAssemblyDependency, "An assembly is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey); + } + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiAssembliesVerifyUninstall( + CPI_ASSEMBLY_LIST* pList + ) +{ + HRESULT hr = S_OK; + + for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // assemblies that are being uninstalled + if (!pItm->fReferencedForUninstall && !pItm->iRoleAssignmentsUninstallCount && (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction) && !WcaIsReInstalling(pItm->isInstalled, pItm->isAction))) + continue; + + // if the application is not present, there is no need to remove the components + if (pItm->pApplication && pItm->pApplication->fObjectNotFound) + { + pItm->fIgnore = TRUE; + pList->iUninstallCount--; // elements with the fIgnore flag set will not be scheduled for uninstall + pList->iRoleUninstallCount--; + } + } + + hr = S_OK; + +//LExit: + return hr; +} + +HRESULT CpiAssembliesInstall( + CPI_ASSEMBLY_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + int iCount = 0; + + // add action text + hr = CpiAddActionTextToActionData(L"RegisterComPlusAssemblies", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // assembly count + switch (iRunMode) + { + case rmDeferred: + iCount = pList->iInstallCount - pList->iCommitCount; + break; + case rmCommit: + iCount = pList->iCommitCount; + break; + case rmRollback: + iCount = pList->iInstallCount; + break; + } + + // add assembly count to action data + hr = WcaWriteIntegerToCaData(iCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add assemblies to custom action data in forward order + for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // assemblies that are being installed, or contains roll assignments to install + if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // assemblies that are being installed must be scheduled during the right type of action + BOOL fRunInCommit = 0 != (pItm->iAttributes & aaRunInCommit); + if (((rmCommit == iRunMode && !fRunInCommit) || (rmDeferred == iRunMode && fRunInCommit))) + continue; + + // action type + if (rmRollback == iRunMode) + { + if (CpiIsInstalled(pItm->isInstalled)) + iActionType = atNoOp; + else + iActionType = atRemove; + } + else + iActionType = atCreate; + + // add to action data + hr = AddAssemblyToActionData(pItm, TRUE, iActionType, COST_ASSEMBLY_REGISTER, ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_ASSEMBLY_REGISTER * iCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiAssembliesUninstall( + CPI_ASSEMBLY_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"UnregisterComPlusAssemblies", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add assembly count to action data + hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add assemblies to custom action data in reverse order + for (CPI_ASSEMBLY* pItm = pList->pLast; pItm; pItm = pItm->pPrev) + { + // assemblies that are being uninstalled + if (pItm->fIgnore || (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction) && !WcaIsReInstalling(pItm->isInstalled, pItm->isAction))) + continue; + + // action type + if (rmRollback == iRunMode) + iActionType = atCreate; + else + iActionType = atRemove; + + // add to action data + hr = AddAssemblyToActionData(pItm, FALSE, iActionType, COST_ASSEMBLY_UNREGISTER, ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_ASSEMBLY_UNREGISTER * pList->iUninstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiRoleAssignmentsInstall( + CPI_ASSEMBLY_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + int iCount = 0; + + // add action text + hr = CpiAddActionTextToActionData(L"AddComPlusRoleAssignments", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // assembly count + switch (iRunMode) + { + case rmDeferred: + iCount = pList->iRoleInstallCount - pList->iRoleCommitCount; + break; + case rmCommit: + iCount = pList->iRoleCommitCount; + break; + case rmRollback: + iCount = pList->iRoleInstallCount; + break; + } + + // add assembly count to action data + hr = WcaWriteIntegerToCaData(iCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add assemblies to custom action data in forward order + for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // assemblies that are being installed, or contains roll assignments to install + if (!pItm->iRoleAssignmentsInstallCount) + continue; + + // assemblies that are being installed must be scheduled during the right type of action + BOOL fRunInCommit = 0 != (pItm->iAttributes & aaRunInCommit); + if (((rmCommit == iRunMode && !fRunInCommit) || (rmDeferred == iRunMode && fRunInCommit))) + continue; + + // action type + if (rmRollback == iRunMode) + { + if (CpiIsInstalled(pItm->isInstalled)) + iActionType = atNoOp; + else + iActionType = atRemove; + } + else + iActionType = atCreate; + + // add to action data + hr = AddRoleAssignmentsToActionData(pItm, TRUE, iActionType, COST_ROLLASSIGNMENT_CREATE, ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey); + + // add progress tics + if (piProgress) + *piProgress += COST_ROLLASSIGNMENT_CREATE * pItm->iRoleAssignmentsInstallCount; + } + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiRoleAssignmentsUninstall( + CPI_ASSEMBLY_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"RemoveComPlusRoleAssignments", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add assembly count to action data + hr = WcaWriteIntegerToCaData(pList->iRoleUninstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add assemblies to custom action data in reverse order + for (CPI_ASSEMBLY* pItm = pList->pLast; pItm; pItm = pItm->pPrev) + { + // assemblies that are being uninstalled + if (pItm->fIgnore || !pItm->iRoleAssignmentsUninstallCount) + continue; + + // action type + if (rmRollback == iRunMode) + iActionType = atCreate; + else + iActionType = atRemove; + + // add to action data + hr = AddRoleAssignmentsToActionData(pItm, FALSE, iActionType, COST_ROLLASSIGNMENT_DELETE, ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey); + + // add progress tics + if (piProgress) + *piProgress += COST_ROLLASSIGNMENT_DELETE * pItm->iRoleAssignmentsUninstallCount; + } + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetSubscriptionsCollForComponent( + CPI_ASSEMBLY* pAsm, + CPI_COMPONENT* pComp, + ICatalogCollection** ppiSubsColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piCompColl = NULL; + ICatalogObject* piCompObj = NULL; + + // get applications collection + if (!pComp->piSubsColl) + { + // get components collection for application + hr = CpiGetComponentsCollForApplication(pAsm->pApplication, &piCompColl); + ExitOnFailure(hr, "Failed to get components collection for application"); + + if (S_FALSE == hr) + ExitFunction(); // exit with hr = S_FALSE + + // find component object + hr = CpiFindCollectionObject(piCompColl, pComp->wzCLSID, NULL, &piCompObj); + ExitOnFailure(hr, "Failed to find component object"); + + if (S_FALSE == hr) + ExitFunction(); // exit with hr = S_FALSE + + // get roles collection + hr = CpiGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", &pComp->piSubsColl); + ExitOnFailure(hr, "Failed to get subscriptions collection"); + } + + // return value + *ppiSubsColl = pComp->piSubsColl; + (*ppiSubsColl)->AddRef(); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCompColl); + ReleaseObject(piCompObj); + + return hr; +} + + +// helper function definitions + +static HRESULT GetAssemblyName( + LPCWSTR pwzComponent, + LPWSTR* ppwzAssemblyName + ) +{ + HRESULT hr = S_OK; + + PMSIHANDLE hView, hRecKey, hRec; + + LPWSTR pwzKey = NULL; + + LPWSTR pwzName = NULL; + LPWSTR pwzVersion = NULL; + LPWSTR pwzCulture = NULL; + LPWSTR pwzPublicKeyToken = NULL; + + // create parameter record + hRecKey = ::MsiCreateRecord(1); + ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); + hr = WcaSetRecordString(hRecKey, 1, pwzComponent); + ExitOnFailure(hr, "Failed to set record string"); + + // open view + hr = WcaOpenView(vcsMsiAssemblyNameQuery, &hView); + ExitOnFailure(hr, "Failed to open view on MsiAssemblyName table"); + hr = WcaExecuteView(hView, hRecKey); + ExitOnFailure(hr, "Failed to execute view on MsiAssemblyName table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // read key + hr = WcaGetRecordString(hRec, manqName, &pwzKey); + ExitOnFailure(hr, "Failed to get name"); + + // read value + if (0 == lstrcmpiW(L"name", pwzKey)) + hr = WcaGetRecordString(hRec, manqValue, &pwzName); + else if (0 == lstrcmpiW(L"version", pwzKey)) + hr = WcaGetRecordString(hRec, manqValue, &pwzVersion); + else if (0 == lstrcmpiW(L"culture", pwzKey)) + hr = WcaGetRecordString(hRec, manqValue, &pwzCulture); + else if (0 == lstrcmpiW(L"publicKeyToken", pwzKey)) + hr = WcaGetRecordString(hRec, manqValue, &pwzPublicKeyToken); + else + { + WcaLog(LOGMSG_VERBOSE, "Unknown name in MsiAssemblyName table: %S, %S", pwzComponent, pwzKey); + hr = S_OK; + } + + ExitOnFailure(hr, "Failed to get value"); + } + + if (E_NOMOREITEMS != hr) + ExitOnFailure(hr, "Failed to fetch record"); + + // verify + if (!(pwzName && *pwzName) || !(pwzVersion && *pwzVersion)) + ExitOnFailure(hr = E_FAIL, "Incomplete assembly name"); + + // build name string + hr = StrAllocFormatted(ppwzAssemblyName, L"%s, Version=%s, Culture=%s, PublicKeyToken=%s", + pwzName, pwzVersion, + pwzCulture && *pwzCulture ? pwzCulture : L"Neutral", + pwzPublicKeyToken && *pwzPublicKeyToken ? pwzPublicKeyToken : L"null"); + ExitOnFailure(hr, "Failed to build assembly name string"); + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzKey); + ReleaseStr(pwzName); + ReleaseStr(pwzVersion); + ReleaseStr(pwzCulture); + ReleaseStr(pwzPublicKeyToken); + + return hr; +} + +static HRESULT KeyPairsRead( + LPCWSTR pwzQuery, + CPI_KEY_PAIR** ppKeyPairList + ) +{ + HRESULT hr = S_OK; + + PMSIHANDLE hView, hRec; + + CPI_KEY_PAIR* pItm = NULL; + LPWSTR pwzData = NULL; + + // loop through all dependencies + hr = WcaOpenExecuteView(pwzQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // create entry + pItm = (CPI_KEY_PAIR*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_KEY_PAIR)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get key + hr = WcaGetRecordString(hRec, kpqFirstKey, &pwzData); + ExitOnFailure(hr, "Failed to get first key"); + StringCchCopyW(pItm->wzFirstKey, countof(pItm->wzFirstKey), pwzData); + + // get key + hr = WcaGetRecordString(hRec, kpqSecondKey, &pwzData); + ExitOnFailure(hr, "Failed to get second key"); + StringCchCopyW(pItm->wzSecondKey, countof(pItm->wzSecondKey), pwzData); + + // add entry + if (*ppKeyPairList) + pItm->pNext = *ppKeyPairList; + *ppKeyPairList = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + KeyPairsFreeList(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +static HRESULT ModulesRead( + CPI_MODULE_LIST* pModList + ) +{ + HRESULT hr = S_OK; + + PMSIHANDLE hView, hRec; + + CPI_MODULE* pItm = NULL; + LPWSTR pwzData = NULL; + + // loop through all modules + hr = WcaOpenExecuteView(vcsModuleQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on ModuleSignature table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // create entry + pItm = (CPI_MODULE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_MODULE)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get key + hr = WcaGetRecordString(hRec, mqModule, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // add entry + if (pModList->pLast) + { + pModList->pLast->pNext = pItm; + pItm->pPrev = pModList->pLast; + } + else + pModList->pFirst = pItm; + pModList->pLast = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + ModuleFree(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +static HRESULT AssembliesRead( + CPI_KEY_PAIR* pModCompList, + CPI_APPLICATION_LIST* pAppList, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ASSEMBLY_LIST* pAsmList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + + CPI_ASSEMBLY* pItm = NULL; + CPI_KEY_PAIR* pModComp; + LPWSTR pwzData = NULL; + LPWSTR pwzComponent = NULL; + BOOL fMatchingArchitecture = FALSE; + + // loop through all assemblies + hr = WcaOpenExecuteView(vcsAssemblyQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on ComPlusAssembly table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // get component + hr = WcaGetRecordString(hRec, aqComponent, &pwzComponent); + ExitOnFailure(hr, "Failed to get component"); + + // check if the component is our processor architecture + hr = CpiVerifyComponentArchitecure(pwzComponent, &fMatchingArchitecture); + ExitOnFailure(hr, "Failed to get component architecture."); + + if (!fMatchingArchitecture) + { + continue; // not the same architecture, ignore + } + + // create entry + pItm = (CPI_ASSEMBLY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ASSEMBLY)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get component install state + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &pItm->isInstalled, &pItm->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); + + // get key + hr = WcaGetRecordString(hRec, aqAssembly, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get attributes + hr = WcaGetRecordInteger(hRec, aqAttributes, &pItm->iAttributes); + ExitOnFailure(hr, "Failed to get attributes"); + + // get assembly name + hr = WcaGetRecordFormattedString(hRec, aqAssemblyName, &pItm->pwzAssemblyName); + ExitOnFailure(hr, "Failed to get assembly name"); + + if (!*pItm->pwzAssemblyName && (pItm->iAttributes & aaPathFromGAC)) + { + // get assembly name for component + hr = GetAssemblyName(pwzComponent, &pItm->pwzAssemblyName); + ExitOnFailure(hr, "Failed to get assembly name for component"); + } + + // get dll path + hr = WcaGetRecordFormattedString(hRec, aqDllPath, &pItm->pwzDllPath); + ExitOnFailure(hr, "Failed to get assembly dll path"); + + // get module + // TODO: if there is a very large number of components belonging to modules, this search might be slow + hr = KeyPairFindByFirstKey(pModCompList, pwzData, &pModComp); + + if (S_OK == hr) + StringCchCopyW(pItm->wzModule, countof(pItm->wzModule), pModComp->wzSecondKey); + + // get application + hr = WcaGetRecordString(hRec, aqApplication, &pwzData); + ExitOnFailure(hr, "Failed to get application"); + + if (pwzData && *pwzData) + { + hr = CpiApplicationFindByKey(pAppList, pwzData, &pItm->pApplication); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to find application, key: %S", pwzData); + } + + // get tlb path + hr = WcaGetRecordFormattedString(hRec, aqTlbPath, &pItm->pwzTlbPath); + ExitOnFailure(hr, "Failed to get assembly tlb path"); + + // get proxy-stub dll path + hr = WcaGetRecordFormattedString(hRec, aqPSDllPath, &pItm->pwzPSDllPath); + ExitOnFailure(hr, "Failed to get assembly proxy-stub DLL path"); + + // read components + if (CpiTableExists(cptComPlusComponent)) + { + hr = ComponentsRead(pItm->wzKey, pAppRoleList, pItm); + ExitOnFailure(hr, "Failed to read components for assembly"); + } + + // set references & increment counters + if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + { + pAsmList->iInstallCount++; + if (pItm->iAttributes & aaRunInCommit) + pAsmList->iCommitCount++; + } + if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction) || WcaIsReInstalling(pItm->isInstalled, pItm->isAction)) + pAsmList->iUninstallCount++; + + if (pItm->iRoleAssignmentsInstallCount) + { + pAsmList->iRoleInstallCount++; + if (pItm->iAttributes & aaRunInCommit) + pAsmList->iRoleCommitCount++; + } + if (pItm->iRoleAssignmentsUninstallCount) + pAsmList->iRoleUninstallCount++; + + if (pItm->pApplication) + { + if (pItm->iRoleAssignmentsInstallCount || WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + CpiApplicationAddReferenceInstall(pItm->pApplication); + if (pItm->iRoleAssignmentsUninstallCount || WcaIsUninstalling(pItm->isInstalled, pItm->isAction) || WcaIsReInstalling(pItm->isInstalled, pItm->isAction)) + CpiApplicationAddReferenceUninstall(pItm->pApplication); + } + + // add entry + if (pAsmList->pLast) + { + pAsmList->pLast->pNext = pItm; + pItm->pPrev = pAsmList->pLast; + } + else + pAsmList->pFirst = pItm; + pAsmList->pLast = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + AssemblyFree(pItm); + + ReleaseStr(pwzData); + ReleaseStr(pwzComponent); + + return hr; +} + +static HRESULT TopSortModuleList( + CPI_KEY_PAIR* pDepList, + CPI_MODULE_LIST* pList + ) +{ + HRESULT hr = S_OK; + + // top sort list + for (CPI_MODULE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // append module + hr = SwapDependentModules(NULL, pDepList, pList, pItm, pItm); + ExitOnFailure(hr, "Failed to swap dependent modules"); + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT SwapDependentModules( + CPI_DEPENDENCY_CHAIN* pdcPrev, // list containing the entire dependency chain + CPI_KEY_PAIR* pDepList, // module dependency list + CPI_MODULE_LIST* pList, // module list being sorted + CPI_MODULE* pRoot, // first module in the chain + CPI_MODULE* pItm // current module to test for dependencies + ) +{ + HRESULT hr = S_OK; + + CPI_MODULE* pDepItm; + + // find dependencies + for (CPI_KEY_PAIR* pDep = pDepList; pDep; pDep = pDep->pNext) + { + if (0 == lstrcmpW(pItm->wzKey, pDep->wzFirstKey)) + { + CPI_DEPENDENCY_CHAIN dcItm; + dcItm.pwzKey = pItm->wzKey; + dcItm.pPrev = pdcPrev; + + // check for circular dependencies + for (CPI_DEPENDENCY_CHAIN* pdcItm = &dcItm; pdcItm; pdcItm = pdcItm->pPrev) + { + if (0 == lstrcmpW(pdcItm->pwzKey, pDep->wzSecondKey)) + { + // circular dependency found + ExitOnFailure(hr = E_FAIL, "Circular module dependency found, key: %S", pDep->wzSecondKey); + } + } + + // make sure the item is not already in the list + hr = ModuleFindByKey(pRoot->pPrev, pDep->wzSecondKey, TRUE, &pDepItm); // find in reverse order + + if (S_OK == hr) + continue; // item found, move on + + // find item in the list + hr = ModuleFindByKey(pRoot->pNext, pDep->wzSecondKey, FALSE, &pDepItm); // find in forward order + + if (S_FALSE == hr) + { + // not found + ExitOnFailure(hr = E_FAIL, "Module dependency not found, key: %S", pDep->wzSecondKey); + } + + // if this item in turn has dependencies, they have to be swaped first + hr = SwapDependentModules(&dcItm, pDepList, pList, pRoot, pDepItm); + ExitOnFailure(hr, "Failed to swap dependent module"); + + // remove item from its current position + pDepItm->pPrev->pNext = pDepItm->pNext; // pDepItm can never be the first item, no need to check pPrev + if (pDepItm->pNext) + pDepItm->pNext->pPrev = pDepItm->pPrev; + else + { + pList->pLast = pDepItm->pPrev; + pList->pLast->pNext = NULL; + } + + // insert before the current item + if (pRoot->pPrev) + pRoot->pPrev->pNext = pDepItm; + else + pList->pFirst = pDepItm; + pDepItm->pPrev = pRoot->pPrev; + pRoot->pPrev = pDepItm; + pDepItm->pNext = pRoot; + } + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT ModuleFindByKey( + CPI_MODULE* pItm, + LPCWSTR pwzKey, + BOOL fReverse, + CPI_MODULE** ppItm + ) +{ + for (; pItm; pItm = fReverse ? pItm->pPrev : pItm->pNext) + { + if (0 == lstrcmpW(pItm->wzKey, pwzKey)) + { + *ppItm = pItm; + return S_OK; + } + } + + return S_FALSE; +} + +static void SortAssemblyListByModule( + CPI_MODULE_LIST* pModList, + CPI_ASSEMBLY_LIST* pAsmList + ) +{ + CPI_ASSEMBLY* pMoved = NULL; // first moved item + + // loop modules in reverse order + for (CPI_MODULE* pMod = pModList->pLast; pMod; pMod = pMod->pPrev) + { + // loop assemblies in forward order, starting with the first unmoved item + CPI_ASSEMBLY* pAsm = pMoved ? pMoved->pNext : pAsmList->pFirst; + while (pAsm) + { + CPI_ASSEMBLY* pNext = pAsm->pNext; + + // check if assembly belongs to the current module + if (0 == lstrcmpW(pMod->wzKey, pAsm->wzModule)) + { + // if the item is not already first in the list + if (pAsm->pPrev) + { + // remove item from it's current position + pAsm->pPrev->pNext = pAsm->pNext; + if (pAsm->pNext) + pAsm->pNext->pPrev = pAsm->pPrev; + else + pAsmList->pLast = pAsm->pPrev; + + // insert item first in the list + pAsmList->pFirst->pPrev = pAsm; + pAsm->pNext = pAsmList->pFirst; + pAsm->pPrev = NULL; + pAsmList->pFirst = pAsm; + } + + // if we haven't moved any items yet, this is the first moved item + if (!pMoved) + pMoved = pAsm; + } + + pAsm = pNext; + } + } +} + +static HRESULT TopSortAssemblyList( + CPI_KEY_PAIR* pDepList, + CPI_ASSEMBLY_LIST* pList + ) +{ + HRESULT hr = S_OK; + + // top sort list + for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // append module + hr = SwapDependentAssemblies(NULL, pDepList, pList, pItm, pItm); + ExitOnFailure(hr, "Failed to swap dependent assemblies"); + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT SwapDependentAssemblies( + CPI_DEPENDENCY_CHAIN* pdcPrev, // list containing the entire dependency chain + CPI_KEY_PAIR* pDepList, // assembly dependency list + CPI_ASSEMBLY_LIST* pList, // assembly list being sorted + CPI_ASSEMBLY* pRoot, // first assembly in the chain + CPI_ASSEMBLY* pItm // current assembly to test for dependencies + ) +{ + HRESULT hr = S_OK; + + CPI_ASSEMBLY* pDepItm; + + // find dependencies + for (CPI_KEY_PAIR* pDep = pDepList; pDep; pDep = pDep->pNext) + { + if (0 == lstrcmpW(pItm->wzKey, pDep->wzFirstKey)) + { + CPI_DEPENDENCY_CHAIN dcItm; + dcItm.pwzKey = pItm->wzKey; + dcItm.pPrev = pdcPrev; + + // check for circular dependencies + for (CPI_DEPENDENCY_CHAIN* pdcItm = &dcItm; pdcItm; pdcItm = pdcItm->pPrev) + { + if (0 == lstrcmpW(pdcItm->pwzKey, pDep->wzSecondKey)) + { + // circular dependency found + ExitOnFailure(hr = E_FAIL, "Circular assembly dependency found, key: %S", pDep->wzSecondKey); + } + } + + // make sure the item is not already in the list + hr = AssemblyFindByKey(pRoot->pPrev, pDep->wzSecondKey, TRUE, &pDepItm); // find in reverse order + + if (S_OK == hr) + continue; // item found, move on + + // find item in the list + hr = AssemblyFindByKey(pRoot->pNext, pDep->wzSecondKey, FALSE, &pDepItm); // find in forward order + + if (S_FALSE == hr) + { + // not found + ExitOnFailure(hr = E_FAIL, "Assembly dependency not found, key: %S", pDep->wzSecondKey); + } + + // if the root item belongs to a module, this item must also belong to the same module + if (*pItm->wzModule) + { + if (0 != lstrcmpW(pDepItm->wzModule, pItm->wzModule)) + ExitOnFailure(hr = E_FAIL, "An assembly dependency can only exist between two assemblies not belonging to modules, or belonging to the same module. assembly: %S, required assembly: %S", pItm->wzKey, pDepItm->wzKey); + } + + // if this item in turn has dependencies, they have to be swaped first + hr = SwapDependentAssemblies(&dcItm, pDepList, pList, pRoot, pDepItm); + ExitOnFailure(hr, "Failed to swap dependent assemblies"); + + // remove item from its current position + pDepItm->pPrev->pNext = pDepItm->pNext; // pDepItm can never be the first item, no need to check pPrev + if (pDepItm->pNext) + pDepItm->pNext->pPrev = pDepItm->pPrev; + else + { + pList->pLast = pDepItm->pPrev; + pList->pLast->pNext = NULL; + } + + // insert before the current item + if (pRoot->pPrev) + pRoot->pPrev->pNext = pDepItm; + else + pList->pFirst = pDepItm; + pDepItm->pPrev = pRoot->pPrev; + pRoot->pPrev = pDepItm; + pDepItm->pNext = pRoot; + } + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT AssemblyFindByKey( + CPI_ASSEMBLY* pItm, + LPCWSTR pwzKey, + BOOL fReverse, + CPI_ASSEMBLY** ppItm + ) +{ + for (; pItm; pItm = fReverse ? pItm->pPrev : pItm->pNext) + { + if (0 == lstrcmpW(pItm->wzKey, pwzKey)) + { + *ppItm = pItm; + return S_OK; + } + } + + return S_FALSE; +} + +static HRESULT ComponentsRead( + LPCWSTR pwzAsmKey, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ASSEMBLY* pAsm + ) +{ + HRESULT hr = S_OK; + PMSIHANDLE hView; + PMSIHANDLE hRec; + PMSIHANDLE hRecKey; + CPI_COMPONENT* pItm = NULL; + LPWSTR pwzData = NULL; + + // create parameter record + hRecKey = ::MsiCreateRecord(1); + ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); + hr = WcaSetRecordString(hRecKey, 1, pwzAsmKey); + ExitOnFailure(hr, "Failed to set record string"); + + // open view + hr = WcaOpenView(vcsComponentQuery, &hView); + ExitOnFailure(hr, "Failed to open view on ComPlusComponent table"); + hr = WcaExecuteView(hView, hRecKey); + ExitOnFailure(hr, "Failed to execute view on ComPlusComponent table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // create entry + pItm = (CPI_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_COMPONENT)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get key + hr = WcaGetRecordString(hRec, cqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get clsid + hr = WcaGetRecordFormattedString(hRec, cqCLSID, &pwzData); + ExitOnFailure(hr, "Failed to get clsid"); + StringCchCopyW(pItm->wzCLSID, countof(pItm->wzCLSID), pwzData); + + // read properties + if (CpiTableExists(cptComPlusComponentProperty)) + { + hr = CpiPropertiesRead(vcsComponentPropertyQuery, pItm->wzKey, pdlComponentProperties, &pItm->pProperties, &pItm->iPropertyCount); + ExitOnFailure(hr, "Failed to get component properties"); + } + + // read roles + if (CpiTableExists(cptComPlusRoleForComponent)) + { + hr = RoleAssignmentsRead(vcsRoleForComponentQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount); + ExitOnFailure(hr, "Failed to get roles for component"); + } + + if (pItm->iRoleInstallCount) + pAsm->iRoleAssignmentsInstallCount++; + if (pItm->iRoleUninstallCount) + pAsm->iRoleAssignmentsUninstallCount++; + + // read interfaces + if (CpiTableExists(cptComPlusInterface)) + { + hr = InterfacesRead(pItm->wzKey, pAppRoleList, pAsm, pItm); + ExitOnFailure(hr, "Failed to get interfaces for component"); + } + + // add entry + pAsm->iComponentCount++; + if (pAsm->pComponents) + pItm->pNext = pAsm->pComponents; + pAsm->pComponents = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + ComponentsFreeList(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +static HRESULT InterfacesRead( + LPCWSTR pwzCompKey, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ASSEMBLY* pAsm, + CPI_COMPONENT* pComp + ) +{ + HRESULT hr = S_OK; + PMSIHANDLE hView; + PMSIHANDLE hRec; + PMSIHANDLE hRecKey; + CPI_INTERFACE* pItm = NULL; + LPWSTR pwzData = NULL; + + // create parameter record + hRecKey = ::MsiCreateRecord(1); + ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); + hr = WcaSetRecordString(hRecKey, 1, pwzCompKey); + ExitOnFailure(hr, "Failed to set record string"); + + // open view + hr = WcaOpenView(vcsInterfaceQuery, &hView); + ExitOnFailure(hr, "Failed to open view on ComPlusInterface table"); + hr = WcaExecuteView(hView, hRecKey); + ExitOnFailure(hr, "Failed to execute view on ComPlusInterface table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // create entry + pItm = (CPI_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_INTERFACE)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get key + hr = WcaGetRecordString(hRec, iqInterface, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get iid + hr = WcaGetRecordFormattedString(hRec, iqIID, &pwzData); + ExitOnFailure(hr, "Failed to get iid"); + StringCchCopyW(pItm->wzIID, countof(pItm->wzIID), pwzData); + + // read properties + if (CpiTableExists(cptComPlusInterfaceProperty)) + { + hr = CpiPropertiesRead(vcsInterfacePropertyQuery, pItm->wzKey, pdlInterfaceProperties, &pItm->pProperties, &pItm->iPropertyCount); + ExitOnFailure(hr, "Failed to get interface properties"); + } + + // read roles + if (CpiTableExists(cptComPlusRoleForInterface)) + { + hr = RoleAssignmentsRead(vcsRoleForInterfaceQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount); + ExitOnFailure(hr, "Failed to get roles for interface"); + } + + if (pItm->iRoleInstallCount) + pAsm->iRoleAssignmentsInstallCount++; + if (pItm->iRoleUninstallCount) + pAsm->iRoleAssignmentsUninstallCount++; + + // read methods + if (CpiTableExists(cptComPlusMethod)) + { + hr = MethodsRead(pItm->wzKey, pAppRoleList, pAsm, pItm); + ExitOnFailure(hr, "Failed to get methods for interface"); + } + + // add entry + pComp->iInterfaceCount++; + if (pComp->pInterfaces) + pItm->pNext = pComp->pInterfaces; + pComp->pInterfaces = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + InterfacesFreeList(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +static HRESULT MethodsRead( + LPCWSTR pwzIntfKey, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ASSEMBLY* pAsm, + CPI_INTERFACE* pIntf + ) +{ + HRESULT hr = S_OK; + PMSIHANDLE hView, hRec, hRecKey; + CPI_METHOD* pItm = NULL; + LPWSTR pwzData = NULL; + + // create parameter record + hRecKey = ::MsiCreateRecord(1); + ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); + hr = WcaSetRecordString(hRecKey, 1, pwzIntfKey); + ExitOnFailure(hr, "Failed to set record string"); + + // open view + hr = WcaOpenView(vcsMethodQuery, &hView); + ExitOnFailure(hr, "Failed to open view on ComPlusMethod table"); + hr = WcaExecuteView(hView, hRecKey); + ExitOnFailure(hr, "Failed to execute view on ComPlusMethod table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // create entry + pItm = (CPI_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_METHOD)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get key + hr = WcaGetRecordString(hRec, iqInterface, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get index + hr = WcaGetRecordFormattedString(hRec, mqIndex, &pwzData); + ExitOnFailure(hr, "Failed to get index"); + StringCchCopyW(pItm->wzIndex, countof(pItm->wzIndex), pwzData); + + // get name + hr = WcaGetRecordFormattedString(hRec, mqName, &pwzData); + ExitOnFailure(hr, "Failed to get name"); + StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); + + // either an index or a name must be provided + if (!*pItm->wzIndex && !*pItm->wzName) + ExitOnFailure(hr = E_FAIL, "A method must have either an index or a name associated, key: %S", pItm->wzKey); + + // read properties + if (CpiTableExists(cptComPlusMethodProperty)) + { + hr = CpiPropertiesRead(vcsMethodPropertyQuery, pItm->wzKey, pdlMethodProperties, &pItm->pProperties, &pItm->iPropertyCount); + ExitOnFailure(hr, "Failed to get method properties"); + } + + // read roles + if (CpiTableExists(cptComPlusRoleForMethod)) + { + hr = RoleAssignmentsRead(vcsRoleForMethodQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount); + ExitOnFailure(hr, "Failed to get roles for method"); + } + + if (pItm->iRoleInstallCount) + pAsm->iRoleAssignmentsInstallCount++; + if (pItm->iRoleUninstallCount) + pAsm->iRoleAssignmentsUninstallCount++; + + // add entry + pIntf->iMethodCount++; + if (pIntf->pMethods) + pItm->pNext = pIntf->pMethods; + pIntf->pMethods = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + MethodsFreeList(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +static HRESULT RoleAssignmentsRead( + LPCWSTR pwzQuery, + LPCWSTR pwzKey, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ROLE_ASSIGNMENT** ppRoleList, + int* piInstallCount, + int* piUninstallCount + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec, hRecKey; + + CPI_ROLE_ASSIGNMENT* pItm = NULL; + LPWSTR pwzData = NULL; + BOOL fMatchingArchitecture = FALSE; + + // create parameter record + hRecKey = ::MsiCreateRecord(1); + ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); + hr = WcaSetRecordString(hRecKey, 1, pwzKey); + ExitOnFailure(hr, "Failed to set record string"); + + // open view + hr = WcaOpenView(pwzQuery, &hView); + ExitOnFailure(hr, "Failed to open view on role assignment table"); + hr = WcaExecuteView(hView, hRecKey); + ExitOnFailure(hr, "Failed to execute view on role assignment table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // get component + hr = WcaGetRecordString(hRec, raqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get assembly component"); + + // check if the component is our processor architecture + hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); + ExitOnFailure(hr, "Failed to get component architecture."); + + if (!fMatchingArchitecture) + { + continue; // not the same architecture, ignore + } + + // create entry + pItm = (CPI_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ROLE_ASSIGNMENT)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get component install state + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); + + // get key + hr = WcaGetRecordString(hRec, raqKey, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get application role + hr = WcaGetRecordString(hRec, raqApplicationRole, &pwzData); + ExitOnFailure(hr, "Failed to get application role"); + + hr = CpiApplicationRoleFindByKey(pAppRoleList, pwzData, &pItm->pApplicationRole); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to find application, key: %S", pwzData); + + // set references & increment counters + if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + { + CpiApplicationRoleAddReferenceInstall(pItm->pApplicationRole); + ++*piInstallCount; + } + if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + { + CpiApplicationRoleAddReferenceUninstall(pItm->pApplicationRole); + ++*piUninstallCount; + } + + // add entry + if (*ppRoleList) + pItm->pNext = *ppRoleList; + *ppRoleList = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + RoleAssignmentsFreeList(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +static HRESULT AddAssemblyToActionData( + CPI_ASSEMBLY* pItm, + BOOL fInstall, + 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 assembly information to custom action data + hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly key to custom action data"); + hr = WcaWriteStringToCaData(pItm->pwzAssemblyName, ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly name to custom action data"); + hr = WcaWriteStringToCaData(pItm->pwzDllPath, ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly dll path to custom action data"); + hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pwzTlbPath : L"", ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly tlb path to custom action data"); + hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pwzPSDllPath : L"", ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly proxy-stub dll path to custom action data"); + hr = WcaWriteIntegerToCaData(pItm->iAttributes, ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly attributes to custom action data"); + + // add application information to custom action data + hr = WcaWriteStringToCaData(pItm->pApplication ? pItm->pApplication->wzID : L"", ppwzActionData); + ExitOnFailure(hr, "Failed to add application id to custom action data"); + + // add partition information to custom action data + LPCWSTR pwzPartID = pItm->pApplication && pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L""; + hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData); + ExitOnFailure(hr, "Failed to add partition id to custom action data"); + + // add components to custom action data + // + // components are needed acording to the following table: + // + // Native .NET + // -------------------------------------------- + // NoOp | No | No + // Create | Yes | Yes + // Remove | Yes | No + // + int iCompCount = (atCreate == iActionType || (atRemove == iActionType && 0 == (pItm->iAttributes & aaDotNetAssembly))) ? pItm->iComponentCount : 0; + hr = WcaWriteIntegerToCaData(iCompCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add component count to custom action data, key: %S", pItm->wzKey); + + if (iCompCount) + { + for (CPI_COMPONENT* pComp = pItm->pComponents; pComp; pComp = pComp->pNext) + { + hr = AddComponentToActionData(pComp, fInstall, atCreate == iActionType, FALSE, ppwzActionData); + ExitOnFailure(hr, "Failed to add component to custom action data, component: %S", pComp->wzKey); + } + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT AddRoleAssignmentsToActionData( + CPI_ASSEMBLY* pItm, + BOOL fInstall, + 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 assembly information to custom action data + hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData); + ExitOnFailure(hr, "Failed to add assembly key to custom action data"); + hr = WcaWriteIntegerToCaData(fInstall ? pItm->iRoleAssignmentsInstallCount : pItm->iRoleAssignmentsUninstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add role assignments count to custom action data"); + + // add application information to custom action data + hr = WcaWriteStringToCaData(pItm->pApplication ? pItm->pApplication->wzID : L"", ppwzActionData); + ExitOnFailure(hr, "Failed to add application id to custom action data"); + + // add partition information to custom action data + LPCWSTR pwzPartID = pItm->pApplication && pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L""; + hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData); + ExitOnFailure(hr, "Failed to add partition id to custom action data"); + + // add components to custom action data + hr = WcaWriteIntegerToCaData(pItm->iComponentCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add component count to custom action data"); + + for (CPI_COMPONENT* pComp = pItm->pComponents; pComp; pComp = pComp->pNext) + { + hr = AddComponentToActionData(pComp, fInstall, FALSE, TRUE, ppwzActionData); + ExitOnFailure(hr, "Failed to add component to custom action data, component: %S", pComp->wzKey); + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT AddComponentToActionData( + CPI_COMPONENT* pItm, + BOOL fInstall, + BOOL fProps, + BOOL fRoles, + LPWSTR* ppwzActionData + ) +{ + HRESULT hr = S_OK; + + // add component information to custom action data + hr = WcaWriteStringToCaData(pItm->wzCLSID, ppwzActionData); + ExitOnFailure(hr, "Failed to add component CLSID to custom action data"); + + // add properties to custom action data + hr = CpiAddPropertiesToActionData(fProps ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData); + ExitOnFailure(hr, "Failed to add properties to custom action data"); + + // add roles to custom action data + hr = AddRolesToActionData(pItm->iRoleInstallCount, pItm->iRoleUninstallCount, pItm->pRoles, fInstall, fRoles, ppwzActionData); + ExitOnFailure(hr, "Failed to add roles to custom action data"); + + // add interfaces to custom action data + int iIntfCount = (fProps || fRoles) ? pItm->iInterfaceCount : 0; + hr = WcaWriteIntegerToCaData(iIntfCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add interface count to custom action data"); + + if (iIntfCount) + { + for (CPI_INTERFACE* pIntf = pItm->pInterfaces; pIntf; pIntf = pIntf->pNext) + { + hr = AddInterfaceToActionData(pIntf, fInstall, fProps, fRoles, ppwzActionData); + ExitOnFailure(hr, "Failed to add interface custom action data, interface: %S", pIntf->wzKey); + } + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT AddInterfaceToActionData( + CPI_INTERFACE* pItm, + BOOL fInstall, + BOOL fProps, + BOOL fRoles, + LPWSTR* ppwzActionData + ) +{ + HRESULT hr = S_OK; + + // add interface information to custom action data + hr = WcaWriteStringToCaData(pItm->wzIID, ppwzActionData); + ExitOnFailure(hr, "Failed to add interface IID to custom action data"); + + // add properties to custom action data + hr = CpiAddPropertiesToActionData(fProps ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData); + ExitOnFailure(hr, "Failed to add properties to custom action data"); + + // add roles to custom action data + hr = AddRolesToActionData(pItm->iRoleInstallCount, pItm->iRoleUninstallCount, pItm->pRoles, fInstall, fRoles, ppwzActionData); + ExitOnFailure(hr, "Failed to add roles to custom action data"); + + // add methods to custom action data + hr = WcaWriteIntegerToCaData(pItm->iMethodCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add method count to custom action data"); + + for (CPI_METHOD* pMeth = pItm->pMethods; pMeth; pMeth = pMeth->pNext) + { + hr = AddMethodToActionData(pMeth, fInstall, fProps, fRoles, ppwzActionData); + ExitOnFailure(hr, "Failed to add method custom action data, method: %S", pMeth->wzKey); + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT AddMethodToActionData( + CPI_METHOD* pItm, + BOOL fInstall, + BOOL fProps, + BOOL fRoles, + LPWSTR* ppwzActionData + ) +{ + HRESULT hr = S_OK; + + // add interface information to custom action data + hr = WcaWriteStringToCaData(pItm->wzIndex, ppwzActionData); + ExitOnFailure(hr, "Failed to add method index to custom action data"); + + hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData); + ExitOnFailure(hr, "Failed to add method name to custom action data"); + + // add properties to custom action data + hr = CpiAddPropertiesToActionData(fProps ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData); + ExitOnFailure(hr, "Failed to add properties to custom action data"); + + // add roles to custom action data + hr = AddRolesToActionData(pItm->iRoleInstallCount, pItm->iRoleUninstallCount, pItm->pRoles, fInstall, fRoles, ppwzActionData); + ExitOnFailure(hr, "Failed to add roles to custom action data"); + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT AddRolesToActionData( + int iRoleInstallCount, + int iRoleUninstallCount, + CPI_ROLE_ASSIGNMENT* pRoleList, + BOOL fInstall, + BOOL fRoles, + LPWSTR* ppwzActionData + ) +{ + HRESULT hr = S_OK; + + int iRoleCount = fRoles ? (fInstall ? iRoleInstallCount : iRoleUninstallCount) : 0; + hr = WcaWriteIntegerToCaData(iRoleCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add role count to custom action data"); + + if (iRoleCount) + { + for (CPI_ROLE_ASSIGNMENT* pRole = pRoleList; pRole; pRole = pRole->pNext) + { + // make sure the install state matches the create flag + if (fInstall ? !WcaIsInstalling(pRole->isInstalled, pRole->isAction) : !WcaIsUninstalling(pRole->isInstalled, pRole->isAction)) + continue; + + hr = WcaWriteStringToCaData(pRole->pApplicationRole->wzKey, ppwzActionData); + ExitOnFailure(hr, "Failed to add key to custom action data, role: %S", pRole->wzKey); + + hr = WcaWriteStringToCaData(pRole->pApplicationRole->wzName, ppwzActionData); + ExitOnFailure(hr, "Failed to add role name to custom action data, role: %S", pRole->wzKey); + } + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT KeyPairFindByFirstKey( + CPI_KEY_PAIR* pList, + LPCWSTR pwzKey, + CPI_KEY_PAIR** ppItm + ) +{ + for (; pList; pList = pList->pNext) + { + if (0 == lstrcmpW(pList->wzFirstKey, pwzKey)) + { + *ppItm = pList; + return S_OK; + } + } + + return S_FALSE; +} + +static void AssemblyFree( + CPI_ASSEMBLY* pItm + ) +{ + ReleaseStr(pItm->pwzAssemblyName); + ReleaseStr(pItm->pwzDllPath); + ReleaseStr(pItm->pwzTlbPath); + ReleaseStr(pItm->pwzPSDllPath); + + if (pItm->pComponents) + ComponentsFreeList(pItm->pComponents); + + ::HeapFree(::GetProcessHeap(), 0, pItm); +} + +static void KeyPairsFreeList( + CPI_KEY_PAIR* pList + ) +{ + while (pList) + { + CPI_KEY_PAIR* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +void ModuleListFree( + CPI_MODULE_LIST* pList + ) +{ + CPI_MODULE* pItm = pList->pFirst; + + while (pItm) + { + CPI_MODULE* pDelete = pItm; + pItm = pItm->pNext; + ModuleFree(pDelete); + } +} + +static void ModuleFree( + CPI_MODULE* pItm + ) +{ + ::HeapFree(::GetProcessHeap(), 0, pItm); +} + +static void ComponentsFreeList( + CPI_COMPONENT* pList + ) +{ + while (pList) + { + if (pList->pProperties) + CpiPropertiesFreeList(pList->pProperties); + + if (pList->pRoles) + RoleAssignmentsFreeList(pList->pRoles); + + if (pList->pInterfaces) + InterfacesFreeList(pList->pInterfaces); + + ReleaseObject(pList->piSubsColl); + + CPI_COMPONENT* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +static void InterfacesFreeList( + CPI_INTERFACE* pList + ) +{ + while (pList) + { + if (pList->pProperties) + CpiPropertiesFreeList(pList->pProperties); + + if (pList->pRoles) + RoleAssignmentsFreeList(pList->pRoles); + + if (pList->pMethods) + MethodsFreeList(pList->pMethods); + + CPI_INTERFACE* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +static void MethodsFreeList( + CPI_METHOD* pList + ) +{ + while (pList) + { + if (pList->pProperties) + CpiPropertiesFreeList(pList->pProperties); + + if (pList->pRoles) + RoleAssignmentsFreeList(pList->pRoles); + + CPI_METHOD* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +static void RoleAssignmentsFreeList( + CPI_ROLE_ASSIGNMENT* pList + ) +{ + while (pList) + { + CPI_ROLE_ASSIGNMENT* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} diff --git a/src/ca/cpasmsched.h b/src/ca/cpasmsched.h new file mode 100644 index 00000000..b5a68d7e --- /dev/null +++ b/src/ca/cpasmsched.h @@ -0,0 +1,168 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +enum eAssemblyAttributes +{ + aaEventClass = (1 << 0), + aaDotNetAssembly = (1 << 1), + aaPathFromGAC = (1 << 2), + aaRunInCommit = (1 << 3) +}; + + +// structs + +struct CPI_ROLE_ASSIGNMENT +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + + INSTALLSTATE isInstalled, isAction; + + CPI_APPLICATION_ROLE* pApplicationRole; + + CPI_ROLE_ASSIGNMENT* pNext; +}; + +struct CPI_METHOD +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzIndex[11 + 1]; + WCHAR wzName[MAX_DARWIN_COLUMN + 1]; + + int iPropertyCount; + CPI_PROPERTY* pProperties; + + int iRoleInstallCount; + int iRoleUninstallCount; + CPI_ROLE_ASSIGNMENT* pRoles; + + CPI_METHOD* pNext; +}; + +struct CPI_INTERFACE +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzIID[CPI_MAX_GUID + 1]; + + int iPropertyCount; + CPI_PROPERTY* pProperties; + + int iRoleInstallCount; + int iRoleUninstallCount; + CPI_ROLE_ASSIGNMENT* pRoles; + + int iMethodCount; + CPI_METHOD* pMethods; + + CPI_INTERFACE* pNext; +}; + +struct CPI_COMPONENT +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzCLSID[CPI_MAX_GUID + 1]; + + int iPropertyCount; + CPI_PROPERTY* pProperties; + + int iRoleInstallCount; + int iRoleUninstallCount; + CPI_ROLE_ASSIGNMENT* pRoles; + + int iInterfaceCount; + CPI_INTERFACE* pInterfaces; + + ICatalogCollection* piSubsColl; + + CPI_COMPONENT* pNext; +}; + +struct CPI_ASSEMBLY +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzModule[MAX_DARWIN_KEY + 1]; + LPWSTR pwzAssemblyName; + LPWSTR pwzDllPath; + LPWSTR pwzTlbPath; + LPWSTR pwzPSDllPath; + int iAttributes; + + int iComponentCount; + CPI_COMPONENT* pComponents; + + BOOL fReferencedForInstall; + BOOL fReferencedForUninstall; + BOOL fIgnore; + + int iRoleAssignmentsInstallCount; + int iRoleAssignmentsUninstallCount; + + INSTALLSTATE isInstalled, isAction; + + CPI_APPLICATION* pApplication; + + CPI_ASSEMBLY* pPrev; + CPI_ASSEMBLY* pNext; +}; + +struct CPI_ASSEMBLY_LIST +{ + CPI_ASSEMBLY* pFirst; + CPI_ASSEMBLY* pLast; + + int iInstallCount; + int iCommitCount; + int iUninstallCount; + + int iRoleInstallCount; + int iRoleCommitCount; + int iRoleUninstallCount; +}; + + +// function prototypes + +void CpiAssemblyListFree( + CPI_ASSEMBLY_LIST* pList + ); +HRESULT CpiAssembliesRead( + CPI_APPLICATION_LIST* pAppList, + CPI_APPLICATION_ROLE_LIST* pAppRoleList, + CPI_ASSEMBLY_LIST* pAsmList + ); +HRESULT CpiAssembliesVerifyInstall( + CPI_ASSEMBLY_LIST* pList + ); +HRESULT CpiAssembliesVerifyUninstall( + CPI_ASSEMBLY_LIST* pList + ); +HRESULT CpiAssembliesInstall( + CPI_ASSEMBLY_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiAssembliesUninstall( + CPI_ASSEMBLY_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiRoleAssignmentsInstall( + CPI_ASSEMBLY_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiRoleAssignmentsUninstall( + CPI_ASSEMBLY_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiGetSubscriptionsCollForComponent( + CPI_ASSEMBLY* pAsm, + CPI_COMPONENT* pComp, + ICatalogCollection** ppiSubsColl + ); diff --git a/src/ca/cpcost.h b/src/ca/cpcost.h new file mode 100644 index 00000000..7a23e03b --- /dev/null +++ b/src/ca/cpcost.h @@ -0,0 +1,30 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +#define COST_PARTITION_CREATE 10000 +#define COST_PARTITION_DELETE 10000 + +#define COST_PARTITION_USER_CREATE 10000 +#define COST_PARTITION_USER_DELETE 10000 + +#define COST_USER_IN_PARTITION_ROLE_CREATE 10000 +#define COST_USER_IN_PARTITION_ROLE_DELETE 10000 + +#define COST_APPLICATION_CREATE 10000 +#define COST_APPLICATION_DELETE 10000 + +#define COST_APPLICATION_ROLE_CREATE 10000 +#define COST_APPLICATION_ROLE_DELETE 10000 + +#define COST_USER_IN_APPLICATION_ROLE_CREATE 10000 +#define COST_USER_IN_APPLICATION_ROLE_DELETE 10000 + +#define COST_ASSEMBLY_REGISTER 50000 +#define COST_ASSEMBLY_UNREGISTER 10000 + +#define COST_ROLLASSIGNMENT_CREATE 10000 +#define COST_ROLLASSIGNMENT_DELETE 10000 + +#define COST_SUBSCRIPTION_CREATE 10000 +#define COST_SUBSCRIPTION_DELETE 10000 diff --git a/src/ca/cpexec.cpp b/src/ca/cpexec.cpp new file mode 100644 index 00000000..fa2446d8 --- /dev/null +++ b/src/ca/cpexec.cpp @@ -0,0 +1,704 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +/******************************************************************** + DllMain - standard entry point for all WiX CustomActions + +********************************************************************/ +extern "C" BOOL WINAPI DllMain( + IN HINSTANCE hInst, + IN ULONG ulReason, + IN LPVOID) +{ + switch(ulReason) + { + case DLL_PROCESS_ATTACH: + WcaGlobalInitialize(hInst); + break; + + case DLL_PROCESS_DETACH: + WcaGlobalFinalize(); + break; + } + + return TRUE; +} + +/******************************************************************** + ComPlusPrepare - CUSTOM ACTION ENTRY POINT + + Input: deferred CustomActionData - ComPlusPrepare +********************************************************************/ +extern "C" UINT __stdcall ComPlusPrepare(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzData = NULL; + + HANDLE hRollbackFile = INVALID_HANDLE_VALUE; + + // initialize + hr = WcaInitialize(hInstall, "ComPlusPrepare"); + ExitOnFailure(hr, "Failed to initialize ComPlusPrepare"); + + // get custom action data + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "Failed to get CustomActionData"); + pwzData = pwzCustomActionData; + + // create rollback file + hRollbackFile = ::CreateFileW(pwzData, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL); + if (INVALID_HANDLE_VALUE == hRollbackFile) + ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to create rollback file, name: %S", pwzData); + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzCustomActionData); + + if (INVALID_HANDLE_VALUE != hRollbackFile) + ::CloseHandle(hRollbackFile); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +/******************************************************************** + ComPlusCleanup - CUSTOM ACTION ENTRY POINT + + Input: deferred CustomActionData - ComPlusCleanup +********************************************************************/ +extern "C" UINT __stdcall ComPlusCleanup(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzData = NULL; + + // initialize + hr = WcaInitialize(hInstall, "ComPlusCleanup"); + ExitOnFailure(hr, "Failed to initialize ComPlusCleanup"); + + // get custom action data + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "Failed to get CustomActionData"); + pwzData = pwzCustomActionData; + + // delete rollback file + if (!::DeleteFileW(pwzData)) + { + // error, but not a showstopper + hr = HRESULT_FROM_WIN32(::GetLastError()); + WcaLog(LOGMSG_STANDARD, "Failed to delete rollback file, hr: 0x%x, name: %S", hr, pwzData); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzCustomActionData); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +/******************************************************************** + ComPlusInstallExecute - CUSTOM ACTION ENTRY POINT + + Input: deferred CustomActionData - ComPlusInstallExecute +********************************************************************/ +extern "C" UINT __stdcall ComPlusInstallExecute(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzRollbackFileName = NULL; + + HANDLE hRollbackFile = INVALID_HANDLE_VALUE; + + BOOL fInitializedCom = FALSE; + + // initialize + hr = WcaInitialize(hInstall, "ComPlusInstallExecute"); + ExitOnFailure(hr, "Failed to initialize ComPlusInstallExecute"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "Failed to initialize COM"); + fInitializedCom = TRUE; + + CpiInitialize(); + + // get custom action data + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "Failed to get CustomActionData"); + pwzData = pwzCustomActionData; + + // open rollback file + hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName); + ExitOnFailure(hr, "Failed to read rollback file name"); + + hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); + if (INVALID_HANDLE_VALUE == hRollbackFile) + ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName); + + // create partitions + hr = CpiConfigurePartitions(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to create partitions"); + if (S_FALSE == hr) ExitFunction(); + + // create users in partition roles + hr = CpiConfigureUsersInPartitionRoles(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to create users in partition roles"); + if (S_FALSE == hr) ExitFunction(); + + // create partition users + hr = CpiConfigurePartitionUsers(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to add partition users"); + if (S_FALSE == hr) ExitFunction(); + + // create applications + hr = CpiConfigureApplications(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to create applications"); + if (S_FALSE == hr) ExitFunction(); + + // create application roles + hr = CpiConfigureApplicationRoles(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to create application roles"); + if (S_FALSE == hr) ExitFunction(); + + // create users in application roles + hr = CpiConfigureUsersInApplicationRoles(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to create users in application roles"); + if (S_FALSE == hr) ExitFunction(); + + // register assemblies + hr = CpiConfigureAssemblies(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to register assemblies"); + if (S_FALSE == hr) ExitFunction(); + + // create role assignments + hr = CpiConfigureRoleAssignments(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to create role assignments"); + if (S_FALSE == hr) ExitFunction(); + + // create subscriptions + hr = CpiConfigureSubscriptions(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to create subscriptions"); + if (S_FALSE == hr) ExitFunction(); + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzRollbackFileName); + + if (INVALID_HANDLE_VALUE != hRollbackFile) + ::CloseHandle(hRollbackFile); + + // unitialize + CpiFinalize(); + + if (fInitializedCom) + ::CoUninitialize(); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +/******************************************************************** + ComPlusInstallExecuteCommit - CUSTOM ACTION ENTRY POINT + + Input: deferred CustomActionData - ComPlusInstallExecuteCommit +********************************************************************/ +extern "C" UINT __stdcall ComPlusInstallExecuteCommit(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzRollbackFileName = NULL; + + HANDLE hRollbackFile = INVALID_HANDLE_VALUE; + + BOOL fInitializedCom = FALSE; + + // initialize + hr = WcaInitialize(hInstall, "ComPlusInstallExecuteCommit"); + ExitOnFailure(hr, "Failed to initialize ComPlusInstallExecuteCommit"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "Failed to initialize COM"); + fInitializedCom = TRUE; + + CpiInitialize(); + + // get custom action data + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "Failed to get CustomActionData"); + pwzData = pwzCustomActionData; + + // open rollback file + hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName); + ExitOnFailure(hr, "Failed to read rollback file name"); + + hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); + if (INVALID_HANDLE_VALUE == hRollbackFile) + ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName); + + if (INVALID_SET_FILE_POINTER == ::SetFilePointer(hRollbackFile, 0, NULL, FILE_END)) + ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set file pointer"); + + // register assemblies + hr = CpiConfigureAssemblies(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to register assemblies"); + if (S_FALSE == hr) ExitFunction(); + + // create role assignments + hr = CpiConfigureRoleAssignments(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to create role assignments"); + if (S_FALSE == hr) ExitFunction(); + + // create subscriptions + hr = CpiConfigureSubscriptions(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to create subscriptions"); + if (S_FALSE == hr) ExitFunction(); + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzCustomActionData); + + if (INVALID_HANDLE_VALUE != hRollbackFile) + ::CloseHandle(hRollbackFile); + + // unitialize + CpiFinalize(); + + if (fInitializedCom) + ::CoUninitialize(); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +/******************************************************************** + ComPlusRollbackInstallExecute - CUSTOM ACTION ENTRY POINT + + Input: deferred CustomActionData - ComPlusRollbackInstallExecute +********************************************************************/ +extern "C" UINT __stdcall ComPlusRollbackInstallExecute(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzRollbackFileName = NULL; + + HANDLE hRollbackFile = INVALID_HANDLE_VALUE; + + CPI_ROLLBACK_DATA* prdPartitions = NULL; + CPI_ROLLBACK_DATA* prdUsersInPartitionRoles = NULL; + CPI_ROLLBACK_DATA* prdPartitionUsers = NULL; + CPI_ROLLBACK_DATA* prdApplications = NULL; + CPI_ROLLBACK_DATA* prdApplicationRoles = NULL; + CPI_ROLLBACK_DATA* prdUsersApplicationRoles = NULL; + CPI_ROLLBACK_DATA* prdAssemblies = NULL; + CPI_ROLLBACK_DATA* prdRoleAssignments = NULL; + CPI_ROLLBACK_DATA* prdSubscriptions = NULL; + + BOOL fInitializedCom = FALSE; + + // initialize + hr = WcaInitialize(hInstall, "ComPlusRollbackInstallExecute"); + ExitOnFailure(hr, "Failed to initialize ComPlusRollbackInstallExecute"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "Failed to initialize COM"); + fInitializedCom = TRUE; + + CpiInitialize(); + + // get custom action data + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "Failed to get CustomActionData"); + pwzData = pwzCustomActionData; + + // open rollback file + hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName); + ExitOnFailure(hr, "Failed to read rollback file name"); + + hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); + if (INVALID_HANDLE_VALUE == hRollbackFile) + ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName); + + // read rollback data (execute) + hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitions); + ExitOnFailure(hr, "Failed to read partitions rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersInPartitionRoles); + ExitOnFailure(hr, "Failed to read users in partition roles rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitionUsers); + ExitOnFailure(hr, "Failed to read partition users rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdApplications); + ExitOnFailure(hr, "Failed to read applications rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdApplicationRoles); + ExitOnFailure(hr, "Failed to read application roles rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersApplicationRoles); + ExitOnFailure(hr, "Failed to read users in application roles rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdAssemblies); + ExitOnFailure(hr, "Failed to read assemblies rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdRoleAssignments); + ExitOnFailure(hr, "Failed to read role assignments rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdSubscriptions); + ExitOnFailure(hr, "Failed to read subscription rollback data"); + + // read rollback data (commit) + hr = CpiReadRollbackDataList(hRollbackFile, &prdAssemblies); + ExitOnFailure(hr, "Failed to read assemblies rollback data (commit)"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdRoleAssignments); + ExitOnFailure(hr, "Failed to read role assignments rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdSubscriptions); + ExitOnFailure(hr, "Failed to read subscription rollback data (commit)"); + + ::CloseHandle(hRollbackFile); + hRollbackFile = INVALID_HANDLE_VALUE; + + // rollback create subscriptions + hr = CpiRollbackConfigureSubscriptions(&pwzData, prdSubscriptions); + ExitOnFailure(hr, "Failed to rollback create subscriptions"); + + // rollback create role assignments + hr = CpiRollbackConfigureRoleAssignments(&pwzData, prdRoleAssignments); + ExitOnFailure(hr, "Failed to rollback create role assignments"); + + // rollback register assemblies + hr = CpiRollbackConfigureAssemblies(&pwzData, prdAssemblies); + ExitOnFailure(hr, "Failed to rollback register assemblies"); + + // rollback create users in application roles + hr = CpiRollbackConfigureUsersInApplicationRoles(&pwzData, prdUsersApplicationRoles); + ExitOnFailure(hr, "Failed to rollback create users in application roles"); + + // rollback create application roles + hr = CpiRollbackConfigureApplicationRoles(&pwzData, prdApplicationRoles); + ExitOnFailure(hr, "Failed to rollback create application roles"); + + // rollback create applications + hr = CpiRollbackConfigureApplications(&pwzData, prdApplications); + ExitOnFailure(hr, "Failed to rollback create applications"); + + // rollback create partition users + hr = CpiRollbackConfigurePartitionUsers(&pwzData, prdPartitionUsers); + ExitOnFailure(hr, "Failed to rollback create partition users"); + + // rollback create users in partition roles + hr = CpiRollbackConfigureUsersInPartitionRoles(&pwzData, prdUsersInPartitionRoles); + ExitOnFailure(hr, "Failed to rollback create users in partition roles"); + + // rollback create partitions + hr = CpiRollbackConfigurePartitions(&pwzData, prdPartitions); + ExitOnFailure(hr, "Failed to rollback create partitions"); + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzRollbackFileName); + + if (INVALID_HANDLE_VALUE != hRollbackFile) + ::CloseHandle(hRollbackFile); + + if (prdPartitions) + CpiFreeRollbackDataList(prdPartitions); + if (prdUsersInPartitionRoles) + CpiFreeRollbackDataList(prdUsersInPartitionRoles); + if (prdPartitionUsers) + CpiFreeRollbackDataList(prdPartitionUsers); + if (prdApplications) + CpiFreeRollbackDataList(prdApplications); + if (prdApplicationRoles) + CpiFreeRollbackDataList(prdApplicationRoles); + if (prdUsersApplicationRoles) + CpiFreeRollbackDataList(prdUsersApplicationRoles); + if (prdAssemblies) + CpiFreeRollbackDataList(prdAssemblies); + if (prdRoleAssignments) + CpiFreeRollbackDataList(prdRoleAssignments); + if (prdSubscriptions) + CpiFreeRollbackDataList(prdSubscriptions); + + // unitialize + CpiFinalize(); + + if (fInitializedCom) + ::CoUninitialize(); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +/******************************************************************** + ComPlusUninstallExecute - CUSTOM ACTION ENTRY POINT + + Input: deferred CustomActionData - ComPlusUninstallExecute +********************************************************************/ +extern "C" UINT __stdcall ComPlusUninstallExecute(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzRollbackFileName = NULL; + + HANDLE hRollbackFile = INVALID_HANDLE_VALUE; + + BOOL fInitializedCom = FALSE; + + // initialize + hr = WcaInitialize(hInstall, "ComPlusUninstallExecute"); + ExitOnFailure(hr, "Failed to initialize ComPlusUninstallExecute"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "Failed to initialize COM"); + fInitializedCom = TRUE; + + CpiInitialize(); + + // get custom action data + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "Failed to get CustomActionData"); + pwzData = pwzCustomActionData; + + // open rollback file + hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName); + ExitOnFailure(hr, "Failed to read rollback file name"); + + hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); + if (INVALID_HANDLE_VALUE == hRollbackFile) + ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName); + + // delete subscriptions + hr = CpiConfigureSubscriptions(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to delete subscriptions"); + if (S_FALSE == hr) ExitFunction(); + + // delete role assignments + hr = CpiConfigureRoleAssignments(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to delete role assignments"); + if (S_FALSE == hr) ExitFunction(); + + // unregister assemblies + hr = CpiConfigureAssemblies(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to unregister assemblies"); + if (S_FALSE == hr) ExitFunction(); + + // remove users in application roles + hr = CpiConfigureUsersInApplicationRoles(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to delete users in application roles"); + if (S_FALSE == hr) ExitFunction(); + + // remove application roles + hr = CpiConfigureApplicationRoles(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to delete application roles"); + if (S_FALSE == hr) ExitFunction(); + + // remove applications + hr = CpiConfigureApplications(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to remove applications"); + if (S_FALSE == hr) ExitFunction(); + + // remove partition users + hr = CpiConfigurePartitionUsers(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to remove partition users"); + if (S_FALSE == hr) ExitFunction(); + + // remove users in partition roles + hr = CpiConfigureUsersInPartitionRoles(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to delete users in partition roles"); + if (S_FALSE == hr) ExitFunction(); + + // remove partitions + hr = CpiConfigurePartitions(&pwzData, hRollbackFile); + ExitOnFailure(hr, "Failed to delete partitions"); + if (S_FALSE == hr) ExitFunction(); + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzRollbackFileName); + + if (INVALID_HANDLE_VALUE != hRollbackFile) + ::CloseHandle(hRollbackFile); + + // unitialize + CpiFinalize(); + + if (fInitializedCom) + ::CoUninitialize(); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +/******************************************************************** + ComPlusRollbackUninstallExecute - CUSTOM ACTION ENTRY POINT + + Input: deferred CustomActionData - ComPlusRollbackUninstallExecute +********************************************************************/ +extern "C" UINT __stdcall ComPlusRollbackUninstallExecute(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzRollbackFileName = NULL; + + HANDLE hRollbackFile = INVALID_HANDLE_VALUE; + + CPI_ROLLBACK_DATA* prdPartitions = NULL; + CPI_ROLLBACK_DATA* prdUsersInPartitionRoles = NULL; + CPI_ROLLBACK_DATA* prdPartitionUsers = NULL; + CPI_ROLLBACK_DATA* prdApplications = NULL; + CPI_ROLLBACK_DATA* prdApplicationRoles = NULL; + CPI_ROLLBACK_DATA* prdUsersApplicationRoles = NULL; + CPI_ROLLBACK_DATA* prdAssemblies = NULL; + CPI_ROLLBACK_DATA* prdRoleAssignments = NULL; + CPI_ROLLBACK_DATA* prdSubscriptions = NULL; + + BOOL fInitializedCom = FALSE; + + // initialize + hr = WcaInitialize(hInstall, "ComPlusRollbackUninstallExecute"); + ExitOnFailure(hr, "Failed to initialize ComPlusRollbackUninstallExecute"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "Failed to initialize COM"); + fInitializedCom = TRUE; + + CpiInitialize(); + + // get custom action data + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "Failed to get CustomActionData"); + pwzData = pwzCustomActionData; + + // open rollback file + hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName); + ExitOnFailure(hr, "Failed to read rollback file name"); + + hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); + if (INVALID_HANDLE_VALUE == hRollbackFile) + ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName); + + // read rollback data + hr = CpiReadRollbackDataList(hRollbackFile, &prdSubscriptions); + ExitOnFailure(hr, "Failed to read subscription rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdRoleAssignments); + ExitOnFailure(hr, "Failed to read role assignments rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdAssemblies); + ExitOnFailure(hr, "Failed to read assemblies rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersApplicationRoles); + ExitOnFailure(hr, "Failed to read users in application roles rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdApplicationRoles); + ExitOnFailure(hr, "Failed to read application roles rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdApplications); + ExitOnFailure(hr, "Failed to read applications rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitionUsers); + ExitOnFailure(hr, "Failed to read partition users rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersInPartitionRoles); + ExitOnFailure(hr, "Failed to read users in partition roles rollback data"); + hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitions); + ExitOnFailure(hr, "Failed to read partitions rollback data"); + + ::CloseHandle(hRollbackFile); + hRollbackFile = INVALID_HANDLE_VALUE; + + // rollback remove partitions + hr = CpiRollbackConfigurePartitions(&pwzData, prdPartitions); + ExitOnFailure(hr, "Failed to rollback delete partitions"); + + // rollback remove users in partition roles + hr = CpiRollbackConfigureUsersInPartitionRoles(&pwzData, prdUsersInPartitionRoles); + ExitOnFailure(hr, "Failed to rollback delete users in partition roles"); + + // rollback remove partition users + hr = CpiRollbackConfigurePartitionUsers(&pwzData, prdPartitionUsers); + ExitOnFailure(hr, "Failed to rollback delete partition users"); + + // rollback remove applications + hr = CpiRollbackConfigureApplications(&pwzData, prdApplications); + ExitOnFailure(hr, "Failed to rollback delete applications"); + + // rollback remove application roles + hr = CpiRollbackConfigureApplicationRoles(&pwzData, prdApplicationRoles); + ExitOnFailure(hr, "Failed to rollback delete application roles"); + + // rollback remove users in application roles + hr = CpiRollbackConfigureUsersInApplicationRoles(&pwzData, prdUsersApplicationRoles); + ExitOnFailure(hr, "Failed to rollback delete users in application roles"); + + // rollback unregister assemblies + hr = CpiRollbackConfigureAssemblies(&pwzData, prdAssemblies); + ExitOnFailure(hr, "Failed to rollback unregister assemblies"); + + // rollback delete role assignments + hr = CpiRollbackConfigureRoleAssignments(&pwzData, prdAssemblies); + ExitOnFailure(hr, "Failed to rollback delete role assignments"); + + // rollback delete subscriptions + hr = CpiRollbackConfigureSubscriptions(&pwzData, prdSubscriptions); + ExitOnFailure(hr, "Failed to rollback delete subscriptions"); + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzRollbackFileName); + + if (INVALID_HANDLE_VALUE != hRollbackFile) + ::CloseHandle(hRollbackFile); + + if (prdPartitions) + CpiFreeRollbackDataList(prdPartitions); + if (prdUsersInPartitionRoles) + CpiFreeRollbackDataList(prdUsersInPartitionRoles); + if (prdPartitionUsers) + CpiFreeRollbackDataList(prdPartitionUsers); + if (prdApplications) + CpiFreeRollbackDataList(prdApplications); + if (prdApplicationRoles) + CpiFreeRollbackDataList(prdApplicationRoles); + if (prdUsersApplicationRoles) + CpiFreeRollbackDataList(prdUsersApplicationRoles); + if (prdAssemblies) + CpiFreeRollbackDataList(prdAssemblies); + if (prdRoleAssignments) + CpiFreeRollbackDataList(prdRoleAssignments); + if (prdSubscriptions) + CpiFreeRollbackDataList(prdSubscriptions); + + // unitialize + CpiFinalize(); + + if (fInitializedCom) + ::CoUninitialize(); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} diff --git a/src/ca/cpexec.def b/src/ca/cpexec.def new file mode 100644 index 00000000..1dad15c2 --- /dev/null +++ b/src/ca/cpexec.def @@ -0,0 +1,11 @@ +; Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +EXPORTS + ComPlusPrepare + ComPlusCleanup + ComPlusInstallExecute + ComPlusInstallExecuteCommit + ComPlusRollbackInstallExecute + ComPlusUninstallExecute + ComPlusRollbackUninstallExecute diff --git a/src/ca/cppartexec.cpp b/src/ca/cppartexec.cpp new file mode 100644 index 00000000..d8c30c6a --- /dev/null +++ b/src/ca/cppartexec.cpp @@ -0,0 +1,690 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// private structs + +struct CPI_PARTITION_ATTRIBUTES +{ + int iActionType; + int iActionCost; + LPWSTR pwzKey; + LPWSTR pwzID; + LPWSTR pwzName; + CPI_PROPERTY* pPropList; +}; + +struct CPI_PARTITION_USER_ATTRIBUTES +{ + int iActionType; + int iActionCost; + LPWSTR pwzKey; + LPWSTR pwzAccount; + LPWSTR pwzPartID; +}; + + +// prototypes for private helper functions + +static HRESULT ReadPartitionAttributes( + LPWSTR* ppwzData, + CPI_PARTITION_ATTRIBUTES* pAttrs + ); +static void FreePartitionAttributes( + CPI_PARTITION_ATTRIBUTES* pAttrs + ); +static HRESULT CreatePartition( + CPI_PARTITION_ATTRIBUTES* pAttrs + ); +static HRESULT RemovePartition( + CPI_PARTITION_ATTRIBUTES* pAttrs + ); +static HRESULT ReadPartitionUserAttributes( + LPWSTR* ppwzData, + CPI_PARTITION_USER_ATTRIBUTES* pAttrs + ); +static void FreePartitionUserAttributes( + CPI_PARTITION_USER_ATTRIBUTES* pAttrs + ); +static HRESULT CreatePartitionUser( + CPI_PARTITION_USER_ATTRIBUTES* pAttrs + ); +static HRESULT RemovePartitionUser( + CPI_PARTITION_USER_ATTRIBUTES* pAttrs + ); + + +// function definitions + +HRESULT CpiConfigurePartitions( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ) +{ + HRESULT hr = S_OK; + + CPI_PARTITION_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, FALSE); + ExitOnFailure(hr, "Failed to send action start message"); + + // ger partition count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // write count to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); + ExitOnFailure(hr, "Failed to write count to rollback file"); + + for (int i = 0; i < iCnt; i++) + { + // read partition attributes from CustomActionData + hr = ReadPartitionAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // write key to rollback file + hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); + ExitOnFailure(hr, "Failed to write key to rollback file"); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreatePartition(&attrs); + ExitOnFailure(hr, "Failed to create partition, key: %S", attrs.pwzKey); + break; + case atRemove: + hr = RemovePartition(&attrs); + ExitOnFailure(hr, "Failed to remove partition, key: %S", attrs.pwzKey); + break; + } + + // write completion status to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); + ExitOnFailure(hr, "Failed to write completion status to rollback file"); + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreePartitionAttributes(&attrs); + + return hr; +} + +HRESULT CpiRollbackConfigurePartitions( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ) +{ + HRESULT hr = S_OK; + + int iRollbackStatus; + + CPI_PARTITION_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCnt; i++) + { + // read partition attributes from CustomActionData + hr = ReadPartitionAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // rollback status + hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); + + if (S_FALSE == hr) + continue; // not found, nothing to rollback + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreatePartition(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to create partition, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + case atRemove: + hr = RemovePartition(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to remove partition, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + } + + // check rollback status + if (0 == iRollbackStatus) + continue; // operation did not complete, skip progress + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreePartitionAttributes(&attrs); + + return hr; +} + +HRESULT CpiConfigurePartitionUsers( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ) +{ + HRESULT hr = S_OK; + + CPI_PARTITION_USER_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, FALSE); + ExitOnFailure(hr, "Failed to send action start message"); + + // ger partition count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // write count to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); + ExitOnFailure(hr, "Failed to write count to rollback file"); + + for (int i = 0; i < iCnt; i++) + { + // read partition attributes from CustomActionData + hr = ReadPartitionUserAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzAccount); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // write key to rollback file + hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); + ExitOnFailure(hr, "Failed to write key to rollback file"); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreatePartitionUser(&attrs); + ExitOnFailure(hr, "Failed to create partition user, key: %S", attrs.pwzKey); + break; + case atRemove: + hr = RemovePartitionUser(&attrs); + ExitOnFailure(hr, "Failed to remove partition user, key: %S", attrs.pwzKey); + break; + } + + // write completion status to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); + ExitOnFailure(hr, "Failed to write completion status to rollback file"); + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreePartitionUserAttributes(&attrs); + + return hr; +} + +HRESULT CpiRollbackConfigurePartitionUsers( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ) +{ + HRESULT hr = S_OK; + + int iRollbackStatus; + + CPI_PARTITION_USER_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCnt; i++) + { + // read partition attributes from CustomActionData + hr = ReadPartitionUserAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // rollback status + hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); + + if (S_FALSE == hr) + continue; // not found, nothing to rollback + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzAccount); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreatePartitionUser(&attrs); + ExitOnFailure(hr, "Failed to create partition user, key: %S", attrs.pwzKey); + break; + case atRemove: + hr = RemovePartitionUser(&attrs); + ExitOnFailure(hr, "Failed to remove partition user, key: %S", attrs.pwzKey); + break; + } + + // check rollback status + if (0 == iRollbackStatus) + continue; // operation did not complete, skip progress + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreePartitionUserAttributes(&attrs); + + return hr; +} + + +// helper function definitions + +static HRESULT ReadPartitionAttributes( + LPWSTR* ppwzData, + CPI_PARTITION_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); + ExitOnFailure(hr, "Failed to read action type"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); + ExitOnFailure(hr, "Failed to read action cost"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); + ExitOnFailure(hr, "Failed to read key"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzID); + ExitOnFailure(hr, "Failed to read id"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName); + ExitOnFailure(hr, "Failed to read name"); + hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList); + ExitOnFailure(hr, "Failed to read properties"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreePartitionAttributes( + CPI_PARTITION_ATTRIBUTES* pAttrs + ) +{ + ReleaseStr(pAttrs->pwzKey); + ReleaseStr(pAttrs->pwzID); + ReleaseStr(pAttrs->pwzName); + + if (pAttrs->pPropList) + CpiFreePropertyList(pAttrs->pPropList); +} + +static HRESULT CreatePartition( + CPI_PARTITION_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piPartColl = NULL; + ICatalogObject* piPartObj = NULL; + + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Creating partition, key: %S", pAttrs->pwzKey); + + // get partitions collection + hr = CpiGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + + // check if partition exists + hr = CpiFindCollectionObjectByStringKey(piPartColl, pAttrs->pwzID, &piPartObj); + ExitOnFailure(hr, "Failed to find partition"); + + if (S_FALSE == hr) + { + // create partition + hr = CpiAddCollectionObject(piPartColl, &piPartObj); + ExitOnFailure(hr, "Failed to add partition to collection"); + + hr = CpiPutCollectionObjectValue(piPartObj, L"ID", pAttrs->pwzID); + ExitOnFailure(hr, "Failed to set partition id property"); + + hr = CpiPutCollectionObjectValue(piPartObj, L"Name", pAttrs->pwzName); + ExitOnFailure(hr, "Failed to set partition name property"); + } + + // properties + hr = CpiPutCollectionObjectValues(piPartObj, pAttrs->pPropList); + ExitOnFailure(hr, "Failed to write properties"); + + // save changes + hr = piPartColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piPartColl); + ReleaseObject(piPartObj); + + return hr; +} + +static HRESULT RemovePartition( + CPI_PARTITION_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piPartColl = NULL; + + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Removing partition, key: %S", pAttrs->pwzKey); + + // get partitions collection + hr = CpiGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + + // remove + hr = CpiRemoveCollectionObject(piPartColl, pAttrs->pwzID, NULL, TRUE); + ExitOnFailure(hr, "Failed to remove partition"); + + if (S_FALSE == hr) + { + // partition not found + WcaLog(LOGMSG_VERBOSE, "Partition not found, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // save changes + hr = piPartColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piPartColl); + + return hr; +} + +static HRESULT ReadPartitionUserAttributes( + LPWSTR* ppwzData, + CPI_PARTITION_USER_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); + ExitOnFailure(hr, "Failed to read action type"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); + ExitOnFailure(hr, "Failed to read action cost"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); + ExitOnFailure(hr, "Failed to read key"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount); + ExitOnFailure(hr, "Failed to read account name"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); + ExitOnFailure(hr, "Failed to read partition id"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreePartitionUserAttributes( + CPI_PARTITION_USER_ATTRIBUTES* pAttrs + ) +{ + ReleaseStr(pAttrs->pwzKey); + ReleaseStr(pAttrs->pwzAccount); + ReleaseStr(pAttrs->pwzPartID); +} + +static HRESULT CreatePartitionUser( + CPI_PARTITION_USER_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogCollection* piUserColl = NULL; + ICatalogObject* piUserObj = NULL; + + PSID pSid = NULL; + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Setting default partition for user, key: %S", pAttrs->pwzKey); + + // get partition users collection + hr = CpiGetPartitionUsersCollection(&piUserColl); + ExitOnFailure(hr, "Failed to get partition users collection"); + + // get SID for account + do { + er = ERROR_SUCCESS; + hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK)) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount); + er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + switch (er) + { + case IDABORT: + ExitFunction(); // exit with error code from CpiAccountNameToSid() + case IDRETRY: + break; + case IDIGNORE: + default: + ExitFunction1(hr = S_OK); + } + } + else + ExitOnFailure(hr, "Failed to get SID for account"); + } while (IDRETRY == er); + + // remove any existing entry + hr = CpiRemoveUserCollectionObject(piUserColl, pSid); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr); + hr = S_FALSE; + } + else + ExitOnFailure(hr, "Failed to remove user"); + + if (S_OK == hr) + WcaLog(LOGMSG_VERBOSE, "Existing default partition for user was removed, key: %S", pAttrs->pwzKey); + + // add partition user + hr = CpiAddCollectionObject(piUserColl, &piUserObj); + ExitOnFailure(hr, "Failed to add partition to collection"); + + hr = CpiPutCollectionObjectValue(piUserObj, L"AccountName", pAttrs->pwzAccount); + ExitOnFailure(hr, "Failed to set account name property"); + + hr = CpiPutCollectionObjectValue(piUserObj, L"DefaultPartitionID", pAttrs->pwzPartID); + ExitOnFailure(hr, "Failed to set default partition id property"); + + // save changes + hr = piUserColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piUserColl); + ReleaseObject(piUserObj); + + if (pSid) + ::HeapFree(::GetProcessHeap(), 0, pSid); + + return hr; +} + +static HRESULT RemovePartitionUser( + CPI_PARTITION_USER_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogCollection* piUserColl = NULL; + + PSID pSid = NULL; + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Removing default partition for user, key: %S", pAttrs->pwzKey); + + // get partition users collection + hr = CpiGetPartitionUsersCollection(&piUserColl); + ExitOnFailure(hr, "Failed to get partition users collection"); + + // get SID for account + do { + er = ERROR_SUCCESS; + hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK)) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount); + er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + switch (er) + { + case IDABORT: + ExitFunction(); // exit with error code from CpiAccountNameToSid() + case IDRETRY: + break; + case IDIGNORE: + default: + ExitFunction1(hr = S_OK); + } + } + else + ExitOnFailure(hr, "Failed to get SID for account"); + } while (IDRETRY == er); + + // remove + hr = CpiRemoveUserCollectionObject(piUserColl, pSid); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr); + hr = S_FALSE; + } + else + ExitOnFailure(hr, "Failed to remove user"); + + if (S_FALSE == hr) + { + // user not found + WcaLog(LOGMSG_VERBOSE, "Default partition for user not found, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // save changes + hr = piUserColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piUserColl); + + if (pSid) + ::HeapFree(::GetProcessHeap(), 0, pSid); + + return hr; +} diff --git a/src/ca/cppartexec.h b/src/ca/cppartexec.h new file mode 100644 index 00000000..132a9f5a --- /dev/null +++ b/src/ca/cppartexec.h @@ -0,0 +1,20 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +HRESULT CpiConfigurePartitions( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ); +HRESULT CpiRollbackConfigurePartitions( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ); +HRESULT CpiConfigurePartitionUsers( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ); +HRESULT CpiRollbackConfigurePartitionUsers( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ); diff --git a/src/ca/cppartroleexec.cpp b/src/ca/cppartroleexec.cpp new file mode 100644 index 00000000..4a503c79 --- /dev/null +++ b/src/ca/cppartroleexec.cpp @@ -0,0 +1,397 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// private structs + +struct CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES +{ + int iActionType; + int iActionCost; + LPWSTR pwzKey; + LPWSTR pwzRoleName; + LPWSTR pwzAccount; + LPWSTR pwzPartID; +}; + + +// prototypes for private helper functions + +static HRESULT ReadUserInPartitionRoleAttributes( + LPWSTR* ppwzData, + CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs + ); +static void FreeUserInPartitionRoleAttributes( + CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs + ); +static HRESULT CreateUserInPartitionRole( + CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs + ); +static HRESULT RemoveUserInPartitionRole( + CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs + ); + + +// function definitions + +HRESULT CpiConfigureUsersInPartitionRoles( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ) +{ + HRESULT hr = S_OK; + + CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, FALSE); + ExitOnFailure(hr, "Failed to send action start message"); + + // ger count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // write count to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); + ExitOnFailure(hr, "Failed to write count to rollback file"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadUserInPartitionRoleAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzRoleName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // write key to rollback file + hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); + ExitOnFailure(hr, "Failed to write key to rollback file"); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreateUserInPartitionRole(&attrs); + ExitOnFailure(hr, "Failed to add user to partition role, key: %S", attrs.pwzKey); + break; + case atRemove: + hr = RemoveUserInPartitionRole(&attrs); + ExitOnFailure(hr, "Failed to remove user from partition role, key: %S", attrs.pwzKey); + break; + } + + // write completion status to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); + ExitOnFailure(hr, "Failed to write completion status to rollback file"); + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeUserInPartitionRoleAttributes(&attrs); + + return hr; +} + +HRESULT CpiRollbackConfigureUsersInPartitionRoles( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ) +{ + HRESULT hr = S_OK; + + int iRollbackStatus; + + CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); + ExitOnFailure(hr, "Failed to send action start message"); + + // get count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadUserInPartitionRoleAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // rollback status + hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); + + if (S_FALSE == hr) + continue; // not found, nothing to rollback + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzRoleName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreateUserInPartitionRole(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to add user to partition role, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + case atRemove: + hr = RemoveUserInPartitionRole(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to remove user from partition role, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + } + + // check rollback status + if (0 == iRollbackStatus) + continue; // operation did not complete, skip progress + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeUserInPartitionRoleAttributes(&attrs); + + return hr; +} + + +// helper function definitions + +static HRESULT ReadUserInPartitionRoleAttributes( + LPWSTR* ppwzData, + CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); + ExitOnFailure(hr, "Failed to read action type"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); + ExitOnFailure(hr, "Failed to read action cost"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); + ExitOnFailure(hr, "Failed to read key"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzRoleName); + ExitOnFailure(hr, "Failed to read role name"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount); + ExitOnFailure(hr, "Failed to read account name"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); + ExitOnFailure(hr, "Failed to read partition id"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreeUserInPartitionRoleAttributes( + CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs + ) +{ + ReleaseStr(pAttrs->pwzKey); + ReleaseStr(pAttrs->pwzRoleName); + ReleaseStr(pAttrs->pwzAccount); + ReleaseStr(pAttrs->pwzPartID); +} + +static HRESULT CreateUserInPartitionRole( + CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogCollection* piUsrInRoleColl = NULL; + ICatalogObject* piUsrInRoleObj = NULL; + + PSID pSid = NULL; + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Adding user to partition role, key: %S", pAttrs->pwzKey); + + // get users in partition role collection + hr = CpiGetUsersInPartitionRoleCollection(pAttrs->pwzPartID, pAttrs->pwzRoleName, &piUsrInRoleColl); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to get users in partition role collection"); + + // get SID for account + do { + er = ERROR_SUCCESS; + hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK)) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount); + er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + switch (er) + { + case IDABORT: + ExitFunction(); // exit with error code from CpiAccountNameToSid() + case IDRETRY: + break; + case IDIGNORE: + default: + ExitFunction1(hr = S_OK); + } + } + else + ExitOnFailure(hr, "Failed to get SID for account"); + } while (IDRETRY == er); + + // find any existing entry + hr = CpiFindUserCollectionObject(piUsrInRoleColl, pSid, NULL); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr) + WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr); + else + ExitOnFailure(hr, "Failed to find user in partition role"); + + if (S_OK == hr) + { + WcaLog(LOGMSG_VERBOSE, "User already assigned to partition role, key: %S", pAttrs->pwzKey); + ExitFunction(); // exit with hr = S_OK + } + + // convert SID back to account name + hr = CpiSidToAccountName(pSid, &pAttrs->pwzAccount); + ExitOnFailure(hr, "Failed to convert SID to account name"); + + // add user + hr = CpiAddCollectionObject(piUsrInRoleColl, &piUsrInRoleObj); + ExitOnFailure(hr, "Failed to add user in role to collection"); + + hr = CpiPutCollectionObjectValue(piUsrInRoleObj, L"User", pAttrs->pwzAccount); + ExitOnFailure(hr, "Failed to set role name property"); + + // save changes + hr = piUsrInRoleColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piUsrInRoleColl); + ReleaseObject(piUsrInRoleObj); + + if (pSid) + ::HeapFree(::GetProcessHeap(), 0, pSid); + + return hr; +} + +static HRESULT RemoveUserInPartitionRole( + CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogCollection* piUsrInRoleColl = NULL; + + PSID pSid = NULL; + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Removing user from partition role, key: %S", pAttrs->pwzKey); + + // get users in partition role collection + hr = CpiGetUsersInPartitionRoleCollection(pAttrs->pwzPartID, pAttrs->pwzRoleName, &piUsrInRoleColl); + ExitOnFailure(hr, "Failed to get users in partition role collection"); + + if (S_FALSE == hr) + { + // users in role collection not found + WcaLog(LOGMSG_VERBOSE, "Unable to retrieve users in partition role collection, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // get SID for account + do { + er = ERROR_SUCCESS; + hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK)) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount); + er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + switch (er) + { + case IDABORT: + ExitFunction(); // exit with error code from CpiAccountNameToSid() + case IDRETRY: + break; + case IDIGNORE: + default: + ExitFunction1(hr = S_OK); + } + } + else + ExitOnFailure(hr, "Failed to get SID for account"); + } while (IDRETRY == er); + + // remove + hr = CpiRemoveUserCollectionObject(piUsrInRoleColl, pSid); + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr); + hr = S_FALSE; + } + else + ExitOnFailure(hr, "Failed to remove user"); + + if (S_FALSE == hr) + { + // role not found + WcaLog(LOGMSG_VERBOSE, "User not found for partition role, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // save changes + hr = piUsrInRoleColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piUsrInRoleColl); + + if (pSid) + ::HeapFree(::GetProcessHeap(), 0, pSid); + + return hr; +} diff --git a/src/ca/cppartroleexec.h b/src/ca/cppartroleexec.h new file mode 100644 index 00000000..0ec47dad --- /dev/null +++ b/src/ca/cppartroleexec.h @@ -0,0 +1,12 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +HRESULT CpiConfigureUsersInPartitionRoles( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ); +HRESULT CpiRollbackConfigureUsersInPartitionRoles( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ); diff --git a/src/ca/cppartrolesched.cpp b/src/ca/cppartrolesched.cpp new file mode 100644 index 00000000..a988f8e3 --- /dev/null +++ b/src/ca/cppartrolesched.cpp @@ -0,0 +1,421 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// sql queries + +LPCWSTR vcsPartitionRoleQuery = + L"SELECT `PartitionRole`, `Partition_`, `Component_`, `Name` FROM `ComPlusPartitionRole`"; +enum ePartitionRoleQuery { prqPartitionRole = 1, prqPartition, prqComponent, prqName }; + +LPCWSTR vcsUserInPartitionRoleQuery = + L"SELECT `UserInPartitionRole`, `PartitionRole_`, `ComPlusUserInPartitionRole`.`Component_`, `Domain`, `Name` FROM `ComPlusUserInPartitionRole`, `User` WHERE `User_` = `User`"; +LPCWSTR vcsGroupInPartitionRoleQuery = + L"SELECT `GroupInPartitionRole`, `PartitionRole_`, `ComPlusGroupInPartitionRole`.`Component_`, `Domain`, `Name` FROM `ComPlusGroupInPartitionRole`, `Group` WHERE `Group_` = `Group`"; +enum eTrusteeInPartitionRoleQuery { tiprqUserInPartitionRole = 1, tiprqPartitionRole, tiprqComponent, tiprqDomain, tiprqName }; + + +// prototypes for private helper functions + +static HRESULT TrusteesInPartitionRolesRead( + LPCWSTR pwzQuery, + CPI_PARTITION_ROLE_LIST* pPartRoleList, + CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList + ); +static void FreePartitionRole( + CPI_PARTITION_ROLE* pItm + ); +static void FreeUserInPartitionRole( + CPI_USER_IN_PARTITION_ROLE* pItm + ); +static HRESULT AddUserInPartitionRoleToActionData( + CPI_USER_IN_PARTITION_ROLE* pItm, + int iActionType, + int iActionCost, + LPWSTR* ppwzActionData + ); + + +// function definitions + +void CpiPartitionRoleListFree( + CPI_PARTITION_ROLE_LIST* pList + ) +{ + CPI_PARTITION_ROLE* pItm = pList->pFirst; + + while (pItm) + { + CPI_PARTITION_ROLE* pDelete = pItm; + pItm = pItm->pNext; + FreePartitionRole(pDelete); + } +} + +HRESULT CpiPartitionRolesRead( + CPI_PARTITION_LIST* pPartList, + CPI_PARTITION_ROLE_LIST* pPartRoleList + ) +{ + HRESULT hr = S_OK; + PMSIHANDLE hView, hRec; + CPI_PARTITION_ROLE* pItm = NULL; + LPWSTR pwzData = NULL; + + // loop through all application roles + hr = WcaOpenExecuteView(vcsPartitionRoleQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on ComPlusPartitionRole table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // create entry + pItm = (CPI_PARTITION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION_ROLE)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get key + hr = WcaGetRecordString(hRec, prqPartitionRole, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get partition + hr = WcaGetRecordString(hRec, prqPartition, &pwzData); + ExitOnFailure(hr, "Failed to get application"); + + hr = CpiPartitionFindByKey(pPartList, pwzData, &pItm->pPartition); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to find partition, key: %S", pwzData); + + // get name + hr = WcaGetRecordFormattedString(hRec, prqName, &pwzData); + ExitOnFailure(hr, "Failed to get name"); + StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); + + // add entry + if (pPartRoleList->pFirst) + pItm->pNext = pPartRoleList->pFirst; + pPartRoleList->pFirst = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + FreePartitionRole(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +HRESULT CpiPartitionRoleFindByKey( + CPI_PARTITION_ROLE_LIST* pList, + LPCWSTR pwzKey, + CPI_PARTITION_ROLE** ppPartRole + ) +{ + for (CPI_PARTITION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + if (0 == lstrcmpW(pItm->wzKey, pwzKey)) + { + *ppPartRole = pItm; + return S_OK; + } + } + + return E_FAIL; +} + +void CpiUserInPartitionRoleListFree( + CPI_USER_IN_PARTITION_ROLE_LIST* pList + ) +{ + CPI_USER_IN_PARTITION_ROLE* pItm = pList->pFirst; + + while (pItm) + { + CPI_USER_IN_PARTITION_ROLE* pDelete = pItm; + pItm = pItm->pNext; + FreeUserInPartitionRole(pDelete); + } +} + +HRESULT CpiUsersInPartitionRolesRead( + CPI_PARTITION_ROLE_LIST* pPartRoleList, + CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList + ) +{ + HRESULT hr = S_OK; + + // read users in partition roles + if (CpiTableExists(cptComPlusUserInPartitionRole)) + { + hr = TrusteesInPartitionRolesRead(vcsUserInPartitionRoleQuery, pPartRoleList, pUsrInPartRoleList); + ExitOnFailure(hr, "Failed to read users in partition roles"); + } + + // read groups in partition roles + if (CpiTableExists(cptComPlusGroupInPartitionRole)) + { + hr = TrusteesInPartitionRolesRead(vcsGroupInPartitionRoleQuery, pPartRoleList, pUsrInPartRoleList); + ExitOnFailure(hr, "Failed to read groups in partition roles"); + } + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiUsersInPartitionRolesInstall( + CPI_USER_IN_PARTITION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"AddUsersToComPlusPartitionRoles", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add count to action data + hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add roles to custom action data + for (CPI_USER_IN_PARTITION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // roles that are being installed only + if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + { + if (CpiIsInstalled(pItm->isInstalled)) + iActionType = atNoOp; + else + iActionType = atRemove; + } + else + iActionType = atCreate; + + // add to action data + hr = AddUserInPartitionRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_CREATE, ppwzActionData); + ExitOnFailure(hr, "Failed to add user in partition role to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_USER_IN_APPLICATION_ROLE_CREATE * pList->iInstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiUsersInPartitionRolesUninstall( + CPI_USER_IN_PARTITION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"RemoveUsersFromComPlusPartRoles", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add count to action data + hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add roles to custom action data + for (CPI_USER_IN_PARTITION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // roles that are being uninstalled only + if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + iActionType = atCreate; + else + iActionType = atRemove; + + // add to action data + hr = AddUserInPartitionRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_DELETE, ppwzActionData); + ExitOnFailure(hr, "Failed to add user in partition role to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_USER_IN_APPLICATION_ROLE_DELETE * pList->iUninstallCount; + + hr = S_OK; + +LExit: + return hr; +} + + +// helper function definitions + +static HRESULT TrusteesInPartitionRolesRead( + LPCWSTR pwzQuery, + CPI_PARTITION_ROLE_LIST* pPartRoleList, + CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + + CPI_USER_IN_PARTITION_ROLE* pItm = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzDomain = NULL; + LPWSTR pwzName = NULL; + BOOL fMatchingArchitecture = FALSE; + + // loop through all application roles + hr = WcaOpenExecuteView(pwzQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // get component + hr = WcaGetRecordString(hRec, tiprqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get component"); + + // check if the component is our processor architecture + hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); + ExitOnFailure(hr, "Failed to get component architecture."); + + if (!fMatchingArchitecture) + { + continue; // not the same architecture, ignore + } + + // create entry + pItm = (CPI_USER_IN_PARTITION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_USER_IN_PARTITION_ROLE)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get component install state + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); + + // get key + hr = WcaGetRecordString(hRec, tiprqUserInPartitionRole, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get partition role + hr = WcaGetRecordString(hRec, tiprqPartitionRole, &pwzData); + ExitOnFailure(hr, "Failed to get partition role"); + + hr = CpiPartitionRoleFindByKey(pPartRoleList, pwzData, &pItm->pPartitionRole); + ExitOnFailure(hr, "Failed to find partition role, key: %S", pwzData); + + // get user domain + hr = WcaGetRecordFormattedString(hRec, tiprqDomain, &pwzDomain); + ExitOnFailure(hr, "Failed to get domain"); + + // get user name + hr = WcaGetRecordFormattedString(hRec, tiprqName, &pwzName); + ExitOnFailure(hr, "Failed to get name"); + + // build account name + hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount); + ExitOnFailure(hr, "Failed to build account name"); + + // increment counters + if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + pUsrInPartRoleList->iInstallCount++; + if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + pUsrInPartRoleList->iUninstallCount++; + + // add entry + if (pUsrInPartRoleList->pFirst) + pItm->pNext = pUsrInPartRoleList->pFirst; + pUsrInPartRoleList->pFirst = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + FreeUserInPartitionRole(pItm); + + ReleaseStr(pwzData); + ReleaseStr(pwzDomain); + ReleaseStr(pwzName); + + return hr; +} + +static void FreePartitionRole( + CPI_PARTITION_ROLE* pItm + ) +{ + ::HeapFree(::GetProcessHeap(), 0, pItm); +} + +static void FreeUserInPartitionRole( + CPI_USER_IN_PARTITION_ROLE* pItm + ) +{ + ReleaseStr(pItm->pwzAccount); + + ::HeapFree(::GetProcessHeap(), 0, pItm); +} + +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; +} diff --git a/src/ca/cppartrolesched.h b/src/ca/cppartrolesched.h new file mode 100644 index 00000000..ff1275d9 --- /dev/null +++ b/src/ca/cppartrolesched.h @@ -0,0 +1,76 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +struct CPI_PARTITION_ROLE +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzName[MAX_DARWIN_COLUMN + 1]; + + CPI_PARTITION* pPartition; + + ICatalogCollection* piUsersColl; + + CPI_PARTITION_ROLE* pNext; +}; + +struct CPI_PARTITION_ROLE_LIST +{ + CPI_PARTITION_ROLE* pFirst; +}; + +struct CPI_USER_IN_PARTITION_ROLE +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + LPWSTR pwzAccount; + + INSTALLSTATE isInstalled, isAction; + + CPI_PARTITION_ROLE* pPartitionRole; + + CPI_USER_IN_PARTITION_ROLE* pNext; +}; + +struct CPI_USER_IN_PARTITION_ROLE_LIST +{ + CPI_USER_IN_PARTITION_ROLE* pFirst; + + int iInstallCount; + int iUninstallCount; +}; + + +// function prototypes + +void CpiPartitionRoleListFree( + CPI_PARTITION_ROLE_LIST* pList + ); +HRESULT CpiPartitionRolesRead( + CPI_PARTITION_LIST* pPartList, + CPI_PARTITION_ROLE_LIST* pPartRoleList + ); +HRESULT CpiPartitionRoleFindByKey( + CPI_PARTITION_ROLE_LIST* pList, + LPCWSTR pwzKey, + CPI_PARTITION_ROLE** ppPartRole + ); + +void CpiUserInPartitionRoleListFree( + CPI_USER_IN_PARTITION_ROLE_LIST* pList + ); +HRESULT CpiUsersInPartitionRolesRead( + CPI_PARTITION_ROLE_LIST* pPartRoleList, + CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList + ); +HRESULT CpiUsersInPartitionRolesInstall( + CPI_USER_IN_PARTITION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiUsersInPartitionRolesUninstall( + CPI_USER_IN_PARTITION_ROLE_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); diff --git a/src/ca/cppartsched.cpp b/src/ca/cppartsched.cpp new file mode 100644 index 00000000..6643a50b --- /dev/null +++ b/src/ca/cppartsched.cpp @@ -0,0 +1,912 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// sql queries + +LPCWSTR vcsPartitionQuery = + L"SELECT `Partition`, `Component_`, `Id`, `Name` FROM `ComPlusPartition`"; +enum ePartitionQuery { pqPartition = 1, pqComponent, pqID, pqName }; + +LPCWSTR vcsPartitionPropertyQuery = + L"SELECT `Name`, `Value` FROM `ComPlusPartitionProperty` WHERE `Partition_` = ?"; + +LPCWSTR vcsPartitionUserQuery = + L"SELECT `PartitionUser`, `Partition_`, `ComPlusPartitionUser`.`Component_`, `Domain`, `Name` FROM `ComPlusPartitionUser`, `User` WHERE `User_` = `User`"; +enum ePartitionUserQuery { puqPartitionUser = 1, puqPartition, puqComponent, puqDomain, puqName }; + + +// property definitions + +CPI_PROPERTY_DEFINITION pdlPartitionProperties[] = +{ + {L"Changeable", cpptBoolean, 502}, + {L"Deleteable", cpptBoolean, 502}, + {L"Description", cpptString, 502}, + {NULL, cpptNone, 0} +}; + + +// prototypes for private helper functions + +static void FreePartition( + CPI_PARTITION* pItm + ); +static void FreePartitionUser( + CPI_PARTITION_USER* pItm + ); +static HRESULT AddPartitionToActionData( + CPI_PARTITION* pItm, + int iActionType, + int iActionCost, + LPWSTR* ppwzActionData + ); +static HRESULT AddPartitionUserToActionData( + CPI_PARTITION_USER* pItm, + int iActionType, + int iActionCost, + LPWSTR* ppwzActionData + ); + + +// function definitions + +void CpiPartitionListFree( + CPI_PARTITION_LIST* pList + ) +{ + CPI_PARTITION* pItm = pList->pFirst; + + while (pItm) + { + CPI_PARTITION* pDelete = pItm; + pItm = pItm->pNext; + FreePartition(pDelete); + } +} + +HRESULT CpiPartitionsRead( + CPI_PARTITION_LIST* pPartList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + + CPI_PARTITION* pItm = NULL; + LPWSTR pwzData = NULL; + BOOL fMatchingArchitecture = FALSE; + + // loop through all partitions + hr = WcaOpenExecuteView(vcsPartitionQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on ComPlusPartition table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // get component + hr = WcaGetRecordString(hRec, pqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get component"); + + // check if the component is our processor architecture + if (pwzData && *pwzData) + { + hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); + ExitOnFailure(hr, "Failed to get component architecture."); + + if (!fMatchingArchitecture) + { + continue; // not the same architecture, ignore + } + } + + // create entry + pItm = (CPI_PARTITION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get component install state + if (pwzData && *pwzData) + { + pItm->fHasComponent = TRUE; + + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); + } + + // get key + hr = WcaGetRecordString(hRec, pqPartition, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get id + hr = WcaGetRecordFormattedString(hRec, pqID, &pwzData); + ExitOnFailure(hr, "Failed to get id"); + + if (pwzData && *pwzData) + { + hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData); + } + + // get name + hr = WcaGetRecordFormattedString(hRec, pqName, &pwzData); + ExitOnFailure(hr, "Failed to get name"); + StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); + + // if partition is a locater, either an id or a name must be provided + if (!pItm->fHasComponent && !*pItm->wzID && !*pItm->wzName) + ExitOnFailure(hr = E_FAIL, "A partition locater must have either an id or a name associated, key: %S", pItm->wzKey); + + // if partition is not a locater, an name must be provided + if (pItm->fHasComponent && !*pItm->wzName) + ExitOnFailure(hr = E_FAIL, "A partition must have a name associated, key: %S", pItm->wzKey); + + // get properties + if (CpiTableExists(cptComPlusPartitionProperty) && pItm->fHasComponent) + { + hr = CpiPropertiesRead(vcsPartitionPropertyQuery, pItm->wzKey, pdlPartitionProperties, &pItm->pProperties, &pItm->iPropertyCount); + ExitOnFailure(hr, "Failed to get properties"); + } + + // increment counters + if (pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + pPartList->iInstallCount++; + if (pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + pPartList->iUninstallCount++; + + // add entry + if (pPartList->pFirst) + pItm->pNext = pPartList->pFirst; + pPartList->pFirst = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + FreePartition(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +HRESULT CpiPartitionsVerifyInstall( + CPI_PARTITION_LIST* pList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogCollection* piPartColl = NULL; + ICatalogObject* piPartObj = NULL; + + for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // referenced locaters or partitions that are being installed + if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))) + continue; + + // if the partition is referensed and is not a locater, it must be installed + if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction)) + MessageExitOnFailure(hr = E_FAIL, msierrComPlusPartitionDependency, "A partition is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey); + + // get partitions collection + if (!piPartColl) + { + hr = CpiGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + } + + // partition is supposed to exist + if (!pItm->fHasComponent || CpiIsInstalled(pItm->isInstalled)) + { + // get collection object for partition + hr = CpiFindCollectionObject(piPartColl, pItm->wzID, *pItm->wzID ? NULL : pItm->wzName, &piPartObj); + ExitOnFailure(hr, "Failed to find collection object for partition"); + + // if the partition was found + if (S_OK == hr) + { + // if we don't have an id, copy id from object + if (!*pItm->wzID) + { + hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to get id"); + } + } + + // if the partition was not found + else + { + // if the application is a locater, this is an error + if (!pItm->fHasComponent) + MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusPartitionNotFound, "A partition required by this installation was not found, key: %S", pItm->wzKey); + + // create a new id if one is missing + if (!*pItm->wzID) + { + hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to create id"); + } + } + } + + // partition is supposed to be created + else + { + // check for conflicts + do { + if (*pItm->wzID) + { + // find partitions with conflicting id + hr = CpiFindCollectionObject(piPartColl, pItm->wzID, NULL, &piPartObj); + ExitOnFailure(hr, "Failed to find collection object for partition"); + + if (S_FALSE == hr) + { + // find partitions with conflicting name + hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj); + ExitOnFailure(hr, "Failed to find collection object for partition"); + + if (S_OK == hr) + // "A partition with a conflictiong name exists. retry cancel" + er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0); + else + break; // no conflicting entry found, break loop + } + else + // "A partition with a conflicting id exists. abort retry ignore" + er = WcaErrorMessage(msierrComPlusPartitionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + } + else + { + // find partitions with conflicting name + hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj); + ExitOnFailure(hr, "Failed to find collection object for partition"); + + if (S_OK == hr) + // "A partition with a conflictiong name exists. abort retry ignore" + er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + else + break; // no conflicting entry found, break loop + } + + switch (er) + { + case IDCANCEL: + case IDABORT: + ExitOnFailure(hr = E_FAIL, "A partition with a conflictiong name or id exists, key: %S", pItm->wzKey); + break; + case IDRETRY: + break; + case IDIGNORE: + default: + // if we don't have an id, copy id from object + if (!*pItm->wzID) + { + hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to get id"); + } + hr = S_FALSE; // indicate that this is not a conflict + } + } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts + + // create a new id if one is missing + if (!*pItm->wzID) + { + hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to create id"); + } + } + + // clean up + ReleaseNullObject(piPartObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piPartColl); + ReleaseObject(piPartObj); + + return hr; +} + +HRESULT CpiPartitionsVerifyUninstall( + CPI_PARTITION_LIST* pList + ) +{ + HRESULT hr = S_OK; + ICatalogCollection* piPartColl = NULL; + ICatalogObject* piPartObj = NULL; + + for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // referenced locaters or partitions that are being uninstalled + if (!pItm->fReferencedForUninstall && !(pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction))) + continue; + + // get partitions collection + if (!piPartColl) + { + hr = CpiGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + } + + // get collection object for partition + hr = CpiFindCollectionObject(piPartColl, pItm->wzID, *pItm->wzID ? NULL : pItm->wzName, &piPartObj); + ExitOnFailure(hr, "Failed to find collection object for partition"); + + // if the partition was found + if (S_OK == hr) + { + // if we don't have an id, copy id from object + if (!*pItm->wzID) + { + hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to get id"); + } + } + + // if the partition was not found + else + { + pItm->fObjectNotFound = TRUE; + if (pItm->fHasComponent) + pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall + } + + // clean up + ReleaseNullObject(piPartObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piPartColl); + ReleaseObject(piPartObj); + + return hr; +} + +void CpiPartitionAddReferenceInstall( + CPI_PARTITION* pItm + ) +{ + pItm->fReferencedForInstall = TRUE; +} + +void CpiPartitionAddReferenceUninstall( + CPI_PARTITION* pItm + ) +{ + pItm->fReferencedForUninstall = TRUE; +} + +HRESULT CpiPartitionsInstall( + CPI_PARTITION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"CreateComPlusPartitions", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add partition count to action data + hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add applications to custom action data + for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // partitions that are being installed only + if (!pItm->fHasComponent || !WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + { + if (CpiIsInstalled(pItm->isInstalled)) + iActionType = atNoOp; + else + iActionType = atRemove; + } + else + iActionType = atCreate; + + // add to action data + hr = AddPartitionToActionData(pItm, iActionType, COST_PARTITION_CREATE, ppwzActionData); + ExitOnFailure(hr, "Failed to add partition to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_PARTITION_CREATE * pList->iInstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiPartitionsUninstall( + CPI_PARTITION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"RemoveComPlusPartitions", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add partition count to action data + hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add partitions to custom action data + for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // partitions that are being uninstalled only + if (!pItm->fHasComponent || pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + iActionType = atCreate; + else + iActionType = atRemove; + + // add to action data + hr = AddPartitionToActionData(pItm, iActionType, COST_PARTITION_DELETE, ppwzActionData); + ExitOnFailure(hr, "Failed to add partition to custom action data, key:", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_PARTITION_DELETE * pList->iUninstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiPartitionFindByKey( + CPI_PARTITION_LIST* pList, + LPCWSTR wzKey, + CPI_PARTITION** ppItm + ) +{ + for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + if (0 == lstrcmpW(pItm->wzKey, wzKey)) + { + *ppItm = pItm; + return S_OK; + } + } + + return S_FALSE; +} + +HRESULT CpiGetApplicationsCollForPartition( + CPI_PARTITION* pPart, + ICatalogCollection** ppiAppColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piPartColl = NULL; + ICatalogObject* piPartObj = NULL; + + // if a previous attempt to locate the collection object failed + if (pPart->fObjectNotFound) + ExitFunction1(hr = S_FALSE); + + // get applications collection + if (!pPart->piApplicationsColl) + { + // get partitions collection from catalog + hr = CpiGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + + // find application object + hr = CpiFindCollectionObject(piPartColl, pPart->wzID, *pPart->wzID ? NULL : pPart->wzName, &piPartObj); + ExitOnFailure(hr, "Failed to find partition object"); + + if (S_FALSE == hr) + { + pPart->fObjectNotFound = TRUE; + ExitFunction(); // exit with hr = S_FALSE + } + + // get roles collection + hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"Applications", &pPart->piApplicationsColl); + ExitOnFailure(hr, "Failed to get applications collection"); + } + + // return value + *ppiAppColl = pPart->piApplicationsColl; + (*ppiAppColl)->AddRef(); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piPartColl); + ReleaseObject(piPartObj); + + return hr; +} + +HRESULT CpiGetRolesCollForPartition( + CPI_PARTITION* pPart, + ICatalogCollection** ppiRolesColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piPartColl = NULL; + ICatalogObject* piPartObj = NULL; + + // if a previous attempt to locate the collection object failed + if (pPart->fObjectNotFound) + ExitFunction1(hr = S_FALSE); + + // get applications collection + if (!pPart->piRolesColl) + { + // get partitions collection from catalog + hr = CpiGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + + // find partition object + hr = CpiFindCollectionObject(piPartColl, pPart->wzID, *pPart->wzID ? NULL : pPart->wzName, &piPartObj); + ExitOnFailure(hr, "Failed to find partition object"); + + if (S_FALSE == hr) + ExitFunction(); // exit with hr = S_FALSE + + // get roles collection + hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", &pPart->piRolesColl); + ExitOnFailure(hr, "Failed to get roles collection"); + } + + // return value + *ppiRolesColl = pPart->piRolesColl; + (*ppiRolesColl)->AddRef(); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piPartColl); + ReleaseObject(piPartObj); + + return hr; +} + +void CpiPartitionUserListFree( + CPI_PARTITION_USER_LIST* pList + ) +{ + CPI_PARTITION_USER* pItm = pList->pFirst; + + while (pItm) + { + CPI_PARTITION_USER* pDelete = pItm; + pItm = pItm->pNext; + FreePartitionUser(pDelete); + } +} + +HRESULT CpiPartitionUsersRead( + CPI_PARTITION_LIST* pPartList, + CPI_PARTITION_USER_LIST* pPartUsrList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + + CPI_PARTITION_USER* pItm = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzDomain = NULL; + LPWSTR pwzName = NULL; + BOOL fMatchingArchitecture = FALSE; + + // loop through all partition users + hr = WcaOpenExecuteView(vcsPartitionUserQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on ComPlusPartitionUser table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // get component + hr = WcaGetRecordString(hRec, puqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get component"); + + // check if the component is our processor architecture + hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); + ExitOnFailure(hr, "Failed to get component architecture."); + + if (!fMatchingArchitecture) + { + continue; // not the same architecture, ignore + } + + // create entry + pItm = (CPI_PARTITION_USER*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION_USER)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get component install state + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); + + // get key + hr = WcaGetRecordString(hRec, puqPartitionUser, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get partition + hr = WcaGetRecordString(hRec, puqPartition, &pwzData); + ExitOnFailure(hr, "Failed to get partition"); + + hr = CpiPartitionFindByKey(pPartList, pwzData, &pItm->pPartition); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to find partition, key: %S", pwzData); + + // get user domain + hr = WcaGetRecordFormattedString(hRec, puqDomain, &pwzDomain); + ExitOnFailure(hr, "Failed to get user domain"); + + // get user name + hr = WcaGetRecordFormattedString(hRec, puqName, &pwzName); + ExitOnFailure(hr, "Failed to get user name"); + + // build account name + hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount); + ExitOnFailure(hr, "Failed to build account name"); + + // set references & increment counters + if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + { + pItm->pPartition->fReferencedForInstall = TRUE; + pPartUsrList->iInstallCount++; + } + if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + { + pItm->pPartition->fReferencedForUninstall = TRUE; + pPartUsrList->iUninstallCount++; + } + + // add entry + if (pPartUsrList->pFirst) + pItm->pNext = pPartUsrList->pFirst; + pPartUsrList->pFirst = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + FreePartitionUser(pItm); + + ReleaseStr(pwzData); + ReleaseStr(pwzDomain); + ReleaseStr(pwzName); + + return hr; +} + +HRESULT CpiPartitionUsersInstall( + CPI_PARTITION_USER_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"AddComPlusPartitionUsers", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add partition count to action data + hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add applications to custom action data + for (CPI_PARTITION_USER* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // partitions that are being installed only + if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + { + if (CpiIsInstalled(pItm->isInstalled)) + iActionType = atNoOp; + else + iActionType = atRemove; + } + else + iActionType = atCreate; + + // add to action data + hr = AddPartitionUserToActionData(pItm, iActionType, COST_PARTITION_USER_CREATE, ppwzActionData); + ExitOnFailure(hr, "Failed to add partition user to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_PARTITION_USER_CREATE * pList->iInstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiPartitionUsersUninstall( + CPI_PARTITION_USER_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"RemoveComPlusPartitionUsers", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add partition count to action data + hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add partitions to custom action data + for (CPI_PARTITION_USER* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // partitions that are being uninstalled only + if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + iActionType = atCreate; + else + iActionType = atRemove; + + // add to action data + hr = AddPartitionUserToActionData(pItm, iActionType, COST_PARTITION_USER_DELETE, ppwzActionData); + ExitOnFailure(hr, "Failed to add partition user to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_PARTITION_USER_DELETE * pList->iUninstallCount; + + hr = S_OK; + +LExit: + return hr; +} + + +// helper function definitions + +static void FreePartition( + CPI_PARTITION* pItm + ) +{ + if (pItm->pProperties) + CpiPropertiesFreeList(pItm->pProperties); + + ReleaseObject(pItm->piApplicationsColl); + ReleaseObject(pItm->piRolesColl); + + ::HeapFree(::GetProcessHeap(), 0, pItm); +} + +static void FreePartitionUser( + CPI_PARTITION_USER* pItm + ) +{ + ReleaseStr(pItm->pwzAccount); + + ::HeapFree(::GetProcessHeap(), 0, pItm); +} + +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; +} + +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; +} diff --git a/src/ca/cppartsched.h b/src/ca/cppartsched.h new file mode 100644 index 00000000..55085912 --- /dev/null +++ b/src/ca/cppartsched.h @@ -0,0 +1,125 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +struct CPI_PARTITION +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzID[CPI_MAX_GUID + 1]; + WCHAR wzName[MAX_DARWIN_COLUMN + 1]; + + int iPropertyCount; + CPI_PROPERTY* pProperties; + + BOOL fHasComponent; + BOOL fReferencedForInstall; + BOOL fReferencedForUninstall; + BOOL fObjectNotFound; + + INSTALLSTATE isInstalled, isAction; + + ICatalogCollection* piApplicationsColl; + ICatalogCollection* piRolesColl; + + CPI_PARTITION* pNext; +}; + +struct CPI_PARTITION_LIST +{ + CPI_PARTITION* pFirst; + + int iInstallCount; + int iUninstallCount; +}; + +struct CPI_PARTITION_USER +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + LPWSTR pwzAccount; + + BOOL fNoFind; + + INSTALLSTATE isInstalled, isAction; + + CPI_PARTITION* pPartition; + + CPI_PARTITION_USER* pNext; +}; + +struct CPI_PARTITION_USER_LIST +{ + CPI_PARTITION_USER* pFirst; + + int iInstallCount; + int iUninstallCount; +}; + + +// function prototypes + +void CpiPartitionListFree( + CPI_PARTITION_LIST* pList + ); +HRESULT CpiPartitionsRead( + CPI_PARTITION_LIST* pPartList + ); +HRESULT CpiPartitionsVerifyInstall( + CPI_PARTITION_LIST* pList + ); +HRESULT CpiPartitionsVerifyUninstall( + CPI_PARTITION_LIST* pList + ); +void CpiPartitionAddReferenceInstall( + CPI_PARTITION* pItm + ); +void CpiPartitionAddReferenceUninstall( + CPI_PARTITION* pItm + ); +HRESULT CpiPartitionsInstall( + CPI_PARTITION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiPartitionsUninstall( + CPI_PARTITION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiPartitionFindByKey( + CPI_PARTITION_LIST* pList, + LPCWSTR wzKey, + CPI_PARTITION** ppItm + ); +HRESULT CpiGetApplicationsCollForPartition( + CPI_PARTITION* pPart, + ICatalogCollection** ppiAppColl + ); +HRESULT CpiGetPartitionUsersCollection( + CPI_PARTITION* pPart, + ICatalogCollection** ppiPartUsrColl + ); +HRESULT CpiGetRolesCollForPartition( + CPI_PARTITION* pPart, + ICatalogCollection** ppiRolesColl + ); +void CpiPartitionUserListFree( + CPI_PARTITION_USER_LIST* pList + ); +HRESULT CpiPartitionUsersRead( + CPI_PARTITION_LIST* pPartList, + CPI_PARTITION_USER_LIST* pPartUsrList + ); +HRESULT CpiPartitionUsersInstall( + CPI_PARTITION_USER_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiPartitionUsersUninstall( + CPI_PARTITION_USER_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); diff --git a/src/ca/cpsched.cpp b/src/ca/cpsched.cpp new file mode 100644 index 00000000..ac0dda59 --- /dev/null +++ b/src/ca/cpsched.cpp @@ -0,0 +1,590 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +#ifdef _WIN64 +#define CP_COMPLUSROLLBACKINSTALLPREPARE L"ComPlusRollbackInstallPrepare_64" +#define CP_COMPLUSINSTALLPREPARE L"ComPlusInstallPrepare_64" +#define CP_COMPLUSROLLBACKINSTALLEXECUTE L"ComPlusRollbackInstallExecute_64" +#define CP_COMPLUSINSTALLEXECUTE L"ComPlusInstallExecute_64" +#define CP_COMPLUSINSTALLEXECUTECOMMIT L"ComPlusInstallExecuteCommit_64" +#define CP_COMPLUSINSTALLCOMMIT L"ComPlusInstallCommit_64" +#define CP_COMPLUSROLLBACKINSTALLPREPARE L"ComPlusRollbackInstallPrepare_64" +#define CP_COMPLUSINSTALLPREPARE L"ComPlusInstallPrepare_64" +#define CP_COMPLUSROLLBACKUNINSTALLEXECUTE L"ComPlusRollbackUninstallExecute_64" +#define CP_COMPLUSUNINSTALLEXECUTE L"ComPlusUninstallExecute_64" +#define CP_COMPLUSINSTALLCOMMIT L"ComPlusInstallCommit_64" +#else +#define CP_COMPLUSROLLBACKINSTALLPREPARE L"ComPlusRollbackInstallPrepare" +#define CP_COMPLUSINSTALLPREPARE L"ComPlusInstallPrepare" +#define CP_COMPLUSROLLBACKINSTALLEXECUTE L"ComPlusRollbackInstallExecute" +#define CP_COMPLUSINSTALLEXECUTE L"ComPlusInstallExecute" +#define CP_COMPLUSINSTALLEXECUTECOMMIT L"ComPlusInstallExecuteCommit" +#define CP_COMPLUSINSTALLCOMMIT L"ComPlusInstallCommit" +#define CP_COMPLUSROLLBACKINSTALLPREPARE L"ComPlusRollbackInstallPrepare" +#define CP_COMPLUSINSTALLPREPARE L"ComPlusInstallPrepare" +#define CP_COMPLUSROLLBACKUNINSTALLEXECUTE L"ComPlusRollbackUninstallExecute" +#define CP_COMPLUSUNINSTALLEXECUTE L"ComPlusUninstallExecute" +#define CP_COMPLUSINSTALLCOMMIT L"ComPlusInstallCommit" +#endif + + +/******************************************************************** + DllMain - standard entry point for all WiX CustomActions + +********************************************************************/ +extern "C" BOOL WINAPI DllMain( + IN HINSTANCE hInst, + IN ULONG ulReason, + IN LPVOID) +{ + switch(ulReason) + { + case DLL_PROCESS_ATTACH: + WcaGlobalInitialize(hInst); + break; + + case DLL_PROCESS_DETACH: + WcaGlobalFinalize(); + break; + } + + return TRUE; +} + +/******************************************************************** + 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); +} + + +/******************************************************************** + ConfigureComPlusUninstall - CUSTOM ACTION ENTRY POINT for uninstalling COM+ components + +********************************************************************/ +extern "C" UINT __stdcall ConfigureComPlusUninstall(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; + + int iVersionNT = 0; + int iProgress = 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, "ConfigureComPlusUninstall"); + 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 uninstall 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 = CpiPartitionsVerifyUninstall(&partList); + ExitOnFailure(hr, "Failed to verify partitions"); + + hr = CpiApplicationsVerifyUninstall(&appList); + ExitOnFailure(hr, "Failed to verify applications"); + + hr = CpiApplicationRolesVerifyUninstall(&appRoleList); + ExitOnFailure(hr, "Failed to verify application roles"); + + hr = CpiAssembliesVerifyUninstall(&asmList); + ExitOnFailure(hr, "Failed to verify assemblies"); + + if (subList.iUninstallCount) + { + hr = CpiSubscriptionsVerifyUninstall(&subList); + ExitOnFailure(hr, "Failed to verify subscriptions"); + } + + // schedule + if (partList.iUninstallCount || appList.iUninstallCount || appRoleList.iUninstallCount || + usrInAppRoleList.iUninstallCount || asmList.iUninstallCount || asmList.iRoleUninstallCount || subList.iUninstallCount) + { + // 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 = CpiPartitionsUninstall(&partList, rmRollback, &pwzRollbackActionData, NULL); + ExitOnFailure(hr, "Failed to uninstall partitions"); + hr = CpiUsersInPartitionRolesUninstall(&usrInPartRoleList, rmRollback, &pwzRollbackActionData, NULL); + ExitOnFailure(hr, "Failed to uninstall users in partition roles"); + hr = CpiPartitionUsersUninstall(&partUsrList, rmRollback, &pwzRollbackActionData, NULL); + ExitOnFailure(hr, "Failed to uninstall partition users"); + hr = CpiApplicationsUninstall(&appList, rmRollback, &pwzRollbackActionData, NULL); + ExitOnFailure(hr, "Failed to uninstall applications"); + hr = CpiApplicationRolesUninstall(&appRoleList, rmRollback, &pwzRollbackActionData, NULL); + ExitOnFailure(hr, "Failed to uninstall application roles"); + hr = CpiUsersInApplicationRolesUninstall(&usrInAppRoleList, rmRollback, &pwzRollbackActionData, NULL); + ExitOnFailure(hr, "Failed to uninstall users in application roles"); + hr = CpiAssembliesUninstall(&asmList, rmRollback, &pwzRollbackActionData, NULL); + ExitOnFailure(hr, "Failed to uninstall assemblies"); + hr = CpiRoleAssignmentsUninstall(&asmList, rmRollback, &pwzRollbackActionData, NULL); + ExitOnFailure(hr, "Failed to uninstall assemblies"); + hr = CpiSubscriptionsUninstall(&subList, rmRollback, &pwzRollbackActionData, NULL); + ExitOnFailure(hr, "Failed to uninstall subscriptions"); + + hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKUNINSTALLEXECUTE, pwzRollbackActionData, 0); + ExitOnFailure(hr, "Failed to schedule ComPlusRollbackUninstallExecute"); + + // schedule install custom action + hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzActionData); + ExitOnFailure(hr, "Failed to add rollback file name to custom action data"); + + hr = CpiSubscriptionsUninstall(&subList, rmDeferred, &pwzActionData, &iProgress); + ExitOnFailure(hr, "Failed to uninstall subscriptions"); + hr = CpiRoleAssignmentsUninstall(&asmList, rmDeferred, &pwzActionData, &iProgress); + ExitOnFailure(hr, "Failed to uninstall assemblies"); + hr = CpiAssembliesUninstall(&asmList, rmDeferred, &pwzActionData, &iProgress); + ExitOnFailure(hr, "Failed to uninstall assemblies"); + hr = CpiUsersInApplicationRolesUninstall(&usrInAppRoleList, rmDeferred, &pwzActionData, &iProgress); + ExitOnFailure(hr, "Failed to uninstall users in application roles"); + hr = CpiApplicationRolesUninstall(&appRoleList, rmDeferred, &pwzActionData, &iProgress); + ExitOnFailure(hr, "Failed to uninstall application roles"); + hr = CpiApplicationsUninstall(&appList, rmDeferred, &pwzActionData, &iProgress); + ExitOnFailure(hr, "Failed to uninstall applications"); + hr = CpiPartitionUsersUninstall(&partUsrList, rmDeferred, &pwzActionData, &iProgress); + ExitOnFailure(hr, "Failed to uninstall partition users"); + hr = CpiUsersInPartitionRolesUninstall(&usrInPartRoleList, rmDeferred, &pwzActionData, &iProgress); + ExitOnFailure(hr, "Failed to uninstall users in partition roles"); + hr = CpiPartitionsUninstall(&partList, rmDeferred, &pwzActionData, &iProgress); + ExitOnFailure(hr, "Failed to uninstall partitions"); + + hr = WcaDoDeferredAction(CP_COMPLUSUNINSTALLEXECUTE, pwzActionData, iProgress); + ExitOnFailure(hr, "Failed to schedule ComPlusUninstallExecute"); + + // 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); + + 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); +} diff --git a/src/ca/cpsubsexec.cpp b/src/ca/cpsubsexec.cpp new file mode 100644 index 00000000..bbcf9853 --- /dev/null +++ b/src/ca/cpsubsexec.cpp @@ -0,0 +1,411 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// private structs + +struct CPI_SUBSCRIPTION_ATTRIBUTES +{ + int iActionType; + int iActionCost; + LPWSTR pwzKey; + LPWSTR pwzID; + LPWSTR pwzName; + LPWSTR pwzEventCLSID; + LPWSTR pwzPublisherID; + LPWSTR pwzCompCLSID; + LPWSTR pwzAppID; + LPWSTR pwzPartID; + CPI_PROPERTY* pPropList; +}; + + +// prototypes for private helper functions + +static HRESULT ReadSubscriptionAttributes( + LPWSTR* ppwzData, + CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs + ); +static void FreeSubscriptionAttributes( + CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs + ); +static HRESULT CreateSubscription( + CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs + ); +static HRESULT RemoveSubscription( + CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs + ); + + +// function definitions + +HRESULT CpiConfigureSubscriptions( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ) +{ + HRESULT hr = S_OK; + + CPI_SUBSCRIPTION_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, FALSE); + ExitOnFailure(hr, "Failed to send action start message"); + + // ger count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + // write count to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); + ExitOnFailure(hr, "Failed to write count to rollback file"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadSubscriptionAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // write key to rollback file + hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); + ExitOnFailure(hr, "Failed to write key to rollback file"); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreateSubscription(&attrs); + ExitOnFailure(hr, "Failed to create subscription, key: %S", attrs.pwzKey); + break; + case atRemove: + hr = RemoveSubscription(&attrs); + ExitOnFailure(hr, "Failed to remove subscription, key: %S", attrs.pwzKey); + break; + } + + // write completion status to rollback file + hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); + ExitOnFailure(hr, "Failed to write completion status to rollback file"); + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeSubscriptionAttributes(&attrs); + + return hr; +} + +HRESULT CpiRollbackConfigureSubscriptions( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ) +{ + HRESULT hr = S_OK; + + int iRollbackStatus; + + CPI_SUBSCRIPTION_ATTRIBUTES attrs; + ::ZeroMemory(&attrs, sizeof(attrs)); + + // read action text + hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); + ExitOnFailure(hr, "Failed to send action start message"); + + // ger count + int iCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCnt; i++) + { + // read attributes from CustomActionData + hr = ReadSubscriptionAttributes(ppwzData, &attrs); + ExitOnFailure(hr, "Failed to read attributes"); + + // rollback status + hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); + + if (S_FALSE == hr) + continue; // not found, nothing to rollback + + // progress message + hr = CpiActionDataMessage(1, attrs.pwzName); + ExitOnFailure(hr, "Failed to send progress messages"); + + if (S_FALSE == hr) + ExitFunction(); + + // action + switch (attrs.iActionType) + { + case atCreate: + hr = CreateSubscription(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to create subscription, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + case atRemove: + hr = RemoveSubscription(&attrs); + if (FAILED(hr)) + WcaLog(LOGMSG_STANDARD, "Failed to remove subscription, hr: 0x%x, key: %S", hr, attrs.pwzKey); + break; + } + + // check rollback status + if (0 == iRollbackStatus) + continue; // operation did not complete, skip progress + + // progress + hr = WcaProgressMessage(attrs.iActionCost, FALSE); + ExitOnFailure(hr, "Failed to update progress"); + } + + hr = S_OK; + +LExit: + // clean up + FreeSubscriptionAttributes(&attrs); + + return hr; +} + + +// helper function definitions + +static HRESULT ReadSubscriptionAttributes( + LPWSTR* ppwzData, + CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); + ExitOnFailure(hr, "Failed to read action type"); + hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); + ExitOnFailure(hr, "Failed to read action cost"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); + ExitOnFailure(hr, "Failed to read key"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzID); + ExitOnFailure(hr, "Failed to read id"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName); + ExitOnFailure(hr, "Failed to read name"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzEventCLSID); + ExitOnFailure(hr, "Failed to read event clsid"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPublisherID); + ExitOnFailure(hr, "Failed to read publisher id"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzCompCLSID); + ExitOnFailure(hr, "Failed to read component clsid"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID); + ExitOnFailure(hr, "Failed to read application id"); + hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); + ExitOnFailure(hr, "Failed to read partition id"); + + hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList); + ExitOnFailure(hr, "Failed to read properties"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreeSubscriptionAttributes( + CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs + ) +{ + ReleaseStr(pAttrs->pwzKey); + ReleaseStr(pAttrs->pwzID); + ReleaseStr(pAttrs->pwzName); + ReleaseStr(pAttrs->pwzEventCLSID); + ReleaseStr(pAttrs->pwzPublisherID); + ReleaseStr(pAttrs->pwzCompCLSID); + ReleaseStr(pAttrs->pwzAppID); + ReleaseStr(pAttrs->pwzPartID); + + if (pAttrs->pPropList) + CpiFreePropertyList(pAttrs->pPropList); +} + +static HRESULT CreateSubscription( + CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogCollection* piSubsColl = NULL; + ICatalogObject* piSubsObj = NULL; + + PSID pSid = NULL; + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Creating subscription, key: %S", pAttrs->pwzKey); + + // get subscriptions collection + hr = CpiGetSubscriptionsCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzCompCLSID, &piSubsColl); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + ExitOnFailure(hr, "Failed to get subscriptions collection"); + + // check if subscription exists + hr = CpiFindCollectionObjectByStringKey(piSubsColl, pAttrs->pwzID, &piSubsObj); + ExitOnFailure(hr, "Failed to find subscription"); + + if (S_FALSE == hr) + { + // create subscription + hr = CpiAddCollectionObject(piSubsColl, &piSubsObj); + ExitOnFailure(hr, "Failed to add subscription to collection"); + + hr = CpiPutCollectionObjectValue(piSubsObj, L"ID", pAttrs->pwzID); + ExitOnFailure(hr, "Failed to set subscription id property"); + + hr = CpiPutCollectionObjectValue(piSubsObj, L"Name", pAttrs->pwzName); + ExitOnFailure(hr, "Failed to set subscription name property"); + + if (pAttrs->pwzEventCLSID && *pAttrs->pwzEventCLSID) + { + hr = CpiPutCollectionObjectValue(piSubsObj, L"EventCLSID", pAttrs->pwzEventCLSID); + ExitOnFailure(hr, "Failed to set role event clsid property"); + } + + if (pAttrs->pwzPublisherID && *pAttrs->pwzPublisherID) + { + hr = CpiPutCollectionObjectValue(piSubsObj, L"PublisherID", pAttrs->pwzPublisherID); + ExitOnFailure(hr, "Failed to set role publisher id property"); + } + } + + // properties + for (CPI_PROPERTY* pItm = pAttrs->pPropList; pItm; pItm = pItm->pNext) + { + // UserName property + if (0 == lstrcmpW(pItm->wzName, L"UserName")) + { + // get SID for account + do { + er = ERROR_SUCCESS; + hr = CpiAccountNameToSid(pItm->pwzValue, &pSid); + if (!::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK)) + { + if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr) + { + WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pItm->pwzValue); + er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + switch (er) + { + case IDABORT: + ExitFunction(); // exit with error code from CpiAccountNameToSid() + case IDRETRY: + break; + case IDIGNORE: + default: + hr = S_FALSE; + } + } + else + ExitOnFailure(hr, "Failed to get SID for account, account: '%S'", pItm->pwzValue); + } + else if (FAILED(hr)) + { + WcaLog(LOGMSG_STANDARD, "Failed to get SID for account, hr: 0x%x, account: '%S'", hr, pItm->pwzValue); + hr = S_FALSE; + } + } while (IDRETRY == er); + + if (S_FALSE == hr) + continue; + + // convert SID back to account name + hr = CpiSidToAccountName(pSid, &pItm->pwzValue); + ExitOnFailure(hr, "Failed to convert SID to account name"); + } + + // set property + hr = CpiPutCollectionObjectValue(piSubsObj, pItm->wzName, pItm->pwzValue); + ExitOnFailure(hr, "Failed to set object property value, name: %S", pItm->wzName); + } + + // save changes + hr = piSubsColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piSubsColl); + ReleaseObject(piSubsObj); + + if (pSid) + ::HeapFree(::GetProcessHeap(), 0, pSid); + + return hr; +} + +static HRESULT RemoveSubscription( + CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piSubsColl = NULL; + + long lChanges = 0; + + // log + WcaLog(LOGMSG_VERBOSE, "Removing subscription, key: %S", pAttrs->pwzKey); + + // get subscriptions collection + hr = CpiGetSubscriptionsCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzCompCLSID, &piSubsColl); + ExitOnFailure(hr, "Failed to get subscriptions collection"); + + if (S_FALSE == hr) + { + // subscription not found + WcaLog(LOGMSG_VERBOSE, "Unable to retrieve subscriptions collection, nothing to delete, key: %S", pAttrs->pwzKey); + ExitFunction1(hr = S_OK); + } + + // remove + hr = CpiRemoveCollectionObject(piSubsColl, pAttrs->pwzID, NULL, FALSE); + ExitOnFailure(hr, "Failed to remove subscriptions"); + + // save changes + hr = piSubsColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + + // log + WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piSubsColl); + + return hr; +} diff --git a/src/ca/cpsubsexec.h b/src/ca/cpsubsexec.h new file mode 100644 index 00000000..2f4d3c75 --- /dev/null +++ b/src/ca/cpsubsexec.h @@ -0,0 +1,12 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +HRESULT CpiConfigureSubscriptions( + LPWSTR* ppwzData, + HANDLE hRollbackFile + ); +HRESULT CpiRollbackConfigureSubscriptions( + LPWSTR* ppwzData, + CPI_ROLLBACK_DATA* pRollbackDataList + ); diff --git a/src/ca/cpsubssched.cpp b/src/ca/cpsubssched.cpp new file mode 100644 index 00000000..73fd4f6d --- /dev/null +++ b/src/ca/cpsubssched.cpp @@ -0,0 +1,606 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// sql queries + +LPCWSTR vcsSubscriptionQuery = + L"SELECT `Subscription`, `ComPlusComponent_`, `Component_`, `Id`, `Name`, `EventCLSID`, `PublisherID` FROM `ComPlusSubscription`"; +enum eSubscriptionQuery { sqSubscription = 1, sqComPlusComponent, sqComponent, sqID, sqName, sqEventCLSID, sqPublisherID }; + +LPCWSTR vcsSubscriptionPropertyQuery = + L"SELECT `Name`, `Value` FROM `ComPlusSubscriptionProperty` WHERE `Subscription_` = ?"; + + +// property definitions + +CPI_PROPERTY_DEFINITION pdlSubscriptionProperties[] = +{ + {L"Description", cpptString, 500}, + {L"Enabled", cpptBoolean, 500}, + {L"EventClassPartitionID", cpptString, 502}, + {L"FilterCriteria", cpptString, 500}, + {L"InterfaceID", cpptString, 500}, + {L"MachineName", cpptString, 500}, + {L"MethodName", cpptString, 500}, + {L"PerUser", cpptBoolean, 500}, + {L"Queued", cpptBoolean, 500}, + {L"SubscriberMoniker", cpptString, 500}, + {L"UserName", cpptUser, 500}, + {NULL, cpptNone, 0} +}; + + +// prototypes for private helper functions + +static void FreeSubscription( + CPI_SUBSCRIPTION* pItm + ); +static HRESULT FindObjectForSubscription( + CPI_SUBSCRIPTION* pItm, + BOOL fFindId, + BOOL fFindName, + ICatalogObject** ppiSubsObj + ); +static HRESULT AddSubscriptionToActionData( + CPI_SUBSCRIPTION* pItm, + int iActionType, + int iActionCost, + LPWSTR* ppwzActionData + ); +static HRESULT ComponentFindByKey( + CPI_ASSEMBLY_LIST* pAsmList, + LPCWSTR pwzKey, + CPI_ASSEMBLY** ppAsmItm, + CPI_COMPONENT** ppCompItm + ); + + +// function definitions + +void CpiSubscriptionListFree( + CPI_SUBSCRIPTION_LIST* pList + ) +{ + CPI_SUBSCRIPTION* pItm = pList->pFirst; + + while (pItm) + { + CPI_SUBSCRIPTION* pDelete = pItm; + pItm = pItm->pNext; + FreeSubscription(pDelete); + } +} + +HRESULT CpiSubscriptionsRead( + CPI_ASSEMBLY_LIST* pAsmList, + CPI_SUBSCRIPTION_LIST* pSubList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + + CPI_SUBSCRIPTION* pItm = NULL; + LPWSTR pwzData = NULL; + BOOL fMatchingArchitecture = FALSE; + + // loop through all applications + hr = WcaOpenExecuteView(vcsSubscriptionQuery, &hView); + ExitOnFailure(hr, "Failed to execute view on ComPlusSubscription table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // get component + hr = WcaGetRecordString(hRec, sqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get component"); + + // check if the component is our processor architecture + hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); + ExitOnFailure(hr, "Failed to get component architecture."); + + if (!fMatchingArchitecture) + { + continue; // not the same architecture, ignore + } + + // create entry + pItm = (CPI_SUBSCRIPTION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_SUBSCRIPTION)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get component install state + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); + + // get key + hr = WcaGetRecordString(hRec, sqSubscription, &pwzData); + ExitOnFailure(hr, "Failed to get key"); + StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); + + // get com+ component + hr = WcaGetRecordString(hRec, sqComPlusComponent, &pwzData); + ExitOnFailure(hr, "Failed to get COM+ component"); + + hr = ComponentFindByKey(pAsmList, pwzData, &pItm->pAssembly, &pItm->pComponent); + + if (S_FALSE == hr) + { + // component not found + ExitOnFailure(hr = E_FAIL, "Failed to find component, key: %S", pwzData); + } + + // get id + hr = WcaGetRecordFormattedString(hRec, sqID, &pwzData); + ExitOnFailure(hr, "Failed to get id"); + + if (pwzData && *pwzData) + { + hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData); + } + + // get name + hr = WcaGetRecordFormattedString(hRec, sqName, &pwzData); + ExitOnFailure(hr, "Failed to get name"); + StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); + + // get event clsid + hr = WcaGetRecordFormattedString(hRec, sqEventCLSID, &pwzData); + ExitOnFailure(hr, "Failed to get event clsid"); + StringCchCopyW(pItm->wzEventCLSID, countof(pItm->wzEventCLSID), pwzData); + + // get publisher id + hr = WcaGetRecordFormattedString(hRec, sqPublisherID, &pwzData); + ExitOnFailure(hr, "Failed to get publisher id"); + StringCchCopyW(pItm->wzPublisherID, countof(pItm->wzPublisherID), pwzData); + + // get properties + if (CpiTableExists(cptComPlusSubscriptionProperty)) + { + hr = CpiPropertiesRead(vcsSubscriptionPropertyQuery, pItm->wzKey, pdlSubscriptionProperties, &pItm->pProperties, &pItm->iPropertyCount); + ExitOnFailure(hr, "Failed to get subscription properties"); + } + + // set references & increment counters + if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + { + CpiApplicationAddReferenceInstall(pItm->pAssembly->pApplication); + pItm->pAssembly->fReferencedForInstall = TRUE; + pSubList->iInstallCount++; + if (pItm->pAssembly->iAttributes & aaRunInCommit) + pSubList->iCommitCount++; + } + if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + { + CpiApplicationAddReferenceUninstall(pItm->pAssembly->pApplication); + pItm->pAssembly->fReferencedForUninstall = TRUE; + pSubList->iUninstallCount++; + } + + // add entry + if (pSubList->pFirst) + pItm->pNext = pSubList->pFirst; + pSubList->pFirst = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + FreeSubscription(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +HRESULT CpiSubscriptionsVerifyInstall( + CPI_SUBSCRIPTION_LIST* pList + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + ICatalogObject* piSubsObj = NULL; + + for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // subscriptions that are being installed + if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // subscription is supposed to exist + if (CpiIsInstalled(pItm->isInstalled)) + { + // if we don't have an id + if (!*pItm->wzID) + { + // find subscriptions with conflicting name + hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj); + ExitOnFailure(hr, "Failed to find collection object for subscription"); + + // if the subscription was found + if (S_OK == hr) + { + // get id from subscription object + hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to get id"); + } + + // if the subscription was not found + else + { + // create a new id + hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to create id"); + } + } + } + + // subscription is supposed to be created + else + { + // check for conflicts + do { + if (*pItm->wzID) + { + // find subscriptions with conflicting id + hr = FindObjectForSubscription(pItm, TRUE, FALSE, &piSubsObj); + ExitOnFailure(hr, "Failed to find collection object for subscription"); + + if (S_FALSE == hr) + { + // find subscriptions with conflicting name + hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj); + ExitOnFailure(hr, "Failed to find collection object for subscription"); + + if (S_OK == hr) + // "A subscription with a conflictiong name exists. retry cancel" + er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0); + else + break; // no conflicting entry found, break loop + } + else + // "A subscription with a conflicting id exists. abort retry ignore" + er = WcaErrorMessage(msierrComPlusSubscriptionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + } + else + { + // find subscriptions with conflicting name + hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj); + ExitOnFailure(hr, "Failed to find collection object for subscription"); + + if (S_OK == hr) + // "A subscription with a conflictiong name exists. abort retry ignore" + er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); + else + break; // no conflicting entry found, break loop + } + + switch (er) + { + case IDCANCEL: + case IDABORT: + ExitOnFailure(hr = E_FAIL, "A subscription with a conflictiong name or id exists, key: %S", pItm->wzKey); + break; + case IDRETRY: + break; + case IDIGNORE: + default: + // if we don't have an id, copy id from object + if (!*pItm->wzID) + { + hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to get id"); + } + hr = S_FALSE; // indicate that this is not a conflict + } + } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts + + // create a new id if one is missing + if (!*pItm->wzID) + { + hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to create id"); + } + } + + // clean up + ReleaseNullObject(piSubsObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piSubsObj); + + return hr; +} + +HRESULT CpiSubscriptionsVerifyUninstall( + CPI_SUBSCRIPTION_LIST* pList + ) +{ + HRESULT hr = S_OK; + ICatalogObject* piSubsObj = NULL; + + for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // subscriptions that are being installed + if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // find subscriptions with conflicting name + hr = FindObjectForSubscription(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piSubsObj); + ExitOnFailure(hr, "Failed to find collection object for subscription"); + + // if the subscription was found + if (S_OK == hr) + { + // if we don't have an id, copy id from object + if (!*pItm->wzID) + { + hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID)); + ExitOnFailure(hr, "Failed to get id"); + } + } + + // if the subscription was not found + else + { + pItm->fObjectNotFound = TRUE; + pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall + } + + // clean up + ReleaseNullObject(piSubsObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piSubsObj); + + return hr; +} + +HRESULT CpiSubscriptionsInstall( + CPI_SUBSCRIPTION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + int iCount = 0; + + // add action text + hr = CpiAddActionTextToActionData(L"CreateSubscrComPlusComponents", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // subscription count + switch (iRunMode) + { + case rmDeferred: + iCount = pList->iInstallCount - pList->iCommitCount; + break; + case rmCommit: + iCount = pList->iCommitCount; + break; + case rmRollback: + iCount = pList->iInstallCount; + break; + } + + // add subscription count to action data + hr = WcaWriteIntegerToCaData(iCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add assemblies to custom action data in forward order + for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // roles that are being installed only + if ((rmCommit == iRunMode && !(pItm->pAssembly->iAttributes & aaRunInCommit)) || + (rmDeferred == iRunMode && (pItm->pAssembly->iAttributes & aaRunInCommit)) || + !WcaIsInstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + { + if (CpiIsInstalled(pItm->isInstalled)) + iActionType = atNoOp; + else + iActionType = atRemove; + } + else + iActionType = atCreate; + + // add to action data + hr = AddSubscriptionToActionData(pItm, iActionType, COST_SUBSCRIPTION_CREATE, ppwzActionData); + ExitOnFailure(hr, "Failed to add subscription to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_SUBSCRIPTION_CREATE * pList->iInstallCount; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiSubscriptionsUninstall( + CPI_SUBSCRIPTION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ) +{ + HRESULT hr = S_OK; + + int iActionType; + + // add action text + hr = CpiAddActionTextToActionData(L"RemoveSubscrComPlusComponents", ppwzActionData); + ExitOnFailure(hr, "Failed to add action text to custom action data"); + + // add subscription count to action data + hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData); + ExitOnFailure(hr, "Failed to add count to custom action data"); + + // add assemblies to custom action data in reverse order + for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) + { + // roles that are being uninstalled only + if (pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) + continue; + + // action type + if (rmRollback == iRunMode) + iActionType = atCreate; + else + iActionType = atRemove; + + // add to action data + hr = AddSubscriptionToActionData(pItm, iActionType, COST_SUBSCRIPTION_DELETE, ppwzActionData); + ExitOnFailure(hr, "Failed to add subscription to custom action data, key: %S", pItm->wzKey); + } + + // add progress tics + if (piProgress) + *piProgress += COST_SUBSCRIPTION_DELETE * pList->iUninstallCount; + + hr = S_OK; + +LExit: + return hr; +} + + +// helper function definitions + +static void FreeSubscription( + CPI_SUBSCRIPTION* pItm + ) +{ + if (pItm->pProperties) + CpiPropertiesFreeList(pItm->pProperties); + + ::HeapFree(::GetProcessHeap(), 0, pItm); +} + +static HRESULT FindObjectForSubscription( + CPI_SUBSCRIPTION* pItm, + BOOL fFindId, + BOOL fFindName, + ICatalogObject** ppiSubsObj + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piSubsColl = NULL; + + // get applications collection + hr = CpiGetSubscriptionsCollForComponent(pItm->pAssembly, pItm->pComponent, &piSubsColl); + ExitOnFailure(hr, "Failed to get collection"); + + if (S_FALSE == hr) + ExitFunction(); // exit with hr = S_FALSE + + // find application object + hr = CpiFindCollectionObject(piSubsColl, fFindId ? pItm->wzID : NULL, fFindName ? pItm->wzName : NULL, ppiSubsObj); + ExitOnFailure(hr, "Failed to find object"); + + // exit with hr from CpiFindCollectionObject() + +LExit: + // clean up + ReleaseObject(piSubsColl); + + 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; +} + +static HRESULT ComponentFindByKey( + CPI_ASSEMBLY_LIST* pAsmList, + LPCWSTR pwzKey, + CPI_ASSEMBLY** ppAsmItm, + CPI_COMPONENT** ppCompItm + ) +{ + for (CPI_ASSEMBLY* pAsmItm = pAsmList->pFirst; pAsmItm; pAsmItm = pAsmItm->pNext) + { + for (CPI_COMPONENT* pCompItm = pAsmItm->pComponents; pCompItm; pCompItm = pCompItm->pNext) + { + if (0 == lstrcmpW(pCompItm->wzKey, pwzKey)) + { + *ppAsmItm = pAsmItm; + *ppCompItm = pCompItm; + return S_OK; + } + } + } + + return S_FALSE; +} diff --git a/src/ca/cpsubssched.h b/src/ca/cpsubssched.h new file mode 100644 index 00000000..3fc18478 --- /dev/null +++ b/src/ca/cpsubssched.h @@ -0,0 +1,62 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +struct CPI_SUBSCRIPTION +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzID[CPI_MAX_GUID + 1]; + WCHAR wzName[MAX_DARWIN_COLUMN + 1]; + WCHAR wzEventCLSID[CPI_MAX_GUID + 1]; + WCHAR wzPublisherID[CPI_MAX_GUID + 1]; + + BOOL fObjectNotFound; + + int iPropertyCount; + CPI_PROPERTY* pProperties; + + INSTALLSTATE isInstalled, isAction; + + CPI_ASSEMBLY* pAssembly; + CPI_COMPONENT* pComponent; + + CPI_SUBSCRIPTION* pNext; +}; + +struct CPI_SUBSCRIPTION_LIST +{ + CPI_SUBSCRIPTION* pFirst; + + int iInstallCount; + int iCommitCount; + int iUninstallCount; +}; + + +// function prototypes + +void CpiSubscriptionListFree( + CPI_SUBSCRIPTION_LIST* pList + ); +HRESULT CpiSubscriptionsRead( + CPI_ASSEMBLY_LIST* pAsmList, + CPI_SUBSCRIPTION_LIST* pSubList + ); +HRESULT CpiSubscriptionsVerifyInstall( + CPI_SUBSCRIPTION_LIST* pList + ); +HRESULT CpiSubscriptionsVerifyUninstall( + CPI_SUBSCRIPTION_LIST* pList + ); +HRESULT CpiSubscriptionsInstall( + CPI_SUBSCRIPTION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); +HRESULT CpiSubscriptionsUninstall( + CPI_SUBSCRIPTION_LIST* pList, + int iRunMode, + LPWSTR* ppwzActionData, + int* piProgress + ); diff --git a/src/ca/cputilexec.cpp b/src/ca/cputilexec.cpp new file mode 100644 index 00000000..e081678b --- /dev/null +++ b/src/ca/cputilexec.cpp @@ -0,0 +1,1881 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// private structs + +struct CPI_WELLKNOWN_SID +{ + LPCWSTR pwzName; + SID_IDENTIFIER_AUTHORITY iaIdentifierAuthority; + BYTE nSubAuthorityCount; + DWORD dwSubAuthority[8]; +}; + + +// well known SIDs + +CPI_WELLKNOWN_SID wsWellKnownSids[] = { + {L"\\Everyone", SECURITY_WORLD_SID_AUTHORITY, 1, {SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0}}, + {L"\\Administrators", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0}}, + {L"\\LocalSystem", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0}}, + {L"\\LocalService", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0}}, + {L"\\NetworkService", SECURITY_NT_AUTHORITY, 1, {SECURITY_NETWORK_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0}}, + {L"\\AuthenticatedUser", SECURITY_NT_AUTHORITY, 1, {SECURITY_AUTHENTICATED_USER_RID, 0, 0, 0, 0, 0, 0, 0}}, + {L"\\Guests", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS, 0, 0, 0, 0, 0, 0}}, + {L"\\Users", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0}}, + {L"\\CREATOR OWNER", SECURITY_NT_AUTHORITY, 1, {SECURITY_CREATOR_OWNER_RID, 0, 0, 0, 0, 0, 0, 0}}, + {NULL, SECURITY_NULL_SID_AUTHORITY, 0, {0, 0, 0, 0, 0, 0, 0, 0}} +}; + + +// prototypes for private helper functions + +static HRESULT FindUserCollectionObjectIndex( + ICatalogCollection* piColl, + PSID pSid, + int* pi + ); +static HRESULT CreateSidFromDomainRidPair( + PSID pDomainSid, + DWORD dwRid, + PSID* ppSid + ); +static HRESULT InitLsaUnicodeString( + PLSA_UNICODE_STRING plusStr, + LPCWSTR pwzStr, + DWORD dwLen + ); +static void FreeLsaUnicodeString( + PLSA_UNICODE_STRING plusStr + ); +static HRESULT WriteFileAll( + HANDLE hFile, + PBYTE pbBuffer, + DWORD dwBufferLength + ); +static HRESULT ReadFileAll( + HANDLE hFile, + PBYTE pbBuffer, + DWORD dwBufferLength + ); + + +// variables + +static ICOMAdminCatalog* gpiCatalog; + + +// function definitions + +void CpiInitialize() +{ + // collections + gpiCatalog = NULL; +} + +void CpiFinalize() +{ + // collections + ReleaseObject(gpiCatalog); +} + +HRESULT CpiActionStartMessage( + LPWSTR* ppwzActionData, + BOOL fSuppress + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hRec; + + LPWSTR pwzData = NULL; + + // create record + hRec = ::MsiCreateRecord(3); + ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Failed to create record"); + + // action name + hr = WcaReadStringFromCaData(ppwzActionData, &pwzData); + ExitOnFailure(hr, "Failed to action name"); + + er = ::MsiRecordSetStringW(hRec, 1, pwzData); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set action name"); + + // description + hr = WcaReadStringFromCaData(ppwzActionData, &pwzData); + ExitOnFailure(hr, "Failed to description"); + + er = ::MsiRecordSetStringW(hRec, 2, pwzData); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set description"); + + // template + hr = WcaReadStringFromCaData(ppwzActionData, &pwzData); + ExitOnFailure(hr, "Failed to template"); + + er = ::MsiRecordSetStringW(hRec, 3, pwzData); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set template"); + + // message + if (!fSuppress) + { + er = WcaProcessMessage(INSTALLMESSAGE_ACTIONSTART, hRec); + if (0 == er || IDOK == er || IDYES == er) + { + hr = S_OK; + } + else if (IDABORT == er || IDCANCEL == er) + { + WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit + hr = S_FALSE; + } + else + hr = E_UNEXPECTED; + } + +LExit: + // clean up + ReleaseStr(pwzData); + + return hr; +} + +HRESULT CpiActionDataMessage( + DWORD cArgs, + ... + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hRec; + va_list args; + + // record + hRec = ::MsiCreateRecord(cArgs); + ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Failed to create record"); + + va_start(args, cArgs); + for (DWORD i = 1; i <= cArgs; i++) + { + LPCWSTR pwzArg = va_arg(args, WCHAR*); + if (pwzArg && *pwzArg) + { + er = ::MsiRecordSetStringW(hRec, i, pwzArg); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set record field string"); + } + } + va_end(args); + + // message + er = WcaProcessMessage(INSTALLMESSAGE_ACTIONDATA, hRec); + if (0 == er || IDOK == er || IDYES == er) + { + hr = S_OK; + } + else if (IDABORT == er || IDCANCEL == er) + { + WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit + hr = S_FALSE; + } + else + hr = E_UNEXPECTED; + +LExit: + return hr; +} + +HRESULT CpiGetAdminCatalog( + ICOMAdminCatalog** ppiCatalog + ) +{ + HRESULT hr = S_OK; + + if (!gpiCatalog) + { + // get collection + hr = ::CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_ALL, IID_ICOMAdminCatalog, (void**)&gpiCatalog); + ExitOnFailure(hr, "Failed to create COM+ admin catalog object"); + } + + // return value + gpiCatalog->AddRef(); + *ppiCatalog = gpiCatalog; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiLogCatalogErrorInfo() +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + ICatalogCollection* piErrColl = NULL; + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + LPWSTR pwzName = NULL; + LPWSTR pwzErrorCode = NULL; + LPWSTR pwzMajorRef = NULL; + LPWSTR pwzMinorRef = NULL; + + // get catalog + hr = CpiGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get error info collection + hr = CpiGetCatalogCollection(L"ErrorInfo", &piErrColl); + ExitOnFailure(hr, "Failed to get error info collection"); + + // loop objects + long lCnt; + hr = piErrColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piErrColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get item from partitions collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // get properties + hr = CpiGetCollectionObjectValue(piObj, L"Name", &pwzName); + ExitOnFailure(hr, "Failed to get name"); + hr = CpiGetCollectionObjectValue(piObj, L"ErrorCode", &pwzErrorCode); + ExitOnFailure(hr, "Failed to get error code"); + hr = CpiGetCollectionObjectValue(piObj, L"MajorRef", &pwzMajorRef); + ExitOnFailure(hr, "Failed to get major ref"); + hr = CpiGetCollectionObjectValue(piObj, L"MinorRef", &pwzMinorRef); + ExitOnFailure(hr, "Failed to get minor ref"); + + // write to log + WcaLog(LOGMSG_STANDARD, "ErrorInfo: Name='%S', ErrorCode='%S', MajorRef='%S', MinorRef='%S'", + pwzName, pwzErrorCode, pwzMajorRef, pwzMinorRef); + + // clean up + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piErrColl); + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ReleaseStr(pwzName); + ReleaseStr(pwzErrorCode); + ReleaseStr(pwzMajorRef); + ReleaseStr(pwzMinorRef); + + return hr; +} + +HRESULT CpiGetCatalogCollection( + LPCWSTR pwzName, + ICatalogCollection** ppiColl + ) +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + IDispatch* piDisp = NULL; + + BSTR bstrName = NULL; + + // copy name string + bstrName = ::SysAllocString(pwzName); + ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name"); + + // get catalog + hr = CpiGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get collecton from catalog + hr = piCatalog->GetCollection(bstrName, &piDisp); + ExitOnFailure(hr, "Failed to get collection"); + + hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl); + ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface"); + + // populate collection + hr = (*ppiColl)->Populate(); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to populate collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piDisp); + ReleaseBSTR(bstrName); + + return hr; +} + +HRESULT CpiGetCatalogCollection( + ICatalogCollection* piColl, + ICatalogObject* piObj, + LPCWSTR pwzName, + ICatalogCollection** ppiColl + ) +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + IDispatch* piDisp = NULL; + + BSTR bstrName = NULL; + + VARIANT vtKey; + ::VariantInit(&vtKey); + + // copy name string + bstrName = ::SysAllocString(pwzName); + ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name"); + + // get catalog + hr = CpiGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get key + hr = piObj->get_Key(&vtKey); + ExitOnFailure(hr, "Failed to get object key"); + + // get collecton from catalog + hr = piColl->GetCollection(bstrName, vtKey, &piDisp); + ExitOnFailure(hr, "Failed to get collection"); + + hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl); + ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface"); + + // populate collection + hr = (*ppiColl)->Populate(); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to populate collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piDisp); + ReleaseBSTR(bstrName); + ::VariantClear(&vtKey); + + return hr; +} + +HRESULT CpiAddCollectionObject( + ICatalogCollection* piColl, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + + hr = piColl->Add(&piDisp); + ExitOnFailure(hr, "Failed to add object to collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)ppiObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piDisp); + + return hr; +} + +HRESULT CpiPutCollectionObjectValue( + ICatalogObject* piObj, + LPCWSTR pwzPropName, + LPCWSTR pwzValue + ) +{ + HRESULT hr = S_OK; + + BSTR bstrPropName = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + // allocate property name string + bstrPropName = ::SysAllocString(pwzPropName); + ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate property name string"); + + // prepare value variant + vtVal.vt = VT_BSTR; + vtVal.bstrVal = ::SysAllocString(pwzValue); + ExitOnNull(vtVal.bstrVal, hr, E_OUTOFMEMORY, "Failed to allocate property value string"); + + // put value + hr = piObj->put_Value(bstrPropName, vtVal); + ExitOnFailure(hr, "Failed to put property value"); + + hr = S_OK; + +LExit: + // clean up + ReleaseBSTR(bstrPropName); + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiPutCollectionObjectValues( + ICatalogObject* piObj, + CPI_PROPERTY* pPropList + ) +{ + HRESULT hr = S_OK; + + for (CPI_PROPERTY* pItm = pPropList; pItm; pItm = pItm->pNext) + { + // set property + hr = CpiPutCollectionObjectValue(piObj, pItm->wzName, pItm->pwzValue); + ExitOnFailure(hr, "Failed to set object property value, name: %S", pItm->wzName); + } + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetCollectionObjectValue( + ICatalogObject* piObj, + LPCWSTR szPropName, + LPWSTR* ppwzValue + ) +{ + HRESULT hr = S_OK; + + BSTR bstrPropName = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + // allocate property name string + bstrPropName = ::SysAllocString(szPropName); + ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate property name string"); + + // get value + hr = piObj->get_Value(bstrPropName, &vtVal); + ExitOnFailure(hr, "Failed to get property value"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + hr = StrAllocString(ppwzValue, vtVal.bstrVal, ::SysStringLen(vtVal.bstrVal)); + ExitOnFailure(hr, "Failed to allocate memory for value string"); + + hr = S_OK; + +LExit: + // clean up + ReleaseBSTR(bstrPropName); + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiResetObjectProperty( + ICatalogCollection* piColl, + ICatalogObject* piObj, + LPCWSTR pwzPropName + ) +{ + HRESULT hr = S_OK; + + BSTR bstrPropName = NULL; + + long lChanges = 0; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + // allocate property name string + bstrPropName = ::SysAllocString(pwzPropName); + ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate deleteable property name string"); + + // get value + hr = piObj->get_Value(bstrPropName, &vtVal); + ExitOnFailure(hr, "Failed to get deleteable property value"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BOOL); + ExitOnFailure(hr, "Failed to change variant type"); + + // if the deleteable property is set + if (VARIANT_FALSE == vtVal.boolVal) + { + // clear property + vtVal.boolVal = VARIANT_TRUE; + + hr = piObj->put_Value(bstrPropName, vtVal); + ExitOnFailure(hr, "Failed to get property value"); + + // save changes + hr = piColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseBSTR(bstrPropName); + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiRemoveCollectionObject( + ICatalogCollection* piColl, + LPCWSTR pwzID, + LPCWSTR pwzName, + BOOL fResetDeleteable + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + BOOL fMatch = FALSE; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + long lCnt; + hr = piColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // compare id + if (pwzID && *pwzID) + { + hr = piObj->get_Key(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + if (0 == lstrcmpiW(vtVal.bstrVal, pwzID)) + fMatch = TRUE; + + ::VariantClear(&vtVal); + } + + // compare name + if (pwzName && *pwzName) + { + hr = piObj->get_Name(&vtVal); + ExitOnFailure(hr, "Failed to get name"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + if (0 == lstrcmpW(vtVal.bstrVal, pwzName)) + fMatch = TRUE; + + ::VariantClear(&vtVal); + } + + // if it's a match, remove it + if (fMatch) + { + if (fResetDeleteable) + { + // reset deleteable property, if set + hr = CpiResetObjectProperty(piColl, piObj, L"Deleteable"); + ExitOnFailure(hr, "Failed to reset deleteable property"); + } + + hr = piColl->Remove(i); + ExitOnFailure(hr, "Failed to remove item from collection"); + break; + } + + // release interface pointers + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiRemoveUserCollectionObject( + ICatalogCollection* piColl, + PSID pSid + ) +{ + HRESULT hr = S_OK; + + int i = 0; + + // find index + hr = FindUserCollectionObjectIndex(piColl, pSid, &i); + ExitOnFailure(hr, "Failed to find user collection index"); + + if (S_FALSE == hr) + ExitFunction(); // not found, exit with hr = S_FALSE + + // remove object + hr = piColl->Remove(i); + ExitOnFailure(hr, "Failed to remove object from collection"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiFindCollectionObjectByStringKey( + ICatalogCollection* piColl, + LPCWSTR pwzKey, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + long lCnt; + hr = piColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // compare key + hr = piObj->get_Key(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + if (0 == lstrcmpiW(vtVal.bstrVal, pwzKey)) + { + if (ppiObj) + { + *ppiObj = piObj; + piObj = NULL; + } + ExitFunction1(hr = S_OK); + } + + // clean up + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + + ::VariantClear(&vtVal); + } + + hr = S_FALSE; + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiFindCollectionObjectByIntegerKey( + ICatalogCollection* piColl, + long lKey, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + long lCnt; + hr = piColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // compare key + hr = piObj->get_Key(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_I4); + ExitOnFailure(hr, "Failed to change variant type"); + + if (vtVal.lVal == lKey) + { + if (ppiObj) + { + *ppiObj = piObj; + piObj = NULL; + } + ExitFunction1(hr = S_OK); + } + + // clean up + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + + ::VariantClear(&vtVal); + } + + hr = S_FALSE; + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiFindCollectionObjectByName( + ICatalogCollection* piColl, + LPCWSTR pwzName, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + long lCnt; + hr = piColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // compare key + hr = piObj->get_Name(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + if (0 == lstrcmpW(vtVal.bstrVal, pwzName)) + { + if (ppiObj) + { + *ppiObj = piObj; + piObj = NULL; + } + ExitFunction1(hr = S_OK); + } + + // clean up + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + + ::VariantClear(&vtVal); + } + + hr = S_FALSE; + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiFindUserCollectionObject( + ICatalogCollection* piColl, + PSID pSid, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + int i = 0; + + IDispatch* piDisp = NULL; + + // find index + hr = FindUserCollectionObjectIndex(piColl, pSid, &i); + ExitOnFailure(hr, "Failed to find user collection index"); + + if (S_FALSE == hr) + ExitFunction(); // not found, exit with hr = S_FALSE + + // get object + if (ppiObj) + { + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)ppiObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piDisp); + + return hr; +} + +HRESULT CpiGetPartitionsCollection( + ICatalogCollection** ppiPartColl + ) +{ + HRESULT hr = S_OK; + + // get collection + hr = CpiGetCatalogCollection(L"Partitions", ppiPartColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetPartitionRolesCollection( + LPCWSTR pwzPartID, + ICatalogCollection** ppiRolesColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piPartColl = NULL; + ICatalogObject* piPartObj = NULL; + + // get partitions collection + hr = CpiGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + + if (S_FALSE == hr) + ExitFunction(); // partitions collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByStringKey(piPartColl, pwzPartID, &piPartObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // partition not found, exit with hr = S_FALSE + + // get roles collection + hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", ppiRolesColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piPartColl); + ReleaseObject(piPartObj); + + return hr; +} + +HRESULT CpiGetUsersInPartitionRoleCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzRoleName, + ICatalogCollection** ppiUsrInRoleColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piRoleColl = NULL; + ICatalogObject* piRoleObj = NULL; + + // get roles collection + hr = CpiGetPartitionRolesCollection(pwzPartID, &piRoleColl); + ExitOnFailure(hr, "Failed to get roles collection"); + + if (S_FALSE == hr) + ExitFunction(); // partition roles collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByName(piRoleColl, pwzRoleName, &piRoleObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // user not found, exit with hr = S_FALSE + + // get roles collection + hr = CpiGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInPartitionRole", ppiUsrInRoleColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piRoleColl); + ReleaseObject(piRoleObj); + + return hr; +} + +HRESULT CpiGetPartitionUsersCollection( + ICatalogCollection** ppiUserColl + ) +{ + HRESULT hr = S_OK; + + // get roles collection + hr = CpiGetCatalogCollection(L"PartitionUsers", ppiUserColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetApplicationsCollection( + LPCWSTR pwzPartID, + ICatalogCollection** ppiAppColl + ) +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + ICOMAdminCatalog2* piCatalog2 = NULL; + BSTR bstrGlobPartID = NULL; + + ICatalogCollection* piPartColl = NULL; + ICatalogObject* piPartObj = NULL; + + // get catalog + hr = CpiGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get ICOMAdminCatalog2 interface + hr = piCatalog->QueryInterface(IID_ICOMAdminCatalog2, (void**)&piCatalog2); + + // COM+ 1.5 or later + if (E_NOINTERFACE != hr) + { + ExitOnFailure(hr, "Failed to get IID_ICOMAdminCatalog2 interface"); + + // partition id + if (!pwzPartID || !*pwzPartID) + { + // get global partition id + hr = piCatalog2->get_GlobalPartitionID(&bstrGlobPartID); + ExitOnFailure(hr, "Failed to get global partition id"); + } + + // get partitions collection + hr = CpiGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + + // find object + hr = CpiFindCollectionObjectByStringKey(piPartColl, bstrGlobPartID ? bstrGlobPartID : pwzPartID, &piPartObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // partition not found, exit with hr = S_FALSE + + // get applications collection + hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"Applications", ppiAppColl); + ExitOnFailure(hr, "Failed to get catalog collection for partition"); + } + + // COM+ pre 1.5 + else + { + // this version of COM+ does not support partitions, make sure a partition was not specified + if (pwzPartID && *pwzPartID) + ExitOnFailure(hr = E_FAIL, "Partitions are not supported by this version of COM+"); + + // get applications collection + hr = CpiGetCatalogCollection(L"Applications", ppiAppColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piCatalog2); + ReleaseBSTR(bstrGlobPartID); + + ReleaseObject(piPartColl); + ReleaseObject(piPartObj); + + return hr; +} + +HRESULT CpiGetRolesCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + ICatalogCollection** ppiRolesColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piAppColl = NULL; + ICatalogObject* piAppObj = NULL; + + // get applications collection + hr = CpiGetApplicationsCollection(pwzPartID, &piAppColl); + ExitOnFailure(hr, "Failed to get applications collection"); + + if (S_FALSE == hr) + ExitFunction(); // applications collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByStringKey(piAppColl, pwzAppID, &piAppObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // application not found, exit with hr = S_FALSE + + // get roles collection + hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Roles", ppiRolesColl); + ExitOnFailure(hr, "Failed to catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piAppColl); + ReleaseObject(piAppObj); + + return hr; +} + +HRESULT CpiGetUsersInRoleCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + LPCWSTR pwzRoleName, + ICatalogCollection** ppiUsrInRoleColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piRoleColl = NULL; + ICatalogObject* piRoleObj = NULL; + + // get roles collection + hr = CpiGetRolesCollection(pwzPartID, pwzAppID, &piRoleColl); + ExitOnFailure(hr, "Failed to get roles collection"); + + if (S_FALSE == hr) + ExitFunction(); // roles collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByName(piRoleColl, pwzRoleName, &piRoleObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // role not found, exit with hr = S_FALSE + + // get roles collection + hr = CpiGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInRole", ppiUsrInRoleColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piRoleColl); + ReleaseObject(piRoleObj); + + return hr; +} + +HRESULT CpiGetComponentsCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + ICatalogCollection** ppiCompsColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piAppColl = NULL; + ICatalogObject* piAppObj = NULL; + + // get applications collection + hr = CpiGetApplicationsCollection(pwzPartID, &piAppColl); + ExitOnFailure(hr, "Failed to get applications collection"); + + if (S_FALSE == hr) + ExitFunction(); // applications collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByStringKey(piAppColl, pwzAppID, &piAppObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // application not found, exit with hr = S_FALSE + + // get components collection + hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Components", ppiCompsColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piAppColl); + ReleaseObject(piAppObj); + + return hr; +} + +HRESULT CpiGetInterfacesCollection( + ICatalogCollection* piCompColl, + ICatalogObject* piCompObj, + ICatalogCollection** ppiIntfColl + ) +{ + HRESULT hr = S_OK; + + // get interfaces collection + hr = CpiGetCatalogCollection(piCompColl, piCompObj, L"InterfacesForComponent", ppiIntfColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetMethodsCollection( + ICatalogCollection* piIntfColl, + ICatalogObject* piIntfObj, + ICatalogCollection** ppiMethColl + ) +{ + HRESULT hr = S_OK; + + // get interfaces collection + hr = CpiGetCatalogCollection(piIntfColl, piIntfObj, L"MethodsForInterface", ppiMethColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetSubscriptionsCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + LPCWSTR pwzCompCLSID, + ICatalogCollection** ppiSubsColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piCompColl = NULL; + ICatalogObject* piCompObj = NULL; + + // get components collection + hr = CpiGetComponentsCollection(pwzPartID, pwzAppID, &piCompColl); + ExitOnFailure(hr, "Failed to get components collection"); + + if (S_FALSE == hr) + ExitFunction(); // components collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByStringKey(piCompColl, pwzCompCLSID, &piCompObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // component not found, exit with hr = S_FALSE + + // get subscriptions collection + hr = CpiGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", ppiSubsColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCompColl); + ReleaseObject(piCompObj); + + return hr; +} + +HRESULT CpiReadPropertyList( + LPWSTR* ppwzData, + CPI_PROPERTY** ppPropList + ) +{ + HRESULT hr = S_OK; + + CPI_PROPERTY* pItm = NULL; + LPWSTR pwzName = NULL; + + // clear list if it already contains items + if (*ppPropList) + CpiFreePropertyList(*ppPropList); + *ppPropList = NULL; + + // read property count + int iPropCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iPropCnt); + ExitOnFailure(hr, "Failed to read property count"); + + for (int i = 0; i < iPropCnt; i++) + { + // allocate new element + pItm = (CPI_PROPERTY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PROPERTY)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // Name + hr = WcaReadStringFromCaData(ppwzData, &pwzName); + ExitOnFailure(hr, "Failed to read name"); + StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzName); + + // Value + hr = WcaReadStringFromCaData(ppwzData, &pItm->pwzValue); + ExitOnFailure(hr, "Failed to read property value"); + + // add to list + if (*ppPropList) + pItm->pNext = *ppPropList; + *ppPropList = pItm; + pItm = NULL; + } + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzName); + + if (pItm) + CpiFreePropertyList(pItm); + + return hr; +} + +void CpiFreePropertyList( + CPI_PROPERTY* pList + ) +{ + while (pList) + { + ReleaseStr(pList->pwzValue); + + CPI_PROPERTY* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +HRESULT CpiWriteKeyToRollbackFile( + HANDLE hFile, + LPCWSTR pwzKey + ) +{ + HRESULT hr = S_OK; + + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + ::ZeroMemory(wzKey, sizeof(wzKey)); + hr = StringCchCopyW(wzKey, countof(wzKey), pwzKey); + ExitOnFailure(hr, "Failed to copy key"); + + hr = WriteFileAll(hFile, (PBYTE)wzKey, MAX_DARWIN_KEY * sizeof(WCHAR)); + ExitOnFailure(hr, "Failed to write buffer"); + + FlushFileBuffers(hFile); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiWriteIntegerToRollbackFile( + HANDLE hFile, + int i + ) +{ + HRESULT hr = S_OK; + + hr = WriteFileAll(hFile, (PBYTE)&i, sizeof(int)); + ExitOnFailure(hr, "Failed to write buffer"); + + FlushFileBuffers(hFile); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiReadRollbackDataList( + HANDLE hFile, + CPI_ROLLBACK_DATA** pprdList + ) +{ + HRESULT hr = S_OK; + + int iCount; + + CPI_ROLLBACK_DATA* pItm = NULL; + + // read count + hr = ReadFileAll(hFile, (PBYTE)&iCount, sizeof(int)); + if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr) + ExitFunction1(hr = S_OK); // EOF reached, nothing left to read + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCount; i++) + { + // allocate new element + pItm = (CPI_ROLLBACK_DATA*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ROLLBACK_DATA)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // read from file + hr = ReadFileAll(hFile, (PBYTE)pItm->wzKey, MAX_DARWIN_KEY * sizeof(WCHAR)); + if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr) + break; // EOF reached, nothing left to read + ExitOnFailure(hr, "Failed to read key"); + + hr = ReadFileAll(hFile, (PBYTE)&pItm->iStatus, sizeof(int)); + if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr) + pItm->iStatus = 0; // EOF reached, the operation was interupted; set status to zero + else + ExitOnFailure(hr, "Failed to read status"); + + // add to list + if (*pprdList) + pItm->pNext = *pprdList; + *pprdList = pItm; + pItm = NULL; + } + + hr = S_OK; + +LExit: + // clean up + if (pItm) + CpiFreeRollbackDataList(pItm); + + return hr; +} + +void CpiFreeRollbackDataList( + CPI_ROLLBACK_DATA* pList + ) +{ + while (pList) + { + CPI_ROLLBACK_DATA* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +HRESULT CpiFindRollbackStatus( + CPI_ROLLBACK_DATA* pList, + LPCWSTR pwzKey, + int* piStatus + ) +{ + HRESULT hr = S_OK; + + for (; pList; pList = pList->pNext) + { + if (0 == lstrcmpW(pList->wzKey, pwzKey)) + { + *piStatus = pList->iStatus; + ExitFunction1(hr = S_OK); + } + } + + hr = S_FALSE; + +LExit: + return hr; +} + +HRESULT CpiAccountNameToSid( + LPCWSTR pwzAccountName, + PSID* ppSid + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + NTSTATUS st = 0; + + PSID pSid = NULL; + LSA_OBJECT_ATTRIBUTES loaAttributes; + LSA_HANDLE lsahPolicy = NULL; + LSA_UNICODE_STRING lusName; + PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL; + PLSA_TRANSLATED_SID pltsSid = NULL; + + ::ZeroMemory(&loaAttributes, sizeof(loaAttributes)); + ::ZeroMemory(&lusName, sizeof(lusName)); + + // identify well known SIDs + for (CPI_WELLKNOWN_SID* pWS = wsWellKnownSids; pWS->pwzName; pWS++) + { + if (0 == lstrcmpiW(pwzAccountName, pWS->pwzName)) + { + // allocate SID buffer + pSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, ::GetSidLengthRequired(pWS->nSubAuthorityCount)); + ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID"); + + // initialize SID + ::InitializeSid(pSid, &pWS->iaIdentifierAuthority, pWS->nSubAuthorityCount); + + // copy sub autorities + for (DWORD i = 0; i < pWS->nSubAuthorityCount; i++) + *::GetSidSubAuthority(pSid, i) = pWS->dwSubAuthority[i]; + + break; + } + } + + // lookup name + if (!pSid) + { + // open policy handle + st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy); + er = ::LsaNtStatusToWinError(st); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle"); + + // create account name lsa unicode string + hr = InitLsaUnicodeString(&lusName, pwzAccountName, (DWORD)wcslen(pwzAccountName)); + ExitOnFailure(hr, "Failed to initialize account name string"); + + // lookup name + st = ::LsaLookupNames(lsahPolicy, 1, &lusName, &plrdsDomains, &pltsSid); + er = ::LsaNtStatusToWinError(st); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names"); + + if (SidTypeDomain == pltsSid->Use) + ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported"); + + // convert sid + hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pSid); + ExitOnFailure(hr, "Failed to convert SID"); + } + + *ppSid = pSid; + pSid = NULL; + + hr = S_OK; + +LExit: + // clean up + if (pSid) + ::HeapFree(::GetProcessHeap(), 0, pSid); + if (lsahPolicy) + ::LsaClose(lsahPolicy); + if (plrdsDomains) + ::LsaFreeMemory(plrdsDomains); + if (pltsSid) + ::LsaFreeMemory(pltsSid); + FreeLsaUnicodeString(&lusName); + + return hr; +} + +HRESULT CpiSidToAccountName( + PSID pSid, + LPWSTR* ppwzAccountName + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + NTSTATUS st = 0; + + LSA_OBJECT_ATTRIBUTES loaAttributes; + LSA_HANDLE lsahPolicy = NULL; + PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL; + PLSA_TRANSLATED_NAME pltnName = NULL; + + LPWSTR pwzDomain = NULL; + LPWSTR pwzName = NULL; + + ::ZeroMemory(&loaAttributes, sizeof(loaAttributes)); + + // open policy handle + st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy); + er = ::LsaNtStatusToWinError(st); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle"); + + // lookup SID + st = ::LsaLookupSids(lsahPolicy, 1, &pSid, &plrdsDomains, &pltnName); + er = ::LsaNtStatusToWinError(st); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed lookup SID"); + + if (SidTypeDomain == pltnName->Use) + ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported"); + + // format account name string + if (SidTypeWellKnownGroup != pltnName->Use) + { + PLSA_UNICODE_STRING plusDomain = &plrdsDomains->Domains[pltnName->DomainIndex].Name; + hr = StrAllocString(&pwzDomain, plusDomain->Buffer, plusDomain->Length / sizeof(WCHAR)); + ExitOnFailure(hr, "Failed to allocate name string"); + } + + hr = StrAllocString(&pwzName, pltnName->Name.Buffer, pltnName->Name.Length / sizeof(WCHAR)); + ExitOnFailure(hr, "Failed to allocate domain string"); + + hr = StrAllocFormatted(ppwzAccountName, L"%s\\%s", pwzDomain ? pwzDomain : L"", pwzName); + ExitOnFailure(hr, "Failed to format account name string"); + + hr = S_OK; + +LExit: + // clean up + if (lsahPolicy) + ::LsaClose(lsahPolicy); + if (plrdsDomains) + ::LsaFreeMemory(plrdsDomains); + if (pltnName) + ::LsaFreeMemory(pltnName); + + ReleaseStr(pwzDomain); + ReleaseStr(pwzName); + + return hr; +} + +// helper function definitions + +static HRESULT FindUserCollectionObjectIndex( + ICatalogCollection* piColl, + PSID pSid, + int* pi + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + NTSTATUS st = 0; + + long i = 0; + long lCollCnt = 0; + + LSA_OBJECT_ATTRIBUTES loaAttributes; + LSA_HANDLE lsahPolicy = NULL; + PLSA_UNICODE_STRING plusNames = NULL; + PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL; + PLSA_TRANSLATED_SID pltsSids = NULL; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + VARIANT vtVal; + + PSID pTmpSid = NULL; + + PLSA_TRANSLATED_SID pltsSid; + + ::VariantInit(&vtVal); + ::ZeroMemory(&loaAttributes, sizeof(loaAttributes)); + + // open policy handle + st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy); + er = ::LsaNtStatusToWinError(st); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle"); + + // get number of elements in collection + hr = piColl->get_Count(&lCollCnt); + ExitOnFailure(hr, "Failed to get to number of objects in collection"); + + if (0 == lCollCnt) + ExitFunction1(hr = S_FALSE); // not found + + // allocate name buffer + plusNames = (PLSA_UNICODE_STRING)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LSA_UNICODE_STRING) * lCollCnt); + ExitOnNull(plusNames, hr, E_OUTOFMEMORY, "Failed to allocate names buffer"); + + // get accounts in collection + for (i = 0; i < lCollCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // get value + hr = piObj->get_Key(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + // copy account name string + hr = InitLsaUnicodeString(&plusNames[i], vtVal.bstrVal, ::SysStringLen(vtVal.bstrVal)); + ExitOnFailure(hr, "Failed to initialize account name string"); + + // clean up + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + ::VariantClear(&vtVal); + } + + // lookup names + st = ::LsaLookupNames(lsahPolicy, lCollCnt, plusNames, &plrdsDomains, &pltsSids); + er = ::LsaNtStatusToWinError(st); + if (ERROR_NONE_MAPPED != er && ERROR_SOME_NOT_MAPPED != er) + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names"); + + // compare SIDs + for (i = 0; i < lCollCnt; i++) + { + // get SID + pltsSid = &pltsSids[i]; + if (SidTypeDomain == pltsSid->Use || SidTypeInvalid == pltsSid->Use || SidTypeUnknown == pltsSid->Use) + continue; // ignore... + + hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pTmpSid); + ExitOnFailure(hr, "Failed to convert SID"); + + // compare SIDs + if (::EqualSid(pSid, pTmpSid)) + { + *pi = i; + ExitFunction1(hr = S_OK); + } + } + + if (ERROR_NONE_MAPPED == er || ERROR_SOME_NOT_MAPPED == er) + hr = HRESULT_FROM_WIN32(er); + else + hr = S_FALSE; // not found + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + ::VariantClear(&vtVal); + + if (plusNames) + { + for (i = 0; i < lCollCnt; i++) + FreeLsaUnicodeString(&plusNames[i]); + ::HeapFree(::GetProcessHeap(), 0, plusNames); + } + + if (lsahPolicy) + ::LsaClose(lsahPolicy); + if (plrdsDomains) + ::LsaFreeMemory(plrdsDomains); + if (pltsSids) + ::LsaFreeMemory(pltsSids); + + if (pTmpSid) + ::HeapFree(::GetProcessHeap(), 0, pTmpSid); + + return hr; +} + +static HRESULT CreateSidFromDomainRidPair( + PSID pDomainSid, + DWORD dwRid, + PSID* ppSid + ) +{ + HRESULT hr = S_OK; + PSID pSid = NULL; + + // get domain SID sub authority count + UCHAR ucSubAuthorityCount = *::GetSidSubAuthorityCount(pDomainSid); + + // allocate SID buffer + DWORD dwLengthRequired = ::GetSidLengthRequired(ucSubAuthorityCount + (UCHAR)1); + if (*ppSid) + { + SIZE_T ccb = ::HeapSize(::GetProcessHeap(), 0, *ppSid); + if (-1 == ccb) + ExitOnFailure(hr = E_FAIL, "Failed to get size of SID buffer"); + + if (ccb < dwLengthRequired) + { + pSid = (PSID)::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, *ppSid, dwLengthRequired); + ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to reallocate buffer for SID, len: %d", dwLengthRequired); + *ppSid = pSid; + } + } + else + { + *ppSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwLengthRequired); + ExitOnNull(*ppSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID, len: %d", dwLengthRequired); + } + + ::InitializeSid(*ppSid, ::GetSidIdentifierAuthority(pDomainSid), ucSubAuthorityCount + (UCHAR)1); + + // copy sub autorities + DWORD i = 0; + for (; i < ucSubAuthorityCount; i++) + *::GetSidSubAuthority(*ppSid, i) = *::GetSidSubAuthority(pDomainSid, i); + *::GetSidSubAuthority(*ppSid, i) = dwRid; + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT InitLsaUnicodeString( + PLSA_UNICODE_STRING plusStr, + LPCWSTR pwzStr, + DWORD dwLen + ) +{ + HRESULT hr = S_OK; + + plusStr->Length = (USHORT)dwLen * sizeof(WCHAR); + plusStr->MaximumLength = (USHORT)(dwLen + 1) * sizeof(WCHAR); + + plusStr->Buffer = (WCHAR*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * (dwLen + 1)); + ExitOnNull(plusStr->Buffer, hr, E_OUTOFMEMORY, "Failed to allocate account name string"); + + hr = StringCchCopyW(plusStr->Buffer, dwLen + 1, pwzStr); + ExitOnFailure(hr, "Failed to copy buffer"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreeLsaUnicodeString( + PLSA_UNICODE_STRING plusStr + ) +{ + if (plusStr->Buffer) + ::HeapFree(::GetProcessHeap(), 0, plusStr->Buffer); +} + +static HRESULT WriteFileAll( + HANDLE hFile, + PBYTE pbBuffer, + DWORD dwBufferLength + ) +{ + HRESULT hr = S_OK; + + DWORD dwBytesWritten; + + while (dwBufferLength) + { + if (!::WriteFile(hFile, pbBuffer, dwBufferLength, &dwBytesWritten, NULL)) + ExitFunction1(hr = HRESULT_FROM_WIN32(::GetLastError())); + + dwBufferLength -= dwBytesWritten; + pbBuffer += dwBytesWritten; + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT ReadFileAll( + HANDLE hFile, + PBYTE pbBuffer, + DWORD dwBufferLength + ) +{ + HRESULT hr = S_OK; + + DWORD dwBytesRead; + + while (dwBufferLength) + { + if (!::ReadFile(hFile, pbBuffer, dwBufferLength, &dwBytesRead, NULL)) + ExitFunction1(hr = HRESULT_FROM_WIN32(::GetLastError())); + + if (0 == dwBytesRead) + ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF)); + + dwBufferLength -= dwBytesRead; + pbBuffer += dwBytesRead; + } + + hr = S_OK; + +LExit: + return hr; +} diff --git a/src/ca/cputilexec.h b/src/ca/cputilexec.h new file mode 100644 index 00000000..51b47583 --- /dev/null +++ b/src/ca/cputilexec.h @@ -0,0 +1,193 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +#define CPI_MAX_GUID 38 + +enum eActionType { atNoOp = 0, atCreate, atRemove }; + + +// structs + +struct CPI_PROPERTY +{ + WCHAR wzName[MAX_DARWIN_KEY + 1]; + LPWSTR pwzValue; + + CPI_PROPERTY* pNext; +}; + +struct CPI_ROLLBACK_DATA +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + int iStatus; + + CPI_ROLLBACK_DATA* pNext; +}; + + +// function prototypes + +void CpiInitialize(); +void CpiFinalize(); +HRESULT CpiActionStartMessage( + LPWSTR* ppwzActionData, + BOOL fSuppress + ); +HRESULT CpiActionDataMessage( + DWORD cArgs, + ... + ); +HRESULT CpiGetAdminCatalog( + ICOMAdminCatalog** ppiCatalog + ); +HRESULT CpiLogCatalogErrorInfo(); +HRESULT CpiGetCatalogCollection( + LPCWSTR pwzName, + ICatalogCollection** ppiColl + ); +HRESULT CpiGetCatalogCollection( + ICatalogCollection* piColl, + ICatalogObject* piObj, + LPCWSTR pwzName, + ICatalogCollection** ppiColl + ); +HRESULT CpiAddCollectionObject( + ICatalogCollection* piColl, + ICatalogObject** ppiObj + ); +HRESULT CpiPutCollectionObjectValue( + ICatalogObject* piObj, + LPCWSTR pwzPropName, + LPCWSTR pwzValue + ); +HRESULT CpiPutCollectionObjectValues( + ICatalogObject* piObj, + CPI_PROPERTY* pPropList + ); +HRESULT CpiGetCollectionObjectValue( + ICatalogObject* piObj, + LPCWSTR szPropName, + LPWSTR* ppwzValue + ); +HRESULT CpiResetObjectProperty( + ICatalogCollection* piColl, + ICatalogObject* piObj, + LPCWSTR pwzPropName + ); +HRESULT CpiRemoveCollectionObject( + ICatalogCollection* piColl, + LPCWSTR pwzID, + LPCWSTR pwzName, + BOOL fResetDeleteable + ); +HRESULT CpiRemoveUserCollectionObject( + ICatalogCollection* piColl, + PSID pSid + ); +HRESULT CpiFindCollectionObjectByStringKey( + ICatalogCollection* piColl, + LPCWSTR pwzKey, + ICatalogObject** ppiObj + ); +HRESULT CpiFindCollectionObjectByIntegerKey( + ICatalogCollection* piColl, + long lKey, + ICatalogObject** ppiObj + ); +HRESULT CpiFindCollectionObjectByName( + ICatalogCollection* piColl, + LPCWSTR pwzName, + ICatalogObject** ppiObj + ); +HRESULT CpiFindUserCollectionObject( + ICatalogCollection* piColl, + PSID pSid, + ICatalogObject** ppiObj + ); +HRESULT CpiGetPartitionsCollection( + ICatalogCollection** ppiPartColl + ); +HRESULT CpiGetPartitionRolesCollection( + LPCWSTR pwzPartID, + ICatalogCollection** ppiRolesColl + ); +HRESULT CpiGetUsersInPartitionRoleCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzRoleName, + ICatalogCollection** ppiUsrInRoleColl + ); +HRESULT CpiGetPartitionUsersCollection( + ICatalogCollection** ppiUserColl + ); +HRESULT CpiGetApplicationsCollection( + LPCWSTR pwzPartID, + ICatalogCollection** ppiAppColl + ); +HRESULT CpiGetRolesCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + ICatalogCollection** ppiRolesColl + ); +HRESULT CpiGetUsersInRoleCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + LPCWSTR pwzRoleName, + ICatalogCollection** ppiUsrInRoleColl + ); +HRESULT CpiGetComponentsCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + ICatalogCollection** ppiCompsColl + ); +HRESULT CpiGetInterfacesCollection( + ICatalogCollection* piCompColl, + ICatalogObject* piCompObj, + ICatalogCollection** ppiIntfColl + ); +HRESULT CpiGetMethodsCollection( + ICatalogCollection* piIntfColl, + ICatalogObject* piIntfObj, + ICatalogCollection** ppiMethColl + ); +HRESULT CpiGetSubscriptionsCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + LPCWSTR pwzCompCLSID, + ICatalogCollection** ppiCompsColl + ); +HRESULT CpiReadPropertyList( + LPWSTR* ppwzData, + CPI_PROPERTY** ppPropList + ); +void CpiFreePropertyList( + CPI_PROPERTY* pList + ); +HRESULT CpiWriteKeyToRollbackFile( + HANDLE hFile, + LPCWSTR pwzKey + ); +HRESULT CpiWriteIntegerToRollbackFile( + HANDLE hFile, + int i + ); +HRESULT CpiReadRollbackDataList( + HANDLE hFile, + CPI_ROLLBACK_DATA** pprdList + ); +void CpiFreeRollbackDataList( + CPI_ROLLBACK_DATA* pList + ); +HRESULT CpiFindRollbackStatus( + CPI_ROLLBACK_DATA* pList, + LPCWSTR pwzKey, + int* piStatus + ); +HRESULT CpiAccountNameToSid( + LPCWSTR pwzAccountName, + PSID* ppSid + ); +HRESULT CpiSidToAccountName( + PSID pSid, + LPWSTR* ppwzAccountName + ); diff --git a/src/ca/cputilsched.cpp b/src/ca/cputilsched.cpp new file mode 100644 index 00000000..9dbe21ec --- /dev/null +++ b/src/ca/cputilsched.cpp @@ -0,0 +1,885 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// sql queries + +LPCWSTR vcsActionTextQuery = + L"SELECT `Description`, `Template` FROM `ActionText` WHERE `Action` = ?"; +enum eActionTextQuery { atqDescription = 1, atqTemplate }; + +LPCWSTR vcsComponentAttributesQuery = + L"SELECT `Attributes` FROM `Component` WHERE `Component` = ?"; +enum eComponentAttributesQuery { caqAttributes = 1 }; + +LPCWSTR vcsUserQuery = L"SELECT `Domain`, `Name` FROM `User` WHERE `User` = ?"; +enum eUserQuery { uqDomain = 1, uqName }; + +enum ePropertyQuery { pqName = 1, pqValue }; + + +// prototypes for private helper functions + +static HRESULT FindPropertyDefinition( + CPI_PROPERTY_DEFINITION* pPropDefList, + LPCWSTR pwzName, + CPI_PROPERTY_DEFINITION** ppPropDef + ); +static HRESULT GetUserAccountName( + LPCWSTR pwzKey, + LPWSTR* ppwzAccount + ); + + +// variables + +static ICOMAdminCatalog* gpiCatalog; +static ICatalogCollection* gpiPartColl; +static ICatalogCollection* gpiAppColl; + +static int giTables; + + +// function definitions + +void CpiInitialize() +{ + // collections + gpiCatalog = NULL; + gpiPartColl = NULL; + gpiAppColl = NULL; + + // tables + giTables = 0; + + if (S_OK == WcaTableExists(L"ComPlusPartition")) giTables |= cptComPlusPartition; + if (S_OK == WcaTableExists(L"ComPlusPartitionProperty")) giTables |= cptComPlusPartitionProperty; + if (S_OK == WcaTableExists(L"ComPlusPartitionRole")) giTables |= cptComPlusPartitionRole; + if (S_OK == WcaTableExists(L"ComPlusUserInPartitionRole")) giTables |= cptComPlusUserInPartitionRole; + if (S_OK == WcaTableExists(L"ComPlusGroupInPartitionRole")) giTables |= cptComPlusGroupInPartitionRole; + if (S_OK == WcaTableExists(L"ComPlusPartitionUser")) giTables |= cptComPlusPartitionUser; + if (S_OK == WcaTableExists(L"ComPlusApplication")) giTables |= cptComPlusApplication; + if (S_OK == WcaTableExists(L"ComPlusApplicationProperty")) giTables |= cptComPlusApplicationProperty; + if (S_OK == WcaTableExists(L"ComPlusApplicationRole")) giTables |= cptComPlusApplicationRole; + if (S_OK == WcaTableExists(L"ComPlusApplicationRoleProperty")) giTables |= cptComPlusApplicationRoleProperty; + if (S_OK == WcaTableExists(L"ComPlusUserInApplicationRole")) giTables |= cptComPlusUserInApplicationRole; + if (S_OK == WcaTableExists(L"ComPlusGroupInApplicationRole")) giTables |= cptComPlusGroupInApplicationRole; + if (S_OK == WcaTableExists(L"ComPlusAssembly")) giTables |= cptComPlusAssembly; + if (S_OK == WcaTableExists(L"ComPlusAssemblyDependency")) giTables |= cptComPlusAssemblyDependency; + if (S_OK == WcaTableExists(L"ComPlusComponent")) giTables |= cptComPlusComponent; + if (S_OK == WcaTableExists(L"ComPlusComponentProperty")) giTables |= cptComPlusComponentProperty; + if (S_OK == WcaTableExists(L"ComPlusRoleForComponent")) giTables |= cptComPlusRoleForComponent; + if (S_OK == WcaTableExists(L"ComPlusInterface")) giTables |= cptComPlusInterface; + if (S_OK == WcaTableExists(L"ComPlusInterfaceProperty")) giTables |= cptComPlusInterfaceProperty; + if (S_OK == WcaTableExists(L"ComPlusRoleForInterface")) giTables |= cptComPlusRoleForInterface; + if (S_OK == WcaTableExists(L"ComPlusMethod")) giTables |= cptComPlusMethod; + if (S_OK == WcaTableExists(L"ComPlusMethodProperty")) giTables |= cptComPlusMethodProperty; + if (S_OK == WcaTableExists(L"ComPlusRoleForMethod")) giTables |= cptComPlusRoleForMethod; + if (S_OK == WcaTableExists(L"ComPlusSubscription")) giTables |= cptComPlusSubscription; + if (S_OK == WcaTableExists(L"ComPlusSubscriptionProperty")) giTables |= cptComPlusSubscriptionProperty; +} + +void CpiFinalize() +{ + // collections + ReleaseObject(gpiCatalog); + ReleaseObject(gpiPartColl); + ReleaseObject(gpiAppColl); +} + +BOOL CpiTableExists( + int iTable + ) +{ + return (giTables & iTable) == iTable; +} + +HRESULT CpiGetAdminCatalog( + ICOMAdminCatalog** ppiCatalog + ) +{ + HRESULT hr = S_OK; + + if (!gpiCatalog) + { + // get collection + hr = ::CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_ALL, IID_ICOMAdminCatalog, (void**)&gpiCatalog); + ExitOnFailure(hr, "Failed to create COM+ admin catalog object"); + } + + // return value + gpiCatalog->AddRef(); + *ppiCatalog = gpiCatalog; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetCatalogCollection( + LPCWSTR pwzName, + ICatalogCollection** ppiColl + ) +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + IDispatch* piDisp = NULL; + BSTR bstrName = NULL; + + // copy name string + bstrName = ::SysAllocString(pwzName); + ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name"); + + // get catalog + hr = CpiGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get collecton from catalog + hr = piCatalog->GetCollection(bstrName, &piDisp); + ExitOnFailure(hr, "Failed to get collection"); + + hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl); + ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface"); + + // populate collection + hr = (*ppiColl)->Populate(); + ExitOnFailure(hr, "Failed to populate collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piDisp); + ReleaseBSTR(bstrName); + + return hr; +} + +HRESULT CpiGetCatalogCollection( + ICatalogCollection* piColl, + ICatalogObject* piObj, + LPCWSTR pwzName, + ICatalogCollection** ppiColl + ) +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + IDispatch* piDisp = NULL; + BSTR bstrName = NULL; + + VARIANT vtKey; + ::VariantInit(&vtKey); + + // copy name string + bstrName = ::SysAllocString(pwzName); + ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name"); + + // get catalog + hr = CpiGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get key + hr = piObj->get_Key(&vtKey); + ExitOnFailure(hr, "Failed to get object key"); + + // get collecton from catalog + hr = piColl->GetCollection(bstrName, vtKey, &piDisp); + ExitOnFailure(hr, "Failed to get collection"); + + hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl); + ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface"); + + // populate collection + hr = (*ppiColl)->Populate(); + ExitOnFailure(hr, "Failed to populate collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piDisp); + ReleaseBSTR(bstrName); + ::VariantClear(&vtKey); + + return hr; +} + +HRESULT CpiGetKeyForObject( + ICatalogObject* piObj, + LPWSTR pwzKey, + SIZE_T cchKey + ) +{ + HRESULT hr = S_OK; + + VARIANT vtKey; + ::VariantInit(&vtKey); + + // get key + hr = piObj->get_Key(&vtKey); + ExitOnFailure(hr, "Failed to get key"); + + // change variant type + hr = ::VariantChangeType(&vtKey, &vtKey, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + // copy key + hr = StringCchCopyW(pwzKey, cchKey, vtKey.bstrVal); + ExitOnFailure(hr, "Failed to copy key"); + + hr = S_OK; + +LExit: + // clean up + ::VariantClear(&vtKey); + + return hr; +} + +HRESULT CpiFindCollectionObject( + ICatalogCollection* piColl, + LPCWSTR pwzID, + LPCWSTR pwzName, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + long lCnt; + hr = piColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // compare id + if (pwzID && *pwzID) + { + hr = piObj->get_Key(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + if (0 == lstrcmpiW(vtVal.bstrVal, pwzID)) + { + if (ppiObj) + { + *ppiObj = piObj; + piObj = NULL; + } + ExitFunction1(hr = S_OK); + } + + ::VariantClear(&vtVal); + } + + // compare name + if (pwzName && *pwzName) + { + hr = piObj->get_Name(&vtVal); + ExitOnFailure(hr, "Failed to get name"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + if (0 == lstrcmpW(vtVal.bstrVal, pwzName)) + { + if (ppiObj) + { + *ppiObj = piObj; + piObj = NULL; + } + ExitFunction1(hr = S_OK); + } + + ::VariantClear(&vtVal); + } + + // release interface pointers + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + } + + hr = S_FALSE; + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiGetPartitionsCollection( + ICatalogCollection** ppiPartColl + ) +{ + HRESULT hr = S_OK; + + if (!gpiPartColl) + { + // get collection + hr = CpiGetCatalogCollection(L"Partitions", &gpiPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + } + + // return value + gpiPartColl->AddRef(); + *ppiPartColl = gpiPartColl; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetApplicationsCollection( + ICatalogCollection** ppiAppColl + ) +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + ICOMAdminCatalog2* piCatalog2 = NULL; + ICatalogCollection* piPartColl = NULL; + ICatalogObject* piPartObj = NULL; + BSTR bstrGlobPartID = NULL; + + if (!gpiAppColl) + { + // get catalog + hr = CpiGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get ICOMAdminCatalog2 interface + hr = piCatalog->QueryInterface(IID_ICOMAdminCatalog2, (void**)&piCatalog2); + + // COM+ 1.5 or later + if (E_NOINTERFACE != hr) + { + ExitOnFailure(hr, "Failed to get IID_ICOMAdminCatalog2 interface"); + + // get global partition id + hr = piCatalog2->get_GlobalPartitionID(&bstrGlobPartID); + ExitOnFailure(hr, "Failed to get global partition id"); + + // get partitions collection + hr = CpiGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + + // find object + hr = CpiFindCollectionObject(piPartColl, bstrGlobPartID, NULL, &piPartObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // partition not found, exit with hr = S_FALSE + + // get applications collection + hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"Applications", &gpiAppColl); + ExitOnFailure(hr, "Failed to get applications collection"); + } + + // COM+ pre 1.5 + else + { + // get applications collection + hr = CpiGetCatalogCollection(L"Applications", &gpiAppColl); + ExitOnFailure(hr, "Failed to get applications collection"); + } + } + + // return value + gpiAppColl->AddRef(); + *ppiAppColl = gpiAppColl; + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piCatalog2); + ReleaseObject(piPartColl); + ReleaseObject(piPartObj); + ReleaseBSTR(bstrGlobPartID); + + 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; +} + +HRESULT CpiVerifyComponentArchitecure( + LPCWSTR pwzComponent, + BOOL* pfMatchingArchitecture + ) +{ + HRESULT hr = S_OK; + + PMSIHANDLE hView, hRecKey, hRec; + + int iAttributes = 0; + + if (S_OK == WcaTableExists(L"Component")) + { + // create parameter record + hRecKey = ::MsiCreateRecord(1); + ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); + hr = WcaSetRecordString(hRecKey, 1, pwzComponent); + ExitOnFailure(hr, "Failed to set record string"); + + // open view + hr = WcaOpenView(vcsComponentAttributesQuery, &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 component record"); + + hr = WcaGetRecordInteger(hRec, caqAttributes, &iAttributes); + ExitOnFailure(hr, "Failed to get component attributes"); + } + } + + // return values +#ifdef _WIN64 + *pfMatchingArchitecture = 256 == (iAttributes & 256); +#else + *pfMatchingArchitecture = 256 != (iAttributes & 256); +#endif + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiPropertiesRead( + LPCWSTR pwzQuery, + LPCWSTR pwzKey, + CPI_PROPERTY_DEFINITION* pPropDefList, + CPI_PROPERTY** ppPropList, + int* piCount + ) +{ + HRESULT hr = S_OK; + + PMSIHANDLE hView, hRecKey, hRec; + + CPI_PROPERTY* pItm = NULL; + LPWSTR pwzData = NULL; + + int iVersionNT = 0; + + CPI_PROPERTY_DEFINITION* pPropDef; + + *piCount = 0; + + // get NT version + hr = WcaGetIntProperty(L"VersionNT", &iVersionNT); + ExitOnFailure(hr, "Failed to set record string"); + + // create parameter record + hRecKey = ::MsiCreateRecord(1); + ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); + hr = WcaSetRecordString(hRecKey, 1, pwzKey); + ExitOnFailure(hr, "Failed to set record string"); + + // open view + hr = WcaOpenView(pwzQuery, &hView); + ExitOnFailure(hr, "Failed to open view on property table"); + hr = WcaExecuteView(hView, hRecKey); + ExitOnFailure(hr, "Failed to execute view on property table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // create entry + pItm = (CPI_PROPERTY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PROPERTY)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // get name + hr = WcaGetRecordString(hRec, pqName, &pwzData); + ExitOnFailure(hr, "Failed to get name"); + StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); + + // get value + hr = WcaGetRecordFormattedString(hRec, pqValue, &pItm->pwzValue); + ExitOnFailure(hr, "Failed to get value"); + + // find property definition + hr = FindPropertyDefinition(pPropDefList, pItm->wzName, &pPropDef); + ExitOnFailure(hr, "Failed to find property definition"); + + if (S_FALSE == hr) + ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Unknown property, key: %S, property: %S", pwzKey, pItm->wzName); + + // check version, ignore if catalog version is too low + if (iVersionNT < pPropDef->iMinVersionNT) + { + WcaLog(LOGMSG_VERBOSE, "Skipping property since NT version is too low, key: %S, property: %S", pwzKey, pItm->wzName); + CpiPropertiesFreeList(pItm); + pItm = NULL; + continue; + } + + // if the property is a user, replace the User table key with a user account name + if (cpptUser == pPropDef->iType) + { + hr = GetUserAccountName(pItm->pwzValue, &pItm->pwzValue); + ExitOnFailure(hr, "Failed to get user account name"); + } + + // add entry + ++*piCount; + if (*ppPropList) + pItm->pNext = *ppPropList; + *ppPropList = pItm; + pItm = NULL; + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + +LExit: + // clean up + if (pItm) + CpiPropertiesFreeList(pItm); + + ReleaseStr(pwzData); + + return hr; +} + +void CpiPropertiesFreeList( + CPI_PROPERTY* pList + ) +{ + while (pList) + { + ReleaseStr(pList->pwzValue); + + CPI_PROPERTY* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +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; +} + +HRESULT CpiBuildAccountName( + LPCWSTR pwzDomain, + LPCWSTR pwzName, + LPWSTR* ppwzAccount + ) +{ + HRESULT hr = S_OK; + + WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1]; + ::ZeroMemory(wzComputerName, sizeof(wzComputerName)); + + // if domain is '.', get computer name + if (0 == lstrcmpW(pwzDomain, L".")) + { + DWORD dwSize = countof(wzComputerName); + if (!::GetComputerNameW(wzComputerName, &dwSize)) + ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to get computer name"); + } + + // build account name + hr = StrAllocFormatted(ppwzAccount, L"%s\\%s", *wzComputerName ? wzComputerName : pwzDomain, pwzName); + ExitOnFailure(hr, "Failed to build domain user name"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetTempFileName( + LPWSTR* ppwzTempFile + ) +{ + HRESULT hr = S_OK; + + // get temp path + WCHAR wzTempPath[MAX_PATH]; + DWORD dw = ::GetTempPathW(countof(wzTempPath), wzTempPath); + if (countof(wzTempPath) <= dw) + ExitOnFailure(hr = E_FAIL, "TEMP directory path too long"); + + // get unique number + LARGE_INTEGER liCount; + if (!::QueryPerformanceCounter(&liCount)) + ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to query performance counter"); + + // create temp file name + hr = StrAllocFormatted(ppwzTempFile, L"%sCPI%I64X.tmp", wzTempPath, liCount.QuadPart); + ExitOnFailure(hr, "Failed to create temp file name string"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiCreateId( + LPWSTR pwzDest, + SIZE_T cchDest + ) +{ + HRESULT hr = S_OK; + + GUID guid; + + // create new guid + hr = ::CoCreateGuid(&guid); + ExitOnFailure(hr, "Failed to create new guid"); + + // convert guid to string + if (0 == ::StringFromGUID2(guid, pwzDest, (int)cchDest)) + ExitOnFailure(hr = E_FAIL, "Failed to convert guid to string"); + + hr = S_OK; + +LExit: + return hr; +} + +BOOL CpiIsInstalled( + INSTALLSTATE isInstalled + ) +{ + return INSTALLSTATE_LOCAL == isInstalled || INSTALLSTATE_SOURCE == isInstalled; +} + +BOOL CpiWillBeInstalled( + INSTALLSTATE isInstalled, + INSTALLSTATE isAction + ) +{ + return WcaIsInstalling(isInstalled, isAction) || + (CpiIsInstalled(isInstalled) && !WcaIsUninstalling(isInstalled, isAction)); +} + +HRESULT PcaGuidToRegFormat( + LPWSTR pwzGuid, + LPWSTR pwzDest, + SIZE_T cchDest + ) +{ + HRESULT hr = S_OK; + + GUID guid = GUID_NULL; + int cch = 0; + + WCHAR wz[39]; + ::ZeroMemory(wz, sizeof(wz)); + + cch = lstrlenW(pwzGuid); + + if (38 == cch && L'{' == pwzGuid[0] && L'}' == pwzGuid[37]) + StringCchCopyW(wz, countof(wz), pwzGuid); + else if (36 == cch) + StringCchPrintfW(wz, countof(wz), L"{%s}", pwzGuid); + else + ExitFunction1(hr = E_INVALIDARG); + + // convert string to guid + hr = ::CLSIDFromString(wz, &guid); + ExitOnFailure(hr, "Failed to parse guid string"); + + // convert guid to string + if (0 == ::StringFromGUID2(guid, pwzDest, (int)cchDest)) + ExitOnFailure(hr = E_FAIL, "Failed to convert guid to string"); + + hr = S_OK; + +LExit: + return hr; +} + + +// helper function definitions + +static HRESULT FindPropertyDefinition( + CPI_PROPERTY_DEFINITION* pPropDefList, + LPCWSTR pwzName, + CPI_PROPERTY_DEFINITION** ppPropDef + ) +{ + for (CPI_PROPERTY_DEFINITION* pItm = pPropDefList; pItm->pwzName; pItm++) + { + if (0 == lstrcmpW(pItm->pwzName, pwzName)) + { + *ppPropDef = pItm; + return S_OK; + } + } + + return S_FALSE; +} + +static HRESULT GetUserAccountName( + LPCWSTR pwzKey, + LPWSTR* ppwzAccount + ) +{ + HRESULT hr = S_OK; + + PMSIHANDLE hView, hRecKey, hRec; + + LPWSTR pwzDomain = NULL; + LPWSTR pwzName = NULL; + + // create parameter record + hRecKey = ::MsiCreateRecord(1); + ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); + hr = WcaSetRecordString(hRecKey, 1, pwzKey); + ExitOnFailure(hr, "Failed to set record string"); + + // open view + hr = WcaOpenView(vcsUserQuery, &hView); + ExitOnFailure(hr, "Failed to open view on User table"); + hr = WcaExecuteView(hView, hRecKey); + ExitOnFailure(hr, "Failed to execute view on User table"); + + // fetch record + hr = WcaFetchSingleRecord(hView, &hRec); + if (S_FALSE == hr) + ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "User not found, key: %S", pwzKey); + ExitOnFailure(hr, "Failed to fetch user record"); + + // get user domain + hr = WcaGetRecordFormattedString(hRec, uqDomain, &pwzDomain); + ExitOnFailure(hr, "Failed to get domain"); + + // get user name + hr = WcaGetRecordFormattedString(hRec, uqName, &pwzName); + ExitOnFailure(hr, "Failed to get name"); + + // build account name + hr = CpiBuildAccountName(pwzDomain, pwzName, ppwzAccount); + ExitOnFailure(hr, "Failed to build account name"); + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzDomain); + ReleaseStr(pwzName); + + return hr; +} diff --git a/src/ca/cputilsched.h b/src/ca/cputilsched.h new file mode 100644 index 00000000..61aaab84 --- /dev/null +++ b/src/ca/cputilsched.h @@ -0,0 +1,144 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +#define CPI_MAX_GUID 38 + +enum eRunMode { rmDeferred = 1, rmCommit, rmRollback }; + +enum eActionType { atNoOp = 0, atCreate, atRemove }; + +enum eComPlusPropertyType { cpptNone = 0, cpptBoolean, cpptInteger, cpptString, cpptUser }; + +enum eComPlusTables +{ + cptComPlusPartition = (1 << 0), + cptComPlusPartitionProperty = (1 << 1), + cptComPlusPartitionRole = (1 << 2), + cptComPlusUserInPartitionRole = (1 << 3), + cptComPlusGroupInPartitionRole = (1 << 4), + cptComPlusPartitionUser = (1 << 5), + cptComPlusApplication = (1 << 6), + cptComPlusApplicationProperty = (1 << 7), + cptComPlusApplicationRole = (1 << 8), + cptComPlusApplicationRoleProperty = (1 << 9), + cptComPlusUserInApplicationRole = (1 << 10), + cptComPlusGroupInApplicationRole = (1 << 11), + cptComPlusAssembly = (1 << 12), + cptComPlusAssemblyDependency = (1 << 13), + cptComPlusComponent = (1 << 14), + cptComPlusComponentProperty = (1 << 15), + cptComPlusRoleForComponent = (1 << 16), + cptComPlusInterface = (1 << 17), + cptComPlusInterfaceProperty = (1 << 18), + cptComPlusRoleForInterface = (1 << 19), + cptComPlusMethod = (1 << 20), + cptComPlusMethodProperty = (1 << 21), + cptComPlusRoleForMethod = (1 << 22), + cptComPlusSubscription = (1 << 23), + cptComPlusSubscriptionProperty = (1 << 24) +}; + + +// structs + +struct CPI_PROPERTY +{ + WCHAR wzName[MAX_DARWIN_KEY + 1]; + LPWSTR pwzValue; + + CPI_PROPERTY* pNext; +}; + +struct CPI_PROPERTY_DEFINITION +{ + LPCWSTR pwzName; + int iType; + int iMinVersionNT; +}; + + +// function prototypes + +void CpiInitialize(); +void CpiFinalize(); +BOOL CpiTableExists( + int iTable + ); +HRESULT CpiGetAdminCatalog( + ICOMAdminCatalog** ppiCatalog + ); +HRESULT CpiGetCatalogCollection( + LPCWSTR pwzName, + ICatalogCollection** ppiColl + ); +HRESULT CpiGetCatalogCollection( + ICatalogCollection* piColl, + ICatalogObject* piObj, + LPCWSTR pwzName, + ICatalogCollection** ppiColl + ); +HRESULT CpiGetKeyForObject( + ICatalogObject* piObj, + LPWSTR pwzKey, + SIZE_T cchKey + ); +HRESULT CpiFindCollectionObject( + ICatalogCollection* piColl, + LPCWSTR pwzID, + LPCWSTR pwzName, + ICatalogObject** ppiObj + ); +HRESULT CpiGetPartitionsCollection( + ICatalogCollection** ppiPartColl + ); +HRESULT CpiGetApplicationsCollection( + ICatalogCollection** ppiAppColl + ); +HRESULT CpiAddActionTextToActionData( + LPCWSTR pwzAction, + LPWSTR* ppwzActionData + ); +HRESULT CpiVerifyComponentArchitecure( + LPCWSTR pwzComponent, + BOOL* pfMatchingArchitecture + ); +HRESULT CpiPropertiesRead( + LPCWSTR pwzQuery, + LPCWSTR pwzKey, + CPI_PROPERTY_DEFINITION* pPropDefList, + CPI_PROPERTY** ppPropList, + int* piCount + ); +void CpiPropertiesFreeList( + CPI_PROPERTY* pList + ); +HRESULT CpiAddPropertiesToActionData( + int iPropCount, + CPI_PROPERTY* pPropList, + LPWSTR* ppwzActionData + ); +HRESULT CpiBuildAccountName( + LPCWSTR pwzDomain, + LPCWSTR pwzName, + LPWSTR* ppwzAccount + ); +HRESULT CpiGetTempFileName( + LPWSTR* ppwzTempFile + ); +HRESULT CpiCreateId( + LPWSTR pwzDest, + SIZE_T cchDest + ); +BOOL CpiIsInstalled( + INSTALLSTATE isInstalled + ); +BOOL CpiWillBeInstalled( + INSTALLSTATE isInstalled, + INSTALLSTATE isAction + ); +HRESULT PcaGuidToRegFormat( + LPWSTR pwzGuid, + LPWSTR pwzDest, + SIZE_T cchDest + ); diff --git a/src/wixext/ComPlusCompiler.cs b/src/wixext/ComPlusCompiler.cs new file mode 100644 index 00000000..7f22c56b --- /dev/null +++ b/src/wixext/ComPlusCompiler.cs @@ -0,0 +1,2188 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Extensions +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Globalization; + using System.Reflection; + using System.Xml; + using System.Xml.Linq; + using System.Xml.Schema; + using WixToolset.Data; + using WixToolset.Extensibility; + + /// + /// The compiler for the WiX Toolset Internet Information Services Extension. + /// + public sealed class ComPlusCompiler : CompilerExtension + { + /// + /// Instantiate a new ComPlusCompiler. + /// + public ComPlusCompiler() + { + this.Namespace = "http://wixtoolset.org/schemas/v4/wxs/complus"; + } + + /// + /// + /// + public enum CpiAssemblyAttributes + { + EventClass = (1 << 0), + DotNetAssembly = (1 << 1), + DllPathFromGAC = (1 << 2), + RegisterInCommit = (1 << 3) + } + + /// + /// Processes an element for the Compiler. + /// + /// Source line number for the parent element. + /// Parent element of element to process. + /// Element to process. + /// Extra information about the context in which this element is being parsed. + public override void ParseElement(XElement parentElement, XElement element, IDictionary context) + { + switch (parentElement.Name.LocalName) + { + case "Component": + string componentId = context["ComponentId"]; + string directoryId = context["DirectoryId"]; + bool win64 = Boolean.Parse(context["Win64"]); + + switch (element.Name.LocalName) + { + case "ComPlusPartition": + this.ParseComPlusPartitionElement(element, componentId, win64); + break; + case "ComPlusPartitionRole": + this.ParseComPlusPartitionRoleElement(element, componentId, null); + break; + case "ComPlusUserInPartitionRole": + this.ParseComPlusUserInPartitionRoleElement(element, componentId, null); + break; + case "ComPlusGroupInPartitionRole": + this.ParseComPlusGroupInPartitionRoleElement(element, componentId, null); + break; + case "ComPlusPartitionUser": + this.ParseComPlusPartitionUserElement(element, componentId, null); + break; + case "ComPlusApplication": + this.ParseComPlusApplicationElement(element, componentId, win64, null); + break; + case "ComPlusApplicationRole": + this.ParseComPlusApplicationRoleElement(element, componentId, null); + break; + case "ComPlusUserInApplicationRole": + this.ParseComPlusUserInApplicationRoleElement(element, componentId, null); + break; + case "ComPlusGroupInApplicationRole": + this.ParseComPlusGroupInApplicationRoleElement(element, componentId, null); + break; + case "ComPlusAssembly": + this.ParseComPlusAssemblyElement(element, componentId, win64, null); + break; + case "ComPlusRoleForComponent": + this.ParseComPlusRoleForComponentElement(element, componentId, null); + break; + case "ComPlusRoleForInterface": + this.ParseComPlusRoleForInterfaceElement(element, componentId, null); + break; + case "ComPlusRoleForMethod": + this.ParseComPlusRoleForMethodElement(element, componentId, null); + break; + case "ComPlusSubscription": + this.ParseComPlusSubscriptionElement(element, componentId, null); + break; + default: + this.Core.UnexpectedElement(parentElement, element); + break; + } + break; + case "Fragment": + case "Module": + case "Product": + switch (element.Name.LocalName) + { + case "ComPlusPartition": + this.ParseComPlusPartitionElement(element, null, false); + break; + case "ComPlusPartitionRole": + this.ParseComPlusPartitionRoleElement(element, null, null); + break; + case "ComPlusApplication": + this.ParseComPlusApplicationElement(element, null, false, null); + break; + case "ComPlusApplicationRole": + this.ParseComPlusApplicationRoleElement(element, null, null); + break; + default: + this.Core.UnexpectedElement(parentElement, element); + break; + } + break; + default: + this.Core.UnexpectedElement(parentElement, element); + break; + } + } + + /// + /// Parses a COM+ partition element. + /// + /// Element to parse. + /// Identifier of parent component. + private void ParseComPlusPartitionElement(XElement node, string componentKey, bool win64) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string id = null; + string name = null; + + Hashtable properties = new Hashtable(); + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "PartitionId": + id = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); + break; + case "Name": + name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Changeable": + this.Core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + break; + case "Deleteable": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["Deleteable"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "Description": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null != componentKey && null == name) + { + this.Core.OnMessage(ComPlusErrors.RequiredAttributeUnderComponent(sourceLineNumbers, node.Name.LocalName, "Name")); + } + if (null == componentKey && null == id && null == name) + { + this.Core.OnMessage(ComPlusErrors.RequiredAttributeNotUnderComponent(sourceLineNumbers, node.Name.LocalName, "Id", "Name")); + } + + foreach (XElement child in node.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "ComPlusPartitionRole": + this.ParseComPlusPartitionRoleElement(child, componentKey, key); + break; + case "ComPlusPartitionUser": + this.ParseComPlusPartitionUserElement(child, componentKey, key); + break; + case "ComPlusApplication": + this.ParseComPlusApplicationElement(child, componentKey, win64, key); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child); + } + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusPartition"); + row[0] = key; + row[1] = componentKey; + row[2] = id; + row[3] = name; + + IDictionaryEnumerator propertiesEnumerator = properties.GetEnumerator(); + while (propertiesEnumerator.MoveNext()) + { + Row propertyRow = this.Core.CreateRow(sourceLineNumbers, "ComPlusPartitionProperty"); + propertyRow[0] = key; + propertyRow[1] = (string)propertiesEnumerator.Key; + propertyRow[2] = (string)propertiesEnumerator.Value; + } + + if (componentKey != null) + { + if (win64) + { + if (this.Core.CurrentPlatform == Platform.IA64) + { + this.Core.OnMessage(WixErrors.UnsupportedPlatformForElement(sourceLineNumbers, "ia64", node.Name.LocalName)); + } + else + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall_x64"); + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall_x64"); + } + } + else + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall"); + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall"); + } + } + } + + /// + /// Parses a COM+ partition role element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Optional identifier of parent application. + private void ParseComPlusPartitionRoleElement(XElement node, string componentKey, string partitionKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string name = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Partition": + if (null != partitionKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + partitionKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusPartition", partitionKey); + break; + case "Name": + name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == partitionKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Partition")); + } + + foreach (XElement child in node.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "ComPlusUserInPartitionRole": + this.ParseComPlusUserInPartitionRoleElement(child, componentKey, key); + break; + case "ComPlusGroupInPartitionRole": + this.ParseComPlusGroupInPartitionRoleElement(child, componentKey, key); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child); + } + } + + // add table row + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusPartitionRole"); + row[0] = key; + row[1] = partitionKey; + row[3] = name; + } + + /// + /// Parses a COM+ partition role user element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Optional identifier of parent application role. + private void ParseComPlusUserInPartitionRoleElement(XElement node, string componentKey, string partitionRoleKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string user = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "PartitionRole": + if (null != partitionRoleKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + partitionRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusPartitionRole", partitionRoleKey); + break; + case "User": + user = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "User", user); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == partitionRoleKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "PartitionRole")); + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusUserInPartitionRole"); + row[0] = key; + row[1] = partitionRoleKey; + row[2] = componentKey; + row[3] = user; + } + + /// + /// Parses a COM+ partition role user element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Optional identifier of parent application role. + private void ParseComPlusGroupInPartitionRoleElement(XElement node, string componentKey, string partitionRoleKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string group = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "PartitionRole": + if (null != partitionRoleKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + partitionRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusPartitionRole", partitionRoleKey); + break; + case "Group": + group = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "Group", group); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == partitionRoleKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "PartitionRole")); + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusGroupInPartitionRole"); + row[0] = key; + row[1] = partitionRoleKey; + row[2] = componentKey; + row[3] = group; + } + + /// + /// Parses a COM+ partition element. + /// + /// Element to parse. + /// Identifier of parent component. + private void ParseComPlusPartitionUserElement(XElement node, string componentKey, string partitionKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string user = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Partition": + if (null != partitionKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + partitionKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusPartition", partitionKey); + break; + case "User": + user = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "User", user); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == partitionKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Partition")); + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusPartitionUser"); + row[0] = key; + row[1] = partitionKey; + row[2] = componentKey; + row[3] = user; + } + + /// + /// Parses a COM+ application element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Optional identifier of parent partition. + private void ParseComPlusApplicationElement(XElement node, string componentKey, bool win64, string partitionKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string id = null; + string name = null; + + Hashtable properties = new Hashtable(); + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Partition": + if (null != partitionKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + partitionKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusPartition", partitionKey); + break; + case "ApplicationId": + id = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); + break; + case "Name": + name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ThreeGigSupportEnabled": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["3GigSupportEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "AccessChecksLevel": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + string accessChecksLevelValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (accessChecksLevelValue) + { + case "applicationLevel": + properties["AccessChecksLevel"] = "0"; + break; + case "applicationComponentLevel": + properties["AccessChecksLevel"] = "1"; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "AccessChecksLevel", accessChecksLevelValue, "applicationLevel", "applicationComponentLevel")); + break; + } + break; + case "Activation": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + string activationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (activationValue) + { + case "inproc": + properties["Activation"] = "Inproc"; + break; + case "local": + properties["Activation"] = "Local"; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "Activation", activationValue, "inproc", "local")); + break; + } + break; + case "ApplicationAccessChecksEnabled": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["ApplicationAccessChecksEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "ApplicationDirectory": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["ApplicationDirectory"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Authentication": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + string authenticationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (authenticationValue) + { + case "default": + properties["Authentication"] = "0"; + break; + case "none": + properties["Authentication"] = "1"; + break; + case "connect": + properties["Authentication"] = "2"; + break; + case "call": + properties["Authentication"] = "3"; + break; + case "packet": + properties["Authentication"] = "4"; + break; + case "integrity": + properties["Authentication"] = "5"; + break; + case "privacy": + properties["Authentication"] = "6"; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "Authentication", authenticationValue, "default", "none", "connect", "call", "packet", "integrity", "privacy")); + break; + } + break; + case "AuthenticationCapability": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + string authenticationCapabilityValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (authenticationCapabilityValue) + { + case "none": + properties["AuthenticationCapability"] = "0"; + break; + case "secureReference": + properties["AuthenticationCapability"] = "2"; + break; + case "staticCloaking": + properties["AuthenticationCapability"] = "32"; + break; + case "dynamicCloaking": + properties["AuthenticationCapability"] = "64"; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "AuthenticationCapability", authenticationCapabilityValue, "none", "secureReference", "staticCloaking", "dynamicCloaking")); + break; + } + break; + case "Changeable": + this.Core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + break; + case "CommandLine": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["CommandLine"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ConcurrentApps": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["ConcurrentApps"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "CreatedBy": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["CreatedBy"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "CRMEnabled": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["CRMEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "CRMLogFile": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["CRMLogFile"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Deleteable": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["Deleteable"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "Description": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "DumpEnabled": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["DumpEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "DumpOnException": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["DumpOnException"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "DumpOnFailfast": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["DumpOnFailfast"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "DumpPath": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["DumpPath"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "EventsEnabled": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["EventsEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "Identity": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["Identity"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ImpersonationLevel": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + string impersonationLevelValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (impersonationLevelValue) + { + case "anonymous": + properties["ImpersonationLevel"] = "1"; + break; + case "identify": + properties["ImpersonationLevel"] = "2"; + break; + case "impersonate": + properties["ImpersonationLevel"] = "3"; + break; + case "delegate": + properties["ImpersonationLevel"] = "4"; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "ImpersonationLevel", impersonationLevelValue, "anonymous", "identify", "impersonate", "delegate")); + break; + } + break; + case "IsEnabled": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["IsEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "MaxDumpCount": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["MaxDumpCount"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Password": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["Password"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "QCAuthenticateMsgs": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + string qcAuthenticateMsgsValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (qcAuthenticateMsgsValue) + { + case "secureApps": + properties["QCAuthenticateMsgs"] = "0"; + break; + case "off": + properties["QCAuthenticateMsgs"] = "1"; + break; + case "on": + properties["QCAuthenticateMsgs"] = "2"; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "QCAuthenticateMsgs", qcAuthenticateMsgsValue, "secureApps", "off", "on")); + break; + } + break; + case "QCListenerMaxThreads": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["QCListenerMaxThreads"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "QueueListenerEnabled": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["QueueListenerEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "QueuingEnabled": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["QueuingEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "RecycleActivationLimit": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["RecycleActivationLimit"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "RecycleCallLimit": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["RecycleCallLimit"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "RecycleExpirationTimeout": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["RecycleExpirationTimeout"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "RecycleLifetimeLimit": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["RecycleLifetimeLimit"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "RecycleMemoryLimit": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["RecycleMemoryLimit"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Replicable": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["Replicable"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "RunForever": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["RunForever"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "ShutdownAfter": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["ShutdownAfter"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "SoapActivated": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["SoapActivated"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "SoapBaseUrl": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["SoapBaseUrl"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "SoapMailTo": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["SoapMailTo"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "SoapVRoot": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["SoapVRoot"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "SRPEnabled": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["SRPEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "SRPTrustLevel": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + string srpTrustLevelValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (srpTrustLevelValue) + { + case "disallowed": + properties["SRPTrustLevel"] = "0"; + break; + case "fullyTrusted": + properties["SRPTrustLevel"] = "262144"; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "SRPTrustLevel", srpTrustLevelValue, "disallowed", "fullyTrusted")); + break; + } + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null != componentKey && null == name) + { + this.Core.OnMessage(ComPlusErrors.RequiredAttributeUnderComponent(sourceLineNumbers, node.Name.LocalName, "Name")); + } + if (null == componentKey && null == id && null == name) + { + this.Core.OnMessage(ComPlusErrors.RequiredAttributeNotUnderComponent(sourceLineNumbers, node.Name.LocalName, "Id", "Name")); + } + + foreach (XElement child in node.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "ComPlusApplicationRole": + this.ParseComPlusApplicationRoleElement(child, componentKey, key); + break; + case "ComPlusAssembly": + this.ParseComPlusAssemblyElement(child, componentKey, win64, key); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child); + } + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusApplication"); + row[0] = key; + row[1] = partitionKey; + row[2] = componentKey; + row[3] = id; + row[4] = name; + + IDictionaryEnumerator propertiesEnumerator = properties.GetEnumerator(); + while (propertiesEnumerator.MoveNext()) + { + Row propertyRow = this.Core.CreateRow(sourceLineNumbers, "ComPlusApplicationProperty"); + propertyRow[0] = key; + propertyRow[1] = (string)propertiesEnumerator.Key; + propertyRow[2] = (string)propertiesEnumerator.Value; + } + + if (componentKey != null) + { + if (win64) + { + if (this.Core.CurrentPlatform == Platform.IA64) + { + this.Core.OnMessage(WixErrors.UnsupportedPlatformForElement(sourceLineNumbers, "ia64", node.Name.LocalName)); + } + else + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall_x64"); + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall_x64"); + } + } + else + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall"); + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall"); + } + } + } + + /// + /// Parses a COM+ application role element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Optional identifier of parent application. + private void ParseComPlusApplicationRoleElement(XElement node, string componentKey, string applicationKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string name = null; + + Hashtable properties = new Hashtable(); + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Application": + if (null != applicationKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + applicationKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusApplication", applicationKey); + break; + case "Name": + name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Description": + if (null == componentKey) + { + this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + } + properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == applicationKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Application")); + } + + foreach (XElement child in node.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "ComPlusUserInApplicationRole": + this.ParseComPlusUserInApplicationRoleElement(child, componentKey, key); + break; + case "ComPlusGroupInApplicationRole": + this.ParseComPlusGroupInApplicationRoleElement(child, componentKey, key); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child); + } + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusApplicationRole"); + row[0] = key; + row[1] = applicationKey; + row[2] = componentKey; + row[3] = name; + + IDictionaryEnumerator propertiesEnumerator = properties.GetEnumerator(); + while (propertiesEnumerator.MoveNext()) + { + Row propertyRow = this.Core.CreateRow(sourceLineNumbers, "ComPlusApplicationRoleProperty"); + propertyRow[0] = key; + propertyRow[1] = (string)propertiesEnumerator.Key; + propertyRow[2] = (string)propertiesEnumerator.Value; + } + } + + /// + /// Parses a COM+ application role user element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Optional identifier of parent application role. + private void ParseComPlusUserInApplicationRoleElement(XElement node, string componentKey, string applicationRoleKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string user = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "ApplicationRole": + if (null != applicationRoleKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + applicationRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusApplicationRole", applicationRoleKey); + break; + case "User": + user = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "User", user); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == applicationRoleKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ApplicationRole")); + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusUserInApplicationRole"); + row[0] = key; + row[1] = applicationRoleKey; + row[2] = componentKey; + row[3] = user; + } + + /// + /// Parses a COM+ application role group element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Optional identifier of parent application role. + private void ParseComPlusGroupInApplicationRoleElement(XElement node, string componentKey, string applicationRoleKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string group = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "ApplicationRole": + if (null != applicationRoleKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + applicationRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusApplicationRole", applicationRoleKey); + break; + case "Group": + group = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "Group", group); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == applicationRoleKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ApplicationRole")); + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusGroupInApplicationRole"); + row[0] = key; + row[1] = applicationRoleKey; + row[2] = componentKey; + row[3] = group; + } + + /// + /// Parses a COM+ assembly element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Optional identifier of parent application. + private void ParseComPlusAssemblyElement(XElement node, string componentKey, bool win64, string applicationKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string assemblyName = null; + string dllPath = null; + string tlbPath = null; + string psDllPath = null; + int attributes = 0; + + bool hasComponents = false; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Application": + if (null != applicationKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + applicationKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusApplication", applicationKey); + break; + case "AssemblyName": + assemblyName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "DllPath": + dllPath = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "TlbPath": + tlbPath = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "PSDllPath": + psDllPath = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Type": + string typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (typeValue) + { + case ".net": + attributes |= (int)CpiAssemblyAttributes.DotNetAssembly; + break; + case "native": + attributes &= ~(int)CpiAssemblyAttributes.DotNetAssembly; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusAssembly", "Type", typeValue, ".net", "native")); + break; + } + break; + case "EventClass": + if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= (int)CpiAssemblyAttributes.EventClass; + } + else + { + attributes &= ~(int)CpiAssemblyAttributes.EventClass; + } + break; + case "DllPathFromGAC": + if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= (int)CpiAssemblyAttributes.DllPathFromGAC; + } + else + { + attributes &= ~(int)CpiAssemblyAttributes.DllPathFromGAC; + } + break; + case "RegisterInCommit": + if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= (int)CpiAssemblyAttributes.RegisterInCommit; + } + else + { + attributes &= ~(int)CpiAssemblyAttributes.RegisterInCommit; + } + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == applicationKey && 0 == (attributes & (int)CpiAssemblyAttributes.DotNetAssembly)) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Application", "Type", "native")); + } + if (null != assemblyName && 0 == (attributes & (int)CpiAssemblyAttributes.DllPathFromGAC)) + { + this.Core.OnMessage(ComPlusErrors.UnexpectedAttributeWithoutOtherValue(sourceLineNumbers, node.Name.LocalName, "AssemblyName", "DllPathFromGAC", "no")); + } + if (null == tlbPath && 0 != (attributes & (int)CpiAssemblyAttributes.DotNetAssembly)) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "TlbPath", "Type", ".net")); + } + if (null != psDllPath && 0 != (attributes & (int)CpiAssemblyAttributes.DotNetAssembly)) + { + this.Core.OnMessage(ComPlusErrors.UnexpectedAttributeWithOtherValue(sourceLineNumbers, node.Name.LocalName, "PSDllPath", "Type", ".net")); + } + if (0 != (attributes & (int)CpiAssemblyAttributes.EventClass) && 0 != (attributes & (int)CpiAssemblyAttributes.DotNetAssembly)) + { + this.Core.OnMessage(ComPlusErrors.UnexpectedAttributeWithOtherValue(sourceLineNumbers, node.Name.LocalName, "EventClass", "yes", "Type", ".net")); + } + + foreach (XElement child in node.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "ComPlusAssemblyDependency": + this.ParseComPlusAssemblyDependencyElement(child, key); + break; + case "ComPlusComponent": + this.ParseComPlusComponentElement(child, componentKey, key); + hasComponents = true; + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child); + } + } + + if (0 == (attributes & (int)CpiAssemblyAttributes.DotNetAssembly) && !hasComponents) + { + this.Core.OnMessage(ComPlusWarnings.MissingComponents(sourceLineNumbers)); + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusAssembly"); + row[0] = key; + row[1] = applicationKey; + row[2] = componentKey; + row[3] = assemblyName; + row[4] = dllPath; + row[5] = tlbPath; + row[6] = psDllPath; + row[7] = attributes; + + if (win64) + { + if (this.Core.CurrentPlatform == Platform.IA64) + { + this.Core.OnMessage(WixErrors.UnsupportedPlatformForElement(sourceLineNumbers, "ia64", node.Name.LocalName)); + } + else + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall_x64"); + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall_x64"); + } + } + else + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall"); + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall"); + } + } + + /// + /// Parses a COM+ assembly dependency element. + /// + /// Element to parse. + /// Identifier of parent assembly. + private void ParseComPlusAssemblyDependencyElement(XElement node, string assemblyKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string requiredAssemblyKey = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "RequiredAssembly": + requiredAssemblyKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusAssemblyDependency"); + row[0] = assemblyKey; + row[1] = requiredAssemblyKey; + } + + /// + /// Parses a COM+ component element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of parent assembly. + private void ParseComPlusComponentElement(XElement node, string componentKey, string assemblyKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string clsid = null; + + Hashtable properties = new Hashtable(); + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "CLSID": + clsid = "{" + this.Core.GetAttributeValue(sourceLineNumbers, attrib) + "}"; + break; + case "AllowInprocSubscribers": + properties["AllowInprocSubscribers"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "ComponentAccessChecksEnabled": + properties["ComponentAccessChecksEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "ComponentTransactionTimeout": + properties["ComponentTransactionTimeout"] = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 3600).ToString(); + break; + case "ComponentTransactionTimeoutEnabled": + properties["ComponentTransactionTimeoutEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "COMTIIntrinsics": + properties["COMTIIntrinsics"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "ConstructionEnabled": + properties["ConstructionEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "ConstructorString": + properties["ConstructorString"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "CreationTimeout": + properties["CreationTimeout"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Description": + properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "EventTrackingEnabled": + properties["EventTrackingEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "ExceptionClass": + properties["ExceptionClass"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "FireInParallel": + properties["FireInParallel"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "IISIntrinsics": + properties["IISIntrinsics"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "InitializesServerApplication": + properties["InitializesServerApplication"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "IsEnabled": + properties["IsEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "IsPrivateComponent": + properties["IsPrivateComponent"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "JustInTimeActivation": + properties["JustInTimeActivation"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "LoadBalancingSupported": + properties["LoadBalancingSupported"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "MaxPoolSize": + properties["MaxPoolSize"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "MinPoolSize": + properties["MinPoolSize"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "MultiInterfacePublisherFilterCLSID": + properties["MultiInterfacePublisherFilterCLSID"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "MustRunInClientContext": + properties["MustRunInClientContext"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "MustRunInDefaultContext": + properties["MustRunInDefaultContext"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "ObjectPoolingEnabled": + properties["ObjectPoolingEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "PublisherID": + properties["PublisherID"] = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); + break; + case "SoapAssemblyName": + properties["SoapAssemblyName"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "SoapTypeName": + properties["SoapTypeName"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Synchronization": + string synchronizationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (synchronizationValue) + { + case "ignored": + properties["Synchronization"] = "0"; + break; + case "none": + properties["Synchronization"] = "1"; + break; + case "supported": + properties["Synchronization"] = "2"; + break; + case "required": + properties["Synchronization"] = "3"; + break; + case "requiresNew": + properties["Synchronization"] = "4"; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusComponent", "Synchronization", synchronizationValue, "ignored", "none", "supported", "required", "requiresNew")); + break; + } + break; + case "Transaction": + string transactionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (transactionValue) + { + case "ignored": + properties["Transaction"] = "0"; + break; + case "none": + properties["Transaction"] = "1"; + break; + case "supported": + properties["Transaction"] = "2"; + break; + case "required": + properties["Transaction"] = "3"; + break; + case "requiresNew": + properties["Transaction"] = "4"; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusComponent", "Transaction", transactionValue, "ignored", "none", "supported", "required", "requiresNew")); + break; + } + break; + case "TxIsolationLevel": + string txIsolationLevelValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (txIsolationLevelValue) + { + case "any": + properties["TxIsolationLevel"] = "0"; + break; + case "readUnCommitted": + properties["TxIsolationLevel"] = "1"; + break; + case "readCommitted": + properties["TxIsolationLevel"] = "2"; + break; + case "repeatableRead": + properties["TxIsolationLevel"] = "3"; + break; + case "serializable": + properties["TxIsolationLevel"] = "4"; + break; + default: + this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusComponent", "TxIsolationLevel", txIsolationLevelValue, "any", "readUnCommitted", "readCommitted", "repeatableRead", "serializable")); + break; + } + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + foreach (XElement child in node.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "ComPlusRoleForComponent": + this.ParseComPlusRoleForComponentElement(child, componentKey, key); + break; + case "ComPlusInterface": + this.ParseComPlusInterfaceElement(child, componentKey, key); + break; + case "ComPlusSubscription": + this.ParseComPlusSubscriptionElement(child, componentKey, key); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child); + } + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusComponent"); + row[0] = key; + row[1] = assemblyKey; + row[2] = clsid; + + IDictionaryEnumerator propertiesEnumerator = properties.GetEnumerator(); + while (propertiesEnumerator.MoveNext()) + { + Row propertyRow = this.Core.CreateRow(sourceLineNumbers, "ComPlusComponentProperty"); + propertyRow[0] = key; + propertyRow[1] = (string)propertiesEnumerator.Key; + propertyRow[2] = (string)propertiesEnumerator.Value; + } + } + + /// + /// Parses a COM+ application role for component element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of parent COM+ component. + private void ParseComPlusRoleForComponentElement(XElement node, string componentKey, string cpcomponentKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string applicationRoleKey = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Component": + if (null != cpcomponentKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + cpcomponentKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusComponent", cpcomponentKey); + break; + case "ApplicationRole": + applicationRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == cpcomponentKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Component")); + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusRoleForComponent"); + row[0] = key; + row[1] = cpcomponentKey; + row[2] = applicationRoleKey; + row[3] = componentKey; + } + + /// + /// Parses a COM+ interface element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of parent COM+ component. + private void ParseComPlusInterfaceElement(XElement node, string componentKey, string cpcomponentKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + // parse attributes + string key = null; + string iid = null; + + Hashtable properties = new Hashtable(); + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "IID": + iid = "{" + this.Core.GetAttributeValue(sourceLineNumbers, attrib) + "}"; + break; + case "Description": + properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "QueuingEnabled": + properties["QueuingEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + foreach (XElement child in node.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "ComPlusRoleForInterface": + this.ParseComPlusRoleForInterfaceElement(child, componentKey, key); + break; + case "ComPlusMethod": + this.ParseComPlusMethodElement(child, componentKey, key); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child); + } + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusInterface"); + row[0] = key; + row[1] = cpcomponentKey; + row[2] = iid; + + IDictionaryEnumerator propertiesEnumerator = properties.GetEnumerator(); + while (propertiesEnumerator.MoveNext()) + { + Row propertyRow = this.Core.CreateRow(sourceLineNumbers, "ComPlusInterfaceProperty"); + propertyRow[0] = key; + propertyRow[1] = (string)propertiesEnumerator.Key; + propertyRow[2] = (string)propertiesEnumerator.Value; + } + } + + /// + /// Parses a COM+ application role for interface element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of parent interface. + private void ParseComPlusRoleForInterfaceElement(XElement node, string componentKey, string interfaceKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string applicationRoleKey = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Interface": + if (null != interfaceKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + interfaceKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusInterface", interfaceKey); + break; + case "ApplicationRole": + applicationRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == interfaceKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Interface")); + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusRoleForInterface"); + row[0] = key; + row[1] = interfaceKey; + row[2] = applicationRoleKey; + row[3] = componentKey; + } + + /// + /// Parses a COM+ method element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of parent interface. + private void ParseComPlusMethodElement(XElement node, string componentKey, string interfaceKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + int index = CompilerConstants.IntegerNotSet; + string name = null; + + Hashtable properties = new Hashtable(); + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Index": + index = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); + break; + case "Name": + name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "AutoComplete": + properties["AutoComplete"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "Description": + properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + foreach (XElement child in node.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "ComPlusRoleForMethod": + this.ParseComPlusRoleForMethodElement(child, componentKey, key); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child); + } + } + + if (CompilerConstants.IntegerNotSet == index && null == name) + { + this.Core.OnMessage(ComPlusErrors.RequiredAttribute(sourceLineNumbers, node.Name.LocalName, "Index", "Name")); + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusMethod"); + row[0] = key; + row[1] = interfaceKey; + if (CompilerConstants.IntegerNotSet != index) + { + row[2] = index; + } + row[3] = name; + + IDictionaryEnumerator propertiesEnumerator = properties.GetEnumerator(); + while (propertiesEnumerator.MoveNext()) + { + Row propertyRow = this.Core.CreateRow(sourceLineNumbers, "ComPlusMethodProperty"); + propertyRow[0] = key; + propertyRow[1] = (string)propertiesEnumerator.Key; + propertyRow[2] = (string)propertiesEnumerator.Value; + } + } + + /// + /// Parses a COM+ application role for method element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of parent method. + private void ParseComPlusRoleForMethodElement(XElement node, string componentKey, string methodKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string applicationRoleKey = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Method": + if (null != methodKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + methodKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusMethod", methodKey); + break; + case "ApplicationRole": + applicationRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == methodKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Method")); + } + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusRoleForMethod"); + row[0] = key; + row[1] = methodKey; + row[2] = applicationRoleKey; + row[3] = componentKey; + } + + /// + /// Parses a COM+ event subscription element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of parent COM+ component. + private void ParseComPlusSubscriptionElement(XElement node, string componentKey, string cpcomponentKey) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + + string key = null; + string id = null; + string name = null; + string eventCLSID = null; + string publisherID = null; + + Hashtable properties = new Hashtable(); + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Component": + if (null != cpcomponentKey) + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); + } + cpcomponentKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusComponent", cpcomponentKey); + break; + case "SubscriptionId": + id = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); + break; + case "Name": + name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "EventCLSID": + eventCLSID = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "PublisherID": + publisherID = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); + break; + case "Description": + properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Enabled": + properties["Enabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "EventClassPartitionID": + properties["EventClassPartitionID"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "FilterCriteria": + properties["FilterCriteria"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "InterfaceID": + properties["InterfaceID"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "MachineName": + properties["MachineName"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "MethodName": + properties["MethodName"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "PerUser": + properties["PerUser"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "Queued": + properties["Queued"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + break; + case "SubscriberMoniker": + properties["SubscriberMoniker"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "UserName": + properties["UserName"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == cpcomponentKey) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Component")); + } + + this.Core.ParseForExtensionElements(node); + + Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusSubscription"); + row[0] = key; + row[1] = cpcomponentKey; + row[2] = componentKey; + row[3] = id; + row[4] = name; + row[5] = eventCLSID; + row[6] = publisherID; + + IDictionaryEnumerator propertiesEnumerator = properties.GetEnumerator(); + while (propertiesEnumerator.MoveNext()) + { + Row propertyRow = this.Core.CreateRow(sourceLineNumbers, "ComPlusSubscriptionProperty"); + propertyRow[0] = key; + propertyRow[1] = (string)propertiesEnumerator.Key; + propertyRow[2] = (string)propertiesEnumerator.Value; + } + } + + /// + /// Attempts to parse the input value as a GUID, and in case the value is a valid + /// GUID returnes it in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}". + /// + /// + /// + string TryFormatGuidValue(string val) + { + try + { + Guid guid = new Guid(val); + return guid.ToString("B").ToUpper(); + } + catch (FormatException) + { + return val; + } + catch (OverflowException) + { + return val; + } + } + } +} diff --git a/src/wixext/ComPlusDecompiler.cs b/src/wixext/ComPlusDecompiler.cs new file mode 100644 index 00000000..27f1653e --- /dev/null +++ b/src/wixext/ComPlusDecompiler.cs @@ -0,0 +1,1843 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Extensions +{ + using System; + using System.Collections; + using System.Globalization; + using WixToolset.Data; + using WixToolset.Extensibility; + using ComPlus = WixToolset.Extensions.Serialize.ComPlus; + using Wix = WixToolset.Data.Serialize; + + /// + /// The decompiler for the WiX Toolset COM+ Extension. + /// + public sealed class ComPlusDecompiler : DecompilerExtension + { + /// + /// Creates a decompiler for ComPlus Extension. + /// + public ComPlusDecompiler() + { + this.TableDefinitions = ComPlusExtensionData.GetExtensionTableDefinitions(); + } + + /// + /// Get the extensions library to be removed. + /// + /// Table definitions for library. + /// Library to remove from decompiled output. + public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions) + { + return ComPlusExtensionData.GetExtensionLibrary(tableDefinitions); + } + + /// + /// Decompiles an extension table. + /// + /// The table to decompile. + public override void DecompileTable(Table table) + { + switch (table.Name) + { + case "ComPlusPartition": + this.DecompileComPlusPartitionTable(table); + break; + case "ComPlusPartitionProperty": + this.DecompileComPlusPartitionPropertyTable(table); + break; + case "ComPlusPartitionRole": + this.DecompileComPlusPartitionRoleTable(table); + break; + case "ComPlusUserInPartitionRole": + this.DecompileComPlusUserInPartitionRoleTable(table); + break; + case "ComPlusGroupInPartitionRole": + this.DecompileComPlusGroupInPartitionRoleTable(table); + break; + case "ComPlusPartitionUser": + this.DecompileComPlusPartitionUserTable(table); + break; + case "ComPlusApplication": + this.DecompileComPlusApplicationTable(table); + break; + case "ComPlusApplicationProperty": + this.DecompileComPlusApplicationPropertyTable(table); + break; + case "ComPlusApplicationRole": + this.DecompileComPlusApplicationRoleTable(table); + break; + case "ComPlusApplicationRoleProperty": + this.DecompileComPlusApplicationRolePropertyTable(table); + break; + case "ComPlusUserInApplicationRole": + this.DecompileComPlusUserInApplicationRoleTable(table); + break; + case "ComPlusGroupInApplicationRole": + this.DecompileComPlusGroupInApplicationRoleTable(table); + break; + case "ComPlusAssembly": + this.DecompileComPlusAssemblyTable(table); + break; + case "ComPlusComponent": + this.DecompileComPlusComponentTable(table); + break; + case "ComPlusComponentProperty": + this.DecompileComPlusComponentPropertyTable(table); + break; + case "ComPlusRoleForComponent": + this.DecompileComPlusRoleForComponentTable(table); + break; + case "ComPlusInterface": + this.DecompileComPlusInterfaceTable(table); + break; + case "ComPlusInterfaceProperty": + this.DecompileComPlusInterfacePropertyTable(table); + break; + case "ComPlusRoleForInterface": + this.DecompileComPlusRoleForInterfaceTable(table); + break; + case "ComPlusMethod": + this.DecompileComPlusMethodTable(table); + break; + case "ComPlusMethodProperty": + this.DecompileComPlusMethodPropertyTable(table); + break; + case "ComPlusRoleForMethod": + this.DecompileComPlusRoleForMethodTable(table); + break; + case "ComPlusSubscription": + this.DecompileComPlusSubscriptionTable(table); + break; + case "ComPlusSubscriptionProperty": + this.DecompileComPlusSubscriptionPropertyTable(table); + break; + default: + base.DecompileTable(table); + break; + } + } + + /// + /// Decompile the ComPlusPartition table. + /// + /// The table to decompile. + private void DecompileComPlusPartitionTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusPartition partition = new ComPlus.ComPlusPartition(); + + partition.Id = (string)row[0]; + + if (null != row[2]) + { + partition.PartitionId = (string)row[2]; + } + + if (null != row[3]) + { + partition.Name = (string)row[3]; + } + + if (null != row[1]) + { + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]); + if (null != component) + { + component.AddChild(partition); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component")); + } + } + else + { + this.Core.RootElement.AddChild(partition); + } + this.Core.IndexElement(row, partition); + } + } + + /// + /// Decompile the ComPlusPartitionProperty table. + /// + /// The table to decompile. + private void DecompileComPlusPartitionPropertyTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusPartition partition = (ComPlus.ComPlusPartition)this.Core.GetIndexedElement("ComPlusPartition", (string)row[0]); + if (null == partition) + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Partition_", (string)row[0], "ComPlusPartition")); + } + + switch ((string)row[1]) + { + case "Changeable": + switch ((string)row[2]) + { + case "1": + partition.Changeable = ComPlus.YesNoType.yes; + break; + case "0": + partition.Changeable = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "Deleteable": + switch ((string)row[2]) + { + case "1": + partition.Deleteable = ComPlus.YesNoType.yes; + break; + case "0": + partition.Deleteable = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "Description": + partition.Description = (string)row[2]; + break; + default: + // TODO: Warning + break; + } + } + } + + /// + /// Decompile the ComPlusPartitionRole table. + /// + /// The table to decompile. + private void DecompileComPlusPartitionRoleTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusPartitionRole partitionRole = new ComPlus.ComPlusPartitionRole(); + + partitionRole.Id = (string)row[0]; + partitionRole.Partition = (string)row[1]; + partitionRole.Name = (string)row[3]; + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); + if (null != component) + { + component.AddChild(partitionRole); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + } + } + + /// + /// Decompile the ComPlusUserInPartitionRole table. + /// + /// The table to decompile. + private void DecompileComPlusUserInPartitionRoleTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusUserInPartitionRole userInPartitionRole = new ComPlus.ComPlusUserInPartitionRole(); + + userInPartitionRole.Id = (string)row[0]; + userInPartitionRole.PartitionRole = (string)row[1]; + userInPartitionRole.User = (string)row[3]; + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); + if (null != component) + { + component.AddChild(userInPartitionRole); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + } + } + + /// + /// Decompile the ComPlusGroupInPartitionRole table. + /// + /// The table to decompile. + private void DecompileComPlusGroupInPartitionRoleTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusGroupInPartitionRole groupInPartitionRole = new ComPlus.ComPlusGroupInPartitionRole(); + + groupInPartitionRole.Id = (string)row[0]; + groupInPartitionRole.PartitionRole = (string)row[1]; + groupInPartitionRole.Group = (string)row[3]; + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); + if (null != component) + { + component.AddChild(groupInPartitionRole); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + } + } + + /// + /// Decompile the ComPlusPartitionUser table. + /// + /// The table to decompile. + private void DecompileComPlusPartitionUserTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusPartitionUser partitionUser = new ComPlus.ComPlusPartitionUser(); + + partitionUser.Id = (string)row[0]; + partitionUser.Partition = (string)row[1]; + partitionUser.User = (string)row[3]; + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); + if (null != component) + { + component.AddChild(partitionUser); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + } + } + + /// + /// Decompile the ComPlusApplication table. + /// + /// The table to decompile. + private void DecompileComPlusApplicationTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusApplication application = new ComPlus.ComPlusApplication(); + + application.Id = (string)row[0]; + application.Partition = (string)row[1]; + + if (null != row[3]) + { + application.ApplicationId = (string)row[3]; + } + + if (null != row[4]) + { + application.Name = (string)row[4]; + } + + if (null != row[2]) + { + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]); + if (null != component) + { + component.AddChild(application); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + } + else + { + this.Core.RootElement.AddChild(application); + } + this.Core.IndexElement(row, application); + } + } + + /// + /// Decompile the ComPlusApplicationProperty table. + /// + /// The table to decompile. + private void DecompileComPlusApplicationPropertyTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusApplication application = (ComPlus.ComPlusApplication)this.Core.GetIndexedElement("ComPlusApplication", (string)row[0]); + if (null == application) + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Application_", (string)row[0], "ComPlusApplication")); + } + + switch ((string)row[1]) + { + case "3GigSupportEnabled": + switch ((string)row[2]) + { + case "1": + application.ThreeGigSupportEnabled = ComPlus.YesNoType.yes; + break; + case "0": + application.ThreeGigSupportEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "AccessChecksLevel": + switch ((string)row[2]) + { + case "0": + application.AccessChecksLevel = ComPlus.ComPlusApplication.AccessChecksLevelType.applicationLevel; + break; + case "1": + application.AccessChecksLevel = ComPlus.ComPlusApplication.AccessChecksLevelType.applicationComponentLevel; + break; + default: + // TODO: Warning + break; + } + break; + case "Activation": + switch ((string)row[2]) + { + case "Inproc": + application.Activation = ComPlus.ComPlusApplication.ActivationType.inproc; + break; + case "Local": + application.Activation = ComPlus.ComPlusApplication.ActivationType.local; + break; + default: + // TODO: Warning + break; + } + break; + case "ApplicationAccessChecksEnabled": + switch ((string)row[2]) + { + case "1": + application.ApplicationAccessChecksEnabled = ComPlus.YesNoType.yes; + break; + case "0": + application.ApplicationAccessChecksEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "ApplicationDirectory": + application.ApplicationDirectory = (string)row[2]; + break; + case "Authentication": + switch ((string)row[2]) + { + case "0": + application.Authentication = ComPlus.ComPlusApplication.AuthenticationType.@default; + break; + case "1": + application.Authentication = ComPlus.ComPlusApplication.AuthenticationType.none; + break; + case "2": + application.Authentication = ComPlus.ComPlusApplication.AuthenticationType.connect; + break; + case "3": + application.Authentication = ComPlus.ComPlusApplication.AuthenticationType.call; + break; + case "4": + application.Authentication = ComPlus.ComPlusApplication.AuthenticationType.packet; + break; + case "5": + application.Authentication = ComPlus.ComPlusApplication.AuthenticationType.integrity; + break; + case "6": + application.Authentication = ComPlus.ComPlusApplication.AuthenticationType.privacy; + break; + default: + // TODO: Warning + break; + } + break; + case "AuthenticationCapability": + switch ((string)row[2]) + { + case "0": + application.AuthenticationCapability = ComPlus.ComPlusApplication.AuthenticationCapabilityType.none; + break; + case "2": + application.AuthenticationCapability = ComPlus.ComPlusApplication.AuthenticationCapabilityType.secureReference; + break; + case "32": + application.AuthenticationCapability = ComPlus.ComPlusApplication.AuthenticationCapabilityType.staticCloaking; + break; + case "64": + application.AuthenticationCapability = ComPlus.ComPlusApplication.AuthenticationCapabilityType.dynamicCloaking; + break; + default: + // TODO: Warning + break; + } + break; + case "Changeable": + switch ((string)row[2]) + { + case "1": + application.Changeable = ComPlus.YesNoType.yes; + break; + case "0": + application.Changeable = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "CommandLine": + application.CommandLine = (string)row[2]; + break; + case "ConcurrentApps": + int concurrentApps; + if (Int32.TryParse((string)row[2], out concurrentApps)) + { + application.ConcurrentApps = concurrentApps; + } + else + { + // TODO: Warning + } + break; + case "CreatedBy": + application.CreatedBy = (string)row[2]; + break; + case "CRMEnabled": + switch ((string)row[2]) + { + case "1": + application.CRMEnabled = ComPlus.YesNoType.yes; + break; + case "0": + application.CRMEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "CRMLogFile": + application.CRMLogFile = (string)row[2]; + break; + case "Deleteable": + switch ((string)row[2]) + { + case "1": + application.Deleteable = ComPlus.YesNoType.yes; + break; + case "0": + application.Deleteable = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "Description": + application.Description = (string)row[2]; + break; + case "DumpEnabled": + switch ((string)row[2]) + { + case "1": + application.DumpEnabled = ComPlus.YesNoType.yes; + break; + case "0": + application.DumpEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "DumpOnException": + switch ((string)row[2]) + { + case "1": + application.DumpOnException = ComPlus.YesNoType.yes; + break; + case "0": + application.DumpOnException = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "DumpOnFailfast": + switch ((string)row[2]) + { + case "1": + application.DumpOnFailfast = ComPlus.YesNoType.yes; + break; + case "0": + application.DumpOnFailfast = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "DumpPath": + application.DumpPath = (string)row[2]; + break; + case "EventsEnabled": + switch ((string)row[2]) + { + case "1": + application.EventsEnabled = ComPlus.YesNoType.yes; + break; + case "0": + application.EventsEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "Identity": + application.Identity = (string)row[2]; + break; + case "ImpersonationLevel": + switch ((string)row[2]) + { + case "1": + application.ImpersonationLevel = ComPlus.ComPlusApplication.ImpersonationLevelType.anonymous; + break; + case "2": + application.ImpersonationLevel = ComPlus.ComPlusApplication.ImpersonationLevelType.identify; + break; + case "3": + application.ImpersonationLevel = ComPlus.ComPlusApplication.ImpersonationLevelType.impersonate; + break; + case "4": + application.ImpersonationLevel = ComPlus.ComPlusApplication.ImpersonationLevelType.@delegate; + break; + default: + // TODO: Warning + break; + } + break; + case "IsEnabled": + switch ((string)row[2]) + { + case "1": + application.IsEnabled = ComPlus.YesNoType.yes; + break; + case "0": + application.IsEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "MaxDumpCount": + int maxDumpCount; + if (Int32.TryParse((string)row[2], out maxDumpCount)) + { + application.MaxDumpCount = maxDumpCount; + } + else + { + // TODO: Warning + } + break; + case "Password": + application.Password = (string)row[2]; + break; + case "QCAuthenticateMsgs": + switch ((string)row[2]) + { + case "0": + application.QCAuthenticateMsgs = ComPlus.ComPlusApplication.QCAuthenticateMsgsType.secureApps; + break; + case "1": + application.QCAuthenticateMsgs = ComPlus.ComPlusApplication.QCAuthenticateMsgsType.off; + break; + case "2": + application.QCAuthenticateMsgs = ComPlus.ComPlusApplication.QCAuthenticateMsgsType.on; + break; + default: + // TODO: Warning + break; + } + break; + case "QCListenerMaxThreads": + int qcListenerMaxThreads; + if (Int32.TryParse((string)row[2], out qcListenerMaxThreads)) + { + application.QCListenerMaxThreads = qcListenerMaxThreads; + } + else + { + // TODO: Warning + } + break; + case "QueueListenerEnabled": + switch ((string)row[2]) + { + case "1": + application.QueueListenerEnabled = ComPlus.YesNoType.yes; + break; + case "0": + application.QueueListenerEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "QueuingEnabled": + switch ((string)row[2]) + { + case "1": + application.QueuingEnabled = ComPlus.YesNoType.yes; + break; + case "0": + application.QueuingEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "RecycleActivationLimit": + int recycleActivationLimit; + if (Int32.TryParse((string)row[2], out recycleActivationLimit)) + { + application.RecycleActivationLimit = recycleActivationLimit; + } + else + { + // TODO: Warning + } + break; + case "RecycleCallLimit": + int recycleCallLimit; + if (Int32.TryParse((string)row[2], out recycleCallLimit)) + { + application.RecycleCallLimit = recycleCallLimit; + } + else + { + // TODO: Warning + } + break; + case "RecycleExpirationTimeout": + int recycleExpirationTimeout; + if (Int32.TryParse((string)row[2], out recycleExpirationTimeout)) + { + application.RecycleExpirationTimeout = recycleExpirationTimeout; + } + else + { + // TODO: Warning + } + break; + case "RecycleLifetimeLimit": + int recycleLifetimeLimit; + if (Int32.TryParse((string)row[2], out recycleLifetimeLimit)) + { + application.RecycleLifetimeLimit = recycleLifetimeLimit; + } + else + { + // TODO: Warning + } + break; + case "RecycleMemoryLimit": + int recycleMemoryLimit; + if (Int32.TryParse((string)row[2], out recycleMemoryLimit)) + { + application.RecycleMemoryLimit = recycleMemoryLimit; + } + else + { + // TODO: Warning + } + break; + case "Replicable": + switch ((string)row[2]) + { + case "1": + application.Replicable = ComPlus.YesNoType.yes; + break; + case "0": + application.Replicable = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "RunForever": + switch ((string)row[2]) + { + case "1": + application.RunForever = ComPlus.YesNoType.yes; + break; + case "0": + application.RunForever = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "ShutdownAfter": + int shutdownAfter; + if (Int32.TryParse((string)row[2], out shutdownAfter)) + { + application.ShutdownAfter = shutdownAfter; + } + else + { + // TODO: Warning + } + break; + case "SoapActivated": + switch ((string)row[2]) + { + case "1": + application.SoapActivated = ComPlus.YesNoType.yes; + break; + case "0": + application.SoapActivated = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "SoapBaseUrl": + application.SoapBaseUrl = (string)row[2]; + break; + case "SoapMailTo": + application.SoapMailTo = (string)row[2]; + break; + case "SoapVRoot": + application.SoapVRoot = (string)row[2]; + break; + case "SRPEnabled": + switch ((string)row[2]) + { + case "1": + application.SRPEnabled = ComPlus.YesNoType.yes; + break; + case "0": + application.SRPEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "SRPTrustLevel": + switch ((string)row[2]) + { + case "0": + application.SRPTrustLevel = ComPlus.ComPlusApplication.SRPTrustLevelType.disallowed; + break; + case "262144": + application.SRPTrustLevel = ComPlus.ComPlusApplication.SRPTrustLevelType.fullyTrusted; + break; + default: + // TODO: Warning + break; + } + break; + default: + // TODO: Warning + break; + } + } + } + + /// + /// Decompile the ComPlusApplicationRole table. + /// + /// The table to decompile. + private void DecompileComPlusApplicationRoleTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusApplicationRole applicationRole = new ComPlus.ComPlusApplicationRole(); + + applicationRole.Id = (string)row[0]; + applicationRole.Application = (string)row[1]; + + if (null != row[3]) + { + applicationRole.Name = (string)row[3]; + } + + if (null != row[2]) + { + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); + if (null != component) + { + component.AddChild(applicationRole); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + } + else + { + this.Core.RootElement.AddChild(applicationRole); + } + this.Core.IndexElement(row, applicationRole); + } + } + + /// + /// Decompile the ComPlusApplicationRoleProperty table. + /// + /// The table to decompile. + private void DecompileComPlusApplicationRolePropertyTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusApplicationRole applicationRole = (ComPlus.ComPlusApplicationRole)this.Core.GetIndexedElement("ComPlusApplicationRole", (string)row[0]); + if (null == applicationRole) + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ApplicationRole_", (string)row[0], "ComPlusApplicationRole")); + } + + switch ((string)row[1]) + { + case "Description": + applicationRole.Description = (string)row[2]; + break; + default: + // TODO: Warning + break; + } + } + } + + /// + /// Decompile the ComPlusUserInApplicationRole table. + /// + /// The table to decompile. + private void DecompileComPlusUserInApplicationRoleTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusUserInApplicationRole userInApplicationRole = new ComPlus.ComPlusUserInApplicationRole(); + + userInApplicationRole.Id = (string)row[0]; + userInApplicationRole.ApplicationRole = (string)row[1]; + userInApplicationRole.User = (string)row[3]; + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); + if (null != component) + { + component.AddChild(userInApplicationRole); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + } + } + + /// + /// Decompile the ComPlusGroupInApplicationRole table. + /// + /// The table to decompile. + private void DecompileComPlusGroupInApplicationRoleTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusGroupInApplicationRole groupInApplicationRole = new ComPlus.ComPlusGroupInApplicationRole(); + + groupInApplicationRole.Id = (string)row[0]; + groupInApplicationRole.ApplicationRole = (string)row[1]; + groupInApplicationRole.Group = (string)row[3]; + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); + if (null != component) + { + component.AddChild(groupInApplicationRole); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + } + } + + /// + /// Decompile the ComPlusAssembly table. + /// + /// The table to decompile. + private void DecompileComPlusAssemblyTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusAssembly assembly = new ComPlus.ComPlusAssembly(); + + assembly.Id = (string)row[0]; + assembly.Application = (string)row[1]; + + if (null != row[3]) + { + assembly.AssemblyName = (string)row[3]; + } + + if (null != row[4]) + { + assembly.DllPath = (string)row[4]; + } + + if (null != row[5]) + { + assembly.TlbPath = (string)row[5]; + } + + if (null != row[6]) + { + assembly.PSDllPath = (string)row[6]; + } + + int attributes = (int)row[7]; + + if (0 != (attributes & (int)ComPlusCompiler.CpiAssemblyAttributes.EventClass)) + { + assembly.EventClass = ComPlus.YesNoType.yes; + } + + if (0 != (attributes & (int)ComPlusCompiler.CpiAssemblyAttributes.DotNetAssembly)) + { + assembly.Type = ComPlus.ComPlusAssembly.TypeType.net; + } + + if (0 != (attributes & (int)ComPlusCompiler.CpiAssemblyAttributes.DllPathFromGAC)) + { + assembly.DllPathFromGAC = ComPlus.YesNoType.yes; + } + + if (0 != (attributes & (int)ComPlusCompiler.CpiAssemblyAttributes.RegisterInCommit)) + { + assembly.RegisterInCommit = ComPlus.YesNoType.yes; + } + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); + if (null != component) + { + component.AddChild(assembly); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + this.Core.IndexElement(row, assembly); + } + } + + /// + /// Decompile the ComPlusAssemblyDependency table. + /// + /// The table to decompile. + private void DecompileComPlusAssemblyDependencyTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusAssemblyDependency assemblyDependency = new ComPlus.ComPlusAssemblyDependency(); + + assemblyDependency.RequiredAssembly = (string)row[1]; + + ComPlus.ComPlusAssembly assembly = (ComPlus.ComPlusAssembly)this.Core.GetIndexedElement("ComPlusAssembly", (string)row[0]); + if (null != assembly) + { + assembly.AddChild(assemblyDependency); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Assembly_", (string)row[0], "ComPlusAssembly")); + } + } + } + + /// + /// Decompile the ComPlusComponent table. + /// + /// The table to decompile. + private void DecompileComPlusComponentTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusComponent comPlusComponent = new ComPlus.ComPlusComponent(); + + comPlusComponent.Id = (string)row[0]; + + try + { + Guid clsid = new Guid((string)row[2]); + comPlusComponent.CLSID = clsid.ToString().ToUpper(); + } + catch + { + // TODO: Warning + } + + ComPlus.ComPlusAssembly assembly = (ComPlus.ComPlusAssembly)this.Core.GetIndexedElement("ComPlusAssembly", (string)row[1]); + if (null != assembly) + { + assembly.AddChild(comPlusComponent); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Assembly_", (string)row[1], "ComPlusAssembly")); + } + this.Core.IndexElement(row, comPlusComponent); + } + } + + /// + /// Decompile the ComPlusComponentProperty table. + /// + /// The table to decompile. + private void DecompileComPlusComponentPropertyTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusComponent comPlusComponent = (ComPlus.ComPlusComponent)this.Core.GetIndexedElement("ComPlusComponent", (string)row[0]); + if (null == comPlusComponent) + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ComPlusComponent_", (string)row[0], "ComPlusComponent")); + } + + switch ((string)row[1]) + { + case "AllowInprocSubscribers": + switch ((string)row[2]) + { + case "1": + comPlusComponent.AllowInprocSubscribers = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.AllowInprocSubscribers = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "ComponentAccessChecksEnabled": + switch ((string)row[2]) + { + case "1": + comPlusComponent.ComponentAccessChecksEnabled = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.ComponentAccessChecksEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "ComponentTransactionTimeout": + int componentTransactionTimeout; + if (Int32.TryParse((string)row[2], out componentTransactionTimeout)) + { + comPlusComponent.ComponentTransactionTimeout = componentTransactionTimeout; + } + else + { + // TODO: Warning + } + break; + case "ComponentTransactionTimeoutEnabled": + switch ((string)row[2]) + { + case "1": + comPlusComponent.ComponentTransactionTimeoutEnabled = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.ComponentTransactionTimeoutEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "COMTIIntrinsics": + switch ((string)row[2]) + { + case "1": + comPlusComponent.COMTIIntrinsics = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.COMTIIntrinsics = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "ConstructionEnabled": + switch ((string)row[2]) + { + case "1": + comPlusComponent.ConstructionEnabled = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.ConstructionEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "ConstructorString": + comPlusComponent.ConstructorString = (string)row[2]; + break; + case "CreationTimeout": + int creationTimeout; + if (Int32.TryParse((string)row[2], out creationTimeout)) + { + comPlusComponent.CreationTimeout = creationTimeout; + } + else + { + // TODO: Warning + } + break; + case "Description": + comPlusComponent.Description = (string)row[2]; + break; + case "EventTrackingEnabled": + switch ((string)row[2]) + { + case "1": + comPlusComponent.EventTrackingEnabled = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.EventTrackingEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "ExceptionClass": + comPlusComponent.ExceptionClass = (string)row[2]; + break; + case "FireInParallel": + switch ((string)row[2]) + { + case "1": + comPlusComponent.FireInParallel = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.FireInParallel = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "IISIntrinsics": + switch ((string)row[2]) + { + case "1": + comPlusComponent.IISIntrinsics = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.IISIntrinsics = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "InitializesServerApplication": + switch ((string)row[2]) + { + case "1": + comPlusComponent.InitializesServerApplication = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.InitializesServerApplication = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "IsEnabled": + switch ((string)row[2]) + { + case "1": + comPlusComponent.IsEnabled = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.IsEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "IsPrivateComponent": + switch ((string)row[2]) + { + case "1": + comPlusComponent.IsPrivateComponent = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.IsPrivateComponent = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "JustInTimeActivation": + switch ((string)row[2]) + { + case "1": + comPlusComponent.JustInTimeActivation = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.JustInTimeActivation = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "LoadBalancingSupported": + switch ((string)row[2]) + { + case "1": + comPlusComponent.LoadBalancingSupported = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.LoadBalancingSupported = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "MaxPoolSize": + int maxPoolSize; + if (Int32.TryParse((string)row[2], out maxPoolSize)) + { + comPlusComponent.MaxPoolSize = maxPoolSize; + } + else + { + // TODO: Warning + } + break; + case "MinPoolSize": + int minPoolSize; + if (Int32.TryParse((string)row[2], out minPoolSize)) + { + comPlusComponent.MinPoolSize = minPoolSize; + } + else + { + // TODO: Warning + } + break; + case "MultiInterfacePublisherFilterCLSID": + comPlusComponent.MultiInterfacePublisherFilterCLSID = (string)row[2]; + break; + case "MustRunInClientContext": + switch ((string)row[2]) + { + case "1": + comPlusComponent.MustRunInClientContext = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.MustRunInClientContext = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "MustRunInDefaultContext": + switch ((string)row[2]) + { + case "1": + comPlusComponent.MustRunInDefaultContext = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.MustRunInDefaultContext = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "ObjectPoolingEnabled": + switch ((string)row[2]) + { + case "1": + comPlusComponent.ObjectPoolingEnabled = ComPlus.YesNoType.yes; + break; + case "0": + comPlusComponent.ObjectPoolingEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "PublisherID": + comPlusComponent.PublisherID = (string)row[2]; + break; + case "SoapAssemblyName": + comPlusComponent.SoapAssemblyName = (string)row[2]; + break; + case "SoapTypeName": + comPlusComponent.SoapTypeName = (string)row[2]; + break; + case "Synchronization": + switch ((string)row[2]) + { + case "0": + comPlusComponent.Synchronization = ComPlus.ComPlusComponent.SynchronizationType.ignored; + break; + case "1": + comPlusComponent.Synchronization = ComPlus.ComPlusComponent.SynchronizationType.none; + break; + case "2": + comPlusComponent.Synchronization = ComPlus.ComPlusComponent.SynchronizationType.supported; + break; + case "3": + comPlusComponent.Synchronization = ComPlus.ComPlusComponent.SynchronizationType.required; + break; + case "4": + comPlusComponent.Synchronization = ComPlus.ComPlusComponent.SynchronizationType.requiresNew; + break; + default: + // TODO: Warning + break; + } + break; + case "Transaction": + switch ((string)row[2]) + { + case "0": + comPlusComponent.Transaction = ComPlus.ComPlusComponent.TransactionType.ignored; + break; + case "1": + comPlusComponent.Transaction = ComPlus.ComPlusComponent.TransactionType.none; + break; + case "2": + comPlusComponent.Transaction = ComPlus.ComPlusComponent.TransactionType.supported; + break; + case "3": + comPlusComponent.Transaction = ComPlus.ComPlusComponent.TransactionType.required; + break; + case "4": + comPlusComponent.Transaction = ComPlus.ComPlusComponent.TransactionType.requiresNew; + break; + default: + // TODO: Warning + break; + } + break; + case "TxIsolationLevel": + switch ((string)row[2]) + { + case "0": + comPlusComponent.TxIsolationLevel = ComPlus.ComPlusComponent.TxIsolationLevelType.any; + break; + case "1": + comPlusComponent.TxIsolationLevel = ComPlus.ComPlusComponent.TxIsolationLevelType.readUnCommitted; + break; + case "2": + comPlusComponent.TxIsolationLevel = ComPlus.ComPlusComponent.TxIsolationLevelType.readCommitted; + break; + case "3": + comPlusComponent.TxIsolationLevel = ComPlus.ComPlusComponent.TxIsolationLevelType.repeatableRead; + break; + case "4": + comPlusComponent.TxIsolationLevel = ComPlus.ComPlusComponent.TxIsolationLevelType.serializable; + break; + default: + // TODO: Warning + break; + } + break; + default: + // TODO: Warning + break; + } + } + } + + /// + /// Decompile the ComPlusRoleForComponent table. + /// + /// The table to decompile. + private void DecompileComPlusRoleForComponentTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusRoleForComponent roleForComponent = new ComPlus.ComPlusRoleForComponent(); + + roleForComponent.Id = (string)row[0]; + roleForComponent.Component = (string)row[1]; + roleForComponent.ApplicationRole = (string)row[2]; + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[3]); + if (null != component) + { + component.AddChild(roleForComponent); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[3], "Component")); + } + } + } + + /// + /// Decompile the ComPlusInterface table. + /// + /// The table to decompile. + private void DecompileComPlusInterfaceTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusInterface comPlusInterface = new ComPlus.ComPlusInterface(); + + comPlusInterface.Id = (string)row[0]; + + try + { + Guid iid = new Guid((string)row[2]); + comPlusInterface.IID = iid.ToString().ToUpper(); + } + catch + { + // TODO: Warning + } + + ComPlus.ComPlusComponent comPlusComponent = (ComPlus.ComPlusComponent)this.Core.GetIndexedElement("ComPlusComponent", (string)row[1]); + if (null != comPlusComponent) + { + comPlusComponent.AddChild(comPlusInterface); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ComPlusComponent_", (string)row[1], "ComPlusComponent")); + } + this.Core.IndexElement(row, comPlusInterface); + } + } + + /// + /// Decompile the ComPlusInterfaceProperty table. + /// + /// The table to decompile. + private void DecompileComPlusInterfacePropertyTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusInterface comPlusInterface = (ComPlus.ComPlusInterface)this.Core.GetIndexedElement("ComPlusInterface", (string)row[0]); + if (null == comPlusInterface) + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Interface_", (string)row[0], "ComPlusInterface")); + } + + switch ((string)row[1]) + { + case "Description": + comPlusInterface.Description = (string)row[2]; + break; + case "QueuingEnabled": + switch ((string)row[2]) + { + case "1": + comPlusInterface.QueuingEnabled = ComPlus.YesNoType.yes; + break; + case "0": + comPlusInterface.QueuingEnabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + default: + // TODO: Warning + break; + } + } + } + + /// + /// Decompile the ComPlusRoleForInterface table. + /// + /// The table to decompile. + private void DecompileComPlusRoleForInterfaceTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusRoleForInterface roleForInterface = new ComPlus.ComPlusRoleForInterface(); + + roleForInterface.Id = (string)row[0]; + roleForInterface.Interface = (string)row[1]; + roleForInterface.ApplicationRole = (string)row[2]; + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[3]); + if (null != component) + { + component.AddChild(roleForInterface); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[3], "Component")); + } + } + } + + /// + /// Decompile the ComPlusMethod table. + /// + /// The table to decompile. + private void DecompileComPlusMethodTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusMethod comPlusMethod = new ComPlus.ComPlusMethod(); + + comPlusMethod.Id = (string)row[0]; + + if (null != row[2]) + { + comPlusMethod.Index = (int)row[2]; + } + + if (null != row[3]) + { + comPlusMethod.Name = (string)row[3]; + } + + ComPlus.ComPlusInterface comPlusInterface = (ComPlus.ComPlusInterface)this.Core.GetIndexedElement("ComPlusInterface", (string)row[1]); + if (null != comPlusInterface) + { + comPlusInterface.AddChild(comPlusMethod); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Interface_", (string)row[1], "ComPlusInterface")); + } + this.Core.IndexElement(row, comPlusMethod); + } + } + + /// + /// Decompile the ComPlusMethodProperty table. + /// + /// The table to decompile. + private void DecompileComPlusMethodPropertyTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusMethod comPlusMethod = (ComPlus.ComPlusMethod)this.Core.GetIndexedElement("ComPlusMethod", (string)row[0]); + if (null == comPlusMethod) + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Method_", (string)row[0], "ComPlusMethod")); + } + + switch ((string)row[1]) + { + case "AutoComplete": + switch ((string)row[2]) + { + case "1": + comPlusMethod.AutoComplete = ComPlus.YesNoType.yes; + break; + case "0": + comPlusMethod.AutoComplete = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "Description": + comPlusMethod.Description = (string)row[2]; + break; + default: + // TODO: Warning + break; + } + } + } + + /// + /// Decompile the ComPlusRoleForMethod table. + /// + /// The table to decompile. + private void DecompileComPlusRoleForMethodTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusRoleForMethod roleForMethod = new ComPlus.ComPlusRoleForMethod(); + + roleForMethod.Id = (string)row[0]; + roleForMethod.Method = (string)row[1]; + roleForMethod.ApplicationRole = (string)row[2]; + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[3]); + if (null != component) + { + component.AddChild(roleForMethod); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[3], "Component")); + } + } + } + + /// + /// Decompile the ComPlusSubscription table. + /// + /// The table to decompile. + private void DecompileComPlusSubscriptionTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusSubscription subscription = new ComPlus.ComPlusSubscription(); + + subscription.Id = (string)row[0]; + subscription.Component = (string)row[1]; + subscription.SubscriptionId = (string)row[3]; + subscription.Name = (string)row[4]; + subscription.EventCLSID = (string)row[5]; + subscription.PublisherID = (string)row[6]; + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); + if (null != component) + { + component.AddChild(subscription); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + this.Core.IndexElement(row, subscription); + } + } + + /// + /// Decompile the ComPlusSubscriptionProperty table. + /// + /// The table to decompile. + private void DecompileComPlusSubscriptionPropertyTable(Table table) + { + foreach (Row row in table.Rows) + { + ComPlus.ComPlusSubscription subscription = (ComPlus.ComPlusSubscription)this.Core.GetIndexedElement("ComPlusSubscription", (string)row[0]); + if (null == subscription) + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Subscription_", (string)row[0], "ComPlusSubscription")); + } + + switch ((string)row[1]) + { + case "Description": + subscription.Description = (string)row[2]; + break; + case "Enabled": + switch ((string)row[2]) + { + case "1": + subscription.Enabled = ComPlus.YesNoType.yes; + break; + case "0": + subscription.Enabled = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "EventClassPartitionID": + subscription.EventClassPartitionID = (string)row[2]; + break; + case "FilterCriteria": + subscription.FilterCriteria = (string)row[2]; + break; + case "InterfaceID": + subscription.InterfaceID = (string)row[2]; + break; + case "MachineName": + subscription.MachineName = (string)row[2]; + break; + case "MethodName": + subscription.MethodName = (string)row[2]; + break; + case "PerUser": + switch ((string)row[2]) + { + case "1": + subscription.PerUser = ComPlus.YesNoType.yes; + break; + case "0": + subscription.PerUser = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "Queued": + switch ((string)row[2]) + { + case "1": + subscription.Queued = ComPlus.YesNoType.yes; + break; + case "0": + subscription.Queued = ComPlus.YesNoType.no; + break; + default: + // TODO: Warning + break; + } + break; + case "SubscriberMoniker": + subscription.SubscriberMoniker = (string)row[2]; + break; + case "UserName": + subscription.UserName = (string)row[2]; + break; + default: + // TODO: Warning + break; + } + } + } + } +} diff --git a/src/wixext/ComPlusExtensionData.cs b/src/wixext/ComPlusExtensionData.cs new file mode 100644 index 00000000..cedc2474 --- /dev/null +++ b/src/wixext/ComPlusExtensionData.cs @@ -0,0 +1,64 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Extensions +{ + using System; + using System.Reflection; + using WixToolset.Data; + using WixToolset.Extensibility; + + /// + /// The WiX Toolset COM+ Extension. + /// + public sealed class ComPlusExtensionData : ExtensionData + { + /// + /// Gets the default culture. + /// + /// The default culture. + public override string DefaultCulture + { + get { return "en-us"; } + } + + /// + /// Gets the optional table definitions for this extension. + /// + /// The optional table definitions for this extension. + public override TableDefinitionCollection TableDefinitions + { + get + { + return ComPlusExtensionData.GetExtensionTableDefinitions(); + } + } + + /// + /// Gets the library associated with this extension. + /// + /// The table definitions to use while loading the library. + /// The loaded library. + public override Library GetLibrary(TableDefinitionCollection tableDefinitions) + { + return ComPlusExtensionData.GetExtensionLibrary(tableDefinitions); + } + + /// + /// Internal mechanism to access the extension's table definitions. + /// + /// Extension's table definitions. + internal static TableDefinitionCollection GetExtensionTableDefinitions() + { + return ExtensionData.LoadTableDefinitionHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.tables.xml"); + } + + /// + /// Internal mechanism to access the extension's library. + /// + /// Extension's library. + internal static Library GetExtensionLibrary(TableDefinitionCollection tableDefinitions) + { + return ExtensionData.LoadLibraryHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.complus.wixlib", tableDefinitions); + } + } +} diff --git a/src/wixext/WixComPlusExtension.csproj b/src/wixext/WixComPlusExtension.csproj new file mode 100644 index 00000000..92cbacae --- /dev/null +++ b/src/wixext/WixComPlusExtension.csproj @@ -0,0 +1,50 @@ + + + + + + + {1497B777-330B-4CFE-927A-22850CD24D64} + WixComPlusExtension + Library + WixToolset.Extensions + + + + + + + + $(RootNamespace).Data.Messages.resources + + + $(RootNamespace).Data.tables.xml + + + $(RootNamespace).Xsd.complus.xsd + + + WixToolset.Data.Serialize + WixToolset.Extensions.Serialize.ComPlus + + + complus.xsd + PreserveNewest + + + Data\complus.wixlib + + + + + + + + + + + false + + + + diff --git a/src/wixext/complus.xsd b/src/wixext/complus.xsd new file mode 100644 index 00000000..f7ddacc6 --- /dev/null +++ b/src/wixext/complus.xsd @@ -0,0 +1,944 @@ + + + + + + + + The source code schema for the WiX Toolset COM+ Extension. + + + + + + + + + + + + + + + Defines a COM+ partition. If this element is a child of a + Component element, the partition will be created in association with this + component. If the element is a child of any of the Fragment, Module or Product + elements it is considered to be a locater, referencing an existing partition. + + + + + + + + + + + + + Identifier for the element. + + + + + Id for the partition. This attribute can be omitted, in + which case an id will be generated on install. If the element is a locater, + this attribute can be omitted if a value is provided for the Name attribute. + + + + + Name of the partition. This attribute can be omitted if + the element is a locater, and a value is provided for the PartitionId + attribute. + + + + + + + + + + + + + + + + + + Defines a COM+ partition role. Partition roles can not be + created; this element can only be used as a locater to reference an existing + role. + + + + + + + + + + + + Identifier for the element. + + + + + The id of a ComPlusPartition element representing the partition + the role belongs to. + + + + + Name of the partition role. + + + + + + + + + + + + This element represents a user membership in a partition + role. When the parent component of this element is installed, the user will be + added to the associated partition role. + + + + + + Identifier for the element. + + + + + The id of a ComPlusPartitionRole element representing the + partition the user should be added to. + + + + + Foreign key into the User table. + + + + + + + + + + + + This element represents a security group membership in a + partition role. When the parent component of this element is installed, the + security group will be added to the associated partition role. + + + + + + Identifier for the element. + + + + + The id of a ComPlusPartitionRole element representing the + partition the user should be added to. + + + + + Foreign key into the Group table. + + + + + + + + + + + + Represents a default partition definition for a user. When + the parent component of this element is installed, the default partition of the + user will be set to the referenced partition. + + + + + + Identifier for the element. + + + + + The id of a ComPlusPartition element representing the + partition that will be the default partition for the user. + + + + + Foreign key into the User table. + + + + + + + + + + + + + + + Defines a COM+ application. If this element is a descendent + of a Component element, the application will be created in association with + this component. If the element is a child of any of the Fragment, Module or + Product elements it is considered to be a locater, referencing an existing + application. + + If the element is a child of a ComPlusPartition element, + or have its Partition attribute set, the application will be installed under + the referenced partition. + + + + + + + + + + + + Identifier for the element. + + + + + If the element is not a child of a ComPlusPartition + element, this attribute can be provided with the id of a ComPlusPartition + element representing the partition the application belongs to. + + + + + Id for the application. This attribute can be omitted, in + which case an id will be generated on install. If the element is a locater, + this attribute can be omitted if a value is provided for the Name attribute. + + + + + Name of the application. This attribute can be omitted if + the element is a locater, and a value is provided for the PartitionId + attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines an application role. If this element is a descendent + of a Component element, the application role will be created in association + with this component. If the element is a child of any of the Fragment, Module + or Product elements it is considered to be a locater, referencing an existing + application role. + + + + + + + + + + + + Identifier for the element. + + + + + If the element is not a child of a ComPlusApplication + element, this attribute should be provided with the id of a + ComPlusApplication element representing the application the role belongs to. + + + + + Name of the application role. + + + + + + + + + + + + + This element represents a user membership in an + application role. When the parent component of this element is installed, the + user will be added to the associated application role. This element must be a descendent + of a Component element; it can not be a child of a ComPlusApplicationRole + locater element. To reference a locater element use the ApplicationRole + attribute. + + + + + + Identifier for the element. + + + + + If the element is not a child of a ComPlusApplicationRole + element, this attribute should be provided with the id of a + ComPlusApplicationRole element representing the application role the user is + to be added to. + + + + + Foreign key into the User table. + + + + + + + + + + + + This element represents a security group membership in an + application role. When the parent component of this element is installed, the + user will be added to the associated application role. This element must be a + descendent of a Component element; it can not be a child of a + ComPlusApplicationRole locater element. To reference a locater element use the + ApplicationRole attribute. + + + + + + Identifier for the element. + + + + + If the element is not a child of a ComPlusApplicationRole + element, this attribute should be provided with the id of a + ComPlusApplicationRole element representing the application role the user is + to be added to. + + + + + Foreign key into the Group table. + + + + + + + + + Represents a DLL or assembly to be registered with COM+. If + this element is a child of a ComPlusApplication element, the assembly will be + registered in this application. Other ways the Application attribute must be + set to an application. The element must be a descendent of a Component element, + it can not be a child of a ComPlusApplication locator element. + + + + + + When installing a native assembly, all components + contained in the assembly must be represented as ComPlusComponent elements + under this element. Any component not listed will not be removed during + uninstall. + + + + The fields DllPath, TlbPath and PSDllPath are formatted + fields that should contain file paths to there respective file types. A typical + value for DllPath for example, should be something like “[#MyAssembly_dll]”, + where “MyAssembly_dll” is the key of the dll file in the File table. + + + + Warning: The assembly name provided in the AssemblyName + attribute must be a fully specified assembly name, if a partial name is + provided a random assembly matching the partial name will be selected. + + + + + + + + + + + + + + Identifier for the element. + + + + + If the element is not a child of a ComPlusApplication + element, this attribute should be provided with the id of a ComPlusApplication + element representing the application the assembly is to be registered in. + This attribute can be omitted for a .NET assembly even if the application is + not a child of a ComPlusApplication element. + + + + + The name of the assembly used to identify the assembly in + the GAC. This attribute can be provided only if DllPathFromGAC is set to + “yes”. + + + + + The path to locate the assembly DLL during registration. + This attribute should be provided if DllPathFromGAC is not set to “yes”. + + + + + An optional path to an external type lib for the assembly. + This attribute must be provided if the Type attribute is set to “.net”. + + + + + An optional path to an external proxy/stub DLL for the assembly. + + + + + + + + + + + + + + + Indicates that the assembly is to be installed as an event + class DLL. This attribute is only valid for native assemblies. The assembly + will be installed with the COM+ catalog’s InstallEventClass() function. + + + + + Indicates that the DLL path should be extracted from the + GAC instead for being provided in the DllPath attribute. If this attribute is + set to “yes”, the name of the assembly can be provided using the AssemblyName + attribute. Or, if this AssemblyName attribute is missing, the name will be + extracted from the MsiAssemblyName table using the id of the parent Component + element. + + + + + Indicates that the assembly should be installed in the + commit custom action instead of the normal deferred custom action. This is + necessary when installing .NET assemblies to the GAC in the same + installation, as the assemblies are not visible in the GAC until after the + InstallFinalize action has run. + + + + + + + + + Defines a dependency between two assemblies. This element + affects the order in which assembles are registered. Any assemblies referenced + by this element are guarantied to be registered before, and unregistered after, + the assembly referenced by the parent ComPlusAssembly element. + + + + It is only necessary to explicitly specify dependencies between + assemblies contained in the same package (MSI or MSM). Assemblies merged in to a + package from a merge module will always be installed before any assemblies + specified in the base package. Assemblies merged in from different merge + modules are sequenced using the ModuleDependency MSI table. It is not possible + to have cross dependencies between merge modules or have an assembly in a merge + module depend on an assembly in the base package. + + + + + + + Reference to the id of the assembly required by the parent + ComPlusAssembly element. + + + + + + + + Represents a COM+ component in an assembly. + + + + + + + + + + + + Identifier for the element. + + + + + CLSID of the component. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Represents a role assignment to a COM+ component. + + + + + + Identifier for the element. + + + + + If the element is not a child of a ComPlusComponent + element, this attribute should be provided with the id of a ComPlusComponent + element representing the component the role is to be added to. + + + + + Id of the ComPlusApplicationRole element representing the + role that shall be granted access to the component. + + + + + + + + Represents an interface for a COM+ component. + + + + + + + + + + + Identifier for the element. + + + + + IID of the interface. + + + + + + + + + + + + + + Represents a role assignment to an interface. + + + + + + Identifier for the element. + + + + + If the element is not a child of a ComPlusInterface + element, this attribute should be provided with the id of a ComPlusInterface + element representing the interface the role is to be added to. + + + + + Id of the ComPlusApplicationRole element representing the + role that shall be granted access to the interface. + + + + + + + + + Represents a method for an interface. + + + + + + + + + + Identifier for the element. + + + + + + + Dispatch id of the method. If this attribute is not set a + value must be provided for the Name attribute. + + + + + + + Name of the method. If this attribute is not set a value + must be provided for the Index attribute. + + + + + + + + + + + + + + + Represents a role assignment to a COM+ method. + + + + + + Identifier for the element. + + + + + If the element is not a child of a ComPlusMethod element, + this attribute should be provided with the id of a ComPlusMethod element + representing the method the role is to be added to. + + + + + Id of the ComPlusApplicationRole element representing the + role that shall be granted access to the method. + + + + + + + + + + + + Defines an event subscription for a COM+ component. + + + + + + Identifier for the element. + + + + + If the element is not a child of a ComPlusComponent + element, this attribute should be provided with the id of a ComPlusComponent + element representing the component the subscription is to be created for. + + + + + Id of the subscription. If a value is not provided for + this attribute, an id will be generated during installation. + + + + + Name of the subscription. + + + + + CLSID of the event class for the subscription. If a value + for this attribute is not provided, a value for the PublisherID attribute + must be provided. + + + + + Publisher id for the subscription. If a value for this + attribute is not provided, a value for the EventCLSID attribute must be + provided. + + + + + + + + + + + + + + + + + + + Values of this type will either be "yes" or "no". + + + + + + + + + + Values of this type will look like: "01234567-89AB-CDEF-0123-456789ABCDEF". + + + + + + + diff --git a/src/wixext/messages.xml b/src/wixext/messages.xml new file mode 100644 index 00000000..66c0a9e6 --- /dev/null +++ b/src/wixext/messages.xml @@ -0,0 +1,77 @@ + + + + + + + + + The {0}/@{1} attribute cannot be specified unless the element has a component as an ancestor. A {0} that does not have a component ancestor is not installed. + + + + + + + The {0} element cannot be specified unless the element has a component as an ancestor. A {0} that does not have a component ancestor is not installed. + + + + + + The {0}/@{1} attribute cannot coexist with the {2} attribute's value of '{3}'. + + + + + + + The {0}/@{1} attribute's value, '{2}', cannot coexist with the {3} attribute's value of '{4}'. + + + + + + + + + + The {0}/@{1} cannot be provided unless the {2} attribute is provided with a value of '{3}'. + + + + + + + + + The {0}/@{1} attribute must be provided when {0} element is nested under a component. + + + + + + + A {0} element must have either a {1} attribute or a {2} attribute, or both set. + + + + + + + + A {0} element not nested under a component must have either a {1} attribute or a {2} attribute, or both set. + + + + + + + + + The ComPlusAssembly element has a Type attribute with a value of 'native', but the element does not contain any ComPlusComponent elements. All components contained in a native assembly must be listed, or they will not be correctly removed during uninstall. + + + + + diff --git a/src/wixext/tables.xml b/src/wixext/tables.xml new file mode 100644 index 00000000..3c3d1728 --- /dev/null +++ b/src/wixext/tables.xml @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wixlib/ComPlusExtension.wixproj b/src/wixlib/ComPlusExtension.wixproj new file mode 100644 index 00000000..49c688cd --- /dev/null +++ b/src/wixlib/ComPlusExtension.wixproj @@ -0,0 +1,26 @@ + + + + + + + {E191E61E-E098-4F71-888F-51A79F952022} + complus + Library + true + 1086 + + + + + + + + + + + + + + + diff --git a/src/wixlib/ComPlusExtension.wxs b/src/wixlib/ComPlusExtension.wxs new file mode 100644 index 00000000..3a5c1512 --- /dev/null +++ b/src/wixlib/ComPlusExtension.wxs @@ -0,0 +1,139 @@ + + + + + + + + + + !(loc.msierrComPlusCannotConnect) + !(loc.msierrComPlusPartitionReadFailed) + !(loc.msierrComPlusPartitionRoleReadFailed) + !(loc.msierrComPlusUserInPartitionRoleReadFailed) + !(loc.msierrComPlusPartitionUserReadFailed) + !(loc.msierrComPlusApplicationReadFailed) + !(loc.msierrComPlusApplicationRoleReadFailed) + !(loc.msierrComPlusUserInApplicationRoleReadFailed) + !(loc.msierrComPlusAssembliesReadFailed) + !(loc.msierrComPlusSubscriptionReadFailed) + !(loc.msierrComPlusPartitionDependency) + !(loc.msierrComPlusPartitionNotFound) + !(loc.msierrComPlusPartitionIdConflict) + !(loc.msierrComPlusPartitionNameConflict) + !(loc.msierrComPlusApplicationDependency) + !(loc.msierrComPlusApplicationNotFound) + !(loc.msierrComPlusApplicationIdConflict) + !(loc.msierrComPlusApplicationNameConflict) + !(loc.msierrComPlusApplicationRoleDependency) + !(loc.msierrComPlusApplicationRoleNotFound) + !(loc.msierrComPlusApplicationRoleConflict) + !(loc.msierrComPlusAssemblyDependency) + !(loc.msierrComPlusSubscriptionIdConflict) + !(loc.msierrComPlusSubscriptionNameConflict) + !(loc.msierrComPlusFailedLookupNames) + + !(loc.ComPlusInstallExecute) + !(loc.ComPlusUninstallExecute) + + !(loc.CreateComPlusPartitions) + !(loc.RemoveComPlusPartitions) + !(loc.AddUsersToComPlusPartitionRoles) + !(loc.RemoveUsersFromComPlusPartitionRoles) + !(loc.AddComPlusPartitionUsers) + !(loc.RemoveComPlusPartitionUsers) + !(loc.CreateComPlusApplications) + !(loc.RemoveComPlusApplications) + !(loc.CreateComPlusApplicationRoles) + !(loc.RemoveComPlusApplicationRoles) + !(loc.AddUsersToComPlusApplicationRoles) + !(loc.RemoveUsersFromComPlusApplicationRoles) + !(loc.RegisterComPlusAssemblies) + !(loc.UnregisterComPlusAssemblies) + !(loc.AddComPlusRoleAssignments) + !(loc.RemoveComPlusRoleAssignments) + !(loc.CreateSubscriptionsComPlusComponents) + !(loc.RemoveSubscriptionsComPlusComponents) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wixlib/en-us.wxl b/src/wixlib/en-us.wxl new file mode 100644 index 00000000..8f6f38fc --- /dev/null +++ b/src/wixlib/en-us.wxl @@ -0,0 +1,71 @@ + + + + + + Cannot connect to the COM+ admin catalog. ([2] [3] [4] [5]) + Failed to read COM+ partitions. ([2] [3] [4] [5]) + Failed to read COM+ partition roles. ([2] [3] [4] [5]) + Failed to read COM+ users in partition roles. ([2] [3] [4] [5]) + Failed to read COM+ partition users. ([2] [3] [4] [5]) + Failed to read COM+ applications. ([2] [3] [4] [5]) + Failed to read COM+ application roles. ([2] [3] [4] [5]) + Failed to read COM+ users in application roles. ([2] [3] [4] [5]) + Failed to read COM+ assemblies. ([2] [3] [4] [5]) + Failed to read COM+ event subscriptions. ([2] [3] [4] [5]) + Another entity is dependent on a COM+ partition that is not being installed. ([2] [3] [4] [5]) + The COM+ partition was not found. ([2] [3] [4] [5]) + A COM+ partition with the same id already exists. ([2] [3] [4] [5]) + A COM+ partition with the same name already exists. ([2] [3] [4] [5]) + Another entity is dependent on a COM+ application that is not being installed. ([2] [3] [4] [5]) + The COM+ application was not found. ([2] [3] [4] [5]) + A COM+ application with the same id already exists. ([2] [3] [4] [5]) + A COM+ application with the same name already exists. ([2] [3] [4] [5]) + Another entity is dependent on a COM+ application role that is not being installed. ([2] [3] [4] [5]) + The COM+ application role was not found. ([2] [3] [4] [5]) + A COM+ application role with the same name already exists. ([2] [3] [4] [5]) + Another entity is dependent on a COM+ assembly that is not being installed. ([2] [3] [4] [5]) + A COM+ component event subscription with the same id already exists. ([2] [3] [4] [5]) + A COM+ component event subscription with the same name already exists. ([2] [3] [4] [5]) + Failed to lookup user account names. ([2] [3] [4] [5]) + + Registering COM+ components + Unregistering COM+ components + + Creating COM+ partitions + Partition: [1] + Removing COM+ partitions + Partition: [1] + Adding users to COM+ partition roles + Role: [1] + Removing users from COM+ partition roles + Role: [1] + Setting default COM+ partitions for users + User: [1] + Removing default COM+ partitions for users + User: [1] + Creating COM+ applications + Application: [1] + Removing COM+ applications + Application: [1] + Creating COM+ application roles + Role: [1] + Removing COM+ application roles + Role: [1] + Adding users to COM+ application roles + User: [1] + Removing users from COM+ application roles + User: [1] + Registering COM+ components + DLL: [1] + Unregistering COM+ components + DLL: [1] + Assigning roles to COM+ components + Component: [1] + Removing role assignments from COM+ components + Component: [1] + Creating subscriptions for COM+ components + Subscription: [1] + Removing subscriptions for COM+ components + Subscription: [1] + diff --git a/src/wixlib/es-es.wxl b/src/wixlib/es-es.wxl new file mode 100644 index 00000000..5e7eba66 --- /dev/null +++ b/src/wixlib/es-es.wxl @@ -0,0 +1,72 @@ + + + + + + No se puede conectar al catálogo de administración de COM+. ([2] [3] [4] [5]) + Falla al leer las particiones COM+. ([2] [3] [4] [5]) + Falla al leer los roles de las particiones COM+. ([2] [3] [4] [5]) + Falla al leer los usuario en los roles de las particiones COM+. ([2] [3] [4] [5]) + Falla al leer los usuario de las particiones COM+. ([2] [3] [4] [5]) + Falla al leer las aplicaciones COM+. ([2] [3] [4] [5]) + Falla al leer los roles de las aplicaciones COM+. ([2] [3] [4] [5]) + Falla al leer los usuario de las aplicaciones COM+. ([2] [3] [4] [5]) + Falla al leer los ensamblados COM+. ([2] [3] [4] [5]) + Falla al leer las suscripciones a eventos COM+. ([2] [3] [4] [5]) + Otra entidad es dependiente de una partición COM+ que no está siendo instalada. ([2] [3] [4] [5]) + La partición COM+ no pudo ser encontrada. ([2] [3] [4] [5]) + Ya existe otra partición COM+ con el mismo id. ([2] [3] [4] [5]) + Ya existe otra partición COM+ con el mismo nombre. ([2] [3] [4] [5]) + Otra entidad es dependiente de una aplicación COM+ que no está siendo instalada. ([2] [3] [4] [5]) + La aplicación COM+ no pudo ser encontrada. ([2] [3] [4] [5]) + Ya existe otra aplicación COM+ con el mismo id. ([2] [3] [4] [5]) + Ya existe otra aplicación COM+ con el mismo nombre. ([2] [3] [4] [5]) + Otra entidad es dependiente de un rol de aplicación COM+ que no está siendo instalado. ([2] [3] [4] [5]) + El rol de aplicación COM+ no pudo ser encontrado. ([2] [3] [4] [5]) + Ya existe otro rol de aplicación COM+ con el mismo nombre. ([2] [3] [4] [5]) + Otra entidad es dependiente de un ensamblado COM+ que no está siendo instalado. ([2] [3] [4] [5]) + Ya existe otra suscripción de evento al componente COM+ con el mismo id. ([2] [3] [4] [5]) + Ya existe otra suscripción de evento al componente COM+ con el mismo nombre. ([2] [3] [4] [5]) + Falla el la búsqueda de los nombres de usuario. ([2] [3] [4] [5]) + + Registrando componentes COM+ + Anular el registro de componentes COM+ + + Creando particiones COM+ + Particiones: [1] + Borrando particiones COM+ + Particiones: [1] + Agregando usuarios a los roles de las particiones COM+ + Rol: [1] + Borrando usuarios a los roles de las particiones COM+ + Rol: [1] + Ajustando partición COM+ por omisión para los usuarios + Usuario: [1] + Borrando partición COM+ por omisión para los usuarios + Usuario: [1] + Creando aplicación COM+ + Aplicación: [1] + Borrando aplicación COM+ + Aplicación: [1] + Creando roles de aplicación COM+ + Rol: [1] + Borrando roles de aplicación COM+ + Rol: [1] + Agregando usuarios a los roles de aplicación COM+ + Usuario: [1] + Borrando usuarios a los roles de aplicación COM + Usuario: [1] + Registrando componente COM+ + DLL: [1] + Anulando el registro de componentes COM+ + DLL: [1] + Asignando roles a los componentes COM+ + Componente: [1] + Borrando asignación de roles a los componentes COM+ + Componente: [1] + Creando suscripción a componentes COM+ + Suscripción: [1] + Borrando suscripción a componentes COM+ + Suscripción: [1] + + diff --git a/src/wixlib/ja-jp.wxl b/src/wixlib/ja-jp.wxl new file mode 100644 index 00000000..03b2cf1c --- /dev/null +++ b/src/wixlib/ja-jp.wxl @@ -0,0 +1,71 @@ + + + + + + COM+ 管理カタログへ接続できません。 ([2] [3] [4] [5]) + COM+ パーティションの読み込みに失敗しました。 ([2] [3] [4] [5]) + COM+ パーティション役割の読み込みに失敗しました。 ([2] [3] [4] [5]) + COM+ パーティション役割内ユーザーの読み込みに失敗しました。 ([2] [3] [4] [5]) + COM+ パーティション ユーザーの読み込みに失敗しました。 ([2] [3] [4] [5]) + COM+ アプリケーションの読み込みに失敗しました。 ([2] [3] [4] [5]) + COM+ アプリケーション役割の読み込みに失敗しました。 ([2] [3] [4] [5]) + COM+ アプリケーション役割内ユーザーの読み込みに失敗しました。 ([2] [3] [4] [5]) + COM+ アセンブリの読み込みに失敗しました。 ([2] [3] [4] [5]) + COM+ イベント登録の読み込みに失敗しました。 ([2] [3] [4] [5]) + 他のエンティティはインストールされない COM+ パーティションに依存します。 ([2] [3] [4] [5]) + COM+ パーティションは見つかりません ([2] [3] [4] [5]) + 同一 ID を持つ COM+ パーティションが既に存在します。 ([2] [3] [4] [5]) + 同一名称を持つ COM+ パーティションが既に存在します。 ([2] [3] [4] [5]) + 他のエンティティはインストールされない COM+ アプリケーションに依存します。 ([2] [3] [4] [5]) + COM+ アプリケーションは見つかりません。 ([2] [3] [4] [5]) + 同一 ID を持つ COM+ アプリケーションが既に存在します。 ([2] [3] [4] [5]) + 同一名称を持つ COM+ アプリケーションが既に存在します。 ([2] [3] [4] [5]) + 他のエンティティはインストールされない COM+ アプリケーション役割に依存します。 ([2] [3] [4] [5]) + COM+ アプリケーション役割は見つかりません。 ([2] [3] [4] [5]) + 同一名称を持つ COM+ アプリケーション役割が既に存在します。 ([2] [3] [4] [5]) + 他のエンティティはインストールされない COM+ アセンブリに依存します。 ([2] [3] [4] [5]) + 同一 ID を持つ COM+ コンポーネントのイベント登録が既に存在します。 ([2] [3] [4] [5]) + 同一名称を持つ COM+ コンポーネントのイベント登録が既に存在します。 ([2] [3] [4] [5]) + ユーザー アカウント名の照合に失敗しました。 ([2] [3] [4] [5]) + + COM+ コンポーネントを登録しています + COM+ コンポーネント登録を解除しています + + COM+ パーティションを作成しています + パーティション: [1] + COM+ パーティションを削除しています + パーティション: [1] + ユーザーを COM+ パーティション役割に追加しています + 役割: [1] + ユーザを COM+ パーティション役割より削除しています + 役割: [1] + ユーザーのデフォルト COM+ 役割を設定しています + ユーザー: [1] + ユーザーのデフォルト COM+ パーティション役割を削除しています + ユーザー: [1] + COM+ アプリケーションを作成しています + アプリケーション: [1] + COM+ アプリケーションを削除しています + アプリケーション: [1] + COM+ アプリケーション役割を作成しています + 役割: [1] + COM+ アプリケーション役割を削除しています + 役割: [1] + ユーザーを COM+ アプリケーション役割に追加しています + ユーザー: [1] + ユーザーを COM+ アプリケーション役割より削除しています + ユーザー: [1] + COM+ コンポーネントを登録しています + DLL: [1] + COM+ コンポーネント登録を解除しています + DLL: [1] + COM+ コンポーネントへ役割を割り当てています + コンポーネント: [1] + COM+ コンポーネントより役割割当を削除しています + コンポーネント: [1] + COM+ コンポーネント用登録を作成しています + 登録: [1] + COM+ コンポーネント用登録を削除しています + 登録: [1] + -- cgit v1.2.3-55-g6feb