Embedding dlls into exe with Mono support with Fody - c#

Well my question is almost similar to Embedding DLLs in a compiled executable but the very great answer provided here looses the compatiblity with mono runtime, though it works on windows.
So how can I use Fody (Costura) and also maintain mono compatibility. Their docs at https://github.com/Fody/Costura#contents read:
CosturaUtility is a class that gives you access to initialize the
Costura system manually in your own code. This is mainly for scenarios
where the module initializer doesn't work, such as libraries and Mono.
To use, call CosturaUtility.Initialize() somewhere in your code, as
early as possible.
class Program {
static Program() {
CosturaUtility.Initialize();
}
static void Main(string[] args) { ... }
}
but even after initialising ConturaUtility manually it does not support mono runtime.
I dont think the error log is relevant but here it is:
Unhandled Exception:
System.IO.FileNotFoundException: Could not load file or assembly 'CommandLine, Version=2.2.1.0, Culture=neutral, PublicKeyToken=de6f01bd326f8c32' or one of its dependencies.
File name: 'CommandLine, Version=2.2.1.0, Culture=neutral, PublicKeyToken=de6f01bd326f8c32'
[ERROR] FATAL UNHANDLED EXCEPTION: System.IO.FileNotFoundException: Could not load file or assembly 'CommandLine, Version=2.2.1.0, Culture=neutral, PublicKeyToken=de6f01bd326f8c32' or one of its dependencies.
File name: 'CommandLine, Version=2.2.1.0, Culture=neutral, PublicKeyToken=de6f01bd326f8c32'

Use this code at the start of Main() in your Program:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
String resourceName = "AssemblyLoadingAndReflection." +
new AssemblyName(args.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);
}
};
Reference: https://blogs.msdn.microsoft.com/microsoft_press/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition/

Related

CefSharp WPF File not found only on debug mode "CefSharp.Core.Runtime" Version 89.0.170

I am using CefSharp.WPF, I updated to the last version using NuGet, in the previuos version that I had. I added a Assembly Resolver like this, because I am using AnyCPU (.Net Framework 4.7.2) Any cpu Support :
private static Assembly Resolver(object sender, ResolveEventArgs args)
{
if (args.Name.StartsWith("CefSharp"))
{
string assemblyName = args.Name.Split(new[] { ',' }, 2)[0] + ".dll";
string path = System.IO.Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
Environment.Is64BitProcess ? "x64" : "x86",
assemblyName);
string archSpecificPath = System.IO.Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
Environment.Is64BitProcess ? "x64" : "x86",
assemblyName);
MessageBox.Show(path);
try
{
return File.Exists(archSpecificPath)
? Assembly.LoadFile(archSpecificPath)
: null;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
}
return null;
}
After update to version 89.0.170 I notice that there is a new file "CefSharp.Core.Runtime" that now is the only runtime dependency CefSharp release notes. After the update I removed the x86 and x64 folder, and also remove the Resolver code, the project run fine in Release mode but when I try to run in Debug mode I get this error when call new CefSettings():
System.IO.FileNotFoundException: 'Could not load file or assembly 'CefSharp.Core.Runtime.dll' or one of its dependencies. The specified module could not be found.'
Output windows --> Exception thrown: 'System.IO.FileNotFoundException' in CefSharp.Wpf.dll
An unhandled exception of type 'System.IO.FileNotFoundException' occurred in CefSharp.Wpf.dll
Could not load file or assembly 'CefSharp.Core.Runtime.dll' or one of its dependencies. The specified module could not be found.
VS code error image
I tried to find a similar issue but I can't found it , How I need to manage the 'CefSharp.Core.Runtime.dll' file?
For sure I am missing something but I can't find it. Also I am not sure if now will run fine in x86 and x64

Embedding SQLite.Interop.dll in C#

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.

Could not load file or assembly but they are loaded

I have a project going on witch uses a DLL from an ERP system.
The DLL is used to get information from the ERP, like invoices and such.
The error i am getting is:
Inner Exception 1: FileNotFoundException: Could not load file or
assembly 'SnelStartGatewayInterface, Version=12.48.37.0,
Culture=neutral, PublicKeyToken=null' or one of its dependencies. The
system cannot find the file specified.
But in the same window I used 'watch 1' to see the current using assembly's with the method:
AppDomain.CurrentDomain.GetAssemblies()
It returns a couple of assembly's.
This is the one loaded in and exactly the same as seen in the error:
+ [36] {SnelStartGatewayInterface, Version=12.48.37.0, Culture=neutral, PublicKeyToken=null} System.Reflection.Assembly
{System.Reflection.RuntimeAssembly}
Why would it return me the error?
Ps. I have tried the exact same method and dll in a windows forms test app and it was running fine.
Like Pawl Lukasik mentioned in the comments, you should look at the dependencies.
To do this, use:
private List<string> ListReferencedAssemblies()
{
List<string> refList = new List<string>();
var assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (var assembly in assemblies)
{
refList.Add(assembly.Name);
}
return refList;
}
to see all referenced assemblies.
Or with LINQ:
private List<string> ListReferencedAssemblies()
{
return Assembly.GetExecutingAssembly().GetReferencedAssemblies().Select(x => x.FullName).ToList();
}

Find out dependencies of all DLLs?

I have a collection of DLLs(say 20). How do I find out all the DLLs on which one specific DLL (say DLL A) is depending upon?
If you mean programmatically, use Assembly.GetReferencedAssemblies.
You can use that recursively to find all the assemblies you need. (So you find the dependencies of X, then the dependencies of the dependencies, etc.)
Since the question is tagged "C#", I would assume you are talking about managed dlls (assemblies). In that case, dependencywalker is not useful. If you want to do that with a program, good ones are dotPeek by JetBrians and Reflector by RedGate. Or you can even use the object inspector in Visual Studio.
However, it can be a long process and cumbersome too. I would write a short C# program/F# script that uses Assembly.GetReferencedAssemblies, as Jon mentioned.
If instead you want to examine native DLLs dependencies with a program (C# code), you have to walk the examine the PE file (the MS dll and exe file format) and its IAT (import address table). Not easy, but not impossible...
I would start here on MSDN and here to understand PE sections, and use a managed library to read it (there are many, including some from the Mono project (I'm thinking of Cecil, it should work with native binaries too); in the past I have used this one from the good John Gough.
All answer credit goes to previous authors for the usage of Assembly.GetReferencedAssemblies. This is just a write-and-forget C# console app that works solely for .NET assemblies. return 0 on assemblies you were able to check, and when successful, outputs them to STDOUT. Everything else will return 1 and print some kind of error output. You can grab the gist here.
using System;
using System.Reflection;
using System.IO;
namespace DotNetInspectorGadget
{
class DotNetInspectorGadget
{
static int Main(string[] args)
{
if(args.GetLength(0) < 1)
{
Console.WriteLine("Add a single parameter that is your" +
" path to the file you want inspected.");
return 1;
}
try {
var assemblies = Assembly.LoadFile(#args[0]).GetReferencedAssemblies();
if (assemblies.GetLength(0) > 0)
{
foreach (var assembly in assemblies)
{
Console.WriteLine(assembly);
}
return 0;
}
}
catch(Exception e) {
Console.WriteLine("An exception occurred: {0}", e.Message);
return 1;
} finally{}
return 1;
}
}
}
Usage:
call %cd%\dotnet_inspector_gadget.exe C:\Windows\Microsoft.NET\assembly\GAC_64\Microsoft.ConfigCI.Commands\v4.0_10.0.0.0__31bf3856ad364e35\Microsoft.ConfigCI.Commands.dll
Output:
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Management, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
You can use dependency walker http://www.dependencywalker.com to figure this out. Take note on the difference between x32 and x64 though.
Dependency Walker is a free utility that scans any 32-bit or 64-bit
Windows module (exe, dll, ocx, sys, etc.) and builds a hierarchical
tree diagram of all dependent modules.
For .NET assemblies, a terrific tool to view the assemblies an assembly is dependent on is AsmSpy.
If you want the DLL's (the files) then, Assembly.GetReferencedAssemblies will also return the .Net Framework assemblies.
Here is a simple code snippet that will get the dll's it can find in the current directory (and also include some other related files):
private readonly string[] _extensions = { ".dll", ".exe", ".pdb", ".dll.config", ".exe.config" };
private string[] GetDependentFiles(Assembly assembly)
{
AssemblyName[] asm = assembly.GetReferencedAssemblies();
List<string> paths = new List<string>(asm.Length);
for (int t = asm.Length - 1; t >= 0; t--)
{
for (int e = _extensions.Length - 1; e >= 0; e--)
{
string path = Path.GetFullPath(asm[t].Name + _extensions[e]);
if (File.Exists(path)) paths.Add(path);
}
}
return paths.ToArray();
}
You can call it like so: MessageBox.Show(string.Join("\r\n", GetDependentFiles(Assembly.GetEntryAssembly())));

RegistrationServices.RegisterAssembly error - help!

I have an assembly on a shared folder (UNC-path only, no mapped drive). When I try to register it programmatically via RegistrationServices, I'm getting a strange error.
Here's the code:
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace BLRegisterAssembly
{
public static class BlRegisterAssembly
{
public static void Register()
{
var asm = Assembly.LoadFile(#"\\myUNCPath\myAssembly.dll");
var rs = new RegistrationServices();
rs.RegisterAssembly(asm, AssemblyRegistrationFlags.SetCodeBase);
// I've also tried AssemblyRegistrationFlags.None : same error.
}
}
}
This is the error I'm getting:
"Could not load file or assembly
'[xxxxxxxxxxxxx],
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=[xxxxxxxxxxxxxx]' or
one of its dependencies. The system
cannot find the file specified."
(The file in question is a referenced assembly that the main assembly uses).
Some more points:
- the referenced assembly is located in the same folder as the main assembly that I'm trying to register.
- the folder cannot be mapped as a logical drive. Because of how the network folders are accessed, users in different groups have different drive mappings to the same network folders, and these cannot be modified, per IT policy...
Can anyone point me in the right direction to resolve the problem?
ANSWERED
Because I was using Assembly.LoadFile, the dependent assemblies have to be resolved manually via AssemblyResolve. The following code update fixed my woes:
public void Register()
{
AppDomain.CurrentDomain.AssemblyResolve +=
new ResolveEventHandler(CurrentDomain_AssemblyResolve);
var asm = Assembly.LoadFile(Path.Combine(m_path, assemblyName));
var rs = new RegistrationServices();
rs.RegisterAssembly(asm, AssemblyRegistrationFlags.SetCodeBase);
}
static Assembly CurrentDomain_AssemblyResolve(object sender,
ResolveEventArgs args)
{
//... code to resolve the path and load the dependent assembly...
}
You should never use LoadFile(), use LoadFrom() so the CLR has a shot at finding any dependent assemblies. If you still have trouble then use Fuslogvw.exe to get a trace of the assembly resolution attempt. The backup plan is to implement AppDomain.AssemblyResolve.

Categories

Resources