Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I need an alternative to `Assembly.GetEntryAssembly()` that never returns null

I need to find the assembly in which managed code execution started.

// using System.Reflection; Assembly entryAssembly = Assembly.GetEntryAssembly(); 

This seems like the way to go, but the MSDN reference page for Assembly.GetEntryAssembly states that this method "[c]an return null when called from unmanaged code."

In that case, I would like to know which assembly was called by unmanaged code.

Is there a reliable way of doing this, i.e. one that always returns a non-null Assembly reference?

like image 743
stakx - no longer contributing Avatar asked Jan 04 '13 22:01

stakx - no longer contributing


2 Answers

The best I could think of so far is the following, which should work in a single-threaded scenario:

// using System.Diagnostics; // using System.Linq;  Assembly entryAssembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly; 

(The above snippet is optimized for ease of understanding, not for execution speed or memory efficiency.)

like image 73
stakx - no longer contributing Avatar answered Sep 26 '22 12:09

stakx - no longer contributing


I tried both methods of stakx.

Method based on MainModule does not work in some special cases (dynamic assemblies for example).

Method based on StackTrace can return an assembly too high (or low) in the hierarchy, like mscorlib.

I made a little variant which works well in my use cases :

// using System.Diagnostics; // using System.Linq; var methodFrames = new StackTrace().GetFrames().Select(t => t?.GetMethod()).ToArray(); MethodBase entryMethod = null; int firstInvokeMethod = 0; for (int i = 0; i < methodFrames.Length; i++) {     var method = methodFrames[i] as MethodInfo;     if (method == null)         continue;     if (method.IsStatic &&         method.Name == "Main" &&         (             method.ReturnType == typeof(void) ||              method.ReturnType == typeof(int) ||             method.ReturnType == typeof(Task) ||             method.ReturnType == typeof(Task<int>)         ))     {         entryMethod = method;     }     else if (firstInvokeMethod == 0 &&         method.IsStatic &&         method.Name == "InvokeMethod" &&         method.DeclaringType == typeof(RuntimeMethodHandle))     {         firstInvokeMethod = i;     } }  if (entryMethod == null)     entryMethod = firstInvokeMethod != 0 ? methodFrames[firstInvokeMethod - 1] : methodFrames.LastOrDefault();  Assembly entryAssembly = entryMethod?.Module?.Assembly; 

Basically, I walk the stack up until I find a conventional method named "Main" with void or int return type. If no such method is found, I look for a method invoked via reflection. For example, NUnit uses that invocation to load unit tests.

Of course, I do that only if Assembly.GetEntryAssembly() returns null.

like image 42
Eric Boumendil Avatar answered Sep 26 '22 12:09

Eric Boumendil