Loading C# DLL to C++/CLI - dependencies directory - c#

I wrote a dll c++/cli library which uses my other c# dll library. C++/cli library works fine when I've got c# dll in the same folder as application which calls it. This library will be finally loaded to many applications and a C# dll must not be copied into directory with application. It has to be in the same folder as c++/cli library, but in that cases I've got System.IO.FileNotFoundException.
My suggestion is to load c# library manually or to change path where f.ex. firefox is looking for dependencies, but I tried with LoadLibrary() and Assembly::LoadFrom() methods to force loading from right directory. Of course I added directory path with dll to system PATH.
I work on VS2010.

You don't change the default directory where an application will look for dlls.
At design time put your dll in some well know location, the one you are going to deploy to. Add a reference to it, make sure it's set to Don't copy ever, otherwise it will end up in the bin folder. You have to do this otherwise it won't compile.
When you deploy, you'll need one package to deploy common dlls, and one for each application. Careful you don't create your own version of dll hell, if appA needs an older or new version of the common dll, compared to AppB
Add an AppDomain.AssemblyResolve event to main (for windows app). At run time the event handler will get fired when you reference a type in your dll, and the assembly has not yet been loaded.
In there you load it from the well known location. That usually in config, or in a relative path.
E.g.
AllMyApps
CommonDLLS
MyFirstApp
So the path you load the required common dll from would be "..\CommonDlls\MyCommondll.dll".
NB you will want to secure the dlls in some way, otherwise a bad guy might be able to inject their version of one in to your app, which would be bad...
You can use this mechanism to get the dll from a remote server or a database blob as well.
The simplest case is only a few lines of code, just look the event up. Took me about 15 minutes to get this going in a similar scenario.
Not on this machine though, otherwise I'd have pasted in the code.

Related

Link dll from subfolders

I have written a C++/CLI wrapper for some unamanaged dll's (OpenCV). Everything works fine until this point. Now I would like to store the dll's in a subfolder, so the final application structure would look like this:
bin\
MainApp.exe
wrapper.dll
Wrapper\library1.dll
Wrapper\library2.dll
Also, I would like to configure this in the Wrapper project, so I don't need to care about this in any other project using wrapper.dll
I have found several posts talking about this, but none of them seems to match my needs:
Setting the path in app.config file: wrapper.dll does not have an
app.config file, and I would have to add this reference in every
executable project using the dll.
Setting AppDomainSetup.PrivateBinPath: this could be a workaround, but I'm
not sure whether it works for unmanaged dll's.
Using ILMerge: Does it work for unmanaged dll's along with C++/CLI dll?
Ideally I am looking for a property in Project settings to add this subfolder, so every Solution including my project will look for the unmanaged dll's in the right folder.
The problem here is that the DLL's are usually loaded by Windows, and they're loaded when your application starts. Windows starts by looking at the EXE, finds what DLL's it needs, loads them, and then continues to load DLL's needed by DLL's. This is not specific to C++ or C#.
.Net does affect DLL loading, but that's not applicable to native DLL's.
So, what can you do? One solution is to not let Windows load your DLL's. Visual Studio has a DelayLoad option. This uses LoadLibrary at runtime. And with dliNotePreLoadLibrary you can control where it's loaded from. Since this happens at runtime from your DLL, the executables don't need to do anything.

Mixed Assembly Not Discovering Native DLLs

I have a mixed mode dll with native dll dependencies.
I am loading the mixed mode dll from a C# exe using Assembly.Load. However, the location of the mixed mode dll is not in the application bin directory, therefore it fails because it only looks for the native C++ dll's in the bin and the folders in the PATH environment variable.
I thought using the option /assemblylinkresource was suppose to stop this and force the native dll's to be found in the alternate directory alongside the deployed mixed mode dll. This is proving to be not correct.
Is there a way to create a multi-file assembly with native dll's using an existing C++/CLI mixed mode dll? The only examples (http://msdn.microsoft.com/en-us/library/xawyf94k(v=vs.100).aspx) I've seen are using .netmodules coupled with a native dll.
Therefore, the solution is to either:
a) some how force the application to search for native dependencies in a directory of your choosing; or
b) package the native dll's into the one managed mixed mode assembly (is this even possible??) - given statically linking the dependencies is not an option.
Normal Windows DLL searching rules apply. So yes, there's no hope it will ever find those DLLs. A "multi-file assembly" isn't going to work either, you cannot merge native code. Options you have, roughly in preferred order:
Call SetDllDirectory() to add the path that contains the DLLs to the set of directories where Windows will look. May fail if the external code uses it as well.
Use Environment.SetEnvironmentVariable() to append the path to the PATH environment variable. This only changes the process' copy of the PATH so is a reasonable approach. May fail on machines that have a bloated PATH that is reaching the limit.
Set Enviroment.CurrentDirectory to the path with the DLLs. May fail if the external code tinkers with it as well.
Record the path for each DLL at install time in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs registry key.
Install the DLLs in the Windows side-by-side cache and use a manifest to tell Windows about it. This is hard to get right.
Potential candidate for a solution, not tested with MMA: This is probably not the optimal solution you were hoping for, but I thought I would add it as it could help you along the way to achieve solution a). In c++ you could control loading path and path search order by either manually setting the directory to be searched using SetDllDirectory (only available from XP SP1) or by manually loading the dll using LoadLibraryEx.
I guess one could use P/invokes to get access to these calls in C#
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern void SetDllDirectory(string lpPathName);

Referenced DLL Cannot Be Found When Running Application

I have a weird situation with some code that I inherited at work. Their application is a multi-project solution, with several of the solutions being (code) pieces of the MS Enterprise Library (not sure which version).
They also have an existing C++ (unmanaged) application which has a bunch of DLLs. One of these DLLs is built in a separate solution, both in 64-bit and 32-bit flavours.
The main application has a reference to this DLL, and calls a couple of static functions (I can see intellisense, even). I can compile and build the main application EXEs, but when I run it, I get an exception that this DLL from the unmanaged code (lets call it CPlusPlusCode.dll cannot be found:
FileNotFound Exception was unhandled: Could not load file or assembly 'CPlusPlusCode.dll' or one of its dependencies. The specified module could not be found.
I'm quite stumped, because I can compile the code, see intellisense for the imported classes, and dig into the DLL in the object browser. I even made sure there's a copy in the \bin\Debug folder (although I don't see why that would make a difference). This is for a Windows Forms application.
Also, if it matters, I had some build issues related to x86 vs. x64 for different projects; I think (hope?) that this is not related to that, but I solved that by using the Configuration Manager to build everything as x64.
Check the GAC, and if necessary you might need to add it or register the DLL there.
I had this problem with a project, it all works ok from Visual Studio and most of my times running the project locally on my machine. But because of the unmanaged code I needed specifically allow the project to be executed with correct permission levels.
So have a look in the manifest file, that enough permissions etc exist.

DllNotFoundException for .dll which is in current folder

I'm getting a System.DllNotFoundException for a .dll which is in the same folder as the executable whenever my application attempts to use a function which exists in the DLL. The weird thing is that it is only occurring on one user's PC; it works fine on my dev PC and it works fine on one non-dev PC that I tried it on. Also, there are other DLLs in the folder which are being found and used correctly. The DLL in question is a native library which is referenced by my application via another DLL which is a c# wrapper for the native library.
My initial instinct is that there must be some other library being referenced by this DLL which doesn't exist on the problematic PC, but I cannot imagine what library this PC could be missing that the other non-dev PC has.
So my questions are this: is there a way to determine the dependencies of a given DLL file? Keep in mind that the DLL in question is a native library (i.e. not managed code), and I do not have access to it's source code. And if it turns out no dependency is missing, what else might cause such an issue?
For unmanaged dlls you can use Dependency Walker to find dependencies.
I would suggest using ILSpy to open the dll and view its dependencies first.

A problem regarding dll inheritance

I have created a dll that will be used by multiple applications, and have created an installer package that installs it to the program files, as well as adds it to the Global Assembly Cache.
The dll itself uses log4net, and requires a xml file for the logging definitions.
Therefore when the installer is run, the following files get copied to the install directory within program files:
The main dll that I developed
- The Log4Net.dll
- the Log4Net.xml file
I am now experiencing a problem. I have created a test console application for experimentation. I have added my dll as a reference, and set the 'local copy' flag to false.
When I compile the test console exe however, I noticed that it has copied the log4net.dll and log4net.xml files to the bin directory. And when running the test console, it appears that it will only work if the log4net.dll is in the same directory as the exe. This is dispite the fact that the test console application does not use log4net, only the dll that was added as a reference does.
Is there some way to have it so that the log4net.dll & xml files used will be the ones that were installed to the program files, rather than any application needed to copy over local copies? The applications that will be using my dll will not be using log4net, only the dll that they are referencing uses it.
Many thanks
Don't install into the Global Assembly Cache! Even if your library dll is used by multiple applications each should have it's own local copy. Otherwise you get into a whole world of pain for saving a few KB of disk space.
Always copy the required dlls locally. If you are really sure that the application won't need it you can simply delete the unnessesary dlls later or don't include them in the installer. But if your application will call ANY reference there it will crash at runtime. So best option is to leave them there (after all they WERE referenced for a reason).
No, it's not possible (at least not without much efford) to have .Net load dlls from arbitrary locations on the disk. And it should be this way (look up DLL-hell if you want to know why).
I suspect your problem is the configuration. You must use fully qualified names if you want it to work from the GAC. As per the documentation at http://logging.apache.org/log4net/release/faq.html:
"When loading an assembly from the GAC the fully qualified assembly name, including the version, culture and public key must be specified. This is in the standard syntax supported by System.Type.GetType. See the next FAQ on how to get the version and public key for an assembly."
I managed to resolve this by adding Log4net.dll to the GAC as well. It will now run without needing a local copy the dll.
It does however require a local copy of the XML file, to correctly log.

Categories