// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // =========================================================================== // File: MDInternalRW.cpp // // Notes: // // // =========================================================================== #include "stdafx.h" #include "../runtime/mdinternalro.h" #include "../compiler/regmeta.h" #include "../compiler/importhelper.h" #include "mdinternalrw.h" #include "metamodelro.h" #include "liteweightstgdb.h" #ifdef FEATURE_METADATA_INTERNAL_APIS __checkReturn HRESULT _GetFixedSigOfVarArg( // S_OK or error. PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob of COM+ method signature ULONG cbSigBlob, // [IN] size of signature CQuickBytes *pqbSig, // [OUT] output buffer for fixed part of VarArg Signature ULONG *pcbSigBlob); // [OUT] number of bytes written to the above output buffer __checkReturn HRESULT _FillMDDefaultValue( BYTE bType, void const *pValue, ULONG cbValue, MDDefaultValue *pMDDefaultValue); //***************************************************************************** // Serve as a delegator to call ImportHelper::MergeUpdateTokenInSig. Or we will // need to include ImportHelper into our md\runtime directory. //***************************************************************************** __checkReturn HRESULT TranslateSigHelper( // S_OK or error. IMDInternalImport* pImport, // [IN] import scope. IMDInternalImport* pAssemImport, // [IN] import assembly scope. const void* pbHashValue, // [IN] hash value for the import assembly. ULONG cbHashValue, // [IN] count of bytes in the hash value. PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope ULONG cbSigBlob, // [IN] count of bytes of signature IMetaDataAssemblyEmit* pAssemEmit, // [IN] assembly emit scope. IMetaDataEmit* emit, // [IN] emit interface CQuickBytes* pqkSigEmit, // [OUT] buffer to hold translated signature ULONG* pcbSig) // [OUT] count of bytes in the translated signature { #ifdef FEATURE_METADATA_EMIT IMetaModelCommon *pCommon = pImport->GetMetaModelCommon(); RegMeta *pAssemEmitRM = static_cast(pAssemEmit); RegMeta *pEmitRM = static_cast(emit); CMiniMdRW *pMiniMdAssemEmit = pAssemEmitRM ? &pAssemEmitRM->m_pStgdb->m_MiniMd : NULL; CMiniMdRW *pMiniMdEmit = &(pEmitRM->m_pStgdb->m_MiniMd); IMetaModelCommon *pCommonAssemImport = pAssemImport ? pAssemImport->GetMetaModelCommon() : NULL; return ImportHelper::MergeUpdateTokenInSig( pMiniMdAssemEmit, // The assembly emit scope. pMiniMdEmit, // The emit scope. pCommonAssemImport, // Assembly scope where the signature is from. pbHashValue, // Hash value for the import scope. cbHashValue, // Size in bytes. pCommon, // The scope where signature is from. pbSigBlob, // signature from the imported scope NULL, // Internal OID mapping structure. pqkSigEmit, // [OUT] translated signature NULL, // start from first byte of the signature NULL, // don't care how many bytes consumed pcbSig); // [OUT] total number of bytes write to pqkSigEmit #else //!FEATURE_METADATA_EMIT // This API doesn't make sense without supporting public Emit APIs return E_NOTIMPL; #endif //!FEATURE_METADATA_EMIT } // TranslateSigHelper //***************************************************************************** // Given an IMDInternalImport on a CMiniMd[RO], convert to CMiniMdRW. //***************************************************************************** __checkReturn STDAPI ConvertRO2RW( IUnknown *pRO, // [IN] The RO interface to convert. REFIID riid, // [IN] The interface desired. void **ppIUnk) // [OUT] Return interface on success. { HRESULT hr = S_OK; // A result. IMDInternalImportENC *pRW = 0; // To test the RW-ness of the input iface. MDInternalRW *pInternalRW = 0; // Gets the new RW object. MDInternalRO *pTrustedRO = 0; // Avoid confusion. *ppIUnk = 0; IfFailGo(VerifyNotWinMD(pRO, "ConvertRO2RW() not supported on .winmd files.")); // If the interface is already RW, done, just return. if (pRO->QueryInterface(IID_IMDInternalImportENC, (void**)&pRW) == S_OK) { hr = pRO->QueryInterface(riid, ppIUnk); goto ErrExit; } // Create the new RW object. pInternalRW = new (nothrow) MDInternalRW; IfNullGo( pInternalRW ); // Init from the RO object. Convert as read-only; QI will make writable if // so needed. // ! QI for IID_IUnknown will return MDInternalRO*. Not that COM guarantees such a thing but MDInternalRO knows about IfFailGo( pRO->QueryInterface(IID_IUnknown, (void**)&pTrustedRO) ); IfFailGo( pInternalRW->InitWithRO(pTrustedRO, true)); IfFailGo( pInternalRW->QueryInterface(riid, ppIUnk) ); ErrExit: if (pRW) pRW->Release(); if (pTrustedRO) pTrustedRO->Release(); // Clean up the object and [OUT] interface on error. if (FAILED(hr)) { if (pInternalRW) delete pInternalRW; *ppIUnk = 0; } else if (pInternalRW) pInternalRW->Release(); return hr; } // ConvertRO2RW //***************************************************************************** // Helper to get the internal interface with RW format //***************************************************************************** __checkReturn HRESULT GetInternalWithRWFormat( LPVOID pData, ULONG cbData, DWORD flags, // [IN] MDInternal_OpenForRead or MDInternal_OpenForENC REFIID riid, // [in] The interface desired. void **ppIUnk) // [out] Return interface on success. { MDInternalRW *pInternalRW = NULL; HRESULT hr; *ppIUnk = 0; pInternalRW = new (nothrow) MDInternalRW; IfNullGo( pInternalRW ); IfFailGo( pInternalRW->Init( const_cast(pData), cbData, (flags == ofRead) ? true : false) ); IfFailGo( pInternalRW->QueryInterface(riid, ppIUnk) ); ErrExit: if (FAILED(hr)) { if (pInternalRW) delete pInternalRW; *ppIUnk = 0; } else if ( pInternalRW ) pInternalRW->Release(); return hr; } // GetInternalWithRWFormat //***************************************************************************** // This function returns a IMDInternalImport interface based on the given // public import interface i.e IMetaDataEmit or IMetaDataImport. //***************************************************************************** __checkReturn STDAPI GetMDInternalInterfaceFromPublic( IUnknown *pIUnkPublic, // [IN] Given public interface. Must be QI of IUnknown REFIID riid, // [in] The interface desired. void **ppIUnkInternal) // [out] Return interface on success. { HRESULT hr = S_OK; ReleaseHolder pGetIMDInternalImport; // IMDInternalImport is the only internal import interface currently supported by // this function. _ASSERTE(riid == IID_IMDInternalImport && pIUnkPublic && ppIUnkInternal); if (riid != IID_IMDInternalImport || pIUnkPublic == NULL || ppIUnkInternal == NULL) IfFailGo(E_INVALIDARG); IfFailGo( pIUnkPublic->QueryInterface(IID_IGetIMDInternalImport, &pGetIMDInternalImport)); IfFailGo( pGetIMDInternalImport->GetIMDInternalImport((IMDInternalImport **)ppIUnkInternal)); ErrExit: if (FAILED(hr)) { if (ppIUnkInternal) *ppIUnkInternal = 0; } return hr; } // GetMDInternalInterfaceFromPublic //***************************************************************************** // This function returns the requested public interface based on the given // internal import interface. It is caller's responsibility to Release ppIUnkPublic //***************************************************************************** __checkReturn STDAPI GetMDPublicInterfaceFromInternal( void *pIUnkInternal, // [IN] Given internal interface. REFIID riid, // [in] The interface desired. void **ppIUnkPublic) // [out] Return interface on success. { HRESULT hr = S_OK; IMDInternalImport *pInternalImport = 0;; IUnknown *pIUnkPublic = NULL; OptionValue optVal = { MDDupAll, MDRefToDefDefault, MDNotifyDefault, MDUpdateFull, MDErrorOutOfOrderDefault , MDThreadSafetyOn}; RegMeta *pMeta = 0; bool isLockedForWrite = false; _ASSERTE(pIUnkInternal && ppIUnkPublic); *ppIUnkPublic = 0; IfFailGo(VerifyNotWinMD((IUnknown*)pIUnkInternal, "GetMDPublicInterfaceFromInternal() not supported on .winmd files.")); IfFailGo(ConvertRO2RW((IUnknown*)pIUnkInternal, IID_IMDInternalImport, (void **)&pInternalImport)); pIUnkPublic = pInternalImport->GetCachedPublicInterface(TRUE); if ( pIUnkPublic ) { // There is already a cached public interface. GetCachedPublicInterface already AddRef the returned // public interface. We want to QueryInterface the riid... // We are done! hr = pIUnkPublic->QueryInterface(riid, ppIUnkPublic); pIUnkPublic->Release(); goto ErrExit; } // grab the write lock when we are creating the corresponding regmeta for the public interface _ASSERTE( pInternalImport->GetReaderWriterLock() != NULL ); isLockedForWrite = true; IfFailGo(pInternalImport->GetReaderWriterLock()->LockWrite()); // check again. Maybe someone else beat us to setting the public interface while we are waiting // for the write lock. Don't need to grab the read lock since we already have the write lock. *ppIUnkPublic = pInternalImport->GetCachedPublicInterface(FALSE); if ( *ppIUnkPublic ) { // there is already a cached public interface. GetCachedPublicInterface already AddRef the returned // public interface. // We are done! goto ErrExit; } pMeta = new (nothrow) RegMeta(); IfNullGo(pMeta); IfFailGo(pMeta->SetOption(&optVal)); IfFailGo( pMeta->InitWithStgdb((IUnknown*)pInternalImport, ((MDInternalRW*)pInternalImport)->GetMiniStgdb()) ); IfFailGo( pMeta->QueryInterface(riid, ppIUnkPublic) ); // The following makes the public object and the internal object point to each other. _ASSERTE( pMeta->GetReaderWriterLock() == NULL ); IfFailGo( pMeta->SetCachedInternalInterface(pInternalImport) ); IfFailGo( pInternalImport->SetCachedPublicInterface((IUnknown *) *ppIUnkPublic) ); IfFailGo( pMeta->SetReaderWriterLock(pInternalImport->GetReaderWriterLock() )); // Add the new RegMeta to the cache. IfFailGo( pMeta->AddToCache() ); ErrExit: if (isLockedForWrite) pInternalImport->GetReaderWriterLock()->UnlockWrite(); if (pInternalImport) pInternalImport->Release(); if (FAILED(hr)) { if (pMeta) delete pMeta; *ppIUnkPublic = 0; } return hr; } // GetMDPublicInterfaceFromInternal //***************************************************************************** // Converts an internal MD import API into the read/write version of this API. // This could support edit and continue, or modification of the metadata at // runtime (say for profiling). //***************************************************************************** __checkReturn STDAPI ConvertMDInternalImport( // S_OK, S_FALSE (no conversion), or error. IMDInternalImport *pIMD, // [in] The metadata to be updated. IMDInternalImport **ppIMD) // [out] Put the RW here. { HRESULT hr; // A result. IMDInternalImportENC *pENC = NULL; // ENC interface on the metadata. _ASSERTE(pIMD != NULL); _ASSERTE(ppIMD != NULL); // Test whether the MD is already RW. hr = pIMD->QueryInterface(IID_IMDInternalImportENC, (void**)&pENC); if (FAILED(hr)) { // Not yet RW, so do the conversion. IfFailGo(ConvertRO2RW(pIMD, IID_IMDInternalImport, (void**)ppIMD)); } else { // Already converted; give back same pointer. *ppIMD = pIMD; hr = S_FALSE; } ErrExit: if (pENC) pENC->Release(); return hr; } // ConvertMDInternalImport //***************************************************************************** // Constructor //***************************************************************************** MDInternalRW::MDInternalRW() : m_pStgdb(NULL), m_cRefs(1), m_fOwnStgdb(false), m_pUnk(NULL), m_pUserUnk(NULL), m_pIMetaDataHelper(NULL), m_pSemReadWrite(NULL), m_fOwnSem(false) { } // MDInternalRW::MDInternalRW //***************************************************************************** // Destructor //***************************************************************************** MDInternalRW::~MDInternalRW() { HRESULT hr = S_OK; LOCKWRITENORET(); // This should have worked if we've cached the internal interface in the past _ASSERTE(SUCCEEDED(hr) || m_pIMetaDataHelper == NULL || m_pIMetaDataHelper->GetCachedInternalInterface(false) == NULL); if (SUCCEEDED(hr)) { if (m_pIMetaDataHelper) { // The internal object is going away before the public object. // If the internal object owns the reader writer lock, transfer the ownership // to the public object and clear the cached internal interface from the public interface. m_pIMetaDataHelper->SetCachedInternalInterface(NULL); m_pIMetaDataHelper = NULL; m_fOwnSem = false; } UNLOCKWRITE(); } if (m_pSemReadWrite && m_fOwnSem) delete m_pSemReadWrite; if ( m_pStgdb && m_fOwnStgdb ) { // we own the stgdb so we need to uninit and delete it. m_pStgdb->Uninit(); delete m_pStgdb; } if ( m_pUserUnk ) m_pUserUnk->Release(); if ( m_pUnk ) m_pUnk->Release(); } // MDInternalRW::~MDInternalRW //***************************************************************************** // Set or clear the cached public interfaces. // NOTE:: Caller should take a Write lock on the reader writer lock. //***************************************************************************** __checkReturn HRESULT MDInternalRW::SetCachedPublicInterface(IUnknown * pUnk) { IMetaDataHelper * pHelper = NULL; HRESULT hr = S_OK; if (pUnk != NULL) { // Internal object and public regmeta should be one to one mapping!! _ASSERTE(m_pIMetaDataHelper == NULL); IfFailRet(pUnk->QueryInterface(IID_IMetaDataHelper, (void **) &pHelper)); _ASSERTE(pHelper != NULL); m_pIMetaDataHelper = pHelper; pHelper->Release(); } else { // public object is going away before the internal object. If we don't own the // reader writer lock, just take over the ownership. m_fOwnSem = true; m_pIMetaDataHelper = NULL; } return hr; } // MDInternalRW::SetCachedPublicInterface //***************************************************************************** // Clear the cached public interfaces. //***************************************************************************** IUnknown * MDInternalRW::GetCachedPublicInterface(BOOL fWithLock) { HRESULT hr = S_OK; IUnknown * pRet = NULL; if (fWithLock) { LOCKREAD(); pRet = m_pIMetaDataHelper; if (pRet != NULL) pRet->AddRef(); } else { pRet = m_pIMetaDataHelper; if (pRet != NULL) pRet->AddRef(); } ErrExit: return pRet; } // MDInternalRW::GetCachedPublicInterface //***************************************************************************** // Get the Reader-Writer lock //***************************************************************************** UTSemReadWrite * MDInternalRW::GetReaderWriterLock() { return getReaderWriterLock(); } // MDInternalRW::GetReaderWriterLock //***************************************************************************** // IUnknown //***************************************************************************** ULONG MDInternalRW::AddRef() { return InterlockedIncrement(&m_cRefs); } // MDInternalRW::AddRef ULONG MDInternalRW::Release() { ULONG cRef; cRef = InterlockedDecrement(&m_cRefs); if (cRef == 0) { LOG((LOGMD, "MDInternalRW(0x%08x)::destruction\n", this)); delete this; } return cRef; } // MDInternalRW::Release __checkReturn HRESULT MDInternalRW::QueryInterface(REFIID riid, void **ppUnk) { *ppUnk = 0; if (riid == IID_IUnknown) *ppUnk = (IUnknown *) (IMDInternalImport *) this; else if (riid == IID_IMDInternalImport) *ppUnk = (IMDInternalImport *) this; else if (riid == IID_IMDInternalImportENC) *ppUnk = (IMDInternalImportENC *) this; else if (riid == IID_IMDCommon) *ppUnk = (IMDCommon*)this; else return E_NOINTERFACE; AddRef(); return S_OK; } // MDInternalRW::QueryInterface //***************************************************************************** // Initialize //***************************************************************************** __checkReturn HRESULT MDInternalRW::Init( LPVOID pData, // points to meta data section in memory ULONG cbData, // count of bytes in pData int bReadOnly) // Is it open for read only? { CLiteWeightStgdbRW * pStgdb = NULL; HRESULT hr = NOERROR; OptionValue optVal = { MDDupAll, MDRefToDefDefault, MDNotifyDefault, MDUpdateFull, MDErrorOutOfOrderDefault, MDThreadSafetyOn }; pStgdb = new (nothrow) CLiteWeightStgdbRW; IfNullGo(pStgdb); m_pSemReadWrite = new (nothrow) UTSemReadWrite; IfNullGo(m_pSemReadWrite); IfFailGo(m_pSemReadWrite->Init()); m_fOwnSem = true; INDEBUG(pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) IfFailGo(pStgdb->InitOnMem(cbData, (BYTE*)pData, bReadOnly)); IfFailGo(pStgdb->m_MiniMd.SetOption(&optVal)); m_tdModule = COR_GLOBAL_PARENT_TOKEN; m_fOwnStgdb = true; m_pStgdb = pStgdb; ErrExit: // clean up upon errors if (FAILED(hr) && (pStgdb != NULL)) { delete pStgdb; } return hr; } // MDInternalRW::Init //***************************************************************************** // Initialize with an existing RegMeta. //***************************************************************************** __checkReturn HRESULT MDInternalRW::InitWithStgdb( IUnknown *pUnk, // The IUnknow that owns the life time for the existing stgdb CLiteWeightStgdbRW *pStgdb) // existing lightweight stgdb { // m_fOwnSem should be false because this is the case where we create the internal interface given a public // interface. m_tdModule = COR_GLOBAL_PARENT_TOKEN; m_fOwnStgdb = false; m_pStgdb = pStgdb; // remember the owner of the light weight stgdb // AddRef it to ensure the lifetime // m_pUnk = pUnk; m_pUnk->AddRef(); return NOERROR; } // MDInternalRW::InitWithStgdb //***************************************************************************** // Initialize with an existing RO format //***************************************************************************** __checkReturn HRESULT MDInternalRW::InitWithRO( MDInternalRO * pRO, int bReadOnly) { CLiteWeightStgdbRW * pStgdb = NULL; HRESULT hr = NOERROR; OptionValue optVal = { MDDupAll, MDRefToDefDefault, MDNotifyDefault, MDUpdateFull, MDErrorOutOfOrderDefault, MDThreadSafetyOn }; pStgdb = new (nothrow) CLiteWeightStgdbRW; IfNullGo(pStgdb); m_pSemReadWrite = new (nothrow) UTSemReadWrite; IfNullGo(m_pSemReadWrite); IfFailGo(m_pSemReadWrite->Init()); m_fOwnSem = true; INDEBUG(pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) IfFailGo(pStgdb->m_MiniMd.InitOnRO(&pRO->m_LiteWeightStgdb.m_MiniMd, bReadOnly)); IfFailGo(pStgdb->m_MiniMd.SetOption(&optVal)); m_tdModule = COR_GLOBAL_PARENT_TOKEN; m_fOwnStgdb = true; pStgdb->m_pvMd=pRO->m_LiteWeightStgdb.m_pvMd; pStgdb->m_cbMd=pRO->m_LiteWeightStgdb.m_cbMd; m_pStgdb = pStgdb; ErrExit: // clean up upon errors if (FAILED(hr) && (pStgdb != NULL)) { delete pStgdb; } return hr; } // MDInternalRW::InitWithRO #ifndef DACCESS_COMPILE //***************************************************************************** // Given a scope, determine whether imported from a typelib. //***************************************************************************** __checkReturn HRESULT MDInternalRW::TranslateSigWithScope( IMDInternalImport* pAssemImport, // [IN] import assembly scope. const void* pbHashValue, // [IN] hash value for the import assembly. ULONG cbHashValue, // [IN] count of bytes in the hash value. PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope ULONG cbSigBlob, // [IN] count of bytes of signature IMetaDataAssemblyEmit* pAssemEmit, // [IN] assembly emit scope. IMetaDataEmit* emit, // [IN] emit interface CQuickBytes* pqkSigEmit, // [OUT] buffer to hold translated signature ULONG* pcbSig) // [OUT] count of bytes in the translated signature { return TranslateSigHelper( this, pAssemImport, pbHashValue, cbHashValue, pbSigBlob, cbSigBlob, pAssemEmit, emit, pqkSigEmit, pcbSig); } // MDInternalRW::TranslateSigWithScope __checkReturn HRESULT MDInternalRW::GetTypeDefRefTokenInTypeSpec(// return S_FALSE if enclosing type does not have a token mdTypeSpec tkTypeSpec, // [IN] TypeSpec token to look at mdToken *tkEnclosedToken) // [OUT] The enclosed type token { return m_pStgdb->m_MiniMd.GetTypeDefRefTokenInTypeSpec(tkTypeSpec, tkEnclosedToken); }// MDInternalRW::GetTypeDefRefTokenInTypeSpec //***************************************************************************** // Given a scope, return the number of tokens in a given table //***************************************************************************** ULONG MDInternalRW::GetCountWithTokenKind( // return hresult DWORD tkKind) // [IN] pass in the kind of token. { ULONG ulCount = 0; HRESULT hr = S_OK; LOCKREAD(); switch (tkKind) { case mdtTypeDef: ulCount = m_pStgdb->m_MiniMd.getCountTypeDefs(); // Remove global typedef from the count of typedefs (and handle the case where there is no global typedef) if (ulCount > 0) ulCount--; break; case mdtTypeRef: ulCount = m_pStgdb->m_MiniMd.getCountTypeRefs(); break; case mdtMethodDef: ulCount = m_pStgdb->m_MiniMd.getCountMethods(); break; case mdtFieldDef: ulCount = m_pStgdb->m_MiniMd.getCountFields(); break; case mdtMemberRef: ulCount = m_pStgdb->m_MiniMd.getCountMemberRefs(); break; case mdtInterfaceImpl: ulCount = m_pStgdb->m_MiniMd.getCountInterfaceImpls(); break; case mdtParamDef: ulCount = m_pStgdb->m_MiniMd.getCountParams(); break; case mdtFile: ulCount = m_pStgdb->m_MiniMd.getCountFiles(); break; case mdtAssemblyRef: ulCount = m_pStgdb->m_MiniMd.getCountAssemblyRefs(); break; case mdtAssembly: ulCount = m_pStgdb->m_MiniMd.getCountAssemblys(); break; case mdtCustomAttribute: ulCount = m_pStgdb->m_MiniMd.getCountCustomAttributes(); break; case mdtModule: ulCount = m_pStgdb->m_MiniMd.getCountModules(); break; case mdtPermission: ulCount = m_pStgdb->m_MiniMd.getCountDeclSecuritys(); break; case mdtSignature: ulCount = m_pStgdb->m_MiniMd.getCountStandAloneSigs(); break; case mdtEvent: ulCount = m_pStgdb->m_MiniMd.getCountEvents(); break; case mdtProperty: ulCount = m_pStgdb->m_MiniMd.getCountPropertys(); break; case mdtModuleRef: ulCount = m_pStgdb->m_MiniMd.getCountModuleRefs(); break; case mdtTypeSpec: ulCount = m_pStgdb->m_MiniMd.getCountTypeSpecs(); break; case mdtExportedType: ulCount = m_pStgdb->m_MiniMd.getCountExportedTypes(); break; case mdtManifestResource: ulCount = m_pStgdb->m_MiniMd.getCountManifestResources(); break; case mdtGenericParam: ulCount = m_pStgdb->m_MiniMd.getCountGenericParams(); break; case mdtGenericParamConstraint: ulCount = m_pStgdb->m_MiniMd.getCountGenericParamConstraints(); break; case mdtMethodSpec: ulCount = m_pStgdb->m_MiniMd.getCountMethodSpecs(); break; default: #ifdef _DEBUG if(REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 1)) _ASSERTE(!"Invalid Blob Offset"); #endif ulCount = 0; break; } ErrExit: return ulCount; } // MDInternalRW::GetCountWithTokenKind #endif //!DACCESS_COMPILE //******************************************************************************* // Enumerator helpers //******************************************************************************* //***************************************************************************** // enumerator init for typedef //***************************************************************************** __checkReturn HRESULT MDInternalRW::EnumTypeDefInit( // return hresult HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data { HRESULT hr = NOERROR; LOCKREAD(); _ASSERTE(phEnum); memset(phEnum, 0, sizeof(HENUMInternal)); phEnum->m_tkKind = mdtTypeDef; if ( m_pStgdb->m_MiniMd.HasDelete() ) { HENUMInternal::InitDynamicArrayEnum(phEnum); phEnum->m_tkKind = mdtTypeDef; for (ULONG index = 2; index <= m_pStgdb->m_MiniMd.getCountTypeDefs(); index ++ ) { TypeDefRec *pTypeDefRec; IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(index, &pTypeDefRec)); LPCSTR szTypeDefName; IfFailGo(m_pStgdb->m_MiniMd.getNameOfTypeDef(pTypeDefRec, &szTypeDefName)); if (IsDeletedName(szTypeDefName)) { continue; } IfFailGo( HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(index, mdtTypeDef) ) ); } } else { phEnum->m_EnumType = MDSimpleEnum; phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountTypeDefs(); // Skip over the global model typedef // // phEnum->u.m_ulCur : the current rid that is not yet enumerated // phEnum->u.m_ulStart : the first rid that will be returned by enumerator // phEnum->u.m_ulEnd : the last rid that will be returned by enumerator phEnum->u.m_ulStart = phEnum->u.m_ulCur = 2; phEnum->u.m_ulEnd = phEnum->m_ulCount + 1; if (phEnum->m_ulCount > 0) phEnum->m_ulCount --; } ErrExit: return hr; } // MDInternalRW::EnumTypeDefInit //***************************************************************************** // get the number of typedef in a scope //***************************************************************************** ULONG MDInternalRW::EnumTypeDefGetCount( HENUMInternal *phEnum) // [IN] the enumerator to retrieve information { _ASSERTE(phEnum->m_tkKind == mdtTypeDef); return phEnum->m_ulCount; } // MDInternalRW::EnumTypeDefGetCount //***************************************************************************** // enumerator for typedef //***************************************************************************** bool MDInternalRW::EnumTypeDefNext( // return hresult HENUMInternal *phEnum, // [IN] input enum mdTypeDef *ptd) // [OUT] return token { return EnumNext( phEnum, ptd); } // MDInternalRW::EnumTypeDefNext //***************************************** // Reset the enumerator to the beginning. //***************************************** void MDInternalRW::EnumTypeDefReset( HENUMInternal *phEnum) // [IN] the enumerator to be reset { EnumReset(phEnum); } // MDInternalRW::EnumTypeDefReset //***************************************** // Close the enumerator. Only for read/write mode that we need to close the cursor. // Hopefully with readonly mode, it will be a no-op //***************************************** void MDInternalRW::EnumTypeDefClose( HENUMInternal *phEnum) // [IN] the enumerator to be closed { EnumClose(phEnum); } // MDInternalRW::EnumTypeDefClose #ifndef DACCESS_COMPILE //***************************************************************************** // enumerator init for MethodImpl //***************************************************************************** __checkReturn HRESULT MDInternalRW::EnumMethodImplInit( // return hresult mdTypeDef td, // [IN] TypeDef over which to scope the enumeration. HENUMInternal *phEnumBody, // [OUT] buffer to fill for enumerator data for MethodBody tokens. HENUMInternal *phEnumDecl) // [OUT] buffer to fill for enumerator data for MethodDecl tokens. { HRESULT hr = NOERROR; int ridCur; mdToken tkMethodBody; mdToken tkMethodDecl; MethodImplRec *pRec; HENUMInternal hEnum; LOCKREAD(); _ASSERTE(TypeFromToken(td) == mdtTypeDef && !IsNilToken(td)); _ASSERTE(phEnumBody && phEnumDecl); memset(phEnumBody, 0, sizeof(HENUMInternal)); memset(phEnumDecl, 0, sizeof(HENUMInternal)); memset(&hEnum, 0, sizeof(HENUMInternal)); HENUMInternal::InitDynamicArrayEnum(phEnumBody); HENUMInternal::InitDynamicArrayEnum(phEnumDecl); phEnumBody->m_tkKind = (TBL_MethodImpl << 24); phEnumDecl->m_tkKind = (TBL_MethodImpl << 24); // Get the range of rids. IfFailGo( m_pStgdb->m_MiniMd.FindMethodImplHelper(td, &hEnum) ); while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur)) { // Get the MethodBody and MethodDeclaration tokens for the current // MethodImpl record. IfFailGo(m_pStgdb->m_MiniMd.GetMethodImplRecord(ridCur, &pRec)); tkMethodBody = m_pStgdb->m_MiniMd.getMethodBodyOfMethodImpl(pRec); tkMethodDecl = m_pStgdb->m_MiniMd.getMethodDeclarationOfMethodImpl(pRec); // Add the Method body/declaration pairs to the Enum IfFailGo( HENUMInternal::AddElementToEnum(phEnumBody, tkMethodBody ) ); IfFailGo( HENUMInternal::AddElementToEnum(phEnumDecl, tkMethodDecl ) ); } ErrExit: HENUMInternal::ClearEnum(&hEnum); return hr; } // MDInternalRW::EnumMethodImplInit //***************************************************************************** // get the number of MethodImpls in a scope //***************************************************************************** ULONG MDInternalRW::EnumMethodImplGetCount( HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. { _ASSERTE((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl && (phEnumDecl->m_tkKind >> 24) == TBL_MethodImpl); _ASSERTE(phEnumBody->m_EnumType == MDDynamicArrayEnum && phEnumDecl->m_EnumType == MDDynamicArrayEnum); _ASSERTE(phEnumBody->m_ulCount == phEnumDecl->m_ulCount); return phEnumBody->m_ulCount; } // MDInternalRW::EnumMethodImplGetCount //***************************************************************************** // enumerator for MethodImpl. //***************************************************************************** __checkReturn HRESULT MDInternalRW::EnumMethodImplNext( // return hresult HENUMInternal *phEnumBody, // [IN] input enum for MethodBody HENUMInternal *phEnumDecl, // [IN] input enum for MethodDecl mdToken *ptkBody, // [OUT] return token for MethodBody mdToken *ptkDecl) // [OUT] return token for MethodDecl { _ASSERTE((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl && (phEnumDecl->m_tkKind >> 24) == TBL_MethodImpl); _ASSERTE(phEnumBody->m_EnumType == MDDynamicArrayEnum && phEnumDecl->m_EnumType == MDDynamicArrayEnum); _ASSERTE(phEnumBody->m_ulCount == phEnumDecl->m_ulCount); _ASSERTE(ptkBody && ptkDecl); EnumNext(phEnumBody, ptkBody); return EnumNext(phEnumDecl, ptkDecl) ? S_OK : S_FALSE; } // MDInternalRW::EnumMethodImplNext //***************************************** // Reset the enumerator to the beginning. //***************************************** void MDInternalRW::EnumMethodImplReset( HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. { _ASSERTE((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl && (phEnumDecl->m_tkKind >> 24) == TBL_MethodImpl); _ASSERTE(phEnumBody->m_EnumType == MDDynamicArrayEnum && phEnumDecl->m_EnumType == MDDynamicArrayEnum); _ASSERTE(phEnumBody->m_ulCount == phEnumDecl->m_ulCount); EnumReset(phEnumBody); EnumReset(phEnumDecl); } // MDInternalRW::EnumMethodImplReset //***************************************** // Close the enumerator. //***************************************** void MDInternalRW::EnumMethodImplClose( HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. { _ASSERTE((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl && (phEnumDecl->m_tkKind >> 24) == TBL_MethodImpl); _ASSERTE(phEnumBody->m_EnumType == MDDynamicArrayEnum && phEnumDecl->m_EnumType == MDDynamicArrayEnum); _ASSERTE(phEnumBody->m_ulCount == phEnumDecl->m_ulCount); EnumClose(phEnumBody); EnumClose(phEnumDecl); } // MDInternalRW::EnumMethodImplClose #endif //!DACCESS_COMPILE //****************************************************************************** // enumerator for global functions //****************************************************************************** __checkReturn HRESULT MDInternalRW::EnumGlobalFunctionsInit( // return hresult HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data { return EnumInit(mdtMethodDef, m_tdModule, phEnum); } // MDInternalRW::EnumGlobalFunctionsInit //****************************************************************************** // enumerator for global fields //****************************************************************************** __checkReturn HRESULT MDInternalRW::EnumGlobalFieldsInit( // return hresult HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data { return EnumInit(mdtFieldDef, m_tdModule, phEnum); } // MDInternalRW::EnumGlobalFieldsInit #ifdef _PREFAST_ #pragma warning(push) #pragma warning(disable:21000) // Suppress PREFast warning about overly large function #endif //***************************************** // Enumerator initializer //***************************************** __checkReturn HRESULT MDInternalRW::EnumInit( // return S_FALSE if record not found DWORD tkKind, // [IN] which table to work on mdToken tkParent, // [IN] token to scope the search HENUMInternal *phEnum) // [OUT] the enumerator to fill { HRESULT hr = S_OK; ULONG ulStart, ulEnd, ulMax; ULONG index; LOCKREAD(); // Vars for query. _ASSERTE(phEnum); memset(phEnum, 0, sizeof(HENUMInternal)); // cache the tkKind and the scope phEnum->m_tkKind = TypeFromToken(tkKind); TypeDefRec *pRec; phEnum->m_EnumType = MDSimpleEnum; switch (TypeFromToken(tkKind)) { case mdtFieldDef: IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(tkParent), &pRec)); ulStart = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pRec); IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(tkParent), &ulEnd)); if ( m_pStgdb->m_MiniMd.HasDelete() ) { HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { FieldRec *pFieldRec; RID fieldRid; IfFailGo(m_pStgdb->m_MiniMd.GetFieldRid(index, &fieldRid)); IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(index, &pFieldRec)); LPCSTR szFieldName; IfFailGo(m_pStgdb->m_MiniMd.getNameOfField(pFieldRec, &szFieldName)); if (IsFdRTSpecialName(pFieldRec->GetFlags()) && IsDeletedName(szFieldName) ) { continue; } IfFailGo(m_pStgdb->m_MiniMd.GetFieldRid(index, &fieldRid)); IfFailGo(HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(fieldRid, mdtFieldDef))); } } else if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Field)) { HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { RID fieldRid; IfFailGo(m_pStgdb->m_MiniMd.GetFieldRid(index, &fieldRid)); IfFailGo(HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(fieldRid, mdtFieldDef))); } } else { HENUMInternal::InitSimpleEnum( mdtFieldDef, ulStart, ulEnd, phEnum); } break; case mdtMethodDef: IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(tkParent), &pRec)); ulStart = m_pStgdb->m_MiniMd.getMethodListOfTypeDef(pRec); IfFailGo(m_pStgdb->m_MiniMd.getEndMethodListOfTypeDef(RidFromToken(tkParent), &ulEnd)); if ( m_pStgdb->m_MiniMd.HasDelete() ) { HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { MethodRec *pMethodRec; RID methodRid; IfFailGo(m_pStgdb->m_MiniMd.GetMethodRid(index, &methodRid)); IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(methodRid, &pMethodRec)); LPCSTR szMethodName; IfFailGo(m_pStgdb->m_MiniMd.getNameOfMethod(pMethodRec, &szMethodName)); if (IsMdRTSpecialName(pMethodRec->GetFlags()) && IsDeletedName(szMethodName)) { continue; } IfFailGo(m_pStgdb->m_MiniMd.GetMethodRid(index, &methodRid)); IfFailGo(HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(methodRid, mdtMethodDef))); } } else if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Method)) { HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { RID methodRid; IfFailGo(m_pStgdb->m_MiniMd.GetMethodRid(index, &methodRid)); IfFailGo(HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(methodRid, mdtMethodDef))); } } else { HENUMInternal::InitSimpleEnum( mdtMethodDef, ulStart, ulEnd, phEnum); } break; case mdtInterfaceImpl: if (!m_pStgdb->m_MiniMd.IsSorted(TBL_InterfaceImpl) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_InterfaceImpl)) { // virtual sort table will be created! // CONVERT_READ_TO_WRITE_LOCK(); } IfFailGo( m_pStgdb->m_MiniMd.GetInterfaceImplsForTypeDef(RidFromToken(tkParent), &ulStart, &ulEnd) ); if ( m_pStgdb->m_MiniMd.IsSorted( TBL_InterfaceImpl ) ) { // These are index to InterfaceImpl table directly HENUMInternal::InitSimpleEnum( mdtInterfaceImpl, ulStart, ulEnd, phEnum); } else { // These are index to VirtualSort table. Skip over one level direction. HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { IfFailGo( HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(m_pStgdb->m_MiniMd.GetInterfaceImplRid(index), mdtInterfaceImpl) ) ); } } break; case mdtGenericParam: //@todo: deal with non-sorted case. if (TypeFromToken(tkParent) == mdtTypeDef) { IfFailGo(m_pStgdb->m_MiniMd.getGenericParamsForTypeDef( RidFromToken(tkParent), &phEnum->u.m_ulEnd, &(phEnum->u.m_ulStart))); } else { IfFailGo(m_pStgdb->m_MiniMd.getGenericParamsForMethodDef( RidFromToken(tkParent), &phEnum->u.m_ulEnd, &(phEnum->u.m_ulStart))); } break; case mdtGenericParamConstraint: if ( !m_pStgdb->m_MiniMd.IsSorted(TBL_GenericParamConstraint) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_GenericParamConstraint)) { // virtual sort table will be created! // CONVERT_READ_TO_WRITE_LOCK(); } IfFailGo( m_pStgdb->m_MiniMd.GetGenericParamConstraintsForToken(RidFromToken(tkParent), &ulStart, &ulEnd) ); if ( m_pStgdb->m_MiniMd.IsSorted( TBL_GenericParamConstraint ) ) { // These are index to GenericParamConstraint table directly HENUMInternal::InitSimpleEnum( mdtGenericParamConstraint, ulStart, ulEnd, phEnum); } else { // These are index to VirtualSort table. Skip over one level direction. HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { IfFailGo( HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(m_pStgdb->m_MiniMd.GetGenericParamConstraintRid(index), mdtGenericParamConstraint) ) ); } } break; case mdtProperty: RID ridPropertyMap; PropertyMapRec *pPropertyMapRec; // get the starting/ending rid of properties of this typedef IfFailGo(m_pStgdb->m_MiniMd.FindPropertyMapFor(RidFromToken(tkParent), &ridPropertyMap)); if (!InvalidRid(ridPropertyMap)) { IfFailGo(m_pStgdb->m_MiniMd.GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec)); ulStart = m_pStgdb->m_MiniMd.getPropertyListOfPropertyMap(pPropertyMapRec); IfFailGo(m_pStgdb->m_MiniMd.getEndPropertyListOfPropertyMap(ridPropertyMap, &ulEnd)); ulMax = m_pStgdb->m_MiniMd.getCountPropertys() + 1; if(ulStart == 0) ulStart = 1; if(ulEnd > ulMax) ulEnd = ulMax; if(ulStart > ulEnd) ulStart = ulEnd; if ( m_pStgdb->m_MiniMd.HasDelete() ) { HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { PropertyRec *pPropertyRec; RID propertyRid; IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRid(index, &propertyRid)); IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord( propertyRid, &pPropertyRec)); LPCSTR szPropertyName; IfFailGo(m_pStgdb->m_MiniMd.getNameOfProperty(pPropertyRec, &szPropertyName)); if (IsPrRTSpecialName(pPropertyRec->GetPropFlags()) && IsDeletedName(szPropertyName)) { continue; } IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRid(index, &propertyRid)); IfFailGo(HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(propertyRid, mdtProperty))); } } else if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Property)) { HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { RID propertyRid; IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRid(index, &propertyRid)); IfFailGo(HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(propertyRid, mdtProperty))); } } else { HENUMInternal::InitSimpleEnum( mdtProperty, ulStart, ulEnd, phEnum); } } break; case mdtEvent: RID ridEventMap; EventMapRec *pEventMapRec; // get the starting/ending rid of events of this typedef IfFailGo(m_pStgdb->m_MiniMd.FindEventMapFor(RidFromToken(tkParent), &ridEventMap)); if (!InvalidRid(ridEventMap)) { IfFailGo(m_pStgdb->m_MiniMd.GetEventMapRecord(ridEventMap, &pEventMapRec)); ulStart = m_pStgdb->m_MiniMd.getEventListOfEventMap(pEventMapRec); IfFailGo(m_pStgdb->m_MiniMd.getEndEventListOfEventMap(ridEventMap, &ulEnd)); ulMax = m_pStgdb->m_MiniMd.getCountEvents() + 1; if(ulStart == 0) ulStart = 1; if(ulEnd > ulMax) ulEnd = ulMax; if(ulStart > ulEnd) ulStart = ulEnd; if ( m_pStgdb->m_MiniMd.HasDelete() ) { HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { EventRec *pEventRec; RID eventRid; IfFailGo(m_pStgdb->m_MiniMd.GetEventRid(index, &eventRid)); IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(eventRid, &pEventRec)); LPCSTR szEventName; IfFailGo(m_pStgdb->m_MiniMd.getNameOfEvent(pEventRec, &szEventName)); if (IsEvRTSpecialName(pEventRec->GetEventFlags()) && IsDeletedName(szEventName)) { continue; } IfFailGo(m_pStgdb->m_MiniMd.GetEventRid(index, &eventRid)); IfFailGo(HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(eventRid, mdtEvent))); } } else if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Event)) { HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { RID eventRid; IfFailGo(m_pStgdb->m_MiniMd.GetEventRid(index, &eventRid)); IfFailGo( HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(eventRid, mdtEvent) ) ); } } else { HENUMInternal::InitSimpleEnum( mdtEvent, ulStart, ulEnd, phEnum); } } break; case mdtParamDef: _ASSERTE(TypeFromToken(tkParent) == mdtMethodDef); MethodRec *pMethodRec; IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkParent), &pMethodRec)); // figure out the start rid and end rid of the parameter list of this methoddef ulStart = m_pStgdb->m_MiniMd.getParamListOfMethod(pMethodRec); IfFailGo(m_pStgdb->m_MiniMd.getEndParamListOfMethod(RidFromToken(tkParent), &ulEnd)); if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Param)) { HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { RID paramRid; IfFailGo(m_pStgdb->m_MiniMd.GetParamRid(index, ¶mRid)); IfFailGo(HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(paramRid, mdtParamDef))); } } else { HENUMInternal::InitSimpleEnum( mdtParamDef, ulStart, ulEnd, phEnum); } break; case mdtCustomAttribute: if (!m_pStgdb->m_MiniMd.IsSorted(TBL_CustomAttribute) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_CustomAttribute)) { // CA's map table table will be sorted! // CONVERT_READ_TO_WRITE_LOCK(); } IfFailGo( m_pStgdb->m_MiniMd.GetCustomAttributeForToken(tkParent, &ulStart, &ulEnd) ); if ( m_pStgdb->m_MiniMd.IsSorted( TBL_CustomAttribute ) ) { // These are index to CustomAttribute table directly HENUMInternal::InitSimpleEnum( mdtCustomAttribute, ulStart, ulEnd, phEnum); } else { // These are index to VirtualSort table. Skip over one level direction. HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = ulStart; index < ulEnd; index ++ ) { IfFailGo( HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(m_pStgdb->m_MiniMd.GetCustomAttributeRid(index), mdtCustomAttribute) ) ); } } break; case mdtAssemblyRef: _ASSERTE(IsNilToken(tkParent)); phEnum->u.m_ulStart = 1; phEnum->u.m_ulEnd = m_pStgdb->m_MiniMd.getCountAssemblyRefs() + 1; break; case mdtFile: _ASSERTE(IsNilToken(tkParent)); phEnum->u.m_ulStart = 1; phEnum->u.m_ulEnd = m_pStgdb->m_MiniMd.getCountFiles() + 1; break; case mdtExportedType: _ASSERTE(IsNilToken(tkParent)); if ( m_pStgdb->m_MiniMd.HasDelete() ) { HENUMInternal::InitDynamicArrayEnum(phEnum); phEnum->m_tkKind = mdtExportedType; for (ULONG typeindex = 1; typeindex <= m_pStgdb->m_MiniMd.getCountExportedTypes(); typeindex ++ ) { ExportedTypeRec *pExportedTypeRec; IfFailGo(m_pStgdb->m_MiniMd.GetExportedTypeRecord(typeindex, &pExportedTypeRec)); LPCSTR szTypeName; IfFailGo(m_pStgdb->m_MiniMd.getTypeNameOfExportedType(pExportedTypeRec, &szTypeName)); if (IsDeletedName(szTypeName)) { continue; } IfFailGo( HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(typeindex, mdtExportedType) ) ); } } else { phEnum->u.m_ulStart = 1; phEnum->u.m_ulEnd = m_pStgdb->m_MiniMd.getCountExportedTypes() + 1; } break; case mdtManifestResource: _ASSERTE(IsNilToken(tkParent)); phEnum->u.m_ulStart = 1; phEnum->u.m_ulEnd = m_pStgdb->m_MiniMd.getCountManifestResources() + 1; break; case mdtModuleRef: _ASSERTE(IsNilToken(tkParent)); phEnum->u.m_ulStart = 1; phEnum->u.m_ulEnd = m_pStgdb->m_MiniMd.getCountModuleRefs() + 1; break; default: _ASSERTE(!"ENUM INIT not implemented for the uncompressed format!"); IfFailGo(E_NOTIMPL); break; } // If the count is negative, the metadata is corrupted somehow. if (phEnum->u.m_ulEnd < phEnum->u.m_ulStart) IfFailGo(CLDB_E_FILE_CORRUPT); phEnum->m_ulCount = phEnum->u.m_ulEnd - phEnum->u.m_ulStart; phEnum->u.m_ulCur = phEnum->u.m_ulStart; ErrExit: // we are done return hr; } // MDInternalRW::EnumInit #ifdef _PREFAST_ #pragma warning(pop) #endif //***************************************** // Enumerator initializer //***************************************** __checkReturn HRESULT MDInternalRW::EnumAllInit( // return S_FALSE if record not found DWORD tkKind, // [IN] which table to work on HENUMInternal *phEnum) // [OUT] the enumerator to fill { HRESULT hr = S_OK; LOCKREAD(); // Vars for query. _ASSERTE(phEnum); memset(phEnum, 0, sizeof(HENUMInternal)); // cache the tkKind and the scope phEnum->m_tkKind = TypeFromToken(tkKind); phEnum->m_EnumType = MDSimpleEnum; switch (TypeFromToken(tkKind)) { case mdtTypeRef: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountTypeRefs(); break; case mdtMemberRef: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountMemberRefs(); break; case mdtSignature: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountStandAloneSigs(); break; case mdtMethodDef: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountMethods(); break; case mdtMethodSpec: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountMethodSpecs(); break; case mdtFieldDef: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountFields(); break; case mdtTypeSpec: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountTypeSpecs(); break; case mdtAssemblyRef: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountAssemblyRefs(); break; case mdtModuleRef: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountModuleRefs(); break; case mdtTypeDef: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountTypeDefs(); break; case mdtFile: phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountFiles(); break; default: _ASSERTE(!"Bad token kind!"); break; } phEnum->u.m_ulStart = phEnum->u.m_ulCur = 1; phEnum->u.m_ulEnd = phEnum->m_ulCount + 1; ErrExit: // we are done return hr; } // MDInternalRW::EnumAllInit //***************************************** // get the count //***************************************** ULONG MDInternalRW::EnumGetCount( HENUMInternal *phEnum) // [IN] the enumerator to retrieve information { _ASSERTE(phEnum); return phEnum->m_ulCount; } // MDInternalRW::EnumGetCount //***************************************** // Get next value contained in the enumerator //***************************************** bool MDInternalRW::EnumNext( HENUMInternal *phEnum, // [IN] the enumerator to retrieve information mdToken *ptk) // [OUT] token to scope the search { _ASSERTE(phEnum && ptk); if (phEnum->u.m_ulCur >= phEnum->u.m_ulEnd) return false; if ( phEnum->m_EnumType == MDSimpleEnum ) { *ptk = phEnum->u.m_ulCur | phEnum->m_tkKind; phEnum->u.m_ulCur++; } else { TOKENLIST *pdalist = (TOKENLIST *)&(phEnum->m_cursor); _ASSERTE( phEnum->m_EnumType == MDDynamicArrayEnum ); *ptk = *( pdalist->Get(phEnum->u.m_ulCur++) ); } return true; } // MDInternalRW::EnumNext //***************************************** // Reset the enumerator to the beginning. //***************************************** void MDInternalRW::EnumReset( HENUMInternal *phEnum) // [IN] the enumerator to be reset { _ASSERTE(phEnum); _ASSERTE( phEnum->m_EnumType == MDSimpleEnum || phEnum->m_EnumType == MDDynamicArrayEnum); phEnum->u.m_ulCur = phEnum->u.m_ulStart; } // MDInternalRW::EnumReset //***************************************** // Close the enumerator. Only for read/write mode that we need to close the cursor. // Hopefully with readonly mode, it will be a no-op //***************************************** void MDInternalRW::EnumClose( HENUMInternal *phEnum) // [IN] the enumerator to be closed { _ASSERTE( phEnum->m_EnumType == MDSimpleEnum || phEnum->m_EnumType == MDDynamicArrayEnum || phEnum->m_EnumType == MDCustomEnum ); if (phEnum->m_EnumType == MDDynamicArrayEnum) HENUMInternal::ClearEnum(phEnum); } // MDInternalRW::EnumClose #ifndef DACCESS_COMPILE //--------------------------------------------------------------------------------------- // // Initialize enumerator of PermissionSets. // // Return Value: // CLDB_E_RECORD_NOTFOUND ... If record not found. // S_OK and empty enumeration ... If tkParent is nil token and Action is dclActionNil. // __checkReturn HRESULT MDInternalRW::EnumPermissionSetsInit( mdToken tkParent, // [IN] Token to scope the search. CorDeclSecurity Action, // [IN] Action to scope the search. HENUMInternal *phEnum) // [OUT] Enumerator to fill. { HRESULT hr = S_OK; DeclSecurityRec *pDecl; RID ridCur; RID ridEnd; LOCKREAD(); _ASSERTE(phEnum != NULL); phEnum->m_EnumType = MDSimpleEnum; if (!m_pStgdb->m_MiniMd.IsSorted(TBL_DeclSecurity) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_DeclSecurity)) { // DeclSecurity lookup table might be created! CONVERT_READ_TO_WRITE_LOCK(); } // This call requires write-lock if the table is not sorted and doesn't have VirtualSort: IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityForToken(tkParent, &ridCur, &ridEnd)); if (m_pStgdb->m_MiniMd.IsSorted(TBL_DeclSecurity)) { // These are index to DeclSecurity table directly if (Action != dclActionNil) { for (; ridCur < ridEnd; ridCur++) { IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(ridCur, &pDecl)); if (Action == m_pStgdb->m_MiniMd.getActionOfDeclSecurity(pDecl)) { // found a match HENUMInternal::InitSimpleEnum(mdtPermission, ridCur, ridCur + 1, phEnum); goto ErrExit; } } hr = CLDB_E_RECORD_NOTFOUND; } else { HENUMInternal::InitSimpleEnum(mdtPermission, ridCur, ridEnd, phEnum); } } else { // These are index to VirtualSort table. Skip over one level direction. if (Action != dclActionNil) { RID ridActual; for (; ridCur < ridEnd; ridCur++) { ridActual = m_pStgdb->m_MiniMd.GetDeclSecurityRid(ridCur); IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(ridActual, &pDecl)); if (Action == m_pStgdb->m_MiniMd.getActionOfDeclSecurity(pDecl)) { // found a match HENUMInternal::InitSimpleEnum(mdtPermission, ridActual, ridActual + 1, phEnum); goto ErrExit; } } hr = CLDB_E_RECORD_NOTFOUND; } else { HENUMInternal::InitDynamicArrayEnum(phEnum); for (; ridCur < ridEnd; ridCur++) { IfFailGo(HENUMInternal::AddElementToEnum( phEnum, TokenFromRid(m_pStgdb->m_MiniMd.GetDeclSecurityRid(ridCur), mdtPermission))); } } } ErrExit: return hr; } // MDInternalRW::EnumPermissionSetsInit #endif //!DACCESS_COMPILE //***************************************** // Enumerator initializer for CustomAttributes //***************************************** __checkReturn HRESULT MDInternalRW::EnumCustomAttributeByNameInit(// return S_FALSE if record not found mdToken tkParent, // [IN] token to scope the search LPCSTR szName, // [IN] CustomAttribute's name to scope the search HENUMInternal *phEnum) // [OUT] the enumerator to fill { return m_pStgdb->m_MiniMd.CommonEnumCustomAttributeByName(tkParent, szName, false, phEnum); } // MDInternalRW::EnumCustomAttributeByNameInit //***************************************** // Enumerator for CustomAttributes which doesn't // allocate any memory //***************************************** __checkReturn HRESULT MDInternalRW::SafeAndSlowEnumCustomAttributeByNameInit(// return S_FALSE if record not found mdToken tkParent, // [IN] token to scope the search LPCSTR szName, // [IN] CustomAttribute's name to scope the search HENUMInternal *phEnum) // [OUT] The enumerator { _ASSERTE(phEnum); HRESULT hr; ULONG ridStart, ridEnd; // Loop start and endpoints. // Get the list of custom values for the parent object. if (m_pStgdb->m_MiniMd.IsSorted(TBL_CustomAttribute)) { IfFailRet(m_pStgdb->m_MiniMd.getCustomAttributeForToken(tkParent, &ridEnd, &ridStart)); // If found none, done. if (ridStart == 0) goto NoMatch; } else { // linear scan of entire table. ridEnd = m_pStgdb->m_MiniMd.getCountCustomAttributes() + 1; if (ridEnd == 1) goto NoMatch; ridStart = 1; } phEnum->m_EnumType = MDCustomEnum; phEnum->m_tkKind = mdtCustomAttribute; phEnum->u.m_ulStart = ridStart; phEnum->u.m_ulEnd = ridEnd; phEnum->u.m_ulCur = ridStart; return S_OK; NoMatch: return S_FALSE; } // MDInternalRW::SafeAndSlowEnumCustomAttributeByNameInit __checkReturn HRESULT MDInternalRW::SafeAndSlowEnumCustomAttributeByNameNext(// return S_FALSE if record not found mdToken tkParent, // [IN] token to scope the search LPCSTR szName, // [IN] CustomAttribute's name to scope the search HENUMInternal *phEnum, // [IN] The enumerator mdCustomAttribute *mdAttribute) // [OUT] The custom attribute that was found { _ASSERTE(phEnum); _ASSERTE(phEnum->m_EnumType == MDCustomEnum); _ASSERTE(phEnum->m_tkKind == mdtCustomAttribute); // Look for one with the given name. for (; phEnum->u.m_ulCur < phEnum->u.m_ulEnd; ++phEnum->u.m_ulCur) { if (S_OK == m_pStgdb->m_MiniMd.CompareCustomAttribute( tkParent, szName, phEnum->u.m_ulCur)) { // If here, found a match. *mdAttribute = TokenFromRid(phEnum->u.m_ulCur, mdtCustomAttribute); phEnum->u.m_ulCur++; return S_OK; } } // No match... return S_FALSE; }// MDInternalRW::SafeAndSlowEnumCustomAttributeByNameNext //***************************************** // Nagivator helper to navigate back to the parent token given a token. // For example, given a memberdef token, it will return the containing typedef. // // the mapping is as following: // ---given child type---------parent type // mdMethodDef mdTypeDef // mdFieldDef mdTypeDef // mdInterfaceImpl mdTypeDef // mdParam mdMethodDef // mdProperty mdTypeDef // mdEvent mdTypeDef // //***************************************** __checkReturn HRESULT MDInternalRW::GetParentToken( mdToken tkChild, // [IN] given child token mdToken *ptkParent) // [OUT] returning parent { HRESULT hr = NOERROR; LOCKREAD(); _ASSERTE(ptkParent); switch (TypeFromToken(tkChild)) { case mdtTypeDef: { RID rid; if (!m_pStgdb->m_MiniMd.IsSorted(TBL_NestedClass) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_NestedClass)) { // NestedClass table is not sorted. CONVERT_READ_TO_WRITE_LOCK(); } IfFailGo(m_pStgdb->m_MiniMd.FindNestedClassFor(RidFromToken(tkChild), &rid)); if (InvalidRid(rid)) { // If not found, the *ptkParent has to be left unchanged! (callers depend on that) hr = S_OK; } else { NestedClassRec *pRecord; IfFailGo(m_pStgdb->m_MiniMd.GetNestedClassRecord(rid, &pRecord)); *ptkParent = m_pStgdb->m_MiniMd.getEnclosingClassOfNestedClass(pRecord); } break; } case mdtMethodDef: IfFailGo(m_pStgdb->m_MiniMd.FindParentOfMethodHelper(RidFromToken(tkChild), ptkParent)); RidToToken(*ptkParent, mdtTypeDef); break; case mdtMethodSpec: { MethodSpecRec *pRec; IfFailGo(m_pStgdb->m_MiniMd.GetMethodSpecRecord(RidFromToken(tkChild), &pRec)); *ptkParent = m_pStgdb->m_MiniMd.getMethodOfMethodSpec(pRec); } break; case mdtFieldDef: IfFailGo(m_pStgdb->m_MiniMd.FindParentOfFieldHelper(RidFromToken(tkChild), ptkParent)); RidToToken(*ptkParent, mdtTypeDef); break; case mdtParamDef: IfFailGo(m_pStgdb->m_MiniMd.FindParentOfParamHelper(RidFromToken(tkChild), ptkParent)); RidToToken(*ptkParent, mdtMethodDef); break; case mdtMemberRef: { MemberRefRec *pRec; IfFailGo(m_pStgdb->m_MiniMd.GetMemberRefRecord(RidFromToken(tkChild), &pRec)); *ptkParent = m_pStgdb->m_MiniMd.getClassOfMemberRef(pRec); break; } case mdtCustomAttribute: { CustomAttributeRec *pRec; IfFailGo(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(tkChild), &pRec)); *ptkParent = m_pStgdb->m_MiniMd.getParentOfCustomAttribute(pRec); break; } case mdtEvent: IfFailGo(m_pStgdb->m_MiniMd.FindParentOfEventHelper(tkChild, ptkParent)); break; case mdtProperty: IfFailGo(m_pStgdb->m_MiniMd.FindParentOfPropertyHelper(tkChild, ptkParent)); break; default: _ASSERTE(!"NYI: for compressed format!"); break; } ErrExit: return hr; } // MDInternalRW::GetParentToken //***************************************************************************** // Get information about a CustomAttribute. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetCustomAttributeProps( // S_OK or error. mdCustomAttribute at, // The attribute. mdToken *pTkType) // Put attribute type here. { HRESULT hr; // Getting the custom value prop with a token, no need to lock! _ASSERTE(TypeFromToken(at) == mdtCustomAttribute); // Do a linear search on compressed version as we do not want to // depend on ICR. // CustomAttributeRec *pCustomAttributeRec; IfFailRet(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(at), &pCustomAttributeRec)); *pTkType = m_pStgdb->m_MiniMd.getTypeOfCustomAttribute(pCustomAttributeRec); return S_OK; } // MDInternalRW::GetCustomAttributeProps //***************************************************************************** // return custom value //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetCustomAttributeAsBlob( mdCustomAttribute cv, // [IN] given custom attribute token void const **ppBlob, // [OUT] return the pointer to internal blob ULONG *pcbSize) // [OUT] return the size of the blob { // Getting the custom value prop with a token, no need to lock! HRESULT hr; _ASSERTE(ppBlob && pcbSize && TypeFromToken(cv) == mdtCustomAttribute); CustomAttributeRec *pCustomAttributeRec; IfFailRet(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(cv), &pCustomAttributeRec)); IfFailRet(m_pStgdb->m_MiniMd.getValueOfCustomAttribute(pCustomAttributeRec, reinterpret_cast(ppBlob), pcbSize)); return S_OK; } // MDInternalRW::GetCustomAttributeAsBlob //***************************************************************************** // Helper function to lookup and retrieve a CustomAttribute. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetCustomAttributeByName( // S_OK or error. mdToken tkObj, // [IN] Object with Custom Attribute. LPCUTF8 szName, // [IN] Name of desired Custom Attribute. __deref_out_bcount(*pcbData) const void **ppData, // [OUT] Put pointer to data here. __out ULONG *pcbData) // [OUT] Put size of data here. { HRESULT hr = S_OK; LOCKREADIFFAILRET(); return m_pStgdb->m_MiniMd.CommonGetCustomAttributeByName(tkObj, szName, ppData, pcbData); } // MDInternalRW::GetCustomAttributeByName //***************************************************************************** // return the name of a custom attribute //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetNameOfCustomAttribute( // S_OK or error. mdCustomAttribute mdAttribute, // [IN] The Custom Attribute LPCUTF8 *pszNamespace, // [OUT] Namespace of Custom Attribute. LPCUTF8 *pszName) // [OUT] Name of Custom Attribute. { HRESULT hr = S_OK; LOCKREADIFFAILRET(); hr = m_pStgdb->m_MiniMd.CommonGetNameOfCustomAttribute(RidFromToken(mdAttribute), pszNamespace, pszName); return (hr == S_FALSE) ? E_FAIL : hr; } // MDInternalRW::GetNameOfCustomAttribute //***************************************************************************** // return scope properties //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetScopeProps( LPCSTR *pszName, // [OUT] scope name GUID *pmvid) // [OUT] version id { HRESULT hr = S_OK; LOCKREAD(); ModuleRec *pModuleRec; // there is only one module record IfFailGo(m_pStgdb->m_MiniMd.GetModuleRecord(1, &pModuleRec)); if (pmvid != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getMvidOfModule(pModuleRec, pmvid)); } if (pszName != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getNameOfModule(pModuleRec, pszName)); } ErrExit: return hr; } // MDInternalRW::GetScopeProps //***************************************************************************** // This function gets the "built for" version of a metadata scope. // NOTE: if the scope has never been saved, it will not have a built-for // version, and an empty string will be returned. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetVersionString( // S_OK or error. LPCSTR *pVer) // [OUT] Put version string here. { HRESULT hr = NOERROR; if (m_pStgdb->m_pvMd != NULL) { // For convenience, get a pointer to the version string. // @todo: get from alternate locations when there is no STOREAGESIGNATURE. *pVer = reinterpret_cast(reinterpret_cast(m_pStgdb->m_pvMd)->pVersion); } else { // No string. *pVer = NULL; } return hr; } // MDInternalRW::GetVersionString //***************************************************************************** // Find a given member in a TypeDef (typically a class). //***************************************************************************** __checkReturn HRESULT MDInternalRW::FindMethodDef(// S_OK or error. mdTypeDef classdef, // The owning class of the member. LPCSTR szName, // Name of the member in utf8. PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature ULONG cbSigBlob, // [IN] count of bytes in the signature blob mdMethodDef *pmethoddef) // Put MemberDef token here. { HRESULT hr = S_OK; LOCKREAD(); _ASSERTE(szName && pmethoddef); IfFailGo(ImportHelper::FindMethod(&(m_pStgdb->m_MiniMd), classdef, szName, pvSigBlob, cbSigBlob, pmethoddef)); ErrExit: return hr; } //***************************************************************************** // Find a given member in a TypeDef (typically a class). //***************************************************************************** __checkReturn HRESULT MDInternalRW::FindMethodDefUsingCompare(// S_OK or error. mdTypeDef classdef, // The owning class of the member. LPCSTR szName, // Name of the member in utf8. PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature ULONG cbSigBlob, // [IN] count of bytes in the signature blob PSIGCOMPARE pSignatureCompare, // [IN] Routine to compare signatures void* pSignatureArgs, // [IN] Additional info to supply the compare function mdMethodDef *pmethoddef) // Put MemberDef token here. { HRESULT hr = S_OK; LOCKREAD(); _ASSERTE(szName && pmethoddef); IfFailGo(ImportHelper::FindMethod(&(m_pStgdb->m_MiniMd), classdef, szName, pvSigBlob, cbSigBlob, pmethoddef, 0, pSignatureCompare, pSignatureArgs)); ErrExit: return hr; } //***************************************************************************** // Find a given param of a Method. //***************************************************************************** __checkReturn HRESULT MDInternalRW::FindParamOfMethod(// S_OK or error. mdMethodDef md, // [IN] The owning method of the param. ULONG iSeq, // [IN] The sequence # of the param. mdParamDef *pparamdef) // [OUT] Put ParamDef token here. { ParamRec *pParamRec; RID ridStart, ridEnd; HRESULT hr = NOERROR; MethodRec *pMethodRec = NULL; LOCKREAD(); _ASSERTE(TypeFromToken(md) == mdtMethodDef && pparamdef); // get the methoddef record IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec)); // figure out the start rid and end rid of the parameter list of this methoddef ridStart = m_pStgdb->m_MiniMd.getParamListOfMethod(pMethodRec); IfFailGo(m_pStgdb->m_MiniMd.getEndParamListOfMethod(RidFromToken(md), &ridEnd)); // loop through each param // for (; ridStart < ridEnd; ridStart++) { RID paramRid; IfFailGo(m_pStgdb->m_MiniMd.GetParamRid(ridStart, ¶mRid)); IfFailGo(m_pStgdb->m_MiniMd.GetParamRecord(paramRid, &pParamRec)); if (iSeq == m_pStgdb->m_MiniMd.getSequenceOfParam( pParamRec) ) { // parameter has the sequence number matches what we are looking for *pparamdef = TokenFromRid(paramRid, mdtParamDef ); goto ErrExit; } } hr = CLDB_E_RECORD_NOTFOUND; ErrExit: return hr; } // MDInternalRW::FindParamOfMethod //***************************************************************************** // return a pointer which points to meta data's internal string // return the the type name in utf8 //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetNameOfTypeDef( // return hresult mdTypeDef classdef, // given typedef LPCSTR* pszname, // pointer to an internal UTF8 string LPCSTR* psznamespace) // pointer to the namespace. { // No need to lock this method. HRESULT hr; if (pszname != NULL) { *pszname = NULL; } if (psznamespace != NULL) { *psznamespace = NULL; } if (TypeFromToken(classdef) == mdtTypeDef) { TypeDefRec *pTypeDefRec; IfFailRet(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(classdef), &pTypeDefRec)); if (pszname != NULL) { IfFailRet(m_pStgdb->m_MiniMd.getNameOfTypeDef(pTypeDefRec, pszname)); } if (psznamespace != NULL) { IfFailRet(m_pStgdb->m_MiniMd.getNamespaceOfTypeDef(pTypeDefRec, psznamespace)); } return S_OK; } _ASSERTE(!"Invalid argument(s) of GetNameOfTypeDef"); return CLDB_E_INTERNALERROR; } // MDInternalRW::GetNameOfTypeDef //***************************************************************************** // return pDual indicating if the given TypeDef is marked as a Dual interface //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetIsDualOfTypeDef(// return hresult mdTypeDef classdef, // given classdef ULONG *pDual) // [OUT] return dual flag here. { ULONG iFace=0; // Iface type. HRESULT hr; // A result. // no need to lock at this level hr = GetIfaceTypeOfTypeDef(classdef, &iFace); if (hr == S_OK) *pDual = (iFace == ifDual); else *pDual = 1; return hr; } // MDInternalRW::GetIsDualOfTypeDef __checkReturn HRESULT MDInternalRW::GetIfaceTypeOfTypeDef( mdTypeDef classdef, // [IN] given classdef. ULONG *pIface) // [OUT] 0=dual, 1=vtable, 2=dispinterface { HRESULT hr; // A result. const BYTE *pVal; // The custom value. ULONG cbVal; // Size of the custom value. ULONG ItfType = DEFAULT_COM_INTERFACE_TYPE; // Set the interface type to the default. // all of the public functions that it calls have proper locked // If the value is not present, the class is assumed dual. hr = GetCustomAttributeByName(classdef, INTEROP_INTERFACETYPE_TYPE, (const void**)&pVal, &cbVal); if (hr == S_OK) { _ASSERTE("The ComInterfaceType custom attribute is invalid" && cbVal); _ASSERTE("ComInterfaceType custom attribute does not have the right format" && (*pVal == 0x01) && (*(pVal + 1) == 0x00)); ItfType = *(pVal + 2); if (ItfType >= ifLast) ItfType = DEFAULT_COM_INTERFACE_TYPE; } // Set the return value. *pIface = ItfType; return hr; } // MDInternalRW::GetIfaceTypeOfTypeDef //***************************************************************************** // Given a methoddef, return a pointer to methoddef's name //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetNameOfMethodDef( mdMethodDef md, LPCSTR *pszMethodName) { // name of method will not change. So no need to lock HRESULT hr; MethodRec *pMethodRec; *pszMethodName = NULL; IfFailRet(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec)); IfFailRet(m_pStgdb->m_MiniMd.getNameOfMethod(pMethodRec, pszMethodName)); return S_OK; } // MDInternalRW::GetNameOfMethodDef //***************************************************************************** // Given a methoddef, return a pointer to methoddef's signature and methoddef's name //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetNameAndSigOfMethodDef( mdMethodDef methoddef, // [IN] given memberdef PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of COM+ signature ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob LPCSTR *pszMethodName) { HRESULT hr; // we don't need lock here because name and signature will not change // Output parameter should not be NULL _ASSERTE(ppvSigBlob && pcbSigBlob); _ASSERTE(TypeFromToken(methoddef) == mdtMethodDef); MethodRec *pMethodRec; *pszMethodName = NULL; *ppvSigBlob = NULL; *ppvSigBlob = NULL; IfFailRet(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(methoddef), &pMethodRec)); IfFailRet(m_pStgdb->m_MiniMd.getSignatureOfMethod(pMethodRec, ppvSigBlob, pcbSigBlob)); return GetNameOfMethodDef(methoddef, pszMethodName); } // MDInternalRW::GetNameAndSigOfMethodDef //***************************************************************************** // Given a FieldDef, return a pointer to FieldDef's name in UTF8 //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetNameOfFieldDef( // return hresult mdFieldDef fd, // given field LPCSTR *pszFieldName) { // we don't need lock here because name of field will not change HRESULT hr; FieldRec *pFieldRec; *pszFieldName = NULL; IfFailRet(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(fd), &pFieldRec)); IfFailRet(m_pStgdb->m_MiniMd.getNameOfField(pFieldRec, pszFieldName)); return S_OK; } // MDInternalRW::GetNameOfFieldDef //***************************************************************************** // Given a classdef, return a pointer to classdef's name in UTF8 //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetNameOfTypeRef( // return TypeDef's name mdTypeRef classref, // [IN] given typeref LPCSTR *psznamespace, // [OUT] return typeref name LPCSTR *pszname) // [OUT] return typeref namespace { _ASSERTE(TypeFromToken(classref) == mdtTypeRef); HRESULT hr; *psznamespace = NULL; *pszname = NULL; // we don't need lock here because name of a typeref will not change TypeRefRec *pTypeRefRec; IfFailRet(m_pStgdb->m_MiniMd.GetTypeRefRecord(RidFromToken(classref), &pTypeRefRec)); IfFailRet(m_pStgdb->m_MiniMd.getNamespaceOfTypeRef(pTypeRefRec, psznamespace)); IfFailRet(m_pStgdb->m_MiniMd.getNameOfTypeRef(pTypeRefRec, pszname)); return S_OK; } // MDInternalRW::GetNameOfTypeRef //***************************************************************************** // return the resolutionscope of typeref //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetResolutionScopeOfTypeRef( mdTypeRef classref, // given classref mdToken *ptkResolutionScope) { HRESULT hr = S_OK; TypeRefRec *pTypeRefRec = NULL; LOCKREAD(); _ASSERTE(TypeFromToken(classref) == mdtTypeRef && RidFromToken(classref)); IfFailGo(m_pStgdb->m_MiniMd.GetTypeRefRecord(RidFromToken(classref), &pTypeRefRec)); _ASSERTE(hr == S_OK); *ptkResolutionScope = m_pStgdb->m_MiniMd.getResolutionScopeOfTypeRef(pTypeRefRec); return S_OK; ErrExit: *ptkResolutionScope = mdTokenNil; return hr; } // MDInternalRW::GetResolutionScopeOfTypeRef //***************************************************************************** // Given a name, find the corresponding TypeRef. //***************************************************************************** __checkReturn HRESULT MDInternalRW::FindTypeRefByName( // S_OK or error. LPCSTR szNamespace, // [IN] Namespace for the TypeRef. LPCSTR szName, // [IN] Name of the TypeRef. mdToken tkResolutionScope, // [IN] Resolution Scope fo the TypeRef. mdTypeRef *ptk) // [OUT] TypeRef token returned. { HRESULT hr = NOERROR; ULONG cTypeRefRecs; TypeRefRec *pTypeRefRec; LPCUTF8 szNamespaceTmp; LPCUTF8 szNameTmp; mdToken tkRes; LOCKREAD(); _ASSERTE(ptk); // initialize the output parameter *ptk = mdTypeRefNil; // Treat no namespace as empty string. if (!szNamespace) szNamespace = ""; // It is a linear search here. Do we want to instantiate the name hash? cTypeRefRecs = m_pStgdb->m_MiniMd.getCountTypeRefs(); for (ULONG i = 1; i <= cTypeRefRecs; i++) { IfFailGo(m_pStgdb->m_MiniMd.GetTypeRefRecord(i, &pTypeRefRec)); tkRes = m_pStgdb->m_MiniMd.getResolutionScopeOfTypeRef(pTypeRefRec); if (IsNilToken(tkRes)) { if (!IsNilToken(tkResolutionScope)) continue; } else if (tkRes != tkResolutionScope) continue; IfFailGo(m_pStgdb->m_MiniMd.getNamespaceOfTypeRef(pTypeRefRec, &szNamespaceTmp)); if (strcmp(szNamespace, szNamespaceTmp)) continue; IfFailGo(m_pStgdb->m_MiniMd.getNameOfTypeRef(pTypeRefRec, &szNameTmp)); if (!strcmp(szNameTmp, szName)) { *ptk = TokenFromRid(i, mdtTypeRef); goto ErrExit; } } // cannot find the typedef hr = CLDB_E_RECORD_NOTFOUND; ErrExit: return hr; } // MDInternalRW::FindTypeRefByName //***************************************************************************** // return flags for a given class //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetTypeDefProps( mdTypeDef td, // given classdef DWORD *pdwAttr, // return flags on class mdToken *ptkExtends) // [OUT] Put base class TypeDef/TypeRef here. { HRESULT hr = S_OK; TypeDefRec *pTypeDefRec = NULL; LOCKREAD(); IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pTypeDefRec)); if (ptkExtends) { *ptkExtends = m_pStgdb->m_MiniMd.getExtendsOfTypeDef(pTypeDefRec); } if (pdwAttr) { *pdwAttr = m_pStgdb->m_MiniMd.getFlagsOfTypeDef(pTypeDefRec); } ErrExit: return hr; } // MDInternalRW::GetTypeDefProps //***************************************************************************** // return guid pointer to MetaData internal guid pool given a given class //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetItemGuid( // return hresult mdToken tkObj, // given item. CLSID *pGuid) // [OUT] put guid here. { HRESULT hr; // A result. const BYTE *pBlob = NULL; // Blob with dispid. ULONG cbBlob; // Length of blob. WCHAR wzBlob[40]; // Wide char format of guid. int ix; // Loop control. // Get the GUID, if any. hr = GetCustomAttributeByName(tkObj, INTEROP_GUID_TYPE, (const void**)&pBlob, &cbBlob); if (SUCCEEDED(hr) && hr != S_FALSE) { // Should be in format. Total length == 41 // <0x0001><0x24>01234567-0123-0123-0123-001122334455<0x0000> if ((cbBlob != 41) || (GET_UNALIGNED_VAL16(pBlob) != 1)) IfFailGo(E_INVALIDARG); for (ix=1; ix<=36; ++ix) wzBlob[ix] = pBlob[ix+2]; wzBlob[0] = '{'; wzBlob[37] = '}'; wzBlob[38] = 0; hr = IIDFromString(wzBlob, pGuid); } else *pGuid = GUID_NULL; ErrExit: return hr; } // MDInternalRW::GetItemGuid //***************************************************************************** // // get enclosing class of NestedClass //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetNestedClassProps( mdTypeDef tkNestedClass, // [IN] NestedClass token. mdTypeDef *ptkEnclosingClass) // [OUT] EnclosingClass token. { HRESULT hr = NOERROR; RID rid; BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); LOCKREAD(); if (!m_pStgdb->m_MiniMd.IsSorted(TBL_NestedClass) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_NestedClass)) { // NestedClass table is not sorted. CONVERT_READ_TO_WRITE_LOCK(); } // This is a binary search thus we need to grap a read lock. Or this table // might be sorted underneath our feet. _ASSERTE(TypeFromToken(tkNestedClass) == mdtTypeDef && ptkEnclosingClass); IfFailGo(m_pStgdb->m_MiniMd.FindNestedClassFor(RidFromToken(tkNestedClass), &rid)); if (InvalidRid(rid)) { hr = CLDB_E_RECORD_NOTFOUND; } else { NestedClassRec *pRecord; IfFailGo(m_pStgdb->m_MiniMd.GetNestedClassRecord(rid, &pRecord)); *ptkEnclosingClass = m_pStgdb->m_MiniMd.getEnclosingClassOfNestedClass(pRecord); } ErrExit: END_SO_INTOLERANT_CODE; return hr; } // MDInternalRW::GetNestedClassProps //******************************************************************************* // Get count of Nested classes given the enclosing class. //******************************************************************************* __checkReturn HRESULT MDInternalRW::GetCountNestedClasses( // return count of Nested classes. mdTypeDef tkEnclosingClass, // [IN]Enclosing class. ULONG *pcNestedClassesCount) { HRESULT hr; ULONG ulCount; ULONG ulRetCount = 0; NestedClassRec *pRecord; _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef && !IsNilToken(tkEnclosingClass)); *pcNestedClassesCount = 0; ulCount = m_pStgdb->m_MiniMd.getCountNestedClasss(); for (ULONG i = 1; i <= ulCount; i++) { IfFailRet(m_pStgdb->m_MiniMd.GetNestedClassRecord(i, &pRecord)); if (tkEnclosingClass == m_pStgdb->m_MiniMd.getEnclosingClassOfNestedClass(pRecord)) ulRetCount++; } *pcNestedClassesCount = ulRetCount; return S_OK; } // MDInternalRW::GetCountNestedClasses //******************************************************************************* // Return array of Nested classes given the enclosing class. //******************************************************************************* __checkReturn HRESULT MDInternalRW::GetNestedClasses( // Return actual count. mdTypeDef tkEnclosingClass, // [IN] Enclosing class. mdTypeDef *rNestedClasses, // [OUT] Array of nested class tokens. ULONG ulNestedClasses, // [IN] Size of array. ULONG *pcNestedClasses) { HRESULT hr; ULONG ulCount; ULONG ulRetCount = 0; NestedClassRec *pRecord; _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef && !IsNilToken(tkEnclosingClass)); *pcNestedClasses = 0; ulCount = m_pStgdb->m_MiniMd.getCountNestedClasss(); for (ULONG i = 1; i <= ulCount; i++) { IfFailRet(m_pStgdb->m_MiniMd.GetNestedClassRecord(i, &pRecord)); if (tkEnclosingClass == m_pStgdb->m_MiniMd.getEnclosingClassOfNestedClass(pRecord)) { if (ovadd_le(ulRetCount, 1, ulNestedClasses)) // ulRetCount is 0 based. rNestedClasses[ulRetCount] = m_pStgdb->m_MiniMd.getNestedClassOfNestedClass(pRecord); ulRetCount++; } } *pcNestedClasses = ulRetCount; return S_OK; } // MDInternalRW::GetNestedClasses //******************************************************************************* // return the ModuleRef properties //******************************************************************************* __checkReturn HRESULT MDInternalRW::GetModuleRefProps( // return hresult mdModuleRef mur, // [IN] moduleref token LPCSTR *pszName) // [OUT] buffer to fill with the moduleref name { _ASSERTE(TypeFromToken(mur) == mdtModuleRef); _ASSERTE(pszName); HRESULT hr = S_OK; ModuleRefRec *pModuleRefRec = NULL; LOCKREAD(); IfFailGo(m_pStgdb->m_MiniMd.GetModuleRefRecord(RidFromToken(mur), &pModuleRefRec)); IfFailGo(m_pStgdb->m_MiniMd.getNameOfModuleRef(pModuleRefRec, pszName)); ErrExit: return hr; } // MDInternalRW::GetModuleRefProps //***************************************************************************** // Given a scope and a methoddef, return a pointer to methoddef's signature //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetSigOfMethodDef( mdMethodDef methoddef, // given a methoddef ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob PCCOR_SIGNATURE *ppSig) { // Output parameter should not be NULL _ASSERTE(pcbSigBlob); _ASSERTE(TypeFromToken(methoddef) == mdtMethodDef); HRESULT hr; // We don't change MethodDef signature. No need to lock. MethodRec *pMethodRec; *ppSig = NULL; *pcbSigBlob = 0; IfFailRet(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(methoddef), &pMethodRec)); IfFailRet(m_pStgdb->m_MiniMd.getSignatureOfMethod(pMethodRec, ppSig, pcbSigBlob)); return S_OK; } // MDInternalRW::GetSigOfMethodDef //***************************************************************************** // Given a scope and a fielddef, return a pointer to fielddef's signature //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetSigOfFieldDef( mdFieldDef fielddef, // given a methoddef ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob PCCOR_SIGNATURE *ppSig) { _ASSERTE(pcbSigBlob); _ASSERTE(TypeFromToken(fielddef) == mdtFieldDef); HRESULT hr; // We don't change Field's signature. No need to lock. FieldRec *pFieldRec; *ppSig = NULL; *pcbSigBlob = 0; IfFailRet(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(fielddef), &pFieldRec)); IfFailRet(m_pStgdb->m_MiniMd.getSignatureOfField(pFieldRec, ppSig, pcbSigBlob)); return S_OK; } // MDInternalRW::GetSigOfFieldDef //***************************************************************************** // Get signature for the token (FieldDef, MethodDef, Signature, or TypeSpec). //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetSigFromToken( mdToken tk, ULONG * pcbSig, PCCOR_SIGNATURE * ppSig) { HRESULT hr; // We don't change token's signature. Thus no need to lock. *ppSig = NULL; *pcbSig = 0; switch (TypeFromToken(tk)) { case mdtSignature: { StandAloneSigRec *pRec; IfFailGo(m_pStgdb->m_MiniMd.GetStandAloneSigRecord(RidFromToken(tk), &pRec)); IfFailGo(m_pStgdb->m_MiniMd.getSignatureOfStandAloneSig(pRec, ppSig, pcbSig)); return S_OK; } case mdtTypeSpec: { TypeSpecRec *pRec; IfFailGo(m_pStgdb->m_MiniMd.GetTypeSpecRecord(RidFromToken(tk), &pRec)); IfFailGo(m_pStgdb->m_MiniMd.getSignatureOfTypeSpec(pRec, ppSig, pcbSig)); return S_OK; } case mdtMethodDef: { IfFailGo(GetSigOfMethodDef(tk, pcbSig, ppSig)); return S_OK; } case mdtFieldDef: { IfFailGo(GetSigOfFieldDef(tk, pcbSig, ppSig)); return S_OK; } } // not a known token type. #ifdef _DEBUG if(REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 1)) _ASSERTE(!"Unexpected token type"); #endif *pcbSig = 0; hr = META_E_INVALID_TOKEN_TYPE; ErrExit: return hr; } // MDInternalRW::GetSigFromToken //***************************************************************************** // Given methoddef, return the flags //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetMethodDefProps( mdMethodDef md, DWORD *pdwFlags) // return mdPublic, mdAbstract, etc { HRESULT hr = S_OK; MethodRec *pMethodRec = NULL; LOCKREAD(); IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec)); _ASSERTE(hr == S_OK); *pdwFlags = m_pStgdb->m_MiniMd.getFlagsOfMethod(pMethodRec); return S_OK; ErrExit: *pdwFlags = (DWORD)-1; return hr; } // MDInternalRW::GetMethodDefProps //***************************************************************************** // Given a scope and a methoddef, return RVA and impl flags //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetMethodImplProps( mdToken tk, // [IN] MethodDef ULONG *pulCodeRVA, // [OUT] CodeRVA DWORD *pdwImplFlags) // [OUT] Impl. Flags { _ASSERTE(TypeFromToken(tk) == mdtMethodDef); HRESULT hr = S_OK; MethodRec *pMethodRec = NULL; LOCKREAD(); IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tk), &pMethodRec)); if (pulCodeRVA) { *pulCodeRVA = m_pStgdb->m_MiniMd.getRVAOfMethod(pMethodRec); } if (pdwImplFlags) { *pdwImplFlags = m_pStgdb->m_MiniMd.getImplFlagsOfMethod(pMethodRec); } ErrExit: return hr; } // MDInternalRW::GetMethodImplProps //***************************************************************************** // return the field RVA //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetFieldRVA( mdToken fd, // [IN] FieldDef ULONG *pulCodeRVA) // [OUT] CodeRVA { _ASSERTE(TypeFromToken(fd) == mdtFieldDef); _ASSERTE(pulCodeRVA); ULONG iRecord; HRESULT hr = NOERROR; LOCKREAD(); IfFailGo(m_pStgdb->m_MiniMd.FindFieldRVAHelper(fd, &iRecord)); if (InvalidRid(iRecord)) { if (pulCodeRVA) *pulCodeRVA = 0; hr = CLDB_E_RECORD_NOTFOUND; } else { FieldRVARec *pFieldRVARec; IfFailGo(m_pStgdb->m_MiniMd.GetFieldRVARecord(iRecord, &pFieldRVARec)); *pulCodeRVA = m_pStgdb->m_MiniMd.getRVAOfFieldRVA(pFieldRVARec); } ErrExit: return hr; } // MDInternalRW::GetFieldRVA //***************************************************************************** // Given a fielddef, return the flags. Such as fdPublic, fdStatic, etc //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetFieldDefProps( mdFieldDef fd, // given memberdef DWORD *pdwFlags) // [OUT] return fdPublic, fdPrive, etc flags { _ASSERTE(TypeFromToken(fd) == mdtFieldDef); HRESULT hr = S_OK; FieldRec *pFieldRec = NULL; LOCKREAD(); IfFailRet(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(fd), &pFieldRec)); _ASSERTE(hr == S_OK); *pdwFlags = m_pStgdb->m_MiniMd.getFlagsOfField(pFieldRec); return S_OK; ErrExit: *pdwFlags = (DWORD)-1; return hr; } // MDInternalRW::GetFieldDefProps //***************************************************************************** // return default value of a token(could be paramdef, fielddef, or property) //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetDefaultValue( // return hresult mdToken tk, // [IN] given FieldDef, ParamDef, or Property MDDefaultValue *pMDDefaultValue) // [OUT] default value { _ASSERTE(pMDDefaultValue); HRESULT hr; BYTE bType; const VOID *pValue; ULONG cbValue; RID rid; ConstantRec *pConstantRec; LOCKREAD(); IfFailGo(m_pStgdb->m_MiniMd.FindConstantHelper(tk, &rid)); if (InvalidRid(rid)) { pMDDefaultValue->m_bType = ELEMENT_TYPE_VOID; return S_OK; } IfFailGo(m_pStgdb->m_MiniMd.GetConstantRecord(rid, &pConstantRec)); // get the type of constant value bType = m_pStgdb->m_MiniMd.getTypeOfConstant(pConstantRec); // get the value blob IfFailGo(m_pStgdb->m_MiniMd.getValueOfConstant(pConstantRec, reinterpret_cast(&pValue), &cbValue)); // convert it to our internal default value representation hr = _FillMDDefaultValue(bType, pValue, cbValue, pMDDefaultValue); ErrExit: return hr; } // MDInternalRW::GetDefaultValue //***************************************************************************** // Given a scope and a methoddef/fielddef, return the dispid //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetDispIdOfMemberDef( // return hresult mdToken tk, // given methoddef or fielddef ULONG *pDispid) // Put the dispid here. { #ifdef FEATURE_COMINTEROP HRESULT hr; // A result. const BYTE *pBlob; // Blob with dispid. ULONG cbBlob; // Length of blob. // No need to lock this function. All of the function that it is calling is already locked! // Get the DISPID, if any. _ASSERTE(pDispid); *pDispid = DISPID_UNKNOWN; hr = GetCustomAttributeByName(tk, INTEROP_DISPID_TYPE, (const void**)&pBlob, &cbBlob); if (hr != S_FALSE) { // Check that this might be a dispid. if (cbBlob >= (sizeof(*pDispid)+2)) *pDispid = GET_UNALIGNED_VAL32(pBlob+2); else IfFailGo(E_INVALIDARG); } ErrExit: return hr; #else // FEATURE_COMINTEROP _ASSERTE(false); return E_NOTIMPL; #endif // FEATURE_COMINTEROP } // MDInternalRW::GetDispIdOfMemberDef //***************************************************************************** // Given interfaceimpl, return the TypeRef/TypeDef and flags //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetTypeOfInterfaceImpl( // return hresult mdInterfaceImpl iiImpl, // given a interfaceimpl mdToken *ptkType) { HRESULT hr; // no need to lock this function. _ASSERTE(TypeFromToken(iiImpl) == mdtInterfaceImpl); *ptkType = mdTypeDefNil; InterfaceImplRec *pIIRec; IfFailRet(m_pStgdb->m_MiniMd.GetInterfaceImplRecord(RidFromToken(iiImpl), &pIIRec)); *ptkType = m_pStgdb->m_MiniMd.getInterfaceOfInterfaceImpl(pIIRec); return S_OK; } // MDInternalRW::GetTypeOfInterfaceImpl //***************************************************************************** // This routine gets the properties for the given MethodSpec token. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetMethodSpecProps( // S_OK or error. mdMethodSpec mi, // [IN] The method instantiation mdToken *tkParent, // [OUT] MethodDef or MemberRef PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data ULONG *pcbSigBlob) // [OUT] actual size of signature blob { HRESULT hr = NOERROR; MethodSpecRec *pMethodSpecRec; _ASSERTE(TypeFromToken(mi) == mdtMethodSpec); IfFailGo(m_pStgdb->m_MiniMd.GetMethodSpecRecord(RidFromToken(mi), &pMethodSpecRec)); if (tkParent) *tkParent = m_pStgdb->m_MiniMd.getMethodOfMethodSpec(pMethodSpecRec); if (ppvSigBlob || pcbSigBlob) { // caller wants signature information PCCOR_SIGNATURE pvSigTmp; ULONG cbSig; IfFailGo(m_pStgdb->m_MiniMd.getInstantiationOfMethodSpec(pMethodSpecRec, &pvSigTmp, &cbSig)); if ( ppvSigBlob ) *ppvSigBlob = pvSigTmp; if ( pcbSigBlob) *pcbSigBlob = cbSig; } ErrExit: return hr; } // MDInternalRW::GetMethodSpecProps //***************************************************************************** // Given a classname, return the typedef //***************************************************************************** __checkReturn HRESULT MDInternalRW::FindTypeDef( // return hresult LPCSTR szNamespace, // [IN] Namespace for the TypeDef. LPCSTR szName, // [IN] Name of the TypeDef. mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class. mdTypeDef *ptypedef) // [OUT] return typedef { HRESULT hr = S_OK; LOCKREADIFFAILRET(); _ASSERTE(ptypedef); // initialize the output parameter *ptypedef = mdTypeDefNil; return ImportHelper::FindTypeDefByName(&(m_pStgdb->m_MiniMd), szNamespace, szName, tkEnclosingClass, ptypedef); } // MDInternalRW::FindTypeDef //***************************************************************************** // Given a memberref, return a pointer to memberref's name and signature //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetNameAndSigOfMemberRef( // meberref's name mdMemberRef memberref, // given a memberref PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of COM+ signature ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob LPCSTR *pszMemberRefName) { HRESULT hr; // MemberRef's name and sig won't change. Don't need to lock this. _ASSERTE(TypeFromToken(memberref) == mdtMemberRef); MemberRefRec *pMemberRefRec; *pszMemberRefName = NULL; if (ppvSigBlob != NULL) { _ASSERTE(pcbSigBlob != NULL); *ppvSigBlob = NULL; *pcbSigBlob = 0; } IfFailRet(m_pStgdb->m_MiniMd.GetMemberRefRecord(RidFromToken(memberref), &pMemberRefRec)); if (ppvSigBlob != NULL) { IfFailRet(m_pStgdb->m_MiniMd.getSignatureOfMemberRef(pMemberRefRec, ppvSigBlob, pcbSigBlob)); } IfFailRet(m_pStgdb->m_MiniMd.getNameOfMemberRef(pMemberRefRec, pszMemberRefName)); return S_OK; } // MDInternalRW::GetNameAndSigOfMemberRef //***************************************************************************** // Given a memberref, return parent token. It can be a TypeRef, ModuleRef, or a MethodDef //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetParentOfMemberRef( // return parent token mdMemberRef memberref, // given a typedef mdToken *ptkParent) // return the parent token { HRESULT hr = S_OK; MemberRefRec *pMemberRefRec = NULL; LOCKREAD(); // parent for MemberRef can change. See SetParent. _ASSERTE(TypeFromToken(memberref) == mdtMemberRef); IfFailRet(m_pStgdb->m_MiniMd.GetMemberRefRecord(RidFromToken(memberref), &pMemberRefRec)); _ASSERTE(hr == S_OK); *ptkParent = m_pStgdb->m_MiniMd.getClassOfMemberRef(pMemberRefRec); return S_OK; ErrExit: *ptkParent = mdTokenNil; return hr; } // MDInternalRW::GetParentOfMemberRef //***************************************************************************** // return properties of a paramdef //*****************************************************************************/ __checkReturn HRESULT MDInternalRW::GetParamDefProps ( mdParamDef paramdef, // given a paramdef USHORT *pusSequence, // [OUT] slot number for this parameter DWORD *pdwAttr, // [OUT] flags LPCSTR *pszName) // [OUT] return the name of the parameter { HRESULT hr = S_OK; ParamRec *pParamRec = NULL; LOCKREAD(); // parent for MemberRef can change. See SetParamProps. _ASSERTE(TypeFromToken(paramdef) == mdtParamDef); IfFailGo(m_pStgdb->m_MiniMd.GetParamRecord(RidFromToken(paramdef), &pParamRec)); _ASSERTE(hr == S_OK); if (pdwAttr != NULL) { *pdwAttr = m_pStgdb->m_MiniMd.getFlagsOfParam(pParamRec); } if (pusSequence != NULL) { *pusSequence = m_pStgdb->m_MiniMd.getSequenceOfParam(pParamRec); } IfFailGo(m_pStgdb->m_MiniMd.getNameOfParam(pParamRec, pszName)); _ASSERTE(hr == S_OK); return S_OK; ErrExit: *pszName = NULL; return S_OK; } // MDInternalRW::GetParamDefProps //***************************************************************************** // Get property info for the method. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetPropertyInfoForMethodDef( // Result. mdMethodDef md, // [IN] memberdef mdProperty *ppd, // [OUT] put property token here LPCSTR *pName, // [OUT] put pointer to name here ULONG *pSemantic) // [OUT] put semantic here { MethodSemanticsRec *pSemantics; RID ridCur; RID ridMax; USHORT usSemantics; HRESULT hr = S_OK; LOCKREAD(); ridMax = m_pStgdb->m_MiniMd.getCountMethodSemantics(); for (ridCur = 1; ridCur <= ridMax; ridCur++) { IfFailGo(m_pStgdb->m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); if (md == m_pStgdb->m_MiniMd.getMethodOfMethodSemantics(pSemantics)) { // match the method usSemantics = m_pStgdb->m_MiniMd.getSemanticOfMethodSemantics(pSemantics); if (usSemantics == msGetter || usSemantics == msSetter) { // Make sure that it is not an invalid entry if (m_pStgdb->m_MiniMd.getAssociationOfMethodSemantics(pSemantics) != mdPropertyNil) { // found a match. Fill out the output parameters PropertyRec *pProperty; mdProperty prop; prop = m_pStgdb->m_MiniMd.getAssociationOfMethodSemantics(pSemantics); if (ppd) *ppd = prop; IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord(RidFromToken(prop), &pProperty)); if (pName) { IfFailGo(m_pStgdb->m_MiniMd.getNameOfProperty(pProperty, pName)); } if (pSemantic) *pSemantic = usSemantics; goto ErrExit; } } } } hr = S_FALSE; ErrExit: return hr; } // MDInternalRW::GetPropertyInfoForMethodDef //***************************************************************************** // return the pack size of a class //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetClassPackSize( mdTypeDef td, // [IN] give typedef DWORD *pdwPackSize) // [OUT] { HRESULT hr = NOERROR; RID ridClassLayout = 0; LOCKREAD(); _ASSERTE(TypeFromToken(td) == mdtTypeDef && pdwPackSize); ClassLayoutRec *pRec; IfFailGo(m_pStgdb->m_MiniMd.FindClassLayoutHelper(td, &ridClassLayout)); if (InvalidRid(ridClassLayout)) { hr = CLDB_E_RECORD_NOTFOUND; goto ErrExit; } IfFailGo(m_pStgdb->m_MiniMd.GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRec)); *pdwPackSize = m_pStgdb->m_MiniMd.getPackingSizeOfClassLayout(pRec); ErrExit: return hr; } // MDInternalRW::GetClassPackSize //***************************************************************************** // return the total size of a value class //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetClassTotalSize( // return error if a class does not have total size info mdTypeDef td, // [IN] give typedef ULONG *pulClassSize) // [OUT] return the total size of the class { CONTRACT_VIOLATION(ThrowsViolation); _ASSERTE(TypeFromToken(td) == mdtTypeDef && pulClassSize); ClassLayoutRec *pRec; HRESULT hr = NOERROR; RID ridClassLayout; LOCKREAD(); IfFailGo(m_pStgdb->m_MiniMd.FindClassLayoutHelper(td, &ridClassLayout)); if (InvalidRid(ridClassLayout)) { hr = CLDB_E_RECORD_NOTFOUND; goto ErrExit; } IfFailGo(m_pStgdb->m_MiniMd.GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRec)); *pulClassSize = m_pStgdb->m_MiniMd.getClassSizeOfClassLayout(pRec); ErrExit: return hr; } // MDInternalRW::GetClassTotalSize //***************************************************************************** // init the layout enumerator of a class //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetClassLayoutInit( mdTypeDef td, // [IN] give typedef MD_CLASS_LAYOUT *pmdLayout) // [OUT] set up the status of query here { HRESULT hr = NOERROR; LOCKREAD(); _ASSERTE(TypeFromToken(td) == mdtTypeDef); // Do we need to lock this function? Can clints add more Fields on a TypeDef? // initialize the output parameter _ASSERTE(pmdLayout); memset(pmdLayout, 0, sizeof(MD_CLASS_LAYOUT)); TypeDefRec *pTypeDefRec; // record for this typedef in TypeDef Table IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pTypeDefRec)); // find the starting and end field for this typedef pmdLayout->m_ridFieldCur = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pTypeDefRec); IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(td), &(pmdLayout->m_ridFieldEnd))); ErrExit: return hr; } // MDInternalRW::GetClassLayoutInit //***************************************************************************** // Get the field offset for a given field token //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetFieldOffset( mdFieldDef fd, // [IN] fielddef ULONG *pulOffset) // [OUT] FieldOffset { HRESULT hr = S_OK; FieldLayoutRec *pRec; _ASSERTE(pulOffset); RID iLayout; LOCKREAD(); IfFailGo(m_pStgdb->m_MiniMd.FindFieldLayoutHelper(fd, &iLayout)); if (InvalidRid(iLayout)) { hr = S_FALSE; goto ErrExit; } IfFailGo(m_pStgdb->m_MiniMd.GetFieldLayoutRecord(iLayout, &pRec)); *pulOffset = m_pStgdb->m_MiniMd.getOffSetOfFieldLayout(pRec); _ASSERTE(*pulOffset != ULONG_MAX); ErrExit: return hr; } // MDInternalRW::GetFieldOffset //***************************************************************************** // enum the next the field layout //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetClassLayoutNext( MD_CLASS_LAYOUT *pLayout, // [IN|OUT] set up the status of query here mdFieldDef *pfd, // [OUT] field def ULONG *pulOffset) // [OUT] field offset or sequence { HRESULT hr = S_OK; _ASSERTE(pfd && pulOffset && pLayout); RID iLayout2; FieldLayoutRec *pRec; LOCKREAD(); while (pLayout->m_ridFieldCur < pLayout->m_ridFieldEnd) { RID fieldRid; IfFailGo(m_pStgdb->m_MiniMd.GetFieldRid(pLayout->m_ridFieldCur, &fieldRid)); mdFieldDef fd = TokenFromRid(fieldRid, mdtFieldDef); IfFailGo(m_pStgdb->m_MiniMd.FindFieldLayoutHelper(fd, &iLayout2)); pLayout->m_ridFieldCur++; if (!InvalidRid(iLayout2)) { IfFailGo(m_pStgdb->m_MiniMd.GetFieldLayoutRecord(iLayout2, &pRec)); *pulOffset = m_pStgdb->m_MiniMd.getOffSetOfFieldLayout(pRec); _ASSERTE(*pulOffset != ULONG_MAX); *pfd = fd; goto ErrExit; } } *pfd = mdFieldDefNil; hr = S_FALSE; // fall through ErrExit: return hr; } // MDInternalRW::GetClassLayoutNext //***************************************************************************** // return the field's native type signature //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetFieldMarshal( // return error if no native type associate with the token mdToken tk, // [IN] given fielddef or paramdef PCCOR_SIGNATURE *pSigNativeType, // [OUT] the native type signature ULONG *pcbNativeType) // [OUT] the count of bytes of *ppvNativeType { // output parameters have to be supplied _ASSERTE(pcbNativeType); RID rid; FieldMarshalRec *pFieldMarshalRec; HRESULT hr = NOERROR; LOCKREAD(); // find the row containing the marshal definition for tk IfFailGo(m_pStgdb->m_MiniMd.FindFieldMarshalHelper(tk, &rid)); if (InvalidRid(rid)) { hr = CLDB_E_RECORD_NOTFOUND; goto ErrExit; } IfFailGo(m_pStgdb->m_MiniMd.GetFieldMarshalRecord(rid, &pFieldMarshalRec)); // get the native type IfFailGo(m_pStgdb->m_MiniMd.getNativeTypeOfFieldMarshal(pFieldMarshalRec, pSigNativeType, pcbNativeType)); ErrExit: return hr; } // MDInternalRW::GetFieldMarshal //***************************************** // property APIs //***************************************** //***************************************************************************** // Find property by name //***************************************************************************** __checkReturn HRESULT MDInternalRW::FindProperty( mdTypeDef td, // [IN] given a typdef LPCSTR szPropName, // [IN] property name mdProperty *pProp) // [OUT] return property token { HRESULT hr = NOERROR; LOCKREAD(); // output parameters have to be supplied _ASSERTE(TypeFromToken(td) == mdtTypeDef && pProp); PropertyMapRec *pRec; PropertyRec *pProperty; RID ridPropertyMap; RID ridCur; RID ridEnd; LPCUTF8 szName; IfFailGo(m_pStgdb->m_MiniMd.FindPropertyMapFor(RidFromToken(td), &ridPropertyMap)); if (InvalidRid(ridPropertyMap)) { // not found! hr = CLDB_E_RECORD_NOTFOUND; goto ErrExit; } IfFailGo(m_pStgdb->m_MiniMd.GetPropertyMapRecord(ridPropertyMap, &pRec)); // get the starting/ending rid of properties of this typedef ridCur = m_pStgdb->m_MiniMd.getPropertyListOfPropertyMap(pRec); IfFailGo(m_pStgdb->m_MiniMd.getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd)); for ( ; ridCur < ridEnd; ridCur ++ ) { RID propertyRid; IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRid(ridCur, &propertyRid)); IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord(propertyRid, &pProperty)); IfFailGo(m_pStgdb->m_MiniMd.getNameOfProperty(pProperty, &szName)); if ( strcmp(szName, szPropName) ==0 ) { // Found the match. Set the output parameter and we are done. *pProp = TokenFromRid(propertyRid, mdtProperty); goto ErrExit; } } // not found hr = CLDB_E_RECORD_NOTFOUND; ErrExit: return hr; } // MDInternalRW::FindProperty //***************************************************************************** // return the properties of a property //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetPropertyProps( mdProperty prop, // [IN] property token LPCSTR *pszProperty, // [OUT] property name DWORD *pdwPropFlags, // [OUT] property flags. PCCOR_SIGNATURE *ppvSig, // [OUT] property type. pointing to meta data internal blob ULONG *pcbSig) // [OUT] count of bytes in *ppvSig { HRESULT hr = S_OK; LOCKREAD(); // output parameters have to be supplied _ASSERTE(TypeFromToken(prop) == mdtProperty); PropertyRec *pProperty; ULONG cbSig; IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord(RidFromToken(prop), &pProperty)); // get name of the property if (pszProperty) { IfFailGo(m_pStgdb->m_MiniMd.getNameOfProperty(pProperty, pszProperty)); } // get the flags of property if (pdwPropFlags) *pdwPropFlags = m_pStgdb->m_MiniMd.getPropFlagsOfProperty(pProperty); // get the type of the property if (ppvSig) { IfFailGo(m_pStgdb->m_MiniMd.getTypeOfProperty(pProperty, ppvSig, &cbSig)); if (pcbSig) { *pcbSig = cbSig; } } ErrExit: return hr; } // MDInternalRW::GetPropertyProps //********************************** // // Event APIs // //********************************** //***************************************************************************** // return an event by given the name //***************************************************************************** __checkReturn HRESULT MDInternalRW::FindEvent( mdTypeDef td, // [IN] given a typdef LPCSTR szEventName, // [IN] event name mdEvent *pEvent) // [OUT] return event token { HRESULT hr = NOERROR; LOCKREAD(); // output parameters have to be supplied _ASSERTE(TypeFromToken(td) == mdtTypeDef && pEvent); EventMapRec *pRec; EventRec *pEventRec; RID ridEventMap; RID ridCur; RID ridEnd; LPCUTF8 szName; IfFailGo(m_pStgdb->m_MiniMd.FindEventMapFor(RidFromToken(td), &ridEventMap)); if (InvalidRid(ridEventMap)) { // not found! hr = CLDB_E_RECORD_NOTFOUND; goto ErrExit; } IfFailGo(m_pStgdb->m_MiniMd.GetEventMapRecord(ridEventMap, &pRec)); // get the starting/ending rid of properties of this typedef ridCur = m_pStgdb->m_MiniMd.getEventListOfEventMap(pRec); IfFailGo(m_pStgdb->m_MiniMd.getEndEventListOfEventMap(ridEventMap, &ridEnd)); for (; ridCur < ridEnd; ridCur ++) { RID eventRid; IfFailGo(m_pStgdb->m_MiniMd.GetEventRid(ridCur, &eventRid)); IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(eventRid, &pEventRec)); IfFailGo(m_pStgdb->m_MiniMd.getNameOfEvent(pEventRec, &szName)); if ( strcmp(szName, szEventName) ==0 ) { // Found the match. Set the output parameter and we are done. *pEvent = TokenFromRid(eventRid, mdtEvent); goto ErrExit; } } // not found hr = CLDB_E_RECORD_NOTFOUND; ErrExit: return hr; } // MDInternalRW::FindEvent //***************************************************************************** // return the properties of an event //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetEventProps( // S_OK, S_FALSE, or error. mdEvent ev, // [IN] event token LPCSTR *pszEvent, // [OUT] Event name DWORD *pdwEventFlags, // [OUT] Event flags. mdToken *ptkEventType) // [OUT] EventType class { HRESULT hr = S_OK; LOCKREAD(); EventRec *pEvent; // output parameters have to be supplied _ASSERTE(TypeFromToken(ev) == mdtEvent); IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(RidFromToken(ev), &pEvent)); if (pszEvent != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getNameOfEvent(pEvent, pszEvent)); } if (pdwEventFlags) *pdwEventFlags = m_pStgdb->m_MiniMd.getEventFlagsOfEvent(pEvent); if (ptkEventType) *ptkEventType = m_pStgdb->m_MiniMd.getEventTypeOfEvent(pEvent); ErrExit: return hr; } // MDInternalRW::GetEventProps //***************************************************************************** // return the properties of a generic param //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetGenericParamProps( // S_OK or error. mdGenericParam rd, // [IN] The type parameter ULONG* pulSequence, // [OUT] Parameter sequence number DWORD* pdwAttr, // [OUT] Type parameter flags (for future use) mdToken *ptOwner, // [OUT] The owner (TypeDef or MethodDef) DWORD *reserved, // [OUT] The kind (TypeDef/Ref/Spec, for future use) LPCSTR *szName) // [OUT] The name { HRESULT hr = NOERROR; GenericParamRec *pGenericParamRec = NULL; // See if this version of the metadata can do Generics if (!m_pStgdb->m_MiniMd.SupportsGenerics()) IfFailGo(CLDB_E_INCOMPATIBLE); _ASSERTE(TypeFromToken(rd) == mdtGenericParam); if (TypeFromToken(rd) != mdtGenericParam) IfFailGo(CLDB_E_FILE_CORRUPT); IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamRecord(RidFromToken(rd), &pGenericParamRec)); if (pulSequence) *pulSequence = m_pStgdb->m_MiniMd.getNumberOfGenericParam(pGenericParamRec); if (pdwAttr) *pdwAttr = m_pStgdb->m_MiniMd.getFlagsOfGenericParam(pGenericParamRec); if (ptOwner) *ptOwner = m_pStgdb->m_MiniMd.getOwnerOfGenericParam(pGenericParamRec); if (szName != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getNameOfGenericParam(pGenericParamRec, szName)); } ErrExit: return hr; } // MDInternalRW::GetGenericParamProps //***************************************************************************** // This routine gets the properties for the given GenericParamConstraint token. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetGenericParamConstraintProps( // S_OK or error. mdGenericParamConstraint rd, // [IN] The constraint token mdGenericParam *ptGenericParam, // [OUT] GenericParam that is constrained mdToken *ptkConstraintType) // [OUT] TypeDef/Ref/Spec constraint { HRESULT hr = NOERROR; GenericParamConstraintRec *pGPCRec; RID ridRD = RidFromToken(rd); // See if this version of the metadata can do Generics if (!m_pStgdb->m_MiniMd.SupportsGenerics()) IfFailGo(CLDB_E_INCOMPATIBLE); if((TypeFromToken(rd) == mdtGenericParamConstraint) && (ridRD != 0)) { IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamConstraintRecord(ridRD, &pGPCRec)); if (ptGenericParam) *ptGenericParam = TokenFromRid(m_pStgdb->m_MiniMd.getOwnerOfGenericParamConstraint(pGPCRec),mdtGenericParam); if (ptkConstraintType) *ptkConstraintType = m_pStgdb->m_MiniMd.getConstraintOfGenericParamConstraint(pGPCRec); } else hr = META_E_BAD_INPUT_PARAMETER; ErrExit: return hr; } // MDInternalRW::GetGenericParamConstraintProps //***************************************************************************** // Find methoddef of a particular associate with a property or an event //***************************************************************************** __checkReturn HRESULT MDInternalRW::FindAssociate( mdToken evprop, // [IN] given a property or event token DWORD dwSemantics, // [IN] given a associate semantics(setter, getter, testdefault, reset) mdMethodDef *pmd) // [OUT] return method def token { HRESULT hr = NOERROR; RID rid; MethodSemanticsRec *pMethodSemantics; // output parameters have to be supplied _ASSERTE(pmd); _ASSERTE(TypeFromToken(evprop) == mdtEvent || TypeFromToken(evprop) == mdtProperty); LOCKREAD(); hr = m_pStgdb->m_MiniMd.FindAssociateHelper(evprop, dwSemantics, &rid); if (SUCCEEDED(hr)) { IfFailGo(m_pStgdb->m_MiniMd.GetMethodSemanticsRecord(rid, &pMethodSemantics)); *pmd = m_pStgdb->m_MiniMd.getMethodOfMethodSemantics(pMethodSemantics); } ErrExit: return hr; } // MDInternalRW::FindAssociate //***************************************************************************** // get counts of methodsemantics associated with a particular property/event //***************************************************************************** __checkReturn HRESULT MDInternalRW::EnumAssociateInit( mdToken evprop, // [IN] given a property or an event token HENUMInternal *phEnum) // [OUT] cursor to hold the query result { HRESULT hr; LOCKREAD(); // output parameters have to be supplied _ASSERTE(phEnum); _ASSERTE(TypeFromToken(evprop) == mdtEvent || TypeFromToken(evprop) == mdtProperty); hr = m_pStgdb->m_MiniMd.FindMethodSemanticsHelper(evprop, phEnum); ErrExit: return hr; } // MDInternalRW::EnumAssociateInit //***************************************************************************** // get all methodsemantics associated with a particular property/event //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetAllAssociates( HENUMInternal *phEnum, // [OUT] cursor to hold the query result ASSOCIATE_RECORD *pAssociateRec, // [OUT] struct to fill for output ULONG cAssociateRec) // [IN] size of the buffer { HRESULT hr = S_OK; MethodSemanticsRec *pSemantics; RID ridCur; int index = 0; LOCKREAD(); // @FUTURE: rewrite the EnumAssociateInit and GetAllAssociates. Because we might add more properties and events. // Then we might resort MethodSemantics table. So this can be totally out of sync. _ASSERTE(phEnum && pAssociateRec); _ASSERTE(cAssociateRec == phEnum->m_ulCount); // Convert from row pointers to RIDs. while (HENUMInternal::EnumNext(phEnum, (mdToken *)&ridCur)) { IfFailGo(m_pStgdb->m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); pAssociateRec[index].m_memberdef = m_pStgdb->m_MiniMd.getMethodOfMethodSemantics(pSemantics); pAssociateRec[index].m_dwSemantics = m_pStgdb->m_MiniMd.getSemanticOfMethodSemantics(pSemantics); index++; } ErrExit: return hr; } // MDInternalRW::GetAllAssociates //***************************************************************************** // Get the Action and Permissions blob for a given PermissionSet. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetPermissionSetProps( mdPermission pm, // [IN] the permission token. DWORD *pdwAction, // [OUT] CorDeclSecurity. void const **ppvPermission, // [OUT] permission blob. ULONG *pcbPermission) // [OUT] count of bytes of pvPermission. { HRESULT hr = S_OK; _ASSERTE(TypeFromToken(pm) == mdtPermission); _ASSERTE(pdwAction && ppvPermission && pcbPermission); DeclSecurityRec *pPerm; LOCKREAD(); IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(pm), &pPerm)); *pdwAction = m_pStgdb->m_MiniMd.getActionOfDeclSecurity(pPerm); IfFailGo(m_pStgdb->m_MiniMd.getPermissionSetOfDeclSecurity(pPerm, reinterpret_cast(ppvPermission), pcbPermission)); ErrExit: return hr; } // MDInternalRW::GetPermissionSetProps //***************************************************************************** // Get the String given the String token. // Return a pointer to the string, or NULL in case of error. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetUserString( // Offset into the string blob heap. mdString stk, // [IN] the string token. ULONG *pcchStringSize, // [OUT] count of characters in the string. BOOL *pfIs80Plus, // [OUT] specifies where there are extended characters >= 0x80. LPCWSTR *pwszUserString) { HRESULT hr; LPWSTR wszTmp; // no need to lock this function. if (pfIs80Plus != NULL) { *pfIs80Plus = FALSE; } *pwszUserString = NULL; *pcchStringSize = 0; _ASSERTE(pcchStringSize != NULL); MetaData::DataBlob userString; IfFailRet(m_pStgdb->m_MiniMd.GetUserString(RidFromToken(stk), &userString)); wszTmp = reinterpret_cast(userString.GetDataPointer()); *pcchStringSize = userString.GetSize() / sizeof(WCHAR); if (userString.IsEmpty()) { *pwszUserString = NULL; return S_OK; } if (pfIs80Plus != NULL) { if (userString.GetSize() % sizeof(WCHAR) == 0) { *pfIs80Plus = TRUE; // no indicator, presume the worst } // Return the user string terminator (contains value fIs80Plus) *pfIs80Plus = *(reinterpret_cast(wszTmp + *pcchStringSize)); } *pwszUserString = wszTmp; return S_OK; } // MDInternalRW::GetUserString //***************************************************************************** // Get the properties for the given Assembly token. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetAssemblyProps( mdAssembly mda, // [IN] The Assembly for which to get the properties. const void **ppbPublicKey, // [OUT] Pointer to the public key. ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key. ULONG *pulHashAlgId, // [OUT] Hash Algorithm. LPCSTR *pszName, // [OUT] Buffer to fill with name. AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData. DWORD *pdwAssemblyFlags) // [OUT] Flags. { AssemblyRec *pRecord; HRESULT hr = S_OK; LOCKREAD(); _ASSERTE(TypeFromToken(mda) == mdtAssembly && RidFromToken(mda)); IfFailGo(m_pStgdb->m_MiniMd.GetAssemblyRecord(RidFromToken(mda), &pRecord)); if (ppbPublicKey != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getPublicKeyOfAssembly(pRecord, reinterpret_cast(ppbPublicKey), pcbPublicKey)); } if (pulHashAlgId) *pulHashAlgId = m_pStgdb->m_MiniMd.getHashAlgIdOfAssembly(pRecord); if (pszName != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getNameOfAssembly(pRecord, pszName)); } if (pMetaData) { pMetaData->usMajorVersion = m_pStgdb->m_MiniMd.getMajorVersionOfAssembly(pRecord); pMetaData->usMinorVersion = m_pStgdb->m_MiniMd.getMinorVersionOfAssembly(pRecord); pMetaData->usBuildNumber = m_pStgdb->m_MiniMd.getBuildNumberOfAssembly(pRecord); pMetaData->usRevisionNumber = m_pStgdb->m_MiniMd.getRevisionNumberOfAssembly(pRecord); IfFailGo(m_pStgdb->m_MiniMd.getLocaleOfAssembly(pRecord, &pMetaData->szLocale)); pMetaData->ulProcessor = 0; pMetaData->ulOS = 0; } if (pdwAssemblyFlags) { *pdwAssemblyFlags = m_pStgdb->m_MiniMd.getFlagsOfAssembly(pRecord); // Turn on the afPublicKey if PublicKey blob is not empty DWORD cbPublicKey; const BYTE *pbPublicKey; IfFailGo(m_pStgdb->m_MiniMd.getPublicKeyOfAssembly(pRecord, &pbPublicKey, &cbPublicKey)); if (cbPublicKey) *pdwAssemblyFlags |= afPublicKey; } ErrExit: return hr; } // MDInternalRW::GetAssemblyProps //***************************************************************************** // Get the properties for the given AssemblyRef token. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetAssemblyRefProps( mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties. const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token. ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. LPCSTR *pszName, // [OUT] Buffer to fill with name. AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData. const void **ppbHashValue, // [OUT] Hash blob. ULONG *pcbHashValue, // [OUT] Count of bytes in the hash blob. DWORD *pdwAssemblyRefFlags) // [OUT] Flags. { AssemblyRefRec *pRecord; HRESULT hr = S_OK; LOCKREAD(); _ASSERTE(TypeFromToken(mdar) == mdtAssemblyRef && RidFromToken(mdar)); IfFailGo(m_pStgdb->m_MiniMd.GetAssemblyRefRecord(RidFromToken(mdar), &pRecord)); if (ppbPublicKeyOrToken != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getPublicKeyOrTokenOfAssemblyRef(pRecord, reinterpret_cast(ppbPublicKeyOrToken), pcbPublicKeyOrToken)); } if (pszName != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getNameOfAssemblyRef(pRecord, pszName)); } if (pMetaData) { pMetaData->usMajorVersion = m_pStgdb->m_MiniMd.getMajorVersionOfAssemblyRef(pRecord); pMetaData->usMinorVersion = m_pStgdb->m_MiniMd.getMinorVersionOfAssemblyRef(pRecord); pMetaData->usBuildNumber = m_pStgdb->m_MiniMd.getBuildNumberOfAssemblyRef(pRecord); pMetaData->usRevisionNumber = m_pStgdb->m_MiniMd.getRevisionNumberOfAssemblyRef(pRecord); IfFailGo(m_pStgdb->m_MiniMd.getLocaleOfAssemblyRef(pRecord, &pMetaData->szLocale)); pMetaData->ulProcessor = 0; pMetaData->ulOS = 0; } if (ppbHashValue != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getHashValueOfAssemblyRef(pRecord, reinterpret_cast(ppbHashValue), pcbHashValue)); } if (pdwAssemblyRefFlags) *pdwAssemblyRefFlags = m_pStgdb->m_MiniMd.getFlagsOfAssemblyRef(pRecord); ErrExit: return hr; } // MDInternalRW::GetAssemblyRefProps //***************************************************************************** // Get the properties for the given File token. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetFileProps( mdFile mdf, // [IN] The File for which to get the properties. LPCSTR *pszName, // [OUT] Buffer to fill with name. const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob. ULONG *pcbHashValue, // [OUT] Count of bytes in the Hash Value Blob. DWORD *pdwFileFlags) // [OUT] Flags. { FileRec *pRecord; HRESULT hr = S_OK; LOCKREAD(); _ASSERTE(TypeFromToken(mdf) == mdtFile && RidFromToken(mdf)); IfFailGo(m_pStgdb->m_MiniMd.GetFileRecord(RidFromToken(mdf), &pRecord)); if (pszName != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getNameOfFile(pRecord, pszName)); } if (ppbHashValue != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getHashValueOfFile(pRecord, reinterpret_cast(ppbHashValue), pcbHashValue)); } if (pdwFileFlags) *pdwFileFlags = m_pStgdb->m_MiniMd.getFlagsOfFile(pRecord); ErrExit: return hr; } // MDInternalRW::GetFileProps //***************************************************************************** // Get the properties for the given ExportedType token. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetExportedTypeProps( mdExportedType mdct, // [IN] The ExportedType for which to get the properties. LPCSTR *pszNamespace, // [OUT] Buffer to fill with name. LPCSTR *pszName, // [OUT] Buffer to fill with name. mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType. mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file. DWORD *pdwExportedTypeFlags) // [OUT] Flags. { ExportedTypeRec *pRecord; HRESULT hr = S_OK; LOCKREAD(); _ASSERTE(TypeFromToken(mdct) == mdtExportedType && RidFromToken(mdct)); IfFailGo(m_pStgdb->m_MiniMd.GetExportedTypeRecord(RidFromToken(mdct), &pRecord)); if (pszNamespace != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getTypeNamespaceOfExportedType(pRecord, pszNamespace)); } if (pszName != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getTypeNameOfExportedType(pRecord, pszName)); } if (ptkImplementation) *ptkImplementation = m_pStgdb->m_MiniMd.getImplementationOfExportedType(pRecord); if (ptkTypeDef) *ptkTypeDef = m_pStgdb->m_MiniMd.getTypeDefIdOfExportedType(pRecord); if (pdwExportedTypeFlags) *pdwExportedTypeFlags = m_pStgdb->m_MiniMd.getFlagsOfExportedType(pRecord); ErrExit: return hr; } // MDInternalRW::GetExportedTypeProps //***************************************************************************** // Get the properties for the given Resource token. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetManifestResourceProps( mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties. LPCSTR *pszName, // [OUT] Buffer to fill with name. mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType. DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file. DWORD *pdwResourceFlags) // [OUT] Flags. { ManifestResourceRec *pRecord; HRESULT hr = S_OK; LOCKREAD(); _ASSERTE(TypeFromToken(mdmr) == mdtManifestResource && RidFromToken(mdmr)); IfFailGo(m_pStgdb->m_MiniMd.GetManifestResourceRecord(RidFromToken(mdmr), &pRecord)); if (pszName != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getNameOfManifestResource(pRecord, pszName)); } if (ptkImplementation) *ptkImplementation = m_pStgdb->m_MiniMd.getImplementationOfManifestResource(pRecord); if (pdwOffset) *pdwOffset = m_pStgdb->m_MiniMd.getOffsetOfManifestResource(pRecord); if (pdwResourceFlags) *pdwResourceFlags = m_pStgdb->m_MiniMd.getFlagsOfManifestResource(pRecord); ErrExit: return hr; } // MDInternalRW::GetManifestResourceProps //***************************************************************************** // Find the ExportedType given the name. //***************************************************************************** __checkReturn STDMETHODIMP MDInternalRW::FindExportedTypeByName( // S_OK or error LPCSTR szNamespace, // [IN] Namespace of the ExportedType. LPCSTR szName, // [IN] Name of the ExportedType. mdExportedType tkEnclosingType, // [IN] Enclosing ExportedType. mdExportedType *pmct) // [OUT] Put ExportedType token here. { _ASSERTE(szName && pmct); HRESULT hr = S_OK; LOCKREADIFFAILRET(); IMetaModelCommon *pCommon = static_cast(&m_pStgdb->m_MiniMd); return pCommon->CommonFindExportedType(szNamespace, szName, tkEnclosingType, pmct); } // MDInternalRW::FindExportedTypeByName //***************************************************************************** // Find the ManifestResource given the name. //***************************************************************************** __checkReturn STDMETHODIMP MDInternalRW::FindManifestResourceByName(// S_OK or error LPCSTR szName, // [IN] Name of the resource. mdManifestResource *pmmr) // [OUT] Put ManifestResource token here. { _ASSERTE(szName && pmmr); ManifestResourceRec *pRecord; ULONG cRecords; // Count of records. LPCUTF8 szNameTmp = 0; // Name obtained from the database. ULONG i; HRESULT hr = S_OK; LOCKREAD(); cRecords = m_pStgdb->m_MiniMd.getCountManifestResources(); // Search for the ExportedType. for (i = 1; i <= cRecords; i++) { IfFailGo(m_pStgdb->m_MiniMd.GetManifestResourceRecord(i, &pRecord)); IfFailGo(m_pStgdb->m_MiniMd.getNameOfManifestResource(pRecord, &szNameTmp)); if (! strcmp(szName, szNameTmp)) { *pmmr = TokenFromRid(i, mdtManifestResource); goto ErrExit; } } hr = CLDB_E_RECORD_NOTFOUND; ErrExit: return hr; } // MDInternalRW::FindManifestResourceByName //***************************************************************************** // Get the Assembly token from the given scope. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetAssemblyFromScope( // S_OK or error mdAssembly *ptkAssembly) // [OUT] Put token here. { _ASSERTE(ptkAssembly); if (m_pStgdb->m_MiniMd.getCountAssemblys()) { *ptkAssembly = TokenFromRid(1, mdtAssembly); return S_OK; } else return CLDB_E_RECORD_NOTFOUND; } // MDInternalRW::GetAssemblyFromScope //******************************************************************************* // return properties regarding a TypeSpec //******************************************************************************* //******************************************************************************* // return properties regarding a TypeSpec //******************************************************************************* __checkReturn HRESULT MDInternalRW::GetTypeSpecFromToken( // S_OK or error. mdTypeSpec typespec, // [IN] Signature token. PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to token. ULONG *pcbSig) // [OUT] return size of signature. { HRESULT hr = NOERROR; _ASSERTE(TypeFromToken(typespec) == mdtTypeSpec); _ASSERTE(ppvSig && pcbSig); if (!IsValidToken(typespec)) return E_INVALIDARG; TypeSpecRec *pRec; IfFailRet(m_pStgdb->m_MiniMd.GetTypeSpecRecord(RidFromToken(typespec), &pRec)); if (pRec == NULL) return CLDB_E_FILE_CORRUPT; IfFailRet(m_pStgdb->m_MiniMd.getSignatureOfTypeSpec(pRec, ppvSig, pcbSig)); return hr; } // MDInternalRW::GetTypeSpecFromToken //***************************************************************************** // Return contents of Pinvoke given the forwarded member token. //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetPinvokeMap( mdToken tk, // [IN] FieldDef, MethodDef or MethodImpl. DWORD *pdwMappingFlags, // [OUT] Flags used for mapping. LPCSTR *pszImportName, // [OUT] Import name. mdModuleRef *pmrImportDLL) // [OUT] ModuleRef token for the target DLL. { ImplMapRec *pRecord; ULONG iRecord; HRESULT hr = S_OK; LOCKREAD(); IfFailGo(m_pStgdb->m_MiniMd.FindImplMapHelper(tk, &iRecord)); if (InvalidRid(iRecord)) { hr = CLDB_E_RECORD_NOTFOUND; goto ErrExit; } else IfFailGo(m_pStgdb->m_MiniMd.GetImplMapRecord(iRecord, &pRecord)); if (pdwMappingFlags) *pdwMappingFlags = m_pStgdb->m_MiniMd.getMappingFlagsOfImplMap(pRecord); if (pszImportName != NULL) { IfFailGo(m_pStgdb->m_MiniMd.getImportNameOfImplMap(pRecord, pszImportName)); } if (pmrImportDLL) *pmrImportDLL = m_pStgdb->m_MiniMd.getImportScopeOfImplMap(pRecord); ErrExit: return hr; } // MDInternalRW::GetPinvokeMap //***************************************************************************** // convert a text signature to com format //***************************************************************************** __checkReturn HRESULT MDInternalRW::ConvertTextSigToComSig(// Return hresult. BOOL fCreateTrIfNotFound, // create typeref if not found or not LPCSTR pSignature, // class file format signature CQuickBytes *pqbNewSig, // [OUT] place holder for COM+ signature ULONG *pcbCount) // [OUT] the result size of signature { return E_NOTIMPL; } // _ConvertTextSigToComSig //***************************************************************************** // This is a way for the EE to associate some data with this RW metadata to // be released when this RW goes away. This is useful when a RO metadata is // converted to RW, because arbitrary threads can be executing in the RO. // So, we hold onto the RO here, and when the module shuts down, we release it. //***************************************************************************** __checkReturn HRESULT MDInternalRW::SetUserContextData(// S_OK or E_NOTIMPL IUnknown *pIUnk) // The user context. { // Only one chance to do this. if (m_pUserUnk) return E_UNEXPECTED; m_pUserUnk = pIUnk; return S_OK; } // MDInternalRW::SetUserContextData //***************************************************************************** // determine if a token is valid or not //***************************************************************************** BOOL MDInternalRW::IsValidToken( // True or False. mdToken tk) // [IN] Given token. { RID rid = RidFromToken(tk); // no need to lock on this function. if (rid == 0) { return FALSE; } switch (TypeFromToken(tk)) { case mdtModule: // can have only one module record return (rid <= m_pStgdb->m_MiniMd.getCountModules()); case mdtTypeRef: return (rid <= m_pStgdb->m_MiniMd.getCountTypeRefs()); case mdtTypeDef: return (rid <= m_pStgdb->m_MiniMd.getCountTypeDefs()); case mdtFieldDef: return (rid <= m_pStgdb->m_MiniMd.getCountFields()); case mdtMethodDef: return (rid <= m_pStgdb->m_MiniMd.getCountMethods()); case mdtParamDef: return (rid <= m_pStgdb->m_MiniMd.getCountParams()); case mdtInterfaceImpl: return (rid <= m_pStgdb->m_MiniMd.getCountInterfaceImpls()); case mdtMemberRef: return (rid <= m_pStgdb->m_MiniMd.getCountMemberRefs()); case mdtCustomAttribute: return (rid <= m_pStgdb->m_MiniMd.getCountCustomAttributes()); case mdtPermission: return (rid <= m_pStgdb->m_MiniMd.getCountDeclSecuritys()); case mdtSignature: return (rid <= m_pStgdb->m_MiniMd.getCountStandAloneSigs()); case mdtEvent: return (rid <= m_pStgdb->m_MiniMd.getCountEvents()); case mdtProperty: return (rid <= m_pStgdb->m_MiniMd.getCountPropertys()); case mdtModuleRef: return (rid <= m_pStgdb->m_MiniMd.getCountModuleRefs()); case mdtTypeSpec: return (rid <= m_pStgdb->m_MiniMd.getCountTypeSpecs()); case mdtAssembly: return (rid <= m_pStgdb->m_MiniMd.getCountAssemblys()); case mdtAssemblyRef: return (rid <= m_pStgdb->m_MiniMd.getCountAssemblyRefs()); case mdtFile: return (rid <= m_pStgdb->m_MiniMd.getCountFiles()); case mdtExportedType: return (rid <= m_pStgdb->m_MiniMd.getCountExportedTypes()); case mdtManifestResource: return (rid <= m_pStgdb->m_MiniMd.getCountManifestResources()); case mdtMethodSpec: return (rid <= m_pStgdb->m_MiniMd.getCountMethodSpecs()); case mdtString: // need to check the user string heap return m_pStgdb->m_MiniMd.m_UserStringHeap.IsValidIndex(rid); } return FALSE; } // MDInternalRW::IsValidToken mdModule MDInternalRW::GetModuleFromScope(void) { return TokenFromRid(1, mdtModule); } // MDInternalRW::GetModuleFromScope //***************************************************************************** // Given a MetaData with ENC changes, apply those changes to this MetaData. //***************************************************************************** __checkReturn HRESULT MDInternalRW::ApplyEditAndContinue( // S_OK or error. MDInternalRW *pDeltaMD) // Interface to MD with the ENC delta. { HRESULT hr; // A result. // Get the MiniMd on the delta. LOCKWRITEIFFAILRET(); CMiniMdRW &mdDelta = pDeltaMD->m_pStgdb->m_MiniMd; CMiniMdRW &mdBase = m_pStgdb->m_MiniMd; IfFailGo(mdBase.ConvertToRW()); IfFailGo(mdBase.ApplyDelta(mdDelta)); ErrExit: return hr; } // MDInternalRW::ApplyEditAndContinue //***************************************************************************** // Given a MetaData with ENC changes, enumerate the changed tokens. //***************************************************************************** __checkReturn HRESULT MDInternalRW::EnumDeltaTokensInit( // return hresult HENUMInternal *phEnum) // Enumerator to initialize. { HRESULT hr = S_OK; // A result. ULONG index; // Loop control. ENCLogRec *pRec; // An ENCLog record. // Vars for query. _ASSERTE(phEnum); memset(phEnum, 0, sizeof(HENUMInternal)); // cache the tkKind and the scope phEnum->m_tkKind = 0; phEnum->m_EnumType = MDSimpleEnum; HENUMInternal::InitDynamicArrayEnum(phEnum); for (index = 1; index <= m_pStgdb->m_MiniMd.m_Schema.m_cRecs[TBL_ENCLog]; ++index) { // Get the token type; see if it is a real token. IfFailGo(m_pStgdb->m_MiniMd.GetENCLogRecord(index, &pRec)); if (CMiniMdRW::IsRecId(pRec->GetToken())) continue; // If there is a function code, that means that this flags a child-record // addition. The child record will generate its own token, so did the // parent, so skip the record. if (pRec->GetFuncCode()) continue; IfFailGo( HENUMInternal::AddElementToEnum( phEnum, pRec->GetToken())); } ErrExit: // we are done return hr; } // MDInternalRW::EnumDeltaTokensInit //***************************************************************************** // Static function to apply a delta md. This is what the EE calls to apply // the metadata updates from an update PE to live metadata. // MAY REPLACE THE IMDInternalImport POINTER! //***************************************************************************** __checkReturn HRESULT MDApplyEditAndContinue( // S_OK or error. IMDInternalImport **ppIMD, // [in, out] The metadata to be updated. IMDInternalImportENC *pDeltaMD) // [in] The delta metadata. { HRESULT hr; // A result. IMDInternalImportENC *pENC; // ENC interface on the metadata. // If the input metadata isn't RW, convert it. hr = (*ppIMD)->QueryInterface(IID_IMDInternalImportENC, (void**)&pENC); if (FAILED(hr)) { IfFailGo(ConvertRO2RW(*ppIMD, IID_IMDInternalImportENC, (void**)&pENC)); // Replace the old interface pointer with the ENC one. (*ppIMD)->Release(); IfFailGo(pENC->QueryInterface(IID_IMDInternalImport, (void**)ppIMD)); } // Apply the delta to the input metadata. hr = pENC->ApplyEditAndContinue(static_cast(pDeltaMD)); ErrExit: if (pENC) pENC->Release(); return hr; } // MDApplyEditAndContinue //***************************************************************************** // Given a scope, return the table size and table ptr for a given index //***************************************************************************** __checkReturn HRESULT MDInternalRW::GetTableInfoWithIndex( // return size ULONG index, // [IN] pass in the index void **pTable, // [OUT] pointer to table at index void **pTableSize) // [OUT] size of table at index { _ASSERTE(!"NYI"); return E_NOTIMPL; } //***************************************************************************** // Given a delta metadata byte stream, apply the changes to the current metadata // object returning the resulting metadata object in ppv //***************************************************************************** __checkReturn HRESULT MDInternalRW::ApplyEditAndContinue( void *pDeltaMD, // [IN] the delta metadata ULONG cbDeltaMD, // [IN] length of pData IMDInternalImport **ppv) // [OUT] the resulting metadata interface { _ASSERTE(pDeltaMD); _ASSERTE(ppv); // debugging-specific usages don't need SO hardening SO_NOT_MAINLINE_FUNCTION; HRESULT hr = E_FAIL; IMDInternalImportENC *pDeltaMDImport = NULL; IfFailGo(GetInternalWithRWFormat(pDeltaMD, cbDeltaMD, 0, IID_IMDInternalImportENC, (void**)&pDeltaMDImport)); *ppv = this; IfFailGo(MDApplyEditAndContinue(ppv, pDeltaMDImport)); ErrExit: if (pDeltaMDImport) pDeltaMDImport->Release(); return hr; } // MDInternalRW::ApplyEditAndContinue #endif //FEATURE_METADATA_INTERNAL_APIS