obfuz/Plugins/dnlib/DotNet/WinMDHelpers.cs

447 lines
23 KiB
C#
Raw Normal View History

// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
namespace dnlib.DotNet {
enum ClrAssembly {
Mscorlib,
SystemNumericsVectors,
SystemObjectModel,
SystemRuntime,
SystemRuntimeInteropServicesWindowsRuntime,
SystemRuntimeWindowsRuntime,
SystemRuntimeWindowsRuntimeUIXaml,
}
/// <summary>
/// Helper class to project WinMD types to CLR types
/// </summary>
public static class WinMDHelpers {
readonly struct ClassName : IEquatable<ClassName> {
public readonly UTF8String Namespace;
public readonly UTF8String Name;
// Not used when comparing for equality etc
public readonly bool IsValueType;
public ClassName(UTF8String ns, UTF8String name, bool isValueType = false) {
Namespace = ns;
Name = name;
IsValueType = isValueType;
}
public ClassName(string ns, string name, bool isValueType = false) {
Namespace = ns;
Name = name;
IsValueType = isValueType;
}
public static bool operator ==(ClassName a, ClassName b) => a.Equals(b);
public static bool operator !=(ClassName a, ClassName b) => !a.Equals(b);
public bool Equals(ClassName other) =>
// Don't check IsValueType
UTF8String.Equals(Namespace, other.Namespace) && UTF8String.Equals(Name, other.Name);
public override bool Equals(object obj) {
if (!(obj is ClassName))
return false;
return Equals((ClassName)obj);
}
public override int GetHashCode() =>
// Don't use IsValueType
UTF8String.GetHashCode(Namespace) ^ UTF8String.GetHashCode(Name);
public override string ToString() => $"{Namespace}.{Name}";
}
sealed class ProjectedClass {
public readonly ClassName WinMDClass;
public readonly ClassName ClrClass;
public readonly ClrAssembly ClrAssembly;
public readonly ClrAssembly ContractAssembly;
public ProjectedClass(string mdns, string mdname, string clrns, string clrname, ClrAssembly clrAsm, ClrAssembly contractAsm, bool winMDValueType, bool clrValueType) {
WinMDClass = new ClassName(mdns, mdname, winMDValueType);
ClrClass = new ClassName(clrns, clrname, clrValueType);
ClrAssembly = clrAsm;
ContractAssembly = contractAsm;
}
public override string ToString() => $"{WinMDClass} <-> {ClrClass}, {CreateAssembly(null, ContractAssembly)}";
}
// See https://github.com/dotnet/coreclr/blob/master/src/inc/winrtprojectedtypes.h
// To generate this code replace the contents of src/inc/winrtprojectedtypes.h with:
// DEFINE_PROJECTED_ENUM
// => DEFINE_PROJECTED_STRUCT
// ^DEFINE_PROJECTED\w*_STRUCT\s*\(("[^"]+"),\s*("[^"]+"),\s*("[^"]+"),\s*("[^"]+"),\s*(\w+),\s*(\w+).*$
// => \t\t\tnew ProjectedClass(\1, \2, \3, \4, ClrAssembly.\5, ClrAssembly.\6, true, true),
// ^DEFINE_PROJECTED\w+\s*\(("[^"]+"),\s*("[^"]+"),\s*("[^"]+"),\s*("[^"]+"),\s*(\w+),\s*(\w+).*$
// => \t\t\tnew ProjectedClass(\1, \2, \3, \4, ClrAssembly.\5, ClrAssembly.\6, false, false),
// Sometimes the types aren't both structs or both classes. Known cases:
// IReference`1 (class) vs Nullable`1 (struct)
// IKeyValuePair`2 (class) vs KeyValuePair`2 (struct)
// TypeName (struct) vs Type (class)
// HResult (struct) vs Exception (class)
// See md/winmd/adapter.cpp WinMDAdapter::RewriteTypeInSignature() or check the types
// in a decompiler.
static readonly ProjectedClass[] ProjectedClasses = new ProjectedClass[] {
new ProjectedClass("Windows.Foundation.Metadata", "AttributeUsageAttribute", "System", "AttributeUsageAttribute", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.Foundation.Metadata", "AttributeTargets", "System", "AttributeTargets", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, true, true),
new ProjectedClass("Windows.UI", "Color", "Windows.UI", "Color", ClrAssembly.SystemRuntimeWindowsRuntime, ClrAssembly.SystemRuntimeWindowsRuntime, true, true),
new ProjectedClass("Windows.Foundation", "DateTime", "System", "DateTimeOffset", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, true, true),
new ProjectedClass("Windows.Foundation", "EventHandler`1", "System", "EventHandler`1", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.Foundation", "EventRegistrationToken", "System.Runtime.InteropServices.WindowsRuntime", "EventRegistrationToken", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntimeInteropServicesWindowsRuntime, true, true),
new ProjectedClass("Windows.Foundation", "HResult", "System", "Exception", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, true, false),
new ProjectedClass("Windows.Foundation", "IReference`1", "System", "Nullable`1", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, true),
new ProjectedClass("Windows.Foundation", "Point", "Windows.Foundation", "Point", ClrAssembly.SystemRuntimeWindowsRuntime, ClrAssembly.SystemRuntimeWindowsRuntime, true, true),
new ProjectedClass("Windows.Foundation", "Rect", "Windows.Foundation", "Rect", ClrAssembly.SystemRuntimeWindowsRuntime, ClrAssembly.SystemRuntimeWindowsRuntime, true, true),
new ProjectedClass("Windows.Foundation", "Size", "Windows.Foundation", "Size", ClrAssembly.SystemRuntimeWindowsRuntime, ClrAssembly.SystemRuntimeWindowsRuntime, true, true),
new ProjectedClass("Windows.Foundation", "TimeSpan", "System", "TimeSpan", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, true, true),
new ProjectedClass("Windows.Foundation", "Uri", "System", "Uri", ClrAssembly.SystemRuntime, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.Foundation", "IClosable", "System", "IDisposable", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.Foundation.Collections", "IIterable`1", "System.Collections.Generic", "IEnumerable`1", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.Foundation.Collections", "IVector`1", "System.Collections.Generic", "IList`1", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.Foundation.Collections", "IVectorView`1", "System.Collections.Generic", "IReadOnlyList`1", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.Foundation.Collections", "IMap`2", "System.Collections.Generic", "IDictionary`2", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.Foundation.Collections", "IMapView`2", "System.Collections.Generic", "IReadOnlyDictionary`2", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.Foundation.Collections", "IKeyValuePair`2", "System.Collections.Generic", "KeyValuePair`2", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, true),
new ProjectedClass("Windows.UI.Xaml.Input", "ICommand", "System.Windows.Input", "ICommand", ClrAssembly.SystemObjectModel, ClrAssembly.SystemObjectModel, false, false),
new ProjectedClass("Windows.UI.Xaml.Interop", "IBindableIterable", "System.Collections", "IEnumerable", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.UI.Xaml.Interop", "IBindableVector", "System.Collections", "IList", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, false, false),
new ProjectedClass("Windows.UI.Xaml.Interop", "INotifyCollectionChanged", "System.Collections.Specialized", "INotifyCollectionChanged", ClrAssembly.SystemObjectModel, ClrAssembly.SystemObjectModel, false, false),
new ProjectedClass("Windows.UI.Xaml.Interop", "NotifyCollectionChangedEventHandler", "System.Collections.Specialized", "NotifyCollectionChangedEventHandler", ClrAssembly.SystemObjectModel, ClrAssembly.SystemObjectModel, false, false),
new ProjectedClass("Windows.UI.Xaml.Interop", "NotifyCollectionChangedEventArgs", "System.Collections.Specialized", "NotifyCollectionChangedEventArgs", ClrAssembly.SystemObjectModel, ClrAssembly.SystemObjectModel, false, false),
new ProjectedClass("Windows.UI.Xaml.Interop", "NotifyCollectionChangedAction", "System.Collections.Specialized", "NotifyCollectionChangedAction", ClrAssembly.SystemObjectModel, ClrAssembly.SystemObjectModel, true, true),
new ProjectedClass("Windows.UI.Xaml.Data", "INotifyPropertyChanged", "System.ComponentModel", "INotifyPropertyChanged", ClrAssembly.SystemObjectModel, ClrAssembly.SystemObjectModel, false, false),
new ProjectedClass("Windows.UI.Xaml.Data", "PropertyChangedEventHandler", "System.ComponentModel", "PropertyChangedEventHandler", ClrAssembly.SystemObjectModel, ClrAssembly.SystemObjectModel, false, false),
new ProjectedClass("Windows.UI.Xaml.Data", "PropertyChangedEventArgs", "System.ComponentModel", "PropertyChangedEventArgs", ClrAssembly.SystemObjectModel, ClrAssembly.SystemObjectModel, false, false),
new ProjectedClass("Windows.UI.Xaml", "CornerRadius", "Windows.UI.Xaml", "CornerRadius", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml", "Duration", "Windows.UI.Xaml", "Duration", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml", "DurationType", "Windows.UI.Xaml", "DurationType", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml", "GridLength", "Windows.UI.Xaml", "GridLength", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml", "GridUnitType", "Windows.UI.Xaml", "GridUnitType", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml", "Thickness", "Windows.UI.Xaml", "Thickness", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml.Interop", "TypeName", "System", "Type", ClrAssembly.Mscorlib, ClrAssembly.SystemRuntime, true, false),
new ProjectedClass("Windows.UI.Xaml.Controls.Primitives", "GeneratorPosition", "Windows.UI.Xaml.Controls.Primitives", "GeneratorPosition", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml.Media", "Matrix", "Windows.UI.Xaml.Media", "Matrix", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml.Media.Animation", "KeyTime", "Windows.UI.Xaml.Media.Animation", "KeyTime", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml.Media.Animation", "RepeatBehavior", "Windows.UI.Xaml.Media.Animation", "RepeatBehavior", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml.Media.Animation", "RepeatBehaviorType", "Windows.UI.Xaml.Media.Animation", "RepeatBehaviorType", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.UI.Xaml.Media.Media3D", "Matrix3D", "Windows.UI.Xaml.Media.Media3D", "Matrix3D", ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml, true, true),
new ProjectedClass("Windows.Foundation.Numerics", "Vector2", "System.Numerics", "Vector2", ClrAssembly.SystemNumericsVectors, ClrAssembly.SystemNumericsVectors, true, true),
new ProjectedClass("Windows.Foundation.Numerics", "Vector3", "System.Numerics", "Vector3", ClrAssembly.SystemNumericsVectors, ClrAssembly.SystemNumericsVectors, true, true),
new ProjectedClass("Windows.Foundation.Numerics", "Vector4", "System.Numerics", "Vector4", ClrAssembly.SystemNumericsVectors, ClrAssembly.SystemNumericsVectors, true, true),
new ProjectedClass("Windows.Foundation.Numerics", "Matrix3x2", "System.Numerics", "Matrix3x2", ClrAssembly.SystemNumericsVectors, ClrAssembly.SystemNumericsVectors, true, true),
new ProjectedClass("Windows.Foundation.Numerics", "Matrix4x4", "System.Numerics", "Matrix4x4", ClrAssembly.SystemNumericsVectors, ClrAssembly.SystemNumericsVectors, true, true),
new ProjectedClass("Windows.Foundation.Numerics", "Plane", "System.Numerics", "Plane", ClrAssembly.SystemNumericsVectors, ClrAssembly.SystemNumericsVectors, true, true),
new ProjectedClass("Windows.Foundation.Numerics", "Quaternion", "System.Numerics", "Quaternion", ClrAssembly.SystemNumericsVectors, ClrAssembly.SystemNumericsVectors, true, true),
};
static readonly Dictionary<ClassName, ProjectedClass> winMDToCLR = new Dictionary<ClassName, ProjectedClass>();
static WinMDHelpers() {
foreach (var projClass in ProjectedClasses)
winMDToCLR.Add(projClass.WinMDClass, projClass);
}
static AssemblyRef ToCLR(ModuleDef module, ref UTF8String ns, ref UTF8String name) {
if (!winMDToCLR.TryGetValue(new ClassName(ns, name), out var pc))
return null;
ns = pc.ClrClass.Namespace;
name = pc.ClrClass.Name;
return CreateAssembly(module, pc.ContractAssembly);
}
static AssemblyRef CreateAssembly(ModuleDef module, ClrAssembly clrAsm) {
var mscorlib = module?.CorLibTypes.AssemblyRef;
var asm = new AssemblyRefUser(GetName(clrAsm), contractAsmVersion, new PublicKeyToken(GetPublicKeyToken(clrAsm)), UTF8String.Empty);
if (mscorlib is not null && mscorlib.Name == mscorlibName && IsValidMscorlibVersion(mscorlib.Version))
asm.Version = mscorlib.Version;
if (module is ModuleDefMD mod) {
Version ver = null;
foreach (var asmRef in mod.GetAssemblyRefs()) {
if (asmRef.IsContentTypeWindowsRuntime)
continue;
if (asmRef.Name != asm.Name)
continue;
if (asmRef.Culture != asm.Culture)
continue;
if (!PublicKeyBase.TokenEquals(asmRef.PublicKeyOrToken, asm.PublicKeyOrToken))
continue;
if (!IsValidMscorlibVersion(asmRef.Version))
continue;
if (ver is null || asmRef.Version > ver)
ver = asmRef.Version;
}
if (ver is not null)
asm.Version = ver;
}
return asm;
}
static readonly Version contractAsmVersion = new Version(4, 0, 0, 0);
static readonly UTF8String mscorlibName = new UTF8String("mscorlib");
// Silverlight uses 5.0.5.0
static bool IsValidMscorlibVersion(Version version) => version is not null && (uint)version.Major <= 5;
static UTF8String GetName(ClrAssembly clrAsm) =>
clrAsm switch {
ClrAssembly.Mscorlib => clrAsmName_Mscorlib,
ClrAssembly.SystemNumericsVectors => clrAsmName_SystemNumericsVectors,
ClrAssembly.SystemObjectModel => clrAsmName_SystemObjectModel,
ClrAssembly.SystemRuntime => clrAsmName_SystemRuntime,
ClrAssembly.SystemRuntimeInteropServicesWindowsRuntime => clrAsmName_SystemRuntimeInteropServicesWindowsRuntime,
ClrAssembly.SystemRuntimeWindowsRuntime => clrAsmName_SystemRuntimeWindowsRuntime,
ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml => clrAsmName_SystemRuntimeWindowsRuntimeUIXaml,
_ => throw new InvalidOperationException(),
};
static readonly UTF8String clrAsmName_Mscorlib = new UTF8String("mscorlib");
static readonly UTF8String clrAsmName_SystemNumericsVectors = new UTF8String("System.Numerics.Vectors");
static readonly UTF8String clrAsmName_SystemObjectModel = new UTF8String("System.ObjectModel");
static readonly UTF8String clrAsmName_SystemRuntime = new UTF8String("System.Runtime");
static readonly UTF8String clrAsmName_SystemRuntimeInteropServicesWindowsRuntime = new UTF8String("System.Runtime.InteropServices.WindowsRuntime");
static readonly UTF8String clrAsmName_SystemRuntimeWindowsRuntime = new UTF8String("System.Runtime.WindowsRuntime");
static readonly UTF8String clrAsmName_SystemRuntimeWindowsRuntimeUIXaml = new UTF8String("System.Runtime.WindowsRuntime.UI.Xaml");
static byte[] GetPublicKeyToken(ClrAssembly clrAsm) =>
clrAsm switch {
ClrAssembly.Mscorlib => neutralPublicKey,
ClrAssembly.SystemNumericsVectors => contractPublicKeyToken,
ClrAssembly.SystemObjectModel => contractPublicKeyToken,
ClrAssembly.SystemRuntime => contractPublicKeyToken,
ClrAssembly.SystemRuntimeInteropServicesWindowsRuntime => contractPublicKeyToken,
ClrAssembly.SystemRuntimeWindowsRuntime => neutralPublicKey,
ClrAssembly.SystemRuntimeWindowsRuntimeUIXaml => neutralPublicKey,
_ => throw new InvalidOperationException(),
};
static readonly byte[] contractPublicKeyToken = new byte[] { 0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A };
static readonly byte[] neutralPublicKey = new byte[] { 0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89 };
/// <summary>
/// Converts WinMD type <paramref name="td"/> to a CLR type. Returns <c>null</c>
/// if it's not a CLR compatible WinMD type.
/// </summary>
/// <param name="module">Owner module or <c>null</c></param>
/// <param name="td">Type</param>
/// <returns></returns>
public static TypeRef ToCLR(ModuleDef module, TypeDef td) => ToCLR(module, td, out bool isClrValueType);
/// <summary>
/// Converts WinMD type <paramref name="td"/> to a CLR type. Returns <c>null</c>
/// if it's not a CLR compatible WinMD type.
/// </summary>
/// <param name="module">Owner module or <c>null</c></param>
/// <param name="td">Type</param>
/// <param name="isClrValueType"><c>true</c> if the returned type is a value type</param>
/// <returns></returns>
public static TypeRef ToCLR(ModuleDef module, TypeDef td, out bool isClrValueType) {
isClrValueType = false;
if (td is null || !td.IsWindowsRuntime)
return null;
var asm = td.DefinitionAssembly;
if (asm is null || !asm.IsContentTypeWindowsRuntime)
return null;
if (!winMDToCLR.TryGetValue(new ClassName(td.Namespace, td.Name), out var pc))
return null;
isClrValueType = pc.ClrClass.IsValueType;
return new TypeRefUser(module, pc.ClrClass.Namespace, pc.ClrClass.Name, CreateAssembly(module, pc.ContractAssembly));
}
/// <summary>
/// Converts WinMD type <paramref name="tr"/> to a CLR type. Returns <c>null</c>
/// if it's not a CLR compatible WinMD type.
/// </summary>
/// <param name="module">Owner module or <c>null</c></param>
/// <param name="tr">Type</param>
/// <returns></returns>
public static TypeRef ToCLR(ModuleDef module, TypeRef tr) => ToCLR(module, tr, out bool isClrValueType);
/// <summary>
/// Converts WinMD type <paramref name="tr"/> to a CLR type. Returns <c>null</c>
/// if it's not a CLR compatible WinMD type.
/// </summary>
/// <param name="module">Owner module or <c>null</c></param>
/// <param name="tr">Type</param>
/// <param name="isClrValueType"><c>true</c> if the returned type is a value type</param>
/// <returns></returns>
public static TypeRef ToCLR(ModuleDef module, TypeRef tr, out bool isClrValueType) {
isClrValueType = false;
if (tr is null)
return null;
var defAsm = tr.DefinitionAssembly;
if (defAsm is null || !defAsm.IsContentTypeWindowsRuntime)
return null;
if (tr.DeclaringType is not null)
return null;
if (!winMDToCLR.TryGetValue(new ClassName(tr.Namespace, tr.Name), out var pc))
return null;
isClrValueType = pc.ClrClass.IsValueType;
return new TypeRefUser(module, pc.ClrClass.Namespace, pc.ClrClass.Name, CreateAssembly(module, pc.ContractAssembly));
}
/// <summary>
/// Converts WinMD type <paramref name="et"/> to a CLR type. Returns <c>null</c>
/// if it's not a CLR compatible WinMD type.
/// </summary>
/// <param name="module">Owner module or <c>null</c></param>
/// <param name="et">Type</param>
/// <returns></returns>
public static ExportedType ToCLR(ModuleDef module, ExportedType et) {
if (et is null)
return null;
var defAsm = et.DefinitionAssembly;
if (defAsm is null || !defAsm.IsContentTypeWindowsRuntime)
return null;
if (et.DeclaringType is not null)
return null;
if (!winMDToCLR.TryGetValue(new ClassName(et.TypeNamespace, et.TypeName), out var pc))
return null;
return new ExportedTypeUser(module, 0, pc.ClrClass.Namespace, pc.ClrClass.Name, et.Attributes, CreateAssembly(module, pc.ContractAssembly));
}
/// <summary>
/// Converts WinMD type <paramref name="ts"/> to a CLR type. Returns <c>null</c>
/// if it's not a CLR compatible WinMD type.
/// </summary>
/// <param name="module">Owner module or <c>null</c></param>
/// <param name="ts">Type</param>
/// <returns></returns>
public static TypeSig ToCLR(ModuleDef module, TypeSig ts) {
if (ts is null)
return null;
var et = ts.ElementType;
if (et != ElementType.Class && et != ElementType.ValueType)
return null;
var tdr = ((ClassOrValueTypeSig)ts).TypeDefOrRef;
TypeRef tr, newTr;
bool isClrValueType;
if (tdr is TypeDef td) {
newTr = ToCLR(module, td, out isClrValueType);
if (newTr is null)
return null;
}
else if ((tr = tdr as TypeRef) is not null) {
newTr = ToCLR(module, tr, out isClrValueType);
if (newTr is null)
return null;
}
else
return null;
return isClrValueType ?
(TypeSig)new ValueTypeSig(newTr) :
new ClassSig(newTr);
}
/// <summary>
/// Converts WinMD member reference <paramref name="mr"/> to a CLR member reference. Returns
/// <c>null</c> if it's not a CLR compatible WinMD member reference.
/// </summary>
/// <param name="module">Owner module or <c>null</c></param>
/// <param name="mr">Member reference</param>
/// <returns></returns>
public static MemberRef ToCLR(ModuleDef module, MemberRef mr) {
// See WinMDAdapter::CheckIfMethodImplImplementsARedirectedInterface
// in coreclr: md/winmd/adapter.cpp
if (mr is null)
return null;
if (mr.Name != CloseName)
return null;
var msig = mr.MethodSig;
if (msig is null)
return null;
var cl = mr.Class;
IMemberRefParent newCl;
TypeSpec ts;
if (cl is TypeRef tr) {
var newTr = ToCLR(module, tr);
if (newTr is null || !IsIDisposable(newTr))
return null;
newCl = newTr;
}
else if ((ts = cl as TypeSpec) is not null) {
var gis = ts.TypeSig as GenericInstSig;
if (gis is null || !(gis.GenericType is ClassSig))
return null;
tr = gis.GenericType.TypeRef;
if (tr is null)
return null;
var newTr = ToCLR(module, tr, out bool isClrValueType);
if (newTr is null || !IsIDisposable(newTr))
return null;
newCl = new TypeSpecUser(new GenericInstSig(isClrValueType ?
(ClassOrValueTypeSig)new ValueTypeSig(newTr) :
new ClassSig(newTr), gis.GenericArguments));
}
else
return null;
return new MemberRefUser(mr.Module, DisposeName, msig, newCl);
}
static readonly UTF8String CloseName = new UTF8String("Close");
static readonly UTF8String DisposeName = new UTF8String("Dispose");
static bool IsIDisposable(TypeRef tr) => tr.Name == IDisposableName && tr.Namespace == IDisposableNamespace;
static readonly UTF8String IDisposableNamespace = new UTF8String("System");
static readonly UTF8String IDisposableName = new UTF8String("IDisposable");
/// <summary>
/// Converts WinMD method <paramref name="md"/> to a CLR member reference. Returns
/// <c>null</c> if it's not a CLR compatible WinMD method
/// </summary>
/// <param name="module">Owner module or <c>null</c></param>
/// <param name="md">Method</param>
/// <returns></returns>
public static MemberRef ToCLR(ModuleDef module, MethodDef md) {
if (md is null)
return null;
if (md.Name != CloseName)
return null;
var declType = md.DeclaringType;
if (declType is null)
return null;
var tr = ToCLR(module, declType);
if (tr is null || !IsIDisposable(tr))
return null;
return new MemberRefUser(md.Module, DisposeName, md.MethodSig, tr);
}
}
}