diff options
Diffstat (limited to 'src/md/inc')
-rw-r--r-- | src/md/inc/.gitmirror | 1 | ||||
-rw-r--r-- | src/md/inc/VerifyLayouts.inc | 351 | ||||
-rw-r--r-- | src/md/inc/assemblymdinternaldisp.h | 723 | ||||
-rw-r--r-- | src/md/inc/cahlprinternal.h | 94 | ||||
-rw-r--r-- | src/md/inc/imptlb.h | 777 | ||||
-rw-r--r-- | src/md/inc/liteweightstgdb.h | 257 | ||||
-rw-r--r-- | src/md/inc/mdcolumndescriptors.h | 51 | ||||
-rw-r--r-- | src/md/inc/mdfileformat.h | 269 | ||||
-rw-r--r-- | src/md/inc/mdinternalrw.h | 862 | ||||
-rw-r--r-- | src/md/inc/mdlog.h | 25 | ||||
-rw-r--r-- | src/md/inc/metadatahash.h | 207 | ||||
-rw-r--r-- | src/md/inc/metamodel.h | 2072 | ||||
-rw-r--r-- | src/md/inc/metamodelro.h | 240 | ||||
-rw-r--r-- | src/md/inc/metamodelrw.h | 1479 | ||||
-rw-r--r-- | src/md/inc/recordpool.h | 161 | ||||
-rw-r--r-- | src/md/inc/rwutil.h | 369 | ||||
-rw-r--r-- | src/md/inc/stgio.h | 293 | ||||
-rw-r--r-- | src/md/inc/stgtiggerstorage.h | 328 | ||||
-rw-r--r-- | src/md/inc/stgtiggerstream.h | 112 | ||||
-rw-r--r-- | src/md/inc/streamutil.h | 221 | ||||
-rw-r--r-- | src/md/inc/verifylayouts.h | 186 | ||||
-rw-r--r-- | src/md/inc/winmdinterfaces.h | 120 |
22 files changed, 9198 insertions, 0 deletions
diff --git a/src/md/inc/.gitmirror b/src/md/inc/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/inc/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/md/inc/VerifyLayouts.inc b/src/md/inc/VerifyLayouts.inc new file mode 100644 index 0000000000..4c0bd65b30 --- /dev/null +++ b/src/md/inc/VerifyLayouts.inc @@ -0,0 +1,351 @@ +// 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. + + +// This file provides an explicit check of field layouts using some macro magic +// in VerifyLayouts.h. The goal is that if any field changes offset or type changes +// size then a build time assert should trigger. DO NOT change these definitions without +// reading the comments in VerifyLayouts.h and understanding what other code you need +// to change at the same time. +// +// +// AN EXAMPLE: +// You want to validate the fields in type CDerived +// +// class CFoo +// { +// void* m_ptrField; +// } +// +// struct BigStruct +// { +// DWORD m_one; +// DWORD m_two; +// DWORD m_three; +// } +// +// CDerived : CFoo +// { +// DWORD m_cRef; +// SomeOtherType* m_otherType; +// #ifdef _SOME_DEFINE +// BigStruct m_struct; +// #endif //_SOME_DEFINE +// } +// +// +// and the layout validation is written as: +// +// BEGIN_TYPE(CDerived, sizeof(CFoo)) // a) The first field starts at sizeof(CFoo) to account for base class data +// // b) Beware of vtable pointers, they take up space before the data fields too +// // c) Beware of using sizeof(some_other_type) unless you also explicitly verify +// // the layout of that type here. Changing the base type would change the derived types +// // layout and won't be caught unless the base type is explicitly verified. +// // d) sizeof(<primitive_type>) is fine - they never change over time and we know how +// // to deal with platform pointer size differences +// FIELD(CDerived, m_cRef, 4) +// FIELD(CDerived, m_otherType, sizeof(void*)) +// #ifdef _SOME_DEFINE_ +// ALIGN_FIELD(CDerived, m_struct, sizeof(BigStruct), 4) // We need to use the ALIGN_FIELD macro because the alignment isn't the same as +// // the field size. The alignment of a structure is typically the max alignment +// // of any member. The alignment of a primitive type is typically the size of the type. +// #endif _SOME_DEFINE_ +// END_TYPE(CDerived, sizeof(void*) +// +// +// BEGIN_TYPE(CFoo, 0) // We must verify this type because we used it to define the starting offset of CDerived +// FIELD(CFoo, m_ptrField, sizeof(void*)) +// END_TYPE(CFoo, sizeof(void*)) +// +// +// BEGIN_TYPE(BigStruct, 0) // We must verify this type because we used sizeof(BigStruct) to define the size of +// // CDerived::m_struct field +// FIELD(BigStruct, m_one, 4) +// FIELD(BigStruct, m_two, 4) +// FIELD(BigStruct, m_thee, 4) +// END_TYPE(BigStruct, 4) +// +// +// +// +// OTHER CONSIDERATIONS: +// +// 1) if the type layout is conditional on a define, just include the same define here in the layout verification +// Make sure that the define is registered in the list of defines and the debugger reading code knows how to dynamically +// adjust for it (See VerifyLayouts.h comment item (b) and (c)) +// +// 2) If your type names use characters that aren't valid identifiers (such as the '<' and '>' chars in templates) +// then you need to provide an escaped name. There are variations of the macros above to do that: +// BEGIN_TYPE_ESCAPED(typeName, escaptedTypeName, firstFieldOffset) +// FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize) +// ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldAlign) +// END_TYPE_ESCAPED(typeName, escapedTypeName, typeAlignment) +// +// If CFoo above had instead been CFoo<ULONG> we would write: +// BEGIN_TYPE_ESCAPED(CFoo<ULONG>, CFoo__ULONG__, 0) +// FIELD_ESCAPED(CFoo<ULONG>, CFoo__ULONG__, m_ptrField, sizeof(void*)) +// END_TYPE_ESCAPED(CFoo<ULONG>, CFoo__ULONG__, sizeof(void*)) +// +// The escapedTypeName is relatively arbitrary, but convention is to replace the illegal characters with double underscore +// The name does show up in build error messages, so it should close to the real name for people to understand +// +// 3) If your type name has commas in it (such as in a list of template arguments) the macros could interpret it as seperate +// arguments (no good). To fix this use the IGNORE_COMMAS() macro to escape any typeNames with commas. If CFoo above had +// been CFoo<ULONG,INT> you could rewrite the defines as: +// BEGIN_TYPE_ESCAPED(IGNORE_COMMAS(CFoo<ULONG,INT>), CFoo__ULONG__INT__, 0) +// FIELD_ESCAPED(IGNORE_COMMAS(CFoo<ULONG,INT>), CFoo__ULONG__INT__, m_ptrField, sizeof(void*)) +// END_TYPE_ESCAPED(IGNORE_COMMAS(CFoo<ULONG,INT>), CFoo__ULONG__INT__, sizeof(void*)) +// +// 4) If you have a bitfield in your type, the offsetof macro can't be used which will break the static asserts. +// There is a special BITFIELD macro that can work around it: +// BITFIELD(typeName, fieldName, expectedFieldOffset, fieldSize, fieldAlign) +// +// The macro is just like FIELD execpt you must provide the offset yourself. Since you can't use offsetof on the field directly +// the convention is to use the offset of the previous field and then add the size and alignment requirements. For example if your +// type had this: +// CMiniMdRW +// { +// ULONG m_cbSaveSize; +// int m_fIsReadOnly : 1; +// int m_bPreSaveDone : 1; +// int m_bSaveCompressed : 1; +// int m_bPostGSSMod : 1; +// } +// +// You could write +// FIELD(CMiniMdRW, m_cbSaveSize, 4) +// BITFIELD(CMiniMdRW, m_fIsReadOnly, offsetof(CMiniMdRW, m_cbSaveSize)+4, 4) +// +// Don't include al the fields in the bitfield, just pick one as the canonical field name +// +// +// +// HOW DO I DEBUG THIS STUFF WHEN THE BUILD DOESN'T WORK? +// +// One way that has been effective for me is to write a few static_assert_no_msg entries manually in VerifyLayouts.h +// You can use those to verify your assumptions such as: +// static_assert_no_msg(sizeof(Foo) == 24) +// static_assert_no_msg(offset(Foo, m_lastField) == 20) +// static_assert_no_msg(offset_of_field_affter_Foo_m_lastField == 24) +// Then rebuild and find out where the compiler disagress with you. +// +// Another option is to run the source through the preprocessor +// +// +// + + + + + + +BEGIN_TYPE(MDInternalRW, 2*sizeof(void*)) +FIELD(MDInternalRW, m_pStgdb, sizeof(void*)) +FIELD(MDInternalRW, m_tdModule, 4) +FIELD(MDInternalRW, m_cRefs, 4) +FIELD(MDInternalRW, m_fOwnStgdb, 4) +FIELD(MDInternalRW, m_pUnk, sizeof(void*)) +FIELD(MDInternalRW, m_pUserUnk, sizeof(void*)) +FIELD(MDInternalRW, m_pIMetaDataHelper, sizeof(void*)) +FIELD(MDInternalRW, m_pSemReadWrite, sizeof(void*)) +FIELD(MDInternalRW, m_fOwnSem, 4) +END_TYPE(MDInternalRW, sizeof(void*)) + +BEGIN_TYPE(CLiteWeightStgdbRW, sizeof(CLiteWeightStgdb<CMiniMdRW>)) +FIELD(CLiteWeightStgdbRW, m_cbSaveSize, 4) +FIELD(CLiteWeightStgdbRW, m_bSaveCompressed, 4) +FIELD(CLiteWeightStgdbRW, m_pImage, sizeof(void*)) +FIELD(CLiteWeightStgdbRW, m_dwImageSize, 4) +FIELD(CLiteWeightStgdbRW, m_dwPEKind, 4) +FIELD(CLiteWeightStgdbRW, m_dwMachine, 4) +FIELD(CLiteWeightStgdbRW, m_pStreamList, sizeof(void*)) +FIELD(CLiteWeightStgdbRW, m_pNextStgdb, sizeof(void*)) +FIELD(CLiteWeightStgdbRW, m_eFileType, 4) +FIELD(CLiteWeightStgdbRW, m_wszFileName, sizeof(void*)) +FIELD(CLiteWeightStgdbRW, m_dwDatabaseLFT, 4) +FIELD(CLiteWeightStgdbRW, m_dwDatabaseLFS, 4) +FIELD(CLiteWeightStgdbRW, m_pStgIO, sizeof(void*)) +END_TYPE(CLiteWeightStgdbRW, 8) + +BEGIN_TYPE_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, 0) +ALIGN_FIELD_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, m_MiniMd, sizeof(CMiniMdRW), sizeof(void*)) +FIELD_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, m_pvMd, sizeof(void*)) +FIELD_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, m_cbMd, 4) +END_TYPE_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, sizeof(void*)) + +BEGIN_TYPE(CMiniMdRW, sizeof(CMiniMdTemplate<CMiniMdRW>)) +FIELD(CMiniMdRW, m_pMemberRefHash, sizeof(void*)) +FIELD(CMiniMdRW, m_pMemberDefHash, sizeof(void*)) +ALIGN_FIELD(CMiniMdRW, m_pLookUpHashs, sizeof(void*)*TBL_COUNT, sizeof(void*)) +ALIGN_FIELD(CMiniMdRW, m_StringPoolOffsetHash, sizeof(MapSHash<UINT32, UINT32>), 4) +FIELD(CMiniMdRW, m_pNamedItemHash, sizeof(void*)) +FIELD(CMiniMdRW, m_maxRid, 4) +FIELD(CMiniMdRW, m_limRid, 4) +FIELD(CMiniMdRW, m_maxIx, 4) +FIELD(CMiniMdRW, m_limIx, 4) +FIELD(CMiniMdRW, m_eGrow, 4) +ALIGN_FIELD(CMiniMdRW, m_Tables, sizeof(RecordPool)*TBL_COUNT, sizeof(void*)) +ALIGN_FIELD(CMiniMdRW, m_pVS, sizeof(void*)*TBL_COUNT, sizeof(void*)) +ALIGN_FIELD(CMiniMdRW, m_StringHeap, sizeof(StgStringPool), sizeof(void*)) +ALIGN_FIELD(CMiniMdRW, m_BlobHeap, sizeof(StgBlobPool), sizeof(void*)) +ALIGN_FIELD(CMiniMdRW, m_UserStringHeap, sizeof(StgBlobPool), sizeof(void*)) +ALIGN_FIELD(CMiniMdRW, m_GuidHeap, sizeof(StgGuidPool), sizeof(void*)) +FIELD(CMiniMdRW, m_pHandler, sizeof(void*)) +FIELD(CMiniMdRW, m_cbSaveSize, 4) +BITFIELD(CMiniMdRW, m_fIsReadOnly, offsetof(CMiniMdRW, m_cbSaveSize)+4, 4) +FIELD(CMiniMdRW, m_pMethodMap, sizeof(void*)) +FIELD(CMiniMdRW, m_pFieldMap, sizeof(void*)) +FIELD(CMiniMdRW, m_pPropertyMap, sizeof(void*)) +FIELD(CMiniMdRW, m_pEventMap, sizeof(void*)) +FIELD(CMiniMdRW, m_pParamMap, sizeof(void*)) +FIELD(CMiniMdRW, m_pFilterTable, sizeof(void*)) +FIELD(CMiniMdRW, m_pHostFilter, sizeof(void*)) +FIELD(CMiniMdRW, m_pTokenRemapManager, sizeof(void*)) +ALIGN_FIELD(CMiniMdRW, m_OptionValue, sizeof(OptionValue), 4) +ALIGN_FIELD(CMiniMdRW, m_StartupSchema, sizeof(CMiniMdSchema), 8) +ALIGN_FIELD(CMiniMdRW, m_bSortable, sizeof(BYTE)*TBL_COUNT, sizeof(BYTE)) +#ifdef _DEBUG +FIELD(CMiniMdRW, dbg_m_pLock, sizeof(void*)) +#endif +FIELD(CMiniMdRW, m_fMinimalDelta, 4) +FIELD(CMiniMdRW, m_rENCRecs, sizeof(void*)) +END_TYPE(CMiniMdRW, 8) + +BEGIN_TYPE(OptionValue, 0) +FIELD(OptionValue, m_DupCheck, 4) +FIELD(OptionValue, m_RefToDefCheck, 4) +FIELD(OptionValue, m_NotifyRemap, 4) +FIELD(OptionValue, m_UpdateMode, 4) +FIELD(OptionValue, m_ErrorIfEmitOutOfOrder, 4) +FIELD(OptionValue, m_ThreadSafetyOptions, 4) +FIELD(OptionValue, m_ImportOption, 4) +FIELD(OptionValue, m_LinkerOption, 4) +FIELD(OptionValue, m_GenerateTCEAdapters, 4) +FIELD(OptionValue, m_RuntimeVersion, sizeof(void*)) +FIELD(OptionValue, m_MetadataVersion, 4) +FIELD(OptionValue, m_MergeOptions, 4) +FIELD(OptionValue, m_InitialSize, 4) +FIELD(OptionValue, m_LocalRefPreservation, 4) +END_TYPE(OptionValue, sizeof(void*)) + + +BEGIN_TYPE(StgBlobPool, sizeof(StgPool)) +ALIGN_FIELD(StgBlobPool, m_Hash, sizeof(CBlobPoolHash), sizeof(void*)) +END_TYPE(StgBlobPool, sizeof(void*)) + +BEGIN_TYPE(StgStringPool, sizeof(StgPool)) +ALIGN_FIELD(StgStringPool, m_Hash, sizeof(CStringPoolHash), sizeof(void*)) +FIELD(StgStringPool, m_bHash, sizeof(BOOL)) +END_TYPE(StgStringPool, sizeof(void*)) + +BEGIN_TYPE(StgGuidPool, sizeof(StgPool)) +ALIGN_FIELD(StgGuidPool, m_Hash, sizeof(CGuidPoolHash), sizeof(void*)) +FIELD(StgGuidPool, m_bHash, sizeof(BOOL)) +END_TYPE(StgGuidPool, sizeof(void*)) + +BEGIN_TYPE(RecordPool, sizeof(StgPool)) +FIELD(RecordPool, m_cbRec, 4) +END_TYPE(RecordPool, sizeof(void*)) + +BEGIN_TYPE(StgPool, sizeof(StgPoolReadOnly)) +FIELD(StgPool, m_ulGrowInc, 4) +FIELD(StgPool, m_pCurSeg, sizeof(void*)) +FIELD(StgPool, m_cbCurSegOffset, 4) +BITFIELD(StgPool, m_bFree, offsetof(StgPool, m_cbCurSegOffset)+4, 4) // can't take offsetof on a bitfield so we have to provide the offset another way +FIELD(StgPool, m_nVariableAlignmentMask, 4) +FIELD(StgPool, m_cbStartOffsetOfEdit, 4) +FIELD(StgPool, m_fValidOffsetOfEdit, 4) +END_TYPE(StgPool, sizeof(void*)) + + +BEGIN_TYPE(CStringPoolHash, sizeof(CChainedHash<STRINGHASH>)) +FIELD(CStringPoolHash, m_Pool, sizeof(void*)) +END_TYPE(CStringPoolHash, sizeof(void*)) + + +BEGIN_TYPE(CBlobPoolHash, sizeof(CChainedHash<STRINGHASH>)) +FIELD(CBlobPoolHash, m_Pool, sizeof(void*)) +END_TYPE(CStringPoolHash, sizeof(void*)) + + +BEGIN_TYPE(CGuidPoolHash, sizeof(CChainedHash<GUIDHASH>)) +FIELD(CGuidPoolHash, m_Pool, sizeof(void*)) +END_TYPE(CGuidPoolHash, sizeof(void*)) + + +BEGIN_TYPE_ESCAPED(MetaData::HotHeap, MetaData__HotHeap, 0) +FIELD_ESCAPED(MetaData::HotHeap, MetaData__HotHeap, m_pHotHeapHeader, sizeof(void*)) +END_TYPE_ESCAPED(MetaData::HotHeap, MetaData__HotHeap, sizeof(void*)) + + +BEGIN_TYPE(StgPoolReadOnly, sizeof(StgPoolSeg) + sizeof(void*)) //vtable pointer +ALIGN_FIELD(StgPoolReadOnly, m_HotHeap, sizeof(MetaData::HotHeap), sizeof(void*)) +END_TYPE(StgPoolReadOnly, sizeof(void*)) + +BEGIN_TYPE_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, sizeof(void*)) +FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_table, sizeof(void*)) +FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableSize, 4) +FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableCount, 4) +FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableOccupied, 4) +FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableMax, 4) +END_TYPE_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, sizeof(void*)) + + +BEGIN_TYPE(StgPoolSeg, 0) +FIELD(StgPoolSeg, m_pSegData, sizeof(void*)) +FIELD(StgPoolSeg, m_pNextSeg, sizeof(void*)) +FIELD(StgPoolSeg, m_cbSegSize, 4) +FIELD(StgPoolSeg, m_cbSegNext, 4) +END_TYPE(StgPoolSeg, sizeof(void*)) + + +BEGIN_TYPE_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, sizeof(void*)) // vtable pointer +FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_rgData, sizeof(void*)) +FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iBuckets, 4) +FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iSize, 4) +FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iCount, 4) +FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iMaxChain, 4) +FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iFree, 4) +END_TYPE_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, sizeof(void*)) + + +BEGIN_TYPE(CMiniColDef, 0) +FIELD(CMiniColDef, m_Type, 1) +FIELD(CMiniColDef, m_oColumn, 1) +FIELD(CMiniColDef, m_cbColumn, 1) +END_TYPE(CMiniColDef, 1) + + +BEGIN_TYPE(CMiniTableDef, 0) +FIELD(CMiniTableDef, m_pColDefs, sizeof(void*)) +FIELD(CMiniTableDef, m_cCols, 1) +FIELD(CMiniTableDef, m_iKey, 1) +FIELD(CMiniTableDef, m_cbRec, 1) +END_TYPE(CMiniTableDef, sizeof(void*)) + +BEGIN_TYPE(CMiniMdBase, 8) //vtable ptr and first field 8-byte alignment +ALIGN_FIELD(CMiniMdBase, m_Schema, sizeof(CMiniMdSchema), 8) +FIELD(CMiniMdBase, m_TblCount, 4) +FIELD(CMiniMdBase, m_fVerifiedByTrustedSource, 4) +ALIGN_FIELD(CMiniMdBase, m_TableDefs, sizeof(CMiniTableDef)*TBL_COUNT, sizeof(void*)) +FIELD(CMiniMdBase, m_iStringsMask, 4) +FIELD(CMiniMdBase, m_iGuidsMask, 4) +FIELD(CMiniMdBase, m_iBlobsMask, 4) +END_TYPE(CMiniMdBase, 8) + + +BEGIN_TYPE(CMiniMdSchemaBase, 0) +FIELD(CMiniMdSchemaBase, m_ulReserved, 4) +FIELD(CMiniMdSchemaBase, m_major, 1) +FIELD(CMiniMdSchemaBase, m_minor, 1) +FIELD(CMiniMdSchemaBase, m_heaps, 1) +FIELD(CMiniMdSchemaBase, m_rid, 1) +FIELD(CMiniMdSchemaBase, m_maskvalid, 8) +FIELD(CMiniMdSchemaBase, m_sorted, 8) +END_TYPE(CMiniMdSchemaBase, 8) + +BEGIN_TYPE(CMiniMdSchema, sizeof(CMiniMdSchemaBase)) +ALIGN_FIELD(CMiniMdSchema, m_cRecs, 4*TBL_COUNT, 4) +FIELD(CMiniMdSchema, m_ulExtra, 4) +END_TYPE(CMiniMdSchema, 8) diff --git a/src/md/inc/assemblymdinternaldisp.h b/src/md/inc/assemblymdinternaldisp.h new file mode 100644 index 0000000000..91b7d2cc29 --- /dev/null +++ b/src/md/inc/assemblymdinternaldisp.h @@ -0,0 +1,723 @@ +// 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. +//***************************************************************************** +// AssemblyMDInternalDispenser.h +// + +// +// Contains utility code for MD directory +// +//***************************************************************************** +#ifndef __AssemblyMDInternalDispenser__h__ +#define __AssemblyMDInternalDispenser__h__ + +#include "../runtime/mdinternalro.h" + +#ifdef FEATURE_FUSION + +#include "fusionpriv.h" + +struct CORCOMPILE_VERSION_INFO; +struct CORCOMPILE_DEPENDENCY; + +//***************************************************************************** +// This class can support the IMetaDataAssemblyImport and some funcationalities +// of IMetaDataImport on the internal import interface (IMDInternalImport). +//***************************************************************************** +class AssemblyMDInternalImport : + public IMetaDataAssemblyImport, + public IMetaDataImport2, +#ifdef FEATURE_PREJIT + public IGetIMDInternalImport, +#endif //FEATURE_PREJIT + public ISNAssemblySignature +#ifdef FEATURE_PREJIT + , public INativeImageInstallInfo +#endif // FEATURE_PREJIT +{ +public: + AssemblyMDInternalImport(IMDInternalImport *pMDInternalImport); + ~AssemblyMDInternalImport(); + + // *** IUnknown methods *** + STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + + // *** IMetaDataAssemblyImport methods *** + STDMETHODIMP GetAssemblyProps ( // S_OK or error. + mdAssembly mda, // [IN] The Assembly for which to get the properties. + const void **ppbPublicKey, // [OUT] Pointer to the public key. + ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key. + ULONG *pulHashAlgId, // [OUT] Hash Algorithm. + __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + ASSEMBLYMETADATA *pMetaData, // [OUT] Assembly MetaData. + DWORD *pdwAssemblyFlags); // [OUT] Flags. + + STDMETHODIMP GetAssemblyRefProps ( // S_OK or error. + mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties. + const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token. + ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. + __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + ASSEMBLYMETADATA *pMetaData, // [OUT] Assembly MetaData. + const void **ppbHashValue, // [OUT] Hash blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the hash blob. + DWORD *pdwAssemblyRefFlags); // [OUT] Flags. + + STDMETHODIMP GetFileProps ( // S_OK or error. + mdFile mdf, // [IN] The File for which to get the properties. + __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the Hash Value Blob. + DWORD *pdwFileFlags); // [OUT] Flags. + + STDMETHODIMP GetExportedTypeProps ( // S_OK or error. + mdExportedType mdct, // [IN] The ExportedType for which to get the properties. + __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef or mdExportedType. + mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file. + DWORD *pdwExportedTypeFlags); // [OUT] Flags. + + STDMETHODIMP GetManifestResourceProps ( // S_OK or error. + mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties. + __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ManifestResource. + DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file. + DWORD *pdwResourceFlags); // [OUT] Flags. + + STDMETHODIMP EnumAssemblyRefs ( // S_OK or error + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdAssemblyRef rAssemblyRefs[], // [OUT] Put AssemblyRefs here. + ULONG cMax, // [IN] Max AssemblyRefs to put. + ULONG *pcTokens); // [OUT] Put # put here. + + STDMETHODIMP EnumFiles ( // S_OK or error + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdFile rFiles[], // [OUT] Put Files here. + ULONG cMax, // [IN] Max Files to put. + ULONG *pcTokens); // [OUT] Put # put here. + + STDMETHODIMP EnumExportedTypes ( // S_OK or error + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdExportedType rExportedTypes[], // [OUT] Put ExportedTypes here. + ULONG cMax, // [IN] Max ExportedTypes to put. + ULONG *pcTokens); // [OUT] Put # put here. + + STDMETHODIMP EnumManifestResources ( // S_OK or error + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdManifestResource rManifestResources[], // [OUT] Put ManifestResources here. + ULONG cMax, // [IN] Max Resources to put. + ULONG *pcTokens); // [OUT] Put # put here. + + STDMETHODIMP GetAssemblyFromScope ( // S_OK or error + mdAssembly *ptkAssembly); // [OUT] Put token here. + + STDMETHODIMP FindExportedTypeByName ( // S_OK or error + LPCWSTR szName, // [IN] Name of the ExportedType. + mdToken mdtExportedType, // [IN] ExportedType for the enclosing class. + mdExportedType *ptkExportedType); // [OUT] Put the ExportedType token here. + + STDMETHODIMP FindManifestResourceByName ( // S_OK or error + LPCWSTR szName, // [IN] Name of the ManifestResource. + mdManifestResource *ptkManifestResource); // [OUT] Put the ManifestResource token here. + + STDMETHOD_(void, CloseEnum)( + HCORENUM hEnum); // Enum to be closed. + + STDMETHODIMP FindAssembliesByName ( // S_OK or error + LPCWSTR szAppBase, // [IN] optional - can be NULL + LPCWSTR szPrivateBin, // [IN] optional - can be NULL + LPCWSTR szAssemblyName, // [IN] required - this is the assembly you are requesting + IUnknown *ppIUnk[], // [OUT] put IMetaDataAssemblyImport pointers here + ULONG cMax, // [IN] The max number to put + ULONG *pcAssemblies); // [OUT] The number of assemblies returned. + + // *** IMetaDataImport methods *** + STDMETHOD(CountEnum)(HCORENUM hEnum, ULONG *pulCount); + STDMETHOD(ResetEnum)(HCORENUM hEnum, ULONG ulPos); + STDMETHOD(EnumTypeDefs)(HCORENUM *phEnum, mdTypeDef rTypeDefs[], + ULONG cMax, ULONG *pcTypeDefs); + STDMETHOD(EnumInterfaceImpls)(HCORENUM *phEnum, mdTypeDef td, + mdInterfaceImpl rImpls[], ULONG cMax, + ULONG* pcImpls); + STDMETHOD(EnumTypeRefs)(HCORENUM *phEnum, mdTypeRef rTypeRefs[], + ULONG cMax, ULONG* pcTypeRefs); + + STDMETHOD(FindTypeDefByName)( // S_OK or error. + LPCWSTR szTypeDef, // [IN] Name of the Type. + mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef for Enclosing class. + mdTypeDef *ptd); // [OUT] Put the TypeDef token here. + + STDMETHOD(GetScopeProps)( + __out_ecount_part_opt(cchName, *pchName) + LPWSTR wszName, // [OUT] Put the name here. + ULONG cchName, // [IN] Size of name buffer in wide chars. + ULONG * pchName, // [OUT] Put size of name (wide chars) here. + GUID * pMvid); // [OUT, OPTIONAL] Put MVID here. + + STDMETHOD(GetModuleFromScope)( // S_OK. + mdModule *pmd); // [OUT] Put mdModule token here. + + STDMETHOD(GetTypeDefProps)( + mdTypeDef td, // [IN] TypeDef token for inquiry. + __out_ecount_part_opt(cchTypeDef, *pchTypeDef) + LPWSTR wszTypeDef, // [OUT] Put name here. + ULONG cchTypeDef, // [IN] size of name buffer in wide chars. + ULONG * pchTypeDef, // [OUT] put size of name (wide chars) here. + DWORD * pdwTypeDefFlags, // [OUT] Put flags here. + mdToken * ptkExtends); // [OUT] Put base class TypeDef/TypeRef here. + + STDMETHOD(GetInterfaceImplProps)( // S_OK or error. + mdInterfaceImpl iiImpl, // [IN] InterfaceImpl token. + mdTypeDef *pClass, // [OUT] Put implementing class token here. + mdToken *ptkIface); // [OUT] Put implemented interface token here. + + STDMETHOD(GetTypeRefProps)( + mdTypeRef tr, // [IN] TypeRef token. + mdToken * ptkResolutionScope, // [OUT] Resolution scope, ModuleRef or AssemblyRef. + __out_ecount_part_opt(cchName, *pchName) + LPWSTR wszName, // [OUT] Name of the TypeRef. + ULONG cchName, // [IN] Size of buffer. + ULONG * pchName); // [OUT] Size of Name. + + STDMETHOD(ResolveTypeRef)(mdTypeRef tr, REFIID riid, IUnknown **ppIScope, mdTypeDef *ptd); + + STDMETHOD(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. + + STDMETHOD(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. + + STDMETHOD(EnumMethods)( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [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. + + STDMETHOD(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. + + STDMETHOD(EnumFields)( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [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. + + STDMETHOD(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. + + + STDMETHOD(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. + + STDMETHOD(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. + + STDMETHOD(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. + + STDMETHOD(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. + + STDMETHOD(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 + + STDMETHOD(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 + + STDMETHOD(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 + + STDMETHOD(FindMemberRef)( + mdTypeRef td, // [IN] given typeRef + 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 + + STDMETHOD (GetMethodProps)( + mdMethodDef mb, // The method for which to get props. + mdTypeDef * pClass, // Put method's class here. + __out_ecount_part_opt(cchMethod, *pchMethod) + LPWSTR wszMethod, // 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 + + STDMETHOD(GetMemberRefProps)( + mdMemberRef mr, // [IN] given memberref + mdToken * ptk, // [OUT] Put classref or classdef here. + __out_ecount_part_opt(cchMember, *pchMember) + LPWSTR wszMember, // [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 + + STDMETHOD(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. + + STDMETHOD(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. + + STDMETHOD(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 + + STDMETHOD(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. + + STDMETHOD(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 + + STDMETHOD(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 + + STDMETHOD(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 + + STDMETHOD(GetRVA)( // S_OK or error. + mdToken tk, // Member for which to set offset + ULONG *pulCodeRVA, // The offset + DWORD *pdwImplFlags); // the implementation flags + + STDMETHOD(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. + + STDMETHOD(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. + + STDMETHOD(GetModuleRefProps)( + mdModuleRef mur, // [IN] moduleref token. + __out_ecount_part_opt(cchName, *pchName) + LPWSTR wszName, // [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. + + STDMETHOD(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. + + STDMETHOD(GetTypeSpecFromToken)( // S_OK or error. + mdTypeSpec typespec, // [IN] TypeSpec token. + PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to TypeSpec signature + ULONG *pcbSig); // [OUT] return size of signature. + + STDMETHOD(GetNameFromToken)( // <TODO>Not Recommended! May be removed!</TODO> + mdToken tk, // [IN] Token to get name from. Must have a name. + MDUTF8CSTR *pszUtf8NamePtr); // [OUT] Return pointer to UTF8 name in heap. + + STDMETHOD(EnumUnresolvedMethods)( // S_OK, S_FALSE, 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. + + STDMETHOD(GetUserString)( + mdString stk, // [IN] String token. + __out_ecount_part_opt(cchString, *pchString) + LPWSTR wszString, // [OUT] Copy of string. + ULONG cchString, // [IN] Max chars of room in szString. + ULONG * pchString); // [OUT] How many chars in actual string. + + STDMETHOD(GetPinvokeMap)( + mdToken tk, // [IN] FieldDef or MethodDef. + DWORD * pdwMappingFlags, // [OUT] Flags used for mapping. + __out_ecount_part_opt(cchImportName, *pchImportName) + LPWSTR wszImportName, // [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. + + STDMETHOD(EnumSignatures)( // S_OK or error. + HCORENUM *phEnum, // [IN|OUT] pointer to the enum. + mdSignature rSignatures[], // [OUT] put signatures here. + ULONG cmax, // [IN] max signatures to put. + ULONG *pcSignatures); // [OUT] put # put here. + + STDMETHOD(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. + + STDMETHOD(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. + + STDMETHOD(GetParamForMethodIndex)( // S_OK or error. + mdMethodDef md, // [IN] Method token. + ULONG ulParamSeq, // [IN] Parameter sequence. + mdParamDef *ppd); // [IN] Put Param token here. + + STDMETHOD(EnumCustomAttributes)( // S_OK or error. + HCORENUM *phEnum, // [IN, OUT] COR enumerator. + mdToken tk, // [IN] Token to scope the enumeration, 0 for all. + mdToken tkType, // [IN] Type of interest, 0 for all. + mdCustomAttribute rCustomAttributes[], // [OUT] Put custom attribute tokens here. + ULONG cMax, // [IN] Size of rCustomAttributes. + ULONG *pcCustomAttributes); // [OUT, OPTIONAL] Put count of token values here. + + STDMETHOD(GetCustomAttributeProps)( // S_OK or error. + mdCustomAttribute cv, // [IN] CustomAttribute token. + mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here. + mdToken *ptkType, // [OUT, OPTIONAL] Put AttrType token here. + void const **ppBlob, // [OUT, OPTIONAL] Put pointer to data here. + ULONG *pcbSize); // [OUT, OPTIONAL] Put size of date here. + + STDMETHOD(FindTypeRef)( + mdToken tkResolutionScope, // [IN] ModuleRef, AssemblyRef or TypeRef. + LPCWSTR szName, // [IN] TypeRef Name. + mdTypeRef *ptr); // [OUT] matching TypeRef. + + STDMETHOD(GetMemberProps)( + mdToken mb, // The member for which to get props. + mdTypeDef * pClass, // Put member's class here. + __out_ecount_part_opt(cchMember, *pchMember) + LPWSTR wszMember, // 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 * pcchValue); // [OUT] size of constant string in chars, 0 for non-strings. + + STDMETHOD(GetFieldProps)( + mdFieldDef mb, // The field for which to get props. + mdTypeDef * pClass, // Put field's class here. + __out_ecount_part_opt(cchField, *pchField) + 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 * pcchValue); // [OUT] size of constant string in chars, 0 for non-strings. + + STDMETHOD(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 *pcchDefaultValue, // [OUT] size of constant string in chars, 0 for non-strings. + 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 + + STDMETHOD(GetParamProps)( + mdParamDef tk, // [IN]The Parameter. + mdMethodDef * pmd, // [OUT] Parent Method token. + ULONG * pulSequence, // [OUT] Parameter sequence. + __out_ecount_part_opt(cchName, *pchName) + LPWSTR wszName, // [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 * pcchValue); // [OUT] size of constant string in chars, 0 for non-strings. + + STDMETHOD(GetCustomAttributeByName)( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCWSTR szName, // [IN] Name of desired Custom Attribute. + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData); // [OUT] Put size of data here. + + STDMETHOD_(BOOL, IsValidToken)( // True or False. + mdToken tk); // [IN] Given token. + + STDMETHOD(GetNestedClassProps)( // S_OK or error. + mdTypeDef tdNestedClass, // [IN] NestedClass token. + mdTypeDef *ptdEnclosingClass); // [OUT] EnclosingClass token. + + STDMETHOD(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). + + STDMETHOD(IsGlobal)( // S_OK or error. + mdToken pd, // [IN] Type, Field, or Method token. + int *pbGlobal); // [OUT] Put 1 if global, 0 otherwise. + +//***************************************************************************** +// IMetaDataImport2 methods +//***************************************************************************** + STDMETHOD(GetMethodSpecProps)( + 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 + + STDMETHOD(GetGenericParamProps)( + mdGenericParam gp, // [IN] GenericParam + ULONG * pulParamSeq, // [OUT] Index of the type parameter + DWORD * pdwParamFlags, // [OUT] Flags, for future use (e.g. variance) + mdToken * ptOwner, // [OUT] Owner (TypeDef or MethodDef) + DWORD * pdwReserved, // [OUT] For future use (e.g. non-type parameters) + __out_ecount_part_opt(cchName, *pchName) + LPWSTR wszName, // [OUT] Put name here + ULONG cchName, // [IN] Size of buffer + ULONG * pchName); // [OUT] Put size of name (wide chars) here. + + STDMETHOD(GetGenericParamConstraintProps)( // S_OK or error. + mdGenericParamConstraint gpc, // [IN] GenericParamConstraint + mdGenericParam *ptGenericParam, // [OUT] GenericParam that is constrained + mdToken *ptkConstraintType); // [OUT] TypeDef/Ref/Spec constraint + + STDMETHOD(EnumGenericParams)( // S_OK or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdToken tk, // [IN] TypeDef or MethodDef whose generic parameters are requested + mdGenericParam rGenericParams[], // [OUT] Put GenericParams here. + ULONG cMax, // [IN] Max GenericParams to put. + ULONG *pcGenericParams); // [OUT] Put # put here. + + STDMETHOD(EnumGenericParamConstraints)( // S_OK or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdGenericParam tk, // [IN] GenericParam whose constraints are requested + mdGenericParamConstraint rGenericParamConstraints[], // [OUT] Put GenericParamConstraints here. + ULONG cMax, // [IN] Max GenericParamConstraints to put. + ULONG *pcGenericParamConstraints); // [OUT] Put # put here. + + STDMETHOD(EnumMethodSpecs)( + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdToken tk, // [IN] MethodDef or MemberRef whose MethodSpecs are requested + mdMethodSpec rMethodSpecs[], // [OUT] Put MethodSpecs here. + ULONG cMax, // [IN] Max tokens to put. + ULONG *pcMethodSpecs); // [OUT] Put actual count here. + + STDMETHOD(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 + + STDMETHOD(GetVersionString)( + __out_ecount_part_opt(ccBufSize, *pccBufSize) + LPWSTR pwzBuf, // Put version string here. + DWORD ccBufSize, // [in] Size of the buffer, in wide chars. + DWORD * pccBufSize); // [out] Size of the version string, wide chars, including terminating nul. + + + // *** ISNAssemblySignature methods *** + + STDMETHOD(GetSNAssemblySignature)( // S_OK or error. + BYTE *pbSig, // [IN, OUT] Buffer to write signature + DWORD *pcbSig); // [IN, OUT] Size of buffer, bytes written + + +#ifdef FEATURE_PREJIT + // *** IGetIMDInternalImport methods *** + + STDMETHOD(GetIMDInternalImport) ( + IMDInternalImport ** ppIMDInternalImport); + + // *** INativeImageInstallInfo *** + + STDMETHOD (GetSignature) ( + CORCOMPILE_NGEN_SIGNATURE * pNgenSign + ); + + STDMETHOD (GetVersionInfo) ( + CORCOMPILE_VERSION_INFO * pVersionInfo + ); + + + STDMETHOD (GetILSignature) ( + CORCOMPILE_ASSEMBLY_SIGNATURE * pILSign + ); + + STDMETHOD (GetConfigMask) ( + DWORD * pConfigMask + ); + + STDMETHOD (EnumDependencies) ( + HCORENUM * phEnum, + INativeImageDependency *rDeps[], + ULONG cMax, + DWORD * pdwCount + ); + + STDMETHOD (GetDependency) ( + const CORCOMPILE_NGEN_SIGNATURE *pcngenSign, + CORCOMPILE_DEPENDENCY *pDep + ); + + +#endif // FEATURE_PREJIT + + //------------ setters for privates ----------- + void SetHandle(HCORMODULE hHandle) + { + RuntimeAddRefHandle(hHandle); + m_pHandle = hHandle; + } + + void SetPEKind(DWORD dwPEKind) + { + m_dwPEKind = dwPEKind; + } + + void SetMachine(DWORD dwMachine) + { + m_dwMachine = dwMachine; + } + + void SetVersionString(const char* szVersionString) + { + m_szVersionString = szVersionString; + } + + void SetBase(LPVOID base) + { + m_pBase = base; + } + +#ifdef FEATURE_PREJIT + void SetZapVersionInfo(CORCOMPILE_VERSION_INFO * info, CORCOMPILE_DEPENDENCY * pDeps, COUNT_T cDeps) + { + m_pZapVersionInfo = info; + m_pZapDependencies = pDeps; + m_cZapDependencies = cDeps; + } +#endif // FEATURE_PREJIT + +private: + LONG m_cRef; + HCORMODULE m_pHandle; // Handle to a cached PE image + LPVOID m_pBase; // File mapping (if runtime is not inited) +#ifdef FEATURE_PREJIT + struct CORCOMPILE_VERSION_INFO * m_pZapVersionInfo; // Zap image information + struct CORCOMPILE_DEPENDENCY * m_pZapDependencies; // Zap Dependancies directory + COUNT_T m_cZapDependencies; +#endif // FEATURE_PREJIT + IMDInternalImport * m_pMDInternalImport; + DWORD m_dwPEKind; + DWORD m_dwMachine; + const char * m_szVersionString; +#ifdef _DEBUG + IMetaDataAssemblyImport * m_pDebugMDImport; +#endif //_DEBUG +}; + +#endif // FEATURE_FUSION + +#endif // __AssemblyMDInternalDispenser__h__ diff --git a/src/md/inc/cahlprinternal.h b/src/md/inc/cahlprinternal.h new file mode 100644 index 0000000000..c4ae18b0f9 --- /dev/null +++ b/src/md/inc/cahlprinternal.h @@ -0,0 +1,94 @@ +// 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. + +// + +#ifndef __CAHLPR_H__ +#define __CAHLPR_H__ + +#include "sarray.h" +#include "caparser.h" + +//***************************************************************************** +// This class assists in the parsing of CustomAttribute blobs. +//***************************************************************************** +struct CaType +{ + void Init(CorSerializationType _type) + { + _ASSERTE(_type != SERIALIZATION_TYPE_SZARRAY && _type != SERIALIZATION_TYPE_ENUM); + tag = _type; + arrayType = SERIALIZATION_TYPE_UNDEFINED; + enumType = SERIALIZATION_TYPE_UNDEFINED; + szEnumName = NULL; + cEnumName = 0; + } + + void Init(CorSerializationType _type, CorSerializationType _arrayType, CorSerializationType _enumType, LPCSTR _szEnumName, ULONG _cEnumName) + { + tag = _type; + arrayType = _arrayType; + enumType = _enumType; + szEnumName = _szEnumName; + cEnumName = _cEnumName; + } + + CorSerializationType tag; + CorSerializationType arrayType; + CorSerializationType enumType; + LPCSTR szEnumName; + ULONG cEnumName; +}; + +struct CaTypeCtor : public CaType +{ + CaTypeCtor(CorSerializationType _type) + { + Init(_type); + } + + CaTypeCtor(CorSerializationType _type, CorSerializationType _arrayType, CorSerializationType _enumType, LPCSTR _szEnumName, ULONG _cEnumName) + { + Init(_type, _arrayType, _enumType, _szEnumName, _cEnumName); + } +}; + +typedef struct CaValue +{ + union + { + unsigned __int8 boolean; + signed __int8 i1; + unsigned __int8 u1; + signed __int16 i2; + unsigned __int16 u2; + signed __int32 i4; + unsigned __int32 u4; + signed __int64 i8; + unsigned __int64 u8; + float r4; + double r8; + + struct + { + CorSerializationType tag; + SArray<CaValue>* pSArray; + ULONG length; + inline CaValue &operator[](int index) { return (*pSArray)[index]; } + } arr; + + struct + { + LPCUTF8 pStr; + ULONG cbStr; + } str; + }; + + CaType type; + +} CaValue; + + + +#endif // __CAHLPR_H__ diff --git a/src/md/inc/imptlb.h b/src/md/inc/imptlb.h new file mode 100644 index 0000000000..ba2981a415 --- /dev/null +++ b/src/md/inc/imptlb.h @@ -0,0 +1,777 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// File: imptlb.h +// + +// +// TypeLib importer. +//***************************************************************************** +#ifndef __imptlb_h__ +#define __imptlb_h__ + +#ifndef FEATURE_COMINTEROP +#error FEATURE_COMINTEROP is required for this file +#endif // FEATURE_COMINTEROP +#ifndef FEATURE_COMINTEROP_TLB_SUPPORT +#error FEATURE_COMINTEROP_TLB_SUPPORT is required for this file +#endif // FEATURE_COMINTEROP_TLB_SUPPORT + +//#define TLB_STATS + +#define MAX_TLB_VT VT_LPWSTR + 1 +#define MAX_INIT_SIG 3 +#define MAX_COM_GUID_SIG 6 +#define MAX_COM_ADDLISTENER_SIG 8 +#define MAX_COM_REMOVELISTENER_SIG 8 +#define CB_MAX_ELEMENT_TYPE 4 + +// Forward declarations. +struct ITypeLibImporterNotifySink; +class Assembly; +class Module; +class CImportTlb; + +//***************************************************************************** +// Class to perform memory management. Memory is not moved as the heap is +// expanded, and all of the allocations are cleaned up in the destructor. +//***************************************************************************** +class CWCHARPool : public StgPool +{ +public: + CWCHARPool() : StgPool() + { + HRESULT hr = InitNew(); + _ASSERTE(hr == S_OK); + } + + // Allocate some bytes from the pool. + WCHAR * Alloc(ULONG nChars) + { + BYTE *pRslt; + // Convert from characters to bytes. + nChars *= sizeof(WCHAR); + if (nChars > GetCbSegAvailable()) + if (!Grow(nChars)) + return 0; + pRslt = GetNextLocation(); + SegAllocate(nChars); + return (WCHAR*)pRslt; + } +}; // class CDescPool : public StgPool + + +//***************************************************************************** +// This helper method is used to track an url to typeref token. This makes +// defining new typerefs faster. +//***************************************************************************** +class CImpTlbTypeRef +{ +public: + CImpTlbTypeRef() { } + ~CImpTlbTypeRef() { m_Map.Clear(); } + + //***************************************************************************** + // Look for an existing typeref in the map and return if found. If not found, + // then create a new one and add it to the map for later. + //***************************************************************************** + HRESULT DefineTypeRef( // S_OK or error. + IMetaDataEmit *pEmit, // Emit interface. + mdAssemblyRef ar, // Containing assembly. + const LPCWSTR szURL, // URL of the TypeDef, wide chars. + mdTypeRef *ptr); // Put mdTypeRef here + + class TokenOfTypeRefHashKey + { + public: + mdToken tkResolutionScope; // TypeRef's resolution scope. + LPCWSTR szName; // TypeRef's name. + mdTypeRef tr; // The TypeRef's token. + }; + +private: + + class CTokenOfTypeRefHash : public CClosedHash<class TokenOfTypeRefHashKey> + { + public: + typedef CClosedHash<class TokenOfTypeRefHashKey> Super; + typedef TokenOfTypeRefHashKey T; + + CTokenOfTypeRefHash() : CClosedHash<class TokenOfTypeRefHashKey>(101) {} + ~CTokenOfTypeRefHash() { Clear(); } + + virtual void Clear(); + + unsigned int Hash(const void *pData) {return Hash((const T*)pData);} + unsigned int Hash(const T *pData); + + unsigned int Compare(const void *p1, BYTE *p2) {return Compare((const T*)p1, (T*)p2);} + unsigned int Compare(const T *p1, T *p2); + + ELEMENTSTATUS Status(BYTE *p) {return Status((T*)p);} + ELEMENTSTATUS Status(T *p); + + void SetStatus(BYTE *p, ELEMENTSTATUS s) {SetStatus((T*)p, s);} + void SetStatus(T *p, ELEMENTSTATUS s); + + void* GetKey(BYTE *p) {return GetKey((T*)p);} + void *GetKey(T *p); + + T* Add(const T *pData); + + CWCHARPool m_Names; // Heap of names. + }; + + CTokenOfTypeRefHash m_Map; // Map of namespace to token. +}; + + +//***************************************************************************** +// This helper class is used to track source interface ITypeInfo*'s to event +// information. +//***************************************************************************** +class ImpTlbEventInfo +{ +public: + LPCWSTR szSrcItfName; // The source interface name (the key). + mdTypeRef trEventItf; // The event interface typedef. + LPCWSTR szEventItfName; // The event interface name. + LPCWSTR szEventProviderName; // The event provider name. + Assembly* SrcItfAssembly; // The assembly where source interface resides. +}; + +class CImpTlbEventInfoMap : protected CClosedHash<class ImpTlbEventInfo> +{ +public: + typedef CClosedHash<class ImpTlbEventInfo> Super; + typedef ImpTlbEventInfo T; + + CImpTlbEventInfoMap() : CClosedHash<class ImpTlbEventInfo>(101) {} + ~CImpTlbEventInfoMap() { Clear(); } + + HRESULT AddEventInfo(LPCWSTR szSrcItfName, mdTypeRef trEventItf, LPCWSTR szEventItfName, LPCWSTR szEventProviderName, Assembly* SrcItfAssembly); + ImpTlbEventInfo *FindEventInfo(LPCWSTR szSrcItfName); + + HRESULT GetEventInfoList(CQuickArray<ImpTlbEventInfo*> &qbEvInfoList); + +private: + unsigned int Hash(const void *pData) {return Hash((const T*)pData);} + unsigned int Hash(const T *pData); + + unsigned int Compare(const void *p1, BYTE *p2) {return Compare((const T*)p1, (T*)p2);} + unsigned int Compare(const T *p1, T *p2); + + ELEMENTSTATUS Status(BYTE *p) {return Status((T*)p);} + ELEMENTSTATUS Status(T *p); + + void SetStatus(BYTE *p, ELEMENTSTATUS s) {SetStatus((T*)p, s);} + void SetStatus(T *p, ELEMENTSTATUS s); + + void* GetKey(BYTE *p) {return GetKey((T*)p);} + void *GetKey(T *p); + + T* Add(const T *pData); + + CWCHARPool m_Names; // Heap of names. +}; + + +#if defined(_UNICODE) || defined(UNICODE) +#define _tHashString(szStr) HashString(szStr) +#else +#define _tHashString(szStr) HashStringA(szStr) +#endif + + + +//***************************************************************************** +// This helper template is used by the TStringMap to track an item by its +// character name. +//***************************************************************************** +template <class T> class TStringMapItem : HASHENTRY +{ +public: + TStringMapItem() : + m_szString(0) + { + LIMITED_METHOD_CONTRACT; + } + ~TStringMapItem() + { + LIMITED_METHOD_CONTRACT; + delete [] m_szString; + } + + HRESULT SetString(LPCTSTR szValue) + { + WRAPPER_NO_CONTRACT; + int iLen = (int)(::_tcslen(szValue) + 1); + if ((m_szString = new TCHAR[iLen]) == 0) + return (OutOfMemory()); + ::_tcscpy_s((TCHAR*)m_szString, iLen, szValue); + return (S_OK); + } + +public: + LPTSTR m_szString; // Key data. + T m_value; // Value for this key. +}; + + +//***************************************************************************** +// IMPORTANT: This data structure is deprecated, please do not add any new uses. +// The hashtable implementation that should be used instead is code:SHash. +// If code:SHash does not work for you, talk to mailto:clrdeag. +//***************************************************************************** +// This template provides a map from string to item, determined by the template +// type passed in. +//***************************************************************************** +template <class T, int iBuckets=17, class TAllocator=CNewData, int iMaxSize=4096> +class TStringMap : + protected CHashTableAndData<TAllocator> +{ + typedef CHashTableAndData<TAllocator> Super; + +public: + typedef TStringMapItem<T> TItemType; + typedef TStringMapItem<long> TOffsetType; + +#ifndef DACCESS_COMPILE + + TStringMap() : + CHashTableAndData<TAllocator>(iBuckets) + { + LIMITED_METHOD_CONTRACT; + } + +//***************************************************************************** +// This is the second part of construction where we do all of the work that +// can fail. We also take the array of structs here because the calling class +// presumably needs to allocate it in its NewInit. +//***************************************************************************** + HRESULT NewInit() // Return status. + { + WRAPPER_NO_CONTRACT; + return (CHashTableAndData<TAllocator>::NewInit( + CNewData::GrowSize(0)/sizeof(TItemType), + sizeof(TItemType), + iMaxSize)); + } + +//***************************************************************************** +// For each item still allocated, invoke its dtor so it frees up anything it +// holds onto. +//***************************************************************************** + void Clear() + { + WRAPPER_NO_CONTRACT; + HASHFIND sSrch; + TItemType *p = (TItemType *) FindFirstEntry(&sSrch); + + while (p != 0) + { + // Call dtor on the item, since m_value is contained the scalar + // dtor will get called. + p->~TStringMapItem<T>(); + p = (TItemType *) FindNextEntry(&sSrch); + } + CHashTableAndData<TAllocator>::Clear(); + } + +#endif // #ifndef DACCESS_COMPILE + +//***************************************************************************** +// Retrieve an item by name. +//***************************************************************************** + T *GetItem( // Null or object. + LPCTSTR szKey) // What to do the lookup on. + { + WRAPPER_NO_CONTRACT; + TItemType sInfo; + TItemType *ptr; // Working pointer. + + // Create a key. + sInfo.m_szString = (LPTSTR) szKey; + + // Look it up in the hash table. + ptr = (TItemType *) Super::Find( _tHashString(szKey), (SIZE_T) &sInfo); + + // Don't let dtor free our string. + sInfo.m_szString = 0; + + // If pointer found, return to caller. To handle T's that have + // an operator &(), find raw address without going through &m_value. + if (ptr) + return ((T *) ((BYTE *) ptr + offsetof(TOffsetType, m_value))); + else + return (0); + } + +//***************************************************************************** +// Initialize an iterator and return the first item. +//***************************************************************************** + TItemType *FindFirstEntry( + HASHFIND *psSrch) + { + WRAPPER_NO_CONTRACT; + TItemType *ptr = (TItemType *) Super::FindFirstEntry(psSrch); + + return (ptr); + } + +//***************************************************************************** +// Return the next item, via an iterator. +//***************************************************************************** + TItemType *FindNextEntry( + HASHFIND *psSrch) + { + WRAPPER_NO_CONTRACT; + TItemType *ptr = (TItemType *) Super::FindNextEntry(psSrch); + + return (ptr); + } + +#ifndef DACCESS_COMPILE + +//***************************************************************************** +// Add an item to the list. +//***************************************************************************** + HRESULT AddItem( // S_OK, or S_FALSE. + LPCTSTR szKey, // The key value for the item. + T &item) // Thing to add. + { + WRAPPER_NO_CONTRACT; + TItemType *ptr; // Working pointer. + + // Allocate an entry in the hash table. + if ((ptr = (TItemType *) this->Add( _tHashString(szKey))) == 0) + return (OutOfMemory()); + + // Fill the record. + if (ptr->SetString(szKey) < 0) + { + DelItem(ptr); + return (OutOfMemory()); + } + + // Call the placement new operator on the item so it can init itself. + // To handle T's that have an operator &(), find raw address without + // going through &m_value. + T *p = new ((void *) ((BYTE *) ptr + offsetof(TOffsetType, m_value))) T; + *p = item; + return (S_OK); + } + +//***************************************************************************** +// Delete an item. +//***************************************************************************** + void DelItem( + LPCTSTR szKey) // What to delete. + { + WRAPPER_NO_CONTRACT; + TItemType sInfo; + TItemType *ptr; // Working pointer. + + // Create a key. + sInfo.m_szString = (LPTSTR) szKey; + + // Look it up in the hash table. + ptr = (TItemType *) this->Find( _tHashString(szKey), (BYTE *) &sInfo); + + // Don't let dtor free our string. + sInfo.m_szString = 0; + + // If found, delete. + if (ptr) + DelItem(ptr); + } + +#endif // #ifndef DACCESS_COMPILE + +//***************************************************************************** +// Compare the keys for two collections. +//***************************************************************************** + BOOL Cmp( // 0 or != 0. + SIZE_T data, // Raw key data on lookup. + const HASHENTRY *pElement) // The element to compare data against. + { + LIMITED_METHOD_DAC_CONTRACT; + TItemType *p = (TItemType *) (size_t) pElement; + return (::_tcscmp(((TItemType *) data)->m_szString, p->m_szString)); + } + +private: + void DelItem( + TItemType *pItem) // Entry to delete. + { + WRAPPER_NO_CONTRACT; + // Need to destruct this item. + pItem->~TStringMapItem<T>(); + CHashTableAndData<TAllocator>::Delete( HashString(pItem->m_szString), (HASHENTRY *)(void *)pItem); + } +}; + +class CImpTlbReservedNames +{ +public: + CImpTlbReservedNames() {} + ~CImpTlbReservedNames() {/*m_StringMap.Clear();*/} + +#ifndef DACCESS_COMPILE + HRESULT Init() {return m_StringMap.NewInit();} + + void AddReservedName(LPCWSTR szName) {BOOL flag = TRUE; m_StringMap.AddItem(szName, flag);} +#endif + BOOL IsReservedName(LPCWSTR szName) {return m_StringMap.GetItem(szName) != 0;} + +private: + TStringMap<BOOL> m_StringMap; +}; + + +//***************************************************************************** +// Helper class to keep track of the mappings from default interfaces to +// class interfaces. +//***************************************************************************** +class ImpTlbClassItfInfo +{ +public: + IID ItfIID; // The IID of the interface. + LPCWSTR szClassItfName; // The class interface name. +}; + +class CImpTlbDefItfToClassItfMap : protected CClosedHash<class ImpTlbClassItfInfo> +{ +public: + typedef CClosedHash<class ImpTlbClassItfInfo> Super; + typedef ImpTlbClassItfInfo T; + + CImpTlbDefItfToClassItfMap(); + ~CImpTlbDefItfToClassItfMap(); + + HRESULT Init(ITypeLib *pTlb, BSTR bstrNameSpace); + + LPCWSTR GetClassItfName(IID &rItfIID); + +private: + HRESULT AddCoClassInterfaces(ITypeInfo *pCoClassITI, TYPEATTR *pCoClassTypeAttr); + + unsigned int Hash(const void *pData) {return Hash((const T*)pData);} + unsigned int Hash(const T *pData); + + unsigned int Compare(const void *p1, BYTE *p2) {return Compare((const T*)p1, (T*)p2);} + unsigned int Compare(const T *p1, T *p2); + + ELEMENTSTATUS Status(BYTE *p) {return Status((T*)p);} + ELEMENTSTATUS Status(T *p); + + void SetStatus(BYTE *p, ELEMENTSTATUS s) {SetStatus((T*)p, s);} + void SetStatus(T *p, ELEMENTSTATUS s); + + void* GetKey(BYTE *p) {return GetKey((T*)p);} + void *GetKey(T *p); + + T* Add(const T *pData); + + CWCHARPool m_Names; // Heap of names. + BSTR m_bstrNameSpace; // Namespace of the typelib. +}; + + +//***************************************************************************** +// Helper class to keep track of imported typelibs. Typically, a typelib +// imports only 2 or 3 other typelibs, so a simple array is used. +//***************************************************************************** +struct CTlbRef +{ + GUID guid; // GUID of referenced typelib. + mdAssemblyRef ar; // AssemblyRef for the module containing reference. + BSTR szNameSpace; // The namespace of the types contained in the assembly. + BSTR szAsmName; // The assembly name. + Assembly* Asm; // The assembly. + CImpTlbDefItfToClassItfMap *pDefItfToClassItfMap; // The default interface to class interface map. + + ~CTlbRef() + { + SysFreeString(szNameSpace); + SysFreeString(szAsmName); + delete pDefItfToClassItfMap; + } +}; + +class CImpTlbLibRef : public CQuickArray<CTlbRef> +{ + typedef CQuickArray<CTlbRef> base; +public: + CImpTlbLibRef() {base::Shrink(0);} + ~CImpTlbLibRef(); + + HRESULT Add(ITypeLib *pITLB, CImportTlb *pImporter, mdAssemblyRef ar, BSTR wzNamespace, BSTR wzAsmName, Assembly* assm, CImpTlbDefItfToClassItfMap **ppMap); + int Find(ITypeLib *pITLB, mdAssemblyRef *par, BSTR *pwzNamespace, BSTR *pwzAsmName, Assembly** assm, CImpTlbDefItfToClassItfMap **ppDefItfToClassItfMap); +}; + + +class CImportTlb +{ +public: + static CImportTlb* CreateImporter(LPCWSTR szLibrary, ITypeLib *pitlb, BOOL bGenerateTCEAdapters, BOOL bUnsafeInterfaces, BOOL bSafeArrayAsSystemArray, BOOL bTransformDispRetVals, BOOL bPreventClassMembers, BOOL bSerializableValueClasses); + + CImportTlb(); + CImportTlb(LPCWSTR szLibrary, ITypeLib *pitlb, BOOL bGenerateTCEAdapters, BOOL bUnsafeInterfaces, BOOL bSafeArrayAsSystemArray, BOOL bTransformDispRetVals, BOOL bPreventClassMembers, BOOL bSerializableValueClasses); + ~CImportTlb(); + + HRESULT Import(); + HRESULT SetNamespace(WCHAR const *pNamespace); + WCHAR *GetNamespace() {return m_wzNamespace;} + HRESULT SetNotification(ITypeLibImporterNotifySink *pINotify); + HRESULT SetMetaData(IUnknown *pIUnk); + void SetAssembly(Assembly *pAssembly) {m_pAssembly = pAssembly;} + void SetModule(Module *pModule) {m_pModule = pModule;} + HRESULT GetNamespaceOfRefTlb(ITypeLib *pITLB, BSTR *pwzNamespace, CImpTlbDefItfToClassItfMap **ppDefItfToClassItfMap); + HRESULT GetEventInfoList(CQuickArray<ImpTlbEventInfo*> &qbEvInfoList) {return m_EventInfoMap.GetEventInfoList(qbEvInfoList);} + + static HRESULT GetDefaultInterface(ITypeInfo *pCoClassTI, ITypeInfo **pDefaultItfTI); + +protected: + + struct MemberInfo + { + union + { + FUNCDESC *m_psFunc; // Pointer to FuncDesc. + VARDESC *m_psVar; // Pointer to VarDesc. + }; + LPWSTR m_pName; // Function/Prop's name, possibly decorated. + int m_iMember; // The index of the member in the ITypeInfo. + union + { + LPWSTR m_pName2; // Prop's second name, if any. + mdToken m_mdFunc; // Function's token & semantics, if not property. + USHORT m_msSemantics; // Semantics only. + }; + void SetFuncInfo(mdMethodDef mdFunc, USHORT msSemantics) {m_mdFunc = RidFromToken(mdFunc) | (msSemantics<<24);} + void GetFuncInfo(mdMethodDef &mdFunc, USHORT &msSemantics) {mdFunc = m_mdFunc&0xffffff | mdtMethodDef; msSemantics = m_mdFunc>>24;} + }; + + + HRESULT ConvertTypeLib(); + HRESULT ConvertTypeInfo(); + + HRESULT ExplicitlyImplementsIEnumerable(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL fLookupPartner = TRUE); + + HRESULT _NewLibraryObject(); + HRESULT ConvCoclass(ITypeInfo *pITI, TYPEATTR *psAttr); + HRESULT ConvEnum(ITypeInfo *pITI, TYPEATTR *psAttr); + HRESULT ConvRecord(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL bUnion); + HRESULT ConvIface(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL bVtblGaps=true); + HRESULT ConvDispatch(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL bVtblGaps=true); + HRESULT ConvModule(ITypeInfo *pITI, TYPEATTR *psAttr); + + HRESULT IsIUnknownDerived(ITypeInfo *pITI, TYPEATTR *psAttr); + HRESULT IsIDispatchDerived(ITypeInfo *pITI, TYPEATTR *psAttr); + HRESULT HasNewEnumMember(ITypeInfo *pItfTI); + HRESULT FuncIsNewEnum(ITypeInfo *pITI, FUNCDESC *pFuncDesc, DWORD index); + HRESULT PropertyIsNewEnum(ITypeInfo *pITI, VARDESC *pVarDesc, DWORD index); + + HRESULT HasObjectFields(ITypeInfo *pITI, TYPEATTR *psAttr); + HRESULT IsObjectType(ITypeInfo *pITI, const TYPEDESC *pType); + HRESULT CompareSigsIgnoringRetType(PCCOR_SIGNATURE pbSig1, ULONG cbSig1, PCCOR_SIGNATURE pbSig2, ULONG cbSig2); + + HRESULT FindMethod(mdTypeDef td, LPCWSTR szName, PCCOR_SIGNATURE pbSig, ULONG cbSig, mdMethodDef *pmb); + HRESULT FindProperty(mdTypeDef td, LPCWSTR szName, PCCOR_SIGNATURE pSig, ULONG cbSig, mdProperty *pPr); + HRESULT FindEvent(mdTypeDef td, LPCWSTR szName, mdProperty *pEv); + + HRESULT ReportEvent(int ev, int hr, ...); + + HRESULT _DefineSysRefs(); + HRESULT _GetNamespaceName(ITypeLib *pITLB, BSTR *pwzNamespace); + HRESULT _GetTokenForTypeInfo(ITypeInfo *pITI, BOOL bConvDefItfToClassItf, mdToken *pToken, __out_ecount (chTypeRef) __out_opt LPWSTR pszTypeRef=0, int chTypeRef=0, int *pchTypeRef=0, BOOL bAsmQualifiedName = FALSE); + + HRESULT _FindFirstUserMethod(ITypeInfo *pITI, TYPEATTR *psAttr, int *pIx); + HRESULT _ResolveTypeDescAliasTypeKind(ITypeInfo *pITIAlias, TYPEDESC *ptdesc, TYPEKIND *ptkind); + HRESULT _ResolveTypeDescAlias(ITypeInfo *pITIAlias, const TYPEDESC *ptdesc, ITypeInfo **ppTIResolved, TYPEATTR **ppsAttrResolved, GUID *pGuid=0); + + HRESULT _SetHiddenCA(mdTypeDef token); + HRESULT _ForceIEnumerableCVExists(ITypeInfo* pITI, BOOL* CVExists); + HRESULT _SetDispIDCA(ITypeInfo* pITI, int iMember, long lDispId, mdToken func, BOOL fAlwaysAdd, long* lDispSet, BOOL bFunc); + HRESULT _GetDispIDCA(ITypeInfo* pITI, int iMember, long* lDispSet, BOOL bFunc); + HRESULT _CheckForPropertyCustomAttributes(ITypeInfo* pITI, int index, INVOKEKIND* ikind); + + HRESULT _ConvIfaceMembers(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL bVtblGaps, BOOL bAddDispIds, BOOL bInheritsIEnum); + HRESULT _ConvSrcIfaceMembers(ITypeInfo *pITI, TYPEATTR* psAttr, BOOL fInheritsIEnum); + HRESULT _ConvDispatchMembers(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL fInheritsIEnum); + HRESULT _GetFunctionPropertyInfo(FUNCDESC *psFunc, USHORT *pSemantics, FUNCDESC **ppSig, TYPEDESC **ppProperty, BOOL *pbRetval, BOOL fUseLastParam, BSTR strName); + HRESULT _ConvFunction(ITypeInfo *pITI, MemberInfo *pMember, int bVtblGapFuncs, BOOL bAddDispIds, BOOL bDelegateInvokeMeth, BOOL* bAllowIEnum); + HRESULT _GenerateEvent(ITypeInfo *pITI, MemberInfo *pMember, BOOL fInheritsIEnum); + HRESULT _GenerateEventDelegate(ITypeInfo *pITI, MemberInfo *pMember, mdTypeDef *ptd, BOOL fInheritsIEnum); + HRESULT _AddSrcItfMembersToClass(mdTypeRef trSrcItf); + + HRESULT _ConvPropertiesForFunctions(ITypeInfo *pITI, TYPEATTR *psAttr); + enum ParamOpts{ParamNormal=0, ParamOptional, ParamVarArg}; + HRESULT _ConvParam(ITypeInfo *pITI, mdMethodDef mbFunc, int iSequence, const ELEMDESC *pdesc, ParamOpts paramOpts, const WCHAR *pszName, BYTE *pbNative, ULONG cbNative); + HRESULT _ConvConstant(ITypeInfo *pITI, VARDESC *psVar, BOOL bEnumMember=false); + HRESULT _ConvField(ITypeInfo *pITI, VARDESC *psVar, mdFieldDef *pmdField, BOOL bUnion); + HRESULT _ConvProperty(ITypeInfo *pITI, MemberInfo *pMember); + HRESULT _ConvNewEnumProperty(ITypeInfo *pITI, VARDESC *psVar, MemberInfo *pMember); + + HRESULT _HandleAliasInfo(ITypeInfo *pITI, TYPEDESC *pTypeDesc, mdToken tk); + + HRESULT _AddTlbRef(ITypeLib *pITLB, mdAssemblyRef *par, BSTR *pwzNamespace, BSTR *pwzAsmName, CImpTlbDefItfToClassItfMap **ppDefItfToClassItfMap); + + HRESULT _AddGuidCa(mdToken tkObj, REFGUID guid); + HRESULT _AddDefaultMemberCa(mdToken tkObj, LPCWSTR szName); + + HRESULT _AddStringCa(int attr, mdToken tk, LPCWSTR wzString); + + HRESULT GetKnownTypeToken(VARTYPE vt, mdTypeRef *ptr); + + HRESULT _GetTokenForEventItf(ITypeInfo *pSrcItfITI, mdTypeRef *ptr); + HRESULT _CreateClassInterface(ITypeInfo *pCoClassITI, ITypeInfo *pDefItfITI, mdTypeRef trDefItf, mdTypeRef rtDefEvItf, mdToken *ptr); + + HRESULT GetManagedNameForCoClass(ITypeInfo *pITI, CQuickArray<WCHAR> &qbClassName); + HRESULT GenerateUniqueTypeName(CQuickArray<WCHAR> &qbTypeName); + HRESULT GenerateUniqueMemberName(CQuickArray<WCHAR> &qbMemberName, PCCOR_SIGNATURE pSig, ULONG SigSize, LPCWSTR szPrefix, mdToken type); + HRESULT _IsAlias(ITypeInfo *pITI, TYPEDESC *pTypeDesc); + + HRESULT GetDefMemberName(ITypeInfo *pITI, BOOL bItfQualified, CQuickArray<WCHAR> &qbDefMemberName); + + enum SigFlags { + // These match the typelib values + SIG_IN = 0x0001, // Input param. + SIG_OUT = 0x0002, // Output param. + SIG_RET = 0x0008, // Retval. Currently unused. + SIG_OPT = 0x0010, // Optional param. Currently unused. + SIG_FLAGS_MASK = 0x001b, // Mask of flags from TypeLib PARAMFLAGs + + SIG_FUNC = 0x0100, // Convert signature for function. + SIG_FIELD = 0x0200, // Convert signature for field. + SIG_ELEM = 0x0300, // Convert signature for sub element (eg, array of X). + SIG_TYPE_MASK = 0x0300, + + SIG_USE_BYREF = 0x1000, // If set convert one ptr as E_T_BYREF. + SIG_VARARG = 0x4000, // If set, this is a paramarray type. Use szArray, not System.Array. + + SIG_FLAGS_NONE = 0 // '0' of this enum type. + }; + + #define IsSigIn(flags) ((flags & SIG_IN) == SIG_IN) + #define IsSigOut(flags) ((flags & SIG_OUT) == SIG_OUT) + #define IsSigRet(flags) ((flags & SIG_RET) == SIG_RET) + #define IsSigOpt(flags) ((flags & SIG_OPT) == SIG_OPT) + #define IsSigOutRet(flags) ((flags & (SIG_OUT|SIG_RET)) == (SIG_OUT|SIG_RET)) + + #define IsSigFunc(flags) ((flags & SIG_TYPE_MASK) == SIG_FUNC) + #define IsSigField(flags) ((flags & SIG_TYPE_MASK) == SIG_FIELD) + #define IsSigElem(flags) ((flags & SIG_TYPE_MASK) == SIG_ELEM) + + #define IsSigUseByref(flags) ((flags & SIG_USE_BYREF) == SIG_USE_BYREF) + #define IsSigVarArg(flags) ((flags & SIG_VARARG) == SIG_VARARG) + + HRESULT _ConvSignature(ITypeInfo *pITI, const TYPEDESC *pType, ULONG Flags, CQuickBytes &qbSigBuf, ULONG cbSig, ULONG *pcbSig, CQuickArray<BYTE> &qbNativeTypeBuf, ULONG cbNativeType, ULONG *pcbNativeType, BOOL bNewEnumMember, int iByRef=0); + + // For handling out-of-order vtables. + CQuickArray<MemberInfo> m_MemberList; + CWCHARPool *m_pMemberNames; + int m_cMemberProps; // Count of props in memberlist. + HRESULT BuildMemberList(ITypeInfo *pITI, int iStart, int iEnd, BOOL bInheritsIEnum); + HRESULT FreeMemberList(ITypeInfo *pITI); + + // List of predefined token types for custom attributes. +#define INTEROP_ATTRIBUTES() \ + INTEROP_ATTRIBUTE(DISPID) \ + INTEROP_ATTRIBUTE(CLASSINTERFACE) \ + INTEROP_ATTRIBUTE(INTERFACETYPE) \ + INTEROP_ATTRIBUTE(TYPELIBTYPE) \ + INTEROP_ATTRIBUTE(TYPELIBVAR) \ + INTEROP_ATTRIBUTE(TYPELIBFUNC) \ + INTEROP_ATTRIBUTE(COMSOURCEINTERFACES) \ + INTEROP_ATTRIBUTE(COMCONVERSIONLOSS) \ + INTEROP_ATTRIBUTE(GUID) \ + INTEROP_ATTRIBUTE(DEFAULTMEMBER) \ + INTEROP_ATTRIBUTE(COMALIASNAME) \ + INTEROP_ATTRIBUTE(PARAMARRAY) \ + INTEROP_ATTRIBUTE(LCIDCONVERSION) \ + INTEROP_ATTRIBUTE(DECIMALVALUE) \ + INTEROP_ATTRIBUTE(DATETIMEVALUE) \ + INTEROP_ATTRIBUTE(IUNKNOWNVALUE) \ + INTEROP_ATTRIBUTE(IDISPATCHVALUE) \ + INTEROP_ATTRIBUTE(COMVISIBLE) \ + INTEROP_ATTRIBUTE(SERIALIZABLE) \ + INTEROP_ATTRIBUTE_SPECIAL(COMEVENTINTERFACE) \ + INTEROP_ATTRIBUTE_SPECIAL(COCLASS) \ + +#define INTEROP_ATTRIBUTE(x) ATTR_##x, +#define INTEROP_ATTRIBUTE_SPECIAL(x) ATTR_##x, + enum {INTEROP_ATTRIBUTES() + // Last value gives array size. + ATTR_COUNT}; +#undef INTEROP_ATTRIBUTE +#undef INTEROP_ATTRIBUTE_SPECIAL + + mdToken m_tkAttr[ATTR_COUNT]; + HRESULT GetAttrType(int attr, mdToken *ptk); + + // look up table for known type + mdTypeRef m_tkKnownTypes[MAX_TLB_VT]; + + LPCWSTR m_szLibrary; // Name of typelib being imported. + BOOL m_bGenerateTCEAdapters; // A flag indicating if the TCE adapters are being generated or not. + BOOL m_bUnsafeInterfaces; // A flag indicating whether runtime security checks should be disabled on an interface + BOOL m_bSafeArrayAsSystemArray; // A flag indicating whether to import SAFEARRAY's as System.Array's. + BOOL m_bTransformDispRetVals; // A flag indicating if we should do [out,retval] transformation on disp only itfs. + BOOL m_bPreventClassMembers; // A flag indicating if we should add members to CoClasses. + BOOL m_bSerializableValueClasses; // A flag indicating if we should mark value classes as serializable. + mdMemberRef m_tkSuppressCheckAttr; // Cached ctor for security check custom attribute + ITypeLib *m_pITLB; // Typelib being imported. + IMetaDataEmit2 *m_pEmit; // Emit API Interface pointer. + IMetaDataImport2 *m_pImport; // Import API Interface pointer. + + BSTR m_wzNamespace; // Namespace of the created TypeDefs. + mdTypeRef m_trObject; // Token of System.Object. + mdTypeRef m_trValueType; // Token of System.ValueType. + mdTypeRef m_trEnum; // Token of System.Enum. + mdAssemblyRef m_arSystem; // AssemblyRef for classlib. + + ITypeInfo *m_pITI; // "Current" ITypeInfo being converted. + ITypeInfo *m_pOrigITI; // Original "Current" ITypeInfo being converted, + // represents TKIND_ALIAS or is equal to m_pITI. + + TYPEATTR *m_psAttr; // "TYPEATTR" of current ITypeInfo. + + BSTR m_szName; // Name of original current ITypeInfo. + BSTR m_szMember; // Name of current Member (method or field). + LPWSTR m_szMngName; // Full name of the managed type. + + ULONG m_cbVtableSlot; // Size of a vtable slot. + ULONG m_Slot; // "Current" vtbl index within an interface. + + void *m_psClass; // "Current" class record. + mdTypeDef m_tdTypeDef; // Current TypeDef. + mdTypeDef m_tdHasDefault; // Most recent TypeDef with a default. + enum {eImplIfaceNone, eImplIfaceDefault, eImplIface} m_ImplIface; + mdToken m_tkInterface; // Interface being added to a coclass. + BSTR m_szInterface; // Interface name for decoration. + + CImpTlbTypeRef m_TRMap; // Typeref map. + CImpTlbLibRef m_LibRefs; // Referenced typelibs. + CImpTlbDefItfToClassItfMap m_DefItfToClassItfMap; // The default interface to class interface map. + + CImpTlbReservedNames m_ReservedNames; // Reserved names. + CImpTlbEventInfoMap m_EventInfoMap; // Map of event info's. + + ITypeLibImporterNotifySink *m_Notify; // Notification object. + Assembly *m_pAssembly; // Containing assembly. + Module *m_pModule; // Module we are emiting into. + +#if defined(TLB_STATS) + LARGE_INTEGER m_freqVal; // Frequency of perf counter. + BOOL m_bStats; // If true, collect timings. +#endif // TLB_STATS +}; + + + +#endif + +//-eof-************************************************************************ diff --git a/src/md/inc/liteweightstgdb.h b/src/md/inc/liteweightstgdb.h new file mode 100644 index 0000000000..1234524731 --- /dev/null +++ b/src/md/inc/liteweightstgdb.h @@ -0,0 +1,257 @@ +// 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. +//***************************************************************************** +// LiteWeightStgdb.h +// + +// +// This contains definition of class CLiteWeightStgDB. This is light weight +// read-only implementation for accessing compressed meta data format. +// +//***************************************************************************** +#ifndef __LiteWeightStgdb_h__ +#define __LiteWeightStgdb_h__ + +#include "metamodelro.h" +#include "metamodelrw.h" + +#include "stgtiggerstorage.h" + +class StgIO; + +#include "mdcommon.h" + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:28718) // public header missing SAL annotations +#endif // _PREFAST_ +class TiggerStorage; +#ifdef _PREFAST_ +#pragma warning(pop) +#endif // _PREFAST_ + +//***************************************************************************** +// This class provides common definitions for heap segments. It is both the +// base class for the heap, and the class for heap extensions (additional +// memory that must be allocated to grow the heap). +//***************************************************************************** +template <class MiniMd> +class CLiteWeightStgdb +{ + friend class VerifyLayoutsMD; +public: + CLiteWeightStgdb() : m_pvMd(NULL), m_cbMd(0) + {} + + ~CLiteWeightStgdb() + { Uninit(); } + + // open an in-memory metadata section for read. + __checkReturn + HRESULT InitOnMem( + ULONG cbData, + LPCVOID pbData); + + __checkReturn + HRESULT InitHotPools(DataBuffer hotMetaData); + + void Uninit(); + +protected: + MiniMd m_MiniMd; // embedded compress meta data schemas definition + const void *m_pvMd; // Pointer to meta data. + ULONG m_cbMd; // Size of the meta data. + + friend class CorMetaDataScope; + friend class COR; + friend class RegMeta; + friend class MERGER; + friend class NEWMERGER; + friend class MDInternalRO; + friend class MDInternalRW; +}; + +//***************************************************************************** +// Open an in-memory metadata section for read +//***************************************************************************** +template <class MiniMd> +void CLiteWeightStgdb<MiniMd>::Uninit() +{ + m_MiniMd.m_StringHeap.Delete(); + m_MiniMd.m_UserStringHeap.Delete(); + m_MiniMd.m_GuidHeap.Delete(); + m_MiniMd.m_BlobHeap.Delete(); + m_pvMd = NULL; + m_cbMd = 0; +} + +class CLiteWeightStgdbRW : public CLiteWeightStgdb<CMiniMdRW> +{ + friend class CImportTlb; + friend class RegMeta; + friend class VerifyLayoutsMD; + friend HRESULT TranslateSigHelper( + IMDInternalImport* pImport, + IMDInternalImport* pAssemImport, + const void* pbHashValue, + ULONG cbHashValue, + PCCOR_SIGNATURE pbSigBlob, + ULONG cbSigBlob, + IMetaDataAssemblyEmit* pAssemEmit, + IMetaDataEmit* emit, + CQuickBytes* pqkSigEmit, + ULONG* pcbSig); +public: + CLiteWeightStgdbRW() : m_cbSaveSize(0), m_pStreamList(0), m_pNextStgdb(NULL), m_pStgIO(NULL) + { + m_wszFileName = NULL; + m_pImage = NULL; + m_dwImageSize = 0; + m_dwPEKind = (DWORD)(-1); + m_dwDatabaseLFS = 0; + m_dwDatabaseLFT = 0; + } + ~CLiteWeightStgdbRW(); + + __checkReturn + HRESULT InitNew(); + + // open an in-memory metadata section for read. + __checkReturn + HRESULT InitOnMem( + ULONG cbData, + LPCVOID pbData, + int bReadOnly); + + __checkReturn + HRESULT GetSaveSize( + CorSaveSize fSize, + UINT32 *pcbSaveSize, + MetaDataReorderingOptions reorderingOptions = NoReordering, + CorProfileData *pProfileData = NULL); // optional IBC profile data for working set optimization + + __checkReturn + HRESULT SaveToStream( + IStream *pIStream, // Stream to which to write + MetaDataReorderingOptions reorderingOptions = NoReordering, + CorProfileData *pProfileData = NULL); // optional IBC profile data for working set optimization + + __checkReturn + HRESULT Save( + LPCWSTR szFile, + DWORD dwSaveFlags); + + // Open a metadata section for read/write + __checkReturn + HRESULT OpenForRead( + LPCWSTR szDatabase, // Name of database. + void *pbData, // Data to open on top of, 0 default. + ULONG cbData, // How big is the data. + DWORD dwFlags); // Flags for the open. + +#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE + // Open a metadata section for read/write + __checkReturn + HRESULT OpenForRead( + IMDCustomDataSource *pDataSource, // data to open on top of + DWORD dwFlags); // Flags for the open. +#endif + + __checkReturn + HRESULT FindImageMetaData( + PVOID pImage, // Pointer to head of a file + DWORD dwFileLength, // length of a flat file + BOOL bMappedImage, // Is the file mapped + PVOID *ppMetaData, // [out] pointer to the metadata + ULONG *pcbMetaData); // [out] size of the metadata + + __checkReturn + HRESULT FindObjMetaData( + PVOID pImage, // Pointer to an OBJ file + DWORD dwFileLength, // Length of the file + PVOID *ppMetaData, // [out] pointer to the metadata + ULONG *pcbMetaData); // [out] size of the metadata + + __checkReturn + HRESULT GetPEKind( // S_OK or error. + MAPPINGTYPE mtMapping, // The type of mapping the image has + DWORD* pdwPEKind, // [OUT] The kind of PE (0 - not a PE) + DWORD* pdwMachine); // [OUT] Machine as defined in NT header + + // Low level data access; not useful for most clients. + __checkReturn + HRESULT GetRawData( + const void **ppvMd, // [OUT] put pointer to MD section here (aka, 'BSJB'). + ULONG *pcbMd); // [OUT] put size of the stream here. + + __checkReturn + STDMETHODIMP GetRawStreamInfo( // Get info about the MD stream. + ULONG ix, // [IN] Stream ordinal desired. + const char **ppchName, // [OUT] put pointer to stream name here. + const void **ppv, // [OUT] put pointer to MD stream here. + ULONG *pcb); // [OUT] put size of the stream here. + + UINT32 m_cbSaveSize; // Size of the saved streams. + int m_bSaveCompressed; // If true, save as compressed stream (#-, not #~) + VOID* m_pImage; // Set in OpenForRead, NULL for anything but PE files + DWORD m_dwImageSize; // On-disk size of image + +protected: + DWORD m_dwPEKind; // The kind of PE - 0: not a PE. + DWORD m_dwMachine; // Machine as defined in NT header. + + __checkReturn + HRESULT GetPoolSaveSize( + LPCWSTR szHeap, // Name of the heap stream. + int iPool, // The pool whose size to get. + UINT32 *pcbSaveSize); // Add pool data to this value. + + __checkReturn + HRESULT GetTablesSaveSize( + CorSaveSize fSave, + UINT32 *pcbSaveSize, + MetaDataReorderingOptions reorderingOptions, + CorProfileData *pProfileData = NULL); // Add pool data to this value. + + __checkReturn + HRESULT AddStreamToList( + UINT32 cbSize, // Size of the stream data. + LPCWSTR szName); // Name of the stream. + + __checkReturn + HRESULT SaveToStorage( + TiggerStorage *pStorage, + MetaDataReorderingOptions reorderingOptions = NoReordering, + CorProfileData *pProfileData = NULL); + + __checkReturn + HRESULT SavePool(LPCWSTR szName, TiggerStorage *pStorage, int iPool); + + STORAGESTREAMLST *m_pStreamList; + + __checkReturn + HRESULT InitFileForRead( + StgIO *pStgIO, // For file i/o. + int bReadOnly=true); // If read-only. + + // Set file name of this database (makes copy of the file name). + __checkReturn HRESULT SetFileName(const WCHAR * wszFileName); + // Returns TRUE if wszFileName has valid file name length. + static BOOL IsValidFileNameLength(const WCHAR * wszFileName); + + CLiteWeightStgdbRW *m_pNextStgdb; + +public: + FORCEINLINE FILETYPE GetFileType() { return m_eFileType; } + +private: + FILETYPE m_eFileType; + WCHAR * m_wszFileName; // Database file name (NULL or non-empty string) + DWORD m_dwDatabaseLFT; // Low bytes of the database file's last write time + DWORD m_dwDatabaseLFS; // Low bytes of the database file's size + StgIO * m_pStgIO; // For file i/o. + +}; // class CLiteWeightStgdbRW + +#endif // __LiteWeightStgdb_h__ diff --git a/src/md/inc/mdcolumndescriptors.h b/src/md/inc/mdcolumndescriptors.h new file mode 100644 index 0000000000..ac2565cdb5 --- /dev/null +++ b/src/md/inc/mdcolumndescriptors.h @@ -0,0 +1,51 @@ +// 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. + +// + +static const BYTE s_ModuleCol[]; +static const BYTE s_TypeRefCol[]; +static const BYTE s_TypeDefCol[]; +static const BYTE s_FieldPtrCol[]; +static const BYTE s_FieldCol[]; +static const BYTE s_MethodPtrCol[]; +static const BYTE s_MethodCol[]; +static const BYTE s_ParamPtrCol[]; +static const BYTE s_ParamCol[]; +static const BYTE s_InterfaceImplCol[]; +static const BYTE s_MemberRefCol[]; +static const BYTE s_ConstantCol[]; +static const BYTE s_CustomAttributeCol[]; +static const BYTE s_FieldMarshalCol[]; +static const BYTE s_DeclSecurityCol[]; +static const BYTE s_ClassLayoutCol[]; +static const BYTE s_FieldLayoutCol[]; +static const BYTE s_StandAloneSigCol[]; +static const BYTE s_EventMapCol[]; +static const BYTE s_EventPtrCol[]; +static const BYTE s_EventCol[]; +static const BYTE s_PropertyMapCol[]; +static const BYTE s_PropertyPtrCol[]; +static const BYTE* s_PropertyCol; +static const BYTE s_MethodSemanticsCol[]; +static const BYTE s_MethodImplCol[]; +static const BYTE s_ModuleRefCol[]; +static const BYTE* s_TypeSpecCol; +static const BYTE s_ImplMapCol[]; +static const BYTE* s_FieldRVACol; +static const BYTE s_ENCLogCol[]; +static const BYTE s_ENCMapCol[]; +static const BYTE s_AssemblyCol[]; +static const BYTE* s_AssemblyProcessorCol; +static const BYTE s_AssemblyOSCol[]; +static const BYTE s_AssemblyRefCol[]; +static const BYTE s_AssemblyRefProcessorCol[]; +static const BYTE s_AssemblyRefOSCol[]; +static const BYTE s_FileCol[]; +static const BYTE s_ExportedTypeCol[]; +static const BYTE s_ManifestResourceCol[]; +static const BYTE s_NestedClassCol[]; +static const BYTE s_GenericParamCol[]; +static const BYTE s_MethodSpecCol[]; +static const BYTE s_GenericParamConstraintCol[]; diff --git a/src/md/inc/mdfileformat.h b/src/md/inc/mdfileformat.h new file mode 100644 index 0000000000..a86549323e --- /dev/null +++ b/src/md/inc/mdfileformat.h @@ -0,0 +1,269 @@ +// 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. +//***************************************************************************** +// MDFileFormat.h +// + +// +// This file contains a set of helpers to verify and read the file format. +// This code does not handle the paging of the data, or different types of +// I/O. See the StgTiggerStorage and StgIO code for this level of support. +// +//***************************************************************************** +#ifndef __MDFileFormat_h__ +#define __MDFileFormat_h__ + +//***************************************************************************** +// The signature ULONG is the first 4 bytes of the file format. The second +// signature string starts the header containing the stream list. It is used +// for an integrity check when reading the header in lieu of a more complicated +// system. +//***************************************************************************** +#define STORAGE_MAGIC_SIG 0x424A5342 // BSJB + + + +//***************************************************************************** +// These values get written to the signature at the front of the file. Changing +// these values should not be done lightly because all old files will no longer +// be supported. In a future revision if a format change is required, a +// backwards compatible migration path must be provided. +//***************************************************************************** + +#define FILE_VER_MAJOR 1 +#define FILE_VER_MINOR 1 + +// These are the last legitimate 0.x version macros. The file format has +// sinced move up to 1.x (see macros above). After COM+ 1.0/NT 5 RTM's, these +// macros should no longer be required or ever seen. +#define FILE_VER_MAJOR_v0 0 + +#define FILE_VER_MINOR_v0 19 + + +#define MAXSTREAMNAME 32 + +enum +{ + STGHDR_NORMAL = 0x00, // Normal default flags. + STGHDR_EXTRADATA = 0x01, // Additional data exists after header. +}; + + +//***************************************************************************** +// This is the formal signature area at the front of the file. This structure +// is not allowed to change, the shim depends on it staying the same size. +// Use the reserved pointer if it must extended. +//***************************************************************************** +struct STORAGESIGNATURE; +typedef STORAGESIGNATURE UNALIGNED * PSTORAGESIGNATURE; + +#include "pshpack1.h" +struct STORAGESIGNATURE +{ +METADATA_FIELDS_PROTECTION: + ULONG lSignature; // "Magic" signature. + USHORT iMajorVer; // Major file version. + USHORT iMinorVer; // Minor file version. + ULONG iExtraData; // Offset to next structure of information + ULONG iVersionString; // Length of version string +public: + BYTE pVersion[0]; // Version string + ULONG GetSignature() + { + return VAL32(lSignature); + } + void SetSignature(ULONG Signature) + { + lSignature = VAL32(Signature); + } + + USHORT GetMajorVer() + { + return VAL16(iMajorVer); + } + void SetMajorVer(USHORT MajorVer) + { + iMajorVer = VAL16(MajorVer); + } + + USHORT GetMinorVer() + { + return VAL16(iMinorVer); + } + void SetMinorVer(USHORT MinorVer) + { + iMinorVer = VAL16(MinorVer); + } + + ULONG GetExtraDataOffset() + { + return VAL32(iExtraData); + } + void SetExtraDataOffset(ULONG ExtraDataOffset) + { + iExtraData = VAL32(ExtraDataOffset); + } + + ULONG GetVersionStringLength() + { + return VAL32(iVersionString); + } + void SetVersionStringLength(ULONG VersionStringLength) + { + iVersionString = VAL32(VersionStringLength); + } +}; +#include "poppack.h" + + +//***************************************************************************** +// The header of the storage format. +//***************************************************************************** +struct STORAGEHEADER; +typedef STORAGEHEADER UNALIGNED * PSTORAGEHEADER; + +#include "pshpack1.h" +struct STORAGEHEADER +{ +METADATA_FIELDS_PROTECTION: + BYTE fFlags; // STGHDR_xxx flags. + BYTE pad; + USHORT iStreams; // How many streams are there. +public: + BYTE GetFlags() + { + return fFlags; + } + void SetFlags(BYTE flags) + { + fFlags = flags; + } + void AddFlags(BYTE flags) + { + fFlags |= flags; + } + + + USHORT GetiStreams() + { + return VAL16(iStreams); + } + void SetiStreams(USHORT iStreamsCount) + { + iStreams = VAL16(iStreamsCount); + } +}; +#include "poppack.h" + + +//***************************************************************************** +// Each stream is described by this struct, which includes the offset and size +// of the data. The name is stored in ANSI null terminated. +//***************************************************************************** +struct STORAGESTREAM; +typedef STORAGESTREAM UNALIGNED * PSTORAGESTREAM; + +#include "pshpack1.h" +struct STORAGESTREAM +{ +METADATA_FIELDS_PROTECTION: + ULONG iOffset; // Offset in file for this stream. + ULONG iSize; // Size of the file. + char rcName[MAXSTREAMNAME]; // Start of name, null terminated. +public: + // Returns pointer to the next stream. Doesn't validate the structure. + inline PSTORAGESTREAM NextStream() + { + int iLen = (int)(strlen(rcName) + 1); + iLen = ALIGN4BYTE(iLen); + return ((PSTORAGESTREAM) (((BYTE*)this) + (sizeof(ULONG) * 2) + iLen)); + } + // Returns pointer to the next stream. + // Returns NULL if the structure has invalid format. + inline PSTORAGESTREAM NextStream_Verify() + { + // Check existence of null-terminator in the name + if (memchr(rcName, 0, MAXSTREAMNAME) == NULL) + { + return NULL; + } + return NextStream(); + } + + inline ULONG GetStreamSize() + { + return (ULONG)(strlen(rcName) + 1 + (sizeof(STORAGESTREAM) - sizeof(rcName))); + } + + inline char* GetName() + { + return rcName; + } + inline LPCWSTR GetName(__inout_ecount (iMaxSize) LPWSTR szName, int iMaxSize) + { + VERIFY(::WszMultiByteToWideChar(CP_ACP, 0, rcName, -1, szName, iMaxSize)); + return (szName); + } + inline void SetName(LPCWSTR szName) + { + int size; + size = WszWideCharToMultiByte(CP_ACP, 0, szName, -1, rcName, MAXSTREAMNAME, 0, 0); + _ASSERTE(size > 0); + } + + ULONG GetSize() + { + return VAL32(iSize); + } + void SetSize(ULONG Size) + { + iSize = VAL32(Size); + } + + ULONG GetOffset() + { + return VAL32(iOffset); + } + void SetOffset(ULONG Offset) + { + iOffset = VAL32(Offset); + } +}; +#include "poppack.h" + + +class MDFormat +{ +public: +//***************************************************************************** +// Verify the signature at the front of the file to see what type it is. +//***************************************************************************** + static HRESULT VerifySignature( + PSTORAGESIGNATURE pSig, // The signature to check. + ULONG cbData); // Size of metadata. + +//***************************************************************************** +// Skip over the header and find the actual stream data. +// It doesn't perform any checks for buffer overflow - use GetFirstStream_Verify +// instead. +//***************************************************************************** + static PSTORAGESTREAM GetFirstStream(// Return pointer to the first stream. + PSTORAGEHEADER pHeader, // Return copy of header struct. + const void *pvMd); // Pointer to the full file. +//***************************************************************************** +// Skip over the header and find the actual stream data. Secure version of +// GetFirstStream method. +// The header is supposed to be verified by VerifySignature. +// +// Caller has to check available buffer size before using the first stream. +//***************************************************************************** + static PSTORAGESTREAM GetFirstStream_Verify(// Return pointer to the first stream. + PSTORAGEHEADER pHeader, // Return copy of header struct. + const void *pvMd, // Pointer to the full file. + ULONG *pcbMd); // [in, out] Size of pvMd buffer (we don't want to read behind it) + +}; + +#endif // __MDFileFormat_h__ diff --git a/src/md/inc/mdinternalrw.h b/src/md/inc/mdinternalrw.h new file mode 100644 index 0000000000..a0cc4816a4 --- /dev/null +++ b/src/md/inc/mdinternalrw.h @@ -0,0 +1,862 @@ +// 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. +//***************************************************************************** +// MDInternalRW.h +// + +// +// Contains utility code for MD directory +// +//***************************************************************************** +#ifndef __MDInternalRW__h__ +#define __MDInternalRW__h__ + +#ifdef FEATURE_METADATA_INTERNAL_APIS + +#include "../inc/mdlog.h" + +class UTSemReadWrite; + +class MDInternalRW : public IMDInternalImportENC, public IMDCommon +{ + friend class VerifyLayoutsMD; +public: + + + MDInternalRW(); + virtual ~MDInternalRW(); + __checkReturn + HRESULT Init(LPVOID pData, ULONG cbData, int bReadOnly); + __checkReturn + HRESULT InitWithStgdb(IUnknown *pUnk, CLiteWeightStgdbRW *pStgdb); + __checkReturn + HRESULT InitWithRO(MDInternalRO *pRO, int bReadOnly); + + // *** IUnknown methods *** + __checkReturn + STDMETHODIMP QueryInterface(REFIID riid, void** ppv); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + + __checkReturn + STDMETHODIMP TranslateSigWithScope( + IMDInternalImport *pAssemImport, // [IN] import assembly scope. + const void *pbHashValue, // [IN] hash value for the import assembly. + ULONG cbHashValue, // [IN] count of bytes in the hash value. + PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope + ULONG cbSigBlob, // [IN] count of bytes of signature + IMetaDataAssemblyEmit *pAssemEmit, // [IN] assembly emit scope. + IMetaDataEmit *emit, // [IN] emit interface + CQuickBytes *pqkSigEmit, // [OUT] buffer to hold translated signature + ULONG *pcbSig) // [OUT] count of bytes in the translated signature + DAC_UNEXPECTED(); + + __checkReturn + STDMETHODIMP GetTypeDefRefTokenInTypeSpec(// return S_FALSE if enclosing type does not have a token + mdTypeSpec tkTypeSpec, // [IN] TypeSpec token to look at + mdToken *tkEnclosedToken) // [OUT] The enclosed type token + DAC_UNEXPECTED(); + + STDMETHODIMP_(IMetaModelCommon*) GetMetaModelCommon() + { + return static_cast<IMetaModelCommon*>(&m_pStgdb->m_MiniMd); + } + + STDMETHODIMP_(IMetaModelCommonRO*) GetMetaModelCommonRO() + { + if (m_pStgdb->m_MiniMd.IsWritable()) + { + _ASSERTE(!"IMetaModelCommonRO methods cannot be used because this importer is writable."); + return NULL; + } + + return static_cast<IMetaModelCommonRO*>(&m_pStgdb->m_MiniMd); + } + + __checkReturn + STDMETHODIMP SetOptimizeAccessForSpeed(// return hresult + BOOL fOptSpeed) + { + // If there is any optional work we can avoid (for example, because we have + // traded space for speed) this is the place to turn it off or on. + + return S_OK; + } + + //***************************************************************************** + // return the count of entries of a given kind in a scope + // For example, pass in mdtMethodDef will tell you how many MethodDef + // contained in a scope + //***************************************************************************** + STDMETHODIMP_(ULONG) GetCountWithTokenKind(// return hresult + DWORD tkKind) // [IN] pass in the kind of token. + DAC_UNEXPECTED(); + + //***************************************************************************** + // enumerator for typedef + //***************************************************************************** + __checkReturn + STDMETHODIMP EnumTypeDefInit( // return hresult + HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data + + STDMETHODIMP_(ULONG) EnumTypeDefGetCount( + HENUMInternal *phEnum); // [IN] the enumerator to retrieve information + + STDMETHODIMP_(void) EnumTypeDefReset( + HENUMInternal *phEnum); // [IN] the enumerator to retrieve information + + STDMETHODIMP_(bool) EnumTypeDefNext( // return hresult + HENUMInternal *phEnum, // [IN] input enum + mdTypeDef *ptd); // [OUT] return token + + STDMETHODIMP_(void) EnumTypeDefClose( + HENUMInternal *phEnum); // [IN] the enumerator to retrieve information + + //***************************************************************************** + // enumerator for MethodImpl + //***************************************************************************** + __checkReturn + STDMETHODIMP EnumMethodImplInit( // return hresult + mdTypeDef td, // [IN] TypeDef over which to scope the enumeration. + HENUMInternal *phEnumBody, // [OUT] buffer to fill for enumerator data for MethodBody tokens. + HENUMInternal *phEnumDecl) // [OUT] buffer to fill for enumerator data for MethodDecl tokens. + DAC_UNEXPECTED(); + + STDMETHODIMP_(ULONG) EnumMethodImplGetCount( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. + DAC_UNEXPECTED(); + + STDMETHODIMP_(void) EnumMethodImplReset( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. + DAC_UNEXPECTED(); + + __checkReturn + STDMETHODIMP EnumMethodImplNext( // return hresult (S_OK = TRUE, S_FALSE = FALSE or error code) + HENUMInternal *phEnumBody, // [IN] input enum for MethodBody + HENUMInternal *phEnumDecl, // [IN] input enum for MethodDecl + mdToken *ptkBody, // [OUT] return token for MethodBody + mdToken *ptkDecl) // [OUT] return token for MethodDecl + DAC_UNEXPECTED(); + + STDMETHODIMP_(void) EnumMethodImplClose( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. + DAC_UNEXPECTED(); + + //***************************************** + // Enumerator helpers for memberdef, memberref, interfaceimp, + // event, property, param, methodimpl + //***************************************** + + __checkReturn + STDMETHODIMP EnumGlobalFunctionsInit( // return hresult + HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data + + __checkReturn + STDMETHODIMP EnumGlobalFieldsInit( // return hresult + HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data + + + __checkReturn + STDMETHODIMP EnumInit( // return S_FALSE if record not found + DWORD tkKind, // [IN] which table to work on + mdToken tkParent, // [IN] token to scope the search + HENUMInternal *phEnum); // [OUT] the enumerator to fill + + __checkReturn + STDMETHODIMP EnumAllInit( // return S_FALSE if record not found + DWORD tkKind, // [IN] which table to work on + HENUMInternal *phEnum); // [OUT] the enumerator to fill + + STDMETHODIMP_(bool) EnumNext( + HENUMInternal *phEnum, // [IN] the enumerator to retrieve information + mdToken *ptk); // [OUT] token to scope the search + + STDMETHODIMP_(ULONG) EnumGetCount( + HENUMInternal *phEnum); // [IN] the enumerator to retrieve information + + STDMETHODIMP_(void) EnumReset( + HENUMInternal *phEnum); // [IN] the enumerator to be reset + + STDMETHODIMP_(void) EnumClose( + HENUMInternal *phEnum); // [IN] the enumerator to be closed + + __checkReturn + STDMETHODIMP EnumPermissionSetsInit( // return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + CorDeclSecurity Action, // [IN] Action to scope the search + HENUMInternal *phEnum) // [OUT] the enumerator to fill + DAC_UNEXPECTED(); + + __checkReturn + STDMETHODIMP EnumCustomAttributeByNameInit(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum); // [OUT] the enumerator to fill + + __checkReturn + STDMETHODIMP GetParentToken( + mdToken tkChild, // [IN] given child token + mdToken *ptkParent); // [OUT] returning parent + + __checkReturn + STDMETHODIMP GetCustomAttributeProps( + mdCustomAttribute at, // The attribute. + mdToken *ptkType); // Put attribute type here. + + __checkReturn + STDMETHODIMP GetCustomAttributeAsBlob( + mdCustomAttribute cv, // [IN] given custom attribute token + void const **ppBlob, // [OUT] return the pointer to internal blob + ULONG *pcbSize); // [OUT] return the size of the blob + + __checkReturn + STDMETHODIMP GetCustomAttributeByName( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData); // [OUT] Put size of data here. + + __checkReturn + STDMETHODIMP GetNameOfCustomAttribute( // S_OK or error. + mdCustomAttribute mdAttribute, // [IN] The Custom Attribute + LPCUTF8 *pszNamespace, // [OUT] Namespace of Custom Attribute. + LPCUTF8 *pszName); // [OUT] Name of Custom Attribute. + + __checkReturn + STDMETHODIMP SafeAndSlowEnumCustomAttributeByNameInit(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum); // [OUT] The enumerator + + __checkReturn + STDMETHODIMP SafeAndSlowEnumCustomAttributeByNameNext(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum, // [IN] The enumerator + mdCustomAttribute *mdAttribute); // [OUT] The custom attribute that was found + + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetScopeProps( + LPCSTR *pszName, // [OUT] scope name + GUID *pmvid); // [OUT] version id + + // finding a particular method + __checkReturn + STDMETHODIMP FindMethodDef( + mdTypeDef classdef, // [IN] given typedef + LPCSTR 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 *pmd); // [OUT] matching memberdef + + // return a iSeq's param given a MethodDef + __checkReturn + STDMETHODIMP FindParamOfMethod( // S_OK or error. + mdMethodDef md, // [IN] The owning method of the param. + ULONG iSeq, // [IN} The sequence # of the param. + mdParamDef *pparamdef); // [OUT] Put ParamDef token here. + + //***************************************** + // + // GetName* functions + // + //***************************************** + + // return the name and namespace of typedef + __checkReturn + STDMETHODIMP GetNameOfTypeDef( + mdTypeDef classdef, // given classdef + LPCSTR *pszname, // return class name(unqualified) + LPCSTR *psznamespace); // return the name space name + + __checkReturn + STDMETHODIMP GetIsDualOfTypeDef( + mdTypeDef classdef, // [IN] given classdef. + ULONG *pDual); // [OUT] return dual flag here. + + __checkReturn + STDMETHODIMP GetIfaceTypeOfTypeDef( + mdTypeDef tkTypeDef, + ULONG * pIface); // [OUT] 0=dual, 1=vtable, 2=dispinterface + + __checkReturn + STDMETHODIMP GetNameOfMethodDef( + mdMethodDef tkMethodDef, + LPCSTR * pszName); + + __checkReturn + STDMETHODIMP GetNameAndSigOfMethodDef( + mdMethodDef methoddef, // [IN] given memberdef + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of COM+ signature + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + LPCSTR *pszName); + + // return the name of a FieldDef + __checkReturn + STDMETHODIMP GetNameOfFieldDef( + mdFieldDef fd, // given memberdef + LPCSTR *pszName); + + // return the name of typeref + __checkReturn + STDMETHODIMP GetNameOfTypeRef( + mdTypeRef classref, // [IN] given typeref + LPCSTR *psznamespace, // [OUT] return typeref name + LPCSTR *pszname); // [OUT] return typeref namespace + + // return the resolutionscope of typeref + __checkReturn + STDMETHODIMP GetResolutionScopeOfTypeRef( + mdTypeRef classref, // given classref + mdToken *ptkResolutionScope); + + // return the typeref token given the name. + __checkReturn + STDMETHODIMP FindTypeRefByName( + LPCSTR szNamespace, // [IN] Namespace for the TypeRef. + LPCSTR szName, // [IN] Name of the TypeRef. + mdToken tkResolutionScope, // [IN] Resolution Scope fo the TypeRef. + mdTypeRef *ptk); // [OUT] TypeRef token returned. + + // return the TypeDef properties + __checkReturn + STDMETHODIMP GetTypeDefProps( // return hresult + mdTypeDef classdef, // given classdef + DWORD *pdwAttr, // return flags on class, tdPublic, tdAbstract + mdToken *ptkExtends); // [OUT] Put base class TypeDef/TypeRef here. + + // return the item's guid + __checkReturn + STDMETHODIMP GetItemGuid( // return hresult + mdToken tkObj, // [IN] given item. + CLSID *pGuid); // [OUT] Put guid here. + + // get enclosing class of NestedClass. + __checkReturn + STDMETHODIMP GetNestedClassProps( // S_OK or error + mdTypeDef tkNestedClass, // [IN] NestedClass token. + mdTypeDef *ptkEnclosingClass); // [OUT] EnclosingClass token. + + // Get count of Nested classes given the enclosing class. + __checkReturn + STDMETHODIMP GetCountNestedClasses( // return count of Nested classes. + mdTypeDef tkEnclosingClass, // [IN]Enclosing class. + ULONG *pcNestedClassesCount); + + // Return array of Nested classes given the enclosing class. + __checkReturn + STDMETHODIMP GetNestedClasses( // Return actual count. + mdTypeDef tkEnclosingClass, // [IN] Enclosing class. + mdTypeDef *rNestedClasses, // [OUT] Array of nested class tokens. + ULONG ulNestedClasses, // [IN] Size of array. + ULONG *pcNestedClasses); + + // return the ModuleRef properties + __checkReturn + STDMETHODIMP GetModuleRefProps( + mdModuleRef mur, // [IN] moduleref token + LPCSTR *pszName); // [OUT] buffer to fill with the moduleref name + + + //***************************************** + // + // GetSig* functions + // + //***************************************** + __checkReturn + STDMETHODIMP GetSigOfMethodDef( + mdMethodDef methoddef, // [IN] given memberdef + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + PCCOR_SIGNATURE *ppSig); + + __checkReturn + STDMETHODIMP GetSigOfFieldDef( + mdMethodDef methoddef, // [IN] given memberdef + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + PCCOR_SIGNATURE *ppSig); + + __checkReturn + STDMETHODIMP GetSigFromToken( + mdToken tk, // FieldDef, MethodDef, Signature or TypeSpec token + ULONG * pcbSig, + PCCOR_SIGNATURE * ppSig); + + + + //***************************************** + // get method property + //***************************************** + __checkReturn + STDMETHODIMP GetMethodDefProps( + mdMethodDef md, // The method for which to get props. + DWORD *pdwFlags); + + STDMETHODIMP_(ULONG) GetMethodDefSlot( + mdMethodDef mb); // The method for which to get props. + + //***************************************** + // return method implementation informaiton, like RVA and implflags + //***************************************** + __checkReturn + STDMETHODIMP GetMethodImplProps( + mdToken tk, // [IN] MethodDef or MethodImpl + DWORD *pulCodeRVA, // [OUT] CodeRVA + DWORD *pdwImplFlags); // [OUT] Impl. Flags + + //***************************************************************************** + // return the field RVA + //***************************************************************************** + __checkReturn + STDMETHODIMP GetFieldRVA( + mdToken fd, // [IN] FieldDef + ULONG *pulCodeRVA); // [OUT] CodeRVA + + //***************************************************************************** + // return the field offset for a given field + //***************************************************************************** + __checkReturn + STDMETHODIMP GetFieldOffset( + mdFieldDef fd, // [IN] fielddef + ULONG *pulOffset); // [OUT] FieldOffset + + //***************************************** + // get field property + //***************************************** + __checkReturn + STDMETHODIMP GetFieldDefProps( + mdFieldDef fd, // [IN] given fielddef + DWORD *pdwFlags); // [OUT] return fdPublic, fdPrive, etc flags + + //***************************************************************************** + // return default value of a token(could be paramdef, fielddef, or property + //***************************************************************************** + __checkReturn + STDMETHODIMP GetDefaultValue( + mdToken tk, // [IN] given FieldDef, ParamDef, or Property + MDDefaultValue *pDefaultValue); // [OUT] default value to fill + + + //***************************************** + // get dispid of a MethodDef or a FieldDef + //***************************************** + __checkReturn + STDMETHODIMP GetDispIdOfMemberDef( // return hresult + mdToken tk, // [IN] given methoddef or fielddef + ULONG *pDispid); // [OUT] Put the dispid here. + + //***************************************** + // return TypeRef/TypeDef given an InterfaceImpl token + //***************************************** + __checkReturn + STDMETHODIMP GetTypeOfInterfaceImpl( // return the TypeRef/typedef token for the interfaceimpl + mdInterfaceImpl iiImpl, // given a interfaceimpl + mdToken *ptkType); + + __checkReturn + STDMETHODIMP GetMethodSpecProps( + 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 + + //***************************************** + // look up function for TypeDef + //***************************************** + __checkReturn + STDMETHODIMP FindTypeDef( + LPCSTR szNamespace, // [IN] Namespace for the TypeDef. + LPCSTR szName, // [IN] Name of the TypeDef. + mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class. + mdTypeDef *ptypedef); // [OUT] return typedef + + __checkReturn + STDMETHODIMP FindTypeDefByGUID( + REFGUID guid, // guid to look up + mdTypeDef *ptypedef); // return typedef + + + + //***************************************** + // return name and sig of a memberref + //***************************************** + __checkReturn + STDMETHODIMP GetNameAndSigOfMemberRef( // return name here + mdMemberRef memberref, // given memberref + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of COM+ signature + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + LPCSTR *pszName); + + //***************************************************************************** + // Given memberref, return the parent. It can be TypeRef, ModuleRef, MethodDef + //***************************************************************************** + __checkReturn + STDMETHODIMP GetParentOfMemberRef( + mdMemberRef memberref, // given memberref + mdToken *ptkParent); // return the parent token + + __checkReturn + STDMETHODIMP GetParamDefProps( + mdParamDef paramdef, // given a paramdef + USHORT *pusSequence, // [OUT] slot number for this parameter + DWORD *pdwAttr, // [OUT] flags + LPCSTR *pszName); // [OUT] return the name of the parameter + + //****************************************** + // property info for method. + //****************************************** + __checkReturn + STDMETHODIMP GetPropertyInfoForMethodDef( // Result. + mdMethodDef md, // [IN] memberdef + mdProperty *ppd, // [OUT] put property token here + LPCSTR *pName, // [OUT] put pointer to name here + ULONG *pSemantic); // [OUT] put semantic here + + //***************************************** + // class layout/sequence information + //***************************************** + __checkReturn + STDMETHODIMP GetClassPackSize( // [OUT] return error if a class doesn't have packsize info + mdTypeDef td, // [IN] give typedef + ULONG *pdwPackSize); // [OUT] return the pack size of the class. 1, 2, 4, 8 or 16 + + __checkReturn + STDMETHODIMP GetClassTotalSize( // [OUT] return error if a class doesn't have total size info + mdTypeDef td, // [IN] give typedef + ULONG *pdwClassSize); // [OUT] return the total size of the class + + __checkReturn + STDMETHODIMP GetClassLayoutInit( + mdTypeDef td, // [IN] give typedef + MD_CLASS_LAYOUT *pLayout); // [OUT] set up the status of query here + + __checkReturn + STDMETHODIMP GetClassLayoutNext( + MD_CLASS_LAYOUT *pLayout, // [IN|OUT] set up the status of query here + mdFieldDef *pfd, // [OUT] return the fielddef + ULONG *pulOffset); // [OUT] return the offset/ulSequence associate with it + + //***************************************** + // marshal information of a field + //***************************************** + __checkReturn + STDMETHODIMP GetFieldMarshal( // return error if no native type associate with the token + mdFieldDef fd, // [IN] given fielddef + PCCOR_SIGNATURE *pSigNativeType, // [OUT] the native type signature + ULONG *pcbNativeType); // [OUT] the count of bytes of *ppvNativeType + + + //***************************************** + // property APIs + //***************************************** + // find a property by name + __checkReturn + STDMETHODIMP FindProperty( + mdTypeDef td, // [IN] given a typdef + LPCSTR szPropName, // [IN] property name + mdProperty *pProp); // [OUT] return property token + + __checkReturn + STDMETHODIMP GetPropertyProps( + mdProperty prop, // [IN] property token + LPCSTR *szProperty, // [OUT] property name + DWORD *pdwPropFlags, // [OUT] property flags. + PCCOR_SIGNATURE *ppvSig, // [OUT] property type. pointing to meta data internal blob + ULONG *pcbSig); // [OUT] count of bytes in *ppvSig + + //********************************** + // Event APIs + //********************************** + __checkReturn + STDMETHODIMP FindEvent( + mdTypeDef td, // [IN] given a typdef + LPCSTR szEventName, // [IN] event name + mdEvent *pEvent); // [OUT] return event token + + __checkReturn + STDMETHODIMP GetEventProps( // S_OK, S_FALSE, or error. + mdEvent ev, // [IN] event token + LPCSTR *pszEvent, // [OUT] Event name + DWORD *pdwEventFlags, // [OUT] Event flags. + mdToken *ptkEventType); // [OUT] EventType class + + + //********************************** + // Generics APIs + //********************************** + __checkReturn + STDMETHODIMP GetGenericParamProps( // S_OK or error. + mdGenericParam rd, // [IN] The type parameter + ULONG* pulSequence, // [OUT] Parameter sequence number + DWORD* pdwAttr, // [OUT] Type parameter flags (for future use) + mdToken *ptOwner, // [OUT] The owner (TypeDef or MethodDef) + DWORD *reserved, // [OUT] The kind (TypeDef/Ref/Spec, for future use) + LPCSTR *szName); // [OUT] The name + + __checkReturn + STDMETHODIMP 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 + + //********************************** + // find a particular associate of a property or an event + //********************************** + __checkReturn + STDMETHODIMP FindAssociate( + mdToken evprop, // [IN] given a property or event token + DWORD associate, // [IN] given a associate semantics(setter, getter, testdefault, reset, AddOn, RemoveOn, Fire) + mdMethodDef *pmd); // [OUT] return method def token + + __checkReturn + STDMETHODIMP EnumAssociateInit( + mdToken evprop, // [IN] given a property or an event token + HENUMInternal *phEnum); // [OUT] cursor to hold the query result + + __checkReturn + STDMETHODIMP GetAllAssociates( + HENUMInternal *phEnum, // [IN] query result form GetPropertyAssociateCounts + ASSOCIATE_RECORD *pAssociateRec, // [OUT] struct to fill for output + ULONG cAssociateRec); // [IN] size of the buffer + + + //********************************** + // Get info about a PermissionSet. + //********************************** + __checkReturn + STDMETHODIMP 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. + + //**************************************** + // Get the String given the String token. + // Returns a pointer to the string, or NULL in case of error. + //**************************************** + __checkReturn + STDMETHODIMP GetUserString( + mdString stk, // [IN] the string token. + ULONG *pchString, // [OUT] count of characters in the string. + BOOL *pbIs80Plus, // [OUT] specifies where there are extended characters >= 0x80. + LPCWSTR *pwszUserString); + + //***************************************************************************** + // p-invoke APIs. + //***************************************************************************** + __checkReturn + STDMETHODIMP GetPinvokeMap( + mdToken tk, // [IN] FieldDef or MethodDef. + DWORD *pdwMappingFlags, // [OUT] Flags used for mapping. + LPCSTR *pszImportName, // [OUT] Import name. + mdModuleRef *pmrImportDLL); // [OUT] ModuleRef token for the target DLL. + + //***************************************************************************** + // Assembly MetaData APIs. + //***************************************************************************** + __checkReturn + STDMETHODIMP GetAssemblyProps( + mdAssembly mda, // [IN] The Assembly for which to get the properties. + const void **ppbPublicKey, // [OUT] Pointer to the public key. + ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key. + ULONG *pulHashAlgId, // [OUT] Hash Algorithm. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData. + DWORD *pdwAssemblyFlags); // [OUT] Flags. + + __checkReturn + STDMETHODIMP GetAssemblyRefProps( + mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties. + const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token. + ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData. + const void **ppbHashValue, // [OUT] Hash blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the hash blob. + DWORD *pdwAssemblyRefFlags); // [OUT] Flags. + + __checkReturn + STDMETHODIMP GetFileProps( + mdFile mdf, // [IN] The File for which to get the properties. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the Hash Value Blob. + DWORD *pdwFileFlags); // [OUT] Flags. + + __checkReturn + STDMETHODIMP GetExportedTypeProps( + mdExportedType mdct, // [IN] The ExportedType for which to get the properties. + LPCSTR *pszNamespace, // [OUT] Buffer to fill with namespace. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType. + mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file. + DWORD *pdwExportedTypeFlags); // [OUT] Flags. + + __checkReturn + STDMETHODIMP GetManifestResourceProps( + mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType. + DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file. + DWORD *pdwResourceFlags); // [OUT] Flags. + + __checkReturn + STDMETHODIMP FindExportedTypeByName( // S_OK or error + LPCSTR szNamespace, // [IN] Namespace of the ExportedType. + LPCSTR szName, // [IN] Name of the ExportedType. + mdExportedType tkEnclosingType, // [IN] Token for the enclosing Type. + mdExportedType *pmct); // [OUT] Put ExportedType token here. + + __checkReturn + STDMETHODIMP FindManifestResourceByName(// S_OK or error + LPCSTR szName, // [IN] Name of the resource. + mdManifestResource *pmmr); // [OUT] Put ManifestResource token here. + + __checkReturn + STDMETHODIMP GetAssemblyFromScope( // S_OK or error + mdAssembly *ptkAssembly); // [OUT] Put token here. + + //*************************************************************************** + // return properties regarding a TypeSpec + //*************************************************************************** + __checkReturn + STDMETHODIMP 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. + + + //***************************************************************************** + // This function gets the "built for" version of a metadata scope. + // NOTE: if the scope has never been saved, it will not have a built-for + // version, and an empty string will be returned. + //***************************************************************************** + __checkReturn + STDMETHODIMP GetVersionString( // S_OK or error. + LPCSTR *pVer); // [OUT] Put version string here. + + + //***************************************************************************** + // helpers to convert a text signature to a com format + //***************************************************************************** + __checkReturn + STDMETHODIMP ConvertTextSigToComSig( // Return hresult. + BOOL fCreateTrIfNotFound, // [IN] create typeref if not found + LPCSTR pSignature, // [IN] class file format signature + CQuickBytes *pqbNewSig, // [OUT] place holder for COM+ signature + ULONG *pcbCount); // [OUT] the result size of signature + + __checkReturn + STDMETHODIMP SetUserContextData( // S_OK or E_NOTIMPL + IUnknown *pIUnk); // The user context. + + STDMETHODIMP_(BOOL) IsValidToken( // True or False. + mdToken tk); // [IN] Given token. + + STDMETHODIMP_(IUnknown *) GetCachedPublicInterface(BOOL fWithLock); // return the cached public interface + __checkReturn + STDMETHODIMP SetCachedPublicInterface(IUnknown *pUnk); // return hresult + STDMETHODIMP_(UTSemReadWrite*) GetReaderWriterLock(); // return the reader writer lock + __checkReturn + STDMETHODIMP SetReaderWriterLock(UTSemReadWrite *pSem) + { + _ASSERTE(m_pSemReadWrite == NULL); + m_pSemReadWrite = pSem; + INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) + return NOERROR; + } + + // *** IMDInternalImportENC methods *** + __checkReturn + STDMETHODIMP ApplyEditAndContinue( // S_OK or error. + MDInternalRW *pDelta); // MD with the ENC delta. + + __checkReturn + STDMETHODIMP EnumDeltaTokensInit( // return hresult + HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data + + STDMETHODIMP_(mdModule) GetModuleFromScope(void); + + // finding a particular method + __checkReturn + STDMETHODIMP FindMethodDefUsingCompare( + mdTypeDef classdef, // [IN] given typedef + LPCSTR 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 + PSIGCOMPARE pSignatureCompare, // [IN] Routine to compare signatures + void* pSignatureArgs, // [IN] Additional info to supply the compare function + mdMethodDef *pmd); // [OUT] matching memberdef + + //***************************************************************************** + // return the table pointer and size for a given table index + //***************************************************************************** + __checkReturn + STDMETHODIMP GetTableInfoWithIndex( + ULONG index, // [IN] pass in the index + void **pTable, // [OUT] pointer to table at index + void **pTableSize); // [OUT] size of table at index + + __checkReturn + STDMETHODIMP ApplyEditAndContinue( + void *pData, // [IN] the delta metadata + ULONG cbData, // [IN] length of pData + IMDInternalImport **ppv); // [OUT] the resulting metadata interface + + + FORCEINLINE CLiteWeightStgdbRW* GetMiniStgdb() { return m_pStgdb; } + FORCEINLINE UTSemReadWrite *getReaderWriterLock() { return m_pSemReadWrite; } + + + CLiteWeightStgdbRW *m_pStgdb; + +private: + mdTypeDef m_tdModule; // <Module> typedef value. + LONG m_cRefs; // Ref count. + bool m_fOwnStgdb; + IUnknown *m_pUnk; + IUnknown *m_pUserUnk; // Release at shutdown. + IMetaDataHelper *m_pIMetaDataHelper;// pointer to cached public interface + UTSemReadWrite *m_pSemReadWrite; // read write lock for multi-threading. + bool m_fOwnSem; // Does MDInternalRW own this read write lock object? + +public: + STDMETHODIMP_(DWORD) GetMetadataStreamVersion() + { + return (DWORD)m_pStgdb->m_MiniMd.m_Schema.m_minor | + ((DWORD)m_pStgdb->m_MiniMd.m_Schema.m_major << 16); + }; + + __checkReturn + STDMETHODIMP SetVerifiedByTrustedSource(// return hresult + BOOL fVerified) + { + m_pStgdb->m_MiniMd.SetVerifiedByTrustedSource(fVerified); + return S_OK; + } + + STDMETHODIMP GetRvaOffsetData(// S_OK or error + DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. + DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. + DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. + DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. + DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. + DWORD *pFieldRvaCount) // [OUT] Number of records in FieldRVA table. + { + return m_pStgdb->m_MiniMd.GetRvaOffsetData( + pFirstMethodRvaOffset, + pMethodDefRecordSize, + pMethodDefCount, + pFirstFieldRvaOffset, + pFieldRvaRecordSize, + pFieldRvaCount); + } +}; // class MDInternalRW + +#endif //FEATURE_METADATA_INTERNAL_APIS + +#endif // __MDInternalRW__h__ diff --git a/src/md/inc/mdlog.h b/src/md/inc/mdlog.h new file mode 100644 index 0000000000..7eb792f9cc --- /dev/null +++ b/src/md/inc/mdlog.h @@ -0,0 +1,25 @@ +// 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. +//***************************************************************************** +// MDLog.h - Meta data logging helper. +// + +// +//***************************************************************************** +#ifndef __MDLog_h__ +#define __MDLog_h__ + +#if defined(_DEBUG) && !defined(DACCESS_COMPILE) +#define LOGGING +#endif + +#include <log.h> + +#define LOGMD LF_METADATA, LL_INFO10000 +#define LOG_MDCALL(func) LOG((LF_METADATA, LL_INFO10000, "MD: %s\n", #func)) + +#define MDSTR(str) ((str) ? str : W("<null>")) +#define MDSTRA(str) ((str) ? str : "<null>") + +#endif // __MDLog_h__ diff --git a/src/md/inc/metadatahash.h b/src/md/inc/metadatahash.h new file mode 100644 index 0000000000..6fa43dbb99 --- /dev/null +++ b/src/md/inc/metadatahash.h @@ -0,0 +1,207 @@ +// 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. +//***************************************************************************** +// MetaDataHash.h -- Meta data hash data structures. +// + +// +// Used by Emitters and by E&C. +// +//***************************************************************************** +#ifndef _MetaDataHash_h_ +#define _MetaDataHash_h_ + +#if _MSC_VER >= 1100 + # pragma once +#endif + +#include "utilcode.h" + + +#define REHASH_THREADSHOLD 3 + + +//***************************************************************************** +// A hash entry list item. +//***************************************************************************** +struct TOKENHASHENTRY +{ + mdToken tok; + ULONG ulHash; + ULONG iNext; +}; + +//***************************************************************************** +// The following is a hash class definition used for hashing MemberDef. The difference +// from the hash table above is because it is expansive to retrieve the parent for MemberDef. +// +//***************************************************************************** +struct MEMBERDEFHASHENTRY +{ + mdToken tok; + mdToken tkParent; + ULONG ulHash; + ULONG iNext; +}; + + +//***************************************************************************** +// This class is used to create transient indexes for meta data structures. +// This class is generic; one must override it to provide hashing and +// accessor methods for your specific record type. It can start out on top +// of malloc with a small memory footprint, and as you get larger, it must +// be capable of rehashing. +//***************************************************************************** +template <class Entry> class CMetaDataHashTemplate +{ +public: + CMetaDataHashTemplate() + { + m_rgBuckets = 0; + m_cItems = 0; + m_iBuckets = 0; + } + + ~CMetaDataHashTemplate() + { + // Free the bucket list. + if (m_rgBuckets) + { + delete [] m_rgBuckets; + m_rgBuckets = 0; + m_cItems = 0; + m_iBuckets = 0; + } + } + +//***************************************************************************** +// Called to allocate the hash table entries so that new data may be added. +//***************************************************************************** + HRESULT NewInit( // Return status. + int iBuckets=17) // How many buckets you want. + { + m_rgBuckets = new (nothrow) int[iBuckets]; + if (!m_rgBuckets) + return (OutOfMemory()); + m_iBuckets = iBuckets; + memset(m_rgBuckets, ~0, sizeof(int) * iBuckets); + return (S_OK); + } + +//***************************************************************************** +// Add new items to the hash list. +//***************************************************************************** + Entry *Add( // Pointer to element to write to. + ULONG iHash) // Hash value of entry to add. + { + Entry *p = 0; + HRESULT hr; + + int iBucket = iHash % m_iBuckets; + + if (m_cItems > REHASH_THREADSHOLD * m_iBuckets) + { + hr = ReHash(); + if (FAILED(hr)) + return (0); + iBucket = iHash % m_iBuckets; + } + + // Add a new item pointer. + p = m_Heap.Append(); + if (!p) + return (0); + + // Chain the new item to the front of the heap. + p->iNext = m_rgBuckets[iBucket]; + p->ulHash = iHash; + m_cItems++; + m_rgBuckets[iBucket] = m_Heap.ItemIndex(p); + return (p); + } + + +//***************************************************************************** +// Grow the hash table +//***************************************************************************** + HRESULT ReHash() + { + int *rgBuckets; + int iBuckets; + int iBucket; + int index; + int iCount; + Entry *p = 0; + + iBuckets = m_iBuckets*2 -1; + rgBuckets = new (nothrow) int[iBuckets]; + if (!rgBuckets) + return (OutOfMemory()); + memset(rgBuckets, ~0, sizeof(int) * iBuckets); + + // loop through each of data and rehash them + iCount = m_Heap.Count(); + for (index = 0; index < iCount; index++) + { + // get the hash value of the entry + p = m_Heap.Get(index); + + // rehash the entry + iBucket = p->ulHash % iBuckets; + + // Chain the item to the front of the new heap. + p->iNext = rgBuckets[iBucket]; + rgBuckets[iBucket] = index; + } + + // swap the hash table + delete [] m_rgBuckets; + m_rgBuckets = rgBuckets; + m_iBuckets = iBuckets; + return NOERROR; + + } + +//***************************************************************************** +// Find first/find next node for a chain given the hash. +//***************************************************************************** + Entry *FindFirst( // Return entry. + ULONG iHash, // The hash value for the entry. + int &POS) // Current position. + { + int iBucket = iHash % m_iBuckets; + POS = m_rgBuckets[iBucket]; + return (FindNext(POS)); + } + + Entry *FindNext( // Return entry or 0. + int &POS) // Current location. + { + Entry *p; + + if (POS == ~0) + return (0); + + p = m_Heap.Get(POS); + POS = p->iNext; + return (p); + } + +private: + CDynArray<Entry> m_Heap; // First heap in the list. + int *m_rgBuckets; // Bucket list. + int m_iBuckets; // How many buckets. + int m_cItems; // Number of items in the hash +}; + + +class CMetaDataHashBase : public CMetaDataHashTemplate<TOKENHASHENTRY> +{ +}; + +class CMemberDefHash : public CMetaDataHashTemplate<MEMBERDEFHASHENTRY> +{ +}; + +#endif // _MetaDataHash_h_ diff --git a/src/md/inc/metamodel.h b/src/md/inc/metamodel.h new file mode 100644 index 0000000000..317501bfa5 --- /dev/null +++ b/src/md/inc/metamodel.h @@ -0,0 +1,2072 @@ +// 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. +//***************************************************************************** +// MetaModel.h -- header file for compressed COM+ metadata. +// + +// +//***************************************************************************** +#ifndef _METAMODEL_H_ +#define _METAMODEL_H_ + +#if _MSC_VER >= 1100 +#pragma once +#endif + +#include <cor.h> +#include <stgpool.h> +#include <metamodelpub.h> +#include "metadatatracker.h" + +#include "../datablob.h" +#include "../debug_metadata.h" + +#undef __unaligned + +#define ALLOCATED_MEMORY_MARKER 0xff + +// Version numbers for metadata format. + +#define METAMODEL_MAJOR_VER_V1_0 1 // Major version for v1.0 +#define METAMODEL_MINOR_VER_V1_0 0 // Minor version for v1.0 + +#define METAMODEL_MAJOR_VER_V2_0 2 // Major version for v2.0 +#define METAMODEL_MINOR_VER_V2_0 0 // Minor version for v2.0 + +#define METAMODEL_MAJOR_VER 2 +#define METAMODEL_MINOR_VER 0 + +// Metadata version number up through Whidbey Beta2 +#define METAMODEL_MAJOR_VER_B1 1 +#define METAMODEL_MINOR_VER_B1 1 + + +typedef enum MetadataVersion +{ + MDVersion1 = 0x00000001, + MDVersion2 = 0x00000002, + + // @TODO - this value should be updated when we increase the version number + MDDefaultVersion = 0x00000002 +} MetadataVersion; + + + +struct HENUMInternal; +extern const CCodedTokenDef g_CodedTokens[CDTKN_COUNT]; +extern const CMiniTableDefEx g_Tables[TBL_COUNT]; // The table definitions. + +struct TblCol +{ + ULONG m_ixtbl; // Table ID. + ULONG m_ixcol; // Column ID. +}; +extern TblCol g_PtrTableIxs[TBL_COUNT]; + +// This abstract defines the common functions that can be used for RW and RO internally +// (The primary user for this is Compiler\ImportHelper.cpp) +class IMetaModelCommon +{ +public: + __checkReturn + virtual HRESULT CommonGetScopeProps( + LPCUTF8 *pszName, + GUID *pMvid) = 0; + + __checkReturn + virtual HRESULT CommonGetTypeRefProps( + mdTypeRef tr, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkResolution) = 0; + + __checkReturn + virtual HRESULT CommonGetTypeDefProps( + mdTypeDef td, + LPCUTF8 *pszNameSpace, + LPCUTF8 *pszName, + DWORD *pdwFlags, + mdToken *pdwExtends, + ULONG *pMethodList) = 0; + + __checkReturn + virtual HRESULT CommonGetTypeSpecProps( + mdTypeSpec ts, + PCCOR_SIGNATURE *ppvSig, + ULONG *pcbSig) = 0; + + __checkReturn + virtual HRESULT CommonGetEnclosingClassOfTypeDef( + mdTypeDef td, + mdTypeDef *ptkEnclosingTypeDef) = 0; + + __checkReturn + virtual HRESULT CommonGetAssemblyProps( + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKey, + ULONG *pcbPublicKey, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale) = 0; + + __checkReturn + virtual HRESULT CommonGetAssemblyRefProps( + mdAssemblyRef tkAssemRef, + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKeyOrToken, + ULONG *pcbPublicKeyOrToken, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale, + const void **ppbHashValue, + ULONG *pcbHashValue) = 0; + + __checkReturn + virtual HRESULT CommonGetModuleRefProps( + mdModuleRef tkModuleRef, + LPCUTF8 *pszName) = 0; + + __checkReturn + virtual HRESULT CommonFindExportedType( + LPCUTF8 szNamespace, + LPCUTF8 szName, + mdToken tkEnclosingType, + mdExportedType *ptkExportedType) = 0; + + __checkReturn + virtual HRESULT CommonGetExportedTypeProps( + mdToken tkExportedType, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkImpl) = 0; + + virtual int CommonIsRo() = 0; + + __checkReturn + virtual HRESULT CommonGetCustomAttributeByName( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) // [OUT] Put size of data here. + { + return CommonGetCustomAttributeByNameEx(tkObj, szName, NULL, ppData, pcbData); + } + + __checkReturn + virtual HRESULT CommonGetCustomAttributeByNameEx( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + mdCustomAttribute *ptkCA, // [OUT] put custom attribute token here + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) = 0; // [OUT] Put size of data here. + + __checkReturn + virtual HRESULT FindParentOfMethodHelper(mdMethodDef md, mdTypeDef *ptd) = 0; + +}; // class IMetaModelCommon + + + +// An extension of IMetaModelCommon, exposed by read-only importers only. +// (The primary user for this is the WinMD import adapter which needs +// a unified view of RegMeta and MDInternalRO.) +// +// These methods were separated from IMetaModelCommon as they are only used by +// the WinMDAdapter and we don't want the maintainence and code-coverage cost +// of providing Enc-aware versions of these methods. +class IMetaModelCommonRO : public IMetaModelCommon +{ +public: + virtual HRESULT CommonGetMethodDefProps( + mdMethodDef tkMethodDef, + LPCUTF8 *pszName, + DWORD *pdwFlags, + PCCOR_SIGNATURE *ppvSigBlob, + ULONG *pcbSigBlob + ) = 0; + + virtual HRESULT CommonGetMemberRefProps( + mdMemberRef tkMemberRef, + mdToken *pParentToken + ) = 0; + + virtual ULONG CommonGetRowCount( // return hresult + DWORD tkKind) = 0; // [IN] pass in the kind of token. + + virtual HRESULT CommonGetMethodImpls( + mdTypeDef tkTypeDef, // [IN] typeDef to scope search + mdToken *ptkMethodImplFirst, // [OUT] returns first methodImpl token + ULONG *pMethodImplCount // [OUT] returns # of methodImpl tokens scoped to type + ) = 0; + + virtual HRESULT CommonGetMethodImplProps( + mdToken tkMethodImpl, // [IN] methodImpl + mdToken *pBody, // [OUT] returns body token + mdToken *pDecl // [OUT] returns decl token + ) = 0; + + virtual HRESULT CommonGetCustomAttributeProps( + mdCustomAttribute cv, // [IN] CustomAttribute token. + mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here. + mdToken *ptkType, // [OUT, OPTIONAL] Put AttrType token here. + const void **ppBlob, // [OUT, OPTIONAL] Put pointer to data here. + ULONG *pcbSize) = 0; // [OUT, OPTIONAL] Put size of date here. + + virtual HRESULT CommonGetFieldDefProps( + mdFieldDef tkFieldDef, + mdTypeDef *ptkParent, + LPCUTF8 *pszName, + DWORD *pdwFlags + ) = 0; +}; // class IMetaModelCommonRO + + +//***************************************************************************** +// The mini, hard-coded schema. For each table, we persist the count of +// records. We also persist the size of string, blob, guid, and rid +// columns. From this information, we can calculate the record sizes, and +// then the sizes of the tables. +//***************************************************************************** + +class CMiniMdSchemaBase +{ +public: + ULONG m_ulReserved; // Reserved, must be zero. + BYTE m_major; // Version numbers. + BYTE m_minor; + BYTE m_heaps; // Bits for heap sizes. + BYTE m_rid; // log-base-2 of largest rid. + + // Bits for heap sizes. + enum { + HEAP_STRING_4 = 0x01, + HEAP_GUID_4 = 0x02, + HEAP_BLOB_4 = 0x04, + + PADDING_BIT = 0x08, // Tables can be created with an extra bit in columns, for growth. + + DELTA_ONLY = 0x20, // If set, only deltas were persisted. + EXTRA_DATA = 0x40, // If set, schema persists an extra 4 bytes of data. + HAS_DELETE = 0x80, // If set, this metadata can contain _Delete tokens. + }; + + unsigned __int64 m_maskvalid; // Bit mask of present table counts. + + unsigned __int64 m_sorted; // Bit mask of sorted tables. + FORCEINLINE bool IsSorted(ULONG ixTbl) + { return m_sorted & BIT(ixTbl) ? true : false; } + void SetSorted(ULONG ixTbl, int bVal) + { if (bVal) m_sorted |= BIT(ixTbl); + else m_sorted &= ~BIT(ixTbl); } + +#if BIGENDIAN + // Verify that the size hasn't changed (Update if necessary) + void ConvertEndianness() + { + _ASSERTE(sizeof(CMiniMdSchemaBase) == 0x18); + m_ulReserved = VAL32(m_ulReserved); + m_maskvalid = VAL64(m_maskvalid); + m_sorted = VAL64(m_sorted); + } +#else + // Nothing to do on little endian machine + void ConvertEndianness() {return ;} +#endif + +private: + FORCEINLINE unsigned __int64 BIT(ULONG ixBit) + { _ASSERTE(ixBit < (sizeof(__int64)*CHAR_BIT)); + return UI64(1) << ixBit; } + +}; + +class CMiniMdSchema : public CMiniMdSchemaBase +{ +public: + // These are not all persisted to disk. See LoadFrom() for details. + ULONG m_cRecs[TBL_COUNT]; // Counts of various tables. + + ULONG m_ulExtra; // Extra data, only persisted if non-zero. (m_heaps&EXTRA_DATA flags) + + ULONG LoadFrom(const void*, ULONG); // Load from a compressed version. Return bytes consumed. + ULONG SaveTo(void *); // Store a compressed version. Return bytes used in buffer. + __checkReturn + HRESULT InitNew(MetadataVersion); +}; + +//***************************************************************************** +// Helper macros and inline functions for navigating through the data. Many +// of the macros are used to define inline accessor functions. Everything +// is based on the naming conventions outlined at the top of the file. +//***************************************************************************** +#define _GETTER(tbl,fld) get##fld##Of##tbl(tbl##Rec *pRec) +#define _GETTER2(tbl,fld,x) get##fld##Of##tbl(tbl##Rec *pRec, x) +#define _GETTER3(tbl,fld,x,y) get##fld##Of##tbl(tbl##Rec *pRec, x, y) +#define _GETTER4(tbl,fld,x,y,z) get##fld##Of##tbl(tbl##Rec *pRec, x, y,z) + +// Direct getter for a field. Defines an inline function like: +// getSomeFieldOfXyz(XyzRec *pRec) { return pRec->m_SomeField;} +// Note that the returned value declaration is NOT included. +#if METADATATRACKER_ENABLED +#define _GETFLD(tbl,fld) _GETTER(tbl,fld){ PVOID pVal = (BYTE*)pRec + offsetof(tbl##Rec, m_##fld); \ + pVal = MetaDataTracker::NoteAccess(pVal); \ + return ((tbl##Rec*)((BYTE*)pVal - offsetof(tbl##Rec, m_##fld)))->Get##fld(); } +#else +#define _GETFLD(tbl,fld) _GETTER(tbl,fld){ return pRec->Get##fld();} +#endif + +// These functions call the helper function getIX to get a two or four byte value from a record, +// and then use that value as an index into the appropriate pool. +// getSomeFieldOfXyz(XyzRec *pRec) { return m_pStrings->GetString(getIX(pRec, _COLDEF(tbl,fld))); } +// Note that the returned value declaration is NOT included. + +// Column definition of a field: Looks like: +// m_XyzCol[XyzRec::COL_SomeField] +#define _COLDEF(tbl,fld) m_TableDefs[TBL_##tbl].m_pColDefs[tbl##Rec::COL_##fld] +#define _COLPAIR(tbl,fld) _COLDEF(tbl,fld), tbl##Rec::COL_##fld +// Size of a record. +#define _CBREC(tbl) m_TableDefs[TBL_##tbl].m_cbRec +// Count of records in a table. +#define _TBLCNT(tbl) m_Schema.m_cRecs[TBL_##tbl] + +#define _GETSTRA(tbl,fld) _GETTER2(tbl, fld, LPCSTR *pszString) \ +{ return getString(getI4(pRec, _COLDEF(tbl,fld)) & m_iStringsMask, pszString); } + +#define _GETSTRW(tbl,fld) _GETTER4(tbl, fld, LPWSTR szOut, ULONG cchBuffer, ULONG *pcchBuffer) \ +{ return getStringW(getI4(pRec, _COLDEF(tbl,fld)) & m_iStringsMask, szOut, cchBuffer, pcchBuffer); } + +#define _GETSTR(tbl, fld) \ + __checkReturn HRESULT _GETSTRA(tbl, fld); \ + __checkReturn HRESULT _GETSTRW(tbl, fld); + + +#define _GETGUID(tbl,fld) _GETTER2(tbl,fld,GUID *pGuid) \ +{ return getGuid(getI4(pRec, _COLDEF(tbl,fld)) & m_iGuidsMask, pGuid); } + +#define _GETBLOB(tbl,fld) __checkReturn HRESULT _GETTER3(tbl,fld,const BYTE **ppbData,ULONG *pcbSize) \ +{ \ + MetaData::DataBlob data; \ + HRESULT hr = getBlob(getI4(pRec, _COLDEF(tbl,fld)) & m_iBlobsMask, &data); \ + *ppbData = data.GetDataPointer(); \ + *pcbSize = (ULONG)data.GetSize(); \ + return hr; \ +} + +#define _GETSIGBLOB(tbl,fld) __checkReturn HRESULT _GETTER3(tbl,fld,PCCOR_SIGNATURE *ppbData,ULONG *pcbSize) \ +{ \ + MetaData::DataBlob data; \ + HRESULT hr = getBlob(getI4(pRec, _COLDEF(tbl,fld)) & m_iBlobsMask, &data); \ + *ppbData = (PCCOR_SIGNATURE)data.GetDataPointer(); \ + *pcbSize = (ULONG)data.GetSize(); \ + return hr; \ +} + +// Like the above functions, but just returns the RID, not a looked-up value. +#define _GETRID(tbl,fld) _GETTER(tbl,fld) \ +{ return getIX(pRec, _COLDEF(tbl,fld)); } + +// Like a RID, but turn into an actual token. +#define _GETTKN(tbl,fld,tok) _GETTER(tbl,fld) \ +{ return TokenFromRid(getIX(pRec, _COLDEF(tbl,fld)), tok); } + +// Get a coded token. +#define _GETCDTKN(tbl,fld,toks) _GETTER(tbl,fld) \ +{ return decodeToken(getIX(pRec, _COLDEF(tbl,fld)), toks, sizeof(toks)/sizeof(toks[0])); } + +// Functions for the start and end of a list. +#define _GETLIST(tbl,fld,tbl2) \ + RID _GETRID(tbl,fld); \ + __checkReturn HRESULT getEnd##fld##Of##tbl(RID nRowIndex, RID *pEndRid) { return getEndRidForColumn(TBL_##tbl, nRowIndex, _COLDEF(tbl,fld), TBL_##tbl2, pEndRid); } + + +#define BYTEARRAY_TO_COLDES(bytearray) (CMiniColDef*)((bytearray) + 1) +#define COLDES_TO_BYTEARRAY(coldes) (((BYTE*)(coldes))-1) + + +//***************************************************************************** +// Base class for the MiniMd. This class provides the schema to derived +// classes. It defines some virtual functions for access to data, suitable +// for use by functions where utmost performance is NOT a requirement. +// Finally, it provides some searching functions, built on the virtual +// data access functions (it is here assumed that if we are searching a table +// for some value, the cost of a virtual function call is acceptable). +// Some static utility functions and associated static data, shared across +// implementations, is provided here. +// +// NB: It's unfortunate that CMiniMDBase "implements" IMetaModelCommonRO rather +// than IMetaModelCommon, as methods on IMetaModelCommonRO are by definition, +// not Enc-aware. Ideally, CMiniMDBase should only implement IMetaModelCommon +// and CMiniMd should be the one implementing IMetaModelCommonRO. +// +// To make that happen would be a substantial refactoring job as RegMeta +// always embeds CMiniMdRW even when it was opened for ReadOnly. +//***************************************************************************** +class CMiniMdBase : public IMetaModelCommonRO +{ + + friend class VerifyLayoutsMD; // verifies class layout doesn't accidentally change + +public: + CMiniMdBase(); + ~CMiniMdBase(); + __checkReturn + virtual HRESULT vGetRow(UINT32 nTableIndex, UINT32 nRowIndex, void **ppRow) = 0; + ULONG GetCountRecs(ULONG ixTbl); + ULONG GetCountTables() { return m_TblCount;} + + // Search a table for the row containing the given key value. + // EG. Constant table has pointer back to Param or Field. + __checkReturn + virtual HRESULT vSearchTable( // RID of matching row, or 0. + ULONG ixTbl, // Table to search. + CMiniColDef sColumn, // Sorted key column, containing search value. + ULONG ulTarget, // Target for search. + RID *pRid) = 0; + + // Search a table for the highest-RID row containing a value that is less than + // or equal to the target value. EG. TypeDef points to first Field, but if + // a TypeDef has no fields, it points to first field of next TypeDef. + __checkReturn + virtual HRESULT vSearchTableNotGreater( // RID of matching row, or 0. + ULONG ixTbl, // Table to search. + CMiniColDef sColumn, // the column def containing search value + ULONG ulTarget, // target for search + RID *pRid) = 0; + + // Search a table for multiple (adjacent) rows containing the given + // key value. EG, InterfaceImpls all point back to the implementing class. + __checkReturn + HRESULT SearchTableForMultipleRows( // First RID found, or 0. + ULONG ixTbl, // Table to search. + CMiniColDef sColumn, // Sorted key column, containing search value. + ULONG ulTarget, // Target for search. + RID *pEnd, // [OPTIONAL, OUT] + RID *pFoundRid); + + // Search for a custom value with a given type. + __checkReturn + HRESULT FindCustomAttributeFor(// RID of custom value, or 0. + RID rid, // The object's rid. + mdToken tkOjb, // The object's type. + mdToken tkType, // Type of custom value. + RID *pFoundRid); + + // Search for the specified Column Definition array in the global cache + BOOL FindSharedColDefs(// TRUE if we found a match in the global cache and updated pTable, FALSE otherwise + CMiniTableDef *pTable, // The table def that wants the column definition array + CMiniColDef *pColsToMatch, // The columns that we need to match + DWORD ixTbl); + + // Return RID to EventMap table, given the rid to a TypeDef. + __checkReturn + HRESULT FindEventMapFor(RID ridParent, RID *pFoundRid); + + // Return RID to PropertyMap table, given the rid to a TypeDef. + __checkReturn + HRESULT FindPropertyMapFor(RID ridParent, RID *pFoundRid); + +#if BIGENDIAN + // Swap a constant + __checkReturn + HRESULT SwapConstant(const void *pBlobValue, DWORD dwType, VOID *pConstant, ULONG BlobLength); +#endif + + // Pull two or four bytes out of a record. + inline static ULONG getIX(const void *pRec, CMiniColDef &def) + { + PVOID pVal = (BYTE *)pRec + def.m_oColumn; + if (def.m_cbColumn == 2) + { + METADATATRACKER_ONLY(pVal = MetaDataTracker::NoteAccess(pVal)); + ULONG ix = GET_UNALIGNED_VAL16(pVal); + return ix; + } + _ASSERTE(def.m_cbColumn == 4); + METADATATRACKER_ONLY(pVal = MetaDataTracker::NoteAccess(pVal)); + return GET_UNALIGNED_VAL32(pVal); + } + + inline static ULONG getIX_NoLogging(const void *pRec, CMiniColDef &def) + { + PVOID pVal = (BYTE *)pRec + def.m_oColumn; + if (def.m_cbColumn == 2) + { + ULONG ix = GET_UNALIGNED_VAL16(pVal); + return ix; + } + _ASSERTE(def.m_cbColumn == 4); + return GET_UNALIGNED_VAL32(pVal); + } + + // Pull four bytes out of a record. + FORCEINLINE static ULONG getI1(const void *pRec, CMiniColDef &def) + { + PVOID pVal = (BYTE *)pRec + def.m_oColumn; + METADATATRACKER_ONLY(pVal = MetaDataTracker::NoteAccess(pVal)); + return *(BYTE*)pVal; + } + + // Pull four bytes out of a record. + FORCEINLINE static ULONG getI4(const void *pRec, CMiniColDef &def) + { + PVOID pVal = (BYTE *)pRec + def.m_oColumn; + METADATATRACKER_ONLY(pVal = MetaDataTracker::NoteAccess(pVal)); + return GET_UNALIGNED_VAL32(pVal); + } + + // Function to encode a token into fewer bits. Looks up token type in array of types. + ULONG static encodeToken(RID rid, mdToken typ, const mdToken rTokens[], ULONG32 cTokens); + + // Decode a token. + inline static mdToken decodeToken(mdToken val, const mdToken rTokens[], ULONG32 cTokens) + { + //<TODO>@FUTURE: make compile-time calculation</TODO> + ULONG32 ix = (ULONG32)(val & ~(-1 << m_cb[cTokens])); + // If the coded token has an invalid table index, return the first entry + // from the array of valid token types. It would be preferable to + // return an error or to raise an exception. + if (ix >= cTokens) + return rTokens[0]; + return TokenFromRid(val >> m_cb[cTokens], rTokens[ix]); + } + static const int m_cb[]; + + // Given a token, what table does it live in? + inline ULONG GetTblForToken(mdToken tk) + { + tk = TypeFromToken(tk); + return (tk < mdtString) ? tk >> 24 : (ULONG) -1; + } + + //***************************************************************************** + // Returns whether the data has been verified, which means it was verified by a + // trusted source and has not changed. + // + // If so, this means the following aspects of the data can be trusted as accurate: + // - m_Schema.IsSorted[TBL_PropertyMap] reflects whether that table is sorted by Parent (see CMiniMdRW::PreSaveFull) + // - m_Schema.IsSorted[TBL_EventMap] reflects whether that table is sorted by Parent (see CMiniMdRW::PreSaveFull) + // + // Currently, metadata saved in NGen images is the only trusted source. + //***************************************************************************** + BOOL IsVerified() + { + return m_fVerifiedByTrustedSource && CommonIsRo(); + } + + void SetVerifiedByTrustedSource(BOOL fVerifiedByTrustedSource) + { + m_fVerifiedByTrustedSource = fVerifiedByTrustedSource; + } + + STDMETHODIMP GetRvaOffsetData(// S_OK or error + DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. + DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. + DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. + DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. + DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. + DWORD *pFieldRvaCount) // [OUT] Number of records in FieldRVA table. + { + _ASSERTE("Not implemented"); + return E_NOTIMPL; + } + + //***************************************************************************** + // Some of the tables need coded tokens, not just rids (ie, the column can + // refer to more than one other table). Code the tokens into as few bits + // as possible, by using 1, 2, 3, etc., bits to code the token type, then + // use that value to index into an array of token types. + //***************************************************************************** + static const mdToken mdtTypeDefOrRef[3]; + static const mdToken mdtHasConstant[3]; + static const mdToken mdtHasCustomAttribute[24]; + static const mdToken mdtHasFieldMarshal[2]; + static const mdToken mdtHasDeclSecurity[3]; + static const mdToken mdtMemberRefParent[5]; + static const mdToken mdtHasSemantic[2]; + static const mdToken mdtMethodDefOrRef[2]; + static const mdToken mdtMemberForwarded[2]; + static const mdToken mdtImplementation[3]; + static const mdToken mdtCustomAttributeType[5]; + static const mdToken mdtResolutionScope[4]; + static const mdToken mdtTypeOrMethodDef[2]; + + +public: + virtual BOOL IsWritable() = 0; + + +protected: + CMiniMdSchema m_Schema; // data header. + ULONG m_TblCount; // Tables in this database. + BOOL m_fVerifiedByTrustedSource; // whether the data was verified by a trusted source + + // Declare CMiniColDefs for every table. They look like either: + // static const BYTE s_xyz[]; + // or + // static const BYTE* s_xyz; + + #include "mdcolumndescriptors.h" + + static const BYTE* const s_TableColumnDescriptors[TBL_COUNT]; + CMiniTableDef m_TableDefs[TBL_COUNT]; + + ULONG m_iStringsMask; + ULONG m_iGuidsMask; + ULONG m_iBlobsMask; + + __checkReturn + HRESULT SchemaPopulate(const void *pvData, ULONG cbData, ULONG *pcbUsed); + __checkReturn + HRESULT SchemaPopulate(const CMiniMdBase &that); + __checkReturn + HRESULT InitColsForTable(CMiniMdSchema &Schema, int ixTbl, CMiniTableDef *pTable, int bExtra, BOOL fUsePointers); + __checkReturn + HRESULT SchemaPopulate2(ULONG *pcbTables, int bExtra=false); + const CMiniTableDef* GetTableDefTemplate(int ixTbl); + __checkReturn + HRESULT SetNewColumnDefinition(CMiniTableDef *pTable, CMiniColDef* pCols, DWORD ixTbl); + +private: + + BOOL UsesAllocatedMemory(CMiniColDef* pCols); +}; + + +#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN +#define MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED() MarkUnsafeToDelete() +#else +#define MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED() +#endif + +//***************************************************************************** +// This class defines the interface to the MiniMd. The template parameter is +// a derived class which provides implementations for a few primitives that +// the interface is built upon. +// To use, declare a class: +// class CMyMiniMd : public CMiniMdTemplate<CMyMiniMd> {...}; +// and provide implementations of the primitives. Any non-trivial +// implementation will also provide initialization, and probably serialization +// functions as well. +//***************************************************************************** +template <class Impl> class CMiniMdTemplate : public CMiniMdBase +{ +#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN +protected: + CMiniMdTemplate() : m_isSafeToDelete(TRUE) { } +#endif + + // Primitives -- these must be implemented in the Impl class. +public: + __checkReturn + FORCEINLINE HRESULT getString(UINT32 nIndex, __out LPCSTR *pszString) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetString(nIndex, pszString); + } + __checkReturn + FORCEINLINE HRESULT getStringW(ULONG nIndex, __inout_ecount (cchBuffer) LPWSTR szOut, ULONG cchBuffer, ULONG *pcchBuffer) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetStringW(nIndex, szOut, cchBuffer, pcchBuffer); + } + __checkReturn + FORCEINLINE HRESULT getGuid(UINT32 nIndex, GUID *pGuid) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetGuid(nIndex, pGuid); + } + __checkReturn + FORCEINLINE HRESULT getBlob(UINT32 nIndex, __out MetaData::DataBlob *pData) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetBlob(nIndex, pData); + } + __checkReturn + FORCEINLINE HRESULT getRow(UINT32 nTableIndex, UINT32 nRowIndex, __deref_out void **ppRow) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetRow(nTableIndex, nRowIndex, reinterpret_cast<BYTE **>(ppRow)); + } + __checkReturn + FORCEINLINE HRESULT getEndRidForColumn( + UINT32 nTableIndex, + RID nRowIndex, + CMiniColDef &columnDefinition, + UINT32 nTargetTableIndex, + __out RID *pEndRid) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetEndRidForColumn(nTableIndex, nRowIndex, columnDefinition, nTargetTableIndex, pEndRid); + } + __checkReturn + FORCEINLINE HRESULT doSearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ixColumn, ULONG ulTarget, RID *pFoundRid) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_SearchTable(ixTbl, sColumn, ixColumn, ulTarget, pFoundRid); + } + + // IMetaModelCommonRO interface beginning + __checkReturn + HRESULT CommonGetScopeProps( + LPCUTF8 *pszName, + GUID *pMvid) + { + HRESULT hr = S_OK; + ModuleRec *pRec; + IfFailRet(GetModuleRecord(1, &pRec)); + if (pszName != NULL) + { + IfFailRet(getNameOfModule(pRec, pszName)); + } + if (pMvid != NULL) + { + IfFailRet(getMvidOfModule(pRec, pMvid)); + } + return hr; + } + + //***************************************************************************** + // Get name and sig of a methodDef + //***************************************************************************** + HRESULT CommonGetMethodDefProps( + mdMethodDef tkMethodDef, + LPCUTF8 *pszName, + DWORD *pdwFlags, + PCCOR_SIGNATURE *ppvSigBlob, + ULONG *pcbSigBlob + ) + { + + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + HRESULT hr; + + LPCUTF8 szName; + DWORD dwFlags; + PCCOR_SIGNATURE pvSigBlob; + ULONG cbSigBlob; + + _ASSERTE(TypeFromToken(tkMethodDef) == mdtMethodDef); + MethodRec *pMethodRec; + IfFailRet(GetMethodRecord(RidFromToken(tkMethodDef), &pMethodRec)); + IfFailRet(getNameOfMethod(pMethodRec, &szName)); + dwFlags = getFlagsOfMethod(pMethodRec); + IfFailRet(getSignatureOfMethod(pMethodRec, &pvSigBlob, &cbSigBlob)); + + if (pszName) + *pszName = szName; + if (pdwFlags) + *pdwFlags = dwFlags; + if (ppvSigBlob) + *ppvSigBlob = pvSigBlob; + if (pcbSigBlob) + *pcbSigBlob = cbSigBlob; + + return S_OK; + } + + HRESULT CommonGetMemberRefProps( + mdMemberRef tkMemberRef, + mdToken *pParentToken + ) + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + HRESULT hr; + + _ASSERTE(TypeFromToken(tkMemberRef) == mdtMemberRef); + + MemberRefRec *pMemberRefRec; + IfFailRet(GetMemberRefRecord(RidFromToken(tkMemberRef), &pMemberRefRec)); + if (pParentToken != NULL) + *pParentToken = getClassOfMemberRef(pMemberRefRec); + + return S_OK; + } + + + + + __checkReturn + HRESULT CommonGetTypeRefProps( + mdTypeRef tr, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkResolution) + { + HRESULT hr = S_OK; + TypeRefRec *pRec; + IfFailRet(GetTypeRefRecord(RidFromToken(tr), &pRec)); + if (pszNamespace != NULL) + { + IfFailRet(getNamespaceOfTypeRef(pRec, pszNamespace)); + } + if (pszName != NULL) + { + IfFailRet(getNameOfTypeRef(pRec, pszName)); + } + if (ptkResolution != NULL) + { + *ptkResolution = getResolutionScopeOfTypeRef(pRec); + } + return hr; + } + + __checkReturn + virtual HRESULT CommonGetTypeDefProps( + mdTypeDef td, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + DWORD *pdwFlags, + mdToken *pdwExtends, + ULONG *pMethodList) + { + HRESULT hr = S_OK; + TypeDefRec *pRec; + IfFailRet(GetTypeDefRecord(RidFromToken(td), &pRec)); + if (pszNamespace != NULL) + { + IfFailRet(getNamespaceOfTypeDef(pRec, pszNamespace)); + } + if (pszName != NULL) + { + IfFailRet(getNameOfTypeDef(pRec, pszName)); + } + if (pdwFlags != NULL) + { + *pdwFlags = getFlagsOfTypeDef(pRec); + } + if (pdwExtends != NULL) + { + *pdwExtends = getExtendsOfTypeDef(pRec); + } + if (pMethodList != NULL) + { + *pMethodList = getMethodListOfTypeDef(pRec); + } + return hr; + } + + __checkReturn + virtual HRESULT CommonGetTypeSpecProps( + mdTypeSpec ts, + PCCOR_SIGNATURE *ppvSig, + ULONG *pcbSig) + { + HRESULT hr = S_OK; + TypeSpecRec *pRec; + IfFailRet(GetTypeSpecRecord(RidFromToken(ts), &pRec)); + ULONG cb; + IfFailRet(getSignatureOfTypeSpec(pRec, ppvSig, &cb)); + *pcbSig = cb; + return hr; + } + + __checkReturn + virtual HRESULT CommonGetEnclosingClassOfTypeDef( + mdTypeDef td, + mdTypeDef *ptkEnclosingTypeDef) + { + _ASSERTE(ptkEnclosingTypeDef != NULL); + + HRESULT hr; + NestedClassRec *pRec; + RID iRec; + + IfFailRet(FindNestedClassFor(RidFromToken(td), &iRec)); + if (iRec == 0) + { + *ptkEnclosingTypeDef = mdTypeDefNil; + return S_OK; + } + + IfFailRet(GetNestedClassRecord(iRec, &pRec)); + *ptkEnclosingTypeDef = getEnclosingClassOfNestedClass(pRec); + return S_OK; + } + + + __checkReturn + virtual HRESULT CommonGetAssemblyProps( + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKey, + ULONG *pcbPublicKey, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale) + { + HRESULT hr = S_OK; + AssemblyRec *pRec; + + IfFailRet(GetAssemblyRecord(1, &pRec)); + + if (pusMajorVersion) *pusMajorVersion = pRec->GetMajorVersion(); + if (pusMinorVersion) *pusMinorVersion = pRec->GetMinorVersion(); + if (pusBuildNumber) *pusBuildNumber = pRec->GetBuildNumber(); + if (pusRevisionNumber) *pusRevisionNumber = pRec->GetRevisionNumber(); + if (pdwFlags != NULL) + { + *pdwFlags = pRec->GetFlags(); + } + + // Turn on the afPublicKey if PublicKey blob is not empty + if (pdwFlags != NULL) + { + DWORD cbPublicKey; + const BYTE *pbPublicKey; + IfFailRet(getPublicKeyOfAssembly(pRec, &pbPublicKey, &cbPublicKey)); + if (cbPublicKey) + *pdwFlags |= afPublicKey; + } + if (ppbPublicKey != NULL) + { + IfFailRet(getPublicKeyOfAssembly(pRec, reinterpret_cast<const BYTE **>(ppbPublicKey), pcbPublicKey)); + } + if (pszName != NULL) + { + IfFailRet(getNameOfAssembly(pRec, pszName)); + } + if (pszLocale != NULL) + { + IfFailRet(getLocaleOfAssembly(pRec, pszLocale)); + } + return hr; + } + + __checkReturn + virtual HRESULT CommonGetAssemblyRefProps( + mdAssemblyRef tkAssemRef, + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKeyOrToken, + ULONG *pcbPublicKeyOrToken, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale, + const void **ppbHashValue, + ULONG *pcbHashValue) + { + HRESULT hr = S_OK; + AssemblyRefRec *pRec; + + IfFailRet(GetAssemblyRefRecord(RidFromToken(tkAssemRef), &pRec)); + + if (pusMajorVersion) *pusMajorVersion = pRec->GetMajorVersion(); + if (pusMinorVersion) *pusMinorVersion = pRec->GetMinorVersion(); + if (pusBuildNumber) *pusBuildNumber = pRec->GetBuildNumber(); + if (pusRevisionNumber) *pusRevisionNumber = pRec->GetRevisionNumber(); + if (pdwFlags) *pdwFlags = pRec->GetFlags(); + if (ppbPublicKeyOrToken != NULL) + { + IfFailRet(getPublicKeyOrTokenOfAssemblyRef(pRec, reinterpret_cast<const BYTE **>(ppbPublicKeyOrToken), pcbPublicKeyOrToken)); + } + if (pszName != NULL) + { + IfFailRet(getNameOfAssemblyRef(pRec, pszName)); + } + if (pszLocale != NULL) + { + IfFailRet(getLocaleOfAssemblyRef(pRec, pszLocale)); + } + if (ppbHashValue != NULL) + { + IfFailRet(getHashValueOfAssemblyRef(pRec, reinterpret_cast<const BYTE **>(ppbHashValue), pcbHashValue)); + } + return hr; + } + + __checkReturn + virtual HRESULT CommonGetModuleRefProps( + mdModuleRef tkModuleRef, + LPCUTF8 *pszName) + { + HRESULT hr = S_OK; + ModuleRefRec *pRec; + + IfFailRet(GetModuleRefRecord(RidFromToken(tkModuleRef), &pRec)); + IfFailRet(getNameOfModuleRef(pRec, pszName)); + return hr; + } + + __checkReturn + HRESULT CommonFindExportedType( + LPCUTF8 szNamespace, + LPCUTF8 szName, + mdToken tkEnclosingType, + mdExportedType *ptkExportedType) + { + HRESULT hr; + ExportedTypeRec *pRec; + ULONG ulCount; + LPCUTF8 szTmp; + mdToken tkImpl; + + _ASSERTE(szName && ptkExportedType); + + // Set NULL namespace to empty string. + if (!szNamespace) + szNamespace = ""; + + // Set output to Nil. + *ptkExportedType = mdTokenNil; + + ulCount = getCountExportedTypes(); + while (ulCount) + { + IfFailRet(GetExportedTypeRecord(ulCount--, &pRec)); + + // Handle the case of nested vs. non-nested classes. + tkImpl = getImplementationOfExportedType(pRec); + if (TypeFromToken(tkImpl) == mdtExportedType && !IsNilToken(tkImpl)) + { + // Current ExportedType being looked at is a nested type, so + // comparing the implementation token. + if (tkImpl != tkEnclosingType) + continue; + } + else if (TypeFromToken(tkEnclosingType) == mdtExportedType && + !IsNilToken(tkEnclosingType)) + { + // ExportedType passed in is nested but the current ExportedType is not. + continue; + } + + // Compare name and namespace. + IfFailRet(getTypeNameOfExportedType(pRec, &szTmp)); + if (strcmp(szTmp, szName)) + continue; + IfFailRet(getTypeNamespaceOfExportedType(pRec, &szTmp)); + if (!strcmp(szTmp, szNamespace)) + { + *ptkExportedType = TokenFromRid(ulCount+1, mdtExportedType); + return S_OK; + } + } + return CLDB_E_RECORD_NOTFOUND; + } + + __checkReturn + virtual HRESULT CommonGetExportedTypeProps( + mdToken tkExportedType, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkImpl) + { + HRESULT hr = S_OK; + ExportedTypeRec *pRec; + + IfFailRet(GetExportedTypeRecord(RidFromToken(tkExportedType), &pRec)); + + if (pszNamespace != NULL) + { + IfFailRet(getTypeNamespaceOfExportedType(pRec, pszNamespace)); + } + if (pszName != NULL) + { + IfFailRet(getTypeNameOfExportedType(pRec, pszName)); + } + if (ptkImpl) *ptkImpl = getImplementationOfExportedType(pRec); + return hr; + } + + int CommonIsRo() + { + return static_cast<Impl*>(this)->Impl_IsRo(); + } + + + + HRESULT CommonGetCustomAttributeProps( + mdCustomAttribute cv, // [IN] CustomAttribute token. + mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here. + mdToken *ptkType, // [OUT, OPTIONAL] Put AttrType token here. + const void **ppBlob, // [OUT, OPTIONAL] Put pointer to data here. + ULONG *pcbSize) // [OUT, OPTIONAL] Put size of date here. + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + HRESULT hr; + _ASSERTE(TypeFromToken(cv) == mdtCustomAttribute); + CustomAttributeRec *pRec; // A CustomAttribute record. + const void *pBlob; + ULONG cbSize; + IfFailRet(GetCustomAttributeRecord(RidFromToken(cv), &pRec)); + if (ptkObj) + *ptkObj = getParentOfCustomAttribute(pRec); + if (ptkType) + *ptkType = getTypeOfCustomAttribute(pRec); + + if (!ppBlob) + ppBlob = &pBlob; + if (!pcbSize) + pcbSize = &cbSize; + IfFailRet(getValueOfCustomAttribute(pRec, (const BYTE **)ppBlob, pcbSize)); + return S_OK; + } + + //***************************************************************************** + // Get name, parent and flags of a fieldDef + //***************************************************************************** + HRESULT CommonGetFieldDefProps( + mdFieldDef tkFieldDef, + mdTypeDef *ptkParent, + LPCUTF8 *pszName, + DWORD *pdwFlags + ) + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + _ASSERTE(TypeFromToken(tkFieldDef) == mdtFieldDef); + + HRESULT hr; + + FieldRec *pFieldRec; + IfFailRet(GetFieldRecord(RidFromToken(tkFieldDef), &pFieldRec)); + + if(ptkParent) + { + IfFailRet(FindParentOfField(RidFromToken(tkFieldDef), (RID *) ptkParent)); + RidToToken(*ptkParent, mdtTypeDef); + } + if (pszName) + IfFailRet(getNameOfField(pFieldRec, pszName)); + if (pdwFlags) + *pdwFlags = getFlagsOfField(pFieldRec); + + return S_OK; + } + + __checkReturn + HRESULT FindParentOfMethodHelper(mdMethodDef md, mdTypeDef *ptd) + { + HRESULT hr; + IfFailRet(FindParentOfMethod(RidFromToken(md), (RID *)ptd)); + RidToToken(*ptd, mdtTypeDef); + return NOERROR; + } + + //***************************************************************************** + // Helper function to lookup and retrieve a CustomAttribute. + //***************************************************************************** + __checkReturn + HRESULT CompareCustomAttribute( + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + ULONG rid) // [IN] the rid of the custom attribute to compare to + { + CustomAttributeRec *pRec; // A CustomAttribute record. + LPCUTF8 szNamespaceTmp = NULL; // Namespace of a CustomAttribute's type. + LPCUTF8 szNameTmp = NULL; // Name of a CustomAttribute's type. + int iLen; // Length of a component name. + HRESULT hr = S_FALSE; + HRESULT hrMatch = S_FALSE; + + if (!_IsValidTokenBase(tkObj)) + return COR_E_BADIMAGEFORMAT; + + // Get the row. + IfFailGo(GetCustomAttributeRecord(rid, &pRec)); + + // Check the parent. In debug, always check. In retail, only when scanning. + mdToken tkParent; + tkParent = getParentOfCustomAttribute(pRec); + if (tkObj != tkParent) + { + goto ErrExit; + } + + hr = CommonGetNameOfCustomAttribute(rid, &szNamespaceTmp, &szNameTmp); + if (hr != S_OK) + goto ErrExit; + + iLen = -1; + if (*szNamespaceTmp) + { + iLen = (int)strlen(szNamespaceTmp); + if (strncmp(szName, szNamespaceTmp, iLen) != 0) + goto ErrExit; + // Namespace separator after the Namespace? + if (szName[iLen] != NAMESPACE_SEPARATOR_CHAR) + goto ErrExit; + } + // Check the type name after the separator. + if (strcmp(szName+iLen+1, szNameTmp) != 0) + goto ErrExit; + + hrMatch = S_OK; + ErrExit: + + if (FAILED(hr)) + return hr; + + return hrMatch; + } // CompareCustomAttribute + + + //***************************************************************************** + // Helper function to lookup the name of a custom attribute + // Note that this function can return S_FALSE to support being called + // by CompareCustomAttribute. See GetTypeDefRefTokenInTypeSpec for + // details on when this will happen. + //***************************************************************************** + __checkReturn + HRESULT CommonGetNameOfCustomAttribute( + ULONG rid, // [IN] the rid of the custom attribute + LPCUTF8 *pszNamespace, // [OUT] Namespace of Custom Attribute. + LPCUTF8 *pszName) // [OUT] Name of Custom Attribute. + { + CustomAttributeRec *pRec; // A CustomAttribute record. + mdToken tkTypeTmp; // Type of some CustomAttribute. + RID ridTmp; // Rid of some custom value. + HRESULT hr = S_FALSE; + + // Get the row. + IfFailGo(GetCustomAttributeRecord(rid, &pRec)); + + // Get the type. + tkTypeTmp = getTypeOfCustomAttribute(pRec); + + // If the record is a MemberRef or a MethodDef, we will come back here to check + // the type of the parent. + CheckParentType: + + if (!_IsValidTokenBase(tkTypeTmp)) + return COR_E_BADIMAGEFORMAT; + + ridTmp = RidFromToken(tkTypeTmp); + + // Get the name of the type. + switch (TypeFromToken(tkTypeTmp)) + { + case mdtTypeRef: + { + TypeRefRec *pTR; + IfFailGo(GetTypeRefRecord(ridTmp, &pTR)); + IfFailGo(getNamespaceOfTypeRef(pTR, pszNamespace)); + IfFailGo(getNameOfTypeRef(pTR, pszName)); + } + break; + case mdtTypeDef: + { + TypeDefRec *pTD; + IfFailGo(GetTypeDefRecord(ridTmp, &pTD)); + IfFailGo(getNamespaceOfTypeDef(pTD, pszNamespace)); + IfFailGo(getNameOfTypeDef(pTD, pszName)); + } + break; + case mdtTypeSpec: + { + // If this has an encoded token, we'll take a look. If it contains + // a base type, we'll just return a non-match. + + hr = GetTypeDefRefTokenInTypeSpec(tkTypeTmp, &tkTypeTmp); + IfFailGo(hr); + + if (hr == S_OK) + // Ok, tkTypeTmp should be the type token now. + goto CheckParentType; + + // This doesn't have a coded typedef or typeref. + goto ErrExit; + } + case mdtMethodDef: + { + // Follow the parent. + IfFailGo( FindParentOfMethodHelper(tkTypeTmp, &tkTypeTmp)); + goto CheckParentType; + } + break; + case mdtMemberRef: + { + MemberRefRec *pMember; + IfFailGo(GetMemberRefRecord(ridTmp, &pMember)); + // Follow the parent. + tkTypeTmp = getClassOfMemberRef(pMember); + goto CheckParentType; + } + break; + case mdtString: + default: + if(REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 0)) + _ASSERTE(!"Unexpected token type in FindCustomAttributeByName"); + hr = COR_E_BADIMAGEFORMAT; + goto ErrExit; + } // switch (TypeFromToken(tkTypeTmp)) + + hr = S_OK; + ErrExit: + + return hr; + } // CommonGetNameOfCustomAttribute + + __checkReturn + HRESULT GetTypeDefRefTokenInTypeSpec(mdTypeSpec tkTypeSpec, // [IN] TypeSpec token to look + mdToken *tkEnclosedToken) // [OUT] The enclosed type token + { + _ASSERTE(TypeFromToken(tkTypeSpec) == mdtTypeSpec); + if (TypeFromToken(tkTypeSpec) != mdtTypeSpec || !_IsValidTokenBase(tkTypeSpec)) + return COR_E_BADIMAGEFORMAT; + + HRESULT hr; + TypeSpecRec *pTS; + IfFailRet(GetTypeSpecRecord(RidFromToken(tkTypeSpec), &pTS)); + ULONG cbSig = 0; + PCCOR_SIGNATURE pSig; + PCCOR_SIGNATURE pEnd; + ULONG data = 0; + + IfFailRet(getSignatureOfTypeSpec(pTS, &pSig, &cbSig)); + pEnd = pSig + cbSig; + + if (cbSig == 0) + return COR_E_BADIMAGEFORMAT; + + pSig += CorSigUncompressData(pSig, &data); + + while (pSig < pEnd && CorIsModifierElementType((CorElementType) data)) + { + pSig += CorSigUncompressData(pSig, &data); + } + + // See if the signature was bad + if (pSig >= pEnd) + return COR_E_BADIMAGEFORMAT; + + // pSig should point to the element type now. + if (data == ELEMENT_TYPE_VALUETYPE || data == ELEMENT_TYPE_CLASS) + { + // Get the new type token + if (CorSigUncompressToken(pSig, tkEnclosedToken) == 0) + return COR_E_BADIMAGEFORMAT; + + // Ok, tkEnclosedToken should be the type token now + return S_OK; + } + + // The enclosed type is a base type or an array. We don't have a token to hand out + *tkEnclosedToken = mdTokenNil; + + return S_FALSE; + } + + + + //***************************************************************************** + // Given a scope, return the number of tokens in a given table + //***************************************************************************** + ULONG CommonGetRowCount( // return hresult + DWORD tkKind) // [IN] pass in the kind of token. + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + ULONG ulCount = 0; + + switch (tkKind) + { + case mdtTypeDef: + ulCount = getCountTypeDefs(); + break; + case mdtTypeRef: + ulCount = getCountTypeRefs(); + break; + case mdtMethodDef: + ulCount = getCountMethods(); + break; + case mdtFieldDef: + ulCount = getCountFields(); + break; + case mdtMemberRef: + ulCount = getCountMemberRefs(); + break; + case mdtInterfaceImpl: + ulCount = getCountInterfaceImpls(); + break; + case mdtParamDef: + ulCount = getCountParams(); + break; + case mdtFile: + ulCount = getCountFiles(); + break; + case mdtAssemblyRef: + ulCount = getCountAssemblyRefs(); + break; + case mdtAssembly: + ulCount = getCountAssemblys(); + break; + case mdtCustomAttribute: + ulCount = getCountCustomAttributes(); + break; + case mdtModule: + ulCount = getCountModules(); + break; + case mdtPermission: + ulCount = getCountDeclSecuritys(); + break; + case mdtSignature: + ulCount = getCountStandAloneSigs(); + break; + case mdtEvent: + ulCount = getCountEvents(); + break; + case mdtProperty: + ulCount = getCountPropertys(); + break; + case mdtModuleRef: + ulCount = getCountModuleRefs(); + break; + case mdtTypeSpec: + ulCount = getCountTypeSpecs(); + break; + case mdtExportedType: + ulCount = getCountExportedTypes(); + break; + case mdtManifestResource: + ulCount = getCountManifestResources(); + break; + case mdtGenericParam: + ulCount = getCountGenericParams(); + break; + case mdtMethodSpec: + ulCount = getCountMethodSpecs(); + break; + default: + Debug_ReportError("Invalid token kind (table)"); + ulCount = 0; + break; + } + return ulCount; + } // ULONG CommonGetRowCount() + + + + //***************************************************************************** + // Locate methodimpl token range for a given typeDef + //***************************************************************************** + HRESULT CommonGetMethodImpls( + mdTypeDef tkTypeDef, // [IN] typeDef to scope search + mdToken *ptkMethodImplFirst, // [OUT] returns first methodImpl token + ULONG *pMethodImplCount // [OUT] returns # of methodImpl tokens scoped to type + ) + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + _ASSERTE(TypeFromToken(tkTypeDef) == mdtTypeDef); + _ASSERTE(ptkMethodImplFirst != NULL); + _ASSERTE(pMethodImplCount != NULL); + + HRESULT hr; + + RID ridEnd; + RID ridStart; + IfFailGo(getMethodImplsForClass(RidFromToken(tkTypeDef), &ridEnd, &ridStart)); + *pMethodImplCount = ridEnd - ridStart; + if (*pMethodImplCount) + { + *ptkMethodImplFirst = TokenFromRid(TBL_MethodImpl << 24, ridStart); + } + hr = S_OK; + + ErrExit: + return hr; + } + + //***************************************************************************** + // Extract row info for methodImpl + //***************************************************************************** + HRESULT CommonGetMethodImplProps( + mdToken tkMethodImpl, // [IN] methodImpl + mdToken *pBody, // [OUT] returns body token + mdToken *pDecl // [OUT] returns decl token + ) + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + HRESULT hr; + _ASSERTE(TypeFromToken(tkMethodImpl) == (TBL_MethodImpl << 24)); + _ASSERTE(pBody != NULL); + _ASSERTE(pDecl != NULL); + MethodImplRec *pRec; + IfFailGo(GetMethodImplRecord(RidFromToken(tkMethodImpl), &pRec)); + *pBody = getMethodBodyOfMethodImpl(pRec); + *pDecl = getMethodDeclarationOfMethodImpl(pRec); + hr = S_OK; + ErrExit: + return hr; + } + + // IMetaModelCommonRO interface end + + + + +public: +// friend class CLiteWeightStgdb; + + __checkReturn + virtual HRESULT vGetRow(UINT32 nTableIndex, UINT32 nRowIndex, void **ppRow) + { + return getRow(nTableIndex, nRowIndex, ppRow); + } + +public: + + //************************************************************************* + // This group of functions are table-level (one function per table). Functions like + // getting a count of rows. + + // Functions to get the count of rows in a table. Functions like: + // ULONG getCountXyzs() { return m_Schema.m_cRecs[TBL_Xyz];} +#undef MiniMdTable +#define MiniMdTable(tbl) ULONG getCount##tbl##s() { return _TBLCNT(tbl); } + MiniMdTables(); + // macro misspells some names. + ULONG getCountProperties() {return getCountPropertys();} + ULONG getCountMethodSemantics() {return getCountMethodSemanticss();} + + // Functions for getting a row by rid. Look like: + // HRESULT GetXyzRecord(RID rid, XyzRec **ppRecord) { return m_Tables[TBL_Xyz].GetRecord(rid, ppRecord); } + // e.g.: + // HRESULT GetMethodRecord(RID rid, MethodRec **ppRecord) { return m_Tables[TBL_Method].GetRecord(rid, ppRecord); } + #undef MiniMdTable +#define MiniMdTable(tbl) __checkReturn HRESULT Get##tbl##Record(RID rid, tbl##Rec **ppRecord) { \ + return getRow(TBL_##tbl, rid, reinterpret_cast<void **>(ppRecord)); } + MiniMdTables(); + + //************************************************************************* + // These are specialized searching functions. Mostly generic (ie, find + // a custom value for any object). + + // Functions to search for a record relating to another record. + // Return RID to Constant table. + __checkReturn + HRESULT FindConstantFor(RID rid, mdToken typ, RID *pFoundRid) + { return doSearchTable(TBL_Constant, _COLPAIR(Constant,Parent), encodeToken(rid,typ,mdtHasConstant,lengthof(mdtHasConstant)), pFoundRid); } + + // Return RID to FieldMarshal table. + __checkReturn + HRESULT FindFieldMarshalFor(RID rid, mdToken typ, RID *pFoundRid) + { return doSearchTable(TBL_FieldMarshal, _COLPAIR(FieldMarshal,Parent), encodeToken(rid,typ,mdtHasFieldMarshal,lengthof(mdtHasFieldMarshal)), pFoundRid); } + + // Return RID to ClassLayout table, given the rid to a TypeDef. + __checkReturn + HRESULT FindClassLayoutFor(RID rid, RID *pFoundRid) + { return doSearchTable(TBL_ClassLayout, _COLPAIR(ClassLayout,Parent), RidFromToken(rid), pFoundRid); } + + // given a rid to the Event table, find an entry in EventMap table that contains the back pointer + // to its typedef parent + __checkReturn + HRESULT FindEventMapParentOfEvent(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_EventMap, _COLDEF(EventMap,EventList), rid, pFoundRid); + } + // return the parent eventmap rid given a event rid + __checkReturn + HRESULT FindParentOfEvent(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_EventMap, _COLDEF(EventMap,EventList), rid, pFoundRid); + } + + // given a rid to the Event table, find an entry in EventMap table that contains the back pointer + // to its typedef parent + __checkReturn + HRESULT FindPropertyMapParentOfProperty(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_PropertyMap, _COLDEF(PropertyMap,PropertyList), rid, pFoundRid); + } + // return the parent propertymap rid given a property rid + __checkReturn + HRESULT FindParentOfProperty(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_PropertyMap, _COLDEF(PropertyMap,PropertyList), rid, pFoundRid); + } + + // Return RID to MethodSemantics table, given the rid to a MethodDef. + __checkReturn + HRESULT FindMethodSemanticsFor(RID rid, RID *pFoundRid) + { return doSearchTable(TBL_MethodSemantics, _COLPAIR(MethodSemantics,Method), RidFromToken(rid), pFoundRid); } + + // return the parent typedef rid given a field def rid + __checkReturn + HRESULT FindParentOfField(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_TypeDef, _COLDEF(TypeDef,FieldList), rid, pFoundRid); + } + + // return the parent typedef rid given a method def rid + __checkReturn + HRESULT FindParentOfMethod(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_TypeDef, _COLDEF(TypeDef,MethodList), rid, pFoundRid); + } + + __checkReturn + HRESULT FindParentOfParam(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_Method, _COLDEF(Method,ParamList), rid, pFoundRid); + } + + // Find a FieldLayout record given the corresponding Field. + __checkReturn + HRESULT FindFieldLayoutFor(RID rid, RID *pFoundRid) + { return doSearchTable(TBL_FieldLayout, _COLPAIR(FieldLayout, Field), rid, pFoundRid); } + + // Return RID to Constant table. + __checkReturn + HRESULT FindImplMapFor(RID rid, mdToken typ, RID *pFoundRid) + { return doSearchTable(TBL_ImplMap, _COLPAIR(ImplMap,MemberForwarded), encodeToken(rid,typ,mdtMemberForwarded,lengthof(mdtMemberForwarded)), pFoundRid); } + + // Return RID to FieldRVA table. + __checkReturn + HRESULT FindFieldRVAFor(RID rid, RID *pFoundRid) + { return doSearchTable(TBL_FieldRVA, _COLPAIR(FieldRVA, Field), rid, pFoundRid); } + + // Find a NestedClass record given the corresponding Field. + __checkReturn + HRESULT FindNestedClassFor(RID rid, RID *pFoundRid) + { return doSearchTable(TBL_NestedClass, _COLPAIR(NestedClass, NestedClass), rid, pFoundRid); } + + //************************************************************************* + // These are table-specific functions. + + // ModuleRec + _GETSTR(Module,Name); + __checkReturn HRESULT _GETGUID(Module,Mvid); + __checkReturn HRESULT _GETGUID(Module,EncId); + __checkReturn HRESULT _GETGUID(Module,EncBaseId); + + // TypeRefRec + mdToken _GETCDTKN(TypeRef, ResolutionScope, mdtResolutionScope); + _GETSTR(TypeRef, Name); + _GETSTR(TypeRef, Namespace); + + // TypeDefRec + ULONG _GETFLD(TypeDef,Flags); // USHORT getFlagsOfTypeDef(TypeDefRec *pRec); + _GETSTR(TypeDef,Name); + _GETSTR(TypeDef,Namespace); + + _GETLIST(TypeDef,FieldList,Field); // RID getFieldListOfTypeDef(TypeDefRec *pRec); + _GETLIST(TypeDef,MethodList,Method); // RID getMethodListOfTypeDef(TypeDefRec *pRec); + mdToken _GETCDTKN(TypeDef,Extends,mdtTypeDefOrRef); // mdToken getExtendsOfTypeDef(TypeDefRec *pRec); + + __checkReturn + HRESULT getGenericParamsForTypeDef(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_GenericParam, + _COLDEF(GenericParam,Owner), + encodeToken(rid, mdtTypeDef, mdtTypeOrMethodDef, lengthof(mdtTypeOrMethodDef)), + pEnd, + pFoundRid); + } + __checkReturn + HRESULT getGenericParamsForMethodDef(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_GenericParam, + _COLDEF(GenericParam,Owner), + encodeToken(rid, mdtMethodDef, mdtTypeOrMethodDef, lengthof(mdtTypeOrMethodDef)), + pEnd, + pFoundRid); + } + __checkReturn + HRESULT getMethodSpecsForMethodDef(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_MethodSpec, + _COLDEF(MethodSpec,Method), + encodeToken(rid, mdtMethodDef, mdtMethodDefOrRef, lengthof(mdtMethodDefOrRef)), + pEnd, + pFoundRid); + } + __checkReturn + HRESULT getMethodSpecsForMemberRef(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_MethodSpec, + _COLDEF(MethodSpec,Method), + encodeToken(rid, mdtMemberRef, mdtMethodDefOrRef, lengthof(mdtMethodDefOrRef)), + pEnd, + pFoundRid); + } + __checkReturn + HRESULT getInterfaceImplsForTypeDef(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_InterfaceImpl, + _COLDEF(InterfaceImpl,Class), + rid, + pEnd, + pFoundRid); + } + + // FieldPtr + ULONG _GETRID(FieldPtr,Field); + + // FieldRec + USHORT _GETFLD(Field,Flags); // USHORT getFlagsOfField(FieldRec *pRec); + _GETSTR(Field,Name); // HRESULT getNameOfField(FieldRec *pRec, LPCUTF8 *pszString); + _GETSIGBLOB(Field,Signature); // HRESULT getSignatureOfField(FieldRec *pRec, PCCOR_SIGNATURE *ppbData, ULONG *pcbSize); + + // MethodPtr + ULONG _GETRID(MethodPtr,Method); + + // MethodRec + ULONG _GETFLD(Method,RVA); + USHORT _GETFLD(Method,ImplFlags); + USHORT _GETFLD(Method,Flags); + _GETSTR(Method,Name); // HRESULT getNameOfMethod(MethodRec *pRec, LPCUTF8 *pszString); + _GETSIGBLOB(Method,Signature); // HRESULT getSignatureOfMethod(MethodRec *pRec, PCCOR_SIGNATURE *ppbData, ULONG *pcbSize); + _GETLIST(Method,ParamList,Param); + + // ParamPtr + ULONG _GETRID(ParamPtr,Param); + + // ParamRec + USHORT _GETFLD(Param,Flags); + USHORT _GETFLD(Param,Sequence); + _GETSTR(Param,Name); + + // InterfaceImplRec + mdToken _GETTKN(InterfaceImpl,Class,mdtTypeDef); + mdToken _GETCDTKN(InterfaceImpl,Interface,mdtTypeDefOrRef); + + // MemberRefRec + mdToken _GETCDTKN(MemberRef,Class,mdtMemberRefParent); + _GETSTR(MemberRef,Name); + _GETSIGBLOB(MemberRef,Signature); // HRESULT getSignatureOfMemberRef(MemberRefRec *pRec, PCCOR_SIGNATURE *ppbData, ULONG *pcbSize); + + // ConstantRec + BYTE _GETFLD(Constant,Type); + mdToken _GETCDTKN(Constant,Parent,mdtHasConstant); + _GETBLOB(Constant,Value); + + // CustomAttributeRec + __checkReturn + HRESULT getCustomAttributeForToken(mdToken tk, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_CustomAttribute, + _COLDEF(CustomAttribute,Parent), + encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasCustomAttribute, lengthof(mdtHasCustomAttribute)), + pEnd, + pFoundRid); + } + + mdToken _GETCDTKN(CustomAttribute,Parent,mdtHasCustomAttribute); + mdToken _GETCDTKN(CustomAttribute,Type,mdtCustomAttributeType); + _GETBLOB(CustomAttribute,Value); + + // FieldMarshalRec + mdToken _GETCDTKN(FieldMarshal,Parent,mdtHasFieldMarshal); + _GETSIGBLOB(FieldMarshal,NativeType); + + // DeclSecurityRec + __checkReturn + HRESULT getDeclSecurityForToken(mdToken tk, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_DeclSecurity, + _COLDEF(DeclSecurity,Parent), + encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasDeclSecurity, lengthof(mdtHasDeclSecurity)), + pEnd, + pFoundRid); + } + + short _GETFLD(DeclSecurity,Action); + mdToken _GETCDTKN(DeclSecurity,Parent,mdtHasDeclSecurity); + _GETBLOB(DeclSecurity,PermissionSet); + + // ClassLayoutRec + USHORT _GETFLD(ClassLayout,PackingSize); + ULONG _GETFLD(ClassLayout,ClassSize); + ULONG _GETTKN(ClassLayout,Parent, mdtTypeDef); + + // FieldLayout + ULONG _GETFLD(FieldLayout,OffSet); + ULONG _GETTKN(FieldLayout, Field, mdtFieldDef); + + // Event map. + _GETLIST(EventMap,EventList,Event); + ULONG _GETRID(EventMap, Parent); + + // EventPtr + ULONG _GETRID(EventPtr, Event); + + // Event. + USHORT _GETFLD(Event,EventFlags); + _GETSTR(Event,Name); + mdToken _GETCDTKN(Event,EventType,mdtTypeDefOrRef); + + // Property map. + _GETLIST(PropertyMap,PropertyList,Property); + ULONG _GETRID(PropertyMap, Parent); + + // PropertyPtr + ULONG _GETRID(PropertyPtr, Property); + + // Property. + USHORT _GETFLD(Property,PropFlags); + _GETSTR(Property,Name); + _GETSIGBLOB(Property,Type); + + // MethodSemantics. + // Given an event or a property token, return the beginning/ending + // associates. + // + __checkReturn + HRESULT getAssociatesForToken(mdToken tk, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_MethodSemantics, + _COLDEF(MethodSemantics,Association), + encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasSemantic, lengthof(mdtHasSemantic)), + pEnd, + pFoundRid); + } + + USHORT _GETFLD(MethodSemantics,Semantic); + mdToken _GETTKN(MethodSemantics,Method,mdtMethodDef); + mdToken _GETCDTKN(MethodSemantics,Association,mdtHasSemantic); + + // MethodImpl + // Given a class token, return the beginning/ending MethodImpls. + // + __checkReturn + HRESULT getMethodImplsForClass(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_MethodImpl, + _COLDEF(MethodImpl, Class), + rid, + pEnd, + pFoundRid); + } + + mdToken _GETTKN(MethodImpl,Class,mdtTypeDef); + mdToken _GETCDTKN(MethodImpl,MethodBody, mdtMethodDefOrRef); + mdToken _GETCDTKN(MethodImpl, MethodDeclaration, mdtMethodDefOrRef); + + // StandAloneSigRec + _GETSIGBLOB(StandAloneSig,Signature); // HRESULT getSignatureOfStandAloneSig(StandAloneSigRec *pRec, PCCOR_SIGNATURE *ppbData, ULONG *pcbSize); + + // TypeSpecRec + // const BYTE* getSignatureOfTypeSpec(TypeSpecRec *pRec, ULONG *pcb); + _GETSIGBLOB(TypeSpec,Signature); + + // ModuleRef + _GETSTR(ModuleRef,Name); + + // ENCLog + ULONG _GETFLD(ENCLog, FuncCode); // ULONG getFuncCodeOfENCLog(ENCLogRec *pRec); + + // ImplMap + USHORT _GETFLD(ImplMap, MappingFlags); // USHORT getMappingFlagsOfImplMap(ImplMapRec *pRec); + mdToken _GETCDTKN(ImplMap, MemberForwarded, mdtMemberForwarded); // mdToken getMemberForwardedOfImplMap(ImplMapRec *pRec); + _GETSTR(ImplMap, ImportName); // HRESULT getImportNameOfImplMap(ImplMapRec *pRec, LPCUTF8 *pszString); + mdToken _GETTKN(ImplMap, ImportScope, mdtModuleRef); // mdToken getImportScopeOfImplMap(ImplMapRec *pRec); + + // FieldRVA + ULONG _GETFLD(FieldRVA, RVA); // ULONG getRVAOfFieldRVA(FieldRVARec *pRec); + mdToken _GETTKN(FieldRVA, Field, mdtFieldDef); // mdToken getFieldOfFieldRVA(FieldRVARec *pRec); + + // Assembly + ULONG _GETFLD(Assembly, HashAlgId); + USHORT _GETFLD(Assembly, MajorVersion); + USHORT _GETFLD(Assembly, MinorVersion); + USHORT _GETFLD(Assembly, BuildNumber); + USHORT _GETFLD(Assembly, RevisionNumber); + ULONG _GETFLD(Assembly, Flags); + _GETBLOB(Assembly, PublicKey); + _GETSTR(Assembly, Name); + _GETSTR(Assembly, Locale); + + // AssemblyRef + USHORT _GETFLD(AssemblyRef, MajorVersion); + USHORT _GETFLD(AssemblyRef, MinorVersion); + USHORT _GETFLD(AssemblyRef, BuildNumber); + USHORT _GETFLD(AssemblyRef, RevisionNumber); + ULONG _GETFLD(AssemblyRef, Flags); + _GETBLOB(AssemblyRef, PublicKeyOrToken); + _GETSTR(AssemblyRef, Name); + _GETSTR(AssemblyRef, Locale); + _GETBLOB(AssemblyRef, HashValue); + + // File + ULONG _GETFLD(File, Flags); + _GETSTR(File, Name); + _GETBLOB(File, HashValue); + + // ExportedType + ULONG _GETFLD(ExportedType, Flags); + ULONG _GETFLD(ExportedType, TypeDefId); + _GETSTR(ExportedType, TypeName); + _GETSTR(ExportedType, TypeNamespace); + mdToken _GETCDTKN(ExportedType, Implementation, mdtImplementation); + + // ManifestResource + ULONG _GETFLD(ManifestResource, Offset); + ULONG _GETFLD(ManifestResource, Flags); + _GETSTR(ManifestResource, Name); + mdToken _GETCDTKN(ManifestResource, Implementation, mdtImplementation); + + // NestedClass + mdToken _GETTKN(NestedClass, NestedClass, mdtTypeDef); + mdToken _GETTKN(NestedClass, EnclosingClass, mdtTypeDef); + + int GetSizeOfMethodNameColumn() + { + return _COLDEF(Method,Name).m_cbColumn; + } + + // GenericParRec + USHORT _GETFLD(GenericParam,Number); + USHORT _GETFLD(GenericParam,Flags); + mdToken _GETCDTKN(GenericParam,Owner,mdtTypeOrMethodDef); + _GETSTR(GenericParam,Name); + + __checkReturn + HRESULT getGenericParamConstraintsForGenericParam(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_GenericParamConstraint, + _COLDEF(GenericParamConstraint,Owner), + rid, + pEnd, + pFoundRid); + } + + // MethodSpecRec + mdToken _GETCDTKN(MethodSpec,Method,mdtMethodDefOrRef); + _GETSIGBLOB(MethodSpec,Instantiation); + + //GenericParamConstraintRec + mdToken _GETTKN(GenericParamConstraint,Owner,mdtGenericParam); + mdToken _GETCDTKN(GenericParamConstraint,Constraint,mdtTypeDefOrRef); + + BOOL SupportsGenerics() + { + // Only 2.0 of the metadata (and 1.1) support generics + return (m_Schema.m_major >= METAMODEL_MAJOR_VER_V2_0 || + (m_Schema.m_major == METAMODEL_MAJOR_VER_B1 && m_Schema.m_minor == METAMODEL_MINOR_VER_B1)); + }// SupportGenerics + + protected: + //***************************************************************************** + // Helper: determine if a token is valid or not + //***************************************************************************** + BOOL _IsValidTokenBase( + mdToken tk) + { + BOOL bRet = FALSE; + RID rid = RidFromToken(tk); + + if (rid != 0) + { + switch (TypeFromToken(tk)) + { + case mdtModule: + // can have only one module record + bRet = (rid <= getCountModules()); + break; + case mdtTypeRef: + bRet = (rid <= getCountTypeRefs()); + break; + case mdtTypeDef: + bRet = (rid <= getCountTypeDefs()); + break; + case mdtFieldDef: + bRet = (rid <= getCountFields()); + break; + case mdtMethodDef: + bRet = (rid <= getCountMethods()); + break; + case mdtParamDef: + bRet = (rid <= getCountParams()); + break; + case mdtInterfaceImpl: + bRet = (rid <= getCountInterfaceImpls()); + break; + case mdtMemberRef: + bRet = (rid <= getCountMemberRefs()); + break; + case mdtCustomAttribute: + bRet = (rid <= getCountCustomAttributes()); + break; + case mdtPermission: + bRet = (rid <= getCountDeclSecuritys()); + break; + case mdtSignature: + bRet = (rid <= getCountStandAloneSigs()); + break; + case mdtEvent: + bRet = (rid <= getCountEvents()); + break; + case mdtProperty: + bRet = (rid <= getCountPropertys()); + break; + case mdtModuleRef: + bRet = (rid <= getCountModuleRefs()); + break; + case mdtTypeSpec: + bRet = (rid <= getCountTypeSpecs()); + break; + case mdtAssembly: + bRet = (rid <= getCountAssemblys()); + break; + case mdtAssemblyRef: + bRet = (rid <= getCountAssemblyRefs()); + break; + case mdtFile: + bRet = (rid <= getCountFiles()); + break; + case mdtExportedType: + bRet = (rid <= getCountExportedTypes()); + break; + case mdtManifestResource: + bRet = (rid <= getCountManifestResources()); + break; + case mdtGenericParam: + bRet = (rid <= getCountGenericParams()); + break; + case mdtGenericParamConstraint: + bRet = (rid <= getCountGenericParamConstraints()); + break; + case mdtMethodSpec: + bRet = (rid <= getCountMethodSpecs()); + break; + default: + _ASSERTE(!bRet); + Debug_ReportError("Unknown token kind!"); + } + } + return bRet; + } // _IsValidToken + +#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN + bool IsSafeToDelete() + { + return m_isSafeToDelete; + } + + FORCEINLINE void MarkUnsafeToDelete() { m_isSafeToDelete = false; } + + bool m_isSafeToDelete; // This starts out true, but gets set to FALSE if we detect + // a MiniMd API call that might have given out an internal pointer. +#endif + +}; //class CMiniMdTemplate<Impl> + + + +#undef SETP +#undef _GETCDTKN +#undef _GETTKN +#undef _GETRID +#undef _GETBLOB +#undef _GETGUID +#undef _GETSTR +#undef SCHEMA + +#endif // _METAMODEL_H_ +// eof ------------------------------------------------------------------------ diff --git a/src/md/inc/metamodelro.h b/src/md/inc/metamodelro.h new file mode 100644 index 0000000000..00d4ead5f9 --- /dev/null +++ b/src/md/inc/metamodelro.h @@ -0,0 +1,240 @@ +// 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. +//***************************************************************************** +// MetaModelRO.h -- header file for Read-Only compressed COM+ metadata. +// + +// +// Used by the EE. +// +//***************************************************************************** +#ifndef _METAMODELRO_H_ +#define _METAMODELRO_H_ + +#if _MSC_VER >= 1100 + # pragma once +#endif + +#include "metamodel.h" + +#include "../heaps/export.h" +#include "../tables/export.h" + +//***************************************************************************** +// A read-only MiniMd. This is the fastest and smallest possible MiniMd, +// and as such, is the preferred EE metadata provider. +//***************************************************************************** + +template <class MiniMd> class CLiteWeightStgdb; +class CMiniMdRW; +class MDInternalRO; +class CMiniMd : public CMiniMdTemplate<CMiniMd> +{ +public: + friend class CLiteWeightStgdb<CMiniMd>; + friend class CMiniMdTemplate<CMiniMd>; + friend class CMiniMdRW; + friend class MDInternalRO; + + __checkReturn + HRESULT InitOnMem(void *pBuf, ULONG ulBufLen); + __checkReturn + HRESULT PostInit(int iLevel); // higher number : more checking + + // Returns TRUE if token (tk) is valid. + // For user strings, consideres 0 as valid token. + BOOL _IsValidToken( + mdToken tk) // [IN] token to be checked + { + if (TypeFromToken(tk) == mdtString) + { + return m_UserStringHeap.IsValidIndex(RidFromToken(tk)); + } + // Base type doesn't know about user string blob (yet) + return _IsValidTokenBase(tk); + } // CMiniMdRO::_IsValidToken + + __checkReturn + FORCEINLINE HRESULT GetUserString(ULONG nIndex, MetaData::DataBlob *pData) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return m_UserStringHeap.GetBlob(nIndex, pData); + } + +#ifdef FEATURE_PREJIT + void DisableHotDataUsage() + { + MetaData::HotHeap emptyHotHeap; + // Initialize hot data again with empty heap to disable their usage + m_StringHeap.InitializeHotData(emptyHotHeap); + m_BlobHeap.InitializeHotData(emptyHotHeap); + m_UserStringHeap.InitializeHotData(emptyHotHeap); + m_GuidHeap.InitializeHotData(emptyHotHeap); + // Disable usage of hot table data (throw it away) + m_pHotTablesDirectory = NULL; + } +#endif //FEATURE_PREJIT + +protected: + // Table info. + MetaData::TableRO m_Tables[TBL_COUNT]; +#ifdef FEATURE_PREJIT + struct MetaData::HotTablesDirectory * m_pHotTablesDirectory; +#endif //FEATURE_PREJIT + + __checkReturn + HRESULT InitializeTables(MetaData::DataBlob tablesData); + + __checkReturn + virtual HRESULT vSearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid); + __checkReturn + virtual HRESULT vSearchTableNotGreater(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid); + + // Heaps + MetaData::StringHeapRO m_StringHeap; + MetaData::BlobHeapRO m_BlobHeap; + MetaData::BlobHeapRO m_UserStringHeap; + MetaData::GuidHeapRO m_GuidHeap; + +protected: + + //************************************************************************* + // Overridables -- must be provided in derived classes. + __checkReturn + FORCEINLINE HRESULT Impl_GetString(UINT32 nIndex, __out LPCSTR *pszString) + { return m_StringHeap.GetString(nIndex, pszString); } + __checkReturn + HRESULT Impl_GetStringW(ULONG ix, __inout_ecount (cchBuffer) LPWSTR szOut, ULONG cchBuffer, ULONG *pcchBuffer); + __checkReturn + FORCEINLINE HRESULT Impl_GetGuid(UINT32 nIndex, GUID *pTargetGuid) + { + HRESULT hr; + GUID UNALIGNED *pSourceGuid; + IfFailRet(m_GuidHeap.GetGuid( + nIndex, + &pSourceGuid)); + // Add void* casts so that the compiler can't make assumptions about alignment. + CopyMemory((void *)pTargetGuid, (void *)pSourceGuid, sizeof(GUID)); + SwapGuid(pTargetGuid); + return S_OK; + } + __checkReturn + FORCEINLINE HRESULT Impl_GetBlob(UINT32 nIndex, __out MetaData::DataBlob *pData) + { return m_BlobHeap.GetBlob(nIndex, pData); } + + __checkReturn + FORCEINLINE HRESULT Impl_GetRow( + UINT32 nTableIndex, + UINT32 nRowIndex, + __deref_out_opt BYTE **ppRecord) + { + _ASSERTE(nTableIndex < TBL_COUNT); + return m_Tables[nTableIndex].GetRecord( + nRowIndex, + ppRecord, + m_TableDefs[nTableIndex].m_cbRec, + m_Schema.m_cRecs[nTableIndex], +#ifdef FEATURE_PREJIT + m_pHotTablesDirectory, +#endif //FEATURE_PREJIT + nTableIndex); + } + + // Count of rows in tbl2, pointed to by the column in tbl. + __checkReturn + HRESULT Impl_GetEndRidForColumn( + UINT32 nTableIndex, + RID nRowIndex, + CMiniColDef &def, // Column containing the RID into other table. + UINT32 nTargetTableIndex, // The other table. + RID *pEndRid); + + __checkReturn + FORCEINLINE HRESULT Impl_SearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ixCol, ULONG ulTarget, RID *pFoundRid) + { + return vSearchTable(ixTbl, sColumn, ulTarget, pFoundRid); + } + + // given a rid to the Property table, find an entry in PropertyMap table that contains the back pointer + // to its typedef parent + __checkReturn + HRESULT FindPropertyMapParentOfProperty(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_PropertyMap, _COLDEF(PropertyMap,PropertyList), rid, pFoundRid); + } + + __checkReturn + HRESULT FindParentOfPropertyHelper( + mdProperty pr, + mdTypeDef *ptd) + { + HRESULT hr = NOERROR; + + RID ridPropertyMap; + PropertyMapRec *pRec; + + IfFailRet(FindPropertyMapParentOfProperty(RidFromToken(pr), &ridPropertyMap)); + IfFailRet(GetPropertyMapRecord(ridPropertyMap, &pRec)); + *ptd = getParentOfPropertyMap( pRec ); + + RidToToken(*ptd, mdtTypeDef); + + return hr; + } // HRESULT CMiniMdRW::FindParentOfPropertyHelper() + + // given a rid to the Event table, find an entry in EventMap table that contains the back pointer + // to its typedef parent + __checkReturn + HRESULT FindEventMapParentOfEvent(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_EventMap, _COLDEF(EventMap, EventList), rid, pFoundRid); + } + + __checkReturn + HRESULT FindParentOfEventHelper( + mdEvent pr, + mdTypeDef *ptd) + { + HRESULT hr = NOERROR; + + RID ridEventMap; + EventMapRec *pRec; + + IfFailRet(FindEventMapParentOfEvent(RidFromToken(pr), &ridEventMap)); + IfFailRet(GetEventMapRecord(ridEventMap, &pRec)); + *ptd = getParentOfEventMap( pRec ); + + RidToToken(*ptd, mdtTypeDef); + + return hr; + } // HRESULT CMiniMdRW::FindParentOfEventHelper() + + FORCEINLINE int Impl_IsRo() + { return 1; } + //************************************************************************* + + __checkReturn + HRESULT CommonEnumCustomAttributeByName( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + bool fStopAtFirstFind, // [IN] just find the first one + HENUMInternal* phEnum); // enumerator to fill up + + __checkReturn + HRESULT CommonGetCustomAttributeByNameEx( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + mdCustomAttribute *ptkCA, // [OUT] put custom attribute token here + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData); // [OUT] Put size of data here. + + public: + virtual BOOL IsWritable() + { + return FALSE; + } + +}; // class CMiniMd + +#endif // _METAMODELRO_H_ diff --git a/src/md/inc/metamodelrw.h b/src/md/inc/metamodelrw.h new file mode 100644 index 0000000000..6e00d3cf3e --- /dev/null +++ b/src/md/inc/metamodelrw.h @@ -0,0 +1,1479 @@ +// 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. + +//***************************************************************************** +// MetaModelRW.h -- header file for Read/Write compressed COM+ metadata. +// + +// +// Used by Emitters and by E&C. +// +//***************************************************************************** +#ifndef _METAMODELRW_H_ +#define _METAMODELRW_H_ + +#if _MSC_VER >= 1100 + # pragma once +#endif + +#include "metamodel.h" // Base classes for the MetaModel. +#include "metadatahash.h" +#include "rwutil.h" +#include "shash.h" + +#include "../heaps/export.h" +#include "../hotdata/export.h" +#include "../tables/export.h" + +struct HENUMInternal; +#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE +struct IMDCustomDataSource; +#endif + +// ENUM for marking bit +enum +{ + InvalidMarkedBit = 0x00000000, + ModuleMarkedBit = 0x00000001, + TypeRefMarkedBit = 0x00000002, + TypeDefMarkedBit = 0x00000004, + FieldMarkedBit = 0x00000008, + MethodMarkedBit = 0x00000010, + ParamMarkedBit = 0x00000020, + MemberRefMarkedBit = 0x00000040, + CustomAttributeMarkedBit = 0x00000080, + DeclSecurityMarkedBit = 0x00000100, + SignatureMarkedBit = 0x00000200, + EventMarkedBit = 0x00000400, + PropertyMarkedBit = 0x00000800, + MethodImplMarkedBit = 0x00001000, + ModuleRefMarkedBit = 0x00002000, + TypeSpecMarkedBit = 0x00004000, + InterfaceImplMarkedBit = 0x00008000, + AssemblyRefMarkedBit = 0x00010000, + MethodSpecMarkedBit = 0x00020000, + +}; + +// entry for marking UserString +struct FilterUserStringEntry +{ + DWORD m_tkString; + bool m_fMarked; +}; + +class FilterTable : public CDynArray<DWORD> +{ +public: + FilterTable() { m_daUserStringMarker = NULL; } + ~FilterTable(); + + __checkReturn FORCEINLINE HRESULT MarkTypeRef(mdToken tk) { return MarkToken(tk, TypeRefMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkTypeDef(mdToken tk) { return MarkToken(tk, TypeDefMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkField(mdToken tk) { return MarkToken(tk, FieldMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkMethod(mdToken tk) { return MarkToken(tk, MethodMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkParam(mdToken tk) { return MarkToken(tk, ParamMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkMemberRef(mdToken tk) { return MarkToken(tk, MemberRefMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkCustomAttribute(mdToken tk) { return MarkToken(tk, CustomAttributeMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkDeclSecurity(mdToken tk) { return MarkToken(tk, DeclSecurityMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkSignature(mdToken tk) { return MarkToken(tk, SignatureMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkEvent(mdToken tk) { return MarkToken(tk, EventMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkProperty(mdToken tk) { return MarkToken(tk, PropertyMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkMethodImpl(RID rid) + { + return MarkToken(TokenFromRid(rid, TBL_MethodImpl << 24), MethodImplMarkedBit); + } + __checkReturn FORCEINLINE HRESULT MarkModuleRef(mdToken tk) { return MarkToken(tk, ModuleRefMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkTypeSpec(mdToken tk) { return MarkToken(tk, TypeSpecMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkInterfaceImpl(mdToken tk) { return MarkToken(tk, InterfaceImplMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkAssemblyRef(mdToken tk) { return MarkToken(tk, AssemblyRefMarkedBit); } + __checkReturn FORCEINLINE HRESULT MarkMethodSpec(mdToken tk) { return MarkToken(tk, MethodSpecMarkedBit); } + + // It may look inconsistent but it is because taht UserString an offset to the heap. + // We don't want to grow the FilterTable to the size of the UserString heap. + // So we use the heap's marking system instead... + // + __checkReturn HRESULT MarkUserString(mdString str); + + __checkReturn HRESULT MarkNewUserString(mdString str); + + FORCEINLINE bool IsTypeRefMarked(mdToken tk) { return IsTokenMarked(tk, TypeRefMarkedBit); } + FORCEINLINE bool IsTypeDefMarked(mdToken tk) { return IsTokenMarked(tk, TypeDefMarkedBit); } + FORCEINLINE bool IsFieldMarked(mdToken tk) { return IsTokenMarked(tk, FieldMarkedBit); } + FORCEINLINE bool IsMethodMarked(mdToken tk) { return IsTokenMarked(tk, MethodMarkedBit); } + FORCEINLINE bool IsParamMarked(mdToken tk) { return IsTokenMarked(tk, ParamMarkedBit); } + FORCEINLINE bool IsMemberRefMarked(mdToken tk) { return IsTokenMarked(tk, MemberRefMarkedBit); } + FORCEINLINE bool IsCustomAttributeMarked(mdToken tk) { return IsTokenMarked(tk, CustomAttributeMarkedBit); } + FORCEINLINE bool IsDeclSecurityMarked(mdToken tk) { return IsTokenMarked(tk, DeclSecurityMarkedBit); } + FORCEINLINE bool IsSignatureMarked(mdToken tk) { return IsTokenMarked(tk, SignatureMarkedBit); } + FORCEINLINE bool IsEventMarked(mdToken tk) { return IsTokenMarked(tk, EventMarkedBit); } + FORCEINLINE bool IsPropertyMarked(mdToken tk) { return IsTokenMarked(tk, PropertyMarkedBit); } + FORCEINLINE bool IsMethodImplMarked(RID rid) + { + return IsTokenMarked(TokenFromRid(rid, TBL_MethodImpl << 24), MethodImplMarkedBit); + } + FORCEINLINE bool IsModuleRefMarked(mdToken tk) { return IsTokenMarked(tk, ModuleRefMarkedBit); } + FORCEINLINE bool IsTypeSpecMarked(mdToken tk) { return IsTokenMarked(tk, TypeSpecMarkedBit); } + FORCEINLINE bool IsInterfaceImplMarked(mdToken tk){ return IsTokenMarked(tk, InterfaceImplMarkedBit); } + FORCEINLINE bool IsAssemblyRefMarked(mdToken tk){ return IsTokenMarked(tk, AssemblyRefMarkedBit); } + FORCEINLINE bool IsMethodSpecMarked(mdToken tk){ return IsTokenMarked(tk, MethodSpecMarkedBit); } + + bool IsUserStringMarked(mdString str); + + __checkReturn HRESULT UnmarkAll(CMiniMdRW *pMiniMd, ULONG ulSize); + __checkReturn HRESULT MarkAll(CMiniMdRW *pMiniMd, ULONG ulSize); + bool IsTokenMarked(mdToken); + + __checkReturn FORCEINLINE HRESULT UnmarkTypeDef(mdToken tk) { return UnmarkToken(tk, TypeDefMarkedBit); } + __checkReturn FORCEINLINE HRESULT UnmarkField(mdToken tk) { return UnmarkToken(tk, FieldMarkedBit); } + __checkReturn FORCEINLINE HRESULT UnmarkMethod(mdToken tk) { return UnmarkToken(tk, MethodMarkedBit); } + __checkReturn FORCEINLINE HRESULT UnmarkCustomAttribute(mdToken tk) { return UnmarkToken(tk, CustomAttributeMarkedBit); } + +private: + CDynArray<FilterUserStringEntry> *m_daUserStringMarker; + bool IsTokenMarked(mdToken tk, DWORD bitMarked); + __checkReturn HRESULT MarkToken(mdToken tk, DWORD bit); + __checkReturn HRESULT UnmarkToken(mdToken tk, DWORD bit); +}; // class FilterTable : public CDynArray<DWORD> + +class CMiniMdRW; + +//***************************************************************************** +// This class is used to keep a list of RID. This list of RID can be sorted +// base on the m_ixCol's value of the m_ixTbl table. +//***************************************************************************** +class VirtualSort +{ +public: + void Init(ULONG ixTbl, ULONG ixCol, CMiniMdRW *pMiniMd); + void Uninit(); + TOKENMAP *m_pMap; // RID for m_ixTbl table. Sorted by on the ixCol + bool m_isMapValid; + ULONG m_ixTbl; // Table this is a sorter for. + ULONG m_ixCol; // Key column in the table. + CMiniMdRW *m_pMiniMd; // The MiniMd with the data. + __checkReturn + HRESULT Sort(); +private: + mdToken m_tkBuf; + __checkReturn + HRESULT SortRange(int iLeft, int iRight); +public: + __checkReturn + HRESULT Compare( + RID iLeft, // First item to compare. + RID iRight, // Second item to compare. + int *pnResult); // -1, 0, or 1 + +private: + FORCEINLINE void Swap( + RID iFirst, + RID iSecond) + { + if ( iFirst == iSecond ) return; + m_tkBuf = *(m_pMap->Get(iFirst)); + *(m_pMap->Get(iFirst)) = *(m_pMap->Get(iSecond)); + *(m_pMap->Get(iSecond)) = m_tkBuf; + } + + +}; // class VirtualSort + +class ReorderData +{ +public: + typedef enum + { + MinReorderBucketType=0, // bucket# shouldn't be less than this value + Undefined=0, // use this for initialization + Duplicate=1, // duplicate string + ProfileData=2, // bucket# for IBC data + PublicData=3, // bucket# for public data + OtherData=4, // bucket# for other data + NonPublicData=5, // bucket# for non-public data + MaxReorderBucketType=255 // bucket# shouldn't exceeed this value + } ReorderBucketType; +}; + +typedef CMetaDataHashBase CMemberRefHash; +typedef CMetaDataHashBase CLookUpHash; + +class MDTOKENMAP; +class MDInternalRW; +class CorProfileData; +class UTSemReadWrite; + +enum MetaDataReorderingOptions { + NoReordering=0x0, + ReArrangeStringPool=0x1 +}; + +#ifdef FEATURE_PREJIT + +// {0702E333-8D64-4ca7-B564-4AA56B1FCEA3} +EXTERN_GUID(IID_IMetaDataCorProfileData, 0x702e333, 0x8d64, 0x4ca7, 0xb5, 0x64, 0x4a, 0xa5, 0x6b, 0x1f, 0xce, 0xa3 ); + +#undef INTERFACE +#define INTERFACE IMetaDataCorProfileData +DECLARE_INTERFACE_(IMetaDataCorProfileData, IUnknown) +{ + STDMETHOD(SetCorProfileData)( + CorProfileData *pProfileData) PURE; // [IN] Pointer to profile data +}; + +// {2B464817-C0F6-454e-99E7-C352D8384D7B} +EXTERN_GUID(IID_IMDInternalMetadataReorderingOptions, 0x2B464817, 0xC0F6, 0x454e, 0x99, 0xE7, 0xC3, 0x52, 0xD8, 0x38, 0x4D, 0x7B ); + +#undef INTERFACE +#define INTERFACE IMDInternalMetadataReorderingOptions +DECLARE_INTERFACE_(IMDInternalMetadataReorderingOptions, IUnknown) +{ + STDMETHOD(SetMetaDataReorderingOptions)( + MetaDataReorderingOptions options) PURE; // [IN] metadata reordering options +}; + +#endif //FEATURE_PREJIT + +template <class MiniMd> class CLiteWeightStgdb; +//***************************************************************************** +// Read/Write MiniMd. +//***************************************************************************** +class CMiniMdRW : public CMiniMdTemplate<CMiniMdRW> +{ +public: + friend class CLiteWeightStgdb<CMiniMdRW>; + friend class CLiteWeightStgdbRW; + friend class CMiniMdTemplate<CMiniMdRW>; + friend class CQuickSortMiniMdRW; + friend class VirtualSort; + friend class MDInternalRW; + friend class RegMeta; + friend class FilterTable; + friend class ImportHelper; + friend class VerifyLayoutsMD; + + CMiniMdRW(); + ~CMiniMdRW(); + + __checkReturn + HRESULT InitNew(); + __checkReturn + HRESULT InitOnMem(const void *pBuf, ULONG ulBufLen, int bReadOnly); + __checkReturn + HRESULT PostInit(int iLevel); + __checkReturn + HRESULT InitPoolOnMem(int iPool, void *pbData, ULONG cbData, int bReadOnly); + __checkReturn + HRESULT InitOnRO(CMiniMd *pMd, int bReadOnly); +#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE + __checkReturn + HRESULT InitOnCustomDataSource(IMDCustomDataSource* pDataSouce); +#endif + __checkReturn + HRESULT ConvertToRW(); + + __checkReturn + HRESULT GetSaveSize( + CorSaveSize fSave, + UINT32 *pcbSize, + DWORD *pbCompressed, + MetaDataReorderingOptions reorderingOptions = NoReordering, + CorProfileData *pProfileData = NULL); + int IsPoolEmpty(int iPool); + __checkReturn + HRESULT GetPoolSaveSize(int iPool, UINT32 *pcbSize); + + __checkReturn + HRESULT SaveTablesToStream(IStream *pIStream, MetaDataReorderingOptions reorderingOptions, CorProfileData *pProfileData); + __checkReturn + HRESULT SavePoolToStream(int iPool, IStream *pIStream); + __checkReturn + HRESULT SaveDone(); + + __checkReturn + HRESULT SetHandler(IUnknown *pIUnk); + + __checkReturn + HRESULT SetOption(OptionValue *pOptionValue); + __checkReturn + HRESULT GetOption(OptionValue *pOptionValue); + + static ULONG GetTableForToken(mdToken tkn); + static mdToken GetTokenForTable(ULONG ixTbl); + + FORCEINLINE static ULONG TblFromRecId(ULONG ul) { return (ul >> 24)&0x7f; } + FORCEINLINE static ULONG RidFromRecId(ULONG ul) { return ul & 0xffffff; } + FORCEINLINE static ULONG RecIdFromRid(ULONG rid, ULONG ixTbl) { return rid | ((ixTbl|0x80) << 24); } + FORCEINLINE static int IsRecId(ULONG ul) { return (ul & 0x80000000) != 0;} + + // Place in every API function before doing any allocations. + __checkReturn + FORCEINLINE HRESULT PreUpdate() + { + if (m_eGrow == eg_grow) + { + return ExpandTables(); + } + return S_OK; + } + + __checkReturn + HRESULT AddRecord( + UINT32 nTableIndex, + void **ppRow, + RID *pRid); + + __checkReturn + FORCEINLINE HRESULT PutCol(ULONG ixTbl, ULONG ixCol, void *pRecord, ULONG uVal) + { _ASSERTE(ixTbl < TBL_COUNT); _ASSERTE(ixCol < m_TableDefs[ixTbl].m_cCols); + return PutCol(m_TableDefs[ixTbl].m_pColDefs[ixCol], pRecord, uVal); + } // HRESULT CMiniMdRW::PutCol() + __checkReturn + HRESULT PutString(ULONG ixTbl, ULONG ixCol, void *pRecord, LPCSTR szString); + __checkReturn + HRESULT PutStringW(ULONG ixTbl, ULONG ixCol, void *pRecord, LPCWSTR wszString); + __checkReturn + HRESULT PutGuid(ULONG ixTbl, ULONG ixCol, void *pRecord, REFGUID guid); + __checkReturn + HRESULT ChangeMvid(REFGUID newMvid); + __checkReturn + HRESULT PutToken(ULONG ixTbl, ULONG ixCol, void *pRecord, mdToken tk); + __checkReturn + HRESULT PutBlob(ULONG ixTbl, ULONG ixCol, void *pRecord, const void *pvData, ULONG cbData); + + __checkReturn + HRESULT PutUserString(MetaData::DataBlob data, UINT32 *pnIndex) + { return m_UserStringHeap.AddBlob(data, pnIndex); } + + ULONG GetCol(ULONG ixTbl, ULONG ixCol, void *pRecord); + mdToken GetToken(ULONG ixTbl, ULONG ixCol, void *pRecord); + + // Add a record to a table, and return a typed XXXRec *. +// #undef AddTblRecord + #define AddTblRecord(tbl) \ + __checkReturn HRESULT Add##tbl##Record(tbl##Rec **ppRow, RID *pnRowIndex) \ + { return AddRecord(TBL_##tbl, reinterpret_cast<void **>(ppRow), pnRowIndex); } + + AddTblRecord(Module) + AddTblRecord(TypeRef) + __checkReturn HRESULT AddTypeDefRecord( // Specialized implementation. + TypeDefRec **ppRow, + RID *pnRowIndex); + AddTblRecord(Field) + __checkReturn HRESULT AddMethodRecord( // Specialized implementation. + MethodRec **ppRow, + RID *pnRowIndex); + AddTblRecord(Param) + AddTblRecord(InterfaceImpl) + AddTblRecord(MemberRef) + AddTblRecord(Constant) + AddTblRecord(CustomAttribute) + AddTblRecord(FieldMarshal) + AddTblRecord(DeclSecurity) + AddTblRecord(ClassLayout) + AddTblRecord(FieldLayout) + AddTblRecord(StandAloneSig) + __checkReturn HRESULT AddEventMapRecord( // Specialized implementation. + EventMapRec **ppRow, + RID *pnRowIndex); + AddTblRecord(Event) + __checkReturn HRESULT AddPropertyMapRecord( // Specialized implementation. + PropertyMapRec **ppRow, + RID *pnRowIndex); + AddTblRecord(Property) + AddTblRecord(MethodSemantics) + AddTblRecord(MethodImpl) + AddTblRecord(ModuleRef) + AddTblRecord(FieldPtr) + AddTblRecord(MethodPtr) + AddTblRecord(ParamPtr) + AddTblRecord(PropertyPtr) + AddTblRecord(EventPtr) + + AddTblRecord(ENCLog) + AddTblRecord(TypeSpec) + AddTblRecord(ImplMap) + AddTblRecord(ENCMap) + AddTblRecord(FieldRVA) + + // Assembly Tables. + AddTblRecord(Assembly) + AddTblRecord(AssemblyProcessor) + AddTblRecord(AssemblyOS) + AddTblRecord(AssemblyRef) + AddTblRecord(AssemblyRefProcessor) + AddTblRecord(AssemblyRefOS) + AddTblRecord(File) + AddTblRecord(ExportedType) + AddTblRecord(ManifestResource) + + AddTblRecord(NestedClass) + AddTblRecord(GenericParam) + AddTblRecord(MethodSpec) + AddTblRecord(GenericParamConstraint) + + // Specialized AddXxxToYyy() functions. + __checkReturn HRESULT AddMethodToTypeDef(RID td, RID md); + __checkReturn HRESULT AddFieldToTypeDef(RID td, RID md); + __checkReturn HRESULT AddParamToMethod(RID md, RID pd); + __checkReturn HRESULT AddPropertyToPropertyMap(RID pmd, RID pd); + __checkReturn HRESULT AddEventToEventMap(ULONG emd, RID ed); + + // does the MiniMdRW has the indirect tables, such as FieldPtr, MethodPtr + FORCEINLINE int HasIndirectTable(ULONG ix) + { if (g_PtrTableIxs[ix].m_ixtbl < TBL_COUNT) return GetCountRecs(g_PtrTableIxs[ix].m_ixtbl); return 0;} + + FORCEINLINE int IsVsMapValid(ULONG ixTbl) + { _ASSERTE(ixTbl<TBL_COUNT); return (m_pVS[ixTbl] && m_pVS[ixTbl]->m_isMapValid); } + + // translate index returned by getMethodListOfTypeDef to a rid into Method table + __checkReturn + FORCEINLINE HRESULT GetMethodRid(ULONG index, ULONG *pRid) + { + HRESULT hr; + if (HasIndirectTable(TBL_Method)) + { + MethodPtrRec *pMethodPtrRecord; + IfFailGo(GetMethodPtrRecord(index, &pMethodPtrRecord)); + *pRid = getMethodOfMethodPtr(pMethodPtrRecord); + } + else + { + *pRid = index; + } + return S_OK; + ErrExit: + *pRid = 0; + return hr; + } + + // translate index returned by getFieldListOfTypeDef to a rid into Field table + __checkReturn + FORCEINLINE HRESULT GetFieldRid(ULONG index, ULONG *pRid) + { + HRESULT hr; + if (HasIndirectTable(TBL_Field)) + { + FieldPtrRec *pFieldPtrRecord; + IfFailGo(GetFieldPtrRecord(index, &pFieldPtrRecord)); + *pRid = getFieldOfFieldPtr(pFieldPtrRecord); + } + else + { + *pRid = index; + } + return S_OK; + ErrExit: + *pRid = 0; + return hr; + } + + // translate index returned by getParamListOfMethod to a rid into Param table + __checkReturn + FORCEINLINE HRESULT GetParamRid(ULONG index, ULONG *pRid) + { + HRESULT hr; + if (HasIndirectTable(TBL_Param)) + { + ParamPtrRec *pParamPtrRecord; + IfFailGo(GetParamPtrRecord(index, &pParamPtrRecord)); + *pRid = getParamOfParamPtr(pParamPtrRecord); + } + else + { + *pRid = index; + } + return S_OK; + ErrExit: + *pRid = 0; + return hr; + } + + // translate index returned by getEventListOfEventMap to a rid into Event table + __checkReturn + FORCEINLINE HRESULT GetEventRid(ULONG index, ULONG *pRid) + { + HRESULT hr; + if (HasIndirectTable(TBL_Event)) + { + EventPtrRec *pEventPtrRecord; + IfFailGo(GetEventPtrRecord(index, &pEventPtrRecord)); + *pRid = getEventOfEventPtr(pEventPtrRecord); + } + else + { + *pRid = index; + } + return S_OK; + ErrExit: + *pRid = 0; + return hr; + } + + // translate index returned by getPropertyListOfPropertyMap to a rid into Property table + __checkReturn + FORCEINLINE HRESULT GetPropertyRid(ULONG index, ULONG *pRid) + { + HRESULT hr; + if (HasIndirectTable(TBL_Property)) + { + PropertyPtrRec *pPropertyPtrRecord; + IfFailGo(GetPropertyPtrRecord(index, &pPropertyPtrRecord)); + *pRid = getPropertyOfPropertyPtr(pPropertyPtrRecord); + } + else + { + *pRid = index; + } + return S_OK; + ErrExit: + *pRid = 0; + return hr; + } + + // Convert a pseudo-RID from a Virtual Sort into a real RID. + FORCEINLINE ULONG GetRidFromVirtualSort(ULONG ixTbl, ULONG index) + { return IsVsMapValid(ixTbl) ? *(m_pVS[ixTbl]->m_pMap->Get(index)) : index; } + + // Index returned by GetInterfaceImplForTypeDef. It could be index to VirtualSort table + // or directly to InterfaceImpl + FORCEINLINE ULONG GetInterfaceImplRid(ULONG index) + { return GetRidFromVirtualSort(TBL_InterfaceImpl, index); } + + // Index returned by GetGenericParamForToken. It could be index to VirtualSort table + // or directly to GenericParam + FORCEINLINE ULONG GetGenericParamRid(ULONG index) + { return GetRidFromVirtualSort(TBL_GenericParam, index); } + + // Index returned by GetGenericParamConstraintForToken. It could be index to VirtualSort table + // or directly to GenericParamConstraint + FORCEINLINE ULONG GetGenericParamConstraintRid(ULONG index) + { return GetRidFromVirtualSort(TBL_GenericParamConstraint, index); } + + // Index returned by GetDeclSecurityForToken. It could be index to VirtualSort table + // or directly to DeclSecurity + FORCEINLINE ULONG GetDeclSecurityRid(ULONG index) + { return GetRidFromVirtualSort(TBL_DeclSecurity, index); } + + // Index returned by GetCustomAttributeForToken. It could be index to VirtualSort table + // or directly to CustomAttribute + FORCEINLINE ULONG GetCustomAttributeRid(ULONG index) + { return GetRidFromVirtualSort(TBL_CustomAttribute, index); } + + // add method, field, property, event, param to the map table + __checkReturn HRESULT AddMethodToLookUpTable(mdMethodDef md, mdTypeDef td); + __checkReturn HRESULT AddFieldToLookUpTable(mdFieldDef fd, mdTypeDef td); + __checkReturn HRESULT AddPropertyToLookUpTable(mdProperty pr, mdTypeDef td); + __checkReturn HRESULT AddEventToLookUpTable(mdEvent ev, mdTypeDef td); + __checkReturn HRESULT AddParamToLookUpTable(mdParamDef pd, mdMethodDef md); + + // look up the parent of method, field, property, event, or param + __checkReturn HRESULT FindParentOfMethodHelper(mdMethodDef md, mdTypeDef *ptd); + __checkReturn HRESULT FindParentOfFieldHelper(mdFieldDef fd, mdTypeDef *ptd); + __checkReturn HRESULT FindParentOfPropertyHelper(mdProperty pr, mdTypeDef *ptd); + __checkReturn HRESULT FindParentOfEventHelper(mdEvent ev, mdTypeDef *ptd); + __checkReturn HRESULT FindParentOfParamHelper(mdParamDef pd, mdMethodDef *pmd); + + bool IsMemberDefHashPresent() { return m_pMemberDefHash != NULL; } + + // Function to reorganize the string pool based on IBC profile data (if available) and static analysis. + // Throws on error. + VOID OrganizeStringPool(CorProfileData *pProfileData); + + // Result of hash search + enum HashSearchResult + { + Found, // Item was found. + NotFound, // Item not found. + NoTable // Table hasn't been built. + }; + + // Create MemberRef hash table. + __checkReturn + HRESULT CreateMemberRefHash(); + + // Add a new MemberRef to the hash table. + __checkReturn + HRESULT AddMemberRefToHash( // Return code. + mdMemberRef mr); // Token of new guy. + + // If the hash is built, search for the item. Ignore token *ptkMemberRef. + HashSearchResult FindMemberRefFromHash( + mdToken tkParent, // Parent token. + LPCUTF8 szName, // Name of item. + PCCOR_SIGNATURE pvSigBlob, // Signature. + ULONG cbSigBlob, // Size of signature. + mdMemberRef * ptkMemberRef); // IN: Ignored token. OUT: Return if found. + + //************************************************************************* + // Check a given mr token to see if this one is a match. + //************************************************************************* + __checkReturn + HRESULT CompareMemberRefs( // S_OK match, S_FALSE no match. + mdMemberRef mr, // Token to check. + mdToken tkPar, // Parent token. + LPCUTF8 szNameUtf8, // Name of item. + PCCOR_SIGNATURE pvSigBlob, // Signature. + ULONG cbSigBlob); // Size of signature. + + // Add a new MemberDef to the hash table. + __checkReturn + HRESULT AddMemberDefToHash( + mdToken tkMember, // Token of new guy. It can be MethodDef or FieldDef + mdToken tkParent); // Parent token. + + // Create MemberDef Hash + __checkReturn + HRESULT CreateMemberDefHash(); + + // If the hash is built, search for the item. Ignore token *ptkMember. + HashSearchResult FindMemberDefFromHash( + mdToken tkParent, // Parent token. + LPCUTF8 szName, // Name of item. + PCCOR_SIGNATURE pvSigBlob, // Signature. + ULONG cbSigBlob, // Size of signature. + mdToken * ptkMember); // IN: Ignored token. OUT: Return if found. It can be MethodDef or FieldDef + + //************************************************************************* + // Check a given Method/Field token to see if this one is a match. + //************************************************************************* + __checkReturn + HRESULT CompareMemberDefs( // S_OK match, S_FALSE no match. + mdToken tkMember, // Token to check. It can be MethodDef or FieldDef + mdToken tkParent, // Parent token recorded in the hash entry + mdToken tkPar, // Parent token. + LPCUTF8 szNameUtf8, // Name of item. + PCCOR_SIGNATURE pvSigBlob, // Signature. + ULONG cbSigBlob); // Size of signature. + + //************************************************************************* + // Add a new CustomAttributes to the hash table. + //************************************************************************* + __checkReturn + HRESULT AddCustomAttributesToHash( // Return code. + mdCustomAttribute cv) // Token of new guy. + { return GenericAddToHash(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, RidFromToken(cv)); } + + inline ULONG HashMemberRef(mdToken tkPar, LPCUTF8 szName) + { + ULONG l = HashBytes((const BYTE *) &tkPar, sizeof(mdToken)) + HashStringA(szName); + return (l); + } + + inline ULONG HashMemberDef(mdToken tkPar, LPCUTF8 szName) + { + return HashMemberRef(tkPar, szName); + } + + // helper to calculate the hash value given a token + inline ULONG HashCustomAttribute(mdToken tkObject) + { + return HashToken(tkObject); + } + + CMemberRefHash *m_pMemberRefHash; + + // Hash table for Methods and Fields + CMemberDefHash *m_pMemberDefHash; + + // helper to calculate the hash value given a pair of tokens + inline ULONG HashToken(mdToken tkObject) + { + ULONG l = HashBytes((const BYTE *) &tkObject, sizeof(mdToken)); + return (l); + } + + + //************************************************************************* + // Add a new FieldMarhsal Rid to the hash table. + //************************************************************************* + __checkReturn + HRESULT AddFieldMarshalToHash( // Return code. + RID rid) // Token of new guy. + { return GenericAddToHash(TBL_FieldMarshal, FieldMarshalRec::COL_Parent, rid); } + + //************************************************************************* + // Add a new Constant Rid to the hash table. + //************************************************************************* + __checkReturn + HRESULT AddConstantToHash( // Return code. + RID rid) // Token of new guy. + { return GenericAddToHash(TBL_Constant, ConstantRec::COL_Parent, rid); } + + //************************************************************************* + // Add a new MethodSemantics Rid to the hash table. + //************************************************************************* + __checkReturn + HRESULT AddMethodSemanticsToHash( // Return code. + RID rid) // Token of new guy. + { return GenericAddToHash(TBL_MethodSemantics, MethodSemanticsRec::COL_Association, rid); } + + //************************************************************************* + // Add a new ClassLayout Rid to the hash table. + //************************************************************************* + __checkReturn + HRESULT AddClassLayoutToHash( // Return code. + RID rid) // Token of new guy. + { return GenericAddToHash(TBL_ClassLayout, ClassLayoutRec::COL_Parent, rid); } + + //************************************************************************* + // Add a new FieldLayout Rid to the hash table. + //************************************************************************* + __checkReturn + HRESULT AddFieldLayoutToHash( // Return code. + RID rid) // Token of new guy. + { return GenericAddToHash(TBL_FieldLayout, FieldLayoutRec::COL_Field, rid); } + + //************************************************************************* + // Add a new ImplMap Rid to the hash table. + //************************************************************************* + __checkReturn + HRESULT AddImplMapToHash( // Return code. + RID rid) // Token of new guy. + { return GenericAddToHash(TBL_ImplMap, ImplMapRec::COL_MemberForwarded, rid); } + + //************************************************************************* + // Add a new FieldRVA Rid to the hash table. + //************************************************************************* + __checkReturn + HRESULT AddFieldRVAToHash( // Return code. + RID rid) // Token of new guy. + { return GenericAddToHash(TBL_FieldRVA, FieldRVARec::COL_Field, rid); } + + //************************************************************************* + // Add a new nested class Rid to the hash table. + //************************************************************************* + __checkReturn + HRESULT AddNestedClassToHash( // Return code. + RID rid) // Token of new guy. + { return GenericAddToHash(TBL_NestedClass, NestedClassRec::COL_NestedClass, rid); } + + //************************************************************************* + // Add a new MethodImpl Rid to the hash table. + //************************************************************************* + __checkReturn + HRESULT AddMethodImplToHash( // Return code. + RID rid) // Token of new guy. + { return GenericAddToHash(TBL_MethodImpl, MethodImplRec::COL_Class, rid); } + + + //************************************************************************* + // Build a hash table for the specified table if the size exceed the thresholds. + //************************************************************************* + __checkReturn + HRESULT GenericBuildHashTable( // Return code. + ULONG ixTbl, // Table with hash + ULONG ixCol); // col that we hash. + + //************************************************************************* + // Add a rid from a table into a hash + //************************************************************************* + __checkReturn + HRESULT GenericAddToHash( // Return code. + ULONG ixTbl, // Table with hash + ULONG ixCol, // col that we hash. + RID rid); // new row of the table. + + //************************************************************************* + // Add a rid from a table into a hash + //************************************************************************* + __checkReturn + HRESULT GenericFindWithHash( // Return code. + ULONG ixTbl, // Table with hash + ULONG ixCol, // col that we hash. + mdToken tkTarget, // token to be find in the hash + RID *pFoundRid); + + + // look up hash table for tokenless tables. + // They are constant, FieldMarshal, MethodSemantics, ClassLayout, FieldLayout, ImplMap, FieldRVA, NestedClass, and MethodImpl + CLookUpHash * m_pLookUpHashs[TBL_COUNT]; + +#if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE) + MapSHash<UINT32, UINT32> m_StringPoolOffsetHash; +#endif + + //************************************************************************* + // Hash for named items. + //************************************************************************* + __checkReturn + HRESULT AddNamedItemToHash( // Return code. + ULONG ixTbl, // Table with the new item. + mdToken tk, // Token of new guy. + LPCUTF8 szName, // Name of item. + mdToken tkParent); // Token of parent, if any. + + HashSearchResult FindNamedItemFromHash( + ULONG ixTbl, // Table with the item. + LPCUTF8 szName, // Name of item. + mdToken tkParent, // Token of parent, if any. + mdToken * ptk); // Return if found. + + __checkReturn + HRESULT CompareNamedItems( // S_OK match, S_FALSE no match. + ULONG ixTbl, // Table with the item. + mdToken tk, // Token to check. + LPCUTF8 szName, // Name of item. + mdToken tkParent); // Token of parent, if any. + + FORCEINLINE ULONG HashNamedItem(mdToken tkPar, LPCUTF8 szName) + { return HashBytes((const BYTE *) &tkPar, sizeof(mdToken)) + HashStringA(szName); } + + CMetaDataHashBase *m_pNamedItemHash; + + //***************************************************************************** + // IMetaModelCommon - RW specific versions for some of the functions. + //***************************************************************************** + __checkReturn + virtual HRESULT CommonGetEnclosingClassOfTypeDef( + mdTypeDef td, + mdTypeDef *ptkEnclosingTypeDef) + { + _ASSERTE(ptkEnclosingTypeDef != NULL); + + HRESULT hr; + NestedClassRec *pRec; + RID iRec; + + IfFailRet(FindNestedClassHelper(td, &iRec)); + if (iRec == 0) + { + *ptkEnclosingTypeDef = mdTypeDefNil; + return S_OK; + } + + IfFailRet(GetNestedClassRecord(iRec, &pRec)); + *ptkEnclosingTypeDef = getEnclosingClassOfNestedClass(pRec); + return S_OK; + } + + __checkReturn + HRESULT CommonEnumCustomAttributeByName( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + bool fStopAtFirstFind, // [IN] just find the first one + HENUMInternal* phEnum); // enumerator to fill up + + __checkReturn + HRESULT CommonGetCustomAttributeByNameEx( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + mdCustomAttribute *ptkCA, // [OUT] put custom attribute token here + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData); // [OUT] Put size of data here. + + //***************************************************************************** + // Find helper for a constant. + //***************************************************************************** + __checkReturn + HRESULT FindConstantHelper( // return index to the constant table + mdToken tkParent, // Parent token. Can be ParamDef, FieldDef, or Property. + RID *pFoundRid); + + //***************************************************************************** + // Find helper for a FieldMarshal. + //***************************************************************************** + __checkReturn + HRESULT FindFieldMarshalHelper( // return index to the field marshal table + mdToken tkParent, // Parent token. Can be a FieldDef or ParamDef. + RID *pFoundRid); + + //***************************************************************************** + // Find helper for a method semantics. + //***************************************************************************** + __checkReturn + HRESULT FindMethodSemanticsHelper( // return HRESULT + mdToken tkAssociate, // Event or property token + HENUMInternal *phEnum); // fill in the enum + + //***************************************************************************** + // Find helper for a method semantics given a associate and semantics. + // This will look up methodsemantics based on its status! + // Return CLDB_E_RECORD_NOTFOUND if cannot find the matching one + //***************************************************************************** + __checkReturn + HRESULT FindAssociateHelper(// return HRESULT + mdToken tkAssociate, // Event or property token + DWORD dwSemantics, // [IN] given a associate semantics(setter, getter, testdefault, reset) + RID *pRid); // [OUT] return matching row index here + + //***************************************************************************** + // Find helper for a MethodImpl. + //***************************************************************************** + __checkReturn + HRESULT FindMethodImplHelper(// return HRESULT + mdTypeDef td, // TypeDef token for the Class. + HENUMInternal *phEnum); // fill in the enum + + //***************************************************************************** + // Find helper for a GenericParams + //***************************************************************************** + __checkReturn + HRESULT FindGenericParamHelper( // Return HRESULT + mdToken tkOwner, // Token for the GenericParams' owner + HENUMInternal *phEnum); // Fill in the enum. + + //***************************************************************************** + // Find helper for a Generic Constraints + //***************************************************************************** + __checkReturn + HRESULT FindGenericParamConstraintHelper( // Return HRESULT + mdGenericParam tkParam, // Token for the GenericParam + HENUMInternal *phEnum); // Fill in the enum. + + //***************************************************************************** + // Find helper for a ClassLayout. + //***************************************************************************** + __checkReturn + HRESULT FindClassLayoutHelper( // return index to the ClassLayout table + mdTypeDef tkParent, // Parent token. + RID *pFoundRid); + + //***************************************************************************** + // Find helper for a FieldLayout. + //***************************************************************************** + __checkReturn + HRESULT FindFieldLayoutHelper( // return index to the FieldLayout table + mdFieldDef tkField, // Token for the field. + RID *pFoundRid); + + //***************************************************************************** + // Find helper for a ImplMap. + //***************************************************************************** + __checkReturn + HRESULT FindImplMapHelper( // return index to the constant table + mdToken tk, // Member forwarded token. + RID *pFoundRid); + + //***************************************************************************** + // Find helper for a FieldRVA. + //***************************************************************************** + __checkReturn + HRESULT FindFieldRVAHelper( // return index to the FieldRVA table + mdFieldDef tkField, // Token for the field. + RID *pFoundRid); + + //***************************************************************************** + // Find helper for a NestedClass. + //***************************************************************************** + __checkReturn + HRESULT FindNestedClassHelper( // return index to the NestedClass table + mdTypeDef tkClass, // Token for the NestedClass. + RID *pFoundRid); + + //***************************************************************************** + // IMPORTANT!!!!!!!! Use these set of functions if you are dealing with RW rather + // getInterfaceImplsForTypeDef, getDeclSecurityForToken, etc. + // The following functions can deal with these tables when they are not sorted and + // build the VirtualSort tables for quick lookup. + //***************************************************************************** + __checkReturn + HRESULT GetInterfaceImplsForTypeDef(mdTypeDef td, RID *pRidStart, RID *pRidEnd = 0) + { + return LookUpTableByCol( RidFromToken(td), m_pVS[TBL_InterfaceImpl], pRidStart, pRidEnd); + } + + __checkReturn + HRESULT GetGenericParamsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0) + { + return LookUpTableByCol( + encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtTypeOrMethodDef, lengthof(mdtTypeOrMethodDef)), + m_pVS[TBL_GenericParam], pRidStart, pRidEnd); + } + + __checkReturn + HRESULT GetGenericParamConstraintsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0) + { + return LookUpTableByCol( RidFromToken(tk), + m_pVS[TBL_GenericParamConstraint], pRidStart, pRidEnd); + } + + __checkReturn + HRESULT GetMethodSpecsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0) + { + return LookUpTableByCol( + encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtMethodDefOrRef, lengthof(mdtMethodDefOrRef)), + m_pVS[TBL_MethodSpec], pRidStart, pRidEnd); + } + + __checkReturn + HRESULT GetDeclSecurityForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0) + { + return LookUpTableByCol( + encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasDeclSecurity, lengthof(mdtHasDeclSecurity)), + m_pVS[TBL_DeclSecurity], + pRidStart, + pRidEnd); + } + + __checkReturn + HRESULT GetCustomAttributeForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0) + { + return LookUpTableByCol( + encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasCustomAttribute, lengthof(mdtHasCustomAttribute)), + m_pVS[TBL_CustomAttribute], + pRidStart, + pRidEnd); + } + + __checkReturn + FORCEINLINE HRESULT GetUserString(ULONG nIndex, MetaData::DataBlob *pData) + { return m_UserStringHeap.GetBlob(nIndex, pData); } + // Gets user string (*Data) at index (nIndex) and fills the index (*pnNextIndex) of the next user string + // in the heap. + // Returns S_OK and fills the string (*pData) and the next index (*pnNextIndex). + // Returns S_FALSE if the index (nIndex) is not valid user string index. + // Returns error code otherwise. + // Clears *pData and sets *pnNextIndex to 0 on error or S_FALSE. + __checkReturn + HRESULT GetUserStringAndNextIndex( + UINT32 nIndex, + MetaData::DataBlob *pData, + UINT32 *pnNextIndex); + + FORCEINLINE int IsSorted(ULONG ixTbl) { return m_Schema.IsSorted(ixTbl);} + FORCEINLINE int IsSortable(ULONG ixTbl) { return m_bSortable[ixTbl];} + FORCEINLINE bool HasDelete() { return ((m_Schema.m_heaps & CMiniMdSchema::HAS_DELETE) ? true : false); } + FORCEINLINE int IsPreSaveDone() { return m_bPreSaveDone; } + +protected: + __checkReturn HRESULT PreSave(MetaDataReorderingOptions reorderingOptions=NoReordering, CorProfileData *pProfileData=NULL); + __checkReturn HRESULT PostSave(); + + __checkReturn HRESULT PreSaveFull(); + __checkReturn HRESULT PreSaveEnc(); + + __checkReturn HRESULT GetFullPoolSaveSize(int iPool, UINT32 *pcbSize); + __checkReturn HRESULT GetENCPoolSaveSize(int iPool, UINT32 *pcbSize); + + __checkReturn HRESULT SaveFullPoolToStream(int iPool, IStream *pIStream); + __checkReturn HRESULT SaveENCPoolToStream(int iPool, IStream *pIStream); + + __checkReturn + HRESULT GetHotMetadataTokensSearchAware( + CorProfileData *pProfileData, + ULONG ixTbl, + ULONG *pResultCount, + mdToken *tokenBuffer, + ULONG maxCount); + + __checkReturn + HRESULT GetFullSaveSize( + CorSaveSize fSave, + UINT32 *pcbSize, + DWORD *pbCompressed, + MetaDataReorderingOptions reorderingOptions = NoReordering, + CorProfileData *pProfileData = NULL); + __checkReturn + HRESULT GetENCSaveSize(UINT32 *pcbSize); + __checkReturn + HRESULT GetHotPoolsSaveSize( + UINT32 *pcbSize, + MetaDataReorderingOptions reorderingOptions, + CorProfileData *pProfileData); + + __checkReturn + HRESULT SaveFullTablesToStream(IStream *pIStream, MetaDataReorderingOptions reorderingOptions=NoReordering, CorProfileData *pProfileData = NULL ); + __checkReturn + HRESULT SaveENCTablesToStream(IStream *pIStream); + __checkReturn + HRESULT SaveHotPoolsToStream( + IStream *pStream, + MetaDataReorderingOptions reorderingOptions, + CorProfileData *pProfileData, + UINT32 *pnPoolDirSize, + UINT32 *pnSavedPoolsSize); + __checkReturn + HRESULT SaveHotPoolToStream( + IStream *pStream, + CorProfileData *pProfileData, + MetaData::HotHeapWriter *pHotHeapWriter, + UINT32 *pnSavedSize); + + // TO ELIMINATE: + __checkReturn + HRESULT AddGuid(REFGUID pGuid, UINT32 *pnIndex) + { return m_GuidHeap.AddGuid(&pGuid, pnIndex); } + + // Allows putting into tables outside this MiniMd, specifically the temporary + // table used on save. + __checkReturn + HRESULT PutCol(CMiniColDef ColDef, void *pRecord, ULONG uVal); + + // Returns TRUE if token (tk) is valid. + // For user strings, consideres 0 as valid token. + BOOL _IsValidToken( + mdToken tk) // [IN] token to be checked + { + if (TypeFromToken(tk) == mdtString) + { + // need to check the user string heap + return m_UserStringHeap.IsValidIndex(RidFromToken(tk)); + } + // Base type doesn't know about user string blob (yet) + return _IsValidTokenBase(tk); + } // CMiniMdRW::_IsValidToken + +#ifdef _DEBUG + bool CanHaveCustomAttribute(ULONG ixTbl); +#endif + + __checkReturn + HRESULT ExpandTables(); + __checkReturn + HRESULT ExpandTableColumns(CMiniMdSchema &Schema, ULONG ixTbl); + + __checkReturn + HRESULT InitWithLargeTables(); + + void ComputeGrowLimits(int bSmall=TRUE); // Set max, lim, based on param. + ULONG m_maxRid; // Highest RID so far allocated. + ULONG m_limRid; // Limit on RID before growing. + ULONG m_maxIx; // Highest pool index so far. + ULONG m_limIx; // Limit on pool index before growing. + enum {eg_ok, eg_grow, eg_grown} m_eGrow; // Is a grow required? done? + #define AUTO_GROW_CODED_TOKEN_PADDING 5 + + // fix up these tables after PreSave has move the tokens + __checkReturn HRESULT FixUpTable(ULONG ixTbl); + __checkReturn HRESULT FixUpRefToDef(); + + // Table info. + MetaData::TableRW m_Tables[TBL_COUNT]; + VirtualSort *m_pVS[TBL_COUNT]; // Virtual sorters, one per table, but sparse. + + //***************************************************************************** + // look up a table by a col given col value is ulVal. + //***************************************************************************** + __checkReturn + HRESULT LookUpTableByCol( + ULONG ulVal, + VirtualSort *pVSTable, + RID *pRidStart, + RID *pRidEnd); + + __checkReturn + HRESULT Impl_SearchTableRW(ULONG ixTbl, ULONG ixCol, ULONG ulTarget, RID *pFoundRid); + __checkReturn + virtual HRESULT vSearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid); + __checkReturn + virtual HRESULT vSearchTableNotGreater(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid); + + void SetSorted(ULONG ixTbl, int bSorted) + { m_Schema.SetSorted(ixTbl, bSorted); } + + void SetPreSaveDone(int bPreSaveDone) + { m_bPreSaveDone = bPreSaveDone; } + + // Heaps + MetaData::StringHeapRW m_StringHeap; + MetaData::BlobHeapRW m_BlobHeap; + MetaData::BlobHeapRW m_UserStringHeap; + MetaData::GuidHeapRW m_GuidHeap; + + IMapToken *m_pHandler; // Remap handler. + __checkReturn HRESULT MapToken(RID from, RID to, mdToken type); + + ULONG m_cbSaveSize; // Estimate of save size. + + int m_fIsReadOnly : 1; // Is this db read-only? + int m_bPreSaveDone : 1; // Has save optimization been done? + int m_bSaveCompressed : 1; // Can the data be saved as fully compressed? + int m_bPostGSSMod : 1; // true if a change was made post GetSaveSize. + + + //************************************************************************* + // Overridables -- must be provided in derived classes. + __checkReturn + FORCEINLINE HRESULT Impl_GetString(UINT32 nIndex, __out LPCSTR *pszString) + { return m_StringHeap.GetString(nIndex, pszString); } + __checkReturn + HRESULT Impl_GetStringW(ULONG ix, __inout_ecount (cchBuffer) LPWSTR szOut, ULONG cchBuffer, ULONG *pcchBuffer); + __checkReturn + FORCEINLINE HRESULT Impl_GetGuid(UINT32 nIndex, GUID *pTargetGuid) + { + HRESULT hr; + GUID UNALIGNED *pSourceGuid; + IfFailRet(m_GuidHeap.GetGuid( + nIndex, + &pSourceGuid)); + // Add void* casts so that the compiler can't make assumptions about alignment. + CopyMemory((void *)pTargetGuid, (void *)pSourceGuid, sizeof(GUID)); + SwapGuid(pTargetGuid); + return S_OK; + } + + __checkReturn + FORCEINLINE HRESULT Impl_GetBlob(ULONG nIndex, __out MetaData::DataBlob *pData) + { return m_BlobHeap.GetBlob(nIndex, pData); } + + __checkReturn + FORCEINLINE HRESULT Impl_GetRow( + UINT32 nTableIndex, + UINT32 nRowIndex, + __deref_out_opt BYTE **ppRecord) + { + _ASSERTE(nTableIndex < TBL_COUNT); + return m_Tables[nTableIndex].GetRecord(nRowIndex, ppRecord); + } + + // Count of rows in tbl2, pointed to by the column in tbl. + __checkReturn + HRESULT Impl_GetEndRidForColumn( + UINT32 nTableIndex, + RID nRowIndex, + CMiniColDef &def, // Column containing the RID into other table. + UINT32 nTargetTableIndex, // The other table. + RID *pEndRid); + + __checkReturn + FORCEINLINE HRESULT Impl_SearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ixCol, ULONG ulTarget, RID *pFoundRid) + { return Impl_SearchTableRW(ixTbl, ixCol, ulTarget, pFoundRid); } + + FORCEINLINE int Impl_IsRo() + { return 0; } + + + //************************************************************************* + enum {END_OF_TABLE = 0}; + FORCEINLINE ULONG NewRecordPointerEndValue(ULONG ixTbl) + { if (HasIndirectTable(ixTbl)) return m_Schema.m_cRecs[ixTbl]+1; else return END_OF_TABLE; } + + __checkReturn HRESULT ConvertMarkerToEndOfTable(ULONG tblParent, ULONG colParent, ULONG ridChild, RID ridParent); + + // Add a child row, adjust pointers in parent rows. + __checkReturn + HRESULT AddChildRowIndirectForParent( + ULONG tblParent, + ULONG colParent, + ULONG tblChild, + RID ridParent, + void **ppRow); + + // Update pointers in the parent table to reflect the addition of a child, if required + // create the indirect table in which case don't update pointers. + __checkReturn + HRESULT AddChildRowDirectForParent(ULONG tblParent, ULONG colParent, ULONG tblChild, RID ridParent); + + // Given a table id, create the corresponding indirect table. + __checkReturn + HRESULT CreateIndirectTable(ULONG ixtbl, BOOL bOneLess = true); + + // If the last param is not added in the right sequence, fix it up. + __checkReturn + HRESULT FixParamSequence(RID md); + + + // these are the map tables to map a method, a field, a property, a event, or a param to its parent + TOKENMAP *m_pMethodMap; + TOKENMAP *m_pFieldMap; + TOKENMAP *m_pPropertyMap; + TOKENMAP *m_pEventMap; + TOKENMAP *m_pParamMap; + + // This table keep tracks tokens that are marked( or filtered) + FilterTable *m_pFilterTable; + IHostFilter *m_pHostFilter; + + // TOKENMAP *m_pTypeRefToTypeDefMap; + TokenRemapManager *m_pTokenRemapManager; + + OptionValue m_OptionValue; + + CMiniMdSchema m_StartupSchema; // Schema at start time. Keep count of records. + BYTE m_bSortable[TBL_COUNT]; // Is a given table sortable? (Can it be reorganized?) +#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE + ReleaseHolder<IMDCustomDataSource> m_pCustomDataSource; +#endif + +#ifdef _DEBUG + +protected: + UTSemReadWrite * dbg_m_pLock; + +public: + // Checks that MetaData is locked for write operation (if thread-safety is enabled and the lock exists) + void Debug_CheckIsLockedForWrite(); + + void Debug_SetLock(UTSemReadWrite * pLock) + { + dbg_m_pLock = pLock; + } + +#endif //_DEBUG + +public: + + FilterTable *GetFilterTable(); + __checkReturn HRESULT UnmarkAll(); + __checkReturn HRESULT MarkAll(); + + FORCEINLINE IHostFilter *GetHostFilter() { return m_pHostFilter;} + + __checkReturn HRESULT CalculateTypeRefToTypeDefMap(); + + FORCEINLINE TOKENMAP *GetTypeRefToTypeDefMap() + { return m_pTokenRemapManager ? m_pTokenRemapManager->GetTypeRefToTypeDefMap() : NULL; }; + + FORCEINLINE TOKENMAP *GetMemberRefToMemberDefMap() + { return m_pTokenRemapManager ? m_pTokenRemapManager->GetMemberRefToMemberDefMap() : NULL; }; + + FORCEINLINE MDTOKENMAP *GetTokenMovementMap() + { return m_pTokenRemapManager ? m_pTokenRemapManager->GetTokenMovementMap() : NULL; }; + + FORCEINLINE TokenRemapManager *GetTokenRemapManager() { return m_pTokenRemapManager; }; + + __checkReturn HRESULT InitTokenRemapManager(); + + virtual ULONG vGetCol(ULONG ixTbl, ULONG ixCol, void *pRecord) + { return GetCol(ixTbl, ixCol, pRecord);} + +public: + virtual BOOL IsWritable() + { + return !m_fIsReadOnly; + } + + + //************************************************************************* + // Delta MetaData (EditAndContinue) functions. +public: + enum eDeltaFuncs{ + eDeltaFuncDefault = 0, + eDeltaMethodCreate, + eDeltaFieldCreate, + eDeltaParamCreate, + eDeltaPropertyCreate, + eDeltaEventCreate, + }; + + __checkReturn HRESULT ApplyDelta(CMiniMdRW &mdDelta); + +public: + // Functions for updating ENC log tables ENC log. + FORCEINLINE BOOL IsENCOn() + { + return (m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateENC; + } + + __checkReturn + FORCEINLINE HRESULT UpdateENCLog(mdToken tk, CMiniMdRW::eDeltaFuncs funccode = CMiniMdRW::eDeltaFuncDefault) + { + if (IsENCOn()) + return UpdateENCLogHelper(tk, funccode); + else + return S_OK; + } + + __checkReturn + FORCEINLINE HRESULT UpdateENCLog2(ULONG ixTbl, ULONG iRid, CMiniMdRW::eDeltaFuncs funccode = CMiniMdRW::eDeltaFuncDefault) + { + if (IsENCOn()) + return UpdateENCLogHelper2(ixTbl, iRid, funccode); + else + return S_OK; + } + + __checkReturn HRESULT ResetENCLog(); + +private: + BOOL m_fMinimalDelta; + + // + // String heap reorganization + // + + // Check to see if it is safe to reorder the string pool. + BOOL IsSafeToReorderStringPool(); + // Function to mark hot strings in the marks array based on the token information in profile data. + VOID MarkHotStrings(CorProfileData *pProfileData, BYTE * pMarks, ULONG poolSize); + // Function to mark hot strings referenced by hot tables based on token information in profile data. + VOID MarkStringsInHotTables(CorProfileData *pProfileData, BYTE * pMarks, ULONG poolSize); + // Function to mark strings referenced by the different metadata tables. + VOID MarkStringsInTables(BYTE * pMarks, ULONG poolSize); + // Function to mark duplicate strings in the mark array. + // Throws on error. + VOID MarkDuplicateStrings(BYTE * pMarks, ULONG poolSize); + // Function to update the tables with the modified string offsets. + VOID FixStringsInTables(); + // Function to fill the given string pool with strings from the existing string pool using the mark array. + // Throws on error. + VOID CreateReorderedStringPool( + MetaData::StringHeapRW *pStringHeap, + BYTE *pMarks, + ULONG cbHeapSize, + CorProfileData *pProfileData); + +public: + BOOL IsMinimalDelta() + { + return m_fMinimalDelta; + } + + + // Turns on/off the ability to emit delta metadatas + + // Unfortunately, we can't allow this to be set via the SetOption method anymore. In v1.0 and v1.1, this flag + // could be set but would still result in generating full metadatas. We can't automatically start generating + // true deltas for people... it could break them. + void EnableDeltaMetadataGeneration() + { + _ASSERTE(m_OptionValue.m_UpdateMode == MDUpdateENC); +#ifndef FEATURE_CORECLR + if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas)) + m_OptionValue.m_UpdateMode = MDUpdateDelta; +#endif //!FEATURE_CORECLR + } + void DisableDeltaMetadataGeneration() {m_OptionValue.m_UpdateMode = MDUpdateENC;} + +protected: + // Internal Helper functions for ENC log. + __checkReturn + HRESULT UpdateENCLogHelper(mdToken tk, CMiniMdRW::eDeltaFuncs funccode); + __checkReturn + HRESULT UpdateENCLogHelper2(ULONG ixTbl, ULONG iRid, CMiniMdRW::eDeltaFuncs funccode); + +protected: + static ULONG m_TruncatedEncTables[]; + static ULONG m_SuppressedDeltaColumns[TBL_COUNT]; + + ULONGARRAY *m_rENCRecs; // Array of RIDs affected by ENC. + + __checkReturn + HRESULT ApplyRecordDelta(CMiniMdRW &mdDelta, ULONG ixTbl, void *pDelta, void *pRecord); + __checkReturn + HRESULT ApplyTableDelta(CMiniMdRW &mdDelta, ULONG ixTbl, RID iRid, int fc); + __checkReturn + HRESULT GetDeltaRecord(ULONG ixTbl, ULONG iRid, void **ppRecord); + __checkReturn + HRESULT ApplyHeapDeltas(CMiniMdRW &mdDelta); + __checkReturn + HRESULT ApplyHeapDeltasWithMinimalDelta(CMiniMdRW &mdDelta); + __checkReturn + HRESULT ApplyHeapDeltasWithFullDelta(CMiniMdRW &mdDelta); + __checkReturn + HRESULT StartENCMap(); // Call, on a delta MD, to prepare to access sparse rows. + __checkReturn + HRESULT EndENCMap(); // Call, on a delta MD, when done with sparse rows. + +public: + // Workaround for compiler performance issue VSW 584653 for 2.0 RTM. + // Get the table's VirtualSort validity state. + bool IsTableVirtualSorted(ULONG ixTbl); + // Workaround for compiler performance issue VSW 584653 for 2.0 RTM. + // Validate table's VirtualSort after adding one record into the table. + // Returns new VirtualSort validity state in *pfIsTableVirtualSortValid. + // Assumptions: + // Table's VirtualSort was valid before adding the record to the table. + // The caller must ensure validity of VirtualSort by calling to + // IsTableVirtualSorted or by using the returned state from previous + // call to this method. + __checkReturn + HRESULT ValidateVirtualSortAfterAddRecord( + ULONG ixTbl, + bool * pfIsTableVirtualSortValid); + +}; // class CMiniMdRW : public CMiniMdTemplate<CMiniMdRW> + +#endif // _METAMODELRW_H_ diff --git a/src/md/inc/recordpool.h b/src/md/inc/recordpool.h new file mode 100644 index 0000000000..36bd67a656 --- /dev/null +++ b/src/md/inc/recordpool.h @@ -0,0 +1,161 @@ +// 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. +//***************************************************************************** +// RecordPool.h -- header file for record heaps. +// + +// +//***************************************************************************** +#ifndef _RECORDPOOL_H_ +#define _RECORDPOOL_H_ + +#if _MSC_VER >= 1100 +#pragma once +#endif + +#include <stgpool.h> + +//***************************************************************************** +// This Record pool class collects user Records into a big consecutive heap. +// The list of Records is kept in memory while adding, and +// finally flushed to a stream at the caller's request. +//***************************************************************************** +class RecordPool : public StgPool +{ + friend class VerifyLayoutsMD; + + using StgPool::InitNew; + using StgPool::InitOnMem; + +public: + RecordPool() : + StgPool(1024, 1) + { } + +//***************************************************************************** +// Init the pool for use. This is called for the create empty case. +//***************************************************************************** + __checkReturn + HRESULT InitNew( + UINT32 cbRec, // Record size. + UINT32 cRecsInit); // Initial guess of count of record. + +//***************************************************************************** +// Load a Record heap from persisted memory. If a copy of the data is made +// (so that it may be updated), then a new hash table is generated which can +// be used to elminate duplicates with new Records. +//***************************************************************************** + __checkReturn + HRESULT InitOnMem( + ULONG cbRec, // Record size. + void *pData, // Predefined data. + ULONG iSize, // Size of data. + BOOL fReadOnly); // true if append is forbidden. + +//***************************************************************************** +// Allocate memory if we don't have any, or grow what we have. If successful, +// then at least iRequired bytes will be allocated. +//***************************************************************************** + bool Grow( // true if successful. + ULONG iRequired); // Min required bytes to allocate. + +//***************************************************************************** +// The Record will be added to the pool. The index of the Record in the pool +// is returned in *piIndex. If the Record is already in the pool, then the +// index will be to the existing copy of the Record. +//***************************************************************************** + HRESULT AddRecord( + BYTE **ppRecord, + UINT32 *pnIndex); // Return 1-based index of Record here. + +//***************************************************************************** +// Insert a Record into the pool. The index of the Record before which to +// insert is specified. Shifts all records down. Return a pointer to the +// new record. +//***************************************************************************** + HRESULT InsertRecord( + UINT32 nIndex, // [IN] Insert record before this. + BYTE **ppRecord); + +//***************************************************************************** +// Return a pointer to a Record given an index previously handed out by +// AddRecord or FindRecord. +//***************************************************************************** + __checkReturn + virtual HRESULT GetRecord( + UINT32 nIndex, // 1-based index of Record in pool. + BYTE **ppRecord); + +//***************************************************************************** +// Given a pointer to a record, determine the index corresponding to the +// record. +//***************************************************************************** + virtual ULONG GetIndexForRecord( // 1-based index of Record in pool. + const void *pRecord); // Pointer to Record in pool. + +//***************************************************************************** +// Given a purported pointer to a record, determine if the pointer is valid. +//***************************************************************************** + virtual int IsValidPointerForRecord( // true or false. + const void *pRecord); // Pointer to Record in pool. + +//***************************************************************************** +// How many objects are there in the pool? If the count is 0, you don't need +// to persist anything at all to disk. +//***************************************************************************** + UINT32 Count() + { return GetNextOffset() / m_cbRec; } + +//***************************************************************************** +// Indicate if heap is empty. This has to be based on the size of the data +// we are keeping. If you open in r/o mode on memory, there is no hash +// table. +//***************************************************************************** + virtual int IsEmpty() // true if empty. + { return (GetNextOffset() == 0); } + +//***************************************************************************** +// Is the index valid for the Record? +//***************************************************************************** + virtual int IsValidCookie(ULONG ulCookie) + { return (ulCookie == 0 || IsValidOffset((ulCookie-1) * m_cbRec)); } + +//***************************************************************************** +// Return the size of the heap. +//***************************************************************************** + ULONG GetNextIndex() + { return (GetNextOffset() / m_cbRec); } + +//***************************************************************************** +// Replace the contents of this pool with those from another pool. The other +// pool loses ownership of the memory. +//***************************************************************************** + __checkReturn + HRESULT ReplaceContents( + RecordPool *pOther); // The other record pool. + +//***************************************************************************** +// Return the first record in a pool, and set up a context for fast +// iterating through the pool. Note that this scheme does pretty minimal +// error checking. +//***************************************************************************** + void *GetFirstRecord( // Pointer to Record in pool. + void **pContext); // Store context here. + +//***************************************************************************** +// Given a pointer to a record, return a pointer to the next record. +// Note that this scheme does pretty minimal error checking. In particular, +// this will let the caller walk off of the end of valid data in the last +// segment. +//***************************************************************************** + void *GetNextRecord( // Pointer to Record in pool. + void *pRecord, // Current record. + void **pContext); // Stored context here. + +private: + UINT32 m_cbRec; // How large is each record? + +}; // class RecordPool + +#endif // _RECORDPOOL_H_ diff --git a/src/md/inc/rwutil.h b/src/md/inc/rwutil.h new file mode 100644 index 0000000000..5d7f98919c --- /dev/null +++ b/src/md/inc/rwutil.h @@ -0,0 +1,369 @@ +// 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. +//***************************************************************************** +// RWUtil.h +// + +// +// Contains utility code for MD directory +// +//***************************************************************************** +#ifndef __RWUtil__h__ +#define __RWUtil__h__ + +class UTSemReadWrite; + +#define UTF8STR(wszInput, szOutput) \ + do { \ + if ((wszInput) == NULL) \ + { \ + (szOutput) = NULL; \ + } \ + else \ + { \ + int cbBuffer = ((int)wcslen(wszInput) * 3) + 1; \ + (szOutput) = (char *)_alloca(cbBuffer); \ + Unicode2UTF((wszInput), (szOutput), cbBuffer); \ + } \ + } while (0) + +//***************************************************************************** +// Helper methods +//***************************************************************************** +void +Unicode2UTF( + LPCWSTR wszSrc, // The string to convert. + __out_ecount(cbDst) + LPUTF8 szDst, // Buffer for the output UTF8 string. + int cbDst); // Size of the buffer for UTF8 string. + +//********************************************************************* +// The token remap record. +//********************************************************************* +struct TOKENREC +{ + mdToken m_tkFrom; // The imported token + bool m_isDuplicate; // Is record duplicate? This information is recorded during merge + bool m_isDeleted; // This information is recorded during RegMeta::ProcessFilter when we might have deleted a record + bool m_isFoundInImport; // This information is also recorded during RegMeta::ProcessFilter + mdToken m_tkTo; // The new token in the merged scope + + void SetEmpty() {m_tkFrom = m_tkTo = (mdToken) -1;} + BOOL IsEmpty() {return m_tkFrom == (mdToken) -1;} +}; + + +//********************************************************************* +// +// This structure keeps track on token remap for an imported scope. This map is initially sorted by from +// tokens. It can then become sorted by To tokens. This usually happen during PreSave remap lookup. Thus +// we assert if we try to look up or sort by From token. +// +//********************************************************************* +class MDTOKENMAP : public CDynArray<TOKENREC> +{ +public: + + enum SortKind{ + Unsorted = 0, + SortByFromToken = 1, + SortByToToken = 2, + Indexed = 3, // Indexed by table/rid. Implies that strings are sorted by "From". + }; + + MDTOKENMAP() + : m_pNextMap(NULL), + m_pMap(NULL), + m_iCountTotal(0), + m_iCountSorted(0), + m_sortKind(SortByFromToken), + m_iCountIndexed(0) +#if defined(_DEBUG) + ,m_pImport(0) +#endif + { } + ~MDTOKENMAP(); + + HRESULT Init(IUnknown *pImport); + + // find a token in the tokenmap. + bool Find(mdToken tkFrom, TOKENREC **ppRec); + + // remap a token. We assert if we don't find the tkFind in the table + HRESULT Remap(mdToken tkFrom, mdToken *ptkTo); + + // Insert a record. This function will keep the inserted record in a sorted sequence + HRESULT InsertNotFound(mdToken tkFrom, bool fDuplicate, mdToken tkTo, TOKENREC **ppRec); + + // This function will just append the record to the end of the list + HRESULT AppendRecord( + mdToken tkFrom, + bool fDuplicate, + mdToken tkTo, + TOKENREC **ppRec); + + // This is a safe remap. *tpkTo will be tkFind if we cannot find tkFind in the lookup table. + mdToken SafeRemap(mdToken tkFrom); // [IN] the token value to find + + bool FindWithToToken( + mdToken tkFind, // [IN] the token value to find + int *piPosition); // [OUT] return the first from-token that has the matching to-token + + FORCEINLINE void SortTokensByFromToken() + { + _ASSERTE(m_sortKind == SortByFromToken || m_sortKind == Indexed); + // Only sort if there are unsorted records. + if (m_iCountSorted < m_iCountTotal) + { + SortRangeFromToken(m_iCountIndexed, m_iCountIndexed+m_iCountTotal - 1); + m_iCountSorted = m_iCountTotal; + } + } // void MDTOKENMAP::SortTokensByFromToken() + + HRESULT EmptyMap(); + + void SortTokensByToToken(); + + MDTOKENMAP *m_pNextMap; + IMapToken *m_pMap; + +private: + FORCEINLINE int CompareFromToken( // -1, 0, or 1 + int iLeft, // First item to compare. + int iRight) // Second item to compare. + { + if ( Get(iLeft)->m_tkFrom < Get(iRight)->m_tkFrom ) + return -1; + if ( Get(iLeft)->m_tkFrom == Get(iRight)->m_tkFrom ) + return 0; + return 1; + } + + FORCEINLINE int CompareToToken( // -1, 0, or 1 + int iLeft, // First item to compare. + int iRight) // Second item to compare. + { + if ( Get(iLeft)->m_tkTo < Get(iRight)->m_tkTo ) + return -1; + if ( Get(iLeft)->m_tkTo == Get(iRight)->m_tkTo ) + return 0; + return 1; + } + + FORCEINLINE void Swap( + int iFirst, + int iSecond) + { + if ( iFirst == iSecond ) return; + memcpy( &m_buf, Get(iFirst), sizeof(TOKENREC) ); + memcpy( Get(iFirst), Get(iSecond),sizeof(TOKENREC) ); + memcpy( Get(iSecond), &m_buf, sizeof(TOKENREC) ); + } + + void SortRangeFromToken(int iLeft, int iRight); + void SortRangeToToken(int iLeft, int iRight); + + TOKENREC m_buf; + ULONG m_iCountTotal; // total entry in the map + ULONG m_iCountSorted; // number of entries that are sorted + + SortKind m_sortKind; + + ULONG m_TableOffset[TBL_COUNT+1]; // Start of each table in map. + ULONG m_iCountIndexed; // number of entries that are indexed. +#if defined(_DEBUG) + IMetaDataImport *m_pImport; // For data validation. +#endif +}; + + + +//********************************************************************* +// +// Merge Token manager. This class is created in GetSaveSize as an agent to +// notify linker regarding token movements. It does not have the ability to +// keep track token movement. +// +//********************************************************************* +class MergeTokenManager : public IMapToken +{ +public: + STDMETHODIMP QueryInterface(REFIID riid, PVOID *pp); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + STDMETHODIMP Map(mdToken tkImp, mdToken tkEmit); + MergeTokenManager(MDTOKENMAP *pTkMapList, IUnknown *pHandler); + virtual ~MergeTokenManager(); +private: + LONG m_cRef; + MDTOKENMAP *m_pTkMapList; + IMapToken *m_pDefaultHostRemap; +}; + + + +//********************************************************************* +// +// This CMapToken class implemented the IMapToken. It is used in RegMeta for +// filter process. This class can track all of the tokens are mapped. It also +// supplies a Find function. +// +//********************************************************************* +class CMapToken : public IMapToken +{ + friend class RegMeta; + +public: + STDMETHODIMP QueryInterface(REFIID riid, PVOID *pp); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + STDMETHODIMP Map(mdToken tkImp, mdToken tkEmit); + bool Find(mdToken tkFrom, TOKENREC **pRecTo); + CMapToken(); + virtual ~CMapToken(); + MDTOKENMAP *m_pTKMap; +private: + LONG m_cRef; + bool m_isSorted; +}; + +typedef CDynArray<mdToken> TOKENMAP; + +//********************************************************************* +// +// This class records all sorts of token movement during optimization phase. +// This including Ref to Def optimization. This also includes token movement +// due to sorting or eleminating the pointer tables. +// +//********************************************************************* +class TokenRemapManager +{ +public: + //********************************************************************* + // + // This function is called when a TypeRef is resolved to a TypeDef. + // + //********************************************************************* + FORCEINLINE void RecordTypeRefToTypeDefOptimization( + mdToken tkFrom, + mdToken tkTo) + { + _ASSERTE( TypeFromToken(tkFrom) == mdtTypeRef ); + _ASSERTE( TypeFromToken(tkTo) == mdtTypeDef ); + + m_TypeRefToTypeDefMap[RidFromToken(tkFrom)] = tkTo; + } // RecordTypeRefToTypeDefOptimization + + + //********************************************************************* + // + // This function is called when a MemberRef is resolved to a MethodDef or FieldDef. + // + //********************************************************************* + FORCEINLINE void RecordMemberRefToMemberDefOptimization( + mdToken tkFrom, + mdToken tkTo) + { + _ASSERTE( TypeFromToken(tkFrom) == mdtMemberRef ); + _ASSERTE( TypeFromToken(tkTo) == mdtMethodDef || TypeFromToken(tkTo) == mdtFieldDef); + + m_MemberRefToMemberDefMap[RidFromToken(tkFrom)] = tkTo; + } // RecordMemberRefToMemberDefOptimization + + //********************************************************************* + // + // This function is called when the token kind does not change but token + // is moved. For example, when we sort CustomAttribute table or when we optimize + // away MethodPtr table. These operation will not change the token type. + // + //********************************************************************* + FORCEINLINE HRESULT RecordTokenMovement( + mdToken tkFrom, + mdToken tkTo) + { + TOKENREC *pTokenRec; + + _ASSERTE( TypeFromToken(tkFrom) == TypeFromToken(tkTo) ); + return m_TKMap.AppendRecord( tkFrom, false, tkTo, &pTokenRec ); + } // RecordTokenMovement + + bool ResolveRefToDef( + mdToken tkRef, // [IN] ref token + mdToken *ptkDef); // [OUT] def token that it resolves to. If it does not resolve to a def + + FORCEINLINE TOKENMAP *GetTypeRefToTypeDefMap() { return &m_TypeRefToTypeDefMap; } + FORCEINLINE TOKENMAP *GetMemberRefToMemberDefMap() { return &m_MemberRefToMemberDefMap; } + FORCEINLINE MDTOKENMAP *GetTokenMovementMap() { return &m_TKMap; } + + ~TokenRemapManager(); + HRESULT ClearAndEnsureCapacity(ULONG cTypeRef, ULONG cMemberRef); +private: + MDTOKENMAP m_TKMap; + TOKENMAP m_TypeRefToTypeDefMap; + TOKENMAP m_MemberRefToMemberDefMap; +}; // class TokenRemapManager + +// value that can be set by SetOption APIs +struct OptionValue +{ + CorCheckDuplicatesFor m_DupCheck; // Bit Map for checking duplicates during emit. + CorRefToDefCheck m_RefToDefCheck; // Bit Map for specifying whether to do a ref to def optimization. + CorNotificationForTokenMovement m_NotifyRemap; // Bit Map for token remap notification. + ULONG m_UpdateMode; // (CorSetENC) Specifies whether ENC or Extension mode is on. + CorErrorIfEmitOutOfOrder m_ErrorIfEmitOutOfOrder; // Do not generate pointer tables + CorThreadSafetyOptions m_ThreadSafetyOptions; // specify if thread safety is turn on or not. + CorImportOptions m_ImportOption; // import options such as to skip over deleted items or not + CorLinkerOptions m_LinkerOption; // Linker option. Currently only used in UnmarkAll + BOOL m_GenerateTCEAdapters; // Do not generate the TCE adapters for COM CPC. + LPSTR m_RuntimeVersion; // CLR Version stamp + MetadataVersion m_MetadataVersion; // Version of the metadata to emit + MergeFlags m_MergeOptions; // Options to pass to the merger + UINT32 m_InitialSize; // Initial size of MetaData with values: code:CorMetaDataInitialSize. + CorLocalRefPreservation m_LocalRefPreservation; // Preserve module-local refs instead of optimizing them to defs +}; // struct OptionValue + +//********************************************************************* +// +// Helper class to ensure calling UTSemReadWrite correctly. +// The destructor will call the correct UnlockRead or UnlockWrite depends what lock it is holding. +// User should use macro defined in below instead of calling functions on this class directly. +// They are LOCKREAD(), LOCKWRITE(), and CONVERT_READ_TO_WRITE_LOCK. +// +//********************************************************************* +class CMDSemReadWrite +{ +public: + CMDSemReadWrite(UTSemReadWrite *pSem); + ~CMDSemReadWrite(); + HRESULT LockRead(); + HRESULT LockWrite(); + void UnlockWrite(); + HRESULT ConvertReadLockToWriteLock(); +private: + bool m_fLockedForRead; + bool m_fLockedForWrite; + UTSemReadWrite *m_pSem; +}; + + +#define LOCKREADIFFAILRET() CMDSemReadWrite cSem(m_pSemReadWrite);\ + IfFailRet(cSem.LockRead()); +#define LOCKWRITEIFFAILRET() CMDSemReadWrite cSem(m_pSemReadWrite);\ + IfFailRet(cSem.LockWrite()); + +#define LOCKREADNORET() CMDSemReadWrite cSem(m_pSemReadWrite);\ + hr = cSem.LockRead(); +#define LOCKWRITENORET() CMDSemReadWrite cSem(m_pSemReadWrite);\ + hr = cSem.LockWrite(); + +#define LOCKREAD() CMDSemReadWrite cSem(m_pSemReadWrite);\ + IfFailGo(cSem.LockRead()); +#define LOCKWRITE() CMDSemReadWrite cSem(m_pSemReadWrite);\ + IfFailGo(cSem.LockWrite()); + +#define UNLOCKWRITE() cSem.UnlockWrite(); +#define CONVERT_READ_TO_WRITE_LOCK() IfFailGo(cSem.ConvertReadLockToWriteLock()); + + +#endif // __RWUtil__h__ diff --git a/src/md/inc/stgio.h b/src/md/inc/stgio.h new file mode 100644 index 0000000000..96a2f1dddb --- /dev/null +++ b/src/md/inc/stgio.h @@ -0,0 +1,293 @@ +// 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. +//***************************************************************************** +// StgIO.h +// + +// +// This module handles disk/memory i/o for a generic set of storage solutions, +// including: +// * File system handle (HFILE) +// * IStream +// * User supplied memory buffer (non-movable) +// +// The Read, Write, Seek, ... functions are all directed to the corresponding +// method for each type of file, allowing the consumer to use one set of api's. +// +// File system data can be paged fully into memory in two scenarios: +// read: Normal memory mapped file is created to manage paging. +// write: A custom paging system provides storage for pages as required. This +// data is invalidated when you call Rewrite on the file. +// +// Transactions and backups are handled in the existing file case only. The +// Rewrite function can make a backup of the current contents, and the Restore +// function can be used to recover the data into the current scope. The backup +// file is flushed to disk (which is slower but safer) after the copy. The +// Restore also flushed the recovered changes to disk. Worst case scenario you +// get a crash after calling Rewrite but before Restore, in which case you will +// have a foo.clb.txn file in the same directory as the source file, foo.clb in +// this example. +//<TODO> +// @FUTURE: issues, +// 1. For reading a .clb in an image, it would be great to memory map +// only the portion of the file with the .clb in it. +//</TODO> +//***************************************************************************** +#ifndef __STGIO_H_ +#define __STGIO_H_ + +#define MAXSHMEM 32 + +#define STGIO_READ 0x1 +#define STGIO_WRITE 0x2 + +enum DBPROPMODE + { DBPROP_TMODEF_READ = 0x1, + DBPROP_TMODEF_WRITE = 0x2, + DBPROP_TMODEF_EXCLUSIVE = 0x4, +#ifndef FEATURE_METADATA_STANDALONE_WINRT_RO + // Shared memory uses ole32.dll - we cannot depend on it in the standalone WinRT Read-Only DLL + DBPROP_TMODEF_SHAREDMEM = 0x8, +#endif + DBPROP_TMODEF_CREATE = 0x10, + DBPROP_TMODEF_FAILIFTHERE = 0x20, + DBPROP_TMODEF_SLOWSAVE = 0x100, + // Means it is OK to use LoadLibrary to map the file. Used by code:ofTrustedImage. + // We prefer that because it is shared with loader's image loading. + DBPROP_TMODEF_TRYLOADLIBRARY = 0x400, +#if 0 // dead code + DBPROP_TMODEF_NOTXNBACKUPFILE = 0x200, + DBPROP_TMODEF_COMPLUS = 0x1000, + DBPROP_TMODEF_SMEMCREATE = 0x2000, + DBPROP_TMODEF_SMEMOPEN = 0x4000, + DBPROP_TMODEF_ALIGNBLOBS = 0x10000 + DBPROP_TMODEF_RESERVED = 0x80000000, +#endif + DBPROP_TMODEF_DFTWRITEMASK = 0x113, + DBPROP_TMODEF_DFTREADWRITEMASK = 0x103, + }; + + +// Types of IO we can handle. +enum STGIOTYPE +{ + STGIO_NODATA = 0, // Currently not open. + STGIO_HFILE = 1, // File handle contains data. + STGIO_HMODULE = 2, // The file was loaded via LoadLibrary as module. + STGIO_STREAM = 3, // Stream pointer has data. + STGIO_MEM = 4, // In memory pointer has data. +#ifndef FEATURE_METADATA_STANDALONE_WINRT_RO + // Shared memory uses ole32.dll - we cannot depend on it in the standalone WinRT Read-Only DLL + STGIO_SHAREDMEM = 5, // Shared memory handle. +#endif + STGIO_HFILEMEM = 6 // Handle open, but memory allocated. +}; + +class StgIO +{ + friend class CLiteWeightStgdbRW; // for low-level access to data for metainfo and such. + friend class TiggerStorage; +public: + StgIO( + bool bAutoMap=true); // Memory map for read on open? + + ~StgIO(); + +//***************************************************************************** +// Open the base file on top of: (a) file, (b) memory buffer, or (c) stream. +// If create flag is specified, then this will create a new file with the +// name supplied. No data is read from an opened file. You must call +// MapFileToMem before doing direct pointer access to the contents. +//***************************************************************************** + HRESULT Open( // Return code. + LPCWSTR szName, // Name of the storage. + int fFlags, // How to open the file. + const void *pbBuff, // Optional buffer for memory. + ULONG cbBuff, // Size of buffer. + IStream *pIStream, // Stream for input. + LPSECURITY_ATTRIBUTES pAttributes); // Security token. + +//***************************************************************************** +// Shut down the file handles and allocated objects. +//***************************************************************************** + void Close(); + +//***************************************************************************** +// Read data from the storage source. This will handle all types of backing +// storage from mmf, streams, and file handles. No read ahead or MRU +// caching is done. +//***************************************************************************** + HRESULT Read( // Return code. + void *pbBuff, // Write buffer here. + ULONG cbBuff, // How much to read. + ULONG *pcbRead); // How much read. + +//***************************************************************************** +// Write to disk. This function will cache up to a page of data in a buffer +// and peridocially flush it on overflow and explicit request. This makes it +// safe to do lots of small writes without too much performance overhead. +//***************************************************************************** + HRESULT Write( // Return code. + const void *pbBuff, // Buffer to write. + ULONG cbWrite, // How much. + ULONG *pcbWritten); // Return how much written. + +//***************************************************************************** +// Moves the file pointer to the new location. This handles the different +// types of storage systems. +//***************************************************************************** + HRESULT Seek( // New offset. + int lVal, // How much to move. + ULONG fMoveType); // Direction, use Win32 FILE_xxxx. + +//***************************************************************************** +// Retrieves the current offset for the storage being used. This value is +// tracked based on Read, Write, and Seek operations. +//***************************************************************************** + ULONG GetCurrentOffset(); // Current offset. + +//***************************************************************************** +// Map the file contents to a memory mapped file and return a pointer to the +// data. For read/write with a backing store, map the file using an internal +// paging system. +//***************************************************************************** + HRESULT MapFileToMem( // Return code. + void *&ptr, // Return pointer to file data. + ULONG *pcbSize, // Return size of data. + LPSECURITY_ATTRIBUTES pAttributes=0); // Security token. + +//***************************************************************************** +// Free the mapping object for shared memory but keep the rest of the internal +// state intact. +//***************************************************************************** + HRESULT ReleaseMappingObject(); // Return code. + +//***************************************************************************** +// Resets the logical base address and size to the value given. This is for +// cases like finding a section embedded in another format, like the .clb inside +// of an image. GetPtrForMem, Read, and Seek will then behave as though only +// data from pbStart to cbSize is valid. +//***************************************************************************** + HRESULT SetBaseRange( // Return code. + void *pbStart, // Start of file data. + ULONG cbSize); // How big is the range. + +//***************************************************************************** +// For read/write case, get a pointer to a chunk of the file at cbStart for +// size cbSize. Return the pointer. This will page in parts of the file from +// disk if not already loaded. +//***************************************************************************** + HRESULT GetPtrForMem( // Return code. + ULONG cbStart, // Offset from beginning to load. + ULONG cbSize, // How much, rounded to page. + void *&ptr); // Return pointer on success. + +//***************************************************************************** +// For cached writes, flush the cache to the data store. +//***************************************************************************** + HRESULT FlushCache(); + +//***************************************************************************** +// Tells the file system to flush any cached data it may have. This is +// expensive, but if successful guarantees you won't lose writes short of +// a disk failure. +//***************************************************************************** + HRESULT FlushFileBuffers(); + +//***************************************************************************** +// Called after a successful rewrite of an existing file. The in memory +// backing store is no longer valid because all new data is in memory and +// on disk. This is essentially the same state as created, so free up some +// working set and remember this state. +//***************************************************************************** + HRESULT ResetBackingStore(); // Return code. + + FILETYPE GetFileType() + { return m_FileType; } + + int IsReadOnly() + { return ((m_fFlags & STGIO_WRITE) == 0); } + + ULONG GetFlags() + { return (m_fFlags); } + + ULONG SetFlags(ULONG fFlags) + { m_fFlags = fFlags; + return (m_fFlags); } + + ULONG GetDataSize() + { return (m_cbData); } + + LONG AddRef() + { + return (++m_cRef); + } + + LONG Release() + { + LONG cRef = --m_cRef; + if (cRef == 0) + delete this; + return (cRef); + } + + int IsAlignedPtr(ULONG_PTR Value, int iAlignment); + MAPPINGTYPE GetMemoryMappedType() + { return m_mtMappedType;} + + +//***************************************************************************** +// Called to read the data into allocated memory and release the backing store. +// Only available on read-only data. +//***************************************************************************** + HRESULT LoadFileToMemory(); + + +private: + int IsBackingStore() + { return (m_rgPageMap != 0); } + int IsMemoryMapped() + { return ((m_hMapping != NULL) || (m_hModule != NULL)); } + + void CtorInit(); + HRESULT WriteToDisk(const void *pbBuff, ULONG cbWrite, ULONG *pcbWritten); + HRESULT ReadFromDisk(void *pbBuff, ULONG cbBuff, ULONG *pcbRead); + HRESULT CopyFileInternal(LPCWSTR szTo, int bFailIfThere, int bWriteThrough); + void FreePageMap(); + +private: + + // Flags and state data. + FILETYPE m_FileType; // Cached type of the file (based on extension). + LONG m_cRef; // Ref count on this object. + bool m_bWriteThrough : 1; // true for write through mode. + bool m_bRewrite : 1; // State check for rewrite mode. + bool m_bAutoMap : 1; // true to automatically memory map file. + bool m_bFreeMem : 1; // true to free allocated memory. + + // Handles. + IStream * m_pIStream; // For save to stream instead of file. + HANDLE m_hFile; // The actual file with contents. + HANDLE m_hMapping; // Mapping handle. + HMODULE m_hModule; // If we load with LoadLibrary, this is the module (otherwise NULL). + void * m_pBaseData; // Base address for memory mapped file. + void * m_pData; // For memory mapped file read. + ULONG m_cbData; // Size of in memory data. + int m_fFlags; // Flags for open/create mode. + STGIOTYPE m_iType; // Where is the data. + MAPPINGTYPE m_mtMappedType; // How the file was memory mapped + + // File cache information. + BYTE * m_rgBuff; // Cache buffer for writing. + ULONG m_cbBuff; // Current cache size. + ULONG m_cbOffset; // Current offset in file. + + // Buffer read management. + static int m_iPageSize; // Size of an OS page. + static int m_iCacheSize; // How big a write back cache to use. + BYTE * m_rgPageMap; // Track loaded pages on read/write. + +}; // class StgIO + +#endif // __STGIO_H_ diff --git a/src/md/inc/stgtiggerstorage.h b/src/md/inc/stgtiggerstorage.h new file mode 100644 index 0000000000..42407bab9f --- /dev/null +++ b/src/md/inc/stgtiggerstorage.h @@ -0,0 +1,328 @@ +// 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. +//***************************************************************************** +// StgTiggerStorage.h +// + +// +// TiggerStorage is a stripped down version of compound doc files. Doc files +// have some very useful and complex features to them, unfortunately nothing +// comes for free. Given the incredibly tuned format of existing .tlb files, +// every single byte counts and 10% added by doc files is just too exspensive. +// +// The storage itself is made up of a bunch of streams (each aligned to a 4 byte +// value), followed at the end of the file with the header. The header is +// put at the end so that you can continue to write as many streams as you +// like without thrashing the disk. +// +-------------------+ +// | Signature | +// +-------------------+ +// | Stream 1, 2, [] | +// +-------------------+ +// | STORAGEHEADER | +// | Extra data | +// | STORAGESTREAM[] | +// +-------------------+ +// | offset | +// +-------------------+ +// +// The STORAGEHEADER contains flags describing the rest of the file, including +// the ability to have extra data stored in the header. If there is extra +// data, then immediately after the STORAGEHEADER struct is a 4 byte size of +// that data, followed immediately by the extra data. The length must be +// 4 byte aligned so that the first STORAGESTREAM starts on an aligned +// boundary. The contents of the extra data is caller defined. +// +// This code handles the signature at the start of the file, and the list of +// streams at the end (kept in the header). The data in each stream is, of +// course, caller specific. +// +// This code requires the StgIO code to handle the input and output from the +// backing storage, whatever scheme that may be. There are no consistency +// checks on the data (for example crc's) due to the expense in computation +// required. There is a signature at the front of the file and in the header. +// +//***************************************************************************** +#ifndef __StgTiggerStorage_h__ +#define __StgTiggerStorage_h__ + +//#include "utilcode.h" // Helpers. + +#include "mdfileformat.h" + +typedef CDynArray<STORAGESTREAM> STORAGESTREAMLST; + + +// Forwards. +class TiggerStream; +class StgIO; + + + +class TiggerStorage : + public IStorage +{ +friend class TiggerStream; +public: + TiggerStorage(); + virtual ~TiggerStorage(); + +// IUnknown so you can ref count this thing. + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *pp) + { return (BadError(E_NOTIMPL)); } + virtual ULONG STDMETHODCALLTYPE AddRef() + { return (InterlockedIncrement(&m_cRef)); } + virtual ULONG STDMETHODCALLTYPE Release() + { + SUPPORTS_DAC_HOST_ONLY; + ULONG cRef; + if ((cRef = InterlockedDecrement(&m_cRef)) == 0) + delete this; + return (cRef); + } + + +//***************************************************************************** +// Init this storage object on top of the given storage unit. +//***************************************************************************** + HRESULT Init( // Return code. + StgIO *pStgIO, // The I/O subsystem. + __in __in_z LPSTR pVersion); // Compiler-supplied CLR version + +//***************************************************************************** +// Retrieves a the size and a pointer to the extra data that can optionally be +// written in the header of the storage system. This data is not required to +// be in the file, in which case *pcbExtra will come back as 0 and pbData will +// be set to null. You must have initialized the storage using Init() before +// calling this function. +//***************************************************************************** + HRESULT GetExtraData( // Return code. + ULONG *pcbExtra, // Return size of extra data. + BYTE *&pbData); // Return a pointer to extra data. + +//***************************************************************************** +// Flushes the header to disk. +//***************************************************************************** + HRESULT WriteHeader( // Return code. + STORAGESTREAMLST *pList, // List of streams. + ULONG cbExtraData, // Size of extra data, may be 0. + BYTE *pbExtraData); // Pointer to extra data for header. + +//***************************************************************************** +// Called when all data has been written. Forces cached data to be flushed +// and stream lists to be validated. +//***************************************************************************** + HRESULT WriteFinished( // Return code. + STORAGESTREAMLST *pList, // List of streams. + ULONG *pcbSaveSize, // Return size of total data. + BOOL fDeltaSave); // Was this a delta + +//***************************************************************************** +// Called after a successful rewrite of an existing file. The in memory +// backing store is no longer valid because all new data is in memory and +// on disk. This is essentially the same state as created, so free up some +// working set and remember this state. +//***************************************************************************** + HRESULT ResetBackingStore(); // Return code. + +//***************************************************************************** +// Called to restore the original file. If this operation is successful, then +// the backup file is deleted as requested. The restore of the file is done +// in write through mode to the disk help ensure the contents are not lost. +// This is not good enough to fulfill ACID props, but it ain't that bad. +//***************************************************************************** + HRESULT Restore( // Return code. + __in __in_z LPWSTR szBackup, // If non-0, backup the file. + int bDeleteOnSuccess); // Delete backup file if successful. + +//***************************************************************************** +// Given the name of a stream that will be persisted into a stream in this +// storage type, figure out how big that stream would be including the user's +// stream data and the header overhead the file format incurs. The name is +// stored in ANSI and the header struct is aligned to 4 bytes. +//***************************************************************************** + static HRESULT GetStreamSaveSize( // Return code. + LPCWSTR szStreamName, // Name of stream. + UINT32 cbDataSize, // Size of data to go into stream. + UINT32 *pcbSaveSize); // Return data size plus stream overhead. + +//***************************************************************************** +// Return the fixed size overhead for the storage implementation. This includes +// the signature and fixed header overhead. The overhead in the header for each +// stream is calculated as part of GetStreamSaveSize because these structs are +// variable sized on the name. +//***************************************************************************** + static HRESULT GetStorageSaveSize( // Return code. + ULONG *pcbSaveSize, // [in] current size, [out] plus overhead. + ULONG cbExtra, // How much extra data to store in header. + LPCSTR pRuntimeVersion); // The version string as it's length is part of the total size. + +//***************************************************************************** +// Adjust the offset in each known stream to match where it will wind up after +// a save operation. +//***************************************************************************** + static HRESULT CalcOffsets( // Return code. + STORAGESTREAMLST *pStreamList, // List of streams for header. + ULONG cbExtra, // Size of variable extra data in header. + LPCSTR pRuntimeVersion); // The version string as it's length is part of the total size. + + + +//***************************************************************************** +// Returns the size of the signature plus the verion information +//***************************************************************************** + static HRESULT SizeOfStorageSignature( + LPCSTR pRuntimeVersion, // The version string as it's length is part of the total size. + ULONG *pcbSignatureSize); + +// IStorage + virtual HRESULT STDMETHODCALLTYPE CreateStream( + const OLECHAR *pwcsName, + DWORD grfMode, + DWORD reserved1, + DWORD reserved2, + IStream **ppstm); + + virtual HRESULT STDMETHODCALLTYPE CreateStream( + LPCSTR szName, + DWORD grfMode, + DWORD reserved1, + DWORD reserved2, + IStream **ppstm) + DAC_UNEXPECTED(); + + virtual HRESULT STDMETHODCALLTYPE OpenStream( + const OLECHAR *pwcsName, + void *reserved1, + DWORD grfMode, + DWORD reserved2, + IStream **ppstm); + + virtual HRESULT STDMETHODCALLTYPE CreateStorage( + const OLECHAR *pwcsName, + DWORD grfMode, + DWORD dwStgFmt, + DWORD reserved2, + IStorage **ppstg); + + virtual HRESULT STDMETHODCALLTYPE OpenStorage( + const OLECHAR * wcsName, + IStorage * pStgPriority, + DWORD dwMode, + __in + SNB snbExclude, + DWORD reserved, + IStorage ** ppStg); + + virtual HRESULT STDMETHODCALLTYPE CopyTo( + DWORD cIidExclude, + const IID * rgIidExclude, + __in + SNB snbExclude, + IStorage * pStgDest); + + virtual HRESULT STDMETHODCALLTYPE MoveElementTo( + const OLECHAR *pwcsName, + IStorage *pstgDest, + const OLECHAR *pwcsNewName, + DWORD grfFlags); + + virtual HRESULT STDMETHODCALLTYPE Commit( + DWORD grfCommitFlags); + + virtual HRESULT STDMETHODCALLTYPE Revert(); + + virtual HRESULT STDMETHODCALLTYPE EnumElements( + DWORD reserved1, + void *reserved2, + DWORD reserved3, + IEnumSTATSTG **ppenum); + + virtual HRESULT STDMETHODCALLTYPE DestroyElement( + const OLECHAR *pwcsName); + + virtual HRESULT STDMETHODCALLTYPE RenameElement( + const OLECHAR *pwcsOldName, + const OLECHAR *pwcsNewName); + + virtual HRESULT STDMETHODCALLTYPE SetElementTimes( + const OLECHAR *pwcsName, + const FILETIME *pctime, + const FILETIME *patime, + const FILETIME *pmtime); + + virtual HRESULT STDMETHODCALLTYPE SetClass( + REFCLSID clsid); + + virtual HRESULT STDMETHODCALLTYPE SetStateBits( + DWORD grfStateBits, + DWORD grfMask); + + virtual HRESULT STDMETHODCALLTYPE Stat( + STATSTG *pstatstg, + DWORD grfStatFlag); + + virtual HRESULT STDMETHODCALLTYPE OpenStream( + LPCWSTR szStream, + ULONG *pcbData, + void **ppAddress); + + // Access storage object. + StgIO *GetStgIO() + { return (m_pStgIO); } + +#if defined(_DEBUG) + ULONG PrintSizeInfo( // Size of streams. + bool verbose); // Be verbose? +#endif + +protected: + HRESULT Write( // Return code. + LPCSTR szName, // Name of stream we're writing. + const void *pData, // Data to write. + ULONG cbData, // Size of data. + ULONG *pcbWritten); // How much did we write. + +private: + HRESULT FindStream(LPCSTR szName, __out PSTORAGESTREAM *stream); + HRESULT WriteSignature(LPCSTR pVersion); + HRESULT VerifySignature(PSTORAGESIGNATURE pSig); + HRESULT ReadHeader(); + HRESULT VerifyHeader(); + + static HRESULT GetDefaultVersion(LPCSTR* ppVersion); + +public: + // This function is a workaround to allow access to the "version requested" string. + HRESULT GetHeaderPointer(const void **ppv, ULONG *pcb); + +private: + // State data. + StgIO *m_pStgIO; // Storage subsystem. + LONG m_cRef; // Ref count for COM. + + // Header data. + STORAGEHEADER m_StgHdr; // Header for storage. + STORAGESTREAMLST m_Streams; // List of streams in the storage. + PSTORAGESTREAM m_pStreamList; // For read mode. + void *m_pbExtra; // Pointer to extra data if on disk. +}; + + +//***************************************************************************** +// Debugging helpers. #define __SAVESIZE_TRACE__ to enable. +//***************************************************************************** + +// #define __SAVESIZE_TRACE__ +#ifdef __SAVESIZE_TRACE__ +#define SAVETRACE(func) DEBUG_STMT(func) +#else +#define SAVETRACE(func) +#endif // __SAVESIZE_TRACE__ + +#endif // StgTiggerStorage + + + +// EOF diff --git a/src/md/inc/stgtiggerstream.h b/src/md/inc/stgtiggerstream.h new file mode 100644 index 0000000000..51a2f967de --- /dev/null +++ b/src/md/inc/stgtiggerstream.h @@ -0,0 +1,112 @@ +// 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. +//***************************************************************************** +// StgTiggerStream.h +// + +// +// TiggerStream is the companion to the TiggerStorage CoClass. It handles the +// streams managed inside of the storage and does the direct file i/o. +// +//***************************************************************************** +#ifndef __StgTiggerStream_h__ +#define __StgTiggerStream_h__ + + + +#include "stgtiggerstorage.h" // Data definitions. + +enum +{ + STREAM_DATA_NAME +}; + + +class TiggerStorage; + + +class TiggerStream : + public IStream +{ +public: + TiggerStream() : + m_pStorage(0), + m_cRef(1) + {} + + virtual ~TiggerStream() {} + + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *pp) + { return (BadError(E_NOTIMPL)); } + virtual ULONG STDMETHODCALLTYPE AddRef() + { return InterlockedIncrement(&m_cRef); } + virtual ULONG STDMETHODCALLTYPE Release() + { + ULONG cRef; + if ((cRef = InterlockedDecrement(&m_cRef)) == 0) + delete this; + return (cRef); + } + +// IStream + virtual HRESULT STDMETHODCALLTYPE Read( + void *pv, + ULONG cb, + ULONG *pcbRead); + + virtual HRESULT STDMETHODCALLTYPE Write( + const void *pv, + ULONG cb, + ULONG *pcbWritten); + + virtual HRESULT STDMETHODCALLTYPE Seek( + LARGE_INTEGER dlibMove, + DWORD dwOrigin, + ULARGE_INTEGER *plibNewPosition); + + virtual HRESULT STDMETHODCALLTYPE SetSize( + ULARGE_INTEGER libNewSize); + + virtual HRESULT STDMETHODCALLTYPE CopyTo( + IStream *pstm, + ULARGE_INTEGER cb, + ULARGE_INTEGER *pcbRead, + ULARGE_INTEGER *pcbWritten); + + virtual HRESULT STDMETHODCALLTYPE Commit( + DWORD grfCommitFlags); + + virtual HRESULT STDMETHODCALLTYPE Revert( void); + + virtual HRESULT STDMETHODCALLTYPE LockRegion( + ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, + DWORD dwLockType); + + virtual HRESULT STDMETHODCALLTYPE UnlockRegion( + ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, + DWORD dwLockType); + + virtual HRESULT STDMETHODCALLTYPE Stat( + STATSTG *pstatstg, + DWORD grfStatFlag); + + virtual HRESULT STDMETHODCALLTYPE Clone( + IStream **ppstm); + + + HRESULT Init( // Return code. + TiggerStorage *pStorage, // Parent storage. + LPCSTR szStream); // Stream name. + + ULONG GetStreamSize(); + +private: + TiggerStorage *m_pStorage; // Our parent storage. + char m_rcStream[MAXSTREAMNAME]; // Name of the stream. + LONG m_cRef; // Ref count. +}; + +#endif // __StgTiggerStream_h__ diff --git a/src/md/inc/streamutil.h b/src/md/inc/streamutil.h new file mode 100644 index 0000000000..89c493476f --- /dev/null +++ b/src/md/inc/streamutil.h @@ -0,0 +1,221 @@ +// 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. + +// + +#if !defined( __STREAMUTIL_H__ ) +#define __STREAMUTIL_H__ + +namespace StreamUtil +{ + +// Write data to stream and advance the totalBytes counter +// +inline +HRESULT WriteToStream( IStream * strm, void const * data, UINT32 sizeInBytes, UINT32 * totalBytes = NULL ) +{ + HRESULT hr = strm->Write( data, sizeInBytes, NULL ); + if ( SUCCEEDED( hr ) && totalBytes != NULL ) + *totalBytes += sizeInBytes; + return hr; +} + + +// Write a POD to stream +// +template < typename T > +HRESULT WritePODToStream( IStream * strm, T val, UINT32 * totalBytes ) +{ + return WriteToStream( strm, & val, sizeof( val ), totalBytes ); +} + + +// Write concrete data types to stream +// Add additional overloads as needed +// + +inline +HRESULT WriteToStream( IStream * strm, int val, UINT32 * totalBytes = NULL ) +{ + return WritePODToStream( strm, val, totalBytes ); +} + + +inline +HRESULT WriteToStream( IStream * strm, DWORD val, UINT32 * totalBytes = NULL ) +{ + return WritePODToStream( strm, val, totalBytes ); +} + + +inline +HRESULT WriteToStream( IStream * strm, WORD val, UINT32 * totalBytes = NULL ) +{ + return WritePODToStream( strm, val, totalBytes ); +} + + +inline +HRESULT WriteToStream( IStream * strm, BYTE val, UINT32 * totalBytes = NULL ) +{ + return WritePODToStream( strm, val, totalBytes ); +} + + +// Align to DWORD boundary +// +inline +HRESULT AlignDWORD( IStream * strm, UINT32 * totalBytes ) +{ + HRESULT hr = S_OK; + + UINT32 aligned = *totalBytes + 3 & ~3; + if (aligned > *totalBytes) + { // The *totalBytes were not aligned to DWORD, we need to add padding + DWORD data = 0; + hr = WriteToStream( strm, & data, aligned - *totalBytes, totalBytes ); + } + else if (aligned < *totalBytes) + { // We got an integer overflow in 'aligned' expression above + hr = COR_E_OVERFLOW; + } + + return hr; +} + + +// Get stream position +// +inline +HRESULT GetPos( IStream * strm, UINT32 * pos ) +{ + LARGE_INTEGER temp = { {0} }; + ULARGE_INTEGER ul_pos = { {0} }; + HRESULT hr = strm->Seek( temp, STREAM_SEEK_CUR, & ul_pos ); + * pos = ul_pos.u.LowPart; + return hr; +} + + +class NullStream : public IStream +{ +public: + NullStream() + : m_pos( 0 ) + {} + + ULONG STDMETHODCALLTYPE AddRef() + { + _ASSERTE( false ); + return 0; + } + + ULONG STDMETHODCALLTYPE Release() + { + SUPPORTS_DAC_HOST_ONLY; + _ASSERTE( false ); + return 0; + } + + HRESULT STDMETHODCALLTYPE QueryInterface( REFIID, PVOID* ) + { + _ASSERTE( false ); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead) + { + _ASSERTE( false ); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE Write(const void *pv, ULONG cb, ULONG *pcbWritten) + { + m_pos += cb; + if (pcbWritten != NULL) + { + *pcbWritten = cb; + } + return S_OK; + } + + HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove,DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) + { + if ( dwOrigin != STREAM_SEEK_CUR || dlibMove.QuadPart != 0 || plibNewPosition == NULL ) + return E_NOTIMPL; + + plibNewPosition->u.HighPart = 0; + plibNewPosition->u.LowPart = m_pos; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize) + { + _ASSERTE( false ); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE CopyTo( + IStream *pstm, + ULARGE_INTEGER cb, + ULARGE_INTEGER *pcbRead, + ULARGE_INTEGER *pcbWritten) + { + _ASSERTE( false ); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE Commit( + DWORD grfCommitFlags) + { + _ASSERTE( false ); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE Revert() + { + _ASSERTE( false ); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE LockRegion( + ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, + DWORD dwLockType) + { + _ASSERTE( false ); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE UnlockRegion( + ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, + DWORD dwLockType) + { + _ASSERTE( false ); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE Stat( + STATSTG *pstatstg, + DWORD grfStatFlag) + { + _ASSERTE( false ); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE Clone( + IStream **ppstm) + { + _ASSERTE( false ); + return E_NOTIMPL; + } + +private: + UINT32 m_pos; +}; // class NullStream + +}; // namespace StreamUtil + +#endif diff --git a/src/md/inc/verifylayouts.h b/src/md/inc/verifylayouts.h new file mode 100644 index 0000000000..035b52d3ec --- /dev/null +++ b/src/md/inc/verifylayouts.h @@ -0,0 +1,186 @@ +// 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. +//***************************************************************************** +// VerifyLayouts.h +// + +// +// Make sure that layouts of MD data strucutres doesn't change accidentally +// +//***************************************************************************** + +// The code in MD\DataSource\TargetTypes.* takes a direct dependency on +// the layouts of types in MD. This is used by the debugger to read metadata +// from a seperate process by deserializing the memory for these datastructures. +// +// You are probably reading this comment because you changed a layout and +// one of the static_asserts failed during build. This is what you should +// do to fix it: +// +// a) Go to clr\src\Debug\EE\Debugger.cpp and increment the global version counter +// m_mdDataStructureVersion set in Debugger::Debugger() +// Please comment the change there with a new entry in the version table +// +// b) If a define is conditionally changing the layout: +// i) add, if needed, an entry to the list of define bits in +// clr\src\Debug\EE\debugger.h Debugger::_Target_Defines +// ii) add code like this that sets the bit in the Debugger::_defines static +// variable +// #ifdef MY_DEFINE +// | DEFINE_MY_DEFINE +// #endif +// +// c) Update the code in MD\DataSource\TargetTypes.h/cpp to deserialize your +// new layout correctly. The code needs to work for any version of the layouts +// with or without defines set. Your reader code can access the current version +// and defines by calling: +// reader.GetMDStructuresVersion() +// reader.IsDefined(Define_XYZ) +// +// d) If your changes affect what a debugger should be reading in order to fetch +// metadata then you probably need to change other parts of the debugger +// implementation as well. In general the debugger cares about the schema, +// TableDefs, storage signature, table records, and storage pools. +// +// e) AFTER you have fixed up the debugger stuff above, now its time to update +// layout definitions so the static asserts will quiet down. Check out +// the comments in VerifyLayouts.inc for how to do that. +// +// Thanks for helping us keep the debugger working :) +// + + + + +//------------------------------------------------------------------------------- +// Type layout verification +// +// +// These macros includes VerifyLayouts.inc a few times with different definitions to build up +// the source. The final result should look something like this: +// (don't assume specific type names/fields/offsets/sizes are accurate in this example) +// +// +// class VerifyLayoutsMD +// { +// +// static const expected_offset_of_first_field_in_CMiniMdRW = 208; +// static const actual_offset_of_first_field_in_CMiniMdRW = +// 208; +// static const offset_of_field_after_CMiniMdRW_m_Schema = +// 312; +// static const offset_of_field_after_CMiniMdRW_m_Tables = +// 316; +// ... many more lines like this covering all fields in all marked up types ... +// +// +// static const alignment_of_first_field_in_CMiniMdRW = +// 4; +// static const alignment_of_field_after_CMiniMdRW_m_Schema = +// 8; +// static const alignment_of_field_after_CMiniMdRW_m_Tables = +// 8; +// ... many more lines like this cover all fields in all marked up types ... +// +// +// static_assert_no_msg(expected_offset_of_first_field_in_CMiniMdRW == actual_offset_of_first_field_in_CMiniMdRW); +// static_assert_no_msg(offset_of_field_after_CMiniMdRW_m_Schema == +// ALIGN_UP(offsetof(CMiniMdRW, m_Schema) + 104, alignment_of_field_after_CMiniMdRW_m_Schema)); +// static_assert_no_msg(offset_of_field_after_CMiniMdRW_m_Tables == +// ALIGN_UP(offsetof(CMiniMdRW, m_Tables) + 4, alignment_of_field_after_CMiniMdRW_m_Tables)); +// ... many more lines like this cover all fields in all marked up types ... +// +// }; +// +// +// +// + +#ifdef FEATURE_METADATA_VERIFY_LAYOUTS + +#include <stddef.h> // offsetof +#include "static_assert.h" +#include "metamodel.h" +#include "WinMDInterfaces.h" +#include "MDInternalRW.h" + +// other types provide friend access to this type so that the +// offsetof macro can access their private fields +class VerifyLayoutsMD +{ + // we have a bunch of arrays with this fixed size, make sure it doesn't change + static_assert_no_msg(TBL_COUNT == 45); + + + +#define IGNORE_COMMAS(...) __VA_ARGS__ // use this to surround templated types with commas in the name + +#define BEGIN_TYPE(typeName, initialFieldOffset) BEGIN_TYPE_ESCAPED(typeName, typeName, initialFieldOffset) +#define FIELD(typeName, fieldName, fieldSize) ALIGN_FIELD_ESCAPED(typeName, typeName, fieldName, fieldSize, fieldSize) +#define ALIGN_FIELD(typeName, fieldName, fieldSize, fieldAlign) ALIGN_FIELD_ESCAPED(typeName, typeName, fieldName, fieldSize, fieldAlign) +#define FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize) ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldSize) +#define END_TYPE(typeName, typeAlign) END_TYPE_ESCAPED(typeName, typeName, typeAlign) + +#define BEGIN_TYPE_ESCAPED(typeName, typeNameEscaped, initialFieldOffset) \ + static const expected_offset_of_first_field_in_##typeNameEscaped## = initialFieldOffset; \ + static const actual_offset_of_first_field_in_##typeNameEscaped## = + +#define ALIGN_FIELD_ESCAPED(typeName, typeNameEscaped, fieldName, fieldSize, fieldAlign) \ + offsetof(IGNORE_COMMAS(typeName), fieldName); \ + static const offset_of_field_after_##typeNameEscaped##_##fieldName = + +#define BITFIELD(typeName, fieldName, fieldOffset, fieldSize) \ + fieldOffset; \ + static const offset_of_field_after_##typeName##_##fieldName = + +#define END_TYPE_ESCAPED(typeName, typeNameEscaped, typeAlignentSize) \ + sizeof(typeName); + +#include "VerifyLayouts.inc" + +#undef BEGIN_TYPE_ESCAPED +#undef ALIGN_FIELD_ESCAPED +#undef END_TYPE_ESCAPED +#undef BITFIELD + +#define BEGIN_TYPE_ESCAPED(typeName, escapedTypeName, initialFieldOffset) \ + static const alignment_of_first_field_in_##escapedTypeName = +#define ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldAlign) \ + fieldAlign; \ + static const alignment_of_field_after_##escapedTypeName##_##fieldName = +#define BITFIELD(typeName, fieldName, fieldOffset, fieldSize) \ + fieldSize; \ + static const alignment_of_field_after_##typeName##_##fieldName = +#define END_TYPE_ESCAPED(typeName, escapedTypeName, typeAlignmentSize) \ + typeAlignmentSize; + +#include "VerifyLayouts.inc" + +#undef BEGIN_TYPE_ESCAPED +#undef ALIGN_FIELD_ESCAPED +#undef END_TYPE_ESCAPED +#undef BITFIELD + + +#define BEGIN_TYPE_ESCAPED(typeName, escapedTypeName, initialFieldOffset) \ + static_assert_no_msg(expected_offset_of_first_field_in_##escapedTypeName == actual_offset_of_first_field_in_##escapedTypeName); + + +#define ALIGN_UP(value, alignment) (((value) + (alignment) - 1)&~((alignment) - 1)) +#define ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldAlign) \ + static_assert_no_msg(offset_of_field_after_##escapedTypeName##_##fieldName == \ + ALIGN_UP(offsetof(IGNORE_COMMAS(typeName), fieldName) + fieldSize, alignment_of_field_after_##escapedTypeName##_##fieldName)); +#define BITFIELD(typeName, fieldName, fieldOffset, fieldSize) \ + static_assert_no_msg(offset_of_field_after_##typeName##_##fieldName == \ + ALIGN_UP(fieldOffset + fieldSize, alignment_of_field_after_##typeName##_##fieldName)); + +#define END_TYPE_ESCAPED(typeName, escapedTypeName, typeAlignmentSize) +#include "VerifyLayouts.inc" + +}; + + + + +#endif //FEATURE_METADATA_VERIFY_LAYOUTS diff --git a/src/md/inc/winmdinterfaces.h b/src/md/inc/winmdinterfaces.h new file mode 100644 index 0000000000..4233e615d3 --- /dev/null +++ b/src/md/inc/winmdinterfaces.h @@ -0,0 +1,120 @@ +// 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. + +// +// ======================================================================================================= +// Defines the surface area between md\WinMD and md\everything-else. +// +// md\WinMD contains adapter importers that wrap RegMeta and MDInternalRO to make .winmd files look like +// regular .NET assemblies. +// ======================================================================================================= + +#ifndef __WINMDINTERFACES_H__ +#define __WINMDINTERFACES_H__ + +#include "metamodel.h" + + +//----------------------------------------------------------------------------------------------------- +// A common interface unifying RegMeta and MDInternalRO, giving the adapter a common interface to +// access the raw metadata. +//----------------------------------------------------------------------------------------------------- + +// {4F8EE8A3-24F8-4241-BC75-C8CAEC0255B5} +EXTERN_GUID(IID_IMDCommon, 0x4f8ee8a3, 0x24f8, 0x4241, 0xbc, 0x75, 0xc8, 0xca, 0xec, 0x2, 0x55, 0xb5); + +#undef INTERFACE +#define INTERFACE IID_IMDCommon +DECLARE_INTERFACE_(IMDCommon, IUnknown) +{ + STDMETHOD_(IMetaModelCommon*, GetMetaModelCommon)() PURE; + STDMETHOD_(IMetaModelCommonRO*, GetMetaModelCommonRO)() PURE; + STDMETHOD(GetVersionString)(LPCSTR *pszVersionString) PURE; +}; + + +//----------------------------------------------------------------------------------------------------- +// Returns: +// S_OK: if WinMD adapter should be used. +// S_FALSE: if not +//----------------------------------------------------------------------------------------------------- +HRESULT CheckIfWinMDAdapterNeeded(IMDCommon *pRawMDCommon); + + + +//----------------------------------------------------------------------------------------------------- +// Factory method that creates an WinMD adapter that implements: +// +// IMetaDataImport2 +// IMetaDataAssemblyImport +// IMetaDataValidate +// IMarshal +// IMDCommon (subset) +// +// IMDCommon is included as a concession to the fact that certain IMetaDataEmit apis have +// an (apparently undocumented) dependency on their importer arguments supporting this. +// +// You must provide a regular MD importer that implements: +// +// IMDCommon +// IMetaDataImport2 +// IMetaDataAssemblyImport +// IMetaDataValidate +// +// The underlying metadata file must follow these restrictions: +// +// - Have an existing assemblyRef to "mscorlib" +// +//----------------------------------------------------------------------------------------------------- +HRESULT CreateWinMDImport(IMDCommon * pRawMDCommon, REFIID riid, /*[out]*/ void **ppWinMDImport); + + +//----------------------------------------------------------------------------------------------------- +// Factory method that creates an WinMD adapter that implements IMDInternalImport. +// You must provide a regular MD importer that implements: +// +// IMDCommon +// IMDInternalImport +// +// The underlying metadata file must follow these restrictions: +// +// - Have an existing assemblyRef to "mscorlib" +// +//----------------------------------------------------------------------------------------------------- +#ifdef FEATURE_METADATA_INTERNAL_APIS +HRESULT CreateWinMDInternalImportRO(IMDCommon * pRawMDCommon, REFIID riid, /*[out]*/ void **ppWinMDInternalImport); + +#endif // FEATURE_METADATA_INTERNAL_APIS +//----------------------------------------------------------------------------------------------------- +// S_OK if pUnknown is really a WinMD wrapper. This is just a polite way of asking "is it bad to +// to static cast pUnknown to RegMeta/MDInternalRO." +//----------------------------------------------------------------------------------------------------- +HRESULT CheckIfImportingWinMD(IUnknown *pUnknown); + + +//----------------------------------------------------------------------------------------------------- +// E_NOTIMPL if pUnknown is really a WinMD wrapper. +//----------------------------------------------------------------------------------------------------- +HRESULT VerifyNotWinMDHelper(IUnknown *pUnknown +#ifdef _DEBUG + ,LPCSTR assertMsg + ,LPCSTR file + ,int line +#endif //_DEBUG + ); +#if defined(FEATURE_METADATA_IN_VM) && !defined(FEATURE_CORECLR) +#ifdef _DEBUG +#define VerifyNotWinMD(pUnknown, assertMsg) VerifyNotWinMDHelper(pUnknown, assertMsg, __FILE__, __LINE__) +#else +#define VerifyNotWinMD(pUnknown, assertMsg) VerifyNotWinMDHelper(pUnknown) +#endif +#else +#define VerifyNotWinMD(pUnknown, assertMsg) S_OK +#endif // FEATURE_METADATA_IN_VM + + +#endif //__WINMDINTERFACES_H__ + + + |