Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I feed a loaded Assembly to a Roslyn Workspace in C#

I am enhancing an existing process with runtime code generation. The code I am creating at runtime needs access to some of the same dlls that the process creating the code is already referencing.

Problem is that the process runs within some 3rd party software that loads dlls from resources and injects them into my process... thus I do not have access to either a dll on disk nor to the resource that contained the dll in the external wrapper.

As a result I am trying to use the assemblies I already have in memory and feed them into the Roslyn workspace into which I place my runtime code for compilation. I thought I could try serializing the Assembly with a binary formatter as per this SO: Opposite operation to Assembly Load(byte[] rawAssembly)

But even if I pretty much take the code as is:

Assembly yourAssembly = typeof(object).Assembly;
var formatter = new BinaryFormatter();
var ms = new MemoryStream();
formatter.Serialize(ms, yourAssembly);
var reloadedAssembly = Assembly.Load(ms.GetBuffer());

I get:

An exception of type 'System.BadImageFormatException' occurred in mscorlib.dll but was not handled in user code

None of the other search results seemed any better.

What I want to do is something like:

var assemblyRef = MetadataReference.CreateFromAssembly(typeof(object).Assembly);
mySolution.AddMetadataReference(projectId, assemblyRef);

Any suggestions?

like image 279
Wizbit Avatar asked Nov 09 '22 06:11

Wizbit


1 Answers

For a managed assembly loaded using Assembly.Load(byte[]) you can create a Roslyn MetadataReference like so:

var assembly = Assembly.Load(bytes);
var modulePtr = Marshal.GetHINSTANCE(assembly.ManifestModule);

var peReader = new PEReader((byte*)modulePtr, bytes.Length))
var metadataBlock = peReader.GetMetadata();
var moduleMetadata = ModuleMetadata.CreateFromMetadata((IntPtr)metadataBlock.Pointer, metadataBlock.Length);
var assemblyMetadata = AssemblyMetadata.Create(moduleMetadata);
var reference = assemblyMetadata.GetReference();

Note that this doesn't work for assemblies loaded from a file, since the layout in the memory is different.

like image 80
user7183509 Avatar answered Nov 14 '22 23:11

user7183509