Third-Party DLL I am not allowed to distribute - c#

Say I have a Visual Studio Project that references a libary XYZ.dll. I am not able to distribute that dll but I know that many people have a license for it.
What can I do to connect my project to XYZ.dll on the target computer? To be more precise, I want to do the following things:
Reference XYZ.dll in a project in Visual Studio.
Distribute a compiled version of the solution/project without XYZ.dll
Let the customer, who installs my program, link the program to his copy of XYZ.dll so that the program can use it.
(This may be an easy question, but I was not able to find the answer, maybe due to wrong search terms).

If the XYZ.dll is installed with a third-party product, you may check whether it is registered in GAC.
If so, then you - in your VS project - reference the XYZ.dll pointing to it in GAC and then setting the copy local to false, so that it will not be copied to your program's bin directory and used from there.
It becomes more problematic in case the dll is not in GAC - in such case you would need to ask user for the assebly's location (or read it from registry if you know what product to search for) and then resolve this assembly dynamiccaly using that path with the use of AssemblyResolve event (https://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve%28v=vs.110%29.aspx)
There is also a way in which you create a "proxy" class in your project that loads the third-party assembly dynamiccaly from the path on the customer's computer, and then create a set of proxy methods that would call loaded third -party assembly using reflection.

Related

Unpredictable System.DllNotFoundException

I downloaded a package from SourceForge, PlanEph, which has 64 and 32 bit DLLs for C#. I got the 32 bit included C# demo to work by putting the DLL in my bin/Debug directory (I'm using Visual Studio 2015 Community) and adding the DLL as a reference.
Then I tried to make my own version of the demo in a separate solution, and got the System.DllNotFoundException. Various experimentation lead me to believe I can't have two identical namespace names anywhere in my Visual Studio installation, so I erased everything and started over.
I made a directory C\GJAbin, put the DLL in it, and added it to the system Path variable. I also put a helloWorld type program in that dir and executed it from the command line to verify the directory really was in the path. Then I recreated the demo solution, added the DLL as a resource, and built the solution "successfully". Then I ran it and got the System.DllNotFoundException.
So I can't understand why the DLL is being found when compiling but not at run time.
Go to project settings, go to "publish" tab and on the top most button (labeled something like "application files"). Chose "Show all files" checkbox if you don't see your DLL. Set the DLL's publish status to "Include" (NOT "Include (Auto)"!!) and publish it again.
Now the DLL should be inside the publish folder.
So I can't understand why the DLL is being found when compiling but not at run time.
Locating the assembly at compile time is done differently (by MSBuild) than at runtime (by the CLR).
At compile time, MSBuild has specific search paths that it knows about, or in most cases like this, there will be something in your project file telling MSBuild where to look for the file. Usually the <Reference> has a <HintPath>.
At runtime, the CLR will attempt to find the assembly from its own set of well-known paths. It will look in your app's config file (if applicable), then in the Global Assembly Cache (GAC), then in your app's root directory. Much more detail on this is available here.
You can tell MSBuild to copy the reference to your build output directory (usually the same as your app root directory when running). In VS, you can do this by selecting the reference and looking at the Properties tool window (or press F4 by default). Set the CopyLocal state to True. In the project file, this will add a <Private>True</Private> on the <Reference>.
You can also add the assembly to the GAC using the gacutil tool, but this does make it harder if you want to share your app with others. Usually it's preferable to keep a copy in your app root directory.
If it's still not working, you can also see the log for how the runtime is trying to find this assembly. The fuslogvw.exe tool in the Windows SDK (you can run it from the VS command prompt and it will be on the %PATH%) allows you to enable logging for assembly loads. You do need to be able to run this as an administrator to configure the setting.
As you can see in the screenshot, you can either log the results in the exception (so that you can see it while debugging), or you can log it to a file on disk (so you can see it whenenver).
The problem turned out to be an unfortunate interaction among the way the author chose names and the way Visual Studio displays information and error messages. The author created a c# dll Astronomy.PlanEph32.dll containing a namespace PlanEph32, which which was really just a wrapper for the c dll PlanEph32.dll. So all the error messages about not being able to load PlanEph32.dll were referring to not finding the c dll; the c# dll was being found just fine.

Resolve 3rd party dll path at runtime

I'm developing an application that depends on some 3rd party dll's (it's actually a plugin to the 3rd party application, and I receive COM objects implementing certain interfaces declared in those dll's). My project contains references to those dll's locally exist on the dev machine, but I want to avoid wraping them inside my installer (for size and legal considerations).
Instead, my installer requires that the dll's are already existing on the target machine, and their path is saved to a text file next to my executable assembly.
How can I use this file to link to the dll's on run time?
Or is it better to add an environment variable during installation and use it instead (how can it be done)?
Using project references, I do not know of a way to have dlls in an arbitrary location. Typically I've handled this issue using an installer, like InstallAware, prompted the user for the 3rd party location, and copied the dlls into my projects folder at the same relative location I chose in my solution file.
If this is improbable for you, you can always load the dlls and create instances of the classes yourself by hand using Assembly.LoadFrom and Activator.CreateInstance.
I hope this helps.

Combine .NET external dlls to a single executable file

This is a simple question. I just can't run my program if the Newtonsoft.Json.dll is not in the program folder. Why this? I've tried adding the reference, added the file to the project root, added to the resources folder, but nothing worked. How to run the program without the Newtonsoft.Json.dll in the program folder? I'm developing in a Windows Form Application.
UPDATE
Problem solved, thanks to spender for introducing me the ILMerge, a really really nice NuGet package that can combine third party dlls to a single executable binary file. For who wants to make a standalone application, just use ILMerge. Rapid, easy and extremely useful. See ya!
Usually, if your program uses a DLL, then you'll need that DLL in the app folder (or in the user path, or the GAC).
The conventional method of distributing multiple files is with an installer. You can write one using either WiX or the VS Installer Projects extension. Now all your output files get installed in one go along with all the other goodness that comes with an installed program. I have a strong preference for this method.
However, there are alternatives:
Download the source and copy the source into your main project, then it will be compiled into your main assembly (make sure you check that this is permitted by the license).
Use ILMerge to combine all your assemblies into a single binary.
If you don't want to reference dll in your program, you can install it to GAC on client machine but I don't understand which the context you want
If you just need some JSON serialization. Can you switch out your functionality with the JavascriptSerializer class which is installed with .Net?
http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer(v=vs.90).aspx

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.

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