Embedding DLLs in a compiled executable

前端 未结 16 3174
情深已故
情深已故 2020-11-21 07:07

Is it possible to embed a pre-existing DLL into a compiled C# executable (so that you only have one file to distribute)? If it is possible, how would one go about doing it?<

16条回答
  •  南旧
    南旧 (楼主)
    2020-11-21 07:54

    Neither the ILMerge approach nor Lars Holm Jensen's handling the AssemblyResolve event will work for a plugin host. Say executable H loads assembly P dynamically and accesses it via interface IP defined in an separate assembly. To embed IP into H one shall need a little modification to Lars's code:

    Dictionary loaded = new Dictionary();
    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
    {   Assembly resAssembly;
        string dllName = args.Name.Contains(",") ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");
        dllName = dllName.Replace(".", "_");
        if ( !loaded.ContainsKey( dllName ) )
        {   if (dllName.EndsWith("_resources")) return null;
            System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
            byte[] bytes = (byte[])rm.GetObject(dllName);
            resAssembly = System.Reflection.Assembly.Load(bytes);
            loaded.Add(dllName, resAssembly);
        }
        else
        {   resAssembly = loaded[dllName];  }
        return resAssembly;
    };  
    

    The trick to handle repeated attempts to resolve the same assembly and return the existing one instead of creating a new instance.

    EDIT: Lest it spoil .NET's serialization, make sure to return null for all assemblies not embedded in yours, thereby defaulting to the standard behaviour. You can get a list of these libraries by:

    static HashSet IncludedAssemblies = new HashSet();
    string[] resources = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();
    for(int i = 0; i < resources.Length; i++)
    {   IncludedAssemblies.Add(resources[i]);  }
    

    and just return null if the passed assembly does not belong to IncludedAssemblies .

提交回复
热议问题