4

I decided to leave my other question to die, since I thought of a new idea using Jeffrey Richter's method written on this page to merge a .dll library to my application. So I added my .dll file as an embedded resource and also added it as a reference. Then in Program.cs (I have no idea where the code he posted is supposed to go), I added this:

    ...
    [STAThread]
    static void Main()
    {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            string[] args = Environment.GetCommandLineArgs();
            if (args.Length > 1)
                _in = args[1];
            SingleInstanceController controller = new SingleInstanceController();
            controller.Run(args);

            AppDomain.CurrentDomain.AssemblyResolve += (sender, argsx) =>
{
String resourceName = "AssemblyLoadingAndReflection." +
   new AssemblyName(argsx.Name).Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
    Byte[] assemblyData = new Byte[stream.Length];
    stream.Read(assemblyData, 0, assemblyData.Length);
    return Assembly.Load(assemblyData);
    }
}
        ;

Am I supposed to change resourceName to something else? Have I added it correctly (in the right place)?

Now the problem is, it still fails to find and load the assembly and I'm not sure what I've done wrong. Any help would be appreciated.

Community
  • 1
  • 1
Iceyoshi
  • 623
  • 3
  • 10
  • 14
  • 2
    Just curious; why even bother to (effectively) statically link a DLL? – Ed S. Jan 09 '11 at 06:59
  • 3
    Because I don't want to distribute my program will 10-15 files the user finds useless. – Iceyoshi Jan 09 '11 at 07:12
  • 2
    Why is the user digging around in program files anyway? Just install them into a sub-directory and be done with it. I mean, the "DL" in "DLL" stands for "Dynamic Link" you know. – Ed S. Jan 09 '11 at 08:17

3 Answers3

3

Your problem is very similar to this one: C#: How to embed DLL into resourcefile (no dll copy in program directory)

Basically, your AppDomain.AssemblyResolve event handler did not get called because Main failed to compile. Even if it did compile, attaching the event handler should be the first thing you do in main.

My answer to the question above has a working code sample and explanation on why your code does not work.

Community
  • 1
  • 1
Ran
  • 5,989
  • 1
  • 24
  • 26
2

Use the debugger. Set breakpoints on the AssemblyResolve assignment and the lambda body. Single step the code.

Yes, that's too late. Move the assignment. If SingleInstanceController is in such a DLL then the Main() method never even gets started. Move that code into a separate helper method and give it the [MethodImpl(MethodImplOptions.Noinlining)] attribute.

Distributing your program in a single file is already very well supported, it doesn't require any code nor merging DLLs. Also takes care of the desktop shortcut, the file associations and getting .NET installed on old machines. It's called setup.exe

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 2
    Yeah, thanks for totally ignoring my question. I asked why my code wasn't working or what I was doing wrong, not "should I distribute .dll files with my application or not". I have my reasons for not distributing the .EXE file with a bunch of .dll files. Also, where did setup.exe come from? My application is a relatively small and portable one and I don't even want to use that. – Iceyoshi Jan 09 '11 at 07:11
  • I didn't ignore your question, you ignored the answer. Do try to read more than just the last paragraph. You won't get the perfect answer until you debug your problem. – Hans Passant Jan 09 '11 at 07:19
  • "until you debug your problem" <- which I needed help with, hence I asked here. You are right in the sense I ignored your first paragraph though. – Iceyoshi Jan 09 '11 at 07:34
  • Is the issue that you don't know how to use the debugger? What did happen when you single stepped the program? I gave the answer but you can't see it in front of your eyes until you try this. – Hans Passant Jan 09 '11 at 07:47
  • I avoid using the debugger as much as possible and this isn't an exception. Also, I figured out the problem myself with help from the answer below and got it to work. – Iceyoshi Jan 09 '11 at 09:46
  • 3
    "I avoid using the debugger as much as possible". I can't believe i just read that... – Phill Jan 09 '11 at 10:05
1

Hook to the AssemblyResolve event before the AppDomain tries to resolve references i.e in the entry point and the first line.

The embedded resource name starts with the application name followed by the resource name. ex: ConsoleApplication.Test.dll.

Vijay Sirigiri
  • 4,653
  • 29
  • 31
  • I'm not quite sure what you mean by your first line, could you explain? (Sorry I'm kind of new to C# and don't have much experience). – Iceyoshi Jan 09 '11 at 07:19
  • Move the AppDomain.CurrentDomain.AssemblyResolve += .... to the first line in Main method. – Vijay Sirigiri Jan 09 '11 at 07:21
  • I get this error: "Could not load file or assembly 'Files, Version=2.3.4025.2210, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Invalid pointer (Exception from HRESULT: 0x80004003 (E_POINTER))" when I do that, and rename my resource name. – Iceyoshi Jan 09 '11 at 07:29
  • replace String resourceName = "AssemblyLoadingAndReflection." + new AssemblyName(argsx.Name).Name + ".dll"; with String resourceName = String.Format("MyApp.{0}", args.Name); – Vijay Sirigiri Jan 09 '11 at 07:32
  • The error still remains, even when I added String resourceName = String.Format("MyApp.{0}", args.Name) + ".dll"; too. It's definitely indicating that it can't find the assembly but I can't think of any reason why it would do that. I added a reference to that file and also embedded it and moved the code to the first line as you stated. – Iceyoshi Jan 09 '11 at 07:46
  • What is your application name? If it is not MyApp (as in the String.Format line),put that instead. – Vijay Sirigiri Jan 09 '11 at 07:49
  • That's what I did. It's called ASMPad and I renamed it to that. – Iceyoshi Jan 09 '11 at 07:56
  • Not sure why it doesn't work for you. Put a breakpoint (f9) inside the AssemblyResolve event handler and check the args. Also running the FusionLogViewer might help. (http://blogs.msdn.com/b/suzcook/archive/2003/05/29/57120.aspx) – Vijay Sirigiri Jan 09 '11 at 08:06
  • I got it to work. It turns out the assembly had to be called Files.dll only. Not sure why though. I'm marking this answer correct because it did help a lot. – Iceyoshi Jan 09 '11 at 09:44
  • @Iceyoshi could you explain how did you resolve your issue a bit more?? im running trough the same problem as you did. thanks in advance for any help – dalexsoto Mar 21 '11 at 19:33
  • @Iceyoshi If you could share a piece of code would be awesome – dalexsoto Mar 21 '11 at 19:38