Let's say I read the manifest for an exe. Something like this:
//Load Assembly
obj_assembly = Assembly.LoadFile(m_strAssembly);
//Return Referenced Assemblies
return obj_assembly.GetReferencedAssemblies();
and I get an assembly object like "{Tools, Version=5.4.620.7, Culture=neutral, PublicKeyToken=null}" for example. How do I know if it is coming from "Tools.dll" or "Tools.exe"? Is there some property in the Assembly object or some trick that tells if it was an EXE or DLL?
No, assemblies don't have a fixed filename extension. Something you can see with Fuslogvw.exe (log all binds). You'll see it searching for an .exe first, then a .dll.
Some observable side effects: you can add a reference to an EXE without a problem. Or you can arbitrarily rename a class library assembly from .dll to .exe and it still works.
The sane thing to do is assume that whomever created this assembly didn't pull stunts like this. You'd expect a reference assembly to be a class library and stored in a file named tools.dll. Which is a good-enough approximation since actually finding that file isn't exactly that easy. You'd have to reproduce CLR search rules which can get awfully convoluted, you don't know enough about binding overrides and probing paths.
Related
I have a solution that includes several projects. A few are libs that are building dll's used in my main project in this solution.
My main project builds with output type console application.
This all works fine.
When i change the build output type to a class library (since i want to use this project as a plugin eventually). The project will still build, this time to a dll.
When i use this plugin in an application where i use it as a dll however, it will run up to a certain point where it's trying to load a type defined in an external dll (so NOT built by my solution) and throw the exception:
Could not load type 'externalinterface' from assembly 'externallib, version=3.0.0.0, Culture=neutral, PublicKeyToken=null'.
The dll's are all in the correct folder,etc.
Also worth noting, the plugin is tested in another location than where i built it. The executable still works on this location, the dll/plugin does not. Same amount of dll's in their folders etc.
EDIT: I already used ILSpy (dll inspector) to open the actual dll that is being referenced (so externallib in the errormessage) and checked if 'externalinterface' was present and it is.
EDIT2: RESOLVED! The program that loaded my plugin was loading the same dll that caused the exception. The dll it loaded was of another version than the one i loaded.
Check whether the type externalinterface is present in the referred dll.
You didn't include the details of the exception the application is throwing. However, based on the message you gave, it appears your assembly does not have a strong name. If the application attempting to load your assembly as a plugin does have a strong name, then .NET will require all assemblies loaded by it also have a strong name, so you need to configure your assembly to have a strong name before continuing.
Maybe some supported dll's which is used by the 'externalinterface' is missing in the target machine. In the target machine, check is all the necessary dll's are present in the output folder.
Or blindly copy paste all the dlls in the output folder from the machine where the code is working to the target machine where you have the problem. After this, if the code is working in the target machine, then try to analyze which supporting dll you are missed to copy.
I am trying to make a simple c# program using Growl C# API.
I tried to compile my program in two different ways:
1) I kept my .dll file in the same directory as my .cs file. Than I ran
csc /r:Growl.Connector.dll,Growl.CoreLibrary.dll /out:test.exe *.cs
It compiled fine and also ran fine.
2) Now I have created a directory inside my current working directory named growl and kept all my .dll references there.
Now when I try to compile it using the below command
csc /r:"D:\Modified\Growl_NET_Connector_SDK\libraries\growl\Growl.Connector.dll","D:
\Modified\Growl_NET_Connector_SDK\libraries\growl\Growl.CoreLibrary.dll" /out:test.exe *.cs
It compiled fine but when I tried to run it the below mentioned exception occurred.
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Growl.Connector, Version=2.0.0.0, Culture=n
eutral, PublicKeyToken=980c2339411be384' or one of its dependencies. The system cannot find the file specified.
at GrowlNotification.Program.Main(String[] args)
So, my question is what is the correct way to reference .dll file in csc when files are in an external folder.
Here is the directory structure for 2nd case.
So, my question is what is the correct way to reference .dll file in csc when files are in an external folder.
You're already referencing them at build time. You just need to make them available at execution time too, but copying them into the same directory as the executable, when you want to run it.
You could also investigate using the Global Assembly Cache if these are signed assemblies, but personally I'd stick with just keeping the executable with the libraries on which it depends.
You can add these using the /lib and /reference command-line switches while compiling.
http://msdn.microsoft.com/en-us/library/s5bac5fx.aspx
But (Quote from the article)
An alternative to using /lib is to copy into the working directory any
required assemblies; this will allow you to simply pass the assembly
name to /reference. You can then delete the assemblies from the
working directory. Since the path to the dependent assembly is not
specified in the assembly manifest, the application can be started on
the target computer and will find and use the assembly in the global
assembly cache.
Because the compiler can reference the assembly does not imply the
common language runtime will be able to find and load the assembly at
runtime. See How the Runtime Locates Assemblies for details on how the
runtime searches for referenced assemblies.
so Jon Skeet's answer is better. (I'm just adding this to provide more info than I could in a comment, not as an answer. Jon's answer is the best IMO)
You can create symlinks to the assemblies in your libraries folder so you would only need to keep them updated in one location.
This is strange...
In a project of mine I need to load external dll's at runtime. I've done this frequently before and I thought I had stepped on all the mines there where but this one has got the best of me so far.
It's very very basic really. I use Assembly.LoadFrom("c:\\test\\mytestlibrary.dll") but Fusion cannot find the file (I get a FileNotFoundException).
I have examined the fusion logs as usual and it just doesn't make sense. Are there some circumstances that would somehow prevent Fusion from finding a file even when I provide the complete and absolute path to it? I suspected the dll in question needed some other assembly but looking at the fusion logs doesn't indicate this. Besides, the test library references nothing that's not also referenced by the host assembly.
Any suggestions?
Perhaps this blog entry by Suzzanne Cook will provide some clues?
For FileNotFoundException:
At the bottom of the log will be the paths that Fusion tried probing for this assembly. If this was a load by path (as in Assembly.LoadFrom()), there will be just one path, and your assembly will need to be there to be found. Otherwise, your assembly will need to be on one of the probing paths listed or in the GAC if it's to be found.
You may also get this exception if an unmanaged dependency or internal module of the assembly failed to load. Try running depends.exe on the file to verify that unmanaged dependencies can be loaded. Note that if you re using ASP.NET, the PATH environment variable it's using may differ from the one the command line uses. If all of them could be loaded, try ildasm.exe on the file, double-click on "MANIFEST" and look for ".file" entries. Each of those files will need to be in the same directory as the manifest-containing file.
-- http://blogs.msdn.com/b/suzcook/archive/2003/05/29/57120.aspx
IIRC, the fusion log should also show the list of paths sought. Is your path included? Further, is the assembly already loaded as a project reference or otherwise previously in the same app domain?
I have 2 projects.
The first one just generates a DLL.
The second one needs the first DLL.
But when I call a method from the DLL, I have a FileNotFoundException, with this message :
BDD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
I'm sure that the file exists.
Where I'm wrong ?
Agree with Kieren (+1). Maybe it is finding your DLL but it requires another dependent DLL that cannot be found. Or is there a signature issue (maybe you are looking for another DLL version, etc...)
To turn on fusion Log (you'll have to create a couple fo registry keys):
BTW, fusion is the DLL that contains the logic to load an assembly (probing for local path and subfolders if specified, looking at the GAC, ...). After running your executable, you'll find a log detailing the issues the CLR has found when loading referenced assemblies (ignore the NativeImage logs, inspect just the Default logs).
Short answer: The DLL needs to be in the same directory as the EXE.
Is this the case?
Could you give the full message - and:
Please bear in mind that the FileNotFoundException could be for a dependency of the referenced DLL, not just the referenced DLL itself.
You might want to turn on assembly-binding log (Fusion log) to see what's going on, if the DLL is indeed present.
I posted a similar question a time ago. I need to load an assembly at runtime.
This is easy if I know the absolute path of the dll at runtime.
But I dont :( The assembly.Load() or LoadFromFile() fails if the file is not in the application root.
The only thing I have is the dll name. The dll could be located in the root, system32 or in even in the GAC.
Is it possible for .net to automatically determine where the dll is at, like for example :
it should first look in the root. If its not there move on to the system folders, else try the GAC.
EDITED
I am using plug-in architecture. I do not need to register the dll. I have a multi user application. I have a applications table containing information regarding applications. Each application has a dll path associated with it, containing certain algorithms associated with that app. Hope this helps.
I hope you've read up on the following. My suggestion...
How the runtime locates assemblies
You can give Assembly.LoadWithPartialName a whirl.. might work.. it says it will search the application folder and the GAC unlike Assembly.Load. (However its less safe.. coz you might end up with the wrong version of the DLL since you dont specify all 4 parts of the Assembly Name)
Also try AppDomainSetup.PrivateBinPath (AppDomain.AppendPrivatePath has been deprecated in favor of this) to add subfolders of the application root to the list of folders to probe assemblies for. You can also try copying over files from other places into a [AppFolder]\MySandboxForDLLsToLoad, which is added to the PrivateBinPath.
When the current application looks for assemblies, it looks in several locations (bin folder, gac, etc..) if it can not find one, then the developer needs to manually tell the application where to look. You can do this by intercepting the AssemblyResolve event, and using the event args to tell the CLR where your assembly is.
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
....................
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var strTempAssmbPath=
Path.GetFullPath("C:\\Windows\\System32\\" + args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll");
var strTempAssmbPath2=
Path.GetFullPath("C:\\Windows\\" + args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll");
if (File.Exists(strTempAssmbPath))
return Assembly.LoadFrom(strTempAssmbPath);
if (File.Exists(strTempAssmbPath2))
return Assembly.LoadFrom(strTempAssmbPath2);
}
You can hook up into AppDomain.CurrentDomain.AssemblyResolve event and load the assembly for your application manually on demand.
Yes there is a way and it depends on whether your dll is weakly(without a public key token) or strongly(with a public key token) named. If its weakly named and you have added a reference to the assembly with the dll within VS, then VS will first look in the application folder root and if it does not find it, it will then look in the subdirectories that you specify as the value of the privatePath attribute in your XML config file.
If its a strongly named dll, then the CLR will search in the GAC so you need to install the dll in the GAC. The CLR can also look in the application directory if you install an XML config file that has its codeBase element pointing to the dll's path.
To specify an assembly in the GAC you can use the /reference:[DLL name] switch when compiling your assembly.
The dll will be found automatically is it is in some location referenced in the PATH system variable (i.e., system32) or if the dll is registered. You can't find it if it can be anywhere on disk, but no one needs that functionality anyway.
EDIT: can the dll's be registered? how are you getting the assembly name if you don't know of the assembly ahead of time? Are you creating some type of plug-in architecture? I think it would help if you explained your situation a bit more.
EDIT2: If that is the case, why not provide a way for the user to register his or her plug in? You can get all the information that you need from an open file dialog. That or simply make them dump it into a folder that you specify.
You have three options
Install the assembly in the global assembly cache (GAC)
Use an application configuration (.config) file with the tags
Use the AssemblyResolve event
You can find the details here.
The resolution algorithm used by .NET to find the assemblies and their dependents is straight forward.
.NET identifies the required version. Usually the information about the dependant assemblies is present in the application's assembly manifest.
.NET searches GAC (Global Assembly Cache), only if the assembly is strong named.
If not found in GAC, and if a .config file presnt, then .NET searches the location specified in the cofiguration file, else .NET searches directory containing the executable (.EXE)
After this, If the assembly is still not found, the application terminates with error.
Click here for the video explaining the .net resolution algorithm, and click here for a video on late binding assemblies
Register this assembly into the GAC. How to do that
Use this
Assembly.LoadWithPartialName(assemblyName);