C#: How to embed DLL into resourcefile (no dll

2020-05-01 02:14发布

I have a C# application (project A) that requires X.dll. I have added the project that produces X.dll to A as a reference in visual studio. I have also added the release build of X.dll to a resource file in A as a binary. I have told project A not to copy X.dll to the output directory.

Now I want A.exe to load, say "hey I can't find this file", then look in the resource file and use Assembly.Load(byte[]) get X.dll back. I have the code that re-magicifies the DLL back, however this code never get called.

Currently I have a bone simple project, just trying to get it to work. It compile OK. When I run it, I get a FileNotFoundException on X.dll.

I have:

[STAThread]
static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

But the breakpoint in *CurrentDomain_AssemblyResolve* never gets hit. I get a FileNotFoundException immediately. Surely there is something I a missing?

1条回答
虎瘦雄心在
2楼-- · 2020-05-01 02:36

This question seems to be very similar to what you are trying to achieve, and it worked for the asker.

Merge .dll into C# Assembly?

Are you doing something differently? Specifically, if you're targetting an older version of the .NET Framework, maybe that's a hint for understanding why your application is behaving differently.

Another direction, use a tool such as Fusion Log Viewer to analyze what was going on when you tried to load the assembly. This may give some more hints. If you manage to get log information, posting it in the question may help someone figure it out.

EDIT: Another explanation, following your comment.

Well, now I think I know what the problem is.

In your Main method, you are refering to the type in the other dll. But you are doing it in static code, i.e. you use the type explicitly in the code (as opposed to loading it dynamically by its name).

Why is this a problem? The CLR tries to load your assembly in order to JIT Main itself.

Your FileNotFoundException was thrown while Main was being compiled. Main didn't even start running, and therefore your event handler wasn't registered.

A simple way to check if I'm right is to change the code to something like this:

static public void Main(string[] args)
{
    AppDomain.CurrentDomain.AssemblyResolve += MyEventHandler;
    MyMain();
}

// The CLR will actually try to load your assembly before even starting the execution
// of this method. It needs the assembly in order to JIT the method because it has to 
// know the Thing type.
static public void MyMain()
{
    using(var thing = new Thing())
    {
         // ...
    }
}

The important difference is that Main has no dependency on another assembly, so there will be no problem to JIT and run it.

By the time MyMain is being JIT'ed, your event handler is already in place so you can manually load the assembly.

By the way, to avoid another possible similar pitfall, make sure that the class in which Main is defined doesn't have any field with a type from the other assembly, because in this case also, the CLR will try loading the assembly before Main starts, in order to compile it.

查看更多
登录 后发表回答