Path of DLL installed to the GAC - c#

How can I get the (physical) installed path of a DLL that is (may be) registered in GAC? This DLL is a control that may be hosted in things other than a .Net app (including IDEs other than VS...).
When I use System.Reflection.Assembly.GetExecutingAssembly().Location, it gives path of GAC folder in winnt\system32 - or in Design mode in VS gives the path to the VS IDE.
I need to get the path where physical dll is actually installed - or the bin/debug or (release) folder for VS.
Reason is that there is an XML file I need to get at in this folder, with config setting that are used both in design mode and at runtime.
Or how is it best to handle this scenario? I have a dubious network location I am using for design mode at the moment... (Don't think that ApplicationData folder is going to cut it (but have the .Net version soved as that's installed via ClickOnce ans can use the Clickonce Data folder) )

If something gets put in the GAC, it actually gets copied into a spot under %WINDIR%\assembly, like
C:\WINDOWS\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll
I assume you're seeing something like that when you check the Location of the assembly in question when it's installed in the GAC. That's actually correct. (In .NET 1.1 there was a "Codebase" listed when you looked at a GAC assembly's properties, but that was only to show you where the original file was located when you ran gacutil - it didn't actually indicate what would be loaded.) You can read more about that here.
Long story short, you may not be able to do what you want to do. Instead of looking in relation to some assembly that's being loaded (Assembly.GetExecutingAssembly()), you might want to switch the behavior to look relative to the primary application assembly (Assembly.GetEntryAssembly()) or put the file in some well-known location, possibly based on an environment variable that gets set.

After the assembly is shadow copied into the Global Assembly cache, i don't think there is any metadata to traceback the location of the source assemblies.
What are you trying to achieve by deploying in GAC? If its just for the sake of CLR for resolving purposes, then there is an alternate way that solves your problem.
Don't gac install the dll, rather add the following key in the registry, (this registry location is looked up by CLR when trying to resolve assemblies)
32 bit OS : HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\foo
64 bit OS : HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\foo
For the foo key (Use your favourite name instead of foo), you will see a Key Name "Default". Double click it and set the value to wherever your assembly exists. (absolute path is preferred)
Now from Visual Studio, your client should be able to see your assemblies in the "Add Reference" Dialog and can use it.
Now coming to your actual problem,
Assembly.GetExecutingAssembly() will return the path of the location where the insatlled dll's are present. Find the XML file from there. :)
Note: In the registry key the 4.0.30319 is the version of the .NET Framework your application targets. Use whatever version your application targets instead.

Do you have the option of embedding a resource to this DLL? That way, it doesn't really matter where the DLL is located on disk, because the XML file will follow it. You can then do something like this:
Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream("MyProject.MyXmlFile.xml");
XmlDocument d = new XmlDocument();
using (StreamReader r = new StreamReader(s))
{
d.LoadXml(r.ReadToEnd());
}

If you are looking for the physical location where your GACed DLL is saved in the file system, try this:
start-->run-->c:\windows\assembly\gac
If you don't find your DLL related folder in there, you can do a "Up" folder in windows explorer to display everything in c:\windows\assembly as folder structures. You can then look for your DLL under GAC_MSIL or any other folder out there....
Cheers,
Sri

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.

Third-Party DLL I am not allowed to distribute

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.

Could not load file or assembly, system could not find the file specified

I am getting this error:
Could not load file or assembly, system could not find the file specified.
Images:
http://s30.postimg.org/4x936f6ch/error2.png
http://s17.postimg.org/41ta9aaj3/errro3.png
I have a solution built in .NET 4.0
In it I have projects that act as plugins. They use dlls and the issue is that one of the solutions projects dlls is being called, and that references the dll that is causing the issue.
I get no error when rebuilding etc just when the program gets to the part where it uses the dll that references this one.
I have also made sure that in the projects bin folder that it has the dll that it is complaining about.
I have opened the dll in reflector and I don't think it has any issues.
COuld someone point me to the next step to try with fixing this issue?
Thanks!
Couple of tips - hard to know if they'll help you:
Open the csproj file(s) in a text editor and see where the dlls are being referenced (GAC possibly)
If it's a signed assembly, make sure you've got a signed copy (if you've built an Open Source project yourself the signing will be lost)
Look at the references in Visual Studio - do you have Copy Local set to True and Specific Version set to False?
Look at you're App.config or Web.config - is there a binding redirect that failing to load
I remember reading a post about assemblies not being able to be unloaded - probably not an issue on this one but I think the trick was
to load the DLL in a separate AppDomain to keep it isolated - loadable
and unloadable.

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.

Why doesn't .NET find the OpenSSL.NET dll?

EDIT (the whole question, it was too unclear)
I want to use OpenSSL.NET
The OpenSSL.NET install instructions page: INSTALL
Make sure you have libeay32.dll and ssleay32.dll in the current working
directory of your application or in your PATH. DONE
In your .NET project, add a reference to the ManagedOpenSsl.dll assembly. DONE
I have put libeay32.dll and ssleay32.dll in both my bin/Debug and bin/Release directories. I have also put them in system32.
Here is my FULL code:
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
try
{
OpenSSL.Crypto.RSA rsa = new OpenSSL.Crypto.RSA();
}
catch (Exception e)
{
Console.WriteLine(e.InnerException.Message);
}
Console.Read();
}
}
}
I get the following error:
Unable to load DLL 'libeay32' http://localhostr.com/files/a719c5/Error.gif
(Unable to load DLL 'libeay32')
Here is the Process Monitor log (upon request):
alt text http://localhostr.com/files/726a46/ProcMon.gif
What am I doing wrong? Why isn't the DLL found?
Try the latest version of OpenSSL.NET (0.4.1) which should now include prebuilt libeay32.dll and ssleay32.dll binaries that link to the CRT statically. Alternatively, you can build these libraries yourself or use an 'official' build from openssl.org.
Without looking at your code exactly, I get that error when I:
do not have the dlls in the path of the executable (not where your sln resides, but where the .exe is made, typically in bin/debug or bin/x86/debug or whatever).
do not have the proper signature of the calling function (ie, I left out an integer parameter, the return types don't match, etc).
am not marshalling the types properly (ie, BOOL is marshalled as a bool, while bool is marshalled as a unsigned single byte integer, etc)-- while this last one may not cause the exception, it can cause decidedly funky behavior.
am on a 64 bit platform and am calling a 32 bit dll. The pointer sizes will be all different, and the dll will probably just crash and cause that exception.
EDIT: When all else fails, try dependency walker, because it sounds like your dlls are calling other dlls that aren't in your path or in the directory of the executable.
For anyone else out there still experiencing this issue (and have verified that the necessary prerequisites exist in their correct locations:
Check the OpenSSL.NET installation documentation and ensure its prerequisites are installed. In my case, a user was missing the Microsoft Visual C++ 2010 Redistributable Package (x86) dependency which is called out in the OpenSSL.NET documentation.
Your problem is related with this question:
DllNotFoundException, but DLL is there
Verify if all depencencies are in same folder of your application or are registred.
Try using probing. You need to create an XML config file named as the application's executable complete name (or named as the assembly that requieres your non-managed dll) with a .config extension. E.g. if your applications is name myapp.exe, the config file will be named myapp.exe.config
The config file must be located in the same directory as the executable / assembly .
The config file is a simple xml file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyuBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="PATH" />
</assemblyuBinding>
</runtime>
</configuration>
Now the application will search in PATH when loading the assemblies. PATH is relative to the config /assembly file.
Not sure if it will work for non-managed dlls, but is worth the try.
The .NET way of doing this is to install your assembly in the global assembly cache.
Each computer where the common
language runtime is installed has a
machine-wide code cache called the
global assembly cache. The global
assembly cache stores assemblies
specifically designated to be shared
by several applications on the
computer.
As a last resort, if nothing else works:
It may be useful to know where the application (.net or not) is looking for the DLLs. Just use Process Monitor and filter for the file name of the DLL. Then copy it to a location where the application is looking for it.
You're probably missing the VC++ redistributables. I'm assuming OpenSSL.NET is x86 only, so you can grab the VS2008 version x86 redistributable if they're release builds.
Otherwise, if they're debug builds (you'll see Microsoft.VC90.DebugCRT in EventViewer or the sxstrace logs) then you'll need to either:
Rebuild them as release
Install or copy the debug redistributables from another machine
Install Visual C++ into Visual Studio (or, probably, Visual C++ Express)
I found a solution.
Unfortunately the VS2008 C++ Redistributable package didn't work - I had to install the SP1 version AND VC++2008. The author said in a comment on its website that it was a mistake on its side, and not mine. He is currently recompiling the DLLs to be statically linked. Thank you to all of those who helped me :)
Try changing the Platform target for your project to x86 instead of "any cpu".
In my case, when we develop a web site with open ssl on x64 win 2008 platforms, we must check with application pool : allow 32 applications : true
Create New Folder Named x86 in your application path and then put libeay32.dll,ssleay32.dll in x86 folder.

Categories