//***************************************************************************** // Get the value of a CustomAttribute, using only TypeName for lookup. //***************************************************************************** STDMETHODIMP RegMeta::GetCustomAttributeByName( // S_OK or error. mdToken tkObj, // [IN] Object with Custom Attribute. LPCWSTR wzName, // [IN] Name of desired Custom Attribute. const void **ppData, // [OUT] Put pointer to data here. ULONG *pcbData) // [OUT] Put size of data here. { HRESULT hr; // A result. BEGIN_ENTRYPOINT_NOTHROW; LPUTF8 szName; // Name in UFT8. int iLen; // A length. CMiniMdRW *pMiniMd = NULL; START_MD_PERF(); LOCKREAD(); pMiniMd = &(m_pStgdb->m_MiniMd); iLen = WszWideCharToMultiByte(CP_UTF8,0, wzName,-1, NULL,0, 0,0); szName = (LPUTF8)_alloca(iLen); VERIFY(WszWideCharToMultiByte(CP_UTF8,0, wzName,-1, szName,iLen, 0,0)); hr = ImportHelper::GetCustomAttributeByName(pMiniMd, tkObj, szName, ppData, pcbData); ErrExit: STOP_MD_PERF(GetCustomAttributeByName); END_ENTRYPOINT_NOTHROW; return hr; } // STDMETHODIMP RegMeta::GetCustomAttributeByName()
// // returns the "built for" version of a metadata scope. // HRESULT RegMeta::GetVersionString( // S_OK or error. LPCSTR *pVer) // [OUT] Put version string here. { _ASSERTE(pVer != NULL); HRESULT hr; LOCKREAD(); #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE if (m_pStgdb->m_pvMd != NULL) { #endif *pVer = reinterpret_cast<const char*>(reinterpret_cast<const STORAGESIGNATURE*>(m_pStgdb->m_pvMd)->pVersion); #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE } else { //This emptry string matches the fallback behavior we have in other places that query the version string. //From what I can tell the only caller to this method is the code that tests if we need to apply the WinMD adapter //and it checks if pVer == "WindowsRuntime". We don't support the debugger custom metadata source scenario with WinMDs (yet?) //so we intend for that check to return FALSE. *pVer = ""; } #endif hr = S_OK; ErrExit: return hr; }
//***************************************************************************** // Remove a RegMeta pointer from the loaded module list //***************************************************************************** HRESULT LOADEDMODULES::ResolveTypeRefWithLoadedModules( mdTypeRef tr, // [IN] TypeRef to be resolved. IMetaModelCommon *pCommon, // [IN] scope in which the typeref is defined. REFIID riid, // [IN] iid for the return interface IUnknown **ppIScope, // [OUT] return interface mdTypeDef *ptd) // [OUT] typedef corresponding the typeref { HRESULT hr = NOERROR; RegMeta *pRegMeta; CQuickArray<mdTypeRef> cqaNesters; CQuickArray<LPCUTF8> cqaNesterNamespaces; CQuickArray<LPCUTF8> cqaNesterNames; int count; int index; if (g_LoadedModules == NULL) { // No loaded module! _ASSERTE(!"Bad state!"); return E_FAIL; } LOCKREAD(); // Get the Nesting hierarchy. IfFailGo(ImportHelper::GetNesterHierarchy(pCommon, tr, cqaNesters, cqaNesterNamespaces, cqaNesterNames)); count = g_LoadedModules->Count(); for (index = 0; index < count; index++) { pRegMeta = (*g_LoadedModules)[index]; hr = ImportHelper::FindNestedTypeDef( pRegMeta->GetMiniMd(), cqaNesterNamespaces, cqaNesterNames, mdTokenNil, ptd); if (SUCCEEDED(hr)) { // found a loaded module containing the TypeDef. hr = pRegMeta->QueryInterface(riid, (void **)ppIScope); break; } else if (hr != CLDB_E_RECORD_NOTFOUND) IfFailGo(hr); } if (FAILED(hr)) { // cannot find the match! hr = E_FAIL; } ErrExit: return hr; } // LOADEDMODULES::ResolveTypeRefWithLoadedModules
//***************************************************************************** // Enumerate Sym.TypeRef //***************************************************************************** STDMETHODIMP RegMeta::EnumTypeRefs( HCORENUM *phEnum, // Pointer to the enumerator. mdTypeRef rTypeRefs[], // Put TypeRefs here. ULONG cMax, // Max TypeRefs to put. ULONG *pcTypeRefs) // Put # put here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); ULONG cTotal; HENUMInternal *pEnum = *ppmdEnum; LOG((LOGMD, "RegMeta::EnumTypeRefs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", phEnum, rTypeRefs, cMax, pcTypeRefs)); START_MD_PERF(); LOCKREAD(); if ( pEnum == 0 ) { // instantiating a new ENUM CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); cTotal = pMiniMd->getCountTypeRefs(); IfFailGo( HENUMInternal::CreateSimpleEnum( mdtTypeRef, 1, cTotal + 1, &pEnum) ); // set the output parameter *ppmdEnum = pEnum; } // fill the output token buffer hr = HENUMInternal::EnumWithCount(pEnum, cMax, rTypeRefs, pcTypeRefs); ErrExit: HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); STOP_MD_PERF(EnumTypeRefs); END_ENTRYPOINT_NOTHROW; return hr; } // STDMETHODIMP RegMeta::EnumTypeRefs()
//***************************************************************************** // Given a namespace and a class name, return the typedef //***************************************************************************** STDMETHODIMP RegMeta::FindTypeDefByName(// S_OK or error. LPCWSTR wzTypeDef, // [IN] Name of the Type. mdToken tkEnclosingClass, // [IN] Enclosing class. mdTypeDef *ptd) // [OUT] Put the TypeDef token here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW LOG((LOGMD, "{%08x} RegMeta::FindTypeDefByName(%S, 0x%08x, 0x%08x)\n", this, MDSTR(wzTypeDef), tkEnclosingClass, ptd)); START_MD_PERF(); LOCKREAD(); if (wzTypeDef == NULL) IfFailGo(E_INVALIDARG); PREFIX_ASSUME(wzTypeDef != NULL); LPSTR szTypeDef; UTF8STR(wzTypeDef, szTypeDef); LPCSTR szNamespace; LPCSTR szName; _ASSERTE(ptd); _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef || TypeFromToken(tkEnclosingClass) == mdtTypeRef || IsNilToken(tkEnclosingClass)); // initialize output parameter *ptd = mdTypeDefNil; ns::SplitInline(szTypeDef, szNamespace, szName); hr = ImportHelper::FindTypeDefByName(&(m_pStgdb->m_MiniMd), szNamespace, szName, tkEnclosingClass, ptd); ErrExit: STOP_MD_PERF(FindTypeDefByName); END_ENTRYPOINT_NOTHROW; return hr; } // STDMETHODIMP RegMeta::FindTypeDefByName()
//***************************************************************************** // Get information about a CustomAttribute. //***************************************************************************** STDMETHODIMP RegMeta::GetCustomAttributeProps( mdCustomAttribute cv, // The attribute token mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here. mdToken *ptkType, // [OUT, OPTIONAL] Put TypeDef/TypeRef token here. void const **ppBlob, // [OUT, OPTIONAL] Put pointer to data here. ULONG *pcbSize) // [OUT, OPTIONAL] Put size of data here. { HRESULT hr = S_OK; // A result. BEGIN_ENTRYPOINT_NOTHROW; CMiniMdRW *pMiniMd; START_MD_PERF(); LOCKREAD(); _ASSERTE(TypeFromToken(cv) == mdtCustomAttribute); pMiniMd = &(m_pStgdb->m_MiniMd); CustomAttributeRec *pCustomAttributeRec; // The custom value record. IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(cv), &pCustomAttributeRec)); if (ptkObj) *ptkObj = pMiniMd->getParentOfCustomAttribute(pCustomAttributeRec); if (ptkType) *ptkType = pMiniMd->getTypeOfCustomAttribute(pCustomAttributeRec); if (ppBlob != NULL) { IfFailGo(pMiniMd->getValueOfCustomAttribute(pCustomAttributeRec, (const BYTE **)ppBlob, pcbSize)); } ErrExit: STOP_MD_PERF(GetCustomAttributeProps); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::GetCustomAttributeProps
//***************************************************************************** // Gets a cached Internal importer, if available. // // Arguments: // fWithLock - if true, takes a reader lock. // If false, assumes caller is handling the synchronization. // // Returns: // A cached Internal importer, which gets addreffed. Caller must release! // If no importer is set, returns NULL // // Notes: // This function also does not trigger the creation of Internal interface. // Set the cached importer via code:RegMeta.SetCachedInternalInterface // // Implements internal API code:IMetaDataHelper::GetCachedInternalInterface. //***************************************************************************** IUnknown* RegMeta::GetCachedInternalInterface(BOOL fWithLock) { IUnknown *pRet = NULL; HRESULT hr = S_OK; if (fWithLock) { LOCKREAD(); pRet = m_pInternalImport; } else { pRet = m_pInternalImport; } if (pRet) pRet->AddRef(); ErrExit: return pRet; } //RegMeta::GetCachedInternalInterface
//***************************************************************************** // Search the cached RegMetas for a given scope. //***************************************************************************** BOOL LOADEDMODULES::IsEntryInList( RegMeta * pRegMeta) { HRESULT hr = S_OK; IfFailGo(InitializeStatics()); { LOCKREAD(); // Loop through each loaded modules int count = s_pLoadedModules->Count(); for (int index = 0; index < count; index++) { if ((*s_pLoadedModules)[index] == pRegMeta) { return TRUE; } } } ErrExit: return FALSE; } // LOADEDMODULES::IsEntryInList
//***************************************************************************** // Implementation of IMetaDataImport::ResolveTypeRef to resolve a typeref across scopes. // // Arguments: // tr - typeref within this scope to resolve // riid - interface on ppIScope to support // ppIScope - out-parameter to get metadata scope for typedef (*ptd) // ptd - out-parameter to get typedef that the ref resolves to. // // Notes: // TypeDefs define a type within a scope. TypeRefs refer to type-defs in other scopes // and allow you to import a type from another scope. This function attempts to determine // which type-def a type-ref points to. // // This resolve (type-ref, this cope) --> (type-def=*ptd, other scope=*ppIScope) // // However, this resolution requires knowing what modules have been loaded, which is not decided // until runtime via loader / fusion policy. Thus this interface can't possibly be correct since // it doesn't have that knowledge. Furthermore, when inspecting metadata from another process // (such as a debugger inspecting the debuggee's metadata), this API can be truly misleading. // // This API usage should be avoided. // //***************************************************************************** STDMETHODIMP RegMeta::ResolveTypeRef( mdTypeRef tr, REFIID riid, IUnknown ** ppIScope, mdTypeDef * ptd) { #ifdef FEATURE_METADATA_IN_VM HRESULT hr; BEGIN_ENTRYPOINT_NOTHROW; TypeRefRec * pTypeRefRec; WCHAR wzNameSpace[_MAX_PATH]; CMiniMdRW * pMiniMd = NULL; LOG((LOGMD, "{%08x} RegMeta::ResolveTypeRef(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", this, tr, riid, ppIScope, ptd)); START_MD_PERF(); LOCKREAD(); pMiniMd = &(m_pStgdb->m_MiniMd); _ASSERTE((ppIScope != NULL) && (ptd != NULL)); // Init the output values. *ppIScope = NULL; *ptd = 0; if (IsNilToken(tr)) { if (ptd != NULL) { *ptd = mdTypeDefNil; } if (ppIScope != NULL) { *ppIScope = NULL; } STOP_MD_PERF(ResolveTypeRef); hr = E_INVALIDARG; goto ErrExit; } if (TypeFromToken(tr) == mdtTypeDef) { // Shortcut when we receive a TypeDef token *ptd = tr; STOP_MD_PERF(ResolveTypeRef); hr = this->QueryInterface(riid, (void **)ppIScope); goto ErrExit; } // Get the class ref row. _ASSERTE(TypeFromToken(tr) == mdtTypeRef); IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tr), &pTypeRefRec)); IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, wzNameSpace, lengthof(wzNameSpace), NULL)); if (hr != NOERROR) { _ASSERTE(hr == CLDB_S_TRUNCATION); // Truncate the namespace string wzNameSpace[lengthof(wzNameSpace) - 1] = 0; } //*********************** // before we go off to CORPATH, check the loaded modules! //*********************** if (LOADEDMODULES::ResolveTypeRefWithLoadedModules( tr, this, pMiniMd, riid, ppIScope, ptd) == NOERROR) { // Done!! We found one match among the loaded modules. goto ErrExit; } IfFailGo(META_E_CANNOTRESOLVETYPEREF); ErrExit: STOP_MD_PERF(ResolveTypeRef); END_ENTRYPOINT_NOTHROW; return hr; #else // FEATURE_METADATA_IN_VM return E_NOTIMPL; #endif // FEATURE_METADATA_IN_VM } // RegMeta::ResolveTypeRef
STDMETHODIMP RegMeta::EnumGenericParamConstraints( HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. mdGenericParam tkOwner, // [IN] GenericParam whose constraints are requested mdGenericParamConstraint rTokens[], // [OUT] Put GenericParamConstraints here. ULONG cMaxTokens, // [IN] Max GenericParamConstraints to put. ULONG *pcTokens) // [OUT] Put # of tokens here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); ULONG ridStart; ULONG ridEnd; HENUMInternal *pEnum; GenericParamConstraintRec *pRec; ULONG index; CMiniMdRW *pMiniMd = NULL; LOG((LOGMD, "RegMeta::EnumGenericParamConstraints(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", phEnum, tkOwner, rTokens, cMaxTokens, pcTokens)); START_MD_PERF(); LOCKREAD(); pMiniMd = &(m_pStgdb->m_MiniMd); if(TypeFromToken(tkOwner) != mdtGenericParam) IfFailGo(META_E_BAD_INPUT_PARAMETER); // See if this version of the metadata can do Generics if (!pMiniMd->SupportsGenerics()) { if (pcTokens) *pcTokens = 0; hr = S_FALSE; goto ErrExit; } if ( *ppmdEnum == 0 ) { // instantiating a new ENUM //<TODO> GENERICS: review this. Are we expecting a sorted table or not? </TODO> if ( pMiniMd->IsSorted( TBL_GenericParamConstraint ) ) { IfFailGo(pMiniMd->getGenericParamConstraintsForGenericParam(RidFromToken(tkOwner), &ridEnd, &ridStart)); IfFailGo( HENUMInternal::CreateSimpleEnum(mdtGenericParamConstraint, ridStart, ridEnd, &pEnum) ); } else { // table is not sorted so we have to create dynamic array // create the dynamic enumerator // ridStart = 1; ridEnd = pMiniMd->getCountGenericParamConstraints() + 1; IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtGenericParamConstraint, &pEnum)); for (index = ridStart; index < ridEnd; index ++ ) { IfFailGo(pMiniMd->GetGenericParamConstraintRecord(index, &pRec)); if ( tkOwner == pMiniMd->getOwnerOfGenericParamConstraint(pRec)) { IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtGenericParamConstraint))); } } } // set the output parameter *ppmdEnum = pEnum; } else { pEnum = *ppmdEnum; } // fill the output token buffer hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens); ErrExit: HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); STOP_MD_PERF(EnumGenericParamConstraints); END_ENTRYPOINT_NOTHROW; return hr; }
STDMETHODIMP RegMeta::EnumMethodSpecs( HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. mdToken tkOwner, // [IN] MethodDef or MemberRef whose MethodSpecs are requested mdMethodSpec rTokens[], // [OUT] Put MethodSpecs here. ULONG cMaxTokens, // [IN] Max tokens to put. ULONG *pcTokens) // [OUT] Put actual count here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); ULONG ridStart; ULONG ridEnd; HENUMInternal *pEnum; MethodSpecRec *pRec; ULONG index; CMiniMdRW *pMiniMd = NULL; LOG((LOGMD, "RegMeta::EnumMethodSpecs(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", phEnum, tkOwner, rTokens, cMaxTokens, pcTokens)); START_MD_PERF(); LOCKREAD(); pMiniMd = &(m_pStgdb->m_MiniMd); // See if this version of the metadata can do Generics if (!pMiniMd->SupportsGenerics()) { if (pcTokens) *pcTokens = 0; hr = S_FALSE; goto ErrExit; } _ASSERTE(RidFromToken(tkOwner)==0 || TypeFromToken(tkOwner) == mdtMethodDef || TypeFromToken(tkOwner) == mdtMemberRef); if ( *ppmdEnum == 0 ) { // instantiating a new ENUM if(RidFromToken(tkOwner)==0) // enumerate all MethodSpecs { ridStart = 1; ridEnd = pMiniMd->getCountMethodSpecs() + 1; IfFailGo( HENUMInternal::CreateSimpleEnum( mdtMethodSpec, ridStart, ridEnd, &pEnum) ); } else { //@todo GENERICS: review this. Are we expecting a sorted table or not? if ( pMiniMd->IsSorted( TBL_MethodSpec ) ) { if (TypeFromToken(tkOwner) == mdtMemberRef) { IfFailGo(pMiniMd->getMethodSpecsForMemberRef(RidFromToken(tkOwner), &ridEnd, &ridStart)); } else { IfFailGo(pMiniMd->getMethodSpecsForMethodDef(RidFromToken(tkOwner), &ridEnd, &ridStart)); } IfFailGo( HENUMInternal::CreateSimpleEnum(mdtMethodSpec, ridStart, ridEnd, &pEnum) ); } else { // table is not sorted so we have to create dynamic array // create the dynamic enumerator // ridStart = 1; ridEnd = pMiniMd->getCountMethodSpecs() + 1; IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtMethodSpec, &pEnum) ); for (index = ridStart; index < ridEnd; index ++ ) { IfFailGo(pMiniMd->GetMethodSpecRecord(index, &pRec)); if ( tkOwner == pMiniMd->getMethodOfMethodSpec(pRec) ) { IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtMethodSpec) ) ); } } } } // set the output parameter *ppmdEnum = pEnum; } else { pEnum = *ppmdEnum; } // fill the output token buffer hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens); ErrExit: HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); STOP_MD_PERF(EnumMethodSpecs); END_ENTRYPOINT_NOTHROW; return hr; } // STDMETHODIMP RegMeta::EnumMethodSpecs()
//***************************************************************************** // Enumerate Sym.InterfaceImpl where Coclass == td //***************************************************************************** STDMETHODIMP RegMeta::EnumInterfaceImpls( HCORENUM *phEnum, // Pointer to the enum. mdTypeDef td, // TypeDef to scope the enumeration. mdInterfaceImpl rImpls[], // Put InterfaceImpls here. ULONG cMax, // Max InterfaceImpls to put. ULONG *pcImpls) // Put # put here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); ULONG ridStart; ULONG ridEnd; HENUMInternal *pEnum; InterfaceImplRec *pRec; ULONG index; LOG((LOGMD, "RegMeta::EnumInterfaceImpls(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", phEnum, td, rImpls, cMax, pcImpls)); START_MD_PERF(); LOCKREAD(); _ASSERTE(TypeFromToken(td) == mdtTypeDef); if ( *ppmdEnum == 0 ) { // instantiating a new ENUM CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); if ( pMiniMd->IsSorted( TBL_InterfaceImpl ) ) { IfFailGo(pMiniMd->getInterfaceImplsForTypeDef(RidFromToken(td), &ridEnd, &ridStart)); IfFailGo( HENUMInternal::CreateSimpleEnum( mdtInterfaceImpl, ridStart, ridEnd, &pEnum) ); } else { // table is not sorted so we have to create dynmaic array // create the dynamic enumerator // ridStart = 1; ridEnd = pMiniMd->getCountInterfaceImpls() + 1; IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtInterfaceImpl, &pEnum) ); for (index = ridStart; index < ridEnd; index ++ ) { IfFailGo(pMiniMd->GetInterfaceImplRecord(index, &pRec)); if ( td == pMiniMd->getClassOfInterfaceImpl(pRec) ) { IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtInterfaceImpl) ) ); } } } // set the output parameter *ppmdEnum = pEnum; } else { pEnum = *ppmdEnum; } // fill the output token buffer hr = HENUMInternal::EnumWithCount(pEnum, cMax, rImpls, pcImpls); ErrExit: HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); STOP_MD_PERF(EnumInterfaceImpls); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::EnumInterfaceImpls
//***************************************************************************** // Enumerate Sym.TypeDef. //***************************************************************************** STDMETHODIMP RegMeta::EnumTypeDefs( HCORENUM *phEnum, // Pointer to the enumerator. mdTypeDef rTypeDefs[], // Put TypeDefs here. ULONG cMax, // Max TypeDefs to put. ULONG *pcTypeDefs) // Put # put here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); HENUMInternal *pEnum; LOG((LOGMD, "RegMeta::EnumTypeDefs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", phEnum, rTypeDefs, cMax, pcTypeDefs)); START_MD_PERF(); LOCKREAD(); if ( *ppmdEnum == 0 ) { // instantiating a new ENUM CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); if (pMiniMd->HasDelete() && ((m_OptionValue.m_ImportOption & MDImportOptionAllTypeDefs) == 0)) { IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtTypeDef, &pEnum) ); // add all Types to the dynamic array if name is not _Delete for (ULONG index = 2; index <= pMiniMd->getCountTypeDefs(); index ++ ) { TypeDefRec *pRec; IfFailGo(pMiniMd->GetTypeDefRecord(index, &pRec)); LPCSTR szTypeDefName; IfFailGo(pMiniMd->getNameOfTypeDef(pRec, &szTypeDefName)); if (IsDeletedName(szTypeDefName)) { continue; } IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtTypeDef) ) ); } } else { // create the enumerator IfFailGo( HENUMInternal::CreateSimpleEnum( mdtTypeDef, 2, pMiniMd->getCountTypeDefs() + 1, &pEnum) ); } // set the output parameter *ppmdEnum = pEnum; } else { pEnum = *ppmdEnum; } // we can only fill the minimun of what caller asked for or what we have left hr = HENUMInternal::EnumWithCount(pEnum, cMax, rTypeDefs, pcTypeDefs); ErrExit: HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); STOP_MD_PERF(EnumTypeDefs); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::EnumTypeDefs
//***************************************************************************** // Remove a RegMeta pointer from the loaded module list //***************************************************************************** // static HRESULT LOADEDMODULES::ResolveTypeRefWithLoadedModules( mdTypeRef tkTypeRef, // [IN] TypeRef to be resolved. RegMeta * pTypeRefRegMeta, // [IN] Scope in which the TypeRef is defined. IMetaModelCommon * pTypeRefScope, // [IN] Scope in which the TypeRef is defined. REFIID riid, // [IN] iid for the return interface. IUnknown ** ppIScope, // [OUT] Return interface. mdTypeDef * ptd) // [OUT] TypeDef corresponding the TypeRef. { HRESULT hr = NOERROR; RegMeta * pRegMeta; CQuickArray<mdTypeRef> cqaNesters; CQuickArray<LPCUTF8> cqaNesterNamespaces; CQuickArray<LPCUTF8> cqaNesterNames; IfFailGo(InitializeStatics()); { LOCKREAD(); // Get the Nesting hierarchy. IfFailGo(ImportHelper::GetNesterHierarchy( pTypeRefScope, tkTypeRef, cqaNesters, cqaNesterNamespaces, cqaNesterNames)); int count = s_pLoadedModules->Count(); for (int index = 0; index < count; index++) { pRegMeta = (*s_pLoadedModules)[index]; { // Do not lock the TypeRef RegMeta (again), as it is already locked for read by the caller. // The code:UTSemReadWrite will block ReadLock even for thread holding already the read lock if // some other thread is waiting for WriteLock on the same lock. That would cause dead-lock if we // try to lock for read again here. CMDSemReadWrite cSemRegMeta((pRegMeta == pTypeRefRegMeta) ? NULL : pRegMeta->GetReaderWriterLock()); IfFailGo(cSemRegMeta.LockRead()); hr = ImportHelper::FindNestedTypeDef( pRegMeta->GetMiniMd(), cqaNesterNamespaces, cqaNesterNames, mdTokenNil, ptd); } if (hr == CLDB_E_RECORD_NOTFOUND) { // Process next MetaData module continue; } IfFailGo(hr); // Found a loaded module containing the TypeDef. IfFailGo(pRegMeta->QueryInterface(riid, (void **)ppIScope)); break; } } if (FAILED(hr)) { // cannot find the match! hr = E_FAIL; } ErrExit: return hr; } // LOADEDMODULES::ResolveTypeRefWithLoadedModules
//***************************************************************************** // Search the cached RegMetas for a given scope. //***************************************************************************** HRESULT LOADEDMODULES::FindCachedReadOnlyEntry( LPCWSTR szName, // Name of the desired file. DWORD dwOpenFlags, // Flags the new file is opened with. RegMeta ** ppMeta) // Put found RegMeta here. { RegMeta * pRegMeta = 0; BOOL bWillBeCopyMemory; // Will the opened file be copied to memory? DWORD dwLowFileSize; // Low bytes of this file's size DWORD dwLowFileTime; // Low butes of this file's last write time HRESULT hr; ULONG ixHash = 0; IfFailGo(InitializeStatics()); { LOCKREAD(); hr = S_FALSE; // We haven't found a match yet. // Avoid confusion. *ppMeta = NULL; bWillBeCopyMemory = IsOfCopyMemory(dwOpenFlags); // The cache is locked for read, so the list will not change. // Figure out the size and timestamp of this file WIN32_FILE_ATTRIBUTE_DATA faData; if (!WszGetFileAttributesEx(szName, GetFileExInfoStandard, &faData)) return E_FAIL; dwLowFileSize = faData.nFileSizeLow; dwLowFileTime = faData.ftLastWriteTime.dwLowDateTime; // Check the hash first. ixHash = HashFileName(szName); if ((pRegMeta = m_HashedModules[ixHash]) != NULL) { _ASSERTE(pRegMeta->IsReadOnly()); // Only match if the IsOfCopyMemory() bit is the same in both. This is because // when ofCopyMemory is set, the file is not locked on disk, and may become stale // in memory. // // Also, only match if the date and size are the same if (pRegMeta->IsCopyMemory() == bWillBeCopyMemory && pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime && pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize) { // If the name matches... LPCWSTR pszName = pRegMeta->GetNameOfDBFile(); #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM if (wcscmp(szName, pszName) == 0) #else if (SString::_wcsicmp(szName, pszName) == 0) #endif { ULONG cRefs; // Found it. Add a reference, and return it. *ppMeta = pRegMeta; cRefs = pRegMeta->AddRef(); LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta in hash: %#8x, crefs: %d\n", pRegMeta, cRefs)); return S_OK; } } } // Not found in hash; loop through each loaded modules int count = s_pLoadedModules->Count(); for (int index = 0; index < count; index++) { pRegMeta = (*s_pLoadedModules)[index]; // If the module is read-only, and the CopyMemory bit matches, and the date // and size are the same.... if (pRegMeta->IsReadOnly() && pRegMeta->IsCopyMemory() == bWillBeCopyMemory && pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime && pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize) { // If the name matches... LPCWSTR pszName = pRegMeta->GetNameOfDBFile(); #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM if (wcscmp(szName, pszName) == 0) #else if (SString::_wcsicmp(szName, pszName) == 0) #endif { ULONG cRefs; // Found it. Add a reference, and return it. *ppMeta = pRegMeta; cRefs = pRegMeta->AddRef(); // Update the hash. m_HashedModules[ixHash] = pRegMeta; LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta by search: %#8x, crefs: %d\n", pRegMeta, cRefs)); return S_OK; } } } } ErrExit: // Didn't find it. LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope did not find cached RegMeta\n")); _ASSERTE(hr != S_OK); return hr; } // LOADEDMODULES::FindCachedReadOnlyEntry
//***************************************************************************** // Enumerate the CustomAttributes for a given token. //***************************************************************************** STDMETHODIMP RegMeta::EnumCustomAttributes( HCORENUM *phEnum, // Pointer to the enum. mdToken tk, // Token to scope the enumeration. mdToken tkType, // Type to limit the enumeration. mdCustomAttribute rCustomAttributes[], // Put CustomAttributes here. ULONG cMax, // Max CustomAttributes to put. ULONG *pcCustomAttributes) // Put # tokens returned here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); ULONG ridStart; ULONG ridEnd; HENUMInternal *pEnum = *ppmdEnum; CustomAttributeRec *pRec; ULONG index; LOG((LOGMD, "RegMeta::EnumCustomAttributes(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", phEnum, tk, tkType, rCustomAttributes, cMax, pcCustomAttributes)); START_MD_PERF(); LOCKREAD(); if ( pEnum == 0 ) { // instantiating a new ENUM CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); CLookUpHash *pHashTable = pMiniMd->m_pLookUpHashs[TBL_CustomAttribute]; // Does caller want all custom Values? if (IsNilToken(tk)) { IfFailGo( HENUMInternal::CreateSimpleEnum(mdtCustomAttribute, 1, pMiniMd->getCountCustomAttributes()+1, &pEnum) ); } else { // Scope by some object. if ( pMiniMd->IsSorted( TBL_CustomAttribute ) ) { // Get CustomAttributes for the object. IfFailGo(pMiniMd->getCustomAttributeForToken(tk, &ridEnd, &ridStart)); if (IsNilToken(tkType)) { // Simple enumerator for object's entire list. IfFailGo( HENUMInternal::CreateSimpleEnum( mdtCustomAttribute, ridStart, ridEnd, &pEnum) ); } else { // Dynamic enumerator for subsetted list. IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) ); for (index = ridStart; index < ridEnd; index ++ ) { IfFailGo(pMiniMd->GetCustomAttributeRecord(index, &pRec)); if (tkType == pMiniMd->getTypeOfCustomAttribute(pRec)) { IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtCustomAttribute) ) ); } } } } else { if (pHashTable) { // table is not sorted but hash is built // We want to create dynmaic array to hold the dynamic enumerator. TOKENHASHENTRY *p; ULONG iHash; int pos; mdToken tkParentTmp; mdToken tkTypeTmp; // Hash the data. iHash = pMiniMd->HashCustomAttribute(tk); IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) ); // Go through every entry in the hash chain looking for ours. for (p = pHashTable->FindFirst(iHash, pos); p; p = pHashTable->FindNext(pos)) { CustomAttributeRec *pCustomAttribute; IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(p->tok), &pCustomAttribute)); tkParentTmp = pMiniMd->getParentOfCustomAttribute(pCustomAttribute); tkTypeTmp = pMiniMd->getTypeOfCustomAttribute(pCustomAttribute); if (tkParentTmp == tk) { if (IsNilToken(tkType) || tkType == tkTypeTmp) { // compare the blob value IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(p->tok, mdtCustomAttribute )) ); } } } } else { // table is not sorted and hash is not built so we have to create dynmaic array // create the dynamic enumerator and loop through CA table linearly // ridStart = 1; ridEnd = pMiniMd->getCountCustomAttributes() + 1; IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) ); for (index = ridStart; index < ridEnd; index ++ ) { IfFailGo(pMiniMd->GetCustomAttributeRecord(index, &pRec)); if ( tk == pMiniMd->getParentOfCustomAttribute(pRec) && (tkType == pMiniMd->getTypeOfCustomAttribute(pRec) || IsNilToken(tkType))) { IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtCustomAttribute) ) ); } } } } } // set the output parameter *ppmdEnum = pEnum; } // fill the output token buffer hr = HENUMInternal::EnumWithCount(pEnum, cMax, rCustomAttributes, pcCustomAttributes); ErrExit: HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); STOP_MD_PERF(EnumCustomAttributes); END_ENTRYPOINT_NOTHROW; return hr; } // STDMETHODIMP RegMeta::EnumCustomAttributes()