From 337124bed6a57b40fca11c5c2f5b554f570522a6 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Tue, 4 May 2021 11:41:55 -0700 Subject: Move ComPlus.wixext into ext --- src/ext/ComPlus/ca/cpasmexec.cpp | 1877 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1877 insertions(+) create mode 100644 src/ext/ComPlus/ca/cpasmexec.cpp (limited to 'src/ext/ComPlus/ca/cpasmexec.cpp') diff --git a/src/ext/ComPlus/ca/cpasmexec.cpp b/src/ext/ComPlus/ca/cpasmexec.cpp new file mode 100644 index 00000000..3d140027 --- /dev/null +++ b/src/ext/ComPlus/ca/cpasmexec.cpp @@ -0,0 +1,1877 @@ +// 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 structs + +struct CPIEXEC_ROLE_ASSIGNMENT +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzRoleName[MAX_DARWIN_COLUMN + 1]; + + CPIEXEC_ROLE_ASSIGNMENT* pNext; +}; + +struct CPIEXEC_METHOD +{ + WCHAR wzIndex[11 + 1]; + WCHAR wzName[MAX_DARWIN_COLUMN + 1]; + + CPI_PROPERTY* pPropertyList; + CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList; + + CPIEXEC_METHOD* pNext; +}; + +struct CPIEXEC_INTERFACE +{ + WCHAR wzIID[CPI_MAX_GUID + 1]; + + CPI_PROPERTY* pPropertyList; + CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList; + CPIEXEC_METHOD* pMethodList; + + CPIEXEC_INTERFACE* pNext; +}; + +struct CPIEXEC_COMPONENT +{ + WCHAR wzCLSID[CPI_MAX_GUID + 1]; + + CPI_PROPERTY* pPropertyList; + CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList; + CPIEXEC_INTERFACE* pInterfaceList; + + CPIEXEC_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; + CPIEXEC_COMPONENT* pCompList; +}; + +struct CPI_ROLE_ASSIGNMENTS_ATTRIBUTES +{ + int iActionType; + int iActionCost; + LPWSTR pwzKey; + LPWSTR pwzAppID; + LPWSTR pwzPartID; + int iRoleCount; + CPIEXEC_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, + CPIEXEC_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, + CPIEXEC_COMPONENT* pCompList, + BOOL fCreate, + BOOL fProgress + ); +static HRESULT ConfigureInterfaces( + ICatalogCollection* piCompColl, + ICatalogObject* piCompObj, + CPIEXEC_INTERFACE* pIntfList, + BOOL fCreate + ); +static HRESULT ConfigureMethods( + ICatalogCollection* piIntfColl, + ICatalogObject* piIntfObj, + CPIEXEC_METHOD* pMethList, + BOOL fCreate + ); +static HRESULT ConfigureRoleAssignments( + LPCWSTR pwzCollName, + ICatalogCollection* piCompColl, + ICatalogObject* piCompObj, + CPIEXEC_ROLE_ASSIGNMENT* pRoleList, + BOOL fCreate + ); +static HRESULT ReadComponentList( + LPWSTR* ppwzData, + CPIEXEC_COMPONENT** ppCompList + ); +static HRESULT ReadInterfaceList( + LPWSTR* ppwzData, + CPIEXEC_INTERFACE** ppIntfList + ); +static HRESULT ReadMethodList( + LPWSTR* ppwzData, + CPIEXEC_METHOD** ppMethList + ); +static HRESULT ReadRoleAssignmentList( + LPWSTR* ppwzData, + CPIEXEC_ROLE_ASSIGNMENT** ppRoleList + ); +static void FreeComponentList( + CPIEXEC_COMPONENT* pList + ); +static void FreeInterfaceList( + CPIEXEC_INTERFACE* pList + ); +static void FreeMethodList( + CPIEXEC_METHOD* pList + ); +static void FreeRoleAssignmentList( + CPIEXEC_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 = CpiExecGetApplicationsCollection(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 = CpiExecGetAdminCatalog(&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, + CPIEXEC_COMPONENT* pCompList + ) +{ + HRESULT hr = S_OK; + + for (CPIEXEC_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, + CPIEXEC_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 (CPIEXEC_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, + CPIEXEC_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 (CPIEXEC_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, + CPIEXEC_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 (CPIEXEC_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, + CPIEXEC_ROLE_ASSIGNMENT* pRoleList, + BOOL fCreate + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piRoleColl = NULL; + ICatalogObject* piRoleObj = NULL; + + long lChanges = 0; + + // get roles collection + hr = CpiExecGetCatalogCollection(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 (CPIEXEC_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, + CPIEXEC_COMPONENT** ppCompList + ) +{ + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + + CPIEXEC_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 = (CPIEXEC_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_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, + CPIEXEC_INTERFACE** ppIntfList + ) +{ + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + + CPIEXEC_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 = (CPIEXEC_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_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, + CPIEXEC_METHOD** ppMethList + ) +{ + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + + CPIEXEC_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 = (CPIEXEC_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_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, + CPIEXEC_ROLE_ASSIGNMENT** ppRoleList + ) +{ + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + + CPIEXEC_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 = (CPIEXEC_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_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( + CPIEXEC_COMPONENT* pList + ) +{ + while (pList) + { + if (pList->pPropertyList) + CpiFreePropertyList(pList->pPropertyList); + if (pList->pRoleAssignmentList) + FreeRoleAssignmentList(pList->pRoleAssignmentList); + if (pList->pInterfaceList) + FreeInterfaceList(pList->pInterfaceList); + + CPIEXEC_COMPONENT* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +static void FreeInterfaceList( + CPIEXEC_INTERFACE* pList + ) +{ + while (pList) + { + if (pList->pPropertyList) + CpiFreePropertyList(pList->pPropertyList); + if (pList->pRoleAssignmentList) + FreeRoleAssignmentList(pList->pRoleAssignmentList); + if (pList->pMethodList) + FreeMethodList(pList->pMethodList); + + CPIEXEC_INTERFACE* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +static void FreeMethodList( + CPIEXEC_METHOD* pList + ) +{ + while (pList) + { + if (pList->pPropertyList) + CpiFreePropertyList(pList->pPropertyList); + if (pList->pRoleAssignmentList) + FreeRoleAssignmentList(pList->pRoleAssignmentList); + + CPIEXEC_METHOD* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +static void FreeRoleAssignmentList( + CPIEXEC_ROLE_ASSIGNMENT* pList + ) +{ + while (pList) + { + CPIEXEC_ROLE_ASSIGNMENT* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} -- cgit v1.2.3-55-g6feb