windows-nt/Source/XPSP1/NT/com/ole32/cs/cstore/csds.cxx
2020-09-26 16:20:57 +08:00

847 lines
22 KiB
C++

//
// Author: DebiM
// Date: January 97
//
//
// 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);
BOOL
CheckMatching (QUERYCONTEXT *pQryContext,
INSTALLINFO *pInstallInfo,
PLATFORMINFO *pPlatformInfo
);
extern LPOLESTR szInstallInfoColumns;
extern LPOLESTR szPackageInfoColumns;
void FreeInstallInfo(INSTALLINFO *pInstallInfo)
{
CoTaskMemFree(pInstallInfo->pszScriptPath);
CoTaskMemFree(pInstallInfo->pszSetupCommand);
CoTaskMemFree(pInstallInfo->pszUrl);
CoTaskMemFree(pInstallInfo->pClsid);
memset(pInstallInfo, 0, sizeof (INSTALLINFO));
}
void FreePlatformInfo(PLATFORMINFO *pPlatformInfo)
{
CoTaskMemFree(pPlatformInfo->prgLocale);
CoTaskMemFree(pPlatformInfo->prgPlatform);
}
//
// CAppContainer implementation
//
CAppContainer::CAppContainer()
{
m_fOpen = FALSE;
m_ADsContainer = NULL;
m_pADsClassStore = NULL;
m_ADsClassContainer = NULL;
m_ADsPackageContainer = NULL;
m_uRefs = 1;
StartQuery(&m_pIDBCreateCommand);
}
//
// CAppContainer implementation
//
CAppContainer::CAppContainer(LPOLESTR szStoreName,
HRESULT *phr)
{
IADs *pADs = NULL;
LPOLESTR pszName = NULL;
DWORD dwStoreVersion = 0;
*phr = S_OK;
#ifdef DBG
WCHAR Name[32];
DWORD NameSize = 32;
if ( ! GetUserName( Name, &NameSize ) )
CSDbgPrint(("CAppContainer::CAppContainer GetUserName failed 0x%x\n", GetLastError()));
else
CSDbgPrint(("CAppContainer::CAppContainer as %S\n", Name));
#endif
m_fOpen = FALSE;
m_ADsContainer = NULL;
m_pADsClassStore = NULL;
m_ADsClassContainer = NULL;
m_ADsPackageContainer = NULL;
//
// For every interface pointer, we create a separate session
//
StartQuery(&m_pIDBCreateCommand);
// Bind to a Class Store Container Object
// Cache the interface pointer
//
wcscpy (m_szContainerName, szStoreName);
*phr = ADsGetObject(
szStoreName,
IID_IADsContainer,
(void **)&m_ADsContainer
);
if (!SUCCEEDED(*phr))
return;
//
// Check the Schema Version of this container
//
*phr = m_ADsContainer->QueryInterface (IID_IADs, (void **)&m_pADsClassStore);
if (!SUCCEEDED(*phr))
return;
*phr = GetPropertyDW (m_pADsClassStore, STOREVERSION, &dwStoreVersion);
if ((!SUCCEEDED(*phr)) ||
(dwStoreVersion != SCHEMA_VERSION_NUMBER))
{
CSDbgPrint(("CS: .. Wrong Version of Class Container:%ws\n",
m_szContainerName));
*phr = CS_E_INVALID_VERSION;
return;
}
CSDbgPrint(("CS: .. Connected to Class Container:%ws\n",
m_szContainerName));
//
// Bind to the class container Object
// Cache the interface pointer
//
m_ADsClassContainer = NULL;
*phr = m_ADsContainer->GetObject(
NULL,
CLASSCONTAINERNAME,
(IDispatch **)&pADs);
if (!SUCCEEDED(*phr))
return;
pADs->QueryInterface(IID_IADsContainer,
(void **)&m_ADsClassContainer
);
*phr = pADs->get_ADsPath(&pszName);
wcscpy (m_szClassName, pszName);
SysFreeString(pszName);
pADs->Release();
pADs = NULL;
if (!SUCCEEDED(*phr))
return;
//
// Bind to the Package container Object
// Cache the interface pointer
//
m_ADsPackageContainer = NULL;
*phr = m_ADsContainer->GetObject(
NULL,
PACKAGECONTAINERNAME,
(IDispatch **)&pADs);
if (!SUCCEEDED(*phr))
return;
pADs->QueryInterface(IID_IADsContainer,
(void **)&m_ADsPackageContainer
);
*phr = pADs->get_ADsPath(&pszName);
wcscpy (m_szPackageName, pszName);
SysFreeString(pszName);
pADs->Release();
pADs = NULL;
if (!SUCCEEDED(*phr))
return;
m_fOpen = TRUE;
m_uRefs = 1;
}
CAppContainer::~CAppContainer(void)
{
UINT i;
EndQuery(m_pIDBCreateCommand);
m_pIDBCreateCommand = NULL;
if (m_fOpen)
{
//UnlistDB (this);
m_fOpen = FALSE;
}
if (m_ADsClassContainer)
{
m_ADsClassContainer->Release();
m_ADsClassContainer = NULL;
}
if (m_ADsPackageContainer)
{
m_ADsPackageContainer->Release();
m_ADsPackageContainer = NULL;
}
if (m_ADsContainer)
{
m_ADsContainer->Release();
m_ADsContainer = NULL;
}
if (m_pADsClassStore)
{
m_pADsClassStore->Release();
m_pADsClassStore = NULL;
}
}
HRESULT CAppContainer::GetPackageDetails (
LPOLESTR pszPackageName,
PACKAGEDETAIL *pPackageDetail)
{
HRESULT hr = S_OK;
IADs *pPackageADs = NULL;
WCHAR szRdn [_MAX_PATH];
wcscpy (szRdn, L"CN=");
wcscat (szRdn, pszPackageName);
hr = m_ADsPackageContainer->GetObject(NULL, szRdn, (IDispatch **)&pPackageADs);
if (!SUCCEEDED(hr))
return hr;
hr = GetPackageDetail (pPackageADs, pPackageDetail);
return hr;
}
//
// ::EnumPackages
//----------------
//
// Obtains an enumerator for packages in the app container.
// Takes the following optional filter specifications:
//
// [in] pszPackageName : Substring match for a package name
// [in] pCategory : Category id of interest
// [in] dwAppFlags : following bits set 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
//
//
HRESULT CAppContainer::EnumPackages (
LPOLESTR pszPackageName,
GUID *pCategory,
ULONGLONG *pLastUsn,
DWORD dwAppFlags,
IEnumPackage **ppIEnumPackage
)
{
HRESULT hr;
CEnumPackage *pEnum;
WCHAR szLdapFilter [2000];
UINT len;
UINT fFilters = 0;
LCID dwLocale, *pdwLocale;
CSPLATFORM *pPlatform, Platform;
if (!IsValidPtrOut(ppIEnumPackage, sizeof(IEnumPackage *)))
return E_INVALIDARG;
*ppIEnumPackage = NULL;
pEnum = new CEnumPackage;
if(NULL == pEnum)
return E_OUTOFMEMORY;
//
// Create a LDAP Search Filter based on input params
//
// Count Filters
if (pszPackageName && (*pszPackageName))
fFilters++;
if (pLastUsn)
fFilters++;
if (pCategory)
fFilters++;
if (dwAppFlags & APPINFO_ASSIGNED)
fFilters++;
if (fFilters == 0)
{
// No Conditionals
wsprintf (szLdapFilter,
L"<%s>;(objectClass=packageRegistration)",
m_szPackageName);
len = wcslen (szLdapFilter);
}
else
{
if (fFilters == 1)
{
wsprintf (szLdapFilter,
L"<%s>;",
m_szPackageName);
}
else
{
wsprintf (szLdapFilter,
L"<%s>;(&",
m_szPackageName);
}
len = wcslen (szLdapFilter);
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)
{
//
// Validate
//
if (!IsValidReadPtrIn(pLastUsn, sizeof(ULONGLONG)))
return E_INVALIDARG;
wsprintf (&szLdapFilter[len],
L"(%s>=%ul)",
PKGUSN,
*pLastUsn);
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;
}
}
//
// Now append the attribute list to the search string
//
wsprintf (&szLdapFilter[len], L";%s", szPackageInfoColumns);
//
// Check all local/platform flags
//
if (dwAppFlags & APPINFO_ALLLOCALE)
{
pdwLocale = NULL;
}
else
{
dwLocale = GetThreadLocale();
pdwLocale = &dwLocale;
}
if (dwAppFlags & APPINFO_ALLPLATFORM)
{
pPlatform = NULL;
}
else
{
pPlatform = &Platform;
GetDefaultPlatform(pPlatform);
}
hr = pEnum->Initialize(szLdapFilter, dwAppFlags, pdwLocale, pPlatform);
if (FAILED(hr))
{
delete pEnum;
return hr;
}
hr = pEnum->QueryInterface(IID_IEnumPackage,(void**) ppIEnumPackage);
if (FAILED(hr))
{
delete pEnum;
return hr;
}
return S_OK;
}
//
// 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 INSTALLINFO structure containing installation details.
//
// Arguments: [in] clsid
// [in] pQryContext
// [out] pInstallInfo
//
// Returns: CS_E_PACKAGE_NOTFOUND
// S_OK
//
//
//
HRESULT STDMETHODCALLTYPE
CAppContainer::GetAppInfo(
uCLSSPEC * pclsspec, // Class Spec (GUID/Ext/MIME)
QUERYCONTEXT * pQryContext, // Query Attributes
INSTALLINFO * pInstallInfo
)
//
// 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 pszCommandText[1000];
STRINGGUID szClsid;
UINT i;
ULONG cRead;
HRESULT hr;
ULONG cSize = _MAX_PATH;
BOOL fFound = FALSE;
PLATFORMINFO PlatformInfo;
LPOLESTR pFileExt = NULL;
memset(pInstallInfo, 0, sizeof(INSTALLINFO));
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 (pszCommandText,
L"<%s>;(%s=%s);name",
m_szClassName, MIMETYPES, pclsspec->tagged_union.pMimeType);
*/
}
switch (pclsspec->tyspec)
{
case TYSPEC_TYPELIB:
if (IsNullGuid(pclsspec->tagged_union.typelibID))
return E_INVALIDARG;
StringFromGUID (pclsspec->tagged_union.typelibID, szClsid);
wsprintf (pszCommandText,
L"<%s>;(%s=%s);",
m_szPackageName, PKGTLBIDLIST, szClsid);
break;
case TYSPEC_IID:
if (IsNullGuid(pclsspec->tagged_union.iid))
return E_INVALIDARG;
StringFromGUID (pclsspec->tagged_union.iid, szClsid);
wsprintf (pszCommandText,
L"<%s>;(%s=%s);",
m_szPackageName, PKGIIDLIST, szClsid);
break;
case TYSPEC_CLSID:
//
// Check TreatAs
/* BUGBUG
Considering removal of support for TreatAs in Class Store.
Till this is closed the code is out.
if ((hr = GetTreatAs (clsid, &MapClsid, &(pPackageInfo->pszClassIconPath)))
== S_OK)
{
//
// Put the result in the TreatAs field of PackageInfo
//
pPackageInfo->pTreatAsClsid = (GUID *)CoTaskMemAlloc(sizeof (CLSID));
memcpy (pPackageInfo->pTreatAsClsid, &MapClsid, sizeof (CLSID));
//
// BUGBUG. Must cache presence/absence of TreatAs info as it is
// a very common lookup into DS.
//
}
*/
if (IsNullGuid(pclsspec->tagged_union.clsid))
return E_INVALIDARG;
StringFromGUID (pclsspec->tagged_union.clsid, szClsid);
wsprintf (pszCommandText,
L"<%s>;(%s=%s);",
m_szPackageName, 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;
/*
//
// BUGBUG. Because FileExt is stored with priority
// make sure that wildcard at end is used.
//
wsprintf (pszCommandText,
L"<%s>;(%s=%s*);",
m_szPackageName, PKGFILEEXTNLIST, pclsspec->tagged_union.pFileExt);
*/
//
// BUGBUG. Workaround for IDS bug.
// Change the below to the code above when this is fixed in NTDEV
//
wsprintf (pszCommandText,
L"<%s>;(%s=%s);",
m_szPackageName, QRYFILEEXT, pclsspec->tagged_union.pFileExt);
pFileExt = pclsspec->tagged_union.pFileExt;
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 (pszCommandText,
L"<%s>;(%s=%s);",
m_szPackageName, PKGPROGIDLIST, pclsspec->tagged_union.pProgId);
break;
case TYSPEC_PACKAGENAME:
//
// Validate package name
//
if (IsBadStringPtr(pclsspec->tagged_union.pPackageName, _MAX_PATH))
return E_INVALIDARG;
if ((pclsspec->tagged_union.pPackageName == NULL) ||
(*(pclsspec->tagged_union.pPackageName) == NULL))
return E_INVALIDARG;
//
PACKAGEDETAIL PackageDetail;
hr = GetPackageDetails (pclsspec->tagged_union.pPackageName,
&PackageDetail);
if (SUCCEEDED(hr))
{
memcpy (pInstallInfo, PackageDetail.pInstallInfo, sizeof(INSTALLINFO));
if (PackageDetail.pActInfo)
{
CoTaskMemFree(PackageDetail.pActInfo->prgShellFileExt);
CoTaskMemFree(PackageDetail.pActInfo->prgPriority);
CoTaskMemFree(PackageDetail.pActInfo->prgInterfaceId);
CoTaskMemFree(PackageDetail.pActInfo->prgTlbId);
CoTaskMemFree(PackageDetail.pActInfo);
}
if (PackageDetail.pPlatformInfo)
{
CoTaskMemFree(PackageDetail.pPlatformInfo->prgPlatform);
CoTaskMemFree(PackageDetail.pPlatformInfo->prgLocale);
CoTaskMemFree(PackageDetail.pPlatformInfo);
}
CoTaskMemFree(PackageDetail.pszSourceList);
CoTaskMemFree(PackageDetail.rpCategory);
CoTaskMemFree(PackageDetail.pInstallInfo);
}
return hr;
default:
return E_NOTIMPL;
}
//
//
HACCESSOR hAccessor = NULL;
IAccessor * pIAccessor = NULL;
IRowset * pIRowset = NULL;
ULONG cRowsFetched;
INSTALLINFO InstallInfo[10];
UINT rgPriority [10];
wcscat (pszCommandText,
szInstallInfoColumns);
hr = ExecuteQuery (m_pIDBCreateCommand,
pszCommandText,
PACKAGEQUERY_COLUMN_COUNT,
NULL,
&hAccessor,
&pIAccessor,
&pIRowset
);
if (!SUCCEEDED(hr))
goto done;
//
// BUGBUG. Currently limited to 10.
// Must put a loop to retry more in future.
//
hr = FetchInstallData(pIRowset,
hAccessor,
pQryContext,
pFileExt,
10,
&cRowsFetched,
&InstallInfo[0],
&rgPriority[0]
);
if ((hr != S_OK) || (cRowsFetched == 0))
{
hr = CS_E_PACKAGE_NOTFOUND;
}
else
{
//
// Selected one is j
//
UINT j = 0;
//
// process file-ext priority.
//
if ((pFileExt) && (cRowsFetched > 1))
{
UINT Pri = rgPriority[0];
for (i=1; i < cRowsFetched; ++i)
{
if (rgPriority[i] > Pri)
{
Pri = rgPriority[i];
j = i;
}
}
}
//
// return the jth one
//
memcpy (pInstallInfo, &InstallInfo[j], sizeof(INSTALLINFO));
memset (&InstallInfo[j], NULL, sizeof(INSTALLINFO));
// Clean up all fetched except for jth one
for (i=0; i < cRowsFetched; i++)
{
if (i != j)
FreeInstallInfo(&InstallInfo[i]);
}
}
CloseQuery(pIAccessor,
hAccessor,
pIRowset);
done:
return hr;
}
BOOL
CheckMatching (QUERYCONTEXT *pQryContext,
INSTALLINFO *pInstallInfo,
PLATFORMINFO *pPlatformInfo
)
{
HRESULT hr;
DWORD dwCtx, dwLocale;
ULONG i;
BOOL fMatch;
CSPLATFORM *pPlatform;
//
// Get all the specifics of this package
//
dwCtx = pInstallInfo->dwComClassContext;
//
// if the implementation is a remote server,
// then skip matching platform
//
fMatch = FALSE;
for (i=0; i < pPlatformInfo->cPlatforms; i++)
{
if (MatchPlatform (&(pQryContext->Platform), pPlatformInfo->prgPlatform+i))
{
// matches
fMatch = TRUE;
break;
}
}
//
// either the locale seen is LANG_NEUTRAL (means does not matter)
// or the locale matches as specified
// then treat this as found.
// BUGBUG. In future we should be going thru the
// entire list to pick the best match
if (fMatch)
{
fMatch = FALSE;
for (i=0; i < pPlatformInfo->cLocales; i++)
{
if (MatchLocale (pQryContext->Locale, pPlatformInfo->prgLocale[i]))
{
// Does not match the Locale requested
fMatch = TRUE;
break;
}
}
}
return fMatch;
}