i’m currently struggeling with the CodeDOM code generator and executing compiled assemblies.
Everything works like a charm, except running the compiled code a second time.
Settings
The user “programs” a model which will be translated into a executable program. The user can define whether the assembly should created in memory only or on disc, whether to have source code or only an executable. When he clicks the “run” button, the CodeDOM tree is put together and compiled, written out to disc (if needed) and executed.
Exception
When he clicks the “run” button a second time, an exception is thrown:
error CS0016: Unable to write to output file ”: —
“The process cannot access the file because it is being used by
another process.”
As I can compile the code as often as I want without encountering the error, I would suggest it has something to do how I run the assembly. I searched the web for information on this topic, but all I came up was creating a separate AppDomain and unloading it afterwards.
Here is the snippet which executes the assembly:
if ( RunProject )
{
_log.info( "Compiled without errors, running..." );
Assembly compiledAssembly = res.CompiledAssembly;
AppDomain compiledAssemblyDomain = AppDomain.CreateDomain( "compiledAssemblyDomain" );
compiledAssemblyDomain.ExecuteAssemblyByName( compiledAssembly.GetName( ) );
AppDomain.Unload( compiledAssemblyDomain );
}
The executable file can only be removed if I quit the program, as if the file is locked by the current appdomain. What to do? Thanks for your help!
Update
When the above code executes, the main file is loaded into the executing assembly (or am I wrong?). The debugging console caputes the following information:
[13:42:19.5576171] i Compiled without errors, running...
'XXX.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\...\bin\main.exe'
and just a few seconds after quitting the executed assembly:
The thread '.NET SystemEvents' (0x20d0) has exited with code 0 (0x0).
The thread '<No Name>' (0x1d20) has exited with code 0 (0x0).
where XXX is the name of my main application compiling the code. Shouldn’t the file loaded somewhere else? Doesn’t XXX.vshost.exe open a handle and don’t close it after unloading the AppDomain?
I have wrestled with this quite a bit (I did something similar with Scrolling Game Development Kit 2). You have to be very carefully to make sure that everything you do with that compiled code happens within that other AppDomain so that when you unload that AppDomain, all references to the DLL are unloaded with it. If you so much as refer to a type from the compiled code, that DLL will get loaded into your AppDomain as well and unloading the other domain will do no good. So what I have had to do was define interfaces in a common DLL which can get loaded into both domains so that I can call functions in the other DLL without loading types from the other DLL. Just make sure that every object you instantiate in the other DLL uses an interface defined in the shared DLL (or another public interface not defined in the user-defined DLL). Then cast each object you instantiate from that DLL to one of those interfaces. You can never use the types defined in that DLL directly.
EDIT: Observe the following note from MSDN documentation about the CompiledAssembly Property