//******************************************************************************* // Set the specified attributes on the given File token. //******************************************************************************* STDMETHODIMP RegMeta::SetFileProps( // S_OK or error. mdFile file, // [IN] File token. const void *pbHashValue, // [IN] Hash Blob. ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob. DWORD dwFileFlags) // [IN] Flags. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; _ASSERTE(TypeFromToken(file) == mdtFile && RidFromToken(file)); LOG((LOGMD, "RegMeta::SetFileProps(%#08x, %#08x, %#08x, %#08x)\n", file, pbHashValue, cbHashValue, dwFileFlags)); START_MD_PERF(); LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); IfFailGo( _SetFileProps(file, pbHashValue, cbHashValue, dwFileFlags) ); ErrExit: STOP_MD_PERF(SetFileProps); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::SetFileProps
//******************************************************************************* // Set the specified attributes on the given ExportedType token. //******************************************************************************* STDMETHODIMP RegMeta::SetExportedTypeProps( // S_OK or error. mdExportedType ct, // [IN] ExportedType token. mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the ExportedType. mdTypeDef tkTypeDef, // [IN] TypeDef token within the file. DWORD dwExportedTypeFlags) // [IN] Flags. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; LOG((LOGMD, "RegMeta::SetExportedTypeProps(%#08x, %#08x, %#08x, %#08x)\n", ct, tkImplementation, tkTypeDef, dwExportedTypeFlags)); START_MD_PERF(); LOCKWRITE(); IfFailGo( _SetExportedTypeProps( ct, tkImplementation, tkTypeDef, dwExportedTypeFlags) ); ErrExit: STOP_MD_PERF(SetExportedTypeProps); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::SetExportedTypeProps
//******************************************************************************* // Set the specified attributes on the given Assembly token. //******************************************************************************* STDMETHODIMP RegMeta::SetAssemblyProps( // S_OK or error. mdAssembly ma, // [IN] Assembly token. const void *pbPublicKey, // [IN] Public key of the assembly. ULONG cbPublicKey, // [IN] Count of bytes in the public key. ULONG ulHashAlgId, // [IN] Hash Algorithm. LPCWSTR szName, // [IN] Name of the assembly. const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData. DWORD dwAssemblyFlags) // [IN] Flags. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; _ASSERTE(TypeFromToken(ma) == mdtAssembly && RidFromToken(ma)); LOG((LOGMD, "RegMeta::SetAssemblyProps(%#08x, %#08x, %#08x, %#08x %S, %#08x, %#08x)\n", ma, pbPublicKey, cbPublicKey, ulHashAlgId, MDSTR(szName), pMetaData, dwAssemblyFlags)); START_MD_PERF(); LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); IfFailGo(_SetAssemblyProps(ma, pbPublicKey, cbPublicKey, ulHashAlgId, szName, pMetaData, dwAssemblyFlags)); ErrExit: STOP_MD_PERF(SetAssemblyProps); END_ENTRYPOINT_NOTHROW; return hr; } // STDMETHODIMP SetAssemblyProps()
//***************************************************************************** // Add a RegMeta pointer to the loaded module list //***************************************************************************** HRESULT LOADEDMODULES::AddModuleToLoadedList(RegMeta * pRegMeta) { HRESULT hr = NOERROR; RegMeta ** ppRegMeta; IfFailGo(InitializeStatics()); { LOCKWRITE(); ppRegMeta = s_pLoadedModules->Append(); IfNullGo(ppRegMeta); // The cache holds a copy of the pointer, but no ref-count. There is no // point to the ref-count, because it just changes comparisons against 0 // to comparisons against 1. *ppRegMeta = pRegMeta; // If the module is read-only, hash it. if (pRegMeta->IsReadOnly()) { ULONG ixHash = HashFileName(pRegMeta->GetNameOfDBFile()); m_HashedModules[ixHash] = pRegMeta; } } ErrExit: return hr; } // LOADEDMODULES::AddModuleToLoadedList
//******************************************************************************* // helper to set field layout // // Implements internal API code:IMetaDataEmitHelper::SetFieldLayoutHelper. //******************************************************************************* HRESULT RegMeta::SetFieldLayoutHelper( // Return hresult. mdFieldDef fd, // [IN] field to associate the layout info ULONG ulOffset) // [IN] the offset for the field { HRESULT hr; FieldLayoutRec *pFieldLayoutRec; RID iFieldLayoutRec; LOCKWRITE(); if (ulOffset == ULONG_MAX) { // invalid argument IfFailGo( E_INVALIDARG ); } // create a field layout record IfFailGo(m_pStgdb->m_MiniMd.AddFieldLayoutRecord(&pFieldLayoutRec, &iFieldLayoutRec)); // Set the Field entry. IfFailGo(m_pStgdb->m_MiniMd.PutToken( TBL_FieldLayout, FieldLayoutRec::COL_Field, pFieldLayoutRec, fd)); pFieldLayoutRec->SetOffSet(ulOffset); IfFailGo( m_pStgdb->m_MiniMd.AddFieldLayoutToHash(iFieldLayoutRec) ); ErrExit: return hr; } // RegMeta::SetFieldLayout
//******************************************************************************* // Set the specified attributes on the given ManifestResource token. //******************************************************************************* STDMETHODIMP RegMeta::SetManifestResourceProps(// S_OK or error. mdManifestResource mr, // [IN] ManifestResource token. mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the resource. DWORD dwOffset, // [IN] Offset to the beginning of the resource within the file. DWORD dwResourceFlags) // [IN] Flags. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; LOG((LOGMD, "RegMeta::SetManifestResourceProps(%#08x, %#08x, %#08x, %#08x)\n", mr, tkImplementation, dwOffset, dwResourceFlags)); _ASSERTE(TypeFromToken(tkImplementation) == mdtFile || TypeFromToken(tkImplementation) == mdtAssemblyRef || tkImplementation == mdTokenNil); START_MD_PERF(); LOCKWRITE(); IfFailGo( _SetManifestResourceProps( mr, tkImplementation, dwOffset, dwResourceFlags) ); ErrExit: STOP_MD_PERF(SetManifestResourceProps); END_ENTRYPOINT_NOTHROW; return hr; } // STDMETHODIMP RegMeta::SetManifestResourceProps()
//******************************************************************************* // helper to define method semantics // // Implements internal API code:IMetaDataEmitHelper::DefineMethodSemanticsHelper. //******************************************************************************* HRESULT RegMeta::DefineMethodSemanticsHelper( mdToken tkAssociation, // [IN] property or event token DWORD dwFlags, // [IN] semantics mdMethodDef md) // [IN] method to associated with { HRESULT hr; LOCKWRITE(); hr = _DefineMethodSemantics((USHORT) dwFlags, md, tkAssociation, false); ErrExit: return hr; } // RegMeta::DefineMethodSemantics
//***************************************************************************** // Helper : Set ResolutionScope of a TypeRef // // Implements internal API code:IMetaDataEmitHelper::SetResolutionScopeHelper. //***************************************************************************** HRESULT RegMeta::SetResolutionScopeHelper( // Return hresult. mdTypeRef tr, // [IN] TypeRef record to update mdToken rs) // [IN] new ResolutionScope { HRESULT hr = NOERROR; TypeRefRec * pTypeRef; LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.GetTypeRefRecord(RidFromToken(tr), &pTypeRef)); IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_TypeRef, TypeRefRec::COL_ResolutionScope, pTypeRef, rs)); ErrExit: return hr; } // RegMeta::SetResolutionScopeHelper
//******************************************************************************* // helper to set type's extends column // // Implements internal API code:IMetaDataEmitHelper::SetTypeParent. //******************************************************************************* HRESULT RegMeta::SetTypeParent( // Return hresult. mdTypeDef td, // [IN] Type definition mdToken tkExtends) // [IN] parent type { HRESULT hr; TypeDefRec *pRec; LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pRec)); IfFailGo( m_pStgdb->m_MiniMd.PutToken(TBL_TypeDef, TypeDefRec::COL_Extends, pRec, tkExtends) ); ErrExit: return hr; } // RegMeta::SetTypeParent
//***************************************************************************** // Helper : Set offset of a ManifestResource // // Implements internal API code:IMetaDataEmitHelper::SetManifestResourceOffsetHelper. //***************************************************************************** HRESULT RegMeta::SetManifestResourceOffsetHelper( mdManifestResource mr, // [IN] The manifest token ULONG ulOffset) // [IN] new offset { HRESULT hr = NOERROR; ManifestResourceRec * pRec; LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.GetManifestResourceRecord(RidFromToken(mr), &pRec)); pRec->SetOffset(ulOffset); ErrExit: return hr; } // RegMeta::SetManifestResourceOffsetHelper
//***************************************************************************** // Remove a RegMeta pointer from the loaded module list //***************************************************************************** BOOL LOADEDMODULES::RemoveModuleFromLoadedList(RegMeta *pRegMeta) { int count; int index; BOOL bRemoved = FALSE; ULONG cRef; LOCKWRITE(); // The cache is locked for write, so no other thread can obtain the RegMeta // from the cache. See if some other thread has a ref-count. cRef = pRegMeta->GetRefCount(); // If some other thread has a ref-count, don't remove from the cache. if (cRef > 0) return FALSE; // If there is no loaded modules, don't bother if (g_LoadedModules == NULL) { return TRUE; // Can't be cached, same as if removed by this thread. } // loop through each loaded modules count = g_LoadedModules->Count(); for (index = 0; index < count; index++) { if ((*g_LoadedModules)[index] == pRegMeta) { // found a match to remove g_LoadedModules->Delete(index); bRemoved = TRUE; break; } } // If no more loaded modules, delete the dynamic array if (g_LoadedModules->Count() == 0) { delete g_LoadedModules; g_LoadedModules = NULL; } return bRemoved; } // LOADEDMODULES::RemoveModuleFromLoadedList
//******************************************************************************* // helper to set type's extends column // // Implements internal API code:IMetaDataEmitHelper::AddInterfaceImpl. //******************************************************************************* HRESULT RegMeta::AddInterfaceImpl( // Return hresult. mdTypeDef td, // [IN] Type definition mdToken tkInterface) // [IN] interface type { HRESULT hr; InterfaceImplRec *pRec; RID ii; LOCKWRITE(); hr = ImportHelper::FindInterfaceImpl(&(m_pStgdb->m_MiniMd), td, tkInterface, (mdInterfaceImpl *)&ii); if (hr == S_OK) goto ErrExit; IfFailGo(m_pStgdb->m_MiniMd.AddInterfaceImplRecord(&pRec, &ii)); IfFailGo(m_pStgdb->m_MiniMd.PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Class, pRec, td)); IfFailGo(m_pStgdb->m_MiniMd.PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Interface, pRec, tkInterface)); ErrExit: return hr; } // RegMeta::AddInterfaceImpl
//******************************************************************************* // helper to define event // // Implements internal API code:IMetaDataEmitHelper::DefineEventHelper. //******************************************************************************* STDMETHODIMP RegMeta::DefineEventHelper( // Return hresult. mdTypeDef td, // [IN] the class/interface on which the event is being defined LPCWSTR szEvent, // [IN] Name of the event DWORD dwEventFlags, // [IN] CorEventAttr mdToken tkEventType, // [IN] a reference (mdTypeRef or mdTypeRef) to the Event class mdEvent *pmdEvent) // [OUT] output event token { HRESULT hr = S_OK; LOG((LOGMD, "MD RegMeta::DefineEventHelper(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n", td, szEvent, dwEventFlags, tkEventType, pmdEvent)); LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); hr = _DefineEvent(td, szEvent, dwEventFlags, tkEventType, pmdEvent); ErrExit: return hr; } // RegMeta::DefineEvent
//******************************************************************************* // Set the specified attributes on the given AssemblyRef token. //******************************************************************************* STDMETHODIMP RegMeta::SetAssemblyRefProps( // S_OK or error. mdAssemblyRef ar, // [IN] AssemblyRefToken. const void *pbPublicKeyOrToken, // [IN] Public key or token of the assembly. ULONG cbPublicKeyOrToken, // [IN] Count of bytes in the public key or token. LPCWSTR szName, // [IN] Name of the assembly being referenced. const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData. const void *pbHashValue, // [IN] Hash Blob. ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob. DWORD dwAssemblyRefFlags) // [IN] Flags. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; _ASSERTE(TypeFromToken(ar) == mdtAssemblyRef && RidFromToken(ar)); LOG((LOGMD, "RegMeta::SetAssemblyRefProps(0x%08x, 0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", ar, pbPublicKeyOrToken, cbPublicKeyOrToken, MDSTR(szName), pMetaData, pbHashValue, cbHashValue, dwAssemblyRefFlags)); START_MD_PERF(); LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); IfFailGo(_SetAssemblyRefProps( ar, pbPublicKeyOrToken, cbPublicKeyOrToken, szName, pMetaData, pbHashValue, cbHashValue, dwAssemblyRefFlags)); ErrExit: STOP_MD_PERF(SetAssemblyRefProps); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::SetAssemblyRefProps
//***************************************************************************** // Add a RegMeta pointer to the loaded module list //***************************************************************************** HRESULT LOADEDMODULES::AddModuleToLoadedList(RegMeta *pRegMeta) { HRESULT hr = NOERROR; RegMeta **ppRegMeta; LOCKWRITE(); // create the dynamic array if it is not created yet. if (g_LoadedModules == NULL) { g_LoadedModules = new LOADEDMODULES; IfNullGo(g_LoadedModules); } ppRegMeta = g_LoadedModules->Append(); IfNullGo(ppRegMeta); *ppRegMeta = pRegMeta; ErrExit: return hr; } // LOADEDMODULES::AddModuleToLoadedList
//--------------------------------------------------------------------------------------- // // Initialize the static instance and lock. // HRESULT LOADEDMODULES::InitializeStatics() { HRESULT hr = S_OK; if (VolatileLoad(&s_pLoadedModules) == NULL) { // Initialize global read-write lock { NewHolder<UTSemReadWrite> pSemReadWrite = new (nothrow) UTSemReadWrite(); IfNullGo(pSemReadWrite); IfFailGo(pSemReadWrite->Init()); if (InterlockedCompareExchangeT<UTSemReadWrite *>(&m_pSemReadWrite, pSemReadWrite, NULL) == NULL) { // We won the initialization race pSemReadWrite.SuppressRelease(); } } // Initialize the global instance { NewHolder<LOADEDMODULES> pLoadedModules = new (nothrow) LOADEDMODULES(); IfNullGo(pLoadedModules); { LOCKWRITE(); if (VolatileLoad(&s_pLoadedModules) == NULL) { VolatileStore(&s_pLoadedModules, pLoadedModules.Extract()); } } } } ErrExit: return hr; } // LOADEDMODULES::InitializeStatics
//***************************************************************************** // Using the existing RegMeta and reopen with another chuck of memory. Make sure that all stgdb // is still kept alive. //***************************************************************************** HRESULT RegMeta::ReOpenWithMemory( LPCVOID pData, // [in] Location of scope data. ULONG cbData, // [in] Size of the data pointed to by pData. DWORD dwReOpenFlags) // [in] ReOpen flags { HRESULT hr = NOERROR; // Only allow the ofCopyMemory and ofTakeOwnership flags if (dwReOpenFlags != 0 && ((dwReOpenFlags & (~(ofCopyMemory|ofTakeOwnership))) > 0)) return E_INVALIDARG; LOCKWRITE(); // put the current m_pStgdb to the free list m_pStgdb->m_pNextStgdb = m_pStgdbFreeList; m_pStgdbFreeList = m_pStgdb; m_pStgdb = new (nothrow) CLiteWeightStgdbRW; IfNullGo( m_pStgdb ); IfFailGo( OpenExistingMD(0 /* szFileName */, const_cast<void*>(pData), cbData, ofReOpen|dwReOpenFlags /* flags */) ); #ifdef FEATURE_METADATA_INTERNAL_APIS // We've created a new Stgdb, but may still have an Internal Importer hanging around accessing the old Stgdb. // The free list ensures we don't have a dangling pointer, but the // If we have a corresponding InternalInterface, need to clear it because it's now using stale data. // Others will need to update their Internal interface to get the new data. { HRESULT hrIgnore = SetCachedInternalInterface(NULL); (void)hrIgnore; //prevent "unused variable" error from GCC _ASSERTE(hrIgnore == NOERROR); // clearing the cached interface should always succeed. } #endif //FEATURE_METADATA_INTERNAL_APIS // we are done! ErrExit: if (FAILED(hr)) { // recover to the old state if (m_pStgdb) delete m_pStgdb; m_pStgdb = m_pStgdbFreeList; m_pStgdbFreeList = m_pStgdbFreeList->m_pNextStgdb; } #ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN else { if( !(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MD_PreserveDebuggerMetadataMemory)) && IsSafeToDeleteStgdb()) { // now that success is assured, delete the old block of memory // This isn't normally a safe operation because we would have given out // internal pointers to the memory. However when this feature is enabled // we track calls that might have given out internal pointers. If none // of the APIs were ever called then we can safely delete. CLiteWeightStgdbRW* pStgdb = m_pStgdbFreeList; m_pStgdbFreeList = m_pStgdbFreeList->m_pNextStgdb; delete pStgdb; } MarkSafeToDeleteStgdb(); // As of right now, no APIs have given out internal pointers // to the newly allocated stgdb } #endif return hr; } // RegMeta::ReOpenWithMemory
//******************************************************************************* // Define an AssemblyRef and set the attributes. //******************************************************************************* STDMETHODIMP RegMeta::DefineAssemblyRef( // S_OK or error. const void *pbPublicKeyOrToken, // [IN] Public key or token of the assembly. ULONG cbPublicKeyOrToken, // [IN] Count of bytes in the public key or token. LPCWSTR szName, // [IN] Name of the assembly being referenced. const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData. const void *pbHashValue, // [IN] Hash Blob. ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob. DWORD dwAssemblyRefFlags, // [IN] Flags. mdAssemblyRef *pmar) // [OUT] Returned AssemblyRef token. { HRESULT hr = S_OK; AssemblyRefRec *pRecord = NULL; ULONG iRecord; if (szName == NULL || pmar == NULL || pMetaData == NULL) return E_INVALIDARG; BEGIN_ENTRYPOINT_NOTHROW; LOG((LOGMD, "RegMeta::DefineAssemblyRef(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", pbPublicKeyOrToken, cbPublicKeyOrToken, MDSTR(szName), pMetaData, pbHashValue, cbHashValue, dwAssemblyRefFlags, pmar)); START_MD_PERF(); LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); _ASSERTE(szName && pmar); if (CheckDups(MDDupAssemblyRef)) { LPUTF8 szUTF8Name, szUTF8Locale; UTF8STR(szName, szUTF8Name); UTF8STR(pMetaData->szLocale, szUTF8Locale); hr = ImportHelper::FindAssemblyRef(&m_pStgdb->m_MiniMd, szUTF8Name, szUTF8Locale, pbPublicKeyOrToken, cbPublicKeyOrToken, pMetaData->usMajorVersion, pMetaData->usMinorVersion, pMetaData->usBuildNumber, pMetaData->usRevisionNumber, dwAssemblyRefFlags, pmar); if (SUCCEEDED(hr)) { if (IsENCOn()) { IfFailGo(m_pStgdb->m_MiniMd.GetAssemblyRefRecord(RidFromToken(*pmar), &pRecord)); } else { hr = META_S_DUPLICATE; goto ErrExit; } } else if (hr != CLDB_E_RECORD_NOTFOUND) { IfFailGo(hr); } } // Create a new record if needed. if (pRecord == NULL) { // Create a new record. IfFailGo(m_pStgdb->m_MiniMd.AddAssemblyRefRecord(&pRecord, &iRecord)); // Set the output parameter. *pmar = TokenFromRid(iRecord, mdtAssemblyRef); } // Set rest of the attributes. SetCallerDefine(); IfFailGo(_SetAssemblyRefProps(*pmar, pbPublicKeyOrToken, cbPublicKeyOrToken, szName, pMetaData, pbHashValue, cbHashValue, dwAssemblyRefFlags)); ErrExit: SetCallerExternal(); STOP_MD_PERF(DefineAssemblyRef); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::DefineAssemblyRef
//***************************************************************************** // translating signature from one scope to another scope // // Implements public API code:IMetaDataEmit::TranslateSigWithScope. // Implements internal API code:IMetaDataHelper::TranslateSigWithScope. //***************************************************************************** STDMETHODIMP RegMeta::TranslateSigWithScope( // S_OK or error. IMetaDataAssemblyImport *pAssemImport, // [IN] importing assembly interface const void *pbHashValue, // [IN] Hash Blob for Assembly. ULONG cbHashValue, // [IN] Count of bytes. IMetaDataImport *pImport, // [IN] importing interface PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope ULONG cbSigBlob, // [IN] count of bytes of signature IMetaDataAssemblyEmit *pAssemEmit,// [IN] emit assembly interface IMetaDataEmit *pEmit, // [IN] emit interface PCOR_SIGNATURE pvTranslatedSig, // [OUT] buffer to hold translated signature ULONG cbTranslatedSigMax, ULONG *pcbTranslatedSig) // [OUT] count of bytes in the translated signature { #ifdef FEATURE_METADATA_EMIT HRESULT hr = S_OK; IMDCommon *pAssemImportMDCommon = NULL; IMDCommon *pImportMDCommon = NULL; BEGIN_ENTRYPOINT_NOTHROW; RegMeta *pRegMetaAssemEmit = static_cast<RegMeta*>(pAssemEmit); RegMeta *pRegMetaEmit = NULL; CQuickBytes qkSigEmit; ULONG cbEmit; pRegMetaEmit = static_cast<RegMeta*>(pEmit); { // This function can cause new TypeRef being introduced. LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); _ASSERTE(pvTranslatedSig && pcbTranslatedSig); if (pAssemImport) { IfFailGo(pAssemImport->QueryInterface(IID_IMDCommon, (void**)&pAssemImportMDCommon)); } IMetaModelCommon *pAssemImportMetaModelCommon = pAssemImportMDCommon ? pAssemImportMDCommon->GetMetaModelCommon() : 0; IfFailGo(pImport->QueryInterface(IID_IMDCommon, (void**)&pImportMDCommon)); IMetaModelCommon *pImportMetaModelCommon = pImportMDCommon->GetMetaModelCommon(); IfFailGo( ImportHelper::MergeUpdateTokenInSig( // S_OK or error. pRegMetaAssemEmit ? &(pRegMetaAssemEmit->m_pStgdb->m_MiniMd) : 0, // The assembly emit scope. &(pRegMetaEmit->m_pStgdb->m_MiniMd), // The emit scope. pAssemImportMetaModelCommon, // Assembly where the signature is from. pbHashValue, // Hash value for the import assembly. cbHashValue, // Size in bytes. pImportMetaModelCommon, // The scope where signature is from. pbSigBlob, // signature from the imported scope NULL, // Internal OID mapping structure. &qkSigEmit, // [OUT] translated signature 0, // start from first byte of the signature 0, // don't care how many bytes consumed &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit memcpy(pvTranslatedSig, qkSigEmit.Ptr(), cbEmit > cbTranslatedSigMax ? cbTranslatedSigMax :cbEmit ); *pcbTranslatedSig = cbEmit; if (cbEmit > cbTranslatedSigMax) hr = CLDB_S_TRUNCATION; } ErrExit: END_ENTRYPOINT_NOTHROW; if (pAssemImportMDCommon) pAssemImportMDCommon->Release(); if (pImportMDCommon) pImportMDCommon->Release(); return hr; #else //!FEATURE_METADATA_EMIT return E_NOTIMPL; #endif //!FEATURE_METADATA_EMIT } // RegMeta::TranslateSigWithScope
//******************************************************************************* // helper to add a declarative security blob to a class or method // // Implements internal API code:IMetaDataEmitHelper::AddDeclarativeSecurityHelper. //******************************************************************************* STDMETHODIMP RegMeta::AddDeclarativeSecurityHelper( mdToken tk, // [IN] Parent token (typedef/methoddef) DWORD dwAction, // [IN] Security action (CorDeclSecurity) void const *pValue, // [IN] Permission set blob DWORD cbValue, // [IN] Byte count of permission set blob mdPermission*pmdPermission) // [OUT] Output permission token { HRESULT hr = S_OK; DeclSecurityRec *pDeclSec = NULL; RID iDeclSec; short sAction = static_cast<short>(dwAction); mdPermission tkPerm; LOG((LOGMD, "MD RegMeta::AddDeclarativeSecurityHelper(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", tk, dwAction, pValue, cbValue, pmdPermission)); LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); _ASSERTE(TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtMethodDef || TypeFromToken(tk) == mdtAssembly); // Check for valid Action. if (sAction == 0 || sAction > dclMaximumValue) IfFailGo(E_INVALIDARG); if (CheckDups(MDDupPermission)) { hr = ImportHelper::FindPermission(&(m_pStgdb->m_MiniMd), tk, sAction, &tkPerm); if (SUCCEEDED(hr)) { // Set output parameter. if (pmdPermission) *pmdPermission = tkPerm; if (IsENCOn()) IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(tkPerm), &pDeclSec)); else { hr = META_S_DUPLICATE; goto ErrExit; } } else if (hr != CLDB_E_RECORD_NOTFOUND) IfFailGo(hr); } // Create a new record. if (!pDeclSec) { IfFailGo(m_pStgdb->m_MiniMd.AddDeclSecurityRecord(&pDeclSec, &iDeclSec)); tkPerm = TokenFromRid(iDeclSec, mdtPermission); // Set output parameter. if (pmdPermission) *pmdPermission = tkPerm; // Save parent and action information. IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_DeclSecurity, DeclSecurityRec::COL_Parent, pDeclSec, tk)); pDeclSec->SetAction(sAction); // Turn on the internal security flag on the parent. if (TypeFromToken(tk) == mdtTypeDef) IfFailGo(_TurnInternalFlagsOn(tk, tdHasSecurity)); else if (TypeFromToken(tk) == mdtMethodDef) IfFailGo(_TurnInternalFlagsOn(tk, mdHasSecurity)); IfFailGo(UpdateENCLog(tk)); } // Write the blob into the record. IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_DeclSecurity, DeclSecurityRec::COL_PermissionSet, pDeclSec, pValue, cbValue)); IfFailGo(UpdateENCLog(tkPerm)); ErrExit: return hr; } // RegMeta::AddDeclarativeSecurityHelper
//******************************************************************************* // Define a File and set the attributes. //******************************************************************************* STDMETHODIMP RegMeta::DefineFile( // S_OK or error. LPCWSTR szName, // [IN] Name of the file. const void *pbHashValue, // [IN] Hash Blob. ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob. DWORD dwFileFlags, // [IN] Flags. mdFile *pmf) // [OUT] Returned File token. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; FileRec *pRecord = NULL; ULONG iRecord; LOG((LOGMD, "RegMeta::DefineFile(%S, %#08x, %#08x, %#08x, %#08x)\n", MDSTR(szName), pbHashValue, cbHashValue, dwFileFlags, pmf)); START_MD_PERF(); LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); _ASSERTE(szName && pmf); if (CheckDups(MDDupFile)) { LPUTF8 szUTF8Name; UTF8STR(szName, szUTF8Name); hr = ImportHelper::FindFile(&m_pStgdb->m_MiniMd, szUTF8Name, pmf); if (SUCCEEDED(hr)) { if (IsENCOn()) { IfFailGo(m_pStgdb->m_MiniMd.GetFileRecord(RidFromToken(*pmf), &pRecord)); } else { hr = META_S_DUPLICATE; goto ErrExit; } } else if (hr != CLDB_E_RECORD_NOTFOUND) { IfFailGo(hr); } } // Create a new record if needed. if (pRecord == NULL) { // Create a new record. IfFailGo(m_pStgdb->m_MiniMd.AddFileRecord(&pRecord, &iRecord)); // Set the output parameter. *pmf = TokenFromRid(iRecord, mdtFile); // Set the name. IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_File, FileRec::COL_Name, pRecord, szName)); } // Set rest of the attributes. IfFailGo(_SetFileProps(*pmf, pbHashValue, cbHashValue, dwFileFlags)); ErrExit: STOP_MD_PERF(DefineFile); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::DefineFile
//******************************************************************************* // Define a ExportedType and set the attributes. //******************************************************************************* STDMETHODIMP RegMeta::DefineExportedType( // S_OK or error. LPCWSTR szName, // [IN] Name of the Com Type. mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the ExportedType. mdTypeDef tkTypeDef, // [IN] TypeDef token within the file. DWORD dwExportedTypeFlags, // [IN] Flags. mdExportedType *pmct) // [OUT] Returned ExportedType token. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; ExportedTypeRec *pRecord = NULL; ULONG iRecord; LPSTR szNameUTF8; LPCSTR szTypeNameUTF8; LPCSTR szTypeNamespaceUTF8; LOG((LOGMD, "RegMeta::DefineExportedType(%S, %#08x, %08x, %#08x, %#08x)\n", MDSTR(szName), tkImplementation, tkTypeDef, dwExportedTypeFlags, pmct)); START_MD_PERF(); LOCKWRITE(); // Validate name for prefix. if (szName == NULL) IfFailGo(E_INVALIDARG); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); //SLASHES2DOTS_NAMESPACE_BUFFER_UNICODE(szName, szName); UTF8STR(szName, szNameUTF8); // Split the name into name/namespace pair. ns::SplitInline(szNameUTF8, szTypeNamespaceUTF8, szTypeNameUTF8); _ASSERTE(szName && dwExportedTypeFlags != ULONG_MAX && pmct); _ASSERTE(TypeFromToken(tkImplementation) == mdtFile || TypeFromToken(tkImplementation) == mdtAssemblyRef || TypeFromToken(tkImplementation) == mdtExportedType || tkImplementation == mdTokenNil); if (CheckDups(MDDupExportedType)) { hr = ImportHelper::FindExportedType(&m_pStgdb->m_MiniMd, szTypeNamespaceUTF8, szTypeNameUTF8, tkImplementation, pmct); if (SUCCEEDED(hr)) { if (IsENCOn()) { IfFailGo(m_pStgdb->m_MiniMd.GetExportedTypeRecord(RidFromToken(*pmct), &pRecord)); } else { hr = META_S_DUPLICATE; goto ErrExit; } } else if (hr != CLDB_E_RECORD_NOTFOUND) { IfFailGo(hr); } } // Create a new record if needed. if (pRecord == NULL) { // Create a new record. IfFailGo(m_pStgdb->m_MiniMd.AddExportedTypeRecord(&pRecord, &iRecord)); // Set the output parameter. *pmct = TokenFromRid(iRecord, mdtExportedType); // Set the TypeName and TypeNamespace. IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_ExportedType, ExportedTypeRec::COL_TypeName, pRecord, szTypeNameUTF8)); if (szTypeNamespaceUTF8) { IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_ExportedType, ExportedTypeRec::COL_TypeNamespace, pRecord, szTypeNamespaceUTF8)); } } // Set rest of the attributes. IfFailGo(_SetExportedTypeProps(*pmct, tkImplementation, tkTypeDef, dwExportedTypeFlags)); ErrExit: STOP_MD_PERF(DefineExportedType); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::DefineExportedType
//******************************************************************************* // Define an Assembly and set the attributes. //******************************************************************************* STDMETHODIMP RegMeta::DefineAssembly( // S_OK or error. const void *pbPublicKey, // [IN] Public key of the assembly. ULONG cbPublicKey, // [IN] Count of bytes in the public key. ULONG ulHashAlgId, // [IN] Hash Algorithm. LPCWSTR szName, // [IN] Name of the assembly. const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData. DWORD dwAssemblyFlags, // [IN] Flags. mdAssembly *pma) // [OUT] Returned Assembly token. { HRESULT hr = S_OK; AssemblyRec *pRecord = NULL; // The assembly record. ULONG iRecord; // RID of the assembly record. if (szName == NULL || pMetaData == NULL || pma == NULL) return E_INVALIDARG; BEGIN_ENTRYPOINT_NOTHROW; LOG((LOGMD, "RegMeta::DefineAssembly(0x%08x, 0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n", pbPublicKey, cbPublicKey, ulHashAlgId, MDSTR(szName), pMetaData, dwAssemblyFlags, pma)); START_MD_PERF(); LOCKWRITE(); _ASSERTE(szName && pMetaData && pma); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); // Assembly defs always contain a full public key (assuming they're strong // named) rather than the tokenized version. Force the flag on to indicate // this, and this way blindly copying public key & flags from a def to a ref // will work (though the ref will be bulkier than strictly necessary). if (cbPublicKey != 0) dwAssemblyFlags |= afPublicKey; if (CheckDups(MDDupAssembly)) { // Should be no more than one -- just check count of records. if (m_pStgdb->m_MiniMd.getCountAssemblys() > 0) { // S/b only one, so we know the rid. iRecord = 1; // If ENC, let them update the existing record. if (IsENCOn()) IfFailGo(m_pStgdb->m_MiniMd.GetAssemblyRecord(iRecord, &pRecord)); else { // Not ENC, so it is a duplicate. *pma = TokenFromRid(iRecord, mdtAssembly); hr = META_S_DUPLICATE; goto ErrExit; } } } else { // Not ENC, not duplicate checking, so shouldn't already have one. _ASSERTE(m_pStgdb->m_MiniMd.getCountAssemblys() == 0); } // Create a new record, if needed. if (pRecord == NULL) { IfFailGo(m_pStgdb->m_MiniMd.AddAssemblyRecord(&pRecord, &iRecord)); } // Set the output parameter. *pma = TokenFromRid(iRecord, mdtAssembly); IfFailGo(_SetAssemblyProps(*pma, pbPublicKey, cbPublicKey, ulHashAlgId, szName, pMetaData, dwAssemblyFlags)); ErrExit: STOP_MD_PERF(DefineAssembly); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::DefineAssembly
//******************************************************************************* // Define a Resource and set the attributes. //******************************************************************************* STDMETHODIMP RegMeta::DefineManifestResource( // S_OK or error. LPCWSTR szName, // [IN] Name of the ManifestResource. mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the resource. DWORD dwOffset, // [IN] Offset to the beginning of the resource within the file. DWORD dwResourceFlags, // [IN] Flags. mdManifestResource *pmmr) // [OUT] Returned ManifestResource token. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; ManifestResourceRec *pRecord = NULL; ULONG iRecord; LOG((LOGMD, "RegMeta::DefineManifestResource(%S, %#08x, %#08x, %#08x, %#08x)\n", MDSTR(szName), tkImplementation, dwOffset, dwResourceFlags, pmmr)); START_MD_PERF(); LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); _ASSERTE(szName && dwResourceFlags != ULONG_MAX && pmmr); _ASSERTE(TypeFromToken(tkImplementation) == mdtFile || TypeFromToken(tkImplementation) == mdtAssemblyRef || tkImplementation == mdTokenNil); if (CheckDups(MDDupManifestResource)) { LPUTF8 szUTF8Name; UTF8STR(szName, szUTF8Name); hr = ImportHelper::FindManifestResource(&m_pStgdb->m_MiniMd, szUTF8Name, pmmr); if (SUCCEEDED(hr)) { if (IsENCOn()) { IfFailGo(m_pStgdb->m_MiniMd.GetManifestResourceRecord(RidFromToken(*pmmr), &pRecord)); } else { hr = META_S_DUPLICATE; goto ErrExit; } } else if (hr != CLDB_E_RECORD_NOTFOUND) { IfFailGo(hr); } } // Create a new record if needed. if (pRecord == NULL) { // Create a new record. IfFailGo(m_pStgdb->m_MiniMd.AddManifestResourceRecord(&pRecord, &iRecord)); // Set the output parameter. *pmmr = TokenFromRid(iRecord, mdtManifestResource); // Set the name. IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_ManifestResource, ManifestResourceRec::COL_Name, pRecord, szName)); } // Set the rest of the attributes. IfFailGo(_SetManifestResourceProps(*pmmr, tkImplementation, dwOffset, dwResourceFlags)); ErrExit: STOP_MD_PERF(DefineManifestResource); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::DefineManifestResource
//***************************************************************************** // Remove a RegMeta pointer from the loaded module list //***************************************************************************** BOOL LOADEDMODULES::RemoveModuleFromLoadedList(RegMeta * pRegMeta) { BOOL bRemoved = FALSE; // Was this module removed from the cache? int iFound = -1; // Index at which it was found. ULONG cRef; // Ref count of the module. // Lock the cache for write, so that no other thread will find what this // thread is about to delete, and so that no other thread will delete // what this thread is about to try to find. HRESULT hr = S_OK; IfFailGo(InitializeStatics()); { LOCKWRITE(); // Search for this module in list of loaded modules. int count = s_pLoadedModules->Count(); for (int index = 0; index < count; index++) { if ((*s_pLoadedModules)[index] == pRegMeta) { // found a match to remove iFound = index; break; } } // If the module is still in the cache, it hasn't been deleted yet. if (iFound >= 0) { // See if there are any external references left. cRef = pRegMeta->GetRefCount(); // If the cRef that we got from the module is zero, it will stay that way, // because no other thread can discover the module while this thread holds // the lock. // OTOH, if the cRef is not zero, this thread can just return, because the // other thread will eventually take the ref count to zero, and will then // come through here to clean up the module. And this thread must not // delete the module out from under other threads. // It is possible that the cRef is zero, yet another thread has a pointer that // it discovered before this thread took the lock. (And that thread has // released the ref-counts.) In such a case, this thread can still remove the // module from the cache, and tell the caller to delete it, because the // other thread will wait on the lock, then discover that the module // is not in the cache, and it won't try to delete the module. if (cRef != 0) { // Some other thread snuck in and found the entry in the cache. return FALSE; } // No other thread owns the object. Remove from cache, and tell caller // that we're done with it. (Caller will delete.) s_pLoadedModules->Delete(iFound); bRemoved = TRUE; // If the module is read-only, remove from hash. if (pRegMeta->IsReadOnly()) { // There may have been multiple capitalizations pointing to the same entry. // Find and remove all of them. for (ULONG ixHash = 0; ixHash < LOADEDMODULES_HASH_SIZE; ++ixHash) { if (m_HashedModules[ixHash] == pRegMeta) m_HashedModules[ixHash] = NULL; } } } } ErrExit: return bRemoved; } // LOADEDMODULES::RemoveModuleFromLoadedList
HRESULT RegMeta::QueryInterface( REFIID riid, void ** ppUnk) { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; int fIsInterfaceRW = false; *ppUnk = 0; if (riid == IID_IUnknown) { *ppUnk = (IUnknown *)(IMetaDataImport2 *)this; } else if (riid == IID_IMDCommon) { *ppUnk = (IMDCommon *)this; } else if (riid == IID_IMetaDataImport) { *ppUnk = (IMetaDataImport2 *)this; } else if (riid == IID_IMetaDataImport2) { *ppUnk = (IMetaDataImport2 *)this; } else if (riid == IID_IMetaDataAssemblyImport) { *ppUnk = (IMetaDataAssemblyImport *)this; } else if (riid == IID_IMetaDataTables) { *ppUnk = static_cast<IMetaDataTables *>(this); } else if (riid == IID_IMetaDataTables2) { *ppUnk = static_cast<IMetaDataTables2 *>(this); } #ifndef FEATURE_METADATA_STANDALONE_WINRT else if (riid == IID_IMetaDataInfo) { *ppUnk = static_cast<IMetaDataInfo *>(this); } #endif //!FEATURE_METADATA_STANDALONE_WINRT #ifdef FEATURE_METADATA_EMIT else if (riid == IID_IMetaDataEmit) { *ppUnk = (IMetaDataEmit2 *)this; fIsInterfaceRW = true; } else if (riid == IID_IMetaDataEmit2) { *ppUnk = (IMetaDataEmit2 *)this; fIsInterfaceRW = true; } else if (riid == IID_IMetaDataAssemblyEmit) { *ppUnk = (IMetaDataAssemblyEmit *)this; fIsInterfaceRW = true; } #endif //FEATURE_METADATA_EMIT #if defined(FEATURE_METADATA_IN_VM) && !defined(FEATURE_CORECLR) else if (riid == IID_IMetaDataValidate) { *ppUnk = (IMetaDataValidate *)this; } #endif //defined(FEATURE_METADATA_IN_VM) && !defined(FEATURE_CORECLR) #ifdef FEATURE_METADATA_EMIT_ALL else if (riid == IID_IMetaDataFilter) { *ppUnk = (IMetaDataFilter *)this; } #endif //FEATURE_METADATA_EMIT_ALL #ifdef FEATURE_METADATA_INTERNAL_APIS else if (riid == IID_IMetaDataHelper) { *ppUnk = (IMetaDataHelper *)this; } else if (riid == IID_IMDInternalEmit) { *ppUnk = static_cast<IMDInternalEmit *>(this); } else if (riid == IID_IGetIMDInternalImport) { *ppUnk = static_cast<IGetIMDInternalImport *>(this); } #endif //FEATURE_METADATA_INTERNAL_APIS #if defined(FEATURE_METADATA_EMIT) && defined(FEATURE_METADATA_INTERNAL_APIS) else if (riid == IID_IMetaDataEmitHelper) { *ppUnk = (IMetaDataEmitHelper *)this; fIsInterfaceRW = true; } #endif //FEATURE_METADATA_EMIT && FEATURE_METADATA_INTERNAL_APIS #ifdef FEATURE_METADATA_IN_VM #ifdef FEATURE_COMINTEROP else if (riid == IID_IMarshal) { // We will only repond to this interface if scope is opened for ReadOnly if (IsOfReadOnly(m_OpenFlags)) { if (m_pFreeThreadedMarshaler == NULL) { // Guard ourselves against first time QI on IMarshal from two different threads.. LOCKWRITE(); if (m_pFreeThreadedMarshaler == NULL) { // First time! Create the FreeThreadedMarshaler IfFailGo(CoCreateFreeThreadedMarshaler((IUnknown *)(IMetaDataEmit2 *)this, &m_pFreeThreadedMarshaler)); } } _ASSERTE(m_pFreeThreadedMarshaler != NULL); IfFailGo(m_pFreeThreadedMarshaler->QueryInterface(riid, ppUnk)); // AddRef has happened in the QueryInterface and thus should just return goto ErrExit; } else { IfFailGo(E_NOINTERFACE); } } #endif // FEATURE_COMINTEROP #ifdef FEATURE_PREJIT else if (riid == IID_IMetaDataCorProfileData) { *ppUnk = (IMetaDataCorProfileData *)this; } else if (riid == IID_IMDInternalMetadataReorderingOptions) { *ppUnk = (IMDInternalMetadataReorderingOptions *)this; } #endif //FEATURE_PREJIT #endif //FEATURE_METADATA_IN_VM else { IfFailGo(E_NOINTERFACE); } if (fIsInterfaceRW && IsOfReadOnly(m_OpenFlags)) { // They are asking for a read/write interface and this scope was // opened as Read-Only *ppUnk = NULL; IfFailGo(CLDB_E_INCOMPATIBLE); } if (fIsInterfaceRW) { LOCKWRITENORET(); if (SUCCEEDED(hr)) { hr = m_pStgdb->m_MiniMd.ConvertToRW(); } if (FAILED(hr)) { *ppUnk = NULL; goto ErrExit; } } AddRef(); ErrExit: END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::QueryInterface