Click here to Skip to main content
15,890,825 members
Please Sign up or sign in to vote.
4.33/5 (3 votes)
See more:
Hi All,
here is the thing I'm hitting the wall with second day in a row.

I'm writing an extension to the 3rd party application.

Application resides in:
AppName\Bin\app.exe

Application can be told "use DLL with this name, entry point has this name", and than
it uses that dll. This extension dll should reside in a specific folder:

AppName\Bin\Ext\

Problem is, my extension DLL depends on a second DLL (also 3rd party).

I place both dlls reside in Ext subfolder:
AppName\Bin\Ext\A.dll
AppName\Bin\Ext\B.dll

Both dlls are written in C#. A.DLL is the one I wrote, B.DLL is 3rd party dll.

When A.DLL uses only objects/functions defined in itself, all is fine.
When A.DLL uses any object/function from B.DLL, FileNotFound exception is thrown.

And now crazy part: if I place B.DLL in Bin folder or "B" folder, everything works:
AppName\Bin\B.dll - works
AppName\Bin\B\B.dll - works
AppName\Bin\Ext\B.dll - does not work.

I tried to force loading B.DLL (in the A.DLL code) right before using objects from it - this did not help. B.DLL is loaded, but not used, and call on the next line to use object from it tries to load B.DLL again, not finding it, and throws exception.

What could be the problem? Why A.DLL is not looking for B.DLL when it is located in the same folder??!

What I have tried:

Everything - nothing works so far, don't understand why dll is not found when needed.
Posted
Updated 18-May-16 6:42am
Comments
RickZeeland 18-May-16 9:48am    
If I remember correctly the .NET locator routine tries to find a dll in a subdirectory with the same name, so it would be: Bin\A\A.dll
Richard MacCutchan 18-May-16 10:01am    
Put the dll files in the same directory as your application and it should all work.
Sergey Alexandrovich Kryukov 18-May-16 10:33am    
It would be true if the host assembly referenced A.DLL. But it looks like this is a plug-in architecture.
The host application tries to find plug-in assemblies according to its internal code, that's the problem. From the inquirer's description, we don't know how it is done exactly, so we can only assume some algorithm. It's possible that the documentation does not exactly reflect observed behavior, or the inquirer misunderstood it...
—SA
Sergey Alexandrovich Kryukov 18-May-16 10:30am    
Do I understand you correctly?

From your observations, it looks like "This extension dll should reside in a specific folder: AppName\Bin\Ext\" should read "This extension dll should reside in a specific folder: AppName\Bin", because adding "Bin" breaks location of your plug-in/extension assemblies. Are you sure you did not misspell the paths.

In other words, when you write your 3 items "works — works — doesn't work", where is your A.DLL? And where do you want to place A and B?

One note: you have to think in terms of "assemblies", not "DLLs". What you call "DLL" is the main executable module of an assembly, where the .NET assembly manifest is, in your case, one module per assembly, but it's possible to have more than one.

—SA
Kosta Cherry 18-May-16 11:54am    
No, application explicitly required user extensions to be in AppName\Bin\Ext, not AppName\Bin. Basically, I cannot place A.DLL into AppName\Bin - it will not let me "register" it. Yeah, this is 3rd party, you know...

For the 3 items "works-works-doesn't work" I mentioned, A.DLL always resides in AppName\Bin\Ext. It just cannot reside anywhere else.

Of course, I can add folder AppName\Bin\B, add there B.DLL and be doe with it, or place B.DLL into AppName\Bin, but end client does not approve this. They want A.dll and B.dll reside side by side in App\Bin\Ext, and I've no idea why search is not done there.

I just tried SetDllDirectory, as mentioned above - did not help at all. Pulling my hair now :(

1 solution

Ok, here what needs to be done to force dll to look for referenced dll in the same forlder in the case described above:

public static class GlobalKeeper
{
   public static string assemblyDirectory
   {
      get
      {
         string codeBase = Assembly.GetExecutingAssembly().CodeBase;
         UriBuilder uri = new UriBuilder(codeBase);
         string path = Uri.UnescapeDataString(uri.Path);
         return Path.GetDirectoryName(path);
      }
   }

   public static Assembly assemblyResolveHandler(object sender, ResolveEventArgs args)
   {
      string assemblyPath = assemblyDirectory;
      string[] words = args.Name.Split(',');
      if (words.Length > 0)
         assemblyPath += "\\" + words[0] + ".dll";

      return Assembly.LoadFrom(assemblyPath);
   }

   public static void initialize()
   {
      AppDomain.CurrentDomain.AssemblyResolve += assemblyResolveHandler;
   }
}
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 18-May-16 13:03pm    
Oh, yes, assembly resolver. It would be next step, after your clarifications. I must say that it may not have practical value in your case, where you could play by the rules of the host application; and, if your goal was research, you still did not figure out what exactly that host assembly does to load plug-in assemblies; what happens still looks weird. One additional step I could advise is: use ILSpy to disassemble the host assembly and see what it does, out of curiosity.

But this is fine. You don't have to do a research on each and every weird application. From the other hand, you found your way to add considerable degree of flexibility to your assemblies, and this is very good.

I will up-vote your question with 5; after all the clarifications, it looks like really interesting in more general context. At the same time, I don't want to vote on the solution. Don't take it wrong: I just think answering one's own question (which was actually a great post if you answered to help someone else) is not a fair practice; many ask questions which are not interesting to anyone and answer themselves, which makes just a noise (I used to put forward the suggestions to disallow answering own questions). Of course I cannot say this about your answer, which is quite good.

My idea is different: if you do some research on your own question, it's either not interesting to anyone, or, just the opposite, quite interesting. If it is interesting, right approach would be writing and article, possibly a Tips/Tricks article (which can be very short) and then reference it in another comment to your question. That way, your contribution would be most visible and suitable for the readers.

—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900