Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3718 lines
113 KiB

//+------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: admin.cxx
//
// Contents:Class Factory and IUnknown methods for CClassContainer
//
// Author: DebiM
//
//-------------------------------------------------------------------------
#include "cstore.hxx"
//
// Constructor for Class Container Class factory
//
unsigned long gulcInstances = 0;
HRESULT GetConsistentPackageFlags(
HANDLE hADs,
DWORD* pdwPackageFlags,
UINT* pdwUpgrades,
UINT* pdwInstallUiLevel,
CLASSPATHTYPE* pdwPathType,
DWORD* pdwNewPackageFlags,
WCHAR* wszSearchFlags)
{
HRESULT hr;
LPOLESTR PackageAttrName;
ADS_ATTR_INFO* pAttrsGot;
DWORD cgot;
DWORD posn;
DWORD dwOldPackageFlags;
DWORD dwNewPackageFlags;
//
// Init locals
//
dwOldPackageFlags = 0;
PackageAttrName = PACKAGEFLAGS;
pAttrsGot = NULL;
hr = S_OK;
if (hADs)
{
//
// We need to find the old package flags -- we do this so we can preserve
// certain properties.
//
hr = ADSIGetObjectAttributes(hADs, &PackageAttrName, 1, &pAttrsGot, &cgot);
if (SUCCEEDED(hr))
{
posn = GetPropertyFromAttr(pAttrsGot, cgot, PACKAGEFLAGS);
if (posn < cgot)
UnpackDWFrom(pAttrsGot[posn], (DWORD *)&dwOldPackageFlags);
else
hr=CS_E_OBJECT_NOTFOUND;
}
}
if (SUCCEEDED(hr))
{
//
// Decide whether to start with existing flags or caller supplied flags based
// on whether the caller passed in desired flags
//
dwNewPackageFlags = pdwPackageFlags ? *pdwPackageFlags : dwOldPackageFlags;
//
// Make sure to preserve upgrades,
// installui, and pathtype transparently
//
dwNewPackageFlags |= dwOldPackageFlags &
(ACTFLG_POSTBETA3 |
ACTFLG_HasUpgrades |
ACTFLG_FullInstallUI |
PATHTYPEMASK);
//
// Now set the upgrade bit according to whether there are upgrades
//
if (pdwUpgrades)
{
dwNewPackageFlags = *pdwUpgrades ?
dwNewPackageFlags | ACTFLG_HasUpgrades :
dwNewPackageFlags & ~(ACTFLG_HasUpgrades);
}
//
// Set the install UI level
//
if (pdwInstallUiLevel)
{
dwNewPackageFlags &= ~(ACTFLG_FullInstallUI);
dwNewPackageFlags |= (*pdwInstallUiLevel != INSTALLUILEVEL_FULL) ?
ACTFLG_FullInstallUI : 0;
}
//
// Now or in the pathtype by shifting it to the far left -- first clear those
// bits out
//
if (pdwPathType)
{
dwNewPackageFlags &= ~PATHTYPEMASK;
dwNewPackageFlags |= *pdwPathType << PATHTYPESHIFT;
}
*pdwNewPackageFlags = dwNewPackageFlags;
if (wszSearchFlags)
{
memset(wszSearchFlags, 0, MAX_SEARCH_FLAGS * sizeof(*wszSearchFlags));
//
// Previously, we determined the search flags based
// on whether the package was an NT 5.0 beta 3 deployment --
// this backward compatibility with beta 3 will not
// be supported in subsequent versions of Windows
//
*wszSearchFlags = SEARCHFLAG_REMOVED;
if (dwNewPackageFlags & ACTFLG_Published)
{
*wszSearchFlags = SEARCHFLAG_PUBLISHED;
wszSearchFlags++;
}
if (dwNewPackageFlags & ACTFLG_Assigned)
{
*wszSearchFlags = SEARCHFLAG_ASSIGNED;
}
}
}
if (pAttrsGot)
{
FreeADsMem(pAttrsGot);
}
return hr;
}
CClassContainerCF::CClassContainerCF()
{
m_uRefs = 1;
InterlockedIncrement((long *) &gulcInstances );
}
//
// Destructor
//
CClassContainerCF::~CClassContainerCF()
{
InterlockedDecrement((long *) &gulcInstances );
}
HRESULT __stdcall CClassContainerCF::QueryInterface(REFIID riid, void * * ppvObject)
{
IUnknown *pUnkTemp = NULL;
SCODE sc = S_OK;
if( IsEqualIID( IID_IUnknown, riid ) )
{
pUnkTemp = (IUnknown *)(ITypeLib *)this;
}
else if( IsEqualIID( IID_IClassFactory, riid ) )
{
pUnkTemp = (IUnknown *)(IClassFactory *)this;
} else
{
sc = (E_NOINTERFACE);
}
if((pUnkTemp != NULL) && (SUCCEEDED(sc)))
{
*ppvObject = (void * )pUnkTemp;
pUnkTemp->AddRef();
}
return(sc);
}
ULONG __stdcall CClassContainerCF::AddRef()
{
InterlockedIncrement(( long * )&m_uRefs );
return m_uRefs;
}
ULONG __stdcall CClassContainerCF::Release()
{
unsigned long uTmp = InterlockedDecrement((long *)&m_uRefs);
unsigned long cRef = m_uRefs;
if (uTmp == 0)
{
delete this;
}
return(cRef);
}
//+-------------------------------------------------------------------------
//
// Member: CClassContainerCF::CreateInstance
//
// Synopsis:
// This is the default create instance on the class factory.
//
// Arguments: pUnkOuter - Should be NULL
// riid - IID of interface wanted
// ppvObject - Returns the pointer to the resulting IClassAdmin.
//
// Returns: S_OK
// E_INVALIDARG
// E_OUTOFMEMORY
// MK_E_SYNTAX
//
//--------------------------------------------------------------------------
//
HRESULT __stdcall CClassContainerCF::CreateInstance(
IUnknown * pUnkOuter,
REFIID riid,
void ** ppvObject)
{
CClassContainer * pIUnk = NULL;
SCODE sc = S_OK;
if( pUnkOuter == NULL )
{
if( (pIUnk = new CClassContainer()) != NULL)
{
sc = pIUnk->QueryInterface( riid , ppvObject );
if(FAILED(sc))
{
sc = E_UNEXPECTED;
}
pIUnk->Release();
}
else
sc = E_OUTOFMEMORY;
}
else
{
return E_INVALIDARG;
}
return (sc);
}
//+-------------------------------------------------------------------------
//
// Member: CClassContainerCF::CreateConnectedInstance
//
// Synopsis:
// This method is called by the ParseDisplayName implementation
// on the ClassFactory object.
// When a display name is used to bind to a Class Store
// an IClassAdmin is returned after binding to the container.
// This method fails if the bind fails.
//
// Arguments: pszPath - DisplayName of Class Store Container
// ppvObject - Returns the pointer to the resulting IClassAdmin.
//
// Returns: S_OK
// E_INVALIDARG
// E_OUTOFMEMORY
// MK_E_SYNTAX
//
//--------------------------------------------------------------------------
HRESULT __stdcall CClassContainerCF::CreateConnectedInstance(
CServerContext* pServerContext,
LPOLESTR pszPath,
void ** ppvObject)
{
CClassContainer * pIUnk = NULL;
SCODE sc = S_OK;
HRESULT hr = S_OK;
if ((pIUnk = new CClassContainer(pServerContext, pszPath, &sc)) != NULL)
{
if (SUCCEEDED(sc))
{
sc = pIUnk->QueryInterface( IID_IClassAdmin, ppvObject );
if(FAILED(sc))
{
sc = E_UNEXPECTED;
}
}
pIUnk->Release();
}
else
sc = E_OUTOFMEMORY;
return (sc);
}
HRESULT __stdcall CClassContainerCF::LockServer(BOOL fLock)
{
if(fLock)
{ InterlockedIncrement((long *) &gulcInstances ); }
else
{ InterlockedDecrement((long *) &gulcInstances ); }
return(S_OK);
}
//
// IUnknown methods for CClassContainer
//
//
HRESULT __stdcall CClassContainer::QueryInterface(REFIID riid, void * * ppvObject)
{
IUnknown *pUnkTemp = NULL;
SCODE sc = S_OK;
if( IsEqualIID( IID_IUnknown, riid ) )
{
pUnkTemp = (IUnknown *)(IClassAdmin *)this;
}
else if( IsEqualIID( IID_IClassAdmin, riid ) )
{
pUnkTemp = (IUnknown *)(IClassAdmin *)this;
}
else
{
sc = (E_NOINTERFACE);
}
if((pUnkTemp != NULL) && (SUCCEEDED(sc)))
{
*ppvObject = (void * )pUnkTemp;
pUnkTemp->AddRef();
}
return(sc);
}
ULONG __stdcall CClassContainer::AddRef()
{
InterlockedIncrement(( long * )&m_uRefs );
return m_uRefs;
}
ULONG __stdcall CClassContainer::Release()
{
unsigned long uTmp = InterlockedDecrement((long *)&m_uRefs);
unsigned long cRef = m_uRefs;
if (uTmp == 0)
{
delete this;
}
return(cRef);
}
// utility functions
HRESULT UpdateStoreUsn(HANDLE hADs, LPOLESTR szUsn)
{
ADS_ATTR_INFO pAttr[1];
DWORD cModified = 0;
HRESULT hr = S_OK;
PackStrToAttr(pAttr, STOREUSN, szUsn);
hr = ADSISetObjectAttributes(hADs, pAttr, 1, &cModified);
FreeAttr(pAttr[0]);
return hr;
}
//----------------------------------------------------------
// Implementation for CClassContainer
//----------------------------------------------------------
//
CClassContainer::CClassContainer()
{
m_fOpen = FALSE;
m_ADsContainer = NULL;
m_ADsPackageContainer = NULL;
m_szCategoryName = NULL;
m_szPackageName = NULL;
m_szPolicyName = NULL;
memset (&m_PolicyId, 0, sizeof(GUID));
m_uRefs = 1;
}
//---------------------------------------------------------------
//
// Function: Constructor
//
// Synopsis: Binds to the ClassStore given a class store path.
//
// Arguments:
// [in]
// szStoreName
// Class Store Path without the leading ADCS:
//
// [out]
// phr
// Sucess code.
//
// Does an ADSI bind at the class store container and matches the
// version numbers. if the version numbers match then it binds to the
// class, package and category containers and keeps the bind handles.
//----------------------------------------------------------------
CClassContainer::CClassContainer(
CServerContext* pServerContext,
LPOLESTR szStoreName,
HRESULT* phr)
{
DWORD dwStoreVersion = 0;
LPOLESTR AttrNames[] = {STOREVERSION, POLICYDN};
ADS_ATTR_INFO * pAttrsGot = NULL;
DWORD cgot = 0, posn = 0;
ADS_SEARCHPREF_INFO SearchPrefs[2];
// set the search preference to one level search
// and make the results come back in batches of size
// 20 as default.
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 = SEARCHPAGESIZE;
// initialising.
*phr = S_OK;
m_fOpen = FALSE;
m_ADsContainer = NULL;
m_ADsPackageContainer = NULL;
m_szCategoryName = NULL;
m_szPackageName = NULL;
m_szPolicyName = NULL;
memset (&m_PolicyId, 0, sizeof(GUID));
// Bind to a Class Store Container Object
// Cache the interface pointer
//
*phr = StringCchCopy (m_szContainerName, _MAX_PATH, szStoreName);
ERROR_ON_FAILURE(*phr);
if ( pServerContext )
{
*phr = m_ServerContext.Initialize( pServerContext );
}
ERROR_ON_FAILURE(*phr);
*phr = DSServerOpenDSObject( &m_ServerContext, m_szContainerName, GetDsFlags(),
&m_ADsContainer);
ERROR_ON_FAILURE(*phr);
//
// Check the Schema Version of this container
//
*phr = ADSIGetObjectAttributes(m_ADsContainer, AttrNames, 2, &pAttrsGot, &cgot);
if ((SUCCEEDED(*phr)) && (cgot))
{
posn = GetPropertyFromAttr(pAttrsGot, cgot, STOREVERSION);
dwStoreVersion = 0;
if (posn < cgot)
{
UnpackDWFrom(pAttrsGot[posn], &dwStoreVersion);
//
// Compare the schema with the expected version
//
if (dwStoreVersion != SCHEMA_VERSION_NUMBER)
{
*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 (szPolicyGuid && szParentPath)
{
if (wcslen(szPolicyGuid) == 41)
{
// valid GUID
GUIDFromString(&szPolicyGuid[4], &m_PolicyId);
}
*phr = GetGPOName( &szPolicyName );
}
else
{
*phr = E_OUTOFMEMORY;
}
if (szParentPath)
FreeADsMem(szParentPath);
if (szPolicyGuid)
FreeADsMem(szPolicyGuid);
}
m_szPolicyName = szPolicyName;
}
}
if (pAttrsGot)
FreeADsMem(pAttrsGot);
ERROR_ON_FAILURE(*phr);
//
// Bind to the Package container Object
// Cache the interface pointer
//
// get the package container name.
BuildADsPathFromParent(m_szContainerName, PACKAGECONTAINERNAME, &m_szPackageName);
m_ADsPackageContainer = NULL;
// bind to the package container.
*phr = DSServerOpenDSObject( &m_ServerContext, m_szPackageName, GetDsFlags(),
&m_ADsPackageContainer);
ERROR_ON_FAILURE(*phr);
// set the search preference.
*phr = ADSISetSearchPreference(m_ADsPackageContainer, SearchPrefs, 2);
ERROR_ON_FAILURE(*phr);
m_fOpen = TRUE;
m_uRefs = 1;
Error_Cleanup:
*phr = RemapErrorCode(*phr, m_szContainerName);
return;
}
CClassContainer::~CClassContainer(void)
{
if (m_fOpen)
{
m_fOpen = FALSE;
}
if (m_ADsPackageContainer)
{
ADSICloseDSObject(m_ADsPackageContainer);
m_ADsPackageContainer = NULL;
}
if (m_szPackageName)
FreeADsMem(m_szPackageName);
if (m_szCategoryName)
FreeADsMem(m_szCategoryName);
if (m_ADsContainer)
{
ADSICloseDSObject(m_ADsContainer);
m_ADsContainer = NULL;
}
}
// currently unused.
BOOL InvalidDSName(LPWSTR pName)
{
if (wcslen(pName) >= 56)
return TRUE;
while (*pName)
{
if ((*pName == L':') ||
(*pName == L',') ||
(*pName == L';') ||
(*pName == L'/') ||
(*pName == L'<') ||
(*pName == L'>') ||
(*pName == L'\\')||
(*pName == L'+'))
return TRUE;
++pName;
}
return FALSE;
}
HRESULT CClassContainer::GetGPOInfo(GUID *pGPOId, LPOLESTR *pszPolicyName)
{
HRESULT hr;
if ((!pGPOId) || (IsBadWritePtr(pGPOId, sizeof(GUID))))
return E_INVALIDARG;
if ((!pszPolicyName) || (IsBadWritePtr(pszPolicyName, sizeof(LPOLESTR))))
return E_OUTOFMEMORY;
memcpy(pGPOId, &m_PolicyId, sizeof(GUID));
if (m_szPolicyName)
{
*pszPolicyName = (LPOLESTR)CsMemAlloc(sizeof(WCHAR)*(1+wcslen(m_szPolicyName)));
if (!(*pszPolicyName))
return E_INVALIDARG;
hr = StringCchCopy(*pszPolicyName, wcslen(m_szPolicyName) + 1, m_szPolicyName);
if (FAILED(hr))
{
return hr;
}
}
else
{
*pszPolicyName = (LPOLESTR)CsMemAlloc(sizeof(WCHAR)*2);
if (!(*pszPolicyName))
return E_OUTOFMEMORY;
(*pszPolicyName)[0] = L'\0';
}
return S_OK;
}
//---------------------------------------------------------------
//
// Function: EnumPackages
//
// Synopsis: Returns an Enumerator for all the packages that satisfies
// the query.
//
// UsedBy Add/Remove Programs
//
// Arguments:
// [in]
// pszFileExt
// FileExt that has to be queried on. ignored if NULL.
// pCategory
// Category that has to be queried on. ignored if NULL.
// dwAppFlags
// One of the APPINFO_XXX. ignored if it is APPINFO_ALL.
// pdwLocale
// Locale that has to be queried on. Ignored if NULL.
// pPlatform
// Platform that has to be queried on. Ignored if NULL.
//
// [out]
// ppIEnumPackage
// Enumerator is returned.
// Returns:
// S_OK, E_OUTOFMEMORY, CS_E_XXX
//
// Validates the inputs, Creates a EnumPackage object, makes up the
// search string made up of file extension, category.
//----------------------------------------------------------------
HRESULT CClassContainer::EnumPackages(
LPOLESTR pszFileExt,
GUID *pCategory,
DWORD dwAppFlags,
DWORD *pdwLocale,
CSPLATFORM *pPlatform,
IEnumPackage **ppIEnumPackage
)
{
const DWORD dwMaxStrLen = 1000;
HRESULT hr = S_OK;
CEnumPackage *pEnum = NULL;
WCHAR szfilter[dwMaxStrLen], szQry[dwMaxStrLen];
if (pszFileExt && IsBadStringPtr(pszFileExt, _MAX_PATH))
return E_INVALIDARG;
if (pCategory && IsBadReadPtr(pCategory, sizeof(GUID)))
return E_INVALIDARG;
if (IsBadWritePtr(ppIEnumPackage, sizeof(IEnumPackage *)))
return E_INVALIDARG;
*ppIEnumPackage = NULL;
pEnum = new CEnumPackage(&m_ServerContext, m_PolicyId, m_szPolicyName, m_szContainerName, NULL);
if(NULL == pEnum)
return E_OUTOFMEMORY;
//
// Create a CommandText
//
hr = StringCchPrintf(szfilter, dwMaxStrLen, L"(& (objectClass=%s) ", CLASS_CS_PACKAGE);
ERROR_ON_FAILURE(hr);
if (pszFileExt)
{
hr = StringCchPrintf(szQry, dwMaxStrLen, L"(%s=%s*) ", PKGFILEEXTNLIST, pszFileExt);
ERROR_ON_FAILURE(hr);
hr = StringCchCat(szfilter, dwMaxStrLen, szQry);
ERROR_ON_FAILURE(hr);
}
if (pCategory)
{
STRINGGUID szCat;
StringFromGUID (*pCategory, szCat);
hr = StringCchPrintf(szQry, dwMaxStrLen, L"(%s=%s) ", PKGCATEGORYLIST, szCat);
ERROR_ON_FAILURE(hr);
hr = StringCchCat(szfilter, dwMaxStrLen, szQry);
ERROR_ON_FAILURE(hr);
}
hr = StringCchCat(szfilter, dwMaxStrLen, L")");
ERROR_ON_FAILURE(hr);
hr = pEnum->Initialize(m_szPackageName, szfilter,
dwAppFlags, FALSE, 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);
}
HRESULT CClassContainer::GetDNFromPackageName(LPOLESTR pszPackageName, LPOLESTR *szDN)
{
HRESULT hr = S_OK;
WCHAR* szfilter;
WCHAR* szEscapedName;
LPOLESTR AttrNames[] = {OBJECTCLASS, PACKAGEFLAGS, OBJECTDN};
DWORD cAttr = 3;
ADS_SEARCH_HANDLE hADsSearchHandle = NULL;
ADS_SEARCH_COLUMN column;
DWORD dwFlags = 0;
*szDN = NULL;
szfilter = NULL;
//
// To get the DN, we perform a search. The search filter syntax requires that
// the package name is properly escaped, so we retrieve such a filter below
//
hr = GetEscapedNameFilter( pszPackageName, &szfilter );
if ( FAILED( hr ) )
{
RETURN_ON_FAILURE( hr );
}
hr = ADSIExecuteSearch(m_ADsPackageContainer, szfilter, AttrNames, cAttr, &hADsSearchHandle);
CsMemFree( szfilter );
RETURN_ON_FAILURE(hr);
for (hr = ADSIGetFirstRow(m_ADsPackageContainer, hADsSearchHandle);
((SUCCEEDED(hr)) && (hr != S_ADS_NOMORE_ROWS));
hr = ADSIGetNextRow(m_ADsPackageContainer, hADsSearchHandle))
{
hr = DSGetAndValidateColumn(m_ADsPackageContainer, hADsSearchHandle, ADSTYPE_INTEGER, PACKAGEFLAGS, &column);
if (SUCCEEDED(hr))
{
UnpackDWFrom(column, &dwFlags);
ADSIFreeColumn(m_ADsPackageContainer, &column);
}
else
continue;
if ((dwFlags & ACTFLG_Orphan) || (dwFlags & ACTFLG_Uninstall))
continue;
hr = DSGetAndValidateColumn(m_ADsPackageContainer, hADsSearchHandle, ADSTYPE_CASE_IGNORE_STRING, OBJECTDN, &column);
if (SUCCEEDED(hr))
{
UnpackStrAllocFrom(column, szDN);
ADSIFreeColumn(m_ADsPackageContainer, &column);
}
else
continue;
break;
}
if (hADsSearchHandle)
ADSICloseSearchHandle(m_ADsPackageContainer, hADsSearchHandle);
return hr;
}
// Gets the RDN of a package given the package Guid.
HRESULT CClassContainer::BuildDNFromPackageGuid(GUID PackageGuid, LPOLESTR *szDN)
{
HRESULT hr = S_OK;
LPOLESTR AttrName = {OBJECTDN};
WCHAR szfilter[_MAX_PATH];
ADS_SEARCH_HANDLE hADsSearchHandle = NULL;
ADS_SEARCH_COLUMN column;
LPWSTR EncodedGuid = NULL;
hr = ADsEncodeBinaryData((PBYTE)&PackageGuid, sizeof(GUID), &EncodedGuid);
hr = StringCchPrintf(szfilter, _MAX_PATH, L"(%s=%s)", OBJECTGUID, EncodedGuid);
RETURN_ON_FAILURE(hr);
FreeADsMem(EncodedGuid);
hr = ADSIExecuteSearch(m_ADsPackageContainer, szfilter, &AttrName, 1, &hADsSearchHandle);
RETURN_ON_FAILURE(hr);
hr = ADSIGetFirstRow(m_ADsPackageContainer, hADsSearchHandle);
if ((FAILED(hr)) || (hr == S_ADS_NOMORE_ROWS))
{
ERROR_ON_FAILURE(hr = CS_E_PACKAGE_NOTFOUND);
}
hr = DSGetAndValidateColumn(m_ADsPackageContainer, hADsSearchHandle, ADSTYPE_CASE_IGNORE_STRING, AttrName, &column);
ERROR_ON_FAILURE(hr);
if (SUCCEEDED(hr))
{
UnpackStrAllocFrom(column, szDN);
}
ADSIFreeColumn(m_ADsPackageContainer, &column);
Error_Cleanup:
if (hADsSearchHandle)
ADSICloseSearchHandle(m_ADsPackageContainer, hADsSearchHandle);
return hr;
}
HRESULT CClassContainer::GetPackageGuid(WCHAR *szRDN, GUID *pPackageGuid)
{
HRESULT hr = S_OK;
LPOLESTR AttrName = {OBJECTGUID};
WCHAR szfilter[_MAX_PATH];
ADS_SEARCH_HANDLE hADsSearchHandle = NULL;
ADS_SEARCH_COLUMN column;
hr = ADSIExecuteSearch(m_ADsPackageContainer, szRDN, &AttrName, 1, &hADsSearchHandle);
RETURN_ON_FAILURE(hr);
hr = ADSIGetFirstRow(m_ADsPackageContainer, hADsSearchHandle);
if ((FAILED(hr)) || (hr == S_ADS_NOMORE_ROWS))
{
ERROR_ON_FAILURE(hr = CS_E_PACKAGE_NOTFOUND);
}
hr = DSGetAndValidateColumn(m_ADsPackageContainer, hADsSearchHandle, ADSTYPE_OCTET_STRING, AttrName, &column);
ERROR_ON_FAILURE(hr);
if (SUCCEEDED(hr))
UnpackGUIDFrom(column, pPackageGuid);
ADSIFreeColumn(m_ADsPackageContainer, &column);
Error_Cleanup:
if (hADsSearchHandle)
ADSICloseSearchHandle(m_ADsPackageContainer, hADsSearchHandle);
return hr;
}
//---------------------------------------------------------------
//
// Function: GetPackageDetails
//
// Synopsis: Returns the PackageDetail corresponding to the PackageName.
//
// Arguments:
// [in]
// pszPackageId
// Id of the Package.
// [out]
// pPackageDetail
// PackageDetail info that is returned.
// Returns:
// S_OK, E_OUTOFMEMORY, CS_E_XXX
//
// Binds to the Package object and calls GetPackageDetail with it.
//----------------------------------------------------------------
HRESULT CClassContainer::GetPackageDetails (
LPOLESTR pszPackageName,
PACKAGEDETAIL * pPackageDetail
)
{
HRESULT hr = S_OK;
HANDLE hADs = NULL;
WCHAR * szFullName = NULL;
ADS_ATTR_INFO * pAttr = NULL;
DWORD cgot = 0;
// this can be made into a search based API. Not required for the time being.
// Should change it if perf is a big issue.
if ((!pszPackageName) || IsBadStringPtr(pszPackageName, _MAX_PATH))
return E_INVALIDARG;
hr = GetDNFromPackageName(pszPackageName, &szFullName);
ERROR_ON_FAILURE(hr);
if (hr != S_OK)
return CS_E_OBJECT_NOTFOUND;
// binding to the package object.
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(), &hADs);
ERROR_ON_FAILURE(hr);
// calling GetPackageDetail.
hr = GetPackageDetail (hADs, NULL, pPackageDetail);
ADSICloseDSObject(hADs);
if (pAttr)
FreeADsMem(pAttr);
if (szFullName)
CsMemFree(szFullName);
Error_Cleanup:
return RemapErrorCode(hr, m_szContainerName);
}
//---------------------------------------------------------------
//
// Function: GetPackageDetails
//
// Synopsis: Returns the PackageDetail corresponding to the PackageName.
//
// Arguments:
// [in]
// pszPackageId
// Id of the Package.
// [out]
// pPackageDetail
// PackageDetail info that is returned.
// Returns:
// S_OK, E_OUTOFMEMORY, CS_E_XXX
//
// Binds to the Package object and calls GetPackageDetail with it.
//----------------------------------------------------------------
HRESULT CClassContainer::GetPackageDetailsFromGuid (
GUID PkgGuid,
PACKAGEDETAIL *pPackageDetail
)
{
HRESULT hr = S_OK;
HANDLE hADs = NULL;
WCHAR * szFullName = NULL, szRDN[_MAX_PATH];
ADS_ATTR_INFO * pAttr = NULL;
DWORD cgot = 0;
// this can be made into a search based API. Not required for the time being.
// Should change it if perf is a big issue.
if (IsNullGuid(PkgGuid))
return E_INVALIDARG;
BuildDNFromPackageGuid(PkgGuid, &szFullName);
ERROR_ON_FAILURE(hr);
if (hr != S_OK)
return CS_E_OBJECT_NOTFOUND;
// binding to the package object.
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(), &hADs);
ERROR_ON_FAILURE(hr);
// calling GetPackageDetail.
hr = GetPackageDetail (hADs, NULL, pPackageDetail);
ADSICloseDSObject(hADs);
if (pAttr)
FreeADsMem(pAttr);
if (szFullName)
CsMemFree(szFullName);
Error_Cleanup:
return RemapErrorCode(hr, m_szContainerName);
}
#define FREEARR(ARR, SZ) { \
DWORD curIndex; \
for (curIndex = 0; curIndex < (SZ); curIndex++) \
CsMemFree((ARR)[curIndex]); \
CsMemFree(ARR); \
ARR = NULL; \
} \
//---------------------------------------------------------------
//
// Function: ChangePackageUpgradeInfoIncremental
//
// Synopsis: Mark the package as upgraded by another package
//
// Arguments:
// [in]
// PackageGuid
// Package Guid to identify the package.
// szUpgradedByClassStore
// Class Store where the package that upgrades exists
// UpgradedByPackageGuid
// The Guid of the package that upgrades
// Add Add or remove the upgradedByrelation
//
// Returns:
// S_OK, E_OUTOFMEMORY, CS_E_XXX
// Otherwise it packs all the required attributes in the ATTR_INFO
// structure and sends it to the Directory.
//----------------------------------------------------------------
HRESULT CClassContainer::ChangePackageUpgradeInfoIncremental(
GUID PackageGuid,
UPGRADEINFO UpgradeInfo,
DWORD OpFlags
)
{
HRESULT hr = S_OK;
HANDLE hADs = NULL;
WCHAR *szFullName=NULL, szGuid[_MAX_PATH], szUsn[20];
LPOLESTR pProp = NULL;
ADS_ATTR_INFO pAttr[2];
DWORD cAttr = 0, cModified = 0, i=0;
UINT len=0;
ULONG ulSize;
hr = BuildDNFromPackageGuid(PackageGuid, &szFullName);
ERROR_ON_FAILURE(hr);
// Bind to the Package Object.
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(), &hADs);
ERROR_ON_FAILURE(hr);
StringFromGUID(UpgradeInfo.PackageGuid, szGuid);
len = wcslen(UpgradeInfo.szClassStore);
ulSize = 36+PKG_UPG_DELIM1_LEN+len+PKG_UPG_DELIM2_LEN+2+2+1;
pProp = (LPOLESTR)CsMemAlloc(sizeof(WCHAR) * ulSize);
// Guid size+::+length++:+flagDigit+2
hr = StringCchPrintf(pProp, ulSize, L"%s%s%s%s%02x", UpgradeInfo.szClassStore, PKG_UPG_DELIMITER1, szGuid, PKG_UPG_DELIMITER2, UpgradeInfo.Flag%16);
ERROR_ON_FAILURE(hr);
PackStrArrToAttrEx(pAttr+cAttr, UPGRADESPACKAGES, &pProp, 1, OpFlags?TRUE:FALSE);
cAttr++;
//
// Update the TimeStamp
//
GetCurrentUsn(szUsn);
PackStrToAttr(pAttr+cAttr, PKGUSN, szUsn);
cAttr++;
hr = ADSISetObjectAttributes(hADs, pAttr, cAttr, &cModified);
if (hADs)
ADSICloseDSObject(hADs);
// ignore it if the property already exists.
if (hr == HRESULT_FROM_WIN32(ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS))
hr = S_OK;
for (i = 0; i < cAttr; i++)
FreeAttr(pAttr[i]);
Error_Cleanup:
if (szFullName)
CsMemFree(szFullName);
return RemapErrorCode(hr, m_szContainerName);
}
//---------------------------------------------------------------
//
// Function: ChangePackageProperties
//
// Synopsis: Change Various (most commonly changed) properties
// for a given package.
//
// Arguments:
// [in]
// PackageId
// Package Id to identify the package.
// pszNewname
// new Name for the Package. If it is being renamed
// all other changes should be NULL.
// pdwFlags
// The Deployment Flags. Should be ACTFLG_XXX
// Ignored if NULL.
// pszUrl
// Help Url for the Package. Ignored if NULL.
// pszScriptPath
// Script Path for the Package. Ignored if NULL.
// pInstallUiLevel
// The InstallationUiLevel. Ignored if NULL.
// pdwRevision
// REVISION. Ignored if NULL.
//
// Returns:
// S_OK, E_OUTOFMEMORY, CS_E_XXX
// Otherwise it packs all the required attributes in the ATTR_INFO
// structure and sends it to the Directory.
//----------------------------------------------------------------
HRESULT CClassContainer::ChangePackageProperties(
LPOLESTR pszPackageName,
LPOLESTR pszNewName,
DWORD *pdwFlags,
LPOLESTR pszUrl,
LPOLESTR pszScriptPath,
UINT *pInstallUiLevel,
DWORD *pdwRevision
)
{
HRESULT hr = S_OK;
HANDLE hADs = NULL;
WCHAR *szRDN=NULL, *szFullName=NULL;
WCHAR szUsn[20];
ADS_ATTR_INFO pAttr[9];
DWORD cAttr = 0, cModified = 0, i=0;
DWORD dwNewPackageFlags;
WCHAR wszSearchFlags[MAX_SEARCH_FLAGS];
if ((!pszPackageName) || IsBadStringPtr(pszPackageName, _MAX_PATH))
return E_INVALIDARG;
hr = GetDNFromPackageName(pszPackageName, &szFullName);
ERROR_ON_FAILURE(hr);
if (hr != S_OK)
return CS_E_OBJECT_NOTFOUND;
// if no properties have to be changed.
if (!(pszScriptPath || pszUrl || pdwFlags || pInstallUiLevel || pdwRevision || pszNewName))
return E_INVALIDARG;
if (pszNewName)
{
// rename package
WCHAR szNewRDN[_MAX_PATH];
BOOL GenerateGuid = FALSE;
GUID PackageGuidId;
WCHAR pszPackageNewId[_MAX_PATH], *szJunk = NULL;
if (IsBadStringPtr(pszNewName, _MAX_PATH))
return E_INVALIDARG;
if (pszScriptPath || pszUrl || pdwFlags || pInstallUiLevel || pdwRevision)
return E_INVALIDARG;
// see whether the new name is valid.
// GenerateGuid = InvalidDSName(pszNewName);
// see whether the newName already exists. Notice that if the same package name is
// entered it will return error.
hr = GetDNFromPackageName(pszNewName, &szJunk);
if (szJunk)
CsMemFree(szJunk);
szJunk = NULL;
ERROR_ON_FAILURE(hr);
if (hr == S_OK)
return CS_E_OBJECT_ALREADY_EXISTS;
// Bind to the Package Object.
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(),
&hADs);
if (szFullName)
CsMemFree(szFullName);
szFullName = NULL;
ERROR_ON_FAILURE(hr);
}
else
{
// Bind to the Package Object.
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(),
&hADs);
ERROR_ON_FAILURE(hr);
if (szFullName)
CsMemFree(szFullName);
szFullName = NULL;
}
// Just change some properties.
//
// Update the TimeStamp
//
GetCurrentUsn(szUsn);
PackStrToAttr(pAttr+cAttr, PKGUSN, szUsn);
cAttr++;
if (SUCCEEDED(hr))
{
hr = GetConsistentPackageFlags(
hADs,
pdwFlags,
NULL,
pInstallUiLevel,
NULL,
&dwNewPackageFlags,
wszSearchFlags);
}
if (SUCCEEDED(hr))
{
//
// Set Package Flags
//
if (pdwFlags)
{
PackDWToAttr (pAttr+cAttr, PACKAGEFLAGS, dwNewPackageFlags);
cAttr++;
if (*wszSearchFlags)
{
PackStrToAttr(pAttr+cAttr, SEARCHFLAGS, wszSearchFlags);
cAttr++;
}
}
//
// Change Package Script
//
if (pszScriptPath)
{
PackStrToAttr(pAttr+cAttr, SCRIPTPATH, pszScriptPath);
cAttr++;
}
//
// Change Package Help URL
//
if (pszUrl)
{
if ( ! *pszUrl )
{
pszUrl = NULL;
}
PackStrToAttr(pAttr+cAttr, HELPURL, pszUrl);
cAttr++;
}
//
// Change Package UI Level.
//
if (pInstallUiLevel)
{
PackDWToAttr (pAttr+cAttr, UILEVEL, *pInstallUiLevel);
cAttr++;
}
//
// Change Revision.
//
if (pdwRevision)
{
PackDWToAttr (pAttr+cAttr, REVISION, *pdwRevision);
cAttr++;
}
if (pszNewName)
{
PackStrToAttr(pAttr+cAttr, PACKAGENAME, pszNewName);
cAttr++;
// also set display name so outside tools can have a
// friendly name
PackStrToAttr(pAttr+cAttr, PKGDISPLAYNAME, pszNewName);
cAttr++;
}
hr = ADSISetObjectAttributes(hADs, pAttr, cAttr, &cModified);
}
if (hADs)
ADSICloseDSObject(hADs);
for (i = 0; i < cAttr; i++)
FreeAttr(pAttr[i]);
if (SUCCEEDED(hr))
{
//
// Update Class Store Usn
//
UpdateStoreUsn(m_ADsContainer, szUsn);
}
Error_Cleanup:
if (szFullName)
CsMemFree(szFullName);
return RemapErrorCode(hr, m_szContainerName);
}
//---------------------------------------------------------------
// Function: ChangePackageCategories
//
// Synopsis: Change (Not Add) the Categories that a package
// belongs to.
//
// Arguments:
// [in]
// pszPackageName
// Package Name to identify the package.
// cCategories
// Number of Categories.
// rpCategory
// Array of categories.
//
// Returns:
// S_OK, E_OUTOFMEMORY, CS_E_XXX
// Binds to the Package Object, Converts all the categories to strings
// Packs it and sends it to the DS.
//----------------------------------------------------------------
HRESULT CClassContainer::ChangePackageCategories(
LPOLESTR pszPackageName,
UINT cCategories,
GUID *rpCategory
)
{
//
// Does not change USN
//
HRESULT hr = S_OK;
HANDLE hADs = NULL;
WCHAR *szFullName = NULL;
LPOLESTR *pszGuid = NULL;
UINT count;
ADS_ATTR_INFO pAttr[1];
DWORD cAttr = 0, cModified = 0, i=0;
if ((!pszPackageName) || IsBadStringPtr(pszPackageName, _MAX_PATH))
return E_INVALIDARG;
if ((cCategories) && ((!rpCategory) ||
(IsBadReadPtr(rpCategory, sizeof(GUID) * cCategories))))
return E_INVALIDARG;
// Construct the Name of the Package Object.
GetDNFromPackageName(pszPackageName, &szFullName);
ERROR_ON_FAILURE(hr);
if (hr != S_OK)
return CS_E_OBJECT_NOTFOUND;
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(),
&hADs);
ERROR_ON_FAILURE(hr);
// fill in the categories
pszGuid = (LPOLESTR *)CsMemAlloc(cCategories * sizeof(LPOLESTR));
if (!pszGuid)
{
hr = E_OUTOFMEMORY;
ERROR_ON_FAILURE(hr);
}
// convert the GUIDs to Strings.
for (count = 0; (count < cCategories); count++)
{
pszGuid[count] = (LPOLESTR)CsMemAlloc(STRINGGUIDLEN*sizeof(WCHAR));
if (!(pszGuid[count]))
{
FREEARR(pszGuid, count);
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
}
StringFromGUID(rpCategory[count], pszGuid[count]);
}
// Pack it into Attribute Structure.
PackStrArrToAttr(pAttr+cAttr, PKGCATEGORYLIST, pszGuid, cCategories);
cAttr++;
// Set the Attribute
hr = ADSISetObjectAttributes(hADs, pAttr, cAttr, &cModified);
Error_Cleanup:
if (hADs)
ADSICloseDSObject(hADs);
if (pszGuid)
for (count = 0; (count < cCategories); count++)
CsMemFree(pszGuid[count]);
CsMemFree(pszGuid);
if (szFullName)
CsMemFree(szFullName);
for (i = 0; i < cAttr; i++)
FreeAttr(pAttr[i]);
return RemapErrorCode(hr, m_szContainerName);
}
//---------------------------------------------------------------
// Function: SetPriorityByFileExt
//
// Synopsis: Changes the priority of a Package corresp. to
// a file Extension.
//
// Arguments:
// [in]
// pszPackageName
// Package Name to identify the package.
// pszFileExt
// File Extension for which the priority has to be changed.
// Priority
// Priority for the Package.
//
// Returns:
// S_OK, E_OUTOFMEMORY, CS_E_XXX
// Binds to the Package Object, Gets the file Extensions and changes
// the priority corresponding to the File Extension.
//----------------------------------------------------------------
HRESULT CClassContainer::SetPriorityByFileExt(
LPOLESTR pszPackageName,
LPOLESTR pszFileExt,
UINT Priority
)
{
HRESULT hr = S_OK;
HANDLE hADs = NULL;
WCHAR *szFullName=NULL;
LPOLESTR *prgFileExt = NULL;
WCHAR szUsn[20];
ADS_ATTR_INFO pAttr[4], *pAttrGot = NULL;
DWORD cAttr = 0, cAttrGot = 0, cModified = 0, cShellFileExt = 0, i=0;
LPOLESTR pAttrNames[] = {PKGFILEEXTNLIST};
// Construct the Package Name
GetDNFromPackageName(pszPackageName, &szFullName);
ERROR_ON_FAILURE(hr);
if (hr != S_OK)
return CS_E_OBJECT_NOTFOUND;
// Bind to the Package Object.
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(),
&hADs);
ERROR_ON_FAILURE(hr);
//
// Update the TimeStamp
//
GetCurrentUsn(szUsn);
PackStrToAttr(pAttr+cAttr, PKGUSN, szUsn);
cAttr++;
// get the file extensions.
hr = ADSIGetObjectAttributes(hADs, pAttrNames, 1, &pAttrGot, &cAttrGot);
if ((SUCCEEDED(hr)) && (cAttrGot))
UnpackStrArrFrom(pAttrGot[0], &prgFileExt, &cShellFileExt);
// Look for the given file extension.
for (i=0; i < cShellFileExt; ++i)
{
if (wcsncmp(prgFileExt[i], pszFileExt, wcslen(pszFileExt)) == 0)
{
// if the file extension is found, change the corresponding priority.
if (wcslen(prgFileExt[i]) != (wcslen(pszFileExt)+3))
continue;
hr = StringCchPrintf(prgFileExt[i], wcslen(prgFileExt[i]) + 1, L"%s:%2d", pszFileExt, Priority%100);
ERROR_ON_FAILURE(hr);
break;
}
}
if (i == cShellFileExt)
{
ERROR_ON_FAILURE(hr = CS_E_OBJECT_NOTFOUND);
}
if (cShellFileExt)
{
PackStrArrToAttr(pAttr+cAttr, PKGFILEEXTNLIST, prgFileExt, cShellFileExt);
cAttr++;
}
hr = ADSISetObjectAttributes(hADs, pAttr, cAttr, &cModified);
if (SUCCEEDED(hr))
{
//
// Update Store Usn
//
UpdateStoreUsn(m_ADsContainer, szUsn);
}
Error_Cleanup:
CsMemFree(prgFileExt);
if (szFullName)
CsMemFree(szFullName);
for (i = 0; i < cAttr; i++)
FreeAttr(pAttr[i]);
if (pAttrGot)
FreeADsMem(pAttrGot);
ADSICloseDSObject(hADs);
return RemapErrorCode(hr, m_szContainerName);
}
//---------------------------------------------------------------
// Function: ChangePackageSourceList
//
// Synopsis: Changes the priority of a Package corresp. to
// a file Extension.
//
// Arguments:
// [in]
// pszPackageName
// Package Name to identify the package.
// cSources
// Number of sources
// pszSourceList
// List of sources
//
// Returns:
// S_OK, E_OUTOFMEMORY, CS_E_XXX
// Binds to the Package Object, Makes the new sourcelist with the order
// maintained.
//----------------------------------------------------------------
HRESULT CClassContainer::ChangePackageSourceList(
LPOLESTR pszPackageName,
UINT cSources,
LPOLESTR *pszSourceList
)
{
HRESULT hr = S_OK;
ULONG ulSize;
HANDLE hADs = NULL;
WCHAR *szFullName = NULL;
UINT count;
WCHAR szUsn[20];
LPOLESTR *pszPrioritySourceList = NULL;
ADS_ATTR_INFO pAttr[2];
DWORD cAttr = 0, cModified = 0, i=0;
if ((!pszPackageName) || IsBadStringPtr(pszPackageName, _MAX_PATH))
return E_INVALIDARG;
if ((!pszSourceList) ||
(IsBadReadPtr(pszSourceList, sizeof(LPOLESTR) * cSources)))
return E_INVALIDARG;
for (count = 0; (count < cSources); count++)
if ((!pszSourceList[count]) || (IsBadStringPtr(pszSourceList[count], _MAX_PATH)))
return E_INVALIDARG;
// Construct the Name of the Package Object.
GetDNFromPackageName(pszPackageName, &szFullName);
ERROR_ON_FAILURE(hr);
if (hr != S_OK)
return CS_E_OBJECT_NOTFOUND;
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(),
&hADs);
ERROR_ON_FAILURE(hr);
// Local variable for adding the order to the list.
pszPrioritySourceList = (LPOLESTR *)CsMemAlloc(cSources * sizeof(LPOLESTR));
if (!pszPrioritySourceList)
{
hr = E_OUTOFMEMORY;
ERROR_ON_FAILURE(hr);
}
// add the order to the list
for (count = 0; (count < cSources); count++)
{
ulSize = wcslen(pszSourceList[count])+1+1+1+NumDigits10(cSources);
pszPrioritySourceList[count] = (LPOLESTR)CsMemAlloc(sizeof(WCHAR)* ulSize);
if (!(pszPrioritySourceList[count]))
{
FREEARR(pszPrioritySourceList, count);
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
}
hr = StringCchPrintf(pszPrioritySourceList[count], ulSize, L"%d:%s", count, pszSourceList[count]);
ERROR_ON_FAILURE(hr);
}
//
// Update the TimeStamp
//
GetCurrentUsn(szUsn);
PackStrToAttr(pAttr+cAttr, PKGUSN, szUsn);
cAttr++;
// Pack it into Attribute Structure.
PackStrArrToAttr(pAttr+cAttr, MSIFILELIST, pszPrioritySourceList, cSources);
cAttr++;
// Set the Attribute
hr = ADSISetObjectAttributes(hADs, pAttr, cAttr, &cModified);
if (SUCCEEDED(hr))
{
//
// Update Store Usn
//
UpdateStoreUsn(m_ADsContainer, szUsn);
}
Error_Cleanup:
if (hADs)
ADSICloseDSObject(hADs);
for (i = 0; i < cAttr; i++)
FreeAttr(pAttr[i]);
if (szFullName)
CsMemFree(szFullName);
return RemapErrorCode(hr, m_szContainerName);
}
//---------------------------------------------------------------
// Function: ChangePackageUpgradeList
//
// Synopsis: Changes the priority of a Package corresp. to
// a file Extension.
//
// Arguments:
// [in]
// pszPackageName
// Package Name to identify the package.
// cSources
// Number of sources
// pszSourceList
// List of sources
//
// Returns:
// S_OK, E_OUTOFMEMORY, CS_E_XXX
// Binds to the Package Object, Makes the new sourcelist with the order
// maintained.
//----------------------------------------------------------------
HRESULT CClassContainer::ChangePackageUpgradeList(
LPOLESTR pszPackageName,
UINT cUpgrades,
UPGRADEINFO *prgUpgradeInfoList
)
{
HRESULT hr = S_OK;
HANDLE hADs = NULL;
WCHAR *szFullName = NULL;
UINT count = 0, count1 = 0, count2 = 0;
LPOLESTR *pProp = NULL, pAttrNames[] = {UPGRADESPACKAGES, OBJECTGUID, PACKAGEFLAGS}, *rpszUpgrades = NULL;
ADS_ATTR_INFO pAttr[3], *pAttrGot = NULL;
DWORD cAttr = 0, cModified = 0, i=0, posn = 0, cUpgradeInfoStored = 0,
cAddList = 0, cRemoveList = 0, cgot = 0;
GUID PkgGuid;
WCHAR szUsn[20];
UPGRADEINFO *pUpgradeInfoStored = NULL, *pAddList = NULL, *pRemoveList = NULL;
DWORD dwPackageFlags;
if ((!pszPackageName) || IsBadStringPtr(pszPackageName, _MAX_PATH))
return E_INVALIDARG;
if ((cUpgrades) && ((!prgUpgradeInfoList) ||
(IsBadReadPtr(prgUpgradeInfoList, sizeof(UPGRADEINFO) * cUpgrades))))
return E_INVALIDARG;
for (count = 0; (count < cUpgrades); count++)
{
if ((!(prgUpgradeInfoList[count].szClassStore)) ||
IsBadStringPtr((prgUpgradeInfoList[count].szClassStore), _MAX_PATH))
return E_INVALIDARG;
if (IsNullGuid(prgUpgradeInfoList[count].PackageGuid))
return E_INVALIDARG;
if (((prgUpgradeInfoList[count].Flag & UPGFLG_Uninstall) == 0) &&
((prgUpgradeInfoList[count].Flag & UPGFLG_NoUninstall) == 0) &&
((prgUpgradeInfoList[count].Flag & UPGFLG_UpgradedBy) == 0))
return E_INVALIDARG;
}
// Construct the Name of the Package Object.
hr = GetDNFromPackageName(pszPackageName, &szFullName);
ERROR_ON_FAILURE(hr);
if (hr != S_OK)
return CS_E_OBJECT_NOTFOUND;
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(),
&hADs);
ERROR_ON_FAILURE(hr);
// get the guid and upgrade info
hr = ADSIGetObjectAttributes(hADs, pAttrNames, 3, &pAttrGot, &cgot);
ERROR_ON_FAILURE(hr);
// Package guid
posn = GetPropertyFromAttr(pAttrGot, cgot, OBJECTGUID);
if (posn < cgot)
UnpackGUIDFrom(pAttrGot[posn], &PkgGuid);
// Upgrade package
posn = GetPropertyFromAttr(pAttrGot, cgot, UPGRADESPACKAGES);
if (posn < cgot)
UnpackStrArrFrom(pAttrGot[posn], &pProp, &cUpgradeInfoStored);
// Package Flags
posn = GetPropertyFromAttr(pAttrGot, cgot, PACKAGEFLAGS);
if (posn < cgot)
UnpackDWFrom(pAttrGot[posn], (DWORD *)&dwPackageFlags);
// allocating the lists
pUpgradeInfoStored = (UPGRADEINFO *)CsMemAlloc(sizeof(UPGRADEINFO)*(cUpgradeInfoStored));
pAddList = (UPGRADEINFO *)CsMemAlloc(sizeof(UPGRADEINFO)*(cUpgrades+cUpgradeInfoStored));
pRemoveList = (UPGRADEINFO *)CsMemAlloc(sizeof(UPGRADEINFO)*(cUpgrades+cUpgradeInfoStored));
if ((!pUpgradeInfoStored) || (!pAddList) || (!pRemoveList))
ERROR_ON_FAILURE(hr = E_OUTOFMEMORY);
// convert the strings to upgradinfo structures.
for (count = 0; count < (cUpgradeInfoStored); count++)
{
WCHAR *pStr = NULL;
LPOLESTR ptr = pProp[count];
UINT len = wcslen (ptr);
pUpgradeInfoStored[count].szClassStore = pProp[count];
if (len <= 41)
continue;
*(ptr + len - 3) = NULL;
pUpgradeInfoStored[count].Flag = wcstoul(ptr+(len-2), &pStr, 16);
*(ptr + len - 3 - 36 - 2) = L'\0';
/* -GUID-'::'*/
GUIDFromString(ptr+len-3-36, &(pUpgradeInfoStored[count].PackageGuid));
}
cUpgradeInfoStored = count; // we might have skipped some.
// AddList formed.
for (count = 0; count < cUpgrades; count++)
{
for (count1 = 0; count1 < cUpgradeInfoStored; count1++)
{
// ignore flag changes
if ((wcscmp(pUpgradeInfoStored[count1].szClassStore, prgUpgradeInfoList[count].szClassStore) == 0) &&
(memcmp(&pUpgradeInfoStored[count1].PackageGuid, &prgUpgradeInfoList[count].PackageGuid, sizeof(GUID)) == 0))
break;
}
if (count1 == cUpgradeInfoStored)
pAddList[cAddList++] = prgUpgradeInfoList[count];
}
// remove list formed.
for (count1 = 0; count1 < cUpgradeInfoStored; count1++)
{
for (count = 0; count < cUpgrades; count++)
{
// ignore flag changes
if ((wcscmp(pUpgradeInfoStored[count1].szClassStore, prgUpgradeInfoList[count].szClassStore) == 0) &&
(memcmp(&pUpgradeInfoStored[count1].PackageGuid, &prgUpgradeInfoList[count].PackageGuid, sizeof(GUID)) == 0))
break;
}
if (count == cUpgrades)
pRemoveList[cRemoveList++] = pUpgradeInfoStored[count];
}
for (count = 0; count < cAddList; count++)
{
// in case of UpgradedBy do no try to fix up the links.
if (!(pAddList[count].Flag & UPGFLG_UpgradedBy))
{
DWORD Flags = 0;
if (pAddList[count].Flag & UPGFLG_Enforced)
Flags = UPGFLG_Enforced;
}
}
for (count = 0; count < cRemoveList; count++)
{
// in case of UpgradedBy do no try to fix up the links.
if (!(pRemoveList[count].Flag & UPGFLG_UpgradedBy))
{
DWORD Flags = 0;
if (pRemoveList[count].Flag & UPGFLG_Enforced)
Flags = UPGFLG_Enforced;
}
}
rpszUpgrades = (LPOLESTR *)CsMemAlloc(sizeof(LPOLESTR)*cUpgrades);
if (!rpszUpgrades)
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
for (count = 0; (count < cUpgrades); count++)
{
WCHAR szPackageGuid[_MAX_PATH];
UINT len = wcslen(prgUpgradeInfoList[count].szClassStore);
ULONG ulSize = 36+PKG_UPG_DELIM1_LEN+len+PKG_UPG_DELIM2_LEN+2+2;
rpszUpgrades[count] = (LPOLESTR)CsMemAlloc(sizeof(WCHAR) *ulSize);
// Guid size+::+length++:+flagDigit+2
if (!rpszUpgrades[count])
{
FREEARR(rpszUpgrades, count);
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
}
StringFromGUID(prgUpgradeInfoList[count].PackageGuid, szPackageGuid);
hr = StringCchPrintf(rpszUpgrades[count], ulSize, L"%s%s%s%s%02x", prgUpgradeInfoList[count].szClassStore, PKG_UPG_DELIMITER1, szPackageGuid,
PKG_UPG_DELIMITER2, prgUpgradeInfoList[count].Flag%16);
ERROR_ON_FAILURE(hr);
}
PackStrArrToAttr(pAttr+cAttr, UPGRADESPACKAGES, rpszUpgrades, cUpgrades);
cAttr++;
//
// Update the TimeStamp
//
GetCurrentUsn(szUsn);
PackStrToAttr(pAttr+cAttr, PKGUSN, szUsn);
cAttr++;
//
// Update the package flags -- this call will make sure the
// ugprade flag is set if there are upgrades, clear if not
//
hr = GetConsistentPackageFlags(
NULL,
&dwPackageFlags,
&cUpgrades,
NULL,
NULL,
&dwPackageFlags,
NULL);
ERROR_ON_FAILURE(hr);
PackDWToAttr (pAttr+cAttr, PACKAGEFLAGS,
dwPackageFlags);
cAttr++;
// Set the Attribute
hr = ADSISetObjectAttributes(hADs, pAttr, cAttr, &cModified);
if (SUCCEEDED(hr))
{
//
// Update Store Usn
//
UpdateStoreUsn(m_ADsContainer, szUsn);
}
Error_Cleanup:
if (hADs)
ADSICloseDSObject(hADs);
if (szFullName)
CsMemFree(szFullName);
for (i = 0; i < cAttr; i++)
FreeAttr(pAttr[i]);
if (pAttrGot)
FreeADsMem(pAttrGot);
if (pProp)
CsMemFree(pProp);
if (pUpgradeInfoStored)
CsMemFree(pUpgradeInfoStored);
if (pAddList)
CsMemFree(pAddList);
if (pRemoveList)
CsMemFree(pRemoveList);
return RemapErrorCode(hr, m_szContainerName);
}
extern LPOLESTR szAppCategoryColumns;
//---------------------------------------------------------------
// Function: GetAppCategories
//
// Synopsis: gets the list of Package Categories in the Domain.
//
// Arguments:
// [in]
// Locale
// Locale for the categories. Used to get the description.
// [out]
// pAppCategoryList
// the list of Application Categories in the domain
//
// Returns:
// S_OK, E_OUTOFMEMORY, CS_E_XXX
//
// Gets the FullName of the Domain, binds to the AppCategory container
// below that. and gets all the categories with approp. types.
//----------------------------------------------------------------
HRESULT CClassContainer::GetAppCategories (
LCID Locale,
APPCATEGORYINFOLIST *pAppCategoryList
)
{
HRESULT hr = S_OK;
WCHAR szfilter[_MAX_PATH];
WCHAR szRootPath[_MAX_PATH], szAppCategoryContainer[_MAX_PATH];
HANDLE hADs = NULL;
ADS_SEARCH_HANDLE hADsSearchHandle = NULL;
ADS_SEARCHPREF_INFO SearchPrefs[2];
WCHAR* szContainerNameForErrorReport;
// set the search preference.
SearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
SearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
SearchPrefs[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
// we do not expect too many categories
SearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
SearchPrefs[1].vValue.dwType = ADSTYPE_INTEGER;
SearchPrefs[1].vValue.Integer = SEARCHPAGESIZE;
if (IsBadWritePtr(pAppCategoryList, sizeof(APPCATEGORYINFOLIST)))
return E_INVALIDARG;
// If an error occurs here, we assume it occurred at the domain root
szContainerNameForErrorReport = L"LDAP://rootdse";
// get the name of the domain.
hr = GetRootPath(NULL, szRootPath, _MAX_PATH);
ERROR_ON_FAILURE(hr);
// Names returned by GetRootPath are in only 1 format and we don't need to
// use BuildADsPath.
hr = StringCchPrintf(szAppCategoryContainer, _MAX_PATH, L"%s%s%s", LDAPPREFIX, APPCATEGORYCONTAINERNAME,
szRootPath+LDAPPREFIXLENGTH);
ERROR_ON_FAILURE(hr);
// If an error occurs now, we use the name of the category container
szContainerNameForErrorReport = szAppCategoryContainer;
hr = StringCchPrintf(szfilter, _MAX_PATH, L"(objectClass=%s)", CLASS_CS_CATEGORY);
ERROR_ON_FAILURE(hr);
//
// We use the secure option in the bind below because this can get called
// in client policy context (outside of the admin tool)
//
//binds to the category container
hr = DSServerOpenDSObject(&m_ServerContext, szAppCategoryContainer,
GetDsFlags(), &hADs);
ERROR_ON_FAILURE(hr);
hr = ADSISetSearchPreference(hADs, SearchPrefs, 2);
ERROR_ON_FAILURE(hr);
// gets a search handle
hr = ADSIExecuteSearch(hADs, szfilter, pszCategoryAttrNames, cCategoryAttr, &hADsSearchHandle);
ERROR_ON_FAILURE(hr);
//
// Retrieve the list of categories from the search
// if successful, memory will be allocated for the category list
//
hr = FetchCategory(hADs, hADsSearchHandle, pAppCategoryList, Locale);
ERROR_ON_FAILURE(hr);
Error_Cleanup:
if (hADsSearchHandle)
ADSICloseSearchHandle(hADs, hADsSearchHandle);
if (hADs)
ADSICloseDSObject(hADs);
return RemapErrorCode(hr, szAppCategoryContainer);
}
//---------------------------------------------------------------
// Function: RegisterAppCategory
//
// Synopsis: Adda category and assoc desc. for the whole Domain(This is per domain
// and not per class store.)
//
// Arguments:
// [in]
// pAppCategory
// Pointer to a APPCATEGORYINFO structure to be added.
//
// Returns:
// S_OK, E_OUTOFMEMORY, E_INVALIDARG, CS_E_XXX
//
// Finds the root path of the domain. binds to the category container
// underneath it. deletes this particular AppCategory.
//----------------------------------------------------------------
HRESULT CClassContainer::RegisterAppCategory (
APPCATEGORYINFO *pAppCategory
)
{
WCHAR szRootPath[_MAX_PATH], localedescription[128+16],
szAppCategoryContainer[_MAX_PATH], szRDN[_MAX_PATH],
* szFullName = NULL, szAppCatid[_MAX_PATH];
HRESULT hr = S_OK;
HANDLE hADsContainer = NULL, hADs = NULL;
ULONG i, j, cdesc = 0, posn = 0;
LPOLESTR * pszDescExisting = NULL, pszDesc = NULL;
LPOLESTR AttrName = LOCALEDESCRIPTION;
ADS_ATTR_INFO * pAttrGot = NULL, pAttr[6];
DWORD cgot = 0, cAttr = 0;
BOOL fExists = TRUE;
if ((!pAppCategory) || (IsBadReadPtr(pAppCategory, sizeof(APPCATEGORYINFO))))
return E_INVALIDARG;
if ((pAppCategory->pszDescription == NULL) ||
(IsBadStringPtr(pAppCategory->pszDescription, _MAX_PATH)))
return E_INVALIDARG;
if (IsNullGuid(pAppCategory->AppCategoryId))
return E_INVALIDARG;
//
// Enforce the maximum category description size
//
if ( wcslen(pAppCategory->pszDescription) > CAT_DESC_MAX_LEN )
{
return E_INVALIDARG;
}
// get the name of the root of the domain
hr = GetRootPath(NULL, szRootPath, _MAX_PATH);
ERROR_ON_FAILURE(hr);
// Bind to a AppCategory container
// Names returned by GetRootPath are in only 1 format and we don't need to
// use BuildADsPath.
hr = StringCchPrintf(szAppCategoryContainer, _MAX_PATH, L"%s%s%s", LDAPPREFIX, APPCATEGORYCONTAINERNAME,
szRootPath+LDAPPREFIXLENGTH);
ERROR_ON_FAILURE(hr);
// container is supposed to exist.
hr = DSServerOpenDSObject(&m_ServerContext, szAppCategoryContainer, GetDsFlags(),
&hADsContainer);
ERROR_ON_FAILURE(hr);
RDNFromGUID(pAppCategory->AppCategoryId, szRDN);
hr = StringCchPrintf(localedescription, 128+16, L"%x %s %s", pAppCategory->Locale, CAT_DESC_DELIMITER,
pAppCategory->pszDescription);
ERROR_ON_FAILURE(hr);
BuildADsPathFromParent(szAppCategoryContainer, szRDN, &szFullName);
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(), &hADs);
if (SUCCEEDED(hr))
hr = ADSIGetObjectAttributes(hADs, &AttrName, 1, &pAttrGot, &cgot);
if (SUCCEEDED(hr))
{
fExists = TRUE;
}
else
{
fExists = FALSE;
PackStrToAttr(pAttr, OBJECTCLASS, CLASS_CS_CATEGORY); cAttr++;
PackGUIDToAttr(pAttr+cAttr, CATEGORYCATID, &(pAppCategory->AppCategoryId)); cAttr++;
hr = ADSICreateDSObject(hADsContainer, szRDN, pAttr, cAttr);
for (j = 0; j < cAttr; j++)
FreeAttr(pAttr[j]);
cAttr = 0;
if (hADs)
{
ADSICloseDSObject(hADs);
hADs = NULL;
}
hr = DSServerOpenDSObject(&m_ServerContext, szFullName, GetDsFlags(), &hADs);
}
if (szFullName)
FreeADsMem(szFullName);
ERROR_ON_FAILURE(hr);
if (fExists) {
if (cgot)
{
UnpackStrArrFrom(pAttrGot[0], &pszDescExisting, &cdesc);
}
// Existing list of descriptions
if (posn = FindDescription(pszDescExisting, cdesc, &(pAppCategory->Locale), NULL, 0))
{ // Delete the old value
PackStrArrToAttrEx(pAttr+cAttr, LOCALEDESCRIPTION, pszDescExisting+(posn-1), 1, FALSE); cAttr++;
}
CsMemFree(pszDescExisting);
}
pszDesc = localedescription;
PackStrArrToAttrEx(pAttr+cAttr, LOCALEDESCRIPTION, &pszDesc, 1, TRUE);
cAttr++;
DWORD cModified;
hr = ADSISetObjectAttributes(hADs, pAttr, cAttr, &cModified);
Error_Cleanup:
if (pAttrGot)
FreeADsMem(pAttrGot);
for (i = 0; i < cAttr; i++)
FreeAttr(pAttr[i]);
if (hADs)
ADSICloseDSObject(hADs);
if (hADsContainer)
ADSICloseDSObject(hADsContainer);
return RemapErrorCode(hr, m_szContainerName);
}
//---------------------------------------------------------------
// Function: UnregisterAppCategory
//
// Synopsis: Removes a category from the whole Domain(This is per domain)
// and not per class store.
//
// Arguments:
// [in]
// pAppCategoryId
// Pointer to a GUID that has to be removed.
//
// Returns:
// S_OK, E_OUTOFMEMORY, E_INVALIDARG, CS_E_XXX
//
// Finds the root path of the domain. binds to the category container
// underneath it. deletes this particular AppCategory.
//----------------------------------------------------------------
HRESULT CClassContainer::UnregisterAppCategory (
GUID *pAppCategoryId
)
{
WCHAR szRootPath[_MAX_PATH], szRDN[_MAX_PATH],
szAppCategoryContainer[_MAX_PATH];
HRESULT hr = S_OK;
HANDLE hADs = NULL;
if (IsBadReadPtr(pAppCategoryId, sizeof(GUID)))
return E_INVALIDARG;
hr = GetRootPath(NULL, szRootPath, _MAX_PATH);
// Bind to a AppCategory container
// Names returned by GetRootPath are in only 1 format and we don't need to
// use BuildADsPath.
hr = StringCchPrintf(szAppCategoryContainer, _MAX_PATH, L"%s%s%s", LDAPPREFIX, APPCATEGORYCONTAINERNAME,
szRootPath+LDAPPREFIXLENGTH);
ERROR_ON_FAILURE(hr);
hr = DSServerOpenDSObject(&m_ServerContext, szAppCategoryContainer, GetDsFlags(),
&hADs);
ERROR_ON_FAILURE(hr);
RDNFromGUID(*pAppCategoryId, szRDN);
hr = ADSIDeleteDSObject(hADs, szRDN);
ADSICloseDSObject(hADs);
// Delete this category
Error_Cleanup:
return RemapErrorCode(hr, m_szContainerName);
}
//---------------------------------------------------------------
// Function: DeletePackage
//
// Synopsis: Permanently remove a package and the associated Classes
// from class store
//
// Arguments:
// [in]
// PackageGuid
// Guid of the package that has to be removed.
//
// Returns:
// S_OK, E_OUTOFMEMORY, E_INVALIDARG, CS_E_XXX
//
// Deletes the package.
// Tries to delete all the upgrade relationships from this package.
// Errors are ignored.
//----------------------------------------------------------------
HRESULT CClassContainer::DeletePackage (LPOLESTR szFullName
)
{
HRESULT hr = S_OK;
DWORD cStr = 0, count = 0, cgot = 0, posn = 0;
LPOLESTR szRDN = NULL, szJunk = NULL;
LPOLESTR * szStr = NULL;
LPOLESTR pAttrName[] = {UPGRADESPACKAGES, OBJECTGUID, SCRIPTPATH};
LPOLESTR szScriptPath;
ADS_ATTR_INFO * pAttr = NULL;
HANDLE hADs = NULL;
WCHAR szUsn[20];
GUID PackageGuid;
hr = DSServerOpenDSObject(&m_ServerContext, szFullName, GetDsFlags(),
&hADs);
if (!SUCCEEDED(hr))
return hr;
GetCurrentUsn(szUsn);
hr = ADSIGetObjectAttributes(
hADs,
pAttrName,
sizeof(pAttrName) / sizeof(pAttrName[0]),
&pAttr, &cgot);
memset(&PackageGuid, 0, sizeof(GUID));
posn = GetPropertyFromAttr(pAttr, cgot, OBJECTGUID);
if (posn < cgot)
UnpackGUIDFrom(pAttr[posn], &PackageGuid);
posn = GetPropertyFromAttr(pAttr, cgot, SCRIPTPATH);
if (posn < cgot)
{
UnpackStrFrom(pAttr[posn], &szScriptPath);
if (szScriptPath)
{
BOOL fDeleted;
fDeleted = DeleteFile(szScriptPath);
CSDBGPrint((DM_WARNING,
IDS_CSTORE_DELETESCRIPT,
szScriptPath,
fDeleted ? ERROR_SUCCESS : GetLastError()));
}
}
posn = GetPropertyFromAttr(pAttr, cgot, UPGRADESPACKAGES);
if (posn < cgot)
UnpackStrArrFrom(pAttr[posn], &szStr, &cStr);
for (count = 0; count < cStr; count++)
{
GUID UpgradeeGuid;
WCHAR *pStr = NULL;
LPOLESTR ptr = szStr[count];
UINT len = wcslen (ptr);
DWORD UpgradeFlag, Flags = 0;
if (len <= 41)
continue;
*(ptr + (len - 3)) = NULL;
UpgradeFlag = wcstoul(ptr+(len-2), &pStr, 16);
*(ptr + (len - 3 - 36 - 2)) = L'\0';
/* -GUID-'::'*/
GUIDFromString(ptr+len-3-36, &UpgradeeGuid);
if (UpgradeFlag & UPGFLG_Enforced)
Flags = UPGFLG_Enforced;
}
if (szStr)
CsMemFree(szStr);
szStr = NULL;
cStr = 0;
// ignore errors
if (pAttr)
FreeADsMem(pAttr);
ADSICloseDSObject(hADs);
BuildADsParentPath(szFullName, &szJunk, &szRDN);
if (szJunk)
FreeADsMem(szJunk);
hr = ADSIDeleteDSObject(m_ADsPackageContainer, szRDN);
if (szRDN)
FreeADsMem(szRDN);
if (SUCCEEDED(hr))
{
//
// Update Store Usn
//
UpdateStoreUsn(m_ADsContainer, szUsn);
}
return hr;
}
//---------------------------------------------------------------
// Function: RemovePackage
//
// Synopsis: Mark a package as disabled or orphaned
// Or permanently remove a package and the associated Classes
// from class store
//
// Arguments:
// [in]
// PackageGuid
// Guid of the package that has to be removed.
// [in]
// dwFlags
// The new flags for the package. To delete the package explicitly
// use flag zero or orphan.
//
// Returns:
// S_OK, E_OUTOFMEMORY, E_INVALIDARG, CS_E_XXX
//
// Calls Delete package if the flags is zero or Orphan.
// Otherwise it sets the new flags and stamps the new time stamp.
//----------------------------------------------------------------
HRESULT CClassContainer::RemovePackage (
LPOLESTR pszPackageName,
DWORD dwFlags
)
{
HRESULT hr = S_OK;
WCHAR *szRDN = NULL, *szFullName = NULL;
HANDLE hADs = NULL;
WCHAR szUsn[20];
ADS_ATTR_INFO pAttr[7];
DWORD cAttr = 0, cModified = 0, i=0;
if ((dwFlags != 0) && !(dwFlags & ACTFLG_Orphan) && !(dwFlags & ACTFLG_Uninstall))
return E_INVALIDARG;
hr = GetDNFromPackageName(pszPackageName, &szFullName);
ERROR_ON_FAILURE(hr);
if (hr != S_OK)
return CS_E_OBJECT_NOTFOUND;
if (dwFlags == 0)
// delete the package from the class store
{
hr = DeletePackage(szFullName);
}
else
{
GUID NewPackageId;
WCHAR szNewRDN[_MAX_PATH], *szJunk = NULL;
DWORD dwPackageFlags;
WCHAR wszSearchFlags[MAX_SEARCH_FLAGS];
//
// PackageName is unchanged.
//
GetCurrentUsn(szUsn);
// Bind to the Package Object.
hr = DSServerOpenDSObject(&m_ServerContext, szFullName, GetDsFlags(), &hADs);
ERROR_ON_FAILURE(hr);
//
// We use GetConsistentPackageFlags so that we can add in one flag without
// resetting the existing flags in the attribute.
//
hr = GetConsistentPackageFlags(
hADs,
&dwFlags,
NULL,
NULL,
NULL,
&dwPackageFlags,
wszSearchFlags);
ERROR_ON_FAILURE(hr);
// setting the flag as orphan/uninstall
PackDWToAttr (pAttr+cAttr, PACKAGEFLAGS, dwPackageFlags);
cAttr++;
if (*wszSearchFlags)
{
PackStrToAttr(pAttr+cAttr, SEARCHFLAGS, wszSearchFlags);
cAttr++;
}
// stamping the modification time for cleanup later.
PackStrToAttr (pAttr+cAttr, PKGUSN, szUsn);
cAttr++;
hr = ADSISetObjectAttributes(hADs, pAttr, cAttr, &cModified);
if (hADs)
ADSICloseDSObject(hADs);
for (i = 0; i < cAttr; i++)
FreeAttr(pAttr[i]);
if (SUCCEEDED(hr))
{
//
// Update Class Store Usn
//
UpdateStoreUsn(m_ADsContainer, szUsn);
}
}
Error_Cleanup:
if (szFullName)
CsMemFree(szFullName);
return RemapErrorCode(hr, m_szContainerName);
}
// Merges list1 and List2 into ResList removing duplicates.
HRESULT MergePropList(LPOLESTR *List1, DWORD cList1,
LPOLESTR *List2, DWORD cList2,
LPOLESTR **ResList,DWORD *cResList)
{
DWORD i, j;
*cResList = 0;
*ResList = (LPOLESTR *)CsMemAlloc(sizeof(LPOLESTR)*(cList1+cList2));
if (!*ResList)
return E_OUTOFMEMORY;
for (i = 0; i < cList1; i++)
(*ResList)[i] = List1[i];
for (i = 0; i < cList2; i++) {
for (j = 0; j < cList1; j++)
if (wcscmp((*ResList)[j], List2[i]) == 0)
break;
if (j == cList1)
(*ResList)[(*cResList)++] = List2[i];
}
return S_OK;
}
#define SCRIPT_IN_DIRECTORY 256
//---------------------------------------------------------------
// Function: RedeployPackage
//
// Synopsis: Redeploys an package object in the DS with new
// package detail information
//
// Arguments:
//
// [in]
// pPackageGuid
// Points to a guid indicating the package we wish
// to redeploy
//
// [in]
// pPackageDetail
// Pointer to a PACKAGEDETAIL info for this package
// The various validations that is done is documented
// in associated class store doc.
//
// Returns:
// S_OK, E_OUTOFMEMORY, E_INVALIDARG, CS_E_XXX
//
// Validates the packagedetail structure. Packs ADS_ATTR_INFO structure with
// the values and sets those attributes on the existing object in the ds.
// If this returns an error the existing package is unaffected.
//
//----------------------------------------------------------------
HRESULT CClassContainer::RedeployPackage (
GUID* pPackageGuid,
PACKAGEDETAIL *pPackageDetail
)
{
HANDLE hExistingPackage;
HRESULT hr;
WCHAR* szFullName;
hExistingPackage = NULL;
szFullName = NULL;
//
// First, get the dn for the existing package
//
hr = BuildDNFromPackageGuid(*pPackageGuid, &szFullName);
ERROR_ON_FAILURE(hr);
//
// Bind to the existing package
//
hr = DSServerOpenDSObject( &m_ServerContext,
szFullName,
GetDsFlags(),
&hExistingPackage);
ERROR_ON_FAILURE(hr);
//
// Now we can redeploy it with the new package detail. We
// pass in a NULL package guid param because we won't
// be changing the package id.
//
hr = DeployPackage(
hExistingPackage,
pPackageDetail,
NULL);
Error_Cleanup:
if (szFullName)
{
CsMemFree(szFullName);
}
if (hExistingPackage)
{
ADSICloseDSObject(hExistingPackage);
}
return hr;
}
//---------------------------------------------------------------
// Function: AddPackage
//
// Synopsis: Adds a package object in the DS.
//
// Arguments:
// [out]
// pszPackageId
// An Id that is returned corresponding to the package.
// [in]
// pPackageDetail
// Pointer to a PACKAGEDETAIL info for this package
// The various validations that is done is documented
// in associated class store doc.
//
// Returns:
// S_OK, E_OUTOFMEMORY, E_INVALIDARG, CS_E_XXX
//
// Validates the packagedetail structure. Packs ADS_ATTR_INFO structure with
// the values and tries to create the object in the DS.
// If this returns error
// the whole package is removed.
//----------------------------------------------------------------
HRESULT CClassContainer::AddPackage (
PACKAGEDETAIL *pPackageDetail,
GUID *pPkgGuid
)
{
//
// Validate parameters specific to AddPackage, then
// let the DeployPackage function do the rest of the validation
// common between this and other methods that use it
//
if (!pPkgGuid || IsBadReadPtr(pPkgGuid, sizeof(GUID)))
{
return E_INVALIDARG;
}
return DeployPackage(
NULL, // create a new package
pPackageDetail,
pPkgGuid);
}
//---------------------------------------------------------------
// Function: DeployPackage
//
// Synopsis: Deploys a package object in the DS.
//
// Arguments:
// [in]
// hExistingPackage
// Handle to an existing package to redeploy. If NULL,
// a new package is created
//
// [out]
// pszPackageId
// An Id that is returned corresponding to a new package.
// Must be specified if hExistingPackage is NULL. Not set
// on return of hExistingPackage is non-NULL.
//
// [in]
// pPackageDetail
// Pointer to a PACKAGEDETAIL info for this package
// The various validations that is done is documented
// in associated class store doc.
//
// Returns:
// S_OK, E_OUTOFMEMORY, E_INVALIDARG, CS_E_XXX
//
// Validates the packagedetail structure. Packs ADS_ATTR_INFO structure with
// the values and tries to create and / or set attributes
// for the package the object in the DS.
// If this returns error when creating a new package, the whole package is removed.
// If this returns error when redeploying an existing package, the existing
// package is unaffected.
//----------------------------------------------------------------
HRESULT CClassContainer::DeployPackage(
HANDLE hExistingPackage,
PACKAGEDETAIL *pPackageDetail,
GUID *pPkgGuid
)
{
HRESULT hr = S_OK;
WCHAR szRDN [_MAX_PATH];
LPOLESTR * pszGuid1 = NULL, *pszGuid2 = NULL,
* pszGuid3 = NULL, *pszGuid4 = NULL,
* pszProgId = NULL, *pszFileExt = NULL,
* rpszUpgrades = NULL, *rpszSources = NULL,
szPackageId = NULL, szJunk = NULL;
DWORD * pdwArch=NULL, count = 0, cPackProgId = 0;
ADS_ATTR_INFO pAttr[30];
DWORD cAttr = 0;
WCHAR szUsn[20];
BOOL fPackageCreated = FALSE, GenerateGuid = FALSE;
GUID PackageGuidId;
DWORD dwPersistedPackageFlags;
WCHAR wszSearchFlags[MAX_SEARCH_FLAGS];
BOOL bCreateNewPackage;
bCreateNewPackage = hExistingPackage ? FALSE : TRUE;
if ((!(pPackageDetail->pszPackageName)) ||
IsBadStringPtr((pPackageDetail->pszPackageName), _MAX_PATH))
return E_INVALIDARG;
if (!pPackageDetail)
return E_INVALIDARG;
if (IsBadReadPtr(pPackageDetail, sizeof(PACKAGEDETAIL)))
return E_INVALIDARG;
// validating ActivationInfo.
if (pPackageDetail->pActInfo)
{
if (IsBadReadPtr(pPackageDetail->pActInfo, sizeof(ACTIVATIONINFO)))
return E_INVALIDARG;
if (IsBadReadPtr(pPackageDetail->pActInfo->pClasses,
sizeof(CLASSDETAIL) * (pPackageDetail->pActInfo->cClasses)))
return E_INVALIDARG;
// validating classdetail
for (count = 0; (count < (pPackageDetail->pActInfo->cClasses)); count++)
{
CLASSDETAIL *pClassDetail = (pPackageDetail->pActInfo->pClasses)+count;
if (IsNullGuid(pClassDetail->Clsid))
return E_INVALIDARG;
for (DWORD count1 = 0; (count1 < (pClassDetail->cProgId)); count1++)
{
// if profid is NULL or an empty string.
if ((!((pClassDetail->prgProgId)[count1])) ||
(!((pClassDetail->prgProgId)[count1][0])))
return E_INVALIDARG;
}
}
if (IsBadReadPtr(pPackageDetail->pActInfo->prgShellFileExt,
sizeof(LPOLESTR) * (pPackageDetail->pActInfo->cShellFileExt)))
return E_INVALIDARG;
for (count = 0; count < (pPackageDetail->pActInfo->cShellFileExt); count++)
{
if (!pPackageDetail->pActInfo->prgShellFileExt[count])
return E_INVALIDARG;
}
if (IsBadReadPtr(pPackageDetail->pActInfo->prgPriority,
sizeof(UINT) * (pPackageDetail->pActInfo->cShellFileExt)))
return E_INVALIDARG;
if (IsBadReadPtr(pPackageDetail->pActInfo->prgInterfaceId,
sizeof(IID) * (pPackageDetail->pActInfo->cInterfaces)))
return E_INVALIDARG;
if (IsBadReadPtr(pPackageDetail->pActInfo->prgTlbId,
sizeof(GUID) * (pPackageDetail->pActInfo->cTypeLib)))
return E_INVALIDARG;
}
// Validating InstallInfo
if ((pPackageDetail->pInstallInfo == NULL) ||
(IsBadReadPtr(pPackageDetail->pInstallInfo, sizeof(INSTALLINFO)))
)
return E_INVALIDARG;
//
// Only validate the product code if we expect one to be
// supplied -- this is only the case if this is a Windows
// Installer package, other deployments will not have
// a product code
//
if ( DrwFilePath == pPackageDetail->pInstallInfo->PathType )
{
if (IsNullGuid(pPackageDetail->pInstallInfo->ProductCode))
return E_INVALIDARG;
}
if (IsBadReadPtr(pPackageDetail->pInstallInfo->prgUpgradeInfoList,
sizeof(UPGRADEINFO)*(pPackageDetail->pInstallInfo->cUpgrades)))
return E_INVALIDARG;
for (count = 0; count < (pPackageDetail->pInstallInfo->cUpgrades); count++)
{
if ((!(pPackageDetail->pInstallInfo->prgUpgradeInfoList[count].szClassStore)) ||
IsBadStringPtr((pPackageDetail->pInstallInfo->prgUpgradeInfoList[count].szClassStore), _MAX_PATH))
return E_INVALIDARG;
if (IsNullGuid(pPackageDetail->pInstallInfo->prgUpgradeInfoList[count].PackageGuid))
return E_INVALIDARG;
if (((pPackageDetail->pInstallInfo->prgUpgradeInfoList[count].Flag & UPGFLG_Uninstall) == 0) &&
((pPackageDetail->pInstallInfo->prgUpgradeInfoList[count].Flag & UPGFLG_NoUninstall) == 0) &&
((pPackageDetail->pInstallInfo->prgUpgradeInfoList[count].Flag & UPGFLG_UpgradedBy) == 0))
return E_INVALIDARG;
}
// validating PlatformInfo
if ((pPackageDetail->pPlatformInfo == NULL) ||
(IsBadReadPtr(pPackageDetail->pPlatformInfo, sizeof(PLATFORMINFO)))
)
return E_INVALIDARG;
if (IsBadReadPtr(pPackageDetail->pPlatformInfo->prgPlatform,
sizeof(CSPLATFORM) * (pPackageDetail->pPlatformInfo->cPlatforms)))
return E_INVALIDARG;
if ((pPackageDetail->pPlatformInfo->cLocales == 0) ||
(pPackageDetail->pPlatformInfo->cPlatforms == 0))
return E_INVALIDARG;
if (IsBadReadPtr(pPackageDetail->pPlatformInfo->prgLocale,
sizeof(LCID) * (pPackageDetail->pPlatformInfo->cLocales)))
return E_INVALIDARG;
// validating InstallInfo
// Validating other fields in PackageDetail structure
if ((pPackageDetail->pszSourceList == NULL) ||
(IsBadReadPtr(pPackageDetail->pszSourceList,
sizeof(LPOLESTR) * (pPackageDetail->cSources))))
return E_INVALIDARG;
for (count = 0; count < (pPackageDetail->cSources); count++)
{
if ((!pPackageDetail->pszSourceList[count]) ||
(IsBadStringPtr(pPackageDetail->pszSourceList[count], _MAX_PATH)))
return E_INVALIDARG;
}
if (pPackageDetail->rpCategory)
{
if (IsBadReadPtr(pPackageDetail->rpCategory,
sizeof(GUID) * (pPackageDetail->cCategories)))
return E_INVALIDARG;
}
// If the restrictions are too constrictive then we should go to
// the DS, to see whether it is a valid name or not. till then..
hr = GetDNFromPackageName(pPackageDetail->pszPackageName, &szJunk);
if (szJunk)
CsMemFree(szJunk);
if (FAILED(hr))
return RemapErrorCode(hr, m_szContainerName);
//
// We expect this to return S_ADS_NOMORE_ROWS if the package doesn't
// exist, otherwise it returns S_OK -- we can use this to determine
// if the package exists already (we care only if we're trying to
// create a new package)
//
if ( bCreateNewPackage && (hr == S_OK))
{
return CS_E_OBJECT_ALREADY_EXISTS;
}
else
{
ASSERT( bCreateNewPackage || (S_ADS_NOMORE_ROWS == hr) || ( hExistingPackage && (hr == S_OK) ) );
}
szPackageId = (LPOLESTR)CsMemAlloc(sizeof(WCHAR)*41);
if (!(szPackageId))
return E_OUTOFMEMORY;
memset(&PackageGuidId, 0, sizeof(GUID));
//
// generate guid if we are creating a new package -- otherwise, we don't
// need it
//
if (bCreateNewPackage)
{
CreateGuid(&PackageGuidId);
StringFromGUID(PackageGuidId, szPackageId);
//
// Create the RDN for the Package Object
//
hr = StringCchPrintf(szRDN, _MAX_PATH, L"CN=%s", szPackageId);
ERROR_ON_FAILURE(hr);
//
// Only set this attribute when creating a new object --
// Otherwise, a constraint violation will occur since it is
// not permissible to change an object's class
//
PackStrToAttr(pAttr+cAttr, OBJECTCLASS, CLASS_CS_PACKAGE); cAttr++;
}
// fill in the activation info
// add the class to the packagecontainer list
//
// Classes are not present during redeploy operations in a domain rename because
// GetPackageDetails does not return the classes. Normally, the ade regenerates
// the classes during redeploy, so this is not an issue, but for domain rename,
// class regeneration is time consuming and may generate different results
// due to the class generation api's (in Darwin) dependency on local state.
//
// We check for a special flag, ACTFLG_PreserveClasses to see if we should
// skip writing clsid's and progid's
//
BOOL bIgnoreClasses;
bIgnoreClasses = pPackageDetail->pInstallInfo->dwActFlags & ACTFLG_PreserveClasses;
if (pPackageDetail->pActInfo)
{
BOOL bWriteClasses;
BOOL bWriteEmptyValue;
UINT cClasses;
UINT cSourceClasses;
bWriteClasses = pPackageDetail->pActInfo->bHasClasses && ! bIgnoreClasses;
bWriteEmptyValue = ! pPackageDetail->pActInfo->bHasClasses;
cClasses = 0;
cSourceClasses = pPackageDetail->pActInfo->cClasses;
cPackProgId = 0;
if ( ! pPackageDetail->pActInfo->bHasClasses )
{
cSourceClasses = 0;
}
//
// To be consistent with NT5, we will not set the clsid or progid properties when the user has specified
// that we deploy classes but there are none. If the user has not specified that we should deploy
// classes, we will still set this property, but it will be zero-length
//
if ( bWriteClasses )
{
if ( cSourceClasses )
{
pszGuid1 = (LPOLESTR *)CsMemAlloc(cSourceClasses*sizeof(LPOLESTR));
if (!pszGuid1) {
ERROR_ON_FAILURE(hr = E_OUTOFMEMORY);
}
for (count = 0; count < cSourceClasses; count++)
{
WCHAR szCtx[10];
pszGuid1[count] = (LPOLESTR)CsMemAlloc(sizeof(WCHAR)*(STRINGGUIDLEN+9));
if (!pszGuid1[count]) {
FREEARR(pszGuid1, count);
ERROR_ON_FAILURE(hr = E_OUTOFMEMORY);
}
StringFromGUID(pPackageDetail->pActInfo->pClasses[count].Clsid, pszGuid1[count]);
hr = StringCchPrintf(szCtx, sizeof(szCtx)/sizeof(szCtx[0]), L":%8x", pPackageDetail->pActInfo->pClasses[count].dwComClassContext);
ERROR_ON_FAILURE(hr);
hr = StringCchCat(pszGuid1[count], STRINGGUIDLEN+9, szCtx);
ERROR_ON_FAILURE(hr);
cPackProgId += pPackageDetail->pActInfo->pClasses[count].cProgId;
}
cClasses = cSourceClasses;
}
}
//
// This flag should not be persisted in the ds, only used as a hint for redeploy
// to avoid overwriting the existing classes
//
pPackageDetail->pInstallInfo->dwActFlags &= ~ACTFLG_PreserveClasses;
LPOLESTR wszNullGuid;
LPOLESTR* ppszClsids;
ppszClsids = pszGuid1;
//
// If required, write the blank clsid value so that
// the NT 5.1 ADE can determine if this package has class information. Note that
// an NT 5.0 ADE will never see this because this uses a null guid -- both
// NT 5.0 and 5.1 ADE's will never accept a request from a caller to search
// for a null guid.
//
if ( bWriteEmptyValue )
{
wszNullGuid = PKG_EMPTY_CLSID_VALUE;
ppszClsids = &wszNullGuid;
cClasses = 1;
}
//
// If there are no clsids, this will cause the value to be cleared
//
if ( ( cClasses || ! bCreateNewPackage ) && ! bIgnoreClasses )
{
PackStrArrToAttr(pAttr+cAttr, PKGCLSIDLIST, ppszClsids, cClasses); cAttr++;
}
if ( bWriteClasses )
{
// collecting all the progids from the various clsids.
pszProgId = (LPOLESTR *)CsMemAlloc(sizeof(LPOLESTR)*cPackProgId);
if (!pszProgId) {
hr = E_OUTOFMEMORY;
ERROR_ON_FAILURE(hr);
}
//
// Reset our count of progid's -- we need to check for duplicates, so we
// do not assume that we will have as many progid's as we allocated space for above --
// we will increment the count for each unique progid we encounter.
//
cPackProgId = 0;
for (count = 0; count < cSourceClasses; count++) {
// for each clsid
DWORD cClassProgId, j = 0;
for (cClassProgId = 0; cClassProgId < pPackageDetail->pActInfo->pClasses[count].cProgId;
cClassProgId++)
{
// for each progid within ClassDetail
for (j = 0; j < cPackProgId; j++)
{
if (_wcsicmp(pszProgId[j],
pPackageDetail->pActInfo->pClasses[count].prgProgId[cClassProgId]) == 0)
break;
}
// needs to be added if there are no dups.
if (j == cPackProgId)
{
pszProgId[cPackProgId] =
pPackageDetail->pActInfo->pClasses[count].prgProgId[cClassProgId];
_wcslwr(pszProgId[cPackProgId]);
cPackProgId++;
}
}
}
}
else
{
//
// Reset this so that we clear out progid's if we are not writing any
//
cPackProgId = 0;
}
//
// If there are no clsids, this will cause the value to be cleared
//
if ( ( cPackProgId || ! bCreateNewPackage ) && ! bIgnoreClasses )
{
PackStrArrToAttr(pAttr+cAttr, PROGIDLIST, pszProgId, cPackProgId); cAttr++;
}
CsMemFree(pszProgId);
if (pPackageDetail->pActInfo->cShellFileExt) {
ULONG ulSize;
//
// Store a tuple in the format <file ext>:<priority>
//
pszFileExt = (LPOLESTR *)CsMemAlloc((pPackageDetail->pActInfo->cShellFileExt) * sizeof(LPOLESTR));
if (!pszFileExt)
{
hr = E_OUTOFMEMORY;
ERROR_ON_FAILURE(hr);
}
for (count = 0; count < pPackageDetail->pActInfo->cShellFileExt; count++)
{
ulSize = wcslen(pPackageDetail->pActInfo->prgShellFileExt[count])+1+2+1;
pszFileExt[count] = (LPOLESTR)CsMemAlloc(sizeof(WCHAR) *ulSize);
if (!pszFileExt[count])
{
FREEARR(pszFileExt, count);
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
}
// format is fileext+:+nn+NULL where nn = 2 digit priority
hr = StringCchPrintf(pszFileExt[count], ulSize, L"%s:%2d",
pPackageDetail->pActInfo->prgShellFileExt[count],
pPackageDetail->pActInfo->prgPriority[count]%100);
ERROR_ON_FAILURE(hr);
_wcslwr(pszFileExt[count]);
}
PackStrArrToAttr(pAttr+cAttr, PKGFILEEXTNLIST, pszFileExt,
pPackageDetail->pActInfo->cShellFileExt); cAttr++;
}
//
// Note: we no longer persist interfaces in the ds as this information
// is not used
//
}
// fill in the platforminfo
//
// Note that the os version contained in this structure is not referenced in the os
//
if (pPackageDetail->pPlatformInfo->cPlatforms) {
pdwArch = (DWORD *)CsMemAlloc(sizeof(DWORD)*(pPackageDetail->pPlatformInfo->cPlatforms));
if (!pdwArch)
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
for (count = 0; (count < (pPackageDetail->pPlatformInfo->cPlatforms)); count++)
UnpackPlatform (pdwArch+count, (pPackageDetail->pPlatformInfo->prgPlatform)+count);
PackDWArrToAttr(pAttr+cAttr, ARCHLIST, pdwArch, pPackageDetail->pPlatformInfo->cPlatforms);
cAttr++;
}
if (pPackageDetail->pPlatformInfo->cLocales) {
PackDWArrToAttr(pAttr+cAttr, LOCALEID, pPackageDetail->pPlatformInfo->prgLocale,
pPackageDetail->pPlatformInfo->cLocales);
cAttr++;
}
// fill in the installinfo
PackStrToAttr(pAttr+cAttr, PACKAGENAME, pPackageDetail->pszPackageName);
cAttr++;
// also include display name so that outside tools can get a friendly description
PackStrToAttr(pAttr+cAttr, PKGDISPLAYNAME, pPackageDetail->pszPackageName);
cAttr++;
PackDWToAttr(pAttr+cAttr, PACKAGETYPE, (DWORD)(pPackageDetail->pInstallInfo->PathType));
cAttr++;
if (pPackageDetail->pInstallInfo->pszScriptPath) {
PackStrToAttr(pAttr+cAttr, SCRIPTPATH, pPackageDetail->pInstallInfo->pszScriptPath);
cAttr++;
}
if (pPackageDetail->pInstallInfo->pszSetupCommand) {
PackStrToAttr(pAttr+cAttr, SETUPCOMMAND, pPackageDetail->pInstallInfo->pszSetupCommand);
cAttr++;
}
if (pPackageDetail->pInstallInfo->pszUrl) {
PackStrToAttr(pAttr+cAttr, HELPURL, pPackageDetail->pInstallInfo->pszUrl);
cAttr++;
}
//
// Store the current USN
//
GetCurrentUsn(szUsn);
PackStrToAttr(pAttr+cAttr, PKGUSN, szUsn);
cAttr++;
// package flags
dwPersistedPackageFlags = pPackageDetail->pInstallInfo->dwActFlags |
ACTFLG_POSTBETA3;
//
// Now set the flags so that they reflect the state of this package
//
hr = GetConsistentPackageFlags(
NULL,
&dwPersistedPackageFlags,
&(pPackageDetail->pInstallInfo->cUpgrades),
&(pPackageDetail->pInstallInfo->InstallUiLevel),
&(pPackageDetail->pInstallInfo->PathType),
&dwPersistedPackageFlags,
wszSearchFlags);
ERROR_ON_FAILURE(hr);
//
// Add in a flag indicating this is a post-Beta 3 deployment
//
PackDWToAttr(pAttr+cAttr, PACKAGEFLAGS, dwPersistedPackageFlags);
cAttr++;
if (*wszSearchFlags)
{
PackStrToAttr(pAttr+cAttr, SEARCHFLAGS, wszSearchFlags);
cAttr++;
}
// product code, different from pkg guid
PackGUIDToAttr(pAttr+cAttr, PRODUCTCODE, &(pPackageDetail->pInstallInfo->ProductCode));
cAttr++;
// Mvipc
PackGUIDToAttr(pAttr+cAttr, MVIPC, &(pPackageDetail->pInstallInfo->Mvipc));
cAttr++;
// Hi Version of the package
PackDWToAttr(pAttr+cAttr, VERSIONHI, pPackageDetail->pInstallInfo->dwVersionHi);
cAttr++;
// Low Version of the package
PackDWToAttr(pAttr+cAttr, VERSIONLO, pPackageDetail->pInstallInfo->dwVersionLo);
cAttr++;
// Revision
PackDWToAttr(pAttr+cAttr, REVISION, pPackageDetail->pInstallInfo->dwRevision);
cAttr++;
// uilevel
PackDWToAttr (pAttr+cAttr, UILEVEL, (DWORD)pPackageDetail->pInstallInfo->InstallUiLevel);
cAttr++;
// adding cUpgrade number of Classstore/PackageGuid combinations
if (pPackageDetail->pInstallInfo->cUpgrades)
{
WCHAR szPackageGuid[_MAX_PATH];
rpszUpgrades = (LPOLESTR *)CsMemAlloc(sizeof(LPOLESTR)*pPackageDetail->pInstallInfo->cUpgrades);
if (!rpszUpgrades)
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
for (count = 0; (count < pPackageDetail->pInstallInfo->cUpgrades); count++)
{
UINT len = wcslen(pPackageDetail->pInstallInfo->prgUpgradeInfoList[count].szClassStore);
ULONG ulSize = 36+PKG_UPG_DELIM1_LEN+len+PKG_UPG_DELIM2_LEN+2+2;
rpszUpgrades[count] = (LPOLESTR)CsMemAlloc(sizeof(WCHAR) *ulSize);
// Guid size+::+length++:+flagDigit+2
if (!rpszUpgrades[count])
{
FREEARR(rpszUpgrades, count);
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
}
StringFromGUID(pPackageDetail->pInstallInfo->prgUpgradeInfoList[count].PackageGuid,
szPackageGuid);
hr = StringCchPrintf(rpszUpgrades[count], ulSize, L"%s%s%s%s%02x",
pPackageDetail->pInstallInfo->prgUpgradeInfoList[count].szClassStore,
PKG_UPG_DELIMITER1,
szPackageGuid,
PKG_UPG_DELIMITER2,
pPackageDetail->pInstallInfo->prgUpgradeInfoList[count].Flag%16);
ERROR_ON_FAILURE(hr);
}
PackStrArrToAttr(pAttr+cAttr, UPGRADESPACKAGES, rpszUpgrades,
pPackageDetail->pInstallInfo->cUpgrades);
cAttr++;
}
// Fill in the source list
// Maintain the serial number associated with the sources. Order matters!!
if (pPackageDetail->cSources)
{
rpszSources = (LPOLESTR *)CsMemAlloc(sizeof(LPOLESTR)*(pPackageDetail->cSources));
if (!rpszSources)
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
for (count = 0; count < (pPackageDetail->cSources); count++)
{
ULONG ulSize = wcslen(pPackageDetail->pszSourceList[count])+1+1+NumDigits10(pPackageDetail->cSources);
rpszSources[count] = (LPOLESTR)CsMemAlloc(sizeof(WCHAR)* ulSize);
if (!rpszSources[count])
{
FREEARR(rpszSources, count);
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
}
hr = StringCchPrintf(rpszSources[count], ulSize, L"%d:%s", count, pPackageDetail->pszSourceList[count]);
ERROR_ON_FAILURE(hr);
}
PackStrArrToAttr(pAttr+cAttr, MSIFILELIST, rpszSources, pPackageDetail->cSources);
cAttr++;
}
// fill in the categories
// Add the package Categories
if (pPackageDetail->cCategories)
{
pszGuid4 = (LPOLESTR *)CsMemAlloc((pPackageDetail->cCategories) * sizeof(LPOLESTR));
if (!pszGuid4)
{
ERROR_ON_FAILURE(hr = E_OUTOFMEMORY);
}
for (count = 0; (count < pPackageDetail->cCategories); count++)
{
pszGuid4[count] = (LPOLESTR)CsMemAlloc(STRINGGUIDLEN*sizeof(WCHAR));
if (!pszGuid4[count])
{
FREEARR(pszGuid4, count);
ERROR_ON_FAILURE(hr = E_OUTOFMEMORY);
}
StringFromGUID((pPackageDetail->rpCategory)[count], pszGuid4[count]);
}
PackStrArrToAttr(pAttr+cAttr, PKGCATEGORYLIST, pszGuid4, pPackageDetail->cCategories);
cAttr++;
}
// fill in the vendor
// Publisher
if (pPackageDetail->pszPublisher)
{
PackStrToAttr(pAttr+cAttr, PUBLISHER, pPackageDetail->pszPublisher);
cAttr++;
}
//
// Create a new package if specified by the caller
//
if (bCreateNewPackage)
{
hr = ADSICreateDSObject(m_ADsPackageContainer, szRDN, pAttr, cAttr);
ERROR_ON_FAILURE(hr);
memset(pPkgGuid, 0, sizeof(GUID));
hr = GetPackageGuid(szRDN, pPkgGuid);
}
else
{
DWORD cModified;
//
// The caller specified us to use an existing package -- do not
// create a new one, just set the attributes for the existing package.
// The ADSISetObjectAttributes call will either set all attributes or
// none -- so if it fails, the package is just as it was
// before we attempted to redeploy.
//
hr = ADSISetObjectAttributes(hExistingPackage, pAttr, cAttr, &cModified);
}
ERROR_ON_FAILURE(hr);
fPackageCreated = bCreateNewPackage ? TRUE : FALSE;
if (!(pPackageDetail->pInstallInfo->dwActFlags & ACTFLG_Uninstall) &&
!(pPackageDetail->pInstallInfo->dwActFlags & ACTFLG_Orphan))
{
if (pPackageDetail->pInstallInfo->cUpgrades)
{
for (count = 0; (count < pPackageDetail->pInstallInfo->cUpgrades); count++)
CsMemFree(rpszUpgrades[count]);
CsMemFree(rpszUpgrades);
}
}
if (SUCCEEDED(hr))
{
//
// Update Store Usn
//
UpdateStoreUsn(m_ADsContainer, szUsn);
}
Error_Cleanup:
for (count = 0; count < cAttr; count++)
FreeAttr(pAttr[count]);
if (pszGuid1) {
for (count = 0; (count < pPackageDetail->pActInfo->cClasses); count++)
CsMemFree(pszGuid1[count]);
CsMemFree(pszGuid1);
}
if (pszGuid2) {
for (count = 0; (count < (pPackageDetail->pActInfo->cInterfaces)); count++)
CsMemFree(pszGuid2[count]);
CsMemFree(pszGuid2);
}
if (pszGuid3) {
for (count = 0; (count < (pPackageDetail->pActInfo->cTypeLib)); count++)
CsMemFree(pszGuid3[count]);
CsMemFree(pszGuid3);
}
if (pszGuid4) {
for (count = 0; (count < pPackageDetail->cCategories); count++)
CsMemFree(pszGuid4[count]);
CsMemFree(pszGuid4);
}
if (pszFileExt) {
for (count = 0; (count < pPackageDetail->pActInfo->cShellFileExt); count++)
CsMemFree(pszFileExt[count]);
CsMemFree(pszFileExt);
}
if (pdwArch) {
CsMemFree(pdwArch);
}
if (rpszSources)
{
for (count = 0; (count < pPackageDetail->cSources); count++)
CsMemFree(rpszSources[count]);
CsMemFree(rpszSources);
}
//
// On failure, the package should be removed from the ds if we
// created it there.
//
if (FAILED(hr) && (fPackageCreated))
{
HRESULT hrDeleted;
LPWSTR wszPackageFullPath;
//
// Need to get a full path to the package in order to delete it.
//
hrDeleted = BuildADsPathFromParent(m_szPackageName, szRDN, &wszPackageFullPath);
ASSERT(SUCCEEDED(hrDeleted));
CSDBGPrint((DM_WARNING, IDS_CSTORE_ROLLBACK_ADD, wszPackageFullPath));
hrDeleted = DeletePackage(wszPackageFullPath);
//
// Free the full path
//
CsMemFree(wszPackageFullPath);
}
return RemapErrorCode(hr, m_szContainerName);
}
//+
//
// Cleanup old packages from Class Store based on lastChangeTime
//
HRESULT CClassContainer::Cleanup (
FILETIME *pTimeBefore
)
{
//
// Delete all packages marked as "Uninstall"
// OR "Orphan" and are older than the time given
//
ULONG cRowsFetched = 0;
ADS_SEARCH_HANDLE hADsSearchHandle = NULL;
WCHAR szFilter[_MAX_PATH], szRDN[_MAX_PATH];
HRESULT hr = S_OK;
ADS_ATTR_INFO pAttr;
SYSTEMTIME SystemTime;
ADS_SEARCH_COLUMN column;
DWORD dwPackageFlags;
LPOLESTR pszPackageId = NULL;
if ((!pTimeBefore) ||
IsBadReadPtr(pTimeBefore, sizeof(FILETIME)))
return E_INVALIDARG;
FileTimeToSystemTime(
(CONST FILETIME *) pTimeBefore,
&SystemTime);
hr = StringCchPrintf (szFilter,
_MAX_PATH,
L"(%s<=%04d%02d%02d%02d%02d%02d)",
PKGUSN,
SystemTime.wYear,
SystemTime.wMonth,
SystemTime.wDay,
SystemTime.wHour,
SystemTime.wMinute,
SystemTime.wSecond);
ERROR_ON_FAILURE(hr);
CSDBGPrint((DM_VERBOSE,
IDS_CSTORE_CLEANSCRIPTS,
SystemTime.wMonth,
SystemTime.wDay,
SystemTime.wYear,
SystemTime.wHour,
SystemTime.wMinute,
SystemTime.wSecond));
// execute the search and keep the handle returned.
hr = ADSIExecuteSearch(m_ADsPackageContainer, szFilter, pszDeleteAttrNames,
cDeleteAttr, &hADsSearchHandle);
hr = ADSIGetFirstRow(m_ADsPackageContainer, hADsSearchHandle);
while (TRUE)
{
if ((FAILED(hr)) || (hr == S_ADS_NOMORE_ROWS))
break;
dwPackageFlags = 0;
// Get the Package State
hr = DSGetAndValidateColumn(m_ADsPackageContainer, hADsSearchHandle, ADSTYPE_INTEGER, PACKAGEFLAGS, &column);
if (SUCCEEDED(hr))
{
UnpackDWFrom(column, &dwPackageFlags);
ADSIFreeColumn(m_ADsPackageContainer, &column);
}
//
// Check flag values to see if this package is Orphaned or Uninstalled
//
if ((dwPackageFlags & ACTFLG_Orphan) || (dwPackageFlags & ACTFLG_Uninstall))
{
hr = DSGetAndValidateColumn(m_ADsPackageContainer, hADsSearchHandle, ADSTYPE_CASE_IGNORE_STRING, OBJECTDN, &column);
if (SUCCEEDED(hr))
{
WCHAR * szDN = NULL;
UnpackStrFrom(column, &szDN);
hr = DeletePackage(szDN);
CSDBGPrint((DM_WARNING,
IDS_CSTORE_DELPACKAGE,
szDN,
dwPackageFlags,
hr));
ADSIFreeColumn(m_ADsPackageContainer, &column);
ERROR_ON_FAILURE(hr);
}
}
hr = ADSIGetNextRow(m_ADsPackageContainer, hADsSearchHandle);
}
Error_Cleanup:
if (hADsSearchHandle)
ADSICloseSearchHandle(m_ADsPackageContainer, hADsSearchHandle);
return RemapErrorCode(hr, m_szContainerName);
}
HRESULT CClassContainer::GetGPOName( WCHAR** ppszPolicyName )
{
HRESULT hr;
HANDLE hGpo;
ADS_ATTR_INFO* pAttr;
LPOLESTR AttrNames[] = {GPNAME};
DWORD cgot;
DWORD posn;
WCHAR* wszGpoPath;
pAttr = NULL;
hGpo = NULL;
//
// This object contains the path to a class store container --
// this path is of the form LDAP://CN=ClassStore,CN=User,<gpopath>.
// This means that the gpo path is shorter than the class store path,
// and we can allocate memory accordingly.
//
DWORD cbClassStorePath;
cbClassStorePath = lstrlen( m_szContainerName ) * sizeof ( *m_szContainerName );
wszGpoPath = (WCHAR*) CsMemAlloc( cbClassStorePath );
if ( ! wszGpoPath )
{
hr = E_OUTOFMEMORY;
goto GetGpoName_ExitAndCleanup;
}
WCHAR* wszGpoSubPath;
//
// Get past the prefix
//
wszGpoSubPath = StripLinkPrefix( m_szContainerName );
//
// Now get past the next two delimiters
//
wszGpoSubPath = wcschr( wszGpoSubPath, L',' ) + 1;
wszGpoSubPath = wcschr( wszGpoSubPath, L',' );
//
// Move one past the last delimiter -- we are now at the gpo path
//
wszGpoSubPath++;
//
// Create the resultant path starting with the prefix
//
hr = StringCbCopy( wszGpoPath, cbClassStorePath, LDAPPREFIX );
if (FAILED(hr))
{
goto GetGpoName_ExitAndCleanup;
}
//
// Append the gpo path -- we now have a fully qualified
// LDAP path to the GPO
//
hr = StringCbCat( wszGpoPath, cbClassStorePath, wszGpoSubPath );
if (FAILED(hr))
{
goto GetGpoName_ExitAndCleanup;
}
hr = DSServerOpenDSObject(&m_ServerContext,
wszGpoPath,
GetDsFlags(),
&hGpo);
if (FAILED(hr))
{
goto GetGpoName_ExitAndCleanup;
}
//
// Now get the friendly name of this gpo
//
hr = ADSIGetObjectAttributes(
hGpo,
AttrNames,
sizeof(AttrNames) / sizeof(*AttrNames),
&pAttr,
&cgot);
if ( SUCCEEDED(hr) )
{
ASSERT( 1 == cgot );
UnpackStrAllocFrom(pAttr[0], ppszPolicyName);
if ( ! *ppszPolicyName )
{
hr = E_OUTOFMEMORY;
}
}
GetGpoName_ExitAndCleanup:
if ( pAttr )
{
FreeADsMem( pAttr );
}
if (hGpo)
{
ADSICloseDSObject( hGpo );
}
if (wszGpoPath)
{
CsMemFree( wszGpoPath );
}
return hr;
}