Incrustar un dll dentro de otro como un recurso incrustado y luego llamarlo desde mi código

Tengo una situación en la que tengo una DLL que estoy creando que usa otra DLL de terceros, pero preferiría poder construir la DLL de terceros en mi DLL en lugar de tener que mantener ambas juntas si es posible.

Esto con C # y .NET 3.5.

La forma en que me gustaría hacer esto es almacenando la DLL de terceros como un recurso incrustado que coloco en el lugar apropiado durante la ejecución de la primera DLL.

La forma en que originalmente planeé hacer esto es escribiendo código para poner el DLL de terceros en la ubicación especificada por System.Reflection.Assembly.GetExecutingAssembly().Location.ToString() menos el último /nameOfMyAssembly.dll . Puedo guardar con éxito el .DLL terceros en esta ubicación (que termina siendo

C: \ Documents and Settings \ myUserName \ Configuración local \ Application Data \ assembly \ dl3 \ KXPPAX6Y.ZCY \ A1MZ1499.1TR \ e0115d44 \ 91bb86eb_fe18c901

), pero cuando llego a la parte de mi código que requiere esta DLL, no puede encontrarla.

¿Alguien tiene alguna idea de lo que necesito hacer diferente?

Una vez que haya incrustado el ensamblado de terceros como un recurso, agregue código para suscribirse al evento AppDomain.AssemblyResolve del dominio actual durante el inicio de la aplicación. Este evento se activa siempre que el subsistema Fusion del CLR no puede ubicar un ensamblaje de acuerdo con las pruebas (políticas) en vigencia. En el controlador de eventos para AppDomain.AssemblyResolve , cargue el recurso usando Assembly.GetManifestResourceStream y alimente su contenido como una matriz de bytes en la sobrecarga correspondiente de Assembly.Load . A continuación se muestra cómo se vería una implementación de este tipo en C #:

 AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var resName = args.Name + ".dll"; var thisAssembly = Assembly.GetExecutingAssembly(); using (var input = thisAssembly.GetManifestResourceStream(resName)) { return input != null ? Assembly.Load(StreamToBytes(input)) : null; } }; 

donde StreamToBytes podría definirse como:

 static byte[] StreamToBytes(Stream input) { var capacity = input.CanSeek ? (int) input.Length : 0; using (var output = new MemoryStream(capacity)) { int readLength; var buffer = new byte[4096]; do { readLength = input.Read(buffer, 0, buffer.Length); output.Write(buffer, 0, readLength); } while (readLength != 0); return output.ToArray(); } } 

Finalmente, como algunos ya han mencionado, ILMerge puede ser otra opción a considerar, aunque algo más involucrada.

Al final lo hice casi exactamente como sugirió Raboof (y similar a lo que sugería dgvid), excepto con algunos cambios menores y algunas omisiones corregidas. Elegí este método porque era el más cercano a lo que estaba buscando en primer lugar y no requería el uso de ningún archivo ejecutable de terceros y tal. ¡Funciona genial!

Esto es a lo que mi código terminó pareciéndose:

EDITAR: decidí mover esta función a otro ensamblaje para poder reutilizarla en varios archivos (simplemente paso en Assembly.GetExecutingAssembly ()).

Esta es la versión actualizada que le permite pasar el ensamblado con los dlls incorporados.

embeddedResourcePrefix es la ruta de acceso de cadena al recurso incrustado, normalmente será el nombre del ensamblado seguido de cualquier estructura de carpeta que contenga el recurso (por ejemplo, “MyComapny.MyProduct.MyAssembly.Resources” si el dll está en una carpeta llamada Resources in the project ) También asume que el dll tiene una extensión .dll.resource.

  public static void EnableDynamicLoadingForDlls(Assembly assemblyToLoadFrom, string embeddedResourcePrefix) { AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // had to add => try { string resName = embeddedResourcePrefix + "." + args.Name.Split(',')[0] + ".dll.resource"; using (Stream input = assemblyToLoadFrom.GetManifestResourceStream(resName)) { return input != null ? Assembly.Load(StreamToBytes(input)) : null; } } catch (Exception ex) { _log.Error("Error dynamically loading dll: " + args.Name, ex); return null; } }; // Had to add colon } private static byte[] StreamToBytes(Stream input) { int capacity = input.CanSeek ? (int)input.Length : 0; using (MemoryStream output = new MemoryStream(capacity)) { int readLength; byte[] buffer = new byte[4096]; do { readLength = input.Read(buffer, 0, buffer.Length); // had to change to buffer.Length output.Write(buffer, 0, readLength); } while (readLength != 0); return output.ToArray(); } } 

Hay una herramienta llamada IlMerge que puede lograr esto: http://research.microsoft.com/~mbarnett/ILMerge.aspx

Entonces puedes hacer un evento de comstackción similar al siguiente.

Establecer ruta = “C: \ Archivos de progtwig \ Microsoft \ ILMerge”

ilmerge /out:$(ProjectDir)\Deploy\LevelEditor.exe $ (ProjectDir) \ bin \ Release \ release.exe $ (ProjectDir) \ bin \ Release \ InteractLib.dll $ (ProjectDir) \ bin \ Release \ SpriteLib.dll $ (ProjectDir) \ bin \ Release \ LevelLibrary.dll

He tenido éxito haciendo lo que describes, pero como el archivo DLL de terceros también es un ensamblado .NET, nunca lo escribo en el disco, solo lo cargo de memoria.

Obtengo el ensamblaje de recursos incrustado como una matriz de bytes como esta:

  Assembly resAssembly = Assembly.LoadFile(assemblyPathName); byte[] assemblyData; using (Stream stream = resAssembly.GetManifestResourceStream(resourceName)) { assemblyData = ReadBytesFromStream(stream); stream.Close(); } 

Luego cargo los datos con Assembly.Load ().

Finalmente, agregué un controlador a AppDomain.CurrentDomain.AssemblyResolve para devolver mi ensamblado cargado cuando el cargador de tipos lo busca.

Consulte el .NET Fusion Workshop para obtener más detalles.

Puede lograr esto notablemente fácilmente usando Netz , un .NET NET Executables Compressor & Packer.

En lugar de escribir el ensamblado en el disco, puede intentar hacer Assembly.Load (byte [] rawAssembly) donde crea rawAssembly a partir del recurso incrustado.