summaryrefslogtreecommitdiff
path: root/src/md/compiler/import.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/compiler/import.cpp')
-rw-r--r--src/md/compiler/import.cpp3809
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()