//+--------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1994 - 1998.
//
//  File:       deploy.cpp
//
//  Contents:   application deployment property page
//
//  Classes:    CDeploy
//
//  History:    03-14-1998   stevebl   Commented
//
//---------------------------------------------------------------------------

#include "precomp.hxx"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//
// Guid of appmgmt client side GP extension, and guids for snapins
//

GUID guidExtension = { 0xc6dc5466, 0x785a, 0x11d2, {0x84, 0xd0, 0x00, 0xc0, 0x4f, 0xb1, 0x69, 0xf7}};
GUID guidUserSnapin = CLSID_Snapin;
GUID guidMachSnapin = CLSID_MachineSnapin;
GUID guidRSOPUserSnapin = CLSID_RSOP_Snapin;
GUID guidRSOPMachSnapin = CLSID_RSOP_MachineSnapin;


/////////////////////////////////////////////////////////////////////////////
// CDeploy property page

IMPLEMENT_DYNCREATE(CDeploy, CPropertyPage)

CDeploy::CDeploy() : CPropertyPage(CDeploy::IDD)
{
        //{{AFX_DATA_INIT(CDeploy)
        m_fAutoInst = FALSE;
        m_fFullInst = FALSE;
        m_iUI = -1;
        m_iDeployment = -1;
        m_fUninstallOnPolicyRemoval = FALSE;
        m_hConsoleHandle = NULL;
        m_fNotUserInstall = FALSE;
        //}}AFX_DATA_INIT
        m_pIClassAdmin = NULL;
        m_fPreDeploy = FALSE;
        m_ppThis = NULL;
        m_dlgAdvDep.m_pDeploy = this;
}

CDeploy::~CDeploy()
{
    if (m_ppThis)
    {
        *m_ppThis = NULL;
    }
    MMCFreeNotifyHandle(m_hConsoleHandle);
    if (m_pIClassAdmin)
    {
        m_pIClassAdmin->Release();
    }
}

void CDeploy::DoDataExchange(CDataExchange* pDX)
{
        CPropertyPage::DoDataExchange(pDX);
        //{{AFX_DATA_MAP(CDeploy)
        DDX_Check(pDX, IDC_CHECK2, m_fAutoInst);
        DDX_Radio(pDX, IDC_RADIO3, m_iUI);
        DDX_Radio(pDX, IDC_RADIO2, m_iDeployment);
        DDX_Check(pDX, IDC_CHECK1, m_fUninstallOnPolicyRemoval);
        DDX_Check(pDX, IDC_CHECK3, m_fNotUserInstall);
        DDX_Check(pDX, IDC_CHECK4, m_fFullInst);
        //}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CDeploy, CPropertyPage)
        //{{AFX_MSG_MAP(CDeploy)
        ON_BN_CLICKED(IDC_BUTTON1, OnAdvanced)
        ON_BN_CLICKED(IDC_RADIO2, OnPublished)
        ON_BN_CLICKED(IDC_RADIO1, OnAssigned)
        ON_BN_CLICKED(IDC_CHECK2, OnChanged)
        ON_BN_CLICKED(IDC_CHECK3, OnChanged)
        ON_BN_CLICKED(IDC_RADIO3, OnChanged)
        ON_BN_CLICKED(IDC_RADIO4, OnChanged)
        ON_BN_CLICKED(IDC_CHECK1, OnChanged)
        ON_BN_CLICKED(IDC_CHECK4, OnChanged)
        ON_WM_DESTROY()
    ON_WM_CONTEXTMENU()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDeploy message handlers

BOOL CDeploy::OnApply()
{
    if (m_fRSOP)
    {
        return CPropertyPage::OnApply();
    }
    DWORD dwActFlags = m_pData->m_pDetails->pInstallInfo->dwActFlags;
    dwActFlags &= ~(ACTFLG_Assigned | ACTFLG_Published |
                    ACTFLG_OnDemandInstall | ACTFLG_UserInstall |
                    ACTFLG_OrphanOnPolicyRemoval | ACTFLG_UninstallOnPolicyRemoval |
                    ACTFLG_InstallUserAssign |
                    ACTFLG_ExcludeX86OnIA64 | ACTFLG_IgnoreLanguage | ACTFLG_UninstallUnmanaged);
    switch (m_iDeployment)
    {
    case 2:
        // Disabled
        break;
    case 0:
        // Published
        dwActFlags |= ACTFLG_Published;
        if (m_fAutoInst)
        {
            dwActFlags |= ACTFLG_OnDemandInstall;
        }
        if (!m_fNotUserInstall)
        {
            dwActFlags |= ACTFLG_UserInstall;
        }
        break;
    case 1:
        // Assigned
        dwActFlags |= (ACTFLG_Assigned | ACTFLG_OnDemandInstall);
        if (!m_fNotUserInstall)
        {
            dwActFlags |= ACTFLG_UserInstall;
        }
        if (m_fFullInst)
        {
            dwActFlags |= ACTFLG_InstallUserAssign;
        }
        break;
    default:
        break;
    }

    if (m_pData->m_pDetails->pInstallInfo->PathType == SetupNamePath)
    {
        // legacy app
        if (m_dlgAdvDep.m_f32On64)
            dwActFlags |= ACTFLG_ExcludeX86OnIA64;
    }
    else
    {
        // not a legacy app
        if (!m_dlgAdvDep.m_f32On64)
            dwActFlags |= ACTFLG_ExcludeX86OnIA64;
    }

    if (m_fUninstallOnPolicyRemoval)
    {
        dwActFlags |= ACTFLG_UninstallOnPolicyRemoval;
    }
    else
    {
        // never set this flag for legacy applications
        if (m_pData->m_pDetails->pInstallInfo->PathType != SetupNamePath)
            dwActFlags |= ACTFLG_OrphanOnPolicyRemoval;
    }

    if (m_dlgAdvDep.m_fIgnoreLCID)
    {
        dwActFlags |= ACTFLG_IgnoreLanguage;
    }

    if (m_dlgAdvDep.m_fUninstallUnmanaged)
    {
        dwActFlags |= ACTFLG_UninstallUnmanaged;
    }

    UINT UILevel;
    switch (m_iUI)
    {
    case 1:
        UILevel = INSTALLUILEVEL_FULL;
        break;
    case 0:
    default:
        UILevel = INSTALLUILEVEL_BASIC;
        break;
    }

    HRESULT hr = E_FAIL;
    if (m_pIClassAdmin)
    {
        hr = m_pIClassAdmin->ChangePackageProperties(m_pData->m_pDetails->pszPackageName,
                                                     NULL,
                                                     &dwActFlags,
                                                     NULL,
                                                     NULL,
                                                     &UILevel,
                                                     NULL);
    }
    if (SUCCEEDED(hr))
    {
        m_pData->m_pDetails->pInstallInfo->InstallUiLevel = UILevel;
        m_pData->m_pDetails->pInstallInfo->dwActFlags = dwActFlags;
#if 0
        if (FAILED(m_pIGPEInformation->PolicyChanged(m_fMachine,
                                                    TRUE,
                                                    &guidExtension,
                                                    m_fMachine ? &guidMachSnapin
                                                        : &guidUserSnapin)))
        {
            ReportPolicyChangedError(m_hWnd);
        }
#endif
        if (!m_fPreDeploy)
        {
            MMCPropertyChangeNotify(m_hConsoleHandle, (long) m_cookie);
        }
        else
        {
            // we're in pre-deploy mode - check to see if the fExtensionsOnly
            // flag has changed (which requires a re-deploy)
            // note that these two flags are normally the same,
            // meaning that when they're different, the user has requested a
            // change.
            if (m_dlgAdvDep.m_fIncludeOLEInfo != m_pData->m_pDetails->pActInfo->bHasClasses)
            {
                // need to redeploy
                BOOL fBuildSucceeded = FALSE;
                PACKAGEDETAIL * ppd;

                //
                // Apply the current setting for classes
                //
                m_pData->m_pDetails->pActInfo->bHasClasses = m_dlgAdvDep.m_fIncludeOLEInfo;

                if (FAILED(CopyPackageDetail(ppd, m_pData->m_pDetails)))
                {
                    return FALSE;
                }

                CString sz;

                // Create a name for the new script file.

                // set the script path
                GUID guid;
                HRESULT hr = CoCreateGuid(&guid);
                if (FAILED(hr))
                {
                    // undone
                }

                //
                // For MSI packages, we must regenerate class information
                //
                if ( DrwFilePath == ppd->pInstallInfo->PathType )
                {
                    OLECHAR szGuid [256];
                    StringFromGUID2(guid, szGuid, 256);

                    CString szScriptFile  = m_pScopePane->m_szGPT_Path;
                    szScriptFile += L"\\";
                    szScriptFile += szGuid;
                    szScriptFile += L".aas";
                    OLESAFE_DELETE(ppd->pInstallInfo->pszScriptPath);
                    OLESAFE_COPYSTRING(ppd->pInstallInfo->pszScriptPath, szScriptFile);
                    CString szOldName = ppd->pszPackageName;
                    hr = BuildScriptAndGetActInfo(*ppd, !m_dlgAdvDep.m_fIncludeOLEInfo);

                    if ( SUCCEEDED( hr ) )
                    {
                        if (0 != wcscmp(m_szInitialPackageName, szOldName))
                        {
                            // The User changed the name so we have to preserve his choice.
                            // If the user hasn't changed the package name then it's ok to
                            // set the packagename to whatever is in the script file.
                            OLESAFE_DELETE(ppd->pszPackageName);
                            OLESAFE_COPYSTRING(ppd->pszPackageName, szOldName);
                        }
                    }
                }

                if (SUCCEEDED(hr))
                {
                    fBuildSucceeded = TRUE;
                    hr = m_pScopePane->PrepareExtensions(*ppd);
                    if (SUCCEEDED(hr))
                    {
                        CString szUniqueName;
                        int     nHint;

                        nHint = 1;

                        m_pScopePane->GetUniquePackageName(ppd->pszPackageName, szUniqueName, nHint);
                        OLESAFE_DELETE(ppd->pszPackageName);
                        OLESAFE_COPYSTRING(ppd->pszPackageName, szUniqueName);

                        if ( ppd->pszPackageName )
                        {
                            hr = m_pIClassAdmin->RedeployPackage(
                                &m_pData->m_pDetails->pInstallInfo->PackageGuid,
                                ppd);
                        }
                        else
                        {
                            hr = E_OUTOFMEMORY;
                        }

                        if (SUCCEEDED(hr))
                        {
                            // delete the old script
                            DeleteFile(m_pData->m_pDetails->pInstallInfo->pszScriptPath);
                            // update indexes and property sheets
                            m_pScopePane->RemoveExtensionEntry(m_cookie, *m_pData);
                            m_pScopePane->RemoveUpgradeEntry(m_cookie, *m_pData);
                            FreePackageDetail(m_pData->m_pDetails);
                            m_pData->m_pDetails = ppd;
                            m_pScopePane->InsertExtensionEntry(m_cookie, *m_pData);
                            m_pScopePane->InsertUpgradeEntry(m_cookie, *m_pData);
                            if (m_pScopePane->m_pFileExt)
                            {
                                m_pScopePane->m_pFileExt->SendMessage(WM_USER_REFRESH, 0, 0);
                            }
                        }
                    }
                }
                if (FAILED(hr))
                {
                    CString sz;
                    sz.LoadString(fBuildSucceeded ? IDS_REDEPLOY_FAILED_IN_CS : IDS_REDEPLOY_FAILED);
                    ReportGeneralPropertySheetError(m_hWnd, sz, hr);

                    // delete new script file (assuming it was created)
                    if ( ( DrwFilePath == ppd->pInstallInfo->PathType ) &&
                         ppd->pInstallInfo->pszScriptPath )
                    {
                        DeleteFile(ppd->pInstallInfo->pszScriptPath);
                    }

                    FreePackageDetail(ppd);
                    return FALSE;
                }

            }
        }
    }
    else
    {
        DebugMsg((DM_WARNING, TEXT("ChangePackageProperties failed with 0x%x"), hr));
        CString sz;
        sz.LoadString(IDS_CHANGEFAILED);
        ReportGeneralPropertySheetError(m_hWnd, sz, hr);
        return FALSE;
    }

    return CPropertyPage::OnApply();
}

BOOL CDeploy::OnInitDialog()
{
    RefreshData();
    if (m_pData->m_pDetails->pInstallInfo->PathType == SetupNamePath)
    {
        // legacy apps can't be assigned
        GetDlgItem(IDC_RADIO1)->EnableWindow(FALSE);
        // legacy apps don't have a UI level
        GetDlgItem(IDC_RADIO3)->EnableWindow(FALSE);
        GetDlgItem(IDC_RADIO4)->EnableWindow(FALSE);
        // legacy apps can't be uninstalled
        GetDlgItem(IDC_CHECK1)->EnableWindow(FALSE);
    }

    m_szInitialPackageName = m_pData->m_pDetails->pszPackageName;

    if (m_fMachine)
    {
        GetDlgItem(IDC_RADIO2)->EnableWindow(FALSE);
        // machine deployed apps don't have a UI
        GetDlgItem(IDC_RADIO3)->EnableWindow(FALSE);
        GetDlgItem(IDC_RADIO4)->EnableWindow(FALSE);
    }
    if (0 != (m_pData->m_pDetails->pInstallInfo->dwActFlags & ACTFLG_MinimalInstallUI))
    {
        GetDlgItem(IDC_RADIO4)->EnableWindow(FALSE);
    }
    CPropertyPage::OnInitDialog();

    return TRUE;  // return TRUE unless you set the focus to a control
                  // EXCEPTION: OCX Property Pages should return FALSE
}

void CDeploy::OnAdvanced()
{
    BOOL fIgnoreLCID = m_dlgAdvDep.m_fIgnoreLCID;
    BOOL fInstallOnAlpha = m_dlgAdvDep.m_fInstallOnAlpha;
    BOOL fUninstallUnmanaged = m_dlgAdvDep.m_fUninstallUnmanaged;
    BOOL f32On64 = m_dlgAdvDep.m_f32On64;
    BOOL fIncludeOLEInfo = m_dlgAdvDep.m_fIncludeOLEInfo;

    m_dlgAdvDep.m_szScriptName = m_pData->m_pDetails->pInstallInfo->pszScriptPath;

    if (IDOK == m_dlgAdvDep.DoModal())
    {
        if (fIgnoreLCID != m_dlgAdvDep.m_fIgnoreLCID
            || fInstallOnAlpha != m_dlgAdvDep.m_fInstallOnAlpha
            || fUninstallUnmanaged != m_dlgAdvDep.m_fUninstallUnmanaged
            || f32On64 != m_dlgAdvDep.m_f32On64
            || fIncludeOLEInfo != m_dlgAdvDep.m_fIncludeOLEInfo)
        {
            if (!m_fPreDeploy)
                SetModified();
        }
    }
}

void CDeploy::OnDisable()
{
    if (!m_fPreDeploy)
        SetModified();
    m_fAutoInst = FALSE;
    GetDlgItem(IDC_CHECK2)->EnableWindow(FALSE);
    GetDlgItem(IDC_CHECK3)->EnableWindow(FALSE);
    if (NULL == GetFocus())
    {
        GetParent()->GetDlgItem(IDOK)->SetFocus();
    }
}

void CDeploy::OnPublished()
{
    if (!m_fPreDeploy)
        SetModified();
    GetDlgItem(IDC_CHECK2)->EnableWindow(TRUE);
    GetDlgItem(IDC_CHECK3)->EnableWindow(!m_fMachine);
    GetDlgItem(IDC_CHECK4)->EnableWindow(FALSE);
    if (NULL == GetFocus())
    {
        GetParent()->GetDlgItem(IDOK)->SetFocus();
    }
}

void CDeploy::OnAssigned()
{
    if (!m_fPreDeploy)
        SetModified();
    m_fAutoInst = TRUE;
    GetDlgItem(IDC_CHECK2)->EnableWindow(FALSE);
    GetDlgItem(IDC_CHECK3)->EnableWindow(!m_fMachine);
    GetDlgItem(IDC_CHECK4)->EnableWindow(TRUE);
    if (NULL == GetFocus())
    {
        GetParent()->GetDlgItem(IDOK)->SetFocus();
    }
}

void CDeploy::OnChanged()
{
    if (!m_fPreDeploy)
        SetModified();
}


LRESULT CDeploy::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_HELP:
        StandardHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, IDD);
        return 0;
    case WM_USER_REFRESH:
        RefreshData();
        UpdateData(FALSE);
        return 0;
    case WM_USER_CLOSE:
        m_dlgAdvDep.EndDialog(IDCANCEL);
        return GetOwner()->SendMessage(WM_CLOSE);
    default:
        return CPropertyPage::WindowProc(message, wParam, lParam);
    }
}

void CDeploy::RefreshData(void)
{
    DWORD dwActFlags = m_pData->m_pDetails->pInstallInfo->dwActFlags;
    m_fAutoInst = (0 != (dwActFlags & ACTFLG_OnDemandInstall));
    m_fNotUserInstall = (0 == (dwActFlags & ACTFLG_UserInstall));
    m_fFullInst = (0 != (dwActFlags & ACTFLG_InstallUserAssign));

    if (dwActFlags & ACTFLG_Assigned)
    {
        m_iDeployment = 1;
        GetDlgItem(IDC_CHECK2)->EnableWindow(FALSE);
        GetDlgItem(IDC_CHECK3)->EnableWindow(!m_fMachine);
        // Only enable full assign checkbox when an app is
        // assigned and not legacy.  And only enable this
        // when we're in USER mode.
        // Of course .ZAP (legacy) packages can't be assigned
        // anyway so we don't actually need to check for that.
        GetDlgItem(IDC_CHECK4)->EnableWindow( m_fMachine == FALSE);
    }
    else if (dwActFlags & ACTFLG_Published)
    {
        m_iDeployment = 0;
        GetDlgItem(IDC_CHECK2)->EnableWindow(TRUE);
        GetDlgItem(IDC_CHECK3)->EnableWindow(!m_fMachine);
        GetDlgItem(IDC_CHECK4)->EnableWindow(FALSE);
    }
    else
    {
        m_iDeployment = 2;
        GetDlgItem(IDC_CHECK2)->EnableWindow(FALSE);
        GetDlgItem(IDC_CHECK3)->EnableWindow(FALSE);
        GetDlgItem(IDC_CHECK4)->EnableWindow(FALSE);
    }
    if (this->m_fRSOP)
    {
        // disable EVERYTHING
        GetDlgItem(IDC_RADIO1)->EnableWindow(FALSE);
        GetDlgItem(IDC_RADIO2)->EnableWindow(FALSE);
        GetDlgItem(IDC_RADIO3)->EnableWindow(FALSE);
        GetDlgItem(IDC_RADIO4)->EnableWindow(FALSE);
        GetDlgItem(IDC_CHECK1)->EnableWindow(FALSE);
        GetDlgItem(IDC_CHECK2)->EnableWindow(FALSE);
        GetDlgItem(IDC_CHECK3)->EnableWindow(FALSE);
        GetDlgItem(IDC_CHECK4)->EnableWindow(FALSE);
    }
    if (NULL == GetFocus())
    {
        GetParent()->GetDlgItem(IDOK)->SetFocus();
    }

    if (dwActFlags & ACTFLG_UninstallOnPolicyRemoval)
    {
        m_fUninstallOnPolicyRemoval = TRUE;
    }
    else
    {
        m_fUninstallOnPolicyRemoval = FALSE;
    }

    // initialize the state flags for the advanced dialog
    m_dlgAdvDep.m_szDeploymentCount.Format(TEXT("%u"), m_pData->m_pDetails->pInstallInfo->dwRevision);
    OLECHAR szTemp[80];
    StringFromGUID2(m_pData->m_pDetails->pInstallInfo->ProductCode,
                    szTemp,
                    sizeof(szTemp) / sizeof(szTemp[0]));
    m_dlgAdvDep.m_szProductCode = szTemp;
    m_dlgAdvDep.m_f32On64 = ((dwActFlags & ACTFLG_ExcludeX86OnIA64) == ACTFLG_ExcludeX86OnIA64);

    if (m_pData->m_pDetails->pInstallInfo->PathType != SetupNamePath)
    {
        // this is not a legacy app
        // reverse the sense of m_f32On64
        m_dlgAdvDep.m_f32On64 = !m_dlgAdvDep.m_f32On64;
    }

    if (dwActFlags & ACTFLG_UninstallUnmanaged)
    {
        m_dlgAdvDep.m_fUninstallUnmanaged = TRUE;
    }
    else
    {
        m_dlgAdvDep.m_fUninstallUnmanaged = FALSE;
    }

    m_dlgAdvDep.m_fInstallOnAlpha = FALSE;

    m_dlgAdvDep.m_fIncludeOLEInfo = m_pData->m_pDetails->pActInfo->bHasClasses;

    if (dwActFlags & ACTFLG_IgnoreLanguage)
    {
        m_dlgAdvDep.m_fIgnoreLCID = TRUE;
    }
    else
    {
        m_dlgAdvDep.m_fIgnoreLCID = FALSE;
    }

    switch (m_pData->m_pDetails->pInstallInfo->InstallUiLevel)
    {
    case INSTALLUILEVEL_FULL:
        m_iUI = 1;
        break;
    case INSTALLUILEVEL_BASIC:
    default:
        m_iUI = 0;
        break;
    }

    SetModified(FALSE);
}

void CDeploy::OnContextMenu(CWnd* pWnd, CPoint point)
{
    StandardContextMenu(pWnd->m_hWnd, IDD_DEPLOYMENT);
}