How to make my dll loadable from codebase only? - c#

My project(some kind of processing engine) is separated into 2 dlls: one with interface declarations and one with functionality.Usually the project is used by external Delphi project via COM technology.
Lets say my program slices fruits. External delphi programm creates Fruit object and fills its properties: weight (int), Name (string) and ProgressUpdater (of type IProgressUpdater which is declared in second dll with interfaces).After this exst programm creater Slicer, makes Slicer.AddFruit(newFruit) and calls Slicer.Slice().
Nothing special. In real life delphi project is Outlook addin. But here is the problem - sometimes some VSTO addins makes Outlook work in "shadow copy files" mode, so when delphi project starts and creats Slicer object, our c# assembly will be put in temp folder and assembly will be created with this local path. Well... this is still not an issue. But the problem is when delphi project creates newFruit and then passes ProgressUpdater object, in my Slicer assembly I can not get external ProgressUpdater: "Return argument has an invalid type", but still can get field with simple types(Weight, Name).
It only happens when shadowCopyFiles mode is on. So my guess is - external ProgressUpdater's assembly and Slicer assembly are placed to different places, so they can not be passed. My question is how to avoid my dll being "shadow copied"? Or is there some different solution?

So as a result I still have no answer for exact question. But the problem is solved (thanks to HansPassant) by using GAC, because assemblies at GAC will be never shadow-copied (actually linker will always first probe assemblies in GAC and then in other places).
Possible answer to the question is to go currentDomain.AssemblyResolve way, but I could not apply this solution to dll which contains public interfaces(types) only. Maybe it will be suitable solution for some cases.

You can use reflection to load DLL dynamically from any location you want. If you can go this way, I can provide further code for loading DLLs.

Related

How to call tool DLLs in C# when the DLL-path is different on the target PC?

I might be a bit stupid, but I want to create a tool in Visual Studio in C# and want to call third party tools via their API-DLLs. The only topics I found here are dealing with one of the two methods that I already know:
Compilation time: add a reference to "C:\FooTool\foo.dll" in my project + "using fooToolNamespace.fooToolClass" in my code (compilation time) --> I can "naturally" use the classes of the DLL and will even get full IntelliSense support if a suiting XML-file is available with the DLL. Also compilation time checks will be done for my usage of the dll.
Dynamic (run time): calling e.g. Assembly.LoadFile(#"C:\FooTool\foo.dll") and then using reflection on it to find functions, fields and so on --> no IntelliSense, no compilation time checks
So I actually have the DLL at hand and thus option 1) would be nice during development. But if my tool is used on a different PC, the third-party DLL might be in a different path there, e.g. "C:\foo\foo.dll" and "C:\bar\foo.dll".
In my understanding using a copy of "foo.dll" will not work, because "foo.dll" might have dependencies, e.g. requiring other files of the FooTool-directory. Thus in my understanding I have to call the DLL which is "installed" to the target PC and not a local copy of it.
So can I somehow change the path where my tool accesses the "foo.dll" at runtime and still use method 1) during development?
Or is there another way of doing things?
Or am I just dumb and there is a simple solution for all this?
Thanks a lot for the help and have a great day
Janis
To be able to use option 1 (a referenced DLL), you need to put the DLL somewhere "where your EXE (or, more precisely, the Assembly Resolver) can find it" on the customer's PC.
So where does the assembly resolver look for your DLL?
In the directory where the EXE resides (for desktop/console applications) or the bin subdirectory (for web applications). Since you mention that your DLL requires other dependencies as well, you'd need to copy them to that location as well.
The Global Assembly Cache (GAC). If your dependency supports this, installing it to the GAC ensures that it can be found by your application.
These two are the "supported" scenarios. There is also the possibility to tweak the assembly resolver to look into other directories as well, but that should be reserved for special cases where the other two options failed. (We had such a case and solved it with a custom AssemblyResolve handler on the application domain.)

How to create a dll that includes all the others?

At the moment of creating a project of type "Library of Classes, usually one can generate a dll when compiling, but how could I generate a dll without losing others that I already have included?
I explain with an example: It turns out that Nuget downloaded an S22.Imap dll with the one I worked with, later I generated the dll in the traditional way that I explained in the beginning, but when I wanted to work with dll in another computer, I got errors that were not I found functions that contained the S22.IMAP dll. So to solve this problem, I had to copy the dll of my project, S22.IMAP in an additional way in a specific path of the other computer.
My question is:
How could you generate a dll that includes the ones included in the project you were working with?
All the referred 3rd party dlls (S22.Imap.dll in your example) will be copied to the output folder together with your own dll file (let's say a.dll) when you build your project. That means you should always copy them together (S22 + a.dll) to the place you want to refer them, on another computer/folder/place.
If you really want to make them only one file (although it is not recommended), you can set the S22 one as some "nested resource". Then you will get only one a.dll file and the S22 one is inside the a.dll. See below page for some reference:
Embedding one dll inside another as an embedded resource and then calling it from my code
AND, ILMerge is some tool that can help you do so.
In general, you don't. A DLL is a dynamic linked library, and you would normally only combine static libraries during a build. Here is an answer on the difference between static and dynamic linking.
Typically you would include all the DLLs you need in the installer package. If you use Visual Studio to create the installer, it can detect the dependencies for you. When you run the installer, all of the necessary DLLs are deployed. Nearly all commercial .NET software follows this pattern.
It is possible to merge an assembly into another assembly using a tool called ILMerge. This would be a very unusual thing to do, and could cause issues with intellectual property and code signing, so it is not recommended.

Late Loading a .net plugin dll

I have a C# .Net 2.0CF application where I would like to load a .NET 'plug-in' DLL at runtime.
As I understand it, I should be able to use the System.Reflection.Assembly.LoadFrom() to load the DLL to an Assembly. Then use Assembly.GetTypes() to get the list of types within the plugin to match them to my expected interfaces.
The problem is that when I call GetTypes(), I get a System.TypeLoadException(). Based on the exception message, I assume this is because this particular plugin references some other assembly that this program knows nothing about. But, that's part of the point of it being a plugin! I don't want my application to have to know anything about these other assemblies.
How can I load this plug-in DLL without having my application reference every assembly used in the plugin?
Thanks,
PaulH
The situation is not that your app should reference every assembly that a plug-in uses. The plug-in references another DLL, not your app, and the plug-in should be "installed" (maybe simply put in a directory) along with everything it needs. This is unavoidable.

C++ calling managed COM object can't find dependent assemblies

I've created and registered a managed COM library in C# on my development machine. I've successfully registered it and created a .tlb file with regasm, and successfully imported the tlb into a c++ console app used for testing.
My COM assembly is called "efcAPI.dll" and it references another assembly that has not been set up for COM or registered in anyway called "efcServerDiscovery.dll". This second dll contains some code used by my COM dll and exists in the same folder as efcAPI.dll.
Everything concerning loading the COM assembly works fine. I can create instances of my classes defined in the COM and call methods from them. However when I call certain methods that use the code defined in efcServerDiscovery.dll I get a _com_error which reports that it could not load file or assembly 'efcServerDiscovery'.
I've verified that everywhere on my hard drive where efcAPI.dll exists there's a copy of efcServerDiscovery.dll (which is just the location I built and registered efcAPI.dll from). I've also attempted to place efcAPI.dll and efcServerDiscovery.dll in the same directory as the c++ app with no success.
Any suggestions as to where the c++ app is looking for the assembly or how to discover where it's looking would be great!
Yes, this is a problem with COM components having non-COM dependencies. Windows doesn't consider the location of the COM DLL when it searches for dependent DLLs. The normal search rules are in effect, the folder that contains the EXE first, Windows directories, current working directory, PATH environment. The location of the COM server does not play a role.
Assuming you don't want to deploy to the EXE folder, none of these are good places to store your DLL, although plenty of installers made the desperation move of storing it in c:\windows\system32 or modify the system PATH environment variable.
One thing you could do is P/Invoke SetDllDirectory() in your C# code before running any code in the DLL. Using Assembly.GetExecutingAssembly().Location will do it. That is however not a safe thing to do though, it might alter the search rules for the app that uses your component.
The only real fix is to install the DLL in the Windows side-by-side cache (WinSxS) and to include a manifest in your C# executable. Given the state of the documentation, I can only wish you the best of luck.
In these situations i always start with Dependency Walker verifying that what & where its trying to load is what i think it is.
fuslogvw will tell you where the CLR is looking for assemblies
Or use GAC.
(here are your characters, stackoverflow)

Can a referenced DLL be loaded even if it's not called?

Env.: .NET / VS2008
Hi All,
My app uses a 3rd party DLL assembly separately installed on some systems (clearly identified) but not all of them.
Which means that on some systems, the DLL is not there hence must not be called. To solve this, I have 2 versions of the app (using 2 configurations) for the 2 use cases. In one of them, all calls to the DLL are #if'ed out.
Since there are no calls to the DLL compiled at all in the app(they're #if'ed out), is it safe to assume that the app won't try to load the DLL even though it is referenced?
Or should I also exclude the reference?
Note: Asked in reaction to womp's comment in this question.
TIA,
IIRC, the C# compiler will omit references to dll's that are never actually used in the code. So if all code is inside #ifs, the reference to the dll will not be there in your compiled app, and the dll will never be loaded.
You can check this using Reflector, by the way. Just drag & drop your compiled app into Reflector, and look at the References node. ILDASM also provides this feature, I think.
Caveat: DllImports and dynamic type loading (e.g., Type.GetType("type,dll")) will dynamically load dlls without the C# compiler knowing or caring. But again, if inside the proper #ifs, nothing will be loaded.
I would exclude it. It might load it no matter what and if you have a type reference, then that also could cause a problem.
Why not load the the assembly dynamically if needed/available? And then if its gets added at a later date you can just make use of it? You'll only need one version of your app also.
You are safe with a reference but without the actual DLL if you never (obviously) instantiate and referenced class AND never refer to the Class in any instantiated or referenced object.
Typically your DLL will be loaded the first time the Class Constructor of a referenced Class is run.
HTH
Jan

Categories

Resources