// // Author: DebiM // Date: September 1996 // // File: csacc.cxx // // Class Store Manager implementation for a client desktop. // // This source file contains implementations for IClassAccess // interface for CClassAccess object. // It also contains the IEnumPackage implementation for the // aggregate of all class containers seen by the caller. // // //--------------------------------------------------------------------- #include "cstore.hxx" /** void LogCsPathError( WCHAR * pwszContainerPath, HRESULT hr ); **/ #define MAXCLASSSTORES 10 IClassAccess *GetNextValidClassStore(PCLASSCONTAINER *pStoreList, DWORD cStores, DWORD *pcount); extern HRESULT GetUserClassStores( PCLASSCONTAINER **ppStoreList, DWORD *pcStores); // // Link list pointer for Class Containers Seen // extern CLASSCONTAINER *gpContainerHead; // // Link list pointer for User Profiles Seen // extern USERPROFILE *gpUserHead; // // Global Class Factory for Class Container // extern CAppContainerCF *pCF; // // Critical Section used during operations on list of class stores // extern CRITICAL_SECTION ClassStoreBindList; // // CClassAccess implementation // CClassAccess::CClassAccess() { m_uRefs = 1; m_cCalls = 0; } CClassAccess::~CClassAccess() { } //---------------------------------------------------------------------- // // #ifdef DBG void PrintClassSpec( uCLSSPEC * pclsspec // Class Spec (GUID/Ext/MIME) ) { STRINGGUID szClsid; if (pclsspec->tyspec == TYSPEC_CLSID) { StringFromGUID (pclsspec->tagged_union.clsid, szClsid); CSDbgPrint((" ... GetClassSpecInfo by CLSID = %ws\n", szClsid)); } if (pclsspec->tyspec == TYSPEC_PROGID) { CSDbgPrint((" ... GetClassSpecInfo by ProgID = %ws\n", pclsspec->tagged_union.pProgId)); } if (pclsspec->tyspec == TYSPEC_MIMETYPE) { CSDbgPrint((" ... GetClassSpecInfo by MimeType = %ws\n", pclsspec->tagged_union.pMimeType)); } if (pclsspec->tyspec == TYSPEC_FILEEXT) { CSDbgPrint((" ... GetClassSpecInfo by FileExt = %ws\n", pclsspec->tagged_union.pFileExt)); } if (pclsspec->tyspec == TYSPEC_IID) { StringFromGUID (pclsspec->tagged_union.iid, szClsid); CSDbgPrint((" ... GetClassSpecInfo by IID = %ws\n", szClsid)); } } #endif //---------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CClassAccess::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 or MIME type. // // If a matching implementation is available for the object type, // client architecture, locale and class context pointer to the // binary is returned. { // // Assume that this method is called in the security context // of the user process. Hence there is no need to impersonate. // // // Get the list of Class Stores for this user // PCLASSCONTAINER *pStoreList; ULONG cStores=0; HRESULT hr; ULONG i; ULONG chEaten; IMoniker *pmk; LPBC pbc; IClassAccess *pICA = NULL; #ifdef DBG PrintClassSpec(pclsspec); #endif hr = GetUserClassStores( &pStoreList, &cStores); if (!SUCCEEDED(hr)) { return hr; } //RpcImpersonateClient( NULL ); for (i=0; i < cStores; i++) { if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i))) continue; // // Call method on this store // pICA->AddRef(); hr = pICA->GetAppInfo( pclsspec, pQryContext, pInstallInfo); // Release it after use. pICA->Release(); // // Special case error return E_INVALIDARG // Do not continue to look, return this. // if (hr == E_INVALIDARG) { //RevertToSelf(); return hr; } // // maintain access counters // (pStoreList[i])->cAccess++; if (SUCCEEDED(hr)) { //RevertToSelf(); return hr; } else { (pStoreList[i])->cNotFound++; CSDbgPrint(("CS: .. CClassAccess::GetClassSpecInfo() returned 0x%x\n", hr)); } } //RevertToSelf(); return CS_E_PACKAGE_NOTFOUND; } // // GetNextValidClassStore // // IClassAccess *GetNextValidClassStore(CLASSCONTAINER **pStoreList, DWORD cStores, DWORD *pcount) { HRESULT hr = S_OK; IClassAccess *pretICA = NULL; // BUGBUG:: Probably should move this inside the for loops so that the // read accesses to gpClassStore do not get serialized. Debi? EnterCriticalSection (&ClassStoreBindList); for (pStoreList += (*pcount); (*pcount) < cStores; (*pcount)++, pStoreList++) { if ((*pStoreList)->gpClassStore != NULL) { hr = S_OK; break; } if (FALSE) // ((*pStoreList)->cBindFailures >= MAX_BIND_ATTEMPTS) { // Number of continuous failures have reached MAX_BIND_ATTEMPTS // for this container. // Will temporarily disable lookups in this container. // Report it in EventLog once // if ((*pStoreList)->cBindFailures == MAX_BIND_ATTEMPTS) { //LogCsPathError((*pStoreList)->pszClassStorePath, hr); (*pStoreList)->cBindFailures++; } continue; } else { CSDbgPrint(("CS: .. Connecting to Store %d \n ... %ws..\n", (*pcount), (*pStoreList)->pszClassStorePath)); // // Bind to this Class Store // if (wcsncmp ((*pStoreList)->pszClassStorePath, L"ADCS:", 5) == 0) { // // If the Storename starts with ADCS // it is NTDS based implementation. Call directly. // hr = pCF->CreateConnectedInstance( ((*pStoreList)->pszClassStorePath + 5), (void **)&((*pStoreList)->gpClassStore)); } else { // // Support for Third Party Pluggable // Class Stores is not in Beta1. // #if 1 hr = E_NOTIMPL; #else ULONG chEaten; IMoniker *pmk; LPBC pbc; pbc = NULL; hr = CreateBindCtx (0, &pbc); if (!SUCCEEDED(hr)) { continue; } pmk = NULL; chEaten = 0; hr = MkParseDisplayName (pbc, (*pStoreList)->pszClassStorePath, &chEaten, &pmk); if (SUCCEEDED(hr)) { hr = pmk->BindToObject (pbc, NULL, IID_IClassAccess, (void **)&((*pStoreList)->gpClassStore)); pmk->Release(); } pbc->Release(); #endif } if (SUCCEEDED(hr)) { (*pStoreList)->cBindFailures = 0; hr = S_OK; break; } if (!SUCCEEDED(hr)) { CSDbgPrint(("CS: ... Failed to connect to this store\n")); if ((*pStoreList)->cBindFailures == 0) { // First failue or First failure after successful // binding. // Report it in EventLog // //LogCsPathError((*pStoreList)->pszClassStorePath, hr); } ((*pStoreList)->cBindFailures) ++; continue; } } } if ((*pcount) != cStores) pretICA = (*pStoreList)->gpClassStore; LeaveCriticalSection (&ClassStoreBindList); return pretICA; } /* HRESULT STDMETHODCALLTYPE CClassAccess::GetUpgrades ( ULONG cClasses, CLSID *pClassList, // CLSIDs Installed CSPLATFORM Platform, LCID Locale, PACKAGEINFOLIST *pPackageInfoList) { // // Assume that this method is called in the security context // of the user process. Hence there is no need to impersonate. // PCLASSCONTAINER *pStoreList; DWORD cStores=0; HRESULT hr; ULONG i; IClassRefresh *pIClassRefresh = NULL; PACKAGEINFOLIST PackageInfoList; IClassAccess *pICA = NULL; pPackageInfoList->cPackInfo = NULL; pPackageInfoList->pPackageInfo = NULL; // // Get the list of Class Stores for this user // hr = GetUserClassStores( &pStoreList, &cStores); if (!SUCCEEDED(hr)) { return hr; } RpcImpersonateClient( NULL ); for (i=0; i < cStores; i++) { if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i))) continue; // // Call method on this store // if (FAILED(pICA->QueryInterface(IID_IClassRefresh, (void **)&pIClassRefresh))) continue; hr = pIClassRefresh->GetUpgrades( cClasses, pClassList, Platform, Locale, &PackageInfoList); pIClassRefresh->Release(); pIClassRefresh = NULL; if (hr == E_INVALIDARG) { RevertToSelf(); return hr; } if (SUCCEEDED(hr) && (PackageInfoList.cPackInfo > 0)) { // // Add to the existing list of upgrades // UINT cCount = pPackageInfoList->cPackInfo; if (cCount) { PACKAGEINFO *pInfo = pPackageInfoList->pPackageInfo; pPackageInfoList->pPackageInfo = (PACKAGEINFO *) CoTaskMemAlloc ((cCount + PackageInfoList.cPackInfo) * sizeof(PACKAGEINFO)); memcpy (pPackageInfoList->pPackageInfo, pInfo, cCount * sizeof(PACKAGEINFO)); memcpy ((pPackageInfoList->pPackageInfo)+cCount, PackageInfoList.pPackageInfo, PackageInfoList.cPackInfo * sizeof(PACKAGEINFO)); CoTaskMemFree (pInfo); pPackageInfoList->cPackInfo += PackageInfoList.cPackInfo; } else { pPackageInfoList->cPackInfo = PackageInfoList.cPackInfo; pPackageInfoList->pPackageInfo = PackageInfoList.pPackageInfo; } } } RevertToSelf(); return S_OK; } HRESULT STDMETHODCALLTYPE CClassAccess::CommitUpgrades () { // // Assume that this method is called in the security context // of the user process. Hence there is no need to impersonate. // PCLASSCONTAINER *pStoreList; DWORD cStores=0; HRESULT hr; ULONG i; IClassRefresh *pIClassRefresh; IClassAccess *pICA = NULL; // // Get the list of Class Stores for this user // hr = GetUserClassStores( &pStoreList, &cStores); if (!SUCCEEDED(hr)) { return hr; } RpcImpersonateClient( NULL ); for (i=0; i < cStores; i++) { if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i))) continue; // // Call method on this store // if (FAILED(pICA->QueryInterface(IID_IClassRefresh, (void **)&pIClassRefresh))) continue; hr = pIClassRefresh->CommitUpgrades(); pIClassRefresh->Release(); } RevertToSelf(); return hr; } */ HRESULT STDMETHODCALLTYPE CClassAccess::EnumPackages( LPOLESTR pszPackageName, GUID *pCategory, ULONGLONG *pLastUsn, DWORD dwAppFlags, // AppType options IEnumPackage **ppIEnumPackage) { // // Get the list of Class Stores for this user // PCLASSCONTAINER *pStoreList; DWORD cStores=0; HRESULT hr; ULONG i; IEnumPackage *Enum[MAXCLASSSTORES]; ULONG cEnum = 0; CMergedEnumPackage *EnumMerged; IClassAccess *pICA = NULL; // // Get the list of Class Stores for this user // hr = GetUserClassStores( &pStoreList, &cStores); *ppIEnumPackage = NULL; if (!SUCCEEDED(hr)) { return hr; } if (cStores == 0) { return CS_E_NO_CLASSSTORE; } //RpcImpersonateClient( NULL ); for (i=0; i < cStores; i++) { if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i))) continue; // // Call method on this store // hr = pICA->EnumPackages (pszPackageName, pCategory, pLastUsn, dwAppFlags, &(Enum[cEnum])); if (hr == E_INVALIDARG) { //RevertToSelf(); return hr; } if (SUCCEEDED(hr)) cEnum++; } EnumMerged = new CMergedEnumPackage; hr = EnumMerged->Initialize(Enum, cEnum); if (FAILED(hr)) { for (i = 0; i < cEnum; i++) Enum[i]->Release(); delete EnumMerged; } else { hr = EnumMerged->QueryInterface(IID_IEnumPackage, (void **)ppIEnumPackage); if (FAILED(hr)) delete EnumMerged; } //RevertToSelf(); return hr; } //-------------------------------------------------------------- CMergedEnumPackage::CMergedEnumPackage() { m_pcsEnum = NULL; m_cEnum = 0; m_csnum = 0; m_dwRefCount = 0; } CMergedEnumPackage::~CMergedEnumPackage() { ULONG i; for (i = 0; i < m_cEnum; i++) m_pcsEnum[i]->Release(); CoTaskMemFree(m_pcsEnum); } HRESULT __stdcall CMergedEnumPackage::QueryInterface(REFIID riid, void * * ppObject) { *ppObject = NULL; //gd if ((riid==IID_IUnknown) || (riid==IID_IEnumPackage)) { *ppObject=(IEnumPackage *) this; } else { return E_NOINTERFACE; } AddRef(); return S_OK; } ULONG __stdcall CMergedEnumPackage::AddRef() { InterlockedIncrement((long*) &m_dwRefCount); return m_dwRefCount; } ULONG __stdcall CMergedEnumPackage::Release() { ULONG dwRefCount; if ((dwRefCount = InterlockedDecrement((long*) &m_dwRefCount))==0) { delete this; return 0; } return dwRefCount; } HRESULT __stdcall CMergedEnumPackage::Next( ULONG celt, PACKAGEDISPINFO *rgelt, ULONG *pceltFetched) { ULONG count=0, total = 0; HRESULT hr = S_OK; //RpcImpersonateClient( NULL ); for (; m_csnum < m_cEnum; m_csnum++) { count = 0; hr = m_pcsEnum[m_csnum]->Next(celt, rgelt+total, &count); if (hr == E_INVALIDARG) { //RevertToSelf(); return hr; } total += count; celt -= count; if (!celt) break; } if (pceltFetched) *pceltFetched = total; //RevertToSelf(); if (!celt) return S_OK; return S_FALSE; } HRESULT __stdcall CMergedEnumPackage::Skip( ULONG celt) { PACKAGEDISPINFO *pPackageInfo = NULL; HRESULT hr = S_OK; ULONG cgot = 0, i; pPackageInfo = (PACKAGEDISPINFO *)CoTaskMemAlloc(sizeof(PACKAGEDISPINFO)*celt); hr = Next(celt, pPackageInfo, &cgot); for (i = 0; i < cgot; i++) ReleasePackageInfo(pPackageInfo+i); CoTaskMemFree(pPackageInfo); return hr; } HRESULT __stdcall CMergedEnumPackage::Reset() { ULONG i; //RpcImpersonateClient( NULL ); for (i = 0; ((i <= m_csnum) && (i < m_cEnum)); i++) m_pcsEnum[i]->Reset(); // ignoring all error values m_csnum = 0; //RevertToSelf(); return S_OK; } HRESULT __stdcall CMergedEnumPackage::Clone(IEnumPackage **ppIEnumPackage) { ULONG i; CMergedEnumPackage *pClone; IEnumPackage *pcsEnumCloned[MAXCLASSSTORES]; //RpcImpersonateClient( NULL ); pClone = new CMergedEnumPackage; for ( i = 0; i < m_cEnum; i++) m_pcsEnum[i]->Clone(&(pcsEnumCloned[i])); pClone->m_csnum = m_csnum; pClone->Initialize(pcsEnumCloned, m_cEnum); *ppIEnumPackage = (IEnumPackage *)pClone; pClone->AddRef(); //RevertToSelf(); return S_OK; } HRESULT CMergedEnumPackage::Initialize(IEnumPackage **pcsEnum, ULONG cEnum) { ULONG i; m_csnum = 0; m_pcsEnum = (IEnumPackage **)CoTaskMemAlloc(sizeof(IEnumPackage *) * cEnum); if (!m_pcsEnum) return E_OUTOFMEMORY; for (i = 0; i < cEnum; i++) m_pcsEnum[i] = pcsEnum[i]; m_cEnum = cEnum; return S_OK; }