/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Diagnostics; using System.Runtime.InteropServices; using dnlib.DotNet; using dnlib.DotNet.MD; namespace dnSpy.Debugger.DotNet.Metadata.Impl.COMD { static class MDAPI { const int CLDB_E_RECORD_NOTFOUND = unchecked((int)0x80131130); const int CLDB_E_INDEX_NOTFOUND = unchecked((int)0x80131124); static bool IsGlobal(IMetaDataImport2 mdi, uint token) { if (mdi is null) return false; int hr = mdi.IsGlobal(token, out int bGlobal); return hr == 0 && bGlobal != 0; } public static bool IsValidToken(IMetaDataImport2 mdi, uint token) { if (mdi is null) return false; return mdi.IsValidToken(token); } public unsafe static bool GetClassLayout(IMetaDataImport2 mdi, uint token, out ushort packingSize, out uint classSize) { packingSize = 0; classSize = 0; if (mdi is null) return false; uint dwPackSize = 0, ulClassSize = 0; int hr = mdi.GetClassLayout(token, new IntPtr(&dwPackSize), null, 0, IntPtr.Zero, new IntPtr(&ulClassSize)); if (hr != 0) return false; packingSize = (ushort)dwPackSize; classSize = ulClassSize; return true; } public unsafe static uint? GetRVA(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; int hr = mdi.GetRVA(token, out uint ulCodeRVA, IntPtr.Zero); if (hr != 0) return null; return ulCodeRVA; } public unsafe static uint[] GetPermissionSetTokens(IMetaDataImport2 mdi, uint token) { if (mdi is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi.EnumPermissionSets(ref iter, token, 0, IntPtr.Zero, 0, out uint cTokens); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi.CountEnum(iter, ref ulCount); if (hr < 0 || ulCount == 0) return Array.Empty(); hr = mdi.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); var tokens = new uint[ulCount]; fixed (uint* p = &tokens[0]) hr = mdi.EnumPermissionSets(ref iter, token, 0, new IntPtr(p), (uint)tokens.Length, out cTokens); if (hr < 0) return Array.Empty(); return tokens; } finally { if (iter != IntPtr.Zero) mdi.CloseEnum(iter); } } public unsafe static (IntPtr addr, uint size, uint action) GetPermissionSetBlob(IMetaDataImport2 mdi, uint token) { if (mdi is null) return (IntPtr.Zero, 0, 0); IntPtr pvPermission; uint cbPermission; uint dwAction; int hr = mdi.GetPermissionSetProps(token, new IntPtr(&dwAction), new IntPtr(&pvPermission), new IntPtr(&cbPermission)); if (hr != 0 || pvPermission == IntPtr.Zero) return (IntPtr.Zero, 0, 0); return (pvPermission, cbPermission, dwAction); } public unsafe static bool GetPinvokeMapProps(IMetaDataImport2 mdi, uint token, out DmdPInvokeAttributes attrs, out uint moduleToken) { attrs = 0; moduleToken = 0; if (mdi is null) return false; uint dwMappingFlags, mrImportDLL; int hr = mdi.GetPinvokeMap(token, new IntPtr(&dwMappingFlags), IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&mrImportDLL)); if (hr != 0) return false; attrs = (DmdPInvokeAttributes)dwMappingFlags; moduleToken = mrImportDLL; return true; } public unsafe static string? GetPinvokeMapName(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; char[]? nameBuf = null; uint chImportName; int hr = mdi.GetPinvokeMap(token, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chImportName), IntPtr.Zero); if (hr >= 0 && chImportName != 0) { nameBuf = new char[chImportName]; fixed (char* p = &nameBuf[0]) hr = mdi.GetPinvokeMap(token, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chImportName), IntPtr.Zero); } if (hr < 0) return null; return chImportName <= 1 ? string.Empty : new string(nameBuf!, 0, (int)chImportName - 1); } public unsafe static string? GetMemberRefName(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; char[]? nameBuf = null; uint chMember; int hr = mdi.GetMemberRefProps(token, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chMember), IntPtr.Zero, IntPtr.Zero); if (hr >= 0 && chMember != 0) { nameBuf = new char[chMember]; fixed (char* p = &nameBuf[0]) hr = mdi.GetMemberRefProps(token, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chMember), IntPtr.Zero, IntPtr.Zero); } if (hr < 0) return null; return chMember <= 1 ? string.Empty : new string(nameBuf!, 0, (int)chMember - 1); } public unsafe static uint GetMemberRefClassToken(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; uint tk; int hr = mdi.GetMemberRefProps(token, new IntPtr(&tk), IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); return hr != 0 ? 0 : tk; } public unsafe static (IntPtr addr, uint size) GetMemberRefSignatureBlob(IMetaDataImport2 mdi, uint token) { if (mdi is null) return (IntPtr.Zero, 0); IntPtr pvSigBlob; uint cbSig; int hr = mdi.GetMemberRefProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&pvSigBlob), new IntPtr(&cbSig)); if (hr != 0 || pvSigBlob == IntPtr.Zero) return (IntPtr.Zero, 0); return (pvSigBlob, cbSig); } public unsafe static uint GetMethodOwnerRid(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; if (IsGlobal(mdi, token)) return 1; uint ownerToken; int hr = mdi.GetMethodProps(token, new IntPtr(&ownerToken), IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr != 0) return 0; var ownerMdToken = new MDToken(ownerToken); return ownerMdToken.Table == Table.TypeDef ? ownerMdToken.Rid : 0; } public unsafe static uint[] GetMethodTokens(IMetaDataImport2 mdi, uint token) { if (mdi is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi.EnumMethods(ref iter, token, IntPtr.Zero, 0, out uint cTokens); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi.CountEnum(iter, ref ulCount); if (hr < 0 || ulCount == 0) return Array.Empty(); hr = mdi.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); var tokens = new uint[ulCount]; fixed (uint* p = &tokens[0]) hr = mdi.EnumMethods(ref iter, token, new IntPtr(p), (uint)tokens.Length, out cTokens); if (hr < 0) return Array.Empty(); return tokens; } finally { if (iter != IntPtr.Zero) mdi.CloseEnum(iter); } } public unsafe static (IntPtr addr, uint size) GetMethodSignatureBlob(IMetaDataImport2 mdi, uint token) { if (mdi is null) return (IntPtr.Zero, 0); uint cbSigBlob; IntPtr pvSigBlob; int hr = mdi.GetMethodProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, new IntPtr(&pvSigBlob), new IntPtr(&cbSigBlob), IntPtr.Zero, IntPtr.Zero); if (hr < 0 || pvSigBlob == IntPtr.Zero) return (IntPtr.Zero, 0); return (pvSigBlob, cbSigBlob); } public static unsafe string? GetMethodName(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; char[]? nameBuf = null; uint chMethod; int hr = mdi.GetMethodProps(token, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chMethod), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr >= 0 && chMethod != 0) { nameBuf = new char[chMethod]; fixed (char* p = &nameBuf[0]) hr = mdi.GetMethodProps(token, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chMethod), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } if (hr < 0) return null; if (chMethod <= 1) return string.Empty; return new string(nameBuf!, 0, (int)chMethod - 1); } public static unsafe bool GetMethodAttributes(IMetaDataImport2 mdi, uint token, out DmdMethodAttributes dwAttr, out DmdMethodImplAttributes dwImplFlags) { dwAttr = 0; dwImplFlags = 0; if (mdi is null) return false; uint dwAttr2, dwImplFlags2; int hr = mdi.GetMethodProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&dwAttr2), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(&dwImplFlags2)); if (hr < 0) return false; dwAttr = (DmdMethodAttributes)dwAttr2; dwImplFlags = (DmdMethodImplAttributes)dwImplFlags2; return true; } public unsafe static uint[] GetInterfaceImplTokens(IMetaDataImport2 mdi, uint token) { if (mdi is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi.EnumInterfaceImpls(ref iter, token, IntPtr.Zero, 0, out uint cTokens); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi.CountEnum(iter, ref ulCount); if (hr < 0 || ulCount == 0) return Array.Empty(); hr = mdi.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); var tokens = new uint[ulCount]; fixed (uint* p = &tokens[0]) hr = mdi.EnumInterfaceImpls(ref iter, token, new IntPtr(p), (uint)tokens.Length, out cTokens); if (hr < 0) return Array.Empty(); return tokens; } finally { if (iter != IntPtr.Zero) mdi.CloseEnum(iter); } } public unsafe static uint GetInterfaceImplInterfaceToken(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; uint tkIface; int hr = mdi.GetInterfaceImplProps(token, IntPtr.Zero, new IntPtr(&tkIface)); return hr == 0 ? tkIface : 0; } public unsafe static uint[] GetParamTokens(IMetaDataImport2 mdi, uint token) { if (mdi is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi.EnumParams(ref iter, token, IntPtr.Zero, 0, out uint cTokens); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi.CountEnum(iter, ref ulCount); if (hr < 0 || ulCount == 0) return Array.Empty(); hr = mdi.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); var tokens = new uint[ulCount]; fixed (uint* p = &tokens[0]) hr = mdi.EnumParams(ref iter, token, new IntPtr(p), (uint)tokens.Length, out cTokens); if (hr < 0) return Array.Empty(); return tokens; } finally { if (iter != IntPtr.Zero) mdi.CloseEnum(iter); } } public unsafe static string? GetParamName(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; char[]? nameBuf = null; uint chName; int hr = mdi.GetParamProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chName), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr >= 0 && chName != 0) { nameBuf = new char[chName]; fixed (char* p = &nameBuf[0]) hr = mdi.GetParamProps(token, IntPtr.Zero, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chName), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } if (hr < 0) return null; return chName <= 1 ? string.Empty : new string(nameBuf!, 0, (int)chName - 1); } public unsafe static bool GetParamSeqAndAttrs(IMetaDataImport2 mdi, uint token, out uint seq, out DmdParameterAttributes attrs) { seq = uint.MaxValue; attrs = 0; if (mdi is null) return false; uint ulSequence, dwAttr; int hr = mdi.GetParamProps(token, IntPtr.Zero, new IntPtr(&ulSequence), IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&dwAttr), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr != 0) return false; seq = ulSequence; attrs = (DmdParameterAttributes)dwAttr; return true; } public unsafe static object? GetParamConstant(IMetaDataImport2 mdi, uint token, out ElementType constantType) { constantType = ElementType.End; if (mdi is null) return null; uint cchValue; IntPtr pValue; ElementType constantTypeTmp; int hr = mdi.GetParamProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, new IntPtr(&constantTypeTmp), new IntPtr(&pValue), new IntPtr(&cchValue)); if (hr < 0 || pValue == IntPtr.Zero) return null; constantType = constantTypeTmp; return ReadConstant(pValue, cchValue, constantType); } public static unsafe string? GetTypeRefName(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; uint chName; char[]? nameBuf = null; int hr = mdi.GetTypeRefProps(token, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chName)); if (hr >= 0 && chName != 0) { nameBuf = new char[chName]; fixed (char* p = &nameBuf[0]) hr = mdi.GetTypeRefProps(token, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chName)); } if (hr < 0) return null; if (chName <= 1) return string.Empty; return new string(nameBuf!, 0, (int)chName - 1); } public static unsafe uint GetTypeRefResolutionScope(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; uint tkResolutionScope; int hr = mdi.GetTypeRefProps(token, new IntPtr(&tkResolutionScope), IntPtr.Zero, 0, IntPtr.Zero); return hr == 0 ? tkResolutionScope : 0; } public unsafe static uint[] GetTypeDefTokens(IMetaDataImport2 mdi) { if (mdi is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi.EnumTypeDefs(ref iter, IntPtr.Zero, 0, out uint count); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi.CountEnum(iter, ref ulCount); if (hr < 0) return Array.Empty(); hr = mdi.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); // The global type isn't included var tokens = new uint[ulCount + 1]; if (tokens.Length > 1) { fixed (uint* p = &tokens[1]) hr = mdi.EnumTypeDefs(ref iter, new IntPtr(p), ulCount, out count); } if (hr < 0) return Array.Empty(); tokens[0] = 0x02000001; return tokens; } finally { if (iter != IntPtr.Zero) mdi.CloseEnum(iter); } } public unsafe static uint GetTypeDefExtends(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; uint tkExtends; int hr = mdi.GetTypeDefProps(token, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, new IntPtr(&tkExtends)); return hr != 0 ? 0 : tkExtends; } public static unsafe string? GetTypeDefName(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; uint chTypeDef; char[]? nameBuf = null; int hr = mdi.GetTypeDefProps(token, IntPtr.Zero, 0, new IntPtr(&chTypeDef), IntPtr.Zero, IntPtr.Zero); if (hr >= 0 && chTypeDef != 0) { nameBuf = new char[chTypeDef]; fixed (char* p = &nameBuf[0]) hr = mdi.GetTypeDefProps(token, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chTypeDef), IntPtr.Zero, IntPtr.Zero); } if (hr < 0) return null; if (chTypeDef <= 1) return string.Empty; return new string(nameBuf!, 0, (int)chTypeDef - 1); } public static unsafe DmdTypeAttributes? GetTypeDefAttributes(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; uint dwTypeDefFlags; int hr = mdi.GetTypeDefProps(token, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&dwTypeDefFlags), IntPtr.Zero); return hr == 0 ? (DmdTypeAttributes)dwTypeDefFlags : (DmdTypeAttributes?)null; } public static unsafe uint GetTypeDefEnclosingType(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; uint dwTypeDefFlags; int hr = mdi.GetTypeDefProps(token, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&dwTypeDefFlags), IntPtr.Zero); if (hr != 0) return 0; if ((dwTypeDefFlags & 7) >= 2) { hr = mdi.GetNestedClassProps(token, out uint enclType); if (hr == 0) return enclType; } return 0; } public static unsafe string? GetGenericParamName(IMetaDataImport2 mdi2, uint token) { if (mdi2 is null) return null; char[]? nameBuf = null; uint chName; int hr = mdi2.GetGenericParamProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chName)); if (hr >= 0 && chName != 0) { nameBuf = new char[chName]; fixed (char* p = &nameBuf[0]) hr = mdi2.GetGenericParamProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chName)); } if (hr < 0) return null; if (chName <= 1) return string.Empty; return new string(nameBuf!, 0, (int)chName - 1); } public static unsafe bool GetGenericParamNumAndAttrs(IMetaDataImport2 mdi2, uint token, out ushort number, out DmdGenericParameterAttributes attrs) { number = ushort.MaxValue; attrs = 0; if (mdi2 is null) return false; uint ulParamSeq, dwParamFlags; int hr = mdi2.GetGenericParamProps(token, new IntPtr(&ulParamSeq), new IntPtr(&dwParamFlags), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); if (hr != 0) return false; number = (ushort)ulParamSeq; attrs = (DmdGenericParameterAttributes)dwParamFlags; return true; } public unsafe static uint[] GetGenericParamTokens(IMetaDataImport2 mdi2, uint token) { if (mdi2 is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi2.EnumGenericParams(ref iter, token, IntPtr.Zero, 0, out uint cGenericParams); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi2.CountEnum(iter, ref ulCount); if (hr < 0 || ulCount == 0) return Array.Empty(); hr = mdi2.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); var gpTokens = new uint[ulCount]; fixed (uint* p = &gpTokens[0]) hr = mdi2.EnumGenericParams(ref iter, token, new IntPtr(p), (uint)gpTokens.Length, out cGenericParams); if (hr < 0) return Array.Empty(); return gpTokens; } finally { if (iter != IntPtr.Zero) mdi2.CloseEnum(iter); } } public unsafe static uint GetGenericParamConstraintTypeToken(IMetaDataImport2 mdi2, uint token) { if (mdi2 is null) return 0; uint tkConstraintType; int hr = mdi2.GetGenericParamConstraintProps(token, IntPtr.Zero, new IntPtr(&tkConstraintType)); if (hr != 0) return 0; return tkConstraintType; } public unsafe static uint[] GetGenericParamConstraintTokens(IMetaDataImport2 mdi2, uint token) { if (mdi2 is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi2.EnumGenericParamConstraints(ref iter, token, IntPtr.Zero, 0, out uint cGenericParamConstraints); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi2.CountEnum(iter, ref ulCount); if (hr < 0 || ulCount == 0) return Array.Empty(); hr = mdi2.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); var gpcTokens = new uint[ulCount]; fixed (uint* p = &gpcTokens[0]) hr = mdi2.EnumGenericParamConstraints(ref iter, token, new IntPtr(p), (uint)gpcTokens.Length, out cGenericParamConstraints); if (hr < 0) return Array.Empty(); return gpcTokens; } finally { if (iter != IntPtr.Zero) mdi2.CloseEnum(iter); } } public static unsafe (IntPtr addr, uint size) GetStandAloneSigBlob(IMetaDataImport2 mdi, uint token) { if (mdi is null) return (IntPtr.Zero, 0); int hr = mdi.GetSigFromToken(token, out var pvSig, out uint cbSig); if (hr < 0 || pvSig == IntPtr.Zero) return (IntPtr.Zero, 0); return (pvSig, cbSig); } public unsafe static COR_FIELD_OFFSET[]? GetFieldOffsets(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; if ((token & 0x00FFFFFF) == 0) return null; int cFieldOffset = 0; int hr = mdi.GetClassLayout(token, IntPtr.Zero, null, 0, new IntPtr(&cFieldOffset), IntPtr.Zero); Debug.Assert(hr == 0 || hr == CLDB_E_RECORD_NOTFOUND || hr == CLDB_E_INDEX_NOTFOUND); var fieldOffsets = cFieldOffset == 0 ? Array.Empty() : new COR_FIELD_OFFSET[cFieldOffset]; if (hr == 0 && fieldOffsets.Length != 0) hr = mdi.GetClassLayout(token, IntPtr.Zero, fieldOffsets, fieldOffsets.Length, new IntPtr(&cFieldOffset), IntPtr.Zero); return hr != 0 ? null : fieldOffsets; } public static uint? GetFieldOffset(IMetaDataImport2 mdi, uint token, uint fieldToken) { var offsets = GetFieldOffsets(mdi, token); if (offsets is null) return null; foreach (var info in offsets) { if (info.FieldToken == fieldToken) { if (info.Offset != uint.MaxValue) return info.Offset; return null; } } return null; } public unsafe static (IntPtr addr, uint size) GetFieldMarshalBlob(IMetaDataImport2 mdi, uint token) { if (mdi is null) return (IntPtr.Zero, 0); if ((token & 0x00FFFFFF) == 0) return (IntPtr.Zero, 0); int hr = mdi.GetFieldMarshal(token, out var pvNativeType, out uint cbNativeType); Debug.Assert(hr == 0 || hr == CLDB_E_RECORD_NOTFOUND); if (hr != 0) return (IntPtr.Zero, 0); return (pvNativeType, cbNativeType); } public unsafe static uint GetFieldOwnerRid(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; if (IsGlobal(mdi, token)) return 1; uint ownerToken; int hr = mdi.GetFieldProps(token, new IntPtr(&ownerToken), IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr != 0) return 0; var ownerMdToken = new MDToken(ownerToken); return ownerMdToken.Table == Table.TypeDef ? ownerMdToken.Rid : 0; } public static unsafe string? GetFieldName(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; uint chField = 0, dwAttr = 0; char[]? nameBuf = null; int hr = mdi.GetFieldProps(token, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chField), new IntPtr(&dwAttr), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr >= 0 && chField != 0) { nameBuf = new char[chField]; fixed (char* p = &nameBuf[0]) hr = mdi.GetFieldProps(token, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chField), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } if (hr < 0) return null; if (chField <= 1) return string.Empty; return new string(nameBuf!, 0, (int)chField - 1); } public unsafe static uint[] GetFieldTokens(IMetaDataImport2 mdi, uint token) { if (mdi is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi.EnumFields(ref iter, token, IntPtr.Zero, 0, out uint cTokens); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi.CountEnum(iter, ref ulCount); if (hr < 0 || ulCount == 0) return Array.Empty(); hr = mdi.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); var tokens = new uint[ulCount]; fixed (uint* p = &tokens[0]) hr = mdi.EnumFields(ref iter, token, new IntPtr(p), (uint)tokens.Length, out cTokens); if (hr < 0) return Array.Empty(); return tokens; } finally { if (iter != IntPtr.Zero) mdi.CloseEnum(iter); } } public static unsafe (IntPtr addr, uint size) GetFieldSignatureBlob(IMetaDataImport2 mdi, uint token) { if (mdi is null) return (IntPtr.Zero, 0); uint sigLen = 0; IntPtr sigAddr; int hr = mdi.GetFieldProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, new IntPtr(&sigAddr), new IntPtr(&sigLen), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr < 0 || sigAddr == IntPtr.Zero) return (IntPtr.Zero, 0); return (sigAddr, sigLen); } public unsafe static DmdFieldAttributes GetFieldAttributes(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; uint dwAttr; int hr = mdi.GetFieldProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&dwAttr), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); Debug.Assert(hr == 0); return hr < 0 ? 0 : (DmdFieldAttributes)dwAttr; } public unsafe static object? GetFieldConstant(IMetaDataImport2 mdi, uint token, out ElementType constantType) { constantType = ElementType.End; if (mdi is null) return null; uint cchValue; IntPtr pValue; ElementType constantTypeTmp; int hr = mdi.GetFieldProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(&constantTypeTmp), new IntPtr(&pValue), new IntPtr(&cchValue)); if (hr < 0 || pValue == IntPtr.Zero) return null; constantType = constantTypeTmp; return ReadConstant(pValue, cchValue, constantType); } unsafe static object? ReadConstant(IntPtr addr, uint size, ElementType elementType) { var p = (byte*)addr; if (p is null) return null; // size is always 0 unless it's a string... switch (elementType) { case ElementType.Boolean: return *p != 0; case ElementType.Char: return *(char*)p; case ElementType.I1: return *(sbyte*)p; case ElementType.U1: return *p; case ElementType.I2: return *(short*)p; case ElementType.U2: return *(ushort*)p; case ElementType.I4: return *(int*)p; case ElementType.U4: return *(uint*)p; case ElementType.I8: return *(long*)p; case ElementType.U8: return *(ulong*)p; case ElementType.R4: return *(float*)p; case ElementType.R8: return *(double*)p; case ElementType.String: return new string((char*)p, 0, (int)size); default: return null; } } public unsafe static uint GetEventOwnerRid(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; if (IsGlobal(mdi, token)) return 1; uint ownerToken; int hr = mdi.GetEventProps(token, new IntPtr(&ownerToken), IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); if (hr != 0) return 0; var ownerMdToken = new MDToken(ownerToken); return ownerMdToken.Table == Table.TypeDef ? ownerMdToken.Rid : 0; } public unsafe static DmdEventAttributes GetEventAttributes(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; uint dwEventFlags; int hr = mdi.GetEventProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&dwEventFlags), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); return hr == 0 ? (DmdEventAttributes)dwEventFlags : 0; } public unsafe static string? GetEventName(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; uint chEvent; int hr = mdi.GetEventProps(token, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chEvent), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); char[]? nameBuf = null; if (hr >= 0 && chEvent != 0) { nameBuf = new char[chEvent]; fixed (char* p = &nameBuf[0]) hr = mdi.GetEventProps(token, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chEvent), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); } if (hr < 0) return null; return chEvent <= 1 ? string.Empty : new string(nameBuf!, 0, (int)chEvent - 1); } public unsafe static uint GetEventTypeToken(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; uint tkEventType; int hr = mdi.GetEventProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, new IntPtr(&tkEventType), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); return hr == 0 ? tkEventType : 0; } public unsafe static bool GetEventAddRemoveFireTokens(IMetaDataImport2 mdi, uint token, out uint addToken, out uint removeToken, out uint fireToken) { addToken = 0; removeToken = 0; fireToken = 0; if (mdi is null) return false; uint addTokenTmp, removeTokenTmp, fireTokenTmp; int hr = mdi.GetEventProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(&addTokenTmp), new IntPtr(&removeTokenTmp), new IntPtr(&fireTokenTmp), IntPtr.Zero, 0, IntPtr.Zero); if (hr != 0) return false; addToken = addTokenTmp; removeToken = removeTokenTmp; fireToken = fireTokenTmp; return true; } public unsafe static uint[] GetEventOtherMethodTokens(IMetaDataImport2 mdi, uint token) { if (mdi is null) return Array.Empty(); uint count; int hr = mdi.GetEventProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&count)); uint[]? tokens = null; if (hr >= 0 && count != 0) { tokens = new uint[count]; fixed (uint* p = &tokens[0]) hr = mdi.GetEventProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(p), (uint)tokens.Length, new IntPtr(&count)); } if (hr < 0) return Array.Empty(); return tokens ?? Array.Empty(); } public unsafe static uint[] GetEventTokens(IMetaDataImport2 mdi, uint token) { if (mdi is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi.EnumEvents(ref iter, token, IntPtr.Zero, 0, out uint cTokens); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi.CountEnum(iter, ref ulCount); if (hr < 0 || ulCount == 0) return Array.Empty(); hr = mdi.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); var tokens = new uint[ulCount]; fixed (uint* p = &tokens[0]) hr = mdi.EnumEvents(ref iter, token, new IntPtr(p), (uint)tokens.Length, out cTokens); if (hr < 0) return Array.Empty(); return tokens; } finally { if (iter != IntPtr.Zero) mdi.CloseEnum(iter); } } public unsafe static uint GetPropertyOwnerRid(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; if (IsGlobal(mdi, token)) return 1; uint ownerToken; int hr = mdi.GetPropertyProps(token, new IntPtr(&ownerToken), IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); if (hr != 0) return 0; var ownerMdToken = new MDToken(ownerToken); return ownerMdToken.Table == Table.TypeDef ? ownerMdToken.Rid : 0; } public unsafe static uint[] GetPropertyTokens(IMetaDataImport2 mdi, uint token) { if (mdi is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi.EnumProperties(ref iter, token, IntPtr.Zero, 0, out uint cTokens); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi.CountEnum(iter, ref ulCount); if (hr < 0 || ulCount == 0) return Array.Empty(); hr = mdi.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); var tokens = new uint[ulCount]; fixed (uint* p = &tokens[0]) hr = mdi.EnumProperties(ref iter, token, new IntPtr(p), (uint)tokens.Length, out cTokens); if (hr < 0) return Array.Empty(); return tokens; } finally { if (iter != IntPtr.Zero) mdi.CloseEnum(iter); } } public unsafe static string? GetPropertyName(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; uint chProperty; int hr = mdi.GetPropertyProps(token, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chProperty), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); char[]? nameBuf = null; if (hr >= 0 && chProperty != 0) { nameBuf = new char[chProperty]; fixed (char* p = &nameBuf[0]) hr = mdi.GetPropertyProps(token, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chProperty), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); } if (hr < 0) return null; return chProperty <= 1 ? string.Empty : new string(nameBuf!, 0, (int)chProperty - 1); } public unsafe static bool GetPropertyGetterSetter(IMetaDataImport2 mdi, uint token, out uint mdGetter, out uint mdSetter) { mdGetter = 0; mdSetter = 0; if (mdi is null) return false; uint mdSetterTmp, mdGetterTmp; int hr = mdi.GetPropertyProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(&mdSetterTmp), new IntPtr(&mdGetterTmp), IntPtr.Zero, 0, IntPtr.Zero); if (hr != 0) return false; mdSetter = mdSetterTmp; mdGetter = mdGetterTmp; return true; } public unsafe static uint[] GetPropertyOtherMethodTokens(IMetaDataImport2 mdi, uint token) { if (mdi is null) return Array.Empty(); uint count; int hr = mdi.GetPropertyProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&count)); uint[]? tokens = null; if (hr >= 0 && count != 0) { tokens = new uint[count]; fixed (uint* p = &tokens[0]) hr = mdi.GetPropertyProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(p), (uint)tokens.Length, new IntPtr(&count)); } if (hr < 0) return Array.Empty(); return tokens ?? Array.Empty(); } public unsafe static DmdPropertyAttributes GetPropertyAttributes(IMetaDataImport2 mdi, uint token) { if (mdi is null) return 0; uint dwPropFlags; int hr = mdi.GetPropertyProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&dwPropFlags), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); return hr == 0 ? (DmdPropertyAttributes)dwPropFlags : 0; } public unsafe static (IntPtr addr, uint size) GetPropertySignatureBlob(IMetaDataImport2 mdi, uint token) { if (mdi is null) return (IntPtr.Zero, 0); IntPtr pvSig; uint cbSig; int hr = mdi.GetPropertyProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, new IntPtr(&pvSig), new IntPtr(&cbSig), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); if (hr != 0) return (IntPtr.Zero, 0); return (pvSig, cbSig); } public unsafe static object? GetPropertyConstant(IMetaDataImport2 mdi, uint token, out ElementType constantType) { constantType = ElementType.End; if (mdi is null) return null; uint cchDefaultValue; IntPtr pDefaultValue; ElementType constantTypeTmp; int hr = mdi.GetPropertyProps(token, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(&constantTypeTmp), new IntPtr(&pDefaultValue), new IntPtr(&cchDefaultValue), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); if (hr < 0 || pDefaultValue == IntPtr.Zero) return null; constantType = constantTypeTmp; return ReadConstant(pDefaultValue, cchDefaultValue, constantType); } public unsafe static (IntPtr addr, uint size) GetTypeSpecSignatureBlob(IMetaDataImport2 mdi, uint token) { if (mdi is null) return (IntPtr.Zero, 0); int hr = mdi.GetTypeSpecFromToken(token, out var pvSig, out uint cbSig); if (hr != 0 || pvSig == IntPtr.Zero) return (IntPtr.Zero, 0); return (pvSig, cbSig); } public unsafe static (IntPtr addr, uint size) GetMethodSpecProps(IMetaDataImport2 mdi2, uint token, out uint method) { method = 0; if (mdi2 is null) return (IntPtr.Zero, 0); int hr = mdi2.GetMethodSpecProps(token, out method, out var pvSigBlob, out uint cbSigBlob); if (hr != 0 || pvSigBlob == IntPtr.Zero) return (IntPtr.Zero, 0); return (pvSigBlob, cbSigBlob); } public unsafe static string? GetAssemblyRefSimpleName(IMetaDataAssemblyImport mdai, uint token) { if (mdai is null) return null; char[]? nameBuf = null; uint chName = 0; int hr = mdai.GetAssemblyRefProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chName), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr >= 0 && chName != 0) { nameBuf = new char[chName]; fixed (char* p = &nameBuf[0]) hr = mdai.GetAssemblyRefProps(token, IntPtr.Zero, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chName), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } if (hr < 0) return null; if (chName <= 1) return string.Empty; return new string(nameBuf!, 0, (int)chName - 1); } public unsafe static Version? GetAssemblyRefVersionAndLocale(IMetaDataAssemblyImport mdai, uint token, out string? locale) { locale = null; if (mdai is null) return null; ASSEMBLYMETADATA data; char[]? nameBuf = null; int hr = mdai.GetAssemblyRefProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&data), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr >= 0 && data.cbLocale != 0) { nameBuf = new char[data.cbLocale]; fixed (char* p = &nameBuf[0]) { data.szLocale = new IntPtr(p); hr = mdai.GetAssemblyRefProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&data), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } } if (hr != 0) return null; locale = data.cbLocale <= 1 ? string.Empty : new string(nameBuf!, 0, (int)data.cbLocale - 1); return new Version(data.usMajorVersion, data.usMinorVersion, data.usBuildNumber, data.usRevisionNumber); } public unsafe static byte[]? GetAssemblyRefPublicKeyOrToken(IMetaDataAssemblyImport mdai, uint token, out DmdAssemblyNameFlags attrs) { attrs = 0; if (mdai is null) return null; IntPtr pbPublicKeyOrToken; uint cbPublicKeyOrToken, dwAssemblyFlags; int hr = mdai.GetAssemblyRefProps(token, new IntPtr(&pbPublicKeyOrToken), new IntPtr(&cbPublicKeyOrToken), IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(&dwAssemblyFlags)); if (hr != 0) return null; attrs = (DmdAssemblyNameFlags)dwAssemblyFlags; if (pbPublicKeyOrToken == IntPtr.Zero) return null; var data = new byte[cbPublicKeyOrToken]; Marshal.Copy(pbPublicKeyOrToken, data, 0, data.Length); return data; } public unsafe static string? GetAssemblySimpleName(IMetaDataAssemblyImport mdai, uint token) { if (mdai is null) return null; char[]? nameBuf = null; uint chName = 0; int hr = mdai.GetAssemblyProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, new IntPtr(&chName), IntPtr.Zero, IntPtr.Zero); if (hr >= 0 && chName != 0) { nameBuf = new char[chName]; fixed (char* p = &nameBuf[0]) hr = mdai.GetAssemblyProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chName), IntPtr.Zero, IntPtr.Zero); } if (hr < 0) return null; if (chName <= 1) return string.Empty; return new string(nameBuf!, 0, (int)chName - 1); } public unsafe static Version? GetAssemblyVersionAndLocale(IMetaDataAssemblyImport mdai, uint token, out string? locale) { locale = null; if (mdai is null) return null; ASSEMBLYMETADATA data; char[]? nameBuf = null; int hr = mdai.GetAssemblyProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&data), IntPtr.Zero); if (hr >= 0 && data.cbLocale != 0) { nameBuf = new char[data.cbLocale]; fixed (char* p = &nameBuf[0]) { data.szLocale = new IntPtr(p); hr = mdai.GetAssemblyProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&data), IntPtr.Zero); } } if (hr != 0) return null; locale = data.cbLocale <= 1 ? string.Empty : new string(nameBuf!, 0, (int)data.cbLocale - 1); return new Version(data.usMajorVersion, data.usMinorVersion, data.usBuildNumber, data.usRevisionNumber); } public unsafe static DmdAssemblyHashAlgorithm? GetAssemblyHashAlgorithm(IMetaDataAssemblyImport mdai, uint token) { if (mdai is null) return null; uint ulHashAlgId; int hr = mdai.GetAssemblyProps(token, IntPtr.Zero, IntPtr.Zero, new IntPtr(&ulHashAlgId), IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr != 0) return null; return (DmdAssemblyHashAlgorithm)ulHashAlgId; } public unsafe static DmdAssemblyNameFlags? GetAssemblyAttributes(IMetaDataAssemblyImport mdai, uint token) { if (mdai is null) return null; uint dwAssemblyFlags; int hr = mdai.GetAssemblyProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, new IntPtr(&dwAssemblyFlags)); if (hr != 0) return null; return (DmdAssemblyNameFlags)dwAssemblyFlags; } public unsafe static byte[]? GetAssemblyPublicKey(IMetaDataAssemblyImport mdai, uint token) { if (mdai is null) return null; IntPtr pbPublicKey; uint cbPublicKey; int hr = mdai.GetAssemblyProps(token, new IntPtr(&pbPublicKey), new IntPtr(&cbPublicKey), IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr != 0 || pbPublicKey == IntPtr.Zero) return null; var data = new byte[cbPublicKey]; Marshal.Copy(pbPublicKey, data, 0, data.Length); return data; } public static DmdImageFileMachine? GetModuleMachineAndPEKind(IMetaDataImport2 mdi2, out DmdPortableExecutableKinds peKind) { peKind = 0; if (mdi2 is null) return null; int hr = mdi2.GetPEKind(out uint dwPEKind, out uint dwMachine); if (hr != 0) return null; peKind = (DmdPortableExecutableKinds)dwPEKind; return (DmdImageFileMachine)dwMachine; } public unsafe static string? GetModuleVersionString(IMetaDataImport2 mdi2) { if (mdi2 is null) return null; char[]? nameBuf = null; int hr = mdi2.GetVersionString(IntPtr.Zero, 0, out uint ccBufSize); if (hr >= 0 && ccBufSize != 0) { nameBuf = new char[ccBufSize]; fixed (char* p = &nameBuf[0]) hr = mdi2.GetVersionString(new IntPtr(p), ccBufSize, out ccBufSize); } if (hr < 0) return null; if (ccBufSize <= 1) return string.Empty; return new string(nameBuf!, 0, (int)ccBufSize - 1); } public unsafe static string? GetModuleName(IMetaDataImport2 mdi) { if (mdi is null) return null; char[]? nameBuf = null; uint cchName = 0; int hr = mdi.GetScopeProps(IntPtr.Zero, 0, new IntPtr(&cchName), IntPtr.Zero); if (hr >= 0 && cchName != 0) { nameBuf = new char[cchName]; fixed (char* p = &nameBuf[0]) hr = mdi.GetScopeProps(new IntPtr(p), cchName, new IntPtr(&cchName), IntPtr.Zero); } if (hr < 0) return null; if (cchName <= 1) return string.Empty; return new string(nameBuf!, 0, (int)cchName - 1); } public unsafe static Guid? GetModuleMvid(IMetaDataImport2 mdi) { if (mdi is null) return null; Guid guid; int hr = mdi.GetScopeProps(IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&guid)); if (hr < 0) return null; return guid; } public unsafe static string? GetModuleRefName(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; char[]? nameBuf = null; int hr = mdi.GetModuleRefProps(token, IntPtr.Zero, 0, out uint chName); if (hr >= 0 && chName != 0) { nameBuf = new char[chName]; fixed (char* p = &nameBuf[0]) hr = mdi.GetModuleRefProps(token, new IntPtr(p), (uint)nameBuf.Length, out chName); } if (hr < 0) return null; if (chName <= 1) return string.Empty; return new string(nameBuf!, 0, (int)chName - 1); } public unsafe static string? GetUserString(IMetaDataImport2 mdi, uint token) { if (mdi is null) return null; char[]? stringBuf = null; int hr = mdi.GetUserString(token, IntPtr.Zero, 0, out uint chString); if (hr >= 0 && chString != 0) { stringBuf = new char[chString]; fixed (char* p = &stringBuf[0]) hr = mdi.GetUserString(token, new IntPtr(p), (uint)stringBuf.Length, out chString); } if (hr < 0) return null; if (chString == 0) return string.Empty; return new string(stringBuf!, 0, (int)chString); } public unsafe static uint[] GetCustomAttributeTokens(IMetaDataImport2 mdi, uint token) { if (mdi is null) return Array.Empty(); var iter = IntPtr.Zero; try { int hr = mdi.EnumCustomAttributes(ref iter, token, 0, IntPtr.Zero, 0, out uint cTokens); if (hr < 0) return Array.Empty(); uint ulCount = 0; hr = mdi.CountEnum(iter, ref ulCount); if (hr < 0 || ulCount == 0) return Array.Empty(); hr = mdi.ResetEnum(iter, 0); if (hr < 0) return Array.Empty(); var tokens = new uint[ulCount]; fixed (uint* p = &tokens[0]) hr = mdi.EnumCustomAttributes(ref iter, token, 0, new IntPtr(p), (uint)tokens.Length, out cTokens); if (hr < 0) return Array.Empty(); return tokens; } finally { if (iter != IntPtr.Zero) mdi.CloseEnum(iter); } } public unsafe static (IntPtr addr, int size, int typeToken) GetCustomAttributeBlob(IMetaDataImport2 mdi, uint token) { if (mdi is null) return (IntPtr.Zero, 0, 0); int hr = mdi.GetCustomAttributeProps(token, IntPtr.Zero, out var typeToken, out var pBlob, out uint cbSize); if (hr != 0 || pBlob == IntPtr.Zero) return (IntPtr.Zero, 0, 0); return (pBlob, (int)cbSize, (int)typeToken); } public unsafe static string? GetFileName(IMetaDataAssemblyImport mdai, uint token) { if (mdai is null) return null; char[]? nameBuf = null; uint chName; int hr = mdai.GetFileProps(token, IntPtr.Zero, 0, new IntPtr(&chName), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr >= 0 && chName != 0) { nameBuf = new char[chName]; fixed (char* p = &nameBuf[0]) hr = mdai.GetFileProps(token, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chName), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } if (hr < 0) return null; return chName <= 1 ? string.Empty : new string(nameBuf!, 0, (int)chName - 1); } public unsafe static string? GetExportedTypeName(IMetaDataAssemblyImport mdai, uint token) { if (mdai is null) return null; char[]? nameBuf = null; uint chName; int hr = mdai.GetExportedTypeProps(token, IntPtr.Zero, 0, new IntPtr(&chName), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hr >= 0 && chName != 0) { nameBuf = new char[chName]; fixed (char* p = &nameBuf[0]) hr = mdai.GetExportedTypeProps(token, new IntPtr(p), (uint)nameBuf.Length, new IntPtr(&chName), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } if (hr < 0) return null; return chName <= 1 ? string.Empty : new string(nameBuf!, 0, (int)chName - 1); } public unsafe static bool GetExportedTypeProps(IMetaDataAssemblyImport mdai, uint token, out uint implementation, out uint typeDefId, out DmdTypeAttributes attrs) { implementation = 0; typeDefId = 0; attrs = 0; if (mdai is null) return false; uint tkImplementation, tkTypeDef, dwExportedTypeFlags; int hr = mdai.GetExportedTypeProps(token, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&tkImplementation), new IntPtr(&tkTypeDef), new IntPtr(&dwExportedTypeFlags)); if (hr != 0) return false; implementation = tkImplementation; typeDefId = tkTypeDef; attrs = (DmdTypeAttributes)dwExportedTypeFlags; return true; } } }