diff options
Diffstat (limited to 'src/md/compiler/import.cpp')
-rw-r--r-- | src/md/compiler/import.cpp | 3809 |
1 files changed, 3809 insertions, 0 deletions
diff --git a/src/md/compiler/import.cpp b/src/md/compiler/import.cpp new file mode 100644 index 0000000000..9d1dfc8116 --- /dev/null +++ b/src/md/compiler/import.cpp @@ -0,0 +1,3809 @@ +// 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. +//***************************************************************************** +// Import.cpp +// + +// +// Methods of code:RegMeta class which implement public API interfaces: +// * code:IMetaDataImport, and +// * code:IMetaDataImport2. +// +//***************************************************************************** +#include "stdafx.h" +#include "regmeta.h" +#include "metadata.h" +#include "corerror.h" +#include "mdutil.h" +#include "rwutil.h" +#include "corpriv.h" +#include "importhelper.h" +#include "mdlog.h" +#include "mdperf.h" +#include "stgio.h" + +//***************************************************************************** +// Enumerate over all the Methods in a TypeDef. +//***************************************************************************** +STDMETHODIMP RegMeta::EnumMembers( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [IN] TypeDef to scope the enumeration. + mdToken rMembers[], // [OUT] Put MemberDefs here. + ULONG cMax, // [IN] Max MemberDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridStartMethod; + ULONG ridEndMethod; + ULONG ridStartField; + ULONG ridEndField; + ULONG index; + ULONG indexField; + TypeDefRec *pRec; + HENUMInternal *pEnum = *ppmdEnum; + + LOG((LOGMD, "MD RegMeta::EnumMembers(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, cl, rMembers, cMax, pcTokens)); + + START_MD_PERF(); + LOCKREAD(); + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + if ( IsGlobalMethodParentTk(cl) ) + { + cl = m_tdModule; + } + + IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(cl), &pRec)); + + ridStartMethod = m_pStgdb->m_MiniMd.getMethodListOfTypeDef(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndMethodListOfTypeDef(RidFromToken(cl), &ridEndMethod)); + + ridStartField = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(cl), &ridEndField)); + + + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMethodDef, &pEnum) ); + + // add all methods to the dynamic array + for (index = ridStartMethod; index < ridEndMethod; index++ ) + { + RID rid; + IfFailGo(pMiniMd->GetMethodRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtMethodDef))); + } + + // add all fields to the dynamic array + for (indexField = ridStartField; indexField < ridEndField; indexField++ ) + { + RID rid; + IfFailGo(pMiniMd->GetFieldRid(indexField, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtFieldDef))); + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMembers, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumMembers); + + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumMembers() + +//***************************************************************************** +// Enumerate over all the Methods in a TypeDef that has szName +//***************************************************************************** +STDMETHODIMP RegMeta::EnumMembersWithName( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [IN] TypeDef to scope the enumeration. + LPCWSTR szName, // [IN] Limit results to those with this name. + mdToken rMembers[], // [OUT] Put MemberDefs here. + ULONG cMax, // [IN] Max MemberDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridStart; + ULONG ridEnd; + ULONG index; + TypeDefRec *pRec; + MethodRec *pMethod; + FieldRec *pField; + HENUMInternal *pEnum = *ppmdEnum; + LPUTF8 szNameUtf8; + UTF8STR(szName, szNameUtf8); + LPCUTF8 szNameUtf8Tmp; + + LOG((LOGMD, "MD RegMeta::EnumMembersWithName(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, cl, MDSTR(szName), rMembers, cMax, pcTokens)); + + START_MD_PERF(); + LOCKREAD(); + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + // create the enumerator + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMethodDef, &pEnum) ); + + if ( IsGlobalMethodParentTk(cl) ) + { + cl = m_tdModule; + } + + // get the range of method rids given a typedef + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(cl), &pRec)); + ridStart = pMiniMd->getMethodListOfTypeDef(pRec); + IfFailGo(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(cl), &ridEnd)); + + for (index = ridStart; index < ridEnd; index++ ) + { + if (szNameUtf8 == NULL) + { + RID rid; + IfFailGo(pMiniMd->GetMethodRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtMethodDef))); + } + else + { + RID rid; + IfFailGo(pMiniMd->GetMethodRid(index, &rid)); + IfFailGo(pMiniMd->GetMethodRecord(rid, &pMethod)); + IfFailGo(pMiniMd->getNameOfMethod(pMethod, &szNameUtf8Tmp)); + if ( strcmp(szNameUtf8Tmp, szNameUtf8) == 0 ) + { + IfFailGo(pMiniMd->GetMethodRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(rid, mdtMethodDef))); + } + } + } + + ridStart = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(cl), &ridEnd)); + + for (index = ridStart; index < ridEnd; index++ ) + { + if (szNameUtf8 == NULL) + { + RID rid; + IfFailGo(pMiniMd->GetFieldRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(rid, mdtFieldDef))); + } + else + { + RID rid; + IfFailGo(pMiniMd->GetFieldRid(index, &rid)); + IfFailGo(pMiniMd->GetFieldRecord(rid, &pField)); + IfFailGo(pMiniMd->getNameOfField(pField, &szNameUtf8Tmp)); + if ( strcmp(szNameUtf8Tmp, szNameUtf8) == 0 ) + { + IfFailGo(pMiniMd->GetFieldRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtFieldDef))); + } + } + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMembers, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumMembersWithName); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumMembersWithName() + +//***************************************************************************** +// enumerating through methods given a Typedef and the flag +//***************************************************************************** +STDMETHODIMP RegMeta::EnumMethods( + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef td, // [IN] TypeDef to scope the enumeration. + mdMethodDef rMethods[], // [OUT] Put MethodDefs here. + ULONG cMax, // [IN] Max MethodDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridStart; + ULONG ridEnd; + TypeDefRec *pRec; + HENUMInternal *pEnum = *ppmdEnum; + + LOG((LOGMD, "MD RegMeta::EnumMethods(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, td, rMethods, cMax, pcTokens)); + + + + START_MD_PERF(); + LOCKREAD(); + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + // Check for mdTypeDefNil (representing <Module>). + // If so, this will map it to its token. + // + if ( IsGlobalMethodParentTk(td) ) + { + td = m_tdModule; + } + + IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pRec)); + ridStart = m_pStgdb->m_MiniMd.getMethodListOfTypeDef(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndMethodListOfTypeDef(RidFromToken(td), &ridEnd)); + + if (pMiniMd->HasIndirectTable(TBL_Method) || pMiniMd->HasDelete()) + { + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMethodDef, &pEnum) ); + + // add all methods to the dynamic array + for (ULONG index = ridStart; index < ridEnd; index++ ) + { + if (pMiniMd->HasDelete() && + ((m_OptionValue.m_ImportOption & MDImportOptionAllMethodDefs) == 0)) + { + MethodRec *pMethRec; + RID rid; + IfFailGo(pMiniMd->GetMethodRid(index, &rid)); + IfFailGo(pMiniMd->GetMethodRecord(rid, &pMethRec)); + LPCSTR szMethodName; + IfFailGo(pMiniMd->getNameOfMethod(pMethRec, &szMethodName)); + if (IsMdRTSpecialName(pMethRec->GetFlags()) && IsDeletedName(szMethodName) ) + { + continue; + } + } + RID rid; + IfFailGo(pMiniMd->GetMethodRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtMethodDef))); + } + } + else + { + IfFailGo( HENUMInternal::CreateSimpleEnum( mdtMethodDef, ridStart, ridEnd, &pEnum) ); + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMethods, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumMethods); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumMethods() + + + + +//***************************************************************************** +// Enumerate over all the methods with szName in a TypeDef. +//***************************************************************************** +STDMETHODIMP RegMeta::EnumMethodsWithName( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [IN] TypeDef to scope the enumeration. + LPCWSTR szName, // [IN] Limit results to those with this name. + mdMethodDef rMethods[], // [OU] Put MethodDefs here. + ULONG cMax, // [IN] Max MethodDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridStart; + ULONG ridEnd; + ULONG index; + TypeDefRec *pRec; + MethodRec *pMethod; + HENUMInternal *pEnum = *ppmdEnum; + LPUTF8 szNameUtf8; + UTF8STR(szName, szNameUtf8); + LPCUTF8 szNameUtf8Tmp; + + LOG((LOGMD, "MD RegMeta::EnumMethodsWithName(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, cl, MDSTR(szName), rMethods, cMax, pcTokens)); + + + + START_MD_PERF(); + LOCKREAD(); + + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + // Check for mdTypeDefNil (representing <Module>). + // If so, this will map it to its token. + // + if ( IsGlobalMethodParentTk(cl) ) + { + cl = m_tdModule; + } + + + // create the enumerator + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMethodDef, &pEnum) ); + + // get the range of method rids given a typedef + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(cl), &pRec)); + ridStart = pMiniMd->getMethodListOfTypeDef(pRec); + IfFailGo(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(cl), &ridEnd)); + + for (index = ridStart; index < ridEnd; index++ ) + { + if ( szNameUtf8 == NULL ) + { + RID rid; + IfFailGo(pMiniMd->GetMethodRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtMethodDef))); + } + else + { + RID rid; + IfFailGo(pMiniMd->GetMethodRid(index, &rid)); + IfFailGo(pMiniMd->GetMethodRecord(rid, &pMethod)); + IfFailGo(pMiniMd->getNameOfMethod(pMethod, &szNameUtf8Tmp)); + if ( strcmp(szNameUtf8Tmp, szNameUtf8) == 0 ) + { + IfFailGo(pMiniMd->GetMethodRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtMethodDef))); + } + } + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMethods, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumMethodsWithName); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumMethodsWithName() + + + +//***************************************************************************** +// Enumerate over all the fields in a TypeDef and a flag. +//***************************************************************************** +STDMETHODIMP +RegMeta::EnumFields( + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef td, // [IN] TypeDef to scope the enumeration. + mdFieldDef rFields[], // [OUT] Put FieldDefs here. + ULONG cMax, // [IN] Max FieldDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **>(phEnum); + ULONG ridStart; + ULONG ridEnd; + TypeDefRec *pRec; + HENUMInternal *pEnum = *ppmdEnum; + + LOG((LOGMD, "MD RegMeta::EnumFields(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, td, rFields, cMax, pcTokens)); + + START_MD_PERF(); + LOCKREAD(); + + if (pEnum == NULL) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + // Check for mdTypeDefNil (representing <Module>). + // If so, this will map it to its token. + // + if (IsGlobalMethodParentTk(td)) + { + td = m_tdModule; + } + + IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pRec)); + ridStart = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(td), &ridEnd)); + + if (pMiniMd->HasIndirectTable(TBL_Field) || pMiniMd->HasDelete()) + { + IfFailGo(HENUMInternal::CreateDynamicArrayEnum(mdtFieldDef, &pEnum)); + + // add all methods to the dynamic array + for (ULONG index = ridStart; index < ridEnd; index++) + { + if (pMiniMd->HasDelete() && + ((m_OptionValue.m_ImportOption & MDImportOptionAllFieldDefs) == 0)) + { + FieldRec *pFieldRec; + RID rid; + IfFailGo(pMiniMd->GetFieldRid(index, &rid)); + IfFailGo(pMiniMd->GetFieldRecord(rid, &pFieldRec)); + LPCUTF8 szFieldName; + IfFailGo(pMiniMd->getNameOfField(pFieldRec, &szFieldName)); + if (IsFdRTSpecialName(pFieldRec->GetFlags()) && IsDeletedName(szFieldName)) + { + continue; + } + } + RID rid; + IfFailGo(pMiniMd->GetFieldRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtFieldDef))); + } + } + else + { + IfFailGo(HENUMInternal::CreateSimpleEnum(mdtFieldDef, ridStart, ridEnd, &pEnum)); + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rFields, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumFields); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // RegMeta::EnumFields + + + +//***************************************************************************** +// Enumerate over all the fields with szName in a TypeDef. +//***************************************************************************** +STDMETHODIMP RegMeta::EnumFieldsWithName( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [IN] TypeDef to scope the enumeration. + LPCWSTR szName, // [IN] Limit results to those with this name. + mdFieldDef rFields[], // [OUT] Put MemberDefs here. + ULONG cMax, // [IN] Max MemberDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridStart; + ULONG ridEnd; + ULONG index; + TypeDefRec *pRec; + FieldRec *pField; + HENUMInternal *pEnum = *ppmdEnum; + LPUTF8 szNameUtf8; + UTF8STR(szName, szNameUtf8); + LPCUTF8 szNameUtf8Tmp; + + LOG((LOGMD, "MD RegMeta::EnumFields(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, cl, MDSTR(szName), rFields, cMax, pcTokens)); + + + + START_MD_PERF(); + LOCKREAD(); + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + // Check for mdTypeDefNil (representing <Module>). + // If so, this will map it to its token. + // + if ( IsGlobalMethodParentTk(cl) ) + { + cl = m_tdModule; + } + + // create the enumerator + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMethodDef, &pEnum) ); + + // get the range of field rids given a typedef + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(cl), &pRec)); + ridStart = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(cl), &ridEnd)); + + for (index = ridStart; index < ridEnd; index++ ) + { + if ( szNameUtf8 == NULL ) + { + RID rid; + IfFailGo(pMiniMd->GetFieldRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtFieldDef))); + } + else + { + RID rid; + IfFailGo(pMiniMd->GetFieldRid(index, &rid)); + IfFailGo(pMiniMd->GetFieldRecord(rid, &pField)); + IfFailGo(pMiniMd->getNameOfField(pField, &szNameUtf8Tmp)); + if ( strcmp(szNameUtf8Tmp, szNameUtf8) == 0 ) + { + IfFailGo(pMiniMd->GetFieldRid(index, &rid)); + IfFailGo( HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtFieldDef) ) ); + } + } + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rFields, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumFieldsWithName); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumFieldsWithName() + + +//***************************************************************************** +// Enumerate over the ParamDefs in a Method. +//***************************************************************************** +STDMETHODIMP RegMeta::EnumParams( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdMethodDef mb, // [IN] MethodDef to scope the enumeration. + mdParamDef rParams[], // [OUT] Put ParamDefs here. + ULONG cMax, // [IN] Max ParamDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridStart; + ULONG ridEnd; + MethodRec *pRec; + HENUMInternal *pEnum = *ppmdEnum; + + LOG((LOGMD, "MD RegMeta::EnumParams(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, mb, rParams, cMax, pcTokens)); + START_MD_PERF(); + LOCKREAD(); + + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(mb), &pRec)); + ridStart = m_pStgdb->m_MiniMd.getParamListOfMethod(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndParamListOfMethod(RidFromToken(mb), &ridEnd)); + + if (pMiniMd->HasIndirectTable(TBL_Param)) + { + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtParamDef, &pEnum) ); + + // add all methods to the dynamic array + for (ULONG index = ridStart; index < ridEnd; index++ ) + { + RID rid; + IfFailGo(pMiniMd->GetParamRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtParamDef))); + } + } + else + { + IfFailGo( HENUMInternal::CreateSimpleEnum( mdtParamDef, ridStart, ridEnd, &pEnum) ); + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rParams, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumParams); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumParams() + + + +//***************************************************************************** +// Enumerate the MemberRefs given the parent token. +//***************************************************************************** +STDMETHODIMP RegMeta::EnumMemberRefs( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdToken tkParent, // [IN] Parent token to scope the enumeration. + mdMemberRef rMemberRefs[], // [OUT] Put MemberRefs here. + ULONG cMax, // [IN] Max MemberRefs to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridEnd; + ULONG index; + MemberRefRec *pRec; + HENUMInternal *pEnum = *ppmdEnum; + + LOG((LOGMD, "MD RegMeta::EnumMemberRefs(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, tkParent, rMemberRefs, cMax, pcTokens)); + + + + START_MD_PERF(); + LOCKREAD(); + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + mdToken tk; + + // Check for mdTypeDefNil (representing <Module>). + // If so, this will map it to its token. + // + IsGlobalMethodParent(&tkParent); + + // create the enumerator + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMemberRef, &pEnum) ); + + // get the range of field rids given a typedef + ridEnd = pMiniMd->getCountMemberRefs(); + + for (index = 1; index <= ridEnd; index++ ) + { + IfFailGo(pMiniMd->GetMemberRefRecord(index, &pRec)); + tk = pMiniMd->getClassOfMemberRef(pRec); + if ( tk == tkParent ) + { + // add the matched ones to the enumerator + IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtMemberRef) ) ); + } + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMemberRefs, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumMemberRefs); + + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumMemberRefs() + + +//***************************************************************************** +// Enumerate methodimpls given a typedef +//***************************************************************************** +STDMETHODIMP RegMeta::EnumMethodImpls( // S_OK, S_FALSE, or error + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef td, // [IN] TypeDef to scope the enumeration. + mdToken rMethodBody[], // [OUT] Put Method Body tokens here. + mdToken rMethodDecl[], // [OUT] Put Method Declaration tokens here. + ULONG cMax, // [IN] Max tokens to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + MethodImplRec *pRec; + HENUMInternal *pEnum = *ppmdEnum; + HENUMInternal hEnum; + + + LOG((LOGMD, "MD RegMeta::EnumMethodImpls(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, td, rMethodBody, rMethodDecl, cMax, pcTokens)); + + + + START_MD_PERF(); + LOCKREAD(); + + memset(&hEnum, 0, sizeof(HENUMInternal)); + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + mdToken tkMethodBody; + mdToken tkMethodDecl; + RID ridCur; + + // Get the range of rids. + IfFailGo( pMiniMd->FindMethodImplHelper(td, &hEnum) ); + + // Create the enumerator, DynamicArrayEnum does not use the token type. + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( (TBL_MethodImpl << 24), &pEnum) ); + + while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur)) + { + // Get the MethodBody and MethodDeclaration tokens for the current + // MethodImpl record. + IfFailGo(pMiniMd->GetMethodImplRecord(ridCur, &pRec)); + tkMethodBody = pMiniMd->getMethodBodyOfMethodImpl(pRec); + tkMethodDecl = pMiniMd->getMethodDeclarationOfMethodImpl(pRec); + + // Add the Method body/declaration pairs to the Enum + IfFailGo( HENUMInternal::AddElementToEnum(pEnum, tkMethodBody ) ); + IfFailGo( HENUMInternal::AddElementToEnum(pEnum, tkMethodDecl ) ); + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMethodBody, rMethodDecl, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + HENUMInternal::ClearEnum(&hEnum); + + STOP_MD_PERF(EnumMethodImpls); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumMethodImpls() + + +//***************************************************************************** +// Enumerate over PermissionSets. Optionally limit to an object and/or an +// action. +//***************************************************************************** +STDMETHODIMP RegMeta::EnumPermissionSets( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdToken tk, // [IN] if !NIL, token to scope the enumeration. + DWORD dwActions, // [IN] if !0, return only these actions. + mdPermission rPermission[], // [OUT] Put Permissions here. + ULONG cMax, // [IN] Max Permissions to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridStart; + ULONG ridEnd; + ULONG index; + DeclSecurityRec *pRec; + HENUMInternal *pEnum = *ppmdEnum; + bool fCompareParent = false; + mdToken typ = TypeFromToken(tk); + mdToken tkParent; + + LOG((LOGMD, "MD RegMeta::EnumPermissionSets(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, tk, dwActions, rPermission, cMax, pcTokens)); + + START_MD_PERF(); + LOCKREAD(); + + if ( pEnum == 0 ) + { + // Does this token type even have security? + if (tk != 0 && + !(typ == mdtTypeDef || typ == mdtMethodDef || typ == mdtAssembly)) + { + if (pcTokens) + *pcTokens = 0; + hr = S_FALSE; + goto ErrExit; + } + + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + if (!IsNilToken(tk)) + { + // parent is provided for lookup + if ( pMiniMd->IsSorted( TBL_DeclSecurity ) ) + { + IfFailGo(pMiniMd->getDeclSecurityForToken(tk, &ridEnd, &ridStart)); + } + else + { + // table is not sorted. So we have to do a table scan + ridStart = 1; + ridEnd = pMiniMd->getCountDeclSecuritys() + 1; + fCompareParent = true; + } + } + else + { + ridStart = 1; + ridEnd = pMiniMd->getCountDeclSecuritys() + 1; + } + + if (IsDclActionNil(dwActions) && !fCompareParent && !m_pStgdb->m_MiniMd.HasDelete()) + { + // create simple enumerator + IfFailGo( HENUMInternal::CreateSimpleEnum( mdtPermission, ridStart, ridEnd, &pEnum) ); + } + else + { + // create the dynamic enumerator + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtPermission, &pEnum) ); + + for (index = ridStart; index < ridEnd; index++ ) + { + IfFailGo(pMiniMd->GetDeclSecurityRecord(index, &pRec)); + tkParent = pMiniMd->getParentOfDeclSecurity(pRec); + if ( (fCompareParent && tk != tkParent) || + IsNilToken(tkParent) ) + { + // We need to compare parent token and they are not equal so skip + // over this row. + // + continue; + } + if ( IsDclActionNil(dwActions) || + ( (DWORD)(pMiniMd->getActionOfDeclSecurity(pRec))) == dwActions ) + { + // If we don't need to compare the action, just add to the enum. + // Or we need to compare the action and the action values are equal, add to enum as well. + // + IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtPermission) ) ); + } + } + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rPermission, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumPermissionSets); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumPermissionSets() + + +//***************************************************************************** +// Find a given member in a TypeDef (typically a class). +//***************************************************************************** +STDMETHODIMP RegMeta::FindMember( + mdTypeDef td, // [IN] given typedef + LPCWSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdToken *pmb) // [OUT] matching memberdef +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + + LOG((LOGMD, "MD RegMeta::FindMember(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n", + td, MDSTR(szName), pvSigBlob, cbSigBlob, pmb)); + + START_MD_PERF(); + + // Don't lock this function. All of the functions that it calls are public APIs. keep it that way. + + // try to match with method first of all + hr = FindMethod( + td, + szName, + pvSigBlob, + cbSigBlob, + pmb); + + if ( hr == CLDB_E_RECORD_NOTFOUND ) + { + // now try field table + IfFailGo( FindField( + td, + szName, + pvSigBlob, + cbSigBlob, + pmb) ); + } +ErrExit: + STOP_MD_PERF(FindMember); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::FindMember() + + + +//***************************************************************************** +// Find a given member in a TypeDef (typically a class). +//***************************************************************************** +STDMETHODIMP RegMeta::FindMethod( + mdTypeDef td, // [IN] given typedef + LPCWSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdMethodDef *pmb) // [OUT] matching memberdef +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + LPUTF8 szNameUtf8; + UTF8STR(szName, szNameUtf8); + + LOG((LOGMD, "MD RegMeta::FindMethod(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n", + td, MDSTR(szName), pvSigBlob, cbSigBlob, pmb)); + + START_MD_PERF(); + LOCKREAD(); + + if (szName == NULL) + IfFailGo(E_INVALIDARG); + PREFIX_ASSUME(szName != NULL); + + // If this is a global method, then use the <Module> typedef as parent. + IsGlobalMethodParent(&td); + + IfFailGo(ImportHelper::FindMethod(pMiniMd, + td, + szNameUtf8, + pvSigBlob, + cbSigBlob, + pmb)); + +ErrExit: + STOP_MD_PERF(FindMethod); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // RegMeta::FindMethod + + +//***************************************************************************** +// Find a given member in a TypeDef (typically a class). +//***************************************************************************** +STDMETHODIMP +RegMeta::FindField( + mdTypeDef td, // [IN] given typedef + LPCWSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdFieldDef *pmb) // [OUT] matching memberdef +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + LOG((LOGMD, "MD RegMeta::FindField(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n", + td, MDSTR(szName), pvSigBlob, cbSigBlob, pmb)); + + START_MD_PERF(); + LOCKREAD(); + + if (szName == NULL) + IfFailGo(E_INVALIDARG); + + LPUTF8 szNameUtf8; + UTF8STR(szName, szNameUtf8); + + // If this is a global method, then use the <Module> typedef as parent. + IsGlobalMethodParent(&td); + + IfFailGo(ImportHelper::FindField(pMiniMd, + td, + szNameUtf8, + pvSigBlob, + cbSigBlob, + pmb)); + +ErrExit: + STOP_MD_PERF(FindField); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // RegMeta::FindField + + +//***************************************************************************** +// Find a given MemberRef in a TypeRef (typically a class). If no TypeRef +// is specified, the query will be for a random member in the scope. +//***************************************************************************** +STDMETHODIMP RegMeta::FindMemberRef( + mdToken tkPar, // [IN] given parent token. + LPCWSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdMemberRef *pmr) // [OUT] matching memberref +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + LPUTF8 szNameUtf8; + UTF8STR(szName, szNameUtf8); + + LOG((LOGMD, "MD RegMeta::FindMemberRef(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n", + tkPar, MDSTR(szName), pvSigBlob, cbSigBlob, pmr)); + + + + START_MD_PERF(); + + // <TODO>@todo: Can this causing building hash table? If so, should this consider the write lock?</TODO> + LOCKREAD(); + + // get the range of field rids given a typedef + _ASSERTE(TypeFromToken(tkPar) == mdtTypeRef || TypeFromToken(tkPar) == mdtMethodDef || + TypeFromToken(tkPar) == mdtModuleRef || TypeFromToken(tkPar) == mdtTypeDef || + TypeFromToken(tkPar) == mdtTypeSpec); + + // Set parent to global class m_tdModule if mdTokenNil is passed. + if (IsNilToken(tkPar)) + tkPar = m_tdModule; + + IfFailGo( ImportHelper::FindMemberRef(pMiniMd, tkPar, szNameUtf8, pvSigBlob, cbSigBlob, pmr) ); + +ErrExit: + + STOP_MD_PERF(FindMemberRef); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::FindMemberRef() + + +//***************************************************************************** +// Return the property of a MethodDef +//***************************************************************************** +STDMETHODIMP RegMeta::GetMethodProps( + mdMethodDef mb, // The method for which to get props. + mdTypeDef *pClass, // Put method's class here. + __out_ecount_opt (cchMethod) LPWSTR szMethod, // Put method's name here. + ULONG cchMethod, // Size of szMethod buffer in wide chars. + ULONG *pchMethod, // Put actual size here + DWORD *pdwAttr, // Put flags here. + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data + ULONG *pcbSigBlob, // [OUT] actual size of signature blob + ULONG *pulCodeRVA, // [OUT] codeRVA + DWORD *pdwImplFlags) // [OUT] Impl. Flags +{ + HRESULT hr = NOERROR; + BEGIN_ENTRYPOINT_NOTHROW; + + MethodRec *pMethodRec; + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + LOG((LOGMD, "MD RegMeta::GetMethodProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + mb, pClass, szMethod, cchMethod, pchMethod, pdwAttr, ppvSigBlob, pcbSigBlob, + pulCodeRVA, pdwImplFlags)); + + + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(mb) == mdtMethodDef); + + IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(mb), &pMethodRec)); + + if (pClass) + { + // caller wants parent typedef + IfFailGo( pMiniMd->FindParentOfMethodHelper(mb, pClass) ); + + if ( IsGlobalMethodParentToken(*pClass) ) + { + // If the parent of Method is the <Module>, return mdTypeDefNil instead. + *pClass = mdTypeDefNil; + } + + } + if (ppvSigBlob || pcbSigBlob) + { + // caller wants signature information + PCCOR_SIGNATURE pvSigTmp; + ULONG cbSig; + IfFailGo(pMiniMd->getSignatureOfMethod(pMethodRec, &pvSigTmp, &cbSig)); + if ( ppvSigBlob ) + *ppvSigBlob = pvSigTmp; + if ( pcbSigBlob) + *pcbSigBlob = cbSig; + } + if ( pdwAttr ) + { + *pdwAttr = pMiniMd->getFlagsOfMethod(pMethodRec); + } + if ( pulCodeRVA ) + { + *pulCodeRVA = pMiniMd->getRVAOfMethod(pMethodRec); + } + if ( pdwImplFlags ) + { + *pdwImplFlags = (DWORD )pMiniMd->getImplFlagsOfMethod(pMethodRec); + } + // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK + if (szMethod || pchMethod) + { + IfFailGo( pMiniMd->getNameOfMethod(pMethodRec, szMethod, cchMethod, pchMethod) ); + } + +ErrExit: + STOP_MD_PERF(GetMethodProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::GetMethodProps() + + +//***************************************************************************** +// Return the property of a MemberRef +//***************************************************************************** +STDMETHODIMP RegMeta::GetMemberRefProps( // S_OK or error. + mdMemberRef mr, // [IN] given memberref + mdToken *ptk, // [OUT] Put classref or classdef here. + __out_ecount_opt (cchMember) LPWSTR szMember, // [OUT] buffer to fill for member's name + ULONG cchMember, // [IN] the count of char of szMember + ULONG *pchMember, // [OUT] actual count of char in member name + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to meta data blob value + ULONG *pbSig) // [OUT] actual size of signature blob +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + MemberRefRec *pMemberRefRec; + + LOG((LOGMD, "MD RegMeta::GetMemberRefProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + mr, ptk, szMember, cchMember, pchMember, ppvSigBlob, pbSig)); + + + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(mr) == mdtMemberRef); + + IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(mr), &pMemberRefRec)); + + if (ptk) + { + *ptk = pMiniMd->getClassOfMemberRef(pMemberRefRec); + if ( IsGlobalMethodParentToken(*ptk) ) + { + // If the parent of MemberRef is the <Module>, return mdTypeDefNil instead. + *ptk = mdTypeDefNil; + } + + } + if (ppvSigBlob || pbSig) + { + // caller wants signature information + PCCOR_SIGNATURE pvSigTmp; + ULONG cbSig; + IfFailGo(pMiniMd->getSignatureOfMemberRef(pMemberRefRec, &pvSigTmp, &cbSig)); + if ( ppvSigBlob ) + *ppvSigBlob = pvSigTmp; + if ( pbSig) + *pbSig = cbSig; + } + // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK + if (szMember || pchMember) + { + IfFailGo( pMiniMd->getNameOfMemberRef(pMemberRefRec, szMember, cchMember, pchMember) ); + } + +ErrExit: + + STOP_MD_PERF(GetMemberRefProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::GetMemberRefProps() + + +//***************************************************************************** +// enumerate Property tokens for a typedef +//***************************************************************************** +STDMETHODIMP RegMeta::EnumProperties( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef td, // [IN] TypeDef to scope the enumeration. + mdProperty rProperties[], // [OUT] Put Properties here. + ULONG cMax, // [IN] Max properties to put. + ULONG *pcProperties) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridStart = 0; + ULONG ridEnd = 0; + ULONG ridMax = 0; + HENUMInternal *pEnum = *ppmdEnum; + + LOG((LOGMD, "MD RegMeta::EnumProperties(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, td, rProperties, cMax, pcProperties)); + + START_MD_PERF(); + LOCKREAD(); + + if (IsNilToken(td)) + { + if (pcProperties) + *pcProperties = 0; + hr = S_FALSE; + goto ErrExit; + } + + _ASSERTE(TypeFromToken(td) == mdtTypeDef); + + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + RID ridPropertyMap; + PropertyMapRec *pPropertyMapRec; + + // get the starting/ending rid of properties of this typedef + IfFailGo(pMiniMd->FindPropertyMapFor(RidFromToken(td), &ridPropertyMap)); + if (!InvalidRid(ridPropertyMap)) + { + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec)); + ridStart = pMiniMd->getPropertyListOfPropertyMap(pPropertyMapRec); + IfFailGo(pMiniMd->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd)); + ridMax = pMiniMd->getCountPropertys() + 1; + if(ridStart == 0) ridStart = 1; + if(ridEnd > ridMax) ridEnd = ridMax; + if(ridStart > ridEnd) ridStart=ridEnd; + } + + if (pMiniMd->HasIndirectTable(TBL_Property) || pMiniMd->HasDelete()) + { + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtProperty, &pEnum) ); + + // add all methods to the dynamic array + for (ULONG index = ridStart; index < ridEnd; index++ ) + { + if (pMiniMd->HasDelete() && + ((m_OptionValue.m_ImportOption & MDImportOptionAllProperties) == 0)) + { + PropertyRec *pRec; + RID rid; + IfFailGo(pMiniMd->GetPropertyRid(index, &rid)); + IfFailGo(pMiniMd->GetPropertyRecord(rid, &pRec)); + LPCUTF8 szPropertyName; + IfFailGo(pMiniMd->getNameOfProperty(pRec, &szPropertyName)); + if (IsPrRTSpecialName(pRec->GetPropFlags()) && IsDeletedName(szPropertyName)) + { + continue; + } + } + RID rid; + IfFailGo(pMiniMd->GetPropertyRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtProperty))); + } + } + else + { + IfFailGo( HENUMInternal::CreateSimpleEnum( mdtProperty, ridStart, ridEnd, &pEnum) ); + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rProperties, pcProperties); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + + STOP_MD_PERF(EnumProperties); + END_ENTRYPOINT_NOTHROW; + + return hr; + +} // STDMETHODIMP RegMeta::EnumProperties() + + +//***************************************************************************** +// enumerate event tokens for a typedef +//***************************************************************************** +STDMETHODIMP RegMeta::EnumEvents( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef td, // [IN] TypeDef to scope the enumeration. + mdEvent rEvents[], // [OUT] Put events here. + ULONG cMax, // [IN] Max events to put. + ULONG *pcEvents) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridStart = 0; + ULONG ridEnd = 0; + ULONG ridMax = 0; + HENUMInternal *pEnum = *ppmdEnum; + + LOG((LOGMD, "MD RegMeta::EnumEvents(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, td, rEvents, cMax, pcEvents)); + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(td) == mdtTypeDef); + + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + RID ridEventMap; + EventMapRec *pEventMapRec; + + // get the starting/ending rid of properties of this typedef + IfFailGo(pMiniMd->FindEventMapFor(RidFromToken(td), &ridEventMap)); + if (!InvalidRid(ridEventMap)) + { + IfFailGo(pMiniMd->GetEventMapRecord(ridEventMap, &pEventMapRec)); + ridStart = pMiniMd->getEventListOfEventMap(pEventMapRec); + IfFailGo(pMiniMd->getEndEventListOfEventMap(ridEventMap, &ridEnd)); + ridMax = pMiniMd->getCountEvents() + 1; + if(ridStart == 0) ridStart = 1; + if(ridEnd > ridMax) ridEnd = ridMax; + if(ridStart > ridEnd) ridStart=ridEnd; + } + + if (pMiniMd->HasIndirectTable(TBL_Event) || pMiniMd->HasDelete()) + { + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtEvent, &pEnum) ); + + // add all methods to the dynamic array + for (ULONG index = ridStart; index < ridEnd; index++ ) + { + if (pMiniMd->HasDelete() && + ((m_OptionValue.m_ImportOption & MDImportOptionAllEvents) == 0)) + { + EventRec *pRec; + RID rid; + IfFailGo(pMiniMd->GetEventRid(index, &rid)); + IfFailGo(pMiniMd->GetEventRecord(rid, &pRec)); + LPCSTR szEventName; + IfFailGo(pMiniMd->getNameOfEvent(pRec, &szEventName)); + if (IsEvRTSpecialName(pRec->GetEventFlags()) && IsDeletedName(szEventName)) + { + continue; + } + } + RID rid; + IfFailGo(pMiniMd->GetEventRid(index, &rid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(rid, mdtEvent))); + } + } + else + { + IfFailGo( HENUMInternal::CreateSimpleEnum( mdtEvent, ridStart, ridEnd, &pEnum) ); + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rEvents, pcEvents); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + + STOP_MD_PERF(EnumEvents); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumEvents() + + + +//***************************************************************************** +// return the properties of an event token +//***************************************************************************** +STDMETHODIMP RegMeta::GetEventProps( // S_OK, S_FALSE, or error. + mdEvent ev, // [IN] event token + mdTypeDef *pClass, // [OUT] typedef containing the event declarion. + LPCWSTR szEvent, // [OUT] Event name + ULONG cchEvent, // [IN] the count of wchar of szEvent + ULONG *pchEvent, // [OUT] actual count of wchar for event's name + DWORD *pdwEventFlags, // [OUT] Event flags. + mdToken *ptkEventType, // [OUT] EventType class + mdMethodDef *pmdAddOn, // [OUT] AddOn method of the event + mdMethodDef *pmdRemoveOn, // [OUT] RemoveOn method of the event + mdMethodDef *pmdFire, // [OUT] Fire method of the event + mdMethodDef rmdOtherMethod[], // [OUT] other method of the event + ULONG cMax, // [IN] size of rmdOtherMethod + ULONG *pcOtherMethod) // [OUT] total number of other method of this event +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + EventRec *pRec; + HENUMInternal hEnum; + + LOG((LOGMD, "MD RegMeta::GetEventProps(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + ev, pClass, MDSTR(szEvent), cchEvent, pchEvent, pdwEventFlags, ptkEventType, + pmdAddOn, pmdRemoveOn, pmdFire, rmdOtherMethod, cMax, pcOtherMethod)); + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(ev) == mdtEvent); + + memset(&hEnum, 0, sizeof(HENUMInternal)); + IfFailGo(pMiniMd->GetEventRecord(RidFromToken(ev), &pRec)); + + if ( pClass ) + { + // find the event map entry corresponding to this event + IfFailGo( pMiniMd->FindParentOfEventHelper( ev, pClass ) ); + } + if ( pdwEventFlags ) + { + *pdwEventFlags = pMiniMd->getEventFlagsOfEvent(pRec); + } + if ( ptkEventType ) + { + *ptkEventType = pMiniMd->getEventTypeOfEvent(pRec); + } + { + MethodSemanticsRec *pSemantics; + RID ridCur; + ULONG cCurOtherMethod = 0; + ULONG ulSemantics; + mdMethodDef tkMethod; + + // initialize output parameters + if (pmdAddOn) + *pmdAddOn = mdMethodDefNil; + if (pmdRemoveOn) + *pmdRemoveOn = mdMethodDefNil; + if (pmdFire) + *pmdFire = mdMethodDefNil; + + IfFailGo( pMiniMd->FindMethodSemanticsHelper(ev, &hEnum) ); + while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur)) + { + IfFailGo(pMiniMd->GetMethodSemanticsRecord(ridCur, &pSemantics)); + ulSemantics = pMiniMd->getSemanticOfMethodSemantics(pSemantics); + tkMethod = TokenFromRid( pMiniMd->getMethodOfMethodSemantics(pSemantics), mdtMethodDef ); + switch (ulSemantics) + { + case msAddOn: + if (pmdAddOn) *pmdAddOn = tkMethod; + break; + case msRemoveOn: + if (pmdRemoveOn) *pmdRemoveOn = tkMethod; + break; + case msFire: + if (pmdFire) *pmdFire = tkMethod; + break; + case msOther: + if (cCurOtherMethod < cMax) + rmdOtherMethod[cCurOtherMethod] = tkMethod; + cCurOtherMethod++; + break; + default: + _ASSERTE(!"BadKind!"); + } + } + + // set the output parameter + if (pcOtherMethod) + *pcOtherMethod = cCurOtherMethod; + } + // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK + if (szEvent || pchEvent) + { + IfFailGo( pMiniMd->getNameOfEvent(pRec, (LPWSTR) szEvent, cchEvent, pchEvent) ); + } + +ErrExit: + HENUMInternal::ClearEnum(&hEnum); + STOP_MD_PERF(GetEventProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::GetEventProps() + + +//***************************************************************************** +// given a method, return an arra of event/property tokens for each accessor role +// it is defined to have +//***************************************************************************** +STDMETHODIMP RegMeta::EnumMethodSemantics( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdMethodDef mb, // [IN] MethodDef to scope the enumeration. + mdToken rEventProp[], // [OUT] Put Event/Property here. + ULONG cMax, // [IN] Max properties to put. + ULONG *pcEventProp) // [OUT] Put # put here. +{ + HRESULT hr = NOERROR; + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridEnd; + ULONG index; + HENUMInternal *pEnum = *ppmdEnum; + MethodSemanticsRec *pRec; + + LOG((LOGMD, "MD RegMeta::EnumMethodSemantics(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, mb, rEventProp, cMax, pcEventProp)); + + START_MD_PERF(); + LOCKREAD(); + + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + // create the enumerator + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( (DWORD) -1, &pEnum) ); + + // get the range of method rids given a typedef + ridEnd = pMiniMd->getCountMethodSemantics(); + + for (index = 1; index <= ridEnd; index++ ) + { + IfFailGo(pMiniMd->GetMethodSemanticsRecord(index, &pRec)); + if ( pMiniMd->getMethodOfMethodSemantics(pRec) == mb ) + { + IfFailGo( HENUMInternal::AddElementToEnum(pEnum, pMiniMd->getAssociationOfMethodSemantics(pRec) ) ); + } + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rEventProp, pcEventProp); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + + STOP_MD_PERF(EnumMethodSemantics); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumMethodSemantics() + + + +//***************************************************************************** +// return the role flags for the method/propevent pair +//***************************************************************************** +STDMETHODIMP RegMeta::GetMethodSemantics( // S_OK, S_FALSE, or error. + mdMethodDef mb, // [IN] method token + mdToken tkEventProp, // [IN] event/property token. + DWORD *pdwSemanticsFlags) // [OUT] the role flags for the method/propevent pair +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + MethodSemanticsRec *pRec; + ULONG ridCur; + HENUMInternal hEnum; + + LOG((LOGMD, "MD RegMeta::GetMethodSemantics(0x%08x, 0x%08x, 0x%08x)\n", + mb, tkEventProp, pdwSemanticsFlags)); + + + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(mb) == mdtMethodDef); + _ASSERTE( pdwSemanticsFlags ); + + *pdwSemanticsFlags = 0; + memset(&hEnum, 0, sizeof(HENUMInternal)); + + // loop through all methods associated with this tkEventProp + IfFailGo( pMiniMd->FindMethodSemanticsHelper(tkEventProp, &hEnum) ); + while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur)) + { + IfFailGo(pMiniMd->GetMethodSemanticsRecord(ridCur, &pRec)); + if ( pMiniMd->getMethodOfMethodSemantics(pRec) == mb ) + { + // we findd the match + *pdwSemanticsFlags = pMiniMd->getSemanticOfMethodSemantics(pRec); + goto ErrExit; + } + } + + IfFailGo( CLDB_E_RECORD_NOTFOUND ); + +ErrExit: + HENUMInternal::ClearEnum(&hEnum); + STOP_MD_PERF(GetMethodSemantics); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::GetMethodSemantics() + + + +//***************************************************************************** +// return the class layout information +//***************************************************************************** +STDMETHODIMP RegMeta::GetClassLayout( + mdTypeDef td, // [IN] give typedef + DWORD *pdwPackSize, // [OUT] 1, 2, 4, 8, or 16 + COR_FIELD_OFFSET rFieldOffset[], // [OUT] field offset array + ULONG cMax, // [IN] size of the array + ULONG *pcFieldOffset, // [OUT] needed array size + ULONG *pulClassSize) // [OUT] the size of the class +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + ClassLayoutRec *pRec; + RID ridClassLayout; + int bLayout=0; // Was any layout information found? + + _ASSERTE(TypeFromToken(td) == mdtTypeDef); + + LOG((LOGMD, "MD RegMeta::GetClassLayout(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + td, pdwPackSize, rFieldOffset, cMax, pcFieldOffset, pulClassSize)); + + START_MD_PERF(); + LOCKREAD(); + + IfFailGo(pMiniMd->FindClassLayoutHelper(td, &ridClassLayout)); + + if (InvalidRid(ridClassLayout)) + { // Nothing specified - return default values of 0. + if ( pdwPackSize ) + *pdwPackSize = 0; + if ( pulClassSize ) + *pulClassSize = 0; + } + else + { + IfFailGo(pMiniMd->GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRec)); + if ( pdwPackSize ) + *pdwPackSize = pMiniMd->getPackingSizeOfClassLayout(pRec); + if ( pulClassSize ) + *pulClassSize = pMiniMd->getClassSizeOfClassLayout(pRec); + bLayout = 1; + } + + // fill the layout array + if (rFieldOffset || pcFieldOffset) + { + ULONG iFieldOffset = 0; + ULONG ridFieldStart; + ULONG ridFieldEnd; + ULONG ridFieldLayout; + ULONG ulOffset; + TypeDefRec *pTypeDefRec; + FieldLayoutRec *pLayout2Rec; + mdFieldDef fd; + + // record for this typedef in TypeDef Table + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(td), &pTypeDefRec)); + + // find the starting and end field for this typedef + ridFieldStart = pMiniMd->getFieldListOfTypeDef(pTypeDefRec); + IfFailGo(pMiniMd->getEndFieldListOfTypeDef(RidFromToken(td), &ridFieldEnd)); + + // loop through the field table + + for(; ridFieldStart < ridFieldEnd; ridFieldStart++) + { + // Calculate the field token. + RID rid; + IfFailGo(pMiniMd->GetFieldRid(ridFieldStart, &rid)); + fd = TokenFromRid(rid, mdtFieldDef); + + // Calculate the FieldLayout rid for the current field. + IfFailGo(pMiniMd->FindFieldLayoutHelper(fd, &ridFieldLayout)); + + // Calculate the offset. + if (InvalidRid(ridFieldLayout)) + ulOffset = (ULONG) -1; + else + { + // get the FieldLayout record. + IfFailGo(pMiniMd->GetFieldLayoutRecord(ridFieldLayout, &pLayout2Rec)); + ulOffset = pMiniMd->getOffSetOfFieldLayout(pLayout2Rec); + bLayout = 1; + } + + // fill in the field layout if output buffer still has space. + if (cMax > iFieldOffset && rFieldOffset) + { + rFieldOffset[iFieldOffset].ridOfField = fd; + rFieldOffset[iFieldOffset].ulOffset = ulOffset; + } + + // advance the index to the buffer. + iFieldOffset++; + } + + if (bLayout && pcFieldOffset) + *pcFieldOffset = iFieldOffset; + } + + if (!bLayout) + hr = CLDB_E_RECORD_NOTFOUND; + +ErrExit: + STOP_MD_PERF(GetClassLayout); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::GetClassLayout() + + + +//***************************************************************************** +// return the native type of a field +//***************************************************************************** +STDMETHODIMP RegMeta::GetFieldMarshal( + mdToken tk, // [IN] given a field's memberdef + PCCOR_SIGNATURE *ppvNativeType, // [OUT] native type of this field + ULONG *pcbNativeType) // [OUT] the count of bytes of *ppvNativeType +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + RID rid; + FieldMarshalRec *pFieldMarshalRec; + + + _ASSERTE(ppvNativeType != NULL && pcbNativeType != NULL); + + LOG((LOGMD, "MD RegMeta::GetFieldMarshal(0x%08x, 0x%08x, 0x%08x)\n", + tk, ppvNativeType, pcbNativeType)); + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(tk) == mdtParamDef || TypeFromToken(tk) == mdtFieldDef); + + // find the row containing the marshal definition for tk + IfFailGo(pMiniMd->FindFieldMarshalHelper(tk, &rid)); + if (InvalidRid(rid)) + { + IfFailGo( CLDB_E_RECORD_NOTFOUND ); + } + IfFailGo(pMiniMd->GetFieldMarshalRecord(rid, &pFieldMarshalRec)); + + // get the native type + IfFailGo(pMiniMd->getNativeTypeOfFieldMarshal(pFieldMarshalRec, ppvNativeType, pcbNativeType)); + +ErrExit: + STOP_MD_PERF(GetFieldMarshal); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::GetFieldMarshal() + + + +//***************************************************************************** +// return the RVA and implflag for MethodDef or FieldDef token +//***************************************************************************** +STDMETHODIMP +RegMeta::GetRVA( + mdToken tk, // Member for which to set offset + ULONG *pulCodeRVA, // The offset + DWORD *pdwImplFlags) // the implementation flags +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + LOG((LOGMD, "MD RegMeta::GetRVA(0x%08x, 0x%08x, 0x%08x)\n", + tk, pulCodeRVA, pdwImplFlags)); + + START_MD_PERF(); + LOCKREAD(); + + if (TypeFromToken(tk) == mdtMethodDef) + { + if (tk == mdMethodDefNil) + { // Backward compatibility with CLR 2.0 implementation + if (pulCodeRVA != NULL) + *pulCodeRVA = 0; + if (pdwImplFlags != NULL) + *pdwImplFlags = 0; + + hr = S_OK; + goto ErrExit; + } + + // MethodDef token + MethodRec *pMethodRec; + IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tk), &pMethodRec)); + + if (pulCodeRVA != NULL) + { + *pulCodeRVA = pMiniMd->getRVAOfMethod(pMethodRec); + } + if (pdwImplFlags != NULL) + { + *pdwImplFlags = pMiniMd->getImplFlagsOfMethod(pMethodRec); + } + } + else + { // FieldDef token or invalid type of token (not mdtMethodDef) + ULONG iRecord; + + IfFailGo(pMiniMd->FindFieldRVAHelper(tk, &iRecord)); + + if (InvalidRid(iRecord)) + { + if (pulCodeRVA != NULL) + *pulCodeRVA = 0; + + IfFailGo(CLDB_E_RECORD_NOTFOUND); + } + + FieldRVARec *pFieldRVARec; + IfFailGo(pMiniMd->GetFieldRVARecord(iRecord, &pFieldRVARec)); + + if (pulCodeRVA != NULL) + { + *pulCodeRVA = pMiniMd->getRVAOfFieldRVA(pFieldRVARec); + } + if (pdwImplFlags != NULL) + { + *pdwImplFlags = 0; + } + } +ErrExit: + STOP_MD_PERF(GetRVA); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // RegMeta::GetRVA + + + +//***************************************************************************** +// Get the Action and Permissions blob for a given PermissionSet. +//***************************************************************************** +STDMETHODIMP RegMeta::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; + + BEGIN_ENTRYPOINT_NOTHROW; + + LOG((LOGMD, "MD RegMeta::GetPermissionSetProps(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + pm, pdwAction, ppvPermission, pcbPermission)); + + CMiniMdRW *pMiniMd = NULL; + DeclSecurityRec *pRecord = NULL; + + START_MD_PERF(); + LOCKREAD(); + + pMiniMd = &(m_pStgdb->m_MiniMd); + IfFailGo(pMiniMd->GetDeclSecurityRecord(RidFromToken(pm), &pRecord)); + + _ASSERTE(TypeFromToken(pm) == mdtPermission && RidFromToken(pm)); + + // If you want the BLOB, better get the BLOB size as well. + _ASSERTE(!ppvPermission || pcbPermission); + + if (pdwAction) + *pdwAction = pMiniMd->getActionOfDeclSecurity(pRecord); + + if (ppvPermission != NULL) + { + IfFailGo(pMiniMd->getPermissionSetOfDeclSecurity(pRecord, (const BYTE **)ppvPermission, pcbPermission)); + } + +ErrExit: + + STOP_MD_PERF(GetPermissionSetProps); + END_ENTRYPOINT_NOTHROW; + return hr; +} // STDMETHODIMP RegMeta::GetPermissionSetProps() + + + +//***************************************************************************** +// Given a signature token, get return a pointer to the signature to the caller. +// +//<TODO>@FUTURE: for short term we have a problem where there is no way to get a +// fixed up address for a blob and do Merge at the same time. So we've created +// this dummy table called StandAloneSig which you hand out a rid for. This +// makes finding the sig an extra indirection that is not required. The +// Model Compression save code needs to map the token into a byte offset in +// the heap. Perhaps we can have another mdt* type to switch on the difference. +// But ultimately it has to simply be "pBlobHeapBase + RidFromToken(mdSig)".</TODO> +//***************************************************************************** +STDMETHODIMP RegMeta::GetSigFromToken( // S_OK or error. + mdSignature mdSig, // [IN] Signature token. + PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to token. + ULONG *pcbSig) // [OUT] return size of signature. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + StandAloneSigRec *pRec; + + LOG((LOGMD, "MD RegMeta::GetSigFromToken(0x%08x, 0x%08x, 0x%08x)\n", + mdSig, ppvSig, pcbSig)); + + + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(mdSig) == mdtSignature); + _ASSERTE(ppvSig && pcbSig); + + IfFailGo(pMiniMd->GetStandAloneSigRecord(RidFromToken(mdSig), &pRec)); + IfFailGo(pMiniMd->getSignatureOfStandAloneSig(pRec, ppvSig, pcbSig)); + + +ErrExit: + + STOP_MD_PERF(GetSigFromToken); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::GetSigFromToken() + + +//******************************************************************************* +// return the ModuleRef properties +//******************************************************************************* +STDMETHODIMP RegMeta::GetModuleRefProps( // S_OK or error. + mdModuleRef mur, // [IN] moduleref token. + __out_ecount_opt (cchName) LPWSTR szName, // [OUT] buffer to fill with the moduleref name. + ULONG cchName, // [IN] size of szName in wide characters. + ULONG *pchName) // [OUT] actual count of characters in the name. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + ModuleRefRec *pModuleRefRec; + + + + LOG((LOGMD, "MD RegMeta::GetModuleRefProps(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + mur, szName, cchName, pchName)); + START_MD_PERF(); + LOCKREAD(); + + IfFailGo(pMiniMd->GetModuleRefRecord(RidFromToken(mur), &pModuleRefRec)); + + _ASSERTE(TypeFromToken(mur) == mdtModuleRef); + + // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK + if (szName || pchName) + { + IfFailGo( pMiniMd->getNameOfModuleRef(pModuleRefRec, szName, cchName, pchName) ); + } + +ErrExit: + + STOP_MD_PERF(GetModuleRefProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::GetModuleRefProps() + + + +//******************************************************************************* +// enumerating through all of the ModuleRefs +//******************************************************************************* +STDMETHODIMP RegMeta::EnumModuleRefs( // S_OK or error. + HCORENUM *phEnum, // [IN|OUT] pointer to the enum. + mdModuleRef rModuleRefs[], // [OUT] put modulerefs here. + ULONG cMax, // [IN] max memberrefs to put. + ULONG *pcModuleRefs) // [OUT] put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + HENUMInternal *pEnum; + + LOG((LOGMD, "MD RegMeta::EnumModuleRefs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, rModuleRefs, cMax, pcModuleRefs)); + + START_MD_PERF(); + LOCKREAD(); + + if (*ppmdEnum == NULL) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + // create the enumerator + IfFailGo(HENUMInternal::CreateSimpleEnum( + mdtModuleRef, + 1, + pMiniMd->getCountModuleRefs() + 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 + IfFailGo(HENUMInternal::EnumWithCount(pEnum, cMax, rModuleRefs, pcModuleRefs)); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumModuleRefs); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumModuleRefs() + + +//******************************************************************************* +// return properties regarding a TypeSpec +//******************************************************************************* +STDMETHODIMP RegMeta::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; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + TypeSpecRec *pRec = NULL; + + LOG((LOGMD, "MD RegMeta::GetTypeSpecFromToken(0x%08x, 0x%08x, 0x%08x)\n", + typespec, ppvSig, pcbSig)); + + + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(typespec) == mdtTypeSpec); + _ASSERTE(ppvSig && pcbSig); + + IfFailGo(pMiniMd->GetTypeSpecRecord(RidFromToken(typespec), &pRec)); + IfFailGo(pMiniMd->getSignatureOfTypeSpec(pRec, ppvSig, pcbSig)); + +ErrExit: + + STOP_MD_PERF(GetTypeSpecFromToken); + END_ENTRYPOINT_NOTHROW; + return hr; +} // STDMETHODIMP RegMeta::GetTypeSpecFromToken() + + +//***************************************************************************** +// For those items that have a name, retrieve a direct pointer to the name +// off of the heap. This reduces copies made for the caller. +//***************************************************************************** +#define NAME_FROM_TOKEN_TYPE(RecType, TokenType) \ + case mdt ## TokenType: \ + { \ + RecType ## Rec *pRecord; \ + IfFailGo(pMiniMd->Get ## RecType ## Record(RidFromToken(tk), &pRecord)); \ + IfFailGo(pMiniMd->getNameOf ## RecType (pRecord, pszUtf8NamePtr)); \ + } \ + break; +#define NAME_FROM_TOKEN(RecType) NAME_FROM_TOKEN_TYPE(RecType, RecType) + +STDMETHODIMP RegMeta::GetNameFromToken( // S_OK or error. + mdToken tk, // [IN] Token to get name from. Must have a name. + MDUTF8CSTR *pszUtf8NamePtr) // [OUT] Return pointer to UTF8 name in heap. +{ + HRESULT hr = S_OK; + + BEGIN_ENTRYPOINT_NOTHROW; + + + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + LOG((LOGMD, "MD RegMeta::GetNameFromToken(0x%08x, 0x%08x)\n", + tk, pszUtf8NamePtr)); + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(pszUtf8NamePtr); + + switch (TypeFromToken(tk)) + { + NAME_FROM_TOKEN(Module); + NAME_FROM_TOKEN(TypeRef); + NAME_FROM_TOKEN(TypeDef); + NAME_FROM_TOKEN_TYPE(Field, FieldDef); + NAME_FROM_TOKEN_TYPE(Method, MethodDef); + NAME_FROM_TOKEN_TYPE(Param, ParamDef); + NAME_FROM_TOKEN(MemberRef); + NAME_FROM_TOKEN(Event); + NAME_FROM_TOKEN(Property); + NAME_FROM_TOKEN(ModuleRef); + + default: + hr = E_INVALIDARG; + } + +ErrExit: + + STOP_MD_PERF(GetNameFromToken); + + END_ENTRYPOINT_NOTHROW; + + return (hr); +} // RegMeta::GetNameFromToken + + +//***************************************************************************** +// Get the symbol binding data back from the module if it is there. It is +// stored as a custom value. +//***************************************************************************** +STDMETHODIMP RegMeta::EnumUnresolvedMethods( // S_OK or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdToken rMethods[], // [OUT] Put MemberDefs here. + ULONG cMax, // [IN] Max MemberDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. +{ +#ifdef FEATURE_METADATA_EMIT + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal ** ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG iCountTypeDef; // Count of TypeDefs. + ULONG ulStart, ulEnd; // Bounds of methods on a given TypeDef. + ULONG index; // For counting methods on a TypeDef. + ULONG indexTypeDef; // For counting TypeDefs. + bool bIsInterface; // Is a given TypeDef an interface? + HENUMInternal * pEnum = *ppmdEnum; // Enum we're working with. + CMiniMdRW * pMiniMd = &(m_pStgdb->m_MiniMd); + + LOG((LOGMD, "MD RegMeta::EnumUnresolvedMethods(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, rMethods, cMax, pcTokens)); + + START_MD_PERF(); + + // take the write lock. Because we should have not have two EnumUnresolvedMethods being called at the + // same time. Ref to Def map may be calculated incorrectly. + LOCKWRITE(); + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + MethodRec *pMethodRec; + TypeDefRec *pTypeDefRec; + + // make sure our ref to def optimization is up to date + IfFailGo( RefToDefOptimization() ); + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( (DWORD) -1, &pEnum) ); + + // Loop through all of the methoddef except global functions. + // If methoddef has RVA 0 and not miRuntime, mdAbstract, mdVirtual, mdNative, + // we will fill it into the enumerator. + // + iCountTypeDef = pMiniMd->getCountTypeDefs(); + + for (indexTypeDef = 2; indexTypeDef <= iCountTypeDef; indexTypeDef ++ ) + { + IfFailGo(pMiniMd->GetTypeDefRecord(indexTypeDef, &pTypeDefRec)); + + // If the type is an interface, check the static methods. + bIsInterface = IsTdInterface(pTypeDefRec->GetFlags()); + + ulStart = pMiniMd->getMethodListOfTypeDef(pTypeDefRec); + IfFailGo(pMiniMd->getEndMethodListOfTypeDef(indexTypeDef, &ulEnd)); + + // always report errors even with any unimplemented methods + for (index = ulStart; index < ulEnd; index++) + { + RID methodRid; + IfFailGo(pMiniMd->GetMethodRid(index, &methodRid)); + IfFailGo(pMiniMd->GetMethodRecord(methodRid, &pMethodRec)); + + // If the type is an interface, and the method is not static, on to next. + if (bIsInterface && !IsMdStatic(pMethodRec->GetFlags())) + continue; + + if ( IsMiForwardRef(pMethodRec->GetImplFlags()) ) + { + if ( IsMdPinvokeImpl(pMethodRec->GetFlags()) ) + { + continue; + } + if ( IsMiRuntime(pMethodRec->GetImplFlags()) || IsMiInternalCall(pMethodRec->GetImplFlags())) + { + continue; + } + + if (IsMdAbstract(pMethodRec->GetFlags())) + continue; + + // If a methoddef has RVA 0 and it is not an abstract or virtual method. + // Nor it is a runtime generated method nore a native method, then we add it + // to the unresolved list. + // + IfFailGo(pMiniMd->GetMethodRid(index, &methodRid)); + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(methodRid, mdtMethodDef))); + + LOG((LOGMD, "MD adding unresolved MethodDef: token=%08x, flags=%08x, impl flags=%08x\n", + TokenFromRid(methodRid, mdtMethodDef), + pMethodRec->GetFlags(), pMethodRec->GetImplFlags())); + } + } + } + + MemberRefRec *pMemberRefRec; + ULONG iCount; + + // loop through MemberRef tables and find all of the unsats + iCount = pMiniMd->getCountMemberRefs(); + for (index = 1; index <= iCount; index++ ) + { + mdToken defToken; + mdMemberRef refToken = TokenFromRid(index, mdtMemberRef); + IfFailGo(pMiniMd->GetMemberRefRecord(index, &pMemberRefRec)); + pMiniMd->GetTokenRemapManager()->ResolveRefToDef(refToken, &defToken); + + if ( pMiniMd->getClassOfMemberRef(pMemberRefRec) == m_tdModule && defToken == refToken ) + { + // unresovled externals reference if parent token is not resolved and this ref token does not + // map to any def token (can be MethodDef or FieldDef). + // + IfFailGo( HENUMInternal::AddElementToEnum(pEnum, refToken) ); + + LOG((LOGMD, "MD adding unresolved MemberRef: token=%08x, doesn't have a proper parent\n", + refToken )); + } + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMethods, pcTokens); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumUnresolvedMethods); + END_ENTRYPOINT_NOTHROW; + + return hr; +#else //!FEATURE_METADATA_EMIT + return E_NOTIMPL; +#endif //!FEATURE_METADATA_EMIT +} // RegMeta::EnumUnresolvedMethods + +//***************************************************************************** +// Return the User string given the token. The offset into the Blob pool where +// the string is stored in Unicode is embedded inside the token. +//***************************************************************************** +STDMETHODIMP RegMeta::GetUserString( // S_OK or error. + mdString stk, // [IN] String token. + __out_ecount_opt(cchStringSize) LPWSTR wszString, // [OUT] Copy of string. + ULONG cchStringSize, // [IN] Max chars of room in szString. + ULONG *pcchStringSize) // [OUT] How many chars in actual string. +{ + HRESULT hr = S_OK; + ULONG cchStringSize_Dummy; + MetaData::DataBlob userString; + + BEGIN_ENTRYPOINT_NOTHROW; + + LOG((LOGMD, "MD RegMeta::GetUserString(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + stk, wszString, cchStringSize, pcchStringSize)); + + START_MD_PERF(); + LOCKREAD(); + + // Get the string data. + IfFailGo(m_pStgdb->m_MiniMd.GetUserString(RidFromToken(stk), &userString)); + // Want to get whole characters, followed by byte to indicate whether there + // are extended characters (>= 0x80). + if ((userString.GetSize() % sizeof(WCHAR)) == 0) + { + Debug_ReportError("User strings should have 1 byte terminator (either 0x00 or 0x80)."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + + // Strip off the last byte. + if (!userString.TruncateBySize(1)) + { + Debug_ReportInternalError("There's a bug, because previous % 2 check didn't return 0."); + IfFailGo(METADATA_E_INTERNAL_ERROR); + } + + // Convert bytes to characters. + if (pcchStringSize == NULL) + { + pcchStringSize = &cchStringSize_Dummy; + } + *pcchStringSize = userString.GetSize() / sizeof(WCHAR); + + // Copy the string back to the caller. + if ((wszString != NULL) && (cchStringSize > 0)) + { + ULONG cbStringSize = cchStringSize * sizeof(WCHAR); + memcpy( + wszString, + userString.GetDataPointer(), + min(userString.GetSize(), cbStringSize)); + if (cbStringSize < userString.GetSize()) + { + if ((wszString != NULL) && (cchStringSize > 0)) + { // null-terminate the truncated output string + wszString[cchStringSize - 1] = W('\0'); + } + + hr = CLDB_S_TRUNCATION; + } + } + + ErrExit: + STOP_MD_PERF(GetUserString); + END_ENTRYPOINT_NOTHROW; + return hr; +} // RegMeta::GetUserString + +//***************************************************************************** +// Return contents of Pinvoke given the forwarded member token. +//***************************************************************************** +STDMETHODIMP RegMeta::GetPinvokeMap( // S_OK or error. + mdToken tk, // [IN] FieldDef or MethodDef. + DWORD *pdwMappingFlags, // [OUT] Flags used for mapping. + __out_ecount_opt (cchImportName) LPWSTR szImportName, // [OUT] Import name. + ULONG cchImportName, // [IN] Size of the name buffer. + ULONG *pchImportName, // [OUT] Actual number of characters stored. + mdModuleRef *pmrImportDLL) // [OUT] ModuleRef token for the target DLL. +{ + HRESULT hr = S_OK; + + BEGIN_ENTRYPOINT_NOTHROW; + + ImplMapRec * pRecord; + ULONG iRecord; + + LOG((LOGMD, "MD RegMeta::GetPinvokeMap(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + tk, pdwMappingFlags, szImportName, cchImportName, pchImportName, pmrImportDLL)); + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(tk) == mdtFieldDef || + TypeFromToken(tk) == mdtMethodDef); + + IfFailGo(m_pStgdb->m_MiniMd.FindImplMapHelper(tk, &iRecord)); + if (InvalidRid(iRecord)) + { + IfFailGo( CLDB_E_RECORD_NOTFOUND ); + } + else + IfFailGo(m_pStgdb->m_MiniMd.GetImplMapRecord(iRecord, &pRecord)); + + if (pdwMappingFlags) + *pdwMappingFlags = m_pStgdb->m_MiniMd.getMappingFlagsOfImplMap(pRecord); + if (pmrImportDLL) + *pmrImportDLL = m_pStgdb->m_MiniMd.getImportScopeOfImplMap(pRecord); + // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK + if (szImportName || pchImportName) + IfFailGo(m_pStgdb->m_MiniMd.getImportNameOfImplMap(pRecord, szImportName, cchImportName, pchImportName)); +ErrExit: + STOP_MD_PERF(GetPinvokeMap); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // HRESULT RegMeta::GetPinvokeMap() + +//***************************************************************************** +// Enumerate through all the local sigs. +//***************************************************************************** +STDMETHODIMP RegMeta::EnumSignatures( // S_OK or error. + HCORENUM *phEnum, // [IN|OUT] pointer to the enum. + mdModuleRef rSignatures[], // [OUT] put signatures here. + ULONG cmax, // [IN] max signatures to put. + ULONG *pcSignatures) // [OUT] put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppsigEnum = reinterpret_cast<HENUMInternal **> (phEnum); + HENUMInternal *pEnum; + + LOG((LOGMD, "MD RegMeta::EnumSignatures(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, rSignatures, cmax, pcSignatures)); + + START_MD_PERF(); + LOCKREAD(); + + if (*ppsigEnum == NULL) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + // create the enumerator. + IfFailGo(HENUMInternal::CreateSimpleEnum( + mdtSignature, + 1, + pMiniMd->getCountStandAloneSigs() + 1, + &pEnum)); + + // set the output parameter + *ppsigEnum = pEnum; + } + else + { + pEnum = *ppsigEnum; + } + + // we can only fill the minimum of what caller asked for or what we have left. + IfFailGo(HENUMInternal::EnumWithCount(pEnum, cmax, rSignatures, pcSignatures)); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppsigEnum); + + STOP_MD_PERF(EnumSignatures); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // RegMeta::EnumSignatures + + +//***************************************************************************** +// Enumerate through all the TypeSpec +//***************************************************************************** +STDMETHODIMP RegMeta::EnumTypeSpecs( // S_OK or error. + HCORENUM *phEnum, // [IN|OUT] pointer to the enum. + mdTypeSpec rTypeSpecs[], // [OUT] put TypeSpecs here. + ULONG cmax, // [IN] max TypeSpecs to put. + ULONG *pcTypeSpecs) // [OUT] put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppEnum = reinterpret_cast<HENUMInternal **> (phEnum); + HENUMInternal *pEnum; + + LOG((LOGMD, "MD RegMeta::EnumTypeSpecs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, rTypeSpecs, cmax, pcTypeSpecs)); + + START_MD_PERF(); + LOCKREAD(); + + if (*ppEnum == NULL) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + // create the enumerator. + IfFailGo(HENUMInternal::CreateSimpleEnum( + mdtTypeSpec, + 1, + pMiniMd->getCountTypeSpecs() + 1, + &pEnum)); + + // set the output parameter + *ppEnum = pEnum; + } + else + { + pEnum = *ppEnum; + } + + // we can only fill the minimum of what caller asked for or what we have left. + IfFailGo(HENUMInternal::EnumWithCount(pEnum, cmax, rTypeSpecs, pcTypeSpecs)); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppEnum); + + STOP_MD_PERF(EnumTypeSpecs); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // RegMeta::EnumTypeSpecs + + +//***************************************************************************** +// Enumerate through all the User Strings. +//***************************************************************************** +STDMETHODIMP RegMeta::EnumUserStrings( // S_OK or error. + HCORENUM *phEnum, // [IN/OUT] pointer to the enum. + mdString rStrings[], // [OUT] put Strings here. + ULONG cmax, // [IN] max Strings to put. + ULONG *pcStrings) // [OUT] put # put here. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppEnum = reinterpret_cast<HENUMInternal **> (phEnum); + HENUMInternal *pEnum = *ppEnum; + + LOG((LOGMD, "MD RegMeta::EnumUserStrings(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, rStrings, cmax, pcStrings)); + + START_MD_PERF(); + LOCKREAD(); + + if (pEnum == NULL) + { + // instantiating a new ENUM. + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + IfFailGo(HENUMInternal::CreateDynamicArrayEnum(mdtString, &pEnum)); + + // Add all strings to the dynamic array + for (UINT32 nIndex = 0; ;) + { + MetaData::DataBlob userString; + UINT32 nNextIndex; + hr = pMiniMd->GetUserStringAndNextIndex( + nIndex, + &userString, + &nNextIndex); + IfFailGo(hr); + if (hr == S_FALSE) + { // We reached the last user string + hr = S_OK; + break; + } + _ASSERTE(hr == S_OK); + + // Skip empty strings + if (userString.IsEmpty()) + { + nIndex = nNextIndex; + continue; + } + // Add the user string into dynamic array + IfFailGo(HENUMInternal::AddElementToEnum( + pEnum, + TokenFromRid(nIndex, mdtString))); + + // Process next user string in the heap + nIndex = nNextIndex; + } + + // set the output parameter. + *ppEnum = pEnum; + } + + // fill the output token buffer. + hr = HENUMInternal::EnumWithCount(pEnum, cmax, rStrings, pcStrings); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppEnum); + + + STOP_MD_PERF(EnumUserStrings); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // RegMeta::EnumUserStrings + + +//***************************************************************************** +// This routine gets the param token given a method and index of the parameter. +//***************************************************************************** +STDMETHODIMP RegMeta::GetParamForMethodIndex( // S_OK or error. + mdMethodDef md, // [IN] Method token. + ULONG ulParamSeq, // [IN] Parameter sequence. + mdParamDef *ppd) // [IN] Put Param token here. +{ + HRESULT hr = S_OK; + + BEGIN_ENTRYPOINT_NOTHROW; + + + LOG((LOGMD, "MD RegMeta::GetParamForMethodIndex(0x%08x, 0x%08x, 0x%08x)\n", + md, ulParamSeq, ppd)); + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE((TypeFromToken(md) == mdtMethodDef) && (ulParamSeq != ULONG_MAX) && (ppd != NULL)); + + IfFailGo(_FindParamOfMethod(md, ulParamSeq, ppd)); +ErrExit: + + STOP_MD_PERF(GetParamForMethodIndex); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // RegMeta::GetParamForMethodIndex() + +//***************************************************************************** +// Return the property of a MethodDef or a FieldDef +//***************************************************************************** +HRESULT RegMeta::GetMemberProps( + mdToken mb, // The member for which to get props. + mdTypeDef *pClass, // Put member's class here. + __out_ecount_opt (cchMember) LPWSTR szMember, // Put member's name here. + ULONG cchMember, // Size of szMember buffer in wide chars. + ULONG *pchMember, // Put actual size here + DWORD *pdwAttr, // Put flags here. + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data + ULONG *pcbSigBlob, // [OUT] actual size of signature blob + ULONG *pulCodeRVA, // [OUT] codeRVA + DWORD *pdwImplFlags, // [OUT] Impl. Flags + DWORD *pdwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* + UVCP_CONSTANT *ppValue, // [OUT] constant value + ULONG *pchValue) // [OUT] size of constant value, string only, wide chars +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + LOG((LOGMD, "MD RegMeta::GetMemberProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + mb, pClass, szMember, cchMember, pchMember, pdwAttr, ppvSigBlob, pcbSigBlob, + pulCodeRVA, pdwImplFlags, pdwCPlusTypeFlag, ppValue, pchValue)); + + + + START_MD_PERF(); + + _ASSERTE(TypeFromToken(mb) == mdtMethodDef || TypeFromToken(mb) == mdtFieldDef); + + // No need to lock this function. It is calling public APIs. Keep it that way. + + if (TypeFromToken(mb) == mdtMethodDef) + { + // It is a Method + IfFailGo( GetMethodProps( + mb, + pClass, + szMember, + cchMember, + pchMember, + pdwAttr, + ppvSigBlob, + pcbSigBlob, + pulCodeRVA, + pdwImplFlags) ); + } + else + { + // It is a Field + IfFailGo( GetFieldProps( + mb, + pClass, + szMember, + cchMember, + pchMember, + pdwAttr, + ppvSigBlob, + pcbSigBlob, + pdwCPlusTypeFlag, + ppValue, + pchValue) ); + } +ErrExit: + STOP_MD_PERF(GetMemberProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // HRESULT RegMeta::GetMemberProps() + +//***************************************************************************** +// Return the property of a FieldDef +//***************************************************************************** +HRESULT RegMeta::GetFieldProps( + mdFieldDef fd, // The field for which to get props. + mdTypeDef *pClass, // Put field's class here. + __out_ecount_opt (cchField) LPWSTR szField, // Put field's name here. + ULONG cchField, // Size of szField buffer in wide chars. + ULONG *pchField, // Put actual size here + DWORD *pdwAttr, // Put flags here. + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data + ULONG *pcbSigBlob, // [OUT] actual size of signature blob + DWORD *pdwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* + UVCP_CONSTANT *ppValue, // [OUT] constant value + ULONG *pchValue) // [OUT] size of constant value, string only, wide chars +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + FieldRec *pFieldRec; + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + LOG((LOGMD, "MD RegMeta::GetFieldProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + fd, pClass, szField, cchField, pchField, pdwAttr, ppvSigBlob, pcbSigBlob, pdwCPlusTypeFlag, + ppValue, pchValue)); + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(fd) == mdtFieldDef); + + IfFailGo(pMiniMd->GetFieldRecord(RidFromToken(fd), &pFieldRec)); + + if (pClass) + { + // caller wants parent typedef + IfFailGo( pMiniMd->FindParentOfFieldHelper(fd, pClass) ); + + if ( IsGlobalMethodParentToken(*pClass) ) + { + // If the parent of Field is the <Module>, return mdTypeDefNil instead. + *pClass = mdTypeDefNil; + } + } + if (ppvSigBlob || pcbSigBlob) + { + // caller wants signature information + PCCOR_SIGNATURE pvSigTmp; + ULONG cbSig; + IfFailGo(pMiniMd->getSignatureOfField(pFieldRec, &pvSigTmp, &cbSig)); + if ( ppvSigBlob ) + *ppvSigBlob = pvSigTmp; + if ( pcbSigBlob) + *pcbSigBlob = cbSig; + } + if ( pdwAttr ) + { + *pdwAttr = pMiniMd->getFlagsOfField(pFieldRec); + } + if ( pdwCPlusTypeFlag || ppValue || pchValue) + { + // get the constant value + ULONG cbValue; + RID rid; + IfFailGo(pMiniMd->FindConstantHelper(fd, &rid)); + + if (pchValue) + *pchValue = 0; + + if (InvalidRid(rid)) + { + // There is no constant value associate with it + if (pdwCPlusTypeFlag) + *pdwCPlusTypeFlag = ELEMENT_TYPE_VOID; + + if ( ppValue ) + *ppValue = NULL; + } + else + { + ConstantRec *pConstantRec; + IfFailGo(m_pStgdb->m_MiniMd.GetConstantRecord(rid, &pConstantRec)); + DWORD dwType; + + // get the type of constant value + dwType = pMiniMd->getTypeOfConstant(pConstantRec); + if ( pdwCPlusTypeFlag ) + *pdwCPlusTypeFlag = dwType; + + // get the value blob + if (ppValue != NULL) + { + IfFailGo(pMiniMd->getValueOfConstant(pConstantRec, (const BYTE **)ppValue, &cbValue)); + if (pchValue && dwType == ELEMENT_TYPE_STRING) + *pchValue = cbValue / sizeof(WCHAR); + } + } + } + // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK + if (szField || pchField) + { + IfFailGo( pMiniMd->getNameOfField(pFieldRec, szField, cchField, pchField) ); + } + +ErrExit: + STOP_MD_PERF(GetFieldProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // HRESULT RegMeta::GetFieldProps() + +//***************************************************************************** +// return the properties of a property token +//***************************************************************************** +HRESULT RegMeta::GetPropertyProps( // S_OK, S_FALSE, or error. + mdProperty prop, // [IN] property token + mdTypeDef *pClass, // [OUT] typedef containing the property declarion. + LPCWSTR szProperty, // [OUT] Property name + ULONG cchProperty, // [IN] the count of wchar of szProperty + ULONG *pchProperty, // [OUT] actual count of wchar for property name + DWORD *pdwPropFlags, // [OUT] property flags. + PCCOR_SIGNATURE *ppvSig, // [OUT] property type. pointing to meta data internal blob + ULONG *pbSig, // [OUT] count of bytes in *ppvSig + DWORD *pdwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* + UVCP_CONSTANT *ppDefaultValue, // [OUT] constant value + ULONG *pchDefaultValue, // [OUT] size of constant value, string only, wide chars + mdMethodDef *pmdSetter, // [OUT] setter method of the property + mdMethodDef *pmdGetter, // [OUT] getter method of the property + mdMethodDef rmdOtherMethod[], // [OUT] other method of the property + ULONG cMax, // [IN] size of rmdOtherMethod + ULONG *pcOtherMethod) // [OUT] total number of other method of this property +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd; + PropertyRec *pRec; + HENUMInternal hEnum; + + LOG((LOGMD, "MD RegMeta::GetPropertyProps(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, " + "0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, " + "0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, " + "0x%08x)\n", + prop, pClass, MDSTR(szProperty), cchProperty, pchProperty, + pdwPropFlags, ppvSig, pbSig, pdwCPlusTypeFlag, ppDefaultValue, + pchDefaultValue, pmdSetter, pmdGetter, rmdOtherMethod, cMax, + pcOtherMethod)); + + + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(prop) == mdtProperty); + + pMiniMd = &(m_pStgdb->m_MiniMd); + + memset(&hEnum, 0, sizeof(HENUMInternal)); + IfFailGo(pMiniMd->GetPropertyRecord(RidFromToken(prop), &pRec)); + + if ( pClass ) + { + // find the property map entry corresponding to this property + IfFailGo( pMiniMd->FindParentOfPropertyHelper( prop, pClass) ); + } + if ( pdwPropFlags ) + { + *pdwPropFlags = pMiniMd->getPropFlagsOfProperty(pRec); + } + if ( ppvSig || pbSig ) + { + // caller wants the signature + // + ULONG cbSig; + PCCOR_SIGNATURE pvSig; + IfFailGo(pMiniMd->getTypeOfProperty(pRec, &pvSig, &cbSig)); + if ( ppvSig ) + { + *ppvSig = pvSig; + } + if ( pbSig ) + { + *pbSig = cbSig; + } + } + if ( pdwCPlusTypeFlag || ppDefaultValue || pchDefaultValue) + { + // get the constant value + ULONG cbValue; + RID rid; + IfFailGo(pMiniMd->FindConstantHelper(prop, &rid)); + + if (pchDefaultValue) + *pchDefaultValue = 0; + + if (InvalidRid(rid)) + { + // There is no constant value associate with it + if (pdwCPlusTypeFlag) + *pdwCPlusTypeFlag = ELEMENT_TYPE_VOID; + + if ( ppDefaultValue ) + *ppDefaultValue = NULL; + } + else + { + ConstantRec *pConstantRec; + IfFailGo(m_pStgdb->m_MiniMd.GetConstantRecord(rid, &pConstantRec)); + DWORD dwType; + + // get the type of constant value + dwType = pMiniMd->getTypeOfConstant(pConstantRec); + if ( pdwCPlusTypeFlag ) + *pdwCPlusTypeFlag = dwType; + + // get the value blob + if (ppDefaultValue != NULL) + { + IfFailGo(pMiniMd->getValueOfConstant(pConstantRec, (const BYTE **)ppDefaultValue, &cbValue)); + if (pchDefaultValue && dwType == ELEMENT_TYPE_STRING) + *pchDefaultValue = cbValue / sizeof(WCHAR); + } + } + } + { + MethodSemanticsRec *pSemantics; + RID ridCur; + ULONG cCurOtherMethod = 0; + ULONG ulSemantics; + mdMethodDef tkMethod; + + // initialize output parameters + if (pmdSetter) + *pmdSetter = mdMethodDefNil; + if (pmdGetter) + *pmdGetter = mdMethodDefNil; + + IfFailGo( pMiniMd->FindMethodSemanticsHelper(prop, &hEnum) ); + while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur)) + { + IfFailGo(pMiniMd->GetMethodSemanticsRecord(ridCur, &pSemantics)); + ulSemantics = pMiniMd->getSemanticOfMethodSemantics(pSemantics); + tkMethod = TokenFromRid( pMiniMd->getMethodOfMethodSemantics(pSemantics), mdtMethodDef ); + switch (ulSemantics) + { + case msSetter: + if (pmdSetter) *pmdSetter = tkMethod; + break; + case msGetter: + if (pmdGetter) *pmdGetter = tkMethod; + break; + case msOther: + if (cCurOtherMethod < cMax) + rmdOtherMethod[cCurOtherMethod] = tkMethod; + cCurOtherMethod ++; + break; + default: + _ASSERTE(!"BadKind!"); + } + } + + // set the output parameter + if (pcOtherMethod) + *pcOtherMethod = cCurOtherMethod; + } + // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK + if (szProperty || pchProperty) + { + IfFailGo( pMiniMd->getNameOfProperty(pRec, (LPWSTR) szProperty, cchProperty, pchProperty) ); + } + +ErrExit: + HENUMInternal::ClearEnum(&hEnum); + STOP_MD_PERF(GetPropertyProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // HRESULT RegMeta::GetPropertyProps() + + +//***************************************************************************** +// This routine gets the properties for the given Param token. +//***************************************************************************** +HRESULT RegMeta::GetParamProps( // S_OK or error. + mdParamDef pd, // [IN]The Parameter. + mdMethodDef *pmd, // [OUT] Parent Method token. + ULONG *pulSequence, // [OUT] Parameter sequence. + __out_ecount_opt (cchName) LPWSTR szName, // [OUT] Put name here. + ULONG cchName, // [OUT] Size of name buffer. + ULONG *pchName, // [OUT] Put actual size of name here. + DWORD *pdwAttr, // [OUT] Put flags here. + DWORD *pdwCPlusTypeFlag, // [OUT] Flag for value type. selected ELEMENT_TYPE_*. + UVCP_CONSTANT *ppValue, // [OUT] Constant value. + ULONG *pchValue) // [OUT] size of constant value, string only, wide chars +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + ParamRec *pParamRec; + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + LOG((LOGMD, "MD RegMeta::GetParamProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + pd, pmd, pulSequence, szName, cchName, pchName, pdwAttr, pdwCPlusTypeFlag, ppValue, pchValue)); + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(pd) == mdtParamDef); + + IfFailGo(pMiniMd->GetParamRecord(RidFromToken(pd), &pParamRec)); + + if (pmd) + { + IfFailGo(pMiniMd->FindParentOfParamHelper(pd, pmd)); + _ASSERTE(TypeFromToken(*pmd) == mdtMethodDef); + } + if (pulSequence) + *pulSequence = pMiniMd->getSequenceOfParam(pParamRec); + if (pdwAttr) + { + *pdwAttr = pMiniMd->getFlagsOfParam(pParamRec); + } + if ( pdwCPlusTypeFlag || ppValue || pchValue) + { + // get the constant value + ULONG cbValue; + RID rid; + IfFailGo(pMiniMd->FindConstantHelper(pd, &rid)); + + if (pchValue) + *pchValue = 0; + + if (InvalidRid(rid)) + { + // There is no constant value associate with it + if (pdwCPlusTypeFlag) + *pdwCPlusTypeFlag = ELEMENT_TYPE_VOID; + + if ( ppValue ) + *ppValue = NULL; + } + else + { + ConstantRec *pConstantRec; + IfFailGo(m_pStgdb->m_MiniMd.GetConstantRecord(rid, &pConstantRec)); + DWORD dwType; + + // get the type of constant value + dwType = pMiniMd->getTypeOfConstant(pConstantRec); + if ( pdwCPlusTypeFlag ) + *pdwCPlusTypeFlag = dwType; + + // get the value blob + if (ppValue != NULL) + { + IfFailGo(pMiniMd->getValueOfConstant(pConstantRec, (const BYTE **)ppValue, &cbValue)); + if (pchValue && dwType == ELEMENT_TYPE_STRING) + *pchValue = cbValue / sizeof(WCHAR); + } + } + } + // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK + if (szName || pchName) + IfFailGo( pMiniMd->getNameOfParam(pParamRec, szName, cchName, pchName) ); + +ErrExit: + STOP_MD_PERF(GetParamProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // HRESULT RegMeta::GetParamProps() + +//***************************************************************************** +// This routine gets the properties for the given GenericParam token. +//***************************************************************************** +HRESULT RegMeta::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) + __out_ecount_opt (cchName) LPWSTR szName, // [OUT] The name + ULONG cchName, // [IN] Size of name buffer + ULONG *pchName) // [OUT] Actual size of name +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + GenericParamRec *pGenericParamRec; + CMiniMdRW *pMiniMd = NULL; + RID ridRD = RidFromToken(rd); + + + LOG((LOGMD, "MD RegMeta::GetGenericParamProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + rd, pulSequence, pdwAttr, ptOwner, reserved, szName, cchName, pchName)); + + START_MD_PERF(); + LOCKREAD(); + + pMiniMd = &(m_pStgdb->m_MiniMd); + + // See if this version of the metadata can do Generics + if (!pMiniMd->SupportsGenerics()) + IfFailGo(CLDB_E_INCOMPATIBLE); + + + if((TypeFromToken(rd) == mdtGenericParam) && (ridRD != 0)) + { + IfFailGo(pMiniMd->GetGenericParamRecord(RidFromToken(rd), &pGenericParamRec)); + + if (pulSequence) + *pulSequence = pMiniMd->getNumberOfGenericParam(pGenericParamRec); + if (pdwAttr) + *pdwAttr = pMiniMd->getFlagsOfGenericParam(pGenericParamRec); + if (ptOwner) + *ptOwner = pMiniMd->getOwnerOfGenericParam(pGenericParamRec); + // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK + if (pchName || szName) + IfFailGo(pMiniMd->getNameOfGenericParam(pGenericParamRec, szName, cchName, pchName)); + } + else + hr = META_E_BAD_INPUT_PARAMETER; + +ErrExit: + STOP_MD_PERF(GetGenericParamProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // HRESULT RegMeta::GetGenericParamProps() + +//***************************************************************************** +// This routine gets the properties for the given GenericParamConstraint token. +//***************************************************************************** +HRESULT RegMeta::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; + + BEGIN_ENTRYPOINT_NOTHROW; + + GenericParamConstraintRec *pGPCRec; + CMiniMdRW *pMiniMd = NULL; + RID ridRD = RidFromToken(rd); + + LOG((LOGMD, "MD RegMeta::GetGenericParamConstraintProps(0x%08x, 0x%08x, 0x%08x)\n", + rd, ptGenericParam, ptkConstraintType)); + + START_MD_PERF(); + LOCKREAD(); + + pMiniMd = &(m_pStgdb->m_MiniMd); + + // See if this version of the metadata can do Generics + if (!pMiniMd->SupportsGenerics()) + IfFailGo(CLDB_E_INCOMPATIBLE); + + + if((TypeFromToken(rd) == mdtGenericParamConstraint) && (ridRD != 0)) + { + IfFailGo(pMiniMd->GetGenericParamConstraintRecord(ridRD, &pGPCRec)); + + if (ptGenericParam) + *ptGenericParam = TokenFromRid(pMiniMd->getOwnerOfGenericParamConstraint(pGPCRec),mdtGenericParam); + if (ptkConstraintType) + *ptkConstraintType = pMiniMd->getConstraintOfGenericParamConstraint(pGPCRec); + } + else + hr = META_E_BAD_INPUT_PARAMETER; + +ErrExit: + STOP_MD_PERF(GetGenericParamConstraintProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // HRESULT RegMeta::GetGenericParamConstraintProps() + +//***************************************************************************** +// This routine gets the properties for the given MethodSpec token. +//***************************************************************************** +HRESULT RegMeta::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; + + BEGIN_ENTRYPOINT_NOTHROW; + + MethodSpecRec *pMethodSpecRec; + CMiniMdRW *pMiniMd = NULL; + + LOG((LOGMD, "MD RegMeta::GetMethodSpecProps(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + mi, tkParent, ppvSigBlob, pcbSigBlob)); + START_MD_PERF(); + LOCKREAD(); + + pMiniMd = &(m_pStgdb->m_MiniMd); + + + // See if this version of the metadata can do Generics + if (!pMiniMd->SupportsGenerics()) + IfFailGo(CLDB_E_INCOMPATIBLE); + + _ASSERTE(TypeFromToken(mi) == mdtMethodSpec && RidFromToken(mi)); + + IfFailGo(pMiniMd->GetMethodSpecRecord(RidFromToken(mi), &pMethodSpecRec)); + + if (tkParent) + *tkParent = pMiniMd->getMethodOfMethodSpec(pMethodSpecRec); + + if (ppvSigBlob || pcbSigBlob) + { + // caller wants signature information + PCCOR_SIGNATURE pvSigTmp; + ULONG cbSig; + IfFailGo(pMiniMd->getInstantiationOfMethodSpec(pMethodSpecRec, &pvSigTmp, &cbSig)); + if ( ppvSigBlob ) + *ppvSigBlob = pvSigTmp; + if ( pcbSigBlob) + *pcbSigBlob = cbSig; + } + + +ErrExit: + + STOP_MD_PERF(GetMethodSpecProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // HRESULT RegMeta::GetMethodSpecProps() + +//***************************************************************************** +// This routine gets the type and machine of the PE file the scope is opened on. +//***************************************************************************** +HRESULT RegMeta::GetPEKind( // S_OK or error. + DWORD *pdwPEKind, // [OUT] The kind of PE (0 - not a PE) + DWORD *pdwMachine) // [OUT] Machine as defined in NT header +{ + HRESULT hr = NOERROR; + MAPPINGTYPE mt = MTYPE_NOMAPPING; + + BEGIN_ENTRYPOINT_NOTHROW; + + LOG((LOGMD, "MD RegMeta::GetPEKind(0x%08x, 0x%08x)\n",pdwPEKind,pdwMachine)); + + START_MD_PERF(); + LOCKREAD(); + + + if (m_pStgdb->m_pStgIO != NULL) + mt = m_pStgdb->m_pStgIO->GetMemoryMappedType(); + + hr = m_pStgdb->GetPEKind(mt, pdwPEKind, pdwMachine); + + ErrExit: + + STOP_MD_PERF(GetPEKind); + END_ENTRYPOINT_NOTHROW; + return hr; +} // HRESULT RegMeta::GetPEKind() + +//***************************************************************************** +// 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. +//***************************************************************************** +HRESULT RegMeta::GetVersionString( // S_OK or error. + __out_ecount_opt (cchBufSize) LPWSTR pwzBuf, // [OUT] Put version string here. + DWORD cchBufSize, // [in] size of the buffer, in wide chars + DWORD *pchBufSize) // [out] Size of the version string, wide chars, including terminating nul. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + + DWORD cch; // Length of WideChar string. + LPCSTR pVer; // Pointer to version string. + + LOG((LOGMD, "MD RegMeta::GetVersionString(0x%08x, 0x%08x, 0x%08x)\n",pwzBuf,cchBufSize,pchBufSize)); + + START_MD_PERF(); + LOCKREAD(); + + 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<const char*>(reinterpret_cast<const STORAGESIGNATURE*>(m_pStgdb->m_pvMd)->pVersion); + // Attempt to convert into caller's buffer. + cch = WszMultiByteToWideChar(CP_UTF8,0, pVer,-1, pwzBuf,cchBufSize); + // Did the string fit? + if (cch == 0) + { // No, didn't fit. Find out space required. + cch = WszMultiByteToWideChar(CP_UTF8,0, pVer,-1, pwzBuf,0); + // NUL terminate string. + if (cchBufSize > 0) + pwzBuf[cchBufSize-1] = W('\0'); + // Truncation return code. + hr = CLDB_S_TRUNCATION; + } + } + else + { // No string. + if (cchBufSize > 0) + *pwzBuf = W('\0'); + cch = 0; + } + + if (pchBufSize) + *pchBufSize = cch; + +ErrExit: + + STOP_MD_PERF(GetVersionString); + END_ENTRYPOINT_NOTHROW; + return hr; +} // HRESULT RegMeta::GetVersionString() + +//***************************************************************************** +// This routine gets the parent class for the nested class. +//***************************************************************************** +HRESULT RegMeta::GetNestedClassProps( // S_OK or error. + mdTypeDef tdNestedClass, // [IN] NestedClass token. + mdTypeDef *ptdEnclosingClass) // [OUT] EnclosingClass token. +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + NestedClassRec *pRecord; + ULONG iRecord; + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + + LOG((LOGMD, "MD RegMeta::GetNestedClassProps(0x%08x, 0x%08x)\n", + tdNestedClass, ptdEnclosingClass)); + + START_MD_PERF(); + LOCKREAD(); + + // If not a typedef -- return error. + if (TypeFromToken(tdNestedClass) != mdtTypeDef) + { + IfFailGo(META_E_INVALID_TOKEN_TYPE); // PostError(META_E_INVALID_TOKEN_TYPE, tdNestedClass)); + } + + _ASSERTE(TypeFromToken(tdNestedClass) && !IsNilToken(tdNestedClass) && ptdEnclosingClass); + + IfFailGo(pMiniMd->FindNestedClassHelper(tdNestedClass, &iRecord)); + + if (InvalidRid(iRecord)) + { + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + + IfFailGo(pMiniMd->GetNestedClassRecord(iRecord, &pRecord)); + + _ASSERTE(tdNestedClass == pMiniMd->getNestedClassOfNestedClass(pRecord)); + *ptdEnclosingClass = pMiniMd->getEnclosingClassOfNestedClass(pRecord); + +ErrExit: + STOP_MD_PERF(GetNestedClassProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // HRESULT RegMeta::GetNestedClassProps() + +//***************************************************************************** +// Given a signature, parse it for custom modifier with calling convention. +//***************************************************************************** +HRESULT RegMeta::GetNativeCallConvFromSig( // S_OK or error. + void const *pvSig, // [IN] Pointer to signature. + ULONG cbSig, // [IN] Count of signature bytes. + ULONG *pCallConv) // [OUT] Put calling conv here (see CorPinvokemap). +{ + HRESULT hr = NOERROR; + + BEGIN_ENTRYPOINT_NOTHROW; + + PCCOR_SIGNATURE pvSigBlob = reinterpret_cast<PCCOR_SIGNATURE>(pvSig); + ULONG cbTotal = 0; // total of number bytes for return type + all fixed arguments + ULONG cbCur = 0; // index through the pvSigBlob + ULONG cb; + ULONG cArg; + ULONG cTyArg = 0; + ULONG callingconv; + ULONG cArgsIndex; + ULONG callConv = pmCallConvWinapi; // The calling convention. + + + + + *pCallConv = pmCallConvWinapi; + + // remember the number of bytes to represent the calling convention + cb = CorSigUncompressData (pvSigBlob, &callingconv); + if (cb == ((ULONG)(-1))) + { + hr = CORSEC_E_INVALID_IMAGE_FORMAT; + goto ErrExit; + } + cbCur += cb; + + // remember the number of bytes to represent the type parameter count + if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC) + { + cb= CorSigUncompressData (&pvSigBlob[cbCur], &cTyArg); + if (cb == ((ULONG)(-1))) + { + hr = CORSEC_E_INVALID_IMAGE_FORMAT; + goto ErrExit; + } + cbCur += cb; + } + + + // remember number of bytes to represent the arg counts + cb= CorSigUncompressData (&pvSigBlob[cbCur], &cArg); + if (cb == ((ULONG)(-1))) + { + hr = CORSEC_E_INVALID_IMAGE_FORMAT; + goto ErrExit; + } + + cbCur += cb; + + // Look at the return type. + hr = _SearchOneArgForCallConv( &pvSigBlob[cbCur], &cb, &callConv); + if (hr == (HRESULT)-1) + { + *pCallConv = callConv; + hr = S_OK; + goto ErrExit; + } + IfFailGo(hr); + cbCur += cb; + cbTotal += cb; + + // loop through argument until we found ELEMENT_TYPE_SENTINEL or run + // out of arguments + for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++) + { + _ASSERTE(cbCur < cbSig); + hr = _SearchOneArgForCallConv( &pvSigBlob[cbCur], &cb, &callConv); + if (hr == (HRESULT)-1) + { + *pCallConv = callConv; + hr = S_OK; + goto ErrExit; + } + IfFailGo(hr); + cbTotal += cb; + cbCur += cb; + } + +ErrExit: + END_ENTRYPOINT_NOTHROW; + + return hr; +} // HRESULT RegMeta::GetNativeCallConvFromSig() + +//***************************************************************************** +// Helper used by GetNativeCallingConvFromSig. +//***************************************************************************** +HRESULT RegMeta::_CheckCmodForCallConv( // S_OK, -1 if found, or error. + PCCOR_SIGNATURE pbSig, // [IN] Signature to check. + ULONG *pcbTotal, // [OUT] Put bytes consumed here. + ULONG *pCallConv) // [OUT] If found, put calling convention here. +{ + ULONG cbTotal = 0; // Bytes consumed. + mdToken tk; // Token for callconv. + HRESULT hr = NOERROR; // A result. + LPCUTF8 szName=0; // Callconv name. + LPCUTF8 szNamespace=0; // Callconv namespace. + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + + _ASSERTE(pcbTotal); + + + + + // count the bytes for the token compression + cbTotal += CorSigUncompressToken(&pbSig[cbTotal], &tk); + + // workaround to skip nil tokens and TypeSpec tokens. + if (IsNilToken(tk) || TypeFromToken(tk) == mdtTypeSpec) + { + *pcbTotal = cbTotal; + goto ErrExit; + } + + // See if this token is a calling convention. + if (TypeFromToken(tk) == mdtTypeRef) + { + TypeRefRec *pTypeRefRec; + IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tk), &pTypeRefRec)); + IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName)); + IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace)); + } + else + if (TypeFromToken(tk) == mdtTypeDef) + { + TypeDefRec *pTypeDefRec; + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tk), &pTypeDefRec)); + IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName)); + IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace)); + } + + if ((szNamespace && szName) && + (strcmp(szNamespace, CMOD_CALLCONV_NAMESPACE) == 0 || + strcmp(szNamespace, CMOD_CALLCONV_NAMESPACE_OLD) == 0) ) + { + // Set the hr to -1, which is an unspecified 'error'. This will percolate + // back up to the caller, where the 'error' should be recognized. + hr=(HRESULT)-1; + if (strcmp(szName, CMOD_CALLCONV_NAME_CDECL) == 0) + *pCallConv = pmCallConvCdecl; + else + if (strcmp(szName, CMOD_CALLCONV_NAME_STDCALL) == 0) + *pCallConv = pmCallConvStdcall; + else + if (strcmp(szName, CMOD_CALLCONV_NAME_THISCALL) == 0) + *pCallConv = pmCallConvThiscall; + else + if (strcmp(szName, CMOD_CALLCONV_NAME_FASTCALL) == 0) + *pCallConv = pmCallConvFastcall; + else + hr = S_OK; // keep looking + IfFailGo(hr); + } + *pcbTotal = cbTotal; + +ErrExit: + + return hr; +} // HRESULT RegMeta::_CheckCmodForCallConv() + +//***************************************************************************** +// Helper used by GetNativeCallingConvFromSig. +//***************************************************************************** +HRESULT RegMeta::_SearchOneArgForCallConv(// S_OK, -1 if found, or error. + PCCOR_SIGNATURE pbSig, // [IN] Signature to check. + ULONG *pcbTotal, // [OUT] Put bytes consumed here. + ULONG *pCallConv) // [OUT] If found, put calling convention here. +{ + ULONG cb; + ULONG cbTotal = 0; + CorElementType ulElementType; + ULONG ulData; + ULONG ulTemp; + int iData; + mdToken tk; + ULONG cArg; + ULONG callingconv; + ULONG cArgsIndex; + HRESULT hr = NOERROR; + + _ASSERTE(pcbTotal); + + cbTotal += CorSigUncompressElementType(&pbSig[cbTotal], &ulElementType); + while (CorIsModifierElementType(ulElementType) || ulElementType == ELEMENT_TYPE_SENTINEL) + { + cbTotal += CorSigUncompressElementType(&pbSig[cbTotal], &ulElementType); + } + switch (ulElementType) + { + case ELEMENT_TYPE_SZARRAY: + // skip over base type + IfFailGo( _SearchOneArgForCallConv(&pbSig[cbTotal], &cb, pCallConv) ); + cbTotal += cb; + break; + + case ELEMENT_TYPE_VAR : + case ELEMENT_TYPE_MVAR : + // skip over index + cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData); + break; + + case ELEMENT_TYPE_GENERICINST : + // skip over generic type + IfFailGo( _SearchOneArgForCallConv(&pbSig[cbTotal], &cb, pCallConv) ); + cbTotal += cb; + + // skip over number of parameters + cbTotal += CorSigUncompressData(&pbSig[cbTotal], &cArg); + + // loop through type parameters + for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++) + { + IfFailGo( _SearchOneArgForCallConv( &pbSig[cbTotal], &cb, pCallConv) ); + cbTotal += cb; + } + + break; + + case ELEMENT_TYPE_FNPTR: + cbTotal += CorSigUncompressData (&pbSig[cbTotal], &callingconv); + + // remember number of bytes to represent the arg counts + cbTotal += CorSigUncompressData (&pbSig[cbTotal], &cArg); + + // how many bytes to represent the return type + IfFailGo( _SearchOneArgForCallConv( &pbSig[cbTotal], &cb, pCallConv) ); + cbTotal += cb; + + // loop through argument + for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++) + { + IfFailGo( _SearchOneArgForCallConv( &pbSig[cbTotal], &cb, pCallConv) ); + cbTotal += cb; + } + + break; + + case ELEMENT_TYPE_ARRAY: + // syntax : ARRAY BaseType <rank> [i size_1... size_i] [j lowerbound_1 ... lowerbound_j] + + // skip over base type + IfFailGo( _SearchOneArgForCallConv(&pbSig[cbTotal], &cb, pCallConv) ); + cbTotal += cb; + + // Parse for the rank + cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData); + + // if rank == 0, we are done + if (ulData == 0) + break; + + // any size of dimension specified? + cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData); + while (ulData--) + { + cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulTemp); + } + + // any lower bound specified? + cbTotal = CorSigUncompressData(&pbSig[cbTotal], &ulData); + + while (ulData--) + { + cbTotal += CorSigUncompressSignedInt(&pbSig[cbTotal], &iData); + } + + break; + case ELEMENT_TYPE_VALUETYPE: + case ELEMENT_TYPE_CLASS: + // count the bytes for the token compression + cbTotal += CorSigUncompressToken(&pbSig[cbTotal], &tk); + break; + case ELEMENT_TYPE_CMOD_REQD: + case ELEMENT_TYPE_CMOD_OPT: + // Check for the calling convention. + IfFailGo(_CheckCmodForCallConv(&pbSig[cbTotal], &cb, pCallConv)); + cbTotal += cb; + // skip over base type + IfFailGo( _SearchOneArgForCallConv(&pbSig[cbTotal], &cb, pCallConv) ); + cbTotal += cb; + break; + default: + break; + } + *pcbTotal = cbTotal; + +ErrExit: + + return hr; +} // HRESULT RegMeta::_SearchOneArgForCallConv() |