1688 lines
57 KiB
C#
1688 lines
57 KiB
C#
![]() |
/*
|
||
|
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 <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
// This file contains methods that directly use the MD API (IMetaDataImport, etc). It's used by
|
||
|
// the CorDebug and CorModuleDef code.
|
||
|
|
||
|
using System;
|
||
|
using System.Diagnostics;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using dndbg.COM.CorDebug;
|
||
|
using dndbg.COM.MetaData;
|
||
|
using dnlib.DotNet;
|
||
|
using dnlib.DotNet.MD;
|
||
|
using dnlib.PE;
|
||
|
|
||
|
namespace dndbg.Engine {
|
||
|
static class MDAPI {
|
||
|
static bool IsGlobal(IMetaDataImport? 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(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return false;
|
||
|
return mdi.IsValidToken(token);
|
||
|
}
|
||
|
|
||
|
public unsafe static bool GetClassLayout(IMetaDataImport? 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(IMetaDataImport? 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 UTF8String? GetUtf8Name(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
int hr = mdi.GetNameFromToken(token, out var pszUtf8NamePtr);
|
||
|
if (hr != 0 || pszUtf8NamePtr == IntPtr.Zero)
|
||
|
return null;
|
||
|
const int MAX_LEN = 0x1000;
|
||
|
var p = (byte*)pszUtf8NamePtr;
|
||
|
for (int i = 0; i < MAX_LEN; i++, p++) {
|
||
|
if (*p == 0)
|
||
|
break;
|
||
|
}
|
||
|
var buf = new byte[p - (byte*)pszUtf8NamePtr];
|
||
|
Marshal.Copy(pszUtf8NamePtr, buf, 0, buf.Length);
|
||
|
return new UTF8String(buf);
|
||
|
}
|
||
|
|
||
|
public unsafe static uint[] GetPermissionSetTokens(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
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>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static SecurityAction GetPermissionSetAction(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return 0;
|
||
|
uint dwAction;
|
||
|
int hr = mdi.GetPermissionSetProps(token, new IntPtr(&dwAction), IntPtr.Zero, IntPtr.Zero);
|
||
|
return hr != 0 ? 0 : (SecurityAction)dwAction;
|
||
|
}
|
||
|
|
||
|
public unsafe static byte[]? GetPermissionSetBlob(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
IntPtr pvPermission;
|
||
|
uint cbPermission;
|
||
|
int hr = mdi.GetPermissionSetProps(token, IntPtr.Zero, new IntPtr(&pvPermission), new IntPtr(&cbPermission));
|
||
|
if (hr != 0 || pvPermission == IntPtr.Zero)
|
||
|
return null;
|
||
|
|
||
|
var sig = new byte[cbPermission];
|
||
|
Marshal.Copy(pvPermission, sig, 0, sig.Length);
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
public unsafe static bool GetPinvokeMapProps(IMetaDataImport? mdi, uint token, out PInvokeAttributes 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 = (PInvokeAttributes)dwMappingFlags;
|
||
|
moduleToken = mrImportDLL;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public unsafe static string? GetPinvokeMapName(IMetaDataImport? 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(IMetaDataImport? 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(IMetaDataImport? 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 byte[]? GetMemberRefSignatureBlob(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
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 null;
|
||
|
|
||
|
var sig = new byte[cbSig];
|
||
|
Marshal.Copy(pvSigBlob, sig, 0, sig.Length);
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
public unsafe static uint GetMethodOwnerRid(IMetaDataImport? 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(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
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>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static byte[]? GetMethodSignatureBlob(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
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 null;
|
||
|
|
||
|
var sig = new byte[cbSigBlob];
|
||
|
Marshal.Copy(pvSigBlob, sig, 0, sig.Length);
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
public static unsafe string? GetMethodName(IMetaDataImport? 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(IMetaDataImport? mdi, uint token, out MethodAttributes dwAttr, out MethodImplAttributes 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 = (MethodAttributes)dwAttr2;
|
||
|
dwImplFlags = (MethodImplAttributes)dwImplFlags2;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public unsafe static MethodOverrideInfo[] GetMethodOverrides(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<MethodOverrideInfo>();
|
||
|
var iter = IntPtr.Zero;
|
||
|
try {
|
||
|
int hr = mdi.EnumMethodImpls(ref iter, token, IntPtr.Zero, IntPtr.Zero, 0, out uint cTokens);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<MethodOverrideInfo>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<MethodOverrideInfo>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<MethodOverrideInfo>();
|
||
|
|
||
|
var bodyTokens = new uint[ulCount];
|
||
|
var declTokens = new uint[ulCount];
|
||
|
fixed (uint* b = &bodyTokens[0]) {
|
||
|
fixed (uint* d = &declTokens[0])
|
||
|
hr = mdi.EnumMethodImpls(ref iter, token, new IntPtr(b), new IntPtr(d), (uint)bodyTokens.Length, out cTokens);
|
||
|
}
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<MethodOverrideInfo>();
|
||
|
var infos = new MethodOverrideInfo[ulCount];
|
||
|
for (int i = 0; i < infos.Length; i++)
|
||
|
infos[i] = new MethodOverrideInfo(bodyTokens[i], declTokens[i]);
|
||
|
return infos;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static uint[] GetMethodSemanticsTokens(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
var iter = IntPtr.Zero;
|
||
|
try {
|
||
|
int hr = mdi.EnumMethodSemantics(ref iter, token, IntPtr.Zero, 0, out uint cTokens);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
var tokens = new uint[ulCount];
|
||
|
fixed (uint* p = &tokens[0])
|
||
|
hr = mdi.EnumMethodSemantics(ref iter, token, new IntPtr(p), (uint)tokens.Length, out cTokens);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static MethodSemanticsAttributes GetMethodSemanticsAttributes(IMetaDataImport? mdi, uint token, uint tkPropEvent) {
|
||
|
if (mdi is null)
|
||
|
return 0;
|
||
|
int hr = mdi.GetMethodSemantics(token, tkPropEvent, out uint dwSemanticsFlags);
|
||
|
return hr == 0 ? (MethodSemanticsAttributes)dwSemanticsFlags : 0;
|
||
|
}
|
||
|
|
||
|
public unsafe static uint GetInterfaceImplOwnerRid(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return 0;
|
||
|
|
||
|
uint ownerToken;
|
||
|
int hr = mdi.GetInterfaceImplProps(token, new IntPtr(&ownerToken), IntPtr.Zero);
|
||
|
var ownerMdToken = new MDToken(ownerToken);
|
||
|
return ownerMdToken.Table == Table.TypeDef ? ownerMdToken.Rid : 0;
|
||
|
}
|
||
|
|
||
|
public unsafe static uint[] GetInterfaceImplTokens(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
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>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static uint GetInterfaceImplInterfaceToken(IMetaDataImport? 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(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
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>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static string? GetParamName(IMetaDataImport? 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(IMetaDataImport? mdi, uint token, out uint seq, out ParamAttributes 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 = (ParamAttributes)dwAttr;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public unsafe static object? GetParamConstant(IMetaDataImport? mdi, uint token, out CorElementType constantType) {
|
||
|
constantType = CorElementType.End;
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
uint cchValue;
|
||
|
IntPtr pValue;
|
||
|
CorElementType 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 unsafe static uint GetParamOwnerRid(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return 0;
|
||
|
uint ownerToken;
|
||
|
int hr = mdi.GetParamProps(token, new IntPtr(&ownerToken), IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||
|
if (hr != 0)
|
||
|
return 0;
|
||
|
var ownerMdToken = new MDToken(ownerToken);
|
||
|
return ownerMdToken.Table == Table.Method ? ownerMdToken.Rid : 0;
|
||
|
}
|
||
|
|
||
|
public static unsafe string? GetTypeRefName(IMetaDataImport? 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(IMetaDataImport? 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(IMetaDataImport? mdi) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
var iter = IntPtr.Zero;
|
||
|
try {
|
||
|
int hr = mdi.EnumTypeDefs(ref iter, IntPtr.Zero, 0, out uint count);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
// 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<uint>();
|
||
|
tokens[0] = 0x02000001;
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static uint GetTypeDefExtends(IMetaDataImport? 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(IMetaDataImport? 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 TypeAttributes? GetTypeDefAttributes(IMetaDataImport? 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 ? (TypeAttributes)dwTypeDefFlags : (TypeAttributes?)null;
|
||
|
}
|
||
|
|
||
|
public static unsafe uint GetTypeDefEnclosingType(IMetaDataImport? 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 unsafe static uint GetGenericParamOwner(IMetaDataImport2? mdi2, uint token) {
|
||
|
if (mdi2 is null)
|
||
|
return 0;
|
||
|
uint ownerToken;
|
||
|
int hr = mdi2.GetGenericParamProps(token, IntPtr.Zero, IntPtr.Zero, new IntPtr(&ownerToken), IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero);
|
||
|
if (hr != 0)
|
||
|
return 0;
|
||
|
var ownerMdToken = new MDToken(ownerToken);
|
||
|
return ownerMdToken.Table == Table.TypeDef || ownerMdToken.Table == Table.Method ? ownerMdToken.Raw : 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 GenericParamAttributes 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 = (GenericParamAttributes)dwParamFlags;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public unsafe static uint[] GetGenericParamTokens(IMetaDataImport2? mdi2, uint token) {
|
||
|
if (mdi2 is null)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi2.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi2.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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<uint>();
|
||
|
return gpTokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi2.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static uint GetGenericParamConstraintOwnerRid(IMetaDataImport2? mdi2, uint token) {
|
||
|
if (mdi2 is null)
|
||
|
return 0;
|
||
|
uint ownerToken;
|
||
|
int hr = mdi2.GetGenericParamConstraintProps(token, new IntPtr(&ownerToken), IntPtr.Zero);
|
||
|
if (hr != 0)
|
||
|
return 0;
|
||
|
var ownerMdToken = new MDToken(ownerToken);
|
||
|
return ownerMdToken.Table == Table.GenericParam ? ownerMdToken.Rid : 0;
|
||
|
}
|
||
|
|
||
|
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<uint>();
|
||
|
|
||
|
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>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi2.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi2.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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<uint>();
|
||
|
return gpcTokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi2.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static unsafe byte[]? GetStandAloneSigBlob(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
|
||
|
int hr = mdi.GetSigFromToken(token, out var pvSig, out uint cbSig);
|
||
|
if (hr < 0 || pvSig == IntPtr.Zero)
|
||
|
return null;
|
||
|
var sig = new byte[cbSig];
|
||
|
Marshal.Copy(pvSig, sig, 0, sig.Length);
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
public unsafe static COR_FIELD_OFFSET[]? GetFieldOffsets(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
|
||
|
int cFieldOffset = 0;
|
||
|
int hr = mdi.GetClassLayout(token, IntPtr.Zero, null, 0, new IntPtr(&cFieldOffset), IntPtr.Zero);
|
||
|
Debug.Assert(hr == 0 || hr == CordbgErrors.CLDB_E_RECORD_NOTFOUND || hr == CordbgErrors.CLDB_E_INDEX_NOTFOUND);
|
||
|
var fieldOffsets = cFieldOffset == 0 ? Array.Empty<COR_FIELD_OFFSET>() : 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 unsafe static byte[]? GetFieldMarshalBlob(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
|
||
|
int hr = mdi.GetFieldMarshal(token, out var pvNativeType, out uint cbNativeType);
|
||
|
Debug.Assert(hr == 0 || hr == CordbgErrors.CLDB_E_RECORD_NOTFOUND);
|
||
|
if (hr != 0)
|
||
|
return null;
|
||
|
|
||
|
var data = new byte[cbNativeType];
|
||
|
Marshal.Copy(pvNativeType, data, 0, data.Length);
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
public unsafe static uint GetFieldOwnerRid(IMetaDataImport? 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(IMetaDataImport? 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(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
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>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static unsafe byte[]? GetFieldSignatureBlob(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
|
||
|
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 null;
|
||
|
|
||
|
var buf = new byte[sigLen];
|
||
|
Marshal.Copy(sigAddr, buf, 0, buf.Length);
|
||
|
return buf;
|
||
|
}
|
||
|
|
||
|
public unsafe static FieldAttributes GetFieldAttributes(IMetaDataImport? 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 : (FieldAttributes)dwAttr;
|
||
|
}
|
||
|
|
||
|
public unsafe static object? GetFieldConstant(IMetaDataImport? mdi, uint token, out CorElementType constantType) {
|
||
|
constantType = CorElementType.End;
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
uint cchValue;
|
||
|
IntPtr pValue;
|
||
|
CorElementType 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, CorElementType elementType) {
|
||
|
var p = (byte*)addr;
|
||
|
if (p is null)
|
||
|
return null;
|
||
|
|
||
|
// size is always 0 unless it's a string...
|
||
|
switch (elementType) {
|
||
|
case CorElementType.Boolean: return *p != 0;
|
||
|
case CorElementType.Char: return *(char*)p;
|
||
|
case CorElementType.I1: return *(sbyte*)p;
|
||
|
case CorElementType.U1: return *p;
|
||
|
case CorElementType.I2: return *(short*)p;
|
||
|
case CorElementType.U2: return *(ushort*)p;
|
||
|
case CorElementType.I4: return *(int*)p;
|
||
|
case CorElementType.U4: return *(uint*)p;
|
||
|
case CorElementType.I8: return *(long*)p;
|
||
|
case CorElementType.U8: return *(ulong*)p;
|
||
|
case CorElementType.R4: return *(float*)p;
|
||
|
case CorElementType.R8: return *(double*)p;
|
||
|
case CorElementType.String: return new string((char*)p, 0, (int)size);
|
||
|
default: return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static uint GetEventOwnerRid(IMetaDataImport? 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 EventAttributes GetEventAttributes(IMetaDataImport? 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 ? (EventAttributes)dwEventFlags : 0;
|
||
|
}
|
||
|
|
||
|
public unsafe static string? GetEventName(IMetaDataImport? 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(IMetaDataImport? 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(IMetaDataImport? 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(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
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<uint>();
|
||
|
return tokens ?? Array.Empty<uint>();
|
||
|
}
|
||
|
|
||
|
public unsafe static uint[] GetEventTokens(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
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>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static uint GetPropertyOwnerRid(IMetaDataImport? 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(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
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>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static string? GetPropertyName(IMetaDataImport? 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(IMetaDataImport? 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(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
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<uint>();
|
||
|
return tokens ?? Array.Empty<uint>();
|
||
|
}
|
||
|
|
||
|
public unsafe static PropertyAttributes GetPropertyAttributes(IMetaDataImport? 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 ? (PropertyAttributes)dwPropFlags : 0;
|
||
|
}
|
||
|
|
||
|
public unsafe static byte[]? GetPropertySignatureBlob(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
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 null;
|
||
|
|
||
|
var data = new byte[cbSig];
|
||
|
Marshal.Copy(pvSig, data, 0, data.Length);
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
public unsafe static object? GetPropertyConstant(IMetaDataImport? mdi, uint token, out CorElementType constantType) {
|
||
|
constantType = CorElementType.End;
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
uint cchDefaultValue;
|
||
|
IntPtr pDefaultValue;
|
||
|
CorElementType 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 byte[]? GetTypeSpecSignatureBlob(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
|
||
|
int hr = mdi.GetTypeSpecFromToken(token, out var pvSig, out uint cbSig);
|
||
|
if (hr != 0 || pvSig == IntPtr.Zero)
|
||
|
return null;
|
||
|
|
||
|
var sig = new byte[cbSig];
|
||
|
Marshal.Copy(pvSig, sig, 0, sig.Length);
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
public unsafe static byte[]? GetMethodSpecProps(IMetaDataImport2? mdi2, uint token, out uint method) {
|
||
|
method = 0;
|
||
|
if (mdi2 is null)
|
||
|
return null;
|
||
|
|
||
|
int hr = mdi2.GetMethodSpecProps(token, out method, out var pvSigBlob, out uint cbSigBlob);
|
||
|
if (hr != 0 || pvSigBlob == IntPtr.Zero)
|
||
|
return null;
|
||
|
|
||
|
var sig = new byte[cbSigBlob];
|
||
|
Marshal.Copy(pvSigBlob, sig, 0, sig.Length);
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
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[]? GetAssemblyRefHash(IMetaDataAssemblyImport? mdai, uint token) {
|
||
|
if (mdai is null)
|
||
|
return null;
|
||
|
IntPtr pbHashValue;
|
||
|
uint cbHashValue;
|
||
|
int hr = mdai.GetAssemblyRefProps(token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, new IntPtr(&pbHashValue), new IntPtr(&cbHashValue), IntPtr.Zero);
|
||
|
if (hr != 0 || pbHashValue == IntPtr.Zero)
|
||
|
return null;
|
||
|
|
||
|
var data = new byte[cbHashValue];
|
||
|
Marshal.Copy(pbHashValue, data, 0, data.Length);
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
public unsafe static PublicKeyBase? GetAssemblyRefPublicKeyOrToken(IMetaDataAssemblyImport? mdai, uint token, out AssemblyAttributes 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 = (AssemblyAttributes)dwAssemblyFlags;
|
||
|
if (pbPublicKeyOrToken == IntPtr.Zero)
|
||
|
return null;
|
||
|
var data = new byte[cbPublicKeyOrToken];
|
||
|
Marshal.Copy(pbPublicKeyOrToken, data, 0, data.Length);
|
||
|
if ((dwAssemblyFlags & (uint)AssemblyAttributes.PublicKey) != 0)
|
||
|
return new PublicKey(data);
|
||
|
return new PublicKeyToken(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 AssemblyHashAlgorithm? 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 (AssemblyHashAlgorithm)ulHashAlgId;
|
||
|
}
|
||
|
|
||
|
public unsafe static AssemblyAttributes? 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 (AssemblyAttributes)dwAssemblyFlags;
|
||
|
}
|
||
|
|
||
|
public unsafe static PublicKey? 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 new PublicKey(data);
|
||
|
}
|
||
|
|
||
|
public static Machine? GetModuleMachineAndPEKind(IMetaDataImport2? mdi2, out CorPEKind 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 = (CorPEKind)dwPEKind;
|
||
|
return (Machine)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(IMetaDataImport? 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(IMetaDataImport? 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(IMetaDataImport? 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(IMetaDataImport? 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 byte[]? GetCustomAttributeByName(IMetaDataImport? mdi, uint token, string name) {
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
IntPtr addr;
|
||
|
uint size;
|
||
|
int hr = mdi.GetCustomAttributeByName(token, name, new IntPtr(&addr), new IntPtr(&size));
|
||
|
if (hr < 0 || addr == IntPtr.Zero)
|
||
|
return null;
|
||
|
|
||
|
var data = new byte[size];
|
||
|
Marshal.Copy(addr, data, 0, data.Length);
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
public static bool HasAttribute(IMetaDataImport? mdi, uint token, string attributeName) {
|
||
|
if (mdi is null)
|
||
|
return false;
|
||
|
return mdi.GetCustomAttributeByName(token, attributeName, IntPtr.Zero, IntPtr.Zero) == 0;
|
||
|
}
|
||
|
|
||
|
public unsafe static uint[] GetCustomAttributeTokens(IMetaDataImport? mdi, uint token) {
|
||
|
if (mdi is null)
|
||
|
return Array.Empty<uint>();
|
||
|
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>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
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<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdi.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static byte[]? GetCustomAttributeBlob(IMetaDataImport? mdi, uint token, out uint typeToken) {
|
||
|
typeToken = 0;
|
||
|
if (mdi is null)
|
||
|
return null;
|
||
|
|
||
|
int hr = mdi.GetCustomAttributeProps(token, IntPtr.Zero, out typeToken, out var pBlob, out uint cbSize);
|
||
|
if (hr != 0 || pBlob == IntPtr.Zero)
|
||
|
return null;
|
||
|
|
||
|
var caBlob = new byte[cbSize];
|
||
|
Marshal.Copy(pBlob, caBlob, 0, caBlob.Length);
|
||
|
return caBlob;
|
||
|
}
|
||
|
|
||
|
public unsafe static FileAttributes? GetFileAttributes(IMetaDataAssemblyImport? mdai, uint token) {
|
||
|
if (mdai is null)
|
||
|
return null;
|
||
|
uint dwFileFlags;
|
||
|
int hr = mdai.GetFileProps(token, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(&dwFileFlags));
|
||
|
return hr != 0 ? null : (FileAttributes?)dwFileFlags;
|
||
|
}
|
||
|
|
||
|
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 byte[]? GetFileHash(IMetaDataAssemblyImport? mdai, uint token) {
|
||
|
if (mdai is null)
|
||
|
return null;
|
||
|
IntPtr pbHashValue;
|
||
|
uint cbHashValue;
|
||
|
int hr = mdai.GetFileProps(token, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&pbHashValue), new IntPtr(&cbHashValue), IntPtr.Zero);
|
||
|
if (hr != 0)
|
||
|
return null;
|
||
|
|
||
|
var sig = new byte[cbHashValue];
|
||
|
Marshal.Copy(pbHashValue, sig, 0, sig.Length);
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
public unsafe static uint[] GetExportedTypeRids(IMetaDataAssemblyImport? mdai) {
|
||
|
if (!(mdai is IMetaDataImport mdi))
|
||
|
return Array.Empty<uint>();
|
||
|
var iter = IntPtr.Zero;
|
||
|
try {
|
||
|
int hr = mdai.EnumExportedTypes(ref iter, IntPtr.Zero, 0, out uint cTokens);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
var tokens = new uint[ulCount];
|
||
|
fixed (uint* p = &tokens[0])
|
||
|
hr = mdai.EnumExportedTypes(ref iter, new IntPtr(p), (uint)tokens.Length, out cTokens);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdai.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 TypeAttributes 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 = (TypeAttributes)dwExportedTypeFlags;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public unsafe static uint[] GetManifestResourceRids(IMetaDataAssemblyImport? mdai) {
|
||
|
if (!(mdai is IMetaDataImport mdi))
|
||
|
return Array.Empty<uint>();
|
||
|
var iter = IntPtr.Zero;
|
||
|
try {
|
||
|
int hr = mdai.EnumManifestResources(ref iter, IntPtr.Zero, 0, out uint cTokens);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
uint ulCount = 0;
|
||
|
hr = mdi.CountEnum(iter, ref ulCount);
|
||
|
if (hr < 0 || ulCount == 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
hr = mdi.ResetEnum(iter, 0);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
|
||
|
var tokens = new uint[ulCount];
|
||
|
fixed (uint* p = &tokens[0])
|
||
|
hr = mdai.EnumManifestResources(ref iter, new IntPtr(p), (uint)tokens.Length, out cTokens);
|
||
|
if (hr < 0)
|
||
|
return Array.Empty<uint>();
|
||
|
return tokens;
|
||
|
}
|
||
|
finally {
|
||
|
if (iter != IntPtr.Zero)
|
||
|
mdai.CloseEnum(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe static string? GetManifestResourceName(IMetaDataAssemblyImport? mdai, uint token) {
|
||
|
if (mdai is null)
|
||
|
return null;
|
||
|
char[]? nameBuf = null;
|
||
|
uint chName;
|
||
|
int hr = mdai.GetManifestResourceProps(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.GetManifestResourceProps(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 GetManifestResourceProps(IMetaDataAssemblyImport? mdai, uint token, out uint offset, out uint implementation, out ManifestResourceAttributes attrs) {
|
||
|
offset = 0;
|
||
|
implementation = 0;
|
||
|
attrs = 0;
|
||
|
if (mdai is null)
|
||
|
return false;
|
||
|
|
||
|
uint tkImplementation, dwOffset, dwResourceFlags;
|
||
|
int hr = mdai.GetManifestResourceProps(token, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&tkImplementation), new IntPtr(&dwOffset), new IntPtr(&dwResourceFlags));
|
||
|
if (hr != 0)
|
||
|
return false;
|
||
|
|
||
|
implementation = tkImplementation;
|
||
|
offset = dwOffset;
|
||
|
attrs = (ManifestResourceAttributes)dwResourceFlags;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public unsafe static uint? GetManifestResourceImplementationToken(IMetaDataAssemblyImport? mdai, uint token) {
|
||
|
if (mdai is null)
|
||
|
return null;
|
||
|
uint tkImplementation;
|
||
|
int hr = mdai.GetManifestResourceProps(token, IntPtr.Zero, 0, IntPtr.Zero, new IntPtr(&tkImplementation), IntPtr.Zero, IntPtr.Zero);
|
||
|
return hr == 0 ? tkImplementation : (uint?)null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
readonly struct MethodOverrideInfo {
|
||
|
public uint BodyToken { get; }
|
||
|
public uint DeclToken { get; }
|
||
|
public MethodOverrideInfo(uint b, uint d) {
|
||
|
BodyToken = b;
|
||
|
DeclToken = d;
|
||
|
}
|
||
|
}
|
||
|
}
|