3173 lines
113 KiB
C++
3173 lines
113 KiB
C++
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1994 - 1998.
|
||
|
//
|
||
|
// File: packages.cpp
|
||
|
//
|
||
|
// Contents: Methods on CScopePane related to package deployment
|
||
|
// and maintenence of the various index and cross-reference
|
||
|
// structures.
|
||
|
//
|
||
|
// Classes:
|
||
|
//
|
||
|
// Functions: CopyPackageDetail
|
||
|
// FreePackageDetail
|
||
|
// GetMsiProperty
|
||
|
//
|
||
|
// History: 2-03-1998 stevebl Created
|
||
|
// 3-25-1998 stevebl Added GetMsiProperty
|
||
|
// 5-20-1998 RahulTh - Added DetectUpgrades for automatic upgrade
|
||
|
// detection
|
||
|
// - Added GetCapitalizedExt
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
// UNDONE - put in exception handling for low memory conditions
|
||
|
|
||
|
#include "precomp.hxx"
|
||
|
|
||
|
// uncomment this line to get the old behavior of putting up an upgrade
|
||
|
// dialog for auto-detected upgrades
|
||
|
//#define SHOWDETECTEDUPGRADEDIALOG
|
||
|
|
||
|
//IMalloc * g_pIMalloc = NULL;
|
||
|
|
||
|
BOOL IsNullGUID (GUID *pguid)
|
||
|
{
|
||
|
|
||
|
return ( (pguid->Data1 == 0) &&
|
||
|
(pguid->Data2 == 0) &&
|
||
|
(pguid->Data3 == 0) &&
|
||
|
(pguid->Data4[0] == 0) &&
|
||
|
(pguid->Data4[1] == 0) &&
|
||
|
(pguid->Data4[2] == 0) &&
|
||
|
(pguid->Data4[3] == 0) &&
|
||
|
(pguid->Data4[4] == 0) &&
|
||
|
(pguid->Data4[5] == 0) &&
|
||
|
(pguid->Data4[6] == 0) &&
|
||
|
(pguid->Data4[7] == 0) );
|
||
|
}
|
||
|
|
||
|
void FreePlatformInfo(PLATFORMINFO * &ppiOut)
|
||
|
{
|
||
|
if (ppiOut)
|
||
|
{
|
||
|
OLESAFE_DELETE(ppiOut->prgPlatform);
|
||
|
OLESAFE_DELETE(ppiOut->prgLocale);
|
||
|
OLESAFE_DELETE(ppiOut);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CopyPlatformInfo(PLATFORMINFO * &ppiOut, PLATFORMINFO * & ppiIn)
|
||
|
{
|
||
|
if (NULL == ppiIn)
|
||
|
{
|
||
|
ppiOut = NULL;
|
||
|
return S_OK;
|
||
|
}
|
||
|
UINT n;
|
||
|
ppiOut = (PLATFORMINFO *)OLEALLOC(sizeof(PLATFORMINFO));
|
||
|
if (!ppiOut)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(ppiOut, ppiIn, sizeof(PLATFORMINFO));
|
||
|
ppiOut->prgPlatform = NULL;
|
||
|
ppiOut->prgLocale = NULL;
|
||
|
n = ppiIn->cPlatforms;
|
||
|
if (n)
|
||
|
{
|
||
|
ppiOut->prgPlatform = (CSPLATFORM*) OLEALLOC(sizeof(CSPLATFORM) * n);
|
||
|
if (!ppiOut->prgPlatform)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
|
||
|
memcpy(ppiOut->prgPlatform, ppiIn->prgPlatform, sizeof(CSPLATFORM) * n);
|
||
|
}
|
||
|
n = ppiIn->cLocales;
|
||
|
if (n)
|
||
|
{
|
||
|
ppiOut->prgLocale = (LCID *) OLEALLOC(sizeof(LCID) * n);
|
||
|
if (!ppiOut->prgLocale)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(ppiOut->prgLocale, ppiIn->prgLocale, sizeof(LCID) * n);
|
||
|
}
|
||
|
return S_OK;
|
||
|
out_of_memory:
|
||
|
FreePlatformInfo(ppiOut);
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
void FreeActInfo(ACTIVATIONINFO * &paiOut)
|
||
|
{
|
||
|
if (paiOut)
|
||
|
{
|
||
|
if (paiOut->pClasses)
|
||
|
{
|
||
|
UINT n = paiOut->cClasses;
|
||
|
while (n--)
|
||
|
{
|
||
|
OLESAFE_DELETE(paiOut->pClasses[n].prgProgId);
|
||
|
}
|
||
|
OLESAFE_DELETE(paiOut->pClasses);
|
||
|
}
|
||
|
OLESAFE_DELETE(paiOut->prgInterfaceId);
|
||
|
OLESAFE_DELETE(paiOut->prgPriority);
|
||
|
if (paiOut->prgShellFileExt)
|
||
|
{
|
||
|
UINT n = paiOut->cShellFileExt;
|
||
|
while (n--)
|
||
|
{
|
||
|
OLESAFE_DELETE(paiOut->prgShellFileExt[n])
|
||
|
}
|
||
|
OLESAFE_DELETE(paiOut->prgShellFileExt);
|
||
|
}
|
||
|
OLESAFE_DELETE(paiOut->prgTlbId);
|
||
|
OLESAFE_DELETE(paiOut);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CopyActInfo(ACTIVATIONINFO * & paiOut, ACTIVATIONINFO * & paiIn)
|
||
|
{
|
||
|
if (NULL == paiIn)
|
||
|
{
|
||
|
paiOut = NULL;
|
||
|
return S_OK;
|
||
|
}
|
||
|
UINT n;
|
||
|
paiOut = (ACTIVATIONINFO *) OLEALLOC(sizeof(ACTIVATIONINFO));
|
||
|
if (!paiOut)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(paiOut, paiIn, sizeof(ACTIVATIONINFO));
|
||
|
paiOut->prgInterfaceId = NULL;
|
||
|
paiOut->prgPriority = NULL;
|
||
|
paiOut->prgShellFileExt = NULL;
|
||
|
paiOut->prgTlbId = NULL;
|
||
|
paiOut->pClasses = NULL;
|
||
|
n = paiIn->cClasses;
|
||
|
|
||
|
paiOut->bHasClasses = paiIn->bHasClasses;
|
||
|
|
||
|
if (n)
|
||
|
{
|
||
|
paiOut->pClasses = (CLASSDETAIL *) OLEALLOC(sizeof(CLASSDETAIL) * n);
|
||
|
if (!paiOut->pClasses)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(paiOut->pClasses, paiIn->pClasses, sizeof(CLASSDETAIL) * n);
|
||
|
while (n--)
|
||
|
{
|
||
|
UINT n2 = paiIn->pClasses[n].cProgId;
|
||
|
if (n2)
|
||
|
{
|
||
|
paiOut->pClasses[n].prgProgId = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR) * n2);
|
||
|
if (!paiOut->pClasses[n].prgProgId)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
while (n2--)
|
||
|
{
|
||
|
OLESAFE_COPYSTRING(paiOut->pClasses[n].prgProgId[n2], paiIn->pClasses[n].prgProgId[n2]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
n = paiIn->cShellFileExt;
|
||
|
if (n)
|
||
|
{
|
||
|
paiOut->prgPriority = (UINT *) OLEALLOC(sizeof(UINT) * n);
|
||
|
if (!paiOut->prgPriority)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(paiOut->prgPriority, paiIn->prgPriority, sizeof(UINT) * n);
|
||
|
paiOut->prgShellFileExt = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR) * n);
|
||
|
if (!paiOut->prgShellFileExt)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
while (n--)
|
||
|
{
|
||
|
OLESAFE_COPYSTRING(paiOut->prgShellFileExt[n], paiIn->prgShellFileExt[n]);
|
||
|
}
|
||
|
}
|
||
|
n = paiIn->cInterfaces;
|
||
|
if (n)
|
||
|
{
|
||
|
paiOut->prgInterfaceId = (IID *) OLEALLOC(sizeof(IID) * n);
|
||
|
if (!paiOut->prgInterfaceId)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(paiOut->prgInterfaceId, paiIn->prgInterfaceId, sizeof(IID) * n);
|
||
|
}
|
||
|
n = paiIn->cTypeLib;
|
||
|
if (n)
|
||
|
{
|
||
|
paiOut->prgTlbId = (GUID *) OLEALLOC(sizeof(GUID) * n);
|
||
|
if (!paiOut->prgTlbId)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(paiOut->prgTlbId, paiIn->prgTlbId, sizeof(GUID) * n);
|
||
|
}
|
||
|
return S_OK;
|
||
|
out_of_memory:
|
||
|
FreeActInfo(paiOut);
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
void FreeInstallInfo(INSTALLINFO * &piiOut)
|
||
|
{
|
||
|
if (piiOut)
|
||
|
{
|
||
|
if (piiOut->prgUpgradeInfoList)
|
||
|
{
|
||
|
UINT n = piiOut->cUpgrades;
|
||
|
while (n--)
|
||
|
{
|
||
|
OLESAFE_DELETE(piiOut->prgUpgradeInfoList[n].szClassStore);
|
||
|
}
|
||
|
OLESAFE_DELETE(piiOut->prgUpgradeInfoList);
|
||
|
}
|
||
|
OLESAFE_DELETE(piiOut->pClsid);
|
||
|
OLESAFE_DELETE(piiOut->pszScriptPath);
|
||
|
OLESAFE_DELETE(piiOut->pszSetupCommand);
|
||
|
OLESAFE_DELETE(piiOut->pszUrl);
|
||
|
OLESAFE_DELETE(piiOut);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CopyInstallInfo(INSTALLINFO * & piiOut, INSTALLINFO * & piiIn)
|
||
|
{
|
||
|
ULONG n;
|
||
|
if (NULL == piiIn)
|
||
|
{
|
||
|
piiOut = NULL;
|
||
|
return S_OK;
|
||
|
}
|
||
|
piiOut = (INSTALLINFO *) OLEALLOC(sizeof(INSTALLINFO));
|
||
|
if (!piiOut)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(piiOut, piiIn, sizeof(INSTALLINFO));
|
||
|
piiOut->pClsid = NULL;
|
||
|
piiOut->prgUpgradeInfoList = NULL;
|
||
|
piiOut->pszScriptPath = NULL;
|
||
|
piiOut->pszSetupCommand = NULL;
|
||
|
piiOut->pszUrl = NULL;
|
||
|
OLESAFE_COPYSTRING(piiOut->pszScriptPath, piiIn->pszScriptPath);
|
||
|
OLESAFE_COPYSTRING(piiOut->pszSetupCommand, piiIn->pszSetupCommand);
|
||
|
OLESAFE_COPYSTRING(piiOut->pszUrl, piiIn->pszUrl);
|
||
|
if (piiIn->pClsid)
|
||
|
{
|
||
|
piiOut->pClsid = (GUID *) OLEALLOC(sizeof(GUID));
|
||
|
if (!piiOut->pClsid)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(piiOut->pClsid, piiIn->pClsid, sizeof(GUID));
|
||
|
}
|
||
|
n = piiIn->cUpgrades;
|
||
|
if (n)
|
||
|
{
|
||
|
piiOut->prgUpgradeInfoList = (UPGRADEINFO *) OLEALLOC(sizeof(UPGRADEINFO) * n);
|
||
|
if (!piiOut->prgUpgradeInfoList)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(piiOut->prgUpgradeInfoList, piiIn->prgUpgradeInfoList, sizeof(UPGRADEINFO) * n);
|
||
|
while (n--)
|
||
|
{
|
||
|
OLESAFE_COPYSTRING(piiOut->prgUpgradeInfoList[n].szClassStore, piiIn->prgUpgradeInfoList[n].szClassStore);
|
||
|
}
|
||
|
}
|
||
|
return S_OK;
|
||
|
out_of_memory:
|
||
|
FreeInstallInfo(piiOut);
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
void InternalFreePackageDetail(PACKAGEDETAIL * &ppdOut)
|
||
|
{
|
||
|
if (ppdOut)
|
||
|
{
|
||
|
FreeActInfo(ppdOut->pActInfo);
|
||
|
FreePlatformInfo(ppdOut->pPlatformInfo);
|
||
|
FreeInstallInfo(ppdOut->pInstallInfo);
|
||
|
OLESAFE_DELETE(ppdOut->pszPackageName);
|
||
|
OLESAFE_DELETE(ppdOut->pszPublisher);
|
||
|
if (ppdOut->pszSourceList)
|
||
|
{
|
||
|
UINT n = ppdOut->cSources;
|
||
|
while (n--)
|
||
|
{
|
||
|
OLESAFE_DELETE(ppdOut->pszSourceList[n]);
|
||
|
}
|
||
|
OLESAFE_DELETE(ppdOut->pszSourceList);
|
||
|
}
|
||
|
OLESAFE_DELETE(ppdOut->rpCategory);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CopyPackageDetail(PACKAGEDETAIL * & ppdOut, PACKAGEDETAIL * & ppdIn)
|
||
|
{
|
||
|
ULONG n;
|
||
|
if (NULL == ppdIn)
|
||
|
{
|
||
|
ppdOut = NULL;
|
||
|
return S_OK;
|
||
|
}
|
||
|
ppdOut = new PACKAGEDETAIL;
|
||
|
if (!ppdOut)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(ppdOut, ppdIn, sizeof(PACKAGEDETAIL));
|
||
|
ppdOut->pActInfo = NULL;
|
||
|
ppdOut->pInstallInfo = NULL;
|
||
|
ppdOut->pPlatformInfo = NULL;
|
||
|
ppdOut->pszPackageName = NULL;
|
||
|
ppdOut->pszPublisher = NULL;
|
||
|
ppdOut->pszSourceList = NULL;
|
||
|
ppdOut->rpCategory = NULL;
|
||
|
OLESAFE_COPYSTRING(ppdOut->pszPackageName, ppdIn->pszPackageName);
|
||
|
n = ppdIn->cSources;
|
||
|
if (n)
|
||
|
{
|
||
|
ppdOut->pszSourceList = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR) * n);
|
||
|
if (!ppdOut->pszSourceList)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
while (n--)
|
||
|
{
|
||
|
OLESAFE_COPYSTRING(ppdOut->pszSourceList[n], ppdIn->pszSourceList[n]);
|
||
|
}
|
||
|
}
|
||
|
n = ppdIn->cCategories;
|
||
|
if (n)
|
||
|
{
|
||
|
ppdOut->rpCategory = (GUID *)OLEALLOC(sizeof(GUID) * n);
|
||
|
if (!ppdOut->rpCategory)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memcpy(ppdOut->rpCategory, ppdIn->rpCategory, sizeof(GUID) * n);
|
||
|
}
|
||
|
if FAILED(CopyActInfo(ppdOut->pActInfo, ppdIn->pActInfo))
|
||
|
goto out_of_memory;
|
||
|
if FAILED(CopyPlatformInfo(ppdOut->pPlatformInfo, ppdIn->pPlatformInfo))
|
||
|
goto out_of_memory;
|
||
|
if FAILED(CopyInstallInfo(ppdOut->pInstallInfo, ppdIn->pInstallInfo))
|
||
|
goto out_of_memory;
|
||
|
return S_OK;
|
||
|
out_of_memory:
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_GENERAL_ERROR, E_OUTOFMEMORY);
|
||
|
InternalFreePackageDetail(ppdOut);
|
||
|
if (ppdOut)
|
||
|
delete ppdOut;
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
void FreePackageDetail(PACKAGEDETAIL * & ppd)
|
||
|
{
|
||
|
if (ppd)
|
||
|
{
|
||
|
ReleasePackageDetail(ppd);
|
||
|
delete ppd;
|
||
|
ppd = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::GetUniquePackageName
|
||
|
//
|
||
|
// Synopsis: Returns a unique package name.
|
||
|
//
|
||
|
// Arguments: [sz] - [in] the name of the package
|
||
|
// [out] the new name, guaranteed unique on this cs
|
||
|
//
|
||
|
// History: 1-23-1998 stevebl Created
|
||
|
//
|
||
|
// Notes: First the input name is checked for uniqueness. If it is
|
||
|
// already unique it is returned unchanged. If it is not
|
||
|
// unique then a new name is formed by adding " (2)" to the end
|
||
|
// of the string, then " (3)" and " (4)" and so on until a
|
||
|
// unique name is found.
|
||
|
//
|
||
|
// If you don't want a number appended to the name, nHint must
|
||
|
// be 1.
|
||
|
//
|
||
|
// The value passed back in nHint will be the seed for the
|
||
|
// next try.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
void CScopePane::GetUniquePackageName(CString szRoot, CString &szOut, int &nHint)
|
||
|
{
|
||
|
map<MMC_COOKIE, CAppData>::iterator i;
|
||
|
set<CString> sNames;
|
||
|
int cch = szRoot.GetLength();
|
||
|
for (i=m_AppData.begin(); i != m_AppData.end(); i++)
|
||
|
{
|
||
|
// As an optimization, I'm only going to add names that might match
|
||
|
// this one to the set.
|
||
|
LPOLESTR szName = i->second.m_pDetails->pszPackageName;
|
||
|
if ((0 == wcsncmp(szRoot, szName, cch)) && (i->second.m_fVisible))
|
||
|
sNames.insert(szName);
|
||
|
}
|
||
|
szOut = szRoot;
|
||
|
if (nHint++ == 1) // try the first name
|
||
|
{
|
||
|
if (sNames.end() == sNames.find(szOut))
|
||
|
return;
|
||
|
}
|
||
|
// now check for a match
|
||
|
do
|
||
|
{
|
||
|
szOut.Format(L"%s (%i)", (LPCTSTR)szRoot, nHint++);
|
||
|
if (sNames.end() == sNames.find(szOut))
|
||
|
{
|
||
|
// we are unique
|
||
|
return;
|
||
|
}
|
||
|
// try a different name
|
||
|
} while (TRUE);
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePand::GetDeploymentType
|
||
|
//
|
||
|
// Synopsis:
|
||
|
//
|
||
|
// Arguments: [szPackagePath] -
|
||
|
// [lpFileTitle] -
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// History: 6-29-1998 stevebl Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::GetDeploymentType(PACKAGEDETAIL * ppd, BOOL & fShowPropertySheet)
|
||
|
{
|
||
|
INSTALLINFO * pii = ppd->pInstallInfo;
|
||
|
if (m_ToolDefaults.fUseWizard)
|
||
|
{
|
||
|
CDeployApp dlgDeployApp;
|
||
|
// Turn on theme'ing for the dialog by activating the theme context
|
||
|
CThemeContextActivator themer;
|
||
|
|
||
|
dlgDeployApp.m_fMachine = m_fMachine;
|
||
|
dlgDeployApp.m_fCrappyZaw = pii->PathType == SetupNamePath;
|
||
|
if (IDCANCEL == dlgDeployApp.DoModal())
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
switch (dlgDeployApp.m_iDeployment)
|
||
|
{
|
||
|
default:
|
||
|
case 0: //published
|
||
|
pii->dwActFlags = ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
||
|
break;
|
||
|
case 1: // assigned
|
||
|
pii->dwActFlags = ACTFLG_Assigned | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
||
|
break;
|
||
|
case 3: // disabled
|
||
|
pii->dwActFlags = 0;
|
||
|
break;
|
||
|
case 2: // custom
|
||
|
if (m_fMachine)
|
||
|
{
|
||
|
pii->dwActFlags = ACTFLG_Assigned | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pii->dwActFlags = ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
||
|
}
|
||
|
fShowPropertySheet = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
switch (m_ToolDefaults.NPBehavior)
|
||
|
{
|
||
|
default:
|
||
|
case NP_PUBLISHED:
|
||
|
if (!m_fMachine)
|
||
|
{
|
||
|
pii->dwActFlags = ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
||
|
break;
|
||
|
}
|
||
|
case NP_ASSIGNED:
|
||
|
if (pii->PathType != SetupNamePath)
|
||
|
{
|
||
|
pii->dwActFlags = ACTFLG_Assigned | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Crappy ZAW app.. force it to be published.
|
||
|
pii->dwActFlags = ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
||
|
}
|
||
|
break;
|
||
|
case NP_DISABLED:
|
||
|
pii->dwActFlags = 0;
|
||
|
break;
|
||
|
}
|
||
|
if (m_ToolDefaults.fCustomDeployment)
|
||
|
{
|
||
|
fShowPropertySheet = TRUE;
|
||
|
}
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::DeployPackage
|
||
|
//
|
||
|
// Synopsis:
|
||
|
//
|
||
|
// Arguments: [hr] -
|
||
|
// [hr] -
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// History: 6-29-1998 stevebl Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::DeployPackage(PACKAGEDETAIL * ppd, BOOL fShowPropertySheet)
|
||
|
{
|
||
|
CHourglass hourglass;
|
||
|
INSTALLINFO * pii = ppd->pInstallInfo;
|
||
|
HRESULT hr = S_OK;
|
||
|
hr = PrepareExtensions(*ppd);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
DWORD dwRememberFlags;
|
||
|
// put the entry in the class store
|
||
|
if (fShowPropertySheet)
|
||
|
{
|
||
|
dwRememberFlags = pii->dwActFlags;
|
||
|
pii->dwActFlags = 0; // disabled state
|
||
|
}
|
||
|
if (!m_pIClassAdmin)
|
||
|
{
|
||
|
hr = GetClassStore(TRUE);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_NOCLASSSTORE_ERROR, hr);
|
||
|
DebugMsg((DM_WARNING, TEXT("GetClassStore failed with 0x%x"), hr));
|
||
|
}
|
||
|
}
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = m_pIClassAdmin->AddPackage(ppd, &ppd->pInstallInfo->PackageGuid);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_ADDPACKAGE_ERROR, hr, ppd->pszPackageName);
|
||
|
DebugMsg((DM_WARNING, TEXT("AddPackage failed with 0x%x"), hr));
|
||
|
}
|
||
|
}
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
if (fShowPropertySheet)
|
||
|
{
|
||
|
pii->dwActFlags = dwRememberFlags; // restore state
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CString szCSPath;
|
||
|
hr = GetClassStoreName(szCSPath, FALSE);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("GetClassStoreName failed with 0x%x"), hr));
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CAppData data;
|
||
|
|
||
|
hr = CopyPackageDetail(data.m_pDetails, ppd);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("CopyPackageDetail failed with 0x%x"), hr));
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
data.InitializeExtraInfo();
|
||
|
|
||
|
m_lLastAllocated++;
|
||
|
|
||
|
// make sure that m_lLastAllocated hasn't already been used
|
||
|
while (m_AppData.end() != m_AppData.find(m_lLastAllocated))
|
||
|
{
|
||
|
m_lLastAllocated++;
|
||
|
}
|
||
|
|
||
|
data.m_fVisible = FALSE;
|
||
|
m_AppData[m_lLastAllocated] = data;
|
||
|
|
||
|
BOOL fAddOk = TRUE;
|
||
|
|
||
|
// The admin has said he wants to do a "custom" deployment.
|
||
|
if (fShowPropertySheet)
|
||
|
{
|
||
|
HRESULT hr; // errors that happen while setting up
|
||
|
// the property sheets are NOT to be
|
||
|
// reported as deployment errors.
|
||
|
|
||
|
MMC_COOKIE cookie = m_lLastAllocated;
|
||
|
|
||
|
PROPSHEETHEADER psh;
|
||
|
memset(&psh, 0, sizeof(psh));
|
||
|
psh.dwSize = sizeof(psh);
|
||
|
psh.dwFlags = PSH_NOAPPLYNOW | PSH_PROPTITLE;
|
||
|
psh.pszCaption = m_AppData[m_lLastAllocated].m_pDetails->pszPackageName;
|
||
|
int nPage = 0;
|
||
|
HPROPSHEETPAGE rgPages[6];
|
||
|
psh.phpage = rgPages;
|
||
|
|
||
|
//
|
||
|
// Create the Product property page
|
||
|
//
|
||
|
CProduct prpProduct;
|
||
|
prpProduct.m_fPreDeploy = TRUE;
|
||
|
prpProduct.m_pData = &m_AppData[m_lLastAllocated];
|
||
|
prpProduct.m_cookie = cookie;
|
||
|
prpProduct.m_pScopePane = this;
|
||
|
prpProduct.m_pAppData = &m_AppData;
|
||
|
prpProduct.m_pIGPEInformation = m_pIGPEInformation;
|
||
|
prpProduct.m_fMachine = m_fMachine;
|
||
|
prpProduct.m_fRSOP = m_fRSOP;
|
||
|
// no longer need to marshal this interface, just set it
|
||
|
|
||
|
prpProduct.m_pIClassAdmin = m_pIClassAdmin;
|
||
|
m_pIClassAdmin->AddRef();
|
||
|
|
||
|
rgPages[nPage++] = CreateThemedPropertySheetPage(&prpProduct.m_psp);
|
||
|
|
||
|
//
|
||
|
// Create the Depeployment property page
|
||
|
//
|
||
|
CDeploy prpDeploy;
|
||
|
prpDeploy.m_fPreDeploy = TRUE;
|
||
|
prpDeploy.m_pData = &m_AppData[m_lLastAllocated];
|
||
|
prpDeploy.m_cookie = cookie;
|
||
|
prpDeploy.m_fMachine = m_fMachine;
|
||
|
prpDeploy.m_fRSOP = m_fRSOP;
|
||
|
prpDeploy.m_pScopePane = this;
|
||
|
#if 0
|
||
|
prpDeploy.m_pIGPEInformation = m_pIGPEInformation;
|
||
|
#endif
|
||
|
|
||
|
// no longer need to marshal this interface, just set it
|
||
|
prpDeploy.m_pIClassAdmin = m_pIClassAdmin;
|
||
|
m_pIClassAdmin->AddRef();
|
||
|
|
||
|
rgPages[nPage++] = CreateThemedPropertySheetPage(&prpDeploy.m_psp);
|
||
|
|
||
|
CUpgradeList prpUpgradeList;
|
||
|
if (pii->PathType != SetupNamePath)
|
||
|
{
|
||
|
//
|
||
|
// Create the upgrades property page
|
||
|
//
|
||
|
prpUpgradeList.m_pData = &m_AppData[m_lLastAllocated];
|
||
|
prpUpgradeList.m_cookie = cookie;
|
||
|
prpUpgradeList.m_pScopePane = this;
|
||
|
prpUpgradeList.m_fPreDeploy = TRUE;
|
||
|
prpUpgradeList.m_fMachine = m_fMachine;
|
||
|
prpUpgradeList.m_fRSOP = m_fRSOP;
|
||
|
#if 0
|
||
|
prpUpgradeList.m_pIGPEInformation = m_pIGPEInformation;
|
||
|
#endif
|
||
|
|
||
|
// no longer need to marshal the interface, just set it
|
||
|
prpUpgradeList.m_pIClassAdmin = m_pIClassAdmin;
|
||
|
m_pIClassAdmin->AddRef();
|
||
|
|
||
|
rgPages[nPage++] = CreateThemedPropertySheetPage(&prpUpgradeList.m_psp);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// make sure we have an up-to-date categories list
|
||
|
//
|
||
|
ClearCategories();
|
||
|
hr = CsGetAppCategories(&m_CatList);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
// report it
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_GETCATEGORIES_ERROR, hr, NULL);
|
||
|
|
||
|
// Since failure only means the categories list will be
|
||
|
// empty, we'll proceed as if nothing happened.
|
||
|
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create the Category property page
|
||
|
//
|
||
|
CCategory prpCategory;
|
||
|
prpCategory.m_pData = &m_AppData[m_lLastAllocated];
|
||
|
prpCategory.m_cookie = cookie;
|
||
|
prpCategory.m_pCatList = &m_CatList;
|
||
|
prpCategory.m_fRSOP = m_fRSOP;
|
||
|
prpCategory.m_fPreDeploy = TRUE;
|
||
|
|
||
|
// no longer need to marshal this interface, just set it
|
||
|
prpCategory.m_pIClassAdmin = m_pIClassAdmin;
|
||
|
m_pIClassAdmin->AddRef();
|
||
|
|
||
|
rgPages[nPage++] = CreateThemedPropertySheetPage(&prpCategory.m_psp);
|
||
|
|
||
|
CXforms prpXforms;
|
||
|
if (pii->PathType != SetupNamePath)
|
||
|
{
|
||
|
//
|
||
|
// Create the Xforms property page
|
||
|
//
|
||
|
prpXforms.m_fPreDeploy = TRUE;
|
||
|
prpXforms.m_pData = &m_AppData[m_lLastAllocated];
|
||
|
prpXforms.m_cookie = cookie;
|
||
|
prpXforms.m_pScopePane = this;
|
||
|
|
||
|
// no longer need to marshal the interface, just set it
|
||
|
prpXforms.m_pIClassAdmin = m_pIClassAdmin;
|
||
|
m_pIClassAdmin->AddRef();
|
||
|
|
||
|
rgPages[nPage++] = CreateThemedPropertySheetPage(&prpXforms.m_psp);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create the security property page
|
||
|
//
|
||
|
|
||
|
CString szPath;
|
||
|
hr = GetPackageDSPath(szPath, m_AppData[m_lLastAllocated].m_pDetails->pszPackageName);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
LPSECURITYINFO pSI;
|
||
|
hr = DSCreateISecurityInfoObject(szPath,
|
||
|
NULL,
|
||
|
0,
|
||
|
&pSI,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
rgPages[nPage++] = CreateSecurityPage(pSI);
|
||
|
pSI->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("DSCreateISecurityInfoObject failed with 0x%x"), hr));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("GetPackageDSPath failed with 0x%x"), hr));
|
||
|
}
|
||
|
psh.nPages = nPage;
|
||
|
psh.hwndParent = m_hwndMainWindow;
|
||
|
|
||
|
if (IDOK != PropertySheet(&psh))
|
||
|
{
|
||
|
fAddOk = FALSE;
|
||
|
RemovePackage(cookie, FALSE, TRUE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Make sure that the package is deployed with the proper
|
||
|
// deployment type
|
||
|
hr = m_pIClassAdmin->ChangePackageProperties(m_AppData[m_lLastAllocated].m_pDetails->pszPackageName,
|
||
|
NULL,
|
||
|
&m_AppData[m_lLastAllocated].m_pDetails->pInstallInfo->dwActFlags,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (FAILED(m_pIGPEInformation->PolicyChanged(m_fMachine, TRUE, &guidExtension,
|
||
|
m_fMachine ? &guidMachSnapin
|
||
|
: &guidUserSnapin )))
|
||
|
{
|
||
|
ReportPolicyChangedError(m_hwndMainWindow);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fAddOk)
|
||
|
{
|
||
|
set <CResultPane *>::iterator i;
|
||
|
for (i = m_sResultPane.begin(); i != m_sResultPane.end(); i++)
|
||
|
{
|
||
|
RESULTDATAITEM resultItem;
|
||
|
memset(&resultItem, 0, sizeof(resultItem));
|
||
|
|
||
|
if ((*i)->_fVisible)
|
||
|
{
|
||
|
resultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
|
||
|
resultItem.str = MMC_CALLBACK;
|
||
|
resultItem.nImage = m_AppData[m_lLastAllocated].GetImageIndex(this);
|
||
|
resultItem.lParam = m_lLastAllocated;
|
||
|
hr = (*i)->m_pResult->InsertItem(&resultItem);
|
||
|
}
|
||
|
|
||
|
// The following code must be excecuted wheather the InsertItem
|
||
|
// call succeeds or not.
|
||
|
// There are legitimate cases when InsertItem will fail. For
|
||
|
// instance, if the scope pane is being shown, but not the
|
||
|
// result pane.
|
||
|
|
||
|
m_AppData[m_lLastAllocated].m_fVisible = TRUE;
|
||
|
m_AppData[m_lLastAllocated].m_itemID = resultItem.itemID;
|
||
|
InsertExtensionEntry(m_lLastAllocated, m_AppData[m_lLastAllocated]);
|
||
|
if (m_pFileExt)
|
||
|
{
|
||
|
m_pFileExt->SendMessage(WM_USER_REFRESH, 0, 0);
|
||
|
}
|
||
|
InsertUpgradeEntry(m_lLastAllocated, m_AppData[m_lLastAllocated]);
|
||
|
m_UpgradeIndex[GetUpgradeIndex(m_AppData[m_lLastAllocated].m_pDetails->pInstallInfo->PackageGuid)] = m_lLastAllocated;
|
||
|
// if this is an upgrade, set icons for upgraded apps to
|
||
|
// the proper icon and refresh any open property sheets
|
||
|
UINT n = m_AppData[m_lLastAllocated].m_pDetails->pInstallInfo->cUpgrades;
|
||
|
while (n--)
|
||
|
{
|
||
|
map<CString, MMC_COOKIE>::iterator i = m_UpgradeIndex.find(GetUpgradeIndex(m_AppData[m_lLastAllocated].m_pDetails->pInstallInfo->prgUpgradeInfoList[n].PackageGuid));
|
||
|
if (i != m_UpgradeIndex.end())
|
||
|
{
|
||
|
if (m_AppData[i->second].m_pUpgradeList)
|
||
|
{
|
||
|
m_AppData[i->second].m_pUpgradeList->SendMessage(WM_USER_REFRESH, 0, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if ((*i)->_fVisible)
|
||
|
{
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
(*i)->m_pResult->SetItem(&resultItem);
|
||
|
(*i)->m_pResult->Sort((*i)->m_nSortColumn, (*i)->m_dwSortOptions, -1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("InsertItem failed with 0x%x"), hr));
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::AddZAPPackage
|
||
|
//
|
||
|
// Synopsis:
|
||
|
//
|
||
|
// Arguments: [szPackagePath] -
|
||
|
// [lpFileTitle] -
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// History: 6-29-1998 stevebl Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::AddZAPPackage(LPCOLESTR szPackagePath, LPCOLESTR lpFileTitle)
|
||
|
{
|
||
|
CHourglass hourglass;
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
OLECHAR szBuffer[1024];
|
||
|
OLECHAR * sz = szBuffer;
|
||
|
CString szFriendlyName;
|
||
|
CString szUniqueFriendlyName;
|
||
|
int nHint = 1;
|
||
|
DWORD dw = GetPrivateProfileString(
|
||
|
L"Application",
|
||
|
L"FriendlyName",
|
||
|
NULL,
|
||
|
sz,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
szPackagePath);
|
||
|
if (0 == dw)
|
||
|
{
|
||
|
// either bogus FriendlyName or no setup command, both of which are fatal
|
||
|
goto bad_script;
|
||
|
}
|
||
|
szFriendlyName = sz; // save this for later
|
||
|
|
||
|
dw = GetPrivateProfileString(
|
||
|
L"Application",
|
||
|
L"SetupCommand",
|
||
|
NULL,
|
||
|
sz,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
szPackagePath);
|
||
|
if (0 == dw)
|
||
|
{
|
||
|
// either bogus file or no setup command, both of which are fatal
|
||
|
bad_script:
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADZAP_ERROR, HRESULT_FROM_WIN32(dw), lpFileTitle);
|
||
|
TCHAR szBuffer[256];
|
||
|
::LoadString(ghInstance, IDS_ADDFAILED_ZAP, szBuffer, 256);
|
||
|
m_pConsole->MessageBox(szBuffer,
|
||
|
lpFileTitle,
|
||
|
MB_OK | MB_ICONEXCLAMATION, NULL);
|
||
|
}
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
INSTALLINFO * pii = NULL;
|
||
|
PLATFORMINFO * ppi = NULL;
|
||
|
ACTIVATIONINFO * pai = NULL;
|
||
|
PACKAGEDETAIL *ppd = new PACKAGEDETAIL;
|
||
|
if (!ppd)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memset(ppd, 0, sizeof(PACKAGEDETAIL));
|
||
|
pii = (INSTALLINFO *) OLEALLOC(sizeof(INSTALLINFO));
|
||
|
ppd->pInstallInfo = pii;
|
||
|
if (!pii)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memset(pii, 0, sizeof(INSTALLINFO));
|
||
|
ppi = (PLATFORMINFO *) OLEALLOC(sizeof(PLATFORMINFO));
|
||
|
ppd->pPlatformInfo = ppi;
|
||
|
if (!ppi)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memset(ppi, 0, sizeof(PLATFORMINFO));
|
||
|
pai = (ACTIVATIONINFO *) OLEALLOC(sizeof(ACTIVATIONINFO));
|
||
|
ppd->pActInfo = pai;
|
||
|
if (!pai)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memset(pai, 0, sizeof(ACTIVATIONINFO));
|
||
|
|
||
|
pai->bHasClasses = ! m_ToolDefaults.fExtensionsOnly;
|
||
|
|
||
|
// Munge the setup path.
|
||
|
// surround the path in quotes to be sure that spaces are dealt
|
||
|
// with properly
|
||
|
CString szPath = L'"';
|
||
|
szPath += szPackagePath;
|
||
|
// strip off the package name
|
||
|
int ich = szPath.ReverseFind(L'\\');
|
||
|
// check for either slash symbol (just in case)
|
||
|
int ich2 = szPath.ReverseFind(L'/');
|
||
|
if (ich2 > ich)
|
||
|
{
|
||
|
ich = ich2;
|
||
|
}
|
||
|
if (ich >= 0)
|
||
|
{
|
||
|
szPath = szPath.Left(ich + 1); // keep the path separator
|
||
|
}
|
||
|
|
||
|
// merge it with the setup command string
|
||
|
BOOL fNeedQuote = TRUE;
|
||
|
if (sz[0] == L'"')
|
||
|
{
|
||
|
// remember that we had a leading quote (no need to insert a quote)
|
||
|
// and strip it off
|
||
|
sz++;
|
||
|
fNeedQuote = FALSE;
|
||
|
}
|
||
|
while (sz[0])
|
||
|
{
|
||
|
if (sz[0] == L'.' && sz[1] == L'.' && (sz[2] == L'/' || sz[2] == L'\\'))
|
||
|
{
|
||
|
// strip off the last path element
|
||
|
// First strip off the path separator (the one we kept previously)
|
||
|
szPath = szPath.Left(ich);
|
||
|
// now find the symbol
|
||
|
ich = szPath.ReverseFind(L'\\');
|
||
|
// check for either slash symbol (just in case)
|
||
|
ich2 = szPath.ReverseFind(L'/');
|
||
|
if (ich2 > ich)
|
||
|
{
|
||
|
ich = ich2;
|
||
|
}
|
||
|
if (ich >= 0)
|
||
|
{
|
||
|
szPath = szPath.Left(ich + 1); // keep the path separator
|
||
|
}
|
||
|
// skip the "..\"
|
||
|
sz += 3;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ((0 != sz[0] && L':' == sz[1])
|
||
|
||
|
||
|
((L'\\' == sz[0] || L'/' == sz[0]) && (L'\\' == sz[1] || L'/' == sz[1]))
|
||
|
||
|
||
|
(0 == wcsncmp(L"http:",sz,5)))
|
||
|
{
|
||
|
// hard path
|
||
|
// throw away szPath;
|
||
|
szPath = L"";
|
||
|
if (!fNeedQuote)
|
||
|
{
|
||
|
// make sure we don't drop that quote
|
||
|
szPath += L'"';
|
||
|
}
|
||
|
// and make sure we don't insert quotes where they're not wanted
|
||
|
fNeedQuote = FALSE;
|
||
|
}
|
||
|
// break the loop on anything other than "..\"
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fNeedQuote)
|
||
|
{
|
||
|
CString szTemp = sz;
|
||
|
// copy everything up to the first space
|
||
|
ich = szTemp.Find(L' ');
|
||
|
szPath += szTemp.Left(ich);
|
||
|
// then add a quote
|
||
|
szPath += L'"';
|
||
|
szPath += szTemp.Mid(ich);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
szPath += sz;
|
||
|
}
|
||
|
|
||
|
OLESAFE_COPYSTRING(pii->pszScriptPath, szPath);
|
||
|
|
||
|
sz = szBuffer;
|
||
|
dw = GetPrivateProfileString(
|
||
|
L"Application",
|
||
|
L"DisplayVersion",
|
||
|
NULL,
|
||
|
sz,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
szPackagePath);
|
||
|
if (dw)
|
||
|
{
|
||
|
// parse product version
|
||
|
CString sz = szBuffer;
|
||
|
sz.TrimLeft();
|
||
|
CString szTemp = sz.SpanIncluding(L"0123456789");
|
||
|
swscanf(szTemp, L"%u", &pii->dwVersionHi);
|
||
|
sz = sz.Mid(szTemp.GetLength());
|
||
|
szTemp = sz.SpanExcluding(L"0123456789");
|
||
|
sz = sz.Mid(szTemp.GetLength());
|
||
|
swscanf(sz, L"%u", &pii->dwVersionLo);
|
||
|
}
|
||
|
|
||
|
dw = GetPrivateProfileString(
|
||
|
L"Application",
|
||
|
L"Publisher",
|
||
|
NULL,
|
||
|
sz,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
szPackagePath);
|
||
|
if (dw)
|
||
|
{
|
||
|
OLESAFE_COPYSTRING(ppd->pszPublisher, sz);
|
||
|
}
|
||
|
|
||
|
dw = GetPrivateProfileString(
|
||
|
L"Application",
|
||
|
L"URL",
|
||
|
NULL,
|
||
|
sz,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
szPackagePath);
|
||
|
if (dw)
|
||
|
{
|
||
|
OLESAFE_COPYSTRING(pii->pszUrl, sz);
|
||
|
}
|
||
|
|
||
|
set<DWORD> sPlatforms;
|
||
|
dw = GetPrivateProfileString(
|
||
|
L"Application",
|
||
|
L"Architecture",
|
||
|
NULL,
|
||
|
sz,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
szPackagePath);
|
||
|
|
||
|
BOOL fValidPlatform;
|
||
|
|
||
|
fValidPlatform = FALSE;
|
||
|
|
||
|
if (dw)
|
||
|
{
|
||
|
CString szPlatforms = szBuffer;
|
||
|
CString szTemp;
|
||
|
while (szPlatforms.GetLength())
|
||
|
{
|
||
|
szTemp = szPlatforms.SpanExcluding(L",");
|
||
|
if (0 == szTemp.CompareNoCase(L"intel"))
|
||
|
{
|
||
|
sPlatforms.insert(PROCESSOR_ARCHITECTURE_INTEL);
|
||
|
fValidPlatform = TRUE;
|
||
|
}
|
||
|
else if (0 == szTemp.CompareNoCase(L"intel64"))
|
||
|
{
|
||
|
sPlatforms.insert(PROCESSOR_ARCHITECTURE_IA64);
|
||
|
fValidPlatform = TRUE;
|
||
|
}
|
||
|
szPlatforms = szPlatforms.Mid(szTemp.GetLength()+1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Ensure that if we saw any platforms, at least one of them
|
||
|
// was a supported platform
|
||
|
//
|
||
|
if ( dw && ! fValidPlatform )
|
||
|
{
|
||
|
TCHAR szBuffer[256];
|
||
|
::LoadString(ghInstance, IDS_ILLEGAL_PLATFORM, szBuffer, 256);
|
||
|
m_pConsole->MessageBox(szBuffer,
|
||
|
lpFileTitle,
|
||
|
MB_OK | MB_ICONEXCLAMATION, NULL);
|
||
|
|
||
|
delete ppd;
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
if (0 == sPlatforms.size())
|
||
|
{
|
||
|
// If the ZAP file doesn't specify an architecture
|
||
|
// then we'll treat is as an x86 package
|
||
|
sPlatforms.insert(PROCESSOR_ARCHITECTURE_INTEL);
|
||
|
DebugMsg((DL_VERBOSE, TEXT("No platform detected, assuming x86.")));
|
||
|
}
|
||
|
ppi->cPlatforms = sPlatforms.size();
|
||
|
ppi->prgPlatform = (CSPLATFORM *) OLEALLOC(sizeof(CSPLATFORM) * (ppi->cPlatforms));;
|
||
|
if (!ppi->prgPlatform)
|
||
|
{
|
||
|
ppi->cPlatforms = 0;
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
set<DWORD>::iterator iPlatform;
|
||
|
INT n = 0;
|
||
|
for (iPlatform = sPlatforms.begin(); iPlatform != sPlatforms.end(); iPlatform++, n++)
|
||
|
{
|
||
|
ppi->prgPlatform[n].dwPlatformId = VER_PLATFORM_WIN32_NT;
|
||
|
ppi->prgPlatform[n].dwVersionHi = 5;
|
||
|
ppi->prgPlatform[n].dwVersionLo = 0;
|
||
|
ppi->prgPlatform[n].dwProcessorArch = *iPlatform;
|
||
|
}
|
||
|
|
||
|
|
||
|
ppi->prgLocale = (LCID *) OLEALLOC(sizeof(LCID));
|
||
|
if (!ppi->prgLocale)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
ppi->cLocales = 1;
|
||
|
ppi->prgLocale[0] = 0; // if none is supplied we assume language neutral
|
||
|
|
||
|
dw = GetPrivateProfileString(
|
||
|
L"Application",
|
||
|
L"LCID",
|
||
|
NULL,
|
||
|
sz,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
szPackagePath);
|
||
|
if (dw)
|
||
|
{
|
||
|
swscanf(szBuffer, L"%i", &ppi->prgLocale[0]);
|
||
|
// we only deploy one LCID (the primary one)
|
||
|
}
|
||
|
|
||
|
// Get the list of extensions
|
||
|
dw = GetPrivateProfileString(
|
||
|
L"ext",
|
||
|
NULL,
|
||
|
NULL,
|
||
|
sz,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
szPackagePath);
|
||
|
if (dw)
|
||
|
{
|
||
|
vector<CString> v;
|
||
|
TCHAR szName[256];
|
||
|
while (sz < &szBuffer[dw])
|
||
|
{
|
||
|
while ('.' == sz[0])
|
||
|
sz++;
|
||
|
CString szExt = ".";
|
||
|
szExt += sz;
|
||
|
v.push_back(szExt);
|
||
|
sz += (wcslen(sz) + 1);
|
||
|
}
|
||
|
// build the new list
|
||
|
UINT n = v.size();
|
||
|
if (n > 0)
|
||
|
{
|
||
|
pai->prgShellFileExt = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR) * n);
|
||
|
if (!pai->prgShellFileExt)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
pai->prgPriority = (UINT *) OLEALLOC(sizeof(UINT) * n);
|
||
|
if (!pai->prgPriority)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
pai->cShellFileExt = n;
|
||
|
while (n--)
|
||
|
{
|
||
|
CString &sz = v[n];
|
||
|
sz.MakeLower();
|
||
|
OLESAFE_COPYSTRING(pai->prgShellFileExt[n], sz);
|
||
|
pai->prgPriority[n] = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get the list of CLSIDs
|
||
|
vector<CLASSDETAIL> v;
|
||
|
sz = szBuffer;
|
||
|
dw = GetPrivateProfileString(
|
||
|
L"CLSIDs",
|
||
|
NULL,
|
||
|
NULL,
|
||
|
sz,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
szPackagePath);
|
||
|
if (dw)
|
||
|
{
|
||
|
while (sz < &szBuffer[dw])
|
||
|
{
|
||
|
OLECHAR szType[256];
|
||
|
DWORD dwSubKey = GetPrivateProfileString(
|
||
|
L"CLSIDs",
|
||
|
sz,
|
||
|
NULL,
|
||
|
szType,
|
||
|
sizeof(szType) / sizeof(szType[0]),
|
||
|
szPackagePath);
|
||
|
CLASSDETAIL cd;
|
||
|
memset(&cd, 0, sizeof(CLASSDETAIL));
|
||
|
hr = CLSIDFromString(sz, &cd.Clsid);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CString szTypes = szType;
|
||
|
szTypes.MakeLower();
|
||
|
if (szTypes.Find(L"inprocserver32") >= 0)
|
||
|
{
|
||
|
cd.dwComClassContext |= CLSCTX_INPROC_SERVER;
|
||
|
}
|
||
|
if (szTypes.Find(L"localserver32") >= 0)
|
||
|
{
|
||
|
cd.dwComClassContext |= CLSCTX_LOCAL_SERVER;
|
||
|
}
|
||
|
if (szTypes.Find(L"inprochandler32") >= 0)
|
||
|
{
|
||
|
cd.dwComClassContext |= CLSCTX_INPROC_HANDLER;
|
||
|
}
|
||
|
v.push_back(cd);
|
||
|
}
|
||
|
sz += (wcslen(sz) + 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get the list of ProgIDs
|
||
|
sz = szBuffer;
|
||
|
dw = GetPrivateProfileString(
|
||
|
L"ProgIDs",
|
||
|
NULL,
|
||
|
NULL,
|
||
|
sz,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
szPackagePath);
|
||
|
if (dw)
|
||
|
{
|
||
|
while (sz < &szBuffer[dw])
|
||
|
{
|
||
|
OLECHAR szType[256];
|
||
|
DWORD dwSubKey = GetPrivateProfileString(
|
||
|
L"ProgIDs",
|
||
|
sz,
|
||
|
NULL,
|
||
|
szType,
|
||
|
sizeof(szType) / sizeof(szType[0]),
|
||
|
szPackagePath);
|
||
|
CLSID cid;
|
||
|
hr = CLSIDFromString(sz, &cid);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Match it to its CLASSDETAIL structure and insert it into the
|
||
|
// ProgID list.
|
||
|
// (fat and slow method)
|
||
|
vector<CLASSDETAIL>::iterator i;
|
||
|
for (i = v.begin(); i != v.end(); i++)
|
||
|
{
|
||
|
if (0 == memcmp(&i->Clsid, &cid, sizeof(CLSID)))
|
||
|
{
|
||
|
// found a match
|
||
|
// hereiam
|
||
|
vector <CString> vIds;
|
||
|
CString szAppIds = szType;
|
||
|
CString szTemp;
|
||
|
while (szAppIds.GetLength())
|
||
|
{
|
||
|
szTemp = szAppIds.SpanExcluding(L",");
|
||
|
szTemp.TrimLeft();
|
||
|
vIds.push_back(szTemp);
|
||
|
szAppIds = szAppIds.Mid(szTemp.GetLength()+1);
|
||
|
}
|
||
|
while (i->cProgId--)
|
||
|
{
|
||
|
OLESAFE_DELETE(i->prgProgId[i->cProgId]);
|
||
|
}
|
||
|
OLESAFE_DELETE(i->prgProgId);
|
||
|
DWORD cProgId = vIds.size();
|
||
|
LPOLESTR * prgProgId = (LPOLESTR *)
|
||
|
OLEALLOC(sizeof(LPOLESTR) * (cProgId));
|
||
|
if (!prgProgId)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
i->cProgId = cProgId;
|
||
|
while (cProgId--)
|
||
|
{
|
||
|
OLESAFE_COPYSTRING(prgProgId[cProgId], vIds[cProgId]);
|
||
|
}
|
||
|
i->prgProgId = prgProgId;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
sz += (wcslen(sz) + 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// create the list of CLASSDETAIL structures
|
||
|
{
|
||
|
UINT n = v.size();
|
||
|
if (n > 0)
|
||
|
{
|
||
|
pai->pClasses = (CLASSDETAIL *) OLEALLOC(sizeof(CLASSDETAIL) * n);
|
||
|
if (!pai->pClasses)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
pai->cClasses = n;
|
||
|
while (n--)
|
||
|
{
|
||
|
pai->pClasses[n] = v[n];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ppd->pszSourceList = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR));
|
||
|
if (!ppd->pszSourceList)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
ppd->cSources = 1;
|
||
|
OLESAFE_COPYSTRING(ppd->pszSourceList[0], szPackagePath);
|
||
|
|
||
|
GetUniquePackageName(szFriendlyName, szUniqueFriendlyName, nHint);
|
||
|
OLESAFE_COPYSTRING(ppd->pszPackageName, szUniqueFriendlyName);
|
||
|
|
||
|
// Popup UI
|
||
|
pii->PathType = SetupNamePath;
|
||
|
|
||
|
BOOL fShowPropertyPage = FALSE;
|
||
|
|
||
|
hr = GetDeploymentType(ppd, fShowPropertyPage);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CHourglass hourglass;
|
||
|
if (m_ToolDefaults.fZapOn64)
|
||
|
{
|
||
|
pii->dwActFlags |= ACTFLG_ExcludeX86OnIA64; // same as ACTFLG_ZAP_IncludeX86OfIA64
|
||
|
}
|
||
|
do
|
||
|
{
|
||
|
hr = DeployPackage(ppd, fShowPropertyPage);
|
||
|
if (hr == CS_E_OBJECT_ALREADY_EXISTS)
|
||
|
{
|
||
|
OLESAFE_DELETE(ppd->pszPackageName);
|
||
|
GetUniquePackageName(szFriendlyName, szUniqueFriendlyName, nHint);
|
||
|
OLESAFE_COPYSTRING(ppd->pszPackageName, szUniqueFriendlyName);
|
||
|
}
|
||
|
} while (hr == CS_E_OBJECT_ALREADY_EXISTS);
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr) && hr != E_FAIL) // don't report E_FAIL error
|
||
|
// because it's a benign error
|
||
|
// (probably a dialog cancellation)
|
||
|
{
|
||
|
// report the error in the event log
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_DEPLOYMENT_ERROR, hr, lpFileTitle);
|
||
|
|
||
|
// now try to come up with a meaningful message for the user
|
||
|
|
||
|
TCHAR szBuffer[256];
|
||
|
if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr)
|
||
|
{
|
||
|
// access permission failure
|
||
|
::LoadString(ghInstance, IDS_ADDFAILED_ACCESS_DENIED, szBuffer, 256);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
switch (hr)
|
||
|
{
|
||
|
// For these errors, we'll report the party line:
|
||
|
case CS_E_CLASS_NOTFOUND:
|
||
|
case CS_E_INVALID_VERSION:
|
||
|
case CS_E_NO_CLASSSTORE:
|
||
|
case CS_E_OBJECT_NOTFOUND:
|
||
|
case CS_E_OBJECT_ALREADY_EXISTS:
|
||
|
case CS_E_INVALID_PATH:
|
||
|
case CS_E_NETWORK_ERROR:
|
||
|
case CS_E_ADMIN_LIMIT_EXCEEDED:
|
||
|
case CS_E_SCHEMA_MISMATCH:
|
||
|
case CS_E_PACKAGE_NOTFOUND:
|
||
|
case CS_E_INTERNAL_ERROR:
|
||
|
{
|
||
|
DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL,
|
||
|
hr,
|
||
|
0,
|
||
|
szBuffer,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
NULL);
|
||
|
if (0 != dw)
|
||
|
{
|
||
|
// got a valid message string
|
||
|
break;
|
||
|
}
|
||
|
// otherwise fall through and give the generic message
|
||
|
}
|
||
|
// Either these CS errors don't apply or an admin
|
||
|
// wouldn't know what they mean:
|
||
|
case CS_E_NOT_DELETABLE:
|
||
|
default:
|
||
|
// generic class store problem
|
||
|
::LoadString(ghInstance, IDS_ADDFAILED_CSFAILURE, szBuffer, 256);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#if DBG
|
||
|
TCHAR szDebugBuffer[256];
|
||
|
DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL,
|
||
|
hr,
|
||
|
0,
|
||
|
szDebugBuffer,
|
||
|
sizeof(szDebugBuffer) / sizeof(szDebugBuffer[0]),
|
||
|
NULL);
|
||
|
if (0 == dw)
|
||
|
{
|
||
|
wsprintf(szDebugBuffer, TEXT("(HRESULT: 0x%lX)"), hr);
|
||
|
}
|
||
|
wcscat(szBuffer, szDebugBuffer);
|
||
|
#endif
|
||
|
m_pConsole->MessageBox(szBuffer,
|
||
|
lpFileTitle,
|
||
|
MB_OK | MB_ICONEXCLAMATION, NULL);
|
||
|
}
|
||
|
FreePackageDetail(ppd);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
out_of_memory:
|
||
|
if (ppd)
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_GENERAL_ERROR, E_OUTOFMEMORY);
|
||
|
InternalFreePackageDetail(ppd);
|
||
|
delete ppd;
|
||
|
}
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::AddMSIPackage
|
||
|
//
|
||
|
// Synopsis: Add's one or more packages to the class store and adds the
|
||
|
// appropriate entries to the result pane.
|
||
|
//
|
||
|
// Arguments: [szPackagePath] - Full path to the Darwin package.
|
||
|
// [lpFileTitle] - file title from the open file dialog (used
|
||
|
// for UI)
|
||
|
//
|
||
|
// Returns: S_OK - succeeded
|
||
|
// E_FAIL - benign failure (probably a cancellation or something)
|
||
|
// other - significant failure
|
||
|
//
|
||
|
// History: 2-03-1998 stevebl Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::AddMSIPackage(LPCOLESTR szPackagePath, LPCOLESTR lpFileTitle)
|
||
|
{
|
||
|
CHourglass hourglass;
|
||
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||
|
HRESULT hr = E_FAIL;
|
||
|
BOOL fPreparationDone = FALSE; // Used to identify if the routine has
|
||
|
// progressed passed the "prep" stage
|
||
|
// and is now in the deployment stage.
|
||
|
// Errors in the earlier part are most
|
||
|
// likely due to Darwin problems.
|
||
|
// Errors in teh latter part are most
|
||
|
// likely due to Class Store problems.
|
||
|
set<LCID> sLocales;
|
||
|
CUpgrades dlgUpgrade;
|
||
|
int nLocales;
|
||
|
set<LCID>::iterator iLocale;
|
||
|
PACKAGEDETAIL *ppd = NULL;
|
||
|
CString szFriendlyName;
|
||
|
CString szUniqueFriendlyName;
|
||
|
int nHint = 1;
|
||
|
|
||
|
ASSERT(m_pConsole);
|
||
|
{
|
||
|
BOOL fShowPropertySheet = FALSE;
|
||
|
GUID guid;
|
||
|
INSTALLINFO *pii = NULL;
|
||
|
PLATFORMINFO *ppi = NULL;
|
||
|
ACTIVATIONINFO *pai = NULL;
|
||
|
ppd = new PACKAGEDETAIL;
|
||
|
if (!ppd)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memset(ppd, 0, sizeof(PACKAGEDETAIL));
|
||
|
pii = (INSTALLINFO *) OLEALLOC(sizeof(INSTALLINFO));
|
||
|
if (!pii)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
memset(pii, 0, sizeof(INSTALLINFO));
|
||
|
ppi = (PLATFORMINFO *) OLEALLOC(sizeof(PLATFORMINFO));
|
||
|
ppd->pPlatformInfo = ppi;
|
||
|
if (!ppi)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
ppd->pInstallInfo = pii;
|
||
|
memset(ppi, 0, sizeof(PLATFORMINFO));
|
||
|
pai = (ACTIVATIONINFO *) OLEALLOC(sizeof(ACTIVATIONINFO));
|
||
|
ppd->pActInfo = pai;
|
||
|
if (!pai)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memset(pai, 0, sizeof(ACTIVATIONINFO));
|
||
|
|
||
|
pai->bHasClasses = ! m_ToolDefaults.fExtensionsOnly;
|
||
|
|
||
|
pii->PathType = DrwFilePath;
|
||
|
|
||
|
hr = GetDeploymentType(ppd, fShowPropertySheet);
|
||
|
CHourglass hourglass;
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
goto done;
|
||
|
}
|
||
|
if (!m_ToolDefaults.f32On64)
|
||
|
{
|
||
|
pii->dwActFlags |= ACTFLG_ExcludeX86OnIA64; // same as ACTFLG_ZAP_IncludeX86OfIA64
|
||
|
}
|
||
|
if (m_ToolDefaults.fUninstallOnPolicyRemoval)
|
||
|
{
|
||
|
pii->dwActFlags |= ACTFLG_UninstallOnPolicyRemoval;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pii->dwActFlags |= ACTFLG_OrphanOnPolicyRemoval;
|
||
|
}
|
||
|
if (m_fMachine)
|
||
|
{
|
||
|
pii->dwActFlags |= ACTFLG_ForceUpgrade;
|
||
|
}
|
||
|
pii->InstallUiLevel = m_ToolDefaults.UILevel;
|
||
|
|
||
|
// disable MSI ui
|
||
|
MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
|
||
|
|
||
|
// Use MsiSummaryInfoGetProperty to get platform and locale info.
|
||
|
{
|
||
|
MSIHANDLE hSummaryInfo;
|
||
|
UINT msiReturn = MsiGetSummaryInformation(0, szPackagePath, 0, &hSummaryInfo);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
TCHAR szBuffer[256];
|
||
|
DWORD dwSize = 256;
|
||
|
msiReturn = MsiSummaryInfoGetProperty(hSummaryInfo,
|
||
|
7, // PID_TEMPLATE
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
szBuffer,
|
||
|
&dwSize);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
// break out the locale and platform properties
|
||
|
CString szLocales = szBuffer;
|
||
|
CString szPlatforms = szLocales.SpanExcluding(L";");
|
||
|
szLocales = szLocales.Mid(szPlatforms.GetLength()+1);
|
||
|
CString szTemp;
|
||
|
set<DWORD> sPlatforms;
|
||
|
BOOL fValidPlatform;
|
||
|
BOOL fPlatformsSpecified;
|
||
|
|
||
|
fValidPlatform = FALSE;
|
||
|
|
||
|
fPlatformsSpecified = 0 != szPlatforms.GetLength();
|
||
|
|
||
|
while (szPlatforms.GetLength())
|
||
|
{
|
||
|
szTemp = szPlatforms.SpanExcluding(L",");
|
||
|
if (0 == szTemp.CompareNoCase(L"intel"))
|
||
|
{
|
||
|
sPlatforms.insert(PROCESSOR_ARCHITECTURE_INTEL);
|
||
|
fValidPlatform = TRUE;
|
||
|
}
|
||
|
else if (0 == szTemp.CompareNoCase(L"intel64"))
|
||
|
{
|
||
|
sPlatforms.insert(PROCESSOR_ARCHITECTURE_IA64);
|
||
|
fValidPlatform = TRUE;
|
||
|
}
|
||
|
szPlatforms = szPlatforms.Mid(szTemp.GetLength()+1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If platforms have been specified, at least one of them
|
||
|
// must be valid
|
||
|
//
|
||
|
if ( fPlatformsSpecified && ! fValidPlatform )
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32( ERROR_INSTALL_PLATFORM_UNSUPPORTED );
|
||
|
ppi->cPlatforms = 0;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
while (szLocales.GetLength())
|
||
|
{
|
||
|
szTemp = szLocales.SpanExcluding(L",");
|
||
|
LCID lcid;
|
||
|
swscanf(szTemp, L"%i", &lcid);
|
||
|
sLocales.insert(lcid);
|
||
|
szLocales = szLocales.Mid(szTemp.GetLength()+1);
|
||
|
}
|
||
|
if (0 == sPlatforms.size())
|
||
|
{
|
||
|
// If the MSI file doesn't specify an architecture
|
||
|
// then we'll mark it X86-allow on IA64.
|
||
|
sPlatforms.insert(PROCESSOR_ARCHITECTURE_INTEL);
|
||
|
pii->dwActFlags &= ~ACTFLG_ExcludeX86OnIA64;
|
||
|
DebugMsg((DL_VERBOSE, TEXT("No platform detected, setting to X86 - allow on IA64.")));
|
||
|
}
|
||
|
if (0 == sLocales.size())
|
||
|
{
|
||
|
// If the MSI file doesn't specify a locale then
|
||
|
// we'll just assume it's language neutral.
|
||
|
DebugMsg((DL_VERBOSE, TEXT("No locale detected, assuming neutral.")));
|
||
|
sLocales.insert(0);
|
||
|
}
|
||
|
ppi->cPlatforms = sPlatforms.size();
|
||
|
ppi->prgPlatform = (CSPLATFORM *) OLEALLOC(sizeof(CSPLATFORM) * (ppi->cPlatforms));;
|
||
|
if (!ppi->prgPlatform)
|
||
|
{
|
||
|
ppi->cPlatforms = 0;
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
set<DWORD>::iterator iPlatform;
|
||
|
INT n = 0;
|
||
|
for (iPlatform = sPlatforms.begin(); iPlatform != sPlatforms.end(); iPlatform++, n++)
|
||
|
{
|
||
|
ppi->prgPlatform[n].dwPlatformId = VER_PLATFORM_WIN32_NT;
|
||
|
ppi->prgPlatform[n].dwVersionHi = 5;
|
||
|
ppi->prgPlatform[n].dwVersionLo = 0;
|
||
|
ppi->prgPlatform[n].dwProcessorArch = *iPlatform;
|
||
|
}
|
||
|
}
|
||
|
MsiCloseHandle(hSummaryInfo);
|
||
|
}
|
||
|
if (ERROR_SUCCESS != msiReturn)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(msiReturn);
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADMSI_ERROR, hr, lpFileTitle);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
{
|
||
|
// Grovel through the database to get additional information
|
||
|
// that for some reason MSI won't give us any other way.
|
||
|
TCHAR szBuffer[256];
|
||
|
DWORD cch = 256;
|
||
|
UINT msiReturn = GetMsiProperty(szPackagePath, L"ProductVersion", szBuffer, &cch);
|
||
|
if (ERROR_SUCCESS != msiReturn)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(msiReturn);
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADMSI_ERROR, hr, lpFileTitle);
|
||
|
goto done;
|
||
|
}
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
// Parse Product Version
|
||
|
CString sz = szBuffer;
|
||
|
sz.TrimLeft();
|
||
|
CString szTemp = sz.SpanIncluding(L"0123456789");
|
||
|
swscanf(szTemp, L"%u", &pii->dwVersionHi);
|
||
|
sz = sz.Mid(szTemp.GetLength());
|
||
|
szTemp = sz.SpanExcluding(L"0123456789");
|
||
|
sz = sz.Mid(szTemp.GetLength());
|
||
|
swscanf(sz, L"%u", &pii->dwVersionLo);
|
||
|
}
|
||
|
cch = 256;
|
||
|
msiReturn = GetMsiProperty(szPackagePath, L"ProductCode", szBuffer, &cch);
|
||
|
if (ERROR_SUCCESS != msiReturn)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(msiReturn);
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADMSI_ERROR, hr, lpFileTitle);
|
||
|
goto done;
|
||
|
}
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
// Parse Product Code
|
||
|
CLSIDFromString(szBuffer, &pii->ProductCode);
|
||
|
}
|
||
|
cch = 256;
|
||
|
msiReturn = GetMsiProperty(szPackagePath, L"ARPHELPLINK", szBuffer, &cch);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
OLESAFE_COPYSTRING(pii->pszUrl, szBuffer);
|
||
|
}
|
||
|
cch = 256;
|
||
|
msiReturn = GetMsiProperty(szPackagePath, L"LIMITUI", szBuffer, &cch);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
pii->dwActFlags |= ACTFLG_MinimalInstallUI;
|
||
|
pii->InstallUiLevel = INSTALLUILEVEL_BASIC;
|
||
|
}
|
||
|
}
|
||
|
ppi->prgLocale = (LCID *) OLEALLOC(sizeof(LCID));
|
||
|
if (!ppi->prgLocale)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
ppi->cLocales = 1;
|
||
|
ppd->pszSourceList = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR));
|
||
|
if (!ppd->pszSourceList)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
ppd->cSources = 1;
|
||
|
OLESAFE_COPYSTRING(ppd->pszSourceList[0], szPackagePath);
|
||
|
|
||
|
if (S_OK == DetectUpgrades(szPackagePath, ppd, dlgUpgrade))
|
||
|
{
|
||
|
UINT n = dlgUpgrade.m_UpgradeList.size();
|
||
|
if (n)
|
||
|
{
|
||
|
pii->prgUpgradeInfoList = (UPGRADEINFO *) OLEALLOC(sizeof(UPGRADEINFO) * n);
|
||
|
if (!pii->prgUpgradeInfoList)
|
||
|
{
|
||
|
goto out_of_memory;
|
||
|
}
|
||
|
pii->cUpgrades = n;
|
||
|
map<CString, CUpgradeData>::iterator i = dlgUpgrade.m_UpgradeList.begin();
|
||
|
while (n--)
|
||
|
{
|
||
|
pii->prgUpgradeInfoList[n].Flag = i->second.m_flags;
|
||
|
OLESAFE_COPYSTRING(pii->prgUpgradeInfoList[n].szClassStore, i->second.m_szClassStore);
|
||
|
memcpy(&pii->prgUpgradeInfoList[n].PackageGuid, &i->second.m_PackageGuid, sizeof(GUID));
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Only one locale may be specified for this package
|
||
|
//
|
||
|
nLocales = 1;
|
||
|
iLocale = sLocales.begin();
|
||
|
|
||
|
{
|
||
|
ppi->prgLocale[0] = *iLocale;
|
||
|
|
||
|
// set the script path
|
||
|
hr = CoCreateGuid(&guid);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
goto done;
|
||
|
}
|
||
|
OLECHAR sz [256];
|
||
|
StringFromGUID2(guid, sz, 256);
|
||
|
CString szScriptPath = m_szGPT_Path;
|
||
|
szScriptPath += L"\\";
|
||
|
szScriptPath += sz;
|
||
|
szScriptPath += L".aas";
|
||
|
OLESAFE_DELETE(pii->pszScriptPath);
|
||
|
OLESAFE_COPYSTRING(pii->pszScriptPath, szScriptPath);
|
||
|
|
||
|
HWND hwnd;
|
||
|
m_pConsole->GetMainWindow(&hwnd);
|
||
|
hr = BuildScriptAndGetActInfo(*ppd, m_ToolDefaults.fExtensionsOnly);
|
||
|
|
||
|
// make sure the name is unique
|
||
|
szFriendlyName = ppd->pszPackageName;
|
||
|
GetUniquePackageName(szFriendlyName, szUniqueFriendlyName, nHint);
|
||
|
OLESAFE_DELETE(ppd->pszPackageName);
|
||
|
OLESAFE_COPYSTRING(ppd->pszPackageName, szUniqueFriendlyName);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
fPreparationDone = TRUE;
|
||
|
do
|
||
|
{
|
||
|
hr = DeployPackage(ppd, fShowPropertySheet);
|
||
|
if (hr == CS_E_OBJECT_ALREADY_EXISTS)
|
||
|
{
|
||
|
GetUniquePackageName(szFriendlyName, szUniqueFriendlyName, nHint);
|
||
|
OLESAFE_DELETE(ppd->pszPackageName);
|
||
|
OLESAFE_COPYSTRING(ppd->pszPackageName, szUniqueFriendlyName);
|
||
|
}
|
||
|
} while (hr == CS_E_OBJECT_ALREADY_EXISTS);
|
||
|
}
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
// clean up script file if deployment fails
|
||
|
DeleteFile(pii->pszScriptPath);
|
||
|
}
|
||
|
}
|
||
|
done:
|
||
|
if (FAILED(hr) && hr != E_FAIL) // don't report E_FAIL error
|
||
|
// because it's a benign error
|
||
|
// (probably a dialog cancellation)
|
||
|
{
|
||
|
// report the error in the event log
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_DEPLOYMENT_ERROR, hr, lpFileTitle);
|
||
|
|
||
|
TCHAR szBuffer[256];
|
||
|
if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr)
|
||
|
{
|
||
|
// access permission failure
|
||
|
::LoadString(ghInstance, IDS_ADDFAILED_ACCESS_DENIED, szBuffer, 256);
|
||
|
}
|
||
|
else if ( HRESULT_FROM_WIN32( ERROR_INSTALL_PLATFORM_UNSUPPORTED ) == hr )
|
||
|
{
|
||
|
::LoadString(ghInstance, IDS_ILLEGAL_PLATFORM, szBuffer, 256);
|
||
|
}
|
||
|
else if ( HRESULT_FROM_WIN32( CS_E_ADMIN_LIMIT_EXCEEDED ) == hr )
|
||
|
{
|
||
|
::LoadString(ghInstance, IDS_ADDFAILED_METADATA_OVERFLOW, szBuffer, 256);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (fPreparationDone)
|
||
|
{
|
||
|
switch (hr)
|
||
|
{
|
||
|
// For these errors, we'll report the party line:
|
||
|
case CS_E_CLASS_NOTFOUND:
|
||
|
case CS_E_INVALID_VERSION:
|
||
|
case CS_E_NO_CLASSSTORE:
|
||
|
case CS_E_OBJECT_NOTFOUND:
|
||
|
case CS_E_OBJECT_ALREADY_EXISTS:
|
||
|
case CS_E_INVALID_PATH:
|
||
|
case CS_E_NETWORK_ERROR:
|
||
|
case CS_E_SCHEMA_MISMATCH:
|
||
|
case CS_E_PACKAGE_NOTFOUND:
|
||
|
case CS_E_INTERNAL_ERROR:
|
||
|
{
|
||
|
DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL,
|
||
|
hr,
|
||
|
0,
|
||
|
szBuffer,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
NULL);
|
||
|
if (0 != dw)
|
||
|
{
|
||
|
// got a valid message string
|
||
|
break;
|
||
|
}
|
||
|
// otherwise fall through and give the generic message
|
||
|
}
|
||
|
// Either these CS errors don't apply or an admin
|
||
|
// wouldn't know what they mean:
|
||
|
case CS_E_NOT_DELETABLE:
|
||
|
default:
|
||
|
// generic class store problem
|
||
|
::LoadString(ghInstance, IDS_ADDFAILED_CSFAILURE, szBuffer, 256);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// probably some error with the package itself
|
||
|
::LoadString(ghInstance, IDS_ADDFAILED, szBuffer, 256);
|
||
|
}
|
||
|
}
|
||
|
#if DBG
|
||
|
TCHAR szDebugBuffer[256];
|
||
|
DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL,
|
||
|
hr,
|
||
|
0,
|
||
|
szDebugBuffer,
|
||
|
sizeof(szDebugBuffer) / sizeof(szDebugBuffer[0]),
|
||
|
NULL);
|
||
|
if (0 == dw)
|
||
|
{
|
||
|
wsprintf(szDebugBuffer, TEXT("(HRESULT: 0x%lX)"), hr);
|
||
|
}
|
||
|
wcscat(szBuffer, szDebugBuffer);
|
||
|
#endif
|
||
|
m_pConsole->MessageBox(szBuffer,
|
||
|
lpFileTitle,
|
||
|
MB_OK | MB_ICONEXCLAMATION, NULL);
|
||
|
}
|
||
|
InternalFreePackageDetail(ppd);
|
||
|
delete ppd;
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
out_of_memory:
|
||
|
if (ppd)
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_GENERAL_ERROR, E_OUTOFMEMORY);
|
||
|
InternalFreePackageDetail(ppd);
|
||
|
delete ppd;
|
||
|
}
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::DetectUpgrades
|
||
|
//
|
||
|
// Synopsis: This functions checks if any of the existing packages in the
|
||
|
// class store can be upgraded by a given package. If any such
|
||
|
// packages exist, then this function populates the m_UpgradeList
|
||
|
// member of the dlgUpgrade parameter passed to it. This function
|
||
|
// also adds the upgrade code GUID to the PACKAGEDETAIL structure
|
||
|
// passed to it.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// szPackagePath - the path of the given package
|
||
|
// ppd - pointer to the PACKAGEDETAIL structure of the
|
||
|
// given package
|
||
|
// dlgUpgrade - the dialog whose member m_UpgradeList needs to be
|
||
|
// populated
|
||
|
//
|
||
|
// Returns:
|
||
|
// S_OK the function succeeded in finding upgradeable packages
|
||
|
// S_FALSE the function did not encounter any errors, but no
|
||
|
// upgradeable packages were found
|
||
|
// other failure codes the function encountered errors
|
||
|
//
|
||
|
// History: 5/19/1998 RahulTh created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
HRESULT CScopePane::DetectUpgrades (LPCOLESTR szPackagePath, const PACKAGEDETAIL* ppd, CUpgrades& dlgUpgrade)
|
||
|
{
|
||
|
DWORD dwBufSize = 50;
|
||
|
TCHAR szUpgradeCode[50]; //the upgrade GUID
|
||
|
GUID guidUpgradeCode;
|
||
|
TCHAR szData[50];
|
||
|
DWORD dwOperator;
|
||
|
HRESULT hr;
|
||
|
HRESULT hres;
|
||
|
MSIHANDLE hDatabase;
|
||
|
UINT msiReturn;
|
||
|
map<MMC_COOKIE, CAppData>::iterator i;
|
||
|
INSTALLINFO* pii;
|
||
|
BOOL fUpgradeable;
|
||
|
LARGE_INTEGER verNew, verExisting;
|
||
|
CString szCSPath;
|
||
|
hr = GetClassStoreName(szCSPath, FALSE);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("GetClassStoreName failed with 0x%x"), hr));
|
||
|
}
|
||
|
|
||
|
msiReturn = GetMsiProperty(szPackagePath, TEXT("UpgradeCode"), szUpgradeCode, &dwBufSize);
|
||
|
if (ERROR_SUCCESS != msiReturn)
|
||
|
return HRESULT_FROM_WIN32(msiReturn); //no upgrade code was found
|
||
|
|
||
|
hr = CLSIDFromString(szUpgradeCode, &guidUpgradeCode);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
//insert the upgrade code GUID into the packagedetail structure.
|
||
|
memcpy((LPVOID)&(ppd->pInstallInfo->Mvipc), (LPVOID)&guidUpgradeCode, sizeof(GUID));
|
||
|
|
||
|
verNew.LowPart = ppd->pInstallInfo->dwVersionLo;
|
||
|
verNew.HighPart = ppd->pInstallInfo->dwVersionHi;
|
||
|
hr = S_FALSE; //this will get set to S_OK only if we find any upgradeable packages
|
||
|
|
||
|
msiReturn = MsiOpenDatabase (szPackagePath, MSIDBOPEN_READONLY, &hDatabase);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
CString szQuery;
|
||
|
szQuery.Format (TEXT("SELECT `UpgradeCode`, `Attributes`, `VersionMin`, `VersionMax`, `Language` FROM `Upgrade`"));
|
||
|
MSIHANDLE hView;
|
||
|
msiReturn = MsiDatabaseOpenView(hDatabase, szQuery, &hView);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
msiReturn = MsiViewExecute (hView, 0);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
MSIHANDLE hRecord;
|
||
|
//for each operator value returned by the query, if an operator is found that permits
|
||
|
//upgrades, iterate through the list of existing packages to see if any of those are
|
||
|
//upgradeable by the supplied package. If any such package is found, add it to the
|
||
|
//m_UpgradeList member of the upgrade dialog dlgUpgrade.
|
||
|
do
|
||
|
{
|
||
|
msiReturn = MsiViewFetch (hView, &hRecord);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
//reset dwBufSize since it is modified by MsiRecordString during every iteration
|
||
|
//of the loop.
|
||
|
dwBufSize = 50;
|
||
|
//get the upgrade code for this upgrade table entry
|
||
|
msiReturn = MsiRecordGetString (hRecord, 1, szData, &dwBufSize);
|
||
|
hres = CLSIDFromString (szData, &guidUpgradeCode);
|
||
|
if (FAILED(hres))
|
||
|
{
|
||
|
MsiCloseHandle(hRecord);
|
||
|
continue; //ignore this package and move on to the next
|
||
|
}
|
||
|
dwBufSize = 50; //must reset to reflect the correct buffer size
|
||
|
//get the operator for this upgrade table entry
|
||
|
msiReturn = MsiRecordGetString (hRecord, 2, szData, &dwBufSize);
|
||
|
swscanf(szData, TEXT("%d"), &dwOperator);
|
||
|
if (0 == (dwOperator & 0x002))
|
||
|
{
|
||
|
// we have a potential hit
|
||
|
LARGE_INTEGER verMin;
|
||
|
LARGE_INTEGER verMax;
|
||
|
|
||
|
// get min version
|
||
|
dwBufSize = 50; //must reset to reflect the correct buffer size
|
||
|
BOOL fMin = FALSE;
|
||
|
msiReturn = MsiRecordGetString (hRecord, 3, szData, &dwBufSize);
|
||
|
if (ERROR_SUCCESS == msiReturn && 0 != szData[0])
|
||
|
{
|
||
|
fMin = TRUE;
|
||
|
// Parse Product Version
|
||
|
CString sz = szData;
|
||
|
sz.TrimLeft();
|
||
|
CString szTemp = sz.SpanIncluding(L"0123456789");
|
||
|
swscanf(szTemp, L"%u", &verMin.HighPart);
|
||
|
sz = sz.Mid(szTemp.GetLength());
|
||
|
szTemp = sz.SpanExcluding(L"0123456789");
|
||
|
sz = sz.Mid(szTemp.GetLength());
|
||
|
swscanf(sz, L"%u", &verMin.LowPart);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(msiReturn), szPackagePath);
|
||
|
}
|
||
|
|
||
|
// get max version
|
||
|
dwBufSize = 50; //must reset to reflect the correct buffer size
|
||
|
BOOL fMax = FALSE;
|
||
|
msiReturn = MsiRecordGetString (hRecord, 4, szData, &dwBufSize);
|
||
|
if (ERROR_SUCCESS == msiReturn && 0 != szData[0])
|
||
|
{
|
||
|
fMax = TRUE;
|
||
|
// Parse Product Version
|
||
|
CString sz = szData;
|
||
|
sz.TrimLeft();
|
||
|
CString szTemp = sz.SpanIncluding(L"0123456789");
|
||
|
swscanf(szTemp, L"%u", &verMax.HighPart);
|
||
|
sz = sz.Mid(szTemp.GetLength());
|
||
|
szTemp = sz.SpanExcluding(L"0123456789");
|
||
|
sz = sz.Mid(szTemp.GetLength());
|
||
|
swscanf(sz, L"%u", &verMax.LowPart);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(msiReturn), szPackagePath);
|
||
|
}
|
||
|
// get lcid list
|
||
|
dwBufSize = 0; //must reset to reflect the correct buffer size
|
||
|
BOOL fLcids = FALSE;
|
||
|
set<LCID> sLCID;
|
||
|
msiReturn = MsiRecordGetString (hRecord, 5, szData, &dwBufSize);
|
||
|
if (ERROR_MORE_DATA == msiReturn)
|
||
|
{
|
||
|
dwBufSize++;
|
||
|
TCHAR * szLanguages = new TCHAR[dwBufSize];
|
||
|
if (szLanguages)
|
||
|
{
|
||
|
msiReturn = MsiRecordGetString (hRecord, 5, szLanguages, &dwBufSize);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
// build set of LCIDs
|
||
|
|
||
|
CString sz = szLanguages;
|
||
|
sz.TrimLeft();
|
||
|
while (!sz.IsEmpty())
|
||
|
{
|
||
|
fLcids = TRUE;
|
||
|
LCID lcid;
|
||
|
CString szTemp = sz.SpanIncluding(L"0123456789");
|
||
|
swscanf(szTemp, L"%u", &lcid);
|
||
|
sz = sz.Mid(szTemp.GetLength());
|
||
|
szTemp = sz.SpanExcluding(L"0123456789");
|
||
|
sz = sz.Mid(szTemp.GetLength());
|
||
|
sLCID.insert(lcid);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(msiReturn), szPackagePath);
|
||
|
}
|
||
|
delete [] szLanguages;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(msiReturn), szPackagePath);
|
||
|
}
|
||
|
|
||
|
//if an operator is found that that does not block installs and
|
||
|
//does not force uninstalling of existing apps, then search
|
||
|
//for any packages that can be upgraded
|
||
|
for (i = m_AppData.begin(); i != m_AppData.end(); i++)
|
||
|
{
|
||
|
//get the install info. for the app.
|
||
|
pii = (i->second.m_pDetails)->pInstallInfo;
|
||
|
//process this only if it has the same upgrade code
|
||
|
if ( (guidUpgradeCode == pii->Mvipc) && ! IsNullGUID(&guidUpgradeCode) )
|
||
|
{
|
||
|
//check if other conditions for the operator are satisfied.
|
||
|
verExisting.LowPart = pii->dwVersionLo;
|
||
|
verExisting.HighPart = pii->dwVersionHi;
|
||
|
|
||
|
// don't even bother to upgrade unless the
|
||
|
// new version is greater or equal to the
|
||
|
// old version
|
||
|
fUpgradeable = (verNew.QuadPart >= verExisting.QuadPart);
|
||
|
|
||
|
if (fMin && fUpgradeable)
|
||
|
{
|
||
|
// check minimum
|
||
|
if (0 != (dwOperator & 0x100))
|
||
|
{
|
||
|
// inclusive
|
||
|
fUpgradeable = verExisting.QuadPart >= verMin.QuadPart;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// exclusive
|
||
|
fUpgradeable = verExisting.QuadPart > verMin.QuadPart;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fMax && fUpgradeable)
|
||
|
{
|
||
|
// check maximum
|
||
|
if (0 != (dwOperator & 0x200))
|
||
|
{
|
||
|
// inclusive
|
||
|
fUpgradeable = verExisting.QuadPart <= verMax.QuadPart;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// exclusive
|
||
|
fUpgradeable = verExisting.QuadPart < verMax.QuadPart;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fLcids && fUpgradeable)
|
||
|
{
|
||
|
// check the lcid
|
||
|
BOOL fMatch = FALSE;
|
||
|
|
||
|
// look for a match
|
||
|
PLATFORMINFO * ppi = (i->second.m_pDetails)->pPlatformInfo;
|
||
|
|
||
|
UINT n = ppi->cLocales;
|
||
|
while ((n--) && !fMatch)
|
||
|
{
|
||
|
if (sLCID.end() != sLCID.find(ppi->prgLocale[n]))
|
||
|
{
|
||
|
fMatch = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// set the upgradeable flag
|
||
|
if (0 != (dwOperator & 0x400))
|
||
|
{
|
||
|
// exclusive
|
||
|
fUpgradeable = !fMatch;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// inclusive
|
||
|
fUpgradeable = fMatch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fUpgradeable) //the package in question can be upgraded
|
||
|
{
|
||
|
CUpgradeData data;
|
||
|
data.m_szClassStore = szCSPath;
|
||
|
memcpy(&data.m_PackageGuid, &pii->PackageGuid, sizeof(GUID));
|
||
|
data.m_flags = UPGFLG_NoUninstall | UPGFLG_Enforced;
|
||
|
dlgUpgrade.m_UpgradeList.insert(pair<const CString, CUpgradeData>(GetUpgradeIndex(data.m_PackageGuid), data));
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
MsiCloseHandle(hRecord);
|
||
|
}
|
||
|
} while (NULL != hRecord && ERROR_SUCCESS == msiReturn);
|
||
|
MsiViewClose (hView); //close the view to be on the safe side, though it is not absolutely essential
|
||
|
}
|
||
|
else
|
||
|
hr = HRESULT_FROM_WIN32(msiReturn);
|
||
|
|
||
|
MsiCloseHandle(hView);
|
||
|
}
|
||
|
else
|
||
|
hr = HRESULT_FROM_WIN32(msiReturn);
|
||
|
|
||
|
MsiCloseHandle (hDatabase);
|
||
|
}
|
||
|
else
|
||
|
hr = HRESULT_FROM_WIN32(msiReturn);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
if (msiReturn != ERROR_SUCCESS)
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADMSI_ERROR, hr, szPackagePath);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_GENERAL_ERROR, hr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::DisplayPropSheet
|
||
|
//
|
||
|
// Synopsis: a generic routine for showing the property sheet for a package
|
||
|
//
|
||
|
// Arguments: [szPackeName] - name of the package to show properties for
|
||
|
// [iPage] - index of the preferred page to display
|
||
|
//
|
||
|
// Returns: nothing
|
||
|
//
|
||
|
// History: 3-11-1998 stevebl Created
|
||
|
//
|
||
|
// Notes: The property sheet will be started on the preferred page
|
||
|
// only if it isn't already being displayed, in which case
|
||
|
// whatever page was being displayed will retain the focus.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
void CScopePane::DisplayPropSheet(CString szPackageName, int iPage)
|
||
|
{
|
||
|
map <MMC_COOKIE, CAppData>::iterator i = m_AppData.begin();
|
||
|
while (i != m_AppData.end())
|
||
|
{
|
||
|
if (0 == szPackageName.Compare(i->second.m_pDetails->pszPackageName))
|
||
|
{
|
||
|
IDataObject * pDataObject;
|
||
|
HRESULT hr = QueryDataObject(i->first, CCT_RESULT, &pDataObject);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
set <CResultPane *>::iterator i2;
|
||
|
for (i2 = m_sResultPane.begin(); i2 != m_sResultPane.end(); i2++)
|
||
|
{
|
||
|
hr = m_pIPropertySheetProvider->FindPropertySheet(i->first, (*i2), pDataObject);
|
||
|
if (S_FALSE == hr)
|
||
|
{
|
||
|
m_pIPropertySheetProvider->CreatePropertySheet(i->second.m_pDetails->pszPackageName, TRUE, i->first, pDataObject, 0);
|
||
|
m_pIPropertySheetProvider->AddPrimaryPages((*i2)->GetUnknown(), FALSE, NULL, FALSE);
|
||
|
m_pIPropertySheetProvider->AddExtensionPages();
|
||
|
m_pIPropertySheetProvider->Show(NULL, iPage);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::RemovePackage
|
||
|
//
|
||
|
// Synopsis: Removes a package from the class store and the result pane.
|
||
|
//
|
||
|
// Arguments: [pDataObject] - data object for this result pane item
|
||
|
// [fForceUninstall] - TRUE - force app to be uninstalled on
|
||
|
// client machines
|
||
|
// FALSE - orphan any installations
|
||
|
//
|
||
|
// Returns: S_OK - success
|
||
|
//
|
||
|
// History: 2-03-1998 stevebl Created
|
||
|
// 3-30-1998 stevebl adde fForceUninstall
|
||
|
//
|
||
|
// Notes: bAssigned is used
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::RemovePackage(MMC_COOKIE cookie, BOOL fForceUninstall, BOOL fRemoveNow)
|
||
|
{
|
||
|
BOOL fAssigned;
|
||
|
HRESULT hr = E_FAIL;
|
||
|
// put up an hourglass (this could take a while)
|
||
|
CHourglass hourglass;
|
||
|
CAppData & data = m_AppData[cookie];
|
||
|
CString szPackageName = data.m_pDetails->pszPackageName;
|
||
|
|
||
|
// We are now not removing script files here; instead the script
|
||
|
// file will be removed by the class store code when the package
|
||
|
// is actually removed from the DS.
|
||
|
#if 0
|
||
|
// only remove script files for packages that have script files
|
||
|
if (data.m_pDetails->pInstallInfo->PathType == DrwFilePath)
|
||
|
{
|
||
|
// We need to make sure it gets removed from
|
||
|
// the GPT before we delete it from the class store.
|
||
|
// check to see if it's an old style relative path
|
||
|
if (L'\\' != data.m_pDetails->pInstallInfo->pszScriptPath[0])
|
||
|
{
|
||
|
// find the last element in the path
|
||
|
int iBreak = m_szGPT_Path.ReverseFind(L'{');
|
||
|
CString sz = m_szGPT_Path.Left(iBreak-1);
|
||
|
sz += L"\\";
|
||
|
sz += data.m_pDetails->pInstallInfo->pszScriptPath;
|
||
|
DeleteFile(sz);
|
||
|
}
|
||
|
else
|
||
|
DeleteFile(data.m_pDetails->pInstallInfo->pszScriptPath);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (0 != (data.m_pDetails->pInstallInfo->dwActFlags & ACTFLG_Assigned))
|
||
|
{
|
||
|
fAssigned = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fAssigned = FALSE;
|
||
|
}
|
||
|
hr = m_pIClassAdmin->RemovePackage((LPOLESTR)((LPCOLESTR)(data.m_pDetails->pszPackageName)),
|
||
|
fRemoveNow ? 0 :
|
||
|
((fForceUninstall ? ACTFLG_Uninstall : ACTFLG_Orphan) |
|
||
|
(data.m_pDetails->pInstallInfo->dwActFlags &
|
||
|
(ACTFLG_ExcludeX86OnIA64 | ACTFLG_IgnoreLanguage))) );
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Notify clients of change
|
||
|
if (FAILED(m_pIGPEInformation->PolicyChanged(m_fMachine, TRUE, &guidExtension,
|
||
|
m_fMachine ? &guidMachSnapin
|
||
|
: &guidUserSnapin)))
|
||
|
{
|
||
|
ReportPolicyChangedError(m_hwndMainWindow);
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
if (data.m_fVisible)
|
||
|
{
|
||
|
set <CResultPane *>::iterator i;
|
||
|
for (i = m_sResultPane.begin(); i != m_sResultPane.end(); i++)
|
||
|
{
|
||
|
(*i)->m_pResult->DeleteItem(data.m_itemID, 0);
|
||
|
}
|
||
|
}
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CString szCSPath;
|
||
|
hr = GetClassStoreName(szCSPath, FALSE);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("GetClassStoreName failed with 0x%x"), hr));
|
||
|
}
|
||
|
|
||
|
// remove its entries in the extension table
|
||
|
RemoveExtensionEntry(cookie, data);
|
||
|
if (m_pFileExt)
|
||
|
{
|
||
|
m_pFileExt->SendMessage(WM_USER_REFRESH, 0, 0);
|
||
|
}
|
||
|
RemoveUpgradeEntry(cookie, data);
|
||
|
m_UpgradeIndex.erase(GetUpgradeIndex(data.m_pDetails->pInstallInfo->PackageGuid));
|
||
|
// If this thing upgraded other apps or had apps that were
|
||
|
// upgrading, make sure that they get the proper icons and any
|
||
|
// property sheets get updated.
|
||
|
UINT n = data.m_pDetails->pInstallInfo->cUpgrades;
|
||
|
while (n--)
|
||
|
{
|
||
|
map<CString, MMC_COOKIE>::iterator i = m_UpgradeIndex.find(GetUpgradeIndex(data.m_pDetails->pInstallInfo->prgUpgradeInfoList[n].PackageGuid));
|
||
|
if (i != m_UpgradeIndex.end())
|
||
|
{
|
||
|
RESULTDATAITEM rd;
|
||
|
memset(&rd, 0, sizeof(rd));
|
||
|
rd.mask = RDI_IMAGE;
|
||
|
rd.itemID = m_AppData[i->second].m_itemID;
|
||
|
rd.nImage = m_AppData[i->second].GetImageIndex(this);
|
||
|
set <CResultPane *>::iterator i2;
|
||
|
for (i2 = m_sResultPane.begin(); i2 != m_sResultPane.end(); i2++)
|
||
|
{
|
||
|
(*i2)->m_pResult->SetItem(&rd);
|
||
|
}
|
||
|
if (m_AppData[i->second].m_pUpgradeList)
|
||
|
{
|
||
|
m_AppData[i->second].m_pUpgradeList->SendMessage(WM_USER_REFRESH, 0, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
FreePackageDetail(data.m_pDetails);
|
||
|
m_AppData.erase(cookie);
|
||
|
set <CResultPane *>::iterator i;
|
||
|
for (i = m_sResultPane.begin(); i != m_sResultPane.end(); i++)
|
||
|
{
|
||
|
(*i)->m_pResult->Sort((*i)->m_nSortColumn, (*i)->m_dwSortOptions, -1);
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
// just force a refresh
|
||
|
Refresh();
|
||
|
}
|
||
|
#endif
|
||
|
else
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("RemovePackage failed with 0x%x"), hr));
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr) && hr != E_FAIL) // don't report E_FAIL error
|
||
|
{
|
||
|
LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_REMOVE_ERROR, hr, data.m_pDetails->pszPackageName);
|
||
|
TCHAR szBuffer[256];
|
||
|
if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr)
|
||
|
{
|
||
|
// access permission failure
|
||
|
::LoadString(ghInstance, IDS_DELFAILED_ACCESS_DENIED, szBuffer, 256);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
switch (hr)
|
||
|
{
|
||
|
// For these errors, we'll report the party line:
|
||
|
case CS_E_CLASS_NOTFOUND:
|
||
|
case CS_E_INVALID_VERSION:
|
||
|
case CS_E_NO_CLASSSTORE:
|
||
|
case CS_E_OBJECT_NOTFOUND:
|
||
|
case CS_E_OBJECT_ALREADY_EXISTS:
|
||
|
case CS_E_INVALID_PATH:
|
||
|
case CS_E_NETWORK_ERROR:
|
||
|
case CS_E_ADMIN_LIMIT_EXCEEDED:
|
||
|
case CS_E_SCHEMA_MISMATCH:
|
||
|
case CS_E_PACKAGE_NOTFOUND:
|
||
|
case CS_E_INTERNAL_ERROR:
|
||
|
case CS_E_NOT_DELETABLE:
|
||
|
{
|
||
|
DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL,
|
||
|
hr,
|
||
|
0,
|
||
|
szBuffer,
|
||
|
sizeof(szBuffer) / sizeof(szBuffer[0]),
|
||
|
NULL);
|
||
|
if (0 != dw)
|
||
|
{
|
||
|
// got a valid message string
|
||
|
break;
|
||
|
}
|
||
|
// otherwise fall through and give the generic message
|
||
|
}
|
||
|
// Either these CS errors don't apply or an admin
|
||
|
// wouldn't know what they mean:
|
||
|
default:
|
||
|
// generic class store problem
|
||
|
::LoadString(ghInstance, IDS_DELFAILED_CSFAILURE, szBuffer, 256);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#if DBG
|
||
|
TCHAR szDebugBuffer[256];
|
||
|
DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL,
|
||
|
hr,
|
||
|
0,
|
||
|
szDebugBuffer,
|
||
|
sizeof(szDebugBuffer) / sizeof(szDebugBuffer[0]),
|
||
|
NULL);
|
||
|
if (0 == dw)
|
||
|
{
|
||
|
wsprintf(szDebugBuffer, TEXT("(HRESULT: 0x%lX)"), hr);
|
||
|
}
|
||
|
wcscat(szBuffer, szDebugBuffer);
|
||
|
#endif
|
||
|
m_pConsole->MessageBox(szBuffer,
|
||
|
szPackageName,
|
||
|
MB_OK | MB_ICONEXCLAMATION, NULL);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::PopulateUpgradeLists
|
||
|
//
|
||
|
// Synopsis: Walks the list of apps, making sure that all the upgrade
|
||
|
// tables are complete.
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 2-02-1998 stevebl Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::PopulateUpgradeLists()
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
// For each app in the list, insert an entry in the upgrade tables of
|
||
|
// the apps it upgrades.
|
||
|
map <MMC_COOKIE, CAppData>::iterator iAppData;
|
||
|
for (iAppData=m_AppData.begin(); iAppData != m_AppData.end(); iAppData++)
|
||
|
{
|
||
|
hr = InsertUpgradeEntry(iAppData->first, iAppData->second);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::InsertUpgradeEntry
|
||
|
//
|
||
|
// Synopsis: For every app that this app upgrades, place an entry in its
|
||
|
// upgrades set so that it points back to this one.
|
||
|
//
|
||
|
// Arguments: [cookie] -
|
||
|
// [data] -
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 2-02-1998 stevebl Created
|
||
|
//
|
||
|
// Notes: Needs to be able to deal with scripts that might not be in
|
||
|
// this OU.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::InsertUpgradeEntry(MMC_COOKIE cookie, CAppData & data)
|
||
|
{
|
||
|
CString szCSPath;
|
||
|
HRESULT hr = GetClassStoreName(szCSPath, FALSE);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("GetClassStoreName failed with 0x%x"), hr));
|
||
|
}
|
||
|
UINT n = data.m_pDetails->pInstallInfo->cUpgrades;
|
||
|
while (n--)
|
||
|
{
|
||
|
map<CString, MMC_COOKIE>::iterator i = m_UpgradeIndex.find(GetUpgradeIndex(data.m_pDetails->pInstallInfo->prgUpgradeInfoList[n].PackageGuid));
|
||
|
if (m_UpgradeIndex.end() != i)
|
||
|
{
|
||
|
// Make sure the entry isn't already added:
|
||
|
INSTALLINFO * pii = m_AppData[i->second].m_pDetails->pInstallInfo;
|
||
|
BOOL fExists = FALSE;
|
||
|
UINT n = pii->cUpgrades;
|
||
|
while (n--)
|
||
|
{
|
||
|
if (0 == memcmp(&data.m_pDetails->pInstallInfo->PackageGuid, &pii->prgUpgradeInfoList[n].PackageGuid, sizeof(GUID)))
|
||
|
{
|
||
|
// it already exists
|
||
|
fExists = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!fExists)
|
||
|
{
|
||
|
// Add the entry to this app.
|
||
|
// We don't need to update the class store because it should
|
||
|
// maintain referential integrity for us. But we do need to
|
||
|
// update our own internal structures so we're consistent with
|
||
|
// what's in the class store.
|
||
|
UINT n = ++(pii->cUpgrades);
|
||
|
UPGRADEINFO * prgUpgradeInfoList = (UPGRADEINFO *)OLEALLOC(sizeof(UPGRADEINFO) * n);
|
||
|
if (!prgUpgradeInfoList)
|
||
|
{
|
||
|
// out of memory
|
||
|
// back out the change (this would be unfortunate but not fatal)
|
||
|
pii->cUpgrades--;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (n > 1)
|
||
|
{
|
||
|
memcpy(prgUpgradeInfoList, pii->prgUpgradeInfoList, sizeof(UPGRADEINFO) * (n-1));
|
||
|
OLESAFE_DELETE(pii->prgUpgradeInfoList);
|
||
|
}
|
||
|
OLESAFE_COPYSTRING(prgUpgradeInfoList[n-1].szClassStore, (LPOLESTR)((LPCWSTR)szCSPath));
|
||
|
memcpy(&prgUpgradeInfoList[n-1].PackageGuid, &data.m_pDetails->pInstallInfo->PackageGuid, sizeof(GUID));
|
||
|
prgUpgradeInfoList[n-1].Flag = UPGFLG_UpgradedBy;
|
||
|
pii->prgUpgradeInfoList = prgUpgradeInfoList;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::RemoveUpgradeEntry
|
||
|
//
|
||
|
// Synopsis: For every app that this app upgraded, remove the entry from
|
||
|
// its upgrades set.
|
||
|
//
|
||
|
// Arguments: [cookie] -
|
||
|
// [data] -
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 2-02-1998 stevebl Created
|
||
|
//
|
||
|
// Notes: Needs to be able to deal with scripts that might not be in
|
||
|
// this OU.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::RemoveUpgradeEntry(MMC_COOKIE cookie, CAppData & data)
|
||
|
{
|
||
|
UINT n = data.m_pDetails->pInstallInfo->cUpgrades;
|
||
|
while (n--)
|
||
|
{
|
||
|
map<CString, MMC_COOKIE>::iterator i = m_UpgradeIndex.find(GetUpgradeIndex(data.m_pDetails->pInstallInfo->prgUpgradeInfoList[n].PackageGuid));
|
||
|
if (m_UpgradeIndex.end() != i)
|
||
|
{
|
||
|
// Find which entry needs to be erased.
|
||
|
INSTALLINFO * pii = m_AppData[i->second].m_pDetails->pInstallInfo;
|
||
|
UINT n = pii->cUpgrades;
|
||
|
while (n--)
|
||
|
{
|
||
|
if (0 == memcmp(&data.m_pDetails->pInstallInfo->PackageGuid, &pii->prgUpgradeInfoList[n].PackageGuid, sizeof(GUID)))
|
||
|
{
|
||
|
// Now free this entry, copy the last entry over this
|
||
|
// one and decrement cUpgrades. Don't need to actually
|
||
|
// reallocate the array because it will be freed later.
|
||
|
OLESAFE_DELETE(pii->prgUpgradeInfoList[n].szClassStore);
|
||
|
if (--(pii->cUpgrades))
|
||
|
{
|
||
|
memcpy(&pii->prgUpgradeInfoList[n], &pii->prgUpgradeInfoList[pii->cUpgrades], sizeof(UPGRADEINFO));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OLESAFE_DELETE(pii->prgUpgradeInfoList);
|
||
|
}
|
||
|
// If we ever were to need to update the class store,
|
||
|
// this is where we would do it.
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::PopulateExtensions
|
||
|
//
|
||
|
// Synopsis: Builds the file extension table from the list of applications.
|
||
|
//
|
||
|
// Arguments: (none)
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 1-29-1998 stevebl Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::PopulateExtensions()
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
// first erase the old extension list
|
||
|
m_Extensions.erase(m_Extensions.begin(), m_Extensions.end());
|
||
|
// now add each app's extensions to the table
|
||
|
map <MMC_COOKIE, CAppData>::iterator iAppData;
|
||
|
for (iAppData=m_AppData.begin(); iAppData != m_AppData.end(); iAppData++)
|
||
|
{
|
||
|
hr = InsertExtensionEntry(iAppData->first, iAppData->second);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
if (m_pFileExt)
|
||
|
{
|
||
|
m_pFileExt->SendMessage(WM_USER_REFRESH, 0, 0);
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::InsertExtensionEntry
|
||
|
//
|
||
|
// Synopsis: Adds a single entry to the extension tables.
|
||
|
//
|
||
|
// Arguments: [cookie] -
|
||
|
// [data] -
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 1-29-1998 stevebl Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::InsertExtensionEntry(MMC_COOKIE cookie, CAppData & data)
|
||
|
{
|
||
|
UINT n = data.m_pDetails->pActInfo->cShellFileExt;
|
||
|
while (n--)
|
||
|
{
|
||
|
m_Extensions[data.m_pDetails->pActInfo->prgShellFileExt[n]].insert(cookie);
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::RemoveExtensionEntry
|
||
|
//
|
||
|
// Synopsis: Removes ane entry from the extension tables.
|
||
|
//
|
||
|
// Arguments: [cookie] -
|
||
|
// [data] -
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 1-29-1998 stevebl Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::RemoveExtensionEntry(MMC_COOKIE cookie, CAppData & data)
|
||
|
{
|
||
|
UINT n = data.m_pDetails->pActInfo->cShellFileExt;
|
||
|
while (n--)
|
||
|
{
|
||
|
m_Extensions[data.m_pDetails->pActInfo->prgShellFileExt[n]].erase(cookie);
|
||
|
if (m_Extensions[data.m_pDetails->pActInfo->prgShellFileExt[n]].empty())
|
||
|
{
|
||
|
m_Extensions.erase(data.m_pDetails->pActInfo->prgShellFileExt[n]);
|
||
|
}
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::PrepareExtensions
|
||
|
//
|
||
|
// Synopsis: Sets extension priorities so that this data can be inserted
|
||
|
// into the extension list with the proper priority.
|
||
|
//
|
||
|
// Arguments: [pd] -
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// History: 1-29-1998 stevebl Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::PrepareExtensions(PACKAGEDETAIL &pd)
|
||
|
{
|
||
|
UINT n = pd.pActInfo->cShellFileExt;
|
||
|
while (n--)
|
||
|
{
|
||
|
// For each extension that is going to be added, we need to assign
|
||
|
// it a priority that is one larger than the largest priority
|
||
|
// already added.
|
||
|
|
||
|
// NOTE: The odds of this number rolling over to 0 are so
|
||
|
// unlikely that it would be pointless to check for it. In any case
|
||
|
// the results of such a bug would be easy for the admin to remedy
|
||
|
// via the file extension priority dialog.
|
||
|
|
||
|
pd.pActInfo->prgPriority[n] = 0;
|
||
|
EXTLIST::iterator i;
|
||
|
CString sz = pd.pActInfo->prgShellFileExt[n];
|
||
|
for (i= m_Extensions[sz].begin(); i != m_Extensions[sz].end(); i++)
|
||
|
{
|
||
|
// look for the entry that matches this file extension
|
||
|
CAppData & data = m_AppData[*i];
|
||
|
UINT n2 = data.m_pDetails->pActInfo->cShellFileExt;
|
||
|
while (n2--)
|
||
|
{
|
||
|
if (0 == sz.CompareNoCase(data.m_pDetails->pActInfo->prgShellFileExt[n2]))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (data.m_pDetails->pActInfo->prgPriority[n2] >= pd.pActInfo->prgPriority[n])
|
||
|
{
|
||
|
pd.pActInfo->prgPriority[n] = data.m_pDetails->pActInfo->prgPriority[n2] + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::ChangePackageState
|
||
|
//
|
||
|
// Synopsis: Changes the state of a package and puts up advisory message
|
||
|
// boxes informing the admin about the effects of the change.
|
||
|
//
|
||
|
// Arguments: [data] - entry to change
|
||
|
// [dwNewState] - new state
|
||
|
//
|
||
|
// History: 2-03-1998 stevebl Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP CScopePane::ChangePackageState(CAppData &data, DWORD dwNewState, BOOL fShowUI)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// first detect what's changed
|
||
|
DWORD dwOldState = data.m_pDetails->pInstallInfo->dwActFlags;
|
||
|
DWORD dwChange = dwOldState ^ dwNewState;
|
||
|
|
||
|
if (dwChange)
|
||
|
{
|
||
|
// commit changes
|
||
|
hr = m_pIClassAdmin->ChangePackageProperties(data.m_pDetails->pszPackageName, NULL, &dwNewState, NULL, NULL, NULL, NULL);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (data.m_fVisible)
|
||
|
{
|
||
|
data.m_pDetails->pInstallInfo->dwActFlags = dwNewState;
|
||
|
RESULTDATAITEM rd;
|
||
|
memset(&rd, 0, sizeof(rd));
|
||
|
rd.mask = RDI_IMAGE;
|
||
|
rd.itemID = data.m_itemID;
|
||
|
rd.nImage = data.GetImageIndex(this);
|
||
|
set <CResultPane *>::iterator i;
|
||
|
for (i = m_sResultPane.begin(); i != m_sResultPane.end(); i++)
|
||
|
{
|
||
|
(*i)->m_pResult->SetItem(&rd);
|
||
|
(*i)->m_pResult->Sort((*i)->m_nSortColumn, (*i)->m_dwSortOptions, -1);
|
||
|
}
|
||
|
}
|
||
|
data.NotifyChange();
|
||
|
if (FAILED(m_pIGPEInformation->PolicyChanged(m_fMachine, TRUE, &guidExtension,
|
||
|
m_fMachine ? &guidMachSnapin
|
||
|
: &guidUserSnapin)))
|
||
|
{
|
||
|
ReportPolicyChangedError(m_hwndMainWindow);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("ChangePackageProperties failed with 0x%x"), hr));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CScopePane::ClearCategories()
|
||
|
{
|
||
|
while (m_CatList.cCategory)
|
||
|
{
|
||
|
m_CatList.cCategory--;
|
||
|
OLESAFE_DELETE(m_CatList.pCategoryInfo[m_CatList.cCategory].pszDescription);
|
||
|
}
|
||
|
OLESAFE_DELETE(m_CatList.pCategoryInfo);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetUpgradeIndex
|
||
|
//
|
||
|
// Synopsis: utility function that returns an upgrade index entry for a package.
|
||
|
//
|
||
|
// Arguments: [PackageID] - the PackageID guid
|
||
|
//
|
||
|
// Returns: S_OK on success
|
||
|
//
|
||
|
// History: 8-12-1998 stevebl Created
|
||
|
//
|
||
|
// Notes: Pretty simple really, the index is just the string form of
|
||
|
// the GUID.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
CString GetUpgradeIndex(GUID & PackageID)
|
||
|
{
|
||
|
CString szIndex;
|
||
|
WCHAR wsz[256];
|
||
|
StringFromGUID2(PackageID, wsz, 256);
|
||
|
return wsz;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CScopePane::GetPackageNameFromUpgradeInfo
|
||
|
//
|
||
|
// Synopsis: returns the name of a package given its PackageGuid and CSPath
|
||
|
//
|
||
|
// Arguments: [szPackageName] - [out] name of the package associated with
|
||
|
// this script
|
||
|
// [szScript] - [in] path to the script
|
||
|
//
|
||
|
// Returns: S_OK - found a package associated with this script
|
||
|
// (other) - failed to find a package (could be for any number
|
||
|
// of reasons)
|
||
|
//
|
||
|
// History: 4-07-1998 stevebl Created
|
||
|
//
|
||
|
// Notes: In cases where the package does not reside in this
|
||
|
// container, the package name will be returned as
|
||
|
// "Package Name (container name)"
|
||
|
// Note that this does not return the friendly name of the
|
||
|
// MSI package, it returns the name of the package entry in the
|
||
|
// class store. The two are not always the same.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CScopePane::GetPackageNameFromUpgradeInfo(CString & szPackageName, GUID &PackageGuid, LPOLESTR szCSPath)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
IEnumPackage * pIPE = NULL;
|
||
|
|
||
|
CString szMyCSPath;
|
||
|
hr = GetClassStoreName(szMyCSPath, FALSE);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("GetClassStoreName failed with 0x%x"), hr));
|
||
|
}
|
||
|
|
||
|
// see if it's in our container
|
||
|
if (0 == _wcsicmp((LPOLESTR)((LPCWSTR)szMyCSPath), szCSPath))
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
map <CString, MMC_COOKIE>::iterator i = m_UpgradeIndex.find(GetUpgradeIndex(PackageGuid));
|
||
|
if (m_UpgradeIndex.end() != i)
|
||
|
{
|
||
|
szPackageName = m_AppData[i->second].m_pDetails->pszPackageName;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
IClassAdmin * pIClassAdmin;
|
||
|
hr = CsGetClassStore((LPOLESTR)((LPCOLESTR)szCSPath), (LPVOID*)&pIClassAdmin);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
PACKAGEDETAIL pd;
|
||
|
hr = pIClassAdmin->GetPackageDetailsFromGuid(PackageGuid,
|
||
|
&pd);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (0 == (pd.pInstallInfo->dwActFlags & (ACTFLG_Orphan | ACTFLG_Uninstall)))
|
||
|
{
|
||
|
GUID guid;
|
||
|
LPOLESTR pszPolicyName;
|
||
|
|
||
|
hr = pIClassAdmin->GetGPOInfo(&guid,
|
||
|
&pszPolicyName);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
szPackageName = pd.pszPackageName;
|
||
|
szPackageName += L" (";
|
||
|
szPackageName += pszPolicyName;
|
||
|
szPackageName += L")";
|
||
|
OLESAFE_DELETE(pszPolicyName);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// this app is marked as deleted
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
ReleasePackageDetail(&pd);
|
||
|
}
|
||
|
pIClassAdmin->Release();
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetMsiProperty
|
||
|
//
|
||
|
// Synopsis: Retrieves a property from the Property table of an MSI package.
|
||
|
//
|
||
|
// Arguments: [szPackagePath] - path to the MSI package
|
||
|
// [szProperty] - property to fetch
|
||
|
// [szValue] - buffer to contain the value
|
||
|
// [puiSize] - size of the buffer
|
||
|
//
|
||
|
// Returns: ERROR_SUCCESS if successful
|
||
|
//
|
||
|
// History: 3-25-1998 stevebl Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
UINT GetMsiProperty(const TCHAR * szPackagePath, const TCHAR* szProperty, TCHAR* szValue, DWORD* puiSize)
|
||
|
{
|
||
|
MSIHANDLE hDatabase;
|
||
|
UINT msiReturn = MsiOpenDatabase(szPackagePath, MSIDBOPEN_READONLY, &hDatabase);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
CString szQuery;
|
||
|
szQuery.Format(L"SELECT `Value` FROM `Property` WHERE `Property`='%s'", szProperty);
|
||
|
MSIHANDLE hView;
|
||
|
msiReturn = MsiDatabaseOpenView(hDatabase, szQuery, &hView);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
msiReturn = MsiViewExecute(hView, 0);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
MSIHANDLE hRecord;
|
||
|
msiReturn = MsiViewFetch(hView, &hRecord);
|
||
|
if (ERROR_SUCCESS == msiReturn)
|
||
|
{
|
||
|
msiReturn = MsiRecordGetString(hRecord, 1, szValue, puiSize);
|
||
|
MsiCloseHandle(hRecord);
|
||
|
}
|
||
|
}
|
||
|
MsiCloseHandle(hView);
|
||
|
}
|
||
|
MsiCloseHandle(hDatabase);
|
||
|
}
|
||
|
return msiReturn;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetCapitalizedExt
|
||
|
//
|
||
|
// Synopsis: Given a file name, this function finds the filename
|
||
|
// extension, and returns it capitalized.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// [in] [szName] The file name
|
||
|
// [out][szExt] The capitalized extension
|
||
|
//
|
||
|
// Returns:
|
||
|
// TRUE - an extension was found
|
||
|
// FALSE - an extension could not be found
|
||
|
//
|
||
|
// History: 5/20/1998 RahulTh created
|
||
|
//
|
||
|
// Notes: If an extension cannot be found, then this function makes
|
||
|
// szExt an empty string
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
BOOL GetCapitalizedExt (LPCOLESTR szName, CString& szExt)
|
||
|
{
|
||
|
int slashpos, dotpos;
|
||
|
BOOL fRetVal = FALSE;
|
||
|
CString szFileName = szName;
|
||
|
|
||
|
szExt.Empty(); //to be on the safe side
|
||
|
|
||
|
//get the positions of the last . and last backslash
|
||
|
dotpos = szFileName.ReverseFind('.');
|
||
|
slashpos = szFileName.ReverseFind('\\');
|
||
|
|
||
|
//if the last dot occurs after the last slash, this file has an extension
|
||
|
if (dotpos > slashpos)
|
||
|
{
|
||
|
szExt = szFileName.Mid(dotpos + 1);
|
||
|
szExt.MakeUpper();
|
||
|
fRetVal = TRUE;
|
||
|
}
|
||
|
|
||
|
return fRetVal;
|
||
|
}
|