// 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"

LPCWSTR vcsPerfCounterDataQuery = L"SELECT `PerformanceCategory`, `Component_`, `Name`, `IniData`, `ConstantData` FROM `Wix4PerformanceCategory`";
enum ePerfCounterDataQuery { pcdqId = 1, pcdqComponent, pcdqName, pcdqIniData, pcdqConstantData };

LPCWSTR vcsPerfMonQuery = L"SELECT `Component_`, `File`, `Name` FROM `Wix4Perfmon`";
enum ePerfMonQuery { pmqComponent = 1, pmqFile, pmqName };


static HRESULT ProcessPerformanceCategory(
    __in MSIHANDLE hInstall,
    __in BOOL fInstall
    );


/********************************************************************
 InstallPerfCounterData - CUSTOM ACTION ENTRY POINT for installing
                          Performance Counters.

********************************************************************/
extern "C" UINT __stdcall InstallPerfCounterData(
    __in MSIHANDLE hInstall
    )
{
    // AssertSz(FALSE, "debug InstallPerfCounterData{}");
    HRESULT hr;
    UINT er = ERROR_SUCCESS;

    hr = WcaInitialize(hInstall, "InstallPerfCounterData");
    ExitOnFailure(hr, "Failed to initialize InstallPerfCounterData.");

    hr = ProcessPerformanceCategory(hInstall, TRUE);
    MessageExitOnFailure(hr, msierrInstallPerfCounterData, "Failed to process Wix4PerformanceCategory table.");

LExit:
    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}


/********************************************************************
 UninstallPerfCounterData - CUSTOM ACTION ENTRY POINT for installing
                          Performance Counters.

********************************************************************/
extern "C" UINT __stdcall UninstallPerfCounterData(
    __in MSIHANDLE hInstall
    )
{
    // AssertSz(FALSE, "debug UninstallPerfCounterData{}");
    HRESULT hr;
    UINT er = ERROR_SUCCESS;

    hr = WcaInitialize(hInstall, "UninstallPerfCounterData");
    ExitOnFailure(hr, "Failed to initialize UninstallPerfCounterData.");

    hr = ProcessPerformanceCategory(hInstall, FALSE);
    MessageExitOnFailure(hr, msierrUninstallPerfCounterData, "Failed to process Wix4PerformanceCategory table.");

LExit:
    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}


/********************************************************************
 RegisterPerfmon - CUSTOM ACTION ENTRY POINT for installing Perfmon counters

********************************************************************/
extern "C" UINT __stdcall ConfigurePerfmonInstall(
    __in MSIHANDLE hInstall
    )
{
//    Assert(FALSE);
    HRESULT hr;
    UINT er = ERROR_SUCCESS;

    PMSIHANDLE hView, hRec;
    LPWSTR pwzData = NULL, pwzName = NULL, pwzFile = NULL;
    INSTALLSTATE isInstalled, isAction;

    hr = WcaInitialize(hInstall, "ConfigurePerfmonInstall");
    ExitOnFailure(hr, "Failed to initialize");

    // check to see if necessary tables are specified
    if (S_OK != WcaTableExists(L"Wix4Perfmon"))
    {
        WcaLog(LOGMSG_VERBOSE, "Skipping RegisterPerfmon() because Wix4Perfmon table not present");
        ExitFunction1(hr = S_FALSE);
    }

    hr = WcaOpenExecuteView(vcsPerfMonQuery, &hView);
    ExitOnFailure(hr, "failed to open view on PerfMon table");
    while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK)
    {
        // get component install state
        hr = WcaGetRecordString(hRec, pmqComponent, &pwzData);
        ExitOnFailure(hr, "failed to get Component for PerfMon");
        er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
        hr = HRESULT_FROM_WIN32(er);
        ExitOnFailure(hr, "failed to get Component state for PerfMon");
        if (!WcaIsInstalling(isInstalled, isAction))
        {
            continue;
        }

        hr = WcaGetRecordString(hRec, pmqName, &pwzName);
        ExitOnFailure(hr, "failed to get Name for PerfMon");

        hr = WcaGetRecordFormattedString(hRec, pmqFile, &pwzFile);
        ExitOnFailure(hr, "failed to get File for PerfMon");

        WcaLog(LOGMSG_VERBOSE, "ConfigurePerfmonInstall's CustomActionData: '%ls', '%ls'", pwzName, pwzFile);
        hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfmon"), pwzFile, COST_PERFMON_REGISTER);
        ExitOnFailure(hr, "failed to schedule RegisterPerfmon action");
        hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfmon"), pwzName, COST_PERFMON_UNREGISTER);
        ExitOnFailure(hr, "failed to schedule RollbackRegisterPerfmon action");
    }

    if (hr == E_NOMOREITEMS)
    {
        hr = S_OK;
    }
    ExitOnFailure(hr, "Failure while processing PerfMon");

    hr = S_OK;

LExit:
    ReleaseStr(pwzData);
    ReleaseStr(pwzName);
    ReleaseStr(pwzFile);

    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}


/********************************************************************
 ConfigurePerfmonUninstall - CUSTOM ACTION ENTRY POINT for uninstalling 
                             Perfmon counters

********************************************************************/
extern "C" UINT __stdcall ConfigurePerfmonUninstall(
    __in MSIHANDLE hInstall
    )
{
//    Assert(FALSE);
    HRESULT hr;
    UINT er = ERROR_SUCCESS;

    PMSIHANDLE hView, hRec;
    LPWSTR pwzData = NULL, pwzName = NULL, pwzFile = NULL;
    INSTALLSTATE isInstalled, isAction;

    hr = WcaInitialize(hInstall, "ConfigurePerfmonUninstall");
    ExitOnFailure(hr, "Failed to initialize");

    // check to see if necessary tables are specified
    if (WcaTableExists(L"Wix4Perfmon") != S_OK)
    {
        WcaLog(LOGMSG_VERBOSE, "Skipping UnregisterPerfmon() because Wix4Perfmon table not present");
        ExitFunction1(hr = S_FALSE);
    }

    hr = WcaOpenExecuteView(vcsPerfMonQuery, &hView);
    ExitOnFailure(hr, "failed to open view on PerfMon table");
    while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK)
    {
        // get component install state
        hr = WcaGetRecordString(hRec, pmqComponent, &pwzData);
        ExitOnFailure(hr, "failed to get Component for PerfMon");
        er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
        hr = HRESULT_FROM_WIN32(er);
        ExitOnFailure(hr, "failed to get Component state for PerfMon");
        if (!WcaIsUninstalling(isInstalled, isAction))
        {
            continue;
        }

        hr = WcaGetRecordString(hRec, pmqName, &pwzName);
        ExitOnFailure(hr, "failed to get Name for PerfMon");

        hr = WcaGetRecordFormattedString(hRec, pmqFile, &pwzFile);
        ExitOnFailure(hr, "failed to get File for PerfMon");

        WcaLog(LOGMSG_VERBOSE, "ConfigurePerfmonUninstall's CustomActionData: '%ls', '%ls'", pwzName, pwzFile);
        hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfmon"), pwzName, COST_PERFMON_UNREGISTER);
        ExitOnFailure(hr, "failed to schedule UnregisterPerfmon action");
        hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfmon"), pwzFile, COST_PERFMON_REGISTER);
        ExitOnFailure(hr, "failed to schedule RollbackUnregisterPerfmon action");
    }

    if (hr == E_NOMOREITEMS)
    {
        hr = S_OK;
    }
    ExitOnFailure(hr, "Failure while processing PerfMon");

    hr = S_OK;

LExit:
    ReleaseStr(pwzData);
    ReleaseStr(pwzName);
    ReleaseStr(pwzFile);

    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}



static HRESULT ProcessPerformanceCategory(
    __in MSIHANDLE hInstall,
    __in BOOL fInstall
    )
{
    HRESULT hr = S_OK;
    DWORD er = ERROR_SUCCESS;

    PMSIHANDLE hView, hRec;
    LPWSTR pwzId = NULL;
    LPWSTR pwzComponent = NULL;
    LPWSTR pwzName = NULL;
    LPWSTR pwzData = NULL;
    INSTALLSTATE isInstalled, isAction;

    LPWSTR pwzCustomActionData = NULL;

    // check to see if necessary tables are specified
    if (S_OK != WcaTableExists(L"Wix4PerformanceCategory"))
    {
        ExitFunction1(hr = S_FALSE);
    }

    hr = WcaOpenExecuteView(vcsPerfCounterDataQuery, &hView);
    ExitOnFailure(hr, "failed to open view on Wix4PerformanceCategory table");
    while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
    {
        hr = WcaGetRecordString(hRec, pcdqId, &pwzId);
        ExitOnFailure(hr, "Failed to get id for Wix4PerformanceCategory.");

        // Check to see if the Component is being installed or uninstalled
        // when we are processing the same.
        hr = WcaGetRecordString(hRec, pcdqComponent, &pwzComponent);
        ExitOnFailure(hr, "Failed to get Component for Wix4PerformanceCategory: %ls", pwzId);

        er = ::MsiGetComponentStateW(hInstall, pwzComponent, &isInstalled, &isAction);
        hr = HRESULT_FROM_WIN32(er);
        ExitOnFailure(hr, "Failed to get Component state for Wix4PerformanceCategory: %ls", pwzId);

        if ((fInstall && !WcaIsInstalling(isInstalled, isAction)) ||
            (!fInstall && !WcaIsUninstalling(isInstalled, isAction)))
        {
            continue;
        }

        hr = WcaGetRecordString(hRec, pcdqName, &pwzName);
        ExitOnFailure(hr, "Failed to get Name for Wix4PerformanceCategory: %ls", pwzId);
        hr = WcaWriteStringToCaData(pwzName, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add Name to CustomActionData for Wix4PerformanceCategory: %ls", pwzId);

        hr = WcaGetRecordString(hRec, pcdqIniData, &pwzData);
        ExitOnFailure(hr, "Failed to get IniData for Wix4PerformanceCategory: %ls", pwzId);
        hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add IniData to CustomActionData for Wix4PerformanceCategory: %ls", pwzId);

        hr = WcaGetRecordString(hRec, pcdqConstantData, &pwzData);
        ExitOnFailure(hr, "Failed to get ConstantData for Wix4PerformanceCategory: %ls", pwzId);
        hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add ConstantData to CustomActionData for Wix4PerformanceCategory: %ls", pwzId);
    }

    if (hr == E_NOMOREITEMS)
    {
        hr = S_OK;
    }
    ExitOnFailure(hr, "Failure while processing Wix4PerformanceCategory table.");

    // If there was any data built up, schedule it for execution.
    if (pwzCustomActionData)
    {
        if (fInstall)
        {
            hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_UNREGISTER);
            ExitOnFailure(hr, "Failed to schedule RollbackRegisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId);

            hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_REGISTER);
            ExitOnFailure(hr, "Failed to schedule RegisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId);
        }
        else
        {
            hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_REGISTER);
            ExitOnFailure(hr, "Failed to schedule RollbackUnregisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId);

            hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_UNREGISTER);
            ExitOnFailure(hr, "Failed to schedule UnregisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId);
        }
    }

LExit:
    ReleaseStr(pwzCustomActionData);
    ReleaseStr(pwzData);
    ReleaseStr(pwzName);
    ReleaseStr(pwzComponent);
    ReleaseStr(pwzId);

    return hr;
}