From c94f50e3d8dc958f8a0b9540e63e920a079c1779 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Mon, 4 Feb 2019 20:04:35 -0600 Subject: Initial commit --- .gitattributes | 2 + .gitignore | 341 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE.TXT | 28 +++++ README.md | 2 + 4 files changed, 373 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE.TXT create mode 100644 README.md diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..dfe07704 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3e8a1553 --- /dev/null +++ b/.gitignore @@ -0,0 +1,341 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ +# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true +**/wwwroot/lib/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 00000000..d4d316ef --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,28 @@ +Copyright (c) .NET Foundation and contributors. +This software is released under the Microsoft Reciprocal License (MS-RL) (the "License"); you may not use the software except in compliance with the License. + +The text of the Microsoft Reciprocal License (MS-RL) can be found online at: + http://opensource.org/licenses/ms-rl + + +Microsoft Reciprocal License (MS-RL) + +This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. + +1. Definitions + The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. + A "contribution" is the original software, or any additions or changes to the software. + A "contributor" is any person that distributes its contribution under this license. + "Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights + (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations + (A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. You may license other files that are entirely your own work and do not contain code from the software under any terms you choose. + (B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + (C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + (D) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + (E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + (F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. diff --git a/README.md b/README.md new file mode 100644 index 00000000..8604c104 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# ComPlus.wixext +WixToolset.ComPlus.wixext - COM+ WiX Toolset Extension -- cgit v1.2.3-55-g6feb 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 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 From c239e0cc3a28a50c42c63b086ee62e17cf699104 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Mon, 4 Feb 2019 20:06:58 -0600 Subject: Integrate into latest v4. --- .editorconfig | 37 + ComPlus.wixext.sln | 64 ++ appveyor.cmd | 16 + appveyor.yml | 42 + nuget.config | 16 + src/Cpp.Build.props | 106 ++ src/Directory.Build.props | 28 + src/Directory.Build.targets | 48 + src/FindLocalWix.props | 8 + src/Wix.Build.props | 31 + src/ca/complusca.def | 15 + src/ca/complusca.vcxproj | 99 ++ src/ca/cpappexec.cpp | 4 +- src/ca/cpappsched.cpp | 10 +- src/ca/cpasmexec.cpp | 133 ++- src/ca/cpasmsched.cpp | 82 +- src/ca/cpasmsched.h | 30 +- src/ca/cpexec.cpp | 43 +- src/ca/cpexec.def | 11 - src/ca/cppartexec.cpp | 4 +- src/ca/cppartsched.cpp | 12 +- src/ca/cpsched.cpp | 36 +- src/ca/cpsubssched.cpp | 6 +- src/ca/cpsubssched.h | 2 +- src/ca/cputilexec.cpp | 56 +- src/ca/cputilexec.h | 14 +- src/ca/cputilsched.cpp | 28 +- src/ca/cputilsched.h | 26 +- src/ca/custommsierrors.h | 29 + src/ca/dllmain.cpp | 27 + src/ca/packages.config | 5 + src/ca/precomp.h | 33 + .../ComPlusExtensionFixture.cs | 32 + .../UsingComPlusPartition/Package.en-us.wxl | 11 + .../TestData/UsingComPlusPartition/Package.wxs | 22 + .../UsingComPlusPartition/PackageComponents.wxs | 12 + .../TestData/UsingComPlusPartition/example.txt | 1 + .../WixToolsetTest.ComPlus.csproj | 38 + src/wixext/ComPlusCompiler.cs | 1079 ++++++++++---------- src/wixext/ComPlusDecompiler.cs | 4 +- src/wixext/ComPlusErrors.cs | 72 ++ src/wixext/ComPlusExtensionData.cs | 50 +- src/wixext/ComPlusExtensionFactory.cs | 18 + src/wixext/ComPlusWarnings.cs | 31 + ...omPlusWindowsInstallerBackendBinderExtension.cs | 26 + .../Tuples/ComPlusApplicationPropertyTuple.cs | 63 ++ .../Tuples/ComPlusApplicationRolePropertyTuple.cs | 63 ++ src/wixext/Tuples/ComPlusApplicationRoleTuple.cs | 71 ++ src/wixext/Tuples/ComPlusApplicationTuple.cs | 79 ++ .../Tuples/ComPlusAssemblyDependencyTuple.cs | 55 + src/wixext/Tuples/ComPlusAssemblyTuple.cs | 103 ++ src/wixext/Tuples/ComPlusComponentPropertyTuple.cs | 63 ++ src/wixext/Tuples/ComPlusComponentTuple.cs | 63 ++ .../Tuples/ComPlusGroupInApplicationRoleTuple.cs | 71 ++ .../Tuples/ComPlusGroupInPartitionRoleTuple.cs | 71 ++ src/wixext/Tuples/ComPlusInterfacePropertyTuple.cs | 63 ++ src/wixext/Tuples/ComPlusInterfaceTuple.cs | 63 ++ src/wixext/Tuples/ComPlusMethodPropertyTuple.cs | 63 ++ src/wixext/Tuples/ComPlusMethodTuple.cs | 71 ++ src/wixext/Tuples/ComPlusPartitionPropertyTuple.cs | 63 ++ src/wixext/Tuples/ComPlusPartitionRoleTuple.cs | 71 ++ src/wixext/Tuples/ComPlusPartitionTuple.cs | 71 ++ src/wixext/Tuples/ComPlusPartitionUserTuple.cs | 71 ++ src/wixext/Tuples/ComPlusRoleForComponentTuple.cs | 71 ++ src/wixext/Tuples/ComPlusRoleForInterfaceTuple.cs | 71 ++ src/wixext/Tuples/ComPlusRoleForMethodTuple.cs | 71 ++ .../Tuples/ComPlusSubscriptionPropertyTuple.cs | 63 ++ src/wixext/Tuples/ComPlusSubscriptionTuple.cs | 95 ++ src/wixext/Tuples/ComPlusTupleDefinitions.cs | 135 +++ .../Tuples/ComPlusUserInApplicationRoleTuple.cs | 71 ++ .../Tuples/ComPlusUserInPartitionRoleTuple.cs | 71 ++ src/wixext/WixComPlusExtension.csproj | 50 - src/wixext/WixToolset.ComPlus.wixext.csproj | 33 + src/wixext/WixToolset.ComPlus.wixext.targets | 11 + src/wixext/messages.xml | 77 -- src/wixlib/ComPlusExtension.wixproj | 26 - src/wixlib/ComPlusExtension.wxs | 58 +- src/wixlib/caerr.wxi | 96 ++ src/wixlib/complus.wixproj | 36 + src/wixlib/packages.config | 5 + version.json | 11 + 81 files changed, 3728 insertions(+), 1058 deletions(-) create mode 100644 .editorconfig create mode 100644 ComPlus.wixext.sln create mode 100644 appveyor.cmd create mode 100644 appveyor.yml create mode 100644 nuget.config create mode 100644 src/Cpp.Build.props create mode 100644 src/Directory.Build.props create mode 100644 src/Directory.Build.targets create mode 100644 src/FindLocalWix.props create mode 100644 src/Wix.Build.props create mode 100644 src/ca/complusca.def create mode 100644 src/ca/complusca.vcxproj delete mode 100644 src/ca/cpexec.def create mode 100644 src/ca/custommsierrors.h create mode 100644 src/ca/dllmain.cpp create mode 100644 src/ca/packages.config create mode 100644 src/ca/precomp.h create mode 100644 src/test/WixToolsetTest.ComPlus/ComPlusExtensionFixture.cs create mode 100644 src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/Package.en-us.wxl create mode 100644 src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/Package.wxs create mode 100644 src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/PackageComponents.wxs create mode 100644 src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/example.txt create mode 100644 src/test/WixToolsetTest.ComPlus/WixToolsetTest.ComPlus.csproj create mode 100644 src/wixext/ComPlusErrors.cs create mode 100644 src/wixext/ComPlusExtensionFactory.cs create mode 100644 src/wixext/ComPlusWarnings.cs create mode 100644 src/wixext/ComPlusWindowsInstallerBackendBinderExtension.cs create mode 100644 src/wixext/Tuples/ComPlusApplicationPropertyTuple.cs create mode 100644 src/wixext/Tuples/ComPlusApplicationRolePropertyTuple.cs create mode 100644 src/wixext/Tuples/ComPlusApplicationRoleTuple.cs create mode 100644 src/wixext/Tuples/ComPlusApplicationTuple.cs create mode 100644 src/wixext/Tuples/ComPlusAssemblyDependencyTuple.cs create mode 100644 src/wixext/Tuples/ComPlusAssemblyTuple.cs create mode 100644 src/wixext/Tuples/ComPlusComponentPropertyTuple.cs create mode 100644 src/wixext/Tuples/ComPlusComponentTuple.cs create mode 100644 src/wixext/Tuples/ComPlusGroupInApplicationRoleTuple.cs create mode 100644 src/wixext/Tuples/ComPlusGroupInPartitionRoleTuple.cs create mode 100644 src/wixext/Tuples/ComPlusInterfacePropertyTuple.cs create mode 100644 src/wixext/Tuples/ComPlusInterfaceTuple.cs create mode 100644 src/wixext/Tuples/ComPlusMethodPropertyTuple.cs create mode 100644 src/wixext/Tuples/ComPlusMethodTuple.cs create mode 100644 src/wixext/Tuples/ComPlusPartitionPropertyTuple.cs create mode 100644 src/wixext/Tuples/ComPlusPartitionRoleTuple.cs create mode 100644 src/wixext/Tuples/ComPlusPartitionTuple.cs create mode 100644 src/wixext/Tuples/ComPlusPartitionUserTuple.cs create mode 100644 src/wixext/Tuples/ComPlusRoleForComponentTuple.cs create mode 100644 src/wixext/Tuples/ComPlusRoleForInterfaceTuple.cs create mode 100644 src/wixext/Tuples/ComPlusRoleForMethodTuple.cs create mode 100644 src/wixext/Tuples/ComPlusSubscriptionPropertyTuple.cs create mode 100644 src/wixext/Tuples/ComPlusSubscriptionTuple.cs create mode 100644 src/wixext/Tuples/ComPlusTupleDefinitions.cs create mode 100644 src/wixext/Tuples/ComPlusUserInApplicationRoleTuple.cs create mode 100644 src/wixext/Tuples/ComPlusUserInPartitionRoleTuple.cs delete mode 100644 src/wixext/WixComPlusExtension.csproj create mode 100644 src/wixext/WixToolset.ComPlus.wixext.csproj create mode 100644 src/wixext/WixToolset.ComPlus.wixext.targets delete mode 100644 src/wixext/messages.xml delete mode 100644 src/wixlib/ComPlusExtension.wixproj create mode 100644 src/wixlib/caerr.wxi create mode 100644 src/wixlib/complus.wixproj create mode 100644 src/wixlib/packages.config create mode 100644 version.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..1d72e683 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,37 @@ +# 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. +# +# Do NOT modify this file. Update the canonical version in Home\repo-template\src\.editorconfig +# then update all of the repos. + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.{cs,vb}] +dotnet_sort_system_directives_first = true + +[*.cs] +csharp_indent_case_contents = true : error +csharp_indent_switch_labels = true : error +csharp_new_line_before_open_brace = all +csharp_prefer_braces = true : error +csharp_style_expression_bodied_methods = when_on_single_line : suggestion +csharp_style_expression_bodied_constructors = when_on_single_line : suggestion +csharp_style_expression_bodied_operators = when_on_single_line : suggestion +csharp_style_expression_bodied_properties = when_on_single_line : suggestion +csharp_style_expression_bodied_indexers = when_on_single_line : suggestion +csharp_style_expression_bodied_accessors = when_on_single_line : suggestion +csharp_style_var_elsewhere = true : suggestion +csharp_style_var_for_built_in_types = true : suggestion +csharp_style_var_when_type_is_apparent = true : suggestion +dotnet_style_qualification_for_event = true : error +dotnet_style_qualification_for_field = true : error +dotnet_style_qualification_for_method = true : error +dotnet_style_qualification_for_property = true : error + +[*.targets] +indent_size = 2 diff --git a/ComPlus.wixext.sln b/ComPlus.wixext.sln new file mode 100644 index 00000000..f117e399 --- /dev/null +++ b/ComPlus.wixext.sln @@ -0,0 +1,64 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.2016 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "complusca", "src\ca\complusca.vcxproj", "{BDEF51ED-E242-4FA2-801A-01B127DF851A}" +EndProject +Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "complus", "src\wixlib\complus.wixproj", "{E191E61E-E098-4F71-888F-51A79F952022}" + ProjectSection(ProjectDependencies) = postProject + {BDEF51ED-E242-4FA2-801A-01B127DF851A} = {BDEF51ED-E242-4FA2-801A-01B127DF851A} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.ComPlus.wixext", "src\wixext\WixToolset.ComPlus.wixext.csproj", "{1497B777-330B-4CFE-927A-22850CD24D64}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.ComPlus", "src\test\WixToolsetTest.ComPlus\WixToolsetTest.ComPlus.csproj", "{2FC5F039-EACF-428B-BA87-8CDE1D25E121}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BDEF51ED-E242-4FA2-801A-01B127DF851A}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {BDEF51ED-E242-4FA2-801A-01B127DF851A}.Debug|Any CPU.Build.0 = Debug|Win32 + {BDEF51ED-E242-4FA2-801A-01B127DF851A}.Debug|x86.ActiveCfg = Debug|Win32 + {BDEF51ED-E242-4FA2-801A-01B127DF851A}.Debug|x86.Build.0 = Debug|Win32 + {BDEF51ED-E242-4FA2-801A-01B127DF851A}.Release|Any CPU.ActiveCfg = Release|Win32 + {BDEF51ED-E242-4FA2-801A-01B127DF851A}.Release|Any CPU.Build.0 = Release|Win32 + {BDEF51ED-E242-4FA2-801A-01B127DF851A}.Release|x86.ActiveCfg = Release|Win32 + {BDEF51ED-E242-4FA2-801A-01B127DF851A}.Release|x86.Build.0 = Release|Win32 + {E191E61E-E098-4F71-888F-51A79F952022}.Debug|Any CPU.ActiveCfg = Debug|x86 + {E191E61E-E098-4F71-888F-51A79F952022}.Debug|Any CPU.Build.0 = Debug|x86 + {E191E61E-E098-4F71-888F-51A79F952022}.Debug|x86.ActiveCfg = Debug|x86 + {E191E61E-E098-4F71-888F-51A79F952022}.Debug|x86.Build.0 = Debug|x86 + {E191E61E-E098-4F71-888F-51A79F952022}.Release|Any CPU.ActiveCfg = Release|x86 + {E191E61E-E098-4F71-888F-51A79F952022}.Release|Any CPU.Build.0 = Release|x86 + {E191E61E-E098-4F71-888F-51A79F952022}.Release|x86.ActiveCfg = Release|x86 + {E191E61E-E098-4F71-888F-51A79F952022}.Release|x86.Build.0 = Release|x86 + {1497B777-330B-4CFE-927A-22850CD24D64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1497B777-330B-4CFE-927A-22850CD24D64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1497B777-330B-4CFE-927A-22850CD24D64}.Debug|x86.ActiveCfg = Debug|Any CPU + {1497B777-330B-4CFE-927A-22850CD24D64}.Debug|x86.Build.0 = Debug|Any CPU + {1497B777-330B-4CFE-927A-22850CD24D64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1497B777-330B-4CFE-927A-22850CD24D64}.Release|Any CPU.Build.0 = Release|Any CPU + {1497B777-330B-4CFE-927A-22850CD24D64}.Release|x86.ActiveCfg = Release|Any CPU + {1497B777-330B-4CFE-927A-22850CD24D64}.Release|x86.Build.0 = Release|Any CPU + {2FC5F039-EACF-428B-BA87-8CDE1D25E121}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2FC5F039-EACF-428B-BA87-8CDE1D25E121}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2FC5F039-EACF-428B-BA87-8CDE1D25E121}.Debug|x86.ActiveCfg = Debug|Any CPU + {2FC5F039-EACF-428B-BA87-8CDE1D25E121}.Debug|x86.Build.0 = Debug|Any CPU + {2FC5F039-EACF-428B-BA87-8CDE1D25E121}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2FC5F039-EACF-428B-BA87-8CDE1D25E121}.Release|Any CPU.Build.0 = Release|Any CPU + {2FC5F039-EACF-428B-BA87-8CDE1D25E121}.Release|x86.ActiveCfg = Release|Any CPU + {2FC5F039-EACF-428B-BA87-8CDE1D25E121}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3E1857C4-5EE1-4C9E-9390-9954E041546D} + EndGlobalSection +EndGlobal diff --git a/appveyor.cmd b/appveyor.cmd new file mode 100644 index 00000000..8a48fe2b --- /dev/null +++ b/appveyor.cmd @@ -0,0 +1,16 @@ +@setlocal +@pushd %~dp0 + +nuget restore + +msbuild -p:Configuration=Release -t:Restore + +msbuild -p:Configuration=Release -p:Platform=Win32 src\ca\complusca.vcxproj +msbuild -p:Configuration=Release -p:Platform=x64 src\ca\complusca.vcxproj + +msbuild -p:Configuration=Release src\test\WixToolsetTest.ComPlus\WixToolsetTest.ComPlus.csproj + +msbuild -p:Configuration=Release -t:Pack src\wixext\WixToolset.ComPlus.wixext.csproj + +@popd +@endlocal \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..8d80c6af --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,42 @@ +# 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. +# +# Do NOT modify this file. Update the canonical version in Home\repo-template\src\appveyor.yml +# then update all of the repos. + +branches: + only: + - master + - develop + +image: Visual Studio 2017 + +version: 0.0.0.{build} +configuration: Release + +environment: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + NUGET_XMLDOC_MODE: skip + +build_script: + - appveyor.cmd + +pull_requests: + do_not_increment_build_number: true + +nuget: + disable_publish_on_pr: true + +skip_branch_with_pr: true +skip_tags: true + +artifacts: +- path: build\Release\**\*.nupkg + name: nuget +- path: build\Release\**\*.msi + name: msi + +notifications: +- provider: Slack + incoming_webhook: + secure: p5xuu+4x2JHfwGDMDe5KcG1k7gZxqYc4jWVwvyNZv5cvkubPD2waJs5yXMAXZNN7Z63/3PWHb7q4KoY/99AjauYa1nZ4c5qYqRPFRBKTHfA= diff --git a/nuget.config b/nuget.config new file mode 100644 index 00000000..aaee3228 --- /dev/null +++ b/nuget.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Cpp.Build.props b/src/Cpp.Build.props new file mode 100644 index 00000000..c6ced58e --- /dev/null +++ b/src/Cpp.Build.props @@ -0,0 +1,106 @@ + + + + + + Win32 + x86 + $(Platform) + $(BaseIntermediateOutputPath)$(Configuration)\$(NormalizedPlatform)\ + $(OutputPath)$(NormalizedPlatform)\ + + + + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) + + + + + $(DisableSpecificCompilerWarnings) + Level4 + $(ProjectDir)inc;$(MSBuildProjectDirectory);$(IntDir);$(SqlCESdkIncludePath);$(ProjectAdditionalIncludeDirectories);%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_WIN32_MSI=500;_WIN32_WINNT=0x0501;$(ArmPreprocessorDefinitions);$(UnicodePreprocessorDefinitions);_CRT_STDIO_LEGACY_WIDE_SPECIFIERS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + Use + precomp.h + StdCall + true + false + -YlprecompDefine + /Zc:threadSafeInit- %(AdditionalOptions) + true + + + $(ArmPreprocessorDefinitions);%(PreprocessorDefinitions) + $(ProjectAdditionalResourceIncludeDirectories);%(AdditionalIncludeDirectories) + + + $(OutDir);$(AdditionalMultiTargetLibraryPath);$(ProjectAdditionalLibraryDirectories);%(AdditionalLibraryDirectories) + + + $(ProjectSubSystem) + $(ProjectModuleDefinitionFile) + $(ResourceOnlyDll) + true + $(ProjectAdditionalLinkLibraries);advapi32.lib;comdlg32.lib;user32.lib;oleaut32.lib;gdi32.lib;shell32.lib;ole32.lib;version.lib;%(AdditionalDependencies) + $(OutDir);$(AdditionalMultiTargetLibraryPath);$(ArmLibraryDirectories);$(ProjectAdditionalLinkLibraryDirectories);%(AdditionalLibraryDirectories) + /IGNORE:4099 %(AdditionalOptions) + + + + + + NoExtensions + + + + + CDecl + + + + + OldStyle + true + true + + + + + Disabled + EnableFastChecks + _DEBUG;DEBUG;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + MultiThreadedDebugDll + + + + + MinSpace + NDEBUG;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + + + + + + MultiThreadedDll + + + + + $(LinkKeyFile) + $(LinkDelaySign) + + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 00000000..a22f4470 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,28 @@ + + + + + + Debug + false + MSB3246 + + $(MSBuildProjectName) + $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\)) + $(BaseOutputPath)obj\$(ProjectName)\ + $(BaseOutputPath)$(Configuration)\ + + WiX Toolset Team + WiX Toolset + Copyright (c) .NET Foundation and contributors. All rights reserved. + MS-RL + WiX Toolset + + + + + + diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets new file mode 100644 index 00000000..dac7452a --- /dev/null +++ b/src/Directory.Build.targets @@ -0,0 +1,48 @@ + + + + + + + true + $(SolutionPath) + $(NCrunchOriginalSolutionPath) + + + + + + + $([System.IO.File]::ReadAllText($(TheSolutionPath))) + $([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) )) + (?<="[PackageName]", ")(.*)(?=", ") + + + + + + %(Identity) + $(SolutionFileContent.Contains('\%(Identity).csproj')) + + + + + $(RegexPattern.Replace('[PackageName]','%(PackageName)') ) + $([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)')) + + + + + + + + + + + diff --git a/src/FindLocalWix.props b/src/FindLocalWix.props new file mode 100644 index 00000000..a784e352 --- /dev/null +++ b/src/FindLocalWix.props @@ -0,0 +1,8 @@ + + + + + + $(MSBuildThisFileDirectory)..\..\Tools\build\Debug\net461\wix.targets + + diff --git a/src/Wix.Build.props b/src/Wix.Build.props new file mode 100644 index 00000000..a81c9615 --- /dev/null +++ b/src/Wix.Build.props @@ -0,0 +1,31 @@ + + + + + + $(DefineConstants);CompanyName=$(Company) + $(OutputPath)x86\ + $(OutputPath)x64\ + $(OutputPath)ARM\ + $(OutputPath)ARM64\ + $(OutputPath)Win32\ + + + + + x86 + + + x64 + + + arm + + + arm64 + + + win32 + + + diff --git a/src/ca/complusca.def b/src/ca/complusca.def new file mode 100644 index 00000000..7c475759 --- /dev/null +++ b/src/ca/complusca.def @@ -0,0 +1,15 @@ +; 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. + + +LIBRARY "complusca" + +EXPORTS + ComPlusPrepare + ComPlusCleanup + ComPlusInstallExecute + ComPlusInstallExecuteCommit + ComPlusRollbackInstallExecute + ComPlusUninstallExecute + ComPlusRollbackUninstallExecute + ConfigureComPlusInstall + ConfigureComPlusUninstall diff --git a/src/ca/complusca.vcxproj b/src/ca/complusca.vcxproj new file mode 100644 index 00000000..5085f61d --- /dev/null +++ b/src/ca/complusca.vcxproj @@ -0,0 +1,99 @@ + + + + + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + {BDEF51ED-E242-4FA2-801A-01B127DF851A} + DynamicLibrary + v141 + Unicode + complusca + complusca.def + WiX Toolset ComPlus CustomAction + + + + + + + msi.lib + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + diff --git a/src/ca/cpappexec.cpp b/src/ca/cpappexec.cpp index 43d6cd6d..48948210 100644 --- a/src/ca/cpappexec.cpp +++ b/src/ca/cpappexec.cpp @@ -239,7 +239,7 @@ static HRESULT CreateApplication( WcaLog(LOGMSG_VERBOSE, "Creating application, key: %S", pAttrs->pwzKey); // get applications collection - hr = CpiGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl); + hr = CpiExecGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl); if (S_FALSE == hr) hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); ExitOnFailure(hr, "Failed to get applications collection"); @@ -304,7 +304,7 @@ static HRESULT RemoveApplication( WcaLog(LOGMSG_VERBOSE, "Removing application, key: %S", pAttrs->pwzKey); // get applications collection - hr = CpiGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl); + hr = CpiExecGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl); ExitOnFailure(hr, "Failed to get applications collection"); if (S_FALSE == hr) diff --git a/src/ca/cpappsched.cpp b/src/ca/cpappsched.cpp index cec99794..1fb2203b 100644 --- a/src/ca/cpappsched.cpp +++ b/src/ca/cpappsched.cpp @@ -579,7 +579,7 @@ HRESULT CpiGetRolesCollForApplication( if (pApp->pPartition) hr = CpiGetApplicationsCollForPartition(pApp->pPartition, &piAppColl); else - hr = CpiGetApplicationsCollection(&piAppColl); + hr = CpiSchedGetApplicationsCollection(&piAppColl); ExitOnFailure(hr, "Failed to get applications collection"); if (S_FALSE == hr) @@ -593,7 +593,7 @@ HRESULT CpiGetRolesCollForApplication( ExitFunction(); // exit with hr = S_FALSE // get roles collection - hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Roles", &pApp->piRolesColl); + hr = CpiSchedGetCatalogCollection(piAppColl, piAppObj, L"Roles", &pApp->piRolesColl); ExitOnFailure(hr, "Failed to get roles collection"); } @@ -632,7 +632,7 @@ HRESULT CpiGetComponentsCollForApplication( if (pApp->pPartition) hr = CpiGetApplicationsCollForPartition(pApp->pPartition, &piAppColl); else - hr = CpiGetApplicationsCollection(&piAppColl); + hr = CpiSchedGetApplicationsCollection(&piAppColl); ExitOnFailure(hr, "Failed to get applications collection"); if (S_FALSE == hr) @@ -646,7 +646,7 @@ HRESULT CpiGetComponentsCollForApplication( ExitFunction(); // exit with hr = S_FALSE // get roles collection - hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Components", &pApp->piCompsColl); + hr = CpiSchedGetCatalogCollection(piAppColl, piAppObj, L"Components", &pApp->piCompsColl); ExitOnFailure(hr, "Failed to get components collection"); } @@ -695,7 +695,7 @@ static HRESULT FindObjectForApplication( if (pItm->pPartition) hr = CpiGetApplicationsCollForPartition(pItm->pPartition, &piAppColl); else - hr = CpiGetApplicationsCollection(&piAppColl); + hr = CpiSchedGetApplicationsCollection(&piAppColl); ExitOnFailure(hr, "Failed to get applications collection"); if (S_FALSE == hr) diff --git a/src/ca/cpasmexec.cpp b/src/ca/cpasmexec.cpp index 339c08e1..3d140027 100644 --- a/src/ca/cpasmexec.cpp +++ b/src/ca/cpasmexec.cpp @@ -75,58 +75,47 @@ enum eInstallationFlags { }; -// private constants - -enum eAssemblyAttributes -{ - aaEventClass = (1 << 0), - aaDotNetAssembly = (1 << 1), - aaPathFromGAC = (1 << 2), - aaRunInCommit = (1 << 3) -}; - - // private structs -struct CPI_ROLE_ASSIGNMENT +struct CPIEXEC_ROLE_ASSIGNMENT { WCHAR wzKey[MAX_DARWIN_KEY + 1]; WCHAR wzRoleName[MAX_DARWIN_COLUMN + 1]; - CPI_ROLE_ASSIGNMENT* pNext; + CPIEXEC_ROLE_ASSIGNMENT* pNext; }; -struct CPI_METHOD +struct CPIEXEC_METHOD { WCHAR wzIndex[11 + 1]; WCHAR wzName[MAX_DARWIN_COLUMN + 1]; CPI_PROPERTY* pPropertyList; - CPI_ROLE_ASSIGNMENT* pRoleAssignmentList; + CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList; - CPI_METHOD* pNext; + CPIEXEC_METHOD* pNext; }; -struct CPI_INTERFACE +struct CPIEXEC_INTERFACE { WCHAR wzIID[CPI_MAX_GUID + 1]; CPI_PROPERTY* pPropertyList; - CPI_ROLE_ASSIGNMENT* pRoleAssignmentList; - CPI_METHOD* pMethodList; + CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList; + CPIEXEC_METHOD* pMethodList; - CPI_INTERFACE* pNext; + CPIEXEC_INTERFACE* pNext; }; -struct CPI_COMPONENT +struct CPIEXEC_COMPONENT { WCHAR wzCLSID[CPI_MAX_GUID + 1]; CPI_PROPERTY* pPropertyList; - CPI_ROLE_ASSIGNMENT* pRoleAssignmentList; - CPI_INTERFACE* pInterfaceList; + CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList; + CPIEXEC_INTERFACE* pInterfaceList; - CPI_COMPONENT* pNext; + CPIEXEC_COMPONENT* pNext; }; struct CPI_ASSEMBLY_ATTRIBUTES @@ -141,7 +130,7 @@ struct CPI_ASSEMBLY_ATTRIBUTES LPWSTR pwzAppID; LPWSTR pwzPartID; int iAttributes; - CPI_COMPONENT* pCompList; + CPIEXEC_COMPONENT* pCompList; }; struct CPI_ROLE_ASSIGNMENTS_ATTRIBUTES @@ -152,7 +141,7 @@ struct CPI_ROLE_ASSIGNMENTS_ATTRIBUTES LPWSTR pwzAppID; LPWSTR pwzPartID; int iRoleCount; - CPI_COMPONENT* pCompList; + CPIEXEC_COMPONENT* pCompList; }; @@ -187,7 +176,7 @@ static HRESULT UnregisterDotNetAssembly( ); static HRESULT RemoveComponents( ICatalogCollection* piCompColl, - CPI_COMPONENT* pCompList + CPIEXEC_COMPONENT* pCompList ); static HRESULT ReadAssemblyAttributes( LPWSTR* ppwzData, @@ -206,56 +195,56 @@ static void FreeRoleAssignmentsAttributes( static HRESULT ConfigureComponents( LPCWSTR pwzPartID, LPCWSTR pwzAppID, - CPI_COMPONENT* pCompList, + CPIEXEC_COMPONENT* pCompList, BOOL fCreate, BOOL fProgress ); static HRESULT ConfigureInterfaces( ICatalogCollection* piCompColl, ICatalogObject* piCompObj, - CPI_INTERFACE* pIntfList, + CPIEXEC_INTERFACE* pIntfList, BOOL fCreate ); static HRESULT ConfigureMethods( ICatalogCollection* piIntfColl, ICatalogObject* piIntfObj, - CPI_METHOD* pMethList, + CPIEXEC_METHOD* pMethList, BOOL fCreate ); static HRESULT ConfigureRoleAssignments( LPCWSTR pwzCollName, ICatalogCollection* piCompColl, ICatalogObject* piCompObj, - CPI_ROLE_ASSIGNMENT* pRoleList, + CPIEXEC_ROLE_ASSIGNMENT* pRoleList, BOOL fCreate ); static HRESULT ReadComponentList( LPWSTR* ppwzData, - CPI_COMPONENT** ppCompList + CPIEXEC_COMPONENT** ppCompList ); static HRESULT ReadInterfaceList( LPWSTR* ppwzData, - CPI_INTERFACE** ppIntfList + CPIEXEC_INTERFACE** ppIntfList ); static HRESULT ReadMethodList( LPWSTR* ppwzData, - CPI_METHOD** ppMethList + CPIEXEC_METHOD** ppMethList ); static HRESULT ReadRoleAssignmentList( LPWSTR* ppwzData, - CPI_ROLE_ASSIGNMENT** ppRoleList + CPIEXEC_ROLE_ASSIGNMENT** ppRoleList ); static void FreeComponentList( - CPI_COMPONENT* pList + CPIEXEC_COMPONENT* pList ); static void FreeInterfaceList( - CPI_INTERFACE* pList + CPIEXEC_INTERFACE* pList ); static void FreeMethodList( - CPI_METHOD* pList + CPIEXEC_METHOD* pList ); static void FreeRoleAssignmentList( - CPI_ROLE_ASSIGNMENT* pList + CPIEXEC_ROLE_ASSIGNMENT* pList ); @@ -648,7 +637,7 @@ static HRESULT UnregisterAssembly( // TODO: handle rollbacks // get applications collection - hr = CpiGetApplicationsCollection(pAttrs->pwzPartID, &piColl); + hr = CpiExecGetApplicationsCollection(pAttrs->pwzPartID, &piColl); ExitOnFailure(hr, "Failed to get applications collection"); if (S_FALSE == hr) @@ -993,7 +982,7 @@ static HRESULT RegisterNativeAssembly( ExitOnNull(bstrPSDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path"); // get catalog - hr = CpiGetAdminCatalog(&piCatalog); + hr = CpiExecGetAdminCatalog(&piCatalog); ExitOnFailure(hr, "Failed to get COM+ admin catalog"); // get ICOMAdminCatalog2 interface @@ -1154,12 +1143,12 @@ LExit: static HRESULT RemoveComponents( ICatalogCollection* piCompColl, - CPI_COMPONENT* pCompList + CPIEXEC_COMPONENT* pCompList ) { HRESULT hr = S_OK; - for (CPI_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext) + for (CPIEXEC_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext) { // remove hr = CpiRemoveCollectionObject(piCompColl, pItm->wzCLSID, NULL, FALSE); @@ -1291,7 +1280,7 @@ static void FreeRoleAssignmentsAttributes( static HRESULT ConfigureComponents( LPCWSTR pwzPartID, LPCWSTR pwzAppID, - CPI_COMPONENT* pCompList, + CPIEXEC_COMPONENT* pCompList, BOOL fCreate, BOOL fProgress ) @@ -1313,7 +1302,7 @@ static HRESULT ConfigureComponents( ExitOnFailure(hr, "Failed to get components collection"); // read components - for (CPI_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext) + for (CPIEXEC_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext) { // progress message if (fProgress) @@ -1375,7 +1364,7 @@ LExit: static HRESULT ConfigureInterfaces( ICatalogCollection* piCompColl, ICatalogObject* piCompObj, - CPI_INTERFACE* pIntfList, + CPIEXEC_INTERFACE* pIntfList, BOOL fCreate ) { @@ -1396,7 +1385,7 @@ static HRESULT ConfigureInterfaces( ExitOnFailure(hr, "Failed to get interfaces collection"); // read interfaces - for (CPI_INTERFACE* pItm = pIntfList; pItm; pItm = pItm->pNext) + for (CPIEXEC_INTERFACE* pItm = pIntfList; pItm; pItm = pItm->pNext) { // find interface hr = CpiFindCollectionObjectByStringKey(piIntfColl, pItm->wzIID, &piIntfObj); @@ -1448,7 +1437,7 @@ LExit: static HRESULT ConfigureMethods( ICatalogCollection* piIntfColl, ICatalogObject* piIntfObj, - CPI_METHOD* pMethList, + CPIEXEC_METHOD* pMethList, BOOL fCreate ) { @@ -1469,7 +1458,7 @@ static HRESULT ConfigureMethods( ExitOnFailure(hr, "Failed to get methods collection"); // read methods - for (CPI_METHOD* pItm = pMethList; pItm; pItm = pItm->pNext) + for (CPIEXEC_METHOD* pItm = pMethList; pItm; pItm = pItm->pNext) { // find method if (*pItm->wzIndex) @@ -1519,7 +1508,7 @@ static HRESULT ConfigureRoleAssignments( LPCWSTR pwzCollName, ICatalogCollection* piCompColl, ICatalogObject* piCompObj, - CPI_ROLE_ASSIGNMENT* pRoleList, + CPIEXEC_ROLE_ASSIGNMENT* pRoleList, BOOL fCreate ) { @@ -1531,7 +1520,7 @@ static HRESULT ConfigureRoleAssignments( long lChanges = 0; // get roles collection - hr = CpiGetCatalogCollection(piCompColl, piCompObj, pwzCollName, &piRoleColl); + hr = CpiExecGetCatalogCollection(piCompColl, piCompObj, pwzCollName, &piRoleColl); if (S_FALSE == hr) if (fCreate) hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); @@ -1540,7 +1529,7 @@ static HRESULT ConfigureRoleAssignments( ExitOnFailure(hr, "Failed to get role assignments collection"); // read roles - for (CPI_ROLE_ASSIGNMENT* pItm = pRoleList; pItm; pItm = pItm->pNext) + for (CPIEXEC_ROLE_ASSIGNMENT* pItm = pRoleList; pItm; pItm = pItm->pNext) { if (fCreate) { @@ -1588,14 +1577,14 @@ LExit: static HRESULT ReadComponentList( LPWSTR* ppwzData, - CPI_COMPONENT** ppCompList + CPIEXEC_COMPONENT** ppCompList ) { HRESULT hr = S_OK; LPWSTR pwzData = NULL; - CPI_COMPONENT* pItm = NULL; + CPIEXEC_COMPONENT* pItm = NULL; int iCnt = 0; @@ -1606,7 +1595,7 @@ static HRESULT ReadComponentList( // read components for (int i = 0; i < iCnt; i++) { - pItm = (CPI_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_COMPONENT)); + pItm = (CPIEXEC_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_COMPONENT)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); @@ -1648,14 +1637,14 @@ LExit: static HRESULT ReadInterfaceList( LPWSTR* ppwzData, - CPI_INTERFACE** ppIntfList + CPIEXEC_INTERFACE** ppIntfList ) { HRESULT hr = S_OK; LPWSTR pwzData = NULL; - CPI_INTERFACE* pItm = NULL; + CPIEXEC_INTERFACE* pItm = NULL; int iCnt = 0; @@ -1666,7 +1655,7 @@ static HRESULT ReadInterfaceList( // read interfaces for (int i = 0; i < iCnt; i++) { - pItm = (CPI_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_INTERFACE)); + pItm = (CPIEXEC_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_INTERFACE)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); @@ -1708,14 +1697,14 @@ LExit: static HRESULT ReadMethodList( LPWSTR* ppwzData, - CPI_METHOD** ppMethList + CPIEXEC_METHOD** ppMethList ) { HRESULT hr = S_OK; LPWSTR pwzData = NULL; - CPI_METHOD* pItm = NULL; + CPIEXEC_METHOD* pItm = NULL; int iCnt = 0; @@ -1726,7 +1715,7 @@ static HRESULT ReadMethodList( // read methods for (int i = 0; i < iCnt; i++) { - pItm = (CPI_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_METHOD)); + pItm = (CPIEXEC_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_METHOD)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); @@ -1769,14 +1758,14 @@ LExit: static HRESULT ReadRoleAssignmentList( LPWSTR* ppwzData, - CPI_ROLE_ASSIGNMENT** ppRoleList + CPIEXEC_ROLE_ASSIGNMENT** ppRoleList ) { HRESULT hr = S_OK; LPWSTR pwzData = NULL; - CPI_ROLE_ASSIGNMENT* pItm = NULL; + CPIEXEC_ROLE_ASSIGNMENT* pItm = NULL; int iCnt = 0; @@ -1787,7 +1776,7 @@ static HRESULT ReadRoleAssignmentList( // read roles for (int i = 0; i < iCnt; i++) { - pItm = (CPI_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ROLE_ASSIGNMENT)); + pItm = (CPIEXEC_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_ROLE_ASSIGNMENT)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); @@ -1821,7 +1810,7 @@ LExit: } static void FreeComponentList( - CPI_COMPONENT* pList + CPIEXEC_COMPONENT* pList ) { while (pList) @@ -1833,14 +1822,14 @@ static void FreeComponentList( if (pList->pInterfaceList) FreeInterfaceList(pList->pInterfaceList); - CPI_COMPONENT* pDelete = pList; + CPIEXEC_COMPONENT* pDelete = pList; pList = pList->pNext; ::HeapFree(::GetProcessHeap(), 0, pDelete); } } static void FreeInterfaceList( - CPI_INTERFACE* pList + CPIEXEC_INTERFACE* pList ) { while (pList) @@ -1852,14 +1841,14 @@ static void FreeInterfaceList( if (pList->pMethodList) FreeMethodList(pList->pMethodList); - CPI_INTERFACE* pDelete = pList; + CPIEXEC_INTERFACE* pDelete = pList; pList = pList->pNext; ::HeapFree(::GetProcessHeap(), 0, pDelete); } } static void FreeMethodList( - CPI_METHOD* pList + CPIEXEC_METHOD* pList ) { while (pList) @@ -1869,19 +1858,19 @@ static void FreeMethodList( if (pList->pRoleAssignmentList) FreeRoleAssignmentList(pList->pRoleAssignmentList); - CPI_METHOD* pDelete = pList; + CPIEXEC_METHOD* pDelete = pList; pList = pList->pNext; ::HeapFree(::GetProcessHeap(), 0, pDelete); } } static void FreeRoleAssignmentList( - CPI_ROLE_ASSIGNMENT* pList + CPIEXEC_ROLE_ASSIGNMENT* pList ) { while (pList) { - CPI_ROLE_ASSIGNMENT* pDelete = pList; + CPIEXEC_ROLE_ASSIGNMENT* pDelete = pList; pList = pList->pNext; ::HeapFree(::GetProcessHeap(), 0, pDelete); } diff --git a/src/ca/cpasmsched.cpp b/src/ca/cpasmsched.cpp index 97ecff61..2d0573a5 100644 --- a/src/ca/cpasmsched.cpp +++ b/src/ca/cpasmsched.cpp @@ -169,19 +169,19 @@ static HRESULT InterfacesRead( LPCWSTR pwzCompKey, CPI_APPLICATION_ROLE_LIST* pAppRoleList, CPI_ASSEMBLY* pAsm, - CPI_COMPONENT* pComp + CPISCHED_COMPONENT* pComp ); static HRESULT MethodsRead( LPCWSTR pwzIntfKey, CPI_APPLICATION_ROLE_LIST* pAppRoleList, CPI_ASSEMBLY* pAsm, - CPI_INTERFACE* pIntf + CPISCHED_INTERFACE* pIntf ); static HRESULT RoleAssignmentsRead( LPCWSTR pwzQuery, LPCWSTR pwzKey, CPI_APPLICATION_ROLE_LIST* pAppRoleList, - CPI_ROLE_ASSIGNMENT** ppRoleList, + CPISCHED_ROLE_ASSIGNMENT** ppRoleList, int* piInstallCount, int* piUninstallCount ); @@ -238,21 +238,21 @@ static HRESULT AddRoleAssignmentsToActionData( LPWSTR* ppwzActionData ); static HRESULT AddComponentToActionData( - CPI_COMPONENT* pItm, + CPISCHED_COMPONENT* pItm, BOOL fInstall, BOOL fProps, BOOL fRoles, LPWSTR* ppwzActionData ); static HRESULT AddInterfaceToActionData( - CPI_INTERFACE* pItm, + CPISCHED_INTERFACE* pItm, BOOL fInstall, BOOL fProps, BOOL fRoles, LPWSTR* ppwzActionData ); static HRESULT AddMethodToActionData( - CPI_METHOD* pItm, + CPISCHED_METHOD* pItm, BOOL fInstall, BOOL fProps, BOOL fRoles, @@ -261,7 +261,7 @@ static HRESULT AddMethodToActionData( static HRESULT AddRolesToActionData( int iRoleInstallCount, int iRoleUninstallCount, - CPI_ROLE_ASSIGNMENT* pRoleList, + CPISCHED_ROLE_ASSIGNMENT* pRoleList, BOOL fInstall, BOOL fRoles, LPWSTR* ppwzActionData @@ -284,16 +284,16 @@ static void ModuleFree( CPI_MODULE* pItm ); static void ComponentsFreeList( - CPI_COMPONENT* pList + CPISCHED_COMPONENT* pList ); static void InterfacesFreeList( - CPI_INTERFACE* pList + CPISCHED_INTERFACE* pList ); static void MethodsFreeList( - CPI_METHOD* pList + CPISCHED_METHOD* pList ); static void RoleAssignmentsFreeList( - CPI_ROLE_ASSIGNMENT* pList + CPISCHED_ROLE_ASSIGNMENT* pList ); @@ -686,7 +686,7 @@ LExit: HRESULT CpiGetSubscriptionsCollForComponent( CPI_ASSEMBLY* pAsm, - CPI_COMPONENT* pComp, + CPISCHED_COMPONENT* pComp, ICatalogCollection** ppiSubsColl ) { @@ -713,7 +713,7 @@ HRESULT CpiGetSubscriptionsCollForComponent( ExitFunction(); // exit with hr = S_FALSE // get roles collection - hr = CpiGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", &pComp->piSubsColl); + hr = CpiSchedGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", &pComp->piSubsColl); ExitOnFailure(hr, "Failed to get subscriptions collection"); } @@ -1372,7 +1372,7 @@ static HRESULT ComponentsRead( PMSIHANDLE hView; PMSIHANDLE hRec; PMSIHANDLE hRecKey; - CPI_COMPONENT* pItm = NULL; + CPISCHED_COMPONENT* pItm = NULL; LPWSTR pwzData = NULL; // create parameter record @@ -1390,7 +1390,7 @@ static HRESULT ComponentsRead( while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // create entry - pItm = (CPI_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_COMPONENT)); + pItm = (CPISCHED_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_COMPONENT)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); @@ -1455,14 +1455,14 @@ static HRESULT InterfacesRead( LPCWSTR pwzCompKey, CPI_APPLICATION_ROLE_LIST* pAppRoleList, CPI_ASSEMBLY* pAsm, - CPI_COMPONENT* pComp + CPISCHED_COMPONENT* pComp ) { HRESULT hr = S_OK; PMSIHANDLE hView; PMSIHANDLE hRec; PMSIHANDLE hRecKey; - CPI_INTERFACE* pItm = NULL; + CPISCHED_INTERFACE* pItm = NULL; LPWSTR pwzData = NULL; // create parameter record @@ -1480,7 +1480,7 @@ static HRESULT InterfacesRead( while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // create entry - pItm = (CPI_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_INTERFACE)); + pItm = (CPISCHED_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_INTERFACE)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); @@ -1545,12 +1545,12 @@ static HRESULT MethodsRead( LPCWSTR pwzIntfKey, CPI_APPLICATION_ROLE_LIST* pAppRoleList, CPI_ASSEMBLY* pAsm, - CPI_INTERFACE* pIntf + CPISCHED_INTERFACE* pIntf ) { HRESULT hr = S_OK; PMSIHANDLE hView, hRec, hRecKey; - CPI_METHOD* pItm = NULL; + CPISCHED_METHOD* pItm = NULL; LPWSTR pwzData = NULL; // create parameter record @@ -1568,7 +1568,7 @@ static HRESULT MethodsRead( while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // create entry - pItm = (CPI_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_METHOD)); + pItm = (CPISCHED_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_METHOD)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); @@ -1635,7 +1635,7 @@ static HRESULT RoleAssignmentsRead( LPCWSTR pwzQuery, LPCWSTR pwzKey, CPI_APPLICATION_ROLE_LIST* pAppRoleList, - CPI_ROLE_ASSIGNMENT** ppRoleList, + CPISCHED_ROLE_ASSIGNMENT** ppRoleList, int* piInstallCount, int* piUninstallCount ) @@ -1645,7 +1645,7 @@ static HRESULT RoleAssignmentsRead( PMSIHANDLE hView, hRec, hRecKey; - CPI_ROLE_ASSIGNMENT* pItm = NULL; + CPISCHED_ROLE_ASSIGNMENT* pItm = NULL; LPWSTR pwzData = NULL; BOOL fMatchingArchitecture = FALSE; @@ -1677,7 +1677,7 @@ static HRESULT RoleAssignmentsRead( } // create entry - pItm = (CPI_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ROLE_ASSIGNMENT)); + pItm = (CPISCHED_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_ROLE_ASSIGNMENT)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); @@ -1786,7 +1786,7 @@ static HRESULT AddAssemblyToActionData( if (iCompCount) { - for (CPI_COMPONENT* pComp = pItm->pComponents; pComp; pComp = pComp->pNext) + for (CPISCHED_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); @@ -1834,7 +1834,7 @@ static HRESULT AddRoleAssignmentsToActionData( 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) + for (CPISCHED_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); @@ -1847,7 +1847,7 @@ LExit: } static HRESULT AddComponentToActionData( - CPI_COMPONENT* pItm, + CPISCHED_COMPONENT* pItm, BOOL fInstall, BOOL fProps, BOOL fRoles, @@ -1875,7 +1875,7 @@ static HRESULT AddComponentToActionData( if (iIntfCount) { - for (CPI_INTERFACE* pIntf = pItm->pInterfaces; pIntf; pIntf = pIntf->pNext) + for (CPISCHED_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); @@ -1889,7 +1889,7 @@ LExit: } static HRESULT AddInterfaceToActionData( - CPI_INTERFACE* pItm, + CPISCHED_INTERFACE* pItm, BOOL fInstall, BOOL fProps, BOOL fRoles, @@ -1914,7 +1914,7 @@ static HRESULT AddInterfaceToActionData( 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) + for (CPISCHED_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); @@ -1927,7 +1927,7 @@ LExit: } static HRESULT AddMethodToActionData( - CPI_METHOD* pItm, + CPISCHED_METHOD* pItm, BOOL fInstall, BOOL fProps, BOOL fRoles, @@ -1960,7 +1960,7 @@ LExit: static HRESULT AddRolesToActionData( int iRoleInstallCount, int iRoleUninstallCount, - CPI_ROLE_ASSIGNMENT* pRoleList, + CPISCHED_ROLE_ASSIGNMENT* pRoleList, BOOL fInstall, BOOL fRoles, LPWSTR* ppwzActionData @@ -1974,7 +1974,7 @@ static HRESULT AddRolesToActionData( if (iRoleCount) { - for (CPI_ROLE_ASSIGNMENT* pRole = pRoleList; pRole; pRole = pRole->pNext) + for (CPISCHED_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)) @@ -2061,7 +2061,7 @@ static void ModuleFree( } static void ComponentsFreeList( - CPI_COMPONENT* pList + CPISCHED_COMPONENT* pList ) { while (pList) @@ -2077,14 +2077,14 @@ static void ComponentsFreeList( ReleaseObject(pList->piSubsColl); - CPI_COMPONENT* pDelete = pList; + CPISCHED_COMPONENT* pDelete = pList; pList = pList->pNext; ::HeapFree(::GetProcessHeap(), 0, pDelete); } } static void InterfacesFreeList( - CPI_INTERFACE* pList + CPISCHED_INTERFACE* pList ) { while (pList) @@ -2098,14 +2098,14 @@ static void InterfacesFreeList( if (pList->pMethods) MethodsFreeList(pList->pMethods); - CPI_INTERFACE* pDelete = pList; + CPISCHED_INTERFACE* pDelete = pList; pList = pList->pNext; ::HeapFree(::GetProcessHeap(), 0, pDelete); } } static void MethodsFreeList( - CPI_METHOD* pList + CPISCHED_METHOD* pList ) { while (pList) @@ -2116,19 +2116,19 @@ static void MethodsFreeList( if (pList->pRoles) RoleAssignmentsFreeList(pList->pRoles); - CPI_METHOD* pDelete = pList; + CPISCHED_METHOD* pDelete = pList; pList = pList->pNext; ::HeapFree(::GetProcessHeap(), 0, pDelete); } } static void RoleAssignmentsFreeList( - CPI_ROLE_ASSIGNMENT* pList + CPISCHED_ROLE_ASSIGNMENT* pList ) { while (pList) { - CPI_ROLE_ASSIGNMENT* pDelete = pList; + CPISCHED_ROLE_ASSIGNMENT* pDelete = pList; pList = pList->pNext; ::HeapFree(::GetProcessHeap(), 0, pDelete); } diff --git a/src/ca/cpasmsched.h b/src/ca/cpasmsched.h index b5a68d7e..ddf4b6c0 100644 --- a/src/ca/cpasmsched.h +++ b/src/ca/cpasmsched.h @@ -13,7 +13,7 @@ enum eAssemblyAttributes // structs -struct CPI_ROLE_ASSIGNMENT +struct CPISCHED_ROLE_ASSIGNMENT { WCHAR wzKey[MAX_DARWIN_KEY + 1]; @@ -21,10 +21,10 @@ struct CPI_ROLE_ASSIGNMENT CPI_APPLICATION_ROLE* pApplicationRole; - CPI_ROLE_ASSIGNMENT* pNext; + CPISCHED_ROLE_ASSIGNMENT* pNext; }; -struct CPI_METHOD +struct CPISCHED_METHOD { WCHAR wzKey[MAX_DARWIN_KEY + 1]; WCHAR wzIndex[11 + 1]; @@ -35,12 +35,12 @@ struct CPI_METHOD int iRoleInstallCount; int iRoleUninstallCount; - CPI_ROLE_ASSIGNMENT* pRoles; + CPISCHED_ROLE_ASSIGNMENT* pRoles; - CPI_METHOD* pNext; + CPISCHED_METHOD* pNext; }; -struct CPI_INTERFACE +struct CPISCHED_INTERFACE { WCHAR wzKey[MAX_DARWIN_KEY + 1]; WCHAR wzIID[CPI_MAX_GUID + 1]; @@ -50,15 +50,15 @@ struct CPI_INTERFACE int iRoleInstallCount; int iRoleUninstallCount; - CPI_ROLE_ASSIGNMENT* pRoles; + CPISCHED_ROLE_ASSIGNMENT* pRoles; int iMethodCount; - CPI_METHOD* pMethods; + CPISCHED_METHOD* pMethods; - CPI_INTERFACE* pNext; + CPISCHED_INTERFACE* pNext; }; -struct CPI_COMPONENT +struct CPISCHED_COMPONENT { WCHAR wzKey[MAX_DARWIN_KEY + 1]; WCHAR wzCLSID[CPI_MAX_GUID + 1]; @@ -68,14 +68,14 @@ struct CPI_COMPONENT int iRoleInstallCount; int iRoleUninstallCount; - CPI_ROLE_ASSIGNMENT* pRoles; + CPISCHED_ROLE_ASSIGNMENT* pRoles; int iInterfaceCount; - CPI_INTERFACE* pInterfaces; + CPISCHED_INTERFACE* pInterfaces; ICatalogCollection* piSubsColl; - CPI_COMPONENT* pNext; + CPISCHED_COMPONENT* pNext; }; struct CPI_ASSEMBLY @@ -89,7 +89,7 @@ struct CPI_ASSEMBLY int iAttributes; int iComponentCount; - CPI_COMPONENT* pComponents; + CPISCHED_COMPONENT* pComponents; BOOL fReferencedForInstall; BOOL fReferencedForUninstall; @@ -163,6 +163,6 @@ HRESULT CpiRoleAssignmentsUninstall( ); HRESULT CpiGetSubscriptionsCollForComponent( CPI_ASSEMBLY* pAsm, - CPI_COMPONENT* pComp, + CPISCHED_COMPONENT* pComp, ICatalogCollection** ppiSubsColl ); diff --git a/src/ca/cpexec.cpp b/src/ca/cpexec.cpp index fa2446d8..9b1691fc 100644 --- a/src/ca/cpexec.cpp +++ b/src/ca/cpexec.cpp @@ -2,29 +2,6 @@ #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 @@ -133,7 +110,7 @@ extern "C" UINT __stdcall ComPlusInstallExecute(MSIHANDLE hInstall) ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; - CpiInitialize(); + CpiExecInitialize(); // get custom action data hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); @@ -204,7 +181,7 @@ LExit: ::CloseHandle(hRollbackFile); // unitialize - CpiFinalize(); + CpiExecFinalize(); if (fInitializedCom) ::CoUninitialize(); @@ -239,7 +216,7 @@ extern "C" UINT __stdcall ComPlusInstallExecuteCommit(MSIHANDLE hInstall) ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; - CpiInitialize(); + CpiExecInitialize(); // get custom action data hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); @@ -282,7 +259,7 @@ LExit: ::CloseHandle(hRollbackFile); // unitialize - CpiFinalize(); + CpiExecFinalize(); if (fInitializedCom) ::CoUninitialize(); @@ -327,7 +304,7 @@ extern "C" UINT __stdcall ComPlusRollbackInstallExecute(MSIHANDLE hInstall) ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; - CpiInitialize(); + CpiExecInitialize(); // get custom action data hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); @@ -439,7 +416,7 @@ LExit: CpiFreeRollbackDataList(prdSubscriptions); // unitialize - CpiFinalize(); + CpiExecFinalize(); if (fInitializedCom) ::CoUninitialize(); @@ -474,7 +451,7 @@ extern "C" UINT __stdcall ComPlusUninstallExecute(MSIHANDLE hInstall) ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; - CpiInitialize(); + CpiExecInitialize(); // get custom action data hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); @@ -545,7 +522,7 @@ LExit: ::CloseHandle(hRollbackFile); // unitialize - CpiFinalize(); + CpiExecFinalize(); if (fInitializedCom) ::CoUninitialize(); @@ -590,7 +567,7 @@ extern "C" UINT __stdcall ComPlusRollbackUninstallExecute(MSIHANDLE hInstall) ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; - CpiInitialize(); + CpiExecInitialize(); // get custom action data hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); @@ -694,7 +671,7 @@ LExit: CpiFreeRollbackDataList(prdSubscriptions); // unitialize - CpiFinalize(); + CpiExecFinalize(); if (fInitializedCom) ::CoUninitialize(); diff --git a/src/ca/cpexec.def b/src/ca/cpexec.def deleted file mode 100644 index 1dad15c2..00000000 --- a/src/ca/cpexec.def +++ /dev/null @@ -1,11 +0,0 @@ -; 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 index d8c30c6a..673bdaf9 100644 --- a/src/ca/cppartexec.cpp +++ b/src/ca/cppartexec.cpp @@ -399,7 +399,7 @@ static HRESULT CreatePartition( WcaLog(LOGMSG_VERBOSE, "Creating partition, key: %S", pAttrs->pwzKey); // get partitions collection - hr = CpiGetPartitionsCollection(&piPartColl); + hr = CpiExecGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); // check if partition exists @@ -456,7 +456,7 @@ static HRESULT RemovePartition( WcaLog(LOGMSG_VERBOSE, "Removing partition, key: %S", pAttrs->pwzKey); // get partitions collection - hr = CpiGetPartitionsCollection(&piPartColl); + hr = CpiExecGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); // remove diff --git a/src/ca/cppartsched.cpp b/src/ca/cppartsched.cpp index 6643a50b..7cd98791 100644 --- a/src/ca/cppartsched.cpp +++ b/src/ca/cppartsched.cpp @@ -199,7 +199,7 @@ HRESULT CpiPartitionsVerifyInstall( // get partitions collection if (!piPartColl) { - hr = CpiGetPartitionsCollection(&piPartColl); + hr = CpiSchedGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); } @@ -336,7 +336,7 @@ HRESULT CpiPartitionsVerifyUninstall( // get partitions collection if (!piPartColl) { - hr = CpiGetPartitionsCollection(&piPartColl); + hr = CpiSchedGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); } @@ -526,7 +526,7 @@ HRESULT CpiGetApplicationsCollForPartition( if (!pPart->piApplicationsColl) { // get partitions collection from catalog - hr = CpiGetPartitionsCollection(&piPartColl); + hr = CpiSchedGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); // find application object @@ -540,7 +540,7 @@ HRESULT CpiGetApplicationsCollForPartition( } // get roles collection - hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"Applications", &pPart->piApplicationsColl); + hr = CpiSchedGetCatalogCollection(piPartColl, piPartObj, L"Applications", &pPart->piApplicationsColl); ExitOnFailure(hr, "Failed to get applications collection"); } @@ -576,7 +576,7 @@ HRESULT CpiGetRolesCollForPartition( if (!pPart->piRolesColl) { // get partitions collection from catalog - hr = CpiGetPartitionsCollection(&piPartColl); + hr = CpiSchedGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); // find partition object @@ -587,7 +587,7 @@ HRESULT CpiGetRolesCollForPartition( ExitFunction(); // exit with hr = S_FALSE // get roles collection - hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", &pPart->piRolesColl); + hr = CpiSchedGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", &pPart->piRolesColl); ExitOnFailure(hr, "Failed to get roles collection"); } diff --git a/src/ca/cpsched.cpp b/src/ca/cpsched.cpp index ac0dda59..ebc547ae 100644 --- a/src/ca/cpsched.cpp +++ b/src/ca/cpsched.cpp @@ -29,30 +29,6 @@ #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 @@ -103,7 +79,7 @@ extern "C" UINT __stdcall ConfigureComPlusInstall(MSIHANDLE hInstall) ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; - CpiInitialize(); + CpiSchedInitialize(); // check for the prerequsite tables if (!CpiTableExists(cptComPlusPartition) && !CpiTableExists(cptComPlusApplication) && !CpiTableExists(cptComPlusAssembly)) @@ -114,7 +90,7 @@ extern "C" UINT __stdcall ConfigureComPlusInstall(MSIHANDLE hInstall) // make sure we can access the COM+ admin catalog do { - hr = CpiGetAdminCatalog(&piCatalog); + hr = CpiSchedGetAdminCatalog(&piCatalog); if (FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "Failed to get COM+ admin catalog"); @@ -320,7 +296,7 @@ LExit: CpiSubscriptionListFree(&subList); // unitialize - CpiFinalize(); + CpiSchedFinalize(); if (fInitializedCom) ::CoUninitialize(); @@ -378,7 +354,7 @@ extern "C" UINT __stdcall ConfigureComPlusUninstall(MSIHANDLE hInstall) ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; - CpiInitialize(); + CpiSchedInitialize(); // check for the prerequsite tables if (!CpiTableExists(cptComPlusPartition) && !CpiTableExists(cptComPlusApplication) && !CpiTableExists(cptComPlusAssembly)) @@ -389,7 +365,7 @@ extern "C" UINT __stdcall ConfigureComPlusUninstall(MSIHANDLE hInstall) // make sure we can access the COM+ admin catalog do { - hr = CpiGetAdminCatalog(&piCatalog); + hr = CpiSchedGetAdminCatalog(&piCatalog); if (FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "Failed to get COM+ admin catalog"); @@ -580,7 +556,7 @@ LExit: CpiSubscriptionListFree(&subList); // unitialize - CpiFinalize(); + CpiSchedFinalize(); if (fInitializedCom) ::CoUninitialize(); diff --git a/src/ca/cpsubssched.cpp b/src/ca/cpsubssched.cpp index 73fd4f6d..df15fd03 100644 --- a/src/ca/cpsubssched.cpp +++ b/src/ca/cpsubssched.cpp @@ -53,7 +53,7 @@ static HRESULT ComponentFindByKey( CPI_ASSEMBLY_LIST* pAsmList, LPCWSTR pwzKey, CPI_ASSEMBLY** ppAsmItm, - CPI_COMPONENT** ppCompItm + CPISCHED_COMPONENT** ppCompItm ); @@ -586,12 +586,12 @@ static HRESULT ComponentFindByKey( CPI_ASSEMBLY_LIST* pAsmList, LPCWSTR pwzKey, CPI_ASSEMBLY** ppAsmItm, - CPI_COMPONENT** ppCompItm + CPISCHED_COMPONENT** ppCompItm ) { for (CPI_ASSEMBLY* pAsmItm = pAsmList->pFirst; pAsmItm; pAsmItm = pAsmItm->pNext) { - for (CPI_COMPONENT* pCompItm = pAsmItm->pComponents; pCompItm; pCompItm = pCompItm->pNext) + for (CPISCHED_COMPONENT* pCompItm = pAsmItm->pComponents; pCompItm; pCompItm = pCompItm->pNext) { if (0 == lstrcmpW(pCompItm->wzKey, pwzKey)) { diff --git a/src/ca/cpsubssched.h b/src/ca/cpsubssched.h index 3fc18478..83ff1af8 100644 --- a/src/ca/cpsubssched.h +++ b/src/ca/cpsubssched.h @@ -18,7 +18,7 @@ struct CPI_SUBSCRIPTION INSTALLSTATE isInstalled, isAction; CPI_ASSEMBLY* pAssembly; - CPI_COMPONENT* pComponent; + CPISCHED_COMPONENT* pComponent; CPI_SUBSCRIPTION* pNext; }; diff --git a/src/ca/cputilexec.cpp b/src/ca/cputilexec.cpp index e081678b..1c2c8b93 100644 --- a/src/ca/cputilexec.cpp +++ b/src/ca/cputilexec.cpp @@ -69,13 +69,13 @@ static ICOMAdminCatalog* gpiCatalog; // function definitions -void CpiInitialize() +void CpiExecInitialize() { // collections gpiCatalog = NULL; } -void CpiFinalize() +void CpiExecFinalize() { // collections ReleaseObject(gpiCatalog); @@ -187,7 +187,7 @@ LExit: return hr; } -HRESULT CpiGetAdminCatalog( +HRESULT CpiExecGetAdminCatalog( ICOMAdminCatalog** ppiCatalog ) { @@ -225,11 +225,11 @@ HRESULT CpiLogCatalogErrorInfo() LPWSTR pwzMinorRef = NULL; // get catalog - hr = CpiGetAdminCatalog(&piCatalog); + hr = CpiExecGetAdminCatalog(&piCatalog); ExitOnFailure(hr, "Failed to get COM+ admin catalog"); // get error info collection - hr = CpiGetCatalogCollection(L"ErrorInfo", &piErrColl); + hr = CpiExecGetCatalogCollection(L"ErrorInfo", &piErrColl); ExitOnFailure(hr, "Failed to get error info collection"); // loop objects @@ -282,7 +282,7 @@ LExit: return hr; } -HRESULT CpiGetCatalogCollection( +HRESULT CpiExecGetCatalogCollection( LPCWSTR pwzName, ICatalogCollection** ppiColl ) @@ -299,7 +299,7 @@ HRESULT CpiGetCatalogCollection( ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name"); // get catalog - hr = CpiGetAdminCatalog(&piCatalog); + hr = CpiExecGetAdminCatalog(&piCatalog); ExitOnFailure(hr, "Failed to get COM+ admin catalog"); // get collecton from catalog @@ -326,7 +326,7 @@ LExit: return hr; } -HRESULT CpiGetCatalogCollection( +HRESULT CpiExecGetCatalogCollection( ICatalogCollection* piColl, ICatalogObject* piObj, LPCWSTR pwzName, @@ -348,7 +348,7 @@ HRESULT CpiGetCatalogCollection( ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name"); // get catalog - hr = CpiGetAdminCatalog(&piCatalog); + hr = CpiExecGetAdminCatalog(&piCatalog); ExitOnFailure(hr, "Failed to get COM+ admin catalog"); // get key @@ -894,14 +894,14 @@ LExit: return hr; } -HRESULT CpiGetPartitionsCollection( +HRESULT CpiExecGetPartitionsCollection( ICatalogCollection** ppiPartColl ) { HRESULT hr = S_OK; // get collection - hr = CpiGetCatalogCollection(L"Partitions", ppiPartColl); + hr = CpiExecGetCatalogCollection(L"Partitions", ppiPartColl); ExitOnFailure(hr, "Failed to get catalog collection"); hr = S_OK; @@ -921,7 +921,7 @@ HRESULT CpiGetPartitionRolesCollection( ICatalogObject* piPartObj = NULL; // get partitions collection - hr = CpiGetPartitionsCollection(&piPartColl); + hr = CpiExecGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); if (S_FALSE == hr) @@ -935,7 +935,7 @@ HRESULT CpiGetPartitionRolesCollection( ExitFunction(); // partition not found, exit with hr = S_FALSE // get roles collection - hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", ppiRolesColl); + hr = CpiExecGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", ppiRolesColl); ExitOnFailure(hr, "Failed to get catalog collection"); hr = S_OK; @@ -974,7 +974,7 @@ HRESULT CpiGetUsersInPartitionRoleCollection( ExitFunction(); // user not found, exit with hr = S_FALSE // get roles collection - hr = CpiGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInPartitionRole", ppiUsrInRoleColl); + hr = CpiExecGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInPartitionRole", ppiUsrInRoleColl); ExitOnFailure(hr, "Failed to get catalog collection"); hr = S_OK; @@ -994,7 +994,7 @@ HRESULT CpiGetPartitionUsersCollection( HRESULT hr = S_OK; // get roles collection - hr = CpiGetCatalogCollection(L"PartitionUsers", ppiUserColl); + hr = CpiExecGetCatalogCollection(L"PartitionUsers", ppiUserColl); ExitOnFailure(hr, "Failed to get catalog collection"); hr = S_OK; @@ -1003,7 +1003,7 @@ LExit: return hr; } -HRESULT CpiGetApplicationsCollection( +HRESULT CpiExecGetApplicationsCollection( LPCWSTR pwzPartID, ICatalogCollection** ppiAppColl ) @@ -1018,7 +1018,7 @@ HRESULT CpiGetApplicationsCollection( ICatalogObject* piPartObj = NULL; // get catalog - hr = CpiGetAdminCatalog(&piCatalog); + hr = CpiExecGetAdminCatalog(&piCatalog); ExitOnFailure(hr, "Failed to get COM+ admin catalog"); // get ICOMAdminCatalog2 interface @@ -1038,7 +1038,7 @@ HRESULT CpiGetApplicationsCollection( } // get partitions collection - hr = CpiGetPartitionsCollection(&piPartColl); + hr = CpiExecGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); // find object @@ -1049,7 +1049,7 @@ HRESULT CpiGetApplicationsCollection( ExitFunction(); // partition not found, exit with hr = S_FALSE // get applications collection - hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"Applications", ppiAppColl); + hr = CpiExecGetCatalogCollection(piPartColl, piPartObj, L"Applications", ppiAppColl); ExitOnFailure(hr, "Failed to get catalog collection for partition"); } @@ -1061,7 +1061,7 @@ HRESULT CpiGetApplicationsCollection( ExitOnFailure(hr = E_FAIL, "Partitions are not supported by this version of COM+"); // get applications collection - hr = CpiGetCatalogCollection(L"Applications", ppiAppColl); + hr = CpiExecGetCatalogCollection(L"Applications", ppiAppColl); ExitOnFailure(hr, "Failed to get catalog collection"); } @@ -1091,7 +1091,7 @@ HRESULT CpiGetRolesCollection( ICatalogObject* piAppObj = NULL; // get applications collection - hr = CpiGetApplicationsCollection(pwzPartID, &piAppColl); + hr = CpiExecGetApplicationsCollection(pwzPartID, &piAppColl); ExitOnFailure(hr, "Failed to get applications collection"); if (S_FALSE == hr) @@ -1105,7 +1105,7 @@ HRESULT CpiGetRolesCollection( ExitFunction(); // application not found, exit with hr = S_FALSE // get roles collection - hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Roles", ppiRolesColl); + hr = CpiExecGetCatalogCollection(piAppColl, piAppObj, L"Roles", ppiRolesColl); ExitOnFailure(hr, "Failed to catalog collection"); hr = S_OK; @@ -1145,7 +1145,7 @@ HRESULT CpiGetUsersInRoleCollection( ExitFunction(); // role not found, exit with hr = S_FALSE // get roles collection - hr = CpiGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInRole", ppiUsrInRoleColl); + hr = CpiExecGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInRole", ppiUsrInRoleColl); ExitOnFailure(hr, "Failed to get catalog collection"); hr = S_OK; @@ -1170,7 +1170,7 @@ HRESULT CpiGetComponentsCollection( ICatalogObject* piAppObj = NULL; // get applications collection - hr = CpiGetApplicationsCollection(pwzPartID, &piAppColl); + hr = CpiExecGetApplicationsCollection(pwzPartID, &piAppColl); ExitOnFailure(hr, "Failed to get applications collection"); if (S_FALSE == hr) @@ -1184,7 +1184,7 @@ HRESULT CpiGetComponentsCollection( ExitFunction(); // application not found, exit with hr = S_FALSE // get components collection - hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Components", ppiCompsColl); + hr = CpiExecGetCatalogCollection(piAppColl, piAppObj, L"Components", ppiCompsColl); ExitOnFailure(hr, "Failed to get catalog collection"); hr = S_OK; @@ -1206,7 +1206,7 @@ HRESULT CpiGetInterfacesCollection( HRESULT hr = S_OK; // get interfaces collection - hr = CpiGetCatalogCollection(piCompColl, piCompObj, L"InterfacesForComponent", ppiIntfColl); + hr = CpiExecGetCatalogCollection(piCompColl, piCompObj, L"InterfacesForComponent", ppiIntfColl); ExitOnFailure(hr, "Failed to get catalog collection"); hr = S_OK; @@ -1224,7 +1224,7 @@ HRESULT CpiGetMethodsCollection( HRESULT hr = S_OK; // get interfaces collection - hr = CpiGetCatalogCollection(piIntfColl, piIntfObj, L"MethodsForInterface", ppiMethColl); + hr = CpiExecGetCatalogCollection(piIntfColl, piIntfObj, L"MethodsForInterface", ppiMethColl); ExitOnFailure(hr, "Failed to get catalog collection"); hr = S_OK; @@ -1260,7 +1260,7 @@ HRESULT CpiGetSubscriptionsCollection( ExitFunction(); // component not found, exit with hr = S_FALSE // get subscriptions collection - hr = CpiGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", ppiSubsColl); + hr = CpiExecGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", ppiSubsColl); ExitOnFailure(hr, "Failed to get catalog collection"); hr = S_OK; diff --git a/src/ca/cputilexec.h b/src/ca/cputilexec.h index 51b47583..b900883d 100644 --- a/src/ca/cputilexec.h +++ b/src/ca/cputilexec.h @@ -28,8 +28,8 @@ struct CPI_ROLLBACK_DATA // function prototypes -void CpiInitialize(); -void CpiFinalize(); +void CpiExecInitialize(); +void CpiExecFinalize(); HRESULT CpiActionStartMessage( LPWSTR* ppwzActionData, BOOL fSuppress @@ -38,15 +38,15 @@ HRESULT CpiActionDataMessage( DWORD cArgs, ... ); -HRESULT CpiGetAdminCatalog( +HRESULT CpiExecGetAdminCatalog( ICOMAdminCatalog** ppiCatalog ); HRESULT CpiLogCatalogErrorInfo(); -HRESULT CpiGetCatalogCollection( +HRESULT CpiExecGetCatalogCollection( LPCWSTR pwzName, ICatalogCollection** ppiColl ); -HRESULT CpiGetCatalogCollection( +HRESULT CpiExecGetCatalogCollection( ICatalogCollection* piColl, ICatalogObject* piObj, LPCWSTR pwzName, @@ -105,7 +105,7 @@ HRESULT CpiFindUserCollectionObject( PSID pSid, ICatalogObject** ppiObj ); -HRESULT CpiGetPartitionsCollection( +HRESULT CpiExecGetPartitionsCollection( ICatalogCollection** ppiPartColl ); HRESULT CpiGetPartitionRolesCollection( @@ -120,7 +120,7 @@ HRESULT CpiGetUsersInPartitionRoleCollection( HRESULT CpiGetPartitionUsersCollection( ICatalogCollection** ppiUserColl ); -HRESULT CpiGetApplicationsCollection( +HRESULT CpiExecGetApplicationsCollection( LPCWSTR pwzPartID, ICatalogCollection** ppiAppColl ); diff --git a/src/ca/cputilsched.cpp b/src/ca/cputilsched.cpp index 9dbe21ec..1a958c56 100644 --- a/src/ca/cputilsched.cpp +++ b/src/ca/cputilsched.cpp @@ -43,7 +43,7 @@ static int giTables; // function definitions -void CpiInitialize() +void CpiSchedInitialize() { // collections gpiCatalog = NULL; @@ -80,7 +80,7 @@ void CpiInitialize() if (S_OK == WcaTableExists(L"ComPlusSubscriptionProperty")) giTables |= cptComPlusSubscriptionProperty; } -void CpiFinalize() +void CpiSchedFinalize() { // collections ReleaseObject(gpiCatalog); @@ -95,7 +95,7 @@ BOOL CpiTableExists( return (giTables & iTable) == iTable; } -HRESULT CpiGetAdminCatalog( +HRESULT CpiSchedGetAdminCatalog( ICOMAdminCatalog** ppiCatalog ) { @@ -118,7 +118,7 @@ LExit: return hr; } -HRESULT CpiGetCatalogCollection( +HRESULT CpiSchedGetCatalogCollection( LPCWSTR pwzName, ICatalogCollection** ppiColl ) @@ -134,7 +134,7 @@ HRESULT CpiGetCatalogCollection( ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name"); // get catalog - hr = CpiGetAdminCatalog(&piCatalog); + hr = CpiSchedGetAdminCatalog(&piCatalog); ExitOnFailure(hr, "Failed to get COM+ admin catalog"); // get collecton from catalog @@ -159,7 +159,7 @@ LExit: return hr; } -HRESULT CpiGetCatalogCollection( +HRESULT CpiSchedGetCatalogCollection( ICatalogCollection* piColl, ICatalogObject* piObj, LPCWSTR pwzName, @@ -180,7 +180,7 @@ HRESULT CpiGetCatalogCollection( ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name"); // get catalog - hr = CpiGetAdminCatalog(&piCatalog); + hr = CpiSchedGetAdminCatalog(&piCatalog); ExitOnFailure(hr, "Failed to get COM+ admin catalog"); // get key @@ -331,7 +331,7 @@ LExit: return hr; } -HRESULT CpiGetPartitionsCollection( +HRESULT CpiSchedGetPartitionsCollection( ICatalogCollection** ppiPartColl ) { @@ -340,7 +340,7 @@ HRESULT CpiGetPartitionsCollection( if (!gpiPartColl) { // get collection - hr = CpiGetCatalogCollection(L"Partitions", &gpiPartColl); + hr = CpiSchedGetCatalogCollection(L"Partitions", &gpiPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); } @@ -354,7 +354,7 @@ LExit: return hr; } -HRESULT CpiGetApplicationsCollection( +HRESULT CpiSchedGetApplicationsCollection( ICatalogCollection** ppiAppColl ) { @@ -369,7 +369,7 @@ HRESULT CpiGetApplicationsCollection( if (!gpiAppColl) { // get catalog - hr = CpiGetAdminCatalog(&piCatalog); + hr = CpiSchedGetAdminCatalog(&piCatalog); ExitOnFailure(hr, "Failed to get COM+ admin catalog"); // get ICOMAdminCatalog2 interface @@ -385,7 +385,7 @@ HRESULT CpiGetApplicationsCollection( ExitOnFailure(hr, "Failed to get global partition id"); // get partitions collection - hr = CpiGetPartitionsCollection(&piPartColl); + hr = CpiSchedGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); // find object @@ -396,7 +396,7 @@ HRESULT CpiGetApplicationsCollection( ExitFunction(); // partition not found, exit with hr = S_FALSE // get applications collection - hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"Applications", &gpiAppColl); + hr = CpiSchedGetCatalogCollection(piPartColl, piPartObj, L"Applications", &gpiAppColl); ExitOnFailure(hr, "Failed to get applications collection"); } @@ -404,7 +404,7 @@ HRESULT CpiGetApplicationsCollection( else { // get applications collection - hr = CpiGetCatalogCollection(L"Applications", &gpiAppColl); + hr = CpiSchedGetCatalogCollection(L"Applications", &gpiAppColl); ExitOnFailure(hr, "Failed to get applications collection"); } } diff --git a/src/ca/cputilsched.h b/src/ca/cputilsched.h index 61aaab84..1f315576 100644 --- a/src/ca/cputilsched.h +++ b/src/ca/cputilsched.h @@ -2,12 +2,8 @@ // 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 @@ -42,14 +38,6 @@ enum eComPlusTables // structs -struct CPI_PROPERTY -{ - WCHAR wzName[MAX_DARWIN_KEY + 1]; - LPWSTR pwzValue; - - CPI_PROPERTY* pNext; -}; - struct CPI_PROPERTY_DEFINITION { LPCWSTR pwzName; @@ -60,19 +48,19 @@ struct CPI_PROPERTY_DEFINITION // function prototypes -void CpiInitialize(); -void CpiFinalize(); +void CpiSchedInitialize(); +void CpiSchedFinalize(); BOOL CpiTableExists( int iTable ); -HRESULT CpiGetAdminCatalog( +HRESULT CpiSchedGetAdminCatalog( ICOMAdminCatalog** ppiCatalog ); -HRESULT CpiGetCatalogCollection( +HRESULT CpiSchedGetCatalogCollection( LPCWSTR pwzName, ICatalogCollection** ppiColl ); -HRESULT CpiGetCatalogCollection( +HRESULT CpiSchedGetCatalogCollection( ICatalogCollection* piColl, ICatalogObject* piObj, LPCWSTR pwzName, @@ -89,10 +77,10 @@ HRESULT CpiFindCollectionObject( LPCWSTR pwzName, ICatalogObject** ppiObj ); -HRESULT CpiGetPartitionsCollection( +HRESULT CpiSchedGetPartitionsCollection( ICatalogCollection** ppiPartColl ); -HRESULT CpiGetApplicationsCollection( +HRESULT CpiSchedGetApplicationsCollection( ICatalogCollection** ppiAppColl ); HRESULT CpiAddActionTextToActionData( diff --git a/src/ca/custommsierrors.h b/src/ca/custommsierrors.h new file mode 100644 index 00000000..219df698 --- /dev/null +++ b/src/ca/custommsierrors.h @@ -0,0 +1,29 @@ +#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 msierrComPlusCannotConnect 28001 +#define msierrComPlusPartitionReadFailed 28002 +#define msierrComPlusPartitionRoleReadFailed 28003 +#define msierrComPlusUserInPartitionRoleReadFailed 28004 +#define msierrComPlusPartitionUserReadFailed 28005 +#define msierrComPlusApplicationReadFailed 28006 +#define msierrComPlusApplicationRoleReadFailed 28007 +#define msierrComPlusUserInApplicationRoleReadFailed 28008 +#define msierrComPlusAssembliesReadFailed 28009 +#define msierrComPlusSubscriptionReadFailed 28010 +#define msierrComPlusPartitionDependency 28011 +#define msierrComPlusPartitionNotFound 28012 +#define msierrComPlusPartitionIdConflict 28013 +#define msierrComPlusPartitionNameConflict 28014 +#define msierrComPlusApplicationDependency 28015 +#define msierrComPlusApplicationNotFound 28016 +#define msierrComPlusApplicationIdConflict 28017 +#define msierrComPlusApplicationNameConflict 28018 +#define msierrComPlusApplicationRoleDependency 28019 +#define msierrComPlusApplicationRoleNotFound 28020 +#define msierrComPlusApplicationRoleConflict 28021 +#define msierrComPlusAssemblyDependency 28022 +#define msierrComPlusSubscriptionIdConflict 28023 +#define msierrComPlusSubscriptionNameConflict 28024 +#define msierrComPlusFailedLookupNames 28025 diff --git a/src/ca/dllmain.cpp b/src/ca/dllmain.cpp new file mode 100644 index 00000000..7d299feb --- /dev/null +++ b/src/ca/dllmain.cpp @@ -0,0 +1,27 @@ +// 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 custom actions. + +********************************************************************/ +extern "C" BOOL WINAPI DllMain( + IN HINSTANCE hInstance, + IN ULONG ulReason, + IN LPVOID) +{ + switch(ulReason) + { + case DLL_PROCESS_ATTACH: + WcaGlobalInitialize(hInstance); + ::DisableThreadLibraryCalls(hInstance); + break; + + case DLL_PROCESS_DETACH: + WcaGlobalFinalize(); + break; + } + + return TRUE; +} diff --git a/src/ca/packages.config b/src/ca/packages.config new file mode 100644 index 00000000..ab964d2c --- /dev/null +++ b/src/ca/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/ca/precomp.h b/src/ca/precomp.h new file mode 100644 index 00000000..74c328d2 --- /dev/null +++ b/src/ca/precomp.h @@ -0,0 +1,33 @@ +#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. + + +#include +#include +#include +#include +#include +#include + +#include "wcautil.h" +#include "memutil.h" +#include "strutil.h" +#include "wiutil.h" + +#include "CustomMsiErrors.h" + +#include "cpcost.h" +#include "cputilexec.h" +#include "cppartexec.h" +#include "cppartroleexec.h" +#include "cpappexec.h" +#include "cpapproleexec.h" +#include "cpasmexec.h" +#include "cpsubsexec.h" +#include "cputilsched.h" +#include "cppartsched.h" +#include "cppartrolesched.h" +#include "cpappsched.h" +#include "cpapprolesched.h" +#include "cpasmsched.h" +#include "cpsubssched.h" diff --git a/src/test/WixToolsetTest.ComPlus/ComPlusExtensionFixture.cs b/src/test/WixToolsetTest.ComPlus/ComPlusExtensionFixture.cs new file mode 100644 index 00000000..4ff3b5f0 --- /dev/null +++ b/src/test/WixToolsetTest.ComPlus/ComPlusExtensionFixture.cs @@ -0,0 +1,32 @@ +// 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 WixToolsetTest.ComPlus +{ + using System.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Core.TestPackage; + using WixToolset.ComPlus; + using Xunit; + + public class ComPlusExtensionFixture + { + [Fact] + public void CanBuildUsingComPlusPartition() + { + var folder = TestData.Get(@"TestData\UsingComPlusPartition"); + var build = new Builder(folder, typeof(ComPlusExtensionFactory), new[] { folder }); + + var results = build.BuildAndQuery(Build, "ComPlusPartition"); + Assert.Equal(new[] + { + "ComPlusPartition:", + }, results.OrderBy(s => s).ToArray()); + } + + private static void Build(string[] args) + { + var result = WixRunner.Execute(args) + .AssertSuccess(); + } + } +} diff --git a/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/Package.en-us.wxl b/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/Package.en-us.wxl new file mode 100644 index 00000000..38c12ac1 --- /dev/null +++ b/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/Package.en-us.wxl @@ -0,0 +1,11 @@ + + + + + + A newer version of [ProductName] is already installed. + MsiPackage + + diff --git a/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/Package.wxs b/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/Package.wxs new file mode 100644 index 00000000..68ff98fd --- /dev/null +++ b/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/Package.wxs @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/PackageComponents.wxs b/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/PackageComponents.wxs new file mode 100644 index 00000000..f61eedd6 --- /dev/null +++ b/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/PackageComponents.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/example.txt b/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/example.txt new file mode 100644 index 00000000..1b4ffe8a --- /dev/null +++ b/src/test/WixToolsetTest.ComPlus/TestData/UsingComPlusPartition/example.txt @@ -0,0 +1 @@ +This is example.txt. \ No newline at end of file diff --git a/src/test/WixToolsetTest.ComPlus/WixToolsetTest.ComPlus.csproj b/src/test/WixToolsetTest.ComPlus/WixToolsetTest.ComPlus.csproj new file mode 100644 index 00000000..801f5ca2 --- /dev/null +++ b/src/test/WixToolsetTest.ComPlus/WixToolsetTest.ComPlus.csproj @@ -0,0 +1,38 @@ + + + + + + netcoreapp2.1 + false + + + + NU1701 + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wixext/ComPlusCompiler.cs b/src/wixext/ComPlusCompiler.cs index 7f22c56b..4709eba9 100644 --- a/src/wixext/ComPlusCompiler.cs +++ b/src/wixext/ComPlusCompiler.cs @@ -1,31 +1,22 @@ // 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 +namespace WixToolset.ComPlus { using System; using System.Collections; using System.Collections.Generic; using System.Globalization; - using System.Reflection; - using System.Xml; + using System.Text; using System.Xml.Linq; - using System.Xml.Schema; using WixToolset.Data; using WixToolset.Extensibility; + using WixToolset.Extensibility.Data; /// - /// The compiler for the WiX Toolset Internet Information Services Extension. + /// The compiler for the WiX Toolset COM+ Extension. /// - public sealed class ComPlusCompiler : CompilerExtension + public sealed class ComPlusCompiler : BaseCompilerExtension { - /// - /// Instantiate a new ComPlusCompiler. - /// - public ComPlusCompiler() - { - this.Namespace = "http://wixtoolset.org/schemas/v4/wxs/complus"; - } - /// /// /// @@ -37,6 +28,8 @@ namespace WixToolset.Extensions RegisterInCommit = (1 << 3) } + public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/complus"; + /// /// Processes an element for the Compiler. /// @@ -44,7 +37,7 @@ namespace WixToolset.Extensions /// 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) + public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context) { switch (parentElement.Name.LocalName) { @@ -56,49 +49,49 @@ namespace WixToolset.Extensions switch (element.Name.LocalName) { case "ComPlusPartition": - this.ParseComPlusPartitionElement(element, componentId, win64); + this.ParseComPlusPartitionElement(intermediate, section, element, componentId, win64); break; case "ComPlusPartitionRole": - this.ParseComPlusPartitionRoleElement(element, componentId, null); + this.ParseComPlusPartitionRoleElement(intermediate, section, element, componentId, null); break; case "ComPlusUserInPartitionRole": - this.ParseComPlusUserInPartitionRoleElement(element, componentId, null); + this.ParseComPlusUserInPartitionRoleElement(intermediate, section, element, componentId, null); break; case "ComPlusGroupInPartitionRole": - this.ParseComPlusGroupInPartitionRoleElement(element, componentId, null); + this.ParseComPlusGroupInPartitionRoleElement(intermediate, section, element, componentId, null); break; case "ComPlusPartitionUser": - this.ParseComPlusPartitionUserElement(element, componentId, null); + this.ParseComPlusPartitionUserElement(intermediate, section, element, componentId, null); break; case "ComPlusApplication": - this.ParseComPlusApplicationElement(element, componentId, win64, null); + this.ParseComPlusApplicationElement(intermediate, section, element, componentId, win64, null); break; case "ComPlusApplicationRole": - this.ParseComPlusApplicationRoleElement(element, componentId, null); + this.ParseComPlusApplicationRoleElement(intermediate, section, element, componentId, null); break; case "ComPlusUserInApplicationRole": - this.ParseComPlusUserInApplicationRoleElement(element, componentId, null); + this.ParseComPlusUserInApplicationRoleElement(intermediate, section, element, componentId, null); break; case "ComPlusGroupInApplicationRole": - this.ParseComPlusGroupInApplicationRoleElement(element, componentId, null); + this.ParseComPlusGroupInApplicationRoleElement(intermediate, section, element, componentId, null); break; case "ComPlusAssembly": - this.ParseComPlusAssemblyElement(element, componentId, win64, null); + this.ParseComPlusAssemblyElement(intermediate, section, element, componentId, win64, null); break; case "ComPlusRoleForComponent": - this.ParseComPlusRoleForComponentElement(element, componentId, null); + this.ParseComPlusRoleForComponentElement(intermediate, section, element, componentId, null); break; case "ComPlusRoleForInterface": - this.ParseComPlusRoleForInterfaceElement(element, componentId, null); + this.ParseComPlusRoleForInterfaceElement(intermediate, section, element, componentId, null); break; case "ComPlusRoleForMethod": - this.ParseComPlusRoleForMethodElement(element, componentId, null); + this.ParseComPlusRoleForMethodElement(intermediate, section, element, componentId, null); break; case "ComPlusSubscription": - this.ParseComPlusSubscriptionElement(element, componentId, null); + this.ParseComPlusSubscriptionElement(intermediate, section, element, componentId, null); break; default: - this.Core.UnexpectedElement(parentElement, element); + this.ParseHelper.UnexpectedElement(parentElement, element); break; } break; @@ -108,24 +101,24 @@ namespace WixToolset.Extensions switch (element.Name.LocalName) { case "ComPlusPartition": - this.ParseComPlusPartitionElement(element, null, false); + this.ParseComPlusPartitionElement(intermediate, section, element, null, false); break; case "ComPlusPartitionRole": - this.ParseComPlusPartitionRoleElement(element, null, null); + this.ParseComPlusPartitionRoleElement(intermediate, section, element, null, null); break; case "ComPlusApplication": - this.ParseComPlusApplicationElement(element, null, false, null); + this.ParseComPlusApplicationElement(intermediate, section, element, null, false, null); break; case "ComPlusApplicationRole": - this.ParseComPlusApplicationRoleElement(element, null, null); + this.ParseComPlusApplicationRoleElement(intermediate, section, element, null, null); break; default: - this.Core.UnexpectedElement(parentElement, element); + this.ParseHelper.UnexpectedElement(parentElement, element); break; } break; default: - this.Core.UnexpectedElement(parentElement, element); + this.ParseHelper.UnexpectedElement(parentElement, element); break; } } @@ -135,9 +128,9 @@ namespace WixToolset.Extensions /// /// Element to parse. /// Identifier of parent component. - private void ParseComPlusPartitionElement(XElement node, string componentKey, bool win64) + private void ParseComPlusPartitionElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, bool win64) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string id = null; @@ -152,49 +145,49 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "PartitionId": - id = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); + id = this.TryFormatGuidValue(this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib)); break; case "Name": - name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "Changeable": - this.Core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(WarningMessages.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)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["Deleteable"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["Deleteable"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "Description": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["Description"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null != componentKey && null == name) { - this.Core.OnMessage(ComPlusErrors.RequiredAttributeUnderComponent(sourceLineNumbers, node.Name.LocalName, "Name")); + this.Messaging.Write(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")); + this.Messaging.Write(ComPlusErrors.RequiredAttributeNotUnderComponent(sourceLineNumbers, node.Name.LocalName, "Id", "Name")); } foreach (XElement child in node.Elements()) @@ -204,58 +197,58 @@ namespace WixToolset.Extensions switch (child.Name.LocalName) { case "ComPlusPartitionRole": - this.ParseComPlusPartitionRoleElement(child, componentKey, key); + this.ParseComPlusPartitionRoleElement(intermediate, section, child, componentKey, key); break; case "ComPlusPartitionUser": - this.ParseComPlusPartitionUserElement(child, componentKey, key); + this.ParseComPlusPartitionUserElement(intermediate, section, child, componentKey, key); break; case "ComPlusApplication": - this.ParseComPlusApplicationElement(child, componentKey, win64, key); + this.ParseComPlusApplicationElement(intermediate, section, child, componentKey, win64, key); break; default: - this.Core.UnexpectedElement(node, child); + this.ParseHelper.UnexpectedElement(node, child); break; } } else { - this.Core.ParseExtensionElement(node, child); + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child); } } - Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusPartition"); - row[0] = key; - row[1] = componentKey; - row[2] = id; - row[3] = name; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusPartition"); + row.Set(0, key); + row.Set(1, componentKey); + row.Set(2, id); + row.Set(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; + var propertyRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusPartitionProperty"); + propertyRow.Set(0, key); + propertyRow.Set(1, (string)propertiesEnumerator.Key); + propertyRow.Set(2, (string)propertiesEnumerator.Value); } if (componentKey != null) { if (win64) { - if (this.Core.CurrentPlatform == Platform.IA64) + if (this.Context.Platform == Platform.IA64) { - this.Core.OnMessage(WixErrors.UnsupportedPlatformForElement(sourceLineNumbers, "ia64", node.Name.LocalName)); + this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, "ia64", node.Name.LocalName)); } else { - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall_x64"); - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall_x64"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall_x64"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall_x64"); } } else { - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall"); - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall"); } } } @@ -266,9 +259,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Optional identifier of parent application. - private void ParseComPlusPartitionRoleElement(XElement node, string componentKey, string partitionKey) + private void ParseComPlusPartitionRoleElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string partitionKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string name = null; @@ -280,33 +273,33 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - partitionKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusPartition", partitionKey); + partitionKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusPartition", partitionKey); break; case "Name": - name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == partitionKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Partition")); + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Partition")); } foreach (XElement child in node.Elements()) @@ -316,27 +309,27 @@ namespace WixToolset.Extensions switch (child.Name.LocalName) { case "ComPlusUserInPartitionRole": - this.ParseComPlusUserInPartitionRoleElement(child, componentKey, key); + this.ParseComPlusUserInPartitionRoleElement(intermediate, section, child, componentKey, key); break; case "ComPlusGroupInPartitionRole": - this.ParseComPlusGroupInPartitionRoleElement(child, componentKey, key); + this.ParseComPlusGroupInPartitionRoleElement(intermediate, section, child, componentKey, key); break; default: - this.Core.UnexpectedElement(node, child); + this.ParseHelper.UnexpectedElement(node, child); break; } } else { - this.Core.ParseExtensionElement(node, child); + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child); } } // add table row - Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusPartitionRole"); - row[0] = key; - row[1] = partitionKey; - row[3] = name; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusPartitionRole"); + row.Set(0, key); + row.Set(1, partitionKey); + row.Set(3, name); } /// @@ -345,9 +338,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Optional identifier of parent application role. - private void ParseComPlusUserInPartitionRoleElement(XElement node, string componentKey, string partitionRoleKey) + private void ParseComPlusUserInPartitionRoleElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string partitionRoleKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string user = null; @@ -359,41 +352,41 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - partitionRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusPartitionRole", partitionRoleKey); + partitionRoleKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusPartitionRole", partitionRoleKey); break; case "User": - user = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "User", user); + user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == partitionRoleKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "PartitionRole")); + this.Messaging.Write(ErrorMessages.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; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusUserInPartitionRole"); + row.Set(0, key); + row.Set(1, partitionRoleKey); + row.Set(2, componentKey); + row.Set(3, user); } /// @@ -402,9 +395,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Optional identifier of parent application role. - private void ParseComPlusGroupInPartitionRoleElement(XElement node, string componentKey, string partitionRoleKey) + private void ParseComPlusGroupInPartitionRoleElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string partitionRoleKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string group = null; @@ -416,41 +409,41 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - partitionRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusPartitionRole", partitionRoleKey); + partitionRoleKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusPartitionRole", partitionRoleKey); break; case "Group": - group = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "Group", group); + group = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "Group", group); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == partitionRoleKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "PartitionRole")); + this.Messaging.Write(ErrorMessages.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; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusGroupInPartitionRole"); + row.Set(0, key); + row.Set(1, partitionRoleKey); + row.Set(2, componentKey); + row.Set(3, group); } /// @@ -458,9 +451,9 @@ namespace WixToolset.Extensions /// /// Element to parse. /// Identifier of parent component. - private void ParseComPlusPartitionUserElement(XElement node, string componentKey, string partitionKey) + private void ParseComPlusPartitionUserElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string partitionKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string user = null; @@ -472,41 +465,41 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - partitionKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusPartition", partitionKey); + partitionKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusPartition", partitionKey); break; case "User": - user = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "User", user); + user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == partitionKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Partition")); + this.Messaging.Write(ErrorMessages.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; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusPartitionUser"); + row.Set(0, key); + row.Set(1, partitionKey); + row.Set(2, componentKey); + row.Set(3, user); } /// @@ -515,9 +508,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Optional identifier of parent partition. - private void ParseComPlusApplicationElement(XElement node, string componentKey, bool win64, string partitionKey) + private void ParseComPlusApplicationElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, bool win64, string partitionKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string id = null; @@ -532,35 +525,35 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - partitionKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusPartition", partitionKey); + partitionKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusPartition", partitionKey); break; case "ApplicationId": - id = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); + id = this.TryFormatGuidValue(this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib)); break; case "Name": - name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "ThreeGigSupportEnabled": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["3GigSupportEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["3GigSupportEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "AccessChecksLevel": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - string accessChecksLevelValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string accessChecksLevelValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (accessChecksLevelValue) { case "applicationLevel": @@ -570,16 +563,16 @@ namespace WixToolset.Extensions properties["AccessChecksLevel"] = "1"; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "AccessChecksLevel", accessChecksLevelValue, "applicationLevel", "applicationComponentLevel")); + this.Messaging.Write(ErrorMessages.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)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - string activationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string activationValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (activationValue) { case "inproc": @@ -589,30 +582,30 @@ namespace WixToolset.Extensions properties["Activation"] = "Local"; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "Activation", activationValue, "inproc", "local")); + this.Messaging.Write(ErrorMessages.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)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["ApplicationAccessChecksEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["ApplicationAccessChecksEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "ApplicationDirectory": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["ApplicationDirectory"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["ApplicationDirectory"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "Authentication": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - string authenticationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string authenticationValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (authenticationValue) { case "default": @@ -637,16 +630,16 @@ namespace WixToolset.Extensions properties["Authentication"] = "6"; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "Authentication", authenticationValue, "default", "none", "connect", "call", "packet", "integrity", "privacy")); + this.Messaging.Write(ErrorMessages.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)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - string authenticationCapabilityValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string authenticationCapabilityValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (authenticationCapabilityValue) { case "none": @@ -662,110 +655,110 @@ namespace WixToolset.Extensions properties["AuthenticationCapability"] = "64"; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "AuthenticationCapability", authenticationCapabilityValue, "none", "secureReference", "staticCloaking", "dynamicCloaking")); + this.Messaging.Write(ErrorMessages.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)); + this.Messaging.Write(WarningMessages.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)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["CommandLine"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["CommandLine"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "ConcurrentApps": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["ConcurrentApps"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["ConcurrentApps"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "CreatedBy": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["CreatedBy"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["CreatedBy"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "CRMEnabled": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["CRMEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["CRMEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "CRMLogFile": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["CRMLogFile"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["CRMLogFile"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "Deleteable": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["Deleteable"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["Deleteable"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "Description": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["Description"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "DumpEnabled": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["DumpEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["DumpEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "DumpOnException": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["DumpOnException"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["DumpOnException"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "DumpOnFailfast": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["DumpOnFailfast"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["DumpOnFailfast"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "DumpPath": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["DumpPath"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["DumpPath"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "EventsEnabled": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["EventsEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["EventsEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "Identity": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["Identity"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["Identity"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "ImpersonationLevel": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - string impersonationLevelValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string impersonationLevelValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (impersonationLevelValue) { case "anonymous": @@ -781,37 +774,37 @@ namespace WixToolset.Extensions properties["ImpersonationLevel"] = "4"; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "ImpersonationLevel", impersonationLevelValue, "anonymous", "identify", "impersonate", "delegate")); + this.Messaging.Write(ErrorMessages.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)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["IsEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["IsEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "MaxDumpCount": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["MaxDumpCount"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["MaxDumpCount"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "Password": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["Password"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["Password"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "QCAuthenticateMsgs": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - string qcAuthenticateMsgsValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string qcAuthenticateMsgsValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (qcAuthenticateMsgsValue) { case "secureApps": @@ -824,128 +817,128 @@ namespace WixToolset.Extensions properties["QCAuthenticateMsgs"] = "2"; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "QCAuthenticateMsgs", qcAuthenticateMsgsValue, "secureApps", "off", "on")); + this.Messaging.Write(ErrorMessages.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)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["QCListenerMaxThreads"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["QCListenerMaxThreads"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "QueueListenerEnabled": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["QueueListenerEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["QueueListenerEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "QueuingEnabled": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["QueuingEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["QueuingEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "RecycleActivationLimit": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["RecycleActivationLimit"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["RecycleActivationLimit"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "RecycleCallLimit": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["RecycleCallLimit"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["RecycleCallLimit"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "RecycleExpirationTimeout": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["RecycleExpirationTimeout"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["RecycleExpirationTimeout"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "RecycleLifetimeLimit": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["RecycleLifetimeLimit"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["RecycleLifetimeLimit"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "RecycleMemoryLimit": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["RecycleMemoryLimit"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["RecycleMemoryLimit"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "Replicable": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["Replicable"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["Replicable"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "RunForever": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["RunForever"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["RunForever"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "ShutdownAfter": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["ShutdownAfter"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["ShutdownAfter"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "SoapActivated": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["SoapActivated"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["SoapActivated"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "SoapBaseUrl": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["SoapBaseUrl"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["SoapBaseUrl"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "SoapMailTo": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["SoapMailTo"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["SoapMailTo"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "SoapVRoot": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["SoapVRoot"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["SoapVRoot"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "SRPEnabled": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["SRPEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["SRPEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "SRPTrustLevel": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - string srpTrustLevelValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string srpTrustLevelValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (srpTrustLevelValue) { case "disallowed": @@ -955,28 +948,28 @@ namespace WixToolset.Extensions properties["SRPTrustLevel"] = "262144"; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "SRPTrustLevel", srpTrustLevelValue, "disallowed", "fullyTrusted")); + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "ComPlusApplication", "SRPTrustLevel", srpTrustLevelValue, "disallowed", "fullyTrusted")); break; } break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null != componentKey && null == name) { - this.Core.OnMessage(ComPlusErrors.RequiredAttributeUnderComponent(sourceLineNumbers, node.Name.LocalName, "Name")); + this.Messaging.Write(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")); + this.Messaging.Write(ComPlusErrors.RequiredAttributeNotUnderComponent(sourceLineNumbers, node.Name.LocalName, "Id", "Name")); } foreach (XElement child in node.Elements()) @@ -986,56 +979,56 @@ namespace WixToolset.Extensions switch (child.Name.LocalName) { case "ComPlusApplicationRole": - this.ParseComPlusApplicationRoleElement(child, componentKey, key); + this.ParseComPlusApplicationRoleElement(intermediate, section, child, componentKey, key); break; case "ComPlusAssembly": - this.ParseComPlusAssemblyElement(child, componentKey, win64, key); + this.ParseComPlusAssemblyElement(intermediate, section, child, componentKey, win64, key); break; default: - this.Core.UnexpectedElement(node, child); + this.ParseHelper.UnexpectedElement(node, child); break; } } else { - this.Core.ParseExtensionElement(node, child); + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child); } } - Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusApplication"); - row[0] = key; - row[1] = partitionKey; - row[2] = componentKey; - row[3] = id; - row[4] = name; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusApplication"); + row.Set(0, key); + row.Set(1, partitionKey); + row.Set(2, componentKey); + row.Set(3, id); + row.Set(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; + var propertyRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusApplicationProperty"); + propertyRow.Set(0, key); + propertyRow.Set(1, (string)propertiesEnumerator.Key); + propertyRow.Set(2, (string)propertiesEnumerator.Value); } if (componentKey != null) { if (win64) { - if (this.Core.CurrentPlatform == Platform.IA64) + if (this.Context.Platform == Platform.IA64) { - this.Core.OnMessage(WixErrors.UnsupportedPlatformForElement(sourceLineNumbers, "ia64", node.Name.LocalName)); + this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, "ia64", node.Name.LocalName)); } else { - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall_x64"); - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall_x64"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall_x64"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall_x64"); } } else { - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall"); - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall"); } } } @@ -1046,9 +1039,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Optional identifier of parent application. - private void ParseComPlusApplicationRoleElement(XElement node, string componentKey, string applicationKey) + private void ParseComPlusApplicationRoleElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string applicationKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string name = null; @@ -1062,40 +1055,40 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - applicationKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusApplication", applicationKey); + applicationKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusApplication", applicationKey); break; case "Name": - name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "Description": if (null == componentKey) { - this.Core.OnMessage(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); + this.Messaging.Write(ComPlusErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); } - properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["Description"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == applicationKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Application")); + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Application")); } foreach (XElement child in node.Elements()) @@ -1105,35 +1098,35 @@ namespace WixToolset.Extensions switch (child.Name.LocalName) { case "ComPlusUserInApplicationRole": - this.ParseComPlusUserInApplicationRoleElement(child, componentKey, key); + this.ParseComPlusUserInApplicationRoleElement(intermediate, section, child, componentKey, key); break; case "ComPlusGroupInApplicationRole": - this.ParseComPlusGroupInApplicationRoleElement(child, componentKey, key); + this.ParseComPlusGroupInApplicationRoleElement(intermediate, section, child, componentKey, key); break; default: - this.Core.UnexpectedElement(node, child); + this.ParseHelper.UnexpectedElement(node, child); break; } } else { - this.Core.ParseExtensionElement(node, child); + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child); } } - Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusApplicationRole"); - row[0] = key; - row[1] = applicationKey; - row[2] = componentKey; - row[3] = name; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusApplicationRole"); + row.Set(0, key); + row.Set(1, applicationKey); + row.Set(2, componentKey); + row.Set(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; + var propertyRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusApplicationRoleProperty"); + propertyRow.Set(0, key); + propertyRow.Set(1, (string)propertiesEnumerator.Key); + propertyRow.Set(2, (string)propertiesEnumerator.Value); } } @@ -1143,9 +1136,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Optional identifier of parent application role. - private void ParseComPlusUserInApplicationRoleElement(XElement node, string componentKey, string applicationRoleKey) + private void ParseComPlusUserInApplicationRoleElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string applicationRoleKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string user = null; @@ -1157,41 +1150,41 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - applicationRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusApplicationRole", applicationRoleKey); + applicationRoleKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusApplicationRole", applicationRoleKey); break; case "User": - user = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "User", user); + user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == applicationRoleKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ApplicationRole")); + this.Messaging.Write(ErrorMessages.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; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusUserInApplicationRole"); + row.Set(0, key); + row.Set(1, applicationRoleKey); + row.Set(2, componentKey); + row.Set(3, user); } /// @@ -1200,9 +1193,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Optional identifier of parent application role. - private void ParseComPlusGroupInApplicationRoleElement(XElement node, string componentKey, string applicationRoleKey) + private void ParseComPlusGroupInApplicationRoleElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string applicationRoleKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string group = null; @@ -1214,41 +1207,41 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - applicationRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusApplicationRole", applicationRoleKey); + applicationRoleKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusApplicationRole", applicationRoleKey); break; case "Group": - group = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "Group", group); + group = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "Group", group); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == applicationRoleKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ApplicationRole")); + this.Messaging.Write(ErrorMessages.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; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusGroupInApplicationRole"); + row.Set(0, key); + row.Set(1, applicationRoleKey); + row.Set(2, componentKey); + row.Set(3, group); } /// @@ -1257,9 +1250,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Optional identifier of parent application. - private void ParseComPlusAssemblyElement(XElement node, string componentKey, bool win64, string applicationKey) + private void ParseComPlusAssemblyElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, bool win64, string applicationKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string assemblyName = null; @@ -1277,30 +1270,30 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - applicationKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusApplication", applicationKey); + applicationKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusApplication", applicationKey); break; case "AssemblyName": - assemblyName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + assemblyName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "DllPath": - dllPath = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + dllPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "TlbPath": - tlbPath = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + tlbPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "PSDllPath": - psDllPath = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + psDllPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "Type": - string typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string typeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (typeValue) { case ".net": @@ -1310,12 +1303,12 @@ namespace WixToolset.Extensions attributes &= ~(int)CpiAssemblyAttributes.DotNetAssembly; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusAssembly", "Type", typeValue, ".net", "native")); + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "ComPlusAssembly", "Type", typeValue, ".net", "native")); break; } break; case "EventClass": - if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= (int)CpiAssemblyAttributes.EventClass; } @@ -1325,7 +1318,7 @@ namespace WixToolset.Extensions } break; case "DllPathFromGAC": - if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= (int)CpiAssemblyAttributes.DllPathFromGAC; } @@ -1335,7 +1328,7 @@ namespace WixToolset.Extensions } break; case "RegisterInCommit": - if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= (int)CpiAssemblyAttributes.RegisterInCommit; } @@ -1345,35 +1338,35 @@ namespace WixToolset.Extensions } break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == applicationKey && 0 == (attributes & (int)CpiAssemblyAttributes.DotNetAssembly)) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Application", "Type", "native")); + this.Messaging.Write(ErrorMessages.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")); + this.Messaging.Write(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")); + this.Messaging.Write(ErrorMessages.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")); + this.Messaging.Write(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")); + this.Messaging.Write(ComPlusErrors.UnexpectedAttributeWithOtherValue(sourceLineNumbers, node.Name.LocalName, "EventClass", "yes", "Type", ".net")); } foreach (XElement child in node.Elements()) @@ -1383,54 +1376,54 @@ namespace WixToolset.Extensions switch (child.Name.LocalName) { case "ComPlusAssemblyDependency": - this.ParseComPlusAssemblyDependencyElement(child, key); + this.ParseComPlusAssemblyDependencyElement(intermediate, section, child, key); break; case "ComPlusComponent": - this.ParseComPlusComponentElement(child, componentKey, key); + this.ParseComPlusComponentElement(intermediate, section, child, componentKey, key); hasComponents = true; break; default: - this.Core.UnexpectedElement(node, child); + this.ParseHelper.UnexpectedElement(node, child); break; } } else { - this.Core.ParseExtensionElement(node, child); + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child); } } if (0 == (attributes & (int)CpiAssemblyAttributes.DotNetAssembly) && !hasComponents) { - this.Core.OnMessage(ComPlusWarnings.MissingComponents(sourceLineNumbers)); + this.Messaging.Write(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; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusAssembly"); + row.Set(0, key); + row.Set(1, applicationKey); + row.Set(2, componentKey); + row.Set(3, assemblyName); + row.Set(4, dllPath); + row.Set(5, tlbPath); + row.Set(6, psDllPath); + row.Set(7, attributes); if (win64) { - if (this.Core.CurrentPlatform == Platform.IA64) + if (this.Context.Platform == Platform.IA64) { - this.Core.OnMessage(WixErrors.UnsupportedPlatformForElement(sourceLineNumbers, "ia64", node.Name.LocalName)); + this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, "ia64", node.Name.LocalName)); } else { - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall_x64"); - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall_x64"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall_x64"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall_x64"); } } else { - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall"); - this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusInstall"); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureComPlusUninstall"); } } @@ -1439,9 +1432,9 @@ namespace WixToolset.Extensions /// /// Element to parse. /// Identifier of parent assembly. - private void ParseComPlusAssemblyDependencyElement(XElement node, string assemblyKey) + private void ParseComPlusAssemblyDependencyElement(Intermediate intermediate, IntermediateSection section, XElement node, string assemblyKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string requiredAssemblyKey = null; @@ -1452,22 +1445,22 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "RequiredAssembly": - requiredAssemblyKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + requiredAssemblyKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } - Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusAssemblyDependency"); - row[0] = assemblyKey; - row[1] = requiredAssemblyKey; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusAssemblyDependency"); + row.Set(0, assemblyKey); + row.Set(1, requiredAssemblyKey); } /// @@ -1476,9 +1469,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Identifier of parent assembly. - private void ParseComPlusComponentElement(XElement node, string componentKey, string assemblyKey) + private void ParseComPlusComponentElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string assemblyKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string clsid = null; @@ -1492,94 +1485,94 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "CLSID": - clsid = "{" + this.Core.GetAttributeValue(sourceLineNumbers, attrib) + "}"; + clsid = "{" + this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib) + "}"; break; case "AllowInprocSubscribers": - properties["AllowInprocSubscribers"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["AllowInprocSubscribers"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "ComponentAccessChecksEnabled": - properties["ComponentAccessChecksEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["ComponentAccessChecksEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "ComponentTransactionTimeout": - properties["ComponentTransactionTimeout"] = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 3600).ToString(); + properties["ComponentTransactionTimeout"] = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 3600).ToString(); break; case "ComponentTransactionTimeoutEnabled": - properties["ComponentTransactionTimeoutEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["ComponentTransactionTimeoutEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "COMTIIntrinsics": - properties["COMTIIntrinsics"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["COMTIIntrinsics"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "ConstructionEnabled": - properties["ConstructionEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["ConstructionEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "ConstructorString": - properties["ConstructorString"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["ConstructorString"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "CreationTimeout": - properties["CreationTimeout"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["CreationTimeout"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "Description": - properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["Description"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "EventTrackingEnabled": - properties["EventTrackingEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["EventTrackingEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "ExceptionClass": - properties["ExceptionClass"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["ExceptionClass"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "FireInParallel": - properties["FireInParallel"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["FireInParallel"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "IISIntrinsics": - properties["IISIntrinsics"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["IISIntrinsics"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "InitializesServerApplication": - properties["InitializesServerApplication"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["InitializesServerApplication"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "IsEnabled": - properties["IsEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["IsEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "IsPrivateComponent": - properties["IsPrivateComponent"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["IsPrivateComponent"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "JustInTimeActivation": - properties["JustInTimeActivation"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["JustInTimeActivation"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "LoadBalancingSupported": - properties["LoadBalancingSupported"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["LoadBalancingSupported"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "MaxPoolSize": - properties["MaxPoolSize"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["MaxPoolSize"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "MinPoolSize": - properties["MinPoolSize"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["MinPoolSize"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "MultiInterfacePublisherFilterCLSID": - properties["MultiInterfacePublisherFilterCLSID"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["MultiInterfacePublisherFilterCLSID"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "MustRunInClientContext": - properties["MustRunInClientContext"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["MustRunInClientContext"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "MustRunInDefaultContext": - properties["MustRunInDefaultContext"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["MustRunInDefaultContext"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "ObjectPoolingEnabled": - properties["ObjectPoolingEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["ObjectPoolingEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "PublisherID": - properties["PublisherID"] = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); + properties["PublisherID"] = this.TryFormatGuidValue(this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib)); break; case "SoapAssemblyName": - properties["SoapAssemblyName"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["SoapAssemblyName"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "SoapTypeName": - properties["SoapTypeName"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["SoapTypeName"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "Synchronization": - string synchronizationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string synchronizationValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (synchronizationValue) { case "ignored": @@ -1598,12 +1591,12 @@ namespace WixToolset.Extensions properties["Synchronization"] = "4"; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusComponent", "Synchronization", synchronizationValue, "ignored", "none", "supported", "required", "requiresNew")); + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "ComPlusComponent", "Synchronization", synchronizationValue, "ignored", "none", "supported", "required", "requiresNew")); break; } break; case "Transaction": - string transactionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string transactionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (transactionValue) { case "ignored": @@ -1622,12 +1615,12 @@ namespace WixToolset.Extensions properties["Transaction"] = "4"; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusComponent", "Transaction", transactionValue, "ignored", "none", "supported", "required", "requiresNew")); + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "ComPlusComponent", "Transaction", transactionValue, "ignored", "none", "supported", "required", "requiresNew")); break; } break; case "TxIsolationLevel": - string txIsolationLevelValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + string txIsolationLevelValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); switch (txIsolationLevelValue) { case "any": @@ -1646,18 +1639,18 @@ namespace WixToolset.Extensions properties["TxIsolationLevel"] = "4"; break; default: - this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "ComPlusComponent", "TxIsolationLevel", txIsolationLevelValue, "any", "readUnCommitted", "readCommitted", "repeatableRead", "serializable")); + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "ComPlusComponent", "TxIsolationLevel", txIsolationLevelValue, "any", "readUnCommitted", "readCommitted", "repeatableRead", "serializable")); break; } break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } @@ -1668,37 +1661,37 @@ namespace WixToolset.Extensions switch (child.Name.LocalName) { case "ComPlusRoleForComponent": - this.ParseComPlusRoleForComponentElement(child, componentKey, key); + this.ParseComPlusRoleForComponentElement(intermediate, section, child, componentKey, key); break; case "ComPlusInterface": - this.ParseComPlusInterfaceElement(child, componentKey, key); + this.ParseComPlusInterfaceElement(intermediate, section, child, componentKey, key); break; case "ComPlusSubscription": - this.ParseComPlusSubscriptionElement(child, componentKey, key); + this.ParseComPlusSubscriptionElement(intermediate, section, child, componentKey, key); break; default: - this.Core.UnexpectedElement(node, child); + this.ParseHelper.UnexpectedElement(node, child); break; } } else { - this.Core.ParseExtensionElement(node, child); + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child); } } - Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusComponent"); - row[0] = key; - row[1] = assemblyKey; - row[2] = clsid; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusComponent"); + row.Set(0, key); + row.Set(1, assemblyKey); + row.Set(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; + var propertyRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusComponentProperty"); + propertyRow.Set(0, key); + propertyRow.Set(1, (string)propertiesEnumerator.Key); + propertyRow.Set(2, (string)propertiesEnumerator.Value); } } @@ -1708,9 +1701,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Identifier of parent COM+ component. - private void ParseComPlusRoleForComponentElement(XElement node, string componentKey, string cpcomponentKey) + private void ParseComPlusRoleForComponentElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string cpcomponentKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string applicationRoleKey = null; @@ -1722,40 +1715,40 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - cpcomponentKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusComponent", cpcomponentKey); + cpcomponentKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusComponent", cpcomponentKey); break; case "ApplicationRole": - applicationRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + applicationRoleKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == cpcomponentKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Component")); + this.Messaging.Write(ErrorMessages.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; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusRoleForComponent"); + row.Set(0, key); + row.Set(1, cpcomponentKey); + row.Set(2, applicationRoleKey); + row.Set(3, componentKey); } /// @@ -1764,9 +1757,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Identifier of parent COM+ component. - private void ParseComPlusInterfaceElement(XElement node, string componentKey, string cpcomponentKey) + private void ParseComPlusInterfaceElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string cpcomponentKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); // parse attributes string key = null; @@ -1781,25 +1774,25 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "IID": - iid = "{" + this.Core.GetAttributeValue(sourceLineNumbers, attrib) + "}"; + iid = "{" + this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib) + "}"; break; case "Description": - properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["Description"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "QueuingEnabled": - properties["QueuingEnabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["QueuingEnabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } @@ -1810,34 +1803,34 @@ namespace WixToolset.Extensions switch (child.Name.LocalName) { case "ComPlusRoleForInterface": - this.ParseComPlusRoleForInterfaceElement(child, componentKey, key); + this.ParseComPlusRoleForInterfaceElement(intermediate, section, child, componentKey, key); break; case "ComPlusMethod": - this.ParseComPlusMethodElement(child, componentKey, key); + this.ParseComPlusMethodElement(intermediate, section, child, componentKey, key); break; default: - this.Core.UnexpectedElement(node, child); + this.ParseHelper.UnexpectedElement(node, child); break; } } else { - this.Core.ParseExtensionElement(node, child); + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child); } } - Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusInterface"); - row[0] = key; - row[1] = cpcomponentKey; - row[2] = iid; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusInterface"); + row.Set(0, key); + row.Set(1, cpcomponentKey); + row.Set(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; + var propertyRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusInterfaceProperty"); + propertyRow.Set(0, key); + propertyRow.Set(1, (string)propertiesEnumerator.Key); + propertyRow.Set(2, (string)propertiesEnumerator.Value); } } @@ -1847,9 +1840,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Identifier of parent interface. - private void ParseComPlusRoleForInterfaceElement(XElement node, string componentKey, string interfaceKey) + private void ParseComPlusRoleForInterfaceElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string interfaceKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string applicationRoleKey = null; @@ -1861,40 +1854,40 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - interfaceKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusInterface", interfaceKey); + interfaceKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusInterface", interfaceKey); break; case "ApplicationRole": - applicationRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + applicationRoleKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == interfaceKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Interface")); + this.Messaging.Write(ErrorMessages.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; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusRoleForInterface"); + row.Set(0, key); + row.Set(1, interfaceKey); + row.Set(2, applicationRoleKey); + row.Set(3, componentKey); } /// @@ -1903,9 +1896,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Identifier of parent interface. - private void ParseComPlusMethodElement(XElement node, string componentKey, string interfaceKey) + private void ParseComPlusMethodElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string interfaceKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; int index = CompilerConstants.IntegerNotSet; @@ -1920,28 +1913,28 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "Index": - index = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); + index = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); break; case "Name": - name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "AutoComplete": - properties["AutoComplete"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["AutoComplete"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "Description": - properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["Description"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } @@ -1952,40 +1945,40 @@ namespace WixToolset.Extensions switch (child.Name.LocalName) { case "ComPlusRoleForMethod": - this.ParseComPlusRoleForMethodElement(child, componentKey, key); + this.ParseComPlusRoleForMethodElement(intermediate, section, child, componentKey, key); break; default: - this.Core.UnexpectedElement(node, child); + this.ParseHelper.UnexpectedElement(node, child); break; } } else { - this.Core.ParseExtensionElement(node, child); + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child); } } if (CompilerConstants.IntegerNotSet == index && null == name) { - this.Core.OnMessage(ComPlusErrors.RequiredAttribute(sourceLineNumbers, node.Name.LocalName, "Index", "Name")); + this.Messaging.Write(ComPlusErrors.RequiredAttribute(sourceLineNumbers, node.Name.LocalName, "Index", "Name")); } - Row row = this.Core.CreateRow(sourceLineNumbers, "ComPlusMethod"); - row[0] = key; - row[1] = interfaceKey; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusMethod"); + row.Set(0, key); + row.Set(1, interfaceKey); if (CompilerConstants.IntegerNotSet != index) { - row[2] = index; + row.Set(2, index); } - row[3] = name; + row.Set(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; + var propertyRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusMethodProperty"); + propertyRow.Set(0, key); + propertyRow.Set(1, (string)propertiesEnumerator.Key); + propertyRow.Set(2, (string)propertiesEnumerator.Value); } } @@ -1995,9 +1988,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Identifier of parent method. - private void ParseComPlusRoleForMethodElement(XElement node, string componentKey, string methodKey) + private void ParseComPlusRoleForMethodElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string methodKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string applicationRoleKey = null; @@ -2009,40 +2002,40 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - methodKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusMethod", methodKey); + methodKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusMethod", methodKey); break; case "ApplicationRole": - applicationRoleKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + applicationRoleKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == methodKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Method")); + this.Messaging.Write(ErrorMessages.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; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusRoleForMethod"); + row.Set(0, key); + row.Set(1, methodKey); + row.Set(2, applicationRoleKey); + row.Set(3, componentKey); } /// @@ -2051,9 +2044,9 @@ namespace WixToolset.Extensions /// Element to parse. /// Identifier of parent component. /// Identifier of parent COM+ component. - private void ParseComPlusSubscriptionElement(XElement node, string componentKey, string cpcomponentKey) + private void ParseComPlusSubscriptionElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentKey, string cpcomponentKey) { - SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); string key = null; string id = null; @@ -2070,95 +2063,95 @@ namespace WixToolset.Extensions switch (attrib.Name.LocalName) { case "Id": - key = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + key = this.ParseHelper.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)); + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); } - cpcomponentKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); - this.Core.CreateSimpleReference(sourceLineNumbers, "ComPlusComponent", cpcomponentKey); + cpcomponentKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "ComPlusComponent", cpcomponentKey); break; case "SubscriptionId": - id = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); + id = this.TryFormatGuidValue(this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib)); break; case "Name": - name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "EventCLSID": - eventCLSID = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + eventCLSID = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "PublisherID": - publisherID = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); + publisherID = this.TryFormatGuidValue(this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib)); break; case "Description": - properties["Description"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["Description"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "Enabled": - properties["Enabled"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["Enabled"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "EventClassPartitionID": - properties["EventClassPartitionID"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["EventClassPartitionID"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "FilterCriteria": - properties["FilterCriteria"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["FilterCriteria"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "InterfaceID": - properties["InterfaceID"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["InterfaceID"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "MachineName": - properties["MachineName"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["MachineName"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "MethodName": - properties["MethodName"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["MethodName"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "PerUser": - properties["PerUser"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["PerUser"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "Queued": - properties["Queued"] = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; + properties["Queued"] = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) ? "1" : "0"; break; case "SubscriberMoniker": - properties["SubscriberMoniker"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["SubscriberMoniker"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; case "UserName": - properties["UserName"] = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + properties["UserName"] = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; default: - this.Core.UnexpectedAttribute(node, attrib); + this.ParseHelper.UnexpectedAttribute(node, attrib); break; } } else { - this.Core.ParseExtensionAttribute(node, attrib); + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); } } if (null == cpcomponentKey) { - this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Component")); + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Component")); } - this.Core.ParseForExtensionElements(node); + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, 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; + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusSubscription"); + row.Set(0, key); + row.Set(1, cpcomponentKey); + row.Set(2, componentKey); + row.Set(3, id); + row.Set(4, name); + row.Set(5, eventCLSID); + row.Set(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; + var propertyRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ComPlusSubscriptionProperty"); + propertyRow.Set(0, key); + propertyRow.Set(1, (string)propertiesEnumerator.Key); + propertyRow.Set(2, (string)propertiesEnumerator.Value); } } diff --git a/src/wixext/ComPlusDecompiler.cs b/src/wixext/ComPlusDecompiler.cs index 27f1653e..6da2df94 100644 --- a/src/wixext/ComPlusDecompiler.cs +++ b/src/wixext/ComPlusDecompiler.cs @@ -1,7 +1,8 @@ // 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 +namespace WixToolset.ComPlus { +#if TODO_CONSIDER_DECOMPILER using System; using System.Collections; using System.Globalization; @@ -1840,4 +1841,5 @@ namespace WixToolset.Extensions } } } +#endif } diff --git a/src/wixext/ComPlusErrors.cs b/src/wixext/ComPlusErrors.cs new file mode 100644 index 00000000..91b41679 --- /dev/null +++ b/src/wixext/ComPlusErrors.cs @@ -0,0 +1,72 @@ +// 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.ComPlus +{ + using System; + using System.Resources; + using WixToolset.Data; + + public static class ComPlusErrors + { + public static Message IllegalAttributeWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName) + { + return Message(sourceLineNumbers, Ids.IllegalAttributeWithoutComponent, "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.", elementName, attributeName); + } + + public static Message IllegalElementWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName) + { + return Message(sourceLineNumbers, Ids.IllegalElementWithoutComponent, "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.", elementName); + } + + public static Message RequiredAttribute(SourceLineNumber sourceLineNumbers, string elementName, string attributeName1, string attributeName2) + { + return Message(sourceLineNumbers, Ids.RequiredAttribute, "A {0} element must have either a {1} attribute or a {2} attribute, or both set.", elementName, attributeName1, attributeName2); + } + + public static Message RequiredAttributeNotUnderComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName1, string attributeName2) + { + return Message(sourceLineNumbers, Ids.RequiredAttributeNotUnderComponent, "A {0} element not nested under a component must have either a {1} attribute or a {2} attribute, or both set.", elementName, attributeName1, attributeName2); + } + + public static Message RequiredAttributeUnderComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName) + { + return Message(sourceLineNumbers, Ids.RequiredAttributeUnderComponent, "The {0}/@{1} attribute must be provided when {0} element is nested under a component.", elementName, attributeName); + } + + public static Message UnexpectedAttributeWithOtherValue(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string otherAttributeName, string otherValue) + { + return Message(sourceLineNumbers, Ids.UnexpectedAttributeWithOtherValue, "The {0}/@{1} attribute cannot coexist with the {2} attribute's value of '{3}'.", elementName, attributeName, otherAttributeName, otherValue); + } + + public static Message UnexpectedAttributeWithOtherValue(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string value, string otherAttributeName, string otherValue) + { + return Message(sourceLineNumbers, Ids.UnexpectedAttributeWithOtherValue, "The {0}/@{1} attribute's value, '{2}', cannot coexist with the {3} attribute's value of '{4}'.", elementName, attributeName, value, otherAttributeName, otherValue); + } + + public static Message UnexpectedAttributeWithoutOtherValue(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string otherAttributeName, string otherValue) + { + return Message(sourceLineNumbers, Ids.UnexpectedAttributeWithoutOtherValue, "The {0}/@{1} cannot be provided unless the {2} attribute is provided with a value of '{3}'.", elementName, attributeName, otherAttributeName, otherValue); + } + + private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) + { + return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args); + } + + private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args) + { + return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args); + } + + public enum Ids + { + IllegalAttributeWithoutComponent = 6000, + IllegalElementWithoutComponent = 6001, + UnexpectedAttributeWithOtherValue = 6002, + UnexpectedAttributeWithoutOtherValue = 6003, + RequiredAttributeUnderComponent = 6004, + RequiredAttribute = 6005, + RequiredAttributeNotUnderComponent = 6006, + } + } +} diff --git a/src/wixext/ComPlusExtensionData.cs b/src/wixext/ComPlusExtensionData.cs index cedc2474..954e89f6 100644 --- a/src/wixext/ComPlusExtensionData.cs +++ b/src/wixext/ComPlusExtensionData.cs @@ -1,64 +1,30 @@ // 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 +namespace WixToolset.ComPlus { - using System; - using System.Reflection; using WixToolset.Data; using WixToolset.Extensibility; /// /// The WiX Toolset COM+ Extension. /// - public sealed class ComPlusExtensionData : ExtensionData + public sealed class ComPlusExtensionData : BaseExtensionData { /// /// 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); - } + public override string DefaultCulture => "en-US"; - /// - /// Internal mechanism to access the extension's table definitions. - /// - /// Extension's table definitions. - internal static TableDefinitionCollection GetExtensionTableDefinitions() + public override bool TryGetTupleDefinitionByName(string name, out IntermediateTupleDefinition tupleDefinition) { - return ExtensionData.LoadTableDefinitionHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.tables.xml"); + tupleDefinition = ComPlusTupleDefinitions.ByName(name); + return tupleDefinition != null; } - /// - /// Internal mechanism to access the extension's library. - /// - /// Extension's library. - internal static Library GetExtensionLibrary(TableDefinitionCollection tableDefinitions) + public override Intermediate GetLibrary(ITupleDefinitionCreator tupleDefinitions) { - return ExtensionData.LoadLibraryHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.complus.wixlib", tableDefinitions); + return Intermediate.Load(typeof(ComPlusExtensionData).Assembly, "WixToolset.ComPlus.complus.wixlib", tupleDefinitions); } } } diff --git a/src/wixext/ComPlusExtensionFactory.cs b/src/wixext/ComPlusExtensionFactory.cs new file mode 100644 index 00000000..d9405867 --- /dev/null +++ b/src/wixext/ComPlusExtensionFactory.cs @@ -0,0 +1,18 @@ +// 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.ComPlus +{ + using System; + using System.Collections.Generic; + using WixToolset.Extensibility; + + public class ComPlusExtensionFactory : BaseExtensionFactory + { + protected override IEnumerable ExtensionTypes => new[] + { + typeof(ComPlusCompiler), + typeof(ComPlusExtensionData), + typeof(ComPlusWindowsInstallerBackendBinderExtension), + }; + } +} diff --git a/src/wixext/ComPlusWarnings.cs b/src/wixext/ComPlusWarnings.cs new file mode 100644 index 00000000..e0000918 --- /dev/null +++ b/src/wixext/ComPlusWarnings.cs @@ -0,0 +1,31 @@ +// 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.ComPlus +{ + using System; + using System.Resources; + using WixToolset.Data; + + public static class ComPlusWarnings + { + public static Message MissingComponents(SourceLineNumber sourceLineNumbers) + { + return Message(sourceLineNumbers, Ids.MissingComponents, "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."); + } + + private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) + { + return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args); + } + + private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args) + { + return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, resourceManager, resourceName, args); + } + + public enum Ids + { + MissingComponents = 6007, + } + } +} diff --git a/src/wixext/ComPlusWindowsInstallerBackendBinderExtension.cs b/src/wixext/ComPlusWindowsInstallerBackendBinderExtension.cs new file mode 100644 index 00000000..b00add9e --- /dev/null +++ b/src/wixext/ComPlusWindowsInstallerBackendBinderExtension.cs @@ -0,0 +1,26 @@ +// 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.ComPlus +{ + using System.Linq; + using System.Xml; + using WixToolset.Data.WindowsInstaller; + using WixToolset.Extensibility; + + public class ComPlusWindowsInstallerBackendBinderExtension : BaseWindowsInstallerBackendBinderExtension + { + private static readonly TableDefinition[] Tables = LoadTables(); + + protected override TableDefinition[] TableDefinitionsForTuples => Tables; + + private static TableDefinition[] LoadTables() + { + using (var resourceStream = typeof(ComPlusWindowsInstallerBackendBinderExtension).Assembly.GetManifestResourceStream("WixToolset.ComPlus.tables.xml")) + using (var reader = XmlReader.Create(resourceStream)) + { + var tables = TableDefinitionCollection.Load(reader); + return tables.ToArray(); + } + } + } +} diff --git a/src/wixext/Tuples/ComPlusApplicationPropertyTuple.cs b/src/wixext/Tuples/ComPlusApplicationPropertyTuple.cs new file mode 100644 index 00000000..2582d323 --- /dev/null +++ b/src/wixext/Tuples/ComPlusApplicationPropertyTuple.cs @@ -0,0 +1,63 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusApplicationProperty = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusApplicationProperty.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusApplicationPropertyTupleFields.Application_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationPropertyTupleFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationPropertyTupleFields.Value), IntermediateFieldType.String), + }, + typeof(ComPlusApplicationPropertyTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusApplicationPropertyTupleFields + { + Application_, + Name, + Value, + } + + public class ComPlusApplicationPropertyTuple : IntermediateTuple + { + public ComPlusApplicationPropertyTuple() : base(ComPlusTupleDefinitions.ComPlusApplicationProperty, null, null) + { + } + + public ComPlusApplicationPropertyTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusApplicationProperty, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusApplicationPropertyTupleFields index] => this.Fields[(int)index]; + + public string Application_ + { + get => this.Fields[(int)ComPlusApplicationPropertyTupleFields.Application_].AsString(); + set => this.Set((int)ComPlusApplicationPropertyTupleFields.Application_, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusApplicationPropertyTupleFields.Name].AsString(); + set => this.Set((int)ComPlusApplicationPropertyTupleFields.Name, value); + } + + public string Value + { + get => this.Fields[(int)ComPlusApplicationPropertyTupleFields.Value].AsString(); + set => this.Set((int)ComPlusApplicationPropertyTupleFields.Value, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusApplicationRolePropertyTuple.cs b/src/wixext/Tuples/ComPlusApplicationRolePropertyTuple.cs new file mode 100644 index 00000000..98eee7f8 --- /dev/null +++ b/src/wixext/Tuples/ComPlusApplicationRolePropertyTuple.cs @@ -0,0 +1,63 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusApplicationRoleProperty = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusApplicationRoleProperty.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusApplicationRolePropertyTupleFields.ApplicationRole_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationRolePropertyTupleFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationRolePropertyTupleFields.Value), IntermediateFieldType.String), + }, + typeof(ComPlusApplicationRolePropertyTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusApplicationRolePropertyTupleFields + { + ApplicationRole_, + Name, + Value, + } + + public class ComPlusApplicationRolePropertyTuple : IntermediateTuple + { + public ComPlusApplicationRolePropertyTuple() : base(ComPlusTupleDefinitions.ComPlusApplicationRoleProperty, null, null) + { + } + + public ComPlusApplicationRolePropertyTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusApplicationRoleProperty, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusApplicationRolePropertyTupleFields index] => this.Fields[(int)index]; + + public string ApplicationRole_ + { + get => this.Fields[(int)ComPlusApplicationRolePropertyTupleFields.ApplicationRole_].AsString(); + set => this.Set((int)ComPlusApplicationRolePropertyTupleFields.ApplicationRole_, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusApplicationRolePropertyTupleFields.Name].AsString(); + set => this.Set((int)ComPlusApplicationRolePropertyTupleFields.Name, value); + } + + public string Value + { + get => this.Fields[(int)ComPlusApplicationRolePropertyTupleFields.Value].AsString(); + set => this.Set((int)ComPlusApplicationRolePropertyTupleFields.Value, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusApplicationRoleTuple.cs b/src/wixext/Tuples/ComPlusApplicationRoleTuple.cs new file mode 100644 index 00000000..5a0cf378 --- /dev/null +++ b/src/wixext/Tuples/ComPlusApplicationRoleTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusApplicationRole = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusApplicationRole.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusApplicationRoleTupleFields.ApplicationRole), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationRoleTupleFields.Application_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationRoleTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationRoleTupleFields.Name), IntermediateFieldType.String), + }, + typeof(ComPlusApplicationRoleTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusApplicationRoleTupleFields + { + ApplicationRole, + Application_, + Component_, + Name, + } + + public class ComPlusApplicationRoleTuple : IntermediateTuple + { + public ComPlusApplicationRoleTuple() : base(ComPlusTupleDefinitions.ComPlusApplicationRole, null, null) + { + } + + public ComPlusApplicationRoleTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusApplicationRole, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusApplicationRoleTupleFields index] => this.Fields[(int)index]; + + public string ApplicationRole + { + get => this.Fields[(int)ComPlusApplicationRoleTupleFields.ApplicationRole].AsString(); + set => this.Set((int)ComPlusApplicationRoleTupleFields.ApplicationRole, value); + } + + public string Application_ + { + get => this.Fields[(int)ComPlusApplicationRoleTupleFields.Application_].AsString(); + set => this.Set((int)ComPlusApplicationRoleTupleFields.Application_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusApplicationRoleTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusApplicationRoleTupleFields.Component_, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusApplicationRoleTupleFields.Name].AsString(); + set => this.Set((int)ComPlusApplicationRoleTupleFields.Name, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusApplicationTuple.cs b/src/wixext/Tuples/ComPlusApplicationTuple.cs new file mode 100644 index 00000000..7fd5fbd4 --- /dev/null +++ b/src/wixext/Tuples/ComPlusApplicationTuple.cs @@ -0,0 +1,79 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusApplication = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusApplication.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusApplicationTupleFields.Application), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationTupleFields.Partition_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationTupleFields.CustomId), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusApplicationTupleFields.Name), IntermediateFieldType.String), + }, + typeof(ComPlusApplicationTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusApplicationTupleFields + { + Application, + Partition_, + Component_, + CustomId, + Name, + } + + public class ComPlusApplicationTuple : IntermediateTuple + { + public ComPlusApplicationTuple() : base(ComPlusTupleDefinitions.ComPlusApplication, null, null) + { + } + + public ComPlusApplicationTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusApplication, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusApplicationTupleFields index] => this.Fields[(int)index]; + + public string Application + { + get => this.Fields[(int)ComPlusApplicationTupleFields.Application].AsString(); + set => this.Set((int)ComPlusApplicationTupleFields.Application, value); + } + + public string Partition_ + { + get => this.Fields[(int)ComPlusApplicationTupleFields.Partition_].AsString(); + set => this.Set((int)ComPlusApplicationTupleFields.Partition_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusApplicationTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusApplicationTupleFields.Component_, value); + } + + public string CustomId + { + get => this.Fields[(int)ComPlusApplicationTupleFields.CustomId].AsString(); + set => this.Set((int)ComPlusApplicationTupleFields.CustomId, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusApplicationTupleFields.Name].AsString(); + set => this.Set((int)ComPlusApplicationTupleFields.Name, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusAssemblyDependencyTuple.cs b/src/wixext/Tuples/ComPlusAssemblyDependencyTuple.cs new file mode 100644 index 00000000..be0bc073 --- /dev/null +++ b/src/wixext/Tuples/ComPlusAssemblyDependencyTuple.cs @@ -0,0 +1,55 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusAssemblyDependency = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusAssemblyDependency.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusAssemblyDependencyTupleFields.Assembly_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusAssemblyDependencyTupleFields.RequiredAssembly_), IntermediateFieldType.String), + }, + typeof(ComPlusAssemblyDependencyTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusAssemblyDependencyTupleFields + { + Assembly_, + RequiredAssembly_, + } + + public class ComPlusAssemblyDependencyTuple : IntermediateTuple + { + public ComPlusAssemblyDependencyTuple() : base(ComPlusTupleDefinitions.ComPlusAssemblyDependency, null, null) + { + } + + public ComPlusAssemblyDependencyTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusAssemblyDependency, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusAssemblyDependencyTupleFields index] => this.Fields[(int)index]; + + public string Assembly_ + { + get => this.Fields[(int)ComPlusAssemblyDependencyTupleFields.Assembly_].AsString(); + set => this.Set((int)ComPlusAssemblyDependencyTupleFields.Assembly_, value); + } + + public string RequiredAssembly_ + { + get => this.Fields[(int)ComPlusAssemblyDependencyTupleFields.RequiredAssembly_].AsString(); + set => this.Set((int)ComPlusAssemblyDependencyTupleFields.RequiredAssembly_, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusAssemblyTuple.cs b/src/wixext/Tuples/ComPlusAssemblyTuple.cs new file mode 100644 index 00000000..0330b4e8 --- /dev/null +++ b/src/wixext/Tuples/ComPlusAssemblyTuple.cs @@ -0,0 +1,103 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusAssembly = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusAssembly.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusAssemblyTupleFields.Assembly), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusAssemblyTupleFields.Application_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusAssemblyTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusAssemblyTupleFields.AssemblyName), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusAssemblyTupleFields.DllPath), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusAssemblyTupleFields.TlbPath), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusAssemblyTupleFields.PSDllPath), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusAssemblyTupleFields.Attributes), IntermediateFieldType.Number), + }, + typeof(ComPlusAssemblyTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusAssemblyTupleFields + { + Assembly, + Application_, + Component_, + AssemblyName, + DllPath, + TlbPath, + PSDllPath, + Attributes, + } + + public class ComPlusAssemblyTuple : IntermediateTuple + { + public ComPlusAssemblyTuple() : base(ComPlusTupleDefinitions.ComPlusAssembly, null, null) + { + } + + public ComPlusAssemblyTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusAssembly, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusAssemblyTupleFields index] => this.Fields[(int)index]; + + public string Assembly + { + get => this.Fields[(int)ComPlusAssemblyTupleFields.Assembly].AsString(); + set => this.Set((int)ComPlusAssemblyTupleFields.Assembly, value); + } + + public string Application_ + { + get => this.Fields[(int)ComPlusAssemblyTupleFields.Application_].AsString(); + set => this.Set((int)ComPlusAssemblyTupleFields.Application_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusAssemblyTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusAssemblyTupleFields.Component_, value); + } + + public string AssemblyName + { + get => this.Fields[(int)ComPlusAssemblyTupleFields.AssemblyName].AsString(); + set => this.Set((int)ComPlusAssemblyTupleFields.AssemblyName, value); + } + + public string DllPath + { + get => this.Fields[(int)ComPlusAssemblyTupleFields.DllPath].AsString(); + set => this.Set((int)ComPlusAssemblyTupleFields.DllPath, value); + } + + public string TlbPath + { + get => this.Fields[(int)ComPlusAssemblyTupleFields.TlbPath].AsString(); + set => this.Set((int)ComPlusAssemblyTupleFields.TlbPath, value); + } + + public string PSDllPath + { + get => this.Fields[(int)ComPlusAssemblyTupleFields.PSDllPath].AsString(); + set => this.Set((int)ComPlusAssemblyTupleFields.PSDllPath, value); + } + + public int Attributes + { + get => this.Fields[(int)ComPlusAssemblyTupleFields.Attributes].AsNumber(); + set => this.Set((int)ComPlusAssemblyTupleFields.Attributes, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusComponentPropertyTuple.cs b/src/wixext/Tuples/ComPlusComponentPropertyTuple.cs new file mode 100644 index 00000000..81651343 --- /dev/null +++ b/src/wixext/Tuples/ComPlusComponentPropertyTuple.cs @@ -0,0 +1,63 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusComponentProperty = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusComponentProperty.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusComponentPropertyTupleFields.ComPlusComponent_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusComponentPropertyTupleFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusComponentPropertyTupleFields.Value), IntermediateFieldType.String), + }, + typeof(ComPlusComponentPropertyTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusComponentPropertyTupleFields + { + ComPlusComponent_, + Name, + Value, + } + + public class ComPlusComponentPropertyTuple : IntermediateTuple + { + public ComPlusComponentPropertyTuple() : base(ComPlusTupleDefinitions.ComPlusComponentProperty, null, null) + { + } + + public ComPlusComponentPropertyTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusComponentProperty, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusComponentPropertyTupleFields index] => this.Fields[(int)index]; + + public string ComPlusComponent_ + { + get => this.Fields[(int)ComPlusComponentPropertyTupleFields.ComPlusComponent_].AsString(); + set => this.Set((int)ComPlusComponentPropertyTupleFields.ComPlusComponent_, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusComponentPropertyTupleFields.Name].AsString(); + set => this.Set((int)ComPlusComponentPropertyTupleFields.Name, value); + } + + public string Value + { + get => this.Fields[(int)ComPlusComponentPropertyTupleFields.Value].AsString(); + set => this.Set((int)ComPlusComponentPropertyTupleFields.Value, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusComponentTuple.cs b/src/wixext/Tuples/ComPlusComponentTuple.cs new file mode 100644 index 00000000..923ff6e3 --- /dev/null +++ b/src/wixext/Tuples/ComPlusComponentTuple.cs @@ -0,0 +1,63 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusComponent = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusComponent.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusComponentTupleFields.ComPlusComponent), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusComponentTupleFields.Assembly_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusComponentTupleFields.CLSID), IntermediateFieldType.String), + }, + typeof(ComPlusComponentTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusComponentTupleFields + { + ComPlusComponent, + Assembly_, + CLSID, + } + + public class ComPlusComponentTuple : IntermediateTuple + { + public ComPlusComponentTuple() : base(ComPlusTupleDefinitions.ComPlusComponent, null, null) + { + } + + public ComPlusComponentTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusComponent, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusComponentTupleFields index] => this.Fields[(int)index]; + + public string ComPlusComponent + { + get => this.Fields[(int)ComPlusComponentTupleFields.ComPlusComponent].AsString(); + set => this.Set((int)ComPlusComponentTupleFields.ComPlusComponent, value); + } + + public string Assembly_ + { + get => this.Fields[(int)ComPlusComponentTupleFields.Assembly_].AsString(); + set => this.Set((int)ComPlusComponentTupleFields.Assembly_, value); + } + + public string CLSID + { + get => this.Fields[(int)ComPlusComponentTupleFields.CLSID].AsString(); + set => this.Set((int)ComPlusComponentTupleFields.CLSID, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusGroupInApplicationRoleTuple.cs b/src/wixext/Tuples/ComPlusGroupInApplicationRoleTuple.cs new file mode 100644 index 00000000..40b47eb3 --- /dev/null +++ b/src/wixext/Tuples/ComPlusGroupInApplicationRoleTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusGroupInApplicationRole = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusGroupInApplicationRole.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusGroupInApplicationRoleTupleFields.GroupInApplicationRole), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusGroupInApplicationRoleTupleFields.ApplicationRole_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusGroupInApplicationRoleTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusGroupInApplicationRoleTupleFields.Group_), IntermediateFieldType.String), + }, + typeof(ComPlusGroupInApplicationRoleTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusGroupInApplicationRoleTupleFields + { + GroupInApplicationRole, + ApplicationRole_, + Component_, + Group_, + } + + public class ComPlusGroupInApplicationRoleTuple : IntermediateTuple + { + public ComPlusGroupInApplicationRoleTuple() : base(ComPlusTupleDefinitions.ComPlusGroupInApplicationRole, null, null) + { + } + + public ComPlusGroupInApplicationRoleTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusGroupInApplicationRole, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusGroupInApplicationRoleTupleFields index] => this.Fields[(int)index]; + + public string GroupInApplicationRole + { + get => this.Fields[(int)ComPlusGroupInApplicationRoleTupleFields.GroupInApplicationRole].AsString(); + set => this.Set((int)ComPlusGroupInApplicationRoleTupleFields.GroupInApplicationRole, value); + } + + public string ApplicationRole_ + { + get => this.Fields[(int)ComPlusGroupInApplicationRoleTupleFields.ApplicationRole_].AsString(); + set => this.Set((int)ComPlusGroupInApplicationRoleTupleFields.ApplicationRole_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusGroupInApplicationRoleTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusGroupInApplicationRoleTupleFields.Component_, value); + } + + public string Group_ + { + get => this.Fields[(int)ComPlusGroupInApplicationRoleTupleFields.Group_].AsString(); + set => this.Set((int)ComPlusGroupInApplicationRoleTupleFields.Group_, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusGroupInPartitionRoleTuple.cs b/src/wixext/Tuples/ComPlusGroupInPartitionRoleTuple.cs new file mode 100644 index 00000000..092937f0 --- /dev/null +++ b/src/wixext/Tuples/ComPlusGroupInPartitionRoleTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusGroupInPartitionRole = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusGroupInPartitionRole.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusGroupInPartitionRoleTupleFields.GroupInPartitionRole), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusGroupInPartitionRoleTupleFields.PartitionRole_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusGroupInPartitionRoleTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusGroupInPartitionRoleTupleFields.Group_), IntermediateFieldType.String), + }, + typeof(ComPlusGroupInPartitionRoleTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusGroupInPartitionRoleTupleFields + { + GroupInPartitionRole, + PartitionRole_, + Component_, + Group_, + } + + public class ComPlusGroupInPartitionRoleTuple : IntermediateTuple + { + public ComPlusGroupInPartitionRoleTuple() : base(ComPlusTupleDefinitions.ComPlusGroupInPartitionRole, null, null) + { + } + + public ComPlusGroupInPartitionRoleTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusGroupInPartitionRole, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusGroupInPartitionRoleTupleFields index] => this.Fields[(int)index]; + + public string GroupInPartitionRole + { + get => this.Fields[(int)ComPlusGroupInPartitionRoleTupleFields.GroupInPartitionRole].AsString(); + set => this.Set((int)ComPlusGroupInPartitionRoleTupleFields.GroupInPartitionRole, value); + } + + public string PartitionRole_ + { + get => this.Fields[(int)ComPlusGroupInPartitionRoleTupleFields.PartitionRole_].AsString(); + set => this.Set((int)ComPlusGroupInPartitionRoleTupleFields.PartitionRole_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusGroupInPartitionRoleTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusGroupInPartitionRoleTupleFields.Component_, value); + } + + public string Group_ + { + get => this.Fields[(int)ComPlusGroupInPartitionRoleTupleFields.Group_].AsString(); + set => this.Set((int)ComPlusGroupInPartitionRoleTupleFields.Group_, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusInterfacePropertyTuple.cs b/src/wixext/Tuples/ComPlusInterfacePropertyTuple.cs new file mode 100644 index 00000000..94f12914 --- /dev/null +++ b/src/wixext/Tuples/ComPlusInterfacePropertyTuple.cs @@ -0,0 +1,63 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusInterfaceProperty = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusInterfaceProperty.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusInterfacePropertyTupleFields.Interface_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusInterfacePropertyTupleFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusInterfacePropertyTupleFields.Value), IntermediateFieldType.String), + }, + typeof(ComPlusInterfacePropertyTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusInterfacePropertyTupleFields + { + Interface_, + Name, + Value, + } + + public class ComPlusInterfacePropertyTuple : IntermediateTuple + { + public ComPlusInterfacePropertyTuple() : base(ComPlusTupleDefinitions.ComPlusInterfaceProperty, null, null) + { + } + + public ComPlusInterfacePropertyTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusInterfaceProperty, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusInterfacePropertyTupleFields index] => this.Fields[(int)index]; + + public string Interface_ + { + get => this.Fields[(int)ComPlusInterfacePropertyTupleFields.Interface_].AsString(); + set => this.Set((int)ComPlusInterfacePropertyTupleFields.Interface_, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusInterfacePropertyTupleFields.Name].AsString(); + set => this.Set((int)ComPlusInterfacePropertyTupleFields.Name, value); + } + + public string Value + { + get => this.Fields[(int)ComPlusInterfacePropertyTupleFields.Value].AsString(); + set => this.Set((int)ComPlusInterfacePropertyTupleFields.Value, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusInterfaceTuple.cs b/src/wixext/Tuples/ComPlusInterfaceTuple.cs new file mode 100644 index 00000000..3c4042ef --- /dev/null +++ b/src/wixext/Tuples/ComPlusInterfaceTuple.cs @@ -0,0 +1,63 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusInterface = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusInterface.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusInterfaceTupleFields.Interface), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusInterfaceTupleFields.ComPlusComponent_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusInterfaceTupleFields.IID), IntermediateFieldType.String), + }, + typeof(ComPlusInterfaceTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusInterfaceTupleFields + { + Interface, + ComPlusComponent_, + IID, + } + + public class ComPlusInterfaceTuple : IntermediateTuple + { + public ComPlusInterfaceTuple() : base(ComPlusTupleDefinitions.ComPlusInterface, null, null) + { + } + + public ComPlusInterfaceTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusInterface, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusInterfaceTupleFields index] => this.Fields[(int)index]; + + public string Interface + { + get => this.Fields[(int)ComPlusInterfaceTupleFields.Interface].AsString(); + set => this.Set((int)ComPlusInterfaceTupleFields.Interface, value); + } + + public string ComPlusComponent_ + { + get => this.Fields[(int)ComPlusInterfaceTupleFields.ComPlusComponent_].AsString(); + set => this.Set((int)ComPlusInterfaceTupleFields.ComPlusComponent_, value); + } + + public string IID + { + get => this.Fields[(int)ComPlusInterfaceTupleFields.IID].AsString(); + set => this.Set((int)ComPlusInterfaceTupleFields.IID, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusMethodPropertyTuple.cs b/src/wixext/Tuples/ComPlusMethodPropertyTuple.cs new file mode 100644 index 00000000..8ebc3f6b --- /dev/null +++ b/src/wixext/Tuples/ComPlusMethodPropertyTuple.cs @@ -0,0 +1,63 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusMethodProperty = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusMethodProperty.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusMethodPropertyTupleFields.Method_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusMethodPropertyTupleFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusMethodPropertyTupleFields.Value), IntermediateFieldType.String), + }, + typeof(ComPlusMethodPropertyTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusMethodPropertyTupleFields + { + Method_, + Name, + Value, + } + + public class ComPlusMethodPropertyTuple : IntermediateTuple + { + public ComPlusMethodPropertyTuple() : base(ComPlusTupleDefinitions.ComPlusMethodProperty, null, null) + { + } + + public ComPlusMethodPropertyTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusMethodProperty, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusMethodPropertyTupleFields index] => this.Fields[(int)index]; + + public string Method_ + { + get => this.Fields[(int)ComPlusMethodPropertyTupleFields.Method_].AsString(); + set => this.Set((int)ComPlusMethodPropertyTupleFields.Method_, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusMethodPropertyTupleFields.Name].AsString(); + set => this.Set((int)ComPlusMethodPropertyTupleFields.Name, value); + } + + public string Value + { + get => this.Fields[(int)ComPlusMethodPropertyTupleFields.Value].AsString(); + set => this.Set((int)ComPlusMethodPropertyTupleFields.Value, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusMethodTuple.cs b/src/wixext/Tuples/ComPlusMethodTuple.cs new file mode 100644 index 00000000..bcca034a --- /dev/null +++ b/src/wixext/Tuples/ComPlusMethodTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusMethod = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusMethod.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusMethodTupleFields.Method), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusMethodTupleFields.Interface_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusMethodTupleFields.Index), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(ComPlusMethodTupleFields.Name), IntermediateFieldType.String), + }, + typeof(ComPlusMethodTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusMethodTupleFields + { + Method, + Interface_, + Index, + Name, + } + + public class ComPlusMethodTuple : IntermediateTuple + { + public ComPlusMethodTuple() : base(ComPlusTupleDefinitions.ComPlusMethod, null, null) + { + } + + public ComPlusMethodTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusMethod, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusMethodTupleFields index] => this.Fields[(int)index]; + + public string Method + { + get => this.Fields[(int)ComPlusMethodTupleFields.Method].AsString(); + set => this.Set((int)ComPlusMethodTupleFields.Method, value); + } + + public string Interface_ + { + get => this.Fields[(int)ComPlusMethodTupleFields.Interface_].AsString(); + set => this.Set((int)ComPlusMethodTupleFields.Interface_, value); + } + + public int Index + { + get => this.Fields[(int)ComPlusMethodTupleFields.Index].AsNumber(); + set => this.Set((int)ComPlusMethodTupleFields.Index, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusMethodTupleFields.Name].AsString(); + set => this.Set((int)ComPlusMethodTupleFields.Name, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusPartitionPropertyTuple.cs b/src/wixext/Tuples/ComPlusPartitionPropertyTuple.cs new file mode 100644 index 00000000..3427b10a --- /dev/null +++ b/src/wixext/Tuples/ComPlusPartitionPropertyTuple.cs @@ -0,0 +1,63 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusPartitionProperty = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusPartitionProperty.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusPartitionPropertyTupleFields.Partition_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionPropertyTupleFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionPropertyTupleFields.Value), IntermediateFieldType.String), + }, + typeof(ComPlusPartitionPropertyTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusPartitionPropertyTupleFields + { + Partition_, + Name, + Value, + } + + public class ComPlusPartitionPropertyTuple : IntermediateTuple + { + public ComPlusPartitionPropertyTuple() : base(ComPlusTupleDefinitions.ComPlusPartitionProperty, null, null) + { + } + + public ComPlusPartitionPropertyTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusPartitionProperty, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusPartitionPropertyTupleFields index] => this.Fields[(int)index]; + + public string Partition_ + { + get => this.Fields[(int)ComPlusPartitionPropertyTupleFields.Partition_].AsString(); + set => this.Set((int)ComPlusPartitionPropertyTupleFields.Partition_, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusPartitionPropertyTupleFields.Name].AsString(); + set => this.Set((int)ComPlusPartitionPropertyTupleFields.Name, value); + } + + public string Value + { + get => this.Fields[(int)ComPlusPartitionPropertyTupleFields.Value].AsString(); + set => this.Set((int)ComPlusPartitionPropertyTupleFields.Value, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusPartitionRoleTuple.cs b/src/wixext/Tuples/ComPlusPartitionRoleTuple.cs new file mode 100644 index 00000000..a2259cc6 --- /dev/null +++ b/src/wixext/Tuples/ComPlusPartitionRoleTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusPartitionRole = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusPartitionRole.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusPartitionRoleTupleFields.PartitionRole), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionRoleTupleFields.Partition_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionRoleTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionRoleTupleFields.Name), IntermediateFieldType.String), + }, + typeof(ComPlusPartitionRoleTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusPartitionRoleTupleFields + { + PartitionRole, + Partition_, + Component_, + Name, + } + + public class ComPlusPartitionRoleTuple : IntermediateTuple + { + public ComPlusPartitionRoleTuple() : base(ComPlusTupleDefinitions.ComPlusPartitionRole, null, null) + { + } + + public ComPlusPartitionRoleTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusPartitionRole, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusPartitionRoleTupleFields index] => this.Fields[(int)index]; + + public string PartitionRole + { + get => this.Fields[(int)ComPlusPartitionRoleTupleFields.PartitionRole].AsString(); + set => this.Set((int)ComPlusPartitionRoleTupleFields.PartitionRole, value); + } + + public string Partition_ + { + get => this.Fields[(int)ComPlusPartitionRoleTupleFields.Partition_].AsString(); + set => this.Set((int)ComPlusPartitionRoleTupleFields.Partition_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusPartitionRoleTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusPartitionRoleTupleFields.Component_, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusPartitionRoleTupleFields.Name].AsString(); + set => this.Set((int)ComPlusPartitionRoleTupleFields.Name, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusPartitionTuple.cs b/src/wixext/Tuples/ComPlusPartitionTuple.cs new file mode 100644 index 00000000..68de9955 --- /dev/null +++ b/src/wixext/Tuples/ComPlusPartitionTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusPartition = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusPartition.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusPartitionTupleFields.Partition), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionTupleFields.CustomId), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionTupleFields.Name), IntermediateFieldType.String), + }, + typeof(ComPlusPartitionTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusPartitionTupleFields + { + Partition, + Component_, + CustomId, + Name, + } + + public class ComPlusPartitionTuple : IntermediateTuple + { + public ComPlusPartitionTuple() : base(ComPlusTupleDefinitions.ComPlusPartition, null, null) + { + } + + public ComPlusPartitionTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusPartition, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusPartitionTupleFields index] => this.Fields[(int)index]; + + public string Partition + { + get => this.Fields[(int)ComPlusPartitionTupleFields.Partition].AsString(); + set => this.Set((int)ComPlusPartitionTupleFields.Partition, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusPartitionTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusPartitionTupleFields.Component_, value); + } + + public string CustomId + { + get => this.Fields[(int)ComPlusPartitionTupleFields.CustomId].AsString(); + set => this.Set((int)ComPlusPartitionTupleFields.CustomId, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusPartitionTupleFields.Name].AsString(); + set => this.Set((int)ComPlusPartitionTupleFields.Name, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusPartitionUserTuple.cs b/src/wixext/Tuples/ComPlusPartitionUserTuple.cs new file mode 100644 index 00000000..33a58d38 --- /dev/null +++ b/src/wixext/Tuples/ComPlusPartitionUserTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusPartitionUser = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusPartitionUser.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusPartitionUserTupleFields.PartitionUser), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionUserTupleFields.Partition_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionUserTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusPartitionUserTupleFields.User_), IntermediateFieldType.String), + }, + typeof(ComPlusPartitionUserTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusPartitionUserTupleFields + { + PartitionUser, + Partition_, + Component_, + User_, + } + + public class ComPlusPartitionUserTuple : IntermediateTuple + { + public ComPlusPartitionUserTuple() : base(ComPlusTupleDefinitions.ComPlusPartitionUser, null, null) + { + } + + public ComPlusPartitionUserTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusPartitionUser, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusPartitionUserTupleFields index] => this.Fields[(int)index]; + + public string PartitionUser + { + get => this.Fields[(int)ComPlusPartitionUserTupleFields.PartitionUser].AsString(); + set => this.Set((int)ComPlusPartitionUserTupleFields.PartitionUser, value); + } + + public string Partition_ + { + get => this.Fields[(int)ComPlusPartitionUserTupleFields.Partition_].AsString(); + set => this.Set((int)ComPlusPartitionUserTupleFields.Partition_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusPartitionUserTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusPartitionUserTupleFields.Component_, value); + } + + public string User_ + { + get => this.Fields[(int)ComPlusPartitionUserTupleFields.User_].AsString(); + set => this.Set((int)ComPlusPartitionUserTupleFields.User_, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusRoleForComponentTuple.cs b/src/wixext/Tuples/ComPlusRoleForComponentTuple.cs new file mode 100644 index 00000000..75d8cfaf --- /dev/null +++ b/src/wixext/Tuples/ComPlusRoleForComponentTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusRoleForComponent = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusRoleForComponent.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusRoleForComponentTupleFields.RoleForComponent), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusRoleForComponentTupleFields.ComPlusComponent_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusRoleForComponentTupleFields.ApplicationRole_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusRoleForComponentTupleFields.Component_), IntermediateFieldType.String), + }, + typeof(ComPlusRoleForComponentTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusRoleForComponentTupleFields + { + RoleForComponent, + ComPlusComponent_, + ApplicationRole_, + Component_, + } + + public class ComPlusRoleForComponentTuple : IntermediateTuple + { + public ComPlusRoleForComponentTuple() : base(ComPlusTupleDefinitions.ComPlusRoleForComponent, null, null) + { + } + + public ComPlusRoleForComponentTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusRoleForComponent, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusRoleForComponentTupleFields index] => this.Fields[(int)index]; + + public string RoleForComponent + { + get => this.Fields[(int)ComPlusRoleForComponentTupleFields.RoleForComponent].AsString(); + set => this.Set((int)ComPlusRoleForComponentTupleFields.RoleForComponent, value); + } + + public string ComPlusComponent_ + { + get => this.Fields[(int)ComPlusRoleForComponentTupleFields.ComPlusComponent_].AsString(); + set => this.Set((int)ComPlusRoleForComponentTupleFields.ComPlusComponent_, value); + } + + public string ApplicationRole_ + { + get => this.Fields[(int)ComPlusRoleForComponentTupleFields.ApplicationRole_].AsString(); + set => this.Set((int)ComPlusRoleForComponentTupleFields.ApplicationRole_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusRoleForComponentTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusRoleForComponentTupleFields.Component_, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusRoleForInterfaceTuple.cs b/src/wixext/Tuples/ComPlusRoleForInterfaceTuple.cs new file mode 100644 index 00000000..139417d3 --- /dev/null +++ b/src/wixext/Tuples/ComPlusRoleForInterfaceTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusRoleForInterface = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusRoleForInterface.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusRoleForInterfaceTupleFields.RoleForInterface), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusRoleForInterfaceTupleFields.Interface_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusRoleForInterfaceTupleFields.ApplicationRole_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusRoleForInterfaceTupleFields.Component_), IntermediateFieldType.String), + }, + typeof(ComPlusRoleForInterfaceTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusRoleForInterfaceTupleFields + { + RoleForInterface, + Interface_, + ApplicationRole_, + Component_, + } + + public class ComPlusRoleForInterfaceTuple : IntermediateTuple + { + public ComPlusRoleForInterfaceTuple() : base(ComPlusTupleDefinitions.ComPlusRoleForInterface, null, null) + { + } + + public ComPlusRoleForInterfaceTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusRoleForInterface, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusRoleForInterfaceTupleFields index] => this.Fields[(int)index]; + + public string RoleForInterface + { + get => this.Fields[(int)ComPlusRoleForInterfaceTupleFields.RoleForInterface].AsString(); + set => this.Set((int)ComPlusRoleForInterfaceTupleFields.RoleForInterface, value); + } + + public string Interface_ + { + get => this.Fields[(int)ComPlusRoleForInterfaceTupleFields.Interface_].AsString(); + set => this.Set((int)ComPlusRoleForInterfaceTupleFields.Interface_, value); + } + + public string ApplicationRole_ + { + get => this.Fields[(int)ComPlusRoleForInterfaceTupleFields.ApplicationRole_].AsString(); + set => this.Set((int)ComPlusRoleForInterfaceTupleFields.ApplicationRole_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusRoleForInterfaceTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusRoleForInterfaceTupleFields.Component_, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusRoleForMethodTuple.cs b/src/wixext/Tuples/ComPlusRoleForMethodTuple.cs new file mode 100644 index 00000000..5b6e994e --- /dev/null +++ b/src/wixext/Tuples/ComPlusRoleForMethodTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusRoleForMethod = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusRoleForMethod.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusRoleForMethodTupleFields.RoleForMethod), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusRoleForMethodTupleFields.Method_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusRoleForMethodTupleFields.ApplicationRole_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusRoleForMethodTupleFields.Component_), IntermediateFieldType.String), + }, + typeof(ComPlusRoleForMethodTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusRoleForMethodTupleFields + { + RoleForMethod, + Method_, + ApplicationRole_, + Component_, + } + + public class ComPlusRoleForMethodTuple : IntermediateTuple + { + public ComPlusRoleForMethodTuple() : base(ComPlusTupleDefinitions.ComPlusRoleForMethod, null, null) + { + } + + public ComPlusRoleForMethodTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusRoleForMethod, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusRoleForMethodTupleFields index] => this.Fields[(int)index]; + + public string RoleForMethod + { + get => this.Fields[(int)ComPlusRoleForMethodTupleFields.RoleForMethod].AsString(); + set => this.Set((int)ComPlusRoleForMethodTupleFields.RoleForMethod, value); + } + + public string Method_ + { + get => this.Fields[(int)ComPlusRoleForMethodTupleFields.Method_].AsString(); + set => this.Set((int)ComPlusRoleForMethodTupleFields.Method_, value); + } + + public string ApplicationRole_ + { + get => this.Fields[(int)ComPlusRoleForMethodTupleFields.ApplicationRole_].AsString(); + set => this.Set((int)ComPlusRoleForMethodTupleFields.ApplicationRole_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusRoleForMethodTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusRoleForMethodTupleFields.Component_, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusSubscriptionPropertyTuple.cs b/src/wixext/Tuples/ComPlusSubscriptionPropertyTuple.cs new file mode 100644 index 00000000..ad0841f4 --- /dev/null +++ b/src/wixext/Tuples/ComPlusSubscriptionPropertyTuple.cs @@ -0,0 +1,63 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusSubscriptionProperty = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusSubscriptionProperty.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusSubscriptionPropertyTupleFields.Subscription_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusSubscriptionPropertyTupleFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusSubscriptionPropertyTupleFields.Value), IntermediateFieldType.String), + }, + typeof(ComPlusSubscriptionPropertyTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusSubscriptionPropertyTupleFields + { + Subscription_, + Name, + Value, + } + + public class ComPlusSubscriptionPropertyTuple : IntermediateTuple + { + public ComPlusSubscriptionPropertyTuple() : base(ComPlusTupleDefinitions.ComPlusSubscriptionProperty, null, null) + { + } + + public ComPlusSubscriptionPropertyTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusSubscriptionProperty, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusSubscriptionPropertyTupleFields index] => this.Fields[(int)index]; + + public string Subscription_ + { + get => this.Fields[(int)ComPlusSubscriptionPropertyTupleFields.Subscription_].AsString(); + set => this.Set((int)ComPlusSubscriptionPropertyTupleFields.Subscription_, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusSubscriptionPropertyTupleFields.Name].AsString(); + set => this.Set((int)ComPlusSubscriptionPropertyTupleFields.Name, value); + } + + public string Value + { + get => this.Fields[(int)ComPlusSubscriptionPropertyTupleFields.Value].AsString(); + set => this.Set((int)ComPlusSubscriptionPropertyTupleFields.Value, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusSubscriptionTuple.cs b/src/wixext/Tuples/ComPlusSubscriptionTuple.cs new file mode 100644 index 00000000..fedab172 --- /dev/null +++ b/src/wixext/Tuples/ComPlusSubscriptionTuple.cs @@ -0,0 +1,95 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusSubscription = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusSubscription.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusSubscriptionTupleFields.Subscription), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusSubscriptionTupleFields.ComPlusComponent_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusSubscriptionTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusSubscriptionTupleFields.CustomId), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusSubscriptionTupleFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusSubscriptionTupleFields.EventCLSID), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusSubscriptionTupleFields.PublisherID), IntermediateFieldType.String), + }, + typeof(ComPlusSubscriptionTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusSubscriptionTupleFields + { + Subscription, + ComPlusComponent_, + Component_, + CustomId, + Name, + EventCLSID, + PublisherID, + } + + public class ComPlusSubscriptionTuple : IntermediateTuple + { + public ComPlusSubscriptionTuple() : base(ComPlusTupleDefinitions.ComPlusSubscription, null, null) + { + } + + public ComPlusSubscriptionTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusSubscription, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusSubscriptionTupleFields index] => this.Fields[(int)index]; + + public string Subscription + { + get => this.Fields[(int)ComPlusSubscriptionTupleFields.Subscription].AsString(); + set => this.Set((int)ComPlusSubscriptionTupleFields.Subscription, value); + } + + public string ComPlusComponent_ + { + get => this.Fields[(int)ComPlusSubscriptionTupleFields.ComPlusComponent_].AsString(); + set => this.Set((int)ComPlusSubscriptionTupleFields.ComPlusComponent_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusSubscriptionTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusSubscriptionTupleFields.Component_, value); + } + + public string CustomId + { + get => this.Fields[(int)ComPlusSubscriptionTupleFields.CustomId].AsString(); + set => this.Set((int)ComPlusSubscriptionTupleFields.CustomId, value); + } + + public string Name + { + get => this.Fields[(int)ComPlusSubscriptionTupleFields.Name].AsString(); + set => this.Set((int)ComPlusSubscriptionTupleFields.Name, value); + } + + public string EventCLSID + { + get => this.Fields[(int)ComPlusSubscriptionTupleFields.EventCLSID].AsString(); + set => this.Set((int)ComPlusSubscriptionTupleFields.EventCLSID, value); + } + + public string PublisherID + { + get => this.Fields[(int)ComPlusSubscriptionTupleFields.PublisherID].AsString(); + set => this.Set((int)ComPlusSubscriptionTupleFields.PublisherID, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusTupleDefinitions.cs b/src/wixext/Tuples/ComPlusTupleDefinitions.cs new file mode 100644 index 00000000..1019c046 --- /dev/null +++ b/src/wixext/Tuples/ComPlusTupleDefinitions.cs @@ -0,0 +1,135 @@ +// 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.ComPlus +{ + using System; + using WixToolset.Data; + + public enum ComPlusTupleDefinitionType + { + ComPlusApplication, + ComPlusApplicationProperty, + ComPlusApplicationRole, + ComPlusApplicationRoleProperty, + ComPlusAssembly, + ComPlusAssemblyDependency, + ComPlusComponent, + ComPlusComponentProperty, + ComPlusGroupInApplicationRole, + ComPlusGroupInPartitionRole, + ComPlusInterface, + ComPlusInterfaceProperty, + ComPlusMethod, + ComPlusMethodProperty, + ComPlusPartition, + ComPlusPartitionProperty, + ComPlusPartitionRole, + ComPlusPartitionUser, + ComPlusRoleForComponent, + ComPlusRoleForInterface, + ComPlusRoleForMethod, + ComPlusSubscription, + ComPlusSubscriptionProperty, + ComPlusUserInApplicationRole, + ComPlusUserInPartitionRole, + } + + public static partial class ComPlusTupleDefinitions + { + public static readonly Version Version = new Version("4.0.0"); + + public static IntermediateTupleDefinition ByName(string name) + { + if (!Enum.TryParse(name, out ComPlusTupleDefinitionType type)) + { + return null; + } + + return ByType(type); + } + + public static IntermediateTupleDefinition ByType(ComPlusTupleDefinitionType type) + { + switch (type) + { + case ComPlusTupleDefinitionType.ComPlusApplication: + return ComPlusTupleDefinitions.ComPlusApplication; + + case ComPlusTupleDefinitionType.ComPlusApplicationProperty: + return ComPlusTupleDefinitions.ComPlusApplicationProperty; + + case ComPlusTupleDefinitionType.ComPlusApplicationRole: + return ComPlusTupleDefinitions.ComPlusApplicationRole; + + case ComPlusTupleDefinitionType.ComPlusApplicationRoleProperty: + return ComPlusTupleDefinitions.ComPlusApplicationRoleProperty; + + case ComPlusTupleDefinitionType.ComPlusAssembly: + return ComPlusTupleDefinitions.ComPlusAssembly; + + case ComPlusTupleDefinitionType.ComPlusAssemblyDependency: + return ComPlusTupleDefinitions.ComPlusAssemblyDependency; + + case ComPlusTupleDefinitionType.ComPlusComponent: + return ComPlusTupleDefinitions.ComPlusComponent; + + case ComPlusTupleDefinitionType.ComPlusComponentProperty: + return ComPlusTupleDefinitions.ComPlusComponentProperty; + + case ComPlusTupleDefinitionType.ComPlusGroupInApplicationRole: + return ComPlusTupleDefinitions.ComPlusGroupInApplicationRole; + + case ComPlusTupleDefinitionType.ComPlusGroupInPartitionRole: + return ComPlusTupleDefinitions.ComPlusGroupInPartitionRole; + + case ComPlusTupleDefinitionType.ComPlusInterface: + return ComPlusTupleDefinitions.ComPlusInterface; + + case ComPlusTupleDefinitionType.ComPlusInterfaceProperty: + return ComPlusTupleDefinitions.ComPlusInterfaceProperty; + + case ComPlusTupleDefinitionType.ComPlusMethod: + return ComPlusTupleDefinitions.ComPlusMethod; + + case ComPlusTupleDefinitionType.ComPlusMethodProperty: + return ComPlusTupleDefinitions.ComPlusMethodProperty; + + case ComPlusTupleDefinitionType.ComPlusPartition: + return ComPlusTupleDefinitions.ComPlusPartition; + + case ComPlusTupleDefinitionType.ComPlusPartitionProperty: + return ComPlusTupleDefinitions.ComPlusPartitionProperty; + + case ComPlusTupleDefinitionType.ComPlusPartitionRole: + return ComPlusTupleDefinitions.ComPlusPartitionRole; + + case ComPlusTupleDefinitionType.ComPlusPartitionUser: + return ComPlusTupleDefinitions.ComPlusPartitionUser; + + case ComPlusTupleDefinitionType.ComPlusRoleForComponent: + return ComPlusTupleDefinitions.ComPlusRoleForComponent; + + case ComPlusTupleDefinitionType.ComPlusRoleForInterface: + return ComPlusTupleDefinitions.ComPlusRoleForInterface; + + case ComPlusTupleDefinitionType.ComPlusRoleForMethod: + return ComPlusTupleDefinitions.ComPlusRoleForMethod; + + case ComPlusTupleDefinitionType.ComPlusSubscription: + return ComPlusTupleDefinitions.ComPlusSubscription; + + case ComPlusTupleDefinitionType.ComPlusSubscriptionProperty: + return ComPlusTupleDefinitions.ComPlusSubscriptionProperty; + + case ComPlusTupleDefinitionType.ComPlusUserInApplicationRole: + return ComPlusTupleDefinitions.ComPlusUserInApplicationRole; + + case ComPlusTupleDefinitionType.ComPlusUserInPartitionRole: + return ComPlusTupleDefinitions.ComPlusUserInPartitionRole; + + default: + throw new ArgumentOutOfRangeException(nameof(type)); + } + } + } +} diff --git a/src/wixext/Tuples/ComPlusUserInApplicationRoleTuple.cs b/src/wixext/Tuples/ComPlusUserInApplicationRoleTuple.cs new file mode 100644 index 00000000..3916c0ee --- /dev/null +++ b/src/wixext/Tuples/ComPlusUserInApplicationRoleTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusUserInApplicationRole = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusUserInApplicationRole.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusUserInApplicationRoleTupleFields.UserInApplicationRole), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusUserInApplicationRoleTupleFields.ApplicationRole_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusUserInApplicationRoleTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusUserInApplicationRoleTupleFields.User_), IntermediateFieldType.String), + }, + typeof(ComPlusUserInApplicationRoleTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusUserInApplicationRoleTupleFields + { + UserInApplicationRole, + ApplicationRole_, + Component_, + User_, + } + + public class ComPlusUserInApplicationRoleTuple : IntermediateTuple + { + public ComPlusUserInApplicationRoleTuple() : base(ComPlusTupleDefinitions.ComPlusUserInApplicationRole, null, null) + { + } + + public ComPlusUserInApplicationRoleTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusUserInApplicationRole, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusUserInApplicationRoleTupleFields index] => this.Fields[(int)index]; + + public string UserInApplicationRole + { + get => this.Fields[(int)ComPlusUserInApplicationRoleTupleFields.UserInApplicationRole].AsString(); + set => this.Set((int)ComPlusUserInApplicationRoleTupleFields.UserInApplicationRole, value); + } + + public string ApplicationRole_ + { + get => this.Fields[(int)ComPlusUserInApplicationRoleTupleFields.ApplicationRole_].AsString(); + set => this.Set((int)ComPlusUserInApplicationRoleTupleFields.ApplicationRole_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusUserInApplicationRoleTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusUserInApplicationRoleTupleFields.Component_, value); + } + + public string User_ + { + get => this.Fields[(int)ComPlusUserInApplicationRoleTupleFields.User_].AsString(); + set => this.Set((int)ComPlusUserInApplicationRoleTupleFields.User_, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/ComPlusUserInPartitionRoleTuple.cs b/src/wixext/Tuples/ComPlusUserInPartitionRoleTuple.cs new file mode 100644 index 00000000..06d742b8 --- /dev/null +++ b/src/wixext/Tuples/ComPlusUserInPartitionRoleTuple.cs @@ -0,0 +1,71 @@ +// 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.ComPlus +{ + using WixToolset.Data; + using WixToolset.ComPlus.Tuples; + + public static partial class ComPlusTupleDefinitions + { + public static readonly IntermediateTupleDefinition ComPlusUserInPartitionRole = new IntermediateTupleDefinition( + ComPlusTupleDefinitionType.ComPlusUserInPartitionRole.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ComPlusUserInPartitionRoleTupleFields.UserInPartitionRole), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusUserInPartitionRoleTupleFields.PartitionRole_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusUserInPartitionRoleTupleFields.Component_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ComPlusUserInPartitionRoleTupleFields.User_), IntermediateFieldType.String), + }, + typeof(ComPlusUserInPartitionRoleTuple)); + } +} + +namespace WixToolset.ComPlus.Tuples +{ + using WixToolset.Data; + + public enum ComPlusUserInPartitionRoleTupleFields + { + UserInPartitionRole, + PartitionRole_, + Component_, + User_, + } + + public class ComPlusUserInPartitionRoleTuple : IntermediateTuple + { + public ComPlusUserInPartitionRoleTuple() : base(ComPlusTupleDefinitions.ComPlusUserInPartitionRole, null, null) + { + } + + public ComPlusUserInPartitionRoleTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(ComPlusTupleDefinitions.ComPlusUserInPartitionRole, sourceLineNumber, id) + { + } + + public IntermediateField this[ComPlusUserInPartitionRoleTupleFields index] => this.Fields[(int)index]; + + public string UserInPartitionRole + { + get => this.Fields[(int)ComPlusUserInPartitionRoleTupleFields.UserInPartitionRole].AsString(); + set => this.Set((int)ComPlusUserInPartitionRoleTupleFields.UserInPartitionRole, value); + } + + public string PartitionRole_ + { + get => this.Fields[(int)ComPlusUserInPartitionRoleTupleFields.PartitionRole_].AsString(); + set => this.Set((int)ComPlusUserInPartitionRoleTupleFields.PartitionRole_, value); + } + + public string Component_ + { + get => this.Fields[(int)ComPlusUserInPartitionRoleTupleFields.Component_].AsString(); + set => this.Set((int)ComPlusUserInPartitionRoleTupleFields.Component_, value); + } + + public string User_ + { + get => this.Fields[(int)ComPlusUserInPartitionRoleTupleFields.User_].AsString(); + set => this.Set((int)ComPlusUserInPartitionRoleTupleFields.User_, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/WixComPlusExtension.csproj b/src/wixext/WixComPlusExtension.csproj deleted file mode 100644 index 92cbacae..00000000 --- a/src/wixext/WixComPlusExtension.csproj +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - {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/WixToolset.ComPlus.wixext.csproj b/src/wixext/WixToolset.ComPlus.wixext.csproj new file mode 100644 index 00000000..882dc7e1 --- /dev/null +++ b/src/wixext/WixToolset.ComPlus.wixext.csproj @@ -0,0 +1,33 @@ + + + + + + netstandard2.0 + WixToolset.ComPlus + WiX Toolset ComPlus Extension + WiX Toolset ComPlus Extension + true + build + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wixext/WixToolset.ComPlus.wixext.targets b/src/wixext/WixToolset.ComPlus.wixext.targets new file mode 100644 index 00000000..8115b715 --- /dev/null +++ b/src/wixext/WixToolset.ComPlus.wixext.targets @@ -0,0 +1,11 @@ + + + + + + $(MSBuildThisFileDirectory)..\tools\WixToolset.ComPlus.wixext.dll + + + + + diff --git a/src/wixext/messages.xml b/src/wixext/messages.xml deleted file mode 100644 index 66c0a9e6..00000000 --- a/src/wixext/messages.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - 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/wixlib/ComPlusExtension.wixproj b/src/wixlib/ComPlusExtension.wixproj deleted file mode 100644 index 49c688cd..00000000 --- a/src/wixlib/ComPlusExtension.wixproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - {E191E61E-E098-4F71-888F-51A79F952022} - complus - Library - true - 1086 - - - - - - - - - - - - - - - diff --git a/src/wixlib/ComPlusExtension.wxs b/src/wixlib/ComPlusExtension.wxs index 3a5c1512..2a5710c0 100644 --- a/src/wixlib/ComPlusExtension.wxs +++ b/src/wixlib/ComPlusExtension.wxs @@ -60,19 +60,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + +