I would like to load a dll file (Test.dll) as an assembly. I am able to do this using both direct Visual Studio references (ie. loading the dll as a reference to my C# application) as well as loading the dll using the Assembly.LoadFile(filename) method. Now, I would like to add my dll file as an embedded resource to my Visual Studio application, and load the dll file as an assembly. I know how to load this resource as a byte array, is there some correlation between the byte array and the assembly that I could use? Furthermore, I need to be able to call a method located within the dll file. See the code below - it will further explain what I am doing.
Assembly SampleAssembly = Assembly.LoadFrom("WindowsFormsApplication2.ThisisaTESTDLL.dll");
Type myType = SampleAssembly.GetTypes()[0];
MethodInfo Method = myType.GetMethod("myVoid");
object myInstance = Activator.CreateInstance(myType,null);
Method.Invoke(myInstance,new object[] { "param1", "param1"});
If I am missing anything here, please respectfully let me know and I will edit the original post.
Assembly.GetExecutingAssembly().GetManifestResourceStream(...)
That should get you a Stream object. You can read a byte array from that.
You can load that using Assembly.Load
I embedded AxInterop.WMPLib.dll and Interop.WMPLib.dll into my exe and got them loaded by using the following code. The code is placed just at the beginning of static void Main() in Program.cs file. Target framework is .NET 3.5 in my case. This code helped me bundle the dlls into the exe itself without having to deploy them through installers. I have hardcoded my names. In the code below "res" is the name of my resource "res.resx" that contains the two embedded dlls.
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(
(s, a) =>
{
if (a.Name.Substring(0, a.Name.IndexOf(",")) == "AxInterop.WMPLib")
{
return Assembly.Load(res.AxInterop_WMPLib);
}
if (a.Name.Substring(0, a.Name.IndexOf(",")) == "Interop.WMPLib")
{
return Assembly.Load(res.Interop_WMPLib);
}
return null;
});
Related
I have an application that has all the DLL files it needs embedded into it so that it is a standalone exe. Here is how I am loading everything now:
public static Assembly ExecutingAssembly = Assembly.GetExecutingAssembly();
public static string[] EmbeddedLibraries = ExecutingAssembly.GetManifestResourceNames().Where(x => x.EndsWith(".dll")).ToArray();
public static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
// Get assembly name
var assemblyName = new AssemblyName(args.Name).Name + ".dll";
// Get resource name
var resourceName = EmbeddedLibraries.FirstOrDefault(x => x.EndsWith(assemblyName));
if (resourceName == null) {
return null;
}
// Load assembly from resource
using (var stream = ExecutingAssembly.GetManifestResourceStream(resourceName)) {
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);
return Assembly.Load(bytes);
}
}
public static void Main(string[] arg) {
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
RealMain();
}
So the first interesting thing I noticed is that it only loads the DLL files that are used in the first page. It isn't enough to put using System.Data.SQLite; at the top to get it to include System.Data.SQLite.dll, you also have to do something that touches that namespace right away.
The next issue involves SQLite.Interop.dll which it won't load into the assembly. When you try you get the following error:
Exception thrown: 'System.BadImageFormatException' in mscorlib.dll
An unhandled exception of type 'System.BadImageFormatException' occurred in mscorlib.dll
The module was expected to contain an assembly manifest. (Exception from HRESULT: 0x80131018)
Now I could unpack the DLL and copy it to the c:\Windows\System32 directory, but since everything else is self contained, it would be nice if this was as well. I noticed this SDK that claims to be able to create it as a virtual file:
https://www.boxedapp.com/boxedappsdk/usecases/embed_system.data.sqlite.dll_dependencies.html
Is there a way to do this without the extra SDK? Or as an alternative, is there another way of creating and using SQLite databases without that DLL using a different package? I tried 3-4 different packages yesterday and didn't get anywhere.
SOLUTION
Ok, so this is disappointing that it is so easy, and yet nowhere else did I see the solution in dozens of other SO questions. On the SQLite.org website, there are a couple different downloads to choose from. When you use the NuGet package manager, you get the wrong version if what you want to do is embed everything.
To do it right, go to: https://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki
On that page you will want to download the BUNDLE version. In my case that was sqlite-netFx46-static-binary-bundle-Win32-2015-1.0.112.0.zip
Manually add that as a resource, include in your application as an Embedded Resource (Those are 2 separate steps), set it to not copy to output directory and use the code from the question to have it added.
I am trying to load a .net assembly using LuaInterface. If I place the assembly in the same folder as my executable (and my LuaInterface.dll and LuaNet.dll) then everything works great. I would like to move the assembly into a different folder, but when I try that I get "A .NET exception occured in user-code". I have tried:
package.path = package.path .. "C:\\path\\to\\my\\assembly\\?.dll"
luanet.load_assembly("MyAssembly")
and
luanet.load_assembly("C:\\path\\to\\my\\assembly\\MyAssembly")
and
luanet.load_assembly("C:\\path\\to\\my\\assembly\\MyAssembly.dll")
All of these return the .NET exception error. Is there a way to define the path that LuaInterface uses?
Your assembly is loaded by your "hosting" executable, and not really loaded by the Lua environment itself. luanet.load_assembly("MyAssembly") simply makes the assembly accessible to the Lua environment. For example (C#):
using MyAssembly; //you can't compile unless MyAssembly is available
namespace LuaRunner
{
class LuaRunner
{
void DoLua()
{
using (LuaInterface.Lua lua = new LuaInterface.Lua())
{
lua.DoString("luanet.load_assembly('MyAssembly')");
//... do what you want within Lua with MyAssembly
}
}
}
}
Your running program is the "host" for Lua to run within, so it's your running program that actually loads MyAssembly. Your executable needs a reference to MyAssembly.dll, (and needs to be able to find it at runtime in the usual locations).
To search other assemblies, set the package.cpath variable. For example:
package.cpath = DATA_DIR .. "\\clibs\\?.dll;" .. package.cpath
From the Lua 5.1 documentation:
require (modname)
First require queries package.preload[modname]. If it has a value, this value (which should be a function) is the loader. Otherwise require searches for a Lua loader using the path stored in package.path. If that also fails, it searches for a C loader using the path stored in package.cpath.
package.cpath
The path used by require to search for a C loader.
Lua initializes the C path package.cpath in the same way it initializes the Lua path package.path, using the environment variable LUA_CPATH or a default path defined in luaconf.h.
PROJECT A contains a View , let's call it View1.ascx marked as "Embedded Resource" in the properties window
both PROJECT A and PROJECT B and C load that view1 from the PROJECTA.DLL using a custom resource provider
This way I can reuse my views across projects.
Sadly, this causes visual studio to be unable to build PROJECT B , OR C the first time around, after each change to the PROJECTA.dll
"Error 12 Could not copy "C:\GIT\PROJECTA\PROJECTA\bin\PROJECTA.dll" to "bin\PROJECTA.dll". Exceeded retry count of 10. Failed."
Is there any way to make this work? or should I somehow move all "re-used" views to a seperate assembly? The views use classes from PROJECT A so that's why I kept them inside PROJECT A
To make everything clear: Building it a second time around usually works, and the code and views are all working, it's just a really big waste of time to have to wait 10 seconds for the first build attempt to fail.
Apparantly my assemblyresourceprovider used a AssemblyResourceVirtualFile:VirtualFile oebject that was loading my dll from Assembly.LoadFile instead of using the recommended way of loading dlls in memory as described here: http://fzysqr.com/2010/04/26/asp-net-mvc2-plugin-architecture-tutorial/
I left the old line of code in comment for you guys to see where the problem was
public override System.IO.Stream Open()
{
string[] parts = path.Split('/');
string assemblyName = parts[2];
string resourceName = parts[3];
assemblyName = Path.Combine(HttpRuntime.BinDirectory, assemblyName);
byte[] assemblyBytes = File.ReadAllBytes(assemblyName);
System.Reflection.Assembly assembly = Assembly.Load(assemblyBytes);
/*System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFile(assemblyName);*/
if (assembly != null)
{
Stream resourceStream = assembly.GetManifestResourceStream(resourceName);
return resourceStream;
}
return null;
}
I have a DLL >> System.Data.SQLite.dll
To use it in a normal way > just add it as reference and
using System.Data.SQLite;
then, I can use all the functions inside this DLL.
But, I want to merge my app.exe and this DLL into one single file.
I have tried using ILmerge, but fail. As I know, ILmerge cannot merge unmanage DLL.
So, I tried another method > make the DLL as embbed resource.
I am able to load it as an assembly with the below code:
Stream stm = Assembly.GetExecutingAssembly().GetManifestResourceStream("MyApp.System.Data.SQLite.dll");
byte[] ba = null;
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = stm.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
ba = ms.ToArray();
}
Assembly sSQLiteDLL = Assembly.Load(ba);
but, how am I going to use the functions in SQLiteDLL?
I also tried add the DLL as resource in properties and load it like this:
public Form1()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
InitializeComponent();
}
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
AppDomain domain = (AppDomain)sender;
if (args.Name.Contains("System_Data_SQLite"))
{
return domain.Load(MyApp.Properties.Resources.System_Data_SQLite);
}
return null;
}
The above explained what I've got so far and I don't know what to do next to use the DLL? I still can't use the functions inside the DLL.
For example, when I type this:
SQLiteCommand cmd = new SQLiteCommand();
The Visual Studio says:
Error 21 The type or namespace name 'SQLiteCommand' could not be found (are you missing a using directive or an assembly reference?)
Can you share your insight? Thanks.
You can embed an assembly AND reference it (in VS) at the same time... for the way you want to use it you need to reference it! Any reason you don't reference the Assembly ?
Using a Type from an embedded Assembly (managed) without referencing it is a bit harder but possible using Reflection etc. - see these links (they include reference material AND some sample code etc.):
http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx
https://stackoverflow.com/a/57450/847363
http://msdn.microsoft.com/en-us/library/h538bck7.aspx (loads an ssembly from a byte array so there is no need to write that assembly to the filesystem)
http://msdn.microsoft.com/en-us/library/system.reflection.assembly.gettype.aspx
http://www.codeproject.com/Articles/32828/Using-Reflection-to-load-unreferenced-assemblies-a
On embedding managed DLLs you have several options:
use ILMerge (free)
For howto see here and here
OR
use some tool like SmartAssembly (commercial)
it can embed and merge among other things (no need to change your source code)
OR
code that yourself in less than 10 lines (free but minimal source code change)
mark all needed dependencies as "embedded resource" - this way they are included in the EXE file... you need to setup an AssemblyResolve handler which at runtime reads from Resources and returns the needed DLLs to the .NET runtime...
This is not a method to use assemblies loaded in AppDomain.
Please read this article: How to: Load Assemblies into an Application Domain
in short you should call GetMethod() with method name (for example SqlCommand) and then call it via .Invoke() method.
I got the problem that I need to distribute a C# project as a single EXE file which is not an installer but the real program. It also needs to include a translation which currently resides in a subdirectory.
Is it possible to embed it directly into the binary?
The short answer is yes, there is a program called Assembly Linker (AL.exe) that will embed assemblies in this way. Its main use case is localization, sounds like that is what you need it for too. If so, it should be straightforward.
Eg:
al /t:lib /embed:strings.de.resources /culture:de /out:MyApp.resources.dll
or
al.exe /culture:en-US /out:bin\Debug\en-US\HelloWorld.resources.dll /embed:Resources\MyResources.en-US.resources,HelloWorld.Resources.MyResources.en-US.resources /template:bin\Debug\HelloWorld.exe
This is an example walkthrough of it MSDN with the above examples and more. Also you may want to read this blog post which explains its usage a bit further.
Here it is the simplest solution which I saw in the Internet:
How to embed your application’s dependent DLLs inside your EXE file
also handy implementation of this solution:
http://code.google.com/p/costura/wiki/HowItWorksEmbedTask
Another option is to embed the other assemblies as an EmbededResource. Then handle the app domains AssemblyResolve, from here you can read the assembly from the resource and load it into the runtime. Something like the following:
public class HookResolver
{
Dictionary<string, Assembly> _loaded;
public HookResolver()
{
_loaded = new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string name = args.Name.Split(',')[0];
Assembly asm;
lock (_loaded)
{
if (!_loaded.TryGetValue(name, out asm))
{
using (Stream io = this.GetType().Assembly.GetManifestResourceStream(name))
{
byte[] bytes = new BinaryReader(io).ReadBytes((int)io.Length);
asm = Assembly.Load(bytes);
_loaded.Add(name, asm);
}
}
}
return asm;
}
}
ILMerge will create a single exe file for your application. You can download it from Microsoft. It merges assemblies together and can internalize them so that the merged classes are set to internal. This is what I have used to create single file releases a number of times. It is pretty easy to integrate into your build process.