ITypeDefOrRef GetScopeType(TypeSig typeSig) { if (typeSig == null) return null; if (!recursionCounter.Increment()) return null; ITypeDefOrRef result; var old = genericArguments; typeSig = ReplaceGenericArg(typeSig); switch (typeSig.ElementType) { case ElementType.Void: case ElementType.Boolean: case ElementType.Char: case ElementType.I1: case ElementType.U1: case ElementType.I2: case ElementType.U2: case ElementType.I4: case ElementType.U4: case ElementType.I8: case ElementType.U8: case ElementType.R4: case ElementType.R8: case ElementType.String: case ElementType.TypedByRef: case ElementType.I: case ElementType.U: case ElementType.Object: case ElementType.ValueType: case ElementType.Class: result = GetScopeType(((TypeDefOrRefSig)typeSig).TypeDefOrRef); break; case ElementType.Ptr: case ElementType.ByRef: case ElementType.Array: case ElementType.SZArray: case ElementType.CModReqd: case ElementType.CModOpt: case ElementType.Pinned: case ElementType.ValueArray: case ElementType.Module: result = GetScopeType(typeSig.Next); break; case ElementType.GenericInst: var genericInstSig = (GenericInstSig)typeSig; var genericType = genericInstSig.GenericType; result = GetScopeType(genericType == null ? null : genericType.TypeDefOrRef); break; case ElementType.Var: case ElementType.MVar: result = new TypeSpecUser(typeSig); break; case ElementType.FnPtr: case ElementType.Sentinel: case ElementType.End: case ElementType.R: case ElementType.Internal: default: result = null; break; } genericArguments = old; recursionCounter.Decrement(); return result; }
public static void Run() { // This is the file that will be created string newFileName = @"GenericExample1.exe"; // Create the module var mod = new ModuleDefUser("GenericExample1", Guid.NewGuid(), new AssemblyRefUser(new AssemblyNameInfo(typeof(int).Assembly.GetName().FullName))); // It's a console app mod.Kind = ModuleKind.Console; // Create the assembly and add the created module to it new AssemblyDefUser("GenericExample1", new Version(1, 2, 3, 4)).Modules.Add(mod); // Add the startup type. It derives from System.Object. TypeDef startUpType = new TypeDefUser("My.Namespace", "Startup", mod.CorLibTypes.Object.TypeDefOrRef); startUpType.Attributes = TypeAttributes.NotPublic | TypeAttributes.AutoLayout | TypeAttributes.Class | TypeAttributes.AnsiClass; // Add the type to the module mod.Types.Add(startUpType); // Create the entry point method MethodDef entryPoint = new MethodDefUser("Main", MethodSig.CreateStatic(mod.CorLibTypes.Int32, new SZArraySig(mod.CorLibTypes.String))); entryPoint.Attributes = MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot; entryPoint.ImplAttributes = MethodImplAttributes.IL | MethodImplAttributes.Managed; // Name the 1st argument (argument 0 is the return type) entryPoint.ParamDefs.Add(new ParamDefUser("args", 1)); // Add the method to the startup type startUpType.Methods.Add(entryPoint); // Set module entry point mod.EntryPoint = entryPoint; // Create System.Console type reference var systemConsole = mod.CorLibTypes.GetTypeRef("System", "Console"); // Create 'void System.Console.WriteLine(string,object)' method reference var writeLine2 = new MemberRefUser(mod, "WriteLine", MethodSig.CreateStatic(mod.CorLibTypes.Void, mod.CorLibTypes.String, mod.CorLibTypes.Object), systemConsole); // // Method 1: Create List<String> inst signature by importing (easy way) // -------------------------------------------------------------------- //Importer importer = new Importer(mod); //var listGenericInstSig = importer.ImportAsTypeSig(typeof(System.Collections.Generic.List<String>)); // // Method 2: Create List<String> inst signature manually (harder way) // ------------------------------------------------------------------ var assemblyRef = mod.CorLibTypes.AssemblyRef; var listRef = new TypeRefUser(mod, @"System.Collections.Generic", "List`1", assemblyRef); // Create the GenericInstSig from a ClassSig with <String> generic arg var listGenericInstSig = new GenericInstSig(new ClassSig(listRef), mod.CorLibTypes.String); // Create TypeSpec from GenericInstSig var listTypeSpec = new TypeSpecUser(listGenericInstSig); // Create System.Collections.Generic.List<String>::.ctor method reference var listCtor = new MemberRefUser(mod, ".ctor", MethodSig.CreateInstance(mod.CorLibTypes.Void), listTypeSpec); // Create Add(!0) method reference, !0 signifying first generic argument of declaring type // In this case, would be Add(String item) // (GenericMVar would be used for method generic argument, such as Add<!!0>(!!0)) var listAdd = new MemberRefUser(mod, "Add", MethodSig.CreateInstance(mod.CorLibTypes.Void, new GenericVar(0)), listTypeSpec); var listGetCount = new MemberRefUser(mod, "get_Count", MethodSig.CreateInstance(mod.CorLibTypes.Int32), listTypeSpec); IList<Local> locals = new List<Local>(); locals.Add(new Local(listGenericInstSig)); // local[0]: class [mscorlib]System.Collections.Generic.List`1<string> var body = new CilBody(true, new List<Instruction>(), new List<ExceptionHandler>(), locals); // Call the list .ctor body.Instructions.Add(OpCodes.Newobj.ToInstruction(listCtor)); body.Instructions.Add(OpCodes.Stloc_0.ToInstruction()); // Store list to local[0] // list.Add("Item 1") body.Instructions.Add(OpCodes.Ldloc_0.ToInstruction()); body.Instructions.Add(OpCodes.Ldstr.ToInstruction("Item 1")); body.Instructions.Add(OpCodes.Callvirt.ToInstruction(listAdd)); // WriteLine("Array: {0}", list.ToArray()); //body.Instructions.Add(OpCodes.Ldstr.ToInstruction("Array: {0}")); //body.Instructions.Add(OpCodes.Ldloc_0.ToInstruction()); // Load list from local[0] //body.Instructions.Add(OpCodes.Callvirt.ToInstruction(listToArray)); //body.Instructions.Add(OpCodes.Call.ToInstruction(writeLine2)); // WriteLine("Count: {0}", list.Count) body.Instructions.Add(OpCodes.Ldstr.ToInstruction("Count: {0}")); body.Instructions.Add(OpCodes.Ldloc_0.ToInstruction()); // Load list from local[0] body.Instructions.Add(OpCodes.Callvirt.ToInstruction(listGetCount)); body.Instructions.Add(OpCodes.Box.ToInstruction(mod.CorLibTypes.Int32)); body.Instructions.Add(OpCodes.Call.ToInstruction(writeLine2)); // return 0; body.Instructions.Add(OpCodes.Ldc_I4_0.ToInstruction()); body.Instructions.Add(OpCodes.Ret.ToInstruction()); entryPoint.Body = body; // Save the assembly mod.Write(newFileName); }
/// <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 == null) { return(null); } if (mr.Name != CloseName) { return(null); } var msig = mr.MethodSig; if (msig == null) { return(null); } var cl = mr.Class; IMemberRefParent newCl; TypeRef tr; TypeSpec ts; if ((tr = cl as TypeRef) != null) { var newTr = ToCLR(module, tr); if (newTr == null || !IsIDisposable(newTr)) { return(null); } newCl = newTr; } else if ((ts = cl as TypeSpec) != null) { var gis = ts.TypeSig as GenericInstSig; if (gis == null || !(gis.GenericType is ClassSig)) { return(null); } tr = gis.GenericType.TypeRef; if (tr == null) { return(null); } bool isClrValueType; var newTr = ToCLR(module, tr, out isClrValueType); if (newTr == 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)); }
public static void Run() { // This is the file that will be created string newFileName = @"GenericExample2.exe"; // Create the module var mod = new ModuleDefUser("GenericExample2", Guid.NewGuid(), new AssemblyRefUser(new AssemblyNameInfo(typeof(int).Assembly.GetName().FullName))); // It's a console app mod.Kind = ModuleKind.Console; // Create the assembly and add the created module to it new AssemblyDefUser("GenericExample2", new Version(1, 2, 3, 4)).Modules.Add(mod); // Add the startup type. It derives from System.Object. TypeDef startUpType = new TypeDefUser("My.Namespace", "Startup", mod.CorLibTypes.Object.TypeDefOrRef); startUpType.Attributes = TypeAttributes.NotPublic | TypeAttributes.AutoLayout | TypeAttributes.Class | TypeAttributes.AnsiClass; // Add the type to the module mod.Types.Add(startUpType); // Create the entry point method MethodDef entryPoint = new MethodDefUser("Main", MethodSig.CreateStatic(mod.CorLibTypes.Int32, new SZArraySig(mod.CorLibTypes.String))); entryPoint.Attributes = MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot; entryPoint.ImplAttributes = MethodImplAttributes.IL | MethodImplAttributes.Managed; // Name the 1st argument (argument 0 is the return type) entryPoint.ParamDefs.Add(new ParamDefUser("args", 1)); // Add the method to the startup type startUpType.Methods.Add(entryPoint); // Set module entry point mod.EntryPoint = entryPoint; // Create System.Console type reference var systemConsole = mod.CorLibTypes.GetTypeRef("System", "Console"); // Create 'void System.Console.WriteLine(string,object)' method reference var writeLine2 = new MemberRefUser(mod, "WriteLine", MethodSig.CreateStatic(mod.CorLibTypes.Void, mod.CorLibTypes.String, mod.CorLibTypes.Object), systemConsole); var assemblyRef = mod.CorLibTypes.AssemblyRef; // Create 'System.Collections.ObjectModel.ReadOnlyCollection`1' type ref var roCollectionRef = new TypeRefUser(mod, "System.Collections.ObjectModel", "ReadOnlyCollection`1", assemblyRef); // Create 'ReadOnlyCollection<!!0>' signature for return type var roCollectionSig = new GenericInstSig(new ClassSig(roCollectionRef), new GenericMVar(0)); // Return type // Create 'ReadOnlyCollection<Int32>' type spec var roCollectionTypeSpec = new TypeSpecUser(new GenericInstSig(new ClassSig(roCollectionRef), mod.CorLibTypes.Int32)); // Create 'ReadOnlyCollection<Int32>.get_Count()' method reference var roCollectionGetCount = new MemberRefUser(mod, "get_Count", MethodSig.CreateInstance(mod.CorLibTypes.Int32), roCollectionTypeSpec); // Create 'System.Array' type ref var arrayRef = new TypeRefUser(mod, "System", "Array", assemblyRef); // Create 'ReadOnlyCollection<T> Array.AsReadOnly<T>(T[] array)' method reference // Apparently CreateStaticGeneric should be used only if at least one GenericMVar is used? Not 100% certain. var asReadOnly = new MemberRefUser(mod, "AsReadOnly", MethodSig.CreateStaticGeneric(1, roCollectionSig, new SZArraySig(new GenericMVar(0))), arrayRef); // Create 'Array.AsReadOnly<Int32>' method spec var asReadOnlySpec = new MethodSpecUser(asReadOnly, new GenericInstMethodSig(mod.CorLibTypes.Int32)); // Create 'ReadOnlyCollection<Int32>' signature for local var roCollectionInt32 = roCollectionTypeSpec.TryGetGenericInstSig(); // Method body locals IList<Local> locals = new List<Local>(); locals.Add(new Local(new SZArraySig(mod.CorLibTypes.Int32))); // local[0]: Int32[] locals.Add(new Local(roCollectionInt32)); // local[1]: class [mscorlib]System.Collections.ObjectModel.ReadOnlyCollection`1<Int32> var body = new CilBody(true, new List<Instruction>(), new List<ExceptionHandler>(), locals); // array = new Int32[2]; body.Instructions.Add(OpCodes.Ldc_I4_2.ToInstruction()); body.Instructions.Add(OpCodes.Newarr.ToInstruction(mod.CorLibTypes.Int32)); body.Instructions.Add(OpCodes.Stloc_0.ToInstruction()); // Store array to local[0] // array[0] = 5; body.Instructions.Add(OpCodes.Ldloc_0.ToInstruction()); body.Instructions.Add(OpCodes.Ldc_I4_0.ToInstruction()); body.Instructions.Add(OpCodes.Ldc_I4_5.ToInstruction()); body.Instructions.Add(OpCodes.Stelem_I4.ToInstruction()); // array[1] = 111; body.Instructions.Add(OpCodes.Ldloc_0.ToInstruction()); body.Instructions.Add(OpCodes.Ldc_I4_1.ToInstruction()); body.Instructions.Add(OpCodes.Ldc_I4.ToInstruction(111)); body.Instructions.Add(OpCodes.Stelem_I4.ToInstruction()); // collection = Array.AsReadOnly<Int32>(array) body.Instructions.Add(OpCodes.Ldloc_0.ToInstruction()); body.Instructions.Add(OpCodes.Call.ToInstruction(asReadOnlySpec)); body.Instructions.Add(OpCodes.Stloc_1.ToInstruction()); // Console.WriteLine("Count: {0}", collection.Count) body.Instructions.Add(OpCodes.Ldstr.ToInstruction("Count: {0}")); body.Instructions.Add(OpCodes.Ldloc_1.ToInstruction()); body.Instructions.Add(OpCodes.Callvirt.ToInstruction(roCollectionGetCount)); body.Instructions.Add(OpCodes.Box.ToInstruction(mod.CorLibTypes.Int32)); body.Instructions.Add(OpCodes.Call.ToInstruction(writeLine2)); // return 0; body.Instructions.Add(OpCodes.Ldc_I4_0.ToInstruction()); body.Instructions.Add(OpCodes.Ret.ToInstruction()); entryPoint.Body = body; // Save the assembly mod.Write(newFileName); }