Add managed DLL dependencied to unmanaged C++ project - c#

I have project with managed DLL A.dll which depends on managed B.dll and C.dll.
I expose A.DLL to unmanaged C++ project D via COM interface. Everything is okay... But A.DLL can't find D.dll and C.dll and raises appropriate exception. I tried putting them in the same folder but it does not work. How and where should I reference those dependencies?
In C++ I would just build A.dll with static linking but .NET does not have this option.
Update: putting library in the same directory as .exe file works, I just lost my binary.

Normal CLR search rules apply here. It first looks in the GAC and next looks in the directory in which the EXE is located. You can convince the COM runtime to locate A.dll from the registration, it can be stored anywhere the Regasm.exe /codebase option tells it to look. But that does not affect where the CLR looks for dependencies, it only considers the EXE location.
You can troubleshoot this by using the Fuslogvw.exe utility.
Alternatives are in general troublesome. As long as you have a [ComVisible] type in A.dll that's guaranteed to be instantiated first (think "Application") then you can subscribe the AppDomain.CurrentDomain.AssemblyResolve event in the constructor to help the CLR locate the other DLLs. But it is very important the constructor doesn't need types from B or C, you'll still crash when the jitter needs them to compile the constructor.
If that's not a suitable option then writing an appname.exe.config file can be somewhat useful if you prefer deploying the DLLs in a subdirectory of the EXE install directory. This is however rarely a good idea in a COM scenario since you are typically not in control over the EXE, it is usually somebody else's responsibility. Deploying locally is fine when you test your code. For production deployment you ought to seriously consider the GAC. In general a good idea in COM anyway since registration is machine-global which gives it strong DLL Hell headaches.

Related

What is the point of references in Visual Studio?

Kind of silly question, but I still can't understand it.
Let's assume I have A.exe file and B.dll file.
B.dll is located in ../Somewhere/Debug/B.dll.
I make a reference to this .dll from my A.exe project, but when I execute the A.exe it looks for the B.dll in the same directory, where A.exe is located. So why do I have to specify the path to B.dll (../Somewhere/Debug/B.dll) in my A.exe project if it does not actually use that?
I can build A.exe which references ../Somewhere/Debug/B.dll with CopyLocal = true. Then, I can make changes to the B.dll (for example add a new Class) and build it. After that I am able to use that new Class in my A.exe project, but if I set CopyLocal on B.dll reference to false and build A.exe, I will face the TypeLoadException once I try to execute A.exe, since it uses the old version of B.dll which is located in the same folder where A.exe is located.
The same thing with strongly named assemblies which are located in the GAC. I reference this assembly (e.g. ../Test/My.dll), but CLR still uses those which are located in the GAC.
Do references in Visual Studio play any role or they just serve for development purposes (like IntelliSense)?
References to assemblies (aka DLLs or EXEs) are used in two ways. Let's take your example. In B.dll, we have a class named ClassB which has a public default constructor and a public method (ClassB.MethodB) which takes a string and has a void return type.
In A.exe, the code instantiates an instance of a ClassB and calls MethodB on that instance:
var b = new ClassB();
b.MethodB("SomeString");
At compile time, the compiler needs to know about the existence of ClassB, as well as what its public methods/properties/etc. are. In C++, that would be encoded in an H file. In COM, it would be in a type library. In .NET languages (VB, C#, etc.), that is exposed as metadata in the assembly itself.
So, when you compile the A project into A.exe, you need to provide the compiler with a reference to the B.dll assembly; that's how the compiler knows what a B is. Note that there is nothing Visual Studio-specific in this; if you were to do this with csc.exe (the C# compiler), you'd still need to include the reference on the command line.
But, in addition to this, when A.exe runs, the runtime needs to load and JIT the B.dll assembly so that when the b.MethodB("SomeString"); line of code in A.exe runs, it can call the right method in B.dll. (JIT means just-in-time compile -- which really isn't pertinent here)
As #waleedNaveed points out, the runtime behavior is different if the assembly is strongly named or not. In particular, the runtime assembly search path for strongly-named assemblies starts with the GAC.
For non-strongly-named assemblies, the easiest place to find a referenced assembly is in the same folder as the currently executed assembly. That's why you typically set "copy local" to true; it makes it just work.
To answer your confusion regarding GAC. .NET framework starts by searching the dll(assembly) in the GAC (obviously if it is strongly named). If assembly is not found in the GAC, and if there is a .config file, then .NET framework searches the location in the configuration file, else .NET framework searches the assembly in the directory containing the executable (.exe). Even if the assembly is not found in the executable directory, then it gives the error.
Hope that answers your question and clears you confusion.
The compiler will copy B.dll every time you compile your solution.
The objective is to allow you to target a dll somewhere outside of your solution. As an example, this dll can be maintained by another team. (but in this case, an internal nuGet package would be a better solution.)
Note that referencing dlls in your compilation folder is not a good idea, because the content of this folder can be cleaned between compilation. In that case you use a source control for your referenced dlls, the read-only flag on the dll in this folder can cause compilation issues.

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.

How to bundle a required DLL with a solution in Visual C# (Express, 2010)

I have an application written in C# which interfaces with some custom hardware using a vendor supplied .Net assembly. The .Net assembly in turn loads another DLL at run time. I can add the vendor supplied assembly to my project but when I run it, the vendor assembly complains that it can't load the required DLL. I can work around this for the moment by copying the DLL to the bin\Debug and bin\Release folder.
The problem is that I will need to distribute this application to clients at some point and they will not have this DLL in place. I can't see how I can make the solution require it; I can't add it as a reference since I get the error "A reference to foo.dll could not be added. Please make sure that the file is accessible, and that it is a valid assembly or COM component."
I can't convert the DLL to a .Net assembly using TlbExp, it gives an error "The module was expected to contain an assembly manifest."
I thought if I published the application via "click once" that I could declare the dependency there but I don't see any way for this either. I also tried adding it as a file resource but this didn't seem to help.
I can see other questions on SO relating to how to invoke functionality in an external DLL but in this case, I just need a way to bundle the DLL with the project.
Thanks.
Indicates that the attributed method is exposed by an unmanaged dynamic-link library (DLL)
The DllImportAttribute attribute provides the information needed to call a function exported from an unmanaged DLL. As a minimum requirement, you must supply the name of the DLL containing the entry point.
For further reference go here
Link to Review
You could add the dll as a resource, write it out as a byte[] to a file on loading, and do an Assembly.Load() at runtime for deployment.
You might have to use an AppDomain.AssemblyResolve Event to make sure the assembly resolves in case of multiple versions.
you could add both (all) of the dlls in your project as references and mark them as "copy local". That should do it unless the first DLL expects the second DLL in a specific place.

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