1101 lines
32 KiB
C++
1101 lines
32 KiB
C++
|
|
||
|
//
|
||
|
// Author: DebiM
|
||
|
// Date: January 97
|
||
|
// Revision History:
|
||
|
// Made Changes for reimplementation with adsldpc interfaces.
|
||
|
// UShaji, Mar 1998
|
||
|
//
|
||
|
// Class Access Implementation
|
||
|
//
|
||
|
// This source file contains implementations for IClassAccess
|
||
|
// interface on CAppContainer object.
|
||
|
//
|
||
|
// It uses ADs interfaces (over LDAP) to talk to an LDAP
|
||
|
// provider such as NTDS.
|
||
|
//
|
||
|
//---------------------------------------------------------------------
|
||
|
//
|
||
|
|
||
|
#include "cstore.hxx"
|
||
|
|
||
|
void
|
||
|
GetDefaultPlatform(CSPLATFORM *pPlatform);
|
||
|
|
||
|
HRESULT
|
||
|
UsnGet(ADS_ATTR_INFO Attr, CSUSN *pUsn);
|
||
|
|
||
|
extern CRITICAL_SECTION ClassStoreBindList;
|
||
|
|
||
|
long CompareUsn(CSUSN *pUsn1, CSUSN *pUsn2)
|
||
|
{
|
||
|
return CompareFileTime((FILETIME *)pUsn1, (FILETIME *)pUsn2);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// CAppContainer implementation
|
||
|
//
|
||
|
CAppContainer::CAppContainer()
|
||
|
|
||
|
{
|
||
|
m_fOpen = FALSE;
|
||
|
|
||
|
m_ADsContainer = NULL;
|
||
|
m_ADsPackageContainer = NULL;
|
||
|
|
||
|
m_szPackageName = NULL;
|
||
|
m_szClassName = NULL;
|
||
|
|
||
|
m_szPolicyName = NULL;
|
||
|
memset (&m_PolicyId, 0, sizeof(GUID));
|
||
|
|
||
|
m_KnownMissingClsidCache.sz = 0;
|
||
|
m_KnownMissingClsidCache.start = 0;
|
||
|
m_KnownMissingClsidCache.end = 0;
|
||
|
|
||
|
m_uRefs = 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// CAppContainer implementation
|
||
|
//
|
||
|
|
||
|
/*----------------------------------------------------------------------*
|
||
|
CAppContainer Constructor:
|
||
|
|
||
|
Parameters:
|
||
|
[in] szStoreName: The Class Store Name without 'ADCS:' moniker
|
||
|
[out] phr The Error Code returned.
|
||
|
|
||
|
Remarks: Tries to Bind to Base Class Store Container, get the version
|
||
|
Number and Packages and Classes container underneath.
|
||
|
|
||
|
Initializes members corresp. to their Names
|
||
|
|
||
|
Return Codes:
|
||
|
Success S_OK
|
||
|
Failures CS_E_INVALID_VERSION
|
||
|
Look at RemapErrorCodes
|
||
|
|
||
|
*----------------------------------------------------------------------*/
|
||
|
CAppContainer::CAppContainer(LPOLESTR szStoreName,
|
||
|
HRESULT *phr)
|
||
|
|
||
|
{
|
||
|
LPOLESTR pszName = NULL;
|
||
|
DWORD dwStoreVersion = 0;
|
||
|
LPOLESTR AttrNames[] = {STOREVERSION, POLICYDN, POLICYNAME};
|
||
|
DWORD posn = 0, cgot = 0;
|
||
|
ADS_SEARCHPREF_INFO SearchPrefs[2];
|
||
|
ADS_ATTR_INFO * pAttrsGot = NULL;
|
||
|
|
||
|
*phr = S_OK;
|
||
|
|
||
|
// set the search preference for the search Handle
|
||
|
|
||
|
SearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
|
||
|
SearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
|
||
|
SearchPrefs[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
|
||
|
|
||
|
SearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
|
||
|
SearchPrefs[1].vValue.dwType = ADSTYPE_INTEGER;
|
||
|
SearchPrefs[1].vValue.Integer = 20;
|
||
|
|
||
|
m_szPolicyName = NULL;
|
||
|
memset (&m_PolicyId, 0, sizeof(GUID));
|
||
|
|
||
|
m_fOpen = FALSE;
|
||
|
m_ADsContainer = NULL;
|
||
|
m_ADsPackageContainer = NULL;
|
||
|
m_szPackageName = NULL;
|
||
|
m_szClassName = NULL;
|
||
|
|
||
|
m_szPolicyName = NULL;
|
||
|
memset (&m_PolicyId, 0, sizeof(GUID));
|
||
|
|
||
|
m_KnownMissingClsidCache.sz = 0;
|
||
|
m_KnownMissingClsidCache.start = 0;
|
||
|
m_KnownMissingClsidCache.end = 0;
|
||
|
|
||
|
m_uRefs = 1;
|
||
|
//
|
||
|
// For every interface pointer, we create a separate session
|
||
|
//
|
||
|
|
||
|
|
||
|
// Bind to a Class Store Container Object
|
||
|
// Cache the interface pointer
|
||
|
//
|
||
|
wcscpy (m_szContainerName, szStoreName);
|
||
|
|
||
|
*phr = ADSIOpenDSObject(m_szContainerName, NULL, NULL, ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND,
|
||
|
&m_ADsContainer);
|
||
|
|
||
|
ERROR_ON_FAILURE(*phr);
|
||
|
//
|
||
|
// Check the Schema Version of this container
|
||
|
//
|
||
|
|
||
|
*phr = ADSIGetObjectAttributes(m_ADsContainer, AttrNames, 3, &pAttrsGot, &cgot);
|
||
|
|
||
|
if ((SUCCEEDED(*phr)) && (cgot))
|
||
|
{
|
||
|
|
||
|
posn = GetPropertyFromAttr(pAttrsGot, cgot, STOREVERSION);
|
||
|
dwStoreVersion = 0;
|
||
|
if (posn < cgot)
|
||
|
{
|
||
|
UnpackDWFrom(pAttrsGot[posn], &dwStoreVersion);
|
||
|
}
|
||
|
|
||
|
if (dwStoreVersion != SCHEMA_VERSION_NUMBER)
|
||
|
{
|
||
|
CSDBGPrint((L"CS: .. Wrong Version of Class Container:%s",
|
||
|
m_szContainerName));
|
||
|
*phr = CS_E_INVALID_VERSION;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (SUCCEEDED(*phr))
|
||
|
{
|
||
|
LPOLESTR szPolicyPath = NULL, szPolicyName = NULL;
|
||
|
|
||
|
posn = GetPropertyFromAttr(pAttrsGot, cgot, POLICYDN);
|
||
|
if (posn < cgot)
|
||
|
{
|
||
|
LPOLESTR szParentPath = NULL, szPolicyGuid = NULL;
|
||
|
|
||
|
UnpackStrFrom(pAttrsGot[posn], &szPolicyPath);
|
||
|
//
|
||
|
|
||
|
BuildADsParentPath(szPolicyPath, &szParentPath, &szPolicyGuid);
|
||
|
if (szParentPath)
|
||
|
FreeADsMem(szParentPath);
|
||
|
|
||
|
if (szPolicyGuid)
|
||
|
{
|
||
|
if (wcslen(szPolicyGuid) == 41)
|
||
|
{
|
||
|
// valid GUID
|
||
|
|
||
|
GUIDFromString(&szPolicyGuid[4], &m_PolicyId);
|
||
|
}
|
||
|
FreeADsMem(szPolicyGuid);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
posn = GetPropertyFromAttr(pAttrsGot, cgot, POLICYNAME);
|
||
|
if (posn < cgot)
|
||
|
{
|
||
|
UnpackStrAllocFrom(pAttrsGot[posn], &m_szPolicyName);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (SUCCEEDED(*phr))
|
||
|
{
|
||
|
CSDBGPrint((L"CS: .. Wrong Version of Class Container:%s",
|
||
|
m_szContainerName));
|
||
|
*phr = CS_E_INVALID_VERSION;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pAttrsGot)
|
||
|
FreeADsMem(pAttrsGot);
|
||
|
|
||
|
ERROR_ON_FAILURE(*phr);
|
||
|
|
||
|
m_szClassName = NULL;
|
||
|
|
||
|
BuildADsPathFromParent(m_szContainerName, CLASSCONTAINERNAME, &m_szClassName);
|
||
|
|
||
|
//
|
||
|
// Bind to the Package container Object
|
||
|
// Cache the interface pointer
|
||
|
//
|
||
|
|
||
|
BuildADsPathFromParent(m_szContainerName, PACKAGECONTAINERNAME, &m_szPackageName);
|
||
|
|
||
|
m_ADsPackageContainer = NULL;
|
||
|
|
||
|
|
||
|
*phr = ADSIOpenDSObject(m_szPackageName, NULL, NULL, ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND,
|
||
|
&m_ADsPackageContainer);
|
||
|
|
||
|
ERROR_ON_FAILURE(*phr);
|
||
|
|
||
|
CSDBGPrint((L"PackageContainer handle 0x%x", m_ADsPackageContainer));
|
||
|
|
||
|
|
||
|
*phr = ADSISetSearchPreference(m_ADsPackageContainer, SearchPrefs, 2);
|
||
|
ERROR_ON_FAILURE(*phr);
|
||
|
|
||
|
m_fOpen = TRUE;
|
||
|
CSDBGPrint((L".. Connected to Class Container:%s",
|
||
|
m_szContainerName));
|
||
|
|
||
|
m_uRefs = 1;
|
||
|
|
||
|
Error_Cleanup:
|
||
|
*phr = RemapErrorCode(*phr, m_szContainerName);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------------------*
|
||
|
CAppContainer Destructor:
|
||
|
|
||
|
|
||
|
Parameters:
|
||
|
None
|
||
|
|
||
|
Function:
|
||
|
Destroys CAppContainer object.
|
||
|
|
||
|
Remarks:
|
||
|
Frees all the members.
|
||
|
Return Codes
|
||
|
*----------------------------------------------------------------------*/
|
||
|
|
||
|
|
||
|
CAppContainer::~CAppContainer(void)
|
||
|
{
|
||
|
UINT i;
|
||
|
|
||
|
if (m_fOpen)
|
||
|
{
|
||
|
m_fOpen = FALSE;
|
||
|
}
|
||
|
|
||
|
if (m_szClassName)
|
||
|
{
|
||
|
FreeADsMem(m_szClassName);
|
||
|
}
|
||
|
|
||
|
|
||
|
if (m_ADsPackageContainer)
|
||
|
{
|
||
|
ADSICloseDSObject(m_ADsPackageContainer);
|
||
|
m_ADsPackageContainer = NULL;
|
||
|
FreeADsMem(m_szPackageName);
|
||
|
}
|
||
|
|
||
|
if (m_ADsContainer)
|
||
|
{
|
||
|
ADSICloseDSObject(m_ADsContainer);
|
||
|
m_ADsContainer = NULL;
|
||
|
}
|
||
|
|
||
|
if (m_szPolicyName)
|
||
|
{
|
||
|
CoTaskMemFree(m_szPolicyName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------*
|
||
|
GetPackageDetails:
|
||
|
|
||
|
Parameters:
|
||
|
[in] pszPackageName: The Package Name
|
||
|
[out] pPackageDetail Package Detail Structure.
|
||
|
|
||
|
Functionality:
|
||
|
Returns the PackageDetail corresp. to a Package given
|
||
|
by pszPackageName.
|
||
|
|
||
|
Remarks:
|
||
|
It constructs the Full Package Name
|
||
|
and calls GetPackageDetail
|
||
|
|
||
|
Return Codes:
|
||
|
Success S_OK
|
||
|
Failures Look at RemapErrorCodes
|
||
|
|
||
|
*----------------------------------------------------------------------*/
|
||
|
|
||
|
// This is not being called currently by anybody and hence is still using PackageId.
|
||
|
HRESULT CAppContainer::GetPackageDetails (
|
||
|
LPOLESTR pszPackageId,
|
||
|
PACKAGEDETAIL *pPackageDetail)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
HANDLE hADs = NULL;
|
||
|
WCHAR * szFullName = NULL, szRDN[_MAX_PATH];
|
||
|
ADS_ATTR_INFO * pAttr = NULL;
|
||
|
DWORD cgot;
|
||
|
|
||
|
if ((!pszPackageId) || IsBadStringPtr(pszPackageId, _MAX_PATH))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
wsprintf(szRDN, L"CN=%s", pszPackageId);
|
||
|
CSDBGPrint((L"GetPackageDetails called for %s", szRDN));
|
||
|
|
||
|
BuildADsPathFromParent(m_szPackageName, szRDN, &szFullName);
|
||
|
|
||
|
hr = ADSIOpenDSObject(szFullName, NULL, NULL, ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND, &hADs);
|
||
|
ERROR_ON_FAILURE(hr);
|
||
|
|
||
|
hr = GetPackageDetail (hADs, m_szClassName, pPackageDetail);
|
||
|
|
||
|
ADSICloseDSObject(hADs);
|
||
|
|
||
|
if (pAttr)
|
||
|
FreeADsMem(pAttr);
|
||
|
|
||
|
if (szFullName)
|
||
|
FreeADsMem(szFullName);
|
||
|
|
||
|
Error_Cleanup:
|
||
|
return RemapErrorCode(hr, m_szContainerName);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------------------*
|
||
|
EnumPackages
|
||
|
|
||
|
Parameters:
|
||
|
[in] pszPackageName Substring match for a package name
|
||
|
[in] pCategory Package Category.
|
||
|
[in] pLastUsn Last modification time.
|
||
|
[in] dwAppFlags Set the following bits to select specific ones
|
||
|
Published Only APPINFO_PUBLISHED
|
||
|
Assigned Only APPINFO_ASSIGNED
|
||
|
Msi Only APPINFO_MSI
|
||
|
Visible APPINFO_VISIBLE
|
||
|
Auto-Install APPINFO_AUTOINSTALL
|
||
|
|
||
|
All Locale APPINFO_ALLLOCALE
|
||
|
All Platform APPINFO_ALLPLATFORM
|
||
|
|
||
|
[out] ppIEnumPackage Returns the Enumerator
|
||
|
|
||
|
Functionality
|
||
|
Obtains an enumerator for packages in the app container.
|
||
|
|
||
|
Remarks:
|
||
|
|
||
|
*----------------------------------------------------------------------*/
|
||
|
|
||
|
HRESULT CAppContainer::EnumPackages (
|
||
|
LPOLESTR pszPackageName,
|
||
|
GUID *pCategory,
|
||
|
ULONGLONG *pLastUsn,
|
||
|
DWORD dwAppFlags, // AppType options
|
||
|
IEnumPackage **ppIEnumPackage
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
CEnumPackage *pEnum = NULL;
|
||
|
WCHAR szLdapFilter [2000];
|
||
|
UINT len = 0;
|
||
|
UINT fFilters = 0;
|
||
|
CSPLATFORM *pPlatform = NULL, Platform;
|
||
|
|
||
|
//
|
||
|
// Validate
|
||
|
//
|
||
|
|
||
|
if (!IsValidPtrOut(ppIEnumPackage, sizeof(IEnumPackage *)))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if (pszPackageName && (IsBadStringPtr(pszPackageName, _MAX_PATH)))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if (pCategory && !IsValidReadPtrIn(pCategory, sizeof(GUID)))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*ppIEnumPackage = NULL;
|
||
|
|
||
|
//pEnum = new CEnumPackage;
|
||
|
pEnum = new CEnumPackage(m_PolicyId, m_szPolicyName);
|
||
|
if(NULL == pEnum)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
//
|
||
|
// Create a LDAP Search Filter based on input params
|
||
|
//
|
||
|
|
||
|
// Count Filters
|
||
|
if (pszPackageName && (*pszPackageName))
|
||
|
fFilters++;
|
||
|
if ((pLastUsn) && (*pLastUsn))
|
||
|
fFilters++;
|
||
|
if (pCategory)
|
||
|
fFilters++;
|
||
|
if (dwAppFlags & APPINFO_ASSIGNED)
|
||
|
fFilters++;
|
||
|
|
||
|
if (fFilters == 0)
|
||
|
{
|
||
|
// No Conditionals
|
||
|
wsprintf (szLdapFilter,
|
||
|
L"(%s=%s)", OBJECTCLASS, CLASS_CS_PACKAGE);
|
||
|
|
||
|
len = wcslen (szLdapFilter);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
if (fFilters > 1)
|
||
|
{
|
||
|
wsprintf (szLdapFilter, L"(&");
|
||
|
len = wcslen (szLdapFilter);
|
||
|
}
|
||
|
else
|
||
|
len = 0;
|
||
|
|
||
|
if (pszPackageName)
|
||
|
{
|
||
|
//
|
||
|
// Validate
|
||
|
//
|
||
|
|
||
|
if (IsBadStringPtr(pszPackageName, _MAX_PATH))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if (*pszPackageName)
|
||
|
{
|
||
|
wsprintf (&szLdapFilter[len],
|
||
|
L"(%s=*%s*)",
|
||
|
PACKAGENAME,
|
||
|
pszPackageName);
|
||
|
|
||
|
len = wcslen (szLdapFilter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((pLastUsn) && (*pLastUsn))
|
||
|
{
|
||
|
//
|
||
|
// Validate
|
||
|
//
|
||
|
|
||
|
SYSTEMTIME SystemTime;
|
||
|
|
||
|
if (!IsValidReadPtrIn(pLastUsn, sizeof(ULONGLONG)))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
FileTimeToSystemTime(
|
||
|
(CONST FILETIME *) pLastUsn,
|
||
|
&SystemTime);
|
||
|
|
||
|
wsprintf (&szLdapFilter[len],
|
||
|
L"(%s>=%04d%02d%02d%02d%02d%02d)",
|
||
|
PKGUSN,
|
||
|
SystemTime.wYear,
|
||
|
SystemTime.wMonth,
|
||
|
SystemTime.wDay,
|
||
|
SystemTime.wHour,
|
||
|
SystemTime.wMinute,
|
||
|
SystemTime.wSecond+1);
|
||
|
|
||
|
len = wcslen (szLdapFilter);
|
||
|
}
|
||
|
|
||
|
if (pCategory)
|
||
|
{
|
||
|
//
|
||
|
// Validate
|
||
|
//
|
||
|
STRINGGUID szCat;
|
||
|
|
||
|
if (!IsValidReadPtrIn(pCategory, sizeof(GUID)))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
StringFromGUID (*pCategory, szCat);
|
||
|
wsprintf (&szLdapFilter[len],
|
||
|
L"(%s=%s)",
|
||
|
PKGCATEGORYLIST,
|
||
|
szCat);
|
||
|
|
||
|
len = wcslen (szLdapFilter);
|
||
|
}
|
||
|
|
||
|
if (dwAppFlags & APPINFO_ASSIGNED)
|
||
|
// if only Assigned Packages are in demand
|
||
|
{
|
||
|
wsprintf (&szLdapFilter[len],
|
||
|
L"(%s>=%d)",
|
||
|
PACKAGEFLAGS,
|
||
|
(ACTFLG_Assigned));
|
||
|
|
||
|
len = wcslen (szLdapFilter);
|
||
|
}
|
||
|
|
||
|
if (fFilters > 1)
|
||
|
{
|
||
|
szLdapFilter[len] = L')';
|
||
|
szLdapFilter[++len] = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
CSDBGPrint((L"EnumPackage Called:: Search filter created is %s, Appflags = %d", szLdapFilter, dwAppFlags));
|
||
|
|
||
|
//
|
||
|
// Check all local/platform flags
|
||
|
//
|
||
|
|
||
|
if (dwAppFlags & APPINFO_ALLPLATFORM)
|
||
|
{
|
||
|
pPlatform = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPlatform = &Platform;
|
||
|
GetDefaultPlatform(pPlatform);
|
||
|
}
|
||
|
|
||
|
if (pLastUsn)
|
||
|
{
|
||
|
//
|
||
|
// Find the current store USN and return it
|
||
|
//
|
||
|
LPOLESTR AttrName = STOREUSN;
|
||
|
ADS_ATTR_INFO * pAttr = NULL;
|
||
|
DWORD cgot = 0;
|
||
|
|
||
|
hr = ADSIGetObjectAttributes(m_ADsContainer, &AttrName, 1, &pAttr, &cgot);
|
||
|
if ((SUCCEEDED(hr)) && (cgot))
|
||
|
{
|
||
|
UsnGet(*pAttr, (CSUSN *)pLastUsn);
|
||
|
if (pAttr)
|
||
|
FreeADsMem(pAttr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr = pEnum->Initialize(m_szPackageName, szLdapFilter, dwAppFlags, pPlatform);
|
||
|
ERROR_ON_FAILURE(hr);
|
||
|
|
||
|
hr = pEnum->QueryInterface(IID_IEnumPackage,(void**) ppIEnumPackage);
|
||
|
ERROR_ON_FAILURE(hr);
|
||
|
|
||
|
return S_OK;
|
||
|
|
||
|
Error_Cleanup:
|
||
|
if (pEnum)
|
||
|
delete pEnum;
|
||
|
*ppIEnumPackage = NULL;
|
||
|
|
||
|
return RemapErrorCode(hr, m_szContainerName);
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD GetTime()
|
||
|
{
|
||
|
return (GetTickCount()/1000);
|
||
|
}
|
||
|
|
||
|
BOOL IsExpired(DWORD dwCurrentTime, DWORD Time, DWORD Tolerance)
|
||
|
{
|
||
|
if (Time > dwCurrentTime)
|
||
|
return TRUE;
|
||
|
|
||
|
if ((Time+Tolerance) < dwCurrentTime)
|
||
|
return TRUE;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// choosing the best package that can be returned after returning from the DS
|
||
|
DWORD CAppContainer::ChooseBestFit(PACKAGEDISPINFO *PackageInfo, UINT *rgPriority, DWORD cRowsFetched)
|
||
|
{
|
||
|
DWORD i=0, k=0, j = 0, temp = 0;
|
||
|
DWORD index[10];
|
||
|
|
||
|
CSDBGPrint((L"Entering ChooseBestFit"));
|
||
|
|
||
|
// initialising the indices
|
||
|
for (i = 0; (i < cRowsFetched); i++)
|
||
|
index[i] = i;
|
||
|
|
||
|
// sort the index based on priority and time stamp
|
||
|
for (i = 0; (i < (cRowsFetched-1)); i++)
|
||
|
{
|
||
|
DWORD Pri = rgPriority[i];
|
||
|
k = i;
|
||
|
// max element's index is in k
|
||
|
for (j=(i+1); (j < cRowsFetched); ++j)
|
||
|
{
|
||
|
// order first by weight and then by time stamp.
|
||
|
if ((rgPriority[index[j]] > Pri) ||
|
||
|
((rgPriority[index[j]] == Pri) &&
|
||
|
(CompareUsn((FILETIME *)&PackageInfo[index[j]].Usn, (FILETIME *)&PackageInfo[index[k]].Usn) == 1)))
|
||
|
{
|
||
|
Pri = rgPriority[index[j]];
|
||
|
k = j;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (k != i)
|
||
|
{
|
||
|
temp = index[k];
|
||
|
index[k] = index[i];
|
||
|
index[i] = temp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DWORD dwPackage;
|
||
|
DWORD dwBestPackage;
|
||
|
|
||
|
dwBestPackage = 0;
|
||
|
|
||
|
//
|
||
|
// Now the packages are sorted in order from highest precedence to lowest.
|
||
|
// We will now check for upgrades for each package
|
||
|
//
|
||
|
for (dwPackage = 0; (dwPackage < cRowsFetched); dwPackage++)
|
||
|
{
|
||
|
DWORD dwPossibleUpgrader;
|
||
|
PACKAGEDISPINFO* pBestPackage;
|
||
|
|
||
|
pBestPackage = PackageInfo+index[dwBestPackage];
|
||
|
|
||
|
CSDBGPrint((L"Processing Package %s", pBestPackage->pszPackageName));
|
||
|
|
||
|
//
|
||
|
// Now search for someone that upgrades the current choice -- look at all packages
|
||
|
// after the current one since we've already determined that the packages before
|
||
|
// this one got upgraded (otherwise we wouldn't be here).
|
||
|
//
|
||
|
for (dwPossibleUpgrader = dwPackage + 1; dwPossibleUpgrader < cRowsFetched; dwPossibleUpgrader ++)
|
||
|
{
|
||
|
PACKAGEDISPINFO* pUpgraderCandidate;
|
||
|
|
||
|
//
|
||
|
// Obviously, we don't need to check the current choice
|
||
|
// to see if it upgrades itself, so skip it
|
||
|
//
|
||
|
if (dwPossibleUpgrader == dwBestPackage)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
pUpgraderCandidate = PackageInfo + index[dwPossibleUpgrader];
|
||
|
|
||
|
//
|
||
|
// See if the upgrader candidate has any upgrades, if not, keep looking
|
||
|
//
|
||
|
if (0 == pUpgraderCandidate->cUpgrades)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now we have to see if any of those upgrades apply to the package we have
|
||
|
// currently selected as the best
|
||
|
//
|
||
|
DWORD dwUpgrade;
|
||
|
BOOL fFoundUpgrade;
|
||
|
|
||
|
fFoundUpgrade = FALSE;
|
||
|
|
||
|
for (dwUpgrade = 0; dwUpgrade < pUpgraderCandidate->cUpgrades; dwUpgrade++)
|
||
|
{
|
||
|
DWORD dwValidUpgradeMask;
|
||
|
|
||
|
dwValidUpgradeMask = UPGFLG_Uninstall |
|
||
|
UPGFLG_NoUninstall |
|
||
|
UPGFLG_Enforced;
|
||
|
|
||
|
//
|
||
|
// If this is a valid upgrade
|
||
|
//
|
||
|
if (pUpgraderCandidate->prgUpgradeInfoList[dwUpgrade].Flag & dwValidUpgradeMask)
|
||
|
{
|
||
|
//
|
||
|
// Does it upgrade the package we think is best at this point? We only
|
||
|
// consider upgrades in this container, as we no longer allow upgrades from lower
|
||
|
// precedence class stores -- the caller who iterates through each container from
|
||
|
// highest precedence to lowest will simply choose the app from the first container in which
|
||
|
// we have a match.
|
||
|
//
|
||
|
// We use memcmp to compare guids to see if the best choice package's guid is listed
|
||
|
// as being upgraded by this upgrade candidate
|
||
|
//
|
||
|
if (memcmp(&((pUpgraderCandidate->prgUpgradeInfoList)[dwUpgrade].PackageGuid),
|
||
|
&(pBestPackage->PackageGuid), sizeof(GUID) == 0))
|
||
|
{
|
||
|
//
|
||
|
// We have a match -- reset the current best choice to the upgrade candidate
|
||
|
//
|
||
|
dwBestPackage = dwPossibleUpgrader;
|
||
|
|
||
|
//
|
||
|
// another package upgrades this -- no need to look any further, so we quit
|
||
|
//
|
||
|
CSDBGPrint((L"Ignoring Package %s because it is getting upgraded in the same store", pBestPackage->pszPackageName));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we found an upgrade in the list above, we can stop abort the search for an upgrade now --
|
||
|
// if we found another, it would just be a lower precedence app since we're iterating from highest to lowest,
|
||
|
// and we want the highest predecence app that upgrades the currently chosen best app
|
||
|
//
|
||
|
if (fFoundUpgrade)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DWORD dwChoice;
|
||
|
|
||
|
dwChoice = index[dwBestPackage];
|
||
|
|
||
|
CSDBGPrint((L"Selecting Package %s as the Best Fit", PackageInfo[dwChoice].pszPackageName));
|
||
|
|
||
|
return dwChoice;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// CAppContainer::GetAppInfo
|
||
|
// -----------------------------
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
// Synopsis: This is the most common access point to the Class Store.
|
||
|
// It receives a CLSID and a QUERYCONTEXT.
|
||
|
// It looks up the Class Store container for a matching set
|
||
|
// of packages with in the context of the QUERYCONTEXT.
|
||
|
//
|
||
|
// QUERYCONTEXT includes
|
||
|
// Execution Context
|
||
|
// Locale Id
|
||
|
// Platform/OS
|
||
|
//
|
||
|
// If i finds an app that matches the requirements, it returns
|
||
|
// an PACKAGEDISPINFO structure containing installation details.
|
||
|
//
|
||
|
// Arguments: [in] clsid
|
||
|
// [in] pQryContext
|
||
|
// [out] pPackageInfo
|
||
|
//
|
||
|
// Returns: CS_E_PACKAGE_NOTFOUND
|
||
|
// S_OK
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE
|
||
|
CAppContainer::GetAppInfo(
|
||
|
uCLSSPEC * pclsspec, // Class Spec (GUID/Ext/MIME)
|
||
|
QUERYCONTEXT * pQryContext, // Query Attributes
|
||
|
PACKAGEDISPINFO * pPackageInfo
|
||
|
)
|
||
|
|
||
|
//
|
||
|
// This is the most common method to access the Class Store.
|
||
|
// It queries the class store for implementations for a specific
|
||
|
// Class Id, or File Ext, or ProgID.
|
||
|
//
|
||
|
// If a matching implementation is available (for the object type,
|
||
|
// client architecture, locale and class context) then the installation
|
||
|
// parameters of the package is returned.
|
||
|
{
|
||
|
GUID clsid;
|
||
|
WCHAR szfilter[1000];
|
||
|
STRINGGUID szClsid;
|
||
|
UINT i, iClsid = 0;
|
||
|
ULONG cRead;
|
||
|
HRESULT hr;
|
||
|
ULONG cSize = _MAX_PATH;
|
||
|
BOOL fFound = FALSE;
|
||
|
PLATFORMINFO PlatformInfo;
|
||
|
LPOLESTR pFileExt = NULL;
|
||
|
BOOL OnDemandInstallOnly = TRUE;
|
||
|
WCHAR FileExtLower [10];
|
||
|
DWORD dwCurrentTime = GetTime();
|
||
|
|
||
|
memset(pPackageInfo, 0, sizeof(PACKAGEDISPINFO));
|
||
|
|
||
|
if (!m_fOpen)
|
||
|
return E_FAIL;
|
||
|
|
||
|
//
|
||
|
// Check if the TypeSpec is MIMEType
|
||
|
// then map it to a CLSID
|
||
|
//
|
||
|
|
||
|
if (pclsspec->tyspec == TYSPEC_MIMETYPE)
|
||
|
{
|
||
|
//
|
||
|
// BUGBUG.
|
||
|
// Considering removal of MimeType support from Class Store
|
||
|
// Till it is decided the code is OUT.
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
|
||
|
/*
|
||
|
if (IsBadStringPtr(pclsspec->tagged_union.pMimeType, _MAX_PATH))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if ((pclsspec->tagged_union.pMimeType == NULL) ||
|
||
|
(*(pclsspec->tagged_union.pMimeType) == NULL))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
wsprintf (szfilter,
|
||
|
L"<%s>;(%s=%s);name",
|
||
|
m_szClassName, MIMETYPES, pclsspec->tagged_union.pMimeType);
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
switch (pclsspec->tyspec)
|
||
|
{
|
||
|
case TYSPEC_TYPELIB: // leaving it here.
|
||
|
if (IsNullGuid(pclsspec->tagged_union.typelibID))
|
||
|
return E_INVALIDARG;
|
||
|
StringFromGUID (pclsspec->tagged_union.typelibID, szClsid);
|
||
|
wsprintf (szfilter,
|
||
|
L"(%s=%s)", PKGTLBIDLIST, szClsid);
|
||
|
break;
|
||
|
|
||
|
case TYSPEC_IID:
|
||
|
if (IsNullGuid(pclsspec->tagged_union.iid))
|
||
|
return E_INVALIDARG;
|
||
|
StringFromGUID (pclsspec->tagged_union.iid, szClsid);
|
||
|
wsprintf (szfilter,
|
||
|
L"(%s=%s)", PKGIIDLIST, szClsid);
|
||
|
break;
|
||
|
|
||
|
case TYSPEC_CLSID:
|
||
|
|
||
|
if (IsNullGuid(pclsspec->tagged_union.clsid))
|
||
|
return E_INVALIDARG;
|
||
|
//
|
||
|
// Check against known missing ones
|
||
|
//
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
EnterCriticalSection (&ClassStoreBindList);
|
||
|
|
||
|
for (iClsid=m_KnownMissingClsidCache.start; (iClsid != m_KnownMissingClsidCache.end);
|
||
|
iClsid = (iClsid+1)%(CLSIDCACHESIZE))
|
||
|
{
|
||
|
if (IsExpired(dwCurrentTime, m_KnownMissingClsidCache.ElemArr[iClsid].Time, CACHE_PURGE_TIME))
|
||
|
{
|
||
|
// all the prev. elems must have expired.
|
||
|
|
||
|
// delete this element
|
||
|
m_KnownMissingClsidCache.start = (m_KnownMissingClsidCache.start+1)%CLSIDCACHESIZE;
|
||
|
m_KnownMissingClsidCache.sz--;
|
||
|
|
||
|
CSDBGPrint((L"Expiring element in CLSID Cache"));
|
||
|
// iClsid will be moved automatically.
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ((IsEqualGUID(pclsspec->tagged_union.clsid,
|
||
|
m_KnownMissingClsidCache.ElemArr[iClsid].Clsid)) &&
|
||
|
((pQryContext->dwContext) == m_KnownMissingClsidCache.ElemArr[iClsid].Ctx))
|
||
|
{
|
||
|
CSDBGPrint((L"Clsid Found in MISSING Cache"));
|
||
|
hr = CS_E_PACKAGE_NOTFOUND;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection (&ClassStoreBindList);
|
||
|
|
||
|
if (hr == CS_E_PACKAGE_NOTFOUND)
|
||
|
return hr;
|
||
|
|
||
|
StringFromGUID (pclsspec->tagged_union.clsid, szClsid);
|
||
|
wsprintf (szfilter, L"(%s=%s*)", PKGCLSIDLIST, szClsid);
|
||
|
break;
|
||
|
|
||
|
case TYSPEC_FILEEXT:
|
||
|
|
||
|
if (IsBadStringPtr(pclsspec->tagged_union.pFileExt, _MAX_PATH))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if ((pclsspec->tagged_union.pFileExt == NULL) ||
|
||
|
(*(pclsspec->tagged_union.pFileExt) == NULL))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
|
||
|
if (wcslen(pclsspec->tagged_union.pFileExt) > 9)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
wcscpy (&FileExtLower[0], pclsspec->tagged_union.pFileExt);
|
||
|
_wcslwr (&FileExtLower[0]);
|
||
|
|
||
|
wsprintf (szfilter,
|
||
|
L"(%s=%s*)",
|
||
|
PKGFILEEXTNLIST, &FileExtLower[0]);
|
||
|
|
||
|
pFileExt = &FileExtLower[0];
|
||
|
break;
|
||
|
|
||
|
|
||
|
case TYSPEC_PROGID:
|
||
|
|
||
|
if (IsBadStringPtr(pclsspec->tagged_union.pProgId, _MAX_PATH))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if ((pclsspec->tagged_union.pProgId == NULL) ||
|
||
|
(*(pclsspec->tagged_union.pProgId) == NULL))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
wsprintf (szfilter,
|
||
|
L"(%s=%s)", PKGPROGIDLIST, pclsspec->tagged_union.pProgId);
|
||
|
break;
|
||
|
|
||
|
case TYSPEC_PACKAGENAME:
|
||
|
//
|
||
|
// Validate package name
|
||
|
//
|
||
|
|
||
|
if (IsBadStringPtr(pclsspec->tagged_union.ByName.pPackageName, _MAX_PATH))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if ((pclsspec->tagged_union.ByName.pPackageName == NULL) ||
|
||
|
(*(pclsspec->tagged_union.ByName.pPackageName) == NULL))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
wsprintf (szfilter, L"(%s=%s)", PACKAGENAME, pclsspec->tagged_union.ByName.pPackageName);
|
||
|
OnDemandInstallOnly = FALSE;
|
||
|
break;
|
||
|
|
||
|
case TYSPEC_SCRIPTNAME:
|
||
|
//
|
||
|
// Validate script name
|
||
|
//
|
||
|
|
||
|
if (IsBadStringPtr(pclsspec->tagged_union.ByScript.pScriptName, _MAX_PATH))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if ((pclsspec->tagged_union.ByScript.pScriptName == NULL) ||
|
||
|
(*(pclsspec->tagged_union.ByScript.pScriptName) == NULL))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
wsprintf (szfilter, L"(%s=*%s*)", SCRIPTPATH, pclsspec->tagged_union.ByScript.pScriptName);
|
||
|
|
||
|
OnDemandInstallOnly = FALSE;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
//
|
||
|
ULONG cRowsFetched;
|
||
|
PACKAGEDISPINFO PackageInfo[10];
|
||
|
UINT rgPriority [10];
|
||
|
|
||
|
ADS_SEARCH_HANDLE hADsSearchHandle = NULL;
|
||
|
|
||
|
CSDBGPrint((L"PackageContainer handle 0x%x", m_ADsPackageContainer));
|
||
|
|
||
|
hr = ADSIExecuteSearch(m_ADsPackageContainer, szfilter, pszInstallInfoAttrNames, cInstallInfoAttr, &hADsSearchHandle);
|
||
|
CSDBGPrint((L"CAppContainer::GetAppInfo search filter %s", szfilter));
|
||
|
ERROR_ON_FAILURE(hr);
|
||
|
|
||
|
//
|
||
|
// BUGBUG. Currently limited to 10.
|
||
|
// Must put a loop to retry more in future.
|
||
|
//
|
||
|
hr = FetchInstallData(m_ADsPackageContainer,
|
||
|
hADsSearchHandle,
|
||
|
pQryContext,
|
||
|
pclsspec,
|
||
|
pFileExt,
|
||
|
10,
|
||
|
&cRowsFetched,
|
||
|
&PackageInfo[0],
|
||
|
&rgPriority[0],
|
||
|
OnDemandInstallOnly
|
||
|
);
|
||
|
|
||
|
CSDBGPrint((L"CAppContainer::FetchInstallData returned 0x%x", hr));
|
||
|
CSDBGPrint((L"CAppContainer::FetchInstallData returned %d Packages", cRowsFetched));
|
||
|
|
||
|
if (cRowsFetched == 0)
|
||
|
{
|
||
|
hr = CS_E_OBJECT_NOTFOUND;
|
||
|
//
|
||
|
// If CLSID was passed cache the miss
|
||
|
//
|
||
|
if (pclsspec->tyspec == TYSPEC_CLSID)
|
||
|
{
|
||
|
EnterCriticalSection (&ClassStoreBindList);
|
||
|
|
||
|
if (m_KnownMissingClsidCache.sz < (CLSIDCACHESIZE-1))
|
||
|
{
|
||
|
memcpy (&m_KnownMissingClsidCache.ElemArr[m_KnownMissingClsidCache.end].Clsid,
|
||
|
&(pclsspec->tagged_union.clsid), sizeof(GUID));
|
||
|
|
||
|
m_KnownMissingClsidCache.ElemArr[m_KnownMissingClsidCache.end].Ctx
|
||
|
= pQryContext->dwContext;
|
||
|
|
||
|
m_KnownMissingClsidCache.ElemArr[m_KnownMissingClsidCache.end].Time
|
||
|
= dwCurrentTime;
|
||
|
|
||
|
m_KnownMissingClsidCache.sz++;
|
||
|
|
||
|
m_KnownMissingClsidCache.end = (m_KnownMissingClsidCache.end+1) % CLSIDCACHESIZE;
|
||
|
|
||
|
CSDBGPrint((L"Adding Element to the clsid cache"));
|
||
|
|
||
|
}
|
||
|
LeaveCriticalSection (&ClassStoreBindList);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DWORD dwChoice = 0;
|
||
|
|
||
|
if (cRowsFetched > 1)
|
||
|
{
|
||
|
dwChoice = ChooseBestFit(PackageInfo, rgPriority, cRowsFetched);
|
||
|
}
|
||
|
|
||
|
|
||
|
memcpy (pPackageInfo, &PackageInfo[dwChoice], sizeof(PACKAGEDISPINFO));
|
||
|
memset (&PackageInfo[dwChoice], NULL, sizeof(PACKAGEDISPINFO));
|
||
|
|
||
|
// Clean up all allocations
|
||
|
for (i=0; i < cRowsFetched; i++)
|
||
|
{
|
||
|
ReleasePackageInfo(&PackageInfo[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (hADsSearchHandle)
|
||
|
ADSICloseSearchHandle(m_ADsPackageContainer, hADsSearchHandle);
|
||
|
|
||
|
//
|
||
|
// fill in PolicyID and Name
|
||
|
//
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
memcpy (&(pPackageInfo->GpoId), &m_PolicyId, sizeof(GUID));
|
||
|
if (m_szPolicyName && (*m_szPolicyName))
|
||
|
{
|
||
|
pPackageInfo->pszPolicyName = (LPOLESTR) CoTaskMemAlloc(sizeof(WCHAR) * (1+wcslen(m_szPolicyName)));
|
||
|
if (pPackageInfo->pszPolicyName)
|
||
|
wcscpy (pPackageInfo->pszPolicyName, m_szPolicyName);
|
||
|
else {
|
||
|
ReleasePackageInfo(pPackageInfo);
|
||
|
memset(pPackageInfo, 0, sizeof(PACKAGEDISPINFO));
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Error_Cleanup:
|
||
|
CSDBGPrint((L"CAppContainer::GetAppInfo returning 0x%x", RemapErrorCode(hr, m_szContainerName)));
|
||
|
return RemapErrorCode(hr, m_szContainerName);
|
||
|
}
|
||
|
|
||
|
|
||
|
|