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;
		}
Example #2
0
        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));
        }
Example #4
0
        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);
        }