How to change a c# console application's entry point?
Asked Answered
P

4

6

I am wondering whether it is possible to change a .NET console application entry point from Main to Main2 method in the example below:

class Program
{ 
    static void Main(string[] args)
    {
        Console.WriteLine("Main");
    }

    //desired entry point
    static void Main2(string[] args)
    {
        Console.WriteLine("Main2");
    }
}

I investigated an IL code of those two. Here is Main method:

  .method private hidebysig static void 
    Main(
      string[] args
    ) cil managed 
  {
    .entrypoint
    .maxstack 8

    // other instructions

  } // end of method Program::Main

And the Main2 method:

.method private hidebysig static void 
    Main2(
      string[] args
    ) cil managed 
  {
    .maxstack 8

    //other instructions
  } // end of method Program::Main2

The only difference is precense of the .entrypoint instruction in the Main method, which is - as far as I understand - detected by CLR when application is started.

Is there any way to influence csc to mark other method with this instruction? Can other compilers do the trick?

EDIT My question is different from this one, because I am asking about csc compiler (and other complilers) behavior... specifically how to put the .entrypoint instruction in the other place

Phyletic answered 14/10, 2018 at 7:48 Comment(9)
@Caramiriel yes, this can be done even with visual studio. My question is more about a possibility to mark a method with different signature as an entry pointPhyletic
Could you give more context to this? Are you trying to do this without having to postprocess the generated code? What's the purpose of using Main2 instead of Main? At the moment this feels like an XY problem.Riproaring
Alright, I think you should be able to, but not with the csc compiler. blogs.msdn.microsoft.com/vijaysk/2006/11/30/a-tryst-with-msil Ilasm.exe is what you'll need, but I doubt it is any more practical than just adding a new class with a main method.Gaffney
Possible duplicate of C# entry point functionEgbert
The comment by Caramiriel that you responded to seems to have been deleted, so I apologize if I'm asking the same question, but: are you asking out of curiosity, or is there a practical reason? Because there are other ways to do it within the language - depending on what you are trying to do, you could call Main2 from Main, or use preprocessor symbols (conditional compilation), or use the -main option mentioned in Richard's answer, or even do it at runtime by calling a different method from Main based on a parameter.Foran
@FilipMilovanović I don't have a practical interest as of now, just curiousPhyletic
@Gaffney I'll check this, thxPhyletic
The entrypoint is just a Token for the MethodDef or File of the entry point for the image in the CLI-Header, see ECMA-335 II.25.3.3. As you already have found, the ilasm compiler lets you define the entrypoint using the .entrypoint directive. II.15.4.1.2 tells you what constraints are present for entrypoints.Denims
@Phyletic Could you also answer JonSkeet's question? It's highly unlikely that you really need this.Gaffney
P
5

This can be achieved by using AssemblyBuilder and other stuff from the System.Reflection library.

AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"),AssemblyBuilderAccess.Save);
TypeBuilder typeBuilder = assemblyBuilder.DefineDynamicModule("Module","Test.exe",false).DefineType("Program",TypeAttributes.Public);
MethodBuilder methodBuilder = typeBuilder.DefineMethod("Main2",MethodAttributes.Public|MethodAttributes.Static);
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.EmitWriteLine("Main2");
ilGenerator.Emit(OpCodes.Ret);
assemblyBuilder.SetEntryPoint(methodBuilder);
typeBuilder.CreateType();
assemblyBuilder.Save("Test.exe");

This produces the following IL code (.entryPoint is placed on Main2 method):

.method public static 
void Main2 () cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 11 (0xb)
    .maxstack 1
    .entrypoint

    IL_0000: ldstr "Main2"
    IL_0005: call void [mscorlib]System.Console::WriteLine(string)
    IL_000a: ret
} // end of method Program::Main2

If you execute Test.exe you'll see that the Main2 method is executed

Phyletic answered 18/10, 2018 at 20:35 Comment(1)
Sure, but you asked specifically about doing it with csc.exe. In this code sample you are using AssemblyBuilder.Across
B
2

The method does have to be called Main, but you can use the -main option to designate which class's Main method is the entry point.

(The use of Main as the entry point is part of the definition of C# – in the C# v5 specification it is in §3.1, you might be able to overcome this but you would be on your own.)

Begorra answered 14/10, 2018 at 7:54 Comment(0)
H
2

This is not possible, by definition Main is the entry point of a C# application.

The Main method is the entry point of a C# application. (Libraries and services do not require a Main method as an entry point.) When the application is started, the Main method is the first method that is invoked.

Source: MSDN

Haihaida answered 14/10, 2018 at 7:56 Comment(0)
S
2

The entry point must be named Main, as specified by the C# language specification §3.1:

3.1 Application Startup

Application startup occurs when the execution environment calls a designated method, which is referred to as the application's entry point. This entry point method is always named Main, and can have one of the following signatures:

static void Main() {...}
static void Main(string[] args) {...}
static int Main() {...}
static int Main(string[] args) {...}

See the words "is always named Main"? If you changed your entry point to something other than Main by writing another compiler, that compiler wouldn't be a C# compiler by definition. :)

Stila answered 14/10, 2018 at 8:4 Comment(3)
also static async Task Main(string[] args) ;)Militant
@Militant I wonder why that signature isn't on the spec... The spec I am quoting here is the 5.0 one. async definitely exists back then.Stila
i think it was C# 7.x that supported it, and i don't think the official specs are available for it yetMilitant

© 2022 - 2025 — McMap. All rights reserved.