Ok so built this app and it's an assignment so I wanted to embed some dll in it so I would only have one file when submitting it. The dll is only used for some UI controls and visuals, nothing else
I went through the necessary steps of setting Copy Local to false under references and setting Build Action to Embedded Resource but the problem I have is that if I copy the application exe to another pc it won't run unless I copy the referenced dll into the same directory of the exe so it seems to me that it's not loading the embedded dll file or I may have set up something wrong
Just to note though, the app does run fine on my pc, the one I created on, without needing the referenced dll next to the exe file.
Here is the code I used:
//other using statements
using System.Reflection;
using library; //<--- reference to embedded dll
namespace app {
public partial class Form1 : Form1 {
[DllImport("user32.dll")]
public static extern int GetAsyncKeyState(int i);
private string embeddedFile = "app.library.dll";
public Form1() {
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
InitializeComponent();
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
using(var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedFile)) { //<-- debugging shows a System.IO.UnmanagedMemoryStream exception here
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}
///
/// some unrelated code
///
}
Related
I need to build a gui to communicate via bulk USB from my Windows PC to a PIC microcontroller. I'm trying to use mpusbapi.dll as I see over diferent tutorials on internet, but I can´t acommplish to succesfully reference the dll in my project. VS 2015 show me this error: "mpusbapi.dll" could not be added. Make sure that the file is accessible, and that its a valis assembly or COM component.
I did research and i figured out the problem was the unmanaged dll, so I tried to reference via DllImport. But at this time, that did not work either.
I share my code below expecting someone could help me or give me some reference to a better way to accomplish my objective with usb.
using System.Runtime.InteropServices;
namespace GUI_ROBOT
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
//Problem here
[DllImport("mpusbapi.dll",CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 MPUSBGetDLLVersion();
[DllImport("mpusbapi.dll")]
static extern UInt32 MPUSBGetDeviceCount(string pVID_PID);
private void btnStart_Click(object sender, RoutedEventArgs e)
{
try
{
string dCount = MPUSBGetDLLVersion().ToString();
listBox1.Items.Add(dCount);
}
catch (Exception j)
{
System.Windows.MessageBox.Show("Error: " + "\nMessage = " +
j.Message);
}
}
}
}
The try catch statetment give me the follow result:
Error after try catch statetment
Translate "Can´t load the .dll file 'mpuasbapi.dll': Can´t find the specified module."
I don´t undesrtand because I just added the file in my project.
Thanks people!
The problem was that the .dll have not being copied to the output folder, as Fruchtzwerg said. So I just changed the properties of the .dll file as I say in the comments.
Then [see comments] I had a 32-bit / 64-bit conflict with the mpusbapi.dll The problem was solve using this answer:Could not load file or assembly ... An attempt was made to load a program with an incorrect format (System.BadImageFormatException)
I have been baffled on how can this be happening.
So heres the deal, im trying to play a V2M chiptune with a dll called NV2.dll
Its referenced, and I used its functions like normal.
BUT when i try to run the application i get
Unable to load DLL 'V2.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
The referenced DLL i used is called NV2, I have checked it, the assembly goes by NV2, not V2, why is it trying to load a dll with a different name?!
So obviously, there is a reference to V2.dll inside the NV2.dll. Either the documentation is just shitty or you didn't notice that part, but inside the constructor of the NV2 class they try to write that V2.dll, which is saved inside the Resources of the dll as a byte[] V2 to disk, namely to the directory C:\Windows\system32. Code:
public NV2()
{
List<WeakReference> _ENCList = NV2.__ENCList;
Monitor.Enter(_ENCList);
try
{
NV2.__ENCList.Add(new WeakReference(this));
}
finally
{
Monitor.Exit(_ENCList);
}
//Here comes the part that writes the resources
FileStream fileStream = new FileStream(string.Concat(Environment.GetFolderPath(Environment.SpecialFolder.System), "\\V2.dll"), FileMode.OpenOrCreate);
fileStream.Write(Resources.V2, 0, checked((int)Resources.V2.Length));
fileStream.Close();
}
Meaning that either in your application you first have to do a
var engine = new NV2(); //triggers the constructor code
to trigger that, or you go hardcore on that and dump the byte[] from their dll.
I've dumped that file here for you and zipped it: http://www.file-upload.net/download-11263190/V2.zip.html
(You could have done that by saving the project using teleriks decompiler, fixing the errors in the ressources, changing the project to a console project, then coding a Main function like)
using System.IO;
using NV2.My.Resources;
namespace NV2
{
class MainClass
{
static void Main(string[] args)
{
FileStream fileStream = new FileStream("V2.dll", FileMode.OpenOrCreate);
fileStream.Write(Resources.V2, 0, checked((int)Resources.V2.Length));
fileStream.Close();
}
}
}
I am trying to make a program that must be run from memory (through Assembly.Load(bin) as described here) using custom components sitting in a (referenced) .dll.
Since the run-from-memory code runs an .exe, how can the components be embedded in the .exe such that the .dll isn't needed?
I've tried ILMerge, but the resulting .exe wouldn't run from memory.
I've looked at this but I don't think it works if you've referenced the .dll (which I had to because it contains components on my form)
Update
Having read NSGaga's answer, I tried the following:
Set the components .dll included in the project to be an embedded resource
Made an addition to Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
namespace MyApp
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve +=
(sender, args) =>
{
// System.Diagnostics.Debugger.Break();
String resourceName = "MyApp." +
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);
}
};
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
Unfortunately this doesn't work, I get a FileNotFoundException:
Could not load file or assembly 'MetroFramework, Version=1.2.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a' or one of its dependencies. The system cannot find the file specified.
The exception occurs on the Application.Run(new MainForm()); line. Also, having breakpointed/added message boxes etc, I don't believe the AssemblyResolve handler is ever being called - what am I doing wrong?
You already answered that pretty much - that manual solution from Jeffrey Richter should work just fine - ILMerge has issues (e.g. WPF).
it was a long time since I played w/ that but this is rougly what you need to do...
1) Prepare your app a bit - meaning - you cannot load anything until you setup your AssemblyResolve handler. That also means anything that is e.g. called from 'main' (even afterwards) will have to be 'resolved' before. In short, move everything you need 'referenced' to some 'later' code,
2) Add the handler - as soon as possible. I'll just repeat that Richter's code w/ some info. Also take a look at the http://support.microsoft.com/kb/319292.
AppDomain.CurrentDomain.AssemblyResolve +=
(sender, args) =>
{
// System.Diagnostics.Debugger.Break();
// Lookup what's your namespace in project properties
String resourceName = "YourAssemblyNamespace." +
new AssemblyName(args.Name).Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
==>
if (stream == null)
return null;
==>
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
3) To make a test - move your 'loading' lib code on some 'click' or something - and put a 'Break' (like I did),
4) Add your dll-s `as embedded resources' - i.e. just like bmp or something, in the root. Add external file - then set it in properties to be 'embedded resources'.
5) Build the app - and notice the change in size, should be pretty much the difference in dll-s,
6) go to your bin dir - and remove dll-s. Don't build the project again and move away from the VS/Debugger,
7) start the app and observe...
NOTE:
You may get exceptions (like the lib you're suggesting) - you need to handle if stream==null. 'Problem' is that all sorts of dll-s are often 'attempted to be loaded (or requested from the app) and they safe fail - since we add the 'handler' we're responsible for softly failing in the same way. See the edited code above.
Your code edit:
You may need to move the window starting at a bit later point - have you checked that handler is called (breakpoint and all - do some trace too).
Problem is that the MainWindow resolution begins as soon as it gets visible - i.e. in the Main - and that happens before the actual code runs or handler is set up. So...
static void Main(){
...
DoAppSetup();
// Application.EnableVisualStyles();
// Application.SetCompatibleTextRenderingDefault(false);
// Application.Run(new MainForm());
}
static void DoAppSetup(){
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
...that way your handler should be set up before anything even tries to resolve.
If you have access the embedded resources directly then just embed them in the EXE, if they're in a third-party DLL then you're not going to be able to lift them out and embed them without running into practicality and potential legal issues.
I'd recommend directly embedding into the EXE if you can.
I have C# application which loads set of managed assemblies. One of this assemblies loads two native dlls (each of them in different location) if they are avaiable. Iam trying to find way to provide search path to those native dlls.
Are there other options? I really dont want to provide those dlls with my software - copying them to programs directory of course solves the problem.
I've tried using SetDllDirectory system function but it is possible to provide only one path using it. Each call to this function resets path.
Setting PATH enviroment variable does not solve the problem too :/
I know this was an old post, but just so there's an answer: Using the LoadLibary function you can force load a native DLL:
public static class Loader
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string fileName);
}
You must call this before any other DLL does - I usually call it in a static constructor of my main program. I had to do this for DllImport(), and static constructors were always executed before the native DLLs were loaded - they only load actually the first time an imported function is called.
Example:
class Program
{
static Program()
{
Loader.LoadLibrary("path\to\native1.dll");
Loader.LoadLibrary("otherpath\to\native2.dll");
}
}
Once the library is loaded it should satisfy the DllImports() of the other managed assemblies you are loading. If not, they might be loaded using some other method, and you may have no other option but to copy them locally.
Note: This is a Windows solution only. To make this more cross-platform you'd have to detect operating systems yourself and use the proper import; for example:
[DllImport("libdl")]
public static extern IntPtr DLOpen(string fileName, int flags);
[DllImport("libdl.so.2")]
public static extern IntPtr DLOpen2(string fileName, int flags);
// (could be "libdl.so.2" also: https://github.com/mellinoe/nativelibraryloader/issues/2#issuecomment-414476716)
// ... etc ...
This could help:
private void Form1_Load(object sender, EventArgs e)
{
//The AssemblyResolve event is called when the common language runtime tries to bind to the assembly and fails.
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(currentDomain_AssemblyResolve);
}
//This handler is called only when the common language runtime tries to bind to the assembly and fails.
Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string dllPath = Path.Combine(YourPath, new AssemblyName(args.Name).Name) + ".dll";
return (File.Exists(dllPath))
? Assembly.Load(dllPath)
: null;
}
Register yours dlls to GAC. More here.
I've read through the two other threads that extract the dll from the application at run time. One of these methods used the current Windows temporary directory to save the dll in, but it was an unmanaged dll and had to be imported at runtime with DllImport. Assuming that my managed dll exported to the temporary directory, how can I properly link that managed assembly to my current MSVC# project?
You dont need to save to a temp directory at all. Just put the managed dll as an 'Embedded Resource' in your project. Then hook the Appdomain.AssemblyResolve event and in the event, load the resource as byte stream and load the assembly from the stream and return it.
Sample code:
// Windows Forms:
// C#: The static contructor of the 'Program' class in Program.cs
// VB.Net: 'MyApplication' class in ApplicationEvents.vb (Project Settings-->Application Tab-->View Application Events)
// WPF:
// The 'App' class in WPF applications (app.xaml.cs/vb)
static Program() // Or MyApplication or App as mentioned above
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name.Contains("Mydll"))
{
// Looking for the Mydll.dll assembly, load it from our own embedded resource
foreach (string res in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
if(res.EndsWith("Mydll.dll"))
{
Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(res);
byte[] buff = new byte[s.Length];
s.Read(buff, 0, buff.Length);
return Assembly.Load(buff);
}
}
}
return null;
}