Managed C dll calling C# dll, FileNotFoundException - c#

I have an application environment that is essentially a plug in where:
host application calls into unmanaged c++ dll which calls into managed C++ dll which calls into C# dll
This is a fairly known way of calling into C# from unamanaged C++ by using a bridge of managed C++. This all works well and good under most circumstances except in a plug in type architecture where my dlls(unmanaged C++, managed C++ and C#) are not in the same directory as the application calling into the dll. When the application calls into the unmanaged C++ all is well and good because the app knows the directory to call into to load up that dll. However, the first time the unmanaged C++ calls into the managed C++ we get a FileNotFoundException. It turns out that it is not finding the C# dll(noting that all three dlls are in the same directory, just not in the app directory). If I drop all of the dlls into the runtime directory of the exe then everything works perfectly and we don't get the FileNotFoundException. But when I deploy I will have no control over the calling application and thus cannot drop my dlls in the runtime directory.
So, the question is how can I in the unmanaged C++ code programmatically set the load directory for the C# dll when managed C++ dll loads up? I have tried SetDllDirectory and setting the path variable on the system to no success for the directory where my dlls reside.

The CLR looks in only two places by default for an assembly: the GAC first, the directory from which the EXE was started second. Getting it to look elsewhere requires extra work. One possibility is off the table, you cannot subscribe an event handler for AppDomain.AssemblyResolve in this scenario. Which leaves an app.exe.config file with the <probing> or <codebase> elements. You must give it the same name as the unmanaged EXE and store it in the same folder as the EXE.
This tends to be unwise if the EXE is not yours and doesn't exactly address the goal of keeping stuff out of the EXE directory. The GAC is the simple workaround.

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.

CoCreateInstance C# COM component from native app does not find reference

I have a question concerning a COM C# component being created from a native C++ application.
The C# component is referencing an assembly which contains the COM interface.
So project A(.dll) contains the COM interface, project B(.dll) contains the COM class that implements this interface.
This C# COM component is then registered using regasm from some folder on my system, say for example:
C:\TestComponent which contains A.dll & B.dll, B being the one registered using regasm.
When my native C++ application (COM server), which is installed in another path, is trying to create an instance of the C# COM class from project B this fails complaining that A.dll can not be found.
If I copy (only) A.dll to the installation directory of my native C++ app, everything works perfectly.
Any ideas on how to tell my native C++ app that it needs to find the A.dll in a specified directory or in the directory where B.dll resides?
Kind regards,
Dwight
Having dependencies in a COM server is always a problem, whether it is an unmanaged server or one written in C#. Just like Windows, the CLR will only look in a few select places for a DLL. Which are the GAC and the directory where the EXE resides. With an option to also look in subdirectories of the EXE directory by using a app.exe.config file.
Knocking off the candidates here: you'll want to avoid giving the client EXE a .config file, you don't control its location nor configuration, it is somebody else's program. Same problem with the EXE directory.
Which leaves the GAC.
Also the location that Regasm.exe prefers, just omit the /codebase option when you register after you put the assemblies in the GAC. And a very good way to solve the DLL Hell problem that's so strongly associated with COM, the GAC can store different versions of your DLLs.
As far as I understand, you only registered B.dll. That is the reason, the COM System has no knowledge, where A.dll reside. I do not know a way to tell the application where it can found a, except of changing the workingdirectory or add the path to the A.dll to the system path variable or last but not least copy the A.dll into the system32 directory (but I hate that).
By the way, having a DLL proxy, like A.dll is, reside in the same directory as your application seems totally fine to me.
Ah one more thing. You can, if you now the path of the A.dll but did not want any of the above solutions, you can have a look into Loadlibrary.

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

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.

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);

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.

Categories